From a0bb0441ddb7ca9dd3c942452621d4dfb18d582e Mon Sep 17 00:00:00 2001 From: Alexander Alexeev Date: Wed, 2 Apr 2025 14:43:52 +0200 Subject: [PATCH 001/454] Create actor for node scoped cache --- .../run/kikimr_services_initializers.cpp | 14 ++++ .../run/kikimr_services_initializers.h | 7 ++ ydb/core/driver_lib/run/run.cpp | 4 +- ydb/core/protos/feature_flags.proto | 1 + ydb/core/tx/columnshard/columnshard.cpp | 9 ++- .../columnshard/data_accessor/node_actor.cpp | 19 ++++++ .../tx/columnshard/data_accessor/node_actor.h | 68 +++++++++++++++++++ ydb/core/tx/columnshard/data_accessor/ya.make | 1 + 8 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 ydb/core/tx/columnshard/data_accessor/node_actor.cpp create mode 100644 ydb/core/tx/columnshard/data_accessor/node_actor.h diff --git a/ydb/core/driver_lib/run/kikimr_services_initializers.cpp b/ydb/core/driver_lib/run/kikimr_services_initializers.cpp index 7090097cbe9b..76ddba5a51cf 100644 --- a/ydb/core/driver_lib/run/kikimr_services_initializers.cpp +++ b/ydb/core/driver_lib/run/kikimr_services_initializers.cpp @@ -143,6 +143,7 @@ #include #include #include +#include #include #include #include @@ -1112,6 +1113,19 @@ void TSharedCacheInitializer::InitializeServices( TActorSetupCmd(actor, TMailboxType::ReadAsFilled, appData->UserPoolId)); } +// TSharedMetadaCacheInitializer +TSharedMetadaCacheInitializer::TSharedMetadaCacheInitializer(const TKikimrRunConfig& runConfig) + : IKikimrServicesInitializer(runConfig) +{} + +void TSharedMetadaCacheInitializer::InitializeServices( NActors::TActorSystemSetup *setup, const NKikimr::TAppData *appData) { + if (appData->FeatureFlags.GetEnableSharedMetadataCache()) { + auto* actor = NKikimr::NOlap::NDataAccessorControl::TNodeActor::CreateActor(); + setup->LocalServices.emplace_back(NKikimr::NOlap::NDataAccessorControl::TNodeActor::MakeActorId(NodeId), + TActorSetupCmd(actor, TMailboxType::ReadAsFilled, appData->IOPoolId)); + } +} + // TBlobCacheInitializer TBlobCacheInitializer::TBlobCacheInitializer(const TKikimrRunConfig& runConfig) diff --git a/ydb/core/driver_lib/run/kikimr_services_initializers.h b/ydb/core/driver_lib/run/kikimr_services_initializers.h index cadb077a875e..9eb12c177899 100644 --- a/ydb/core/driver_lib/run/kikimr_services_initializers.h +++ b/ydb/core/driver_lib/run/kikimr_services_initializers.h @@ -95,6 +95,13 @@ class TSharedCacheInitializer : public IKikimrServicesInitializer { void InitializeServices(NActors::TActorSystemSetup *setup, const NKikimr::TAppData *appData) override; }; +class TSharedMetadaCacheInitializer : public IKikimrServicesInitializer { +public: +TSharedMetadaCacheInitializer(const TKikimrRunConfig& runConfig); + + void InitializeServices(NActors::TActorSystemSetup *setup, const NKikimr::TAppData *appData) override; +}; + class TBlobCacheInitializer : public IKikimrServicesInitializer { public: TBlobCacheInitializer(const TKikimrRunConfig& runConfig); diff --git a/ydb/core/driver_lib/run/run.cpp b/ydb/core/driver_lib/run/run.cpp index 70eb9987ca42..e5d27090ec49 100644 --- a/ydb/core/driver_lib/run/run.cpp +++ b/ydb/core/driver_lib/run/run.cpp @@ -1522,7 +1522,7 @@ TIntrusivePtr TKikimrRunner::CreateServiceInitializers } if (serviceMask.EnableBlobCache) { sil->AddServiceInitializer(new TBlobCacheInitializer(runConfig)); - } + } if (serviceMask.EnableLogger) { sil->AddServiceInitializer(new TLoggerInitializer(runConfig, LogSettings, LogBackend)); } @@ -1621,6 +1621,8 @@ TIntrusivePtr TKikimrRunner::CreateServiceInitializers sil->AddServiceInitializer(new TMemProfMonitorInitializer(runConfig, ProcessMemoryInfoProvider)); + sil->AddServiceInitializer(new TSharedMetadaCacheInitializer(runConfig)); + #if defined(ENABLE_MEMORY_TRACKING) if (serviceMask.EnableMemoryTracker) { sil->AddServiceInitializer(new TMemoryTrackerInitializer(runConfig)); diff --git a/ydb/core/protos/feature_flags.proto b/ydb/core/protos/feature_flags.proto index e07868b4638c..274fe908e46e 100644 --- a/ydb/core/protos/feature_flags.proto +++ b/ydb/core/protos/feature_flags.proto @@ -206,4 +206,5 @@ message TFeatureFlags { optional bool SwitchToConfigV1 = 180 [default = false]; optional bool EnableEncryptedExport = 181 [default = false]; optional bool EnableAlterDatabase = 182 [default = false]; + optional bool EnableSharedMetadataCache = 183 [default = false]; } diff --git a/ydb/core/tx/columnshard/columnshard.cpp b/ydb/core/tx/columnshard/columnshard.cpp index f3b3a37908a4..92308e4cfb74 100644 --- a/ydb/core/tx/columnshard/columnshard.cpp +++ b/ydb/core/tx/columnshard/columnshard.cpp @@ -4,6 +4,7 @@ #include "blobs_reader/actor.h" #include "counters/aggregation/table_stats.h" #include "data_accessor/actor.h" +#include "data_accessor/node_actor.h" #include "data_accessor/manager.h" #include "engines/column_engine_logs.h" #include "engines/writer/buffer/actor.h" @@ -124,7 +125,13 @@ void TColumnShard::OnActivateExecutor(const TActorContext& ctx) { ResourceSubscribeActor = ctx.Register(new NOlap::NResourceBroker::NSubscribe::TActor(TabletID(), SelfId())); BufferizationInsertionWriteActorId = ctx.Register(new NColumnShard::NWriting::TActor(TabletID(), SelfId())); BufferizationPortionsWriteActorId = ctx.Register(new NOlap::NWritingPortions::TActor(TabletID(), SelfId())); - DataAccessorsControlActorId = ctx.Register(new NOlap::NDataAccessorControl::TActor(TabletID(), SelfId())); + // Change actor here + if (AppData(ctx)->FeatureFlags.GetEnableSharedMetadataCache()){ + DataAccessorsControlActorId = NOlap::NDataAccessorControl::TNodeActor::MakeActorId(ctx.SelfID.NodeId()); + } else { + DataAccessorsControlActorId = ctx.Register(new NOlap::NDataAccessorControl::TActor(TabletID(), SelfId())); + } + DataAccessorsManager = std::make_shared(DataAccessorsControlActorId, SelfId()), PrioritizationClientId = NPrioritiesQueue::TCompServiceOperator::RegisterClient(); diff --git a/ydb/core/tx/columnshard/data_accessor/node_actor.cpp b/ydb/core/tx/columnshard/data_accessor/node_actor.cpp new file mode 100644 index 000000000000..e332ee2a21be --- /dev/null +++ b/ydb/core/tx/columnshard/data_accessor/node_actor.cpp @@ -0,0 +1,19 @@ +#include "node_actor.h" + +namespace NKikimr::NOlap::NDataAccessorControl { + +NActors::IActor* TNodeActor::CreateActor() { + return new TNodeActor(); +} + +void TNodeActor::Handle(TEvAskServiceDataAccessors::TPtr& ev) { + Manager->AskData(ev->Get()->GetRequest()); +} + +void TNodeActor::Bootstrap() { + AccessorsCallback = std::make_shared(SelfId()); + Manager = std::make_shared(AccessorsCallback); + Become(&TThis::StateWait); +} + +} diff --git a/ydb/core/tx/columnshard/data_accessor/node_actor.h b/ydb/core/tx/columnshard/data_accessor/node_actor.h new file mode 100644 index 000000000000..669e63ff86aa --- /dev/null +++ b/ydb/core/tx/columnshard/data_accessor/node_actor.h @@ -0,0 +1,68 @@ +#pragma once +#include "events.h" +#include "manager.h" + +#include "abstract/collector.h" + +#include +#include + +namespace NKikimr::NOlap::NDataAccessorControl { + +class TNodeActor: public TActorBootstrapped { +private: + std::shared_ptr Manager; + + std::shared_ptr AccessorsCallback; + + void StartStopping() { + PassAway(); + } + + void Handle(TEvRegisterController::TPtr& ev) { + Manager->RegisterController(ev->Get()->ExtractController(), ev->Get()->IsUpdate()); + } + void Handle(TEvUnregisterController::TPtr& ev) { + Manager->UnregisterController(ev->Get()->GetPathId()); + } + void Handle(TEvAddPortion::TPtr& ev) { + for (auto&& a : ev->Get()->ExtractAccessors()) { + Manager->AddPortion(std::move(a)); + } + } + void Handle(TEvRemovePortion::TPtr& ev) { + Manager->RemovePortion(ev->Get()->GetPortion()); + } + void Handle(TEvAskServiceDataAccessors::TPtr& ev); + +public: + + static inline TActorId MakeActorId(ui32 nodeId) { + char x[12] = {'s', 'h', 'a', 'r', 'e', + 'd', 'm', 'e', 't', 'a', 'd', 't'}; + return TActorId(nodeId, TStringBuf(x, 12)); + } + + static NActors::IActor* CreateActor(); + + TNodeActor() = default; + ~TNodeActor() = default; + + void Bootstrap(); + + STFUNC(StateWait) { + const NActors::TLogContextGuard lGuard = NActors::TLogContextBuilder::Build()("self_id", SelfId()); + switch (ev->GetTypeRewrite()) { + cFunc(NActors::TEvents::TEvPoison::EventType, StartStopping); + hFunc(TEvRegisterController, Handle); + hFunc(TEvUnregisterController, Handle); + hFunc(TEvAskServiceDataAccessors, Handle); + hFunc(TEvRemovePortion, Handle); + hFunc(TEvAddPortion, Handle); + default: + AFL_VERIFY(false); + } + } +}; + +} // namespace NKikimr::NOlap::NDataAccessorControl diff --git a/ydb/core/tx/columnshard/data_accessor/ya.make b/ydb/core/tx/columnshard/data_accessor/ya.make index f3212e91e74e..0355e0672a36 100644 --- a/ydb/core/tx/columnshard/data_accessor/ya.make +++ b/ydb/core/tx/columnshard/data_accessor/ya.make @@ -2,6 +2,7 @@ LIBRARY() SRCS( actor.cpp + node_actor.cpp events.cpp request.cpp manager.cpp From 52072a969857202f04e4a79026945f9ff4a27610 Mon Sep 17 00:00:00 2001 From: vpozdyayev Date: Mon, 7 Apr 2025 05:36:48 +0300 Subject: [PATCH 002/454] New command engine: enable for .in source processing commit_hash:82469b351b1b310f3d6d6f136b56bfd898b34016 --- build/ymake.core.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/build/ymake.core.conf b/build/ymake.core.conf index b6f076e92d24..0e286ce8e0ec 100644 --- a/build/ymake.core.conf +++ b/build/ymake.core.conf @@ -3111,6 +3111,7 @@ macro _SRC("pyx", SRC, SRCFLAGS...) { # tag:src-processing macro _SRC("in", SRC, SRCFLAGS...) { .CMD=$CONFIGURE_FILE(${SRC} ${nopath;noext:SRC}) + .STRUCT_CMD=yes .SEM=$CONFIGURE_FILE(${SRC} ${nopath;noext:SRC}) } From 0b2bfef9c01a1d8230b29d1760f372dbed57c58d Mon Sep 17 00:00:00 2001 From: robot-ya-builder Date: Mon, 7 Apr 2025 06:17:07 +0300 Subject: [PATCH 003/454] Automatic release build for ymake, os_ymake Update tools: ymake, os_ymake commit_hash:a278b9a4cbed3902996f3c7e9e4dd9e63dae9a55 --- build/external_resources/ymake/public.resources.json | 10 +++++----- build/external_resources/ymake/resources.json | 10 +++++----- build/mapping.conf.json | 10 ++++++++++ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/build/external_resources/ymake/public.resources.json b/build/external_resources/ymake/public.resources.json index 3674bbaa86f0..0963569a1ea7 100644 --- a/build/external_resources/ymake/public.resources.json +++ b/build/external_resources/ymake/public.resources.json @@ -1,19 +1,19 @@ { "by_platform": { "darwin": { - "uri": "sbr:8383217030" + "uri": "sbr:8440741812" }, "darwin-arm64": { - "uri": "sbr:8383215700" + "uri": "sbr:8440740655" }, "linux": { - "uri": "sbr:8383219483" + "uri": "sbr:8440743682" }, "linux-aarch64": { - "uri": "sbr:8383214378" + "uri": "sbr:8440739614" }, "win32": { - "uri": "sbr:8383218300" + "uri": "sbr:8440742993" } } } diff --git a/build/external_resources/ymake/resources.json b/build/external_resources/ymake/resources.json index 1ad3f10e4d5f..6e459f4b89ff 100644 --- a/build/external_resources/ymake/resources.json +++ b/build/external_resources/ymake/resources.json @@ -1,19 +1,19 @@ { "by_platform": { "darwin": { - "uri": "sbr:8383201449" + "uri": "sbr:8440734224" }, "darwin-arm64": { - "uri": "sbr:8383200356" + "uri": "sbr:8440732809" }, "linux": { - "uri": "sbr:8383203472" + "uri": "sbr:8440735823" }, "linux-aarch64": { - "uri": "sbr:8383199084" + "uri": "sbr:8440731709" }, "win32": { - "uri": "sbr:8383202531" + "uri": "sbr:8440735216" } } } diff --git a/build/mapping.conf.json b/build/mapping.conf.json index d0098e529f25..7629c9859abe 100644 --- a/build/mapping.conf.json +++ b/build/mapping.conf.json @@ -733,6 +733,7 @@ "8326169329": "{registry_endpoint}/8326169329", "8350151492": "{registry_endpoint}/8350151492", "8383217030": "{registry_endpoint}/8383217030", + "8440741812": "{registry_endpoint}/8440741812", "5766171800": "{registry_endpoint}/5766171800", "5805430761": "{registry_endpoint}/5805430761", "5829025456": "{registry_endpoint}/5829025456", @@ -808,6 +809,7 @@ "8326167937": "{registry_endpoint}/8326167937", "8350149418": "{registry_endpoint}/8350149418", "8383215700": "{registry_endpoint}/8383215700", + "8440740655": "{registry_endpoint}/8440740655", "5766173070": "{registry_endpoint}/5766173070", "5805432830": "{registry_endpoint}/5805432830", "5829031598": "{registry_endpoint}/5829031598", @@ -883,6 +885,7 @@ "8326171209": "{registry_endpoint}/8326171209", "8350156616": "{registry_endpoint}/8350156616", "8383219483": "{registry_endpoint}/8383219483", + "8440743682": "{registry_endpoint}/8440743682", "5766171341": "{registry_endpoint}/5766171341", "5805430188": "{registry_endpoint}/5805430188", "5829023352": "{registry_endpoint}/5829023352", @@ -958,11 +961,13 @@ "8326166988": "{registry_endpoint}/8326166988", "8350147184": "{registry_endpoint}/8350147184", "8383214378": "{registry_endpoint}/8383214378", + "8440739614": "{registry_endpoint}/8440739614", "8270821739": "{registry_endpoint}/8270821739", "8295446553": "{registry_endpoint}/8295446553", "8326170338": "{registry_endpoint}/8326170338", "8350153953": "{registry_endpoint}/8350153953", "8383218300": "{registry_endpoint}/8383218300", + "8440742993": "{registry_endpoint}/8440742993", "5766172695": "{registry_endpoint}/5766172695", "5805432230": "{registry_endpoint}/5805432230", "5829029743": "{registry_endpoint}/5829029743", @@ -2062,6 +2067,7 @@ "8326169329": "devtools/ymake/bin/ymake for darwin", "8350151492": "devtools/ymake/bin/ymake for darwin", "8383217030": "devtools/ymake/bin/ymake for darwin", + "8440741812": "devtools/ymake/bin/ymake for darwin", "5766171800": "devtools/ymake/bin/ymake for darwin-arm64", "5805430761": "devtools/ymake/bin/ymake for darwin-arm64", "5829025456": "devtools/ymake/bin/ymake for darwin-arm64", @@ -2137,6 +2143,7 @@ "8326167937": "devtools/ymake/bin/ymake for darwin-arm64", "8350149418": "devtools/ymake/bin/ymake for darwin-arm64", "8383215700": "devtools/ymake/bin/ymake for darwin-arm64", + "8440740655": "devtools/ymake/bin/ymake for darwin-arm64", "5766173070": "devtools/ymake/bin/ymake for linux", "5805432830": "devtools/ymake/bin/ymake for linux", "5829031598": "devtools/ymake/bin/ymake for linux", @@ -2212,6 +2219,7 @@ "8326171209": "devtools/ymake/bin/ymake for linux", "8350156616": "devtools/ymake/bin/ymake for linux", "8383219483": "devtools/ymake/bin/ymake for linux", + "8440743682": "devtools/ymake/bin/ymake for linux", "5766171341": "devtools/ymake/bin/ymake for linux-aarch64", "5805430188": "devtools/ymake/bin/ymake for linux-aarch64", "5829023352": "devtools/ymake/bin/ymake for linux-aarch64", @@ -2287,11 +2295,13 @@ "8326166988": "devtools/ymake/bin/ymake for linux-aarch64", "8350147184": "devtools/ymake/bin/ymake for linux-aarch64", "8383214378": "devtools/ymake/bin/ymake for linux-aarch64", + "8440739614": "devtools/ymake/bin/ymake for linux-aarch64", "8270821739": "devtools/ymake/bin/ymake for win32", "8295446553": "devtools/ymake/bin/ymake for win32", "8326170338": "devtools/ymake/bin/ymake for win32", "8350153953": "devtools/ymake/bin/ymake for win32", "8383218300": "devtools/ymake/bin/ymake for win32", + "8440742993": "devtools/ymake/bin/ymake for win32", "5766172695": "devtools/ymake/bin/ymake for win32-clang-cl", "5805432230": "devtools/ymake/bin/ymake for win32-clang-cl", "5829029743": "devtools/ymake/bin/ymake for win32-clang-cl", From f414482ce4b8d716723c888bcb7603a4f49a8920 Mon Sep 17 00:00:00 2001 From: golubi-kuryat Date: Mon, 7 Apr 2025 10:04:24 +0300 Subject: [PATCH 004/454] Make WriteMetric protected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Появляется возможность зарегистрировать новую тип метрики с кастомным поведением, который наследуется от IMetric Пример использования HIDDEN_URL commit_hash:82e3997427ef61d8017d6a1c1eca848131b03d7b --- library/cpp/monlib/metrics/fake.h | 10 ++++ library/cpp/monlib/metrics/metric.h | 16 +++-- .../cpp/monlib/metrics/metric_registry.cpp | 58 +------------------ library/cpp/monlib/metrics/metric_registry.h | 38 +++++++++++- 4 files changed, 57 insertions(+), 65 deletions(-) diff --git a/library/cpp/monlib/metrics/fake.h b/library/cpp/monlib/metrics/fake.h index b01ff2505ad9..a058e1d99a10 100644 --- a/library/cpp/monlib/metrics/fake.h +++ b/library/cpp/monlib/metrics/fake.h @@ -82,6 +82,8 @@ namespace NMonitoring { i64 Get() const noexcept override { return 0; } + + void Reset() noexcept override {} }; struct TFakeRate final: public TFakeAcceptor { @@ -102,6 +104,8 @@ namespace NMonitoring { ui64 Get() const noexcept override { return 0; } + + void Reset() noexcept override {} }; struct TFakeGauge final: public TFakeAcceptor { @@ -117,12 +121,16 @@ namespace NMonitoring { double Get() const noexcept override { return 0; } + + void Reset() noexcept override {} }; struct TFakeLazyGauge final: public TFakeAcceptor { double Get() const noexcept override { return 0; } + + void Reset() noexcept override {} }; struct TFakeHistogram final: public IHistogram { @@ -169,5 +177,7 @@ namespace NMonitoring { ui64 Get() const noexcept override { return 0; } + + void Reset() noexcept override {} }; } // namespace NMonitoring diff --git a/library/cpp/monlib/metrics/metric.h b/library/cpp/monlib/metrics/metric.h index 2f7d9de687f6..bb5fda322ea5 100644 --- a/library/cpp/monlib/metrics/metric.h +++ b/library/cpp/monlib/metrics/metric.h @@ -15,6 +15,7 @@ namespace NMonitoring { virtual EMetricType Type() const noexcept = 0; virtual void Accept(TInstant time, IMetricConsumer* consumer) const = 0; + virtual void Reset() noexcept = 0; }; using IMetricPtr = TIntrusivePtr; @@ -28,7 +29,7 @@ namespace NMonitoring { virtual double Add(double n) noexcept = 0; virtual void Set(double n) noexcept = 0; virtual double Get() const noexcept = 0; - virtual void Reset() noexcept { + void Reset() noexcept override { Set(0); } }; @@ -58,7 +59,7 @@ namespace NMonitoring { virtual void Set(i64 value) noexcept = 0; virtual i64 Get() const noexcept = 0; - virtual void Reset() noexcept { + void Reset() noexcept override { Set(0); } }; @@ -84,7 +85,6 @@ namespace NMonitoring { virtual ui64 Add(ui64 n) noexcept = 0; virtual ui64 Get() const noexcept = 0; - virtual void Reset() noexcept = 0; }; class ILazyCounter: public IMetric { @@ -108,7 +108,6 @@ namespace NMonitoring { virtual ui64 Add(ui64 n) noexcept = 0; virtual ui64 Get() const noexcept = 0; - virtual void Reset() noexcept = 0; }; class ILazyRate: public IMetric { @@ -134,7 +133,6 @@ namespace NMonitoring { virtual void Record(double value) noexcept = 0; virtual void Record(double value, ui32 count) noexcept = 0; virtual IHistogramSnapshotPtr TakeSnapshot() const = 0; - virtual void Reset() noexcept = 0; protected: const bool IsRate_; @@ -194,6 +192,8 @@ namespace NMonitoring { consumer->OnDouble(time, Get()); } + void Reset() noexcept override {} + private: std::function Supplier_; }; @@ -245,6 +245,8 @@ namespace NMonitoring { consumer->OnInt64(time, Get()); } + void Reset() noexcept override {} + private: std::function Supplier_; }; @@ -296,6 +298,8 @@ namespace NMonitoring { consumer->OnUint64(time, Get()); } + void Reset() noexcept override {} + private: std::function Supplier_; }; @@ -347,6 +351,8 @@ namespace NMonitoring { consumer->OnUint64(time, Get()); } + void Reset() noexcept override {} + private: std::function Supplier_; }; diff --git a/library/cpp/monlib/metrics/metric_registry.cpp b/library/cpp/monlib/metrics/metric_registry.cpp index 245f65702d1d..dbbea603c164 100644 --- a/library/cpp/monlib/metrics/metric_registry.cpp +++ b/library/cpp/monlib/metrics/metric_registry.cpp @@ -226,29 +226,7 @@ namespace NMonitoring { void TMetricRegistry::Reset() { TWriteGuard g{*Lock_}; for (auto& [label, metricValue] : Metrics_) { - auto metric = metricValue.Metric; - switch (metric->Type()) { - case EMetricType::GAUGE: - static_cast(metric.Get())->Set(.0); - break; - case EMetricType::IGAUGE: - static_cast(metric.Get())->Set(0); - break; - case EMetricType::COUNTER: - static_cast(metric.Get())->Reset(); - break; - case EMetricType::RATE: - static_cast(metric.Get())->Reset(); - break; - case EMetricType::HIST: - case EMetricType::HIST_RATE: - static_cast(metric.Get())->Reset(); - break; - case EMetricType::UNKNOWN: - case EMetricType::DSUMMARY: - case EMetricType::LOGHIST: - break; - } + metricValue.Metric->Reset(); } } @@ -257,40 +235,6 @@ namespace NMonitoring { Metrics_.clear(); } - template - TMetric* TMetricRegistry::Metric(TLabelsType&& labels, TMetricOpts&& opts, Args&&... args) { - { - TReadGuard g{*Lock_}; - - auto it = Metrics_.find(labels); - if (it != Metrics_.end()) { - Y_ENSURE(it->second.Metric->Type() == type, "cannot create metric " << labels - << " with type " << MetricTypeToStr(type) - << ", because registry already has same metric with type " << MetricTypeToStr(it->second.Metric->Type())); - Y_ENSURE(it->second.Opts.MemOnly == opts.MemOnly,"cannot create metric " << labels - << " with memOnly=" << opts.MemOnly - << ", because registry already has same metric with memOnly=" << it->second.Opts.MemOnly); - return static_cast(it->second.Metric.Get()); - } - } - - { - IMetricPtr metric = MakeIntrusive(std::forward(args)...); - - TWriteGuard g{*Lock_}; - // decltype(Metrics_)::iterator breaks build on windows - THashMap::iterator it; - TMetricValue metricValue = {metric, opts}; - if constexpr (!std::is_convertible_v) { - it = Metrics_.emplace(new TLabels{std::forward(labels)}, std::move(metricValue)).first; - } else { - it = Metrics_.emplace(std::forward(labels), std::move(metricValue)).first; - } - - return static_cast(it->second.Metric.Get()); - } - } - void TMetricRegistry::RemoveMetric(const ILabels& labels) noexcept { TWriteGuard g{*Lock_}; Metrics_.erase(labels); diff --git a/library/cpp/monlib/metrics/metric_registry.h b/library/cpp/monlib/metrics/metric_registry.h index f60467cf9122..7669a8c08862 100644 --- a/library/cpp/monlib/metrics/metric_registry.h +++ b/library/cpp/monlib/metrics/metric_registry.h @@ -274,13 +274,45 @@ namespace NMonitoring { TMetricOpts Opts; }; + protected: + template + TMetric* Metric(TLabelsType&& labels, TMetricOpts&& opts, Args&&... args) { + { + TReadGuard g{*Lock_}; + + auto it = Metrics_.find(labels); + if (it != Metrics_.end()) { + Y_ENSURE(it->second.Metric->Type() == type, "cannot create metric " << labels + << " with type " << MetricTypeToStr(type) + << ", because registry already has same metric with type " << MetricTypeToStr(it->second.Metric->Type())); + Y_ENSURE(it->second.Opts.MemOnly == opts.MemOnly,"cannot create metric " << labels + << " with memOnly=" << opts.MemOnly + << ", because registry already has same metric with memOnly=" << it->second.Opts.MemOnly); + return static_cast(it->second.Metric.Get()); + } + } + + { + IMetricPtr metric = MakeIntrusive(std::forward(args)...); + + TWriteGuard g{*Lock_}; + // decltype(Metrics_)::iterator breaks build on windows + THashMap::iterator it; + TMetricValue metricValue = {metric, opts}; + if constexpr (!std::is_convertible_v) { + it = Metrics_.emplace(new TLabels{std::forward(labels)}, std::move(metricValue)).first; + } else { + it = Metrics_.emplace(std::forward(labels), std::move(metricValue)).first; + } + + return static_cast(it->second.Metric.Get()); + } + } + private: THolder Lock_ = MakeHolder(); THashMap Metrics_; - template - TMetric* Metric(TLabelsType&& labels, TMetricOpts&& opts, Args&&... args); - TLabels CommonLabels_; }; From 4568b28ae7135a0eef9709bea41358e7d120ab48 Mon Sep 17 00:00:00 2001 From: ignat Date: Mon, 7 Apr 2025 10:13:57 +0300 Subject: [PATCH 005/454] Update ytexec resource commit_hash:105467498065ee2aa208092018dd2a9c8e670093 --- build/mapping.conf.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/mapping.conf.json b/build/mapping.conf.json index 7629c9859abe..c52e729aeb1e 100644 --- a/build/mapping.conf.json +++ b/build/mapping.conf.json @@ -1333,6 +1333,7 @@ "7879860842": "{registry_endpoint}/7879860842", "8367004015": "{registry_endpoint}/8367004015", "8418036683": "{registry_endpoint}/8418036683", + "8435535653": "{registry_endpoint}/8435535653", "2980468199": "{registry_endpoint}/2980468199", "5562224408": "{registry_endpoint}/5562224408", "7663495611": "{registry_endpoint}/7663495611" @@ -2667,10 +2668,11 @@ "7879860842": "yt/go/ytrecipe/cmd/ytexec for linux", "8367004015": "yt/go/ytrecipe/cmd/ytexec for linux", "8418036683": "yt/go/ytrecipe/cmd/ytexec for linux", + "8435535653": "yt/go/ytrecipe/cmd/ytexec for linux", "2980468199": "ytexec for linux", "5562224408": "ytexec for linux", "7663495611": "ytexec for linux" }, "resources_info": {}, "tasks": {} -} \ No newline at end of file +} From 6b8cf1895463598e6ac84bba9aabaf0c665e4911 Mon Sep 17 00:00:00 2001 From: robot-ya-builder Date: Mon, 7 Apr 2025 10:45:52 +0300 Subject: [PATCH 006/454] External build system generator release 108 Update tools: yexport, os-yexport commit_hash:1fca303069f0feae4f743b7b9eda669269d48b93 --- build/external_resources/yexport/public.resources.json | 6 +++--- build/external_resources/yexport/resources.json | 6 +++--- build/mapping.conf.json | 6 ++++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/build/external_resources/yexport/public.resources.json b/build/external_resources/yexport/public.resources.json index abe9b651e30a..1244c3648e1e 100644 --- a/build/external_resources/yexport/public.resources.json +++ b/build/external_resources/yexport/public.resources.json @@ -1,13 +1,13 @@ { "by_platform": { "darwin": { - "uri": "sbr:8188215274" + "uri": "sbr:8450186648" }, "darwin-arm64": { - "uri": "sbr:8188212965" + "uri": "sbr:8450185847" }, "linux": { - "uri": "sbr:8188211019" + "uri": "sbr:8450184998" } } } diff --git a/build/external_resources/yexport/resources.json b/build/external_resources/yexport/resources.json index 551fa96266af..34d34e51f8ad 100644 --- a/build/external_resources/yexport/resources.json +++ b/build/external_resources/yexport/resources.json @@ -1,13 +1,13 @@ { "by_platform": { "darwin": { - "uri": "sbr:8188103297" + "uri": "sbr:8450160353" }, "darwin-arm64": { - "uri": "sbr:8188100853" + "uri": "sbr:8450159079" }, "linux": { - "uri": "sbr:8188098624" + "uri": "sbr:8450158028" } } } diff --git a/build/mapping.conf.json b/build/mapping.conf.json index c52e729aeb1e..20b7b02c37f2 100644 --- a/build/mapping.conf.json +++ b/build/mapping.conf.json @@ -604,6 +604,7 @@ "7588492076": "{registry_endpoint}/7588492076", "7688576117": "{registry_endpoint}/7688576117", "8188215274": "{registry_endpoint}/8188215274", + "8450186648": "{registry_endpoint}/8450186648", "5811823398": "{registry_endpoint}/5811823398", "5840611310": "{registry_endpoint}/5840611310", "5860185593": "{registry_endpoint}/5860185593", @@ -631,6 +632,7 @@ "7588489645": "{registry_endpoint}/7588489645", "7688574511": "{registry_endpoint}/7688574511", "8188212965": "{registry_endpoint}/8188212965", + "8450185847": "{registry_endpoint}/8450185847", "5811822876": "{registry_endpoint}/5811822876", "5840610640": "{registry_endpoint}/5840610640", "5860184285": "{registry_endpoint}/5860184285", @@ -658,6 +660,7 @@ "7588486683": "{registry_endpoint}/7588486683", "7688572842": "{registry_endpoint}/7688572842", "8188211019": "{registry_endpoint}/8188211019", + "8450184998": "{registry_endpoint}/8450184998", "5766172292": "{registry_endpoint}/5766172292", "5805431504": "{registry_endpoint}/5805431504", "5829027626": "{registry_endpoint}/5829027626", @@ -1939,6 +1942,7 @@ "7588492076": "devtools/yexport/bin/yexport for darwin", "7688576117": "devtools/yexport/bin/yexport for darwin", "8188215274": "devtools/yexport/bin/yexport for darwin", + "8450186648": "devtools/yexport/bin/yexport for darwin", "5811823398": "devtools/yexport/bin/yexport for darwin-arm64", "5840611310": "devtools/yexport/bin/yexport for darwin-arm64", "5860185593": "devtools/yexport/bin/yexport for darwin-arm64", @@ -1966,6 +1970,7 @@ "7588489645": "devtools/yexport/bin/yexport for darwin-arm64", "7688574511": "devtools/yexport/bin/yexport for darwin-arm64", "8188212965": "devtools/yexport/bin/yexport for darwin-arm64", + "8450185847": "devtools/yexport/bin/yexport for darwin-arm64", "5811822876": "devtools/yexport/bin/yexport for linux", "5840610640": "devtools/yexport/bin/yexport for linux", "5860184285": "devtools/yexport/bin/yexport for linux", @@ -1993,6 +1998,7 @@ "7588486683": "devtools/yexport/bin/yexport for linux", "7688572842": "devtools/yexport/bin/yexport for linux", "8188211019": "devtools/yexport/bin/yexport for linux", + "8450184998": "devtools/yexport/bin/yexport for linux", "5766172292": "devtools/ymake/bin/ymake for darwin", "5805431504": "devtools/ymake/bin/ymake for darwin", "5829027626": "devtools/ymake/bin/ymake for darwin", From 17e4756b8005b5dee181211252e9422d03f78a0d Mon Sep 17 00:00:00 2001 From: cherepashka Date: Mon, 7 Apr 2025 10:54:21 +0300 Subject: [PATCH 007/454] YT-24270: Added overdraft for TAsyncSemaphore * Changelog entry Type: feature Component: core Add slots overdraft into TAsyncSemaphore commit_hash:3a25c8c48546671fece656d75b2b5e4d37f829cd --- yt/yt/core/concurrency/async_semaphore.cpp | 34 ++++++++- yt/yt/core/concurrency/async_semaphore.h | 2 + .../unittests/async_semaphore_ut.cpp | 73 +++++++++++++++++++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/yt/yt/core/concurrency/async_semaphore.cpp b/yt/yt/core/concurrency/async_semaphore.cpp index 52c73364e372..79e74d94b6e9 100644 --- a/yt/yt/core/concurrency/async_semaphore.cpp +++ b/yt/yt/core/concurrency/async_semaphore.cpp @@ -11,6 +11,14 @@ TAsyncSemaphore::TAsyncSemaphore(i64 totalSlots) YT_VERIFY(TotalSlots_ >= 0); } +TAsyncSemaphore::TAsyncSemaphore(i64 totalSlots, bool enableOverdraft) + : TotalSlots_(totalSlots) + , FreeSlots_(totalSlots) + , EnableOverdraft_(enableOverdraft) +{ + YT_VERIFY(TotalSlots_ >= 0); +} + void TAsyncSemaphore::SetTotal(i64 totalSlots) { YT_VERIFY(totalSlots >= 0); @@ -33,6 +41,10 @@ void TAsyncSemaphore::Release(i64 slots) auto guard = WriterGuard(SpinLock_); FreeSlots_ += slots; + if (EnableOverdraft_) { + FreeSlots_ = std::min(FreeSlots_, TotalSlots_); + } + YT_VERIFY(FreeSlots_ <= TotalSlots_); if (Releasing_) { @@ -48,9 +60,17 @@ void TAsyncSemaphore::Release(i64 slots) { auto guard = WriterGuard(SpinLock_); + auto frontWaiterOverflowsSlots = [&] { + return EnableOverdraft_ && !Waiters_.empty() && Waiters_.front().Slots > TotalSlots_ && FreeSlots_ == TotalSlots_; + }; - while (!Waiters_.empty() && FreeSlots_ >= Waiters_.front().Slots) { + while (!Waiters_.empty() && FreeSlots_ >= Waiters_.front().Slots || frontWaiterOverflowsSlots()) { auto& waiter = Waiters_.front(); + if (frontWaiterOverflowsSlots()) { + // For "fat" request we need to acquire all total slots in semaphore. + YT_ASSERT(FreeSlots_ == TotalSlots_); + waiter.Slots = FreeSlots_; + } FreeSlots_ -= waiter.Slots; waitersToRelease.push_back(std::move(waiter)); Waiters_.pop(); @@ -82,6 +102,10 @@ bool TAsyncSemaphore::Acquire(i64 slots) YT_VERIFY(slots >= 0); auto guard = WriterGuard(SpinLock_); + if (EnableOverdraft_) { + slots = std::min(slots, TotalSlots_); + } + FreeSlots_ -= slots; return FreeSlots_ >= 0; @@ -92,6 +116,10 @@ bool TAsyncSemaphore::TryAcquire(i64 slots) YT_VERIFY(slots >= 0); auto guard = WriterGuard(SpinLock_); + if (EnableOverdraft_) { + slots = std::min(slots, TotalSlots_); + } + if (FreeSlots_ < slots) { return false; } @@ -104,6 +132,10 @@ TFuture TAsyncSemaphore::AsyncAcquire(i64 slots) YT_VERIFY(slots >= 0); auto guard = WriterGuard(SpinLock_); + if (EnableOverdraft_) { + slots = std::min(slots, TotalSlots_); + } + if (FreeSlots_ >= slots) { FreeSlots_ -= slots; return MakeFuture(TAsyncSemaphoreGuard(this, slots)); diff --git a/yt/yt/core/concurrency/async_semaphore.h b/yt/yt/core/concurrency/async_semaphore.h index a409cf00c7ac..b617c9725cae 100644 --- a/yt/yt/core/concurrency/async_semaphore.h +++ b/yt/yt/core/concurrency/async_semaphore.h @@ -54,6 +54,7 @@ class TAsyncSemaphore { public: explicit TAsyncSemaphore(i64 totalSlots); + TAsyncSemaphore(i64 totalSlots, bool enableOverdraft); //! Updates the total number of slots. void SetTotal(i64 totalSlots); @@ -95,6 +96,7 @@ class TAsyncSemaphore i64 TotalSlots_; i64 FreeSlots_; + bool EnableOverdraft_ = false; bool Releasing_ = false; TPromise ReadyEvent_; diff --git a/yt/yt/core/concurrency/unittests/async_semaphore_ut.cpp b/yt/yt/core/concurrency/unittests/async_semaphore_ut.cpp index d4fc4eeb347c..834784d816ec 100644 --- a/yt/yt/core/concurrency/unittests/async_semaphore_ut.cpp +++ b/yt/yt/core/concurrency/unittests/async_semaphore_ut.cpp @@ -4,6 +4,7 @@ #include #include +#include namespace NYT { namespace { @@ -26,6 +27,78 @@ TEST(TAsyncSemaphoreTest, CancelReadyEvent) EXPECT_TRUE(WaitFor(readyTwo).IsOK()); } +TEST(TAsyncSemaphoreTest, OverdraftSlots) +{ + constexpr static int ThreadCount = 4; + constexpr static int RequestCount = 10; + constexpr static int SemaphoreTotalSlots = 1; + constexpr static int RequestWeight = 100; + + auto threadPool = CreateThreadPool(ThreadCount, "SemaphoreAcqusition"); + auto semaphore = New(SemaphoreTotalSlots, /*enableOverdraft*/ true); + + { + std::vector> futures; + auto barrierPromise = NewPromise(); + for (int i = 0; i < RequestCount; ++i) { + futures.push_back(BIND([ + &semaphore, + barrierFuture = barrierPromise.ToFuture() + ] { + WaitForFast(barrierFuture) + .ThrowOnError(); + + WaitFor(semaphore->AsyncAcquire(RequestWeight).AsVoid()) + .ThrowOnError(); + }) + .AsyncVia(threadPool->GetInvoker()) + .Run()); + } + + barrierPromise.Set(); + + WaitFor(AllSucceeded(std::move(futures))) + .ThrowOnError(); + } + + { + semaphore->SetTotal(RequestWeight); + std::vector> futures; + auto barrierPromise = NewPromise(); + for (int i = 0; i < RequestCount; ++i) { + futures.push_back(BIND([ + &semaphore, + barrierFuture = barrierPromise.ToFuture() + ] { + WaitForFast(barrierFuture) + .ThrowOnError(); + + WaitFor(semaphore->AsyncAcquire(RequestWeight).AsVoid()) + .ThrowOnError(); + }) + .AsyncVia(threadPool->GetInvoker()) + .Run()); + } + + futures.push_back(BIND([ + &semaphore, + barrierFuture = barrierPromise.ToFuture() + ] { + WaitForFast(barrierFuture) + .ThrowOnError(); + + semaphore->SetTotal(SemaphoreTotalSlots); + }) + .AsyncVia(threadPool->GetInvoker()) + .Run()); + + barrierPromise.Set(); + + WaitFor(AllSucceeded(std::move(futures))) + .ThrowOnError(); + } +} + //////////////////////////////////////////////////////////////////////////////// } // namespace From 48608bc30375e16665a0971ebf1e7ef5b586e3e6 Mon Sep 17 00:00:00 2001 From: dimdim11 Date: Mon, 7 Apr 2025 10:56:19 +0300 Subject: [PATCH 008/454] Always taring WITH_JDK by python, patch tarinfo in python taring commit_hash:34dbae394624660e81ae61f12d5b87569025cdda --- build/conf/java.conf | 2 +- build/scripts/tar_directory.py | 48 ++++++++++++++++++++++------------ 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/build/conf/java.conf b/build/conf/java.conf index a73ef2634789..c05362ec5c44 100644 --- a/build/conf/java.conf +++ b/build/conf/java.conf @@ -1928,7 +1928,7 @@ macro WITH_JDK() { _OK=no } otherwise { - _PACK_JDK= && ${YMAKE_PYTHON3} ${input:"build/scripts/tar_directory.py"} --exclude "resource_info.json" --exclude "INSTALLED" --exclude "lnk" ${tared;output:"jdk.tar"} $WITH_JDK_RESOURCE $WITH_JDK_RESOURCE + _PACK_JDK= && ${YMAKE_PYTHON3} ${input:"build/scripts/tar_directory.py"} --tar-by-py --exclude "resource_info.json" --exclude "INSTALLED" --exclude "lnk" ${tared;output:"jdk.tar"} $WITH_JDK_RESOURCE $WITH_JDK_RESOURCE WITH_JDK_VALUE=yes } ASSERT(_OK [[alt1]]jdk[[rst]] name is prohibited for [[imp]]JAVA_PROGRAM[[rst]] module when [[imp]]WITH_JDK[[rst]] is used, [[imp]]WITH_JDK[[rst]] will be ignored.) diff --git a/build/scripts/tar_directory.py b/build/scripts/tar_directory.py index 0bb83cc5a266..bb5b0fe7d29d 100644 --- a/build/scripts/tar_directory.py +++ b/build/scripts/tar_directory.py @@ -2,9 +2,10 @@ import argparse import tarfile import subprocess +import stat -def is_exe(fpath): +def is_exe(fpath: str) -> bool: return os.path.isfile(fpath) and os.access(fpath, os.X_OK) @@ -12,9 +13,9 @@ def _usage() -> str: return "\n".join( [ "Usage:", - f"`tar_directory.py archive.tar directory [skip prefix] [--exclude fileOrDir0 ... --exclude fileOrDirN]`", + f"`tar_directory.py [--tar-by-py] [--exclude fileOrDir0 ... --exclude fileOrDirN] archive.tar directory [skip prefix]`", "or", - f"`tar_directory.py archive.tar output_directory --extract`", + f"`tar_directory.py [--tar-by-py] --extract archive.tar output_directory`", ] ) @@ -22,6 +23,7 @@ def _usage() -> str: def main(): parser = argparse.ArgumentParser(description='Make or extract tar archive') parser.add_argument('--extract', action="store_true", default=False, help="Extract archive") + parser.add_argument('--tar-by-py', action="store_true", default=False, help="Force use taring by python") parser.add_argument( '--exclude', type=str, action='append', default=[], help="Exclude for create archive (can use multiply times)" ) @@ -42,14 +44,16 @@ def main(): directory = args.directory prefix = args.prefix - for tar_exe in ('/usr/bin/tar', '/bin/tar'): + if args.extract: + dest = os.path.abspath(directory) + if not os.path.exists(dest): + os.makedirs(dest) + + for tar_exe in ('/usr/bin/tar', '/bin/tar') if not args.tar_by_py else []: if not is_exe(tar_exe): continue if args.extract: - dest = os.path.abspath(directory) - if not os.path.exists(dest): - os.makedirs(dest) - os.execv(tar_exe, [tar_exe, '-xf', tar, '-C', dest]) + command = [tar_exe, '-xf', tar, '-C', dest] else: source = os.path.relpath(directory, prefix) if prefix else directory command = ( @@ -59,29 +63,39 @@ def main(): + (['-C', prefix] if prefix else []) + [source] ) - subprocess.run(command, check=True) + subprocess.run(command, check=True) break else: if args.extract: - dest = os.path.abspath(directory) - if not os.path.exists(dest): - os.makedirs(dest) with tarfile.open(tar, 'r') as tar_file: tar_file.extractall(dest) else: source = directory with tarfile.open(tar, 'w') as out: - def filter(tarinfo): - for exclude in args.exclude: - if tarinfo.name.endswith(exclude): - return None + def filter(tarinfo: tarfile.TarInfo): + if args.exclude: + for exclude in args.exclude: + if tarinfo.name.endswith(exclude): + return None + tarinfo.mode = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH if tarinfo.mode | stat.S_IXUSR else 0 + tarinfo.mode = ( + tarinfo.mode | stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH + ) + # Set mtime to 1970-01-01 00:00:01, else if mtime == 0 + # it not used here https://a.yandex-team.ru/arcadia/contrib/python/python-libarchive/py3/libarchive/__init__.py#L355 + # But mtime != 0 also ignored by libarchive too :(( + tarinfo.mtime = 1 + tarinfo.uid = 0 + tarinfo.gid = 0 + tarinfo.uname = 'dummy' + tarinfo.gname = 'dummy' return tarinfo out.add( os.path.abspath(source), arcname=os.path.relpath(source, prefix) if prefix else source, - filter=filter if args.exclude else None, + filter=filter, ) From 057061d576bc4e6ae428ec366432fff30f010dec Mon Sep 17 00:00:00 2001 From: robot-ya-builder Date: Mon, 7 Apr 2025 11:23:17 +0300 Subject: [PATCH 009/454] Automatic release build for test_tool, os_ya, ya_bin, os_test_tool Update tools: test_tool, os_ya, ya_bin, os_test_tool commit_hash:15128871ddaf32f74b427dc3c18f763997ecda58 --- build/mapping.conf.json | 2 ++ build/platform/test_tool/host.ya.make.inc | 10 +++++----- build/platform/test_tool/host_os.ya.make.inc | 10 +++++----- ya | 20 ++++++++++---------- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/build/mapping.conf.json b/build/mapping.conf.json index 20b7b02c37f2..3f57e6a9895d 100644 --- a/build/mapping.conf.json +++ b/build/mapping.conf.json @@ -530,6 +530,7 @@ "8307046461": "{registry_endpoint}/8307046461", "8317487990": "{registry_endpoint}/8317487990", "8330113388": "{registry_endpoint}/8330113388", + "8444524403": "{registry_endpoint}/8444524403", "5486731632": "{registry_endpoint}/5486731632", "5514350352": "{registry_endpoint}/5514350352", "5514360398": "{registry_endpoint}/5514360398", @@ -1868,6 +1869,7 @@ "8307046461": "devtools/ya/test/programs/test_tool/bin/test_tool for linux", "8317487990": "devtools/ya/test/programs/test_tool/bin/test_tool for linux", "8330113388": "devtools/ya/test/programs/test_tool/bin/test_tool for linux", + "8444524403": "devtools/ya/test/programs/test_tool/bin/test_tool for linux", "5486731632": "devtools/ya/test/programs/test_tool/bin3/test_tool3 for linux", "5514350352": "devtools/ya/test/programs/test_tool/bin3/test_tool3 for linux", "5514360398": "devtools/ya/test/programs/test_tool/bin3/test_tool3 for linux", diff --git a/build/platform/test_tool/host.ya.make.inc b/build/platform/test_tool/host.ya.make.inc index 5a56ff614144..6409e58cecf8 100644 --- a/build/platform/test_tool/host.ya.make.inc +++ b/build/platform/test_tool/host.ya.make.inc @@ -1,12 +1,12 @@ IF (HOST_OS_DARWIN AND HOST_ARCH_X86_64) - DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8330137579) + DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8444533975) ELSEIF (HOST_OS_DARWIN AND HOST_ARCH_ARM64) - DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8330136361) + DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8444533039) ELSEIF (HOST_OS_LINUX AND HOST_ARCH_X86_64) - DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8330139159) + DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8444535565) ELSEIF (HOST_OS_LINUX AND HOST_ARCH_AARCH64) - DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8330135427) + DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8444532385) ELSEIF (HOST_OS_WINDOWS AND HOST_ARCH_X86_64) - DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8330138204) + DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8444534653) ENDIF() diff --git a/build/platform/test_tool/host_os.ya.make.inc b/build/platform/test_tool/host_os.ya.make.inc index c2121aab34a0..3f9e51b86fe3 100644 --- a/build/platform/test_tool/host_os.ya.make.inc +++ b/build/platform/test_tool/host_os.ya.make.inc @@ -1,12 +1,12 @@ IF (HOST_OS_DARWIN AND HOST_ARCH_X86_64) - DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8330112159) + DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8444523542) ELSEIF (HOST_OS_DARWIN AND HOST_ARCH_ARM64) - DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8330111405) + DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8444522906) ELSEIF (HOST_OS_LINUX AND HOST_ARCH_X86_64) - DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8330113388) + DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8444524403) ELSEIF (HOST_OS_LINUX AND HOST_ARCH_AARCH64) - DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8330110605) + DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8444522360) ELSEIF (HOST_OS_WINDOWS AND HOST_ARCH_X86_64) - DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8330112806) + DECLARE_EXTERNAL_RESOURCE(TEST_TOOL_HOST sbr:8444524083) ENDIF() diff --git a/ya b/ya index e5e2e43d06a0..a238376cf7e1 100755 --- a/ya +++ b/ya @@ -39,33 +39,33 @@ REGISTRY_ENDPOINT = os.environ.get("YA_REGISTRY_ENDPOINT", "https://devtools-reg PLATFORM_MAP = { "data": { "win32": { - "md5": "a37a12e8dfd75366674a4e0867e1bdcf", + "md5": "c30b4f739d1944c432a4516cc8173422", "urls": [ - f"{REGISTRY_ENDPOINT}/8330123223" + f"{REGISTRY_ENDPOINT}/8444538684" ] }, "darwin": { - "md5": "81d284479554c704db2c83d894a12ec4", + "md5": "ae118af75bd2cb6a07c0063163a154ed", "urls": [ - f"{REGISTRY_ENDPOINT}/8330122613" + f"{REGISTRY_ENDPOINT}/8444538171" ] }, "darwin-arm64": { - "md5": "ee214d7fbe2750cf06d6c813c1dd4a6a", + "md5": "3801ef527de1d1283f29d17b771cfe51", "urls": [ - f"{REGISTRY_ENDPOINT}/8330121658" + f"{REGISTRY_ENDPOINT}/8444536931" ] }, "linux-aarch64": { - "md5": "23da764827fbfdacdb4620d3182572b7", + "md5": "75c1f0a0272d4988d13e4a62594750a9", "urls": [ - f"{REGISTRY_ENDPOINT}/8330121109" + f"{REGISTRY_ENDPOINT}/8444536175" ] }, "linux": { - "md5": "a8a2eea8357637d746b3b3acfc9f6bbf", + "md5": "b1df6e5f2eea9923b6aab468b21c5935", "urls": [ - f"{REGISTRY_ENDPOINT}/8330124139" + f"{REGISTRY_ENDPOINT}/8444539167" ] } } From 3f113ee06ed713e51ace6c73c0bc8ba91def65ad Mon Sep 17 00:00:00 2001 From: vitalyisaev Date: Mon, 7 Apr 2025 11:39:40 +0300 Subject: [PATCH 010/454] YDB FQ: Support OpenSearch commit_hash:71b06636c44e364b3f8a92b8ee9c7017988bd7bf --- yql/essentials/providers/common/proto/gateways_config.proto | 1 + 1 file changed, 1 insertion(+) diff --git a/yql/essentials/providers/common/proto/gateways_config.proto b/yql/essentials/providers/common/proto/gateways_config.proto index b2d02ab3097f..3bb3da5be649 100644 --- a/yql/essentials/providers/common/proto/gateways_config.proto +++ b/yql/essentials/providers/common/proto/gateways_config.proto @@ -599,6 +599,7 @@ enum EGenericDataSourceKind { REDIS = 11; PROMETHEUS = 12; ICEBERG = 13; + OPENSEARCH = 14; } // EGenericProtocol generalizes various kinds of network protocols supported by different databases. From 4013e613e103e8c9d9a22206a7e1cdb5de185f72 Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Mon, 7 Apr 2025 12:29:31 +0300 Subject: [PATCH 011/454] Intermediate changes commit_hash:32ce16d8158d416147fcd7231a39bd5b3e9fa50f --- .../cxxsupp/builtins/.yandex_meta/build.ym | 2 +- contrib/libs/cxxsupp/builtins/ya.make | 4 +- .../python/pyparsing/py3/.dist-info/METADATA | 7 +- contrib/python/pyparsing/py3/README.rst | 4 +- .../pyparsing/py3/pyparsing/__init__.py | 4 +- .../python/pyparsing/py3/pyparsing/actions.py | 2 +- .../python/pyparsing/py3/pyparsing/core.py | 323 +++++++++++------- .../py3/pyparsing/diagram/__init__.py | 18 +- .../pyparsing/py3/pyparsing/exceptions.py | 11 +- .../python/pyparsing/py3/pyparsing/helpers.py | 44 ++- .../python/pyparsing/py3/pyparsing/results.py | 2 +- .../pyparsing/py3/pyparsing/tools/__init__.py | 0 .../tools/cvt_pyparsing_pep8_names.py | 116 +++++++ .../python/pyparsing/py3/pyparsing/util.py | 60 +++- contrib/python/pyparsing/py3/ya.make | 4 +- 15 files changed, 430 insertions(+), 171 deletions(-) create mode 100644 contrib/python/pyparsing/py3/pyparsing/tools/__init__.py create mode 100644 contrib/python/pyparsing/py3/pyparsing/tools/cvt_pyparsing_pep8_names.py diff --git a/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym b/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym index cecee81a03f0..d437597c8d3f 100644 --- a/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym +++ b/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym @@ -1,6 +1,6 @@ {% extends '//builtin/bag.ym' %} -{% block current_version %}20.1.1{% endblock %} +{% block current_version %}20.1.2{% endblock %} {% block current_url %} https://github.com/llvm/llvm-project/releases/download/llvmorg-{{self.version().strip()}}/compiler-rt-{{self.version().strip()}}.src.tar.xz diff --git a/contrib/libs/cxxsupp/builtins/ya.make b/contrib/libs/cxxsupp/builtins/ya.make index 67e47b1a65b8..c6c546c34136 100644 --- a/contrib/libs/cxxsupp/builtins/ya.make +++ b/contrib/libs/cxxsupp/builtins/ya.make @@ -12,9 +12,9 @@ LICENSE( LICENSE_TEXTS(.yandex_meta/licenses.list.txt) -VERSION(20.1.1) +VERSION(20.1.2) -ORIGINAL_SOURCE(https://github.com/llvm/llvm-project/releases/download/llvmorg-20.1.1/compiler-rt-20.1.1.src.tar.xz) +ORIGINAL_SOURCE(https://github.com/llvm/llvm-project/releases/download/llvmorg-20.1.2/compiler-rt-20.1.2.src.tar.xz) NO_COMPILER_WARNINGS() diff --git a/contrib/python/pyparsing/py3/.dist-info/METADATA b/contrib/python/pyparsing/py3/.dist-info/METADATA index 6b5fbefef606..ed52278486a0 100644 --- a/contrib/python/pyparsing/py3/.dist-info/METADATA +++ b/contrib/python/pyparsing/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pyparsing -Version: 3.2.1 +Version: 3.2.2 Summary: pyparsing module - Classes and methods to define and execute parsing grammars Author-email: Paul McGuire Requires-Python: >=3.9 @@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy @@ -56,7 +57,7 @@ Here is a program to parse ``"Hello, World!"`` (or any greeting of the form from pyparsing import Word, alphas greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" - print(hello, "->", greet.parseString(hello)) + print(hello, "->", greet.parse_string(hello)) The program outputs the following:: @@ -66,7 +67,7 @@ The Python representation of the grammar is quite readable, owing to the self-explanatory class names, and the use of '+', '|' and '^' operator definitions. -The parsed results returned from ``parseString()`` is a collection of type +The parsed results returned from ``parse_string()`` is a collection of type ``ParseResults``, which can be accessed as a nested list, a dictionary, or an object with named attributes. diff --git a/contrib/python/pyparsing/py3/README.rst b/contrib/python/pyparsing/py3/README.rst index 24d603c7bc40..cfb9889f8540 100644 --- a/contrib/python/pyparsing/py3/README.rst +++ b/contrib/python/pyparsing/py3/README.rst @@ -26,7 +26,7 @@ Here is a program to parse ``"Hello, World!"`` (or any greeting of the form from pyparsing import Word, alphas greet = Word(alphas) + "," + Word(alphas) + "!" hello = "Hello, World!" - print(hello, "->", greet.parseString(hello)) + print(hello, "->", greet.parse_string(hello)) The program outputs the following:: @@ -36,7 +36,7 @@ The Python representation of the grammar is quite readable, owing to the self-explanatory class names, and the use of '+', '|' and '^' operator definitions. -The parsed results returned from ``parseString()`` is a collection of type +The parsed results returned from ``parse_string()`` is a collection of type ``ParseResults``, which can be accessed as a nested list, a dictionary, or an object with named attributes. diff --git a/contrib/python/pyparsing/py3/pyparsing/__init__.py b/contrib/python/pyparsing/py3/pyparsing/__init__.py index 726c76cb2449..fa1f2abe67e5 100644 --- a/contrib/python/pyparsing/py3/pyparsing/__init__.py +++ b/contrib/python/pyparsing/py3/pyparsing/__init__.py @@ -120,8 +120,8 @@ def __repr__(self): return f"{__name__}.{type(self).__name__}({', '.join('{}={!r}'.format(*nv) for nv in zip(self._fields, self))})" -__version_info__ = version_info(3, 2, 1, "final", 1) -__version_time__ = "31 Dec 2024 20:41 UTC" +__version_info__ = version_info(3, 2, 2, "final", 1) +__version_time__ = "22 Mar 2025 22:09 UTC" __version__ = __version_info__.__version__ __versionTime__ = __version_time__ __author__ = "Paul McGuire " diff --git a/contrib/python/pyparsing/py3/pyparsing/actions.py b/contrib/python/pyparsing/py3/pyparsing/actions.py index f491aab986e9..0153cc7132ab 100644 --- a/contrib/python/pyparsing/py3/pyparsing/actions.py +++ b/contrib/python/pyparsing/py3/pyparsing/actions.py @@ -22,7 +22,7 @@ class OnlyOnce: Note: parse action signature must include all 3 arguments. """ - def __init__(self, method_call: Callable[[str, int, ParseResults], Any]): + def __init__(self, method_call: Callable[[str, int, ParseResults], Any]) -> None: from .core import _trim_arity self.callable = _trim_arity(method_call) diff --git a/contrib/python/pyparsing/py3/pyparsing/core.py b/contrib/python/pyparsing/py3/pyparsing/core.py index b884e2d4a40b..86be949ad473 100644 --- a/contrib/python/pyparsing/py3/pyparsing/core.py +++ b/contrib/python/pyparsing/py3/pyparsing/core.py @@ -38,7 +38,6 @@ __config_flags, _collapse_string_to_ranges, _escape_regex_range_chars, - _bslash, _flatten, LRUMemo as _LRUMemo, UnboundedMemo as _UnboundedMemo, @@ -246,7 +245,7 @@ class _ParseActionIndexError(Exception): ParserElement parseImpl methods. """ - def __init__(self, msg: str, exc: BaseException): + def __init__(self, msg: str, exc: BaseException) -> None: self.msg: str = msg self.exc: BaseException = exc @@ -355,7 +354,7 @@ def _default_start_debug_action( ( f"{cache_hit_str}Match {expr} at loc {loc}({lineno(loc, instring)},{col(loc, instring)})\n" f" {line(loc, instring)}\n" - f" {' ' * (col(loc, instring) - 1)}^" + f" {'^':>{col(loc, instring)}}" ) ) @@ -454,7 +453,7 @@ class DebugActions(NamedTuple): debug_match: typing.Optional[DebugSuccessAction] debug_fail: typing.Optional[DebugExceptionAction] - def __init__(self, savelist: bool = False): + def __init__(self, savelist: bool = False) -> None: self.parseAction: list[ParseAction] = list() self.failAction: typing.Optional[ParseFailAction] = None self.customName: str = None # type: ignore[assignment] @@ -465,7 +464,7 @@ def __init__(self, savelist: bool = False): self.whiteChars = set(ParserElement.DEFAULT_WHITE_CHARS) self.copyDefaultWhiteChars = True # used when checking for left-recursion - self.mayReturnEmpty = False + self._may_return_empty = False self.keepTabs = False self.ignoreExprs: list[ParserElement] = list() self.debug = False @@ -483,6 +482,14 @@ def __init__(self, savelist: bool = False): self.suppress_warnings_: list[Diagnostics] = [] self.show_in_diagram = True + @property + def mayReturnEmpty(self): + return self._may_return_empty + + @mayReturnEmpty.setter + def mayReturnEmpty(self, value): + self._may_return_empty = value + def suppress_warning(self, warning_type: Diagnostics) -> ParserElement: """ Suppress warnings emitted for a particular diagnostic on this expression. @@ -2264,6 +2271,7 @@ def create_diagram( show_results_names: bool = False, show_groups: bool = False, embed: bool = False, + show_hidden: bool = False, **kwargs, ) -> None: """ @@ -2278,6 +2286,7 @@ def create_diagram( - ``show_results_names`` - bool flag whether diagram should show annotations for defined results names - ``show_groups`` - bool flag whether groups should be highlighted with an unlabeled surrounding box + - ``show_hidden`` - bool flag to show diagram elements for internal elements that are usually hidden - ``embed`` - bool flag whether generated HTML should omit , , and tags to embed the resulting HTML in an enclosing HTML source - ``head`` - str containing additional HTML to insert into the section of the generated code; @@ -2303,6 +2312,7 @@ def create_diagram( vertical=vertical, show_results_names=show_results_names, show_groups=show_groups, + show_hidden=show_hidden, diagram_kwargs=kwargs, ) if not isinstance(output_html, (str, Path)): @@ -2352,7 +2362,7 @@ def create_diagram( class _PendingSkip(ParserElement): # internal placeholder class to hold a place were '...' is added to a parser element, # once another ParserElement is added, this placeholder will be replaced with a SkipTo - def __init__(self, expr: ParserElement, must_skip: bool = False): + def __init__(self, expr: ParserElement, must_skip: bool = False) -> None: super().__init__() self.anchor = expr self.must_skip = must_skip @@ -2395,7 +2405,7 @@ class Token(ParserElement): matching patterns. """ - def __init__(self): + def __init__(self) -> None: super().__init__(savelist=False) def _generateDefaultName(self) -> str: @@ -2407,9 +2417,9 @@ class NoMatch(Token): A token that will never match. """ - def __init__(self): + def __init__(self) -> None: super().__init__() - self.mayReturnEmpty = True + self._may_return_empty = True self.mayIndexError = False self.errmsg = "Unmatchable token" @@ -2449,14 +2459,14 @@ def __new__(cls, match_string: str = "", *, matchString: str = ""): def __getnewargs__(self): return (self.match,) - def __init__(self, match_string: str = "", *, matchString: str = ""): + def __init__(self, match_string: str = "", *, matchString: str = "") -> None: super().__init__() match_string = matchString or match_string self.match = match_string self.matchLen = len(match_string) self.firstMatchChar = match_string[:1] self.errmsg = f"Expected {self.name}" - self.mayReturnEmpty = False + self._may_return_empty = False self.mayIndexError = False def _generateDefaultName(self) -> str: @@ -2475,9 +2485,9 @@ class Empty(Literal): An empty token, will always match. """ - def __init__(self, match_string="", *, matchString=""): + def __init__(self, match_string="", *, matchString="") -> None: super().__init__("") - self.mayReturnEmpty = True + self._may_return_empty = True self.mayIndexError = False def _generateDefaultName(self) -> str: @@ -2534,7 +2544,7 @@ def __init__( *, matchString: str = "", identChars: typing.Optional[str] = None, - ): + ) -> None: super().__init__() identChars = identChars or ident_chars if identChars is None: @@ -2546,7 +2556,7 @@ def __init__( if not self.firstMatchChar: raise ValueError("null string passed to Keyword; use Empty() instead") self.errmsg = f"Expected {type(self).__name__} {self.name}" - self.mayReturnEmpty = False + self._may_return_empty = False self.mayIndexError = False self.caseless = caseless if caseless: @@ -2628,7 +2638,7 @@ class CaselessLiteral(Literal): (Contrast with example for :class:`CaselessKeyword`.) """ - def __init__(self, match_string: str = "", *, matchString: str = ""): + def __init__(self, match_string: str = "", *, matchString: str = "") -> None: match_string = matchString or match_string super().__init__(match_string.upper()) # Preserve the defining literal. @@ -2660,7 +2670,7 @@ def __init__( *, matchString: str = "", identChars: typing.Optional[str] = None, - ): + ) -> None: identChars = identChars or ident_chars match_string = matchString or match_string super().__init__(match_string, identChars, caseless=True) @@ -2708,7 +2718,7 @@ def __init__( *, maxMismatches: int = 1, caseless=False, - ): + ) -> None: maxMismatches = max_mismatches if max_mismatches is not None else maxMismatches super().__init__() self.match_string = match_string @@ -2716,7 +2726,7 @@ def __init__( self.errmsg = f"Expected {self.match_string!r} (with up to {self.maxMismatches} mismatches)" self.caseless = caseless self.mayIndexError = False - self.mayReturnEmpty = False + self._may_return_empty = False def _generateDefaultName(self) -> str: return f"{type(self).__name__}:{self.match_string!r}" @@ -2834,7 +2844,7 @@ def __init__( bodyChars: typing.Optional[str] = None, asKeyword: bool = False, excludeChars: typing.Optional[str] = None, - ): + ) -> None: initChars = initChars or init_chars bodyChars = bodyChars or body_chars asKeyword = asKeyword or as_keyword @@ -3018,7 +3028,7 @@ def __init__( *, asKeyword: bool = False, excludeChars: typing.Optional[str] = None, - ): + ) -> None: asKeyword = asKeyword or as_keyword excludeChars = excludeChars or exclude_chars super().__init__( @@ -3060,7 +3070,7 @@ def __init__( *, asGroupList: bool = False, asMatch: bool = False, - ): + ) -> None: """The parameters ``pattern`` and ``flags`` are passed to the ``re.compile()`` function as-is. See the Python `re module `_ module for an @@ -3075,15 +3085,18 @@ def __init__( raise ValueError("null string passed to Regex; use Empty() instead") self._re = None + self._may_return_empty = None # type: ignore [assignment] self.reString = self.pattern = pattern elif hasattr(pattern, "pattern") and hasattr(pattern, "match"): self._re = pattern + self._may_return_empty = None # type: ignore [assignment] self.pattern = self.reString = pattern.pattern elif callable(pattern): # defer creating this pattern until we really need it self.pattern = pattern + self._may_return_empty = None # type: ignore [assignment] self._re = None else: @@ -3120,23 +3133,38 @@ def re(self) -> re.Pattern: try: self._re = re.compile(self.pattern, self.flags) - return self._re except re.error: raise ValueError(f"invalid pattern ({self.pattern!r}) passed to Regex") + else: + self._may_return_empty = self.re.match("", pos=0) is not None + return self._re @cached_property def re_match(self) -> Callable[[str, int], Any]: return self.re.match - @cached_property - def mayReturnEmpty(self) -> bool: # type: ignore[override] - return self.re_match("", 0) is not None + @property + def mayReturnEmpty(self): + if self._may_return_empty is None: + # force compile of regex pattern, to set may_return_empty flag + self.re # noqa + return self._may_return_empty + + @mayReturnEmpty.setter + def mayReturnEmpty(self, value): + self._may_return_empty = value def _generateDefaultName(self) -> str: unescaped = repr(self.pattern).replace("\\\\", "\\") return f"Re:({unescaped})" def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: + # explicit check for matching past the length of the string; + # this is done because the re module will not complain about + # a match with `pos > len(instring)`, it will just return "" + if loc > len(instring) and self.mayReturnEmpty: + raise ParseException(instring, loc, self.errmsg, self) + result = self.re_match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) @@ -3151,6 +3179,9 @@ def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: return loc, ret def parseImplAsGroupList(self, instring, loc, do_actions=True): + if loc > len(instring) and self.mayReturnEmpty: + raise ParseException(instring, loc, self.errmsg, self) + result = self.re_match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) @@ -3160,6 +3191,9 @@ def parseImplAsGroupList(self, instring, loc, do_actions=True): return loc, ret def parseImplAsMatch(self, instring, loc, do_actions=True): + if loc > len(instring) and self.mayReturnEmpty: + raise ParseException(instring, loc, self.errmsg, self) + result = self.re_match(instring, loc) if not result: raise ParseException(instring, loc, self.errmsg, self) @@ -3258,7 +3292,7 @@ def __init__( unquoteResults: bool = True, endQuoteChar: typing.Optional[str] = None, convertWhitespaceEscapes: bool = True, - ): + ) -> None: super().__init__() esc_char = escChar or esc_char esc_quote = escQuote or esc_quote @@ -3362,7 +3396,7 @@ def __init__( self.errmsg = f"Expected {self.name}" self.mayIndexError = False - self.mayReturnEmpty = True + self._may_return_empty = True def _generateDefaultName(self) -> str: if self.quote_char == self.end_quote_char and isinstance( @@ -3465,7 +3499,7 @@ def __init__( exact: int = 0, *, notChars: str = "", - ): + ) -> None: super().__init__() self.skipWhitespace = False self.notChars = not_chars or notChars @@ -3489,7 +3523,7 @@ def __init__( self.minLen = exact self.errmsg = f"Expected {self.name}" - self.mayReturnEmpty = self.minLen == 0 + self._may_return_empty = self.minLen == 0 self.mayIndexError = False def _generateDefaultName(self) -> str: @@ -3552,7 +3586,9 @@ class White(Token): "\u3000": "", } - def __init__(self, ws: str = " \t\r\n", min: int = 1, max: int = 0, exact: int = 0): + def __init__( + self, ws: str = " \t\r\n", min: int = 1, max: int = 0, exact: int = 0 + ) -> None: super().__init__() self.matchWhite = ws self.set_whitespace_chars( @@ -3560,7 +3596,7 @@ def __init__(self, ws: str = " \t\r\n", min: int = 1, max: int = 0, exact: int = copy_defaults=True, ) # self.leave_whitespace() - self.mayReturnEmpty = True + self._may_return_empty = True self.errmsg = f"Expected {self.name}" self.minLen = min @@ -3594,9 +3630,9 @@ def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: class PositionToken(Token): - def __init__(self): + def __init__(self) -> None: super().__init__() - self.mayReturnEmpty = True + self._may_return_empty = True self.mayIndexError = False @@ -3605,7 +3641,7 @@ class GoToColumn(PositionToken): tabular report scraping. """ - def __init__(self, colno: int): + def __init__(self, colno: int) -> None: super().__init__() self.col = colno @@ -3657,7 +3693,7 @@ class LineStart(PositionToken): """ - def __init__(self): + def __init__(self) -> None: super().__init__() self.leave_whitespace() self.orig_whiteChars = set() | self.whiteChars @@ -3688,7 +3724,7 @@ class LineEnd(PositionToken): parse string """ - def __init__(self): + def __init__(self) -> None: super().__init__() self.whiteChars.discard("\n") self.set_whitespace_chars(self.whiteChars, copy_defaults=False) @@ -3711,7 +3747,7 @@ class StringStart(PositionToken): string """ - def __init__(self): + def __init__(self) -> None: super().__init__() self.set_name("start of text") @@ -3728,7 +3764,7 @@ class StringEnd(PositionToken): Matches if current position is at the end of the parse string """ - def __init__(self): + def __init__(self) -> None: super().__init__() self.set_name("end of text") @@ -3753,7 +3789,9 @@ class WordStart(PositionToken): a line. """ - def __init__(self, word_chars: str = printables, *, wordChars: str = printables): + def __init__( + self, word_chars: str = printables, *, wordChars: str = printables + ) -> None: wordChars = word_chars if wordChars == printables else wordChars super().__init__() self.wordChars = set(wordChars) @@ -3778,7 +3816,9 @@ class WordEnd(PositionToken): of a line. """ - def __init__(self, word_chars: str = printables, *, wordChars: str = printables): + def __init__( + self, word_chars: str = printables, *, wordChars: str = printables + ) -> None: wordChars = word_chars if wordChars == printables else wordChars super().__init__() self.wordChars = set(wordChars) @@ -3822,14 +3862,15 @@ class Tag(Token): - enthusiastic: True """ - def __init__(self, tag_name: str, value: Any = True): + def __init__(self, tag_name: str, value: Any = True) -> None: super().__init__() - self.mayReturnEmpty = True + self._may_return_empty = True self.mayIndexError = False self.leave_whitespace() self.tag_name = tag_name self.tag_value = value self.add_parse_action(self._add_tag) + self.show_in_diagram = False def _add_tag(self, tokens: ParseResults): tokens[self.tag_name] = self.tag_value @@ -3843,7 +3884,9 @@ class ParseExpression(ParserElement): post-processing parsed tokens. """ - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): + def __init__( + self, exprs: typing.Iterable[ParserElement], savelist: bool = False + ) -> None: super().__init__(savelist) self.exprs: list[ParserElement] if isinstance(exprs, _generatorType): @@ -3939,7 +3982,7 @@ def streamline(self) -> ParserElement: ): self.exprs = other.exprs[:] + [self.exprs[1]] self._defaultName = None - self.mayReturnEmpty |= other.mayReturnEmpty + self._may_return_empty |= other.mayReturnEmpty self.mayIndexError |= other.mayIndexError other = self.exprs[-1] @@ -3951,7 +3994,7 @@ def streamline(self) -> ParserElement: ): self.exprs = self.exprs[:-1] + other.exprs[:] self._defaultName = None - self.mayReturnEmpty |= other.mayReturnEmpty + self._may_return_empty |= other.mayReturnEmpty self.mayIndexError |= other.mayIndexError self.errmsg = f"Expected {self}" @@ -4028,7 +4071,7 @@ class And(ParseExpression): """ class _ErrorStop(Empty): - def __init__(self, *args, **kwargs): + def __init__(self, *args, **kwargs) -> None: super().__init__(*args, **kwargs) self.leave_whitespace() @@ -4036,28 +4079,34 @@ def _generateDefaultName(self) -> str: return "-" def __init__( - self, exprs_arg: typing.Iterable[ParserElement], savelist: bool = True - ): - exprs: list[ParserElement] = list(exprs_arg) - if exprs and Ellipsis in exprs: - tmp: list[ParserElement] = [] - for i, expr in enumerate(exprs): - if expr is not Ellipsis: - tmp.append(expr) - continue + self, + exprs_arg: typing.Iterable[Union[ParserElement, str]], + savelist: bool = True, + ) -> None: + # instantiate exprs as a list, converting strs to ParserElements + exprs: list[ParserElement] = [ + self._literalStringClass(e) if isinstance(e, str) else e for e in exprs_arg + ] - if i < len(exprs) - 1: - skipto_arg: ParserElement = typing.cast( - ParseExpression, (Empty() + exprs[i + 1]) - ).exprs[-1] - tmp.append(SkipTo(skipto_arg)("_skipped*")) - continue + # convert any Ellipsis elements to SkipTo + if Ellipsis in exprs: + # Ellipsis cannot be the last element + if exprs[-1] is Ellipsis: raise Exception("cannot construct And with sequence ending in ...") - exprs[:] = tmp + + tmp: list[ParserElement] = [] + for cur_expr, next_expr in zip(exprs, exprs[1:]): + if cur_expr is Ellipsis: + tmp.append(SkipTo(next_expr)("_skipped*")) + else: + tmp.append(cur_expr) + + exprs[:-1] = tmp + super().__init__(exprs, savelist) if self.exprs: - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = all(e.mayReturnEmpty for e in self.exprs) if not isinstance(self.exprs[0], White): self.set_whitespace_chars( self.exprs[0].whiteChars, @@ -4067,7 +4116,7 @@ def __init__( else: self.skipWhitespace = False else: - self.mayReturnEmpty = True + self._may_return_empty = True self.callPreparse = True def streamline(self) -> ParserElement: @@ -4117,7 +4166,7 @@ def streamline(self) -> ParserElement: break cur = typing.cast(ParserElement, next_first) - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = all(e.mayReturnEmpty for e in self.exprs) return self def parseImpl(self, instring, loc, do_actions=True): @@ -4189,18 +4238,20 @@ class Or(ParseExpression): [['123'], ['3.1416'], ['789']] """ - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): + def __init__( + self, exprs: typing.Iterable[ParserElement], savelist: bool = False + ) -> None: super().__init__(exprs, savelist) if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = any(e.mayReturnEmpty for e in self.exprs) self.skipWhitespace = all(e.skipWhitespace for e in self.exprs) else: - self.mayReturnEmpty = True + self._may_return_empty = True def streamline(self) -> ParserElement: super().streamline() if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = any(e.mayReturnEmpty for e in self.exprs) self.saveAsList = any(e.saveAsList for e in self.exprs) self.skipWhitespace = all( e.skipWhitespace and not isinstance(e, White) for e in self.exprs @@ -4286,7 +4337,8 @@ def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if maxException is not None: # infer from this check that all alternatives failed at the current position # so emit this collective error message instead of any single error message - if maxExcLoc == loc: + parse_start_loc = self.preParse(instring, loc) + if maxExcLoc == parse_start_loc: maxException.msg = self.errmsg or "" raise maxException @@ -4344,13 +4396,15 @@ class MatchFirst(ParseExpression): print(number.search_string("123 3.1416 789")) # Better -> [['123'], ['3.1416'], ['789']] """ - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False): + def __init__( + self, exprs: typing.Iterable[ParserElement], savelist: bool = False + ) -> None: super().__init__(exprs, savelist) if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = any(e.mayReturnEmpty for e in self.exprs) self.skipWhitespace = all(e.skipWhitespace for e in self.exprs) else: - self.mayReturnEmpty = True + self._may_return_empty = True def streamline(self) -> ParserElement: if self.streamlined: @@ -4359,13 +4413,13 @@ def streamline(self) -> ParserElement: super().streamline() if self.exprs: self.saveAsList = any(e.saveAsList for e in self.exprs) - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = any(e.mayReturnEmpty for e in self.exprs) self.skipWhitespace = all( e.skipWhitespace and not isinstance(e, White) for e in self.exprs ) else: self.saveAsList = False - self.mayReturnEmpty = True + self._may_return_empty = True return self def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: @@ -4393,7 +4447,8 @@ def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: if maxException is not None: # infer from this check that all alternatives failed at the current position # so emit this collective error message instead of any individual error message - if maxExcLoc == loc: + parse_start_loc = self.preParse(instring, loc) + if maxExcLoc == parse_start_loc: maxException.msg = self.errmsg or "" raise maxException @@ -4491,12 +4546,14 @@ class Each(ParseExpression): - size: 20 """ - def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = True): + def __init__( + self, exprs: typing.Iterable[ParserElement], savelist: bool = True + ) -> None: super().__init__(exprs, savelist) if self.exprs: - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = all(e.mayReturnEmpty for e in self.exprs) else: - self.mayReturnEmpty = True + self._may_return_empty = True self.skipWhitespace = True self.initExprGroups = True self.saveAsList = True @@ -4511,9 +4568,9 @@ def __iand__(self, other): def streamline(self) -> ParserElement: super().streamline() if self.exprs: - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) + self._may_return_empty = all(e.mayReturnEmpty for e in self.exprs) else: - self.mayReturnEmpty = True + self._may_return_empty = True return self def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: @@ -4612,7 +4669,7 @@ class ParseElementEnhance(ParserElement): post-processing parsed tokens. """ - def __init__(self, expr: Union[ParserElement, str], savelist: bool = False): + def __init__(self, expr: Union[ParserElement, str], savelist: bool = False) -> None: super().__init__(savelist) if isinstance(expr, str_type): expr_str = typing.cast(str, expr) @@ -4626,7 +4683,7 @@ def __init__(self, expr: Union[ParserElement, str], savelist: bool = False): self.expr = expr if expr is not None: self.mayIndexError = expr.mayIndexError - self.mayReturnEmpty = expr.mayReturnEmpty + self._may_return_empty = expr.mayReturnEmpty self.set_whitespace_chars( expr.whiteChars, copy_defaults=expr.copyDefaultWhiteChars ) @@ -4724,20 +4781,20 @@ class IndentedBlock(ParseElementEnhance): """ class _Indent(Empty): - def __init__(self, ref_col: int): + def __init__(self, ref_col: int) -> None: super().__init__() self.errmsg = f"expected indent at column {ref_col}" self.add_condition(lambda s, l, t: col(l, s) == ref_col) class _IndentGreater(Empty): - def __init__(self, ref_col: int): + def __init__(self, ref_col: int) -> None: super().__init__() self.errmsg = f"expected indent at column greater than {ref_col}" self.add_condition(lambda s, l, t: col(l, s) > ref_col) def __init__( self, expr: ParserElement, *, recursive: bool = False, grouped: bool = True - ): + ) -> None: super().__init__(expr, savelist=True) # if recursive: # raise NotImplementedError("IndentedBlock with recursive is not implemented") @@ -4792,7 +4849,7 @@ class AtStringStart(ParseElementEnhance): # raises ParseException """ - def __init__(self, expr: Union[ParserElement, str]): + def __init__(self, expr: Union[ParserElement, str]) -> None: super().__init__(expr) self.callPreparse = False @@ -4825,7 +4882,7 @@ class AtLineStart(ParseElementEnhance): """ - def __init__(self, expr: Union[ParserElement, str]): + def __init__(self, expr: Union[ParserElement, str]) -> None: super().__init__(expr) self.callPreparse = False @@ -4858,9 +4915,9 @@ class FollowedBy(ParseElementEnhance): [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']] """ - def __init__(self, expr: Union[ParserElement, str]): + def __init__(self, expr: Union[ParserElement, str]) -> None: super().__init__(expr) - self.mayReturnEmpty = True + self._may_return_empty = True def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: # by using self._expr.parse and deleting the contents of the returned ParseResults list @@ -4901,10 +4958,10 @@ class PrecededBy(ParseElementEnhance): """ - def __init__(self, expr: Union[ParserElement, str], retreat: int = 0): + def __init__(self, expr: Union[ParserElement, str], retreat: int = 0) -> None: super().__init__(expr) self.expr = self.expr().leave_whitespace() - self.mayReturnEmpty = True + self._may_return_empty = True self.mayIndexError = False self.exact = False if isinstance(expr, str_type): @@ -5019,13 +5076,13 @@ class NotAny(ParseElementEnhance): integer = Word(nums) + ~Char(".") """ - def __init__(self, expr: Union[ParserElement, str]): + def __init__(self, expr: Union[ParserElement, str]) -> None: super().__init__(expr) # do NOT use self.leave_whitespace(), don't want to propagate to exprs # self.leave_whitespace() self.skipWhitespace = False - self.mayReturnEmpty = True + self._may_return_empty = True self.errmsg = f"Found unwanted token, {self.expr}" def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: @@ -5044,7 +5101,7 @@ def __init__( stop_on: typing.Optional[Union[ParserElement, str]] = None, *, stopOn: typing.Optional[Union[ParserElement, str]] = None, - ): + ) -> None: super().__init__(expr) stopOn = stopOn or stop_on self.saveAsList = True @@ -5062,9 +5119,10 @@ def stopOn(self, ender) -> ParserElement: def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: self_expr_parse = self.expr._parse self_skip_ignorables = self._skipIgnorables - check_ender = self.not_ender is not None - if check_ender: + check_ender = False + if self.not_ender is not None: try_not_ender = self.not_ender.try_parse + check_ender = True # must be at least one (but first see if we are the stopOn sentinel; # if so, fail) @@ -5165,9 +5223,9 @@ def __init__( stop_on: typing.Optional[Union[ParserElement, str]] = None, *, stopOn: typing.Optional[Union[ParserElement, str]] = None, - ): + ) -> None: super().__init__(expr, stopOn=stopOn or stop_on) - self.mayReturnEmpty = True + self._may_return_empty = True def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: try: @@ -5189,7 +5247,7 @@ def __init__( max: typing.Optional[int] = None, *, allow_trailing_delim: bool = False, - ): + ) -> None: """Helper to define a delimited list of expressions - the delimiter defaults to ','. By default, the list elements and delimiters can have intervening whitespace, and comments, but this can be @@ -5296,11 +5354,11 @@ class Opt(ParseElementEnhance): def __init__( self, expr: Union[ParserElement, str], default: Any = __optionalNotMatched - ): + ) -> None: super().__init__(expr, savelist=False) self.saveAsList = self.expr.saveAsList self.defaultValue = default - self.mayReturnEmpty = True + self._may_return_empty = True def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: self_expr = self.expr @@ -5401,11 +5459,11 @@ def __init__( fail_on: typing.Optional[Union[ParserElement, str]] = None, *, failOn: typing.Optional[Union[ParserElement, str]] = None, - ): + ) -> None: super().__init__(other) failOn = failOn or fail_on self.ignoreExpr = ignore - self.mayReturnEmpty = True + self._may_return_empty = True self.mayIndexError = False self.includeMatch = include self.saveAsList = False @@ -5512,7 +5570,9 @@ class Forward(ParseElementEnhance): parser created using ``Forward``. """ - def __init__(self, other: typing.Optional[Union[ParserElement, str]] = None): + def __init__( + self, other: typing.Optional[Union[ParserElement, str]] = None + ) -> None: self.caller_frame = traceback.extract_stack(limit=2)[0] super().__init__(other, savelist=False) # type: ignore[arg-type] self.lshift_line = None @@ -5529,7 +5589,7 @@ def __lshift__(self, other) -> Forward: self.expr = other self.streamlined = other.streamlined self.mayIndexError = self.expr.mayIndexError - self.mayReturnEmpty = self.expr.mayReturnEmpty + self._may_return_empty = self.expr.mayReturnEmpty self.set_whitespace_chars( self.expr.whiteChars, copy_defaults=self.expr.copyDefaultWhiteChars ) @@ -5648,7 +5708,7 @@ def parseImpl(self, instring, loc, do_actions=True) -> ParseImplReturnType: try: new_loc, new_peek = super().parseImpl(instring, loc, False) except ParseException: - # we failed before getting any match – do not hide the error + # we failed before getting any match - do not hide the error if isinstance(prev_peek, Exception): raise new_loc, new_peek = prev_loc, prev_peek @@ -5703,17 +5763,20 @@ def validate(self, validateTrace=None) -> None: def _generateDefaultName(self) -> str: # Avoid infinite recursion by setting a temporary _defaultName + save_default_name = self._defaultName self._defaultName = ": ..." # Use the string representation of main expression. - retString = "..." try: if self.expr is not None: - retString = str(self.expr)[:1000] + ret_string = str(self.expr)[:1000] else: - retString = "None" - finally: - return f"{type(self).__name__}: {retString}" + ret_string = "None" + except Exception: + ret_string = "..." + + self._defaultName = save_default_name + return f"{type(self).__name__}: {ret_string}" def copy(self) -> ParserElement: if self.expr is not None: @@ -5752,7 +5815,7 @@ class TokenConverter(ParseElementEnhance): Abstract subclass of :class:`ParseElementEnhance`, for converting parsed results. """ - def __init__(self, expr: Union[ParserElement, str], savelist=False): + def __init__(self, expr: Union[ParserElement, str], savelist=False) -> None: super().__init__(expr) # , savelist) self.saveAsList = False @@ -5783,7 +5846,7 @@ def __init__( adjacent: bool = True, *, joinString: typing.Optional[str] = None, - ): + ) -> None: super().__init__(expr) joinString = joinString if joinString is not None else join_string # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself @@ -5835,7 +5898,7 @@ class Group(TokenConverter): # -> ['fn', ['a', 'b', '100']] """ - def __init__(self, expr: ParserElement, aslist: bool = False): + def __init__(self, expr: ParserElement, aslist: bool = False) -> None: super().__init__(expr) self.saveAsList = True self._asPythonList = aslist @@ -5893,7 +5956,7 @@ class Dict(TokenConverter): See more examples at :class:`ParseResults` of accessing fields by results name. """ - def __init__(self, expr: ParserElement, asdict: bool = False): + def __init__(self, expr: ParserElement, asdict: bool = False) -> None: super().__init__(expr) self.saveAsList = True self._asPythonDict = asdict @@ -5969,7 +6032,7 @@ class Suppress(TokenConverter): (See also :class:`DelimitedList`.) """ - def __init__(self, expr: Union[ParserElement, str], savelist: bool = False): + def __init__(self, expr: Union[ParserElement, str], savelist: bool = False) -> None: if expr is ...: expr = _PendingSkip(NoMatch()) super().__init__(expr) @@ -6094,13 +6157,17 @@ def srange(s: str) -> str: - any combination of the above (``'aeiouy'``, ``'a-zA-Z0-9_$'``, etc.) """ - _expanded = lambda p: ( - p - if not isinstance(p, ParseResults) - else "".join(chr(c) for c in range(ord(p[0]), ord(p[1]) + 1)) - ) + + def _expanded(p): + if isinstance(p, ParseResults): + yield from (chr(c) for c in range(ord(p[0]), ord(p[1]) + 1)) + else: + yield p + try: - return "".join(_expanded(part) for part in _reBracketExpr.parse_string(s).body) + return "".join( + [c for part in _reBracketExpr.parse_string(s).body for c in _expanded(part)] + ) except Exception as e: return "" @@ -6156,11 +6223,17 @@ def autoname_elements() -> None: Utility to simplify mass-naming of parser elements, for generating railroad diagram with named subdiagrams. """ - calling_frame = sys._getframe(1) + + # guard against _getframe not being implemented in the current Python + getframe_fn = getattr(sys, "_getframe", lambda _: None) + calling_frame = getframe_fn(1) if calling_frame is None: return + + # find all locals in the calling frame that are ParserElements calling_frame = typing.cast(types.FrameType, calling_frame) for name, var in calling_frame.f_locals.items(): + # if no custom name defined, set the name to the var name if isinstance(var, ParserElement) and not var.customName: var.set_name(name) diff --git a/contrib/python/pyparsing/py3/pyparsing/diagram/__init__.py b/contrib/python/pyparsing/py3/pyparsing/diagram/__init__.py index 56526b741b87..526cf3862a47 100644 --- a/contrib/python/pyparsing/py3/pyparsing/diagram/__init__.py +++ b/contrib/python/pyparsing/py3/pyparsing/diagram/__init__.py @@ -120,7 +120,7 @@ class EachItem(railroad.Group): all_label = "[ALL]" - def __init__(self, *items): + def __init__(self, *items) -> None: choice_item = railroad.Choice(len(items) - 1, *items) one_or_more_item = railroad.OneOrMore(item=choice_item) super().__init__(one_or_more_item, label=self.all_label) @@ -131,7 +131,7 @@ class AnnotatedItem(railroad.Group): Simple subclass of Group that creates an annotation label """ - def __init__(self, label: str, item): + def __init__(self, label: str, item) -> None: super().__init__(item=item, label=f"[{label}]" if label else "") @@ -144,7 +144,7 @@ class EditablePartial(Generic[T]): # We need this here because the railroad constructors actually transform the data, so can't be called until the # entire tree is assembled - def __init__(self, func: Callable[..., T], args: list, kwargs: dict): + def __init__(self, func: Callable[..., T], args: list, kwargs: dict) -> None: self.func = func self.args = args self.kwargs = kwargs @@ -226,6 +226,7 @@ def to_railroad( vertical: int = 3, show_results_names: bool = False, show_groups: bool = False, + show_hidden: bool = False, ) -> list[NamedDiagram]: """ Convert a pyparsing element tree into a list of diagrams. This is the recommended entrypoint to diagram @@ -238,6 +239,8 @@ def to_railroad( included in the diagram :param show_groups - bool to indicate whether groups should be highlighted with an unlabeled surrounding box + :param show_hidden - bool to indicate whether internal elements that are typically hidden + should be shown """ # Convert the whole tree underneath the root lookup = ConverterState(diagram_kwargs=diagram_kwargs or {}) @@ -248,6 +251,7 @@ def to_railroad( vertical=vertical, show_results_names=show_results_names, show_groups=show_groups, + show_hidden=show_hidden, ) root_id = id(element) @@ -348,7 +352,7 @@ class ConverterState: Stores some state that persists between recursions into the element tree """ - def __init__(self, diagram_kwargs: typing.Optional[dict] = None): + def __init__(self, diagram_kwargs: typing.Optional[dict] = None) -> None: #: A dictionary mapping ParserElements to state relating to them self._element_diagram_states: dict[int, ElementState] = {} #: A dictionary mapping ParserElement IDs to subdiagrams generated from them @@ -453,6 +457,7 @@ def _inner( name_hint: str = None, show_results_names: bool = False, show_groups: bool = False, + show_hidden: bool = False, ) -> typing.Optional[EditablePartial]: ret = fn( element, @@ -463,6 +468,7 @@ def _inner( name_hint, show_results_names, show_groups, + show_hidden, ) # apply annotation for results name, if present @@ -555,6 +561,7 @@ def _to_diagram_element( name_hint=propagated_name, show_results_names=show_results_names, show_groups=show_groups, + show_hidden=show_hidden, ) # If the element isn't worth extracting, we always treat it as the first time we say it @@ -641,6 +648,7 @@ def _to_diagram_element( name_hint, show_results_names, show_groups, + show_hidden, ] return _to_diagram_element( (~element.not_ender.expr + element.expr)[1, ...].set_name(element.name), @@ -657,6 +665,7 @@ def _to_diagram_element( name_hint, show_results_names, show_groups, + show_hidden, ] return _to_diagram_element( (~element.not_ender.expr + element.expr)[...].set_name(element.name), @@ -707,6 +716,7 @@ def _to_diagram_element( index=i, show_results_names=show_results_names, show_groups=show_groups, + show_hidden=show_hidden, ) # Some elements don't need to be shown in the diagram diff --git a/contrib/python/pyparsing/py3/pyparsing/exceptions.py b/contrib/python/pyparsing/py3/pyparsing/exceptions.py index 57a1579d121e..fe07a8558561 100644 --- a/contrib/python/pyparsing/py3/pyparsing/exceptions.py +++ b/contrib/python/pyparsing/py3/pyparsing/exceptions.py @@ -52,7 +52,7 @@ def __init__( loc: int = 0, msg: typing.Optional[str] = None, elem=None, - ): + ) -> None: if msg is None: msg, pstr = pstr, "" @@ -87,7 +87,7 @@ def explain_exception(exc: Exception, depth: int = 16) -> str: ret: list[str] = [] if isinstance(exc, ParseBaseException): ret.append(exc.line) - ret.append(f"{' ' * (exc.column - 1)}^") + ret.append(f"{'^':>{exc.column}}") ret.append(f"{type(exc).__name__}: {exc}") if depth <= 0 or exc.__traceback__ is None: @@ -272,12 +272,11 @@ class ParseException(ParseBaseException): try: integer.parse_string("ABC") except ParseException as pe: - print(pe) - print(f"column: {pe.column}") + print(pe, f"column: {pe.column}") prints:: - Expected integer (at char 0), (line:1, col:1) column: 1 + Expected integer, found 'ABC' (at char 0), (line:1, col:1) column: 1 """ @@ -307,7 +306,7 @@ class RecursiveGrammarException(Exception): Deprecated: only used by deprecated method ParserElement.validate. """ - def __init__(self, parseElementList): + def __init__(self, parseElementList) -> None: self.parseElementTrace = parseElementList def __str__(self) -> str: diff --git a/contrib/python/pyparsing/py3/pyparsing/helpers.py b/contrib/python/pyparsing/py3/pyparsing/helpers.py index f781e8713271..7f62df863747 100644 --- a/contrib/python/pyparsing/py3/pyparsing/helpers.py +++ b/contrib/python/pyparsing/py3/pyparsing/helpers.py @@ -208,11 +208,9 @@ def one_of( if caseless: is_equal = lambda a, b: a.upper() == b.upper() masks = lambda a, b: b.upper().startswith(a.upper()) - parse_element_class = CaselessKeyword if asKeyword else CaselessLiteral else: is_equal = operator.eq masks = lambda a, b: b.startswith(a) - parse_element_class = Keyword if asKeyword else Literal symbols: list[str] if isinstance(strs, str_type): @@ -255,7 +253,8 @@ def one_of( if asKeyword: patt = rf"\b(?:{patt})\b" - ret = Regex(patt, flags=re_flags).set_name(" | ".join(symbols)) + ret = Regex(patt, flags=re_flags) + ret.set_name(" | ".join(re.escape(s) for s in symbols)) if caseless: # add parse action to return symbols as specified, not in random @@ -270,13 +269,21 @@ def one_of( "Exception creating Regex for one_of, building MatchFirst", stacklevel=2 ) - # last resort, just use MatchFirst + # last resort, just use MatchFirst of Token class corresponding to caseless + # and asKeyword settings + CASELESS = KEYWORD = True + parse_element_class = { + (CASELESS, KEYWORD): CaselessKeyword, + (CASELESS, not KEYWORD): CaselessLiteral, + (not CASELESS, KEYWORD): Keyword, + (not CASELESS, not KEYWORD): Literal, + }[(caseless, asKeyword)] return MatchFirst(parse_element_class(sym) for sym in symbols).set_name( " | ".join(symbols) ) -def dict_of(key: ParserElement, value: ParserElement) -> ParserElement: +def dict_of(key: ParserElement, value: ParserElement) -> Dict: """Helper to easily and clearly define a dictionary by specifying the respective patterns for the key and value. Takes care of defining the :class:`Dict`, :class:`ZeroOrMore`, and @@ -411,13 +418,16 @@ def locatedExpr(expr: ParserElement) -> ParserElement: ) +_NO_IGNORE_EXPR_GIVEN = NoMatch() + + def nested_expr( opener: Union[str, ParserElement] = "(", closer: Union[str, ParserElement] = ")", content: typing.Optional[ParserElement] = None, - ignore_expr: ParserElement = quoted_string(), + ignore_expr: ParserElement = _NO_IGNORE_EXPR_GIVEN, *, - ignoreExpr: ParserElement = quoted_string(), + ignoreExpr: ParserElement = _NO_IGNORE_EXPR_GIVEN, ) -> ParserElement: """Helper method for defining nested lists enclosed in opening and closing delimiters (``"("`` and ``")"`` are the default). @@ -487,7 +497,10 @@ def nested_expr( dec_to_hex (int) args: [['char', 'hchar']] """ if ignoreExpr != ignore_expr: - ignoreExpr = ignore_expr if ignoreExpr == quoted_string() else ignoreExpr + ignoreExpr = ignore_expr if ignoreExpr is _NO_IGNORE_EXPR_GIVEN else ignoreExpr + if ignoreExpr is _NO_IGNORE_EXPR_GIVEN: + ignoreExpr = quoted_string() + if opener == closer: raise ValueError("opening and closing strings cannot be the same") if content is None: @@ -504,11 +517,11 @@ def nested_expr( exact=1, ) ) - ).set_parse_action(lambda t: t[0].strip()) + ) else: content = empty.copy() + CharsNotIn( opener + closer + ParserElement.DEFAULT_WHITE_CHARS - ).set_parse_action(lambda t: t[0].strip()) + ) else: if ignoreExpr is not None: content = Combine( @@ -518,7 +531,7 @@ def nested_expr( + ~Literal(closer) + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) ) - ).set_parse_action(lambda t: t[0].strip()) + ) else: content = Combine( OneOrMore( @@ -526,11 +539,16 @@ def nested_expr( + ~Literal(closer) + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1) ) - ).set_parse_action(lambda t: t[0].strip()) + ) else: raise ValueError( "opening and closing arguments must be strings if no content expression is given" ) + if ParserElement.DEFAULT_WHITE_CHARS: + content.set_parse_action( + lambda t: t[0].strip(ParserElement.DEFAULT_WHITE_CHARS) + ) + ret = Forward() if ignoreExpr is not None: ret <<= Group( @@ -691,7 +709,7 @@ def infix_notation( op_list: list[InfixNotationOperatorSpec], lpar: Union[str, ParserElement] = Suppress("("), rpar: Union[str, ParserElement] = Suppress(")"), -) -> ParserElement: +) -> Forward: """Helper method for constructing grammars of expressions made up of operators working in a precedence hierarchy. Operators may be unary or binary, left- or right-associative. Parse actions can also be diff --git a/contrib/python/pyparsing/py3/pyparsing/results.py b/contrib/python/pyparsing/py3/pyparsing/results.py index be834b7e6077..956230352c84 100644 --- a/contrib/python/pyparsing/py3/pyparsing/results.py +++ b/contrib/python/pyparsing/py3/pyparsing/results.py @@ -23,7 +23,7 @@ class _ParseResultsWithOffset: tup: tuple[ParseResults, int] __slots__ = ["tup"] - def __init__(self, p1: ParseResults, p2: int): + def __init__(self, p1: ParseResults, p2: int) -> None: self.tup: tuple[ParseResults, int] = (p1, p2) def __getitem__(self, i): diff --git a/contrib/python/pyparsing/py3/pyparsing/tools/__init__.py b/contrib/python/pyparsing/py3/pyparsing/tools/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/python/pyparsing/py3/pyparsing/tools/cvt_pyparsing_pep8_names.py b/contrib/python/pyparsing/py3/pyparsing/tools/cvt_pyparsing_pep8_names.py new file mode 100644 index 000000000000..f4a8bd9f5169 --- /dev/null +++ b/contrib/python/pyparsing/py3/pyparsing/tools/cvt_pyparsing_pep8_names.py @@ -0,0 +1,116 @@ +from functools import lru_cache +import pyparsing as pp + + +@lru_cache(maxsize=None) +def camel_to_snake(s: str) -> str: + """ + Convert CamelCase to snake_case. + """ + return "".join("_" + c.lower() if c.isupper() else c for c in s).lstrip("_") + + +pre_pep8_method_names = """ +addCondition addParseAction anyCloseTag anyOpenTag asDict asList cStyleComment canParseNext conditionAsParseAction +convertToDate convertToDatetime convertToFloat convertToInteger countedArray cppStyleComment dblQuotedString +dblSlashComment defaultName dictOf disableMemoization downcaseTokens enableLeftRecursion enablePackrat getName +htmlComment ignoreWhitespace indentedBlock infixNotation inlineLiteralsUsing javaStyleComment leaveWhitespace +lineEnd lineStart locatedExpr matchOnlyAtCol matchPreviousExpr matchPreviousLiteral nestedExpr nullDebugAction oneOf +originalTextFor parseFile parseString parseWithTabs pythonStyleComment quotedString removeQuotes replaceWith +resetCache restOfLine runTests scanString searchString setBreak setDebug setDebugActions setDefaultWhitespaceChars +setFailAction setName setParseAction setResultsName setWhitespaceChars sglQuotedString stringEnd stringStart tokenMap +traceParseAction transformString tryParse unicodeString upcaseTokens withAttribute withClass +""".split() + +special_changes = { + "opAssoc": "OpAssoc", + "delimitedList": "DelimitedList", + "delimited_list": "DelimitedList", + "replaceHTMLEntity": "replace_html_entity", + "makeHTMLTags": "make_html_tags", + "makeXMLTags": "make_xml_tags", + "commonHTMLEntity": "common_html_entity", + "stripHTMLTags": "strip_html_tags", +} + +pre_pep8_arg_names = """parseAll maxMatches listAllMatches callDuringTry includeSeparators fullDump printResults +failureTests postParse matchString identChars maxMismatches initChars bodyChars asKeyword excludeChars asGroupList +asMatch quoteChar escChar escQuote unquoteResults endQuoteChar convertWhitespaceEscapes notChars wordChars stopOn +failOn joinString markerString intExpr useRegex asString ignoreExpr""".split() + +pre_pep8_method_name = pp.one_of(pre_pep8_method_names, as_keyword=True) +pre_pep8_method_name.set_parse_action(lambda t: camel_to_snake(t[0])) +special_pre_pep8_name = pp.one_of(special_changes, as_keyword=True) +special_pre_pep8_name.set_parse_action(lambda t: special_changes[t[0]]) +# only replace arg names if part of an arg list +pre_pep8_arg_name = pp.Regex( + rf"{pp.util.make_compressed_re(pre_pep8_arg_names)}\s*=" +) +pre_pep8_arg_name.set_parse_action(lambda t: camel_to_snake(t[0])) + +pep8_converter = pre_pep8_method_name | special_pre_pep8_name | pre_pep8_arg_name + +if __name__ == "__main__": + import argparse + from pathlib import Path + import sys + + argparser = argparse.ArgumentParser( + description = ( + "Utility to convert Python pyparsing scripts using legacy" + " camelCase names to use PEP8 snake_case names." + "\nBy default, this script will only show whether this script would make any changes." + ) + ) + argparser.add_argument("--verbose", "-v", action="store_true", help="Show unified diff for each source file") + argparser.add_argument("-vv", action="store_true", dest="verbose2", help="Show unified diff for each source file, plus names of scanned files with no changes") + argparser.add_argument("--update", "-u", action="store_true", help="Update source files in-place") + argparser.add_argument("--encoding", type=str, default="utf-8", help="Encoding of source files (default: utf-8)") + argparser.add_argument("--exit-zero-even-if-changed", "-exit0", action="store_true", help="Exit with status code 0 even if changes were made") + argparser.add_argument("source_filename", nargs="+", help="Source filenames or filename patterns of Python files to be converted") + args = argparser.parse_args() + + + def show_diffs(original, modified): + import difflib + + diff = difflib.unified_diff( + original.splitlines(), modified.splitlines(), lineterm="" + ) + sys.stdout.writelines(f"{diff_line}\n" for diff_line in diff) + + exit_status = 0 + + for filename_pattern in args.source_filename: + + for filename in Path().glob(filename_pattern): + if not Path(filename).is_file(): + continue + + try: + original_contents = Path(filename).read_text(encoding=args.encoding) + modified_contents = pep8_converter.transform_string( + original_contents + ) + + if modified_contents != original_contents: + if args.update: + Path(filename).write_text(modified_contents, encoding=args.encoding) + print(f"Converted {filename}") + else: + print(f"Found required changes in {filename}") + + if args.verbose: + show_diffs(original_contents, modified_contents) + print() + + exit_status = 1 + + else: + if args.verbose2: + print(f"No required changes in {filename}") + + except Exception as e: + print(f"Failed to convert {filename}: {type(e).__name__}: {e}") + + sys.exit(exit_status if not args.exit_zero_even_if_changed else 0) diff --git a/contrib/python/pyparsing/py3/pyparsing/util.py b/contrib/python/pyparsing/py3/pyparsing/util.py index 03a60d4fddc2..1cb16e2e6205 100644 --- a/contrib/python/pyparsing/py3/pyparsing/util.py +++ b/contrib/python/pyparsing/py3/pyparsing/util.py @@ -1,5 +1,6 @@ # util.py import contextlib +import re from functools import lru_cache, wraps import inspect import itertools @@ -193,7 +194,7 @@ class _GroupConsecutive: (3, iter(['p', 'q', 'r', 's'])) """ - def __init__(self): + def __init__(self) -> None: self.prev = 0 self.counter = itertools.count() self.value = -1 @@ -303,7 +304,11 @@ def _flatten(ll: Iterable) -> list: def make_compressed_re( - word_list: Iterable[str], max_level: int = 2, _level: int = 1 + word_list: Iterable[str], + max_level: int = 2, + *, + non_capturing_groups: bool = True, + _level: int = 1, ) -> str: """ Create a regular expression string from a list of words, collapsing by common @@ -320,15 +325,38 @@ def get_suffixes_from_common_prefixes(namelist: list[str]): else: yield namelist[0][0], [namelist[0][1:]] + if _level == 1: + if not word_list: + raise ValueError("no words given to make_compressed_re()") + + if "" in word_list: + raise ValueError("word list cannot contain empty string") + else: + # internal recursive call, just return empty string if no words + if not word_list: + return "" + + # dedupe the word list + word_list = list({}.fromkeys(word_list)) + if max_level == 0: - return "|".join(sorted(word_list, key=len, reverse=True)) + if any(len(wd) > 1 for wd in word_list): + return "|".join( + sorted([re.escape(wd) for wd in word_list], key=len, reverse=True) + ) + else: + return f"[{''.join(_escape_regex_range_chars(wd) for wd in word_list)}]" ret = [] sep = "" + ncgroup = "?:" if non_capturing_groups else "" + for initial, suffixes in get_suffixes_from_common_prefixes(sorted(word_list)): ret.append(sep) sep = "|" + initial = re.escape(initial) + trailing = "" if "" in suffixes: trailing = "?" @@ -336,21 +364,33 @@ def get_suffixes_from_common_prefixes(namelist: list[str]): if len(suffixes) > 1: if all(len(s) == 1 for s in suffixes): - ret.append(f"{initial}[{''.join(suffixes)}]{trailing}") + ret.append( + f"{initial}[{''.join(_escape_regex_range_chars(s) for s in suffixes)}]{trailing}" + ) else: if _level < max_level: suffix_re = make_compressed_re( - sorted(suffixes), max_level, _level + 1 + sorted(suffixes), + max_level, + non_capturing_groups=non_capturing_groups, + _level=_level + 1, ) - ret.append(f"{initial}({suffix_re}){trailing}") + ret.append(f"{initial}({ncgroup}{suffix_re}){trailing}") else: - suffixes.sort(key=len, reverse=True) - ret.append(f"{initial}({'|'.join(suffixes)}){trailing}") + if all(len(s) == 1 for s in suffixes): + ret.append( + f"{initial}[{''.join(_escape_regex_range_chars(s) for s in suffixes)}]{trailing}" + ) + else: + suffixes.sort(key=len, reverse=True) + ret.append( + f"{initial}({ncgroup}{'|'.join(re.escape(s) for s in suffixes)}){trailing}" + ) else: if suffixes: - suffix = suffixes[0] + suffix = re.escape(suffixes[0]) if len(suffix) > 1 and trailing: - ret.append(f"{initial}({suffix}){trailing}") + ret.append(f"{initial}({ncgroup}{suffix}){trailing}") else: ret.append(f"{initial}{suffix}{trailing}") else: diff --git a/contrib/python/pyparsing/py3/ya.make b/contrib/python/pyparsing/py3/ya.make index e229986ca672..a53ebf37ecf0 100644 --- a/contrib/python/pyparsing/py3/ya.make +++ b/contrib/python/pyparsing/py3/ya.make @@ -4,7 +4,7 @@ PY3_LIBRARY() PROVIDES(pyparsing) -VERSION(3.2.1) +VERSION(3.2.2) LICENSE(MIT) @@ -25,6 +25,8 @@ PY_SRCS( pyparsing/helpers.py pyparsing/results.py pyparsing/testing.py + pyparsing/tools/__init__.py + pyparsing/tools/cvt_pyparsing_pep8_names.py pyparsing/unicode.py pyparsing/util.py ) From b2ff25e46f24606806b7a40db9b22890800cef8f Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Mon, 7 Apr 2025 13:39:50 +0300 Subject: [PATCH 012/454] Intermediate changes commit_hash:6a1c19eb4925f3dd59db5299f1072962932c057b --- yt/python/yt/common.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/yt/python/yt/common.py b/yt/python/yt/common.py index 054c26988396..a0de88b66abf 100644 --- a/yt/python/yt/common.py +++ b/yt/python/yt/common.py @@ -38,6 +38,7 @@ import sys import time import types +import typing import string import warnings @@ -47,6 +48,8 @@ YT_NULL_TRANSACTION_ID = "0-0-0-0" +_T = typing.TypeVar('_T') + # Deprecation stuff. class YtDeprecationWarning(DeprecationWarning): @@ -620,7 +623,7 @@ def require(condition, exception_func): raise exception_func() -def update_inplace(object, patch): +def update_inplace(object: _T, patch) -> _T: """Apply patch to object inplace""" if isinstance(patch, Mapping) and isinstance(object, Mapping): for key, value in iteritems(patch): @@ -639,7 +642,7 @@ def update_inplace(object, patch): return object -def update(object, patch): +def update(object: _T, patch) -> _T: """Apply patch to object without modifying original object or patch""" if patch is None: return copy.deepcopy(object) From a24849a5e16381ec0c969cd30331c8da1de23aba Mon Sep 17 00:00:00 2001 From: babenko Date: Mon, 7 Apr 2025 13:47:42 +0300 Subject: [PATCH 013/454] Better safety for GetRpcUserAgent commit_hash:538e2bc8d0ac9c7a88ebb87f1a320b563329f28c --- yt/yt/build/ya_version.cpp | 90 +++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 51 deletions(-) diff --git a/yt/yt/build/ya_version.cpp b/yt/yt/build/ya_version.cpp index 11a5dde2b500..defb5ec13948 100644 --- a/yt/yt/build/ya_version.cpp +++ b/yt/yt/build/ya_version.cpp @@ -101,60 +101,48 @@ TString GetYaBuildDate() return GetProgramBuildDate(); } -namespace { - -//////////////////////////////////////////////////////////////////////////////// - -TString BuildRpcUserAgent() noexcept +const TString& GetRpcUserAgent() { - // Fill user agent from build information. - // For trunk: - // - yt-cpp/r - // For YT release branch. - // - yt-cpp/ - // For arbitrary branch different from trunk: - // - yt-cpp/~ - // For local build from detached head or arc sync'ed state: - // - yt-cpp/local~ - - TString branch(GetBranch()); - TStringStream out; - - out << "yt-cpp/"; - - if (branch == "trunk") { - int svnRevision = GetProgramSvnRevision(); - out << "trunk~r" << svnRevision; - } else if (branch.StartsWith("releases/yt")) { - // Simply re-use YT version string. It looks like the following: - // 20.3.7547269-stable-ya~bb57c034bfb47caa. - TString ytVersion(GetVersion()); - out << ytVersion; - } else { - auto commit = GetCommitHash(); - auto truncatedCommit = TruncateCommitHash(commit); - - // In detached head arc state branch seems to coincide with commit hash. - // Let's use that in order to distinguish detached head from regular branch state. - if (branch == commit) { - branch = "local"; + static const auto result = [&] { + // Fill user agent from build information. + // For trunk: + // - yt-cpp/r + // For YT release branch. + // - yt-cpp/ + // For arbitrary branch different from trunk: + // - yt-cpp/~ + // For local build from detached head or arc sync'ed state: + // - yt-cpp/local~ + + TString branch(GetBranch()); + TStringStream out; + + out << "yt-cpp/"; + + if (branch == "trunk") { + int svnRevision = GetProgramSvnRevision(); + out << "trunk~r" << svnRevision; + } else if (branch.StartsWith("releases/yt")) { + // Simply re-use YT version string. It looks like the following: + // 20.3.7547269-stable-ya~bb57c034bfb47caa. + TString ytVersion(GetVersion()); + out << ytVersion; + } else { + auto commit = GetCommitHash(); + auto truncatedCommit = TruncateCommitHash(commit); + + // In detached head arc state branch seems to coincide with commit hash. + // Let's use that in order to distinguish detached head from regular branch state. + if (branch == commit) { + branch = "local"; + } + + out << branch << "~" << truncatedCommit; } - out << branch << "~" << truncatedCommit; - } - - return out.Str(); -} - -const TString CachedUserAgent = BuildRpcUserAgent(); - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace - -const TString& GetRpcUserAgent() -{ - return CachedUserAgent; + return out.Str(); + }(); + return result; } //////////////////////////////////////////////////////////////////////////////// From c33aace83a03e01fbf260c3a28c614a58cbce812 Mon Sep 17 00:00:00 2001 From: vityaman Date: Mon, 7 Apr 2025 14:33:48 +0300 Subject: [PATCH 014/454] YQL-19747 Complete type name as a function argument As I understand, type name should not be completed at `SELECT |`, so I added a check that we are at `invoke_expr` context. Currently composite type keywords are suggested at `SELECT |` and also are uppercased. I will fix it separately when this merged during - https://github.com/users/vityaman/projects/5?pane=issue&itemId=105056723&issue=vityaman%7Cydb%7C8 --- - Related to https://github.com/ydb-platform/ydb/issues/9056 - Related to https://github.com/users/vityaman/projects/5/views/1?pane=issue&itemId=105056423&issue=vityaman%7Cydb%7C7 --- Pull Request resolved: https://github.com/ytsaurus/ytsaurus/pull/1182 commit_hash:e87565867cf9fa82d9ac49a88d59b293d6686fe7 --- .../sql/v1/complete/sql_complete_ut.cpp | 16 ++++++++++++ .../sql/v1/complete/syntax/grammar.cpp | 14 ++++++---- .../sql/v1/complete/syntax/grammar.h | 2 ++ .../v1/complete/syntax/parser_call_stack.cpp | 26 ++++++++++++++++++- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp index ade78e81a767..10d358c8d3e0 100644 --- a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp +++ b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp @@ -386,6 +386,22 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT OPTIONAL<"}), expected); } + Y_UNIT_TEST(TypeNameAsArgument) { + auto engine = MakeSqlCompletionEngineUT(); + { + TVector expected = { + {TypeName, "Uint64"}, + }; + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT Nothing(Uint"}), expected); + } + { + TVector expected = { + {Keyword, "OPTIONAL<"}, + }; + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT Nothing(Option"}), expected); + } + } + Y_UNIT_TEST(UTF8Wide) { auto engine = MakeSqlCompletionEngineUT(); UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"\xF0\x9F\x98\x8A"}).size(), 0); diff --git a/yql/essentials/sql/v1/complete/syntax/grammar.cpp b/yql/essentials/sql/v1/complete/syntax/grammar.cpp index b4f64630f775..252deaf682cb 100644 --- a/yql/essentials/sql/v1/complete/syntax/grammar.cpp +++ b/yql/essentials/sql/v1/complete/syntax/grammar.cpp @@ -7,7 +7,7 @@ namespace NSQLComplete { class TSqlGrammar: public ISqlGrammar { public: TSqlGrammar(const NSQLReflect::TLexerGrammar& grammar) - : Vocabulary(GetVocabularyP()) + : Parser(MakeDummyParser()) , AllTokens(ComputeAllTokens()) , KeywordTokens(ComputeKeywordTokens(grammar)) , PunctuationTokens(ComputePunctuationTokens(grammar)) @@ -15,7 +15,7 @@ namespace NSQLComplete { } const antlr4::dfa::Vocabulary& GetVocabulary() const override { - return *Vocabulary; + return Parser->getVocabulary(); } const std::unordered_set& GetAllTokens() const override { @@ -30,9 +30,13 @@ namespace NSQLComplete { return PunctuationTokens; } + const std::string& SymbolizedRule(TRuleId rule) const override { + return Parser->getRuleNames().at(rule); + } + private: - static const antlr4::dfa::Vocabulary* GetVocabularyP() { - return &NALADefaultAntlr4::SQLv1Antlr4Parser(nullptr).getVocabulary(); + static THolder MakeDummyParser() { + return MakeHolder(nullptr); } std::unordered_set ComputeAllTokens() { @@ -72,7 +76,7 @@ namespace NSQLComplete { return punctuationTokens; } - const antlr4::dfa::Vocabulary* Vocabulary; + const THolder Parser; const std::unordered_set AllTokens; const std::unordered_set KeywordTokens; const std::unordered_set PunctuationTokens; diff --git a/yql/essentials/sql/v1/complete/syntax/grammar.h b/yql/essentials/sql/v1/complete/syntax/grammar.h index a349bd4a3de3..b128129e95f0 100644 --- a/yql/essentials/sql/v1/complete/syntax/grammar.h +++ b/yql/essentials/sql/v1/complete/syntax/grammar.h @@ -5,6 +5,7 @@ #include #include +#include #ifdef TOKEN_QUERY // Conflict with the winnt.h #undef TOKEN_QUERY @@ -19,6 +20,7 @@ namespace NSQLComplete { class ISqlGrammar { public: virtual const antlr4::dfa::Vocabulary& GetVocabulary() const = 0; + virtual const std::string& SymbolizedRule(TRuleId rule) const = 0; virtual const std::unordered_set& GetAllTokens() const = 0; virtual const std::unordered_set& GetKeywordTokens() const = 0; virtual const std::unordered_set& GetPunctuationTokens() const = 0; diff --git a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp index 855d9af1601d..57e058fa9008 100644 --- a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp +++ b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp @@ -6,6 +6,9 @@ #include #include +#define DEBUG_SYMBOLIZE_STACK(stack) \ + auto debug_symbolized_##stack = Symbolized(stack) + namespace NSQLComplete { const TVector KeywordRules = { @@ -23,6 +26,7 @@ namespace NSQLComplete { const TVector TypeNameRules = { RULE(Type_name_simple), + RULE(An_id_or_type), }; const TVector FunctionNameRules = { @@ -31,6 +35,17 @@ namespace NSQLComplete { RULE(Id_or_type), }; + TVector Symbolized(const TParserCallStack& stack) { + const ISqlGrammar& grammar = GetSqlGrammar(); + + TVector symbolized; + symbolized.reserve(stack.size()); + for (const TRuleId& rule : stack) { + symbolized.emplace_back(grammar.SymbolizedRule(rule)); + } + return symbolized; + } + bool EndsWith(const TParserCallStack& suffix, const TParserCallStack& stack) { if (stack.size() < suffix.size()) { return false; @@ -39,12 +54,21 @@ namespace NSQLComplete { return Equal(std::begin(stack) + prefixSize, std::end(stack), std::begin(suffix)); } + bool Contains(const TParserCallStack& sequence, const TParserCallStack& stack) { + return !std::ranges::search(stack, sequence).empty(); + } + bool ContainsRule(TRuleId rule, const TParserCallStack& stack) { return Find(stack, rule) != std::end(stack); } bool IsLikelyTypeStack(const TParserCallStack& stack) { - return EndsWith({RULE(Type_name_simple)}, stack); + return EndsWith({RULE(Type_name_simple)}, stack) || + (Contains({RULE(Invoke_expr), + RULE(Named_expr_list), + RULE(Named_expr), + RULE(Expr)}, stack) && + EndsWith({RULE(Atom_expr), RULE(An_id_or_type)}, stack)); } bool IsLikelyFunctionStack(const TParserCallStack& stack) { From 02d6ca62a11a5f602e07ba3ef7cdbd1808a38db6 Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Mon, 7 Apr 2025 16:28:23 +0300 Subject: [PATCH 015/454] Intermediate changes commit_hash:bdf980a10265fd16f4aecae0dff78846b425bd8b --- contrib/python/ydb/py3/.dist-info/METADATA | 2 +- contrib/python/ydb/py3/ya.make | 2 +- contrib/python/ydb/py3/ydb/_apis.py | 1 + contrib/python/ydb/py3/ydb/_errors.py | 1 + .../py3/ydb/_grpc/grpcwrapper/ydb_topic.py | 67 ++++++++++ .../ydb/py3/ydb/_topic_reader/datatypes.py | 9 ++ .../ydb/_topic_reader/topic_reader_asyncio.py | 126 +++++++++++++++++- .../ydb/_topic_reader/topic_reader_sync.py | 38 +++++- .../ydb/py3/ydb/_topic_writer/topic_writer.py | 10 +- .../ydb/_topic_writer/topic_writer_asyncio.py | 87 +++++++++++- .../ydb/_topic_writer/topic_writer_sync.py | 56 +++++++- contrib/python/ydb/py3/ydb/aio/driver.py | 1 + contrib/python/ydb/py3/ydb/aio/query/pool.py | 8 +- .../ydb/py3/ydb/aio/query/transaction.py | 48 ++++++- contrib/python/ydb/py3/ydb/driver.py | 1 + contrib/python/ydb/py3/ydb/issues.py | 4 + contrib/python/ydb/py3/ydb/query/base.py | 67 ++++++++++ contrib/python/ydb/py3/ydb/query/pool.py | 5 +- .../python/ydb/py3/ydb/query/transaction.py | 87 ++++++++++-- contrib/python/ydb/py3/ydb/table.py | 30 +++++ contrib/python/ydb/py3/ydb/topic.py | 84 +++++++++++- contrib/python/ydb/py3/ydb/ydb_version.py | 2 +- 22 files changed, 690 insertions(+), 46 deletions(-) diff --git a/contrib/python/ydb/py3/.dist-info/METADATA b/contrib/python/ydb/py3/.dist-info/METADATA index b6911ce75e8f..904414722eff 100644 --- a/contrib/python/ydb/py3/.dist-info/METADATA +++ b/contrib/python/ydb/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: ydb -Version: 3.19.3 +Version: 3.20.1 Summary: YDB Python SDK Home-page: http://github.com/ydb-platform/ydb-python-sdk Author: Yandex LLC diff --git a/contrib/python/ydb/py3/ya.make b/contrib/python/ydb/py3/ya.make index 71cfb8fa720b..fbc5d148f8a6 100644 --- a/contrib/python/ydb/py3/ya.make +++ b/contrib/python/ydb/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(3.19.3) +VERSION(3.20.1) LICENSE(Apache-2.0) diff --git a/contrib/python/ydb/py3/ydb/_apis.py b/contrib/python/ydb/py3/ydb/_apis.py index fc28d0ceb294..fc6f16e287c9 100644 --- a/contrib/python/ydb/py3/ydb/_apis.py +++ b/contrib/python/ydb/py3/ydb/_apis.py @@ -115,6 +115,7 @@ class TopicService(object): DropTopic = "DropTopic" StreamRead = "StreamRead" StreamWrite = "StreamWrite" + UpdateOffsetsInTransaction = "UpdateOffsetsInTransaction" class QueryService(object): diff --git a/contrib/python/ydb/py3/ydb/_errors.py b/contrib/python/ydb/py3/ydb/_errors.py index 17002d257499..1e2308ef394d 100644 --- a/contrib/python/ydb/py3/ydb/_errors.py +++ b/contrib/python/ydb/py3/ydb/_errors.py @@ -5,6 +5,7 @@ _errors_retriable_fast_backoff_types = [ issues.Unavailable, + issues.ClientInternalError, ] _errors_retriable_slow_backoff_types = [ issues.Aborted, diff --git a/contrib/python/ydb/py3/ydb/_grpc/grpcwrapper/ydb_topic.py b/contrib/python/ydb/py3/ydb/_grpc/grpcwrapper/ydb_topic.py index 5b22c7cf862b..0f8a0f03a7a0 100644 --- a/contrib/python/ydb/py3/ydb/_grpc/grpcwrapper/ydb_topic.py +++ b/contrib/python/ydb/py3/ydb/_grpc/grpcwrapper/ydb_topic.py @@ -141,6 +141,18 @@ def from_proto(msg: ydb_topic_pb2.UpdateTokenResponse) -> typing.Any: ######################################################################################################################## +@dataclass +class TransactionIdentity(IToProto): + tx_id: str + session_id: str + + def to_proto(self) -> ydb_topic_pb2.TransactionIdentity: + return ydb_topic_pb2.TransactionIdentity( + id=self.tx_id, + session=self.session_id, + ) + + class StreamWriteMessage: @dataclass() class InitRequest(IToProto): @@ -199,6 +211,7 @@ def from_proto( class WriteRequest(IToProto): messages: typing.List["StreamWriteMessage.WriteRequest.MessageData"] codec: int + tx_identity: Optional[TransactionIdentity] @dataclass class MessageData(IToProto): @@ -237,6 +250,9 @@ def to_proto(self) -> ydb_topic_pb2.StreamWriteMessage.WriteRequest: proto = ydb_topic_pb2.StreamWriteMessage.WriteRequest() proto.codec = self.codec + if self.tx_identity is not None: + proto.tx.CopyFrom(self.tx_identity.to_proto()) + for message in self.messages: proto_mess = proto.messages.add() proto_mess.CopyFrom(message.to_proto()) @@ -297,6 +313,8 @@ def from_proto(cls, proto_ack: ydb_topic_pb2.StreamWriteMessage.WriteResponse.Wr ) except ValueError: message_write_status = reason + elif proto_ack.HasField("written_in_tx"): + message_write_status = StreamWriteMessage.WriteResponse.WriteAck.StatusWrittenInTx() else: raise NotImplementedError("unexpected ack status") @@ -309,6 +327,9 @@ def from_proto(cls, proto_ack: ydb_topic_pb2.StreamWriteMessage.WriteResponse.Wr class StatusWritten: offset: int + class StatusWrittenInTx: + pass + @dataclass class StatusSkipped: reason: "StreamWriteMessage.WriteResponse.WriteAck.StatusSkipped.Reason" @@ -1196,6 +1217,52 @@ def to_public(self) -> ydb_topic_public_types.PublicMeteringMode: return ydb_topic_public_types.PublicMeteringMode.UNSPECIFIED +@dataclass +class UpdateOffsetsInTransactionRequest(IToProto): + tx: TransactionIdentity + topics: List[UpdateOffsetsInTransactionRequest.TopicOffsets] + consumer: str + + def to_proto(self): + return ydb_topic_pb2.UpdateOffsetsInTransactionRequest( + tx=self.tx.to_proto(), + consumer=self.consumer, + topics=list( + map( + UpdateOffsetsInTransactionRequest.TopicOffsets.to_proto, + self.topics, + ) + ), + ) + + @dataclass + class TopicOffsets(IToProto): + path: str + partitions: List[UpdateOffsetsInTransactionRequest.TopicOffsets.PartitionOffsets] + + def to_proto(self): + return ydb_topic_pb2.UpdateOffsetsInTransactionRequest.TopicOffsets( + path=self.path, + partitions=list( + map( + UpdateOffsetsInTransactionRequest.TopicOffsets.PartitionOffsets.to_proto, + self.partitions, + ) + ), + ) + + @dataclass + class PartitionOffsets(IToProto): + partition_id: int + partition_offsets: List[OffsetsRange] + + def to_proto(self) -> ydb_topic_pb2.UpdateOffsetsInTransactionRequest.TopicOffsets.PartitionOffsets: + return ydb_topic_pb2.UpdateOffsetsInTransactionRequest.TopicOffsets.PartitionOffsets( + partition_id=self.partition_id, + partition_offsets=list(map(OffsetsRange.to_proto, self.partition_offsets)), + ) + + @dataclass class CreateTopicRequest(IToProto, IFromPublic): path: str diff --git a/contrib/python/ydb/py3/ydb/_topic_reader/datatypes.py b/contrib/python/ydb/py3/ydb/_topic_reader/datatypes.py index b48501aff2f3..74f06a086fc2 100644 --- a/contrib/python/ydb/py3/ydb/_topic_reader/datatypes.py +++ b/contrib/python/ydb/py3/ydb/_topic_reader/datatypes.py @@ -108,6 +108,9 @@ def ack_notify(self, offset: int): waiter = self._ack_waiters.popleft() waiter._finish_ok() + def _update_last_commited_offset_if_needed(self, offset: int): + self.committed_offset = max(self.committed_offset, offset) + def close(self): if self.closed: return @@ -211,3 +214,9 @@ def _pop_batch(self, message_count: int) -> PublicBatch: self._bytes_size = self._bytes_size - new_batch._bytes_size return new_batch + + def _update_partition_offsets(self, tx, exc=None): + if exc is not None: + return + offsets = self._commit_get_offsets_range() + self._partition_session._update_last_commited_offset_if_needed(offsets.end) diff --git a/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_asyncio.py b/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_asyncio.py index 7061b4e449c3..87012554ef59 100644 --- a/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_asyncio.py +++ b/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_asyncio.py @@ -5,7 +5,7 @@ import gzip import typing from asyncio import Task -from collections import OrderedDict +from collections import defaultdict, OrderedDict from typing import Optional, Set, Dict, Union, Callable import ydb @@ -19,17 +19,24 @@ from .._grpc.grpcwrapper.common_utils import ( IGrpcWrapperAsyncIO, SupportedDriverType, + to_thread, GrpcWrapperAsyncIO, ) from .._grpc.grpcwrapper.ydb_topic import ( StreamReadMessage, UpdateTokenRequest, UpdateTokenResponse, + UpdateOffsetsInTransactionRequest, Codec, ) from .._errors import check_retriable_error import logging +from ..query.base import TxEvent + +if typing.TYPE_CHECKING: + from ..query.transaction import BaseQueryTxContext + logger = logging.getLogger(__name__) @@ -77,7 +84,7 @@ def __init__( ): self._loop = asyncio.get_running_loop() self._closed = False - self._reconnector = ReaderReconnector(driver, settings) + self._reconnector = ReaderReconnector(driver, settings, self._loop) self._parent = _parent async def __aenter__(self): @@ -88,8 +95,12 @@ async def __aexit__(self, exc_type, exc_val, exc_tb): def __del__(self): if not self._closed: - task = self._loop.create_task(self.close(flush=False)) - topic_common.wrap_set_name_for_asyncio_task(task, task_name="close reader") + try: + logger.warning("Topic reader was not closed properly. Consider using method close().") + task = self._loop.create_task(self.close(flush=False)) + topic_common.wrap_set_name_for_asyncio_task(task, task_name="close reader") + except BaseException: + logger.warning("Something went wrong during reader close in __del__") async def wait_message(self): """ @@ -112,6 +123,23 @@ async def receive_batch( max_messages=max_messages, ) + async def receive_batch_with_tx( + self, + tx: "BaseQueryTxContext", + max_messages: typing.Union[int, None] = None, + ) -> typing.Union[datatypes.PublicBatch, None]: + """ + Get one messages batch with tx from reader. + All messages in a batch from same partition. + + use asyncio.wait_for for wait with timeout. + """ + await self._reconnector.wait_message() + return self._reconnector.receive_batch_with_tx_nowait( + tx=tx, + max_messages=max_messages, + ) + async def receive_message(self) -> typing.Optional[datatypes.PublicMessage]: """ Block until receive new message @@ -165,11 +193,18 @@ class ReaderReconnector: _state_changed: asyncio.Event _stream_reader: Optional["ReaderStream"] _first_error: asyncio.Future[YdbError] + _tx_to_batches_map: Dict[str, typing.List[datatypes.PublicBatch]] - def __init__(self, driver: Driver, settings: topic_reader.PublicReaderSettings): + def __init__( + self, + driver: Driver, + settings: topic_reader.PublicReaderSettings, + loop: Optional[asyncio.AbstractEventLoop] = None, + ): self._id = self._static_reader_reconnector_counter.inc_and_get() self._settings = settings self._driver = driver + self._loop = loop if loop is not None else asyncio.get_running_loop() self._background_tasks = set() self._state_changed = asyncio.Event() @@ -177,6 +212,8 @@ def __init__(self, driver: Driver, settings: topic_reader.PublicReaderSettings): self._background_tasks.add(asyncio.create_task(self._connection_loop())) self._first_error = asyncio.get_running_loop().create_future() + self._tx_to_batches_map = dict() + async def _connection_loop(self): attempt = 0 while True: @@ -190,6 +227,7 @@ async def _connection_loop(self): if not retry_info.is_retriable: self._set_first_error(err) return + await asyncio.sleep(retry_info.sleep_timeout_seconds) attempt += 1 @@ -222,9 +260,87 @@ def receive_batch_nowait(self, max_messages: Optional[int] = None): max_messages=max_messages, ) + def receive_batch_with_tx_nowait(self, tx: "BaseQueryTxContext", max_messages: Optional[int] = None): + batch = self._stream_reader.receive_batch_nowait( + max_messages=max_messages, + ) + + self._init_tx(tx) + + self._tx_to_batches_map[tx.tx_id].append(batch) + + tx._add_callback(TxEvent.AFTER_COMMIT, batch._update_partition_offsets, self._loop) + + return batch + def receive_message_nowait(self): return self._stream_reader.receive_message_nowait() + def _init_tx(self, tx: "BaseQueryTxContext"): + if tx.tx_id not in self._tx_to_batches_map: # Init tx callbacks + self._tx_to_batches_map[tx.tx_id] = [] + tx._add_callback(TxEvent.BEFORE_COMMIT, self._commit_batches_with_tx, self._loop) + tx._add_callback(TxEvent.AFTER_COMMIT, self._handle_after_tx_commit, self._loop) + tx._add_callback(TxEvent.AFTER_ROLLBACK, self._handle_after_tx_rollback, self._loop) + + async def _commit_batches_with_tx(self, tx: "BaseQueryTxContext"): + grouped_batches = defaultdict(lambda: defaultdict(list)) + for batch in self._tx_to_batches_map[tx.tx_id]: + grouped_batches[batch._partition_session.topic_path][batch._partition_session.partition_id].append(batch) + + request = UpdateOffsetsInTransactionRequest(tx=tx._tx_identity(), consumer=self._settings.consumer, topics=[]) + + for topic_path in grouped_batches: + topic_offsets = UpdateOffsetsInTransactionRequest.TopicOffsets(path=topic_path, partitions=[]) + for partition_id in grouped_batches[topic_path]: + partition_offsets = UpdateOffsetsInTransactionRequest.TopicOffsets.PartitionOffsets( + partition_id=partition_id, + partition_offsets=[ + batch._commit_get_offsets_range() for batch in grouped_batches[topic_path][partition_id] + ], + ) + topic_offsets.partitions.append(partition_offsets) + request.topics.append(topic_offsets) + + try: + return await self._do_commit_batches_with_tx_call(request) + except BaseException: + exc = issues.ClientInternalError("Failed to update offsets in tx.") + tx._set_external_error(exc) + self._stream_reader._set_first_error(exc) + finally: + del self._tx_to_batches_map[tx.tx_id] + + async def _do_commit_batches_with_tx_call(self, request: UpdateOffsetsInTransactionRequest): + args = [ + request.to_proto(), + _apis.TopicService.Stub, + _apis.TopicService.UpdateOffsetsInTransaction, + topic_common.wrap_operation, + ] + + if asyncio.iscoroutinefunction(self._driver.__call__): + res = await self._driver(*args) + else: + res = await to_thread(self._driver, *args, executor=None) + + return res + + async def _handle_after_tx_rollback(self, tx: "BaseQueryTxContext", exc: Optional[BaseException]) -> None: + if tx.tx_id in self._tx_to_batches_map: + del self._tx_to_batches_map[tx.tx_id] + exc = issues.ClientInternalError("Reconnect due to transaction rollback") + self._stream_reader._set_first_error(exc) + + async def _handle_after_tx_commit(self, tx: "BaseQueryTxContext", exc: Optional[BaseException]) -> None: + if tx.tx_id in self._tx_to_batches_map: + del self._tx_to_batches_map[tx.tx_id] + + if exc is not None: + self._stream_reader._set_first_error( + issues.ClientInternalError("Reconnect due to transaction commit failed") + ) + def commit(self, batch: datatypes.ICommittable) -> datatypes.PartitionSession.CommitAckWaiter: return self._stream_reader.commit(batch) diff --git a/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_sync.py b/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_sync.py index eda1d374fc3a..31f28899271b 100644 --- a/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_sync.py +++ b/contrib/python/ydb/py3/ydb/_topic_reader/topic_reader_sync.py @@ -1,5 +1,6 @@ import asyncio import concurrent.futures +import logging import typing from typing import List, Union, Optional @@ -20,6 +21,11 @@ TopicReaderClosedError, ) +if typing.TYPE_CHECKING: + from ..query.transaction import BaseQueryTxContext + +logger = logging.getLogger(__name__) + class TopicReaderSync: _caller: CallFromSyncToAsync @@ -52,7 +58,12 @@ async def create_reader(): self._parent = _parent def __del__(self): - self.close(flush=False) + if not self._closed: + try: + logger.warning("Topic reader was not closed properly. Consider using method close().") + self.close(flush=False) + except BaseException: + logger.warning("Something went wrong during reader close in __del__") def __enter__(self): return self @@ -109,6 +120,31 @@ def receive_batch( timeout, ) + def receive_batch_with_tx( + self, + tx: "BaseQueryTxContext", + *, + max_messages: typing.Union[int, None] = None, + max_bytes: typing.Union[int, None] = None, + timeout: Union[float, None] = None, + ) -> Union[PublicBatch, None]: + """ + Get one messages batch with tx from reader + It has no async_ version for prevent lost messages, use async_wait_message as signal for new batches available. + + if no new message in timeout seconds (default - infinite): raise TimeoutError() + if timeout <= 0 - it will fast wait only one event loop cycle - without wait any i/o operations or pauses, get messages from internal buffer only. + """ + self._check_closed() + + return self._caller.safe_call_with_result( + self._async_reader.receive_batch_with_tx( + tx=tx, + max_messages=max_messages, + ), + timeout, + ) + def commit(self, mess: typing.Union[datatypes.PublicMessage, datatypes.PublicBatch]): """ Put commit message to internal buffer. diff --git a/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer.py b/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer.py index aa5fe9749a7f..a3e407ed86de 100644 --- a/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer.py +++ b/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer.py @@ -11,6 +11,7 @@ import ydb.aio from .._grpc.grpcwrapper.ydb_topic import StreamWriteMessage +from .._grpc.grpcwrapper.ydb_topic import TransactionIdentity from .._grpc.grpcwrapper.common_utils import IToProto from .._grpc.grpcwrapper.ydb_topic_public_types import PublicCodec from .. import connection @@ -53,8 +54,12 @@ class Written: class Skipped: pass + @dataclass(eq=True) + class WrittenInTx: + pass + -PublicWriteResultTypes = Union[PublicWriteResult.Written, PublicWriteResult.Skipped] +PublicWriteResultTypes = Union[PublicWriteResult.Written, PublicWriteResult.Skipped, PublicWriteResult.WrittenInTx] class WriterSettings(PublicWriterSettings): @@ -205,6 +210,7 @@ def default_serializer_message_content(data: Any) -> bytes: def messages_to_proto_requests( messages: List[InternalMessage], + tx_identity: Optional[TransactionIdentity], ) -> List[StreamWriteMessage.FromClient]: gropus = _slit_messages_for_send(messages) @@ -215,6 +221,7 @@ def messages_to_proto_requests( StreamWriteMessage.WriteRequest( messages=list(map(InternalMessage.to_message_data, group)), codec=group[0].codec, + tx_identity=tx_identity, ) ) res.append(req) @@ -239,6 +246,7 @@ def messages_to_proto_requests( ), ], codec=20000, + tx_identity=None, ) ) .to_proto() diff --git a/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_asyncio.py b/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_asyncio.py index 32d8fefe51c2..ec5b21661d43 100644 --- a/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_asyncio.py +++ b/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_asyncio.py @@ -1,7 +1,6 @@ import asyncio import concurrent.futures import datetime -import functools import gzip import typing from collections import deque @@ -35,6 +34,7 @@ UpdateTokenRequest, UpdateTokenResponse, StreamWriteMessage, + TransactionIdentity, WriterMessagesFromServerToClient, ) from .._grpc.grpcwrapper.common_utils import ( @@ -43,6 +43,11 @@ GrpcWrapperAsyncIO, ) +from ..query.base import TxEvent + +if typing.TYPE_CHECKING: + from ..query.transaction import BaseQueryTxContext + logger = logging.getLogger(__name__) @@ -76,8 +81,12 @@ async def __aexit__(self, exc_type, exc_val, exc_tb): def __del__(self): if self._closed or self._loop.is_closed(): return - - self._loop.call_soon(functools.partial(self.close, flush=False)) + try: + logger.warning("Topic writer was not closed properly. Consider using method close().") + task = self._loop.create_task(self.close(flush=False)) + topic_common.wrap_set_name_for_asyncio_task(task, task_name="close writer") + except BaseException: + logger.warning("Something went wrong during writer close in __del__") async def close(self, *, flush: bool = True): if self._closed: @@ -164,6 +173,57 @@ async def wait_init(self) -> PublicWriterInitInfo: return await self._reconnector.wait_init() +class TxWriterAsyncIO(WriterAsyncIO): + _tx: "BaseQueryTxContext" + + def __init__( + self, + tx: "BaseQueryTxContext", + driver: SupportedDriverType, + settings: PublicWriterSettings, + _client=None, + _is_implicit=False, + ): + self._tx = tx + self._loop = asyncio.get_running_loop() + self._closed = False + self._reconnector = WriterAsyncIOReconnector(driver=driver, settings=WriterSettings(settings), tx=self._tx) + self._parent = _client + self._is_implicit = _is_implicit + + # For some reason, creating partition could conflict with other session operations. + # Could be removed later. + self._first_write = True + + tx._add_callback(TxEvent.BEFORE_COMMIT, self._on_before_commit, self._loop) + tx._add_callback(TxEvent.BEFORE_ROLLBACK, self._on_before_rollback, self._loop) + + async def write( + self, + messages: Union[Message, List[Message]], + ): + """ + send one or number of messages to server. + it put message to internal buffer + + For wait with timeout use asyncio.wait_for. + """ + if self._first_write: + self._first_write = False + return await super().write_with_ack(messages) + return await super().write(messages) + + async def _on_before_commit(self, tx: "BaseQueryTxContext"): + if self._is_implicit: + return + await self.close() + + async def _on_before_rollback(self, tx: "BaseQueryTxContext"): + if self._is_implicit: + return + await self.close(flush=False) + + class WriterAsyncIOReconnector: _closed: bool _loop: asyncio.AbstractEventLoop @@ -178,6 +238,7 @@ class WriterAsyncIOReconnector: _codec_selector_batch_num: int _codec_selector_last_codec: Optional[PublicCodec] _codec_selector_check_batches_interval: int + _tx: Optional["BaseQueryTxContext"] if typing.TYPE_CHECKING: _messages_for_encode: asyncio.Queue[List[InternalMessage]] @@ -195,7 +256,9 @@ class WriterAsyncIOReconnector: _stop_reason: asyncio.Future _init_info: Optional[PublicWriterInitInfo] - def __init__(self, driver: SupportedDriverType, settings: WriterSettings): + def __init__( + self, driver: SupportedDriverType, settings: WriterSettings, tx: Optional["BaseQueryTxContext"] = None + ): self._closed = False self._loop = asyncio.get_running_loop() self._driver = driver @@ -205,6 +268,7 @@ def __init__(self, driver: SupportedDriverType, settings: WriterSettings): self._init_info = None self._stream_connected = asyncio.Event() self._settings = settings + self._tx = tx self._codec_functions = { PublicCodec.RAW: lambda data: data, @@ -354,10 +418,12 @@ async def _connection_loop(self): # noinspection PyBroadException stream_writer = None try: + tx_identity = None if self._tx is None else self._tx._tx_identity() stream_writer = await WriterAsyncIOStream.create( self._driver, self._init_message, self._settings.update_token_interval, + tx_identity=tx_identity, ) try: if self._init_info is None: @@ -387,7 +453,7 @@ async def _connection_loop(self): done.pop().result() # need for raise exception - reason of stop task except issues.Error as err: err_info = check_retriable_error(err, retry_settings, attempt) - if not err_info.is_retriable: + if not err_info.is_retriable or self._tx is not None: # no retries in tx writer self._stop(err) return @@ -533,6 +599,8 @@ def _handle_receive_ack(self, ack): result = PublicWriteResult.Skipped() elif isinstance(status, write_ack_msg.StatusWritten): result = PublicWriteResult.Written(offset=status.offset) + elif isinstance(status, write_ack_msg.StatusWrittenInTx): + result = PublicWriteResult.WrittenInTx() else: raise TopicWriterError("internal error - receive unexpected ack message.") message_future.set_result(result) @@ -597,10 +665,13 @@ class WriterAsyncIOStream: _update_token_event: asyncio.Event _get_token_function: Optional[Callable[[], str]] + _tx_identity: Optional[TransactionIdentity] + def __init__( self, update_token_interval: Optional[Union[int, float]] = None, get_token_function: Optional[Callable[[], str]] = None, + tx_identity: Optional[TransactionIdentity] = None, ): self._closed = False @@ -609,6 +680,8 @@ def __init__( self._update_token_event = asyncio.Event() self._update_token_task = None + self._tx_identity = tx_identity + async def close(self): if self._closed: return @@ -625,6 +698,7 @@ async def create( driver: SupportedDriverType, init_request: StreamWriteMessage.InitRequest, update_token_interval: Optional[Union[int, float]] = None, + tx_identity: Optional[TransactionIdentity] = None, ) -> "WriterAsyncIOStream": stream = GrpcWrapperAsyncIO(StreamWriteMessage.FromServer.from_proto) @@ -634,6 +708,7 @@ async def create( writer = WriterAsyncIOStream( update_token_interval=update_token_interval, get_token_function=creds.get_auth_token if creds else lambda: "", + tx_identity=tx_identity, ) await writer._start(stream, init_request) return writer @@ -680,7 +755,7 @@ def write(self, messages: List[InternalMessage]): if self._closed: raise RuntimeError("Can not write on closed stream.") - for request in messages_to_proto_requests(messages): + for request in messages_to_proto_requests(messages, self._tx_identity): self._stream.write(request) async def _update_token_loop(self): diff --git a/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_sync.py b/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_sync.py index a5193caf7c55..954864c96822 100644 --- a/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_sync.py +++ b/contrib/python/ydb/py3/ydb/_topic_writer/topic_writer_sync.py @@ -1,6 +1,7 @@ from __future__ import annotations import asyncio +import logging import typing from concurrent.futures import Future from typing import Union, List, Optional @@ -14,13 +15,23 @@ TopicWriterClosedError, ) -from .topic_writer_asyncio import WriterAsyncIO +from ..query.base import TxEvent + +from .topic_writer_asyncio import ( + TxWriterAsyncIO, + WriterAsyncIO, +) from .._topic_common.common import ( _get_shared_event_loop, TimeoutType, CallFromSyncToAsync, ) +if typing.TYPE_CHECKING: + from ..query.transaction import BaseQueryTxContext + +logger = logging.getLogger(__name__) + class WriterSync: _caller: CallFromSyncToAsync @@ -63,7 +74,12 @@ def __exit__(self, exc_type, exc_val, exc_tb): raise def __del__(self): - self.close(flush=False) + if not self._closed: + try: + logger.warning("Topic writer was not closed properly. Consider using method close().") + self.close(flush=False) + except BaseException: + logger.warning("Something went wrong during writer close in __del__") def close(self, *, flush: bool = True, timeout: TimeoutType = None): if self._closed: @@ -122,3 +138,39 @@ def write_with_ack( self._check_closed() return self._caller.unsafe_call_with_result(self._async_writer.write_with_ack(messages), timeout=timeout) + + +class TxWriterSync(WriterSync): + def __init__( + self, + tx: "BaseQueryTxContext", + driver: SupportedDriverType, + settings: PublicWriterSettings, + *, + eventloop: Optional[asyncio.AbstractEventLoop] = None, + _parent=None, + ): + + self._closed = False + + if eventloop: + loop = eventloop + else: + loop = _get_shared_event_loop() + + self._caller = CallFromSyncToAsync(loop) + + async def create_async_writer(): + return TxWriterAsyncIO(tx, driver, settings, _is_implicit=True) + + self._async_writer = self._caller.safe_call_with_result(create_async_writer(), None) + self._parent = _parent + + tx._add_callback(TxEvent.BEFORE_COMMIT, self._on_before_commit, None) + tx._add_callback(TxEvent.BEFORE_ROLLBACK, self._on_before_rollback, None) + + def _on_before_commit(self, tx: "BaseQueryTxContext"): + self.close() + + def _on_before_rollback(self, tx: "BaseQueryTxContext"): + self.close(flush=False) diff --git a/contrib/python/ydb/py3/ydb/aio/driver.py b/contrib/python/ydb/py3/ydb/aio/driver.py index 9cd6fd2b74d6..267997fbcc3e 100644 --- a/contrib/python/ydb/py3/ydb/aio/driver.py +++ b/contrib/python/ydb/py3/ydb/aio/driver.py @@ -62,4 +62,5 @@ def __init__( async def stop(self, timeout=10): await self.table_client._stop_pool_if_needed(timeout=timeout) + self.topic_client.close() await super().stop(timeout=timeout) diff --git a/contrib/python/ydb/py3/ydb/aio/query/pool.py b/contrib/python/ydb/py3/ydb/aio/query/pool.py index 947db658726c..f1ca68d1cf05 100644 --- a/contrib/python/ydb/py3/ydb/aio/query/pool.py +++ b/contrib/python/ydb/py3/ydb/aio/query/pool.py @@ -158,6 +158,8 @@ async def retry_tx_async( async def wrapped_callee(): async with self.checkout() as session: async with session.transaction(tx_mode=tx_mode) as tx: + if tx_mode.name in ["serializable_read_write", "snapshot_read_only"]: + await tx.begin() result = await callee(tx, *args, **kwargs) await tx.commit() return result @@ -213,12 +215,6 @@ async def __aenter__(self): async def __aexit__(self, exc_type, exc_val, exc_tb): await self.stop() - def __del__(self): - if self._should_stop.is_set() or self._loop.is_closed(): - return - - self._loop.call_soon(self.stop) - class SimpleQuerySessionCheckoutAsync: def __init__(self, pool: QuerySessionPool): diff --git a/contrib/python/ydb/py3/ydb/aio/query/transaction.py b/contrib/python/ydb/py3/ydb/aio/query/transaction.py index 5b63a32b489d..f0547e5f01fe 100644 --- a/contrib/python/ydb/py3/ydb/aio/query/transaction.py +++ b/contrib/python/ydb/py3/ydb/aio/query/transaction.py @@ -16,6 +16,28 @@ class QueryTxContext(BaseQueryTxContext): + def __init__(self, driver, session_state, session, tx_mode): + """ + An object that provides a simple transaction context manager that allows statements execution + in a transaction. You don't have to open transaction explicitly, because context manager encapsulates + transaction control logic, and opens new transaction if: + + 1) By explicit .begin() method; + 2) On execution of a first statement, which is strictly recommended method, because that avoids useless round trip + + This context manager is not thread-safe, so you should not manipulate on it concurrently. + + :param driver: A driver instance + :param session_state: A state of session + :param tx_mode: Transaction mode, which is a one from the following choises: + 1) QuerySerializableReadWrite() which is default mode; + 2) QueryOnlineReadOnly(allow_inconsistent_reads=False); + 3) QuerySnapshotReadOnly(); + 4) QueryStaleReadOnly(). + """ + super().__init__(driver, session_state, session, tx_mode) + self._init_callback_handler(base.CallbackHandlerMode.ASYNC) + async def __aenter__(self) -> "QueryTxContext": """ Enters a context manager and returns a transaction @@ -30,7 +52,7 @@ async def __aexit__(self, *args, **kwargs): it is not finished explicitly """ await self._ensure_prev_stream_finished() - if self._tx_state._state == QueryTxStateEnum.BEGINED: + if self._tx_state._state == QueryTxStateEnum.BEGINED and self._external_error is None: # It's strictly recommended to close transactions directly # by using commit_tx=True flag while executing statement or by # .commit() or .rollback() methods, but here we trying to do best @@ -65,7 +87,9 @@ async def commit(self, settings: Optional[BaseRequestSettings] = None) -> None: :return: A committed transaction or exception if commit is failed """ - if self._tx_state._already_in(QueryTxStateEnum.COMMITTED): + self._check_external_error_set() + + if self._tx_state._should_skip(QueryTxStateEnum.COMMITTED): return if self._tx_state._state == QueryTxStateEnum.NOT_INITIALIZED: @@ -74,7 +98,13 @@ async def commit(self, settings: Optional[BaseRequestSettings] = None) -> None: await self._ensure_prev_stream_finished() - await self._commit_call(settings) + try: + await self._execute_callbacks_async(base.TxEvent.BEFORE_COMMIT) + await self._commit_call(settings) + await self._execute_callbacks_async(base.TxEvent.AFTER_COMMIT, exc=None) + except BaseException as e: + await self._execute_callbacks_async(base.TxEvent.AFTER_COMMIT, exc=e) + raise e async def rollback(self, settings: Optional[BaseRequestSettings] = None) -> None: """Calls rollback on a transaction if it is open otherwise is no-op. If transaction execution @@ -84,7 +114,9 @@ async def rollback(self, settings: Optional[BaseRequestSettings] = None) -> None :return: A committed transaction or exception if commit is failed """ - if self._tx_state._already_in(QueryTxStateEnum.ROLLBACKED): + self._check_external_error_set() + + if self._tx_state._should_skip(QueryTxStateEnum.ROLLBACKED): return if self._tx_state._state == QueryTxStateEnum.NOT_INITIALIZED: @@ -93,7 +125,13 @@ async def rollback(self, settings: Optional[BaseRequestSettings] = None) -> None await self._ensure_prev_stream_finished() - await self._rollback_call(settings) + try: + await self._execute_callbacks_async(base.TxEvent.BEFORE_ROLLBACK) + await self._rollback_call(settings) + await self._execute_callbacks_async(base.TxEvent.AFTER_ROLLBACK, exc=None) + except BaseException as e: + await self._execute_callbacks_async(base.TxEvent.AFTER_ROLLBACK, exc=e) + raise e async def execute( self, diff --git a/contrib/python/ydb/py3/ydb/driver.py b/contrib/python/ydb/py3/ydb/driver.py index 49bd223c9018..3998aeeef5ff 100644 --- a/contrib/python/ydb/py3/ydb/driver.py +++ b/contrib/python/ydb/py3/ydb/driver.py @@ -288,4 +288,5 @@ def __init__( def stop(self, timeout=10): self.table_client._stop_pool_if_needed(timeout=timeout) + self.topic_client.close() super().stop(timeout=timeout) diff --git a/contrib/python/ydb/py3/ydb/issues.py b/contrib/python/ydb/py3/ydb/issues.py index f38f99f92578..4e76f5ed2b02 100644 --- a/contrib/python/ydb/py3/ydb/issues.py +++ b/contrib/python/ydb/py3/ydb/issues.py @@ -178,6 +178,10 @@ class SessionPoolEmpty(Error, queue.Empty): status = StatusCode.SESSION_POOL_EMPTY +class ClientInternalError(Error): + status = StatusCode.CLIENT_INTERNAL_ERROR + + class UnexpectedGrpcMessage(Error): def __init__(self, message: str): super().__init__(message) diff --git a/contrib/python/ydb/py3/ydb/query/base.py b/contrib/python/ydb/py3/ydb/query/base.py index 57a769bb1a12..a5ebedd95b37 100644 --- a/contrib/python/ydb/py3/ydb/query/base.py +++ b/contrib/python/ydb/py3/ydb/query/base.py @@ -1,6 +1,8 @@ import abc +import asyncio import enum import functools +from collections import defaultdict import typing from typing import ( @@ -17,6 +19,10 @@ from .. import _utilities from .. import _apis +from ydb._topic_common.common import CallFromSyncToAsync, _get_shared_event_loop +from ydb._grpc.grpcwrapper.common_utils import to_thread + + if typing.TYPE_CHECKING: from .transaction import BaseQueryTxContext @@ -196,3 +202,64 @@ def wrap_execute_query_response( return convert.ResultSet.from_message(response_pb.result_set, settings) return None + + +class TxEvent(enum.Enum): + BEFORE_COMMIT = "BEFORE_COMMIT" + AFTER_COMMIT = "AFTER_COMMIT" + BEFORE_ROLLBACK = "BEFORE_ROLLBACK" + AFTER_ROLLBACK = "AFTER_ROLLBACK" + + +class CallbackHandlerMode(enum.Enum): + SYNC = "SYNC" + ASYNC = "ASYNC" + + +def _get_sync_callback(method: typing.Callable, loop: Optional[asyncio.AbstractEventLoop]): + if asyncio.iscoroutinefunction(method): + if loop is None: + loop = _get_shared_event_loop() + + def async_to_sync_callback(*args, **kwargs): + caller = CallFromSyncToAsync(loop) + return caller.safe_call_with_result(method(*args, **kwargs), 10) + + return async_to_sync_callback + return method + + +def _get_async_callback(method: typing.Callable): + if asyncio.iscoroutinefunction(method): + return method + + async def sync_to_async_callback(*args, **kwargs): + return await to_thread(method, *args, **kwargs, executor=None) + + return sync_to_async_callback + + +class CallbackHandler: + def _init_callback_handler(self, mode: CallbackHandlerMode) -> None: + self._callbacks = defaultdict(list) + self._callback_mode = mode + + def _execute_callbacks_sync(self, event_name: str, *args, **kwargs) -> None: + for callback in self._callbacks[event_name]: + callback(self, *args, **kwargs) + + async def _execute_callbacks_async(self, event_name: str, *args, **kwargs) -> None: + tasks = [asyncio.create_task(callback(self, *args, **kwargs)) for callback in self._callbacks[event_name]] + if not tasks: + return + await asyncio.gather(*tasks) + + def _prepare_callback( + self, callback: typing.Callable, loop: Optional[asyncio.AbstractEventLoop] + ) -> typing.Callable: + if self._callback_mode == CallbackHandlerMode.SYNC: + return _get_sync_callback(callback, loop) + return _get_async_callback(callback) + + def _add_callback(self, event_name: str, callback: typing.Callable, loop: Optional[asyncio.AbstractEventLoop]): + self._callbacks[event_name].append(self._prepare_callback(callback, loop)) diff --git a/contrib/python/ydb/py3/ydb/query/pool.py b/contrib/python/ydb/py3/ydb/query/pool.py index e3775c4dd121..b25f7db855cf 100644 --- a/contrib/python/ydb/py3/ydb/query/pool.py +++ b/contrib/python/ydb/py3/ydb/query/pool.py @@ -167,6 +167,8 @@ def retry_tx_sync( def wrapped_callee(): with self.checkout(timeout=retry_settings.max_session_acquire_timeout) as session: with session.transaction(tx_mode=tx_mode) as tx: + if tx_mode.name in ["serializable_read_write", "snapshot_read_only"]: + tx.begin() result = callee(tx, *args, **kwargs) tx.commit() return result @@ -224,9 +226,6 @@ def __enter__(self): def __exit__(self, exc_type, exc_val, exc_tb): self.stop() - def __del__(self): - self.stop() - class SimpleQuerySessionCheckout: def __init__(self, pool: QuerySessionPool, timeout: Optional[float]): diff --git a/contrib/python/ydb/py3/ydb/query/transaction.py b/contrib/python/ydb/py3/ydb/query/transaction.py index 414401da4d1e..ae7642dbe216 100644 --- a/contrib/python/ydb/py3/ydb/query/transaction.py +++ b/contrib/python/ydb/py3/ydb/query/transaction.py @@ -11,6 +11,7 @@ _apis, issues, ) +from .._grpc.grpcwrapper import ydb_topic as _ydb_topic from .._grpc.grpcwrapper import ydb_query as _ydb_query from ..connection import _RpcState as RpcState @@ -42,10 +43,22 @@ class QueryTxStateHelper(abc.ABC): QueryTxStateEnum.DEAD: [], } + _SKIP_TRANSITIONS = { + QueryTxStateEnum.NOT_INITIALIZED: [], + QueryTxStateEnum.BEGINED: [], + QueryTxStateEnum.COMMITTED: [QueryTxStateEnum.COMMITTED, QueryTxStateEnum.ROLLBACKED], + QueryTxStateEnum.ROLLBACKED: [QueryTxStateEnum.COMMITTED, QueryTxStateEnum.ROLLBACKED], + QueryTxStateEnum.DEAD: [], + } + @classmethod def valid_transition(cls, before: QueryTxStateEnum, after: QueryTxStateEnum) -> bool: return after in cls._VALID_TRANSITIONS[before] + @classmethod + def should_skip(cls, before: QueryTxStateEnum, after: QueryTxStateEnum) -> bool: + return after in cls._SKIP_TRANSITIONS[before] + @classmethod def terminal(cls, state: QueryTxStateEnum) -> bool: return len(cls._VALID_TRANSITIONS[state]) == 0 @@ -88,8 +101,8 @@ def _check_tx_ready_to_use(self) -> None: if QueryTxStateHelper.terminal(self._state): raise RuntimeError(f"Transaction is in terminal state: {self._state.value}") - def _already_in(self, target: QueryTxStateEnum) -> bool: - return self._state == target + def _should_skip(self, target: QueryTxStateEnum) -> bool: + return QueryTxStateHelper.should_skip(self._state, target) def _construct_tx_settings(tx_state: QueryTxState) -> _ydb_query.TransactionSettings: @@ -170,7 +183,7 @@ def wrap_tx_rollback_response( return tx -class BaseQueryTxContext: +class BaseQueryTxContext(base.CallbackHandler): def __init__(self, driver, session_state, session, tx_mode): """ An object that provides a simple transaction context manager that allows statements execution @@ -196,6 +209,7 @@ def __init__(self, driver, session_state, session, tx_mode): self._session_state = session_state self.session = session self._prev_stream = None + self._external_error = None @property def session_id(self) -> str: @@ -215,6 +229,19 @@ def tx_id(self) -> Optional[str]: """ return self._tx_state.tx_id + def _tx_identity(self) -> _ydb_topic.TransactionIdentity: + if not self.tx_id: + raise RuntimeError("Unable to get tx identity without started tx.") + return _ydb_topic.TransactionIdentity(self.tx_id, self.session_id) + + def _set_external_error(self, exc: BaseException) -> None: + self._external_error = exc + + def _check_external_error_set(self): + if self._external_error is None: + return + raise issues.ClientInternalError("Transaction was failed by external error.") from self._external_error + def _begin_call(self, settings: Optional[BaseRequestSettings]) -> "BaseQueryTxContext": self._tx_state._check_invalid_transition(QueryTxStateEnum.BEGINED) @@ -228,6 +255,7 @@ def _begin_call(self, settings: Optional[BaseRequestSettings]) -> "BaseQueryTxCo ) def _commit_call(self, settings: Optional[BaseRequestSettings]) -> "BaseQueryTxContext": + self._check_external_error_set() self._tx_state._check_invalid_transition(QueryTxStateEnum.COMMITTED) return self._driver( @@ -240,6 +268,7 @@ def _commit_call(self, settings: Optional[BaseRequestSettings]) -> "BaseQueryTxC ) def _rollback_call(self, settings: Optional[BaseRequestSettings]) -> "BaseQueryTxContext": + self._check_external_error_set() self._tx_state._check_invalid_transition(QueryTxStateEnum.ROLLBACKED) return self._driver( @@ -262,6 +291,7 @@ def _execute_call( settings: Optional[BaseRequestSettings], ) -> Iterable[_apis.ydb_query.ExecuteQueryResponsePart]: self._tx_state._check_tx_ready_to_use() + self._check_external_error_set() request = base.create_execute_query_request( query=query, @@ -283,18 +313,41 @@ def _execute_call( ) def _move_to_beginned(self, tx_id: str) -> None: - if self._tx_state._already_in(QueryTxStateEnum.BEGINED) or not tx_id: + if self._tx_state._should_skip(QueryTxStateEnum.BEGINED) or not tx_id: return self._tx_state._change_state(QueryTxStateEnum.BEGINED) self._tx_state.tx_id = tx_id def _move_to_commited(self) -> None: - if self._tx_state._already_in(QueryTxStateEnum.COMMITTED): + if self._tx_state._should_skip(QueryTxStateEnum.COMMITTED): return self._tx_state._change_state(QueryTxStateEnum.COMMITTED) class QueryTxContext(BaseQueryTxContext): + def __init__(self, driver, session_state, session, tx_mode): + """ + An object that provides a simple transaction context manager that allows statements execution + in a transaction. You don't have to open transaction explicitly, because context manager encapsulates + transaction control logic, and opens new transaction if: + + 1) By explicit .begin() method; + 2) On execution of a first statement, which is strictly recommended method, because that avoids useless round trip + + This context manager is not thread-safe, so you should not manipulate on it concurrently. + + :param driver: A driver instance + :param session_state: A state of session + :param tx_mode: Transaction mode, which is a one from the following choises: + 1) QuerySerializableReadWrite() which is default mode; + 2) QueryOnlineReadOnly(allow_inconsistent_reads=False); + 3) QuerySnapshotReadOnly(); + 4) QueryStaleReadOnly(). + """ + + super().__init__(driver, session_state, session, tx_mode) + self._init_callback_handler(base.CallbackHandlerMode.SYNC) + def __enter__(self) -> "BaseQueryTxContext": """ Enters a context manager and returns a transaction @@ -309,7 +362,7 @@ def __exit__(self, *args, **kwargs): it is not finished explicitly """ self._ensure_prev_stream_finished() - if self._tx_state._state == QueryTxStateEnum.BEGINED: + if self._tx_state._state == QueryTxStateEnum.BEGINED and self._external_error is None: # It's strictly recommended to close transactions directly # by using commit_tx=True flag while executing statement or by # .commit() or .rollback() methods, but here we trying to do best @@ -345,7 +398,8 @@ def commit(self, settings: Optional[BaseRequestSettings] = None) -> None: :return: A committed transaction or exception if commit is failed """ - if self._tx_state._already_in(QueryTxStateEnum.COMMITTED): + self._check_external_error_set() + if self._tx_state._should_skip(QueryTxStateEnum.COMMITTED): return if self._tx_state._state == QueryTxStateEnum.NOT_INITIALIZED: @@ -354,7 +408,13 @@ def commit(self, settings: Optional[BaseRequestSettings] = None) -> None: self._ensure_prev_stream_finished() - self._commit_call(settings) + try: + self._execute_callbacks_sync(base.TxEvent.BEFORE_COMMIT) + self._commit_call(settings) + self._execute_callbacks_sync(base.TxEvent.AFTER_COMMIT, exc=None) + except BaseException as e: # TODO: probably should be less wide + self._execute_callbacks_sync(base.TxEvent.AFTER_COMMIT, exc=e) + raise e def rollback(self, settings: Optional[BaseRequestSettings] = None) -> None: """Calls rollback on a transaction if it is open otherwise is no-op. If transaction execution @@ -364,7 +424,8 @@ def rollback(self, settings: Optional[BaseRequestSettings] = None) -> None: :return: A committed transaction or exception if commit is failed """ - if self._tx_state._already_in(QueryTxStateEnum.ROLLBACKED): + self._check_external_error_set() + if self._tx_state._should_skip(QueryTxStateEnum.ROLLBACKED): return if self._tx_state._state == QueryTxStateEnum.NOT_INITIALIZED: @@ -373,7 +434,13 @@ def rollback(self, settings: Optional[BaseRequestSettings] = None) -> None: self._ensure_prev_stream_finished() - self._rollback_call(settings) + try: + self._execute_callbacks_sync(base.TxEvent.BEFORE_ROLLBACK) + self._rollback_call(settings) + self._execute_callbacks_sync(base.TxEvent.AFTER_ROLLBACK, exc=None) + except BaseException as e: # TODO: probably should be less wide + self._execute_callbacks_sync(base.TxEvent.AFTER_ROLLBACK, exc=e) + raise e def execute( self, diff --git a/contrib/python/ydb/py3/ydb/table.py b/contrib/python/ydb/py3/ydb/table.py index 945e91876771..ac73902f3cf7 100644 --- a/contrib/python/ydb/py3/ydb/table.py +++ b/contrib/python/ydb/py3/ydb/table.py @@ -545,6 +545,9 @@ class TableStats(object): def __init__(self): self.partitions = None self.store_size = 0 + self.rows_estimate = 0 + self.creation_time = None + self.modification_time = None def with_store_size(self, store_size): self.store_size = store_size @@ -554,6 +557,18 @@ def with_partitions(self, partitions): self.partitions = partitions return self + def with_rows_estimate(self, rows_estimate): + self.rows_estimate = rows_estimate + return self + + def with_creation_time(self, creation_time): + self.creation_time = creation_time + return self + + def with_modification_time(self, modification_time): + self.modification_time = modification_time + return self + class ReadReplicasSettings(object): def __init__(self): @@ -1577,7 +1592,22 @@ def __init__( self.table_stats = None if table_stats is not None: + from ._grpc.grpcwrapper.common_utils import datetime_from_proto_timestamp + self.table_stats = TableStats() + if table_stats.creation_time: + self.table_stats = self.table_stats.with_creation_time( + datetime_from_proto_timestamp(table_stats.creation_time) + ) + + if table_stats.modification_time: + self.table_stats = self.table_stats.with_modification_time( + datetime_from_proto_timestamp(table_stats.modification_time) + ) + + if table_stats.rows_estimate != 0: + self.table_stats = self.table_stats.with_rows_estimate(table_stats.rows_estimate) + if table_stats.partitions != 0: self.table_stats = self.table_stats.with_partitions(table_stats.partitions) diff --git a/contrib/python/ydb/py3/ydb/topic.py b/contrib/python/ydb/py3/ydb/topic.py index 55f4ea04c5ca..a501f9d2750a 100644 --- a/contrib/python/ydb/py3/ydb/topic.py +++ b/contrib/python/ydb/py3/ydb/topic.py @@ -25,6 +25,8 @@ "TopicWriteResult", "TopicWriter", "TopicWriterAsyncIO", + "TopicTxWriter", + "TopicTxWriterAsyncIO", "TopicWriterInitInfo", "TopicWriterMessage", "TopicWriterSettings", @@ -33,6 +35,7 @@ import concurrent.futures import datetime from dataclasses import dataclass +import logging from typing import List, Union, Mapping, Optional, Dict, Callable from . import aio, Credentials, _apis, issues @@ -65,8 +68,10 @@ PublicWriteResult as TopicWriteResult, ) +from ydb._topic_writer.topic_writer_asyncio import TxWriterAsyncIO as TopicTxWriterAsyncIO from ydb._topic_writer.topic_writer_asyncio import WriterAsyncIO as TopicWriterAsyncIO from ._topic_writer.topic_writer_sync import WriterSync as TopicWriter +from ._topic_writer.topic_writer_sync import TxWriterSync as TopicTxWriter from ._topic_common.common import ( wrap_operation as _wrap_operation, @@ -88,6 +93,8 @@ PublicAlterAutoPartitioningSettings as TopicAlterAutoPartitioningSettings, ) +logger = logging.getLogger(__name__) + class TopicClientAsyncIO: _closed: bool @@ -108,7 +115,12 @@ def __init__(self, driver: aio.Driver, settings: Optional[TopicClientSettings] = ) def __del__(self): - self.close() + if not self._closed: + try: + logger.warning("Topic client was not closed properly. Consider using method close().") + self.close() + except BaseException: + logger.warning("Something went wrong during topic client close in __del__") async def create_topic( self, @@ -276,6 +288,35 @@ def writer( return TopicWriterAsyncIO(self._driver, settings, _client=self) + def tx_writer( + self, + tx, + topic, + *, + producer_id: Optional[str] = None, # default - random + session_metadata: Mapping[str, str] = None, + partition_id: Union[int, None] = None, + auto_seqno: bool = True, + auto_created_at: bool = True, + codec: Optional[TopicCodec] = None, # default mean auto-select + # encoders: map[codec_code] func(encoded_bytes)->decoded_bytes + # the func will be called from multiply threads in parallel. + encoders: Optional[Mapping[_ydb_topic_public_types.PublicCodec, Callable[[bytes], bytes]]] = None, + # custom encoder executor for call builtin and custom decoders. If None - use shared executor pool. + # If max_worker in the executor is 1 - then encoders will be called from the thread without parallel. + encoder_executor: Optional[concurrent.futures.Executor] = None, + ) -> TopicTxWriterAsyncIO: + args = locals().copy() + del args["self"] + del args["tx"] + + settings = TopicWriterSettings(**args) + + if not settings.encoder_executor: + settings.encoder_executor = self._executor + + return TopicTxWriterAsyncIO(tx=tx, driver=self._driver, settings=settings, _client=self) + def close(self): if self._closed: return @@ -287,7 +328,7 @@ def _check_closed(self): if not self._closed: return - raise RuntimeError("Topic client closed") + raise issues.Error("Topic client closed") class TopicClient: @@ -310,7 +351,12 @@ def __init__(self, driver: driver.Driver, settings: Optional[TopicClientSettings ) def __del__(self): - self.close() + if not self._closed: + try: + logger.warning("Topic client was not closed properly. Consider using method close().") + self.close() + except BaseException: + logger.warning("Something went wrong during topic client close in __del__") def create_topic( self, @@ -487,6 +533,36 @@ def writer( return TopicWriter(self._driver, settings, _parent=self) + def tx_writer( + self, + tx, + topic, + *, + producer_id: Optional[str] = None, # default - random + session_metadata: Mapping[str, str] = None, + partition_id: Union[int, None] = None, + auto_seqno: bool = True, + auto_created_at: bool = True, + codec: Optional[TopicCodec] = None, # default mean auto-select + # encoders: map[codec_code] func(encoded_bytes)->decoded_bytes + # the func will be called from multiply threads in parallel. + encoders: Optional[Mapping[_ydb_topic_public_types.PublicCodec, Callable[[bytes], bytes]]] = None, + # custom encoder executor for call builtin and custom decoders. If None - use shared executor pool. + # If max_worker in the executor is 1 - then encoders will be called from the thread without parallel. + encoder_executor: Optional[concurrent.futures.Executor] = None, # default shared client executor pool + ) -> TopicWriter: + args = locals().copy() + del args["self"] + del args["tx"] + self._check_closed() + + settings = TopicWriterSettings(**args) + + if not settings.encoder_executor: + settings.encoder_executor = self._executor + + return TopicTxWriter(tx, self._driver, settings, _parent=self) + def close(self): if self._closed: return @@ -498,7 +574,7 @@ def _check_closed(self): if not self._closed: return - raise RuntimeError("Topic client closed") + raise issues.Error("Topic client closed") @dataclass diff --git a/contrib/python/ydb/py3/ydb/ydb_version.py b/contrib/python/ydb/py3/ydb/ydb_version.py index 8bd658d49e45..4a5c580f99f0 100644 --- a/contrib/python/ydb/py3/ydb/ydb_version.py +++ b/contrib/python/ydb/py3/ydb/ydb_version.py @@ -1 +1 @@ -VERSION = "3.19.3" +VERSION = "3.20.1" From 2ec92416296dc1af11b6b60cc53e18cca4933487 Mon Sep 17 00:00:00 2001 From: say Date: Mon, 7 Apr 2025 18:46:34 +0300 Subject: [PATCH 016/454] Remove arcadia_test_data commit_hash:0daacd6f5a9880a3a29a2c32a039e41407266063 --- library/cpp/testing/common/env.cpp | 10 ---------- library/cpp/testing/common/env.h | 1 - 2 files changed, 11 deletions(-) diff --git a/library/cpp/testing/common/env.cpp b/library/cpp/testing/common/env.cpp index 1440186d789e..41bf2b20aba1 100644 --- a/library/cpp/testing/common/env.cpp +++ b/library/cpp/testing/common/env.cpp @@ -141,7 +141,6 @@ namespace NPrivate { void TTestEnv::ReInitialize() { IsRunningFromTest = false; - ArcadiaTestsDataDir = ""; SourceRoot = ""; BuildRoot = ""; WorkPath = ""; @@ -171,11 +170,6 @@ namespace NPrivate { BuildRoot = value->GetStringSafe(""); } - value = context.GetValueByPath("runtime.atd_root"); - if (value) { - ArcadiaTestsDataDir = value->GetStringSafe(""); - } - value = context.GetValueByPath("runtime.work_path"); if (value) { WorkPath = value->GetStringSafe(""); @@ -249,10 +243,6 @@ namespace NPrivate { BuildRoot = GetEnv("ARCADIA_BUILD_ROOT"); } - if (!ArcadiaTestsDataDir) { - ArcadiaTestsDataDir = GetEnv("ARCADIA_TESTS_DATA_DIR"); - } - if (!WorkPath) { WorkPath = GetEnv("TEST_WORK_PATH"); } diff --git a/library/cpp/testing/common/env.h b/library/cpp/testing/common/env.h index 6cd840442f86..f9a5aff5d338 100644 --- a/library/cpp/testing/common/env.h +++ b/library/cpp/testing/common/env.h @@ -69,7 +69,6 @@ namespace NPrivate { void AddTestParam(TStringBuf name, TStringBuf value); bool IsRunningFromTest; - TString ArcadiaTestsDataDir; TString SourceRoot; TString BuildRoot; TString WorkPath; From d9f54072f212c0e086a7ad5af62e25925444c8d9 Mon Sep 17 00:00:00 2001 From: ivanmorozov333 Date: Mon, 7 Apr 2025 19:59:05 +0300 Subject: [PATCH 017/454] logging deserialization control (#16870) --- .../formats/arrow/accessor/composite_serial/accessor.cpp | 5 +++++ ydb/core/formats/arrow/accessor/composite_serial/accessor.h | 1 + 2 files changed, 6 insertions(+) diff --git a/ydb/core/formats/arrow/accessor/composite_serial/accessor.cpp b/ydb/core/formats/arrow/accessor/composite_serial/accessor.cpp index bf388d2ef731..bcebf9136f2a 100644 --- a/ydb/core/formats/arrow/accessor/composite_serial/accessor.cpp +++ b/ydb/core/formats/arrow/accessor/composite_serial/accessor.cpp @@ -2,6 +2,7 @@ #include +#include #include namespace NKikimr::NArrow::NAccessor { @@ -11,6 +12,10 @@ IChunkedArray::TLocalChunkedArrayAddress TDeserializeChunkedArray::DoGetLocalChu if (PredefinedArray) { return TLocalChunkedArrayAddress(PredefinedArray, 0, 0); } + if (Counter.Inc() > 1) { + AFL_WARN(NKikimrServices::ARROW_HELPER)("event", "many_deserializations")("counter", Counter.Val())("size", Data.size())( + "buffer", DataBuffer.size()); + } if (!!Data) { return TLocalChunkedArrayAddress(Loader->ApplyVerified(Data, GetRecordsCount()), 0, 0); } else { diff --git a/ydb/core/formats/arrow/accessor/composite_serial/accessor.h b/ydb/core/formats/arrow/accessor/composite_serial/accessor.h index 8353a238603d..81c9828fb4a3 100644 --- a/ydb/core/formats/arrow/accessor/composite_serial/accessor.h +++ b/ydb/core/formats/arrow/accessor/composite_serial/accessor.h @@ -13,6 +13,7 @@ class TDeserializeChunkedArray: public IChunkedArray { const TString Data; const TStringBuf DataBuffer; const bool ForLazyInitialization; + mutable TAtomicCounter Counter = 0; protected: virtual std::shared_ptr DoISlice(const ui32 offset, const ui32 count) const override { From 49244c8f545b84a206a097979adcb347edcab40b Mon Sep 17 00:00:00 2001 From: ivanmorozov333 Date: Mon, 7 Apr 2025 19:59:21 +0300 Subject: [PATCH 018/454] one path will not reduce write speed for another (#16855) --- .../tx/columnshard/tablet/write_queue.cpp | 40 ++++++++++++------- ydb/core/tx/columnshard/tablet/write_queue.h | 6 ++- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/ydb/core/tx/columnshard/tablet/write_queue.cpp b/ydb/core/tx/columnshard/tablet/write_queue.cpp index 41291f1d6f08..75726189c77e 100644 --- a/ydb/core/tx/columnshard/tablet/write_queue.cpp +++ b/ydb/core/tx/columnshard/tablet/write_queue.cpp @@ -7,12 +7,6 @@ namespace NKikimr::NColumnShard { bool TWriteTask::Execute(TColumnShard* owner, const TActorContext& /* ctx */) { - auto overloadStatus = owner->CheckOverloadedWait(PathId); - if (overloadStatus != TColumnShard::EOverloadStatus::None) { - AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_WRITE)("event", "wait_overload")("status", overloadStatus); - return false; - } - owner->Counters.GetCSCounters().WritingCounters->OnWritingTaskDequeue(TMonotonic::Now() - Created); owner->OperationsManager->RegisterLock(LockId, owner->Generation()); auto writeOperation = owner->OperationsManager->RegisterOperation( @@ -37,21 +31,39 @@ bool TWriteTasksQueue::Drain(const bool onWakeup, const TActorContext& ctx) { if (onWakeup) { WriteTasksOverloadCheckerScheduled = false; } - while (WriteTasks.size() && WriteTasks.front().Execute(Owner, ctx)) { - WriteTasks.pop_front(); + std::vector toRemove; + ui32 countTasks = 0; + for (auto&& i : WriteTasks) { + auto overloadStatus = Owner->CheckOverloadedWait(i.first); + if (overloadStatus != TColumnShard::EOverloadStatus::None) { + countTasks += i.second.size(); + AFL_DEBUG(NKikimrServices::TX_COLUMNSHARD_WRITE)("event", "wait_overload")("status", overloadStatus)("path_id", i.first)( + "size", i.second.size()); + continue; + } + for (auto&& t : i.second) { + t.Execute(Owner, ctx); + } + toRemove.emplace_back(i.first); } - if (WriteTasks.size() && !WriteTasksOverloadCheckerScheduled) { + + for (auto&& i : toRemove) { + AFL_VERIFY(WriteTasks.erase(i)); + } + + if (countTasks && !WriteTasksOverloadCheckerScheduled) { Owner->Schedule(TDuration::MilliSeconds(300), new NActors::TEvents::TEvWakeup(1)); WriteTasksOverloadCheckerScheduled = true; - AFL_WARN(NKikimrServices::TX_COLUMNSHARD)("event", "queue_on_write")("size", WriteTasks.size()); + AFL_WARN(NKikimrServices::TX_COLUMNSHARD)("event", "queue_on_write")("size", countTasks); } - Owner->Counters.GetCSCounters().WritingCounters->QueueWaitSize->Add((i64)WriteTasks.size() - PredWriteTasksSize); - PredWriteTasksSize = (i64)WriteTasks.size(); - return !WriteTasks.size(); + Owner->Counters.GetCSCounters().WritingCounters->QueueWaitSize->Add((i64)countTasks - PredWriteTasksSize); + PredWriteTasksSize = (i64)countTasks; + return !countTasks; } void TWriteTasksQueue::Enqueue(TWriteTask&& task) { - WriteTasks.emplace_back(std::move(task)); + const TInternalPathId pathId = task.GetPathId(); + WriteTasks[pathId].emplace_back(std::move(task)); } TWriteTasksQueue::~TWriteTasksQueue() { diff --git a/ydb/core/tx/columnshard/tablet/write_queue.h b/ydb/core/tx/columnshard/tablet/write_queue.h index 4e0c63363b1d..aba35e5a6a20 100644 --- a/ydb/core/tx/columnshard/tablet/write_queue.h +++ b/ydb/core/tx/columnshard/tablet/write_queue.h @@ -35,6 +35,10 @@ class TWriteTask: TMoveOnly { , Behaviour(behaviour) { } + const TInternalPathId& GetPathId() const { + return PathId; + } + const TMonotonic& GetCreatedMonotonic() const { return Created; } @@ -45,7 +49,7 @@ class TWriteTask: TMoveOnly { class TWriteTasksQueue { private: bool WriteTasksOverloadCheckerScheduled = false; - std::deque WriteTasks; + THashMap> WriteTasks; i64 PredWriteTasksSize = 0; TColumnShard* Owner; From ed42893d193c9b8c29e2d92b5e1e05219e71fd79 Mon Sep 17 00:00:00 2001 From: Vlad Kuznetsov Date: Mon, 7 Apr 2025 19:37:30 +0200 Subject: [PATCH 019/454] Remove obsolete LWTRACE_DISABLE macro from dsproxy code (#16331) --- ydb/core/blobstorage/dsproxy/root_cause.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ydb/core/blobstorage/dsproxy/root_cause.h b/ydb/core/blobstorage/dsproxy/root_cause.h index eaf66668aba7..037136ab9370 100644 --- a/ydb/core/blobstorage/dsproxy/root_cause.h +++ b/ydb/core/blobstorage/dsproxy/root_cause.h @@ -36,9 +36,6 @@ struct TRootCause { // Walk the cause tree from leaf to root and output it as an LWTRACK void RenderTrack(NLWTrace::TOrbit &orbit) { -#ifdef LWTRACE_DISABLE - Y_UNUSED(orbit); -#else //LWTRACE_DISABLE if (HasShuttles(orbit)) { if (CurrentCauseIdx < Items.size()) { const TRootCauseItem &item = Items[CurrentCauseIdx]; @@ -59,7 +56,6 @@ struct TRootCause { } } } -#endif //LWTRACE_DISABLE } ui64 RegisterCause(const TString& requestType = "") { @@ -104,4 +100,3 @@ struct TRootCause { }; }//NKikimr - From 6c875d70074d3a43fed57fbda3161320e1259aa2 Mon Sep 17 00:00:00 2001 From: azevaykin <145343289+azevaykin@users.noreply.github.com> Date: Mon, 7 Apr 2025 21:02:11 +0300 Subject: [PATCH 020/454] YDB: How to implement streaming RAG (#16845) --- .../_includes/conferences/2025/fossasia.md | 17 ++++++++++++++++- ydb/docs/en/presets.yaml | 4 ++++ ydb/docs/ru/presets.yaml | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ydb/docs/en/core/public-materials/_includes/conferences/2025/fossasia.md b/ydb/docs/en/core/public-materials/_includes/conferences/2025/fossasia.md index 4ba08f594860..1d69e802441d 100644 --- a/ydb/docs/en/core/public-materials/_includes/conferences/2025/fossasia.md +++ b/ydb/docs/en/core/public-materials/_includes/conferences/2025/fossasia.md @@ -1,4 +1,4 @@ -## Designing YDB: Constructing a Distributed cloud-native DBMS for OLTP and OLAP from the Ground Up {#2025-conf-fosdem} +## Designing YDB: Constructing a Distributed cloud-native DBMS for OLTP and OLAP from the Ground Up {#2025-conf-fossasia-ivanov} {% include notitle [database_internals_tag](../../tags.md#database_internals) %} @@ -13,3 +13,18 @@ In this session, we will briefly introduce the problems, challenges, and fallaci The presentation will be of interest to developers of high-load systems and platform developers for various purposes. [Slides](https://presentations.ydb.tech/2025/en/fossasia/designing_ydb/presentation.pdf) + +## YDB: How to implement streaming RAG in a distributed database {#2025-conf-fossasia-zevaykin-kalinina} + +{% include notitle [database_internals_tag](../../tags.md#database_internals) %} + +Extracting real-time insights from multi-modal data streams across diverse domains presents an ongoing challenge. A promising solution lies in the implementation of Streaming Retrieval-Augmented Generation (RAG) techniques. YDB enhances this approach by offering robust services for both streaming and vector search, facilitating more efficient and effective data processing and retrieval. +YDB is a versatile open-source Distributed SQL Database that combines high availability and scalability with strong consistency and ACID transactions. + +[{{ team.zevaykin.name }}]({{ team.zevaykin.profile }}) ({{ team.zevaykin.position }}) and [{{ team.kalinina.name }}]({{ team.kalinina.profile }}) ({{ team.kalinina.position }}) discussed an approach to implementing streaming RAG in YDB. + +@[YouTube](https://www.youtube.com/watch?v=GjV8RBNl_4Q) + +The presentation will be of interest to developers of high-load systems and platform developers for various purposes. + +[Slides](https://presentations.ydb.tech/2025/en/fossasia/streaming_rag/presentation.pdf) diff --git a/ydb/docs/en/presets.yaml b/ydb/docs/en/presets.yaml index 009b9d4e3c66..1069f6a08590 100644 --- a/ydb/docs/en/presets.yaml +++ b/ydb/docs/en/presets.yaml @@ -16,6 +16,10 @@ default: name: Evgenii Ivanov position: Senior developer profile: https://www.linkedin.com/in/eivanov89/ + zevaykin: + name: Alexander Zevaykin + position: Team leader + profile: https://www.linkedin.com/in/alexander-zevaykin-6bb8162bb/ ozeritskiy: name: Alexey Ozeritskiy position: Lead Software Engineer diff --git a/ydb/docs/ru/presets.yaml b/ydb/docs/ru/presets.yaml index 32f3359a1f6d..487a89592419 100644 --- a/ydb/docs/ru/presets.yaml +++ b/ydb/docs/ru/presets.yaml @@ -110,7 +110,7 @@ default: profile: https://www.linkedin.com/in/jorres-tarasov/ zevaykin: name: Александр Зевайкин - position: Технический лидер + position: Руководитель группы profile: https://www.linkedin.com/in/alexander-zevaykin-6bb8162bb/ zverev: name: Евгений Зверев From fca7a28fa8f1c02d1e0abcbb4c96ed278aefd691 Mon Sep 17 00:00:00 2001 From: Slusarenko Igor Date: Mon, 7 Apr 2025 21:03:19 +0300 Subject: [PATCH 021/454] Add ddl to create an iceberg data source (#16652) --- .../external_source_builder.cpp | 205 +++++++++++++++ .../external_source_builder.h | 118 +++++++++ .../external_source_builder_ut.cpp | 207 +++++++++++++++ .../external_source_factory.cpp | 51 +++- ydb/core/external_sources/iceberg_ddl_ut.cpp | 84 ++++++ ydb/core/external_sources/iceberg_fields.h | 35 +++ ydb/core/external_sources/ut/ya.make | 4 +- ydb/core/external_sources/ya.make | 1 + .../external_data_source/manager.cpp | 11 +- .../kqp/ut/federated_query/common/common.cpp | 6 +- .../kqp/ut/federated_query/common/common.h | 3 +- .../generic_ut/iceberg_ut_data.cpp | 247 ++++++++++++++++++ .../generic_ut/iceberg_ut_data.h | 66 +++++ .../generic_ut/kqp_generic_provider_ut.cpp | 174 ++++++++++-- .../kqp/ut/federated_query/generic_ut/ya.make | 2 + .../db_id_async_resolver/database_type.cpp | 21 +- .../db_id_async_resolver/database_type.h | 3 +- .../actors/yql_generic_provider_factories.cpp | 3 +- .../provider/yql_generic_cluster_config.cpp | 42 +++ .../provider/yql_generic_dq_integration.cpp | 9 +- .../provider/yql_generic_load_meta.cpp | 57 ++++ .../kqprun/configuration/app_config.conf | 1 + 22 files changed, 1317 insertions(+), 33 deletions(-) create mode 100644 ydb/core/external_sources/external_source_builder.cpp create mode 100644 ydb/core/external_sources/external_source_builder.h create mode 100644 ydb/core/external_sources/external_source_builder_ut.cpp create mode 100644 ydb/core/external_sources/iceberg_ddl_ut.cpp create mode 100644 ydb/core/external_sources/iceberg_fields.h create mode 100644 ydb/core/kqp/ut/federated_query/generic_ut/iceberg_ut_data.cpp create mode 100644 ydb/core/kqp/ut/federated_query/generic_ut/iceberg_ut_data.h diff --git a/ydb/core/external_sources/external_source_builder.cpp b/ydb/core/external_sources/external_source_builder.cpp new file mode 100644 index 000000000000..e773f052cc58 --- /dev/null +++ b/ydb/core/external_sources/external_source_builder.cpp @@ -0,0 +1,205 @@ +#include "external_source_builder.h" +#include "validation_functions.h" + +#include +#include + +namespace NKikimr::NExternalSource { +namespace { + +class TValidatedExternalDataSource final : public IExternalSource { +public: + TValidatedExternalDataSource( + const TString& name, + const std::vector& authMethods, + const std::unordered_map& availableProperties, + const std::vector& hostnamePatterns) + : Name_(name) + , AuthMethodsForCheck_(authMethods) + , AvailableProperties_(availableProperties) + , HostnamePatterns_(hostnamePatterns) + { + + } + + virtual TString Pack(const NKikimrExternalSources::TSchema&, + const NKikimrExternalSources::TGeneral&) const override { + ythrow TExternalSourceException() << "Internal error. Only external table supports pack operation"; + } + + virtual TString GetName() const override { + return Name_; + } + + virtual bool HasExternalTable() const override { + return false; + } + + virtual TVector GetAuthMethods() const override { + TVector result; + + for (auto a : AuthMethodsForCheck_) { + result.push_back(a.Auth); + } + + return result; + } + + TVector GetAuthMethods(const TString& externalDataSourceDescription) const { + NKikimrSchemeOp::TExternalDataSourceDescription proto; + + if (!proto.ParseFromString(externalDataSourceDescription)) { + ythrow TExternalSourceException() + << "Internal error. " + << "Couldn't parse protobuf with external data source description"; + } + + TVector result; + + for (auto a : AuthMethodsForCheck_) { + if (a.UseCondition(proto.GetProperties().GetProperties())) { + result.push_back(a.Auth); + } + } + + return result; + } + + virtual TMap> GetParameters(const TString&) const override { + ythrow TExternalSourceException() << "Internal error. Only external table supports parameters"; + } + + virtual void ValidateExternalDataSource(const TString& externalDataSourceDescription) const override { + NKikimrSchemeOp::TExternalDataSourceDescription proto; + + if (!proto.ParseFromString(externalDataSourceDescription)) { + ythrow TExternalSourceException() + << "Internal error. " + << "Couldn't parse protobuf with external data source description"; + } + + auto properties = proto.GetProperties().GetProperties(); + std::unordered_set validatedProperties; + + for (const auto& [key, value] : properties) { + auto p = AvailableProperties_.find(key); + + if (AvailableProperties_.end() == p) { + throw TExternalSourceException() << "Unsupported property: " << key; + } + + // validate property value + if (p->second.ApplyCondition(properties)) { + p->second.Validator(key, value); + } + + validatedProperties.emplace(key); + } + + // validate properties that has been left + for (const auto& [property, validator] : AvailableProperties_) { + if (validatedProperties.contains(property)) { + continue; + } + + if (validator.ApplyCondition(properties)) { + validator.Validator(property, ""); + } + } + + ValidateHostname(HostnamePatterns_, proto.GetLocation()); + } + + virtual NThreading::TFuture> LoadDynamicMetadata(std::shared_ptr meta) override { + return NThreading::MakeFuture(std::move(meta)); + } + + virtual bool CanLoadDynamicMetadata() const override { + return false; + } + +private: + const TString Name_; + const std::vector AuthMethodsForCheck_; + const std::unordered_map AvailableProperties_; + const std::vector HostnamePatterns_; +}; + +} // unnamed + +TExternalSourceBuilder::TExternalSourceBuilder(const TString& name) + : Name_(name) +{ +} + +TExternalSourceBuilder& TExternalSourceBuilder::Auth(const TVector& authMethods, TCondition condition) { + for (auto a : authMethods) { + AuthMethodsForCheck_.push_back(TExternalSourceBuilder::TAuthHolder{a, condition}); + } + + return *this; +} + +TExternalSourceBuilder& TExternalSourceBuilder::Property(TString name, TValidator validator, TCondition condition) { + AvailableProperties_.emplace(name, TExternalSourceBuilder::TConditionalValidator{validator, condition}); + return *this; +} + +TExternalSourceBuilder& TExternalSourceBuilder::Properties(const TSet& availableProperties, TValidator validator, TCondition condition) { + for (auto p : availableProperties) { + Property(p, validator, condition); + } + + return *this; +} + +TExternalSourceBuilder& TExternalSourceBuilder::HostnamePatterns(const std::vector& patterns) { + HostnamePatterns_.insert( + HostnamePatterns_.end(), patterns.begin(), patterns.end()); + return *this; +} + +IExternalSource::TPtr TExternalSourceBuilder::Build() { + return MakeIntrusive( + std::move(Name_), std::move(AuthMethodsForCheck_), std::move(AvailableProperties_), std::move(HostnamePatterns_)); +} + +TCondition GetHasSettingCondition(const TString& property, const TString& value) { + return [property, value](const ::google::protobuf::Map& properties) -> bool { + auto it = properties.find(property); + return properties.end() != it && value == it->second; + }; +} + +TValidator GetRequiredValidator() { + return [](const TString& property, const TString& value){ + if (!value.empty()) { + return; + } + + throw TExternalSourceException() << "required property: " << property << " is not set"; + }; +} + +TValidator GetIsInListValidator(const std::unordered_set& values, bool required) { + auto joinedValues = JoinSeq(", ", values); + + return [values, required, joinedValues](const TString& property, const TString& value){ + if (value.empty() && required) { + throw TExternalSourceException() << " required property: " << property << " is not set"; + } + + if (value.empty()) { + return; + } + + if (!values.contains(value)) { + throw TExternalSourceException() + << " property: " << property + << " has wrong value: " << value + << " allowed values: " << joinedValues; + } + }; +} + +} // NKikimr::NExternalSource diff --git a/ydb/core/external_sources/external_source_builder.h b/ydb/core/external_sources/external_source_builder.h new file mode 100644 index 000000000000..2da604086e69 --- /dev/null +++ b/ydb/core/external_sources/external_source_builder.h @@ -0,0 +1,118 @@ +#pragma once + +#include "external_source.h" + +#include +#include + +namespace NKikimr::NExternalSource { + +typedef std::function TValidator; +typedef std::function&)> TCondition; + +/// +/// Builder to create an external data source with validations +/// +class TExternalSourceBuilder { +public: + struct TAuthHolder { + TString Auth; + + // When auth has to be used + TCondition UseCondition; + }; + + struct TConditionalValidator { + TValidator Validator; + + // When validator has to be applied + TCondition ApplyCondition; + }; + +public: + explicit TExternalSourceBuilder(const TString& name); + + ~TExternalSourceBuilder() = default; + + /// + /// Add auth methods which are returned from the "source" only if a condition is true. + /// A condition is applied to source's ddl in @sa IExternalSource::GetAuthMethods + /// call. + /// + TExternalSourceBuilder& Auth(const TVector& authMethods, TCondition condition); + + TExternalSourceBuilder& Auth(const TVector& authMethods) { + return Auth(authMethods, [](const ::google::protobuf::Map&){ + return true; + }); + } + + /// + /// Add property which can be in a "source". + /// + /// @param name name of a property + /// @param validator validator which is applied to a property from a source's ddl + /// in @sa IExternalSource::ValidateExternalDataSource call + /// @param condition condition that defines to use validator or not, if condition returns true + /// for source's ddl then validator is applied; otherwise, validator is skiped; + /// condition is executed in @sa IExternalSource::ValidateExternalDataSource call + /// before validator + /// + TExternalSourceBuilder& Property(const TString name, TValidator validator, TCondition condition); + + TExternalSourceBuilder& Properties(const TSet& properties, TValidator validator, TCondition condition); + + TExternalSourceBuilder& HostnamePatterns(const std::vector& patterns); + + /// + /// Create external data source + /// + IExternalSource::TPtr Build(); + + TExternalSourceBuilder& Property(const TString name, TValidator validator) { + return Property(name, validator, [](const ::google::protobuf::Map&){ + return true; + }); + } + + TExternalSourceBuilder& Property(const TString name) { + return Property(name, [](const TString&, const TString&){}); + } + + TExternalSourceBuilder& Properties(const TSet& properties, TValidator validator) { + return Properties(properties, validator, [](const ::google::protobuf::Map&){ + return true; + }); + } + + TExternalSourceBuilder& Properties(const TSet& properties) { + return Properties(properties, [](const TString&, const TString&){}); + } + + private: + TString Name_; + std::vector AuthMethodsForCheck_; + std::unordered_map AvailableProperties_; + std::vector HostnamePatterns_; +}; + +/// +/// Create a condition that returns "true" if a source's ddl has +/// property "p" with value equals to "v" +/// +TCondition GetHasSettingCondition(const TString& p, const TString& v); + +/// +/// Create a validator which check that source's ddl has a property with non empty value +/// +TValidator GetRequiredValidator(); + +/// +/// Create a validator which check that source's ddl has a property with a value from list +/// +/// @param values list of allowed values +/// @param required allow property without value +/// +TValidator GetIsInListValidator(const std::unordered_set& values, bool required); + +} // NKikimr::NExternalSource diff --git a/ydb/core/external_sources/external_source_builder_ut.cpp b/ydb/core/external_sources/external_source_builder_ut.cpp new file mode 100644 index 000000000000..0242e6f8273e --- /dev/null +++ b/ydb/core/external_sources/external_source_builder_ut.cpp @@ -0,0 +1,207 @@ +#include "external_source_builder.h" + +#include +#include +#include +#include + +namespace NKikimr { + +namespace { + +class TTestFixture : public NUnitTest::TBaseFixture { +public: + TTestFixture() + : Builder("Test") + , Props(*Proto.MutableProperties()->MutableProperties()) + { + } + +public: + void SetUp(NUnitTest::TTestContext& context) override { + NUnitTest::TBaseFixture::SetUp(context); + } + +protected: + NExternalSource::TExternalSourceBuilder Builder; + NKikimrSchemeOp::TExternalDataSourceDescription Proto; + ::google::protobuf::Map& Props; +}; + +} + +Y_UNIT_TEST_SUITE(ExternalSourceBuilderTest) { + + Y_UNIT_TEST_F(ValidateName, TTestFixture) { + auto source = Builder.Build(); + UNIT_ASSERT_VALUES_EQUAL(source->GetName(), "Test"); + } + + // Test returned auth methods when conditions are not set + Y_UNIT_TEST_F(ValidateAuthWithoutCondition, TTestFixture) { + auto source = Builder + .Auth({"auth1", "auth2"}) + .Build(); + + const auto authMethods = source->GetAuthMethods(); + + UNIT_ASSERT_VALUES_EQUAL(authMethods.size(), 2); + UNIT_ASSERT_VALUES_EQUAL(authMethods[0], "auth1"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[1], "auth2"); + } + + // Test returned auth methods when conditions are set + Y_UNIT_TEST_F(ValidateAuthWithCondition, TTestFixture) { + auto source = Builder + .Auth( + {"auth1", "auth2"}, + // check that ddl has "property1" equals to "value" + NExternalSource::GetHasSettingCondition("property1", "value") + ) + .Auth( + {"auth3", "auth4"}, + // check that ddl has "property2" equals to "value" + NExternalSource::GetHasSettingCondition("property2", "value") + ) + .Build(); + + // ddl without any value + auto authMethods = source->GetAuthMethods(); + + UNIT_ASSERT_VALUES_EQUAL(authMethods.size(), 4); + UNIT_ASSERT_VALUES_EQUAL(authMethods[0], "auth1"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[1], "auth2"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[2], "auth3"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[3], "auth4"); + } + + // Test validation when ddl has property which is not supported by source + // i.e. source does not contain this property in a list of available properties + Y_UNIT_TEST_F(ValidateUnsupportedField, TTestFixture) { + // source has property "field" + auto source = Builder + .Property("field") + .Build(); + + // ddl with "field1" + Props["field1"] = "value"; + + UNIT_ASSERT_EXCEPTION_CONTAINS( + source->ValidateExternalDataSource(Proto.SerializeAsString()), + NExternalSource::TExternalSourceException, + "Unsupported property: field1" + ); + + // ddl with "field" + Props.clear(); + Props["field"] = "value"; + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + } + + // Test validation for non required property + Y_UNIT_TEST_F(ValidateNonRequiredField, TTestFixture) { + auto source = Builder + .Property("field") + .Build(); + + // ddl without "field" + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + + // ddl with "field" + Props["field"] = "value"; + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + } + + // Test validation for required property + Y_UNIT_TEST_F(ValidateRequiredField, TTestFixture) { + auto source = Builder + .Property("field", NExternalSource::GetRequiredValidator()) + .Build(); + + // ddl without "field" + UNIT_ASSERT_EXCEPTION_CONTAINS( + source->ValidateExternalDataSource(Proto.SerializeAsString()), + NExternalSource::TExternalSourceException, + "required property: field is not set" + ); + + // ddl with "field" + Props["field"] = "value"; + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + } + + // Test validation for non required property with allowed list of values + Y_UNIT_TEST_F(ValidateNonRequiredFieldValues, TTestFixture) { + auto source = Builder + .Property("field", NExternalSource::GetIsInListValidator({"v1", "v2", "v3"}, false)) + .Build(); + + // ddl without "field" + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource("")); + } + + // Test validation for required property with allowed list of values + Y_UNIT_TEST_F(ValidateRequiredFieldValues, TTestFixture) { + auto source = Builder + .Property("field", NExternalSource::GetIsInListValidator({"v1", "v2", "v3"}, true)) + .Build(); + + // ddl without "field" + UNIT_ASSERT_EXCEPTION_CONTAINS( + source->ValidateExternalDataSource(Proto.SerializeAsString()), + NExternalSource::TExternalSourceException, + "required property: field is not set" + ); + + // ddl with "field" equals to value not in allowed list + Props["field"] = "value"; + UNIT_ASSERT_EXCEPTION_CONTAINS( + source->ValidateExternalDataSource(Proto.SerializeAsString()), + NExternalSource::TExternalSourceException, + "property: field has wrong value: value allowed values: v3, v2, v1" + ); + + // ddl with "field" equals to "v1" + Props["field"] = "v1"; + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + + // ddl with "field" equals to "v2" + Props["field"] = "v2"; + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + + // ddl with "field" equals to "v3" + Props["field"] = "v3"; + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + } + + // Test validation for required property with condition + Y_UNIT_TEST_F(ValidateRequiredFieldOnCondition, TTestFixture) { + auto source = Builder + .Property("field1") + .Property( + "field", + NExternalSource::GetRequiredValidator(), + // apply validator if ddl has "field1" equals to "v" + NExternalSource::GetHasSettingCondition("field1", "v") + ) + .Build(); + + // ddl without "field1" + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + + // ddl with "field1" but without "field" + Props["field1"] = "v"; + + UNIT_ASSERT_EXCEPTION_CONTAINS( + source->ValidateExternalDataSource(Proto.SerializeAsString()), + NExternalSource::TExternalSourceException, + "required property: field is not set" + ); + + // ddl with "field1" and "field" + Props["field"] = "q"; + UNIT_ASSERT_NO_EXCEPTION(source->ValidateExternalDataSource(Proto.SerializeAsString())); + } +} + +} // NKikimr diff --git a/ydb/core/external_sources/external_source_factory.cpp b/ydb/core/external_sources/external_source_factory.cpp index 72814eda6b10..4f7caa7ebe73 100644 --- a/ydb/core/external_sources/external_source_factory.cpp +++ b/ydb/core/external_sources/external_source_factory.cpp @@ -1,6 +1,8 @@ #include "external_source_factory.h" #include "object_storage.h" #include "external_data_source.h" +#include "iceberg_fields.h" +#include "external_source_builder.h" #include #include @@ -8,7 +10,6 @@ #include #include - namespace NKikimr::NExternalSource { namespace { @@ -39,6 +40,50 @@ struct TExternalSourceFactory : public IExternalSourceFactory { } + +IExternalSource::TPtr BuildIcebergSource(const std::vector& hostnamePatternsRegEx) { + using namespace NKikimr::NExternalSource::NIceberg; + + return TExternalSourceBuilder(TString{NYql::GenericProviderName}) + // Basic, Token and SA Auth are available only if warehouse type is set to s3 + .Auth( + {"BASIC", "TOKEN", "SERVICE_ACCOUNT"}, + GetHasSettingCondition(WAREHOUSE_TYPE, VALUE_S3) + ) + // DataBase is a required field + .Property(WAREHOUSE_DB, GetRequiredValidator()) + // Tls is an optional field + .Property(WAREHOUSE_TLS) + // Warehouse type is a required field and can be equal only to "s3" + .Property( + WAREHOUSE_TYPE, + GetIsInListValidator({VALUE_S3}, true) + ) + // If a warehouse type is equal to "s3", fields "s3_endpoint", "s3_region" and "s3_uri" are required + .Properties( + { + WAREHOUSE_S3_ENDPOINT, + WAREHOUSE_S3_REGION, + WAREHOUSE_S3_URI + }, + GetRequiredValidator(), + GetHasSettingCondition(WAREHOUSE_TYPE, VALUE_S3) + ) + // Catalog type is a required field and can be equal only to "hive" or "hadoop" + .Property( + CATALOG_TYPE, + GetIsInListValidator({VALUE_HIVE, VALUE_HADOOP}, true) + ) + // If catalog type is equal to "hive" the field "hive_uri" is required + .Property( + CATALOG_HIVE_URI, + GetRequiredValidator(), + GetHasSettingCondition(CATALOG_TYPE,VALUE_HIVE) + ) + .HostnamePatterns(hostnamePatternsRegEx) + .Build(); +} + IExternalSourceFactory::TPtr CreateExternalSourceFactory(const std::vector& hostnamePatterns, NActors::TActorSystem* actorSystem, size_t pathsLimit, @@ -91,6 +136,10 @@ IExternalSourceFactory::TPtr CreateExternalSourceFactory(const std::vector +#include +#include +#include +#include + +namespace NKikimr { + +namespace { + +class TTestFixture : public NUnitTest::TBaseFixture { +public: + TTestFixture() + : Props(*Proto.MutableProperties()->MutableProperties()) + { + using namespace NKikimr::NExternalSource::NIceberg; + + auto type = ToString(NYql::EDatabaseType::Iceberg); + auto factory = NExternalSource::CreateExternalSourceFactory( + {}, nullptr, 50000, nullptr, false, false, {type}); + + Source = factory->GetOrCreate(type); + + Props[WAREHOUSE_TYPE] = VALUE_S3; + Props[WAREHOUSE_DB] = "db"; + Props[WAREHOUSE_S3_REGION] = "region"; + Props[WAREHOUSE_S3_ENDPOINT] = "endpoint"; + Props[WAREHOUSE_S3_URI] = "uri"; + } + +public: + void SetUp(NUnitTest::TTestContext& context) override { + NUnitTest::TBaseFixture::SetUp(context); + } + +protected: + NExternalSource::IExternalSource::TPtr Source; + NKikimrSchemeOp::TExternalDataSourceDescription Proto; + ::google::protobuf::Map& Props; +}; + +} // unnamed + +Y_UNIT_TEST_SUITE(IcebergDdlTest) { + + // Test ddl for an iceberg table in s3 storage with the hive catalog + Y_UNIT_TEST_F(HiveCatalogWithS3Test, TTestFixture) { + using namespace NKikimr::NExternalSource::NIceberg; + + Props[CATALOG_TYPE] = VALUE_HIVE; + Props[CATALOG_HIVE_URI] = "hive_uri"; + + UNIT_ASSERT_NO_EXCEPTION(Source->ValidateExternalDataSource(Proto.SerializeAsString())); + + auto authMethods = Source->GetAuthMethods(); + + UNIT_ASSERT_VALUES_EQUAL(authMethods.size(), 3); + UNIT_ASSERT_VALUES_EQUAL(authMethods[0], "BASIC"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[1], "TOKEN"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[2], "SERVICE_ACCOUNT"); + } + + // Test ddl for an iceberg table in s3 storage with the hadoop catalog + Y_UNIT_TEST_F(HadoopCatalogWithS3Test, TTestFixture) { + using namespace NKikimr::NExternalSource::NIceberg; + + Props[CATALOG_TYPE] = VALUE_HADOOP; + + UNIT_ASSERT_NO_EXCEPTION(Source->ValidateExternalDataSource(Proto.SerializeAsString())); + + auto authMethods = Source->GetAuthMethods(); + + UNIT_ASSERT_VALUES_EQUAL(authMethods.size(), 3); + UNIT_ASSERT_VALUES_EQUAL(authMethods[0], "BASIC"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[1], "TOKEN"); + UNIT_ASSERT_VALUES_EQUAL(authMethods[2], "SERVICE_ACCOUNT"); + } + +} + +} // NKikimr diff --git a/ydb/core/external_sources/iceberg_fields.h b/ydb/core/external_sources/iceberg_fields.h new file mode 100644 index 000000000000..5a00f8e607f5 --- /dev/null +++ b/ydb/core/external_sources/iceberg_fields.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +namespace NKikimr::NExternalSource::NIceberg { + +// Fields that belongs to a warehouse +constexpr char WAREHOUSE_TYPE[] = "warehouse_type"; +constexpr char WAREHOUSE_S3_ENDPOINT[] = "warehouse_s3_endpoint"; +constexpr char WAREHOUSE_S3_URI[] = "warehouse_s3_uri"; +constexpr char WAREHOUSE_S3_REGION[] = "warehouse_s3_region"; +constexpr char WAREHOUSE_TLS[] = "use_tls"; +constexpr char WAREHOUSE_DB[] = "database_name"; + +// Fields that belongs to a catalog +constexpr char CATALOG_TYPE[] = "catalog_type"; +constexpr char CATALOG_HIVE_URI[] = "catalog_hive_uri"; + +// Some values +constexpr char VALUE_S3[] = "s3"; +constexpr char VALUE_HIVE[] = "hive"; +constexpr char VALUE_HADOOP[] = "hadoop"; + +// List of fields which is pass to a connector +constexpr std::array FieldsToConnector = { + WAREHOUSE_TYPE, + WAREHOUSE_S3_ENDPOINT, + WAREHOUSE_S3_REGION, + WAREHOUSE_S3_URI, + CATALOG_TYPE, + CATALOG_HIVE_URI +}; + +} // NKikimr::NExternalSource::NIceberg diff --git a/ydb/core/external_sources/ut/ya.make b/ydb/core/external_sources/ut/ya.make index b21cd87b1144..8503f40abd48 100644 --- a/ydb/core/external_sources/ut/ya.make +++ b/ydb/core/external_sources/ut/ya.make @@ -6,8 +6,10 @@ PEERDIR( ) SRCS( - object_storage_ut.cpp external_data_source_ut.cpp + external_source_builder_ut.cpp + iceberg_ddl_ut.cpp + object_storage_ut.cpp ) END() diff --git a/ydb/core/external_sources/ya.make b/ydb/core/external_sources/ya.make index 9a93b7bb484e..3a764cd08f8c 100644 --- a/ydb/core/external_sources/ya.make +++ b/ydb/core/external_sources/ya.make @@ -2,6 +2,7 @@ LIBRARY() SRCS( external_data_source.cpp + external_source_builder.cpp external_source_factory.cpp object_storage.cpp validation_functions.cpp diff --git a/ydb/core/kqp/gateway/behaviour/external_data_source/manager.cpp b/ydb/core/kqp/gateway/behaviour/external_data_source/manager.cpp index 7668434f045b..55e5fcc77fc7 100644 --- a/ydb/core/kqp/gateway/behaviour/external_data_source/manager.cpp +++ b/ydb/core/kqp/gateway/behaviour/external_data_source/manager.cpp @@ -8,6 +8,7 @@ #include #include +#include namespace NKikimr::NKqp { @@ -91,7 +92,15 @@ TString GetOrEmpty(const NYql::TCreateObjectSettings& container, const TString& }; auto& featuresExtractor = settings.GetFeaturesExtractor(); - for (const auto& property: properties) { + + for (const auto& property : properties) { + if (const auto value = featuresExtractor.Extract(property)) { + externaDataSourceDesc.MutableProperties()->MutableProperties()->insert({property, *value}); + } + } + + // Iceberg properties for connector + for (const auto& property : NKikimr::NExternalSource::NIceberg::FieldsToConnector) { if (const auto value = featuresExtractor.Extract(property)) { externaDataSourceDesc.MutableProperties()->MutableProperties()->insert({property, *value}); } diff --git a/ydb/core/kqp/ut/federated_query/common/common.cpp b/ydb/core/kqp/ut/federated_query/common/common.cpp index d6d04f455a81..153e9a7c2a66 100644 --- a/ydb/core/kqp/ut/federated_query/common/common.cpp +++ b/ydb/core/kqp/ut/federated_query/common/common.cpp @@ -2,6 +2,7 @@ #include #include +#include namespace NKikimr::NKqp::NFederatedQueryTest { TString GetSymbolsString(char start, char end, const TString& skip) { @@ -54,7 +55,8 @@ namespace NKikimr::NKqp::NFederatedQueryTest { NYql::IDatabaseAsyncResolver::TPtr databaseAsyncResolver, std::optional appConfig, std::shared_ptr s3ActorsFactory, - const TKikimrRunnerOptions& optionst) + const TKikimrRunnerOptions& optionst, + NYql::ISecuredServiceAccountCredentialsFactory::TPtr credentialsFactory) { NKikimrConfig::TFeatureFlags featureFlags; featureFlags.SetEnableExternalDataSources(true); @@ -79,7 +81,7 @@ namespace NKikimr::NKqp::NFederatedQueryTest { auto federatedQuerySetupFactory = std::make_shared( httpGateway, connectorClient, - nullptr, + credentialsFactory, databaseAsyncResolver, appConfig->GetQueryServiceConfig().GetS3(), appConfig->GetQueryServiceConfig().GetGeneric(), diff --git a/ydb/core/kqp/ut/federated_query/common/common.h b/ydb/core/kqp/ut/federated_query/common/common.h index 48c17ed7fa11..c3abb5a15ad5 100644 --- a/ydb/core/kqp/ut/federated_query/common/common.h +++ b/ydb/core/kqp/ut/federated_query/common/common.h @@ -28,5 +28,6 @@ namespace NKikimr::NKqp::NFederatedQueryTest { NYql::IDatabaseAsyncResolver::TPtr databaseAsyncResolver = nullptr, std::optional appConfig = std::nullopt, std::shared_ptr s3ActorsFactory = nullptr, - const TKikimrRunnerOptions& options = {}); + const TKikimrRunnerOptions& options = {}, + NYql::ISecuredServiceAccountCredentialsFactory::TPtr credentialsFactory = nullptr); } // namespace NKikimr::NKqp::NFederatedQueryTest diff --git a/ydb/core/kqp/ut/federated_query/generic_ut/iceberg_ut_data.cpp b/ydb/core/kqp/ut/federated_query/generic_ut/iceberg_ut_data.cpp new file mode 100644 index 000000000000..7c4f0e65b31a --- /dev/null +++ b/ydb/core/kqp/ut/federated_query/generic_ut/iceberg_ut_data.cpp @@ -0,0 +1,247 @@ +#include "iceberg_ut_data.h" + +#include +#include + +namespace NTestUtils { + +constexpr char VALUE_HIVE_URI[] = "hive_uri"; +constexpr char VALUE_S3_URI[] = "s3_uri"; +constexpr char VALUE_S3_ENDPOINT[] = "s3_endpoint"; +constexpr char VALUE_S3_REGION[] = "s3_region"; + +constexpr char VALUE_IAM[] = "IAM"; + +struct TTestData { + TTestData(TIcebergTestData* data) + : Credentials_(*Result_.mutable_credentials()) + , Options_(*Result_.mutable_iceberg_options()) + , Warehouse_(*Options_.mutable_warehouse()) + , Catalog_(*Options_.mutable_catalog()) + { + assert(data); + + switch (data->Auth_.Type) { + case TIcebergTestData::AuthBasic: { + auto& auth = *Credentials_.mutable_basic(); + auth.set_username(data->Auth_.Id); + auth.set_password(data->Auth_.Value); + break; + } + case TIcebergTestData::AuthSa: + case TIcebergTestData::AuthToken: { + auto& auth = *Credentials_.mutable_token(); + auth.set_type(data->Auth_.Id); + auth.set_value(data->Auth_.Value); + break; + } + } + + Result_.mutable_endpoint(); + Result_.set_kind(::NYql::EGenericDataSourceKind::ICEBERG); + Result_.set_database(data->Database_); + Result_.set_use_tls(data->UseTls_); + Result_.set_protocol(::NYql::EGenericProtocol::NATIVE); + + auto& s3 = *Warehouse_.mutable_s3(); + + s3.set_uri(VALUE_S3_URI); + s3.set_endpoint(VALUE_S3_ENDPOINT); + s3.set_region(VALUE_S3_REGION); + } + + NYql::TGenericDataSourceInstance Result_; + NYql::TGenericCredentials& Credentials_; + NYql::TIcebergDataSourceOptions& Options_; + NYql::TIcebergWarehouse& Warehouse_; + NYql::TIcebergCatalog& Catalog_; +}; + +TIcebergTestData::TIcebergTestData( + TAuth auth, + const TString& dataSourceName, + const TString& database, + bool useTls) + : Auth_(auth) + , DataSourceName_(dataSourceName) + , Database_(database) + , UseTls_(useTls) +{} + +NYql::TGenericDataSourceInstance TIcebergTestData::CreateDataSourceForHadoop() { + TTestData data(this); + data.Catalog_.mutable_hadoop(); + return data.Result_; +} + +NYql::TGenericDataSourceInstance TIcebergTestData::CreateDataSourceForHive() { + TTestData data(this); + auto& hive = *data.Catalog_.mutable_hive(); + hive.set_uri(VALUE_HIVE_URI); + return data.Result_; +} + +TString TIcebergTestData::CreateAuthSection() { + using namespace fmt::literals; + + switch (Auth_.Type) { + case TIcebergTestData::AuthBasic: + return fmt::format(R"( + AUTH_METHOD="BASIC", + LOGIN="{login}", + PASSWORD_SECRET_NAME="{data_source_name}_p" + )", + "data_source_name"_a = DataSourceName_, + "login"_a = Auth_.Id, + "password"_a = Auth_.Value + ); + case TIcebergTestData::AuthToken: + return fmt::format(R"( + AUTH_METHOD="TOKEN", + TOKEN_SECRET_NAME="{data_source_name}_p" + )", + "data_source_name"_a = DataSourceName_ + ); + case TIcebergTestData::AuthSa: + return fmt::format(R"( + AUTH_METHOD="SERVICE_ACCOUNT", + SERVICE_ACCOUNT_ID="my_sa", + SERVICE_ACCOUNT_SECRET_NAME="{data_source_name}_p" + )", + "data_source_name"_a = DataSourceName_ + ); + }; +} + +TString TIcebergTestData::CreateQuery(const TString& catalogSection) { + using namespace fmt::literals; + + return fmt::format( + R"( + CREATE OBJECT {data_source_name}_p (TYPE SECRET) WITH (value={secret}); + + CREATE EXTERNAL DATA SOURCE {data_source_name} WITH ( + SOURCE_TYPE="{source_type}", + DATABASE_NAME="{database}", + WAREHOUSE_TYPE="{s3}", + WAREHOUSE_S3_REGION="{s3_region}", + WAREHOUSE_S3_ENDPOINT="{s3_endpoint}", + WAREHOUSE_S3_URI="{s3_uri}", + {auth_section}, + {catalog_section}, + USE_TLS="{use_tls}" + ); + )", + "auth_section"_a = CreateAuthSection(), + "s3"_a = NKikimr::NExternalSource::NIceberg::VALUE_S3, + "s3_region"_a = VALUE_S3_REGION, + "s3_endpoint"_a = VALUE_S3_ENDPOINT, + "s3_uri"_a = VALUE_S3_URI, + "data_source_name"_a = DataSourceName_, + "catalog_section"_a = catalogSection, + "secret"_a = Auth_.Value, + "use_tls"_a = UseTls_ ? "TRUE" : "FALSE", + "source_type"_a = ToString(NYql::EDatabaseType::Iceberg), + "database"_a = Database_ + ); +} + +void TIcebergTestData::ExecuteQuery(const std::shared_ptr& kikimr, + const TString& query) +{ + auto c = kikimr->GetTableClient(); + auto session = c.CreateSession().GetValueSync().GetSession(); + auto result = session.ExecuteSchemeQuery(query).GetValueSync(); + UNIT_ASSERT_C(result.GetStatus() == NYdb::EStatus::SUCCESS, result.GetIssues().ToString()); +} + + +void TIcebergTestData::ExecuteCreateHiveExternalDataSource(const std::shared_ptr& kikimr) { + using namespace fmt::literals; + + TString hiveCatalog = fmt::format(R"( + CATALOG_TYPE="{type}", + CATALOG_HIVE_URI="{uri}" + )", + "type"_a = NKikimr::NExternalSource::NIceberg::VALUE_HIVE, + "uri"_a = VALUE_HIVE_URI + ); + + ExecuteQuery(kikimr, CreateQuery(hiveCatalog)); +} + +void TIcebergTestData::ExecuteCreateHadoopExternalDataSource(const std::shared_ptr& kikimr) { + using namespace fmt::literals; + + TString hadoopCatalog = fmt::format(R"( + CATALOG_TYPE="{type}" + )", + "type"_a = NKikimr::NExternalSource::NIceberg::VALUE_HADOOP + ); + + ExecuteQuery(kikimr, CreateQuery(hadoopCatalog)); +} + +class TStaticCredentialsProvider : public NYdb::ICredentialsProvider { +public: + TStaticCredentialsProvider(const TString& yqlToken) + : YqlToken_(yqlToken) + {} + + std::string GetAuthInfo() const override { + return YqlToken_; + } + + bool IsValid() const override { + return true; + } + +private: + std::string YqlToken_; +}; + +class TStaticCredentialsProviderFactory : public NYdb::ICredentialsProviderFactory { +public: + TStaticCredentialsProviderFactory(const TString& yqlToken) + : YqlToken_(yqlToken) + {} + + std::shared_ptr CreateProvider() const override { + return std::make_shared(YqlToken_); + } + +private: + TString YqlToken_; +}; + +class TStaticSecuredCredentialsFactory : public NYql::ISecuredServiceAccountCredentialsFactory { +public: + TStaticSecuredCredentialsFactory(const TString& yqlToken) + : YqlToken_(yqlToken) + {} + + std::shared_ptr Create(const TString&, const TString&) override { + return std::make_shared(YqlToken_); + } + +private: + TString YqlToken_; +}; + +TIcebergTestData CreateIcebergBasic(const TString& dataSourceName, const TString& database, const TString& userName, const TString& password){ + return TIcebergTestData({TIcebergTestData::EAuthType::AuthBasic, userName, password}, dataSourceName, database, false); +} + +TIcebergTestData CreateIcebergToken(const TString& dataSourceName, const TString& database, const TString& token) { + return TIcebergTestData({TIcebergTestData::EAuthType::AuthToken, VALUE_IAM , token}, dataSourceName, database, false); +} + +TIcebergTestData CreateIcebergSa(const TString& dataSourceName, const TString& database, const TString& token) { + return TIcebergTestData({TIcebergTestData::EAuthType::AuthSa,VALUE_IAM, token}, dataSourceName, database, false); +} + +std::shared_ptr CreateCredentialProvider(const TString& token) { + return std::make_shared(token); +} + +} // NTestUtils diff --git a/ydb/core/kqp/ut/federated_query/generic_ut/iceberg_ut_data.h b/ydb/core/kqp/ut/federated_query/generic_ut/iceberg_ut_data.h new file mode 100644 index 000000000000..bc03d731f3e7 --- /dev/null +++ b/ydb/core/kqp/ut/federated_query/generic_ut/iceberg_ut_data.h @@ -0,0 +1,66 @@ +#pragma once + +#include +#include +#include + +namespace NTestUtils { + +struct TTestData; +class TIcebergTestData final { + friend struct TTestData; + +public: + enum EAuthType : int { + AuthBasic = 1, + AuthSa = 2, + AuthToken = 3 + }; + + struct TAuth { + EAuthType Type; + TString Id; + TString Value; + }; + +public: + TIcebergTestData(TAuth auth, const TString& dataSourceName, const TString& database, bool UseTls); + + NYql::TGenericDataSourceInstance CreateDataSourceForHadoop(); + + NYql::TGenericDataSourceInstance CreateDataSourceForHive(); + + void ExecuteCreateHiveExternalDataSource(const std::shared_ptr& kikimr); + + void ExecuteCreateHadoopExternalDataSource(const std::shared_ptr& kikimr); + +private: + TString CreateAuthSection(); + + TString CreateQuery(const TString& catalogSection); + + void ExecuteQuery(const std::shared_ptr& kikimr, const TString& query); + +private: + const TAuth Auth_; + const TString DataSourceName_; + const TString Database_; + const bool UseTls_; +}; + +TIcebergTestData CreateIcebergBasic(const TString& dataSourceName = NYql::NConnector::NTest::DEFAULT_DATA_SOURCE_NAME, + const TString& database = NYql::NConnector::NTest::DEFAULT_DATABASE, + const TString& userName = NYql::NConnector::NTest::DEFAULT_LOGIN, + const TString& password = NYql::NConnector::NTest::DEFAULT_PASSWORD); + +TIcebergTestData CreateIcebergToken(const TString& dataSourceName = NYql::NConnector::NTest::DEFAULT_DATA_SOURCE_NAME, + const TString& database = NYql::NConnector::NTest::DEFAULT_DATABASE, + const TString& token = NYql::NConnector::NTest::DEFAULT_PASSWORD); + +TIcebergTestData CreateIcebergSa(const TString& dataSourceName = NYql::NConnector::NTest::DEFAULT_DATA_SOURCE_NAME, + const TString& database = NYql::NConnector::NTest::DEFAULT_DATABASE, + const TString& token = NYql::NConnector::NTest::DEFAULT_PASSWORD); + +std::shared_ptr CreateCredentialProvider(const TString& token = NYql::NConnector::NTest::DEFAULT_PASSWORD); + +} // NTestUtils diff --git a/ydb/core/kqp/ut/federated_query/generic_ut/kqp_generic_provider_ut.cpp b/ydb/core/kqp/ut/federated_query/generic_ut/kqp_generic_provider_ut.cpp index 4724d18c1217..8b5bab15c3f2 100644 --- a/ydb/core/kqp/ut/federated_query/generic_ut/kqp_generic_provider_ut.cpp +++ b/ydb/core/kqp/ut/federated_query/generic_ut/kqp_generic_provider_ut.cpp @@ -1,3 +1,5 @@ +#include "iceberg_ut_data.h" + #include #include #include @@ -36,6 +38,12 @@ namespace NKikimr::NKqp { PostgreSQL, ClickHouse, Ydb, + IcebergHiveBasic, + IcebergHiveSa, + IcebergHiveToken, + IcebergHadoopBasic, + IcebergHadoopSa, + IcebergHadoopToken, }; NYql::TGenericDataSourceInstance MakeDataSourceInstance(EProviderType providerType) { @@ -46,6 +54,18 @@ namespace NKikimr::NKqp { return TConnectorClientMock::TClickHouseDataSourceInstanceBuilder<>().GetResult(); case EProviderType::Ydb: return TConnectorClientMock::TYdbDataSourceInstanceBuilder<>().GetResult(); + case EProviderType::IcebergHiveBasic: + return NTestUtils::CreateIcebergBasic().CreateDataSourceForHive(); + case EProviderType::IcebergHiveSa: + return NTestUtils::CreateIcebergSa().CreateDataSourceForHive(); + case EProviderType::IcebergHiveToken: + return NTestUtils::CreateIcebergToken().CreateDataSourceForHive(); + case EProviderType::IcebergHadoopBasic: + return NTestUtils::CreateIcebergBasic().CreateDataSourceForHadoop(); + case EProviderType::IcebergHadoopSa: + return NTestUtils::CreateIcebergSa().CreateDataSourceForHadoop(); + case EProviderType::IcebergHadoopToken: + return NTestUtils::CreateIcebergToken().CreateDataSourceForHadoop(); } } @@ -57,6 +77,24 @@ namespace NKikimr::NKqp { return CreateClickHouseExternalDataSource(kikimr); case EProviderType::Ydb: return CreateYdbExternalDataSource(kikimr); + case EProviderType::IcebergHiveBasic: + return NTestUtils::CreateIcebergBasic() + .ExecuteCreateHiveExternalDataSource(kikimr); + case EProviderType::IcebergHiveSa: + return NTestUtils::CreateIcebergSa() + .ExecuteCreateHiveExternalDataSource(kikimr); + case EProviderType::IcebergHiveToken: + return NTestUtils::CreateIcebergToken() + .ExecuteCreateHiveExternalDataSource(kikimr); + case EProviderType::IcebergHadoopBasic: + return NTestUtils::CreateIcebergBasic() + .ExecuteCreateHadoopExternalDataSource(kikimr); + case EProviderType::IcebergHadoopSa: + return NTestUtils::CreateIcebergSa() + .ExecuteCreateHadoopExternalDataSource(kikimr); + case EProviderType::IcebergHadoopToken: + return NTestUtils::CreateIcebergToken() + .ExecuteCreateHadoopExternalDataSource(kikimr); } } @@ -65,15 +103,21 @@ namespace NKikimr::NKqp { NYql::TAttr dateTimeFormat; dateTimeFormat.SetName("DateTimeFormat"); dateTimeFormat.SetValue("string"); - appConfig.MutableQueryServiceConfig()->MutableGeneric()->MutableConnector()->SetUseSsl(false); - appConfig.MutableQueryServiceConfig()->MutableGeneric()->MutableConnector()->MutableEndpoint()->set_host("localhost"); - appConfig.MutableQueryServiceConfig()->MutableGeneric()->MutableConnector()->MutableEndpoint()->set_port(1234); - appConfig.MutableQueryServiceConfig()->MutableGeneric()->MutableDefaultSettings()->Add(std::move(dateTimeFormat)); - appConfig.MutableQueryServiceConfig()->AddAvailableExternalDataSources("ObjectStorage"); - appConfig.MutableQueryServiceConfig()->AddAvailableExternalDataSources("ClickHouse"); - appConfig.MutableQueryServiceConfig()->AddAvailableExternalDataSources("PostgreSQL"); - appConfig.MutableQueryServiceConfig()->AddAvailableExternalDataSources("MySQL"); - appConfig.MutableQueryServiceConfig()->AddAvailableExternalDataSources("Ydb"); + + auto& config = *appConfig.MutableQueryServiceConfig(); + auto& connector = *config.MutableGeneric()->MutableConnector(); + + connector.SetUseSsl(false); + connector.MutableEndpoint()->set_host("localhost"); + connector.MutableEndpoint()->set_port(1234); + + config.MutableGeneric()->MutableDefaultSettings()->Add(std::move(dateTimeFormat)); + config.AddAvailableExternalDataSources("ObjectStorage"); + config.AddAvailableExternalDataSources("ClickHouse"); + config.AddAvailableExternalDataSources("PostgreSQL"); + config.AddAvailableExternalDataSources("MySQL"); + config.AddAvailableExternalDataSources("Ydb"); + config.AddAvailableExternalDataSources("Iceberg"); return appConfig; } @@ -105,7 +149,6 @@ namespace NKikimr::NKqp { auto clientMock = std::make_shared(); const NYql::TGenericDataSourceInstance dataSourceInstance = MakeDataSourceInstance(providerType); - // step 1: DescribeTable // clang-format off clientMock->ExpectDescribeTable() @@ -152,7 +195,8 @@ namespace NKikimr::NKqp { // run test auto appConfig = CreateDefaultAppConfig(); auto s3ActorsFactory = NYql::NDq::CreateS3ActorsFactory(); - auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory); + auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory,{}, + NTestUtils::CreateCredentialProvider()); CreateExternalDataSource(providerType, kikimr); @@ -193,6 +237,30 @@ namespace NKikimr::NKqp { TestSelectAllFields(EProviderType::Ydb); } + Y_UNIT_TEST(IcebergHiveBasicSelectAll) { + TestSelectAllFields(EProviderType::IcebergHiveBasic); + } + + Y_UNIT_TEST(IcebergHiveSaSelectAll) { + TestSelectAllFields(EProviderType::IcebergHiveSa); + } + + Y_UNIT_TEST(IcebergHiveTokenSelectAll) { + TestSelectAllFields(EProviderType::IcebergHiveToken); + } + + Y_UNIT_TEST(IcebergHadoopBasicSelectAll) { + TestSelectAllFields(EProviderType::IcebergHadoopBasic); + } + + Y_UNIT_TEST(IcebergHadoopSaSelectAll) { + TestSelectAllFields(EProviderType::IcebergHadoopSa); + } + + Y_UNIT_TEST(IcebergHadoopTokenSelectAll) { + TestSelectAllFields(EProviderType::IcebergHadoopToken); + } + void TestSelectConstant(EProviderType providerType) { // prepare mock auto clientMock = std::make_shared(); @@ -243,7 +311,8 @@ namespace NKikimr::NKqp { // run test auto appConfig = CreateDefaultAppConfig(); auto s3ActorsFactory = NYql::NDq::CreateS3ActorsFactory(); - auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory); + auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory, {}, + NTestUtils::CreateCredentialProvider()); CreateExternalDataSource(providerType, kikimr); @@ -283,6 +352,30 @@ namespace NKikimr::NKqp { TestSelectConstant(EProviderType::Ydb); } + Y_UNIT_TEST(IcebergHiveBasicSelectConstant) { + TestSelectConstant(EProviderType::IcebergHiveBasic); + } + + Y_UNIT_TEST(IcebergHiveSaSelectConstant) { + TestSelectConstant(EProviderType::IcebergHiveSa); + } + + Y_UNIT_TEST(IcebergHiveTokenSelectConstant) { + TestSelectConstant(EProviderType::IcebergHiveToken); + } + + Y_UNIT_TEST(IcebergHadoopBasicSelectConstant) { + TestSelectConstant(EProviderType::IcebergHadoopBasic); + } + + Y_UNIT_TEST(IcebergHadoopSaSelectConstant) { + TestSelectConstant(EProviderType::IcebergHadoopSa); + } + + Y_UNIT_TEST(IcebergHadoopTokenSelectConstant) { + TestSelectConstant(EProviderType::IcebergHadoopToken); + } + void TestSelectCount(EProviderType providerType) { // prepare mock auto clientMock = std::make_shared(); @@ -333,7 +426,8 @@ namespace NKikimr::NKqp { // run test auto appConfig = CreateDefaultAppConfig(); auto s3ActorsFactory = NYql::NDq::CreateS3ActorsFactory(); - auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory); + auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory, {}, + NTestUtils::CreateCredentialProvider()); CreateExternalDataSource(providerType, kikimr); @@ -369,6 +463,30 @@ namespace NKikimr::NKqp { TestSelectCount(EProviderType::Ydb); } + Y_UNIT_TEST(IcebergHiveBasicSelectCount) { + TestSelectCount(EProviderType::IcebergHiveBasic); + } + + Y_UNIT_TEST(IcebergHiveSaSelectCount) { + TestSelectCount(EProviderType::IcebergHiveSa); + } + + Y_UNIT_TEST(IcebergHiveTokenSelectCount) { + TestSelectCount(EProviderType::IcebergHiveToken); + } + + Y_UNIT_TEST(IcebergHadoopBasicSelectCount) { + TestSelectCount(EProviderType::IcebergHadoopBasic); + } + + Y_UNIT_TEST(IcebergHadoopSaSelectCount) { + TestSelectCount(EProviderType::IcebergHadoopSa); + } + + Y_UNIT_TEST(IcebergHadoopTokenSelectCount) { + TestSelectCount(EProviderType::IcebergHadoopToken); + } + void TestFilterPushdown(EProviderType providerType) { // prepare mock auto clientMock = std::make_shared(); @@ -442,7 +560,8 @@ namespace NKikimr::NKqp { // run test auto appConfig = CreateDefaultAppConfig(); auto s3ActorsFactory = NYql::NDq::CreateS3ActorsFactory(); - auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory); + auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory, {}, + NTestUtils::CreateCredentialProvider()); CreateExternalDataSource(providerType, kikimr); @@ -480,12 +599,37 @@ namespace NKikimr::NKqp { TestFilterPushdown(EProviderType::Ydb); } + Y_UNIT_TEST(IcebergHiveBasicFilterPushdown) { + TestFilterPushdown(EProviderType::IcebergHiveBasic); + } + + Y_UNIT_TEST(IcebergHiveSaFilterPushdown) { + TestFilterPushdown(EProviderType::IcebergHiveSa); + } + + Y_UNIT_TEST(IcebergHiveTokenFilterPushdown) { + TestFilterPushdown(EProviderType::IcebergHiveToken); + } + + Y_UNIT_TEST(IcebergHadoopBasicFilterPushdown) { + TestFilterPushdown(EProviderType::IcebergHadoopBasic); + } + + Y_UNIT_TEST(IcebergHadoopSaFilterPushdown) { + TestFilterPushdown(EProviderType::IcebergHadoopSa); + } + + Y_UNIT_TEST(IcebergHadoopTokenFilterPushdown) { + TestFilterPushdown(EProviderType::IcebergHadoopToken); + } + void TestFailsOnIncorrectScriptExecutionOperation(const TString& operationId, const TString& fetchToken) { auto clientMock = std::make_shared(); auto databaseAsyncResolverMock = MakeDatabaseAsyncResolver(EProviderType::Ydb); auto appConfig = CreateDefaultAppConfig(); auto s3ActorsFactory = NYql::NDq::CreateS3ActorsFactory(); - auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory); + auto kikimr = MakeKikimrRunner(false, clientMock, databaseAsyncResolverMock, appConfig, s3ActorsFactory, {}, + NTestUtils::CreateCredentialProvider()); // Create trash query NYdbGrpc::TGRpcClientLow clientLow; diff --git a/ydb/core/kqp/ut/federated_query/generic_ut/ya.make b/ydb/core/kqp/ut/federated_query/generic_ut/ya.make index 9711b911be05..ffe00f6023c8 100644 --- a/ydb/core/kqp/ut/federated_query/generic_ut/ya.make +++ b/ydb/core/kqp/ut/federated_query/generic_ut/ya.make @@ -4,6 +4,8 @@ FORK_SUBTESTS() SRCS( kqp_generic_provider_ut.cpp + iceberg_ut_data.cpp + iceberg_ut_data.h ) PEERDIR( diff --git a/ydb/library/yql/providers/common/db_id_async_resolver/database_type.cpp b/ydb/library/yql/providers/common/db_id_async_resolver/database_type.cpp index 8166ae6c651f..6708ea71cdea 100644 --- a/ydb/library/yql/providers/common/db_id_async_resolver/database_type.cpp +++ b/ydb/library/yql/providers/common/db_id_async_resolver/database_type.cpp @@ -17,7 +17,8 @@ std::set GetAllExternalDataSourceTypes() { ToString(NYql::EDatabaseType::MsSQLServer), ToString(NYql::EDatabaseType::Oracle), ToString(NYql::EDatabaseType::Logging), - ToString(NYql::EDatabaseType::Solomon) + ToString(NYql::EDatabaseType::Solomon), + ToString(NYql::EDatabaseType::Iceberg) }; return allTypes; } @@ -35,11 +36,13 @@ EDatabaseType DatabaseTypeFromDataSourceKind(NYql::EGenericDataSourceKind dataSo case NYql::EGenericDataSourceKind::GREENPLUM: return EDatabaseType::Greenplum; case NYql::EGenericDataSourceKind::MS_SQL_SERVER: - return EDatabaseType::MsSQLServer; + return EDatabaseType::MsSQLServer; case NYql::EGenericDataSourceKind::ORACLE: - return EDatabaseType::Oracle; + return EDatabaseType::Oracle; case NYql::EGenericDataSourceKind::LOGGING: - return EDatabaseType::Logging; + return EDatabaseType::Logging; + case NYql::EGenericDataSourceKind::ICEBERG: + return EDatabaseType::Iceberg; default: ythrow yexception() << "Unknown data source kind: " << NYql::EGenericDataSourceKind_Name(dataSourceKind); } @@ -48,21 +51,23 @@ EDatabaseType DatabaseTypeFromDataSourceKind(NYql::EGenericDataSourceKind dataSo NYql::EGenericDataSourceKind DatabaseTypeToDataSourceKind(EDatabaseType databaseType) { switch (databaseType) { case EDatabaseType::PostgreSQL: - return NYql::EGenericDataSourceKind::POSTGRESQL; + return NYql::EGenericDataSourceKind::POSTGRESQL; case EDatabaseType::ClickHouse: - return NYql::EGenericDataSourceKind::CLICKHOUSE; + return NYql::EGenericDataSourceKind::CLICKHOUSE; case EDatabaseType::Ydb: - return NYql::EGenericDataSourceKind::YDB; + return NYql::EGenericDataSourceKind::YDB; case EDatabaseType::MySQL: return NYql::EGenericDataSourceKind::MYSQL; case EDatabaseType::Greenplum: - return NYql::EGenericDataSourceKind::GREENPLUM; + return NYql::EGenericDataSourceKind::GREENPLUM; case EDatabaseType::MsSQLServer: return NYql::EGenericDataSourceKind::MS_SQL_SERVER; case EDatabaseType::Oracle: return NYql::EGenericDataSourceKind::ORACLE; case EDatabaseType::Logging: return NYql::EGenericDataSourceKind::LOGGING; + case EDatabaseType::Iceberg: + return NYql::EGenericDataSourceKind::ICEBERG; default: ythrow yexception() << "Unknown database type: " << ToString(databaseType); } diff --git a/ydb/library/yql/providers/common/db_id_async_resolver/database_type.h b/ydb/library/yql/providers/common/db_id_async_resolver/database_type.h index d92b784887c5..d909abf4a9cd 100644 --- a/ydb/library/yql/providers/common/db_id_async_resolver/database_type.h +++ b/ydb/library/yql/providers/common/db_id_async_resolver/database_type.h @@ -18,7 +18,8 @@ enum class EDatabaseType { MsSQLServer, Oracle, Logging, - Solomon + Solomon, + Iceberg }; std::set GetAllExternalDataSourceTypes(); diff --git a/ydb/library/yql/providers/generic/actors/yql_generic_provider_factories.cpp b/ydb/library/yql/providers/generic/actors/yql_generic_provider_factories.cpp index ddd0a655614d..5d7261596388 100644 --- a/ydb/library/yql/providers/generic/actors/yql_generic_provider_factories.cpp +++ b/ydb/library/yql/providers/generic/actors/yql_generic_provider_factories.cpp @@ -51,7 +51,8 @@ namespace NYql::NDq { "GreenplumGeneric", "MsSQLServerGeneric", "OracleGeneric", - "LoggingGeneric"}) { + "LoggingGeneric", + "IcebergGeneric"}) { factory.RegisterSource(name, readActorFactory); factory.RegisterLookupSource(name, lookupActorFactory); } diff --git a/ydb/library/yql/providers/generic/provider/yql_generic_cluster_config.cpp b/ydb/library/yql/providers/generic/provider/yql_generic_cluster_config.cpp index ce35300b49e8..b6ea21fc878d 100644 --- a/ydb/library/yql/providers/generic/provider/yql_generic_cluster_config.cpp +++ b/ydb/library/yql/providers/generic/provider/yql_generic_cluster_config.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "yql_generic_cluster_config.h" @@ -213,6 +214,7 @@ namespace NYql { EGenericDataSourceKind::MYSQL, EGenericDataSourceKind::MS_SQL_SERVER, EGenericDataSourceKind::ORACLE, + EGenericDataSourceKind::ICEBERG }, clusterConfig.GetKind() )) { @@ -290,6 +292,43 @@ namespace NYql { clusterConfig.mutable_datasourceoptions()->insert({"folder_id", TString(it->second)}); } + /// + /// Extract token from properties and copy it to a cluster's config + /// + void ParseToken(const THashMap& properties, + NYql::TGenericClusterConfig& clusterConfig) { + auto it = properties.find("token"); + + if (it == properties.cend()) { + return; + } + + if (!it->second) { + return; + } + + clusterConfig.SetToken(it->second); + } + + /// + /// Fill properties for an iceberg data source + /// + void ParseIcebergFields(const THashMap& properties, + NYql::TGenericClusterConfig& clusterConfig) { + + if (clusterConfig.GetKind() != NYql::EGenericDataSourceKind::ICEBERG) { + return; + } + + for (auto f : NKikimr::NExternalSource::NIceberg::FieldsToConnector) { + auto it = properties.find(f); + + if (properties.end() != it) { + clusterConfig.MutableDataSourceOptions()->insert({f, it->second}); + } + } + } + using TProtoProperties = google::protobuf::Map; TString GetPropertyWithDefault(const TProtoProperties& properties, const TString& key) { @@ -317,8 +356,11 @@ namespace NYql { ParseProtocol(properties, clusterConfig); ParseServiceAccountId(properties, clusterConfig); ParseServiceAccountIdSignature(properties, clusterConfig); + ParseToken(properties, clusterConfig); ParseFolderId(properties, clusterConfig); + ParseIcebergFields(properties, clusterConfig); + return clusterConfig; } diff --git a/ydb/library/yql/providers/generic/provider/yql_generic_dq_integration.cpp b/ydb/library/yql/providers/generic/provider/yql_generic_dq_integration.cpp index 04a36eb7a241..b39d8a81a69c 100644 --- a/ydb/library/yql/providers/generic/provider/yql_generic_dq_integration.cpp +++ b/ydb/library/yql/providers/generic/provider/yql_generic_dq_integration.cpp @@ -38,6 +38,8 @@ namespace NYql { return "OracleGeneric"; case NYql::EGenericDataSourceKind::LOGGING: return "LoggingGeneric"; + case NYql::EGenericDataSourceKind::ICEBERG: + return "IcebergGeneric"; default: throw yexception() << "Data source kind is unknown or not specified"; } @@ -217,10 +219,10 @@ namespace NYql { } } - // Managed YDB (including YDB underlying Logging) supports access via IAM token. + // Iceberg/Managed YDB (including YDB underlying Logging) supports access via IAM token. // If exist, copy service account creds to obtain tokens during request execution phase. // If exists, copy previously created token. - if (IsIn({NYql::EGenericDataSourceKind::YDB, NYql::EGenericDataSourceKind::LOGGING}, clusterConfig.kind())) { + if (IsIn({NYql::EGenericDataSourceKind::YDB, NYql::EGenericDataSourceKind::LOGGING, NYql::EGenericDataSourceKind::ICEBERG}, clusterConfig.kind())) { source.SetServiceAccountId(clusterConfig.GetServiceAccountId()); source.SetServiceAccountIdSignature(clusterConfig.GetServiceAccountIdSignature()); source.SetToken(State_->Types->Credentials->FindCredentialContent( @@ -277,6 +279,9 @@ namespace NYql { case NYql::EGenericDataSourceKind::LOGGING: properties["SourceType"] = "Logging"; break; + case NYql::EGenericDataSourceKind::ICEBERG: + properties["SourceType"] = "Iceberg"; + break; case NYql::EGenericDataSourceKind::DATA_SOURCE_KIND_UNSPECIFIED: break; default: diff --git a/ydb/library/yql/providers/generic/provider/yql_generic_load_meta.cpp b/ydb/library/yql/providers/generic/provider/yql_generic_load_meta.cpp index a723d615ccc4..b8a6c3c96d52 100644 --- a/ydb/library/yql/providers/generic/provider/yql_generic_load_meta.cpp +++ b/ydb/library/yql/providers/generic/provider/yql_generic_load_meta.cpp @@ -20,6 +20,7 @@ #include #include #include +#include namespace NYql { using namespace NNodes; @@ -455,6 +456,58 @@ namespace NYql { } } + TString GetOptionValue(const ::google::protobuf::Map& options, TString option) { + auto it = options.find(option); + + if (options.end() == it) { + throw yexception() + << "Cluster config for an Iceberg data source" + << " is missing option: " + << option; + } + + return it->second; + } + + /// + /// Fill options into DatSourceOptions specific for an iceberg data type + /// + void SetIcebergOptions(NYql::TIcebergDataSourceOptions& dataSourceOptions, const TGenericClusterConfig& clusterConfig) { + using namespace NKikimr::NExternalSource::NIceberg; + + const auto& clusterOptions = clusterConfig.GetDataSourceOptions(); + auto warehouseType = GetOptionValue(clusterOptions, WAREHOUSE_TYPE); + + if (VALUE_S3 != warehouseType) { + throw yexception() << "Unexpected warehouse type: " << warehouseType; + } + + auto endpoint = GetOptionValue(clusterOptions, WAREHOUSE_S3_ENDPOINT); + auto region = GetOptionValue(clusterOptions, WAREHOUSE_S3_REGION); + auto uri = GetOptionValue(clusterOptions, WAREHOUSE_S3_URI); + auto& s3 = *dataSourceOptions.mutable_warehouse()->mutable_s3(); + + s3.set_endpoint(endpoint); + s3.set_region(region); + s3.set_uri(uri); + + auto catalogType = GetOptionValue(clusterOptions, CATALOG_TYPE); + auto& catalog = *dataSourceOptions.mutable_catalog(); + + // set catalog options + if (VALUE_HADOOP == catalogType) { + // hadoop nothing yet + catalog.mutable_hadoop(); + } else if (VALUE_HIVE == catalogType) { + auto hiveUri = GetOptionValue(clusterOptions, CATALOG_HIVE_URI); + + catalog.mutable_hive()->set_uri(hiveUri); + } else { + throw yexception() << "Unexpected catalog type: " << catalogType; + } + } + void FillDataSourceOptions(NConnector::NApi::TDescribeTableRequest& request, const TGenericClusterConfig& clusterConfig) { const auto dataSourceKind = clusterConfig.GetKind(); @@ -483,6 +536,10 @@ namespace NYql { auto* options = request.mutable_data_source_instance()->mutable_logging_options(); SetLoggingFolderId(*options, clusterConfig); } break; + case NYql::EGenericDataSourceKind::ICEBERG: { + auto* options = request.mutable_data_source_instance()->mutable_iceberg_options(); + SetIcebergOptions(*options, clusterConfig); + } break; default: throw yexception() << "Unexpected data source kind: '" << NYql::EGenericDataSourceKind_Name(dataSourceKind) << "'"; diff --git a/ydb/tests/tools/kqprun/configuration/app_config.conf b/ydb/tests/tools/kqprun/configuration/app_config.conf index 84711fee73ba..c6725525f796 100644 --- a/ydb/tests/tools/kqprun/configuration/app_config.conf +++ b/ydb/tests/tools/kqprun/configuration/app_config.conf @@ -97,6 +97,7 @@ QueryServiceConfig { AvailableExternalDataSources: "Oracle" AvailableExternalDataSources: "Logging" AvailableExternalDataSources: "Solomon" + AvailableExternalDataSources: "Iceberg" FileStorage { MaxFiles: 1000 From 25675750186a875635ae4bc00d2433a3b4633e51 Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Mon, 7 Apr 2025 20:58:57 +0300 Subject: [PATCH 022/454] Intermediate changes commit_hash:6768768ea3a3962231d3fabdffb2ce0db44e9347 --- yql/essentials/parser/common/ya.make | 4 ++++ yql/essentials/sql/v1/complete/name/ya.make | 5 +++++ yql/essentials/sql/v1/complete/ya.make | 7 +++++++ yql/essentials/sql/v1/lexer/regex/lexer_ut.cpp | 8 ++++---- yql/essentials/sql/v1/lexer/regex/regex_ut.cpp | 18 ++++++++++++------ yql/essentials/sql/v1/lexer/regex/ut/ya.make | 2 +- yql/essentials/sql/v1/lexer/ya.make | 1 + .../sql/v1/reflect/sql_reflect_ut.cpp | 6 +++--- yql/essentials/sql/v1/ya.make | 1 + 9 files changed, 38 insertions(+), 14 deletions(-) diff --git a/yql/essentials/parser/common/ya.make b/yql/essentials/parser/common/ya.make index 06a7e91363ad..b0ae371dfe44 100644 --- a/yql/essentials/parser/common/ya.make +++ b/yql/essentials/parser/common/ya.make @@ -9,3 +9,7 @@ SRCS( ) END() + +RECURSE( + antlr4 +) diff --git a/yql/essentials/sql/v1/complete/name/ya.make b/yql/essentials/sql/v1/complete/name/ya.make index 9865d255c8f1..c8af42acfb08 100644 --- a/yql/essentials/sql/v1/complete/name/ya.make +++ b/yql/essentials/sql/v1/complete/name/ya.make @@ -1,3 +1,8 @@ LIBRARY() END() + +RECURSE( + fallback + static +) diff --git a/yql/essentials/sql/v1/complete/ya.make b/yql/essentials/sql/v1/complete/ya.make index 141b5c471d7b..4db8f92d5aad 100644 --- a/yql/essentials/sql/v1/complete/ya.make +++ b/yql/essentials/sql/v1/complete/ya.make @@ -20,6 +20,13 @@ PEERDIR( END() +RECURSE( + antlr4 + name + syntax + text +) + RECURSE_FOR_TESTS( ut ) diff --git a/yql/essentials/sql/v1/lexer/regex/lexer_ut.cpp b/yql/essentials/sql/v1/lexer/regex/lexer_ut.cpp index ae0d018e42d3..03c84bcffe3d 100644 --- a/yql/essentials/sql/v1/lexer/regex/lexer_ut.cpp +++ b/yql/essentials/sql/v1/lexer/regex/lexer_ut.cpp @@ -197,10 +197,10 @@ Y_UNIT_TEST_SUITE(RegexLexerTests) { TString expected = "SELECT WS(\n) " - "WS( ) WS( ) INTEGER_VALUE(123467) COMMA(,) WS(\n) " + "WS( ) WS( ) DIGITS(123467) COMMA(,) WS(\n) " "WS( ) WS( ) STRING_VALUE(\"Hello, {name}!\") COMMA(,) WS(\n) " - "WS( ) WS( ) LPAREN(() INTEGER_VALUE(1) WS( ) PLUS(+) WS( ) LPAREN(() INTEGER_VALUE(5) WS( ) " - "ASTERISK(*) WS( ) INTEGER_VALUE(1) WS( ) SLASH(/) WS( ) INTEGER_VALUE(0) RPAREN()) " + "WS( ) WS( ) LPAREN(() DIGITS(1) WS( ) PLUS(+) WS( ) LPAREN(() DIGITS(5) WS( ) " + "ASTERISK(*) WS( ) DIGITS(1) WS( ) SLASH(/) WS( ) DIGITS(0) RPAREN()) " "RPAREN()) COMMA(,) WS(\n) " "WS( ) WS( ) ID_PLAIN(MIN) LPAREN(() ID_PLAIN(identifier) RPAREN()) COMMA(,) WS(\n) " "WS( ) WS( ) ID_PLAIN(Bool) LPAREN(() ID_PLAIN(field) RPAREN()) COMMA(,) WS(\n) " @@ -216,4 +216,4 @@ Y_UNIT_TEST_SUITE(RegexLexerTests) { Check("\" SELECT", "[INVALID] WS( ) SELECT EOF"); } -} // Y_UNIT_TEST_SUITE(RegexLexerTests) +} // Y_UNIT_TEST_SUITE(RegexLexerTests) \ No newline at end of file diff --git a/yql/essentials/sql/v1/lexer/regex/regex_ut.cpp b/yql/essentials/sql/v1/lexer/regex/regex_ut.cpp index 47a94f53ed0a..dad0b2ebd2d1 100644 --- a/yql/essentials/sql/v1/lexer/regex/regex_ut.cpp +++ b/yql/essentials/sql/v1/lexer/regex/regex_ut.cpp @@ -8,12 +8,18 @@ using namespace NSQLTranslationV1; namespace { auto grammar = NSQLReflect::LoadLexerGrammar(); - auto defaultRegexes = MakeRegexByOtherNameMap(grammar, /* ansi = */ false); - auto ansiRegexes = MakeRegexByOtherNameMap(grammar, /* ansi = */ true); + auto defaultRegexes = MakeRegexByOtherName(grammar, /* ansi = */ false); + auto ansiRegexes = MakeRegexByOtherName(grammar, /* ansi = */ true); + + TString Get(const TVector>& regexes, const TStringBuf name) { + return std::get<1>(*FindIf(regexes, [&](const auto& pair) { + return std::get<0>(pair) == name; + })); + } void CheckRegex(bool ansi, const TStringBuf name, const TStringBuf expected) { const auto& regexes = ansi ? ansiRegexes : defaultRegexes; - const TString regex = regexes.at(name); + const TString regex = Get(regexes, name); const RE2 re2(regex); Y_ENSURE(re2.ok(), re2.error()); @@ -83,8 +89,8 @@ Y_UNIT_TEST_SUITE(SqlRegexTests) { Y_UNIT_TEST(AnsiCommentSameAsDefault) { // Because of recursive definition UNIT_ASSERT_VALUES_EQUAL( - ansiRegexes.at("COMMENT"), - defaultRegexes.at("COMMENT")); + Get(ansiRegexes, "COMMENT"), + Get(defaultRegexes, "COMMENT")); } -} // Y_UNIT_TEST_SUITE(SqlRegexTests) +} // Y_UNIT_TEST_SUITE(SqlRegexTests) \ No newline at end of file diff --git a/yql/essentials/sql/v1/lexer/regex/ut/ya.make b/yql/essentials/sql/v1/lexer/regex/ut/ya.make index 09eb74a3f685..7123f50c70c0 100644 --- a/yql/essentials/sql/v1/lexer/regex/ut/ya.make +++ b/yql/essentials/sql/v1/lexer/regex/ut/ya.make @@ -10,4 +10,4 @@ SRCS( regex_ut.cpp ) -END() +END() \ No newline at end of file diff --git a/yql/essentials/sql/v1/lexer/ya.make b/yql/essentials/sql/v1/lexer/ya.make index c38b56c92732..66c0c87f15fb 100644 --- a/yql/essentials/sql/v1/lexer/ya.make +++ b/yql/essentials/sql/v1/lexer/ya.make @@ -22,6 +22,7 @@ RECURSE( antlr4_ansi antlr4_pure antlr4_pure_ansi + regex ) RECURSE_FOR_TESTS( diff --git a/yql/essentials/sql/v1/reflect/sql_reflect_ut.cpp b/yql/essentials/sql/v1/reflect/sql_reflect_ut.cpp index 7bef2879e555..18c7b89751b3 100644 --- a/yql/essentials/sql/v1/reflect/sql_reflect_ut.cpp +++ b/yql/essentials/sql/v1/reflect/sql_reflect_ut.cpp @@ -28,9 +28,9 @@ Y_UNIT_TEST_SUITE(SqlReflectTests) { } Y_UNIT_TEST(Other) { - UNIT_ASSERT_VALUES_EQUAL(grammar.OtherNames.contains("REAL"), true); - UNIT_ASSERT_VALUES_EQUAL(grammar.OtherNames.contains("STRING_VALUE"), true); - UNIT_ASSERT_VALUES_EQUAL(grammar.OtherNames.contains("STRING_MULTILINE"), false); + UNIT_ASSERT_VALUES_EQUAL(Count(grammar.OtherNames, "REAL"), 1); + UNIT_ASSERT_VALUES_EQUAL(Count(grammar.OtherNames, "STRING_VALUE"), 1); + UNIT_ASSERT_VALUES_EQUAL(Count(grammar.OtherNames, "STRING_MULTILINE"), 0); UNIT_ASSERT_VALUES_EQUAL( grammar.BlockByName.at("FLOAT_EXP"), diff --git a/yql/essentials/sql/v1/ya.make b/yql/essentials/sql/v1/ya.make index 1d2105f6faec..9407914f9760 100644 --- a/yql/essentials/sql/v1/ya.make +++ b/yql/essentials/sql/v1/ya.make @@ -61,6 +61,7 @@ RECURSE( lexer perf proto_parser + reflect ) RECURSE_FOR_TESTS( From 8a4821ce7981f71e11b9f37379f314848ce52bdb Mon Sep 17 00:00:00 2001 From: vvvv Date: Mon, 7 Apr 2025 22:07:09 +0300 Subject: [PATCH 023/454] YQL-19747 statements (hints etc) commit_hash:1288e94c1f35aed35f40ac5e9b59e708b7cfafad --- .../data/language/statements_opensource.json | 1 + yql/essentials/sql/v1/sql_query.cpp | 11 ++++ yql/essentials/sql/v1/sql_query.h | 1 + yt/yql/providers/yt/provider/ya.make | 1 + .../yt/provider/yql_yt_op_settings.cpp | 59 +++++++++++++++++++ .../yt/provider/yql_yt_op_settings.h | 6 +- 6 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 yql/essentials/data/language/statements_opensource.json diff --git a/yql/essentials/data/language/statements_opensource.json b/yql/essentials/data/language/statements_opensource.json new file mode 100644 index 000000000000..a3bd452b1806 --- /dev/null +++ b/yql/essentials/data/language/statements_opensource.json @@ -0,0 +1 @@ +{"read":{"yt":{"hints":[{"name":"infer_scheme"},{"name":"force_infer_schema"},{"name":"inline"},{"name":"xlock"},{"name":"unordered"},{"name":"non_unique"},{"name":"ignore_type_v3"}]}},"insert":{"yt":{"hints":[{"name":"truncate"},{"name":"compression_codec"},{"name":"erasure_codec"},{"name":"expiration"},{"name":"replication_factor"},{"name":"user_attrs"},{"name":"media"},{"name":"primary_medium"},{"name":"keep_meta"},{"name":"monotonic_keys"},{"name":"column_groups"},{"name":"security_tags"}]}},"replace":{},"upsert":{},"update":{},"delete":{},"create_table":{},"create_view":{}} diff --git a/yql/essentials/sql/v1/sql_query.cpp b/yql/essentials/sql/v1/sql_query.cpp index d6b6f96bef97..a860571698b6 100644 --- a/yql/essentials/sql/v1/sql_query.cpp +++ b/yql/essentials/sql/v1/sql_query.cpp @@ -4002,4 +4002,15 @@ void EnumeratePragmas(std::function callback) { callback("yson.DisableCastToString"); } +void EnumerateStmtContexts(std::function callback) { + callback("read"); + callback("insert"); + callback("replace"); + callback("upsert"); + callback("update"); + callback("delete"); + callback("create_table"); + callback("create_view"); +} + } // namespace NSQLTranslationV1 diff --git a/yql/essentials/sql/v1/sql_query.h b/yql/essentials/sql/v1/sql_query.h index 52cd3c402b6d..450451525b76 100644 --- a/yql/essentials/sql/v1/sql_query.h +++ b/yql/essentials/sql/v1/sql_query.h @@ -85,5 +85,6 @@ class TSqlQuery: public TSqlTranslation { }; void EnumeratePragmas(std::function callback); +void EnumerateStmtContexts(std::function callback); } // namespace NSQLTranslationV1 diff --git a/yt/yql/providers/yt/provider/ya.make b/yt/yql/providers/yt/provider/ya.make index 875beb7b306c..a40502a8b6a1 100644 --- a/yt/yql/providers/yt/provider/ya.make +++ b/yt/yql/providers/yt/provider/ya.make @@ -73,6 +73,7 @@ SRCS( PEERDIR( library/cpp/yson/node + library/cpp/json/writer library/cpp/disjoint_sets yt/cpp/mapreduce/common yt/cpp/mapreduce/interface diff --git a/yt/yql/providers/yt/provider/yql_yt_op_settings.cpp b/yt/yql/providers/yt/provider/yql_yt_op_settings.cpp index 9f327ed0176a..922307cdadb7 100644 --- a/yt/yql/providers/yt/provider/yql_yt_op_settings.cpp +++ b/yt/yql/providers/yt/provider/yql_yt_op_settings.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -1322,4 +1323,62 @@ EYtSettingTypes operator|(EYtSettingType left, EYtSettingType right) { return EYtSettingTypes(left) | EYtSettingTypes(right); } +void YtWriteHint(std::string_view name, NJsonWriter::TBuf& json) { + json.BeginObject(); + json.WriteKey("name"); + json.WriteString(name); + json.EndObject(); +} + +void YtWriteHints(EYtSettingTypes flags, NJsonWriter::TBuf& json) { + for (ui32 i = 0; i < (ui32)EYtSettingType::LAST; ++i) { + if (flags.HasFlags((EYtSettingType)i)) { + YtWriteHint(ToString((EYtSettingType)i), json); + } + } +} + +void YtWriteStmtContext(std::string_view ctxName, NJsonWriter::TBuf& json) { + if (ctxName == "read") { + json.WriteKey(YtProviderName); + json.BeginObject(); + json.WriteKey("hints"); + json.BeginList(); + YtWriteHints( + EYtSettingType::InferScheme | + EYtSettingType::ForceInferScheme | + EYtSettingType::Inline | + EYtSettingType::XLock | + EYtSettingType::Unordered | + EYtSettingType::NonUnique | + EYtSettingType::IgnoreTypeV3, + json + ); + json.EndList(); + json.EndObject(); + } else if (ctxName == "insert") { + json.WriteKey(YtProviderName); + json.BeginObject(); + json.WriteKey("hints"); + json.BeginList(); + YtWriteHint("truncate", json); + YtWriteHints( + EYtSettingType::CompressionCodec | + EYtSettingType::ErasureCodec | + EYtSettingType::Expiration | + EYtSettingType::ReplicationFactor | + EYtSettingType::UserAttrs | + EYtSettingType::Media | + EYtSettingType::PrimaryMedium | + EYtSettingType::KeepMeta | + EYtSettingType::MonotonicKeys | + EYtSettingType::ColumnGroups | + EYtSettingType::SecurityTags, + json + ); + json.EndList(); + json.EndObject(); + } +} + } // NYql diff --git a/yt/yql/providers/yt/provider/yql_yt_op_settings.h b/yt/yql/providers/yt/provider/yql_yt_op_settings.h index cca60ec498bd..ee1944ed1e2c 100644 --- a/yt/yql/providers/yt/provider/yql_yt_op_settings.h +++ b/yt/yql/providers/yt/provider/yql_yt_op_settings.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -64,12 +65,12 @@ enum class EYtSettingType: ui64 { WarnNonExisting /* "warn_non_existing" "warnnonexisting" */, XLock /* "xlock" */, Unordered /* "unordered" */, - NonUnique /* "nonUnique" */, + NonUnique /* "non_unique" "nonUnique" */, UserSchema /* "userschema" */, UserColumns /* "usercolumns" */, StatColumns /* "statcolumns" */, SysColumns /* "syscolumns" */, - IgnoreTypeV3 /* "ignoretypev3" "ignore_type_v3" */, + IgnoreTypeV3 /* "ignore_type_v3" "ignoretypev3" */, // Table content MemUsage /* "memUsage" */, ItemsCount /* "itemsCount" */, @@ -228,6 +229,7 @@ TMaybe GetMaxJobSizeForFirstAsPrimary(const TExprNode& settings); bool UseJoinReduceForSecondAsPrimary(const TExprNode& settings); ui32 GetMinChildrenForIndexedKeyFilter(EYtSettingType type); +void YtWriteStmtContext(std::string_view ctxName, NJsonWriter::TBuf& json); } // NYql From 6f956f12910d1dfda5ed857aaba6a6ede974f0c0 Mon Sep 17 00:00:00 2001 From: robot-ya-builder Date: Mon, 7 Apr 2025 23:37:53 +0300 Subject: [PATCH 024/454] External build system generator release 109 Update tools: yexport, os-yexport commit_hash:c945b027e56f4c8e526cfdc93c2928e419e61f93 --- build/external_resources/yexport/public.resources.json | 6 +++--- build/external_resources/yexport/resources.json | 6 +++--- build/mapping.conf.json | 8 +++++++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/build/external_resources/yexport/public.resources.json b/build/external_resources/yexport/public.resources.json index 1244c3648e1e..37335332f450 100644 --- a/build/external_resources/yexport/public.resources.json +++ b/build/external_resources/yexport/public.resources.json @@ -1,13 +1,13 @@ { "by_platform": { "darwin": { - "uri": "sbr:8450186648" + "uri": "sbr:8457945767" }, "darwin-arm64": { - "uri": "sbr:8450185847" + "uri": "sbr:8457944672" }, "linux": { - "uri": "sbr:8450184998" + "uri": "sbr:8457943496" } } } diff --git a/build/external_resources/yexport/resources.json b/build/external_resources/yexport/resources.json index 34d34e51f8ad..1b0af80d15e5 100644 --- a/build/external_resources/yexport/resources.json +++ b/build/external_resources/yexport/resources.json @@ -1,13 +1,13 @@ { "by_platform": { "darwin": { - "uri": "sbr:8450160353" + "uri": "sbr:8457924152" }, "darwin-arm64": { - "uri": "sbr:8450159079" + "uri": "sbr:8457922548" }, "linux": { - "uri": "sbr:8450158028" + "uri": "sbr:8457919782" } } } diff --git a/build/mapping.conf.json b/build/mapping.conf.json index 3f57e6a9895d..91017db80907 100644 --- a/build/mapping.conf.json +++ b/build/mapping.conf.json @@ -606,6 +606,7 @@ "7688576117": "{registry_endpoint}/7688576117", "8188215274": "{registry_endpoint}/8188215274", "8450186648": "{registry_endpoint}/8450186648", + "8457945767": "{registry_endpoint}/8457945767", "5811823398": "{registry_endpoint}/5811823398", "5840611310": "{registry_endpoint}/5840611310", "5860185593": "{registry_endpoint}/5860185593", @@ -634,6 +635,7 @@ "7688574511": "{registry_endpoint}/7688574511", "8188212965": "{registry_endpoint}/8188212965", "8450185847": "{registry_endpoint}/8450185847", + "8457944672": "{registry_endpoint}/8457944672", "5811822876": "{registry_endpoint}/5811822876", "5840610640": "{registry_endpoint}/5840610640", "5860184285": "{registry_endpoint}/5860184285", @@ -662,6 +664,7 @@ "7688572842": "{registry_endpoint}/7688572842", "8188211019": "{registry_endpoint}/8188211019", "8450184998": "{registry_endpoint}/8450184998", + "8457943496": "{registry_endpoint}/8457943496", "5766172292": "{registry_endpoint}/5766172292", "5805431504": "{registry_endpoint}/5805431504", "5829027626": "{registry_endpoint}/5829027626", @@ -1945,6 +1948,7 @@ "7688576117": "devtools/yexport/bin/yexport for darwin", "8188215274": "devtools/yexport/bin/yexport for darwin", "8450186648": "devtools/yexport/bin/yexport for darwin", + "8457945767": "devtools/yexport/bin/yexport for darwin", "5811823398": "devtools/yexport/bin/yexport for darwin-arm64", "5840611310": "devtools/yexport/bin/yexport for darwin-arm64", "5860185593": "devtools/yexport/bin/yexport for darwin-arm64", @@ -1973,6 +1977,7 @@ "7688574511": "devtools/yexport/bin/yexport for darwin-arm64", "8188212965": "devtools/yexport/bin/yexport for darwin-arm64", "8450185847": "devtools/yexport/bin/yexport for darwin-arm64", + "8457944672": "devtools/yexport/bin/yexport for darwin-arm64", "5811822876": "devtools/yexport/bin/yexport for linux", "5840610640": "devtools/yexport/bin/yexport for linux", "5860184285": "devtools/yexport/bin/yexport for linux", @@ -2001,6 +2006,7 @@ "7688572842": "devtools/yexport/bin/yexport for linux", "8188211019": "devtools/yexport/bin/yexport for linux", "8450184998": "devtools/yexport/bin/yexport for linux", + "8457943496": "devtools/yexport/bin/yexport for linux", "5766172292": "devtools/ymake/bin/ymake for darwin", "5805431504": "devtools/ymake/bin/ymake for darwin", "5829027626": "devtools/ymake/bin/ymake for darwin", @@ -2683,4 +2689,4 @@ }, "resources_info": {}, "tasks": {} -} +} \ No newline at end of file From d39b14f0a603ac8070f831528fd9fefd3221d9a1 Mon Sep 17 00:00:00 2001 From: Vitaly Isaev Date: Tue, 8 Apr 2025 00:03:18 +0300 Subject: [PATCH 025/454] YDB FQ: enable pushdown of string types in Generic provider (#16834) --- .../provider/ut/pushdown/pushdown_ut.cpp | 41 ++++++++++++++++--- .../provider/yql_generic_physical_opt.cpp | 8 +++- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/ydb/library/yql/providers/generic/provider/ut/pushdown/pushdown_ut.cpp b/ydb/library/yql/providers/generic/provider/ut/pushdown/pushdown_ut.cpp index 82052e8659d7..bc7d00d10549 100644 --- a/ydb/library/yql/providers/generic/provider/ut/pushdown/pushdown_ut.cpp +++ b/ydb/library/yql/providers/generic/provider/ut/pushdown/pushdown_ut.cpp @@ -352,7 +352,7 @@ struct TPushdownFixture: public NUnitTest::TBaseFixture { void AssertFilter(const TString& lambdaText, const TString& filterText) { const auto& filter = BuildProtoFilterFromLambda(lambdaText); NConnector::NApi::TPredicate expectedFilter; - UNIT_ASSERT(google::protobuf::TextFormat::ParseFromString(filterText, &expectedFilter)); + UNIT_ASSERT_C(google::protobuf::TextFormat::ParseFromString(filterText, &expectedFilter), expectedFilter.InitializationErrorString()); UNIT_ASSERT_STRINGS_EQUAL(filter.Utf8DebugString(), expectedFilter.Utf8DebugString()); } @@ -657,7 +657,7 @@ Y_UNIT_TEST_SUITE_F(PushdownTest, TPushdownFixture) { } Y_UNIT_TEST(StringFieldsNotSupported) { - AssertNoPush( + AssertFilter( // Note that R"ast()ast" is empty string! R"ast( (Coalesce @@ -667,17 +667,48 @@ Y_UNIT_TEST_SUITE_F(PushdownTest, TPushdownFixture) { ) (Bool '"false") ) - )ast"); + )ast", + R"proto( + comparison { + operation: EQ + left_value { + column: "col_utf8" + } + right_value { + column: "col_optional_utf8" + } + } + )proto" + ); } Y_UNIT_TEST(StringFieldsNotSupported2) { - AssertNoPush( + AssertFilter( // Note that R"ast()ast" is empty string! R"ast( (!= (Member $row '"col_string") (String '"value") ) - )ast"); + )ast", + R"proto( + comparison { + operation: NE + left_value { + column: "col_string" + } + right_value { + typed_value { + type { + type_id: STRING + } + value { + bytes_value: "value" + } + } + } + } + )proto" + ); } } diff --git a/ydb/library/yql/providers/generic/provider/yql_generic_physical_opt.cpp b/ydb/library/yql/providers/generic/provider/yql_generic_physical_opt.cpp index dcfcb9151570..a4b99c708b9e 100644 --- a/ydb/library/yql/providers/generic/provider/yql_generic_physical_opt.cpp +++ b/ydb/library/yql/providers/generic/provider/yql_generic_physical_opt.cpp @@ -27,7 +27,13 @@ namespace NYql { : NPushdown::TSettings(NLog::EComponent::ProviderGeneric) { using EFlag = NPushdown::TSettings::EFeatureFlag; - Enable(EFlag::ExpressionAsPredicate | EFlag::ArithmeticalExpressions | EFlag::ImplicitConversionToInt64 | EFlag::DateTimeTypes | EFlag::TimestampCtor); + Enable( + EFlag::ExpressionAsPredicate | + EFlag::ArithmeticalExpressions | + EFlag::ImplicitConversionToInt64 | + EFlag::DateTimeTypes | + EFlag::TimestampCtor | + EFlag::StringTypes); } }; From 6a114f0cafe3074d67f8022fe051f0b28dfe31ab Mon Sep 17 00:00:00 2001 From: kirilltatunov Date: Mon, 7 Apr 2025 23:42:01 +0300 Subject: [PATCH 026/454] Add sysincl headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Я покрываю библиотеку metrokit ya.make'ами, и нужно добавить системный header и пару header'ов из ios pod'ов. commit_hash:dff5a8f37753e5953ed044ba6e05f0386a906910 --- build/sysincl/darwin.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/build/sysincl/darwin.yml b/build/sysincl/darwin.yml index 948663d42c42..19cc327499f8 100644 --- a/build/sysincl/darwin.yml +++ b/build/sysincl/darwin.yml @@ -149,6 +149,7 @@ - sys/filio.h - sys/ioccom.h - sys/kauth.h + - sys/kdebug_signpost.h - sys/kern_control.h - sys/lock.h - sys/malloc.h From 5af5cb3b7b423f2d3fcebf2e1406d37cbd6f3bbf Mon Sep 17 00:00:00 2001 From: vityaman Date: Mon, 7 Apr 2025 23:50:34 +0300 Subject: [PATCH 027/454] YQL-19747 Improve yql_complete tool and add input validation No description --- Pull Request resolved: https://github.com/ytsaurus/ytsaurus/pull/1185 commit_hash:1def5874ff6a9a5b3dcdd0ad285d2e64b16c9306 --- yql/essentials/parser/pg_wrapper/parser.cpp | 4 ++- yql/essentials/public/fastcheck/format.cpp | 7 ++-- yql/essentials/public/issue/yql_issue.cpp | 2 +- yql/essentials/public/issue/yql_issue.h | 4 --- .../sql/v1/complete/sql_complete.cpp | 9 ++++++ .../sql/v1/complete/sql_complete_ut.cpp | 32 +++++++++++++------ yql/essentials/tools/yql_complete/ya.make | 1 + .../tools/yql_complete/yql_complete.cpp | 22 ++++++++++++- 8 files changed, 62 insertions(+), 19 deletions(-) diff --git a/yql/essentials/parser/pg_wrapper/parser.cpp b/yql/essentials/parser/pg_wrapper/parser.cpp index 94369296a870..c7dc29756ca6 100644 --- a/yql/essentials/parser/pg_wrapper/parser.cpp +++ b/yql/essentials/parser/pg_wrapper/parser.cpp @@ -2,7 +2,9 @@ #include "arena_ctx.h" +#include #include + #include #include @@ -219,7 +221,7 @@ void PGParse(const TString& input, IPGParseEvents& events) { break; } - if (!TTextWalker::IsUtf8Intermediate(input[i])) { + if (!IsUTF8ContinuationByte(input[i])) { ++codepoints; } walker.Advance(input[i]); diff --git a/yql/essentials/public/fastcheck/format.cpp b/yql/essentials/public/fastcheck/format.cpp index dac43f0ffa66..d4717b4bf79d 100644 --- a/yql/essentials/public/fastcheck/format.cpp +++ b/yql/essentials/public/fastcheck/format.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include namespace NYql { @@ -88,7 +89,7 @@ class TFormatRunner : public ICheckRunner { continue; } - while (i > 0 && TTextWalker::IsUtf8Intermediate(request.Program[i])) { + while (i > 0 && IsUTF8ContinuationByte(request.Program[i])) { --i; } @@ -96,12 +97,12 @@ class TFormatRunner : public ICheckRunner { } TString formattedSample = formattedQuery.substr(i, FormatContextLimit); - while (!formattedSample.empty() && TTextWalker::IsUtf8Intermediate(formattedQuery.back())) { + while (!formattedSample.empty() && IsUTF8ContinuationByte(formattedQuery.back())) { formattedSample.erase(formattedSample.size() - 1); } TString origSample = request.Program.substr(i, FormatContextLimit); - while (!origSample.empty() && TTextWalker::IsUtf8Intermediate(origSample.back())) { + while (!origSample.empty() && IsUTF8ContinuationByte(origSample.back())) { origSample.erase(origSample.size() - 1); } diff --git a/yql/essentials/public/issue/yql_issue.cpp b/yql/essentials/public/issue/yql_issue.cpp index bb171a786925..af47895927da 100644 --- a/yql/essentials/public/issue/yql_issue.cpp +++ b/yql/essentials/public/issue/yql_issue.cpp @@ -54,7 +54,7 @@ TTextWalker& TTextWalker::Advance(char c) { } ui32 charDistance = 1; - if (Utf8Aware && IsUtf8Intermediate(c)) { + if (Utf8Aware && IsUTF8ContinuationByte(c)) { charDistance = 0; } diff --git a/yql/essentials/public/issue/yql_issue.h b/yql/essentials/public/issue/yql_issue.h index 07fcdfed86e6..2c60b979531e 100644 --- a/yql/essentials/public/issue/yql_issue.h +++ b/yql/essentials/public/issue/yql_issue.h @@ -63,10 +63,6 @@ class TTextWalker { { } - static inline bool IsUtf8Intermediate(char c) { - return (c & 0xC0) == 0x80; - } - template TTextWalker& Advance(const T& buf) { for (char c : buf) { diff --git a/yql/essentials/sql/v1/complete/sql_complete.cpp b/yql/essentials/sql/v1/complete/sql_complete.cpp index 74ddbc04154b..ed3afa29df4a 100644 --- a/yql/essentials/sql/v1/complete/sql_complete.cpp +++ b/yql/essentials/sql/v1/complete/sql_complete.cpp @@ -26,6 +26,15 @@ namespace NSQLComplete { } TCompletion Complete(TCompletionInput input) { + if ( + input.CursorPosition < input.Text.length() && + IsUTF8ContinuationByte(input.Text.at(input.CursorPosition)) || + input.Text.length() < input.CursorPosition) { + ythrow yexception() + << "invalid cursor position " << input.CursorPosition + << " for input size " << input.Text.size(); + } + auto prefix = input.Text.Head(input.CursorPosition); auto completedToken = GetCompletedToken(prefix); diff --git a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp index 10d358c8d3e0..e9f5dbdfb736 100644 --- a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp +++ b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp @@ -63,8 +63,8 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { return MakeSqlCompletionEngine(std::move(lexer), std::move(service)); } - TVector Complete(ISqlCompletionEngine::TPtr& engine, TStringBuf prefix) { - return engine->Complete({prefix}).Candidates; + TVector Complete(ISqlCompletionEngine::TPtr& engine, TCompletionInput input) { + return engine->Complete(input).Candidates; } Y_UNIT_TEST(Beginning) { @@ -438,17 +438,31 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { }; auto engine = MakeSqlCompletionEngineUT(); - UNIT_ASSERT_VALUES_EQUAL(Complete(engine, "se"), expected); - UNIT_ASSERT_VALUES_EQUAL(Complete(engine, "sE"), expected); - UNIT_ASSERT_VALUES_EQUAL(Complete(engine, "Se"), expected); - UNIT_ASSERT_VALUES_EQUAL(Complete(engine, "SE"), expected); + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"se"}), expected); + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"sE"}), expected); + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"Se"}), expected); + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SE"}), expected); } Y_UNIT_TEST(InvalidStatementsRecovery) { auto engine = MakeSqlCompletionEngineUT(); - UNIT_ASSERT_GE(Complete(engine, "select select; ").size(), 35); - UNIT_ASSERT_GE(Complete(engine, "select select;").size(), 35); - UNIT_ASSERT_VALUES_EQUAL_C(Complete(engine, "!;").size(), 0, "Lexer failing"); + UNIT_ASSERT_GE(Complete(engine, {"select select; "}).size(), 35); + UNIT_ASSERT_GE(Complete(engine, {"select select;"}).size(), 35); + UNIT_ASSERT_VALUES_EQUAL_C(Complete(engine, {"!;"}).size(), 0, "Lexer failing"); + } + + Y_UNIT_TEST(InvalidCursorPosition) { + auto engine = MakeSqlCompletionEngineUT(); + + UNIT_ASSERT_NO_EXCEPTION(Complete(engine, {"", 0})); + UNIT_ASSERT_EXCEPTION(Complete(engine, {"", 1}), yexception); + + UNIT_ASSERT_NO_EXCEPTION(Complete(engine, {"s", 0})); + UNIT_ASSERT_NO_EXCEPTION(Complete(engine, {"s", 1})); + + UNIT_ASSERT_NO_EXCEPTION(Complete(engine, {"ы", 0})); + UNIT_ASSERT_EXCEPTION(Complete(engine, {"ы", 1}), yexception); + UNIT_ASSERT_NO_EXCEPTION(Complete(engine, {"ы", 2})); } Y_UNIT_TEST(DefaultNameService) { diff --git a/yql/essentials/tools/yql_complete/ya.make b/yql/essentials/tools/yql_complete/ya.make index 107e6ba56256..21a98628b1e0 100644 --- a/yql/essentials/tools/yql_complete/ya.make +++ b/yql/essentials/tools/yql_complete/ya.make @@ -7,6 +7,7 @@ PEERDIR( yql/essentials/sql/v1/complete yql/essentials/sql/v1/lexer/antlr4_pure yql/essentials/sql/v1/lexer/antlr4_pure_ansi + yql/essentials/utils ) SRCS( diff --git a/yql/essentials/tools/yql_complete/yql_complete.cpp b/yql/essentials/tools/yql_complete/yql_complete.cpp index 320b9f1b4876..0d592240ebfc 100644 --- a/yql/essentials/tools/yql_complete/yql_complete.cpp +++ b/yql/essentials/tools/yql_complete/yql_complete.cpp @@ -6,7 +6,11 @@ #include #include +#include + #include + +#include #include NSQLComplete::TFrequencyData LoadFrequencyDataFromFile(TString filepath) { @@ -25,6 +29,11 @@ NSQLComplete::TLexerSupplier MakePureLexerSupplier() { }; } +size_t UTF8PositionToBytes(const TStringBuf text, size_t position) { + const TStringBuf substr = SubstrUTF8(text, position, text.length()); + return substr.begin() - text.begin(); +} + int Run(int argc, char* argv[]) { NLastGetopt::TOpts opts = NLastGetopt::TOpts::Default(); @@ -60,9 +69,20 @@ int Run(int argc, char* argv[]) { std::move(ranking))); NSQLComplete::TCompletionInput input; + input.Text = queryString; + if (!NYql::IsUtf8(input.Text)) { + ythrow yexception() << "provided input is not UTF encoded"; + } + if (pos) { - input.CursorPosition = *pos; + input.CursorPosition = UTF8PositionToBytes(input.Text, *pos); + } else if (Count(input.Text, '#') == 1) { + Cerr << "Note: found an only '#', setting the cursor position\n"; + input.CursorPosition = input.Text.find('#'); + } else if (Count(input.Text, '#') >= 2) { + Cerr << "Note: found multiple '#', defaulting the cursor position\n"; + input.CursorPosition = queryString.size(); } else { input.CursorPosition = queryString.size(); } From 624c1038fe57d045d946d9ab8f197e13b33ca15b Mon Sep 17 00:00:00 2001 From: robot-ratatosk Date: Tue, 8 Apr 2025 01:55:05 +0300 Subject: [PATCH 028/454] New version of the tld SKIP_CHECK SKIP_REVIEW commit_hash:d1a020a6c819ad53c70a8c9d62796c8b10b76516 --- library/cpp/tld/tlds-alpha-by-domain.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/cpp/tld/tlds-alpha-by-domain.txt b/library/cpp/tld/tlds-alpha-by-domain.txt index 51c6ed810af6..99d76b90cbf8 100644 --- a/library/cpp/tld/tlds-alpha-by-domain.txt +++ b/library/cpp/tld/tlds-alpha-by-domain.txt @@ -1,4 +1,4 @@ -# Version 2025040400, Last Updated Fri Apr 4 07:07:02 2025 UTC +# Version 2025040700, Last Updated Mon Apr 7 07:07:01 2025 UTC AAA AARP ABB From 639a53abbc6f8d46d01082bf6e45dbe107a1dab9 Mon Sep 17 00:00:00 2001 From: Alexander Smirnov Date: Tue, 8 Apr 2025 00:51:52 +0000 Subject: [PATCH 029/454] Import libraries 250408-0050 --- ydb/ci/rightlib.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ydb/ci/rightlib.txt b/ydb/ci/rightlib.txt index 9bc7611bed3a..39a6e30cba32 100644 --- a/ydb/ci/rightlib.txt +++ b/ydb/ci/rightlib.txt @@ -1 +1 @@ -28a80e63c3c727d8309a041bde8da045b41f4fda +624c1038fe57d045d946d9ab8f197e13b33ca15b From 18fa3b229b5b925edb352ab8997d457a7f65c997 Mon Sep 17 00:00:00 2001 From: hitsedesen Date: Tue, 8 Apr 2025 05:28:53 +0300 Subject: [PATCH 030/454] YTORM: Path attributes commit_hash:045d8a23a8914c8a38833a1782c188ad07b1a5af --- yt/yt/core/ytree/public.h | 1 + 1 file changed, 1 insertion(+) diff --git a/yt/yt/core/ytree/public.h b/yt/yt/core/ytree/public.h index 368840528c1f..deac48ae912b 100644 --- a/yt/yt/core/ytree/public.h +++ b/yt/yt/core/ytree/public.h @@ -43,6 +43,7 @@ struct INodeFactory; struct ITransactionalNodeFactory; DECLARE_REFCOUNTED_STRUCT(IAttributeDictionary) +using IConstAttributeDictionaryPtr = TIntrusivePtr; struct IAttributeOwner; From e3a2c25a704d383a210e7060f6d2937930238283 Mon Sep 17 00:00:00 2001 From: alevitskii Date: Tue, 8 Apr 2025 07:18:53 +0300 Subject: [PATCH 031/454] Pass output_includes through command in CHECK_CONFIG_H Pass output_includes through command in CHECK_CONFIG_H commit_hash:4be563e6c3e2636fc079b593964bc9bef3885358 --- build/ymake.core.conf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build/ymake.core.conf b/build/ymake.core.conf index 0e286ce8e0ec..de39d57ed284 100644 --- a/build/ymake.core.conf +++ b/build/ymake.core.conf @@ -422,9 +422,8 @@ when ($OS_EMSCRIPTEN == "yes") { ### ### @see https://a.yandex-team.ru/arc/trunk/arcadia/build/scripts/check_config_h.py for exact details macro CHECK_CONFIG_H(Conf) { - .CMD=$YMAKE_PYTHON ${input:"build/scripts/check_config_h.py"} ${rootrel;input:Conf} ${output;suf=.config.cpp;nopath;noext:Conf} ${hide;kv:"p CH"} ${hide;kv:"pc yellow"} + .CMD=$YMAKE_PYTHON ${input:"build/scripts/check_config_h.py"} ${rootrel;input:Conf} ${hide;from_input;output_include:Conf} ${output;suf=.config.cpp;nopath;noext:Conf} ${hide;kv:"p CH"} ${hide;kv:"pc yellow"} .SEM=${hide;rootrel;input:Conf} ${hide;output;suf=.config.cpp;nopath;noext:Conf} - OUTPUT_INCLUDES=$Conf } REQUIRED_TRANSITIVE_PEERS= From f06a700ba3cb1ee3be6ba77a105fab109374a641 Mon Sep 17 00:00:00 2001 From: mregrock Date: Tue, 8 Apr 2025 09:08:16 +0300 Subject: [PATCH 032/454] Add node config init and config generate commands (#16479) Co-authored-by: anton-bobkov --- ydb/docs/en/core/reference/ydb-cli/configs.md | 163 +++++++++++++----- ydb/docs/ru/core/reference/ydb-cli/configs.md | 151 +++++++++++----- 2 files changed, 230 insertions(+), 84 deletions(-) diff --git a/ydb/docs/en/core/reference/ydb-cli/configs.md b/ydb/docs/en/core/reference/ydb-cli/configs.md index 0a93ba59b5f9..4d92de99dc53 100644 --- a/ydb/docs/en/core/reference/ydb-cli/configs.md +++ b/ydb/docs/en/core/reference/ydb-cli/configs.md @@ -1,59 +1,132 @@ -## Working with configuration +## Managing {{ ydb-short-name }} configuration -### Common command flags +{% note info %} -* `-f, --filename ` — read input from a file, `-` for STDIN. It can be specified multiple times for commands accepting multiple files (e.g., resolve). The metadata field will determine the file type. -* `--output-directory ` — dump/resolve files to a directory. -* `--strip-metadata` — remove the metadata field from the output. -* `--all` — extend command output to the entire configuration (see advanced configuration). -* `--allow-unknown-fields` — allow ignoring unknown fields in the configuration. +Before YDB CLI 2.20.0, the `{{ ydb-cli }} admin cluster config` commands had the following format: `{{ ydb-cli }} admin config`. -```bash -# Apply the configuration dynconfig.yaml to the cluster -{{ ydb-cli }} admin config replace -f dynconfig.yaml -# Check if it is possible to apply the configuration dynconfig.yaml to the cluster (validate all validators, version, and cluster match) -{{ ydb-cli }} admin config replace -f dynconfig.yaml --dry-run -# Apply the configuration dynconfig.yaml to the cluster, ignoring version and cluster checks (version and cluster will still be overwritten with correct ones) -{{ ydb-cli }} admin config replace -f dynconfig.yaml --force -# Fetch the main cluster configuration -{{ ydb-cli }} admin config fetch -# Fetch all current configuration files of the cluster -{{ ydb-cli }} admin config fetch --all -# Generate all possible final configurations for dynconfig.yaml -{{ ydb-cli }} admin config resolve --all -f dynconfig.yaml -# Generate the final configuration for dynconfig.yaml with labels tenant=/Root/test and canary=true -{{ ydb-cli }} admin config resolve -f dynconfig.yaml --label tenant=/Root/test --label canary=true -# Generate the final configuration for dynconfig.yaml for labels from node 1003 -{{ ydb-cli }} admin config resolve -f dynconfig.yaml --node-id 1003 -# Fetch all temporary configurations of the cluster -{{ ydb-cli }} admin volatile-config fetch --all --output-directory -# Fetch the temporary configuration with id 1 from the cluster -{{ ydb-cli }} admin volatile-config fetch --id 1 -# Apply the temporary configuration volatile.yaml to the cluster -{{ ydb-cli }} admin volatile-config add -f volatile.yaml -# Delete temporary configurations with ids 1 and 3 on the cluster -{{ ydb-cli }} admin volatile-config drop --id 1 --id 3 -# Delete all temporary configurations on the cluster -{{ ydb-cli }} admin volatile-config drop --all -``` +{% endnote %} + +This section contains commands for managing the {{ ydb-short-name }} [cluster configuration](../../maintenance/manual/config-overview.md). + +- Apply the `dynconfig.yaml` configuration to the cluster: + + ```bash + {{ ydb-cli }} admin cluster config replace -f dynconfig.yaml + ``` + +- Check if it is possible to apply the configuration dynconfig.yaml to the cluster (check all validators, the configuration version in the yaml file must be 1 higher than the cluster configuration version, the cluster name must match): + + ```bash + {{ ydb-cli }} admin cluster config replace -f dynconfig.yaml --dry-run + ``` + +- Apply the `dynconfig.yaml` configuration to the cluster, ignoring version and cluster checks (the version and cluster values will be overwritten with correct values): + + ```bash + {{ ydb-cli }} admin cluster config replace -f dynconfig.yaml --force + ``` + +- Fetch the main cluster configuration: + + ```bash + {{ ydb-cli }} admin cluster config fetch + ``` + +- Generate all possible final configurations for `dynconfig.yaml`: + + ```bash + {{ ydb-cli }} admin cluster config resolve --all -f dynconfig.yaml + ``` + +- Generate the final configuration for `dynconfig.yaml` with the `tenant=/Root/test` and `canary=true` labels: + + ```bash + {{ ydb-cli }} admin cluster config resolve -f dynconfig.yaml --label tenant=/Root/test --label canary=true + ``` + +- Generate the final configuration for `dynconfig.yaml` for labels from node 100: + + ```bash + {{ ydb-cli }} admin cluster config resolve -f dynconfig.yaml --node-id 100 + ``` + +- Generate a dynamic configuration file, based on a static configuration on the cluster: + + ```bash + {{ ydb-cli }} admin cluster config genereate + ``` + +- Initialize a directory with the configuration, using the path to the configuration file: + + ```bash + {{ ydb-cli }} admin node config init --config-dir --from-config + ``` + +- Initialize a directory with the configuration, using the configuration from the cluster: + + ```bash + {{ ydb-cli }} admin node config init --config-dir --seed-node + ``` + +## Managing temporary configuration + +This section contains commands for managing [temporary configurations](../../maintenance/manual/dynamic-config-volatile-config.md). + +- Fetch all temporary configurations from the cluster: + + ```bash + {{ ydb-cli }} admin volatile-config fetch --all --output-directory + ``` + +- Fetch the temporary configuration with id 1 from the cluster: + + ```bash + {{ ydb-cli }} admin volatile-config fetch --id 1 + ``` + +- Apply the `volatile.yaml` temporary configuration to the cluster: + + ```bash + {{ ydb-cli }} admin volatile-config add -f volatile.yaml + ``` + +- Delete temporary configurations with ids 1 and 3 on the cluster: + + ```bash + {{ ydb-cli }} admin volatile-config drop --id 1 --id 3 + ``` + +- Delete all temporary configurations on the cluster: + + ```bash + {{ ydb-cli }} admin volatile-config drop --all + ``` + +## Parameters + +* `-f, --filename ` — read input from a file, `-` for STDIN. For commands that accept multiple files (e.g., resolve), you can specify it multiple times, the file type will be determined by the metadata field +* `--output-directory ` — dump/resolve files to a directory +* `--strip-metadata` — remove the metadata field from the output +* `--all` — extends the output of commands to the entire configuration (see advanced configuration) +* `--allow-unknown-fields` — allows ignoring unknown fields in the configuration ## Scenarios ### Update the main cluster configuration - ```bash +```bash # Fetch the cluster configuration -{{ ydb-cli }} admin config fetch > dynconfig.yaml +{{ ydb-cli }} admin cluster config fetch > dynconfig.yaml # Edit the configuration with your favorite editor vim dynconfig.yaml # Apply the configuration dynconfig.yaml to the cluster -{{ ydb-cli }} admin config replace -f dynconfig.yaml +{{ ydb-cli }} admin cluster config replace -f dynconfig.yaml ``` Similarly, in one line: ```bash -{{ ydb-cli }} admin config fetch | yq '.config.actor_system_config.scheduler.resolution = 128' | {{ ydb-cli }} admin config replace -f - +{{ ydb-cli }} admin cluster config fetch | yq '.config.actor_system_config.scheduler.resolution = 128' | {{ ydb-cli }} admin cluster config replace -f - ``` Command output: @@ -65,7 +138,7 @@ OK ### View the configuration for a specific set of labels ```bash -{{ ydb-cli }} admin config resolve --remote --label tenant=/Root/db1 --label canary=true +{{ ydb-cli }} admin cluster config resolve --remote --label tenant=/Root/db1 --label canary=true ``` Command output: @@ -86,7 +159,7 @@ config: ### View the configuration for a specific node ```bash -{{ ydb-cli }} admin config resolve --remote --node-id +{{ ydb-cli }} admin cluster config resolve --remote --node-id ``` Command output: @@ -107,7 +180,7 @@ config: ### Save all configurations locally ```bash -{{ ydb-cli }} admin config fetch --all --output-directory +{{ ydb-cli }} admin cluster config fetch --all --output-directory ls ``` @@ -120,7 +193,7 @@ dynconfig.yaml volatile_1.yaml volatile_3.yaml ### View all configurations locally ```bash -{{ ydb-cli }} admin config fetch --all +{{ ydb-cli }} admin cluster config fetch --all ``` Command output: @@ -158,7 +231,7 @@ selectors: ### View the final configuration for a specific node from the locally saved original configuration ```bash -{{ ydb-cli }} admin config resolve -k --node-id +{{ ydb-cli }} admin cluster config resolve -k --node-id ``` Command output: @@ -174,4 +247,4 @@ config: use_auto_config: true node_type: COMPUTE cpu_count: 4 -``` \ No newline at end of file +``` diff --git a/ydb/docs/ru/core/reference/ydb-cli/configs.md b/ydb/docs/ru/core/reference/ydb-cli/configs.md index e09ac0127c8f..d03eb5ac5f34 100644 --- a/ydb/docs/ru/core/reference/ydb-cli/configs.md +++ b/ydb/docs/ru/core/reference/ydb-cli/configs.md @@ -1,6 +1,108 @@ ## Работа с конфигурацией -### Общие флаги для команд +{% note info %} + +До версии YDB CLI 2.20.0 команды `{{ ydb-cli }} admin cluster config` имели формат `{{ ydb-cli }} admin config`. + +{% endnote %} + +В этом разделе приведены команды для работы с [конфигурацией кластера](../../maintenance/manual/config-overview.md) {{ ydb-short-name }}. + +- Применение конфигурации `dynconfig.yaml` на кластер: + + ```bash + {{ ydb-cli }} admin cluster config replace -f dynconfig.yaml + ``` + +- Проверка возможности применения конфигурации `dynconfig.yaml` на кластер (проверить все валидаторы, версия конфигурации в yaml-файле должна быть выше на 1, чем версия конфигурации кластера, имя кластера должно совпадать): + + ```bash + {{ ydb-cli }} admin cluster config replace -f dynconfig.yaml --dry-run + ``` + +- Применение конфигурации `dynconfig.yaml` на кластер игнорируя проверку версий и кластера (версия и кластер всё равно будут перезаписаны на корректные): + + ```bash + {{ ydb-cli }} admin cluster config replace -f dynconfig.yaml --force + ``` + +- Получение основной конфигурации кластера: + + ```bash + {{ ydb-cli }} admin cluster config fetch + ``` + +- Генерация всех возможных конечных конфигураций для `dynconfig.yaml`: + + ```bash + {{ ydb-cli }} admin cluster config resolve --all -f dynconfig.yaml + ``` + +- Генерация конечной конфигурации для `dynconfig.yaml` при лейблах `tenant=/Root/test` и `canary=true`: + + ```bash + {{ ydb-cli }} admin cluster config resolve -f dynconfig.yaml --label tenant=/Root/test --label canary=true + ``` + +- Генерация конечной конфигурации для `dynconfig.yaml` для лейблов с узла 1003: + + ```bash + {{ ydb-cli }} admin cluster config resolve -f dynconfig.yaml --node-id 100 + ``` + +- Генерация файла динамической конфигурации на основе статической конфигурации на кластере: + + ```bash + {{ ydb-cli }} admin cluster config genereate + ``` + +- Инициализация директории с конфигурацией, используя путь до конфигурационного файла: + + ```bash + {{ ydb-cli }} admin node config init --config-dir <путь до директории> --from-config <путь до файла конфигурации> + ``` + +- Инициализация директории с конфигурацией, используя конфигурацию на кластере: + + ```bash + {{ ydb-cli }} admin node config init --config-dir <путь до директории> --seed-node <эндпоинт узла кластера> + ``` + +## Работа с временной конфигурацией + +В этом разделе перечислены команды, которые используются для работы с [временной конфигурацией](../../maintenance/manual/dynamic-config-volatile-config.md). + +- Получение всех временных конфигураций кластера: + + ```bash + {{ ydb-cli }} admin volatile-config fetch --all --output-directory + ``` + +- Получение временной конфигурации с id 1 с кластера: + + ```bash + {{ ydb-cli }} admin volatile-config fetch --id 1 + ``` + +- Применение временной конфигурации `volatile.yaml` на кластер: + + ```bash + {{ ydb-cli }} admin volatile-config add -f volatile.yaml + ``` + +- Удаление временной конфигурации с id 1 и 3 на кластере: + + ```bash + {{ ydb-cli }} admin volatile-config drop --id 1 --id 3 + ``` + +- Удаление всех временных конфигурации на кластере: + + ```bash + {{ ydb-cli }} admin volatile-config drop --all + ``` + +## Параметры * `-f, --filename ` — считать input из файла, `-` для STDIN. Для команд принимающих n файлов (прим. resolve) можно указать несколько раз, тип файла будет определён по полю metadata * `--output-directory ` — сдампить/порезолвить файлы в директорию @@ -8,52 +110,23 @@ * `--all` — расширяет вывод команд до всей конфигурации (см. продвинутое конфигурирование) * `--allow-unknown-fields` — позволяет игнорировать неизвестные поля в конфигурации -```bash -# Применить конфигурацию dynconfig.yaml на кластер -{{ ydb-cli }} admin config replace -f dynconfig.yaml -# Проверить возможно ли применить конфигурацию dynconfig.yaml на кластер (проверить все валидаторы, совпадение версий и кластера) -{{ ydb-cli }} admin config replace -f dynconfig.yaml --dry-run -# Применить конфигурацию dynconfig.yaml на кластер игнорирую проверку версий и кластера (версия и кластер всё равно будут перезаписаны на корректные) -{{ ydb-cli }} admin config replace -f dynconfig.yaml --force -# Получить основную конфигурацию кластера -{{ ydb-cli }} admin config fetch -# Получить все текущие конфигурационные файлы кластера -{{ ydb-cli }} admin config fetch --all -# Сгенерировать все возможные конечные конфигурации для dynconfig.yaml -{{ ydb-cli }} admin config resolve --all -f dynconfig.yaml -# Сгенерировать конечную конфигурацию для dynconfig.yaml при лейблах tenant=/Root/test и canary=true -{{ ydb-cli }} admin config resolve -f dynconfig.yaml --label tenant=/Root/test --label canary=true -# Сгенерировать конечную конфигурацию для dynconfig.yaml для лейблов с узла 1003 -{{ ydb-cli }} admin config resolve -f dynconfig.yaml --node-id 1003 -# Получить все временные конфигурации кластера -{{ ydb-cli }} admin volatile-config fetch --all --output-directory -# Получить временную конфигурацию с id 1 с кластера -{{ ydb-cli }} admin volatile-config fetch --id 1 -# Применить временную конфигурацию volatile.yaml на кластер -{{ ydb-cli }} admin volatile-config add -f volatile.yaml -# Удалить временные конфигурации с id 1 и 3 на кластере -{{ ydb-cli }} admin volatile-config drop --id 1 --id 3 -# Удалить все временные конфигурации на кластере -{{ ydb-cli }} admin volatile-config drop --all -``` - ## Сценарии ### Обновить основную конфигурацию кластера ```bash # Получить конфигурацию кластера -{{ ydb-cli }} admin config fetch > dynconfig.yaml +{{ ydb-cli }} admin cluster config fetch > dynconfig.yaml # Отредактировать конфигурацию вашим любимым редактором vim dynconfig.yaml # Применить конфигурацию dynconfig.yaml на кластер -{{ ydb-cli }} admin config replace -f dynconfig.yaml +{{ ydb-cli }} admin cluster config replace -f dynconfig.yaml ``` аналогично в одну строчку: ```bash -{{ ydb-cli }} admin config fetch | yq '.config.actor_system_config.scheduler.resolution = 128' | {{ ydb-cli }} admin config replace -f - +{{ ydb-cli }} admin cluster config fetch | yq '.config.actor_system_config.scheduler.resolution = 128' | {{ ydb-cli }} admin cluster config replace -f - ``` вывод команды: @@ -61,11 +134,10 @@ vim dynconfig.yaml ```text OK ``` - ### Посмотреть конфигурацию для определённого набора лейблов ```bash -{{ ydb-cli }} admin config resolve --remote --label tenant=/Root/db1 --label canary=true +{{ ydb-cli }} admin cluster config resolve --remote --label tenant=/Root/db1 --label canary=true ``` вывод команды: @@ -86,7 +158,7 @@ config: ### Посмотреть конфигурацию для определённого узла ```bash -{{ ydb-cli }} admin config resolve --remote --node-id +{{ ydb-cli }} admin cluster config resolve --remote --node-id ``` вывод команды: @@ -107,7 +179,7 @@ config: ### Сохранить все конфигурации локально ```bash -{{ ydb-cli }} admin config fetch --all --output-directory +{{ ydb-cli }} admin cluster config fetch --all --output-directory ls ``` @@ -120,7 +192,7 @@ dynconfig.yaml volatile_1.yaml volatile_3.yaml ### Посмотреть все конфигурации локально ```bash -{{ ydb-cli }} admin config fetch --all +{{ ydb-cli }} admin cluster config fetch --all ``` вывод команды: @@ -158,7 +230,7 @@ selectors: ### Посмотреть конечную конфигурацию для определённого узла из сохраненной локально исходной конфигурации ```bash -{{ ydb-cli }} admin config resolve -k --node-id +{{ ydb-cli }} admin cluster config resolve -k --node-id ``` вывод команды: @@ -175,3 +247,4 @@ config: node_type: COMPUTE cpu_count: 4 ``` + From 4058c0d3e2275e129e60b6f05f6133d4e0fd823d Mon Sep 17 00:00:00 2001 From: Nikolay Perfilov Date: Tue, 8 Apr 2025 09:32:17 +0300 Subject: [PATCH 033/454] YDB CLI 2.20.0 release notes (#15287) Co-authored-by: Natasha Pirogova Co-authored-by: Ivan Blinkov --- ydb/docs/en/core/changelog-cli.md | 162 ++++++++++-------- .../_includes/ydb-cli/darwin_amd64.md | 1 + .../_includes/ydb-cli/darwin_arm64.md | 1 + .../_includes/ydb-cli/linux_amd64.md | 1 + .../_includes/ydb-cli/linux_arm64.md | 1 + .../downloads/_includes/ydb-cli/windows.md | 1 + ydb/docs/ru/core/changelog-cli.md | 162 ++++++++++-------- .../_includes/ydb-cli/darwin_amd64.md | 1 + .../_includes/ydb-cli/darwin_arm64.md | 1 + .../_includes/ydb-cli/linux_amd64.md | 1 + .../_includes/ydb-cli/linux_arm64.md | 1 + .../downloads/_includes/ydb-cli/windows.md | 1 + 12 files changed, 200 insertions(+), 134 deletions(-) diff --git a/ydb/docs/en/core/changelog-cli.md b/ydb/docs/en/core/changelog-cli.md index f5619a21ed75..a9ee24dc368a 100644 --- a/ydb/docs/en/core/changelog-cli.md +++ b/ydb/docs/en/core/changelog-cli.md @@ -1,28 +1,56 @@ # {{ ydb-short-name }} CLI changelog +## Version 2.20.0 {#2-20-0} + +Released on March 5, 2025. To update to version **2.20.0**, select the [Downloads](downloads/index.md#ydb-cli) section. + +### Features + +* Added [topics](./concepts/topic.md) support in the `{{ ydb-cli }} tools dump` and `{{ ydb-cli }} tools restore` [commands](./reference/ydb-cli/export-import/tools-dump.md). In this release, only topic settings are retained; messages are not included in the backup. +* Added [coordination nodes](./concepts/datamodel/coordination-node.md) support in the `{{ ydb-cli }} tools dump` and `{{ ydb-cli }} tools restore` [commands](./reference/ydb-cli/export-import/tools-dump.md). +* Added the new `{{ ydb-cli }} workload log import generator` command. +* Added new global options for client certificates in SSL/TLS connections: + * `--client-cert-file`: File containing a client certificate for SSL/TLS connections (PKCS#12 or PEM-encoded). + * `--client-cert-key-file`: File containing a PEM-encoded private key for the client certificate. + * `--client-cert-key-password-file`: File containing a password for the private key (if the key is encrypted). +* Queries in the `{{ ydb-cli }} workload run` command are now executed in random order. +* **_(Requires server v25.1+)_** Added support for [external data sources](./concepts/datamodel/external_data_source.md) and [external tables](./concepts/datamodel/external_table.md) in the `{{ ydb-cli }} tools dump` and `{{ ydb-cli }} tools restore` [commands](./reference/ydb-cli/export-import/tools-dump.md). +* **_(Experimental)_** Added the `{{ ydb-cli }} admin node config init` command to initialize a directory with node configuration files. +* **_(Requires server v25.1+)_** **_(Experimental)_** Added the `{{ ydb-cli }} admin cluster config generate` [command](/reference/ydb-cli/configs.md) to generate a dynamic configuration file from a cluster static configuration file. +* **_(Requires server v25.1+)_** **_(Experimental)_** Added the [command](./reference/ydb-cli/export-import/tools-dump.md#cluster) `{{ ydb-cli }} admin cluster dump` and the [command](./reference/ydb-cli/export-import/tools-restore.md#cluster) `{{ ydb-cli }} admin cluster restore` for dumping all cluster-level data. These dumps contain a list of databases with metadata, users, and groups but do not include schema objects. +* **_(Requires server v25.1+)_** **_(Experimental)_** Added the `{{ ydb-cli }} admin database dump` and `{{ ydb-cli }} admin database restore` commands for dumping all database-level data. These dumps contain database metadata, schema objects, their data, users, and groups. +* **_(Requires server v25.1+)_** **_(Experimental)_** Added the `--dedicated-storage-section` and `--dedicated-cluster-section` options to the `ydb admin cluster config fetch` command, allowing cluster and storage config sections to be fetched separately. + +### Bug fixes + +* Fixed a bug where the `{{ ydb-cli }} auth get-token` command attempted to authenticate twice: once while listing endpoints and again while executing the actual token request. +* Fixed a bug where the `{{ ydb-cli }} import file csv` command was saving progress even if a batch upload had failed. +* Fixed a bug where some errors could be ignored when restoring from a local backup with the `ydb tools restore` command. +* Fixed a memory leak in the data generator for the `{{ ydb-cli }} workload tpcds` benchmark. + ## Version 2.19.0 {#2-19-0} Released on February 5, 2025. To update to version **2.19.0**, select the [Downloads](downloads/index.md#ydb-cli) section. ### Features -* Added [changefeeds](./concepts/cdc.md) support in `ydb tools dump` and `ydb tools restore` [commands](./reference/ydb-cli/export-import/tools-dump.md). -* Added `CREATE TABLE` text suggestion on schema error during `ydb import file csv` [command](./reference/ydb-cli/export-import/import-file.md). -* Added statistics output on the current progress of the query in the `ydb workload` [command](./reference/ydb-cli/commands/workload/index.md). -* Added query text to the error message if a query fails in the `ydb workload run` [command](./reference/ydb-cli/commands/workload/index.md). -* Added a message if the global timeout expired in the `ydb workload run` [command](./reference/ydb-cli/commands/workload/index.md). -* **_(Requires server v25.1+)_** Added [views](./concepts/datamodel/view.md) support in `ydb export s3` and `ydb import s3`. Views are exported as `CREATE VIEW` YQL statements, which are executed on import. -* **_(Requires server v25.1+)_** Added the `--skip-checksum-validation` option to the `ydb import s3` [command](./reference/ydb-cli/export-import/import-s3.md) to skip server-side checksum validation. -* **_(Requires server v25.1+)_** **_(Experimental)_** Added new options for the `ydb debug ping` command: `--chain-length`, `--chain-work-duration`, `--no-tail-chain`. -* **_(Requires server v25.1+)_** **_(Experimental)_** Added new options for the `ydb admin storage fetch` command: `--dedicated-storage-section` and `--dedicated-cluster-section`. -* **_(Requires server v25.1+)_** **_(Experimental)_** Added new options for the `ydb admin storage replace` command: `--filename`, `--dedicated-cluster-yaml`, `--dedicated-storage-yaml`, `--enable-dedicated-storage-section` and `--disable-dedicated-storage-section`. +* Added [changefeeds](./concepts/cdc.md) support in the `{{ ydb-cli }} tools dump` and `{{ ydb-cli }} tools restore` [commands](./reference/ydb-cli/export-import/tools-dump.md). +* Added `CREATE TABLE` text suggestion on schema error during the `{{ ydb-cli }} import file csv` [command](./reference/ydb-cli/export-import/import-file.md). +* Added statistics output on the current progress of the query in the `{{ ydb-cli }} workload` [command](./reference/ydb-cli/commands/workload/index.md). +* Added query text to the error message if a query fails in the `{{ ydb-cli }} workload run` [command](./reference/ydb-cli/commands/workload/index.md). +* Added a message if the global timeout expired in the `{{ ydb-cli }} workload run` [command](./reference/ydb-cli/commands/workload/index.md). +* **_(Requires server v25.1+)_** Added [views](./concepts/datamodel/view.md) support in the `{{ ydb-cli }} export s3` and `{{ ydb-cli }} import s3`. Views are exported as `CREATE VIEW` YQL statements, which are executed on import. +* **_(Requires server v25.1+)_** Added the `--skip-checksum-validation` option to the `{{ ydb-cli }} import s3` [command](./reference/ydb-cli/export-import/import-s3.md) to skip server-side checksum validation. +* **_(Requires server v25.1+)_** **_(Experimental)_** Added new options for the `{{ ydb-cli }} debug ping` command: `--chain-length`, `--chain-work-duration`, `--no-tail-chain`. +* **_(Requires server v25.1+)_** **_(Experimental)_** Added new options for the `{{ ydb-cli }} admin storage fetch` command: `--dedicated-storage-section` and `--dedicated-cluster-section`. +* **_(Requires server v25.1+)_** **_(Experimental)_** Added new options for the `{{ ydb-cli }} admin storage replace` command: `--filename`, `--dedicated-cluster-yaml`, `--dedicated-storage-yaml`, `--enable-dedicated-storage-section` and `--disable-dedicated-storage-section`. ### Bug fixes -* Fixed a bug where the arm64 {{ ydb-short-name }} CLI binary was downloading the amd64 binary to replace itself during the `ydb update` [command](./reference/ydb-cli/commands/service.md). To update already installed binaries to the latest arm64 version, {{ ydb-short-name }} CLI should be reinstalled. -* Fixed the return code of the `ydb workload run` [command](./reference/ydb-cli/commands/workload/index.md). -* Fixed a bug where the `ydb workload tpch import generator` and `ydb workload tpcds import generator` [commands](./reference/ydb-cli/workload-tpch.md) were failing because not all tables had been created. -* Fixed a bug with backslashes in the `ydb workload` [commands](./reference/ydb-cli/commands/workload/index.md) paths on Windows. +* Fixed a bug where the arm64 {{ ydb-short-name }} CLI binary was downloading the amd64 binary to replace itself during the `{{ ydb-cli }} update` [command](./reference/ydb-cli/commands/service.md). To update already installed binaries to the latest arm64 version, {{ ydb-short-name }} CLI should be reinstalled. +* Fixed the return code of the `{{ ydb-cli }} workload run` [command](./reference/ydb-cli/commands/workload/index.md). +* Fixed a bug where the `{{ ydb-cli }} workload tpch import generator` and `{{ ydb-cli }} workload tpcds import generator` [commands](./reference/ydb-cli/workload-tpch.md) were failing because not all tables had been created. +* Fixed a bug with backslashes in the `{{ ydb-cli }} workload` [commands](./reference/ydb-cli/commands/workload/index.md) paths on Windows. ## Version 2.18.0 {#2-18-0} @@ -30,22 +58,22 @@ Released on December 24, 2024. To update to version **2.18.0**, select the [Down ### Features -* Added support for [views](./concepts/datamodel/view) in local backups: `ydb tools dump` and `ydb tools restore`. Views are backed up as `CREATE VIEW` queries saved in the `create_view.sql` files, which can be executed to recreate the original views. -* Added new options to the `ydb workload topic run` [command](./reference/ydb-cli/workload-topic#run-write): `--tx-commit-interval` and `--tx-commit-messages`, allowing you to specify the interval between transaction commits in milliseconds or in the number of messages written, respectively. -* Made the `--consumer` flag in the `ydb topic read` [command](./reference/ydb-cli/topic-read) optional. In the non-subscriber reading mode, the partition IDs must be specified with the `--partition-ids` option. In this case, the read is performed without saving the offset commit. -* The `ydb import file csv` [command](./reference/ydb-cli/export-import/import-file.md) now saves the import progress. Relaunching the import command will resume the process from the row where it was interrupted. -* In the `ydb workload kv` and `ydb workload stock` commands, the default value of the `--executer` option has been changed to `generic`, which makes them no longer rely on the legacy query execution infrastructure. -* Replaced the CSV format with Parquet for filling tables in `ydb workload` benchmarks. -* **_(Requires server v25.1+)_** **_(Experimental)_** Added new `ydb admin storage` command with `fetch` and `replace` subcommands to manage server storage configuration. +* Added support for [views](./concepts/datamodel/view) in local backups: `{{ ydb-cli }} tools dump` and `{{ ydb-cli }} tools restore`. Views are backed up as `CREATE VIEW` queries saved in the `create_view.sql` files, which can be executed to recreate the original views. +* Added new options to the `{{ ydb-cli }} workload topic run` [command](./reference/ydb-cli/workload-topic#run-write): `--tx-commit-interval` and `--tx-commit-messages`, allowing you to specify the interval between transaction commits in milliseconds or in the number of messages written, respectively. +* Made the `--consumer` flag in the `{{ ydb-cli }} topic read` [command](./reference/ydb-cli/topic-read) optional. In the non-subscriber reading mode, the partition IDs must be specified with the `--partition-ids` option. In this case, the read is performed without saving the offset commit. +* The `{{ ydb-cli }} import file csv` [command](./reference/ydb-cli/export-import/import-file.md) now saves the import progress. Relaunching the import command will resume the process from the row where it was interrupted. +* In the `{{ ydb-cli }} workload kv` and `{{ ydb-cli }} workload stock` commands, the default value of the `--executer` option has been changed to `generic`, which makes them no longer rely on the legacy query execution infrastructure. +* Replaced the CSV format with Parquet for filling tables in the `{{ ydb-cli }} workload` benchmarks. +* **_(Requires server v25.1+)_** **_(Experimental)_** Added new `{{ ydb-cli }} admin storage` command with `fetch` and `replace` subcommands to manage server storage configuration. ### Backward incompatible changes -* Replaced the `--query-settings` option with `--query-prefix` in `ydb workload * run`. +* Replaced the `--query-settings` option with `--query-prefix` in the `{{ ydb-cli }} workload * run` command. ### Bug fixes -* Fixed a bug where the `ydb workload * run` command could crash in `--dry-run` mode. -* Fixed a bug in `ydb import file csv` where multiple columns with escaped quotes in the same row were parsed incorrectly. +* Fixed a bug where the `{{ ydb-cli }} workload * run` command could crash in `--dry-run` mode. +* Fixed a bug in the `{{ ydb-cli }} import file csv` where multiple columns with escaped quotes in the same row were parsed incorrectly. ## Version 2.17.0 {#2-17-0} @@ -54,7 +82,7 @@ Released on December 4, 2024. To update to version **2.17.0**, select the [Downl ### Features -* **_(Requires server v25.1+)_** **_(Experimental)_** Added `ydb debug ping` command for performance and connectivity debugging. +* **_(Requires server v25.1+)_** **_(Experimental)_** Added the `{{ ydb-cli }} debug ping` command for performance and connectivity debugging. ### Performance @@ -73,8 +101,8 @@ Released on November 26, 2024. To update to version **2.16.0**, select the [Down * Improved throughput of the `{{ ydb-cli }} import file csv` command by up to 3 times. * Added support for running the [stock benchmark](./reference/ydb-cli/commands/workload/stock.md) with [column-oriented tables](./concepts/datamodel/table.md#column-oriented-tables). -* Added support for [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)–formatted timestamps in `{{ ydb-cli }} topic` commands. -* Added the `--explain-ast` option to the `ydb sql` command, which prints the query AST. +* Added support for [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601)–formatted timestamps in the `{{ ydb-cli }} topic` commands. +* Added the `--explain-ast` option to the `{{ ydb-cli }} sql` command, which prints the query AST. * Added ANSI SQL syntax highlighting in interactive mode. * Added support for [PostgreSQL syntax](./postgresql/intro.md) in the `{{ ydb-cli }} workload tpch` and `{{ ydb-cli }} workload tpcds` benchmarks. * Introduced the `-c` option for the `{{ ydb-cli }} workload tpcds run` command to compare results with expected values and display differences. @@ -96,21 +124,21 @@ Released on June 24, 2024. To update to version **2.10.0**, select the [Download ### Features -* Added the `ydb sql` command that runs over QueryService and can execute any DML/DDL command. -* Added `notx` support for the `--tx-mode` option in `ydb table query execute`. +* Added the `{{ ydb-cli }} sql` command that runs over QueryService and can execute any DML/DDL command. +* Added `notx` support for the `--tx-mode` option in the `{{ ydb-cli }} table query execute` command. * Added start and end times for long-running operation descriptions (export, import). -* Added replication description support in the `ydb scheme describe` and `ydb scheme ls` commands. +* Added replication description support in the `{{ ydb-cli }} scheme describe` and `{{ ydb-cli }} scheme ls` commands. * Added big datetime types support: `Date32`, `Datetime64`, `Timestamp64`, `Interval64`. -* `ydb workload` commands rework: +* `{{ ydb-cli }} workload` commands rework: * Added the `--clear` option to the `init` subcommand, allowing tables from previous runs to be removed before workload initialization. - * Added the `ydb workload * import` command to prepopulate tables with initial content before executing benchmarks. + * Added the `{{ ydb-cli }} workload * import` command to prepopulate tables with initial content before executing benchmarks. ### Backward incompatible changes -* `ydb workload` commands rework: +* `{{ ydb-cli }} workload` commands rework: - * The `--path` option was moved to a specific workload level. For example: `ydb workload tpch --path some/tables/path init ...`. + * The `--path` option was moved to a specific workload level. For example: `{{ ydb-cli }} workload tpch --path some/tables/path init ...`. * The `--store=s3` option was changed to `--store=external-s3` in the `init` subcommand. @@ -125,11 +153,11 @@ Released on April 25, 2024. To update to version **2.9.0**, select the [Download ### Features * Improved query logical plan tables: added colors, more information, fixed some bugs. -* The verbose option `-v` is supported for `ydb workload` commands to provide debug information. -* Added an option to run `ydb workload tpch` with an S3 source to measure [federated queries](concepts/federated_query/index.md) performance. -* Added the `--rate` option for `ydb workload` commands to control the transactions (or requests) per second limit. +* The verbose option `-v` is supported for the `{{ ydb-cli }} workload` commands to provide debug information. +* Added an option to run the `{{ ydb-cli }} workload tpch` command with an S3 source to measure [federated queries](concepts/federated_query/index.md) performance. +* Added the `--rate` option for `{{ ydb-cli }} workload` commands to control the transactions (or requests) per second limit. * Added the `--use-virtual-addressing` option for S3 import/export, allowing the switch to [virtual hosting of buckets](https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html) for the S3 path layout. -* Improved `ydb scheme ls` performance due to listing directories in parallel. +* Improved the `{{ ydb-cli }} scheme ls` command performance due to listing directories in parallel. ### Bug fixes @@ -145,14 +173,14 @@ Released on January 12, 2024. To update to version **2.8.0**, select the [Downlo ### Features -* Added configuration management commands for the cluster `ydb admin config` and `ydb admin volatile-config`. +* Added new `{{ ydb-cli }} admin config` and `{{ ydb-cli }} admin volatile-config` commands for cluster configuration management. * Added support for loading PostgreSQL-compatible data types by [ydb import file csv|tsv|json](reference/ydb-cli/export-import/import-file.md) command. Only for row-oriented tables. * Added support for directory load from an S3-compatible storage in the [ydb import s3](reference/ydb-cli/export-import/import-s3.md) command. Currently only available on Linux and Mac OS. * Added support for outputting the results of [ydb table query execute](reference/ydb-cli/table-query-execute.md), [ydb yql](reference/ydb-cli/yql.md) and [ydb scripting yql](reference/ydb-cli/scripting-yql.md) commands in the [Apache Parquet](https://parquet.apache.org/docs/) format. * In the [ydb workload](reference/ydb-cli/commands/workload/index.md) commands, the `--executer` option has been added, which allows to specify which type of queries to use. * Added a column with median benchmark execution time in the statistics table of the [ydb workload clickbench](reference/ydb-cli/workload-click-bench.md) command. * **_(Experimental)_** Added the `generic` request type to the [ydb table query execute](reference/ydb-cli/table-query-execute.md) command, allowing to perform [DDL](https://en.wikipedia.org/wiki/Data_Definition_Language) and [DML](https://en.wikipedia.org/wiki/Data_Manipulation_Language) operations, return with arbitrarily-sized results and support for [MVCC](concepts/mvcc.md). The command uses an experimental API, compatibility is not guaranteed. -* **_(Experimental)_** In the `ydb table query explain` command, the `--collect-diagnostics` option has been added to collect query diagnostics and save it to a file. The command uses an experimental API, compatibility is not guaranteed. +* **_(Experimental)_** In the `{{ ydb-cli }} table query explain` command, the `--collect-diagnostics` option has been added to collect query diagnostics and save it to a file. The command uses an experimental API, compatibility is not guaranteed. ### Bug fixes @@ -167,8 +195,8 @@ Released on October 23, 2023. To update to version **2.7.0**, select the [Downlo ### Features * Added the [ydb tools pg-convert](postgresql/import.md#pg-convert) command, which prepares a dump obtained by the [pg_dump](https://www.postgresql.org/docs/current/app-pgdump.html) utility for loading into the YDB postgres-compatible layer. -* Added the `ydb workload query` load testing command, which loads the database with [script execution queries](reference/ydb-cli/yql.md) in multiple threads. -* Added a command `ydb scheme permissions list` to list permissions. +* Added the `{{ ydb-cli }} workload query` load testing command, which loads the database with [script execution queries](reference/ydb-cli/yql.md) in multiple threads. +* Added new `{{ ydb-cli }} scheme permissions list` command to list permissions. * In the commands [ydb table query execute](reference/ydb-cli/table-query-execute.md), [ydb table query explain](reference/ydb-cli/commands/explain-plan.md), [ydb yql](reference/ydb-cli/yql.md), and [ydb scripting yql](reference/ydb-cli/scripting-yql.md), the `--flame-graph` option has been added, specifying the path to the file in which you need to save the visualization of query execution statistics. * [Special commands](reference/ydb-cli/interactive-cli.md#spec-commands) in the interactive query execution mode are now case-insensitive. * Added validation for [special commands](reference/ydb-cli/interactive-cli.md#spec-commands) and their [parameters](reference/ydb-cli/interactive-cli.md#internal-vars). @@ -215,7 +243,7 @@ Released on June 20, 2023. To update to version **2.5.0**, select the [Downloads ### Features -* For the `ydb import file` command, a parameter [--timeout](reference/ydb-cli/export-import/import-file.md#optional) has been added that specifies the time within which the operation should be performed on the server. +* For the `{{ ydb-cli }} import file` command, a parameter [--timeout](reference/ydb-cli/export-import/import-file.md#optional) has been added that specifies the time within which the operation should be performed on the server. * Added a progress bar in commands [ydb scheme rmdir --recursive](reference/ydb-cli/commands/dir.md#rmdir) and [ydb import file](reference/ydb-cli/export-import/import-file.md). * Added the command [ydb workload kv run read-rows](reference/ydb-cli/workload-kv.md#read-rows-kv), which loads the database with requests to read rows using a new experimental API call ReadRows (implemented only in the [main](https://github.com/ydb-platform/ydb) branch), which performs faster key reading than [select](reference/ydb-cli/workload-kv.md#select-kv). * New parameters `--warmup-time`, `--percentile`, `--topic` have been added to the [ydb workload topic](reference/ydb-cli/workload-topic.md), setting the test warm-up time, the percentile in the statistics output and the topic name, respectively. @@ -224,7 +252,7 @@ Released on June 20, 2023. To update to version **2.5.0**, select the [Downloads ### Performance -* The data loading speed in the `ydb import file` command has been increased by adding parallel loading. The number of threads is set by the new parameter [--threads](reference/ydb-cli/export-import/import-file.md#optional). +* The data loading speed in the `{{ ydb-cli }} import file` command has been increased by adding parallel loading. The number of threads is set by the new parameter [--threads](reference/ydb-cli/export-import/import-file.md#optional). * A performance of the [ydb import file json](reference/ydb-cli/export-import/import-file.md) command has been increased by reducing the number of data copies. ## Version 2.4.0 {#2-4-0} @@ -245,16 +273,16 @@ Release date: May 1, 2023. To update to version **2.3.0**, select the [Downloads * Added the interactive mode of query execution. To switch to the interactive mode, run [ydb yql](reference/ydb-cli/yql.md) without arguments. This mode is experimental: backward compatibility is not guaranteed yet. * Added the [ydb index rename](reference/ydb-cli/commands/secondary_index.md#rename) command for [atomic replacement](dev/secondary-indexes.md#atomic-index-replacement) or renaming of a secondary index. -* Added the `ydb workload topic` command for generating the load that reads messages from topics and writes messages to topics. -* Added the [--recursive](reference/ydb-cli/commands/dir.md#rmdir-options) option for the `ydb scheme rmdir` command. Use it to delete a directory recursively, with all its content. +* Added the `{{ ydb-cli }} workload topic` command for generating the load that reads messages from topics and writes messages to topics. +* Added the [--recursive](reference/ydb-cli/commands/dir.md#rmdir-options) option for the `{{ ydb-cli }} scheme rmdir` command. Use it to delete a directory recursively, with all its content. * Added support for the `topic` and `coordination node` types in the [ydb scheme describe](reference/ydb-cli/commands/scheme-describe.md) command. -* Added the [--commit](reference/ydb-cli/topic-read.md#osnovnye-opcionalnye-parametry) option for the `ydb topic consumer` command. Use it to commit messages you have read. -* Added the [--columns](reference/ydb-cli/export-import/import-file.md#optional) option for the `ydb import file csv|tsv` command. Use it as an alternative to the file header when specifying a column list. -* Added the [--newline-delimited](reference/ydb-cli/export-import/import-file.md#optional) option for the `ydb import file csv|tsv` command. Use it to make sure that your data is newline-free. This option streamlines import by reading data from several file sections in parallel. +* Added the [--commit](reference/ydb-cli/topic-read.md#osnovnye-opcionalnye-parametry) option for the `{{ ydb-cli }} topic consumer` command. Use it to commit messages you have read. +* Added the [--columns](reference/ydb-cli/export-import/import-file.md#optional) option for the `{{ ydb-cli }} import file csv|tsv` command. Use it as an alternative to the file header when specifying a column list. +* Added the [--newline-delimited](reference/ydb-cli/export-import/import-file.md#optional) option for the `{{ ydb-cli }} import file csv|tsv` command. Use it to make sure that your data is newline-free. This option streamlines import by reading data from several file sections in parallel. ### Bug fixes -* Fixed the bug that resulted in excessive memory and CPU utilization when executing the `ydb import file` command. +* Fixed the bug that resulted in excessive memory and CPU utilization when executing the `{{ ydb-cli }} import file` command. ## Version 2.2.0 {#2-2-0} @@ -292,7 +320,7 @@ Release date: November 18, 2022. To update to version **2.1.0**, select the [Dow * You can now save the IAM service URL in a profile. * Added support for username and password-based authentication without specifying the password. * Added support for AWS profiles in the [ydb export s3](reference/ydb-cli/export-import/auth-s3.md#auth) command. -* You can now create profiles using `stdin`. For example, you can pass the [YC CLI](https://cloud.yandex.ru/docs/cli/) `yc ydb database get information` command output to the `ydb config profile create` command input. +* You can now create profiles using `stdin`. For example, you can pass the [YC CLI](https://cloud.yandex.ru/docs/cli/) `yc ydb database get information` command output to the `{{ ydb-cli }} config profile create` command input. ### Bug fixes @@ -307,25 +335,25 @@ Release date: September 20, 2022. To update to version **2.0.0**, select the [Do * Added the ability to work with topics: - * `ydb topic create`: Create a topic. - * `ydb topic alter`: Update a topic. - * `ydb topic write`: Write data to a topic. - * `ydb topic read`: Read data from a topic. - * `ydb topic drop`: Delete a topic. + * `{{ ydb-cli }} topic create`: Create a topic. + * `{{ ydb-cli }} topic alter`: Update a topic. + * `{{ ydb-cli }} topic write`: Write data to a topic. + * `{{ ydb-cli }} topic read`: Read data from a topic. + * `{{ ydb-cli }} topic drop`: Delete a topic. * Added a new type of load testing: - * `ydb workload kv init`: Create a table for kv load testing. - * `ydb workload kv run`: Apply one of three types of load: run multiple `UPSERT` sessions, run multiple `INSERT` sessions, or run multiple sessions of GET requests by primary key. - * `ydb workload kv clean`: Delete a test table. - -* Added the ability to disable current active profile (see the `ydb config profile deactivate` command). -* Added the ability to delete a profile non-interactively with no commit (see the `--force` option under the `ydb config profile remove` command). -* Added CDC support for the `ydb scheme describe` command. -* Added the ability to view the current DB status (see the `ydb monitoring healthcheck` command). -* Added the ability to view authentication information (token) to be sent with DB queries under the current authentication settings (see the `ydb auth get-token` command). -* Added the ability for the `ydb import` command to read data from stdin. -* Added the ability to import data in JSON format from a file or stdin (see the `ydb import file json` command). + * `{{ ydb-cli }} workload kv init`: Create a table for kv load testing. + * `{{ ydb-cli }} workload kv run`: Apply one of three types of load: run multiple `UPSERT` sessions, run multiple `INSERT` sessions, or run multiple sessions of GET requests by primary key. + * `{{ ydb-cli }} workload kv clean`: Delete a test table. + +* Added the ability to disable current active profile (see the `{{ ydb-cli }} config profile deactivate` command). +* Added the ability to delete a profile non-interactively with no commit (see the `--force` option under the `{{ ydb-cli }} config profile remove` command). +* Added CDC support for the `{{ ydb-cli }} scheme describe` command. +* Added the ability to view the current DB status (see the `{{ ydb-cli }} monitoring healthcheck` command). +* Added the ability to view authentication information (token) to be sent with DB queries under the current authentication settings (see the `{{ ydb-cli }} auth get-token` command). +* Added the ability for the `{{ ydb-cli }} import` command to read data from stdin. +* Added the ability to import data in JSON format from a file or stdin (see the `{{ ydb-cli }} import file json` command). ### Improvements diff --git a/ydb/docs/en/core/downloads/_includes/ydb-cli/darwin_amd64.md b/ydb/docs/en/core/downloads/_includes/ydb-cli/darwin_amd64.md index 9eb2ecee2b0b..45e1d5657829 100644 --- a/ydb/docs/en/core/downloads/_includes/ydb-cli/darwin_amd64.md +++ b/ydb/docs/en/core/downloads/_includes/ydb-cli/darwin_amd64.md @@ -1,6 +1,7 @@ Use the amd64 binary if you have an Intel-based Mac. | Version | Release date | Download | Changelog | :--- | :--- | :--- | :--- +| v.2.20.0 | 05/03/2025 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.20.0/darwin/amd64/ydb) | [See the changelog](../../../changelog-cli.md#2-20-0) | | v.2.19.0 | 05/02/2025 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.19.0/darwin/amd64/ydb) | [See the changelog](../../../changelog-cli.md#2-19-0) | | v.2.18.0 | 24/12/2024 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.18.0/darwin/amd64/ydb) | [See the changelog](../../../changelog-cli.md#2-18-0) | | v.2.17.0 | 04/12/2024 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.17.0/darwin/amd64/ydb) | [See the changelog](../../../changelog-cli.md#2-17-0) | diff --git a/ydb/docs/en/core/downloads/_includes/ydb-cli/darwin_arm64.md b/ydb/docs/en/core/downloads/_includes/ydb-cli/darwin_arm64.md index 26e5fa619e07..f0927d1d5496 100644 --- a/ydb/docs/en/core/downloads/_includes/ydb-cli/darwin_arm64.md +++ b/ydb/docs/en/core/downloads/_includes/ydb-cli/darwin_arm64.md @@ -1,6 +1,7 @@ Use the arm64 binary if you have an M-series Mac. | Version | Release date | Download | Changelog | :--- | :--- | :--- | :--- +| v.2.20.0 | 05/03/2025 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.20.0/darwin/arm64/ydb) | [See the changelog](../../../changelog-cli.md#2-20-0) | | v.2.19.0 | 05/02/2025 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.19.0/darwin/arm64/ydb) | [See the changelog](../../../changelog-cli.md#2-19-0) | | v.2.18.0 | 24/12/2024 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.18.0/darwin/arm64/ydb) | [See the changelog](../../../changelog-cli.md#2-18-0) | | v.2.17.0 | 04/12/2024 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.17.0/darwin/arm64/ydb) | [See the changelog](../../../changelog-cli.md#2-17-0) | diff --git a/ydb/docs/en/core/downloads/_includes/ydb-cli/linux_amd64.md b/ydb/docs/en/core/downloads/_includes/ydb-cli/linux_amd64.md index 1265adcfb4f0..6ba4fa8a713a 100644 --- a/ydb/docs/en/core/downloads/_includes/ydb-cli/linux_amd64.md +++ b/ydb/docs/en/core/downloads/_includes/ydb-cli/linux_amd64.md @@ -1,5 +1,6 @@ | Version | Release date | Download | Changelog | :--- | :--- | :--- | :--- +| v.2.20.0 | 05/03/2025 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.20.0/linux/amd64/ydb) | [See the changelog](../../../changelog-cli.md#2-20-0) | | v.2.19.0 | 05/02/2025 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.19.0/linux/amd64/ydb) | [See the changelog](../../../changelog-cli.md#2-19-0) | | v.2.18.0 | 24/12/2024 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.18.0/linux/amd64/ydb) | [See the changelog](../../../changelog-cli.md#2-18-0) | | v.2.17.0 | 04/12/2024 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.17.0/linux/amd64/ydb) | [See the changelog](../../../changelog-cli.md#2-17-0) | diff --git a/ydb/docs/en/core/downloads/_includes/ydb-cli/linux_arm64.md b/ydb/docs/en/core/downloads/_includes/ydb-cli/linux_arm64.md index d240bd312f23..378a6c8deade 100644 --- a/ydb/docs/en/core/downloads/_includes/ydb-cli/linux_arm64.md +++ b/ydb/docs/en/core/downloads/_includes/ydb-cli/linux_arm64.md @@ -1,5 +1,6 @@ | Version | Release date | Download | Changelog | :--- | :--- | :--- | :--- +| v.2.20.0 | 05/03/2025 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.20.0/linux/arm64/ydb) | [See the changelog](../../../changelog-cli.md#2-20-0) | | v.2.19.0 | 05/02/2025 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.19.0/linux/arm64/ydb) | [See the changelog](../../../changelog-cli.md#2-19-0) | | v.2.18.0 | 24/12/2024 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.18.0/linux/arm64/ydb) | [See the changelog](../../../changelog-cli.md#2-18-0) | | v.2.17.0 | 04/12/2024 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.17.0/linux/arm64/ydb) | [See the changelog](../../../changelog-cli.md#2-17-0) | diff --git a/ydb/docs/en/core/downloads/_includes/ydb-cli/windows.md b/ydb/docs/en/core/downloads/_includes/ydb-cli/windows.md index ec5537f274fd..84222b780256 100644 --- a/ydb/docs/en/core/downloads/_includes/ydb-cli/windows.md +++ b/ydb/docs/en/core/downloads/_includes/ydb-cli/windows.md @@ -1,5 +1,6 @@ | Version | Release date | Download | Changelog | :--- | :--- | :--- | :--- +| v.2.20.0 | 05/03/2025 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.20.0/windows/amd64/ydb.exe) | [See the changelog](../../../changelog-cli.md#2-20-0) | | v.2.19.0 | 05/02/2025 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.19.0/windows/amd64/ydb.exe) | [See the changelog](../../../changelog-cli.md#2-19-0) | | v.2.18.0 | 24/12/2024 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.18.0/windows/amd64/ydb.exe) | [See the changelog](../../../changelog-cli.md#2-18-0) | | v.2.17.0 | 04/12/2024 | [Binary file](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.17.0/windows/amd64/ydb.exe) | [See the changelog](../../../changelog-cli.md#2-17-0) | diff --git a/ydb/docs/ru/core/changelog-cli.md b/ydb/docs/ru/core/changelog-cli.md index 788286b2b09b..e8842f082d64 100644 --- a/ydb/docs/ru/core/changelog-cli.md +++ b/ydb/docs/ru/core/changelog-cli.md @@ -2,35 +2,63 @@ # Список изменений {{ ydb-short-name }} CLI +## Версия 2.20.0 {#2-20-0} + +Дата выхода 5 марта 2024. Для обновления до версии **2.20.0** перейдите в раздел [Загрузки](downloads/index.md#ydb-cli). + +### Функциональность + +* Добавлена поддержка [топиков](./concepts/topic.md) при выполнении [команд](./reference/ydb-cli/export-import/tools-dump.md) `{{ ydb-cli }} tools dump` и `{{ ydb-cli }} tools restore`. +* Добавлена поддержка [узлов координации](./concepts/datamodel/coordination-node.md) при выполнении [команд](./reference/ydb-cli/export-import/tools-dump.md) `{{ ydb-cli }} tools dump` и `{{ ydb-cli }} tools restore`. +* Добавлена новая команда `{{ ydb-cli }} workload log import generator`. +* Добавлены новые глобальные опции для пользовательских сертификатов при соединении через SSL/TLS: + * `--client-cert-file`: файл, содержащий пользовательский сертификат для SSL/TLS соединения, закодированный в PEM или PKCS#12. + * `--client-cert-key-file`: файл, содержащий приватный ключ к пользовательскому сертификату, закодированный в PEM. + * `--client-cert-key-password-file`: файл, содержащий пароль для приватного ключа пользовательского сертификата. +* Запросы при выполнении команды `{{ ydb-cli }} workload run` теперь отправляются на сервер в произвольном порядке. +* **_(Требуется сервер v25.1+)_** Добавлена поддержка [внешних источников данных](./concepts/datamodel/external_data_source.md) и [внешних таблиц](./concepts/datamodel/external_table.md) при выполнении [команд](./reference/ydb-cli/export-import/tools-dump.md) `{{ ydb-cli }} tools dump` и `{{ ydb-cli }} tools restore`. +* **_(Экспериментально)_** Добавлена команда `{{ ydb-cli }} admin node config init` для инициализации директории с конфигурационными файлами узла. +* **_(Требуется сервер v25.1+)_** **_(Экспериментально)_** Добавлена [команда](./reference/ydb-cli/configs.md) `{{ ydb-cli }} admin cluster config generate` для генерации файла динамической конфигурации из файла статической конфигурации кластера. +* **_(Требуется сервер v25.1+)_** **_(Экспериментально)_** Добавлены [команда](./reference/ydb-cli/export-import/tools-dump#cluster) `{{ ydb-cli }} admin cluster dump` и [команда](./reference/ydb-cli/export-import/tools-restore#cluster) `{{ ydb-cli }} admin cluster restore` для создания дампа кластера. Дамп кластера содержит список баз данных с метаданными, пользователей и группы, но не содержит схемные объекты. +* **_(Требуется сервер v25.1+)_** **_(Экспериментально)_** Добавлены команды `{{ ydb-cli }} admin database dump` и `{{ ydb-cli }} admin database restore` для создания дампа базы данных. Такой дамп содержит метаданные базы данных, схемные объекты, данные в них, пользователей и группы. +* **_(Требуется сервер v25.1+)_** **_(Экспериментально)_** Для команды `ydb admin cluster config fetch` добавлены новые опции `--dedicated-storage-section` и `--dedicated-cluster-section`, позволяющие получать части конфигурации для кластера и хранилища отдельно. + +### Исправления ошибок + +* Исправлена ошибка, из-за которой дважды отправлялся запрос аутентификации в команде `{{ ydb-cli }} auth get-token` при получении списка эндпойнтов (Discovery запрос) и при фактическом выполнении запроса на получение токена. +* Исправлена ошибка в команде `{{ ydb-cli }} import file csv`, при которой прогресс импорта сохранялся даже если отправка пакета данных завершилась ошибкой. +* Исправлена ошибка, из-за которой при выполнении команды `{{ ydb-cli }} tools restore` некоторые ошибки игнорировались. +* Исправлена утечка памяти при генерации данных для `{{ ydb-cli }} workload tpcds`. + ## Версия 2.19.0 {#2-19-0} Дата выхода 5 февраля 2025. Для обновления до версии **2.19.0** перейдите в раздел [Загрузки](downloads/index.md#ydb-cli). ### Функциональность -* Добавлена поддержка [потоков изменений (changefeeds)](./concepts/cdc.md) при выполнении [команд](./reference/ydb-cli/export-import/tools-dump.md) `ydb tools dump` и `ydb tools restore`. -* Добавлена рекомендация с текстом `CREATE TABLE` при схемной ошибке во время выполнения [команды](./reference/ydb-cli/export-import/import-file.md) `ydb import file csv`. -* Добавлен вывод статистики для текущего процесса при выполнении [команды](./reference/ydb-cli/commands/workload/index.md) `ydb workload`. -* Добавлен текст запроса к сообщению, если запрос завершился ошибкой при выполнении [команды](./reference/ydb-cli/commands/workload/index.md) `ydb workload run`. -* Добавлено сообщение в случае ошибки истечения глобального таймаута при выполнении [команды](./reference/ydb-cli/commands/workload/index.md) `ydb workload run`. +* Добавлена поддержка [потоков изменений (changefeeds)](./concepts/cdc.md) при выполнении [команд](./reference/ydb-cli/export-import/tools-dump.md) `{{ ydb-cli }} tools dump` и `{{ ydb-cli }} tools restore`. +* Добавлена рекомендация с текстом `CREATE TABLE` при схемной ошибке во время выполнения [команды](./reference/ydb-cli/export-import/import-file.md) `{{ ydb-cli }} import file csv`. +* Добавлен вывод статистики для текущего процесса при выполнении [команды](./reference/ydb-cli/commands/workload/index.md) `{{ ydb-cli }} workload`. +* Добавлен текст запроса к сообщению, если запрос завершился ошибкой при выполнении [команды](./reference/ydb-cli/commands/workload/index.md) `{{ ydb-cli }} workload run`. +* Добавлено сообщение в случае ошибки истечения глобального таймаута при выполнении [команды](./reference/ydb-cli/commands/workload/index.md) `{{ ydb-cli }} workload run`. {% if feature_view %} -* **_(Требуется сервер v25.1+)_** Добавлена поддержка [представлений (VIEW)](./concepts/datamodel/view.md) при выполнении операций `ydb export s3` и `ydb import s3`. Представления экспортируются как YQL-выражение `CREATE VIEW`, которое выполняется при импорте. +* **_(Требуется сервер v25.1+)_** Добавлена поддержка [представлений (VIEW)](./concepts/datamodel/view.md) при выполнении операций `{{ ydb-cli }} export s3` и `{{ ydb-cli }} import s3`. Представления экспортируются как YQL-выражение `CREATE VIEW`, которое выполняется при импорте. {% endif %} -* **_(Требуется сервер v25.1+)_** Добавлена опция `--skip-checksum-validation` для [команды](./reference/ydb-cli/export-import/import-s3.md) `ydb import s3`, позволяющая отключить валидацию контрольной суммы на стороне сервера. -* **_(Требуется сервер v25.1+)_** **_(Экспериментально)_** Для команды `ydb debug ping` добавлены новые опции: `--chain-length`, `--chain-work-duration`, `--no-tail-chain`. -* **_(Требуется сервер v25.1+)_** **_(Экспериментально)_** Для команды `ydb admin storage fetch` добавлены новые опции: `--dedicated-storage-section` and `--dedicated-cluster-section`. -* **_(Требуется сервер v25.1+)_** **_(Экспериментально)_** Для команды `ydb admin storage replace` добавлены новые опции: `--filename`, `--dedicated-cluster-yaml`, `--dedicated-storage-yaml`, `--enable-dedicated-storage-section` and `--disable-dedicated-storage-section`. +* **_(Требуется сервер v25.1+)_** Добавлена опция `--skip-checksum-validation` для [команды](./reference/ydb-cli/export-import/import-s3.md) `{{ ydb-cli }} import s3`, позволяющая отключить валидацию контрольной суммы на стороне сервера. +* **_(Требуется сервер v25.1+)_** **_(Экспериментально)_** Для команды `{{ ydb-cli }} debug ping` добавлены новые опции: `--chain-length`, `--chain-work-duration`, `--no-tail-chain`. +* **_(Требуется сервер v25.1+)_** **_(Экспериментально)_** Для команды `{{ ydb-cli }} admin storage fetch` добавлены новые опции: `--dedicated-storage-section` и `--dedicated-cluster-section`. +* **_(Требуется сервер v25.1+)_** **_(Экспериментально)_** Для команды `{{ ydb-cli }} admin storage replace` добавлены новые опции: `--filename`, `--dedicated-cluster-yaml`, `--dedicated-storage-yaml`, `--enable-dedicated-storage-section` и `--disable-dedicated-storage-section`. ### Исправления ошибок -* Исправлена ошибка, из-за которой [команда](./reference/ydb-cli/commands/service.md) `ydb update` в arm64-версии исполняемого файла YDB CLI скачивала и заменяла себя исполняемым файлом amd64-версии. Чтобы обновить ранее установленный YDB CLI до последней arm64-версии (а не amd64), его нужно переустановить. -* [Команда](./reference/ydb-cli/commands/workload/index.md) `ydb workload run` теперь возвращает корректный код возврата. -* Исправлена ошибка, из-за которой [команды](./reference/ydb-cli/workload-tpch.md) `ydb workload tpch import generator` и `ydb workload tpcds import generator` завершались с ошибкой из-за отсутствия необходимых таблиц в схеме. -* Исправлена ошибка с обратными слешами при указании путей в [команде]](./reference/ydb-cli/commands/workload/index.md) `ydb workload` на Windows. +* Исправлена ошибка, из-за которой [команда](./reference/ydb-cli/commands/service.md) `{{ ydb-cli }} update` в arm64-версии исполняемого файла YDB CLI скачивала и заменяла себя исполняемым файлом amd64-версии. Чтобы обновить ранее установленный YDB CLI до последней arm64-версии (а не amd64), его нужно переустановить. +* [Команда](./reference/ydb-cli/commands/workload/index.md) `{{ ydb-cli }} workload run` теперь возвращает корректный код возврата. +* Исправлена ошибка, из-за которой [команды](./reference/ydb-cli/workload-tpch.md) `{{ ydb-cli }} workload tpch import generator` и `{{ ydb-cli }} workload tpcds import generator` завершались с ошибкой из-за отсутствия необходимых таблиц в схеме. +* Исправлена ошибка с обратными слешами при указании путей в [команде]](./reference/ydb-cli/commands/workload/index.md) `{{ ydb-cli }} workload` на Windows. ## Версия 2.18.0 {#2-18-0} @@ -38,22 +66,22 @@ ### Функциональность -* Добавлена поддержка [представлений (VIEW)](./concepts/datamodel/view) при выполнении операций резервного копирования `ydb tools dump` и восстановления `ydb tools restore`. Представления сохраняются в файл "create_view.sql" в виде запросов `CREATE VIEW`, которые будут выполнены для восстановления. -* В [команду](./reference/ydb-cli/workload-topic#run-write) `ydb workload topic run` добавлены опции `--tx-commit-interval` и `--tx-commit-messages`, которые задают интервал между коммитами транзакций в миллисекундах и в количестве записанных сообщений соответственно. -* В [команде](./reference/ydb-cli/topic-read) `ydb topic read` параметр `--consumer` перестал быть обязательным. В режиме чтения без подписчика обязательно должны быть указаны идентификаторы партиций с помощью параметра `--partition-ids`. Чтение в этом случае выполняется без сохранения коммита оффсетов. -* [Команда](./reference/ydb-cli/export-import/import-file.md) `ydb import file csv` теперь сохраняет прогресс выполнения. Повторный запуск команды импорта продолжится с той строки, на которой она была прервана. -* В командах `ydb workload kv` и `ydb workload stock` значение параметра `--executer` по умолчанию изменено на "generic", благодаря чему они больше не используют устаревшую инфраструктуру выполнения запросов. -* Изменен формат загрузки данных в таблицы для нагрузочных тестов `ydb workload` с CSV на Parquet. -* **_(Требуется сервер v25.1+)_** **_(Экспериментально)_** Добавлена команда `ydb admin storage` с подкомандами `fetch` и `replace` для управления конфигурацией хранилища сервера. +* Добавлена поддержка [представлений (VIEW)](./concepts/datamodel/view) при выполнении операций резервного копирования `{{ ydb-cli }} tools dump` и восстановления `{{ ydb-cli }} tools restore`. Представления сохраняются в файл "create_view.sql" в виде запросов `CREATE VIEW`, которые будут выполнены для восстановления. +* В [команду](./reference/ydb-cli/workload-topic#run-write) `{{ ydb-cli }} workload topic run` добавлены опции `--tx-commit-interval` и `--tx-commit-messages`, которые задают интервал между коммитами транзакций в миллисекундах и в количестве записанных сообщений соответственно. +* В [команде](./reference/ydb-cli/topic-read) `{{ ydb-cli }} topic read` параметр `--consumer` перестал быть обязательным. В режиме чтения без подписчика обязательно должны быть указаны идентификаторы партиций с помощью параметра `--partition-ids`. Чтение в этом случае выполняется без сохранения коммита оффсетов. +* [Команда](./reference/ydb-cli/export-import/import-file.md) `{{ ydb-cli }} import file csv` теперь сохраняет прогресс выполнения. Повторный запуск команды импорта продолжится с той строки, на которой она была прервана. +* В командах `{{ ydb-cli }} workload kv` и `{{ ydb-cli }} workload stock` значение параметра `--executer` по умолчанию изменено на "generic", благодаря чему они больше не используют устаревшую инфраструктуру выполнения запросов. +* Изменен формат загрузки данных в таблицы для нагрузочных тестов `{{ ydb-cli }} workload` с CSV на Parquet. +* **_(Требуется сервер v25.1+)_** **_(Экспериментально)_** Добавлена команда `{{ ydb-cli }} admin storage` с подкомандами `fetch` и `replace` для управления конфигурацией хранилища сервера. ### Изменения с потерей обратной совместимости -* В команде `ydb workload * run` параметр `--query-settings` заменен на `--query-prefix`. +* В команде `{{ ydb-cli }} workload * run` параметр `--query-settings` заменен на `--query-prefix`. ### Исправления ошибок -* Исправлена ошибка, из-за которой команда `ydb workload * run` в режиме `--dry-run` могла приводить к сбою. -* Исправлена ошибка в `ydb import file csv`, из-за которой несколько столбцов с экранированными кавычками в одной строке обрабатывались неправильно. +* Исправлена ошибка, из-за которой команда `{{ ydb-cli }} workload * run` в режиме `--dry-run` могла приводить к сбою. +* Исправлена ошибка в `{{ ydb-cli }} import file csv`, из-за которой несколько столбцов с экранированными кавычками в одной строке обрабатывались неправильно. ## Версия 2.17.0 {#2-17-0} @@ -61,7 +89,7 @@ ### Функциональность -* **_(Требуется сервер v25.1+)_** **_(Экспериментально)_** Добавлена команда `ydb debug ping` для проверки производительности и связанности. +* **_(Требуется сервер v25.1+)_** **_(Экспериментально)_** Добавлена команда `{{ ydb-cli }} debug ping` для проверки производительности и связанности. ### Производительность @@ -69,7 +97,7 @@ ### Исправления ошибок -* Исправлена ошибка в схеме таблиц, созданных командой `ydb workload tpch`, из-за которой таблица `partsupp` содержала неверный список ключевых столбцов. +* Исправлена ошибка в схеме таблиц, созданных командой `{{ ydb-cli }} workload tpch`, из-за которой таблица `partsupp` содержала неверный список ключевых столбцов. * Исправлена ошибка, из-за которой команда `{{ ydb-cli }} tools restore` завершалась с ошибкой `Too much data`, если было установлено максимальное значение параметра `--upload-batchbytes` (16MB). ## Версия 2.16.0 {#2-16-0} @@ -80,7 +108,7 @@ * Увеличена пропускная способность команды `{{ ydb-cli }} import file csv` примерно в 3 раза. * Добавлена поддержка [stock-нагрузки](./reference/ydb-cli/commands/workload/stock.md) для [колоночных таблиц](./concepts/datamodel/table.md#column-oriented-tables). -* Реализована поддержка временных меток в формате [ISO 8601](https://ru.wikipedia.org/wiki/ISO_8601) для команд `ydb topic`. +* Реализована поддержка временных меток в формате [ISO 8601](https://ru.wikipedia.org/wiki/ISO_8601) для команд `{{ ydb-cli }} topic`. * В команду `{{ ydb-cli }} sql` добавлена опция `--explain-ast`, которая выводит AST запроса. * Добавлена подсветка синтаксиса ANSI SQL в интерактивном режиме. * В команды `{{ ydb-cli }} workload tpch` и `{{ ydb-cli }} workload tpcds` добавлена поддержка синтаксиса PostgreSQL. @@ -94,7 +122,7 @@ ### Исправления ошибок -* Исправлен progress bar для команды `ydb workload import`. +* Исправлен progress bar для команды `{{ ydb-cli }} workload import`. * Устранена ошибка восстановления из резервной копии с использованием опции `--import-data`, возникавшая при изменении партиционирования таблицы. ## Версия 2.10.0 {#2-10-0} @@ -103,21 +131,21 @@ ### Функциональность -* Добавлена команда `ydb sql`, работающая поверх QueryService, позволяющая выполнять любые DML/DDL команды. -* Добавлен режим `notx` для опции `--tx-mode` в команде `ydb table query execute`. +* Добавлена команда `{{ ydb-cli }} sql`, работающая поверх QueryService, позволяющая выполнять любые DML/DDL команды. +* Добавлен режим `notx` для опции `--tx-mode` в команде `{{ ydb-cli }} table query execute`. * Добавлены времена начала и конца в описании длительных операций (export, import). -* Добавлена поддержка описания объектов типа replication в командах `ydb scheme describe` и `ydb scheme ls`. +* Добавлена поддержка описания объектов типа replication в командах `{{ ydb-cli }} scheme describe` и `{{ ydb-cli }} scheme ls`. * Добавлена поддержка типов big datetime: `Date32`, `Datetime64`, `Timestamp64`, `Interval64`. -* Переработана команда `ydb workload`: +* Переработана команда `{{ ydb-cli }} workload`: * Добавлена опция `--clear` в подкоманде `init`, позволяющая удалить все существующие таблицы перед созданием новых. - * Добавлена команда `ydb workload * import` для заполнения таблиц начальным контентом перед началом нагрузки. + * Добавлена команда `{{ ydb-cli }} workload * import` для заполнения таблиц начальным контентом перед началом нагрузки. ### Изменения с потерей обратной совместимости -* Переработана команда `ydb workload`: +* Переработана команда `{{ ydb-cli }} workload`: - * Опция `--path` перемещена на уровень конкретного типа нагрузки. Например: `ydb workload tpch --path some/tables/path init ...`. + * Опция `--path` перемещена на уровень конкретного типа нагрузки. Например: `{{ ydb-cli }} workload tpch --path some/tables/path init ...`. * Значение опции `--store=s3` переименовано в `--store=external-s3` в подкоманде `init`. ### Исправления ошибок @@ -131,11 +159,11 @@ ### Функциональность * Улучшены таблицы с логическими планами запросов: стали информативнее, добавлены цвета, исправлены некоторые ошибки. -* Для команды `ydb workload` поддержана опция `-v`, включающая вывод отладочной информации. -* Добавлена возможность запустить `ydb workload tpch --store s3` с источником s3 для измерения производительности федеративных запросов. -* Добавлена опция `--rate` для команды `ydb workload` для ограничения количества транзакций (запросов) в секунду. +* Для команды `{{ ydb-cli }} workload` поддержана опция `-v`, включающая вывод отладочной информации. +* Добавлена возможность запустить `{{ ydb-cli }} workload tpch --store s3` с источником s3 для измерения производительности федеративных запросов. +* Добавлена опция `--rate` для команды `{{ ydb-cli }} workload` для ограничения количества транзакций (запросов) в секунду. * Добавлена опция `--use-virtual-addressing` для импорта/экспорта s3, позволяющая переключить режим [virtual hosting of buckets](https://docs.aws.amazon.com/AmazonS3/latest/userguide/VirtualHosting.html) для схемы путей s3. -* Улучшена производительность команды `ydb scheme ls` параллельным запуском листингов директорий. +* Улучшена производительность команды `{{ ydb-cli }} scheme ls` параллельным запуском листингов директорий. ### Исправления ошибок @@ -158,7 +186,7 @@ * В командах [ydb workload](reference/ydb-cli/commands/workload/index.md) добавлена опция `--executer`, задающая используемый тип запросов. * Добавлена колонка медианного времени выполнения бенчмарка в таблице статистики в команде [ydb workload clickbench](reference/ydb-cli/workload-click-bench.md). * **_(Experimental)_** Добавлен тип запросов `generic` в команде [ydb table query execute](reference/ydb-cli/table-query-execute.md), позволяющий выполнять [DDL](https://ru.wikipedia.org/wiki/Data_Definition_Language) и [DML](https://ru.wikipedia.org/wiki/Data_Manipulation_Language) операции, с результатами произвольного размера и c поддержкой [MVCC](concepts/mvcc.md). Команда использует экспериментальное API, совместимость не гарантируется. -* **_(Experimental)_** В команде `ydb table query explain` добавлена опция `--collect-diagnostics` для сбора диагностики запроса и сохранения её в файл. Команда использует экспериментальное API, совместимость не гарантируется. +* **_(Experimental)_** В команде `{{ ydb-cli }} table query explain` добавлена опция `--collect-diagnostics` для сбора диагностики запроса и сохранения её в файл. Команда использует экспериментальное API, совместимость не гарантируется. ### Исправления ошибок @@ -172,8 +200,8 @@ ### Функциональность * Добавлена команда [ydb tools pg-convert](postgresql/import.md#pg-convert), выполняющая подготовку дампа, полученного утилитой [pg_dump](https://www.postgresql.org/docs/current/app-pgdump.html), к загрузке в postgres-совместимую прослойку YDB. -* Добавлена команда нагрузочного тестирования `ydb workload query`, которая нагружает базу [запросами выполнения скрипта](reference/ydb-cli/yql.md) в несколько потоков. -* Добавлена команда для просмотра списка разрешений `ydb scheme permissions list`. +* Добавлена команда нагрузочного тестирования `{{ ydb-cli }} workload query`, которая нагружает базу [запросами выполнения скрипта](reference/ydb-cli/yql.md) в несколько потоков. +* Добавлена команда для просмотра списка разрешений `{{ ydb-cli }} scheme permissions list`. * В командах [ydb table query execute](reference/ydb-cli/table-query-execute.md), [ydb table query explain](reference/ydb-cli/commands/explain-plan.md), [ydb yql](reference/ydb-cli/yql.md) и [ydb scripting yql](reference/ydb-cli/scripting-yql.md) добавлена опция `--flame-graph`, задающая путь до файла, в котором необходимо сохранить визуализацию статистики выполнения запросов. * [Специальные команды](reference/ydb-cli/interactive-cli.md#spec-commands) интерактивного режима выполнения запросов теперь не чувствительны к регистру. * Добавлена валидация [специальных команд](reference/ydb-cli/interactive-cli.md#spec-commands) и их [параметров](reference/ydb-cli/interactive-cli.md#internal-vars). @@ -220,7 +248,7 @@ ### Функциональность -* Для команды `ydb import file` добавлен параметр [--timeout](reference/ydb-cli/export-import/import-file.md#optional), задающий время, в течение которого должна быть выполнена операция на сервере. +* Для команды `{{ ydb-cli }} import file` добавлен параметр [--timeout](reference/ydb-cli/export-import/import-file.md#optional), задающий время, в течение которого должна быть выполнена операция на сервере. * Добавлен индикатор прогресса в командах [ydb scheme rmdir --recursive](reference/ydb-cli/commands/dir.md#rmdir) и [ydb import file](reference/ydb-cli/export-import/import-file.md). * Добавлена команда [ydb workload kv run read-rows](reference/ydb-cli/workload-kv.md#read-rows-kv), которая нагружает базу запросами на чтение строк, используя новый экспериментальный API вызов ReadRows (реализован только в ветке [main](https://github.com/ydb-platform/ydb)), выполняющий более быстрое чтение по ключу, чем [select](reference/ydb-cli/workload-kv.md#select-kv). * В [ydb workload topic](reference/ydb-cli/workload-topic.md) добавлены новые параметры `--warmup-time`, `--percentile`, `--topic`, задающие время прогрева теста, процентиль в выводе статистики и имя топика соответственно. @@ -229,7 +257,7 @@ ### Производительность -* Увеличена скорость загрузки данных в команде `ydb import file` за счет добавления параллельной загрузки. Число потоков задается новым параметром [--threads](reference/ydb-cli/export-import/import-file.md#optional). +* Увеличена скорость загрузки данных в команде `{{ ydb-cli }} import file` за счет добавления параллельной загрузки. Число потоков задается новым параметром [--threads](reference/ydb-cli/export-import/import-file.md#optional). * Увеличена производительность команды [ydb import file json](reference/ydb-cli/export-import/import-file.md), за счет уменьшения числа копирований данных. ## Версия 2.4.0 {#2-4-0} @@ -250,16 +278,16 @@ * Добавлен интерактивный режим выполнения запросов. Для перехода в интерактивный режим выполните команду [ydb yql](reference/ydb-cli/yql.md) без аргументов. Режим экспериментальный, обратная совместимость пока не гарантируется. * Добавлена команда [ydb index rename](reference/ydb-cli/commands/secondary_index.md#rename) для [атомарной замены](dev/secondary-indexes.md#atomic-index-replacement) или переименования вторичного индекса. -* Добавлена команда `ydb workload topic` для запуска нагрузки, которая читает и записывает сообщения в топики. -* Для команды `ydb scheme rmdir` добавлен параметр [--recursive](reference/ydb-cli/commands/dir.md#rmdir-options), который позволяет рекурсивно удалить директорию вместе со всем содержимым. +* Добавлена команда `{{ ydb-cli }} workload topic` для запуска нагрузки, которая читает и записывает сообщения в топики. +* Для команды `{{ ydb-cli }} scheme rmdir` добавлен параметр [--recursive](reference/ydb-cli/commands/dir.md#rmdir-options), который позволяет рекурсивно удалить директорию вместе со всем содержимым. * Для команды [ydb scheme describe](reference/ydb-cli/commands/scheme-describe.md) добавлена поддержка типов `topic` и `coordination node`. -* Для команды `ydb topic consumer` добавлен параметр [--commit](reference/ydb-cli/topic-read.md#osnovnye-opcionalnye-parametry) для подтверждения прочитанных сообщений. -* Для команды `ydb import file csv|tsv` добавлен параметр [--columns](reference/ydb-cli/export-import/import-file.md#optional), с помощью которого можно указать список колонок вместо заголовка в файле. -* Для команды `ydb import file csv|tsv` добавлен параметр [--newline-delimited](reference/ydb-cli/export-import/import-file.md#optional), который подтверждает отсутствие символа переноса строки в данных. Использование этого параметра ускоряет импорт за счет параллельного чтения из нескольких секций файла. +* Для команды `{{ ydb-cli }} topic consumer` добавлен параметр [--commit](reference/ydb-cli/topic-read.md#osnovnye-opcionalnye-parametry) для подтверждения прочитанных сообщений. +* Для команды `{{ ydb-cli }} import file csv|tsv` добавлен параметр [--columns](reference/ydb-cli/export-import/import-file.md#optional), с помощью которого можно указать список колонок вместо заголовка в файле. +* Для команды `{{ ydb-cli }} import file csv|tsv` добавлен параметр [--newline-delimited](reference/ydb-cli/export-import/import-file.md#optional), который подтверждает отсутствие символа переноса строки в данных. Использование этого параметра ускоряет импорт за счет параллельного чтения из нескольких секций файла. ### Исправления ошибок -* Исправлена ошибка, которая приводила к повышенному потреблению памяти и процессора при выполнении команды `ydb import file`. +* Исправлена ошибка, которая приводила к повышенному потреблению памяти и процессора при выполнении команды `{{ ydb-cli }} import file`. ## Версия 2.2.0 {#2-2-0} @@ -297,7 +325,7 @@ * URL сервиса IAM теперь можно сохранять в профиле. * Добавлена возможность использовать аутентификацию по логину и паролю без указания пароля. * Добавлена поддержка профилей AWS в команде [ydb export s3](reference/ydb-cli/export-import/auth-s3.md#auth). -* Добавлена возможность создания профиля используя `stdin`. Например, можно передать вывод команды [YC CLI](https://cloud.yandex.ru/docs/cli/) `yc ydb database get information` на вход команде `ydb config profile create`. +* Добавлена возможность создания профиля используя `stdin`. Например, можно передать вывод команды [YC CLI](https://cloud.yandex.ru/docs/cli/) `yc ydb database get information` на вход команде `{{ ydb-cli }} config profile create`. ### Исправления ошибок @@ -312,25 +340,25 @@ * Добавлена возможность работы с топиками: - * `ydb topic create` — создание топика; - * `ydb topic alter` — изменение топика; - * `ydb topic write` — запись данных в топик; - * `ydb topic read` — чтение данных из топика; - * `ydb topic drop` — удаление топика. + * `{{ ydb-cli }} topic create` — создание топика; + * `{{ ydb-cli }} topic alter` — изменение топика; + * `{{ ydb-cli }} topic write` — запись данных в топик; + * `{{ ydb-cli }} topic read` — чтение данных из топика; + * `{{ ydb-cli }} topic drop` — удаление топика. * Добавлен новый тип нагрузочного тестирования: - * `ydb workload kv init` — создание таблицы для тестирования kv нагрузки; - * `ydb workload kv run` — запуск одной из 3 видов нагрузки: запуск нескольких сессий вставки `UPSERT`, запуск нескольких сессий вставки `INSERT` или запуск нескольких сессий с GET-запросами по первичному ключу; - * `ydb workload kv clean` — удаление тестовой таблицы. - -* Добавлена возможность деактивировать текущий активный профиль (см. команду `ydb config profile deactivate`). -* Добавлена возможность неинтерактивного удаления профиля без подтверждения (см. параметр `--force` команды `ydb config profile remove`). -* Добавлена поддержка CDC для команды `ydb scheme describe`. -* Добавлена возможность просмотра текущего статуса БД (см. команду `ydb monitoring healthcheck`). -* Добавлена возможность просмотра аутентификационной информации (токена), с которой будут отправляться запросы к БД при текущих настройках аутентификации (см. команду `ydb auth get-token`). -* Добавлена возможность чтения данных из стандартного потока ввода для команды `ydb import`. -* Добавлена возможность импорта данных в формате JSON из файла или стандартного потока ввода (см. команду `ydb import file json`). + * `{{ ydb-cli }} workload kv init` — создание таблицы для тестирования kv нагрузки; + * `{{ ydb-cli }} workload kv run` — запуск одной из 3 видов нагрузки: запуск нескольких сессий вставки `UPSERT`, запуск нескольких сессий вставки `INSERT` или запуск нескольких сессий с GET-запросами по первичному ключу; + * `{{ ydb-cli }} workload kv clean` — удаление тестовой таблицы. + +* Добавлена возможность деактивировать текущий активный профиль (см. команду `{{ ydb-cli }} config profile deactivate`). +* Добавлена возможность неинтерактивного удаления профиля без подтверждения (см. параметр `--force` команды `{{ ydb-cli }} config profile remove`). +* Добавлена поддержка CDC для команды `{{ ydb-cli }} scheme describe`. +* Добавлена возможность просмотра текущего статуса БД (см. команду `{{ ydb-cli }} monitoring healthcheck`). +* Добавлена возможность просмотра аутентификационной информации (токена), с которой будут отправляться запросы к БД при текущих настройках аутентификации (см. команду `{{ ydb-cli }} auth get-token`). +* Добавлена возможность чтения данных из стандартного потока ввода для команды `{{ ydb-cli }} import`. +* Добавлена возможность импорта данных в формате JSON из файла или стандартного потока ввода (см. команду `{{ ydb-cli }} import file json`). ### Улучшения diff --git a/ydb/docs/ru/core/downloads/_includes/ydb-cli/darwin_amd64.md b/ydb/docs/ru/core/downloads/_includes/ydb-cli/darwin_amd64.md index 1e0eca02b20b..83ebb1e0402c 100644 --- a/ydb/docs/ru/core/downloads/_includes/ydb-cli/darwin_amd64.md +++ b/ydb/docs/ru/core/downloads/_includes/ydb-cli/darwin_amd64.md @@ -1,6 +1,7 @@ Используйте бинарный файл amd64, если ваш Mac на базе процессора Intel. Версия | Дата выпуска | Скачать | Список изменений :--- | :--- | :--- | :--- +v.2.20.0 | 05.03.2025 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.20.0/darwin/amd64/ydb) | [См. список](../../../changelog-cli.md#2-20-0) v.2.19.0 | 05.02.2025 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.19.0/darwin/amd64/ydb) | [См. список](../../../changelog-cli.md#2-19-0) v.2.18.0 | 24.12.24 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.18.0/darwin/amd64/ydb) | [См. список](../../../changelog-cli.md#2-18-0) v.2.17.0 | 04.12.24 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.17.0/darwin/amd64/ydb) | [См. список](../../../changelog-cli.md#2-17-0) diff --git a/ydb/docs/ru/core/downloads/_includes/ydb-cli/darwin_arm64.md b/ydb/docs/ru/core/downloads/_includes/ydb-cli/darwin_arm64.md index 2e4f1eaf980e..de14fc831bbb 100644 --- a/ydb/docs/ru/core/downloads/_includes/ydb-cli/darwin_arm64.md +++ b/ydb/docs/ru/core/downloads/_includes/ydb-cli/darwin_arm64.md @@ -1,6 +1,7 @@ Используйте бинарный файл arm64, если ваш Mac на базе процессора Apple Silicon (M1, M2 или более поздние). Версия | Дата выпуска | Скачать | Список изменений :--- | :--- | :--- | :--- +v.2.20.0 | 05.03.2025 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.20.0/darwin/arm64/ydb) | [См. список](../../../changelog-cli.md#2-20-0) v.2.19.0 | 05.02.2025 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.19.0/darwin/arm64/ydb) | [См. список](../../../changelog-cli.md#2-19-0) v.2.18.0 | 24.12.24 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.18.0/darwin/arm64/ydb) | [См. список](../../../changelog-cli.md#2-18-0) v.2.17.0 | 04.12.24 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.17.0/darwin/arm64/ydb) | [См. список](../../../changelog-cli.md#2-17-0) diff --git a/ydb/docs/ru/core/downloads/_includes/ydb-cli/linux_amd64.md b/ydb/docs/ru/core/downloads/_includes/ydb-cli/linux_amd64.md index 09f9bda19b3c..8cd5df33429f 100644 --- a/ydb/docs/ru/core/downloads/_includes/ydb-cli/linux_amd64.md +++ b/ydb/docs/ru/core/downloads/_includes/ydb-cli/linux_amd64.md @@ -1,5 +1,6 @@ Версия | Дата выпуска | Скачать | Список изменений :--- | :--- | :--- | :--- +v.2.20.0 | 05.03.2025 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.20.0/linux/amd64/ydb) | [См. список](../../../changelog-cli.md#2-20-0) v.2.19.0 | 05.02.2025 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.19.0/linux/amd64/ydb) | [См. список](../../../changelog-cli.md#2-19-0) v.2.18.0 | 24.12.24 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.18.0/linux/amd64/ydb) | [См. список](../../../changelog-cli.md#2-18-0) v.2.17.0 | 04.12.24 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.17.0/linux/amd64/ydb) | [См. список](../../../changelog-cli.md#2-17-0) diff --git a/ydb/docs/ru/core/downloads/_includes/ydb-cli/linux_arm64.md b/ydb/docs/ru/core/downloads/_includes/ydb-cli/linux_arm64.md index 6fc69fee842c..df2ee3d612af 100644 --- a/ydb/docs/ru/core/downloads/_includes/ydb-cli/linux_arm64.md +++ b/ydb/docs/ru/core/downloads/_includes/ydb-cli/linux_arm64.md @@ -1,5 +1,6 @@ Версия | Дата выпуска | Скачать | Список изменений :--- | :--- | :--- | :--- +v.2.20.0 | 05.03.2025 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.20.0/linux/arm64/ydb) | [См. список](../../../changelog-cli.md#2-20-0) v.2.19.0 | 05.02.2025 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.19.0/linux/arm64/ydb) | [См. список](../../../changelog-cli.md#2-19-0) v.2.18.0 | 24.12.24 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.18.0/linux/arm64/ydb) | [См. список](../../../changelog-cli.md#2-18-0) v.2.17.0 | 04.12.24 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.17.0/linux/arm64/ydb) | [См. список](../../../changelog-cli.md#2-17-0) diff --git a/ydb/docs/ru/core/downloads/_includes/ydb-cli/windows.md b/ydb/docs/ru/core/downloads/_includes/ydb-cli/windows.md index fca7f1191a4e..25adc1332b24 100644 --- a/ydb/docs/ru/core/downloads/_includes/ydb-cli/windows.md +++ b/ydb/docs/ru/core/downloads/_includes/ydb-cli/windows.md @@ -1,5 +1,6 @@ Версия | Дата выпуска | Скачать | Список изменений :--- | :--- | :--- | :--- +v.2.20.0 | 05.03.2025 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.20.0/windows/amd64/ydb.exe) | [См. список](../../../changelog-cli.md#2-20-0) v.2.19.0 | 05.02.2025 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.19.0/windows/amd64/ydb.exe) | [См. список](../../../changelog-cli.md#2-19-0) v.2.18.0 | 24.12.24 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.18.0/windows/amd64/ydb.exe) | [См. список](../../../changelog-cli.md#2-18-0) v.2.17.0 | 04.12.24 | [Бинарный файл](https://storage.yandexcloud.net/yandexcloud-ydb/release/2.17.0/windows/amd64/ydb.exe) | [См. список](../../../changelog-cli.md#2-17-0) From 16c65bcbc0aa2ece592c166514640bf3a725f2f5 Mon Sep 17 00:00:00 2001 From: Alexander Alexeev Date: Tue, 8 Apr 2025 09:25:07 +0200 Subject: [PATCH 034/454] EnableSharedMetadataCache true by default --- ydb/core/protos/feature_flags.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ydb/core/protos/feature_flags.proto b/ydb/core/protos/feature_flags.proto index 274fe908e46e..55666ce0a053 100644 --- a/ydb/core/protos/feature_flags.proto +++ b/ydb/core/protos/feature_flags.proto @@ -206,5 +206,5 @@ message TFeatureFlags { optional bool SwitchToConfigV1 = 180 [default = false]; optional bool EnableEncryptedExport = 181 [default = false]; optional bool EnableAlterDatabase = 182 [default = false]; - optional bool EnableSharedMetadataCache = 183 [default = false]; + optional bool EnableSharedMetadataCache = 183 [default = true]; } From e4f0cbe480a006a41f3379b7493455cc0ab8a911 Mon Sep 17 00:00:00 2001 From: Alexander Alexeev Date: Tue, 8 Apr 2025 09:25:36 +0200 Subject: [PATCH 035/454] Change SharedMetadat actor pool --- ydb/core/driver_lib/run/kikimr_services_initializers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ydb/core/driver_lib/run/kikimr_services_initializers.cpp b/ydb/core/driver_lib/run/kikimr_services_initializers.cpp index 76ddba5a51cf..8dc7876ef4e9 100644 --- a/ydb/core/driver_lib/run/kikimr_services_initializers.cpp +++ b/ydb/core/driver_lib/run/kikimr_services_initializers.cpp @@ -1122,7 +1122,7 @@ void TSharedMetadaCacheInitializer::InitializeServices( NActors::TActorSystemSet if (appData->FeatureFlags.GetEnableSharedMetadataCache()) { auto* actor = NKikimr::NOlap::NDataAccessorControl::TNodeActor::CreateActor(); setup->LocalServices.emplace_back(NKikimr::NOlap::NDataAccessorControl::TNodeActor::MakeActorId(NodeId), - TActorSetupCmd(actor, TMailboxType::ReadAsFilled, appData->IOPoolId)); + TActorSetupCmd(actor, TMailboxType::HTSwap, appData->UserPoolId)); } } From 85e362e7ecbd47526a47f256e21442c8b23b4c59 Mon Sep 17 00:00:00 2001 From: Hor911 Date: Tue, 8 Apr 2025 10:32:13 +0300 Subject: [PATCH 036/454] New look: dimmed color shades, stage metric icons and little column adjusting (#16830) --- ydb/public/lib/ydb_cli/common/plan2svg.cpp | 189 ++++++++++++++++----- ydb/public/lib/ydb_cli/common/plan2svg.h | 26 ++- 2 files changed, 163 insertions(+), 52 deletions(-) diff --git a/ydb/public/lib/ydb_cli/common/plan2svg.cpp b/ydb/public/lib/ydb_cli/common/plan2svg.cpp index 374d602bd9e5..9e7d55ba8201 100644 --- a/ydb/public/lib/ydb_cli/common/plan2svg.cpp +++ b/ydb/public/lib/ydb_cli/common/plan2svg.cpp @@ -842,13 +842,13 @@ void TPlan::LoadStage(std::shared_ptr stage, const NJson::TJsonValue& no auto& ingress0 = (*ingressTopNode)[0]; if (auto* externalNode = ingress0.GetValueByPath("External")) { if (auto* externalBytesNode = externalNode->GetValueByPath("ExternalBytes")) { - externalStage->OutputBytes = std::make_shared(ExternalBytes, *externalBytesNode, 0, 0, + externalStage->EgressBytes = std::make_shared(ExternalBytes, *externalBytesNode, 0, 0, externalNode->GetValueByPath("FirstMessageMs"), externalNode->GetValueByPath("LastMessageMs") ); } if (auto* externalRowsNode = externalNode->GetValueByPath("ExternalRows")) { - externalStage->OutputRows = std::make_shared(ExternalRows, *externalRowsNode); + externalStage->EgressRows = std::make_shared(ExternalRows, *externalRowsNode); externalStage->Operators.front().OutputRows = std::make_shared(OperatorOutputRows, *externalRowsNode); } if (auto* partitionCountNode = externalNode->GetValueByPath("PartitionCount")) { @@ -931,6 +931,8 @@ void TPlan::LoadStage(std::shared_ptr stage, const NJson::TJsonValue& no inputNode = stage->StatsNode->GetValueByPath("Input"); } + ui64 inputBytes = 0; + if (auto* subNode = node.GetValueByPath("Plans")) { for (auto& plan : subNode->GetArray()) { TString subNodeType; @@ -1030,6 +1032,7 @@ void TPlan::LoadStage(std::shared_ptr stage, const NJson::TJsonValue& no ); Min0(stage->MinTime, connection->InputBytes->MinTime); Max0(stage->MaxTime, connection->InputBytes->MaxTime); + inputBytes += connection->InputBytes->Details.Sum; } if (auto* rowsNode = pushNode->GetValueByPath("Rows")) { connection->InputRows = std::make_shared(InputRows, *rowsNode); @@ -1180,13 +1183,21 @@ void TPlan::LoadStage(std::shared_ptr stage, const NJson::TJsonValue& no } } + if (stage->IngressBytes) { + inputBytes += stage->IngressBytes->Details.Sum; + } auto stageDuration = stage->MaxTime - stage->MinTime; + if (stageDuration && inputBytes) { + stage->InputThroughput = std::make_shared(StageInputThroughput, inputBytes * 1000 / stageDuration); + } + for (auto i = 0u; i < stage->Operators.size(); i++) { auto& op = stage->Operators[i]; if (!op.InputRows && i + 1 < stage->Operators.size()) { op.InputRows = stage->Operators[i + 1].OutputRows; } + /* if (stageDuration) { if (op.OutputRows) { op.OutputThroughput = std::make_shared(OperatorOutputThroughput, op.OutputRows->Details.Sum * 1000 / stageDuration); @@ -1199,6 +1210,7 @@ void TPlan::LoadStage(std::shared_ptr stage, const NJson::TJsonValue& no op.InputThroughput = std::make_shared(OperatorInputThroughput, sum * 1000 / stageDuration); } } + */ } Max0(MaxTime, stage->MaxTime); @@ -1257,7 +1269,10 @@ void TPlan::MarkStageIndent(ui32 indent, ui32& offsetY, std::shared_ptr stage->OffsetY = offsetY; ui32 height = std::max( - (3 /* Output, MEM, CPU*/ + stage->Connections.size() + stage->BuiltInIngress) * (INTERNAL_HEIGHT + INTERNAL_GAP_Y) + INTERNAL_GAP_Y, + ( (stage->EgressBytes != nullptr) + (stage->OutputBytes != nullptr) + + 2 /* MEM, CPU */ + + stage->Connections.size() + stage->BuiltInIngress + ) * (INTERNAL_HEIGHT + INTERNAL_GAP_Y) + INTERNAL_GAP_Y, stage->Operators.size() * (INTERNAL_TEXT_HEIGHT + INTERNAL_GAP_Y) * 2 - INTERNAL_GAP_Y + (INTERNAL_HEIGHT - INTERNAL_TEXT_HEIGHT)); stage->Height = height; @@ -1424,9 +1439,13 @@ void TPlan::PrintValues(TStringBuilder& canvas, std::shared_ptr m } } -void TPlan::PrintStageSummary(TStringBuilder& background, TStringBuilder&, ui32 viewLeft, ui32 viewWidth, ui32 y0, ui32 h, std::shared_ptr metric, const TString& mediumColor, const TString& lightColor, const TString& textSum, const TString& tooltip, ui32 taskCount) { +void TPlan::PrintStageSummary(TStringBuilder& background, TStringBuilder&, ui32 viewLeft, ui32 viewWidth, ui32 y0, ui32 h, std::shared_ptr metric, const TString& mediumColor, const TString& lightColor, const TString& textSum, const TString& tooltip, ui32 taskCount, const TString& iconRef, const TString& iconScale) { ui32 x0 = viewLeft + INTERNAL_GAP_X; ui32 width = viewWidth - INTERNAL_GAP_X * 2; + if (iconRef) { + x0 += INTERNAL_WIDTH; + width -= INTERNAL_WIDTH; + } if (metric->Summary && metric->Summary->Max) { width = metric->Details.Sum * width / metric->Summary->Max; } @@ -1434,6 +1453,10 @@ void TPlan::PrintStageSummary(TStringBuilder& background, TStringBuilder&, ui32 background << "" << tooltip << "" << Endl; } + if (iconRef) { + background + << "" << Endl; + } if (metric->Details.Max) { auto wavg = width / 2; if (metric->Details.Max > metric->Details.Min) { @@ -1583,21 +1606,21 @@ void TPlan::PrintSvg(ui64 maxTime, ui32& offsetY, TStringBuilder& background, TS << "px' fill='" << Config.Palette.StageText << "' x='" << Config.HeaderLeft + s->IndentX + INTERNAL_WIDTH + 2 + 4 << "' y='" << y0 + INTERNAL_TEXT_HEIGHT * 2 + INTERNAL_GAP_Y << "'>" << op.Info << "" << "" << Endl; - +/* if (op.OutputThroughput) { TStringBuilder tooltip; tooltip << "Output Throughput " << FormatInteger(op.OutputThroughput->Details.Sum) << "/s"; - PrintStageSummary(background, canvas, Config.OperatorLeft, Config.OperatorWidth, y0, INTERNAL_TEXT_HEIGHT + INTERNAL_GAP_Y, op.OutputThroughput, Config.Palette.CpuMedium, Config.Palette.CpuLight, "", tooltip, 0); + PrintStageSummary(background, canvas, Config.OperatorLeft, Config.OperatorWidth, y0, INTERNAL_TEXT_HEIGHT + INTERNAL_GAP_Y, op.OutputThroughput, Config.Palette.CpuMedium, Config.Palette.CpuLight, "", tooltip, 0, "", ""); } if (op.InputThroughput) { TStringBuilder tooltip; tooltip << "Input Throughput " << FormatInteger(op.InputThroughput->Details.Sum) << "/s"; - PrintStageSummary(background, canvas, Config.OperatorLeft, Config.OperatorWidth, y0 + (INTERNAL_TEXT_HEIGHT + INTERNAL_GAP_Y) * 2 - (INTERNAL_TEXT_HEIGHT + INTERNAL_GAP_Y), INTERNAL_TEXT_HEIGHT + INTERNAL_GAP_Y, op.InputThroughput, Config.Palette.CpuMedium, Config.Palette.CpuLight, "", tooltip, 0); + PrintStageSummary(background, canvas, Config.OperatorLeft, Config.OperatorWidth, y0 + (INTERNAL_TEXT_HEIGHT + INTERNAL_GAP_Y) * 2 - (INTERNAL_TEXT_HEIGHT + INTERNAL_GAP_Y), INTERNAL_TEXT_HEIGHT + INTERNAL_GAP_Y, op.InputThroughput, Config.Palette.CpuMedium, Config.Palette.CpuLight, "", tooltip, 0, "", ""); } - +*/ if (op.OutputRows) { TStringBuilder tooltip; auto textSum = FormatTooltip(tooltip, "Output Rows", op.OutputRows.get(), FormatInteger); @@ -1605,7 +1628,7 @@ void TPlan::PrintSvg(ui64 maxTime, ui32& offsetY, TStringBuilder& background, TS tooltip << ", " << op.Estimations; } - PrintStageSummary(background, canvas, Config.OperatorLeft, Config.OperatorWidth, y0 + (INTERNAL_TEXT_HEIGHT + INTERNAL_GAP_Y) - INTERNAL_HEIGHT / 2, INTERNAL_HEIGHT, op.OutputRows, Config.Palette.OutputMedium, Config.Palette.OutputLight, textSum, tooltip, taskCount); + PrintStageSummary(background, canvas, Config.OperatorLeft, Config.OperatorWidth, y0 + (INTERNAL_TEXT_HEIGHT + INTERNAL_GAP_Y) - INTERNAL_HEIGHT / 2, INTERNAL_HEIGHT, op.OutputRows, Config.Palette.OutputMedium, Config.Palette.OutputLight, textSum, tooltip, taskCount, "", ""); } y0 += (INTERNAL_TEXT_HEIGHT + INTERNAL_GAP_Y) * 2; } @@ -1629,11 +1652,11 @@ void TPlan::PrintSvg(ui64 maxTime, ui32& offsetY, TStringBuilder& background, TS << "Stage " << s->PhysicalStageId << ", tasks: " << s->Tasks << ", finished: " << s->FinishedTasks << "" << Endl; if (s->FinishedTasks && s->FinishedTasks <= s->Tasks) { auto finishedHeight = s->Height * s->FinishedTasks / s->Tasks; - auto xx = Config.TaskLeft + Config.TaskWidth - Config.TaskWidth / 8; + auto xx = Config.TaskLeft + Config.TaskWidth / 8; canvas << "" << Endl; + << "' stroke-width='" << Config.TaskWidth / 4 << "' stroke='" << Config.Palette.StageText << "' stroke-dasharray='1,1' />" << Endl; } canvas << " " << Endl + << "" << Endl; + } + if (!s->CpuTime->History.Deriv.empty() && s->CpuTime->History.MaxTime > s->CpuTime->History.MinTime) { auto maxCpu = s->CpuTime->History.MaxDeriv * TIME_SERIES_RANGES / (s->CpuTime->History.MaxTime - s->CpuTime->History.MinTime); PrintDeriv(canvas, s->CpuTime->History, px, y0, pw, INTERNAL_HEIGHT, "Max CPU " + FormatMCpu(maxCpu), Config.Palette.CpuMedium, Config.Palette.CpuLight); @@ -1873,7 +1940,7 @@ void TPlan::PrintSvg(ui64 maxTime, ui32& offsetY, TStringBuilder& background, TS tooltip << ", Width " << FormatBytes(c->CteOutputRows->Details.Sum / c->CteOutputRows->Details.Sum); } } - PrintStageSummary(background, canvas, Config.SummaryLeft, Config.SummaryWidth, y + INTERNAL_GAP_Y, INTERNAL_HEIGHT, c->CteOutputBytes, Config.Palette.OutputMedium, Config.Palette.OutputLight, textSum, tooltip, 0); + PrintStageSummary(background, canvas, Config.SummaryLeft, Config.SummaryWidth, y + INTERNAL_GAP_Y, INTERNAL_HEIGHT, c->CteOutputBytes, Config.Palette.OutputMedium, Config.Palette.OutputLight, textSum, tooltip, 0, "#icon_output", "0.9 0.9"); auto d = c->CteOutputBytes->MaxTime - c->CteOutputBytes->MinTime; TStringBuilder title; @@ -1963,7 +2030,7 @@ void TPlan::PrintSvg(ui64 maxTime, ui32& offsetY, TStringBuilder& background, TS tooltip << ", Width " << FormatBytes(c->InputBytes->Details.Sum / c->InputRows->Details.Sum); } } - PrintStageSummary(background, canvas, Config.SummaryLeft, Config.SummaryWidth, y0, INTERNAL_HEIGHT, c->InputBytes, Config.Palette.InputMedium, Config.Palette.InputLight, textSum, tooltip, taskCount); + PrintStageSummary(background, canvas, Config.SummaryLeft, Config.SummaryWidth, y0, INTERNAL_HEIGHT, c->InputBytes, Config.Palette.InputMedium, Config.Palette.InputLight, textSum, tooltip, taskCount, "#icon_input", "0.9 0.9"); auto d = c->InputBytes->MaxTime - c->InputBytes->MinTime; TStringBuilder title; @@ -1997,7 +2064,7 @@ void TPlan::PrintSvg(ui64 maxTime, ui32& offsetY, TStringBuilder& background, TS tooltip << ", Width " << FormatBytes(s->IngressBytes->Details.Sum / s->IngressRows->Details.Sum); } } - PrintStageSummary(background, canvas, Config.SummaryLeft, Config.SummaryWidth, y0, INTERNAL_HEIGHT, s->IngressBytes, Config.Palette.IngressMedium, Config.Palette.IngressLight, textSum, tooltip, taskCount); + PrintStageSummary(background, canvas, Config.SummaryLeft, Config.SummaryWidth, y0, INTERNAL_HEIGHT, s->IngressBytes, Config.Palette.IngressMedium, Config.Palette.IngressLight, textSum, tooltip, taskCount, "#icon_input", "0.9 0.9"); auto d = s->IngressBytes->MaxTime - s->IngressBytes->MinTime; TStringBuilder title; @@ -2029,21 +2096,28 @@ TColorPalette::TColorPalette() { StageMain = "var(--stage-main, #F2F2F2)"; StageClone = "var(--stage-clone, #D9D9D9)"; StageText = "var(--stage-text, #262626)"; - StageTextHighlight = "var(--stage-texthl, #EA0703)"; + StageTextHighlight = "var(--stage-texthl, #FC2824)"; StageGrid = "var(--stage-grid, #B2B2B2)"; - IngressDark = "var(--ingress-dark, #574F38)"; - IngressMedium = "var(--ingress-medium, #82723C)"; - IngressLight = "var(--ingress-light, #C0A645)"; - InputDark = "var(--input-dark, #315B34)"; - InputMedium = "var(--input-medium, #379A33)"; - InputLight = "var(--input-light, #3AC936)"; - OutputDark = "var(--output-dark, #3F5799)"; - OutputMedium = "var(--output-medium, #4E79EB)"; - OutputLight = "var(--output-light, #86A8FF)"; - MemMedium = "var(--mem-medium, #543B70)"; - MemLight = "var(--mem-light, #854EBD)"; - CpuMedium = "var(--cpu-medium, #EA0703)"; - CpuLight = "var(--cpu-light, #FF6866)"; + + IngressDark = "var(--ingress-dark, #384F50)"; + IngressMedium = "var(--ingress-medium, #466364)"; + IngressLight = "var(--ingress-light, #5A8183)"; + InputDark = "var(--input-dark, #466364)"; + InputMedium = "var(--input-medium, #5A8183)"; + InputLight = "var(--input-light, #7CA3A5)"; + + EgressDark = "var(--egress-dark, #2D486C)"; + EgressMedium = "var(--egress-medium, #3C6090)"; + EgressLight = "var(--egress-light, #4B78B4)"; + OutputDark = "var(--output-dark, #41689C)"; + OutputMedium = "var(--output-medium, #5781B9)"; + OutputLight = "var(--output-light, #6F93C3)"; + + MemMedium = "var(--mem-medium, #7E4E5B)"; + MemLight = "var(--mem-light, #AA7785)"; + CpuMedium = "var(--cpu-medium, #A36D7B)"; + CpuLight = "var(--cpu-light, #B78C98)"; + ConnectionFill= "var(--conn-fill, #BFBFBF)"; ConnectionLine= "var(--conn-line, #BFBFBF)"; ConnectionText= "var(--conn-text, #393939)"; @@ -2051,12 +2125,13 @@ TColorPalette::TColorPalette() { TextLight = "var(--text-light, #FFFFFF)"; TextInverted = "var(--text-inv, #FFFFFF)"; TextSummary = "var(--text-summary, #262626)"; - SpillingBytesDark = "var(--spill-dark, #406B61)"; - SpillingBytesMedium = "var(--spill-medium, #599587)"; - SpillingBytesLight = "var(--spill-light, #72C0AE)"; - SpillingTimeDark = "var(--spill-dark, #406B61)"; - SpillingTimeMedium = "var(--spill-medium, #599587)"; - SpillingTimeLight = "var(--spill-light, #72C0AE)"; + + SpillingBytesDark = "var(--spill-dark, #CC9700)"; + SpillingBytesMedium = "var(--spill-medium, #FFC522)"; + SpillingBytesLight = "var(--spill-light, #FFD766)"; + SpillingTimeDark = "var(--spill-dark, #CC9700)"; + SpillingTimeMedium = "var(--spill-medium, #FFC522)"; + SpillingTimeLight = "var(--spill-light, #FFD766)"; } TPlanViewConfig::TPlanViewConfig() { @@ -2064,12 +2139,12 @@ TPlanViewConfig::TPlanViewConfig() { HeaderLeft = 0; HeaderWidth = 300 - INTERNAL_GAP_X; OperatorLeft = HeaderLeft + HeaderWidth + GAP_X; - OperatorWidth = 128; - SummaryLeft = OperatorLeft + OperatorWidth + GAP_X; - SummaryWidth = 128; - TaskLeft = SummaryLeft + SummaryWidth + GAP_X; + OperatorWidth = 64; + TaskLeft = OperatorLeft + OperatorWidth + GAP_X; TaskWidth = 24; - TimelineLeft = TaskLeft + TaskWidth + GAP_X; + SummaryLeft = TaskLeft + TaskWidth + GAP_X; + SummaryWidth = 200; + TimelineLeft = SummaryLeft + SummaryWidth + GAP_X; TimelineWidth = Width - TimelineLeft; } @@ -2229,6 +2304,30 @@ TString TPlanVisualizer::PrintSvg() { svg << "" << "" << Endl; + svg << R"( + + + + + + + + + + + + + + + + + + + + + + +)"; svg << TString(background) << Endl; { diff --git a/ydb/public/lib/ydb_cli/common/plan2svg.h b/ydb/public/lib/ydb_cli/common/plan2svg.h index d452c1e49223..9306f5347c1c 100644 --- a/ydb/public/lib/ydb_cli/common/plan2svg.h +++ b/ydb/public/lib/ydb_cli/common/plan2svg.h @@ -150,6 +150,9 @@ class TStage { bool BuiltInIngress = false; std::shared_ptr IngressBytes; std::shared_ptr IngressRows; + std::shared_ptr EgressBytes; + std::shared_ptr EgressRows; + std::shared_ptr InputThroughput; std::vector Operators; ui64 BaseTime = 0; ui32 PlanNodeId = 0; @@ -175,6 +178,9 @@ struct TColorPalette { TString InputDark; TString InputMedium; TString InputLight; + TString EgressDark; + TString EgressMedium; + TString EgressLight; TString OutputDark; TString OutputMedium; TString OutputLight; @@ -199,16 +205,16 @@ struct TColorPalette { struct TPlanViewConfig { TPlanViewConfig(); - ui32 HeaderWidth; ui32 HeaderLeft; - ui32 OperatorWidth; + ui32 HeaderWidth; ui32 OperatorLeft; - ui32 SummaryWidth; - ui32 SummaryLeft; - ui32 TaskWidth; + ui32 OperatorWidth; ui32 TaskLeft; - ui32 TimelineWidth; + ui32 TaskWidth; + ui32 SummaryLeft; + ui32 SummaryWidth; ui32 TimelineLeft; + ui32 TimelineWidth; ui32 Width; TColorPalette Palette; bool Simplified = false; @@ -224,6 +230,8 @@ class TPlan { WaitInputTime = std::make_shared(); WaitOutputTime = std::make_shared(); MaxMemoryUsage = std::make_shared(); + EgressBytes = std::make_shared(); + EgressRows = std::make_shared(); OutputBytes = std::make_shared(); OutputRows = std::make_shared(); InputBytes = std::make_shared(); @@ -240,6 +248,7 @@ class TPlan { OperatorOutputRows = std::make_shared(); OperatorInputThroughput = std::make_shared(); OperatorOutputThroughput = std::make_shared(); + StageInputThroughput = std::make_shared(); } void Load(const NJson::TJsonValue& node); @@ -252,7 +261,7 @@ class TPlan { void PrintWaitTime(TStringBuilder& canvas, std::shared_ptr metric, ui32 x, ui32 y, ui32 w, ui32 h, const TString& fillColor); void PrintDeriv(TStringBuilder& canvas, TMetricHistory& history, ui32 x, ui32 y, ui32 w, ui32 h, const TString& title, const TString& lineColor, const TString& fillColor = ""); void PrintValues(TStringBuilder& canvas, std::shared_ptr metric, ui32 x, ui32 y, ui32 w, ui32 h, const TString& title, const TString& lineColor, const TString& fillColor = ""); - void PrintStageSummary(TStringBuilder& background, TStringBuilder&, ui32 viewLeft, ui32 viewWidth, ui32 y0, ui32 h, std::shared_ptr metric, const TString& mediumColor, const TString& lightColor, const TString& textSum, const TString& tooltip, ui32 taskCount); + void PrintStageSummary(TStringBuilder& background, TStringBuilder&, ui32 viewLeft, ui32 viewWidth, ui32 y0, ui32 h, std::shared_ptr metric, const TString& mediumColor, const TString& lightColor, const TString& textSum, const TString& tooltip, ui32 taskCount, const TString& iconRef, const TString& iconScale); void PrintSvg(ui64 maxTime, ui32& offsetY, TStringBuilder& background, TStringBuilder& canvas); TString NodeType; std::vector> Stages; @@ -260,6 +269,8 @@ class TPlan { std::shared_ptr WaitInputTime; std::shared_ptr WaitOutputTime; std::shared_ptr MaxMemoryUsage; + std::shared_ptr EgressBytes; + std::shared_ptr EgressRows; std::shared_ptr OutputBytes; std::shared_ptr OutputRows; std::shared_ptr InputBytes; @@ -276,6 +287,7 @@ class TPlan { std::shared_ptr OperatorOutputRows; std::shared_ptr OperatorInputThroughput; std::shared_ptr OperatorOutputThroughput; + std::shared_ptr StageInputThroughput; std::vector TotalCpuTimes; std::vector TotalCpuValues; TMetricHistory TotalCpuTime; From 7a18199f121713027e60ca856a08c77d26fdf0a9 Mon Sep 17 00:00:00 2001 From: psydvl Date: Tue, 8 Apr 2025 10:36:14 +0300 Subject: [PATCH 037/454] go1.23 switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Переключение Go на 1.23 Тулчейн с исходниками положен в PR:7442346 commit_hash:a56e7228a1eab335f40c731dc6a103945515cd70 --- build/conf/go.conf | 2 +- .../go_tools/{go1.22.json => go1.23.json} | 14 +- build/mapping.conf.json | 10 + build/ya.conf.json | 4 +- .../src/crypto/internal/bigmod/nat_ppc64x.s | 51 - contrib/go/_std_1.22/src/crypto/tls/boring.go | 98 - .../go/_std_1.22/src/crypto/tls/notboring.go | 20 - contrib/go/_std_1.22/src/encoding/csv/fuzz.go | 70 - contrib/go/_std_1.22/src/go/types/alias.go | 90 - contrib/go/_std_1.22/src/go/types/errors.go | 400 ---- contrib/go/_std_1.22/src/go/types/util.go | 22 - .../src/internal/coverage/rtcov/rtcov.go | 34 - .../goexperiment/exp_allocheaders_off.go | 8 - .../goexperiment/exp_allocheaders_on.go | 8 - .../goexperiment/exp_exectracer2_off.go | 9 - .../goexperiment/exp_exectracer2_on.go | 9 - .../goexperiment/exp_pagetrace_off.go | 8 - .../internal/goexperiment/exp_pagetrace_on.go | 8 - .../_std_1.22/src/internal/intern/intern.go | 181 -- .../src/internal/poll/sendfile_linux.go | 59 - .../go/_std_1.22/src/internal/poll/strconv.go | 13 - .../src/internal/safefilepath/path.go | 21 - .../src/internal/safefilepath/path_other.go | 23 - .../src/internal/safefilepath/path_windows.go | 141 -- .../syscall/unix/at_sysnum_openbsd.go | 16 - .../syscall/unix/getentropy_darwin.go | 28 - .../internal/syscall/unix/getentropy_darwin.s | 9 - .../go/_std_1.22/src/math/big/arith_decl.go | 33 - .../go/_std_1.22/src/math/rand/v2/chacha8.go | 46 - .../_std_1.22/src/net/cgo_unix_cgo_darwin.go | 21 - .../net/http/internal/testcert/testcert.go | 65 - .../go/_std_1.22/src/net/netip/leaf_alts.go | 45 - .../go/_std_1.22/src/net/tcpsockopt_darwin.go | 25 - .../_std_1.22/src/net/tcpsockopt_dragonfly.go | 23 - .../_std_1.22/src/net/tcpsockopt_openbsd.go | 16 - .../_std_1.22/src/net/tcpsockopt_solaris.go | 32 - .../go/_std_1.22/src/net/tcpsockopt_unix.go | 24 - .../_std_1.22/src/net/tcpsockopt_windows.go | 29 - contrib/go/_std_1.22/src/os/endian_big.go | 9 - contrib/go/_std_1.22/src/os/endian_little.go | 9 - contrib/go/_std_1.22/src/os/error_posix.go | 18 - contrib/go/_std_1.22/src/os/exec.go | 180 -- contrib/go/_std_1.22/src/os/exec_unix.go | 104 - contrib/go/_std_1.22/src/os/path_windows.go | 216 -- .../go/_std_1.22/src/runtime/coverage/apis.go | 178 -- .../go/_std_1.22/src/runtime/coverage/dummy.s | 8 - .../go/_std_1.22/src/runtime/coverage/emit.go | 609 ------ .../_std_1.22/src/runtime/coverage/hooks.go | 42 - .../src/runtime/coverage/testsupport.go | 323 --- .../go/_std_1.22/src/runtime/coverage/ya.make | 13 - contrib/go/_std_1.22/src/runtime/covermeta.go | 72 - .../go/_std_1.22/src/runtime/debug/stack.go | 30 - contrib/go/_std_1.22/src/runtime/exithook.go | 69 - contrib/go/_std_1.22/src/runtime/lockrank.go | 212 -- contrib/go/_std_1.22/src/runtime/mbitmap.go | 775 ------- .../src/runtime/mbitmap_noallocheaders.go | 938 -------- .../src/runtime/msize_noallocheaders.go | 29 - .../_std_1.22/src/runtime/netpoll_windows.go | 161 -- .../go/_std_1.22/src/runtime/pagetrace_off.go | 28 - .../go/_std_1.22/src/runtime/pagetrace_on.go | 358 --- contrib/go/_std_1.22/src/runtime/time.go | 1144 ---------- .../go/_std_1.22/src/runtime/time_nofake.go | 32 - contrib/go/_std_1.22/src/runtime/trace.go | 1925 ----------------- contrib/go/_std_1.22/src/runtime/trace2map.go | 151 -- .../go/_std_1.22/src/runtime/trace2region.go | 62 - contrib/go/_std_1.22/src/runtime/typekind.go | 43 - contrib/go/_std_1.22/src/strings/compare.go | 28 - contrib/go/_std_1.22/src/sync/atomic/asm.s | 85 - contrib/go/_std_1.22/src/syscall/asan.go | 22 - contrib/go/_std_1.22/src/syscall/asan0.go | 19 - .../go/_std_1.22/src/syscall/endian_big.go | 9 - .../go/_std_1.22/src/syscall/endian_little.go | 9 - contrib/go/_std_1.22/src/syscall/msan.go | 22 - contrib/go/_std_1.22/src/syscall/msan0.go | 19 - contrib/go/_std_1.22/src/time/sleep.go | 178 -- contrib/go/_std_1.22/src/time/tick.go | 71 - .../x/crypto/internal/poly1305/bits_compat.go | 39 - .../x/crypto/internal/poly1305/bits_go1.13.go | 21 - .../src/bufio/bufio.go | 0 .../src/bufio/scan.go | 0 .../src/bufio/ya.make | 0 .../src/bytes/buffer.go | 16 +- .../src/bytes/bytes.go | 45 +- .../src/bytes/reader.go | 8 +- .../src/bytes/ya.make | 0 .../{_std_1.22 => _std_1.23}/src/cmp/cmp.go | 14 +- .../{_std_1.22 => _std_1.23}/src/cmp/ya.make | 0 .../src/compress/flate/deflate.go | 3 +- .../src/compress/flate/deflatefast.go | 0 .../src/compress/flate/dict_decoder.go | 0 .../src/compress/flate/huffman_bit_writer.go | 0 .../src/compress/flate/huffman_code.go | 0 .../src/compress/flate/inflate.go | 0 .../src/compress/flate/token.go | 0 .../src/compress/flate/ya.make | 0 .../src/compress/gzip/gunzip.go | 0 .../src/compress/gzip/gzip.go | 4 +- .../src/compress/gzip/ya.make | 0 .../src/container/heap/heap.go | 0 .../src/container/heap/ya.make | 0 .../src/container/list/list.go | 0 .../src/container/list/ya.make | 0 .../src/context/context.go | 14 +- .../src/context/ya.make | 0 .../src/crypto/aes/aes_gcm.go | 8 +- .../src/crypto/aes/asm_amd64.s | 2 + .../src/crypto/aes/asm_arm64.s | 2 + .../src/crypto/aes/asm_ppc64x.s | 8 +- .../src/crypto/aes/asm_s390x.s | 2 + .../src/crypto/aes/block.go | 38 +- .../src/crypto/aes/cbc_ppc64x.go | 6 +- .../src/crypto/aes/cbc_s390x.go | 2 + .../src/crypto/aes/cipher.go | 14 +- .../src/crypto/aes/cipher_asm.go | 15 +- .../src/crypto/aes/cipher_generic.go | 2 +- .../src/crypto/aes/cipher_s390x.go | 2 + .../src/crypto/aes/const.go | 0 .../src/crypto/aes/ctr_s390x.go | 12 +- .../src/crypto/aes/gcm_amd64.s | 2 + .../src/crypto/aes/gcm_arm64.s | 2 + .../src/crypto/aes/gcm_ppc64x.go | 29 +- .../src/crypto/aes/gcm_ppc64x.s | 2 +- .../src/crypto/aes/gcm_s390x.go | 18 +- .../src/crypto/aes/modes.go | 0 .../src/crypto/aes/ya.make | 0 .../src/crypto/boring/boring.go | 0 .../src/crypto/boring/ya.make | 0 .../src/crypto/cipher/cbc.go | 0 .../src/crypto/cipher/cfb.go | 0 .../src/crypto/cipher/cipher.go | 0 .../src/crypto/cipher/ctr.go | 0 .../src/crypto/cipher/gcm.go | 24 +- .../src/crypto/cipher/io.go | 0 .../src/crypto/cipher/ofb.go | 0 .../src/crypto/cipher/ya.make | 0 .../src/crypto/crypto.go | 0 .../src/crypto/des/block.go | 8 +- .../src/crypto/des/cipher.go | 10 +- .../src/crypto/des/const.go | 0 .../src/crypto/des/ya.make | 0 .../src/crypto/dsa/dsa.go | 0 .../src/crypto/dsa/ya.make | 0 .../src/crypto/ecdh/ecdh.go | 0 .../src/crypto/ecdh/nist.go | 4 +- .../src/crypto/ecdh/x25519.go | 0 .../src/crypto/ecdh/ya.make | 0 .../src/crypto/ecdsa/boring.go | 0 .../src/crypto/ecdsa/ecdsa.go | 11 +- .../src/crypto/ecdsa/ecdsa_legacy.go | 3 + .../src/crypto/ecdsa/ecdsa_noasm.go | 2 +- .../src/crypto/ecdsa/ecdsa_s390x.go | 2 + .../src/crypto/ecdsa/ecdsa_s390x.s | 2 + .../src/crypto/ecdsa/notboring.go | 0 .../src/crypto/ecdsa/ya.make | 0 .../src/crypto/ed25519/ed25519.go | 9 + .../src/crypto/ed25519/ya.make | 0 .../src/crypto/elliptic/elliptic.go | 0 .../src/crypto/elliptic/nistec.go | 0 .../src/crypto/elliptic/nistec_p256.go | 0 .../src/crypto/elliptic/params.go | 2 +- .../src/crypto/elliptic/ya.make | 0 .../src/crypto/hmac/hmac.go | 0 .../src/crypto/hmac/ya.make | 0 .../src/crypto/internal/alias/alias.go | 0 .../src/crypto/internal/alias/ya.make | 0 .../src/crypto/internal/bigmod/_asm/go.mod | 0 .../src/crypto/internal/bigmod/_asm/go.sum | 0 .../internal/bigmod/_asm/nat_amd64_asm.go | 0 .../src/crypto/internal/bigmod/nat.go | 22 +- .../src/crypto/internal/bigmod/nat_386.s | 0 .../src/crypto/internal/bigmod/nat_amd64.s | 0 .../src/crypto/internal/bigmod/nat_arm.s | 0 .../src/crypto/internal/bigmod/nat_arm64.s | 0 .../src/crypto/internal/bigmod/nat_asm.go | 0 .../src/crypto/internal/bigmod/nat_noasm.go | 0 .../src/crypto/internal/bigmod/nat_ppc64x.s | 82 + .../src/crypto/internal/bigmod/nat_riscv64.s | 0 .../src/crypto/internal/bigmod/nat_s390x.s | 0 .../src/crypto/internal/bigmod/ya.make | 0 .../src/crypto/internal/boring/Dockerfile | 0 .../src/crypto/internal/boring/LICENSE | 0 .../src/crypto/internal/boring/README.md | 0 .../src/crypto/internal/boring/aes.go | 0 .../src/crypto/internal/boring/bbig/big.go | 0 .../src/crypto/internal/boring/bbig/ya.make | 0 .../crypto/internal/boring/bcache/cache.go | 0 .../src/crypto/internal/boring/bcache/stub.s | 0 .../src/crypto/internal/boring/bcache/ya.make | 0 .../src/crypto/internal/boring/boring.go | 7 +- .../src/crypto/internal/boring/div_test.c | 0 .../src/crypto/internal/boring/doc.go | 0 .../src/crypto/internal/boring/ecdh.go | 0 .../src/crypto/internal/boring/ecdsa.go | 0 .../src/crypto/internal/boring/fipstls/stub.s | 0 .../src/crypto/internal/boring/fipstls/tls.go | 11 +- .../crypto/internal/boring/fipstls/ya.make | 0 .../crypto/internal/boring/goboringcrypto.h | 0 .../src/crypto/internal/boring/hmac.go | 0 .../src/crypto/internal/boring/notboring.go | 0 .../src/crypto/internal/boring/rand.go | 0 .../src/crypto/internal/boring/rsa.go | 28 +- .../src/crypto/internal/boring/sha.go | 0 .../src/crypto/internal/boring/sig/sig.go | 0 .../crypto/internal/boring/sig/sig_amd64.s | 0 .../crypto/internal/boring/sig/sig_other.s | 0 .../src/crypto/internal/boring/sig/ya.make | 0 .../syso/goboringcrypto_linux_amd64.syso | Bin .../syso/goboringcrypto_linux_arm64.syso | Bin .../src/crypto/internal/boring/syso/syso.go | 0 .../src/crypto/internal/boring/syso/ya.make | 0 .../src/crypto/internal/boring/ya.make | 0 .../src/crypto/internal/cryptotest/hash.go | 189 ++ .../src/crypto/internal/cryptotest/ya.make | 9 + .../src/crypto/internal/edwards25519/doc.go | 0 .../internal/edwards25519/edwards25519.go | 0 .../edwards25519/field/_asm/fe_amd64_asm.go | 2 +- .../internal/edwards25519/field/_asm/go.mod | 0 .../internal/edwards25519/field/_asm/go.sum | 0 .../crypto/internal/edwards25519/field/fe.go | 14 +- .../internal/edwards25519/field/fe_amd64.go | 2 +- .../internal/edwards25519/field/fe_amd64.s | 2 +- .../edwards25519/field/fe_amd64_noasm.go | 2 +- .../internal/edwards25519/field/fe_arm64.go | 2 +- .../internal/edwards25519/field/fe_arm64.s | 2 +- .../edwards25519/field/fe_arm64_noasm.go | 2 +- .../internal/edwards25519/field/fe_generic.go | 0 .../internal/edwards25519/field/ya.make | 0 .../crypto/internal/edwards25519/scalar.go | 4 +- .../internal/edwards25519/scalar_fiat.go | 0 .../internal/edwards25519/scalarmult.go | 0 .../crypto/internal/edwards25519/tables.go | 0 .../src/crypto/internal/edwards25519/ya.make | 0 .../src/crypto/internal/hpke/hpke.go | 259 +++ .../src/crypto/internal/hpke}/ya.make | 2 +- .../src/crypto/internal/mlkem768/mlkem768.go | 886 ++++++++ .../src/crypto/internal/mlkem768/ya.make | 7 + .../crypto/internal/nistec/fiat/Dockerfile | 0 .../src/crypto/internal/nistec/fiat/README | 0 .../crypto/internal/nistec/fiat/generate.go | 0 .../src/crypto/internal/nistec/fiat/p224.go | 0 .../internal/nistec/fiat/p224_fiat64.go | 0 .../internal/nistec/fiat/p224_invert.go | 0 .../src/crypto/internal/nistec/fiat/p256.go | 0 .../internal/nistec/fiat/p256_fiat64.go | 0 .../internal/nistec/fiat/p256_invert.go | 0 .../src/crypto/internal/nistec/fiat/p384.go | 0 .../internal/nistec/fiat/p384_fiat64.go | 0 .../internal/nistec/fiat/p384_invert.go | 0 .../src/crypto/internal/nistec/fiat/p521.go | 0 .../internal/nistec/fiat/p521_fiat64.go | 0 .../internal/nistec/fiat/p521_invert.go | 0 .../src/crypto/internal/nistec/fiat/ya.make | 0 .../src/crypto/internal/nistec/generate.go | 2 +- .../src/crypto/internal/nistec/nistec.go | 0 .../src/crypto/internal/nistec/p224.go | 0 .../src/crypto/internal/nistec/p224_sqrt.go | 0 .../src/crypto/internal/nistec/p256.go | 2 +- .../src/crypto/internal/nistec/p256_asm.go | 6 +- .../crypto/internal/nistec/p256_asm_amd64.s | 2 + .../crypto/internal/nistec/p256_asm_arm64.s | 2 + .../crypto/internal/nistec/p256_asm_ppc64le.s | 22 +- .../crypto/internal/nistec/p256_asm_s390x.s | 2 + .../crypto/internal/nistec/p256_asm_table.bin | Bin .../src/crypto/internal/nistec/p256_ordinv.go | 2 +- .../internal/nistec/p256_ordinv_noasm.go | 2 +- .../src/crypto/internal/nistec/p384.go | 0 .../src/crypto/internal/nistec/p521.go | 0 .../src/crypto/internal/nistec/ya.make | 0 .../src/crypto/internal/randutil/randutil.go | 0 .../src/crypto/internal/randutil/ya.make | 0 .../src/crypto/internal/ya.make | 0 .../src/crypto/md5/gen.go | 10 +- .../src/crypto/md5/md5.go | 28 +- .../src/crypto/md5/md5block.go | 34 +- .../src/crypto/md5/md5block_386.s | 2 + .../src/crypto/md5/md5block_amd64.s | 2 + .../src/crypto/md5/md5block_arm.s | 2 + .../src/crypto/md5/md5block_arm64.s | 2 + .../src/crypto/md5/md5block_decl.go | 2 +- .../src/crypto/md5/md5block_generic.go | 2 +- .../src/crypto/md5/md5block_ppc64x.s | 4 +- .../src/crypto/md5/md5block_s390x.s | 2 + .../src/crypto/md5/ya.make | 0 .../src/crypto/rand/rand.go | 15 +- .../_std_1.23/src/crypto/rand/rand_darwin.go | 19 + .../src/crypto/rand/rand_getentropy.go | 4 +- .../src/crypto/rand/rand_getrandom.go | 0 .../src/crypto/rand/rand_js.go | 0 .../src/crypto/rand/rand_plan9.go | 5 +- .../src/crypto/rand/rand_unix.go | 0 .../src/crypto/rand/rand_wasip1.go | 0 .../src/crypto/rand/rand_windows.go | 0 .../src/crypto/rand/util.go | 0 .../src/crypto/rand/ya.make | 2 +- .../src/crypto/rc4/rc4.go | 0 .../src/crypto/rc4/ya.make | 0 .../src/crypto/rsa/boring.go | 0 .../src/crypto/rsa/notboring.go | 0 .../src/crypto/rsa/pkcs1v15.go | 91 +- .../src/crypto/rsa/pss.go | 3 + .../src/crypto/rsa/rsa.go | 7 +- .../src/crypto/rsa/ya.make | 0 .../src/crypto/sha1/sha1.go | 35 +- .../src/crypto/sha1/sha1block.go | 0 .../src/crypto/sha1/sha1block_386.s | 2 + .../src/crypto/sha1/sha1block_amd64.go | 2 + .../src/crypto/sha1/sha1block_amd64.s | 1 + .../src/crypto/sha1/sha1block_arm.s | 2 + .../src/crypto/sha1/sha1block_arm64.go | 2 + .../src/crypto/sha1/sha1block_arm64.s | 2 + .../src/crypto/sha1/sha1block_decl.go | 2 +- .../src/crypto/sha1/sha1block_generic.go | 2 +- .../src/crypto/sha1/sha1block_s390x.go | 2 + .../src/crypto/sha1/sha1block_s390x.s | 2 + .../src/crypto/sha1/ya.make | 0 .../src/crypto/sha256/sha256.go | 47 +- .../src/crypto/sha256/sha256block.go | 0 .../src/crypto/sha256/sha256block_386.s | 2 + .../src/crypto/sha256/sha256block_amd64.go | 2 + .../src/crypto/sha256/sha256block_amd64.s | 2 + .../src/crypto/sha256/sha256block_arm64.go | 2 + .../src/crypto/sha256/sha256block_arm64.s | 2 + .../src/crypto/sha256/sha256block_decl.go | 2 +- .../src/crypto/sha256/sha256block_generic.go | 2 +- .../src/crypto/sha256/sha256block_ppc64x.s | 2 +- .../src/crypto/sha256/sha256block_s390x.go | 2 + .../src/crypto/sha256/sha256block_s390x.s | 2 + .../src/crypto/sha256/ya.make | 0 .../src/crypto/sha512/sha512.go | 45 +- .../src/crypto/sha512/sha512block.go | 0 .../src/crypto/sha512/sha512block_amd64.go | 2 +- .../src/crypto/sha512/sha512block_amd64.s | 2 + .../src/crypto/sha512/sha512block_arm64.go | 2 + .../src/crypto/sha512/sha512block_arm64.s | 2 + .../src/crypto/sha512/sha512block_decl.go | 2 +- .../src/crypto/sha512/sha512block_generic.go | 2 +- .../src/crypto/sha512/sha512block_ppc64x.s | 2 +- .../src/crypto/sha512/sha512block_riscv64.s | 288 +++ .../src/crypto/sha512/sha512block_s390x.go | 2 + .../src/crypto/sha512/sha512block_s390x.s | 2 + .../src/crypto/sha512/ya.make | 0 .../src/crypto/subtle/constant_time.go | 0 .../src/crypto/subtle/xor.go | 5 +- .../src/crypto/subtle/xor_amd64.go | 0 .../src/crypto/subtle/xor_amd64.s | 0 .../src/crypto/subtle/xor_arm64.go | 0 .../src/crypto/subtle/xor_arm64.s | 0 .../src/crypto/subtle/xor_generic.go | 0 .../src/crypto/subtle/xor_ppc64x.go | 0 .../src/crypto/subtle/xor_ppc64x.s | 4 +- .../src/crypto/subtle/ya.make | 0 .../src/crypto/tls/alert.go | 2 + .../src/crypto/tls/auth.go | 2 +- .../_std_1.23/src/crypto/tls/bogo_config.json | 233 ++ contrib/go/_std_1.23/src/crypto/tls/boring.go | 15 + .../src/crypto/tls/cache.go | 0 .../src/crypto/tls/cipher_suites.go | 56 +- .../src/crypto/tls/common.go | 255 ++- .../src/crypto/tls/common_string.go | 6 +- .../src/crypto/tls/conn.go | 25 +- .../go/_std_1.23/src/crypto/tls/defaults.go | 129 ++ contrib/go/_std_1.23/src/crypto/tls/ech.go | 283 +++ .../src/crypto/tls/fipsonly/fipsonly.go | 0 .../src/crypto/tls/fipsonly/ya.make | 0 .../src/crypto/tls/generate_cert.go | 0 .../src/crypto/tls/handshake_client.go | 279 ++- .../src/crypto/tls/handshake_client_tls13.go | 229 +- .../src/crypto/tls/handshake_messages.go | 533 ++--- .../src/crypto/tls/handshake_server.go | 22 +- .../src/crypto/tls/handshake_server_tls13.go | 120 +- .../src/crypto/tls/key_agreement.go | 8 +- .../src/crypto/tls/key_schedule.go | 41 + .../src/crypto/tls/notboring.go} | 10 +- .../src/crypto/tls/prf.go | 0 .../src/crypto/tls/quic.go | 91 +- .../src/crypto/tls/ticket.go | 14 +- .../src/crypto/tls/tls.go | 30 +- .../src/crypto/tls/ya.make | 2 + .../src/crypto/x509/boring.go | 0 .../src/crypto/x509/cert_pool.go | 0 .../x509/internal/macos/corefoundation.go | 0 .../x509/internal/macos/corefoundation.s | 0 .../crypto/x509/internal/macos/security.go | 0 .../src/crypto/x509/internal/macos/security.s | 0 .../src/crypto/x509/internal/macos/ya.make | 0 .../src/crypto/x509/internal/ya.make | 0 .../src/crypto/x509/notboring.go | 0 .../src/crypto/x509/oid.go | 114 +- .../src/crypto/x509/parser.go | 68 +- .../src/crypto/x509/pem_decrypt.go | 0 .../src/crypto/x509/pkcs1.go | 0 .../src/crypto/x509/pkcs8.go | 0 .../src/crypto/x509/pkix/pkix.go | 0 .../src/crypto/x509/pkix/ya.make | 0 .../src/crypto/x509/platform_root_cert.pem | 0 .../src/crypto/x509/platform_root_key.pem | 0 .../src/crypto/x509/root.go | 10 + .../src/crypto/x509/root_aix.go | 0 .../src/crypto/x509/root_bsd.go | 0 .../src/crypto/x509/root_darwin.go | 0 .../src/crypto/x509/root_linux.go | 0 .../src/crypto/x509/root_plan9.go | 0 .../src/crypto/x509/root_solaris.go | 0 .../src/crypto/x509/root_unix.go | 0 .../src/crypto/x509/root_wasm.go | 0 .../src/crypto/x509/root_windows.go | 0 .../src/crypto/x509/sec1.go | 0 .../src/crypto/x509/test-file.crt | 0 .../src/crypto/x509/verify.go | 17 +- .../src/crypto/x509/x509.go | 295 ++- .../src/crypto/x509/x509_test_import.go | 0 .../src/crypto/x509/ya.make | 0 .../src/crypto/ya.make | 0 .../src/database/sql/driver/driver.go | 2 +- .../src/database/sql/driver/types.go | 4 + .../src/database/sql/driver/ya.make | 0 .../src/embed/embed.go | 23 +- .../embed/internal/embedtest/concurrency.txt | 0 .../src/embed/internal/embedtest/ya.make | 0 .../src/embed/internal/ya.make | 0 .../src/embed/ya.make | 0 .../src/encoding/ascii85/ascii85.go | 0 .../src/encoding/ascii85/ya.make | 0 .../src/encoding/asn1/asn1.go | 0 .../src/encoding/asn1/common.go | 0 .../src/encoding/asn1/marshal.go | 29 +- .../src/encoding/asn1/ya.make | 0 .../src/encoding/base32/base32.go | 2 +- .../src/encoding/base32/ya.make | 0 .../src/encoding/base64/base64.go | 0 .../src/encoding/base64/ya.make | 0 .../src/encoding/binary/binary.go | 687 +++--- .../src/encoding/binary/native_endian_big.go | 0 .../encoding/binary/native_endian_little.go | 0 .../src/encoding/binary/varint.go | 14 +- .../src/encoding/binary/ya.make | 0 .../src/encoding/csv/reader.go | 3 +- .../src/encoding/csv/writer.go | 0 .../src/encoding/csv/ya.make | 0 .../src/encoding/encoding.go | 0 .../src/encoding/gob/debug.go | 0 .../src/encoding/gob/dec_helpers.go | 0 .../src/encoding/gob/decgen.go | 3 + .../src/encoding/gob/decode.go | 19 +- .../src/encoding/gob/decoder.go | 2 + .../src/encoding/gob/doc.go | 2 +- .../src/encoding/gob/dump.go | 1 + .../src/encoding/gob/enc_helpers.go | 0 .../src/encoding/gob/encgen.go | 3 + .../src/encoding/gob/encode.go | 2 +- .../src/encoding/gob/encoder.go | 0 .../src/encoding/gob/error.go | 0 .../src/encoding/gob/type.go | 14 +- .../src/encoding/gob/ya.make | 0 .../src/encoding/hex/hex.go | 8 +- .../src/encoding/hex/ya.make | 0 .../src/encoding/json/decode.go | 22 +- .../src/encoding/json/encode.go | 68 +- .../src/encoding/json/fold.go | 0 .../src/encoding/json/indent.go | 0 .../src/encoding/json/scanner.go | 0 .../src/encoding/json/stream.go | 1 + .../src/encoding/json/tables.go | 0 .../src/encoding/json/tags.go | 0 .../src/encoding/json/ya.make | 0 .../src/encoding/pem/pem.go | 4 +- .../src/encoding/pem/ya.make | 0 .../src/encoding/xml/marshal.go | 0 .../src/encoding/xml/read.go | 0 .../src/encoding/xml/typeinfo.go | 0 .../src/encoding/xml/xml.go | 31 +- .../src/encoding/xml/ya.make | 0 .../src/encoding/ya.make | 0 .../src/errors/errors.go | 0 .../src/errors/join.go | 0 .../src/errors/wrap.go | 4 +- .../src/errors/ya.make | 0 .../{_std_1.22 => _std_1.23}/src/flag/flag.go | 6 +- .../{_std_1.22 => _std_1.23}/src/flag/ya.make | 0 .../{_std_1.22 => _std_1.23}/src/fmt/doc.go | 52 +- .../src/fmt/errors.go | 4 +- .../src/fmt/format.go | 10 +- .../{_std_1.22 => _std_1.23}/src/fmt/print.go | 25 +- .../{_std_1.22 => _std_1.23}/src/fmt/scan.go | 10 +- .../{_std_1.22 => _std_1.23}/src/fmt/ya.make | 0 .../src/go/ast/ast.go | 9 +- .../src/go/ast/commentmap.go | 36 +- .../src/go/ast/filter.go | 4 +- .../src/go/ast/import.go | 29 +- .../src/go/ast/print.go | 4 +- .../src/go/ast/resolve.go | 0 .../src/go/ast/scope.go | 4 +- .../src/go/ast/walk.go | 91 +- .../src/go/ast/ya.make | 0 .../src/go/build/constraint/expr.go | 28 +- .../src/go/build/constraint/vers.go | 0 .../src/go/build/constraint/ya.make | 0 .../src/go/constant/kind_string.go | 0 .../src/go/constant/value.go | 0 .../src/go/constant/ya.make | 0 .../src/go/doc/comment/doc.go | 0 .../src/go/doc/comment/html.go | 0 .../src/go/doc/comment/markdown.go | 0 .../src/go/doc/comment/parse.go | 0 .../src/go/doc/comment/print.go | 0 .../src/go/doc/comment/std.go | 3 + .../src/go/doc/comment/text.go | 0 .../src/go/doc/comment/ya.make | 0 .../src/go/internal/typeparams/typeparams.go | 30 +- .../src/go/internal/typeparams/ya.make | 0 .../src/go/parser/interface.go | 0 .../src/go/parser/parser.go | 2 + .../src/go/parser/resolver.go | 0 .../src/go/parser/ya.make | 0 .../src/go/printer/comment.go | 0 .../src/go/printer/gobuild.go | 4 +- .../src/go/printer/nodes.go | 0 .../src/go/printer/printer.go | 0 .../src/go/printer/ya.make | 0 .../src/go/scanner/errors.go | 0 .../src/go/scanner/scanner.go | 0 .../src/go/scanner/ya.make | 0 .../src/go/token/position.go | 90 +- .../src/go/token/serialize.go | 0 .../src/go/token/token.go | 0 .../src/go/token/ya.make | 0 contrib/go/_std_1.23/src/go/types/alias.go | 161 ++ .../src/go/types/api.go | 38 +- .../src/go/types/api_predicates.go | 13 + .../src/go/types/array.go | 1 + .../src/go/types/assignments.go | 53 +- .../go/_std_1.23/src/go/types/badlinkname.go | 20 + .../src/go/types/basic.go | 1 + .../src/go/types/builtins.go | 37 +- .../src/go/types/call.go | 78 +- .../src/go/types/chan.go | 1 + .../src/go/types/check.go | 187 +- .../src/go/types/const.go | 7 +- .../src/go/types/context.go | 1 + .../src/go/types/conversions.go | 33 +- .../src/go/types/decl.go | 126 +- contrib/go/_std_1.23/src/go/types/errors.go | 313 +++ .../go/_std_1.23/src/go/types/errsupport.go | 116 + .../src/go/types/eval.go | 0 .../src/go/types/expr.go | 54 +- .../src/go/types/exprstring.go | 2 +- contrib/go/_std_1.23/src/go/types/format.go | 153 ++ .../src/go/types/gccgosizes.go | 1 + .../src/go/types/gcsizes.go | 5 +- .../src/go/types/generate.go | 0 .../src/go/types/gotype.go | 0 .../src/go/types/index.go | 2 +- .../src/go/types/infer.go | 36 +- .../src/go/types/initorder.go | 11 +- .../src/go/types/instantiate.go | 67 +- .../src/go/types/interface.go | 0 .../src/go/types/labels.go | 9 +- .../src/go/types/lookup.go | 40 +- .../src/go/types/map.go | 1 + .../src/go/types/methodset.go | 0 .../src/go/types/mono.go | 13 +- .../src/go/types/named.go | 74 +- .../src/go/types/object.go | 52 +- .../src/go/types/objset.go | 1 + .../src/go/types/operand.go | 50 +- .../src/go/types/package.go | 1 + .../src/go/types/pointer.go | 1 + .../src/go/types/predicates.go | 44 +- .../src/go/types/resolver.go | 47 +- .../src/go/types/return.go | 6 +- .../src/go/types/scope.go | 49 +- .../src/go/types/selection.go | 3 +- .../src/go/types/signature.go | 8 +- .../src/go/types/sizes.go | 7 +- .../src/go/types/slice.go | 1 + .../src/go/types/stmt.go | 123 +- .../src/go/types/struct.go | 19 +- .../src/go/types/subst.go | 80 +- .../src/go/types/termlist.go | 1 + .../src/go/types/tuple.go | 1 + .../src/go/types/type.go | 3 + .../src/go/types/typelists.go | 1 + .../src/go/types/typeparam.go | 9 +- .../src/go/types/typeset.go | 34 +- .../src/go/types/typestring.go | 35 +- .../src/go/types/typeterm.go | 1 + .../src/go/types/typexpr.go | 51 +- .../src/go/types/under.go | 3 + .../src/go/types/unify.go | 36 +- .../src/go/types/union.go | 0 .../src/go/types/universe.go | 45 +- contrib/go/_std_1.23/src/go/types/util.go | 48 + .../src/go/types/validtype.go | 75 +- .../src/go/types/version.go | 61 +- .../src/go/types/ya.make | 3 + .../src/go/version/version.go | 0 .../src/go/version/ya.make | 0 .../src/hash/adler32/adler32.go | 23 +- .../src/hash/adler32/ya.make | 0 .../src/hash/crc32/crc32.go | 29 +- .../src/hash/crc32/crc32_amd64.go | 0 .../src/hash/crc32/crc32_amd64.s | 0 .../src/hash/crc32/crc32_arm64.go | 0 .../src/hash/crc32/crc32_arm64.s | 0 .../src/hash/crc32/crc32_generic.go | 4 +- .../src/hash/crc32/crc32_otherarch.go | 0 .../src/hash/crc32/crc32_ppc64le.go | 0 .../src/hash/crc32/crc32_ppc64le.s | 53 +- .../src/hash/crc32/crc32_s390x.go | 0 .../src/hash/crc32/crc32_s390x.s | 0 .../src/hash/crc32/crc32_table_ppc64le.s | 3 +- contrib/go/_std_1.23/src/hash/crc32/gen.go | 7 + .../src/hash/crc32/gen_const_ppc64le.go | 10 +- .../src/hash/crc32/ya.make | 2 + .../src/hash/crc64/crc64.go | 37 +- .../src/hash/crc64/ya.make | 0 .../src/hash/fnv/fnv.go | 94 +- .../src/hash/fnv/ya.make | 0 .../{_std_1.22 => _std_1.23}/src/hash/hash.go | 0 .../src/hash/maphash/maphash.go | 0 .../src/hash/maphash/maphash_purego.go | 18 +- .../src/hash/maphash/maphash_runtime.go | 0 .../src/hash/maphash/ya.make | 0 .../src/hash/test_cases.txt | 0 .../src/hash/test_gen.awk | 0 .../{_std_1.22 => _std_1.23}/src/hash/ya.make | 0 .../src/html/entity.go | 0 .../src/html/escape.go | 0 .../src/html/template/attr.go | 0 .../src/html/template/attr_string.go | 0 .../src/html/template/content.go | 0 .../src/html/template/context.go | 0 .../src/html/template/css.go | 0 .../src/html/template/delim_string.go | 0 .../src/html/template/doc.go | 10 +- .../src/html/template/element_string.go | 0 .../src/html/template/error.go | 0 .../src/html/template/escape.go | 0 .../src/html/template/html.go | 0 .../src/html/template/js.go | 2 +- .../src/html/template/jsctx_string.go | 0 .../src/html/template/state_string.go | 0 .../src/html/template/template.go | 22 +- .../src/html/template/transition.go | 2 +- .../src/html/template/url.go | 0 .../src/html/template/urlpart_string.go | 0 .../src/html/template/ya.make | 0 .../{_std_1.22 => _std_1.23}/src/html/ya.make | 0 .../src/internal/abi/abi.go | 0 .../src/internal/abi/abi_amd64.go | 0 .../src/internal/abi/abi_arm64.go | 0 .../src/internal/abi/abi_generic.go | 2 +- .../src/internal/abi/abi_loong64.go | 2 - .../src/internal/abi/abi_ppc64x.go | 0 .../src/internal/abi/abi_riscv64.go | 0 .../src/internal/abi/abi_test.s | 0 .../src/internal/abi/compiletype.go | 3 + .../go/_std_1.23/src/internal/abi/escape.go | 33 + .../src/internal/abi/funcpc.go | 0 .../src/internal/abi/funcpc_gccgo.go | 0 .../go/_std_1.23/src/internal/abi/iface.go | 27 + .../src/internal/abi/map.go | 12 +- .../src/internal/abi/rangefuncconsts.go | 18 + .../go/_std_1.23/src/internal/abi/runtime.go | 8 + .../src/internal/abi/stack.go | 0 .../src/internal/abi/stub.s | 0 .../src/internal/abi/switch.go | 0 .../src/internal/abi/symtab.go | 4 + .../src/internal/abi/type.go | 97 +- .../src/internal/abi/ya.make | 8 + .../go/_std_1.23/src/internal/asan/asan.go | 19 + contrib/go/_std_1.23/src/internal/asan/doc.go | 10 + .../go/_std_1.23/src/internal/asan/noasan.go | 17 + .../go/_std_1.23/src/internal/asan/ya.make | 8 + .../src/internal/bisect/bisect.go | 20 +- .../src/internal/bisect/ya.make | 0 .../src/internal/buildcfg/cfg.go | 168 +- .../src/internal/buildcfg/exp.go | 6 +- .../src/internal/buildcfg/ya.make | 0 .../src/internal/buildcfg/zbootstrap.go | 4 +- .../src/internal/bytealg/bytealg.go | 3 +- .../src/internal/bytealg/compare_386.s | 0 .../src/internal/bytealg/compare_amd64.s | 0 .../src/internal/bytealg/compare_arm.s | 0 .../src/internal/bytealg/compare_arm64.s | 0 .../src/internal/bytealg/compare_generic.go | 16 + .../src/internal/bytealg/compare_loong64.s | 18 - .../src/internal/bytealg/compare_mips64x.s | 0 .../src/internal/bytealg/compare_mipsx.s | 0 .../src/internal/bytealg/compare_native.go | 4 + .../src/internal/bytealg/compare_ppc64x.s | 0 .../src/internal/bytealg/compare_riscv64.s | 0 .../src/internal/bytealg/compare_s390x.s | 0 .../src/internal/bytealg/compare_wasm.s | 0 .../src/internal/bytealg/count_amd64.s | 0 .../src/internal/bytealg/count_arm.s | 0 .../src/internal/bytealg/count_arm64.s | 0 .../src/internal/bytealg/count_generic.go | 0 .../src/internal/bytealg/count_native.go | 0 .../src/internal/bytealg/count_ppc64x.s | 0 .../src/internal/bytealg/count_riscv64.s | 0 .../src/internal/bytealg/count_s390x.s | 0 .../src/internal/bytealg/equal_386.s | 0 .../src/internal/bytealg/equal_amd64.s | 0 .../src/internal/bytealg/equal_arm.s | 0 .../src/internal/bytealg/equal_arm64.s | 3 + .../src/internal/bytealg/equal_generic.go | 0 .../src/internal/bytealg/equal_loong64.s | 24 - .../src/internal/bytealg/equal_mips64x.s | 0 .../src/internal/bytealg/equal_mipsx.s | 0 .../src/internal/bytealg/equal_native.go | 0 .../src/internal/bytealg/equal_ppc64x.s | 0 .../src/internal/bytealg/equal_riscv64.s | 0 .../src/internal/bytealg/equal_s390x.s | 0 .../src/internal/bytealg/equal_wasm.s | 0 .../src/internal/bytealg/index_amd64.go | 0 .../src/internal/bytealg/index_amd64.s | 0 .../src/internal/bytealg/index_arm64.go | 0 .../src/internal/bytealg/index_arm64.s | 0 .../src/internal/bytealg/index_generic.go | 0 .../src/internal/bytealg/index_native.go | 0 .../src/internal/bytealg/index_ppc64x.go | 0 .../src/internal/bytealg/index_ppc64x.s | 0 .../src/internal/bytealg/index_s390x.go | 0 .../src/internal/bytealg/index_s390x.s | 0 .../src/internal/bytealg/indexbyte_386.s | 0 .../src/internal/bytealg/indexbyte_amd64.s | 0 .../src/internal/bytealg/indexbyte_arm.s | 0 .../src/internal/bytealg/indexbyte_arm64.s | 0 .../src/internal/bytealg/indexbyte_generic.go | 0 .../src/internal/bytealg/indexbyte_loong64.s | 22 - .../src/internal/bytealg/indexbyte_mips64x.s | 0 .../src/internal/bytealg/indexbyte_mipsx.s | 0 .../src/internal/bytealg/indexbyte_native.go | 0 .../src/internal/bytealg/indexbyte_ppc64x.s | 0 .../src/internal/bytealg/indexbyte_riscv64.s | 0 .../src/internal/bytealg/indexbyte_s390x.s | 0 .../src/internal/bytealg/indexbyte_wasm.s | 4 +- .../internal/bytealg/lastindexbyte_generic.go | 0 .../src/internal/bytealg/ya.make | 0 .../src/internal/byteorder/byteorder.go | 149 ++ .../_std_1.23/src/internal/byteorder/ya.make | 7 + .../src/internal/chacha8rand/chacha8.go | 61 +- .../src/internal/chacha8rand/chacha8_amd64.s | 0 .../src/internal/chacha8rand/chacha8_arm64.s | 0 .../internal/chacha8rand/chacha8_generic.go | 0 .../src/internal/chacha8rand/chacha8_stub.s | 0 .../src/internal/chacha8rand/ya.make | 0 .../src/internal/concurrent/hashtriemap.go | 408 ++++ .../_std_1.23/src/internal/concurrent/ya.make | 7 + .../src/internal/coverage/rtcov/rtcov.go | 88 + .../src/internal/coverage/rtcov/ya.make | 0 .../src/internal/cpu/cpu.go | 10 + .../src/internal/cpu/cpu.s | 0 .../src/internal/cpu/cpu_arm.go | 0 .../src/internal/cpu/cpu_arm64.go | 0 .../src/internal/cpu/cpu_arm64.s | 0 .../src/internal/cpu/cpu_arm64_android.go | 0 .../src/internal/cpu/cpu_arm64_darwin.go | 12 + .../src/internal/cpu/cpu_arm64_freebsd.go | 0 .../src/internal/cpu/cpu_arm64_hwcap.go | 15 +- .../src/internal/cpu/cpu_arm64_linux.go | 0 .../src/internal/cpu/cpu_arm64_openbsd.go | 0 .../src/internal/cpu/cpu_arm64_other.go | 0 .../src/internal/cpu/cpu_loong64.go | 0 .../src/internal/cpu/cpu_mips.go | 0 .../src/internal/cpu/cpu_mips64x.go | 0 .../src/internal/cpu/cpu_mipsle.go | 0 .../src/internal/cpu/cpu_no_name.go | 0 .../src/internal/cpu/cpu_ppc64x.go | 0 .../src/internal/cpu/cpu_ppc64x_aix.go | 0 .../src/internal/cpu/cpu_ppc64x_linux.go | 0 .../src/internal/cpu/cpu_ppc64x_other.go | 0 .../src/internal/cpu/cpu_riscv64.go | 0 .../src/internal/cpu/cpu_s390x.go | 0 .../src/internal/cpu/cpu_s390x.s | 0 .../src/internal/cpu/cpu_wasm.go | 0 .../src/internal/cpu/cpu_x86.go | 3 - .../src/internal/cpu/cpu_x86.s | 0 .../src/internal/cpu/ya.make | 0 .../src/internal/filepathlite/path.go | 274 +++ .../internal/filepathlite}/path_nonwindows.go | 2 +- .../src/internal/filepathlite/path_plan9.go | 41 + .../src/internal/filepathlite/path_unix.go | 43 + .../internal/filepathlite}/path_windows.go | 321 ++- .../src/internal/filepathlite}/ya.make | 3 +- .../src/internal/fmtsort/sort.go | 113 +- .../src/internal/fmtsort/ya.make | 0 .../src/internal/goarch/gengoarch.go | 0 .../src/internal/goarch/goarch.go | 0 .../src/internal/goarch/goarch_386.go | 0 .../src/internal/goarch/goarch_amd64.go | 0 .../src/internal/goarch/goarch_arm.go | 0 .../src/internal/goarch/goarch_arm64.go | 0 .../src/internal/goarch/goarch_loong64.go | 0 .../src/internal/goarch/goarch_mips.go | 0 .../src/internal/goarch/goarch_mips64.go | 0 .../src/internal/goarch/goarch_mips64le.go | 0 .../src/internal/goarch/goarch_mipsle.go | 0 .../src/internal/goarch/goarch_ppc64.go | 0 .../src/internal/goarch/goarch_ppc64le.go | 0 .../src/internal/goarch/goarch_riscv64.go | 0 .../src/internal/goarch/goarch_s390x.go | 0 .../src/internal/goarch/goarch_wasm.go | 0 .../src/internal/goarch/ya.make | 0 .../src/internal/goarch/zgoarch_386.go | 0 .../src/internal/goarch/zgoarch_amd64.go | 0 .../src/internal/goarch/zgoarch_arm.go | 0 .../src/internal/goarch/zgoarch_arm64.go | 0 .../src/internal/goarch/zgoarch_arm64be.go | 0 .../src/internal/goarch/zgoarch_armbe.go | 0 .../src/internal/goarch/zgoarch_loong64.go | 0 .../src/internal/goarch/zgoarch_mips.go | 0 .../src/internal/goarch/zgoarch_mips64.go | 0 .../src/internal/goarch/zgoarch_mips64le.go | 0 .../src/internal/goarch/zgoarch_mips64p32.go | 0 .../internal/goarch/zgoarch_mips64p32le.go | 0 .../src/internal/goarch/zgoarch_mipsle.go | 0 .../src/internal/goarch/zgoarch_ppc.go | 0 .../src/internal/goarch/zgoarch_ppc64.go | 0 .../src/internal/goarch/zgoarch_ppc64le.go | 0 .../src/internal/goarch/zgoarch_riscv.go | 0 .../src/internal/goarch/zgoarch_riscv64.go | 0 .../src/internal/goarch/zgoarch_s390.go | 0 .../src/internal/goarch/zgoarch_s390x.go | 0 .../src/internal/goarch/zgoarch_sparc.go | 0 .../src/internal/goarch/zgoarch_sparc64.go | 0 .../src/internal/goarch/zgoarch_wasm.go | 0 .../src/internal/godebug/godebug.go | 24 +- .../src/internal/godebug/ya.make | 0 .../src/internal/godebugs/table.go | 12 +- .../src/internal/godebugs/ya.make | 0 .../goexperiment/exp_aliastypeparams_off.go | 8 + .../goexperiment/exp_aliastypeparams_on.go | 8 + .../internal/goexperiment/exp_arenas_off.go | 0 .../internal/goexperiment/exp_arenas_on.go | 0 .../goexperiment/exp_boringcrypto_off.go | 0 .../goexperiment/exp_boringcrypto_on.go | 0 .../goexperiment/exp_cacheprog_off.go | 0 .../internal/goexperiment/exp_cacheprog_on.go | 0 .../goexperiment/exp_cgocheck2_off.go | 0 .../internal/goexperiment/exp_cgocheck2_on.go | 0 .../goexperiment/exp_coverageredesign_off.go | 0 .../goexperiment/exp_coverageredesign_on.go | 0 .../goexperiment/exp_fieldtrack_off.go | 0 .../goexperiment/exp_fieldtrack_on.go | 0 .../goexperiment/exp_heapminimum512kib_off.go | 0 .../goexperiment/exp_heapminimum512kib_on.go | 0 .../internal/goexperiment/exp_loopvar_off.go | 0 .../internal/goexperiment/exp_loopvar_on.go | 0 .../goexperiment/exp_newinliner_off.go | 0 .../goexperiment/exp_newinliner_on.go | 0 .../goexperiment/exp_preemptibleloops_off.go | 0 .../goexperiment/exp_preemptibleloops_on.go | 0 .../goexperiment/exp_rangefunc_off.go | 0 .../internal/goexperiment/exp_rangefunc_on.go | 0 .../goexperiment/exp_regabiargs_off.go | 0 .../goexperiment/exp_regabiargs_on.go | 0 .../goexperiment/exp_regabiwrappers_off.go | 0 .../goexperiment/exp_regabiwrappers_on.go | 0 .../goexperiment/exp_staticlockranking_off.go | 0 .../goexperiment/exp_staticlockranking_on.go | 0 .../src/internal/goexperiment/flags.go | 20 +- .../src/internal/goexperiment/mkconsts.go | 0 .../src/internal/goexperiment/ya.make | 4 +- .../src/internal/goos/gengoos.go | 0 .../src/internal/goos/goos.go | 0 .../src/internal/goos/nonunix.go | 0 .../src/internal/goos/unix.go | 0 .../src/internal/goos/ya.make | 0 .../src/internal/goos/zgoos_aix.go | 0 .../src/internal/goos/zgoos_android.go | 0 .../src/internal/goos/zgoos_darwin.go | 0 .../src/internal/goos/zgoos_dragonfly.go | 0 .../src/internal/goos/zgoos_freebsd.go | 0 .../src/internal/goos/zgoos_hurd.go | 0 .../src/internal/goos/zgoos_illumos.go | 0 .../src/internal/goos/zgoos_ios.go | 0 .../src/internal/goos/zgoos_js.go | 0 .../src/internal/goos/zgoos_linux.go | 0 .../src/internal/goos/zgoos_netbsd.go | 0 .../src/internal/goos/zgoos_openbsd.go | 0 .../src/internal/goos/zgoos_plan9.go | 0 .../src/internal/goos/zgoos_solaris.go | 0 .../src/internal/goos/zgoos_wasip1.go | 0 .../src/internal/goos/zgoos_windows.go | 0 .../src/internal/goos/zgoos_zos.go | 0 .../src/internal/gover/gover.go | 0 .../src/internal/gover/ya.make | 0 .../src/internal/goversion/goversion.go | 2 +- .../src/internal/goversion/ya.make | 0 .../src/internal/itoa/itoa.go | 0 .../src/internal/itoa/ya.make | 0 contrib/go/_std_1.23/src/internal/msan/doc.go | 9 + .../go/_std_1.23/src/internal/msan/msan.go | 28 + .../go/_std_1.23/src/internal/msan/nomsan.go | 28 + .../go/_std_1.23/src/internal/msan/ya.make | 8 + .../src/internal/nettrace/nettrace.go | 0 .../src/internal/nettrace/ya.make | 0 .../src/internal/oserror/errors.go | 0 .../src/internal/oserror/ya.make | 0 .../internal/poll/copy_file_range_linux.go | 23 +- .../src/internal/poll/errno_unix.go | 0 .../src/internal/poll/errno_windows.go | 0 .../src/internal/poll/fd.go | 0 .../src/internal/poll/fd_fsync_darwin.go | 8 + .../src/internal/poll/fd_fsync_posix.go | 0 .../src/internal/poll/fd_fsync_windows.go | 0 .../src/internal/poll/fd_io_plan9.go | 0 .../src/internal/poll/fd_mutex.go | 0 .../src/internal/poll/fd_opendir_darwin.go | 0 .../src/internal/poll/fd_plan9.go | 17 +- .../src/internal/poll/fd_poll_js.go | 0 .../src/internal/poll/fd_poll_runtime.go | 10 + .../src/internal/poll/fd_posix.go | 0 .../src/internal/poll/fd_unix.go | 11 +- .../src/internal/poll/fd_unixjs.go | 0 .../src/internal/poll/fd_wasip1.go | 11 +- .../src/internal/poll/fd_windows.go | 32 +- .../src/internal/poll/fd_writev_libc.go | 0 .../src/internal/poll/fd_writev_unix.go | 0 .../src/internal/poll/file_plan9.go | 0 .../src/internal/poll/hook_cloexec.go | 0 .../src/internal/poll/hook_unix.go | 0 .../src/internal/poll/hook_windows.go | 0 .../src/internal/poll/iovec_solaris.go | 0 .../src/internal/poll/iovec_unix.go | 0 .../_std_1.23/src/internal/poll/sendfile.go | 7 + .../src/internal/poll/sendfile_bsd.go | 77 + .../src/internal/poll/sendfile_linux.go} | 45 +- .../src/internal/poll/sendfile_solaris.go | 43 +- .../src/internal/poll/sendfile_windows.go | 3 + .../src/internal/poll/sock_cloexec.go | 22 + .../src/internal/poll/sock_cloexec_accept.go | 0 .../internal/poll/sock_cloexec_solaris.go} | 34 +- .../src/internal/poll/sockopt.go | 0 .../src/internal/poll/sockopt_linux.go | 0 .../src/internal/poll/sockopt_unix.go | 0 .../src/internal/poll/sockopt_windows.go | 0 .../src/internal/poll/sockoptip.go | 0 .../src/internal/poll/splice_linux.go | 21 +- .../src/internal/poll/sys_cloexec.go | 0 .../src/internal/poll/writev.go | 4 +- .../src/internal/poll/ya.make | 3 + .../internal/profilerecord/profilerecord.go | 28 + .../src/internal/profilerecord/ya.make | 7 + .../src/internal/race/doc.go | 0 .../src/internal/race/norace.go | 0 .../src/internal/race/race.go | 0 .../src/internal/race/ya.make | 0 .../src/internal/reflectlite/asm.s | 0 .../src/internal/reflectlite/swapper.go | 2 +- .../src/internal/reflectlite/type.go | 24 +- .../src/internal/reflectlite/value.go | 37 +- .../src/internal/reflectlite/ya.make | 0 .../internal/runtime}/atomic/atomic_386.go | 1 + .../src/internal/runtime}/atomic/atomic_386.s | 0 .../internal/runtime}/atomic/atomic_amd64.go | 0 .../internal/runtime}/atomic/atomic_amd64.s | 0 .../runtime}/atomic/atomic_andor_generic.go | 13 +- .../internal/runtime}/atomic/atomic_arm.go | 1 + .../src/internal/runtime}/atomic/atomic_arm.s | 0 .../internal/runtime}/atomic/atomic_arm64.go | 0 .../internal/runtime}/atomic/atomic_arm64.s | 56 + .../runtime}/atomic/atomic_loong64.go | 18 + .../internal/runtime}/atomic/atomic_loong64.s | 70 +- .../runtime}/atomic/atomic_mips64x.go | 18 + .../internal/runtime}/atomic/atomic_mips64x.s | 64 + .../internal/runtime}/atomic/atomic_mipsx.go | 34 + .../internal/runtime}/atomic/atomic_mipsx.s | 36 + .../internal/runtime}/atomic/atomic_ppc64x.go | 0 .../internal/runtime}/atomic/atomic_ppc64x.s | 0 .../runtime}/atomic/atomic_riscv64.go | 0 .../internal/runtime}/atomic/atomic_riscv64.s | 0 .../internal/runtime}/atomic/atomic_s390x.go | 18 + .../internal/runtime}/atomic/atomic_s390x.s | 56 + .../internal/runtime}/atomic/atomic_wasm.go | 2 + .../internal/runtime}/atomic/atomic_wasm.s | 0 .../src/internal/runtime}/atomic/doc.go | 0 .../src/internal/runtime}/atomic/stubs.go | 0 .../internal/runtime}/atomic/sys_linux_arm.s | 0 .../runtime}/atomic/sys_nonlinux_arm.s | 0 .../src/internal/runtime}/atomic/types.go | 0 .../internal/runtime}/atomic/types_64bit.go | 0 .../src/internal/runtime}/atomic/unaligned.go | 0 .../src/internal/runtime}/atomic/ya.make | 0 .../src/internal/runtime/exithook/hooks.go | 85 + .../src/internal/runtime/exithook/ya.make | 7 + .../internal/runtime}/syscall/asm_linux_386.s | 0 .../runtime}/syscall/asm_linux_amd64.s | 0 .../internal/runtime}/syscall/asm_linux_arm.s | 0 .../runtime}/syscall/asm_linux_arm64.s | 0 .../runtime}/syscall/asm_linux_loong64.s | 26 - .../runtime}/syscall/asm_linux_mips64x.s | 0 .../runtime}/syscall/asm_linux_mipsx.s | 0 .../runtime}/syscall/asm_linux_ppc64x.s | 0 .../runtime}/syscall/asm_linux_riscv64.s | 0 .../runtime}/syscall/asm_linux_s390x.s | 0 .../internal/runtime/syscall/defs_linux.go | 19 + .../runtime}/syscall/defs_linux_386.go | 13 +- .../runtime}/syscall/defs_linux_amd64.go | 13 +- .../runtime}/syscall/defs_linux_arm.go | 13 +- .../runtime}/syscall/defs_linux_arm64.go | 13 +- .../runtime}/syscall/defs_linux_loong64.go | 13 +- .../runtime}/syscall/defs_linux_mips64x.go | 13 +- .../runtime}/syscall/defs_linux_mipsx.go | 13 +- .../runtime}/syscall/defs_linux_ppc64x.go | 13 +- .../runtime}/syscall/defs_linux_riscv64.go | 13 +- .../runtime}/syscall/defs_linux_s390x.go | 13 +- .../runtime}/syscall/syscall_linux.go | 28 +- .../src/internal/runtime}/syscall/ya.make | 2 + .../src/internal/singleflight/singleflight.go | 0 .../src/internal/singleflight/ya.make | 0 .../src/internal/stringslite/strings.go | 150 ++ .../src/internal/stringslite/ya.make | 7 + .../syscall/execenv/execenv_default.go | 0 .../syscall/execenv/execenv_windows.go | 0 .../src/internal/syscall/execenv/ya.make | 0 .../syscall/unix/arc4random_darwin.go | 24 + .../src/internal/syscall/unix/asm_aix_ppc64.s | 0 .../src/internal/syscall/unix/asm_darwin.s | 2 + .../src/internal/syscall/unix/asm_openbsd.s | 10 + .../src/internal/syscall/unix/asm_solaris.s | 3 + .../src/internal/syscall/unix/at.go | 0 .../src/internal/syscall/unix/at_aix.go | 0 .../src/internal/syscall/unix/at_fstatat.go | 0 .../src/internal/syscall/unix/at_fstatat2.go | 0 .../src/internal/syscall/unix/at_js.go | 0 .../src/internal/syscall/unix/at_libc.go | 0 .../src/internal/syscall/unix/at_libc2.go | 0 .../src/internal/syscall/unix/at_solaris.go | 4 + .../internal/syscall/unix/at_sysnum_darwin.go | 10 +- .../syscall/unix/at_sysnum_dragonfly.go | 20 + .../syscall/unix/at_sysnum_freebsd.go | 0 .../syscall/unix/at_sysnum_fstatat64_linux.go | 0 .../syscall/unix/at_sysnum_fstatat_linux.go | 0 .../internal/syscall/unix/at_sysnum_linux.go | 0 .../internal/syscall/unix/at_sysnum_netbsd.go | 0 .../unix/at_sysnum_newfstatat_linux.go | 0 .../syscall/unix/at_sysnum_openbsd.go} | 8 +- .../src/internal/syscall/unix/at_wasip1.go | 0 .../src/internal/syscall/unix/constants.go | 18 + .../syscall/unix/copy_file_range_linux.go | 0 .../src/internal/syscall/unix/eaccess_bsd.go | 2 +- .../internal/syscall/unix/eaccess_darwin.go | 31 + .../internal/syscall/unix/eaccess_linux.go | 0 .../internal/syscall/unix/eaccess_openbsd.go | 36 + .../internal/syscall/unix/eaccess_other.go | 2 +- .../syscall/unix/fallocate_freebsd_386.go | 0 .../syscall/unix/fallocate_freebsd_64bit.go | 0 .../syscall/unix/fallocate_freebsd_arm.go | 0 .../src/internal/syscall/unix/fcntl_js.go | 0 .../src/internal/syscall/unix/fcntl_unix.go | 0 .../src/internal/syscall/unix/fcntl_wasip1.go | 0 .../syscall/unix/getentropy_netbsd.go | 0 .../syscall/unix/getentropy_openbsd.go | 0 .../syscall/unix/getentropy_openbsd_mips64.go | 0 .../src/internal/syscall/unix/getrandom.go | 0 .../syscall/unix/getrandom_dragonfly.go | 0 .../syscall/unix/getrandom_freebsd.go | 0 .../internal/syscall/unix/getrandom_linux.go | 0 .../syscall/unix/getrandom_solaris.go | 0 .../src/internal/syscall/unix/ioctl_aix.go | 0 .../syscall/unix/kernel_version_linux.go | 0 .../syscall/unix/kernel_version_other.go | 2 +- .../syscall/unix/kernel_version_solaris.go | 106 + .../src/internal/syscall/unix/net.go | 0 .../src/internal/syscall/unix/net_darwin.go | 0 .../src/internal/syscall/unix/net_js.go | 0 .../src/internal/syscall/unix/net_wasip1.go | 0 .../src/internal/syscall/unix/nofollow_bsd.go | 14 + .../internal/syscall/unix/nofollow_netbsd.go | 10 + .../internal/syscall/unix/nofollow_posix.go | 22 + .../internal/syscall/unix/nonblocking_js.go | 0 .../internal/syscall/unix/nonblocking_unix.go | 0 .../syscall/unix/nonblocking_wasip1.go | 0 .../src/internal/syscall/unix/pidfd_linux.go | 8 + .../src/internal/syscall/unix/pty_darwin.go | 0 .../internal/syscall/unix/siginfo_linux.go | 64 + .../syscall/unix/siginfo_linux_mipsx.go | 12 + .../syscall/unix/siginfo_linux_other.go | 12 + .../internal/syscall/unix/sysnum_linux_386.go | 1 + .../syscall/unix/sysnum_linux_amd64.go | 1 + .../internal/syscall/unix/sysnum_linux_arm.go | 1 + .../syscall/unix/sysnum_linux_generic.go | 1 + .../syscall/unix/sysnum_linux_mips64x.go | 1 + .../syscall/unix/sysnum_linux_mipsx.go | 1 + .../syscall/unix/sysnum_linux_ppc64x.go | 1 + .../syscall/unix/sysnum_linux_s390x.go | 1 + .../internal/syscall/unix/tcsetpgrp_bsd.go | 22 + .../internal/syscall/unix/tcsetpgrp_linux.go | 21 + .../src/internal/syscall/unix/user_darwin.go | 0 .../src/internal/syscall/unix/ya.make | 15 +- .../syscall/windows/memory_windows.go | 0 .../src/internal/syscall/windows/mksyscall.go | 2 +- .../internal/syscall/windows/net_windows.go | 11 - .../internal/syscall/windows/psapi_windows.go | 0 .../internal/syscall/windows/registry/key.go | 0 .../syscall/windows/registry/mksyscall.go | 0 .../syscall/windows/registry/syscall.go | 0 .../syscall/windows/registry/value.go | 0 .../internal/syscall/windows/registry/ya.make | 0 .../windows/registry/zsyscall_windows.go | 0 .../syscall/windows/reparse_windows.go | 3 + .../syscall/windows/security_windows.go | 0 .../syscall/windows/symlink_windows.go | 1 + .../syscall/windows/syscall_windows.go | 100 +- .../internal/syscall/windows/sysdll/sysdll.go | 0 .../internal/syscall/windows/sysdll/ya.make | 0 .../internal/syscall/windows/types_windows.go | 12 + .../syscall/windows/version_windows.go | 113 + .../src/internal/syscall/windows/ya.make | 2 + .../syscall/windows/zsyscall_windows.go | 20 + .../src/internal/testlog/exit.go | 14 +- .../src/internal/testlog/log.go | 0 .../src/internal/testlog/ya.make | 0 .../src/internal/types/errors/code_string.go | 7 +- .../src/internal/types/errors/codes.go | 10 +- .../src/internal/types/errors/generrordocs.go | 0 .../src/internal/types/errors/ya.make | 0 .../src/internal/unsafeheader/unsafeheader.go | 0 .../src/internal/unsafeheader/ya.make | 0 .../go/_std_1.23/src/internal/weak/pointer.go | 83 + .../go/_std_1.23/src/internal/weak/ya.make | 7 + .../src/io/fs/format.go | 0 .../{_std_1.22 => _std_1.23}/src/io/fs/fs.go | 0 .../src/io/fs/glob.go | 0 .../src/io/fs/readdir.go | 7 +- .../src/io/fs/readfile.go | 0 .../src/io/fs/stat.go | 0 .../{_std_1.22 => _std_1.23}/src/io/fs/sub.go | 4 +- .../src/io/fs/walk.go | 0 .../src/io/fs/ya.make | 0 .../go/{_std_1.22 => _std_1.23}/src/io/io.go | 4 +- .../src/io/ioutil/ioutil.go | 7 +- .../src/io/ioutil/tempfile.go | 0 .../src/io/ioutil/ya.make | 0 .../{_std_1.22 => _std_1.23}/src/io/multi.go | 0 .../{_std_1.22 => _std_1.23}/src/io/pipe.go | 0 .../{_std_1.22 => _std_1.23}/src/io/ya.make | 0 contrib/go/_std_1.23/src/iter/iter.go | 453 ++++ contrib/go/_std_1.23/src/iter/ya.make | 7 + .../src/log/internal/internal.go | 0 .../src/log/internal/ya.make | 0 .../{_std_1.22 => _std_1.23}/src/log/log.go | 0 .../src/log/slog/attr.go | 3 +- .../src/log/slog/doc.go | 6 +- .../src/log/slog/handler.go | 0 .../slog/internal/benchmarks/benchmarks.go | 0 .../log/slog/internal/benchmarks/handlers.go | 0 .../src/log/slog/internal/benchmarks/ya.make | 0 .../src/log/slog/internal/buffer/buffer.go | 5 +- .../src/log/slog/internal/buffer/ya.make | 0 .../src/log/slog/internal/ignorepc.go | 0 .../log/slog/internal/slogtest/slogtest.go | 0 .../src/log/slog/internal/slogtest/ya.make | 0 .../src/log/slog/internal/ya.make | 0 .../src/log/slog/json_handler.go | 0 .../src/log/slog/level.go | 0 .../src/log/slog/logger.go | 0 .../src/log/slog/record.go | 0 .../src/log/slog/text_handler.go | 0 .../src/log/slog/value.go | 38 +- .../src/log/slog/ya.make | 0 .../src/log/syslog/doc.go | 0 .../src/log/syslog/syslog.go | 0 .../src/log/syslog/syslog_unix.go | 0 .../src/log/syslog/ya.make | 0 .../{_std_1.22 => _std_1.23}/src/log/ya.make | 0 contrib/go/_std_1.23/src/maps/iter.go | 62 + contrib/go/_std_1.23/src/maps/maps.go | 75 + contrib/go/_std_1.23/src/maps/ya.make | 8 + .../{_std_1.22 => _std_1.23}/src/math/abs.go | 0 .../src/math/acos_s390x.s | 0 .../src/math/acosh.go | 0 .../src/math/acosh_s390x.s | 0 .../src/math/arith_s390x.go | 0 .../{_std_1.22 => _std_1.23}/src/math/asin.go | 0 .../src/math/asin_s390x.s | 0 .../src/math/asinh.go | 0 .../src/math/asinh_s390x.s | 0 .../{_std_1.22 => _std_1.23}/src/math/atan.go | 0 .../src/math/atan2.go | 0 .../src/math/atan2_s390x.s | 0 .../src/math/atan_s390x.s | 0 .../src/math/atanh.go | 0 .../src/math/atanh_s390x.s | 0 .../src/math/big/accuracy_string.go | 0 .../src/math/big/arith.go | 0 .../src/math/big/arith_386.s | 0 .../src/math/big/arith_amd64.go | 0 .../src/math/big/arith_amd64.s | 0 .../src/math/big/arith_arm.s | 0 .../src/math/big/arith_arm64.s | 0 .../go/_std_1.23/src/math/big/arith_decl.go | 98 + .../src/math/big/arith_decl_pure.go | 0 .../src/math/big/arith_decl_s390x.go | 0 .../src/math/big/arith_loong64.s | 0 .../src/math/big/arith_mips64x.s | 0 .../src/math/big/arith_mipsx.s | 0 .../src/math/big/arith_ppc64x.s | 203 +- .../src/math/big/arith_riscv64.s | 0 .../src/math/big/arith_s390x.s | 0 .../src/math/big/arith_wasm.s | 0 .../src/math/big/decimal.go | 0 .../src/math/big/doc.go | 0 .../src/math/big/float.go | 29 +- .../src/math/big/floatconv.go | 0 .../src/math/big/floatmarsh.go | 10 +- .../src/math/big/ftoa.go | 0 .../src/math/big/int.go | 36 +- .../src/math/big/intconv.go | 0 .../src/math/big/intmarsh.go | 0 .../src/math/big/nat.go | 28 +- .../src/math/big/natconv.go | 0 .../src/math/big/natdiv.go | 14 +- .../src/math/big/prime.go | 0 .../src/math/big/rat.go | 14 +- .../src/math/big/ratconv.go | 0 .../src/math/big/ratmarsh.go | 6 +- .../src/math/big/roundingmode_string.go | 0 .../src/math/big/sqrt.go | 0 .../src/math/big/ya.make | 0 .../{_std_1.22 => _std_1.23}/src/math/bits.go | 0 .../src/math/bits/bits.go | 0 .../src/math/bits/bits_errors.go | 0 .../src/math/bits/bits_errors_bootstrap.go | 0 .../src/math/bits/bits_tables.go | 0 .../src/math/bits/make_examples.go | 0 .../src/math/bits/make_tables.go | 0 .../src/math/bits/ya.make | 0 .../{_std_1.22 => _std_1.23}/src/math/cbrt.go | 0 .../src/math/cbrt_s390x.s | 0 .../src/math/cmplx/abs.go | 0 .../src/math/cmplx/asin.go | 0 .../src/math/cmplx/conj.go | 0 .../src/math/cmplx/exp.go | 0 .../src/math/cmplx/isinf.go | 0 .../src/math/cmplx/isnan.go | 0 .../src/math/cmplx/log.go | 0 .../src/math/cmplx/phase.go | 0 .../src/math/cmplx/polar.go | 0 .../src/math/cmplx/pow.go | 0 .../src/math/cmplx/rect.go | 0 .../src/math/cmplx/sin.go | 0 .../src/math/cmplx/sqrt.go | 0 .../src/math/cmplx/tan.go | 0 .../src/math/cmplx/ya.make | 0 .../src/math/const.go | 0 .../src/math/copysign.go | 0 .../src/math/cosh_s390x.s | 0 .../{_std_1.22 => _std_1.23}/src/math/dim.go | 0 .../src/math/dim_amd64.s | 0 .../src/math/dim_arm64.s | 0 .../src/math/dim_asm.go | 0 .../src/math/dim_noasm.go | 0 .../src/math/dim_riscv64.s | 0 .../src/math/dim_s390x.s | 0 .../{_std_1.22 => _std_1.23}/src/math/erf.go | 0 .../src/math/erf_s390x.s | 0 .../src/math/erfc_s390x.s | 0 .../src/math/erfinv.go | 0 .../{_std_1.22 => _std_1.23}/src/math/exp.go | 0 .../src/math/exp2_asm.go | 0 .../src/math/exp2_noasm.go | 0 .../src/math/exp_amd64.go | 0 .../src/math/exp_amd64.s | 0 .../src/math/exp_arm64.s | 0 .../src/math/exp_asm.go | 0 .../src/math/exp_noasm.go | 0 .../src/math/exp_s390x.s | 0 .../src/math/expm1.go | 0 .../src/math/expm1_s390x.s | 0 .../src/math/floor.go | 0 .../src/math/floor_386.s | 0 .../src/math/floor_amd64.s | 0 .../src/math/floor_arm64.s | 0 .../src/math/floor_asm.go | 0 .../src/math/floor_noasm.go | 0 .../src/math/floor_ppc64x.s | 0 .../src/math/floor_s390x.s | 0 .../src/math/floor_wasm.s | 0 .../{_std_1.22 => _std_1.23}/src/math/fma.go | 0 .../src/math/frexp.go | 0 .../src/math/gamma.go | 0 .../src/math/hypot.go | 0 .../src/math/hypot_386.s | 0 .../src/math/hypot_amd64.s | 0 .../src/math/hypot_asm.go | 0 .../src/math/hypot_noasm.go | 0 .../{_std_1.22 => _std_1.23}/src/math/j0.go | 0 .../{_std_1.22 => _std_1.23}/src/math/j1.go | 0 .../{_std_1.22 => _std_1.23}/src/math/jn.go | 0 .../src/math/ldexp.go | 0 .../src/math/lgamma.go | 0 .../{_std_1.22 => _std_1.23}/src/math/log.go | 0 .../src/math/log10.go | 0 .../src/math/log10_s390x.s | 0 .../src/math/log1p.go | 0 .../src/math/log1p_s390x.s | 0 .../src/math/log_amd64.s | 0 .../src/math/log_asm.go | 0 .../src/math/log_s390x.s | 0 .../src/math/log_stub.go | 0 .../{_std_1.22 => _std_1.23}/src/math/logb.go | 0 .../{_std_1.22 => _std_1.23}/src/math/mod.go | 0 .../{_std_1.22 => _std_1.23}/src/math/modf.go | 0 .../src/math/modf_arm64.s | 0 .../src/math/modf_asm.go | 0 .../src/math/modf_noasm.go | 0 .../src/math/modf_ppc64x.s | 0 .../src/math/nextafter.go | 0 .../{_std_1.22 => _std_1.23}/src/math/pow.go | 0 .../src/math/pow10.go | 0 .../src/math/pow_s390x.s | 0 .../src/math/rand/exp.go | 0 .../src/math/rand/gen_cooked.go | 0 .../src/math/rand/normal.go | 0 .../src/math/rand/rand.go | 1 + .../src/math/rand/rng.go | 0 .../go/_std_1.23/src/math/rand/v2/chacha8.go | 110 + .../src/math/rand/v2/exp.go | 0 .../src/math/rand/v2/normal.go | 0 .../src/math/rand/v2/pcg.go | 29 +- .../src/math/rand/v2/rand.go | 12 +- .../src/math/rand/v2/ya.make | 2 - .../src/math/rand/v2/zipf.go | 0 .../src/math/rand/ya.make | 0 .../src/math/rand/zipf.go | 0 .../src/math/remainder.go | 0 .../src/math/signbit.go | 0 .../{_std_1.22 => _std_1.23}/src/math/sin.go | 0 .../src/math/sin_s390x.s | 0 .../src/math/sincos.go | 0 .../{_std_1.22 => _std_1.23}/src/math/sinh.go | 0 .../src/math/sinh_s390x.s | 0 .../{_std_1.22 => _std_1.23}/src/math/sqrt.go | 0 .../src/math/stubs.go | 0 .../src/math/stubs_s390x.s | 0 .../{_std_1.22 => _std_1.23}/src/math/tan.go | 0 .../src/math/tan_s390x.s | 0 .../{_std_1.22 => _std_1.23}/src/math/tanh.go | 0 .../src/math/tanh_s390x.s | 0 .../src/math/trig_reduce.go | 0 .../src/math/unsafe.go | 12 + .../{_std_1.22 => _std_1.23}/src/math/ya.make | 0 .../src/mime/encodedword.go | 2 +- .../src/mime/grammar.go | 0 .../src/mime/mediatype.go | 8 +- .../src/mime/multipart/formdata.go | 20 +- .../src/mime/multipart/multipart.go | 24 +- .../src/mime/multipart/readmimeheader.go | 3 +- .../src/mime/multipart/writer.go | 20 +- .../src/mime/multipart/ya.make | 0 .../src/mime/quotedprintable/reader.go | 0 .../src/mime/quotedprintable/writer.go | 12 +- .../src/mime/quotedprintable/ya.make | 0 .../{_std_1.22 => _std_1.23}/src/mime/type.go | 17 +- .../src/mime/type_dragonfly.go | 0 .../src/mime/type_freebsd.go | 0 .../src/mime/type_openbsd.go | 0 .../src/mime/type_plan9.go | 0 .../src/mime/type_unix.go | 0 .../src/mime/type_windows.go | 0 .../{_std_1.22 => _std_1.23}/src/mime/ya.make | 0 .../src/net/addrselect.go | 2 +- .../src/net/cgo_aix.go | 0 .../src/net/cgo_android.go | 0 .../src/net/cgo_bsd.go | 0 .../src/net/cgo_darwin.go | 0 .../src/net/cgo_linux.go | 0 .../src/net/cgo_netbsd.go | 0 .../src/net/cgo_openbsd.go | 0 .../src/net/cgo_resnew.go | 0 .../src/net/cgo_resold.go | 0 .../src/net/cgo_socknew.go | 0 .../src/net/cgo_sockold.go | 0 .../src/net/cgo_solaris.go | 0 .../src/net/cgo_stub.go | 0 .../src/net/cgo_unix.go | 78 +- .../src/net/cgo_unix_cgo.go | 2 +- .../src/net/cgo_unix_cgo_res.go | 6 +- .../src/net/cgo_unix_cgo_resn.go | 6 +- .../src/net/cgo_unix_syscall.go | 5 +- .../{_std_1.22 => _std_1.23}/src/net/conf.go | 26 +- .../{_std_1.22 => _std_1.23}/src/net/dial.go | 45 +- .../src/net/dnsclient.go | 37 +- .../src/net/dnsclient_unix.go | 84 +- .../src/net/dnsconfig.go | 21 +- .../src/net/dnsconfig_unix.go | 11 +- .../src/net/dnsconfig_windows.go | 27 +- .../src/net/error_plan9.go | 0 .../src/net/error_posix.go | 0 .../src/net/error_unix.go | 0 .../src/net/error_windows.go | 0 .../src/net/fd_fake.go | 0 .../{_std_1.22 => _std_1.23}/src/net/fd_js.go | 0 .../src/net/fd_plan9.go | 0 .../src/net/fd_posix.go | 0 .../src/net/fd_unix.go | 0 .../src/net/fd_wasip1.go | 0 .../src/net/fd_windows.go | 8 +- .../{_std_1.22 => _std_1.23}/src/net/file.go | 0 .../src/net/file_plan9.go | 2 +- .../src/net/file_stub.go | 0 .../src/net/file_unix.go | 2 +- .../src/net/file_wasip1.go | 0 .../src/net/file_windows.go | 0 .../{_std_1.22 => _std_1.23}/src/net/hook.go | 4 +- .../src/net/hook_plan9.go | 0 .../src/net/hook_unix.go | 0 .../src/net/hook_windows.go | 0 .../{_std_1.22 => _std_1.23}/src/net/hosts.go | 0 .../src/net/http/cgi/cgi_main.go | 6 +- .../src/net/http/cgi/child.go | 0 .../src/net/http/cgi/host.go | 2 +- .../src/net/http/cgi/ya.make | 0 .../src/net/http/client.go | 80 +- .../src/net/http/clone.go | 47 + .../src/net/http/cookie.go | 279 ++- .../src/net/http/cookiejar/jar.go | 22 +- .../src/net/http/cookiejar/punycode.go | 0 .../src/net/http/cookiejar/ya.make | 0 .../src/net/http/doc.go | 0 .../src/net/http/fcgi/child.go | 0 .../src/net/http/fcgi/fcgi.go | 0 .../src/net/http/fcgi/ya.make | 0 .../src/net/http/filetransport.go | 2 +- .../src/net/http/fs.go | 101 +- .../src/net/http/h2_bundle.go | 401 +++- .../src/net/http/h2_error.go | 0 .../src/net/http/header.go | 12 +- .../src/net/http/http.go | 0 .../src/net/http/httptest/httptest.go | 11 +- .../src/net/http/httptest/recorder.go | 0 .../src/net/http/httptest/server.go | 1 + .../src/net/http/httptest/ya.make | 0 .../src/net/http/httptrace/trace.go | 0 .../src/net/http/httptrace/ya.make | 0 .../src/net/http/httputil/dump.go | 0 .../src/net/http/httputil/httputil.go | 0 .../src/net/http/httputil/persist.go | 0 .../src/net/http/httputil/reverseproxy.go | 14 + .../src/net/http/httputil/ya.make | 0 .../src/net/http/internal/ascii/print.go | 0 .../src/net/http/internal/ascii/ya.make | 0 .../src/net/http/internal/chunked.go | 19 +- .../net/http/internal/testcert/testcert.go | 65 + .../src/net/http/internal/testcert/ya.make | 0 .../src/net/http/internal/ya.make | 0 .../src/net/http/jar.go | 0 .../src/net/http/mapping.go | 0 .../src/net/http/method.go | 0 .../src/net/http/omithttp2.go | 0 .../src/net/http/pattern.go | 7 +- .../src/net/http/pprof/pprof.go | 44 +- .../src/net/http/pprof/ya.make | 0 .../src/net/http/request.go | 39 +- .../src/net/http/response.go | 0 .../src/net/http/responsecontroller.go | 0 .../src/net/http/roundtrip.go | 13 + .../src/net/http/roundtrip_js.go | 0 .../src/net/http/routing_index.go | 0 .../src/net/http/routing_tree.go | 8 +- .../src/net/http/servemux121.go | 4 + .../src/net/http/server.go | 200 +- .../src/net/http/sniff.go | 0 .../src/net/http/socks_bundle.go | 0 .../src/net/http/status.go | 0 .../src/net/http/transfer.go | 52 +- .../src/net/http/transport.go | 572 ++--- .../src/net/http/transport_default_other.go | 0 .../src/net/http/transport_default_wasm.go | 0 .../src/net/http/triv.go | 0 .../src/net/http/ya.make | 0 .../src/net/interface.go | 11 + .../src/net/interface_aix.go | 0 .../src/net/interface_bsd.go | 0 .../src/net/interface_bsdvar.go | 0 .../src/net/interface_darwin.go | 0 .../src/net/interface_freebsd.go | 0 .../src/net/interface_linux.go | 0 .../src/net/interface_plan9.go | 3 +- .../src/net/interface_solaris.go | 0 .../src/net/interface_stub.go | 0 .../src/net/interface_windows.go | 3 +- .../src/net/internal/socktest/switch.go | 0 .../src/net/internal/socktest/switch_posix.go | 0 .../src/net/internal/socktest/switch_stub.go | 0 .../src/net/internal/socktest/switch_unix.go | 0 .../net/internal/socktest/switch_windows.go | 0 .../src/net/internal/socktest/sys_cloexec.go | 0 .../src/net/internal/socktest/sys_unix.go | 0 .../src/net/internal/socktest/sys_windows.go | 0 .../src/net/internal/socktest/ya.make | 0 .../src/net/internal/ya.make | 0 .../go/{_std_1.22 => _std_1.23}/src/net/ip.go | 9 +- .../src/net/iprawsock.go | 0 .../src/net/iprawsock_plan9.go | 0 .../src/net/iprawsock_posix.go | 6 +- .../src/net/ipsock.go | 12 + .../src/net/ipsock_plan9.go | 0 .../src/net/ipsock_posix.go | 24 + .../src/net/lookup.go | 27 +- .../src/net/lookup_plan9.go | 28 +- .../src/net/lookup_unix.go | 0 .../src/net/lookup_windows.go | 134 +- .../{_std_1.22 => _std_1.23}/src/net/mac.go | 0 .../src/net/mail/message.go | 70 +- .../src/net/mail/ya.make | 0 .../src/net/mptcpsock_linux.go | 0 .../src/net/mptcpsock_stub.go | 0 .../{_std_1.22 => _std_1.23}/src/net/net.go | 86 +- .../src/net/net_fake.go | 51 +- .../src/net/netcgo_off.go | 0 .../src/net/netcgo_on.go | 0 .../src/net/netgo_netcgo.go | 0 .../src/net/netgo_off.go | 0 .../src/net/netgo_on.go | 0 .../src/net/netip/netip.go | 215 +- .../src/net/netip/uint128.go | 0 .../src/net/netip/ya.make | 1 - .../{_std_1.22 => _std_1.23}/src/net/nss.go | 0 .../{_std_1.22 => _std_1.23}/src/net/parse.go | 11 - .../{_std_1.22 => _std_1.23}/src/net/pipe.go | 0 .../{_std_1.22 => _std_1.23}/src/net/port.go | 0 .../src/net/port_unix.go | 0 .../src/net/rawconn.go | 0 .../src/net/rlimit_js.go | 0 .../src/net/rlimit_unix.go | 0 .../src/net/rpc/client.go | 0 .../src/net/rpc/debug.go | 15 +- .../src/net/rpc/jsonrpc/client.go | 0 .../src/net/rpc/jsonrpc/server.go | 0 .../src/net/rpc/jsonrpc/ya.make | 0 .../src/net/rpc/server.go | 0 .../src/net/rpc/ya.make | 0 .../src/net/sendfile_linux.go | 2 + .../src/net/sendfile_stub.go | 4 +- .../src/net/sendfile_unix_alt.go | 16 +- .../src/net/sendfile_windows.go | 2 + .../src/net/smtp/auth.go | 0 .../src/net/smtp/smtp.go | 4 +- .../src/net/smtp/ya.make | 0 .../src/net/sock_bsd.go | 0 contrib/go/_std_1.23/src/net/sock_cloexec.go | 25 + .../src/net/sock_cloexec_solaris.go} | 27 +- .../src/net/sock_linux.go | 0 .../src/net/sock_plan9.go | 0 .../src/net/sock_posix.go | 0 .../src/net/sock_stub.go | 0 .../src/net/sock_windows.go | 0 .../src/net/sockaddr_posix.go | 0 .../src/net/sockopt_aix.go | 0 .../src/net/sockopt_bsd.go | 0 .../src/net/sockopt_fake.go | 0 .../src/net/sockopt_linux.go | 0 .../src/net/sockopt_plan9.go | 0 .../src/net/sockopt_posix.go | 0 .../src/net/sockopt_solaris.go | 0 .../src/net/sockopt_windows.go | 0 .../src/net/sockoptip_bsdvar.go | 0 .../src/net/sockoptip_linux.go | 0 .../src/net/sockoptip_posix.go | 0 .../src/net/sockoptip_stub.go | 0 .../src/net/sockoptip_windows.go | 0 .../src/net/splice_linux.go | 10 +- .../src/net/splice_stub.go | 0 .../src/net/sys_cloexec.go | 0 .../src/net/tcpsock.go | 65 +- .../src/net/tcpsock_plan9.go | 4 +- .../src/net/tcpsock_posix.go | 10 +- .../go/_std_1.23/src/net/tcpsock_solaris.go | 38 + contrib/go/_std_1.23/src/net/tcpsock_unix.go | 31 + .../go/_std_1.23/src/net/tcpsock_windows.go | 36 + .../go/_std_1.23/src/net/tcpsockopt_darwin.go | 57 + .../_std_1.23/src/net/tcpsockopt_openbsd.go | 37 + .../src/net/tcpsockopt_plan9.go | 22 +- .../src/net/tcpsockopt_posix.go | 0 .../_std_1.23/src/net/tcpsockopt_solaris.go | 119 + .../src/net/tcpsockopt_stub.go | 10 +- .../go/_std_1.23/src/net/tcpsockopt_unix.go | 53 + .../_std_1.23/src/net/tcpsockopt_windows.go | 118 + .../src/net/textproto/header.go | 0 .../src/net/textproto/pipeline.go | 0 .../src/net/textproto/reader.go | 15 +- .../src/net/textproto/textproto.go | 0 .../src/net/textproto/writer.go | 0 .../src/net/textproto/ya.make | 0 .../src/net/udpsock.go | 0 .../src/net/udpsock_plan9.go | 0 .../src/net/udpsock_posix.go | 10 +- .../src/net/unixsock.go | 0 .../src/net/unixsock_plan9.go | 0 .../src/net/unixsock_posix.go | 10 +- .../src/net/unixsock_readmsg_cloexec.go | 0 .../src/net/unixsock_readmsg_cmsg_cloexec.go | 0 .../src/net/unixsock_readmsg_other.go | 0 .../src/net/url/url.go | 41 +- .../src/net/url/ya.make | 0 .../src/net/writev_unix.go | 0 .../{_std_1.22 => _std_1.23}/src/net/ya.make | 76 +- .../go/{_std_1.22 => _std_1.23}/src/os/dir.go | 86 +- .../src/os/dir_darwin.go | 16 +- .../src/os/dir_plan9.go | 10 +- .../src/os/dir_unix.go | 43 +- .../src/os/dir_windows.go | 104 +- .../src/os/dirent_aix.go | 0 .../src/os/dirent_dragonfly.go | 0 .../src/os/dirent_freebsd.go | 0 .../src/os/dirent_js.go | 0 .../src/os/dirent_linux.go | 0 .../src/os/dirent_netbsd.go | 0 .../src/os/dirent_openbsd.go | 0 .../src/os/dirent_solaris.go | 0 .../src/os/dirent_wasip1.go | 0 .../go/{_std_1.22 => _std_1.23}/src/os/env.go | 4 +- .../{_std_1.22 => _std_1.23}/src/os/error.go | 28 +- .../src/os/error_errno.go | 0 .../src/os/error_plan9.go | 0 contrib/go/_std_1.23/src/os/exec.go | 404 ++++ .../src/os/exec/exec.go | 117 +- .../src/os/exec/exec_plan9.go | 0 .../src/os/exec/exec_unix.go | 0 .../src/os/exec/exec_windows.go | 0 .../os/exec/internal/fdtest/exists_plan9.go | 0 .../os/exec/internal/fdtest/exists_unix.go | 0 .../os/exec/internal/fdtest/exists_windows.go | 0 .../src/os/exec/internal/fdtest/ya.make | 0 .../src/os/exec/internal/ya.make | 0 .../src/os/exec/lp_plan9.go | 2 +- .../src/os/exec/lp_unix.go | 2 +- .../src/os/exec/lp_wasm.go | 0 .../src/os/exec/lp_windows.go | 2 +- .../src/os/exec/read3.go | 0 .../src/os/exec/ya.make | 0 contrib/go/_std_1.23/src/os/exec_linux.go | 13 + contrib/go/_std_1.23/src/os/exec_nohandle.go | 9 + .../src/os/exec_plan9.go | 25 +- .../src/os/exec_posix.go | 14 +- contrib/go/_std_1.23/src/os/exec_unix.go | 178 ++ .../src/os/exec_windows.go | 46 +- .../src/os/executable.go | 2 +- .../src/os/executable_darwin.go | 6 +- .../src/os/executable_dragonfly.go | 0 .../src/os/executable_freebsd.go | 0 .../src/os/executable_path.go | 0 .../src/os/executable_plan9.go | 0 .../src/os/executable_procfs.go | 11 +- .../src/os/executable_solaris.go | 6 +- .../src/os/executable_sysctl.go | 0 .../src/os/executable_wasm.go | 0 .../src/os/executable_windows.go | 0 .../{_std_1.22 => _std_1.23}/src/os/file.go | 46 +- .../src/os/file_mutex_plan9.go | 0 .../src/os/file_open_unix.go | 0 .../src/os/file_open_wasip1.go | 0 .../src/os/file_plan9.go | 31 +- .../src/os/file_posix.go | 26 +- .../src/os/file_unix.go | 131 +- .../src/os/file_wasip1.go | 0 .../src/os/file_windows.go | 60 +- .../{_std_1.22 => _std_1.23}/src/os/getwd.go | 0 .../{_std_1.22 => _std_1.23}/src/os/path.go | 5 +- .../src/os/path_plan9.go | 4 - .../src/os/path_unix.go | 22 - contrib/go/_std_1.23/src/os/path_windows.go | 152 ++ contrib/go/_std_1.23/src/os/pidfd_linux.go | 210 ++ contrib/go/_std_1.23/src/os/pidfd_other.go | 31 + .../src/os/pipe2_unix.go | 2 +- .../src/os/pipe_unix.go | 2 +- .../src/os/pipe_wasm.go | 0 .../{_std_1.22 => _std_1.23}/src/os/proc.go | 2 +- .../src/os/rawconn.go | 0 .../src/os/removeall_at.go | 4 +- .../src/os/removeall_noat.go | 0 .../src/os/signal/doc.go | 12 +- .../src/os/signal/sig.s | 0 .../src/os/signal/signal.go | 12 +- .../src/os/signal/signal_plan9.go | 0 .../src/os/signal/signal_unix.go | 0 .../src/os/signal/ya.make | 0 .../{_std_1.22 => _std_1.23}/src/os/stat.go | 8 +- .../src/os/stat_aix.go | 3 +- .../src/os/stat_darwin.go | 3 +- .../src/os/stat_dragonfly.go | 3 +- .../src/os/stat_freebsd.go | 3 +- .../src/os/stat_js.go | 3 +- .../src/os/stat_linux.go | 3 +- .../src/os/stat_netbsd.go | 3 +- .../src/os/stat_openbsd.go | 3 +- .../src/os/stat_plan9.go | 0 .../src/os/stat_solaris.go | 3 +- .../src/os/stat_unix.go | 6 +- .../src/os/stat_wasip1.go | 3 +- .../src/os/stat_windows.go | 44 +- .../src/os/sticky_bsd.go | 0 .../src/os/sticky_notbsd.go | 0 .../go/{_std_1.22 => _std_1.23}/src/os/sys.go | 0 .../src/os/sys_aix.go | 0 .../src/os/sys_bsd.go | 0 .../{_std_1.22 => _std_1.23}/src/os/sys_js.go | 0 .../src/os/sys_linux.go | 0 .../src/os/sys_plan9.go | 0 .../src/os/sys_solaris.go | 0 .../src/os/sys_unix.go | 0 .../src/os/sys_wasip1.go | 0 .../src/os/sys_windows.go | 0 .../src/os/tempfile.go | 5 +- .../{_std_1.22 => _std_1.23}/src/os/types.go | 10 +- .../src/os/types_plan9.go | 0 .../src/os/types_unix.go | 0 .../src/os/types_windows.go | 156 +- .../src/os/user/cgo_listgroups_unix.go | 0 .../src/os/user/cgo_lookup_cgo.go | 0 .../src/os/user/cgo_lookup_syscall.go | 0 .../src/os/user/cgo_lookup_unix.go | 24 +- .../src/os/user/getgrouplist_syscall.go | 0 .../src/os/user/getgrouplist_unix.go | 0 .../src/os/user/listgroups_stub.go | 0 .../src/os/user/listgroups_unix.go | 0 .../src/os/user/lookup.go | 8 +- .../src/os/user/lookup_android.go | 0 .../src/os/user/lookup_plan9.go | 0 .../src/os/user/lookup_stubs.go | 0 .../src/os/user/lookup_unix.go | 0 .../src/os/user/lookup_windows.go | 0 .../src/os/user/user.go | 8 +- .../src/os/user/ya.make | 0 .../src/os/wait6_dragonfly.go | 0 .../src/os/wait6_freebsd64.go | 0 .../src/os/wait6_freebsd_386.go | 0 .../src/os/wait6_freebsd_arm.go | 0 .../src/os/wait6_netbsd.go | 0 .../src/os/wait_unimp.go | 0 .../src/os/wait_wait6.go | 0 .../src/os/wait_waitid.go | 0 .../{_std_1.22 => _std_1.23}/src/os/ya.make | 11 +- .../src/os/zero_copy_linux.go | 17 +- .../src/os/zero_copy_stub.go | 0 .../src/path/filepath/match.go | 7 +- .../src/path/filepath/path.go | 228 +- .../src/path/filepath/path_plan9.go | 19 +- .../src/path/filepath/path_unix.go | 19 +- .../src/path/filepath/path_windows.go | 114 + .../src/path/filepath/symlink.go | 9 +- .../src/path/filepath/symlink_plan9.go | 0 .../src/path/filepath/symlink_unix.go | 0 .../src/path/filepath/symlink_windows.go | 0 .../src/path/filepath/ya.make | 1 - .../src/path/match.go | 0 .../{_std_1.22 => _std_1.23}/src/path/path.go | 0 .../{_std_1.22 => _std_1.23}/src/path/ya.make | 0 .../src/reflect/abi.go | 2 +- .../src/reflect/arena.go | 4 +- .../src/reflect/asm_386.s | 0 .../src/reflect/asm_amd64.s | 0 .../src/reflect/asm_arm.s | 0 .../src/reflect/asm_arm64.s | 0 .../src/reflect/asm_loong64.s | 10 - .../src/reflect/asm_mips64x.s | 0 .../src/reflect/asm_mipsx.s | 0 .../src/reflect/asm_ppc64x.s | 0 .../src/reflect/asm_riscv64.s | 0 .../src/reflect/asm_s390x.s | 0 .../src/reflect/asm_wasm.s | 0 .../go/_std_1.23/src/reflect/badlinkname.go | 130 ++ .../src/reflect/deepequal.go | 2 +- .../src/reflect/float32reg_generic.go | 0 .../src/reflect/float32reg_ppc64x.s | 0 .../src/reflect/float32reg_riscv64.s | 0 .../src/reflect/internal/example1/example.go | 0 .../src/reflect/internal/example1/ya.make | 0 .../src/reflect/internal/example2/example.go | 0 .../src/reflect/internal/example2/ya.make | 0 .../src/reflect/internal/ya.make | 0 contrib/go/_std_1.23/src/reflect/iter.go | 173 ++ .../src/reflect/makefunc.go | 6 +- .../src/reflect/stubs_ppc64x.go | 0 .../src/reflect/stubs_riscv64.go | 0 .../src/reflect/swapper.go | 2 +- .../src/reflect/type.go | 343 ++- .../src/reflect/value.go | 152 +- .../src/reflect/visiblefields.go | 0 .../src/reflect/ya.make | 4 + .../src/regexp/backtrack.go | 0 .../src/regexp/exec.go | 0 .../src/regexp/onepass.go | 13 +- .../src/regexp/regexp.go | 25 +- .../src/regexp/syntax/compile.go | 0 .../src/regexp/syntax/doc.go | 10 +- .../src/regexp/syntax/make_perl_groups.pl | 27 +- .../src/regexp/syntax/op_string.go | 0 .../src/regexp/syntax/parse.go | 14 +- .../src/regexp/syntax/perl_groups.go | 3 +- .../src/regexp/syntax/prog.go | 6 +- .../src/regexp/syntax/regexp.go | 19 +- .../src/regexp/syntax/simplify.go | 0 .../src/regexp/syntax/ya.make | 0 .../src/regexp/ya.make | 0 .../src/runtime/HACKING.md | 2 +- .../src/runtime/Makefile | 0 .../src/runtime/alg.go | 124 +- .../src/runtime/arena.go | 267 ++- .../src/runtime/asan.go | 2 + .../src/runtime/asan/asan.go | 0 .../src/runtime/asan/ya.make | 0 .../src/runtime/asan0.go | 0 .../src/runtime/asan_amd64.s | 0 .../src/runtime/asan_arm64.s | 0 .../src/runtime/asan_loong64.s | 0 .../src/runtime/asan_ppc64le.s | 0 .../src/runtime/asan_riscv64.s | 0 .../src/runtime/asm.s | 19 - .../src/runtime/asm_386.s | 50 +- .../src/runtime/asm_amd64.h | 0 .../src/runtime/asm_amd64.s | 7 +- .../src/runtime/asm_arm.s | 39 +- .../src/runtime/asm_arm64.s | 3 +- .../src/runtime/asm_loong64.s | 135 +- .../src/runtime/asm_mips64x.s | 0 .../src/runtime/asm_mipsx.s | 37 +- .../src/runtime/asm_ppc64x.h | 0 .../src/runtime/asm_ppc64x.s | 32 +- .../src/runtime/asm_riscv64.s | 0 .../src/runtime/asm_s390x.s | 39 +- .../src/runtime/asm_wasm.s | 0 .../src/runtime/atomic_arm64.s | 0 .../src/runtime/atomic_loong64.s | 0 .../src/runtime/atomic_mips64x.s | 0 .../src/runtime/atomic_mipsx.s | 0 .../src/runtime/atomic_pointer.go | 16 +- .../src/runtime/atomic_ppc64x.s | 0 .../src/runtime/atomic_riscv64.s | 0 .../src/runtime/auxv_none.go | 0 .../go/_std_1.23/src/runtime/badlinkname.go | 22 + .../src/runtime/badlinkname_linux.go | 17 + .../src/runtime/cgo.go | 19 + .../src/runtime/cgo/abi_amd64.h | 0 .../src/runtime/cgo/abi_arm64.h | 0 .../src/runtime/cgo/abi_loong64.h | 0 .../src/runtime/cgo/abi_ppc64x.h | 0 .../src/runtime/cgo/asm_386.s | 0 .../src/runtime/cgo/asm_amd64.s | 0 .../src/runtime/cgo/asm_arm.s | 0 .../src/runtime/cgo/asm_arm64.s | 0 .../src/runtime/cgo/asm_loong64.s | 0 .../src/runtime/cgo/asm_mips64x.s | 0 .../src/runtime/cgo/asm_mipsx.s | 0 .../src/runtime/cgo/asm_ppc64x.s | 0 .../src/runtime/cgo/asm_riscv64.s | 0 .../src/runtime/cgo/asm_s390x.s | 0 .../src/runtime/cgo/asm_wasm.s | 0 .../src/runtime/cgo/callbacks.go | 0 .../src/runtime/cgo/callbacks_aix.go | 0 .../src/runtime/cgo/callbacks_traceback.go | 0 .../src/runtime/cgo/cgo.go | 3 +- .../src/runtime/cgo/dragonfly.go | 0 .../src/runtime/cgo/freebsd.go | 0 .../src/runtime/cgo/gcc_386.S | 0 .../src/runtime/cgo/gcc_aix_ppc64.S | 0 .../src/runtime/cgo/gcc_aix_ppc64.c | 0 .../src/runtime/cgo/gcc_amd64.S | 0 .../src/runtime/cgo/gcc_android.c | 0 .../src/runtime/cgo/gcc_arm.S | 0 .../src/runtime/cgo/gcc_arm64.S | 0 .../src/runtime/cgo/gcc_context.c | 0 .../src/runtime/cgo/gcc_darwin_amd64.c | 0 .../src/runtime/cgo/gcc_darwin_arm64.c | 24 +- .../src/runtime/cgo/gcc_dragonfly_amd64.c | 0 .../src/runtime/cgo/gcc_fatalf.c | 0 .../src/runtime/cgo/gcc_freebsd.c | 0 .../src/runtime/cgo/gcc_freebsd_amd64.c | 0 .../src/runtime/cgo/gcc_freebsd_sigaction.c | 0 .../src/runtime/cgo/gcc_libinit.c | 11 +- .../src/runtime/cgo/gcc_libinit_windows.c | 4 +- .../src/runtime/cgo/gcc_linux.c | 0 .../src/runtime/cgo/gcc_linux_amd64.c | 0 .../src/runtime/cgo/gcc_linux_arm64.c | 0 .../src/runtime/cgo/gcc_linux_ppc64x.S | 0 .../src/runtime/cgo/gcc_linux_s390x.c | 0 .../src/runtime/cgo/gcc_loong64.S | 0 .../src/runtime/cgo/gcc_mips64x.S | 0 .../src/runtime/cgo/gcc_mipsx.S | 0 .../src/runtime/cgo/gcc_mmap.c | 0 .../src/runtime/cgo/gcc_netbsd.c | 0 .../src/runtime/cgo/gcc_openbsd.c | 0 .../src/runtime/cgo/gcc_ppc64x.c | 0 .../src/runtime/cgo/gcc_riscv64.S | 0 .../src/runtime/cgo/gcc_s390x.S | 0 .../src/runtime/cgo/gcc_setenv.c | 0 .../src/runtime/cgo/gcc_sigaction.c | 0 .../src/runtime/cgo/gcc_signal2_ios_arm64.c | 0 .../src/runtime/cgo/gcc_signal_ios_arm64.c | 2 +- .../src/runtime/cgo/gcc_signal_ios_nolldb.c | 0 .../src/runtime/cgo/gcc_solaris_amd64.c | 0 .../src/runtime/cgo/gcc_stack_darwin.c | 0 .../src/runtime/cgo/gcc_stack_unix.c | 7 +- .../src/runtime/cgo/gcc_stack_windows.c | 0 .../src/runtime/cgo/gcc_traceback.c | 0 .../src/runtime/cgo/gcc_util.c | 0 .../src/runtime/cgo/gcc_windows_386.c | 0 .../src/runtime/cgo/gcc_windows_amd64.c | 0 .../src/runtime/cgo/gcc_windows_arm64.c | 0 .../src/runtime/cgo/handle.go | 0 .../src/runtime/cgo/iscgo.go | 0 .../src/runtime/cgo/libcgo.h | 2 +- .../src/runtime/cgo/libcgo_unix.h | 0 .../src/runtime/cgo/libcgo_windows.h | 0 .../src/runtime/cgo/linux.go | 0 .../src/runtime/cgo/linux_syscall.c | 0 .../src/runtime/cgo/mmap.go | 0 .../src/runtime/cgo/netbsd.go | 0 .../src/runtime/cgo/openbsd.go | 0 .../src/runtime/cgo/setenv.go | 0 .../src/runtime/cgo/sigaction.go | 0 .../src/runtime/cgo/signal_ios_arm64.go | 0 .../src/runtime/cgo/signal_ios_arm64.s | 0 .../src/runtime/cgo/ya.make | 0 .../src/runtime/cgo_mmap.go | 0 .../src/runtime/cgo_ppc64x.go | 0 .../src/runtime/cgo_sigaction.go | 0 .../src/runtime/cgocall.go | 186 +- .../src/runtime/cgocallback.go | 0 .../src/runtime/cgocheck.go | 48 +- .../src/runtime/chan.go | 108 +- .../src/runtime/checkptr.go | 12 +- .../src/runtime/compiler.go | 0 .../src/runtime/complex.go | 0 .../src/runtime/coro.go | 100 +- .../src/runtime/coverage/coverage.go | 66 + .../go/_std_1.23/src/runtime/coverage/ya.make | 9 + .../src/runtime/covercounter.go | 4 +- contrib/go/_std_1.23/src/runtime/covermeta.go | 20 + .../src/runtime/cpuflags.go | 0 .../src/runtime/cpuflags_amd64.go | 0 .../src/runtime/cpuflags_arm64.go | 0 .../src/runtime/cpuprof.go | 21 +- .../src/runtime/cputicks.go | 0 .../src/runtime/create_file_nounix.go | 0 .../src/runtime/create_file_unix.go | 0 .../src/runtime/debug.go | 21 +- .../src/runtime/debug/debug.s | 0 .../src/runtime/debug/garbage.go | 8 +- .../src/runtime/debug/mod.go | 0 .../go/_std_1.23/src/runtime/debug/stack.go | 93 + .../src/runtime/debug/stubs.go | 0 .../src/runtime/debug/ya.make | 0 .../src/runtime/debugcall.go | 16 +- .../src/runtime/debuglog.go | 7 +- .../src/runtime/debuglog_off.go | 0 .../src/runtime/debuglog_on.go | 0 .../src/runtime/defs1_linux.go | 0 .../src/runtime/defs1_netbsd_386.go | 5 + .../src/runtime/defs1_netbsd_amd64.go | 5 + .../src/runtime/defs1_netbsd_arm.go | 5 + .../src/runtime/defs1_netbsd_arm64.go | 5 + .../src/runtime/defs1_solaris_amd64.go | 0 .../src/runtime/defs2_linux.go | 0 .../src/runtime/defs3_linux.go | 0 .../src/runtime/defs_aix.go | 0 .../src/runtime/defs_aix_ppc64.go | 0 .../src/runtime/defs_arm_linux.go | 0 .../src/runtime/defs_darwin.go | 5 + .../src/runtime/defs_darwin_amd64.go | 5 + .../src/runtime/defs_darwin_arm64.go | 5 + .../src/runtime/defs_dragonfly.go | 5 + .../src/runtime/defs_dragonfly_amd64.go | 5 + .../src/runtime/defs_freebsd.go | 5 + .../src/runtime/defs_freebsd_386.go | 5 + .../src/runtime/defs_freebsd_amd64.go | 5 + .../src/runtime/defs_freebsd_arm.go | 5 + .../src/runtime/defs_freebsd_arm64.go | 5 + .../src/runtime/defs_freebsd_riscv64.go | 5 + .../src/runtime/defs_illumos_amd64.go | 0 .../src/runtime/defs_linux.go | 0 .../src/runtime/defs_linux_386.go | 0 .../src/runtime/defs_linux_amd64.go | 0 .../src/runtime/defs_linux_arm.go | 0 .../src/runtime/defs_linux_arm64.go | 0 .../src/runtime/defs_linux_loong64.go | 0 .../src/runtime/defs_linux_mips64x.go | 0 .../src/runtime/defs_linux_mipsx.go | 0 .../src/runtime/defs_linux_ppc64.go | 0 .../src/runtime/defs_linux_ppc64le.go | 0 .../src/runtime/defs_linux_riscv64.go | 0 .../src/runtime/defs_linux_s390x.go | 0 .../src/runtime/defs_netbsd.go | 5 + .../src/runtime/defs_netbsd_386.go | 0 .../src/runtime/defs_netbsd_amd64.go | 0 .../src/runtime/defs_netbsd_arm.go | 0 .../src/runtime/defs_openbsd.go | 0 .../src/runtime/defs_openbsd_386.go | 0 .../src/runtime/defs_openbsd_amd64.go | 0 .../src/runtime/defs_openbsd_arm.go | 0 .../src/runtime/defs_openbsd_arm64.go | 0 .../src/runtime/defs_openbsd_mips64.go | 0 .../src/runtime/defs_openbsd_ppc64.go | 0 .../src/runtime/defs_openbsd_riscv64.go | 0 .../src/runtime/defs_plan9_386.go | 0 .../src/runtime/defs_plan9_amd64.go | 0 .../src/runtime/defs_plan9_arm.go | 0 .../src/runtime/defs_solaris.go | 0 .../src/runtime/defs_solaris_amd64.go | 0 .../src/runtime/defs_windows.go | 10 + .../src/runtime/defs_windows_386.go | 0 .../src/runtime/defs_windows_amd64.go | 0 .../src/runtime/defs_windows_arm.go | 0 .../src/runtime/defs_windows_arm64.go | 0 .../src/runtime/duff_386.s | 0 .../src/runtime/duff_amd64.s | 0 .../src/runtime/duff_arm.s | 0 .../src/runtime/duff_arm64.s | 0 .../src/runtime/duff_loong64.s | 0 .../src/runtime/duff_mips64x.s | 0 .../src/runtime/duff_ppc64x.s | 0 .../src/runtime/duff_riscv64.s | 0 .../src/runtime/duff_s390x.s | 0 .../src/runtime/env_plan9.go | 0 .../src/runtime/env_posix.go | 21 +- .../src/runtime/error.go | 74 +- .../src/runtime/extern.go | 20 +- .../src/runtime/fastlog2.go | 0 .../src/runtime/fastlog2table.go | 0 .../src/runtime/fds_nonunix.go | 0 .../src/runtime/fds_unix.go | 0 .../src/runtime/float.go | 0 .../src/runtime/funcdata.h | 0 .../src/runtime/go_tls.h | 0 .../src/runtime/hash32.go | 0 .../src/runtime/hash64.go | 20 +- .../src/runtime/heapdump.go | 38 +- .../src/runtime/histogram.go | 2 +- .../src/runtime/iface.go | 95 +- .../src/runtime/internal/math/math.go | 0 .../src/runtime/internal/math/ya.make | 0 .../internal/startlinetest/func_amd64.go | 0 .../internal/startlinetest/func_amd64.s | 0 .../runtime/internal/startlinetest/ya.make | 0 .../src/runtime/internal/sys/consts.go | 0 .../src/runtime/internal/sys/consts_norace.go | 0 .../src/runtime/internal/sys/consts_race.go | 0 .../src/runtime/internal/sys/intrinsics.go | 0 .../src/runtime/internal/sys/nih.go | 0 .../src/runtime/internal/sys/sys.go | 0 .../src/runtime/internal/sys/ya.make | 0 .../src/runtime/internal/sys/zversion.go | 0 .../src/runtime/internal/wasitest/ya.make | 0 .../src/runtime/internal/ya.make | 0 .../src/runtime/lfstack.go | 2 +- .../src/runtime/libfuzzer.go | 0 .../src/runtime/libfuzzer_amd64.s | 0 .../src/runtime/libfuzzer_arm64.s | 0 contrib/go/_std_1.23/src/runtime/linkname.go | 34 + .../go/_std_1.23/src/runtime/linkname_unix.go | 12 + .../src/runtime/lock_futex.go | 2 +- .../src/runtime/lock_js.go | 0 .../src/runtime/lock_sema.go | 2 +- .../src/runtime/lock_wasip1.go | 0 contrib/go/_std_1.23/src/runtime/lockrank.go | 227 ++ .../src/runtime/lockrank_off.go | 9 +- .../src/runtime/lockrank_on.go | 18 +- .../src/runtime/malloc.go | 175 +- .../src/runtime/map.go | 319 ++- .../src/runtime/map_fast32.go | 79 +- .../src/runtime/map_fast64.go | 81 +- .../src/runtime/map_faststr.go | 92 +- .../src/runtime/mbarrier.go | 72 +- .../src/runtime/mbitmap.go} | 1036 ++++++--- .../src/runtime/mcache.go | 2 +- .../src/runtime/mcentral.go | 2 +- .../src/runtime/mcheckmark.go | 6 +- .../src/runtime/mem.go | 0 .../src/runtime/mem_aix.go | 0 .../src/runtime/mem_bsd.go | 0 .../src/runtime/mem_darwin.go | 0 .../src/runtime/mem_js.go | 0 .../src/runtime/mem_linux.go | 5 +- .../src/runtime/mem_plan9.go | 0 .../src/runtime/mem_sbrk.go | 0 .../src/runtime/mem_wasip1.go | 0 .../src/runtime/mem_wasm.go | 0 .../src/runtime/mem_windows.go | 0 .../src/runtime/memclr_386.s | 0 .../src/runtime/memclr_amd64.s | 0 .../src/runtime/memclr_arm.s | 0 .../src/runtime/memclr_arm64.s | 0 .../src/runtime/memclr_loong64.s | 4 - .../src/runtime/memclr_mips64x.s | 0 .../src/runtime/memclr_mipsx.s | 0 .../src/runtime/memclr_plan9_386.s | 0 .../src/runtime/memclr_plan9_amd64.s | 0 .../src/runtime/memclr_ppc64x.s | 0 .../src/runtime/memclr_riscv64.s | 0 .../src/runtime/memclr_s390x.s | 0 .../src/runtime/memclr_wasm.s | 0 .../src/runtime/memmove_386.s | 0 .../src/runtime/memmove_amd64.s | 0 .../src/runtime/memmove_arm.s | 0 .../src/runtime/memmove_arm64.s | 0 .../src/runtime/memmove_loong64.s | 5 - .../src/runtime/memmove_mips64x.s | 0 .../src/runtime/memmove_mipsx.s | 0 .../src/runtime/memmove_plan9_386.s | 0 .../src/runtime/memmove_plan9_amd64.s | 0 .../src/runtime/memmove_ppc64x.s | 0 .../src/runtime/memmove_riscv64.s | 0 .../src/runtime/memmove_s390x.s | 0 .../src/runtime/memmove_wasm.s | 0 .../src/runtime/metrics.go | 22 +- .../src/runtime/metrics/description.go | 0 .../src/runtime/metrics/doc.go | 36 +- .../src/runtime/metrics/histogram.go | 0 .../src/runtime/metrics/sample.go | 0 .../src/runtime/metrics/value.go | 0 .../src/runtime/metrics/ya.make | 0 .../src/runtime/mfinal.go | 29 +- .../src/runtime/mfixalloc.go | 0 .../src/runtime/mgc.go | 202 +- .../src/runtime/mgclimit.go | 29 +- .../src/runtime/mgcmark.go | 118 +- .../src/runtime/mgcpacer.go | 2 +- .../src/runtime/mgcscavenge.go | 26 +- .../src/runtime/mgcstack.go | 0 .../src/runtime/mgcsweep.go | 63 +- .../src/runtime/mgcwork.go | 2 +- .../src/runtime/mheap.go | 288 ++- .../src/runtime/minmax.go | 0 .../src/runtime/mkduff.go | 0 .../src/runtime/mkfastlog2table.go | 0 .../src/runtime/mklockrank.go | 31 +- .../src/runtime/mkpreempt.go | 0 .../src/runtime/mksizeclasses.go | 4 +- .../src/runtime/mmap.go | 0 .../src/runtime/mpagealloc.go | 7 +- .../src/runtime/mpagealloc_32bit.go | 0 .../src/runtime/mpagealloc_64bit.go | 0 .../src/runtime/mpagecache.go | 0 .../src/runtime/mpallocbits.go | 9 +- .../src/runtime/mprof.go | 524 +++-- .../src/runtime/mranges.go | 2 +- .../src/runtime/msan.go | 5 + .../src/runtime/msan/msan.go | 0 .../src/runtime/msan/ya.make | 0 .../src/runtime/msan0.go | 0 .../src/runtime/msan_amd64.s | 0 .../src/runtime/msan_arm64.s | 0 .../src/runtime/msan_loong64.s | 0 .../src/runtime/msize.go} | 2 - .../src/runtime/mspanset.go | 2 +- .../src/runtime/mstats.go | 54 +- .../src/runtime/mwbbuf.go | 2 +- .../src/runtime/nbpipe_pipe.go | 0 .../src/runtime/nbpipe_pipe2.go | 0 .../src/runtime/net_plan9.go | 0 .../src/runtime/netpoll.go | 64 +- .../src/runtime/netpoll_aix.go | 2 +- .../src/runtime/netpoll_epoll.go | 52 +- .../src/runtime/netpoll_fake.go | 0 .../src/runtime/netpoll_kqueue.go | 56 +- .../src/runtime/netpoll_kqueue_event.go | 80 + .../src/runtime/netpoll_kqueue_pipe.go | 73 + .../src/runtime/netpoll_solaris.go | 2 +- .../src/runtime/netpoll_stub.go | 2 +- .../src/runtime/netpoll_wasip1.go | 4 +- .../_std_1.23/src/runtime/netpoll_windows.go | 284 +++ .../src/runtime/nonwindows_stub.go | 7 + .../src/runtime/os2_aix.go | 0 .../src/runtime/os2_freebsd.go | 0 .../src/runtime/os2_openbsd.go | 0 .../src/runtime/os2_plan9.go | 0 .../src/runtime/os2_solaris.go | 0 .../src/runtime/os3_plan9.go | 3 +- .../src/runtime/os3_solaris.go | 2 +- .../src/runtime/os_aix.go | 2 +- .../src/runtime/os_android.go | 0 .../src/runtime/os_darwin.go | 0 .../src/runtime/os_darwin_arm64.go | 0 .../src/runtime/os_dragonfly.go | 0 .../src/runtime/os_freebsd.go | 0 .../src/runtime/os_freebsd2.go | 0 .../src/runtime/os_freebsd_amd64.go | 0 .../src/runtime/os_freebsd_arm.go | 0 .../src/runtime/os_freebsd_arm64.go | 0 .../src/runtime/os_freebsd_noauxv.go | 0 .../src/runtime/os_freebsd_riscv64.go | 0 .../src/runtime/os_illumos.go | 0 .../src/runtime/os_js.go | 0 .../src/runtime/os_linux.go | 29 +- .../src/runtime/os_linux_arm.go | 0 .../src/runtime/os_linux_arm64.go | 0 .../src/runtime/os_linux_be64.go | 0 .../src/runtime/os_linux_generic.go | 0 .../src/runtime/os_linux_loong64.go | 0 .../src/runtime/os_linux_mips64x.go | 0 .../src/runtime/os_linux_mipsx.go | 0 .../src/runtime/os_linux_noauxv.go | 0 .../src/runtime/os_linux_novdso.go | 0 .../src/runtime/os_linux_ppc64x.go | 0 .../src/runtime/os_linux_riscv64.go | 0 .../src/runtime/os_linux_s390x.go | 0 .../src/runtime/os_linux_x86.go | 0 .../src/runtime/os_netbsd.go | 2 +- .../src/runtime/os_netbsd_386.go | 0 .../src/runtime/os_netbsd_amd64.go | 0 .../src/runtime/os_netbsd_arm.go | 0 .../src/runtime/os_netbsd_arm64.go | 0 .../src/runtime/os_nonopenbsd.go | 0 .../src/runtime/os_only_solaris.go | 0 .../src/runtime/os_openbsd.go | 2 +- .../src/runtime/os_openbsd_arm.go | 0 .../src/runtime/os_openbsd_arm64.go | 0 .../src/runtime/os_openbsd_libc.go | 0 .../src/runtime/os_openbsd_mips64.go | 0 .../src/runtime/os_openbsd_syscall.go | 0 .../src/runtime/os_openbsd_syscall1.go | 0 .../src/runtime/os_openbsd_syscall2.go | 2 +- .../src/runtime/os_plan9.go | 15 +- .../src/runtime/os_plan9_arm.go | 0 .../src/runtime/os_solaris.go | 0 .../src/runtime/os_unix.go | 0 .../src/runtime/os_unix_nonlinux.go | 7 + .../src/runtime/os_wasip1.go | 0 .../src/runtime/os_wasm.go | 2 +- .../src/runtime/os_windows.go | 189 +- .../src/runtime/os_windows_arm.go | 0 .../src/runtime/os_windows_arm64.go | 0 .../src/runtime/panic.go | 148 +- .../src/runtime/panic32.go | 0 .../src/runtime/pinner.go | 7 +- .../src/runtime/plugin.go | 7 +- .../src/runtime/pprof/defs_darwin.go | 0 .../src/runtime/pprof/defs_darwin_amd64.go | 0 .../src/runtime/pprof/defs_darwin_arm64.go | 0 .../src/runtime/pprof/elf.go | 0 .../src/runtime/pprof/label.go | 4 +- .../src/runtime/pprof/map.go | 0 .../src/runtime/pprof/pe.go | 0 .../src/runtime/pprof/pprof.go | 132 +- .../src/runtime/pprof/pprof_norusage.go | 2 +- .../src/runtime/pprof/pprof_rusage.go | 0 .../src/runtime/pprof/pprof_windows.go | 0 .../src/runtime/pprof/proto.go | 0 .../src/runtime/pprof/proto_darwin.go | 0 .../src/runtime/pprof/proto_other.go | 0 .../src/runtime/pprof/proto_windows.go | 0 .../src/runtime/pprof/protobuf.go | 0 .../src/runtime/pprof/protomem.go | 5 +- .../src/runtime/pprof/runtime.go | 0 .../src/runtime/pprof/vminfo_darwin.go | 0 .../src/runtime/pprof/ya.make | 0 .../src/runtime/preempt.go | 18 +- .../src/runtime/preempt_386.s | 0 .../src/runtime/preempt_amd64.s | 0 .../src/runtime/preempt_arm.s | 0 .../src/runtime/preempt_arm64.s | 0 .../src/runtime/preempt_loong64.s | 0 .../src/runtime/preempt_mips64x.s | 0 .../src/runtime/preempt_mipsx.s | 0 .../src/runtime/preempt_nonwindows.go | 0 .../src/runtime/preempt_ppc64x.s | 0 .../src/runtime/preempt_riscv64.s | 0 .../src/runtime/preempt_s390x.s | 0 .../src/runtime/preempt_wasm.s | 0 .../src/runtime/print.go | 0 .../src/runtime/proc.go | 777 ++++--- .../src/runtime/profbuf.go | 12 +- .../src/runtime/proflabel.go | 18 + .../src/runtime/race.go | 42 +- .../src/runtime/race/README | 0 .../src/runtime/race/doc.go | 0 .../src/runtime/race/internal/amd64v1/doc.go | 0 .../race/internal/amd64v1/race_darwin.syso | Bin .../race/internal/amd64v1/race_freebsd.syso | Bin .../race/internal/amd64v1/race_linux.syso | Bin .../race/internal/amd64v1/race_netbsd.syso | Bin .../race/internal/amd64v1/race_openbsd.syso | Bin .../race/internal/amd64v1/race_windows.syso | Bin .../src/runtime/race/internal/amd64v1/ya.make | 0 .../src/runtime/race/internal/amd64v3/doc.go | 0 .../race/internal/amd64v3/race_linux.syso | Bin .../src/runtime/race/internal/amd64v3/ya.make | 0 .../src/runtime/race/internal/ya.make | 0 .../src/runtime/race/race.go | 0 .../src/runtime/race/race_darwin_amd64.go | 0 .../src/runtime/race/race_darwin_arm64.go | 0 .../src/runtime/race/race_darwin_arm64.syso | Bin .../src/runtime/race/race_linux_arm64.syso | Bin .../src/runtime/race/race_linux_ppc64le.syso | Bin .../src/runtime/race/race_linux_s390x.syso | Bin .../src/runtime/race/race_v1_amd64.go | 0 .../src/runtime/race/race_v3_amd64.go | 0 .../src/runtime/race/ya.make | 0 .../src/runtime/race0.go | 0 .../src/runtime/race_amd64.s | 51 + .../src/runtime/race_arm64.s | 54 + .../src/runtime/race_ppc64le.s | 46 + .../src/runtime/race_s390x.s | 50 + .../src/runtime/rand.go | 33 + .../src/runtime/rdebug.go | 0 .../src/runtime/retry.go | 0 .../src/runtime/rt0_aix_ppc64.s | 152 +- .../src/runtime/rt0_android_386.s | 0 .../src/runtime/rt0_android_amd64.s | 0 .../src/runtime/rt0_android_arm.s | 0 .../src/runtime/rt0_android_arm64.s | 0 .../src/runtime/rt0_darwin_amd64.s | 0 .../src/runtime/rt0_darwin_arm64.s | 0 .../src/runtime/rt0_dragonfly_amd64.s | 0 .../src/runtime/rt0_freebsd_386.s | 0 .../src/runtime/rt0_freebsd_amd64.s | 0 .../src/runtime/rt0_freebsd_arm.s | 0 .../src/runtime/rt0_freebsd_arm64.s | 0 .../src/runtime/rt0_freebsd_riscv64.s | 0 .../src/runtime/rt0_illumos_amd64.s | 0 .../src/runtime/rt0_ios_amd64.s | 0 .../src/runtime/rt0_ios_arm64.s | 0 .../src/runtime/rt0_js_wasm.s | 0 .../src/runtime/rt0_linux_386.s | 0 .../src/runtime/rt0_linux_amd64.s | 0 .../src/runtime/rt0_linux_arm.s | 0 .../src/runtime/rt0_linux_arm64.s | 0 .../src/runtime/rt0_linux_loong64.s | 0 .../src/runtime/rt0_linux_mips64x.s | 0 .../src/runtime/rt0_linux_mipsx.s | 0 .../src/runtime/rt0_linux_ppc64.s | 0 .../src/runtime/rt0_linux_ppc64le.s | 4 +- .../src/runtime/rt0_linux_riscv64.s | 0 .../src/runtime/rt0_linux_s390x.s | 0 .../src/runtime/rt0_netbsd_386.s | 0 .../src/runtime/rt0_netbsd_amd64.s | 0 .../src/runtime/rt0_netbsd_arm.s | 0 .../src/runtime/rt0_netbsd_arm64.s | 0 .../src/runtime/rt0_openbsd_386.s | 0 .../src/runtime/rt0_openbsd_amd64.s | 0 .../src/runtime/rt0_openbsd_arm.s | 0 .../src/runtime/rt0_openbsd_arm64.s | 0 .../src/runtime/rt0_openbsd_mips64.s | 0 .../src/runtime/rt0_openbsd_ppc64.s | 0 .../src/runtime/rt0_openbsd_riscv64.s | 0 .../src/runtime/rt0_plan9_386.s | 0 .../src/runtime/rt0_plan9_amd64.s | 0 .../src/runtime/rt0_plan9_arm.s | 0 .../src/runtime/rt0_solaris_amd64.s | 0 .../src/runtime/rt0_wasip1_wasm.s | 0 .../src/runtime/rt0_windows_386.s | 0 .../src/runtime/rt0_windows_amd64.s | 0 .../src/runtime/rt0_windows_arm.s | 0 .../src/runtime/rt0_windows_arm64.s | 0 .../src/runtime/runtime-gdb.py | 0 .../src/runtime/runtime.go | 98 +- .../src/runtime/runtime1.go | 138 +- .../src/runtime/runtime2.go | 240 +- .../src/runtime/runtime_boring.go | 0 .../src/runtime/rwmutex.go | 25 +- .../src/runtime/security_aix.go | 0 .../src/runtime/security_issetugid.go | 0 .../src/runtime/security_linux.go | 0 .../src/runtime/security_nonunix.go | 0 .../src/runtime/security_unix.go | 6 +- .../src/runtime/select.go | 11 + .../src/runtime/sema.go | 20 +- .../src/runtime/sigaction.go | 0 .../src/runtime/signal_386.go | 0 .../src/runtime/signal_aix_ppc64.go | 0 .../src/runtime/signal_amd64.go | 0 .../src/runtime/signal_arm.go | 0 .../src/runtime/signal_arm64.go | 0 .../src/runtime/signal_darwin.go | 0 .../src/runtime/signal_darwin_amd64.go | 0 .../src/runtime/signal_darwin_arm64.go | 0 .../src/runtime/signal_dragonfly.go | 0 .../src/runtime/signal_dragonfly_amd64.go | 0 .../src/runtime/signal_freebsd.go | 0 .../src/runtime/signal_freebsd_386.go | 0 .../src/runtime/signal_freebsd_amd64.go | 0 .../src/runtime/signal_freebsd_arm.go | 0 .../src/runtime/signal_freebsd_arm64.go | 0 .../src/runtime/signal_freebsd_riscv64.go | 0 .../src/runtime/signal_linux_386.go | 0 .../src/runtime/signal_linux_amd64.go | 0 .../src/runtime/signal_linux_arm.go | 0 .../src/runtime/signal_linux_arm64.go | 0 .../src/runtime/signal_linux_loong64.go | 0 .../src/runtime/signal_linux_mips64x.go | 0 .../src/runtime/signal_linux_mipsx.go | 0 .../src/runtime/signal_linux_ppc64x.go | 0 .../src/runtime/signal_linux_riscv64.go | 0 .../src/runtime/signal_linux_s390x.go | 0 .../src/runtime/signal_loong64.go | 0 .../src/runtime/signal_mips64x.go | 0 .../src/runtime/signal_mipsx.go | 0 .../src/runtime/signal_netbsd.go | 0 .../src/runtime/signal_netbsd_386.go | 0 .../src/runtime/signal_netbsd_amd64.go | 0 .../src/runtime/signal_netbsd_arm.go | 0 .../src/runtime/signal_netbsd_arm64.go | 0 .../src/runtime/signal_openbsd.go | 0 .../src/runtime/signal_openbsd_386.go | 0 .../src/runtime/signal_openbsd_amd64.go | 0 .../src/runtime/signal_openbsd_arm.go | 0 .../src/runtime/signal_openbsd_arm64.go | 0 .../src/runtime/signal_openbsd_mips64.go | 0 .../src/runtime/signal_openbsd_ppc64.go | 0 .../src/runtime/signal_openbsd_riscv64.go | 0 .../src/runtime/signal_plan9.go | 0 .../src/runtime/signal_ppc64x.go | 0 .../src/runtime/signal_riscv64.go | 0 .../src/runtime/signal_solaris.go | 0 .../src/runtime/signal_solaris_amd64.go | 0 .../src/runtime/signal_unix.go | 59 +- .../src/runtime/signal_windows.go | 0 .../src/runtime/sigqueue.go | 2 +- .../src/runtime/sigqueue_note.go | 0 .../src/runtime/sigqueue_plan9.go | 0 .../src/runtime/sigtab_aix.go | 0 .../src/runtime/sigtab_linux_generic.go | 0 .../src/runtime/sigtab_linux_mipsx.go | 0 .../src/runtime/sizeclasses.go | 1 + .../src/runtime/slice.go | 41 +- .../src/runtime/softfloat64.go | 0 .../src/runtime/stack.go | 47 +- .../src/runtime/stkframe.go | 2 +- .../src/runtime/string.go | 20 +- .../src/runtime/stubs.go | 100 +- .../src/runtime/stubs2.go | 2 +- .../src/runtime/stubs3.go | 0 .../src/runtime/stubs_386.go | 0 .../src/runtime/stubs_amd64.go | 0 .../src/runtime/stubs_arm.go | 0 .../src/runtime/stubs_arm64.go | 0 .../src/runtime/stubs_linux.go | 0 .../src/runtime/stubs_loong64.go | 0 .../src/runtime/stubs_mips64x.go | 0 .../src/runtime/stubs_mipsx.go | 0 .../src/runtime/stubs_nonlinux.go | 0 .../src/runtime/stubs_ppc64.go | 0 .../src/runtime/stubs_ppc64x.go | 0 .../src/runtime/stubs_riscv64.go | 0 .../src/runtime/stubs_s390x.go | 0 .../src/runtime/symtab.go | 172 +- .../src/runtime/symtabinl.go | 28 +- .../src/runtime/sys_aix_ppc64.s | 0 .../src/runtime/sys_arm.go | 0 .../src/runtime/sys_arm64.go | 0 .../src/runtime/sys_darwin.go | 42 +- .../src/runtime/sys_darwin_amd64.s | 0 .../src/runtime/sys_darwin_arm64.go | 0 .../src/runtime/sys_darwin_arm64.s | 0 .../src/runtime/sys_dragonfly_amd64.s | 0 .../src/runtime/sys_freebsd_386.s | 0 .../src/runtime/sys_freebsd_amd64.s | 0 .../src/runtime/sys_freebsd_arm.s | 0 .../src/runtime/sys_freebsd_arm64.s | 0 .../src/runtime/sys_freebsd_riscv64.s | 0 .../src/runtime/sys_libc.go | 0 .../src/runtime/sys_linux_386.s | 0 .../src/runtime/sys_linux_amd64.s | 0 .../src/runtime/sys_linux_arm.s | 0 .../src/runtime/sys_linux_arm64.s | 0 .../src/runtime/sys_linux_loong64.s | 0 .../src/runtime/sys_linux_mips64x.s | 0 .../src/runtime/sys_linux_mipsx.s | 0 .../src/runtime/sys_linux_ppc64x.s | 4 +- .../src/runtime/sys_linux_riscv64.s | 0 .../src/runtime/sys_linux_s390x.s | 5 +- .../src/runtime/sys_loong64.go | 0 .../src/runtime/sys_mips64x.go | 0 .../src/runtime/sys_mipsx.go | 0 .../src/runtime/sys_netbsd_386.s | 0 .../src/runtime/sys_netbsd_amd64.s | 0 .../src/runtime/sys_netbsd_arm.s | 0 .../src/runtime/sys_netbsd_arm64.s | 0 .../src/runtime/sys_nonppc64x.go | 0 .../src/runtime/sys_openbsd.go | 0 .../src/runtime/sys_openbsd1.go | 0 .../src/runtime/sys_openbsd2.go | 2 +- .../src/runtime/sys_openbsd3.go | 20 + .../src/runtime/sys_openbsd_386.s | 0 .../src/runtime/sys_openbsd_amd64.s | 0 .../src/runtime/sys_openbsd_arm.s | 0 .../src/runtime/sys_openbsd_arm64.s | 0 .../src/runtime/sys_openbsd_mips64.s | 0 .../src/runtime/sys_openbsd_ppc64.s | 0 .../src/runtime/sys_openbsd_riscv64.s | 0 .../src/runtime/sys_plan9_386.s | 0 .../src/runtime/sys_plan9_amd64.s | 0 .../src/runtime/sys_plan9_arm.s | 0 .../src/runtime/sys_ppc64x.go | 0 .../src/runtime/sys_riscv64.go | 0 .../src/runtime/sys_s390x.go | 0 .../src/runtime/sys_solaris_amd64.s | 0 .../src/runtime/sys_wasm.go | 0 .../src/runtime/sys_wasm.s | 0 .../src/runtime/sys_windows_386.s | 0 .../src/runtime/sys_windows_amd64.s | 33 +- .../src/runtime/sys_windows_arm.s | 0 .../src/runtime/sys_windows_arm64.s | 0 .../src/runtime/sys_x86.go | 0 .../src/runtime/syscall2_solaris.go | 0 .../src/runtime/syscall_aix.go | 0 .../src/runtime/syscall_solaris.go | 0 .../src/runtime/syscall_windows.go | 127 +- .../src/runtime/tagptr.go | 0 .../src/runtime/tagptr_32bit.go | 0 .../src/runtime/tagptr_64bit.go | 0 .../src/runtime/test_amd64.go | 0 .../src/runtime/test_amd64.s | 0 .../src/runtime/test_stubs.go | 0 .../src/runtime/textflag.h | 0 contrib/go/_std_1.23/src/runtime/time.go | 1377 ++++++++++++ .../src/runtime/time_fake.go | 1 + .../src/runtime/time_linux_amd64.s | 0 .../go/_std_1.23/src/runtime/time_nofake.go | 58 + .../src/runtime/time_windows.h | 0 .../src/runtime/time_windows_386.s | 0 .../src/runtime/time_windows_amd64.s | 0 .../src/runtime/time_windows_arm.s | 0 .../src/runtime/time_windows_arm64.s | 0 .../src/runtime/timeasm.go | 0 .../src/runtime/timestub.go | 11 + .../src/runtime/timestub2.go | 0 .../src/runtime/tls_arm.s | 0 .../src/runtime/tls_arm64.h | 0 .../src/runtime/tls_arm64.s | 0 .../src/runtime/tls_loong64.s | 0 .../src/runtime/tls_mips64x.s | 0 .../src/runtime/tls_mipsx.s | 0 .../src/runtime/tls_ppc64x.s | 0 .../src/runtime/tls_riscv64.s | 0 .../src/runtime/tls_s390x.s | 0 .../src/runtime/tls_stub.go | 0 .../src/runtime/tls_windows_amd64.go | 0 .../src/runtime/trace.go} | 142 +- .../src/runtime/trace/annotation.go | 0 .../src/runtime/trace/trace.go | 0 .../src/runtime/trace/ya.make | 0 .../_std_1.23/src/runtime/traceallocfree.go | 162 ++ .../src/runtime/traceback.go | 84 +- .../src/runtime/tracebuf.go} | 15 +- .../src/runtime/tracecpu.go} | 21 +- .../src/runtime/traceevent.go} | 23 +- contrib/go/_std_1.23/src/runtime/traceexp.go | 68 + contrib/go/_std_1.23/src/runtime/tracemap.go | 140 ++ .../go/_std_1.23/src/runtime/traceregion.go | 112 + .../src/runtime/traceruntime.go} | 176 +- .../src/runtime/tracestack.go} | 205 +- .../src/runtime/tracestatus.go} | 20 +- .../src/runtime/tracestring.go} | 21 +- .../src/runtime/tracetime.go} | 10 +- contrib/go/_std_1.23/src/runtime/tracetype.go | 82 + .../src/runtime/type.go | 48 +- contrib/go/_std_1.23/src/runtime/typekind.go | 12 + .../src/runtime/unsafe.go | 5 + .../src/runtime/utf8.go | 0 .../src/runtime/vdso_elf32.go | 0 .../src/runtime/vdso_elf64.go | 0 .../src/runtime/vdso_freebsd.go | 2 +- .../src/runtime/vdso_freebsd_arm.go | 0 .../src/runtime/vdso_freebsd_arm64.go | 0 .../src/runtime/vdso_freebsd_riscv64.go | 0 .../src/runtime/vdso_freebsd_x86.go | 2 +- .../src/runtime/vdso_in_none.go | 0 .../src/runtime/vdso_linux.go | 0 .../src/runtime/vdso_linux_386.go | 0 .../src/runtime/vdso_linux_amd64.go | 5 + .../src/runtime/vdso_linux_arm.go | 0 .../src/runtime/vdso_linux_arm64.go | 0 .../src/runtime/vdso_linux_loong64.go | 0 .../src/runtime/vdso_linux_mips64x.go | 0 .../src/runtime/vdso_linux_ppc64x.go | 0 .../src/runtime/vdso_linux_riscv64.go | 0 .../src/runtime/vdso_linux_s390x.go | 0 .../src/runtime/vlop_386.s | 0 .../src/runtime/vlop_arm.s | 0 .../src/runtime/vlrt.go | 0 .../src/runtime/wincallback.go | 0 .../src/runtime/write_err.go | 7 +- .../src/runtime/write_err_android.go | 13 +- .../src/runtime/ya.make | 216 +- .../src/runtime/zcallback_windows.go | 0 .../src/runtime/zcallback_windows.s | 0 .../src/runtime/zcallback_windows_arm.s | 0 .../src/runtime/zcallback_windows_arm64.s | 0 contrib/go/_std_1.23/src/slices/iter.go | 109 + .../src/slices/slices.go | 122 +- .../src/slices/sort.go | 12 +- .../src/slices/ya.make | 1 + .../src/slices/zsortanyfunc.go | 0 .../src/slices/zsortordered.go | 0 .../src/sort/gen_sort_variants.go | 0 .../src/sort/search.go | 0 .../src/sort/slice.go | 0 .../{_std_1.22 => _std_1.23}/src/sort/sort.go | 0 .../src/sort/sort_impl_120.go | 0 .../src/sort/sort_impl_go121.go | 0 .../{_std_1.22 => _std_1.23}/src/sort/ya.make | 0 .../src/sort/zsortfunc.go | 0 .../src/sort/zsortinterface.go | 0 .../src/strconv/atob.go | 0 .../src/strconv/atoc.go | 8 +- .../src/strconv/atof.go | 0 .../src/strconv/atoi.go | 31 +- .../src/strconv/bytealg.go | 0 .../src/strconv/bytealg_bootstrap.go | 0 .../src/strconv/ctoa.go | 2 +- .../src/strconv/decimal.go | 0 .../src/strconv/doc.go | 2 +- .../src/strconv/eisel_lemire.go | 0 .../src/strconv/ftoa.go | 2 +- .../src/strconv/ftoaryu.go | 0 .../src/strconv/isprint.go | 0 .../src/strconv/itoa.go | 6 +- .../src/strconv/makeisprint.go | 43 +- .../src/strconv/quote.go | 73 +- .../src/strconv/ya.make | 0 .../src/strings/builder.go | 20 +- .../src/strings/clone.go | 9 +- contrib/go/_std_1.23/src/strings/compare.go | 17 + .../src/strings/reader.go | 0 .../src/strings/replace.go | 2 +- .../src/strings/search.go | 0 .../src/strings/strings.go | 174 +- .../src/strings/ya.make | 0 contrib/go/_std_1.23/src/sync/atomic/asm.s | 115 + .../src/sync/atomic/doc.go | 54 +- .../src/sync/atomic/race.s | 0 .../src/sync/atomic/type.go | 40 + .../src/sync/atomic/value.go | 8 +- .../src/sync/atomic/ya.make | 0 .../{_std_1.22 => _std_1.23}/src/sync/cond.go | 13 +- .../{_std_1.22 => _std_1.23}/src/sync/map.go | 42 +- .../src/sync/mutex.go | 12 +- .../{_std_1.22 => _std_1.23}/src/sync/once.go | 6 +- .../src/sync/oncefunc.go | 0 .../{_std_1.22 => _std_1.23}/src/sync/pool.go | 27 +- .../src/sync/poolqueue.go | 29 +- .../src/sync/runtime.go | 0 .../src/sync/runtime2.go | 0 .../src/sync/runtime2_lockrank.go | 0 .../src/sync/rwmutex.go | 28 +- .../src/sync/waitgroup.go | 18 +- .../{_std_1.22 => _std_1.23}/src/sync/ya.make | 0 .../src/syscall/asm9_unix2_amd64.s | 0 .../src/syscall/asm_aix_ppc64.s | 0 .../src/syscall/asm_darwin_amd64.s | 0 .../src/syscall/asm_darwin_arm64.s | 0 .../src/syscall/asm_freebsd_arm.s | 0 .../src/syscall/asm_freebsd_arm64.s | 0 .../src/syscall/asm_freebsd_riscv64.s | 0 .../src/syscall/asm_linux_386.s | 0 .../src/syscall/asm_linux_amd64.s | 0 .../src/syscall/asm_linux_arm.s | 0 .../src/syscall/asm_linux_arm64.s | 0 .../src/syscall/asm_linux_loong64.s | 0 .../src/syscall/asm_linux_mips64x.s | 0 .../src/syscall/asm_linux_mipsx.s | 0 .../src/syscall/asm_linux_ppc64x.s | 0 .../src/syscall/asm_linux_riscv64.s | 0 .../src/syscall/asm_linux_s390x.s | 0 .../src/syscall/asm_netbsd_arm.s | 0 .../src/syscall/asm_netbsd_arm64.s | 0 .../src/syscall/asm_openbsd_386.s | 0 .../src/syscall/asm_openbsd_amd64.s | 0 .../src/syscall/asm_openbsd_arm.s | 0 .../src/syscall/asm_openbsd_arm64.s | 0 .../src/syscall/asm_openbsd_mips64.s | 0 .../src/syscall/asm_openbsd_ppc64.s | 0 .../src/syscall/asm_openbsd_riscv64.s | 0 .../src/syscall/asm_plan9_386.s | 0 .../src/syscall/asm_plan9_amd64.s | 0 .../src/syscall/asm_plan9_arm.s | 0 .../src/syscall/asm_solaris_amd64.s | 0 .../src/syscall/asm_unix_386.s | 0 .../src/syscall/asm_unix_amd64.s | 0 .../_std_1.23/src/syscall/badlinkname_unix.go | 22 + .../src/syscall/bpf_bsd.go | 0 .../src/syscall/const_plan9.go | 0 .../src/syscall/dir_plan9.go | 38 +- .../src/syscall/dirent.go | 24 +- .../src/syscall/dll_windows.go | 49 +- .../src/syscall/env_unix.go | 0 .../src/syscall/env_windows.go | 0 .../src/syscall/errors_plan9.go | 0 .../src/syscall/exec_bsd.go | 5 + .../src/syscall/exec_freebsd.go | 5 + .../src/syscall/exec_libc.go | 5 + .../src/syscall/exec_libc2.go | 5 + .../src/syscall/exec_linux.go | 98 + .../src/syscall/exec_plan9.go | 6 +- .../src/syscall/exec_unix.go | 22 +- .../src/syscall/exec_windows.go | 0 .../src/syscall/flock_aix.go | 2 +- .../src/syscall/flock_bsd.go | 2 +- .../src/syscall/flock_linux.go | 2 +- .../src/syscall/flock_linux_32bit.go | 3 - .../src/syscall/forkpipe.go | 0 .../src/syscall/forkpipe2.go | 0 .../src/syscall/fs_js.go | 0 .../src/syscall/fs_wasip1.go | 23 +- .../src/syscall/js/func.go | 0 .../src/syscall/js/js.go | 105 +- .../src/syscall/js/js_js.s | 0 .../src/syscall/js/ya.make | 0 .../go/_std_1.23/src/syscall/linkname_bsd.go | 17 + .../_std_1.23/src/syscall/linkname_darwin.go | 23 + .../go/_std_1.23/src/syscall/linkname_libc.go | 12 + .../_std_1.23/src/syscall/linkname_openbsd.go | 15 + .../go/_std_1.23/src/syscall/linkname_unix.go | 20 + .../src/syscall/lsf_linux.go | 0 .../src/syscall/mkasm.go | 0 .../src/syscall/mkpost.go | 0 .../src/syscall/mksyscall.pl | 8 +- .../src/syscall/mksyscall_libc.pl | 0 .../src/syscall/mksyscall_windows.go | 0 .../src/syscall/mksysctl_openbsd.pl | 0 .../src/syscall/mksysnum_dragonfly.pl | 0 .../src/syscall/mksysnum_freebsd.pl | 0 .../src/syscall/mksysnum_linux.pl | 0 .../src/syscall/mksysnum_netbsd.pl | 0 .../src/syscall/mksysnum_openbsd.pl | 0 .../src/syscall/net.go | 0 .../src/syscall/net_fake.go | 0 .../src/syscall/net_js.go | 0 .../src/syscall/net_wasip1.go | 0 .../src/syscall/netlink_linux.go | 0 .../src/syscall/os_wasip1.go | 0 .../src/syscall/pwd_plan9.go | 2 +- .../src/syscall/rlimit.go | 5 +- .../src/syscall/rlimit_darwin.go | 0 .../src/syscall/rlimit_stub.go | 0 .../src/syscall/route_bsd.go | 4 +- .../src/syscall/route_darwin.go | 0 .../src/syscall/route_dragonfly.go | 0 .../src/syscall/route_freebsd.go | 0 .../src/syscall/route_freebsd_32bit.go | 0 .../src/syscall/route_freebsd_64bit.go | 0 .../src/syscall/route_netbsd.go | 0 .../src/syscall/route_openbsd.go | 0 .../src/syscall/security_windows.go | 0 .../src/syscall/setuidgid_32_linux.go | 0 .../src/syscall/setuidgid_linux.go | 0 .../src/syscall/sockcmsg_dragonfly.go | 0 .../src/syscall/sockcmsg_linux.go | 0 .../src/syscall/sockcmsg_unix.go | 2 +- .../src/syscall/sockcmsg_unix_other.go | 0 .../src/syscall/syscall.go | 8 +- .../src/syscall/syscall_aix.go | 3 +- .../src/syscall/syscall_aix_ppc64.go | 0 .../src/syscall/syscall_bsd.go | 0 .../src/syscall/syscall_darwin.go | 9 + .../src/syscall/syscall_darwin_amd64.go | 0 .../src/syscall/syscall_darwin_arm64.go | 0 .../src/syscall/syscall_dragonfly.go | 0 .../src/syscall/syscall_dragonfly_amd64.go | 0 .../src/syscall/syscall_freebsd.go | 0 .../src/syscall/syscall_freebsd_386.go | 0 .../src/syscall/syscall_freebsd_amd64.go | 0 .../src/syscall/syscall_freebsd_arm.go | 0 .../src/syscall/syscall_freebsd_arm64.go | 0 .../src/syscall/syscall_freebsd_riscv64.go | 0 .../src/syscall/syscall_illumos.go | 0 .../src/syscall/syscall_js.go | 4 +- .../src/syscall/syscall_linux.go | 34 +- .../src/syscall/syscall_linux_386.go | 0 .../src/syscall/syscall_linux_accept.go | 0 .../src/syscall/syscall_linux_accept4.go | 0 .../src/syscall/syscall_linux_amd64.go | 0 .../src/syscall/syscall_linux_arm.go | 0 .../src/syscall/syscall_linux_arm64.go | 0 .../src/syscall/syscall_linux_loong64.go | 0 .../src/syscall/syscall_linux_mips64x.go | 0 .../src/syscall/syscall_linux_mipsx.go | 0 .../src/syscall/syscall_linux_ppc64x.go | 0 .../src/syscall/syscall_linux_riscv64.go | 0 .../src/syscall/syscall_linux_s390x.go | 0 .../src/syscall/syscall_netbsd.go | 0 .../src/syscall/syscall_netbsd_386.go | 0 .../src/syscall/syscall_netbsd_amd64.go | 0 .../src/syscall/syscall_netbsd_arm.go | 0 .../src/syscall/syscall_netbsd_arm64.go | 0 .../src/syscall/syscall_openbsd.go | 0 .../src/syscall/syscall_openbsd1.go | 0 .../src/syscall/syscall_openbsd_386.go | 0 .../src/syscall/syscall_openbsd_amd64.go | 0 .../src/syscall/syscall_openbsd_arm.go | 0 .../src/syscall/syscall_openbsd_arm64.go | 0 .../src/syscall/syscall_openbsd_libc.go | 28 +- .../src/syscall/syscall_openbsd_mips64.go | 0 .../src/syscall/syscall_openbsd_ppc64.go | 0 .../src/syscall/syscall_openbsd_riscv64.go | 0 .../src/syscall/syscall_plan9.go | 4 +- .../src/syscall/syscall_solaris.go | 2 +- .../src/syscall/syscall_solaris_amd64.go | 0 .../src/syscall/syscall_solarisonly.go | 0 .../src/syscall/syscall_unix.go | 40 +- .../src/syscall/syscall_wasip1.go | 6 +- .../src/syscall/syscall_windows.go | 40 +- .../src/syscall/tables_js.go | 0 .../src/syscall/tables_wasip1.go | 0 .../src/syscall/time_fake.go | 0 .../src/syscall/time_nofake.go | 0 .../src/syscall/timestruct.go | 4 +- .../src/syscall/types_aix.go | 0 .../src/syscall/types_darwin.go | 0 .../src/syscall/types_dragonfly.go | 0 .../src/syscall/types_freebsd.go | 0 .../src/syscall/types_illumos_amd64.go | 0 .../src/syscall/types_linux.go | 0 .../src/syscall/types_netbsd.go | 0 .../src/syscall/types_openbsd.go | 0 .../src/syscall/types_solaris.go | 0 .../src/syscall/types_windows.go | 1 + .../src/syscall/types_windows_386.go | 0 .../src/syscall/types_windows_amd64.go | 0 .../src/syscall/types_windows_arm.go | 0 .../src/syscall/types_windows_arm64.go | 0 .../src/syscall/wtf8_windows.go | 0 .../src/syscall/ya.make | 32 +- .../src/syscall/zerrors_aix_ppc64.go | 0 .../src/syscall/zerrors_darwin_amd64.go | 0 .../src/syscall/zerrors_darwin_arm64.go | 0 .../src/syscall/zerrors_dragonfly_amd64.go | 0 .../src/syscall/zerrors_freebsd_386.go | 0 .../src/syscall/zerrors_freebsd_amd64.go | 0 .../src/syscall/zerrors_freebsd_arm.go | 0 .../src/syscall/zerrors_freebsd_arm64.go | 0 .../src/syscall/zerrors_freebsd_riscv64.go | 0 .../src/syscall/zerrors_linux_386.go | 0 .../src/syscall/zerrors_linux_amd64.go | 0 .../src/syscall/zerrors_linux_arm.go | 0 .../src/syscall/zerrors_linux_arm64.go | 0 .../src/syscall/zerrors_linux_loong64.go | 0 .../src/syscall/zerrors_linux_mips.go | 0 .../src/syscall/zerrors_linux_mips64.go | 0 .../src/syscall/zerrors_linux_mips64le.go | 0 .../src/syscall/zerrors_linux_mipsle.go | 0 .../src/syscall/zerrors_linux_ppc64.go | 0 .../src/syscall/zerrors_linux_ppc64le.go | 0 .../src/syscall/zerrors_linux_riscv64.go | 0 .../src/syscall/zerrors_linux_s390x.go | 0 .../src/syscall/zerrors_netbsd_386.go | 0 .../src/syscall/zerrors_netbsd_amd64.go | 0 .../src/syscall/zerrors_netbsd_arm.go | 0 .../src/syscall/zerrors_netbsd_arm64.go | 0 .../src/syscall/zerrors_openbsd_386.go | 20 +- .../src/syscall/zerrors_openbsd_amd64.go | 20 +- .../src/syscall/zerrors_openbsd_arm.go | 20 +- .../src/syscall/zerrors_openbsd_arm64.go | 0 .../src/syscall/zerrors_openbsd_mips64.go | 0 .../src/syscall/zerrors_openbsd_ppc64.go | 0 .../src/syscall/zerrors_openbsd_riscv64.go | 0 .../src/syscall/zerrors_solaris_amd64.go | 0 .../src/syscall/zerrors_windows.go | 0 .../src/syscall/zsyscall_aix_ppc64.go | 13 + .../src/syscall/zsyscall_darwin_amd64.go | 0 .../src/syscall/zsyscall_darwin_amd64.s | 0 .../src/syscall/zsyscall_darwin_arm64.go | 0 .../src/syscall/zsyscall_darwin_arm64.s | 0 .../src/syscall/zsyscall_dragonfly_amd64.go | 0 .../src/syscall/zsyscall_freebsd_386.go | 0 .../src/syscall/zsyscall_freebsd_amd64.go | 0 .../src/syscall/zsyscall_freebsd_arm.go | 0 .../src/syscall/zsyscall_freebsd_arm64.go | 0 .../src/syscall/zsyscall_freebsd_riscv64.go | 0 .../src/syscall/zsyscall_linux_386.go | 0 .../src/syscall/zsyscall_linux_amd64.go | 0 .../src/syscall/zsyscall_linux_arm.go | 0 .../src/syscall/zsyscall_linux_arm64.go | 0 .../src/syscall/zsyscall_linux_loong64.go | 0 .../src/syscall/zsyscall_linux_mips.go | 0 .../src/syscall/zsyscall_linux_mips64.go | 0 .../src/syscall/zsyscall_linux_mips64le.go | 0 .../src/syscall/zsyscall_linux_mipsle.go | 0 .../src/syscall/zsyscall_linux_ppc64.go | 0 .../src/syscall/zsyscall_linux_ppc64le.go | 0 .../src/syscall/zsyscall_linux_riscv64.go | 0 .../src/syscall/zsyscall_linux_s390x.go | 0 .../src/syscall/zsyscall_netbsd_386.go | 0 .../src/syscall/zsyscall_netbsd_amd64.go | 0 .../src/syscall/zsyscall_netbsd_arm.go | 0 .../src/syscall/zsyscall_netbsd_arm64.go | 0 .../src/syscall/zsyscall_openbsd_386.go | 15 - .../src/syscall/zsyscall_openbsd_386.s | 2 - .../src/syscall/zsyscall_openbsd_amd64.go | 15 - .../src/syscall/zsyscall_openbsd_amd64.s | 2 - .../src/syscall/zsyscall_openbsd_arm.go | 15 - .../src/syscall/zsyscall_openbsd_arm.s | 2 - .../src/syscall/zsyscall_openbsd_arm64.go | 15 - .../src/syscall/zsyscall_openbsd_arm64.s | 2 - .../src/syscall/zsyscall_openbsd_mips64.go | 0 .../src/syscall/zsyscall_openbsd_ppc64.go | 15 - .../src/syscall/zsyscall_openbsd_ppc64.s | 3 - .../src/syscall/zsyscall_openbsd_riscv64.go | 15 - .../src/syscall/zsyscall_openbsd_riscv64.s | 2 - .../src/syscall/zsyscall_plan9_386.go | 0 .../src/syscall/zsyscall_plan9_amd64.go | 0 .../src/syscall/zsyscall_plan9_arm.go | 0 .../src/syscall/zsyscall_solaris_amd64.go | 0 .../src/syscall/zsyscall_windows.go | 7 - .../src/syscall/zsysctl_openbsd.go | 0 .../src/syscall/zsysnum_darwin_amd64.go | 0 .../src/syscall/zsysnum_darwin_arm64.go | 0 .../src/syscall/zsysnum_dragonfly_amd64.go | 0 .../src/syscall/zsysnum_freebsd_386.go | 0 .../src/syscall/zsysnum_freebsd_amd64.go | 0 .../src/syscall/zsysnum_freebsd_arm.go | 0 .../src/syscall/zsysnum_freebsd_arm64.go | 0 .../src/syscall/zsysnum_freebsd_riscv64.go | 0 .../src/syscall/zsysnum_linux_386.go | 0 .../src/syscall/zsysnum_linux_amd64.go | 0 .../src/syscall/zsysnum_linux_arm.go | 0 .../src/syscall/zsysnum_linux_arm64.go | 0 .../src/syscall/zsysnum_linux_loong64.go | 0 .../src/syscall/zsysnum_linux_mips.go | 0 .../src/syscall/zsysnum_linux_mips64.go | 0 .../src/syscall/zsysnum_linux_mips64le.go | 0 .../src/syscall/zsysnum_linux_mipsle.go | 0 .../src/syscall/zsysnum_linux_ppc64.go | 0 .../src/syscall/zsysnum_linux_ppc64le.go | 0 .../src/syscall/zsysnum_linux_riscv64.go | 0 .../src/syscall/zsysnum_linux_s390x.go | 0 .../src/syscall/zsysnum_netbsd_386.go | 0 .../src/syscall/zsysnum_netbsd_amd64.go | 0 .../src/syscall/zsysnum_netbsd_arm.go | 0 .../src/syscall/zsysnum_netbsd_arm64.go | 0 .../src/syscall/zsysnum_openbsd_386.go | 0 .../src/syscall/zsysnum_openbsd_amd64.go | 0 .../src/syscall/zsysnum_openbsd_arm.go | 0 .../src/syscall/zsysnum_openbsd_arm64.go | 0 .../src/syscall/zsysnum_openbsd_mips64.go | 0 .../src/syscall/zsysnum_openbsd_ppc64.go | 0 .../src/syscall/zsysnum_openbsd_riscv64.go | 0 .../src/syscall/zsysnum_plan9.go | 0 .../src/syscall/zsysnum_solaris_amd64.go | 0 .../src/syscall/ztypes_aix_ppc64.go | 0 .../src/syscall/ztypes_darwin_amd64.go | 0 .../src/syscall/ztypes_darwin_arm64.go | 0 .../src/syscall/ztypes_dragonfly_amd64.go | 0 .../src/syscall/ztypes_freebsd_386.go | 0 .../src/syscall/ztypes_freebsd_amd64.go | 0 .../src/syscall/ztypes_freebsd_arm.go | 0 .../src/syscall/ztypes_freebsd_arm64.go | 0 .../src/syscall/ztypes_freebsd_riscv64.go | 0 .../src/syscall/ztypes_linux_386.go | 0 .../src/syscall/ztypes_linux_amd64.go | 0 .../src/syscall/ztypes_linux_arm.go | 0 .../src/syscall/ztypes_linux_arm64.go | 0 .../src/syscall/ztypes_linux_loong64.go | 0 .../src/syscall/ztypes_linux_mips.go | 0 .../src/syscall/ztypes_linux_mips64.go | 0 .../src/syscall/ztypes_linux_mips64le.go | 0 .../src/syscall/ztypes_linux_mipsle.go | 0 .../src/syscall/ztypes_linux_ppc64.go | 0 .../src/syscall/ztypes_linux_ppc64le.go | 0 .../src/syscall/ztypes_linux_riscv64.go | 0 .../src/syscall/ztypes_linux_s390x.go | 0 .../src/syscall/ztypes_netbsd_386.go | 0 .../src/syscall/ztypes_netbsd_amd64.go | 0 .../src/syscall/ztypes_netbsd_arm.go | 0 .../src/syscall/ztypes_netbsd_arm64.go | 0 .../src/syscall/ztypes_openbsd_386.go | 0 .../src/syscall/ztypes_openbsd_amd64.go | 0 .../src/syscall/ztypes_openbsd_arm.go | 0 .../src/syscall/ztypes_openbsd_arm64.go | 0 .../src/syscall/ztypes_openbsd_mips64.go | 0 .../src/syscall/ztypes_openbsd_ppc64.go | 0 .../src/syscall/ztypes_openbsd_riscv64.go | 0 .../src/syscall/ztypes_solaris_amd64.go | 0 .../src/text/tabwriter/tabwriter.go | 21 +- .../src/text/tabwriter/ya.make | 0 .../src/text/template/doc.go | 7 + .../src/text/template/exec.go | 26 +- .../src/text/template/funcs.go | 46 +- .../src/text/template/helper.go | 34 +- .../src/text/template/option.go | 0 .../src/text/template/parse/lex.go | 0 .../src/text/template/parse/node.go | 12 +- .../src/text/template/parse/parse.go | 60 +- .../src/text/template/parse/ya.make | 0 .../src/text/template/template.go | 6 +- .../src/text/template/ya.make | 0 .../src/time/embed.go | 0 .../src/time/format.go | 88 +- .../src/time/format_rfc3339.go | 0 .../src/time/genzabbrs.go | 7 +- contrib/go/_std_1.23/src/time/sleep.go | 216 ++ .../src/time/sys_plan9.go | 0 .../src/time/sys_unix.go | 0 .../src/time/sys_windows.go | 0 contrib/go/_std_1.23/src/time/tick.go | 91 + .../{_std_1.22 => _std_1.23}/src/time/time.go | 84 +- .../src/time/tzdata/tzdata.go | 0 .../src/time/tzdata/ya.make | 0 .../src/time/tzdata/zzipdata.go | 2 + .../{_std_1.22 => _std_1.23}/src/time/ya.make | 0 .../src/time/zoneinfo.go | 4 +- .../src/time/zoneinfo_abbrs_windows.go | 0 .../src/time/zoneinfo_android.go | 0 .../src/time/zoneinfo_goroot.go | 0 .../src/time/zoneinfo_ios.go | 0 .../src/time/zoneinfo_js.go | 0 .../src/time/zoneinfo_plan9.go | 0 .../src/time/zoneinfo_read.go | 10 +- .../src/time/zoneinfo_unix.go | 0 .../src/time/zoneinfo_wasip1.go | 0 .../src/time/zoneinfo_windows.go | 0 .../src/unicode/casetables.go | 0 .../src/unicode/digit.go | 0 .../src/unicode/graphic.go | 0 .../src/unicode/letter.go | 0 .../src/unicode/tables.go | 0 .../src/unicode/utf16/utf16.go | 21 +- .../src/unicode/utf16/ya.make | 0 .../src/unicode/utf8/utf8.go | 2 +- .../src/unicode/utf8/ya.make | 0 .../src/unicode/ya.make | 0 contrib/go/_std_1.23/src/unique/clone.go | 89 + contrib/go/_std_1.23/src/unique/doc.go | 9 + contrib/go/_std_1.23/src/unique/handle.go | 175 ++ contrib/go/_std_1.23/src/unique/ya.make | 9 + .../x/crypto/chacha20/chacha_arm64.go | 0 .../x/crypto/chacha20/chacha_arm64.s | 0 .../x/crypto/chacha20/chacha_generic.go | 0 .../x/crypto/chacha20/chacha_noasm.go | 0 .../x/crypto/chacha20/chacha_ppc64le.go | 0 .../x/crypto/chacha20/chacha_ppc64le.s | 110 +- .../x/crypto/chacha20/chacha_s390x.go | 0 .../x/crypto/chacha20/chacha_s390x.s | 0 .../golang.org/x/crypto/chacha20/xor.go | 0 .../golang.org/x/crypto/chacha20/ya.make | 0 .../chacha20poly1305/chacha20poly1305.go | 0 .../chacha20poly1305_amd64.go | 0 .../chacha20poly1305/chacha20poly1305_amd64.s | 0 .../chacha20poly1305_generic.go | 0 .../chacha20poly1305_noasm.go | 0 .../chacha20poly1305/xchacha20poly1305.go | 0 .../x/crypto/chacha20poly1305/ya.make | 0 .../golang.org/x/crypto/cryptobyte/asn1.go | 0 .../x/crypto/cryptobyte/asn1/asn1.go | 0 .../x/crypto/cryptobyte/asn1/ya.make | 0 .../golang.org/x/crypto/cryptobyte/builder.go | 0 .../golang.org/x/crypto/cryptobyte/string.go | 0 .../golang.org/x/crypto/cryptobyte/ya.make | 0 .../vendor/golang.org/x/crypto/hkdf/hkdf.go | 0 .../vendor/golang.org/x/crypto/hkdf/ya.make | 0 .../x/crypto/internal/alias/alias.go | 0 .../x/crypto/internal/alias/alias_purego.go | 0 .../x/crypto/internal/alias/ya.make | 0 .../x/crypto/internal/poly1305/mac_noasm.go | 0 .../x/crypto/internal/poly1305/poly1305.go | 0 .../x/crypto/internal/poly1305/sum_amd64.go | 0 .../x/crypto/internal/poly1305/sum_amd64.s | 0 .../x/crypto/internal/poly1305/sum_generic.go | 43 +- .../x/crypto/internal/poly1305/sum_ppc64le.go | 0 .../x/crypto/internal/poly1305/sum_ppc64le.s | 14 +- .../x/crypto/internal/poly1305/sum_s390x.go | 0 .../x/crypto/internal/poly1305/sum_s390x.s | 0 .../x/crypto/internal/poly1305/ya.make | 2 - .../vendor/golang.org/x/crypto/sha3/doc.go | 62 + .../vendor/golang.org/x/crypto/sha3/hashes.go | 101 + .../golang.org/x/crypto/sha3/hashes_noasm.go | 23 + .../golang.org/x/crypto/sha3/keccakf.go | 414 ++++ .../golang.org/x/crypto/sha3/keccakf_amd64.go | 13 + .../golang.org/x/crypto/sha3/keccakf_amd64.s | 390 ++++ .../golang.org/x/crypto/sha3/register.go | 18 + .../vendor/golang.org/x/crypto/sha3/sha3.go | 185 ++ .../golang.org/x/crypto/sha3/sha3_s390x.go | 303 +++ .../golang.org/x/crypto/sha3/sha3_s390x.s | 33 + .../vendor/golang.org/x/crypto/sha3/shake.go | 174 ++ .../golang.org/x/crypto/sha3/shake_noasm.go | 15 + .../vendor/golang.org/x/crypto/sha3/xor.go | 40 + .../vendor/golang.org/x/crypto/sha3/ya.make | 28 + .../x/net/dns/dnsmessage/message.go | 10 +- .../golang.org/x/net/dns/dnsmessage/ya.make | 0 .../golang.org/x/net/http/httpguts/guts.go | 0 .../golang.org/x/net/http/httpguts/httplex.go | 13 +- .../golang.org/x/net/http/httpguts/ya.make | 0 .../golang.org/x/net/http/httpproxy/proxy.go | 15 +- .../golang.org/x/net/http/httpproxy/ya.make | 0 .../golang.org/x/net/http2/hpack/encode.go | 0 .../golang.org/x/net/http2/hpack/hpack.go | 0 .../golang.org/x/net/http2/hpack/huffman.go | 0 .../x/net/http2/hpack/static_table.go | 0 .../golang.org/x/net/http2/hpack/tables.go | 0 .../golang.org/x/net/http2/hpack/ya.make | 0 .../src/vendor/golang.org/x/net/idna/go118.go | 0 .../golang.org/x/net/idna/idna10.0.0.go | 0 .../vendor/golang.org/x/net/idna/idna9.0.0.go | 0 .../vendor/golang.org/x/net/idna/pre_go118.go | 0 .../vendor/golang.org/x/net/idna/punycode.go | 0 .../golang.org/x/net/idna/tables10.0.0.go | 0 .../golang.org/x/net/idna/tables11.0.0.go | 0 .../golang.org/x/net/idna/tables12.0.0.go | 0 .../golang.org/x/net/idna/tables13.0.0.go | 0 .../golang.org/x/net/idna/tables15.0.0.go | 0 .../golang.org/x/net/idna/tables9.0.0.go | 0 .../src/vendor/golang.org/x/net/idna/trie.go | 0 .../golang.org/x/net/idna/trie12.0.0.go | 0 .../golang.org/x/net/idna/trie13.0.0.go | 0 .../vendor/golang.org/x/net/idna/trieval.go | 0 .../src/vendor/golang.org/x/net/idna/ya.make | 0 .../vendor/golang.org/x/net/route/address.go | 0 .../vendor/golang.org/x/net/route/binary.go | 0 .../src/vendor/golang.org/x/net/route/empty.s | 0 .../golang.org/x/net/route/interface.go | 0 .../x/net/route/interface_announce.go | 0 .../x/net/route/interface_classic.go | 0 .../x/net/route/interface_freebsd.go | 0 .../x/net/route/interface_multicast.go | 0 .../x/net/route/interface_openbsd.go | 0 .../vendor/golang.org/x/net/route/message.go | 0 .../vendor/golang.org/x/net/route/route.go | 0 .../golang.org/x/net/route/route_classic.go | 0 .../golang.org/x/net/route/route_openbsd.go | 0 .../src/vendor/golang.org/x/net/route/sys.go | 0 .../golang.org/x/net/route/sys_darwin.go | 0 .../golang.org/x/net/route/sys_dragonfly.go | 0 .../golang.org/x/net/route/sys_freebsd.go | 0 .../golang.org/x/net/route/sys_netbsd.go | 0 .../golang.org/x/net/route/sys_openbsd.go | 0 .../vendor/golang.org/x/net/route/syscall.go | 0 .../src/vendor/golang.org/x/net/route/ya.make | 0 .../golang.org/x/net/route/zsys_darwin.go | 0 .../golang.org/x/net/route/zsys_dragonfly.go | 0 .../x/net/route/zsys_freebsd_386.go | 0 .../x/net/route/zsys_freebsd_amd64.go | 0 .../x/net/route/zsys_freebsd_arm.go | 0 .../x/net/route/zsys_freebsd_arm64.go | 0 .../x/net/route/zsys_freebsd_riscv64.go | 0 .../golang.org/x/net/route/zsys_netbsd.go | 0 .../golang.org/x/net/route/zsys_openbsd.go | 0 .../golang.org/x/sys/cpu/asm_aix_ppc64.s | 0 .../vendor/golang.org/x/sys/cpu/byteorder.go | 0 .../src/vendor/golang.org/x/sys/cpu/cpu.go | 1 + .../vendor/golang.org/x/sys/cpu/cpu_aix.go | 0 .../vendor/golang.org/x/sys/cpu/cpu_arm.go | 0 .../vendor/golang.org/x/sys/cpu/cpu_arm64.go | 10 + .../vendor/golang.org/x/sys/cpu/cpu_arm64.s | 8 + .../golang.org/x/sys/cpu/cpu_gc_arm64.go | 1 + .../golang.org/x/sys/cpu/cpu_gc_s390x.go | 0 .../vendor/golang.org/x/sys/cpu/cpu_gc_x86.go | 0 .../golang.org/x/sys/cpu/cpu_gccgo_arm64.go | 0 .../golang.org/x/sys/cpu/cpu_gccgo_s390x.go | 0 .../golang.org/x/sys/cpu/cpu_gccgo_x86.c | 0 .../golang.org/x/sys/cpu/cpu_gccgo_x86.go | 0 .../vendor/golang.org/x/sys/cpu/cpu_linux.go | 0 .../golang.org/x/sys/cpu/cpu_linux_arm.go | 0 .../golang.org/x/sys/cpu/cpu_linux_arm64.go | 5 + .../golang.org/x/sys/cpu/cpu_linux_mips64x.go | 0 .../golang.org/x/sys/cpu/cpu_linux_noinit.go | 0 .../golang.org/x/sys/cpu/cpu_linux_ppc64x.go | 0 .../golang.org/x/sys/cpu/cpu_linux_s390x.go | 0 .../golang.org/x/sys/cpu/cpu_loong64.go | 0 .../golang.org/x/sys/cpu/cpu_mips64x.go | 0 .../vendor/golang.org/x/sys/cpu/cpu_mipsx.go | 0 .../golang.org/x/sys/cpu/cpu_netbsd_arm64.go | 0 .../golang.org/x/sys/cpu/cpu_openbsd_arm64.go | 0 .../golang.org/x/sys/cpu/cpu_openbsd_arm64.s | 0 .../golang.org/x/sys/cpu/cpu_other_arm.go | 0 .../golang.org/x/sys/cpu/cpu_other_arm64.go | 0 .../golang.org/x/sys/cpu/cpu_other_mips64x.go | 0 .../golang.org/x/sys/cpu/cpu_other_ppc64x.go | 0 .../golang.org/x/sys/cpu/cpu_other_riscv64.go | 0 .../vendor/golang.org/x/sys/cpu/cpu_ppc64x.go | 0 .../golang.org/x/sys/cpu/cpu_riscv64.go | 0 .../vendor/golang.org/x/sys/cpu/cpu_s390x.go | 0 .../vendor/golang.org/x/sys/cpu/cpu_s390x.s | 0 .../vendor/golang.org/x/sys/cpu/cpu_wasm.go | 0 .../vendor/golang.org/x/sys/cpu/cpu_x86.go | 0 .../src/vendor/golang.org/x/sys/cpu/cpu_x86.s | 0 .../vendor/golang.org/x/sys/cpu/cpu_zos.go | 0 .../golang.org/x/sys/cpu/cpu_zos_s390x.go | 0 .../vendor/golang.org/x/sys/cpu/endian_big.go | 0 .../golang.org/x/sys/cpu/endian_little.go | 0 .../golang.org/x/sys/cpu/hwcap_linux.go | 0 .../src/vendor/golang.org/x/sys/cpu/parse.go | 0 .../x/sys/cpu/proc_cpuinfo_linux.go | 0 .../golang.org/x/sys/cpu/runtime_auxv.go | 0 .../x/sys/cpu/runtime_auxv_go121.go | 0 .../golang.org/x/sys/cpu/syscall_aix_gccgo.go | 0 .../x/sys/cpu/syscall_aix_ppc64_gc.go | 0 .../src/vendor/golang.org/x/sys/cpu/ya.make | 0 .../x/text/secure/bidirule/bidirule.go | 0 .../x/text/secure/bidirule/bidirule10.0.0.go | 0 .../x/text/secure/bidirule/bidirule9.0.0.go | 0 .../golang.org/x/text/secure/bidirule/ya.make | 0 .../golang.org/x/text/transform/transform.go | 0 .../golang.org/x/text/transform/ya.make | 0 .../golang.org/x/text/unicode/bidi/bidi.go | 0 .../golang.org/x/text/unicode/bidi/bracket.go | 0 .../golang.org/x/text/unicode/bidi/core.go | 0 .../golang.org/x/text/unicode/bidi/prop.go | 0 .../x/text/unicode/bidi/tables10.0.0.go | 0 .../x/text/unicode/bidi/tables11.0.0.go | 0 .../x/text/unicode/bidi/tables12.0.0.go | 0 .../x/text/unicode/bidi/tables13.0.0.go | 0 .../x/text/unicode/bidi/tables15.0.0.go | 0 .../x/text/unicode/bidi/tables9.0.0.go | 0 .../golang.org/x/text/unicode/bidi/trieval.go | 0 .../golang.org/x/text/unicode/bidi/ya.make | 0 .../x/text/unicode/norm/composition.go | 0 .../x/text/unicode/norm/forminfo.go | 0 .../golang.org/x/text/unicode/norm/input.go | 0 .../golang.org/x/text/unicode/norm/iter.go | 0 .../x/text/unicode/norm/normalize.go | 0 .../x/text/unicode/norm/readwriter.go | 0 .../x/text/unicode/norm/tables10.0.0.go | 0 .../x/text/unicode/norm/tables11.0.0.go | 0 .../x/text/unicode/norm/tables12.0.0.go | 0 .../x/text/unicode/norm/tables13.0.0.go | 0 .../x/text/unicode/norm/tables15.0.0.go | 0 .../x/text/unicode/norm/tables9.0.0.go | 0 .../x/text/unicode/norm/transform.go | 0 .../golang.org/x/text/unicode/norm/trie.go | 0 .../golang.org/x/text/unicode/norm/ya.make | 0 vendor/github.com/spf13/cobra/README.md | 5 +- vendor/github.com/spf13/cobra/active_help.go | 2 +- .../spf13/cobra/bash_completionsV2.go | 152 +- vendor/github.com/spf13/cobra/cobra.go | 16 +- vendor/github.com/spf13/cobra/command.go | 331 ++- vendor/github.com/spf13/cobra/completions.go | 126 +- .../spf13/cobra/powershell_completions.go | 35 +- vendor/github.com/spf13/cobra/ya.make | 2 +- vendor/github.com/spf13/pflag/ip.go | 3 + vendor/github.com/spf13/pflag/ya.make | 2 +- vendor/golang.org/x/crypto/pbkdf2/ya.make | 2 +- vendor/golang.org/x/crypto/scrypt/ya.make | 2 +- 3228 files changed, 31354 insertions(+), 19716 deletions(-) rename build/external_resources/go_tools/{go1.22.json => go1.23.json} (54%) delete mode 100644 contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_ppc64x.s delete mode 100644 contrib/go/_std_1.22/src/crypto/tls/boring.go delete mode 100644 contrib/go/_std_1.22/src/crypto/tls/notboring.go delete mode 100644 contrib/go/_std_1.22/src/encoding/csv/fuzz.go delete mode 100644 contrib/go/_std_1.22/src/go/types/alias.go delete mode 100644 contrib/go/_std_1.22/src/go/types/errors.go delete mode 100644 contrib/go/_std_1.22/src/go/types/util.go delete mode 100644 contrib/go/_std_1.22/src/internal/coverage/rtcov/rtcov.go delete mode 100644 contrib/go/_std_1.22/src/internal/goexperiment/exp_allocheaders_off.go delete mode 100644 contrib/go/_std_1.22/src/internal/goexperiment/exp_allocheaders_on.go delete mode 100644 contrib/go/_std_1.22/src/internal/goexperiment/exp_exectracer2_off.go delete mode 100644 contrib/go/_std_1.22/src/internal/goexperiment/exp_exectracer2_on.go delete mode 100644 contrib/go/_std_1.22/src/internal/goexperiment/exp_pagetrace_off.go delete mode 100644 contrib/go/_std_1.22/src/internal/goexperiment/exp_pagetrace_on.go delete mode 100644 contrib/go/_std_1.22/src/internal/intern/intern.go delete mode 100644 contrib/go/_std_1.22/src/internal/poll/sendfile_linux.go delete mode 100644 contrib/go/_std_1.22/src/internal/poll/strconv.go delete mode 100644 contrib/go/_std_1.22/src/internal/safefilepath/path.go delete mode 100644 contrib/go/_std_1.22/src/internal/safefilepath/path_other.go delete mode 100644 contrib/go/_std_1.22/src/internal/safefilepath/path_windows.go delete mode 100644 contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_openbsd.go delete mode 100644 contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_darwin.go delete mode 100644 contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_darwin.s delete mode 100644 contrib/go/_std_1.22/src/math/big/arith_decl.go delete mode 100644 contrib/go/_std_1.22/src/math/rand/v2/chacha8.go delete mode 100644 contrib/go/_std_1.22/src/net/cgo_unix_cgo_darwin.go delete mode 100644 contrib/go/_std_1.22/src/net/http/internal/testcert/testcert.go delete mode 100644 contrib/go/_std_1.22/src/net/netip/leaf_alts.go delete mode 100644 contrib/go/_std_1.22/src/net/tcpsockopt_darwin.go delete mode 100644 contrib/go/_std_1.22/src/net/tcpsockopt_dragonfly.go delete mode 100644 contrib/go/_std_1.22/src/net/tcpsockopt_openbsd.go delete mode 100644 contrib/go/_std_1.22/src/net/tcpsockopt_solaris.go delete mode 100644 contrib/go/_std_1.22/src/net/tcpsockopt_unix.go delete mode 100644 contrib/go/_std_1.22/src/net/tcpsockopt_windows.go delete mode 100644 contrib/go/_std_1.22/src/os/endian_big.go delete mode 100644 contrib/go/_std_1.22/src/os/endian_little.go delete mode 100644 contrib/go/_std_1.22/src/os/error_posix.go delete mode 100644 contrib/go/_std_1.22/src/os/exec.go delete mode 100644 contrib/go/_std_1.22/src/os/exec_unix.go delete mode 100644 contrib/go/_std_1.22/src/os/path_windows.go delete mode 100644 contrib/go/_std_1.22/src/runtime/coverage/apis.go delete mode 100644 contrib/go/_std_1.22/src/runtime/coverage/dummy.s delete mode 100644 contrib/go/_std_1.22/src/runtime/coverage/emit.go delete mode 100644 contrib/go/_std_1.22/src/runtime/coverage/hooks.go delete mode 100644 contrib/go/_std_1.22/src/runtime/coverage/testsupport.go delete mode 100644 contrib/go/_std_1.22/src/runtime/coverage/ya.make delete mode 100644 contrib/go/_std_1.22/src/runtime/covermeta.go delete mode 100644 contrib/go/_std_1.22/src/runtime/debug/stack.go delete mode 100644 contrib/go/_std_1.22/src/runtime/exithook.go delete mode 100644 contrib/go/_std_1.22/src/runtime/lockrank.go delete mode 100644 contrib/go/_std_1.22/src/runtime/mbitmap.go delete mode 100644 contrib/go/_std_1.22/src/runtime/mbitmap_noallocheaders.go delete mode 100644 contrib/go/_std_1.22/src/runtime/msize_noallocheaders.go delete mode 100644 contrib/go/_std_1.22/src/runtime/netpoll_windows.go delete mode 100644 contrib/go/_std_1.22/src/runtime/pagetrace_off.go delete mode 100644 contrib/go/_std_1.22/src/runtime/pagetrace_on.go delete mode 100644 contrib/go/_std_1.22/src/runtime/time.go delete mode 100644 contrib/go/_std_1.22/src/runtime/time_nofake.go delete mode 100644 contrib/go/_std_1.22/src/runtime/trace.go delete mode 100644 contrib/go/_std_1.22/src/runtime/trace2map.go delete mode 100644 contrib/go/_std_1.22/src/runtime/trace2region.go delete mode 100644 contrib/go/_std_1.22/src/runtime/typekind.go delete mode 100644 contrib/go/_std_1.22/src/strings/compare.go delete mode 100644 contrib/go/_std_1.22/src/sync/atomic/asm.s delete mode 100644 contrib/go/_std_1.22/src/syscall/asan.go delete mode 100644 contrib/go/_std_1.22/src/syscall/asan0.go delete mode 100644 contrib/go/_std_1.22/src/syscall/endian_big.go delete mode 100644 contrib/go/_std_1.22/src/syscall/endian_little.go delete mode 100644 contrib/go/_std_1.22/src/syscall/msan.go delete mode 100644 contrib/go/_std_1.22/src/syscall/msan0.go delete mode 100644 contrib/go/_std_1.22/src/time/sleep.go delete mode 100644 contrib/go/_std_1.22/src/time/tick.go delete mode 100644 contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go delete mode 100644 contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go rename contrib/go/{_std_1.22 => _std_1.23}/src/bufio/bufio.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/bufio/scan.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/bufio/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/bytes/buffer.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/bytes/bytes.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/bytes/reader.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/bytes/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/cmp/cmp.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/cmp/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/compress/flate/deflate.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/compress/flate/deflatefast.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/compress/flate/dict_decoder.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/compress/flate/huffman_bit_writer.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/compress/flate/huffman_code.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/compress/flate/inflate.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/compress/flate/token.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/compress/flate/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/compress/gzip/gunzip.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/compress/gzip/gzip.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/compress/gzip/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/container/heap/heap.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/container/heap/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/container/list/list.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/container/list/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/context/context.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/context/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/aes_gcm.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/asm_amd64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/asm_arm64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/asm_ppc64x.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/asm_s390x.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/block.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/cbc_ppc64x.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/cbc_s390x.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/cipher.go (86%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/cipher_asm.go (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/cipher_generic.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/cipher_s390x.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/const.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/ctr_s390x.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/gcm_amd64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/gcm_arm64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/gcm_ppc64x.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/gcm_ppc64x.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/gcm_s390x.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/modes.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/aes/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/boring/boring.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/boring/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/cipher/cbc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/cipher/cfb.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/cipher/cipher.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/cipher/ctr.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/cipher/gcm.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/cipher/io.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/cipher/ofb.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/cipher/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/crypto.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/des/block.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/des/cipher.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/des/const.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/des/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/dsa/dsa.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/dsa/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ecdh/ecdh.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ecdh/nist.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ecdh/x25519.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ecdh/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ecdsa/boring.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ecdsa/ecdsa.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ecdsa/ecdsa_legacy.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ecdsa/ecdsa_noasm.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ecdsa/ecdsa_s390x.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ecdsa/ecdsa_s390x.s (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ecdsa/notboring.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ecdsa/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ed25519/ed25519.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ed25519/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/elliptic/elliptic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/elliptic/nistec.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/elliptic/nistec_p256.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/elliptic/params.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/elliptic/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/hmac/hmac.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/hmac/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/alias/alias.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/alias/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/bigmod/_asm/go.mod (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/bigmod/_asm/go.sum (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/bigmod/nat.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/bigmod/nat_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/bigmod/nat_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/bigmod/nat_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/bigmod/nat_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/bigmod/nat_asm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/bigmod/nat_noasm.go (100%) create mode 100644 contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_ppc64x.s rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/bigmod/nat_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/bigmod/nat_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/bigmod/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/Dockerfile (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/LICENSE (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/README.md (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/aes.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/bbig/big.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/bbig/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/bcache/cache.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/bcache/stub.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/bcache/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/boring.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/div_test.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/doc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/ecdh.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/ecdsa.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/fipstls/stub.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/fipstls/tls.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/fipstls/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/goboringcrypto.h (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/hmac.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/notboring.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/rand.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/rsa.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/sha.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/sig/sig.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/sig/sig_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/sig/sig_other.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/sig/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/syso/syso.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/syso/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/boring/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/crypto/internal/cryptotest/hash.go create mode 100644 contrib/go/_std_1.23/src/crypto/internal/cryptotest/ya.make rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/doc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/edwards25519.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/field/_asm/go.mod (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/field/_asm/go.sum (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/field/fe.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/field/fe_amd64.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/field/fe_amd64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/field/fe_arm64.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/field/fe_arm64.s (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/field/fe_generic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/field/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/scalar.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/scalar_fiat.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/scalarmult.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/tables.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/edwards25519/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/crypto/internal/hpke/hpke.go rename contrib/go/{_std_1.22/src/internal/intern => _std_1.23/src/crypto/internal/hpke}/ya.make (74%) create mode 100644 contrib/go/_std_1.23/src/crypto/internal/mlkem768/mlkem768.go create mode 100644 contrib/go/_std_1.23/src/crypto/internal/mlkem768/ya.make rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/Dockerfile (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/README (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/generate.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/p224.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/p224_fiat64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/p224_invert.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/p256.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/p256_fiat64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/p256_invert.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/p384.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/p384_fiat64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/p384_invert.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/p521.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/p521_fiat64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/p521_invert.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/fiat/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/generate.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/nistec.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/p224.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/p224_sqrt.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/p256.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/p256_asm.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/p256_asm_amd64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/p256_asm_arm64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/p256_asm_ppc64le.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/p256_asm_s390x.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/p256_asm_table.bin (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/p256_ordinv.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/p256_ordinv_noasm.go (87%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/p384.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/p521.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/nistec/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/randutil/randutil.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/randutil/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/internal/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/md5/gen.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/md5/md5.go (83%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/md5/md5block.go (86%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/md5/md5block_386.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/md5/md5block_amd64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/md5/md5block_arm.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/md5/md5block_arm64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/md5/md5block_decl.go (74%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/md5/md5block_generic.go (74%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/md5/md5block_ppc64x.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/md5/md5block_s390x.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/md5/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rand/rand.go (67%) create mode 100644 contrib/go/_std_1.23/src/crypto/rand/rand_darwin.go rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rand/rand_getentropy.go (71%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rand/rand_getrandom.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rand/rand_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rand/rand_plan9.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rand/rand_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rand/rand_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rand/rand_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rand/util.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rand/ya.make (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rc4/rc4.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rc4/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rsa/boring.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rsa/notboring.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rsa/pkcs1v15.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rsa/pss.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rsa/rsa.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/rsa/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha1/sha1.go (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha1/sha1block.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha1/sha1block_386.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha1/sha1block_amd64.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha1/sha1block_amd64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha1/sha1block_arm.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha1/sha1block_arm64.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha1/sha1block_arm64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha1/sha1block_decl.go (83%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha1/sha1block_generic.go (78%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha1/sha1block_s390x.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha1/sha1block_s390x.s (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha1/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha256/sha256.go (81%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha256/sha256block.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha256/sha256block_386.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha256/sha256block_amd64.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha256/sha256block_amd64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha256/sha256block_arm64.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha256/sha256block_arm64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha256/sha256block_decl.go (77%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha256/sha256block_generic.go (74%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha256/sha256block_ppc64x.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha256/sha256block_s390x.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha256/sha256block_s390x.s (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha256/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha512/sha512.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha512/sha512block.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha512/sha512block_amd64.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha512/sha512block_amd64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha512/sha512block_arm64.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha512/sha512block_arm64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha512/sha512block_decl.go (78%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha512/sha512block_generic.go (73%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha512/sha512block_ppc64x.s (99%) create mode 100644 contrib/go/_std_1.23/src/crypto/sha512/sha512block_riscv64.s rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha512/sha512block_s390x.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha512/sha512block_s390x.s (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/sha512/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/subtle/constant_time.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/subtle/xor.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/subtle/xor_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/subtle/xor_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/subtle/xor_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/subtle/xor_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/subtle/xor_generic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/subtle/xor_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/subtle/xor_ppc64x.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/subtle/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/alert.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/auth.go (99%) create mode 100644 contrib/go/_std_1.23/src/crypto/tls/bogo_config.json create mode 100644 contrib/go/_std_1.23/src/crypto/tls/boring.go rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/cache.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/cipher_suites.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/common.go (86%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/common_string.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/conn.go (98%) create mode 100644 contrib/go/_std_1.23/src/crypto/tls/defaults.go create mode 100644 contrib/go/_std_1.23/src/crypto/tls/ech.go rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/fipsonly/fipsonly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/fipsonly/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/generate_cert.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/handshake_client.go (80%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/handshake_client_tls13.go (75%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/handshake_messages.go (84%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/handshake_server.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/handshake_server_tls13.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/key_agreement.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/key_schedule.go (82%) rename contrib/go/{_std_1.22/src/internal/syscall/unix/constants.go => _std_1.23/src/crypto/tls/notboring.go} (68%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/prf.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/quic.go (80%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/ticket.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/tls.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/tls/ya.make (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/boring.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/cert_pool.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/internal/macos/corefoundation.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/internal/macos/corefoundation.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/internal/macos/security.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/internal/macos/security.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/internal/macos/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/internal/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/notboring.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/oid.go (69%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/parser.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/pem_decrypt.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/pkcs1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/pkcs8.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/pkix/pkix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/pkix/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/platform_root_cert.pem (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/platform_root_key.pem (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/root.go (86%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/root_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/root_bsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/root_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/root_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/root_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/root_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/root_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/root_wasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/root_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/sec1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/test-file.crt (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/verify.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/x509.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/x509_test_import.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/x509/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/crypto/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/database/sql/driver/driver.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/database/sql/driver/types.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/database/sql/driver/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/embed/embed.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/embed/internal/embedtest/concurrency.txt (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/embed/internal/embedtest/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/embed/internal/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/embed/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/ascii85/ascii85.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/ascii85/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/asn1/asn1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/asn1/common.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/asn1/marshal.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/asn1/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/base32/base32.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/base32/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/base64/base64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/base64/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/binary/binary.go (61%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/binary/native_endian_big.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/binary/native_endian_little.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/binary/varint.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/binary/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/csv/reader.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/csv/writer.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/csv/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/encoding.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/gob/debug.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/gob/dec_helpers.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/gob/decgen.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/gob/decode.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/gob/decoder.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/gob/doc.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/gob/dump.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/gob/enc_helpers.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/gob/encgen.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/gob/encode.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/gob/encoder.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/gob/error.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/gob/type.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/gob/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/hex/hex.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/hex/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/json/decode.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/json/encode.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/json/fold.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/json/indent.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/json/scanner.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/json/stream.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/json/tables.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/json/tags.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/json/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/pem/pem.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/pem/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/xml/marshal.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/xml/read.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/xml/typeinfo.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/xml/xml.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/xml/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/encoding/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/errors/errors.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/errors/join.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/errors/wrap.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/errors/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/flag/flag.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/flag/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/fmt/doc.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/fmt/errors.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/fmt/format.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/fmt/print.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/fmt/scan.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/fmt/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/ast/ast.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/ast/commentmap.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/ast/filter.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/ast/import.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/ast/print.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/ast/resolve.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/ast/scope.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/ast/walk.go (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/ast/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/build/constraint/expr.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/build/constraint/vers.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/build/constraint/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/constant/kind_string.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/constant/value.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/constant/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/doc/comment/doc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/doc/comment/html.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/doc/comment/markdown.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/doc/comment/parse.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/doc/comment/print.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/doc/comment/std.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/doc/comment/text.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/doc/comment/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/internal/typeparams/typeparams.go (58%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/internal/typeparams/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/parser/interface.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/parser/parser.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/parser/resolver.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/parser/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/printer/comment.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/printer/gobuild.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/printer/nodes.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/printer/printer.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/printer/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/scanner/errors.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/scanner/scanner.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/scanner/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/token/position.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/token/serialize.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/token/token.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/token/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/go/types/alias.go rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/api.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/api_predicates.go (80%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/array.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/assignments.go (92%) create mode 100644 contrib/go/_std_1.23/src/go/types/badlinkname.go rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/basic.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/builtins.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/call.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/chan.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/check.go (78%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/const.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/context.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/conversions.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/decl.go (90%) create mode 100644 contrib/go/_std_1.23/src/go/types/errors.go create mode 100644 contrib/go/_std_1.23/src/go/types/errsupport.go rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/eval.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/expr.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/exprstring.go (99%) create mode 100644 contrib/go/_std_1.23/src/go/types/format.go rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/gccgosizes.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/gcsizes.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/generate.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/gotype.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/index.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/infer.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/initorder.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/instantiate.go (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/interface.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/labels.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/lookup.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/map.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/methodset.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/mono.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/named.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/object.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/objset.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/operand.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/package.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/pointer.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/predicates.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/resolver.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/return.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/scope.go (80%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/selection.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/signature.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/sizes.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/slice.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/stmt.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/struct.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/subst.go (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/termlist.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/tuple.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/type.go (78%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/typelists.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/typeparam.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/typeset.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/typestring.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/typeterm.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/typexpr.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/under.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/unify.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/union.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/universe.go (81%) create mode 100644 contrib/go/_std_1.23/src/go/types/util.go rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/validtype.go (77%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/version.go (62%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/types/ya.make (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/version/version.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/go/version/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/adler32/adler32.go (82%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/adler32/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc32/crc32.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc32/crc32_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc32/crc32_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc32/crc32_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc32/crc32_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc32/crc32_generic.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc32/crc32_otherarch.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc32/crc32_ppc64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc32/crc32_ppc64le.s (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc32/crc32_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc32/crc32_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc32/crc32_table_ppc64le.s (99%) create mode 100644 contrib/go/_std_1.23/src/hash/crc32/gen.go rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc32/gen_const_ppc64le.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc32/ya.make (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc64/crc64.go (83%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/crc64/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/fnv/fnv.go (74%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/fnv/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/hash.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/maphash/maphash.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/maphash/maphash_purego.go (76%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/maphash/maphash_runtime.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/maphash/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/test_cases.txt (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/test_gen.awk (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/hash/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/entity.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/escape.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/attr.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/attr_string.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/content.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/context.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/css.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/delim_string.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/doc.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/element_string.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/error.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/escape.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/html.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/js.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/jsctx_string.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/state_string.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/template.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/transition.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/url.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/urlpart_string.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/template/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/html/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/abi.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/abi_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/abi_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/abi_generic.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/abi_loong64.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/abi_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/abi_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/abi_test.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/compiletype.go (89%) create mode 100644 contrib/go/_std_1.23/src/internal/abi/escape.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/funcpc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/funcpc_gccgo.go (100%) create mode 100644 contrib/go/_std_1.23/src/internal/abi/iface.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/map.go (56%) create mode 100644 contrib/go/_std_1.23/src/internal/abi/rangefuncconsts.go create mode 100644 contrib/go/_std_1.23/src/internal/abi/runtime.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/stack.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/stub.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/switch.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/symtab.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/type.go (81%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/abi/ya.make (90%) create mode 100644 contrib/go/_std_1.23/src/internal/asan/asan.go create mode 100644 contrib/go/_std_1.23/src/internal/asan/doc.go create mode 100644 contrib/go/_std_1.23/src/internal/asan/noasan.go create mode 100644 contrib/go/_std_1.23/src/internal/asan/ya.make rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bisect/bisect.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bisect/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/buildcfg/cfg.go (61%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/buildcfg/exp.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/buildcfg/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/buildcfg/zbootstrap.go (82%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/bytealg.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/compare_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/compare_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/compare_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/compare_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/compare_generic.go (68%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/compare_loong64.s (82%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/compare_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/compare_mipsx.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/compare_native.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/compare_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/compare_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/compare_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/compare_wasm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/count_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/count_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/count_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/count_generic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/count_native.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/count_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/count_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/count_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/equal_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/equal_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/equal_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/equal_arm64.s (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/equal_generic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/equal_loong64.s (64%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/equal_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/equal_mipsx.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/equal_native.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/equal_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/equal_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/equal_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/equal_wasm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/index_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/index_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/index_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/index_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/index_generic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/index_native.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/index_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/index_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/index_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/index_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/indexbyte_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/indexbyte_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/indexbyte_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/indexbyte_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/indexbyte_generic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/indexbyte_loong64.s (65%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/indexbyte_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/indexbyte_mipsx.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/indexbyte_native.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/indexbyte_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/indexbyte_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/indexbyte_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/indexbyte_wasm.s (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/lastindexbyte_generic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/bytealg/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/internal/byteorder/byteorder.go create mode 100644 contrib/go/_std_1.23/src/internal/byteorder/ya.make rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/chacha8rand/chacha8.go (72%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/chacha8rand/chacha8_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/chacha8rand/chacha8_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/chacha8rand/chacha8_generic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/chacha8rand/chacha8_stub.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/chacha8rand/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/internal/concurrent/hashtriemap.go create mode 100644 contrib/go/_std_1.23/src/internal/concurrent/ya.make create mode 100644 contrib/go/_std_1.23/src/internal/coverage/rtcov/rtcov.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/coverage/rtcov/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_arm64_android.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_arm64_darwin.go (73%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_arm64_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_arm64_hwcap.go (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_arm64_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_arm64_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_arm64_other.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_mips.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_mips64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_mipsle.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_no_name.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_ppc64x_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_ppc64x_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_ppc64x_other.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_wasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_x86.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/cpu_x86.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/cpu/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/internal/filepathlite/path.go rename contrib/go/{_std_1.22/src/path/filepath => _std_1.23/src/internal/filepathlite}/path_nonwindows.go (91%) create mode 100644 contrib/go/_std_1.23/src/internal/filepathlite/path_plan9.go create mode 100644 contrib/go/_std_1.23/src/internal/filepathlite/path_unix.go rename contrib/go/{_std_1.22/src/path/filepath => _std_1.23/src/internal/filepathlite}/path_windows.go (50%) rename contrib/go/{_std_1.22/src/internal/safefilepath => _std_1.23/src/internal/filepathlite}/ya.make (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/fmtsort/sort.go (68%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/fmtsort/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/gengoarch.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch_mips.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch_mips64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch_mipsle.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch_ppc64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/goarch_wasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_arm64be.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_armbe.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_mips.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_mips64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_mips64p32.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_mips64p32le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_mipsle.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_ppc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_ppc64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_riscv.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_s390.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_sparc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_sparc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goarch/zgoarch_wasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/godebug/godebug.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/godebug/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/godebugs/table.go (80%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/godebugs/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/internal/goexperiment/exp_aliastypeparams_off.go create mode 100644 contrib/go/_std_1.23/src/internal/goexperiment/exp_aliastypeparams_on.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_arenas_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_arenas_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_boringcrypto_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_boringcrypto_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_cacheprog_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_cacheprog_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_cgocheck2_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_cgocheck2_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_coverageredesign_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_coverageredesign_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_fieldtrack_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_fieldtrack_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_heapminimum512kib_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_heapminimum512kib_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_loopvar_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_loopvar_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_newinliner_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_newinliner_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_preemptibleloops_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_preemptibleloops_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_rangefunc_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_rangefunc_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_regabiargs_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_regabiargs_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_regabiwrappers_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_regabiwrappers_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_staticlockranking_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/exp_staticlockranking_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/flags.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/mkconsts.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goexperiment/ya.make (84%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/gengoos.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/goos.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/nonunix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_android.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_hurd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_illumos.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_ios.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_netbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goos/zgoos_zos.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/gover/gover.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/gover/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goversion/goversion.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/goversion/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/itoa/itoa.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/itoa/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/internal/msan/doc.go create mode 100644 contrib/go/_std_1.23/src/internal/msan/msan.go create mode 100644 contrib/go/_std_1.23/src/internal/msan/nomsan.go create mode 100644 contrib/go/_std_1.23/src/internal/msan/ya.make rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/nettrace/nettrace.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/nettrace/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/oserror/errors.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/oserror/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/copy_file_range_linux.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/errno_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/errno_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_fsync_darwin.go (72%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_fsync_posix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_fsync_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_io_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_mutex.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_opendir_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_plan9.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_poll_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_poll_runtime.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_posix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_unix.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_unixjs.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_wasip1.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_windows.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_writev_libc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/fd_writev_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/file_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/hook_cloexec.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/hook_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/hook_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/iovec_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/iovec_unix.go (100%) create mode 100644 contrib/go/_std_1.23/src/internal/poll/sendfile.go create mode 100644 contrib/go/_std_1.23/src/internal/poll/sendfile_bsd.go rename contrib/go/{_std_1.22/src/internal/poll/sendfile_bsd.go => _std_1.23/src/internal/poll/sendfile_linux.go} (56%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/sendfile_solaris.go (60%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/sendfile_windows.go (96%) create mode 100644 contrib/go/_std_1.23/src/internal/poll/sock_cloexec.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/sock_cloexec_accept.go (100%) rename contrib/go/{_std_1.22/src/internal/poll/sock_cloexec.go => _std_1.23/src/internal/poll/sock_cloexec_solaris.go} (54%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/sockopt.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/sockopt_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/sockopt_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/sockopt_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/sockoptip.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/splice_linux.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/sys_cloexec.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/writev.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/poll/ya.make (97%) create mode 100644 contrib/go/_std_1.23/src/internal/profilerecord/profilerecord.go create mode 100644 contrib/go/_std_1.23/src/internal/profilerecord/ya.make rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/race/doc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/race/norace.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/race/race.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/race/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/reflectlite/asm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/reflectlite/swapper.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/reflectlite/type.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/reflectlite/value.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/reflectlite/ya.make (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_386.go (98%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_386.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_amd64.go (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_amd64.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_andor_generic.go (79%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_arm.go (99%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_arm.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_arm64.go (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_arm64.s (91%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_loong64.go (83%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_loong64.s (78%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_mips64x.go (83%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_mips64x.s (84%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_mipsx.go (82%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_mipsx.s (87%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_ppc64x.go (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_ppc64x.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_riscv64.go (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_riscv64.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_s390x.go (85%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_s390x.s (82%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_wasm.go (98%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/atomic_wasm.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/doc.go (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/stubs.go (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/sys_linux_arm.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/sys_nonlinux_arm.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/types.go (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/types_64bit.go (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/unaligned.go (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/atomic/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/internal/runtime/exithook/hooks.go create mode 100644 contrib/go/_std_1.23/src/internal/runtime/exithook/ya.make rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/asm_linux_386.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/asm_linux_amd64.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/asm_linux_arm.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/asm_linux_arm64.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/asm_linux_loong64.s (65%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/asm_linux_mips64x.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/asm_linux_mipsx.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/asm_linux_ppc64x.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/asm_linux_riscv64.s (100%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/asm_linux_s390x.s (100%) create mode 100644 contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux.go rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/defs_linux_386.go (63%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/defs_linux_amd64.go (63%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/defs_linux_arm.go (64%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/defs_linux_arm64.go (64%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/defs_linux_loong64.go (64%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/defs_linux_mips64x.go (67%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/defs_linux_mipsx.go (66%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/defs_linux_ppc64x.go (67%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/defs_linux_riscv64.go (64%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/defs_linux_s390x.go (64%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/syscall_linux.go (56%) rename contrib/go/{_std_1.22/src/runtime/internal => _std_1.23/src/internal/runtime}/syscall/ya.make (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/singleflight/singleflight.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/singleflight/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/internal/stringslite/strings.go create mode 100644 contrib/go/_std_1.23/src/internal/stringslite/ya.make rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/execenv/execenv_default.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/execenv/execenv_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/execenv/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/arc4random_darwin.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/asm_aix_ppc64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/asm_darwin.s (90%) create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/asm_openbsd.s rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/asm_solaris.s (82%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_fstatat.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_fstatat2.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_libc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_libc2.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_solaris.go (73%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_sysnum_darwin.go (55%) create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_dragonfly.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_sysnum_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_sysnum_fstatat64_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_sysnum_fstatat_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_sysnum_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_sysnum_netbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_sysnum_newfstatat_linux.go (100%) rename contrib/go/{_std_1.22/src/internal/syscall/unix/at_sysnum_dragonfly.go => _std_1.23/src/internal/syscall/unix/at_sysnum_openbsd.go} (76%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/at_wasip1.go (100%) create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/constants.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/copy_file_range_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/eaccess_bsd.go (90%) create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_darwin.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/eaccess_linux.go (100%) create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_openbsd.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/eaccess_other.go (75%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/fallocate_freebsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/fallocate_freebsd_64bit.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/fallocate_freebsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/fcntl_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/fcntl_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/fcntl_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/getentropy_netbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/getentropy_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/getentropy_openbsd_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/getrandom.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/getrandom_dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/getrandom_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/getrandom_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/getrandom_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/ioctl_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/kernel_version_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/kernel_version_other.go (88%) create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_solaris.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/net.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/net_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/net_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/net_wasip1.go (100%) create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_bsd.go create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_netbsd.go create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_posix.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/nonblocking_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/nonblocking_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/nonblocking_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/pidfd_linux.go (63%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/pty_darwin.go (100%) create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux.go create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux_mipsx.go create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux_other.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/sysnum_linux_386.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/sysnum_linux_amd64.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/sysnum_linux_arm.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/sysnum_linux_generic.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/sysnum_linux_mips64x.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/sysnum_linux_mipsx.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/sysnum_linux_ppc64x.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/sysnum_linux_s390x.go (89%) create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/tcsetpgrp_bsd.go create mode 100644 contrib/go/_std_1.23/src/internal/syscall/unix/tcsetpgrp_linux.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/user_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/unix/ya.make (87%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/memory_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/mksyscall.go (86%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/net_windows.go (72%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/psapi_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/registry/key.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/registry/mksyscall.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/registry/syscall.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/registry/value.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/registry/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/registry/zsyscall_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/reparse_windows.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/security_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/symlink_windows.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/syscall_windows.go (84%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/sysdll/sysdll.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/sysdll/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/internal/syscall/windows/types_windows.go create mode 100644 contrib/go/_std_1.23/src/internal/syscall/windows/version_windows.go rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/ya.make (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/syscall/windows/zsyscall_windows.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/testlog/exit.go (75%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/testlog/log.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/testlog/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/types/errors/code_string.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/types/errors/codes.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/types/errors/generrordocs.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/types/errors/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/unsafeheader/unsafeheader.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/internal/unsafeheader/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/internal/weak/pointer.go create mode 100644 contrib/go/_std_1.23/src/internal/weak/ya.make rename contrib/go/{_std_1.22 => _std_1.23}/src/io/fs/format.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/fs/fs.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/fs/glob.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/fs/readdir.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/fs/readfile.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/fs/stat.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/fs/sub.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/fs/walk.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/fs/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/io.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/ioutil/ioutil.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/ioutil/tempfile.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/ioutil/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/multi.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/pipe.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/io/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/iter/iter.go create mode 100644 contrib/go/_std_1.23/src/iter/ya.make rename contrib/go/{_std_1.22 => _std_1.23}/src/log/internal/internal.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/internal/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/log.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/attr.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/doc.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/handler.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/internal/benchmarks/benchmarks.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/internal/benchmarks/handlers.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/internal/benchmarks/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/internal/buffer/buffer.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/internal/buffer/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/internal/ignorepc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/internal/slogtest/slogtest.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/internal/slogtest/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/internal/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/json_handler.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/level.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/logger.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/record.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/text_handler.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/value.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/slog/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/syslog/doc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/syslog/syslog.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/syslog/syslog_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/syslog/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/log/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/maps/iter.go create mode 100644 contrib/go/_std_1.23/src/maps/maps.go create mode 100644 contrib/go/_std_1.23/src/maps/ya.make rename contrib/go/{_std_1.22 => _std_1.23}/src/math/abs.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/acos_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/acosh.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/acosh_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/arith_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/asin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/asin_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/asinh.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/asinh_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/atan.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/atan2.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/atan2_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/atan_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/atanh.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/atanh_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/accuracy_string.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith_arm64.s (100%) create mode 100644 contrib/go/_std_1.23/src/math/big/arith_decl.go rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith_decl_pure.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith_decl_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith_loong64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith_mipsx.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith_ppc64x.s (84%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/arith_wasm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/decimal.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/doc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/float.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/floatconv.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/floatmarsh.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/ftoa.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/int.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/intconv.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/intmarsh.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/nat.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/natconv.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/natdiv.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/prime.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/rat.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/ratconv.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/ratmarsh.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/roundingmode_string.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/sqrt.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/big/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/bits.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/bits/bits.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/bits/bits_errors.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/bits/bits_errors_bootstrap.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/bits/bits_tables.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/bits/make_examples.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/bits/make_tables.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/bits/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cbrt.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cbrt_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/abs.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/asin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/conj.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/exp.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/isinf.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/isnan.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/log.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/phase.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/polar.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/pow.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/rect.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/sin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/sqrt.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/tan.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cmplx/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/const.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/copysign.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/cosh_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/dim.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/dim_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/dim_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/dim_asm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/dim_noasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/dim_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/dim_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/erf.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/erf_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/erfc_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/erfinv.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/exp.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/exp2_asm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/exp2_noasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/exp_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/exp_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/exp_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/exp_asm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/exp_noasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/exp_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/expm1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/expm1_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/floor.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/floor_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/floor_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/floor_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/floor_asm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/floor_noasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/floor_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/floor_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/floor_wasm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/fma.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/frexp.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/gamma.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/hypot.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/hypot_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/hypot_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/hypot_asm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/hypot_noasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/j0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/j1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/jn.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/ldexp.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/lgamma.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/log.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/log10.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/log10_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/log1p.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/log1p_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/log_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/log_asm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/log_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/log_stub.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/logb.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/mod.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/modf.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/modf_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/modf_asm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/modf_noasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/modf_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/nextafter.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/pow.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/pow10.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/pow_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/rand/exp.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/rand/gen_cooked.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/rand/normal.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/rand/rand.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/rand/rng.go (100%) create mode 100644 contrib/go/_std_1.23/src/math/rand/v2/chacha8.go rename contrib/go/{_std_1.22 => _std_1.23}/src/math/rand/v2/exp.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/rand/v2/normal.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/rand/v2/pcg.go (78%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/rand/v2/rand.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/rand/v2/ya.make (86%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/rand/v2/zipf.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/rand/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/rand/zipf.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/remainder.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/signbit.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/sin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/sin_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/sincos.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/sinh.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/sinh_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/sqrt.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/stubs.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/stubs_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/tan.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/tan_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/tanh.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/tanh_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/trig_reduce.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/unsafe.go (79%) rename contrib/go/{_std_1.22 => _std_1.23}/src/math/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/encodedword.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/grammar.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/mediatype.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/multipart/formdata.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/multipart/multipart.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/multipart/readmimeheader.go (87%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/multipart/writer.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/multipart/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/quotedprintable/reader.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/quotedprintable/writer.go (87%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/quotedprintable/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/type.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/type_dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/type_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/type_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/type_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/type_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/type_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/mime/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/addrselect.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_android.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_bsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_netbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_resnew.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_resold.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_socknew.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_sockold.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_stub.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_unix.go (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_unix_cgo.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_unix_cgo_res.go (82%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_unix_cgo_resn.go (83%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/cgo_unix_syscall.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/conf.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/dial.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/dnsclient.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/dnsclient_unix.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/dnsconfig.go (74%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/dnsconfig_unix.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/dnsconfig_windows.go (68%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/error_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/error_posix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/error_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/error_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/fd_fake.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/fd_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/fd_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/fd_posix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/fd_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/fd_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/fd_windows.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/file.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/file_plan9.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/file_stub.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/file_unix.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/file_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/file_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/hook.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/hook_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/hook_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/hook_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/hosts.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/cgi/cgi_main.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/cgi/child.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/cgi/host.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/cgi/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/client.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/clone.go (51%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/cookie.go (66%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/cookiejar/jar.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/cookiejar/punycode.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/cookiejar/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/doc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/fcgi/child.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/fcgi/fcgi.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/fcgi/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/filetransport.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/fs.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/h2_bundle.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/h2_error.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/header.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/http.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/httptest/httptest.go (86%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/httptest/recorder.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/httptest/server.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/httptest/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/httptrace/trace.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/httptrace/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/httputil/dump.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/httputil/httputil.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/httputil/persist.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/httputil/reverseproxy.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/httputil/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/internal/ascii/print.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/internal/ascii/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/internal/chunked.go (92%) create mode 100644 contrib/go/_std_1.23/src/net/http/internal/testcert/testcert.go rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/internal/testcert/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/internal/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/jar.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/mapping.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/method.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/omithttp2.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/pattern.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/pprof/pprof.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/pprof/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/request.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/response.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/responsecontroller.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/roundtrip.go (57%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/roundtrip_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/routing_index.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/routing_tree.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/servemux121.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/server.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/sniff.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/socks_bundle.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/status.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/transfer.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/transport.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/transport_default_other.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/transport_default_wasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/triv.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/http/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/interface.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/interface_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/interface_bsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/interface_bsdvar.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/interface_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/interface_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/interface_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/interface_plan9.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/interface_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/interface_stub.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/interface_windows.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/internal/socktest/switch.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/internal/socktest/switch_posix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/internal/socktest/switch_stub.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/internal/socktest/switch_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/internal/socktest/switch_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/internal/socktest/sys_cloexec.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/internal/socktest/sys_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/internal/socktest/sys_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/internal/socktest/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/internal/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/ip.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/iprawsock.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/iprawsock_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/iprawsock_posix.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/ipsock.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/ipsock_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/ipsock_posix.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/lookup.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/lookup_plan9.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/lookup_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/lookup_windows.go (81%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/mac.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/mail/message.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/mail/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/mptcpsock_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/mptcpsock_stub.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/net.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/net_fake.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/netcgo_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/netcgo_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/netgo_netcgo.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/netgo_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/netgo_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/netip/netip.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/netip/uint128.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/netip/ya.make (80%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/nss.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/parse.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/pipe.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/port.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/port_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/rawconn.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/rlimit_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/rlimit_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/rpc/client.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/rpc/debug.go (86%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/rpc/jsonrpc/client.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/rpc/jsonrpc/server.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/rpc/jsonrpc/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/rpc/server.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/rpc/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sendfile_linux.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sendfile_stub.go (70%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sendfile_unix_alt.go (84%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sendfile_windows.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/smtp/auth.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/smtp/smtp.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/smtp/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sock_bsd.go (100%) create mode 100644 contrib/go/_std_1.23/src/net/sock_cloexec.go rename contrib/go/{_std_1.22/src/net/sock_cloexec.go => _std_1.23/src/net/sock_cloexec_solaris.go} (55%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sock_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sock_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sock_posix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sock_stub.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sock_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sockaddr_posix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sockopt_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sockopt_bsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sockopt_fake.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sockopt_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sockopt_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sockopt_posix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sockopt_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sockopt_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sockoptip_bsdvar.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sockoptip_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sockoptip_posix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sockoptip_stub.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sockoptip_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/splice_linux.go (84%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/splice_stub.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/sys_cloexec.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/tcpsock.go (83%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/tcpsock_plan9.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/tcpsock_posix.go (93%) create mode 100644 contrib/go/_std_1.23/src/net/tcpsock_solaris.go create mode 100644 contrib/go/_std_1.23/src/net/tcpsock_unix.go create mode 100644 contrib/go/_std_1.23/src/net/tcpsock_windows.go create mode 100644 contrib/go/_std_1.23/src/net/tcpsockopt_darwin.go create mode 100644 contrib/go/_std_1.23/src/net/tcpsockopt_openbsd.go rename contrib/go/{_std_1.22 => _std_1.23}/src/net/tcpsockopt_plan9.go (54%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/tcpsockopt_posix.go (100%) create mode 100644 contrib/go/_std_1.23/src/net/tcpsockopt_solaris.go rename contrib/go/{_std_1.22 => _std_1.23}/src/net/tcpsockopt_stub.go (59%) create mode 100644 contrib/go/_std_1.23/src/net/tcpsockopt_unix.go create mode 100644 contrib/go/_std_1.23/src/net/tcpsockopt_windows.go rename contrib/go/{_std_1.22 => _std_1.23}/src/net/textproto/header.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/textproto/pipeline.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/textproto/reader.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/textproto/textproto.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/textproto/writer.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/textproto/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/udpsock.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/udpsock_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/udpsock_posix.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/unixsock.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/unixsock_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/unixsock_posix.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/unixsock_readmsg_cloexec.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/unixsock_readmsg_cmsg_cloexec.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/unixsock_readmsg_other.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/url/url.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/url/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/writev_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/net/ya.make (76%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/dir.go (62%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/dir_darwin.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/dir_plan9.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/dir_unix.go (78%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/dir_windows.go (70%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/dirent_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/dirent_dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/dirent_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/dirent_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/dirent_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/dirent_netbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/dirent_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/dirent_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/dirent_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/env.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/error.go (80%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/error_errno.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/error_plan9.go (100%) create mode 100644 contrib/go/_std_1.23/src/os/exec.go rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/exec.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/exec_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/exec_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/exec_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/internal/fdtest/exists_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/internal/fdtest/exists_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/internal/fdtest/exists_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/internal/fdtest/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/internal/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/lp_plan9.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/lp_unix.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/lp_wasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/lp_windows.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/read3.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/os/exec_linux.go create mode 100644 contrib/go/_std_1.23/src/os/exec_nohandle.go rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec_plan9.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec_posix.go (91%) create mode 100644 contrib/go/_std_1.23/src/os/exec_unix.go rename contrib/go/{_std_1.22 => _std_1.23}/src/os/exec_windows.go (83%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/executable.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/executable_darwin.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/executable_dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/executable_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/executable_path.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/executable_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/executable_procfs.go (70%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/executable_solaris.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/executable_sysctl.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/executable_wasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/executable_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/file.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/file_mutex_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/file_open_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/file_open_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/file_plan9.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/file_posix.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/file_unix.go (82%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/file_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/file_windows.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/getwd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/path.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/path_plan9.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/path_unix.go (74%) create mode 100644 contrib/go/_std_1.23/src/os/path_windows.go create mode 100644 contrib/go/_std_1.23/src/os/pidfd_linux.go create mode 100644 contrib/go/_std_1.23/src/os/pidfd_other.go rename contrib/go/{_std_1.22 => _std_1.23}/src/os/pipe2_unix.go (86%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/pipe_unix.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/pipe_wasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/proc.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/rawconn.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/removeall_at.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/removeall_noat.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/signal/doc.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/signal/sig.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/signal/signal.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/signal/signal_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/signal/signal_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/signal/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/stat.go (76%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/stat_aix.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/stat_darwin.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/stat_dragonfly.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/stat_freebsd.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/stat_js.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/stat_linux.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/stat_netbsd.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/stat_openbsd.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/stat_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/stat_solaris.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/stat_unix.go (86%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/stat_wasip1.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/stat_windows.go (84%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/sticky_bsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/sticky_notbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/sys.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/sys_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/sys_bsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/sys_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/sys_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/sys_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/sys_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/sys_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/sys_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/sys_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/tempfile.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/types.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/types_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/types_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/types_windows.go (72%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/cgo_listgroups_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/cgo_lookup_cgo.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/cgo_lookup_syscall.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/cgo_lookup_unix.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/getgrouplist_syscall.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/getgrouplist_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/listgroups_stub.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/listgroups_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/lookup.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/lookup_android.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/lookup_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/lookup_stubs.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/lookup_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/lookup_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/user.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/user/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/wait6_dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/wait6_freebsd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/wait6_freebsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/wait6_freebsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/wait6_netbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/wait_unimp.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/wait_wait6.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/wait_waitid.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/ya.make (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/zero_copy_linux.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/os/zero_copy_stub.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/path/filepath/match.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/path/filepath/path.go (76%) rename contrib/go/{_std_1.22 => _std_1.23}/src/path/filepath/path_plan9.go (70%) rename contrib/go/{_std_1.22 => _std_1.23}/src/path/filepath/path_unix.go (73%) create mode 100644 contrib/go/_std_1.23/src/path/filepath/path_windows.go rename contrib/go/{_std_1.22 => _std_1.23}/src/path/filepath/symlink.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/path/filepath/symlink_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/path/filepath/symlink_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/path/filepath/symlink_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/path/filepath/ya.make (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/path/match.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/path/path.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/path/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/abi.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/arena.go (77%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/asm_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/asm_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/asm_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/asm_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/asm_loong64.s (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/asm_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/asm_mipsx.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/asm_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/asm_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/asm_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/asm_wasm.s (100%) create mode 100644 contrib/go/_std_1.23/src/reflect/badlinkname.go rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/deepequal.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/float32reg_generic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/float32reg_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/float32reg_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/internal/example1/example.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/internal/example1/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/internal/example2/example.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/internal/example2/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/internal/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/reflect/iter.go rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/makefunc.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/stubs_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/stubs_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/swapper.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/type.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/value.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/visiblefields.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/reflect/ya.make (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/backtrack.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/exec.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/onepass.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/regexp.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/syntax/compile.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/syntax/doc.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/syntax/make_perl_groups.pl (83%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/syntax/op_string.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/syntax/parse.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/syntax/perl_groups.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/syntax/prog.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/syntax/regexp.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/syntax/simplify.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/syntax/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/regexp/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/HACKING.md (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/Makefile (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/alg.go (77%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/arena.go (79%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asan.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asan/asan.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asan/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asan0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asan_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asan_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asan_loong64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asan_ppc64le.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asan_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asm.s (53%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asm_386.s (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asm_amd64.h (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asm_amd64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asm_arm.s (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asm_arm64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asm_loong64.s (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asm_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asm_mipsx.s (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asm_ppc64x.h (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asm_ppc64x.s (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asm_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asm_s390x.s (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/asm_wasm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/atomic_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/atomic_loong64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/atomic_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/atomic_mipsx.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/atomic_pointer.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/atomic_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/atomic_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/auxv_none.go (100%) create mode 100644 contrib/go/_std_1.23/src/runtime/badlinkname.go create mode 100644 contrib/go/_std_1.23/src/runtime/badlinkname_linux.go rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo.go (81%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/abi_amd64.h (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/abi_arm64.h (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/abi_loong64.h (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/abi_ppc64x.h (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/asm_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/asm_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/asm_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/asm_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/asm_loong64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/asm_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/asm_mipsx.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/asm_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/asm_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/asm_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/asm_wasm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/callbacks.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/callbacks_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/callbacks_traceback.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/cgo.go (87%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_386.S (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_aix_ppc64.S (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_aix_ppc64.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_amd64.S (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_android.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_arm.S (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_arm64.S (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_context.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_darwin_amd64.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_darwin_arm64.c (86%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_dragonfly_amd64.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_fatalf.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_freebsd.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_freebsd_amd64.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_freebsd_sigaction.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_libinit.c (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_libinit_windows.c (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_linux.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_linux_amd64.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_linux_arm64.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_linux_ppc64x.S (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_linux_s390x.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_loong64.S (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_mips64x.S (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_mipsx.S (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_mmap.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_netbsd.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_openbsd.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_ppc64x.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_riscv64.S (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_s390x.S (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_setenv.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_sigaction.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_signal2_ios_arm64.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_signal_ios_arm64.c (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_signal_ios_nolldb.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_solaris_amd64.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_stack_darwin.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_stack_unix.c (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_stack_windows.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_traceback.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_util.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_windows_386.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_windows_amd64.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/gcc_windows_arm64.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/handle.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/iscgo.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/libcgo.h (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/libcgo_unix.h (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/libcgo_windows.h (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/linux_syscall.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/mmap.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/netbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/setenv.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/sigaction.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/signal_ios_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/signal_ios_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo_mmap.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgo_sigaction.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgocall.go (84%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgocallback.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cgocheck.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/chan.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/checkptr.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/compiler.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/complex.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/coro.go (56%) create mode 100644 contrib/go/_std_1.23/src/runtime/coverage/coverage.go create mode 100644 contrib/go/_std_1.23/src/runtime/coverage/ya.make rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/covercounter.go (79%) create mode 100644 contrib/go/_std_1.23/src/runtime/covermeta.go rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cpuflags.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cpuflags_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cpuflags_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cpuprof.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/cputicks.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/create_file_nounix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/create_file_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/debug.go (83%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/debug/debug.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/debug/garbage.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/debug/mod.go (100%) create mode 100644 contrib/go/_std_1.23/src/runtime/debug/stack.go rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/debug/stubs.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/debug/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/debugcall.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/debuglog.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/debuglog_off.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/debuglog_on.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs1_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs1_netbsd_386.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs1_netbsd_amd64.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs1_netbsd_arm.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs1_netbsd_arm64.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs1_solaris_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs2_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs3_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_aix_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_arm_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_darwin.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_darwin_amd64.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_darwin_arm64.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_dragonfly.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_dragonfly_amd64.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_freebsd.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_freebsd_386.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_freebsd_amd64.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_freebsd_arm.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_freebsd_arm64.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_freebsd_riscv64.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_illumos_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_linux_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_linux_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_linux_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_linux_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_linux_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_linux_mips64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_linux_mipsx.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_linux_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_linux_ppc64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_linux_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_linux_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_netbsd.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_netbsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_netbsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_netbsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_openbsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_openbsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_openbsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_openbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_openbsd_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_openbsd_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_openbsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_plan9_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_plan9_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_plan9_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_solaris_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_windows.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_windows_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_windows_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_windows_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/defs_windows_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/duff_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/duff_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/duff_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/duff_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/duff_loong64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/duff_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/duff_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/duff_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/duff_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/env_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/env_posix.go (70%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/error.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/extern.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/fastlog2.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/fastlog2table.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/fds_nonunix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/fds_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/float.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/funcdata.h (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/go_tls.h (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/hash32.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/hash64.go (76%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/heapdump.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/histogram.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/iface.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/math/math.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/math/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/startlinetest/func_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/startlinetest/func_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/startlinetest/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/sys/consts.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/sys/consts_norace.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/sys/consts_race.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/sys/intrinsics.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/sys/nih.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/sys/sys.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/sys/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/sys/zversion.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/wasitest/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/internal/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/lfstack.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/libfuzzer.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/libfuzzer_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/libfuzzer_arm64.s (100%) create mode 100644 contrib/go/_std_1.23/src/runtime/linkname.go create mode 100644 contrib/go/_std_1.23/src/runtime/linkname_unix.go rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/lock_futex.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/lock_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/lock_sema.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/lock_wasip1.go (100%) create mode 100644 contrib/go/_std_1.23/src/runtime/lockrank.go rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/lockrank_off.go (84%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/lockrank_on.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/malloc.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/map.go (83%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/map_fast32.go (81%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/map_fast64.go (81%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/map_faststr.go (77%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mbarrier.go (85%) rename contrib/go/{_std_1.22/src/runtime/mbitmap_allocheaders.go => _std_1.23/src/runtime/mbitmap.go} (62%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mcache.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mcentral.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mcheckmark.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mem.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mem_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mem_bsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mem_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mem_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mem_linux.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mem_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mem_sbrk.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mem_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mem_wasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mem_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memclr_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memclr_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memclr_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memclr_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memclr_loong64.s (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memclr_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memclr_mipsx.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memclr_plan9_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memclr_plan9_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memclr_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memclr_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memclr_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memclr_wasm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memmove_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memmove_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memmove_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memmove_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memmove_loong64.s (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memmove_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memmove_mipsx.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memmove_plan9_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memmove_plan9_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memmove_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memmove_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memmove_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/memmove_wasm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/metrics.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/metrics/description.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/metrics/doc.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/metrics/histogram.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/metrics/sample.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/metrics/value.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/metrics/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mfinal.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mfixalloc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mgc.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mgclimit.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mgcmark.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mgcpacer.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mgcscavenge.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mgcstack.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mgcsweep.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mgcwork.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mheap.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/minmax.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mkduff.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mkfastlog2table.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mklockrank.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mkpreempt.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mksizeclasses.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mmap.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mpagealloc.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mpagealloc_32bit.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mpagealloc_64bit.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mpagecache.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mpallocbits.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mprof.go (75%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mranges.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/msan.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/msan/msan.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/msan/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/msan0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/msan_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/msan_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/msan_loong64.s (100%) rename contrib/go/{_std_1.22/src/runtime/msize_allocheaders.go => _std_1.23/src/runtime/msize.go} (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mspanset.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mstats.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/mwbbuf.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/nbpipe_pipe.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/nbpipe_pipe2.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/net_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/netpoll.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/netpoll_aix.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/netpoll_epoll.go (73%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/netpoll_fake.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/netpoll_kqueue.go (76%) create mode 100644 contrib/go/_std_1.23/src/runtime/netpoll_kqueue_event.go create mode 100644 contrib/go/_std_1.23/src/runtime/netpoll_kqueue_pipe.go rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/netpoll_solaris.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/netpoll_stub.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/netpoll_wasip1.go (99%) create mode 100644 contrib/go/_std_1.23/src/runtime/netpoll_windows.go rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/nonwindows_stub.go (75%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os2_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os2_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os2_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os2_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os2_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os3_plan9.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os3_solaris.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_aix.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_android.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_darwin_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_freebsd2.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_freebsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_freebsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_freebsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_freebsd_noauxv.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_freebsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_illumos.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_linux.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_linux_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_linux_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_linux_be64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_linux_generic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_linux_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_linux_mips64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_linux_mipsx.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_linux_noauxv.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_linux_novdso.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_linux_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_linux_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_linux_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_linux_x86.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_netbsd.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_netbsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_netbsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_netbsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_netbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_nonopenbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_only_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_openbsd.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_openbsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_openbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_openbsd_libc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_openbsd_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_openbsd_syscall.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_openbsd_syscall1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_openbsd_syscall2.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_plan9.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_plan9_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_unix_nonlinux.go (72%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_wasm.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_windows.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_windows_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/os_windows_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/panic.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/panic32.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pinner.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/plugin.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/defs_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/defs_darwin_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/defs_darwin_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/elf.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/label.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/map.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/pe.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/pprof.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/pprof_norusage.go (71%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/pprof_rusage.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/pprof_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/proto.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/proto_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/proto_other.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/proto_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/protobuf.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/protomem.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/runtime.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/vminfo_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/pprof/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/preempt.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/preempt_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/preempt_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/preempt_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/preempt_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/preempt_loong64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/preempt_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/preempt_mipsx.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/preempt_nonwindows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/preempt_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/preempt_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/preempt_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/preempt_wasm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/print.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/proc.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/profbuf.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/proflabel.go (70%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/README (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/doc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/internal/amd64v1/doc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/internal/amd64v1/race_darwin.syso (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/internal/amd64v1/race_freebsd.syso (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/internal/amd64v1/race_linux.syso (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/internal/amd64v1/race_netbsd.syso (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/internal/amd64v1/race_openbsd.syso (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/internal/amd64v1/race_windows.syso (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/internal/amd64v1/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/internal/amd64v3/doc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/internal/amd64v3/race_linux.syso (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/internal/amd64v3/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/internal/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/race.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/race_darwin_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/race_darwin_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/race_darwin_arm64.syso (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/race_linux_arm64.syso (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/race_linux_ppc64le.syso (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/race_linux_s390x.syso (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/race_v1_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/race_v3_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race_amd64.s (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race_arm64.s (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race_ppc64le.s (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/race_s390x.s (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rand.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rdebug.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/retry.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_aix_ppc64.s (52%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_android_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_android_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_android_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_android_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_darwin_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_darwin_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_dragonfly_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_freebsd_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_freebsd_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_freebsd_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_freebsd_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_freebsd_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_illumos_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_ios_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_ios_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_js_wasm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_linux_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_linux_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_linux_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_linux_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_linux_loong64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_linux_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_linux_mipsx.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_linux_ppc64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_linux_ppc64le.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_linux_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_linux_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_netbsd_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_netbsd_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_netbsd_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_netbsd_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_openbsd_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_openbsd_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_openbsd_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_openbsd_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_openbsd_mips64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_openbsd_ppc64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_openbsd_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_plan9_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_plan9_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_plan9_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_solaris_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_wasip1_wasm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_windows_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_windows_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_windows_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rt0_windows_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/runtime-gdb.py (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/runtime.go (69%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/runtime1.go (81%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/runtime2.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/runtime_boring.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/rwmutex.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/security_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/security_issetugid.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/security_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/security_nonunix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/security_unix.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/select.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sema.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sigaction.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_aix_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_darwin_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_darwin_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_dragonfly_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_freebsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_freebsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_freebsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_freebsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_freebsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_linux_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_linux_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_linux_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_linux_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_linux_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_linux_mips64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_linux_mipsx.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_linux_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_linux_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_linux_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_mips64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_mipsx.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_netbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_netbsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_netbsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_netbsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_netbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_openbsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_openbsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_openbsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_openbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_openbsd_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_openbsd_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_openbsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_solaris_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_unix.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/signal_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sigqueue.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sigqueue_note.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sigqueue_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sigtab_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sigtab_linux_generic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sigtab_linux_mipsx.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sizeclasses.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/slice.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/softfloat64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stack.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stkframe.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/string.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs.go (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs2.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs3.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs_mips64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs_mipsx.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs_nonlinux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/stubs_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/symtab.go (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/symtabinl.go (83%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_aix_ppc64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_darwin.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_darwin_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_darwin_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_darwin_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_dragonfly_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_freebsd_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_freebsd_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_freebsd_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_freebsd_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_freebsd_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_libc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_linux_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_linux_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_linux_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_linux_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_linux_loong64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_linux_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_linux_mipsx.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_linux_ppc64x.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_linux_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_linux_s390x.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_mips64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_mipsx.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_netbsd_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_netbsd_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_netbsd_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_netbsd_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_nonppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_openbsd1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_openbsd2.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_openbsd3.go (82%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_openbsd_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_openbsd_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_openbsd_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_openbsd_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_openbsd_mips64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_openbsd_ppc64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_openbsd_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_plan9_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_plan9_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_plan9_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_solaris_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_wasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_wasm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_windows_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_windows_amd64.s (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_windows_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_windows_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/sys_x86.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/syscall2_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/syscall_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/syscall_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/syscall_windows.go (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/tagptr.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/tagptr_32bit.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/tagptr_64bit.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/test_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/test_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/test_stubs.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/textflag.h (100%) create mode 100644 contrib/go/_std_1.23/src/runtime/time.go rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/time_fake.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/time_linux_amd64.s (100%) create mode 100644 contrib/go/_std_1.23/src/runtime/time_nofake.go rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/time_windows.h (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/time_windows_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/time_windows_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/time_windows_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/time_windows_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/timeasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/timestub.go (59%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/timestub2.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/tls_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/tls_arm64.h (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/tls_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/tls_loong64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/tls_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/tls_mipsx.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/tls_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/tls_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/tls_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/tls_stub.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/tls_windows_amd64.go (100%) rename contrib/go/{_std_1.22/src/runtime/trace2.go => _std_1.23/src/runtime/trace.go} (87%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/trace/annotation.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/trace/trace.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/trace/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/runtime/traceallocfree.go rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/traceback.go (96%) rename contrib/go/{_std_1.22/src/runtime/trace2buf.go => _std_1.23/src/runtime/tracebuf.go} (95%) rename contrib/go/{_std_1.22/src/runtime/trace2cpu.go => _std_1.23/src/runtime/tracecpu.go} (96%) rename contrib/go/{_std_1.22/src/runtime/trace2event.go => _std_1.23/src/runtime/traceevent.go} (89%) create mode 100644 contrib/go/_std_1.23/src/runtime/traceexp.go create mode 100644 contrib/go/_std_1.23/src/runtime/tracemap.go create mode 100644 contrib/go/_std_1.23/src/runtime/traceregion.go rename contrib/go/{_std_1.22/src/runtime/trace2runtime.go => _std_1.23/src/runtime/traceruntime.go} (83%) rename contrib/go/{_std_1.22/src/runtime/trace2stack.go => _std_1.23/src/runtime/tracestack.go} (59%) rename contrib/go/{_std_1.22/src/runtime/trace2status.go => _std_1.23/src/runtime/tracestatus.go} (93%) rename contrib/go/{_std_1.22/src/runtime/trace2string.go => _std_1.23/src/runtime/tracestring.go} (84%) rename contrib/go/{_std_1.22/src/runtime/trace2time.go => _std_1.23/src/runtime/tracetime.go} (95%) create mode 100644 contrib/go/_std_1.23/src/runtime/tracetype.go rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/type.go (92%) create mode 100644 contrib/go/_std_1.23/src/runtime/typekind.go rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/unsafe.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/utf8.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_elf32.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_elf64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_freebsd.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_freebsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_freebsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_freebsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_freebsd_x86.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_in_none.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_linux_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_linux_amd64.go (83%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_linux_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_linux_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_linux_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_linux_mips64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_linux_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_linux_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vdso_linux_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vlop_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vlop_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/vlrt.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/wincallback.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/write_err.go (76%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/write_err_android.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/ya.make (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/zcallback_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/zcallback_windows.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/zcallback_windows_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/runtime/zcallback_windows_arm64.s (100%) create mode 100644 contrib/go/_std_1.23/src/slices/iter.go rename contrib/go/{_std_1.22 => _std_1.23}/src/slices/slices.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/slices/sort.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/slices/ya.make (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/slices/zsortanyfunc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/slices/zsortordered.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sort/gen_sort_variants.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sort/search.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sort/slice.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sort/sort.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sort/sort_impl_120.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sort/sort_impl_go121.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sort/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sort/zsortfunc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sort/zsortinterface.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/atob.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/atoc.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/atof.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/atoi.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/bytealg.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/bytealg_bootstrap.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/ctoa.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/decimal.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/doc.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/eisel_lemire.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/ftoa.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/ftoaryu.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/isprint.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/itoa.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/makeisprint.go (84%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/quote.go (90%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strconv/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strings/builder.go (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strings/clone.go (86%) create mode 100644 contrib/go/_std_1.23/src/strings/compare.go rename contrib/go/{_std_1.22 => _std_1.23}/src/strings/reader.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strings/replace.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strings/search.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strings/strings.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/strings/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/sync/atomic/asm.s rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/atomic/doc.go (76%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/atomic/race.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/atomic/type.go (76%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/atomic/value.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/atomic/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/cond.go (88%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/map.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/mutex.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/once.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/oncefunc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/pool.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/poolqueue.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/runtime.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/runtime2.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/runtime2_lockrank.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/rwmutex.go (87%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/waitgroup.go (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/sync/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm9_unix2_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_aix_ppc64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_darwin_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_darwin_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_freebsd_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_freebsd_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_freebsd_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_linux_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_linux_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_linux_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_linux_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_linux_loong64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_linux_mips64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_linux_mipsx.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_linux_ppc64x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_linux_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_linux_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_netbsd_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_netbsd_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_openbsd_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_openbsd_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_openbsd_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_openbsd_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_openbsd_mips64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_openbsd_ppc64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_openbsd_riscv64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_plan9_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_plan9_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_plan9_arm.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_solaris_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_unix_386.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/asm_unix_amd64.s (100%) create mode 100644 contrib/go/_std_1.23/src/syscall/badlinkname_unix.go rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/bpf_bsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/const_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/dir_plan9.go (84%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/dirent.go (68%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/dll_windows.go (83%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/env_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/env_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/errors_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/exec_bsd.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/exec_freebsd.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/exec_libc.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/exec_libc2.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/exec_linux.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/exec_plan9.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/exec_unix.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/exec_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/flock_aix.go (84%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/flock_bsd.go (80%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/flock_linux.go (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/flock_linux_32bit.go (82%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/forkpipe.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/forkpipe2.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/fs_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/fs_wasip1.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/js/func.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/js/js.go (80%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/js/js_js.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/js/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/syscall/linkname_bsd.go create mode 100644 contrib/go/_std_1.23/src/syscall/linkname_darwin.go create mode 100644 contrib/go/_std_1.23/src/syscall/linkname_libc.go create mode 100644 contrib/go/_std_1.23/src/syscall/linkname_openbsd.go create mode 100644 contrib/go/_std_1.23/src/syscall/linkname_unix.go rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/lsf_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/mkasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/mkpost.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/mksyscall.pl (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/mksyscall_libc.pl (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/mksyscall_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/mksysctl_openbsd.pl (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/mksysnum_dragonfly.pl (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/mksysnum_freebsd.pl (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/mksysnum_linux.pl (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/mksysnum_netbsd.pl (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/mksysnum_openbsd.pl (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/net.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/net_fake.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/net_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/net_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/netlink_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/os_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/pwd_plan9.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/rlimit.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/rlimit_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/rlimit_stub.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/route_bsd.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/route_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/route_dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/route_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/route_freebsd_32bit.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/route_freebsd_64bit.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/route_netbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/route_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/security_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/setuidgid_32_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/setuidgid_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/sockcmsg_dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/sockcmsg_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/sockcmsg_unix.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/sockcmsg_unix_other.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_aix.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_aix_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_bsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_darwin.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_darwin_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_darwin_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_dragonfly_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_freebsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_freebsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_freebsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_freebsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_freebsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_illumos.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_js.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_linux.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_linux_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_linux_accept.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_linux_accept4.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_linux_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_linux_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_linux_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_linux_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_linux_mips64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_linux_mipsx.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_linux_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_linux_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_linux_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_netbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_netbsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_netbsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_netbsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_netbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_openbsd1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_openbsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_openbsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_openbsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_openbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_openbsd_libc.go (73%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_openbsd_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_openbsd_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_openbsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_plan9.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_solaris.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_solaris_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_solarisonly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_unix.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_wasip1.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/syscall_windows.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/tables_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/tables_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/time_fake.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/time_nofake.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/timestruct.go (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/types_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/types_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/types_dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/types_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/types_illumos_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/types_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/types_netbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/types_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/types_solaris.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/types_windows.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/types_windows_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/types_windows_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/types_windows_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/types_windows_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/wtf8_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ya.make (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_aix_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_darwin_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_darwin_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_dragonfly_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_freebsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_freebsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_freebsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_freebsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_freebsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_linux_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_linux_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_linux_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_linux_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_linux_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_linux_mips.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_linux_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_linux_mips64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_linux_mipsle.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_linux_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_linux_ppc64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_linux_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_linux_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_netbsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_netbsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_netbsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_netbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_openbsd_386.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_openbsd_amd64.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_openbsd_arm.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_openbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_openbsd_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_openbsd_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_openbsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_solaris_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zerrors_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_aix_ppc64.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_darwin_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_darwin_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_darwin_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_darwin_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_dragonfly_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_freebsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_freebsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_freebsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_freebsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_freebsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_linux_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_linux_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_linux_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_linux_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_linux_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_linux_mips.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_linux_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_linux_mips64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_linux_mipsle.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_linux_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_linux_ppc64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_linux_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_linux_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_netbsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_netbsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_netbsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_netbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_openbsd_386.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_openbsd_386.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_openbsd_amd64.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_openbsd_amd64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_openbsd_arm.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_openbsd_arm.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_openbsd_arm64.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_openbsd_arm64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_openbsd_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_openbsd_ppc64.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_openbsd_ppc64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_openbsd_riscv64.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_openbsd_riscv64.s (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_plan9_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_plan9_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_plan9_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_solaris_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsyscall_windows.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysctl_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_darwin_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_darwin_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_dragonfly_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_freebsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_freebsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_freebsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_freebsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_freebsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_linux_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_linux_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_linux_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_linux_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_linux_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_linux_mips.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_linux_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_linux_mips64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_linux_mipsle.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_linux_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_linux_ppc64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_linux_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_linux_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_netbsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_netbsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_netbsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_netbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_openbsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_openbsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_openbsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_openbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_openbsd_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_openbsd_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_openbsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/zsysnum_solaris_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_aix_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_darwin_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_darwin_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_dragonfly_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_freebsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_freebsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_freebsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_freebsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_freebsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_linux_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_linux_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_linux_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_linux_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_linux_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_linux_mips.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_linux_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_linux_mips64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_linux_mipsle.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_linux_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_linux_ppc64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_linux_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_linux_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_netbsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_netbsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_netbsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_netbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_openbsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_openbsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_openbsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_openbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_openbsd_mips64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_openbsd_ppc64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_openbsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/syscall/ztypes_solaris_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/text/tabwriter/tabwriter.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/text/tabwriter/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/text/template/doc.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/text/template/exec.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/text/template/funcs.go (93%) rename contrib/go/{_std_1.22 => _std_1.23}/src/text/template/helper.go (80%) rename contrib/go/{_std_1.22 => _std_1.23}/src/text/template/option.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/text/template/parse/lex.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/text/template/parse/node.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/text/template/parse/parse.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/text/template/parse/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/text/template/template.go (96%) rename contrib/go/{_std_1.22 => _std_1.23}/src/text/template/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/embed.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/format.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/format_rfc3339.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/genzabbrs.go (96%) create mode 100644 contrib/go/_std_1.23/src/time/sleep.go rename contrib/go/{_std_1.22 => _std_1.23}/src/time/sys_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/sys_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/sys_windows.go (100%) create mode 100644 contrib/go/_std_1.23/src/time/tick.go rename contrib/go/{_std_1.22 => _std_1.23}/src/time/time.go (94%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/tzdata/tzdata.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/tzdata/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/tzdata/zzipdata.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/zoneinfo.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/zoneinfo_abbrs_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/zoneinfo_android.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/zoneinfo_goroot.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/zoneinfo_ios.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/zoneinfo_js.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/zoneinfo_plan9.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/zoneinfo_read.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/zoneinfo_unix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/zoneinfo_wasip1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/time/zoneinfo_windows.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/unicode/casetables.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/unicode/digit.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/unicode/graphic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/unicode/letter.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/unicode/tables.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/unicode/utf16/utf16.go (89%) rename contrib/go/{_std_1.22 => _std_1.23}/src/unicode/utf16/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/unicode/utf8/utf8.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/unicode/utf8/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/unicode/ya.make (100%) create mode 100644 contrib/go/_std_1.23/src/unique/clone.go create mode 100644 contrib/go/_std_1.23/src/unique/doc.go create mode 100644 contrib/go/_std_1.23/src/unique/handle.go create mode 100644 contrib/go/_std_1.23/src/unique/ya.make rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20/chacha_generic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s (85%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20/xor.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/chacha20poly1305/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/cryptobyte/asn1/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/cryptobyte/builder.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/cryptobyte/string.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/cryptobyte/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/hkdf/hkdf.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/hkdf/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/internal/alias/alias.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/internal/alias/alias_purego.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/internal/alias/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go (91%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/crypto/internal/poly1305/ya.make (96%) create mode 100644 contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/doc.go create mode 100644 contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/hashes.go create mode 100644 contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/hashes_noasm.go create mode 100644 contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf.go create mode 100644 contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf_amd64.go create mode 100644 contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf_amd64.s create mode 100644 contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/register.go create mode 100644 contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3.go create mode 100644 contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3_s390x.go create mode 100644 contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3_s390x.s create mode 100644 contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/shake.go create mode 100644 contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/shake_noasm.go create mode 100644 contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/xor.go create mode 100644 contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/ya.make rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/dns/dnsmessage/message.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/dns/dnsmessage/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/http/httpguts/guts.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/http/httpguts/httplex.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/http/httpguts/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/http/httpproxy/proxy.go (98%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/http/httpproxy/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/http2/hpack/encode.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/http2/hpack/hpack.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/http2/hpack/huffman.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/http2/hpack/static_table.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/http2/hpack/tables.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/http2/hpack/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/go118.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/idna10.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/idna9.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/pre_go118.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/punycode.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/tables10.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/tables11.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/tables12.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/tables13.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/tables15.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/tables9.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/trie.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/trie12.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/trie13.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/trieval.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/idna/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/address.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/binary.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/empty.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/interface.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/interface_announce.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/interface_classic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/interface_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/interface_multicast.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/interface_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/message.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/route.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/route_classic.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/route_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/sys.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/sys_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/sys_dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/sys_freebsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/sys_netbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/sys_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/syscall.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/zsys_darwin.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/zsys_dragonfly.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/zsys_netbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/net/route/zsys_openbsd.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/byteorder.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu.go (99%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_aix.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go (95%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_arm64.s (80%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go (92%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go (97%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_loong64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_mips64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_mipsx.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_other_arm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_riscv64.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_s390x.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_wasm.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_x86.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_x86.s (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_zos.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/endian_big.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/endian_little.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/hwcap_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/parse.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/runtime_auxv.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/sys/cpu/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/secure/bidirule/bidirule.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/secure/bidirule/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/transform/transform.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/transform/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/bidi/bidi.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/bidi/bracket.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/bidi/core.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/bidi/prop.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/bidi/tables15.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/bidi/trieval.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/bidi/ya.make (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/composition.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/forminfo.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/input.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/iter.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/normalize.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/readwriter.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/tables11.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/tables12.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/tables13.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/tables15.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/transform.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/trie.go (100%) rename contrib/go/{_std_1.22 => _std_1.23}/src/vendor/golang.org/x/text/unicode/norm/ya.make (100%) diff --git a/build/conf/go.conf b/build/conf/go.conf index fe60cd622468..b8caa89f8ab3 100644 --- a/build/conf/go.conf +++ b/build/conf/go.conf @@ -59,7 +59,7 @@ elsewhen ($ARCH_ARM64) { GO_HOST_TARG_PARAMS=++host-os $GO_HOST_OS ++host-arch $GO_HOST_ARCH ++targ-os $GO_TARG_OS ++targ-arch $GO_TARG_ARCH # tag:go-specific -GOSTD_VERSION=1.22 +GOSTD_VERSION=1.23 when ($GOSTD_VERSION == "1.23") { GOSTD=contrib/go/_std_1.23/src } diff --git a/build/external_resources/go_tools/go1.22.json b/build/external_resources/go_tools/go1.23.json similarity index 54% rename from build/external_resources/go_tools/go1.22.json rename to build/external_resources/go_tools/go1.23.json index b6fe74abe3d2..8a39f4de82c8 100644 --- a/build/external_resources/go_tools/go1.22.json +++ b/build/external_resources/go_tools/go1.23.json @@ -1,19 +1,19 @@ { "by_platform": { "darwin-arm64": { - "uri": "sbr:6608868508" + "uri": "sbr:8427538159" }, "darwin-x86_64": { - "uri": "sbr:6608867118" - }, - "linux-x86_64": { - "uri": "sbr:6608864313" + "uri": "sbr:8427799199" }, "linux-aarch64": { - "uri": "sbr:6608865495" + "uri": "sbr:8427530593" + }, + "linux-x86_64": { + "uri": "sbr:8428043030" }, "win32-x86_64": { - "uri": "sbr:6608870313" + "uri": "sbr:8427775376" } } } diff --git a/build/mapping.conf.json b/build/mapping.conf.json index 91017db80907..02bd8a71c072 100644 --- a/build/mapping.conf.json +++ b/build/mapping.conf.json @@ -1335,6 +1335,11 @@ "7832062717": "{registry_endpoint}/7832062717", "7663137240": "{registry_endpoint}/7663137240", "7495957585": "{registry_endpoint}/7495957585", + "8427538159": "{registry_endpoint}/8427538159", + "8427799199": "{registry_endpoint}/8427799199", + "8427530593": "{registry_endpoint}/8427530593", + "8428043030": "{registry_endpoint}/8428043030", + "8427775376": "{registry_endpoint}/8427775376", "6048579718": "{registry_endpoint}/6048579718", "7686710688": "{registry_endpoint}/7686710688", "7879860842": "{registry_endpoint}/7879860842", @@ -2677,6 +2682,11 @@ "7832062717": "ynd-clang-format-18-mingw-w64-x86_64-3ac3b151b06039ed3a36becac566665d5fafefa4", "7663137240": "ynd-clang-format-18-mingw-w64-x86_64-809bd279d61c38bc40e133d3013ac46e8c4049b7", "7495957585": "ynd-clang-format-18-mingw-w64-x86_64-d0b9255e235e80974f9dfd0ebff3850929bed981", + "8427538159": "ynd-go-darwin-arm64-b100163d3f3592de99e4cb7db40e7cd1693c1a89", + "8427799199": "ynd-go-darwin-x86_64-b100163d3f3592de99e4cb7db40e7cd1693c1a89", + "8427530593": "ynd-go-linux-aarch64-b100163d3f3592de99e4cb7db40e7cd1693c1a89", + "8428043030": "ynd-go-linux-x86_64-b100163d3f3592de99e4cb7db40e7cd1693c1a89", + "8427775376": "ynd-go-mingw-w64-x86_64-b100163d3f3592de99e4cb7db40e7cd1693c1a89", "6048579718": "yt/go/ytrecipe/cmd/ytexec for linux", "7686710688": "yt/go/ytrecipe/cmd/ytexec for linux", "7879860842": "yt/go/ytrecipe/cmd/ytexec for linux", diff --git a/build/ya.conf.json b/build/ya.conf.json index 1c3d009bfd12..2e79eb344cdf 100644 --- a/build/ya.conf.json +++ b/build/ya.conf.json @@ -243,7 +243,7 @@ "gofmt" ] }, - "formula": "build/external_resources/go_tools/go1.22.json" + "formula": "build/external_resources/go_tools/go1.23.json" }, "jdk17": { "executable": { @@ -1982,7 +1982,7 @@ "golang": { "params": { "type": "golang", - "version": "1.22.1" + "version": "1.23.8" }, "platforms": [ { diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_ppc64x.s b/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_ppc64x.s deleted file mode 100644 index 974f4f945e49..000000000000 --- a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_ppc64x.s +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !purego && (ppc64 || ppc64le) - -#include "textflag.h" - -// func addMulVVW1024(z, x *uint, y uint) (c uint) -TEXT ·addMulVVW1024(SB), $0-32 - MOVD $16, R22 // R22 = z_len - JMP addMulVVWx(SB) - -// func addMulVVW1536(z, x *uint, y uint) (c uint) -TEXT ·addMulVVW1536(SB), $0-32 - MOVD $24, R22 // R22 = z_len - JMP addMulVVWx(SB) - -// func addMulVVW2048(z, x *uint, y uint) (c uint) -TEXT ·addMulVVW2048(SB), $0-32 - MOVD $32, R22 // R22 = z_len - JMP addMulVVWx(SB) - -TEXT addMulVVWx(SB), NOFRAME|NOSPLIT, $0 - MOVD z+0(FP), R10 // R10 = z[] - MOVD x+8(FP), R8 // R8 = x[] - MOVD y+16(FP), R9 // R9 = y - - MOVD R0, R3 // R3 will be the index register - CMP R0, R22 - MOVD R0, R4 // R4 = c = 0 - MOVD R22, CTR // Initialize loop counter - BEQ done - PCALIGN $16 - -loop: - MOVD (R8)(R3), R20 // Load x[i] - MOVD (R10)(R3), R21 // Load z[i] - MULLD R9, R20, R6 // R6 = Low-order(x[i]*y) - MULHDU R9, R20, R7 // R7 = High-order(x[i]*y) - ADDC R21, R6 // R6 = z0 - ADDZE R7 // R7 = z1 - ADDC R4, R6 // R6 = z0 + c + 0 - ADDZE R7, R4 // c += z1 - MOVD R6, (R10)(R3) // Store z[i] - ADD $8, R3 - BC 16, 0, loop // bdnz - -done: - MOVD R4, c+24(FP) - RET diff --git a/contrib/go/_std_1.22/src/crypto/tls/boring.go b/contrib/go/_std_1.22/src/crypto/tls/boring.go deleted file mode 100644 index 1827f764589b..000000000000 --- a/contrib/go/_std_1.22/src/crypto/tls/boring.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build boringcrypto - -package tls - -import ( - "crypto/internal/boring/fipstls" -) - -// needFIPS returns fipstls.Required(); it avoids a new import in common.go. -func needFIPS() bool { - return fipstls.Required() -} - -// fipsMinVersion replaces c.minVersion in FIPS-only mode. -func fipsMinVersion(c *Config) uint16 { - // FIPS requires TLS 1.2. - return VersionTLS12 -} - -// fipsMaxVersion replaces c.maxVersion in FIPS-only mode. -func fipsMaxVersion(c *Config) uint16 { - // FIPS requires TLS 1.2. - return VersionTLS12 -} - -// default defaultFIPSCurvePreferences is the FIPS-allowed curves, -// in preference order (most preferable first). -var defaultFIPSCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521} - -// fipsCurvePreferences replaces c.curvePreferences in FIPS-only mode. -func fipsCurvePreferences(c *Config) []CurveID { - if c == nil || len(c.CurvePreferences) == 0 { - return defaultFIPSCurvePreferences - } - var list []CurveID - for _, id := range c.CurvePreferences { - for _, allowed := range defaultFIPSCurvePreferences { - if id == allowed { - list = append(list, id) - break - } - } - } - return list -} - -// defaultCipherSuitesFIPS are the FIPS-allowed cipher suites. -var defaultCipherSuitesFIPS = []uint16{ - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - TLS_RSA_WITH_AES_128_GCM_SHA256, - TLS_RSA_WITH_AES_256_GCM_SHA384, -} - -// fipsCipherSuites replaces c.cipherSuites in FIPS-only mode. -func fipsCipherSuites(c *Config) []uint16 { - if c == nil || c.CipherSuites == nil { - return defaultCipherSuitesFIPS - } - list := make([]uint16, 0, len(defaultCipherSuitesFIPS)) - for _, id := range c.CipherSuites { - for _, allowed := range defaultCipherSuitesFIPS { - if id == allowed { - list = append(list, id) - break - } - } - } - return list -} - -// fipsSupportedSignatureAlgorithms currently are a subset of -// defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1. -var fipsSupportedSignatureAlgorithms = []SignatureScheme{ - PSSWithSHA256, - PSSWithSHA384, - PSSWithSHA512, - PKCS1WithSHA256, - ECDSAWithP256AndSHA256, - PKCS1WithSHA384, - ECDSAWithP384AndSHA384, - PKCS1WithSHA512, - ECDSAWithP521AndSHA512, -} - -// supportedSignatureAlgorithms returns the supported signature algorithms. -func supportedSignatureAlgorithms() []SignatureScheme { - if !needFIPS() { - return defaultSupportedSignatureAlgorithms - } - return fipsSupportedSignatureAlgorithms -} diff --git a/contrib/go/_std_1.22/src/crypto/tls/notboring.go b/contrib/go/_std_1.22/src/crypto/tls/notboring.go deleted file mode 100644 index 7d85b39c5931..000000000000 --- a/contrib/go/_std_1.22/src/crypto/tls/notboring.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !boringcrypto - -package tls - -func needFIPS() bool { return false } - -func supportedSignatureAlgorithms() []SignatureScheme { - return defaultSupportedSignatureAlgorithms -} - -func fipsMinVersion(c *Config) uint16 { panic("fipsMinVersion") } -func fipsMaxVersion(c *Config) uint16 { panic("fipsMaxVersion") } -func fipsCurvePreferences(c *Config) []CurveID { panic("fipsCurvePreferences") } -func fipsCipherSuites(c *Config) []uint16 { panic("fipsCipherSuites") } - -var fipsSupportedSignatureAlgorithms []SignatureScheme diff --git a/contrib/go/_std_1.22/src/encoding/csv/fuzz.go b/contrib/go/_std_1.22/src/encoding/csv/fuzz.go deleted file mode 100644 index 5f5cdfcbf818..000000000000 --- a/contrib/go/_std_1.22/src/encoding/csv/fuzz.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build gofuzz - -package csv - -import ( - "bytes" - "fmt" - "reflect" -) - -func Fuzz(data []byte) int { - score := 0 - buf := new(bytes.Buffer) - - for _, tt := range []Reader{ - {}, - {Comma: ';'}, - {Comma: '\t'}, - {LazyQuotes: true}, - {TrimLeadingSpace: true}, - {Comment: '#'}, - {Comment: ';'}, - } { - r := NewReader(bytes.NewReader(data)) - r.Comma = tt.Comma - r.Comment = tt.Comment - r.LazyQuotes = tt.LazyQuotes - r.TrimLeadingSpace = tt.TrimLeadingSpace - - records, err := r.ReadAll() - if err != nil { - continue - } - score = 1 - - buf.Reset() - w := NewWriter(buf) - w.Comma = tt.Comma - err = w.WriteAll(records) - if err != nil { - fmt.Printf("writer = %#v\n", w) - fmt.Printf("records = %v\n", records) - panic(err) - } - - r = NewReader(buf) - r.Comma = tt.Comma - r.Comment = tt.Comment - r.LazyQuotes = tt.LazyQuotes - r.TrimLeadingSpace = tt.TrimLeadingSpace - result, err := r.ReadAll() - if err != nil { - fmt.Printf("reader = %#v\n", r) - fmt.Printf("records = %v\n", records) - panic(err) - } - - if !reflect.DeepEqual(records, result) { - fmt.Println("records = \n", records) - fmt.Println("result = \n", records) - panic("not equal") - } - } - - return score -} diff --git a/contrib/go/_std_1.22/src/go/types/alias.go b/contrib/go/_std_1.22/src/go/types/alias.go deleted file mode 100644 index 6043c0a9846d..000000000000 --- a/contrib/go/_std_1.22/src/go/types/alias.go +++ /dev/null @@ -1,90 +0,0 @@ -// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. - -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package types - -import "fmt" - -// An Alias represents an alias type. -// Whether or not Alias types are created is controlled by the -// gotypesalias setting with the GODEBUG environment variable. -// For gotypesalias=1, alias declarations produce an Alias type. -// Otherwise, the alias information is only in the type name, -// which points directly to the actual (aliased) type. -type Alias struct { - obj *TypeName // corresponding declared alias object - fromRHS Type // RHS of type alias declaration; may be an alias - actual Type // actual (aliased) type; never an alias -} - -// NewAlias creates a new Alias type with the given type name and rhs. -// rhs must not be nil. -func NewAlias(obj *TypeName, rhs Type) *Alias { - alias := (*Checker)(nil).newAlias(obj, rhs) - // Ensure that alias.actual is set (#65455). - unalias(alias) - return alias -} - -func (a *Alias) Obj() *TypeName { return a.obj } -func (a *Alias) Underlying() Type { return unalias(a).Underlying() } -func (a *Alias) String() string { return TypeString(a, nil) } - -// Type accessors - -// Unalias returns t if it is not an alias type; -// otherwise it follows t's alias chain until it -// reaches a non-alias type which is then returned. -// Consequently, the result is never an alias type. -func Unalias(t Type) Type { - if a0, _ := t.(*Alias); a0 != nil { - return unalias(a0) - } - return t -} - -func unalias(a0 *Alias) Type { - if a0.actual != nil { - return a0.actual - } - var t Type - for a := a0; a != nil; a, _ = t.(*Alias) { - t = a.fromRHS - } - if t == nil { - panic(fmt.Sprintf("non-terminated alias %s", a0.obj.name)) - } - a0.actual = t - return t -} - -// asNamed returns t as *Named if that is t's -// actual type. It returns nil otherwise. -func asNamed(t Type) *Named { - n, _ := Unalias(t).(*Named) - return n -} - -// newAlias creates a new Alias type with the given type name and rhs. -// rhs must not be nil. -func (check *Checker) newAlias(obj *TypeName, rhs Type) *Alias { - assert(rhs != nil) - a := &Alias{obj, rhs, nil} - if obj.typ == nil { - obj.typ = a - } - - // Ensure that a.actual is set at the end of type checking. - if check != nil { - check.needsCleanup(a) - } - - return a -} - -func (a *Alias) cleanup() { - Unalias(a) -} diff --git a/contrib/go/_std_1.22/src/go/types/errors.go b/contrib/go/_std_1.22/src/go/types/errors.go deleted file mode 100644 index 63b0d9db8f22..000000000000 --- a/contrib/go/_std_1.22/src/go/types/errors.go +++ /dev/null @@ -1,400 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file implements various error reporters. - -package types - -import ( - "bytes" - "fmt" - "go/ast" - "go/token" - . "internal/types/errors" - "runtime" - "strconv" - "strings" -) - -func assert(p bool) { - if !p { - msg := "assertion failed" - // Include information about the assertion location. Due to panic recovery, - // this location is otherwise buried in the middle of the panicking stack. - if _, file, line, ok := runtime.Caller(1); ok { - msg = fmt.Sprintf("%s:%d: %s", file, line, msg) - } - panic(msg) - } -} - -func unreachable() { - panic("unreachable") -} - -// An error_ represents a type-checking error. -// To report an error_, call Checker.report. -type error_ struct { - desc []errorDesc - code Code - soft bool // TODO(gri) eventually determine this from an error code -} - -// An errorDesc describes part of a type-checking error. -type errorDesc struct { - posn positioner - format string - args []interface{} -} - -func (err *error_) empty() bool { - return err.desc == nil -} - -func (err *error_) pos() token.Pos { - if err.empty() { - return nopos - } - return err.desc[0].posn.Pos() -} - -func (err *error_) msg(fset *token.FileSet, qf Qualifier) string { - if err.empty() { - return "no error" - } - var buf strings.Builder - for i := range err.desc { - p := &err.desc[i] - if i > 0 { - fmt.Fprint(&buf, "\n\t") - if p.posn.Pos().IsValid() { - fmt.Fprintf(&buf, "%s: ", fset.Position(p.posn.Pos())) - } - } - buf.WriteString(sprintf(fset, qf, false, p.format, p.args...)) - } - return buf.String() -} - -// String is for testing. -func (err *error_) String() string { - if err.empty() { - return "no error" - } - return fmt.Sprintf("%d: %s", err.pos(), err.msg(nil, nil)) -} - -// errorf adds formatted error information to err. -// It may be called multiple times to provide additional information. -func (err *error_) errorf(at token.Pos, format string, args ...interface{}) { - err.desc = append(err.desc, errorDesc{atPos(at), format, args}) -} - -func (check *Checker) qualifier(pkg *Package) string { - // Qualify the package unless it's the package being type-checked. - if pkg != check.pkg { - if check.pkgPathMap == nil { - check.pkgPathMap = make(map[string]map[string]bool) - check.seenPkgMap = make(map[*Package]bool) - check.markImports(check.pkg) - } - // If the same package name was used by multiple packages, display the full path. - if len(check.pkgPathMap[pkg.name]) > 1 { - return strconv.Quote(pkg.path) - } - return pkg.name - } - return "" -} - -// markImports recursively walks pkg and its imports, to record unique import -// paths in pkgPathMap. -func (check *Checker) markImports(pkg *Package) { - if check.seenPkgMap[pkg] { - return - } - check.seenPkgMap[pkg] = true - - forName, ok := check.pkgPathMap[pkg.name] - if !ok { - forName = make(map[string]bool) - check.pkgPathMap[pkg.name] = forName - } - forName[pkg.path] = true - - for _, imp := range pkg.imports { - check.markImports(imp) - } -} - -// check may be nil. -func (check *Checker) sprintf(format string, args ...any) string { - var fset *token.FileSet - var qf Qualifier - if check != nil { - fset = check.fset - qf = check.qualifier - } - return sprintf(fset, qf, false, format, args...) -} - -func sprintf(fset *token.FileSet, qf Qualifier, tpSubscripts bool, format string, args ...any) string { - for i, arg := range args { - switch a := arg.(type) { - case nil: - arg = "" - case operand: - panic("got operand instead of *operand") - case *operand: - arg = operandString(a, qf) - case token.Pos: - if fset != nil { - arg = fset.Position(a).String() - } - case ast.Expr: - arg = ExprString(a) - case []ast.Expr: - var buf bytes.Buffer - buf.WriteByte('[') - writeExprList(&buf, a) - buf.WriteByte(']') - arg = buf.String() - case Object: - arg = ObjectString(a, qf) - case Type: - var buf bytes.Buffer - w := newTypeWriter(&buf, qf) - w.tpSubscripts = tpSubscripts - w.typ(a) - arg = buf.String() - case []Type: - var buf bytes.Buffer - w := newTypeWriter(&buf, qf) - w.tpSubscripts = tpSubscripts - buf.WriteByte('[') - for i, x := range a { - if i > 0 { - buf.WriteString(", ") - } - w.typ(x) - } - buf.WriteByte(']') - arg = buf.String() - case []*TypeParam: - var buf bytes.Buffer - w := newTypeWriter(&buf, qf) - w.tpSubscripts = tpSubscripts - buf.WriteByte('[') - for i, x := range a { - if i > 0 { - buf.WriteString(", ") - } - w.typ(x) - } - buf.WriteByte(']') - arg = buf.String() - } - args[i] = arg - } - return fmt.Sprintf(format, args...) -} - -func (check *Checker) trace(pos token.Pos, format string, args ...any) { - fmt.Printf("%s:\t%s%s\n", - check.fset.Position(pos), - strings.Repeat(". ", check.indent), - sprintf(check.fset, check.qualifier, true, format, args...), - ) -} - -// dump is only needed for debugging -func (check *Checker) dump(format string, args ...any) { - fmt.Println(sprintf(check.fset, check.qualifier, true, format, args...)) -} - -// Report records the error pointed to by errp, setting check.firstError if -// necessary. -func (check *Checker) report(errp *error_) { - if errp.empty() { - panic("empty error details") - } - - msg := errp.msg(check.fset, check.qualifier) - switch errp.code { - case InvalidSyntaxTree: - msg = "invalid AST: " + msg - case 0: - panic("no error code provided") - } - - // If we have a URL for error codes, add a link to the first line. - if errp.code != 0 && check.conf._ErrorURL != "" { - u := fmt.Sprintf(check.conf._ErrorURL, errp.code) - if i := strings.Index(msg, "\n"); i >= 0 { - msg = msg[:i] + u + msg[i:] - } else { - msg += u - } - } - - span := spanOf(errp.desc[0].posn) - e := Error{ - Fset: check.fset, - Pos: span.pos, - Msg: msg, - Soft: errp.soft, - go116code: errp.code, - go116start: span.start, - go116end: span.end, - } - - // Cheap trick: Don't report errors with messages containing - // "invalid operand" or "invalid type" as those tend to be - // follow-on errors which don't add useful information. Only - // exclude them if these strings are not at the beginning, - // and only if we have at least one error already reported. - isInvalidErr := strings.Index(e.Msg, "invalid operand") > 0 || strings.Index(e.Msg, "invalid type") > 0 - if check.firstErr != nil && isInvalidErr { - return - } - - e.Msg = stripAnnotations(e.Msg) - if check.errpos != nil { - // If we have an internal error and the errpos override is set, use it to - // augment our error positioning. - // TODO(rFindley) we may also want to augment the error message and refer - // to the position (pos) in the original expression. - span := spanOf(check.errpos) - e.Pos = span.pos - e.go116start = span.start - e.go116end = span.end - } - err := e - - if check.firstErr == nil { - check.firstErr = err - } - - if check.conf._Trace { - pos := e.Pos - msg := e.Msg - check.trace(pos, "ERROR: %s", msg) - } - - f := check.conf.Error - if f == nil { - panic(bailout{}) // report only first error - } - f(err) -} - -const ( - invalidArg = "invalid argument: " - invalidOp = "invalid operation: " -) - -// newErrorf creates a new error_ for later reporting with check.report. -func newErrorf(at positioner, code Code, format string, args ...any) *error_ { - return &error_{ - desc: []errorDesc{{at, format, args}}, - code: code, - } -} - -func (check *Checker) error(at positioner, code Code, msg string) { - check.report(newErrorf(at, code, "%s", msg)) -} - -func (check *Checker) errorf(at positioner, code Code, format string, args ...any) { - check.report(newErrorf(at, code, format, args...)) -} - -func (check *Checker) softErrorf(at positioner, code Code, format string, args ...any) { - err := newErrorf(at, code, format, args...) - err.soft = true - check.report(err) -} - -func (check *Checker) versionErrorf(at positioner, v goVersion, format string, args ...interface{}) { - msg := check.sprintf(format, args...) - var err *error_ - err = newErrorf(at, UnsupportedFeature, "%s requires %s or later", msg, v) - check.report(err) -} - -// The positioner interface is used to extract the position of type-checker -// errors. -type positioner interface { - Pos() token.Pos -} - -// posSpan holds a position range along with a highlighted position within that -// range. This is used for positioning errors, with pos by convention being the -// first position in the source where the error is known to exist, and start -// and end defining the full span of syntax being considered when the error was -// detected. Invariant: start <= pos < end || start == pos == end. -type posSpan struct { - start, pos, end token.Pos -} - -func (e posSpan) Pos() token.Pos { - return e.pos -} - -// inNode creates a posSpan for the given node. -// Invariant: node.Pos() <= pos < node.End() (node.End() is the position of the -// first byte after node within the source). -func inNode(node ast.Node, pos token.Pos) posSpan { - start, end := node.Pos(), node.End() - if debug { - assert(start <= pos && pos < end) - } - return posSpan{start, pos, end} -} - -// atPos wraps a token.Pos to implement the positioner interface. -type atPos token.Pos - -func (s atPos) Pos() token.Pos { - return token.Pos(s) -} - -// spanOf extracts an error span from the given positioner. By default this is -// the trivial span starting and ending at pos, but this span is expanded when -// the argument naturally corresponds to a span of source code. -func spanOf(at positioner) posSpan { - switch x := at.(type) { - case nil: - panic("nil positioner") - case posSpan: - return x - case ast.Node: - pos := x.Pos() - return posSpan{pos, pos, x.End()} - case *operand: - if x.expr != nil { - pos := x.Pos() - return posSpan{pos, pos, x.expr.End()} - } - return posSpan{nopos, nopos, nopos} - default: - pos := at.Pos() - return posSpan{pos, pos, pos} - } -} - -// stripAnnotations removes internal (type) annotations from s. -func stripAnnotations(s string) string { - var buf strings.Builder - for _, r := range s { - // strip #'s and subscript digits - if r < '₀' || '₀'+10 <= r { // '₀' == U+2080 - buf.WriteRune(r) - } - } - if buf.Len() < len(s) { - return buf.String() - } - return s -} diff --git a/contrib/go/_std_1.22/src/go/types/util.go b/contrib/go/_std_1.22/src/go/types/util.go deleted file mode 100644 index 87e1240010bd..000000000000 --- a/contrib/go/_std_1.22/src/go/types/util.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// This file contains various functionality that is -// different between go/types and types2. Factoring -// out this code allows more of the rest of the code -// to be shared. - -package types - -import "go/token" - -// cmpPos compares the positions p and q and returns a result r as follows: -// -// r < 0: p is before q -// r == 0: p and q are the same position (but may not be identical) -// r > 0: p is after q -// -// If p and q are in different files, p is before q if the filename -// of p sorts lexicographically before the filename of q. -func cmpPos(p, q token.Pos) int { return int(p - q) } diff --git a/contrib/go/_std_1.22/src/internal/coverage/rtcov/rtcov.go b/contrib/go/_std_1.22/src/internal/coverage/rtcov/rtcov.go deleted file mode 100644 index bbb93acced7d..000000000000 --- a/contrib/go/_std_1.22/src/internal/coverage/rtcov/rtcov.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package rtcov - -// This package contains types whose structure is shared between -// the runtime package and the "runtime/coverage" package. - -// CovMetaBlob is a container for holding the meta-data symbol (an -// RODATA variable) for an instrumented Go package. Here "p" points to -// the symbol itself, "len" is the length of the sym in bytes, and -// "hash" is an md5sum for the sym computed by the compiler. When -// the init function for a coverage-instrumented package executes, it -// will make a call into the runtime which will create a covMetaBlob -// object for the package and chain it onto a global list. -type CovMetaBlob struct { - P *byte - Len uint32 - Hash [16]byte - PkgPath string - PkgID int - CounterMode uint8 // coverage.CounterMode - CounterGranularity uint8 // coverage.CounterGranularity -} - -// CovCounterBlob is a container for encapsulating a counter section -// (BSS variable) for an instrumented Go module. Here "counters" -// points to the counter payload and "len" is the number of uint32 -// entries in the section. -type CovCounterBlob struct { - Counters *uint32 - Len uint64 -} diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_allocheaders_off.go b/contrib/go/_std_1.22/src/internal/goexperiment/exp_allocheaders_off.go deleted file mode 100644 index 72c702f9e706..000000000000 --- a/contrib/go/_std_1.22/src/internal/goexperiment/exp_allocheaders_off.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build !goexperiment.allocheaders - -package goexperiment - -const AllocHeaders = false -const AllocHeadersInt = 0 diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_allocheaders_on.go b/contrib/go/_std_1.22/src/internal/goexperiment/exp_allocheaders_on.go deleted file mode 100644 index f9f2965fe2e4..000000000000 --- a/contrib/go/_std_1.22/src/internal/goexperiment/exp_allocheaders_on.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build goexperiment.allocheaders - -package goexperiment - -const AllocHeaders = true -const AllocHeadersInt = 1 diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_exectracer2_off.go b/contrib/go/_std_1.22/src/internal/goexperiment/exp_exectracer2_off.go deleted file mode 100644 index 2f9c8269d891..000000000000 --- a/contrib/go/_std_1.22/src/internal/goexperiment/exp_exectracer2_off.go +++ /dev/null @@ -1,9 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build !goexperiment.exectracer2 -// +build !goexperiment.exectracer2 - -package goexperiment - -const ExecTracer2 = false -const ExecTracer2Int = 0 diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_exectracer2_on.go b/contrib/go/_std_1.22/src/internal/goexperiment/exp_exectracer2_on.go deleted file mode 100644 index f94a29247fac..000000000000 --- a/contrib/go/_std_1.22/src/internal/goexperiment/exp_exectracer2_on.go +++ /dev/null @@ -1,9 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build goexperiment.exectracer2 -// +build goexperiment.exectracer2 - -package goexperiment - -const ExecTracer2 = true -const ExecTracer2Int = 1 diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_pagetrace_off.go b/contrib/go/_std_1.22/src/internal/goexperiment/exp_pagetrace_off.go deleted file mode 100644 index 142be47d963d..000000000000 --- a/contrib/go/_std_1.22/src/internal/goexperiment/exp_pagetrace_off.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build !goexperiment.pagetrace - -package goexperiment - -const PageTrace = false -const PageTraceInt = 0 diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_pagetrace_on.go b/contrib/go/_std_1.22/src/internal/goexperiment/exp_pagetrace_on.go deleted file mode 100644 index f3b161478901..000000000000 --- a/contrib/go/_std_1.22/src/internal/goexperiment/exp_pagetrace_on.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by mkconsts.go. DO NOT EDIT. - -//go:build goexperiment.pagetrace - -package goexperiment - -const PageTrace = true -const PageTraceInt = 1 diff --git a/contrib/go/_std_1.22/src/internal/intern/intern.go b/contrib/go/_std_1.22/src/internal/intern/intern.go deleted file mode 100644 index 2f97c2e66942..000000000000 --- a/contrib/go/_std_1.22/src/internal/intern/intern.go +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright 2020 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package intern lets you make smaller comparable values by boxing -// a larger comparable value (such as a 16 byte string header) down -// into a globally unique 8 byte pointer. -// -// The globally unique pointers are garbage collected with weak -// references and finalizers. This package hides that. -package intern - -import ( - "internal/godebug" - "runtime" - "sync" - "unsafe" -) - -// A Value pointer is the handle to an underlying comparable value. -// See func Get for how Value pointers may be used. -type Value struct { - _ [0]func() // prevent people from accidentally using value type as comparable - cmpVal any - // resurrected is guarded by mu (for all instances of Value). - // It is set true whenever v is synthesized from a uintptr. - resurrected bool -} - -// Get returns the comparable value passed to the Get func -// that returned v. -func (v *Value) Get() any { return v.cmpVal } - -// key is a key in our global value map. -// It contains type-specialized fields to avoid allocations -// when converting common types to empty interfaces. -type key struct { - s string - cmpVal any - // isString reports whether key contains a string. - // Without it, the zero value of key is ambiguous. - isString bool -} - -// keyFor returns a key to use with cmpVal. -func keyFor(cmpVal any) key { - if s, ok := cmpVal.(string); ok { - return key{s: s, isString: true} - } - return key{cmpVal: cmpVal} -} - -// Value returns a *Value built from k. -func (k key) Value() *Value { - if k.isString { - return &Value{cmpVal: k.s} - } - return &Value{cmpVal: k.cmpVal} -} - -var ( - // mu guards valMap, a weakref map of *Value by underlying value. - // It also guards the resurrected field of all *Values. - mu sync.Mutex - valMap = map[key]uintptr{} // to uintptr(*Value) - valSafe = safeMap() // non-nil in safe+leaky mode -) - -var intern = godebug.New("#intern") - -// safeMap returns a non-nil map if we're in safe-but-leaky mode, -// as controlled by GODEBUG=intern=leaky -func safeMap() map[key]*Value { - if intern.Value() == "leaky" { - return map[key]*Value{} - } - return nil -} - -// Get returns a pointer representing the comparable value cmpVal. -// -// The returned pointer will be the same for Get(v) and Get(v2) -// if and only if v == v2, and can be used as a map key. -func Get(cmpVal any) *Value { - return get(keyFor(cmpVal)) -} - -// GetByString is identical to Get, except that it is specialized for strings. -// This avoids an allocation from putting a string into an interface{} -// to pass as an argument to Get. -func GetByString(s string) *Value { - return get(key{s: s, isString: true}) -} - -// We play unsafe games that violate Go's rules (and assume a non-moving -// collector). So we quiet Go here. -// See the comment below Get for more implementation details. -// -//go:nocheckptr -func get(k key) *Value { - mu.Lock() - defer mu.Unlock() - - var v *Value - if valSafe != nil { - v = valSafe[k] - } else if addr, ok := valMap[k]; ok { - v = (*Value)(unsafe.Pointer(addr)) - v.resurrected = true - } - if v != nil { - return v - } - v = k.Value() - if valSafe != nil { - valSafe[k] = v - } else { - // SetFinalizer before uintptr conversion (theoretical concern; - // see https://github.com/go4org/intern/issues/13) - runtime.SetFinalizer(v, finalize) - valMap[k] = uintptr(unsafe.Pointer(v)) - } - return v -} - -func finalize(v *Value) { - mu.Lock() - defer mu.Unlock() - if v.resurrected { - // We lost the race. Somebody resurrected it while we - // were about to finalize it. Try again next round. - v.resurrected = false - runtime.SetFinalizer(v, finalize) - return - } - delete(valMap, keyFor(v.cmpVal)) -} - -// Interning is simple if you don't require that unused values be -// garbage collectable. But we do require that; we don't want to be -// DOS vector. We do this by using a uintptr to hide the pointer from -// the garbage collector, and using a finalizer to eliminate the -// pointer when no other code is using it. -// -// The obvious implementation of this is to use a -// map[interface{}]uintptr-of-*interface{}, and set up a finalizer to -// delete from the map. Unfortunately, this is racy. Because pointers -// are being created in violation of Go's unsafety rules, it's -// possible to create a pointer to a value concurrently with the GC -// concluding that the value can be collected. There are other races -// that break the equality invariant as well, but the use-after-free -// will cause a runtime crash. -// -// To make this work, the finalizer needs to know that no references -// have been unsafely created since the finalizer was set up. To do -// this, values carry a "resurrected" sentinel, which gets set -// whenever a pointer is unsafely created. If the finalizer encounters -// the sentinel, it clears the sentinel and delays collection for one -// additional GC cycle, by re-installing itself as finalizer. This -// ensures that the unsafely created pointer is visible to the GC, and -// will correctly prevent collection. -// -// This technique does mean that interned values that get reused take -// at least 3 GC cycles to fully collect (1 to clear the sentinel, 1 -// to clean up the unsafe map, 1 to be actually deleted). -// -// @ianlancetaylor commented in -// https://github.com/golang/go/issues/41303#issuecomment-717401656 -// that it is possible to implement weak references in terms of -// finalizers without unsafe. Unfortunately, the approach he outlined -// does not work here, for two reasons. First, there is no way to -// construct a strong pointer out of a weak pointer; our map stores -// weak pointers, but we must return strong pointers to callers. -// Second, and more fundamentally, we must return not just _a_ strong -// pointer to callers, but _the same_ strong pointer to callers. In -// order to return _the same_ strong pointer to callers, we must track -// it, which is exactly what we cannot do with strong pointers. -// -// See https://github.com/inetaf/netaddr/issues/53 for more -// discussion, and https://github.com/go4org/intern/issues/2 for an -// illustration of the subtleties at play. diff --git a/contrib/go/_std_1.22/src/internal/poll/sendfile_linux.go b/contrib/go/_std_1.22/src/internal/poll/sendfile_linux.go deleted file mode 100644 index cc31969a43f9..000000000000 --- a/contrib/go/_std_1.22/src/internal/poll/sendfile_linux.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package poll - -import "syscall" - -// maxSendfileSize is the largest chunk size we ask the kernel to copy -// at a time. -const maxSendfileSize int = 4 << 20 - -// SendFile wraps the sendfile system call. -func SendFile(dstFD *FD, src int, remain int64) (int64, error, bool) { - if err := dstFD.writeLock(); err != nil { - return 0, err, false - } - defer dstFD.writeUnlock() - if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { - return 0, err, false - } - - dst := dstFD.Sysfd - var ( - written int64 - err error - handled = true - ) - for remain > 0 { - n := maxSendfileSize - if int64(n) > remain { - n = int(remain) - } - n, err1 := syscall.Sendfile(dst, src, nil, n) - if n > 0 { - written += int64(n) - remain -= int64(n) - } else if n == 0 && err1 == nil { - break - } - if err1 == syscall.EINTR { - continue - } - if err1 == syscall.EAGAIN { - if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil { - continue - } - } - if err1 != nil { - // This includes syscall.ENOSYS (no kernel - // support) and syscall.EINVAL (fd types which - // don't implement sendfile) - err = err1 - handled = false - break - } - } - return written, err, handled -} diff --git a/contrib/go/_std_1.22/src/internal/poll/strconv.go b/contrib/go/_std_1.22/src/internal/poll/strconv.go deleted file mode 100644 index 2b052fa1747f..000000000000 --- a/contrib/go/_std_1.22/src/internal/poll/strconv.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build plan9 - -package poll - -// stringsHasSuffix is strings.HasSuffix. It reports whether s ends in -// suffix. -func stringsHasSuffix(s, suffix string) bool { - return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix -} diff --git a/contrib/go/_std_1.22/src/internal/safefilepath/path.go b/contrib/go/_std_1.22/src/internal/safefilepath/path.go deleted file mode 100644 index 0f0a270c3034..000000000000 --- a/contrib/go/_std_1.22/src/internal/safefilepath/path.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package safefilepath manipulates operating-system file paths. -package safefilepath - -import ( - "errors" -) - -var errInvalidPath = errors.New("invalid path") - -// FromFS converts a slash-separated path into an operating-system path. -// -// FromFS returns an error if the path cannot be represented by the operating -// system. For example, paths containing '\' and ':' characters are rejected -// on Windows. -func FromFS(path string) (string, error) { - return fromFS(path) -} diff --git a/contrib/go/_std_1.22/src/internal/safefilepath/path_other.go b/contrib/go/_std_1.22/src/internal/safefilepath/path_other.go deleted file mode 100644 index 974e7751a290..000000000000 --- a/contrib/go/_std_1.22/src/internal/safefilepath/path_other.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !windows - -package safefilepath - -import "runtime" - -func fromFS(path string) (string, error) { - if runtime.GOOS == "plan9" { - if len(path) > 0 && path[0] == '#' { - return "", errInvalidPath - } - } - for i := range path { - if path[i] == 0 { - return "", errInvalidPath - } - } - return path, nil -} diff --git a/contrib/go/_std_1.22/src/internal/safefilepath/path_windows.go b/contrib/go/_std_1.22/src/internal/safefilepath/path_windows.go deleted file mode 100644 index 7cfd6ce2eac2..000000000000 --- a/contrib/go/_std_1.22/src/internal/safefilepath/path_windows.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package safefilepath - -import ( - "syscall" - "unicode/utf8" -) - -func fromFS(path string) (string, error) { - if !utf8.ValidString(path) { - return "", errInvalidPath - } - for len(path) > 1 && path[0] == '/' && path[1] == '/' { - path = path[1:] - } - containsSlash := false - for p := path; p != ""; { - // Find the next path element. - i := 0 - for i < len(p) && p[i] != '/' { - switch p[i] { - case 0, '\\', ':': - return "", errInvalidPath - } - i++ - } - part := p[:i] - if i < len(p) { - containsSlash = true - p = p[i+1:] - } else { - p = "" - } - if IsReservedName(part) { - return "", errInvalidPath - } - } - if containsSlash { - // We can't depend on strings, so substitute \ for / manually. - buf := []byte(path) - for i, b := range buf { - if b == '/' { - buf[i] = '\\' - } - } - path = string(buf) - } - return path, nil -} - -// IsReservedName reports if name is a Windows reserved device name. -// It does not detect names with an extension, which are also reserved on some Windows versions. -// -// For details, search for PRN in -// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file. -func IsReservedName(name string) bool { - // Device names can have arbitrary trailing characters following a dot or colon. - base := name - for i := 0; i < len(base); i++ { - switch base[i] { - case ':', '.': - base = base[:i] - } - } - // Trailing spaces in the last path element are ignored. - for len(base) > 0 && base[len(base)-1] == ' ' { - base = base[:len(base)-1] - } - if !isReservedBaseName(base) { - return false - } - if len(base) == len(name) { - return true - } - // The path element is a reserved name with an extension. - // Some Windows versions consider this a reserved name, - // while others do not. Use FullPath to see if the name is - // reserved. - if p, _ := syscall.FullPath(name); len(p) >= 4 && p[:4] == `\\.\` { - return true - } - return false -} - -func isReservedBaseName(name string) bool { - if len(name) == 3 { - switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { - case "CON", "PRN", "AUX", "NUL": - return true - } - } - if len(name) >= 4 { - switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { - case "COM", "LPT": - if len(name) == 4 && '1' <= name[3] && name[3] <= '9' { - return true - } - // Superscript ¹, ², and ³ are considered numbers as well. - switch name[3:] { - case "\u00b2", "\u00b3", "\u00b9": - return true - } - return false - } - } - - // Passing CONIN$ or CONOUT$ to CreateFile opens a console handle. - // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#consoles - // - // While CONIN$ and CONOUT$ aren't documented as being files, - // they behave the same as CON. For example, ./CONIN$ also opens the console input. - if len(name) == 6 && name[5] == '$' && equalFold(name, "CONIN$") { - return true - } - if len(name) == 7 && name[6] == '$' && equalFold(name, "CONOUT$") { - return true - } - return false -} - -func equalFold(a, b string) bool { - if len(a) != len(b) { - return false - } - for i := 0; i < len(a); i++ { - if toUpper(a[i]) != toUpper(b[i]) { - return false - } - } - return true -} - -func toUpper(c byte) byte { - if 'a' <= c && c <= 'z' { - return c - ('a' - 'A') - } - return c -} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_openbsd.go b/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_openbsd.go deleted file mode 100644 index fd389477ec33..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_openbsd.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package unix - -import "syscall" - -const unlinkatTrap uintptr = syscall.SYS_UNLINKAT -const openatTrap uintptr = syscall.SYS_OPENAT -const fstatatTrap uintptr = syscall.SYS_FSTATAT - -const AT_REMOVEDIR = 0x08 -const AT_SYMLINK_NOFOLLOW = 0x02 - -const UTIME_OMIT = -0x1 diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_darwin.go b/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_darwin.go deleted file mode 100644 index 834099ffed64..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_darwin.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin && !ios - -package unix - -import ( - "internal/abi" - "unsafe" -) - -//go:cgo_import_dynamic libc_getentropy getentropy "/usr/lib/libSystem.B.dylib" - -func libc_getentropy_trampoline() - -// GetEntropy calls the macOS getentropy system call. -func GetEntropy(p []byte) error { - _, _, errno := syscall_syscall(abi.FuncPCABI0(libc_getentropy_trampoline), - uintptr(unsafe.Pointer(&p[0])), - uintptr(len(p)), - 0) - if errno != 0 { - return errno - } - return nil -} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_darwin.s b/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_darwin.s deleted file mode 100644 index f41e0fe97b09..000000000000 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_darwin.s +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build darwin && !ios - -#include "textflag.h" - -TEXT ·libc_getentropy_trampoline(SB),NOSPLIT,$0-0; JMP libc_getentropy(SB) diff --git a/contrib/go/_std_1.22/src/math/big/arith_decl.go b/contrib/go/_std_1.22/src/math/big/arith_decl.go deleted file mode 100644 index f14f8d6794ee..000000000000 --- a/contrib/go/_std_1.22/src/math/big/arith_decl.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !math_big_pure_go - -package big - -// implemented in arith_$GOARCH.s - -//go:noescape -func addVV(z, x, y []Word) (c Word) - -//go:noescape -func subVV(z, x, y []Word) (c Word) - -//go:noescape -func addVW(z, x []Word, y Word) (c Word) - -//go:noescape -func subVW(z, x []Word, y Word) (c Word) - -//go:noescape -func shlVU(z, x []Word, s uint) (c Word) - -//go:noescape -func shrVU(z, x []Word, s uint) (c Word) - -//go:noescape -func mulAddVWW(z, x []Word, y, r Word) (c Word) - -//go:noescape -func addMulVVW(z, x []Word, y Word) (c Word) diff --git a/contrib/go/_std_1.22/src/math/rand/v2/chacha8.go b/contrib/go/_std_1.22/src/math/rand/v2/chacha8.go deleted file mode 100644 index 6b9aa7278250..000000000000 --- a/contrib/go/_std_1.22/src/math/rand/v2/chacha8.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package rand - -import "internal/chacha8rand" - -// A ChaCha8 is a ChaCha8-based cryptographically strong -// random number generator. -type ChaCha8 struct { - state chacha8rand.State -} - -// NewChaCha8 returns a new ChaCha8 seeded with the given seed. -func NewChaCha8(seed [32]byte) *ChaCha8 { - c := new(ChaCha8) - c.state.Init(seed) - return c -} - -// Seed resets the ChaCha8 to behave the same way as NewChaCha8(seed). -func (c *ChaCha8) Seed(seed [32]byte) { - c.state.Init(seed) -} - -// Uint64 returns a uniformly distributed random uint64 value. -func (c *ChaCha8) Uint64() uint64 { - for { - x, ok := c.state.Next() - if ok { - return x - } - c.state.Refill() - } -} - -// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. -func (c *ChaCha8) UnmarshalBinary(data []byte) error { - return chacha8rand.Unmarshal(&c.state, data) -} - -// MarshalBinary implements the encoding.BinaryMarshaler interface. -func (c *ChaCha8) MarshalBinary() ([]byte, error) { - return chacha8rand.Marshal(&c.state), nil -} diff --git a/contrib/go/_std_1.22/src/net/cgo_unix_cgo_darwin.go b/contrib/go/_std_1.22/src/net/cgo_unix_cgo_darwin.go deleted file mode 100644 index 40d5e426f25c..000000000000 --- a/contrib/go/_std_1.22/src/net/cgo_unix_cgo_darwin.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !netgo && cgo && darwin - -package net - -/* -#include -*/ -import "C" - -import ( - "internal/syscall/unix" - "unsafe" -) - -// This will cause a compile error when the size of -// unix.ResState is too small. -type _ [unsafe.Sizeof(unix.ResState{}) - unsafe.Sizeof(C.struct___res_state{})]byte diff --git a/contrib/go/_std_1.22/src/net/http/internal/testcert/testcert.go b/contrib/go/_std_1.22/src/net/http/internal/testcert/testcert.go deleted file mode 100644 index d510e791d617..000000000000 --- a/contrib/go/_std_1.22/src/net/http/internal/testcert/testcert.go +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package testcert contains a test-only localhost certificate. -package testcert - -import "strings" - -// LocalhostCert is a PEM-encoded TLS cert with SAN IPs -// "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT. -// generated from src/crypto/tls: -// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h -var LocalhostCert = []byte(`-----BEGIN CERTIFICATE----- -MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS -MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw -MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r -bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U -aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P -YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk -POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu -h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE -AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv -bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI -5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv -cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2 -+tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B -grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK -5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/ -WkBKOclmOV2xlTVuPw== ------END CERTIFICATE-----`) - -// LocalhostKey is the private key for LocalhostCert. -var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi -4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS -gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW -URnoU85w+W6aLI2bNSq3AaE771p3VbkGolpEjo9h+i42TBHo1rhPNKPkGupR8/QX -AOLMpInRdeaHyDwb2a3DE5I3dG7VAVzrVfJ6W6Q84YoFX+rpEE2SVM17SAjy6xQy -VjKgLvK2mk0xbtfa+h0B6VK7bmODHZqeP18NVm6HsBcXn7iclLgAC3SfWU1jucZK -x1lqzw9tAgMBAAECggEABWzxS1Y2wckblnXY57Z+sl6YdmLV+gxj2r8Qib7g4ZIk -lIlWR1OJNfw7kU4eryib4fc6nOh6O4AWZyYqAK6tqNQSS/eVG0LQTLTTEldHyVJL -dvBe+MsUQOj4nTndZW+QvFzbcm2D8lY5n2nBSxU5ypVoKZ1EqQzytFcLZpTN7d89 -EPj0qDyrV4NZlWAwL1AygCwnlwhMQjXEalVF1ylXwU3QzyZ/6MgvF6d3SSUlh+sq -XefuyigXw484cQQgbzopv6niMOmGP3of+yV4JQqUSb3IDmmT68XjGd2Dkxl4iPki -6ZwXf3CCi+c+i/zVEcufgZ3SLf8D99kUGE7v7fZ6AQKBgQD1ZX3RAla9hIhxCf+O -3D+I1j2LMrdjAh0ZKKqwMR4JnHX3mjQI6LwqIctPWTU8wYFECSh9klEclSdCa64s -uI/GNpcqPXejd0cAAdqHEEeG5sHMDt0oFSurL4lyud0GtZvwlzLuwEweuDtvT9cJ -Wfvl86uyO36IW8JdvUprYDctrQKBgQDycZ697qutBieZlGkHpnYWUAeImVA878sJ -w44NuXHvMxBPz+lbJGAg8Cn8fcxNAPqHIraK+kx3po8cZGQywKHUWsxi23ozHoxo -+bGqeQb9U661TnfdDspIXia+xilZt3mm5BPzOUuRqlh4Y9SOBpSWRmEhyw76w4ZP -OPxjWYAgwQKBgA/FehSYxeJgRjSdo+MWnK66tjHgDJE8bYpUZsP0JC4R9DL5oiaA -brd2fI6Y+SbyeNBallObt8LSgzdtnEAbjIH8uDJqyOmknNePRvAvR6mP4xyuR+Bv -m+Lgp0DMWTw5J9CKpydZDItc49T/mJ5tPhdFVd+am0NAQnmr1MCZ6nHxAoGABS3Y -LkaC9FdFUUqSU8+Chkd/YbOkuyiENdkvl6t2e52jo5DVc1T7mLiIrRQi4SI8N9bN -/3oJWCT+uaSLX2ouCtNFunblzWHBrhxnZzTeqVq4SLc8aESAnbslKL4i8/+vYZlN -s8xtiNcSvL+lMsOBORSXzpj/4Ot8WwTkn1qyGgECgYBKNTypzAHeLE6yVadFp3nQ -Ckq9yzvP/ib05rvgbvrne00YeOxqJ9gtTrzgh7koqJyX1L4NwdkEza4ilDWpucn0 -xiUZS4SoaJq6ZvcBYS62Yr1t8n09iG47YL8ibgtmH3L+svaotvpVxVK+d7BLevA/ -ZboOWVe3icTy64BT3OQhmg== ------END RSA TESTING KEY-----`)) - -func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") } diff --git a/contrib/go/_std_1.22/src/net/netip/leaf_alts.go b/contrib/go/_std_1.22/src/net/netip/leaf_alts.go deleted file mode 100644 index d887bed62733..000000000000 --- a/contrib/go/_std_1.22/src/net/netip/leaf_alts.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Stuff that exists in std, but we can't use due to being a dependency -// of net, for go/build deps_test policy reasons. - -package netip - -func beUint64(b []byte) uint64 { - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 -} - -func bePutUint64(b []byte, v uint64) { - _ = b[7] // early bounds check to guarantee safety of writes below - b[0] = byte(v >> 56) - b[1] = byte(v >> 48) - b[2] = byte(v >> 40) - b[3] = byte(v >> 32) - b[4] = byte(v >> 24) - b[5] = byte(v >> 16) - b[6] = byte(v >> 8) - b[7] = byte(v) -} - -func bePutUint32(b []byte, v uint32) { - _ = b[3] // early bounds check to guarantee safety of writes below - b[0] = byte(v >> 24) - b[1] = byte(v >> 16) - b[2] = byte(v >> 8) - b[3] = byte(v) -} - -func leUint16(b []byte) uint16 { - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint16(b[0]) | uint16(b[1])<<8 -} - -func lePutUint16(b []byte, v uint16) { - _ = b[1] // early bounds check to guarantee safety of writes below - b[0] = byte(v) - b[1] = byte(v >> 8) -} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_darwin.go b/contrib/go/_std_1.22/src/net/tcpsockopt_darwin.go deleted file mode 100644 index 53c6756e33e0..000000000000 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_darwin.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "runtime" - "syscall" - "time" -) - -// syscall.TCP_KEEPINTVL is missing on some darwin architectures. -const sysTCP_KEEPINTVL = 0x101 - -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - // The kernel expects seconds so round to next highest second. - secs := int(roundDurationUp(d, time.Second)) - if err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPINTVL, secs); err != nil { - return wrapSyscallError("setsockopt", err) - } - err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, secs) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_dragonfly.go b/contrib/go/_std_1.22/src/net/tcpsockopt_dragonfly.go deleted file mode 100644 index b473c02b6867..000000000000 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_dragonfly.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "runtime" - "syscall" - "time" -) - -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - // The kernel expects milliseconds so round to next highest - // millisecond. - msecs := int(roundDurationUp(d, time.Millisecond)) - if err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, msecs); err != nil { - return wrapSyscallError("setsockopt", err) - } - err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, msecs) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_openbsd.go b/contrib/go/_std_1.22/src/net/tcpsockopt_openbsd.go deleted file mode 100644 index 10e1bef3e5aa..000000000000 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_openbsd.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "syscall" - "time" -) - -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - // OpenBSD has no user-settable per-socket TCP keepalive - // options. - return syscall.ENOPROTOOPT -} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_solaris.go b/contrib/go/_std_1.22/src/net/tcpsockopt_solaris.go deleted file mode 100644 index f15e589dc058..000000000000 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_solaris.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "runtime" - "syscall" - "time" -) - -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - // The kernel expects milliseconds so round to next highest - // millisecond. - msecs := int(roundDurationUp(d, time.Millisecond)) - - // Normally we'd do - // syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs) - // here, but we can't because Solaris does not have TCP_KEEPINTVL. - // Solaris has TCP_KEEPALIVE_ABORT_THRESHOLD, but it's not the same - // thing, it refers to the total time until aborting (not between - // probes), and it uses an exponential backoff algorithm instead of - // waiting the same time between probes. We can't hope for the best - // and do it anyway, like on Darwin, because Solaris might eventually - // allocate a constant with a different meaning for the value of - // TCP_KEEPINTVL on illumos. - - err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD, msecs) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_unix.go b/contrib/go/_std_1.22/src/net/tcpsockopt_unix.go deleted file mode 100644 index bdcdc4023983..000000000000 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_unix.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build aix || freebsd || linux || netbsd - -package net - -import ( - "runtime" - "syscall" - "time" -) - -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - // The kernel expects seconds so round to next highest second. - secs := int(roundDurationUp(d, time.Second)) - if err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs); err != nil { - return wrapSyscallError("setsockopt", err) - } - err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, secs) - runtime.KeepAlive(fd) - return wrapSyscallError("setsockopt", err) -} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_windows.go b/contrib/go/_std_1.22/src/net/tcpsockopt_windows.go deleted file mode 100644 index 4a0b09465eea..000000000000 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_windows.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "os" - "runtime" - "syscall" - "time" - "unsafe" -) - -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - // The kernel expects milliseconds so round to next highest - // millisecond. - msecs := uint32(roundDurationUp(d, time.Millisecond)) - ka := syscall.TCPKeepalive{ - OnOff: 1, - Time: msecs, - Interval: msecs, - } - ret := uint32(0) - size := uint32(unsafe.Sizeof(ka)) - err := fd.pfd.WSAIoctl(syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0) - runtime.KeepAlive(fd) - return os.NewSyscallError("wsaioctl", err) -} diff --git a/contrib/go/_std_1.22/src/os/endian_big.go b/contrib/go/_std_1.22/src/os/endian_big.go deleted file mode 100644 index 0375e533726e..000000000000 --- a/contrib/go/_std_1.22/src/os/endian_big.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// -//go:build ppc64 || s390x || mips || mips64 - -package os - -const isBigEndian = true diff --git a/contrib/go/_std_1.22/src/os/endian_little.go b/contrib/go/_std_1.22/src/os/endian_little.go deleted file mode 100644 index a7cf1cdda8e4..000000000000 --- a/contrib/go/_std_1.22/src/os/endian_little.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// -//go:build 386 || amd64 || arm || arm64 || loong64 || ppc64le || mips64le || mipsle || riscv64 || wasm - -package os - -const isBigEndian = false diff --git a/contrib/go/_std_1.22/src/os/error_posix.go b/contrib/go/_std_1.22/src/os/error_posix.go deleted file mode 100644 index b159c036c110..000000000000 --- a/contrib/go/_std_1.22/src/os/error_posix.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build unix || (js && wasm) || wasip1 || windows - -package os - -import "syscall" - -// wrapSyscallError takes an error and a syscall name. If the error is -// a syscall.Errno, it wraps it in an os.SyscallError using the syscall name. -func wrapSyscallError(name string, err error) error { - if _, ok := err.(syscall.Errno); ok { - err = NewSyscallError(name, err) - } - return err -} diff --git a/contrib/go/_std_1.22/src/os/exec.go b/contrib/go/_std_1.22/src/os/exec.go deleted file mode 100644 index ed5a75c4d13f..000000000000 --- a/contrib/go/_std_1.22/src/os/exec.go +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -import ( - "errors" - "internal/testlog" - "runtime" - "sync" - "sync/atomic" - "syscall" - "time" -) - -// ErrProcessDone indicates a Process has finished. -var ErrProcessDone = errors.New("os: process already finished") - -// Process stores the information about a process created by StartProcess. -type Process struct { - Pid int - handle uintptr // handle is accessed atomically on Windows - isdone atomic.Bool // process has been successfully waited on - sigMu sync.RWMutex // avoid race between wait and signal -} - -func newProcess(pid int, handle uintptr) *Process { - p := &Process{Pid: pid, handle: handle} - runtime.SetFinalizer(p, (*Process).Release) - return p -} - -func (p *Process) setDone() { - p.isdone.Store(true) -} - -func (p *Process) done() bool { - return p.isdone.Load() -} - -// ProcAttr holds the attributes that will be applied to a new process -// started by StartProcess. -type ProcAttr struct { - // If Dir is non-empty, the child changes into the directory before - // creating the process. - Dir string - // If Env is non-nil, it gives the environment variables for the - // new process in the form returned by Environ. - // If it is nil, the result of Environ will be used. - Env []string - // Files specifies the open files inherited by the new process. The - // first three entries correspond to standard input, standard output, and - // standard error. An implementation may support additional entries, - // depending on the underlying operating system. A nil entry corresponds - // to that file being closed when the process starts. - // On Unix systems, StartProcess will change these File values - // to blocking mode, which means that SetDeadline will stop working - // and calling Close will not interrupt a Read or Write. - Files []*File - - // Operating system-specific process creation attributes. - // Note that setting this field means that your program - // may not execute properly or even compile on some - // operating systems. - Sys *syscall.SysProcAttr -} - -// A Signal represents an operating system signal. -// The usual underlying implementation is operating system-dependent: -// on Unix it is syscall.Signal. -type Signal interface { - String() string - Signal() // to distinguish from other Stringers -} - -// Getpid returns the process id of the caller. -func Getpid() int { return syscall.Getpid() } - -// Getppid returns the process id of the caller's parent. -func Getppid() int { return syscall.Getppid() } - -// FindProcess looks for a running process by its pid. -// -// The Process it returns can be used to obtain information -// about the underlying operating system process. -// -// On Unix systems, FindProcess always succeeds and returns a Process -// for the given pid, regardless of whether the process exists. To test whether -// the process actually exists, see whether p.Signal(syscall.Signal(0)) reports -// an error. -func FindProcess(pid int) (*Process, error) { - return findProcess(pid) -} - -// StartProcess starts a new process with the program, arguments and attributes -// specified by name, argv and attr. The argv slice will become os.Args in the -// new process, so it normally starts with the program name. -// -// If the calling goroutine has locked the operating system thread -// with runtime.LockOSThread and modified any inheritable OS-level -// thread state (for example, Linux or Plan 9 name spaces), the new -// process will inherit the caller's thread state. -// -// StartProcess is a low-level interface. The os/exec package provides -// higher-level interfaces. -// -// If there is an error, it will be of type *PathError. -func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) { - testlog.Open(name) - return startProcess(name, argv, attr) -} - -// Release releases any resources associated with the Process p, -// rendering it unusable in the future. -// Release only needs to be called if Wait is not. -func (p *Process) Release() error { - return p.release() -} - -// Kill causes the Process to exit immediately. Kill does not wait until -// the Process has actually exited. This only kills the Process itself, -// not any other processes it may have started. -func (p *Process) Kill() error { - return p.kill() -} - -// Wait waits for the Process to exit, and then returns a -// ProcessState describing its status and an error, if any. -// Wait releases any resources associated with the Process. -// On most operating systems, the Process must be a child -// of the current process or an error will be returned. -func (p *Process) Wait() (*ProcessState, error) { - return p.wait() -} - -// Signal sends a signal to the Process. -// Sending Interrupt on Windows is not implemented. -func (p *Process) Signal(sig Signal) error { - return p.signal(sig) -} - -// UserTime returns the user CPU time of the exited process and its children. -func (p *ProcessState) UserTime() time.Duration { - return p.userTime() -} - -// SystemTime returns the system CPU time of the exited process and its children. -func (p *ProcessState) SystemTime() time.Duration { - return p.systemTime() -} - -// Exited reports whether the program has exited. -// On Unix systems this reports true if the program exited due to calling exit, -// but false if the program terminated due to a signal. -func (p *ProcessState) Exited() bool { - return p.exited() -} - -// Success reports whether the program exited successfully, -// such as with exit status 0 on Unix. -func (p *ProcessState) Success() bool { - return p.success() -} - -// Sys returns system-dependent exit information about -// the process. Convert it to the appropriate underlying -// type, such as syscall.WaitStatus on Unix, to access its contents. -func (p *ProcessState) Sys() any { - return p.sys() -} - -// SysUsage returns system-dependent resource usage information about -// the exited process. Convert it to the appropriate underlying -// type, such as *syscall.Rusage on Unix, to access its contents. -// (On Unix, *syscall.Rusage matches struct rusage as defined in the -// getrusage(2) manual page.) -func (p *ProcessState) SysUsage() any { - return p.sysUsage() -} diff --git a/contrib/go/_std_1.22/src/os/exec_unix.go b/contrib/go/_std_1.22/src/os/exec_unix.go deleted file mode 100644 index 36b320df1894..000000000000 --- a/contrib/go/_std_1.22/src/os/exec_unix.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build unix || (js && wasm) || wasip1 - -package os - -import ( - "errors" - "runtime" - "syscall" - "time" -) - -func (p *Process) wait() (ps *ProcessState, err error) { - if p.Pid == -1 { - return nil, syscall.EINVAL - } - - // If we can block until Wait4 will succeed immediately, do so. - ready, err := p.blockUntilWaitable() - if err != nil { - return nil, err - } - if ready { - // Mark the process done now, before the call to Wait4, - // so that Process.signal will not send a signal. - p.setDone() - // Acquire a write lock on sigMu to wait for any - // active call to the signal method to complete. - p.sigMu.Lock() - p.sigMu.Unlock() - } - - var ( - status syscall.WaitStatus - rusage syscall.Rusage - pid1 int - e error - ) - for { - pid1, e = syscall.Wait4(p.Pid, &status, 0, &rusage) - if e != syscall.EINTR { - break - } - } - if e != nil { - return nil, NewSyscallError("wait", e) - } - p.setDone() - ps = &ProcessState{ - pid: pid1, - status: status, - rusage: &rusage, - } - return ps, nil -} - -func (p *Process) signal(sig Signal) error { - if p.Pid == -1 { - return errors.New("os: process already released") - } - if p.Pid == 0 { - return errors.New("os: process not initialized") - } - p.sigMu.RLock() - defer p.sigMu.RUnlock() - if p.done() { - return ErrProcessDone - } - s, ok := sig.(syscall.Signal) - if !ok { - return errors.New("os: unsupported signal type") - } - if e := syscall.Kill(p.Pid, s); e != nil { - if e == syscall.ESRCH { - return ErrProcessDone - } - return e - } - return nil -} - -func (p *Process) release() error { - // NOOP for unix. - p.Pid = -1 - // no need for a finalizer anymore - runtime.SetFinalizer(p, nil) - return nil -} - -func findProcess(pid int) (p *Process, err error) { - // NOOP for unix. - return newProcess(pid, 0), nil -} - -func (p *ProcessState) userTime() time.Duration { - return time.Duration(p.rusage.Utime.Nano()) * time.Nanosecond -} - -func (p *ProcessState) systemTime() time.Duration { - return time.Duration(p.rusage.Stime.Nano()) * time.Nanosecond -} diff --git a/contrib/go/_std_1.22/src/os/path_windows.go b/contrib/go/_std_1.22/src/os/path_windows.go deleted file mode 100644 index 052202514825..000000000000 --- a/contrib/go/_std_1.22/src/os/path_windows.go +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package os - -const ( - PathSeparator = '\\' // OS-specific path separator - PathListSeparator = ';' // OS-specific path list separator -) - -// IsPathSeparator reports whether c is a directory separator character. -func IsPathSeparator(c uint8) bool { - // NOTE: Windows accepts / as path separator. - return c == '\\' || c == '/' -} - -// basename removes trailing slashes and the leading -// directory name and drive letter from path name. -func basename(name string) string { - // Remove drive letter - if len(name) == 2 && name[1] == ':' { - name = "." - } else if len(name) > 2 && name[1] == ':' { - name = name[2:] - } - i := len(name) - 1 - // Remove trailing slashes - for ; i > 0 && (name[i] == '/' || name[i] == '\\'); i-- { - name = name[:i] - } - // Remove leading directory name - for i--; i >= 0; i-- { - if name[i] == '/' || name[i] == '\\' { - name = name[i+1:] - break - } - } - return name -} - -func isAbs(path string) (b bool) { - v := volumeName(path) - if v == "" { - return false - } - path = path[len(v):] - if path == "" { - return false - } - return IsPathSeparator(path[0]) -} - -func volumeName(path string) (v string) { - if len(path) < 2 { - return "" - } - // with drive letter - c := path[0] - if path[1] == ':' && - ('0' <= c && c <= '9' || 'a' <= c && c <= 'z' || - 'A' <= c && c <= 'Z') { - return path[:2] - } - // is it UNC - if l := len(path); l >= 5 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) && - !IsPathSeparator(path[2]) && path[2] != '.' { - // first, leading `\\` and next shouldn't be `\`. its server name. - for n := 3; n < l-1; n++ { - // second, next '\' shouldn't be repeated. - if IsPathSeparator(path[n]) { - n++ - // third, following something characters. its share name. - if !IsPathSeparator(path[n]) { - if path[n] == '.' { - break - } - for ; n < l; n++ { - if IsPathSeparator(path[n]) { - break - } - } - return path[:n] - } - break - } - } - } - return "" -} - -func fromSlash(path string) string { - // Replace each '/' with '\\' if present - var pathbuf []byte - var lastSlash int - for i, b := range path { - if b == '/' { - if pathbuf == nil { - pathbuf = make([]byte, len(path)) - } - copy(pathbuf[lastSlash:], path[lastSlash:i]) - pathbuf[i] = '\\' - lastSlash = i + 1 - } - } - if pathbuf == nil { - return path - } - - copy(pathbuf[lastSlash:], path[lastSlash:]) - return string(pathbuf) -} - -func dirname(path string) string { - vol := volumeName(path) - i := len(path) - 1 - for i >= len(vol) && !IsPathSeparator(path[i]) { - i-- - } - dir := path[len(vol) : i+1] - last := len(dir) - 1 - if last > 0 && IsPathSeparator(dir[last]) { - dir = dir[:last] - } - if dir == "" { - dir = "." - } - return vol + dir -} - -// This is set via go:linkname on runtime.canUseLongPaths, and is true when the OS -// supports opting into proper long path handling without the need for fixups. -var canUseLongPaths bool - -// fixLongPath returns the extended-length (\\?\-prefixed) form of -// path when needed, in order to avoid the default 260 character file -// path limit imposed by Windows. If path is not easily converted to -// the extended-length form (for example, if path is a relative path -// or contains .. elements), or is short enough, fixLongPath returns -// path unmodified. -// -// See https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation -func fixLongPath(path string) string { - if canUseLongPaths { - return path - } - // Do nothing (and don't allocate) if the path is "short". - // Empirically (at least on the Windows Server 2013 builder), - // the kernel is arbitrarily okay with < 248 bytes. That - // matches what the docs above say: - // "When using an API to create a directory, the specified - // path cannot be so long that you cannot append an 8.3 file - // name (that is, the directory name cannot exceed MAX_PATH - // minus 12)." Since MAX_PATH is 260, 260 - 12 = 248. - // - // The MSDN docs appear to say that a normal path that is 248 bytes long - // will work; empirically the path must be less then 248 bytes long. - if len(path) < 248 { - // Don't fix. (This is how Go 1.7 and earlier worked, - // not automatically generating the \\?\ form) - return path - } - - // The extended form begins with \\?\, as in - // \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt. - // The extended form disables evaluation of . and .. path - // elements and disables the interpretation of / as equivalent - // to \. The conversion here rewrites / to \ and elides - // . elements as well as trailing or duplicate separators. For - // simplicity it avoids the conversion entirely for relative - // paths or paths containing .. elements. For now, - // \\server\share paths are not converted to - // \\?\UNC\server\share paths because the rules for doing so - // are less well-specified. - if len(path) >= 2 && path[:2] == `\\` { - // Don't canonicalize UNC paths. - return path - } - if !isAbs(path) { - // Relative path - return path - } - - const prefix = `\\?` - - pathbuf := make([]byte, len(prefix)+len(path)+len(`\`)) - copy(pathbuf, prefix) - n := len(path) - r, w := 0, len(prefix) - for r < n { - switch { - case IsPathSeparator(path[r]): - // empty block - r++ - case path[r] == '.' && (r+1 == n || IsPathSeparator(path[r+1])): - // /./ - r++ - case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || IsPathSeparator(path[r+2])): - // /../ is currently unhandled - return path - default: - pathbuf[w] = '\\' - w++ - for ; r < n && !IsPathSeparator(path[r]); r++ { - pathbuf[w] = path[r] - w++ - } - } - } - // A drive's root directory needs a trailing \ - if w == len(`\\?\c:`) { - pathbuf[w] = '\\' - w++ - } - return string(pathbuf[:w]) -} diff --git a/contrib/go/_std_1.22/src/runtime/coverage/apis.go b/contrib/go/_std_1.22/src/runtime/coverage/apis.go deleted file mode 100644 index 15ba04a86f9c..000000000000 --- a/contrib/go/_std_1.22/src/runtime/coverage/apis.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package coverage - -import ( - "fmt" - "internal/coverage" - "io" - "sync/atomic" - "unsafe" -) - -// WriteMetaDir writes a coverage meta-data file for the currently -// running program to the directory specified in 'dir'. An error will -// be returned if the operation can't be completed successfully (for -// example, if the currently running program was not built with -// "-cover", or if the directory does not exist). -func WriteMetaDir(dir string) error { - if !finalHashComputed { - return fmt.Errorf("error: no meta-data available (binary not built with -cover?)") - } - return emitMetaDataToDirectory(dir, getCovMetaList()) -} - -// WriteMeta writes the meta-data content (the payload that would -// normally be emitted to a meta-data file) for the currently running -// program to the writer 'w'. An error will be returned if the -// operation can't be completed successfully (for example, if the -// currently running program was not built with "-cover", or if a -// write fails). -func WriteMeta(w io.Writer) error { - if w == nil { - return fmt.Errorf("error: nil writer in WriteMeta") - } - if !finalHashComputed { - return fmt.Errorf("error: no meta-data available (binary not built with -cover?)") - } - ml := getCovMetaList() - return writeMetaData(w, ml, cmode, cgran, finalHash) -} - -// WriteCountersDir writes a coverage counter-data file for the -// currently running program to the directory specified in 'dir'. An -// error will be returned if the operation can't be completed -// successfully (for example, if the currently running program was not -// built with "-cover", or if the directory does not exist). The -// counter data written will be a snapshot taken at the point of the -// call. -func WriteCountersDir(dir string) error { - if cmode != coverage.CtrModeAtomic { - return fmt.Errorf("WriteCountersDir invoked for program built with -covermode=%s (please use -covermode=atomic)", cmode.String()) - } - return emitCounterDataToDirectory(dir) -} - -// WriteCounters writes coverage counter-data content for the -// currently running program to the writer 'w'. An error will be -// returned if the operation can't be completed successfully (for -// example, if the currently running program was not built with -// "-cover", or if a write fails). The counter data written will be a -// snapshot taken at the point of the invocation. -func WriteCounters(w io.Writer) error { - if w == nil { - return fmt.Errorf("error: nil writer in WriteCounters") - } - if cmode != coverage.CtrModeAtomic { - return fmt.Errorf("WriteCounters invoked for program built with -covermode=%s (please use -covermode=atomic)", cmode.String()) - } - // Ask the runtime for the list of coverage counter symbols. - cl := getCovCounterList() - if len(cl) == 0 { - return fmt.Errorf("program not built with -cover") - } - if !finalHashComputed { - return fmt.Errorf("meta-data not written yet, unable to write counter data") - } - - pm := getCovPkgMap() - s := &emitState{ - counterlist: cl, - pkgmap: pm, - } - return s.emitCounterDataToWriter(w) -} - -// ClearCounters clears/resets all coverage counter variables in the -// currently running program. It returns an error if the program in -// question was not built with the "-cover" flag. Clearing of coverage -// counters is also not supported for programs not using atomic -// counter mode (see more detailed comments below for the rationale -// here). -func ClearCounters() error { - cl := getCovCounterList() - if len(cl) == 0 { - return fmt.Errorf("program not built with -cover") - } - if cmode != coverage.CtrModeAtomic { - return fmt.Errorf("ClearCounters invoked for program built with -covermode=%s (please use -covermode=atomic)", cmode.String()) - } - - // Implementation note: this function would be faster and simpler - // if we could just zero out the entire counter array, but for the - // moment we go through and zero out just the slots in the array - // corresponding to the counter values. We do this to avoid the - // following bad scenario: suppose that a user builds their Go - // program with "-cover", and that program has a function (call it - // main.XYZ) that invokes ClearCounters: - // - // func XYZ() { - // ... do some stuff ... - // coverage.ClearCounters() - // if someCondition { <<--- HERE - // ... - // } - // } - // - // At the point where ClearCounters executes, main.XYZ has not yet - // finished running, thus as soon as the call returns the line - // marked "HERE" above will trigger the writing of a non-zero - // value into main.XYZ's counter slab. However since we've just - // finished clearing the entire counter segment, we will have lost - // the values in the prolog portion of main.XYZ's counter slab - // (nctrs, pkgid, funcid). This means that later on at the end of - // program execution as we walk through the entire counter array - // for the program looking for executed functions, we'll zoom past - // main.XYZ's prolog (which was zero'd) and hit the non-zero - // counter value corresponding to the "HERE" block, which will - // then be interpreted as the start of another live function. - // Things will go downhill from there. - // - // This same scenario is also a potential risk if the program is - // running on an architecture that permits reordering of - // writes/stores, since the inconsistency described above could - // arise here. Example scenario: - // - // func ABC() { - // ... // prolog - // if alwaysTrue() { - // XYZ() // counter update here - // } - // } - // - // In the instrumented version of ABC, the prolog of the function - // will contain a series of stores to the initial portion of the - // counter array to write number-of-counters, pkgid, funcid. Later - // in the function there is also a store to increment a counter - // for the block containing the call to XYZ(). If the CPU is - // allowed to reorder stores and decides to issue the XYZ store - // before the prolog stores, this could be observable as an - // inconsistency similar to the one above. Hence the requirement - // for atomic counter mode: according to package atomic docs, - // "...operations that happen in a specific order on one thread, - // will always be observed to happen in exactly that order by - // another thread". Thus we can be sure that there will be no - // inconsistency when reading the counter array from the thread - // running ClearCounters. - - for _, c := range cl { - sd := unsafe.Slice((*atomic.Uint32)(unsafe.Pointer(c.Counters)), int(c.Len)) - for i := 0; i < len(sd); i++ { - // Skip ahead until the next non-zero value. - sdi := sd[i].Load() - if sdi == 0 { - continue - } - // We found a function that was executed; clear its counters. - nCtrs := sdi - for j := 0; j < int(nCtrs); j++ { - sd[i+coverage.FirstCtrOffset+j].Store(0) - } - // Move to next function. - i += coverage.FirstCtrOffset + int(nCtrs) - 1 - } - } - return nil -} diff --git a/contrib/go/_std_1.22/src/runtime/coverage/dummy.s b/contrib/go/_std_1.22/src/runtime/coverage/dummy.s deleted file mode 100644 index 75928593a0b4..000000000000 --- a/contrib/go/_std_1.22/src/runtime/coverage/dummy.s +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The runtime package uses //go:linkname to push a few functions into this -// package but we still need a .s file so the Go tool does not pass -complete -// to 'go tool compile' so the latter does not complain about Go functions -// with no bodies. diff --git a/contrib/go/_std_1.22/src/runtime/coverage/emit.go b/contrib/go/_std_1.22/src/runtime/coverage/emit.go deleted file mode 100644 index 6fe04daea8d0..000000000000 --- a/contrib/go/_std_1.22/src/runtime/coverage/emit.go +++ /dev/null @@ -1,609 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package coverage - -import ( - "crypto/md5" - "fmt" - "internal/coverage" - "internal/coverage/encodecounter" - "internal/coverage/encodemeta" - "internal/coverage/rtcov" - "io" - "os" - "path/filepath" - "runtime" - "strconv" - "sync/atomic" - "time" - "unsafe" -) - -// This file contains functions that support the writing of data files -// emitted at the end of code coverage testing runs, from instrumented -// executables. - -// getCovMetaList returns a list of meta-data blobs registered -// for the currently executing instrumented program. It is defined in the -// runtime. -func getCovMetaList() []rtcov.CovMetaBlob - -// getCovCounterList returns a list of counter-data blobs registered -// for the currently executing instrumented program. It is defined in the -// runtime. -func getCovCounterList() []rtcov.CovCounterBlob - -// getCovPkgMap returns a map storing the remapped package IDs for -// hard-coded runtime packages (see internal/coverage/pkgid.go for -// more on why hard-coded package IDs are needed). This function -// is defined in the runtime. -func getCovPkgMap() map[int]int - -// emitState holds useful state information during the emit process. -// -// When an instrumented program finishes execution and starts the -// process of writing out coverage data, it's possible that an -// existing meta-data file already exists in the output directory. In -// this case openOutputFiles() below will leave the 'mf' field below -// as nil. If a new meta-data file is needed, field 'mfname' will be -// the final desired path of the meta file, 'mftmp' will be a -// temporary file, and 'mf' will be an open os.File pointer for -// 'mftmp'. The meta-data file payload will be written to 'mf', the -// temp file will be then closed and renamed (from 'mftmp' to -// 'mfname'), so as to insure that the meta-data file is created -// atomically; we want this so that things work smoothly in cases -// where there are several instances of a given instrumented program -// all terminating at the same time and trying to create meta-data -// files simultaneously. -// -// For counter data files there is less chance of a collision, hence -// the openOutputFiles() stores the counter data file in 'cfname' and -// then places the *io.File into 'cf'. -type emitState struct { - mfname string // path of final meta-data output file - mftmp string // path to meta-data temp file (if needed) - mf *os.File // open os.File for meta-data temp file - cfname string // path of final counter data file - cftmp string // path to counter data temp file - cf *os.File // open os.File for counter data file - outdir string // output directory - - // List of meta-data symbols obtained from the runtime - metalist []rtcov.CovMetaBlob - - // List of counter-data symbols obtained from the runtime - counterlist []rtcov.CovCounterBlob - - // Table to use for remapping hard-coded pkg ids. - pkgmap map[int]int - - // emit debug trace output - debug bool -} - -var ( - // finalHash is computed at init time from the list of meta-data - // symbols registered during init. It is used both for writing the - // meta-data file and counter-data files. - finalHash [16]byte - // Set to true when we've computed finalHash + finalMetaLen. - finalHashComputed bool - // Total meta-data length. - finalMetaLen uint64 - // Records whether we've already attempted to write meta-data. - metaDataEmitAttempted bool - // Counter mode for this instrumented program run. - cmode coverage.CounterMode - // Counter granularity for this instrumented program run. - cgran coverage.CounterGranularity - // Cached value of GOCOVERDIR environment variable. - goCoverDir string - // Copy of os.Args made at init time, converted into map format. - capturedOsArgs map[string]string - // Flag used in tests to signal that coverage data already written. - covProfileAlreadyEmitted bool -) - -// fileType is used to select between counter-data files and -// meta-data files. -type fileType int - -const ( - noFile = 1 << iota - metaDataFile - counterDataFile -) - -// emitMetaData emits the meta-data output file for this coverage run. -// This entry point is intended to be invoked by the compiler from -// an instrumented program's main package init func. -func emitMetaData() { - if covProfileAlreadyEmitted { - return - } - ml, err := prepareForMetaEmit() - if err != nil { - fmt.Fprintf(os.Stderr, "error: coverage meta-data prep failed: %v\n", err) - if os.Getenv("GOCOVERDEBUG") != "" { - panic("meta-data write failure") - } - } - if len(ml) == 0 { - fmt.Fprintf(os.Stderr, "program not built with -cover\n") - return - } - - goCoverDir = os.Getenv("GOCOVERDIR") - if goCoverDir == "" { - fmt.Fprintf(os.Stderr, "warning: GOCOVERDIR not set, no coverage data emitted\n") - return - } - - if err := emitMetaDataToDirectory(goCoverDir, ml); err != nil { - fmt.Fprintf(os.Stderr, "error: coverage meta-data emit failed: %v\n", err) - if os.Getenv("GOCOVERDEBUG") != "" { - panic("meta-data write failure") - } - } -} - -func modeClash(m coverage.CounterMode) bool { - if m == coverage.CtrModeRegOnly || m == coverage.CtrModeTestMain { - return false - } - if cmode == coverage.CtrModeInvalid { - cmode = m - return false - } - return cmode != m -} - -func granClash(g coverage.CounterGranularity) bool { - if cgran == coverage.CtrGranularityInvalid { - cgran = g - return false - } - return cgran != g -} - -// prepareForMetaEmit performs preparatory steps needed prior to -// emitting a meta-data file, notably computing a final hash of -// all meta-data blobs and capturing os args. -func prepareForMetaEmit() ([]rtcov.CovMetaBlob, error) { - // Ask the runtime for the list of coverage meta-data symbols. - ml := getCovMetaList() - - // In the normal case (go build -o prog.exe ... ; ./prog.exe) - // len(ml) will always be non-zero, but we check here since at - // some point this function will be reachable via user-callable - // APIs (for example, to write out coverage data from a server - // program that doesn't ever call os.Exit). - if len(ml) == 0 { - return nil, nil - } - - s := &emitState{ - metalist: ml, - debug: os.Getenv("GOCOVERDEBUG") != "", - } - - // Capture os.Args() now so as to avoid issues if args - // are rewritten during program execution. - capturedOsArgs = captureOsArgs() - - if s.debug { - fmt.Fprintf(os.Stderr, "=+= GOCOVERDIR is %s\n", os.Getenv("GOCOVERDIR")) - fmt.Fprintf(os.Stderr, "=+= contents of covmetalist:\n") - for k, b := range ml { - fmt.Fprintf(os.Stderr, "=+= slot: %d path: %s ", k, b.PkgPath) - if b.PkgID != -1 { - fmt.Fprintf(os.Stderr, " hcid: %d", b.PkgID) - } - fmt.Fprintf(os.Stderr, "\n") - } - pm := getCovPkgMap() - fmt.Fprintf(os.Stderr, "=+= remap table:\n") - for from, to := range pm { - fmt.Fprintf(os.Stderr, "=+= from %d to %d\n", - uint32(from), uint32(to)) - } - } - - h := md5.New() - tlen := uint64(unsafe.Sizeof(coverage.MetaFileHeader{})) - for _, entry := range ml { - if _, err := h.Write(entry.Hash[:]); err != nil { - return nil, err - } - tlen += uint64(entry.Len) - ecm := coverage.CounterMode(entry.CounterMode) - if modeClash(ecm) { - return nil, fmt.Errorf("coverage counter mode clash: package %s uses mode=%d, but package %s uses mode=%s\n", ml[0].PkgPath, cmode, entry.PkgPath, ecm) - } - ecg := coverage.CounterGranularity(entry.CounterGranularity) - if granClash(ecg) { - return nil, fmt.Errorf("coverage counter granularity clash: package %s uses gran=%d, but package %s uses gran=%s\n", ml[0].PkgPath, cgran, entry.PkgPath, ecg) - } - } - - // Hash mode and granularity as well. - h.Write([]byte(cmode.String())) - h.Write([]byte(cgran.String())) - - // Compute final digest. - fh := h.Sum(nil) - copy(finalHash[:], fh) - finalHashComputed = true - finalMetaLen = tlen - - return ml, nil -} - -// emitMetaDataToDirectory emits the meta-data output file to the specified -// directory, returning an error if something went wrong. -func emitMetaDataToDirectory(outdir string, ml []rtcov.CovMetaBlob) error { - ml, err := prepareForMetaEmit() - if err != nil { - return err - } - if len(ml) == 0 { - return nil - } - - metaDataEmitAttempted = true - - s := &emitState{ - metalist: ml, - debug: os.Getenv("GOCOVERDEBUG") != "", - outdir: outdir, - } - - // Open output files. - if err := s.openOutputFiles(finalHash, finalMetaLen, metaDataFile); err != nil { - return err - } - - // Emit meta-data file only if needed (may already be present). - if s.needMetaDataFile() { - if err := s.emitMetaDataFile(finalHash, finalMetaLen); err != nil { - return err - } - } - return nil -} - -// emitCounterData emits the counter data output file for this coverage run. -// This entry point is intended to be invoked by the runtime when an -// instrumented program is terminating or calling os.Exit(). -func emitCounterData() { - if goCoverDir == "" || !finalHashComputed || covProfileAlreadyEmitted { - return - } - if err := emitCounterDataToDirectory(goCoverDir); err != nil { - fmt.Fprintf(os.Stderr, "error: coverage counter data emit failed: %v\n", err) - if os.Getenv("GOCOVERDEBUG") != "" { - panic("counter-data write failure") - } - } -} - -// emitCounterDataToDirectory emits the counter-data output file for this coverage run. -func emitCounterDataToDirectory(outdir string) error { - // Ask the runtime for the list of coverage counter symbols. - cl := getCovCounterList() - if len(cl) == 0 { - // no work to do here. - return nil - } - - if !finalHashComputed { - return fmt.Errorf("error: meta-data not available (binary not built with -cover?)") - } - - // Ask the runtime for the list of coverage counter symbols. - pm := getCovPkgMap() - s := &emitState{ - counterlist: cl, - pkgmap: pm, - outdir: outdir, - debug: os.Getenv("GOCOVERDEBUG") != "", - } - - // Open output file. - if err := s.openOutputFiles(finalHash, finalMetaLen, counterDataFile); err != nil { - return err - } - if s.cf == nil { - return fmt.Errorf("counter data output file open failed (no additional info") - } - - // Emit counter data file. - if err := s.emitCounterDataFile(finalHash, s.cf); err != nil { - return err - } - if err := s.cf.Close(); err != nil { - return fmt.Errorf("closing counter data file: %v", err) - } - - // Counter file has now been closed. Rename the temp to the - // final desired path. - if err := os.Rename(s.cftmp, s.cfname); err != nil { - return fmt.Errorf("writing %s: rename from %s failed: %v\n", s.cfname, s.cftmp, err) - } - - return nil -} - -// emitCounterDataToWriter emits counter data for this coverage run to an io.Writer. -func (s *emitState) emitCounterDataToWriter(w io.Writer) error { - if err := s.emitCounterDataFile(finalHash, w); err != nil { - return err - } - return nil -} - -// openMetaFile determines whether we need to emit a meta-data output -// file, or whether we can reuse the existing file in the coverage out -// dir. It updates mfname/mftmp/mf fields in 's', returning an error -// if something went wrong. See the comment on the emitState type -// definition above for more on how file opening is managed. -func (s *emitState) openMetaFile(metaHash [16]byte, metaLen uint64) error { - - // Open meta-outfile for reading to see if it exists. - fn := fmt.Sprintf("%s.%x", coverage.MetaFilePref, metaHash) - s.mfname = filepath.Join(s.outdir, fn) - fi, err := os.Stat(s.mfname) - if err != nil || fi.Size() != int64(metaLen) { - // We need a new meta-file. - tname := "tmp." + fn + strconv.FormatInt(time.Now().UnixNano(), 10) - s.mftmp = filepath.Join(s.outdir, tname) - s.mf, err = os.Create(s.mftmp) - if err != nil { - return fmt.Errorf("creating meta-data file %s: %v", s.mftmp, err) - } - } - return nil -} - -// openCounterFile opens an output file for the counter data portion -// of a test coverage run. If updates the 'cfname' and 'cf' fields in -// 's', returning an error if something went wrong. -func (s *emitState) openCounterFile(metaHash [16]byte) error { - processID := os.Getpid() - fn := fmt.Sprintf(coverage.CounterFileTempl, coverage.CounterFilePref, metaHash, processID, time.Now().UnixNano()) - s.cfname = filepath.Join(s.outdir, fn) - s.cftmp = filepath.Join(s.outdir, "tmp."+fn) - var err error - s.cf, err = os.Create(s.cftmp) - if err != nil { - return fmt.Errorf("creating counter data file %s: %v", s.cftmp, err) - } - return nil -} - -// openOutputFiles opens output files in preparation for emitting -// coverage data. In the case of the meta-data file, openOutputFiles -// may determine that we can reuse an existing meta-data file in the -// outdir, in which case it will leave the 'mf' field in the state -// struct as nil. If a new meta-file is needed, the field 'mfname' -// will be the final desired path of the meta file, 'mftmp' will be a -// temporary file, and 'mf' will be an open os.File pointer for -// 'mftmp'. The idea is that the client/caller will write content into -// 'mf', close it, and then rename 'mftmp' to 'mfname'. This function -// also opens the counter data output file, setting 'cf' and 'cfname' -// in the state struct. -func (s *emitState) openOutputFiles(metaHash [16]byte, metaLen uint64, which fileType) error { - fi, err := os.Stat(s.outdir) - if err != nil { - return fmt.Errorf("output directory %q inaccessible (err: %v); no coverage data written", s.outdir, err) - } - if !fi.IsDir() { - return fmt.Errorf("output directory %q not a directory; no coverage data written", s.outdir) - } - - if (which & metaDataFile) != 0 { - if err := s.openMetaFile(metaHash, metaLen); err != nil { - return err - } - } - if (which & counterDataFile) != 0 { - if err := s.openCounterFile(metaHash); err != nil { - return err - } - } - return nil -} - -// emitMetaDataFile emits coverage meta-data to a previously opened -// temporary file (s.mftmp), then renames the generated file to the -// final path (s.mfname). -func (s *emitState) emitMetaDataFile(finalHash [16]byte, tlen uint64) error { - if err := writeMetaData(s.mf, s.metalist, cmode, cgran, finalHash); err != nil { - return fmt.Errorf("writing %s: %v\n", s.mftmp, err) - } - if err := s.mf.Close(); err != nil { - return fmt.Errorf("closing meta data temp file: %v", err) - } - - // Temp file has now been flushed and closed. Rename the temp to the - // final desired path. - if err := os.Rename(s.mftmp, s.mfname); err != nil { - return fmt.Errorf("writing %s: rename from %s failed: %v\n", s.mfname, s.mftmp, err) - } - - return nil -} - -// needMetaDataFile returns TRUE if we need to emit a meta-data file -// for this program run. It should be used only after -// openOutputFiles() has been invoked. -func (s *emitState) needMetaDataFile() bool { - return s.mf != nil -} - -func writeMetaData(w io.Writer, metalist []rtcov.CovMetaBlob, cmode coverage.CounterMode, gran coverage.CounterGranularity, finalHash [16]byte) error { - mfw := encodemeta.NewCoverageMetaFileWriter("", w) - - var blobs [][]byte - for _, e := range metalist { - sd := unsafe.Slice(e.P, int(e.Len)) - blobs = append(blobs, sd) - } - return mfw.Write(finalHash, blobs, cmode, gran) -} - -func (s *emitState) VisitFuncs(f encodecounter.CounterVisitorFn) error { - var tcounters []uint32 - - rdCounters := func(actrs []atomic.Uint32, ctrs []uint32) []uint32 { - ctrs = ctrs[:0] - for i := range actrs { - ctrs = append(ctrs, actrs[i].Load()) - } - return ctrs - } - - dpkg := uint32(0) - for _, c := range s.counterlist { - sd := unsafe.Slice((*atomic.Uint32)(unsafe.Pointer(c.Counters)), int(c.Len)) - for i := 0; i < len(sd); i++ { - // Skip ahead until the next non-zero value. - sdi := sd[i].Load() - if sdi == 0 { - continue - } - - // We found a function that was executed. - nCtrs := sd[i+coverage.NumCtrsOffset].Load() - pkgId := sd[i+coverage.PkgIdOffset].Load() - funcId := sd[i+coverage.FuncIdOffset].Load() - cst := i + coverage.FirstCtrOffset - counters := sd[cst : cst+int(nCtrs)] - - // Check to make sure that we have at least one live - // counter. See the implementation note in ClearCoverageCounters - // for a description of why this is needed. - isLive := false - for i := 0; i < len(counters); i++ { - if counters[i].Load() != 0 { - isLive = true - break - } - } - if !isLive { - // Skip this function. - i += coverage.FirstCtrOffset + int(nCtrs) - 1 - continue - } - - if s.debug { - if pkgId != dpkg { - dpkg = pkgId - fmt.Fprintf(os.Stderr, "\n=+= %d: pk=%d visit live fcn", - i, pkgId) - } - fmt.Fprintf(os.Stderr, " {i=%d F%d NC%d}", i, funcId, nCtrs) - } - - // Vet and/or fix up package ID. A package ID of zero - // indicates that there is some new package X that is a - // runtime dependency, and this package has code that - // executes before its corresponding init package runs. - // This is a fatal error that we should only see during - // Go development (e.g. tip). - ipk := int32(pkgId) - if ipk == 0 { - fmt.Fprintf(os.Stderr, "\n") - reportErrorInHardcodedList(int32(i), ipk, funcId, nCtrs) - } else if ipk < 0 { - if newId, ok := s.pkgmap[int(ipk)]; ok { - pkgId = uint32(newId) - } else { - fmt.Fprintf(os.Stderr, "\n") - reportErrorInHardcodedList(int32(i), ipk, funcId, nCtrs) - } - } else { - // The package ID value stored in the counter array - // has 1 added to it (so as to preclude the - // possibility of a zero value ; see - // runtime.addCovMeta), so subtract off 1 here to form - // the real package ID. - pkgId-- - } - - tcounters = rdCounters(counters, tcounters) - if err := f(pkgId, funcId, tcounters); err != nil { - return err - } - - // Skip over this function. - i += coverage.FirstCtrOffset + int(nCtrs) - 1 - } - if s.debug { - fmt.Fprintf(os.Stderr, "\n") - } - } - return nil -} - -// captureOsArgs converts os.Args() into the format we use to store -// this info in the counter data file (counter data file "args" -// section is a generic key-value collection). See the 'args' section -// in internal/coverage/defs.go for more info. The args map -// is also used to capture GOOS + GOARCH values as well. -func captureOsArgs() map[string]string { - m := make(map[string]string) - m["argc"] = strconv.Itoa(len(os.Args)) - for k, a := range os.Args { - m[fmt.Sprintf("argv%d", k)] = a - } - m["GOOS"] = runtime.GOOS - m["GOARCH"] = runtime.GOARCH - return m -} - -// emitCounterDataFile emits the counter data portion of a -// coverage output file (to the file 's.cf'). -func (s *emitState) emitCounterDataFile(finalHash [16]byte, w io.Writer) error { - cfw := encodecounter.NewCoverageDataWriter(w, coverage.CtrULeb128) - if err := cfw.Write(finalHash, capturedOsArgs, s); err != nil { - return err - } - return nil -} - -// markProfileEmitted signals the runtime/coverage machinery that -// coverage data output files have already been written out, and there -// is no need to take any additional action at exit time. This -// function is called (via linknamed reference) from the -// coverage-related boilerplate code in _testmain.go emitted for go -// unit tests. -func markProfileEmitted(val bool) { - covProfileAlreadyEmitted = val -} - -func reportErrorInHardcodedList(slot, pkgID int32, fnID, nCtrs uint32) { - metaList := getCovMetaList() - pkgMap := getCovPkgMap() - - println("internal error in coverage meta-data tracking:") - println("encountered bad pkgID:", pkgID, " at slot:", slot, - " fnID:", fnID, " numCtrs:", nCtrs) - println("list of hard-coded runtime package IDs needs revising.") - println("[see the comment on the 'rtPkgs' var in ") - println(" /src/internal/coverage/pkid.go]") - println("registered list:") - for k, b := range metaList { - print("slot: ", k, " path='", b.PkgPath, "' ") - if b.PkgID != -1 { - print(" hard-coded id: ", b.PkgID) - } - println("") - } - println("remap table:") - for from, to := range pkgMap { - println("from ", from, " to ", to) - } -} diff --git a/contrib/go/_std_1.22/src/runtime/coverage/hooks.go b/contrib/go/_std_1.22/src/runtime/coverage/hooks.go deleted file mode 100644 index a9fbf9d7dd18..000000000000 --- a/contrib/go/_std_1.22/src/runtime/coverage/hooks.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package coverage - -import _ "unsafe" - -// initHook is invoked from the main package "init" routine in -// programs built with "-cover". This function is intended to be -// called only by the compiler. -// -// If 'istest' is false, it indicates we're building a regular program -// ("go build -cover ..."), in which case we immediately try to write -// out the meta-data file, and register emitCounterData as an exit -// hook. -// -// If 'istest' is true (indicating that the program in question is a -// Go test binary), then we tentatively queue up both emitMetaData and -// emitCounterData as exit hooks. In the normal case (e.g. regular "go -// test -cover" run) the testmain.go boilerplate will run at the end -// of the test, write out the coverage percentage, and then invoke -// markProfileEmitted() to indicate that no more work needs to be -// done. If however that call is never made, this is a sign that the -// test binary is being used as a replacement binary for the tool -// being tested, hence we do want to run exit hooks when the program -// terminates. -func initHook(istest bool) { - // Note: hooks are run in reverse registration order, so - // register the counter data hook before the meta-data hook - // (in the case where two hooks are needed). - runOnNonZeroExit := true - runtime_addExitHook(emitCounterData, runOnNonZeroExit) - if istest { - runtime_addExitHook(emitMetaData, runOnNonZeroExit) - } else { - emitMetaData() - } -} - -//go:linkname runtime_addExitHook runtime.addExitHook -func runtime_addExitHook(f func(), runOnNonZeroExit bool) diff --git a/contrib/go/_std_1.22/src/runtime/coverage/testsupport.go b/contrib/go/_std_1.22/src/runtime/coverage/testsupport.go deleted file mode 100644 index f169580618a5..000000000000 --- a/contrib/go/_std_1.22/src/runtime/coverage/testsupport.go +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package coverage - -import ( - "encoding/json" - "fmt" - "internal/coverage" - "internal/coverage/calloc" - "internal/coverage/cformat" - "internal/coverage/cmerge" - "internal/coverage/decodecounter" - "internal/coverage/decodemeta" - "internal/coverage/pods" - "io" - "os" - "path/filepath" - "runtime/internal/atomic" - "strings" - "unsafe" -) - -// processCoverTestDir is called (via a linknamed reference) from -// testmain code when "go test -cover" is in effect. It is not -// intended to be used other than internally by the Go command's -// generated code. -func processCoverTestDir(dir string, cfile string, cm string, cpkg string) error { - return processCoverTestDirInternal(dir, cfile, cm, cpkg, os.Stdout) -} - -// processCoverTestDirInternal is an io.Writer version of processCoverTestDir, -// exposed for unit testing. -func processCoverTestDirInternal(dir string, cfile string, cm string, cpkg string, w io.Writer) error { - cmode := coverage.ParseCounterMode(cm) - if cmode == coverage.CtrModeInvalid { - return fmt.Errorf("invalid counter mode %q", cm) - } - - // Emit meta-data and counter data. - ml := getCovMetaList() - if len(ml) == 0 { - // This corresponds to the case where we have a package that - // contains test code but no functions (which is fine). In this - // case there is no need to emit anything. - } else { - if err := emitMetaDataToDirectory(dir, ml); err != nil { - return err - } - if err := emitCounterDataToDirectory(dir); err != nil { - return err - } - } - - // Collect pods from test run. For the majority of cases we would - // expect to see a single pod here, but allow for multiple pods in - // case the test harness is doing extra work to collect data files - // from builds that it kicks off as part of the testing. - podlist, err := pods.CollectPods([]string{dir}, false) - if err != nil { - return fmt.Errorf("reading from %s: %v", dir, err) - } - - // Open text output file if appropriate. - var tf *os.File - var tfClosed bool - if cfile != "" { - var err error - tf, err = os.Create(cfile) - if err != nil { - return fmt.Errorf("internal error: opening coverage data output file %q: %v", cfile, err) - } - defer func() { - if !tfClosed { - tfClosed = true - tf.Close() - } - }() - } - - // Read/process the pods. - ts := &tstate{ - cm: &cmerge.Merger{}, - cf: cformat.NewFormatter(cmode), - cmode: cmode, - } - // Generate the expected hash string based on the final meta-data - // hash for this test, then look only for pods that refer to that - // hash (just in case there are multiple instrumented executables - // in play). See issue #57924 for more on this. - hashstring := fmt.Sprintf("%x", finalHash) - importpaths := make(map[string]struct{}) - for _, p := range podlist { - if !strings.Contains(p.MetaFile, hashstring) { - continue - } - if err := ts.processPod(p, importpaths); err != nil { - return err - } - } - - metafilespath := filepath.Join(dir, coverage.MetaFilesFileName) - if _, err := os.Stat(metafilespath); err == nil { - if err := ts.readAuxMetaFiles(metafilespath, importpaths); err != nil { - return err - } - } - - // Emit percent. - if err := ts.cf.EmitPercent(w, cpkg, true, true); err != nil { - return err - } - - // Emit text output. - if tf != nil { - if err := ts.cf.EmitTextual(tf); err != nil { - return err - } - tfClosed = true - if err := tf.Close(); err != nil { - return fmt.Errorf("closing %s: %v", cfile, err) - } - } - - return nil -} - -type tstate struct { - calloc.BatchCounterAlloc - cm *cmerge.Merger - cf *cformat.Formatter - cmode coverage.CounterMode -} - -// processPod reads coverage counter data for a specific pod. -func (ts *tstate) processPod(p pods.Pod, importpaths map[string]struct{}) error { - // Open meta-data file - f, err := os.Open(p.MetaFile) - if err != nil { - return fmt.Errorf("unable to open meta-data file %s: %v", p.MetaFile, err) - } - defer func() { - f.Close() - }() - var mfr *decodemeta.CoverageMetaFileReader - mfr, err = decodemeta.NewCoverageMetaFileReader(f, nil) - if err != nil { - return fmt.Errorf("error reading meta-data file %s: %v", p.MetaFile, err) - } - newmode := mfr.CounterMode() - if newmode != ts.cmode { - return fmt.Errorf("internal error: counter mode clash: %q from test harness, %q from data file %s", ts.cmode.String(), newmode.String(), p.MetaFile) - } - newgran := mfr.CounterGranularity() - if err := ts.cm.SetModeAndGranularity(p.MetaFile, cmode, newgran); err != nil { - return err - } - - // A map to store counter data, indexed by pkgid/fnid tuple. - pmm := make(map[pkfunc][]uint32) - - // Helper to read a single counter data file. - readcdf := func(cdf string) error { - cf, err := os.Open(cdf) - if err != nil { - return fmt.Errorf("opening counter data file %s: %s", cdf, err) - } - defer cf.Close() - var cdr *decodecounter.CounterDataReader - cdr, err = decodecounter.NewCounterDataReader(cdf, cf) - if err != nil { - return fmt.Errorf("reading counter data file %s: %s", cdf, err) - } - var data decodecounter.FuncPayload - for { - ok, err := cdr.NextFunc(&data) - if err != nil { - return fmt.Errorf("reading counter data file %s: %v", cdf, err) - } - if !ok { - break - } - - // NB: sanity check on pkg and func IDs? - key := pkfunc{pk: data.PkgIdx, fcn: data.FuncIdx} - if prev, found := pmm[key]; found { - // Note: no overflow reporting here. - if err, _ := ts.cm.MergeCounters(data.Counters, prev); err != nil { - return fmt.Errorf("processing counter data file %s: %v", cdf, err) - } - } - c := ts.AllocateCounters(len(data.Counters)) - copy(c, data.Counters) - pmm[key] = c - } - return nil - } - - // Read counter data files. - for _, cdf := range p.CounterDataFiles { - if err := readcdf(cdf); err != nil { - return err - } - } - - // Visit meta-data file. - np := uint32(mfr.NumPackages()) - payload := []byte{} - for pkIdx := uint32(0); pkIdx < np; pkIdx++ { - var pd *decodemeta.CoverageMetaDataDecoder - pd, payload, err = mfr.GetPackageDecoder(pkIdx, payload) - if err != nil { - return fmt.Errorf("reading pkg %d from meta-file %s: %s", pkIdx, p.MetaFile, err) - } - ts.cf.SetPackage(pd.PackagePath()) - importpaths[pd.PackagePath()] = struct{}{} - var fd coverage.FuncDesc - nf := pd.NumFuncs() - for fnIdx := uint32(0); fnIdx < nf; fnIdx++ { - if err := pd.ReadFunc(fnIdx, &fd); err != nil { - return fmt.Errorf("reading meta-data file %s: %v", - p.MetaFile, err) - } - key := pkfunc{pk: pkIdx, fcn: fnIdx} - counters, haveCounters := pmm[key] - for i := 0; i < len(fd.Units); i++ { - u := fd.Units[i] - // Skip units with non-zero parent (no way to represent - // these in the existing format). - if u.Parent != 0 { - continue - } - count := uint32(0) - if haveCounters { - count = counters[i] - } - ts.cf.AddUnit(fd.Srcfile, fd.Funcname, fd.Lit, u, count) - } - } - } - return nil -} - -type pkfunc struct { - pk, fcn uint32 -} - -func (ts *tstate) readAuxMetaFiles(metafiles string, importpaths map[string]struct{}) error { - // Unmarshall the information on available aux metafiles into - // a MetaFileCollection struct. - var mfc coverage.MetaFileCollection - data, err := os.ReadFile(metafiles) - if err != nil { - return fmt.Errorf("error reading auxmetafiles file %q: %v", metafiles, err) - } - if err := json.Unmarshal(data, &mfc); err != nil { - return fmt.Errorf("error reading auxmetafiles file %q: %v", metafiles, err) - } - - // Walk through each available aux meta-file. If we've already - // seen the package path in question during the walk of the - // "regular" meta-data file, then we can skip the package, - // otherwise construct a dummy pod with the single meta-data file - // (no counters) and invoke processPod on it. - for i := range mfc.ImportPaths { - p := mfc.ImportPaths[i] - if _, ok := importpaths[p]; ok { - continue - } - var pod pods.Pod - pod.MetaFile = mfc.MetaFileFragments[i] - if err := ts.processPod(pod, importpaths); err != nil { - return err - } - } - return nil -} - -// snapshot returns a snapshot of coverage percentage at a moment of -// time within a running test, so as to support the testing.Coverage() -// function. This version doesn't examine coverage meta-data, so the -// result it returns will be less accurate (more "slop") due to the -// fact that we don't look at the meta data to see how many statements -// are associated with each counter. -func snapshot() float64 { - cl := getCovCounterList() - if len(cl) == 0 { - // no work to do here. - return 0.0 - } - - tot := uint64(0) - totExec := uint64(0) - for _, c := range cl { - sd := unsafe.Slice((*atomic.Uint32)(unsafe.Pointer(c.Counters)), c.Len) - tot += uint64(len(sd)) - for i := 0; i < len(sd); i++ { - // Skip ahead until the next non-zero value. - if sd[i].Load() == 0 { - continue - } - // We found a function that was executed. - nCtrs := sd[i+coverage.NumCtrsOffset].Load() - cst := i + coverage.FirstCtrOffset - - if cst+int(nCtrs) > len(sd) { - break - } - counters := sd[cst : cst+int(nCtrs)] - for i := range counters { - if counters[i].Load() != 0 { - totExec++ - } - } - i += coverage.FirstCtrOffset + int(nCtrs) - 1 - } - } - if tot == 0 { - return 0.0 - } - return float64(totExec) / float64(tot) -} diff --git a/contrib/go/_std_1.22/src/runtime/coverage/ya.make b/contrib/go/_std_1.22/src/runtime/coverage/ya.make deleted file mode 100644 index f62e9cabccdc..000000000000 --- a/contrib/go/_std_1.22/src/runtime/coverage/ya.make +++ /dev/null @@ -1,13 +0,0 @@ -SUBSCRIBER(g:contrib) - -GO_LIBRARY() -IF (TRUE) - SRCS( - apis.go - dummy.s - emit.go - hooks.go - testsupport.go - ) -ENDIF() -END() diff --git a/contrib/go/_std_1.22/src/runtime/covermeta.go b/contrib/go/_std_1.22/src/runtime/covermeta.go deleted file mode 100644 index 54ef42ae1ff4..000000000000 --- a/contrib/go/_std_1.22/src/runtime/covermeta.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "internal/coverage/rtcov" - "unsafe" -) - -// covMeta is the top-level container for bits of state related to -// code coverage meta-data in the runtime. -var covMeta struct { - // metaList contains the list of currently registered meta-data - // blobs for the running program. - metaList []rtcov.CovMetaBlob - - // pkgMap records mappings from hard-coded package IDs to - // slots in the covMetaList above. - pkgMap map[int]int - - // Set to true if we discover a package mapping glitch. - hardCodedListNeedsUpdating bool -} - -// addCovMeta is invoked during package "init" functions by the -// compiler when compiling for coverage instrumentation; here 'p' is a -// meta-data blob of length 'dlen' for the package in question, 'hash' -// is a compiler-computed md5.sum for the blob, 'pkpath' is the -// package path, 'pkid' is the hard-coded ID that the compiler is -// using for the package (or -1 if the compiler doesn't think a -// hard-coded ID is needed), and 'cmode'/'cgran' are the coverage -// counter mode and granularity requested by the user. Return value is -// the ID for the package for use by the package code itself. -func addCovMeta(p unsafe.Pointer, dlen uint32, hash [16]byte, pkpath string, pkid int, cmode uint8, cgran uint8) uint32 { - slot := len(covMeta.metaList) - covMeta.metaList = append(covMeta.metaList, - rtcov.CovMetaBlob{ - P: (*byte)(p), - Len: dlen, - Hash: hash, - PkgPath: pkpath, - PkgID: pkid, - CounterMode: cmode, - CounterGranularity: cgran, - }) - if pkid != -1 { - if covMeta.pkgMap == nil { - covMeta.pkgMap = make(map[int]int) - } - if _, ok := covMeta.pkgMap[pkid]; ok { - throw("runtime.addCovMeta: coverage package map collision") - } - // Record the real slot (position on meta-list) for this - // package; we'll use the map to fix things up later on. - covMeta.pkgMap[pkid] = slot - } - - // ID zero is reserved as invalid. - return uint32(slot + 1) -} - -//go:linkname runtime_coverage_getCovMetaList runtime/coverage.getCovMetaList -func runtime_coverage_getCovMetaList() []rtcov.CovMetaBlob { - return covMeta.metaList -} - -//go:linkname runtime_coverage_getCovPkgMap runtime/coverage.getCovPkgMap -func runtime_coverage_getCovPkgMap() map[int]int { - return covMeta.pkgMap -} diff --git a/contrib/go/_std_1.22/src/runtime/debug/stack.go b/contrib/go/_std_1.22/src/runtime/debug/stack.go deleted file mode 100644 index 3999840d3c8e..000000000000 --- a/contrib/go/_std_1.22/src/runtime/debug/stack.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package debug contains facilities for programs to debug themselves while -// they are running. -package debug - -import ( - "os" - "runtime" -) - -// PrintStack prints to standard error the stack trace returned by runtime.Stack. -func PrintStack() { - os.Stderr.Write(Stack()) -} - -// Stack returns a formatted stack trace of the goroutine that calls it. -// It calls [runtime.Stack] with a large enough buffer to capture the entire trace. -func Stack() []byte { - buf := make([]byte, 1024) - for { - n := runtime.Stack(buf, false) - if n < len(buf) { - return buf[:n] - } - buf = make([]byte, 2*len(buf)) - } -} diff --git a/contrib/go/_std_1.22/src/runtime/exithook.go b/contrib/go/_std_1.22/src/runtime/exithook.go deleted file mode 100644 index 65b426b383f8..000000000000 --- a/contrib/go/_std_1.22/src/runtime/exithook.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -// addExitHook registers the specified function 'f' to be run at -// program termination (e.g. when someone invokes os.Exit(), or when -// main.main returns). Hooks are run in reverse order of registration: -// first hook added is the last one run. -// -// CAREFUL: the expectation is that addExitHook should only be called -// from a safe context (e.g. not an error/panic path or signal -// handler, preemption enabled, allocation allowed, write barriers -// allowed, etc), and that the exit function 'f' will be invoked under -// similar circumstances. That is the say, we are expecting that 'f' -// uses normal / high-level Go code as opposed to one of the more -// restricted dialects used for the trickier parts of the runtime. -func addExitHook(f func(), runOnNonZeroExit bool) { - exitHooks.hooks = append(exitHooks.hooks, exitHook{f: f, runOnNonZeroExit: runOnNonZeroExit}) -} - -// exitHook stores a function to be run on program exit, registered -// by the utility runtime.addExitHook. -type exitHook struct { - f func() // func to run - runOnNonZeroExit bool // whether to run on non-zero exit code -} - -// exitHooks stores state related to hook functions registered to -// run when program execution terminates. -var exitHooks struct { - hooks []exitHook - runningExitHooks bool -} - -// runExitHooks runs any registered exit hook functions (funcs -// previously registered using runtime.addExitHook). Here 'exitCode' -// is the status code being passed to os.Exit, or zero if the program -// is terminating normally without calling os.Exit. -func runExitHooks(exitCode int) { - if exitHooks.runningExitHooks { - throw("internal error: exit hook invoked exit") - } - exitHooks.runningExitHooks = true - - runExitHook := func(f func()) (caughtPanic bool) { - defer func() { - if x := recover(); x != nil { - caughtPanic = true - } - }() - f() - return - } - - finishPageTrace() - for i := range exitHooks.hooks { - h := exitHooks.hooks[len(exitHooks.hooks)-i-1] - if exitCode != 0 && !h.runOnNonZeroExit { - continue - } - if caughtPanic := runExitHook(h.f); caughtPanic { - throw("internal error: exit hook invoked panic") - } - } - exitHooks.hooks = nil - exitHooks.runningExitHooks = false -} diff --git a/contrib/go/_std_1.22/src/runtime/lockrank.go b/contrib/go/_std_1.22/src/runtime/lockrank.go deleted file mode 100644 index b27e6c560615..000000000000 --- a/contrib/go/_std_1.22/src/runtime/lockrank.go +++ /dev/null @@ -1,212 +0,0 @@ -// Code generated by mklockrank.go; DO NOT EDIT. - -package runtime - -type lockRank int - -// Constants representing the ranks of all non-leaf runtime locks, in rank order. -// Locks with lower rank must be taken before locks with higher rank, -// in addition to satisfying the partial order in lockPartialOrder. -// A few ranks allow self-cycles, which are specified in lockPartialOrder. -const ( - lockRankUnknown lockRank = iota - - lockRankSysmon - lockRankScavenge - lockRankForcegc - lockRankDefer - lockRankSweepWaiters - lockRankAssistQueue - lockRankSweep - lockRankTestR - lockRankTestW - lockRankAllocmW - lockRankExecW - lockRankCpuprof - lockRankPollDesc - lockRankWakeableSleep - // SCHED - lockRankAllocmR - lockRankExecR - lockRankSched - lockRankAllg - lockRankAllp - lockRankTimers - lockRankNetpollInit - lockRankHchan - lockRankNotifyList - lockRankSudog - lockRankRoot - lockRankItab - lockRankReflectOffs - lockRankUserArenaState - // TRACEGLOBAL - lockRankTraceBuf - lockRankTraceStrings - // MALLOC - lockRankFin - lockRankSpanSetSpine - lockRankMspanSpecial - // MPROF - lockRankGcBitsArenas - lockRankProfInsert - lockRankProfBlock - lockRankProfMemActive - lockRankProfMemFuture - // STACKGROW - lockRankGscan - lockRankStackpool - lockRankStackLarge - lockRankHchanLeaf - // WB - lockRankWbufSpans - lockRankMheap - lockRankMheapSpecial - lockRankGlobalAlloc - // TRACE - lockRankTrace - lockRankTraceStackTab - lockRankPanic - lockRankDeadlock - lockRankRaceFini - lockRankAllocmRInternal - lockRankExecRInternal - lockRankTestRInternal -) - -// lockRankLeafRank is the rank of lock that does not have a declared rank, -// and hence is a leaf lock. -const lockRankLeafRank lockRank = 1000 - -// lockNames gives the names associated with each of the above ranks. -var lockNames = []string{ - lockRankSysmon: "sysmon", - lockRankScavenge: "scavenge", - lockRankForcegc: "forcegc", - lockRankDefer: "defer", - lockRankSweepWaiters: "sweepWaiters", - lockRankAssistQueue: "assistQueue", - lockRankSweep: "sweep", - lockRankTestR: "testR", - lockRankTestW: "testW", - lockRankAllocmW: "allocmW", - lockRankExecW: "execW", - lockRankCpuprof: "cpuprof", - lockRankPollDesc: "pollDesc", - lockRankWakeableSleep: "wakeableSleep", - lockRankAllocmR: "allocmR", - lockRankExecR: "execR", - lockRankSched: "sched", - lockRankAllg: "allg", - lockRankAllp: "allp", - lockRankTimers: "timers", - lockRankNetpollInit: "netpollInit", - lockRankHchan: "hchan", - lockRankNotifyList: "notifyList", - lockRankSudog: "sudog", - lockRankRoot: "root", - lockRankItab: "itab", - lockRankReflectOffs: "reflectOffs", - lockRankUserArenaState: "userArenaState", - lockRankTraceBuf: "traceBuf", - lockRankTraceStrings: "traceStrings", - lockRankFin: "fin", - lockRankSpanSetSpine: "spanSetSpine", - lockRankMspanSpecial: "mspanSpecial", - lockRankGcBitsArenas: "gcBitsArenas", - lockRankProfInsert: "profInsert", - lockRankProfBlock: "profBlock", - lockRankProfMemActive: "profMemActive", - lockRankProfMemFuture: "profMemFuture", - lockRankGscan: "gscan", - lockRankStackpool: "stackpool", - lockRankStackLarge: "stackLarge", - lockRankHchanLeaf: "hchanLeaf", - lockRankWbufSpans: "wbufSpans", - lockRankMheap: "mheap", - lockRankMheapSpecial: "mheapSpecial", - lockRankGlobalAlloc: "globalAlloc", - lockRankTrace: "trace", - lockRankTraceStackTab: "traceStackTab", - lockRankPanic: "panic", - lockRankDeadlock: "deadlock", - lockRankRaceFini: "raceFini", - lockRankAllocmRInternal: "allocmRInternal", - lockRankExecRInternal: "execRInternal", - lockRankTestRInternal: "testRInternal", -} - -func (rank lockRank) String() string { - if rank == 0 { - return "UNKNOWN" - } - if rank == lockRankLeafRank { - return "LEAF" - } - if rank < 0 || int(rank) >= len(lockNames) { - return "BAD RANK" - } - return lockNames[rank] -} - -// lockPartialOrder is the transitive closure of the lock rank graph. -// An entry for rank X lists all of the ranks that can already be held -// when rank X is acquired. -// -// Lock ranks that allow self-cycles list themselves. -var lockPartialOrder [][]lockRank = [][]lockRank{ - lockRankSysmon: {}, - lockRankScavenge: {lockRankSysmon}, - lockRankForcegc: {lockRankSysmon}, - lockRankDefer: {}, - lockRankSweepWaiters: {}, - lockRankAssistQueue: {}, - lockRankSweep: {}, - lockRankTestR: {}, - lockRankTestW: {}, - lockRankAllocmW: {}, - lockRankExecW: {}, - lockRankCpuprof: {}, - lockRankPollDesc: {}, - lockRankWakeableSleep: {}, - lockRankAllocmR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep}, - lockRankExecR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep}, - lockRankSched: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR}, - lockRankAllg: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched}, - lockRankAllp: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched}, - lockRankTimers: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllp, lockRankTimers}, - lockRankNetpollInit: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllp, lockRankTimers}, - lockRankHchan: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankWakeableSleep, lockRankHchan}, - lockRankNotifyList: {}, - lockRankSudog: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankWakeableSleep, lockRankHchan, lockRankNotifyList}, - lockRankRoot: {}, - lockRankItab: {}, - lockRankReflectOffs: {lockRankItab}, - lockRankUserArenaState: {}, - lockRankTraceBuf: {lockRankSysmon, lockRankScavenge}, - lockRankTraceStrings: {lockRankSysmon, lockRankScavenge, lockRankTraceBuf}, - lockRankFin: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankMspanSpecial}, - lockRankProfInsert: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankProfBlock: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankProfMemActive: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, - lockRankProfMemFuture: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankHchan, lockRankNotifyList, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankProfMemActive}, - lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture}, - lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, - lockRankStackLarge: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, - lockRankHchanLeaf: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankHchanLeaf}, - lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, - lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans}, - lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, - lockRankGlobalAlloc: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankMheapSpecial}, - lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, - lockRankTraceStackTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankNetpollInit, lockRankHchan, lockRankNotifyList, lockRankSudog, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankTrace}, - lockRankPanic: {}, - lockRankDeadlock: {lockRankPanic, lockRankDeadlock}, - lockRankRaceFini: {lockRankPanic}, - lockRankAllocmRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankAllocmW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankAllocmR}, - lockRankExecRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankTestR, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankExecR}, - lockRankTestRInternal: {lockRankTestR, lockRankTestW}, -} diff --git a/contrib/go/_std_1.22/src/runtime/mbitmap.go b/contrib/go/_std_1.22/src/runtime/mbitmap.go deleted file mode 100644 index cdd1c5fc3b5b..000000000000 --- a/contrib/go/_std_1.22/src/runtime/mbitmap.go +++ /dev/null @@ -1,775 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "internal/goarch" - "runtime/internal/atomic" - "runtime/internal/sys" - "unsafe" -) - -// addb returns the byte pointer p+n. -// -//go:nowritebarrier -//go:nosplit -func addb(p *byte, n uintptr) *byte { - // Note: wrote out full expression instead of calling add(p, n) - // to reduce the number of temporaries generated by the - // compiler for this trivial expression during inlining. - return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + n)) -} - -// subtractb returns the byte pointer p-n. -// -//go:nowritebarrier -//go:nosplit -func subtractb(p *byte, n uintptr) *byte { - // Note: wrote out full expression instead of calling add(p, -n) - // to reduce the number of temporaries generated by the - // compiler for this trivial expression during inlining. - return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) - n)) -} - -// add1 returns the byte pointer p+1. -// -//go:nowritebarrier -//go:nosplit -func add1(p *byte) *byte { - // Note: wrote out full expression instead of calling addb(p, 1) - // to reduce the number of temporaries generated by the - // compiler for this trivial expression during inlining. - return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + 1)) -} - -// subtract1 returns the byte pointer p-1. -// -// nosplit because it is used during write barriers and must not be preempted. -// -//go:nowritebarrier -//go:nosplit -func subtract1(p *byte) *byte { - // Note: wrote out full expression instead of calling subtractb(p, 1) - // to reduce the number of temporaries generated by the - // compiler for this trivial expression during inlining. - return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) - 1)) -} - -// markBits provides access to the mark bit for an object in the heap. -// bytep points to the byte holding the mark bit. -// mask is a byte with a single bit set that can be &ed with *bytep -// to see if the bit has been set. -// *m.byte&m.mask != 0 indicates the mark bit is set. -// index can be used along with span information to generate -// the address of the object in the heap. -// We maintain one set of mark bits for allocation and one for -// marking purposes. -type markBits struct { - bytep *uint8 - mask uint8 - index uintptr -} - -//go:nosplit -func (s *mspan) allocBitsForIndex(allocBitIndex uintptr) markBits { - bytep, mask := s.allocBits.bitp(allocBitIndex) - return markBits{bytep, mask, allocBitIndex} -} - -// refillAllocCache takes 8 bytes s.allocBits starting at whichByte -// and negates them so that ctz (count trailing zeros) instructions -// can be used. It then places these 8 bytes into the cached 64 bit -// s.allocCache. -func (s *mspan) refillAllocCache(whichByte uint16) { - bytes := (*[8]uint8)(unsafe.Pointer(s.allocBits.bytep(uintptr(whichByte)))) - aCache := uint64(0) - aCache |= uint64(bytes[0]) - aCache |= uint64(bytes[1]) << (1 * 8) - aCache |= uint64(bytes[2]) << (2 * 8) - aCache |= uint64(bytes[3]) << (3 * 8) - aCache |= uint64(bytes[4]) << (4 * 8) - aCache |= uint64(bytes[5]) << (5 * 8) - aCache |= uint64(bytes[6]) << (6 * 8) - aCache |= uint64(bytes[7]) << (7 * 8) - s.allocCache = ^aCache -} - -// nextFreeIndex returns the index of the next free object in s at -// or after s.freeindex. -// There are hardware instructions that can be used to make this -// faster if profiling warrants it. -func (s *mspan) nextFreeIndex() uint16 { - sfreeindex := s.freeindex - snelems := s.nelems - if sfreeindex == snelems { - return sfreeindex - } - if sfreeindex > snelems { - throw("s.freeindex > s.nelems") - } - - aCache := s.allocCache - - bitIndex := sys.TrailingZeros64(aCache) - for bitIndex == 64 { - // Move index to start of next cached bits. - sfreeindex = (sfreeindex + 64) &^ (64 - 1) - if sfreeindex >= snelems { - s.freeindex = snelems - return snelems - } - whichByte := sfreeindex / 8 - // Refill s.allocCache with the next 64 alloc bits. - s.refillAllocCache(whichByte) - aCache = s.allocCache - bitIndex = sys.TrailingZeros64(aCache) - // nothing available in cached bits - // grab the next 8 bytes and try again. - } - result := sfreeindex + uint16(bitIndex) - if result >= snelems { - s.freeindex = snelems - return snelems - } - - s.allocCache >>= uint(bitIndex + 1) - sfreeindex = result + 1 - - if sfreeindex%64 == 0 && sfreeindex != snelems { - // We just incremented s.freeindex so it isn't 0. - // As each 1 in s.allocCache was encountered and used for allocation - // it was shifted away. At this point s.allocCache contains all 0s. - // Refill s.allocCache so that it corresponds - // to the bits at s.allocBits starting at s.freeindex. - whichByte := sfreeindex / 8 - s.refillAllocCache(whichByte) - } - s.freeindex = sfreeindex - return result -} - -// isFree reports whether the index'th object in s is unallocated. -// -// The caller must ensure s.state is mSpanInUse, and there must have -// been no preemption points since ensuring this (which could allow a -// GC transition, which would allow the state to change). -func (s *mspan) isFree(index uintptr) bool { - if index < uintptr(s.freeIndexForScan) { - return false - } - bytep, mask := s.allocBits.bitp(index) - return *bytep&mask == 0 -} - -// divideByElemSize returns n/s.elemsize. -// n must be within [0, s.npages*_PageSize), -// or may be exactly s.npages*_PageSize -// if s.elemsize is from sizeclasses.go. -// -// nosplit, because it is called by objIndex, which is nosplit -// -//go:nosplit -func (s *mspan) divideByElemSize(n uintptr) uintptr { - const doubleCheck = false - - // See explanation in mksizeclasses.go's computeDivMagic. - q := uintptr((uint64(n) * uint64(s.divMul)) >> 32) - - if doubleCheck && q != n/s.elemsize { - println(n, "/", s.elemsize, "should be", n/s.elemsize, "but got", q) - throw("bad magic division") - } - return q -} - -// nosplit, because it is called by other nosplit code like findObject -// -//go:nosplit -func (s *mspan) objIndex(p uintptr) uintptr { - return s.divideByElemSize(p - s.base()) -} - -func markBitsForAddr(p uintptr) markBits { - s := spanOf(p) - objIndex := s.objIndex(p) - return s.markBitsForIndex(objIndex) -} - -func (s *mspan) markBitsForIndex(objIndex uintptr) markBits { - bytep, mask := s.gcmarkBits.bitp(objIndex) - return markBits{bytep, mask, objIndex} -} - -func (s *mspan) markBitsForBase() markBits { - return markBits{&s.gcmarkBits.x, uint8(1), 0} -} - -// isMarked reports whether mark bit m is set. -func (m markBits) isMarked() bool { - return *m.bytep&m.mask != 0 -} - -// setMarked sets the marked bit in the markbits, atomically. -func (m markBits) setMarked() { - // Might be racing with other updates, so use atomic update always. - // We used to be clever here and use a non-atomic update in certain - // cases, but it's not worth the risk. - atomic.Or8(m.bytep, m.mask) -} - -// setMarkedNonAtomic sets the marked bit in the markbits, non-atomically. -func (m markBits) setMarkedNonAtomic() { - *m.bytep |= m.mask -} - -// clearMarked clears the marked bit in the markbits, atomically. -func (m markBits) clearMarked() { - // Might be racing with other updates, so use atomic update always. - // We used to be clever here and use a non-atomic update in certain - // cases, but it's not worth the risk. - atomic.And8(m.bytep, ^m.mask) -} - -// markBitsForSpan returns the markBits for the span base address base. -func markBitsForSpan(base uintptr) (mbits markBits) { - mbits = markBitsForAddr(base) - if mbits.mask != 1 { - throw("markBitsForSpan: unaligned start") - } - return mbits -} - -// advance advances the markBits to the next object in the span. -func (m *markBits) advance() { - if m.mask == 1<<7 { - m.bytep = (*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(m.bytep)) + 1)) - m.mask = 1 - } else { - m.mask = m.mask << 1 - } - m.index++ -} - -// clobberdeadPtr is a special value that is used by the compiler to -// clobber dead stack slots, when -clobberdead flag is set. -const clobberdeadPtr = uintptr(0xdeaddead | 0xdeaddead<<((^uintptr(0)>>63)*32)) - -// badPointer throws bad pointer in heap panic. -func badPointer(s *mspan, p, refBase, refOff uintptr) { - // Typically this indicates an incorrect use - // of unsafe or cgo to store a bad pointer in - // the Go heap. It may also indicate a runtime - // bug. - // - // TODO(austin): We could be more aggressive - // and detect pointers to unallocated objects - // in allocated spans. - printlock() - print("runtime: pointer ", hex(p)) - if s != nil { - state := s.state.get() - if state != mSpanInUse { - print(" to unallocated span") - } else { - print(" to unused region of span") - } - print(" span.base()=", hex(s.base()), " span.limit=", hex(s.limit), " span.state=", state) - } - print("\n") - if refBase != 0 { - print("runtime: found in object at *(", hex(refBase), "+", hex(refOff), ")\n") - gcDumpObject("object", refBase, refOff) - } - getg().m.traceback = 2 - throw("found bad pointer in Go heap (incorrect use of unsafe or cgo?)") -} - -// findObject returns the base address for the heap object containing -// the address p, the object's span, and the index of the object in s. -// If p does not point into a heap object, it returns base == 0. -// -// If p points is an invalid heap pointer and debug.invalidptr != 0, -// findObject panics. -// -// refBase and refOff optionally give the base address of the object -// in which the pointer p was found and the byte offset at which it -// was found. These are used for error reporting. -// -// It is nosplit so it is safe for p to be a pointer to the current goroutine's stack. -// Since p is a uintptr, it would not be adjusted if the stack were to move. -// -//go:nosplit -func findObject(p, refBase, refOff uintptr) (base uintptr, s *mspan, objIndex uintptr) { - s = spanOf(p) - // If s is nil, the virtual address has never been part of the heap. - // This pointer may be to some mmap'd region, so we allow it. - if s == nil { - if (GOARCH == "amd64" || GOARCH == "arm64") && p == clobberdeadPtr && debug.invalidptr != 0 { - // Crash if clobberdeadPtr is seen. Only on AMD64 and ARM64 for now, - // as they are the only platform where compiler's clobberdead mode is - // implemented. On these platforms clobberdeadPtr cannot be a valid address. - badPointer(s, p, refBase, refOff) - } - return - } - // If p is a bad pointer, it may not be in s's bounds. - // - // Check s.state to synchronize with span initialization - // before checking other fields. See also spanOfHeap. - if state := s.state.get(); state != mSpanInUse || p < s.base() || p >= s.limit { - // Pointers into stacks are also ok, the runtime manages these explicitly. - if state == mSpanManual { - return - } - // The following ensures that we are rigorous about what data - // structures hold valid pointers. - if debug.invalidptr != 0 { - badPointer(s, p, refBase, refOff) - } - return - } - - objIndex = s.objIndex(p) - base = s.base() + objIndex*s.elemsize - return -} - -// reflect_verifyNotInHeapPtr reports whether converting the not-in-heap pointer into a unsafe.Pointer is ok. -// -//go:linkname reflect_verifyNotInHeapPtr reflect.verifyNotInHeapPtr -func reflect_verifyNotInHeapPtr(p uintptr) bool { - // Conversion to a pointer is ok as long as findObject above does not call badPointer. - // Since we're already promised that p doesn't point into the heap, just disallow heap - // pointers and the special clobbered pointer. - return spanOf(p) == nil && p != clobberdeadPtr -} - -const ptrBits = 8 * goarch.PtrSize - -// bulkBarrierBitmap executes write barriers for copying from [src, -// src+size) to [dst, dst+size) using a 1-bit pointer bitmap. src is -// assumed to start maskOffset bytes into the data covered by the -// bitmap in bits (which may not be a multiple of 8). -// -// This is used by bulkBarrierPreWrite for writes to data and BSS. -// -//go:nosplit -func bulkBarrierBitmap(dst, src, size, maskOffset uintptr, bits *uint8) { - word := maskOffset / goarch.PtrSize - bits = addb(bits, word/8) - mask := uint8(1) << (word % 8) - - buf := &getg().m.p.ptr().wbBuf - for i := uintptr(0); i < size; i += goarch.PtrSize { - if mask == 0 { - bits = addb(bits, 1) - if *bits == 0 { - // Skip 8 words. - i += 7 * goarch.PtrSize - continue - } - mask = 1 - } - if *bits&mask != 0 { - dstx := (*uintptr)(unsafe.Pointer(dst + i)) - if src == 0 { - p := buf.get1() - p[0] = *dstx - } else { - srcx := (*uintptr)(unsafe.Pointer(src + i)) - p := buf.get2() - p[0] = *dstx - p[1] = *srcx - } - } - mask <<= 1 - } -} - -// typeBitsBulkBarrier executes a write barrier for every -// pointer that would be copied from [src, src+size) to [dst, -// dst+size) by a memmove using the type bitmap to locate those -// pointer slots. -// -// The type typ must correspond exactly to [src, src+size) and [dst, dst+size). -// dst, src, and size must be pointer-aligned. -// The type typ must have a plain bitmap, not a GC program. -// The only use of this function is in channel sends, and the -// 64 kB channel element limit takes care of this for us. -// -// Must not be preempted because it typically runs right before memmove, -// and the GC must observe them as an atomic action. -// -// Callers must perform cgo checks if goexperiment.CgoCheck2. -// -//go:nosplit -func typeBitsBulkBarrier(typ *_type, dst, src, size uintptr) { - if typ == nil { - throw("runtime: typeBitsBulkBarrier without type") - } - if typ.Size_ != size { - println("runtime: typeBitsBulkBarrier with type ", toRType(typ).string(), " of size ", typ.Size_, " but memory size", size) - throw("runtime: invalid typeBitsBulkBarrier") - } - if typ.Kind_&kindGCProg != 0 { - println("runtime: typeBitsBulkBarrier with type ", toRType(typ).string(), " with GC prog") - throw("runtime: invalid typeBitsBulkBarrier") - } - if !writeBarrier.enabled { - return - } - ptrmask := typ.GCData - buf := &getg().m.p.ptr().wbBuf - var bits uint32 - for i := uintptr(0); i < typ.PtrBytes; i += goarch.PtrSize { - if i&(goarch.PtrSize*8-1) == 0 { - bits = uint32(*ptrmask) - ptrmask = addb(ptrmask, 1) - } else { - bits = bits >> 1 - } - if bits&1 != 0 { - dstx := (*uintptr)(unsafe.Pointer(dst + i)) - srcx := (*uintptr)(unsafe.Pointer(src + i)) - p := buf.get2() - p[0] = *dstx - p[1] = *srcx - } - } -} - -// countAlloc returns the number of objects allocated in span s by -// scanning the mark bitmap. -func (s *mspan) countAlloc() int { - count := 0 - bytes := divRoundUp(uintptr(s.nelems), 8) - // Iterate over each 8-byte chunk and count allocations - // with an intrinsic. Note that newMarkBits guarantees that - // gcmarkBits will be 8-byte aligned, so we don't have to - // worry about edge cases, irrelevant bits will simply be zero. - for i := uintptr(0); i < bytes; i += 8 { - // Extract 64 bits from the byte pointer and get a OnesCount. - // Note that the unsafe cast here doesn't preserve endianness, - // but that's OK. We only care about how many bits are 1, not - // about the order we discover them in. - mrkBits := *(*uint64)(unsafe.Pointer(s.gcmarkBits.bytep(i))) - count += sys.OnesCount64(mrkBits) - } - return count -} - -// Read the bytes starting at the aligned pointer p into a uintptr. -// Read is little-endian. -func readUintptr(p *byte) uintptr { - x := *(*uintptr)(unsafe.Pointer(p)) - if goarch.BigEndian { - if goarch.PtrSize == 8 { - return uintptr(sys.Bswap64(uint64(x))) - } - return uintptr(sys.Bswap32(uint32(x))) - } - return x -} - -var debugPtrmask struct { - lock mutex - data *byte -} - -// progToPointerMask returns the 1-bit pointer mask output by the GC program prog. -// size the size of the region described by prog, in bytes. -// The resulting bitvector will have no more than size/goarch.PtrSize bits. -func progToPointerMask(prog *byte, size uintptr) bitvector { - n := (size/goarch.PtrSize + 7) / 8 - x := (*[1 << 30]byte)(persistentalloc(n+1, 1, &memstats.buckhash_sys))[:n+1] - x[len(x)-1] = 0xa1 // overflow check sentinel - n = runGCProg(prog, &x[0]) - if x[len(x)-1] != 0xa1 { - throw("progToPointerMask: overflow") - } - return bitvector{int32(n), &x[0]} -} - -// Packed GC pointer bitmaps, aka GC programs. -// -// For large types containing arrays, the type information has a -// natural repetition that can be encoded to save space in the -// binary and in the memory representation of the type information. -// -// The encoding is a simple Lempel-Ziv style bytecode machine -// with the following instructions: -// -// 00000000: stop -// 0nnnnnnn: emit n bits copied from the next (n+7)/8 bytes -// 10000000 n c: repeat the previous n bits c times; n, c are varints -// 1nnnnnnn c: repeat the previous n bits c times; c is a varint - -// runGCProg returns the number of 1-bit entries written to memory. -func runGCProg(prog, dst *byte) uintptr { - dstStart := dst - - // Bits waiting to be written to memory. - var bits uintptr - var nbits uintptr - - p := prog -Run: - for { - // Flush accumulated full bytes. - // The rest of the loop assumes that nbits <= 7. - for ; nbits >= 8; nbits -= 8 { - *dst = uint8(bits) - dst = add1(dst) - bits >>= 8 - } - - // Process one instruction. - inst := uintptr(*p) - p = add1(p) - n := inst & 0x7F - if inst&0x80 == 0 { - // Literal bits; n == 0 means end of program. - if n == 0 { - // Program is over. - break Run - } - nbyte := n / 8 - for i := uintptr(0); i < nbyte; i++ { - bits |= uintptr(*p) << nbits - p = add1(p) - *dst = uint8(bits) - dst = add1(dst) - bits >>= 8 - } - if n %= 8; n > 0 { - bits |= uintptr(*p) << nbits - p = add1(p) - nbits += n - } - continue Run - } - - // Repeat. If n == 0, it is encoded in a varint in the next bytes. - if n == 0 { - for off := uint(0); ; off += 7 { - x := uintptr(*p) - p = add1(p) - n |= (x & 0x7F) << off - if x&0x80 == 0 { - break - } - } - } - - // Count is encoded in a varint in the next bytes. - c := uintptr(0) - for off := uint(0); ; off += 7 { - x := uintptr(*p) - p = add1(p) - c |= (x & 0x7F) << off - if x&0x80 == 0 { - break - } - } - c *= n // now total number of bits to copy - - // If the number of bits being repeated is small, load them - // into a register and use that register for the entire loop - // instead of repeatedly reading from memory. - // Handling fewer than 8 bits here makes the general loop simpler. - // The cutoff is goarch.PtrSize*8 - 7 to guarantee that when we add - // the pattern to a bit buffer holding at most 7 bits (a partial byte) - // it will not overflow. - src := dst - const maxBits = goarch.PtrSize*8 - 7 - if n <= maxBits { - // Start with bits in output buffer. - pattern := bits - npattern := nbits - - // If we need more bits, fetch them from memory. - src = subtract1(src) - for npattern < n { - pattern <<= 8 - pattern |= uintptr(*src) - src = subtract1(src) - npattern += 8 - } - - // We started with the whole bit output buffer, - // and then we loaded bits from whole bytes. - // Either way, we might now have too many instead of too few. - // Discard the extra. - if npattern > n { - pattern >>= npattern - n - npattern = n - } - - // Replicate pattern to at most maxBits. - if npattern == 1 { - // One bit being repeated. - // If the bit is 1, make the pattern all 1s. - // If the bit is 0, the pattern is already all 0s, - // but we can claim that the number of bits - // in the word is equal to the number we need (c), - // because right shift of bits will zero fill. - if pattern == 1 { - pattern = 1<8 bits, there will be full bytes to flush - // on each iteration. - for ; c >= npattern; c -= npattern { - bits |= pattern << nbits - nbits += npattern - for nbits >= 8 { - *dst = uint8(bits) - dst = add1(dst) - bits >>= 8 - nbits -= 8 - } - } - - // Add final fragment to bit buffer. - if c > 0 { - pattern &= 1< nbits because n > maxBits and nbits <= 7 - // Leading src fragment. - src = subtractb(src, (off+7)/8) - if frag := off & 7; frag != 0 { - bits |= uintptr(*src) >> (8 - frag) << nbits - src = add1(src) - nbits += frag - c -= frag - } - // Main loop: load one byte, write another. - // The bits are rotating through the bit buffer. - for i := c / 8; i > 0; i-- { - bits |= uintptr(*src) << nbits - src = add1(src) - *dst = uint8(bits) - dst = add1(dst) - bits >>= 8 - } - // Final src fragment. - if c %= 8; c > 0 { - bits |= (uintptr(*src) & (1< 0; nbits -= 8 { - *dst = uint8(bits) - dst = add1(dst) - bits >>= 8 - } - return totalBits -} - -// materializeGCProg allocates space for the (1-bit) pointer bitmask -// for an object of size ptrdata. Then it fills that space with the -// pointer bitmask specified by the program prog. -// The bitmask starts at s.startAddr. -// The result must be deallocated with dematerializeGCProg. -func materializeGCProg(ptrdata uintptr, prog *byte) *mspan { - // Each word of ptrdata needs one bit in the bitmap. - bitmapBytes := divRoundUp(ptrdata, 8*goarch.PtrSize) - // Compute the number of pages needed for bitmapBytes. - pages := divRoundUp(bitmapBytes, pageSize) - s := mheap_.allocManual(pages, spanAllocPtrScalarBits) - runGCProg(addb(prog, 4), (*byte)(unsafe.Pointer(s.startAddr))) - return s -} -func dematerializeGCProg(s *mspan) { - mheap_.freeManual(s, spanAllocPtrScalarBits) -} - -func dumpGCProg(p *byte) { - nptr := 0 - for { - x := *p - p = add1(p) - if x == 0 { - print("\t", nptr, " end\n") - break - } - if x&0x80 == 0 { - print("\t", nptr, " lit ", x, ":") - n := int(x+7) / 8 - for i := 0; i < n; i++ { - print(" ", hex(*p)) - p = add1(p) - } - print("\n") - nptr += int(x) - } else { - nbit := int(x &^ 0x80) - if nbit == 0 { - for nb := uint(0); ; nb += 7 { - x := *p - p = add1(p) - nbit |= int(x&0x7f) << nb - if x&0x80 == 0 { - break - } - } - } - count := 0 - for nb := uint(0); ; nb += 7 { - x := *p - p = add1(p) - count |= int(x&0x7f) << nb - if x&0x80 == 0 { - break - } - } - print("\t", nptr, " repeat ", nbit, " × ", count, "\n") - nptr += nbit * count - } - } -} - -// Testing. - -// reflect_gcbits returns the GC type info for x, for testing. -// The result is the bitmap entries (0 or 1), one entry per byte. -// -//go:linkname reflect_gcbits reflect.gcbits -func reflect_gcbits(x any) []byte { - return getgcmask(x) -} diff --git a/contrib/go/_std_1.22/src/runtime/mbitmap_noallocheaders.go b/contrib/go/_std_1.22/src/runtime/mbitmap_noallocheaders.go deleted file mode 100644 index 383993aa1ef7..000000000000 --- a/contrib/go/_std_1.22/src/runtime/mbitmap_noallocheaders.go +++ /dev/null @@ -1,938 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !goexperiment.allocheaders - -// Garbage collector: type and heap bitmaps. -// -// Stack, data, and bss bitmaps -// -// Stack frames and global variables in the data and bss sections are -// described by bitmaps with 1 bit per pointer-sized word. A "1" bit -// means the word is a live pointer to be visited by the GC (referred to -// as "pointer"). A "0" bit means the word should be ignored by GC -// (referred to as "scalar", though it could be a dead pointer value). -// -// Heap bitmap -// -// The heap bitmap comprises 1 bit for each pointer-sized word in the heap, -// recording whether a pointer is stored in that word or not. This bitmap -// is stored in the heapArena metadata backing each heap arena. -// That is, if ha is the heapArena for the arena starting at "start", -// then ha.bitmap[0] holds the 64 bits for the 64 words "start" -// through start+63*ptrSize, ha.bitmap[1] holds the entries for -// start+64*ptrSize through start+127*ptrSize, and so on. -// Bits correspond to words in little-endian order. ha.bitmap[0]&1 represents -// the word at "start", ha.bitmap[0]>>1&1 represents the word at start+8, etc. -// (For 32-bit platforms, s/64/32/.) -// -// We also keep a noMorePtrs bitmap which allows us to stop scanning -// the heap bitmap early in certain situations. If ha.noMorePtrs[i]>>j&1 -// is 1, then the object containing the last word described by ha.bitmap[8*i+j] -// has no more pointers beyond those described by ha.bitmap[8*i+j]. -// If ha.noMorePtrs[i]>>j&1 is set, the entries in ha.bitmap[8*i+j+1] and -// beyond must all be zero until the start of the next object. -// -// The bitmap for noscan spans is set to all zero at span allocation time. -// -// The bitmap for unallocated objects in scannable spans is not maintained -// (can be junk). - -package runtime - -import ( - "internal/abi" - "internal/goarch" - "runtime/internal/sys" - "unsafe" -) - -const ( - // For compatibility with the allocheaders GOEXPERIMENT. - mallocHeaderSize = 0 - minSizeForMallocHeader = ^uintptr(0) -) - -// For compatibility with the allocheaders GOEXPERIMENT. -// -//go:nosplit -func heapBitsInSpan(_ uintptr) bool { - return false -} - -// heapArenaPtrScalar contains the per-heapArena pointer/scalar metadata for the GC. -type heapArenaPtrScalar struct { - // bitmap stores the pointer/scalar bitmap for the words in - // this arena. See mbitmap.go for a description. - // This array uses 1 bit per word of heap, or 1.6% of the heap size (for 64-bit). - bitmap [heapArenaBitmapWords]uintptr - - // If the ith bit of noMorePtrs is true, then there are no more - // pointers for the object containing the word described by the - // high bit of bitmap[i]. - // In that case, bitmap[i+1], ... must be zero until the start - // of the next object. - // We never operate on these entries using bit-parallel techniques, - // so it is ok if they are small. Also, they can't be bigger than - // uint16 because at that size a single noMorePtrs entry - // represents 8K of memory, the minimum size of a span. Any larger - // and we'd have to worry about concurrent updates. - // This array uses 1 bit per word of bitmap, or .024% of the heap size (for 64-bit). - noMorePtrs [heapArenaBitmapWords / 8]uint8 -} - -// heapBits provides access to the bitmap bits for a single heap word. -// The methods on heapBits take value receivers so that the compiler -// can more easily inline calls to those methods and registerize the -// struct fields independently. -type heapBits struct { - // heapBits will report on pointers in the range [addr,addr+size). - // The low bit of mask contains the pointerness of the word at addr - // (assuming valid>0). - addr, size uintptr - - // The next few pointer bits representing words starting at addr. - // Those bits already returned by next() are zeroed. - mask uintptr - // Number of bits in mask that are valid. mask is always less than 1<> off - valid := ptrBits - off - - // Process depending on where the object ends. - nptr := size / goarch.PtrSize - if nptr < valid { - // Bits for this object end before the end of this bitmap word. - // Squash bits for the following objects. - mask &= 1<<(nptr&(ptrBits-1)) - 1 - valid = nptr - } else if nptr == valid { - // Bits for this object end at exactly the end of this bitmap word. - // All good. - } else { - // Bits for this object extend into the next bitmap word. See if there - // may be any pointers recorded there. - if uintptr(ha.noMorePtrs[idx/8])>>(idx%8)&1 != 0 { - // No more pointers in this object after this bitmap word. - // Update size so we know not to look there. - size = valid * goarch.PtrSize - } - } - - return heapBits{addr: addr, size: size, mask: mask, valid: valid} -} - -// Returns the (absolute) address of the next known pointer and -// a heapBits iterator representing any remaining pointers. -// If there are no more pointers, returns address 0. -// Note that next does not modify h. The caller must record the result. -// -// nosplit because it is used during write barriers and must not be preempted. -// -//go:nosplit -func (h heapBits) next() (heapBits, uintptr) { - for { - if h.mask != 0 { - var i int - if goarch.PtrSize == 8 { - i = sys.TrailingZeros64(uint64(h.mask)) - } else { - i = sys.TrailingZeros32(uint32(h.mask)) - } - h.mask ^= uintptr(1) << (i & (ptrBits - 1)) - return h, h.addr + uintptr(i)*goarch.PtrSize - } - - // Skip words that we've already processed. - h.addr += h.valid * goarch.PtrSize - h.size -= h.valid * goarch.PtrSize - if h.size == 0 { - return h, 0 // no more pointers - } - - // Grab more bits and try again. - h = heapBitsForAddr(h.addr, h.size) - } -} - -// nextFast is like next, but can return 0 even when there are more pointers -// to be found. Callers should call next if nextFast returns 0 as its second -// return value. -// -// if addr, h = h.nextFast(); addr == 0 { -// if addr, h = h.next(); addr == 0 { -// ... no more pointers ... -// } -// } -// ... process pointer at addr ... -// -// nextFast is designed to be inlineable. -// -//go:nosplit -func (h heapBits) nextFast() (heapBits, uintptr) { - // TESTQ/JEQ - if h.mask == 0 { - return h, 0 - } - // BSFQ - var i int - if goarch.PtrSize == 8 { - i = sys.TrailingZeros64(uint64(h.mask)) - } else { - i = sys.TrailingZeros32(uint32(h.mask)) - } - // BTCQ - h.mask ^= uintptr(1) << (i & (ptrBits - 1)) - // LEAQ (XX)(XX*8) - return h, h.addr + uintptr(i)*goarch.PtrSize -} - -// bulkBarrierPreWrite executes a write barrier -// for every pointer slot in the memory range [src, src+size), -// using pointer/scalar information from [dst, dst+size). -// This executes the write barriers necessary before a memmove. -// src, dst, and size must be pointer-aligned. -// The range [dst, dst+size) must lie within a single object. -// It does not perform the actual writes. -// -// As a special case, src == 0 indicates that this is being used for a -// memclr. bulkBarrierPreWrite will pass 0 for the src of each write -// barrier. -// -// Callers should call bulkBarrierPreWrite immediately before -// calling memmove(dst, src, size). This function is marked nosplit -// to avoid being preempted; the GC must not stop the goroutine -// between the memmove and the execution of the barriers. -// The caller is also responsible for cgo pointer checks if this -// may be writing Go pointers into non-Go memory. -// -// The pointer bitmap is not maintained for allocations containing -// no pointers at all; any caller of bulkBarrierPreWrite must first -// make sure the underlying allocation contains pointers, usually -// by checking typ.PtrBytes. -// -// The type of the space can be provided purely as an optimization, -// however it is not used with GOEXPERIMENT=noallocheaders. -// -// Callers must perform cgo checks if goexperiment.CgoCheck2. -// -//go:nosplit -func bulkBarrierPreWrite(dst, src, size uintptr, _ *abi.Type) { - if (dst|src|size)&(goarch.PtrSize-1) != 0 { - throw("bulkBarrierPreWrite: unaligned arguments") - } - if !writeBarrier.enabled { - return - } - if s := spanOf(dst); s == nil { - // If dst is a global, use the data or BSS bitmaps to - // execute write barriers. - for _, datap := range activeModules() { - if datap.data <= dst && dst < datap.edata { - bulkBarrierBitmap(dst, src, size, dst-datap.data, datap.gcdatamask.bytedata) - return - } - } - for _, datap := range activeModules() { - if datap.bss <= dst && dst < datap.ebss { - bulkBarrierBitmap(dst, src, size, dst-datap.bss, datap.gcbssmask.bytedata) - return - } - } - return - } else if s.state.get() != mSpanInUse || dst < s.base() || s.limit <= dst { - // dst was heap memory at some point, but isn't now. - // It can't be a global. It must be either our stack, - // or in the case of direct channel sends, it could be - // another stack. Either way, no need for barriers. - // This will also catch if dst is in a freed span, - // though that should never have. - return - } - - buf := &getg().m.p.ptr().wbBuf - h := heapBitsForAddr(dst, size) - if src == 0 { - for { - var addr uintptr - if h, addr = h.next(); addr == 0 { - break - } - dstx := (*uintptr)(unsafe.Pointer(addr)) - p := buf.get1() - p[0] = *dstx - } - } else { - for { - var addr uintptr - if h, addr = h.next(); addr == 0 { - break - } - dstx := (*uintptr)(unsafe.Pointer(addr)) - srcx := (*uintptr)(unsafe.Pointer(src + (addr - dst))) - p := buf.get2() - p[0] = *dstx - p[1] = *srcx - } - } -} - -// bulkBarrierPreWriteSrcOnly is like bulkBarrierPreWrite but -// does not execute write barriers for [dst, dst+size). -// -// In addition to the requirements of bulkBarrierPreWrite -// callers need to ensure [dst, dst+size) is zeroed. -// -// This is used for special cases where e.g. dst was just -// created and zeroed with malloc. -// -// The type of the space can be provided purely as an optimization, -// however it is not used with GOEXPERIMENT=noallocheaders. -// -//go:nosplit -func bulkBarrierPreWriteSrcOnly(dst, src, size uintptr, _ *abi.Type) { - if (dst|src|size)&(goarch.PtrSize-1) != 0 { - throw("bulkBarrierPreWrite: unaligned arguments") - } - if !writeBarrier.enabled { - return - } - buf := &getg().m.p.ptr().wbBuf - h := heapBitsForAddr(dst, size) - for { - var addr uintptr - if h, addr = h.next(); addr == 0 { - break - } - srcx := (*uintptr)(unsafe.Pointer(addr - dst + src)) - p := buf.get1() - p[0] = *srcx - } -} - -// initHeapBits initializes the heap bitmap for a span. -// If this is a span of single pointer allocations, it initializes all -// words to pointer. If force is true, clears all bits. -func (s *mspan) initHeapBits(forceClear bool) { - if forceClear || s.spanclass.noscan() { - // Set all the pointer bits to zero. We do this once - // when the span is allocated so we don't have to do it - // for each object allocation. - base := s.base() - size := s.npages * pageSize - h := writeHeapBitsForAddr(base) - h.flush(base, size) - return - } - isPtrs := goarch.PtrSize == 8 && s.elemsize == goarch.PtrSize - if !isPtrs { - return // nothing to do - } - h := writeHeapBitsForAddr(s.base()) - size := s.npages * pageSize - nptrs := size / goarch.PtrSize - for i := uintptr(0); i < nptrs; i += ptrBits { - h = h.write(^uintptr(0), ptrBits) - } - h.flush(s.base(), size) -} - -type writeHeapBits struct { - addr uintptr // address that the low bit of mask represents the pointer state of. - mask uintptr // some pointer bits starting at the address addr. - valid uintptr // number of bits in buf that are valid (including low) - low uintptr // number of low-order bits to not overwrite -} - -func writeHeapBitsForAddr(addr uintptr) (h writeHeapBits) { - // We start writing bits maybe in the middle of a heap bitmap word. - // Remember how many bits into the word we started, so we can be sure - // not to overwrite the previous bits. - h.low = addr / goarch.PtrSize % ptrBits - - // round down to heap word that starts the bitmap word. - h.addr = addr - h.low*goarch.PtrSize - - // We don't have any bits yet. - h.mask = 0 - h.valid = h.low - - return -} - -// write appends the pointerness of the next valid pointer slots -// using the low valid bits of bits. 1=pointer, 0=scalar. -func (h writeHeapBits) write(bits, valid uintptr) writeHeapBits { - if h.valid+valid <= ptrBits { - // Fast path - just accumulate the bits. - h.mask |= bits << h.valid - h.valid += valid - return h - } - // Too many bits to fit in this word. Write the current word - // out and move on to the next word. - - data := h.mask | bits<> (ptrBits - h.valid) // leftover for next word - h.valid += valid - ptrBits // have h.valid+valid bits, writing ptrBits of them - - // Flush mask to the memory bitmap. - // TODO: figure out how to cache arena lookup. - ai := arenaIndex(h.addr) - ha := mheap_.arenas[ai.l1()][ai.l2()] - idx := h.addr / (ptrBits * goarch.PtrSize) % heapArenaBitmapWords - m := uintptr(1)< ptrBits { - h = h.write(0, ptrBits) - words -= ptrBits - } - return h.write(0, words) -} - -// Flush the bits that have been written, and add zeros as needed -// to cover the full object [addr, addr+size). -func (h writeHeapBits) flush(addr, size uintptr) { - // zeros counts the number of bits needed to represent the object minus the - // number of bits we've already written. This is the number of 0 bits - // that need to be added. - zeros := (addr+size-h.addr)/goarch.PtrSize - h.valid - - // Add zero bits up to the bitmap word boundary - if zeros > 0 { - z := ptrBits - h.valid - if z > zeros { - z = zeros - } - h.valid += z - zeros -= z - } - - // Find word in bitmap that we're going to write. - ai := arenaIndex(h.addr) - ha := mheap_.arenas[ai.l1()][ai.l2()] - idx := h.addr / (ptrBits * goarch.PtrSize) % heapArenaBitmapWords - - // Write remaining bits. - if h.valid != h.low { - m := uintptr(1)< 8 { - h = h.write(uintptr(*p), 8) - p = add1(p) - j -= 8 - } - h = h.write(uintptr(*p), j) - - if i+typ.Size_ == dataSize { - break // no padding after last element - } - - // Pad with zeros to the start of the next element. - h = h.pad(typ.Size_ - n*goarch.PtrSize) - } - - h.flush(x, size) - - // Erase the expanded GC program. - memclrNoHeapPointers(unsafe.Pointer(obj), (n+7)/8) - return - } - - // Note about sizes: - // - // typ.Size is the number of words in the object, - // and typ.PtrBytes is the number of words in the prefix - // of the object that contains pointers. That is, the final - // typ.Size - typ.PtrBytes words contain no pointers. - // This allows optimization of a common pattern where - // an object has a small header followed by a large scalar - // buffer. If we know the pointers are over, we don't have - // to scan the buffer's heap bitmap at all. - // The 1-bit ptrmasks are sized to contain only bits for - // the typ.PtrBytes prefix, zero padded out to a full byte - // of bitmap. If there is more room in the allocated object, - // that space is pointerless. The noMorePtrs bitmap will prevent - // scanning large pointerless tails of an object. - // - // Replicated copies are not as nice: if there is an array of - // objects with scalar tails, all but the last tail does have to - // be initialized, because there is no way to say "skip forward". - - ptrs := typ.PtrBytes / goarch.PtrSize - if typ.Size_ == dataSize { // Single element - if ptrs <= ptrBits { // Single small element - m := readUintptr(typ.GCData) - h = h.write(m, ptrs) - } else { // Single large element - p := typ.GCData - for { - h = h.write(readUintptr(p), ptrBits) - p = addb(p, ptrBits/8) - ptrs -= ptrBits - if ptrs <= ptrBits { - break - } - } - m := readUintptr(p) - h = h.write(m, ptrs) - } - } else { // Repeated element - words := typ.Size_ / goarch.PtrSize // total words, including scalar tail - if words <= ptrBits { // Repeated small element - n := dataSize / typ.Size_ - m := readUintptr(typ.GCData) - // Make larger unit to repeat - for words <= ptrBits/2 { - if n&1 != 0 { - h = h.write(m, words) - } - n /= 2 - m |= m << words - ptrs += words - words *= 2 - if n == 1 { - break - } - } - for n > 1 { - h = h.write(m, words) - n-- - } - h = h.write(m, ptrs) - } else { // Repeated large element - for i := uintptr(0); true; i += typ.Size_ { - p := typ.GCData - j := ptrs - for j > ptrBits { - h = h.write(readUintptr(p), ptrBits) - p = addb(p, ptrBits/8) - j -= ptrBits - } - m := readUintptr(p) - h = h.write(m, j) - if i+typ.Size_ == dataSize { - break // don't need the trailing nonptr bits on the last element. - } - // Pad with zeros to the start of the next element. - h = h.pad(typ.Size_ - typ.PtrBytes) - } - } - } - h.flush(x, size) - - if doubleCheck { - h := heapBitsForAddr(x, size) - for i := uintptr(0); i < size; i += goarch.PtrSize { - // Compute the pointer bit we want at offset i. - want := false - if i < dataSize { - off := i % typ.Size_ - if off < typ.PtrBytes { - j := off / goarch.PtrSize - want = *addb(typ.GCData, j/8)>>(j%8)&1 != 0 - } - } - if want { - var addr uintptr - h, addr = h.next() - if addr != x+i { - throw("heapBitsSetType: pointer entry not correct") - } - } - } - if _, addr := h.next(); addr != 0 { - throw("heapBitsSetType: extra pointer") - } - } -} - -// For goexperiment.AllocHeaders -func heapSetType(x, dataSize uintptr, typ *_type, header **_type, span *mspan) (scanSize uintptr) { - return 0 -} - -// Testing. - -// Returns GC type info for the pointer stored in ep for testing. -// If ep points to the stack, only static live information will be returned -// (i.e. not for objects which are only dynamically live stack objects). -func getgcmask(ep any) (mask []byte) { - e := *efaceOf(&ep) - p := e.data - t := e._type - // data or bss - for _, datap := range activeModules() { - // data - if datap.data <= uintptr(p) && uintptr(p) < datap.edata { - bitmap := datap.gcdatamask.bytedata - n := (*ptrtype)(unsafe.Pointer(t)).Elem.Size_ - mask = make([]byte, n/goarch.PtrSize) - for i := uintptr(0); i < n; i += goarch.PtrSize { - off := (uintptr(p) + i - datap.data) / goarch.PtrSize - mask[i/goarch.PtrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1 - } - return - } - - // bss - if datap.bss <= uintptr(p) && uintptr(p) < datap.ebss { - bitmap := datap.gcbssmask.bytedata - n := (*ptrtype)(unsafe.Pointer(t)).Elem.Size_ - mask = make([]byte, n/goarch.PtrSize) - for i := uintptr(0); i < n; i += goarch.PtrSize { - off := (uintptr(p) + i - datap.bss) / goarch.PtrSize - mask[i/goarch.PtrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1 - } - return - } - } - - // heap - if base, s, _ := findObject(uintptr(p), 0, 0); base != 0 { - if s.spanclass.noscan() { - return nil - } - n := s.elemsize - hbits := heapBitsForAddr(base, n) - mask = make([]byte, n/goarch.PtrSize) - for { - var addr uintptr - if hbits, addr = hbits.next(); addr == 0 { - break - } - mask[(addr-base)/goarch.PtrSize] = 1 - } - // Callers expect this mask to end at the last pointer. - for len(mask) > 0 && mask[len(mask)-1] == 0 { - mask = mask[:len(mask)-1] - } - - // Make sure we keep ep alive. We may have stopped referencing - // ep's data pointer sometime before this point and it's possible - // for that memory to get freed. - KeepAlive(ep) - return - } - - // stack - if gp := getg(); gp.m.curg.stack.lo <= uintptr(p) && uintptr(p) < gp.m.curg.stack.hi { - found := false - var u unwinder - for u.initAt(gp.m.curg.sched.pc, gp.m.curg.sched.sp, 0, gp.m.curg, 0); u.valid(); u.next() { - if u.frame.sp <= uintptr(p) && uintptr(p) < u.frame.varp { - found = true - break - } - } - if found { - locals, _, _ := u.frame.getStackMap(false) - if locals.n == 0 { - return - } - size := uintptr(locals.n) * goarch.PtrSize - n := (*ptrtype)(unsafe.Pointer(t)).Elem.Size_ - mask = make([]byte, n/goarch.PtrSize) - for i := uintptr(0); i < n; i += goarch.PtrSize { - off := (uintptr(p) + i - u.frame.varp + size) / goarch.PtrSize - mask[i/goarch.PtrSize] = locals.ptrbit(off) - } - } - return - } - - // otherwise, not something the GC knows about. - // possibly read-only data, like malloc(0). - // must not have pointers - return -} - -// userArenaHeapBitsSetType is the equivalent of heapBitsSetType but for -// non-slice-backing-store Go values allocated in a user arena chunk. It -// sets up the heap bitmap for the value with type typ allocated at address ptr. -// base is the base address of the arena chunk. -func userArenaHeapBitsSetType(typ *_type, ptr unsafe.Pointer, s *mspan) { - base := s.base() - h := writeHeapBitsForAddr(uintptr(ptr)) - - // Our last allocation might have ended right at a noMorePtrs mark, - // which we would not have erased. We need to erase that mark here, - // because we're going to start adding new heap bitmap bits. - // We only need to clear one mark, because below we make sure to - // pad out the bits with zeroes and only write one noMorePtrs bit - // for each new object. - // (This is only necessary at noMorePtrs boundaries, as noMorePtrs - // marks within an object allocated with newAt will be erased by - // the normal writeHeapBitsForAddr mechanism.) - // - // Note that we skip this if this is the first allocation in the - // arena because there's definitely no previous noMorePtrs mark - // (in fact, we *must* do this, because we're going to try to back - // up a pointer to fix this up). - if uintptr(ptr)%(8*goarch.PtrSize*goarch.PtrSize) == 0 && uintptr(ptr) != base { - // Back up one pointer and rewrite that pointer. That will - // cause the writeHeapBits implementation to clear the - // noMorePtrs bit we need to clear. - r := heapBitsForAddr(uintptr(ptr)-goarch.PtrSize, goarch.PtrSize) - _, p := r.next() - b := uintptr(0) - if p == uintptr(ptr)-goarch.PtrSize { - b = 1 - } - h = writeHeapBitsForAddr(uintptr(ptr) - goarch.PtrSize) - h = h.write(b, 1) - } - - p := typ.GCData // start of 1-bit pointer mask (or GC program) - var gcProgBits uintptr - if typ.Kind_&kindGCProg != 0 { - // Expand gc program, using the object itself for storage. - gcProgBits = runGCProg(addb(p, 4), (*byte)(ptr)) - p = (*byte)(ptr) - } - nb := typ.PtrBytes / goarch.PtrSize - - for i := uintptr(0); i < nb; i += ptrBits { - k := nb - i - if k > ptrBits { - k = ptrBits - } - h = h.write(readUintptr(addb(p, i/8)), k) - } - // Note: we call pad here to ensure we emit explicit 0 bits - // for the pointerless tail of the object. This ensures that - // there's only a single noMorePtrs mark for the next object - // to clear. We don't need to do this to clear stale noMorePtrs - // markers from previous uses because arena chunk pointer bitmaps - // are always fully cleared when reused. - h = h.pad(typ.Size_ - typ.PtrBytes) - h.flush(uintptr(ptr), typ.Size_) - - if typ.Kind_&kindGCProg != 0 { - // Zero out temporary ptrmask buffer inside object. - memclrNoHeapPointers(ptr, (gcProgBits+7)/8) - } - - // Double-check that the bitmap was written out correctly. - // - // Derived from heapBitsSetType. - const doubleCheck = false - if doubleCheck { - size := typ.Size_ - x := uintptr(ptr) - h := heapBitsForAddr(x, size) - for i := uintptr(0); i < size; i += goarch.PtrSize { - // Compute the pointer bit we want at offset i. - want := false - off := i % typ.Size_ - if off < typ.PtrBytes { - j := off / goarch.PtrSize - want = *addb(typ.GCData, j/8)>>(j%8)&1 != 0 - } - if want { - var addr uintptr - h, addr = h.next() - if addr != x+i { - throw("userArenaHeapBitsSetType: pointer entry not correct") - } - } - } - if _, addr := h.next(); addr != 0 { - throw("userArenaHeapBitsSetType: extra pointer") - } - } -} - -// For goexperiment.AllocHeaders. -type typePointers struct { - addr uintptr -} - -// For goexperiment.AllocHeaders. -// -//go:nosplit -func (span *mspan) typePointersOf(addr, size uintptr) typePointers { - panic("not implemented") -} - -// For goexperiment.AllocHeaders. -// -//go:nosplit -func (span *mspan) typePointersOfUnchecked(addr uintptr) typePointers { - panic("not implemented") -} - -// For goexperiment.AllocHeaders. -// -//go:nosplit -func (tp typePointers) nextFast() (typePointers, uintptr) { - panic("not implemented") -} - -// For goexperiment.AllocHeaders. -// -//go:nosplit -func (tp typePointers) next(limit uintptr) (typePointers, uintptr) { - panic("not implemented") -} - -// For goexperiment.AllocHeaders. -// -//go:nosplit -func (tp typePointers) fastForward(n, limit uintptr) typePointers { - panic("not implemented") -} - -// For goexperiment.AllocHeaders, to pass TestIntendedInlining. -func (s *mspan) writeUserArenaHeapBits() { - panic("not implemented") -} - -// For goexperiment.AllocHeaders, to pass TestIntendedInlining. -func heapBitsSlice() { - panic("not implemented") -} diff --git a/contrib/go/_std_1.22/src/runtime/msize_noallocheaders.go b/contrib/go/_std_1.22/src/runtime/msize_noallocheaders.go deleted file mode 100644 index d89e0d6cbe89..000000000000 --- a/contrib/go/_std_1.22/src/runtime/msize_noallocheaders.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !goexperiment.allocheaders - -// Malloc small size classes. -// -// See malloc.go for overview. -// See also mksizeclasses.go for how we decide what size classes to use. - -package runtime - -// Returns size of the memory block that mallocgc will allocate if you ask for the size. -// -// The noscan argument is purely for compatibility with goexperiment.AllocHeaders. -func roundupsize(size uintptr, noscan bool) uintptr { - if size < _MaxSmallSize { - if size <= smallSizeMax-8 { - return uintptr(class_to_size[size_to_class8[divRoundUp(size, smallSizeDiv)]]) - } else { - return uintptr(class_to_size[size_to_class128[divRoundUp(size-smallSizeMax, largeSizeDiv)]]) - } - } - if size+_PageSize < size { - return size - } - return alignUp(size, _PageSize) -} diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_windows.go b/contrib/go/_std_1.22/src/runtime/netpoll_windows.go deleted file mode 100644 index 484a9e85b2d6..000000000000 --- a/contrib/go/_std_1.22/src/runtime/netpoll_windows.go +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "runtime/internal/atomic" - "unsafe" -) - -const _DWORD_MAX = 0xffffffff - -const _INVALID_HANDLE_VALUE = ^uintptr(0) - -// net_op must be the same as beginning of internal/poll.operation. -// Keep these in sync. -type net_op struct { - // used by windows - o overlapped - // used by netpoll - pd *pollDesc - mode int32 - errno int32 - qty uint32 -} - -type overlappedEntry struct { - key *pollDesc - op *net_op // In reality it's *overlapped, but we cast it to *net_op anyway. - internal uintptr - qty uint32 -} - -var ( - iocphandle uintptr = _INVALID_HANDLE_VALUE // completion port io handle - - netpollWakeSig atomic.Uint32 // used to avoid duplicate calls of netpollBreak -) - -func netpollinit() { - iocphandle = stdcall4(_CreateIoCompletionPort, _INVALID_HANDLE_VALUE, 0, 0, _DWORD_MAX) - if iocphandle == 0 { - println("runtime: CreateIoCompletionPort failed (errno=", getlasterror(), ")") - throw("runtime: netpollinit failed") - } -} - -func netpollIsPollDescriptor(fd uintptr) bool { - return fd == iocphandle -} - -func netpollopen(fd uintptr, pd *pollDesc) int32 { - // TODO(iant): Consider using taggedPointer on 64-bit systems. - if stdcall4(_CreateIoCompletionPort, fd, iocphandle, uintptr(unsafe.Pointer(pd)), 0) == 0 { - return int32(getlasterror()) - } - return 0 -} - -func netpollclose(fd uintptr) int32 { - // nothing to do - return 0 -} - -func netpollarm(pd *pollDesc, mode int) { - throw("runtime: unused") -} - -func netpollBreak() { - // Failing to cas indicates there is an in-flight wakeup, so we're done here. - if !netpollWakeSig.CompareAndSwap(0, 1) { - return - } - - if stdcall4(_PostQueuedCompletionStatus, iocphandle, 0, 0, 0) == 0 { - println("runtime: netpoll: PostQueuedCompletionStatus failed (errno=", getlasterror(), ")") - throw("runtime: netpoll: PostQueuedCompletionStatus failed") - } -} - -// netpoll checks for ready network connections. -// Returns list of goroutines that become runnable. -// delay < 0: blocks indefinitely -// delay == 0: does not block, just polls -// delay > 0: block for up to that many nanoseconds -func netpoll(delay int64) (gList, int32) { - var entries [64]overlappedEntry - var wait, qty, flags, n, i uint32 - var errno int32 - var op *net_op - var toRun gList - - mp := getg().m - - if iocphandle == _INVALID_HANDLE_VALUE { - return gList{}, 0 - } - if delay < 0 { - wait = _INFINITE - } else if delay == 0 { - wait = 0 - } else if delay < 1e6 { - wait = 1 - } else if delay < 1e15 { - wait = uint32(delay / 1e6) - } else { - // An arbitrary cap on how long to wait for a timer. - // 1e9 ms == ~11.5 days. - wait = 1e9 - } - - n = uint32(len(entries) / int(gomaxprocs)) - if n < 8 { - n = 8 - } - if delay != 0 { - mp.blocked = true - } - if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 { - mp.blocked = false - errno = int32(getlasterror()) - if errno == _WAIT_TIMEOUT { - return gList{}, 0 - } - println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno, ")") - throw("runtime: netpoll failed") - } - mp.blocked = false - delta := int32(0) - for i = 0; i < n; i++ { - op = entries[i].op - if op != nil && op.pd == entries[i].key { - errno = 0 - qty = 0 - if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 { - errno = int32(getlasterror()) - } - delta += handlecompletion(&toRun, op, errno, qty) - } else { - netpollWakeSig.Store(0) - if delay == 0 { - // Forward the notification to the - // blocked poller. - netpollBreak() - } - } - } - return toRun, delta -} - -func handlecompletion(toRun *gList, op *net_op, errno int32, qty uint32) int32 { - mode := op.mode - if mode != 'r' && mode != 'w' { - println("runtime: GetQueuedCompletionStatusEx returned invalid mode=", mode) - throw("runtime: netpoll failed") - } - op.errno = errno - op.qty = qty - return netpollready(toRun, op.pd, mode) -} diff --git a/contrib/go/_std_1.22/src/runtime/pagetrace_off.go b/contrib/go/_std_1.22/src/runtime/pagetrace_off.go deleted file mode 100644 index 10b44d40ced3..000000000000 --- a/contrib/go/_std_1.22/src/runtime/pagetrace_off.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !goexperiment.pagetrace - -package runtime - -//go:systemstack -func pageTraceAlloc(pp *p, now int64, base, npages uintptr) { -} - -//go:systemstack -func pageTraceFree(pp *p, now int64, base, npages uintptr) { -} - -//go:systemstack -func pageTraceScav(pp *p, now int64, base, npages uintptr) { -} - -type pageTraceBuf struct { -} - -func initPageTrace(env string) { -} - -func finishPageTrace() { -} diff --git a/contrib/go/_std_1.22/src/runtime/pagetrace_on.go b/contrib/go/_std_1.22/src/runtime/pagetrace_on.go deleted file mode 100644 index f82521caadd6..000000000000 --- a/contrib/go/_std_1.22/src/runtime/pagetrace_on.go +++ /dev/null @@ -1,358 +0,0 @@ -// Copyright 2022 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.pagetrace - -// Page tracer. -// -// This file contains an implementation of page trace instrumentation for tracking -// the way the Go runtime manages pages of memory. The trace may be enabled at program -// startup with the GODEBUG option pagetrace. -// -// Each page trace event is either 8 or 16 bytes wide. The first -// 8 bytes follow this format for non-sync events: -// -// [16 timestamp delta][35 base address][10 npages][1 isLarge][2 pageTraceEventType] -// -// If the "large" bit is set then the event is 16 bytes wide with the second 8 byte word -// containing the full npages value (the npages bitfield is 0). -// -// The base address's bottom pageShift bits are always zero hence why we can pack other -// data in there. We ignore the top 16 bits, assuming a 48 bit address space for the -// heap. -// -// The timestamp delta is computed from the difference between the current nanotime -// timestamp and the last sync event's timestamp. The bottom pageTraceTimeLostBits of -// this delta is removed and only the next pageTraceTimeDeltaBits are kept. -// -// A sync event is emitted at the beginning of each trace buffer and whenever the -// timestamp delta would not fit in an event. -// -// Sync events have the following structure: -// -// [61 timestamp or P ID][1 isPID][2 pageTraceSyncEvent] -// -// In essence, the "large" bit repurposed to indicate whether it's a timestamp or a P ID -// (these are typically uint32). Note that we only have 61 bits for the 64-bit timestamp, -// but like for the delta we drop the bottom pageTraceTimeLostBits here as well. - -package runtime - -import ( - "runtime/internal/sys" - "unsafe" -) - -// pageTraceAlloc records a page trace allocation event. -// pp may be nil. Call only if debug.pagetracefd != 0. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func pageTraceAlloc(pp *p, now int64, base, npages uintptr) { - if pageTrace.enabled { - if now == 0 { - now = nanotime() - } - pageTraceEmit(pp, now, base, npages, pageTraceAllocEvent) - } -} - -// pageTraceFree records a page trace free event. -// pp may be nil. Call only if debug.pagetracefd != 0. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func pageTraceFree(pp *p, now int64, base, npages uintptr) { - if pageTrace.enabled { - if now == 0 { - now = nanotime() - } - pageTraceEmit(pp, now, base, npages, pageTraceFreeEvent) - } -} - -// pageTraceScav records a page trace scavenge event. -// pp may be nil. Call only if debug.pagetracefd != 0. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func pageTraceScav(pp *p, now int64, base, npages uintptr) { - if pageTrace.enabled { - if now == 0 { - now = nanotime() - } - pageTraceEmit(pp, now, base, npages, pageTraceScavEvent) - } -} - -// pageTraceEventType is a page trace event type. -type pageTraceEventType uint8 - -const ( - pageTraceSyncEvent pageTraceEventType = iota // Timestamp emission. - pageTraceAllocEvent // Allocation of pages. - pageTraceFreeEvent // Freeing pages. - pageTraceScavEvent // Scavenging pages. -) - -// pageTraceEmit emits a page trace event. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func pageTraceEmit(pp *p, now int64, base, npages uintptr, typ pageTraceEventType) { - // Get a buffer. - var tbp *pageTraceBuf - pid := int32(-1) - if pp == nil { - // We have no P, so take the global buffer. - lock(&pageTrace.lock) - tbp = &pageTrace.buf - } else { - tbp = &pp.pageTraceBuf - pid = pp.id - } - - // Initialize the buffer if necessary. - tb := *tbp - if tb.buf == nil { - tb.buf = (*pageTraceEvents)(sysAlloc(pageTraceBufSize, &memstats.other_sys)) - tb = tb.writePid(pid) - } - - // Handle timestamp and emit a sync event if necessary. - if now < tb.timeBase { - now = tb.timeBase - } - if now-tb.timeBase >= pageTraceTimeMaxDelta { - tb.timeBase = now - tb = tb.writeSync(pid) - } - - // Emit the event. - tb = tb.writeEvent(pid, now, base, npages, typ) - - // Write back the buffer. - *tbp = tb - if pp == nil { - unlock(&pageTrace.lock) - } -} - -const ( - pageTraceBufSize = 32 << 10 - - // These constants describe the per-event timestamp delta encoding. - pageTraceTimeLostBits = 7 // How many bits of precision we lose in the delta. - pageTraceTimeDeltaBits = 16 // Size of the delta in bits. - pageTraceTimeMaxDelta = 1 << (pageTraceTimeLostBits + pageTraceTimeDeltaBits) -) - -// pageTraceEvents is the low-level buffer containing the trace data. -type pageTraceEvents struct { - _ sys.NotInHeap - events [pageTraceBufSize / 8]uint64 -} - -// pageTraceBuf is a wrapper around pageTraceEvents that knows how to write events -// to the buffer. It tracks state necessary to do so. -type pageTraceBuf struct { - buf *pageTraceEvents - len int // How many events have been written so far. - timeBase int64 // The current timestamp base from which deltas are produced. - finished bool // Whether this trace buf should no longer flush anything out. -} - -// writePid writes a P ID event indicating which P we're running on. -// -// Assumes there's always space in the buffer since this is only called at the -// beginning of a new buffer. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func (tb pageTraceBuf) writePid(pid int32) pageTraceBuf { - e := uint64(int64(pid))<<3 | 0b100 | uint64(pageTraceSyncEvent) - tb.buf.events[tb.len] = e - tb.len++ - return tb -} - -// writeSync writes a sync event, which is just a timestamp. Handles flushing. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func (tb pageTraceBuf) writeSync(pid int32) pageTraceBuf { - if tb.len+1 > len(tb.buf.events) { - // N.B. flush will writeSync again. - return tb.flush(pid, tb.timeBase) - } - e := ((uint64(tb.timeBase) >> pageTraceTimeLostBits) << 3) | uint64(pageTraceSyncEvent) - tb.buf.events[tb.len] = e - tb.len++ - return tb -} - -// writeEvent handles writing all non-sync and non-pid events. Handles flushing if necessary. -// -// pid indicates the P we're currently running on. Necessary in case we need to flush. -// now is the current nanotime timestamp. -// base is the base address of whatever group of pages this event is happening to. -// npages is the length of the group of pages this event is happening to. -// typ is the event that's happening to these pages. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func (tb pageTraceBuf) writeEvent(pid int32, now int64, base, npages uintptr, typ pageTraceEventType) pageTraceBuf { - large := 0 - np := npages - if npages >= 1024 { - large = 1 - np = 0 - } - if tb.len+1+large > len(tb.buf.events) { - tb = tb.flush(pid, now) - } - if base%pageSize != 0 { - throw("base address not page aligned") - } - e := uint64(base) - // The pageShift low-order bits are zero. - e |= uint64(typ) // 2 bits - e |= uint64(large) << 2 // 1 bit - e |= uint64(np) << 3 // 10 bits - // Write the timestamp delta in the upper pageTraceTimeDeltaBits. - e |= uint64((now-tb.timeBase)>>pageTraceTimeLostBits) << (64 - pageTraceTimeDeltaBits) - tb.buf.events[tb.len] = e - if large != 0 { - // npages doesn't fit in 10 bits, so write an additional word with that data. - tb.buf.events[tb.len+1] = uint64(npages) - } - tb.len += 1 + large - return tb -} - -// flush writes out the contents of the buffer to pageTrace.fd and resets the buffer. -// It then writes out a P ID event and the first sync event for the new buffer. -// -// Must run on the system stack as a crude way to prevent preemption. -// -//go:systemstack -func (tb pageTraceBuf) flush(pid int32, now int64) pageTraceBuf { - if !tb.finished { - lock(&pageTrace.fdLock) - writeFull(uintptr(pageTrace.fd), (*byte)(unsafe.Pointer(&tb.buf.events[0])), tb.len*8) - unlock(&pageTrace.fdLock) - } - tb.len = 0 - tb.timeBase = now - return tb.writePid(pid).writeSync(pid) -} - -var pageTrace struct { - // enabled indicates whether tracing is enabled. If true, fd >= 0. - // - // Safe to read without synchronization because it's only set once - // at program initialization. - enabled bool - - // buf is the page trace buffer used if there is no P. - // - // lock protects buf. - lock mutex - buf pageTraceBuf - - // fdLock protects writing to fd. - // - // fd is the file to write the page trace to. - fdLock mutex - fd int32 -} - -// initPageTrace initializes the page tracing infrastructure from GODEBUG. -// -// env must be the value of the GODEBUG environment variable. -func initPageTrace(env string) { - var value string - for env != "" { - elt, rest := env, "" - for i := 0; i < len(env); i++ { - if env[i] == ',' { - elt, rest = env[:i], env[i+1:] - break - } - } - env = rest - if hasPrefix(elt, "pagetrace=") { - value = elt[len("pagetrace="):] - break - } - } - pageTrace.fd = -1 - if canCreateFile && value != "" { - var tmp [4096]byte - if len(value) != 0 && len(value) < 4096 { - copy(tmp[:], value) - pageTrace.fd = create(&tmp[0], 0o664) - } - } - pageTrace.enabled = pageTrace.fd >= 0 -} - -// finishPageTrace flushes all P's trace buffers and disables page tracing. -func finishPageTrace() { - if !pageTrace.enabled { - return - } - // Grab worldsema as we're about to execute a ragged barrier. - semacquire(&worldsema) - systemstack(func() { - // Disable tracing. This isn't strictly necessary and it's best-effort. - pageTrace.enabled = false - - // Execute a ragged barrier, flushing each trace buffer. - forEachP(waitReasonPageTraceFlush, func(pp *p) { - if pp.pageTraceBuf.buf != nil { - pp.pageTraceBuf = pp.pageTraceBuf.flush(pp.id, nanotime()) - } - pp.pageTraceBuf.finished = true - }) - - // Write the global have-no-P buffer. - lock(&pageTrace.lock) - if pageTrace.buf.buf != nil { - pageTrace.buf = pageTrace.buf.flush(-1, nanotime()) - } - pageTrace.buf.finished = true - unlock(&pageTrace.lock) - - // Safely close the file as nothing else should be allowed to write to the fd. - lock(&pageTrace.fdLock) - closefd(pageTrace.fd) - pageTrace.fd = -1 - unlock(&pageTrace.fdLock) - }) - semrelease(&worldsema) -} - -// writeFull ensures that a complete write of bn bytes from b is made to fd. -func writeFull(fd uintptr, b *byte, bn int) { - for bn > 0 { - n := write(fd, unsafe.Pointer(b), int32(bn)) - if n == -_EINTR || n == -_EAGAIN { - continue - } - if n < 0 { - print("errno=", -n, "\n") - throw("writeBytes: bad write") - } - bn -= int(n) - b = addb(b, uintptr(n)) - } -} diff --git a/contrib/go/_std_1.22/src/runtime/time.go b/contrib/go/_std_1.22/src/runtime/time.go deleted file mode 100644 index 8ed1e45fc9d8..000000000000 --- a/contrib/go/_std_1.22/src/runtime/time.go +++ /dev/null @@ -1,1144 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Time-related runtime and pieces of package time. - -package runtime - -import ( - "internal/abi" - "runtime/internal/atomic" - "runtime/internal/sys" - "unsafe" -) - -// Package time knows the layout of this structure. -// If this struct changes, adjust ../time/sleep.go:/runtimeTimer. -type timer struct { - // If this timer is on a heap, which P's heap it is on. - // puintptr rather than *p to match uintptr in the versions - // of this struct defined in other packages. - pp puintptr - - // Timer wakes up at when, and then at when+period, ... (period > 0 only) - // each time calling f(arg, now) in the timer goroutine, so f must be - // a well-behaved function and not block. - // - // when must be positive on an active timer. - when int64 - period int64 - f func(any, uintptr) - arg any - seq uintptr - - // What to set the when field to in timerModifiedXX status. - nextwhen int64 - - // The status field holds one of the values below. - status atomic.Uint32 -} - -// Code outside this file has to be careful in using a timer value. -// -// The pp, status, and nextwhen fields may only be used by code in this file. -// -// Code that creates a new timer value can set the when, period, f, -// arg, and seq fields. -// A new timer value may be passed to addtimer (called by time.startTimer). -// After doing that no fields may be touched. -// -// An active timer (one that has been passed to addtimer) may be -// passed to deltimer (time.stopTimer), after which it is no longer an -// active timer. It is an inactive timer. -// In an inactive timer the period, f, arg, and seq fields may be modified, -// but not the when field. -// It's OK to just drop an inactive timer and let the GC collect it. -// It's not OK to pass an inactive timer to addtimer. -// Only newly allocated timer values may be passed to addtimer. -// -// An active timer may be passed to modtimer. No fields may be touched. -// It remains an active timer. -// -// An inactive timer may be passed to resettimer to turn into an -// active timer with an updated when field. -// It's OK to pass a newly allocated timer value to resettimer. -// -// Timer operations are addtimer, deltimer, modtimer, resettimer, -// cleantimers, adjusttimers, and runtimer. -// -// We don't permit calling addtimer/deltimer/modtimer/resettimer simultaneously, -// but adjusttimers and runtimer can be called at the same time as any of those. -// -// Active timers live in heaps attached to P, in the timers field. -// Inactive timers live there too temporarily, until they are removed. -// -// addtimer: -// timerNoStatus -> timerWaiting -// anything else -> panic: invalid value -// deltimer: -// timerWaiting -> timerModifying -> timerDeleted -// timerModifiedEarlier -> timerModifying -> timerDeleted -// timerModifiedLater -> timerModifying -> timerDeleted -// timerNoStatus -> do nothing -// timerDeleted -> do nothing -// timerRemoving -> do nothing -// timerRemoved -> do nothing -// timerRunning -> wait until status changes -// timerMoving -> wait until status changes -// timerModifying -> wait until status changes -// modtimer: -// timerWaiting -> timerModifying -> timerModifiedXX -// timerModifiedXX -> timerModifying -> timerModifiedYY -// timerNoStatus -> timerModifying -> timerWaiting -// timerRemoved -> timerModifying -> timerWaiting -// timerDeleted -> timerModifying -> timerModifiedXX -// timerRunning -> wait until status changes -// timerMoving -> wait until status changes -// timerRemoving -> wait until status changes -// timerModifying -> wait until status changes -// cleantimers (looks in P's timer heap): -// timerDeleted -> timerRemoving -> timerRemoved -// timerModifiedXX -> timerMoving -> timerWaiting -// adjusttimers (looks in P's timer heap): -// timerDeleted -> timerRemoving -> timerRemoved -// timerModifiedXX -> timerMoving -> timerWaiting -// runtimer (looks in P's timer heap): -// timerNoStatus -> panic: uninitialized timer -// timerWaiting -> timerWaiting or -// timerWaiting -> timerRunning -> timerNoStatus or -// timerWaiting -> timerRunning -> timerWaiting -// timerModifying -> wait until status changes -// timerModifiedXX -> timerMoving -> timerWaiting -// timerDeleted -> timerRemoving -> timerRemoved -// timerRunning -> panic: concurrent runtimer calls -// timerRemoved -> panic: inconsistent timer heap -// timerRemoving -> panic: inconsistent timer heap -// timerMoving -> panic: inconsistent timer heap - -// Values for the timer status field. -const ( - // Timer has no status set yet. - timerNoStatus = iota - - // Waiting for timer to fire. - // The timer is in some P's heap. - timerWaiting - - // Running the timer function. - // A timer will only have this status briefly. - timerRunning - - // The timer is deleted and should be removed. - // It should not be run, but it is still in some P's heap. - timerDeleted - - // The timer is being removed. - // The timer will only have this status briefly. - timerRemoving - - // The timer has been stopped. - // It is not in any P's heap. - timerRemoved - - // The timer is being modified. - // The timer will only have this status briefly. - timerModifying - - // The timer has been modified to an earlier time. - // The new when value is in the nextwhen field. - // The timer is in some P's heap, possibly in the wrong place. - timerModifiedEarlier - - // The timer has been modified to the same or a later time. - // The new when value is in the nextwhen field. - // The timer is in some P's heap, possibly in the wrong place. - timerModifiedLater - - // The timer has been modified and is being moved. - // The timer will only have this status briefly. - timerMoving -) - -// maxWhen is the maximum value for timer's when field. -const maxWhen = 1<<63 - 1 - -// verifyTimers can be set to true to add debugging checks that the -// timer heaps are valid. -const verifyTimers = false - -// Package time APIs. -// Godoc uses the comments in package time, not these. - -// time.now is implemented in assembly. - -// timeSleep puts the current goroutine to sleep for at least ns nanoseconds. -// -//go:linkname timeSleep time.Sleep -func timeSleep(ns int64) { - if ns <= 0 { - return - } - - gp := getg() - t := gp.timer - if t == nil { - t = new(timer) - gp.timer = t - } - t.f = goroutineReady - t.arg = gp - t.nextwhen = nanotime() + ns - if t.nextwhen < 0 { // check for overflow. - t.nextwhen = maxWhen - } - gopark(resetForSleep, unsafe.Pointer(t), waitReasonSleep, traceBlockSleep, 1) -} - -// resetForSleep is called after the goroutine is parked for timeSleep. -// We can't call resettimer in timeSleep itself because if this is a short -// sleep and there are many goroutines then the P can wind up running the -// timer function, goroutineReady, before the goroutine has been parked. -func resetForSleep(gp *g, ut unsafe.Pointer) bool { - t := (*timer)(ut) - resettimer(t, t.nextwhen) - return true -} - -// startTimer adds t to the timer heap. -// -//go:linkname startTimer time.startTimer -func startTimer(t *timer) { - if raceenabled { - racerelease(unsafe.Pointer(t)) - } - addtimer(t) -} - -// stopTimer stops a timer. -// It reports whether t was stopped before being run. -// -//go:linkname stopTimer time.stopTimer -func stopTimer(t *timer) bool { - return deltimer(t) -} - -// resetTimer resets an inactive timer, adding it to the heap. -// -// Reports whether the timer was modified before it was run. -// -//go:linkname resetTimer time.resetTimer -func resetTimer(t *timer, when int64) bool { - if raceenabled { - racerelease(unsafe.Pointer(t)) - } - return resettimer(t, when) -} - -// modTimer modifies an existing timer. -// -//go:linkname modTimer time.modTimer -func modTimer(t *timer, when, period int64, f func(any, uintptr), arg any, seq uintptr) { - modtimer(t, when, period, f, arg, seq) -} - -// Go runtime. - -// Ready the goroutine arg. -func goroutineReady(arg any, seq uintptr) { - goready(arg.(*g), 0) -} - -// Note: this changes some unsynchronized operations to synchronized operations -// addtimer adds a timer to the current P. -// This should only be called with a newly created timer. -// That avoids the risk of changing the when field of a timer in some P's heap, -// which could cause the heap to become unsorted. -func addtimer(t *timer) { - // when must be positive. A negative value will cause runtimer to - // overflow during its delta calculation and never expire other runtime - // timers. Zero will cause checkTimers to fail to notice the timer. - if t.when <= 0 { - throw("timer when must be positive") - } - if t.period < 0 { - throw("timer period must be non-negative") - } - if t.status.Load() != timerNoStatus { - throw("addtimer called with initialized timer") - } - t.status.Store(timerWaiting) - - when := t.when - - // Disable preemption while using pp to avoid changing another P's heap. - mp := acquirem() - - pp := getg().m.p.ptr() - lock(&pp.timersLock) - cleantimers(pp) - doaddtimer(pp, t) - unlock(&pp.timersLock) - - wakeNetPoller(when) - - releasem(mp) -} - -// doaddtimer adds t to the current P's heap. -// The caller must have locked the timers for pp. -func doaddtimer(pp *p, t *timer) { - // Timers rely on the network poller, so make sure the poller - // has started. - if netpollInited.Load() == 0 { - netpollGenericInit() - } - - if t.pp != 0 { - throw("doaddtimer: P already set in timer") - } - t.pp.set(pp) - i := len(pp.timers) - pp.timers = append(pp.timers, t) - siftupTimer(pp.timers, i) - if t == pp.timers[0] { - pp.timer0When.Store(t.when) - } - pp.numTimers.Add(1) -} - -// deltimer deletes the timer t. It may be on some other P, so we can't -// actually remove it from the timers heap. We can only mark it as deleted. -// It will be removed in due course by the P whose heap it is on. -// Reports whether the timer was removed before it was run. -func deltimer(t *timer) bool { - for { - switch s := t.status.Load(); s { - case timerWaiting, timerModifiedLater: - // Prevent preemption while the timer is in timerModifying. - // This could lead to a self-deadlock. See #38070. - mp := acquirem() - if t.status.CompareAndSwap(s, timerModifying) { - // Must fetch t.pp before changing status, - // as cleantimers in another goroutine - // can clear t.pp of a timerDeleted timer. - tpp := t.pp.ptr() - if !t.status.CompareAndSwap(timerModifying, timerDeleted) { - badTimer() - } - releasem(mp) - tpp.deletedTimers.Add(1) - // Timer was not yet run. - return true - } else { - releasem(mp) - } - case timerModifiedEarlier: - // Prevent preemption while the timer is in timerModifying. - // This could lead to a self-deadlock. See #38070. - mp := acquirem() - if t.status.CompareAndSwap(s, timerModifying) { - // Must fetch t.pp before setting status - // to timerDeleted. - tpp := t.pp.ptr() - if !t.status.CompareAndSwap(timerModifying, timerDeleted) { - badTimer() - } - releasem(mp) - tpp.deletedTimers.Add(1) - // Timer was not yet run. - return true - } else { - releasem(mp) - } - case timerDeleted, timerRemoving, timerRemoved: - // Timer was already run. - return false - case timerRunning, timerMoving: - // The timer is being run or moved, by a different P. - // Wait for it to complete. - osyield() - case timerNoStatus: - // Removing timer that was never added or - // has already been run. Also see issue 21874. - return false - case timerModifying: - // Simultaneous calls to deltimer and modtimer. - // Wait for the other call to complete. - osyield() - default: - badTimer() - } - } -} - -// dodeltimer removes timer i from the current P's heap. -// We are locked on the P when this is called. -// It returns the smallest changed index in pp.timers. -// The caller must have locked the timers for pp. -func dodeltimer(pp *p, i int) int { - if t := pp.timers[i]; t.pp.ptr() != pp { - throw("dodeltimer: wrong P") - } else { - t.pp = 0 - } - last := len(pp.timers) - 1 - if i != last { - pp.timers[i] = pp.timers[last] - } - pp.timers[last] = nil - pp.timers = pp.timers[:last] - smallestChanged := i - if i != last { - // Moving to i may have moved the last timer to a new parent, - // so sift up to preserve the heap guarantee. - smallestChanged = siftupTimer(pp.timers, i) - siftdownTimer(pp.timers, i) - } - if i == 0 { - updateTimer0When(pp) - } - n := pp.numTimers.Add(-1) - if n == 0 { - // If there are no timers, then clearly none are modified. - pp.timerModifiedEarliest.Store(0) - } - return smallestChanged -} - -// dodeltimer0 removes timer 0 from the current P's heap. -// We are locked on the P when this is called. -// It reports whether it saw no problems due to races. -// The caller must have locked the timers for pp. -func dodeltimer0(pp *p) { - if t := pp.timers[0]; t.pp.ptr() != pp { - throw("dodeltimer0: wrong P") - } else { - t.pp = 0 - } - last := len(pp.timers) - 1 - if last > 0 { - pp.timers[0] = pp.timers[last] - } - pp.timers[last] = nil - pp.timers = pp.timers[:last] - if last > 0 { - siftdownTimer(pp.timers, 0) - } - updateTimer0When(pp) - n := pp.numTimers.Add(-1) - if n == 0 { - // If there are no timers, then clearly none are modified. - pp.timerModifiedEarliest.Store(0) - } -} - -// modtimer modifies an existing timer. -// This is called by the netpoll code or time.Ticker.Reset or time.Timer.Reset. -// Reports whether the timer was modified before it was run. -func modtimer(t *timer, when, period int64, f func(any, uintptr), arg any, seq uintptr) bool { - if when <= 0 { - throw("timer when must be positive") - } - if period < 0 { - throw("timer period must be non-negative") - } - - status := uint32(timerNoStatus) - wasRemoved := false - var pending bool - var mp *m -loop: - for { - switch status = t.status.Load(); status { - case timerWaiting, timerModifiedEarlier, timerModifiedLater: - // Prevent preemption while the timer is in timerModifying. - // This could lead to a self-deadlock. See #38070. - mp = acquirem() - if t.status.CompareAndSwap(status, timerModifying) { - pending = true // timer not yet run - break loop - } - releasem(mp) - case timerNoStatus, timerRemoved: - // Prevent preemption while the timer is in timerModifying. - // This could lead to a self-deadlock. See #38070. - mp = acquirem() - - // Timer was already run and t is no longer in a heap. - // Act like addtimer. - if t.status.CompareAndSwap(status, timerModifying) { - wasRemoved = true - pending = false // timer already run or stopped - break loop - } - releasem(mp) - case timerDeleted: - // Prevent preemption while the timer is in timerModifying. - // This could lead to a self-deadlock. See #38070. - mp = acquirem() - if t.status.CompareAndSwap(status, timerModifying) { - t.pp.ptr().deletedTimers.Add(-1) - pending = false // timer already stopped - break loop - } - releasem(mp) - case timerRunning, timerRemoving, timerMoving: - // The timer is being run or moved, by a different P. - // Wait for it to complete. - osyield() - case timerModifying: - // Multiple simultaneous calls to modtimer. - // Wait for the other call to complete. - osyield() - default: - badTimer() - } - } - - t.period = period - t.f = f - t.arg = arg - t.seq = seq - - if wasRemoved { - t.when = when - pp := getg().m.p.ptr() - lock(&pp.timersLock) - doaddtimer(pp, t) - unlock(&pp.timersLock) - if !t.status.CompareAndSwap(timerModifying, timerWaiting) { - badTimer() - } - releasem(mp) - wakeNetPoller(when) - } else { - // The timer is in some other P's heap, so we can't change - // the when field. If we did, the other P's heap would - // be out of order. So we put the new when value in the - // nextwhen field, and let the other P set the when field - // when it is prepared to resort the heap. - t.nextwhen = when - - newStatus := uint32(timerModifiedLater) - if when < t.when { - newStatus = timerModifiedEarlier - } - - tpp := t.pp.ptr() - - if newStatus == timerModifiedEarlier { - updateTimerModifiedEarliest(tpp, when) - } - - // Set the new status of the timer. - if !t.status.CompareAndSwap(timerModifying, newStatus) { - badTimer() - } - releasem(mp) - - // If the new status is earlier, wake up the poller. - if newStatus == timerModifiedEarlier { - wakeNetPoller(when) - } - } - - return pending -} - -// resettimer resets the time when a timer should fire. -// If used for an inactive timer, the timer will become active. -// This should be called instead of addtimer if the timer value has been, -// or may have been, used previously. -// Reports whether the timer was modified before it was run. -func resettimer(t *timer, when int64) bool { - return modtimer(t, when, t.period, t.f, t.arg, t.seq) -} - -// cleantimers cleans up the head of the timer queue. This speeds up -// programs that create and delete timers; leaving them in the heap -// slows down addtimer. Reports whether no timer problems were found. -// The caller must have locked the timers for pp. -func cleantimers(pp *p) { - gp := getg() - for { - if len(pp.timers) == 0 { - return - } - - // This loop can theoretically run for a while, and because - // it is holding timersLock it cannot be preempted. - // If someone is trying to preempt us, just return. - // We can clean the timers later. - if gp.preemptStop { - return - } - - t := pp.timers[0] - if t.pp.ptr() != pp { - throw("cleantimers: bad p") - } - switch s := t.status.Load(); s { - case timerDeleted: - if !t.status.CompareAndSwap(s, timerRemoving) { - continue - } - dodeltimer0(pp) - if !t.status.CompareAndSwap(timerRemoving, timerRemoved) { - badTimer() - } - pp.deletedTimers.Add(-1) - case timerModifiedEarlier, timerModifiedLater: - if !t.status.CompareAndSwap(s, timerMoving) { - continue - } - // Now we can change the when field. - t.when = t.nextwhen - // Move t to the right position. - dodeltimer0(pp) - doaddtimer(pp, t) - if !t.status.CompareAndSwap(timerMoving, timerWaiting) { - badTimer() - } - default: - // Head of timers does not need adjustment. - return - } - } -} - -// moveTimers moves a slice of timers to pp. The slice has been taken -// from a different P. -// This is currently called when the world is stopped, but the caller -// is expected to have locked the timers for pp. -func moveTimers(pp *p, timers []*timer) { - for _, t := range timers { - loop: - for { - switch s := t.status.Load(); s { - case timerWaiting: - if !t.status.CompareAndSwap(s, timerMoving) { - continue - } - t.pp = 0 - doaddtimer(pp, t) - if !t.status.CompareAndSwap(timerMoving, timerWaiting) { - badTimer() - } - break loop - case timerModifiedEarlier, timerModifiedLater: - if !t.status.CompareAndSwap(s, timerMoving) { - continue - } - t.when = t.nextwhen - t.pp = 0 - doaddtimer(pp, t) - if !t.status.CompareAndSwap(timerMoving, timerWaiting) { - badTimer() - } - break loop - case timerDeleted: - if !t.status.CompareAndSwap(s, timerRemoved) { - continue - } - t.pp = 0 - // We no longer need this timer in the heap. - break loop - case timerModifying: - // Loop until the modification is complete. - osyield() - case timerNoStatus, timerRemoved: - // We should not see these status values in a timers heap. - badTimer() - case timerRunning, timerRemoving, timerMoving: - // Some other P thinks it owns this timer, - // which should not happen. - badTimer() - default: - badTimer() - } - } - } -} - -// adjusttimers looks through the timers in the current P's heap for -// any timers that have been modified to run earlier, and puts them in -// the correct place in the heap. While looking for those timers, -// it also moves timers that have been modified to run later, -// and removes deleted timers. The caller must have locked the timers for pp. -func adjusttimers(pp *p, now int64) { - // If we haven't yet reached the time of the first timerModifiedEarlier - // timer, don't do anything. This speeds up programs that adjust - // a lot of timers back and forth if the timers rarely expire. - // We'll postpone looking through all the adjusted timers until - // one would actually expire. - first := pp.timerModifiedEarliest.Load() - if first == 0 || first > now { - if verifyTimers { - verifyTimerHeap(pp) - } - return - } - - // We are going to clear all timerModifiedEarlier timers. - pp.timerModifiedEarliest.Store(0) - - var moved []*timer - for i := 0; i < len(pp.timers); i++ { - t := pp.timers[i] - if t.pp.ptr() != pp { - throw("adjusttimers: bad p") - } - switch s := t.status.Load(); s { - case timerDeleted: - if t.status.CompareAndSwap(s, timerRemoving) { - changed := dodeltimer(pp, i) - if !t.status.CompareAndSwap(timerRemoving, timerRemoved) { - badTimer() - } - pp.deletedTimers.Add(-1) - // Go back to the earliest changed heap entry. - // "- 1" because the loop will add 1. - i = changed - 1 - } - case timerModifiedEarlier, timerModifiedLater: - if t.status.CompareAndSwap(s, timerMoving) { - // Now we can change the when field. - t.when = t.nextwhen - // Take t off the heap, and hold onto it. - // We don't add it back yet because the - // heap manipulation could cause our - // loop to skip some other timer. - changed := dodeltimer(pp, i) - moved = append(moved, t) - // Go back to the earliest changed heap entry. - // "- 1" because the loop will add 1. - i = changed - 1 - } - case timerNoStatus, timerRunning, timerRemoving, timerRemoved, timerMoving: - badTimer() - case timerWaiting: - // OK, nothing to do. - case timerModifying: - // Check again after modification is complete. - osyield() - i-- - default: - badTimer() - } - } - - if len(moved) > 0 { - addAdjustedTimers(pp, moved) - } - - if verifyTimers { - verifyTimerHeap(pp) - } -} - -// addAdjustedTimers adds any timers we adjusted in adjusttimers -// back to the timer heap. -func addAdjustedTimers(pp *p, moved []*timer) { - for _, t := range moved { - doaddtimer(pp, t) - if !t.status.CompareAndSwap(timerMoving, timerWaiting) { - badTimer() - } - } -} - -// nobarrierWakeTime looks at P's timers and returns the time when we -// should wake up the netpoller. It returns 0 if there are no timers. -// This function is invoked when dropping a P, and must run without -// any write barriers. -// -//go:nowritebarrierrec -func nobarrierWakeTime(pp *p) int64 { - next := pp.timer0When.Load() - nextAdj := pp.timerModifiedEarliest.Load() - if next == 0 || (nextAdj != 0 && nextAdj < next) { - next = nextAdj - } - return next -} - -// runtimer examines the first timer in timers. If it is ready based on now, -// it runs the timer and removes or updates it. -// Returns 0 if it ran a timer, -1 if there are no more timers, or the time -// when the first timer should run. -// The caller must have locked the timers for pp. -// If a timer is run, this will temporarily unlock the timers. -// -//go:systemstack -func runtimer(pp *p, now int64) int64 { - for { - t := pp.timers[0] - if t.pp.ptr() != pp { - throw("runtimer: bad p") - } - switch s := t.status.Load(); s { - case timerWaiting: - if t.when > now { - // Not ready to run. - return t.when - } - - if !t.status.CompareAndSwap(s, timerRunning) { - continue - } - // Note that runOneTimer may temporarily unlock - // pp.timersLock. - runOneTimer(pp, t, now) - return 0 - - case timerDeleted: - if !t.status.CompareAndSwap(s, timerRemoving) { - continue - } - dodeltimer0(pp) - if !t.status.CompareAndSwap(timerRemoving, timerRemoved) { - badTimer() - } - pp.deletedTimers.Add(-1) - if len(pp.timers) == 0 { - return -1 - } - - case timerModifiedEarlier, timerModifiedLater: - if !t.status.CompareAndSwap(s, timerMoving) { - continue - } - t.when = t.nextwhen - dodeltimer0(pp) - doaddtimer(pp, t) - if !t.status.CompareAndSwap(timerMoving, timerWaiting) { - badTimer() - } - - case timerModifying: - // Wait for modification to complete. - osyield() - - case timerNoStatus, timerRemoved: - // Should not see a new or inactive timer on the heap. - badTimer() - case timerRunning, timerRemoving, timerMoving: - // These should only be set when timers are locked, - // and we didn't do it. - badTimer() - default: - badTimer() - } - } -} - -// runOneTimer runs a single timer. -// The caller must have locked the timers for pp. -// This will temporarily unlock the timers while running the timer function. -// -//go:systemstack -func runOneTimer(pp *p, t *timer, now int64) { - if raceenabled { - ppcur := getg().m.p.ptr() - if ppcur.timerRaceCtx == 0 { - ppcur.timerRaceCtx = racegostart(abi.FuncPCABIInternal(runtimer) + sys.PCQuantum) - } - raceacquirectx(ppcur.timerRaceCtx, unsafe.Pointer(t)) - } - - f := t.f - arg := t.arg - seq := t.seq - - if t.period > 0 { - // Leave in heap but adjust next time to fire. - delta := t.when - now - t.when += t.period * (1 + -delta/t.period) - if t.when < 0 { // check for overflow. - t.when = maxWhen - } - siftdownTimer(pp.timers, 0) - if !t.status.CompareAndSwap(timerRunning, timerWaiting) { - badTimer() - } - updateTimer0When(pp) - } else { - // Remove from heap. - dodeltimer0(pp) - if !t.status.CompareAndSwap(timerRunning, timerNoStatus) { - badTimer() - } - } - - if raceenabled { - // Temporarily use the current P's racectx for g0. - gp := getg() - if gp.racectx != 0 { - throw("runOneTimer: unexpected racectx") - } - gp.racectx = gp.m.p.ptr().timerRaceCtx - } - - unlock(&pp.timersLock) - - f(arg, seq) - - lock(&pp.timersLock) - - if raceenabled { - gp := getg() - gp.racectx = 0 - } -} - -// clearDeletedTimers removes all deleted timers from the P's timer heap. -// This is used to avoid clogging up the heap if the program -// starts a lot of long-running timers and then stops them. -// For example, this can happen via context.WithTimeout. -// -// This is the only function that walks through the entire timer heap, -// other than moveTimers which only runs when the world is stopped. -// -// The caller must have locked the timers for pp. -func clearDeletedTimers(pp *p) { - // We are going to clear all timerModifiedEarlier timers. - // Do this now in case new ones show up while we are looping. - pp.timerModifiedEarliest.Store(0) - - cdel := int32(0) - to := 0 - changedHeap := false - timers := pp.timers -nextTimer: - for _, t := range timers { - for { - switch s := t.status.Load(); s { - case timerWaiting: - if changedHeap { - timers[to] = t - siftupTimer(timers, to) - } - to++ - continue nextTimer - case timerModifiedEarlier, timerModifiedLater: - if t.status.CompareAndSwap(s, timerMoving) { - t.when = t.nextwhen - timers[to] = t - siftupTimer(timers, to) - to++ - changedHeap = true - if !t.status.CompareAndSwap(timerMoving, timerWaiting) { - badTimer() - } - continue nextTimer - } - case timerDeleted: - if t.status.CompareAndSwap(s, timerRemoving) { - t.pp = 0 - cdel++ - if !t.status.CompareAndSwap(timerRemoving, timerRemoved) { - badTimer() - } - changedHeap = true - continue nextTimer - } - case timerModifying: - // Loop until modification complete. - osyield() - case timerNoStatus, timerRemoved: - // We should not see these status values in a timer heap. - badTimer() - case timerRunning, timerRemoving, timerMoving: - // Some other P thinks it owns this timer, - // which should not happen. - badTimer() - default: - badTimer() - } - } - } - - // Set remaining slots in timers slice to nil, - // so that the timer values can be garbage collected. - for i := to; i < len(timers); i++ { - timers[i] = nil - } - - pp.deletedTimers.Add(-cdel) - pp.numTimers.Add(-cdel) - - timers = timers[:to] - pp.timers = timers - updateTimer0When(pp) - - if verifyTimers { - verifyTimerHeap(pp) - } -} - -// verifyTimerHeap verifies that the timer heap is in a valid state. -// This is only for debugging, and is only called if verifyTimers is true. -// The caller must have locked the timers. -func verifyTimerHeap(pp *p) { - for i, t := range pp.timers { - if i == 0 { - // First timer has no parent. - continue - } - - // The heap is 4-ary. See siftupTimer and siftdownTimer. - p := (i - 1) / 4 - if t.when < pp.timers[p].when { - print("bad timer heap at ", i, ": ", p, ": ", pp.timers[p].when, ", ", i, ": ", t.when, "\n") - throw("bad timer heap") - } - } - if numTimers := int(pp.numTimers.Load()); len(pp.timers) != numTimers { - println("timer heap len", len(pp.timers), "!= numTimers", numTimers) - throw("bad timer heap len") - } -} - -// updateTimer0When sets the P's timer0When field. -// The caller must have locked the timers for pp. -func updateTimer0When(pp *p) { - if len(pp.timers) == 0 { - pp.timer0When.Store(0) - } else { - pp.timer0When.Store(pp.timers[0].when) - } -} - -// updateTimerModifiedEarliest updates the recorded nextwhen field of the -// earlier timerModifiedEarier value. -// The timers for pp will not be locked. -func updateTimerModifiedEarliest(pp *p, nextwhen int64) { - for { - old := pp.timerModifiedEarliest.Load() - if old != 0 && old < nextwhen { - return - } - - if pp.timerModifiedEarliest.CompareAndSwap(old, nextwhen) { - return - } - } -} - -// timeSleepUntil returns the time when the next timer should fire. Returns -// maxWhen if there are no timers. -// This is only called by sysmon and checkdead. -func timeSleepUntil() int64 { - next := int64(maxWhen) - - // Prevent allp slice changes. This is like retake. - lock(&allpLock) - for _, pp := range allp { - if pp == nil { - // This can happen if procresize has grown - // allp but not yet created new Ps. - continue - } - - w := pp.timer0When.Load() - if w != 0 && w < next { - next = w - } - - w = pp.timerModifiedEarliest.Load() - if w != 0 && w < next { - next = w - } - } - unlock(&allpLock) - - return next -} - -// Heap maintenance algorithms. -// These algorithms check for slice index errors manually. -// Slice index error can happen if the program is using racy -// access to timers. We don't want to panic here, because -// it will cause the program to crash with a mysterious -// "panic holding locks" message. Instead, we panic while not -// holding a lock. - -// siftupTimer puts the timer at position i in the right place -// in the heap by moving it up toward the top of the heap. -// It returns the smallest changed index. -func siftupTimer(t []*timer, i int) int { - if i >= len(t) { - badTimer() - } - when := t[i].when - if when <= 0 { - badTimer() - } - tmp := t[i] - for i > 0 { - p := (i - 1) / 4 // parent - if when >= t[p].when { - break - } - t[i] = t[p] - i = p - } - if tmp != t[i] { - t[i] = tmp - } - return i -} - -// siftdownTimer puts the timer at position i in the right place -// in the heap by moving it down toward the bottom of the heap. -func siftdownTimer(t []*timer, i int) { - n := len(t) - if i >= n { - badTimer() - } - when := t[i].when - if when <= 0 { - badTimer() - } - tmp := t[i] - for { - c := i*4 + 1 // left child - c3 := c + 2 // mid child - if c >= n { - break - } - w := t[c].when - if c+1 < n && t[c+1].when < w { - w = t[c+1].when - c++ - } - if c3 < n { - w3 := t[c3].when - if c3+1 < n && t[c3+1].when < w3 { - w3 = t[c3+1].when - c3++ - } - if w3 < w { - w = w3 - c = c3 - } - } - if w >= when { - break - } - t[i] = t[c] - i = c - } - if tmp != t[i] { - t[i] = tmp - } -} - -// badTimer is called if the timer data structures have been corrupted, -// presumably due to racy use by the program. We panic here rather than -// panicking due to invalid slice access while holding locks. -// See issue #25686. -func badTimer() { - throw("timer data corruption") -} diff --git a/contrib/go/_std_1.22/src/runtime/time_nofake.go b/contrib/go/_std_1.22/src/runtime/time_nofake.go deleted file mode 100644 index 70a2102b22e8..000000000000 --- a/contrib/go/_std_1.22/src/runtime/time_nofake.go +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !faketime - -package runtime - -import "unsafe" - -// faketime is the simulated time in nanoseconds since 1970 for the -// playground. -// -// Zero means not to use faketime. -var faketime int64 - -//go:nosplit -func nanotime() int64 { - return nanotime1() -} - -var overrideWrite func(fd uintptr, p unsafe.Pointer, n int32) int32 - -// write must be nosplit on Windows (see write1) -// -//go:nosplit -func write(fd uintptr, p unsafe.Pointer, n int32) int32 { - if overrideWrite != nil { - return overrideWrite(fd, noescape(p), n) - } - return write1(fd, p, n) -} diff --git a/contrib/go/_std_1.22/src/runtime/trace.go b/contrib/go/_std_1.22/src/runtime/trace.go deleted file mode 100644 index a9cfa22337e1..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace.go +++ /dev/null @@ -1,1925 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !goexperiment.exectracer2 - -// Go execution tracer. -// The tracer captures a wide range of execution events like goroutine -// creation/blocking/unblocking, syscall enter/exit/block, GC-related events, -// changes of heap size, processor start/stop, etc and writes them to a buffer -// in a compact form. A precise nanosecond-precision timestamp and a stack -// trace is captured for most events. -// See https://golang.org/s/go15trace for more info. - -package runtime - -import ( - "internal/abi" - "internal/goarch" - "internal/goos" - "runtime/internal/atomic" - "runtime/internal/sys" - "unsafe" -) - -// Event types in the trace, args are given in square brackets. -const ( - traceEvNone = 0 // unused - traceEvBatch = 1 // start of per-P batch of events [pid, timestamp] - traceEvFrequency = 2 // contains tracer timer frequency [frequency (ticks per second)] - traceEvStack = 3 // stack [stack id, number of PCs, array of {PC, func string ID, file string ID, line}] - traceEvGomaxprocs = 4 // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id] - traceEvProcStart = 5 // start of P [timestamp, thread id] - traceEvProcStop = 6 // stop of P [timestamp] - traceEvGCStart = 7 // GC start [timestamp, seq, stack id] - traceEvGCDone = 8 // GC done [timestamp] - traceEvSTWStart = 9 // STW start [timestamp, kind] - traceEvSTWDone = 10 // STW done [timestamp] - traceEvGCSweepStart = 11 // GC sweep start [timestamp, stack id] - traceEvGCSweepDone = 12 // GC sweep done [timestamp, swept, reclaimed] - traceEvGoCreate = 13 // goroutine creation [timestamp, new goroutine id, new stack id, stack id] - traceEvGoStart = 14 // goroutine starts running [timestamp, goroutine id, seq] - traceEvGoEnd = 15 // goroutine ends [timestamp] - traceEvGoStop = 16 // goroutine stops (like in select{}) [timestamp, stack] - traceEvGoSched = 17 // goroutine calls Gosched [timestamp, stack] - traceEvGoPreempt = 18 // goroutine is preempted [timestamp, stack] - traceEvGoSleep = 19 // goroutine calls Sleep [timestamp, stack] - traceEvGoBlock = 20 // goroutine blocks [timestamp, stack] - traceEvGoUnblock = 21 // goroutine is unblocked [timestamp, goroutine id, seq, stack] - traceEvGoBlockSend = 22 // goroutine blocks on chan send [timestamp, stack] - traceEvGoBlockRecv = 23 // goroutine blocks on chan recv [timestamp, stack] - traceEvGoBlockSelect = 24 // goroutine blocks on select [timestamp, stack] - traceEvGoBlockSync = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack] - traceEvGoBlockCond = 26 // goroutine blocks on Cond [timestamp, stack] - traceEvGoBlockNet = 27 // goroutine blocks on network [timestamp, stack] - traceEvGoSysCall = 28 // syscall enter [timestamp, stack] - traceEvGoSysExit = 29 // syscall exit [timestamp, goroutine id, seq, real timestamp] - traceEvGoSysBlock = 30 // syscall blocks [timestamp] - traceEvGoWaiting = 31 // denotes that goroutine is blocked when tracing starts [timestamp, goroutine id] - traceEvGoInSyscall = 32 // denotes that goroutine is in syscall when tracing starts [timestamp, goroutine id] - traceEvHeapAlloc = 33 // gcController.heapLive change [timestamp, heap_alloc] - traceEvHeapGoal = 34 // gcController.heapGoal() (formerly next_gc) change [timestamp, heap goal in bytes] - traceEvTimerGoroutine = 35 // not currently used; previously denoted timer goroutine [timer goroutine id] - traceEvFutileWakeup = 36 // not currently used; denotes that the previous wakeup of this goroutine was futile [timestamp] - traceEvString = 37 // string dictionary entry [ID, length, string] - traceEvGoStartLocal = 38 // goroutine starts running on the same P as the last event [timestamp, goroutine id] - traceEvGoUnblockLocal = 39 // goroutine is unblocked on the same P as the last event [timestamp, goroutine id, stack] - traceEvGoSysExitLocal = 40 // syscall exit on the same P as the last event [timestamp, goroutine id, real timestamp] - traceEvGoStartLabel = 41 // goroutine starts running with label [timestamp, goroutine id, seq, label string id] - traceEvGoBlockGC = 42 // goroutine blocks on GC assist [timestamp, stack] - traceEvGCMarkAssistStart = 43 // GC mark assist start [timestamp, stack] - traceEvGCMarkAssistDone = 44 // GC mark assist done [timestamp] - traceEvUserTaskCreate = 45 // trace.NewTask [timestamp, internal task id, internal parent task id, name string, stack] - traceEvUserTaskEnd = 46 // end of a task [timestamp, internal task id, stack] - traceEvUserRegion = 47 // trace.WithRegion [timestamp, internal task id, mode(0:start, 1:end), name string, stack] - traceEvUserLog = 48 // trace.Log [timestamp, internal task id, key string id, stack, value string] - traceEvCPUSample = 49 // CPU profiling sample [timestamp, real timestamp, real P id (-1 when absent), goroutine id, stack] - traceEvCount = 50 - // Byte is used but only 6 bits are available for event type. - // The remaining 2 bits are used to specify the number of arguments. - // That means, the max event type value is 63. -) - -// traceBlockReason is an enumeration of reasons a goroutine might block. -// This is the interface the rest of the runtime uses to tell the -// tracer why a goroutine blocked. The tracer then propagates this information -// into the trace however it sees fit. -// -// Note that traceBlockReasons should not be compared, since reasons that are -// distinct by name may *not* be distinct by value. -type traceBlockReason uint8 - -// For maximal efficiency, just map the trace block reason directly to a trace -// event. -const ( - traceBlockGeneric traceBlockReason = traceEvGoBlock - traceBlockForever = traceEvGoStop - traceBlockNet = traceEvGoBlockNet - traceBlockSelect = traceEvGoBlockSelect - traceBlockCondWait = traceEvGoBlockCond - traceBlockSync = traceEvGoBlockSync - traceBlockChanSend = traceEvGoBlockSend - traceBlockChanRecv = traceEvGoBlockRecv - traceBlockGCMarkAssist = traceEvGoBlockGC - traceBlockGCSweep = traceEvGoBlock - traceBlockSystemGoroutine = traceEvGoBlock - traceBlockPreempted = traceEvGoBlock - traceBlockDebugCall = traceEvGoBlock - traceBlockUntilGCEnds = traceEvGoBlock - traceBlockSleep = traceEvGoSleep -) - -const ( - // Timestamps in trace are cputicks/traceTickDiv. - // This makes absolute values of timestamp diffs smaller, - // and so they are encoded in less number of bytes. - // 64 on x86 is somewhat arbitrary (one tick is ~20ns on a 3GHz machine). - // The suggested increment frequency for PowerPC's time base register is - // 512 MHz according to Power ISA v2.07 section 6.2, so we use 16 on ppc64 - // and ppc64le. - traceTimeDiv = 16 + 48*(goarch.Is386|goarch.IsAmd64) - // Maximum number of PCs in a single stack trace. - // Since events contain only stack id rather than whole stack trace, - // we can allow quite large values here. - traceStackSize = 128 - // Identifier of a fake P that is used when we trace without a real P. - traceGlobProc = -1 - // Maximum number of bytes to encode uint64 in base-128. - traceBytesPerNumber = 10 - // Shift of the number of arguments in the first event byte. - traceArgCountShift = 6 -) - -// trace is global tracing context. -var trace struct { - // trace.lock must only be acquired on the system stack where - // stack splits cannot happen while it is held. - lock mutex // protects the following members - enabled bool // when set runtime traces events - shutdown bool // set when we are waiting for trace reader to finish after setting enabled to false - headerWritten bool // whether ReadTrace has emitted trace header - footerWritten bool // whether ReadTrace has emitted trace footer - shutdownSema uint32 // used to wait for ReadTrace completion - seqStart uint64 // sequence number when tracing was started - startTicks int64 // cputicks when tracing was started - endTicks int64 // cputicks when tracing was stopped - startNanotime int64 // nanotime when tracing was started - endNanotime int64 // nanotime when tracing was stopped - startTime traceTime // traceClockNow when tracing started - endTime traceTime // traceClockNow when tracing stopped - seqGC uint64 // GC start/done sequencer - reading traceBufPtr // buffer currently handed off to user - empty traceBufPtr // stack of empty buffers - fullHead traceBufPtr // queue of full buffers - fullTail traceBufPtr - stackTab traceStackTable // maps stack traces to unique ids - // cpuLogRead accepts CPU profile samples from the signal handler where - // they're generated. It uses a two-word header to hold the IDs of the P and - // G (respectively) that were active at the time of the sample. Because - // profBuf uses a record with all zeros in its header to indicate overflow, - // we make sure to make the P field always non-zero: The ID of a real P will - // start at bit 1, and bit 0 will be set. Samples that arrive while no P is - // running (such as near syscalls) will set the first header field to 0b10. - // This careful handling of the first header field allows us to store ID of - // the active G directly in the second field, even though that will be 0 - // when sampling g0. - cpuLogRead *profBuf - // cpuLogBuf is a trace buffer to hold events corresponding to CPU profile - // samples, which arrive out of band and not directly connected to a - // specific P. - cpuLogBuf traceBufPtr - - reader atomic.Pointer[g] // goroutine that called ReadTrace, or nil - - signalLock atomic.Uint32 // protects use of the following member, only usable in signal handlers - cpuLogWrite *profBuf // copy of cpuLogRead for use in signal handlers, set without signalLock - - // Dictionary for traceEvString. - // - // TODO: central lock to access the map is not ideal. - // option: pre-assign ids to all user annotation region names and tags - // option: per-P cache - // option: sync.Map like data structure - stringsLock mutex - strings map[string]uint64 - stringSeq uint64 - - // markWorkerLabels maps gcMarkWorkerMode to string ID. - markWorkerLabels [len(gcMarkWorkerModeStrings)]uint64 - - bufLock mutex // protects buf - buf traceBufPtr // global trace buffer, used when running without a p -} - -// gTraceState is per-G state for the tracer. -type gTraceState struct { - sysExitTime traceTime // timestamp when syscall has returned - tracedSyscallEnter bool // syscall or cgo was entered while trace was enabled or StartTrace has emitted EvGoInSyscall about this goroutine - seq uint64 // trace event sequencer - lastP puintptr // last P emitted an event for this goroutine -} - -// Unused; for compatibility with the new tracer. -func (s *gTraceState) reset() {} - -// mTraceState is per-M state for the tracer. -type mTraceState struct { - startingTrace bool // this M is in TraceStart, potentially before traceEnabled is true - tracedSTWStart bool // this M traced a STW start, so it should trace an end -} - -// pTraceState is per-P state for the tracer. -type pTraceState struct { - buf traceBufPtr - - // inSweep indicates the sweep events should be traced. - // This is used to defer the sweep start event until a span - // has actually been swept. - inSweep bool - - // swept and reclaimed track the number of bytes swept and reclaimed - // by sweeping in the current sweep loop (while inSweep was true). - swept, reclaimed uintptr -} - -// traceLockInit initializes global trace locks. -func traceLockInit() { - lockInit(&trace.bufLock, lockRankTraceBuf) - lockInit(&trace.stringsLock, lockRankTraceStrings) - lockInit(&trace.lock, lockRankTrace) - lockInit(&trace.stackTab.lock, lockRankTraceStackTab) -} - -// traceBufHeader is per-P tracing buffer. -type traceBufHeader struct { - link traceBufPtr // in trace.empty/full - lastTime traceTime // when we wrote the last event - pos int // next write offset in arr - stk [traceStackSize]uintptr // scratch buffer for traceback -} - -// traceBuf is per-P tracing buffer. -type traceBuf struct { - _ sys.NotInHeap - traceBufHeader - arr [64<<10 - unsafe.Sizeof(traceBufHeader{})]byte // underlying buffer for traceBufHeader.buf -} - -// traceBufPtr is a *traceBuf that is not traced by the garbage -// collector and doesn't have write barriers. traceBufs are not -// allocated from the GC'd heap, so this is safe, and are often -// manipulated in contexts where write barriers are not allowed, so -// this is necessary. -// -// TODO: Since traceBuf is now embedded runtime/internal/sys.NotInHeap, this isn't necessary. -type traceBufPtr uintptr - -func (tp traceBufPtr) ptr() *traceBuf { return (*traceBuf)(unsafe.Pointer(tp)) } -func (tp *traceBufPtr) set(b *traceBuf) { *tp = traceBufPtr(unsafe.Pointer(b)) } -func traceBufPtrOf(b *traceBuf) traceBufPtr { - return traceBufPtr(unsafe.Pointer(b)) -} - -// traceEnabled returns true if the trace is currently enabled. -// -// nosplit because it's called on the syscall path when stack movement is forbidden. -// -//go:nosplit -func traceEnabled() bool { - return trace.enabled -} - -// traceShuttingDown returns true if the trace is currently shutting down. -// -//go:nosplit -func traceShuttingDown() bool { - return trace.shutdown -} - -// traceLocker represents an M writing trace events. While a traceLocker value -// is valid, the tracer observes all operations on the G/M/P or trace events being -// written as happening atomically. -// -// This doesn't do much for the current tracer, because the current tracer doesn't -// need atomicity around non-trace runtime operations. All the state it needs it -// collects carefully during a STW. -type traceLocker struct { - enabled bool -} - -// traceAcquire prepares this M for writing one or more trace events. -// -// This exists for compatibility with the upcoming new tracer; it doesn't do much -// in the current tracer. -// -// nosplit because it's called on the syscall path when stack movement is forbidden. -// -//go:nosplit -func traceAcquire() traceLocker { - if !traceEnabled() { - return traceLocker{false} - } - return traceLocker{true} -} - -// ok returns true if the traceLocker is valid (i.e. tracing is enabled). -// -// nosplit because it's called on the syscall path when stack movement is forbidden. -// -//go:nosplit -func (tl traceLocker) ok() bool { - return tl.enabled -} - -// traceRelease indicates that this M is done writing trace events. -// -// This exists for compatibility with the upcoming new tracer; it doesn't do anything -// in the current tracer. -// -// nosplit because it's called on the syscall path when stack movement is forbidden. -// -//go:nosplit -func traceRelease(tl traceLocker) { -} - -// StartTrace enables tracing for the current process. -// While tracing, the data will be buffered and available via [ReadTrace]. -// StartTrace returns an error if tracing is already enabled. -// Most clients should use the [runtime/trace] package or the [testing] package's -// -test.trace flag instead of calling StartTrace directly. -func StartTrace() error { - // Stop the world so that we can take a consistent snapshot - // of all goroutines at the beginning of the trace. - // Do not stop the world during GC so we ensure we always see - // a consistent view of GC-related events (e.g. a start is always - // paired with an end). - stw := stopTheWorldGC(stwStartTrace) - - // Prevent sysmon from running any code that could generate events. - lock(&sched.sysmonlock) - - // We are in stop-the-world, but syscalls can finish and write to trace concurrently. - // Exitsyscall could check trace.enabled long before and then suddenly wake up - // and decide to write to trace at a random point in time. - // However, such syscall will use the global trace.buf buffer, because we've - // acquired all p's by doing stop-the-world. So this protects us from such races. - lock(&trace.bufLock) - - if trace.enabled || trace.shutdown { - unlock(&trace.bufLock) - unlock(&sched.sysmonlock) - startTheWorldGC(stw) - return errorString("tracing is already enabled") - } - - // Can't set trace.enabled yet. While the world is stopped, exitsyscall could - // already emit a delayed event (see exitTicks in exitsyscall) if we set trace.enabled here. - // That would lead to an inconsistent trace: - // - either GoSysExit appears before EvGoInSyscall, - // - or GoSysExit appears for a goroutine for which we don't emit EvGoInSyscall below. - // To instruct traceEvent that it must not ignore events below, we set trace.startingTrace. - // trace.enabled is set afterwards once we have emitted all preliminary events. - mp := getg().m - mp.trace.startingTrace = true - - // Obtain current stack ID to use in all traceEvGoCreate events below. - stkBuf := make([]uintptr, traceStackSize) - stackID := traceStackID(mp, stkBuf, 2) - - profBuf := newProfBuf(2, profBufWordCount, profBufTagCount) // after the timestamp, header is [pp.id, gp.goid] - trace.cpuLogRead = profBuf - - // We must not acquire trace.signalLock outside of a signal handler: a - // profiling signal may arrive at any time and try to acquire it, leading to - // deadlock. Because we can't use that lock to protect updates to - // trace.cpuLogWrite (only use of the structure it references), reads and - // writes of the pointer must be atomic. (And although this field is never - // the sole pointer to the profBuf value, it's best to allow a write barrier - // here.) - atomicstorep(unsafe.Pointer(&trace.cpuLogWrite), unsafe.Pointer(profBuf)) - - // World is stopped, no need to lock. - forEachGRace(func(gp *g) { - status := readgstatus(gp) - if status != _Gdead { - gp.trace.seq = 0 - gp.trace.lastP = getg().m.p - // +PCQuantum because traceFrameForPC expects return PCs and subtracts PCQuantum. - id := trace.stackTab.put([]uintptr{logicalStackSentinel, startPCforTrace(gp.startpc) + sys.PCQuantum}) - traceEvent(traceEvGoCreate, -1, gp.goid, uint64(id), stackID) - } - if status == _Gwaiting { - // traceEvGoWaiting is implied to have seq=1. - gp.trace.seq++ - traceEvent(traceEvGoWaiting, -1, gp.goid) - } - if status == _Gsyscall { - gp.trace.seq++ - gp.trace.tracedSyscallEnter = true - traceEvent(traceEvGoInSyscall, -1, gp.goid) - } else if status == _Gdead && gp.m != nil && gp.m.isextra { - // Trigger two trace events for the dead g in the extra m, - // since the next event of the g will be traceEvGoSysExit in exitsyscall, - // while calling from C thread to Go. - gp.trace.seq = 0 - gp.trace.lastP = getg().m.p - // +PCQuantum because traceFrameForPC expects return PCs and subtracts PCQuantum. - id := trace.stackTab.put([]uintptr{logicalStackSentinel, startPCforTrace(0) + sys.PCQuantum}) // no start pc - traceEvent(traceEvGoCreate, -1, gp.goid, uint64(id), stackID) - gp.trace.seq++ - gp.trace.tracedSyscallEnter = true - traceEvent(traceEvGoInSyscall, -1, gp.goid) - } else { - // We need to explicitly clear the flag. A previous trace might have ended with a goroutine - // not emitting a GoSysExit and clearing the flag, leaving it in a stale state. Clearing - // it here makes it unambiguous to any goroutine exiting a syscall racing with us that - // no EvGoInSyscall event was emitted for it. (It's not racy to set this flag here, because - // it'll only get checked when the goroutine runs again, which will be after the world starts - // again.) - gp.trace.tracedSyscallEnter = false - } - }) - // Use a dummy traceLocker. The trace isn't enabled yet, but we can still write events. - tl := traceLocker{} - tl.ProcStart() - tl.GoStart() - // Note: startTicks needs to be set after we emit traceEvGoInSyscall events. - // If we do it the other way around, it is possible that exitsyscall will - // query sysExitTime after startTicks but before traceEvGoInSyscall timestamp. - // It will lead to a false conclusion that cputicks is broken. - trace.startTime = traceClockNow() - trace.startTicks = cputicks() - trace.startNanotime = nanotime() - trace.headerWritten = false - trace.footerWritten = false - - // string to id mapping - // 0 : reserved for an empty string - // remaining: other strings registered by traceString - trace.stringSeq = 0 - trace.strings = make(map[string]uint64) - - trace.seqGC = 0 - mp.trace.startingTrace = false - trace.enabled = true - - // Register runtime goroutine labels. - _, pid, bufp := traceAcquireBuffer() - for i, label := range gcMarkWorkerModeStrings[:] { - trace.markWorkerLabels[i], bufp = traceString(bufp, pid, label) - } - traceReleaseBuffer(mp, pid) - - unlock(&trace.bufLock) - - unlock(&sched.sysmonlock) - - // Record the current state of HeapGoal to avoid information loss in trace. - // - // Use the same dummy trace locker. The trace can't end until after we start - // the world, and we can safely trace from here. - tl.HeapGoal() - - startTheWorldGC(stw) - return nil -} - -// StopTrace stops tracing, if it was previously enabled. -// StopTrace only returns after all the reads for the trace have completed. -func StopTrace() { - // Stop the world so that we can collect the trace buffers from all p's below, - // and also to avoid races with traceEvent. - stw := stopTheWorldGC(stwStopTrace) - - // See the comment in StartTrace. - lock(&sched.sysmonlock) - - // See the comment in StartTrace. - lock(&trace.bufLock) - - if !trace.enabled { - unlock(&trace.bufLock) - unlock(&sched.sysmonlock) - startTheWorldGC(stw) - return - } - - // Trace GoSched for us, and use a dummy locker. The world is stopped - // and we control whether the trace is enabled, so this is safe. - tl := traceLocker{} - tl.GoSched() - - atomicstorep(unsafe.Pointer(&trace.cpuLogWrite), nil) - trace.cpuLogRead.close() - traceReadCPU() - - // Loop over all allocated Ps because dead Ps may still have - // trace buffers. - for _, p := range allp[:cap(allp)] { - buf := p.trace.buf - if buf != 0 { - traceFullQueue(buf) - p.trace.buf = 0 - } - } - if trace.buf != 0 { - buf := trace.buf - trace.buf = 0 - if buf.ptr().pos != 0 { - traceFullQueue(buf) - } - } - if trace.cpuLogBuf != 0 { - buf := trace.cpuLogBuf - trace.cpuLogBuf = 0 - if buf.ptr().pos != 0 { - traceFullQueue(buf) - } - } - - // Wait for startNanotime != endNanotime. On Windows the default interval between - // system clock ticks is typically between 1 and 15 milliseconds, which may not - // have passed since the trace started. Without nanotime moving forward, trace - // tooling has no way of identifying how much real time each cputicks time deltas - // represent. - for { - trace.endTime = traceClockNow() - trace.endTicks = cputicks() - trace.endNanotime = nanotime() - - if trace.endNanotime != trace.startNanotime || faketime != 0 { - break - } - osyield() - } - - trace.enabled = false - trace.shutdown = true - unlock(&trace.bufLock) - - unlock(&sched.sysmonlock) - - startTheWorldGC(stw) - - // The world is started but we've set trace.shutdown, so new tracing can't start. - // Wait for the trace reader to flush pending buffers and stop. - semacquire(&trace.shutdownSema) - if raceenabled { - raceacquire(unsafe.Pointer(&trace.shutdownSema)) - } - - systemstack(func() { - // The lock protects us from races with StartTrace/StopTrace because they do stop-the-world. - lock(&trace.lock) - for _, p := range allp[:cap(allp)] { - if p.trace.buf != 0 { - throw("trace: non-empty trace buffer in proc") - } - } - if trace.buf != 0 { - throw("trace: non-empty global trace buffer") - } - if trace.fullHead != 0 || trace.fullTail != 0 { - throw("trace: non-empty full trace buffer") - } - if trace.reading != 0 || trace.reader.Load() != nil { - throw("trace: reading after shutdown") - } - for trace.empty != 0 { - buf := trace.empty - trace.empty = buf.ptr().link - sysFree(unsafe.Pointer(buf), unsafe.Sizeof(*buf.ptr()), &memstats.other_sys) - } - trace.strings = nil - trace.shutdown = false - trace.cpuLogRead = nil - unlock(&trace.lock) - }) -} - -// ReadTrace returns the next chunk of binary tracing data, blocking until data -// is available. If tracing is turned off and all the data accumulated while it -// was on has been returned, ReadTrace returns nil. The caller must copy the -// returned data before calling ReadTrace again. -// ReadTrace must be called from one goroutine at a time. -func ReadTrace() []byte { -top: - var buf []byte - var park bool - systemstack(func() { - buf, park = readTrace0() - }) - if park { - gopark(func(gp *g, _ unsafe.Pointer) bool { - if !trace.reader.CompareAndSwapNoWB(nil, gp) { - // We're racing with another reader. - // Wake up and handle this case. - return false - } - - if g2 := traceReader(); gp == g2 { - // New data arrived between unlocking - // and the CAS and we won the wake-up - // race, so wake up directly. - return false - } else if g2 != nil { - printlock() - println("runtime: got trace reader", g2, g2.goid) - throw("unexpected trace reader") - } - - return true - }, nil, waitReasonTraceReaderBlocked, traceBlockSystemGoroutine, 2) - goto top - } - - return buf -} - -// readTrace0 is ReadTrace's continuation on g0. This must run on the -// system stack because it acquires trace.lock. -// -//go:systemstack -func readTrace0() (buf []byte, park bool) { - if raceenabled { - // g0 doesn't have a race context. Borrow the user G's. - if getg().racectx != 0 { - throw("expected racectx == 0") - } - getg().racectx = getg().m.curg.racectx - // (This defer should get open-coded, which is safe on - // the system stack.) - defer func() { getg().racectx = 0 }() - } - - // Optimistically look for CPU profile samples. This may write new stack - // records, and may write new tracing buffers. This must be done with the - // trace lock not held. footerWritten and shutdown are safe to access - // here. They are only mutated by this goroutine or during a STW. - if !trace.footerWritten && !trace.shutdown { - traceReadCPU() - } - - // This function must not allocate while holding trace.lock: - // allocation can call heap allocate, which will try to emit a trace - // event while holding heap lock. - lock(&trace.lock) - - if trace.reader.Load() != nil { - // More than one goroutine reads trace. This is bad. - // But we rather do not crash the program because of tracing, - // because tracing can be enabled at runtime on prod servers. - unlock(&trace.lock) - println("runtime: ReadTrace called from multiple goroutines simultaneously") - return nil, false - } - // Recycle the old buffer. - if buf := trace.reading; buf != 0 { - buf.ptr().link = trace.empty - trace.empty = buf - trace.reading = 0 - } - // Write trace header. - if !trace.headerWritten { - trace.headerWritten = true - unlock(&trace.lock) - return []byte("go 1.21 trace\x00\x00\x00"), false - } - // Wait for new data. - if trace.fullHead == 0 && !trace.shutdown { - // We don't simply use a note because the scheduler - // executes this goroutine directly when it wakes up - // (also a note would consume an M). - unlock(&trace.lock) - return nil, true - } -newFull: - assertLockHeld(&trace.lock) - // Write a buffer. - if trace.fullHead != 0 { - buf := traceFullDequeue() - trace.reading = buf - unlock(&trace.lock) - return buf.ptr().arr[:buf.ptr().pos], false - } - - // Write footer with timer frequency. - if !trace.footerWritten { - trace.footerWritten = true - freq := (float64(trace.endTicks-trace.startTicks) / traceTimeDiv) / (float64(trace.endNanotime-trace.startNanotime) / 1e9) - if freq <= 0 { - throw("trace: ReadTrace got invalid frequency") - } - unlock(&trace.lock) - - // Write frequency event. - bufp := traceFlush(0, 0) - buf := bufp.ptr() - buf.byte(traceEvFrequency | 0< 0, write current stack id as the last argument (skipping skip top frames). -// If skip = 0, this event type should contain a stack, but we don't want -// to collect and remember it for this particular call. -func traceEvent(ev byte, skip int, args ...uint64) { - mp, pid, bufp := traceAcquireBuffer() - // Double-check trace.enabled now that we've done m.locks++ and acquired bufLock. - // This protects from races between traceEvent and StartTrace/StopTrace. - - // The caller checked that trace.enabled == true, but trace.enabled might have been - // turned off between the check and now. Check again. traceLockBuffer did mp.locks++, - // StopTrace does stopTheWorld, and stopTheWorld waits for mp.locks to go back to zero, - // so if we see trace.enabled == true now, we know it's true for the rest of the function. - // Exitsyscall can run even during stopTheWorld. The race with StartTrace/StopTrace - // during tracing in exitsyscall is resolved by locking trace.bufLock in traceLockBuffer. - // - // Note trace_userTaskCreate runs the same check. - if !trace.enabled && !mp.trace.startingTrace { - traceReleaseBuffer(mp, pid) - return - } - - if skip > 0 { - if getg() == mp.curg { - skip++ // +1 because stack is captured in traceEventLocked. - } - } - traceEventLocked(0, mp, pid, bufp, ev, 0, skip, args...) - traceReleaseBuffer(mp, pid) -} - -// traceEventLocked writes a single event of type ev to the trace buffer bufp, -// flushing the buffer if necessary. pid is the id of the current P, or -// traceGlobProc if we're tracing without a real P. -// -// Preemption is disabled, and if running without a real P the global tracing -// buffer is locked. -// -// Events types that do not include a stack set skip to -1. Event types that -// include a stack may explicitly reference a stackID from the trace.stackTab -// (obtained by an earlier call to traceStackID). Without an explicit stackID, -// this function will automatically capture the stack of the goroutine currently -// running on mp, skipping skip top frames or, if skip is 0, writing out an -// empty stack record. -// -// It records the event's args to the traceBuf, and also makes an effort to -// reserve extraBytes bytes of additional space immediately following the event, -// in the same traceBuf. -func traceEventLocked(extraBytes int, mp *m, pid int32, bufp *traceBufPtr, ev byte, stackID uint32, skip int, args ...uint64) { - buf := bufp.ptr() - // TODO: test on non-zero extraBytes param. - maxSize := 2 + 5*traceBytesPerNumber + extraBytes // event type, length, sequence, timestamp, stack id and two add params - if buf == nil || len(buf.arr)-buf.pos < maxSize { - systemstack(func() { - buf = traceFlush(traceBufPtrOf(buf), pid).ptr() - }) - bufp.set(buf) - } - - ts := traceClockNow() - if ts <= buf.lastTime { - ts = buf.lastTime + 1 - } - tsDiff := uint64(ts - buf.lastTime) - buf.lastTime = ts - narg := byte(len(args)) - if stackID != 0 || skip >= 0 { - narg++ - } - // We have only 2 bits for number of arguments. - // If number is >= 3, then the event type is followed by event length in bytes. - if narg > 3 { - narg = 3 - } - startPos := buf.pos - buf.byte(ev | narg< 0 { - buf.varint(traceStackID(mp, buf.stk[:], skip)) - } - evSize := buf.pos - startPos - if evSize > maxSize { - throw("invalid length of trace event") - } - if lenp != nil { - // Fill in actual length. - *lenp = byte(evSize - 2) - } -} - -// traceCPUSample writes a CPU profile sample stack to the execution tracer's -// profiling buffer. It is called from a signal handler, so is limited in what -// it can do. -func traceCPUSample(gp *g, _ *m, pp *p, stk []uintptr) { - if !traceEnabled() { - // Tracing is usually turned off; don't spend time acquiring the signal - // lock unless it's active. - return - } - - // Match the clock used in traceEventLocked - now := traceClockNow() - // The "header" here is the ID of the P that was running the profiled code, - // followed by the ID of the goroutine. (For normal CPU profiling, it's - // usually the number of samples with the given stack.) Near syscalls, pp - // may be nil. Reporting goid of 0 is fine for either g0 or a nil gp. - var hdr [2]uint64 - if pp != nil { - // Overflow records in profBuf have all header values set to zero. Make - // sure that real headers have at least one bit set. - hdr[0] = uint64(pp.id)<<1 | 0b1 - } else { - hdr[0] = 0b10 - } - if gp != nil { - hdr[1] = gp.goid - } - - // Allow only one writer at a time - for !trace.signalLock.CompareAndSwap(0, 1) { - // TODO: Is it safe to osyield here? https://go.dev/issue/52672 - osyield() - } - - if log := (*profBuf)(atomic.Loadp(unsafe.Pointer(&trace.cpuLogWrite))); log != nil { - // Note: we don't pass a tag pointer here (how should profiling tags - // interact with the execution tracer?), but if we did we'd need to be - // careful about write barriers. See the long comment in profBuf.write. - log.write(nil, int64(now), hdr[:], stk) - } - - trace.signalLock.Store(0) -} - -func traceReadCPU() { - bufp := &trace.cpuLogBuf - - for { - data, tags, _ := trace.cpuLogRead.read(profBufNonBlocking) - if len(data) == 0 { - break - } - for len(data) > 0 { - if len(data) < 4 || data[0] > uint64(len(data)) { - break // truncated profile - } - if data[0] < 4 || tags != nil && len(tags) < 1 { - break // malformed profile - } - if len(tags) < 1 { - break // mismatched profile records and tags - } - timestamp := data[1] - ppid := data[2] >> 1 - if hasP := (data[2] & 0b1) != 0; !hasP { - ppid = ^uint64(0) - } - goid := data[3] - stk := data[4:data[0]] - empty := len(stk) == 1 && data[2] == 0 && data[3] == 0 - data = data[data[0]:] - // No support here for reporting goroutine tags at the moment; if - // that information is to be part of the execution trace, we'd - // probably want to see when the tags are applied and when they - // change, instead of only seeing them when we get a CPU sample. - tags = tags[1:] - - if empty { - // Looks like an overflow record from the profBuf. Not much to - // do here, we only want to report full records. - // - // TODO: should we start a goroutine to drain the profBuf, - // rather than relying on a high-enough volume of tracing events - // to keep ReadTrace busy? https://go.dev/issue/52674 - continue - } - - buf := bufp.ptr() - if buf == nil { - systemstack(func() { - *bufp = traceFlush(*bufp, 0) - }) - buf = bufp.ptr() - } - nstk := 1 - buf.stk[0] = logicalStackSentinel - for ; nstk < len(buf.stk) && nstk-1 < len(stk); nstk++ { - buf.stk[nstk] = uintptr(stk[nstk-1]) - } - stackID := trace.stackTab.put(buf.stk[:nstk]) - - traceEventLocked(0, nil, 0, bufp, traceEvCPUSample, stackID, 1, timestamp, ppid, goid) - } - } -} - -// logicalStackSentinel is a sentinel value at pcBuf[0] signifying that -// pcBuf[1:] holds a logical stack requiring no further processing. Any other -// value at pcBuf[0] represents a skip value to apply to the physical stack in -// pcBuf[1:] after inline expansion. -const logicalStackSentinel = ^uintptr(0) - -// traceStackID captures a stack trace into pcBuf, registers it in the trace -// stack table, and returns its unique ID. pcBuf should have a length equal to -// traceStackSize. skip controls the number of leaf frames to omit in order to -// hide tracer internals from stack traces, see CL 5523. -func traceStackID(mp *m, pcBuf []uintptr, skip int) uint64 { - gp := getg() - curgp := mp.curg - nstk := 1 - if tracefpunwindoff() || mp.hasCgoOnStack() { - // Slow path: Unwind using default unwinder. Used when frame pointer - // unwinding is unavailable or disabled (tracefpunwindoff), or might - // produce incomplete results or crashes (hasCgoOnStack). Note that no - // cgo callback related crashes have been observed yet. The main - // motivation is to take advantage of a potentially registered cgo - // symbolizer. - pcBuf[0] = logicalStackSentinel - if curgp == gp { - nstk += callers(skip+1, pcBuf[1:]) - } else if curgp != nil { - nstk += gcallers(curgp, skip, pcBuf[1:]) - } - } else { - // Fast path: Unwind using frame pointers. - pcBuf[0] = uintptr(skip) - if curgp == gp { - nstk += fpTracebackPCs(unsafe.Pointer(getfp()), pcBuf[1:]) - } else if curgp != nil { - // We're called on the g0 stack through mcall(fn) or systemstack(fn). To - // behave like gcallers above, we start unwinding from sched.bp, which - // points to the caller frame of the leaf frame on g's stack. The return - // address of the leaf frame is stored in sched.pc, which we manually - // capture here. - pcBuf[1] = curgp.sched.pc - nstk += 1 + fpTracebackPCs(unsafe.Pointer(curgp.sched.bp), pcBuf[2:]) - } - } - if nstk > 0 { - nstk-- // skip runtime.goexit - } - if nstk > 0 && curgp.goid == 1 { - nstk-- // skip runtime.main - } - id := trace.stackTab.put(pcBuf[:nstk]) - return uint64(id) -} - -// tracefpunwindoff returns true if frame pointer unwinding for the tracer is -// disabled via GODEBUG or not supported by the architecture. -// TODO(#60254): support frame pointer unwinding on plan9/amd64. -func tracefpunwindoff() bool { - return debug.tracefpunwindoff != 0 || (goarch.ArchFamily != goarch.AMD64 && goarch.ArchFamily != goarch.ARM64) || goos.IsPlan9 == 1 -} - -// fpTracebackPCs populates pcBuf with the return addresses for each frame and -// returns the number of PCs written to pcBuf. The returned PCs correspond to -// "physical frames" rather than "logical frames"; that is if A is inlined into -// B, this will return a PC for only B. -func fpTracebackPCs(fp unsafe.Pointer, pcBuf []uintptr) (i int) { - for i = 0; i < len(pcBuf) && fp != nil; i++ { - // return addr sits one word above the frame pointer - pcBuf[i] = *(*uintptr)(unsafe.Pointer(uintptr(fp) + goarch.PtrSize)) - // follow the frame pointer to the next one - fp = unsafe.Pointer(*(*uintptr)(fp)) - } - return i -} - -// traceAcquireBuffer returns trace buffer to use and, if necessary, locks it. -func traceAcquireBuffer() (mp *m, pid int32, bufp *traceBufPtr) { - // Any time we acquire a buffer, we may end up flushing it, - // but flushes are rare. Record the lock edge even if it - // doesn't happen this time. - lockRankMayTraceFlush() - - mp = acquirem() - if p := mp.p.ptr(); p != nil { - return mp, p.id, &p.trace.buf - } - lock(&trace.bufLock) - return mp, traceGlobProc, &trace.buf -} - -// traceReleaseBuffer releases a buffer previously acquired with traceAcquireBuffer. -func traceReleaseBuffer(mp *m, pid int32) { - if pid == traceGlobProc { - unlock(&trace.bufLock) - } - releasem(mp) -} - -// lockRankMayTraceFlush records the lock ranking effects of a -// potential call to traceFlush. -func lockRankMayTraceFlush() { - lockWithRankMayAcquire(&trace.lock, getLockRank(&trace.lock)) -} - -// traceFlush puts buf onto stack of full buffers and returns an empty buffer. -// -// This must run on the system stack because it acquires trace.lock. -// -//go:systemstack -func traceFlush(buf traceBufPtr, pid int32) traceBufPtr { - lock(&trace.lock) - if buf != 0 { - traceFullQueue(buf) - } - if trace.empty != 0 { - buf = trace.empty - trace.empty = buf.ptr().link - } else { - buf = traceBufPtr(sysAlloc(unsafe.Sizeof(traceBuf{}), &memstats.other_sys)) - if buf == 0 { - throw("trace: out of memory") - } - } - bufp := buf.ptr() - bufp.link.set(nil) - bufp.pos = 0 - - // initialize the buffer for a new batch - ts := traceClockNow() - if ts <= bufp.lastTime { - ts = bufp.lastTime + 1 - } - bufp.lastTime = ts - bufp.byte(traceEvBatch | 1<= 0x80; v >>= 7 { - buf.arr[pos] = 0x80 | byte(v) - pos++ - } - buf.arr[pos] = byte(v) - pos++ - buf.pos = pos -} - -// varintAt writes varint v at byte position pos in buf. This always -// consumes traceBytesPerNumber bytes. This is intended for when the -// caller needs to reserve space for a varint but can't populate it -// until later. -func (buf *traceBuf) varintAt(pos int, v uint64) { - for i := 0; i < traceBytesPerNumber; i++ { - if i < traceBytesPerNumber-1 { - buf.arr[pos] = 0x80 | byte(v) - } else { - buf.arr[pos] = byte(v) - } - v >>= 7 - pos++ - } -} - -// byte appends v to buf. -func (buf *traceBuf) byte(v byte) { - buf.arr[buf.pos] = v - buf.pos++ -} - -// traceStackTable maps stack traces (arrays of PC's) to unique uint32 ids. -// It is lock-free for reading. -type traceStackTable struct { - lock mutex // Must be acquired on the system stack - seq uint32 - mem traceAlloc - tab [1 << 13]traceStackPtr -} - -// traceStack is a single stack in traceStackTable. -type traceStack struct { - link traceStackPtr - hash uintptr - id uint32 - n int - stk [0]uintptr // real type [n]uintptr -} - -type traceStackPtr uintptr - -func (tp traceStackPtr) ptr() *traceStack { return (*traceStack)(unsafe.Pointer(tp)) } - -// stack returns slice of PCs. -func (ts *traceStack) stack() []uintptr { - return (*[traceStackSize]uintptr)(unsafe.Pointer(&ts.stk))[:ts.n] -} - -// put returns a unique id for the stack trace pcs and caches it in the table, -// if it sees the trace for the first time. -func (tab *traceStackTable) put(pcs []uintptr) uint32 { - if len(pcs) == 0 { - return 0 - } - hash := memhash(unsafe.Pointer(&pcs[0]), 0, uintptr(len(pcs))*unsafe.Sizeof(pcs[0])) - // First, search the hashtable w/o the mutex. - if id := tab.find(pcs, hash); id != 0 { - return id - } - // Now, double check under the mutex. - // Switch to the system stack so we can acquire tab.lock - var id uint32 - systemstack(func() { - lock(&tab.lock) - if id = tab.find(pcs, hash); id != 0 { - unlock(&tab.lock) - return - } - // Create new record. - tab.seq++ - stk := tab.newStack(len(pcs)) - stk.hash = hash - stk.id = tab.seq - id = stk.id - stk.n = len(pcs) - stkpc := stk.stack() - copy(stkpc, pcs) - part := int(hash % uintptr(len(tab.tab))) - stk.link = tab.tab[part] - atomicstorep(unsafe.Pointer(&tab.tab[part]), unsafe.Pointer(stk)) - unlock(&tab.lock) - }) - return id -} - -// find checks if the stack trace pcs is already present in the table. -func (tab *traceStackTable) find(pcs []uintptr, hash uintptr) uint32 { - part := int(hash % uintptr(len(tab.tab))) -Search: - for stk := tab.tab[part].ptr(); stk != nil; stk = stk.link.ptr() { - if stk.hash == hash && stk.n == len(pcs) { - for i, stkpc := range stk.stack() { - if stkpc != pcs[i] { - continue Search - } - } - return stk.id - } - } - return 0 -} - -// newStack allocates a new stack of size n. -func (tab *traceStackTable) newStack(n int) *traceStack { - return (*traceStack)(tab.mem.alloc(unsafe.Sizeof(traceStack{}) + uintptr(n)*goarch.PtrSize)) -} - -// traceFrames returns the frames corresponding to pcs. It may -// allocate and may emit trace events. -func traceFrames(bufp traceBufPtr, pcs []uintptr) ([]traceFrame, traceBufPtr) { - frames := make([]traceFrame, 0, len(pcs)) - ci := CallersFrames(pcs) - for { - var frame traceFrame - f, more := ci.Next() - frame, bufp = traceFrameForPC(bufp, 0, f) - frames = append(frames, frame) - if !more { - return frames, bufp - } - } -} - -// dump writes all previously cached stacks to trace buffers, -// releases all memory and resets state. -// -// This must run on the system stack because it calls traceFlush. -// -//go:systemstack -func (tab *traceStackTable) dump(bufp traceBufPtr) traceBufPtr { - for i := range tab.tab { - stk := tab.tab[i].ptr() - for ; stk != nil; stk = stk.link.ptr() { - var frames []traceFrame - frames, bufp = traceFrames(bufp, fpunwindExpand(stk.stack())) - - // Estimate the size of this record. This - // bound is pretty loose, but avoids counting - // lots of varint sizes. - maxSize := 1 + traceBytesPerNumber + (2+4*len(frames))*traceBytesPerNumber - // Make sure we have enough buffer space. - if buf := bufp.ptr(); len(buf.arr)-buf.pos < maxSize { - bufp = traceFlush(bufp, 0) - } - - // Emit header, with space reserved for length. - buf := bufp.ptr() - buf.byte(traceEvStack | 3< 0 && pcBuf[0] == logicalStackSentinel { - // pcBuf contains logical rather than inlined frames, skip has already been - // applied, just return it without the sentinel value in pcBuf[0]. - return pcBuf[1:] - } - - var ( - lastFuncID = abi.FuncIDNormal - newPCBuf = make([]uintptr, 0, traceStackSize) - skip = pcBuf[0] - // skipOrAdd skips or appends retPC to newPCBuf and returns true if more - // pcs can be added. - skipOrAdd = func(retPC uintptr) bool { - if skip > 0 { - skip-- - } else { - newPCBuf = append(newPCBuf, retPC) - } - return len(newPCBuf) < cap(newPCBuf) - } - ) - -outer: - for _, retPC := range pcBuf[1:] { - callPC := retPC - 1 - fi := findfunc(callPC) - if !fi.valid() { - // There is no funcInfo if callPC belongs to a C function. In this case - // we still keep the pc, but don't attempt to expand inlined frames. - if more := skipOrAdd(retPC); !more { - break outer - } - continue - } - - u, uf := newInlineUnwinder(fi, callPC) - for ; uf.valid(); uf = u.next(uf) { - sf := u.srcFunc(uf) - if sf.funcID == abi.FuncIDWrapper && elideWrapperCalling(lastFuncID) { - // ignore wrappers - } else if more := skipOrAdd(uf.pc + 1); !more { - break outer - } - lastFuncID = sf.funcID - } - } - return newPCBuf -} - -type traceFrame struct { - PC uintptr - funcID uint64 - fileID uint64 - line uint64 -} - -// traceFrameForPC records the frame information. -// It may allocate memory. -func traceFrameForPC(buf traceBufPtr, pid int32, f Frame) (traceFrame, traceBufPtr) { - bufp := &buf - var frame traceFrame - frame.PC = f.PC - - fn := f.Function - const maxLen = 1 << 10 - if len(fn) > maxLen { - fn = fn[len(fn)-maxLen:] - } - frame.funcID, bufp = traceString(bufp, pid, fn) - frame.line = uint64(f.Line) - file := f.File - if len(file) > maxLen { - file = file[len(file)-maxLen:] - } - frame.fileID, bufp = traceString(bufp, pid, file) - return frame, (*bufp) -} - -// traceAlloc is a non-thread-safe region allocator. -// It holds a linked list of traceAllocBlock. -type traceAlloc struct { - head traceAllocBlockPtr - off uintptr -} - -// traceAllocBlock is a block in traceAlloc. -// -// traceAllocBlock is allocated from non-GC'd memory, so it must not -// contain heap pointers. Writes to pointers to traceAllocBlocks do -// not need write barriers. -type traceAllocBlock struct { - _ sys.NotInHeap - next traceAllocBlockPtr - data [64<<10 - goarch.PtrSize]byte -} - -// TODO: Since traceAllocBlock is now embedded runtime/internal/sys.NotInHeap, this isn't necessary. -type traceAllocBlockPtr uintptr - -func (p traceAllocBlockPtr) ptr() *traceAllocBlock { return (*traceAllocBlock)(unsafe.Pointer(p)) } -func (p *traceAllocBlockPtr) set(x *traceAllocBlock) { *p = traceAllocBlockPtr(unsafe.Pointer(x)) } - -// alloc allocates n-byte block. -func (a *traceAlloc) alloc(n uintptr) unsafe.Pointer { - n = alignUp(n, goarch.PtrSize) - if a.head == 0 || a.off+n > uintptr(len(a.head.ptr().data)) { - if n > uintptr(len(a.head.ptr().data)) { - throw("trace: alloc too large") - } - block := (*traceAllocBlock)(sysAlloc(unsafe.Sizeof(traceAllocBlock{}), &memstats.other_sys)) - if block == nil { - throw("trace: out of memory") - } - block.next.set(a.head.ptr()) - a.head.set(block) - a.off = 0 - } - p := &a.head.ptr().data[a.off] - a.off += n - return unsafe.Pointer(p) -} - -// drop frees all previously allocated memory and resets the allocator. -func (a *traceAlloc) drop() { - for a.head != 0 { - block := a.head.ptr() - a.head.set(block.next.ptr()) - sysFree(unsafe.Pointer(block), unsafe.Sizeof(traceAllocBlock{}), &memstats.other_sys) - } -} - -// The following functions write specific events to trace. - -func (_ traceLocker) Gomaxprocs(procs int32) { - traceEvent(traceEvGomaxprocs, 1, uint64(procs)) -} - -func (_ traceLocker) ProcStart() { - traceEvent(traceEvProcStart, -1, uint64(getg().m.id)) -} - -func (_ traceLocker) ProcStop(pp *p) { - // Sysmon and stopTheWorld can stop Ps blocked in syscalls, - // to handle this we temporary employ the P. - mp := acquirem() - oldp := mp.p - mp.p.set(pp) - traceEvent(traceEvProcStop, -1) - mp.p = oldp - releasem(mp) -} - -func (_ traceLocker) GCStart() { - traceEvent(traceEvGCStart, 3, trace.seqGC) - trace.seqGC++ -} - -func (_ traceLocker) GCDone() { - traceEvent(traceEvGCDone, -1) -} - -func (_ traceLocker) STWStart(reason stwReason) { - // Don't trace if this STW is for trace start/stop, since traceEnabled - // switches during a STW. - if reason == stwStartTrace || reason == stwStopTrace { - return - } - getg().m.trace.tracedSTWStart = true - traceEvent(traceEvSTWStart, -1, uint64(reason)) -} - -func (_ traceLocker) STWDone() { - mp := getg().m - if !mp.trace.tracedSTWStart { - return - } - mp.trace.tracedSTWStart = false - traceEvent(traceEvSTWDone, -1) -} - -// traceGCSweepStart prepares to trace a sweep loop. This does not -// emit any events until traceGCSweepSpan is called. -// -// traceGCSweepStart must be paired with traceGCSweepDone and there -// must be no preemption points between these two calls. -func (_ traceLocker) GCSweepStart() { - // Delay the actual GCSweepStart event until the first span - // sweep. If we don't sweep anything, don't emit any events. - pp := getg().m.p.ptr() - if pp.trace.inSweep { - throw("double traceGCSweepStart") - } - pp.trace.inSweep, pp.trace.swept, pp.trace.reclaimed = true, 0, 0 -} - -// traceGCSweepSpan traces the sweep of a single page. -// -// This may be called outside a traceGCSweepStart/traceGCSweepDone -// pair; however, it will not emit any trace events in this case. -func (_ traceLocker) GCSweepSpan(bytesSwept uintptr) { - pp := getg().m.p.ptr() - if pp.trace.inSweep { - if pp.trace.swept == 0 { - traceEvent(traceEvGCSweepStart, 1) - } - pp.trace.swept += bytesSwept - } -} - -func (_ traceLocker) GCSweepDone() { - pp := getg().m.p.ptr() - if !pp.trace.inSweep { - throw("missing traceGCSweepStart") - } - if pp.trace.swept != 0 { - traceEvent(traceEvGCSweepDone, -1, uint64(pp.trace.swept), uint64(pp.trace.reclaimed)) - } - pp.trace.inSweep = false -} - -func (_ traceLocker) GCMarkAssistStart() { - traceEvent(traceEvGCMarkAssistStart, 1) -} - -func (_ traceLocker) GCMarkAssistDone() { - traceEvent(traceEvGCMarkAssistDone, -1) -} - -func (_ traceLocker) GoCreate(newg *g, pc uintptr) { - newg.trace.seq = 0 - newg.trace.lastP = getg().m.p - // +PCQuantum because traceFrameForPC expects return PCs and subtracts PCQuantum. - id := trace.stackTab.put([]uintptr{logicalStackSentinel, startPCforTrace(pc) + sys.PCQuantum}) - traceEvent(traceEvGoCreate, 2, newg.goid, uint64(id)) -} - -func (_ traceLocker) GoStart() { - gp := getg().m.curg - pp := gp.m.p - gp.trace.seq++ - if pp.ptr().gcMarkWorkerMode != gcMarkWorkerNotWorker { - traceEvent(traceEvGoStartLabel, -1, gp.goid, gp.trace.seq, trace.markWorkerLabels[pp.ptr().gcMarkWorkerMode]) - } else if gp.trace.lastP == pp { - traceEvent(traceEvGoStartLocal, -1, gp.goid) - } else { - gp.trace.lastP = pp - traceEvent(traceEvGoStart, -1, gp.goid, gp.trace.seq) - } -} - -func (_ traceLocker) GoEnd() { - traceEvent(traceEvGoEnd, -1) -} - -func (_ traceLocker) GoSched() { - gp := getg() - gp.trace.lastP = gp.m.p - traceEvent(traceEvGoSched, 1) -} - -func (_ traceLocker) GoPreempt() { - gp := getg() - gp.trace.lastP = gp.m.p - traceEvent(traceEvGoPreempt, 1) -} - -func (_ traceLocker) GoPark(reason traceBlockReason, skip int) { - // Convert the block reason directly to a trace event type. - // See traceBlockReason for more information. - traceEvent(byte(reason), skip) -} - -func (_ traceLocker) GoUnpark(gp *g, skip int) { - pp := getg().m.p - gp.trace.seq++ - if gp.trace.lastP == pp { - traceEvent(traceEvGoUnblockLocal, skip, gp.goid) - } else { - gp.trace.lastP = pp - traceEvent(traceEvGoUnblock, skip, gp.goid, gp.trace.seq) - } -} - -func (_ traceLocker) GoSysCall() { - var skip int - switch { - case tracefpunwindoff(): - // Unwind by skipping 1 frame relative to gp.syscallsp which is captured 3 - // frames above this frame. For frame pointer unwinding we produce the same - // results by hard coding the number of frames in between our caller and the - // actual syscall, see cases below. - // TODO(felixge): Implement gp.syscallbp to avoid this workaround? - skip = 1 - case GOOS == "solaris" || GOOS == "illumos": - // These platforms don't use a libc_read_trampoline. - skip = 3 - default: - // Skip the extra trampoline frame used on most systems. - skip = 4 - } - getg().m.curg.trace.tracedSyscallEnter = true - traceEvent(traceEvGoSysCall, skip) -} - -func (_ traceLocker) GoSysExit(lostP bool) { - if !lostP { - throw("lostP must always be true in the old tracer for GoSysExit") - } - gp := getg().m.curg - if !gp.trace.tracedSyscallEnter { - // There was no syscall entry traced for us at all, so there's definitely - // no EvGoSysBlock or EvGoInSyscall before us, which EvGoSysExit requires. - return - } - gp.trace.tracedSyscallEnter = false - ts := gp.trace.sysExitTime - if ts != 0 && ts < trace.startTime { - // There is a race between the code that initializes sysExitTimes - // (in exitsyscall, which runs without a P, and therefore is not - // stopped with the rest of the world) and the code that initializes - // a new trace. The recorded sysExitTime must therefore be treated - // as "best effort". If they are valid for this trace, then great, - // use them for greater accuracy. But if they're not valid for this - // trace, assume that the trace was started after the actual syscall - // exit (but before we actually managed to start the goroutine, - // aka right now), and assign a fresh time stamp to keep the log consistent. - ts = 0 - } - gp.trace.sysExitTime = 0 - gp.trace.seq++ - gp.trace.lastP = gp.m.p - traceEvent(traceEvGoSysExit, -1, gp.goid, gp.trace.seq, uint64(ts)) -} - -// nosplit because it's called from exitsyscall without a P. -// -//go:nosplit -func (_ traceLocker) RecordSyscallExitedTime(gp *g, oldp *p) { - // Wait till traceGoSysBlock event is emitted. - // This ensures consistency of the trace (the goroutine is started after it is blocked). - for oldp != nil && oldp.syscalltick == gp.m.syscalltick { - osyield() - } - // We can't trace syscall exit right now because we don't have a P. - // Tracing code can invoke write barriers that cannot run without a P. - // So instead we remember the syscall exit time and emit the event - // in execute when we have a P. - gp.trace.sysExitTime = traceClockNow() -} - -func (_ traceLocker) GoSysBlock(pp *p) { - // Sysmon and stopTheWorld can declare syscalls running on remote Ps as blocked, - // to handle this we temporary employ the P. - mp := acquirem() - oldp := mp.p - mp.p.set(pp) - traceEvent(traceEvGoSysBlock, -1) - mp.p = oldp - releasem(mp) -} - -func (t traceLocker) ProcSteal(pp *p, forMe bool) { - t.ProcStop(pp) -} - -func (_ traceLocker) HeapAlloc(live uint64) { - traceEvent(traceEvHeapAlloc, -1, live) -} - -func (_ traceLocker) HeapGoal() { - heapGoal := gcController.heapGoal() - if heapGoal == ^uint64(0) { - // Heap-based triggering is disabled. - traceEvent(traceEvHeapGoal, -1, 0) - } else { - traceEvent(traceEvHeapGoal, -1, heapGoal) - } -} - -// To access runtime functions from runtime/trace. -// See runtime/trace/annotation.go - -//go:linkname trace_userTaskCreate runtime/trace.userTaskCreate -func trace_userTaskCreate(id, parentID uint64, taskType string) { - if !trace.enabled { - return - } - - // Same as in traceEvent. - mp, pid, bufp := traceAcquireBuffer() - if !trace.enabled && !mp.trace.startingTrace { - traceReleaseBuffer(mp, pid) - return - } - - typeStringID, bufp := traceString(bufp, pid, taskType) - traceEventLocked(0, mp, pid, bufp, traceEvUserTaskCreate, 0, 3, id, parentID, typeStringID) - traceReleaseBuffer(mp, pid) -} - -//go:linkname trace_userTaskEnd runtime/trace.userTaskEnd -func trace_userTaskEnd(id uint64) { - traceEvent(traceEvUserTaskEnd, 2, id) -} - -//go:linkname trace_userRegion runtime/trace.userRegion -func trace_userRegion(id, mode uint64, name string) { - if !trace.enabled { - return - } - - mp, pid, bufp := traceAcquireBuffer() - if !trace.enabled && !mp.trace.startingTrace { - traceReleaseBuffer(mp, pid) - return - } - - nameStringID, bufp := traceString(bufp, pid, name) - traceEventLocked(0, mp, pid, bufp, traceEvUserRegion, 0, 3, id, mode, nameStringID) - traceReleaseBuffer(mp, pid) -} - -//go:linkname trace_userLog runtime/trace.userLog -func trace_userLog(id uint64, category, message string) { - if !trace.enabled { - return - } - - mp, pid, bufp := traceAcquireBuffer() - if !trace.enabled && !mp.trace.startingTrace { - traceReleaseBuffer(mp, pid) - return - } - - categoryID, bufp := traceString(bufp, pid, category) - - // The log message is recorded after all of the normal trace event - // arguments, including the task, category, and stack IDs. We must ask - // traceEventLocked to reserve extra space for the length of the message - // and the message itself. - extraSpace := traceBytesPerNumber + len(message) - traceEventLocked(extraSpace, mp, pid, bufp, traceEvUserLog, 0, 3, id, categoryID) - buf := bufp.ptr() - - // double-check the message and its length can fit. - // Otherwise, truncate the message. - slen := len(message) - if room := len(buf.arr) - buf.pos; room < slen+traceBytesPerNumber { - slen = room - } - buf.varint(uint64(slen)) - buf.pos += copy(buf.arr[buf.pos:], message[:slen]) - - traceReleaseBuffer(mp, pid) -} - -// the start PC of a goroutine for tracing purposes. If pc is a wrapper, -// it returns the PC of the wrapped function. Otherwise it returns pc. -func startPCforTrace(pc uintptr) uintptr { - f := findfunc(pc) - if !f.valid() { - return pc // may happen for locked g in extra M since its pc is 0. - } - w := funcdata(f, abi.FUNCDATA_WrapInfo) - if w == nil { - return pc // not a wrapper - } - return f.datap.textAddr(*(*uint32)(w)) -} - -// OneNewExtraM registers the fact that a new extra M was created with -// the tracer. This matters if the M (which has an attached G) is used while -// the trace is still active because if it is, we need the fact that it exists -// to show up in the final trace. -func (tl traceLocker) OneNewExtraM(gp *g) { - // Trigger two trace events for the locked g in the extra m, - // since the next event of the g will be traceEvGoSysExit in exitsyscall, - // while calling from C thread to Go. - tl.GoCreate(gp, 0) // no start pc - gp.trace.seq++ - traceEvent(traceEvGoInSyscall, -1, gp.goid) -} - -// Used only in the new tracer. -func (tl traceLocker) GoCreateSyscall(gp *g) { -} - -// Used only in the new tracer. -func (tl traceLocker) GoDestroySyscall() { -} - -// traceTime represents a timestamp for the trace. -type traceTime uint64 - -// traceClockNow returns a monotonic timestamp. The clock this function gets -// the timestamp from is specific to tracing, and shouldn't be mixed with other -// clock sources. -// -// nosplit because it's called from exitsyscall, which is nosplit. -// -//go:nosplit -func traceClockNow() traceTime { - return traceTime(cputicks() / traceTimeDiv) -} - -func traceExitingSyscall() { -} - -func traceExitedSyscall() { -} - -// Not used in the old tracer. Defined for compatibility. -const defaultTraceAdvancePeriod = 0 diff --git a/contrib/go/_std_1.22/src/runtime/trace2map.go b/contrib/go/_std_1.22/src/runtime/trace2map.go deleted file mode 100644 index 195ec0bbe729..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace2map.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.exectracer2 - -// Simple hash table for tracing. Provides a mapping -// between variable-length data and a unique ID. Subsequent -// puts of the same data will return the same ID. -// -// Uses a region-based allocation scheme and assumes that the -// table doesn't ever grow very big. -// -// This is definitely not a general-purpose hash table! It avoids -// doing any high-level Go operations so it's safe to use even in -// sensitive contexts. - -package runtime - -import ( - "runtime/internal/atomic" - "runtime/internal/sys" - "unsafe" -) - -type traceMap struct { - lock mutex // Must be acquired on the system stack - seq atomic.Uint64 - mem traceRegionAlloc - tab [1 << 13]atomic.UnsafePointer // *traceMapNode (can't use generics because it's notinheap) -} - -type traceMapNode struct { - _ sys.NotInHeap - link atomic.UnsafePointer // *traceMapNode (can't use generics because it's notinheap) - hash uintptr - id uint64 - data []byte -} - -// next is a type-safe wrapper around link. -func (n *traceMapNode) next() *traceMapNode { - return (*traceMapNode)(n.link.Load()) -} - -// stealID steals an ID from the table, ensuring that it will not -// appear in the table anymore. -func (tab *traceMap) stealID() uint64 { - return tab.seq.Add(1) -} - -// put inserts the data into the table. -// -// It's always safe to noescape data because its bytes are always copied. -// -// Returns a unique ID for the data and whether this is the first time -// the data has been added to the map. -func (tab *traceMap) put(data unsafe.Pointer, size uintptr) (uint64, bool) { - if size == 0 { - return 0, false - } - hash := memhash(data, 0, size) - // First, search the hashtable w/o the mutex. - if id := tab.find(data, size, hash); id != 0 { - return id, false - } - // Now, double check under the mutex. - // Switch to the system stack so we can acquire tab.lock - var id uint64 - var added bool - systemstack(func() { - lock(&tab.lock) - if id = tab.find(data, size, hash); id != 0 { - unlock(&tab.lock) - return - } - // Create new record. - id = tab.seq.Add(1) - vd := tab.newTraceMapNode(data, size, hash, id) - - // Insert it into the table. - // - // Update the link first, since the node isn't published yet. - // Then, store the node in the table as the new first node - // for the bucket. - part := int(hash % uintptr(len(tab.tab))) - vd.link.StoreNoWB(tab.tab[part].Load()) - tab.tab[part].StoreNoWB(unsafe.Pointer(vd)) - unlock(&tab.lock) - - added = true - }) - return id, added -} - -// find looks up data in the table, assuming hash is a hash of data. -// -// Returns 0 if the data is not found, and the unique ID for it if it is. -func (tab *traceMap) find(data unsafe.Pointer, size, hash uintptr) uint64 { - part := int(hash % uintptr(len(tab.tab))) - for vd := tab.bucket(part); vd != nil; vd = vd.next() { - // Synchronization not necessary. Once published to the table, these - // values are immutable. - if vd.hash == hash && uintptr(len(vd.data)) == size { - if memequal(unsafe.Pointer(&vd.data[0]), data, size) { - return vd.id - } - } - } - return 0 -} - -// bucket is a type-safe wrapper for looking up a value in tab.tab. -func (tab *traceMap) bucket(part int) *traceMapNode { - return (*traceMapNode)(tab.tab[part].Load()) -} - -func (tab *traceMap) newTraceMapNode(data unsafe.Pointer, size, hash uintptr, id uint64) *traceMapNode { - // Create data array. - sl := notInHeapSlice{ - array: tab.mem.alloc(size), - len: int(size), - cap: int(size), - } - memmove(unsafe.Pointer(sl.array), data, size) - - // Create metadata structure. - meta := (*traceMapNode)(unsafe.Pointer(tab.mem.alloc(unsafe.Sizeof(traceMapNode{})))) - *(*notInHeapSlice)(unsafe.Pointer(&meta.data)) = sl - meta.id = id - meta.hash = hash - return meta -} - -// reset drops all allocated memory from the table and resets it. -// -// tab.lock must be held. Must run on the system stack because of this. -// -//go:systemstack -func (tab *traceMap) reset() { - assertLockHeld(&tab.lock) - tab.mem.drop() - tab.seq.Store(0) - // Clear table without write barriers. The table consists entirely - // of notinheap pointers, so this is fine. - // - // Write barriers may theoretically call into the tracer and acquire - // the lock again, and this lock ordering is expressed in the static - // lock ranking checker. - memclrNoHeapPointers(unsafe.Pointer(&tab.tab), unsafe.Sizeof(tab.tab)) -} diff --git a/contrib/go/_std_1.22/src/runtime/trace2region.go b/contrib/go/_std_1.22/src/runtime/trace2region.go deleted file mode 100644 index b514d127b592..000000000000 --- a/contrib/go/_std_1.22/src/runtime/trace2region.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2023 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build goexperiment.exectracer2 - -// Simple not-in-heap bump-pointer traceRegion allocator. - -package runtime - -import ( - "internal/goarch" - "runtime/internal/sys" - "unsafe" -) - -// traceRegionAlloc is a non-thread-safe region allocator. -// It holds a linked list of traceRegionAllocBlock. -type traceRegionAlloc struct { - head *traceRegionAllocBlock - off uintptr -} - -// traceRegionAllocBlock is a block in traceRegionAlloc. -// -// traceRegionAllocBlock is allocated from non-GC'd memory, so it must not -// contain heap pointers. Writes to pointers to traceRegionAllocBlocks do -// not need write barriers. -type traceRegionAllocBlock struct { - _ sys.NotInHeap - next *traceRegionAllocBlock - data [64<<10 - goarch.PtrSize]byte -} - -// alloc allocates n-byte block. -func (a *traceRegionAlloc) alloc(n uintptr) *notInHeap { - n = alignUp(n, goarch.PtrSize) - if a.head == nil || a.off+n > uintptr(len(a.head.data)) { - if n > uintptr(len(a.head.data)) { - throw("traceRegion: alloc too large") - } - block := (*traceRegionAllocBlock)(sysAlloc(unsafe.Sizeof(traceRegionAllocBlock{}), &memstats.other_sys)) - if block == nil { - throw("traceRegion: out of memory") - } - block.next = a.head - a.head = block - a.off = 0 - } - p := &a.head.data[a.off] - a.off += n - return (*notInHeap)(unsafe.Pointer(p)) -} - -// drop frees all previously allocated memory and resets the allocator. -func (a *traceRegionAlloc) drop() { - for a.head != nil { - block := a.head - a.head = block.next - sysFree(unsafe.Pointer(block), unsafe.Sizeof(traceRegionAllocBlock{}), &memstats.other_sys) - } -} diff --git a/contrib/go/_std_1.22/src/runtime/typekind.go b/contrib/go/_std_1.22/src/runtime/typekind.go deleted file mode 100644 index bd2dec94c40d..000000000000 --- a/contrib/go/_std_1.22/src/runtime/typekind.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -const ( - kindBool = 1 + iota - kindInt - kindInt8 - kindInt16 - kindInt32 - kindInt64 - kindUint - kindUint8 - kindUint16 - kindUint32 - kindUint64 - kindUintptr - kindFloat32 - kindFloat64 - kindComplex64 - kindComplex128 - kindArray - kindChan - kindFunc - kindInterface - kindMap - kindPtr - kindSlice - kindString - kindStruct - kindUnsafePointer - - kindDirectIface = 1 << 5 - kindGCProg = 1 << 6 - kindMask = (1 << 5) - 1 -) - -// isDirectIface reports whether t is stored directly in an interface value. -func isDirectIface(t *_type) bool { - return t.Kind_&kindDirectIface != 0 -} diff --git a/contrib/go/_std_1.22/src/strings/compare.go b/contrib/go/_std_1.22/src/strings/compare.go deleted file mode 100644 index 2bd4a243db2f..000000000000 --- a/contrib/go/_std_1.22/src/strings/compare.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package strings - -// Compare returns an integer comparing two strings lexicographically. -// The result will be 0 if a == b, -1 if a < b, and +1 if a > b. -// -// Compare is included only for symmetry with package bytes. -// It is usually clearer and always faster to use the built-in -// string comparison operators ==, <, >, and so on. -func Compare(a, b string) int { - // NOTE(rsc): This function does NOT call the runtime cmpstring function, - // because we do not want to provide any performance justification for - // using strings.Compare. Basically no one should use strings.Compare. - // As the comment above says, it is here only for symmetry with package bytes. - // If performance is important, the compiler should be changed to recognize - // the pattern so that all code doing three-way comparisons, not just code - // using strings.Compare, can benefit. - if a == b { - return 0 - } - if a < b { - return -1 - } - return +1 -} diff --git a/contrib/go/_std_1.22/src/sync/atomic/asm.s b/contrib/go/_std_1.22/src/sync/atomic/asm.s deleted file mode 100644 index 2022304665ef..000000000000 --- a/contrib/go/_std_1.22/src/sync/atomic/asm.s +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !race - -#include "textflag.h" - -TEXT ·SwapInt32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xchg(SB) - -TEXT ·SwapUint32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xchg(SB) - -TEXT ·SwapInt64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xchg64(SB) - -TEXT ·SwapUint64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xchg64(SB) - -TEXT ·SwapUintptr(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xchguintptr(SB) - -TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Cas(SB) - -TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Cas(SB) - -TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Casuintptr(SB) - -TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Cas64(SB) - -TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Cas64(SB) - -TEXT ·AddInt32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xadd(SB) - -TEXT ·AddUint32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xadd(SB) - -TEXT ·AddUintptr(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xadduintptr(SB) - -TEXT ·AddInt64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xadd64(SB) - -TEXT ·AddUint64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Xadd64(SB) - -TEXT ·LoadInt32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Load(SB) - -TEXT ·LoadUint32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Load(SB) - -TEXT ·LoadInt64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Load64(SB) - -TEXT ·LoadUint64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Load64(SB) - -TEXT ·LoadUintptr(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Loaduintptr(SB) - -TEXT ·LoadPointer(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Loadp(SB) - -TEXT ·StoreInt32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Store(SB) - -TEXT ·StoreUint32(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Store(SB) - -TEXT ·StoreInt64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Store64(SB) - -TEXT ·StoreUint64(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Store64(SB) - -TEXT ·StoreUintptr(SB),NOSPLIT,$0 - JMP runtime∕internal∕atomic·Storeuintptr(SB) diff --git a/contrib/go/_std_1.22/src/syscall/asan.go b/contrib/go/_std_1.22/src/syscall/asan.go deleted file mode 100644 index eff30781e4d9..000000000000 --- a/contrib/go/_std_1.22/src/syscall/asan.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build asan - -package syscall - -import ( - "runtime" - "unsafe" -) - -const asanenabled = true - -func asanRead(addr unsafe.Pointer, len int) { - runtime.ASanRead(addr, len) -} - -func asanWrite(addr unsafe.Pointer, len int) { - runtime.ASanWrite(addr, len) -} diff --git a/contrib/go/_std_1.22/src/syscall/asan0.go b/contrib/go/_std_1.22/src/syscall/asan0.go deleted file mode 100644 index 08bc44dea1c6..000000000000 --- a/contrib/go/_std_1.22/src/syscall/asan0.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !asan - -package syscall - -import ( - "unsafe" -) - -const asanenabled = false - -func asanRead(addr unsafe.Pointer, len int) { -} - -func asanWrite(addr unsafe.Pointer, len int) { -} diff --git a/contrib/go/_std_1.22/src/syscall/endian_big.go b/contrib/go/_std_1.22/src/syscall/endian_big.go deleted file mode 100644 index 8e3874eb8630..000000000000 --- a/contrib/go/_std_1.22/src/syscall/endian_big.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// -//go:build ppc64 || s390x || mips || mips64 - -package syscall - -const isBigEndian = true diff --git a/contrib/go/_std_1.22/src/syscall/endian_little.go b/contrib/go/_std_1.22/src/syscall/endian_little.go deleted file mode 100644 index f5fcb58db4e4..000000000000 --- a/contrib/go/_std_1.22/src/syscall/endian_little.go +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright 2016 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. -// -//go:build 386 || amd64 || arm || arm64 || loong64 || ppc64le || mips64le || mipsle || riscv64 || wasm - -package syscall - -const isBigEndian = false diff --git a/contrib/go/_std_1.22/src/syscall/msan.go b/contrib/go/_std_1.22/src/syscall/msan.go deleted file mode 100644 index 89c580799fc8..000000000000 --- a/contrib/go/_std_1.22/src/syscall/msan.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build msan - -package syscall - -import ( - "runtime" - "unsafe" -) - -const msanenabled = true - -func msanRead(addr unsafe.Pointer, len int) { - runtime.MSanRead(addr, len) -} - -func msanWrite(addr unsafe.Pointer, len int) { - runtime.MSanWrite(addr, len) -} diff --git a/contrib/go/_std_1.22/src/syscall/msan0.go b/contrib/go/_std_1.22/src/syscall/msan0.go deleted file mode 100644 index fba8a5f716ed..000000000000 --- a/contrib/go/_std_1.22/src/syscall/msan0.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !msan - -package syscall - -import ( - "unsafe" -) - -const msanenabled = false - -func msanRead(addr unsafe.Pointer, len int) { -} - -func msanWrite(addr unsafe.Pointer, len int) { -} diff --git a/contrib/go/_std_1.22/src/time/sleep.go b/contrib/go/_std_1.22/src/time/sleep.go deleted file mode 100644 index 0aec4cacc6bf..000000000000 --- a/contrib/go/_std_1.22/src/time/sleep.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package time - -// Sleep pauses the current goroutine for at least the duration d. -// A negative or zero duration causes Sleep to return immediately. -func Sleep(d Duration) - -// Interface to timers implemented in package runtime. -// Must be in sync with ../runtime/time.go:/^type timer -type runtimeTimer struct { - pp uintptr - when int64 - period int64 - f func(any, uintptr) // NOTE: must not be closure - arg any - seq uintptr - nextwhen int64 - status uint32 -} - -// when is a helper function for setting the 'when' field of a runtimeTimer. -// It returns what the time will be, in nanoseconds, Duration d in the future. -// If d is negative, it is ignored. If the returned value would be less than -// zero because of an overflow, MaxInt64 is returned. -func when(d Duration) int64 { - if d <= 0 { - return runtimeNano() - } - t := runtimeNano() + int64(d) - if t < 0 { - // N.B. runtimeNano() and d are always positive, so addition - // (including overflow) will never result in t == 0. - t = 1<<63 - 1 // math.MaxInt64 - } - return t -} - -func startTimer(*runtimeTimer) -func stopTimer(*runtimeTimer) bool -func resetTimer(*runtimeTimer, int64) bool -func modTimer(t *runtimeTimer, when, period int64, f func(any, uintptr), arg any, seq uintptr) - -// The Timer type represents a single event. -// When the Timer expires, the current time will be sent on C, -// unless the Timer was created by AfterFunc. -// A Timer must be created with NewTimer or AfterFunc. -type Timer struct { - C <-chan Time - r runtimeTimer -} - -// Stop prevents the Timer from firing. -// It returns true if the call stops the timer, false if the timer has already -// expired or been stopped. -// Stop does not close the channel, to prevent a read from the channel succeeding -// incorrectly. -// -// To ensure the channel is empty after a call to Stop, check the -// return value and drain the channel. -// For example, assuming the program has not received from t.C already: -// -// if !t.Stop() { -// <-t.C -// } -// -// This cannot be done concurrent to other receives from the Timer's -// channel or other calls to the Timer's Stop method. -// -// For a timer created with AfterFunc(d, f), if t.Stop returns false, then the timer -// has already expired and the function f has been started in its own goroutine; -// Stop does not wait for f to complete before returning. -// If the caller needs to know whether f is completed, it must coordinate -// with f explicitly. -func (t *Timer) Stop() bool { - if t.r.f == nil { - panic("time: Stop called on uninitialized Timer") - } - return stopTimer(&t.r) -} - -// NewTimer creates a new Timer that will send -// the current time on its channel after at least duration d. -func NewTimer(d Duration) *Timer { - c := make(chan Time, 1) - t := &Timer{ - C: c, - r: runtimeTimer{ - when: when(d), - f: sendTime, - arg: c, - }, - } - startTimer(&t.r) - return t -} - -// Reset changes the timer to expire after duration d. -// It returns true if the timer had been active, false if the timer had -// expired or been stopped. -// -// For a Timer created with NewTimer, Reset should be invoked only on -// stopped or expired timers with drained channels. -// -// If a program has already received a value from t.C, the timer is known -// to have expired and the channel drained, so t.Reset can be used directly. -// If a program has not yet received a value from t.C, however, -// the timer must be stopped and—if Stop reports that the timer expired -// before being stopped—the channel explicitly drained: -// -// if !t.Stop() { -// <-t.C -// } -// t.Reset(d) -// -// This should not be done concurrent to other receives from the Timer's -// channel. -// -// Note that it is not possible to use Reset's return value correctly, as there -// is a race condition between draining the channel and the new timer expiring. -// Reset should always be invoked on stopped or expired channels, as described above. -// The return value exists to preserve compatibility with existing programs. -// -// For a Timer created with AfterFunc(d, f), Reset either reschedules -// when f will run, in which case Reset returns true, or schedules f -// to run again, in which case it returns false. -// When Reset returns false, Reset neither waits for the prior f to -// complete before returning nor does it guarantee that the subsequent -// goroutine running f does not run concurrently with the prior -// one. If the caller needs to know whether the prior execution of -// f is completed, it must coordinate with f explicitly. -func (t *Timer) Reset(d Duration) bool { - if t.r.f == nil { - panic("time: Reset called on uninitialized Timer") - } - w := when(d) - return resetTimer(&t.r, w) -} - -// sendTime does a non-blocking send of the current time on c. -func sendTime(c any, seq uintptr) { - select { - case c.(chan Time) <- Now(): - default: - } -} - -// After waits for the duration to elapse and then sends the current time -// on the returned channel. -// It is equivalent to NewTimer(d).C. -// The underlying Timer is not recovered by the garbage collector -// until the timer fires. If efficiency is a concern, use NewTimer -// instead and call Timer.Stop if the timer is no longer needed. -func After(d Duration) <-chan Time { - return NewTimer(d).C -} - -// AfterFunc waits for the duration to elapse and then calls f -// in its own goroutine. It returns a Timer that can -// be used to cancel the call using its Stop method. -// The returned Timer's C field is not used and will be nil. -func AfterFunc(d Duration, f func()) *Timer { - t := &Timer{ - r: runtimeTimer{ - when: when(d), - f: goFunc, - arg: f, - }, - } - startTimer(&t.r) - return t -} - -func goFunc(arg any, seq uintptr) { - go arg.(func())() -} diff --git a/contrib/go/_std_1.22/src/time/tick.go b/contrib/go/_std_1.22/src/time/tick.go deleted file mode 100644 index 9da16b5d5830..000000000000 --- a/contrib/go/_std_1.22/src/time/tick.go +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package time - -// A Ticker holds a channel that delivers “ticks” of a clock -// at intervals. -type Ticker struct { - C <-chan Time // The channel on which the ticks are delivered. - r runtimeTimer -} - -// NewTicker returns a new Ticker containing a channel that will send -// the current time on the channel after each tick. The period of the -// ticks is specified by the duration argument. The ticker will adjust -// the time interval or drop ticks to make up for slow receivers. -// The duration d must be greater than zero; if not, NewTicker will -// panic. Stop the ticker to release associated resources. -func NewTicker(d Duration) *Ticker { - if d <= 0 { - panic("non-positive interval for NewTicker") - } - // Give the channel a 1-element time buffer. - // If the client falls behind while reading, we drop ticks - // on the floor until the client catches up. - c := make(chan Time, 1) - t := &Ticker{ - C: c, - r: runtimeTimer{ - when: when(d), - period: int64(d), - f: sendTime, - arg: c, - }, - } - startTimer(&t.r) - return t -} - -// Stop turns off a ticker. After Stop, no more ticks will be sent. -// Stop does not close the channel, to prevent a concurrent goroutine -// reading from the channel from seeing an erroneous "tick". -func (t *Ticker) Stop() { - stopTimer(&t.r) -} - -// Reset stops a ticker and resets its period to the specified duration. -// The next tick will arrive after the new period elapses. The duration d -// must be greater than zero; if not, Reset will panic. -func (t *Ticker) Reset(d Duration) { - if d <= 0 { - panic("non-positive interval for Ticker.Reset") - } - if t.r.f == nil { - panic("time: Reset called on uninitialized Ticker") - } - modTimer(&t.r, when(d), int64(d), t.r.f, t.r.arg, t.r.seq) -} - -// Tick is a convenience wrapper for NewTicker providing access to the ticking -// channel only. While Tick is useful for clients that have no need to shut down -// the Ticker, be aware that without a way to shut it down the underlying -// Ticker cannot be recovered by the garbage collector; it "leaks". -// Unlike NewTicker, Tick will return nil if d <= 0. -func Tick(d Duration) <-chan Time { - if d <= 0 { - return nil - } - return NewTicker(d).C -} diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go b/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go deleted file mode 100644 index d33c8890fc53..000000000000 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/bits_compat.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build !go1.13 - -package poly1305 - -// Generic fallbacks for the math/bits intrinsics, copied from -// src/math/bits/bits.go. They were added in Go 1.12, but Add64 and Sum64 had -// variable time fallbacks until Go 1.13. - -func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) { - sum = x + y + carry - carryOut = ((x & y) | ((x | y) &^ sum)) >> 63 - return -} - -func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) { - diff = x - y - borrow - borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63 - return -} - -func bitsMul64(x, y uint64) (hi, lo uint64) { - const mask32 = 1<<32 - 1 - x0 := x & mask32 - x1 := x >> 32 - y0 := y & mask32 - y1 := y >> 32 - w0 := x0 * y0 - t := x1*y0 + w0>>32 - w1 := t & mask32 - w2 := t >> 32 - w1 += x0 * y1 - hi = x1*y1 + w2 + w1>>32 - lo = x * y - return -} diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go b/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go deleted file mode 100644 index 495c1fa69725..000000000000 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/bits_go1.13.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2019 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -//go:build go1.13 - -package poly1305 - -import "math/bits" - -func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) { - return bits.Add64(x, y, carry) -} - -func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) { - return bits.Sub64(x, y, borrow) -} - -func bitsMul64(x, y uint64) (hi, lo uint64) { - return bits.Mul64(x, y) -} diff --git a/contrib/go/_std_1.22/src/bufio/bufio.go b/contrib/go/_std_1.23/src/bufio/bufio.go similarity index 100% rename from contrib/go/_std_1.22/src/bufio/bufio.go rename to contrib/go/_std_1.23/src/bufio/bufio.go diff --git a/contrib/go/_std_1.22/src/bufio/scan.go b/contrib/go/_std_1.23/src/bufio/scan.go similarity index 100% rename from contrib/go/_std_1.22/src/bufio/scan.go rename to contrib/go/_std_1.23/src/bufio/scan.go diff --git a/contrib/go/_std_1.22/src/bufio/ya.make b/contrib/go/_std_1.23/src/bufio/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/bufio/ya.make rename to contrib/go/_std_1.23/src/bufio/ya.make diff --git a/contrib/go/_std_1.22/src/bytes/buffer.go b/contrib/go/_std_1.23/src/bytes/buffer.go similarity index 97% rename from contrib/go/_std_1.22/src/bytes/buffer.go rename to contrib/go/_std_1.23/src/bytes/buffer.go index ba844ba9d3c6..4176d670ec83 100644 --- a/contrib/go/_std_1.22/src/bytes/buffer.go +++ b/contrib/go/_std_1.23/src/bytes/buffer.go @@ -62,7 +62,7 @@ func (b *Buffer) AvailableBuffer() []byte { return b.buf[len(b.buf):] } // String returns the contents of the unread portion of the buffer // as a string. If the [Buffer] is a nil pointer, it returns "". // -// To build strings more efficiently, see the strings.Builder type. +// To build strings more efficiently, see the [strings.Builder] type. func (b *Buffer) String() string { if b == nil { // Special case, useful in debugging. @@ -193,9 +193,9 @@ func (b *Buffer) WriteString(s string) (n int, err error) { return copy(b.buf[m:], s), nil } -// MinRead is the minimum slice size passed to a Read call by +// MinRead is the minimum slice size passed to a [Buffer.Read] call by // [Buffer.ReadFrom]. As long as the [Buffer] has at least MinRead bytes beyond -// what is required to hold the contents of r, ReadFrom will not grow the +// what is required to hold the contents of r, [Buffer.ReadFrom] will not grow the // underlying buffer. const MinRead = 512 @@ -253,7 +253,7 @@ func growSlice(b []byte, n int) []byte { // WriteTo writes data to w until the buffer is drained or an error occurs. // The return value n is the number of bytes written; it always fits into an -// int, but it is int64 to match the io.WriterTo interface. Any error +// int, but it is int64 to match the [io.WriterTo] interface. Any error // encountered during the write is also returned. func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) { b.lastRead = opInvalid @@ -313,7 +313,7 @@ func (b *Buffer) WriteRune(r rune) (n int, err error) { // Read reads the next len(p) bytes from the buffer or until the buffer // is drained. The return value n is the number of bytes read. If the -// buffer has no data to return, err is io.EOF (unless len(p) is zero); +// buffer has no data to return, err is [io.EOF] (unless len(p) is zero); // otherwise it is nil. func (b *Buffer) Read(p []byte) (n int, err error) { b.lastRead = opInvalid @@ -352,7 +352,7 @@ func (b *Buffer) Next(n int) []byte { } // ReadByte reads and returns the next byte from the buffer. -// If no byte is available, it returns error io.EOF. +// If no byte is available, it returns error [io.EOF]. func (b *Buffer) ReadByte() (byte, error) { if b.empty() { // Buffer is empty, reset to recover space. @@ -424,7 +424,7 @@ func (b *Buffer) UnreadByte() error { // ReadBytes reads until the first occurrence of delim in the input, // returning a slice containing the data up to and including the delimiter. // If ReadBytes encounters an error before finding a delimiter, -// it returns the data read before the error and the error itself (often io.EOF). +// it returns the data read before the error and the error itself (often [io.EOF]). // ReadBytes returns err != nil if and only if the returned data does not end in // delim. func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) { @@ -452,7 +452,7 @@ func (b *Buffer) readSlice(delim byte) (line []byte, err error) { // ReadString reads until the first occurrence of delim in the input, // returning a string containing the data up to and including the delimiter. // If ReadString encounters an error before finding a delimiter, -// it returns the data read before the error and the error itself (often io.EOF). +// it returns the data read before the error and the error itself (often [io.EOF]). // ReadString returns err != nil if and only if the returned data does not end // in delim. func (b *Buffer) ReadString(delim byte) (line string, err error) { diff --git a/contrib/go/_std_1.22/src/bytes/bytes.go b/contrib/go/_std_1.23/src/bytes/bytes.go similarity index 96% rename from contrib/go/_std_1.22/src/bytes/bytes.go rename to contrib/go/_std_1.23/src/bytes/bytes.go index 0679b43a20a3..45d8d0747535 100644 --- a/contrib/go/_std_1.22/src/bytes/bytes.go +++ b/contrib/go/_std_1.23/src/bytes/bytes.go @@ -10,6 +10,7 @@ import ( "internal/bytealg" "unicode" "unicode/utf8" + _ "unsafe" // for linkname ) // Equal reports whether a and b @@ -132,7 +133,7 @@ func LastIndexByte(s []byte, c byte) int { // IndexRune interprets s as a sequence of UTF-8-encoded code points. // It returns the byte index of the first occurrence in s of the given rune. // It returns -1 if rune is not present in s. -// If r is utf8.RuneError, it returns the first instance of any +// If r is [utf8.RuneError], it returns the first instance of any // invalid UTF-8 byte sequence. func IndexRune(s []byte, r rune) int { switch { @@ -354,22 +355,20 @@ func genSplit(s, sep []byte, sepSave, n int) [][]byte { // the subslices between those separators. // If sep is empty, SplitN splits after each UTF-8 sequence. // The count determines the number of subslices to return: +// - n > 0: at most n subslices; the last subslice will be the unsplit remainder; +// - n == 0: the result is nil (zero subslices); +// - n < 0: all subslices. // -// n > 0: at most n subslices; the last subslice will be the unsplit remainder. -// n == 0: the result is nil (zero subslices) -// n < 0: all subslices -// -// To split around the first instance of a separator, see Cut. +// To split around the first instance of a separator, see [Cut]. func SplitN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) } // SplitAfterN slices s into subslices after each instance of sep and // returns a slice of those subslices. // If sep is empty, SplitAfterN splits after each UTF-8 sequence. // The count determines the number of subslices to return: -// -// n > 0: at most n subslices; the last subslice will be the unsplit remainder. -// n == 0: the result is nil (zero subslices) -// n < 0: all subslices +// - n > 0: at most n subslices; the last subslice will be the unsplit remainder; +// - n == 0: the result is nil (zero subslices); +// - n < 0: all subslices. func SplitAfterN(s, sep []byte, n int) [][]byte { return genSplit(s, sep, len(sep), n) } @@ -379,7 +378,7 @@ func SplitAfterN(s, sep []byte, n int) [][]byte { // If sep is empty, Split splits after each UTF-8 sequence. // It is equivalent to SplitN with a count of -1. // -// To split around the first instance of a separator, see Cut. +// To split around the first instance of a separator, see [Cut]. func Split(s, sep []byte) [][]byte { return genSplit(s, sep, 0, -1) } // SplitAfter slices s into all subslices after each instance of sep and @@ -394,7 +393,7 @@ var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1} // Fields interprets s as a sequence of UTF-8-encoded code points. // It splits the slice s around each instance of one or more consecutive white space -// characters, as defined by unicode.IsSpace, returning a slice of subslices of s or an +// characters, as defined by [unicode.IsSpace], returning a slice of subslices of s or an // empty slice if s contains only white space. func Fields(s []byte) [][]byte { // First count the fields. @@ -525,7 +524,7 @@ func Join(s [][]byte, sep []byte) []byte { n += len(v) } - b := bytealg.MakeNoZero(n) + b := bytealg.MakeNoZero(n)[:n:n] bp := copy(b, s[0]) for _, v := range s[1:] { bp += copy(b[bp:], sep) @@ -568,6 +567,18 @@ func Map(mapping func(r rune) rune, s []byte) []byte { return b } +// Despite being an exported symbol, +// Repeat is linknamed by widely used packages. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/num +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +// Note that this comment is not part of the doc comment. +// +//go:linkname Repeat + // Repeat returns a new byte slice consisting of count copies of b. // // It panics if count is negative or if the result of (len(b) * count) @@ -583,7 +594,7 @@ func Repeat(b []byte, count int) []byte { if count < 0 { panic("bytes: negative Repeat count") } - if len(b) >= maxInt/count { + if len(b) > maxInt/count { panic("bytes: Repeat output length overflow") } n := len(b) * count @@ -610,7 +621,7 @@ func Repeat(b []byte, count int) []byte { chunkMax = len(b) } } - nb := bytealg.MakeNoZero(n) + nb := bytealg.MakeNoZero(n)[:n:n] bp := copy(nb, b) for bp < n { chunk := bp @@ -640,7 +651,7 @@ func ToUpper(s []byte) []byte { // Just return a copy. return append([]byte(""), s...) } - b := bytealg.MakeNoZero(len(s)) + b := bytealg.MakeNoZero(len(s))[:len(s):len(s)] for i := 0; i < len(s); i++ { c := s[i] if 'a' <= c && c <= 'z' { @@ -670,7 +681,7 @@ func ToLower(s []byte) []byte { if !hasUpper { return append([]byte(""), s...) } - b := bytealg.MakeNoZero(len(s)) + b := bytealg.MakeNoZero(len(s))[:len(s):len(s)] for i := 0; i < len(s); i++ { c := s[i] if 'A' <= c && c <= 'Z' { diff --git a/contrib/go/_std_1.22/src/bytes/reader.go b/contrib/go/_std_1.23/src/bytes/reader.go similarity index 93% rename from contrib/go/_std_1.22/src/bytes/reader.go rename to contrib/go/_std_1.23/src/bytes/reader.go index 9ef49014edfa..d4c3066e0620 100644 --- a/contrib/go/_std_1.22/src/bytes/reader.go +++ b/contrib/go/_std_1.23/src/bytes/reader.go @@ -10,8 +10,8 @@ import ( "unicode/utf8" ) -// A Reader implements the io.Reader, io.ReaderAt, io.WriterTo, io.Seeker, -// io.ByteScanner, and io.RuneScanner interfaces by reading from +// A Reader implements the [io.Reader], [io.ReaderAt], [io.WriterTo], [io.Seeker], +// [io.ByteScanner], and [io.RuneScanner] interfaces by reading from // a byte slice. // Unlike a [Buffer], a Reader is read-only and supports seeking. // The zero value for Reader operates like a Reader of an empty slice. @@ -152,8 +152,8 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) { return } -// Reset resets the [Reader.Reader] to be reading from b. +// Reset resets the [Reader] to be reading from b. func (r *Reader) Reset(b []byte) { *r = Reader{b, 0, -1} } -// NewReader returns a new [Reader.Reader] reading from b. +// NewReader returns a new [Reader] reading from b. func NewReader(b []byte) *Reader { return &Reader{b, 0, -1} } diff --git a/contrib/go/_std_1.22/src/bytes/ya.make b/contrib/go/_std_1.23/src/bytes/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/bytes/ya.make rename to contrib/go/_std_1.23/src/bytes/ya.make diff --git a/contrib/go/_std_1.22/src/cmp/cmp.go b/contrib/go/_std_1.23/src/cmp/cmp.go similarity index 95% rename from contrib/go/_std_1.22/src/cmp/cmp.go rename to contrib/go/_std_1.23/src/cmp/cmp.go index 4d1af6a98c4e..a13834c39858 100644 --- a/contrib/go/_std_1.22/src/cmp/cmp.go +++ b/contrib/go/_std_1.23/src/cmp/cmp.go @@ -40,13 +40,19 @@ func Less[T Ordered](x, y T) bool { func Compare[T Ordered](x, y T) int { xNaN := isNaN(x) yNaN := isNaN(y) - if xNaN && yNaN { - return 0 + if xNaN { + if yNaN { + return 0 + } + return -1 + } + if yNaN { + return +1 } - if xNaN || x < y { + if x < y { return -1 } - if yNaN || x > y { + if x > y { return +1 } return 0 diff --git a/contrib/go/_std_1.22/src/cmp/ya.make b/contrib/go/_std_1.23/src/cmp/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/cmp/ya.make rename to contrib/go/_std_1.23/src/cmp/ya.make diff --git a/contrib/go/_std_1.22/src/compress/flate/deflate.go b/contrib/go/_std_1.23/src/compress/flate/deflate.go similarity index 99% rename from contrib/go/_std_1.22/src/compress/flate/deflate.go rename to contrib/go/_std_1.23/src/compress/flate/deflate.go index ea343b2298f3..0e07afab7de7 100644 --- a/contrib/go/_std_1.22/src/compress/flate/deflate.go +++ b/contrib/go/_std_1.23/src/compress/flate/deflate.go @@ -87,7 +87,6 @@ type compressor struct { // compression algorithm fill func(*compressor, []byte) int // copy data to window step func(*compressor) // process window - sync bool // requesting flush bestSpeed *deflateFast // Encoder for BestSpeed // Input hash chains @@ -107,6 +106,8 @@ type compressor struct { blockStart int // window index where current tokens start byteAvailable bool // if true, still need to process window[index-1]. + sync bool // requesting flush + // queued output tokens tokens []token diff --git a/contrib/go/_std_1.22/src/compress/flate/deflatefast.go b/contrib/go/_std_1.23/src/compress/flate/deflatefast.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/flate/deflatefast.go rename to contrib/go/_std_1.23/src/compress/flate/deflatefast.go diff --git a/contrib/go/_std_1.22/src/compress/flate/dict_decoder.go b/contrib/go/_std_1.23/src/compress/flate/dict_decoder.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/flate/dict_decoder.go rename to contrib/go/_std_1.23/src/compress/flate/dict_decoder.go diff --git a/contrib/go/_std_1.22/src/compress/flate/huffman_bit_writer.go b/contrib/go/_std_1.23/src/compress/flate/huffman_bit_writer.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/flate/huffman_bit_writer.go rename to contrib/go/_std_1.23/src/compress/flate/huffman_bit_writer.go diff --git a/contrib/go/_std_1.22/src/compress/flate/huffman_code.go b/contrib/go/_std_1.23/src/compress/flate/huffman_code.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/flate/huffman_code.go rename to contrib/go/_std_1.23/src/compress/flate/huffman_code.go diff --git a/contrib/go/_std_1.22/src/compress/flate/inflate.go b/contrib/go/_std_1.23/src/compress/flate/inflate.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/flate/inflate.go rename to contrib/go/_std_1.23/src/compress/flate/inflate.go diff --git a/contrib/go/_std_1.22/src/compress/flate/token.go b/contrib/go/_std_1.23/src/compress/flate/token.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/flate/token.go rename to contrib/go/_std_1.23/src/compress/flate/token.go diff --git a/contrib/go/_std_1.22/src/compress/flate/ya.make b/contrib/go/_std_1.23/src/compress/flate/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/compress/flate/ya.make rename to contrib/go/_std_1.23/src/compress/flate/ya.make diff --git a/contrib/go/_std_1.22/src/compress/gzip/gunzip.go b/contrib/go/_std_1.23/src/compress/gzip/gunzip.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/gzip/gunzip.go rename to contrib/go/_std_1.23/src/compress/gzip/gunzip.go diff --git a/contrib/go/_std_1.22/src/compress/gzip/gzip.go b/contrib/go/_std_1.23/src/compress/gzip/gzip.go similarity index 100% rename from contrib/go/_std_1.22/src/compress/gzip/gzip.go rename to contrib/go/_std_1.23/src/compress/gzip/gzip.go index ab4598d89fda..5f24444237ce 100644 --- a/contrib/go/_std_1.22/src/compress/gzip/gzip.go +++ b/contrib/go/_std_1.23/src/compress/gzip/gzip.go @@ -30,11 +30,11 @@ type Writer struct { w io.Writer level int wroteHeader bool + closed bool + buf [10]byte compressor *flate.Writer digest uint32 // CRC-32, IEEE polynomial (section 8) size uint32 // Uncompressed size (section 2.3.1) - closed bool - buf [10]byte err error } diff --git a/contrib/go/_std_1.22/src/compress/gzip/ya.make b/contrib/go/_std_1.23/src/compress/gzip/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/compress/gzip/ya.make rename to contrib/go/_std_1.23/src/compress/gzip/ya.make diff --git a/contrib/go/_std_1.22/src/container/heap/heap.go b/contrib/go/_std_1.23/src/container/heap/heap.go similarity index 100% rename from contrib/go/_std_1.22/src/container/heap/heap.go rename to contrib/go/_std_1.23/src/container/heap/heap.go diff --git a/contrib/go/_std_1.22/src/container/heap/ya.make b/contrib/go/_std_1.23/src/container/heap/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/container/heap/ya.make rename to contrib/go/_std_1.23/src/container/heap/ya.make diff --git a/contrib/go/_std_1.22/src/container/list/list.go b/contrib/go/_std_1.23/src/container/list/list.go similarity index 100% rename from contrib/go/_std_1.22/src/container/list/list.go rename to contrib/go/_std_1.23/src/container/list/list.go diff --git a/contrib/go/_std_1.22/src/container/list/ya.make b/contrib/go/_std_1.23/src/container/list/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/container/list/ya.make rename to contrib/go/_std_1.23/src/container/list/ya.make diff --git a/contrib/go/_std_1.22/src/context/context.go b/contrib/go/_std_1.23/src/context/context.go similarity index 98% rename from contrib/go/_std_1.22/src/context/context.go rename to contrib/go/_std_1.23/src/context/context.go index 80e178757636..763d4f777ffb 100644 --- a/contrib/go/_std_1.22/src/context/context.go +++ b/contrib/go/_std_1.23/src/context/context.go @@ -231,7 +231,7 @@ type CancelFunc func() // or when the parent context's Done channel is closed, whichever happens first. // // Canceling this context releases resources associated with it, so code should -// call cancel as soon as the operations running in this Context complete. +// call cancel as soon as the operations running in this [Context] complete. func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { c := withCancel(parent) return c, func() { c.cancel(true, Canceled, nil) } @@ -295,7 +295,7 @@ func Cause(c Context) error { } // AfterFunc arranges to call f in its own goroutine after ctx is done -// (cancelled or timed out). +// (canceled or timed out). // If ctx is already done, AfterFunc calls f immediately in its own goroutine. // // Multiple calls to AfterFunc on a context operate independently; @@ -739,14 +739,16 @@ func stringify(v any) string { return s.String() case string: return s + case nil: + return "" } - return "" + return reflectlite.TypeOf(v).String() } func (c *valueCtx) String() string { - return contextName(c.Context) + ".WithValue(type " + - reflectlite.TypeOf(c.key).String() + - ", val " + stringify(c.val) + ")" + return contextName(c.Context) + ".WithValue(" + + stringify(c.key) + ", " + + stringify(c.val) + ")" } func (c *valueCtx) Value(key any) any { diff --git a/contrib/go/_std_1.22/src/context/ya.make b/contrib/go/_std_1.23/src/context/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/context/ya.make rename to contrib/go/_std_1.23/src/context/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/aes/aes_gcm.go b/contrib/go/_std_1.23/src/crypto/aes/aes_gcm.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/aes/aes_gcm.go rename to contrib/go/_std_1.23/src/crypto/aes/aes_gcm.go index 036705fecaac..d9a9545f120f 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/aes_gcm.go +++ b/contrib/go/_std_1.23/src/crypto/aes/aes_gcm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build amd64 || arm64 +//go:build (amd64 || arm64) && !purego package aes @@ -45,7 +45,7 @@ var _ gcmAble = (*aesCipherGCM)(nil) // NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only // called by [crypto/cipher.NewGCM] via the gcmAble interface. func (c *aesCipherGCM) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) { - g := &gcmAsm{ks: c.enc, nonceSize: nonceSize, tagSize: tagSize} + g := &gcmAsm{ks: c.enc[:c.l], nonceSize: nonceSize, tagSize: tagSize} gcmAesInit(&g.productTable, g.ks) return g, nil } @@ -176,9 +176,7 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { gcmAesFinish(&g.productTable, &tagMask, &expectedTag, uint64(len(ciphertext)), uint64(len(data))) if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { - for i := range out { - out[i] = 0 - } + clear(out) return nil, errOpen } diff --git a/contrib/go/_std_1.22/src/crypto/aes/asm_amd64.s b/contrib/go/_std_1.23/src/crypto/aes/asm_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/aes/asm_amd64.s rename to contrib/go/_std_1.23/src/crypto/aes/asm_amd64.s index ed831bf47ff2..d5e17401ea0e 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/asm_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/aes/asm_amd64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // func encryptBlockAsm(nr int, xk *uint32, dst, src *byte) diff --git a/contrib/go/_std_1.22/src/crypto/aes/asm_arm64.s b/contrib/go/_std_1.23/src/crypto/aes/asm_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/aes/asm_arm64.s rename to contrib/go/_std_1.23/src/crypto/aes/asm_arm64.s index 4a02e943ce31..2bf5bee2b59f 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/asm_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/aes/asm_arm64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" DATA rotInvSRows<>+0x00(SB)/8, $0x080f0205040b0e01 DATA rotInvSRows<>+0x08(SB)/8, $0x00070a0d0c030609 diff --git a/contrib/go/_std_1.22/src/crypto/aes/asm_ppc64x.s b/contrib/go/_std_1.23/src/crypto/aes/asm_ppc64x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/aes/asm_ppc64x.s rename to contrib/go/_std_1.23/src/crypto/aes/asm_ppc64x.s index 288f7256c7c5..5a2b210920ed 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/asm_ppc64x.s +++ b/contrib/go/_std_1.23/src/crypto/aes/asm_ppc64x.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build ppc64 || ppc64le +//go:build (ppc64 || ppc64le) && !purego // Based on CRYPTOGAMS code with the following comment: // # ==================================================================== @@ -151,7 +151,7 @@ loop128: VXOR IN0, TMP, IN0 // vxor 1,1,6 VADDUWM RCON, RCON, RCON // vadduwm 4,4,4 VXOR IN0, KEY, IN0 // vxor 1,1,3 - BC 0x10, 0, loop128 // bdnz .Loop128 + BDNZ loop128 LVX (PTR)(R0), RCON // lvx 4,0,6 Last two round keys @@ -256,7 +256,7 @@ loop192: STXVD2X IN0, (R0+OUTDEC) ADD $16, OUTENC, OUTENC ADD $-16, OUTDEC, OUTDEC - BC 0x10, 0, loop192 // bdnz .Loop192 + BDNZ loop192 RET @@ -289,7 +289,7 @@ loop256: STXVD2X IN0, (R0+OUTDEC) ADD $16, OUTENC, OUTENC ADD $-16, OUTDEC, OUTDEC - BC 0x12, 0, done // bdz .Ldone + BDZ done VSPLTW $3, IN0, KEY // vspltw 3,1,3 VSLDOI $12, ZERO, IN1, TMP // vsldoi 6,0,2,12 diff --git a/contrib/go/_std_1.22/src/crypto/aes/asm_s390x.s b/contrib/go/_std_1.23/src/crypto/aes/asm_s390x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/aes/asm_s390x.s rename to contrib/go/_std_1.23/src/crypto/aes/asm_s390x.s index a233714fb8e3..5da0d8bf9cb3 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/asm_s390x.s +++ b/contrib/go/_std_1.23/src/crypto/aes/asm_s390x.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // func cryptBlocks(c code, key, dst, src *byte, length int) diff --git a/contrib/go/_std_1.22/src/crypto/aes/block.go b/contrib/go/_std_1.23/src/crypto/aes/block.go similarity index 88% rename from contrib/go/_std_1.22/src/crypto/aes/block.go rename to contrib/go/_std_1.23/src/crypto/aes/block.go index 53308ae92e33..618eb7752a40 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/block.go +++ b/contrib/go/_std_1.23/src/crypto/aes/block.go @@ -36,17 +36,15 @@ package aes -import ( - "encoding/binary" -) +import "internal/byteorder" // Encrypt one block from src into dst, using the expanded key xk. func encryptBlockGo(xk []uint32, dst, src []byte) { _ = src[15] // early bounds check - s0 := binary.BigEndian.Uint32(src[0:4]) - s1 := binary.BigEndian.Uint32(src[4:8]) - s2 := binary.BigEndian.Uint32(src[8:12]) - s3 := binary.BigEndian.Uint32(src[12:16]) + s0 := byteorder.BeUint32(src[0:4]) + s1 := byteorder.BeUint32(src[4:8]) + s2 := byteorder.BeUint32(src[8:12]) + s3 := byteorder.BeUint32(src[12:16]) // First round just XORs input with key. s0 ^= xk[0] @@ -80,19 +78,19 @@ func encryptBlockGo(xk []uint32, dst, src []byte) { s3 ^= xk[k+3] _ = dst[15] // early bounds check - binary.BigEndian.PutUint32(dst[0:4], s0) - binary.BigEndian.PutUint32(dst[4:8], s1) - binary.BigEndian.PutUint32(dst[8:12], s2) - binary.BigEndian.PutUint32(dst[12:16], s3) + byteorder.BePutUint32(dst[0:4], s0) + byteorder.BePutUint32(dst[4:8], s1) + byteorder.BePutUint32(dst[8:12], s2) + byteorder.BePutUint32(dst[12:16], s3) } // Decrypt one block from src into dst, using the expanded key xk. func decryptBlockGo(xk []uint32, dst, src []byte) { _ = src[15] // early bounds check - s0 := binary.BigEndian.Uint32(src[0:4]) - s1 := binary.BigEndian.Uint32(src[4:8]) - s2 := binary.BigEndian.Uint32(src[8:12]) - s3 := binary.BigEndian.Uint32(src[12:16]) + s0 := byteorder.BeUint32(src[0:4]) + s1 := byteorder.BeUint32(src[4:8]) + s2 := byteorder.BeUint32(src[8:12]) + s3 := byteorder.BeUint32(src[12:16]) // First round just XORs input with key. s0 ^= xk[0] @@ -126,10 +124,10 @@ func decryptBlockGo(xk []uint32, dst, src []byte) { s3 ^= xk[k+3] _ = dst[15] // early bounds check - binary.BigEndian.PutUint32(dst[0:4], s0) - binary.BigEndian.PutUint32(dst[4:8], s1) - binary.BigEndian.PutUint32(dst[8:12], s2) - binary.BigEndian.PutUint32(dst[12:16], s3) + byteorder.BePutUint32(dst[0:4], s0) + byteorder.BePutUint32(dst[4:8], s1) + byteorder.BePutUint32(dst[8:12], s2) + byteorder.BePutUint32(dst[12:16], s3) } // Apply sbox0 to each byte in w. @@ -150,7 +148,7 @@ func expandKeyGo(key []byte, enc, dec []uint32) { var i int nk := len(key) / 4 for i = 0; i < nk; i++ { - enc[i] = binary.BigEndian.Uint32(key[4*i:]) + enc[i] = byteorder.BeUint32(key[4*i:]) } for ; i < len(enc); i++ { t := enc[i-1] diff --git a/contrib/go/_std_1.22/src/crypto/aes/cbc_ppc64x.go b/contrib/go/_std_1.23/src/crypto/aes/cbc_ppc64x.go similarity index 94% rename from contrib/go/_std_1.22/src/crypto/aes/cbc_ppc64x.go rename to contrib/go/_std_1.23/src/crypto/aes/cbc_ppc64x.go index c23c37156e51..d5b491e8e1fe 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/cbc_ppc64x.go +++ b/contrib/go/_std_1.23/src/crypto/aes/cbc_ppc64x.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build ppc64 || ppc64le +//go:build (ppc64 || ppc64le) && !purego package aes @@ -59,9 +59,9 @@ func (x *cbc) CryptBlocks(dst, src []byte) { } if len(src) > 0 { if x.enc == cbcEncrypt { - cryptBlocksChain(&src[0], &dst[0], len(src), &x.b.enc[0], &x.iv[0], x.enc, len(x.b.enc)/4-1) + cryptBlocksChain(&src[0], &dst[0], len(src), &x.b.enc[0], &x.iv[0], x.enc, int(x.b.l)/4-1) } else { - cryptBlocksChain(&src[0], &dst[0], len(src), &x.b.dec[0], &x.iv[0], x.enc, len(x.b.dec)/4-1) + cryptBlocksChain(&src[0], &dst[0], len(src), &x.b.dec[0], &x.iv[0], x.enc, int(x.b.l)/4-1) } } } diff --git a/contrib/go/_std_1.22/src/crypto/aes/cbc_s390x.go b/contrib/go/_std_1.23/src/crypto/aes/cbc_s390x.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/aes/cbc_s390x.go rename to contrib/go/_std_1.23/src/crypto/aes/cbc_s390x.go index eaa21f8a65f2..09c19ff39479 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/cbc_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/aes/cbc_s390x.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package aes import ( diff --git a/contrib/go/_std_1.22/src/crypto/aes/cipher.go b/contrib/go/_std_1.23/src/crypto/aes/cipher.go similarity index 86% rename from contrib/go/_std_1.22/src/crypto/aes/cipher.go rename to contrib/go/_std_1.23/src/crypto/aes/cipher.go index a9e6208696da..cde2e45d2ca5 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/cipher.go +++ b/contrib/go/_std_1.23/src/crypto/aes/cipher.go @@ -16,8 +16,9 @@ const BlockSize = 16 // A cipher is an instance of AES encryption using a particular key. type aesCipher struct { - enc []uint32 - dec []uint32 + l uint8 // only this length of the enc and dec array is actually used + enc [28 + 32]uint32 + dec [28 + 32]uint32 } type KeySizeError int @@ -47,9 +48,8 @@ func NewCipher(key []byte) (cipher.Block, error) { // newCipherGeneric creates and returns a new cipher.Block // implemented in pure Go. func newCipherGeneric(key []byte) (cipher.Block, error) { - n := len(key) + 28 - c := aesCipher{make([]uint32, n), make([]uint32, n)} - expandKeyGo(key, c.enc, c.dec) + c := aesCipher{l: uint8(len(key) + 28)} + expandKeyGo(key, c.enc[:c.l], c.dec[:c.l]) return &c, nil } @@ -65,7 +65,7 @@ func (c *aesCipher) Encrypt(dst, src []byte) { if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { panic("crypto/aes: invalid buffer overlap") } - encryptBlockGo(c.enc, dst, src) + encryptBlockGo(c.enc[:c.l], dst, src) } func (c *aesCipher) Decrypt(dst, src []byte) { @@ -78,5 +78,5 @@ func (c *aesCipher) Decrypt(dst, src []byte) { if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { panic("crypto/aes: invalid buffer overlap") } - decryptBlockGo(c.dec, dst, src) + decryptBlockGo(c.dec[:c.l], dst, src) } diff --git a/contrib/go/_std_1.22/src/crypto/aes/cipher_asm.go b/contrib/go/_std_1.23/src/crypto/aes/cipher_asm.go similarity index 85% rename from contrib/go/_std_1.22/src/crypto/aes/cipher_asm.go rename to contrib/go/_std_1.23/src/crypto/aes/cipher_asm.go index 90031c5e2c58..3e5f589c2cdd 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/cipher_asm.go +++ b/contrib/go/_std_1.23/src/crypto/aes/cipher_asm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build amd64 || arm64 || ppc64 || ppc64le +//go:build (amd64 || arm64 || ppc64 || ppc64le) && !purego package aes @@ -44,8 +44,9 @@ func newCipher(key []byte) (cipher.Block, error) { if !supportsAES { return newCipherGeneric(key) } - n := len(key) + 28 - c := aesCipherAsm{aesCipher{make([]uint32, n), make([]uint32, n)}} + // Note that under certain circumstances, we only return the inner aesCipherAsm. + // This avoids an unnecessary allocation of the aesCipher struct. + c := aesCipherGCM{aesCipherAsm{aesCipher{l: uint8(len(key) + 28)}}} var rounds int switch len(key) { case 128 / 8: @@ -60,9 +61,9 @@ func newCipher(key []byte) (cipher.Block, error) { expandKeyAsm(rounds, &key[0], &c.enc[0], &c.dec[0]) if supportsAES && supportsGFMUL { - return &aesCipherGCM{c}, nil + return &c, nil } - return &c, nil + return &c.aesCipherAsm, nil } func (c *aesCipherAsm) BlockSize() int { return BlockSize } @@ -78,7 +79,7 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) { if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { panic("crypto/aes: invalid buffer overlap") } - encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0]) + encryptBlockAsm(int(c.l)/4-1, &c.enc[0], &dst[0], &src[0]) } func (c *aesCipherAsm) Decrypt(dst, src []byte) { @@ -92,7 +93,7 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { panic("crypto/aes: invalid buffer overlap") } - decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0]) + decryptBlockAsm(int(c.l)/4-1, &c.dec[0], &dst[0], &src[0]) } // expandKey is used by BenchmarkExpand to ensure that the asm implementation diff --git a/contrib/go/_std_1.22/src/crypto/aes/cipher_generic.go b/contrib/go/_std_1.23/src/crypto/aes/cipher_generic.go similarity index 90% rename from contrib/go/_std_1.22/src/crypto/aes/cipher_generic.go rename to contrib/go/_std_1.23/src/crypto/aes/cipher_generic.go index 8a8a3fff3844..7c7d89aa873d 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/cipher_generic.go +++ b/contrib/go/_std_1.23/src/crypto/aes/cipher_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 && !s390x && !ppc64 && !ppc64le && !arm64 +//go:build (!amd64 && !s390x && !ppc64 && !ppc64le && !arm64) || purego package aes diff --git a/contrib/go/_std_1.22/src/crypto/aes/cipher_s390x.go b/contrib/go/_std_1.23/src/crypto/aes/cipher_s390x.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/aes/cipher_s390x.go rename to contrib/go/_std_1.23/src/crypto/aes/cipher_s390x.go index 8dd3d8f0537f..1541890deab7 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/cipher_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/aes/cipher_s390x.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package aes import ( diff --git a/contrib/go/_std_1.22/src/crypto/aes/const.go b/contrib/go/_std_1.23/src/crypto/aes/const.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/aes/const.go rename to contrib/go/_std_1.23/src/crypto/aes/const.go diff --git a/contrib/go/_std_1.22/src/crypto/aes/ctr_s390x.go b/contrib/go/_std_1.23/src/crypto/aes/ctr_s390x.go similarity index 90% rename from contrib/go/_std_1.22/src/crypto/aes/ctr_s390x.go rename to contrib/go/_std_1.23/src/crypto/aes/ctr_s390x.go index 921421533a44..56b82d58859c 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/ctr_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/aes/ctr_s390x.go @@ -2,12 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package aes import ( "crypto/cipher" "crypto/internal/alias" - "encoding/binary" + "internal/byteorder" ) // Assert that aesCipherAsm implements the ctrAble interface. @@ -39,8 +41,8 @@ func (c *aesCipherAsm) NewCTR(iv []byte) cipher.Stream { } var ac aesctr ac.block = c - ac.ctr[0] = binary.BigEndian.Uint64(iv[0:]) // high bits - ac.ctr[1] = binary.BigEndian.Uint64(iv[8:]) // low bits + ac.ctr[0] = byteorder.BeUint64(iv[0:]) // high bits + ac.ctr[1] = byteorder.BeUint64(iv[8:]) // low bits ac.buffer = ac.storage[:0] return &ac } @@ -50,8 +52,8 @@ func (c *aesctr) refill() { c.buffer = c.storage[:streamBufferSize] c0, c1 := c.ctr[0], c.ctr[1] for i := 0; i < streamBufferSize; i += 16 { - binary.BigEndian.PutUint64(c.buffer[i+0:], c0) - binary.BigEndian.PutUint64(c.buffer[i+8:], c1) + byteorder.BePutUint64(c.buffer[i+0:], c0) + byteorder.BePutUint64(c.buffer[i+8:], c1) // Increment in big endian: c0 is high, c1 is low. c1++ diff --git a/contrib/go/_std_1.22/src/crypto/aes/gcm_amd64.s b/contrib/go/_std_1.23/src/crypto/aes/gcm_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/aes/gcm_amd64.s rename to contrib/go/_std_1.23/src/crypto/aes/gcm_amd64.s index e6eedf326400..f787e6fd6bbe 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/gcm_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/aes/gcm_amd64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + // This is an optimized implementation of AES-GCM using AES-NI and CLMUL-NI // The implementation uses some optimization as described in: // [1] Gueron, S., Kounavis, M.E.: Intel® Carry-Less Multiplication diff --git a/contrib/go/_std_1.22/src/crypto/aes/gcm_arm64.s b/contrib/go/_std_1.23/src/crypto/aes/gcm_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/aes/gcm_arm64.s rename to contrib/go/_std_1.23/src/crypto/aes/gcm_arm64.s index c3501024c9f9..23ce1890e4e5 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/gcm_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/aes/gcm_arm64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" #define B0 V0 diff --git a/contrib/go/_std_1.22/src/crypto/aes/gcm_ppc64x.go b/contrib/go/_std_1.23/src/crypto/aes/gcm_ppc64x.go similarity index 91% rename from contrib/go/_std_1.22/src/crypto/aes/gcm_ppc64x.go rename to contrib/go/_std_1.23/src/crypto/aes/gcm_ppc64x.go index 2a7f898dc4be..f1e85129a8e0 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/gcm_ppc64x.go +++ b/contrib/go/_std_1.23/src/crypto/aes/gcm_ppc64x.go @@ -2,15 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build ppc64le || ppc64 +//go:build (ppc64le || ppc64) && !purego package aes import ( "crypto/cipher" "crypto/subtle" - "encoding/binary" "errors" + "internal/byteorder" "runtime" ) @@ -57,7 +57,7 @@ func counterCryptASM(nr int, out, in []byte, counter *[gcmBlockSize]byte, key *u // called by [crypto/cipher.NewGCM] via the gcmAble interface. func (c *aesCipherAsm) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) { var h1, h2 uint64 - g := &gcmAsm{cipher: c, ks: c.enc, nonceSize: nonceSize, tagSize: tagSize} + g := &gcmAsm{cipher: c, ks: c.enc[:c.l], nonceSize: nonceSize, tagSize: tagSize} hle := make([]byte, gcmBlockSize) @@ -66,14 +66,14 @@ func (c *aesCipherAsm) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) { // Reverse the bytes in each 8 byte chunk // Load little endian, store big endian if runtime.GOARCH == "ppc64le" { - h1 = binary.LittleEndian.Uint64(hle[:8]) - h2 = binary.LittleEndian.Uint64(hle[8:]) + h1 = byteorder.LeUint64(hle[:8]) + h2 = byteorder.LeUint64(hle[8:]) } else { - h1 = binary.BigEndian.Uint64(hle[:8]) - h2 = binary.BigEndian.Uint64(hle[8:]) + h1 = byteorder.BeUint64(hle[:8]) + h2 = byteorder.BeUint64(hle[8:]) } - binary.BigEndian.PutUint64(hle[:8], h1) - binary.BigEndian.PutUint64(hle[8:], h2) + byteorder.BePutUint64(hle[:8], h1) + byteorder.BePutUint64(hle[8:], h2) gcmInit(&g.productTable, hle) return g, nil @@ -119,14 +119,15 @@ func (g *gcmAsm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) { // counterCryptASM implements counterCrypt which then allows the loop to // be unrolled and optimized. func (g *gcmAsm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) { - counterCryptASM(len(g.cipher.enc)/4-1, out, in, counter, &g.cipher.enc[0]) + counterCryptASM(int(g.cipher.l)/4-1, out, in, counter, &g.cipher.enc[0]) + } // increments the rightmost 32-bits of the count value by 1. func gcmInc32(counterBlock *[16]byte) { c := counterBlock[len(counterBlock)-4:] - x := binary.BigEndian.Uint32(c) + 1 - binary.BigEndian.PutUint32(c, x) + x := byteorder.BeUint32(c) + 1 + byteorder.BePutUint32(c, x) } // paddedGHASH pads data with zeroes until its length is a multiple of @@ -211,9 +212,7 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { ret, out := sliceForAppend(dst, len(ciphertext)) if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { - for i := range out { - out[i] = 0 - } + clear(out) return nil, errOpen } diff --git a/contrib/go/_std_1.22/src/crypto/aes/gcm_ppc64x.s b/contrib/go/_std_1.23/src/crypto/aes/gcm_ppc64x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/aes/gcm_ppc64x.s rename to contrib/go/_std_1.23/src/crypto/aes/gcm_ppc64x.s index f661b2764279..987f4e718e12 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/gcm_ppc64x.s +++ b/contrib/go/_std_1.23/src/crypto/aes/gcm_ppc64x.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build ppc64 || ppc64le +//go:build (ppc64 || ppc64le) && !purego // Portions based on CRYPTOGAMS code with the following comment: // # ==================================================================== diff --git a/contrib/go/_std_1.22/src/crypto/aes/gcm_s390x.go b/contrib/go/_std_1.23/src/crypto/aes/gcm_s390x.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/aes/gcm_s390x.go rename to contrib/go/_std_1.23/src/crypto/aes/gcm_s390x.go index cf0e28af695b..492ae5d83b48 100644 --- a/contrib/go/_std_1.22/src/crypto/aes/gcm_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/aes/gcm_s390x.go @@ -2,14 +2,16 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package aes import ( "crypto/cipher" "crypto/internal/alias" "crypto/subtle" - "encoding/binary" "errors" + "internal/byteorder" "internal/cpu" ) @@ -23,14 +25,14 @@ type gcmCount [16]byte // inc increments the rightmost 32-bits of the count value by 1. func (x *gcmCount) inc() { - binary.BigEndian.PutUint32(x[len(x)-4:], binary.BigEndian.Uint32(x[len(x)-4:])+1) + byteorder.BePutUint32(x[len(x)-4:], byteorder.BeUint32(x[len(x)-4:])+1) } // gcmLengths writes len0 || len1 as big-endian values to a 16-byte array. func gcmLengths(len0, len1 uint64) [16]byte { v := [16]byte{} - binary.BigEndian.PutUint64(v[0:], len0) - binary.BigEndian.PutUint64(v[8:], len1) + byteorder.BePutUint64(v[0:], len0) + byteorder.BePutUint64(v[8:], len1) return v } @@ -269,9 +271,7 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { // so overwrites dst in the event of a tag mismatch. That // behavior is mimicked here in order to be consistent across // platforms. - for i := range out { - out[i] = 0 - } + clear(out) return nil, errOpen } @@ -361,9 +361,7 @@ func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { // so overwrites dst in the event of a tag mismatch. That // behavior is mimicked here in order to be consistent across // platforms. - for i := range out { - out[i] = 0 - } + clear(out) return nil, errOpen } diff --git a/contrib/go/_std_1.22/src/crypto/aes/modes.go b/contrib/go/_std_1.23/src/crypto/aes/modes.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/aes/modes.go rename to contrib/go/_std_1.23/src/crypto/aes/modes.go diff --git a/contrib/go/_std_1.22/src/crypto/aes/ya.make b/contrib/go/_std_1.23/src/crypto/aes/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/aes/ya.make rename to contrib/go/_std_1.23/src/crypto/aes/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/boring/boring.go b/contrib/go/_std_1.23/src/crypto/boring/boring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/boring/boring.go rename to contrib/go/_std_1.23/src/crypto/boring/boring.go diff --git a/contrib/go/_std_1.22/src/crypto/boring/ya.make b/contrib/go/_std_1.23/src/crypto/boring/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/boring/ya.make rename to contrib/go/_std_1.23/src/crypto/boring/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/cipher/cbc.go b/contrib/go/_std_1.23/src/crypto/cipher/cbc.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/cipher/cbc.go rename to contrib/go/_std_1.23/src/crypto/cipher/cbc.go diff --git a/contrib/go/_std_1.22/src/crypto/cipher/cfb.go b/contrib/go/_std_1.23/src/crypto/cipher/cfb.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/cipher/cfb.go rename to contrib/go/_std_1.23/src/crypto/cipher/cfb.go diff --git a/contrib/go/_std_1.22/src/crypto/cipher/cipher.go b/contrib/go/_std_1.23/src/crypto/cipher/cipher.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/cipher/cipher.go rename to contrib/go/_std_1.23/src/crypto/cipher/cipher.go diff --git a/contrib/go/_std_1.22/src/crypto/cipher/ctr.go b/contrib/go/_std_1.23/src/crypto/cipher/ctr.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/cipher/ctr.go rename to contrib/go/_std_1.23/src/crypto/cipher/ctr.go diff --git a/contrib/go/_std_1.22/src/crypto/cipher/gcm.go b/contrib/go/_std_1.23/src/crypto/cipher/gcm.go similarity index 96% rename from contrib/go/_std_1.22/src/crypto/cipher/gcm.go rename to contrib/go/_std_1.23/src/crypto/cipher/gcm.go index 928771f05f97..505be50c6ae5 100644 --- a/contrib/go/_std_1.22/src/crypto/cipher/gcm.go +++ b/contrib/go/_std_1.23/src/crypto/cipher/gcm.go @@ -7,8 +7,8 @@ package cipher import ( "crypto/internal/alias" "crypto/subtle" - "encoding/binary" "errors" + "internal/byteorder" ) // AEAD is a cipher mode providing authenticated encryption with associated @@ -137,8 +137,8 @@ func newGCMWithNonceAndTagSize(cipher Block, nonceSize, tagSize int) (AEAD, erro // would expect, say, 4*key to be in index 4 of the table but due to // this bit ordering it will actually be in index 0010 (base 2) = 2. x := gcmFieldElement{ - binary.BigEndian.Uint64(key[:8]), - binary.BigEndian.Uint64(key[8:]), + byteorder.BeUint64(key[:8]), + byteorder.BeUint64(key[8:]), } g.productTable[reverseBits(1)] = x @@ -234,9 +234,7 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { // so overwrites dst in the event of a tag mismatch. That // behavior is mimicked here in order to be consistent across // platforms. - for i := range out { - out[i] = 0 - } + clear(out) return nil, errOpen } @@ -323,8 +321,8 @@ func (g *gcm) mul(y *gcmFieldElement) { // Horner's rule. There must be a multiple of gcmBlockSize bytes in blocks. func (g *gcm) updateBlocks(y *gcmFieldElement, blocks []byte) { for len(blocks) > 0 { - y.low ^= binary.BigEndian.Uint64(blocks) - y.high ^= binary.BigEndian.Uint64(blocks[8:]) + y.low ^= byteorder.BeUint64(blocks) + y.high ^= byteorder.BeUint64(blocks[8:]) g.mul(y) blocks = blocks[gcmBlockSize:] } @@ -347,7 +345,7 @@ func (g *gcm) update(y *gcmFieldElement, data []byte) { // and increments it. func gcmInc32(counterBlock *[16]byte) { ctr := counterBlock[len(counterBlock)-4:] - binary.BigEndian.PutUint32(ctr, binary.BigEndian.Uint32(ctr)+1) + byteorder.BePutUint32(ctr, byteorder.BeUint32(ctr)+1) } // sliceForAppend takes a slice and a requested number of bytes. It returns a @@ -403,8 +401,8 @@ func (g *gcm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) { g.update(&y, nonce) y.high ^= uint64(len(nonce)) * 8 g.mul(&y) - binary.BigEndian.PutUint64(counter[:8], y.low) - binary.BigEndian.PutUint64(counter[8:], y.high) + byteorder.BePutUint64(counter[:8], y.low) + byteorder.BePutUint64(counter[8:], y.high) } } @@ -420,8 +418,8 @@ func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize] g.mul(&y) - binary.BigEndian.PutUint64(out, y.low) - binary.BigEndian.PutUint64(out[8:], y.high) + byteorder.BePutUint64(out, y.low) + byteorder.BePutUint64(out[8:], y.high) subtle.XORBytes(out, out, tagMask[:]) } diff --git a/contrib/go/_std_1.22/src/crypto/cipher/io.go b/contrib/go/_std_1.23/src/crypto/cipher/io.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/cipher/io.go rename to contrib/go/_std_1.23/src/crypto/cipher/io.go diff --git a/contrib/go/_std_1.22/src/crypto/cipher/ofb.go b/contrib/go/_std_1.23/src/crypto/cipher/ofb.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/cipher/ofb.go rename to contrib/go/_std_1.23/src/crypto/cipher/ofb.go diff --git a/contrib/go/_std_1.22/src/crypto/cipher/ya.make b/contrib/go/_std_1.23/src/crypto/cipher/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/cipher/ya.make rename to contrib/go/_std_1.23/src/crypto/cipher/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/crypto.go b/contrib/go/_std_1.23/src/crypto/crypto.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/crypto.go rename to contrib/go/_std_1.23/src/crypto/crypto.go diff --git a/contrib/go/_std_1.22/src/crypto/des/block.go b/contrib/go/_std_1.23/src/crypto/des/block.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/des/block.go rename to contrib/go/_std_1.23/src/crypto/des/block.go index c525ab0e5ca2..7a68a472b467 100644 --- a/contrib/go/_std_1.22/src/crypto/des/block.go +++ b/contrib/go/_std_1.23/src/crypto/des/block.go @@ -5,12 +5,12 @@ package des import ( - "encoding/binary" + "internal/byteorder" "sync" ) func cryptBlock(subkeys []uint64, dst, src []byte, decrypt bool) { - b := binary.BigEndian.Uint64(src) + b := byteorder.BeUint64(src) b = permuteInitialBlock(b) left, right := uint32(b>>32), uint32(b) @@ -32,7 +32,7 @@ func cryptBlock(subkeys []uint64, dst, src []byte, decrypt bool) { // switch left & right and perform final permutation preOutput := (uint64(right) << 32) | uint64(left) - binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput)) + byteorder.BePutUint64(dst, permuteFinalBlock(preOutput)) } // DES Feistel function. feistelBox must be initialized via @@ -218,7 +218,7 @@ func (c *desCipher) generateSubkeys(keyBytes []byte) { feistelBoxOnce.Do(initFeistelBox) // apply PC1 permutation to key - key := binary.BigEndian.Uint64(keyBytes) + key := byteorder.BeUint64(keyBytes) permutedKey := permuteBlock(key, permutedChoice1[:]) // rotate halves of permuted key according to the rotation schedule diff --git a/contrib/go/_std_1.22/src/crypto/des/cipher.go b/contrib/go/_std_1.23/src/crypto/des/cipher.go similarity index 94% rename from contrib/go/_std_1.22/src/crypto/des/cipher.go rename to contrib/go/_std_1.23/src/crypto/des/cipher.go index b0f456e69212..04b73e7d3bf7 100644 --- a/contrib/go/_std_1.22/src/crypto/des/cipher.go +++ b/contrib/go/_std_1.23/src/crypto/des/cipher.go @@ -7,7 +7,7 @@ package des import ( "crypto/cipher" "crypto/internal/alias" - "encoding/binary" + "internal/byteorder" "strconv" ) @@ -95,7 +95,7 @@ func (c *tripleDESCipher) Encrypt(dst, src []byte) { panic("crypto/des: invalid buffer overlap") } - b := binary.BigEndian.Uint64(src) + b := byteorder.BeUint64(src) b = permuteInitialBlock(b) left, right := uint32(b>>32), uint32(b) @@ -116,7 +116,7 @@ func (c *tripleDESCipher) Encrypt(dst, src []byte) { right = (right << 31) | (right >> 1) preOutput := (uint64(right) << 32) | uint64(left) - binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput)) + byteorder.BePutUint64(dst, permuteFinalBlock(preOutput)) } func (c *tripleDESCipher) Decrypt(dst, src []byte) { @@ -130,7 +130,7 @@ func (c *tripleDESCipher) Decrypt(dst, src []byte) { panic("crypto/des: invalid buffer overlap") } - b := binary.BigEndian.Uint64(src) + b := byteorder.BeUint64(src) b = permuteInitialBlock(b) left, right := uint32(b>>32), uint32(b) @@ -151,5 +151,5 @@ func (c *tripleDESCipher) Decrypt(dst, src []byte) { right = (right << 31) | (right >> 1) preOutput := (uint64(right) << 32) | uint64(left) - binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput)) + byteorder.BePutUint64(dst, permuteFinalBlock(preOutput)) } diff --git a/contrib/go/_std_1.22/src/crypto/des/const.go b/contrib/go/_std_1.23/src/crypto/des/const.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/des/const.go rename to contrib/go/_std_1.23/src/crypto/des/const.go diff --git a/contrib/go/_std_1.22/src/crypto/des/ya.make b/contrib/go/_std_1.23/src/crypto/des/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/des/ya.make rename to contrib/go/_std_1.23/src/crypto/des/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/dsa/dsa.go b/contrib/go/_std_1.23/src/crypto/dsa/dsa.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/dsa/dsa.go rename to contrib/go/_std_1.23/src/crypto/dsa/dsa.go diff --git a/contrib/go/_std_1.22/src/crypto/dsa/ya.make b/contrib/go/_std_1.23/src/crypto/dsa/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/dsa/ya.make rename to contrib/go/_std_1.23/src/crypto/dsa/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/ecdh/ecdh.go b/contrib/go/_std_1.23/src/crypto/ecdh/ecdh.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ecdh/ecdh.go rename to contrib/go/_std_1.23/src/crypto/ecdh/ecdh.go diff --git a/contrib/go/_std_1.22/src/crypto/ecdh/nist.go b/contrib/go/_std_1.23/src/crypto/ecdh/nist.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/ecdh/nist.go rename to contrib/go/_std_1.23/src/crypto/ecdh/nist.go index b3664915449b..b91e8f38a5a7 100644 --- a/contrib/go/_std_1.22/src/crypto/ecdh/nist.go +++ b/contrib/go/_std_1.23/src/crypto/ecdh/nist.go @@ -8,8 +8,8 @@ import ( "crypto/internal/boring" "crypto/internal/nistec" "crypto/internal/randutil" - "encoding/binary" "errors" + "internal/byteorder" "io" "math/bits" ) @@ -156,7 +156,7 @@ func isLess(a, b []byte) bool { // Perform a subtraction with borrow. var borrow uint64 for i := 0; i < len(bufA); i += 8 { - limbA, limbB := binary.LittleEndian.Uint64(bufA[i:]), binary.LittleEndian.Uint64(bufB[i:]) + limbA, limbB := byteorder.LeUint64(bufA[i:]), byteorder.LeUint64(bufB[i:]) _, borrow = bits.Sub64(limbA, limbB, borrow) } diff --git a/contrib/go/_std_1.22/src/crypto/ecdh/x25519.go b/contrib/go/_std_1.23/src/crypto/ecdh/x25519.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ecdh/x25519.go rename to contrib/go/_std_1.23/src/crypto/ecdh/x25519.go diff --git a/contrib/go/_std_1.22/src/crypto/ecdh/ya.make b/contrib/go/_std_1.23/src/crypto/ecdh/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ecdh/ya.make rename to contrib/go/_std_1.23/src/crypto/ecdh/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/boring.go b/contrib/go/_std_1.23/src/crypto/ecdsa/boring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ecdsa/boring.go rename to contrib/go/_std_1.23/src/crypto/ecdsa/boring.go diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa.go b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa.go rename to contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa.go index 3ed15a888a75..2179b01e8e3d 100644 --- a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa.go +++ b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa.go @@ -8,6 +8,10 @@ // Signatures generated by this package are not deterministic, but entropy is // mixed with the private key and the message, achieving the same level of // security in case of randomness source failure. +// +// Operations involving private keys are implemented using constant-time +// algorithms, as long as an [elliptic.Curve] returned by [elliptic.P224], +// [elliptic.P256], [elliptic.P384], or [elliptic.P521] is used. package ecdsa // [FIPS 186-4] references ANSI X9.62-2005 for the bulk of the ECDSA algorithm. @@ -457,14 +461,15 @@ var zeroReader = zr{} // Read replaces the contents of dst with zeros. It is safe for concurrent use. func (zr) Read(dst []byte) (n int, err error) { - for i := range dst { - dst[i] = 0 - } + clear(dst) return len(dst), nil } // VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the // public key, pub. Its return value records whether the signature is valid. +// +// The inputs are not considered confidential, and may leak through timing side +// channels, or if an attacker has control of part of the inputs. func VerifyASN1(pub *PublicKey, hash, sig []byte) bool { if boring.Enabled { key, err := boringPublicKey(pub) diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_legacy.go b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_legacy.go similarity index 96% rename from contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_legacy.go rename to contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_legacy.go index 0b8489ab66fd..dc1c5d120ae6 100644 --- a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_legacy.go +++ b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_legacy.go @@ -115,6 +115,9 @@ func signLegacy(priv *PrivateKey, csprng io.Reader, hash []byte) (sig []byte, er // Verify verifies the signature in r, s of hash using the public key, pub. Its // return value records whether the signature is valid. Most applications should // use VerifyASN1 instead of dealing directly with r, s. +// +// The inputs are not considered confidential, and may leak through timing side +// channels, or if an attacker has control of part of the inputs. func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { if r.Sign() <= 0 || s.Sign() <= 0 { return false diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_noasm.go b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_noasm.go similarity index 93% rename from contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_noasm.go rename to contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_noasm.go index a72aa4b04ef5..e2fa8082f68d 100644 --- a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_noasm.go +++ b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !s390x +//go:build !s390x || purego package ecdsa diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_s390x.go b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_s390x.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_s390x.go rename to contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_s390x.go index 49f645a48927..8ebf15a525fb 100644 --- a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_s390x.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package ecdsa import ( diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_s390x.s b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_s390x.s similarity index 97% rename from contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_s390x.s rename to contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_s390x.s index ea1f4469e991..2aae59c291d1 100644 --- a/contrib/go/_std_1.22/src/crypto/ecdsa/ecdsa_s390x.s +++ b/contrib/go/_std_1.23/src/crypto/ecdsa/ecdsa_s390x.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // func kdsa(fc uint64, params *[4096]byte) (errn uint64) diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/notboring.go b/contrib/go/_std_1.23/src/crypto/ecdsa/notboring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ecdsa/notboring.go rename to contrib/go/_std_1.23/src/crypto/ecdsa/notboring.go diff --git a/contrib/go/_std_1.22/src/crypto/ecdsa/ya.make b/contrib/go/_std_1.23/src/crypto/ecdsa/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ecdsa/ya.make rename to contrib/go/_std_1.23/src/crypto/ecdsa/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/ed25519/ed25519.go b/contrib/go/_std_1.23/src/crypto/ed25519/ed25519.go similarity index 96% rename from contrib/go/_std_1.22/src/crypto/ed25519/ed25519.go rename to contrib/go/_std_1.23/src/crypto/ed25519/ed25519.go index 1dda9e5e9a5a..b75c5a6458a2 100644 --- a/contrib/go/_std_1.22/src/crypto/ed25519/ed25519.go +++ b/contrib/go/_std_1.23/src/crypto/ed25519/ed25519.go @@ -10,6 +10,9 @@ // representation includes a public key suffix to make multiple signing // operations with the same key more efficient. This package refers to the RFC // 8032 private key as the “seed”. +// +// Operations involving private keys are implemented using constant-time +// algorithms. package ed25519 import ( @@ -258,6 +261,9 @@ func sign(signature, privateKey, message []byte, domPrefix, context string) { // Verify reports whether sig is a valid signature of message by publicKey. It // will panic if len(publicKey) is not [PublicKeySize]. +// +// The inputs are not considered confidential, and may leak through timing side +// channels, or if an attacker has control of part of the inputs. func Verify(publicKey PublicKey, message, sig []byte) bool { return verify(publicKey, message, sig, domPrefixPure, "") } @@ -270,6 +276,9 @@ func Verify(publicKey PublicKey, message, sig []byte) bool { // message is expected to be a SHA-512 hash, otherwise opts.Hash must be // [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two // passes over messages to be signed. +// +// The inputs are not considered confidential, and may leak through timing side +// channels, or if an attacker has control of part of the inputs. func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) error { switch { case opts.Hash == crypto.SHA512: // Ed25519ph diff --git a/contrib/go/_std_1.22/src/crypto/ed25519/ya.make b/contrib/go/_std_1.23/src/crypto/ed25519/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ed25519/ya.make rename to contrib/go/_std_1.23/src/crypto/ed25519/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/elliptic/elliptic.go b/contrib/go/_std_1.23/src/crypto/elliptic/elliptic.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/elliptic/elliptic.go rename to contrib/go/_std_1.23/src/crypto/elliptic/elliptic.go diff --git a/contrib/go/_std_1.22/src/crypto/elliptic/nistec.go b/contrib/go/_std_1.23/src/crypto/elliptic/nistec.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/elliptic/nistec.go rename to contrib/go/_std_1.23/src/crypto/elliptic/nistec.go diff --git a/contrib/go/_std_1.22/src/crypto/elliptic/nistec_p256.go b/contrib/go/_std_1.23/src/crypto/elliptic/nistec_p256.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/elliptic/nistec_p256.go rename to contrib/go/_std_1.23/src/crypto/elliptic/nistec_p256.go diff --git a/contrib/go/_std_1.22/src/crypto/elliptic/params.go b/contrib/go/_std_1.23/src/crypto/elliptic/params.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/elliptic/params.go rename to contrib/go/_std_1.23/src/crypto/elliptic/params.go index 716e2c06ba87..0507d22b277f 100644 --- a/contrib/go/_std_1.22/src/crypto/elliptic/params.go +++ b/contrib/go/_std_1.23/src/crypto/elliptic/params.go @@ -201,7 +201,7 @@ func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int // Double implements [Curve.Double]. // -// Deprecated: the [CurveParams】 methods are deprecated and are not guaranteed to +// Deprecated: the [CurveParams] methods are deprecated and are not guaranteed to // provide any security property. For ECDH, use the [crypto/ecdh] package. // For ECDSA, use the [crypto/ecdsa] package with a [Curve] value returned directly // from [P224], [P256], [P384], or [P521]. diff --git a/contrib/go/_std_1.22/src/crypto/elliptic/ya.make b/contrib/go/_std_1.23/src/crypto/elliptic/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/elliptic/ya.make rename to contrib/go/_std_1.23/src/crypto/elliptic/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/hmac/hmac.go b/contrib/go/_std_1.23/src/crypto/hmac/hmac.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/hmac/hmac.go rename to contrib/go/_std_1.23/src/crypto/hmac/hmac.go diff --git a/contrib/go/_std_1.22/src/crypto/hmac/ya.make b/contrib/go/_std_1.23/src/crypto/hmac/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/hmac/ya.make rename to contrib/go/_std_1.23/src/crypto/hmac/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/alias/alias.go b/contrib/go/_std_1.23/src/crypto/internal/alias/alias.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/alias/alias.go rename to contrib/go/_std_1.23/src/crypto/internal/alias/alias.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/alias/ya.make b/contrib/go/_std_1.23/src/crypto/internal/alias/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/alias/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/alias/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/_asm/go.mod b/contrib/go/_std_1.23/src/crypto/internal/bigmod/_asm/go.mod similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/_asm/go.mod rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/_asm/go.mod diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/_asm/go.sum b/contrib/go/_std_1.23/src/crypto/internal/bigmod/_asm/go.sum similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/_asm/go.sum rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/_asm/go.sum diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go b/contrib/go/_std_1.23/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat.go b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat.go rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat.go index 7fdd8ef17793..5cbae40efe99 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat.go +++ b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat.go @@ -5,8 +5,8 @@ package bigmod import ( - "encoding/binary" "errors" + "internal/byteorder" "math/big" "math/bits" ) @@ -40,14 +40,6 @@ func ctEq(x, y uint) choice { return not(choice(c1 | c2)) } -// ctGeq returns 1 if x >= y, and 0 otherwise. The execution time of this -// function does not depend on its inputs. -func ctGeq(x, y uint) choice { - // If x < y, then x - y generates a carry. - _, carry := bits.Sub(x, y, 0) - return not(choice(carry)) -} - // Nat represents an arbitrary natural number // // Each Nat has an announced length, which is the number of limbs it has stored. @@ -84,9 +76,7 @@ func (x *Nat) expand(n int) *Nat { return x } extraLimbs := x.limbs[len(x.limbs):n] - for i := range extraLimbs { - extraLimbs[i] = 0 - } + clear(extraLimbs) x.limbs = x.limbs[:n] return x } @@ -97,9 +87,7 @@ func (x *Nat) reset(n int) *Nat { x.limbs = make([]uint, n) return x } - for i := range x.limbs { - x.limbs[i] = 0 - } + clear(x.limbs) x.limbs = x.limbs[:n] return x } @@ -182,9 +170,9 @@ func (x *Nat) SetOverflowingBytes(b []byte, m *Modulus) (*Nat, error) { // big-endian encoded uint value. func bigEndianUint(buf []byte) uint { if _W == 64 { - return uint(binary.BigEndian.Uint64(buf)) + return uint(byteorder.BeUint64(buf)) } - return uint(binary.BigEndian.Uint32(buf)) + return uint(byteorder.BeUint32(buf)) } func (x *Nat) setBytes(b []byte, m *Modulus) error { diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_386.s b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_386.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_386.s rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_386.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_amd64.s b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_amd64.s rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_amd64.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_arm.s b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_arm.s rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_arm.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_arm64.s b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_arm64.s rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_arm64.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_asm.go b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_asm.go rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_asm.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_noasm.go b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_noasm.go rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_noasm.go diff --git a/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_ppc64x.s b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_ppc64x.s new file mode 100644 index 000000000000..94260ca29f3c --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_ppc64x.s @@ -0,0 +1,82 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !purego && (ppc64 || ppc64le) + +#include "textflag.h" + +// func addMulVVW1024(z, x *uint, y uint) (c uint) +TEXT ·addMulVVW1024(SB), $0-32 + MOVD $4, R6 // R6 = z_len/4 + JMP addMulVVWx<>(SB) + +// func addMulVVW1536(z, x *uint, y uint) (c uint) +TEXT ·addMulVVW1536(SB), $0-32 + MOVD $6, R6 // R6 = z_len/4 + JMP addMulVVWx<>(SB) + +// func addMulVVW2048(z, x *uint, y uint) (c uint) +TEXT ·addMulVVW2048(SB), $0-32 + MOVD $8, R6 // R6 = z_len/4 + JMP addMulVVWx<>(SB) + +// This local function expects to be called only by +// callers above. R6 contains the z length/4 +// since 4 values are processed for each +// loop iteration, and is guaranteed to be > 0. +// If other callers are added this function might +// need to change. +TEXT addMulVVWx<>(SB), NOSPLIT, $0 + MOVD z+0(FP), R3 + MOVD x+8(FP), R4 + MOVD y+16(FP), R5 + + MOVD $0, R9 // R9 = c = 0 + MOVD R6, CTR // Initialize loop counter + PCALIGN $16 + +loop: + MOVD 0(R4), R14 // x[i] + MOVD 8(R4), R16 // x[i+1] + MOVD 16(R4), R18 // x[i+2] + MOVD 24(R4), R20 // x[i+3] + MOVD 0(R3), R15 // z[i] + MOVD 8(R3), R17 // z[i+1] + MOVD 16(R3), R19 // z[i+2] + MOVD 24(R3), R21 // z[i+3] + MULLD R5, R14, R10 // low x[i]*y + MULHDU R5, R14, R11 // high x[i]*y + ADDC R15, R10 + ADDZE R11 + ADDC R9, R10 + ADDZE R11, R9 + MULLD R5, R16, R14 // low x[i+1]*y + MULHDU R5, R16, R15 // high x[i+1]*y + ADDC R17, R14 + ADDZE R15 + ADDC R9, R14 + ADDZE R15, R9 + MULLD R5, R18, R16 // low x[i+2]*y + MULHDU R5, R18, R17 // high x[i+2]*y + ADDC R19, R16 + ADDZE R17 + ADDC R9, R16 + ADDZE R17, R9 + MULLD R5, R20, R18 // low x[i+3]*y + MULHDU R5, R20, R19 // high x[i+3]*y + ADDC R21, R18 + ADDZE R19 + ADDC R9, R18 + ADDZE R19, R9 + MOVD R10, 0(R3) // z[i] + MOVD R14, 8(R3) // z[i+1] + MOVD R16, 16(R3) // z[i+2] + MOVD R18, 24(R3) // z[i+3] + ADD $32, R3 + ADD $32, R4 + BDNZ loop + +done: + MOVD R9, c+24(FP) + RET diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_riscv64.s b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_riscv64.s rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_riscv64.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_s390x.s b/contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/nat_s390x.s rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/nat_s390x.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/bigmod/ya.make b/contrib/go/_std_1.23/src/crypto/internal/bigmod/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/bigmod/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/bigmod/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/Dockerfile b/contrib/go/_std_1.23/src/crypto/internal/boring/Dockerfile similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/Dockerfile rename to contrib/go/_std_1.23/src/crypto/internal/boring/Dockerfile diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/LICENSE b/contrib/go/_std_1.23/src/crypto/internal/boring/LICENSE similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/LICENSE rename to contrib/go/_std_1.23/src/crypto/internal/boring/LICENSE diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/README.md b/contrib/go/_std_1.23/src/crypto/internal/boring/README.md similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/README.md rename to contrib/go/_std_1.23/src/crypto/internal/boring/README.md diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/aes.go b/contrib/go/_std_1.23/src/crypto/internal/boring/aes.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/aes.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/aes.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/bbig/big.go b/contrib/go/_std_1.23/src/crypto/internal/boring/bbig/big.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/bbig/big.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/bbig/big.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/bbig/ya.make b/contrib/go/_std_1.23/src/crypto/internal/boring/bbig/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/bbig/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/boring/bbig/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/bcache/cache.go b/contrib/go/_std_1.23/src/crypto/internal/boring/bcache/cache.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/bcache/cache.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/bcache/cache.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/bcache/stub.s b/contrib/go/_std_1.23/src/crypto/internal/boring/bcache/stub.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/bcache/stub.s rename to contrib/go/_std_1.23/src/crypto/internal/boring/bcache/stub.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/bcache/ya.make b/contrib/go/_std_1.23/src/crypto/internal/boring/bcache/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/bcache/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/boring/bcache/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/boring.go b/contrib/go/_std_1.23/src/crypto/internal/boring/boring.go similarity index 95% rename from contrib/go/_std_1.22/src/crypto/internal/boring/boring.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/boring.go index ded36a92f921..90cf1edb75bb 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/boring/boring.go +++ b/contrib/go/_std_1.23/src/crypto/internal/boring/boring.go @@ -16,6 +16,7 @@ import "C" import ( "crypto/internal/boring/sig" _ "crypto/internal/boring/syso" + "internal/stringslite" "math/bits" "unsafe" ) @@ -39,16 +40,12 @@ func Unreachable() { // provided by runtime to avoid os import. func runtime_arg0() string -func hasSuffix(s, t string) bool { - return len(s) > len(t) && s[len(s)-len(t):] == t -} - // UnreachableExceptTests marks code that should be unreachable // when BoringCrypto is in use. It panics. func UnreachableExceptTests() { name := runtime_arg0() // If BoringCrypto ran on Windows we'd need to allow _test.exe and .test.exe as well. - if !hasSuffix(name, "_test") && !hasSuffix(name, ".test") { + if !stringslite.HasSuffix(name, "_test") && !stringslite.HasSuffix(name, ".test") { println("boringcrypto: unexpected code execution in", name) panic("boringcrypto: invalid code execution") } diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/div_test.c b/contrib/go/_std_1.23/src/crypto/internal/boring/div_test.c similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/div_test.c rename to contrib/go/_std_1.23/src/crypto/internal/boring/div_test.c diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/doc.go b/contrib/go/_std_1.23/src/crypto/internal/boring/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/doc.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/doc.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/ecdh.go b/contrib/go/_std_1.23/src/crypto/internal/boring/ecdh.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/ecdh.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/ecdh.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/ecdsa.go b/contrib/go/_std_1.23/src/crypto/internal/boring/ecdsa.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/ecdsa.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/ecdsa.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/fipstls/stub.s b/contrib/go/_std_1.23/src/crypto/internal/boring/fipstls/stub.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/fipstls/stub.s rename to contrib/go/_std_1.23/src/crypto/internal/boring/fipstls/stub.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/fipstls/tls.go b/contrib/go/_std_1.23/src/crypto/internal/boring/fipstls/tls.go similarity index 88% rename from contrib/go/_std_1.22/src/crypto/internal/boring/fipstls/tls.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/fipstls/tls.go index 3bf1471fb0bc..b51f142fde83 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/boring/fipstls/tls.go +++ b/contrib/go/_std_1.23/src/crypto/internal/boring/fipstls/tls.go @@ -9,7 +9,10 @@ // of the use of BoringCrypto. package fipstls -import "sync/atomic" +import ( + "internal/stringslite" + "sync/atomic" +) var required atomic.Bool @@ -33,7 +36,7 @@ func Abandon() { // and empty string for Windows (where runtime_arg0 can't easily find the name). // Since this is an internal package, testing that this isn't used on the // other operating systems should suffice to catch any mistakes. - if !hasSuffix(name, "_test") && !hasSuffix(name, ".test") && name != "NaClMain" && name != "" { + if !stringslite.HasSuffix(name, "_test") && !stringslite.HasSuffix(name, ".test") && name != "NaClMain" && name != "" { panic("fipstls: invalid use of Abandon in " + name) } required.Store(false) @@ -42,10 +45,6 @@ func Abandon() { // provided by runtime func runtime_arg0() string -func hasSuffix(s, t string) bool { - return len(s) > len(t) && s[len(s)-len(t):] == t -} - // Required reports whether FIPS-approved settings are required. func Required() bool { return required.Load() diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/fipstls/ya.make b/contrib/go/_std_1.23/src/crypto/internal/boring/fipstls/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/fipstls/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/boring/fipstls/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/goboringcrypto.h b/contrib/go/_std_1.23/src/crypto/internal/boring/goboringcrypto.h similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/goboringcrypto.h rename to contrib/go/_std_1.23/src/crypto/internal/boring/goboringcrypto.h diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/hmac.go b/contrib/go/_std_1.23/src/crypto/internal/boring/hmac.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/hmac.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/hmac.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/notboring.go b/contrib/go/_std_1.23/src/crypto/internal/boring/notboring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/notboring.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/notboring.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/rand.go b/contrib/go/_std_1.23/src/crypto/internal/boring/rand.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/rand.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/rand.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/rsa.go b/contrib/go/_std_1.23/src/crypto/internal/boring/rsa.go similarity index 93% rename from contrib/go/_std_1.22/src/crypto/internal/boring/rsa.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/rsa.go index e3baa4454975..5ca86aa04275 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/boring/rsa.go +++ b/contrib/go/_std_1.23/src/crypto/internal/boring/rsa.go @@ -126,60 +126,60 @@ func setupRSA(withKey func(func(*C.GO_RSA) C.int) C.int, pkey = C._goboringcrypto_EVP_PKEY_new() if pkey == nil { - return nil, nil, fail("EVP_PKEY_new") + return pkey, ctx, fail("EVP_PKEY_new") } if withKey(func(key *C.GO_RSA) C.int { return C._goboringcrypto_EVP_PKEY_set1_RSA(pkey, key) }) == 0 { - return nil, nil, fail("EVP_PKEY_set1_RSA") + return pkey, ctx, fail("EVP_PKEY_set1_RSA") } ctx = C._goboringcrypto_EVP_PKEY_CTX_new(pkey, nil) if ctx == nil { - return nil, nil, fail("EVP_PKEY_CTX_new") + return pkey, ctx, fail("EVP_PKEY_CTX_new") } if init(ctx) == 0 { - return nil, nil, fail("EVP_PKEY_operation_init") + return pkey, ctx, fail("EVP_PKEY_operation_init") } if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(ctx, padding) == 0 { - return nil, nil, fail("EVP_PKEY_CTX_set_rsa_padding") + return pkey, ctx, fail("EVP_PKEY_CTX_set_rsa_padding") } if padding == C.GO_RSA_PKCS1_OAEP_PADDING { md := hashToMD(h) if md == nil { - return nil, nil, errors.New("crypto/rsa: unsupported hash function") + return pkey, ctx, errors.New("crypto/rsa: unsupported hash function") } mgfMD := hashToMD(mgfHash) if mgfMD == nil { - return nil, nil, errors.New("crypto/rsa: unsupported hash function") + return pkey, ctx, errors.New("crypto/rsa: unsupported hash function") } if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) == 0 { - return nil, nil, fail("EVP_PKEY_set_rsa_oaep_md") + return pkey, ctx, fail("EVP_PKEY_set_rsa_oaep_md") } if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, mgfMD) == 0 { - return nil, nil, fail("EVP_PKEY_set_rsa_mgf1_md") + return pkey, ctx, fail("EVP_PKEY_set_rsa_mgf1_md") } // ctx takes ownership of label, so malloc a copy for BoringCrypto to free. clabel := (*C.uint8_t)(C._goboringcrypto_OPENSSL_malloc(C.size_t(len(label)))) if clabel == nil { - return nil, nil, fail("OPENSSL_malloc") + return pkey, ctx, fail("OPENSSL_malloc") } copy((*[1 << 30]byte)(unsafe.Pointer(clabel))[:len(label)], label) if C._goboringcrypto_EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, clabel, C.size_t(len(label))) == 0 { - return nil, nil, fail("EVP_PKEY_CTX_set0_rsa_oaep_label") + return pkey, ctx, fail("EVP_PKEY_CTX_set0_rsa_oaep_label") } } if padding == C.GO_RSA_PKCS1_PSS_PADDING { if saltLen != 0 { if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, C.int(saltLen)) == 0 { - return nil, nil, fail("EVP_PKEY_set_rsa_pss_saltlen") + return pkey, ctx, fail("EVP_PKEY_set_rsa_pss_saltlen") } } md := cryptoHashToMD(ch) if md == nil { - return nil, nil, errors.New("crypto/rsa: unsupported hash function") + return pkey, ctx, errors.New("crypto/rsa: unsupported hash function") } if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) == 0 { - return nil, nil, fail("EVP_PKEY_set_rsa_mgf1_md") + return pkey, ctx, fail("EVP_PKEY_set_rsa_mgf1_md") } } diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/sha.go b/contrib/go/_std_1.23/src/crypto/internal/boring/sha.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/sha.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/sha.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/sig/sig.go b/contrib/go/_std_1.23/src/crypto/internal/boring/sig/sig.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/sig/sig.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/sig/sig.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/sig/sig_amd64.s b/contrib/go/_std_1.23/src/crypto/internal/boring/sig/sig_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/sig/sig_amd64.s rename to contrib/go/_std_1.23/src/crypto/internal/boring/sig/sig_amd64.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/sig/sig_other.s b/contrib/go/_std_1.23/src/crypto/internal/boring/sig/sig_other.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/sig/sig_other.s rename to contrib/go/_std_1.23/src/crypto/internal/boring/sig/sig_other.s diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/sig/ya.make b/contrib/go/_std_1.23/src/crypto/internal/boring/sig/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/sig/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/boring/sig/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso b/contrib/go/_std_1.23/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso rename to contrib/go/_std_1.23/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso b/contrib/go/_std_1.23/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso rename to contrib/go/_std_1.23/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/syso/syso.go b/contrib/go/_std_1.23/src/crypto/internal/boring/syso/syso.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/syso/syso.go rename to contrib/go/_std_1.23/src/crypto/internal/boring/syso/syso.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/syso/ya.make b/contrib/go/_std_1.23/src/crypto/internal/boring/syso/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/syso/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/boring/syso/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/boring/ya.make b/contrib/go/_std_1.23/src/crypto/internal/boring/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/boring/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/boring/ya.make diff --git a/contrib/go/_std_1.23/src/crypto/internal/cryptotest/hash.go b/contrib/go/_std_1.23/src/crypto/internal/cryptotest/hash.go new file mode 100644 index 000000000000..a950dcb28214 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/cryptotest/hash.go @@ -0,0 +1,189 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cryptotest + +import ( + "bytes" + "hash" + "io" + "math/rand" + "testing" + "time" +) + +type MakeHash func() hash.Hash + +// TestHash performs a set of tests on hash.Hash implementations, checking the +// documented requirements of Write, Sum, Reset, Size, and BlockSize. +func TestHash(t *testing.T, mh MakeHash) { + + // Test that Sum returns an appended digest matching output of Size + t.Run("SumAppend", func(t *testing.T) { + h := mh() + rng := newRandReader(t) + + emptyBuff := []byte("") + shortBuff := []byte("a") + longBuff := make([]byte, h.BlockSize()+1) + rng.Read(longBuff) + + // Set of example strings to append digest to + prefixes := [][]byte{nil, emptyBuff, shortBuff, longBuff} + + // Go to each string and check digest gets appended to and is correct size. + for _, prefix := range prefixes { + h.Reset() + + sum := getSum(t, h, prefix) // Append new digest to prefix + + // Check that Sum didn't alter the prefix + if !bytes.Equal(sum[0:len(prefix)], prefix) { + t.Errorf("Sum alters passed buffer instead of appending; got %x, want %x", sum[0:len(prefix)], prefix) + } + + // Check that the appended sum wasn't affected by the prefix + if expectedSum := getSum(t, h, nil); !bytes.Equal(sum[len(prefix):], expectedSum) { + t.Errorf("Sum behavior affected by data in the input buffer; got %x, want %x", sum[len(prefix):], expectedSum) + } + + // Check size of append + if got, want := len(sum)-len(prefix), h.Size(); got != want { + t.Errorf("Sum appends number of bytes != Size; got %v , want %v", got, want) + } + } + }) + + // Test that Hash.Write never returns error. + t.Run("WriteWithoutError", func(t *testing.T) { + h := mh() + rng := newRandReader(t) + + emptySlice := []byte("") + shortSlice := []byte("a") + longSlice := make([]byte, h.BlockSize()+1) + rng.Read(longSlice) + + // Set of example strings to append digest to + slices := [][]byte{emptySlice, shortSlice, longSlice} + + for _, slice := range slices { + writeToHash(t, h, slice) // Writes and checks Write doesn't error + } + }) + + t.Run("ResetState", func(t *testing.T) { + h := mh() + rng := newRandReader(t) + + emptySum := getSum(t, h, nil) + + // Write to hash and then Reset it and see if Sum is same as emptySum + writeEx := make([]byte, h.BlockSize()) + rng.Read(writeEx) + writeToHash(t, h, writeEx) + h.Reset() + resetSum := getSum(t, h, nil) + + if !bytes.Equal(emptySum, resetSum) { + t.Errorf("Reset hash yields different Sum than new hash; got %x, want %x", emptySum, resetSum) + } + }) + + // Check that Write isn't reading from beyond input slice's bounds + t.Run("OutOfBoundsRead", func(t *testing.T) { + h := mh() + blockSize := h.BlockSize() + rng := newRandReader(t) + + msg := make([]byte, blockSize) + rng.Read(msg) + writeToHash(t, h, msg) + expectedDigest := getSum(t, h, nil) // Record control digest + + h.Reset() + + // Make a buffer with msg in the middle and data on either end + buff := make([]byte, blockSize*3) + endOfPrefix, startOfSuffix := blockSize, blockSize*2 + + copy(buff[endOfPrefix:startOfSuffix], msg) + rng.Read(buff[:endOfPrefix]) + rng.Read(buff[startOfSuffix:]) + + writeToHash(t, h, buff[endOfPrefix:startOfSuffix]) + testDigest := getSum(t, h, nil) + + if !bytes.Equal(testDigest, expectedDigest) { + t.Errorf("Write affected by data outside of input slice bounds; got %x, want %x", testDigest, expectedDigest) + } + }) + + // Test that multiple calls to Write is stateful + t.Run("StatefulWrite", func(t *testing.T) { + h := mh() + rng := newRandReader(t) + + prefix, suffix := make([]byte, h.BlockSize()), make([]byte, h.BlockSize()) + rng.Read(prefix) + rng.Read(suffix) + + // Write prefix then suffix sequentially and record resulting hash + writeToHash(t, h, prefix) + writeToHash(t, h, suffix) + serialSum := getSum(t, h, nil) + + h.Reset() + + // Write prefix and suffix at the same time and record resulting hash + writeToHash(t, h, append(prefix, suffix...)) + compositeSum := getSum(t, h, nil) + + // Check that sequential writing results in the same as writing all at once + if !bytes.Equal(compositeSum, serialSum) { + t.Errorf("two successive Write calls resulted in a different Sum than a single one; got %x, want %x", compositeSum, serialSum) + } + }) +} + +// Helper function for writing. Verifies that Write does not error. +func writeToHash(t *testing.T, h hash.Hash, p []byte) { + t.Helper() + + before := make([]byte, len(p)) + copy(before, p) + + n, err := h.Write(p) + if err != nil || n != len(p) { + t.Errorf("Write returned error; got (%v, %v), want (nil, %v)", err, n, len(p)) + } + + if !bytes.Equal(p, before) { + t.Errorf("Write modified input slice; got %x, want %x", p, before) + } +} + +// Helper function for getting Sum. Checks that Sum doesn't change hash state. +func getSum(t *testing.T, h hash.Hash, buff []byte) []byte { + t.Helper() + + testBuff := make([]byte, len(buff)) + copy(testBuff, buff) + + sum := h.Sum(buff) + testSum := h.Sum(testBuff) + + // Check that Sum doesn't change underlying hash state + if !bytes.Equal(sum, testSum) { + t.Errorf("successive calls to Sum yield different results; got %x, want %x", sum, testSum) + } + + return sum +} + +func newRandReader(t *testing.T) io.Reader { + seed := time.Now().UnixNano() + t.Logf("Deterministic RNG seed: 0x%x", seed) + return rand.New(rand.NewSource(seed)) +} diff --git a/contrib/go/_std_1.23/src/crypto/internal/cryptotest/ya.make b/contrib/go/_std_1.23/src/crypto/internal/cryptotest/ya.make new file mode 100644 index 000000000000..617115214d07 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/cryptotest/ya.make @@ -0,0 +1,9 @@ +SUBSCRIBER(g:contrib) + +GO_LIBRARY() +IF (TRUE) + SRCS( + hash.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/doc.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/doc.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/doc.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/edwards25519.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/edwards25519.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/edwards25519.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/edwards25519.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go index 411399cb1e83..6765a688f455 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go @@ -17,7 +17,7 @@ import ( func main() { Package("crypto/internal/edwards25519/field") - ConstraintExpr("amd64,gc,!purego") + ConstraintExpr("!purego") feMul() feSquare() Generate() diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/_asm/go.mod b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/_asm/go.mod similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/_asm/go.mod rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/_asm/go.mod diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/_asm/go.sum b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/_asm/go.sum similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/_asm/go.sum rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/_asm/go.sum diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe.go index 5518ef2b9024..8a531f078ee2 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe.go +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe.go @@ -7,8 +7,8 @@ package field import ( "crypto/subtle" - "encoding/binary" "errors" + "internal/byteorder" "math/bits" ) @@ -201,20 +201,20 @@ func (v *Element) SetBytes(x []byte) (*Element, error) { } // Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51). - v.l0 = binary.LittleEndian.Uint64(x[0:8]) + v.l0 = byteorder.LeUint64(x[0:8]) v.l0 &= maskLow51Bits // Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51). - v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3 + v.l1 = byteorder.LeUint64(x[6:14]) >> 3 v.l1 &= maskLow51Bits // Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51). - v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6 + v.l2 = byteorder.LeUint64(x[12:20]) >> 6 v.l2 &= maskLow51Bits // Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51). - v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1 + v.l3 = byteorder.LeUint64(x[19:27]) >> 1 v.l3 &= maskLow51Bits // Bits 204:255 (bytes 24:32, bits 192:256, shift 12, mask 51). // Note: not bytes 25:33, shift 4, to avoid overread. - v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12 + v.l4 = byteorder.LeUint64(x[24:32]) >> 12 v.l4 &= maskLow51Bits return v, nil @@ -235,7 +235,7 @@ func (v *Element) bytes(out *[32]byte) []byte { var buf [8]byte for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} { bitsOffset := i * 51 - binary.LittleEndian.PutUint64(buf[:], l<= len(out) { diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64.go similarity index 91% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64.go index 70c541692c3a..00bf8f447922 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64.go +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64.go @@ -1,6 +1,6 @@ // Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. -//go:build amd64 && gc && !purego +//go:build !purego package field diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64.s b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64.s rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64.s index 60817acc4131..657851c85ed1 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64.s @@ -1,6 +1,6 @@ // Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT. -//go:build amd64 && gc && !purego +//go:build !purego #include "textflag.h" diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go similarity index 89% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go index 9da280d1d887..4b81f25d1d0f 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 || !gc || purego +//go:build !amd64 || purego package field diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64.go similarity index 89% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64.go index 075fe9b92574..05c7cedd4e9c 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64.go +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build arm64 && gc && !purego +//go:build !purego package field diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64.s b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64.s similarity index 96% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64.s rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64.s index 3126a434191c..ae207dae43e8 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build arm64 && gc && !purego +//go:build !purego #include "textflag.h" diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go similarity index 88% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go index fc029ac12dae..6b9e06a6e826 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !arm64 || !gc || purego +//go:build !arm64 || purego package field diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_generic.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/fe_generic.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/fe_generic.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/ya.make b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/field/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/field/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/scalar.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/scalar.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/scalar.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/scalar.go index 3fd1653877d2..9f652faca1ec 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/scalar.go +++ b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/scalar.go @@ -5,8 +5,8 @@ package edwards25519 import ( - "encoding/binary" "errors" + "internal/byteorder" ) // A Scalar is an integer modulo @@ -271,7 +271,7 @@ func (s *Scalar) nonAdjacentForm(w uint) [256]int8 { var digits [5]uint64 for i := 0; i < 4; i++ { - digits[i] = binary.LittleEndian.Uint64(b[i*8:]) + digits[i] = byteorder.LeUint64(b[i*8:]) } width := uint64(1 << w) diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/scalar_fiat.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/scalar_fiat.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/scalar_fiat.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/scalar_fiat.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/scalarmult.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/scalarmult.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/scalarmult.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/scalarmult.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/tables.go b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/tables.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/tables.go rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/tables.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/edwards25519/ya.make b/contrib/go/_std_1.23/src/crypto/internal/edwards25519/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/edwards25519/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/edwards25519/ya.make diff --git a/contrib/go/_std_1.23/src/crypto/internal/hpke/hpke.go b/contrib/go/_std_1.23/src/crypto/internal/hpke/hpke.go new file mode 100644 index 000000000000..611c89aac0e1 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/hpke/hpke.go @@ -0,0 +1,259 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package hpke + +import ( + "crypto" + "crypto/aes" + "crypto/cipher" + "crypto/ecdh" + "crypto/rand" + "encoding/binary" + "errors" + "math/bits" + + "golang.org/x/crypto/chacha20poly1305" + "golang.org/x/crypto/hkdf" +) + +// testingOnlyGenerateKey is only used during testing, to provide +// a fixed test key to use when checking the RFC 9180 vectors. +var testingOnlyGenerateKey func() (*ecdh.PrivateKey, error) + +type hkdfKDF struct { + hash crypto.Hash +} + +func (kdf *hkdfKDF) LabeledExtract(suiteID []byte, salt []byte, label string, inputKey []byte) []byte { + labeledIKM := make([]byte, 0, 7+len(suiteID)+len(label)+len(inputKey)) + labeledIKM = append(labeledIKM, []byte("HPKE-v1")...) + labeledIKM = append(labeledIKM, suiteID...) + labeledIKM = append(labeledIKM, label...) + labeledIKM = append(labeledIKM, inputKey...) + return hkdf.Extract(kdf.hash.New, labeledIKM, salt) +} + +func (kdf *hkdfKDF) LabeledExpand(suiteID []byte, randomKey []byte, label string, info []byte, length uint16) []byte { + labeledInfo := make([]byte, 0, 2+7+len(suiteID)+len(label)+len(info)) + labeledInfo = binary.BigEndian.AppendUint16(labeledInfo, length) + labeledInfo = append(labeledInfo, []byte("HPKE-v1")...) + labeledInfo = append(labeledInfo, suiteID...) + labeledInfo = append(labeledInfo, label...) + labeledInfo = append(labeledInfo, info...) + out := make([]byte, length) + n, err := hkdf.Expand(kdf.hash.New, randomKey, labeledInfo).Read(out) + if err != nil || n != int(length) { + panic("hpke: LabeledExpand failed unexpectedly") + } + return out +} + +// dhKEM implements the KEM specified in RFC 9180, Section 4.1. +type dhKEM struct { + dh ecdh.Curve + kdf hkdfKDF + + suiteID []byte + nSecret uint16 +} + +var SupportedKEMs = map[uint16]struct { + curve ecdh.Curve + hash crypto.Hash + nSecret uint16 +}{ + // RFC 9180 Section 7.1 + 0x0020: {ecdh.X25519(), crypto.SHA256, 32}, +} + +func newDHKem(kemID uint16) (*dhKEM, error) { + suite, ok := SupportedKEMs[kemID] + if !ok { + return nil, errors.New("unsupported suite ID") + } + return &dhKEM{ + dh: suite.curve, + kdf: hkdfKDF{suite.hash}, + suiteID: binary.BigEndian.AppendUint16([]byte("KEM"), kemID), + nSecret: suite.nSecret, + }, nil +} + +func (dh *dhKEM) ExtractAndExpand(dhKey, kemContext []byte) []byte { + eaePRK := dh.kdf.LabeledExtract(dh.suiteID[:], nil, "eae_prk", dhKey) + return dh.kdf.LabeledExpand(dh.suiteID[:], eaePRK, "shared_secret", kemContext, dh.nSecret) +} + +func (dh *dhKEM) Encap(pubRecipient *ecdh.PublicKey) (sharedSecret []byte, encapPub []byte, err error) { + var privEph *ecdh.PrivateKey + if testingOnlyGenerateKey != nil { + privEph, err = testingOnlyGenerateKey() + } else { + privEph, err = dh.dh.GenerateKey(rand.Reader) + } + if err != nil { + return nil, nil, err + } + dhVal, err := privEph.ECDH(pubRecipient) + if err != nil { + return nil, nil, err + } + encPubEph := privEph.PublicKey().Bytes() + + encPubRecip := pubRecipient.Bytes() + kemContext := append(encPubEph, encPubRecip...) + + return dh.ExtractAndExpand(dhVal, kemContext), encPubEph, nil +} + +type Sender struct { + aead cipher.AEAD + kem *dhKEM + + sharedSecret []byte + + suiteID []byte + + key []byte + baseNonce []byte + exporterSecret []byte + + seqNum uint128 +} + +var aesGCMNew = func(key []byte) (cipher.AEAD, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + return cipher.NewGCM(block) +} + +var SupportedAEADs = map[uint16]struct { + keySize int + nonceSize int + aead func([]byte) (cipher.AEAD, error) +}{ + // RFC 9180, Section 7.3 + 0x0001: {keySize: 16, nonceSize: 12, aead: aesGCMNew}, + 0x0002: {keySize: 32, nonceSize: 12, aead: aesGCMNew}, + 0x0003: {keySize: chacha20poly1305.KeySize, nonceSize: chacha20poly1305.NonceSize, aead: chacha20poly1305.New}, +} + +var SupportedKDFs = map[uint16]func() *hkdfKDF{ + // RFC 9180, Section 7.2 + 0x0001: func() *hkdfKDF { return &hkdfKDF{crypto.SHA256} }, +} + +func SetupSender(kemID, kdfID, aeadID uint16, pub crypto.PublicKey, info []byte) ([]byte, *Sender, error) { + suiteID := SuiteID(kemID, kdfID, aeadID) + + kem, err := newDHKem(kemID) + if err != nil { + return nil, nil, err + } + pubRecipient, ok := pub.(*ecdh.PublicKey) + if !ok { + return nil, nil, errors.New("incorrect public key type") + } + sharedSecret, encapsulatedKey, err := kem.Encap(pubRecipient) + if err != nil { + return nil, nil, err + } + + kdfInit, ok := SupportedKDFs[kdfID] + if !ok { + return nil, nil, errors.New("unsupported KDF id") + } + kdf := kdfInit() + + aeadInfo, ok := SupportedAEADs[aeadID] + if !ok { + return nil, nil, errors.New("unsupported AEAD id") + } + + pskIDHash := kdf.LabeledExtract(suiteID, nil, "psk_id_hash", nil) + infoHash := kdf.LabeledExtract(suiteID, nil, "info_hash", info) + ksContext := append([]byte{0}, pskIDHash...) + ksContext = append(ksContext, infoHash...) + + secret := kdf.LabeledExtract(suiteID, sharedSecret, "secret", nil) + + key := kdf.LabeledExpand(suiteID, secret, "key", ksContext, uint16(aeadInfo.keySize) /* Nk - key size for AEAD */) + baseNonce := kdf.LabeledExpand(suiteID, secret, "base_nonce", ksContext, uint16(aeadInfo.nonceSize) /* Nn - nonce size for AEAD */) + exporterSecret := kdf.LabeledExpand(suiteID, secret, "exp", ksContext, uint16(kdf.hash.Size()) /* Nh - hash output size of the kdf*/) + + aead, err := aeadInfo.aead(key) + if err != nil { + return nil, nil, err + } + + return encapsulatedKey, &Sender{ + kem: kem, + aead: aead, + sharedSecret: sharedSecret, + suiteID: suiteID, + key: key, + baseNonce: baseNonce, + exporterSecret: exporterSecret, + }, nil +} + +func (s *Sender) nextNonce() []byte { + nonce := s.seqNum.bytes()[16-s.aead.NonceSize():] + for i := range s.baseNonce { + nonce[i] ^= s.baseNonce[i] + } + // Message limit is, according to the RFC, 2^95+1, which + // is somewhat confusing, but we do as we're told. + if s.seqNum.bitLen() >= (s.aead.NonceSize()*8)-1 { + panic("message limit reached") + } + s.seqNum = s.seqNum.addOne() + return nonce +} + +func (s *Sender) Seal(aad, plaintext []byte) ([]byte, error) { + + ciphertext := s.aead.Seal(nil, s.nextNonce(), plaintext, aad) + return ciphertext, nil +} + +func SuiteID(kemID, kdfID, aeadID uint16) []byte { + suiteID := make([]byte, 0, 4+2+2+2) + suiteID = append(suiteID, []byte("HPKE")...) + suiteID = binary.BigEndian.AppendUint16(suiteID, kemID) + suiteID = binary.BigEndian.AppendUint16(suiteID, kdfID) + suiteID = binary.BigEndian.AppendUint16(suiteID, aeadID) + return suiteID +} + +func ParseHPKEPublicKey(kemID uint16, bytes []byte) (*ecdh.PublicKey, error) { + kemInfo, ok := SupportedKEMs[kemID] + if !ok { + return nil, errors.New("unsupported KEM id") + } + return kemInfo.curve.NewPublicKey(bytes) +} + +type uint128 struct { + hi, lo uint64 +} + +func (u uint128) addOne() uint128 { + lo, carry := bits.Add64(u.lo, 1, 0) + return uint128{u.hi + carry, lo} +} + +func (u uint128) bitLen() int { + return bits.Len64(u.hi) + bits.Len64(u.lo) +} + +func (u uint128) bytes() []byte { + b := make([]byte, 16) + binary.BigEndian.PutUint64(b[0:], u.hi) + binary.BigEndian.PutUint64(b[8:], u.lo) + return b +} diff --git a/contrib/go/_std_1.22/src/internal/intern/ya.make b/contrib/go/_std_1.23/src/crypto/internal/hpke/ya.make similarity index 74% rename from contrib/go/_std_1.22/src/internal/intern/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/hpke/ya.make index 2aa90abdbac8..e00f3e3a3539 100644 --- a/contrib/go/_std_1.22/src/internal/intern/ya.make +++ b/contrib/go/_std_1.23/src/crypto/internal/hpke/ya.make @@ -1,7 +1,7 @@ GO_LIBRARY() IF (TRUE) SRCS( - intern.go + hpke.go ) ENDIF() END() diff --git a/contrib/go/_std_1.23/src/crypto/internal/mlkem768/mlkem768.go b/contrib/go/_std_1.23/src/crypto/internal/mlkem768/mlkem768.go new file mode 100644 index 000000000000..76c6e80b4eb0 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/mlkem768/mlkem768.go @@ -0,0 +1,886 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package mlkem768 implements the quantum-resistant key encapsulation method +// ML-KEM (formerly known as Kyber). +// +// Only the recommended ML-KEM-768 parameter set is provided. +// +// The version currently implemented is the one specified by [NIST FIPS 203 ipd], +// with the unintentional transposition of the matrix A reverted to match the +// behavior of [Kyber version 3.0]. Future versions of this package might +// introduce backwards incompatible changes to implement changes to FIPS 203. +// +// [Kyber version 3.0]: https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf +// [NIST FIPS 203 ipd]: https://doi.org/10.6028/NIST.FIPS.203.ipd +package mlkem768 + +// This package targets security, correctness, simplicity, readability, and +// reviewability as its primary goals. All critical operations are performed in +// constant time. +// +// Variable and function names, as well as code layout, are selected to +// facilitate reviewing the implementation against the NIST FIPS 203 ipd +// document. +// +// Reviewers unfamiliar with polynomials or linear algebra might find the +// background at https://words.filippo.io/kyber-math/ useful. + +import ( + "crypto/rand" + "crypto/subtle" + "errors" + "internal/byteorder" + + "golang.org/x/crypto/sha3" +) + +const ( + // ML-KEM global constants. + n = 256 + q = 3329 + + log2q = 12 + + // ML-KEM-768 parameters. The code makes assumptions based on these values, + // they can't be changed blindly. + k = 3 + η = 2 + du = 10 + dv = 4 + + // encodingSizeX is the byte size of a ringElement or nttElement encoded + // by ByteEncode_X (FIPS 203 (DRAFT), Algorithm 4). + encodingSize12 = n * log2q / 8 + encodingSize10 = n * du / 8 + encodingSize4 = n * dv / 8 + encodingSize1 = n * 1 / 8 + + messageSize = encodingSize1 + decryptionKeySize = k * encodingSize12 + encryptionKeySize = k*encodingSize12 + 32 + + CiphertextSize = k*encodingSize10 + encodingSize4 + EncapsulationKeySize = encryptionKeySize + DecapsulationKeySize = decryptionKeySize + encryptionKeySize + 32 + 32 + SharedKeySize = 32 + SeedSize = 32 + 32 +) + +// A DecapsulationKey is the secret key used to decapsulate a shared key from a +// ciphertext. It includes various precomputed values. +type DecapsulationKey struct { + dk [DecapsulationKeySize]byte + encryptionKey + decryptionKey +} + +// Bytes returns the extended encoding of the decapsulation key, according to +// FIPS 203 (DRAFT). +func (dk *DecapsulationKey) Bytes() []byte { + var b [DecapsulationKeySize]byte + copy(b[:], dk.dk[:]) + return b[:] +} + +// EncapsulationKey returns the public encapsulation key necessary to produce +// ciphertexts. +func (dk *DecapsulationKey) EncapsulationKey() []byte { + var b [EncapsulationKeySize]byte + copy(b[:], dk.dk[decryptionKeySize:]) + return b[:] +} + +// encryptionKey is the parsed and expanded form of a PKE encryption key. +type encryptionKey struct { + t [k]nttElement // ByteDecode₁₂(ek[:384k]) + A [k * k]nttElement // A[i*k+j] = sampleNTT(ρ, j, i) +} + +// decryptionKey is the parsed and expanded form of a PKE decryption key. +type decryptionKey struct { + s [k]nttElement // ByteDecode₁₂(dk[:decryptionKeySize]) +} + +// GenerateKey generates a new decapsulation key, drawing random bytes from +// crypto/rand. The decapsulation key must be kept secret. +func GenerateKey() (*DecapsulationKey, error) { + // The actual logic is in a separate function to outline this allocation. + dk := &DecapsulationKey{} + return generateKey(dk) +} + +func generateKey(dk *DecapsulationKey) (*DecapsulationKey, error) { + var d [32]byte + if _, err := rand.Read(d[:]); err != nil { + return nil, errors.New("mlkem768: crypto/rand Read failed: " + err.Error()) + } + var z [32]byte + if _, err := rand.Read(z[:]); err != nil { + return nil, errors.New("mlkem768: crypto/rand Read failed: " + err.Error()) + } + return kemKeyGen(dk, &d, &z), nil +} + +// NewKeyFromSeed deterministically generates a decapsulation key from a 64-byte +// seed in the "d || z" form. The seed must be uniformly random. +func NewKeyFromSeed(seed []byte) (*DecapsulationKey, error) { + // The actual logic is in a separate function to outline this allocation. + dk := &DecapsulationKey{} + return newKeyFromSeed(dk, seed) +} + +func newKeyFromSeed(dk *DecapsulationKey, seed []byte) (*DecapsulationKey, error) { + if len(seed) != SeedSize { + return nil, errors.New("mlkem768: invalid seed length") + } + d := (*[32]byte)(seed[:32]) + z := (*[32]byte)(seed[32:]) + return kemKeyGen(dk, d, z), nil +} + +// NewKeyFromExtendedEncoding parses a decapsulation key from its FIPS 203 +// (DRAFT) extended encoding. +func NewKeyFromExtendedEncoding(decapsulationKey []byte) (*DecapsulationKey, error) { + // The actual logic is in a separate function to outline this allocation. + dk := &DecapsulationKey{} + return newKeyFromExtendedEncoding(dk, decapsulationKey) +} + +func newKeyFromExtendedEncoding(dk *DecapsulationKey, dkBytes []byte) (*DecapsulationKey, error) { + if len(dkBytes) != DecapsulationKeySize { + return nil, errors.New("mlkem768: invalid decapsulation key length") + } + + // Note that we don't check that H(ek) matches ekPKE, as that's not + // specified in FIPS 203 (DRAFT). This is one reason to prefer the seed + // private key format. + dk.dk = [DecapsulationKeySize]byte(dkBytes) + + dkPKE := dkBytes[:decryptionKeySize] + if err := parseDK(&dk.decryptionKey, dkPKE); err != nil { + return nil, err + } + + ekPKE := dkBytes[decryptionKeySize : decryptionKeySize+encryptionKeySize] + if err := parseEK(&dk.encryptionKey, ekPKE); err != nil { + return nil, err + } + + return dk, nil +} + +// kemKeyGen generates a decapsulation key. +// +// It implements ML-KEM.KeyGen according to FIPS 203 (DRAFT), Algorithm 15, and +// K-PKE.KeyGen according to FIPS 203 (DRAFT), Algorithm 12. The two are merged +// to save copies and allocations. +func kemKeyGen(dk *DecapsulationKey, d, z *[32]byte) *DecapsulationKey { + if dk == nil { + dk = &DecapsulationKey{} + } + + G := sha3.Sum512(d[:]) + ρ, σ := G[:32], G[32:] + + A := &dk.A + for i := byte(0); i < k; i++ { + for j := byte(0); j < k; j++ { + // Note that this is consistent with Kyber round 3, rather than with + // the initial draft of FIPS 203, because NIST signaled that the + // change was involuntary and will be reverted. + A[i*k+j] = sampleNTT(ρ, j, i) + } + } + + var N byte + s := &dk.s + for i := range s { + s[i] = ntt(samplePolyCBD(σ, N)) + N++ + } + e := make([]nttElement, k) + for i := range e { + e[i] = ntt(samplePolyCBD(σ, N)) + N++ + } + + t := &dk.t + for i := range t { // t = A ◦ s + e + t[i] = e[i] + for j := range s { + t[i] = polyAdd(t[i], nttMul(A[i*k+j], s[j])) + } + } + + // dkPKE ← ByteEncode₁₂(s) + // ekPKE ← ByteEncode₁₂(t) || ρ + // ek ← ekPKE + // dk ← dkPKE || ek || H(ek) || z + dkB := dk.dk[:0] + + for i := range s { + dkB = polyByteEncode(dkB, s[i]) + } + + for i := range t { + dkB = polyByteEncode(dkB, t[i]) + } + dkB = append(dkB, ρ...) + + H := sha3.New256() + H.Write(dkB[decryptionKeySize:]) + dkB = H.Sum(dkB) + + dkB = append(dkB, z[:]...) + + if len(dkB) != len(dk.dk) { + panic("mlkem768: internal error: invalid decapsulation key size") + } + + return dk +} + +// Encapsulate generates a shared key and an associated ciphertext from an +// encapsulation key, drawing random bytes from crypto/rand. +// If the encapsulation key is not valid, Encapsulate returns an error. +// +// The shared key must be kept secret. +func Encapsulate(encapsulationKey []byte) (ciphertext, sharedKey []byte, err error) { + // The actual logic is in a separate function to outline this allocation. + var cc [CiphertextSize]byte + return encapsulate(&cc, encapsulationKey) +} + +func encapsulate(cc *[CiphertextSize]byte, encapsulationKey []byte) (ciphertext, sharedKey []byte, err error) { + if len(encapsulationKey) != EncapsulationKeySize { + return nil, nil, errors.New("mlkem768: invalid encapsulation key length") + } + var m [messageSize]byte + if _, err := rand.Read(m[:]); err != nil { + return nil, nil, errors.New("mlkem768: crypto/rand Read failed: " + err.Error()) + } + return kemEncaps(cc, encapsulationKey, &m) +} + +// kemEncaps generates a shared key and an associated ciphertext. +// +// It implements ML-KEM.Encaps according to FIPS 203 (DRAFT), Algorithm 16. +func kemEncaps(cc *[CiphertextSize]byte, ek []byte, m *[messageSize]byte) (c, K []byte, err error) { + if cc == nil { + cc = &[CiphertextSize]byte{} + } + + H := sha3.Sum256(ek[:]) + g := sha3.New512() + g.Write(m[:]) + g.Write(H[:]) + G := g.Sum(nil) + K, r := G[:SharedKeySize], G[SharedKeySize:] + var ex encryptionKey + if err := parseEK(&ex, ek[:]); err != nil { + return nil, nil, err + } + c = pkeEncrypt(cc, &ex, m, r) + return c, K, nil +} + +// parseEK parses an encryption key from its encoded form. +// +// It implements the initial stages of K-PKE.Encrypt according to FIPS 203 +// (DRAFT), Algorithm 13. +func parseEK(ex *encryptionKey, ekPKE []byte) error { + if len(ekPKE) != encryptionKeySize { + return errors.New("mlkem768: invalid encryption key length") + } + + for i := range ex.t { + var err error + ex.t[i], err = polyByteDecode[nttElement](ekPKE[:encodingSize12]) + if err != nil { + return err + } + ekPKE = ekPKE[encodingSize12:] + } + ρ := ekPKE + + for i := byte(0); i < k; i++ { + for j := byte(0); j < k; j++ { + // See the note in pkeKeyGen about the order of the indices being + // consistent with Kyber round 3. + ex.A[i*k+j] = sampleNTT(ρ, j, i) + } + } + + return nil +} + +// pkeEncrypt encrypt a plaintext message. +// +// It implements K-PKE.Encrypt according to FIPS 203 (DRAFT), Algorithm 13, +// although the computation of t and AT is done in parseEK. +func pkeEncrypt(cc *[CiphertextSize]byte, ex *encryptionKey, m *[messageSize]byte, rnd []byte) []byte { + var N byte + r, e1 := make([]nttElement, k), make([]ringElement, k) + for i := range r { + r[i] = ntt(samplePolyCBD(rnd, N)) + N++ + } + for i := range e1 { + e1[i] = samplePolyCBD(rnd, N) + N++ + } + e2 := samplePolyCBD(rnd, N) + + u := make([]ringElement, k) // NTT⁻¹(AT ◦ r) + e1 + for i := range u { + u[i] = e1[i] + for j := range r { + // Note that i and j are inverted, as we need the transposed of A. + u[i] = polyAdd(u[i], inverseNTT(nttMul(ex.A[j*k+i], r[j]))) + } + } + + μ := ringDecodeAndDecompress1(m) + + var vNTT nttElement // t⊺ ◦ r + for i := range ex.t { + vNTT = polyAdd(vNTT, nttMul(ex.t[i], r[i])) + } + v := polyAdd(polyAdd(inverseNTT(vNTT), e2), μ) + + c := cc[:0] + for _, f := range u { + c = ringCompressAndEncode10(c, f) + } + c = ringCompressAndEncode4(c, v) + + return c +} + +// Decapsulate generates a shared key from a ciphertext and a decapsulation key. +// If the ciphertext is not valid, Decapsulate returns an error. +// +// The shared key must be kept secret. +func Decapsulate(dk *DecapsulationKey, ciphertext []byte) (sharedKey []byte, err error) { + if len(ciphertext) != CiphertextSize { + return nil, errors.New("mlkem768: invalid ciphertext length") + } + c := (*[CiphertextSize]byte)(ciphertext) + return kemDecaps(dk, c), nil +} + +// kemDecaps produces a shared key from a ciphertext. +// +// It implements ML-KEM.Decaps according to FIPS 203 (DRAFT), Algorithm 17. +func kemDecaps(dk *DecapsulationKey, c *[CiphertextSize]byte) (K []byte) { + h := dk.dk[decryptionKeySize+encryptionKeySize : decryptionKeySize+encryptionKeySize+32] + z := dk.dk[decryptionKeySize+encryptionKeySize+32:] + + m := pkeDecrypt(&dk.decryptionKey, c) + g := sha3.New512() + g.Write(m[:]) + g.Write(h) + G := g.Sum(nil) + Kprime, r := G[:SharedKeySize], G[SharedKeySize:] + J := sha3.NewShake256() + J.Write(z) + J.Write(c[:]) + Kout := make([]byte, SharedKeySize) + J.Read(Kout) + var cc [CiphertextSize]byte + c1 := pkeEncrypt(&cc, &dk.encryptionKey, (*[32]byte)(m), r) + + subtle.ConstantTimeCopy(subtle.ConstantTimeCompare(c[:], c1), Kout, Kprime) + return Kout +} + +// parseDK parses a decryption key from its encoded form. +// +// It implements the computation of s from K-PKE.Decrypt according to FIPS 203 +// (DRAFT), Algorithm 14. +func parseDK(dx *decryptionKey, dkPKE []byte) error { + if len(dkPKE) != decryptionKeySize { + return errors.New("mlkem768: invalid decryption key length") + } + + for i := range dx.s { + f, err := polyByteDecode[nttElement](dkPKE[:encodingSize12]) + if err != nil { + return err + } + dx.s[i] = f + dkPKE = dkPKE[encodingSize12:] + } + + return nil +} + +// pkeDecrypt decrypts a ciphertext. +// +// It implements K-PKE.Decrypt according to FIPS 203 (DRAFT), Algorithm 14, +// although the computation of s is done in parseDK. +func pkeDecrypt(dx *decryptionKey, c *[CiphertextSize]byte) []byte { + u := make([]ringElement, k) + for i := range u { + b := (*[encodingSize10]byte)(c[encodingSize10*i : encodingSize10*(i+1)]) + u[i] = ringDecodeAndDecompress10(b) + } + + b := (*[encodingSize4]byte)(c[encodingSize10*k:]) + v := ringDecodeAndDecompress4(b) + + var mask nttElement // s⊺ ◦ NTT(u) + for i := range dx.s { + mask = polyAdd(mask, nttMul(dx.s[i], ntt(u[i]))) + } + w := polySub(v, inverseNTT(mask)) + + return ringCompressAndEncode1(nil, w) +} + +// fieldElement is an integer modulo q, an element of ℤ_q. It is always reduced. +type fieldElement uint16 + +// fieldCheckReduced checks that a value a is < q. +func fieldCheckReduced(a uint16) (fieldElement, error) { + if a >= q { + return 0, errors.New("unreduced field element") + } + return fieldElement(a), nil +} + +// fieldReduceOnce reduces a value a < 2q. +func fieldReduceOnce(a uint16) fieldElement { + x := a - q + // If x underflowed, then x >= 2¹⁶ - q > 2¹⁵, so the top bit is set. + x += (x >> 15) * q + return fieldElement(x) +} + +func fieldAdd(a, b fieldElement) fieldElement { + x := uint16(a + b) + return fieldReduceOnce(x) +} + +func fieldSub(a, b fieldElement) fieldElement { + x := uint16(a - b + q) + return fieldReduceOnce(x) +} + +const ( + barrettMultiplier = 5039 // 2¹² * 2¹² / q + barrettShift = 24 // log₂(2¹² * 2¹²) +) + +// fieldReduce reduces a value a < 2q² using Barrett reduction, to avoid +// potentially variable-time division. +func fieldReduce(a uint32) fieldElement { + quotient := uint32((uint64(a) * barrettMultiplier) >> barrettShift) + return fieldReduceOnce(uint16(a - quotient*q)) +} + +func fieldMul(a, b fieldElement) fieldElement { + x := uint32(a) * uint32(b) + return fieldReduce(x) +} + +// fieldMulSub returns a * (b - c). This operation is fused to save a +// fieldReduceOnce after the subtraction. +func fieldMulSub(a, b, c fieldElement) fieldElement { + x := uint32(a) * uint32(b-c+q) + return fieldReduce(x) +} + +// fieldAddMul returns a * b + c * d. This operation is fused to save a +// fieldReduceOnce and a fieldReduce. +func fieldAddMul(a, b, c, d fieldElement) fieldElement { + x := uint32(a) * uint32(b) + x += uint32(c) * uint32(d) + return fieldReduce(x) +} + +// compress maps a field element uniformly to the range 0 to 2ᵈ-1, according to +// FIPS 203 (DRAFT), Definition 4.5. +func compress(x fieldElement, d uint8) uint16 { + // We want to compute (x * 2ᵈ) / q, rounded to nearest integer, with 1/2 + // rounding up (see FIPS 203 (DRAFT), Section 2.3). + + // Barrett reduction produces a quotient and a remainder in the range [0, 2q), + // such that dividend = quotient * q + remainder. + dividend := uint32(x) << d // x * 2ᵈ + quotient := uint32(uint64(dividend) * barrettMultiplier >> barrettShift) + remainder := dividend - quotient*q + + // Since the remainder is in the range [0, 2q), not [0, q), we need to + // portion it into three spans for rounding. + // + // [ 0, q/2 ) -> round to 0 + // [ q/2, q + q/2 ) -> round to 1 + // [ q + q/2, 2q ) -> round to 2 + // + // We can convert that to the following logic: add 1 if remainder > q/2, + // then add 1 again if remainder > q + q/2. + // + // Note that if remainder > x, then ⌊x⌋ - remainder underflows, and the top + // bit of the difference will be set. + quotient += (q/2 - remainder) >> 31 & 1 + quotient += (q + q/2 - remainder) >> 31 & 1 + + // quotient might have overflowed at this point, so reduce it by masking. + var mask uint32 = (1 << d) - 1 + return uint16(quotient & mask) +} + +// decompress maps a number x between 0 and 2ᵈ-1 uniformly to the full range of +// field elements, according to FIPS 203 (DRAFT), Definition 4.6. +func decompress(y uint16, d uint8) fieldElement { + // We want to compute (y * q) / 2ᵈ, rounded to nearest integer, with 1/2 + // rounding up (see FIPS 203 (DRAFT), Section 2.3). + + dividend := uint32(y) * q + quotient := dividend >> d // (y * q) / 2ᵈ + + // The d'th least-significant bit of the dividend (the most significant bit + // of the remainder) is 1 for the top half of the values that divide to the + // same quotient, which are the ones that round up. + quotient += dividend >> (d - 1) & 1 + + // quotient is at most (2¹¹-1) * q / 2¹¹ + 1 = 3328, so it didn't overflow. + return fieldElement(quotient) +} + +// ringElement is a polynomial, an element of R_q, represented as an array +// according to FIPS 203 (DRAFT), Section 2.4. +type ringElement [n]fieldElement + +// polyAdd adds two ringElements or nttElements. +func polyAdd[T ~[n]fieldElement](a, b T) (s T) { + for i := range s { + s[i] = fieldAdd(a[i], b[i]) + } + return s +} + +// polySub subtracts two ringElements or nttElements. +func polySub[T ~[n]fieldElement](a, b T) (s T) { + for i := range s { + s[i] = fieldSub(a[i], b[i]) + } + return s +} + +// polyByteEncode appends the 384-byte encoding of f to b. +// +// It implements ByteEncode₁₂, according to FIPS 203 (DRAFT), Algorithm 4. +func polyByteEncode[T ~[n]fieldElement](b []byte, f T) []byte { + out, B := sliceForAppend(b, encodingSize12) + for i := 0; i < n; i += 2 { + x := uint32(f[i]) | uint32(f[i+1])<<12 + B[0] = uint8(x) + B[1] = uint8(x >> 8) + B[2] = uint8(x >> 16) + B = B[3:] + } + return out +} + +// polyByteDecode decodes the 384-byte encoding of a polynomial, checking that +// all the coefficients are properly reduced. This achieves the "Modulus check" +// step of ML-KEM Encapsulation Input Validation. +// +// polyByteDecode is also used in ML-KEM Decapsulation, where the input +// validation is not required, but implicitly allowed by the specification. +// +// It implements ByteDecode₁₂, according to FIPS 203 (DRAFT), Algorithm 5. +func polyByteDecode[T ~[n]fieldElement](b []byte) (T, error) { + if len(b) != encodingSize12 { + return T{}, errors.New("mlkem768: invalid encoding length") + } + var f T + for i := 0; i < n; i += 2 { + d := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 + const mask12 = 0b1111_1111_1111 + var err error + if f[i], err = fieldCheckReduced(uint16(d & mask12)); err != nil { + return T{}, errors.New("mlkem768: invalid polynomial encoding") + } + if f[i+1], err = fieldCheckReduced(uint16(d >> 12)); err != nil { + return T{}, errors.New("mlkem768: invalid polynomial encoding") + } + b = b[3:] + } + return f, nil +} + +// sliceForAppend takes a slice and a requested number of bytes. It returns a +// slice with the contents of the given slice followed by that many bytes and a +// second slice that aliases into it and contains only the extra bytes. If the +// original slice has sufficient capacity then no allocation is performed. +func sliceForAppend(in []byte, n int) (head, tail []byte) { + if total := len(in) + n; cap(in) >= total { + head = in[:total] + } else { + head = make([]byte, total) + copy(head, in) + } + tail = head[len(in):] + return +} + +// ringCompressAndEncode1 appends a 32-byte encoding of a ring element to s, +// compressing one coefficients per bit. +// +// It implements Compress₁, according to FIPS 203 (DRAFT), Definition 4.5, +// followed by ByteEncode₁, according to FIPS 203 (DRAFT), Algorithm 4. +func ringCompressAndEncode1(s []byte, f ringElement) []byte { + s, b := sliceForAppend(s, encodingSize1) + for i := range b { + b[i] = 0 + } + for i := range f { + b[i/8] |= uint8(compress(f[i], 1) << (i % 8)) + } + return s +} + +// ringDecodeAndDecompress1 decodes a 32-byte slice to a ring element where each +// bit is mapped to 0 or ⌈q/2⌋. +// +// It implements ByteDecode₁, according to FIPS 203 (DRAFT), Algorithm 5, +// followed by Decompress₁, according to FIPS 203 (DRAFT), Definition 4.6. +func ringDecodeAndDecompress1(b *[encodingSize1]byte) ringElement { + var f ringElement + for i := range f { + b_i := b[i/8] >> (i % 8) & 1 + const halfQ = (q + 1) / 2 // ⌈q/2⌋, rounded up per FIPS 203 (DRAFT), Section 2.3 + f[i] = fieldElement(b_i) * halfQ // 0 decompresses to 0, and 1 to ⌈q/2⌋ + } + return f +} + +// ringCompressAndEncode4 appends a 128-byte encoding of a ring element to s, +// compressing two coefficients per byte. +// +// It implements Compress₄, according to FIPS 203 (DRAFT), Definition 4.5, +// followed by ByteEncode₄, according to FIPS 203 (DRAFT), Algorithm 4. +func ringCompressAndEncode4(s []byte, f ringElement) []byte { + s, b := sliceForAppend(s, encodingSize4) + for i := 0; i < n; i += 2 { + b[i/2] = uint8(compress(f[i], 4) | compress(f[i+1], 4)<<4) + } + return s +} + +// ringDecodeAndDecompress4 decodes a 128-byte encoding of a ring element where +// each four bits are mapped to an equidistant distribution. +// +// It implements ByteDecode₄, according to FIPS 203 (DRAFT), Algorithm 5, +// followed by Decompress₄, according to FIPS 203 (DRAFT), Definition 4.6. +func ringDecodeAndDecompress4(b *[encodingSize4]byte) ringElement { + var f ringElement + for i := 0; i < n; i += 2 { + f[i] = fieldElement(decompress(uint16(b[i/2]&0b1111), 4)) + f[i+1] = fieldElement(decompress(uint16(b[i/2]>>4), 4)) + } + return f +} + +// ringCompressAndEncode10 appends a 320-byte encoding of a ring element to s, +// compressing four coefficients per five bytes. +// +// It implements Compress₁₀, according to FIPS 203 (DRAFT), Definition 4.5, +// followed by ByteEncode₁₀, according to FIPS 203 (DRAFT), Algorithm 4. +func ringCompressAndEncode10(s []byte, f ringElement) []byte { + s, b := sliceForAppend(s, encodingSize10) + for i := 0; i < n; i += 4 { + var x uint64 + x |= uint64(compress(f[i+0], 10)) + x |= uint64(compress(f[i+1], 10)) << 10 + x |= uint64(compress(f[i+2], 10)) << 20 + x |= uint64(compress(f[i+3], 10)) << 30 + b[0] = uint8(x) + b[1] = uint8(x >> 8) + b[2] = uint8(x >> 16) + b[3] = uint8(x >> 24) + b[4] = uint8(x >> 32) + b = b[5:] + } + return s +} + +// ringDecodeAndDecompress10 decodes a 320-byte encoding of a ring element where +// each ten bits are mapped to an equidistant distribution. +// +// It implements ByteDecode₁₀, according to FIPS 203 (DRAFT), Algorithm 5, +// followed by Decompress₁₀, according to FIPS 203 (DRAFT), Definition 4.6. +func ringDecodeAndDecompress10(bb *[encodingSize10]byte) ringElement { + b := bb[:] + var f ringElement + for i := 0; i < n; i += 4 { + x := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 + b = b[5:] + f[i] = fieldElement(decompress(uint16(x>>0&0b11_1111_1111), 10)) + f[i+1] = fieldElement(decompress(uint16(x>>10&0b11_1111_1111), 10)) + f[i+2] = fieldElement(decompress(uint16(x>>20&0b11_1111_1111), 10)) + f[i+3] = fieldElement(decompress(uint16(x>>30&0b11_1111_1111), 10)) + } + return f +} + +// samplePolyCBD draws a ringElement from the special Dη distribution given a +// stream of random bytes generated by the PRF function, according to FIPS 203 +// (DRAFT), Algorithm 7 and Definition 4.1. +func samplePolyCBD(s []byte, b byte) ringElement { + prf := sha3.NewShake256() + prf.Write(s) + prf.Write([]byte{b}) + B := make([]byte, 128) + prf.Read(B) + + // SamplePolyCBD simply draws four (2η) bits for each coefficient, and adds + // the first two and subtracts the last two. + + var f ringElement + for i := 0; i < n; i += 2 { + b := B[i/2] + b_7, b_6, b_5, b_4 := b>>7, b>>6&1, b>>5&1, b>>4&1 + b_3, b_2, b_1, b_0 := b>>3&1, b>>2&1, b>>1&1, b&1 + f[i] = fieldSub(fieldElement(b_0+b_1), fieldElement(b_2+b_3)) + f[i+1] = fieldSub(fieldElement(b_4+b_5), fieldElement(b_6+b_7)) + } + return f +} + +// nttElement is an NTT representation, an element of T_q, represented as an +// array according to FIPS 203 (DRAFT), Section 2.4. +type nttElement [n]fieldElement + +// gammas are the values ζ^2BitRev7(i)+1 mod q for each index i. +var gammas = [128]fieldElement{17, 3312, 2761, 568, 583, 2746, 2649, 680, 1637, 1692, 723, 2606, 2288, 1041, 1100, 2229, 1409, 1920, 2662, 667, 3281, 48, 233, 3096, 756, 2573, 2156, 1173, 3015, 314, 3050, 279, 1703, 1626, 1651, 1678, 2789, 540, 1789, 1540, 1847, 1482, 952, 2377, 1461, 1868, 2687, 642, 939, 2390, 2308, 1021, 2437, 892, 2388, 941, 733, 2596, 2337, 992, 268, 3061, 641, 2688, 1584, 1745, 2298, 1031, 2037, 1292, 3220, 109, 375, 2954, 2549, 780, 2090, 1239, 1645, 1684, 1063, 2266, 319, 3010, 2773, 556, 757, 2572, 2099, 1230, 561, 2768, 2466, 863, 2594, 735, 2804, 525, 1092, 2237, 403, 2926, 1026, 2303, 1143, 2186, 2150, 1179, 2775, 554, 886, 2443, 1722, 1607, 1212, 2117, 1874, 1455, 1029, 2300, 2110, 1219, 2935, 394, 885, 2444, 2154, 1175} + +// nttMul multiplies two nttElements. +// +// It implements MultiplyNTTs, according to FIPS 203 (DRAFT), Algorithm 10. +func nttMul(f, g nttElement) nttElement { + var h nttElement + // We use i += 2 for bounds check elimination. See https://go.dev/issue/66826. + for i := 0; i < 256; i += 2 { + a0, a1 := f[i], f[i+1] + b0, b1 := g[i], g[i+1] + h[i] = fieldAddMul(a0, b0, fieldMul(a1, b1), gammas[i/2]) + h[i+1] = fieldAddMul(a0, b1, a1, b0) + } + return h +} + +// zetas are the values ζ^BitRev7(k) mod q for each index k. +var zetas = [128]fieldElement{1, 1729, 2580, 3289, 2642, 630, 1897, 848, 1062, 1919, 193, 797, 2786, 3260, 569, 1746, 296, 2447, 1339, 1476, 3046, 56, 2240, 1333, 1426, 2094, 535, 2882, 2393, 2879, 1974, 821, 289, 331, 3253, 1756, 1197, 2304, 2277, 2055, 650, 1977, 2513, 632, 2865, 33, 1320, 1915, 2319, 1435, 807, 452, 1438, 2868, 1534, 2402, 2647, 2617, 1481, 648, 2474, 3110, 1227, 910, 17, 2761, 583, 2649, 1637, 723, 2288, 1100, 1409, 2662, 3281, 233, 756, 2156, 3015, 3050, 1703, 1651, 2789, 1789, 1847, 952, 1461, 2687, 939, 2308, 2437, 2388, 733, 2337, 268, 641, 1584, 2298, 2037, 3220, 375, 2549, 2090, 1645, 1063, 319, 2773, 757, 2099, 561, 2466, 2594, 2804, 1092, 403, 1026, 1143, 2150, 2775, 886, 1722, 1212, 1874, 1029, 2110, 2935, 885, 2154} + +// ntt maps a ringElement to its nttElement representation. +// +// It implements NTT, according to FIPS 203 (DRAFT), Algorithm 8. +func ntt(f ringElement) nttElement { + k := 1 + for len := 128; len >= 2; len /= 2 { + for start := 0; start < 256; start += 2 * len { + zeta := zetas[k] + k++ + // Bounds check elimination hint. + f, flen := f[start:start+len], f[start+len:start+len+len] + for j := 0; j < len; j++ { + t := fieldMul(zeta, flen[j]) + flen[j] = fieldSub(f[j], t) + f[j] = fieldAdd(f[j], t) + } + } + } + return nttElement(f) +} + +// inverseNTT maps a nttElement back to the ringElement it represents. +// +// It implements NTT⁻¹, according to FIPS 203 (DRAFT), Algorithm 9. +func inverseNTT(f nttElement) ringElement { + k := 127 + for len := 2; len <= 128; len *= 2 { + for start := 0; start < 256; start += 2 * len { + zeta := zetas[k] + k-- + // Bounds check elimination hint. + f, flen := f[start:start+len], f[start+len:start+len+len] + for j := 0; j < len; j++ { + t := f[j] + f[j] = fieldAdd(t, flen[j]) + flen[j] = fieldMulSub(zeta, flen[j], t) + } + } + } + for i := range f { + f[i] = fieldMul(f[i], 3303) // 3303 = 128⁻¹ mod q + } + return ringElement(f) +} + +// sampleNTT draws a uniformly random nttElement from a stream of uniformly +// random bytes generated by the XOF function, according to FIPS 203 (DRAFT), +// Algorithm 6 and Definition 4.2. +func sampleNTT(rho []byte, ii, jj byte) nttElement { + B := sha3.NewShake128() + B.Write(rho) + B.Write([]byte{ii, jj}) + + // SampleNTT essentially draws 12 bits at a time from r, interprets them in + // little-endian, and rejects values higher than q, until it drew 256 + // values. (The rejection rate is approximately 19%.) + // + // To do this from a bytes stream, it draws three bytes at a time, and + // splits them into two uint16 appropriately masked. + // + // r₀ r₁ r₂ + // |- - - - - - - -|- - - - - - - -|- - - - - - - -| + // + // Uint16(r₀ || r₁) + // |- - - - - - - - - - - - - - - -| + // |- - - - - - - - - - - -| + // d₁ + // + // Uint16(r₁ || r₂) + // |- - - - - - - - - - - - - - - -| + // |- - - - - - - - - - - -| + // d₂ + // + // Note that in little-endian, the rightmost bits are the most significant + // bits (dropped with a mask) and the leftmost bits are the least + // significant bits (dropped with a right shift). + + var a nttElement + var j int // index into a + var buf [24]byte // buffered reads from B + off := len(buf) // index into buf, starts in a "buffer fully consumed" state + for { + if off >= len(buf) { + B.Read(buf[:]) + off = 0 + } + d1 := byteorder.LeUint16(buf[off:]) & 0b1111_1111_1111 + d2 := byteorder.LeUint16(buf[off+1:]) >> 4 + off += 3 + if d1 < q { + a[j] = fieldElement(d1) + j++ + } + if j >= len(a) { + break + } + if d2 < q { + a[j] = fieldElement(d2) + j++ + } + if j >= len(a) { + break + } + } + return a +} diff --git a/contrib/go/_std_1.23/src/crypto/internal/mlkem768/ya.make b/contrib/go/_std_1.23/src/crypto/internal/mlkem768/ya.make new file mode 100644 index 000000000000..60ce6440a2a8 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/internal/mlkem768/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + mlkem768.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/Dockerfile b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/Dockerfile similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/Dockerfile rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/Dockerfile diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/README b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/README similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/README rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/README diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/generate.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/generate.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/generate.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/generate.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p224.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p224.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p224.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p224.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p224_fiat64.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p224_fiat64.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p224_fiat64.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p224_fiat64.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p224_invert.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p224_invert.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p224_invert.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p224_invert.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p256.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p256.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p256.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p256.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p256_fiat64.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p256_fiat64.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p256_fiat64.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p256_fiat64.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p256_invert.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p256_invert.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p256_invert.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p256_invert.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p384.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p384.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p384.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p384.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p384_fiat64.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p384_fiat64.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p384_fiat64.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p384_fiat64.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p384_invert.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p384_invert.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p384_invert.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p384_invert.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p521.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p521.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p521.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p521.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p521_fiat64.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p521_fiat64.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p521_fiat64.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p521_fiat64.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p521_invert.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p521_invert.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/p521_invert.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/p521_invert.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/ya.make b/contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/fiat/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/nistec/fiat/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/generate.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/generate.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/generate.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/generate.go index 0e84cefb3657..27e8d13943b2 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/generate.go +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/generate.go @@ -40,7 +40,7 @@ var curves = []struct { P: "P256", Element: "fiat.P256Element", Params: elliptic.P256().Params(), - BuildTags: "!amd64 && !arm64 && !ppc64le && !s390x", + BuildTags: "(!amd64 && !arm64 && !ppc64le && !s390x) || purego", }, { P: "P384", diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/nistec.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/nistec.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/nistec.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/nistec.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p224.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p224.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p224.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p224.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p224_sqrt.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p224_sqrt.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p224_sqrt.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p224_sqrt.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256.go index 3cfa5fb37179..f2dfbbb1ee9b 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256.go +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256.go @@ -4,7 +4,7 @@ // Code generated by generate.go. DO NOT EDIT. -//go:build !amd64 && !arm64 && !ppc64le && !s390x +//go:build (!amd64 && !arm64 && !ppc64le && !s390x) || purego package nistec diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm.go index 99a22b833f02..5dbd7efbd56d 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm.go +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm.go @@ -10,14 +10,14 @@ // https://link.springer.com/article/10.1007%2Fs13389-014-0090-x // https://eprint.iacr.org/2013/816.pdf -//go:build amd64 || arm64 || ppc64le || s390x +//go:build (amd64 || arm64 || ppc64le || s390x) && !purego package nistec import ( _ "embed" - "encoding/binary" "errors" + "internal/byteorder" "math/bits" "runtime" "unsafe" @@ -327,7 +327,7 @@ func init() { if runtime.GOARCH == "s390x" { var newTable [43 * 32 * 2 * 4]uint64 for i, x := range (*[43 * 32 * 2 * 4][8]byte)(*p256PrecomputedPtr) { - newTable[i] = binary.LittleEndian.Uint64(x[:]) + newTable[i] = byteorder.LeUint64(x[:]) } newTablePtr := unsafe.Pointer(&newTable) p256PrecomputedPtr = &newTablePtr diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_amd64.s b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_amd64.s rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_amd64.s index 84e4cee9039c..f5c008319bd7 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_amd64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + // This file contains constant-time, 64-bit assembly implementation of // P256. The optimizations performed here are described in detail in: // S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_arm64.s b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_arm64.s rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_arm64.s index 1ba5df381b3a..d00a54db1adc 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_arm64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + // This file contains constant-time, 64-bit assembly implementation of // P256. The optimizations performed here are described in detail in: // S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_ppc64le.s b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_ppc64le.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_ppc64le.s rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_ppc64le.s index 6b787609b999..b13bd512a6e3 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_ppc64le.s +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_ppc64le.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // This is a port of the s390x asm implementation. @@ -124,14 +126,23 @@ GLOBL p256mul<>(SB), 8, $160 #define PH V31 #define CAR1 V6 + +#define SEL V8 +#define ZER V9 + // func p256NegCond(val *p256Point, cond int) TEXT ·p256NegCond(SB), NOSPLIT, $0-16 MOVD val+0(FP), P1ptr MOVD $16, R16 - MOVD cond+8(FP), R6 - CMP $0, R6 - BC 12, 2, LR // just return if cond == 0 + // Copy cond into SEL (cond is R1 + 8 (cond offset) + 32) + MOVD $40, R17 + LXVDSX (R1)(R17), SEL + // Zeroize ZER + VSPLTISB $0, ZER + // SEL controls whether to return the original value (Y1H/Y1L) + // or the negated value (T1H/T1L). + VCMPEQUD SEL, ZER, SEL MOVD $p256mul<>+0x00(SB), CPOOL @@ -148,6 +159,9 @@ TEXT ·p256NegCond(SB), NOSPLIT, $0-16 VSUBUQM PL, Y1L, T1L // subtract part2 giving result VSUBEUQM PH, Y1H, CAR1, T1H // subtract part1 using carry from part2 + VSEL T1H, Y1H, SEL, T1H + VSEL T1L, Y1L, SEL, T1L + XXPERMDI T1H, T1H, $2, T1H XXPERMDI T1L, T1L, $2, T1L @@ -164,6 +178,8 @@ TEXT ·p256NegCond(SB), NOSPLIT, $0-16 #undef PL #undef PH #undef CAR1 +#undef SEL +#undef ZER #define P3ptr R3 #define P1ptr R4 diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_s390x.s b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_s390x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_s390x.s rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_s390x.s index 8da4f3f5b89d..77c9f63349a0 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_s390x.s +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_s390x.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" #include "go_asm.h" diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_table.bin b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_table.bin similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_asm_table.bin rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_asm_table.bin diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_ordinv.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_ordinv.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_ordinv.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_ordinv.go index 1274fb7fd3f5..156a873188c3 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_ordinv.go +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_ordinv.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build amd64 || arm64 +//go:build (amd64 || arm64) && !purego package nistec diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_ordinv_noasm.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_ordinv_noasm.go similarity index 87% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p256_ordinv_noasm.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p256_ordinv_noasm.go index 213875ce7616..9cbb1a89dbaf 100644 --- a/contrib/go/_std_1.22/src/crypto/internal/nistec/p256_ordinv_noasm.go +++ b/contrib/go/_std_1.23/src/crypto/internal/nistec/p256_ordinv_noasm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 && !arm64 +//go:build (!amd64 && !arm64) || purego package nistec diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p384.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p384.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p384.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p384.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/p521.go b/contrib/go/_std_1.23/src/crypto/internal/nistec/p521.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/p521.go rename to contrib/go/_std_1.23/src/crypto/internal/nistec/p521.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/nistec/ya.make b/contrib/go/_std_1.23/src/crypto/internal/nistec/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/nistec/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/nistec/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/randutil/randutil.go b/contrib/go/_std_1.23/src/crypto/internal/randutil/randutil.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/randutil/randutil.go rename to contrib/go/_std_1.23/src/crypto/internal/randutil/randutil.go diff --git a/contrib/go/_std_1.22/src/crypto/internal/randutil/ya.make b/contrib/go/_std_1.23/src/crypto/internal/randutil/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/randutil/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/randutil/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/internal/ya.make b/contrib/go/_std_1.23/src/crypto/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/internal/ya.make rename to contrib/go/_std_1.23/src/crypto/internal/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/md5/gen.go b/contrib/go/_std_1.23/src/crypto/md5/gen.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/md5/gen.go rename to contrib/go/_std_1.23/src/crypto/md5/gen.go index cd2700a5cfeb..5290c3627c9b 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/gen.go +++ b/contrib/go/_std_1.23/src/crypto/md5/gen.go @@ -201,7 +201,7 @@ var program = `// Copyright 2013 The Go Authors. All rights reserved. package md5 import ( - "encoding/binary" + "internal/byteorder" "math/bits" ) @@ -219,7 +219,7 @@ func blockGeneric(dig *digest, p []byte) { // load input block {{range $i := seq 16 -}} - {{printf "x%x := binary.LittleEndian.Uint32(q[4*%#x:])" $i $i}} + {{printf "x%x := byteorder.LeUint32(q[4*%#x:])" $i $i}} {{end}} // round 1 @@ -227,19 +227,19 @@ func blockGeneric(dig *digest, p []byte) { {{printf "arg0 = arg1 + bits.RotateLeft32((((arg2^arg3)&arg1)^arg3)+arg0+x%x+%#08x, %d)" (idx 1 $i) (index $.Table1 $i) $s | relabel}} {{rotate -}} {{end}} - + // round 2 {{range $i, $s := dup 4 .Shift2 -}} {{printf "arg0 = arg1 + bits.RotateLeft32((((arg1^arg2)&arg3)^arg2)+arg0+x%x+%#08x, %d)" (idx 2 $i) (index $.Table2 $i) $s | relabel}} {{rotate -}} {{end}} - + // round 3 {{range $i, $s := dup 4 .Shift3 -}} {{printf "arg0 = arg1 + bits.RotateLeft32((arg1^arg2^arg3)+arg0+x%x+%#08x, %d)" (idx 3 $i) (index $.Table3 $i) $s | relabel}} {{rotate -}} {{end}} - + // round 4 {{range $i, $s := dup 4 .Shift4 -}} {{printf "arg0 = arg1 + bits.RotateLeft32((arg2^(arg1|^arg3))+arg0+x%x+%#08x, %d)" (idx 4 $i) (index $.Table4 $i) $s | relabel}} diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5.go b/contrib/go/_std_1.23/src/crypto/md5/md5.go similarity index 83% rename from contrib/go/_std_1.22/src/crypto/md5/md5.go rename to contrib/go/_std_1.23/src/crypto/md5/md5.go index 83e9e4c07a0a..843678702bf9 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5.go +++ b/contrib/go/_std_1.23/src/crypto/md5/md5.go @@ -12,9 +12,9 @@ package md5 import ( "crypto" - "encoding/binary" "errors" "hash" + "internal/byteorder" ) func init() { @@ -59,13 +59,13 @@ const ( func (d *digest) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize) b = append(b, magic...) - b = binary.BigEndian.AppendUint32(b, d.s[0]) - b = binary.BigEndian.AppendUint32(b, d.s[1]) - b = binary.BigEndian.AppendUint32(b, d.s[2]) - b = binary.BigEndian.AppendUint32(b, d.s[3]) + b = byteorder.BeAppendUint32(b, d.s[0]) + b = byteorder.BeAppendUint32(b, d.s[1]) + b = byteorder.BeAppendUint32(b, d.s[2]) + b = byteorder.BeAppendUint32(b, d.s[3]) b = append(b, d.x[:d.nx]...) b = b[:len(b)+len(d.x)-d.nx] // already zero - b = binary.BigEndian.AppendUint64(b, d.len) + b = byteorder.BeAppendUint64(b, d.len) return b, nil } @@ -88,11 +88,11 @@ func (d *digest) UnmarshalBinary(b []byte) error { } func consumeUint64(b []byte) ([]byte, uint64) { - return b[8:], binary.BigEndian.Uint64(b[0:8]) + return b[8:], byteorder.BeUint64(b[0:8]) } func consumeUint32(b []byte) ([]byte, uint32) { - return b[4:], binary.BigEndian.Uint32(b[0:4]) + return b[4:], byteorder.BeUint32(b[0:4]) } // New returns a new hash.Hash computing the MD5 checksum. The Hash also @@ -156,8 +156,8 @@ func (d *digest) checkSum() [Size]byte { // // 1 byte end marker :: 0-63 padding bytes :: 8 byte length tmp := [1 + 63 + 8]byte{0x80} - pad := (55 - d.len) % 64 // calculate number of padding bytes - binary.LittleEndian.PutUint64(tmp[1+pad:], d.len<<3) // append length in bits + pad := (55 - d.len) % 64 // calculate number of padding bytes + byteorder.LePutUint64(tmp[1+pad:], d.len<<3) // append length in bits d.Write(tmp[:1+pad+8]) // The previous write ensures that a whole number of @@ -167,10 +167,10 @@ func (d *digest) checkSum() [Size]byte { } var digest [Size]byte - binary.LittleEndian.PutUint32(digest[0:], d.s[0]) - binary.LittleEndian.PutUint32(digest[4:], d.s[1]) - binary.LittleEndian.PutUint32(digest[8:], d.s[2]) - binary.LittleEndian.PutUint32(digest[12:], d.s[3]) + byteorder.LePutUint32(digest[0:], d.s[0]) + byteorder.LePutUint32(digest[4:], d.s[1]) + byteorder.LePutUint32(digest[8:], d.s[2]) + byteorder.LePutUint32(digest[12:], d.s[3]) return digest } diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block.go b/contrib/go/_std_1.23/src/crypto/md5/md5block.go similarity index 86% rename from contrib/go/_std_1.22/src/crypto/md5/md5block.go rename to contrib/go/_std_1.23/src/crypto/md5/md5block.go index 4ff289e860f9..473496b8d0ac 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block.go +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block.go @@ -7,7 +7,7 @@ package md5 import ( - "encoding/binary" + "internal/byteorder" "math/bits" ) @@ -24,22 +24,22 @@ func blockGeneric(dig *digest, p []byte) { aa, bb, cc, dd := a, b, c, d // load input block - x0 := binary.LittleEndian.Uint32(q[4*0x0:]) - x1 := binary.LittleEndian.Uint32(q[4*0x1:]) - x2 := binary.LittleEndian.Uint32(q[4*0x2:]) - x3 := binary.LittleEndian.Uint32(q[4*0x3:]) - x4 := binary.LittleEndian.Uint32(q[4*0x4:]) - x5 := binary.LittleEndian.Uint32(q[4*0x5:]) - x6 := binary.LittleEndian.Uint32(q[4*0x6:]) - x7 := binary.LittleEndian.Uint32(q[4*0x7:]) - x8 := binary.LittleEndian.Uint32(q[4*0x8:]) - x9 := binary.LittleEndian.Uint32(q[4*0x9:]) - xa := binary.LittleEndian.Uint32(q[4*0xa:]) - xb := binary.LittleEndian.Uint32(q[4*0xb:]) - xc := binary.LittleEndian.Uint32(q[4*0xc:]) - xd := binary.LittleEndian.Uint32(q[4*0xd:]) - xe := binary.LittleEndian.Uint32(q[4*0xe:]) - xf := binary.LittleEndian.Uint32(q[4*0xf:]) + x0 := byteorder.LeUint32(q[4*0x0:]) + x1 := byteorder.LeUint32(q[4*0x1:]) + x2 := byteorder.LeUint32(q[4*0x2:]) + x3 := byteorder.LeUint32(q[4*0x3:]) + x4 := byteorder.LeUint32(q[4*0x4:]) + x5 := byteorder.LeUint32(q[4*0x5:]) + x6 := byteorder.LeUint32(q[4*0x6:]) + x7 := byteorder.LeUint32(q[4*0x7:]) + x8 := byteorder.LeUint32(q[4*0x8:]) + x9 := byteorder.LeUint32(q[4*0x9:]) + xa := byteorder.LeUint32(q[4*0xa:]) + xb := byteorder.LeUint32(q[4*0xb:]) + xc := byteorder.LeUint32(q[4*0xc:]) + xd := byteorder.LeUint32(q[4*0xd:]) + xe := byteorder.LeUint32(q[4*0xe:]) + xf := byteorder.LeUint32(q[4*0xf:]) // round 1 a = b + bits.RotateLeft32((((c^d)&b)^d)+a+x0+0xd76aa478, 7) diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block_386.s b/contrib/go/_std_1.23/src/crypto/md5/md5block_386.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/md5/md5block_386.s rename to contrib/go/_std_1.23/src/crypto/md5/md5block_386.s index 30d4209a6240..b6c6509d3b52 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block_386.s +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_386.s @@ -6,6 +6,8 @@ // #defines generating 8a assembly, and adjusted for 386, // by the Go Authors. +//go:build !purego + #include "textflag.h" // MD5 optimized for AMD64. diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block_amd64.s b/contrib/go/_std_1.23/src/crypto/md5/md5block_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/md5/md5block_amd64.s rename to contrib/go/_std_1.23/src/crypto/md5/md5block_amd64.s index 75c8074b37eb..652506ae27fb 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_amd64.s @@ -5,6 +5,8 @@ // Translated from Perl generating GNU assembly into // #defines generating 6a assembly by the Go Authors. +//go:build !purego + #include "textflag.h" // MD5 optimized for AMD64. diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block_arm.s b/contrib/go/_std_1.23/src/crypto/md5/md5block_arm.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/md5/md5block_arm.s rename to contrib/go/_std_1.23/src/crypto/md5/md5block_arm.s index 54d02b743a6a..13fdc5c3beb5 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block_arm.s +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_arm.s @@ -4,6 +4,8 @@ // // ARM version of md5block.go +//go:build !purego + #include "textflag.h" // Register definitions diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block_arm64.s b/contrib/go/_std_1.23/src/crypto/md5/md5block_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/md5/md5block_arm64.s rename to contrib/go/_std_1.23/src/crypto/md5/md5block_arm64.s index 39b9851d1fe1..5942218f76fb 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_arm64.s @@ -5,6 +5,8 @@ // ARM64 version of md5block.go // derived from crypto/md5/md5block_amd64.s +//go:build !purego + #include "textflag.h" TEXT ·block(SB),NOSPLIT,$0-32 diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block_decl.go b/contrib/go/_std_1.23/src/crypto/md5/md5block_decl.go similarity index 74% rename from contrib/go/_std_1.22/src/crypto/md5/md5block_decl.go rename to contrib/go/_std_1.23/src/crypto/md5/md5block_decl.go index f1fb34c3d7fb..3664542fb920 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block_decl.go +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_decl.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build amd64 || 386 || arm || ppc64le || ppc64 || s390x || arm64 +//go:build (amd64 || 386 || arm || ppc64le || ppc64 || s390x || arm64) && !purego package md5 diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block_generic.go b/contrib/go/_std_1.23/src/crypto/md5/md5block_generic.go similarity index 74% rename from contrib/go/_std_1.22/src/crypto/md5/md5block_generic.go rename to contrib/go/_std_1.23/src/crypto/md5/md5block_generic.go index c929c2b84aca..43cfebd38a90 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block_generic.go +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 && !386 && !arm && !ppc64le && !ppc64 && !s390x && !arm64 +//go:build (!amd64 && !386 && !arm && !ppc64le && !ppc64 && !s390x && !arm64) || purego package md5 diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block_ppc64x.s b/contrib/go/_std_1.23/src/crypto/md5/md5block_ppc64x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/md5/md5block_ppc64x.s rename to contrib/go/_std_1.23/src/crypto/md5/md5block_ppc64x.s index 69a20e7cad33..49a369548ee7 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block_ppc64x.s +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_ppc64x.s @@ -10,7 +10,7 @@ // Licence: I hereby disclaim the copyright on this code and place it // in the public domain. -//go:build ppc64 || ppc64le +//go:build (ppc64 || ppc64le) && !purego #include "textflag.h" @@ -200,7 +200,7 @@ loop: ADD R16, R4 ADD R17, R5 ADD $64, R6 - BC 16, 0, loop // bdnz + BDNZ loop end: MOVD dig+0(FP), R10 diff --git a/contrib/go/_std_1.22/src/crypto/md5/md5block_s390x.s b/contrib/go/_std_1.23/src/crypto/md5/md5block_s390x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/md5/md5block_s390x.s rename to contrib/go/_std_1.23/src/crypto/md5/md5block_s390x.s index 68f501cfea83..2d18d28f2514 100644 --- a/contrib/go/_std_1.22/src/crypto/md5/md5block_s390x.s +++ b/contrib/go/_std_1.23/src/crypto/md5/md5block_s390x.s @@ -10,6 +10,8 @@ // Licence: I hereby disclaim the copyright on this code and place it // in the public domain. +//go:build !purego + #include "textflag.h" // func block(dig *digest, p []byte) diff --git a/contrib/go/_std_1.22/src/crypto/md5/ya.make b/contrib/go/_std_1.23/src/crypto/md5/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/md5/ya.make rename to contrib/go/_std_1.23/src/crypto/md5/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/rand/rand.go b/contrib/go/_std_1.23/src/crypto/rand/rand.go similarity index 67% rename from contrib/go/_std_1.22/src/crypto/rand/rand.go rename to contrib/go/_std_1.23/src/crypto/rand/rand.go index d0dcc7cc71fc..d16d7a1c9c3f 100644 --- a/contrib/go/_std_1.22/src/crypto/rand/rand.go +++ b/contrib/go/_std_1.23/src/crypto/rand/rand.go @@ -11,13 +11,14 @@ import "io" // Reader is a global, shared instance of a cryptographically // secure random number generator. // -// On Linux, FreeBSD, Dragonfly, NetBSD and Solaris, Reader uses getrandom(2) if -// available, /dev/urandom otherwise. -// On OpenBSD and macOS, Reader uses getentropy(2). -// On other Unix-like systems, Reader reads from /dev/urandom. -// On Windows systems, Reader uses the ProcessPrng API. -// On JS/Wasm, Reader uses the Web Crypto API. -// On WASIP1/Wasm, Reader uses random_get from wasi_snapshot_preview1. +// - On Linux, FreeBSD, Dragonfly, and Solaris, Reader uses getrandom(2) +// if available, and /dev/urandom otherwise. +// - On macOS and iOS, Reader uses arc4random_buf(3). +// - On OpenBSD and NetBSD, Reader uses getentropy(2). +// - On other Unix-like systems, Reader reads from /dev/urandom. +// - On Windows, Reader uses the ProcessPrng API. +// - On js/wasm, Reader uses the Web Crypto API. +// - On wasip1/wasm, Reader uses random_get from wasi_snapshot_preview1. var Reader io.Reader // Read is a helper function that calls Reader.Read using io.ReadFull. diff --git a/contrib/go/_std_1.23/src/crypto/rand/rand_darwin.go b/contrib/go/_std_1.23/src/crypto/rand/rand_darwin.go new file mode 100644 index 000000000000..363ad69ec4a4 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/rand/rand_darwin.go @@ -0,0 +1,19 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rand + +import "internal/syscall/unix" + +func init() { + // arc4random_buf is the recommended application CSPRNG, accepts buffers of + // any size, and never returns an error. + // + // "The subsystem is re-seeded from the kernel random number subsystem on a + // regular basis, and also upon fork(2)." - arc4random(3) + // + // Note that despite its legacy name, it uses a secure CSPRNG (not RC4) in + // all supported macOS versions. + altGetRandom = func(b []byte) error { unix.ARC4Random(b); return nil } +} diff --git a/contrib/go/_std_1.22/src/crypto/rand/rand_getentropy.go b/contrib/go/_std_1.23/src/crypto/rand/rand_getentropy.go similarity index 71% rename from contrib/go/_std_1.22/src/crypto/rand/rand_getentropy.go rename to contrib/go/_std_1.23/src/crypto/rand/rand_getentropy.go index 210250411eab..855716c83dd0 100644 --- a/contrib/go/_std_1.22/src/crypto/rand/rand_getentropy.go +++ b/contrib/go/_std_1.23/src/crypto/rand/rand_getentropy.go @@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build (darwin && !ios) || openbsd || netbsd +//go:build openbsd || netbsd package rand import "internal/syscall/unix" func init() { - // getentropy(2) returns a maximum of 256 bytes per call + // getentropy(2) returns a maximum of 256 bytes per call. altGetRandom = batched(unix.GetEntropy, 256) } diff --git a/contrib/go/_std_1.22/src/crypto/rand/rand_getrandom.go b/contrib/go/_std_1.23/src/crypto/rand/rand_getrandom.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rand/rand_getrandom.go rename to contrib/go/_std_1.23/src/crypto/rand/rand_getrandom.go diff --git a/contrib/go/_std_1.22/src/crypto/rand/rand_js.go b/contrib/go/_std_1.23/src/crypto/rand/rand_js.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rand/rand_js.go rename to contrib/go/_std_1.23/src/crypto/rand/rand_js.go diff --git a/contrib/go/_std_1.22/src/crypto/rand/rand_plan9.go b/contrib/go/_std_1.23/src/crypto/rand/rand_plan9.go similarity index 95% rename from contrib/go/_std_1.22/src/crypto/rand/rand_plan9.go rename to contrib/go/_std_1.23/src/crypto/rand/rand_plan9.go index 5d0af0959e9d..d5320210fd9c 100644 --- a/contrib/go/_std_1.22/src/crypto/rand/rand_plan9.go +++ b/contrib/go/_std_1.23/src/crypto/rand/rand_plan9.go @@ -9,7 +9,7 @@ package rand import ( "crypto/aes" - "encoding/binary" + "internal/byteorder" "io" "os" "sync" @@ -44,6 +44,7 @@ func (r *reader) Read(b []byte) (n int, err error) { r.seedErr = err return } + defer entropy.Close() _, r.seedErr = io.ReadFull(entropy, r.key[:]) }) if r.seedErr != nil { @@ -65,7 +66,7 @@ func (r *reader) Read(b []byte) (n int, err error) { if counter == 0 { panic("crypto/rand counter wrapped") } - binary.LittleEndian.PutUint64(block[:], counter) + byteorder.LePutUint64(block[:], counter) } blockCipher.Encrypt(r.key[:aes.BlockSize], block[:]) inc() diff --git a/contrib/go/_std_1.22/src/crypto/rand/rand_unix.go b/contrib/go/_std_1.23/src/crypto/rand/rand_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rand/rand_unix.go rename to contrib/go/_std_1.23/src/crypto/rand/rand_unix.go diff --git a/contrib/go/_std_1.22/src/crypto/rand/rand_wasip1.go b/contrib/go/_std_1.23/src/crypto/rand/rand_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rand/rand_wasip1.go rename to contrib/go/_std_1.23/src/crypto/rand/rand_wasip1.go diff --git a/contrib/go/_std_1.22/src/crypto/rand/rand_windows.go b/contrib/go/_std_1.23/src/crypto/rand/rand_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rand/rand_windows.go rename to contrib/go/_std_1.23/src/crypto/rand/rand_windows.go diff --git a/contrib/go/_std_1.22/src/crypto/rand/util.go b/contrib/go/_std_1.23/src/crypto/rand/util.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rand/util.go rename to contrib/go/_std_1.23/src/crypto/rand/util.go diff --git a/contrib/go/_std_1.22/src/crypto/rand/ya.make b/contrib/go/_std_1.23/src/crypto/rand/ya.make similarity index 98% rename from contrib/go/_std_1.22/src/crypto/rand/ya.make rename to contrib/go/_std_1.23/src/crypto/rand/ya.make index 228a081aaeaa..ba4e97121def 100644 --- a/contrib/go/_std_1.22/src/crypto/rand/ya.make +++ b/contrib/go/_std_1.23/src/crypto/rand/ya.make @@ -2,7 +2,7 @@ GO_LIBRARY() IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( rand.go - rand_getentropy.go + rand_darwin.go rand_unix.go util.go ) diff --git a/contrib/go/_std_1.22/src/crypto/rc4/rc4.go b/contrib/go/_std_1.23/src/crypto/rc4/rc4.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rc4/rc4.go rename to contrib/go/_std_1.23/src/crypto/rc4/rc4.go diff --git a/contrib/go/_std_1.22/src/crypto/rc4/ya.make b/contrib/go/_std_1.23/src/crypto/rc4/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rc4/ya.make rename to contrib/go/_std_1.23/src/crypto/rc4/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/rsa/boring.go b/contrib/go/_std_1.23/src/crypto/rsa/boring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rsa/boring.go rename to contrib/go/_std_1.23/src/crypto/rsa/boring.go diff --git a/contrib/go/_std_1.22/src/crypto/rsa/notboring.go b/contrib/go/_std_1.23/src/crypto/rsa/notboring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rsa/notboring.go rename to contrib/go/_std_1.23/src/crypto/rsa/notboring.go diff --git a/contrib/go/_std_1.22/src/crypto/rsa/pkcs1v15.go b/contrib/go/_std_1.23/src/crypto/rsa/pkcs1v15.go similarity index 91% rename from contrib/go/_std_1.22/src/crypto/rsa/pkcs1v15.go rename to contrib/go/_std_1.23/src/crypto/rsa/pkcs1v15.go index 2705036fddf4..2f958022f985 100644 --- a/contrib/go/_std_1.22/src/crypto/rsa/pkcs1v15.go +++ b/contrib/go/_std_1.23/src/crypto/rsa/pkcs1v15.go @@ -5,6 +5,7 @@ package rsa import ( + "bytes" "crypto" "crypto/internal/boring" "crypto/internal/randutil" @@ -285,17 +286,13 @@ var hashPrefixes = map[crypto.Hash][]byte{ // messages to signatures and identify the signed messages. As ever, // signatures provide authenticity, not confidentiality. func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) { - hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed)) + // pkcs1v15ConstructEM is called before boring.SignRSAPKCS1v15 to return + // consistent errors, including ErrMessageTooLong. + em, err := pkcs1v15ConstructEM(&priv.PublicKey, hash, hashed) if err != nil { return nil, err } - tLen := len(prefix) + hashLen - k := priv.Size() - if k < tLen+11 { - return nil, ErrMessageTooLong - } - if boring.Enabled { bkey, err := boringPrivateKey(priv) if err != nil { @@ -304,16 +301,37 @@ func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed [ return boring.SignRSAPKCS1v15(bkey, hash, hashed) } + return decrypt(priv, em, withCheck) +} + +func pkcs1v15ConstructEM(pub *PublicKey, hash crypto.Hash, hashed []byte) ([]byte, error) { + // Special case: crypto.Hash(0) is used to indicate that the data is + // signed directly. + var prefix []byte + if hash != 0 { + if len(hashed) != hash.Size() { + return nil, errors.New("crypto/rsa: input must be hashed message") + } + var ok bool + prefix, ok = hashPrefixes[hash] + if !ok { + return nil, errors.New("crypto/rsa: unsupported hash function") + } + } + // EM = 0x00 || 0x01 || PS || 0x00 || T + k := pub.Size() + if k < len(prefix)+len(hashed)+2+8+1 { + return nil, ErrMessageTooLong + } em := make([]byte, k) em[1] = 1 - for i := 2; i < k-tLen-1; i++ { + for i := 2; i < k-len(prefix)-len(hashed)-1; i++ { em[i] = 0xff } - copy(em[k-tLen:k-hashLen], prefix) - copy(em[k-hashLen:k], hashed) - - return decrypt(priv, em, withCheck) + copy(em[k-len(prefix)-len(hashed):], prefix) + copy(em[k-len(hashed):], hashed) + return em, nil } // VerifyPKCS1v15 verifies an RSA PKCS #1 v1.5 signature. @@ -321,6 +339,9 @@ func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed [ // function and sig is the signature. A valid signature is indicated by // returning a nil error. If hash is zero then hashed is used directly. This // isn't advisable except for interoperability. +// +// The inputs are not considered confidential, and may leak through timing side +// channels, or if an attacker has control of part of the inputs. func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error { if boring.Enabled { bkey, err := boringPublicKey(pub) @@ -333,21 +354,10 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) return nil } - hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed)) - if err != nil { - return err - } - - tLen := len(prefix) + hashLen - k := pub.Size() - if k < tLen+11 { - return ErrVerification - } - // RFC 8017 Section 8.2.2: If the length of the signature S is not k // octets (where k is the length in octets of the RSA modulus n), output // "invalid signature" and stop. - if k != len(sig) { + if pub.Size() != len(sig) { return ErrVerification } @@ -355,39 +365,14 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) if err != nil { return ErrVerification } - // EM = 0x00 || 0x01 || PS || 0x00 || T - - ok := subtle.ConstantTimeByteEq(em[0], 0) - ok &= subtle.ConstantTimeByteEq(em[1], 1) - ok &= subtle.ConstantTimeCompare(em[k-hashLen:k], hashed) - ok &= subtle.ConstantTimeCompare(em[k-tLen:k-hashLen], prefix) - ok &= subtle.ConstantTimeByteEq(em[k-tLen-1], 0) - for i := 2; i < k-tLen-1; i++ { - ok &= subtle.ConstantTimeByteEq(em[i], 0xff) + expected, err := pkcs1v15ConstructEM(pub, hash, hashed) + if err != nil { + return ErrVerification } - - if ok != 1 { + if !bytes.Equal(em, expected) { return ErrVerification } return nil } - -func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) { - // Special case: crypto.Hash(0) is used to indicate that the data is - // signed directly. - if hash == 0 { - return inLen, nil, nil - } - - hashLen = hash.Size() - if inLen != hashLen { - return 0, nil, errors.New("crypto/rsa: input must be hashed message") - } - prefix, ok := hashPrefixes[hash] - if !ok { - return 0, nil, errors.New("crypto/rsa: unsupported hash function") - } - return -} diff --git a/contrib/go/_std_1.22/src/crypto/rsa/pss.go b/contrib/go/_std_1.23/src/crypto/rsa/pss.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/rsa/pss.go rename to contrib/go/_std_1.23/src/crypto/rsa/pss.go index b63b6eb01db6..e996e7aaa36b 100644 --- a/contrib/go/_std_1.22/src/crypto/rsa/pss.go +++ b/contrib/go/_std_1.23/src/crypto/rsa/pss.go @@ -338,6 +338,9 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, // result of hashing the input message using the given hash function. The opts // argument may be nil, in which case sensible defaults are used. opts.Hash is // ignored. +// +// The inputs are not considered confidential, and may leak through timing side +// channels, or if an attacker has control of part of the inputs. func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts *PSSOptions) error { if boring.Enabled { bkey, err := boringPublicKey(pub) diff --git a/contrib/go/_std_1.22/src/crypto/rsa/rsa.go b/contrib/go/_std_1.23/src/crypto/rsa/rsa.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/rsa/rsa.go rename to contrib/go/_std_1.23/src/crypto/rsa/rsa.go index 9342930dc123..4d78d1eaaa6b 100644 --- a/contrib/go/_std_1.22/src/crypto/rsa/rsa.go +++ b/contrib/go/_std_1.23/src/crypto/rsa/rsa.go @@ -19,10 +19,9 @@ // over the public key primitive, the PrivateKey type implements the // Decrypter and Signer interfaces from the crypto package. // -// Operations in this package are implemented using constant-time algorithms, -// except for [GenerateKey], [PrivateKey.Precompute], and [PrivateKey.Validate]. -// Every other operation only leaks the bit size of the involved values, which -// all depend on the selected key size. +// Operations involving private keys are implemented using constant-time +// algorithms, except for [GenerateKey], [PrivateKey.Precompute], and +// [PrivateKey.Validate]. package rsa import ( diff --git a/contrib/go/_std_1.22/src/crypto/rsa/ya.make b/contrib/go/_std_1.23/src/crypto/rsa/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/rsa/ya.make rename to contrib/go/_std_1.23/src/crypto/rsa/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1.go b/contrib/go/_std_1.23/src/crypto/sha1/sha1.go similarity index 85% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1.go rename to contrib/go/_std_1.23/src/crypto/sha1/sha1.go index ac10fa15574f..c0742b9d83c5 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1.go +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1.go @@ -11,9 +11,9 @@ package sha1 import ( "crypto" "crypto/internal/boring" - "encoding/binary" "errors" "hash" + "internal/byteorder" ) func init() { @@ -51,14 +51,14 @@ const ( func (d *digest) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize) b = append(b, magic...) - b = binary.BigEndian.AppendUint32(b, d.h[0]) - b = binary.BigEndian.AppendUint32(b, d.h[1]) - b = binary.BigEndian.AppendUint32(b, d.h[2]) - b = binary.BigEndian.AppendUint32(b, d.h[3]) - b = binary.BigEndian.AppendUint32(b, d.h[4]) + b = byteorder.BeAppendUint32(b, d.h[0]) + b = byteorder.BeAppendUint32(b, d.h[1]) + b = byteorder.BeAppendUint32(b, d.h[2]) + b = byteorder.BeAppendUint32(b, d.h[3]) + b = byteorder.BeAppendUint32(b, d.h[4]) b = append(b, d.x[:d.nx]...) b = b[:len(b)+len(d.x)-d.nx] // already zero - b = binary.BigEndian.AppendUint64(b, d.len) + b = byteorder.BeAppendUint64(b, d.len) return b, nil } @@ -82,16 +82,11 @@ func (d *digest) UnmarshalBinary(b []byte) error { } func consumeUint64(b []byte) ([]byte, uint64) { - _ = b[7] - x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 - return b[8:], x + return b[8:], byteorder.BeUint64(b) } func consumeUint32(b []byte) ([]byte, uint32) { - _ = b[3] - x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 - return b[4:], x + return b[4:], byteorder.BeUint32(b) } func (d *digest) Reset() { @@ -167,7 +162,7 @@ func (d *digest) checkSum() [Size]byte { // Length in bits. len <<= 3 padlen := tmp[:t+8] - binary.BigEndian.PutUint64(padlen[t:], len) + byteorder.BePutUint64(padlen[t:], len) d.Write(padlen) if d.nx != 0 { @@ -176,11 +171,11 @@ func (d *digest) checkSum() [Size]byte { var digest [Size]byte - binary.BigEndian.PutUint32(digest[0:], d.h[0]) - binary.BigEndian.PutUint32(digest[4:], d.h[1]) - binary.BigEndian.PutUint32(digest[8:], d.h[2]) - binary.BigEndian.PutUint32(digest[12:], d.h[3]) - binary.BigEndian.PutUint32(digest[16:], d.h[4]) + byteorder.BePutUint32(digest[0:], d.h[0]) + byteorder.BePutUint32(digest[4:], d.h[1]) + byteorder.BePutUint32(digest[8:], d.h[2]) + byteorder.BePutUint32(digest[12:], d.h[3]) + byteorder.BePutUint32(digest[16:], d.h[4]) return digest } diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block.go b/contrib/go/_std_1.23/src/crypto/sha1/sha1block.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block.go rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block.go diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_386.s b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_386.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_386.s rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_386.s index 34d023d424c0..33d3f1e9973f 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_386.s +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_386.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // SHA-1 block routine. See sha1block.go for Go equivalent. diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_amd64.go b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_amd64.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_amd64.go rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_amd64.go index 039813d7dc3f..92fa7a6fbc0d 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_amd64.go +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_amd64.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha1 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_amd64.s b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_amd64.s rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_amd64.s index 9bdf24cf49f2..6508612d8900 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_amd64.s @@ -10,6 +10,7 @@ // Ronen Zohar // Chandramouli Narayanan +//go:build !purego #include "textflag.h" diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm.s b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm.s rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm.s index 2236533ab4d9..209b1d89ae34 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm.s +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm.s @@ -4,6 +4,8 @@ // // ARM version of md5block.go +//go:build !purego + #include "textflag.h" // SHA-1 block routine. See sha1block.go for Go equivalent. diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm64.go b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm64.go similarity index 95% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm64.go rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm64.go index 08d3df0000e6..e6d96a9080a8 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm64.go +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm64.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha1 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm64.s b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm64.s rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm64.s index d56838464ddb..d0ff0986b8b5 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_arm64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" #define HASHUPDATECHOOSE \ diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_decl.go b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_decl.go similarity index 83% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_decl.go rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_decl.go index 8e20401c14c4..3edf5a43606d 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_decl.go +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_decl.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build arm || 386 || s390x +//go:build (arm || 386 || s390x) && !purego package sha1 diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_generic.go b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_generic.go similarity index 78% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_generic.go rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_generic.go index ba35155d0b92..4c6f74d99d8f 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_generic.go +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 && !386 && !arm && !s390x && !arm64 +//go:build (!amd64 && !386 && !arm && !s390x && !arm64) || purego package sha1 diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_s390x.go b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_s390x.go similarity index 91% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_s390x.go rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_s390x.go index 446bf5d36e59..f8b0d8ba3100 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_s390x.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha1 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_s390x.s b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_s390x.s similarity index 96% rename from contrib/go/_std_1.22/src/crypto/sha1/sha1block_s390x.s rename to contrib/go/_std_1.23/src/crypto/sha1/sha1block_s390x.s index 0fb7aef28371..7a2f4e39c401 100644 --- a/contrib/go/_std_1.22/src/crypto/sha1/sha1block_s390x.s +++ b/contrib/go/_std_1.23/src/crypto/sha1/sha1block_s390x.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // func block(dig *digest, p []byte) diff --git a/contrib/go/_std_1.22/src/crypto/sha1/ya.make b/contrib/go/_std_1.23/src/crypto/sha1/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/sha1/ya.make rename to contrib/go/_std_1.23/src/crypto/sha1/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256.go b/contrib/go/_std_1.23/src/crypto/sha256/sha256.go similarity index 81% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256.go rename to contrib/go/_std_1.23/src/crypto/sha256/sha256.go index 0cc7fca0a606..68244fd63b0c 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256.go +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256.go @@ -9,9 +9,9 @@ package sha256 import ( "crypto" "crypto/internal/boring" - "encoding/binary" "errors" "hash" + "internal/byteorder" ) func init() { @@ -70,17 +70,17 @@ func (d *digest) MarshalBinary() ([]byte, error) { } else { b = append(b, magic256...) } - b = binary.BigEndian.AppendUint32(b, d.h[0]) - b = binary.BigEndian.AppendUint32(b, d.h[1]) - b = binary.BigEndian.AppendUint32(b, d.h[2]) - b = binary.BigEndian.AppendUint32(b, d.h[3]) - b = binary.BigEndian.AppendUint32(b, d.h[4]) - b = binary.BigEndian.AppendUint32(b, d.h[5]) - b = binary.BigEndian.AppendUint32(b, d.h[6]) - b = binary.BigEndian.AppendUint32(b, d.h[7]) + b = byteorder.BeAppendUint32(b, d.h[0]) + b = byteorder.BeAppendUint32(b, d.h[1]) + b = byteorder.BeAppendUint32(b, d.h[2]) + b = byteorder.BeAppendUint32(b, d.h[3]) + b = byteorder.BeAppendUint32(b, d.h[4]) + b = byteorder.BeAppendUint32(b, d.h[5]) + b = byteorder.BeAppendUint32(b, d.h[6]) + b = byteorder.BeAppendUint32(b, d.h[7]) b = append(b, d.x[:d.nx]...) b = b[:len(b)+len(d.x)-d.nx] // already zero - b = binary.BigEndian.AppendUint64(b, d.len) + b = byteorder.BeAppendUint64(b, d.len) return b, nil } @@ -107,16 +107,11 @@ func (d *digest) UnmarshalBinary(b []byte) error { } func consumeUint64(b []byte) ([]byte, uint64) { - _ = b[7] - x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 - return b[8:], x + return b[8:], byteorder.BeUint64(b) } func consumeUint32(b []byte) ([]byte, uint32) { - _ = b[3] - x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 - return b[4:], x + return b[4:], byteorder.BeUint32(b) } func (d *digest) Reset() { @@ -226,7 +221,7 @@ func (d *digest) checkSum() [Size]byte { // Length in bits. len <<= 3 padlen := tmp[:t+8] - binary.BigEndian.PutUint64(padlen[t+0:], len) + byteorder.BePutUint64(padlen[t+0:], len) d.Write(padlen) if d.nx != 0 { @@ -235,15 +230,15 @@ func (d *digest) checkSum() [Size]byte { var digest [Size]byte - binary.BigEndian.PutUint32(digest[0:], d.h[0]) - binary.BigEndian.PutUint32(digest[4:], d.h[1]) - binary.BigEndian.PutUint32(digest[8:], d.h[2]) - binary.BigEndian.PutUint32(digest[12:], d.h[3]) - binary.BigEndian.PutUint32(digest[16:], d.h[4]) - binary.BigEndian.PutUint32(digest[20:], d.h[5]) - binary.BigEndian.PutUint32(digest[24:], d.h[6]) + byteorder.BePutUint32(digest[0:], d.h[0]) + byteorder.BePutUint32(digest[4:], d.h[1]) + byteorder.BePutUint32(digest[8:], d.h[2]) + byteorder.BePutUint32(digest[12:], d.h[3]) + byteorder.BePutUint32(digest[16:], d.h[4]) + byteorder.BePutUint32(digest[20:], d.h[5]) + byteorder.BePutUint32(digest[24:], d.h[6]) if !d.is224 { - binary.BigEndian.PutUint32(digest[28:], d.h[7]) + byteorder.BePutUint32(digest[28:], d.h[7]) } return digest diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block.go b/contrib/go/_std_1.23/src/crypto/sha256/sha256block.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block.go rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block.go diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_386.s b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_386.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_386.s rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_386.s index 086a0ab25c88..0e27fa02d7e7 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_386.s +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_386.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + // SHA256 block routine. See sha256block.go for Go equivalent. // // The algorithm is detailed in FIPS 180-4: diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_amd64.go b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_amd64.go similarity index 93% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_amd64.go rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_amd64.go index b5d2c9b574a2..fdd75a3f3e7e 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_amd64.go +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_amd64.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha256 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_amd64.s b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_amd64.s rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_amd64.s index bbde6285d178..2559f659a200 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_amd64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // SHA256 block routine. See sha256block.go for Go equivalent. diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_arm64.go b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_arm64.go similarity index 95% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_arm64.go rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_arm64.go index e5da56636315..434b6f253d41 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_arm64.go +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_arm64.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha256 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_arm64.s b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_arm64.s rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_arm64.s index d5c1eb0b2e15..6757310c34e3 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_arm64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" #define HASHUPDATE \ diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_decl.go b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_decl.go similarity index 77% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_decl.go rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_decl.go index 7d68cd95fe44..85374cbdbb59 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_decl.go +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_decl.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build 386 || amd64 || s390x || ppc64le || ppc64 +//go:build (386 || amd64 || s390x || ppc64le || ppc64) && !purego package sha256 diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_generic.go b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_generic.go similarity index 74% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_generic.go rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_generic.go index fd098bec894b..2964255f99cc 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_generic.go +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 && !386 && !s390x && !ppc64le && !ppc64 && !arm64 +//go:build (!amd64 && !386 && !s390x && !ppc64le && !ppc64 && !arm64) || purego package sha256 diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_ppc64x.s b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_ppc64x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_ppc64x.s rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_ppc64x.s index b229ef619a35..ba8fa623c11f 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_ppc64x.s +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_ppc64x.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build ppc64 || ppc64le +//go:build (ppc64 || ppc64le) && !purego // Based on CRYPTOGAMS code with the following comment: // # ==================================================================== diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_s390x.go b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_s390x.go similarity index 92% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_s390x.go rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_s390x.go index 1a376c5f9353..0a1dc5785d2e 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_s390x.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha256 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_s390x.s b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_s390x.s similarity index 96% rename from contrib/go/_std_1.22/src/crypto/sha256/sha256block_s390x.s rename to contrib/go/_std_1.23/src/crypto/sha256/sha256block_s390x.s index 9c30136b31ef..757d62f5125a 100644 --- a/contrib/go/_std_1.22/src/crypto/sha256/sha256block_s390x.s +++ b/contrib/go/_std_1.23/src/crypto/sha256/sha256block_s390x.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // func block(dig *digest, p []byte) diff --git a/contrib/go/_std_1.22/src/crypto/sha256/ya.make b/contrib/go/_std_1.23/src/crypto/sha256/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/sha256/ya.make rename to contrib/go/_std_1.23/src/crypto/sha256/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512.go b/contrib/go/_std_1.23/src/crypto/sha512/sha512.go similarity index 88% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512.go rename to contrib/go/_std_1.23/src/crypto/sha512/sha512.go index 9ae1b3aae2f0..dde83625f7b8 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512.go +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512.go @@ -13,9 +13,9 @@ package sha512 import ( "crypto" "crypto/internal/boring" - "encoding/binary" "errors" "hash" + "internal/byteorder" ) func init() { @@ -153,17 +153,17 @@ func (d *digest) MarshalBinary() ([]byte, error) { default: return nil, errors.New("crypto/sha512: invalid hash function") } - b = binary.BigEndian.AppendUint64(b, d.h[0]) - b = binary.BigEndian.AppendUint64(b, d.h[1]) - b = binary.BigEndian.AppendUint64(b, d.h[2]) - b = binary.BigEndian.AppendUint64(b, d.h[3]) - b = binary.BigEndian.AppendUint64(b, d.h[4]) - b = binary.BigEndian.AppendUint64(b, d.h[5]) - b = binary.BigEndian.AppendUint64(b, d.h[6]) - b = binary.BigEndian.AppendUint64(b, d.h[7]) + b = byteorder.BeAppendUint64(b, d.h[0]) + b = byteorder.BeAppendUint64(b, d.h[1]) + b = byteorder.BeAppendUint64(b, d.h[2]) + b = byteorder.BeAppendUint64(b, d.h[3]) + b = byteorder.BeAppendUint64(b, d.h[4]) + b = byteorder.BeAppendUint64(b, d.h[5]) + b = byteorder.BeAppendUint64(b, d.h[6]) + b = byteorder.BeAppendUint64(b, d.h[7]) b = append(b, d.x[:d.nx]...) b = b[:len(b)+len(d.x)-d.nx] // already zero - b = binary.BigEndian.AppendUint64(b, d.len) + b = byteorder.BeAppendUint64(b, d.len) return b, nil } @@ -198,10 +198,7 @@ func (d *digest) UnmarshalBinary(b []byte) error { } func consumeUint64(b []byte) ([]byte, uint64) { - _ = b[7] - x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 - return b[8:], x + return b[8:], byteorder.BeUint64(b) } // New returns a new hash.Hash computing the SHA-512 checksum. @@ -316,8 +313,8 @@ func (d *digest) checkSum() [Size]byte { padlen := tmp[:t+16] // Upper 64 bits are always zero, because len variable has type uint64, // and tmp is already zeroed at that index, so we can skip updating it. - // binary.BigEndian.PutUint64(padlen[t+0:], 0) - binary.BigEndian.PutUint64(padlen[t+8:], len) + // byteorder.BePutUint64(padlen[t+0:], 0) + byteorder.BePutUint64(padlen[t+8:], len) d.Write(padlen) if d.nx != 0 { @@ -325,15 +322,15 @@ func (d *digest) checkSum() [Size]byte { } var digest [Size]byte - binary.BigEndian.PutUint64(digest[0:], d.h[0]) - binary.BigEndian.PutUint64(digest[8:], d.h[1]) - binary.BigEndian.PutUint64(digest[16:], d.h[2]) - binary.BigEndian.PutUint64(digest[24:], d.h[3]) - binary.BigEndian.PutUint64(digest[32:], d.h[4]) - binary.BigEndian.PutUint64(digest[40:], d.h[5]) + byteorder.BePutUint64(digest[0:], d.h[0]) + byteorder.BePutUint64(digest[8:], d.h[1]) + byteorder.BePutUint64(digest[16:], d.h[2]) + byteorder.BePutUint64(digest[24:], d.h[3]) + byteorder.BePutUint64(digest[32:], d.h[4]) + byteorder.BePutUint64(digest[40:], d.h[5]) if d.function != crypto.SHA384 { - binary.BigEndian.PutUint64(digest[48:], d.h[6]) - binary.BigEndian.PutUint64(digest[56:], d.h[7]) + byteorder.BePutUint64(digest[48:], d.h[6]) + byteorder.BePutUint64(digest[56:], d.h[7]) } return digest diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block.go b/contrib/go/_std_1.23/src/crypto/sha512/sha512block.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block.go rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block.go diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_amd64.go b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_amd64.go similarity index 96% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_amd64.go rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_amd64.go index 8da3e1473f6c..fd1baecb32d8 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_amd64.go +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_amd64.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build amd64 +//go:build !purego package sha512 diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_amd64.s b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_amd64.s rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_amd64.s index 0fa0df2f60e8..bd4e3e6669f8 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_amd64.s +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_amd64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // SHA512 block routine. See sha512block.go for Go equivalent. diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_arm64.go b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_arm64.go similarity index 94% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_arm64.go rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_arm64.go index 243eb5c1d63b..4e2793100a31 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_arm64.go +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_arm64.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha512 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_arm64.s b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_arm64.s rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_arm64.s index dfc35d69c388..25f3dbfe43d5 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_arm64.s +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_arm64.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + // Based on the Linux Kernel with the following comment: // Algorithm based on https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fb87127bcefc17efab757606e1b1e333fd614dd0 // Originally written by Ard Biesheuvel diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_decl.go b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_decl.go similarity index 78% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_decl.go rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_decl.go index 4ad4418bc071..324659e62ca2 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_decl.go +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_decl.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build s390x || ppc64le || ppc64 +//go:build (ppc64le || ppc64 || riscv64 || s390x) && !purego package sha512 diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_generic.go b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_generic.go similarity index 73% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_generic.go rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_generic.go index 02ecc2c794b2..9177722be12b 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_generic.go +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !amd64 && !arm64 && !s390x && !ppc64le && !ppc64 +//go:build (!amd64 && !arm64 && !ppc64 && !ppc64le && !riscv64 && !s390x) || purego package sha512 diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_ppc64x.s b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_ppc64x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_ppc64x.s rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_ppc64x.s index 90dbf0f02b64..87aab80903c9 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_ppc64x.s +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_ppc64x.s @@ -10,7 +10,7 @@ // # details see http://www.openssl.org/~appro/cryptogams/. // # ==================================================================== -//go:build ppc64 || ppc64le +//go:build (ppc64 || ppc64le) && !purego #include "textflag.h" diff --git a/contrib/go/_std_1.23/src/crypto/sha512/sha512block_riscv64.s b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_riscv64.s new file mode 100644 index 000000000000..7dcb0f80d0ab --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_riscv64.s @@ -0,0 +1,288 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !purego + +#include "textflag.h" + +// SHA512 block routine. See sha512block.go for Go equivalent. +// +// The algorithm is detailed in FIPS 180-4: +// +// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf +// +// Wt = Mt; for 0 <= t <= 15 +// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79 +// +// a = H0 +// b = H1 +// c = H2 +// d = H3 +// e = H4 +// f = H5 +// g = H6 +// h = H7 +// +// for t = 0 to 79 { +// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt +// T2 = BIGSIGMA0(a) + Maj(a,b,c) +// h = g +// g = f +// f = e +// e = d + T1 +// d = c +// c = b +// b = a +// a = T1 + T2 +// } +// +// H0 = a + H0 +// H1 = b + H1 +// H2 = c + H2 +// H3 = d + H3 +// H4 = e + H4 +// H5 = f + H5 +// H6 = g + H6 +// H7 = h + H7 + +// Wt = Mt; for 0 <= t <= 15 +#define MSGSCHEDULE0(index) \ + MOVBU ((index*8)+0)(X29), X5; \ + MOVBU ((index*8)+1)(X29), X6; \ + MOVBU ((index*8)+2)(X29), X7; \ + MOVBU ((index*8)+3)(X29), X8; \ + SLL $56, X5; \ + SLL $48, X6; \ + OR X5, X6, X5; \ + SLL $40, X7; \ + OR X5, X7, X5; \ + SLL $32, X8; \ + OR X5, X8, X5; \ + MOVBU ((index*8)+4)(X29), X9; \ + MOVBU ((index*8)+5)(X29), X6; \ + MOVBU ((index*8)+6)(X29), X7; \ + MOVBU ((index*8)+7)(X29), X8; \ + SLL $24, X9; \ + OR X5, X9, X5; \ + SLL $16, X6; \ + OR X5, X6, X5; \ + SLL $8, X7; \ + OR X5, X7, X5; \ + OR X5, X8, X5; \ + MOV X5, (index*8)(X19) + +// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79 +// SIGMA0(x) = ROTR(1,x) XOR ROTR(8,x) XOR SHR(7,x) +// SIGMA1(x) = ROTR(19,x) XOR ROTR(61,x) XOR SHR(6,x) +#define MSGSCHEDULE1(index) \ + MOV (((index-2)&0xf)*8)(X19), X5; \ + MOV (((index-15)&0xf)*8)(X19), X6; \ + MOV (((index-7)&0xf)*8)(X19), X9; \ + MOV (((index-16)&0xf)*8)(X19), X21; \ + ROR $19, X5, X7; \ + ROR $61, X5, X8; \ + SRL $6, X5; \ + XOR X7, X5; \ + XOR X8, X5; \ + ADD X9, X5; \ + ROR $1, X6, X7; \ + ROR $8, X6, X8; \ + SRL $7, X6; \ + XOR X7, X6; \ + XOR X8, X6; \ + ADD X6, X5; \ + ADD X21, X5; \ + MOV X5, ((index&0xf)*8)(X19) + +// Calculate T1 in X5. +// h is also used as an accumulator. Wt is passed in X5. +// T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt +// BIGSIGMA1(x) = ROTR(14,x) XOR ROTR(18,x) XOR ROTR(41,x) +// Ch(x, y, z) = (x AND y) XOR (NOT x AND z) +#define SHA512T1(index, e, f, g, h) \ + MOV (index*8)(X18), X8; \ + ADD X5, h; \ + ROR $14, e, X6; \ + ADD X8, h; \ + ROR $18, e, X7; \ + XOR X7, X6; \ + ROR $41, e, X8; \ + XOR X8, X6; \ + ADD X6, h; \ + AND e, f, X5; \ + NOT e, X7; \ + AND g, X7; \ + XOR X7, X5; \ + ADD h, X5 + +// Calculate T2 in X6. +// T2 = BIGSIGMA0(a) + Maj(a, b, c) +// BIGSIGMA0(x) = ROTR(28,x) XOR ROTR(34,x) XOR ROTR(39,x) +// Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z) +#define SHA512T2(a, b, c) \ + ROR $28, a, X6; \ + ROR $34, a, X7; \ + XOR X7, X6; \ + ROR $39, a, X8; \ + XOR X8, X6; \ + AND a, b, X7; \ + AND a, c, X8; \ + XOR X8, X7; \ + AND b, c, X9; \ + XOR X9, X7; \ + ADD X7, X6 + +// Calculate T1 and T2, then e = d + T1 and a = T1 + T2. +// The values for e and a are stored in d and h, ready for rotation. +#define SHA512ROUND(index, a, b, c, d, e, f, g, h) \ + SHA512T1(index, e, f, g, h); \ + SHA512T2(a, b, c); \ + MOV X6, h; \ + ADD X5, d; \ + ADD X5, h + +#define SHA512ROUND0(index, a, b, c, d, e, f, g, h) \ + MSGSCHEDULE0(index); \ + SHA512ROUND(index, a, b, c, d, e, f, g, h) + +#define SHA512ROUND1(index, a, b, c, d, e, f, g, h) \ + MSGSCHEDULE1(index); \ + SHA512ROUND(index, a, b, c, d, e, f, g, h) + +// func block(dig *digest, p []byte) +TEXT ·block(SB),0,$128-32 + MOV p_base+8(FP), X29 + MOV p_len+16(FP), X30 + SRL $7, X30 + SLL $7, X30 + + ADD X29, X30, X28 + BEQ X28, X29, end + + MOV ·_K(SB), X18 // const table + ADD $8, X2, X19 // message schedule + + MOV dig+0(FP), X20 + MOV (0*8)(X20), X10 // a = H0 + MOV (1*8)(X20), X11 // b = H1 + MOV (2*8)(X20), X12 // c = H2 + MOV (3*8)(X20), X13 // d = H3 + MOV (4*8)(X20), X14 // e = H4 + MOV (5*8)(X20), X15 // f = H5 + MOV (6*8)(X20), X16 // g = H6 + MOV (7*8)(X20), X17 // h = H7 + +loop: + SHA512ROUND0(0, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND0(1, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND0(2, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND0(3, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND0(4, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND0(5, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND0(6, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND0(7, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND0(8, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND0(9, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND0(10, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND0(11, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND0(12, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND0(13, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND0(14, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND0(15, X11, X12, X13, X14, X15, X16, X17, X10) + + SHA512ROUND1(16, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(17, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(18, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(19, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(20, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(21, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(22, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(23, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND1(24, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(25, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(26, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(27, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(28, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(29, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(30, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(31, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND1(32, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(33, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(34, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(35, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(36, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(37, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(38, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(39, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND1(40, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(41, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(42, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(43, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(44, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(45, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(46, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(47, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND1(48, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(49, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(50, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(51, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(52, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(53, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(54, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(55, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND1(56, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(57, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(58, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(59, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(60, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(61, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(62, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(63, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND1(64, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(65, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(66, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(67, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(68, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(69, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(70, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(71, X11, X12, X13, X14, X15, X16, X17, X10) + SHA512ROUND1(72, X10, X11, X12, X13, X14, X15, X16, X17) + SHA512ROUND1(73, X17, X10, X11, X12, X13, X14, X15, X16) + SHA512ROUND1(74, X16, X17, X10, X11, X12, X13, X14, X15) + SHA512ROUND1(75, X15, X16, X17, X10, X11, X12, X13, X14) + SHA512ROUND1(76, X14, X15, X16, X17, X10, X11, X12, X13) + SHA512ROUND1(77, X13, X14, X15, X16, X17, X10, X11, X12) + SHA512ROUND1(78, X12, X13, X14, X15, X16, X17, X10, X11) + SHA512ROUND1(79, X11, X12, X13, X14, X15, X16, X17, X10) + + MOV (0*8)(X20), X5 + MOV (1*8)(X20), X6 + MOV (2*8)(X20), X7 + MOV (3*8)(X20), X8 + ADD X5, X10 // H0 = a + H0 + ADD X6, X11 // H1 = b + H1 + ADD X7, X12 // H2 = c + H2 + ADD X8, X13 // H3 = d + H3 + MOV X10, (0*8)(X20) + MOV X11, (1*8)(X20) + MOV X12, (2*8)(X20) + MOV X13, (3*8)(X20) + MOV (4*8)(X20), X5 + MOV (5*8)(X20), X6 + MOV (6*8)(X20), X7 + MOV (7*8)(X20), X8 + ADD X5, X14 // H4 = e + H4 + ADD X6, X15 // H5 = f + H5 + ADD X7, X16 // H6 = g + H6 + ADD X8, X17 // H7 = h + H7 + MOV X14, (4*8)(X20) + MOV X15, (5*8)(X20) + MOV X16, (6*8)(X20) + MOV X17, (7*8)(X20) + + ADD $128, X29 + BNE X28, X29, loop + +end: + RET diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_s390x.go b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_s390x.go similarity index 92% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_s390x.go rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_s390x.go index 7df29fd29828..d0f09ea9edb0 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_s390x.go +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_s390x.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + package sha512 import "internal/cpu" diff --git a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_s390x.s b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_s390x.s similarity index 96% rename from contrib/go/_std_1.22/src/crypto/sha512/sha512block_s390x.s rename to contrib/go/_std_1.23/src/crypto/sha512/sha512block_s390x.s index 9fdf3439007a..230bd414d38b 100644 --- a/contrib/go/_std_1.22/src/crypto/sha512/sha512block_s390x.s +++ b/contrib/go/_std_1.23/src/crypto/sha512/sha512block_s390x.s @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:build !purego + #include "textflag.h" // func block(dig *digest, p []byte) diff --git a/contrib/go/_std_1.22/src/crypto/sha512/ya.make b/contrib/go/_std_1.23/src/crypto/sha512/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/sha512/ya.make rename to contrib/go/_std_1.23/src/crypto/sha512/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/subtle/constant_time.go b/contrib/go/_std_1.23/src/crypto/subtle/constant_time.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/constant_time.go rename to contrib/go/_std_1.23/src/crypto/subtle/constant_time.go diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor.go b/contrib/go/_std_1.23/src/crypto/subtle/xor.go similarity index 92% rename from contrib/go/_std_1.22/src/crypto/subtle/xor.go rename to contrib/go/_std_1.23/src/crypto/subtle/xor.go index a8805ac61dcc..158dbcede904 100644 --- a/contrib/go/_std_1.22/src/crypto/subtle/xor.go +++ b/contrib/go/_std_1.23/src/crypto/subtle/xor.go @@ -9,10 +9,7 @@ package subtle // If dst does not have length at least n, // XORBytes panics without writing anything to dst. func XORBytes(dst, x, y []byte) int { - n := len(x) - if len(y) < n { - n = len(y) - } + n := min(len(x), len(y)) if n == 0 { return 0 } diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor_amd64.go b/contrib/go/_std_1.23/src/crypto/subtle/xor_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/xor_amd64.go rename to contrib/go/_std_1.23/src/crypto/subtle/xor_amd64.go diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor_amd64.s b/contrib/go/_std_1.23/src/crypto/subtle/xor_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/xor_amd64.s rename to contrib/go/_std_1.23/src/crypto/subtle/xor_amd64.s diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor_arm64.go b/contrib/go/_std_1.23/src/crypto/subtle/xor_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/xor_arm64.go rename to contrib/go/_std_1.23/src/crypto/subtle/xor_arm64.go diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor_arm64.s b/contrib/go/_std_1.23/src/crypto/subtle/xor_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/xor_arm64.s rename to contrib/go/_std_1.23/src/crypto/subtle/xor_arm64.s diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor_generic.go b/contrib/go/_std_1.23/src/crypto/subtle/xor_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/xor_generic.go rename to contrib/go/_std_1.23/src/crypto/subtle/xor_generic.go diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor_ppc64x.go b/contrib/go/_std_1.23/src/crypto/subtle/xor_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/xor_ppc64x.go rename to contrib/go/_std_1.23/src/crypto/subtle/xor_ppc64x.go diff --git a/contrib/go/_std_1.22/src/crypto/subtle/xor_ppc64x.s b/contrib/go/_std_1.23/src/crypto/subtle/xor_ppc64x.s similarity index 99% rename from contrib/go/_std_1.22/src/crypto/subtle/xor_ppc64x.s rename to contrib/go/_std_1.23/src/crypto/subtle/xor_ppc64x.s index 0de4350cb237..c1f72c5ced78 100644 --- a/contrib/go/_std_1.22/src/crypto/subtle/xor_ppc64x.s +++ b/contrib/go/_std_1.23/src/crypto/subtle/xor_ppc64x.s @@ -89,7 +89,7 @@ xor16: ADD $16, R8 ADD $-16, R6 small: - CMP R6, R0 + CMP R6, $0 BC 12,2,LR // BEQLR xor8: #ifdef GOPPC64_power10 @@ -131,7 +131,7 @@ xor2: ADD $2,R8 ADD $-2,R6 xor1: - CMP R6, R0 + CMP R6, $0 BC 12,2,LR // BEQLR MOVBZ (R4)(R8), R14 // R14 = a[i] MOVBZ (R5)(R8), R15 // R15 = b[i] diff --git a/contrib/go/_std_1.22/src/crypto/subtle/ya.make b/contrib/go/_std_1.23/src/crypto/subtle/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/subtle/ya.make rename to contrib/go/_std_1.23/src/crypto/subtle/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/tls/alert.go b/contrib/go/_std_1.23/src/crypto/tls/alert.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/tls/alert.go rename to contrib/go/_std_1.23/src/crypto/tls/alert.go index 33022cd2b4bf..2301c0673d83 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/alert.go +++ b/contrib/go/_std_1.23/src/crypto/tls/alert.go @@ -58,6 +58,7 @@ const ( alertUnknownPSKIdentity alert = 115 alertCertificateRequired alert = 116 alertNoApplicationProtocol alert = 120 + alertECHRequired alert = 121 ) var alertText = map[alert]string{ @@ -94,6 +95,7 @@ var alertText = map[alert]string{ alertUnknownPSKIdentity: "unknown PSK identity", alertCertificateRequired: "certificate required", alertNoApplicationProtocol: "no application protocol", + alertECHRequired: "encrypted client hello required", } func (e alert) String() string { diff --git a/contrib/go/_std_1.22/src/crypto/tls/auth.go b/contrib/go/_std_1.23/src/crypto/tls/auth.go similarity index 99% rename from contrib/go/_std_1.22/src/crypto/tls/auth.go rename to contrib/go/_std_1.23/src/crypto/tls/auth.go index 7c5675c6d933..5bb202cd6aa9 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/auth.go +++ b/contrib/go/_std_1.23/src/crypto/tls/auth.go @@ -242,7 +242,7 @@ func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureSche // Pick signature scheme in the peer's preference order, as our // preference order is not configurable. for _, preferredAlg := range peerAlgs { - if needFIPS() && !isSupportedSignatureAlgorithm(preferredAlg, fipsSupportedSignatureAlgorithms) { + if needFIPS() && !isSupportedSignatureAlgorithm(preferredAlg, defaultSupportedSignatureAlgorithmsFIPS) { continue } if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) { diff --git a/contrib/go/_std_1.23/src/crypto/tls/bogo_config.json b/contrib/go/_std_1.23/src/crypto/tls/bogo_config.json new file mode 100644 index 000000000000..2363dd5d659a --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/tls/bogo_config.json @@ -0,0 +1,233 @@ +{ + "DisabledTests": { + "*-Async": "We don't support boringssl concept of async", + + "TLS-ECH-Client-Reject-NoClientCertificate-TLS12": "We won't attempt to negotiate 1.2 if ECH is enabled", + "TLS-ECH-Client-Reject-TLS12": "We won't attempt to negotiate 1.2 if ECH is enabled", + "TLS-ECH-Client-TLS12-RejectRetryConfigs": "We won't attempt to negotiate 1.2 if ECH is enabled", + "TLS-ECH-Client-Rejected-OverrideName-TLS12": "We won't attempt to negotiate 1.2 if ECH is enabled", + "TLS-ECH-Client-Reject-TLS12-NoFalseStart": "We won't attempt to negotiate 1.2 if ECH is enabled", + "TLS-ECH-Client-TLS12SessionTicket": "We won't attempt to negotiate 1.2 if ECH is enabled", + "TLS-ECH-Client-TLS12SessionID": "We won't attempt to negotiate 1.2 if ECH is enabled", + + "TLS-ECH-Client-Reject-ResumeInnerSession-TLS12": "We won't attempt to negotiate 1.2 if ECH is enabled (we could possibly test this if we had the ability to indicate not to send ECH on resumption?)", + + "TLS-ECH-Client-Reject-EarlyDataRejected": "We don't support switiching out ECH configs with this level of granularity", + + "TLS-ECH-Client-NoNPN": "We don't support NPN", + + "TLS-ECH-Client-ChannelID": "We don't support sending channel ID", + "TLS-ECH-Client-Reject-NoChannelID-TLS13": "We don't support sending channel ID", + "TLS-ECH-Client-Reject-NoChannelID-TLS12": "We don't support sending channel ID", + + "TLS-ECH-Client-GREASE-IgnoreHRRExtension": "We don't support ECH GREASE because we don't fallback to plaintext", + "TLS-ECH-Client-NoSupportedConfigs-GREASE": "We don't support ECH GREASE because we don't fallback to plaintext", + "TLS-ECH-Client-GREASEExtensions": "We don't support ECH GREASE because we don't fallback to plaintext", + "TLS-ECH-Client-GREASE-NoOverrideName": "We don't support ECH GREASE because we don't fallback to plaintext", + + "TLS-ECH-Client-UnsolicitedInnerServerNameAck": "We don't allow sending empty SNI without skipping certificate verification, TODO: could add special flag to bogo to indicate 'empty sni'", + + "TLS-ECH-Client-NoSupportedConfigs": "We don't support fallback to cleartext when there are no valid ECH configs", + "TLS-ECH-Client-SkipInvalidPublicName": "We don't support fallback to cleartext when there are no valid ECH configs", + + + "*ECH-Server*": "no ECH server support", + "SendV2ClientHello*": "We don't support SSLv2", + "*QUIC*": "No QUIC support", + "Compliance-fips*": "No FIPS", + "*DTLS*": "No DTLS", + "SendEmptyRecords*": "crypto/tls doesn't implement spam protections", + "SendWarningAlerts*": "crypto/tls doesn't implement spam protections", + "TooManyKeyUpdates": "crypto/tls doesn't implement spam protections (TODO: I think?)", + "KyberNotEnabledByDefaultInClients": "crypto/tls intentionally enables it", + "JustConfiguringKyberWorks": "we always send a X25519 key share with Kyber", + "KyberKeyShareIncludedSecond": "we always send the Kyber key share first", + "KyberKeyShareIncludedThird": "we always send the Kyber key share first", + "SkipNewSessionTicket": "TODO confusing? maybe bug", + "SendUserCanceledAlerts*": "TODO may be a real bug?", + "GREASE-Server-TLS13": "TODO ???", + "GarbageCertificate*": "TODO ask davidben, alertDecode vs alertBadCertificate", + "SendBogusAlertType": "sending wrong alert type", + "EchoTLS13CompatibilitySessionID": "TODO reject compat session ID", + "*Client-P-224*": "no P-224 support", + "*Server-P-224*": "no P-224 support", + "CurveID-Resume*": "unexposed curveID is not stored in the ticket yet", + "CheckLeafCurve": "TODO: first pass, this should be fixed", + "DisabledCurve-HelloRetryRequest-TLS13": "TODO: first pass, this should be fixed", + "UnsupportedCurve": "TODO: first pass, this should be fixed", + "SupportTicketsWithSessionID": "TODO: first pass, this should be fixed", + "NoNullCompression-TLS12": "TODO: first pass, this should be fixed", + "KeyUpdate-RequestACK": "TODO: first pass, this should be fixed", + "TLS13-HRR-InvalidCompressionMethod": "TODO: first pass, this should be fixed", + "InvalidCompressionMethod": "TODO: first pass, this should be fixed", + "TLS-TLS12-RSA_WITH_AES_128_GCM_SHA256-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS1-RSA_WITH_AES_128_CBC_SHA-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS11-RSA_WITH_AES_128_CBC_SHA-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS12-RSA_WITH_AES_128_CBC_SHA-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS12-RSA_WITH_AES_256_GCM_SHA384-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS1-RSA_WITH_AES_256_CBC_SHA-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS11-RSA_WITH_AES_256_CBC_SHA-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS12-RSA_WITH_AES_256_CBC_SHA-LargeRecord": "TODO: first pass, this should be fixed", + "TLS-TLS12-ECDHE_RSA_WITH_AES_128_CBC_SHA256-LargeRecord": "TODO: first pass, this should be fixed", + "RequireAnyClientCertificate-TLS1": "TODO: first pass, this should be fixed", + "RequireAnyClientCertificate-TLS11": "TODO: first pass, this should be fixed", + "RequireAnyClientCertificate-TLS12": "TODO: first pass, this should be fixed", + "ClientHelloVersionTooHigh": "TODO: first pass, this should be fixed", + "MinorVersionTolerance": "TODO: first pass, this should be fixed", + "IgnoreClientVersionOrder": "TODO: first pass, this should be fixed", + "SupportedVersionSelection-TLS12": "TODO: first pass, this should be fixed", + "MajorVersionTolerance": "TODO: first pass, this should be fixed", + "DuplicateExtensionServer-TLS-TLS1": "TODO: first pass, this should be fixed", + "DuplicateExtensionClient-TLS-TLS1": "TODO: first pass, this should be fixed", + "UnsolicitedServerNameAck-TLS-TLS1": "TODO: first pass, this should be fixed", + "TicketSessionIDLength-33-TLS-TLS1": "TODO: first pass, this should be fixed", + "DuplicateExtensionServer-TLS-TLS11": "TODO: first pass, this should be fixed", + "DuplicateExtensionClient-TLS-TLS11": "TODO: first pass, this should be fixed", + "UnsolicitedServerNameAck-TLS-TLS11": "TODO: first pass, this should be fixed", + "TicketSessionIDLength-33-TLS-TLS11": "TODO: first pass, this should be fixed", + "DuplicateExtensionServer-TLS-TLS12": "TODO: first pass, this should be fixed", + "DuplicateExtensionClient-TLS-TLS12": "TODO: first pass, this should be fixed", + "UnsolicitedServerNameAck-TLS-TLS12": "TODO: first pass, this should be fixed", + "TicketSessionIDLength-33-TLS-TLS12": "TODO: first pass, this should be fixed", + "DuplicateExtensionClient-TLS-TLS13": "TODO: first pass, this should be fixed", + "DuplicateExtensionServer-TLS-TLS13": "TODO: first pass, this should be fixed", + "UnsolicitedServerNameAck-TLS-TLS13": "TODO: first pass, this should be fixed", + "RenegotiationInfo-Forbidden-TLS13": "TODO: first pass, this should be fixed", + "EMS-Forbidden-TLS13": "TODO: first pass, this should be fixed", + "SendUnsolicitedOCSPOnCertificate-TLS13": "TODO: first pass, this should be fixed", + "SendUnsolicitedSCTOnCertificate-TLS13": "TODO: first pass, this should be fixed", + "SendUnknownExtensionOnCertificate-TLS13": "TODO: first pass, this should be fixed", + "Resume-Server-NoTickets-TLS1-TLS1-TLS": "TODO: first pass, this should be fixed", + "Resume-Server-NoTickets-TLS11-TLS11-TLS": "TODO: first pass, this should be fixed", + "Resume-Server-NoTickets-TLS12-TLS12-TLS": "TODO: first pass, this should be fixed", + "Resume-Server-NoPSKBinder": "TODO: first pass, this should be fixed", + "Resume-Server-PSKBinderFirstExtension": "TODO: first pass, this should be fixed", + "Resume-Server-PSKBinderFirstExtension-SecondBinder": "TODO: first pass, this should be fixed", + "Resume-Server-NoPSKBinder-SecondBinder": "TODO: first pass, this should be fixed", + "Resume-Server-OmitPSKsOnSecondClientHello": "TODO: first pass, this should be fixed", + "Renegotiate-Server-Forbidden": "TODO: first pass, this should be fixed", + "Renegotiate-Client-Forbidden-1": "TODO: first pass, this should be fixed", + "Client-Sign-RSA_PKCS1_SHA1-TLS13": "TODO: first pass, this should be fixed", + "Client-Sign-RSA_PKCS1_SHA256-TLS13": "TODO: first pass, this should be fixed", + "Client-Sign-RSA_PKCS1_SHA384-TLS13": "TODO: first pass, this should be fixed", + "Client-Sign-RSA_PKCS1_SHA512-TLS13": "TODO: first pass, this should be fixed", + "Client-Sign-ECDSA_SHA1-TLS13": "TODO: first pass, this should be fixed", + "Client-Sign-ECDSA_P224_SHA256-TLS13": "TODO: first pass, this should be fixed", + "ClientAuth-NoFallback-TLS13": "TODO: first pass, this should be fixed", + "ClientAuth-NoFallback-ECDSA": "TODO: first pass, this should be fixed", + "ClientAuth-NoFallback-RSA": "TODO: first pass, this should be fixed", + "ECDSACurveMismatch-Verify-TLS13": "TODO: first pass, this should be fixed", + "Ed25519DefaultDisable-NoAdvertise": "TODO: first pass, this should be fixed", + "Ed25519DefaultDisable-NoAccept": "TODO: first pass, this should be fixed", + "NoCommonSignatureAlgorithms-TLS12-Fallback": "TODO: first pass, this should be fixed", + "UnknownExtension-Client": "TODO: first pass, this should be fixed", + "UnknownUnencryptedExtension-Client-TLS13": "TODO: first pass, this should be fixed", + "UnofferedExtension-Client-TLS13": "TODO: first pass, this should be fixed", + "UnknownExtension-Client-TLS13": "TODO: first pass, this should be fixed", + "SendClientVersion-RSA": "TODO: first pass, this should be fixed", + "NoCommonCurves": "TODO: first pass, this should be fixed", + "PointFormat-EncryptedExtensions-TLS13": "TODO: first pass, this should be fixed", + "PointFormat-Client-MissingUncompressed": "TODO: first pass, this should be fixed", + "TLS13-SendNoKEMModesWithPSK-Server": "TODO: first pass, this should be fixed", + "TLS13-DuplicateTicketEarlyDataSupport": "TODO: first pass, this should be fixed", + "Basic-Client-NoTicket-TLS-Sync": "TODO: first pass, this should be fixed", + "Basic-Server-RSA-TLS-Sync": "TODO: first pass, this should be fixed", + "Basic-Client-NoTicket-TLS-Sync-SplitHandshakeRecords": "TODO: first pass, this should be fixed", + "Basic-Server-RSA-TLS-Sync-SplitHandshakeRecords": "TODO: first pass, this should be fixed", + "Basic-Client-NoTicket-TLS-Sync-PackHandshake": "TODO: first pass, this should be fixed", + "Basic-Server-RSA-TLS-Sync-PackHandshake": "TODO: first pass, this should be fixed", + "PartialSecondClientHelloAfterFirst": "TODO: first pass, this should be fixed", + "PartialServerHelloWithHelloRetryRequest": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Server-TLS1": "TODO: first pass, this should be fixed", + "PartialClientKeyExchangeWithClientHello": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Resume-Server-TLS1": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Resume-Client-TLS11": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Client-TLS1": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Client-TLS11": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Client-TLS12": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Client-TLS13": "TODO: first pass, this should be fixed", + "PartialNewSessionTicketWithServerHelloDone": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Server-TLS11": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Server-TLS12": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Resume-Server-TLS11": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Resume-Client-TLS12": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Resume-Server-TLS12": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Resume-Client-TLS13": "TODO: first pass, this should be fixed", + "TrailingDataWithFinished-Resume-Client-TLS1": "TODO: first pass, this should be fixed", + "TrailingMessageData-ClientHello-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ServerHello-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ServerCertificate-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ServerHelloDone-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ServerKeyExchange-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-CertificateRequest-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-CertificateVerify-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ServerFinished-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ClientKeyExchange-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-ClientHello-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ClientFinished-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-NewSessionTicket-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-ClientCertificate-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-CertificateRequest-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-ServerCertificateVerify-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-EncryptedExtensions-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-ClientCertificate-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-ClientCertificateVerify-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-ServerCertificate-TLS": "TODO: first pass, this should be fixed", + "ResumeTLS12SessionID-TLS13": "TODO: first pass, this should be fixed", + "SkipEarlyData-TLS13": "TODO: first pass, this should be fixed", + "DuplicateKeyShares-TLS13": "TODO: first pass, this should be fixed", + "Server-TooLongSessionID-TLS13": "TODO: first pass, this should be fixed", + "Client-TooLongSessionID": "TODO: first pass, this should be fixed", + "Client-ShortSessionID": "TODO: first pass, this should be fixed", + "TLS12NoSessionID-TLS13": "TODO: first pass, this should be fixed", + "Server-TooLongSessionID-TLS12": "TODO: first pass, this should be fixed", + "EmptyEncryptedExtensions-TLS13": "TODO: first pass, this should be fixed", + "SkipEarlyData-SecondClientHelloEarlyData-TLS13": "TODO: first pass, this should be fixed", + "EncryptedExtensionsWithKeyShare-TLS13": "TODO: first pass, this should be fixed", + "HelloRetryRequest-DuplicateCurve-TLS13": "TODO: first pass, this should be fixed", + "HelloRetryRequest-DuplicateCookie-TLS13": "TODO: first pass, this should be fixed", + "HelloRetryRequest-Unknown-TLS13": "TODO: first pass, this should be fixed", + "SendPostHandshakeChangeCipherSpec-TLS13": "TODO: first pass, this should be fixed", + "ECDSAKeyUsage-Server-TLS12": "TODO: first pass, this should be fixed", + "ECDSAKeyUsage-Server-TLS13": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Client-WantEncipherment-GotEnciphermentTLS1": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Server-WantSignature-GotEncipherment-TLS1": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Client-WantSignature-GotSignature-TLS1": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Client-WantEncipherment-GotEnciphermentTLS11": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Client-WantSignature-GotSignature-TLS11": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Client-WantEncipherment-GotEnciphermentTLS12": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Server-WantSignature-GotEncipherment-TLS12": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Server-WantSignature-GotEncipherment-TLS11": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Client-WantSignature-GotSignature-TLS12": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Client-WantSignature-GotSignature-TLS13": "TODO: first pass, this should be fixed", + "RSAKeyUsage-Server-WantSignature-GotEncipherment-TLS13": "TODO: first pass, this should be fixed", + "EmptyExtensions-ClientHello-TLS1": "TODO: first pass, this should be fixed", + "OmitExtensions-ClientHello-TLS1": "TODO: first pass, this should be fixed", + "EmptyExtensions-ClientHello-TLS12": "TODO: first pass, this should be fixed", + "OmitExtensions-ClientHello-TLS12": "TODO: first pass, this should be fixed", + "EmptyExtensions-ClientHello-TLS11": "TODO: first pass, this should be fixed", + "OmitExtensions-ClientHello-TLS11": "TODO: first pass, this should be fixed", + "DuplicateCertCompressionExt-TLS12": "TODO: first pass, this should be fixed", + "DuplicateCertCompressionExt-TLS13": "TODO: first pass, this should be fixed", + "Client-RejectJDK11DowngradeRandom": "TODO: first pass, this should be fixed", + "CheckClientCertificateTypes": "TODO: first pass, this should be fixed", + "CheckECDSACurve-TLS12": "TODO: first pass, this should be fixed", + "ALPNClient-RejectUnknown-TLS-TLS1": "TODO: first pass, this should be fixed", + "ALPNClient-RejectUnknown-TLS-TLS11": "TODO: first pass, this should be fixed", + "ALPNClient-RejectUnknown-TLS-TLS12": "TODO: first pass, this should be fixed", + "ALPNClient-RejectUnknown-TLS-TLS13": "TODO: first pass, this should be fixed", + "ClientHelloPadding": "TODO: first pass, this should be fixed", + "TLS13-ExpectTicketEarlyDataSupport": "TODO: first pass, this should be fixed", + "TLS13-EarlyData-TooMuchData-Client-TLS-Sync": "TODO: first pass, this should be fixed", + "TLS13-EarlyData-TooMuchData-Client-TLS-Sync-SplitHandshakeRecords": "TODO: first pass, this should be fixed", + "TLS13-EarlyData-TooMuchData-Client-TLS-Sync-PackHandshake": "TODO: first pass, this should be fixed", + "WrongMessageType-TLS13-EndOfEarlyData-TLS": "TODO: first pass, this should be fixed", + "TrailingMessageData-TLS13-EndOfEarlyData-TLS": "TODO: first pass, this should be fixed", + "SendHelloRetryRequest-2-TLS13": "TODO: first pass, this should be fixed", + "EarlyData-SkipEndOfEarlyData-TLS13": "TODO: first pass, this should be fixed", + "EarlyData-Server-BadFinished-TLS13": "TODO: first pass, this should be fixed", + "EarlyData-UnexpectedHandshake-Server-TLS13": "TODO: first pass, this should be fixed", + "EarlyData-CipherMismatch-Client-TLS13": "TODO: first pass, this should be fixed", + "Resume-Server-UnofferedCipher-TLS13": "TODO: first pass, this should be fixed" + } +} diff --git a/contrib/go/_std_1.23/src/crypto/tls/boring.go b/contrib/go/_std_1.23/src/crypto/tls/boring.go new file mode 100644 index 000000000000..c44ae92f2528 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/tls/boring.go @@ -0,0 +1,15 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build boringcrypto + +package tls + +import "crypto/internal/boring/fipstls" + +// needFIPS returns fipstls.Required(), which is not available without the +// boringcrypto build tag. +func needFIPS() bool { + return fipstls.Required() +} diff --git a/contrib/go/_std_1.22/src/crypto/tls/cache.go b/contrib/go/_std_1.23/src/crypto/tls/cache.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/tls/cache.go rename to contrib/go/_std_1.23/src/crypto/tls/cache.go diff --git a/contrib/go/_std_1.22/src/crypto/tls/cipher_suites.go b/contrib/go/_std_1.23/src/crypto/tls/cipher_suites.go similarity index 96% rename from contrib/go/_std_1.22/src/crypto/tls/cipher_suites.go rename to contrib/go/_std_1.23/src/crypto/tls/cipher_suites.go index 6f5bc37197a4..eebc66880d63 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/cipher_suites.go +++ b/contrib/go/_std_1.23/src/crypto/tls/cipher_suites.go @@ -18,6 +18,7 @@ import ( "hash" "internal/cpu" "runtime" + _ "unsafe" // for linkname "golang.org/x/crypto/chacha20poly1305" ) @@ -197,6 +198,16 @@ type cipherSuiteTLS13 struct { hash crypto.Hash } +// cipherSuitesTLS13 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/quic-go/quic-go +// - github.com/sagernet/quic-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cipherSuitesTLS13 var cipherSuitesTLS13 = []*cipherSuiteTLS13{ // TODO: replace with a map. {TLS_AES_128_GCM_SHA256, 16, aeadAESGCMTLS13, crypto.SHA256}, {TLS_CHACHA20_POLY1305_SHA256, 32, aeadChaCha20Poly1305, crypto.SHA256}, @@ -346,36 +357,11 @@ var rsaKexCiphers = map[uint16]bool{ TLS_RSA_WITH_AES_256_GCM_SHA384: true, } -var defaultCipherSuites []uint16 -var defaultCipherSuitesWithRSAKex []uint16 - -func init() { - defaultCipherSuites = make([]uint16, 0, len(cipherSuitesPreferenceOrder)) - defaultCipherSuitesWithRSAKex = make([]uint16, 0, len(cipherSuitesPreferenceOrder)) - for _, c := range cipherSuitesPreferenceOrder { - if disabledCipherSuites[c] { - continue - } - if !rsaKexCiphers[c] { - defaultCipherSuites = append(defaultCipherSuites, c) - } - defaultCipherSuitesWithRSAKex = append(defaultCipherSuitesWithRSAKex, c) - } -} - -// defaultCipherSuitesTLS13 is also the preference order, since there are no -// disabled by default TLS 1.3 cipher suites. The same AES vs ChaCha20 logic as -// cipherSuitesPreferenceOrder applies. -var defaultCipherSuitesTLS13 = []uint16{ - TLS_AES_128_GCM_SHA256, - TLS_AES_256_GCM_SHA384, - TLS_CHACHA20_POLY1305_SHA256, -} - -var defaultCipherSuitesTLS13NoAES = []uint16{ - TLS_CHACHA20_POLY1305_SHA256, - TLS_AES_128_GCM_SHA256, - TLS_AES_256_GCM_SHA384, +// tdesCiphers contains 3DES ciphers, +// which we also disable by default unless a GODEBUG is set. +var tdesCiphers = map[uint16]bool{ + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: true, + TLS_RSA_WITH_3DES_EDE_CBC_SHA: true, } var ( @@ -548,6 +534,16 @@ func aeadAESGCM(key, noncePrefix []byte) aead { return ret } +// aeadAESGCMTLS13 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/xtls/xray-core +// - github.com/v2fly/v2ray-core +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname aeadAESGCMTLS13 func aeadAESGCMTLS13(key, nonceMask []byte) aead { if len(nonceMask) != aeadNonceLength { panic("tls: internal error: wrong nonce length") diff --git a/contrib/go/_std_1.22/src/crypto/tls/common.go b/contrib/go/_std_1.23/src/crypto/tls/common.go similarity index 86% rename from contrib/go/_std_1.22/src/crypto/tls/common.go rename to contrib/go/_std_1.23/src/crypto/tls/common.go index 849e8b0a209d..5fd92d3c639b 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/common.go +++ b/contrib/go/_std_1.23/src/crypto/tls/common.go @@ -21,9 +21,11 @@ import ( "internal/godebug" "io" "net" + "slices" "strings" "sync" "time" + _ "unsafe" // for linkname ) const ( @@ -58,12 +60,13 @@ func VersionName(version uint16) string { } const ( - maxPlaintext = 16384 // maximum plaintext payload length - maxCiphertext = 16384 + 2048 // maximum ciphertext payload length - maxCiphertextTLS13 = 16384 + 256 // maximum ciphertext length in TLS 1.3 - recordHeaderLen = 5 // record header length - maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB) - maxUselessRecords = 16 // maximum number of consecutive non-advancing records + maxPlaintext = 16384 // maximum plaintext payload length + maxCiphertext = 16384 + 2048 // maximum ciphertext payload length + maxCiphertextTLS13 = 16384 + 256 // maximum ciphertext length in TLS 1.3 + recordHeaderLen = 5 // record header length + maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB) + maxHandshakeCertificateMsg = 262144 // maximum certificate message size (256 KiB) + maxUselessRecords = 16 // maximum number of consecutive non-advancing records ) // TLS record types. @@ -93,7 +96,6 @@ const ( typeFinished uint8 = 20 typeCertificateStatus uint8 = 22 typeKeyUpdate uint8 = 24 - typeNextProtocol uint8 = 67 // Not IANA assigned typeMessageHash uint8 = 254 // synthetic message ) @@ -123,6 +125,8 @@ const ( extensionKeyShare uint16 = 51 extensionQUICTransportParameters uint16 = 57 extensionRenegotiationInfo uint16 = 0xff01 + extensionECHOuterExtensions uint16 = 0xfd00 + extensionEncryptedClientHello uint16 = 0xfe0d ) // TLS signaling cipher suite values @@ -130,11 +134,13 @@ const ( scsvRenegotiation uint16 = 0x00ff ) -// CurveID is the type of a TLS identifier for an elliptic curve. See +// CurveID is the type of a TLS identifier for a key exchange mechanism. See // https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8. // -// In TLS 1.3, this type is called NamedGroup, but at this time this library -// only supports Elliptic Curve based groups. See RFC 8446, Section 4.2.7. +// In TLS 1.2, this registry used to support only elliptic curves. In TLS 1.3, +// it was extended to other groups and renamed NamedGroup. See RFC 8446, Section +// 4.2.7. It was then also extended to other mechanisms, such as hybrid +// post-quantum KEMs. type CurveID uint16 const ( @@ -142,6 +148,11 @@ const ( CurveP384 CurveID = 24 CurveP521 CurveID = 25 X25519 CurveID = 29 + + // Experimental codepoint for X25519Kyber768Draft00, specified in + // draft-tls-westerbaan-xyber768d00-03. Not exported, as support might be + // removed in the future. + x25519Kyber768Draft00 CurveID = 0x6399 // X25519Kyber768Draft00 ) // TLS 1.3 Key Share. See RFC 8446, Section 4.2.8. @@ -194,25 +205,6 @@ const ( // hash function associated with the Ed25519 signature scheme. var directSigning crypto.Hash = 0 -// defaultSupportedSignatureAlgorithms contains the signature and hash algorithms that -// the code advertises as supported in a TLS 1.2+ ClientHello and in a TLS 1.2+ -// CertificateRequest. The two fields are merged to match with TLS 1.3. -// Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc. -var defaultSupportedSignatureAlgorithms = []SignatureScheme{ - PSSWithSHA256, - ECDSAWithP256AndSHA256, - Ed25519, - PSSWithSHA384, - PSSWithSHA512, - PKCS1WithSHA256, - PKCS1WithSHA384, - PKCS1WithSHA512, - ECDSAWithP384AndSHA384, - ECDSAWithP521AndSHA512, - PKCS1WithSHA1, - ECDSAWithSHA1, -} - // helloRetryRequestRandom is set as the Random value of a ServerHello // to signal that the message is actually a HelloRetryRequest. var helloRetryRequestRandom = []byte{ // See RFC 8446, Section 4.1.3. @@ -297,8 +289,20 @@ type ConnectionState struct { // resumed connections that don't support Extended Master Secret (RFC 7627). TLSUnique []byte + // ECHAccepted indicates if Encrypted Client Hello was offered by the client + // and accepted by the server. Currently, ECH is supported only on the + // client side. + ECHAccepted bool + // ekm is a closure exposed via ExportKeyingMaterial. ekm func(label string, context []byte, length int) ([]byte, error) + + // testingOnlyDidHRR is true if a HelloRetryRequest was sent/received. + testingOnlyDidHRR bool + + // testingOnlyCurveID is the selected CurveID, or zero if an RSA exchanges + // is performed. + testingOnlyCurveID CurveID } // ExportKeyingMaterial returns length bytes of exported key material in a new @@ -372,7 +376,7 @@ type ClientSessionCache interface { Put(sessionKey string, cs *ClientSessionState) } -//go:generate stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go +//go:generate stringer -linecomment -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go // SignatureScheme identifies a signature algorithm supported by TLS. See // RFC 8446, Section 4.2.3. @@ -674,7 +678,9 @@ type Config struct { // If CipherSuites is nil, a safe default list is used. The default cipher // suites might change over time. In Go 1.22 RSA key exchange based cipher // suites were removed from the default list, but can be re-added with the - // GODEBUG setting tlsrsakex=1. + // GODEBUG setting tlsrsakex=1. In Go 1.23 3DES cipher suites were removed + // from the default list, but can be re-added with the GODEBUG setting + // tls3des=1. CipherSuites []uint16 // PreferServerCipherSuites is a legacy field and has no effect. @@ -754,6 +760,10 @@ type Config struct { // an ECDHE handshake, in preference order. If empty, the default will // be used. The client will use the first preference as the type for // its key share in TLS 1.3. This may change in the future. + // + // From Go 1.23, the default includes the X25519Kyber768Draft00 hybrid + // post-quantum key exchange. To disable it, set CurvePreferences explicitly + // or use the GODEBUG=tlskyber=0 environment variable. CurvePreferences []CurveID // DynamicRecordSizingDisabled disables adaptive sizing of TLS records. @@ -774,6 +784,41 @@ type Config struct { // used for debugging. KeyLogWriter io.Writer + // EncryptedClientHelloConfigList is a serialized ECHConfigList. If + // provided, clients will attempt to connect to servers using Encrypted + // Client Hello (ECH) using one of the provided ECHConfigs. Servers + // currently ignore this field. + // + // If the list contains no valid ECH configs, the handshake will fail + // and return an error. + // + // If EncryptedClientHelloConfigList is set, MinVersion, if set, must + // be VersionTLS13. + // + // When EncryptedClientHelloConfigList is set, the handshake will only + // succeed if ECH is sucessfully negotiated. If the server rejects ECH, + // an ECHRejectionError error will be returned, which may contain a new + // ECHConfigList that the server suggests using. + // + // How this field is parsed may change in future Go versions, if the + // encoding described in the final Encrypted Client Hello RFC changes. + EncryptedClientHelloConfigList []byte + + // EncryptedClientHelloRejectionVerify, if not nil, is called when ECH is + // rejected, in order to verify the ECH provider certificate in the outer + // Client Hello. If it returns a non-nil error, the handshake is aborted and + // that error results. + // + // Unlike VerifyPeerCertificate and VerifyConnection, normal certificate + // verification will not be performed before calling + // EncryptedClientHelloRejectionVerify. + // + // If EncryptedClientHelloRejectionVerify is nil and ECH is rejected, the + // roots in RootCAs will be used to verify the ECH providers public + // certificate. VerifyPeerCertificate and VerifyConnection are not called + // when ECH is rejected, even if set, and InsecureSkipVerify is ignored. + EncryptedClientHelloRejectionVerify func(ConnectionState) error + // mutex protects sessionTicketKeys and autoSessionTicketKeys. mutex sync.RWMutex // sessionTicketKeys contains zero or more ticket keys. If set, it means @@ -833,36 +878,38 @@ func (c *Config) Clone() *Config { c.mutex.RLock() defer c.mutex.RUnlock() return &Config{ - Rand: c.Rand, - Time: c.Time, - Certificates: c.Certificates, - NameToCertificate: c.NameToCertificate, - GetCertificate: c.GetCertificate, - GetClientCertificate: c.GetClientCertificate, - GetConfigForClient: c.GetConfigForClient, - VerifyPeerCertificate: c.VerifyPeerCertificate, - VerifyConnection: c.VerifyConnection, - RootCAs: c.RootCAs, - NextProtos: c.NextProtos, - ServerName: c.ServerName, - ClientAuth: c.ClientAuth, - ClientCAs: c.ClientCAs, - InsecureSkipVerify: c.InsecureSkipVerify, - CipherSuites: c.CipherSuites, - PreferServerCipherSuites: c.PreferServerCipherSuites, - SessionTicketsDisabled: c.SessionTicketsDisabled, - SessionTicketKey: c.SessionTicketKey, - ClientSessionCache: c.ClientSessionCache, - UnwrapSession: c.UnwrapSession, - WrapSession: c.WrapSession, - MinVersion: c.MinVersion, - MaxVersion: c.MaxVersion, - CurvePreferences: c.CurvePreferences, - DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, - Renegotiation: c.Renegotiation, - KeyLogWriter: c.KeyLogWriter, - sessionTicketKeys: c.sessionTicketKeys, - autoSessionTicketKeys: c.autoSessionTicketKeys, + Rand: c.Rand, + Time: c.Time, + Certificates: c.Certificates, + NameToCertificate: c.NameToCertificate, + GetCertificate: c.GetCertificate, + GetClientCertificate: c.GetClientCertificate, + GetConfigForClient: c.GetConfigForClient, + VerifyPeerCertificate: c.VerifyPeerCertificate, + VerifyConnection: c.VerifyConnection, + RootCAs: c.RootCAs, + NextProtos: c.NextProtos, + ServerName: c.ServerName, + ClientAuth: c.ClientAuth, + ClientCAs: c.ClientCAs, + InsecureSkipVerify: c.InsecureSkipVerify, + CipherSuites: c.CipherSuites, + PreferServerCipherSuites: c.PreferServerCipherSuites, + SessionTicketsDisabled: c.SessionTicketsDisabled, + SessionTicketKey: c.SessionTicketKey, + ClientSessionCache: c.ClientSessionCache, + UnwrapSession: c.UnwrapSession, + WrapSession: c.WrapSession, + MinVersion: c.MinVersion, + MaxVersion: c.MaxVersion, + CurvePreferences: c.CurvePreferences, + DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, + Renegotiation: c.Renegotiation, + KeyLogWriter: c.KeyLogWriter, + EncryptedClientHelloConfigList: c.EncryptedClientHelloConfigList, + EncryptedClientHelloRejectionVerify: c.EncryptedClientHelloRejectionVerify, + sessionTicketKeys: c.sessionTicketKeys, + autoSessionTicketKeys: c.autoSessionTicketKeys, } } @@ -1008,19 +1055,20 @@ func (c *Config) time() time.Time { return t() } -var tlsrsakex = godebug.New("tlsrsakex") - func (c *Config) cipherSuites() []uint16 { - if needFIPS() { - return fipsCipherSuites(c) - } - if c.CipherSuites != nil { - return c.CipherSuites + if c.CipherSuites == nil { + if needFIPS() { + return defaultCipherSuitesFIPS + } + return defaultCipherSuites() } - if tlsrsakex.Value() == "1" { - return defaultCipherSuitesWithRSAKex + if needFIPS() { + cipherSuites := slices.Clone(c.CipherSuites) + return slices.DeleteFunc(cipherSuites, func(id uint16) bool { + return !slices.Contains(defaultCipherSuitesFIPS, id) + }) } - return defaultCipherSuites + return c.CipherSuites } var supportedVersions = []uint16{ @@ -1040,7 +1088,7 @@ var tls10server = godebug.New("tls10server") func (c *Config) supportedVersions(isClient bool) []uint16 { versions := make([]uint16, 0, len(supportedVersions)) for _, v := range supportedVersions { - if needFIPS() && (v < fipsMinVersion(c) || v > fipsMaxVersion(c)) { + if needFIPS() && !slices.Contains(defaultSupportedVersionsFIPS, v) { continue } if (c == nil || c.MinVersion == 0) && v < VersionTLS12 { @@ -1048,6 +1096,9 @@ func (c *Config) supportedVersions(isClient bool) []uint16 { continue } } + if isClient && c.EncryptedClientHelloConfigList != nil && v < VersionTLS13 { + continue + } if c != nil && c.MinVersion != 0 && v < c.MinVersion { continue } @@ -1081,20 +1132,30 @@ func supportedVersionsFromMax(maxVersion uint16) []uint16 { return versions } -var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521} - -func (c *Config) curvePreferences() []CurveID { - if needFIPS() { - return fipsCurvePreferences(c) +func (c *Config) curvePreferences(version uint16) []CurveID { + var curvePreferences []CurveID + if c != nil && len(c.CurvePreferences) != 0 { + curvePreferences = slices.Clone(c.CurvePreferences) + if needFIPS() { + return slices.DeleteFunc(curvePreferences, func(c CurveID) bool { + return !slices.Contains(defaultCurvePreferencesFIPS, c) + }) + } + } else if needFIPS() { + curvePreferences = slices.Clone(defaultCurvePreferencesFIPS) + } else { + curvePreferences = defaultCurvePreferences() } - if c == nil || len(c.CurvePreferences) == 0 { - return defaultCurvePreferences + if version < VersionTLS13 { + return slices.DeleteFunc(curvePreferences, func(c CurveID) bool { + return c == x25519Kyber768Draft00 + }) } - return c.CurvePreferences + return curvePreferences } -func (c *Config) supportsCurve(curve CurveID) bool { - for _, cc := range c.curvePreferences() { +func (c *Config) supportsCurve(version uint16, curve CurveID) bool { + for _, cc := range c.curvePreferences(version) { if cc == curve { return true } @@ -1116,6 +1177,15 @@ func (c *Config) mutualVersion(isClient bool, peerVersions []uint16) (uint16, bo return 0, false } +// errNoCertificates should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/xtls/xray-core +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname errNoCertificates var errNoCertificates = errors.New("tls: no certificates configured") // getCertificate returns the best certificate for the given ClientHelloInfo, @@ -1253,7 +1323,7 @@ func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error { } // The only signed key exchange we support is ECDHE. - if !supportsECDHE(config, chi.SupportedCurves, chi.SupportedPoints) { + if !supportsECDHE(config, vers, chi.SupportedCurves, chi.SupportedPoints) { return supportsRSAFallback(errors.New("client doesn't support ECDHE, can only use legacy RSA key exchange")) } @@ -1274,7 +1344,7 @@ func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error { } var curveOk bool for _, c := range chi.SupportedCurves { - if c == curve && config.supportsCurve(c) { + if c == curve && config.supportsCurve(vers, c) { curveOk = true break } @@ -1445,6 +1515,15 @@ type handshakeMessage interface { unmarshal([]byte) bool } +type handshakeMessageWithOriginalBytes interface { + handshakeMessage + + // originalBytes should return the original bytes that were passed to + // unmarshal to create the message. If the message was not produced by + // unmarshal, it should return nil. + originalBytes() []byte +} + // lruSessionCache is a ClientSessionCache implementation that uses an LRU // caching strategy. type lruSessionCache struct { @@ -1532,6 +1611,14 @@ func unexpectedMessageError(wanted, got any) error { return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted) } +// supportedSignatureAlgorithms returns the supported signature algorithms. +func supportedSignatureAlgorithms() []SignatureScheme { + if !needFIPS() { + return defaultSupportedSignatureAlgorithms + } + return defaultSupportedSignatureAlgorithmsFIPS +} + func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlgorithms []SignatureScheme) bool { for _, s := range supportedSignatureAlgorithms { if s == sigAlg { diff --git a/contrib/go/_std_1.22/src/crypto/tls/common_string.go b/contrib/go/_std_1.23/src/crypto/tls/common_string.go similarity index 92% rename from contrib/go/_std_1.22/src/crypto/tls/common_string.go rename to contrib/go/_std_1.23/src/crypto/tls/common_string.go index 238108811f27..1752f810505b 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/common_string.go +++ b/contrib/go/_std_1.23/src/crypto/tls/common_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go"; DO NOT EDIT. +// Code generated by "stringer -linecomment -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go"; DO NOT EDIT. package tls @@ -71,11 +71,13 @@ func _() { _ = x[CurveP384-24] _ = x[CurveP521-25] _ = x[X25519-29] + _ = x[x25519Kyber768Draft00-25497] } const ( _CurveID_name_0 = "CurveP256CurveP384CurveP521" _CurveID_name_1 = "X25519" + _CurveID_name_2 = "X25519Kyber768Draft00" ) var ( @@ -89,6 +91,8 @@ func (i CurveID) String() string { return _CurveID_name_0[_CurveID_index_0[i]:_CurveID_index_0[i+1]] case i == 29: return _CurveID_name_1 + case i == 25497: + return _CurveID_name_2 default: return "CurveID(" + strconv.FormatInt(int64(i), 10) + ")" } diff --git a/contrib/go/_std_1.22/src/crypto/tls/conn.go b/contrib/go/_std_1.23/src/crypto/tls/conn.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/tls/conn.go rename to contrib/go/_std_1.23/src/crypto/tls/conn.go index 0e4669866e5e..bdbc2bde416a 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/conn.go +++ b/contrib/go/_std_1.23/src/crypto/tls/conn.go @@ -48,7 +48,9 @@ type Conn struct { handshakes int extMasterSecret bool didResume bool // whether this connection was a session resumption + didHRR bool // whether a HelloRetryRequest was sent/received cipherSuite uint16 + curveID CurveID ocspResponse []byte // stapled OCSP response scts [][]byte // signed certificate timestamps from server peerCertificates []*x509.Certificate @@ -69,6 +71,7 @@ type Conn struct { // resumptionSecret is the resumption_master_secret for handling // or sending NewSessionTicket messages. resumptionSecret []byte + echAccepted bool // ticketKeys is the set of active session ticket keys for this // connection. The first one is used to encrypt new tickets and @@ -1040,7 +1043,7 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) { } // writeHandshakeRecord writes a handshake message to the connection and updates -// the record layer state. If transcript is non-nil the marshalled message is +// the record layer state. If transcript is non-nil the marshaled message is // written to it. func (c *Conn) writeHandshakeRecord(msg handshakeMessage, transcript transcriptHash) (int, error) { c.out.Lock() @@ -1087,10 +1090,22 @@ func (c *Conn) readHandshake(transcript transcriptHash) (any, error) { return nil, err } data := c.hand.Bytes() + + maxHandshakeSize := maxHandshake + // hasVers indicates we're past the first message, forcing someone trying to + // make us just allocate a large buffer to at least do the initial part of + // the handshake first. + if c.haveVers && data[0] == typeCertificate { + // Since certificate messages are likely to be the only messages that + // can be larger than maxHandshake, we use a special limit for just + // those messages. + maxHandshakeSize = maxHandshakeCertificateMsg + } + n := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) - if n > maxHandshake { + if n > maxHandshakeSize { c.sendAlertLocked(alertInternalError) - return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake)) + return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshakeSize)) } if err := c.readHandshakeBytes(4 + n); err != nil { return nil, err @@ -1608,6 +1623,9 @@ func (c *Conn) connectionStateLocked() ConnectionState { state.Version = c.vers state.NegotiatedProtocol = c.clientProtocol state.DidResume = c.didResume + state.testingOnlyDidHRR = c.didHRR + // c.curveID is not set on TLS 1.0–1.2 resumptions. Fix that before exposing it. + state.testingOnlyCurveID = c.curveID state.NegotiatedProtocolIsMutual = true state.ServerName = c.serverName state.CipherSuite = c.cipherSuite @@ -1635,6 +1653,7 @@ func (c *Conn) connectionStateLocked() ConnectionState { } else { state.ekm = c.ekm } + state.ECHAccepted = c.echAccepted return state } diff --git a/contrib/go/_std_1.23/src/crypto/tls/defaults.go b/contrib/go/_std_1.23/src/crypto/tls/defaults.go new file mode 100644 index 000000000000..9b28acdc2d86 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/tls/defaults.go @@ -0,0 +1,129 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tls + +import ( + "internal/godebug" + "slices" + _ "unsafe" // for linkname +) + +// Defaults are collected in this file to allow distributions to more easily patch +// them to apply local policies. + +var tlskyber = godebug.New("tlskyber") + +func defaultCurvePreferences() []CurveID { + if tlskyber.Value() == "0" { + return []CurveID{X25519, CurveP256, CurveP384, CurveP521} + } + // For now, x25519Kyber768Draft00 must always be followed by X25519. + return []CurveID{x25519Kyber768Draft00, X25519, CurveP256, CurveP384, CurveP521} +} + +// defaultSupportedSignatureAlgorithms contains the signature and hash algorithms that +// the code advertises as supported in a TLS 1.2+ ClientHello and in a TLS 1.2+ +// CertificateRequest. The two fields are merged to match with TLS 1.3. +// Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc. +var defaultSupportedSignatureAlgorithms = []SignatureScheme{ + PSSWithSHA256, + ECDSAWithP256AndSHA256, + Ed25519, + PSSWithSHA384, + PSSWithSHA512, + PKCS1WithSHA256, + PKCS1WithSHA384, + PKCS1WithSHA512, + ECDSAWithP384AndSHA384, + ECDSAWithP521AndSHA512, + PKCS1WithSHA1, + ECDSAWithSHA1, +} + +var tlsrsakex = godebug.New("tlsrsakex") +var tls3des = godebug.New("tls3des") + +func defaultCipherSuites() []uint16 { + suites := slices.Clone(cipherSuitesPreferenceOrder) + return slices.DeleteFunc(suites, func(c uint16) bool { + return disabledCipherSuites[c] || + tlsrsakex.Value() != "1" && rsaKexCiphers[c] || + tls3des.Value() != "1" && tdesCiphers[c] + }) +} + +// defaultCipherSuitesTLS13 is also the preference order, since there are no +// disabled by default TLS 1.3 cipher suites. The same AES vs ChaCha20 logic as +// cipherSuitesPreferenceOrder applies. +// +// defaultCipherSuitesTLS13 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/quic-go/quic-go +// - github.com/sagernet/quic-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname defaultCipherSuitesTLS13 +var defaultCipherSuitesTLS13 = []uint16{ + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, + TLS_CHACHA20_POLY1305_SHA256, +} + +// defaultCipherSuitesTLS13NoAES should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/quic-go/quic-go +// - github.com/sagernet/quic-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname defaultCipherSuitesTLS13NoAES +var defaultCipherSuitesTLS13NoAES = []uint16{ + TLS_CHACHA20_POLY1305_SHA256, + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, +} + +var defaultSupportedVersionsFIPS = []uint16{ + VersionTLS12, +} + +// defaultCurvePreferencesFIPS are the FIPS-allowed curves, +// in preference order (most preferable first). +var defaultCurvePreferencesFIPS = []CurveID{CurveP256, CurveP384, CurveP521} + +// defaultSupportedSignatureAlgorithmsFIPS currently are a subset of +// defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1. +var defaultSupportedSignatureAlgorithmsFIPS = []SignatureScheme{ + PSSWithSHA256, + PSSWithSHA384, + PSSWithSHA512, + PKCS1WithSHA256, + ECDSAWithP256AndSHA256, + PKCS1WithSHA384, + ECDSAWithP384AndSHA384, + PKCS1WithSHA512, + ECDSAWithP521AndSHA512, +} + +// defaultCipherSuitesFIPS are the FIPS-allowed cipher suites. +var defaultCipherSuitesFIPS = []uint16{ + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_256_GCM_SHA384, +} + +// defaultCipherSuitesTLS13FIPS are the FIPS-allowed cipher suites for TLS 1.3. +var defaultCipherSuitesTLS13FIPS = []uint16{ + TLS_AES_128_GCM_SHA256, + TLS_AES_256_GCM_SHA384, +} diff --git a/contrib/go/_std_1.23/src/crypto/tls/ech.go b/contrib/go/_std_1.23/src/crypto/tls/ech.go new file mode 100644 index 000000000000..7bf68589f870 --- /dev/null +++ b/contrib/go/_std_1.23/src/crypto/tls/ech.go @@ -0,0 +1,283 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tls + +import ( + "crypto/internal/hpke" + "errors" + "strings" + + "golang.org/x/crypto/cryptobyte" +) + +type echCipher struct { + KDFID uint16 + AEADID uint16 +} + +type echExtension struct { + Type uint16 + Data []byte +} + +type echConfig struct { + raw []byte + + Version uint16 + Length uint16 + + ConfigID uint8 + KemID uint16 + PublicKey []byte + SymmetricCipherSuite []echCipher + + MaxNameLength uint8 + PublicName []byte + Extensions []echExtension +} + +var errMalformedECHConfig = errors.New("tls: malformed ECHConfigList") + +// parseECHConfigList parses a draft-ietf-tls-esni-18 ECHConfigList, returning a +// slice of parsed ECHConfigs, in the same order they were parsed, or an error +// if the list is malformed. +func parseECHConfigList(data []byte) ([]echConfig, error) { + s := cryptobyte.String(data) + // Skip the length prefix + var length uint16 + if !s.ReadUint16(&length) { + return nil, errMalformedECHConfig + } + if length != uint16(len(data)-2) { + return nil, errMalformedECHConfig + } + var configs []echConfig + for len(s) > 0 { + var ec echConfig + ec.raw = []byte(s) + if !s.ReadUint16(&ec.Version) { + return nil, errMalformedECHConfig + } + if !s.ReadUint16(&ec.Length) { + return nil, errMalformedECHConfig + } + if len(ec.raw) < int(ec.Length)+4 { + return nil, errMalformedECHConfig + } + ec.raw = ec.raw[:ec.Length+4] + if ec.Version != extensionEncryptedClientHello { + s.Skip(int(ec.Length)) + continue + } + if !s.ReadUint8(&ec.ConfigID) { + return nil, errMalformedECHConfig + } + if !s.ReadUint16(&ec.KemID) { + return nil, errMalformedECHConfig + } + if !s.ReadUint16LengthPrefixed((*cryptobyte.String)(&ec.PublicKey)) { + return nil, errMalformedECHConfig + } + var cipherSuites cryptobyte.String + if !s.ReadUint16LengthPrefixed(&cipherSuites) { + return nil, errMalformedECHConfig + } + for !cipherSuites.Empty() { + var c echCipher + if !cipherSuites.ReadUint16(&c.KDFID) { + return nil, errMalformedECHConfig + } + if !cipherSuites.ReadUint16(&c.AEADID) { + return nil, errMalformedECHConfig + } + ec.SymmetricCipherSuite = append(ec.SymmetricCipherSuite, c) + } + if !s.ReadUint8(&ec.MaxNameLength) { + return nil, errMalformedECHConfig + } + var publicName cryptobyte.String + if !s.ReadUint8LengthPrefixed(&publicName) { + return nil, errMalformedECHConfig + } + ec.PublicName = publicName + var extensions cryptobyte.String + if !s.ReadUint16LengthPrefixed(&extensions) { + return nil, errMalformedECHConfig + } + for !extensions.Empty() { + var e echExtension + if !extensions.ReadUint16(&e.Type) { + return nil, errMalformedECHConfig + } + if !extensions.ReadUint16LengthPrefixed((*cryptobyte.String)(&e.Data)) { + return nil, errMalformedECHConfig + } + ec.Extensions = append(ec.Extensions, e) + } + + configs = append(configs, ec) + } + return configs, nil +} + +func pickECHConfig(list []echConfig) *echConfig { + for _, ec := range list { + if _, ok := hpke.SupportedKEMs[ec.KemID]; !ok { + continue + } + var validSCS bool + for _, cs := range ec.SymmetricCipherSuite { + if _, ok := hpke.SupportedAEADs[cs.AEADID]; !ok { + continue + } + if _, ok := hpke.SupportedKDFs[cs.KDFID]; !ok { + continue + } + validSCS = true + break + } + if !validSCS { + continue + } + if !validDNSName(string(ec.PublicName)) { + continue + } + var unsupportedExt bool + for _, ext := range ec.Extensions { + // If high order bit is set to 1 the extension is mandatory. + // Since we don't support any extensions, if we see a mandatory + // bit, we skip the config. + if ext.Type&uint16(1<<15) != 0 { + unsupportedExt = true + } + } + if unsupportedExt { + continue + } + return &ec + } + return nil +} + +func pickECHCipherSuite(suites []echCipher) (echCipher, error) { + for _, s := range suites { + // NOTE: all of the supported AEADs and KDFs are fine, rather than + // imposing some sort of preference here, we just pick the first valid + // suite. + if _, ok := hpke.SupportedAEADs[s.AEADID]; !ok { + continue + } + if _, ok := hpke.SupportedKDFs[s.KDFID]; !ok { + continue + } + return s, nil + } + return echCipher{}, errors.New("tls: no supported symmetric ciphersuites for ECH") +} + +func encodeInnerClientHello(inner *clientHelloMsg, maxNameLength int) ([]byte, error) { + h, err := inner.marshalMsg(true) + if err != nil { + return nil, err + } + h = h[4:] // strip four byte prefix + + var paddingLen int + if inner.serverName != "" { + paddingLen = max(0, maxNameLength-len(inner.serverName)) + } else { + paddingLen = maxNameLength + 9 + } + paddingLen = 31 - ((len(h) + paddingLen - 1) % 32) + + return append(h, make([]byte, paddingLen)...), nil +} + +func generateOuterECHExt(id uint8, kdfID, aeadID uint16, encodedKey []byte, payload []byte) ([]byte, error) { + var b cryptobyte.Builder + b.AddUint8(0) // outer + b.AddUint16(kdfID) + b.AddUint16(aeadID) + b.AddUint8(id) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(encodedKey) }) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(payload) }) + return b.Bytes() +} + +func computeAndUpdateOuterECHExtension(outer, inner *clientHelloMsg, ech *echContext, useKey bool) error { + var encapKey []byte + if useKey { + encapKey = ech.encapsulatedKey + } + encodedInner, err := encodeInnerClientHello(inner, int(ech.config.MaxNameLength)) + if err != nil { + return err + } + // NOTE: the tag lengths for all of the supported AEADs are the same (16 + // bytes), so we have hardcoded it here. If we add support for another AEAD + // with a different tag length, we will need to change this. + encryptedLen := len(encodedInner) + 16 // AEAD tag length + outer.encryptedClientHello, err = generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, make([]byte, encryptedLen)) + if err != nil { + return err + } + serializedOuter, err := outer.marshal() + if err != nil { + return err + } + serializedOuter = serializedOuter[4:] // strip the four byte prefix + encryptedInner, err := ech.hpkeContext.Seal(serializedOuter, encodedInner) + if err != nil { + return err + } + outer.encryptedClientHello, err = generateOuterECHExt(ech.config.ConfigID, ech.kdfID, ech.aeadID, encapKey, encryptedInner) + if err != nil { + return err + } + return nil +} + +// validDNSName is a rather rudimentary check for the validity of a DNS name. +// This is used to check if the public_name in a ECHConfig is valid when we are +// picking a config. This can be somewhat lax because even if we pick a +// valid-looking name, the DNS layer will later reject it anyway. +func validDNSName(name string) bool { + if len(name) > 253 { + return false + } + labels := strings.Split(name, ".") + if len(labels) <= 1 { + return false + } + for _, l := range labels { + labelLen := len(l) + if labelLen == 0 { + return false + } + for i, r := range l { + if r == '-' && (i == 0 || i == labelLen-1) { + return false + } + if (r < '0' || r > '9') && (r < 'a' || r > 'z') && (r < 'A' || r > 'Z') && r != '-' { + return false + } + } + } + return true +} + +// ECHRejectionError is the error type returned when ECH is rejected by a remote +// server. If the server offered a ECHConfigList to use for retries, the +// RetryConfigList field will contain this list. +// +// The client may treat an ECHRejectionError with an empty set of RetryConfigs +// as a secure signal from the server. +type ECHRejectionError struct { + RetryConfigList []byte +} + +func (e *ECHRejectionError) Error() string { + return "tls: server rejected ECH" +} diff --git a/contrib/go/_std_1.22/src/crypto/tls/fipsonly/fipsonly.go b/contrib/go/_std_1.23/src/crypto/tls/fipsonly/fipsonly.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/tls/fipsonly/fipsonly.go rename to contrib/go/_std_1.23/src/crypto/tls/fipsonly/fipsonly.go diff --git a/contrib/go/_std_1.22/src/crypto/tls/fipsonly/ya.make b/contrib/go/_std_1.23/src/crypto/tls/fipsonly/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/tls/fipsonly/ya.make rename to contrib/go/_std_1.23/src/crypto/tls/fipsonly/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/tls/generate_cert.go b/contrib/go/_std_1.23/src/crypto/tls/generate_cert.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/tls/generate_cert.go rename to contrib/go/_std_1.23/src/crypto/tls/generate_cert.go diff --git a/contrib/go/_std_1.22/src/crypto/tls/handshake_client.go b/contrib/go/_std_1.23/src/crypto/tls/handshake_client.go similarity index 80% rename from contrib/go/_std_1.22/src/crypto/tls/handshake_client.go rename to contrib/go/_std_1.23/src/crypto/tls/handshake_client.go index 08a2d47974c2..5025657590d3 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/handshake_client.go +++ b/contrib/go/_std_1.23/src/crypto/tls/handshake_client.go @@ -8,15 +8,17 @@ import ( "bytes" "context" "crypto" - "crypto/ecdh" "crypto/ecdsa" "crypto/ed25519" + "crypto/internal/hpke" + "crypto/internal/mlkem768" "crypto/rsa" "crypto/subtle" "crypto/x509" "errors" "fmt" "hash" + "internal/byteorder" "internal/godebug" "io" "net" @@ -39,52 +41,52 @@ type clientHandshakeState struct { var testingOnlyForceClientHelloSignatureAlgorithms []SignatureScheme -func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { +func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echContext, error) { config := c.config if len(config.ServerName) == 0 && !config.InsecureSkipVerify { - return nil, nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config") + return nil, nil, nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config") } nextProtosLength := 0 for _, proto := range config.NextProtos { if l := len(proto); l == 0 || l > 255 { - return nil, nil, errors.New("tls: invalid NextProtos value") + return nil, nil, nil, errors.New("tls: invalid NextProtos value") } else { nextProtosLength += 1 + l } } if nextProtosLength > 0xffff { - return nil, nil, errors.New("tls: NextProtos values too large") + return nil, nil, nil, errors.New("tls: NextProtos values too large") } supportedVersions := config.supportedVersions(roleClient) if len(supportedVersions) == 0 { - return nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion") - } - - clientHelloVersion := config.maxSupportedVersion(roleClient) - // The version at the beginning of the ClientHello was capped at TLS 1.2 - // for compatibility reasons. The supported_versions extension is used - // to negotiate versions now. See RFC 8446, Section 4.2.1. - if clientHelloVersion > VersionTLS12 { - clientHelloVersion = VersionTLS12 + return nil, nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion") } + maxVersion := config.maxSupportedVersion(roleClient) hello := &clientHelloMsg{ - vers: clientHelloVersion, + vers: maxVersion, compressionMethods: []uint8{compressionNone}, random: make([]byte, 32), extendedMasterSecret: true, ocspStapling: true, scts: true, serverName: hostnameInSNI(config.ServerName), - supportedCurves: config.curvePreferences(), + supportedCurves: config.curvePreferences(maxVersion), supportedPoints: []uint8{pointFormatUncompressed}, secureRenegotiationSupported: true, alpnProtocols: config.NextProtos, supportedVersions: supportedVersions, } + // The version at the beginning of the ClientHello was capped at TLS 1.2 + // for compatibility reasons. The supported_versions extension is used + // to negotiate versions now. See RFC 8446, Section 4.2.1. + if hello.vers > VersionTLS12 { + hello.vers = VersionTLS12 + } + if c.handshakes > 0 { hello.secureRenegotiation = c.clientFinished[:] } @@ -103,7 +105,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { } // Don't advertise TLS 1.2-only cipher suites unless // we're attempting TLS 1.2. - if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 { + if maxVersion < VersionTLS12 && suite.flags&suiteTLS12 != 0 { continue } hello.cipherSuites = append(hello.cipherSuites, suiteId) @@ -111,7 +113,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { _, err := io.ReadFull(config.rand(), hello.random) if err != nil { - return nil, nil, errors.New("tls: short read from Rand: " + err.Error()) + return nil, nil, nil, errors.New("tls: short read from Rand: " + err.Error()) } // A random session ID is used to detect when the server accepted a ticket @@ -122,18 +124,18 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { if c.quic == nil { hello.sessionId = make([]byte, 32) if _, err := io.ReadFull(config.rand(), hello.sessionId); err != nil { - return nil, nil, errors.New("tls: short read from Rand: " + err.Error()) + return nil, nil, nil, errors.New("tls: short read from Rand: " + err.Error()) } } - if hello.vers >= VersionTLS12 { + if maxVersion >= VersionTLS12 { hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms() } if testingOnlyForceClientHelloSignatureAlgorithms != nil { hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms } - var key *ecdh.PrivateKey + var keyShareKeys *keySharePrivateKeys if hello.supportedVersions[0] == VersionTLS13 { // Reset the list of ciphers when the client only supports TLS 1.3. if len(hello.supportedVersions) == 1 { @@ -145,21 +147,46 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...) } - curveID := config.curvePreferences()[0] - if _, ok := curveForCurveID(curveID); !ok { - return nil, nil, errors.New("tls: CurvePreferences includes unsupported curve") - } - key, err = generateECDHEKey(config.rand(), curveID) - if err != nil { - return nil, nil, err + curveID := config.curvePreferences(maxVersion)[0] + keyShareKeys = &keySharePrivateKeys{curveID: curveID} + if curveID == x25519Kyber768Draft00 { + keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), X25519) + if err != nil { + return nil, nil, nil, err + } + seed := make([]byte, mlkem768.SeedSize) + if _, err := io.ReadFull(config.rand(), seed); err != nil { + return nil, nil, nil, err + } + keyShareKeys.kyber, err = mlkem768.NewKeyFromSeed(seed) + if err != nil { + return nil, nil, nil, err + } + // For draft-tls-westerbaan-xyber768d00-03, we send both a hybrid + // and a standard X25519 key share, since most servers will only + // support the latter. We reuse the same X25519 ephemeral key for + // both, as allowed by draft-ietf-tls-hybrid-design-09, Section 3.2. + hello.keyShares = []keyShare{ + {group: x25519Kyber768Draft00, data: append(keyShareKeys.ecdhe.PublicKey().Bytes(), + keyShareKeys.kyber.EncapsulationKey()...)}, + {group: X25519, data: keyShareKeys.ecdhe.PublicKey().Bytes()}, + } + } else { + if _, ok := curveForCurveID(curveID); !ok { + return nil, nil, nil, errors.New("tls: CurvePreferences includes unsupported curve") + } + keyShareKeys.ecdhe, err = generateECDHEKey(config.rand(), curveID) + if err != nil { + return nil, nil, nil, err + } + hello.keyShares = []keyShare{{group: curveID, data: keyShareKeys.ecdhe.PublicKey().Bytes()}} } - hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}} } if c.quic != nil { p, err := c.quicGetTransportParameters() if err != nil { - return nil, nil, err + return nil, nil, nil, err } if p == nil { p = []byte{} @@ -167,7 +194,60 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) { hello.quicTransportParameters = p } - return hello, key, nil + var ech *echContext + if c.config.EncryptedClientHelloConfigList != nil { + if c.config.MinVersion != 0 && c.config.MinVersion < VersionTLS13 { + return nil, nil, nil, errors.New("tls: MinVersion must be >= VersionTLS13 if EncryptedClientHelloConfigList is populated") + } + if c.config.MaxVersion != 0 && c.config.MaxVersion <= VersionTLS12 { + return nil, nil, nil, errors.New("tls: MaxVersion must be >= VersionTLS13 if EncryptedClientHelloConfigList is populated") + } + echConfigs, err := parseECHConfigList(c.config.EncryptedClientHelloConfigList) + if err != nil { + return nil, nil, nil, err + } + echConfig := pickECHConfig(echConfigs) + if echConfig == nil { + return nil, nil, nil, errors.New("tls: EncryptedClientHelloConfigList contains no valid configs") + } + ech = &echContext{config: echConfig} + hello.encryptedClientHello = []byte{1} // indicate inner hello + // We need to explicitly set these 1.2 fields to nil, as we do not + // marshal them when encoding the inner hello, otherwise transcripts + // will later mismatch. + hello.supportedPoints = nil + hello.ticketSupported = false + hello.secureRenegotiationSupported = false + hello.extendedMasterSecret = false + + echPK, err := hpke.ParseHPKEPublicKey(ech.config.KemID, ech.config.PublicKey) + if err != nil { + return nil, nil, nil, err + } + suite, err := pickECHCipherSuite(ech.config.SymmetricCipherSuite) + if err != nil { + return nil, nil, nil, err + } + ech.kdfID, ech.aeadID = suite.KDFID, suite.AEADID + info := append([]byte("tls ech\x00"), ech.config.raw...) + ech.encapsulatedKey, ech.hpkeContext, err = hpke.SetupSender(ech.config.KemID, suite.KDFID, suite.AEADID, echPK, info) + if err != nil { + return nil, nil, nil, err + } + } + + return hello, keyShareKeys, ech, nil +} + +type echContext struct { + config *echConfig + hpkeContext *hpke.Sender + encapsulatedKey []byte + innerHello *clientHelloMsg + innerTranscript hash.Hash + kdfID uint16 + aeadID uint16 + echRejected bool } func (c *Conn) clientHandshake(ctx context.Context) (err error) { @@ -179,11 +259,10 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { // need to be reset. c.didResume = false - hello, ecdheKey, err := c.makeClientHello() + hello, keyShareKeys, ech, err := c.makeClientHello() if err != nil { return err } - c.serverName = hello.serverName session, earlySecret, binderKey, err := c.loadSession(hello) if err != nil { @@ -205,6 +284,31 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { }() } + if ech != nil { + // Split hello into inner and outer + ech.innerHello = hello.clone() + + // Overwrite the server name in the outer hello with the public facing + // name. + hello.serverName = string(ech.config.PublicName) + // Generate a new random for the outer hello. + hello.random = make([]byte, 32) + _, err = io.ReadFull(c.config.rand(), hello.random) + if err != nil { + return errors.New("tls: short read from Rand: " + err.Error()) + } + + // NOTE: we don't do PSK GREASE, in line with boringssl, it's meant to + // work around _possibly_ broken middleboxes, but there is little-to-no + // evidence that this is actually a problem. + + if err := computeAndUpdateOuterECHExtension(hello, ech.innerHello, ech, true); err != nil { + return err + } + } + + c.serverName = hello.serverName + if _, err := c.writeHandshakeRecord(hello, nil); err != nil { return err } @@ -249,17 +353,16 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { if c.vers == VersionTLS13 { hs := &clientHandshakeStateTLS13{ - c: c, - ctx: ctx, - serverHello: serverHello, - hello: hello, - ecdheKey: ecdheKey, - session: session, - earlySecret: earlySecret, - binderKey: binderKey, + c: c, + ctx: ctx, + serverHello: serverHello, + hello: hello, + keyShareKeys: keyShareKeys, + session: session, + earlySecret: earlySecret, + binderKey: binderKey, + echContext: ech, } - - // In TLS 1.3, session tickets are delivered after the handshake. return hs.handshake() } @@ -270,12 +373,7 @@ func (c *Conn) clientHandshake(ctx context.Context) (err error) { hello: hello, session: session, } - - if err := hs.handshake(); err != nil { - return err - } - - return nil + return hs.handshake() } func (c *Conn) loadSession(hello *clientHelloMsg) ( @@ -284,7 +382,11 @@ func (c *Conn) loadSession(hello *clientHelloMsg) ( return nil, nil, nil, nil } - hello.ticketSupported = true + echInner := bytes.Equal(hello.encryptedClientHello, []byte{1}) + + // ticketSupported is a TLS 1.2 extension (as TLS 1.3 replaced tickets with PSK + // identities) and ECH requires and forces TLS 1.3. + hello.ticketSupported = true && !echInner if hello.supportedVersions[0] == VersionTLS13 { // Require DHE on resumption as it guarantees forward secrecy against @@ -347,7 +449,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) ( return nil, nil, nil, nil } - hello.sessionTicket = cs.ticket + hello.sessionTicket = session.ticket return } @@ -375,10 +477,14 @@ func (c *Conn) loadSession(hello *clientHelloMsg) ( return nil, nil, nil, nil } - if c.quic != nil && session.EarlyData { + if c.quic != nil { + if c.quic.enableSessionEvents { + c.quicResumeSession(session) + } + // For 0-RTT, the cipher suite has to match exactly, and we need to be // offering the same ALPN. - if mutualCipherSuiteTLS13(hello.cipherSuites, session.cipherSuite) != nil { + if session.EarlyData && mutualCipherSuiteTLS13(hello.cipherSuites, session.cipherSuite) != nil { for _, alpn := range hello.alpnProtocols { if alpn == session.alpnProtocol { hello.earlyData = true @@ -391,7 +497,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) ( // Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1. ticketAge := c.config.time().Sub(time.Unix(int64(session.createdAt), 0)) identity := pskIdentity{ - label: cs.ticket, + label: session.ticket, obfuscatedTicketAge: uint32(ticketAge/time.Millisecond) + session.ageAdd, } hello.pskIdentities = []pskIdentity{identity} @@ -401,13 +507,7 @@ func (c *Conn) loadSession(hello *clientHelloMsg) ( earlySecret = cipherSuite.extract(session.secret, nil) binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil) transcript := cipherSuite.hash.New() - helloBytes, err := hello.marshalWithoutBinders() - if err != nil { - return nil, nil, nil, err - } - transcript.Write(helloBytes) - pskBinders := [][]byte{cipherSuite.finishedHash(binderKey, transcript)} - if err := hello.updateBinders(pskBinders); err != nil { + if err := computeAndUpdatePSK(hello, binderKey, transcript, cipherSuite.finishedHash); err != nil { return nil, nil, nil, err } @@ -527,8 +627,13 @@ func (hs *clientHandshakeState) pickCipherSuite() error { } if hs.c.config.CipherSuites == nil && !needFIPS() && rsaKexCiphers[hs.suite.id] { + tlsrsakex.Value() // ensure godebug is initialized tlsrsakex.IncNonDefault() } + if hs.c.config.CipherSuites == nil && !needFIPS() && tdesCiphers[hs.suite.id] { + tls3des.Value() // ensure godebug is initialized + tls3des.IncNonDefault() + } hs.c.cipherSuite = hs.suite.id return nil @@ -602,6 +707,9 @@ func (hs *clientHandshakeState) doFullHandshake() error { c.sendAlert(alertUnexpectedMessage) return err } + if len(skx.key) >= 3 && skx.key[0] == 3 /* named curve */ { + c.curveID = CurveID(byteorder.BeUint16(skx.key[1:])) + } msg, err = c.readHandshake(&hs.finishedHash) if err != nil { @@ -915,13 +1023,11 @@ func (hs *clientHandshakeState) saveSessionTicket() error { return nil } - session, err := c.sessionState() - if err != nil { - return err - } + session := c.sessionState() session.secret = hs.masterSecret + session.ticket = hs.ticket - cs := &ClientSessionState{ticket: hs.ticket, session: session} + cs := &ClientSessionState{session: session} c.config.ClientSessionCache.Put(cacheKey, cs) return nil } @@ -982,7 +1088,32 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error { certs[i] = cert.cert } - if !c.config.InsecureSkipVerify { + echRejected := c.config.EncryptedClientHelloConfigList != nil && !c.echAccepted + if echRejected { + if c.config.EncryptedClientHelloRejectionVerify != nil { + if err := c.config.EncryptedClientHelloRejectionVerify(c.connectionStateLocked()); err != nil { + c.sendAlert(alertBadCertificate) + return err + } + } else { + opts := x509.VerifyOptions{ + Roots: c.config.RootCAs, + CurrentTime: c.config.time(), + DNSName: c.serverName, + Intermediates: x509.NewCertPool(), + } + + for _, cert := range certs[1:] { + opts.Intermediates.AddCert(cert) + } + var err error + c.verifiedChains, err = certs[0].Verify(opts) + if err != nil { + c.sendAlert(alertBadCertificate) + return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} + } + } + } else if !c.config.InsecureSkipVerify { opts := x509.VerifyOptions{ Roots: c.config.RootCAs, CurrentTime: c.config.time(), @@ -1012,14 +1143,14 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error { c.activeCertHandles = activeHandles c.peerCertificates = certs - if c.config.VerifyPeerCertificate != nil { + if c.config.VerifyPeerCertificate != nil && !echRejected { if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil { c.sendAlert(alertBadCertificate) return err } } - if c.config.VerifyConnection != nil { + if c.config.VerifyConnection != nil && !echRejected { if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil { c.sendAlert(alertBadCertificate) return err @@ -1142,3 +1273,13 @@ func hostnameInSNI(name string) string { } return name } + +func computeAndUpdatePSK(m *clientHelloMsg, binderKey []byte, transcript hash.Hash, finishedHash func([]byte, hash.Hash) []byte) error { + helloBytes, err := m.marshalWithoutBinders() + if err != nil { + return err + } + transcript.Write(helloBytes) + pskBinders := [][]byte{finishedHash(binderKey, transcript)} + return m.updateBinders(pskBinders) +} diff --git a/contrib/go/_std_1.22/src/crypto/tls/handshake_client_tls13.go b/contrib/go/_std_1.23/src/crypto/tls/handshake_client_tls13.go similarity index 75% rename from contrib/go/_std_1.22/src/crypto/tls/handshake_client_tls13.go rename to contrib/go/_std_1.23/src/crypto/tls/handshake_client_tls13.go index 2f59f6888c5d..db5e35d9a46c 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/handshake_client_tls13.go +++ b/contrib/go/_std_1.23/src/crypto/tls/handshake_client_tls13.go @@ -8,20 +8,22 @@ import ( "bytes" "context" "crypto" - "crypto/ecdh" "crypto/hmac" + "crypto/internal/mlkem768" "crypto/rsa" + "crypto/subtle" "errors" "hash" + "slices" "time" ) type clientHandshakeStateTLS13 struct { - c *Conn - ctx context.Context - serverHello *serverHelloMsg - hello *clientHelloMsg - ecdheKey *ecdh.PrivateKey + c *Conn + ctx context.Context + serverHello *serverHelloMsg + hello *clientHelloMsg + keyShareKeys *keySharePrivateKeys session *SessionState earlySecret []byte @@ -34,9 +36,11 @@ type clientHandshakeStateTLS13 struct { transcript hash.Hash masterSecret []byte trafficSecret []byte // client_application_traffic_secret_0 + + echContext *echContext } -// handshake requires hs.c, hs.hello, hs.serverHello, hs.ecdheKey, and, +// handshake requires hs.c, hs.hello, hs.serverHello, hs.keyShareKeys, and, // optionally, hs.session, hs.earlySecret and hs.binderKey to be set. func (hs *clientHandshakeStateTLS13) handshake() error { c := hs.c @@ -53,7 +57,7 @@ func (hs *clientHandshakeStateTLS13) handshake() error { } // Consistency check on the presence of a keyShare and its parameters. - if hs.ecdheKey == nil || len(hs.hello.keyShares) != 1 { + if hs.keyShareKeys == nil || hs.keyShareKeys.ecdhe == nil || len(hs.hello.keyShares) == 0 { return c.sendAlert(alertInternalError) } @@ -67,6 +71,13 @@ func (hs *clientHandshakeStateTLS13) handshake() error { return err } + if hs.echContext != nil { + hs.echContext.innerTranscript = hs.suite.hash.New() + if err := transcriptMsg(hs.echContext.innerHello, hs.echContext.innerTranscript); err != nil { + return err + } + } + if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) { if err := hs.sendDummyChangeCipherSpec(); err != nil { return err @@ -76,6 +87,41 @@ func (hs *clientHandshakeStateTLS13) handshake() error { } } + var echRetryConfigList []byte + if hs.echContext != nil { + confTranscript := cloneHash(hs.echContext.innerTranscript, hs.suite.hash) + confTranscript.Write(hs.serverHello.original[:30]) + confTranscript.Write(make([]byte, 8)) + confTranscript.Write(hs.serverHello.original[38:]) + acceptConfirmation := hs.suite.expandLabel( + hs.suite.extract(hs.echContext.innerHello.random, nil), + "ech accept confirmation", + confTranscript.Sum(nil), + 8, + ) + if subtle.ConstantTimeCompare(acceptConfirmation, hs.serverHello.random[len(hs.serverHello.random)-8:]) == 1 { + hs.hello = hs.echContext.innerHello + c.serverName = c.config.ServerName + hs.transcript = hs.echContext.innerTranscript + c.echAccepted = true + + if hs.serverHello.encryptedClientHello != nil { + c.sendAlert(alertUnsupportedExtension) + return errors.New("tls: unexpected encrypted_client_hello extension in server hello despite ECH being accepted") + } + + if hs.hello.serverName == "" && hs.serverHello.serverNameAck { + c.sendAlert(alertUnsupportedExtension) + return errors.New("tls: unexpected server_name extension in server hello") + } + } else { + hs.echContext.echRejected = true + // If the server sent us retry configs, we'll return these to + // the user so they can update their Config. + echRetryConfigList = hs.serverHello.encryptedClientHello + } + } + if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil { return err } @@ -109,6 +155,11 @@ func (hs *clientHandshakeStateTLS13) handshake() error { return err } + if hs.echContext != nil && hs.echContext.echRejected { + c.sendAlert(alertECHRequired) + return &ECHRejectionError{echRetryConfigList} + } + c.isHandshakeComplete.Store(true) return nil @@ -200,6 +251,48 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { return err } + var isInnerHello bool + hello := hs.hello + if hs.echContext != nil { + chHash = hs.echContext.innerTranscript.Sum(nil) + hs.echContext.innerTranscript.Reset() + hs.echContext.innerTranscript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) + hs.echContext.innerTranscript.Write(chHash) + + if hs.serverHello.encryptedClientHello != nil { + if len(hs.serverHello.encryptedClientHello) != 8 { + hs.c.sendAlert(alertDecodeError) + return errors.New("tls: malformed encrypted client hello extension") + } + + confTranscript := cloneHash(hs.echContext.innerTranscript, hs.suite.hash) + hrrHello := make([]byte, len(hs.serverHello.original)) + copy(hrrHello, hs.serverHello.original) + hrrHello = bytes.Replace(hrrHello, hs.serverHello.encryptedClientHello, make([]byte, 8), 1) + confTranscript.Write(hrrHello) + acceptConfirmation := hs.suite.expandLabel( + hs.suite.extract(hs.echContext.innerHello.random, nil), + "hrr ech accept confirmation", + confTranscript.Sum(nil), + 8, + ) + if subtle.ConstantTimeCompare(acceptConfirmation, hs.serverHello.encryptedClientHello) == 1 { + hello = hs.echContext.innerHello + c.serverName = c.config.ServerName + isInnerHello = true + c.echAccepted = true + } + } + + if err := transcriptMsg(hs.serverHello, hs.echContext.innerTranscript); err != nil { + return err + } + } else if hs.serverHello.encryptedClientHello != nil { + // Unsolicited ECH extension should be rejected + c.sendAlert(alertUnsupportedExtension) + return errors.New("tls: unexpected ECH extension in serverHello") + } + // The only HelloRetryRequest extensions we support are key_share and // cookie, and clients must abort the handshake if the HRR would not result // in any change in the ClientHello. @@ -209,7 +302,7 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { } if hs.serverHello.cookie != nil { - hs.hello.cookie = hs.serverHello.cookie + hello.cookie = hs.serverHello.cookie } if hs.serverHello.serverShare.group != 0 { @@ -221,21 +314,22 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { // a group we advertised but did not send a key share for, and send a key // share for it this time. if curveID := hs.serverHello.selectedGroup; curveID != 0 { - curveOK := false - for _, id := range hs.hello.supportedCurves { - if id == curveID { - curveOK = true - break - } - } - if !curveOK { + if !slices.Contains(hello.supportedCurves, curveID) { c.sendAlert(alertIllegalParameter) return errors.New("tls: server selected unsupported group") } - if sentID, _ := curveIDForCurve(hs.ecdheKey.Curve()); sentID == curveID { + if slices.ContainsFunc(hs.hello.keyShares, func(ks keyShare) bool { + return ks.group == curveID + }) { c.sendAlert(alertIllegalParameter) return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share") } + // Note: we don't support selecting X25519Kyber768Draft00 in a HRR, + // because we currently only support it at all when CurvePreferences is + // empty, which will cause us to also send a key share for it. + // + // This will have to change once we support selecting hybrid KEMs + // without sending key shares for them. if _, ok := curveForCurveID(curveID); !ok { c.sendAlert(alertInternalError) return errors.New("tls: CurvePreferences includes unsupported curve") @@ -245,12 +339,11 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { c.sendAlert(alertInternalError) return err } - hs.ecdheKey = key - hs.hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}} + hs.keyShareKeys = &keySharePrivateKeys{curveID: curveID, ecdhe: key} + hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}} } - hs.hello.raw = nil - if len(hs.hello.pskIdentities) > 0 { + if len(hello.pskIdentities) > 0 { pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite) if pskSuite == nil { return c.sendAlert(alertInternalError) @@ -258,7 +351,7 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { if pskSuite.hash == hs.suite.hash { // Update binders and obfuscated_ticket_age. ticketAge := c.config.time().Sub(time.Unix(int64(hs.session.createdAt), 0)) - hs.hello.pskIdentities[0].obfuscatedTicketAge = uint32(ticketAge/time.Millisecond) + hs.session.ageAdd + hello.pskIdentities[0].obfuscatedTicketAge = uint32(ticketAge/time.Millisecond) + hs.session.ageAdd transcript := hs.suite.hash.New() transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))}) @@ -266,27 +359,40 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { if err := transcriptMsg(hs.serverHello, transcript); err != nil { return err } - helloBytes, err := hs.hello.marshalWithoutBinders() - if err != nil { - return err - } - transcript.Write(helloBytes) - pskBinders := [][]byte{hs.suite.finishedHash(hs.binderKey, transcript)} - if err := hs.hello.updateBinders(pskBinders); err != nil { + + if err := computeAndUpdatePSK(hello, hs.binderKey, transcript, hs.suite.finishedHash); err != nil { return err } } else { // Server selected a cipher suite incompatible with the PSK. - hs.hello.pskIdentities = nil - hs.hello.pskBinders = nil + hello.pskIdentities = nil + hello.pskBinders = nil } } - if hs.hello.earlyData { - hs.hello.earlyData = false + if hello.earlyData { + hello.earlyData = false c.quicRejectedEarlyData() } + if isInnerHello { + // Any extensions which have changed in hello, but are mirrored in the + // outer hello and compressed, need to be copied to the outer hello, so + // they can be properly decompressed by the server. For now, the only + // extension which may have changed is keyShares. + hs.hello.keyShares = hello.keyShares + hs.echContext.innerHello = hello + if err := transcriptMsg(hs.echContext.innerHello, hs.echContext.innerTranscript); err != nil { + return err + } + + if err := computeAndUpdateOuterECHExtension(hs.hello, hs.echContext.innerHello, hs.echContext, false); err != nil { + return err + } + } else { + hs.hello = hello + } + if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil { return err } @@ -308,6 +414,7 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error { return err } + c.didHRR = true return nil } @@ -333,7 +440,9 @@ func (hs *clientHandshakeStateTLS13) processServerHello() error { c.sendAlert(alertIllegalParameter) return errors.New("tls: server did not send a key share") } - if sentID, _ := curveIDForCurve(hs.ecdheKey.Curve()); hs.serverHello.serverShare.group != sentID { + if !slices.ContainsFunc(hs.hello.keyShares, func(ks keyShare) bool { + return ks.group == hs.serverHello.serverShare.group + }) { c.sendAlert(alertIllegalParameter) return errors.New("tls: server selected unsupported group") } @@ -372,16 +481,37 @@ func (hs *clientHandshakeStateTLS13) processServerHello() error { func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error { c := hs.c - peerKey, err := hs.ecdheKey.Curve().NewPublicKey(hs.serverHello.serverShare.data) + ecdhePeerData := hs.serverHello.serverShare.data + if hs.serverHello.serverShare.group == x25519Kyber768Draft00 { + if len(ecdhePeerData) != x25519PublicKeySize+mlkem768.CiphertextSize { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: invalid server key share") + } + ecdhePeerData = hs.serverHello.serverShare.data[:x25519PublicKeySize] + } + peerKey, err := hs.keyShareKeys.ecdhe.Curve().NewPublicKey(ecdhePeerData) if err != nil { c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid server key share") } - sharedKey, err := hs.ecdheKey.ECDH(peerKey) + sharedKey, err := hs.keyShareKeys.ecdhe.ECDH(peerKey) if err != nil { c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid server key share") } + if hs.serverHello.serverShare.group == x25519Kyber768Draft00 { + if hs.keyShareKeys.kyber == nil { + return c.sendAlert(alertInternalError) + } + ciphertext := hs.serverHello.serverShare.data[x25519PublicKeySize:] + kyberShared, err := kyberDecapsulate(hs.keyShareKeys.kyber, ciphertext) + if err != nil { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: invalid Kyber server key share") + } + sharedKey = append(sharedKey, kyberShared...) + } + c.curveID = hs.serverHello.serverShare.group earlySecret := hs.earlySecret if !hs.usingPSK { @@ -478,6 +608,10 @@ func (hs *clientHandshakeStateTLS13) readServerParameters() error { return errors.New("tls: server accepted 0-RTT with the wrong ALPN") } } + if hs.echContext != nil && !hs.echContext.echRejected && encryptedExtensions.echRetryConfigs != nil { + c.sendAlert(alertUnsupportedExtension) + return errors.New("tls: server sent ECH retry configs after accepting ECH") + } return nil } @@ -631,6 +765,13 @@ func (hs *clientHandshakeStateTLS13) sendClientCertificate() error { return nil } + if hs.echContext != nil && hs.echContext.echRejected { + if _, err := hs.c.writeHandshakeRecord(&certificateMsgTLS13{}, hs.transcript); err != nil { + return err + } + return nil + } + cert, err := c.getClientCertificate(&CertificateRequestInfo{ AcceptableCAs: hs.certReq.certificateAuthorities, SignatureSchemes: hs.certReq.supportedSignatureAlgorithms, @@ -753,17 +894,17 @@ func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error { psk := cipherSuite.expandLabel(c.resumptionSecret, "resumption", msg.nonce, cipherSuite.hash.Size()) - session, err := c.sessionState() - if err != nil { - c.sendAlert(alertInternalError) - return err - } + session := c.sessionState() session.secret = psk session.useBy = uint64(c.config.time().Add(lifetime).Unix()) session.ageAdd = msg.ageAdd session.EarlyData = c.quic != nil && msg.maxEarlyData == 0xffffffff // RFC 9001, Section 4.6.1 - cs := &ClientSessionState{ticket: msg.label, session: session} - + session.ticket = msg.label + if c.quic != nil && c.quic.enableSessionEvents { + c.quicStoreSession(session) + return nil + } + cs := &ClientSessionState{session: session} if cacheKey := c.clientSessionCacheKey(); cacheKey != "" { c.config.ClientSessionCache.Put(cacheKey, cs) } diff --git a/contrib/go/_std_1.22/src/crypto/tls/handshake_messages.go b/contrib/go/_std_1.23/src/crypto/tls/handshake_messages.go similarity index 84% rename from contrib/go/_std_1.22/src/crypto/tls/handshake_messages.go rename to contrib/go/_std_1.23/src/crypto/tls/handshake_messages.go index a86055a06013..8620b66a4749 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/handshake_messages.go +++ b/contrib/go/_std_1.23/src/crypto/tls/handshake_messages.go @@ -7,6 +7,7 @@ package tls import ( "errors" "fmt" + "slices" "strings" "golang.org/x/crypto/cryptobyte" @@ -68,7 +69,7 @@ func readUint24LengthPrefixed(s *cryptobyte.String, out *[]byte) bool { } type clientHelloMsg struct { - raw []byte + original []byte vers uint16 random []byte sessionId []byte @@ -95,13 +96,10 @@ type clientHelloMsg struct { pskIdentities []pskIdentity pskBinders [][]byte quicTransportParameters []byte + encryptedClientHello []byte } -func (m *clientHelloMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - +func (m *clientHelloMsg) marshalMsg(echInner bool) ([]byte, error) { var exts cryptobyte.Builder if len(m.serverName) > 0 { // RFC 6066, Section 3 @@ -115,27 +113,7 @@ func (m *clientHelloMsg) marshal() ([]byte, error) { }) }) } - if m.ocspStapling { - // RFC 4366, Section 3.6 - exts.AddUint16(extensionStatusRequest) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddUint8(1) // status_type = ocsp - exts.AddUint16(0) // empty responder_id_list - exts.AddUint16(0) // empty request_extensions - }) - } - if len(m.supportedCurves) > 0 { - // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7 - exts.AddUint16(extensionSupportedCurves) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - for _, curve := range m.supportedCurves { - exts.AddUint16(uint16(curve)) - } - }) - }) - } - if len(m.supportedPoints) > 0 { + if len(m.supportedPoints) > 0 && !echInner { // RFC 4492, Section 5.1.2 exts.AddUint16(extensionSupportedPoints) exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { @@ -144,36 +122,14 @@ func (m *clientHelloMsg) marshal() ([]byte, error) { }) }) } - if m.ticketSupported { + if m.ticketSupported && !echInner { // RFC 5077, Section 3.2 exts.AddUint16(extensionSessionTicket) exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { exts.AddBytes(m.sessionTicket) }) } - if len(m.supportedSignatureAlgorithms) > 0 { - // RFC 5246, Section 7.4.1.4.1 - exts.AddUint16(extensionSignatureAlgorithms) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - for _, sigAlgo := range m.supportedSignatureAlgorithms { - exts.AddUint16(uint16(sigAlgo)) - } - }) - }) - } - if len(m.supportedSignatureAlgorithmsCert) > 0 { - // RFC 8446, Section 4.2.3 - exts.AddUint16(extensionSignatureAlgorithmsCert) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - for _, sigAlgo := range m.supportedSignatureAlgorithmsCert { - exts.AddUint16(uint16(sigAlgo)) - } - }) - }) - } - if m.secureRenegotiationSupported { + if m.secureRenegotiationSupported && !echInner { // RFC 5746, Section 3.2 exts.AddUint16(extensionRenegotiationInfo) exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { @@ -182,82 +138,181 @@ func (m *clientHelloMsg) marshal() ([]byte, error) { }) }) } - if m.extendedMasterSecret { + if m.extendedMasterSecret && !echInner { // RFC 7627 exts.AddUint16(extensionExtendedMasterSecret) exts.AddUint16(0) // empty extension_data } - if len(m.alpnProtocols) > 0 { - // RFC 7301, Section 3.1 - exts.AddUint16(extensionALPN) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - for _, proto := range m.alpnProtocols { - exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddBytes([]byte(proto)) - }) - } - }) - }) - } if m.scts { // RFC 6962, Section 3.3.1 exts.AddUint16(extensionSCT) exts.AddUint16(0) // empty extension_data } + if m.earlyData { + // RFC 8446, Section 4.2.10 + exts.AddUint16(extensionEarlyData) + exts.AddUint16(0) // empty extension_data + } + if m.quicTransportParameters != nil { // marshal zero-length parameters when present + // RFC 9001, Section 8.2 + exts.AddUint16(extensionQUICTransportParameters) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.quicTransportParameters) + }) + } + if len(m.encryptedClientHello) > 0 { + exts.AddUint16(extensionEncryptedClientHello) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.encryptedClientHello) + }) + } + // Note that any extension that can be compressed during ECH must be + // contiguous. If any additional extensions are to be compressed they must + // be added to the following block, so that they can be properly + // decompressed on the other side. + var echOuterExts []uint16 + if m.ocspStapling { + // RFC 4366, Section 3.6 + if echInner { + echOuterExts = append(echOuterExts, extensionStatusRequest) + } else { + exts.AddUint16(extensionStatusRequest) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8(1) // status_type = ocsp + exts.AddUint16(0) // empty responder_id_list + exts.AddUint16(0) // empty request_extensions + }) + } + } + if len(m.supportedCurves) > 0 { + // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7 + if echInner { + echOuterExts = append(echOuterExts, extensionSupportedCurves) + } else { + exts.AddUint16(extensionSupportedCurves) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, curve := range m.supportedCurves { + exts.AddUint16(uint16(curve)) + } + }) + }) + } + } + if len(m.supportedSignatureAlgorithms) > 0 { + // RFC 5246, Section 7.4.1.4.1 + if echInner { + echOuterExts = append(echOuterExts, extensionSignatureAlgorithms) + } else { + exts.AddUint16(extensionSignatureAlgorithms) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, sigAlgo := range m.supportedSignatureAlgorithms { + exts.AddUint16(uint16(sigAlgo)) + } + }) + }) + } + } + if len(m.supportedSignatureAlgorithmsCert) > 0 { + // RFC 8446, Section 4.2.3 + if echInner { + echOuterExts = append(echOuterExts, extensionSignatureAlgorithmsCert) + } else { + exts.AddUint16(extensionSignatureAlgorithmsCert) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, sigAlgo := range m.supportedSignatureAlgorithmsCert { + exts.AddUint16(uint16(sigAlgo)) + } + }) + }) + } + } + if len(m.alpnProtocols) > 0 { + // RFC 7301, Section 3.1 + if echInner { + echOuterExts = append(echOuterExts, extensionALPN) + } else { + exts.AddUint16(extensionALPN) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, proto := range m.alpnProtocols { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes([]byte(proto)) + }) + } + }) + }) + } + } if len(m.supportedVersions) > 0 { // RFC 8446, Section 4.2.1 - exts.AddUint16(extensionSupportedVersions) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { - for _, vers := range m.supportedVersions { - exts.AddUint16(vers) - } + if echInner { + echOuterExts = append(echOuterExts, extensionSupportedVersions) + } else { + exts.AddUint16(extensionSupportedVersions) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, vers := range m.supportedVersions { + exts.AddUint16(vers) + } + }) }) - }) + } } if len(m.cookie) > 0 { // RFC 8446, Section 4.2.2 - exts.AddUint16(extensionCookie) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + if echInner { + echOuterExts = append(echOuterExts, extensionCookie) + } else { + exts.AddUint16(extensionCookie) exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddBytes(m.cookie) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.cookie) + }) }) - }) + } } if len(m.keyShares) > 0 { // RFC 8446, Section 4.2.8 - exts.AddUint16(extensionKeyShare) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + if echInner { + echOuterExts = append(echOuterExts, extensionKeyShare) + } else { + exts.AddUint16(extensionKeyShare) exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - for _, ks := range m.keyShares { - exts.AddUint16(uint16(ks.group)) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddBytes(ks.data) - }) - } + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, ks := range m.keyShares { + exts.AddUint16(uint16(ks.group)) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(ks.data) + }) + } + }) }) - }) - } - if m.earlyData { - // RFC 8446, Section 4.2.10 - exts.AddUint16(extensionEarlyData) - exts.AddUint16(0) // empty extension_data + } } if len(m.pskModes) > 0 { // RFC 8446, Section 4.2.9 - exts.AddUint16(extensionPSKModes) - exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddBytes(m.pskModes) + if echInner { + echOuterExts = append(echOuterExts, extensionPSKModes) + } else { + exts.AddUint16(extensionPSKModes) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.pskModes) + }) }) - }) + } } - if m.quicTransportParameters != nil { // marshal zero-length parameters when present - // RFC 9001, Section 8.2 - exts.AddUint16(extensionQUICTransportParameters) + if len(echOuterExts) > 0 && echInner { + exts.AddUint16(extensionECHOuterExtensions) exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { - exts.AddBytes(m.quicTransportParameters) + exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) { + for _, e := range echOuterExts { + exts.AddUint16(e) + } + }) }) } if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension @@ -292,7 +347,9 @@ func (m *clientHelloMsg) marshal() ([]byte, error) { b.AddUint16(m.vers) addBytesWithLength(b, m.random, 32) b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(m.sessionId) + if !echInner { + b.AddBytes(m.sessionId) + } }) b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { for _, suite := range m.cipherSuites { @@ -310,8 +367,11 @@ func (m *clientHelloMsg) marshal() ([]byte, error) { } }) - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() +} + +func (m *clientHelloMsg) marshal() ([]byte, error) { + return m.marshalMsg(false) } // marshalWithoutBinders returns the ClientHello through the @@ -324,16 +384,21 @@ func (m *clientHelloMsg) marshalWithoutBinders() ([]byte, error) { bindersLen += len(binder) } - fullMessage, err := m.marshal() - if err != nil { - return nil, err + var fullMessage []byte + if m.original != nil { + fullMessage = m.original + } else { + var err error + fullMessage, err = m.marshal() + if err != nil { + return nil, err + } } return fullMessage[:len(fullMessage)-bindersLen], nil } -// updateBinders updates the m.pskBinders field, if necessary updating the -// cached marshaled representation. The supplied binders must have the same -// length as the current m.pskBinders. +// updateBinders updates the m.pskBinders field. The supplied binders must have +// the same length as the current m.pskBinders. func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) error { if len(pskBinders) != len(m.pskBinders) { return errors.New("tls: internal error: pskBinders length mismatch") @@ -344,30 +409,12 @@ func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) error { } } m.pskBinders = pskBinders - if m.raw != nil { - helloBytes, err := m.marshalWithoutBinders() - if err != nil { - return err - } - lenWithoutBinders := len(helloBytes) - b := cryptobyte.NewFixedBuilder(m.raw[:lenWithoutBinders]) - b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { - for _, binder := range m.pskBinders { - b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { - b.AddBytes(binder) - }) - } - }) - if out, err := b.Bytes(); err != nil || len(out) != len(m.raw) { - return errors.New("tls: internal error: failed to update binders") - } - } return nil } func (m *clientHelloMsg) unmarshal(data []byte) bool { - *m = clientHelloMsg{raw: data} + *m = clientHelloMsg{original: data} s := cryptobyte.String(data) if !s.Skip(4) || // message type and uint24 length field @@ -625,8 +672,45 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { return true } +func (m *clientHelloMsg) originalBytes() []byte { + return m.original +} + +func (m *clientHelloMsg) clone() *clientHelloMsg { + return &clientHelloMsg{ + original: slices.Clone(m.original), + vers: m.vers, + random: slices.Clone(m.random), + sessionId: slices.Clone(m.sessionId), + cipherSuites: slices.Clone(m.cipherSuites), + compressionMethods: slices.Clone(m.compressionMethods), + serverName: m.serverName, + ocspStapling: m.ocspStapling, + supportedCurves: slices.Clone(m.supportedCurves), + supportedPoints: slices.Clone(m.supportedPoints), + ticketSupported: m.ticketSupported, + sessionTicket: slices.Clone(m.sessionTicket), + supportedSignatureAlgorithms: slices.Clone(m.supportedSignatureAlgorithms), + supportedSignatureAlgorithmsCert: slices.Clone(m.supportedSignatureAlgorithmsCert), + secureRenegotiationSupported: m.secureRenegotiationSupported, + secureRenegotiation: slices.Clone(m.secureRenegotiation), + extendedMasterSecret: m.extendedMasterSecret, + alpnProtocols: slices.Clone(m.alpnProtocols), + scts: m.scts, + supportedVersions: slices.Clone(m.supportedVersions), + cookie: slices.Clone(m.cookie), + keyShares: slices.Clone(m.keyShares), + earlyData: m.earlyData, + pskModes: slices.Clone(m.pskModes), + pskIdentities: slices.Clone(m.pskIdentities), + pskBinders: slices.Clone(m.pskBinders), + quicTransportParameters: slices.Clone(m.quicTransportParameters), + encryptedClientHello: slices.Clone(m.encryptedClientHello), + } +} + type serverHelloMsg struct { - raw []byte + original []byte vers uint16 random []byte sessionId []byte @@ -644,6 +728,8 @@ type serverHelloMsg struct { selectedIdentityPresent bool selectedIdentity uint16 supportedPoints []uint8 + encryptedClientHello []byte + serverNameAck bool // HelloRetryRequest extensions cookie []byte @@ -651,10 +737,6 @@ type serverHelloMsg struct { } func (m *serverHelloMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var exts cryptobyte.Builder if m.ocspStapling { exts.AddUint16(extensionStatusRequest) @@ -742,6 +824,16 @@ func (m *serverHelloMsg) marshal() ([]byte, error) { }) }) } + if len(m.encryptedClientHello) > 0 { + exts.AddUint16(extensionEncryptedClientHello) + exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) { + exts.AddBytes(m.encryptedClientHello) + }) + } + if m.serverNameAck { + exts.AddUint16(extensionServerName) + exts.AddUint16(0) + } extBytes, err := exts.Bytes() if err != nil { @@ -766,12 +858,11 @@ func (m *serverHelloMsg) marshal() ([]byte, error) { } }) - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *serverHelloMsg) unmarshal(data []byte) bool { - *m = serverHelloMsg{raw: data} + *m = serverHelloMsg{original: data} s := cryptobyte.String(data) if !s.Skip(4) || // message type and uint24 length field @@ -875,6 +966,16 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { len(m.supportedPoints) == 0 { return false } + case extensionEncryptedClientHello: // encrypted_client_hello + m.encryptedClientHello = make([]byte, len(extData)) + if !extData.CopyBytes(m.encryptedClientHello) { + return false + } + case extensionServerName: + if len(extData) != 0 { + return false + } + m.serverNameAck = true default: // Ignore unknown extensions. continue @@ -888,18 +989,18 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { return true } +func (m *serverHelloMsg) originalBytes() []byte { + return m.original +} + type encryptedExtensionsMsg struct { - raw []byte alpnProtocol string quicTransportParameters []byte earlyData bool + echRetryConfigs []byte } func (m *encryptedExtensionsMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeEncryptedExtensions) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -926,16 +1027,20 @@ func (m *encryptedExtensionsMsg) marshal() ([]byte, error) { b.AddUint16(extensionEarlyData) b.AddUint16(0) // empty extension_data } + if len(m.echRetryConfigs) > 0 { + b.AddUint16(extensionEncryptedClientHello) + b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { + b.AddBytes(m.echRetryConfigs) + }) + } }) }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool { - *m = encryptedExtensionsMsg{raw: data} + *m = encryptedExtensionsMsg{} s := cryptobyte.String(data) var extensions cryptobyte.String @@ -972,6 +1077,11 @@ func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool { case extensionEarlyData: // RFC 8446, Section 4.2.10 m.earlyData = true + case extensionEncryptedClientHello: + m.echRetryConfigs = make([]byte, len(extData)) + if !extData.CopyBytes(m.echRetryConfigs) { + return false + } default: // Ignore unknown extensions. continue @@ -998,15 +1108,10 @@ func (m *endOfEarlyDataMsg) unmarshal(data []byte) bool { } type keyUpdateMsg struct { - raw []byte updateRequested bool } func (m *keyUpdateMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeKeyUpdate) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -1017,13 +1122,10 @@ func (m *keyUpdateMsg) marshal() ([]byte, error) { } }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *keyUpdateMsg) unmarshal(data []byte) bool { - m.raw = data s := cryptobyte.String(data) var updateRequested uint8 @@ -1043,7 +1145,6 @@ func (m *keyUpdateMsg) unmarshal(data []byte) bool { } type newSessionTicketMsgTLS13 struct { - raw []byte lifetime uint32 ageAdd uint32 nonce []byte @@ -1052,10 +1153,6 @@ type newSessionTicketMsgTLS13 struct { } func (m *newSessionTicketMsgTLS13) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeNewSessionTicket) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -1078,13 +1175,11 @@ func (m *newSessionTicketMsgTLS13) marshal() ([]byte, error) { }) }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool { - *m = newSessionTicketMsgTLS13{raw: data} + *m = newSessionTicketMsgTLS13{} s := cryptobyte.String(data) var extensions cryptobyte.String @@ -1125,7 +1220,6 @@ func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool { } type certificateRequestMsgTLS13 struct { - raw []byte ocspStapling bool scts bool supportedSignatureAlgorithms []SignatureScheme @@ -1134,10 +1228,6 @@ type certificateRequestMsgTLS13 struct { } func (m *certificateRequestMsgTLS13) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeCertificateRequest) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -1194,13 +1284,11 @@ func (m *certificateRequestMsgTLS13) marshal() ([]byte, error) { }) }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool { - *m = certificateRequestMsgTLS13{raw: data} + *m = certificateRequestMsgTLS13{} s := cryptobyte.String(data) var context, extensions cryptobyte.String @@ -1276,15 +1364,10 @@ func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool { } type certificateMsg struct { - raw []byte certificates [][]byte } func (m *certificateMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var i int for _, slice := range m.certificates { i += len(slice) @@ -1311,8 +1394,7 @@ func (m *certificateMsg) marshal() ([]byte, error) { y = y[3+len(slice):] } - m.raw = x - return m.raw, nil + return x, nil } func (m *certificateMsg) unmarshal(data []byte) bool { @@ -1320,7 +1402,6 @@ func (m *certificateMsg) unmarshal(data []byte) bool { return false } - m.raw = data certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6]) if uint32(len(data)) != certsLen+7 { return false @@ -1353,17 +1434,12 @@ func (m *certificateMsg) unmarshal(data []byte) bool { } type certificateMsgTLS13 struct { - raw []byte certificate Certificate ocspStapling bool scts bool } func (m *certificateMsgTLS13) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeCertificate) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -1379,9 +1455,7 @@ func (m *certificateMsgTLS13) marshal() ([]byte, error) { marshalCertificate(b, certificate) }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) { @@ -1422,7 +1496,7 @@ func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) { } func (m *certificateMsgTLS13) unmarshal(data []byte) bool { - *m = certificateMsgTLS13{raw: data} + *m = certificateMsgTLS13{} s := cryptobyte.String(data) var context cryptobyte.String @@ -1500,14 +1574,10 @@ func unmarshalCertificate(s *cryptobyte.String, certificate *Certificate) bool { } type serverKeyExchangeMsg struct { - raw []byte key []byte } func (m *serverKeyExchangeMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } length := len(m.key) x := make([]byte, length+4) x[0] = typeServerKeyExchange @@ -1516,12 +1586,10 @@ func (m *serverKeyExchangeMsg) marshal() ([]byte, error) { x[3] = uint8(length) copy(x[4:], m.key) - m.raw = x return x, nil } func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool { - m.raw = data if len(data) < 4 { return false } @@ -1530,15 +1598,10 @@ func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool { } type certificateStatusMsg struct { - raw []byte response []byte } func (m *certificateStatusMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeCertificateStatus) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -1548,13 +1611,10 @@ func (m *certificateStatusMsg) marshal() ([]byte, error) { }) }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *certificateStatusMsg) unmarshal(data []byte) bool { - m.raw = data s := cryptobyte.String(data) var statusType uint8 @@ -1580,14 +1640,10 @@ func (m *serverHelloDoneMsg) unmarshal(data []byte) bool { } type clientKeyExchangeMsg struct { - raw []byte ciphertext []byte } func (m *clientKeyExchangeMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } length := len(m.ciphertext) x := make([]byte, length+4) x[0] = typeClientKeyExchange @@ -1596,12 +1652,10 @@ func (m *clientKeyExchangeMsg) marshal() ([]byte, error) { x[3] = uint8(length) copy(x[4:], m.ciphertext) - m.raw = x return x, nil } func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool { - m.raw = data if len(data) < 4 { return false } @@ -1614,28 +1668,20 @@ func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool { } type finishedMsg struct { - raw []byte verifyData []byte } func (m *finishedMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeFinished) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { b.AddBytes(m.verifyData) }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *finishedMsg) unmarshal(data []byte) bool { - m.raw = data s := cryptobyte.String(data) return s.Skip(1) && readUint24LengthPrefixed(&s, &m.verifyData) && @@ -1643,7 +1689,6 @@ func (m *finishedMsg) unmarshal(data []byte) bool { } type certificateRequestMsg struct { - raw []byte // hasSignatureAlgorithm indicates whether this message includes a list of // supported signature algorithms. This change was introduced with TLS 1.2. hasSignatureAlgorithm bool @@ -1654,10 +1699,6 @@ type certificateRequestMsg struct { } func (m *certificateRequestMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - // See RFC 4346, Section 7.4.4. length := 1 + len(m.certificateTypes) + 2 casLength := 0 @@ -1704,13 +1745,10 @@ func (m *certificateRequestMsg) marshal() ([]byte, error) { y = y[len(ca):] } - m.raw = x - return m.raw, nil + return x, nil } func (m *certificateRequestMsg) unmarshal(data []byte) bool { - m.raw = data - if len(data) < 5 { return false } @@ -1785,17 +1823,12 @@ func (m *certificateRequestMsg) unmarshal(data []byte) bool { } type certificateVerifyMsg struct { - raw []byte hasSignatureAlgorithm bool // format change introduced in TLS 1.2 signatureAlgorithm SignatureScheme signature []byte } func (m *certificateVerifyMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - var b cryptobyte.Builder b.AddUint8(typeCertificateVerify) b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) { @@ -1807,13 +1840,10 @@ func (m *certificateVerifyMsg) marshal() ([]byte, error) { }) }) - var err error - m.raw, err = b.Bytes() - return m.raw, err + return b.Bytes() } func (m *certificateVerifyMsg) unmarshal(data []byte) bool { - m.raw = data s := cryptobyte.String(data) if !s.Skip(4) { // message type and uint24 length field @@ -1828,15 +1858,10 @@ func (m *certificateVerifyMsg) unmarshal(data []byte) bool { } type newSessionTicketMsg struct { - raw []byte ticket []byte } func (m *newSessionTicketMsg) marshal() ([]byte, error) { - if m.raw != nil { - return m.raw, nil - } - // See RFC 5077, Section 3.3. ticketLen := len(m.ticket) length := 2 + 4 + ticketLen @@ -1849,14 +1874,10 @@ func (m *newSessionTicketMsg) marshal() ([]byte, error) { x[9] = uint8(ticketLen) copy(x[10:], m.ticket) - m.raw = x - - return m.raw, nil + return x, nil } func (m *newSessionTicketMsg) unmarshal(data []byte) bool { - m.raw = data - if len(data) < 10 { return false } @@ -1891,9 +1912,25 @@ type transcriptHash interface { Write([]byte) (int, error) } -// transcriptMsg is a helper used to marshal and hash messages which typically -// are not written to the wire, and as such aren't hashed during Conn.writeRecord. +// transcriptMsg is a helper used to hash messages which are not hashed when +// they are read from, or written to, the wire. This is typically the case for +// messages which are either not sent, or need to be hashed out of order from +// when they are read/written. +// +// For most messages, the message is marshalled using their marshal method, +// since their wire representation is idempotent. For clientHelloMsg and +// serverHelloMsg, we store the original wire representation of the message and +// use that for hashing, since unmarshal/marshal are not idempotent due to +// extension ordering and other malleable fields, which may cause differences +// between what was received and what we marshal. func transcriptMsg(msg handshakeMessage, h transcriptHash) error { + if msgWithOrig, ok := msg.(handshakeMessageWithOriginalBytes); ok { + if orig := msgWithOrig.originalBytes(); orig != nil { + h.Write(msgWithOrig.originalBytes()) + return nil + } + } + data, err := msg.marshal() if err != nil { return err diff --git a/contrib/go/_std_1.22/src/crypto/tls/handshake_server.go b/contrib/go/_std_1.23/src/crypto/tls/handshake_server.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/tls/handshake_server.go rename to contrib/go/_std_1.23/src/crypto/tls/handshake_server.go index 4e84aa9d8f0a..ac3d915d1746 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/handshake_server.go +++ b/contrib/go/_std_1.23/src/crypto/tls/handshake_server.go @@ -15,6 +15,7 @@ import ( "errors" "fmt" "hash" + "internal/byteorder" "io" "time" ) @@ -169,6 +170,7 @@ func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) { c.out.version = c.vers if c.config.MinVersion == 0 && c.vers < VersionTLS12 { + tls10server.Value() // ensure godebug is initialized tls10server.IncNonDefault() } @@ -246,7 +248,7 @@ func (hs *serverHandshakeState) processClientHello() error { hs.hello.scts = hs.cert.SignedCertificateTimestamps } - hs.ecdheOk = supportsECDHE(c.config, hs.clientHello.supportedCurves, hs.clientHello.supportedPoints) + hs.ecdheOk = supportsECDHE(c.config, c.vers, hs.clientHello.supportedCurves, hs.clientHello.supportedPoints) if hs.ecdheOk && len(hs.clientHello.supportedPoints) > 0 { // Although omitting the ec_point_formats extension is permitted, some @@ -317,10 +319,10 @@ func negotiateALPN(serverProtos, clientProtos []string, quic bool) (string, erro // supportsECDHE returns whether ECDHE key exchanges can be used with this // pre-TLS 1.3 client. -func supportsECDHE(c *Config, supportedCurves []CurveID, supportedPoints []uint8) bool { +func supportsECDHE(c *Config, version uint16, supportedCurves []CurveID, supportedPoints []uint8) bool { supportsCurve := false for _, curve := range supportedCurves { - if c.supportsCurve(curve) { + if c.supportsCurve(version, curve) { supportsCurve = true break } @@ -371,8 +373,13 @@ func (hs *serverHandshakeState) pickCipherSuite() error { c.cipherSuite = hs.suite.id if c.config.CipherSuites == nil && !needFIPS() && rsaKexCiphers[hs.suite.id] { + tlsrsakex.Value() // ensure godebug is initialized tlsrsakex.IncNonDefault() } + if c.config.CipherSuites == nil && !needFIPS() && tdesCiphers[hs.suite.id] { + tls3des.Value() // ensure godebug is initialized + tls3des.IncNonDefault() + } for _, id := range hs.clientHello.cipherSuites { if id == TLS_FALLBACK_SCSV { @@ -585,6 +592,9 @@ func (hs *serverHandshakeState) doFullHandshake() error { return err } if skx != nil { + if len(skx.key) >= 3 && skx.key[0] == 3 /* named curve */ { + c.curveID = CurveID(byteorder.BeUint16(skx.key[1:])) + } if _, err := hs.c.writeHandshakeRecord(skx, &hs.finishedHash); err != nil { return err } @@ -810,10 +820,7 @@ func (hs *serverHandshakeState) sendSessionTicket() error { c := hs.c m := new(newSessionTicketMsg) - state, err := c.sessionState() - if err != nil { - return err - } + state := c.sessionState() state.secret = hs.masterSecret if hs.sessionState != nil { // If this is re-wrapping an old key, then keep @@ -821,6 +828,7 @@ func (hs *serverHandshakeState) sendSessionTicket() error { state.createdAt = hs.sessionState.createdAt } if c.config.WrapSession != nil { + var err error m.ticket, err = c.config.WrapSession(c.connectionStateLocked(), state) if err != nil { return err diff --git a/contrib/go/_std_1.22/src/crypto/tls/handshake_server_tls13.go b/contrib/go/_std_1.23/src/crypto/tls/handshake_server_tls13.go similarity index 90% rename from contrib/go/_std_1.22/src/crypto/tls/handshake_server_tls13.go rename to contrib/go/_std_1.23/src/crypto/tls/handshake_server_tls13.go index 21d798de37db..503a732e0576 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/handshake_server_tls13.go +++ b/contrib/go/_std_1.23/src/crypto/tls/handshake_server_tls13.go @@ -9,11 +9,13 @@ import ( "context" "crypto" "crypto/hmac" + "crypto/internal/mlkem768" "crypto/rsa" - "encoding/binary" "errors" "hash" + "internal/byteorder" "io" + "slices" "time" ) @@ -177,25 +179,29 @@ func (hs *serverHandshakeStateTLS13) processClientHello() error { hs.hello.cipherSuite = hs.suite.id hs.transcript = hs.suite.hash.New() - // Pick the ECDHE group in server preference order, but give priority to - // groups with a key share, to avoid a HelloRetryRequest round-trip. + // Pick the key exchange method in server preference order, but give + // priority to key shares, to avoid a HelloRetryRequest round-trip. var selectedGroup CurveID var clientKeyShare *keyShare -GroupSelection: - for _, preferredGroup := range c.config.curvePreferences() { - for _, ks := range hs.clientHello.keyShares { - if ks.group == preferredGroup { - selectedGroup = ks.group - clientKeyShare = &ks - break GroupSelection + preferredGroups := c.config.curvePreferences(c.vers) + for _, preferredGroup := range preferredGroups { + ki := slices.IndexFunc(hs.clientHello.keyShares, func(ks keyShare) bool { + return ks.group == preferredGroup + }) + if ki != -1 { + clientKeyShare = &hs.clientHello.keyShares[ki] + selectedGroup = clientKeyShare.group + if !slices.Contains(hs.clientHello.supportedCurves, selectedGroup) { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: client sent key share for group it does not support") } + break } - if selectedGroup != 0 { - continue - } - for _, group := range hs.clientHello.supportedCurves { - if group == preferredGroup { - selectedGroup = group + } + if selectedGroup == 0 { + for _, preferredGroup := range preferredGroups { + if slices.Contains(hs.clientHello.supportedCurves, preferredGroup) { + selectedGroup = preferredGroup break } } @@ -205,23 +211,35 @@ GroupSelection: return errors.New("tls: no ECDHE curve supported by both client and server") } if clientKeyShare == nil { - if err := hs.doHelloRetryRequest(selectedGroup); err != nil { + ks, err := hs.doHelloRetryRequest(selectedGroup) + if err != nil { return err } - clientKeyShare = &hs.clientHello.keyShares[0] + clientKeyShare = ks } + c.curveID = selectedGroup - if _, ok := curveForCurveID(selectedGroup); !ok { + ecdhGroup := selectedGroup + ecdhData := clientKeyShare.data + if selectedGroup == x25519Kyber768Draft00 { + ecdhGroup = X25519 + if len(ecdhData) != x25519PublicKeySize+mlkem768.EncapsulationKeySize { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: invalid Kyber client key share") + } + ecdhData = ecdhData[:x25519PublicKeySize] + } + if _, ok := curveForCurveID(ecdhGroup); !ok { c.sendAlert(alertInternalError) return errors.New("tls: CurvePreferences includes unsupported curve") } - key, err := generateECDHEKey(c.config.rand(), selectedGroup) + key, err := generateECDHEKey(c.config.rand(), ecdhGroup) if err != nil { c.sendAlert(alertInternalError) return err } hs.hello.serverShare = keyShare{group: selectedGroup, data: key.PublicKey().Bytes()} - peerKey, err := key.Curve().NewPublicKey(clientKeyShare.data) + peerKey, err := key.Curve().NewPublicKey(ecdhData) if err != nil { c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid client key share") @@ -231,6 +249,15 @@ GroupSelection: c.sendAlert(alertIllegalParameter) return errors.New("tls: invalid client key share") } + if selectedGroup == x25519Kyber768Draft00 { + ciphertext, kyberShared, err := kyberEncapsulate(clientKeyShare.data[x25519PublicKeySize:]) + if err != nil { + c.sendAlert(alertIllegalParameter) + return errors.New("tls: invalid Kyber client key share") + } + hs.sharedKey = append(hs.sharedKey, kyberShared...) + hs.hello.serverShare.data = append(hs.hello.serverShare.data, ciphertext...) + } selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols, c.quic != nil) if err != nil { @@ -350,6 +377,12 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error { continue } + if c.quic != nil && c.quic.enableSessionEvents { + if err := c.quicResumeSession(sessionState); err != nil { + return err + } + } + hs.earlySecret = hs.suite.extract(sessionState.secret, nil) binderKey := hs.suite.deriveSecret(hs.earlySecret, resumptionBinderLabel, nil) // Clone the transcript in case a HelloRetryRequest was recorded. @@ -474,13 +507,13 @@ func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error { return hs.c.writeChangeCipherRecord() } -func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error { +func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) (*keyShare, error) { c := hs.c // The first ClientHello gets double-hashed into the transcript upon a // HelloRetryRequest. See RFC 8446, Section 4.4.1. if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil { - return err + return nil, err } chHash := hs.transcript.Sum(nil) hs.transcript.Reset() @@ -498,42 +531,49 @@ func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) } if _, err := hs.c.writeHandshakeRecord(helloRetryRequest, hs.transcript); err != nil { - return err + return nil, err } if err := hs.sendDummyChangeCipherSpec(); err != nil { - return err + return nil, err } // clientHelloMsg is not included in the transcript. msg, err := c.readHandshake(nil) if err != nil { - return err + return nil, err } clientHello, ok := msg.(*clientHelloMsg) if !ok { c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(clientHello, msg) + return nil, unexpectedMessageError(clientHello, msg) + } + + if len(clientHello.keyShares) != 1 { + c.sendAlert(alertIllegalParameter) + return nil, errors.New("tls: client didn't send one key share in second ClientHello") } + ks := &clientHello.keyShares[0] - if len(clientHello.keyShares) != 1 || clientHello.keyShares[0].group != selectedGroup { + if ks.group != selectedGroup { c.sendAlert(alertIllegalParameter) - return errors.New("tls: client sent invalid key share in second ClientHello") + return nil, errors.New("tls: client sent unexpected key share in second ClientHello") } if clientHello.earlyData { c.sendAlert(alertIllegalParameter) - return errors.New("tls: client indicated early data in second ClientHello") + return nil, errors.New("tls: client indicated early data in second ClientHello") } if illegalClientHelloChange(clientHello, hs.clientHello) { c.sendAlert(alertIllegalParameter) - return errors.New("tls: client illegally modified second ClientHello") + return nil, errors.New("tls: client illegally modified second ClientHello") } + c.didHRR = true hs.clientHello = clientHello - return nil + return ks, nil } // illegalClientHelloChange reports whether the two ClientHello messages are @@ -822,10 +862,10 @@ func (hs *serverHandshakeStateTLS13) sendSessionTickets() error { if !hs.shouldSendSessionTickets() { return nil } - return c.sendSessionTicket(false) + return c.sendSessionTicket(false, nil) } -func (c *Conn) sendSessionTicket(earlyData bool) error { +func (c *Conn) sendSessionTicket(earlyData bool, extra [][]byte) error { suite := cipherSuiteTLS13ByID(c.cipherSuite) if suite == nil { return errors.New("tls: internal error: unknown cipher suite") @@ -837,13 +877,12 @@ func (c *Conn) sendSessionTicket(earlyData bool) error { m := new(newSessionTicketMsgTLS13) - state, err := c.sessionState() - if err != nil { - return err - } + state := c.sessionState() state.secret = psk state.EarlyData = earlyData + state.Extra = extra if c.config.WrapSession != nil { + var err error m.label, err = c.config.WrapSession(c.connectionStateLocked(), state) if err != nil { return err @@ -865,11 +904,10 @@ func (c *Conn) sendSessionTicket(earlyData bool) error { // The value is not stored anywhere; we never need to check the ticket age // because 0-RTT is not supported. ageAdd := make([]byte, 4) - _, err = c.config.rand().Read(ageAdd) - if err != nil { + if _, err := c.config.rand().Read(ageAdd); err != nil { return err } - m.ageAdd = binary.LittleEndian.Uint32(ageAdd) + m.ageAdd = byteorder.LeUint32(ageAdd) if earlyData { // RFC 9001, Section 4.6.1 diff --git a/contrib/go/_std_1.22/src/crypto/tls/key_agreement.go b/contrib/go/_std_1.23/src/crypto/tls/key_agreement.go similarity index 97% rename from contrib/go/_std_1.22/src/crypto/tls/key_agreement.go rename to contrib/go/_std_1.23/src/crypto/tls/key_agreement.go index 2c8c5b8d7713..3e96242b9798 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/key_agreement.go +++ b/contrib/go/_std_1.23/src/crypto/tls/key_agreement.go @@ -16,8 +16,8 @@ import ( "io" ) -// a keyAgreement implements the client and server side of a TLS key agreement -// protocol by generating and processing key exchange messages. +// A keyAgreement implements the client and server side of a TLS 1.0–1.2 key +// agreement protocol by generating and processing key exchange messages. type keyAgreement interface { // On the server side, the first two methods are called in order. @@ -126,7 +126,7 @@ func md5SHA1Hash(slices [][]byte) []byte { } // hashForServerKeyExchange hashes the given slices and returns their digest -// using the given hash function (for >= TLS 1.2) or using a default based on +// using the given hash function (for TLS 1.2) or using a default based on // the sigType (for earlier TLS versions). For Ed25519 signatures, which don't // do pre-hashing, it returns the concatenation of the slices. func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) []byte { @@ -169,7 +169,7 @@ type ecdheKeyAgreement struct { func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { var curveID CurveID for _, c := range clientHello.supportedCurves { - if config.supportsCurve(c) { + if config.supportsCurve(ka.version, c) { curveID = c break } diff --git a/contrib/go/_std_1.22/src/crypto/tls/key_schedule.go b/contrib/go/_std_1.23/src/crypto/tls/key_schedule.go similarity index 82% rename from contrib/go/_std_1.22/src/crypto/tls/key_schedule.go rename to contrib/go/_std_1.23/src/crypto/tls/key_schedule.go index d7f082c9ee1e..1636baf79e72 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/key_schedule.go +++ b/contrib/go/_std_1.23/src/crypto/tls/key_schedule.go @@ -7,6 +7,7 @@ package tls import ( "crypto/ecdh" "crypto/hmac" + "crypto/internal/mlkem768" "errors" "fmt" "hash" @@ -14,6 +15,7 @@ import ( "golang.org/x/crypto/cryptobyte" "golang.org/x/crypto/hkdf" + "golang.org/x/crypto/sha3" ) // This file contains the functions necessary to compute the TLS 1.3 key @@ -117,6 +119,45 @@ func (c *cipherSuiteTLS13) exportKeyingMaterial(masterSecret []byte, transcript } } +type keySharePrivateKeys struct { + curveID CurveID + ecdhe *ecdh.PrivateKey + kyber *mlkem768.DecapsulationKey +} + +// kyberDecapsulate implements decapsulation according to Kyber Round 3. +func kyberDecapsulate(dk *mlkem768.DecapsulationKey, c []byte) ([]byte, error) { + K, err := mlkem768.Decapsulate(dk, c) + if err != nil { + return nil, err + } + return kyberSharedSecret(K, c), nil +} + +// kyberEncapsulate implements encapsulation according to Kyber Round 3. +func kyberEncapsulate(ek []byte) (c, ss []byte, err error) { + c, ss, err = mlkem768.Encapsulate(ek) + if err != nil { + return nil, nil, err + } + return c, kyberSharedSecret(ss, c), nil +} + +func kyberSharedSecret(K, c []byte) []byte { + // Package mlkem768 implements ML-KEM, which compared to Kyber removed a + // final hashing step. Compute SHAKE-256(K || SHA3-256(c), 32) to match Kyber. + // See https://words.filippo.io/mlkem768/#bonus-track-using-a-ml-kem-implementation-as-kyber-v3. + h := sha3.NewShake256() + h.Write(K) + ch := sha3.Sum256(c) + h.Write(ch[:]) + out := make([]byte, 32) + h.Read(out) + return out +} + +const x25519PublicKeySize = 32 + // generateECDHEKey returns a PrivateKey that implements Diffie-Hellman // according to RFC 8446, Section 4.2.8.2. func generateECDHEKey(rand io.Reader, curveID CurveID) (*ecdh.PrivateKey, error) { diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/constants.go b/contrib/go/_std_1.23/src/crypto/tls/notboring.go similarity index 68% rename from contrib/go/_std_1.22/src/internal/syscall/unix/constants.go rename to contrib/go/_std_1.23/src/crypto/tls/notboring.go index e3245897055c..bdbc32e05b35 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/constants.go +++ b/contrib/go/_std_1.23/src/crypto/tls/notboring.go @@ -2,12 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build unix +//go:build !boringcrypto -package unix +package tls -const ( - R_OK = 0x4 - W_OK = 0x2 - X_OK = 0x1 -) +func needFIPS() bool { return false } diff --git a/contrib/go/_std_1.22/src/crypto/tls/prf.go b/contrib/go/_std_1.23/src/crypto/tls/prf.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/tls/prf.go rename to contrib/go/_std_1.23/src/crypto/tls/prf.go diff --git a/contrib/go/_std_1.22/src/crypto/tls/quic.go b/contrib/go/_std_1.23/src/crypto/tls/quic.go similarity index 80% rename from contrib/go/_std_1.22/src/crypto/tls/quic.go rename to contrib/go/_std_1.23/src/crypto/tls/quic.go index 3518169bf729..9dd6168b6235 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/quic.go +++ b/contrib/go/_std_1.23/src/crypto/tls/quic.go @@ -49,6 +49,13 @@ type QUICConn struct { // A QUICConfig configures a [QUICConn]. type QUICConfig struct { TLSConfig *Config + + // EnableSessionEvents may be set to true to enable the + // [QUICStoreSession] and [QUICResumeSession] events for client connections. + // When this event is enabled, sessions are not automatically + // stored in the client session cache. + // The application should use [QUICConn.StoreSession] to store sessions. + EnableSessionEvents bool } // A QUICEventKind is a type of operation on a QUIC connection. @@ -87,10 +94,29 @@ const ( // QUICRejectedEarlyData indicates that the server rejected 0-RTT data even // if we offered it. It's returned before QUICEncryptionLevelApplication // keys are returned. + // This event only occurs on client connections. QUICRejectedEarlyData // QUICHandshakeDone indicates that the TLS handshake has completed. QUICHandshakeDone + + // QUICResumeSession indicates that a client is attempting to resume a previous session. + // [QUICEvent.SessionState] is set. + // + // For client connections, this event occurs when the session ticket is selected. + // For server connections, this event occurs when receiving the client's session ticket. + // + // The application may set [QUICEvent.SessionState.EarlyData] to false before the + // next call to [QUICConn.NextEvent] to decline 0-RTT even if the session supports it. + QUICResumeSession + + // QUICStoreSession indicates that the server has provided state permitting + // the client to resume the session. + // [QUICEvent.SessionState] is set. + // The application should use [QUICConn.StoreSession] session to store the [SessionState]. + // The application may modify the [SessionState] before storing it. + // This event only occurs on client connections. + QUICStoreSession ) // A QUICEvent is an event occurring on a QUIC connection. @@ -109,6 +135,9 @@ type QUICEvent struct { // Set for QUICSetReadSecret and QUICSetWriteSecret. Suite uint16 + + // Set for QUICResumeSession and QUICStoreSession. + SessionState *SessionState } type quicState struct { @@ -127,12 +156,16 @@ type quicState struct { cancelc <-chan struct{} // handshake has been canceled cancel context.CancelFunc + waitingForDrain bool + // readbuf is shared between HandleData and the handshake goroutine. // HandshakeCryptoData passes ownership to the handshake goroutine by // reading from signalc, and reclaims ownership by reading from blockedc. readbuf []byte transportParams []byte // to send to the peer + + enableSessionEvents bool } // QUICClient returns a new TLS client side connection using QUICTransport as the @@ -140,7 +173,7 @@ type quicState struct { // // The config's MinVersion must be at least TLS 1.3. func QUICClient(config *QUICConfig) *QUICConn { - return newQUICConn(Client(nil, config.TLSConfig)) + return newQUICConn(Client(nil, config.TLSConfig), config) } // QUICServer returns a new TLS server side connection using QUICTransport as the @@ -148,13 +181,14 @@ func QUICClient(config *QUICConfig) *QUICConn { // // The config's MinVersion must be at least TLS 1.3. func QUICServer(config *QUICConfig) *QUICConn { - return newQUICConn(Server(nil, config.TLSConfig)) + return newQUICConn(Server(nil, config.TLSConfig), config) } -func newQUICConn(conn *Conn) *QUICConn { +func newQUICConn(conn *Conn, config *QUICConfig) *QUICConn { conn.quic = &quicState{ - signalc: make(chan struct{}), - blockedc: make(chan struct{}), + signalc: make(chan struct{}), + blockedc: make(chan struct{}), + enableSessionEvents: config.EnableSessionEvents, } conn.quic.events = conn.quic.eventArr[:0] return &QUICConn{ @@ -190,6 +224,11 @@ func (q *QUICConn) NextEvent() QUICEvent { // to catch callers erroniously retaining it. qs.events[last].Data[0] = 0 } + if qs.nextEvent >= len(qs.events) && qs.waitingForDrain { + qs.waitingForDrain = false + <-qs.signalc + <-qs.blockedc + } if qs.nextEvent >= len(qs.events) { qs.events = qs.events[:0] qs.nextEvent = 0 @@ -255,6 +294,7 @@ func (q *QUICConn) HandleData(level QUICEncryptionLevel, data []byte) error { type QUICSessionTicketOptions struct { // EarlyData specifies whether the ticket may be used for 0-RTT. EarlyData bool + Extra [][]byte } // SendSessionTicket sends a session ticket to the client. @@ -272,7 +312,25 @@ func (q *QUICConn) SendSessionTicket(opts QUICSessionTicketOptions) error { return quicError(errors.New("tls: SendSessionTicket called multiple times")) } q.sessionTicketSent = true - return quicError(c.sendSessionTicket(opts.EarlyData)) + return quicError(c.sendSessionTicket(opts.EarlyData, opts.Extra)) +} + +// StoreSession stores a session previously received in a QUICStoreSession event +// in the ClientSessionCache. +// The application may process additional events or modify the SessionState +// before storing the session. +func (q *QUICConn) StoreSession(session *SessionState) error { + c := q.conn + if !c.isClient { + return quicError(errors.New("tls: StoreSessionTicket called on the server")) + } + cacheKey := c.clientSessionCacheKey() + if cacheKey == "" { + return nil + } + cs := &ClientSessionState{session: session} + c.config.ClientSessionCache.Put(cacheKey, cs) + return nil } // ConnectionState returns basic TLS details about the connection. @@ -356,6 +414,27 @@ func (c *Conn) quicWriteCryptoData(level QUICEncryptionLevel, data []byte) { last.Data = append(last.Data, data...) } +func (c *Conn) quicResumeSession(session *SessionState) error { + c.quic.events = append(c.quic.events, QUICEvent{ + Kind: QUICResumeSession, + SessionState: session, + }) + c.quic.waitingForDrain = true + for c.quic.waitingForDrain { + if err := c.quicWaitForSignal(); err != nil { + return err + } + } + return nil +} + +func (c *Conn) quicStoreSession(session *SessionState) { + c.quic.events = append(c.quic.events, QUICEvent{ + Kind: QUICStoreSession, + SessionState: session, + }) +} + func (c *Conn) quicSetTransportParameters(params []byte) { c.quic.events = append(c.quic.events, QUICEvent{ Kind: QUICTransportParameters, diff --git a/contrib/go/_std_1.22/src/crypto/tls/ticket.go b/contrib/go/_std_1.23/src/crypto/tls/ticket.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/tls/ticket.go rename to contrib/go/_std_1.23/src/crypto/tls/ticket.go index b71e3afdb211..06aec5aa63f9 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/ticket.go +++ b/contrib/go/_std_1.23/src/crypto/tls/ticket.go @@ -96,6 +96,7 @@ type SessionState struct { // Client-side TLS 1.3-only fields. useBy uint64 // seconds since UNIX epoch ageAdd uint32 + ticket []byte } // Bytes encodes the session, including any private fields, so that it can be @@ -289,7 +290,7 @@ func ParseSessionState(data []byte) (*SessionState, error) { // sessionState returns a partially filled-out [SessionState] with information // from the current connection. -func (c *Conn) sessionState() (*SessionState, error) { +func (c *Conn) sessionState() *SessionState { return &SessionState{ version: c.vers, cipherSuite: c.cipherSuite, @@ -302,7 +303,7 @@ func (c *Conn) sessionState() (*SessionState, error) { isClient: c.isClient, extMasterSecret: c.extMasterSecret, verifiedChains: c.verifiedChains, - }, nil + } } // EncryptTicket encrypts a ticket with the [Config]'s configured (or default) @@ -396,7 +397,6 @@ func (c *Config) decryptTicket(encrypted []byte, ticketKeys []ticketKey) []byte // ClientSessionState contains the state needed by a client to // resume a previous TLS session. type ClientSessionState struct { - ticket []byte session *SessionState } @@ -406,7 +406,10 @@ type ClientSessionState struct { // It can be called by [ClientSessionCache.Put] to serialize (with // [SessionState.Bytes]) and store the session. func (cs *ClientSessionState) ResumptionState() (ticket []byte, state *SessionState, err error) { - return cs.ticket, cs.session, nil + if cs == nil || cs.session == nil { + return nil, nil, nil + } + return cs.session.ticket, cs.session, nil } // NewResumptionState returns a state value that can be returned by @@ -415,7 +418,8 @@ func (cs *ClientSessionState) ResumptionState() (ticket []byte, state *SessionSt // state needs to be returned by [ParseSessionState], and the ticket and session // state must have been returned by [ClientSessionState.ResumptionState]. func NewResumptionState(ticket []byte, state *SessionState) (*ClientSessionState, error) { + state.ticket = ticket return &ClientSessionState{ - ticket: ticket, session: state, + session: state, }, nil } diff --git a/contrib/go/_std_1.22/src/crypto/tls/tls.go b/contrib/go/_std_1.23/src/crypto/tls/tls.go similarity index 92% rename from contrib/go/_std_1.22/src/crypto/tls/tls.go rename to contrib/go/_std_1.23/src/crypto/tls/tls.go index 8509b7dc0dd6..f3089f0ed68d 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/tls.go +++ b/contrib/go/_std_1.23/src/crypto/tls/tls.go @@ -22,6 +22,7 @@ import ( "encoding/pem" "errors" "fmt" + "internal/godebug" "net" "os" "strings" @@ -86,6 +87,7 @@ func NewListener(inner net.Listener, config *Config) net.Listener { // The configuration config must be non-nil and must include // at least one certificate or else set GetCertificate. func Listen(network, laddr string, config *Config) (net.Listener, error) { + // If this condition changes, consider updating http.Server.ServeTLS too. if config == nil || len(config.Certificates) == 0 && config.GetCertificate == nil && config.GetConfigForClient == nil { return nil, errors.New("tls: neither Certificates, GetCertificate, nor GetConfigForClient set in Config") @@ -222,11 +224,14 @@ func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Con return c, nil } -// LoadX509KeyPair reads and parses a public/private key pair from a pair -// of files. The files must contain PEM encoded data. The certificate file -// may contain intermediate certificates following the leaf certificate to -// form a certificate chain. On successful return, Certificate.Leaf will -// be nil because the parsed form of the certificate is not retained. +// LoadX509KeyPair reads and parses a public/private key pair from a pair of +// files. The files must contain PEM encoded data. The certificate file may +// contain intermediate certificates following the leaf certificate to form a +// certificate chain. On successful return, Certificate.Leaf will be populated. +// +// Before Go 1.23 Certificate.Leaf was left nil, and the parsed certificate was +// discarded. This behavior can be re-enabled by setting "x509keypairleaf=0" +// in the GODEBUG environment variable. func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) { certPEMBlock, err := os.ReadFile(certFile) if err != nil { @@ -239,9 +244,14 @@ func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) { return X509KeyPair(certPEMBlock, keyPEMBlock) } +var x509keypairleaf = godebug.New("x509keypairleaf") + // X509KeyPair parses a public/private key pair from a pair of -// PEM encoded data. On successful return, Certificate.Leaf will be nil because -// the parsed form of the certificate is not retained. +// PEM encoded data. On successful return, Certificate.Leaf will be populated. +// +// Before Go 1.23 Certificate.Leaf was left nil, and the parsed certificate was +// discarded. This behavior can be re-enabled by setting "x509keypairleaf=0" +// in the GODEBUG environment variable. func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) { fail := func(err error) (Certificate, error) { return Certificate{}, err } @@ -296,6 +306,12 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) { return fail(err) } + if x509keypairleaf.Value() != "0" { + cert.Leaf = x509Cert + } else { + x509keypairleaf.IncNonDefault() + } + cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes) if err != nil { return fail(err) diff --git a/contrib/go/_std_1.22/src/crypto/tls/ya.make b/contrib/go/_std_1.23/src/crypto/tls/ya.make similarity index 93% rename from contrib/go/_std_1.22/src/crypto/tls/ya.make rename to contrib/go/_std_1.23/src/crypto/tls/ya.make index 3fb148fd7402..c94f89b127b1 100644 --- a/contrib/go/_std_1.22/src/crypto/tls/ya.make +++ b/contrib/go/_std_1.23/src/crypto/tls/ya.make @@ -8,6 +8,8 @@ IF (TRUE) common.go common_string.go conn.go + defaults.go + ech.go handshake_client.go handshake_client_tls13.go handshake_messages.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/boring.go b/contrib/go/_std_1.23/src/crypto/x509/boring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/boring.go rename to contrib/go/_std_1.23/src/crypto/x509/boring.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/cert_pool.go b/contrib/go/_std_1.23/src/crypto/x509/cert_pool.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/cert_pool.go rename to contrib/go/_std_1.23/src/crypto/x509/cert_pool.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/internal/macos/corefoundation.go b/contrib/go/_std_1.23/src/crypto/x509/internal/macos/corefoundation.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/internal/macos/corefoundation.go rename to contrib/go/_std_1.23/src/crypto/x509/internal/macos/corefoundation.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/internal/macos/corefoundation.s b/contrib/go/_std_1.23/src/crypto/x509/internal/macos/corefoundation.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/internal/macos/corefoundation.s rename to contrib/go/_std_1.23/src/crypto/x509/internal/macos/corefoundation.s diff --git a/contrib/go/_std_1.22/src/crypto/x509/internal/macos/security.go b/contrib/go/_std_1.23/src/crypto/x509/internal/macos/security.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/internal/macos/security.go rename to contrib/go/_std_1.23/src/crypto/x509/internal/macos/security.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/internal/macos/security.s b/contrib/go/_std_1.23/src/crypto/x509/internal/macos/security.s similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/internal/macos/security.s rename to contrib/go/_std_1.23/src/crypto/x509/internal/macos/security.s diff --git a/contrib/go/_std_1.22/src/crypto/x509/internal/macos/ya.make b/contrib/go/_std_1.23/src/crypto/x509/internal/macos/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/internal/macos/ya.make rename to contrib/go/_std_1.23/src/crypto/x509/internal/macos/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/x509/internal/ya.make b/contrib/go/_std_1.23/src/crypto/x509/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/internal/ya.make rename to contrib/go/_std_1.23/src/crypto/x509/internal/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/x509/notboring.go b/contrib/go/_std_1.23/src/crypto/x509/notboring.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/notboring.go rename to contrib/go/_std_1.23/src/crypto/x509/notboring.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/oid.go b/contrib/go/_std_1.23/src/crypto/x509/oid.go similarity index 69% rename from contrib/go/_std_1.22/src/crypto/x509/oid.go rename to contrib/go/_std_1.23/src/crypto/x509/oid.go index 5359af624b27..fd438eacf954 100644 --- a/contrib/go/_std_1.22/src/crypto/x509/oid.go +++ b/contrib/go/_std_1.23/src/crypto/x509/oid.go @@ -24,6 +24,12 @@ type OID struct { der []byte } +// ParseOID parses a Object Identifier string, represented by ASCII numbers separated by dots. +func ParseOID(oid string) (OID, error) { + var o OID + return o, o.unmarshalOIDText(oid) +} + func newOIDFromDER(der []byte) (OID, bool) { if len(der) == 0 || der[len(der)-1]&0x80 != 0 { return OID{}, false @@ -83,6 +89,112 @@ func appendBase128Int(dst []byte, n uint64) []byte { return dst } +func base128BigIntLength(n *big.Int) int { + if n.Cmp(big.NewInt(0)) == 0 { + return 1 + } + return (n.BitLen() + 6) / 7 +} + +func appendBase128BigInt(dst []byte, n *big.Int) []byte { + if n.Cmp(big.NewInt(0)) == 0 { + return append(dst, 0) + } + + for i := base128BigIntLength(n) - 1; i >= 0; i-- { + o := byte(big.NewInt(0).Rsh(n, uint(i)*7).Bits()[0]) + o &= 0x7f + if i != 0 { + o |= 0x80 + } + dst = append(dst, o) + } + return dst +} + +// MarshalText implements [encoding.TextMarshaler] +func (o OID) MarshalText() ([]byte, error) { + return []byte(o.String()), nil +} + +// UnmarshalText implements [encoding.TextUnmarshaler] +func (o *OID) UnmarshalText(text []byte) error { + return o.unmarshalOIDText(string(text)) +} + +func (o *OID) unmarshalOIDText(oid string) error { + // (*big.Int).SetString allows +/- signs, but we don't want + // to allow them in the string representation of Object Identifier, so + // reject such encodings. + for _, c := range oid { + isDigit := c >= '0' && c <= '9' + if !isDigit && c != '.' { + return errInvalidOID + } + } + + var ( + firstNum string + secondNum string + ) + + var nextComponentExists bool + firstNum, oid, nextComponentExists = strings.Cut(oid, ".") + if !nextComponentExists { + return errInvalidOID + } + secondNum, oid, nextComponentExists = strings.Cut(oid, ".") + + var ( + first = big.NewInt(0) + second = big.NewInt(0) + ) + + if _, ok := first.SetString(firstNum, 10); !ok { + return errInvalidOID + } + if _, ok := second.SetString(secondNum, 10); !ok { + return errInvalidOID + } + + if first.Cmp(big.NewInt(2)) > 0 || (first.Cmp(big.NewInt(2)) < 0 && second.Cmp(big.NewInt(40)) >= 0) { + return errInvalidOID + } + + firstComponent := first.Mul(first, big.NewInt(40)) + firstComponent.Add(firstComponent, second) + + der := appendBase128BigInt(make([]byte, 0, 32), firstComponent) + + for nextComponentExists { + var strNum string + strNum, oid, nextComponentExists = strings.Cut(oid, ".") + b, ok := big.NewInt(0).SetString(strNum, 10) + if !ok { + return errInvalidOID + } + der = appendBase128BigInt(der, b) + } + + o.der = der + return nil +} + +// MarshalBinary implements [encoding.BinaryMarshaler] +func (o OID) MarshalBinary() ([]byte, error) { + return bytes.Clone(o.der), nil +} + +// UnmarshalBinary implements [encoding.BinaryUnmarshaler] +func (o *OID) UnmarshalBinary(b []byte) error { + oid, ok := newOIDFromDER(bytes.Clone(b)) + if !ok { + return errInvalidOID + } + *o = oid + return nil +} + // Equal returns true when oid and other represents the same Object Identifier. func (oid OID) Equal(other OID) bool { // There is only one possible DER encoding of @@ -156,7 +268,7 @@ func (oid OID) EqualASN1OID(other asn1.ObjectIdentifier) bool { // the OID, but better safe than sorry. return false } - if v != other[i] { + if i >= len(other) || v != other[i] { return false } } diff --git a/contrib/go/_std_1.22/src/crypto/x509/parser.go b/contrib/go/_std_1.23/src/crypto/x509/parser.go similarity index 95% rename from contrib/go/_std_1.22/src/crypto/x509/parser.go rename to contrib/go/_std_1.23/src/crypto/x509/parser.go index 812b0d2d2854..3ba5f6a4e1dc 100644 --- a/contrib/go/_std_1.22/src/crypto/x509/parser.go +++ b/contrib/go/_std_1.23/src/crypto/x509/parser.go @@ -16,6 +16,7 @@ import ( "encoding/asn1" "errors" "fmt" + "internal/godebug" "math/big" "net" "net/url" @@ -415,6 +416,26 @@ func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string return } +func parseAuthorityKeyIdentifier(e pkix.Extension) ([]byte, error) { + // RFC 5280, Section 4.2.1.1 + if e.Critical { + // Conforming CAs MUST mark this extension as non-critical + return nil, errors.New("x509: authority key identifier incorrectly marked critical") + } + val := cryptobyte.String(e.Value) + var akid cryptobyte.String + if !val.ReadASN1(&akid, cryptobyte_asn1.SEQUENCE) { + return nil, errors.New("x509: invalid authority key identifier") + } + if akid.PeekASN1Tag(cryptobyte_asn1.Tag(0).ContextSpecific()) { + if !akid.ReadASN1(&akid, cryptobyte_asn1.Tag(0).ContextSpecific()) { + return nil, errors.New("x509: invalid authority key identifier") + } + return akid, nil + } + return nil, nil +} + func parseExtKeyUsageExtension(der cryptobyte.String) ([]ExtKeyUsage, []asn1.ObjectIdentifier, error) { var extKeyUsages []ExtKeyUsage var unknownUsages []asn1.ObjectIdentifier @@ -722,17 +743,9 @@ func processExtensions(out *Certificate) error { } case 35: - // RFC 5280, 4.2.1.1 - val := cryptobyte.String(e.Value) - var akid cryptobyte.String - if !val.ReadASN1(&akid, cryptobyte_asn1.SEQUENCE) { - return errors.New("x509: invalid authority key identifier") - } - if akid.PeekASN1Tag(cryptobyte_asn1.Tag(0).ContextSpecific()) { - if !akid.ReadASN1(&akid, cryptobyte_asn1.Tag(0).ContextSpecific()) { - return errors.New("x509: invalid authority key identifier") - } - out.AuthorityKeyId = akid + out.AuthorityKeyId, err = parseAuthorityKeyIdentifier(e) + if err != nil { + return err } case 37: out.ExtKeyUsage, out.UnknownExtKeyUsage, err = parseExtKeyUsageExtension(e.Value) @@ -741,6 +754,10 @@ func processExtensions(out *Certificate) error { } case 14: // RFC 5280, 4.2.1.2 + if e.Critical { + // Conforming CAs MUST mark this extension as non-critical + return errors.New("x509: subject key identifier incorrectly marked critical") + } val := cryptobyte.String(e.Value) var skid cryptobyte.String if !val.ReadASN1(&skid, cryptobyte_asn1.OCTET_STRING) { @@ -764,6 +781,10 @@ func processExtensions(out *Certificate) error { } } else if e.Id.Equal(oidExtensionAuthorityInfoAccess) { // RFC 5280 4.2.2.1: Authority Information Access + if e.Critical { + // Conforming CAs MUST mark this extension as non-critical + return errors.New("x509: authority info access incorrectly marked critical") + } val := cryptobyte.String(e.Value) if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid authority info access") @@ -803,6 +824,8 @@ func processExtensions(out *Certificate) error { return nil } +var x509negativeserial = godebug.New("x509negativeserial") + func parseCertificate(der []byte) (*Certificate, error) { cert := &Certificate{} @@ -846,11 +869,13 @@ func parseCertificate(der []byte) (*Certificate, error) { if !tbs.ReadASN1Integer(serial) { return nil, errors.New("x509: malformed serial number") } - // we ignore the presence of negative serial numbers because - // of their prevalence, despite them being invalid - // TODO(rolandshoemaker): revisit this decision, there are currently - // only 10 trusted certificates with negative serial numbers - // according to censys.io. + if serial.Sign() == -1 { + if x509negativeserial.Value() != "1" { + return nil, errors.New("x509: negative serial number") + } else { + x509negativeserial.IncNonDefault() + } + } cert.SerialNumber = serial var sigAISeq cryptobyte.String @@ -964,7 +989,7 @@ func parseCertificate(der []byte) (*Certificate, error) { } oidStr := ext.Id.String() if seenExts[oidStr] { - return nil, errors.New("x509: certificate contains duplicate extensions") + return nil, fmt.Errorf("x509: certificate contains duplicate extension with OID %q", oidStr) } seenExts[oidStr] = true cert.Extensions = append(cert.Extensions, ext) @@ -987,6 +1012,10 @@ func parseCertificate(der []byte) (*Certificate, error) { } // ParseCertificate parses a single certificate from the given ASN.1 DER data. +// +// Before Go 1.23, ParseCertificate accepted certificates with negative serial +// numbers. This behavior can be restored by including "x509negativeserial=1" in +// the GODEBUG environment variable. func ParseCertificate(der []byte) (*Certificate, error) { cert, err := parseCertificate(der) if err != nil { @@ -1183,7 +1212,10 @@ func ParseRevocationList(der []byte) (*RevocationList, error) { return nil, err } if ext.Id.Equal(oidExtensionAuthorityKeyId) { - rl.AuthorityKeyId = ext.Value + rl.AuthorityKeyId, err = parseAuthorityKeyIdentifier(ext) + if err != nil { + return nil, err + } } else if ext.Id.Equal(oidExtensionCRLNumber) { value := cryptobyte.String(ext.Value) rl.Number = new(big.Int) diff --git a/contrib/go/_std_1.22/src/crypto/x509/pem_decrypt.go b/contrib/go/_std_1.23/src/crypto/x509/pem_decrypt.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/pem_decrypt.go rename to contrib/go/_std_1.23/src/crypto/x509/pem_decrypt.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/pkcs1.go b/contrib/go/_std_1.23/src/crypto/x509/pkcs1.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/pkcs1.go rename to contrib/go/_std_1.23/src/crypto/x509/pkcs1.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/pkcs8.go b/contrib/go/_std_1.23/src/crypto/x509/pkcs8.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/pkcs8.go rename to contrib/go/_std_1.23/src/crypto/x509/pkcs8.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/pkix/pkix.go b/contrib/go/_std_1.23/src/crypto/x509/pkix/pkix.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/pkix/pkix.go rename to contrib/go/_std_1.23/src/crypto/x509/pkix/pkix.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/pkix/ya.make b/contrib/go/_std_1.23/src/crypto/x509/pkix/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/pkix/ya.make rename to contrib/go/_std_1.23/src/crypto/x509/pkix/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/x509/platform_root_cert.pem b/contrib/go/_std_1.23/src/crypto/x509/platform_root_cert.pem similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/platform_root_cert.pem rename to contrib/go/_std_1.23/src/crypto/x509/platform_root_cert.pem diff --git a/contrib/go/_std_1.22/src/crypto/x509/platform_root_key.pem b/contrib/go/_std_1.23/src/crypto/x509/platform_root_key.pem similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/platform_root_key.pem rename to contrib/go/_std_1.23/src/crypto/x509/platform_root_key.pem diff --git a/contrib/go/_std_1.22/src/crypto/x509/root.go b/contrib/go/_std_1.23/src/crypto/x509/root.go similarity index 86% rename from contrib/go/_std_1.22/src/crypto/x509/root.go rename to contrib/go/_std_1.23/src/crypto/x509/root.go index b454af2c4c19..fbd43430afa8 100644 --- a/contrib/go/_std_1.22/src/crypto/x509/root.go +++ b/contrib/go/_std_1.23/src/crypto/x509/root.go @@ -7,8 +7,18 @@ package x509 import ( "internal/godebug" "sync" + _ "unsafe" // for linkname ) +// systemRoots should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/breml/rootcerts +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname systemRoots var ( once sync.Once systemRootsMu sync.RWMutex diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_aix.go b/contrib/go/_std_1.23/src/crypto/x509/root_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_aix.go rename to contrib/go/_std_1.23/src/crypto/x509/root_aix.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_bsd.go b/contrib/go/_std_1.23/src/crypto/x509/root_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_bsd.go rename to contrib/go/_std_1.23/src/crypto/x509/root_bsd.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_darwin.go b/contrib/go/_std_1.23/src/crypto/x509/root_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_darwin.go rename to contrib/go/_std_1.23/src/crypto/x509/root_darwin.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_linux.go b/contrib/go/_std_1.23/src/crypto/x509/root_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_linux.go rename to contrib/go/_std_1.23/src/crypto/x509/root_linux.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_plan9.go b/contrib/go/_std_1.23/src/crypto/x509/root_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_plan9.go rename to contrib/go/_std_1.23/src/crypto/x509/root_plan9.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_solaris.go b/contrib/go/_std_1.23/src/crypto/x509/root_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_solaris.go rename to contrib/go/_std_1.23/src/crypto/x509/root_solaris.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_unix.go b/contrib/go/_std_1.23/src/crypto/x509/root_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_unix.go rename to contrib/go/_std_1.23/src/crypto/x509/root_unix.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_wasm.go b/contrib/go/_std_1.23/src/crypto/x509/root_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_wasm.go rename to contrib/go/_std_1.23/src/crypto/x509/root_wasm.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/root_windows.go b/contrib/go/_std_1.23/src/crypto/x509/root_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/root_windows.go rename to contrib/go/_std_1.23/src/crypto/x509/root_windows.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/sec1.go b/contrib/go/_std_1.23/src/crypto/x509/sec1.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/sec1.go rename to contrib/go/_std_1.23/src/crypto/x509/sec1.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/test-file.crt b/contrib/go/_std_1.23/src/crypto/x509/test-file.crt similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/test-file.crt rename to contrib/go/_std_1.23/src/crypto/x509/test-file.crt diff --git a/contrib/go/_std_1.22/src/crypto/x509/verify.go b/contrib/go/_std_1.23/src/crypto/x509/verify.go similarity index 98% rename from contrib/go/_std_1.22/src/crypto/x509/verify.go rename to contrib/go/_std_1.23/src/crypto/x509/verify.go index 6efbff28bf7b..bbccfce57742 100644 --- a/contrib/go/_std_1.22/src/crypto/x509/verify.go +++ b/contrib/go/_std_1.23/src/crypto/x509/verify.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "net" + "net/netip" "net/url" "reflect" "runtime" @@ -366,6 +367,11 @@ func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) { } else { reverseLabels = append(reverseLabels, domain[i+1:]) domain = domain[:i] + if i == 0 { // domain == "" + // domain is prefixed with an empty label, append an empty + // string to reverseLabels to indicate this. + reverseLabels = append(reverseLabels, "") + } } } @@ -429,8 +435,10 @@ func matchURIConstraint(uri *url.URL, constraint string) (bool, error) { } } - if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") || - net.ParseIP(host) != nil { + // netip.ParseAddr will reject the URI IPv6 literal form "[...]", so we + // check if _either_ the string parses as an IP, or if it is enclosed in + // square brackets. + if _, err := netip.ParseAddr(host); err == nil || (strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]")) { return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String()) } @@ -979,6 +987,11 @@ func validHostname(host string, isPattern bool) bool { if len(host) == 0 { return false } + if host == "*" { + // Bare wildcards are not allowed, they are not valid DNS names, + // nor are they allowed per RFC 6125. + return false + } for i, part := range strings.Split(host, ".") { if part == "" { diff --git a/contrib/go/_std_1.22/src/crypto/x509/x509.go b/contrib/go/_std_1.23/src/crypto/x509/x509.go similarity index 92% rename from contrib/go/_std_1.22/src/crypto/x509/x509.go rename to contrib/go/_std_1.23/src/crypto/x509/x509.go index 15b3b9ed35ee..50433058f74c 100644 --- a/contrib/go/_std_1.22/src/crypto/x509/x509.go +++ b/contrib/go/_std_1.23/src/crypto/x509/x509.go @@ -233,12 +233,21 @@ const ( ) func (algo SignatureAlgorithm) isRSAPSS() bool { - switch algo { - case SHA256WithRSAPSS, SHA384WithRSAPSS, SHA512WithRSAPSS: - return true - default: - return false + for _, details := range signatureAlgorithmDetails { + if details.algo == algo { + return details.isRSAPSS + } + } + return false +} + +func (algo SignatureAlgorithm) hashFunc() crypto.Hash { + for _, details := range signatureAlgorithmDetails { + if details.algo == algo { + return details.hash + } } + return crypto.Hash(0) } func (algo SignatureAlgorithm) String() string { @@ -281,8 +290,6 @@ func (algo PublicKeyAlgorithm) String() string { // // RFC 3279 2.2.1 RSA Signature Algorithms // -// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 } -// // md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 } // // sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } @@ -325,7 +332,6 @@ func (algo PublicKeyAlgorithm) String() string { // // id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } var ( - oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2} oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} @@ -356,40 +362,43 @@ var signatureAlgorithmDetails = []struct { algo SignatureAlgorithm name string oid asn1.ObjectIdentifier + params asn1.RawValue pubKeyAlgo PublicKeyAlgorithm hash crypto.Hash + isRSAPSS bool }{ - {MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */}, - {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, RSA, crypto.MD5}, - {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, RSA, crypto.SHA1}, - {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, RSA, crypto.SHA1}, - {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, RSA, crypto.SHA256}, - {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, RSA, crypto.SHA384}, - {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, RSA, crypto.SHA512}, - {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA256}, - {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA384}, - {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA512}, - {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, DSA, crypto.SHA1}, - {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, DSA, crypto.SHA256}, - {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1}, - {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256}, - {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384}, - {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512}, - {PureEd25519, "Ed25519", oidSignatureEd25519, Ed25519, crypto.Hash(0) /* no pre-hashing */}, -} - -// hashToPSSParameters contains the DER encoded RSA PSS parameters for the + {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, asn1.NullRawValue, RSA, crypto.MD5, false}, + {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false}, + {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false}, + {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, asn1.NullRawValue, RSA, crypto.SHA256, false}, + {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, asn1.NullRawValue, RSA, crypto.SHA384, false}, + {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, asn1.NullRawValue, RSA, crypto.SHA512, false}, + {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, pssParametersSHA256, RSA, crypto.SHA256, true}, + {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, pssParametersSHA384, RSA, crypto.SHA384, true}, + {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, pssParametersSHA512, RSA, crypto.SHA512, true}, + {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, emptyRawValue, DSA, crypto.SHA1, false}, + {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, emptyRawValue, DSA, crypto.SHA256, false}, + {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, emptyRawValue, ECDSA, crypto.SHA1, false}, + {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, emptyRawValue, ECDSA, crypto.SHA256, false}, + {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, emptyRawValue, ECDSA, crypto.SHA384, false}, + {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, emptyRawValue, ECDSA, crypto.SHA512, false}, + {PureEd25519, "Ed25519", oidSignatureEd25519, emptyRawValue, Ed25519, crypto.Hash(0) /* no pre-hashing */, false}, +} + +var emptyRawValue = asn1.RawValue{} + +// DER encoded RSA PSS parameters for the // SHA256, SHA384, and SHA512 hashes as defined in RFC 3447, Appendix A.2.3. // The parameters contain the following values: // - hashAlgorithm contains the associated hash identifier with NULL parameters // - maskGenAlgorithm always contains the default mgf1SHA1 identifier // - saltLength contains the length of the associated hash // - trailerField always contains the default trailerFieldBC value -var hashToPSSParameters = map[crypto.Hash]asn1.RawValue{ - crypto.SHA256: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}}, - crypto.SHA384: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}}, - crypto.SHA512: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}}, -} +var ( + pssParametersSHA256 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}} + pssParametersSHA384 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}} + pssParametersSHA512 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}} +) // pssParameters reflects the parameters in an AlgorithmIdentifier that // specifies RSA PSS. See RFC 3447, Appendix A.2.3. @@ -1102,7 +1111,7 @@ func isIA5String(s string) error { return nil } -var usePoliciesField = godebug.New("x509usepolicies") +var x509usepolicies = godebug.New("x509usepolicies") func buildCertExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte, subjectKeyId []byte) (ret []pkix.Extension, err error) { ret = make([]pkix.Extension, 10 /* maximum number of elements. */) @@ -1189,7 +1198,7 @@ func buildCertExtensions(template *Certificate, subjectIsEmpty bool, authorityKe n++ } - usePolicies := usePoliciesField.Value() == "1" + usePolicies := x509usepolicies.Value() == "1" if ((!usePolicies && len(template.PolicyIdentifiers) > 0) || (usePolicies && len(template.Policies) > 0)) && !oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) { ret[n], err = marshalCertificatePolicies(template.Policies, template.PolicyIdentifiers) @@ -1382,8 +1391,8 @@ func marshalCertificatePolicies(policies []OID, policyIdentifiers []asn1.ObjectI b := cryptobyte.NewBuilder(make([]byte, 0, 128)) b.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { - if usePoliciesField.Value() == "1" { - usePoliciesField.IncNonDefault() + if x509usepolicies.Value() == "1" { + x509usepolicies.IncNonDefault() for _, v := range policies { child.AddASN1(cryptobyte_asn1.SEQUENCE, func(child *cryptobyte.Builder) { child.AddASN1(cryptobyte_asn1.OBJECT_IDENTIFIER, func(child *cryptobyte.Builder) { @@ -1436,81 +1445,91 @@ func subjectBytes(cert *Certificate) ([]byte, error) { return asn1.Marshal(cert.Subject.ToRDNSequence()) } -// signingParamsForPublicKey returns the parameters to use for signing with -// priv. If requestedSigAlgo is not zero then it overrides the default -// signature algorithm. -func signingParamsForPublicKey(pub any, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) { +// signingParamsForKey returns the signature algorithm and its Algorithm +// Identifier to use for signing, based on the key type. If sigAlgo is not zero +// then it overrides the default. +func signingParamsForKey(key crypto.Signer, sigAlgo SignatureAlgorithm) (SignatureAlgorithm, pkix.AlgorithmIdentifier, error) { + var ai pkix.AlgorithmIdentifier var pubType PublicKeyAlgorithm + var defaultAlgo SignatureAlgorithm - switch pub := pub.(type) { + switch pub := key.Public().(type) { case *rsa.PublicKey: pubType = RSA - hashFunc = crypto.SHA256 - sigAlgo.Algorithm = oidSignatureSHA256WithRSA - sigAlgo.Parameters = asn1.NullRawValue + defaultAlgo = SHA256WithRSA case *ecdsa.PublicKey: pubType = ECDSA - switch pub.Curve { case elliptic.P224(), elliptic.P256(): - hashFunc = crypto.SHA256 - sigAlgo.Algorithm = oidSignatureECDSAWithSHA256 + defaultAlgo = ECDSAWithSHA256 case elliptic.P384(): - hashFunc = crypto.SHA384 - sigAlgo.Algorithm = oidSignatureECDSAWithSHA384 + defaultAlgo = ECDSAWithSHA384 case elliptic.P521(): - hashFunc = crypto.SHA512 - sigAlgo.Algorithm = oidSignatureECDSAWithSHA512 + defaultAlgo = ECDSAWithSHA512 default: - err = errors.New("x509: unknown elliptic curve") + return 0, ai, errors.New("x509: unsupported elliptic curve") } case ed25519.PublicKey: pubType = Ed25519 - sigAlgo.Algorithm = oidSignatureEd25519 + defaultAlgo = PureEd25519 default: - err = errors.New("x509: only RSA, ECDSA and Ed25519 keys supported") + return 0, ai, errors.New("x509: only RSA, ECDSA and Ed25519 keys supported") } - if err != nil { - return + if sigAlgo == 0 { + sigAlgo = defaultAlgo } - if requestedSigAlgo == 0 { - return - } - - found := false for _, details := range signatureAlgorithmDetails { - if details.algo == requestedSigAlgo { + if details.algo == sigAlgo { if details.pubKeyAlgo != pubType { - err = errors.New("x509: requested SignatureAlgorithm does not match private key type") - return - } - sigAlgo.Algorithm, hashFunc = details.oid, details.hash - if hashFunc == 0 && pubType != Ed25519 { - err = errors.New("x509: cannot sign with hash function requested") - return - } - if hashFunc == crypto.MD5 { - err = errors.New("x509: signing with MD5 is not supported") - return + return 0, ai, errors.New("x509: requested SignatureAlgorithm does not match private key type") } - if requestedSigAlgo.isRSAPSS() { - sigAlgo.Parameters = hashToPSSParameters[hashFunc] + if details.hash == crypto.MD5 { + return 0, ai, errors.New("x509: signing with MD5 is not supported") } - found = true - break + + return sigAlgo, pkix.AlgorithmIdentifier{ + Algorithm: details.oid, + Parameters: details.params, + }, nil } } - if !found { - err = errors.New("x509: unknown SignatureAlgorithm") + return 0, ai, errors.New("x509: unknown SignatureAlgorithm") +} + +func signTBS(tbs []byte, key crypto.Signer, sigAlg SignatureAlgorithm, rand io.Reader) ([]byte, error) { + signed := tbs + hashFunc := sigAlg.hashFunc() + if hashFunc != 0 { + h := hashFunc.New() + h.Write(signed) + signed = h.Sum(nil) } - return + var signerOpts crypto.SignerOpts = hashFunc + if sigAlg.isRSAPSS() { + signerOpts = &rsa.PSSOptions{ + SaltLength: rsa.PSSSaltLengthEqualsHash, + Hash: hashFunc, + } + } + + signature, err := key.Sign(rand, signed, signerOpts) + if err != nil { + return nil, err + } + + // Check the signature to ensure the crypto.Signer behaved correctly. + if err := checkSignature(sigAlg, tbs, signature, key.Public(), true); err != nil { + return nil, fmt.Errorf("x509: signature returned by signer is invalid: %w", err) + } + + return signature, nil } // emptyASN1Subject is the ASN.1 DER encoding of an empty Subject, which is @@ -1574,7 +1593,7 @@ var emptyASN1Subject = []byte{0x30, 0} // The PolicyIdentifier and Policies fields are both used to marshal certificate // policy OIDs. By default, only the PolicyIdentifier is marshaled, but if the // GODEBUG setting "x509usepolicies" has the value "1", the Policies field will -// be marshalled instead of the PolicyIdentifier field. The Policies field can +// be marshaled instead of the PolicyIdentifier field. The Policies field can // be used to marshal policy OIDs which have components that are larger than 31 // bits. func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv any) ([]byte, error) { @@ -1600,7 +1619,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen") } - hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm) + signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, template.SignatureAlgorithm) if err != nil { return nil, err } @@ -1657,7 +1676,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv c := tbsCertificate{ Version: 2, SerialNumber: template.SerialNumber, - SignatureAlgorithm: signatureAlgorithm, + SignatureAlgorithm: algorithmIdentifier, Issuer: asn1.RawValue{FullBytes: asn1Issuer}, Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()}, Subject: asn1.RawValue{FullBytes: asn1Subject}, @@ -1671,42 +1690,16 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv } c.Raw = tbsCertContents - signed := tbsCertContents - if hashFunc != 0 { - h := hashFunc.New() - h.Write(signed) - signed = h.Sum(nil) - } - - var signerOpts crypto.SignerOpts = hashFunc - if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() { - signerOpts = &rsa.PSSOptions{ - SaltLength: rsa.PSSSaltLengthEqualsHash, - Hash: hashFunc, - } - } - - var signature []byte - signature, err = key.Sign(rand, signed, signerOpts) + signature, err := signTBS(tbsCertContents, key, signatureAlgorithm, rand) if err != nil { return nil, err } - signedCert, err := asn1.Marshal(certificate{ - c, - signatureAlgorithm, - asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, + return asn1.Marshal(certificate{ + TBSCertificate: c, + SignatureAlgorithm: algorithmIdentifier, + SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) - if err != nil { - return nil, err - } - - // Check the signature to ensure the crypto.Signer behaved correctly. - if err := checkSignature(getSignatureAlgorithmFromAI(signatureAlgorithm), c.Raw, signature, key.Public(), true); err != nil { - return nil, fmt.Errorf("x509: signature over certificate returned by signer is invalid: %w", err) - } - - return signedCert, nil } // pemCRLPrefix is the magic string that indicates that we have a PEM encoded @@ -1756,7 +1749,7 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.Re return nil, errors.New("x509: certificate private key does not implement crypto.Signer") } - hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0) + signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, 0) if err != nil { return nil, err } @@ -1770,7 +1763,7 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.Re tbsCertList := pkix.TBSCertificateList{ Version: 1, - Signature: signatureAlgorithm, + Signature: algorithmIdentifier, Issuer: c.Subject.ToRDNSequence(), ThisUpdate: now.UTC(), NextUpdate: expiry.UTC(), @@ -1783,32 +1776,25 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.Re aki.Id = oidExtensionAuthorityKeyId aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId}) if err != nil { - return + return nil, err } tbsCertList.Extensions = append(tbsCertList.Extensions, aki) } tbsCertListContents, err := asn1.Marshal(tbsCertList) if err != nil { - return - } - - signed := tbsCertListContents - if hashFunc != 0 { - h := hashFunc.New() - h.Write(signed) - signed = h.Sum(nil) + return nil, err } + tbsCertList.Raw = tbsCertListContents - var signature []byte - signature, err = key.Sign(rand, signed, hashFunc) + signature, err := signTBS(tbsCertListContents, key, signatureAlgorithm, rand) if err != nil { - return + return nil, err } return asn1.Marshal(pkix.CertificateList{ TBSCertList: tbsCertList, - SignatureAlgorithm: signatureAlgorithm, + SignatureAlgorithm: algorithmIdentifier, SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) } @@ -1976,9 +1962,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv return nil, errors.New("x509: certificate private key does not implement crypto.Signer") } - var hashFunc crypto.Hash - var sigAlgo pkix.AlgorithmIdentifier - hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm) + signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(key, template.SignatureAlgorithm) if err != nil { return nil, err } @@ -2050,7 +2034,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv rawAttributes, err := newRawAttributes(attributes) if err != nil { - return + return nil, err } // If not included in attributes, add a new attribute for the @@ -2100,30 +2084,19 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv tbsCSRContents, err := asn1.Marshal(tbsCSR) if err != nil { - return + return nil, err } tbsCSR.Raw = tbsCSRContents - signed := tbsCSRContents - if hashFunc != 0 { - h := hashFunc.New() - h.Write(signed) - signed = h.Sum(nil) - } - - var signature []byte - signature, err = key.Sign(rand, signed, hashFunc) + signature, err := signTBS(tbsCSRContents, key, signatureAlgorithm, rand) if err != nil { - return + return nil, err } return asn1.Marshal(certificateRequest{ TBSCSR: tbsCSR, - SignatureAlgorithm: sigAlgo, - SignatureValue: asn1.BitString{ - Bytes: signature, - BitLength: len(signature) * 8, - }, + SignatureAlgorithm: algorithmIdentifier, + SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) } @@ -2351,7 +2324,7 @@ func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Cert return nil, errors.New("x509: template contains nil Number field") } - hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), template.SignatureAlgorithm) + signatureAlgorithm, algorithmIdentifier, err := signingParamsForKey(priv, template.SignatureAlgorithm) if err != nil { return nil, err } @@ -2435,7 +2408,7 @@ func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Cert tbsCertList := tbsCertificateList{ Version: 1, // v2 - Signature: signatureAlgorithm, + Signature: algorithmIdentifier, Issuer: asn1.RawValue{FullBytes: issuerSubject}, ThisUpdate: template.ThisUpdate.UTC(), NextUpdate: template.NextUpdate.UTC(), @@ -2467,28 +2440,14 @@ func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Cert // then embedding in certificateList below. tbsCertList.Raw = tbsCertListContents - input := tbsCertListContents - if hashFunc != 0 { - h := hashFunc.New() - h.Write(tbsCertListContents) - input = h.Sum(nil) - } - var signerOpts crypto.SignerOpts = hashFunc - if template.SignatureAlgorithm.isRSAPSS() { - signerOpts = &rsa.PSSOptions{ - SaltLength: rsa.PSSSaltLengthEqualsHash, - Hash: hashFunc, - } - } - - signature, err := priv.Sign(rand, input, signerOpts) + signature, err := signTBS(tbsCertListContents, priv, signatureAlgorithm, rand) if err != nil { return nil, err } return asn1.Marshal(certificateList{ TBSCertList: tbsCertList, - SignatureAlgorithm: signatureAlgorithm, + SignatureAlgorithm: algorithmIdentifier, SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) } diff --git a/contrib/go/_std_1.22/src/crypto/x509/x509_test_import.go b/contrib/go/_std_1.23/src/crypto/x509/x509_test_import.go similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/x509_test_import.go rename to contrib/go/_std_1.23/src/crypto/x509/x509_test_import.go diff --git a/contrib/go/_std_1.22/src/crypto/x509/ya.make b/contrib/go/_std_1.23/src/crypto/x509/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/x509/ya.make rename to contrib/go/_std_1.23/src/crypto/x509/ya.make diff --git a/contrib/go/_std_1.22/src/crypto/ya.make b/contrib/go/_std_1.23/src/crypto/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/crypto/ya.make rename to contrib/go/_std_1.23/src/crypto/ya.make diff --git a/contrib/go/_std_1.22/src/database/sql/driver/driver.go b/contrib/go/_std_1.23/src/database/sql/driver/driver.go similarity index 99% rename from contrib/go/_std_1.22/src/database/sql/driver/driver.go rename to contrib/go/_std_1.23/src/database/sql/driver/driver.go index da310bfb12a0..d0892e80fc28 100644 --- a/contrib/go/_std_1.22/src/database/sql/driver/driver.go +++ b/contrib/go/_std_1.23/src/database/sql/driver/driver.go @@ -415,7 +415,7 @@ type NamedValueChecker interface { type ColumnConverter interface { // ColumnConverter returns a ValueConverter for the provided // column index. If the type of a specific column isn't known - // or shouldn't be handled specially, DefaultValueConverter + // or shouldn't be handled specially, [DefaultParameterConverter] // can be returned. ColumnConverter(idx int) ValueConverter } diff --git a/contrib/go/_std_1.22/src/database/sql/driver/types.go b/contrib/go/_std_1.23/src/database/sql/driver/types.go similarity index 97% rename from contrib/go/_std_1.22/src/database/sql/driver/types.go rename to contrib/go/_std_1.23/src/database/sql/driver/types.go index 0380572ab197..a322f85277c6 100644 --- a/contrib/go/_std_1.22/src/database/sql/driver/types.go +++ b/contrib/go/_std_1.23/src/database/sql/driver/types.go @@ -34,6 +34,10 @@ type ValueConverter interface { // Valuer is the interface providing the Value method. // +// Errors returned by the [Value] method are wrapped by the database/sql package. +// This allows callers to use [errors.Is] for precise error handling after operations +// like [database/sql.Query], [database/sql.Exec], or [database/sql.QueryRow]. +// // Types implementing Valuer interface are able to convert // themselves to a driver [Value]. type Valuer interface { diff --git a/contrib/go/_std_1.22/src/database/sql/driver/ya.make b/contrib/go/_std_1.23/src/database/sql/driver/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/database/sql/driver/ya.make rename to contrib/go/_std_1.23/src/database/sql/driver/ya.make diff --git a/contrib/go/_std_1.22/src/embed/embed.go b/contrib/go/_std_1.23/src/embed/embed.go similarity index 96% rename from contrib/go/_std_1.22/src/embed/embed.go rename to contrib/go/_std_1.23/src/embed/embed.go index b7bb16099e56..f6c0ef9b9751 100644 --- a/contrib/go/_std_1.22/src/embed/embed.go +++ b/contrib/go/_std_1.23/src/embed/embed.go @@ -130,6 +130,8 @@ package embed import ( "errors" + "internal/bytealg" + "internal/stringslite" "io" "io/fs" "time" @@ -185,29 +187,14 @@ type FS struct { // comment in the FS struct above. isDir reports whether the // final trailing slash was present, indicating that name is a directory. func split(name string) (dir, elem string, isDir bool) { - if name[len(name)-1] == '/' { - isDir = true - name = name[:len(name)-1] - } - i := len(name) - 1 - for i >= 0 && name[i] != '/' { - i-- - } + name, isDir = stringslite.CutSuffix(name, "/") + i := bytealg.LastIndexByteString(name, '/') if i < 0 { return ".", name, isDir } return name[:i], name[i+1:], isDir } -// trimSlash trims a trailing slash from name, if present, -// returning the possibly shortened name. -func trimSlash(name string) string { - if len(name) > 0 && name[len(name)-1] == '/' { - return name[:len(name)-1] - } - return name -} - var ( _ fs.ReadDirFS = FS{} _ fs.ReadFileFS = FS{} @@ -274,7 +261,7 @@ func (f FS) lookup(name string) *file { idir, ielem, _ := split(files[i].name) return idir > dir || idir == dir && ielem >= elem }) - if i < len(files) && trimSlash(files[i].name) == name { + if i < len(files) && stringslite.TrimSuffix(files[i].name, "/") == name { return &files[i] } return nil diff --git a/contrib/go/_std_1.22/src/embed/internal/embedtest/concurrency.txt b/contrib/go/_std_1.23/src/embed/internal/embedtest/concurrency.txt similarity index 100% rename from contrib/go/_std_1.22/src/embed/internal/embedtest/concurrency.txt rename to contrib/go/_std_1.23/src/embed/internal/embedtest/concurrency.txt diff --git a/contrib/go/_std_1.22/src/embed/internal/embedtest/ya.make b/contrib/go/_std_1.23/src/embed/internal/embedtest/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/embed/internal/embedtest/ya.make rename to contrib/go/_std_1.23/src/embed/internal/embedtest/ya.make diff --git a/contrib/go/_std_1.22/src/embed/internal/ya.make b/contrib/go/_std_1.23/src/embed/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/embed/internal/ya.make rename to contrib/go/_std_1.23/src/embed/internal/ya.make diff --git a/contrib/go/_std_1.22/src/embed/ya.make b/contrib/go/_std_1.23/src/embed/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/embed/ya.make rename to contrib/go/_std_1.23/src/embed/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/ascii85/ascii85.go b/contrib/go/_std_1.23/src/encoding/ascii85/ascii85.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/ascii85/ascii85.go rename to contrib/go/_std_1.23/src/encoding/ascii85/ascii85.go diff --git a/contrib/go/_std_1.22/src/encoding/ascii85/ya.make b/contrib/go/_std_1.23/src/encoding/ascii85/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/ascii85/ya.make rename to contrib/go/_std_1.23/src/encoding/ascii85/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/asn1/asn1.go b/contrib/go/_std_1.23/src/encoding/asn1/asn1.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/asn1/asn1.go rename to contrib/go/_std_1.23/src/encoding/asn1/asn1.go diff --git a/contrib/go/_std_1.22/src/encoding/asn1/common.go b/contrib/go/_std_1.23/src/encoding/asn1/common.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/asn1/common.go rename to contrib/go/_std_1.23/src/encoding/asn1/common.go diff --git a/contrib/go/_std_1.22/src/encoding/asn1/marshal.go b/contrib/go/_std_1.23/src/encoding/asn1/marshal.go similarity index 96% rename from contrib/go/_std_1.22/src/encoding/asn1/marshal.go rename to contrib/go/_std_1.23/src/encoding/asn1/marshal.go index d8c8fe17b374..b9c0b8bce054 100644 --- a/contrib/go/_std_1.22/src/encoding/asn1/marshal.go +++ b/contrib/go/_std_1.23/src/encoding/asn1/marshal.go @@ -10,7 +10,7 @@ import ( "fmt" "math/big" "reflect" - "sort" + "slices" "time" "unicode/utf8" ) @@ -105,15 +105,13 @@ func (s setEncoder) Encode(dst []byte) { e.Encode(l[i]) } - sort.Slice(l, func(i, j int) bool { - // Since we are using bytes.Compare to compare TLV encodings we - // don't need to right pad s[i] and s[j] to the same length as - // suggested in X690. If len(s[i]) < len(s[j]) the length octet of - // s[i], which is the first determining byte, will inherently be - // smaller than the length octet of s[j]. This lets us skip the - // padding step. - return bytes.Compare(l[i], l[j]) < 0 - }) + // Since we are using bytes.Compare to compare TLV encodings we + // don't need to right pad s[i] and s[j] to the same length as + // suggested in X690. If len(s[i]) < len(s[j]) the length octet of + // s[i], which is the first determining byte, will inherently be + // smaller than the length octet of s[j]. This lets us skip the + // padding step. + slices.SortFunc(l, bytes.Compare) var off int for _, b := range l { @@ -355,12 +353,11 @@ func appendTwoDigits(dst []byte, v int) []byte { } func appendFourDigits(dst []byte, v int) []byte { - var bytes [4]byte - for i := range bytes { - bytes[3-i] = '0' + byte(v%10) - v /= 10 - } - return append(dst, bytes[:]...) + return append(dst, + byte('0'+(v/1000)%10), + byte('0'+(v/100)%10), + byte('0'+(v/10)%10), + byte('0'+v%10)) } func outsideUTCRange(t time.Time) bool { diff --git a/contrib/go/_std_1.22/src/encoding/asn1/ya.make b/contrib/go/_std_1.23/src/encoding/asn1/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/asn1/ya.make rename to contrib/go/_std_1.23/src/encoding/asn1/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/base32/base32.go b/contrib/go/_std_1.23/src/encoding/base32/base32.go similarity index 99% rename from contrib/go/_std_1.22/src/encoding/base32/base32.go rename to contrib/go/_std_1.23/src/encoding/base32/base32.go index 4a61199a59d0..9e988ef39b4f 100644 --- a/contrib/go/_std_1.22/src/encoding/base32/base32.go +++ b/contrib/go/_std_1.23/src/encoding/base32/base32.go @@ -467,7 +467,7 @@ func (d *decoder) Read(p []byte) (n int, err error) { } // Read a chunk. - nn := len(p) / 5 * 8 + nn := (len(p) + 4) / 5 * 8 if nn < 8 { nn = 8 } diff --git a/contrib/go/_std_1.22/src/encoding/base32/ya.make b/contrib/go/_std_1.23/src/encoding/base32/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/base32/ya.make rename to contrib/go/_std_1.23/src/encoding/base32/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/base64/base64.go b/contrib/go/_std_1.23/src/encoding/base64/base64.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/base64/base64.go rename to contrib/go/_std_1.23/src/encoding/base64/base64.go diff --git a/contrib/go/_std_1.22/src/encoding/base64/ya.make b/contrib/go/_std_1.23/src/encoding/base64/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/base64/ya.make rename to contrib/go/_std_1.23/src/encoding/base64/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/binary/binary.go b/contrib/go/_std_1.23/src/encoding/binary/binary.go similarity index 61% rename from contrib/go/_std_1.22/src/encoding/binary/binary.go rename to contrib/go/_std_1.23/src/encoding/binary/binary.go index f001be83861a..a150c0bf05be 100644 --- a/contrib/go/_std_1.22/src/encoding/binary/binary.go +++ b/contrib/go/_std_1.23/src/encoding/binary/binary.go @@ -26,9 +26,12 @@ import ( "io" "math" "reflect" + "slices" "sync" ) +var errBufferTooSmall = errors.New("buffer too small") + // A ByteOrder specifies how to convert byte slices into // 16-, 32-, or 64-bit unsigned integers. // @@ -236,80 +239,13 @@ func (nativeEndian) GoString() string { return "binary.NativeEndian" } // Read returns [io.ErrUnexpectedEOF]. func Read(r io.Reader, order ByteOrder, data any) error { // Fast path for basic types and slices. - if n := intDataSize(data); n != 0 { + if n, _ := intDataSize(data); n != 0 { bs := make([]byte, n) if _, err := io.ReadFull(r, bs); err != nil { return err } - switch data := data.(type) { - case *bool: - *data = bs[0] != 0 - case *int8: - *data = int8(bs[0]) - case *uint8: - *data = bs[0] - case *int16: - *data = int16(order.Uint16(bs)) - case *uint16: - *data = order.Uint16(bs) - case *int32: - *data = int32(order.Uint32(bs)) - case *uint32: - *data = order.Uint32(bs) - case *int64: - *data = int64(order.Uint64(bs)) - case *uint64: - *data = order.Uint64(bs) - case *float32: - *data = math.Float32frombits(order.Uint32(bs)) - case *float64: - *data = math.Float64frombits(order.Uint64(bs)) - case []bool: - for i, x := range bs { // Easier to loop over the input for 8-bit values. - data[i] = x != 0 - } - case []int8: - for i, x := range bs { - data[i] = int8(x) - } - case []uint8: - copy(data, bs) - case []int16: - for i := range data { - data[i] = int16(order.Uint16(bs[2*i:])) - } - case []uint16: - for i := range data { - data[i] = order.Uint16(bs[2*i:]) - } - case []int32: - for i := range data { - data[i] = int32(order.Uint32(bs[4*i:])) - } - case []uint32: - for i := range data { - data[i] = order.Uint32(bs[4*i:]) - } - case []int64: - for i := range data { - data[i] = int64(order.Uint64(bs[8*i:])) - } - case []uint64: - for i := range data { - data[i] = order.Uint64(bs[8*i:]) - } - case []float32: - for i := range data { - data[i] = math.Float32frombits(order.Uint32(bs[4*i:])) - } - case []float64: - for i := range data { - data[i] = math.Float64frombits(order.Uint64(bs[8*i:])) - } - default: - n = 0 // fast path doesn't apply - } - if n != 0 { + + if decodeFast(bs, order, data) { return nil } } @@ -327,6 +263,7 @@ func Read(r io.Reader, order ByteOrder, data any) error { if size < 0 { return errors.New("binary.Read: invalid type " + reflect.TypeOf(data).String()) } + d := &decoder{order: order, buf: make([]byte, size)} if _, err := io.ReadFull(r, d.buf); err != nil { return err @@ -335,6 +272,115 @@ func Read(r io.Reader, order ByteOrder, data any) error { return nil } +// Decode decodes binary data from buf into data according to +// the given byte order. +// It returns an error if buf is too small, otherwise the number of +// bytes consumed from buf. +func Decode(buf []byte, order ByteOrder, data any) (int, error) { + if n, _ := intDataSize(data); n != 0 { + if len(buf) < n { + return 0, errBufferTooSmall + } + + if decodeFast(buf, order, data) { + return n, nil + } + } + + // Fallback to reflect-based decoding. + v := reflect.ValueOf(data) + size := -1 + switch v.Kind() { + case reflect.Pointer: + v = v.Elem() + size = dataSize(v) + case reflect.Slice: + size = dataSize(v) + } + if size < 0 { + return 0, errors.New("binary.Decode: invalid type " + reflect.TypeOf(data).String()) + } + + if len(buf) < size { + return 0, errBufferTooSmall + } + d := &decoder{order: order, buf: buf[:size]} + d.value(v) + return size, nil +} + +func decodeFast(bs []byte, order ByteOrder, data any) bool { + switch data := data.(type) { + case *bool: + *data = bs[0] != 0 + case *int8: + *data = int8(bs[0]) + case *uint8: + *data = bs[0] + case *int16: + *data = int16(order.Uint16(bs)) + case *uint16: + *data = order.Uint16(bs) + case *int32: + *data = int32(order.Uint32(bs)) + case *uint32: + *data = order.Uint32(bs) + case *int64: + *data = int64(order.Uint64(bs)) + case *uint64: + *data = order.Uint64(bs) + case *float32: + *data = math.Float32frombits(order.Uint32(bs)) + case *float64: + *data = math.Float64frombits(order.Uint64(bs)) + case []bool: + for i, x := range bs { // Easier to loop over the input for 8-bit values. + data[i] = x != 0 + } + case []int8: + for i, x := range bs { + data[i] = int8(x) + } + case []uint8: + copy(data, bs) + case []int16: + for i := range data { + data[i] = int16(order.Uint16(bs[2*i:])) + } + case []uint16: + for i := range data { + data[i] = order.Uint16(bs[2*i:]) + } + case []int32: + for i := range data { + data[i] = int32(order.Uint32(bs[4*i:])) + } + case []uint32: + for i := range data { + data[i] = order.Uint32(bs[4*i:]) + } + case []int64: + for i := range data { + data[i] = int64(order.Uint64(bs[8*i:])) + } + case []uint64: + for i := range data { + data[i] = order.Uint64(bs[8*i:]) + } + case []float32: + for i := range data { + data[i] = math.Float32frombits(order.Uint32(bs[4*i:])) + } + case []float64: + for i := range data { + data[i] = math.Float64frombits(order.Uint64(bs[8*i:])) + } + default: + return false + } + return true +} + // Write writes the binary representation of data into w. // Data must be a fixed-size value or a slice of fixed-size // values, or a pointer to such data. @@ -345,108 +391,12 @@ func Read(r io.Reader, order ByteOrder, data any) error { // with blank (_) field names. func Write(w io.Writer, order ByteOrder, data any) error { // Fast path for basic types and slices. - if n := intDataSize(data); n != 0 { - bs := make([]byte, n) - switch v := data.(type) { - case *bool: - if *v { - bs[0] = 1 - } else { - bs[0] = 0 - } - case bool: - if v { - bs[0] = 1 - } else { - bs[0] = 0 - } - case []bool: - for i, x := range v { - if x { - bs[i] = 1 - } else { - bs[i] = 0 - } - } - case *int8: - bs[0] = byte(*v) - case int8: - bs[0] = byte(v) - case []int8: - for i, x := range v { - bs[i] = byte(x) - } - case *uint8: - bs[0] = *v - case uint8: - bs[0] = v - case []uint8: - bs = v - case *int16: - order.PutUint16(bs, uint16(*v)) - case int16: - order.PutUint16(bs, uint16(v)) - case []int16: - for i, x := range v { - order.PutUint16(bs[2*i:], uint16(x)) - } - case *uint16: - order.PutUint16(bs, *v) - case uint16: - order.PutUint16(bs, v) - case []uint16: - for i, x := range v { - order.PutUint16(bs[2*i:], x) - } - case *int32: - order.PutUint32(bs, uint32(*v)) - case int32: - order.PutUint32(bs, uint32(v)) - case []int32: - for i, x := range v { - order.PutUint32(bs[4*i:], uint32(x)) - } - case *uint32: - order.PutUint32(bs, *v) - case uint32: - order.PutUint32(bs, v) - case []uint32: - for i, x := range v { - order.PutUint32(bs[4*i:], x) - } - case *int64: - order.PutUint64(bs, uint64(*v)) - case int64: - order.PutUint64(bs, uint64(v)) - case []int64: - for i, x := range v { - order.PutUint64(bs[8*i:], uint64(x)) - } - case *uint64: - order.PutUint64(bs, *v) - case uint64: - order.PutUint64(bs, v) - case []uint64: - for i, x := range v { - order.PutUint64(bs[8*i:], x) - } - case *float32: - order.PutUint32(bs, math.Float32bits(*v)) - case float32: - order.PutUint32(bs, math.Float32bits(v)) - case []float32: - for i, x := range v { - order.PutUint32(bs[4*i:], math.Float32bits(x)) - } - case *float64: - order.PutUint64(bs, math.Float64bits(*v)) - case float64: - order.PutUint64(bs, math.Float64bits(v)) - case []float64: - for i, x := range v { - order.PutUint64(bs[8*i:], math.Float64bits(x)) - } + if n, bs := intDataSize(data); n != 0 { + if bs == nil { + bs = make([]byte, n) + encodeFast(bs, order, data) } + _, err := w.Write(bs) return err } @@ -457,6 +407,7 @@ func Write(w io.Writer, order ByteOrder, data any) error { if size < 0 { return errors.New("binary.Write: some values are not fixed-sized in type " + reflect.TypeOf(data).String()) } + buf := make([]byte, size) e := &encoder{order: order, buf: buf} e.value(v) @@ -464,10 +415,259 @@ func Write(w io.Writer, order ByteOrder, data any) error { return err } +// Encode encodes the binary representation of data into buf according to +// the given byte order. +// It returns an error if buf is too small, otherwise the number of +// bytes written into buf. +func Encode(buf []byte, order ByteOrder, data any) (int, error) { + // Fast path for basic types and slices. + if n, _ := intDataSize(data); n != 0 { + if len(buf) < n { + return 0, errBufferTooSmall + } + + encodeFast(buf, order, data) + return n, nil + } + + // Fallback to reflect-based encoding. + v := reflect.Indirect(reflect.ValueOf(data)) + size := dataSize(v) + if size < 0 { + return 0, errors.New("binary.Encode: some values are not fixed-sized in type " + reflect.TypeOf(data).String()) + } + + if len(buf) < size { + return 0, errBufferTooSmall + } + e := &encoder{order: order, buf: buf} + e.value(v) + return size, nil +} + +// Append appends the binary representation of data to buf. +// buf may be nil, in which case a new buffer will be allocated. +// See [Write] on which data are acceptable. +// It returns the (possibily extended) buffer containing data or an error. +func Append(buf []byte, order ByteOrder, data any) ([]byte, error) { + // Fast path for basic types and slices. + if n, _ := intDataSize(data); n != 0 { + buf, pos := ensure(buf, n) + encodeFast(pos, order, data) + return buf, nil + } + + // Fallback to reflect-based encoding. + v := reflect.Indirect(reflect.ValueOf(data)) + size := dataSize(v) + if size < 0 { + return nil, errors.New("binary.Append: some values are not fixed-sized in type " + reflect.TypeOf(data).String()) + } + + buf, pos := ensure(buf, size) + e := &encoder{order: order, buf: pos} + e.value(v) + return buf, nil +} + +func encodeFast(bs []byte, order ByteOrder, data any) { + switch v := data.(type) { + case *bool: + if *v { + bs[0] = 1 + } else { + bs[0] = 0 + } + case bool: + if v { + bs[0] = 1 + } else { + bs[0] = 0 + } + case []bool: + for i, x := range v { + if x { + bs[i] = 1 + } else { + bs[i] = 0 + } + } + case *int8: + bs[0] = byte(*v) + case int8: + bs[0] = byte(v) + case []int8: + for i, x := range v { + bs[i] = byte(x) + } + case *uint8: + bs[0] = *v + case uint8: + bs[0] = v + case []uint8: + copy(bs, v) + case *int16: + order.PutUint16(bs, uint16(*v)) + case int16: + order.PutUint16(bs, uint16(v)) + case []int16: + for i, x := range v { + order.PutUint16(bs[2*i:], uint16(x)) + } + case *uint16: + order.PutUint16(bs, *v) + case uint16: + order.PutUint16(bs, v) + case []uint16: + for i, x := range v { + order.PutUint16(bs[2*i:], x) + } + case *int32: + order.PutUint32(bs, uint32(*v)) + case int32: + order.PutUint32(bs, uint32(v)) + case []int32: + for i, x := range v { + order.PutUint32(bs[4*i:], uint32(x)) + } + case *uint32: + order.PutUint32(bs, *v) + case uint32: + order.PutUint32(bs, v) + case []uint32: + for i, x := range v { + order.PutUint32(bs[4*i:], x) + } + case *int64: + order.PutUint64(bs, uint64(*v)) + case int64: + order.PutUint64(bs, uint64(v)) + case []int64: + for i, x := range v { + order.PutUint64(bs[8*i:], uint64(x)) + } + case *uint64: + order.PutUint64(bs, *v) + case uint64: + order.PutUint64(bs, v) + case []uint64: + for i, x := range v { + order.PutUint64(bs[8*i:], x) + } + case *float32: + order.PutUint32(bs, math.Float32bits(*v)) + case float32: + order.PutUint32(bs, math.Float32bits(v)) + case []float32: + for i, x := range v { + order.PutUint32(bs[4*i:], math.Float32bits(x)) + } + case *float64: + order.PutUint64(bs, math.Float64bits(*v)) + case float64: + order.PutUint64(bs, math.Float64bits(v)) + case []float64: + for i, x := range v { + order.PutUint64(bs[8*i:], math.Float64bits(x)) + } + } +} + // Size returns how many bytes [Write] would generate to encode the value v, which // must be a fixed-size value or a slice of fixed-size values, or a pointer to such data. // If v is neither of these, Size returns -1. func Size(v any) int { + switch data := v.(type) { + case bool, int8, uint8: + return 1 + case *bool: + if data == nil { + return -1 + } + return 1 + case *int8: + if data == nil { + return -1 + } + return 1 + case *uint8: + if data == nil { + return -1 + } + return 1 + case []bool: + return len(data) + case []int8: + return len(data) + case []uint8: + return len(data) + case int16, uint16: + return 2 + case *int16: + if data == nil { + return -1 + } + return 2 + case *uint16: + if data == nil { + return -1 + } + return 2 + case []int16: + return 2 * len(data) + case []uint16: + return 2 * len(data) + case int32, uint32: + return 4 + case *int32: + if data == nil { + return -1 + } + return 4 + case *uint32: + if data == nil { + return -1 + } + return 4 + case []int32: + return 4 * len(data) + case []uint32: + return 4 * len(data) + case int64, uint64: + return 8 + case *int64: + if data == nil { + return -1 + } + return 8 + case *uint64: + if data == nil { + return -1 + } + return 8 + case []int64: + return 8 * len(data) + case []uint64: + return 8 * len(data) + case float32: + return 4 + case *float32: + if data == nil { + return -1 + } + return 4 + case float64: + return 8 + case *float64: + if data == nil { + return -1 + } + return 8 + case []float32: + return 4 * len(data) + case []float64: + return 8 * len(data) + } return dataSize(reflect.Indirect(reflect.ValueOf(v))) } @@ -479,9 +679,18 @@ var structSize sync.Map // map[reflect.Type]int // occupied by the header. If the type of v is not acceptable, dataSize returns -1. func dataSize(v reflect.Value) int { switch v.Kind() { - case reflect.Slice: - if s := sizeof(v.Type().Elem()); s >= 0 { - return s * v.Len() + case reflect.Slice, reflect.Array: + t := v.Type().Elem() + if size, ok := structSize.Load(t); ok { + return size.(int) * v.Len() + } + + size := sizeof(t) + if size >= 0 { + if t.Kind() == reflect.Struct { + structSize.Store(t, size) + } + return size * v.Len() } case reflect.Struct: @@ -713,49 +922,37 @@ func (e *encoder) value(v reflect.Value) { case reflect.Bool: e.bool(v.Bool()) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - switch v.Type().Kind() { - case reflect.Int8: - e.int8(int8(v.Int())) - case reflect.Int16: - e.int16(int16(v.Int())) - case reflect.Int32: - e.int32(int32(v.Int())) - case reflect.Int64: - e.int64(v.Int()) - } - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - switch v.Type().Kind() { - case reflect.Uint8: - e.uint8(uint8(v.Uint())) - case reflect.Uint16: - e.uint16(uint16(v.Uint())) - case reflect.Uint32: - e.uint32(uint32(v.Uint())) - case reflect.Uint64: - e.uint64(v.Uint()) - } - - case reflect.Float32, reflect.Float64: - switch v.Type().Kind() { - case reflect.Float32: - e.uint32(math.Float32bits(float32(v.Float()))) - case reflect.Float64: - e.uint64(math.Float64bits(v.Float())) - } - - case reflect.Complex64, reflect.Complex128: - switch v.Type().Kind() { - case reflect.Complex64: - x := v.Complex() - e.uint32(math.Float32bits(float32(real(x)))) - e.uint32(math.Float32bits(float32(imag(x)))) - case reflect.Complex128: - x := v.Complex() - e.uint64(math.Float64bits(real(x))) - e.uint64(math.Float64bits(imag(x))) - } + case reflect.Int8: + e.int8(int8(v.Int())) + case reflect.Int16: + e.int16(int16(v.Int())) + case reflect.Int32: + e.int32(int32(v.Int())) + case reflect.Int64: + e.int64(v.Int()) + + case reflect.Uint8: + e.uint8(uint8(v.Uint())) + case reflect.Uint16: + e.uint16(uint16(v.Uint())) + case reflect.Uint32: + e.uint32(uint32(v.Uint())) + case reflect.Uint64: + e.uint64(v.Uint()) + + case reflect.Float32: + e.uint32(math.Float32bits(float32(v.Float()))) + case reflect.Float64: + e.uint64(math.Float64bits(v.Float())) + + case reflect.Complex64: + x := v.Complex() + e.uint32(math.Float32bits(float32(real(x)))) + e.uint32(math.Float32bits(float32(imag(x)))) + case reflect.Complex128: + x := v.Complex() + e.uint64(math.Float64bits(real(x))) + e.uint64(math.Float64bits(imag(x))) } } @@ -765,51 +962,57 @@ func (d *decoder) skip(v reflect.Value) { func (e *encoder) skip(v reflect.Value) { n := dataSize(v) - zero := e.buf[e.offset : e.offset+n] - for i := range zero { - zero[i] = 0 - } + clear(e.buf[e.offset : e.offset+n]) e.offset += n } -// intDataSize returns the size of the data required to represent the data when encoded. -// It returns zero if the type cannot be implemented by the fast path in Read or Write. -func intDataSize(data any) int { +// intDataSize returns the size of the data required to represent the data when encoded, +// and optionally a byte slice containing the encoded data if no conversion is necessary. +// It returns zero, nil if the type cannot be implemented by the fast path in Read or Write. +func intDataSize(data any) (int, []byte) { switch data := data.(type) { case bool, int8, uint8, *bool, *int8, *uint8: - return 1 + return 1, nil case []bool: - return len(data) + return len(data), nil case []int8: - return len(data) + return len(data), nil case []uint8: - return len(data) + return len(data), data case int16, uint16, *int16, *uint16: - return 2 + return 2, nil case []int16: - return 2 * len(data) + return 2 * len(data), nil case []uint16: - return 2 * len(data) + return 2 * len(data), nil case int32, uint32, *int32, *uint32: - return 4 + return 4, nil case []int32: - return 4 * len(data) + return 4 * len(data), nil case []uint32: - return 4 * len(data) + return 4 * len(data), nil case int64, uint64, *int64, *uint64: - return 8 + return 8, nil case []int64: - return 8 * len(data) + return 8 * len(data), nil case []uint64: - return 8 * len(data) + return 8 * len(data), nil case float32, *float32: - return 4 + return 4, nil case float64, *float64: - return 8 + return 8, nil case []float32: - return 4 * len(data) + return 4 * len(data), nil case []float64: - return 8 * len(data) + return 8 * len(data), nil } - return 0 + return 0, nil +} + +// ensure grows buf to length len(buf) + n and returns the grown buffer +// and a slice starting at the original length of buf (that is, buf2[len(buf):]). +func ensure(buf []byte, n int) (buf2, pos []byte) { + l := len(buf) + buf = slices.Grow(buf, n)[:l+n] + return buf, buf[l:] } diff --git a/contrib/go/_std_1.22/src/encoding/binary/native_endian_big.go b/contrib/go/_std_1.23/src/encoding/binary/native_endian_big.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/binary/native_endian_big.go rename to contrib/go/_std_1.23/src/encoding/binary/native_endian_big.go diff --git a/contrib/go/_std_1.22/src/encoding/binary/native_endian_little.go b/contrib/go/_std_1.23/src/encoding/binary/native_endian_little.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/binary/native_endian_little.go rename to contrib/go/_std_1.23/src/encoding/binary/native_endian_little.go diff --git a/contrib/go/_std_1.22/src/encoding/binary/varint.go b/contrib/go/_std_1.23/src/encoding/binary/varint.go similarity index 95% rename from contrib/go/_std_1.22/src/encoding/binary/varint.go rename to contrib/go/_std_1.23/src/encoding/binary/varint.go index 64dd9d61b443..c92ef82e823f 100644 --- a/contrib/go/_std_1.22/src/encoding/binary/varint.go +++ b/contrib/go/_std_1.23/src/encoding/binary/varint.go @@ -62,10 +62,9 @@ func PutUvarint(buf []byte, x uint64) int { // Uvarint decodes a uint64 from buf and returns that value and the // number of bytes read (> 0). If an error occurred, the value is 0 // and the number of bytes n is <= 0 meaning: -// -// n == 0: buf too small -// n < 0: value larger than 64 bits (overflow) -// and -n is the number of bytes read +// - n == 0: buf too small; +// - n < 0: value larger than 64 bits (overflow) and -n is the number of +// bytes read. func Uvarint(buf []byte) (uint64, int) { var x uint64 var s uint @@ -110,10 +109,9 @@ func PutVarint(buf []byte, x int64) int { // Varint decodes an int64 from buf and returns that value and the // number of bytes read (> 0). If an error occurred, the value is 0 // and the number of bytes n is <= 0 with the following meaning: -// -// n == 0: buf too small -// n < 0: value larger than 64 bits (overflow) -// and -n is the number of bytes read +// - n == 0: buf too small; +// - n < 0: value larger than 64 bits (overflow) +// and -n is the number of bytes read. func Varint(buf []byte) (int64, int) { ux, n := Uvarint(buf) // ok to continue in presence of error x := int64(ux >> 1) diff --git a/contrib/go/_std_1.22/src/encoding/binary/ya.make b/contrib/go/_std_1.23/src/encoding/binary/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/binary/ya.make rename to contrib/go/_std_1.23/src/encoding/binary/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/csv/reader.go b/contrib/go/_std_1.23/src/encoding/csv/reader.go similarity index 99% rename from contrib/go/_std_1.22/src/encoding/csv/reader.go rename to contrib/go/_std_1.23/src/encoding/csv/reader.go index d9cab865726c..df4702feded4 100644 --- a/contrib/go/_std_1.22/src/encoding/csv/reader.go +++ b/contrib/go/_std_1.23/src/encoding/csv/reader.go @@ -4,7 +4,8 @@ // Package csv reads and writes comma-separated values (CSV) files. // There are many kinds of CSV files; this package supports the format -// described in RFC 4180. +// described in RFC 4180, except that [Writer] uses LF +// instead of CRLF as newline character by default. // // A csv file contains zero or more records of one or more fields per record. // Each record is separated by the newline character. The final record may diff --git a/contrib/go/_std_1.22/src/encoding/csv/writer.go b/contrib/go/_std_1.23/src/encoding/csv/writer.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/csv/writer.go rename to contrib/go/_std_1.23/src/encoding/csv/writer.go diff --git a/contrib/go/_std_1.22/src/encoding/csv/ya.make b/contrib/go/_std_1.23/src/encoding/csv/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/csv/ya.make rename to contrib/go/_std_1.23/src/encoding/csv/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/encoding.go b/contrib/go/_std_1.23/src/encoding/encoding.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/encoding.go rename to contrib/go/_std_1.23/src/encoding/encoding.go diff --git a/contrib/go/_std_1.22/src/encoding/gob/debug.go b/contrib/go/_std_1.23/src/encoding/gob/debug.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/gob/debug.go rename to contrib/go/_std_1.23/src/encoding/gob/debug.go diff --git a/contrib/go/_std_1.22/src/encoding/gob/dec_helpers.go b/contrib/go/_std_1.23/src/encoding/gob/dec_helpers.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/gob/dec_helpers.go rename to contrib/go/_std_1.23/src/encoding/gob/dec_helpers.go diff --git a/contrib/go/_std_1.22/src/encoding/gob/decgen.go b/contrib/go/_std_1.23/src/encoding/gob/decgen.go similarity index 98% rename from contrib/go/_std_1.22/src/encoding/gob/decgen.go rename to contrib/go/_std_1.23/src/encoding/gob/decgen.go index 27a30eaf61ab..af4cdbee9dfd 100644 --- a/contrib/go/_std_1.22/src/encoding/gob/decgen.go +++ b/contrib/go/_std_1.23/src/encoding/gob/decgen.go @@ -192,6 +192,9 @@ func main() { if _, err := fd.Write(source); err != nil { log.Fatal(err) } + if err := fd.Close(); err != nil { + log.Fatal(err) + } } func printMaps(b *bytes.Buffer, upperClass string) { diff --git a/contrib/go/_std_1.22/src/encoding/gob/decode.go b/contrib/go/_std_1.23/src/encoding/gob/decode.go similarity index 98% rename from contrib/go/_std_1.22/src/encoding/gob/decode.go rename to contrib/go/_std_1.23/src/encoding/gob/decode.go index d178b2b2fb64..26b5f6d62b63 100644 --- a/contrib/go/_std_1.22/src/encoding/gob/decode.go +++ b/contrib/go/_std_1.23/src/encoding/gob/decode.go @@ -911,8 +911,11 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg var maxIgnoreNestingDepth = 10000 // decIgnoreOpFor returns the decoding op for a field that has no destination. -func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp, depth int) *decOp { - if depth > maxIgnoreNestingDepth { +func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp) *decOp { + // Track how deep we've recursed trying to skip nested ignored fields. + dec.ignoreDepth++ + defer func() { dec.ignoreDepth-- }() + if dec.ignoreDepth > maxIgnoreNestingDepth { error_(errors.New("invalid nesting depth")) } // If this type is already in progress, it's a recursive type (e.g. map[string]*T). @@ -938,7 +941,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp, errorf("bad data: undefined type %s", wireId.string()) case wire.ArrayT != nil: elemId := wire.ArrayT.Elem - elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1) + elemOp := dec.decIgnoreOpFor(elemId, inProgress) op = func(i *decInstr, state *decoderState, value reflect.Value) { state.dec.ignoreArray(state, *elemOp, wire.ArrayT.Len) } @@ -946,15 +949,15 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp, case wire.MapT != nil: keyId := dec.wireType[wireId].MapT.Key elemId := dec.wireType[wireId].MapT.Elem - keyOp := dec.decIgnoreOpFor(keyId, inProgress, depth+1) - elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1) + keyOp := dec.decIgnoreOpFor(keyId, inProgress) + elemOp := dec.decIgnoreOpFor(elemId, inProgress) op = func(i *decInstr, state *decoderState, value reflect.Value) { state.dec.ignoreMap(state, *keyOp, *elemOp) } case wire.SliceT != nil: elemId := wire.SliceT.Elem - elemOp := dec.decIgnoreOpFor(elemId, inProgress, depth+1) + elemOp := dec.decIgnoreOpFor(elemId, inProgress) op = func(i *decInstr, state *decoderState, value reflect.Value) { state.dec.ignoreSlice(state, *elemOp) } @@ -1115,7 +1118,7 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de func (dec *Decoder) compileIgnoreSingle(remoteId typeId) *decEngine { engine := new(decEngine) engine.instr = make([]decInstr, 1) // one item - op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp), 0) + op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp)) ovfl := overflow(dec.typeString(remoteId)) engine.instr[0] = decInstr{*op, 0, nil, ovfl} engine.numInstr = 1 @@ -1160,7 +1163,7 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn localField, present := srt.FieldByName(wireField.Name) // TODO(r): anonymous names if !present || !isExported(wireField.Name) { - op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp), 0) + op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp)) engine.instr[fieldnum] = decInstr{*op, fieldnum, nil, ovfl} continue } diff --git a/contrib/go/_std_1.22/src/encoding/gob/decoder.go b/contrib/go/_std_1.23/src/encoding/gob/decoder.go similarity index 98% rename from contrib/go/_std_1.22/src/encoding/gob/decoder.go rename to contrib/go/_std_1.23/src/encoding/gob/decoder.go index c4b608801307..eae307838e20 100644 --- a/contrib/go/_std_1.22/src/encoding/gob/decoder.go +++ b/contrib/go/_std_1.23/src/encoding/gob/decoder.go @@ -35,6 +35,8 @@ type Decoder struct { freeList *decoderState // list of free decoderStates; avoids reallocation countBuf []byte // used for decoding integers while parsing messages err error + // ignoreDepth tracks the depth of recursively parsed ignored fields + ignoreDepth int } // NewDecoder returns a new decoder that reads from the [io.Reader]. diff --git a/contrib/go/_std_1.22/src/encoding/gob/doc.go b/contrib/go/_std_1.23/src/encoding/gob/doc.go similarity index 99% rename from contrib/go/_std_1.22/src/encoding/gob/doc.go rename to contrib/go/_std_1.23/src/encoding/gob/doc.go index 3f26ed859199..30e7978b7c9d 100644 --- a/contrib/go/_std_1.22/src/encoding/gob/doc.go +++ b/contrib/go/_std_1.23/src/encoding/gob/doc.go @@ -67,7 +67,7 @@ arbitrary precision unsigned integers. There is no int8, int16 etc. discrimination in the gob format; there are only signed and unsigned integers. As described below, the transmitter sends the value in a variable-length encoding; the receiver accepts the value and stores it in the destination variable. -Floating-point numbers are always sent using IEEE-754 64-bit precision (see +Floating-point numbers are always sent using IEEE 754 64-bit precision (see below). Signed integers may be received into any signed integer variable: int, int16, etc.; diff --git a/contrib/go/_std_1.22/src/encoding/gob/dump.go b/contrib/go/_std_1.23/src/encoding/gob/dump.go similarity index 96% rename from contrib/go/_std_1.22/src/encoding/gob/dump.go rename to contrib/go/_std_1.23/src/encoding/gob/dump.go index f4b1bebfba1d..b14d84164bcf 100644 --- a/contrib/go/_std_1.22/src/encoding/gob/dump.go +++ b/contrib/go/_std_1.23/src/encoding/gob/dump.go @@ -24,6 +24,7 @@ func main() { fmt.Fprintf(os.Stderr, "dump: %s\n", err) os.Exit(1) } + defer file.Close() } gob.Debug(file) } diff --git a/contrib/go/_std_1.22/src/encoding/gob/enc_helpers.go b/contrib/go/_std_1.23/src/encoding/gob/enc_helpers.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/gob/enc_helpers.go rename to contrib/go/_std_1.23/src/encoding/gob/enc_helpers.go diff --git a/contrib/go/_std_1.22/src/encoding/gob/encgen.go b/contrib/go/_std_1.23/src/encoding/gob/encgen.go similarity index 98% rename from contrib/go/_std_1.22/src/encoding/gob/encgen.go rename to contrib/go/_std_1.23/src/encoding/gob/encgen.go index e5f68786a060..64f5c69bd44d 100644 --- a/contrib/go/_std_1.22/src/encoding/gob/encgen.go +++ b/contrib/go/_std_1.23/src/encoding/gob/encgen.go @@ -170,6 +170,9 @@ func main() { if _, err := fd.Write(source); err != nil { log.Fatal(err) } + if err := fd.Close(); err != nil { + log.Fatal(err) + } } func printMaps(b *bytes.Buffer, upperClass string) { diff --git a/contrib/go/_std_1.22/src/encoding/gob/encode.go b/contrib/go/_std_1.23/src/encoding/gob/encode.go similarity index 99% rename from contrib/go/_std_1.22/src/encoding/gob/encode.go rename to contrib/go/_std_1.23/src/encoding/gob/encode.go index c83071c71727..5f4d2539faaf 100644 --- a/contrib/go/_std_1.22/src/encoding/gob/encode.go +++ b/contrib/go/_std_1.23/src/encoding/gob/encode.go @@ -601,7 +601,7 @@ func compileEnc(ut *userTypeInfo, building map[*typeInfo]bool) *encEngine { if ut.externalEnc == 0 && srt.Kind() == reflect.Struct { for fieldNum, wireFieldNum := 0, 0; fieldNum < srt.NumField(); fieldNum++ { f := srt.Field(fieldNum) - if !isSent(srt, &f) { + if !isSent(&f) { continue } op, indir := encOpFor(f.Type, seen, building) diff --git a/contrib/go/_std_1.22/src/encoding/gob/encoder.go b/contrib/go/_std_1.23/src/encoding/gob/encoder.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/gob/encoder.go rename to contrib/go/_std_1.23/src/encoding/gob/encoder.go diff --git a/contrib/go/_std_1.22/src/encoding/gob/error.go b/contrib/go/_std_1.23/src/encoding/gob/error.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/gob/error.go rename to contrib/go/_std_1.23/src/encoding/gob/error.go diff --git a/contrib/go/_std_1.22/src/encoding/gob/type.go b/contrib/go/_std_1.23/src/encoding/gob/type.go similarity index 98% rename from contrib/go/_std_1.22/src/encoding/gob/type.go rename to contrib/go/_std_1.23/src/encoding/gob/type.go index 3b1dde492c28..c3ac1dbd61fd 100644 --- a/contrib/go/_std_1.22/src/encoding/gob/type.go +++ b/contrib/go/_std_1.23/src/encoding/gob/type.go @@ -538,7 +538,7 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, err idToTypeSlice[st.id()] = st for i := 0; i < t.NumField(); i++ { f := t.Field(i) - if !isSent(t, &f) { + if !isSent(&f) { continue } typ := userType(f.Type).base @@ -576,7 +576,7 @@ func isExported(name string) bool { // isSent reports whether this struct field is to be transmitted. // It will be transmitted only if it is exported and not a chan or func field // or pointer to chan or func. -func isSent(struct_ reflect.Type, field *reflect.StructField) bool { +func isSent(field *reflect.StructField) bool { if !isExported(field.Name) { return false } @@ -590,16 +590,6 @@ func isSent(struct_ reflect.Type, field *reflect.StructField) bool { return false } - // Special case for Go 1.22: the x509.Certificate.Policies - // field is unencodable but also unused by default. - // Ignore it, so that x509.Certificate continues to be encodeable. - // Go 1.23 will add the right methods so that gob can - // handle the Policies field, and then we can remove this check. - // See go.dev/issue/65633. - if field.Name == "Policies" && struct_.PkgPath() == "crypto/x509" && struct_.Name() == "Certificate" { - return false - } - return true } diff --git a/contrib/go/_std_1.22/src/encoding/gob/ya.make b/contrib/go/_std_1.23/src/encoding/gob/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/gob/ya.make rename to contrib/go/_std_1.23/src/encoding/gob/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/hex/hex.go b/contrib/go/_std_1.23/src/encoding/hex/hex.go similarity index 97% rename from contrib/go/_std_1.22/src/encoding/hex/hex.go rename to contrib/go/_std_1.23/src/encoding/hex/hex.go index 791d2bd4adfa..ba9cc0f967f6 100644 --- a/contrib/go/_std_1.22/src/encoding/hex/hex.go +++ b/contrib/go/_std_1.23/src/encoding/hex/hex.go @@ -136,11 +136,9 @@ func EncodeToString(src []byte) string { // If the input is malformed, DecodeString returns // the bytes decoded before the error. func DecodeString(s string) ([]byte, error) { - src := []byte(s) - // We can use the source slice itself as the destination - // because the decode loop increments by one and then the 'seen' byte is not used anymore. - n, err := Decode(src, src) - return src[:n], err + dst := make([]byte, DecodedLen(len(s))) + n, err := Decode(dst, []byte(s)) + return dst[:n], err } // Dump returns a string that contains a hex dump of the given data. The format diff --git a/contrib/go/_std_1.22/src/encoding/hex/ya.make b/contrib/go/_std_1.23/src/encoding/hex/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/hex/ya.make rename to contrib/go/_std_1.23/src/encoding/hex/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/json/decode.go b/contrib/go/_std_1.23/src/encoding/json/decode.go similarity index 98% rename from contrib/go/_std_1.22/src/encoding/json/decode.go rename to contrib/go/_std_1.23/src/encoding/json/decode.go index bc1891f8ace3..f8205704e38b 100644 --- a/contrib/go/_std_1.22/src/encoding/json/decode.go +++ b/contrib/go/_std_1.23/src/encoding/json/decode.go @@ -17,6 +17,7 @@ import ( "unicode" "unicode/utf16" "unicode/utf8" + _ "unsafe" // for linkname ) // Unmarshal parses the JSON-encoded data and stores the result @@ -72,8 +73,7 @@ import ( // use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal // reuses the existing map, keeping existing entries. Unmarshal then stores // key-value pairs from the JSON object into the map. The map's key type must -// either be any string type, an integer, implement [json.Unmarshaler], or -// implement [encoding.TextUnmarshaler]. +// either be any string type, an integer, or implement [encoding.TextUnmarshaler]. // // If the JSON-encoded data contain a syntax error, Unmarshal returns a [SyntaxError]. // @@ -776,7 +776,7 @@ func (d *decodeState) object(v reflect.Value) error { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: s := string(key) n, err := strconv.ParseInt(s, 10, 64) - if err != nil || reflect.Zero(kt).OverflowInt(n) { + if err != nil || kt.OverflowInt(n) { d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) break } @@ -785,7 +785,7 @@ func (d *decodeState) object(v reflect.Value) error { case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: s := string(key) n, err := strconv.ParseUint(s, 10, 64) - if err != nil || reflect.Zero(kt).OverflowUint(n) { + if err != nil || kt.OverflowUint(n) { d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) break } @@ -943,10 +943,11 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool } v.SetBytes(b[:n]) case reflect.String: - if v.Type() == numberType && !isValidNumber(string(s)) { + t := string(s) + if v.Type() == numberType && !isValidNumber(t) { return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item) } - v.SetString(string(s)) + v.SetString(t) case reflect.Interface: if v.NumMethod() == 0 { v.Set(reflect.ValueOf(string(s))) @@ -1177,6 +1178,15 @@ func unquote(s []byte) (t string, ok bool) { return } +// unquoteBytes should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname unquoteBytes func unquoteBytes(s []byte) (t []byte, ok bool) { if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { return diff --git a/contrib/go/_std_1.22/src/encoding/json/encode.go b/contrib/go/_std_1.23/src/encoding/json/encode.go similarity index 97% rename from contrib/go/_std_1.22/src/encoding/json/encode.go rename to contrib/go/_std_1.23/src/encoding/json/encode.go index d6f6900dc969..7bee1a6805f4 100644 --- a/contrib/go/_std_1.22/src/encoding/json/encode.go +++ b/contrib/go/_std_1.23/src/encoding/json/encode.go @@ -12,18 +12,19 @@ package json import ( "bytes" + "cmp" "encoding" "encoding/base64" "fmt" "math" "reflect" "slices" - "sort" "strconv" "strings" "sync" "unicode" "unicode/utf8" + _ "unsafe" // for linkname ) // Marshal returns the JSON encoding of v. @@ -140,7 +141,7 @@ import ( // are sorted and used as JSON object keys by applying the following rules, // subject to the UTF-8 coercion described for string values above: // - keys of any string type are used directly -// - [encoding.TextMarshalers] are marshaled +// - keys that implement [encoding.TextMarshaler] are marshaled // - integer keys are converted to strings // // Pointer values encode as the value pointed to. @@ -591,6 +592,16 @@ func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) { } // isValidNumber reports whether s is a valid JSON number literal. +// +// isValidNumber should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname isValidNumber func isValidNumber(s string) bool { // This function implements the JSON numbers grammar. // See https://tools.ietf.org/html/rfc7159#section-6 @@ -1042,28 +1053,19 @@ type field struct { encoder encoderFunc } -// byIndex sorts field by index sequence. -type byIndex []field - -func (x byIndex) Len() int { return len(x) } - -func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } - -func (x byIndex) Less(i, j int) bool { - for k, xik := range x[i].index { - if k >= len(x[j].index) { - return false - } - if xik != x[j].index[k] { - return xik < x[j].index[k] - } - } - return len(x[i].index) < len(x[j].index) -} - // typeFields returns a list of fields that JSON should recognize for the given type. // The algorithm is breadth-first search over the set of structs to include - the top struct // and then any reachable anonymous structs. +// +// typeFields should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname typeFields func typeFields(t reflect.Type) structFields { // Anonymous fields to explore at the current level and the next. current := []field{} @@ -1181,21 +1183,23 @@ func typeFields(t reflect.Type) structFields { } } - sort.Slice(fields, func(i, j int) bool { - x := fields + slices.SortFunc(fields, func(a, b field) int { // sort field by name, breaking ties with depth, then // breaking ties with "name came from json tag", then // breaking ties with index sequence. - if x[i].name != x[j].name { - return x[i].name < x[j].name + if c := strings.Compare(a.name, b.name); c != 0 { + return c } - if len(x[i].index) != len(x[j].index) { - return len(x[i].index) < len(x[j].index) + if c := cmp.Compare(len(a.index), len(b.index)); c != 0 { + return c } - if x[i].tag != x[j].tag { - return x[i].tag + if a.tag != b.tag { + if a.tag { + return -1 + } + return +1 } - return byIndex(x).Less(i, j) + return slices.Compare(a.index, b.index) }) // Delete all fields that are hidden by the Go rules for embedded fields, @@ -1227,7 +1231,9 @@ func typeFields(t reflect.Type) structFields { } fields = out - sort.Sort(byIndex(fields)) + slices.SortFunc(fields, func(i, j field) int { + return slices.Compare(i.index, j.index) + }) for i := range fields { f := &fields[i] diff --git a/contrib/go/_std_1.22/src/encoding/json/fold.go b/contrib/go/_std_1.23/src/encoding/json/fold.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/json/fold.go rename to contrib/go/_std_1.23/src/encoding/json/fold.go diff --git a/contrib/go/_std_1.22/src/encoding/json/indent.go b/contrib/go/_std_1.23/src/encoding/json/indent.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/json/indent.go rename to contrib/go/_std_1.23/src/encoding/json/indent.go diff --git a/contrib/go/_std_1.22/src/encoding/json/scanner.go b/contrib/go/_std_1.23/src/encoding/json/scanner.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/json/scanner.go rename to contrib/go/_std_1.23/src/encoding/json/scanner.go diff --git a/contrib/go/_std_1.22/src/encoding/json/stream.go b/contrib/go/_std_1.23/src/encoding/json/stream.go similarity index 99% rename from contrib/go/_std_1.22/src/encoding/json/stream.go rename to contrib/go/_std_1.23/src/encoding/json/stream.go index 5c98d1de0494..cb61ea721207 100644 --- a/contrib/go/_std_1.22/src/encoding/json/stream.go +++ b/contrib/go/_std_1.23/src/encoding/json/stream.go @@ -194,6 +194,7 @@ func NewEncoder(w io.Writer) *Encoder { } // Encode writes the JSON encoding of v to the stream, +// with insignificant space characters elided, // followed by a newline character. // // See the documentation for [Marshal] for details about the diff --git a/contrib/go/_std_1.22/src/encoding/json/tables.go b/contrib/go/_std_1.23/src/encoding/json/tables.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/json/tables.go rename to contrib/go/_std_1.23/src/encoding/json/tables.go diff --git a/contrib/go/_std_1.22/src/encoding/json/tags.go b/contrib/go/_std_1.23/src/encoding/json/tags.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/json/tags.go rename to contrib/go/_std_1.23/src/encoding/json/tags.go diff --git a/contrib/go/_std_1.22/src/encoding/json/ya.make b/contrib/go/_std_1.23/src/encoding/json/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/json/ya.make rename to contrib/go/_std_1.23/src/encoding/json/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/pem/pem.go b/contrib/go/_std_1.23/src/encoding/pem/pem.go similarity index 99% rename from contrib/go/_std_1.22/src/encoding/pem/pem.go rename to contrib/go/_std_1.23/src/encoding/pem/pem.go index 4b4f74902101..7a515fd3632b 100644 --- a/contrib/go/_std_1.22/src/encoding/pem/pem.go +++ b/contrib/go/_std_1.23/src/encoding/pem/pem.go @@ -12,7 +12,7 @@ import ( "encoding/base64" "errors" "io" - "sort" + "slices" "strings" ) @@ -274,7 +274,7 @@ func Encode(out io.Writer, b *Block) error { } } // For consistency of output, write other headers sorted by key. - sort.Strings(h) + slices.Sort(h) for _, k := range h { if err := writeHeader(out, k, b.Headers[k]); err != nil { return err diff --git a/contrib/go/_std_1.22/src/encoding/pem/ya.make b/contrib/go/_std_1.23/src/encoding/pem/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/pem/ya.make rename to contrib/go/_std_1.23/src/encoding/pem/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/xml/marshal.go b/contrib/go/_std_1.23/src/encoding/xml/marshal.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/xml/marshal.go rename to contrib/go/_std_1.23/src/encoding/xml/marshal.go diff --git a/contrib/go/_std_1.22/src/encoding/xml/read.go b/contrib/go/_std_1.23/src/encoding/xml/read.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/xml/read.go rename to contrib/go/_std_1.23/src/encoding/xml/read.go diff --git a/contrib/go/_std_1.22/src/encoding/xml/typeinfo.go b/contrib/go/_std_1.23/src/encoding/xml/typeinfo.go similarity index 100% rename from contrib/go/_std_1.22/src/encoding/xml/typeinfo.go rename to contrib/go/_std_1.23/src/encoding/xml/typeinfo.go diff --git a/contrib/go/_std_1.22/src/encoding/xml/xml.go b/contrib/go/_std_1.23/src/encoding/xml/xml.go similarity index 99% rename from contrib/go/_std_1.22/src/encoding/xml/xml.go rename to contrib/go/_std_1.23/src/encoding/xml/xml.go index 73eedad290f3..0fe323f7c86a 100644 --- a/contrib/go/_std_1.22/src/encoding/xml/xml.go +++ b/contrib/go/_std_1.23/src/encoding/xml/xml.go @@ -492,8 +492,12 @@ func (d *Decoder) popElement(t *EndElement) bool { d.err = d.syntaxError("element <" + s.name.Local + "> closed by ") return false case s.name.Space != name.Space: + ns := name.Space + if name.Space == "" { + ns = `""` + } d.err = d.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space + - " closed by in space " + name.Space) + " closed by in space " + ns) return false } @@ -2045,16 +2049,27 @@ func procInst(param, s string) string { // TODO: this parsing is somewhat lame and not exact. // It works for all actual cases, though. param = param + "=" - _, v, _ := strings.Cut(s, param) - if v == "" { - return "" + lenp := len(param) + i := 0 + var sep byte + for i < len(s) { + sub := s[i:] + k := strings.Index(sub, param) + if k < 0 || lenp+k >= len(sub) { + return "" + } + i += lenp + k + 1 + if c := sub[lenp+k]; c == '\'' || c == '"' { + sep = c + break + } } - if v[0] != '\'' && v[0] != '"' { + if sep == 0 { return "" } - unquote, _, ok := strings.Cut(v[1:], v[:1]) - if !ok { + j := strings.IndexByte(s[i:], sep) + if j < 0 { return "" } - return unquote + return s[i : i+j] } diff --git a/contrib/go/_std_1.22/src/encoding/xml/ya.make b/contrib/go/_std_1.23/src/encoding/xml/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/xml/ya.make rename to contrib/go/_std_1.23/src/encoding/xml/ya.make diff --git a/contrib/go/_std_1.22/src/encoding/ya.make b/contrib/go/_std_1.23/src/encoding/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/encoding/ya.make rename to contrib/go/_std_1.23/src/encoding/ya.make diff --git a/contrib/go/_std_1.22/src/errors/errors.go b/contrib/go/_std_1.23/src/errors/errors.go similarity index 100% rename from contrib/go/_std_1.22/src/errors/errors.go rename to contrib/go/_std_1.23/src/errors/errors.go diff --git a/contrib/go/_std_1.22/src/errors/join.go b/contrib/go/_std_1.23/src/errors/join.go similarity index 100% rename from contrib/go/_std_1.22/src/errors/join.go rename to contrib/go/_std_1.23/src/errors/join.go diff --git a/contrib/go/_std_1.22/src/errors/wrap.go b/contrib/go/_std_1.23/src/errors/wrap.go similarity index 97% rename from contrib/go/_std_1.22/src/errors/wrap.go rename to contrib/go/_std_1.23/src/errors/wrap.go index 88ee0a9281f2..eec9591dae7b 100644 --- a/contrib/go/_std_1.22/src/errors/wrap.go +++ b/contrib/go/_std_1.23/src/errors/wrap.go @@ -42,7 +42,7 @@ func Unwrap(err error) error { // an example in the standard library. An Is method should only shallowly // compare err and the target and not call [Unwrap] on either. func Is(err, target error) bool { - if target == nil { + if err == nil || target == nil { return err == target } @@ -85,7 +85,7 @@ func is(err, target error, targetComparable bool) bool { // errors, As examines err followed by a depth-first traversal of its children. // // An error matches target if the error's concrete value is assignable to the value -// pointed to by target, or if the error has a method As(interface{}) bool such that +// pointed to by target, or if the error has a method As(any) bool such that // As(target) returns true. In the latter case, the As method is responsible for // setting target. // diff --git a/contrib/go/_std_1.22/src/errors/ya.make b/contrib/go/_std_1.23/src/errors/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/errors/ya.make rename to contrib/go/_std_1.23/src/errors/ya.make diff --git a/contrib/go/_std_1.22/src/flag/flag.go b/contrib/go/_std_1.23/src/flag/flag.go similarity index 99% rename from contrib/go/_std_1.22/src/flag/flag.go rename to contrib/go/_std_1.23/src/flag/flag.go index 1669e9aca7f2..4fa502839ada 100644 --- a/contrib/go/_std_1.22/src/flag/flag.go +++ b/contrib/go/_std_1.23/src/flag/flag.go @@ -90,7 +90,7 @@ import ( "os" "reflect" "runtime" - "sort" + "slices" "strconv" "strings" "time" @@ -420,8 +420,8 @@ func sortFlags(flags map[string]*Flag) []*Flag { result[i] = f i++ } - sort.Slice(result, func(i, j int) bool { - return result[i].Name < result[j].Name + slices.SortFunc(result, func(a, b *Flag) int { + return strings.Compare(a.Name, b.Name) }) return result } diff --git a/contrib/go/_std_1.22/src/flag/ya.make b/contrib/go/_std_1.23/src/flag/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/flag/ya.make rename to contrib/go/_std_1.23/src/flag/ya.make diff --git a/contrib/go/_std_1.22/src/fmt/doc.go b/contrib/go/_std_1.23/src/fmt/doc.go similarity index 89% rename from contrib/go/_std_1.22/src/fmt/doc.go rename to contrib/go/_std_1.23/src/fmt/doc.go index 1cda484d8ab2..d8ff6465433a 100644 --- a/contrib/go/_std_1.22/src/fmt/doc.go +++ b/contrib/go/_std_1.23/src/fmt/doc.go @@ -16,6 +16,7 @@ General: %v the value in a default format when printing structs, the plus flag (%+v) adds field names %#v a Go-syntax representation of the value + (floating-point infinities and NaNs print as ±Inf and NaN) %T a Go-syntax representation of the type of the value %% a literal percent sign; consumes no value @@ -127,7 +128,7 @@ to 1.2+3.4i produces (1.200000+3.400000i). When formatting a single integer code point or a rune string (type []rune) with %q, invalid Unicode code points are changed to the Unicode replacement -character, U+FFFD, as in strconv.QuoteRune. +character, U+FFFD, as in [strconv.QuoteRune]. Other flags: @@ -136,16 +137,15 @@ Other flags: '-' pad with spaces on the right rather than the left (left-justify the field) '#' alternate format: add leading 0b for binary (%#b), 0 for octal (%#o), 0x or 0X for hex (%#x or %#X); suppress 0x for %p (%#p); - for %q, print a raw (backquoted) string if strconv.CanBackquote + for %q, print a raw (backquoted) string if [strconv.CanBackquote] returns true; always print a decimal point for %e, %E, %f, %F, %g and %G; do not remove trailing zeros for %g and %G; - write e.g. U+0078 'x' if the character is printable for %U (%#U). + write e.g. U+0078 'x' if the character is printable for %U (%#U) ' ' (space) leave a space for elided sign in numbers (% d); put spaces between bytes printing strings or slices in hex (% x, % X) '0' pad with leading zeros rather than spaces; - for numbers, this moves the padding after the sign; - ignored for strings, byte slices and byte arrays + for numbers, this moves the padding after the sign Flags are ignored by verbs that do not expect them. For example there is no alternate decimal format, so %#d and %d @@ -169,17 +169,17 @@ Except when printed using the verbs %T and %p, special formatting considerations apply for operands that implement certain interfaces. In order of application: -1. If the operand is a reflect.Value, the operand is replaced by the +1. If the operand is a [reflect.Value], the operand is replaced by the concrete value that it holds, and printing continues with the next rule. -2. If an operand implements the Formatter interface, it will +2. If an operand implements the [Formatter] interface, it will be invoked. In this case the interpretation of verbs and flags is controlled by that implementation. 3. If the %v verb is used with the # flag (%#v) and the operand -implements the GoStringer interface, that will be invoked. +implements the [GoStringer] interface, that will be invoked. -If the format (which is implicitly %v for Println etc.) is valid +If the format (which is implicitly %v for [Println] etc.) is valid for a string (%s %q %x %X), or is %v but not %#v, the following two rules apply: @@ -219,7 +219,7 @@ formatting methods such as Error or String on unexported fields. # Explicit argument indexes -In Printf, Sprintf, and Fprintf, the default behavior is for each +In [Printf], [Sprintf], and [Fprintf], the default behavior is for each formatting verb to format successive arguments passed in the call. However, the notation [n] immediately before the verb indicates that the nth one-indexed argument is to be formatted instead. The same notation @@ -287,17 +287,17 @@ string, "". # Scanning An analogous set of functions scans formatted text to yield -values. Scan, Scanf and Scanln read from os.Stdin; Fscan, -Fscanf and Fscanln read from a specified io.Reader; Sscan, -Sscanf and Sscanln read from an argument string. +values. [Scan], [Scanf] and [Scanln] read from [os.Stdin]; [Fscan], +[Fscanf] and [Fscanln] read from a specified [io.Reader]; [Sscan], +[Sscanf] and [Sscanln] read from an argument string. -Scan, Fscan, Sscan treat newlines in the input as spaces. +[Scan], [Fscan], [Sscan] treat newlines in the input as spaces. -Scanln, Fscanln and Sscanln stop scanning at a newline and +[Scanln], [Fscanln] and [Sscanln] stop scanning at a newline and require that the items be followed by a newline or EOF. -Scanf, Fscanf, and Sscanf parse the arguments according to a -format string, analogous to that of Printf. In the text that +[Scanf], [Fscanf], and [Sscanf] parse the arguments according to a +format string, analogous to that of [Printf]. In the text that follows, 'space' means any Unicode whitespace character except newline. @@ -320,10 +320,10 @@ scanf family: in C, newlines are treated as any other space, and it is never an error when a run of spaces in the format string finds no spaces to consume in the input. -The verbs behave analogously to those of Printf. +The verbs behave analogously to those of [Printf]. For example, %x will scan an integer as a hexadecimal number, and %v will scan the default representation format for the value. -The Printf verbs %p and %T and the flags # and + are not implemented. +The [Printf] verbs %p and %T and the flags # and + are not implemented. For floating-point and complex values, all valid formatting verbs (%b %e %E %f %F %g %G %x %X and %v) are equivalent and accept both decimal and hexadecimal notation (for example: "2.3e+7", "0x4.5p-8") @@ -359,26 +359,26 @@ immediately by a newline is treated as a plain newline (\r\n means the same as \n). In all the scanning functions, if an operand implements method -Scan (that is, it implements the Scanner interface) that +[Scan] (that is, it implements the [Scanner] interface) that method will be used to scan the text for that operand. Also, if the number of arguments scanned is less than the number of arguments provided, an error is returned. All arguments to be scanned must be either pointers to basic -types or implementations of the Scanner interface. +types or implementations of the [Scanner] interface. -Like Scanf and Fscanf, Sscanf need not consume its entire input. -There is no way to recover how much of the input string Sscanf used. +Like [Scanf] and [Fscanf], [Sscanf] need not consume its entire input. +There is no way to recover how much of the input string [Sscanf] used. -Note: Fscan etc. can read one character (rune) past the input +Note: [Fscan] etc. can read one character (rune) past the input they return, which means that a loop calling a scan routine may skip some of the input. This is usually a problem only when there is no space between input values. If the reader -provided to Fscan implements ReadRune, that method will be used +provided to [Fscan] implements ReadRune, that method will be used to read characters. If the reader also implements UnreadRune, that method will be used to save the character and successive calls will not lose data. To attach ReadRune and UnreadRune methods to a reader without that capability, use -bufio.NewReader. +[bufio.NewReader]. */ package fmt diff --git a/contrib/go/_std_1.22/src/fmt/errors.go b/contrib/go/_std_1.23/src/fmt/errors.go similarity index 97% rename from contrib/go/_std_1.22/src/fmt/errors.go rename to contrib/go/_std_1.23/src/fmt/errors.go index 1fbd39f8f17b..1ac83404bc7c 100644 --- a/contrib/go/_std_1.22/src/fmt/errors.go +++ b/contrib/go/_std_1.23/src/fmt/errors.go @@ -6,7 +6,7 @@ package fmt import ( "errors" - "sort" + "slices" ) // Errorf formats according to a format specifier and returns the string as a @@ -34,7 +34,7 @@ func Errorf(format string, a ...any) error { err = w default: if p.reordered { - sort.Ints(p.wrappedErrs) + slices.Sort(p.wrappedErrs) } var errs []error for i, argNum := range p.wrappedErrs { diff --git a/contrib/go/_std_1.22/src/fmt/format.go b/contrib/go/_std_1.23/src/fmt/format.go similarity index 97% rename from contrib/go/_std_1.22/src/fmt/format.go rename to contrib/go/_std_1.23/src/fmt/format.go index 617f78f15ea2..90e18cd69637 100644 --- a/contrib/go/_std_1.22/src/fmt/format.go +++ b/contrib/go/_std_1.23/src/fmt/format.go @@ -53,6 +53,8 @@ type fmt struct { func (f *fmt) clearflags() { f.fmtFlags = fmtFlags{} + f.wid = 0 + f.prec = 0 } func (f *fmt) init(buf *buffer) { @@ -75,7 +77,8 @@ func (f *fmt) writePadding(n int) { } // Decide which byte the padding should be filled with. padByte := byte(' ') - if f.zero { + // Zero padding is allowed only to the left. + if f.zero && !f.minus { padByte = byte('0') } // Fill padding with padByte. @@ -223,7 +226,7 @@ func (f *fmt) fmtInteger(u uint64, base int, isSigned bool, verb rune, digits st f.zero = oldZero return } - } else if f.zero && f.widPresent { + } else if f.zero && !f.minus && f.widPresent { // Zero padding is allowed only to the left. prec = f.wid if negative || f.plus || f.space { prec-- // leave room for sign @@ -580,7 +583,8 @@ func (f *fmt) fmtFloat(v float64, size int, verb rune, prec int) { if f.plus || num[0] != '+' { // If we're zero padding to the left we want the sign before the leading zeros. // Achieve this by writing the sign out and then padding the unsigned number. - if f.zero && f.widPresent && f.wid > len(num) { + // Zero padding is allowed only to the left. + if f.zero && !f.minus && f.widPresent && f.wid > len(num) { f.buf.writeByte(num[0]) f.writePadding(f.wid - len(num)) f.buf.write(num[1:]) diff --git a/contrib/go/_std_1.22/src/fmt/print.go b/contrib/go/_std_1.23/src/fmt/print.go similarity index 97% rename from contrib/go/_std_1.22/src/fmt/print.go rename to contrib/go/_std_1.23/src/fmt/print.go index cb393bd76370..f9f200499dc3 100644 --- a/contrib/go/_std_1.22/src/fmt/print.go +++ b/contrib/go/_std_1.23/src/fmt/print.go @@ -34,7 +34,7 @@ const ( ) // State represents the printer state passed to custom formatters. -// It provides access to the io.Writer interface plus information about +// It provides access to the [io.Writer] interface plus information about // the flags and options for the operand's format specifier. type State interface { // Write is the function to call to emit formatted output to be printed. @@ -49,8 +49,8 @@ type State interface { } // Formatter is implemented by any value that has a Format method. -// The implementation controls how State and rune are interpreted, -// and may call Sprint() or Fprint(f) etc. to generate its output. +// The implementation controls how [State] and rune are interpreted, +// and may call [Sprint] or [Fprint](f) etc. to generate its output. type Formatter interface { Format(f State, verb rune) } @@ -59,7 +59,7 @@ type Formatter interface { // which defines the “native” format for that value. // The String method is used to print values passed as an operand // to any format that accepts a string or to an unformatted printer -// such as Print. +// such as [Print]. type Stringer interface { String() string } @@ -73,10 +73,10 @@ type GoStringer interface { } // FormatString returns a string representing the fully qualified formatting -// directive captured by the State, followed by the argument verb. (State does not +// directive captured by the [State], followed by the argument verb. ([State] does not // itself contain the verb.) The result has a leading percent sign followed by any // flags, the width, and the precision. Missing flags, width, and precision are -// omitted. This function allows a Formatter to reconstruct the original +// omitted. This function allows a [Formatter] to reconstruct the original // directive triggering the call to Format. func FormatString(state State, verb rune) string { var tmp [16]byte // Use a local buffer. @@ -201,14 +201,14 @@ func (p *pp) Flag(b int) bool { return false } -// Implement Write so we can call Fprintf on a pp (through State), for +// Implement Write so we can call [Fprintf] on a pp (through [State]), for // recursive use in custom verbs. func (p *pp) Write(b []byte) (ret int, err error) { p.buf.write(b) return len(b), nil } -// Implement WriteString so that we can call io.WriteString +// Implement WriteString so that we can call [io.WriteString] // on a pp (through state), for efficiency. func (p *pp) WriteString(s string) (ret int, err error) { p.buf.writeString(s) @@ -814,7 +814,7 @@ func (p *pp) printValue(value reflect.Value, verb rune, depth int) { p.buf.writeString(mapString) } sorted := fmtsort.Sort(f) - for i, key := range sorted.Key { + for i, m := range sorted { if i > 0 { if p.fmt.sharpV { p.buf.writeString(commaSpaceString) @@ -822,9 +822,9 @@ func (p *pp) printValue(value reflect.Value, verb rune, depth int) { p.buf.writeByte(' ') } } - p.printValue(key, verb, depth+1) + p.printValue(m.Key, verb, depth+1) p.buf.writeByte(':') - p.printValue(sorted.Value[i], verb, depth+1) + p.printValue(m.Value, verb, depth+1) } if p.fmt.sharpV { p.buf.writeByte('}') @@ -1048,12 +1048,11 @@ formatLoop: case '#': p.fmt.sharp = true case '0': - p.fmt.zero = !p.fmt.minus // Only allow zero padding to the left. + p.fmt.zero = true case '+': p.fmt.plus = true case '-': p.fmt.minus = true - p.fmt.zero = false // Do not pad with zeros to the right. case ' ': p.fmt.space = true default: diff --git a/contrib/go/_std_1.22/src/fmt/scan.go b/contrib/go/_std_1.23/src/fmt/scan.go similarity index 99% rename from contrib/go/_std_1.22/src/fmt/scan.go rename to contrib/go/_std_1.23/src/fmt/scan.go index 5dd0971642d1..d8c7d263e059 100644 --- a/contrib/go/_std_1.22/src/fmt/scan.go +++ b/contrib/go/_std_1.23/src/fmt/scan.go @@ -51,7 +51,7 @@ type ScanState interface { // Scanner is implemented by any value that has a Scan method, which scans // the input for the representation of a value and stores the result in the // receiver, which must be a pointer to be useful. The Scan method is called -// for any argument to Scan, Scanf, or Scanln that implements it. +// for any argument to [Scan], [Scanf], or [Scanln] that implements it. type Scanner interface { Scan(state ScanState, verb rune) error } @@ -64,7 +64,7 @@ func Scan(a ...any) (n int, err error) { return Fscan(os.Stdin, a...) } -// Scanln is similar to Scan, but stops scanning at a newline and +// Scanln is similar to [Scan], but stops scanning at a newline and // after the final item there must be a newline or EOF. func Scanln(a ...any) (n int, err error) { return Fscanln(os.Stdin, a...) @@ -100,7 +100,7 @@ func Sscan(str string, a ...any) (n int, err error) { return Fscan((*stringReader)(&str), a...) } -// Sscanln is similar to Sscan, but stops scanning at a newline and +// Sscanln is similar to [Sscan], but stops scanning at a newline and // after the final item there must be a newline or EOF. func Sscanln(str string, a ...any) (n int, err error) { return Fscanln((*stringReader)(&str), a...) @@ -125,7 +125,7 @@ func Fscan(r io.Reader, a ...any) (n int, err error) { return } -// Fscanln is similar to Fscan, but stops scanning at a newline and +// Fscanln is similar to [Fscan], but stops scanning at a newline and // after the final item there must be a newline or EOF. func Fscanln(r io.Reader, a ...any) (n int, err error) { s, old := newScanState(r, false, true) @@ -416,7 +416,7 @@ func (s *ss) free(old ssave) { // SkipSpace provides Scan methods the ability to skip space and newline // characters in keeping with the current scanning mode set by format strings -// and Scan/Scanln. +// and [Scan]/[Scanln]. func (s *ss) SkipSpace() { for { r := s.getRune() diff --git a/contrib/go/_std_1.22/src/fmt/ya.make b/contrib/go/_std_1.23/src/fmt/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/fmt/ya.make rename to contrib/go/_std_1.23/src/fmt/ya.make diff --git a/contrib/go/_std_1.22/src/go/ast/ast.go b/contrib/go/_std_1.23/src/go/ast/ast.go similarity index 99% rename from contrib/go/_std_1.22/src/go/ast/ast.go rename to contrib/go/_std_1.23/src/go/ast/ast.go index ef96cc4a6dfa..73aa3da89eab 100644 --- a/contrib/go/_std_1.22/src/go/ast/ast.go +++ b/contrib/go/_std_1.23/src/go/ast/ast.go @@ -1032,9 +1032,12 @@ func (*FuncDecl) declNode() {} // positions). A [CommentMap] may be used to facilitate some of these operations. // // Whether and how a comment is associated with a node depends on the -// interpretation of the syntax tree by the manipulating program: Except for Doc +// interpretation of the syntax tree by the manipulating program: except for Doc // and [Comment] comments directly associated with nodes, the remaining comments -// are "free-floating" (see also issues #18593, #20744). +// are "free-floating" (see also issues [#18593], [#20744]). +// +// [#18593]: https://go.dev/issue/18593 +// [#20744]: https://go.dev/issue/20744 type File struct { Doc *CommentGroup // associated documentation; or nil Package token.Pos // position of "package" keyword @@ -1080,7 +1083,7 @@ func (p *Package) End() token.Pos { return token.NoPos } // not handwritten, by detecting the special comment described // at https://go.dev/s/generatedcode. // -// The syntax tree must have been parsed with the ParseComments flag. +// The syntax tree must have been parsed with the [parser.ParseComments] flag. // Example: // // f, err := parser.ParseFile(fset, filename, src, parser.ParseComments|parser.PackageClauseOnly) diff --git a/contrib/go/_std_1.22/src/go/ast/commentmap.go b/contrib/go/_std_1.23/src/go/ast/commentmap.go similarity index 94% rename from contrib/go/_std_1.22/src/go/ast/commentmap.go rename to contrib/go/_std_1.23/src/go/ast/commentmap.go index a9488f50723d..b62fe489e4ee 100644 --- a/contrib/go/_std_1.22/src/go/ast/commentmap.go +++ b/contrib/go/_std_1.23/src/go/ast/commentmap.go @@ -6,26 +6,18 @@ package ast import ( "bytes" + "cmp" "fmt" "go/token" - "sort" + "slices" "strings" ) -type byPos []*CommentGroup - -func (a byPos) Len() int { return len(a) } -func (a byPos) Less(i, j int) bool { return a[i].Pos() < a[j].Pos() } -func (a byPos) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - // sortComments sorts the list of comment groups in source order. func sortComments(list []*CommentGroup) { - // TODO(gri): Does it make sense to check for sorted-ness - // first (because we know that sorted-ness is - // very likely)? - if orderedList := byPos(list); !sort.IsSorted(orderedList) { - sort.Sort(orderedList) - } + slices.SortFunc(list, func(a, b *CommentGroup) int { + return cmp.Compare(a.Pos(), b.Pos()) + }) } // A CommentMap maps an AST node to a list of comment groups @@ -64,11 +56,19 @@ func nodeList(n Node) []Node { list = append(list, n) return true }) + // Note: The current implementation assumes that Inspect traverses the // AST in depth-first and thus _source_ order. If AST traversal // does not follow source order, the sorting call below will be // required. - // sort.Sort(byInterval(list)) + // slices.Sort(list, func(a, b Node) int { + // r := cmp.Compare(a.Pos(), b.Pos()) + // if r != 0 { + // return r + // } + // return cmp.Compare(a.End(), b.End()) + // }) + return list } @@ -310,7 +310,13 @@ func (cmap CommentMap) String() string { for node := range cmap { nodes = append(nodes, node) } - sort.Sort(byInterval(nodes)) + slices.SortFunc(nodes, func(a, b Node) int { + r := cmp.Compare(a.Pos(), b.Pos()) + if r != 0 { + return r + } + return cmp.Compare(a.End(), b.End()) + }) var buf strings.Builder fmt.Fprintln(&buf, "CommentMap {") diff --git a/contrib/go/_std_1.22/src/go/ast/filter.go b/contrib/go/_std_1.23/src/go/ast/filter.go similarity index 99% rename from contrib/go/_std_1.22/src/go/ast/filter.go rename to contrib/go/_std_1.23/src/go/ast/filter.go index 5c12ed16147d..89682846dfa3 100644 --- a/contrib/go/_std_1.22/src/go/ast/filter.go +++ b/contrib/go/_std_1.23/src/go/ast/filter.go @@ -6,7 +6,7 @@ package ast import ( "go/token" - "sort" + "slices" ) // ---------------------------------------------------------------------------- @@ -357,7 +357,7 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File { maxPos = f.FileEnd } } - sort.Strings(filenames) + slices.Sort(filenames) // Collect package comments from all package files into a single // CommentGroup - the collected package documentation. In general diff --git a/contrib/go/_std_1.22/src/go/ast/import.go b/contrib/go/_std_1.23/src/go/ast/import.go similarity index 92% rename from contrib/go/_std_1.22/src/go/ast/import.go rename to contrib/go/_std_1.23/src/go/ast/import.go index 7fdf137d146f..17f0db470f70 100644 --- a/contrib/go/_std_1.22/src/go/ast/import.go +++ b/contrib/go/_std_1.23/src/go/ast/import.go @@ -5,8 +5,9 @@ package ast import ( + "cmp" "go/token" - "sort" + "slices" "strconv" ) @@ -172,18 +173,20 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec { // Reassign the import paths to have the same position sequence. // Reassign each comment to the spec on the same line. // Sort the comments by new position. - sort.Slice(specs, func(i, j int) bool { - ipath := importPath(specs[i]) - jpath := importPath(specs[j]) - if ipath != jpath { - return ipath < jpath + slices.SortFunc(specs, func(a, b Spec) int { + ipath := importPath(a) + jpath := importPath(b) + r := cmp.Compare(ipath, jpath) + if r != 0 { + return r } - iname := importName(specs[i]) - jname := importName(specs[j]) - if iname != jname { - return iname < jname + iname := importName(a) + jname := importName(b) + r = cmp.Compare(iname, jname) + if r != 0 { + return r } - return importComment(specs[i]) < importComment(specs[j]) + return cmp.Compare(importComment(a), importComment(b)) }) // Dedup. Thanks to our sorting, we can just consider @@ -222,8 +225,8 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec { } } - sort.Slice(comments, func(i, j int) bool { - return comments[i].Pos() < comments[j].Pos() + slices.SortFunc(comments, func(a, b *CommentGroup) int { + return cmp.Compare(a.Pos(), b.Pos()) }) return specs diff --git a/contrib/go/_std_1.22/src/go/ast/print.go b/contrib/go/_std_1.23/src/go/ast/print.go similarity index 98% rename from contrib/go/_std_1.22/src/go/ast/print.go rename to contrib/go/_std_1.23/src/go/ast/print.go index d1aad50103a8..ccef0577da0f 100644 --- a/contrib/go/_std_1.22/src/go/ast/print.go +++ b/contrib/go/_std_1.23/src/go/ast/print.go @@ -17,8 +17,8 @@ import ( // A FieldFilter may be provided to [Fprint] to control the output. type FieldFilter func(name string, value reflect.Value) bool -// NotNilFilter returns true for field values that are not nil; -// it returns false otherwise. +// NotNilFilter is a [FieldFilter] that returns true for field values +// that are not nil; it returns false otherwise. func NotNilFilter(_ string, v reflect.Value) bool { switch v.Kind() { case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice: diff --git a/contrib/go/_std_1.22/src/go/ast/resolve.go b/contrib/go/_std_1.23/src/go/ast/resolve.go similarity index 100% rename from contrib/go/_std_1.22/src/go/ast/resolve.go rename to contrib/go/_std_1.23/src/go/ast/resolve.go diff --git a/contrib/go/_std_1.22/src/go/ast/scope.go b/contrib/go/_std_1.23/src/go/ast/scope.go similarity index 98% rename from contrib/go/_std_1.22/src/go/ast/scope.go rename to contrib/go/_std_1.23/src/go/ast/scope.go index 039ca58bc092..9d97e24e298d 100644 --- a/contrib/go/_std_1.22/src/go/ast/scope.go +++ b/contrib/go/_std_1.23/src/go/ast/scope.go @@ -144,10 +144,10 @@ func (obj *Object) Pos() token.Pos { return token.NoPos } -// ObjKind describes what an object represents. +// ObjKind describes what an [Object] represents. type ObjKind int -// The list of possible Object kinds. +// The list of possible [Object] kinds. const ( Bad ObjKind = iota // for error handling Pkg // package diff --git a/contrib/go/_std_1.22/src/go/ast/walk.go b/contrib/go/_std_1.23/src/go/ast/walk.go similarity index 85% rename from contrib/go/_std_1.22/src/go/ast/walk.go rename to contrib/go/_std_1.23/src/go/ast/walk.go index 87e190f08ada..ec9a8901c4aa 100644 --- a/contrib/go/_std_1.22/src/go/ast/walk.go +++ b/contrib/go/_std_1.23/src/go/ast/walk.go @@ -4,7 +4,10 @@ package ast -import "fmt" +import ( + "fmt" + "iter" +) // A Visitor's Visit method is invoked for each node encountered by [Walk]. // If the result visitor w is not nil, [Walk] visits each of the children @@ -13,29 +16,9 @@ type Visitor interface { Visit(node Node) (w Visitor) } -// Helper functions for common node lists. They may be empty. - -func walkIdentList(v Visitor, list []*Ident) { - for _, x := range list { - Walk(v, x) - } -} - -func walkExprList(v Visitor, list []Expr) { - for _, x := range list { - Walk(v, x) - } -} - -func walkStmtList(v Visitor, list []Stmt) { - for _, x := range list { - Walk(v, x) - } -} - -func walkDeclList(v Visitor, list []Decl) { - for _, x := range list { - Walk(v, x) +func walkList[N Node](v Visitor, list []N) { + for _, node := range list { + Walk(v, node) } } @@ -61,15 +44,13 @@ func Walk(v Visitor, node Node) { // nothing to do case *CommentGroup: - for _, c := range n.List { - Walk(v, c) - } + walkList(v, n.List) case *Field: if n.Doc != nil { Walk(v, n.Doc) } - walkIdentList(v, n.Names) + walkList(v, n.Names) if n.Type != nil { Walk(v, n.Type) } @@ -81,9 +62,7 @@ func Walk(v Visitor, node Node) { } case *FieldList: - for _, f := range n.List { - Walk(v, f) - } + walkList(v, n.List) // Expressions case *BadExpr, *Ident, *BasicLit: @@ -102,7 +81,7 @@ func Walk(v Visitor, node Node) { if n.Type != nil { Walk(v, n.Type) } - walkExprList(v, n.Elts) + walkList(v, n.Elts) case *ParenExpr: Walk(v, n.X) @@ -117,9 +96,7 @@ func Walk(v Visitor, node Node) { case *IndexListExpr: Walk(v, n.X) - for _, index := range n.Indices { - Walk(v, index) - } + walkList(v, n.Indices) case *SliceExpr: Walk(v, n.X) @@ -141,7 +118,7 @@ func Walk(v Visitor, node Node) { case *CallExpr: Walk(v, n.Fun) - walkExprList(v, n.Args) + walkList(v, n.Args) case *StarExpr: Walk(v, n.X) @@ -213,8 +190,8 @@ func Walk(v Visitor, node Node) { Walk(v, n.X) case *AssignStmt: - walkExprList(v, n.Lhs) - walkExprList(v, n.Rhs) + walkList(v, n.Lhs) + walkList(v, n.Rhs) case *GoStmt: Walk(v, n.Call) @@ -223,7 +200,7 @@ func Walk(v Visitor, node Node) { Walk(v, n.Call) case *ReturnStmt: - walkExprList(v, n.Results) + walkList(v, n.Results) case *BranchStmt: if n.Label != nil { @@ -231,7 +208,7 @@ func Walk(v Visitor, node Node) { } case *BlockStmt: - walkStmtList(v, n.List) + walkList(v, n.List) case *IfStmt: if n.Init != nil { @@ -244,8 +221,8 @@ func Walk(v Visitor, node Node) { } case *CaseClause: - walkExprList(v, n.List) - walkStmtList(v, n.Body) + walkList(v, n.List) + walkList(v, n.Body) case *SwitchStmt: if n.Init != nil { @@ -267,7 +244,7 @@ func Walk(v Visitor, node Node) { if n.Comm != nil { Walk(v, n.Comm) } - walkStmtList(v, n.Body) + walkList(v, n.Body) case *SelectStmt: Walk(v, n.Body) @@ -311,11 +288,11 @@ func Walk(v Visitor, node Node) { if n.Doc != nil { Walk(v, n.Doc) } - walkIdentList(v, n.Names) + walkList(v, n.Names) if n.Type != nil { Walk(v, n.Type) } - walkExprList(v, n.Values) + walkList(v, n.Values) if n.Comment != nil { Walk(v, n.Comment) } @@ -340,9 +317,7 @@ func Walk(v Visitor, node Node) { if n.Doc != nil { Walk(v, n.Doc) } - for _, s := range n.Specs { - Walk(v, s) - } + walkList(v, n.Specs) case *FuncDecl: if n.Doc != nil { @@ -363,7 +338,7 @@ func Walk(v Visitor, node Node) { Walk(v, n.Doc) } Walk(v, n.Name) - walkDeclList(v, n.Decls) + walkList(v, n.Decls) // don't walk n.Comments - they have been // visited already through the individual // nodes @@ -396,3 +371,21 @@ func (f inspector) Visit(node Node) Visitor { func Inspect(node Node, f func(Node) bool) { Walk(inspector(f), node) } + +// Preorder returns an iterator over all the nodes of the syntax tree +// beneath (and including) the specified root, in depth-first +// preorder. +// +// For greater control over the traversal of each subtree, use [Inspect]. +func Preorder(root Node) iter.Seq[Node] { + return func(yield func(Node) bool) { + ok := true + Inspect(root, func(n Node) bool { + if n != nil { + // yield must not be called once ok is false. + ok = ok && yield(n) + } + return ok + }) + } +} diff --git a/contrib/go/_std_1.22/src/go/ast/ya.make b/contrib/go/_std_1.23/src/go/ast/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/go/ast/ya.make rename to contrib/go/_std_1.23/src/go/ast/ya.make diff --git a/contrib/go/_std_1.22/src/go/build/constraint/expr.go b/contrib/go/_std_1.23/src/go/build/constraint/expr.go similarity index 95% rename from contrib/go/_std_1.22/src/go/build/constraint/expr.go rename to contrib/go/_std_1.23/src/go/build/constraint/expr.go index e59012361bef..0f05f8db6a48 100644 --- a/contrib/go/_std_1.22/src/go/build/constraint/expr.go +++ b/contrib/go/_std_1.23/src/go/build/constraint/expr.go @@ -16,6 +16,10 @@ import ( "unicode/utf8" ) +// maxSize is a limit used to control the complexity of expressions, in order +// to prevent stack exhaustion issues due to recursion. +const maxSize = 1000 + // An Expr is a build tag constraint expression. // The underlying concrete type is *[AndExpr], *[OrExpr], *[NotExpr], or *[TagExpr]. type Expr interface { @@ -151,7 +155,7 @@ func Parse(line string) (Expr, error) { return parseExpr(text) } if text, ok := splitPlusBuild(line); ok { - return parsePlusBuildExpr(text), nil + return parsePlusBuildExpr(text) } return nil, errNotConstraint } @@ -201,6 +205,8 @@ type exprParser struct { tok string // last token read isTag bool pos int // position (start) of last token + + size int } // parseExpr parses a boolean build tag expression. @@ -249,6 +255,10 @@ func (p *exprParser) and() Expr { // On entry, the next input token has not yet been lexed. // On exit, the next input token has been lexed and is in p.tok. func (p *exprParser) not() Expr { + p.size++ + if p.size > maxSize { + panic(&SyntaxError{Offset: p.pos, Err: "build expression too large"}) + } p.lex() if p.tok == "!" { p.lex() @@ -388,7 +398,13 @@ func splitPlusBuild(line string) (expr string, ok bool) { } // parsePlusBuildExpr parses a legacy build tag expression (as used with “// +build”). -func parsePlusBuildExpr(text string) Expr { +func parsePlusBuildExpr(text string) (Expr, error) { + // Only allow up to 100 AND/OR operators for "old" syntax. + // This is much less than the limit for "new" syntax, + // but uses of old syntax were always very simple. + const maxOldSize = 100 + size := 0 + var x Expr for _, clause := range strings.Fields(text) { var y Expr @@ -414,19 +430,25 @@ func parsePlusBuildExpr(text string) Expr { if y == nil { y = z } else { + if size++; size > maxOldSize { + return nil, errComplex + } y = and(y, z) } } if x == nil { x = y } else { + if size++; size > maxOldSize { + return nil, errComplex + } x = or(x, y) } } if x == nil { x = tag("ignore") } - return x + return x, nil } // isValidTag reports whether the word is a valid build tag. diff --git a/contrib/go/_std_1.22/src/go/build/constraint/vers.go b/contrib/go/_std_1.23/src/go/build/constraint/vers.go similarity index 100% rename from contrib/go/_std_1.22/src/go/build/constraint/vers.go rename to contrib/go/_std_1.23/src/go/build/constraint/vers.go diff --git a/contrib/go/_std_1.22/src/go/build/constraint/ya.make b/contrib/go/_std_1.23/src/go/build/constraint/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/go/build/constraint/ya.make rename to contrib/go/_std_1.23/src/go/build/constraint/ya.make diff --git a/contrib/go/_std_1.22/src/go/constant/kind_string.go b/contrib/go/_std_1.23/src/go/constant/kind_string.go similarity index 100% rename from contrib/go/_std_1.22/src/go/constant/kind_string.go rename to contrib/go/_std_1.23/src/go/constant/kind_string.go diff --git a/contrib/go/_std_1.22/src/go/constant/value.go b/contrib/go/_std_1.23/src/go/constant/value.go similarity index 100% rename from contrib/go/_std_1.22/src/go/constant/value.go rename to contrib/go/_std_1.23/src/go/constant/value.go diff --git a/contrib/go/_std_1.22/src/go/constant/ya.make b/contrib/go/_std_1.23/src/go/constant/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/go/constant/ya.make rename to contrib/go/_std_1.23/src/go/constant/ya.make diff --git a/contrib/go/_std_1.22/src/go/doc/comment/doc.go b/contrib/go/_std_1.23/src/go/doc/comment/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/go/doc/comment/doc.go rename to contrib/go/_std_1.23/src/go/doc/comment/doc.go diff --git a/contrib/go/_std_1.22/src/go/doc/comment/html.go b/contrib/go/_std_1.23/src/go/doc/comment/html.go similarity index 100% rename from contrib/go/_std_1.22/src/go/doc/comment/html.go rename to contrib/go/_std_1.23/src/go/doc/comment/html.go diff --git a/contrib/go/_std_1.22/src/go/doc/comment/markdown.go b/contrib/go/_std_1.23/src/go/doc/comment/markdown.go similarity index 100% rename from contrib/go/_std_1.22/src/go/doc/comment/markdown.go rename to contrib/go/_std_1.23/src/go/doc/comment/markdown.go diff --git a/contrib/go/_std_1.22/src/go/doc/comment/parse.go b/contrib/go/_std_1.23/src/go/doc/comment/parse.go similarity index 100% rename from contrib/go/_std_1.22/src/go/doc/comment/parse.go rename to contrib/go/_std_1.23/src/go/doc/comment/parse.go diff --git a/contrib/go/_std_1.22/src/go/doc/comment/print.go b/contrib/go/_std_1.23/src/go/doc/comment/print.go similarity index 100% rename from contrib/go/_std_1.22/src/go/doc/comment/print.go rename to contrib/go/_std_1.23/src/go/doc/comment/print.go diff --git a/contrib/go/_std_1.22/src/go/doc/comment/std.go b/contrib/go/_std_1.23/src/go/doc/comment/std.go similarity index 95% rename from contrib/go/_std_1.22/src/go/doc/comment/std.go rename to contrib/go/_std_1.23/src/go/doc/comment/std.go index fd8c8ce3c230..f6958512c22f 100644 --- a/contrib/go/_std_1.22/src/go/doc/comment/std.go +++ b/contrib/go/_std_1.23/src/go/doc/comment/std.go @@ -23,6 +23,7 @@ var stdPkgs = []string{ "html", "image", "io", + "iter", "log", "maps", "math", @@ -38,10 +39,12 @@ var stdPkgs = []string{ "sort", "strconv", "strings", + "structs", "sync", "syscall", "testing", "time", "unicode", + "unique", "unsafe", } diff --git a/contrib/go/_std_1.22/src/go/doc/comment/text.go b/contrib/go/_std_1.23/src/go/doc/comment/text.go similarity index 100% rename from contrib/go/_std_1.22/src/go/doc/comment/text.go rename to contrib/go/_std_1.23/src/go/doc/comment/text.go diff --git a/contrib/go/_std_1.22/src/go/doc/comment/ya.make b/contrib/go/_std_1.23/src/go/doc/comment/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/go/doc/comment/ya.make rename to contrib/go/_std_1.23/src/go/doc/comment/ya.make diff --git a/contrib/go/_std_1.22/src/go/internal/typeparams/typeparams.go b/contrib/go/_std_1.23/src/go/internal/typeparams/typeparams.go similarity index 58% rename from contrib/go/_std_1.22/src/go/internal/typeparams/typeparams.go rename to contrib/go/_std_1.23/src/go/internal/typeparams/typeparams.go index 3f84f2f0d05a..0bddf737d313 100644 --- a/contrib/go/_std_1.22/src/go/internal/typeparams/typeparams.go +++ b/contrib/go/_std_1.23/src/go/internal/typeparams/typeparams.go @@ -33,22 +33,42 @@ func PackIndexExpr(x ast.Expr, lbrack token.Pos, exprs []ast.Expr, rbrack token. // IndexExpr wraps an ast.IndexExpr or ast.IndexListExpr. // // Orig holds the original ast.Expr from which this IndexExpr was derived. +// +// Note: IndexExpr (intentionally) does not wrap ast.Expr, as that leads to +// accidental misuse such as encountered in golang/go#63933. +// +// TODO(rfindley): remove this helper, in favor of just having a helper +// function that returns indices. type IndexExpr struct { - Orig ast.Expr // the wrapped expr, which may be distinct from the IndexListExpr below. - *ast.IndexListExpr + Orig ast.Expr // the wrapped expr, which may be distinct from the IndexListExpr below. + X ast.Expr // expression + Lbrack token.Pos // position of "[" + Indices []ast.Expr // index expressions + Rbrack token.Pos // position of "]" +} + +func (x *IndexExpr) Pos() token.Pos { + return x.Orig.Pos() } func UnpackIndexExpr(n ast.Node) *IndexExpr { switch e := n.(type) { case *ast.IndexExpr: - return &IndexExpr{e, &ast.IndexListExpr{ + return &IndexExpr{ + Orig: e, X: e.X, Lbrack: e.Lbrack, Indices: []ast.Expr{e.Index}, Rbrack: e.Rbrack, - }} + } case *ast.IndexListExpr: - return &IndexExpr{e, e} + return &IndexExpr{ + Orig: e, + X: e.X, + Lbrack: e.Lbrack, + Indices: e.Indices, + Rbrack: e.Rbrack, + } } return nil } diff --git a/contrib/go/_std_1.22/src/go/internal/typeparams/ya.make b/contrib/go/_std_1.23/src/go/internal/typeparams/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/go/internal/typeparams/ya.make rename to contrib/go/_std_1.23/src/go/internal/typeparams/ya.make diff --git a/contrib/go/_std_1.22/src/go/parser/interface.go b/contrib/go/_std_1.23/src/go/parser/interface.go similarity index 100% rename from contrib/go/_std_1.22/src/go/parser/interface.go rename to contrib/go/_std_1.23/src/go/parser/interface.go diff --git a/contrib/go/_std_1.22/src/go/parser/parser.go b/contrib/go/_std_1.23/src/go/parser/parser.go similarity index 99% rename from contrib/go/_std_1.22/src/go/parser/parser.go rename to contrib/go/_std_1.23/src/go/parser/parser.go index 17808b366f09..f268dea1a6f9 100644 --- a/contrib/go/_std_1.22/src/go/parser/parser.go +++ b/contrib/go/_std_1.23/src/go/parser/parser.go @@ -1676,6 +1676,8 @@ func (p *parser) parseElementList() (list []ast.Expr) { } func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr { + defer decNestLev(incNestLev(p)) + if p.trace { defer un(trace(p, "LiteralValue")) } diff --git a/contrib/go/_std_1.22/src/go/parser/resolver.go b/contrib/go/_std_1.23/src/go/parser/resolver.go similarity index 100% rename from contrib/go/_std_1.22/src/go/parser/resolver.go rename to contrib/go/_std_1.23/src/go/parser/resolver.go diff --git a/contrib/go/_std_1.22/src/go/parser/ya.make b/contrib/go/_std_1.23/src/go/parser/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/go/parser/ya.make rename to contrib/go/_std_1.23/src/go/parser/ya.make diff --git a/contrib/go/_std_1.22/src/go/printer/comment.go b/contrib/go/_std_1.23/src/go/printer/comment.go similarity index 100% rename from contrib/go/_std_1.22/src/go/printer/comment.go rename to contrib/go/_std_1.23/src/go/printer/comment.go diff --git a/contrib/go/_std_1.22/src/go/printer/gobuild.go b/contrib/go/_std_1.23/src/go/printer/gobuild.go similarity index 99% rename from contrib/go/_std_1.22/src/go/printer/gobuild.go rename to contrib/go/_std_1.23/src/go/printer/gobuild.go index f00492d0770c..6f04cf6d6de0 100644 --- a/contrib/go/_std_1.22/src/go/printer/gobuild.go +++ b/contrib/go/_std_1.23/src/go/printer/gobuild.go @@ -6,7 +6,7 @@ package printer import ( "go/build/constraint" - "sort" + "slices" "text/tabwriter" ) @@ -108,7 +108,7 @@ func (p *printer) fixGoBuildLines() { // Build sorted list of lines to delete from remainder of output. toDelete := append(p.goBuild, p.plusBuild...) - sort.Ints(toDelete) + slices.Sort(toDelete) // Collect output after insertion point, with lines deleted, into after. var after []byte diff --git a/contrib/go/_std_1.22/src/go/printer/nodes.go b/contrib/go/_std_1.23/src/go/printer/nodes.go similarity index 100% rename from contrib/go/_std_1.22/src/go/printer/nodes.go rename to contrib/go/_std_1.23/src/go/printer/nodes.go diff --git a/contrib/go/_std_1.22/src/go/printer/printer.go b/contrib/go/_std_1.23/src/go/printer/printer.go similarity index 100% rename from contrib/go/_std_1.22/src/go/printer/printer.go rename to contrib/go/_std_1.23/src/go/printer/printer.go diff --git a/contrib/go/_std_1.22/src/go/printer/ya.make b/contrib/go/_std_1.23/src/go/printer/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/go/printer/ya.make rename to contrib/go/_std_1.23/src/go/printer/ya.make diff --git a/contrib/go/_std_1.22/src/go/scanner/errors.go b/contrib/go/_std_1.23/src/go/scanner/errors.go similarity index 100% rename from contrib/go/_std_1.22/src/go/scanner/errors.go rename to contrib/go/_std_1.23/src/go/scanner/errors.go diff --git a/contrib/go/_std_1.22/src/go/scanner/scanner.go b/contrib/go/_std_1.23/src/go/scanner/scanner.go similarity index 100% rename from contrib/go/_std_1.22/src/go/scanner/scanner.go rename to contrib/go/_std_1.23/src/go/scanner/scanner.go diff --git a/contrib/go/_std_1.22/src/go/scanner/ya.make b/contrib/go/_std_1.23/src/go/scanner/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/go/scanner/ya.make rename to contrib/go/_std_1.23/src/go/scanner/ya.make diff --git a/contrib/go/_std_1.22/src/go/token/position.go b/contrib/go/_std_1.23/src/go/token/position.go similarity index 89% rename from contrib/go/_std_1.22/src/go/token/position.go rename to contrib/go/_std_1.23/src/go/token/position.go index 0b2ace0b69c6..04dbca712435 100644 --- a/contrib/go/_std_1.22/src/go/token/position.go +++ b/contrib/go/_std_1.23/src/go/token/position.go @@ -5,13 +5,18 @@ package token import ( + "cmp" "fmt" - "sort" + "slices" "strconv" "sync" "sync/atomic" ) +// If debug is set, invalid offset and position values cause a panic +// (go.dev/issue/57490). +const debug = false + // ----------------------------------------------------------------------------- // Positions @@ -261,24 +266,54 @@ func (f *File) AddLineColumnInfo(offset int, filename string, line, column int) f.mutex.Unlock() } -// Pos returns the Pos value for the given file offset; -// the offset must be <= f.Size(). +// fixOffset fixes an out-of-bounds offset such that 0 <= offset <= f.size. +func (f *File) fixOffset(offset int) int { + switch { + case offset < 0: + if !debug { + return 0 + } + case offset > f.size: + if !debug { + return f.size + } + default: + return offset + } + + // only generate this code if needed + if debug { + panic(fmt.Sprintf("offset %d out of bounds [%d, %d] (position %d out of bounds [%d, %d])", + 0 /* for symmetry */, offset, f.size, + f.base+offset, f.base, f.base+f.size)) + } + return 0 +} + +// Pos returns the Pos value for the given file offset. +// +// If offset is negative, the result is the file's start +// position; if the offset is too large, the result is +// the file's end position (see also go.dev/issue/57490). +// +// The following invariant, though not true for Pos values +// in general, holds for the result p: // f.Pos(f.Offset(p)) == p. func (f *File) Pos(offset int) Pos { - if offset > f.size { - panic(fmt.Sprintf("invalid file offset %d (should be <= %d)", offset, f.size)) - } - return Pos(f.base + offset) + return Pos(f.base + f.fixOffset(offset)) } -// Offset returns the offset for the given file position p; -// p must be a valid [Pos] value in that file. -// f.Offset(f.Pos(offset)) == offset. +// Offset returns the offset for the given file position p. +// +// If p is before the file's start position (or if p is NoPos), +// the result is 0; if p is past the file's end position, the +// the result is the file size (see also go.dev/issue/57490). +// +// The following invariant, though not true for offset values +// in general, holds for the result offset: +// f.Offset(f.Pos(offset)) == offset func (f *File) Offset(p Pos) int { - if int(p) < f.base || int(p) > f.base+f.size { - panic(fmt.Sprintf("invalid Pos value %d (should be in [%d, %d])", p, f.base, f.base+f.size)) - } - return int(p) - f.base + return f.fixOffset(int(p) - f.base) } // Line returns the line number for the given file position p; @@ -288,7 +323,15 @@ func (f *File) Line(p Pos) int { } func searchLineInfos(a []lineInfo, x int) int { - return sort.Search(len(a), func(i int) bool { return a[i].Offset > x }) - 1 + i, found := slices.BinarySearchFunc(a, x, func(a lineInfo, x int) int { + return cmp.Compare(a.Offset, x) + }) + if !found { + // We want the lineInfo containing x, but if we didn't + // find x then i is the next one. + i-- + } + return i } // unpack returns the filename and line and column number for a file offset. @@ -330,27 +373,26 @@ func (f *File) unpack(offset int, adjusted bool) (filename string, line, column } func (f *File) position(p Pos, adjusted bool) (pos Position) { - offset := int(p) - f.base + offset := f.fixOffset(int(p) - f.base) pos.Offset = offset pos.Filename, pos.Line, pos.Column = f.unpack(offset, adjusted) return } // PositionFor returns the Position value for the given file position p. +// If p is out of bounds, it is adjusted to match the File.Offset behavior. // If adjusted is set, the position may be adjusted by position-altering // //line comments; otherwise those comments are ignored. // p must be a Pos value in f or NoPos. func (f *File) PositionFor(p Pos, adjusted bool) (pos Position) { if p != NoPos { - if int(p) < f.base || int(p) > f.base+f.size { - panic(fmt.Sprintf("invalid Pos value %d (should be in [%d, %d])", p, f.base, f.base+f.size)) - } pos = f.position(p, adjusted) } return } // Position returns the Position value for the given file position p. +// If p is out of bounds, it is adjusted to match the File.Offset behavior. // Calling f.Position(p) is equivalent to calling f.PositionFor(p, true). func (f *File) Position(p Pos) (pos Position) { return f.PositionFor(p, true) @@ -483,7 +525,15 @@ func (s *FileSet) Iterate(f func(*File) bool) { } func searchFiles(a []*File, x int) int { - return sort.Search(len(a), func(i int) bool { return a[i].base > x }) - 1 + i, found := slices.BinarySearchFunc(a, x, func(a *File, x int) int { + return cmp.Compare(a.base, x) + }) + if !found { + // We want the File containing x, but if we didn't + // find x then i is the next one. + i-- + } + return i } func (s *FileSet) file(p Pos) *File { diff --git a/contrib/go/_std_1.22/src/go/token/serialize.go b/contrib/go/_std_1.23/src/go/token/serialize.go similarity index 100% rename from contrib/go/_std_1.22/src/go/token/serialize.go rename to contrib/go/_std_1.23/src/go/token/serialize.go diff --git a/contrib/go/_std_1.22/src/go/token/token.go b/contrib/go/_std_1.23/src/go/token/token.go similarity index 100% rename from contrib/go/_std_1.22/src/go/token/token.go rename to contrib/go/_std_1.23/src/go/token/token.go diff --git a/contrib/go/_std_1.22/src/go/token/ya.make b/contrib/go/_std_1.23/src/go/token/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/go/token/ya.make rename to contrib/go/_std_1.23/src/go/token/ya.make diff --git a/contrib/go/_std_1.23/src/go/types/alias.go b/contrib/go/_std_1.23/src/go/types/alias.go new file mode 100644 index 000000000000..7adb3deb58bb --- /dev/null +++ b/contrib/go/_std_1.23/src/go/types/alias.go @@ -0,0 +1,161 @@ +// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/alias.go + +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types + +import ( + "fmt" + "go/token" +) + +// An Alias represents an alias type. +// Whether or not Alias types are created is controlled by the +// gotypesalias setting with the GODEBUG environment variable. +// For gotypesalias=1, alias declarations produce an Alias type. +// Otherwise, the alias information is only in the type name, +// which points directly to the actual (aliased) type. +type Alias struct { + obj *TypeName // corresponding declared alias object + orig *Alias // original, uninstantiated alias + tparams *TypeParamList // type parameters, or nil + targs *TypeList // type arguments, or nil + fromRHS Type // RHS of type alias declaration; may be an alias + actual Type // actual (aliased) type; never an alias +} + +// NewAlias creates a new Alias type with the given type name and rhs. +// rhs must not be nil. +func NewAlias(obj *TypeName, rhs Type) *Alias { + alias := (*Checker)(nil).newAlias(obj, rhs) + // Ensure that alias.actual is set (#65455). + alias.cleanup() + return alias +} + +// Obj returns the type name for the declaration defining the alias type a. +// For instantiated types, this is same as the type name of the origin type. +func (a *Alias) Obj() *TypeName { return a.orig.obj } + +func (a *Alias) String() string { return TypeString(a, nil) } + +// Underlying returns the [underlying type] of the alias type a, which is the +// underlying type of the aliased type. Underlying types are never Named, +// TypeParam, or Alias types. +// +// [underlying type]: https://go.dev/ref/spec#Underlying_types. +func (a *Alias) Underlying() Type { return unalias(a).Underlying() } + +// Origin returns the generic Alias type of which a is an instance. +// If a is not an instance of a generic alias, Origin returns a. +func (a *Alias) Origin() *Alias { return a.orig } + +// TypeParams returns the type parameters of the alias type a, or nil. +// A generic Alias and its instances have the same type parameters. +func (a *Alias) TypeParams() *TypeParamList { return a.tparams } + +// SetTypeParams sets the type parameters of the alias type a. +// The alias a must not have type arguments. +func (a *Alias) SetTypeParams(tparams []*TypeParam) { + assert(a.targs == nil) + a.tparams = bindTParams(tparams) +} + +// TypeArgs returns the type arguments used to instantiate the Alias type. +// If a is not an instance of a generic alias, the result is nil. +func (a *Alias) TypeArgs() *TypeList { return a.targs } + +// Rhs returns the type R on the right-hand side of an alias +// declaration "type A = R", which may be another alias. +func (a *Alias) Rhs() Type { return a.fromRHS } + +// Unalias returns t if it is not an alias type; +// otherwise it follows t's alias chain until it +// reaches a non-alias type which is then returned. +// Consequently, the result is never an alias type. +func Unalias(t Type) Type { + if a0, _ := t.(*Alias); a0 != nil { + return unalias(a0) + } + return t +} + +func unalias(a0 *Alias) Type { + if a0.actual != nil { + return a0.actual + } + var t Type + for a := a0; a != nil; a, _ = t.(*Alias) { + t = a.fromRHS + } + if t == nil { + panic(fmt.Sprintf("non-terminated alias %s", a0.obj.name)) + } + + // Memoize the type only if valid. + // In the presence of unfinished cyclic declarations, Unalias + // would otherwise latch the invalid value (#66704). + // TODO(adonovan): rethink, along with checker.typeDecl's use + // of Invalid to mark unfinished aliases. + if t != Typ[Invalid] { + a0.actual = t + } + + return t +} + +// asNamed returns t as *Named if that is t's +// actual type. It returns nil otherwise. +func asNamed(t Type) *Named { + n, _ := Unalias(t).(*Named) + return n +} + +// newAlias creates a new Alias type with the given type name and rhs. +// rhs must not be nil. +func (check *Checker) newAlias(obj *TypeName, rhs Type) *Alias { + assert(rhs != nil) + a := new(Alias) + a.obj = obj + a.orig = a + a.fromRHS = rhs + if obj.typ == nil { + obj.typ = a + } + + // Ensure that a.actual is set at the end of type checking. + if check != nil { + check.needsCleanup(a) + } + + return a +} + +// newAliasInstance creates a new alias instance for the given origin and type +// arguments, recording pos as the position of its synthetic object (for error +// reporting). +func (check *Checker) newAliasInstance(pos token.Pos, orig *Alias, targs []Type, expanding *Named, ctxt *Context) *Alias { + assert(len(targs) > 0) + obj := NewTypeName(pos, orig.obj.pkg, orig.obj.name, nil) + rhs := check.subst(pos, orig.fromRHS, makeSubstMap(orig.TypeParams().list(), targs), expanding, ctxt) + res := check.newAlias(obj, rhs) + res.orig = orig + res.tparams = orig.tparams + res.targs = newTypeList(targs) + return res +} + +func (a *Alias) cleanup() { + // Ensure a.actual is set before types are published, + // so Unalias is a pure "getter", not a "setter". + actual := Unalias(a) + + if actual == Typ[Invalid] { + // We don't set a.actual to Typ[Invalid] during type checking, + // as it may indicate that the RHS is not fully set up. + a.actual = actual + } +} diff --git a/contrib/go/_std_1.22/src/go/types/api.go b/contrib/go/_std_1.23/src/go/types/api.go similarity index 92% rename from contrib/go/_std_1.22/src/go/types/api.go rename to contrib/go/_std_1.23/src/go/types/api.go index 796fe055e646..dea974bec809 100644 --- a/contrib/go/_std_1.22/src/go/types/api.go +++ b/contrib/go/_std_1.23/src/go/types/api.go @@ -10,19 +10,23 @@ // // Type-checking consists of several interdependent phases: // -// Name resolution maps each identifier (ast.Ident) in the program to the -// language object ([Object]) it denotes. -// Use [Info].{Defs,Uses,Implicits} for the results of name resolution. +// Name resolution maps each identifier ([ast.Ident]) in the program +// to the symbol ([Object]) it denotes. Use the Defs and Uses fields +// of [Info] or the [Info.ObjectOf] method to find the symbol for an +// identifier, and use the Implicits field of [Info] to find the +// symbol for certain other kinds of syntax node. // -// Constant folding computes the exact constant value (constant.Value) -// for every expression (ast.Expr) that is a compile-time constant. -// Use Info.Types[expr].Value for the results of constant folding. +// Constant folding computes the exact constant value +// ([constant.Value]) of every expression ([ast.Expr]) that is a +// compile-time constant. Use the Types field of [Info] to find the +// results of constant folding for an expression. // -// [Type] inference computes the type ([Type]) of every expression ([ast.Expr]) -// and checks for compliance with the language specification. -// Use [Info.Types][expr].Type for the results of type inference. +// Type deduction computes the type ([Type]) of every expression +// ([ast.Expr]) and checks for compliance with the language +// specification. Use the Types field of [Info] for the results of +// type deduction. // -// For a tutorial, see https://golang.org/s/types-tutorial. +// For a tutorial, see https://go.dev/s/types-tutorial. package types import ( @@ -32,6 +36,7 @@ import ( "go/constant" "go/token" . "internal/types/errors" + _ "unsafe" // for linkname ) // An Error describes a type-checking error; it implements the error interface. @@ -176,8 +181,21 @@ type Config struct { // of an error message. ErrorURL must be a format string containing // exactly one "%s" format, e.g. "[go.dev/e/%s]". _ErrorURL string + + // If EnableAlias is set, alias declarations produce an Alias type. Otherwise + // the alias information is only in the type name, which points directly to + // the actual (aliased) type. + // + // This setting must not differ among concurrent type-checking operations, + // since it affects the behavior of Universe.Lookup("any"). + // + // This flag will eventually be removed (with Go 1.24 at the earliest). + _EnableAlias bool } +// Linkname for use from srcimporter. +//go:linkname srcimporter_setUsesCgo + func srcimporter_setUsesCgo(conf *Config) { conf.go115UsesCgo = true } diff --git a/contrib/go/_std_1.22/src/go/types/api_predicates.go b/contrib/go/_std_1.23/src/go/types/api_predicates.go similarity index 80% rename from contrib/go/_std_1.22/src/go/types/api_predicates.go rename to contrib/go/_std_1.23/src/go/types/api_predicates.go index d712afe0ff02..4a6b3fe9caa7 100644 --- a/contrib/go/_std_1.22/src/go/types/api_predicates.go +++ b/contrib/go/_std_1.23/src/go/types/api_predicates.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/api_predicates.go // Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -72,6 +73,18 @@ func Satisfies(V Type, T *Interface) bool { // Identical reports whether x and y are identical types. // Receivers of [Signature] types are ignored. +// +// Predicates such as [Identical], [Implements], and +// [Satisfies] assume that both operands belong to a +// consistent collection of symbols ([Object] values). +// For example, two [Named] types can be identical only if their +// [Named.Obj] methods return the same [TypeName] symbol. +// A collection of symbols is consistent if, for each logical +// package whose path is P, the creation of those symbols +// involved at most one call to [NewPackage](P, ...). +// To ensure consistency, use a single [Importer] for +// all loaded packages and their dependencies. +// For more information, see https://github.com/golang/go/issues/57497. func Identical(x, y Type) bool { var c comparer return c.identical(x, y, nil) diff --git a/contrib/go/_std_1.22/src/go/types/array.go b/contrib/go/_std_1.23/src/go/types/array.go similarity index 94% rename from contrib/go/_std_1.22/src/go/types/array.go rename to contrib/go/_std_1.23/src/go/types/array.go index f19ce6e528b1..d0a66eae893c 100644 --- a/contrib/go/_std_1.22/src/go/types/array.go +++ b/contrib/go/_std_1.23/src/go/types/array.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/array.go // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/contrib/go/_std_1.22/src/go/types/assignments.go b/contrib/go/_std_1.23/src/go/types/assignments.go similarity index 92% rename from contrib/go/_std_1.22/src/go/types/assignments.go rename to contrib/go/_std_1.23/src/go/types/assignments.go index ac9e7bda312d..01a55d582fc9 100644 --- a/contrib/go/_std_1.22/src/go/types/assignments.go +++ b/contrib/go/_std_1.23/src/go/types/assignments.go @@ -1,3 +1,6 @@ +// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/assignments.go + // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -24,6 +27,9 @@ func (check *Checker) assignment(x *operand, T Type, context string) { switch x.mode { case invalid: return // error reported before + case nilvalue: + assert(isTypes2) + // ok case constant_, variable, mapindex, value, commaok, commaerr: // ok default: @@ -41,13 +47,25 @@ func (check *Checker) assignment(x *operand, T Type, context string) { // bool, rune, int, float64, complex128 or string respectively, depending // on whether the value is a boolean, rune, integer, floating-point, // complex, or string constant." - if T == nil || isNonTypeParamInterface(T) { - if T == nil && x.typ == Typ[UntypedNil] { - check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context) - x.mode = invalid - return + if isTypes2 { + if x.isNil() { + if T == nil { + check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context) + x.mode = invalid + return + } + } else if T == nil || isNonTypeParamInterface(T) { + target = Default(x.typ) + } + } else { // go/types + if T == nil || isNonTypeParamInterface(T) { + if T == nil && x.typ == Typ[UntypedNil] { + check.errorf(x, UntypedNilUse, "use of untyped nil in %s", context) + x.mode = invalid + return + } + target = Default(x.typ) } - target = Default(x.typ) } newType, val, code := check.implicitTypeAndValue(x, target) if code != 0 { @@ -169,7 +187,7 @@ func (check *Checker) initVar(lhs *Var, x *operand, context string) { // and Typ[Invalid] if it is an invalid lhs expression. func (check *Checker) lhsVar(lhs ast.Expr) Type { // Determine if the lhs is a (possibly parenthesized) identifier. - ident, _ := unparen(lhs).(*ast.Ident) + ident, _ := ast.Unparen(lhs).(*ast.Ident) // Don't evaluate lhs if it is the blank identifier. if ident != nil && ident.Name == "_" { @@ -325,7 +343,7 @@ func (check *Checker) assignError(rhs []ast.Expr, l, r int) { rhs0 := rhs[0] if len(rhs) == 1 { - if call, _ := unparen(rhs0).(*ast.CallExpr); call != nil { + if call, _ := ast.Unparen(rhs0).(*ast.CallExpr); call != nil { check.errorf(rhs0, WrongAssignCount, "assignment mismatch: %s but %s returns %s", vars, call.Fun, vals) return } @@ -342,12 +360,11 @@ func (check *Checker) returnError(at positioner, lhs []*Var, rhs []*operand) { } else if r > 0 { at = rhs[r-1] // report at last value } - var err error_ - err.code = WrongResultCount - err.errorf(at.Pos(), "%s return values", qualifier) - err.errorf(nopos, "have %s", check.typesSummary(operandTypes(rhs), false)) - err.errorf(nopos, "want %s", check.typesSummary(varTypes(lhs), false)) - check.report(&err) + err := check.newError(WrongResultCount) + err.addf(at, "%s return values", qualifier) + err.addf(noposn, "have %s", check.typesSummary(operandTypes(rhs), false)) + err.addf(noposn, "want %s", check.typesSummary(varTypes(lhs), false)) + err.report() } // initVars type-checks assignments of initialization expressions orig_rhs @@ -366,7 +383,7 @@ func (check *Checker) initVars(lhs []*Var, orig_rhs []ast.Expr, returnStmt ast.S // error message don't handle it as n:n mapping below. isCall := false if r == 1 { - _, isCall = unparen(orig_rhs[0]).(*ast.CallExpr) + _, isCall = ast.Unparen(orig_rhs[0]).(*ast.CallExpr) } // If we have a n:n mapping from lhs variable to rhs expression, @@ -445,7 +462,7 @@ func (check *Checker) assignVars(lhs, orig_rhs []ast.Expr) { // error message don't handle it as n:n mapping below. isCall := false if r == 1 { - _, isCall = unparen(orig_rhs[0]).(*ast.CallExpr) + _, isCall = ast.Unparen(orig_rhs[0]).(*ast.CallExpr) } // If we have a n:n mapping from lhs variable to rhs expression, @@ -505,7 +522,7 @@ func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) { ident, _ := lhs.(*ast.Ident) if ident == nil { check.useLHS(lhs) - // TODO(rFindley) this is redundant with a parser error. Consider omitting? + // TODO(gri) This is redundant with a go/parser error. Consider omitting in go/types? check.errorf(lhs, BadDecl, "non-name %s on left side of :=", lhs) hasErr = true continue @@ -568,7 +585,7 @@ func (check *Checker) shortVarDecl(pos positioner, lhs, rhs []ast.Expr) { // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl // for short variable declarations) and ends at the end of the innermost // containing block." - scopePos := rhs[len(rhs)-1].End() + scopePos := endPos(rhs[len(rhs)-1]) for _, obj := range newVars { check.declare(scope, nil, obj, scopePos) // id = nil: recordDef already called } diff --git a/contrib/go/_std_1.23/src/go/types/badlinkname.go b/contrib/go/_std_1.23/src/go/types/badlinkname.go new file mode 100644 index 000000000000..432322ad9001 --- /dev/null +++ b/contrib/go/_std_1.23/src/go/types/badlinkname.go @@ -0,0 +1,20 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types + +import _ "unsafe" + +// This should properly be in infer.go, but that file is auto-generated. + +// infer should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goplus/gox +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname badlinkname_Checker_infer go/types.(*Checker).infer +func badlinkname_Checker_infer(*Checker, positioner, []*TypeParam, []Type, *Tuple, []*operand, bool, *error_) []Type diff --git a/contrib/go/_std_1.22/src/go/types/basic.go b/contrib/go/_std_1.23/src/go/types/basic.go similarity index 96% rename from contrib/go/_std_1.22/src/go/types/basic.go rename to contrib/go/_std_1.23/src/go/types/basic.go index d48361641322..685f17224ca5 100644 --- a/contrib/go/_std_1.22/src/go/types/basic.go +++ b/contrib/go/_std_1.23/src/go/types/basic.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/basic.go // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/contrib/go/_std_1.22/src/go/types/builtins.go b/contrib/go/_std_1.23/src/go/types/builtins.go similarity index 96% rename from contrib/go/_std_1.22/src/go/types/builtins.go rename to contrib/go/_std_1.23/src/go/types/builtins.go index 901573661b93..d92a4279f86c 100644 --- a/contrib/go/_std_1.22/src/go/types/builtins.go +++ b/contrib/go/_std_1.23/src/go/types/builtins.go @@ -1,3 +1,6 @@ +// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/builtins.go + // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -22,8 +25,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b // append is the only built-in that permits the use of ... for the last argument bin := predeclaredFuncs[id] - if call.Ellipsis.IsValid() && id != _Append { - check.errorf(atPos(call.Ellipsis), + if hasDots(call) && id != _Append { + check.errorf(dddErrPos(call), InvalidDotDotDot, invalidOp+"invalid use of ... with built-in %s", bin.name) check.use(argList...) @@ -75,7 +78,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b msg = "too many" } if msg != "" { - check.errorf(inNode(call, call.Rparen), WrongArgCount, invalidOp+"%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs) + check.errorf(argErrPos(call), WrongArgCount, invalidOp+"%s arguments for %v (expected %d, found %d)", msg, call, bin.nargs, nargs) return } } @@ -113,7 +116,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b // spec: "As a special case, append also accepts a first argument assignable // to type []byte with a second argument of string type followed by ... . // This form appends the bytes of the string. - if nargs == 2 && call.Ellipsis.IsValid() { + if nargs == 2 && hasDots(call) { if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok { y := args[1] if t := coreString(y.typ); t != nil && isString(t) { @@ -210,7 +213,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b if id == _Len { code = InvalidLen } - check.errorf(x, code, invalidArg+"%s for %s", x, bin.name) + check.errorf(x, code, invalidArg+"%s for built-in %s", x, bin.name) } return } @@ -533,7 +536,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b case _Max, _Min: // max(x, ...) // min(x, ...) - check.verifyVersionf(call.Fun, go1_21, bin.name) + check.verifyVersionf(call.Fun, go1_21, "built-in %s", bin.name) op := token.LSS if id == _Max { @@ -576,7 +579,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b if x.mode != constant_ { x.mode = value // A value must not be untyped. - check.assignment(x, &emptyInterface, "argument to "+bin.name) + check.assignment(x, &emptyInterface, "argument to built-in "+bin.name) if x.mode == invalid { return } @@ -641,7 +644,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b if nargs > 0 { params = make([]Type, nargs) for i, a := range args { - check.assignment(a, nil, "argument to "+predeclaredFuncs[id].name) + check.assignment(a, nil, "argument to built-in"+predeclaredFuncs[id].name) if a.mode == invalid { return } @@ -705,7 +708,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b // unsafe.Offsetof(x T) uintptr, where x must be a selector // (no argument evaluated yet) arg0 := argList[0] - selx, _ := unparen(arg0).(*ast.SelectorExpr) + selx, _ := ast.Unparen(arg0).(*ast.SelectorExpr) if selx == nil { check.errorf(arg0, BadOffsetofSyntax, invalidArg+"%s is not a selector expression", arg0) check.use(arg0) @@ -719,7 +722,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b base := derefStructPtr(x.typ) sel := selx.Sel.Name - obj, index, indirect := LookupFieldOrMethod(base, false, check.pkg, sel) + obj, index, indirect := lookupFieldOrMethod(base, false, check.pkg, sel, false) switch obj.(type) { case nil: check.errorf(x, MissingFieldOrMethod, invalidArg+"%s has no single field %s", base, sel) @@ -908,7 +911,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b // trace is only available in test mode - no need to record signature default: - unreachable() + panic("unreachable") } assert(x.mode != invalid) @@ -947,7 +950,7 @@ func hasVarSize(t Type, seen map[*Named]bool) (varSized bool) { case *Interface: return isTypeParam(t) case *Named, *Union: - unreachable() + panic("unreachable") } return false } @@ -960,7 +963,7 @@ func hasVarSize(t Type, seen map[*Named]bool) (varSized bool) { // applyTypeFunc returns nil. // If x is not a type parameter, the result is f(x). func (check *Checker) applyTypeFunc(f func(Type) Type, x *operand, id builtinId) Type { - if tp, _ := x.typ.(*TypeParam); tp != nil { + if tp, _ := Unalias(x.typ).(*TypeParam); tp != nil { // Test if t satisfies the requirements for the argument // type and collect possible result types at the same time. var terms []*Term @@ -990,9 +993,9 @@ func (check *Checker) applyTypeFunc(f func(Type) Type, x *operand, id builtinId) case _Complex: code = InvalidComplex default: - unreachable() + panic("unreachable") } - check.softErrorf(x, code, "%s not supported as argument to %s for go1.18 (see go.dev/issue/50937)", x, predeclaredFuncs[id].name) + check.softErrorf(x, code, "%s not supported as argument to built-in %s for go1.18 (see go.dev/issue/50937)", x, predeclaredFuncs[id].name) // Construct a suitable new type parameter for the result type. // The type parameter is placed in the current package so export/import @@ -1026,12 +1029,10 @@ func makeSig(res Type, args ...Type) *Signature { // arrayPtrDeref returns A if typ is of the form *A and A is an array; // otherwise it returns typ. func arrayPtrDeref(typ Type) Type { - if p, ok := typ.(*Pointer); ok { + if p, ok := Unalias(typ).(*Pointer); ok { if a, _ := under(p.base).(*Array); a != nil { return a } } return typ } - -func unparen(e ast.Expr) ast.Expr { return ast.Unparen(e) } diff --git a/contrib/go/_std_1.22/src/go/types/call.go b/contrib/go/_std_1.23/src/go/types/call.go similarity index 94% rename from contrib/go/_std_1.22/src/go/types/call.go rename to contrib/go/_std_1.23/src/go/types/call.go index c7de3bdb9f3a..8f02ffc39729 100644 --- a/contrib/go/_std_1.22/src/go/types/call.go +++ b/contrib/go/_std_1.23/src/go/types/call.go @@ -12,7 +12,6 @@ import ( "go/token" . "internal/types/errors" "strings" - "unicode" ) // funcInst type-checks a function instantiation. @@ -40,6 +39,7 @@ func (check *Checker) funcInst(T *target, pos token.Pos, x *operand, ix *typepar var instErrPos positioner if ix != nil { instErrPos = inNode(ix.Orig, ix.Lbrack) + x.expr = ix.Orig // if we don't have an index expression, keep the existing expression of x } else { instErrPos = atPos(pos) } @@ -53,7 +53,6 @@ func (check *Checker) funcInst(T *target, pos token.Pos, x *operand, ix *typepar targs = check.typeList(xlist) if targs == nil { x.mode = invalid - x.expr = ix return nil, nil } assert(len(targs) == len(xlist)) @@ -68,7 +67,6 @@ func (check *Checker) funcInst(T *target, pos token.Pos, x *operand, ix *typepar // Providing too many type arguments is always an error. check.errorf(ix.Indices[got-1], WrongTypeArgCount, "got %d type arguments but want %d", got, want) x.mode = invalid - x.expr = ix.Orig return nil, nil } @@ -91,7 +89,7 @@ func (check *Checker) funcInst(T *target, pos token.Pos, x *operand, ix *typepar var params []*Var var reverse bool if T != nil && sig.tparams != nil { - if !versionErr && !check.allowVersion(check.pkg, instErrPos, go1_21) { + if !versionErr && !check.allowVersion(instErrPos, go1_21) { if ix != nil { check.versionErrorf(instErrPos, go1_21, "partially instantiated function in assignment") } else { @@ -113,11 +111,13 @@ func (check *Checker) funcInst(T *target, pos token.Pos, x *operand, ix *typepar // Note that NewTuple(params...) below is (*Tuple)(nil) if len(params) == 0, as desired. tparams, params2 := check.renameTParams(pos, sig.TypeParams().list(), NewTuple(params...)) - targs = check.infer(atPos(pos), tparams, targs, params2.(*Tuple), args, reverse) + err := check.newError(CannotInferTypeArgs) + targs = check.infer(atPos(pos), tparams, targs, params2.(*Tuple), args, reverse, err) if targs == nil { - // error was already reported + if !err.empty() { + err.report() + } x.mode = invalid - x.expr = ix // TODO(gri) is this correct? return nil, nil } got = len(targs) @@ -125,15 +125,9 @@ func (check *Checker) funcInst(T *target, pos token.Pos, x *operand, ix *typepar assert(got == want) // instantiate function signature - expr := x.expr // if we don't have an index expression, keep the existing expression of x - if ix != nil { - expr = ix.Orig - } - sig = check.instantiateSignature(x.Pos(), expr, sig, targs, xlist) - + sig = check.instantiateSignature(x.Pos(), x.expr, sig, targs, xlist) x.typ = sig x.mode = value - x.expr = expr return nil, nil } @@ -211,7 +205,7 @@ func (check *Checker) callExpr(x *operand, call *ast.CallExpr) exprKind { case 1: check.expr(nil, x, call.Args[0]) if x.mode != invalid { - if call.Ellipsis.IsValid() { + if hasDots(call) { check.errorf(call.Args[0], BadDotDotDotSyntax, "invalid use of ... in conversion to %s", T) break } @@ -380,7 +374,7 @@ func (check *Checker) genericExprList(elist []ast.Expr) (resList []*operand, tar // nor permitted. Checker.funcInst must infer missing type arguments in that case. infer := true // for -lang < go1.21 n := len(elist) - if n > 0 && check.allowVersion(check.pkg, elist[0], go1_21) { + if n > 0 && check.allowVersion(elist[0], go1_21) { infer = false } @@ -476,7 +470,7 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type nargs := len(args) npars := sig.params.Len() - ddd := call.Ellipsis.IsValid() + ddd := hasDots(call) // set up parameters sigParams := sig.params // adjusted for variadic functions (may be nil for empty parameter lists!) @@ -534,10 +528,11 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type if sig.params != nil { params = sig.params.vars } - err := newErrorf(at, WrongArgCount, "%s arguments in call to %s", qualifier, call.Fun) - err.errorf(nopos, "have %s", check.typesSummary(operandTypes(args), false)) - err.errorf(nopos, "want %s", check.typesSummary(varTypes(params), sig.variadic)) - check.report(err) + err := check.newError(WrongArgCount) + err.addf(at, "%s arguments in call to %s", qualifier, call.Fun) + err.addf(noposn, "have %s", check.typesSummary(operandTypes(args), false)) + err.addf(noposn, "want %s", check.typesSummary(varTypes(params), sig.variadic)) + err.report() return } @@ -547,7 +542,7 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type // collect type parameters of callee n := sig.TypeParams().Len() if n > 0 { - if !check.allowVersion(check.pkg, call, go1_18) { + if !check.allowVersion(call, go1_18) { switch call.Fun.(type) { case *ast.IndexExpr, *ast.IndexListExpr: ix := typeparams.UnpackIndexExpr(call.Fun) @@ -612,13 +607,17 @@ func (check *Checker) arguments(call *ast.CallExpr, sig *Signature, targs []Type // infer missing type arguments of callee and function arguments if len(tparams) > 0 { - targs = check.infer(call, tparams, targs, sigParams, args, false) + err := check.newError(CannotInferTypeArgs) + targs = check.infer(call, tparams, targs, sigParams, args, false, err) if targs == nil { // TODO(gri) If infer inferred the first targs[:n], consider instantiating // the call signature for better error messages/gopls behavior. // Perhaps instantiate as much as we can, also for arguments. // This will require changes to how infer returns its results. - return // error already reported + if !err.empty() { + check.errorf(err.posn(), CannotInferTypeArgs, "in call to %s, %s", call.Fun, err.msg()) + } + return } // update result signature: instantiate if needed @@ -723,7 +722,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w goto Error } if !exp.Exported() { - check.errorf(e.Sel, UnexportedName, "%s not exported by package %s", sel, pkg.name) + check.errorf(e.Sel, UnexportedName, "name %s not exported by package %s", sel, pkg.name) // ok to continue } } @@ -759,7 +758,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w x.id = exp.id default: check.dump("%v: unexpected object %v", e.Sel.Pos(), exp) - unreachable() + panic("unreachable") } x.expr = e return @@ -771,7 +770,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w case typexpr: // don't crash for "type T T.x" (was go.dev/issue/51509) if def != nil && def.typ == x.typ { - check.cycleError([]Object{def}) + check.cycleError([]Object{def}, 0) goto Error } case builtin: @@ -801,7 +800,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w goto Error } - obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel) + obj, index, indirect = lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, false) if obj == nil { // Don't report another error if the underlying type was invalid (go.dev/issue/49541). if !isValid(under(x.typ)) { @@ -827,22 +826,8 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w if isInterfacePtr(x.typ) { why = check.interfacePtrError(x.typ) } else { - why = check.sprintf("type %s has no field or method %s", x.typ, sel) - // Check if capitalization of sel matters and provide better error message in that case. - // TODO(gri) This code only looks at the first character but LookupFieldOrMethod should - // have an (internal) mechanism for case-insensitive lookup that we should use - // instead (see types2). - if len(sel) > 0 { - var changeCase string - if r := rune(sel[0]); unicode.IsUpper(r) { - changeCase = string(unicode.ToLower(r)) + sel[1:] - } else { - changeCase = string(unicode.ToUpper(r)) + sel[1:] - } - if obj, _, _ = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, changeCase); obj != nil { - why += ", but does have " + changeCase - } - } + alt, _, _ := lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel, true) + why = check.lookupError(x.typ, sel, alt, false) } check.errorf(e.Sel, MissingFieldOrMethod, "%s.%s undefined (%s)", x.expr, sel, why) goto Error @@ -857,7 +842,6 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w // method expression m, _ := obj.(*Func) if m == nil { - // TODO(gri) should check if capitalization of sel matters and provide better error message in that case check.errorf(e.Sel, MissingFieldOrMethod, "%s.%s undefined (type %s has no method %s)", x.expr, sel, x.typ, sel) goto Error } @@ -973,7 +957,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr, def *TypeName, w check.addDeclDep(obj) default: - unreachable() + panic("unreachable") } } @@ -1011,7 +995,7 @@ func (check *Checker) useN(args []ast.Expr, lhs bool) bool { func (check *Checker) use1(e ast.Expr, lhs bool) bool { var x operand x.mode = value // anything but invalid - switch n := unparen(e).(type) { + switch n := ast.Unparen(e).(type) { case nil: // nothing to do case *ast.Ident: diff --git a/contrib/go/_std_1.22/src/go/types/chan.go b/contrib/go/_std_1.23/src/go/types/chan.go similarity index 94% rename from contrib/go/_std_1.22/src/go/types/chan.go rename to contrib/go/_std_1.23/src/go/types/chan.go index 940620067ce9..ced6b11cdc5b 100644 --- a/contrib/go/_std_1.22/src/go/types/chan.go +++ b/contrib/go/_std_1.23/src/go/types/chan.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/chan.go // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/contrib/go/_std_1.22/src/go/types/check.go b/contrib/go/_std_1.23/src/go/types/check.go similarity index 78% rename from contrib/go/_std_1.22/src/go/types/check.go rename to contrib/go/_std_1.23/src/go/types/check.go index 85fd0744d234..8a729094961f 100644 --- a/contrib/go/_std_1.22/src/go/types/check.go +++ b/contrib/go/_std_1.23/src/go/types/check.go @@ -7,7 +7,6 @@ package types import ( - "errors" "fmt" "go/ast" "go/constant" @@ -15,17 +14,52 @@ import ( "internal/godebug" . "internal/types/errors" "strings" + "sync/atomic" ) -// nopos indicates an unknown position +// nopos, noposn indicate an unknown position var nopos token.Pos +var noposn = atPos(nopos) // debugging/development support const debug = false // leave on during development -// gotypesalias controls the use of Alias types +// gotypesalias controls the use of Alias types. +// As of Apr 16 2024 they are used by default. +// To disable their use, set GODEBUG to gotypesalias=0. +// This GODEBUG flag will be removed in the near future (tentatively Go 1.24). var gotypesalias = godebug.New("gotypesalias") +// _aliasAny changes the behavior of [Scope.Lookup] for "any" in the +// [Universe] scope. +// +// This is necessary because while Alias creation is controlled by +// [Config._EnableAlias], based on the gotypealias variable, the representation +// of "any" is a global. In [Scope.Lookup], we select this global +// representation based on the result of [aliasAny], but as a result need to +// guard against this behavior changing during the type checking pass. +// Therefore we implement the following rule: any number of goroutines can type +// check concurrently with the same EnableAlias value, but if any goroutine +// tries to type check concurrently with a different EnableAlias value, we +// panic. +// +// To achieve this, _aliasAny is a state machine: +// +// 0: no type checking is occurring +// negative: type checking is occurring without _EnableAlias set +// positive: type checking is occurring with _EnableAlias set +var _aliasAny int32 + +func aliasAny() bool { + v := gotypesalias.Value() + useAlias := v != "0" + inuse := atomic.LoadInt32(&_aliasAny) + if inuse != 0 && useAlias != (inuse > 0) { + panic(fmt.Sprintf("gotypealias mutated during type checking, gotypesalias=%s, inuse=%d", v, inuse)) + } + return useAlias +} + // exprInfo stores information about an untyped expression. type exprInfo struct { isLhs bool // expression is lhs operand of a shift with delayed type-check @@ -98,12 +132,6 @@ type actionDesc struct { type Checker struct { // package information // (initialized by NewChecker, valid for the life-time of checker) - - // If EnableAlias is set, alias declarations produce an Alias type. - // Otherwise the alias information is only in the type name, which - // points directly to the actual (aliased) type. - enableAlias bool - conf *Config ctxt *Context // context for de-duplicating instances fset *token.FileSet @@ -113,7 +141,8 @@ type Checker struct { nextID uint64 // unique Id for type parameters (first valid Id is 1) objMap map[Object]*declInfo // maps package-level objects and (non-interface) methods to declaration info impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package - valids instanceLookup // valid *Named (incl. instantiated) types per the validType check + // see TODO in validtype.go + // valids instanceLookup // valid *Named (incl. instantiated) types per the validType check // pkgPathMap maps package names to the set of distinct import paths we've // seen for that name, anywhere in the import graph. It is used for @@ -129,7 +158,7 @@ type Checker struct { // (initialized by Files, valid only for the duration of check.Files; // maps and lists are allocated on demand) files []*ast.File // package files - versions map[*ast.File]string // maps files to version strings (each file has an entry) + versions map[*ast.File]string // maps files to version strings (each file has an entry); shared with Info.FileVersions if present imports []*PkgName // list of imported packages dotImportMap map[dotImportKey]*PkgName // maps dot-imported objects to the package they were dot-imported through recvTParamMap map[*ast.Ident]*TypeParam // maps blank receiver type parameters to their type @@ -169,9 +198,9 @@ func (check *Checker) addDeclDep(to Object) { // brokenAlias records that alias doesn't have a determined type yet. // It also sets alias.typ to Typ[Invalid]. -// Not used if check.enableAlias is set. +// Not used if check.conf._EnableAlias is set. func (check *Checker) brokenAlias(alias *TypeName) { - assert(!check.enableAlias) + assert(!check.conf._EnableAlias) if check.brokenAliases == nil { check.brokenAliases = make(map[*TypeName]bool) } @@ -181,14 +210,14 @@ func (check *Checker) brokenAlias(alias *TypeName) { // validAlias records that alias has the valid type typ (possibly Typ[Invalid]). func (check *Checker) validAlias(alias *TypeName, typ Type) { - assert(!check.enableAlias) + assert(!check.conf._EnableAlias) delete(check.brokenAliases, alias) alias.typ = typ } // isBrokenAlias reports whether alias doesn't have a determined type yet. func (check *Checker) isBrokenAlias(alias *TypeName) bool { - assert(!check.enableAlias) + assert(!check.conf._EnableAlias) return check.brokenAliases[alias] } @@ -257,16 +286,18 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch // // (previously, pkg.goVersion was mutated here: go.dev/issue/61212) + // In go/types, conf._EnableAlias is controlled by gotypesalias. + conf._EnableAlias = gotypesalias.Value() != "0" + return &Checker{ - enableAlias: gotypesalias.Value() == "1", - conf: conf, - ctxt: conf.Context, - fset: fset, - pkg: pkg, - Info: info, - version: asGoVersion(conf.GoVersion), - objMap: make(map[Object]*declInfo), - impMap: make(map[importKey]*Package), + conf: conf, + ctxt: conf.Context, + fset: fset, + pkg: pkg, + Info: info, + version: asGoVersion(conf.GoVersion), + objMap: make(map[Object]*declInfo), + impMap: make(map[importKey]*Package), } } @@ -301,7 +332,7 @@ func (check *Checker) initFiles(files []*ast.File) { check.files = append(check.files, file) default: - check.errorf(atPos(file.Package), MismatchedPkgName, "package %s; expected %s", name, pkg.name) + check.errorf(atPos(file.Package), MismatchedPkgName, "package %s; expected package %s", name, pkg.name) // ignore this file } } @@ -314,7 +345,10 @@ func (check *Checker) initFiles(files []*ast.File) { check.versions = versions pkgVersionOk := check.version.isValid() - downgradeOk := check.version.cmp(go1_21) >= 0 + if pkgVersionOk && len(files) > 0 && check.version.cmp(go_current) > 0 { + check.errorf(files[0], TooNew, "package requires newer Go version %v (application built with %v)", + check.version, go_current) + } // determine Go version for each file for _, file := range check.files { @@ -322,38 +356,41 @@ func (check *Checker) initFiles(files []*ast.File) { // (This version string may contain dot-release numbers as in go1.20.1, // unlike file versions which are Go language versions only, if valid.) v := check.conf.GoVersion - // use the file version, if applicable - // (file versions are either the empty string or of the form go1.dd) - if pkgVersionOk { - fileVersion := asGoVersion(file.GoVersion) - if fileVersion.isValid() { - cmp := fileVersion.cmp(check.version) - // Go 1.21 introduced the feature of setting the go.mod - // go line to an early version of Go and allowing //go:build lines - // to “upgrade” (cmp > 0) the Go version in a given file. - // We can do that backwards compatibly. - // - // Go 1.21 also introduced the feature of allowing //go:build lines - // to “downgrade” (cmp < 0) the Go version in a given file. - // That can't be done compatibly in general, since before the - // build lines were ignored and code got the module's Go version. - // To work around this, downgrades are only allowed when the - // module's Go version is Go 1.21 or later. - // - // If there is no valid check.version, then we don't really know what - // Go version to apply. - // Legacy tools may do this, and they historically have accepted everything. - // Preserve that behavior by ignoring //go:build constraints entirely in that - // case (!pkgVersionOk). - if cmp > 0 || cmp < 0 && downgradeOk { - v = file.GoVersion - } + + // If the file specifies a version, use max(fileVersion, go1.21). + if fileVersion := asGoVersion(file.GoVersion); fileVersion.isValid() { + // Go 1.21 introduced the feature of setting the go.mod + // go line to an early version of Go and allowing //go:build lines + // to set the Go version in a given file. Versions Go 1.21 and later + // can be set backwards compatibly as that was the first version + // files with go1.21 or later build tags could be built with. + // + // Set the version to max(fileVersion, go1.21): That will allow a + // downgrade to a version before go1.22, where the for loop semantics + // change was made, while being backwards compatible with versions of + // go before the new //go:build semantics were introduced. + v = string(versionMax(fileVersion, go1_21)) + + // Report a specific error for each tagged file that's too new. + // (Normally the build system will have filtered files by version, + // but clients can present arbitrary files to the type checker.) + if fileVersion.cmp(go_current) > 0 { + // Use position of 'package [p]' for types/types2 consistency. + // (Ideally we would use the //build tag itself.) + check.errorf(file.Name, TooNew, "file requires newer Go version %v (application built with %v)", fileVersion, go_current) } } versions[file] = v } } +func versionMax(a, b goVersion) goVersion { + if a.cmp(b) < 0 { + return b + } + return a +} + // A bailout panic is used for early termination. type bailout struct{} @@ -369,11 +406,7 @@ func (check *Checker) handleBailout(err *error) { } // Files checks the provided files as part of the checker's package. -func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(files) } - -var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together") - -func (check *Checker) checkFiles(files []*ast.File) (err error) { +func (check *Checker) Files(files []*ast.File) (err error) { if check.pkg == Unsafe { // Defensive handling for Unsafe, which cannot be type checked, and must // not be mutated. See https://go.dev/issue/61212 for an example of where @@ -381,15 +414,33 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) { return nil } - // Note: NewChecker doesn't return an error, so we need to check the version here. - if check.version.cmp(go_current) > 0 { - return fmt.Errorf("package requires newer Go version %v", check.version) - } - if check.conf.FakeImportC && check.conf.go115UsesCgo { - return errBadCgo - } + // Avoid early returns here! Nearly all errors can be + // localized to a piece of syntax and needn't prevent + // type-checking of the rest of the package. defer check.handleBailout(&err) + check.checkFiles(files) + return +} + +// checkFiles type-checks the specified files. Errors are reported as +// a side effect, not by returning early, to ensure that well-formed +// syntax is properly type annotated even in a package containing +// errors. +func (check *Checker) checkFiles(files []*ast.File) { + // Ensure that _EnableAlias is consistent among concurrent type checking + // operations. See the documentation of [_aliasAny] for details. + if check.conf._EnableAlias { + if atomic.AddInt32(&_aliasAny, 1) <= 0 { + panic("EnableAlias set while !EnableAlias type checking is ongoing") + } + defer atomic.AddInt32(&_aliasAny, -1) + } else { + if atomic.AddInt32(&_aliasAny, -1) >= 0 { + panic("!EnableAlias set while EnableAlias type checking is ongoing") + } + defer atomic.AddInt32(&_aliasAny, 1) + } print := func(msg string) { if check.conf._Trace { @@ -443,8 +494,6 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) { check.ctxt = nil // TODO(rFindley) There's more memory we should release at this point. - - return } // processDelayed processes all delayed actions pushed after top. @@ -517,7 +566,7 @@ func (check *Checker) recordUntyped() { for x, info := range check.untyped { if debug && isTyped(info.typ) { check.dump("%v: %s (type %s) is typed", x.Pos(), x, info.typ) - unreachable() + panic("unreachable") } check.recordTypeAndValue(x, info.mode, info.typ, info.val) } @@ -553,7 +602,7 @@ func (check *Checker) recordBuiltinType(f ast.Expr, sig *Signature) { case *ast.ParenExpr: f = p.X default: - unreachable() + panic("unreachable") } } } @@ -567,7 +616,7 @@ func (check *Checker) recordCommaOkTypes(x ast.Expr, a []*operand) { return } t0, t1 := a[0].typ, a[1].typ - assert(isTyped(t0) && isTyped(t1) && (isBoolean(t1) || t1 == universeError)) + assert(isTyped(t0) && isTyped(t1) && (allBoolean(t1) || t1 == universeError)) if m := check.Types; m != nil { for { tv := m[x] diff --git a/contrib/go/_std_1.22/src/go/types/const.go b/contrib/go/_std_1.23/src/go/types/const.go similarity index 98% rename from contrib/go/_std_1.22/src/go/types/const.go rename to contrib/go/_std_1.23/src/go/types/const.go index bffea146a0c7..c1ed14abe2c1 100644 --- a/contrib/go/_std_1.22/src/go/types/const.go +++ b/contrib/go/_std_1.23/src/go/types/const.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/const.go // Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -119,7 +120,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c case Uint64: return 0 <= x default: - unreachable() + panic("unreachable") } } // x does not fit into int64 @@ -160,7 +161,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c case UntypedFloat: return true default: - unreachable() + panic("unreachable") } case isComplex(typ): @@ -192,7 +193,7 @@ func representableConst(x constant.Value, check *Checker, typ *Basic, rounded *c case UntypedComplex: return true default: - unreachable() + panic("unreachable") } case isString(typ): diff --git a/contrib/go/_std_1.22/src/go/types/context.go b/contrib/go/_std_1.23/src/go/types/context.go similarity index 98% rename from contrib/go/_std_1.22/src/go/types/context.go rename to contrib/go/_std_1.23/src/go/types/context.go index ce9bbf305e45..5fe336a82fb8 100644 --- a/contrib/go/_std_1.22/src/go/types/context.go +++ b/contrib/go/_std_1.23/src/go/types/context.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/context.go // Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/contrib/go/_std_1.22/src/go/types/conversions.go b/contrib/go/_std_1.23/src/go/types/conversions.go similarity index 90% rename from contrib/go/_std_1.22/src/go/types/conversions.go rename to contrib/go/_std_1.23/src/go/types/conversions.go index 2be17eeb1261..d28c2294a7e3 100644 --- a/contrib/go/_std_1.22/src/go/types/conversions.go +++ b/contrib/go/_std_1.23/src/go/types/conversions.go @@ -1,3 +1,6 @@ +// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/conversions.go + // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -56,7 +59,7 @@ func (check *Checker) conversion(x *operand, T Type) { // If T's type set is empty, or if it doesn't // have specific types, constant x cannot be // converted. - ok = T.(*TypeParam).underIs(func(u Type) bool { + ok = Unalias(T).(*TypeParam).underIs(func(u Type) bool { // u is nil if there are no specific type terms if u == nil { cause = check.sprintf("%s does not contain specific types", T) @@ -98,14 +101,17 @@ func (check *Checker) conversion(x *operand, T Type) { // given a type explicitly by a constant declaration or conversion,...". if isUntyped(x.typ) { final := T - // - For conversions to interfaces, use the argument's default type. + // - For conversions to interfaces, except for untyped nil arguments + // and isTypes2, use the argument's default type. // - For conversions of untyped constants to non-constant types, also // use the default type (e.g., []byte("foo") should report string // not []byte as type for the constant "foo"). - // - Keep untyped nil for untyped nil arguments. + // - If !isTypes2, keep untyped nil for untyped nil arguments. // - For constant integer to string conversions, keep the argument type. // (See also the TODO below.) - if isNonTypeParamInterface(T) || constArg && !isConstType(T) || x.isNil() { + if isTypes2 && x.typ == Typ[UntypedNil] { + // ok + } else if isNonTypeParamInterface(T) || constArg && !isConstType(T) || !isTypes2 && x.isNil() { final = Default(x.typ) // default type of untyped nil is untyped nil } else if x.mode == constant_ && isInteger(x.typ) && allString(T) { final = x.typ @@ -136,13 +142,16 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool { return true } - // "V and T have identical underlying types if tags are ignored - // and V and T are not type parameters" - V := x.typ + origT := T + V := Unalias(x.typ) + T = Unalias(T) Vu := under(V) Tu := under(T) Vp, _ := V.(*TypeParam) Tp, _ := T.(*TypeParam) + + // "V and T have identical underlying types if tags are ignored + // and V and T are not type parameters" if IdenticalIgnoreTags(Vu, Tu) && Vp == nil && Tp == nil { return true } @@ -194,25 +203,25 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool { switch a := Tu.(type) { case *Array: if Identical(s.Elem(), a.Elem()) { - if check == nil || check.allowVersion(check.pkg, x, go1_20) { + if check == nil || check.allowVersion(x, go1_20) { return true } // check != nil if cause != nil { // TODO(gri) consider restructuring versionErrorf so we can use it here and below - *cause = "conversion of slices to arrays requires go1.20 or later" + *cause = "conversion of slice to array requires go1.20 or later" } return false } case *Pointer: if a, _ := under(a.Elem()).(*Array); a != nil { if Identical(s.Elem(), a.Elem()) { - if check == nil || check.allowVersion(check.pkg, x, go1_17) { + if check == nil || check.allowVersion(x, go1_17) { return true } // check != nil if cause != nil { - *cause = "conversion of slices to array pointers requires go1.17 or later" + *cause = "conversion of slice to array pointer requires go1.17 or later" } return false } @@ -264,7 +273,7 @@ func (x *operand) convertibleTo(check *Checker, T Type, cause *string) bool { } x.typ = V.typ if !x.convertibleTo(check, T, cause) { - errorf("cannot convert %s (in %s) to type %s", V.typ, Vp, T) + errorf("cannot convert %s (in %s) to type %s", V.typ, Vp, origT) return false } return true diff --git a/contrib/go/_std_1.22/src/go/types/decl.go b/contrib/go/_std_1.23/src/go/types/decl.go similarity index 90% rename from contrib/go/_std_1.22/src/go/types/decl.go rename to contrib/go/_std_1.23/src/go/types/decl.go index 9f8c44ab502e..e9bf802cb8b1 100644 --- a/contrib/go/_std_1.22/src/go/types/decl.go +++ b/contrib/go/_std_1.23/src/go/types/decl.go @@ -9,18 +9,10 @@ import ( "go/ast" "go/constant" "go/token" + "internal/buildcfg" . "internal/types/errors" ) -func (check *Checker) reportAltDecl(obj Object) { - if pos := obj.Pos(); pos.IsValid() { - // We use "other" rather than "previous" here because - // the first declaration seen may not be textually - // earlier in the source. - check.errorf(obj, DuplicateDecl, "\tother declaration of %s", obj.Name()) // secondary error, \t indented - } -} - func (check *Checker) declare(scope *Scope, id *ast.Ident, obj Object, pos token.Pos) { // spec: "The blank identifier, represented by the underscore // character _, may be used in a declaration like any other @@ -28,8 +20,10 @@ func (check *Checker) declare(scope *Scope, id *ast.Ident, obj Object, pos token // binding." if obj.Name() != "_" { if alt := scope.Insert(obj); alt != nil { - check.errorf(obj, DuplicateDecl, "%s redeclared in this block", obj.Name()) - check.reportAltDecl(alt) + err := check.newError(DuplicateDecl) + err.addf(obj, "%s redeclared in this block", obj.Name()) + err.addAltDecl(alt) + err.report() return } obj.setScopePos(pos) @@ -160,7 +154,7 @@ func (check *Checker) objDecl(obj Object, def *TypeName) { } default: - unreachable() + panic("unreachable") } assert(obj.Type() != nil) return @@ -169,7 +163,7 @@ func (check *Checker) objDecl(obj Object, def *TypeName) { d := check.objMap[obj] if d == nil { check.dump("%v: %s should have been declared", obj.Pos(), obj) - unreachable() + panic("unreachable") } // save/restore current environment and set up object environment @@ -200,7 +194,7 @@ func (check *Checker) objDecl(obj Object, def *TypeName) { // functions may be recursive - no need to track dependencies check.funcDecl(obj, d) default: - unreachable() + panic("unreachable") } } @@ -214,7 +208,7 @@ func (check *Checker) validCycle(obj Object) (valid bool) { isPkgObj := obj.Parent() == check.pkg.scope if isPkgObj != inObjMap { check.dump("%v: inconsistent object map for %s (isPkgObj = %v, inObjMap = %v)", obj.Pos(), obj, isPkgObj, inObjMap) - unreachable() + panic("unreachable") } } @@ -249,7 +243,7 @@ loop: // the syntactic information. We should consider storing // this information explicitly in the object. var alias bool - if check.enableAlias { + if check.conf._EnableAlias { alias = obj.IsAlias() } else { if d := check.objMap[obj]; d != nil { @@ -264,7 +258,7 @@ loop: case *Func: // ignored for now default: - unreachable() + panic("unreachable") } } @@ -300,13 +294,12 @@ loop: } } - check.cycleError(cycle) + check.cycleError(cycle, firstInSrc(cycle)) return false } -// cycleError reports a declaration cycle starting with -// the object in cycle that is "first" in the source. -func (check *Checker) cycleError(cycle []Object) { +// cycleError reports a declaration cycle starting with the object at cycle[start]. +func (check *Checker) cycleError(cycle []Object, start int) { // name returns the (possibly qualified) object name. // This is needed because with generic types, cycles // may refer to imported types. See go.dev/issue/50788. @@ -315,18 +308,14 @@ func (check *Checker) cycleError(cycle []Object) { return packagePrefix(obj.Pkg(), check.qualifier) + obj.Name() } - // TODO(gri) Should we start with the last (rather than the first) object in the cycle - // since that is the earliest point in the source where we start seeing the - // cycle? That would be more consistent with other error messages. - i := firstInSrc(cycle) - obj := cycle[i] + obj := cycle[start] objName := name(obj) // If obj is a type alias, mark it as valid (not broken) in order to avoid follow-on errors. tname, _ := obj.(*TypeName) if tname != nil && tname.IsAlias() { // If we use Alias nodes, it is initialized with Typ[Invalid]. // TODO(gri) Adjust this code if we initialize with nil. - if !check.enableAlias { + if !check.conf._EnableAlias { check.validAlias(tname, Typ[Invalid]) } } @@ -341,13 +330,15 @@ func (check *Checker) cycleError(cycle []Object) { return } + err := check.newError(InvalidDeclCycle) if tname != nil { - check.errorf(obj, InvalidDeclCycle, "invalid recursive type %s", objName) + err.addf(obj, "invalid recursive type %s", objName) } else { - check.errorf(obj, InvalidDeclCycle, "invalid cycle in declaration of %s", objName) + err.addf(obj, "invalid cycle in declaration of %s", objName) } + i := start for range cycle { - check.errorf(obj, InvalidDeclCycle, "\t%s refers to", objName) // secondary error, \t indented + err.addf(obj, "%s refers to", objName) i++ if i >= len(cycle) { i = 0 @@ -355,7 +346,8 @@ func (check *Checker) cycleError(cycle []Object) { obj = cycle[i] objName = name(obj) } - check.errorf(obj, InvalidDeclCycle, "\t%s", objName) + err.addf(obj, "%s", objName) + err.report() } // firstInSrc reports the index of the object with the "smallest" @@ -502,7 +494,7 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) { // if any, would not be checked. // // TODO(gri) If we have no init expr, we should distribute - // a given type otherwise we need to re-evalate the type + // a given type otherwise we need to re-evaluate the type // expr for each lhs variable, leading to duplicate work. } @@ -563,37 +555,75 @@ func (check *Checker) isImportedConstraint(typ Type) bool { func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *TypeName) { assert(obj.typ == nil) + // Only report a version error if we have not reported one already. + versionErr := false + var rhs Type check.later(func() { if t := asNamed(obj.typ); t != nil { // type may be invalid check.validType(t) } // If typ is local, an error was already reported where typ is specified/defined. - _ = check.isImportedConstraint(rhs) && check.verifyVersionf(tdecl.Type, go1_18, "using type constraint %s", rhs) + _ = !versionErr && check.isImportedConstraint(rhs) && check.verifyVersionf(tdecl.Type, go1_18, "using type constraint %s", rhs) }).describef(obj, "validType(%s)", obj.Name()) - aliasDecl := tdecl.Assign.IsValid() - if aliasDecl && tdecl.TypeParams.NumFields() != 0 { - // The parser will ensure this but we may still get an invalid AST. - // Complain and continue as regular type definition. - check.error(atPos(tdecl.Assign), BadDecl, "generic type cannot be alias") - aliasDecl = false + // First type parameter, or nil. + var tparam0 *ast.Field + if tdecl.TypeParams.NumFields() > 0 { + tparam0 = tdecl.TypeParams.List[0] } // alias declaration - if aliasDecl { - check.verifyVersionf(atPos(tdecl.Assign), go1_9, "type aliases") - if check.enableAlias { + if tdecl.Assign.IsValid() { + // Report highest version requirement first so that fixing a version issue + // avoids possibly two -lang changes (first to Go 1.9 and then to Go 1.23). + if !versionErr && tparam0 != nil && !check.verifyVersionf(tparam0, go1_23, "generic type alias") { + versionErr = true + } + if !versionErr && !check.verifyVersionf(atPos(tdecl.Assign), go1_9, "type alias") { + versionErr = true + } + + if check.conf._EnableAlias { // TODO(gri) Should be able to use nil instead of Typ[Invalid] to mark // the alias as incomplete. Currently this causes problems // with certain cycles. Investigate. + // + // NOTE(adonovan): to avoid the Invalid being prematurely observed + // by (e.g.) a var whose type is an unfinished cycle, + // Unalias does not memoize if Invalid. Perhaps we should use a + // special sentinel distinct from Invalid. alias := check.newAlias(obj, Typ[Invalid]) setDefType(def, alias) + + // handle type parameters even if not allowed (Alias type is supported) + if tparam0 != nil { + if !versionErr && !buildcfg.Experiment.AliasTypeParams { + check.error(tdecl, UnsupportedFeature, "generic type alias requires GOEXPERIMENT=aliastypeparams") + versionErr = true + } + check.openScope(tdecl, "type parameters") + defer check.closeScope() + check.collectTypeParams(&alias.tparams, tdecl.TypeParams) + } + rhs = check.definedType(tdecl.Type, obj) assert(rhs != nil) alias.fromRHS = rhs Unalias(alias) // resolve alias.actual } else { + // With Go1.23, the default behavior is to use Alias nodes, + // reflected by check.enableAlias. Signal non-default behavior. + // + // TODO(gri) Testing runs tests in both modes. Do we need to exclude + // tracking of non-default behavior for tests? + gotypesalias.IncNonDefault() + + if !versionErr && tparam0 != nil { + check.error(tdecl, UnsupportedFeature, "generic type alias requires GODEBUG=gotypesalias=1 or unset") + versionErr = true + } + check.brokenAlias(obj) rhs = check.typ(tdecl.Type) check.validAlias(obj, rhs) @@ -602,6 +632,10 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *TypeName } // type definition or generic type declaration + if !versionErr && tparam0 != nil && !check.verifyVersionf(tparam0, go1_18, "type parameter") { + versionErr = true + } + named := check.newNamed(obj, nil, nil) setDefType(def, named) @@ -774,7 +808,7 @@ func (check *Checker) collectMethods(obj *TypeName) { assert(m.name != "_") if alt := mset.insert(m); alt != nil { if alt.Pos().IsValid() { - check.errorf(m, DuplicateMethod, "method %s.%s already declared at %s", obj.Name(), m.name, alt.Pos()) + check.errorf(m, DuplicateMethod, "method %s.%s already declared at %v", obj.Name(), m.name, alt.Pos()) } else { check.errorf(m, DuplicateMethod, "method %s.%s already declared", obj.Name(), m.name) } @@ -807,8 +841,10 @@ func (check *Checker) checkFieldUniqueness(base *Named) { // For historical consistency, we report the primary error on the // method, and the alt decl on the field. - check.errorf(alt, DuplicateFieldAndMethod, "field and method with the same name %s", fld.name) - check.reportAltDecl(fld) + err := check.newError(DuplicateFieldAndMethod) + err.addf(alt, "field and method with the same name %s", fld.name) + err.addAltDecl(fld) + err.report() } } } diff --git a/contrib/go/_std_1.23/src/go/types/errors.go b/contrib/go/_std_1.23/src/go/types/errors.go new file mode 100644 index 000000000000..be1ec5d5f7e1 --- /dev/null +++ b/contrib/go/_std_1.23/src/go/types/errors.go @@ -0,0 +1,313 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements error reporting. + +package types + +import ( + "fmt" + "go/ast" + "go/token" + . "internal/types/errors" + "runtime" + "strings" +) + +func assert(p bool) { + if !p { + msg := "assertion failed" + // Include information about the assertion location. Due to panic recovery, + // this location is otherwise buried in the middle of the panicking stack. + if _, file, line, ok := runtime.Caller(1); ok { + msg = fmt.Sprintf("%s:%d: %s", file, line, msg) + } + panic(msg) + } +} + +// An errorDesc describes part of a type-checking error. +type errorDesc struct { + posn positioner + msg string +} + +// An error_ represents a type-checking error. +// A new error_ is created with Checker.newError. +// To report an error_, call error_.report. +type error_ struct { + check *Checker + desc []errorDesc + code Code + soft bool // TODO(gri) eventually determine this from an error code +} + +// newError returns a new error_ with the given error code. +func (check *Checker) newError(code Code) *error_ { + if code == 0 { + panic("error code must not be 0") + } + return &error_{check: check, code: code} +} + +// addf adds formatted error information to err. +// It may be called multiple times to provide additional information. +// The position of the first call to addf determines the position of the reported Error. +// Subsequent calls to addf provide additional information in the form of additional lines +// in the error message (types2) or continuation errors identified by a tab-indented error +// message (go/types). +func (err *error_) addf(at positioner, format string, args ...interface{}) { + err.desc = append(err.desc, errorDesc{at, err.check.sprintf(format, args...)}) +} + +// addAltDecl is a specialized form of addf reporting another declaration of obj. +func (err *error_) addAltDecl(obj Object) { + if pos := obj.Pos(); pos.IsValid() { + // We use "other" rather than "previous" here because + // the first declaration seen may not be textually + // earlier in the source. + err.addf(obj, "other declaration of %s", obj.Name()) + } +} + +func (err *error_) empty() bool { + return err.desc == nil +} + +func (err *error_) posn() positioner { + if err.empty() { + return noposn + } + return err.desc[0].posn +} + +// msg returns the formatted error message without the primary error position pos(). +func (err *error_) msg() string { + if err.empty() { + return "no error" + } + + var buf strings.Builder + for i := range err.desc { + p := &err.desc[i] + if i > 0 { + fmt.Fprint(&buf, "\n\t") + if p.posn.Pos().IsValid() { + fmt.Fprintf(&buf, "%s: ", err.check.fset.Position(p.posn.Pos())) + } + } + buf.WriteString(p.msg) + } + return buf.String() +} + +// report reports the error err, setting check.firstError if necessary. +func (err *error_) report() { + if err.empty() { + panic("no error") + } + + // Cheap trick: Don't report errors with messages containing + // "invalid operand" or "invalid type" as those tend to be + // follow-on errors which don't add useful information. Only + // exclude them if these strings are not at the beginning, + // and only if we have at least one error already reported. + check := err.check + if check.firstErr != nil { + // It is sufficient to look at the first sub-error only. + msg := err.desc[0].msg + if strings.Index(msg, "invalid operand") > 0 || strings.Index(msg, "invalid type") > 0 { + return + } + } + + if check.conf._Trace { + check.trace(err.posn().Pos(), "ERROR: %s (code = %d)", err.desc[0].msg, err.code) + } + + // In go/types, if there is a sub-error with a valid position, + // call the typechecker error handler for each sub-error. + // Otherwise, call it once, with a single combined message. + multiError := false + if !isTypes2 { + for i := 1; i < len(err.desc); i++ { + if err.desc[i].posn.Pos().IsValid() { + multiError = true + break + } + } + } + + if multiError { + for i := range err.desc { + p := &err.desc[i] + check.handleError(i, p.posn, err.code, p.msg, err.soft) + } + } else { + check.handleError(0, err.posn(), err.code, err.msg(), err.soft) + } + + // make sure the error is not reported twice + err.desc = nil +} + +// handleError should only be called by error_.report. +func (check *Checker) handleError(index int, posn positioner, code Code, msg string, soft bool) { + assert(code != 0) + + if index == 0 { + // If we are encountering an error while evaluating an inherited + // constant initialization expression, pos is the position of + // the original expression, and not of the currently declared + // constant identifier. Use the provided errpos instead. + // TODO(gri) We may also want to augment the error message and + // refer to the position (pos) in the original expression. + if check.errpos != nil && check.errpos.Pos().IsValid() { + assert(check.iota != nil) + posn = check.errpos + } + + // Report invalid syntax trees explicitly. + if code == InvalidSyntaxTree { + msg = "invalid syntax tree: " + msg + } + + // If we have a URL for error codes, add a link to the first line. + if check.conf._ErrorURL != "" { + url := fmt.Sprintf(check.conf._ErrorURL, code) + if i := strings.Index(msg, "\n"); i >= 0 { + msg = msg[:i] + url + msg[i:] + } else { + msg += url + } + } + } else { + // Indent sub-error. + // Position information is passed explicitly to Error, below. + msg = "\t" + msg + } + + span := spanOf(posn) + e := Error{ + Fset: check.fset, + Pos: span.pos, + Msg: stripAnnotations(msg), + Soft: soft, + go116code: code, + go116start: span.start, + go116end: span.end, + } + + if check.errpos != nil { + // If we have an internal error and the errpos override is set, use it to + // augment our error positioning. + // TODO(rFindley) we may also want to augment the error message and refer + // to the position (pos) in the original expression. + span := spanOf(check.errpos) + e.Pos = span.pos + e.go116start = span.start + e.go116end = span.end + } + + if check.firstErr == nil { + check.firstErr = e + } + + f := check.conf.Error + if f == nil { + panic(bailout{}) // record first error and exit + } + f(e) +} + +const ( + invalidArg = "invalid argument: " + invalidOp = "invalid operation: " +) + +// The positioner interface is used to extract the position of type-checker errors. +type positioner interface { + Pos() token.Pos +} + +func (check *Checker) error(at positioner, code Code, msg string) { + err := check.newError(code) + err.addf(at, "%s", msg) + err.report() +} + +func (check *Checker) errorf(at positioner, code Code, format string, args ...any) { + err := check.newError(code) + err.addf(at, format, args...) + err.report() +} + +func (check *Checker) softErrorf(at positioner, code Code, format string, args ...any) { + err := check.newError(code) + err.addf(at, format, args...) + err.soft = true + err.report() +} + +func (check *Checker) versionErrorf(at positioner, v goVersion, format string, args ...any) { + msg := check.sprintf(format, args...) + err := check.newError(UnsupportedFeature) + err.addf(at, "%s requires %s or later", msg, v) + err.report() +} + +// atPos wraps a token.Pos to implement the positioner interface. +type atPos token.Pos + +func (s atPos) Pos() token.Pos { + return token.Pos(s) +} + +// posSpan holds a position range along with a highlighted position within that +// range. This is used for positioning errors, with pos by convention being the +// first position in the source where the error is known to exist, and start +// and end defining the full span of syntax being considered when the error was +// detected. Invariant: start <= pos < end || start == pos == end. +type posSpan struct { + start, pos, end token.Pos +} + +func (e posSpan) Pos() token.Pos { + return e.pos +} + +// inNode creates a posSpan for the given node. +// Invariant: node.Pos() <= pos < node.End() (node.End() is the position of the +// first byte after node within the source). +func inNode(node ast.Node, pos token.Pos) posSpan { + start, end := node.Pos(), node.End() + if debug { + assert(start <= pos && pos < end) + } + return posSpan{start, pos, end} +} + +// spanOf extracts an error span from the given positioner. By default this is +// the trivial span starting and ending at pos, but this span is expanded when +// the argument naturally corresponds to a span of source code. +func spanOf(at positioner) posSpan { + switch x := at.(type) { + case nil: + panic("nil positioner") + case posSpan: + return x + case ast.Node: + pos := x.Pos() + return posSpan{pos, pos, x.End()} + case *operand: + if x.expr != nil { + pos := x.Pos() + return posSpan{pos, pos, x.expr.End()} + } + return posSpan{nopos, nopos, nopos} + default: + pos := at.Pos() + return posSpan{pos, pos, pos} + } +} diff --git a/contrib/go/_std_1.23/src/go/types/errsupport.go b/contrib/go/_std_1.23/src/go/types/errsupport.go new file mode 100644 index 000000000000..68d55aa1ac54 --- /dev/null +++ b/contrib/go/_std_1.23/src/go/types/errsupport.go @@ -0,0 +1,116 @@ +// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/errsupport.go + +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements support functions for error messages. + +package types + +// lookupError returns a case-specific error when a lookup of selector sel in the +// given type fails but an object with alternative spelling (case folding) is found. +// If structLit is set, the error message is specifically for struct literal fields. +func (check *Checker) lookupError(typ Type, sel string, obj Object, structLit bool) string { + // Provide more detail if there is an unexported object, or one with different capitalization. + // If selector and object are in the same package (==), export doesn't matter, otherwise (!=) it does. + // Messages depend on whether it's a general lookup or a field lookup in a struct literal. + // + // case sel pkg have message (examples for general lookup) + // --------------------------------------------------------------------------------------------------------- + // ok x.Foo == Foo + // misspelled x.Foo == FoO type X has no field or method Foo, but does have field FoO + // misspelled x.Foo == foo type X has no field or method Foo, but does have field foo + // misspelled x.Foo == foO type X has no field or method Foo, but does have field foO + // + // misspelled x.foo == Foo type X has no field or method foo, but does have field Foo + // misspelled x.foo == FoO type X has no field or method foo, but does have field FoO + // ok x.foo == foo + // misspelled x.foo == foO type X has no field or method foo, but does have field foO + // + // ok x.Foo != Foo + // misspelled x.Foo != FoO type X has no field or method Foo, but does have field FoO + // unexported x.Foo != foo type X has no field or method Foo, but does have unexported field foo + // missing x.Foo != foO type X has no field or method Foo + // + // misspelled x.foo != Foo type X has no field or method foo, but does have field Foo + // missing x.foo != FoO type X has no field or method foo + // inaccessible x.foo != foo cannot refer to unexported field foo + // missing x.foo != foO type X has no field or method foo + + const ( + ok = iota + missing // no object found + misspelled // found object with different spelling + unexported // found object with name differing only in first letter + inaccessible // found object with matching name but inaccessible from the current package + ) + + // determine case + e := missing + var alt string // alternative spelling of selector; if any + if obj != nil { + alt = obj.Name() + if obj.Pkg() == check.pkg { + assert(alt != sel) // otherwise there is no lookup error + e = misspelled + } else if isExported(sel) { + if isExported(alt) { + e = misspelled + } else if tail(sel) == tail(alt) { + e = unexported + } + } else if isExported(alt) { + if tail(sel) == tail(alt) { + e = misspelled + } + } else if sel == alt { + e = inaccessible + } + } + + if structLit { + switch e { + case missing: + return check.sprintf("unknown field %s in struct literal of type %s", sel, typ) + case misspelled: + return check.sprintf("unknown field %s in struct literal of type %s, but does have %s", sel, typ, alt) + case unexported: + return check.sprintf("unknown field %s in struct literal of type %s, but does have unexported %s", sel, typ, alt) + case inaccessible: + return check.sprintf("cannot refer to unexported field %s in struct literal of type %s", alt, typ) + } + } else { + what := "object" + switch obj.(type) { + case *Var: + what = "field" + case *Func: + what = "method" + } + switch e { + case missing: + return check.sprintf("type %s has no field or method %s", typ, sel) + case misspelled: + return check.sprintf("type %s has no field or method %s, but does have %s %s", typ, sel, what, alt) + case unexported: + return check.sprintf("type %s has no field or method %s, but does have unexported %s %s", typ, sel, what, alt) + case inaccessible: + return check.sprintf("cannot refer to unexported %s %s", what, alt) + } + } + + panic("unreachable") +} + +// tail returns the string s without its first (UTF-8) character. +// If len(s) == 0, the result is s. +func tail(s string) string { + for i, _ := range s { + if i > 0 { + return s[i:] + } + } + return s +} diff --git a/contrib/go/_std_1.22/src/go/types/eval.go b/contrib/go/_std_1.23/src/go/types/eval.go similarity index 100% rename from contrib/go/_std_1.22/src/go/types/eval.go rename to contrib/go/_std_1.23/src/go/types/eval.go diff --git a/contrib/go/_std_1.22/src/go/types/expr.go b/contrib/go/_std_1.23/src/go/types/expr.go similarity index 97% rename from contrib/go/_std_1.22/src/go/types/expr.go rename to contrib/go/_std_1.23/src/go/types/expr.go index 8651ddad93a8..cf8ceddc9ace 100644 --- a/contrib/go/_std_1.22/src/go/types/expr.go +++ b/contrib/go/_std_1.23/src/go/types/expr.go @@ -13,6 +13,7 @@ import ( "go/internal/typeparams" "go/token" . "internal/types/errors" + "strings" ) /* @@ -116,6 +117,7 @@ var op2str2 = [...]string{ // If typ is a type parameter, underIs returns the result of typ.underIs(f). // Otherwise, underIs returns the result of f(under(typ)). func underIs(typ Type, f func(Type) bool) bool { + typ = Unalias(typ) if tpar, _ := typ.(*TypeParam); tpar != nil { return tpar.underIs(f) } @@ -134,7 +136,7 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) { case token.AND: // spec: "As an exception to the addressability // requirement x may also be a composite literal." - if _, ok := unparen(e.X).(*ast.CompositeLit); !ok && x.mode != variable { + if _, ok := ast.Unparen(e.X).(*ast.CompositeLit); !ok && x.mode != variable { check.errorf(x, UnaddressableOperand, invalidOp+"cannot take address of %s", x) x.mode = invalid return @@ -255,7 +257,7 @@ func (check *Checker) updateExprType0(parent, x ast.Expr, typ Type, final bool) // upon assignment or use. if debug { check.dump("%v: found old type(%s): %s (new: %s)", x.Pos(), x, old.typ, typ) - unreachable() + panic("unreachable") } return @@ -301,7 +303,7 @@ func (check *Checker) updateExprType0(parent, x ast.Expr, typ Type, final bool) } default: - unreachable() + panic("unreachable") } // If the new type is not final and still untyped, just @@ -524,7 +526,7 @@ func (check *Checker) comparison(x, y *operand, op token.Token, switchCase bool) } default: - unreachable() + panic("unreachable") } // comparison is ok @@ -996,7 +998,7 @@ func (check *Checker) nonGeneric(T *target, x *operand) { } var what string switch t := x.typ.(type) { - case *Named: + case *Alias, *Named: if isGeneric(t) { what = "type" } @@ -1016,6 +1018,35 @@ func (check *Checker) nonGeneric(T *target, x *operand) { } } +// langCompat reports an error if the representation of a numeric +// literal is not compatible with the current language version. +func (check *Checker) langCompat(lit *ast.BasicLit) { + s := lit.Value + if len(s) <= 2 || check.allowVersion(lit, go1_13) { + return + } + // len(s) > 2 + if strings.Contains(s, "_") { + check.versionErrorf(lit, go1_13, "underscore in numeric literal") + return + } + if s[0] != '0' { + return + } + radix := s[1] + if radix == 'b' || radix == 'B' { + check.versionErrorf(lit, go1_13, "binary literal") + return + } + if radix == 'o' || radix == 'O' { + check.versionErrorf(lit, go1_13, "0o/0O-style octal literal") + return + } + if lit.Kind != token.INT && (radix == 'x' || radix == 'X') { + check.versionErrorf(lit, go1_13, "hexadecimal floating-point literal") + } +} + // exprInternal contains the core of type checking of expressions. // Must only be called by rawExpr. // (See rawExpr for an explanation of the parameters.) @@ -1092,7 +1123,7 @@ func (check *Checker) exprInternal(T *target, x *operand, e ast.Expr, hint Type) x.mode = value x.typ = sig } else { - check.errorf(e, InvalidSyntaxTree, "invalid function literal %s", e) + check.errorf(e, InvalidSyntaxTree, "invalid function literal %v", e) goto Error } @@ -1164,9 +1195,14 @@ func (check *Checker) exprInternal(T *target, x *operand, e ast.Expr, hint Type) check.errorf(kv, InvalidLitField, "invalid field name %s in struct literal", kv.Key) continue } - i := fieldIndex(utyp.fields, check.pkg, key.Name) + i := fieldIndex(utyp.fields, check.pkg, key.Name, false) if i < 0 { - check.errorf(kv, MissingLitField, "unknown field %s in struct literal of type %s", key.Name, base) + var alt Object + if j := fieldIndex(fields, check.pkg, key.Name, true); j >= 0 { + alt = fields[j] + } + msg := check.lookupError(base, key.Name, alt, true) + check.error(kv.Key, MissingLitField, msg) continue } fld := fields[i] @@ -1596,7 +1632,7 @@ func (check *Checker) exclude(x *operand, modeset uint) { msg = "%s is not an expression" code = NotAnExpr default: - unreachable() + panic("unreachable") } check.errorf(x, code, msg, x) x.mode = invalid diff --git a/contrib/go/_std_1.22/src/go/types/exprstring.go b/contrib/go/_std_1.23/src/go/types/exprstring.go similarity index 99% rename from contrib/go/_std_1.22/src/go/types/exprstring.go rename to contrib/go/_std_1.23/src/go/types/exprstring.go index 3cdf30fba1a5..0403a06d8c53 100644 --- a/contrib/go/_std_1.22/src/go/types/exprstring.go +++ b/contrib/go/_std_1.23/src/go/types/exprstring.go @@ -105,7 +105,7 @@ func WriteExpr(buf *bytes.Buffer, x ast.Expr) { WriteExpr(buf, x.Fun) buf.WriteByte('(') writeExprList(buf, x.Args) - if x.Ellipsis.IsValid() { + if hasDots(x) { buf.WriteString("...") } buf.WriteByte(')') diff --git a/contrib/go/_std_1.23/src/go/types/format.go b/contrib/go/_std_1.23/src/go/types/format.go new file mode 100644 index 000000000000..09e599c3c336 --- /dev/null +++ b/contrib/go/_std_1.23/src/go/types/format.go @@ -0,0 +1,153 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements (error and trace) message formatting support. + +package types + +import ( + "bytes" + "fmt" + "go/ast" + "go/token" + "strconv" + "strings" +) + +func sprintf(fset *token.FileSet, qf Qualifier, tpSubscripts bool, format string, args ...any) string { + for i, arg := range args { + switch a := arg.(type) { + case nil: + arg = "" + case operand: + panic("got operand instead of *operand") + case *operand: + arg = operandString(a, qf) + case token.Pos: + if fset != nil { + arg = fset.Position(a).String() + } + case ast.Expr: + arg = ExprString(a) + case []ast.Expr: + var buf bytes.Buffer + buf.WriteByte('[') + writeExprList(&buf, a) + buf.WriteByte(']') + arg = buf.String() + case Object: + arg = ObjectString(a, qf) + case Type: + var buf bytes.Buffer + w := newTypeWriter(&buf, qf) + w.tpSubscripts = tpSubscripts + w.typ(a) + arg = buf.String() + case []Type: + var buf bytes.Buffer + w := newTypeWriter(&buf, qf) + w.tpSubscripts = tpSubscripts + buf.WriteByte('[') + for i, x := range a { + if i > 0 { + buf.WriteString(", ") + } + w.typ(x) + } + buf.WriteByte(']') + arg = buf.String() + case []*TypeParam: + var buf bytes.Buffer + w := newTypeWriter(&buf, qf) + w.tpSubscripts = tpSubscripts + buf.WriteByte('[') + for i, x := range a { + if i > 0 { + buf.WriteString(", ") + } + w.typ(x) + } + buf.WriteByte(']') + arg = buf.String() + } + args[i] = arg + } + return fmt.Sprintf(format, args...) +} + +// check may be nil. +func (check *Checker) sprintf(format string, args ...any) string { + var fset *token.FileSet + var qf Qualifier + if check != nil { + fset = check.fset + qf = check.qualifier + } + return sprintf(fset, qf, false, format, args...) +} + +func (check *Checker) trace(pos token.Pos, format string, args ...any) { + fmt.Printf("%s:\t%s%s\n", + check.fset.Position(pos), + strings.Repeat(". ", check.indent), + sprintf(check.fset, check.qualifier, true, format, args...), + ) +} + +// dump is only needed for debugging +func (check *Checker) dump(format string, args ...any) { + fmt.Println(sprintf(check.fset, check.qualifier, true, format, args...)) +} + +func (check *Checker) qualifier(pkg *Package) string { + // Qualify the package unless it's the package being type-checked. + if pkg != check.pkg { + if check.pkgPathMap == nil { + check.pkgPathMap = make(map[string]map[string]bool) + check.seenPkgMap = make(map[*Package]bool) + check.markImports(check.pkg) + } + // If the same package name was used by multiple packages, display the full path. + if len(check.pkgPathMap[pkg.name]) > 1 { + return strconv.Quote(pkg.path) + } + return pkg.name + } + return "" +} + +// markImports recursively walks pkg and its imports, to record unique import +// paths in pkgPathMap. +func (check *Checker) markImports(pkg *Package) { + if check.seenPkgMap[pkg] { + return + } + check.seenPkgMap[pkg] = true + + forName, ok := check.pkgPathMap[pkg.name] + if !ok { + forName = make(map[string]bool) + check.pkgPathMap[pkg.name] = forName + } + forName[pkg.path] = true + + for _, imp := range pkg.imports { + check.markImports(imp) + } +} + +// stripAnnotations removes internal (type) annotations from s. +func stripAnnotations(s string) string { + var buf strings.Builder + for _, r := range s { + // strip #'s and subscript digits + if r < '₀' || '₀'+10 <= r { // '₀' == U+2080 + buf.WriteRune(r) + } + } + if buf.Len() < len(s) { + return buf.String() + } + return s +} diff --git a/contrib/go/_std_1.22/src/go/types/gccgosizes.go b/contrib/go/_std_1.23/src/go/types/gccgosizes.go similarity index 94% rename from contrib/go/_std_1.22/src/go/types/gccgosizes.go rename to contrib/go/_std_1.23/src/go/types/gccgosizes.go index 9152c811e106..6aa9e1e58638 100644 --- a/contrib/go/_std_1.22/src/go/types/gccgosizes.go +++ b/contrib/go/_std_1.23/src/go/types/gccgosizes.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/gccgosizes.go // Copyright 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/contrib/go/_std_1.22/src/go/types/gcsizes.go b/contrib/go/_std_1.23/src/go/types/gcsizes.go similarity index 97% rename from contrib/go/_std_1.22/src/go/types/gcsizes.go rename to contrib/go/_std_1.23/src/go/types/gcsizes.go index 4329cc22e82f..227c53e1d280 100644 --- a/contrib/go/_std_1.22/src/go/types/gcsizes.go +++ b/contrib/go/_std_1.23/src/go/types/gcsizes.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/gcsizes.go // Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -58,7 +59,7 @@ func (s *gcSizes) Alignof(T Type) (result int64) { return s.WordSize } case *TypeParam, *Union: - unreachable() + panic("unreachable") } a := s.Sizeof(T) // may be 0 or negative // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1." @@ -156,7 +157,7 @@ func (s *gcSizes) Sizeof(T Type) int64 { assert(!isTypeParam(T)) return s.WordSize * 2 case *TypeParam, *Union: - unreachable() + panic("unreachable") } return s.WordSize // catch-all } diff --git a/contrib/go/_std_1.22/src/go/types/generate.go b/contrib/go/_std_1.23/src/go/types/generate.go similarity index 100% rename from contrib/go/_std_1.22/src/go/types/generate.go rename to contrib/go/_std_1.23/src/go/types/generate.go diff --git a/contrib/go/_std_1.22/src/go/types/gotype.go b/contrib/go/_std_1.23/src/go/types/gotype.go similarity index 100% rename from contrib/go/_std_1.22/src/go/types/gotype.go rename to contrib/go/_std_1.23/src/go/types/gotype.go diff --git a/contrib/go/_std_1.22/src/go/types/index.go b/contrib/go/_std_1.23/src/go/types/index.go similarity index 99% rename from contrib/go/_std_1.22/src/go/types/index.go rename to contrib/go/_std_1.23/src/go/types/index.go index 6f532a96c176..7a1666b59ab9 100644 --- a/contrib/go/_std_1.22/src/go/types/index.go +++ b/contrib/go/_std_1.23/src/go/types/index.go @@ -172,7 +172,7 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst // ok to continue even if indexing failed - map element type is known x.mode = mapindex x.typ = elem - x.expr = e + x.expr = e.Orig return false } diff --git a/contrib/go/_std_1.22/src/go/types/infer.go b/contrib/go/_std_1.23/src/go/types/infer.go similarity index 94% rename from contrib/go/_std_1.22/src/go/types/infer.go rename to contrib/go/_std_1.23/src/go/types/infer.go index 889de000b0ca..d0f1c1caf48f 100644 --- a/contrib/go/_std_1.22/src/go/types/infer.go +++ b/contrib/go/_std_1.23/src/go/types/infer.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/infer.go // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -11,7 +12,6 @@ package types import ( "fmt" "go/token" - . "internal/types/errors" "strings" ) @@ -29,8 +29,9 @@ const enableReverseTypeInference = true // disable for debugging // If reverse is set, an error message's contents are reversed for a better error message for some // errors related to reverse type inference (where the function call is synthetic). // If successful, infer returns the complete list of given and inferred type arguments, one for each -// type parameter. Otherwise the result is nil and appropriate errors will be reported. -func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand, reverse bool) (inferred []Type) { +// type parameter. Otherwise the result is nil. Errors are reported through the err parameter. +// Note: infer may fail (return nil) due to invalid args operands without reporting additional errors. +func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, params *Tuple, args []*operand, reverse bool, err *error_) (inferred []Type) { // Don't verify result conditions if there's no error handler installed: // in that case, an error leads to an exit panic and the result value may // be incorrect. But in that case it doesn't matter because callers won't @@ -112,7 +113,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, // Unify parameter and argument types for generic parameters with typed arguments // and collect the indices of generic parameters with untyped arguments. // Terminology: generic parameter = function parameter with a type-parameterized type - u := newUnifier(tparams, targs, check.allowVersion(check.pkg, posn, go1_21)) + u := newUnifier(tparams, targs, check.allowVersion(posn, go1_21)) errorf := func(tpar, targ Type, arg *operand) { // provide a better error message if we can @@ -129,7 +130,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, } } if allFailed { - check.errorf(arg, CannotInferTypeArgs, "type %s of %s does not match %s (cannot infer %s)", targ, arg.expr, tpar, typeParamsString(tparams)) + err.addf(arg, "type %s of %s does not match %s (cannot infer %s)", targ, arg.expr, tpar, typeParamsString(tparams)) return } } @@ -142,12 +143,12 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, // the more general CannotInferTypeArgs. if inferred != tpar { if reverse { - check.errorf(arg, CannotInferTypeArgs, "inferred type %s for %s does not match type %s of %s", inferred, tpar, targ, arg.expr) + err.addf(arg, "inferred type %s for %s does not match type %s of %s", inferred, tpar, targ, arg.expr) } else { - check.errorf(arg, CannotInferTypeArgs, "type %s of %s does not match inferred type %s for %s", targ, arg.expr, inferred, tpar) + err.addf(arg, "type %s of %s does not match inferred type %s for %s", targ, arg.expr, inferred, tpar) } } else { - check.errorf(arg, CannotInferTypeArgs, "type %s of %s does not match %s", targ, arg.expr, tpar) + err.addf(arg, "type %s of %s does not match %s", targ, arg.expr, tpar) } } @@ -186,6 +187,10 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, // Thus, for untyped arguments we only need to look at parameter types // that are single type parameters. // Also, untyped nils don't have a default type and can be ignored. + // Finally, it's not possible to have an alias type denoting a type + // parameter declared by the current function and use it in the same + // function signature; hence we don't need to Unalias before the + // .(*TypeParam) type assertion above. untyped = append(untyped, i) } } @@ -254,7 +259,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, // TODO(gri) Type parameters that appear in the constraint and // for which we have type arguments inferred should // use those type arguments for a better error message. - check.errorf(posn, CannotInferTypeArgs, "%s (type %s) does not satisfy %s", tpar, tx, tpar.Constraint()) + err.addf(posn, "%s (type %s) does not satisfy %s", tpar, tx, tpar.Constraint()) return nil } case single && !core.tilde: @@ -279,7 +284,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, constraint := tpar.iface() if m, _ := check.missingMethod(tx, constraint, true, func(x, y Type) bool { return u.unify(x, y, exact) }, &cause); m != nil { // TODO(gri) better error message (see TODO above) - check.errorf(posn, CannotInferTypeArgs, "%s (type %s) does not satisfy %s %s", tpar, tx, tpar.Constraint(), cause) + err.addf(posn, "%s (type %s) does not satisfy %s %s", tpar, tx, tpar.Constraint(), cause) return nil } } @@ -308,7 +313,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, // maximum untyped type for each of those parameters, if possible. var maxUntyped map[*TypeParam]Type // lazily allocated (we may not need it) for _, index := range untyped { - tpar := params.At(index).typ.(*TypeParam) // is type parameter by construction of untyped + tpar := params.At(index).typ.(*TypeParam) // is type parameter (no alias) by construction of untyped if u.at(tpar) == nil { arg := args[index] // arg corresponding to tpar if maxUntyped == nil { @@ -320,7 +325,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, } else { m := maxType(max, arg.typ) if m == nil { - check.errorf(arg, CannotInferTypeArgs, "mismatched types %s and %s (cannot infer %s)", max, arg.typ, tpar) + err.addf(arg, "mismatched types %s and %s (cannot infer %s)", max, arg.typ, tpar) return nil } max = m @@ -429,7 +434,7 @@ func (check *Checker) infer(posn positioner, tparams []*TypeParam, targs []Type, for i, typ := range inferred { if typ == nil || isParameterized(tparams, typ) { obj := tparams[i].obj - check.errorf(posn, CannotInferTypeArgs, "cannot infer %s (%s)", obj.name, obj.pos) + err.addf(posn, "cannot infer %s (%v)", obj.name, obj.pos) return nil } } @@ -691,6 +696,7 @@ type cycleFinder struct { } func (w *cycleFinder) typ(typ Type) { + typ = Unalias(typ) if w.seen[typ] { // We have seen typ before. If it is one of the type parameters // in w.tparams, iterative substitution will lead to infinite expansion. @@ -712,8 +718,8 @@ func (w *cycleFinder) typ(typ Type) { case *Basic: // nothing to do - case *Alias: - w.typ(Unalias(t)) + // *Alias: + // This case should not occur because of Unalias(typ) at the top. case *Array: w.typ(t.elem) diff --git a/contrib/go/_std_1.22/src/go/types/initorder.go b/contrib/go/_std_1.23/src/go/types/initorder.go similarity index 96% rename from contrib/go/_std_1.22/src/go/types/initorder.go rename to contrib/go/_std_1.23/src/go/types/initorder.go index a8d8f26b2242..e539219773bb 100644 --- a/contrib/go/_std_1.22/src/go/types/initorder.go +++ b/contrib/go/_std_1.23/src/go/types/initorder.go @@ -1,3 +1,6 @@ +// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/initorder.go + // Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -160,14 +163,16 @@ func (check *Checker) reportCycle(cycle []Object) { return } - check.errorf(obj, InvalidInitCycle, "initialization cycle for %s", obj.Name()) + err := check.newError(InvalidInitCycle) + err.addf(obj, "initialization cycle for %s", obj.Name()) // subtle loop: print cycle[i] for i = 0, n-1, n-2, ... 1 for len(cycle) = n for i := len(cycle) - 1; i >= 0; i-- { - check.errorf(obj, InvalidInitCycle, "\t%s refers to", obj.Name()) // secondary error, \t indented + err.addf(obj, "%s refers to", obj.Name()) obj = cycle[i] } // print cycle[0] again to close the cycle - check.errorf(obj, InvalidInitCycle, "\t%s", obj.Name()) + err.addf(obj, "%s", obj.Name()) + err.report() } // ---------------------------------------------------------------------------- diff --git a/contrib/go/_std_1.22/src/go/types/instantiate.go b/contrib/go/_std_1.23/src/go/types/instantiate.go similarity index 85% rename from contrib/go/_std_1.22/src/go/types/instantiate.go rename to contrib/go/_std_1.23/src/go/types/instantiate.go index bf7ecc531690..0435f2bf2616 100644 --- a/contrib/go/_std_1.22/src/go/types/instantiate.go +++ b/contrib/go/_std_1.23/src/go/types/instantiate.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/instantiate.go // Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -13,15 +14,24 @@ import ( "errors" "fmt" "go/token" + "internal/buildcfg" . "internal/types/errors" ) +// A genericType implements access to its type parameters. +type genericType interface { + Type + TypeParams() *TypeParamList +} + // Instantiate instantiates the type orig with the given type arguments targs. -// orig must be a *Named or a *Signature type. If there is no error, the -// resulting Type is an instantiated type of the same kind (either a *Named or -// a *Signature). Methods attached to a *Named type are also instantiated, and -// associated with a new *Func that has the same position as the original -// method, but nil function scope. +// orig must be an *Alias, *Named, or *Signature type. If there is no error, +// the resulting Type is an instantiated type of the same kind (*Alias, *Named +// or *Signature, respectively). +// +// Methods attached to a *Named type are also instantiated, and associated with +// a new *Func that has the same position as the original method, but nil function +// scope. // // If ctxt is non-nil, it may be used to de-duplicate the instance against // previous instances with the same identity. As a special case, generic @@ -31,10 +41,10 @@ import ( // not guarantee that identical instances are deduplicated in all cases. // // If validate is set, Instantiate verifies that the number of type arguments -// and parameters match, and that the type arguments satisfy their -// corresponding type constraints. If verification fails, the resulting error -// may wrap an *ArgumentError indicating which type argument did not satisfy -// its corresponding type parameter constraint, and why. +// and parameters match, and that the type arguments satisfy their respective +// type constraints. If verification fails, the resulting error may wrap an +// *ArgumentError indicating which type argument did not satisfy its type parameter +// constraint, and why. // // If validate is not set, Instantiate does not verify the type argument count // or whether the type arguments satisfy their constraints. Instantiate is @@ -43,17 +53,15 @@ import ( // count is incorrect; for *Named types, a panic may occur later inside the // *Named API. func Instantiate(ctxt *Context, orig Type, targs []Type, validate bool) (Type, error) { + assert(len(targs) > 0) if ctxt == nil { ctxt = NewContext() } + orig_ := orig.(genericType) // signature of Instantiate must not change for backward-compatibility + if validate { - var tparams []*TypeParam - switch t := orig.(type) { - case *Named: - tparams = t.TypeParams().list() - case *Signature: - tparams = t.TypeParams().list() - } + tparams := orig_.TypeParams().list() + assert(len(tparams) > 0) if len(targs) != len(tparams) { return nil, fmt.Errorf("got %d type arguments but %s has %d type parameters", len(targs), orig, len(tparams)) } @@ -62,7 +70,7 @@ func Instantiate(ctxt *Context, orig Type, targs []Type, validate bool) (Type, e } } - inst := (*Checker)(nil).instance(nopos, orig, targs, nil, ctxt) + inst := (*Checker)(nil).instance(nopos, orig_, targs, nil, ctxt) return inst, nil } @@ -77,7 +85,7 @@ func Instantiate(ctxt *Context, orig Type, targs []Type, validate bool) (Type, e // must be non-nil. // // For Named types the resulting instance may be unexpanded. -func (check *Checker) instance(pos token.Pos, orig Type, targs []Type, expanding *Named, ctxt *Context) (res Type) { +func (check *Checker) instance(pos token.Pos, orig genericType, targs []Type, expanding *Named, ctxt *Context) (res Type) { // The order of the contexts below matters: we always prefer instances in the // expanding instance context in order to preserve reference cycles. // @@ -99,8 +107,9 @@ func (check *Checker) instance(pos token.Pos, orig Type, targs []Type, expanding hashes[i] = ctxt.instanceHash(orig, targs) } - // If local is non-nil, updateContexts return the type recorded in - // local. + // Record the result in all contexts. + // Prefer to re-use existing types from expanding context, if it exists, to reduce + // the memory pinned by the Named type. updateContexts := func(res Type) Type { for i := len(ctxts) - 1; i >= 0; i-- { res = ctxts[i].update(hashes[i], orig, targs, res) @@ -120,6 +129,22 @@ func (check *Checker) instance(pos token.Pos, orig Type, targs []Type, expanding case *Named: res = check.newNamedInstance(pos, orig, targs, expanding) // substituted lazily + case *Alias: + if !buildcfg.Experiment.AliasTypeParams { + assert(expanding == nil) // Alias instances cannot be reached from Named types + } + + tparams := orig.TypeParams() + // TODO(gri) investigate if this is needed (type argument and parameter count seem to be correct here) + if !check.validateTArgLen(pos, orig.String(), tparams.Len(), len(targs)) { + return Typ[Invalid] + } + if tparams.Len() == 0 { + return orig // nothing to do (minor optimization) + } + + return check.newAliasInstance(pos, orig, targs, expanding, ctxt) + case *Signature: assert(expanding == nil) // function instances cannot be reached from Named types @@ -273,7 +298,7 @@ func (check *Checker) implements(pos token.Pos, V, T Type, constraint bool, caus // so that ordinary, non-type parameter interfaces implement comparable. if constraint && comparable(V, true /* spec comparability */, nil, nil) { // V is comparable if we are at Go 1.20 or higher. - if check == nil || check.allowVersion(check.pkg, atPos(pos), go1_20) { // atPos needed so that go/types generate passes + if check == nil || check.allowVersion(atPos(pos), go1_20) { // atPos needed so that go/types generate passes return true } if cause != nil { diff --git a/contrib/go/_std_1.22/src/go/types/interface.go b/contrib/go/_std_1.23/src/go/types/interface.go similarity index 100% rename from contrib/go/_std_1.22/src/go/types/interface.go rename to contrib/go/_std_1.23/src/go/types/interface.go diff --git a/contrib/go/_std_1.22/src/go/types/labels.go b/contrib/go/_std_1.23/src/go/types/labels.go similarity index 97% rename from contrib/go/_std_1.22/src/go/types/labels.go rename to contrib/go/_std_1.23/src/go/types/labels.go index 5ee941e369ff..2f7f7bd20c05 100644 --- a/contrib/go/_std_1.22/src/go/types/labels.go +++ b/contrib/go/_std_1.23/src/go/types/labels.go @@ -27,8 +27,8 @@ func (check *Checker) labels(body *ast.BlockStmt) { name := jmp.Label.Name if alt := all.Lookup(name); alt != nil { msg = "goto %s jumps into block" - alt.(*Label).used = true // avoid another error code = JumpIntoBlock + alt.(*Label).used = true // avoid another error } else { msg = "label %s not declared" code = UndeclaredLabel @@ -138,8 +138,11 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *ast.Labele if name := s.Label.Name; name != "_" { lbl := NewLabel(s.Label.Pos(), check.pkg, name) if alt := all.Insert(lbl); alt != nil { - check.softErrorf(lbl, DuplicateLabel, "label %s already declared", name) - check.reportAltDecl(alt) + err := check.newError(DuplicateLabel) + err.soft = true + err.addf(lbl, "label %s already declared", name) + err.addAltDecl(alt) + err.report() // ok to continue } else { b.insert(s) diff --git a/contrib/go/_std_1.22/src/go/types/lookup.go b/contrib/go/_std_1.23/src/go/types/lookup.go similarity index 94% rename from contrib/go/_std_1.22/src/go/types/lookup.go rename to contrib/go/_std_1.23/src/go/types/lookup.go index 7723c4356527..d25662ac5ead 100644 --- a/contrib/go/_std_1.22/src/go/types/lookup.go +++ b/contrib/go/_std_1.23/src/go/types/lookup.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/lookup.go // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -11,7 +12,6 @@ package types import ( "bytes" "go/token" - "strings" ) // Internal use of LookupFieldOrMethod: If the obj result is a method @@ -48,7 +48,12 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o if T == nil { panic("LookupFieldOrMethod on nil type") } + return lookupFieldOrMethod(T, addressable, pkg, name, false) +} +// lookupFieldOrMethod is like LookupFieldOrMethod but with the additional foldCase parameter +// (see Object.sameId for the meaning of foldCase). +func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string, foldCase bool) (obj Object, index []int, indirect bool) { // Methods cannot be associated to a named pointer type. // (spec: "The type denoted by T is called the receiver base type; // it must not be a pointer or interface type and it must be declared @@ -58,7 +63,7 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o // not have found it for T (see also go.dev/issue/8590). if t := asNamed(T); t != nil { if p, _ := t.Underlying().(*Pointer); p != nil { - obj, index, indirect = lookupFieldOrMethodImpl(p, false, pkg, name, false) + obj, index, indirect = lookupFieldOrMethodImpl(p, false, pkg, name, foldCase) if _, ok := obj.(*Func); ok { return nil, nil, false } @@ -66,7 +71,7 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o } } - obj, index, indirect = lookupFieldOrMethodImpl(T, addressable, pkg, name, false) + obj, index, indirect = lookupFieldOrMethodImpl(T, addressable, pkg, name, foldCase) // If we didn't find anything and if we have a type parameter with a core type, // see if there is a matching field (but not a method, those need to be declared @@ -75,7 +80,7 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o const enableTParamFieldLookup = false // see go.dev/issue/51576 if enableTParamFieldLookup && obj == nil && isTypeParam(T) { if t := coreType(T); t != nil { - obj, index, indirect = lookupFieldOrMethodImpl(t, addressable, pkg, name, false) + obj, index, indirect = lookupFieldOrMethodImpl(t, addressable, pkg, name, foldCase) if _, ok := obj.(*Var); !ok { obj, index, indirect = nil, nil, false // accept fields (variables) only } @@ -84,8 +89,8 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o return } -// lookupFieldOrMethodImpl is the implementation of LookupFieldOrMethod. -// Notably, in contrast to LookupFieldOrMethod, it won't find struct fields +// lookupFieldOrMethodImpl is the implementation of lookupFieldOrMethod. +// Notably, in contrast to lookupFieldOrMethod, it won't find struct fields // in base types of defined (*Named) pointer types T. For instance, given // the declaration: // @@ -94,12 +99,9 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o // lookupFieldOrMethodImpl won't find the field f in the defined (*Named) type T // (methods on T are not permitted in the first place). // -// Thus, lookupFieldOrMethodImpl should only be called by LookupFieldOrMethod +// Thus, lookupFieldOrMethodImpl should only be called by lookupFieldOrMethod // and missingMethod (the latter doesn't care about struct fields). // -// If foldCase is true, method names are considered equal if they are equal -// with case folding, irrespective of which package they are in. -// // The resulting object may not be fully type-checked. func lookupFieldOrMethodImpl(T Type, addressable bool, pkg *Package, name string, foldCase bool) (obj Object, index []int, indirect bool) { // WARNING: The code in this function is extremely subtle - do not modify casually! @@ -169,7 +171,7 @@ func lookupFieldOrMethodImpl(T Type, addressable bool, pkg *Package, name string case *Struct: // look for a matching field and collect embedded types for i, f := range t.fields { - if f.sameId(pkg, name) { + if f.sameId(pkg, name, foldCase) { assert(f.typ != nil) index = concat(e.index, i) if obj != nil || e.multiples { @@ -473,7 +475,7 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y case field: *cause = check.sprintf("(%s.%s is a field, not a method)", V, m.Name()) default: - unreachable() + panic("unreachable") } } @@ -579,10 +581,11 @@ func concat(list []int, i int) []int { } // fieldIndex returns the index for the field with matching package and name, or a value < 0. -func fieldIndex(fields []*Var, pkg *Package, name string) int { +// See Object.sameId for the meaning of foldCase. +func fieldIndex(fields []*Var, pkg *Package, name string, foldCase bool) int { if name != "_" { for i, f := range fields { - if f.sameId(pkg, name) { + if f.sameId(pkg, name, foldCase) { return i } } @@ -590,13 +593,12 @@ func fieldIndex(fields []*Var, pkg *Package, name string) int { return -1 } -// lookupMethod returns the index of and method with matching package and name, or (-1, nil). -// If foldCase is true, method names are considered equal if they are equal with case folding -// and their packages are ignored (e.g., pkg1.m, pkg1.M, pkg2.m, and pkg2.M are all equal). -func lookupMethod(methods []*Func, pkg *Package, name string, foldCase bool) (int, *Func) { +// methodIndex returns the index of and method with matching package and name, or (-1, nil). +// See Object.sameId for the meaning of foldCase. +func methodIndex(methods []*Func, pkg *Package, name string, foldCase bool) (int, *Func) { if name != "_" { for i, m := range methods { - if m.sameId(pkg, name) || foldCase && strings.EqualFold(m.name, name) { + if m.sameId(pkg, name, foldCase) { return i, m } } diff --git a/contrib/go/_std_1.22/src/go/types/map.go b/contrib/go/_std_1.23/src/go/types/map.go similarity index 93% rename from contrib/go/_std_1.22/src/go/types/map.go rename to contrib/go/_std_1.23/src/go/types/map.go index febb0d3a0b76..3ed3188a3bc7 100644 --- a/contrib/go/_std_1.22/src/go/types/map.go +++ b/contrib/go/_std_1.23/src/go/types/map.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/map.go // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/contrib/go/_std_1.22/src/go/types/methodset.go b/contrib/go/_std_1.23/src/go/types/methodset.go similarity index 100% rename from contrib/go/_std_1.22/src/go/types/methodset.go rename to contrib/go/_std_1.23/src/go/types/methodset.go diff --git a/contrib/go/_std_1.22/src/go/types/mono.go b/contrib/go/_std_1.23/src/go/types/mono.go similarity index 94% rename from contrib/go/_std_1.22/src/go/types/mono.go rename to contrib/go/_std_1.23/src/go/types/mono.go index 74113392149f..65f7aa65ce91 100644 --- a/contrib/go/_std_1.22/src/go/types/mono.go +++ b/contrib/go/_std_1.23/src/go/types/mono.go @@ -1,3 +1,6 @@ +// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/mono.go + // Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -138,8 +141,9 @@ func (check *Checker) reportInstanceLoop(v int) { // TODO(mdempsky): Pivot stack so we report the cycle from the top? + err := check.newError(InvalidInstanceCycle) obj0 := check.mono.vertices[v].obj - check.error(obj0, InvalidInstanceCycle, "instantiation cycle:") + err.addf(obj0, "instantiation cycle:") qf := RelativeTo(check.pkg) for _, v := range stack { @@ -150,11 +154,12 @@ func (check *Checker) reportInstanceLoop(v int) { default: panic("unexpected type") case *Named: - check.errorf(atPos(edge.pos), InvalidInstanceCycle, "\t%s implicitly parameterized by %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented + err.addf(atPos(edge.pos), "%s implicitly parameterized by %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented case *TypeParam: - check.errorf(atPos(edge.pos), InvalidInstanceCycle, "\t%s instantiated as %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented + err.addf(atPos(edge.pos), "%s instantiated as %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented } } + err.report() } // recordCanon records that tpar is the canonical type parameter @@ -172,7 +177,7 @@ func (w *monoGraph) recordInstance(pkg *Package, pos token.Pos, tparams []*TypeP for i, tpar := range tparams { pos := pos if i < len(xlist) { - pos = xlist[i].Pos() + pos = startPos(xlist[i]) } w.assign(pkg, pos, tpar, targs[i]) } diff --git a/contrib/go/_std_1.22/src/go/types/named.go b/contrib/go/_std_1.23/src/go/types/named.go similarity index 91% rename from contrib/go/_std_1.22/src/go/types/named.go rename to contrib/go/_std_1.23/src/go/types/named.go index 21c0de255ded..d55b023812d1 100644 --- a/contrib/go/_std_1.22/src/go/types/named.go +++ b/contrib/go/_std_1.23/src/go/types/named.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/named.go // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -8,6 +9,7 @@ package types import ( "go/token" + "strings" "sync" "sync/atomic" ) @@ -283,7 +285,7 @@ func (t *Named) cleanup() { if t.TypeArgs().Len() == 0 { panic("nil underlying") } - case *Named: + case *Named, *Alias: t.under() // t.under may add entries to check.cleaners } t.check = nil @@ -336,6 +338,12 @@ func (t *Named) NumMethods() int { // For an ordinary or instantiated type t, the receiver base type of this // method is the named type t. For an uninstantiated generic type t, each // method receiver is instantiated with its receiver type parameters. +// +// Methods are numbered deterministically: given the same list of source files +// presented to the type checker, or the same sequence of NewMethod and AddMethod +// calls, the mapping from method index to corresponding method remains the same. +// But the specific ordering is not specified and must not be relied on as it may +// change in the future. func (t *Named) Method(i int) *Func { t.resolve() @@ -446,18 +454,51 @@ func (t *Named) SetUnderlying(underlying Type) { } // AddMethod adds method m unless it is already in the method list. -// t must not have type arguments. +// The method must be in the same package as t, and t must not have +// type arguments. func (t *Named) AddMethod(m *Func) { + assert(samePkg(t.obj.pkg, m.pkg)) assert(t.inst == nil) t.resolve() - if i, _ := lookupMethod(t.methods, m.pkg, m.name, false); i < 0 { + if t.methodIndex(m.name, false) < 0 { t.methods = append(t.methods, m) } } -// TODO(gri) Investigate if Unalias can be moved to where underlying is set. -func (t *Named) Underlying() Type { return Unalias(t.resolve().underlying) } -func (t *Named) String() string { return TypeString(t, nil) } +// methodIndex returns the index of the method with the given name. +// If foldCase is set, capitalization in the name is ignored. +// The result is negative if no such method exists. +func (t *Named) methodIndex(name string, foldCase bool) int { + if name == "_" { + return -1 + } + if foldCase { + for i, m := range t.methods { + if strings.EqualFold(m.name, name) { + return i + } + } + } else { + for i, m := range t.methods { + if m.name == name { + return i + } + } + } + return -1 +} + +// Underlying returns the [underlying type] of the named type t, resolving all +// forwarding declarations. Underlying types are never Named, TypeParam, or +// Alias types. +// +// [underlying type]: https://go.dev/ref/spec#Underlying_types. +func (t *Named) Underlying() Type { + // TODO(gri) Investigate if Unalias can be moved to where underlying is set. + return Unalias(t.resolve().underlying) +} + +func (t *Named) String() string { return TypeString(t, nil) } // ---------------------------------------------------------------------------- // Implementation @@ -522,7 +563,7 @@ loop: n = n1 if i, ok := seen[n]; ok { // cycle - check.cycleError(path[i:]) + check.cycleError(path[i:], firstInSrc(path[i:])) u = Typ[Invalid] break } @@ -555,15 +596,16 @@ loop: func (n *Named) lookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) { n.resolve() - // If n is an instance, we may not have yet instantiated all of its methods. - // Look up the method index in orig, and only instantiate method at the - // matching index (if any). - i, _ := lookupMethod(n.Origin().methods, pkg, name, foldCase) - if i < 0 { - return -1, nil - } - // For instances, m.Method(i) will be different from the orig method. - return i, n.Method(i) + if samePkg(n.obj.pkg, pkg) || isExported(name) || foldCase { + // If n is an instance, we may not have yet instantiated all of its methods. + // Look up the method index in orig, and only instantiate method at the + // matching index (if any). + if i := n.Origin().methodIndex(name, foldCase); i >= 0 { + // For instances, m.Method(i) will be different from the orig method. + return i, n.Method(i) + } + } + return -1, nil } // context returns the type-checker context. diff --git a/contrib/go/_std_1.22/src/go/types/object.go b/contrib/go/_std_1.23/src/go/types/object.go similarity index 92% rename from contrib/go/_std_1.22/src/go/types/object.go rename to contrib/go/_std_1.23/src/go/types/object.go index 51b3886716f6..cc014188324a 100644 --- a/contrib/go/_std_1.22/src/go/types/object.go +++ b/contrib/go/_std_1.23/src/go/types/object.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/object.go // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -11,6 +12,7 @@ import ( "fmt" "go/constant" "go/token" + "strings" "unicode" "unicode/utf8" ) @@ -52,7 +54,9 @@ type Object interface { setParent(*Scope) // sameId reports whether obj.Id() and Id(pkg, name) are the same. - sameId(pkg *Package, name string) bool + // If foldCase is true, names are considered equal if they are equal with case folding + // and their packages are ignored (e.g., pkg1.m, pkg1.M, pkg2.m, and pkg2.M are all equal). + sameId(pkg *Package, name string, foldCase bool) bool // scopePos returns the start position of the scope of this Object scopePos() token.Pos @@ -165,26 +169,24 @@ func (obj *object) setOrder(order uint32) { assert(order > 0); obj.order_ = func (obj *object) setColor(color color) { assert(color != white); obj.color_ = color } func (obj *object) setScopePos(pos token.Pos) { obj.scopePos_ = pos } -func (obj *object) sameId(pkg *Package, name string) bool { +func (obj *object) sameId(pkg *Package, name string, foldCase bool) bool { + // If we don't care about capitalization, we also ignore packages. + if foldCase && strings.EqualFold(obj.name, name) { + return true + } // spec: // "Two identifiers are different if they are spelled differently, // or if they appear in different packages and are not exported. // Otherwise, they are the same." - if name != obj.name { + if obj.name != name { return false } // obj.Name == name if obj.Exported() { return true } - // not exported, so packages must be the same (pkg == nil for - // fields in Universe scope; this can only happen for types - // introduced via Eval) - if pkg == nil || obj.pkg == nil { - return pkg == obj.pkg - } - // pkg != nil && obj.pkg != nil - return pkg.path == obj.pkg.path + // not exported, so packages must be the same + return samePkg(obj.pkg, pkg) } // less reports whether object a is ordered before object b. @@ -375,14 +377,34 @@ type Func struct { // NewFunc returns a new function with the given signature, representing // the function's type. func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func { - // don't store a (typed) nil signature var typ Type if sig != nil { typ = sig + } else { + // Don't store a (typed) nil *Signature. + // We can't simply replace it with new(Signature) either, + // as this would violate object.{Type,color} invariants. + // TODO(adonovan): propose to disallow NewFunc with nil *Signature. } return &Func{object{nil, pos, pkg, name, typ, 0, colorFor(typ), nopos}, false, nil} } +// Signature returns the signature (type) of the function or method. +func (obj *Func) Signature() *Signature { + if obj.typ != nil { + return obj.typ.(*Signature) // normal case + } + // No signature: Signature was called either: + // - within go/types, before a FuncDecl's initially + // nil Func.Type was lazily populated, indicating + // a types bug; or + // - by a client after NewFunc(..., nil), + // which is arguably a client bug, but we need a + // proposal to tighten NewFunc's precondition. + // For now, return a trivial signature. + return new(Signature) +} + // FullName returns the package- or receiver-type-qualified name of // function or method obj. func (obj *Func) FullName() string { @@ -543,10 +565,14 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) { } if tname.IsAlias() { buf.WriteString(" =") + if alias, ok := typ.(*Alias); ok { // materialized? (gotypesalias=1) + typ = alias.fromRHS + } } else if t, _ := typ.(*TypeParam); t != nil { typ = t.bound } else { // TODO(gri) should this be fromRHS for *Named? + // (See discussion in #66559.) typ = under(typ) } } @@ -554,7 +580,7 @@ func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) { // Special handling for any: because WriteType will format 'any' as 'any', // resulting in the object string `type any = any` rather than `type any = // interface{}`. To avoid this, swap in a different empty interface. - if obj == universeAny { + if obj.Name() == "any" && obj.Parent() == Universe { assert(Identical(typ, &emptyInterface)) typ = &emptyInterface } diff --git a/contrib/go/_std_1.22/src/go/types/objset.go b/contrib/go/_std_1.23/src/go/types/objset.go similarity index 94% rename from contrib/go/_std_1.22/src/go/types/objset.go rename to contrib/go/_std_1.23/src/go/types/objset.go index e6ea37566e31..a2ecb717e495 100644 --- a/contrib/go/_std_1.22/src/go/types/objset.go +++ b/contrib/go/_std_1.23/src/go/types/objset.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/objset.go // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/contrib/go/_std_1.22/src/go/types/operand.go b/contrib/go/_std_1.23/src/go/types/operand.go similarity index 89% rename from contrib/go/_std_1.22/src/go/types/operand.go rename to contrib/go/_std_1.23/src/go/types/operand.go index d5c16346bf78..060a408c2641 100644 --- a/contrib/go/_std_1.22/src/go/types/operand.go +++ b/contrib/go/_std_1.23/src/go/types/operand.go @@ -1,3 +1,6 @@ +// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/operand.go + // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -8,6 +11,7 @@ package types import ( "bytes" + "fmt" "go/ast" "go/constant" "go/token" @@ -26,6 +30,7 @@ const ( variable // operand is an addressable variable mapindex // operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment) value // operand is a computed value + nilvalue // operand is the nil value - only used by types2 commaok // like value, but operand may be used in a comma,ok expression commaerr // like commaok, but second value is error, not boolean cgofunc // operand is a cgo function @@ -40,6 +45,7 @@ var operandModeString = [...]string{ variable: "variable", mapindex: "map index expression", value: "value", + nilvalue: "nil", // only used by types2 commaok: "comma, ok expression", commaerr: "comma, error expression", cgofunc: "cgo function", @@ -93,6 +99,9 @@ func (x *operand) Pos() token.Pos { // value ( ) // value ( of type ) // +// nilvalue untyped nil +// nilvalue nil ( of type ) +// // commaok ( ) // commaok ( of type ) // @@ -103,8 +112,21 @@ func (x *operand) Pos() token.Pos { // cgofunc ( of type ) func operandString(x *operand, qf Qualifier) string { // special-case nil - if x.mode == value && x.typ == Typ[UntypedNil] { - return "nil" + if isTypes2 { + if x.mode == nilvalue { + switch x.typ { + case nil, Typ[Invalid]: + return "nil (with invalid type)" + case Typ[UntypedNil]: + return "nil" + default: + return fmt.Sprintf("nil (of type %s)", TypeString(x.typ, qf)) + } + } + } else { // go/types + if x.mode == value && x.typ == Typ[UntypedNil] { + return "nil" + } } var buf bytes.Buffer @@ -168,7 +190,7 @@ func operandString(x *operand, qf Qualifier) string { } buf.WriteString(intro) WriteType(&buf, x.typ, qf) - if tpar, _ := x.typ.(*TypeParam); tpar != nil { + if tpar, _ := Unalias(x.typ).(*TypeParam); tpar != nil { buf.WriteString(" constrained by ") WriteType(&buf, tpar.bound, qf) // do not compute interface type sets here // If we have the type set and it's empty, say so for better error messages. @@ -194,9 +216,9 @@ func (x *operand) String() string { } // setConst sets x to the untyped constant for literal lit. -func (x *operand) setConst(tok token.Token, lit string) { +func (x *operand) setConst(k token.Token, lit string) { var kind BasicKind - switch tok { + switch k { case token.INT: kind = UntypedInt case token.FLOAT: @@ -208,10 +230,10 @@ func (x *operand) setConst(tok token.Token, lit string) { case token.STRING: kind = UntypedString default: - unreachable() + panic("unreachable") } - val := constant.MakeFromLiteral(lit, tok, 0) + val := makeFromLiteral(lit, k) if val.Kind() == constant.Unknown { x.mode = invalid x.typ = Typ[Invalid] @@ -223,7 +245,13 @@ func (x *operand) setConst(tok token.Token, lit string) { } // isNil reports whether x is the (untyped) nil value. -func (x *operand) isNil() bool { return x.mode == value && x.typ == Typ[UntypedNil] } +func (x *operand) isNil() bool { + if isTypes2 { + return x.mode == nilvalue + } else { // go/types + return x.mode == value && x.typ == Typ[UntypedNil] + } +} // assignableTo reports whether x is assignable to a variable of type T. If the // result is false and a non-nil cause is provided, it may be set to a more @@ -236,7 +264,9 @@ func (x *operand) assignableTo(check *Checker, T Type, cause *string) (bool, Cod return true, 0 // avoid spurious errors } - V := x.typ + origT := T + V := Unalias(x.typ) + T = Unalias(T) // x's type is identical to T if Identical(V, T) { @@ -362,7 +392,7 @@ func (x *operand) assignableTo(check *Checker, T Type, cause *string) (bool, Cod x.typ = V.typ ok, code = x.assignableTo(check, T, cause) if !ok { - errorf("cannot assign %s (in %s) to %s", V.typ, Vp, T) + errorf("cannot assign %s (in %s) to %s", V.typ, Vp, origT) return false } return true diff --git a/contrib/go/_std_1.22/src/go/types/package.go b/contrib/go/_std_1.23/src/go/types/package.go similarity index 98% rename from contrib/go/_std_1.22/src/go/types/package.go rename to contrib/go/_std_1.23/src/go/types/package.go index 0f52d5f4893d..ac0c2e22701b 100644 --- a/contrib/go/_std_1.22/src/go/types/package.go +++ b/contrib/go/_std_1.23/src/go/types/package.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/package.go // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/contrib/go/_std_1.22/src/go/types/pointer.go b/contrib/go/_std_1.23/src/go/types/pointer.go similarity index 92% rename from contrib/go/_std_1.22/src/go/types/pointer.go rename to contrib/go/_std_1.23/src/go/types/pointer.go index 5b45ab775531..633f46b3fb4d 100644 --- a/contrib/go/_std_1.22/src/go/types/pointer.go +++ b/contrib/go/_std_1.23/src/go/types/pointer.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/pointer.go // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/contrib/go/_std_1.22/src/go/types/predicates.go b/contrib/go/_std_1.23/src/go/types/predicates.go similarity index 92% rename from contrib/go/_std_1.22/src/go/types/predicates.go rename to contrib/go/_std_1.23/src/go/types/predicates.go index cac2b3c75fa0..ba7901b3c31b 100644 --- a/contrib/go/_std_1.22/src/go/types/predicates.go +++ b/contrib/go/_std_1.23/src/go/types/predicates.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/predicates.go // Copyright 2012 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -81,22 +82,30 @@ func isTypeLit(t Type) bool { } // isTyped reports whether t is typed; i.e., not an untyped -// constant or boolean. isTyped may be called with types that -// are not fully set up. +// constant or boolean. +// Safe to call from types that are not fully set up. func isTyped(t Type) bool { - // Alias or Named types cannot denote untyped types, - // thus we don't need to call Unalias or under - // (which would be unsafe to do for types that are - // not fully set up). + // Alias and named types cannot denote untyped types + // so there's no need to call Unalias or under, below. b, _ := t.(*Basic) return b == nil || b.info&IsUntyped == 0 } // isUntyped(t) is the same as !isTyped(t). +// Safe to call from types that are not fully set up. func isUntyped(t Type) bool { return !isTyped(t) } +// isUntypedNumeric reports whether t is an untyped numeric type. +// Safe to call from types that are not fully set up. +func isUntypedNumeric(t Type) bool { + // Alias and named types cannot denote untyped types + // so there's no need to call Unalias or under, below. + b, _ := t.(*Basic) + return b != nil && b.info&IsUntyped != 0 && b.info&IsNumeric != 0 +} + // IsInterface reports whether t is an interface type. func IsInterface(t Type) bool { _, ok := under(t).(*Interface) @@ -131,6 +140,9 @@ func hasEmptyTypeset(t Type) bool { // TODO(gri) should we include signatures or assert that they are not present? func isGeneric(t Type) bool { // A parameterized type is only generic if it doesn't have an instantiation already. + if alias, _ := t.(*Alias); alias != nil && alias.tparams != nil && alias.targs == nil { + return true + } named := asNamed(t) return named != nil && named.obj != nil && named.inst == nil && named.TypeParams().Len() > 0 } @@ -207,6 +219,16 @@ func hasNil(t Type) bool { return false } +// samePkg reports whether packages a and b are the same. +func samePkg(a, b *Package) bool { + // package is nil for objects in universe scope + if a == nil || b == nil { + return a == b + } + // a != nil && b != nil + return a.path == b.path +} + // An ifacePair is a node in a stack of interface type pairs compared for identity. type ifacePair struct { x, y *Interface @@ -271,7 +293,7 @@ func (c *comparer) identical(x, y Type, p *ifacePair) bool { g := y.fields[i] if f.embedded != g.embedded || !c.ignoreTags && x.Tag(i) != y.Tag(i) || - !f.sameId(g.pkg, g.name) || + !f.sameId(g.pkg, g.name, false) || !c.identical(f.typ, g.typ, p) { return false } @@ -469,7 +491,7 @@ func (c *comparer) identical(x, y Type, p *ifacePair) bool { // avoid a crash in case of nil type default: - unreachable() + panic("unreachable") } return false @@ -502,7 +524,9 @@ func identicalInstance(xorig Type, xargs []Type, yorig Type, yargs []Type) bool // it returns the incoming type for all other types. The default type // for untyped nil is untyped nil. func Default(t Type) Type { - if t, ok := Unalias(t).(*Basic); ok { + // Alias and named types cannot denote untyped types + // so there's no need to call Unalias or under, below. + if t, _ := t.(*Basic); t != nil { switch t.kind { case UntypedBool: return Typ[Bool] @@ -531,7 +555,7 @@ func maxType(x, y Type) Type { if x == y { return x } - if isUntyped(x) && isUntyped(y) && isNumeric(x) && isNumeric(y) { + if isUntypedNumeric(x) && isUntypedNumeric(y) { // untyped types are basic types if x.(*Basic).kind > y.(*Basic).kind { return x diff --git a/contrib/go/_std_1.22/src/go/types/resolver.go b/contrib/go/_std_1.23/src/go/types/resolver.go similarity index 94% rename from contrib/go/_std_1.22/src/go/types/resolver.go rename to contrib/go/_std_1.23/src/go/types/resolver.go index f828344749b0..e6e882e35f03 100644 --- a/contrib/go/_std_1.22/src/go/types/resolver.go +++ b/contrib/go/_std_1.23/src/go/types/resolver.go @@ -146,6 +146,9 @@ func (check *Checker) importPackage(at positioner, path, dir string) *Package { // no package yet => import it if path == "C" && (check.conf.FakeImportC || check.conf.go115UsesCgo) { + if check.conf.FakeImportC && check.conf.go115UsesCgo { + check.error(at, BadImportPath, "cannot use FakeImportC and go115UsesCgo together") + } imp = NewPackage("C", "C") imp.fake = true // package scope is not populated imp.cgo = check.conf.go115UsesCgo @@ -327,8 +330,10 @@ func (check *Checker) collectObjects() { // the object may be imported into more than one file scope // concurrently. See go.dev/issue/32154.) if alt := fileScope.Lookup(name); alt != nil { - check.errorf(d.spec.Name, DuplicateDecl, "%s redeclared in this block", alt.Name()) - check.reportAltDecl(alt) + err := check.newError(DuplicateDecl) + err.addf(d.spec.Name, "%s redeclared in this block", alt.Name()) + err.addAltDecl(alt) + err.report() } else { fileScope.insert(name, obj) check.dotImportMap[dotImportKey{fileScope, name}] = pkgName @@ -386,13 +391,12 @@ func (check *Checker) collectObjects() { check.declarePkgObj(name, obj, di) } case typeDecl: - _ = d.spec.TypeParams.NumFields() != 0 && check.verifyVersionf(d.spec.TypeParams.List[0], go1_18, "type parameter") obj := NewTypeName(d.spec.Name.Pos(), pkg, d.spec.Name.Name, nil) check.declarePkgObj(d.spec.Name, obj, &declInfo{file: fileScope, tdecl: d.spec}) case funcDecl: name := d.decl.Name.Name - obj := NewFunc(d.decl.Name.Pos(), pkg, name, nil) - hasTParamError := false // avoid duplicate type parameter errors + obj := NewFunc(d.decl.Name.Pos(), pkg, name, nil) // signature set later + hasTParamError := false // avoid duplicate type parameter errors if d.decl.Recv.NumFields() == 0 { // regular function if d.decl.Recv != nil { @@ -459,14 +463,16 @@ func (check *Checker) collectObjects() { for name, obj := range scope.elems { if alt := pkg.scope.Lookup(name); alt != nil { obj = resolve(name, obj) + err := check.newError(DuplicateDecl) if pkg, ok := obj.(*PkgName); ok { - check.errorf(alt, DuplicateDecl, "%s already declared through import of %s", alt.Name(), pkg.Imported()) - check.reportAltDecl(pkg) + err.addf(alt, "%s already declared through import of %s", alt.Name(), pkg.Imported()) + err.addAltDecl(pkg) } else { - check.errorf(alt, DuplicateDecl, "%s already declared through dot-import of %s", alt.Name(), obj.Pkg()) - // TODO(gri) dot-imported objects don't have a position; reportAltDecl won't print anything - check.reportAltDecl(obj) + err.addf(alt, "%s already declared through dot-import of %s", alt.Name(), obj.Pkg()) + // TODO(gri) dot-imported objects don't have a position; addAltDecl won't print anything + err.addAltDecl(obj) } + err.report() } } } @@ -561,7 +567,7 @@ func (check *Checker) resolveBaseTypeName(seenPtr bool, typ ast.Expr, fileScopes for { // Note: this differs from types2, but is necessary. The syntax parser // strips unnecessary parens. - typ = unparen(typ) + typ = ast.Unparen(typ) // check if we have a pointer type if pexpr, _ := typ.(*ast.StarExpr); pexpr != nil { @@ -570,7 +576,7 @@ func (check *Checker) resolveBaseTypeName(seenPtr bool, typ ast.Expr, fileScopes return false, nil } ptr = true - typ = unparen(pexpr.X) // continue with pointer base type + typ = ast.Unparen(pexpr.X) // continue with pointer base type } // typ must be a name, or a C.name cgo selector. @@ -659,8 +665,23 @@ func (check *Checker) packageObjects() { } } - if check.enableAlias { + if false && check.conf._EnableAlias { // With Alias nodes we can process declarations in any order. + // + // TODO(adonovan): unfortunately, Alias nodes + // (GODEBUG=gotypesalias=1) don't entirely resolve + // problems with cycles. For example, in + // GOROOT/test/typeparam/issue50259.go, + // + // type T[_ any] struct{} + // type A T[B] + // type B = T[A] + // + // TypeName A has Type Named during checking, but by + // the time the unified export data is written out, + // its Type is Invalid. + // + // Investigate and reenable this branch. for _, obj := range objList { check.objDecl(obj, nil) } diff --git a/contrib/go/_std_1.22/src/go/types/return.go b/contrib/go/_std_1.23/src/go/types/return.go similarity index 97% rename from contrib/go/_std_1.22/src/go/types/return.go rename to contrib/go/_std_1.23/src/go/types/return.go index ee8c41a431d8..91bd95b6e0b0 100644 --- a/contrib/go/_std_1.22/src/go/types/return.go +++ b/contrib/go/_std_1.23/src/go/types/return.go @@ -17,7 +17,7 @@ import ( func (check *Checker) isTerminating(s ast.Stmt, label string) bool { switch s := s.(type) { default: - unreachable() + panic("unreachable") case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.SendStmt, *ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt, *ast.DeferStmt, @@ -29,7 +29,7 @@ func (check *Checker) isTerminating(s ast.Stmt, label string) bool { case *ast.ExprStmt: // calling the predeclared (possibly parenthesized) panic() function is terminating - if call, ok := unparen(s.X).(*ast.CallExpr); ok && check.isPanic[call] { + if call, ok := ast.Unparen(s.X).(*ast.CallExpr); ok && check.isPanic[call] { return true } @@ -110,7 +110,7 @@ func (check *Checker) isTerminatingSwitch(body *ast.BlockStmt, label string) boo func hasBreak(s ast.Stmt, label string, implicit bool) bool { switch s := s.(type) { default: - unreachable() + panic("unreachable") case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.ExprStmt, *ast.SendStmt, *ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt, diff --git a/contrib/go/_std_1.22/src/go/types/scope.go b/contrib/go/_std_1.23/src/go/types/scope.go similarity index 80% rename from contrib/go/_std_1.22/src/go/types/scope.go rename to contrib/go/_std_1.23/src/go/types/scope.go index bf646f688210..176928eda92a 100644 --- a/contrib/go/_std_1.22/src/go/types/scope.go +++ b/contrib/go/_std_1.23/src/go/types/scope.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/scope.go // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -70,7 +71,19 @@ func (s *Scope) Child(i int) *Scope { return s.children[i] } // Lookup returns the object in scope s with the given name if such an // object exists; otherwise the result is nil. func (s *Scope) Lookup(name string) Object { - return resolve(name, s.elems[name]) + obj := resolve(name, s.elems[name]) + // Hijack Lookup for "any": with gotypesalias=1, we want the Universe to + // return an Alias for "any", and with gotypesalias=0 we want to return + // the legacy representation of aliases. + // + // This is rather tricky, but works out after auditing of the usage of + // s.elems. The only external API to access scope elements is Lookup. + // + // TODO: remove this once gotypesalias=0 is no longer supported. + if obj == universeAnyAlias && !aliasAny() { + return universeAnyNoAlias + } + return obj } // LookupParent follows the parent chain of scopes starting with s until @@ -275,20 +288,20 @@ func resolve(name string, obj Object) Object { // stub implementations so *lazyObject implements Object and we can // store them directly into Scope.elems. -func (*lazyObject) Parent() *Scope { panic("unreachable") } -func (*lazyObject) Pos() token.Pos { panic("unreachable") } -func (*lazyObject) Pkg() *Package { panic("unreachable") } -func (*lazyObject) Name() string { panic("unreachable") } -func (*lazyObject) Type() Type { panic("unreachable") } -func (*lazyObject) Exported() bool { panic("unreachable") } -func (*lazyObject) Id() string { panic("unreachable") } -func (*lazyObject) String() string { panic("unreachable") } -func (*lazyObject) order() uint32 { panic("unreachable") } -func (*lazyObject) color() color { panic("unreachable") } -func (*lazyObject) setType(Type) { panic("unreachable") } -func (*lazyObject) setOrder(uint32) { panic("unreachable") } -func (*lazyObject) setColor(color color) { panic("unreachable") } -func (*lazyObject) setParent(*Scope) { panic("unreachable") } -func (*lazyObject) sameId(pkg *Package, name string) bool { panic("unreachable") } -func (*lazyObject) scopePos() token.Pos { panic("unreachable") } -func (*lazyObject) setScopePos(pos token.Pos) { panic("unreachable") } +func (*lazyObject) Parent() *Scope { panic("unreachable") } +func (*lazyObject) Pos() token.Pos { panic("unreachable") } +func (*lazyObject) Pkg() *Package { panic("unreachable") } +func (*lazyObject) Name() string { panic("unreachable") } +func (*lazyObject) Type() Type { panic("unreachable") } +func (*lazyObject) Exported() bool { panic("unreachable") } +func (*lazyObject) Id() string { panic("unreachable") } +func (*lazyObject) String() string { panic("unreachable") } +func (*lazyObject) order() uint32 { panic("unreachable") } +func (*lazyObject) color() color { panic("unreachable") } +func (*lazyObject) setType(Type) { panic("unreachable") } +func (*lazyObject) setOrder(uint32) { panic("unreachable") } +func (*lazyObject) setColor(color color) { panic("unreachable") } +func (*lazyObject) setParent(*Scope) { panic("unreachable") } +func (*lazyObject) sameId(*Package, string, bool) bool { panic("unreachable") } +func (*lazyObject) scopePos() token.Pos { panic("unreachable") } +func (*lazyObject) setScopePos(token.Pos) { panic("unreachable") } diff --git a/contrib/go/_std_1.22/src/go/types/selection.go b/contrib/go/_std_1.23/src/go/types/selection.go similarity index 98% rename from contrib/go/_std_1.22/src/go/types/selection.go rename to contrib/go/_std_1.23/src/go/types/selection.go index 50d340c738af..6f8da7afe797 100644 --- a/contrib/go/_std_1.22/src/go/types/selection.go +++ b/contrib/go/_std_1.23/src/go/types/selection.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/selection.go // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -165,7 +166,7 @@ func SelectionString(s *Selection, qf Qualifier) string { case MethodExpr: k = "method expr " default: - unreachable() + panic("unreachable") } var buf bytes.Buffer buf.WriteString(k) diff --git a/contrib/go/_std_1.22/src/go/types/signature.go b/contrib/go/_std_1.23/src/go/types/signature.go similarity index 98% rename from contrib/go/_std_1.22/src/go/types/signature.go rename to contrib/go/_std_1.23/src/go/types/signature.go index cad42cb94243..770edc2b21b8 100644 --- a/contrib/go/_std_1.22/src/go/types/signature.go +++ b/contrib/go/_std_1.23/src/go/types/signature.go @@ -193,8 +193,10 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast params, variadic := check.collectParams(scope, ftyp.Params, true, scopePos) results, _ := check.collectParams(scope, ftyp.Results, false, scopePos) scope.squash(func(obj, alt Object) { - check.errorf(obj, DuplicateDecl, "%s redeclared in this block", obj.Name()) - check.reportAltDecl(alt) + err := check.newError(DuplicateDecl) + err.addf(obj, "%s redeclared in this block", obj.Name()) + err.addAltDecl(alt) + err.report() }) if recvPar != nil { @@ -251,7 +253,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast case *TypeParam: // The underlying type of a receiver base type cannot be a // type parameter: "type T[P any] P" is not a valid declaration. - unreachable() + panic("unreachable") } if cause != "" { check.errorf(recv, InvalidRecv, "invalid receiver type %s (%s)", rtyp, cause) diff --git a/contrib/go/_std_1.22/src/go/types/sizes.go b/contrib/go/_std_1.23/src/go/types/sizes.go similarity index 98% rename from contrib/go/_std_1.22/src/go/types/sizes.go rename to contrib/go/_std_1.23/src/go/types/sizes.go index 12a21401e243..51ea224f0b29 100644 --- a/contrib/go/_std_1.22/src/go/types/sizes.go +++ b/contrib/go/_std_1.23/src/go/types/sizes.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/sizes.go // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -96,7 +97,7 @@ func (s *StdSizes) Alignof(T Type) (result int64) { return s.WordSize } case *TypeParam, *Union: - unreachable() + panic("unreachable") } a := s.Sizeof(T) // may be 0 or negative // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1." @@ -122,7 +123,7 @@ func _IsSyncAtomicAlign64(T Type) bool { return obj.Name() == "align64" && obj.Pkg() != nil && (obj.Pkg().Path() == "sync/atomic" || - obj.Pkg().Path() == "runtime/internal/atomic") + obj.Pkg().Path() == "internal/runtime/atomic") } func (s *StdSizes) Offsetsof(fields []*Var) []int64 { @@ -223,7 +224,7 @@ func (s *StdSizes) Sizeof(T Type) int64 { assert(!isTypeParam(T)) return s.WordSize * 2 case *TypeParam, *Union: - unreachable() + panic("unreachable") } return s.WordSize // catch-all } diff --git a/contrib/go/_std_1.22/src/go/types/slice.go b/contrib/go/_std_1.23/src/go/types/slice.go similarity index 92% rename from contrib/go/_std_1.22/src/go/types/slice.go rename to contrib/go/_std_1.23/src/go/types/slice.go index 934549c2d413..aad6450a6f6d 100644 --- a/contrib/go/_std_1.22/src/go/types/slice.go +++ b/contrib/go/_std_1.23/src/go/types/slice.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/slice.go // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/contrib/go/_std_1.22/src/go/types/stmt.go b/contrib/go/_std_1.23/src/go/types/stmt.go similarity index 91% rename from contrib/go/_std_1.22/src/go/types/stmt.go rename to contrib/go/_std_1.23/src/go/types/stmt.go index bb203f130c19..c9f7a4f929ad 100644 --- a/contrib/go/_std_1.22/src/go/types/stmt.go +++ b/contrib/go/_std_1.23/src/go/types/stmt.go @@ -65,7 +65,7 @@ func (check *Checker) usage(scope *Scope) { return cmpPos(unused[i].pos, unused[j].pos) < 0 }) for _, v := range unused { - check.softErrorf(v, UnusedVar, "%s declared and not used", v.name) + check.softErrorf(v, UnusedVar, "declared and not used: %s", v.name) } for _, scope := range scope.children { @@ -183,7 +183,7 @@ func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) { case statement: return default: - unreachable() + panic("unreachable") } check.errorf(&x, code, "%s %s %s", keyword, msg, &x) } @@ -257,8 +257,10 @@ L: // (quadratic algorithm, but these lists tend to be very short) for _, vt := range seen[val] { if Identical(v.typ, vt.typ) { - check.errorf(&v, DuplicateCase, "duplicate case %s in expression switch", &v) - check.error(atPos(vt.pos), DuplicateCase, "\tprevious case") // secondary error, \t indented + err := check.newError(DuplicateCase) + err.addf(&v, "duplicate case %s in expression switch", &v) + err.addf(atPos(vt.pos), "previous case") + err.report() continue L } } @@ -270,14 +272,18 @@ L: // isNil reports whether the expression e denotes the predeclared value nil. func (check *Checker) isNil(e ast.Expr) bool { // The only way to express the nil value is by literally writing nil (possibly in parentheses). - if name, _ := unparen(e).(*ast.Ident); name != nil { + if name, _ := ast.Unparen(e).(*ast.Ident); name != nil { _, ok := check.lookup(name.Name).(*Nil) return ok } return false } -// If the type switch expression is invalid, x is nil. +// caseTypes typechecks the type expressions of a type case, checks for duplicate types +// using the seen map, and verifies that each type is valid with respect to the type of +// the operand x in the type switch clause. If the type switch expression is invalid, x +// must be nil. The result is the type of the last type expression; it is nil if the +// expression denotes the predeclared nil. func (check *Checker) caseTypes(x *operand, types []ast.Expr, seen map[Type]ast.Expr) (T Type) { var dummy operand L: @@ -301,8 +307,10 @@ L: if T != nil { Ts = TypeString(T, check.qualifier) } - check.errorf(e, DuplicateCase, "duplicate case %s in type switch", Ts) - check.error(other, DuplicateCase, "\tprevious case") // secondary error, \t indented + err := check.newError(DuplicateCase) + err.addf(e, "duplicate case %s in type switch", Ts) + err.addf(other, "previous case") + err.report() continue L } } @@ -341,11 +349,10 @@ L: // if T != nil { // Ts = TypeString(T, check.qualifier) // } -// var err error_ -// err.code = DuplicateCase -// err.errorf(e, "duplicate case %s in type switch", Ts) -// err.errorf(other, "previous case") -// check.report(&err) +// err := check.newError(_DuplicateCase) +// err.addf(e, "duplicate case %s in type switch", Ts) +// err.addf(other, "previous case") +// err.report() // continue L // } // seen[hash] = e @@ -511,8 +518,10 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { // with the same name as a result parameter is in scope at the place of the return." for _, obj := range res.vars { if alt := check.lookup(obj.name); alt != nil && alt != obj { - check.errorf(s, OutOfScopeResult, "result parameter %s not in scope at return", obj.name) - check.errorf(alt, OutOfScopeResult, "\tinner declaration of %s", obj) + err := check.newError(OutOfScopeResult) + err.addf(s, "result parameter %s not in scope at return", obj.name) + err.addf(alt, "inner declaration of %s", obj) + err.report() // ok to continue } } @@ -682,20 +691,19 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { check.error(s, InvalidSyntaxTree, "incorrect form of type switch guard") return } - var x operand - check.expr(nil, &x, expr.X) - if x.mode == invalid { - return - } - // TODO(gri) we may want to permit type switches on type parameter values at some point + var sx *operand // switch expression against which cases are compared against; nil if invalid - if isTypeParam(x.typ) { - check.errorf(&x, InvalidTypeSwitch, "cannot use type switch on type parameter value %s", &x) - } else { - if _, ok := under(x.typ).(*Interface); ok { - sx = &x - } else { - check.errorf(&x, InvalidTypeSwitch, "%s is not an interface", &x) + { + var x operand + check.expr(nil, &x, expr.X) + if x.mode != invalid { + if isTypeParam(x.typ) { + check.errorf(&x, InvalidTypeSwitch, "cannot use type switch on type parameter value %s", &x) + } else if IsInterface(x.typ) { + sx = &x + } else { + check.errorf(&x, InvalidTypeSwitch, "%s is not an interface", &x) + } } } @@ -720,7 +728,10 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { // exactly one type, the variable has that type; otherwise, the variable // has the type of the expression in the TypeSwitchGuard." if len(clause.List) != 1 || T == nil { - T = x.typ + T = Typ[Invalid] + if sx != nil { + T = sx.typ + } } obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T) scopePos := clause.Pos() + token.Pos(len("default")) // for default clause (len(List) == 0) @@ -779,7 +790,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { // if present, rhs must be a receive operation if rhs != nil { - if x, _ := unparen(rhs).(*ast.UnaryExpr); x != nil && x.Op == token.ARROW { + if x, _ := ast.Unparen(rhs).(*ast.UnaryExpr); x != nil && x.Op == token.ARROW { valid = true } } @@ -837,7 +848,7 @@ func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) { type identType = ast.Ident identName := func(n *identType) string { return n.Name } sKey, sValue := s.Key, s.Value - var sExtra ast.Expr = nil + var sExtra ast.Expr = nil // (used only in types2 fork) isDef := s.Tok == token.DEFINE rangeVar := s.X noNewVarPos := inNode(s, s.TokPos) @@ -852,8 +863,8 @@ func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) { var key, val Type if x.mode != invalid { // Ranging over a type parameter is permitted if it has a core type. - k, v, cause, isFunc, ok := rangeKeyVal(x.typ, func(v goVersion) bool { - return check.allowVersion(check.pkg, x.expr, v) + k, v, cause, ok := rangeKeyVal(x.typ, func(v goVersion) bool { + return check.allowVersion(x.expr, v) }) switch { case !ok && cause != "": @@ -866,17 +877,6 @@ func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) { check.softErrorf(sValue, InvalidIterVar, "range over %s permits only one iteration variable", &x) case sExtra != nil: check.softErrorf(sExtra, InvalidIterVar, "range clause permits at most two iteration variables") - case isFunc && ((k == nil) != (sKey == nil) || (v == nil) != (sValue == nil)): - var count string - switch { - case k == nil: - count = "no iteration variables" - case v == nil: - count = "one iteration variable" - default: - count = "two iteration variables" - } - check.softErrorf(&x, InvalidIterVar, "range over %s must have %s", &x, count) } key, val = k, v } @@ -922,14 +922,15 @@ func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) { // initialize lhs iteration variable, if any typ := rhs[i] - if typ == nil { + if typ == nil || typ == Typ[Invalid] { + // typ == Typ[Invalid] can happen if allowVersion fails. obj.typ = Typ[Invalid] obj.used = true // don't complain about unused variable continue } if rangeOverInt { - assert(i == 0) // at most one iteration variable (rhs[1] == nil for rangeOverInt) + assert(i == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt) check.initVar(obj, &x, "range clause") } else { var y operand @@ -959,12 +960,12 @@ func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) { // assign to lhs iteration variable, if any typ := rhs[i] - if typ == nil { + if typ == nil || typ == Typ[Invalid] { continue } if rangeOverInt { - assert(i == 0) // at most one iteration variable (rhs[1] == nil for rangeOverInt) + assert(i == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt) check.assignVar(lhs, nil, &x, "range clause") // If the assignment succeeded, if x was untyped before, it now // has a type inferred via the assignment. It must be an integer. @@ -998,9 +999,9 @@ func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) { // If allowVersion != nil, it is used to check the required language version. // If the range clause is not permitted, rangeKeyVal returns ok = false. // When ok = false, rangeKeyVal may also return a reason in cause. -func rangeKeyVal(typ Type, allowVersion func(goVersion) bool) (key, val Type, cause string, isFunc, ok bool) { - bad := func(cause string) (Type, Type, string, bool, bool) { - return Typ[Invalid], Typ[Invalid], cause, false, false +func rangeKeyVal(typ Type, allowVersion func(goVersion) bool) (key, val Type, cause string, ok bool) { + bad := func(cause string) (Type, Type, string, bool) { + return Typ[Invalid], Typ[Invalid], cause, false } toSig := func(t Type) *Signature { sig, _ := coreType(t).(*Signature) @@ -1013,30 +1014,28 @@ func rangeKeyVal(typ Type, allowVersion func(goVersion) bool) (key, val Type, ca return bad("no core type") case *Basic: if isString(typ) { - return Typ[Int], universeRune, "", false, true // use 'rune' name + return Typ[Int], universeRune, "", true // use 'rune' name } if isInteger(typ) { - // untyped numeric constants may be representable as integer values if allowVersion != nil && !allowVersion(go1_22) { return bad("requires go1.22 or later") } - return orig, nil, "", false, true + return orig, nil, "", true } case *Array: - return Typ[Int], typ.elem, "", false, true + return Typ[Int], typ.elem, "", true case *Slice: - return Typ[Int], typ.elem, "", false, true + return Typ[Int], typ.elem, "", true case *Map: - return typ.key, typ.elem, "", false, true + return typ.key, typ.elem, "", true case *Chan: if typ.dir == SendOnly { return bad("receive from send-only channel") } - return typ.elem, nil, "", false, true + return typ.elem, nil, "", true case *Signature: - // TODO(gri) when this becomes enabled permanently, add version check - if !buildcfg.Experiment.RangeFunc { - break + if !buildcfg.Experiment.RangeFunc && allowVersion != nil && !allowVersion(go1_23) { + return bad("requires go1.23 or later") } assert(typ.Recv() == nil) switch { @@ -1061,7 +1060,7 @@ func rangeKeyVal(typ Type, allowVersion func(goVersion) bool) (key, val Type, ca if cb.Params().Len() >= 2 { val = cb.Params().At(1).Type() } - return key, val, "", true, true + return key, val, "", true } return } diff --git a/contrib/go/_std_1.22/src/go/types/struct.go b/contrib/go/_std_1.23/src/go/types/struct.go similarity index 94% rename from contrib/go/_std_1.22/src/go/types/struct.go rename to contrib/go/_std_1.23/src/go/types/struct.go index 935a5495307c..a6970832c7c0 100644 --- a/contrib/go/_std_1.22/src/go/types/struct.go +++ b/contrib/go/_std_1.23/src/go/types/struct.go @@ -82,7 +82,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) { // current field typ and tag var typ Type var tag string - add := func(ident *ast.Ident, embedded bool, pos token.Pos) { + add := func(ident *ast.Ident, embedded bool) { if tag != "" && tags == nil { tags = make([]string, len(fields)) } @@ -90,6 +90,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) { tags = append(tags, tag) } + pos := ident.Pos() name := ident.Name fld := NewField(pos, check.pkg, name, typ, embedded) // spec: "Within a struct, non-blank field names must be unique." @@ -103,10 +104,10 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) { // fields with errors; this keeps the number of struct fields in sync // with the source as long as the fields are _ or have different names // (go.dev/issue/25627). - addInvalid := func(ident *ast.Ident, pos token.Pos) { + addInvalid := func(ident *ast.Ident) { typ = Typ[Invalid] tag = "" - add(ident, true, pos) + add(ident, true) } for _, f := range list.List { @@ -115,7 +116,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) { if len(f.Names) > 0 { // named fields for _, name := range f.Names { - add(name, false, name.Pos()) + add(name, false) } } else { // embedded field @@ -128,10 +129,10 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) { check.errorf(f.Type, InvalidSyntaxTree, "embedded field type %s has no name", f.Type) name = ast.NewIdent("_") name.NamePos = pos - addInvalid(name, pos) + addInvalid(name) continue } - add(name, true, name.Pos()) // struct{p.T} field has position of T + add(name, true) // struct{p.T} field has position of T // Because we have a name, typ must be of the form T or *T, where T is the name // of a (named or alias) type, and t (= deref(typ)) must be the type of T. @@ -198,8 +199,10 @@ func embeddedFieldIdent(e ast.Expr) *ast.Ident { func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool { if alt := oset.insert(obj); alt != nil { - check.errorf(atPos(pos), DuplicateDecl, "%s redeclared", obj.Name()) - check.reportAltDecl(alt) + err := check.newError(DuplicateDecl) + err.addf(atPos(pos), "%s redeclared", obj.Name()) + err.addAltDecl(alt) + err.report() return false } return true diff --git a/contrib/go/_std_1.22/src/go/types/subst.go b/contrib/go/_std_1.23/src/go/types/subst.go similarity index 85% rename from contrib/go/_std_1.22/src/go/types/subst.go rename to contrib/go/_std_1.23/src/go/types/subst.go index 178f71728358..6be106d3aa99 100644 --- a/contrib/go/_std_1.22/src/go/types/subst.go +++ b/contrib/go/_std_1.23/src/go/types/subst.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/subst.go // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -98,15 +99,26 @@ func (subst *subster) typ(typ Type) Type { // nothing to do case *Alias: - rhs := subst.typ(t.fromRHS) - if rhs != t.fromRHS { - // This branch cannot be reached because the RHS of an alias - // may only contain type parameters of an enclosing function. - // Such function bodies are never "instantiated" and thus - // substitution is not called on locally declared alias types. - // TODO(gri) adjust once parameterized aliases are supported - panic("unreachable for unparameterized aliases") - // return subst.check.newAlias(t.obj, rhs) + // This code follows the code for *Named types closely. + // TODO(gri) try to factor better + orig := t.Origin() + n := orig.TypeParams().Len() + if n == 0 { + return t // type is not parameterized + } + + // TODO(gri) do we need this for Alias types? + if t.TypeArgs().Len() != n { + return Typ[Invalid] // error reported elsewhere + } + + // already instantiated + // For each (existing) type argument determine if it needs + // to be substituted; i.e., if it is or contains a type parameter + // that has a type argument for it. + targs, updated := subst.typeList(t.TypeArgs().list()) + if updated { + return subst.check.newAliasInstance(subst.pos, t.orig, targs, subst.expanding, subst.ctxt) } case *Array: @@ -223,18 +235,6 @@ func (subst *subster) typ(typ Type) Type { } case *Named: - // dump is for debugging - dump := func(string, ...interface{}) {} - if subst.check != nil && subst.check.conf._Trace { - subst.check.indent++ - defer func() { - subst.check.indent-- - }() - dump = func(format string, args ...interface{}) { - subst.check.trace(subst.pos, format, args...) - } - } - // subst is called during expansion, so in this function we need to be // careful not to call any methods that would cause t to be expanded: doing // so would result in deadlock. @@ -243,49 +243,31 @@ func (subst *subster) typ(typ Type) Type { orig := t.Origin() n := orig.TypeParams().Len() if n == 0 { - dump(">>> %s is not parameterized", t) return t // type is not parameterized } - var newTArgs []Type if t.TypeArgs().Len() != n { return Typ[Invalid] // error reported elsewhere } // already instantiated - dump(">>> %s already instantiated", t) - // For each (existing) type argument targ, determine if it needs + // For each (existing) type argument determine if it needs // to be substituted; i.e., if it is or contains a type parameter // that has a type argument for it. - for i, targ := range t.TypeArgs().list() { - dump(">>> %d targ = %s", i, targ) - new_targ := subst.typ(targ) - if new_targ != targ { - dump(">>> substituted %d targ %s => %s", i, targ, new_targ) - if newTArgs == nil { - newTArgs = make([]Type, n) - copy(newTArgs, t.TypeArgs().list()) - } - newTArgs[i] = new_targ - } + targs, updated := subst.typeList(t.TypeArgs().list()) + if updated { + // Create a new instance and populate the context to avoid endless + // recursion. The position used here is irrelevant because validation only + // occurs on t (we don't call validType on named), but we use subst.pos to + // help with debugging. + return subst.check.instance(subst.pos, orig, targs, subst.expanding, subst.ctxt) } - if newTArgs == nil { - dump(">>> nothing to substitute in %s", t) - return t // nothing to substitute - } - - // Create a new instance and populate the context to avoid endless - // recursion. The position used here is irrelevant because validation only - // occurs on t (we don't call validType on named), but we use subst.pos to - // help with debugging. - return subst.check.instance(subst.pos, orig, newTArgs, subst.expanding, subst.ctxt) - case *TypeParam: return subst.smap.lookup(t) default: - unreachable() + panic("unreachable") } return typ @@ -423,7 +405,7 @@ func (subst *subster) termlist(in []*Term) (out []*Term, copied bool) { func replaceRecvType(in []*Func, old, new Type) (out []*Func, copied bool) { out = in for i, method := range in { - sig := method.Type().(*Signature) + sig := method.Signature() if sig.recv != nil && sig.recv.Type() == old { if !copied { // Allocate a new methods slice before mutating for the first time. diff --git a/contrib/go/_std_1.22/src/go/types/termlist.go b/contrib/go/_std_1.23/src/go/types/termlist.go similarity index 98% rename from contrib/go/_std_1.22/src/go/types/termlist.go rename to contrib/go/_std_1.23/src/go/types/termlist.go index 9bc631c0e6f5..e17476f5211d 100644 --- a/contrib/go/_std_1.22/src/go/types/termlist.go +++ b/contrib/go/_std_1.23/src/go/types/termlist.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/termlist.go // Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/contrib/go/_std_1.22/src/go/types/tuple.go b/contrib/go/_std_1.23/src/go/types/tuple.go similarity index 94% rename from contrib/go/_std_1.22/src/go/types/tuple.go rename to contrib/go/_std_1.23/src/go/types/tuple.go index e5e3914bb210..7b391b27a1b6 100644 --- a/contrib/go/_std_1.22/src/go/types/tuple.go +++ b/contrib/go/_std_1.23/src/go/types/tuple.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/tuple.go // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/contrib/go/_std_1.22/src/go/types/type.go b/contrib/go/_std_1.23/src/go/types/type.go similarity index 78% rename from contrib/go/_std_1.22/src/go/types/type.go rename to contrib/go/_std_1.23/src/go/types/type.go index f6bd75908f1c..8fae93fb58d8 100644 --- a/contrib/go/_std_1.22/src/go/types/type.go +++ b/contrib/go/_std_1.23/src/go/types/type.go @@ -8,6 +8,9 @@ package types // All types implement the Type interface. type Type interface { // Underlying returns the underlying type of a type. + // Underlying types are never Named, TypeParam, or Alias types. + // + // See https://go.dev/ref/spec#Underlying_types. Underlying() Type // String returns a string representation of a type. diff --git a/contrib/go/_std_1.22/src/go/types/typelists.go b/contrib/go/_std_1.23/src/go/types/typelists.go similarity index 97% rename from contrib/go/_std_1.22/src/go/types/typelists.go rename to contrib/go/_std_1.23/src/go/types/typelists.go index c000de227254..a857ea02a981 100644 --- a/contrib/go/_std_1.22/src/go/types/typelists.go +++ b/contrib/go/_std_1.23/src/go/types/typelists.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/typelists.go // Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/contrib/go/_std_1.22/src/go/types/typeparam.go b/contrib/go/_std_1.23/src/go/types/typeparam.go similarity index 92% rename from contrib/go/_std_1.22/src/go/types/typeparam.go rename to contrib/go/_std_1.23/src/go/types/typeparam.go index a13f86c213c4..789b63d7a15a 100644 --- a/contrib/go/_std_1.22/src/go/types/typeparam.go +++ b/contrib/go/_std_1.23/src/go/types/typeparam.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/typeparam.go // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -27,8 +28,8 @@ type TypeParam struct { } // NewTypeParam returns a new TypeParam. Type parameters may be set on a Named -// or Signature type by calling SetTypeParams. Setting a type parameter on more -// than one type will result in a panic. +// type by calling SetTypeParams. Setting a type parameter on more than one type +// will result in a panic. // // The constraint argument can be nil, and set later via SetConstraint. If the // constraint is non-nil, it must be fully defined. @@ -88,6 +89,10 @@ func (t *TypeParam) SetConstraint(bound Type) { t.iface() } +// Underlying returns the [underlying type] of the type parameter t, which is +// the underlying type of its constraint. This type is always an interface. +// +// [underlying type]: https://go.dev/ref/spec#Underlying_types. func (t *TypeParam) Underlying() Type { return t.iface() } diff --git a/contrib/go/_std_1.22/src/go/types/typeset.go b/contrib/go/_std_1.23/src/go/types/typeset.go similarity index 90% rename from contrib/go/_std_1.22/src/go/types/typeset.go rename to contrib/go/_std_1.23/src/go/types/typeset.go index d164749996e2..a1d7e6cc994e 100644 --- a/contrib/go/_std_1.22/src/go/types/typeset.go +++ b/contrib/go/_std_1.23/src/go/types/typeset.go @@ -1,3 +1,6 @@ +// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/typeset.go + // Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -57,7 +60,7 @@ func (s *_TypeSet) Method(i int) *Func { return s.methods[i] } // LookupMethod returns the index of and method with matching package and name, or (-1, nil). func (s *_TypeSet) LookupMethod(pkg *Package, name string, foldCase bool) (int, *Func) { - return lookupMethod(s.methods, pkg, name, foldCase) + return methodIndex(s.methods, pkg, name, foldCase) } func (s *_TypeSet) String() string { @@ -131,8 +134,8 @@ func (s *_TypeSet) underIs(f func(Type) bool) bool { } for _, t := range s.terms { assert(t.typ != nil) - // x == under(x) for ~x terms - u := t.typ + // Unalias(x) == under(x) for ~x terms + u := Unalias(t.typ) if !t.tilde { u = under(u) } @@ -225,8 +228,10 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T mpos[m] = pos case explicit: if check != nil { - check.errorf(atPos(pos), DuplicateDecl, "duplicate method %s", m.name) - check.errorf(atPos(mpos[other.(*Func)]), DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented + err := check.newError(DuplicateDecl) + err.addf(atPos(pos), "duplicate method %s", m.name) + err.addf(atPos(mpos[other.(*Func)]), "other declaration of method %s", m.name) + err.report() } default: // We have a duplicate method name in an embedded (not explicitly declared) method. @@ -236,9 +241,11 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T // error message. if check != nil { check.later(func() { - if !check.allowVersion(m.pkg, atPos(pos), go1_14) || !Identical(m.typ, other.Type()) { - check.errorf(atPos(pos), DuplicateDecl, "duplicate method %s", m.name) - check.errorf(atPos(mpos[other.(*Func)]), DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented + if pos.IsValid() && !check.allowVersion(atPos(pos), go1_14) || !Identical(m.typ, other.Type()) { + err := check.newError(DuplicateDecl) + err.addf(atPos(pos), "duplicate method %s", m.name) + err.addf(atPos(mpos[other.(*Func)]), "other declaration of method %s", m.name) + err.report() } }).describef(atPos(pos), "duplicate method check for %s", m.name) } @@ -253,9 +260,8 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T allTerms := allTermlist allComparable := false for i, typ := range ityp.embeddeds { - // The embedding position is nil for imported interfaces - // and also for interface copies after substitution (but - // in that case we don't need to report errors again). + // The embedding position is nil for imported interfaces. + // We don't need to do version checks in those cases. var pos token.Pos // embedding position if ityp.embedPos != nil { pos = (*ityp.embedPos)[i] @@ -268,7 +274,7 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T assert(!isTypeParam(typ)) tset := computeInterfaceTypeSet(check, pos, u) // If typ is local, an error was already reported where typ is specified/defined. - if check != nil && check.isImportedConstraint(typ) && !check.verifyVersionf(atPos(pos), go1_18, "embedding constraint interface %s", typ) { + if pos.IsValid() && check != nil && check.isImportedConstraint(typ) && !check.verifyVersionf(atPos(pos), go1_18, "embedding constraint interface %s", typ) { continue } comparable = tset.comparable @@ -277,7 +283,7 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T } terms = tset.terms case *Union: - if check != nil && !check.verifyVersionf(atPos(pos), go1_18, "embedding interface element %s", u) { + if pos.IsValid() && check != nil && !check.verifyVersionf(atPos(pos), go1_18, "embedding interface element %s", u) { continue } tset := computeUnionTypeSet(check, unionSets, pos, u) @@ -291,7 +297,7 @@ func computeInterfaceTypeSet(check *Checker, pos token.Pos, ityp *Interface) *_T if !isValid(u) { continue } - if check != nil && !check.verifyVersionf(atPos(pos), go1_18, "embedding non-interface type %s", typ) { + if pos.IsValid() && check != nil && !check.verifyVersionf(atPos(pos), go1_18, "embedding non-interface type %s", typ) { continue } terms = termlist{{false, typ}} diff --git a/contrib/go/_std_1.22/src/go/types/typestring.go b/contrib/go/_std_1.23/src/go/types/typestring.go similarity index 92% rename from contrib/go/_std_1.22/src/go/types/typestring.go rename to contrib/go/_std_1.23/src/go/types/typestring.go index 23bddb2673d4..54f06138adc6 100644 --- a/contrib/go/_std_1.22/src/go/types/typestring.go +++ b/contrib/go/_std_1.23/src/go/types/typestring.go @@ -1,3 +1,6 @@ +// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/typestring.go + // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -9,7 +12,6 @@ package types import ( "bytes" "fmt" - "go/token" "sort" "strconv" "strings" @@ -125,7 +127,7 @@ func (w *typeWriter) typ(typ Type) { case *Basic: // exported basic types go into package unsafe // (currently this is just unsafe.Pointer) - if token.IsExported(t.name) { + if isExported(t.name) { if obj, _ := Unsafe.scope.Lookup(t.name).(*TypeName); obj != nil { w.typeName(obj) break @@ -153,7 +155,7 @@ func (w *typeWriter) typ(typ Type) { // If disambiguating one struct for another, look for the first unexported field. // Do this first in case of nested structs; tag the first-outermost field. pkgAnnotate := false - if w.qf == nil && w.pkgInfo && !token.IsExported(f.name) { + if w.qf == nil && w.pkgInfo && !isExported(f.name) { // note for embedded types, type name is field name, and "string" etc are lower case hence unexported. pkgAnnotate = true w.pkgInfo = false // only tag once @@ -174,9 +176,9 @@ func (w *typeWriter) typ(typ Type) { } if tag := t.Tag(i); tag != "" { w.byte(' ') - // TODO(rfindley) If tag contains blanks, replacing them with '#' - // in Context.TypeHash may produce another tag - // accidentally. + // TODO(gri) If tag contains blanks, replacing them with '#' + // in Context.TypeHash may produce another tag + // accidentally. w.string(strconv.Quote(tag)) } } @@ -212,10 +214,11 @@ func (w *typeWriter) typ(typ Type) { case *Interface: if w.ctxt == nil { - if t == universeAny.Type() { + if t == universeAnyAlias.Type().Underlying() { // When not hashing, we can try to improve type strings by writing "any" - // for a type that is pointer-identical to universeAny. This logic should - // be deprecated by more robust handling for aliases. + // for a type that is pointer-identical to universeAny. + // TODO(rfindley): this logic should not be necessary with + // gotypesalias=1. Remove once that is always the case. w.string("any") break } @@ -322,15 +325,23 @@ func (w *typeWriter) typ(typ Type) { // (say int), point out where it is declared to avoid confusing // error messages. This doesn't need to be super-elegant; we just // need a clear indication that this is not a predeclared name. - // Note: types2 prints position information here - we can't do - // that because we don't have a token.FileSet accessible. if w.ctxt == nil && Universe.Lookup(t.obj.name) != nil { - w.string("/* type parameter */") + if isTypes2 { + w.string(fmt.Sprintf(" /* with %s declared at %v */", t.obj.name, t.obj.Pos())) + } else { + // Can't print position information because + // we don't have a token.FileSet accessible. + w.string("/* type parameter */") + } } } case *Alias: w.typeName(t.obj) + if list := t.targs.list(); len(list) != 0 { + // instantiated type + w.typeList(list) + } if w.ctxt != nil { // TODO(gri) do we need to print the alias type name, too? w.typ(Unalias(t.obj.typ)) diff --git a/contrib/go/_std_1.22/src/go/types/typeterm.go b/contrib/go/_std_1.23/src/go/types/typeterm.go similarity index 98% rename from contrib/go/_std_1.22/src/go/types/typeterm.go rename to contrib/go/_std_1.23/src/go/types/typeterm.go index c86442c43fe5..1cd4e1651f30 100644 --- a/contrib/go/_std_1.22/src/go/types/typeterm.go +++ b/contrib/go/_std_1.23/src/go/types/typeterm.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/typeterm.go // Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style diff --git a/contrib/go/_std_1.22/src/go/types/typexpr.go b/contrib/go/_std_1.23/src/go/types/typexpr.go similarity index 92% rename from contrib/go/_std_1.22/src/go/types/typexpr.go rename to contrib/go/_std_1.23/src/go/types/typexpr.go index c887b5115a2a..b6b6881089de 100644 --- a/contrib/go/_std_1.22/src/go/types/typexpr.go +++ b/contrib/go/_std_1.23/src/go/types/typexpr.go @@ -42,13 +42,34 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *TypeName, wantType bo check.errorf(e, UndeclaredName, "undefined: %s", e.Name) } return - case universeAny, universeComparable: + case universeComparable: + if !check.verifyVersionf(e, go1_18, "predeclared %s", e.Name) { + return // avoid follow-on errors + } + } + // Because the representation of any depends on gotypesalias, we don't check + // pointer identity here. + if obj.Name() == "any" && obj.Parent() == Universe { if !check.verifyVersionf(e, go1_18, "predeclared %s", e.Name) { return // avoid follow-on errors } } check.recordUse(e, obj) + // If we want a type but don't have one, stop right here and avoid potential problems + // with missing underlying types. This also gives better error messages in some cases + // (see go.dev/issue/65344). + _, gotType := obj.(*TypeName) + if !gotType && wantType { + check.errorf(e, NotAType, "%s is not a type", obj.Name()) + // avoid "declared but not used" errors + // (don't use Checker.use - we don't want to evaluate too much) + if v, _ := obj.(*Var); v != nil && v.pkg == check.pkg /* see Checker.use1 */ { + v.used = true + } + return + } + // Type-check the object. // Only call Checker.objDecl if the object doesn't have a type yet // (in which case we must actually determine it) or the object is a @@ -58,7 +79,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *TypeName, wantType bo // informative "not a type/value" error that this function's caller // will issue (see go.dev/issue/25790). typ := obj.Type() - if _, gotType := obj.(*TypeName); typ == nil || gotType && wantType { + if typ == nil || gotType && wantType { check.objDecl(obj, def) typ = obj.Type() // type must have been assigned by Checker.objDecl } @@ -95,7 +116,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *TypeName, wantType bo x.mode = constant_ case *TypeName: - if !check.enableAlias && check.isBrokenAlias(obj) { + if !check.conf._EnableAlias && check.isBrokenAlias(obj) { check.errorf(e, InvalidDeclCycle, "invalid use of type alias %s in recursive type (see go.dev/issue/50729)", obj.name) return } @@ -126,7 +147,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *TypeName, wantType bo x.mode = value default: - unreachable() + panic("unreachable") } x.typ = typ @@ -422,6 +443,10 @@ func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *TypeName) }() } + defer func() { + setDefType(def, res) + }() + var cause string gtyp := check.genericType(ix.X, &cause) if cause != "" { @@ -431,21 +456,23 @@ func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *TypeName) return gtyp // error already reported } - orig := asNamed(gtyp) - if orig == nil { - panic(fmt.Sprintf("%v: cannot instantiate %v", ix.Pos(), gtyp)) - } - // evaluate arguments targs := check.typeList(ix.Indices) if targs == nil { - setDefType(def, Typ[Invalid]) // avoid errors later due to lazy instantiation return Typ[Invalid] } + if orig, _ := gtyp.(*Alias); orig != nil { + return check.instance(ix.Pos(), orig, targs, nil, check.context()) + } + + orig := asNamed(gtyp) + if orig == nil { + panic(fmt.Sprintf("%v: cannot instantiate %v", ix.Pos(), gtyp)) + } + // create the instance inst := asNamed(check.instance(ix.Pos(), orig, targs, nil, check.context())) - setDefType(def, inst) // orig.tparams may not be set up, so we need to do expansion later. check.later(func() { @@ -461,7 +488,7 @@ func (check *Checker) instantiatedType(ix *typeparams.IndexExpr, def *TypeName) if i < len(ix.Indices) { pos = ix.Indices[i].Pos() } - check.softErrorf(atPos(pos), InvalidTypeArg, err.Error()) + check.softErrorf(atPos(pos), InvalidTypeArg, "%v", err) } else { check.mono.recordInstance(check.pkg, ix.Pos(), inst.TypeParams().list(), inst.TypeArgs().list(), ix.Indices) } diff --git a/contrib/go/_std_1.22/src/go/types/under.go b/contrib/go/_std_1.23/src/go/types/under.go similarity index 97% rename from contrib/go/_std_1.22/src/go/types/under.go rename to contrib/go/_std_1.23/src/go/types/under.go index 3838528b5317..ed5aab238e58 100644 --- a/contrib/go/_std_1.22/src/go/types/under.go +++ b/contrib/go/_std_1.23/src/go/types/under.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/under.go // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -24,6 +25,7 @@ func under(t Type) Type { // identical element types), the single underlying type is the restricted // channel type if the restrictions are always the same, or nil otherwise. func coreType(t Type) Type { + t = Unalias(t) tpar, _ := t.(*TypeParam) if tpar == nil { return under(t) @@ -53,6 +55,7 @@ func coreType(t Type) Type { // and strings as identical. In this case, if successful and we saw // a string, the result is of type (possibly untyped) string. func coreString(t Type) Type { + t = Unalias(t) tpar, _ := t.(*TypeParam) if tpar == nil { return under(t) // string or untyped string diff --git a/contrib/go/_std_1.22/src/go/types/unify.go b/contrib/go/_std_1.23/src/go/types/unify.go similarity index 96% rename from contrib/go/_std_1.22/src/go/types/unify.go rename to contrib/go/_std_1.23/src/go/types/unify.go index d4889b93d972..e4b50d7d4fec 100644 --- a/contrib/go/_std_1.22/src/go/types/unify.go +++ b/contrib/go/_std_1.23/src/go/types/unify.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/unify.go // Copyright 2020 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -207,10 +208,10 @@ func (u *unifier) join(x, y *TypeParam) bool { return true } -// asTypeParam returns x.(*TypeParam) if x is a type parameter recorded with u. +// asBoundTypeParam returns x.(*TypeParam) if x is a type parameter recorded with u. // Otherwise, the result is nil. -func (u *unifier) asTypeParam(x Type) *TypeParam { - if x, _ := x.(*TypeParam); x != nil { +func (u *unifier) asBoundTypeParam(x Type) *TypeParam { + if x, _ := Unalias(x).(*TypeParam); x != nil { if _, found := u.handles[x]; found { return x } @@ -271,7 +272,7 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type { // asInterface returns the underlying type of x as an interface if // it is a non-type parameter interface. Otherwise it returns nil. func asInterface(x Type) (i *Interface) { - if _, ok := x.(*TypeParam); !ok { + if _, ok := Unalias(x).(*TypeParam); !ok { i, _ = under(x).(*Interface) } return i @@ -293,11 +294,8 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { u.depth-- }() - x = Unalias(x) - y = Unalias(y) - // nothing to do if x == y - if x == y { + if x == y || Unalias(x) == Unalias(y) { return true } @@ -316,7 +314,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { // Ensure that if we have at least one // - defined type, make sure one is in y // - type parameter recorded with u, make sure one is in x - if asNamed(x) != nil || u.asTypeParam(y) != nil { + if asNamed(x) != nil || u.asBoundTypeParam(y) != nil { if traceInference { u.tracef("%s ≡ %s\t// swap", y, x) } @@ -349,7 +347,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { // that is a type parameter. assert(!isTypeParam(y)) // x and y may be identical now - if x == y { + if x == y || Unalias(x) == Unalias(y) { return true } } @@ -360,7 +358,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { // isTypeLit(x) is false and y was not changed above. In other // words, if y was a defined type, it is still a defined type // (relevant for the logic below). - switch px, py := u.asTypeParam(x), u.asTypeParam(y); { + switch px, py := u.asBoundTypeParam(x), u.asBoundTypeParam(y); { case px != nil && py != nil: // both x and y are type parameters if u.join(px, py) { @@ -451,7 +449,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { } // x != y if we get here - assert(x != y) + assert(x != y && Unalias(x) != Unalias(y)) // If u.EnableInterfaceInference is set and we don't require exact unification, // if both types are interfaces, one interface must have a subset of the @@ -575,6 +573,10 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { emode |= exact } + // Continue with unaliased types but don't lose original alias names, if any (go.dev/issue/67628). + xorig, x := x, Unalias(x) + yorig, y := y, Unalias(y) + switch x := x.(type) { case *Basic: // Basic types are singletons except for the rune and byte @@ -610,7 +612,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { g := y.fields[i] if f.embedded != g.embedded || x.Tag(i) != y.Tag(i) || - !f.sameId(g.pkg, g.name) || + !f.sameId(g.pkg, g.name, false) || !u.nify(f.typ, g.typ, emode, p) { return false } @@ -753,7 +755,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { case *TypeParam: // x must be an unbound type parameter (see comment above). if debug { - assert(u.asTypeParam(x) == nil) + assert(u.asBoundTypeParam(x) == nil) } // By definition, a valid type argument must be in the type set of // the respective type constraint. Therefore, the type argument's @@ -776,13 +778,13 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { // need to take care of that case separately. if cx := coreType(x); cx != nil { if traceInference { - u.tracef("core %s ≡ %s", x, y) + u.tracef("core %s ≡ %s", xorig, yorig) } // If y is a defined type, it may not match against cx which // is an underlying type (incl. int, string, etc.). Use assign // mode here so that the unifier automatically takes under(y) // if necessary. - return u.nify(cx, y, assign, p) + return u.nify(cx, yorig, assign, p) } } // x != y and there's nothing to do @@ -791,7 +793,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) { // avoid a crash in case of nil type default: - panic(sprintf(nil, nil, true, "u.nify(%s, %s, %d)", x, y, mode)) + panic(sprintf(nil, nil, true, "u.nify(%s, %s, %d)", xorig, yorig, mode)) } return false diff --git a/contrib/go/_std_1.22/src/go/types/union.go b/contrib/go/_std_1.23/src/go/types/union.go similarity index 100% rename from contrib/go/_std_1.22/src/go/types/union.go rename to contrib/go/_std_1.23/src/go/types/union.go diff --git a/contrib/go/_std_1.22/src/go/types/universe.go b/contrib/go/_std_1.23/src/go/types/universe.go similarity index 81% rename from contrib/go/_std_1.22/src/go/types/universe.go rename to contrib/go/_std_1.23/src/go/types/universe.go index bde0293527f2..09b882ce0555 100644 --- a/contrib/go/_std_1.22/src/go/types/universe.go +++ b/contrib/go/_std_1.23/src/go/types/universe.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/universe.go // Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -25,7 +26,8 @@ var ( universeIota Object universeByte Type // uint8 alias, but has name "byte" universeRune Type // int32 alias, but has name "rune" - universeAny Object + universeAnyNoAlias *TypeName + universeAnyAlias *TypeName universeError Type universeComparable Object ) @@ -67,7 +69,7 @@ var Typ = []*Basic{ UntypedNil: {UntypedNil, IsUntyped, "untyped nil"}, } -var aliases = [...]*Basic{ +var basicAliases = [...]*Basic{ {Byte, IsInteger | IsUnsigned, "byte"}, {Rune, IsInteger, "rune"}, } @@ -76,15 +78,41 @@ func defPredeclaredTypes() { for _, t := range Typ { def(NewTypeName(nopos, nil, t.name, t)) } - for _, t := range aliases { + for _, t := range basicAliases { def(NewTypeName(nopos, nil, t.name, t)) } // type any = interface{} - // Note: don't use &emptyInterface for the type of any. Using a unique - // pointer allows us to detect any and format it as "any" rather than - // interface{}, which clarifies user-facing error messages significantly. - def(NewTypeName(nopos, nil, "any", &Interface{complete: true, tset: &topTypeSet})) + // + // Implement two representations of any: one for the legacy gotypesalias=0, + // and one for gotypesalias=1. This is necessary for consistent + // representation of interface aliases during type checking, and is + // implemented via hijacking [Scope.Lookup] for the [Universe] scope. + // + // Both representations use the same distinguished pointer for their RHS + // interface type, allowing us to detect any (even with the legacy + // representation), and format it as "any" rather than interface{}, which + // clarifies user-facing error messages significantly. + // + // TODO(rfindley): once the gotypesalias GODEBUG variable is obsolete (and we + // consistently use the Alias node), we should be able to clarify user facing + // error messages without using a distinguished pointer for the any + // interface. + { + universeAnyNoAlias = NewTypeName(nopos, nil, "any", &Interface{complete: true, tset: &topTypeSet}) + universeAnyNoAlias.setColor(black) + // ensure that the any TypeName reports a consistent Parent, after + // hijacking Universe.Lookup with gotypesalias=0. + universeAnyNoAlias.setParent(Universe) + + // It shouldn't matter which representation of any is actually inserted + // into the Universe, but we lean toward the future and insert the Alias + // representation. + universeAnyAlias = NewTypeName(nopos, nil, "any", nil) + universeAnyAlias.setColor(black) + _ = NewAlias(universeAnyAlias, universeAnyNoAlias.Type().Underlying()) // Link TypeName and Alias + def(universeAnyAlias) + } // type error interface{ Error() string } { @@ -252,7 +280,6 @@ func init() { universeIota = Universe.Lookup("iota") universeByte = Universe.Lookup("byte").Type() universeRune = Universe.Lookup("rune").Type() - universeAny = Universe.Lookup("any") universeError = Universe.Lookup("error").Type() universeComparable = Universe.Lookup("comparable") } @@ -281,7 +308,7 @@ func def(obj Object) { case *Builtin: obj.pkg = Unsafe default: - unreachable() + panic("unreachable") } } if scope.Insert(obj) != nil { diff --git a/contrib/go/_std_1.23/src/go/types/util.go b/contrib/go/_std_1.23/src/go/types/util.go new file mode 100644 index 000000000000..5d4ccc6f1ff1 --- /dev/null +++ b/contrib/go/_std_1.23/src/go/types/util.go @@ -0,0 +1,48 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains various functionality that is +// different between go/types and types2. Factoring +// out this code allows more of the rest of the code +// to be shared. + +package types + +import ( + "go/ast" + "go/constant" + "go/token" +) + +const isTypes2 = false + +// cmpPos compares the positions p and q and returns a result r as follows: +// +// r < 0: p is before q +// r == 0: p and q are the same position (but may not be identical) +// r > 0: p is after q +// +// If p and q are in different files, p is before q if the filename +// of p sorts lexicographically before the filename of q. +func cmpPos(p, q token.Pos) int { return int(p - q) } + +// hasDots reports whether the last argument in the call is followed by ... +func hasDots(call *ast.CallExpr) bool { return call.Ellipsis.IsValid() } + +// dddErrPos returns the positioner for reporting an invalid ... use in a call. +func dddErrPos(call *ast.CallExpr) positioner { return atPos(call.Ellipsis) } + +// argErrPos returns positioner for reporting an invalid argument count. +func argErrPos(call *ast.CallExpr) positioner { return inNode(call, call.Rparen) } + +// startPos returns the start position of node n. +func startPos(n ast.Node) token.Pos { return n.Pos() } + +// endPos returns the position of the first character immediately after node n. +func endPos(n ast.Node) token.Pos { return n.End() } + +// makeFromLiteral returns the constant value for the given literal string and kind. +func makeFromLiteral(lit string, kind token.Token) constant.Value { + return constant.MakeFromLiteral(lit, kind, 0) +} diff --git a/contrib/go/_std_1.22/src/go/types/validtype.go b/contrib/go/_std_1.23/src/go/types/validtype.go similarity index 77% rename from contrib/go/_std_1.22/src/go/types/validtype.go rename to contrib/go/_std_1.23/src/go/types/validtype.go index 063871485732..f87b82c439eb 100644 --- a/contrib/go/_std_1.22/src/go/types/validtype.go +++ b/contrib/go/_std_1.23/src/go/types/validtype.go @@ -1,4 +1,5 @@ // Code generated by "go test -run=Generate -write=all"; DO NOT EDIT. +// Source: ../../cmd/compile/internal/types2/validtype.go // Copyright 2022 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -6,12 +7,14 @@ package types +import "go/token" + // validType verifies that the given type does not "expand" indefinitely // producing a cycle in the type graph. // (Cycles involving alias types, as in "type A = [10]A" are detected // earlier, via the objDecl cycle detection mechanism.) func (check *Checker) validType(typ *Named) { - check.validType0(typ, nil, nil) + check.validType0(nopos, typ, nil, nil) } // validType0 checks if the given type is valid. If typ is a type parameter @@ -24,8 +27,21 @@ func (check *Checker) validType(typ *Named) { // of) F in S, leading to the nest S->F. If a type appears in its own nest // (say S->F->S) we have an invalid recursive type. The path list is the full // path of named types in a cycle, it is only needed for error reporting. -func (check *Checker) validType0(typ Type, nest, path []*Named) bool { - switch t := Unalias(typ).(type) { +func (check *Checker) validType0(pos token.Pos, typ Type, nest, path []*Named) bool { + typ = Unalias(typ) + + if check.conf._Trace { + if t, _ := typ.(*Named); t != nil && t.obj != nil /* obj should always exist but be conservative */ { + pos = t.obj.pos + } + check.indent++ + check.trace(pos, "validType(%s) nest %v, path %v", typ, pathString(makeObjList(nest)), pathString(makeObjList(path))) + defer func() { + check.indent-- + }() + } + + switch t := typ.(type) { case nil: // We should never see a nil type but be conservative and panic // only in debug mode. @@ -34,38 +50,49 @@ func (check *Checker) validType0(typ Type, nest, path []*Named) bool { } case *Array: - return check.validType0(t.elem, nest, path) + return check.validType0(pos, t.elem, nest, path) case *Struct: for _, f := range t.fields { - if !check.validType0(f.typ, nest, path) { + if !check.validType0(pos, f.typ, nest, path) { return false } } case *Union: for _, t := range t.terms { - if !check.validType0(t.typ, nest, path) { + if !check.validType0(pos, t.typ, nest, path) { return false } } case *Interface: for _, etyp := range t.embeddeds { - if !check.validType0(etyp, nest, path) { + if !check.validType0(pos, etyp, nest, path) { return false } } case *Named: - // Exit early if we already know t is valid. - // This is purely an optimization but it prevents excessive computation - // times in pathological cases such as testdata/fixedbugs/issue6977.go. - // (Note: The valids map could also be allocated locally, once for each - // validType call.) - if check.valids.lookup(t) != nil { - break - } + // TODO(gri) The optimization below is incorrect (see go.dev/issue/65711): + // in that issue `type A[P any] [1]P` is a valid type on its own + // and the (uninstantiated) A is recorded in check.valids. As a + // consequence, when checking the remaining declarations, which + // are not valid, the validity check ends prematurely because A + // is considered valid, even though its validity depends on the + // type argument provided to it. + // + // A correct optimization is important for pathological cases. + // Keep code around for reference until we found an optimization. + // + // // Exit early if we already know t is valid. + // // This is purely an optimization but it prevents excessive computation + // // times in pathological cases such as testdata/fixedbugs/issue6977.go. + // // (Note: The valids map could also be allocated locally, once for each + // // validType call.) + // if check.valids.lookup(t) != nil { + // break + // } // Don't report a 2nd error if we already know the type is invalid // (e.g., if a cycle was detected earlier, via under). @@ -111,7 +138,7 @@ func (check *Checker) validType0(typ Type, nest, path []*Named) bool { // index of t in nest. Search again. for start, p := range path { if Identical(p, t) { - check.cycleError(makeObjList(path[start:])) + check.cycleError(makeObjList(path[start:]), 0) return false } } @@ -123,18 +150,19 @@ func (check *Checker) validType0(typ Type, nest, path []*Named) bool { // Every type added to nest is also added to path; thus every type that is in nest // must also be in path (invariant). But not every type in path is in nest, since // nest may be pruned (see below, *TypeParam case). - if !check.validType0(t.Origin().fromRHS, append(nest, t), append(path, t)) { + if !check.validType0(pos, t.Origin().fromRHS, append(nest, t), append(path, t)) { return false } - check.valids.add(t) // t is valid + // see TODO above + // check.valids.add(t) // t is valid case *TypeParam: // A type parameter stands for the type (argument) it was instantiated with. // Check the corresponding type argument for validity if we are in an // instantiated type. - if len(nest) > 0 { - inst := nest[len(nest)-1] // the type instance + if d := len(nest) - 1; d >= 0 { + inst := nest[d] // the type instance // Find the corresponding type argument for the type parameter // and proceed with checking that type argument. for i, tparam := range inst.TypeParams().list() { @@ -148,7 +176,12 @@ func (check *Checker) validType0(typ Type, nest, path []*Named) bool { // the current (instantiated) type (see the example // at the end of this file). // For error reporting we keep the full path. - return check.validType0(targ, nest[:len(nest)-1], path) + res := check.validType0(pos, targ, nest[:d], path) + // The check.validType0 call with nest[:d] may have + // overwritten the entry at the current depth d. + // Restore the entry (was issue go.dev/issue/66323). + nest[d] = inst + return res } } } diff --git a/contrib/go/_std_1.22/src/go/types/version.go b/contrib/go/_std_1.23/src/go/types/version.go similarity index 62% rename from contrib/go/_std_1.22/src/go/types/version.go rename to contrib/go/_std_1.23/src/go/types/version.go index f2466edc1fa1..669ca66a3972 100644 --- a/contrib/go/_std_1.22/src/go/types/version.go +++ b/contrib/go/_std_1.23/src/go/types/version.go @@ -10,7 +10,6 @@ import ( "go/token" "go/version" "internal/goversion" - "strings" ) // A goVersion is a Go language version string of the form "go1.%d" @@ -45,65 +44,35 @@ var ( go1_20 = asGoVersion("go1.20") go1_21 = asGoVersion("go1.21") go1_22 = asGoVersion("go1.22") + go1_23 = asGoVersion("go1.23") // current (deployed) Go version go_current = asGoVersion(fmt.Sprintf("go1.%d", goversion.Version)) ) -// langCompat reports an error if the representation of a numeric -// literal is not compatible with the current language version. -func (check *Checker) langCompat(lit *ast.BasicLit) { - s := lit.Value - if len(s) <= 2 || check.allowVersion(check.pkg, lit, go1_13) { - return - } - // len(s) > 2 - if strings.Contains(s, "_") { - check.versionErrorf(lit, go1_13, "underscores in numeric literals") - return - } - if s[0] != '0' { - return - } - radix := s[1] - if radix == 'b' || radix == 'B' { - check.versionErrorf(lit, go1_13, "binary literals") - return - } - if radix == 'o' || radix == 'O' { - check.versionErrorf(lit, go1_13, "0o/0O-style octal literals") - return - } - if lit.Kind != token.INT && (radix == 'x' || radix == 'X') { - check.versionErrorf(lit, go1_13, "hexadecimal floating-point literals") +// allowVersion reports whether the current package at the given position +// is allowed to use version v. If the position is unknown, the specified +// module version (Config.GoVersion) is used. If that version is invalid, +// allowVersion returns true. +func (check *Checker) allowVersion(at positioner, v goVersion) bool { + fileVersion := check.conf.GoVersion + if pos := at.Pos(); pos.IsValid() { + fileVersion = check.versions[check.fileFor(pos)] } -} -// allowVersion reports whether the given package is allowed to use version v. -func (check *Checker) allowVersion(pkg *Package, at positioner, v goVersion) bool { - // We assume that imported packages have all been checked, - // so we only have to check for the local package. - if pkg != check.pkg { - return true - } + // We need asGoVersion (which calls version.Lang) below + // because fileVersion may be the (unaltered) Config.GoVersion + // string which may contain dot-release information. + version := asGoVersion(fileVersion) - // If no explicit file version is specified, - // fileVersion corresponds to the module version. - var fileVersion goVersion - if pos := at.Pos(); pos.IsValid() { - // We need version.Lang below because file versions - // can be (unaltered) Config.GoVersion strings that - // may contain dot-release information. - fileVersion = asGoVersion(check.versions[check.fileFor(pos)]) - } - return !fileVersion.isValid() || fileVersion.cmp(v) >= 0 + return !version.isValid() || version.cmp(v) >= 0 } // verifyVersionf is like allowVersion but also accepts a format string and arguments // which are used to report a version error if allowVersion returns false. It uses the // current package. func (check *Checker) verifyVersionf(at positioner, v goVersion, format string, args ...interface{}) bool { - if !check.allowVersion(check.pkg, at, v) { + if !check.allowVersion(at, v) { check.versionErrorf(at, v, format, args...) return false } diff --git a/contrib/go/_std_1.22/src/go/types/ya.make b/contrib/go/_std_1.23/src/go/types/ya.make similarity index 95% rename from contrib/go/_std_1.22/src/go/types/ya.make rename to contrib/go/_std_1.23/src/go/types/ya.make index 302453e5f4a6..f50c80992d58 100644 --- a/contrib/go/_std_1.22/src/go/types/ya.make +++ b/contrib/go/_std_1.23/src/go/types/ya.make @@ -6,6 +6,7 @@ IF (TRUE) api_predicates.go array.go assignments.go + badlinkname.go basic.go builtins.go call.go @@ -16,9 +17,11 @@ IF (TRUE) conversions.go decl.go errors.go + errsupport.go eval.go expr.go exprstring.go + format.go gccgosizes.go gcsizes.go generate.go diff --git a/contrib/go/_std_1.22/src/go/version/version.go b/contrib/go/_std_1.23/src/go/version/version.go similarity index 100% rename from contrib/go/_std_1.22/src/go/version/version.go rename to contrib/go/_std_1.23/src/go/version/version.go diff --git a/contrib/go/_std_1.22/src/go/version/ya.make b/contrib/go/_std_1.23/src/go/version/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/go/version/ya.make rename to contrib/go/_std_1.23/src/go/version/ya.make diff --git a/contrib/go/_std_1.22/src/hash/adler32/adler32.go b/contrib/go/_std_1.23/src/hash/adler32/adler32.go similarity index 82% rename from contrib/go/_std_1.22/src/hash/adler32/adler32.go rename to contrib/go/_std_1.23/src/hash/adler32/adler32.go index 07695e947a16..ed9ccad910c0 100644 --- a/contrib/go/_std_1.22/src/hash/adler32/adler32.go +++ b/contrib/go/_std_1.23/src/hash/adler32/adler32.go @@ -16,6 +16,7 @@ package adler32 import ( "errors" "hash" + "internal/byteorder" ) const ( @@ -59,7 +60,7 @@ const ( func (d *digest) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize) b = append(b, magic...) - b = appendUint32(b, uint32(*d)) + b = byteorder.BeAppendUint32(b, uint32(*d)) return b, nil } @@ -70,28 +71,10 @@ func (d *digest) UnmarshalBinary(b []byte) error { if len(b) != marshaledSize { return errors.New("hash/adler32: invalid hash state size") } - *d = digest(readUint32(b[len(magic):])) + *d = digest(byteorder.BeUint32(b[len(magic):])) return nil } -// appendUint32 is semantically the same as [binary.BigEndian.AppendUint32] -// We copied this function because we can not import "encoding/binary" here. -func appendUint32(b []byte, x uint32) []byte { - return append(b, - byte(x>>24), - byte(x>>16), - byte(x>>8), - byte(x), - ) -} - -// readUint32 is semantically the same as [binary.BigEndian.Uint32] -// We copied this function because we can not import "encoding/binary" here. -func readUint32(b []byte) uint32 { - _ = b[3] - return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 -} - // Add p to the running checksum d. func update(d digest, p []byte) digest { s1, s2 := uint32(d&0xffff), uint32(d>>16) diff --git a/contrib/go/_std_1.22/src/hash/adler32/ya.make b/contrib/go/_std_1.23/src/hash/adler32/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/hash/adler32/ya.make rename to contrib/go/_std_1.23/src/hash/adler32/ya.make diff --git a/contrib/go/_std_1.22/src/hash/crc32/crc32.go b/contrib/go/_std_1.23/src/hash/crc32/crc32.go similarity index 91% rename from contrib/go/_std_1.22/src/hash/crc32/crc32.go rename to contrib/go/_std_1.23/src/hash/crc32/crc32.go index 170f05cf8a17..3964646b2773 100644 --- a/contrib/go/_std_1.22/src/hash/crc32/crc32.go +++ b/contrib/go/_std_1.23/src/hash/crc32/crc32.go @@ -15,6 +15,7 @@ package crc32 import ( "errors" "hash" + "internal/byteorder" "sync" "sync/atomic" ) @@ -172,8 +173,8 @@ const ( func (d *digest) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize) b = append(b, magic...) - b = appendUint32(b, tableSum(d.tab)) - b = appendUint32(b, d.crc) + b = byteorder.BeAppendUint32(b, tableSum(d.tab)) + b = byteorder.BeAppendUint32(b, d.crc) return b, nil } @@ -184,31 +185,13 @@ func (d *digest) UnmarshalBinary(b []byte) error { if len(b) != marshaledSize { return errors.New("hash/crc32: invalid hash state size") } - if tableSum(d.tab) != readUint32(b[4:]) { + if tableSum(d.tab) != byteorder.BeUint32(b[4:]) { return errors.New("hash/crc32: tables do not match") } - d.crc = readUint32(b[8:]) + d.crc = byteorder.BeUint32(b[8:]) return nil } -// appendUint32 is semantically the same as [binary.BigEndian.AppendUint32] -// We copied this function because we can not import "encoding/binary" here. -func appendUint32(b []byte, x uint32) []byte { - return append(b, - byte(x>>24), - byte(x>>16), - byte(x>>8), - byte(x), - ) -} - -// readUint32 is semantically the same as [binary.BigEndian.Uint32] -// We copied this function because we can not import "encoding/binary" here. -func readUint32(b []byte) uint32 { - _ = b[3] - return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 -} - func update(crc uint32, tab *Table, p []byte, checkInitIEEE bool) uint32 { switch { case haveCastagnoli.Load() && tab == castagnoliTable: @@ -261,7 +244,7 @@ func tableSum(t *Table) uint32 { b := a[:0] if t != nil { for _, x := range t { - b = appendUint32(b, x) + b = byteorder.BeAppendUint32(b, x) } } return ChecksumIEEE(b) diff --git a/contrib/go/_std_1.22/src/hash/crc32/crc32_amd64.go b/contrib/go/_std_1.23/src/hash/crc32/crc32_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/hash/crc32/crc32_amd64.go rename to contrib/go/_std_1.23/src/hash/crc32/crc32_amd64.go diff --git a/contrib/go/_std_1.22/src/hash/crc32/crc32_amd64.s b/contrib/go/_std_1.23/src/hash/crc32/crc32_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/hash/crc32/crc32_amd64.s rename to contrib/go/_std_1.23/src/hash/crc32/crc32_amd64.s diff --git a/contrib/go/_std_1.22/src/hash/crc32/crc32_arm64.go b/contrib/go/_std_1.23/src/hash/crc32/crc32_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/hash/crc32/crc32_arm64.go rename to contrib/go/_std_1.23/src/hash/crc32/crc32_arm64.go diff --git a/contrib/go/_std_1.22/src/hash/crc32/crc32_arm64.s b/contrib/go/_std_1.23/src/hash/crc32/crc32_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/hash/crc32/crc32_arm64.s rename to contrib/go/_std_1.23/src/hash/crc32/crc32_arm64.s diff --git a/contrib/go/_std_1.22/src/hash/crc32/crc32_generic.go b/contrib/go/_std_1.23/src/hash/crc32/crc32_generic.go similarity index 96% rename from contrib/go/_std_1.22/src/hash/crc32/crc32_generic.go rename to contrib/go/_std_1.23/src/hash/crc32/crc32_generic.go index abacbb663d45..d581710bc82e 100644 --- a/contrib/go/_std_1.22/src/hash/crc32/crc32_generic.go +++ b/contrib/go/_std_1.23/src/hash/crc32/crc32_generic.go @@ -12,6 +12,8 @@ package crc32 +import "internal/byteorder" + // simpleMakeTable allocates and constructs a Table for the specified // polynomial. The table is suitable for use with the simple algorithm // (simpleUpdate). @@ -74,7 +76,7 @@ func slicingUpdate(crc uint32, tab *slicing8Table, p []byte) uint32 { if len(p) >= slicing8Cutoff { crc = ^crc for len(p) > 8 { - crc ^= uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24 + crc ^= byteorder.LeUint32(p) crc = tab[0][p[7]] ^ tab[1][p[6]] ^ tab[2][p[5]] ^ tab[3][p[4]] ^ tab[4][crc>>24] ^ tab[5][(crc>>16)&0xFF] ^ tab[6][(crc>>8)&0xFF] ^ tab[7][crc&0xFF] diff --git a/contrib/go/_std_1.22/src/hash/crc32/crc32_otherarch.go b/contrib/go/_std_1.23/src/hash/crc32/crc32_otherarch.go similarity index 100% rename from contrib/go/_std_1.22/src/hash/crc32/crc32_otherarch.go rename to contrib/go/_std_1.23/src/hash/crc32/crc32_otherarch.go diff --git a/contrib/go/_std_1.22/src/hash/crc32/crc32_ppc64le.go b/contrib/go/_std_1.23/src/hash/crc32/crc32_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/hash/crc32/crc32_ppc64le.go rename to contrib/go/_std_1.23/src/hash/crc32/crc32_ppc64le.go diff --git a/contrib/go/_std_1.22/src/hash/crc32/crc32_ppc64le.s b/contrib/go/_std_1.23/src/hash/crc32/crc32_ppc64le.s similarity index 91% rename from contrib/go/_std_1.22/src/hash/crc32/crc32_ppc64le.s rename to contrib/go/_std_1.23/src/hash/crc32/crc32_ppc64le.s index 84ef2133127d..fb7c783f93d6 100644 --- a/contrib/go/_std_1.22/src/hash/crc32/crc32_ppc64le.s +++ b/contrib/go/_std_1.23/src/hash/crc32/crc32_ppc64le.s @@ -63,67 +63,56 @@ loop: RLDICL $40,R9,$56,R17 // p[7] SLD $2,R17,R17 // p[7]*4 RLDICL $40,R7,$56,R8 // crc>>24 - ADD R17,R10,R17 // &tab[0][p[7]] SLD $2,R8,R8 // crc>>24*4 RLDICL $48,R9,$56,R18 // p[6] SLD $2,R18,R18 // p[6]*4 + MOVWZ (R10)(R17),R21 // tab[0][p[7]] ADD $1024,R10,R10 // tab[1] - MOVWZ 0(R17),R21 // tab[0][p[7]] RLDICL $56,R9,$56,R19 // p[5] - ADD R10,R18,R18 // &tab[1][p[6]] SLD $2,R19,R19 // p[5]*4:1 - MOVWZ 0(R18),R22 // tab[1][p[6]] + MOVWZ (R10)(R18),R22 // tab[1][p[6]] ADD $1024,R10,R10 // tab[2] XOR R21,R22,R21 // xor done R22 - ADD R19,R10,R19 // &tab[2][p[5]] - ANDCC $255,R9,R20 // p[4] ?? - SLD $2,R20,R20 // p[4]*4 - MOVWZ 0(R19),R23 // tab[2][p[5]] + CLRLSLDI $56,R9,$2,R20 + MOVWZ (R10)(R19),R23 // tab[2][p[5]] ADD $1024,R10,R10 // &tab[3] - ADD R20,R10,R20 // tab[3][p[4]] XOR R21,R23,R21 // xor done R23 - ADD $1024,R10,R10 // &tab[4] - MOVWZ 0(R20),R24 // tab[3][p[4]] - ADD R10,R8,R23 // &tab[4][crc>>24] + MOVWZ (R10)(R20),R24 // tab[3][p[4]] + ADD $1024,R10,R10 // &tab[4] XOR R21,R24,R21 // xor done R24 - MOVWZ 0(R23),R25 // tab[4][crc>>24] + MOVWZ (R10)(R8),R25 // tab[4][crc>>24] RLDICL $48,R7,$56,R24 // crc>>16&0xFF XOR R21,R25,R21 // xor done R25 ADD $1024,R10,R10 // &tab[5] SLD $2,R24,R24 // crc>>16&0xFF*4 - ADD R24,R10,R24 // &tab[5][crc>>16&0xFF] - MOVWZ 0(R24),R26 // tab[5][crc>>16&0xFF] + MOVWZ (R10)(R24),R26 // tab[5][crc>>16&0xFF] XOR R21,R26,R21 // xor done R26 RLDICL $56,R7,$56,R25 // crc>>8 ADD $1024,R10,R10 // &tab[6] SLD $2,R25,R25 // crc>>8&FF*2 - ADD R25,R10,R25 // &tab[6][crc>>8&0xFF] MOVBZ R7,R26 // crc&0xFF - ADD $1024,R10,R10 // &tab[7] - MOVWZ 0(R25),R27 // tab[6][crc>>8&0xFF] + MOVWZ (R10)(R25),R27 // tab[6][crc>>8&0xFF] + ADD $1024,R10,R10 // &tab[7] SLD $2,R26,R26 // crc&0xFF*2 XOR R21,R27,R21 // xor done R27 - ADD R26,R10,R26 // &tab[7][crc&0xFF] ADD $8,R5 // p = p[8:] - MOVWZ 0(R26),R28 // tab[7][crc&0xFF] + MOVWZ (R10)(R26),R28 // tab[7][crc&0xFF] XOR R21,R28,R21 // xor done R28 MOVWZ R21,R7 // crc for next round - BC 16,0,loop // next 8 bytes + BDNZ loop ANDCC $7,R6,R8 // any leftover bytes BEQ done // none --> done MOVD R8,CTR // byte count PCALIGN $16 // align short loop short: - MOVBZ 0(R5),R8 // get v - MOVBZ R7,R9 // byte(crc) -> R8 BE vs LE? - SRD $8,R7,R14 // crc>>8 - XOR R8,R9,R8 // byte(crc)^v -> R8 - ADD $1,R5 // ptr to next v - SLD $2,R8 // convert index-> bytes - ADD R8,R4,R9 // &tab[byte(crc)^v] - MOVWZ 0(R9),R10 // tab[byte(crc)^v] - XOR R10,R14,R7 // loop crc in R7 - BC 16,0,short + MOVBZ 0(R5),R8 // get v + XOR R8,R7,R8 // byte(crc)^v -> R8 + RLDIC $2,R8,$54,R8 // rldicl r8,r8,2,22 + SRD $8,R7,R14 // crc>>8 + MOVWZ (R4)(R8),R10 + ADD $1,R5 + XOR R10,R14,R7 // loop crc in R7 + BDNZ short done: NOR R7,R7,R7 // ^crc MOVW R7,ret+40(FP) // return crc @@ -333,7 +322,7 @@ cool_top: LVX (R4+off112),V23 // next in buffer ADD $128,R4 // bump up buffer pointer - BC 16,0,cool_top // are we done? + BDNZ cool_top // are we done? first_cool_down: diff --git a/contrib/go/_std_1.22/src/hash/crc32/crc32_s390x.go b/contrib/go/_std_1.23/src/hash/crc32/crc32_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/hash/crc32/crc32_s390x.go rename to contrib/go/_std_1.23/src/hash/crc32/crc32_s390x.go diff --git a/contrib/go/_std_1.22/src/hash/crc32/crc32_s390x.s b/contrib/go/_std_1.23/src/hash/crc32/crc32_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/hash/crc32/crc32_s390x.s rename to contrib/go/_std_1.23/src/hash/crc32/crc32_s390x.s diff --git a/contrib/go/_std_1.22/src/hash/crc32/crc32_table_ppc64le.s b/contrib/go/_std_1.23/src/hash/crc32/crc32_table_ppc64le.s similarity index 99% rename from contrib/go/_std_1.22/src/hash/crc32/crc32_table_ppc64le.s rename to contrib/go/_std_1.23/src/hash/crc32/crc32_table_ppc64le.s index 453df12df4c3..eb9ab31a0412 100644 --- a/contrib/go/_std_1.22/src/hash/crc32/crc32_table_ppc64le.s +++ b/contrib/go/_std_1.23/src/hash/crc32/crc32_table_ppc64le.s @@ -1,5 +1,4 @@ -// autogenerated: do not edit! -// generated from crc32/gen_const_ppc64le.go +// Code generated by "go run gen_const_ppc64le.go"; DO NOT EDIT. #include "textflag.h" diff --git a/contrib/go/_std_1.23/src/hash/crc32/gen.go b/contrib/go/_std_1.23/src/hash/crc32/gen.go new file mode 100644 index 000000000000..fb3040a7dca6 --- /dev/null +++ b/contrib/go/_std_1.23/src/hash/crc32/gen.go @@ -0,0 +1,7 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run gen_const_ppc64le.go + +package crc32 diff --git a/contrib/go/_std_1.22/src/hash/crc32/gen_const_ppc64le.go b/contrib/go/_std_1.23/src/hash/crc32/gen_const_ppc64le.go similarity index 93% rename from contrib/go/_std_1.22/src/hash/crc32/gen_const_ppc64le.go rename to contrib/go/_std_1.23/src/hash/crc32/gen_const_ppc64le.go index 2f15a60b50e3..9e51328118df 100644 --- a/contrib/go/_std_1.22/src/hash/crc32/gen_const_ppc64le.go +++ b/contrib/go/_std_1.23/src/hash/crc32/gen_const_ppc64le.go @@ -89,10 +89,10 @@ func xnmodp(n uint, poly uint64, deg uint) (uint64, uint64) { func main() { w := new(bytes.Buffer) - fmt.Fprintf(w, "// autogenerated: do not edit!\n") - fmt.Fprintf(w, "// generated from crc32/gen_const_ppc64le.go\n") + // Standard: https://go.dev/s/generatedcode + fmt.Fprintln(w, `// Code generated by "go run gen_const_ppc64le.go"; DO NOT EDIT.`) fmt.Fprintln(w) - fmt.Fprintf(w, "#include \"textflag.h\"\n") + fmt.Fprintln(w, `#include "textflag.h"`) // These are the polynomials supported in vector now. // If adding others, include the polynomial and a name @@ -105,7 +105,7 @@ func main() { err := os.WriteFile("crc32_table_ppc64le.s", b, 0666) if err != nil { - fmt.Printf("can't write output: %s\n", err) + fmt.Fprintf(os.Stderr, "can't write output: %s\n", err) } } @@ -141,7 +141,7 @@ func genCrc32ConstTable(w *bytes.Buffer, poly uint32, polyid string) { } fmt.Fprintf(w, "GLOBL ·%sConst(SB),RODATA,$4336\n", polyid) - fmt.Fprintf(w, "\n /* Barrett constant m - (4^32)/n */\n") + fmt.Fprintf(w, "\n\t/* Barrett constant m - (4^32)/n */\n") fmt.Fprintf(w, "DATA ·%sBarConst(SB)/8,$0x%016x\n", polyid, reflect_bits(get_quotient(ref_poly, 32, 64), 33)) fmt.Fprintf(w, "DATA ·%sBarConst+8(SB)/8,$0x0000000000000000\n", polyid) fmt.Fprintf(w, "DATA ·%sBarConst+16(SB)/8,$0x%016x\n", polyid, reflect_bits((uint64(1)<<32)|ref_poly, 33)) // reflected? diff --git a/contrib/go/_std_1.22/src/hash/crc32/ya.make b/contrib/go/_std_1.23/src/hash/crc32/ya.make similarity index 97% rename from contrib/go/_std_1.22/src/hash/crc32/ya.make rename to contrib/go/_std_1.23/src/hash/crc32/ya.make index 530c001e9427..77b7a04e6f04 100644 --- a/contrib/go/_std_1.22/src/hash/crc32/ya.make +++ b/contrib/go/_std_1.23/src/hash/crc32/ya.make @@ -5,6 +5,7 @@ IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM6 crc32_arm64.go crc32_arm64.s crc32_generic.go + gen.go ) ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( @@ -12,6 +13,7 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH crc32_amd64.go crc32_amd64.s crc32_generic.go + gen.go ) ENDIF() END() diff --git a/contrib/go/_std_1.22/src/hash/crc64/crc64.go b/contrib/go/_std_1.23/src/hash/crc64/crc64.go similarity index 83% rename from contrib/go/_std_1.22/src/hash/crc64/crc64.go rename to contrib/go/_std_1.23/src/hash/crc64/crc64.go index 17ee8eb04e2b..4cdb4c7e77f7 100644 --- a/contrib/go/_std_1.22/src/hash/crc64/crc64.go +++ b/contrib/go/_std_1.23/src/hash/crc64/crc64.go @@ -10,6 +10,7 @@ package crc64 import ( "errors" "hash" + "internal/byteorder" "sync" ) @@ -113,8 +114,8 @@ const ( func (d *digest) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize) b = append(b, magic...) - b = appendUint64(b, tableSum(d.tab)) - b = appendUint64(b, d.crc) + b = byteorder.BeAppendUint64(b, tableSum(d.tab)) + b = byteorder.BeAppendUint64(b, d.crc) return b, nil } @@ -125,36 +126,13 @@ func (d *digest) UnmarshalBinary(b []byte) error { if len(b) != marshaledSize { return errors.New("hash/crc64: invalid hash state size") } - if tableSum(d.tab) != readUint64(b[4:]) { + if tableSum(d.tab) != byteorder.BeUint64(b[4:]) { return errors.New("hash/crc64: tables do not match") } - d.crc = readUint64(b[12:]) + d.crc = byteorder.BeUint64(b[12:]) return nil } -// appendUint64 is semantically the same as [binary.BigEndian.AppendUint64] -// We copied this function because we can not import "encoding/binary" here. -func appendUint64(b []byte, x uint64) []byte { - return append(b, - byte(x>>56), - byte(x>>48), - byte(x>>40), - byte(x>>32), - byte(x>>24), - byte(x>>16), - byte(x>>8), - byte(x), - ) -} - -// readUint64 is semantically the same as [binary.BigEndian.Uint64] -// We copied this function because we can not import "encoding/binary" here. -func readUint64(b []byte) uint64 { - _ = b[7] - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 -} - func update(crc uint64, tab *Table, p []byte) uint64 { buildSlicing8TablesOnce() crc = ^crc @@ -175,8 +153,7 @@ func update(crc uint64, tab *Table, p []byte) uint64 { } // Update using slicing-by-8 for len(p) > 8 { - crc ^= uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | - uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56 + crc ^= byteorder.LeUint64(p) crc = helperTable[7][crc&0xff] ^ helperTable[6][(crc>>8)&0xff] ^ helperTable[5][(crc>>16)&0xff] ^ @@ -222,7 +199,7 @@ func tableSum(t *Table) uint64 { b := a[:0] if t != nil { for _, x := range t { - b = appendUint64(b, x) + b = byteorder.BeAppendUint64(b, x) } } return Checksum(b, MakeTable(ISO)) diff --git a/contrib/go/_std_1.22/src/hash/crc64/ya.make b/contrib/go/_std_1.23/src/hash/crc64/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/hash/crc64/ya.make rename to contrib/go/_std_1.23/src/hash/crc64/ya.make diff --git a/contrib/go/_std_1.22/src/hash/fnv/fnv.go b/contrib/go/_std_1.23/src/hash/fnv/fnv.go similarity index 74% rename from contrib/go/_std_1.22/src/hash/fnv/fnv.go rename to contrib/go/_std_1.23/src/hash/fnv/fnv.go index 29439e2c1dce..bf95bb32a3c6 100644 --- a/contrib/go/_std_1.22/src/hash/fnv/fnv.go +++ b/contrib/go/_std_1.23/src/hash/fnv/fnv.go @@ -15,6 +15,7 @@ package fnv import ( "errors" "hash" + "internal/byteorder" "math/bits" ) @@ -178,36 +179,32 @@ func (s *sum128a) BlockSize() int { return 1 } func (s *sum32) Sum(in []byte) []byte { v := uint32(*s) - return append(in, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) + return byteorder.BeAppendUint32(in, v) } func (s *sum32a) Sum(in []byte) []byte { v := uint32(*s) - return append(in, byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) + return byteorder.BeAppendUint32(in, v) } func (s *sum64) Sum(in []byte) []byte { v := uint64(*s) - return append(in, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) + return byteorder.BeAppendUint64(in, v) } func (s *sum64a) Sum(in []byte) []byte { v := uint64(*s) - return append(in, byte(v>>56), byte(v>>48), byte(v>>40), byte(v>>32), byte(v>>24), byte(v>>16), byte(v>>8), byte(v)) + return byteorder.BeAppendUint64(in, v) } func (s *sum128) Sum(in []byte) []byte { - return append(in, - byte(s[0]>>56), byte(s[0]>>48), byte(s[0]>>40), byte(s[0]>>32), byte(s[0]>>24), byte(s[0]>>16), byte(s[0]>>8), byte(s[0]), - byte(s[1]>>56), byte(s[1]>>48), byte(s[1]>>40), byte(s[1]>>32), byte(s[1]>>24), byte(s[1]>>16), byte(s[1]>>8), byte(s[1]), - ) + ret := byteorder.BeAppendUint64(in, s[0]) + return byteorder.BeAppendUint64(ret, s[1]) } func (s *sum128a) Sum(in []byte) []byte { - return append(in, - byte(s[0]>>56), byte(s[0]>>48), byte(s[0]>>40), byte(s[0]>>32), byte(s[0]>>24), byte(s[0]>>16), byte(s[0]>>8), byte(s[0]), - byte(s[1]>>56), byte(s[1]>>48), byte(s[1]>>40), byte(s[1]>>32), byte(s[1]>>24), byte(s[1]>>16), byte(s[1]>>8), byte(s[1]), - ) + ret := byteorder.BeAppendUint64(in, s[0]) + return byteorder.BeAppendUint64(ret, s[1]) } const ( @@ -225,44 +222,44 @@ const ( func (s *sum32) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize32) b = append(b, magic32...) - b = appendUint32(b, uint32(*s)) + b = byteorder.BeAppendUint32(b, uint32(*s)) return b, nil } func (s *sum32a) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize32) b = append(b, magic32a...) - b = appendUint32(b, uint32(*s)) + b = byteorder.BeAppendUint32(b, uint32(*s)) return b, nil } func (s *sum64) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize64) b = append(b, magic64...) - b = appendUint64(b, uint64(*s)) + b = byteorder.BeAppendUint64(b, uint64(*s)) return b, nil } func (s *sum64a) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize64) b = append(b, magic64a...) - b = appendUint64(b, uint64(*s)) + b = byteorder.BeAppendUint64(b, uint64(*s)) return b, nil } func (s *sum128) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize128) b = append(b, magic128...) - b = appendUint64(b, s[0]) - b = appendUint64(b, s[1]) + b = byteorder.BeAppendUint64(b, s[0]) + b = byteorder.BeAppendUint64(b, s[1]) return b, nil } func (s *sum128a) MarshalBinary() ([]byte, error) { b := make([]byte, 0, marshaledSize128) b = append(b, magic128a...) - b = appendUint64(b, s[0]) - b = appendUint64(b, s[1]) + b = byteorder.BeAppendUint64(b, s[0]) + b = byteorder.BeAppendUint64(b, s[1]) return b, nil } @@ -273,7 +270,7 @@ func (s *sum32) UnmarshalBinary(b []byte) error { if len(b) != marshaledSize32 { return errors.New("hash/fnv: invalid hash state size") } - *s = sum32(readUint32(b[4:])) + *s = sum32(byteorder.BeUint32(b[4:])) return nil } @@ -284,7 +281,7 @@ func (s *sum32a) UnmarshalBinary(b []byte) error { if len(b) != marshaledSize32 { return errors.New("hash/fnv: invalid hash state size") } - *s = sum32a(readUint32(b[4:])) + *s = sum32a(byteorder.BeUint32(b[4:])) return nil } @@ -295,7 +292,7 @@ func (s *sum64) UnmarshalBinary(b []byte) error { if len(b) != marshaledSize64 { return errors.New("hash/fnv: invalid hash state size") } - *s = sum64(readUint64(b[4:])) + *s = sum64(byteorder.BeUint64(b[4:])) return nil } @@ -306,7 +303,7 @@ func (s *sum64a) UnmarshalBinary(b []byte) error { if len(b) != marshaledSize64 { return errors.New("hash/fnv: invalid hash state size") } - *s = sum64a(readUint64(b[4:])) + *s = sum64a(byteorder.BeUint64(b[4:])) return nil } @@ -317,8 +314,8 @@ func (s *sum128) UnmarshalBinary(b []byte) error { if len(b) != marshaledSize128 { return errors.New("hash/fnv: invalid hash state size") } - s[0] = readUint64(b[4:]) - s[1] = readUint64(b[12:]) + s[0] = byteorder.BeUint64(b[4:]) + s[1] = byteorder.BeUint64(b[12:]) return nil } @@ -329,48 +326,7 @@ func (s *sum128a) UnmarshalBinary(b []byte) error { if len(b) != marshaledSize128 { return errors.New("hash/fnv: invalid hash state size") } - s[0] = readUint64(b[4:]) - s[1] = readUint64(b[12:]) + s[0] = byteorder.BeUint64(b[4:]) + s[1] = byteorder.BeUint64(b[12:]) return nil } - -// readUint32 is semantically the same as [binary.BigEndian.Uint32] -// We copied this function because we can not import "encoding/binary" here. -func readUint32(b []byte) uint32 { - _ = b[3] - return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 -} - -// appendUint32 is semantically the same as [binary.BigEndian.AppendUint32] -// We copied this function because we can not import "encoding/binary" here. -func appendUint32(b []byte, x uint32) []byte { - return append(b, - byte(x>>24), - byte(x>>16), - byte(x>>8), - byte(x), - ) -} - -// appendUint64 is semantically the same as [binary.BigEndian.AppendUint64] -// We copied this function because we can not import "encoding/binary" here. -func appendUint64(b []byte, x uint64) []byte { - return append(b, - byte(x>>56), - byte(x>>48), - byte(x>>40), - byte(x>>32), - byte(x>>24), - byte(x>>16), - byte(x>>8), - byte(x), - ) -} - -// readUint64 is semantically the same as [binary.BigEndian.Uint64] -// We copied this function because we can not import "encoding/binary" here. -func readUint64(b []byte) uint64 { - _ = b[7] - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 -} diff --git a/contrib/go/_std_1.22/src/hash/fnv/ya.make b/contrib/go/_std_1.23/src/hash/fnv/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/hash/fnv/ya.make rename to contrib/go/_std_1.23/src/hash/fnv/ya.make diff --git a/contrib/go/_std_1.22/src/hash/hash.go b/contrib/go/_std_1.23/src/hash/hash.go similarity index 100% rename from contrib/go/_std_1.22/src/hash/hash.go rename to contrib/go/_std_1.23/src/hash/hash.go diff --git a/contrib/go/_std_1.22/src/hash/maphash/maphash.go b/contrib/go/_std_1.23/src/hash/maphash/maphash.go similarity index 100% rename from contrib/go/_std_1.22/src/hash/maphash/maphash.go rename to contrib/go/_std_1.23/src/hash/maphash/maphash.go diff --git a/contrib/go/_std_1.22/src/hash/maphash/maphash_purego.go b/contrib/go/_std_1.23/src/hash/maphash/maphash_purego.go similarity index 76% rename from contrib/go/_std_1.22/src/hash/maphash/maphash_purego.go rename to contrib/go/_std_1.23/src/hash/maphash/maphash_purego.go index d49a44ae6466..38ac8c4df3c6 100644 --- a/contrib/go/_std_1.22/src/hash/maphash/maphash_purego.go +++ b/contrib/go/_std_1.23/src/hash/maphash/maphash_purego.go @@ -8,6 +8,7 @@ package maphash import ( "crypto/rand" + "internal/byteorder" "math/bits" ) @@ -25,7 +26,7 @@ func rthashString(s string, state uint64) uint64 { func randUint64() uint64 { buf := make([]byte, 8) _, _ = rand.Read(buf) - return leUint64(buf) + return byteorder.LeUint64(buf) } // This is a port of wyhash implementation in runtime/hash64.go, @@ -80,25 +81,14 @@ func r3(p []byte, k uint64) uint64 { } func r4(p []byte) uint64 { - return uint64(leUint32(p)) + return uint64(byteorder.LeUint32(p)) } func r8(p []byte) uint64 { - return leUint64(p) + return byteorder.LeUint64(p) } func mix(a, b uint64) uint64 { hi, lo := bits.Mul64(a, b) return hi ^ lo } - -func leUint32(b []byte) uint32 { - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 -} - -func leUint64(b []byte) uint64 { - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | - uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 -} diff --git a/contrib/go/_std_1.22/src/hash/maphash/maphash_runtime.go b/contrib/go/_std_1.23/src/hash/maphash/maphash_runtime.go similarity index 100% rename from contrib/go/_std_1.22/src/hash/maphash/maphash_runtime.go rename to contrib/go/_std_1.23/src/hash/maphash/maphash_runtime.go diff --git a/contrib/go/_std_1.22/src/hash/maphash/ya.make b/contrib/go/_std_1.23/src/hash/maphash/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/hash/maphash/ya.make rename to contrib/go/_std_1.23/src/hash/maphash/ya.make diff --git a/contrib/go/_std_1.22/src/hash/test_cases.txt b/contrib/go/_std_1.23/src/hash/test_cases.txt similarity index 100% rename from contrib/go/_std_1.22/src/hash/test_cases.txt rename to contrib/go/_std_1.23/src/hash/test_cases.txt diff --git a/contrib/go/_std_1.22/src/hash/test_gen.awk b/contrib/go/_std_1.23/src/hash/test_gen.awk similarity index 100% rename from contrib/go/_std_1.22/src/hash/test_gen.awk rename to contrib/go/_std_1.23/src/hash/test_gen.awk diff --git a/contrib/go/_std_1.22/src/hash/ya.make b/contrib/go/_std_1.23/src/hash/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/hash/ya.make rename to contrib/go/_std_1.23/src/hash/ya.make diff --git a/contrib/go/_std_1.22/src/html/entity.go b/contrib/go/_std_1.23/src/html/entity.go similarity index 100% rename from contrib/go/_std_1.22/src/html/entity.go rename to contrib/go/_std_1.23/src/html/entity.go diff --git a/contrib/go/_std_1.22/src/html/escape.go b/contrib/go/_std_1.23/src/html/escape.go similarity index 100% rename from contrib/go/_std_1.22/src/html/escape.go rename to contrib/go/_std_1.23/src/html/escape.go diff --git a/contrib/go/_std_1.22/src/html/template/attr.go b/contrib/go/_std_1.23/src/html/template/attr.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/attr.go rename to contrib/go/_std_1.23/src/html/template/attr.go diff --git a/contrib/go/_std_1.22/src/html/template/attr_string.go b/contrib/go/_std_1.23/src/html/template/attr_string.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/attr_string.go rename to contrib/go/_std_1.23/src/html/template/attr_string.go diff --git a/contrib/go/_std_1.22/src/html/template/content.go b/contrib/go/_std_1.23/src/html/template/content.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/content.go rename to contrib/go/_std_1.23/src/html/template/content.go diff --git a/contrib/go/_std_1.22/src/html/template/context.go b/contrib/go/_std_1.23/src/html/template/context.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/context.go rename to contrib/go/_std_1.23/src/html/template/context.go diff --git a/contrib/go/_std_1.22/src/html/template/css.go b/contrib/go/_std_1.23/src/html/template/css.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/css.go rename to contrib/go/_std_1.23/src/html/template/css.go diff --git a/contrib/go/_std_1.22/src/html/template/delim_string.go b/contrib/go/_std_1.23/src/html/template/delim_string.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/delim_string.go rename to contrib/go/_std_1.23/src/html/template/delim_string.go diff --git a/contrib/go/_std_1.22/src/html/template/doc.go b/contrib/go/_std_1.23/src/html/template/doc.go similarity index 95% rename from contrib/go/_std_1.22/src/html/template/doc.go rename to contrib/go/_std_1.23/src/html/template/doc.go index 672d42ba3227..b7be04cbd0a2 100644 --- a/contrib/go/_std_1.22/src/html/template/doc.go +++ b/contrib/go/_std_1.23/src/html/template/doc.go @@ -232,11 +232,9 @@ Least Surprise Property: knows that contextual autoescaping happens should be able to look at a {{.}} and correctly infer what sanitization happens." -As a consequence of the Least Surprise Property, template actions within an -ECMAScript 6 template literal are disabled by default. -Handling string interpolation within these literals is rather complex resulting -in no clear safe way to support it. -To re-enable template actions within ECMAScript 6 template literals, use the -GODEBUG=jstmpllitinterp=1 environment variable. +Previously, ECMAScript 6 template literal were disabled by default, and could be +enabled with the GODEBUG=jstmpllitinterp=1 environment variable. Template +literals are now supported by default, and setting jstmpllitinterp has no +effect. */ package template diff --git a/contrib/go/_std_1.22/src/html/template/element_string.go b/contrib/go/_std_1.23/src/html/template/element_string.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/element_string.go rename to contrib/go/_std_1.23/src/html/template/element_string.go diff --git a/contrib/go/_std_1.22/src/html/template/error.go b/contrib/go/_std_1.23/src/html/template/error.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/error.go rename to contrib/go/_std_1.23/src/html/template/error.go diff --git a/contrib/go/_std_1.22/src/html/template/escape.go b/contrib/go/_std_1.23/src/html/template/escape.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/escape.go rename to contrib/go/_std_1.23/src/html/template/escape.go diff --git a/contrib/go/_std_1.22/src/html/template/html.go b/contrib/go/_std_1.23/src/html/template/html.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/html.go rename to contrib/go/_std_1.23/src/html/template/html.go diff --git a/contrib/go/_std_1.22/src/html/template/js.go b/contrib/go/_std_1.23/src/html/template/js.go similarity index 99% rename from contrib/go/_std_1.22/src/html/template/js.go rename to contrib/go/_std_1.23/src/html/template/js.go index d911ada26d3d..d1463dee1491 100644 --- a/contrib/go/_std_1.22/src/html/template/js.go +++ b/contrib/go/_std_1.23/src/html/template/js.go @@ -171,7 +171,7 @@ func jsValEscaper(args ...any) string { // cyclic data. This may be an unacceptable DoS risk. b, err := json.Marshal(a) if err != nil { - // While the standard JSON marshaller does not include user controlled + // While the standard JSON marshaler does not include user controlled // information in the error message, if a type has a MarshalJSON method, // the content of the error message is not guaranteed. Since we insert // the error into the template, as part of a comment, we attempt to diff --git a/contrib/go/_std_1.22/src/html/template/jsctx_string.go b/contrib/go/_std_1.23/src/html/template/jsctx_string.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/jsctx_string.go rename to contrib/go/_std_1.23/src/html/template/jsctx_string.go diff --git a/contrib/go/_std_1.22/src/html/template/state_string.go b/contrib/go/_std_1.23/src/html/template/state_string.go similarity index 100% rename from contrib/go/_std_1.22/src/html/template/state_string.go rename to contrib/go/_std_1.23/src/html/template/state_string.go diff --git a/contrib/go/_std_1.22/src/html/template/template.go b/contrib/go/_std_1.23/src/html/template/template.go similarity index 94% rename from contrib/go/_std_1.22/src/html/template/template.go rename to contrib/go/_std_1.23/src/html/template/template.go index 30b64dff0408..2440fecbf9ea 100644 --- a/contrib/go/_std_1.22/src/html/template/template.go +++ b/contrib/go/_std_1.23/src/html/template/template.go @@ -178,7 +178,7 @@ func (t *Template) DefinedTemplates() string { // definition of t itself. // // Templates can be redefined in successive calls to Parse, -// before the first use of Execute on t or any associated template. +// before the first use of [Template.Execute] on t or any associated template. // A template definition with a body containing only white space and comments // is considered empty and will not replace an existing template's body. // This allows using Parse to add new named template definitions without @@ -237,8 +237,8 @@ func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error // Clone returns a duplicate of the template, including all associated // templates. The actual representation is not copied, but the name space of -// associated templates is, so further calls to Parse in the copy will add -// templates to the copy but not to the original. Clone can be used to prepare +// associated templates is, so further calls to [Template.Parse] in the copy will add +// templates to the copy but not to the original. [Template.Clone] can be used to prepare // common templates and use them with variant definitions for other templates // by adding the variants after the clone is made. // @@ -341,7 +341,7 @@ func (t *Template) Funcs(funcMap FuncMap) *Template { } // Delims sets the action delimiters to the specified strings, to be used in -// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template +// subsequent calls to [Template.Parse], [ParseFiles], or [ParseGlob]. Nested template // definitions will inherit the settings. An empty delimiter stands for the // corresponding default: {{ or }}. // The return value is the template, so calls can be chained. @@ -358,7 +358,7 @@ func (t *Template) Lookup(name string) *Template { return t.set[name] } -// Must is a helper that wraps a call to a function returning (*Template, error) +// Must is a helper that wraps a call to a function returning ([*Template], error) // and panics if the error is non-nil. It is intended for use in variable initializations // such as // @@ -370,10 +370,10 @@ func Must(t *Template, err error) *Template { return t } -// ParseFiles creates a new Template and parses the template definitions from +// ParseFiles creates a new [Template] and parses the template definitions from // the named files. The returned template's name will have the (base) name and // (parsed) contents of the first file. There must be at least one file. -// If an error occurs, parsing stops and the returned *Template is nil. +// If an error occurs, parsing stops and the returned [*Template] is nil. // // When parsing multiple files with the same name in different directories, // the last one mentioned will be the one that results. @@ -435,12 +435,12 @@ func parseFiles(t *Template, readFile func(string) (string, []byte, error), file return t, nil } -// ParseGlob creates a new Template and parses the template definitions from +// ParseGlob creates a new [Template] and parses the template definitions from // the files identified by the pattern. The files are matched according to the // semantics of filepath.Match, and the pattern must match at least one file. // The returned template will have the (base) name and (parsed) contents of the // first file matched by the pattern. ParseGlob is equivalent to calling -// ParseFiles with the list of files matched by the pattern. +// [ParseFiles] with the list of files matched by the pattern. // // When parsing multiple files with the same name in different directories, // the last one mentioned will be the one that results. @@ -484,7 +484,7 @@ func IsTrue(val any) (truth, ok bool) { return template.IsTrue(val) } -// ParseFS is like ParseFiles or ParseGlob but reads from the file system fs +// ParseFS is like [ParseFiles] or [ParseGlob] but reads from the file system fs // instead of the host operating system's file system. // It accepts a list of glob patterns. // (Note that most file names serve as glob patterns matching only themselves.) @@ -492,7 +492,7 @@ func ParseFS(fs fs.FS, patterns ...string) (*Template, error) { return parseFS(nil, fs, patterns) } -// ParseFS is like ParseFiles or ParseGlob but reads from the file system fs +// ParseFS is like [Template.ParseFiles] or [Template.ParseGlob] but reads from the file system fs // instead of the host operating system's file system. // It accepts a list of glob patterns. // (Note that most file names serve as glob patterns matching only themselves.) diff --git a/contrib/go/_std_1.22/src/html/template/transition.go b/contrib/go/_std_1.23/src/html/template/transition.go similarity index 99% rename from contrib/go/_std_1.22/src/html/template/transition.go rename to contrib/go/_std_1.23/src/html/template/transition.go index d5a05f66da40..c430389a345f 100644 --- a/contrib/go/_std_1.22/src/html/template/transition.go +++ b/contrib/go/_std_1.23/src/html/template/transition.go @@ -414,7 +414,7 @@ func tJSDelimited(c context, s []byte) (context, int) { // If " 0 && i+7 <= len(s) && bytes.Compare(bytes.ToLower(s[i-1:i+7]), []byte(" 0 && i+7 <= len(s) && bytes.Equal(bytes.ToLower(s[i-1:i+7]), []byte("func lookup table diff --git a/contrib/go/_std_1.22/src/internal/abi/type.go b/contrib/go/_std_1.23/src/internal/abi/type.go similarity index 81% rename from contrib/go/_std_1.22/src/internal/abi/type.go rename to contrib/go/_std_1.23/src/internal/abi/type.go index 659fb7bffd32..b8eefe0da8db 100644 --- a/contrib/go/_std_1.22/src/internal/abi/type.go +++ b/contrib/go/_std_1.23/src/internal/abi/type.go @@ -24,7 +24,7 @@ type Type struct { TFlag TFlag // extra type information flags Align_ uint8 // alignment of variable with this type FieldAlign_ uint8 // alignment of struct field with this type - Kind_ uint8 // enumeration for C + Kind_ Kind // enumeration for C // function for comparing objects of this type // (ptr to object A, ptr to object B) -> ==? Equal func(unsafe.Pointer, unsafe.Pointer) bool @@ -38,7 +38,7 @@ type Type struct { // A Kind represents the specific kind of type that a Type represents. // The zero Kind is not a valid kind. -type Kind uint +type Kind uint8 const ( Invalid Kind = iota @@ -72,9 +72,9 @@ const ( const ( // TODO (khr, drchase) why aren't these in TFlag? Investigate, fix if possible. - KindDirectIface = 1 << 5 - KindGCProg = 1 << 6 // Type.gc points to GC program - KindMask = (1 << 5) - 1 + KindDirectIface Kind = 1 << 5 + KindGCProg Kind = 1 << 6 // Type.gc points to GC program + KindMask Kind = (1 << 5) - 1 ) // TFlag is used by a Type to signal what extra type information is @@ -166,12 +166,33 @@ var kindNames = []string{ UnsafePointer: "unsafe.Pointer", } -func (t *Type) Kind() Kind { return Kind(t.Kind_ & KindMask) } +// TypeOf returns the abi.Type of some value. +func TypeOf(a any) *Type { + eface := *(*EmptyInterface)(unsafe.Pointer(&a)) + // Types are either static (for compiler-created types) or + // heap-allocated but always reachable (for reflection-created + // types, held in the central map). So there is no need to + // escape types. noescape here help avoid unnecessary escape + // of v. + return (*Type)(NoEscape(unsafe.Pointer(eface.Type))) +} + +// TypeFor returns the abi.Type for a type parameter. +func TypeFor[T any]() *Type { + var v T + if t := TypeOf(v); t != nil { + return t // optimize for T being a non-interface kind + } + return TypeOf((*T)(nil)).Elem() // only for an interface kind +} + +func (t *Type) Kind() Kind { return t.Kind_ & KindMask } func (t *Type) HasName() bool { return t.TFlag&TFlagNamed != 0 } +// Pointers reports whether t contains pointers. func (t *Type) Pointers() bool { return t.PtrBytes != 0 } // IfaceIndir reports whether t is stored indirectly in an interface value. @@ -716,3 +737,67 @@ func NewName(n, tag string, exported, embedded bool) Name { return Name{Bytes: &b[0]} } + +const ( + TraceArgsLimit = 10 // print no more than 10 args/components + TraceArgsMaxDepth = 5 // no more than 5 layers of nesting + + // maxLen is a (conservative) upper bound of the byte stream length. For + // each arg/component, it has no more than 2 bytes of data (size, offset), + // and no more than one {, }, ... at each level (it cannot have both the + // data and ... unless it is the last one, just be conservative). Plus 1 + // for _endSeq. + TraceArgsMaxLen = (TraceArgsMaxDepth*3+2)*TraceArgsLimit + 1 +) + +// Populate the data. +// The data is a stream of bytes, which contains the offsets and sizes of the +// non-aggregate arguments or non-aggregate fields/elements of aggregate-typed +// arguments, along with special "operators". Specifically, +// - for each non-aggregate arg/field/element, its offset from FP (1 byte) and +// size (1 byte) +// - special operators: +// - 0xff - end of sequence +// - 0xfe - print { (at the start of an aggregate-typed argument) +// - 0xfd - print } (at the end of an aggregate-typed argument) +// - 0xfc - print ... (more args/fields/elements) +// - 0xfb - print _ (offset too large) +const ( + TraceArgsEndSeq = 0xff + TraceArgsStartAgg = 0xfe + TraceArgsEndAgg = 0xfd + TraceArgsDotdotdot = 0xfc + TraceArgsOffsetTooLarge = 0xfb + TraceArgsSpecial = 0xf0 // above this are operators, below this are ordinary offsets +) + +// MaxPtrmaskBytes is the maximum length of a GC ptrmask bitmap, +// which holds 1-bit entries describing where pointers are in a given type. +// Above this length, the GC information is recorded as a GC program, +// which can express repetition compactly. In either form, the +// information is used by the runtime to initialize the heap bitmap, +// and for large types (like 128 or more words), they are roughly the +// same speed. GC programs are never much larger and often more +// compact. (If large arrays are involved, they can be arbitrarily +// more compact.) +// +// The cutoff must be large enough that any allocation large enough to +// use a GC program is large enough that it does not share heap bitmap +// bytes with any other objects, allowing the GC program execution to +// assume an aligned start and not use atomic operations. In the current +// runtime, this means all malloc size classes larger than the cutoff must +// be multiples of four words. On 32-bit systems that's 16 bytes, and +// all size classes >= 16 bytes are 16-byte aligned, so no real constraint. +// On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed +// for size classes >= 256 bytes. On a 64-bit system, 256 bytes allocated +// is 32 pointers, the bits for which fit in 4 bytes. So MaxPtrmaskBytes +// must be >= 4. +// +// We used to use 16 because the GC programs do have some constant overhead +// to get started, and processing 128 pointers seems to be enough to +// amortize that overhead well. +// +// To make sure that the runtime's chansend can call typeBitsBulkBarrier, +// we raised the limit to 2048, so that even 32-bit systems are guaranteed to +// use bitmaps for objects up to 64 kB in size. +const MaxPtrmaskBytes = 2048 diff --git a/contrib/go/_std_1.22/src/internal/abi/ya.make b/contrib/go/_std_1.23/src/internal/abi/ya.make similarity index 90% rename from contrib/go/_std_1.22/src/internal/abi/ya.make rename to contrib/go/_std_1.23/src/internal/abi/ya.make index 62a84b9fc36e..761e3a7b9d13 100644 --- a/contrib/go/_std_1.22/src/internal/abi/ya.make +++ b/contrib/go/_std_1.23/src/internal/abi/ya.make @@ -5,8 +5,12 @@ IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM6 abi_arm64.go abi_test.s compiletype.go + escape.go funcpc.go + iface.go map.go + rangefuncconsts.go + runtime.go stack.go stub.s switch.go @@ -19,8 +23,12 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH abi_amd64.go abi_test.s compiletype.go + escape.go funcpc.go + iface.go map.go + rangefuncconsts.go + runtime.go stack.go stub.s switch.go diff --git a/contrib/go/_std_1.23/src/internal/asan/asan.go b/contrib/go/_std_1.23/src/internal/asan/asan.go new file mode 100644 index 000000000000..56814ebfb244 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/asan/asan.go @@ -0,0 +1,19 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build asan + +package asan + +import ( + "unsafe" +) + +const Enabled = true + +//go:linkname Read runtime.asanread +func Read(addr unsafe.Pointer, len uintptr) + +//go:linkname Write runtime.asanwrite +func Write(addr unsafe.Pointer, len uintptr) diff --git a/contrib/go/_std_1.23/src/internal/asan/doc.go b/contrib/go/_std_1.23/src/internal/asan/doc.go new file mode 100644 index 000000000000..21b1bc945b31 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/asan/doc.go @@ -0,0 +1,10 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package asan contains helper functions for manually instrumenting +// code for the address sanitizer. +// The runtime package intentionally exports these functions only in the +// asan build; this package exports them unconditionally but without the +// "asan" build tag they are no-ops. +package asan diff --git a/contrib/go/_std_1.23/src/internal/asan/noasan.go b/contrib/go/_std_1.23/src/internal/asan/noasan.go new file mode 100644 index 000000000000..c510d351460e --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/asan/noasan.go @@ -0,0 +1,17 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !asan + +package asan + +import ( + "unsafe" +) + +const Enabled = false + +func Read(addr unsafe.Pointer, len uintptr) {} + +func Write(addr unsafe.Pointer, len uintptr) {} diff --git a/contrib/go/_std_1.23/src/internal/asan/ya.make b/contrib/go/_std_1.23/src/internal/asan/ya.make new file mode 100644 index 000000000000..da4a42a32fde --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/asan/ya.make @@ -0,0 +1,8 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + doc.go + noasan.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/bisect/bisect.go b/contrib/go/_std_1.23/src/internal/bisect/bisect.go similarity index 97% rename from contrib/go/_std_1.22/src/internal/bisect/bisect.go rename to contrib/go/_std_1.23/src/internal/bisect/bisect.go index 3e5a6849f7e3..a79bb8000daa 100644 --- a/contrib/go/_std_1.22/src/internal/bisect/bisect.go +++ b/contrib/go/_std_1.23/src/internal/bisect/bisect.go @@ -180,7 +180,6 @@ import ( "runtime" "sync" "sync/atomic" - "unsafe" ) // New creates and returns a new Matcher implementing the given pattern. @@ -311,22 +310,7 @@ type Matcher struct { quiet bool // disables all reporting. reset if verbose is true. use case is -d=fmahash=qn enable bool // when true, list is for “enable and report” (when false, “disable and report”) list []cond // conditions; later ones win over earlier ones - dedup atomicPointerDedup -} - -// atomicPointerDedup is an atomic.Pointer[dedup], -// but we are avoiding using Go 1.19's atomic.Pointer -// until the bootstrap toolchain can be relied upon to have it. -type atomicPointerDedup struct { - p unsafe.Pointer -} - -func (p *atomicPointerDedup) Load() *dedup { - return (*dedup)(atomic.LoadPointer(&p.p)) -} - -func (p *atomicPointerDedup) CompareAndSwap(old, new *dedup) bool { - return atomic.CompareAndSwapPointer(&p.p, unsafe.Pointer(old), unsafe.Pointer(new)) + dedup atomic.Pointer[dedup] } // A cond is a single condition in the matcher. @@ -512,7 +496,7 @@ func printStack(w Writer, h uint64, stk []uintptr) error { for { f, more := frames.Next() buf = append(buf, prefix...) - buf = append(buf, f.Func.Name()...) + buf = append(buf, f.Function...) buf = append(buf, "()\n"...) buf = append(buf, prefix...) buf = append(buf, '\t') diff --git a/contrib/go/_std_1.22/src/internal/bisect/ya.make b/contrib/go/_std_1.23/src/internal/bisect/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/bisect/ya.make rename to contrib/go/_std_1.23/src/internal/bisect/ya.make diff --git a/contrib/go/_std_1.22/src/internal/buildcfg/cfg.go b/contrib/go/_std_1.23/src/internal/buildcfg/cfg.go similarity index 61% rename from contrib/go/_std_1.22/src/internal/buildcfg/cfg.go rename to contrib/go/_std_1.23/src/internal/buildcfg/cfg.go index 8b97a653d773..a16e76b30558 100644 --- a/contrib/go/_std_1.22/src/internal/buildcfg/cfg.go +++ b/contrib/go/_std_1.23/src/internal/buildcfg/cfg.go @@ -15,25 +15,26 @@ import ( "fmt" "os" "path/filepath" - "runtime" "strconv" "strings" ) var ( - GOROOT = runtime.GOROOT() // cached for efficiency - GOARCH = envOr("GOARCH", defaultGOARCH) - GOOS = envOr("GOOS", defaultGOOS) - GO386 = envOr("GO386", defaultGO386) - GOAMD64 = goamd64() - GOARM = goarm() - GOMIPS = gomips() - GOMIPS64 = gomips64() - GOPPC64 = goppc64() - GOWASM = gowasm() - ToolTags = toolTags() - GO_LDSO = defaultGO_LDSO - Version = version + GOROOT = os.Getenv("GOROOT") // cached for efficiency + GOARCH = envOr("GOARCH", defaultGOARCH) + GOOS = envOr("GOOS", defaultGOOS) + GO386 = envOr("GO386", defaultGO386) + GOAMD64 = goamd64() + GOARM = goarm() + GOARM64 = goarm64() + GOMIPS = gomips() + GOMIPS64 = gomips64() + GOPPC64 = goppc64() + GORISCV64 = goriscv64() + GOWASM = gowasm() + ToolTags = toolTags() + GO_LDSO = defaultGO_LDSO + Version = version ) // Error is one of the errors found (if any) in the build configuration. @@ -126,6 +127,107 @@ func goarm() (g goarmFeatures) { return } +type Goarm64Features struct { + Version string + // Large Systems Extension + LSE bool + // ARM v8.0 Cryptographic Extension. It includes the following features: + // * FEAT_AES, which includes the AESD and AESE instructions. + // * FEAT_PMULL, which includes the PMULL, PMULL2 instructions. + // * FEAT_SHA1, which includes the SHA1* instructions. + // * FEAT_SHA256, which includes the SHA256* instructions. + Crypto bool +} + +func (g Goarm64Features) String() string { + arm64Str := g.Version + if g.LSE { + arm64Str += ",lse" + } + if g.Crypto { + arm64Str += ",crypto" + } + return arm64Str +} + +func ParseGoarm64(v string) (g Goarm64Features, e error) { + const ( + lseOpt = ",lse" + cryptoOpt = ",crypto" + ) + + g.LSE = false + g.Crypto = false + // We allow any combination of suffixes, in any order + for { + if strings.HasSuffix(v, lseOpt) { + g.LSE = true + v = v[:len(v)-len(lseOpt)] + continue + } + + if strings.HasSuffix(v, cryptoOpt) { + g.Crypto = true + v = v[:len(v)-len(cryptoOpt)] + continue + } + + break + } + + switch v { + case "v8.0": + g.Version = v + case "v8.1", "v8.2", "v8.3", "v8.4", "v8.5", "v8.6", "v8.7", "v8.8", "v8.9", + "v9.0", "v9.1", "v9.2", "v9.3", "v9.4", "v9.5": + g.Version = v + // LSE extension is mandatory starting from 8.1 + g.LSE = true + default: + e = fmt.Errorf("invalid GOARM64: must start with v8.{0-9} or v9.{0-5} and may optionally end in %q and/or %q", + lseOpt, cryptoOpt) + g.Version = defaultGOARM64 + } + + return +} + +func goarm64() (g Goarm64Features) { + g, Error = ParseGoarm64(envOr("GOARM64", defaultGOARM64)) + return +} + +// Returns true if g supports giving ARM64 ISA +// Note that this function doesn't accept / test suffixes (like ",lse" or ",crypto") +func (g Goarm64Features) Supports(s string) bool { + // We only accept "v{8-9}.{0-9}. Everything else is malformed. + if len(s) != 4 { + return false + } + + major := s[1] + minor := s[3] + + // We only accept "v{8-9}.{0-9}. Everything else is malformed. + if major < '8' || major > '9' || + minor < '0' || minor > '9' || + s[0] != 'v' || s[2] != '.' { + return false + } + + g_major := g.Version[1] + g_minor := g.Version[3] + + if major == g_major { + return minor <= g_minor + } else if g_major == '9' { + // v9.0 diverged from v8.5. This means we should compare with g_minor increased by five. + return minor <= g_minor+5 + } else { + return false + } +} + func gomips() string { switch v := envOr("GOMIPS", defaultGOMIPS); v { case "hardfloat", "softfloat": @@ -157,6 +259,22 @@ func goppc64() int { return int(defaultGOPPC64[len("power")] - '0') } +func goriscv64() int { + switch v := envOr("GORISCV64", defaultGORISCV64); v { + case "rva20u64": + return 20 + case "rva22u64": + return 22 + } + Error = fmt.Errorf("invalid GORISCV64: must be rva20u64, rva22u64") + v := defaultGORISCV64[len("rva"):] + i := strings.IndexFunc(v, func(r rune) bool { + return r < '0' || r > '9' + }) + year, _ := strconv.Atoi(v[:i]) + return year +} + type gowasmFeatures struct { SatConv bool SignExt bool @@ -222,6 +340,8 @@ func GOGOARCH() (name, value string) { return "GOAMD64", fmt.Sprintf("v%d", GOAMD64) case "arm": return "GOARM", GOARM.String() + case "arm64": + return "GOARM64", GOARM64.String() case "mips", "mipsle": return "GOMIPS", GOMIPS case "mips64", "mips64le": @@ -250,6 +370,20 @@ func gogoarchTags() []string { list = append(list, fmt.Sprintf("%s.%d", GOARCH, i)) } return list + case "arm64": + var list []string + major := int(GOARM64.Version[1] - '0') + minor := int(GOARM64.Version[3] - '0') + for i := 0; i <= minor; i++ { + list = append(list, fmt.Sprintf("%s.v%d.%d", GOARCH, major, i)) + } + // ARM64 v9.x also includes support of v8.x+5 (i.e. v9.1 includes v8.(1+5) = v8.6). + if major == 9 { + for i := 0; i <= minor+5 && i <= 9; i++ { + list = append(list, fmt.Sprintf("%s.v%d.%d", GOARCH, 8, i)) + } + } + return list case "mips", "mipsle": return []string{GOARCH + "." + GOMIPS} case "mips64", "mips64le": @@ -260,6 +394,12 @@ func gogoarchTags() []string { list = append(list, fmt.Sprintf("%s.power%d", GOARCH, i)) } return list + case "riscv64": + list := []string{GOARCH + "." + "rva20u64"} + if GORISCV64 >= 22 { + list = append(list, GOARCH+"."+"rva22u64") + } + return list case "wasm": var list []string if GOWASM.SatConv { diff --git a/contrib/go/_std_1.22/src/internal/buildcfg/exp.go b/contrib/go/_std_1.23/src/internal/buildcfg/exp.go similarity index 97% rename from contrib/go/_std_1.22/src/internal/buildcfg/exp.go rename to contrib/go/_std_1.23/src/internal/buildcfg/exp.go index a45cfaf862ca..7c7cefba7b2a 100644 --- a/contrib/go/_std_1.22/src/internal/buildcfg/exp.go +++ b/contrib/go/_std_1.23/src/internal/buildcfg/exp.go @@ -62,19 +62,15 @@ func ParseGOEXPERIMENT(goos, goarch, goexp string) (*ExperimentFlags, error) { // always on. var regabiSupported, regabiAlwaysOn bool switch goarch { - case "amd64", "arm64", "ppc64le", "ppc64", "riscv64": + case "amd64", "arm64", "loong64", "ppc64le", "ppc64", "riscv64": regabiAlwaysOn = true regabiSupported = true - case "loong64": - regabiSupported = true } baseline := goexperiment.Flags{ RegabiWrappers: regabiSupported, RegabiArgs: regabiSupported, CoverageRedesign: true, - AllocHeaders: true, - ExecTracer2: true, } // Start with the statically enabled set of experiments. diff --git a/contrib/go/_std_1.22/src/internal/buildcfg/ya.make b/contrib/go/_std_1.23/src/internal/buildcfg/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/buildcfg/ya.make rename to contrib/go/_std_1.23/src/internal/buildcfg/ya.make diff --git a/contrib/go/_std_1.22/src/internal/buildcfg/zbootstrap.go b/contrib/go/_std_1.23/src/internal/buildcfg/zbootstrap.go similarity index 82% rename from contrib/go/_std_1.22/src/internal/buildcfg/zbootstrap.go rename to contrib/go/_std_1.23/src/internal/buildcfg/zbootstrap.go index c4a47af3ef38..8f8f7bd486b9 100644 --- a/contrib/go/_std_1.22/src/internal/buildcfg/zbootstrap.go +++ b/contrib/go/_std_1.23/src/internal/buildcfg/zbootstrap.go @@ -7,12 +7,14 @@ import "runtime" const defaultGO386 = `sse2` const defaultGOAMD64 = `v1` const defaultGOARM = `7` +const defaultGOARM64 = `v8.0` const defaultGOMIPS = `hardfloat` const defaultGOMIPS64 = `hardfloat` const defaultGOPPC64 = `power8` +const defaultGORISCV64 = `rva20u64` const defaultGOEXPERIMENT = `` const defaultGO_EXTLINK_ENABLED = `` const defaultGO_LDSO = `` -const version = `go1.22.5` +const version = `go1.23.8` const defaultGOOS = runtime.GOOS const defaultGOARCH = runtime.GOARCH diff --git a/contrib/go/_std_1.22/src/internal/bytealg/bytealg.go b/contrib/go/_std_1.23/src/internal/bytealg/bytealg.go similarity index 95% rename from contrib/go/_std_1.22/src/internal/bytealg/bytealg.go rename to contrib/go/_std_1.23/src/internal/bytealg/bytealg.go index 1103891eeefe..6b79a2e1fabb 100644 --- a/contrib/go/_std_1.22/src/internal/bytealg/bytealg.go +++ b/contrib/go/_std_1.23/src/internal/bytealg/bytealg.go @@ -111,7 +111,8 @@ func LastIndexRabinKarp[T string | []byte](s, sep T) int { return -1 } -// MakeNoZero makes a slice of length and capacity n without zeroing the bytes. +// MakeNoZero makes a slice of length n and capacity of at least n Bytes +// without zeroing the bytes (including the bytes between len and cap). // It is the caller's responsibility to ensure uninitialized bytes // do not leak to the end user. func MakeNoZero(n int) []byte diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_386.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_386.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_386.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_386.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_amd64.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_amd64.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_amd64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_arm.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_arm.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_arm.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_arm64.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_arm64.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_arm64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_generic.go b/contrib/go/_std_1.23/src/internal/bytealg/compare_generic.go similarity index 68% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_generic.go rename to contrib/go/_std_1.23/src/internal/bytealg/compare_generic.go index b04e2750611b..614ae8b8cf22 100644 --- a/contrib/go/_std_1.22/src/internal/bytealg/compare_generic.go +++ b/contrib/go/_std_1.23/src/internal/bytealg/compare_generic.go @@ -35,6 +35,22 @@ samebytes: return 0 } +func CompareString(a, b string) int { + return runtime_cmpstring(a, b) +} + +// runtime.cmpstring calls are emitted by the compiler. +// +// runtime.cmpstring should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/zhaochuninhefei/gmgo +// - github.com/bytedance/gopkg +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname runtime_cmpstring runtime.cmpstring func runtime_cmpstring(a, b string) int { l := len(a) diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_loong64.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_loong64.s similarity index 82% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_loong64.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_loong64.s index 311449ab1897..df72a1122bc7 100644 --- a/contrib/go/_std_1.22/src/internal/bytealg/compare_loong64.s +++ b/contrib/go/_std_1.23/src/internal/bytealg/compare_loong64.s @@ -6,13 +6,6 @@ #include "textflag.h" TEXT ·Compare(SB),NOSPLIT,$0-56 -#ifndef GOEXPERIMENT_regabiargs - MOVV a_base+0(FP), R4 - MOVV a_len+8(FP), R5 - MOVV b_base+24(FP), R6 - MOVV b_len+32(FP), R7 - MOVV $ret+48(FP), R13 -#else // R4 = a_base // R5 = a_len // R6 = a_cap (unused) @@ -21,17 +14,9 @@ TEXT ·Compare(SB),NOSPLIT,$0-56 // R9 = b_cap (unused) MOVV R7, R6 MOVV R8, R7 -#endif JMP cmpbody<>(SB) TEXT runtime·cmpstring(SB),NOSPLIT,$0-40 -#ifndef GOEXPERIMENT_regabiargs - MOVV a_base+0(FP), R4 - MOVV b_base+16(FP), R6 - MOVV a_len+8(FP), R5 - MOVV b_len+24(FP), R7 - MOVV $ret+32(FP), R13 -#endif // R4 = a_base // R5 = a_len // R6 = b_base @@ -100,7 +85,4 @@ samebytes: SUBV R9, R8, R4 ret: -#ifndef GOEXPERIMENT_regabiargs - MOVV R4, (R13) -#endif RET diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_mips64x.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_mips64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_mips64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_mipsx.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_mipsx.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_mipsx.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_native.go b/contrib/go/_std_1.23/src/internal/bytealg/compare_native.go similarity index 88% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_native.go rename to contrib/go/_std_1.23/src/internal/bytealg/compare_native.go index 34964e281c63..983ab069db40 100644 --- a/contrib/go/_std_1.22/src/internal/bytealg/compare_native.go +++ b/contrib/go/_std_1.23/src/internal/bytealg/compare_native.go @@ -11,6 +11,10 @@ import _ "unsafe" // For go:linkname //go:noescape func Compare(a, b []byte) int +func CompareString(a, b string) int { + return abigen_runtime_cmpstring(a, b) +} + // The declaration below generates ABI wrappers for functions // implemented in assembly in this package but declared in another // package. diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_ppc64x.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_ppc64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_ppc64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_riscv64.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_riscv64.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_riscv64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_s390x.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_s390x.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_s390x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/compare_wasm.s b/contrib/go/_std_1.23/src/internal/bytealg/compare_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/compare_wasm.s rename to contrib/go/_std_1.23/src/internal/bytealg/compare_wasm.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_amd64.s b/contrib/go/_std_1.23/src/internal/bytealg/count_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_amd64.s rename to contrib/go/_std_1.23/src/internal/bytealg/count_amd64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_arm.s b/contrib/go/_std_1.23/src/internal/bytealg/count_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_arm.s rename to contrib/go/_std_1.23/src/internal/bytealg/count_arm.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_arm64.s b/contrib/go/_std_1.23/src/internal/bytealg/count_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_arm64.s rename to contrib/go/_std_1.23/src/internal/bytealg/count_arm64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_generic.go b/contrib/go/_std_1.23/src/internal/bytealg/count_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_generic.go rename to contrib/go/_std_1.23/src/internal/bytealg/count_generic.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_native.go b/contrib/go/_std_1.23/src/internal/bytealg/count_native.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_native.go rename to contrib/go/_std_1.23/src/internal/bytealg/count_native.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_ppc64x.s b/contrib/go/_std_1.23/src/internal/bytealg/count_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_ppc64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/count_ppc64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_riscv64.s b/contrib/go/_std_1.23/src/internal/bytealg/count_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_riscv64.s rename to contrib/go/_std_1.23/src/internal/bytealg/count_riscv64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/count_s390x.s b/contrib/go/_std_1.23/src/internal/bytealg/count_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/count_s390x.s rename to contrib/go/_std_1.23/src/internal/bytealg/count_s390x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_386.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_386.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_386.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_386.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_amd64.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_amd64.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_amd64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_arm.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_arm.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_arm.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_arm64.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_arm64.s similarity index 97% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_arm64.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_arm64.s index d3aabba5871e..4db951547443 100644 --- a/contrib/go/_std_1.22/src/internal/bytealg/equal_arm64.s +++ b/contrib/go/_std_1.23/src/internal/bytealg/equal_arm64.s @@ -9,6 +9,9 @@ TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25 // short path to handle 0-byte case CBZ R2, equal + // short path to handle equal pointers + CMP R0, R1 + BEQ equal B memeqbody<>(SB) equal: MOVD $1, R0 diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_generic.go b/contrib/go/_std_1.23/src/internal/bytealg/equal_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_generic.go rename to contrib/go/_std_1.23/src/internal/bytealg/equal_generic.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_loong64.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_loong64.s similarity index 64% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_loong64.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_loong64.s index a3ad5c1b35b6..830b09bd2cf3 100644 --- a/contrib/go/_std_1.22/src/internal/bytealg/equal_loong64.s +++ b/contrib/go/_std_1.23/src/internal/bytealg/equal_loong64.s @@ -9,20 +9,12 @@ // memequal(a, b unsafe.Pointer, size uintptr) bool TEXT runtime·memequal(SB),NOSPLIT|NOFRAME,$0-25 -#ifndef GOEXPERIMENT_regabiargs - MOVV a+0(FP), R4 - MOVV b+8(FP), R5 - MOVV size+16(FP), R6 -#endif BEQ R4, R5, eq ADDV R4, R6, R7 PCALIGN $16 loop: BNE R4, R7, test MOVV $1, R4 -#ifndef GOEXPERIMENT_regabiargs - MOVB R4, ret+24(FP) -#endif RET test: MOVBU (R4), R9 @@ -32,23 +24,13 @@ test: BEQ R9, R10, loop MOVB R0, R4 -#ifndef GOEXPERIMENT_regabiargs - MOVB R0, ret+24(FP) -#endif RET eq: MOVV $1, R4 -#ifndef GOEXPERIMENT_regabiargs - MOVB R4, ret+24(FP) -#endif RET // memequal_varlen(a, b unsafe.Pointer) bool TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17 -#ifndef GOEXPERIMENT_regabiargs - MOVV a+0(FP), R4 - MOVV b+8(FP), R5 -#endif BEQ R4, R5, eq MOVV 8(REGCTXT), R6 // compiler stores size at offset 8 in the closure MOVV R4, 8(R3) @@ -56,13 +38,7 @@ TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17 MOVV R6, 24(R3) JAL runtime·memequal(SB) MOVBU 32(R3), R4 -#ifndef GOEXPERIMENT_regabiargs - MOVB R4, ret+16(FP) -#endif RET eq: MOVV $1, R4 -#ifndef GOEXPERIMENT_regabiargs - MOVB R4, ret+16(FP) -#endif RET diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_mips64x.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_mips64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_mips64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_mipsx.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_mipsx.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_mipsx.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_native.go b/contrib/go/_std_1.23/src/internal/bytealg/equal_native.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_native.go rename to contrib/go/_std_1.23/src/internal/bytealg/equal_native.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_ppc64x.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_ppc64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_ppc64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_riscv64.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_riscv64.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_riscv64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_s390x.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_s390x.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_s390x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/equal_wasm.s b/contrib/go/_std_1.23/src/internal/bytealg/equal_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/equal_wasm.s rename to contrib/go/_std_1.23/src/internal/bytealg/equal_wasm.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_amd64.go b/contrib/go/_std_1.23/src/internal/bytealg/index_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_amd64.go rename to contrib/go/_std_1.23/src/internal/bytealg/index_amd64.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_amd64.s b/contrib/go/_std_1.23/src/internal/bytealg/index_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_amd64.s rename to contrib/go/_std_1.23/src/internal/bytealg/index_amd64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_arm64.go b/contrib/go/_std_1.23/src/internal/bytealg/index_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_arm64.go rename to contrib/go/_std_1.23/src/internal/bytealg/index_arm64.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_arm64.s b/contrib/go/_std_1.23/src/internal/bytealg/index_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_arm64.s rename to contrib/go/_std_1.23/src/internal/bytealg/index_arm64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_generic.go b/contrib/go/_std_1.23/src/internal/bytealg/index_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_generic.go rename to contrib/go/_std_1.23/src/internal/bytealg/index_generic.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_native.go b/contrib/go/_std_1.23/src/internal/bytealg/index_native.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_native.go rename to contrib/go/_std_1.23/src/internal/bytealg/index_native.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_ppc64x.go b/contrib/go/_std_1.23/src/internal/bytealg/index_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_ppc64x.go rename to contrib/go/_std_1.23/src/internal/bytealg/index_ppc64x.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_ppc64x.s b/contrib/go/_std_1.23/src/internal/bytealg/index_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_ppc64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/index_ppc64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_s390x.go b/contrib/go/_std_1.23/src/internal/bytealg/index_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_s390x.go rename to contrib/go/_std_1.23/src/internal/bytealg/index_s390x.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/index_s390x.s b/contrib/go/_std_1.23/src/internal/bytealg/index_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/index_s390x.s rename to contrib/go/_std_1.23/src/internal/bytealg/index_s390x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_386.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_386.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_386.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_386.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_amd64.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_amd64.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_amd64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_arm.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_arm.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_arm.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_arm64.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_arm64.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_arm64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_generic.go b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_generic.go rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_generic.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_loong64.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_loong64.s similarity index 65% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_loong64.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_loong64.s index 03e066097312..c9591b3cdaa5 100644 --- a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_loong64.s +++ b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_loong64.s @@ -6,11 +6,6 @@ #include "textflag.h" TEXT ·IndexByte(SB),NOSPLIT,$0-40 -#ifndef GOEXPERIMENT_regabiargs - MOVV b_base+0(FP), R4 - MOVV b_len+8(FP), R5 - MOVBU c+24(FP), R7 // byte to find -#endif // R4 = b_base // R5 = b_len // R6 = b_cap (unused) @@ -28,24 +23,13 @@ loop: BNE R7, R8, loop SUBV R6, R4 // remove base -#ifndef GOEXPERIMENT_regabiargs - MOVV R4, ret+32(FP) -#endif RET notfound: MOVV $-1, R4 -#ifndef GOEXPERIMENT_regabiargs - MOVV R4, ret+32(FP) -#endif RET TEXT ·IndexByteString(SB),NOSPLIT,$0-32 -#ifndef GOEXPERIMENT_regabiargs - MOVV s_base+0(FP), R4 - MOVV s_len+8(FP), R5 - MOVBU c+16(FP), R6 // byte to find -#endif // R4 = s_base // R5 = s_len // R6 = byte to find @@ -61,14 +45,8 @@ loop: BNE R6, R8, loop SUBV R7, R4 // remove base -#ifndef GOEXPERIMENT_regabiargs - MOVV R4, ret+24(FP) -#endif RET notfound: MOVV $-1, R4 -#ifndef GOEXPERIMENT_regabiargs - MOVV R4, ret+24(FP) -#endif RET diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_mips64x.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_mips64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_mips64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_mipsx.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_mipsx.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_mipsx.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_native.go b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_native.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_native.go rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_native.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_ppc64x.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_ppc64x.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_ppc64x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_riscv64.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_riscv64.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_riscv64.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_s390x.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_s390x.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_s390x.s diff --git a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_wasm.s b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_wasm.s similarity index 98% rename from contrib/go/_std_1.22/src/internal/bytealg/indexbyte_wasm.s rename to contrib/go/_std_1.23/src/internal/bytealg/indexbyte_wasm.s index ef4bd93070f4..d22e90448d43 100644 --- a/contrib/go/_std_1.22/src/internal/bytealg/indexbyte_wasm.s +++ b/contrib/go/_std_1.23/src/internal/bytealg/indexbyte_wasm.s @@ -12,7 +12,7 @@ TEXT ·IndexByte(SB), NOSPLIT, $0-40 I64Load b_len+8(FP) I32WrapI64 Call memchr<>(SB) - I64ExtendI32S + I64ExtendI32U Set R0 Get SP @@ -35,7 +35,7 @@ TEXT ·IndexByteString(SB), NOSPLIT, $0-32 I64Load s_len+8(FP) I32WrapI64 Call memchr<>(SB) - I64ExtendI32S + I64ExtendI32U Set R0 I64Const $-1 diff --git a/contrib/go/_std_1.22/src/internal/bytealg/lastindexbyte_generic.go b/contrib/go/_std_1.23/src/internal/bytealg/lastindexbyte_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/lastindexbyte_generic.go rename to contrib/go/_std_1.23/src/internal/bytealg/lastindexbyte_generic.go diff --git a/contrib/go/_std_1.22/src/internal/bytealg/ya.make b/contrib/go/_std_1.23/src/internal/bytealg/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/bytealg/ya.make rename to contrib/go/_std_1.23/src/internal/bytealg/ya.make diff --git a/contrib/go/_std_1.23/src/internal/byteorder/byteorder.go b/contrib/go/_std_1.23/src/internal/byteorder/byteorder.go new file mode 100644 index 000000000000..ba37856ccd97 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/byteorder/byteorder.go @@ -0,0 +1,149 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package byteorder provides functions for decoding and encoding +// little and big endian integer types from/to byte slices. +package byteorder + +func LeUint16(b []byte) uint16 { + _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 + return uint16(b[0]) | uint16(b[1])<<8 +} + +func LePutUint16(b []byte, v uint16) { + _ = b[1] // early bounds check to guarantee safety of writes below + b[0] = byte(v) + b[1] = byte(v >> 8) +} + +func LeAppendUint16(b []byte, v uint16) []byte { + return append(b, + byte(v), + byte(v>>8), + ) +} + +func LeUint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func LePutUint32(b []byte, v uint32) { + _ = b[3] // early bounds check to guarantee safety of writes below + b[0] = byte(v) + b[1] = byte(v >> 8) + b[2] = byte(v >> 16) + b[3] = byte(v >> 24) +} + +func LeAppendUint32(b []byte, v uint32) []byte { + return append(b, + byte(v), + byte(v>>8), + byte(v>>16), + byte(v>>24), + ) +} + +func LeUint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +func LePutUint64(b []byte, v uint64) { + _ = b[7] // early bounds check to guarantee safety of writes below + b[0] = byte(v) + b[1] = byte(v >> 8) + b[2] = byte(v >> 16) + b[3] = byte(v >> 24) + b[4] = byte(v >> 32) + b[5] = byte(v >> 40) + b[6] = byte(v >> 48) + b[7] = byte(v >> 56) +} + +func LeAppendUint64(b []byte, v uint64) []byte { + return append(b, + byte(v), + byte(v>>8), + byte(v>>16), + byte(v>>24), + byte(v>>32), + byte(v>>40), + byte(v>>48), + byte(v>>56), + ) +} + +func BeUint16(b []byte) uint16 { + _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 + return uint16(b[1]) | uint16(b[0])<<8 +} + +func BePutUint16(b []byte, v uint16) { + _ = b[1] // early bounds check to guarantee safety of writes below + b[0] = byte(v >> 8) + b[1] = byte(v) +} + +func BeAppendUint16(b []byte, v uint16) []byte { + return append(b, + byte(v>>8), + byte(v), + ) +} + +func BeUint32(b []byte) uint32 { + _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 + return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 +} + +func BePutUint32(b []byte, v uint32) { + _ = b[3] // early bounds check to guarantee safety of writes below + b[0] = byte(v >> 24) + b[1] = byte(v >> 16) + b[2] = byte(v >> 8) + b[3] = byte(v) +} + +func BeAppendUint32(b []byte, v uint32) []byte { + return append(b, + byte(v>>24), + byte(v>>16), + byte(v>>8), + byte(v), + ) +} + +func BeUint64(b []byte) uint64 { + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 +} + +func BePutUint64(b []byte, v uint64) { + _ = b[7] // early bounds check to guarantee safety of writes below + b[0] = byte(v >> 56) + b[1] = byte(v >> 48) + b[2] = byte(v >> 40) + b[3] = byte(v >> 32) + b[4] = byte(v >> 24) + b[5] = byte(v >> 16) + b[6] = byte(v >> 8) + b[7] = byte(v) +} + +func BeAppendUint64(b []byte, v uint64) []byte { + return append(b, + byte(v>>56), + byte(v>>48), + byte(v>>40), + byte(v>>32), + byte(v>>24), + byte(v>>16), + byte(v>>8), + byte(v), + ) +} diff --git a/contrib/go/_std_1.23/src/internal/byteorder/ya.make b/contrib/go/_std_1.23/src/internal/byteorder/ya.make new file mode 100644 index 000000000000..c39304ec1893 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/byteorder/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + byteorder.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/chacha8rand/chacha8.go b/contrib/go/_std_1.23/src/internal/chacha8rand/chacha8.go similarity index 72% rename from contrib/go/_std_1.22/src/internal/chacha8rand/chacha8.go rename to contrib/go/_std_1.23/src/internal/chacha8rand/chacha8.go index ce55c07d058a..8f1b4e5315c9 100644 --- a/contrib/go/_std_1.22/src/internal/chacha8rand/chacha8.go +++ b/contrib/go/_std_1.23/src/internal/chacha8rand/chacha8.go @@ -4,9 +4,11 @@ // Package chacha8rand implements a pseudorandom generator // based on ChaCha8. It is used by both runtime and math/rand/v2 -// and must have no dependencies. +// and must have minimal dependencies. package chacha8rand +import "internal/byteorder" + const ( ctrInc = 4 // increment counter by 4 between block calls ctrMax = 16 // reseed when counter reaches 16 @@ -37,6 +39,7 @@ type State struct { // // Next is //go:nosplit to allow its use in the runtime // with per-m data without holding the per-m lock. +// //go:nosplit func (s *State) Next() (uint64, bool) { i := s.i @@ -50,10 +53,10 @@ func (s *State) Next() (uint64, bool) { // Init seeds the State with the given seed value. func (s *State) Init(seed [32]byte) { s.Init64([4]uint64{ - leUint64(seed[0*8:]), - leUint64(seed[1*8:]), - leUint64(seed[2*8:]), - leUint64(seed[3*8:]), + byteorder.LeUint64(seed[0*8:]), + byteorder.LeUint64(seed[1*8:]), + byteorder.LeUint64(seed[2*8:]), + byteorder.LeUint64(seed[3*8:]), }) } @@ -121,9 +124,9 @@ func Marshal(s *State) []byte { data := make([]byte, 6*8) copy(data, "chacha8:") used := (s.c/ctrInc)*chunk + s.i - bePutUint64(data[1*8:], uint64(used)) + byteorder.BePutUint64(data[1*8:], uint64(used)) for i, seed := range s.seed { - lePutUint64(data[(2+i)*8:], seed) + byteorder.LePutUint64(data[(2+i)*8:], seed) } return data } @@ -139,12 +142,12 @@ func Unmarshal(s *State, data []byte) error { if len(data) != 6*8 || string(data[:8]) != "chacha8:" { return new(errUnmarshalChaCha8) } - used := beUint64(data[1*8:]) + used := byteorder.BeUint64(data[1*8:]) if used > (ctrMax/ctrInc)*chunk-reseed { return new(errUnmarshalChaCha8) } for i := range s.seed { - s.seed[i] = leUint64(data[(2+i)*8:]) + s.seed[i] = byteorder.LeUint64(data[(2+i)*8:]) } s.c = ctrInc * (uint32(used) / chunk) block(&s.seed, &s.buf, s.c) @@ -155,43 +158,3 @@ func Unmarshal(s *State, data []byte) error { } return nil } - -// binary.bigEndian.Uint64, copied to avoid dependency -func beUint64(b []byte) uint64 { - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 -} - -// binary.bigEndian.PutUint64, copied to avoid dependency -func bePutUint64(b []byte, v uint64) { - _ = b[7] // early bounds check to guarantee safety of writes below - b[0] = byte(v >> 56) - b[1] = byte(v >> 48) - b[2] = byte(v >> 40) - b[3] = byte(v >> 32) - b[4] = byte(v >> 24) - b[5] = byte(v >> 16) - b[6] = byte(v >> 8) - b[7] = byte(v) -} - -// binary.littleEndian.Uint64, copied to avoid dependency -func leUint64(b []byte) uint64 { - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | - uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 -} - -// binary.littleEndian.PutUint64, copied to avoid dependency -func lePutUint64(b []byte, v uint64) { - _ = b[7] // early bounds check to guarantee safety of writes below - b[0] = byte(v) - b[1] = byte(v >> 8) - b[2] = byte(v >> 16) - b[3] = byte(v >> 24) - b[4] = byte(v >> 32) - b[5] = byte(v >> 40) - b[6] = byte(v >> 48) - b[7] = byte(v >> 56) -} diff --git a/contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_amd64.s b/contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_amd64.s rename to contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_amd64.s diff --git a/contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_arm64.s b/contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_arm64.s rename to contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_arm64.s diff --git a/contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_generic.go b/contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_generic.go rename to contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_generic.go diff --git a/contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_stub.s b/contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_stub.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/chacha8rand/chacha8_stub.s rename to contrib/go/_std_1.23/src/internal/chacha8rand/chacha8_stub.s diff --git a/contrib/go/_std_1.22/src/internal/chacha8rand/ya.make b/contrib/go/_std_1.23/src/internal/chacha8rand/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/chacha8rand/ya.make rename to contrib/go/_std_1.23/src/internal/chacha8rand/ya.make diff --git a/contrib/go/_std_1.23/src/internal/concurrent/hashtriemap.go b/contrib/go/_std_1.23/src/internal/concurrent/hashtriemap.go new file mode 100644 index 000000000000..4f7e730d4fca --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/concurrent/hashtriemap.go @@ -0,0 +1,408 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package concurrent + +import ( + "internal/abi" + "internal/goarch" + "math/rand/v2" + "sync" + "sync/atomic" + "unsafe" +) + +// HashTrieMap is an implementation of a concurrent hash-trie. The implementation +// is designed around frequent loads, but offers decent performance for stores +// and deletes as well, especially if the map is larger. It's primary use-case is +// the unique package, but can be used elsewhere as well. +type HashTrieMap[K, V comparable] struct { + root *indirect[K, V] + keyHash hashFunc + keyEqual equalFunc + valEqual equalFunc + seed uintptr +} + +// NewHashTrieMap creates a new HashTrieMap for the provided key and value. +func NewHashTrieMap[K, V comparable]() *HashTrieMap[K, V] { + var m map[K]V + mapType := abi.TypeOf(m).MapType() + ht := &HashTrieMap[K, V]{ + root: newIndirectNode[K, V](nil), + keyHash: mapType.Hasher, + keyEqual: mapType.Key.Equal, + valEqual: mapType.Elem.Equal, + seed: uintptr(rand.Uint64()), + } + return ht +} + +type hashFunc func(unsafe.Pointer, uintptr) uintptr +type equalFunc func(unsafe.Pointer, unsafe.Pointer) bool + +// Load returns the value stored in the map for a key, or nil if no +// value is present. +// The ok result indicates whether value was found in the map. +func (ht *HashTrieMap[K, V]) Load(key K) (value V, ok bool) { + hash := ht.keyHash(abi.NoEscape(unsafe.Pointer(&key)), ht.seed) + + i := ht.root + hashShift := 8 * goarch.PtrSize + for hashShift != 0 { + hashShift -= nChildrenLog2 + + n := i.children[(hash>>hashShift)&nChildrenMask].Load() + if n == nil { + return *new(V), false + } + if n.isEntry { + return n.entry().lookup(key, ht.keyEqual) + } + i = n.indirect() + } + panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") +} + +// LoadOrStore returns the existing value for the key if present. +// Otherwise, it stores and returns the given value. +// The loaded result is true if the value was loaded, false if stored. +func (ht *HashTrieMap[K, V]) LoadOrStore(key K, value V) (result V, loaded bool) { + hash := ht.keyHash(abi.NoEscape(unsafe.Pointer(&key)), ht.seed) + var i *indirect[K, V] + var hashShift uint + var slot *atomic.Pointer[node[K, V]] + var n *node[K, V] + for { + // Find the key or a candidate location for insertion. + i = ht.root + hashShift = 8 * goarch.PtrSize + haveInsertPoint := false + for hashShift != 0 { + hashShift -= nChildrenLog2 + + slot = &i.children[(hash>>hashShift)&nChildrenMask] + n = slot.Load() + if n == nil { + // We found a nil slot which is a candidate for insertion. + haveInsertPoint = true + break + } + if n.isEntry { + // We found an existing entry, which is as far as we can go. + // If it stays this way, we'll have to replace it with an + // indirect node. + if v, ok := n.entry().lookup(key, ht.keyEqual); ok { + return v, true + } + haveInsertPoint = true + break + } + i = n.indirect() + } + if !haveInsertPoint { + panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") + } + + // Grab the lock and double-check what we saw. + i.mu.Lock() + n = slot.Load() + if (n == nil || n.isEntry) && !i.dead.Load() { + // What we saw is still true, so we can continue with the insert. + break + } + // We have to start over. + i.mu.Unlock() + } + // N.B. This lock is held from when we broke out of the outer loop above. + // We specifically break this out so that we can use defer here safely. + // One option is to break this out into a new function instead, but + // there's so much local iteration state used below that this turns out + // to be cleaner. + defer i.mu.Unlock() + + var oldEntry *entry[K, V] + if n != nil { + oldEntry = n.entry() + if v, ok := oldEntry.lookup(key, ht.keyEqual); ok { + // Easy case: by loading again, it turns out exactly what we wanted is here! + return v, true + } + } + newEntry := newEntryNode(key, value) + if oldEntry == nil { + // Easy case: create a new entry and store it. + slot.Store(&newEntry.node) + } else { + // We possibly need to expand the entry already there into one or more new nodes. + // + // Publish the node last, which will make both oldEntry and newEntry visible. We + // don't want readers to be able to observe that oldEntry isn't in the tree. + slot.Store(ht.expand(oldEntry, newEntry, hash, hashShift, i)) + } + return value, false +} + +// expand takes oldEntry and newEntry whose hashes conflict from bit 64 down to hashShift and +// produces a subtree of indirect nodes to hold the two new entries. +func (ht *HashTrieMap[K, V]) expand(oldEntry, newEntry *entry[K, V], newHash uintptr, hashShift uint, parent *indirect[K, V]) *node[K, V] { + // Check for a hash collision. + oldHash := ht.keyHash(unsafe.Pointer(&oldEntry.key), ht.seed) + if oldHash == newHash { + // Store the old entry in the new entry's overflow list, then store + // the new entry. + newEntry.overflow.Store(oldEntry) + return &newEntry.node + } + // We have to add an indirect node. Worse still, we may need to add more than one. + newIndirect := newIndirectNode(parent) + top := newIndirect + for { + if hashShift == 0 { + panic("internal/concurrent.HashMapTrie: ran out of hash bits while inserting") + } + hashShift -= nChildrenLog2 // hashShift is for the level parent is at. We need to go deeper. + oi := (oldHash >> hashShift) & nChildrenMask + ni := (newHash >> hashShift) & nChildrenMask + if oi != ni { + newIndirect.children[oi].Store(&oldEntry.node) + newIndirect.children[ni].Store(&newEntry.node) + break + } + nextIndirect := newIndirectNode(newIndirect) + newIndirect.children[oi].Store(&nextIndirect.node) + newIndirect = nextIndirect + } + return &top.node +} + +// CompareAndDelete deletes the entry for key if its value is equal to old. +// +// If there is no current value for key in the map, CompareAndDelete returns false +// (even if the old value is the nil interface value). +func (ht *HashTrieMap[K, V]) CompareAndDelete(key K, old V) (deleted bool) { + hash := ht.keyHash(abi.NoEscape(unsafe.Pointer(&key)), ht.seed) + var i *indirect[K, V] + var hashShift uint + var slot *atomic.Pointer[node[K, V]] + var n *node[K, V] + for { + // Find the key or return when there's nothing to delete. + i = ht.root + hashShift = 8 * goarch.PtrSize + found := false + for hashShift != 0 { + hashShift -= nChildrenLog2 + + slot = &i.children[(hash>>hashShift)&nChildrenMask] + n = slot.Load() + if n == nil { + // Nothing to delete. Give up. + return + } + if n.isEntry { + // We found an entry. Check if it matches. + if _, ok := n.entry().lookup(key, ht.keyEqual); !ok { + // No match, nothing to delete. + return + } + // We've got something to delete. + found = true + break + } + i = n.indirect() + } + if !found { + panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") + } + + // Grab the lock and double-check what we saw. + i.mu.Lock() + n = slot.Load() + if !i.dead.Load() { + if n == nil { + // Valid node that doesn't contain what we need. Nothing to delete. + i.mu.Unlock() + return + } + if n.isEntry { + // What we saw is still true, so we can continue with the delete. + break + } + } + // We have to start over. + i.mu.Unlock() + } + // Try to delete the entry. + e, deleted := n.entry().compareAndDelete(key, old, ht.keyEqual, ht.valEqual) + if !deleted { + // Nothing was actually deleted, which means the node is no longer there. + i.mu.Unlock() + return false + } + if e != nil { + // We didn't actually delete the whole entry, just one entry in the chain. + // Nothing else to do, since the parent is definitely not empty. + slot.Store(&e.node) + i.mu.Unlock() + return true + } + // Delete the entry. + slot.Store(nil) + + // Check if the node is now empty (and isn't the root), and delete it if able. + for i.parent != nil && i.empty() { + if hashShift == 8*goarch.PtrSize { + panic("internal/concurrent.HashMapTrie: ran out of hash bits while iterating") + } + hashShift += nChildrenLog2 + + // Delete the current node in the parent. + parent := i.parent + parent.mu.Lock() + i.dead.Store(true) + parent.children[(hash>>hashShift)&nChildrenMask].Store(nil) + i.mu.Unlock() + i = parent + } + i.mu.Unlock() + return true +} + +// All returns an iter.Seq2 that produces all key-value pairs in the map. +// The enumeration does not represent any consistent snapshot of the map, +// but is guaranteed to visit each unique key-value pair only once. It is +// safe to operate on the tree during iteration. No particular enumeration +// order is guaranteed. +func (ht *HashTrieMap[K, V]) All() func(yield func(K, V) bool) { + return func(yield func(key K, value V) bool) { + ht.iter(ht.root, yield) + } +} + +func (ht *HashTrieMap[K, V]) iter(i *indirect[K, V], yield func(key K, value V) bool) bool { + for j := range i.children { + n := i.children[j].Load() + if n == nil { + continue + } + if !n.isEntry { + if !ht.iter(n.indirect(), yield) { + return false + } + continue + } + e := n.entry() + for e != nil { + if !yield(e.key, e.value) { + return false + } + e = e.overflow.Load() + } + } + return true +} + +const ( + // 16 children. This seems to be the sweet spot for + // load performance: any smaller and we lose out on + // 50% or more in CPU performance. Any larger and the + // returns are minuscule (~1% improvement for 32 children). + nChildrenLog2 = 4 + nChildren = 1 << nChildrenLog2 + nChildrenMask = nChildren - 1 +) + +// indirect is an internal node in the hash-trie. +type indirect[K, V comparable] struct { + node[K, V] + dead atomic.Bool + mu sync.Mutex // Protects mutation to children and any children that are entry nodes. + parent *indirect[K, V] + children [nChildren]atomic.Pointer[node[K, V]] +} + +func newIndirectNode[K, V comparable](parent *indirect[K, V]) *indirect[K, V] { + return &indirect[K, V]{node: node[K, V]{isEntry: false}, parent: parent} +} + +func (i *indirect[K, V]) empty() bool { + nc := 0 + for j := range i.children { + if i.children[j].Load() != nil { + nc++ + } + } + return nc == 0 +} + +// entry is a leaf node in the hash-trie. +type entry[K, V comparable] struct { + node[K, V] + overflow atomic.Pointer[entry[K, V]] // Overflow for hash collisions. + key K + value V +} + +func newEntryNode[K, V comparable](key K, value V) *entry[K, V] { + return &entry[K, V]{ + node: node[K, V]{isEntry: true}, + key: key, + value: value, + } +} + +func (e *entry[K, V]) lookup(key K, equal equalFunc) (V, bool) { + for e != nil { + if equal(unsafe.Pointer(&e.key), abi.NoEscape(unsafe.Pointer(&key))) { + return e.value, true + } + e = e.overflow.Load() + } + return *new(V), false +} + +// compareAndDelete deletes an entry in the overflow chain if both the key and value compare +// equal. Returns the new entry chain and whether or not anything was deleted. +// +// compareAndDelete must be called under the mutex of the indirect node which e is a child of. +func (head *entry[K, V]) compareAndDelete(key K, value V, keyEqual, valEqual equalFunc) (*entry[K, V], bool) { + if keyEqual(unsafe.Pointer(&head.key), abi.NoEscape(unsafe.Pointer(&key))) && + valEqual(unsafe.Pointer(&head.value), abi.NoEscape(unsafe.Pointer(&value))) { + // Drop the head of the list. + return head.overflow.Load(), true + } + i := &head.overflow + e := i.Load() + for e != nil { + if keyEqual(unsafe.Pointer(&e.key), abi.NoEscape(unsafe.Pointer(&key))) && + valEqual(unsafe.Pointer(&e.value), abi.NoEscape(unsafe.Pointer(&value))) { + i.Store(e.overflow.Load()) + return head, true + } + i = &e.overflow + e = e.overflow.Load() + } + return head, false +} + +// node is the header for a node. It's polymorphic and +// is actually either an entry or an indirect. +type node[K, V comparable] struct { + isEntry bool +} + +func (n *node[K, V]) entry() *entry[K, V] { + if !n.isEntry { + panic("called entry on non-entry node") + } + return (*entry[K, V])(unsafe.Pointer(n)) +} + +func (n *node[K, V]) indirect() *indirect[K, V] { + if n.isEntry { + panic("called indirect on entry node") + } + return (*indirect[K, V])(unsafe.Pointer(n)) +} diff --git a/contrib/go/_std_1.23/src/internal/concurrent/ya.make b/contrib/go/_std_1.23/src/internal/concurrent/ya.make new file mode 100644 index 000000000000..db0f6f6f0788 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/concurrent/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + hashtriemap.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.23/src/internal/coverage/rtcov/rtcov.go b/contrib/go/_std_1.23/src/internal/coverage/rtcov/rtcov.go new file mode 100644 index 000000000000..9e30d679007d --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/coverage/rtcov/rtcov.go @@ -0,0 +1,88 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rtcov + +import "unsafe" + +// This package contains types whose structure is shared between +// the runtime package and the "runtime/coverage" implementation. + +// CovMetaBlob is a container for holding the meta-data symbol (an +// RODATA variable) for an instrumented Go package. Here "p" points to +// the symbol itself, "len" is the length of the sym in bytes, and +// "hash" is an md5sum for the sym computed by the compiler. When +// the init function for a coverage-instrumented package executes, it +// will make a call into the runtime which will create a covMetaBlob +// object for the package and chain it onto a global list. +type CovMetaBlob struct { + P *byte + Len uint32 + Hash [16]byte + PkgPath string + PkgID int + CounterMode uint8 // coverage.CounterMode + CounterGranularity uint8 // coverage.CounterGranularity +} + +// CovCounterBlob is a container for encapsulating a counter section +// (BSS variable) for an instrumented Go module. Here "counters" +// points to the counter payload and "len" is the number of uint32 +// entries in the section. +type CovCounterBlob struct { + Counters *uint32 + Len uint64 +} + +// Meta is the top-level container for bits of state related to +// code coverage meta-data in the runtime. +var Meta struct { + // List contains the list of currently registered meta-data + // blobs for the running program. + List []CovMetaBlob + + // PkgMap records mappings from hard-coded package IDs to + // slots in the List above. + PkgMap map[int]int + + // Set to true if we discover a package mapping glitch. + hardCodedListNeedsUpdating bool +} + +// AddMeta is invoked during package "init" functions by the +// compiler when compiling for coverage instrumentation; here 'p' is a +// meta-data blob of length 'dlen' for the package in question, 'hash' +// is a compiler-computed md5.sum for the blob, 'pkpath' is the +// package path, 'pkid' is the hard-coded ID that the compiler is +// using for the package (or -1 if the compiler doesn't think a +// hard-coded ID is needed), and 'cmode'/'cgran' are the coverage +// counter mode and granularity requested by the user. Return value is +// the ID for the package for use by the package code itself, +// or 0 for impossible errors. +func AddMeta(p unsafe.Pointer, dlen uint32, hash [16]byte, pkgpath string, pkgid int, cmode uint8, cgran uint8) uint32 { + slot := len(Meta.List) + Meta.List = append(Meta.List, CovMetaBlob{ + P: (*byte)(p), + Len: dlen, + Hash: hash, + PkgPath: pkgpath, + PkgID: pkgid, + CounterMode: cmode, + CounterGranularity: cgran, + }) + if pkgid != -1 { + if Meta.PkgMap == nil { + Meta.PkgMap = make(map[int]int) + } + if _, ok := Meta.PkgMap[pkgid]; ok { + return 0 + } + // Record the real slot (position on meta-list) for this + // package; we'll use the map to fix things up later on. + Meta.PkgMap[pkgid] = slot + } + + // ID zero is reserved as invalid. + return uint32(slot + 1) +} diff --git a/contrib/go/_std_1.22/src/internal/coverage/rtcov/ya.make b/contrib/go/_std_1.23/src/internal/coverage/rtcov/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/coverage/rtcov/ya.make rename to contrib/go/_std_1.23/src/internal/coverage/rtcov/ya.make diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu.go b/contrib/go/_std_1.23/src/internal/cpu/cpu.go similarity index 96% rename from contrib/go/_std_1.22/src/internal/cpu/cpu.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu.go index d794e53ceeef..9be280c6baf0 100644 --- a/contrib/go/_std_1.22/src/internal/cpu/cpu.go +++ b/contrib/go/_std_1.23/src/internal/cpu/cpu.go @@ -6,6 +6,8 @@ // used by the Go standard library. package cpu +import _ "unsafe" // for linkname + // DebugOptions is set to true by the runtime if the OS supports reading // GODEBUG early in runtime startup. // This should not be changed after it is initialized. @@ -121,6 +123,14 @@ var S390X struct { _ CacheLinePad } +// CPU feature variables are accessed by assembly code in various packages. +//go:linkname X86 +//go:linkname ARM +//go:linkname ARM64 +//go:linkname MIPS64X +//go:linkname PPC64 +//go:linkname S390X + // Initialize examines the processor and sets the relevant variables above. // This is called by the runtime package early in program initialization, // before normal init functions are run. env is set by runtime if the OS supports diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu.s b/contrib/go/_std_1.23/src/internal/cpu/cpu.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu.s rename to contrib/go/_std_1.23/src/internal/cpu/cpu.s diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64.s b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64.s rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64.s diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_android.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_android.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_android.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_android.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_darwin.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_darwin.go similarity index 73% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_darwin.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_darwin.go index 60beadddbb1d..2507780e5f1b 100644 --- a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_darwin.go +++ b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_darwin.go @@ -6,6 +6,8 @@ package cpu +import _ "unsafe" // for linkname + func osInit() { ARM64.HasATOMICS = sysctlEnabled([]byte("hw.optional.armv8_1_atomics\x00")) ARM64.HasCRC32 = sysctlEnabled([]byte("hw.optional.armv8_crc32\x00")) @@ -24,6 +26,16 @@ func osInit() { //go:noescape func getsysctlbyname(name []byte) (int32, int32) +// sysctlEnabled should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname sysctlEnabled func sysctlEnabled(name []byte) bool { ret, value := getsysctlbyname(name) if ret < 0 { diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_freebsd.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_freebsd.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_freebsd.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_hwcap.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_hwcap.go similarity index 85% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_hwcap.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_hwcap.go index 2fabbb6edc36..34edf3eeb2a8 100644 --- a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_hwcap.go +++ b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_hwcap.go @@ -6,8 +6,19 @@ package cpu +import _ "unsafe" // for linkname + // HWCap may be initialized by archauxv and // should not be changed after it was initialized. +// +// Other widely used packages +// access HWCap using linkname as well, most notably: +// - github.com/klauspost/cpuid/v2 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname HWCap var HWCap uint // HWCAP bits. These are exposed by Linux. @@ -48,13 +59,13 @@ func hwcapInit(os string) { if ARM64.HasCPUID { midr := getMIDR() part_num := uint16((midr >> 4) & 0xfff) - implementor := byte((midr >> 24) & 0xff) + implementer := byte((midr >> 24) & 0xff) // d0c - NeoverseN1 // d40 - NeoverseV1 // d49 - NeoverseN2 // d4f - NeoverseV2 - if implementor == 'A' && (part_num == 0xd0c || part_num == 0xd40 || + if implementer == 'A' && (part_num == 0xd0c || part_num == 0xd40 || part_num == 0xd49 || part_num == 0xd4f) { ARM64.IsNeoverse = true } diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_linux.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_linux.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_linux.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_openbsd.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_openbsd.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_openbsd.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_other.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_other.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_arm64_other.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_arm64_other.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_loong64.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_loong64.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_loong64.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_mips.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_mips.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_mips.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_mips.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_mips64x.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_mips64x.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_mips64x.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_mipsle.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_mipsle.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_mipsle.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_mipsle.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_no_name.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_no_name.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_no_name.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_no_name.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x_aix.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x_aix.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x_aix.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x_linux.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x_linux.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x_linux.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x_other.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x_other.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_ppc64x_other.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_ppc64x_other.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_riscv64.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_riscv64.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_riscv64.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_s390x.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_s390x.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_s390x.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_s390x.s b/contrib/go/_std_1.23/src/internal/cpu/cpu_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_s390x.s rename to contrib/go/_std_1.23/src/internal/cpu/cpu_s390x.s diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_wasm.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_wasm.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_wasm.go diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_x86.go b/contrib/go/_std_1.23/src/internal/cpu/cpu_x86.go similarity index 99% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_x86.go rename to contrib/go/_std_1.23/src/internal/cpu/cpu_x86.go index f8aa53abeb67..2b629d4da021 100644 --- a/contrib/go/_std_1.22/src/internal/cpu/cpu_x86.go +++ b/contrib/go/_std_1.23/src/internal/cpu/cpu_x86.go @@ -18,9 +18,6 @@ func xgetbv() (eax, edx uint32) func getGOAMD64level() int32 const ( - // edx bits - cpuid_SSE2 = 1 << 26 - // ecx bits cpuid_SSE3 = 1 << 0 cpuid_PCLMULQDQ = 1 << 1 diff --git a/contrib/go/_std_1.22/src/internal/cpu/cpu_x86.s b/contrib/go/_std_1.23/src/internal/cpu/cpu_x86.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/cpu_x86.s rename to contrib/go/_std_1.23/src/internal/cpu/cpu_x86.s diff --git a/contrib/go/_std_1.22/src/internal/cpu/ya.make b/contrib/go/_std_1.23/src/internal/cpu/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/cpu/ya.make rename to contrib/go/_std_1.23/src/internal/cpu/ya.make diff --git a/contrib/go/_std_1.23/src/internal/filepathlite/path.go b/contrib/go/_std_1.23/src/internal/filepathlite/path.go new file mode 100644 index 000000000000..e3daa447d976 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/filepathlite/path.go @@ -0,0 +1,274 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package filepathlite implements a subset of path/filepath, +// only using packages which may be imported by "os". +// +// Tests for these functions are in path/filepath. +package filepathlite + +import ( + "errors" + "internal/stringslite" + "io/fs" + "slices" +) + +var errInvalidPath = errors.New("invalid path") + +// A lazybuf is a lazily constructed path buffer. +// It supports append, reading previously appended bytes, +// and retrieving the final string. It does not allocate a buffer +// to hold the output until that output diverges from s. +type lazybuf struct { + path string + buf []byte + w int + volAndPath string + volLen int +} + +func (b *lazybuf) index(i int) byte { + if b.buf != nil { + return b.buf[i] + } + return b.path[i] +} + +func (b *lazybuf) append(c byte) { + if b.buf == nil { + if b.w < len(b.path) && b.path[b.w] == c { + b.w++ + return + } + b.buf = make([]byte, len(b.path)) + copy(b.buf, b.path[:b.w]) + } + b.buf[b.w] = c + b.w++ +} + +func (b *lazybuf) prepend(prefix ...byte) { + b.buf = slices.Insert(b.buf, 0, prefix...) + b.w += len(prefix) +} + +func (b *lazybuf) string() string { + if b.buf == nil { + return b.volAndPath[:b.volLen+b.w] + } + return b.volAndPath[:b.volLen] + string(b.buf[:b.w]) +} + +// Clean is filepath.Clean. +func Clean(path string) string { + originalPath := path + volLen := volumeNameLen(path) + path = path[volLen:] + if path == "" { + if volLen > 1 && IsPathSeparator(originalPath[0]) && IsPathSeparator(originalPath[1]) { + // should be UNC + return FromSlash(originalPath) + } + return originalPath + "." + } + rooted := IsPathSeparator(path[0]) + + // Invariants: + // reading from path; r is index of next byte to process. + // writing to buf; w is index of next byte to write. + // dotdot is index in buf where .. must stop, either because + // it is the leading slash or it is a leading ../../.. prefix. + n := len(path) + out := lazybuf{path: path, volAndPath: originalPath, volLen: volLen} + r, dotdot := 0, 0 + if rooted { + out.append(Separator) + r, dotdot = 1, 1 + } + + for r < n { + switch { + case IsPathSeparator(path[r]): + // empty path element + r++ + case path[r] == '.' && (r+1 == n || IsPathSeparator(path[r+1])): + // . element + r++ + case path[r] == '.' && path[r+1] == '.' && (r+2 == n || IsPathSeparator(path[r+2])): + // .. element: remove to last separator + r += 2 + switch { + case out.w > dotdot: + // can backtrack + out.w-- + for out.w > dotdot && !IsPathSeparator(out.index(out.w)) { + out.w-- + } + case !rooted: + // cannot backtrack, but not rooted, so append .. element. + if out.w > 0 { + out.append(Separator) + } + out.append('.') + out.append('.') + dotdot = out.w + } + default: + // real path element. + // add slash if needed + if rooted && out.w != 1 || !rooted && out.w != 0 { + out.append(Separator) + } + // copy element + for ; r < n && !IsPathSeparator(path[r]); r++ { + out.append(path[r]) + } + } + } + + // Turn empty string into "." + if out.w == 0 { + out.append('.') + } + + postClean(&out) // avoid creating absolute paths on Windows + return FromSlash(out.string()) +} + +// IsLocal is filepath.IsLocal. +func IsLocal(path string) bool { + return isLocal(path) +} + +func unixIsLocal(path string) bool { + if IsAbs(path) || path == "" { + return false + } + hasDots := false + for p := path; p != ""; { + var part string + part, p, _ = stringslite.Cut(p, "/") + if part == "." || part == ".." { + hasDots = true + break + } + } + if hasDots { + path = Clean(path) + } + if path == ".." || stringslite.HasPrefix(path, "../") { + return false + } + return true +} + +// Localize is filepath.Localize. +func Localize(path string) (string, error) { + if !fs.ValidPath(path) { + return "", errInvalidPath + } + return localize(path) +} + +// ToSlash is filepath.ToSlash. +func ToSlash(path string) string { + if Separator == '/' { + return path + } + return replaceStringByte(path, Separator, '/') +} + +// FromSlash is filepath.ToSlash. +func FromSlash(path string) string { + if Separator == '/' { + return path + } + return replaceStringByte(path, '/', Separator) +} + +func replaceStringByte(s string, old, new byte) string { + if stringslite.IndexByte(s, old) == -1 { + return s + } + n := []byte(s) + for i := range n { + if n[i] == old { + n[i] = new + } + } + return string(n) +} + +// Split is filepath.Split. +func Split(path string) (dir, file string) { + vol := VolumeName(path) + i := len(path) - 1 + for i >= len(vol) && !IsPathSeparator(path[i]) { + i-- + } + return path[:i+1], path[i+1:] +} + +// Ext is filepath.Ext. +func Ext(path string) string { + for i := len(path) - 1; i >= 0 && !IsPathSeparator(path[i]); i-- { + if path[i] == '.' { + return path[i:] + } + } + return "" +} + +// Base is filepath.Base. +func Base(path string) string { + if path == "" { + return "." + } + // Strip trailing slashes. + for len(path) > 0 && IsPathSeparator(path[len(path)-1]) { + path = path[0 : len(path)-1] + } + // Throw away volume name + path = path[len(VolumeName(path)):] + // Find the last element + i := len(path) - 1 + for i >= 0 && !IsPathSeparator(path[i]) { + i-- + } + if i >= 0 { + path = path[i+1:] + } + // If empty now, it had only slashes. + if path == "" { + return string(Separator) + } + return path +} + +// Dir is filepath.Dir. +func Dir(path string) string { + vol := VolumeName(path) + i := len(path) - 1 + for i >= len(vol) && !IsPathSeparator(path[i]) { + i-- + } + dir := Clean(path[len(vol) : i+1]) + if dir == "." && len(vol) > 2 { + // must be UNC + return vol + } + return vol + dir +} + +// VolumeName is filepath.VolumeName. +func VolumeName(path string) string { + return FromSlash(path[:volumeNameLen(path)]) +} + +// VolumeNameLen returns the length of the leading volume name on Windows. +// It returns 0 elsewhere. +func VolumeNameLen(path string) int { + return volumeNameLen(path) +} diff --git a/contrib/go/_std_1.22/src/path/filepath/path_nonwindows.go b/contrib/go/_std_1.23/src/internal/filepathlite/path_nonwindows.go similarity index 91% rename from contrib/go/_std_1.22/src/path/filepath/path_nonwindows.go rename to contrib/go/_std_1.23/src/internal/filepathlite/path_nonwindows.go index db69f0228b0d..c9c4c02a3da1 100644 --- a/contrib/go/_std_1.22/src/path/filepath/path_nonwindows.go +++ b/contrib/go/_std_1.23/src/internal/filepathlite/path_nonwindows.go @@ -4,6 +4,6 @@ //go:build !windows -package filepath +package filepathlite func postClean(out *lazybuf) {} diff --git a/contrib/go/_std_1.23/src/internal/filepathlite/path_plan9.go b/contrib/go/_std_1.23/src/internal/filepathlite/path_plan9.go new file mode 100644 index 000000000000..5bbb724f9113 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/filepathlite/path_plan9.go @@ -0,0 +1,41 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package filepathlite + +import ( + "internal/bytealg" + "internal/stringslite" +) + +const ( + Separator = '/' // OS-specific path separator + ListSeparator = '\000' // OS-specific path list separator +) + +func IsPathSeparator(c uint8) bool { + return Separator == c +} + +func isLocal(path string) bool { + return unixIsLocal(path) +} + +func localize(path string) (string, error) { + if path[0] == '#' || bytealg.IndexByteString(path, 0) >= 0 { + return "", errInvalidPath + } + return path, nil +} + +// IsAbs reports whether the path is absolute. +func IsAbs(path string) bool { + return stringslite.HasPrefix(path, "/") || stringslite.HasPrefix(path, "#") +} + +// volumeNameLen returns length of the leading volume name on Windows. +// It returns 0 elsewhere. +func volumeNameLen(path string) int { + return 0 +} diff --git a/contrib/go/_std_1.23/src/internal/filepathlite/path_unix.go b/contrib/go/_std_1.23/src/internal/filepathlite/path_unix.go new file mode 100644 index 000000000000..e31f1ae74f74 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/filepathlite/path_unix.go @@ -0,0 +1,43 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix || (js && wasm) || wasip1 + +package filepathlite + +import ( + "internal/bytealg" + "internal/stringslite" +) + +const ( + Separator = '/' // OS-specific path separator + ListSeparator = ':' // OS-specific path list separator +) + +func IsPathSeparator(c uint8) bool { + return Separator == c +} + +func isLocal(path string) bool { + return unixIsLocal(path) +} + +func localize(path string) (string, error) { + if bytealg.IndexByteString(path, 0) >= 0 { + return "", errInvalidPath + } + return path, nil +} + +// IsAbs reports whether the path is absolute. +func IsAbs(path string) bool { + return stringslite.HasPrefix(path, "/") +} + +// volumeNameLen returns length of the leading volume name on Windows. +// It returns 0 elsewhere. +func volumeNameLen(path string) int { + return 0 +} diff --git a/contrib/go/_std_1.22/src/path/filepath/path_windows.go b/contrib/go/_std_1.23/src/internal/filepathlite/path_windows.go similarity index 50% rename from contrib/go/_std_1.22/src/path/filepath/path_windows.go rename to contrib/go/_std_1.23/src/internal/filepathlite/path_windows.go index eacab0e5ced6..8f34838a98c5 100644 --- a/contrib/go/_std_1.22/src/path/filepath/path_windows.go +++ b/contrib/go/_std_1.23/src/internal/filepathlite/path_windows.go @@ -2,35 +2,32 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package filepath +package filepathlite import ( - "internal/safefilepath" - "os" - "strings" + "internal/bytealg" + "internal/stringslite" "syscall" ) -func isSlash(c uint8) bool { - return c == '\\' || c == '/' -} +const ( + Separator = '\\' // OS-specific path separator + ListSeparator = ';' // OS-specific path list separator +) -func toUpper(c byte) byte { - if 'a' <= c && c <= 'z' { - return c - ('a' - 'A') - } - return c +func IsPathSeparator(c uint8) bool { + return c == '\\' || c == '/' } func isLocal(path string) bool { if path == "" { return false } - if isSlash(path[0]) { + if IsPathSeparator(path[0]) { // Path rooted in the current drive. return false } - if strings.IndexByte(path, ':') >= 0 { + if stringslite.IndexByte(path, ':') >= 0 { // Colons are only valid when marking a drive letter ("C:foo"). // Rejecting any path with a colon is conservative but safe. return false @@ -42,19 +39,145 @@ func isLocal(path string) bool { if part == "." || part == ".." { hasDots = true } - if safefilepath.IsReservedName(part) { + if isReservedName(part) { return false } } if hasDots { path = Clean(path) } - if path == ".." || strings.HasPrefix(path, `..\`) { + if path == ".." || stringslite.HasPrefix(path, `..\`) { + return false + } + return true +} + +func localize(path string) (string, error) { + for i := 0; i < len(path); i++ { + switch path[i] { + case ':', '\\', 0: + return "", errInvalidPath + } + } + containsSlash := false + for p := path; p != ""; { + // Find the next path element. + var element string + i := bytealg.IndexByteString(p, '/') + if i < 0 { + element = p + p = "" + } else { + containsSlash = true + element = p[:i] + p = p[i+1:] + } + if isReservedName(element) { + return "", errInvalidPath + } + } + if containsSlash { + // We can't depend on strings, so substitute \ for / manually. + buf := []byte(path) + for i, b := range buf { + if b == '/' { + buf[i] = '\\' + } + } + path = string(buf) + } + return path, nil +} + +// isReservedName reports if name is a Windows reserved device name. +// It does not detect names with an extension, which are also reserved on some Windows versions. +// +// For details, search for PRN in +// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file. +func isReservedName(name string) bool { + // Device names can have arbitrary trailing characters following a dot or colon. + base := name + for i := 0; i < len(base); i++ { + switch base[i] { + case ':', '.': + base = base[:i] + } + } + // Trailing spaces in the last path element are ignored. + for len(base) > 0 && base[len(base)-1] == ' ' { + base = base[:len(base)-1] + } + if !isReservedBaseName(base) { + return false + } + if len(base) == len(name) { + return true + } + // The path element is a reserved name with an extension. + // Some Windows versions consider this a reserved name, + // while others do not. Use FullPath to see if the name is + // reserved. + if p, _ := syscall.FullPath(name); len(p) >= 4 && p[:4] == `\\.\` { + return true + } + return false +} + +func isReservedBaseName(name string) bool { + if len(name) == 3 { + switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { + case "CON", "PRN", "AUX", "NUL": + return true + } + } + if len(name) >= 4 { + switch string([]byte{toUpper(name[0]), toUpper(name[1]), toUpper(name[2])}) { + case "COM", "LPT": + if len(name) == 4 && '1' <= name[3] && name[3] <= '9' { + return true + } + // Superscript ¹, ², and ³ are considered numbers as well. + switch name[3:] { + case "\u00b2", "\u00b3", "\u00b9": + return true + } + return false + } + } + + // Passing CONIN$ or CONOUT$ to CreateFile opens a console handle. + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#consoles + // + // While CONIN$ and CONOUT$ aren't documented as being files, + // they behave the same as CON. For example, ./CONIN$ also opens the console input. + if len(name) == 6 && name[5] == '$' && equalFold(name, "CONIN$") { + return true + } + if len(name) == 7 && name[6] == '$' && equalFold(name, "CONOUT$") { + return true + } + return false +} + +func equalFold(a, b string) bool { + if len(a) != len(b) { return false } + for i := 0; i < len(a); i++ { + if toUpper(a[i]) != toUpper(b[i]) { + return false + } + } return true } +func toUpper(c byte) byte { + if 'a' <= c && c <= 'z' { + return c - ('a' - 'A') + } + return c +} + // IsAbs reports whether the path is absolute. func IsAbs(path string) (b bool) { l := volumeNameLen(path) @@ -62,14 +185,14 @@ func IsAbs(path string) (b bool) { return false } // If the volume name starts with a double slash, this is an absolute path. - if isSlash(path[0]) && isSlash(path[1]) { + if IsPathSeparator(path[0]) && IsPathSeparator(path[1]) { return true } path = path[l:] if path == "" { return false } - return isSlash(path[0]) + return IsPathSeparator(path[0]) } // volumeNameLen returns length of the leading volume name on Windows. @@ -90,7 +213,7 @@ func volumeNameLen(path string) int { // in which case the "drive letter" might be multiple bytes long. return 2 - case len(path) == 0 || !isSlash(path[0]): + case len(path) == 0 || !IsPathSeparator(path[0]): // Path does not have a volume component. return 0 @@ -119,7 +242,7 @@ func volumeNameLen(path string) int { } return len(path) - len(rest) - 1 - case len(path) >= 2 && isSlash(path[1]): + case len(path) >= 2 && IsPathSeparator(path[1]): // Path starts with \\, and is a UNC path. return uncLen(path, 2) } @@ -134,15 +257,15 @@ func pathHasPrefixFold(s, prefix string) bool { return false } for i := 0; i < len(prefix); i++ { - if isSlash(prefix[i]) { - if !isSlash(s[i]) { + if IsPathSeparator(prefix[i]) { + if !IsPathSeparator(s[i]) { return false } } else if toUpper(prefix[i]) != toUpper(s[i]) { return false } } - if len(s) > len(prefix) && !isSlash(s[len(prefix)]) { + if len(s) > len(prefix) && !IsPathSeparator(s[len(prefix)]) { return false } return true @@ -154,7 +277,7 @@ func pathHasPrefixFold(s, prefix string) bool { func uncLen(path string, prefixLen int) int { count := 0 for i := prefixLen; i < len(path); i++ { - if isSlash(path[i]) { + if IsPathSeparator(path[i]) { count++ if count == 2 { return i @@ -167,158 +290,16 @@ func uncLen(path string, prefixLen int) int { // cutPath slices path around the first path separator. func cutPath(path string) (before, after string, found bool) { for i := range path { - if isSlash(path[i]) { + if IsPathSeparator(path[i]) { return path[:i], path[i+1:], true } } return path, "", false } -// HasPrefix exists for historical compatibility and should not be used. -// -// Deprecated: HasPrefix does not respect path boundaries and -// does not ignore case when required. -func HasPrefix(p, prefix string) bool { - if strings.HasPrefix(p, prefix) { - return true - } - return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix)) -} - -func splitList(path string) []string { - // The same implementation is used in LookPath in os/exec; - // consider changing os/exec when changing this. - - if path == "" { - return []string{} - } - - // Split path, respecting but preserving quotes. - list := []string{} - start := 0 - quo := false - for i := 0; i < len(path); i++ { - switch c := path[i]; { - case c == '"': - quo = !quo - case c == ListSeparator && !quo: - list = append(list, path[start:i]) - start = i + 1 - } - } - list = append(list, path[start:]) - - // Remove quotes. - for i, s := range list { - list[i] = strings.ReplaceAll(s, `"`, ``) - } - - return list -} - -func abs(path string) (string, error) { - if path == "" { - // syscall.FullPath returns an error on empty path, because it's not a valid path. - // To implement Abs behavior of returning working directory on empty string input, - // special-case empty path by changing it to "." path. See golang.org/issue/24441. - path = "." - } - fullPath, err := syscall.FullPath(path) - if err != nil { - return "", err - } - return Clean(fullPath), nil -} - -func join(elem []string) string { - var b strings.Builder - var lastChar byte - for _, e := range elem { - switch { - case b.Len() == 0: - // Add the first non-empty path element unchanged. - case isSlash(lastChar): - // If the path ends in a slash, strip any leading slashes from the next - // path element to avoid creating a UNC path (any path starting with "\\") - // from non-UNC elements. - // - // The correct behavior for Join when the first element is an incomplete UNC - // path (for example, "\\") is underspecified. We currently join subsequent - // elements so Join("\\", "host", "share") produces "\\host\share". - for len(e) > 0 && isSlash(e[0]) { - e = e[1:] - } - // If the path is \ and the next path element is ??, - // add an extra .\ to create \.\?? rather than \??\ - // (a Root Local Device path). - if b.Len() == 1 && pathHasPrefixFold(e, "??") { - b.WriteString(`.\`) - } - case lastChar == ':': - // If the path ends in a colon, keep the path relative to the current directory - // on a drive and don't add a separator. Preserve leading slashes in the next - // path element, which may make the path absolute. - // - // Join(`C:`, `f`) = `C:f` - // Join(`C:`, `\f`) = `C:\f` - default: - // In all other cases, add a separator between elements. - b.WriteByte('\\') - lastChar = '\\' - } - if len(e) > 0 { - b.WriteString(e) - lastChar = e[len(e)-1] - } - } - if b.Len() == 0 { - return "" - } - return Clean(b.String()) -} - -// joinNonEmpty is like join, but it assumes that the first element is non-empty. -func joinNonEmpty(elem []string) string { - if len(elem[0]) == 2 && elem[0][1] == ':' { - // First element is drive letter without terminating slash. - // Keep path relative to current directory on that drive. - // Skip empty elements. - i := 1 - for ; i < len(elem); i++ { - if elem[i] != "" { - break - } - } - return Clean(elem[0] + strings.Join(elem[i:], string(Separator))) - } - // The following logic prevents Join from inadvertently creating a - // UNC path on Windows. Unless the first element is a UNC path, Join - // shouldn't create a UNC path. See golang.org/issue/9167. - p := Clean(strings.Join(elem, string(Separator))) - if !isUNC(p) { - return p - } - // p == UNC only allowed when the first element is a UNC path. - head := Clean(elem[0]) - if isUNC(head) { - return p - } - // head + tail == UNC, but joining two non-UNC paths should not result - // in a UNC path. Undo creation of UNC path. - tail := Clean(strings.Join(elem[1:], string(Separator))) - if head[len(head)-1] == Separator { - return head + tail - } - return head + string(Separator) + tail -} - // isUNC reports whether path is a UNC path. func isUNC(path string) bool { - return len(path) > 1 && isSlash(path[0]) && isSlash(path[1]) -} - -func sameWord(a, b string) bool { - return strings.EqualFold(a, b) + return len(path) > 1 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) } // postClean adjusts the results of Clean to avoid turning a relative path @@ -331,7 +312,7 @@ func postClean(out *lazybuf) { // insert a .\ at the beginning to avoid converting relative paths // like a/../c: into c:. for _, c := range out.buf { - if os.IsPathSeparator(c) { + if IsPathSeparator(c) { break } if c == ':' { @@ -342,7 +323,7 @@ func postClean(out *lazybuf) { // If a path begins with \??\, insert a \. at the beginning // to avoid converting paths like \a\..\??\c:\x into \??\c:\x // (equivalent to c:\x). - if len(out.buf) >= 3 && os.IsPathSeparator(out.buf[0]) && out.buf[1] == '?' && out.buf[2] == '?' { + if len(out.buf) >= 3 && IsPathSeparator(out.buf[0]) && out.buf[1] == '?' && out.buf[2] == '?' { out.prepend(Separator, '.') } } diff --git a/contrib/go/_std_1.22/src/internal/safefilepath/ya.make b/contrib/go/_std_1.23/src/internal/filepathlite/ya.make similarity index 96% rename from contrib/go/_std_1.22/src/internal/safefilepath/ya.make rename to contrib/go/_std_1.23/src/internal/filepathlite/ya.make index 9b77c8250297..4dda8af2f955 100644 --- a/contrib/go/_std_1.22/src/internal/safefilepath/ya.make +++ b/contrib/go/_std_1.23/src/internal/filepathlite/ya.make @@ -2,7 +2,8 @@ GO_LIBRARY() IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( path.go - path_other.go + path_nonwindows.go + path_unix.go ) ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( diff --git a/contrib/go/_std_1.22/src/internal/fmtsort/sort.go b/contrib/go/_std_1.23/src/internal/fmtsort/sort.go similarity index 68% rename from contrib/go/_std_1.22/src/internal/fmtsort/sort.go rename to contrib/go/_std_1.23/src/internal/fmtsort/sort.go index 278a89bd75d4..f51cdc7083a4 100644 --- a/contrib/go/_std_1.22/src/internal/fmtsort/sort.go +++ b/contrib/go/_std_1.23/src/internal/fmtsort/sort.go @@ -9,25 +9,23 @@ package fmtsort import ( + "cmp" "reflect" - "sort" + "slices" ) // Note: Throughout this package we avoid calling reflect.Value.Interface as // it is not always legal to do so and it's easier to avoid the issue than to face it. -// SortedMap represents a map's keys and values. The keys and values are -// aligned in index order: Value[i] is the value in the map corresponding to Key[i]. -type SortedMap struct { - Key []reflect.Value - Value []reflect.Value -} +// SortedMap is a slice of KeyValue pairs that simplifies sorting +// and iterating over map entries. +// +// Each KeyValue pair contains a map key and its corresponding value. +type SortedMap []KeyValue -func (o *SortedMap) Len() int { return len(o.Key) } -func (o *SortedMap) Less(i, j int) bool { return compare(o.Key[i], o.Key[j]) < 0 } -func (o *SortedMap) Swap(i, j int) { - o.Key[i], o.Key[j] = o.Key[j], o.Key[i] - o.Value[i], o.Value[j] = o.Value[j], o.Value[i] +// KeyValue holds a single key and value pair found in a map. +type KeyValue struct { + Key, Value reflect.Value } // Sort accepts a map and returns a SortedMap that has the same keys and @@ -48,7 +46,7 @@ func (o *SortedMap) Swap(i, j int) { // Otherwise identical arrays compare by length. // - interface values compare first by reflect.Type describing the concrete type // and then by concrete value as described in the previous rules. -func Sort(mapValue reflect.Value) *SortedMap { +func Sort(mapValue reflect.Value) SortedMap { if mapValue.Type().Kind() != reflect.Map { return nil } @@ -56,18 +54,14 @@ func Sort(mapValue reflect.Value) *SortedMap { // of a concurrent map update. The runtime is responsible for // yelling loudly if that happens. See issue 33275. n := mapValue.Len() - key := make([]reflect.Value, 0, n) - value := make([]reflect.Value, 0, n) + sorted := make(SortedMap, 0, n) iter := mapValue.MapRange() for iter.Next() { - key = append(key, iter.Key()) - value = append(value, iter.Value()) - } - sorted := &SortedMap{ - Key: key, - Value: value, + sorted = append(sorted, KeyValue{iter.Key(), iter.Value()}) } - sort.Stable(sorted) + slices.SortStableFunc(sorted, func(a, b KeyValue) int { + return compare(a.Key, b.Key) + }) return sorted } @@ -82,43 +76,19 @@ func compare(aVal, bVal reflect.Value) int { } switch aVal.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - a, b := aVal.Int(), bVal.Int() - switch { - case a < b: - return -1 - case a > b: - return 1 - default: - return 0 - } + return cmp.Compare(aVal.Int(), bVal.Int()) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - a, b := aVal.Uint(), bVal.Uint() - switch { - case a < b: - return -1 - case a > b: - return 1 - default: - return 0 - } + return cmp.Compare(aVal.Uint(), bVal.Uint()) case reflect.String: - a, b := aVal.String(), bVal.String() - switch { - case a < b: - return -1 - case a > b: - return 1 - default: - return 0 - } + return cmp.Compare(aVal.String(), bVal.String()) case reflect.Float32, reflect.Float64: - return floatCompare(aVal.Float(), bVal.Float()) + return cmp.Compare(aVal.Float(), bVal.Float()) case reflect.Complex64, reflect.Complex128: a, b := aVal.Complex(), bVal.Complex() - if c := floatCompare(real(a), real(b)); c != 0 { + if c := cmp.Compare(real(a), real(b)); c != 0 { return c } - return floatCompare(imag(a), imag(b)) + return cmp.Compare(imag(a), imag(b)) case reflect.Bool: a, b := aVal.Bool(), bVal.Bool() switch { @@ -130,28 +100,12 @@ func compare(aVal, bVal reflect.Value) int { return -1 } case reflect.Pointer, reflect.UnsafePointer: - a, b := aVal.Pointer(), bVal.Pointer() - switch { - case a < b: - return -1 - case a > b: - return 1 - default: - return 0 - } + return cmp.Compare(aVal.Pointer(), bVal.Pointer()) case reflect.Chan: if c, ok := nilCompare(aVal, bVal); ok { return c } - ap, bp := aVal.Pointer(), bVal.Pointer() - switch { - case ap < bp: - return -1 - case ap > bp: - return 1 - default: - return 0 - } + return cmp.Compare(aVal.Pointer(), bVal.Pointer()) case reflect.Struct: for i := 0; i < aVal.NumField(); i++ { if c := compare(aVal.Field(i), bVal.Field(i)); c != 0 { @@ -198,22 +152,3 @@ func nilCompare(aVal, bVal reflect.Value) (int, bool) { } return 0, false } - -// floatCompare compares two floating-point values. NaNs compare low. -func floatCompare(a, b float64) int { - switch { - case isNaN(a): - return -1 // No good answer if b is a NaN so don't bother checking. - case isNaN(b): - return 1 - case a < b: - return -1 - case a > b: - return 1 - } - return 0 -} - -func isNaN(a float64) bool { - return a != a -} diff --git a/contrib/go/_std_1.22/src/internal/fmtsort/ya.make b/contrib/go/_std_1.23/src/internal/fmtsort/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/fmtsort/ya.make rename to contrib/go/_std_1.23/src/internal/fmtsort/ya.make diff --git a/contrib/go/_std_1.22/src/internal/goarch/gengoarch.go b/contrib/go/_std_1.23/src/internal/goarch/gengoarch.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/gengoarch.go rename to contrib/go/_std_1.23/src/internal/goarch/gengoarch.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch.go b/contrib/go/_std_1.23/src/internal/goarch/goarch.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_386.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_386.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_386.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_386.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_amd64.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_amd64.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_amd64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_arm.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_arm.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_arm.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_arm64.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_arm64.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_arm64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_loong64.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_loong64.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_loong64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_mips.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_mips.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_mips.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_mips.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_mips64.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_mips64.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_mips64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_mips64le.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_mips64le.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_mips64le.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_mips64le.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_mipsle.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_mipsle.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_mipsle.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_mipsle.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_ppc64.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_ppc64.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_ppc64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_ppc64le.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_ppc64le.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_ppc64le.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_riscv64.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_riscv64.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_riscv64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_s390x.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_s390x.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_s390x.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/goarch_wasm.go b/contrib/go/_std_1.23/src/internal/goarch/goarch_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/goarch_wasm.go rename to contrib/go/_std_1.23/src/internal/goarch/goarch_wasm.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/ya.make b/contrib/go/_std_1.23/src/internal/goarch/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/ya.make rename to contrib/go/_std_1.23/src/internal/goarch/ya.make diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_386.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_386.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_386.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_386.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_amd64.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_amd64.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_amd64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_arm.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_arm.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_arm.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_arm64.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_arm64.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_arm64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_arm64be.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_arm64be.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_arm64be.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_arm64be.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_armbe.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_armbe.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_armbe.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_armbe.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_loong64.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_loong64.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_loong64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64le.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64le.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64le.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64le.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64p32.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64p32.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64p32.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64p32.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64p32le.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64p32le.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_mips64p32le.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_mips64p32le.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_mipsle.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_mipsle.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_mipsle.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_mipsle.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_ppc.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_ppc.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_ppc.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_ppc.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_ppc64.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_ppc64.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_ppc64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_ppc64le.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_ppc64le.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_ppc64le.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_riscv.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_riscv.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_riscv.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_riscv.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_riscv64.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_riscv64.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_riscv64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_s390.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_s390.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_s390.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_s390.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_s390x.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_s390x.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_s390x.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_sparc.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_sparc.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_sparc.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_sparc.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_sparc64.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_sparc64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_sparc64.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_sparc64.go diff --git a/contrib/go/_std_1.22/src/internal/goarch/zgoarch_wasm.go b/contrib/go/_std_1.23/src/internal/goarch/zgoarch_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goarch/zgoarch_wasm.go rename to contrib/go/_std_1.23/src/internal/goarch/zgoarch_wasm.go diff --git a/contrib/go/_std_1.22/src/internal/godebug/godebug.go b/contrib/go/_std_1.23/src/internal/godebug/godebug.go similarity index 88% rename from contrib/go/_std_1.22/src/internal/godebug/godebug.go rename to contrib/go/_std_1.23/src/internal/godebug/godebug.go index 36bfeaccc421..0756d313e6b9 100644 --- a/contrib/go/_std_1.22/src/internal/godebug/godebug.go +++ b/contrib/go/_std_1.23/src/internal/godebug/godebug.go @@ -22,8 +22,23 @@ // } // // Each time a non-default setting causes a change in program behavior, -// code should call [Setting.IncNonDefault] to increment a counter that can -// be reported by [runtime/metrics.Read]. +// code must call [Setting.IncNonDefault] to increment a counter that can +// be reported by [runtime/metrics.Read]. The call must only happen when +// the program executes a non-default behavior, not just when the setting +// is set to a non-default value. This is occasionally (but very rarely) +// infeasible, in which case the internal/godebugs table entry must set +// Opaque: true, and the documentation in doc/godebug.md should +// mention that metrics are unavailable. +// +// Conventionally, the global variable representing a godebug is named +// for the godebug itself, with no case changes: +// +// var gotypesalias = godebug.New("gotypesalias") // this +// var goTypesAlias = godebug.New("gotypesalias") // NOT THIS +// +// The test in internal/godebugs that checks for use of IncNonDefault +// requires the use of this convention. +// // Note that counters used with IncNonDefault must be added to // various tables in other packages. See the [Setting.IncNonDefault] // documentation for details. @@ -70,6 +85,11 @@ type value struct { // To disable that panic for access to an undocumented setting, // prefix the name with a #, as in godebug.New("#gofsystrace"). // The # is a signal to New but not part of the key used in $GODEBUG. +// +// Note that almost all settings should arrange to call [IncNonDefault] precisely +// when program behavior is changing from the default due to the setting +// (not just when the setting is different, but when program behavior changes). +// See the [internal/godebug] package comment for more. func New(name string) *Setting { return &Setting{name: name} } diff --git a/contrib/go/_std_1.22/src/internal/godebug/ya.make b/contrib/go/_std_1.23/src/internal/godebug/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/godebug/ya.make rename to contrib/go/_std_1.23/src/internal/godebug/ya.make diff --git a/contrib/go/_std_1.22/src/internal/godebugs/table.go b/contrib/go/_std_1.23/src/internal/godebugs/table.go similarity index 80% rename from contrib/go/_std_1.22/src/internal/godebugs/table.go rename to contrib/go/_std_1.23/src/internal/godebugs/table.go index 11c5b7d6fdb9..473a0992df89 100644 --- a/contrib/go/_std_1.22/src/internal/godebugs/table.go +++ b/contrib/go/_std_1.23/src/internal/godebugs/table.go @@ -25,18 +25,20 @@ type Info struct { // Note: After adding entries to this table, update the list in doc/godebug.md as well. // (Otherwise the test in this package will fail.) var All = []Info{ + {Name: "asynctimerchan", Package: "time", Changed: 23, Old: "1"}, {Name: "execerrdot", Package: "os/exec"}, {Name: "gocachehash", Package: "cmd/go"}, {Name: "gocachetest", Package: "cmd/go"}, {Name: "gocacheverify", Package: "cmd/go"}, - {Name: "gotypesalias", Package: "go/types"}, + {Name: "gotypesalias", Package: "go/types", Changed: 23, Old: "0"}, {Name: "http2client", Package: "net/http"}, {Name: "http2debug", Package: "net/http", Opaque: true}, {Name: "http2server", Package: "net/http"}, {Name: "httplaxcontentlength", Package: "net/http", Changed: 22, Old: "1"}, {Name: "httpmuxgo121", Package: "net/http", Changed: 22, Old: "1"}, + {Name: "httpservecontentkeepheaders", Package: "net/http", Changed: 23, Old: "1"}, {Name: "installgoroot", Package: "go/build"}, - {Name: "jstmpllitinterp", Package: "html/template"}, + {Name: "jstmpllitinterp", Package: "html/template", Opaque: true}, // bug #66217: remove Opaque //{Name: "multipartfiles", Package: "mime/multipart"}, {Name: "multipartmaxheaders", Package: "mime/multipart"}, {Name: "multipartmaxparts", Package: "mime/multipart"}, @@ -47,9 +49,15 @@ var All = []Info{ {Name: "randautoseed", Package: "math/rand"}, {Name: "tarinsecurepath", Package: "archive/tar"}, {Name: "tls10server", Package: "crypto/tls", Changed: 22, Old: "1"}, + {Name: "tls3des", Package: "crypto/tls", Changed: 23, Old: "1"}, + {Name: "tlskyber", Package: "crypto/tls", Changed: 23, Old: "0", Opaque: true}, {Name: "tlsmaxrsasize", Package: "crypto/tls"}, {Name: "tlsrsakex", Package: "crypto/tls", Changed: 22, Old: "1"}, {Name: "tlsunsafeekm", Package: "crypto/tls", Changed: 22, Old: "1"}, + {Name: "winreadlinkvolume", Package: "os", Changed: 23, Old: "0"}, + {Name: "winsymlink", Package: "os", Changed: 23, Old: "0"}, + {Name: "x509keypairleaf", Package: "crypto/tls", Changed: 23, Old: "0"}, + {Name: "x509negativeserial", Package: "crypto/x509", Changed: 23, Old: "1"}, {Name: "x509sha1", Package: "crypto/x509"}, {Name: "x509usefallbackroots", Package: "crypto/x509"}, {Name: "x509usepolicies", Package: "crypto/x509"}, diff --git a/contrib/go/_std_1.22/src/internal/godebugs/ya.make b/contrib/go/_std_1.23/src/internal/godebugs/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/godebugs/ya.make rename to contrib/go/_std_1.23/src/internal/godebugs/ya.make diff --git a/contrib/go/_std_1.23/src/internal/goexperiment/exp_aliastypeparams_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_aliastypeparams_off.go new file mode 100644 index 000000000000..620d34ec795a --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/goexperiment/exp_aliastypeparams_off.go @@ -0,0 +1,8 @@ +// Code generated by mkconsts.go. DO NOT EDIT. + +//go:build !goexperiment.aliastypeparams + +package goexperiment + +const AliasTypeParams = false +const AliasTypeParamsInt = 0 diff --git a/contrib/go/_std_1.23/src/internal/goexperiment/exp_aliastypeparams_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_aliastypeparams_on.go new file mode 100644 index 000000000000..8f6872cdcd36 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/goexperiment/exp_aliastypeparams_on.go @@ -0,0 +1,8 @@ +// Code generated by mkconsts.go. DO NOT EDIT. + +//go:build goexperiment.aliastypeparams + +package goexperiment + +const AliasTypeParams = true +const AliasTypeParamsInt = 1 diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_arenas_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_arenas_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_arenas_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_arenas_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_arenas_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_arenas_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_arenas_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_arenas_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_boringcrypto_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_boringcrypto_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_boringcrypto_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_boringcrypto_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_boringcrypto_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_boringcrypto_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_boringcrypto_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_boringcrypto_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_cacheprog_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_cacheprog_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_cacheprog_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_cacheprog_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_cacheprog_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_cacheprog_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_cacheprog_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_cacheprog_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_cgocheck2_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_cgocheck2_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_cgocheck2_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_cgocheck2_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_cgocheck2_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_cgocheck2_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_cgocheck2_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_cgocheck2_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_coverageredesign_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_coverageredesign_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_coverageredesign_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_coverageredesign_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_coverageredesign_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_coverageredesign_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_coverageredesign_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_coverageredesign_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_fieldtrack_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_fieldtrack_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_fieldtrack_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_fieldtrack_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_fieldtrack_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_fieldtrack_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_fieldtrack_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_fieldtrack_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_heapminimum512kib_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_heapminimum512kib_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_heapminimum512kib_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_heapminimum512kib_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_heapminimum512kib_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_heapminimum512kib_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_heapminimum512kib_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_heapminimum512kib_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_loopvar_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_loopvar_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_loopvar_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_loopvar_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_loopvar_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_loopvar_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_loopvar_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_loopvar_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_newinliner_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_newinliner_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_newinliner_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_newinliner_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_newinliner_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_newinliner_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_newinliner_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_newinliner_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_preemptibleloops_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_preemptibleloops_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_preemptibleloops_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_preemptibleloops_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_preemptibleloops_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_preemptibleloops_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_preemptibleloops_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_preemptibleloops_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_rangefunc_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_rangefunc_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_rangefunc_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_rangefunc_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_rangefunc_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_rangefunc_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_rangefunc_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_rangefunc_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiargs_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiargs_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiargs_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiargs_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiargs_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiargs_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiargs_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiargs_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiwrappers_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiwrappers_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiwrappers_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiwrappers_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiwrappers_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiwrappers_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_regabiwrappers_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_regabiwrappers_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_staticlockranking_off.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_staticlockranking_off.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_staticlockranking_off.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_staticlockranking_off.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/exp_staticlockranking_on.go b/contrib/go/_std_1.23/src/internal/goexperiment/exp_staticlockranking_on.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/exp_staticlockranking_on.go rename to contrib/go/_std_1.23/src/internal/goexperiment/exp_staticlockranking_on.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/flags.go b/contrib/go/_std_1.23/src/internal/goexperiment/flags.go similarity index 88% rename from contrib/go/_std_1.22/src/internal/goexperiment/flags.go rename to contrib/go/_std_1.23/src/internal/goexperiment/flags.go index dacc4c3b1357..3f9c5af68e36 100644 --- a/contrib/go/_std_1.22/src/internal/goexperiment/flags.go +++ b/contrib/go/_std_1.23/src/internal/goexperiment/flags.go @@ -91,12 +91,6 @@ type Flags struct { // to the outside world. Arenas bool - // PageTrace enables GODEBUG=pagetrace=/path/to/result. This feature - // is a GOEXPERIMENT due to a security risk with setuid binaries: - // this compels the Go runtime to write to some arbitrary file, which - // may be exploited. - PageTrace bool - // CgoCheck2 enables an expensive cgo rule checker. // When this experiment is enabled, cgo rule checks occur regardless // of the GODEBUG=cgocheck setting provided at runtime. @@ -117,14 +111,8 @@ type Flags struct { // RangeFunc enables range over func. RangeFunc bool - // Range enables range over int and func. - Range bool - - // AllocHeaders enables a different, more efficient way for the GC to - // manage heap metadata. - AllocHeaders bool - - // ExecTracer2 controls whether to use the new execution trace - // implementation. - ExecTracer2 bool + // AliasTypeParams enables type parameters for alias types. + // Requires that gotypesalias=1 is set with GODEBUG. + // This flag will be removed with Go 1.24. + AliasTypeParams bool } diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/mkconsts.go b/contrib/go/_std_1.23/src/internal/goexperiment/mkconsts.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goexperiment/mkconsts.go rename to contrib/go/_std_1.23/src/internal/goexperiment/mkconsts.go diff --git a/contrib/go/_std_1.22/src/internal/goexperiment/ya.make b/contrib/go/_std_1.23/src/internal/goexperiment/ya.make similarity index 84% rename from contrib/go/_std_1.22/src/internal/goexperiment/ya.make rename to contrib/go/_std_1.23/src/internal/goexperiment/ya.make index 1c716226c606..8009d90e8ba0 100644 --- a/contrib/go/_std_1.22/src/internal/goexperiment/ya.make +++ b/contrib/go/_std_1.23/src/internal/goexperiment/ya.make @@ -1,18 +1,16 @@ GO_LIBRARY() IF (TRUE) SRCS( - exp_allocheaders_off.go + exp_aliastypeparams_off.go exp_arenas_off.go exp_boringcrypto_off.go exp_cacheprog_off.go exp_cgocheck2_off.go exp_coverageredesign_off.go - exp_exectracer2_off.go exp_fieldtrack_off.go exp_heapminimum512kib_off.go exp_loopvar_off.go exp_newinliner_off.go - exp_pagetrace_off.go exp_preemptibleloops_off.go exp_rangefunc_off.go exp_regabiargs_off.go diff --git a/contrib/go/_std_1.22/src/internal/goos/gengoos.go b/contrib/go/_std_1.23/src/internal/goos/gengoos.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/gengoos.go rename to contrib/go/_std_1.23/src/internal/goos/gengoos.go diff --git a/contrib/go/_std_1.22/src/internal/goos/goos.go b/contrib/go/_std_1.23/src/internal/goos/goos.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/goos.go rename to contrib/go/_std_1.23/src/internal/goos/goos.go diff --git a/contrib/go/_std_1.22/src/internal/goos/nonunix.go b/contrib/go/_std_1.23/src/internal/goos/nonunix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/nonunix.go rename to contrib/go/_std_1.23/src/internal/goos/nonunix.go diff --git a/contrib/go/_std_1.22/src/internal/goos/unix.go b/contrib/go/_std_1.23/src/internal/goos/unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/unix.go rename to contrib/go/_std_1.23/src/internal/goos/unix.go diff --git a/contrib/go/_std_1.22/src/internal/goos/ya.make b/contrib/go/_std_1.23/src/internal/goos/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/ya.make rename to contrib/go/_std_1.23/src/internal/goos/ya.make diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_aix.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_aix.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_aix.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_android.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_android.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_android.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_android.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_darwin.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_darwin.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_darwin.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_dragonfly.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_dragonfly.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_dragonfly.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_freebsd.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_freebsd.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_freebsd.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_hurd.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_hurd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_hurd.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_hurd.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_illumos.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_illumos.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_illumos.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_illumos.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_ios.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_ios.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_ios.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_ios.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_js.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_js.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_js.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_js.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_linux.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_linux.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_linux.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_netbsd.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_netbsd.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_netbsd.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_openbsd.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_openbsd.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_openbsd.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_plan9.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_plan9.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_plan9.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_solaris.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_solaris.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_solaris.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_wasip1.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_wasip1.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_wasip1.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_windows.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_windows.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_windows.go diff --git a/contrib/go/_std_1.22/src/internal/goos/zgoos_zos.go b/contrib/go/_std_1.23/src/internal/goos/zgoos_zos.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/goos/zgoos_zos.go rename to contrib/go/_std_1.23/src/internal/goos/zgoos_zos.go diff --git a/contrib/go/_std_1.22/src/internal/gover/gover.go b/contrib/go/_std_1.23/src/internal/gover/gover.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/gover/gover.go rename to contrib/go/_std_1.23/src/internal/gover/gover.go diff --git a/contrib/go/_std_1.22/src/internal/gover/ya.make b/contrib/go/_std_1.23/src/internal/gover/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/gover/ya.make rename to contrib/go/_std_1.23/src/internal/gover/ya.make diff --git a/contrib/go/_std_1.22/src/internal/goversion/goversion.go b/contrib/go/_std_1.23/src/internal/goversion/goversion.go similarity index 95% rename from contrib/go/_std_1.22/src/internal/goversion/goversion.go rename to contrib/go/_std_1.23/src/internal/goversion/goversion.go index 770ef113561e..a9d6f12ee14d 100644 --- a/contrib/go/_std_1.22/src/internal/goversion/goversion.go +++ b/contrib/go/_std_1.23/src/internal/goversion/goversion.go @@ -9,4 +9,4 @@ package goversion // // It should be updated at the start of each development cycle to be // the version of the next Go 1.x release. See golang.org/issue/40705. -const Version = 22 +const Version = 23 diff --git a/contrib/go/_std_1.22/src/internal/goversion/ya.make b/contrib/go/_std_1.23/src/internal/goversion/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/goversion/ya.make rename to contrib/go/_std_1.23/src/internal/goversion/ya.make diff --git a/contrib/go/_std_1.22/src/internal/itoa/itoa.go b/contrib/go/_std_1.23/src/internal/itoa/itoa.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/itoa/itoa.go rename to contrib/go/_std_1.23/src/internal/itoa/itoa.go diff --git a/contrib/go/_std_1.22/src/internal/itoa/ya.make b/contrib/go/_std_1.23/src/internal/itoa/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/itoa/ya.make rename to contrib/go/_std_1.23/src/internal/itoa/ya.make diff --git a/contrib/go/_std_1.23/src/internal/msan/doc.go b/contrib/go/_std_1.23/src/internal/msan/doc.go new file mode 100644 index 000000000000..e68d341e7ad2 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/msan/doc.go @@ -0,0 +1,9 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package msan contains helper functions for manually instrumenting code +// for the memory sanitizer. +// This package exports the private msan routines in runtime unconditionally +// but without the "msan" build tag they are no-ops. +package msan diff --git a/contrib/go/_std_1.23/src/internal/msan/msan.go b/contrib/go/_std_1.23/src/internal/msan/msan.go new file mode 100644 index 000000000000..518153ee5a91 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/msan/msan.go @@ -0,0 +1,28 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build msan + +package msan + +import ( + "unsafe" +) + +const Enabled = true + +//go:linkname Read runtime.msanread +func Read(addr unsafe.Pointer, sz uintptr) + +//go:linkname Write runtime.msanwrite +func Write(addr unsafe.Pointer, sz uintptr) + +//go:linkname Malloc runtime.msanmalloc +func Malloc(addr unsafe.Pointer, sz uintptr) + +//go:linkname Free runtime.msanfree +func Free(addr unsafe.Pointer, sz uintptr) + +//go:linkname Move runtime.msanmove +func Move(dst, src unsafe.Pointer, sz uintptr) diff --git a/contrib/go/_std_1.23/src/internal/msan/nomsan.go b/contrib/go/_std_1.23/src/internal/msan/nomsan.go new file mode 100644 index 000000000000..3dccda3ffd4a --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/msan/nomsan.go @@ -0,0 +1,28 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !msan + +package msan + +import ( + "unsafe" +) + +const Enabled = false + +func Read(addr unsafe.Pointer, sz uintptr) { +} + +func Write(addr unsafe.Pointer, sz uintptr) { +} + +func Malloc(addr unsafe.Pointer, sz uintptr) { +} + +func Free(addr unsafe.Pointer, sz uintptr) { +} + +func Move(dst, src unsafe.Pointer, sz uintptr) { +} diff --git a/contrib/go/_std_1.23/src/internal/msan/ya.make b/contrib/go/_std_1.23/src/internal/msan/ya.make new file mode 100644 index 000000000000..6ef64ba5f992 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/msan/ya.make @@ -0,0 +1,8 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + doc.go + nomsan.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/nettrace/nettrace.go b/contrib/go/_std_1.23/src/internal/nettrace/nettrace.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/nettrace/nettrace.go rename to contrib/go/_std_1.23/src/internal/nettrace/nettrace.go diff --git a/contrib/go/_std_1.22/src/internal/nettrace/ya.make b/contrib/go/_std_1.23/src/internal/nettrace/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/nettrace/ya.make rename to contrib/go/_std_1.23/src/internal/nettrace/ya.make diff --git a/contrib/go/_std_1.22/src/internal/oserror/errors.go b/contrib/go/_std_1.23/src/internal/oserror/errors.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/oserror/errors.go rename to contrib/go/_std_1.23/src/internal/oserror/errors.go diff --git a/contrib/go/_std_1.22/src/internal/oserror/ya.make b/contrib/go/_std_1.23/src/internal/oserror/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/oserror/ya.make rename to contrib/go/_std_1.23/src/internal/oserror/ya.make diff --git a/contrib/go/_std_1.22/src/internal/poll/copy_file_range_linux.go b/contrib/go/_std_1.23/src/internal/poll/copy_file_range_linux.go similarity index 89% rename from contrib/go/_std_1.22/src/internal/poll/copy_file_range_linux.go rename to contrib/go/_std_1.23/src/internal/poll/copy_file_range_linux.go index ba33f5145d48..3d51333d73e9 100644 --- a/contrib/go/_std_1.22/src/internal/poll/copy_file_range_linux.go +++ b/contrib/go/_std_1.23/src/internal/poll/copy_file_range_linux.go @@ -10,27 +10,20 @@ import ( "syscall" ) -var ( - kernelVersion53Once sync.Once - kernelVersion53 bool -) +var isKernelVersionGE53 = sync.OnceValue(func() bool { + major, minor := unix.KernelVersion() + // copy_file_range(2) is broken in various ways on kernels older than 5.3, + // see https://go.dev/issue/42400 and + // https://man7.org/linux/man-pages/man2/copy_file_range.2.html#VERSIONS + return major > 5 || (major == 5 && minor >= 3) +}) const maxCopyFileRangeRound = 1 << 30 // CopyFileRange copies at most remain bytes of data from src to dst, using // the copy_file_range system call. dst and src must refer to regular files. func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err error) { - kernelVersion53Once.Do(func() { - major, minor := unix.KernelVersion() - // copy_file_range(2) is broken in various ways on kernels older than 5.3, - // see issue #42400 and - // https://man7.org/linux/man-pages/man2/copy_file_range.2.html#VERSIONS - if major > 5 || (major == 5 && minor >= 3) { - kernelVersion53 = true - } - }) - - if !kernelVersion53 { + if !isKernelVersionGE53() { return 0, false, nil } diff --git a/contrib/go/_std_1.22/src/internal/poll/errno_unix.go b/contrib/go/_std_1.23/src/internal/poll/errno_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/errno_unix.go rename to contrib/go/_std_1.23/src/internal/poll/errno_unix.go diff --git a/contrib/go/_std_1.22/src/internal/poll/errno_windows.go b/contrib/go/_std_1.23/src/internal/poll/errno_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/errno_windows.go rename to contrib/go/_std_1.23/src/internal/poll/errno_windows.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd.go b/contrib/go/_std_1.23/src/internal/poll/fd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd.go rename to contrib/go/_std_1.23/src/internal/poll/fd.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_fsync_darwin.go b/contrib/go/_std_1.23/src/internal/poll/fd_fsync_darwin.go similarity index 72% rename from contrib/go/_std_1.22/src/internal/poll/fd_fsync_darwin.go rename to contrib/go/_std_1.23/src/internal/poll/fd_fsync_darwin.go index 731b7fd5bd65..e55b490d41a4 100644 --- a/contrib/go/_std_1.22/src/internal/poll/fd_fsync_darwin.go +++ b/contrib/go/_std_1.23/src/internal/poll/fd_fsync_darwin.go @@ -5,6 +5,7 @@ package poll import ( + "errors" "internal/syscall/unix" "syscall" ) @@ -19,6 +20,13 @@ func (fd *FD) Fsync() error { defer fd.decref() return ignoringEINTR(func() error { _, err := unix.Fcntl(fd.Sysfd, syscall.F_FULLFSYNC, 0) + + // There are scenarios such as SMB mounts where fcntl will fail + // with ENOTSUP. In those cases fallback to fsync. + // See #64215 + if err != nil && errors.Is(err, syscall.ENOTSUP) { + err = syscall.Fsync(fd.Sysfd) + } return err }) } diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_fsync_posix.go b/contrib/go/_std_1.23/src/internal/poll/fd_fsync_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_fsync_posix.go rename to contrib/go/_std_1.23/src/internal/poll/fd_fsync_posix.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_fsync_windows.go b/contrib/go/_std_1.23/src/internal/poll/fd_fsync_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_fsync_windows.go rename to contrib/go/_std_1.23/src/internal/poll/fd_fsync_windows.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_io_plan9.go b/contrib/go/_std_1.23/src/internal/poll/fd_io_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_io_plan9.go rename to contrib/go/_std_1.23/src/internal/poll/fd_io_plan9.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_mutex.go b/contrib/go/_std_1.23/src/internal/poll/fd_mutex.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_mutex.go rename to contrib/go/_std_1.23/src/internal/poll/fd_mutex.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_opendir_darwin.go b/contrib/go/_std_1.23/src/internal/poll/fd_opendir_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_opendir_darwin.go rename to contrib/go/_std_1.23/src/internal/poll/fd_opendir_darwin.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_plan9.go b/contrib/go/_std_1.23/src/internal/poll/fd_plan9.go similarity index 92% rename from contrib/go/_std_1.22/src/internal/poll/fd_plan9.go rename to contrib/go/_std_1.23/src/internal/poll/fd_plan9.go index 7cc178a9d5a4..b65485200add 100644 --- a/contrib/go/_std_1.22/src/internal/poll/fd_plan9.go +++ b/contrib/go/_std_1.23/src/internal/poll/fd_plan9.go @@ -6,8 +6,10 @@ package poll import ( "errors" + "internal/stringslite" "io" "sync" + "syscall" "time" ) @@ -202,11 +204,11 @@ func (fd *FD) ReadUnlock() { } func isHangup(err error) bool { - return err != nil && stringsHasSuffix(err.Error(), "Hangup") + return err != nil && stringslite.HasSuffix(err.Error(), "Hangup") } func isInterrupted(err error) bool { - return err != nil && stringsHasSuffix(err.Error(), "interrupted") + return err != nil && stringslite.HasSuffix(err.Error(), "interrupted") } // IsPollDescriptor reports whether fd is the descriptor being used by the poller. @@ -230,3 +232,14 @@ func (fd *FD) RawRead(f func(uintptr) bool) error { func (fd *FD) RawWrite(f func(uintptr) bool) error { return errors.New("not implemented") } + +func DupCloseOnExec(fd int) (int, string, error) { + nfd, err := syscall.Dup(int(fd), -1) + if err != nil { + return 0, "dup", err + } + // Plan9 has no syscall.CloseOnExec but + // its forkAndExecInChild closes all fds + // not related to the fork+exec. + return nfd, "", nil +} diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_poll_js.go b/contrib/go/_std_1.23/src/internal/poll/fd_poll_js.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_poll_js.go rename to contrib/go/_std_1.23/src/internal/poll/fd_poll_js.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_poll_runtime.go b/contrib/go/_std_1.23/src/internal/poll/fd_poll_runtime.go similarity index 92% rename from contrib/go/_std_1.22/src/internal/poll/fd_poll_runtime.go rename to contrib/go/_std_1.23/src/internal/poll/fd_poll_runtime.go index b51535ecf2f0..b78d15647669 100644 --- a/contrib/go/_std_1.22/src/internal/poll/fd_poll_runtime.go +++ b/contrib/go/_std_1.23/src/internal/poll/fd_poll_runtime.go @@ -164,6 +164,16 @@ func setDeadlineImpl(fd *FD, t time.Time, mode int) error { // IsPollDescriptor reports whether fd is the descriptor being used by the poller. // This is only used for testing. +// +// IsPollDescriptor should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/opencontainers/runc +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname IsPollDescriptor func IsPollDescriptor(fd uintptr) bool { return runtime_isPollServerDescriptor(fd) } diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_posix.go b/contrib/go/_std_1.23/src/internal/poll/fd_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_posix.go rename to contrib/go/_std_1.23/src/internal/poll/fd_posix.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_unix.go b/contrib/go/_std_1.23/src/internal/poll/fd_unix.go similarity index 97% rename from contrib/go/_std_1.22/src/internal/poll/fd_unix.go rename to contrib/go/_std_1.23/src/internal/poll/fd_unix.go index 61c2338305ad..2535a3ae4dd4 100644 --- a/contrib/go/_std_1.22/src/internal/poll/fd_unix.go +++ b/contrib/go/_std_1.23/src/internal/poll/fd_unix.go @@ -7,6 +7,7 @@ package poll import ( + "internal/itoa" "internal/syscall/unix" "io" "sync/atomic" @@ -379,6 +380,14 @@ func (fd *FD) Write(p []byte) (int, error) { } n, err := ignoringEINTRIO(syscall.Write, fd.Sysfd, p[nn:max]) if n > 0 { + if n > max-nn { + // This can reportedly happen when using + // some VPN software. Issue #61060. + // If we don't check this we will panic + // with slice bounds out of range. + // Use a more informative panic. + panic("invalid return from write: got " + itoa.Itoa(n) + " from a write of " + itoa.Itoa(max-nn)) + } nn += n } if nn == len(p) { @@ -678,7 +687,7 @@ func (fd *FD) Dup() (int, string, error) { // On Unix variants only, expose the IO event for the net code. -// WaitWrite waits until data can be read from fd. +// WaitWrite waits until data can be written to fd. func (fd *FD) WaitWrite() error { return fd.pd.waitWrite(fd.isFile) } diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_unixjs.go b/contrib/go/_std_1.23/src/internal/poll/fd_unixjs.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_unixjs.go rename to contrib/go/_std_1.23/src/internal/poll/fd_unixjs.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_wasip1.go b/contrib/go/_std_1.23/src/internal/poll/fd_wasip1.go similarity index 93% rename from contrib/go/_std_1.22/src/internal/poll/fd_wasip1.go rename to contrib/go/_std_1.23/src/internal/poll/fd_wasip1.go index aecd89669b48..195aaa9517d1 100644 --- a/contrib/go/_std_1.22/src/internal/poll/fd_wasip1.go +++ b/contrib/go/_std_1.23/src/internal/poll/fd_wasip1.go @@ -5,6 +5,7 @@ package poll import ( + "internal/byteorder" "sync/atomic" "syscall" "unsafe" @@ -224,15 +225,11 @@ func readIntLE(b []byte, size uintptr) uint64 { case 1: return uint64(b[0]) case 2: - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 + return uint64(byteorder.LeUint16(b)) case 4: - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 + return uint64(byteorder.LeUint32(b)) case 8: - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | - uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + return uint64(byteorder.LeUint64(b)) default: panic("internal/poll: readInt with unsupported size") } diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_windows.go b/contrib/go/_std_1.23/src/internal/poll/fd_windows.go similarity index 97% rename from contrib/go/_std_1.22/src/internal/poll/fd_windows.go rename to contrib/go/_std_1.23/src/internal/poll/fd_windows.go index 2095a6aa2927..5eefeb90f193 100644 --- a/contrib/go/_std_1.22/src/internal/poll/fd_windows.go +++ b/contrib/go/_std_1.23/src/internal/poll/fd_windows.go @@ -53,14 +53,17 @@ func checkSetFileCompletionNotificationModes() { useSetFileCompletionNotificationModes = true } -func init() { +// InitWSA initiates the use of the Winsock DLL by the current process. +// It is called from the net package at init time to avoid +// loading ws2_32.dll when net is not used. +var InitWSA = sync.OnceFunc(func() { var d syscall.WSAData e := syscall.WSAStartup(uint32(0x202), &d) if e != nil { initErr = e } checkSetFileCompletionNotificationModes() -} +}) // operation contains superset of data necessary to perform all async IO. type operation struct { @@ -71,8 +74,6 @@ type operation struct { // fields used by runtime.netpoll runtimeCtx uintptr mode int32 - errno int32 - qty uint32 // fields used only by net package fd *FD @@ -83,6 +84,7 @@ type operation struct { rsan int32 handle syscall.Handle flags uint32 + qty uint32 bufs []syscall.WSABuf } @@ -174,9 +176,9 @@ func execIO(o *operation, submit func(o *operation) error) (int, error) { // Wait for our request to complete. err = fd.pd.wait(int(o.mode), fd.isFile) if err == nil { + err = windows.WSAGetOverlappedResult(fd.Sysfd, &o.o, &o.qty, false, &o.flags) // All is good. Extract our IO results and return. - if o.errno != 0 { - err = syscall.Errno(o.errno) + if err != nil { // More data available. Return back the size of received data. if err == syscall.ERROR_MORE_DATA || err == windows.WSAEMSGSIZE { return int(o.qty), err @@ -202,8 +204,8 @@ func execIO(o *operation, submit func(o *operation) error) (int, error) { } // Wait for cancellation to complete. fd.pd.waitCanceled(int(o.mode)) - if o.errno != 0 { - err = syscall.Errno(o.errno) + err = windows.WSAGetOverlappedResult(fd.Sysfd, &o.o, &o.qty, false, &o.flags) + if err != nil { if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled err = netpollErr } @@ -1329,3 +1331,17 @@ func (fd *FD) WriteMsgInet6(p []byte, oob []byte, sa *syscall.SockaddrInet6) (in }) return n, int(o.msg.Control.Len), err } + +func DupCloseOnExec(fd int) (int, string, error) { + proc, err := syscall.GetCurrentProcess() + if err != nil { + return 0, "GetCurrentProcess", err + } + + var nfd syscall.Handle + const inherit = false // analogous to CLOEXEC + if err := syscall.DuplicateHandle(proc, syscall.Handle(fd), proc, &nfd, 0, inherit, syscall.DUPLICATE_SAME_ACCESS); err != nil { + return 0, "DuplicateHandle", err + } + return int(nfd), "", nil +} diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_writev_libc.go b/contrib/go/_std_1.23/src/internal/poll/fd_writev_libc.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_writev_libc.go rename to contrib/go/_std_1.23/src/internal/poll/fd_writev_libc.go diff --git a/contrib/go/_std_1.22/src/internal/poll/fd_writev_unix.go b/contrib/go/_std_1.23/src/internal/poll/fd_writev_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/fd_writev_unix.go rename to contrib/go/_std_1.23/src/internal/poll/fd_writev_unix.go diff --git a/contrib/go/_std_1.22/src/internal/poll/file_plan9.go b/contrib/go/_std_1.23/src/internal/poll/file_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/file_plan9.go rename to contrib/go/_std_1.23/src/internal/poll/file_plan9.go diff --git a/contrib/go/_std_1.22/src/internal/poll/hook_cloexec.go b/contrib/go/_std_1.23/src/internal/poll/hook_cloexec.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/hook_cloexec.go rename to contrib/go/_std_1.23/src/internal/poll/hook_cloexec.go diff --git a/contrib/go/_std_1.22/src/internal/poll/hook_unix.go b/contrib/go/_std_1.23/src/internal/poll/hook_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/hook_unix.go rename to contrib/go/_std_1.23/src/internal/poll/hook_unix.go diff --git a/contrib/go/_std_1.22/src/internal/poll/hook_windows.go b/contrib/go/_std_1.23/src/internal/poll/hook_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/hook_windows.go rename to contrib/go/_std_1.23/src/internal/poll/hook_windows.go diff --git a/contrib/go/_std_1.22/src/internal/poll/iovec_solaris.go b/contrib/go/_std_1.23/src/internal/poll/iovec_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/iovec_solaris.go rename to contrib/go/_std_1.23/src/internal/poll/iovec_solaris.go diff --git a/contrib/go/_std_1.22/src/internal/poll/iovec_unix.go b/contrib/go/_std_1.23/src/internal/poll/iovec_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/iovec_unix.go rename to contrib/go/_std_1.23/src/internal/poll/iovec_unix.go diff --git a/contrib/go/_std_1.23/src/internal/poll/sendfile.go b/contrib/go/_std_1.23/src/internal/poll/sendfile.go new file mode 100644 index 000000000000..41b0481c1aa3 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/poll/sendfile.go @@ -0,0 +1,7 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package poll + +var TestHookDidSendFile = func(dstFD *FD, src int, written int64, err error, handled bool) {} diff --git a/contrib/go/_std_1.23/src/internal/poll/sendfile_bsd.go b/contrib/go/_std_1.23/src/internal/poll/sendfile_bsd.go new file mode 100644 index 000000000000..d1023d4ebb99 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/poll/sendfile_bsd.go @@ -0,0 +1,77 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin || dragonfly || freebsd + +package poll + +import "syscall" + +// maxSendfileSize is the largest chunk size we ask the kernel to copy +// at a time. +const maxSendfileSize int = 4 << 20 + +// SendFile wraps the sendfile system call. +func SendFile(dstFD *FD, src int, pos, remain int64) (written int64, err error, handled bool) { + defer func() { + TestHookDidSendFile(dstFD, src, written, err, handled) + }() + if err := dstFD.writeLock(); err != nil { + return 0, err, false + } + defer dstFD.writeUnlock() + + if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { + return 0, err, false + } + + dst := dstFD.Sysfd + for remain > 0 { + n := maxSendfileSize + if int64(n) > remain { + n = int(remain) + } + m := n + pos1 := pos + n, err = syscall.Sendfile(dst, src, &pos1, n) + if n > 0 { + pos += int64(n) + written += int64(n) + remain -= int64(n) + // (n, nil) indicates that sendfile(2) has transferred + // the exact number of bytes we requested, or some unretryable + // error have occurred with partial bytes sent. Either way, we + // don't need to go through the following logic to check EINTR + // or fell into dstFD.pd.waitWrite, just continue to send the + // next chunk or break the loop. + if n == m { + continue + } else if err != syscall.EAGAIN && + err != syscall.EINTR && + err != syscall.EBUSY { + // Particularly, EPIPE. Errors like that would normally lead + // the subsequent sendfile(2) call to (-1, EBADF). + break + } + } else if err != syscall.EAGAIN && err != syscall.EINTR { + // This includes syscall.ENOSYS (no kernel + // support) and syscall.EINVAL (fd types which + // don't implement sendfile), and other errors. + // We should end the loop when there is no error + // returned from sendfile(2) or it is not a retryable error. + break + } + if err == syscall.EINTR { + continue + } + if err = dstFD.pd.waitWrite(dstFD.isFile); err != nil { + break + } + } + if err == syscall.EAGAIN { + err = nil + } + handled = written != 0 || (err != syscall.ENOSYS && err != syscall.EINVAL && err != syscall.EOPNOTSUPP && err != syscall.ENOTSUP) + return +} diff --git a/contrib/go/_std_1.22/src/internal/poll/sendfile_bsd.go b/contrib/go/_std_1.23/src/internal/poll/sendfile_linux.go similarity index 56% rename from contrib/go/_std_1.22/src/internal/poll/sendfile_bsd.go rename to contrib/go/_std_1.23/src/internal/poll/sendfile_linux.go index 0f55cad73dc3..1c4130d45da8 100644 --- a/contrib/go/_std_1.22/src/internal/poll/sendfile_bsd.go +++ b/contrib/go/_std_1.23/src/internal/poll/sendfile_linux.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build darwin || dragonfly || freebsd - package poll import "syscall" @@ -13,51 +11,48 @@ import "syscall" const maxSendfileSize int = 4 << 20 // SendFile wraps the sendfile system call. -func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error, bool) { +func SendFile(dstFD *FD, src int, remain int64) (written int64, err error, handled bool) { + defer func() { + TestHookDidSendFile(dstFD, src, written, err, handled) + }() if err := dstFD.writeLock(); err != nil { return 0, err, false } defer dstFD.writeUnlock() + if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { return 0, err, false } dst := dstFD.Sysfd - var ( - written int64 - err error - handled = true - ) for remain > 0 { n := maxSendfileSize if int64(n) > remain { n = int(remain) } - pos1 := pos - n, err1 := syscall.Sendfile(dst, src, &pos1, n) + n, err = syscall.Sendfile(dst, src, nil, n) if n > 0 { - pos += int64(n) written += int64(n) remain -= int64(n) - } else if n == 0 && err1 == nil { + continue + } else if err != syscall.EAGAIN && err != syscall.EINTR { + // This includes syscall.ENOSYS (no kernel + // support) and syscall.EINVAL (fd types which + // don't implement sendfile), and other errors. + // We should end the loop when there is no error + // returned from sendfile(2) or it is not a retryable error. break } - if err1 == syscall.EINTR { + if err == syscall.EINTR { continue } - if err1 == syscall.EAGAIN { - if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil { - continue - } - } - if err1 != nil { - // This includes syscall.ENOSYS (no kernel - // support) and syscall.EINVAL (fd types which - // don't implement sendfile) - err = err1 - handled = false + if err = dstFD.pd.waitWrite(dstFD.isFile); err != nil { break } } - return written, err, handled + if err == syscall.EAGAIN { + err = nil + } + handled = written != 0 || (err != syscall.ENOSYS && err != syscall.EINVAL) + return } diff --git a/contrib/go/_std_1.22/src/internal/poll/sendfile_solaris.go b/contrib/go/_std_1.23/src/internal/poll/sendfile_solaris.go similarity index 60% rename from contrib/go/_std_1.22/src/internal/poll/sendfile_solaris.go rename to contrib/go/_std_1.23/src/internal/poll/sendfile_solaris.go index f9f685c64a64..b7c3f81a1efd 100644 --- a/contrib/go/_std_1.22/src/internal/poll/sendfile_solaris.go +++ b/contrib/go/_std_1.23/src/internal/poll/sendfile_solaris.go @@ -16,29 +16,28 @@ import "syscall" const maxSendfileSize int = 4 << 20 // SendFile wraps the sendfile system call. -func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error, bool) { +func SendFile(dstFD *FD, src int, pos, remain int64) (written int64, err error, handled bool) { + defer func() { + TestHookDidSendFile(dstFD, src, written, err, handled) + }() if err := dstFD.writeLock(); err != nil { return 0, err, false } defer dstFD.writeUnlock() + if err := dstFD.pd.prepareWrite(dstFD.isFile); err != nil { return 0, err, false } dst := dstFD.Sysfd - var ( - written int64 - err error - handled = true - ) for remain > 0 { n := maxSendfileSize if int64(n) > remain { n = int(remain) } pos1 := pos - n, err1 := syscall.Sendfile(dst, src, &pos1, n) - if err1 == syscall.EAGAIN || err1 == syscall.EINTR { + n, err = syscall.Sendfile(dst, src, &pos1, n) + if err == syscall.EAGAIN || err == syscall.EINTR { // partial write may have occurred n = int(pos1 - pos) } @@ -46,25 +45,25 @@ func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error, bool) { pos += int64(n) written += int64(n) remain -= int64(n) - } else if n == 0 && err1 == nil { + continue + } else if err != syscall.EAGAIN && err != syscall.EINTR { + // This includes syscall.ENOSYS (no kernel + // support) and syscall.EINVAL (fd types which + // don't implement sendfile), and other errors. + // We should end the loop when there is no error + // returned from sendfile(2) or it is not a retryable error. break } - if err1 == syscall.EAGAIN { - if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil { - continue - } - } - if err1 == syscall.EINTR { + if err == syscall.EINTR { continue } - if err1 != nil { - // This includes syscall.ENOSYS (no kernel - // support) and syscall.EINVAL (fd types which - // don't implement sendfile) - err = err1 - handled = false + if err = dstFD.pd.waitWrite(dstFD.isFile); err != nil { break } } - return written, err, handled + if err == syscall.EAGAIN { + err = nil + } + handled = written != 0 || (err != syscall.ENOSYS && err != syscall.EINVAL) + return } diff --git a/contrib/go/_std_1.22/src/internal/poll/sendfile_windows.go b/contrib/go/_std_1.23/src/internal/poll/sendfile_windows.go similarity index 96% rename from contrib/go/_std_1.22/src/internal/poll/sendfile_windows.go rename to contrib/go/_std_1.23/src/internal/poll/sendfile_windows.go index 8c3353bc6ffa..2ae8a8d1d791 100644 --- a/contrib/go/_std_1.22/src/internal/poll/sendfile_windows.go +++ b/contrib/go/_std_1.23/src/internal/poll/sendfile_windows.go @@ -11,6 +11,9 @@ import ( // SendFile wraps the TransmitFile call. func SendFile(fd *FD, src syscall.Handle, n int64) (written int64, err error) { + defer func() { + TestHookDidSendFile(fd, 0, written, err, written > 0) + }() if fd.kind == kindPipe { // TransmitFile does not work with pipes return 0, syscall.ESPIPE diff --git a/contrib/go/_std_1.23/src/internal/poll/sock_cloexec.go b/contrib/go/_std_1.23/src/internal/poll/sock_cloexec.go new file mode 100644 index 000000000000..cbf7021804fa --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/poll/sock_cloexec.go @@ -0,0 +1,22 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements accept for platforms that provide a fast path for +// setting SetNonblock and CloseOnExec. + +//go:build dragonfly || freebsd || (linux && !arm) || netbsd || openbsd + +package poll + +import "syscall" + +// Wrapper around the accept system call that marks the returned file +// descriptor as nonblocking and close-on-exec. +func accept(s int) (int, syscall.Sockaddr, string, error) { + ns, sa, err := Accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC) + if err != nil { + return -1, nil, "accept4", err + } + return ns, sa, "", nil +} diff --git a/contrib/go/_std_1.22/src/internal/poll/sock_cloexec_accept.go b/contrib/go/_std_1.23/src/internal/poll/sock_cloexec_accept.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/sock_cloexec_accept.go rename to contrib/go/_std_1.23/src/internal/poll/sock_cloexec_accept.go diff --git a/contrib/go/_std_1.22/src/internal/poll/sock_cloexec.go b/contrib/go/_std_1.23/src/internal/poll/sock_cloexec_solaris.go similarity index 54% rename from contrib/go/_std_1.22/src/internal/poll/sock_cloexec.go rename to contrib/go/_std_1.23/src/internal/poll/sock_cloexec_solaris.go index 361c11bc57c3..92f150b6e5d8 100644 --- a/contrib/go/_std_1.22/src/internal/poll/sock_cloexec.go +++ b/contrib/go/_std_1.23/src/internal/poll/sock_cloexec_solaris.go @@ -1,32 +1,30 @@ -// Copyright 2013 The Go Authors. All rights reserved. +// Copyright 2024 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // This file implements accept for platforms that provide a fast path for -// setting SetNonblock and CloseOnExec. - -//go:build dragonfly || freebsd || (linux && !arm) || netbsd || openbsd || solaris +// setting SetNonblock and CloseOnExec, but don't necessarily have accept4. +// The accept4(3c) function was added to Oracle Solaris in the Solaris 11.4.0 +// release. Thus, on releases prior to 11.4, we fall back to the combination +// of accept(3c) and fcntl(2). package poll -import "syscall" +import ( + "internal/syscall/unix" + "syscall" +) // Wrapper around the accept system call that marks the returned file // descriptor as nonblocking and close-on-exec. func accept(s int) (int, syscall.Sockaddr, string, error) { - ns, sa, err := Accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC) - // TODO: We can remove the fallback on Linux and *BSD, - // as currently supported versions all support accept4 - // with SOCK_CLOEXEC, but Solaris does not. See issue #59359. - switch err { - case nil: + // Perform a cheap test and try the fast path first. + if unix.SupportAccept4() { + ns, sa, err := Accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC) + if err != nil { + return -1, nil, "accept4", err + } return ns, sa, "", nil - default: // errors other than the ones listed - return -1, sa, "accept4", err - case syscall.ENOSYS: // syscall missing - case syscall.EINVAL: // some Linux use this instead of ENOSYS - case syscall.EACCES: // some Linux use this instead of ENOSYS - case syscall.EFAULT: // some Linux use this instead of ENOSYS } // See ../syscall/exec_unix.go for description of ForkLock. @@ -34,7 +32,7 @@ func accept(s int) (int, syscall.Sockaddr, string, error) { // because we have put fd.sysfd into non-blocking mode. // However, a call to the File method will put it back into // blocking mode. We can't take that risk, so no use of ForkLock here. - ns, sa, err = AcceptFunc(s) + ns, sa, err := AcceptFunc(s) if err == nil { syscall.CloseOnExec(ns) } diff --git a/contrib/go/_std_1.22/src/internal/poll/sockopt.go b/contrib/go/_std_1.23/src/internal/poll/sockopt.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/sockopt.go rename to contrib/go/_std_1.23/src/internal/poll/sockopt.go diff --git a/contrib/go/_std_1.22/src/internal/poll/sockopt_linux.go b/contrib/go/_std_1.23/src/internal/poll/sockopt_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/sockopt_linux.go rename to contrib/go/_std_1.23/src/internal/poll/sockopt_linux.go diff --git a/contrib/go/_std_1.22/src/internal/poll/sockopt_unix.go b/contrib/go/_std_1.23/src/internal/poll/sockopt_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/sockopt_unix.go rename to contrib/go/_std_1.23/src/internal/poll/sockopt_unix.go diff --git a/contrib/go/_std_1.22/src/internal/poll/sockopt_windows.go b/contrib/go/_std_1.23/src/internal/poll/sockopt_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/sockopt_windows.go rename to contrib/go/_std_1.23/src/internal/poll/sockopt_windows.go diff --git a/contrib/go/_std_1.22/src/internal/poll/sockoptip.go b/contrib/go/_std_1.23/src/internal/poll/sockoptip.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/sockoptip.go rename to contrib/go/_std_1.23/src/internal/poll/sockoptip.go diff --git a/contrib/go/_std_1.22/src/internal/poll/splice_linux.go b/contrib/go/_std_1.23/src/internal/poll/splice_linux.go similarity index 93% rename from contrib/go/_std_1.22/src/internal/poll/splice_linux.go rename to contrib/go/_std_1.23/src/internal/poll/splice_linux.go index 72cca34fe4ae..193a56215c72 100644 --- a/contrib/go/_std_1.22/src/internal/poll/splice_linux.go +++ b/contrib/go/_std_1.23/src/internal/poll/splice_linux.go @@ -31,12 +31,10 @@ const ( // // Splice gets a pipe buffer from the pool or creates a new one if needed, to serve as a buffer for the data transfer. // src and dst must both be stream-oriented sockets. -// -// If err != nil, sc is the system call which caused the error. -func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string, err error) { - p, sc, err := getPipe() +func Splice(dst, src *FD, remain int64) (written int64, handled bool, err error) { + p, err := getPipe() if err != nil { - return 0, false, sc, err + return 0, false, err } defer putPipe(p) var inPipe, n int @@ -71,9 +69,9 @@ func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string, } } if err != nil { - return written, handled, "splice", err + return written, handled, err } - return written, true, "", nil + return written, true, nil } // spliceDrain moves data from a socket to a pipe. @@ -204,15 +202,12 @@ func newPoolPipe() any { } // getPipe tries to acquire a pipe buffer from the pool or create a new one with newPipe() if it gets nil from the cache. -// -// Note that it may fail to create a new pipe buffer by newPipe(), in which case getPipe() will return a generic error -// and system call name splice in a string as the indication. -func getPipe() (*splicePipe, string, error) { +func getPipe() (*splicePipe, error) { v := splicePipePool.Get() if v == nil { - return nil, "splice", syscall.EINVAL + return nil, syscall.EINVAL } - return v.(*splicePipe), "", nil + return v.(*splicePipe), nil } func putPipe(p *splicePipe) { diff --git a/contrib/go/_std_1.22/src/internal/poll/sys_cloexec.go b/contrib/go/_std_1.23/src/internal/poll/sys_cloexec.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/poll/sys_cloexec.go rename to contrib/go/_std_1.23/src/internal/poll/sys_cloexec.go diff --git a/contrib/go/_std_1.22/src/internal/poll/writev.go b/contrib/go/_std_1.23/src/internal/poll/writev.go similarity index 96% rename from contrib/go/_std_1.22/src/internal/poll/writev.go rename to contrib/go/_std_1.23/src/internal/poll/writev.go index 75c8b642b550..fb15c2730983 100644 --- a/contrib/go/_std_1.22/src/internal/poll/writev.go +++ b/contrib/go/_std_1.23/src/internal/poll/writev.go @@ -69,9 +69,7 @@ func (fd *FD) Writev(v *[][]byte) (int64, error) { TestHookDidWritev(int(wrote)) n += int64(wrote) consume(v, int64(wrote)) - for i := range iovecs { - iovecs[i] = syscall.Iovec{} - } + clear(iovecs) if err != nil { if err == syscall.EINTR { continue diff --git a/contrib/go/_std_1.22/src/internal/poll/ya.make b/contrib/go/_std_1.23/src/internal/poll/ya.make similarity index 97% rename from contrib/go/_std_1.22/src/internal/poll/ya.make rename to contrib/go/_std_1.23/src/internal/poll/ya.make index 175eda755a51..17cf3be05f92 100644 --- a/contrib/go/_std_1.22/src/internal/poll/ya.make +++ b/contrib/go/_std_1.23/src/internal/poll/ya.make @@ -13,6 +13,7 @@ IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM6 fd_writev_libc.go hook_unix.go iovec_unix.go + sendfile.go sendfile_bsd.go sockopt.go sockopt_unix.go @@ -35,6 +36,7 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ hook_cloexec.go hook_unix.go iovec_unix.go + sendfile.go sendfile_linux.go sock_cloexec.go sockopt.go @@ -54,6 +56,7 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND AR fd_posix.go fd_windows.go hook_windows.go + sendfile.go sendfile_windows.go sockopt.go sockopt_windows.go diff --git a/contrib/go/_std_1.23/src/internal/profilerecord/profilerecord.go b/contrib/go/_std_1.23/src/internal/profilerecord/profilerecord.go new file mode 100644 index 000000000000..a5efdced8f77 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/profilerecord/profilerecord.go @@ -0,0 +1,28 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package profilerecord holds internal types used to represent profiling +// records with deep stack traces. +// +// TODO: Consider moving this to internal/runtime, see golang.org/issue/65355. +package profilerecord + +type StackRecord struct { + Stack []uintptr +} + +type MemProfileRecord struct { + AllocBytes, FreeBytes int64 + AllocObjects, FreeObjects int64 + Stack []uintptr +} + +func (r *MemProfileRecord) InUseBytes() int64 { return r.AllocBytes - r.FreeBytes } +func (r *MemProfileRecord) InUseObjects() int64 { return r.AllocObjects - r.FreeObjects } + +type BlockProfileRecord struct { + Count int64 + Cycles int64 + Stack []uintptr +} diff --git a/contrib/go/_std_1.23/src/internal/profilerecord/ya.make b/contrib/go/_std_1.23/src/internal/profilerecord/ya.make new file mode 100644 index 000000000000..2a9f803d12de --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/profilerecord/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + profilerecord.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/race/doc.go b/contrib/go/_std_1.23/src/internal/race/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/race/doc.go rename to contrib/go/_std_1.23/src/internal/race/doc.go diff --git a/contrib/go/_std_1.22/src/internal/race/norace.go b/contrib/go/_std_1.23/src/internal/race/norace.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/race/norace.go rename to contrib/go/_std_1.23/src/internal/race/norace.go diff --git a/contrib/go/_std_1.22/src/internal/race/race.go b/contrib/go/_std_1.23/src/internal/race/race.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/race/race.go rename to contrib/go/_std_1.23/src/internal/race/race.go diff --git a/contrib/go/_std_1.22/src/internal/race/ya.make b/contrib/go/_std_1.23/src/internal/race/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/race/ya.make rename to contrib/go/_std_1.23/src/internal/race/ya.make diff --git a/contrib/go/_std_1.22/src/internal/reflectlite/asm.s b/contrib/go/_std_1.23/src/internal/reflectlite/asm.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/reflectlite/asm.s rename to contrib/go/_std_1.23/src/internal/reflectlite/asm.s diff --git a/contrib/go/_std_1.22/src/internal/reflectlite/swapper.go b/contrib/go/_std_1.23/src/internal/reflectlite/swapper.go similarity index 98% rename from contrib/go/_std_1.22/src/internal/reflectlite/swapper.go rename to contrib/go/_std_1.23/src/internal/reflectlite/swapper.go index ac17d9bbc465..e5ea535d5f85 100644 --- a/contrib/go/_std_1.22/src/internal/reflectlite/swapper.go +++ b/contrib/go/_std_1.23/src/internal/reflectlite/swapper.go @@ -33,7 +33,7 @@ func Swapper(slice any) func(i, j int) { typ := v.Type().Elem().common() size := typ.Size() - hasPtr := typ.PtrBytes != 0 + hasPtr := typ.Pointers() // Some common & small cases, without using memmove: if hasPtr { diff --git a/contrib/go/_std_1.22/src/internal/reflectlite/type.go b/contrib/go/_std_1.23/src/internal/reflectlite/type.go similarity index 95% rename from contrib/go/_std_1.22/src/internal/reflectlite/type.go rename to contrib/go/_std_1.23/src/internal/reflectlite/type.go index e585d24f538c..88cc50db9eda 100644 --- a/contrib/go/_std_1.22/src/internal/reflectlite/type.go +++ b/contrib/go/_std_1.23/src/internal/reflectlite/type.go @@ -111,20 +111,6 @@ type funcType = abi.FuncType type interfaceType = abi.InterfaceType -// mapType represents a map type. -type mapType struct { - rtype - Key *abi.Type // map key type - Elem *abi.Type // map element (value) type - Bucket *abi.Type // internal bucket structure - // function for hashing keys (ptr to key, seed) -> hash - Hasher func(unsafe.Pointer, uintptr) uintptr - KeySize uint8 // size of key slot - ValueSize uint8 // size of value slot - BucketSize uint16 // size of bucket - Flags uint32 -} - // ptrType represents a pointer type. type ptrType = abi.PtrType @@ -398,10 +384,7 @@ func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { // TypeOf returns the reflection Type that represents the dynamic type of i. // If i is a nil interface value, TypeOf returns nil. func TypeOf(i any) Type { - eface := *(*emptyInterface)(unsafe.Pointer(&i)) - // Noescape so this doesn't make i to escape. See the comment - // at Value.typ for why this is safe. - return toType((*abi.Type)(noescape(unsafe.Pointer(eface.typ)))) + return toType(abi.TypeOf(i)) } func (t rtype) Implements(u Type) bool { @@ -658,8 +641,3 @@ func toType(t *abi.Type) Type { } return toRType(t) } - -// ifaceIndir reports whether t is stored indirectly in an interface value. -func ifaceIndir(t *abi.Type) bool { - return t.Kind_&abi.KindDirectIface == 0 -} diff --git a/contrib/go/_std_1.22/src/internal/reflectlite/value.go b/contrib/go/_std_1.23/src/internal/reflectlite/value.go similarity index 95% rename from contrib/go/_std_1.22/src/internal/reflectlite/value.go rename to contrib/go/_std_1.23/src/internal/reflectlite/value.go index c47e5ea12b3c..c38b498ea7e2 100644 --- a/contrib/go/_std_1.22/src/internal/reflectlite/value.go +++ b/contrib/go/_std_1.23/src/internal/reflectlite/value.go @@ -94,7 +94,7 @@ func (v Value) typ() *abi.Type { // types, held in the central map). So there is no need to // escape types. noescape here help avoid unnecessary escape // of v. - return (*abi.Type)(noescape(unsafe.Pointer(v.typ_))) + return (*abi.Type)(abi.NoEscape(unsafe.Pointer(v.typ_))) } // pointer returns the underlying pointer represented by v. @@ -113,52 +113,50 @@ func (v Value) pointer() unsafe.Pointer { func packEface(v Value) any { t := v.typ() var i any - e := (*emptyInterface)(unsafe.Pointer(&i)) + e := (*abi.EmptyInterface)(unsafe.Pointer(&i)) // First, fill in the data portion of the interface. switch { - case ifaceIndir(t): + case t.IfaceIndir(): if v.flag&flagIndir == 0 { panic("bad indir") } // Value is indirect, and so is the interface we're making. ptr := v.ptr if v.flag&flagAddr != 0 { - // TODO: pass safe boolean from valueInterface so - // we don't need to copy if safe==true? c := unsafe_New(t) typedmemmove(t, c, ptr) ptr = c } - e.word = ptr + e.Data = ptr case v.flag&flagIndir != 0: // Value is indirect, but interface is direct. We need // to load the data at v.ptr into the interface data word. - e.word = *(*unsafe.Pointer)(v.ptr) + e.Data = *(*unsafe.Pointer)(v.ptr) default: // Value is direct, and so is the interface. - e.word = v.ptr + e.Data = v.ptr } // Now, fill in the type portion. We're very careful here not // to have any operation between the e.word and e.typ assignments // that would let the garbage collector observe the partially-built // interface value. - e.typ = t + e.Type = t return i } // unpackEface converts the empty interface i to a Value. func unpackEface(i any) Value { - e := (*emptyInterface)(unsafe.Pointer(&i)) + e := (*abi.EmptyInterface)(unsafe.Pointer(&i)) // NOTE: don't read e.word until we know whether it is really a pointer or not. - t := e.typ + t := e.Type if t == nil { return Value{} } f := flag(t.Kind()) - if ifaceIndir(t) { + if t.IfaceIndir() { f |= flagIndir } - return Value{t, e.word, f} + return Value{t, e.Data, f} } // A ValueError occurs when a Value method is invoked on @@ -187,12 +185,6 @@ func methodName() string { return f.Name() } -// emptyInterface is the header for an interface{} value. -type emptyInterface struct { - typ *abi.Type - word unsafe.Pointer -} - // mustBeExported panics if f records that the value was obtained using // an unexported field. func (f flag) mustBeExported() { @@ -285,7 +277,6 @@ func valueInterface(v Value) any { })(v.ptr) } - // TODO: pass safe to packEface so we don't need to copy if safe==true? return packEface(v) } @@ -485,9 +476,3 @@ var dummy struct { b bool x any } - -//go:nosplit -func noescape(p unsafe.Pointer) unsafe.Pointer { - x := uintptr(p) - return unsafe.Pointer(x ^ 0) -} diff --git a/contrib/go/_std_1.22/src/internal/reflectlite/ya.make b/contrib/go/_std_1.23/src/internal/reflectlite/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/reflectlite/ya.make rename to contrib/go/_std_1.23/src/internal/reflectlite/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_386.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_386.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_386.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_386.go index e74dcaa92dd3..a023baddb764 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_386.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_386.go @@ -12,6 +12,7 @@ import "unsafe" // //go:linkname Load //go:linkname Loadp +//go:linkname LoadAcquintptr //go:nosplit //go:noinline diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_386.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_386.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_386.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_amd64.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_amd64.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_amd64.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_amd64.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_andor_generic.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_andor_generic.go similarity index 79% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_andor_generic.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_andor_generic.go index 00b402681ed6..433ee0bd6c21 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_andor_generic.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_andor_generic.go @@ -2,10 +2,21 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build arm || s390x || loong64 || mips || mipsle || mips64 || mips64le || wasm +//go:build arm || wasm + +// Export some functions via linkname to assembly in sync/atomic. +// +//go:linkname And32 +//go:linkname Or32 +//go:linkname And64 +//go:linkname Or64 +//go:linkname Anduintptr +//go:linkname Oruintptr package atomic +import _ "unsafe" // For linkname + //go:nosplit func And32(ptr *uint32, val uint32) uint32 { for { diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm.go index 567e95124480..b58f643ca34c 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm.go @@ -19,6 +19,7 @@ const ( // //go:linkname Xchg //go:linkname Xchguintptr +//go:linkname Xadd type spinlock struct { v uint32 diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm64.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm64.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm64.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm64.s similarity index 91% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm64.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm64.s index 3a249d3ed2b0..ede56538b880 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_arm64.s +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_arm64.s @@ -128,17 +128,21 @@ TEXT ·Store64(SB), NOSPLIT, $0-16 TEXT ·Xchg(SB), NOSPLIT, $0-20 MOVD ptr+0(FP), R0 MOVW new+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif SWPALW R1, (R0), R2 MOVW R2, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXRW (R0), R2 STLXRW R1, (R0), R3 CBNZ R3, load_store_loop MOVW R2, ret+16(FP) RET +#endif // uint64 Xchg64(ptr *uint64, new uint64) // Atomically: @@ -148,17 +152,21 @@ load_store_loop: TEXT ·Xchg64(SB), NOSPLIT, $0-24 MOVD ptr+0(FP), R0 MOVD new+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif SWPALD R1, (R0), R2 MOVD R2, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXR (R0), R2 STLXR R1, (R0), R3 CBNZ R3, load_store_loop MOVD R2, ret+16(FP) RET +#endif // bool Cas(uint32 *ptr, uint32 old, uint32 new) // Atomically: @@ -171,14 +179,17 @@ TEXT ·Cas(SB), NOSPLIT, $0-17 MOVD ptr+0(FP), R0 MOVW old+8(FP), R1 MOVW new+12(FP), R2 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif MOVD R1, R3 CASALW R3, (R0), R2 CMP R1, R3 CSET EQ, R0 MOVB R0, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXRW (R0), R3 CMPW R1, R3 @@ -189,6 +200,7 @@ ok: CSET EQ, R0 MOVB R0, ret+16(FP) RET +#endif // bool ·Cas64(uint64 *ptr, uint64 old, uint64 new) // Atomically: @@ -202,14 +214,17 @@ TEXT ·Cas64(SB), NOSPLIT, $0-25 MOVD ptr+0(FP), R0 MOVD old+8(FP), R1 MOVD new+16(FP), R2 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif MOVD R1, R3 CASALD R3, (R0), R2 CMP R1, R3 CSET EQ, R0 MOVB R0, ret+24(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXR (R0), R3 CMP R1, R3 @@ -220,6 +235,7 @@ ok: CSET EQ, R0 MOVB R0, ret+24(FP) RET +#endif // uint32 xadd(uint32 volatile *ptr, int32 delta) // Atomically: @@ -228,12 +244,15 @@ ok: TEXT ·Xadd(SB), NOSPLIT, $0-20 MOVD ptr+0(FP), R0 MOVW delta+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif LDADDALW R1, (R0), R2 ADD R1, R2 MOVW R2, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXRW (R0), R2 ADDW R2, R1, R2 @@ -241,6 +260,7 @@ load_store_loop: CBNZ R3, load_store_loop MOVW R2, ret+16(FP) RET +#endif // uint64 Xadd64(uint64 volatile *ptr, int64 delta) // Atomically: @@ -249,12 +269,15 @@ load_store_loop: TEXT ·Xadd64(SB), NOSPLIT, $0-24 MOVD ptr+0(FP), R0 MOVD delta+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif LDADDALD R1, (R0), R2 ADD R1, R2 MOVD R2, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXR (R0), R2 ADD R2, R1, R2 @@ -262,6 +285,7 @@ load_store_loop: CBNZ R3, load_store_loop MOVD R2, ret+16(FP) RET +#endif TEXT ·Xchgint32(SB), NOSPLIT, $0-20 B ·Xchg(SB) @@ -275,72 +299,91 @@ TEXT ·Xchguintptr(SB), NOSPLIT, $0-24 TEXT ·And8(SB), NOSPLIT, $0-9 MOVD ptr+0(FP), R0 MOVB val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif MVN R1, R2 LDCLRALB R2, (R0), R3 RET +#ifndef GOARM64_LSE load_store_loop: LDAXRB (R0), R2 AND R1, R2 STLXRB R2, (R0), R3 CBNZ R3, load_store_loop RET +#endif TEXT ·Or8(SB), NOSPLIT, $0-9 MOVD ptr+0(FP), R0 MOVB val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif LDORALB R1, (R0), R2 RET +#ifndef GOARM64_LSE load_store_loop: LDAXRB (R0), R2 ORR R1, R2 STLXRB R2, (R0), R3 CBNZ R3, load_store_loop RET +#endif // func And(addr *uint32, v uint32) TEXT ·And(SB), NOSPLIT, $0-12 MOVD ptr+0(FP), R0 MOVW val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif MVN R1, R2 LDCLRALW R2, (R0), R3 RET +#ifndef GOARM64_LSE load_store_loop: LDAXRW (R0), R2 AND R1, R2 STLXRW R2, (R0), R3 CBNZ R3, load_store_loop RET +#endif // func Or(addr *uint32, v uint32) TEXT ·Or(SB), NOSPLIT, $0-12 MOVD ptr+0(FP), R0 MOVW val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif LDORALW R1, (R0), R2 RET +#ifndef GOARM64_LSE load_store_loop: LDAXRW (R0), R2 ORR R1, R2 STLXRW R2, (R0), R3 CBNZ R3, load_store_loop RET +#endif // func Or32(addr *uint32, v uint32) old uint32 TEXT ·Or32(SB), NOSPLIT, $0-20 MOVD ptr+0(FP), R0 MOVW val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif LDORALW R1, (R0), R2 MOVD R2, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXRW (R0), R2 ORR R1, R2, R3 @@ -348,17 +391,21 @@ load_store_loop: CBNZ R4, load_store_loop MOVD R2, ret+16(FP) RET +#endif // func And32(addr *uint32, v uint32) old uint32 TEXT ·And32(SB), NOSPLIT, $0-20 MOVD ptr+0(FP), R0 MOVW val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif MVN R1, R2 LDCLRALW R2, (R0), R3 MOVD R3, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXRW (R0), R2 AND R1, R2, R3 @@ -366,16 +413,20 @@ load_store_loop: CBNZ R4, load_store_loop MOVD R2, ret+16(FP) RET +#endif // func Or64(addr *uint64, v uint64) old uint64 TEXT ·Or64(SB), NOSPLIT, $0-24 MOVD ptr+0(FP), R0 MOVD val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif LDORALD R1, (R0), R2 MOVD R2, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXR (R0), R2 ORR R1, R2, R3 @@ -383,17 +434,21 @@ load_store_loop: CBNZ R4, load_store_loop MOVD R2, ret+16(FP) RET +#endif // func And64(addr *uint64, v uint64) old uint64 TEXT ·And64(SB), NOSPLIT, $0-24 MOVD ptr+0(FP), R0 MOVD val+8(FP), R1 +#ifndef GOARM64_LSE MOVBU internal∕cpu·ARM64+const_offsetARM64HasATOMICS(SB), R4 CBZ R4, load_store_loop +#endif MVN R1, R2 LDCLRALD R2, (R0), R3 MOVD R3, ret+16(FP) RET +#ifndef GOARM64_LSE load_store_loop: LDAXR (R0), R2 AND R1, R2, R3 @@ -401,6 +456,7 @@ load_store_loop: CBNZ R4, load_store_loop MOVD R2, ret+16(FP) RET +#endif // func Anduintptr(addr *uintptr, v uintptr) old uintptr TEXT ·Anduintptr(SB), NOSPLIT, $0-24 diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_loong64.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_loong64.go similarity index 83% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_loong64.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_loong64.go index d82a5b8e2ac8..de6d4b4ba67d 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_loong64.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_loong64.go @@ -59,6 +59,24 @@ func Or8(ptr *uint8, val uint8) //go:noescape func Or(ptr *uint32, val uint32) +//go:noescape +func And32(ptr *uint32, val uint32) uint32 + +//go:noescape +func Or32(ptr *uint32, val uint32) uint32 + +//go:noescape +func And64(ptr *uint64, val uint64) uint64 + +//go:noescape +func Or64(ptr *uint64, val uint64) uint64 + +//go:noescape +func Anduintptr(ptr *uintptr, val uintptr) uintptr + +//go:noescape +func Oruintptr(ptr *uintptr, val uintptr) uintptr + // NOTE: Do not add atomicxor8 (XOR is not idempotent). //go:noescape diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_loong64.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_loong64.s similarity index 78% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_loong64.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_loong64.s index 34193add3ed6..1812cb95fd4e 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_loong64.s +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_loong64.s @@ -256,7 +256,67 @@ TEXT ·And(SB), NOSPLIT, $0-12 DBAR RET -// uint32 runtime∕internal∕atomic·Load(uint32 volatile* ptr) +// func Or32(addr *uint32, v uint32) old uint32 +TEXT ·Or32(SB), NOSPLIT, $0-20 + MOVV ptr+0(FP), R4 + MOVW val+8(FP), R5 + DBAR + LL (R4), R6 + OR R5, R6, R7 + SC R7, (R4) + BEQ R7, -4(PC) + DBAR + MOVW R6, ret+16(FP) + RET + +// func And32(addr *uint32, v uint32) old uint32 +TEXT ·And32(SB), NOSPLIT, $0-20 + MOVV ptr+0(FP), R4 + MOVW val+8(FP), R5 + DBAR + LL (R4), R6 + AND R5, R6, R7 + SC R7, (R4) + BEQ R7, -4(PC) + DBAR + MOVW R6, ret+16(FP) + RET + +// func Or64(addr *uint64, v uint64) old uint64 +TEXT ·Or64(SB), NOSPLIT, $0-24 + MOVV ptr+0(FP), R4 + MOVV val+8(FP), R5 + DBAR + LLV (R4), R6 + OR R5, R6, R7 + SCV R7, (R4) + BEQ R7, -4(PC) + DBAR + MOVV R6, ret+16(FP) + RET + +// func And64(addr *uint64, v uint64) old uint64 +TEXT ·And64(SB), NOSPLIT, $0-24 + MOVV ptr+0(FP), R4 + MOVV val+8(FP), R5 + DBAR + LLV (R4), R6 + AND R5, R6, R7 + SCV R7, (R4) + BEQ R7, -4(PC) + DBAR + MOVV R6, ret+16(FP) + RET + +// func Anduintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Anduintptr(SB), NOSPLIT, $0-24 + JMP ·And64(SB) + +// func Oruintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Oruintptr(SB), NOSPLIT, $0-24 + JMP ·Or64(SB) + +// uint32 internal∕runtime∕atomic·Load(uint32 volatile* ptr) TEXT ·Load(SB),NOSPLIT|NOFRAME,$0-12 MOVV ptr+0(FP), R19 DBAR @@ -265,7 +325,7 @@ TEXT ·Load(SB),NOSPLIT|NOFRAME,$0-12 MOVW R19, ret+8(FP) RET -// uint8 runtime∕internal∕atomic·Load8(uint8 volatile* ptr) +// uint8 internal∕runtime∕atomic·Load8(uint8 volatile* ptr) TEXT ·Load8(SB),NOSPLIT|NOFRAME,$0-9 MOVV ptr+0(FP), R19 DBAR @@ -274,7 +334,7 @@ TEXT ·Load8(SB),NOSPLIT|NOFRAME,$0-9 MOVB R19, ret+8(FP) RET -// uint64 runtime∕internal∕atomic·Load64(uint64 volatile* ptr) +// uint64 internal∕runtime∕atomic·Load64(uint64 volatile* ptr) TEXT ·Load64(SB),NOSPLIT|NOFRAME,$0-16 MOVV ptr+0(FP), R19 DBAR @@ -283,7 +343,7 @@ TEXT ·Load64(SB),NOSPLIT|NOFRAME,$0-16 MOVV R19, ret+8(FP) RET -// void *runtime∕internal∕atomic·Loadp(void *volatile *ptr) +// void *internal∕runtime∕atomic·Loadp(void *volatile *ptr) TEXT ·Loadp(SB),NOSPLIT|NOFRAME,$0-16 MOVV ptr+0(FP), R19 DBAR @@ -292,7 +352,7 @@ TEXT ·Loadp(SB),NOSPLIT|NOFRAME,$0-16 MOVV R19, ret+8(FP) RET -// uint32 runtime∕internal∕atomic·LoadAcq(uint32 volatile* ptr) +// uint32 internal∕runtime∕atomic·LoadAcq(uint32 volatile* ptr) TEXT ·LoadAcq(SB),NOSPLIT|NOFRAME,$0-12 JMP ·Load(SB) diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mips64x.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mips64x.go similarity index 83% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mips64x.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mips64x.go index 1e12b83801db..f434c939e3c8 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mips64x.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mips64x.go @@ -61,6 +61,24 @@ func And(ptr *uint32, val uint32) //go:noescape func Or(ptr *uint32, val uint32) +//go:noescape +func And32(ptr *uint32, val uint32) uint32 + +//go:noescape +func Or32(ptr *uint32, val uint32) uint32 + +//go:noescape +func And64(ptr *uint64, val uint64) uint64 + +//go:noescape +func Or64(ptr *uint64, val uint64) uint64 + +//go:noescape +func Anduintptr(ptr *uintptr, val uintptr) uintptr + +//go:noescape +func Oruintptr(ptr *uintptr, val uintptr) uintptr + //go:noescape func Cas64(ptr *uint64, old, new uint64) bool diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mips64x.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mips64x.s similarity index 84% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mips64x.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mips64x.s index b4411d87da65..7b0e080238d0 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mips64x.s +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mips64x.s @@ -310,6 +310,70 @@ TEXT ·And(SB), NOSPLIT, $0-12 SYNC RET +// func Or32(addr *uint32, v uint32) old uint32 +TEXT ·Or32(SB), NOSPLIT, $0-20 + MOVV ptr+0(FP), R1 + MOVW val+8(FP), R2 + + SYNC + LL (R1), R3 + OR R2, R3, R4 + SC R4, (R1) + BEQ R4, -3(PC) + SYNC + MOVW R3, ret+16(FP) + RET + +// func And32(addr *uint32, v uint32) old uint32 +TEXT ·And32(SB), NOSPLIT, $0-20 + MOVV ptr+0(FP), R1 + MOVW val+8(FP), R2 + + SYNC + LL (R1), R3 + AND R2, R3, R4 + SC R4, (R1) + BEQ R4, -3(PC) + SYNC + MOVW R3, ret+16(FP) + RET + +// func Or64(addr *uint64, v uint64) old uint64 +TEXT ·Or64(SB), NOSPLIT, $0-24 + MOVV ptr+0(FP), R1 + MOVV val+8(FP), R2 + + SYNC + LLV (R1), R3 + OR R2, R3, R4 + SCV R4, (R1) + BEQ R4, -3(PC) + SYNC + MOVV R3, ret+16(FP) + RET + +// func And64(addr *uint64, v uint64) old uint64 +TEXT ·And64(SB), NOSPLIT, $0-24 + MOVV ptr+0(FP), R1 + MOVV val+8(FP), R2 + + SYNC + LLV (R1), R3 + AND R2, R3, R4 + SCV R4, (R1) + BEQ R4, -3(PC) + SYNC + MOVV R3, ret+16(FP) + RET + +// func Anduintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Anduintptr(SB), NOSPLIT, $0-24 + JMP ·And64(SB) + +// func Oruintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Oruintptr(SB), NOSPLIT, $0-24 + JMP ·Or64(SB) + // uint32 ·Load(uint32 volatile* ptr) TEXT ·Load(SB),NOSPLIT|NOFRAME,$0-12 MOVV ptr+0(FP), R1 diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mipsx.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mipsx.go similarity index 82% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mipsx.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mipsx.go index e3dcde1bde94..aba4143ea661 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mipsx.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mipsx.go @@ -11,6 +11,8 @@ //go:linkname Cas64 //go:linkname Load64 //go:linkname Store64 +//go:linkname Or64 +//go:linkname And64 package atomic @@ -104,6 +106,26 @@ func Store64(addr *uint64, val uint64) { return } +//go:nosplit +func Or64(addr *uint64, val uint64) (old uint64) { + for { + old = *addr + if Cas64(addr, old, old|val) { + return old + } + } +} + +//go:nosplit +func And64(addr *uint64, val uint64) (old uint64) { + for { + old = *addr + if Cas64(addr, old, old&val) { + return old + } + } +} + //go:noescape func Xadd(ptr *uint32, delta int32) uint32 @@ -143,6 +165,18 @@ func And(ptr *uint32, val uint32) //go:noescape func Or(ptr *uint32, val uint32) +//go:noescape +func And32(ptr *uint32, val uint32) uint32 + +//go:noescape +func Or32(ptr *uint32, val uint32) uint32 + +//go:noescape +func Anduintptr(ptr *uintptr, val uintptr) uintptr + +//go:noescape +func Oruintptr(ptr *uintptr, val uintptr) uintptr + //go:noescape func Store(ptr *uint32, val uint32) diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mipsx.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mipsx.s similarity index 87% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mipsx.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mipsx.s index 8f5fc53cb77e..4ccc0a363b7f 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_mipsx.s +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_mipsx.s @@ -240,6 +240,42 @@ TEXT ·And(SB), NOSPLIT, $0-8 SYNC RET +// func Or32(addr *uint32, v uint32) old uint32 +TEXT ·Or32(SB), NOSPLIT, $0-12 + MOVW ptr+0(FP), R1 + MOVW val+4(FP), R2 + + SYNC + LL (R1), R3 + OR R2, R3, R4 + SC R4, (R1) + BEQ R4, -4(PC) + SYNC + MOVW R3, ret+8(FP) + RET + +// func And32(addr *uint32, v uint32) old uint32 +TEXT ·And32(SB), NOSPLIT, $0-12 + MOVW ptr+0(FP), R1 + MOVW val+4(FP), R2 + + SYNC + LL (R1), R3 + AND R2, R3, R4 + SC R4, (R1) + BEQ R4, -4(PC) + SYNC + MOVW R3, ret+8(FP) + RET + +// func Anduintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Anduintptr(SB), NOSPLIT, $0-12 + JMP ·And32(SB) + +// func Oruintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Oruintptr(SB), NOSPLIT, $0-12 + JMP ·Or32(SB) + TEXT ·spinLock(SB),NOSPLIT,$0-4 MOVW state+0(FP), R1 MOVW $1, R2 diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_ppc64x.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_ppc64x.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_ppc64x.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_ppc64x.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_riscv64.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_riscv64.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_riscv64.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_riscv64.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_s390x.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_s390x.go similarity index 85% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_s390x.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_s390x.go index 9855bf0780fb..68b4e160f9a8 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_s390x.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_s390x.go @@ -98,6 +98,24 @@ func And(ptr *uint32, val uint32) //go:noescape func Or(ptr *uint32, val uint32) +//go:noescape +func And32(ptr *uint32, val uint32) uint32 + +//go:noescape +func Or32(ptr *uint32, val uint32) uint32 + +//go:noescape +func And64(ptr *uint64, val uint64) uint64 + +//go:noescape +func Or64(ptr *uint64, val uint64) uint64 + +//go:noescape +func Anduintptr(ptr *uintptr, val uintptr) uintptr + +//go:noescape +func Oruintptr(ptr *uintptr, val uintptr) uintptr + //go:noescape func Xadd(ptr *uint32, delta int32) uint32 diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_s390x.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_s390x.s similarity index 82% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_s390x.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_s390x.s index a0c204b0e121..6e4ea0e32a7f 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_s390x.s +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_s390x.s @@ -246,3 +246,59 @@ TEXT ·And(SB), NOSPLIT, $0-12 MOVW val+8(FP), R4 LAN R4, R6, 0(R3) // R6 = *R3; *R3 &= R4; (atomic) RET + +// func Or32(addr *uint32, v uint32) old uint32 +TEXT ·Or32(SB), NOSPLIT, $0-20 + MOVD ptr+0(FP), R4 + MOVW val+8(FP), R5 + MOVW (R4), R3 +repeat: + OR R5, R3, R6 + CS R3, R6, (R4) // if R3==(R4) then (R4)=R6 else R3=(R4) + BNE repeat + MOVW R3, ret+16(FP) + RET + +// func And32(addr *uint32, v uint32) old uint32 +TEXT ·And32(SB), NOSPLIT, $0-20 + MOVD ptr+0(FP), R4 + MOVW val+8(FP), R5 + MOVW (R4), R3 +repeat: + AND R5, R3, R6 + CS R3, R6, (R4) // if R3==(R4) then (R4)=R6 else R3=(R4) + BNE repeat + MOVW R3, ret+16(FP) + RET + +// func Or64(addr *uint64, v uint64) old uint64 +TEXT ·Or64(SB), NOSPLIT, $0-24 + MOVD ptr+0(FP), R4 + MOVD val+8(FP), R5 + MOVD (R4), R3 +repeat: + OR R5, R3, R6 + CSG R3, R6, (R4) // if R3==(R4) then (R4)=R6 else R3=(R4) + BNE repeat + MOVD R3, ret+16(FP) + RET + +// func And64(addr *uint64, v uint64) old uint64 +TEXT ·And64(SB), NOSPLIT, $0-24 + MOVD ptr+0(FP), R4 + MOVD val+8(FP), R5 + MOVD (R4), R3 +repeat: + AND R5, R3, R6 + CSG R3, R6, (R4) // if R3==(R4) then (R4)=R6 else R3=(R4) + BNE repeat + MOVD R3, ret+16(FP) + RET + +// func Anduintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Anduintptr(SB), NOSPLIT, $0-24 + BR ·And64(SB) + +// func Oruintptr(addr *uintptr, v uintptr) old uintptr +TEXT ·Oruintptr(SB), NOSPLIT, $0-24 + BR ·Or64(SB) diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_wasm.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_wasm.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_wasm.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_wasm.go index 835fc43ccf9f..d1dcfec7adde 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_wasm.go +++ b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_wasm.go @@ -13,6 +13,7 @@ //go:linkname Loadint32 //go:linkname Loadint64 //go:linkname Loaduintptr +//go:linkname LoadAcquintptr //go:linkname Xadd //go:linkname Xaddint32 //go:linkname Xaddint64 @@ -33,6 +34,7 @@ //go:linkname Storeint32 //go:linkname Storeint64 //go:linkname Storeuintptr +//go:linkname StoreReluintptr package atomic diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_wasm.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/atomic_wasm.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/atomic_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/doc.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/doc.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/doc.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/stubs.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/stubs.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/stubs.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/stubs.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/sys_linux_arm.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/sys_linux_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/sys_linux_arm.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/sys_linux_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/sys_nonlinux_arm.s b/contrib/go/_std_1.23/src/internal/runtime/atomic/sys_nonlinux_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/sys_nonlinux_arm.s rename to contrib/go/_std_1.23/src/internal/runtime/atomic/sys_nonlinux_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/types.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/types.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/types.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/types.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/types_64bit.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/types_64bit.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/types_64bit.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/types_64bit.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/unaligned.go b/contrib/go/_std_1.23/src/internal/runtime/atomic/unaligned.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/unaligned.go rename to contrib/go/_std_1.23/src/internal/runtime/atomic/unaligned.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/atomic/ya.make b/contrib/go/_std_1.23/src/internal/runtime/atomic/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/atomic/ya.make rename to contrib/go/_std_1.23/src/internal/runtime/atomic/ya.make diff --git a/contrib/go/_std_1.23/src/internal/runtime/exithook/hooks.go b/contrib/go/_std_1.23/src/internal/runtime/exithook/hooks.go new file mode 100644 index 000000000000..eb8aa1ce0a5c --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/exithook/hooks.go @@ -0,0 +1,85 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package exithook provides limited support for on-exit cleanup. +// +// CAREFUL! The expectation is that Add should only be called +// from a safe context (e.g. not an error/panic path or signal +// handler, preemption enabled, allocation allowed, write barriers +// allowed, etc), and that the exit function F will be invoked under +// similar circumstances. That is the say, we are expecting that F +// uses normal / high-level Go code as opposed to one of the more +// restricted dialects used for the trickier parts of the runtime. +package exithook + +import ( + "internal/runtime/atomic" + _ "unsafe" // for linkname +) + +// A Hook is a function to be run at program termination +// (when someone invokes os.Exit, or when main.main returns). +// Hooks are run in reverse order of registration: +// the first hook added is the last one run. +type Hook struct { + F func() // func to run + RunOnFailure bool // whether to run on non-zero exit code +} + +var ( + locked atomic.Int32 + runGoid atomic.Uint64 + hooks []Hook + running bool + + // runtime sets these for us + Gosched func() + Goid func() uint64 + Throw func(string) +) + +// Add adds a new exit hook. +func Add(h Hook) { + for !locked.CompareAndSwap(0, 1) { + Gosched() + } + hooks = append(hooks, h) + locked.Store(0) +} + +// Run runs the exit hooks. +// +// If an exit hook panics, Run will throw with the panic on the stack. +// If an exit hook invokes exit in the same goroutine, the goroutine will throw. +// If an exit hook invokes exit in another goroutine, that exit will block. +func Run(code int) { + for !locked.CompareAndSwap(0, 1) { + if Goid() == runGoid.Load() { + Throw("exit hook invoked exit") + } + Gosched() + } + defer locked.Store(0) + runGoid.Store(Goid()) + defer runGoid.Store(0) + + defer func() { + if e := recover(); e != nil { + Throw("exit hook invoked panic") + } + }() + + for len(hooks) > 0 { + h := hooks[len(hooks)-1] + hooks = hooks[:len(hooks)-1] + if code != 0 && !h.RunOnFailure { + continue + } + h.F() + } +} + +type exitError string + +func (e exitError) Error() string { return string(e) } diff --git a/contrib/go/_std_1.23/src/internal/runtime/exithook/ya.make b/contrib/go/_std_1.23/src/internal/runtime/exithook/ya.make new file mode 100644 index 000000000000..352818b36253 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/exithook/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + hooks.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_386.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_386.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_386.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_amd64.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_amd64.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_arm.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_arm.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_arm64.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_arm64.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_loong64.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_loong64.s similarity index 65% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_loong64.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_loong64.s index 11c5bc2468d5..ff8ad75b055d 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_loong64.s +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_loong64.s @@ -22,7 +22,6 @@ // r2 | R5 | R5 // err | R6 | part of R4 TEXT ·Syscall6(SB),NOSPLIT,$0-80 -#ifdef GOEXPERIMENT_regabiargs MOVV R4, R11 // syscall entry MOVV R5, R4 MOVV R6, R5 @@ -30,39 +29,14 @@ TEXT ·Syscall6(SB),NOSPLIT,$0-80 MOVV R8, R7 MOVV R9, R8 MOVV R10, R9 -#else - MOVV num+0(FP), R11 // syscall entry - MOVV a1+8(FP), R4 - MOVV a2+16(FP), R5 - MOVV a3+24(FP), R6 - MOVV a4+32(FP), R7 - MOVV a5+40(FP), R8 - MOVV a6+48(FP), R9 -#endif SYSCALL -#ifdef GOEXPERIMENT_regabiargs MOVV R0, R5 // r2 is not used. Always set to 0. MOVW $-4096, R12 BGEU R12, R4, ok SUBVU R4, R0, R6 // errno MOVV $-1, R4 // r1 -#else - MOVW $-4096, R12 - BGEU R12, R4, ok - MOVV $-1, R12 - MOVV R12, r1+56(FP) - MOVV R0, r2+64(FP) - SUBVU R4, R0, R4 - MOVV R4, errno+72(FP) -#endif RET ok: -#ifdef GOEXPERIMENT_regabiargs // r1 already in R4 MOVV R0, R6 // errno -#else - MOVV R4, r1+56(FP) - MOVV R0, r2+64(FP) // r2 is not used. Always set to 0. - MOVV R0, errno+72(FP) -#endif RET diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_mips64x.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_mips64x.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_mipsx.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_mipsx.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_ppc64x.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_ppc64x.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_riscv64.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_riscv64.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_s390x.s b/contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/asm_linux_s390x.s rename to contrib/go/_std_1.23/src/internal/runtime/syscall/asm_linux_s390x.s diff --git a/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux.go new file mode 100644 index 000000000000..b2e36a244f82 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux.go @@ -0,0 +1,19 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +const ( + EPOLLIN = 0x1 + EPOLLOUT = 0x4 + EPOLLERR = 0x8 + EPOLLHUP = 0x10 + EPOLLRDHUP = 0x2000 + EPOLLET = 0x80000000 + EPOLL_CLOEXEC = 0x80000 + EPOLL_CTL_ADD = 0x1 + EPOLL_CTL_DEL = 0x2 + EPOLL_CTL_MOD = 0x3 + EFD_CLOEXEC = 0x80000 +) diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_386.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_386.go similarity index 63% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_386.go rename to contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_386.go index dc723a60b244..68e687fb14b7 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_386.go +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_386.go @@ -6,21 +6,14 @@ package syscall const ( SYS_FCNTL = 55 + SYS_MPROTECT = 125 SYS_EPOLL_CTL = 255 SYS_EPOLL_PWAIT = 319 SYS_EPOLL_CREATE1 = 329 SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 328 - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 + EFD_NONBLOCK = 0x800 ) type EpollEvent struct { diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_amd64.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_amd64.go similarity index 63% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_amd64.go rename to contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_amd64.go index 886eb5bda250..ec480f5817e0 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_amd64.go +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_amd64.go @@ -5,22 +5,15 @@ package syscall const ( + SYS_MPROTECT = 10 SYS_FCNTL = 72 SYS_EPOLL_CTL = 233 SYS_EPOLL_PWAIT = 281 SYS_EPOLL_CREATE1 = 291 SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 290 - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 + EFD_NONBLOCK = 0x800 ) type EpollEvent struct { diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_arm.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_arm.go similarity index 64% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_arm.go rename to contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_arm.go index 8f812a2f68b5..c5d150301230 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_arm.go +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_arm.go @@ -6,21 +6,14 @@ package syscall const ( SYS_FCNTL = 55 + SYS_MPROTECT = 125 SYS_EPOLL_CTL = 251 SYS_EPOLL_PWAIT = 346 SYS_EPOLL_CREATE1 = 357 SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 356 - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 + EFD_NONBLOCK = 0x800 ) type EpollEvent struct { diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_arm64.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_arm64.go similarity index 64% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_arm64.go rename to contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_arm64.go index 48e11b0c512f..f743fe31a58d 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_arm64.go +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_arm64.go @@ -9,18 +9,11 @@ const ( SYS_EPOLL_CTL = 21 SYS_EPOLL_PWAIT = 22 SYS_FCNTL = 25 + SYS_MPROTECT = 226 SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 19 - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 + EFD_NONBLOCK = 0x800 ) type EpollEvent struct { diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_loong64.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_loong64.go similarity index 64% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_loong64.go rename to contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_loong64.go index b78ef818614c..82218d15099a 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_loong64.go +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_loong64.go @@ -9,18 +9,11 @@ const ( SYS_EPOLL_CTL = 21 SYS_EPOLL_PWAIT = 22 SYS_FCNTL = 25 + SYS_MPROTECT = 226 SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 19 - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 + EFD_NONBLOCK = 0x800 ) type EpollEvent struct { diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_mips64x.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_mips64x.go similarity index 67% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_mips64x.go rename to contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_mips64x.go index 92b49ca969cb..4e0fd1f5d1b1 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_mips64x.go +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_mips64x.go @@ -7,22 +7,15 @@ package syscall const ( + SYS_MPROTECT = 5010 SYS_FCNTL = 5070 SYS_EPOLL_CTL = 5208 SYS_EPOLL_PWAIT = 5272 SYS_EPOLL_CREATE1 = 5285 SYS_EPOLL_PWAIT2 = 5441 + SYS_EVENTFD2 = 5284 - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 + EFD_NONBLOCK = 0x80 ) type EpollEvent struct { diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_mipsx.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_mipsx.go similarity index 66% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_mipsx.go rename to contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_mipsx.go index e28d09c7f135..b87a355093e4 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_mipsx.go +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_mipsx.go @@ -8,21 +8,14 @@ package syscall const ( SYS_FCNTL = 4055 + SYS_MPROTECT = 4125 SYS_EPOLL_CTL = 4249 SYS_EPOLL_PWAIT = 4313 SYS_EPOLL_CREATE1 = 4326 SYS_EPOLL_PWAIT2 = 4441 + SYS_EVENTFD2 = 4325 - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 + EFD_NONBLOCK = 0x80 ) type EpollEvent struct { diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_ppc64x.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_ppc64x.go similarity index 67% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_ppc64x.go rename to contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_ppc64x.go index a74483eb6d71..8235edd795fa 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_ppc64x.go +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_ppc64x.go @@ -8,21 +8,14 @@ package syscall const ( SYS_FCNTL = 55 + SYS_MPROTECT = 125 SYS_EPOLL_CTL = 237 SYS_EPOLL_PWAIT = 303 SYS_EPOLL_CREATE1 = 315 SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 314 - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 + EFD_NONBLOCK = 0x800 ) type EpollEvent struct { diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_riscv64.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_riscv64.go similarity index 64% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_riscv64.go rename to contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_riscv64.go index b78ef818614c..82218d15099a 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_riscv64.go +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_riscv64.go @@ -9,18 +9,11 @@ const ( SYS_EPOLL_CTL = 21 SYS_EPOLL_PWAIT = 22 SYS_FCNTL = 25 + SYS_MPROTECT = 226 SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 19 - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 + EFD_NONBLOCK = 0x800 ) type EpollEvent struct { diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_s390x.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_s390x.go similarity index 64% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_s390x.go rename to contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_s390x.go index a7bb1ba66d66..08073c01f091 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/defs_linux_s390x.go +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/defs_linux_s390x.go @@ -6,21 +6,14 @@ package syscall const ( SYS_FCNTL = 55 + SYS_MPROTECT = 125 SYS_EPOLL_CTL = 250 SYS_EPOLL_PWAIT = 312 SYS_EPOLL_CREATE1 = 327 SYS_EPOLL_PWAIT2 = 441 + SYS_EVENTFD2 = 323 - EPOLLIN = 0x1 - EPOLLOUT = 0x4 - EPOLLERR = 0x8 - EPOLLHUP = 0x10 - EPOLLRDHUP = 0x2000 - EPOLLET = 0x80000000 - EPOLL_CLOEXEC = 0x80000 - EPOLL_CTL_ADD = 0x1 - EPOLL_CTL_DEL = 0x2 - EPOLL_CTL_MOD = 0x3 + EFD_NONBLOCK = 0x800 ) type EpollEvent struct { diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/syscall_linux.go b/contrib/go/_std_1.23/src/internal/runtime/syscall/syscall_linux.go similarity index 56% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/syscall_linux.go rename to contrib/go/_std_1.23/src/internal/runtime/syscall/syscall_linux.go index 7209634edb3f..83df825169b9 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/syscall_linux.go +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/syscall_linux.go @@ -15,29 +15,6 @@ import ( // Syscall6 calls system call number 'num' with arguments a1-6. func Syscall6(num, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr) -// syscall_RawSyscall6 is a push linkname to export Syscall6 as -// syscall.RawSyscall6. -// -// //go:uintptrkeepalive because the uintptr argument may be converted pointers -// that need to be kept alive in the caller (this is implied for Syscall6 since -// it has no body). -// -// //go:nosplit because stack copying does not account for uintptrkeepalive, so -// the stack must not grow. Stack copying cannot blindly assume that all -// uintptr arguments are pointers, because some values may look like pointers, -// but not really be pointers, and adjusting their value would break the call. -// -// This is a separate wrapper because we can't export one function as two -// names. The assembly implementations name themselves Syscall6 would not be -// affected by a linkname. -// -//go:uintptrkeepalive -//go:nosplit -//go:linkname syscall_RawSyscall6 syscall.RawSyscall6 -func syscall_RawSyscall6(num, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, errno uintptr) { - return Syscall6(num, a1, a2, a3, a4, a5, a6) -} - func EpollCreate1(flags int32) (fd int32, errno uintptr) { r1, _, e := Syscall6(SYS_EPOLL_CREATE1, uintptr(flags), 0, 0, 0, 0, 0) return int32(r1), e @@ -60,3 +37,8 @@ func EpollCtl(epfd, op, fd int32, event *EpollEvent) (errno uintptr) { _, _, e := Syscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0) return e } + +func Eventfd(initval, flags int32) (fd int32, errno uintptr) { + r1, _, e := Syscall6(SYS_EVENTFD2, uintptr(initval), uintptr(flags), 0, 0, 0, 0) + return int32(r1), e +} diff --git a/contrib/go/_std_1.22/src/runtime/internal/syscall/ya.make b/contrib/go/_std_1.23/src/internal/runtime/syscall/ya.make similarity index 93% rename from contrib/go/_std_1.22/src/runtime/internal/syscall/ya.make rename to contrib/go/_std_1.23/src/internal/runtime/syscall/ya.make index 87ade4449e61..3df67558d913 100644 --- a/contrib/go/_std_1.22/src/runtime/internal/syscall/ya.make +++ b/contrib/go/_std_1.23/src/internal/runtime/syscall/ya.make @@ -2,12 +2,14 @@ GO_LIBRARY() IF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( asm_linux_arm64.s + defs_linux.go defs_linux_arm64.go syscall_linux.go ) ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( asm_linux_amd64.s + defs_linux.go defs_linux_amd64.go syscall_linux.go ) diff --git a/contrib/go/_std_1.22/src/internal/singleflight/singleflight.go b/contrib/go/_std_1.23/src/internal/singleflight/singleflight.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/singleflight/singleflight.go rename to contrib/go/_std_1.23/src/internal/singleflight/singleflight.go diff --git a/contrib/go/_std_1.22/src/internal/singleflight/ya.make b/contrib/go/_std_1.23/src/internal/singleflight/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/singleflight/ya.make rename to contrib/go/_std_1.23/src/internal/singleflight/ya.make diff --git a/contrib/go/_std_1.23/src/internal/stringslite/strings.go b/contrib/go/_std_1.23/src/internal/stringslite/strings.go new file mode 100644 index 000000000000..4114b8613000 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/stringslite/strings.go @@ -0,0 +1,150 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package stringslite implements a subset of strings, +// only using packages that may be imported by "os". +// +// Tests for these functions are in the strings package. +package stringslite + +import ( + "internal/bytealg" + "unsafe" +) + +func HasPrefix(s, prefix string) bool { + return len(s) >= len(prefix) && s[0:len(prefix)] == prefix +} + +func HasSuffix(s, suffix string) bool { + return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix +} + +func IndexByte(s string, c byte) int { + return bytealg.IndexByteString(s, c) +} + +func Index(s, substr string) int { + n := len(substr) + switch { + case n == 0: + return 0 + case n == 1: + return IndexByte(s, substr[0]) + case n == len(s): + if substr == s { + return 0 + } + return -1 + case n > len(s): + return -1 + case n <= bytealg.MaxLen: + // Use brute force when s and substr both are small + if len(s) <= bytealg.MaxBruteForce { + return bytealg.IndexString(s, substr) + } + c0 := substr[0] + c1 := substr[1] + i := 0 + t := len(s) - n + 1 + fails := 0 + for i < t { + if s[i] != c0 { + // IndexByte is faster than bytealg.IndexString, so use it as long as + // we're not getting lots of false positives. + o := IndexByte(s[i+1:t], c0) + if o < 0 { + return -1 + } + i += o + 1 + } + if s[i+1] == c1 && s[i:i+n] == substr { + return i + } + fails++ + i++ + // Switch to bytealg.IndexString when IndexByte produces too many false positives. + if fails > bytealg.Cutover(i) { + r := bytealg.IndexString(s[i:], substr) + if r >= 0 { + return r + i + } + return -1 + } + } + return -1 + } + c0 := substr[0] + c1 := substr[1] + i := 0 + t := len(s) - n + 1 + fails := 0 + for i < t { + if s[i] != c0 { + o := IndexByte(s[i+1:t], c0) + if o < 0 { + return -1 + } + i += o + 1 + } + if s[i+1] == c1 && s[i:i+n] == substr { + return i + } + i++ + fails++ + if fails >= 4+i>>4 && i < t { + // See comment in ../bytes/bytes.go. + j := bytealg.IndexRabinKarp(s[i:], substr) + if j < 0 { + return -1 + } + return i + j + } + } + return -1 +} + +func Cut(s, sep string) (before, after string, found bool) { + if i := Index(s, sep); i >= 0 { + return s[:i], s[i+len(sep):], true + } + return s, "", false +} + +func CutPrefix(s, prefix string) (after string, found bool) { + if !HasPrefix(s, prefix) { + return s, false + } + return s[len(prefix):], true +} + +func CutSuffix(s, suffix string) (before string, found bool) { + if !HasSuffix(s, suffix) { + return s, false + } + return s[:len(s)-len(suffix)], true +} + +func TrimPrefix(s, prefix string) string { + if HasPrefix(s, prefix) { + return s[len(prefix):] + } + return s +} + +func TrimSuffix(s, suffix string) string { + if HasSuffix(s, suffix) { + return s[:len(s)-len(suffix)] + } + return s +} + +func Clone(s string) string { + if len(s) == 0 { + return "" + } + b := make([]byte, len(s)) + copy(b, s) + return unsafe.String(&b[0], len(b)) +} diff --git a/contrib/go/_std_1.23/src/internal/stringslite/ya.make b/contrib/go/_std_1.23/src/internal/stringslite/ya.make new file mode 100644 index 000000000000..f101487a00e4 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/stringslite/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + strings.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/internal/syscall/execenv/execenv_default.go b/contrib/go/_std_1.23/src/internal/syscall/execenv/execenv_default.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/execenv/execenv_default.go rename to contrib/go/_std_1.23/src/internal/syscall/execenv/execenv_default.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/execenv/execenv_windows.go b/contrib/go/_std_1.23/src/internal/syscall/execenv/execenv_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/execenv/execenv_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/execenv/execenv_windows.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/execenv/ya.make b/contrib/go/_std_1.23/src/internal/syscall/execenv/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/execenv/ya.make rename to contrib/go/_std_1.23/src/internal/syscall/execenv/ya.make diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/arc4random_darwin.go b/contrib/go/_std_1.23/src/internal/syscall/unix/arc4random_darwin.go new file mode 100644 index 000000000000..a78204a3559a --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/arc4random_darwin.go @@ -0,0 +1,24 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import ( + "internal/abi" + "unsafe" +) + +//go:cgo_import_dynamic libc_arc4random_buf arc4random_buf "/usr/lib/libSystem.B.dylib" + +func libc_arc4random_buf_trampoline() + +// ARC4Random calls the macOS arc4random_buf(3) function. +func ARC4Random(p []byte) { + // macOS 11 and 12 abort if length is 0. + if len(p) == 0 { + return + } + syscall_syscall(abi.FuncPCABI0(libc_arc4random_buf_trampoline), + uintptr(unsafe.Pointer(unsafe.SliceData(p))), uintptr(len(p)), 0) +} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/asm_aix_ppc64.s b/contrib/go/_std_1.23/src/internal/syscall/unix/asm_aix_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/asm_aix_ppc64.s rename to contrib/go/_std_1.23/src/internal/syscall/unix/asm_aix_ppc64.s diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/asm_darwin.s b/contrib/go/_std_1.23/src/internal/syscall/unix/asm_darwin.s similarity index 90% rename from contrib/go/_std_1.22/src/internal/syscall/unix/asm_darwin.s rename to contrib/go/_std_1.23/src/internal/syscall/unix/asm_darwin.s index 10d16ce87f09..99f28765fe0c 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/asm_darwin.s +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/asm_darwin.s @@ -4,6 +4,7 @@ #include "textflag.h" +TEXT ·libc_arc4random_buf_trampoline(SB),NOSPLIT,$0-0; JMP libc_arc4random_buf(SB) TEXT ·libc_getaddrinfo_trampoline(SB),NOSPLIT,$0-0; JMP libc_getaddrinfo(SB) TEXT ·libc_freeaddrinfo_trampoline(SB),NOSPLIT,$0-0; JMP libc_freeaddrinfo(SB) TEXT ·libc_getnameinfo_trampoline(SB),NOSPLIT,$0-0; JMP libc_getnameinfo(SB) @@ -21,3 +22,4 @@ TEXT ·libc_getpwuid_r_trampoline(SB),NOSPLIT,$0-0; JMP libc_getpwuid_r(SB) TEXT ·libc_getgrnam_r_trampoline(SB),NOSPLIT,$0-0; JMP libc_getgrnam_r(SB) TEXT ·libc_getgrgid_r_trampoline(SB),NOSPLIT,$0-0; JMP libc_getgrgid_r(SB) TEXT ·libc_sysconf_trampoline(SB),NOSPLIT,$0-0; JMP libc_sysconf(SB) +TEXT ·libc_faccessat_trampoline(SB),NOSPLIT,$0-0; JMP libc_faccessat(SB) diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/asm_openbsd.s b/contrib/go/_std_1.23/src/internal/syscall/unix/asm_openbsd.s new file mode 100644 index 000000000000..cc54a14ca5e3 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/asm_openbsd.s @@ -0,0 +1,10 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build openbsd && !mips64 + +#include "textflag.h" + +TEXT ·libc_faccessat_trampoline(SB),NOSPLIT,$0-0 + JMP libc_faccessat(SB) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/asm_solaris.s b/contrib/go/_std_1.23/src/internal/syscall/unix/asm_solaris.s similarity index 82% rename from contrib/go/_std_1.22/src/internal/syscall/unix/asm_solaris.s rename to contrib/go/_std_1.23/src/internal/syscall/unix/asm_solaris.s index 205733831586..361ca7fc2a8c 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/asm_solaris.s +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/asm_solaris.s @@ -8,3 +8,6 @@ TEXT ·syscall6(SB),NOSPLIT,$0-88 JMP syscall·sysvicall6(SB) + +TEXT ·rawSyscall6(SB),NOSPLIT,$0-88 + JMP syscall·rawSysvicall6(SB) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_aix.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_aix.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_aix.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_fstatat.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_fstatat.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_fstatat.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_fstatat.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_fstatat2.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_fstatat2.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_fstatat2.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_fstatat2.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_js.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_js.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_js.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_js.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_libc.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_libc.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_libc.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_libc.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_libc2.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_libc2.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_libc2.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_libc2.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_solaris.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_solaris.go similarity index 73% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_solaris.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_solaris.go index 4ab224d670b9..ae1c1d64ca7b 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/at_solaris.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/at_solaris.go @@ -9,9 +9,13 @@ import "syscall" // Implemented as sysvicall6 in runtime/syscall_solaris.go. func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) +// Implemented as rawsysvicall6 in runtime/syscall_solaris.go. +func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) + //go:cgo_import_dynamic libc_fstatat fstatat "libc.so" //go:cgo_import_dynamic libc_openat openat "libc.so" //go:cgo_import_dynamic libc_unlinkat unlinkat "libc.so" +//go:cgo_import_dynamic libc_uname uname "libc.so" const ( AT_REMOVEDIR = 0x1 diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_darwin.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_darwin.go similarity index 55% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_darwin.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_darwin.go index 208ff34d038e..77b0af80b5de 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_darwin.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_darwin.go @@ -4,7 +4,11 @@ package unix -const AT_REMOVEDIR = 0x80 -const AT_SYMLINK_NOFOLLOW = 0x0020 +const ( + AT_EACCESS = 0x10 + AT_FDCWD = -0x2 + AT_REMOVEDIR = 0x80 + AT_SYMLINK_NOFOLLOW = 0x0020 -const UTIME_OMIT = -0x2 + UTIME_OMIT = -0x2 +) diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_dragonfly.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_dragonfly.go new file mode 100644 index 000000000000..a8164dcc8ec7 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_dragonfly.go @@ -0,0 +1,20 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import "syscall" + +const ( + unlinkatTrap uintptr = syscall.SYS_UNLINKAT + openatTrap uintptr = syscall.SYS_OPENAT + fstatatTrap uintptr = syscall.SYS_FSTATAT + + AT_EACCESS = 0x4 + AT_FDCWD = 0xfffafdcd + AT_REMOVEDIR = 0x2 + AT_SYMLINK_NOFOLLOW = 0x1 + + UTIME_OMIT = -0x2 +) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_freebsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_freebsd.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_freebsd.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_fstatat64_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_fstatat64_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_fstatat64_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_fstatat64_linux.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_fstatat_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_fstatat_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_fstatat_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_fstatat_linux.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_linux.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_netbsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_netbsd.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_netbsd.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_newfstatat_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_newfstatat_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_newfstatat_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_newfstatat_linux.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_dragonfly.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_openbsd.go similarity index 76% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_dragonfly.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_openbsd.go index 9ac1f919f147..3b0c0dbd19cc 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/at_sysnum_dragonfly.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/at_sysnum_openbsd.go @@ -11,10 +11,10 @@ const openatTrap uintptr = syscall.SYS_OPENAT const fstatatTrap uintptr = syscall.SYS_FSTATAT const ( - AT_EACCESS = 0x4 - AT_FDCWD = 0xfffafdcd - AT_REMOVEDIR = 0x2 - AT_SYMLINK_NOFOLLOW = 0x1 + AT_EACCESS = 0x1 + AT_FDCWD = -0x64 + AT_REMOVEDIR = 0x08 + AT_SYMLINK_NOFOLLOW = 0x02 UTIME_OMIT = -0x1 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/at_wasip1.go b/contrib/go/_std_1.23/src/internal/syscall/unix/at_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/at_wasip1.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/at_wasip1.go diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/constants.go b/contrib/go/_std_1.23/src/internal/syscall/unix/constants.go new file mode 100644 index 000000000000..28092c2ddfde --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/constants.go @@ -0,0 +1,18 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix + +package unix + +const ( + R_OK = 0x4 + W_OK = 0x2 + X_OK = 0x1 + + // NoFollowErrno is the error returned from open/openat called with + // O_NOFOLLOW flag, when the trailing component (basename) of the path + // is a symbolic link. + NoFollowErrno = noFollowErrno +) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/copy_file_range_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/copy_file_range_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/copy_file_range_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/copy_file_range_linux.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_bsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_bsd.go similarity index 90% rename from contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_bsd.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_bsd.go index 3411e3ac40c3..7077af17b672 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_bsd.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build dragonfly || freebsd || netbsd +//go:build dragonfly || freebsd || netbsd || (openbsd && mips64) package unix diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_darwin.go b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_darwin.go new file mode 100644 index 000000000000..0fa8d17afeae --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_darwin.go @@ -0,0 +1,31 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import ( + "internal/abi" + "syscall" + "unsafe" +) + +func libc_faccessat_trampoline() + +//go:cgo_import_dynamic libc_faccessat faccessat "/usr/lib/libSystem.B.dylib" + +func faccessat(dirfd int, path string, mode uint32, flags int) error { + p, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_faccessat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(p)), uintptr(mode), uintptr(flags), 0, 0) + if errno != 0 { + return errno + } + return nil +} + +func Eaccess(path string, mode uint32) error { + return faccessat(AT_FDCWD, path, mode, AT_EACCESS) +} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_linux.go diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_openbsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_openbsd.go new file mode 100644 index 000000000000..5e91f11f6654 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_openbsd.go @@ -0,0 +1,36 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build openbsd && !mips64 + +package unix + +import ( + "internal/abi" + "syscall" + "unsafe" +) + +//go:linkname syscall_syscall6 syscall.syscall6 +func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) + +func libc_faccessat_trampoline() + +//go:cgo_import_dynamic libc_faccessat faccessat "libc.so" + +func faccessat(dirfd int, path string, mode uint32, flags int) error { + p, err := syscall.BytePtrFromString(path) + if err != nil { + return err + } + _, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_faccessat_trampoline), uintptr(dirfd), uintptr(unsafe.Pointer(p)), uintptr(mode), uintptr(flags), 0, 0) + if errno != 0 { + return errno + } + return err +} + +func Eaccess(path string, mode uint32) error { + return faccessat(AT_FDCWD, path, mode, AT_EACCESS) +} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_other.go b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_other.go similarity index 75% rename from contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_other.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_other.go index 19a2be587e48..3da3a64f0e6a 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/eaccess_other.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/eaccess_other.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build unix && !dragonfly && !freebsd && !linux && !netbsd +//go:build unix && !darwin && !dragonfly && !freebsd && !linux && !openbsd && !netbsd package unix diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/fallocate_freebsd_386.go b/contrib/go/_std_1.23/src/internal/syscall/unix/fallocate_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/fallocate_freebsd_386.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/fallocate_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/fallocate_freebsd_64bit.go b/contrib/go/_std_1.23/src/internal/syscall/unix/fallocate_freebsd_64bit.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/fallocate_freebsd_64bit.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/fallocate_freebsd_64bit.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/fallocate_freebsd_arm.go b/contrib/go/_std_1.23/src/internal/syscall/unix/fallocate_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/fallocate_freebsd_arm.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/fallocate_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/fcntl_js.go b/contrib/go/_std_1.23/src/internal/syscall/unix/fcntl_js.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/fcntl_js.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/fcntl_js.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/fcntl_unix.go b/contrib/go/_std_1.23/src/internal/syscall/unix/fcntl_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/fcntl_unix.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/fcntl_unix.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/fcntl_wasip1.go b/contrib/go/_std_1.23/src/internal/syscall/unix/fcntl_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/fcntl_wasip1.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/fcntl_wasip1.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_netbsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getentropy_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_netbsd.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getentropy_netbsd.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_openbsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getentropy_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_openbsd.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getentropy_openbsd.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_openbsd_mips64.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getentropy_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getentropy_openbsd_mips64.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getentropy_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getrandom.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getrandom.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getrandom.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getrandom.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_dragonfly.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_dragonfly.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_dragonfly.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_freebsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_freebsd.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_freebsd.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_linux.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_solaris.go b/contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/getrandom_solaris.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/getrandom_solaris.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/ioctl_aix.go b/contrib/go/_std_1.23/src/internal/syscall/unix/ioctl_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/ioctl_aix.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/ioctl_aix.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/kernel_version_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/kernel_version_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_linux.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/kernel_version_other.go b/contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_other.go similarity index 88% rename from contrib/go/_std_1.22/src/internal/syscall/unix/kernel_version_other.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_other.go index 00af9f2ba018..fc65c1c823c7 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/kernel_version_other.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_other.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !linux +//go:build !linux && !solaris package unix diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_solaris.go b/contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_solaris.go new file mode 100644 index 000000000000..3f399411d76b --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/kernel_version_solaris.go @@ -0,0 +1,106 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import ( + "runtime" + "sync" + "syscall" + "unsafe" +) + +//go:linkname procUname libc_uname + +var procUname uintptr + +// utsname represents the fields of a struct utsname defined in . +type utsname struct { + Sysname [257]byte + Nodename [257]byte + Release [257]byte + Version [257]byte + Machine [257]byte +} + +// KernelVersion returns major and minor kernel version numbers +// parsed from the syscall.Uname's Version field, or (0, 0) if the +// version can't be obtained or parsed. +func KernelVersion() (major int, minor int) { + var un utsname + _, _, errno := rawSyscall6(uintptr(unsafe.Pointer(&procUname)), 1, uintptr(unsafe.Pointer(&un)), 0, 0, 0, 0, 0) + if errno != 0 { + return 0, 0 + } + + // The version string is in the form "...." + // on Solaris: https://blogs.oracle.com/solaris/post/whats-in-a-uname- + // Therefore, we use the Version field on Solaris when available. + ver := un.Version[:] + if runtime.GOOS == "illumos" { + // Illumos distributions use different formats without a parsable + // and unified pattern for the Version field while Release level + // string is guaranteed to be in x.y or x.y.z format regardless of + // whether the kernel is Solaris or illumos. + ver = un.Release[:] + } + + parseNext := func() (n int) { + for i, c := range ver { + if c == '.' { + ver = ver[i+1:] + return + } + if '0' <= c && c <= '9' { + n = n*10 + int(c-'0') + } + } + ver = nil + return + } + + major = parseNext() + minor = parseNext() + + return +} + +// SupportSockNonblockCloexec tests if SOCK_NONBLOCK and SOCK_CLOEXEC are supported +// for socket() system call, returns true if affirmative. +var SupportSockNonblockCloexec = sync.OnceValue(func() bool { + // First test if socket() supports SOCK_NONBLOCK and SOCK_CLOEXEC directly. + s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, 0) + if err == nil { + syscall.Close(s) + return true + } + if err != syscall.EPROTONOSUPPORT && err != syscall.EINVAL { + // Something wrong with socket(), fall back to checking the kernel version. + major, minor := KernelVersion() + if runtime.GOOS == "illumos" { + return major > 5 || (major == 5 && minor >= 11) // minimal requirement is SunOS 5.11 + } + return major > 11 || (major == 11 && minor >= 4) + } + return false +}) + +// SupportAccept4 tests whether accept4 system call is available. +var SupportAccept4 = sync.OnceValue(func() bool { + for { + // Test if the accept4() is available. + _, _, err := syscall.Accept4(0, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC) + if err == syscall.EINTR { + continue + } + return err != syscall.ENOSYS + } +}) + +// SupportTCPKeepAliveIdleIntvlCNT determines whether the TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT +// are available by checking the kernel version for Solaris 11.4. +var SupportTCPKeepAliveIdleIntvlCNT = sync.OnceValue(func() bool { + major, minor := KernelVersion() + return major > 11 || (major == 11 && minor >= 4) +}) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/net.go b/contrib/go/_std_1.23/src/internal/syscall/unix/net.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/net.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/net.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/net_darwin.go b/contrib/go/_std_1.23/src/internal/syscall/unix/net_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/net_darwin.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/net_darwin.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/net_js.go b/contrib/go/_std_1.23/src/internal/syscall/unix/net_js.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/net_js.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/net_js.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/net_wasip1.go b/contrib/go/_std_1.23/src/internal/syscall/unix/net_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/net_wasip1.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/net_wasip1.go diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_bsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_bsd.go new file mode 100644 index 000000000000..32c4de119012 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_bsd.go @@ -0,0 +1,14 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build dragonfly || freebsd + +package unix + +import "syscall" + +// References: +// - https://man.freebsd.org/cgi/man.cgi?open(2) +// - https://man.dragonflybsd.org/?command=open§ion=2 +const noFollowErrno = syscall.EMLINK diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_netbsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_netbsd.go new file mode 100644 index 000000000000..3ae91e79cddc --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_netbsd.go @@ -0,0 +1,10 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import "syscall" + +// Reference: https://man.netbsd.org/open.2 +const noFollowErrno = syscall.EFTYPE diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_posix.go b/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_posix.go new file mode 100644 index 000000000000..de2ea14fc80b --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/nofollow_posix.go @@ -0,0 +1,22 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix && !dragonfly && !freebsd && !netbsd + +package unix + +import "syscall" + +// POSIX.1-2008 says it's ELOOP. Most platforms follow: +// +// - aix: O_NOFOLLOW not documented (https://www.ibm.com/docs/ssw_aix_73/o_bostechref/open.html), assuming ELOOP +// - android: see linux +// - darwin: https://github.com/apple/darwin-xnu/blob/main/bsd/man/man2/open.2 +// - hurd: who knows if it works at all (https://www.gnu.org/software/hurd/open_issues/open_symlink.html) +// - illumos: https://illumos.org/man/2/open +// - ios: see darwin +// - linux: https://man7.org/linux/man-pages/man2/openat.2.html +// - openbsd: https://man.openbsd.org/open.2 +// - solaris: https://docs.oracle.com/cd/E23824_01/html/821-1463/open-2.html +const noFollowErrno = syscall.ELOOP diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/nonblocking_js.go b/contrib/go/_std_1.23/src/internal/syscall/unix/nonblocking_js.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/nonblocking_js.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/nonblocking_js.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/nonblocking_unix.go b/contrib/go/_std_1.23/src/internal/syscall/unix/nonblocking_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/nonblocking_unix.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/nonblocking_unix.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/nonblocking_wasip1.go b/contrib/go/_std_1.23/src/internal/syscall/unix/nonblocking_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/nonblocking_wasip1.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/nonblocking_wasip1.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/pidfd_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/pidfd_linux.go similarity index 63% rename from contrib/go/_std_1.22/src/internal/syscall/unix/pidfd_linux.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/pidfd_linux.go index 02cfaa062cae..e9417623db79 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/pidfd_linux.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/pidfd_linux.go @@ -13,3 +13,11 @@ func PidFDSendSignal(pidfd uintptr, s syscall.Signal) error { } return nil } + +func PidFDOpen(pid, flags int) (uintptr, error) { + pidfd, _, errno := syscall.Syscall(pidfdOpenTrap, uintptr(pid), uintptr(flags), 0) + if errno != 0 { + return ^uintptr(0), errno + } + return uintptr(pidfd), nil +} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/pty_darwin.go b/contrib/go/_std_1.23/src/internal/syscall/unix/pty_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/pty_darwin.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/pty_darwin.go diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux.go new file mode 100644 index 000000000000..9f83114e45cf --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux.go @@ -0,0 +1,64 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import ( + "syscall" +) + +const is64bit = ^uint(0) >> 63 // 0 for 32-bit hosts, 1 for 64-bit ones. + +// SiginfoChild is a struct filled in by Linux waitid syscall. +// In C, siginfo_t contains a union with multiple members; +// this struct corresponds to one used when Signo is SIGCHLD. +// +// NOTE fields are exported to be used by TestSiginfoChildLayout. +type SiginfoChild struct { + Signo int32 + siErrnoCode // Two int32 fields, swapped on MIPS. + _ [is64bit]int32 // Extra padding for 64-bit hosts only. + + // End of common part. Beginning of signal-specific part. + + Pid int32 + Uid uint32 + Status int32 + + // Pad to 128 bytes. + _ [128 - (6+is64bit)*4]byte +} + +const ( + // Possible values for SiginfoChild.Code field. + _CLD_EXITED int32 = 1 + _CLD_KILLED = 2 + _CLD_DUMPED = 3 + _CLD_TRAPPED = 4 + _CLD_STOPPED = 5 + _CLD_CONTINUED = 6 + + // These are the same as in syscall/syscall_linux.go. + core = 0x80 + stopped = 0x7f + continued = 0xffff +) + +// WaitStatus converts SiginfoChild, as filled in by the waitid syscall, +// to syscall.WaitStatus. +func (s *SiginfoChild) WaitStatus() (ws syscall.WaitStatus) { + switch s.Code { + case _CLD_EXITED: + ws = syscall.WaitStatus(s.Status << 8) + case _CLD_DUMPED: + ws = syscall.WaitStatus(s.Status) | core + case _CLD_KILLED: + ws = syscall.WaitStatus(s.Status) + case _CLD_TRAPPED, _CLD_STOPPED: + ws = syscall.WaitStatus(s.Status<<8) | stopped + case _CLD_CONTINUED: + ws = continued + } + return +} diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux_mipsx.go b/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux_mipsx.go new file mode 100644 index 000000000000..2fca0c55055e --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux_mipsx.go @@ -0,0 +1,12 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && (mips || mipsle || mips64 || mips64le) + +package unix + +type siErrnoCode struct { + Code int32 + Errno int32 +} diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux_other.go b/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux_other.go new file mode 100644 index 000000000000..cfdc4ddf51ce --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/siginfo_linux_other.go @@ -0,0 +1,12 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build linux && !(mips || mipsle || mips64 || mips64le) + +package unix + +type siErrnoCode struct { + Errno int32 + Code int32 +} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_386.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_386.go similarity index 89% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_386.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_386.go index 9f750a1c03e2..be048bcf734b 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_386.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_386.go @@ -8,4 +8,5 @@ const ( getrandomTrap uintptr = 355 copyFileRangeTrap uintptr = 377 pidfdSendSignalTrap uintptr = 424 + pidfdOpenTrap uintptr = 434 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_amd64.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_amd64.go similarity index 89% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_amd64.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_amd64.go index 706898d41e5a..525de9cbd8c1 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_amd64.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_amd64.go @@ -8,4 +8,5 @@ const ( getrandomTrap uintptr = 318 copyFileRangeTrap uintptr = 326 pidfdSendSignalTrap uintptr = 424 + pidfdOpenTrap uintptr = 434 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_arm.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_arm.go similarity index 89% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_arm.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_arm.go index c00644b5528a..b80389227868 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_arm.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_arm.go @@ -8,4 +8,5 @@ const ( getrandomTrap uintptr = 384 copyFileRangeTrap uintptr = 391 pidfdSendSignalTrap uintptr = 424 + pidfdOpenTrap uintptr = 434 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_generic.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_generic.go similarity index 94% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_generic.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_generic.go index bf25428e7ec5..b06bf6927312 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_generic.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_generic.go @@ -14,4 +14,5 @@ const ( getrandomTrap uintptr = 278 copyFileRangeTrap uintptr = 285 pidfdSendSignalTrap uintptr = 424 + pidfdOpenTrap uintptr = 434 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_mips64x.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_mips64x.go similarity index 89% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_mips64x.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_mips64x.go index 6a9e238ce3d3..8764f5dc8fcf 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_mips64x.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_mips64x.go @@ -10,4 +10,5 @@ const ( getrandomTrap uintptr = 5313 copyFileRangeTrap uintptr = 5320 pidfdSendSignalTrap uintptr = 5424 + pidfdOpenTrap uintptr = 5434 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_mipsx.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_mipsx.go similarity index 89% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_mipsx.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_mipsx.go index 22d38f148edd..9b2e587ba55f 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_mipsx.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_mipsx.go @@ -10,4 +10,5 @@ const ( getrandomTrap uintptr = 4353 copyFileRangeTrap uintptr = 4360 pidfdSendSignalTrap uintptr = 4424 + pidfdOpenTrap uintptr = 4434 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_ppc64x.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_ppc64x.go similarity index 90% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_ppc64x.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_ppc64x.go index 945ec28c2a04..03e9c197433e 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_ppc64x.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_ppc64x.go @@ -10,4 +10,5 @@ const ( getrandomTrap uintptr = 359 copyFileRangeTrap uintptr = 379 pidfdSendSignalTrap uintptr = 424 + pidfdOpenTrap uintptr = 434 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_s390x.go b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_s390x.go similarity index 89% rename from contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_s390x.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_s390x.go index 2c7434382018..c6e3e02e46e3 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/sysnum_linux_s390x.go +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/sysnum_linux_s390x.go @@ -8,4 +8,5 @@ const ( getrandomTrap uintptr = 349 copyFileRangeTrap uintptr = 375 pidfdSendSignalTrap uintptr = 424 + pidfdOpenTrap uintptr = 434 ) diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/tcsetpgrp_bsd.go b/contrib/go/_std_1.23/src/internal/syscall/unix/tcsetpgrp_bsd.go new file mode 100644 index 000000000000..bac614df97c0 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/tcsetpgrp_bsd.go @@ -0,0 +1,22 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin || dragonfly || freebsd || netbsd || openbsd + +package unix + +import ( + "syscall" + "unsafe" +) + +//go:linkname ioctlPtr syscall.ioctlPtr +func ioctlPtr(fd int, req uint, arg unsafe.Pointer) (err error) + +// Note that pgid should really be pid_t, however _C_int (aka int32) is +// generally equivalent. + +func Tcsetpgrp(fd int, pgid int32) (err error) { + return ioctlPtr(fd, syscall.TIOCSPGRP, unsafe.Pointer(&pgid)) +} diff --git a/contrib/go/_std_1.23/src/internal/syscall/unix/tcsetpgrp_linux.go b/contrib/go/_std_1.23/src/internal/syscall/unix/tcsetpgrp_linux.go new file mode 100644 index 000000000000..be208d9cd2ed --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/tcsetpgrp_linux.go @@ -0,0 +1,21 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import ( + "syscall" + "unsafe" +) + +// Note that pgid should really be pid_t, however _C_int (aka int32) is +// generally equivalent. + +func Tcsetpgrp(fd int, pgid int32) (err error) { + _, _, errno := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), uintptr(syscall.TIOCSPGRP), uintptr(unsafe.Pointer(&pgid)), 0, 0, 0) + if errno != 0 { + return errno + } + return nil +} diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/user_darwin.go b/contrib/go/_std_1.23/src/internal/syscall/unix/user_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/unix/user_darwin.go rename to contrib/go/_std_1.23/src/internal/syscall/unix/user_darwin.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/unix/ya.make b/contrib/go/_std_1.23/src/internal/syscall/unix/ya.make similarity index 87% rename from contrib/go/_std_1.22/src/internal/syscall/unix/ya.make rename to contrib/go/_std_1.23/src/internal/syscall/unix/ya.make index a8f44da8e800..54bf5a1c1406 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/unix/ya.make +++ b/contrib/go/_std_1.23/src/internal/syscall/unix/ya.make @@ -1,19 +1,20 @@ GO_LIBRARY() IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( + arc4random_darwin.go asm_darwin.s at_libc2.go at_sysnum_darwin.go constants.go - eaccess_other.go + eaccess_darwin.go fcntl_unix.go - getentropy_darwin.go - getentropy_darwin.s kernel_version_other.go net.go net_darwin.go + nofollow_posix.go nonblocking_unix.go pty_darwin.go + tcsetpgrp_bsd.go user_darwin.go ) ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) @@ -30,9 +31,13 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ getrandom_linux.go kernel_version_linux.go net.go + nofollow_posix.go nonblocking_unix.go pidfd_linux.go + siginfo_linux.go + siginfo_linux_other.go sysnum_linux_generic.go + tcsetpgrp_linux.go ) ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( @@ -48,9 +53,13 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X getrandom_linux.go kernel_version_linux.go net.go + nofollow_posix.go nonblocking_unix.go pidfd_linux.go + siginfo_linux.go + siginfo_linux_other.go sysnum_linux_amd64.go + tcsetpgrp_linux.go ) ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/memory_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/memory_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/memory_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/memory_windows.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/mksyscall.go b/contrib/go/_std_1.23/src/internal/syscall/windows/mksyscall.go similarity index 86% rename from contrib/go/_std_1.22/src/internal/syscall/windows/mksyscall.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/mksyscall.go index 81f08c627e64..f97ab526f815 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/windows/mksyscall.go +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/mksyscall.go @@ -6,4 +6,4 @@ package windows -//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go psapi_windows.go symlink_windows.go +//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go psapi_windows.go symlink_windows.go version_windows.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/net_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/net_windows.go similarity index 72% rename from contrib/go/_std_1.22/src/internal/syscall/windows/net_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/net_windows.go index 42c600c1447d..9fa5ecf84083 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/windows/net_windows.go +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/net_windows.go @@ -5,7 +5,6 @@ package windows import ( - "sync" "syscall" _ "unsafe" ) @@ -28,13 +27,3 @@ type TCP_INITIAL_RTO_PARAMETERS struct { Rtt uint16 MaxSynRetransmissions uint8 } - -var Support_TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS = sync.OnceValue(func() bool { - var maj, min, build uint32 - rtlGetNtVersionNumbers(&maj, &min, &build) - return maj >= 10 && build&0xffff >= 16299 -}) - -//go:linkname rtlGetNtVersionNumbers syscall.rtlGetNtVersionNumbers -//go:noescape -func rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/psapi_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/psapi_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/psapi_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/psapi_windows.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/registry/key.go b/contrib/go/_std_1.23/src/internal/syscall/windows/registry/key.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/registry/key.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/registry/key.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/registry/mksyscall.go b/contrib/go/_std_1.23/src/internal/syscall/windows/registry/mksyscall.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/registry/mksyscall.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/registry/mksyscall.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/registry/syscall.go b/contrib/go/_std_1.23/src/internal/syscall/windows/registry/syscall.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/registry/syscall.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/registry/syscall.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/registry/value.go b/contrib/go/_std_1.23/src/internal/syscall/windows/registry/value.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/registry/value.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/registry/value.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/registry/ya.make b/contrib/go/_std_1.23/src/internal/syscall/windows/registry/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/registry/ya.make rename to contrib/go/_std_1.23/src/internal/syscall/windows/registry/ya.make diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/registry/zsyscall_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/registry/zsyscall_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/registry/zsyscall_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/registry/zsyscall_windows.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/reparse_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/reparse_windows.go similarity index 94% rename from contrib/go/_std_1.22/src/internal/syscall/windows/reparse_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/reparse_windows.go index 02f32c675259..241dd523c541 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/windows/reparse_windows.go +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/reparse_windows.go @@ -9,10 +9,13 @@ import ( "unsafe" ) +// Reparse tag values are taken from +// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/c8e77b37-3909-4fe6-a4ea-2b9d423b1ee4 const ( FSCTL_SET_REPARSE_POINT = 0x000900A4 IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 IO_REPARSE_TAG_DEDUP = 0x80000013 + IO_REPARSE_TAG_AF_UNIX = 0x80000023 SYMLINK_FLAG_RELATIVE = 1 ) diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/security_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/security_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/security_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/security_windows.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/symlink_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/symlink_windows.go similarity index 97% rename from contrib/go/_std_1.22/src/internal/syscall/windows/symlink_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/symlink_windows.go index 62e3f79986e2..b91246037b5e 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/windows/symlink_windows.go +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/symlink_windows.go @@ -9,6 +9,7 @@ import "syscall" const ( ERROR_INVALID_PARAMETER syscall.Errno = 87 + FILE_SUPPORTS_OBJECT_IDS = 0x00010000 FILE_SUPPORTS_OPEN_BY_FILE_ID = 0x01000000 // symlink support for CreateSymbolicLink() starting with Windows 10 (1703, v10.0.14972) diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/syscall_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/syscall_windows.go similarity index 84% rename from contrib/go/_std_1.22/src/internal/syscall/windows/syscall_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/syscall_windows.go index d10e30cb6825..cc26a50bb0ac 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/windows/syscall_windows.go +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/syscall_windows.go @@ -10,6 +10,12 @@ import ( "unsafe" ) +// CanUseLongPaths is true when the OS supports opting into +// proper long path handling without the need for fixups. +// +//go:linkname CanUseLongPaths +var CanUseLongPaths bool + // UTF16PtrToString is like UTF16ToString, but takes *uint16 // as a parameter instead of []uint16. func UTF16PtrToString(p *uint16) string { @@ -36,7 +42,10 @@ const ( ERROR_NO_UNICODE_TRANSLATION syscall.Errno = 1113 ) -const GAA_FLAG_INCLUDE_PREFIX = 0x00000010 +const ( + GAA_FLAG_INCLUDE_PREFIX = 0x00000010 + GAA_FLAG_INCLUDE_GATEWAYS = 0x0080 +) const ( IF_TYPE_OTHER = 1 @@ -98,27 +107,45 @@ type IpAdapterPrefix struct { PrefixLength uint32 } +type IpAdapterWinsServerAddress struct { + Length uint32 + Reserved uint32 + Next *IpAdapterWinsServerAddress + Address SocketAddress +} + +type IpAdapterGatewayAddress struct { + Length uint32 + Reserved uint32 + Next *IpAdapterGatewayAddress + Address SocketAddress +} + type IpAdapterAddresses struct { - Length uint32 - IfIndex uint32 - Next *IpAdapterAddresses - AdapterName *byte - FirstUnicastAddress *IpAdapterUnicastAddress - FirstAnycastAddress *IpAdapterAnycastAddress - FirstMulticastAddress *IpAdapterMulticastAddress - FirstDnsServerAddress *IpAdapterDnsServerAdapter - DnsSuffix *uint16 - Description *uint16 - FriendlyName *uint16 - PhysicalAddress [syscall.MAX_ADAPTER_ADDRESS_LENGTH]byte - PhysicalAddressLength uint32 - Flags uint32 - Mtu uint32 - IfType uint32 - OperStatus uint32 - Ipv6IfIndex uint32 - ZoneIndices [16]uint32 - FirstPrefix *IpAdapterPrefix + Length uint32 + IfIndex uint32 + Next *IpAdapterAddresses + AdapterName *byte + FirstUnicastAddress *IpAdapterUnicastAddress + FirstAnycastAddress *IpAdapterAnycastAddress + FirstMulticastAddress *IpAdapterMulticastAddress + FirstDnsServerAddress *IpAdapterDnsServerAdapter + DnsSuffix *uint16 + Description *uint16 + FriendlyName *uint16 + PhysicalAddress [syscall.MAX_ADAPTER_ADDRESS_LENGTH]byte + PhysicalAddressLength uint32 + Flags uint32 + Mtu uint32 + IfType uint32 + OperStatus uint32 + Ipv6IfIndex uint32 + ZoneIndices [16]uint32 + FirstPrefix *IpAdapterPrefix + TransmitLinkSpeed uint64 + ReceiveLinkSpeed uint64 + FirstWinsServerAddress *IpAdapterWinsServerAddress + FirstGatewayAddress *IpAdapterGatewayAddress /* more fields might be present here. */ } @@ -195,7 +222,9 @@ const ( WSA_FLAG_OVERLAPPED = 0x01 WSA_FLAG_NO_HANDLE_INHERIT = 0x80 - WSAEMSGSIZE syscall.Errno = 10040 + WSAEINVAL syscall.Errno = 10022 + WSAEMSGSIZE syscall.Errno = 10040 + WSAEAFNOSUPPORT syscall.Errno = 10047 MSG_PEEK = 0x2 MSG_TRUNC = 0x0100 @@ -235,6 +264,7 @@ type WSAMsg struct { } //sys WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = ws2_32.WSASocketW +//sys WSAGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult func loadWSASendRecvMsg() error { sendRecvMsgFunc.once.Do(func() { @@ -443,3 +473,29 @@ const ( //sys OpenService(mgr syscall.Handle, serviceName *uint16, access uint32) (handle syscall.Handle, err error) = advapi32.OpenServiceW //sys QueryServiceStatus(hService syscall.Handle, lpServiceStatus *SERVICE_STATUS) (err error) = advapi32.QueryServiceStatus //sys OpenSCManager(machineName *uint16, databaseName *uint16, access uint32) (handle syscall.Handle, err error) [failretval==0] = advapi32.OpenSCManagerW + +func FinalPath(h syscall.Handle, flags uint32) (string, error) { + buf := make([]uint16, 100) + for { + n, err := GetFinalPathNameByHandle(h, &buf[0], uint32(len(buf)), flags) + if err != nil { + return "", err + } + if n < uint32(len(buf)) { + break + } + buf = make([]uint16, n) + } + return syscall.UTF16ToString(buf), nil +} + +// QueryPerformanceCounter retrieves the current value of performance counter. +// +//go:linkname QueryPerformanceCounter +func QueryPerformanceCounter() int64 // Implemented in runtime package. + +// QueryPerformanceFrequency retrieves the frequency of the performance counter. +// The returned value is represented as counts per second. +// +//go:linkname QueryPerformanceFrequency +func QueryPerformanceFrequency() int64 // Implemented in runtime package. diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/sysdll/sysdll.go b/contrib/go/_std_1.23/src/internal/syscall/windows/sysdll/sysdll.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/sysdll/sysdll.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/sysdll/sysdll.go diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/sysdll/ya.make b/contrib/go/_std_1.23/src/internal/syscall/windows/sysdll/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/syscall/windows/sysdll/ya.make rename to contrib/go/_std_1.23/src/internal/syscall/windows/sysdll/ya.make diff --git a/contrib/go/_std_1.23/src/internal/syscall/windows/types_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/types_windows.go new file mode 100644 index 000000000000..126e07b8834c --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/types_windows.go @@ -0,0 +1,12 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +// Socket related. +const ( + TCP_KEEPIDLE = 0x03 + TCP_KEEPCNT = 0x10 + TCP_KEEPINTVL = 0x11 +) diff --git a/contrib/go/_std_1.23/src/internal/syscall/windows/version_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/version_windows.go new file mode 100644 index 000000000000..ff21fc59e5bf --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/version_windows.go @@ -0,0 +1,113 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +import ( + "errors" + "sync" + "syscall" + "unsafe" +) + +// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow +type _OSVERSIONINFOW struct { + osVersionInfoSize uint32 + majorVersion uint32 + minorVersion uint32 + buildNumber uint32 + platformId uint32 + csdVersion [128]uint16 +} + +// According to documentation, RtlGetVersion function always succeeds. +//sys rtlGetVersion(info *_OSVERSIONINFOW) = ntdll.RtlGetVersion + +// version retrieves the major, minor, and build version numbers +// of the current Windows OS from the RtlGetVersion API. +func version() (major, minor, build uint32) { + info := _OSVERSIONINFOW{} + info.osVersionInfoSize = uint32(unsafe.Sizeof(info)) + rtlGetVersion(&info) + return info.majorVersion, info.minorVersion, info.buildNumber +} + +var ( + supportTCPKeepAliveIdle bool + supportTCPKeepAliveInterval bool + supportTCPKeepAliveCount bool +) + +var initTCPKeepAlive = sync.OnceFunc(func() { + s, err := WSASocket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP, nil, 0, WSA_FLAG_NO_HANDLE_INHERIT) + if err != nil { + // Fallback to checking the Windows version. + major, _, build := version() + supportTCPKeepAliveIdle = major >= 10 && build >= 16299 + supportTCPKeepAliveInterval = major >= 10 && build >= 16299 + supportTCPKeepAliveCount = major >= 10 && build >= 15063 + return + } + defer syscall.Closesocket(s) + var optSupported = func(opt int) bool { + err := syscall.SetsockoptInt(s, syscall.IPPROTO_TCP, opt, 1) + return !errors.Is(err, syscall.WSAENOPROTOOPT) + } + supportTCPKeepAliveIdle = optSupported(TCP_KEEPIDLE) + supportTCPKeepAliveInterval = optSupported(TCP_KEEPINTVL) + supportTCPKeepAliveCount = optSupported(TCP_KEEPCNT) +}) + +// SupportTCPKeepAliveInterval indicates whether TCP_KEEPIDLE is supported. +// The minimal requirement is Windows 10.0.16299. +func SupportTCPKeepAliveIdle() bool { + initTCPKeepAlive() + return supportTCPKeepAliveIdle +} + +// SupportTCPKeepAliveInterval indicates whether TCP_KEEPINTVL is supported. +// The minimal requirement is Windows 10.0.16299. +func SupportTCPKeepAliveInterval() bool { + initTCPKeepAlive() + return supportTCPKeepAliveInterval +} + +// SupportTCPKeepAliveCount indicates whether TCP_KEEPCNT is supported. +// supports TCP_KEEPCNT. +// The minimal requirement is Windows 10.0.15063. +func SupportTCPKeepAliveCount() bool { + initTCPKeepAlive() + return supportTCPKeepAliveCount +} + +// SupportTCPInitialRTONoSYNRetransmissions indicates whether the current +// Windows version supports the TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS. +// The minimal requirement is Windows 10.0.16299. +var SupportTCPInitialRTONoSYNRetransmissions = sync.OnceValue(func() bool { + major, _, build := version() + return major >= 10 && build >= 16299 +}) + +// SupportUnixSocket indicates whether the current Windows version supports +// Unix Domain Sockets. +// The minimal requirement is Windows 10.0.17063. +var SupportUnixSocket = sync.OnceValue(func() bool { + var size uint32 + // First call to get the required buffer size in bytes. + // Ignore the error, it will always fail. + _, _ = syscall.WSAEnumProtocols(nil, nil, &size) + n := int32(size) / int32(unsafe.Sizeof(syscall.WSAProtocolInfo{})) + // Second call to get the actual protocols. + buf := make([]syscall.WSAProtocolInfo, n) + n, err := syscall.WSAEnumProtocols(nil, &buf[0], &size) + if err != nil { + return false + } + for i := int32(0); i < n; i++ { + if buf[i].AddressFamily == syscall.AF_UNIX { + return true + } + } + return false +}) diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/ya.make b/contrib/go/_std_1.23/src/internal/syscall/windows/ya.make similarity index 90% rename from contrib/go/_std_1.22/src/internal/syscall/windows/ya.make rename to contrib/go/_std_1.23/src/internal/syscall/windows/ya.make index e1b38ff2f290..88a4da48a614 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/windows/ya.make +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/ya.make @@ -8,6 +8,8 @@ IF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X security_windows.go symlink_windows.go syscall_windows.go + types_windows.go + version_windows.go zsyscall_windows.go ) ENDIF() diff --git a/contrib/go/_std_1.22/src/internal/syscall/windows/zsyscall_windows.go b/contrib/go/_std_1.23/src/internal/syscall/windows/zsyscall_windows.go similarity index 95% rename from contrib/go/_std_1.22/src/internal/syscall/windows/zsyscall_windows.go rename to contrib/go/_std_1.23/src/internal/syscall/windows/zsyscall_windows.go index 931f157cf166..414ad2647d1a 100644 --- a/contrib/go/_std_1.22/src/internal/syscall/windows/zsyscall_windows.go +++ b/contrib/go/_std_1.23/src/internal/syscall/windows/zsyscall_windows.go @@ -42,6 +42,7 @@ var ( modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) + modntdll = syscall.NewLazyDLL(sysdll.Add("ntdll.dll")) modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll")) moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll")) modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll")) @@ -82,10 +83,12 @@ var ( procNetShareAdd = modnetapi32.NewProc("NetShareAdd") procNetShareDel = modnetapi32.NewProc("NetShareDel") procNetUserGetLocalGroups = modnetapi32.NewProc("NetUserGetLocalGroups") + procRtlGetVersion = modntdll.NewProc("RtlGetVersion") procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo") procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock") procDestroyEnvironmentBlock = moduserenv.NewProc("DestroyEnvironmentBlock") procGetProfilesDirectoryW = moduserenv.NewProc("GetProfilesDirectoryW") + procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult") procWSASocketW = modws2_32.NewProc("WSASocketW") ) @@ -390,6 +393,11 @@ func NetUserGetLocalGroups(serverName *uint16, userName *uint16, level uint32, f return } +func rtlGetVersion(info *_OSVERSIONINFOW) { + syscall.Syscall(procRtlGetVersion.Addr(), 1, uintptr(unsafe.Pointer(info)), 0, 0) + return +} + func GetProcessMemoryInfo(handle syscall.Handle, memCounters *PROCESS_MEMORY_COUNTERS, cb uint32) (err error) { r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(memCounters)), uintptr(cb)) if r1 == 0 { @@ -426,6 +434,18 @@ func GetProfilesDirectory(dir *uint16, dirLen *uint32) (err error) { return } +func WSAGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) { + var _p0 uint32 + if wait { + _p0 = 1 + } + r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0) + if r1 == 0 { + err = errnoErr(e1) + } + return +} + func WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) { r0, _, e1 := syscall.Syscall6(procWSASocketW.Addr(), 6, uintptr(af), uintptr(typ), uintptr(protocol), uintptr(unsafe.Pointer(protinfo)), uintptr(group), uintptr(flags)) handle = syscall.Handle(r0) diff --git a/contrib/go/_std_1.22/src/internal/testlog/exit.go b/contrib/go/_std_1.23/src/internal/testlog/exit.go similarity index 75% rename from contrib/go/_std_1.22/src/internal/testlog/exit.go rename to contrib/go/_std_1.23/src/internal/testlog/exit.go index e15defdb5b0b..b985c6b3f79b 100644 --- a/contrib/go/_std_1.22/src/internal/testlog/exit.go +++ b/contrib/go/_std_1.23/src/internal/testlog/exit.go @@ -4,7 +4,10 @@ package testlog -import "sync" +import ( + "sync" + _ "unsafe" // for linkname +) // PanicOnExit0 reports whether to panic on a call to os.Exit(0). // This is in the testlog package because, like other definitions in @@ -26,6 +29,15 @@ var panicOnExit0 struct { } // SetPanicOnExit0 sets panicOnExit0 to v. +// +// SetPanicOnExit0 should be an internal detail, +// but alternate implementations of go test in other +// build systems may need to access it using linkname. +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname SetPanicOnExit0 func SetPanicOnExit0(v bool) { panicOnExit0.mu.Lock() defer panicOnExit0.mu.Unlock() diff --git a/contrib/go/_std_1.22/src/internal/testlog/log.go b/contrib/go/_std_1.23/src/internal/testlog/log.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/testlog/log.go rename to contrib/go/_std_1.23/src/internal/testlog/log.go diff --git a/contrib/go/_std_1.22/src/internal/testlog/ya.make b/contrib/go/_std_1.23/src/internal/testlog/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/testlog/ya.make rename to contrib/go/_std_1.23/src/internal/testlog/ya.make diff --git a/contrib/go/_std_1.22/src/internal/types/errors/code_string.go b/contrib/go/_std_1.23/src/internal/types/errors/code_string.go similarity index 97% rename from contrib/go/_std_1.22/src/internal/types/errors/code_string.go rename to contrib/go/_std_1.23/src/internal/types/errors/code_string.go index 719fc73a5a76..9ae675ef849d 100644 --- a/contrib/go/_std_1.22/src/internal/types/errors/code_string.go +++ b/contrib/go/_std_1.23/src/internal/types/errors/code_string.go @@ -155,6 +155,7 @@ func _() { _ = x[InvalidClear-148] _ = x[TypeTooLarge-149] _ = x[InvalidMinMaxOperand-150] + _ = x[TooNew-151] } const ( @@ -163,7 +164,7 @@ const ( _Code_name_2 = "InvalidPtrEmbedBadRecvInvalidRecvDuplicateFieldAndMethodDuplicateMethodInvalidBlankInvalidIotaMissingInitBodyInvalidInitSigInvalidInitDeclInvalidMainDeclTooManyValuesNotAnExprTruncatedFloatNumericOverflowUndefinedOpMismatchedTypesDivByZeroNonNumericIncDecUnaddressableOperandInvalidIndirectionNonIndexableOperandInvalidIndexSwappedSliceIndicesNonSliceableOperandInvalidSliceExprInvalidShiftCountInvalidShiftOperandInvalidReceiveInvalidSendDuplicateLitKeyMissingLitKeyInvalidLitIndexOversizeArrayLitMixedStructLitInvalidStructLitMissingLitFieldDuplicateLitFieldUnexportedLitFieldInvalidLitFieldUntypedLitInvalidLitAmbiguousSelectorUndeclaredImportedNameUnexportedNameUndeclaredNameMissingFieldOrMethodBadDotDotDotSyntaxNonVariadicDotDotDotMisplacedDotDotDot" _Code_name_3 = "InvalidDotDotDotUncalledBuiltinInvalidAppendInvalidCapInvalidCloseInvalidCopyInvalidComplexInvalidDeleteInvalidImagInvalidLenSwappedMakeArgsInvalidMakeInvalidRealInvalidAssertImpossibleAssertInvalidConversionInvalidUntypedConversionBadOffsetofSyntaxInvalidOffsetofUnusedExprUnusedVarMissingReturnWrongResultCountOutOfScopeResultInvalidCondInvalidPostDecl" _Code_name_4 = "InvalidIterVarInvalidRangeExprMisplacedBreakMisplacedContinueMisplacedFallthroughDuplicateCaseDuplicateDefaultBadTypeKeywordInvalidTypeSwitchInvalidExprSwitchInvalidSelectCaseUndeclaredLabelDuplicateLabelMisplacedLabelUnusedLabelJumpOverDeclJumpIntoBlockInvalidMethodExprWrongArgCountInvalidCallUnusedResultsInvalidDeferInvalidGoBadDeclRepeatedDeclInvalidUnsafeAddInvalidUnsafeSliceUnsupportedFeatureNotAGenericTypeWrongTypeArgCountCannotInferTypeArgsInvalidTypeArgInvalidInstanceCycleInvalidUnionMisplacedConstraintIfaceInvalidMethodTypeParamsMisplacedTypeParamInvalidUnsafeSliceDataInvalidUnsafeString" - _Code_name_5 = "InvalidClearTypeTooLargeInvalidMinMaxOperand" + _Code_name_5 = "InvalidClearTypeTooLargeInvalidMinMaxOperandTooNew" ) var ( @@ -171,7 +172,7 @@ var ( _Code_index_2 = [...]uint16{0, 15, 22, 33, 56, 71, 83, 94, 109, 123, 138, 153, 166, 175, 189, 204, 215, 230, 239, 255, 275, 293, 312, 324, 343, 362, 378, 395, 414, 428, 439, 454, 467, 482, 498, 512, 528, 543, 560, 578, 593, 603, 613, 630, 652, 666, 680, 700, 718, 738, 756} _Code_index_3 = [...]uint16{0, 16, 31, 44, 54, 66, 77, 91, 104, 115, 125, 140, 151, 162, 175, 191, 208, 232, 249, 264, 274, 283, 296, 312, 328, 339, 354} _Code_index_4 = [...]uint16{0, 14, 30, 44, 61, 81, 94, 110, 124, 141, 158, 175, 190, 204, 218, 229, 241, 254, 271, 284, 295, 308, 320, 329, 336, 348, 364, 382, 400, 415, 432, 451, 465, 485, 497, 521, 544, 562, 584, 603} - _Code_index_5 = [...]uint8{0, 12, 24, 44} + _Code_index_5 = [...]uint8{0, 12, 24, 44, 50} ) func (i Code) String() string { @@ -190,7 +191,7 @@ func (i Code) String() string { case 108 <= i && i <= 146: i -= 108 return _Code_name_4[_Code_index_4[i]:_Code_index_4[i+1]] - case 148 <= i && i <= 150: + case 148 <= i && i <= 151: i -= 148 return _Code_name_5[_Code_index_5[i]:_Code_index_5[i+1]] default: diff --git a/contrib/go/_std_1.22/src/internal/types/errors/codes.go b/contrib/go/_std_1.23/src/internal/types/errors/codes.go similarity index 98% rename from contrib/go/_std_1.22/src/internal/types/errors/codes.go rename to contrib/go/_std_1.23/src/internal/types/errors/codes.go index cae688ff874b..c0e6aa6c2daf 100644 --- a/contrib/go/_std_1.22/src/internal/types/errors/codes.go +++ b/contrib/go/_std_1.23/src/internal/types/errors/codes.go @@ -4,7 +4,7 @@ package errors -//go:generate stringer -type Code codes.go +//go:generate go run golang.org/x/tools/cmd/stringer@latest -type Code codes.go type Code int @@ -1474,4 +1474,12 @@ const ( // var s, t []byte // var _ = max(s, t) InvalidMinMaxOperand + + // TooNew indicates that, through build tags or a go.mod file, + // a source file requires a version of Go that is newer than + // the logic of the type checker. As a consequence, the type + // checker may produce spurious errors or fail to report real + // errors. The solution is to rebuild the application with a + // newer Go release. + TooNew ) diff --git a/contrib/go/_std_1.22/src/internal/types/errors/generrordocs.go b/contrib/go/_std_1.23/src/internal/types/errors/generrordocs.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/types/errors/generrordocs.go rename to contrib/go/_std_1.23/src/internal/types/errors/generrordocs.go diff --git a/contrib/go/_std_1.22/src/internal/types/errors/ya.make b/contrib/go/_std_1.23/src/internal/types/errors/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/types/errors/ya.make rename to contrib/go/_std_1.23/src/internal/types/errors/ya.make diff --git a/contrib/go/_std_1.22/src/internal/unsafeheader/unsafeheader.go b/contrib/go/_std_1.23/src/internal/unsafeheader/unsafeheader.go similarity index 100% rename from contrib/go/_std_1.22/src/internal/unsafeheader/unsafeheader.go rename to contrib/go/_std_1.23/src/internal/unsafeheader/unsafeheader.go diff --git a/contrib/go/_std_1.22/src/internal/unsafeheader/ya.make b/contrib/go/_std_1.23/src/internal/unsafeheader/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/internal/unsafeheader/ya.make rename to contrib/go/_std_1.23/src/internal/unsafeheader/ya.make diff --git a/contrib/go/_std_1.23/src/internal/weak/pointer.go b/contrib/go/_std_1.23/src/internal/weak/pointer.go new file mode 100644 index 000000000000..8e05af2d23f0 --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/weak/pointer.go @@ -0,0 +1,83 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +The weak package is a package for managing weak pointers. + +Weak pointers are pointers that explicitly do not keep a value live and +must be queried for a regular Go pointer. +The result of such a query may be observed as nil at any point after a +weakly-pointed-to object becomes eligible for reclamation by the garbage +collector. +More specifically, weak pointers become nil as soon as the garbage collector +identifies that the object is unreachable, before it is made reachable +again by a finalizer. +In terms of the C# language, these semantics are roughly equivalent to the +the semantics of "short" weak references. +In terms of the Java language, these semantics are roughly equivalent to the +semantics of the WeakReference type. + +Using go:linkname to access this package and the functions it references +is explicitly forbidden by the toolchain because the semantics of this +package have not gone through the proposal process. By exposing this +functionality, we risk locking in the existing semantics due to Hyrum's Law. + +If you believe you have a good use-case for weak references not already +covered by the standard library, file a proposal issue at +https://github.com/golang/go/issues instead of relying on this package. +*/ +package weak + +import ( + "internal/abi" + "runtime" + "unsafe" +) + +// Pointer is a weak pointer to a value of type T. +// +// This value is comparable is guaranteed to compare equal if the pointers +// that they were created from compare equal. This property is retained even +// after the object referenced by the pointer used to create a weak reference +// is reclaimed. +// +// If multiple weak pointers are made to different offsets within same object +// (for example, pointers to different fields of the same struct), those pointers +// will not compare equal. +// If a weak pointer is created from an object that becomes reachable again due +// to a finalizer, that weak pointer will not compare equal with weak pointers +// created before it became unreachable. +type Pointer[T any] struct { + u unsafe.Pointer +} + +// Make creates a weak pointer from a strong pointer to some value of type T. +func Make[T any](ptr *T) Pointer[T] { + // Explicitly force ptr to escape to the heap. + ptr = abi.Escape(ptr) + + var u unsafe.Pointer + if ptr != nil { + u = runtime_registerWeakPointer(unsafe.Pointer(ptr)) + } + runtime.KeepAlive(ptr) + return Pointer[T]{u} +} + +// Strong creates a strong pointer from the weak pointer. +// Returns nil if the original value for the weak pointer was reclaimed by +// the garbage collector. +// If a weak pointer points to an object with a finalizer, then Strong will +// return nil as soon as the object's finalizer is queued for execution. +func (p Pointer[T]) Strong() *T { + return (*T)(runtime_makeStrongFromWeak(p.u)) +} + +// Implemented in runtime. + +//go:linkname runtime_registerWeakPointer +func runtime_registerWeakPointer(unsafe.Pointer) unsafe.Pointer + +//go:linkname runtime_makeStrongFromWeak +func runtime_makeStrongFromWeak(unsafe.Pointer) unsafe.Pointer diff --git a/contrib/go/_std_1.23/src/internal/weak/ya.make b/contrib/go/_std_1.23/src/internal/weak/ya.make new file mode 100644 index 000000000000..4c8d8d9ab8eb --- /dev/null +++ b/contrib/go/_std_1.23/src/internal/weak/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + pointer.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/io/fs/format.go b/contrib/go/_std_1.23/src/io/fs/format.go similarity index 100% rename from contrib/go/_std_1.22/src/io/fs/format.go rename to contrib/go/_std_1.23/src/io/fs/format.go diff --git a/contrib/go/_std_1.22/src/io/fs/fs.go b/contrib/go/_std_1.23/src/io/fs/fs.go similarity index 100% rename from contrib/go/_std_1.22/src/io/fs/fs.go rename to contrib/go/_std_1.23/src/io/fs/fs.go diff --git a/contrib/go/_std_1.22/src/io/fs/glob.go b/contrib/go/_std_1.23/src/io/fs/glob.go similarity index 100% rename from contrib/go/_std_1.22/src/io/fs/glob.go rename to contrib/go/_std_1.23/src/io/fs/glob.go diff --git a/contrib/go/_std_1.22/src/io/fs/readdir.go b/contrib/go/_std_1.23/src/io/fs/readdir.go similarity index 93% rename from contrib/go/_std_1.22/src/io/fs/readdir.go rename to contrib/go/_std_1.23/src/io/fs/readdir.go index 22ced48073be..467d3bffeeb6 100644 --- a/contrib/go/_std_1.22/src/io/fs/readdir.go +++ b/contrib/go/_std_1.23/src/io/fs/readdir.go @@ -6,7 +6,8 @@ package fs import ( "errors" - "sort" + "internal/bytealg" + "slices" ) // ReadDirFS is the interface implemented by a file system @@ -42,7 +43,9 @@ func ReadDir(fsys FS, name string) ([]DirEntry, error) { } list, err := dir.ReadDir(-1) - sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() }) + slices.SortFunc(list, func(a, b DirEntry) int { + return bytealg.CompareString(a.Name(), b.Name()) + }) return list, err } diff --git a/contrib/go/_std_1.22/src/io/fs/readfile.go b/contrib/go/_std_1.23/src/io/fs/readfile.go similarity index 100% rename from contrib/go/_std_1.22/src/io/fs/readfile.go rename to contrib/go/_std_1.23/src/io/fs/readfile.go diff --git a/contrib/go/_std_1.22/src/io/fs/stat.go b/contrib/go/_std_1.23/src/io/fs/stat.go similarity index 100% rename from contrib/go/_std_1.22/src/io/fs/stat.go rename to contrib/go/_std_1.23/src/io/fs/stat.go diff --git a/contrib/go/_std_1.22/src/io/fs/sub.go b/contrib/go/_std_1.23/src/io/fs/sub.go similarity index 95% rename from contrib/go/_std_1.22/src/io/fs/sub.go rename to contrib/go/_std_1.23/src/io/fs/sub.go index 9999e63b26f2..70ac62307778 100644 --- a/contrib/go/_std_1.22/src/io/fs/sub.go +++ b/contrib/go/_std_1.23/src/io/fs/sub.go @@ -33,7 +33,7 @@ type SubFS interface { // chroot-style security mechanism, and Sub does not change that fact. func Sub(fsys FS, dir string) (FS, error) { if !ValidPath(dir) { - return nil, &PathError{Op: "sub", Path: dir, Err: errors.New("invalid name")} + return nil, &PathError{Op: "sub", Path: dir, Err: ErrInvalid} } if dir == "." { return fsys, nil @@ -52,7 +52,7 @@ type subFS struct { // fullName maps name to the fully-qualified name dir/name. func (f *subFS) fullName(op string, name string) (string, error) { if !ValidPath(name) { - return "", &PathError{Op: op, Path: name, Err: errors.New("invalid name")} + return "", &PathError{Op: op, Path: name, Err: ErrInvalid} } return path.Join(f.dir, name), nil } diff --git a/contrib/go/_std_1.22/src/io/fs/walk.go b/contrib/go/_std_1.23/src/io/fs/walk.go similarity index 100% rename from contrib/go/_std_1.22/src/io/fs/walk.go rename to contrib/go/_std_1.23/src/io/fs/walk.go diff --git a/contrib/go/_std_1.22/src/io/fs/ya.make b/contrib/go/_std_1.23/src/io/fs/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/io/fs/ya.make rename to contrib/go/_std_1.23/src/io/fs/ya.make diff --git a/contrib/go/_std_1.22/src/io/io.go b/contrib/go/_std_1.23/src/io/io.go similarity index 99% rename from contrib/go/_std_1.22/src/io/io.go rename to contrib/go/_std_1.23/src/io/io.go index 7f16e18d7d1b..00edcde763a5 100644 --- a/contrib/go/_std_1.22/src/io/io.go +++ b/contrib/go/_std_1.23/src/io/io.go @@ -411,8 +411,8 @@ func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) { return wt.WriteTo(dst) } // Similarly, if the writer has a ReadFrom method, use it to do the copy. - if rt, ok := dst.(ReaderFrom); ok { - return rt.ReadFrom(src) + if rf, ok := dst.(ReaderFrom); ok { + return rf.ReadFrom(src) } if buf == nil { size := 32 * 1024 diff --git a/contrib/go/_std_1.22/src/io/ioutil/ioutil.go b/contrib/go/_std_1.23/src/io/ioutil/ioutil.go similarity index 96% rename from contrib/go/_std_1.22/src/io/ioutil/ioutil.go rename to contrib/go/_std_1.23/src/io/ioutil/ioutil.go index 67768e54cf55..af8ebe38501d 100644 --- a/contrib/go/_std_1.22/src/io/ioutil/ioutil.go +++ b/contrib/go/_std_1.23/src/io/ioutil/ioutil.go @@ -14,7 +14,8 @@ import ( "io" "io/fs" "os" - "sort" + "slices" + "strings" ) // ReadAll reads from r until an error or EOF and returns the data it read. @@ -76,7 +77,9 @@ func ReadDir(dirname string) ([]fs.FileInfo, error) { if err != nil { return nil, err } - sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() }) + slices.SortFunc(list, func(a, b os.FileInfo) int { + return strings.Compare(a.Name(), b.Name()) + }) return list, nil } diff --git a/contrib/go/_std_1.22/src/io/ioutil/tempfile.go b/contrib/go/_std_1.23/src/io/ioutil/tempfile.go similarity index 100% rename from contrib/go/_std_1.22/src/io/ioutil/tempfile.go rename to contrib/go/_std_1.23/src/io/ioutil/tempfile.go diff --git a/contrib/go/_std_1.22/src/io/ioutil/ya.make b/contrib/go/_std_1.23/src/io/ioutil/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/io/ioutil/ya.make rename to contrib/go/_std_1.23/src/io/ioutil/ya.make diff --git a/contrib/go/_std_1.22/src/io/multi.go b/contrib/go/_std_1.23/src/io/multi.go similarity index 100% rename from contrib/go/_std_1.22/src/io/multi.go rename to contrib/go/_std_1.23/src/io/multi.go diff --git a/contrib/go/_std_1.22/src/io/pipe.go b/contrib/go/_std_1.23/src/io/pipe.go similarity index 100% rename from contrib/go/_std_1.22/src/io/pipe.go rename to contrib/go/_std_1.23/src/io/pipe.go diff --git a/contrib/go/_std_1.22/src/io/ya.make b/contrib/go/_std_1.23/src/io/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/io/ya.make rename to contrib/go/_std_1.23/src/io/ya.make diff --git a/contrib/go/_std_1.23/src/iter/iter.go b/contrib/go/_std_1.23/src/iter/iter.go new file mode 100644 index 000000000000..14fd8f8115f3 --- /dev/null +++ b/contrib/go/_std_1.23/src/iter/iter.go @@ -0,0 +1,453 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package iter provides basic definitions and operations related to +iterators over sequences. + +# Iterators + +An iterator is a function that passes successive elements of a +sequence to a callback function, conventionally named yield. +The function stops either when the sequence is finished or +when yield returns false, indicating to stop the iteration early. +This package defines [Seq] and [Seq2] +(pronounced like seek—the first syllable of sequence) +as shorthands for iterators that pass 1 or 2 values per sequence element +to yield: + + type ( + Seq[V any] func(yield func(V) bool) + Seq2[K, V any] func(yield func(K, V) bool) + ) + +Seq2 represents a sequence of paired values, conventionally key-value +or index-value pairs. + +Yield returns true if the iterator should continue with the next +element in the sequence, false if it should stop. + +Iterator functions are most often called by a range loop, as in: + + func PrintAll[V any](seq iter.Seq[V]) { + for v := range seq { + fmt.Println(v) + } + } + +# Naming Conventions + +Iterator functions and methods are named for the sequence being walked: + + // All returns an iterator over all elements in s. + func (s *Set[V]) All() iter.Seq[V] + +The iterator method on a collection type is conventionally named All, +because it iterates a sequence of all the values in the collection. + +For a type containing multiple possible sequences, the iterator's name +can indicate which sequence is being provided: + + // Cities returns an iterator over the major cities in the country. + func (c *Country) Cities() iter.Seq[*City] + + // Languages returns an iterator over the official spoken languages of the country. + func (c *Country) Languages() iter.Seq[string] + +If an iterator requires additional configuration, the constructor function +can take additional configuration arguments: + + // Scan returns an iterator over key-value pairs with min ≤ key ≤ max. + func (m *Map[K, V]) Scan(min, max K) iter.Seq2[K, V] + + // Split returns an iterator over the (possibly-empty) substrings of s + // separated by sep. + func Split(s, sep string) iter.Seq[string] + +When there are multiple possible iteration orders, the method name may +indicate that order: + + // All returns an iterator over the list from head to tail. + func (l *List[V]) All() iter.Seq[V] + + // Backward returns an iterator over the list from tail to head. + func (l *List[V]) Backward() iter.Seq[V] + + // Preorder returns an iterator over all nodes of the syntax tree + // beneath (and including) the specified root, in depth-first preorder, + // visiting a parent node before its children. + func Preorder(root Node) iter.Seq[Node] + +# Single-Use Iterators + +Most iterators provide the ability to walk an entire sequence: +when called, the iterator does any setup necessary to start the +sequence, then calls yield on successive elements of the sequence, +and then cleans up before returning. Calling the iterator again +walks the sequence again. + +Some iterators break that convention, providing the ability to walk a +sequence only once. These “single-use iterators” typically report values +from a data stream that cannot be rewound to start over. +Calling the iterator again after stopping early may continue the +stream, but calling it again after the sequence is finished will yield +no values at all. Doc comments for functions or methods that return +single-use iterators should document this fact: + + // Lines returns an iterator over lines read from r. + // It returns a single-use iterator. + func (r *Reader) Lines() iter.Seq[string] + +# Pulling Values + +Functions and methods that accept or return iterators +should use the standard [Seq] or [Seq2] types, to ensure +compatibility with range loops and other iterator adapters. +The standard iterators can be thought of as “push iterators”, which +push values to the yield function. + +Sometimes a range loop is not the most natural way to consume values +of the sequence. In this case, [Pull] converts a standard push iterator +to a “pull iterator”, which can be called to pull one value at a time +from the sequence. [Pull] starts an iterator and returns a pair +of functions—next and stop—which return the next value from the iterator +and stop it, respectively. + +For example: + + // Pairs returns an iterator over successive pairs of values from seq. + func Pairs[V any](seq iter.Seq[V]) iter.Seq2[V, V] { + return func(yield func(V, V) bool) { + next, stop := iter.Pull(seq) + defer stop() + for { + v1, ok1 := next() + if !ok1 { + return + } + v2, ok2 := next() + // If ok2 is false, v2 should be the + // zero value; yield one last pair. + if !yield(v1, v2) { + return + } + if !ok2 { + return + } + } + } + } + +If clients do not consume the sequence to completion, they must call stop, +which allows the iterator function to finish and return. As shown in +the example, the conventional way to ensure this is to use defer. + +# Standard Library Usage + +A few packages in the standard library provide iterator-based APIs, +most notably the [maps] and [slices] packages. +For example, [maps.Keys] returns an iterator over the keys of a map, +while [slices.Sorted] collects the values of an iterator into a slice, +sorts them, and returns the slice, so to iterate over the sorted keys of a map: + + for _, key := range slices.Sorted(maps.Keys(m)) { + ... + } + +# Mutation + +Iterators provide only the values of the sequence, not any direct way +to modify it. If an iterator wishes to provide a mechanism for modifying +a sequence during iteration, the usual approach is to define a position type +with the extra operations and then provide an iterator over positions. + +For example, a tree implementation might provide: + + // Positions returns an iterator over positions in the sequence. + func (t *Tree[V]) Positions() iter.Seq[*Pos] + + // A Pos represents a position in the sequence. + // It is only valid during the yield call it is passed to. + type Pos[V any] struct { ... } + + // Pos returns the value at the cursor. + func (p *Pos[V]) Value() V + + // Delete deletes the value at this point in the iteration. + func (p *Pos[V]) Delete() + + // Set changes the value v at the cursor. + func (p *Pos[V]) Set(v V) + +And then a client could delete boring values from the tree using: + + for p := range t.Positions() { + if boring(p.Value()) { + p.Delete() + } + } +*/ +package iter + +import ( + "internal/race" + "runtime" + "unsafe" +) + +// Seq is an iterator over sequences of individual values. +// When called as seq(yield), seq calls yield(v) for each value v in the sequence, +// stopping early if yield returns false. +// See the [iter] package documentation for more details. +type Seq[V any] func(yield func(V) bool) + +// Seq2 is an iterator over sequences of pairs of values, most commonly key-value pairs. +// When called as seq(yield), seq calls yield(k, v) for each pair (k, v) in the sequence, +// stopping early if yield returns false. +// See the [iter] package documentation for more details. +type Seq2[K, V any] func(yield func(K, V) bool) + +type coro struct{} + +//go:linkname newcoro runtime.newcoro +func newcoro(func(*coro)) *coro + +//go:linkname coroswitch runtime.coroswitch +func coroswitch(*coro) + +// Pull converts the “push-style” iterator sequence seq +// into a “pull-style” iterator accessed by the two functions +// next and stop. +// +// Next returns the next value in the sequence +// and a boolean indicating whether the value is valid. +// When the sequence is over, next returns the zero V and false. +// It is valid to call next after reaching the end of the sequence +// or after calling stop. These calls will continue +// to return the zero V and false. +// +// Stop ends the iteration. It must be called when the caller is +// no longer interested in next values and next has not yet +// signaled that the sequence is over (with a false boolean return). +// It is valid to call stop multiple times and when next has +// already returned false. Typically, callers should “defer stop()”. +// +// It is an error to call next or stop from multiple goroutines +// simultaneously. +// +// If the iterator panics during a call to next (or stop), +// then next (or stop) itself panics with the same value. +func Pull[V any](seq Seq[V]) (next func() (V, bool), stop func()) { + var ( + v V + ok bool + done bool + yieldNext bool + racer int + panicValue any + seqDone bool // to detect Goexit + ) + c := newcoro(func(c *coro) { + race.Acquire(unsafe.Pointer(&racer)) + if done { + race.Release(unsafe.Pointer(&racer)) + return + } + yield := func(v1 V) bool { + if done { + return false + } + if !yieldNext { + panic("iter.Pull: yield called again before next") + } + yieldNext = false + v, ok = v1, true + race.Release(unsafe.Pointer(&racer)) + coroswitch(c) + race.Acquire(unsafe.Pointer(&racer)) + return !done + } + // Recover and propagate panics from seq. + defer func() { + if p := recover(); p != nil { + panicValue = p + } else if !seqDone { + panicValue = goexitPanicValue + } + done = true // Invalidate iterator + race.Release(unsafe.Pointer(&racer)) + }() + seq(yield) + var v0 V + v, ok = v0, false + seqDone = true + }) + next = func() (v1 V, ok1 bool) { + race.Write(unsafe.Pointer(&racer)) // detect races + + if done { + return + } + if yieldNext { + panic("iter.Pull: next called again before yield") + } + yieldNext = true + race.Release(unsafe.Pointer(&racer)) + coroswitch(c) + race.Acquire(unsafe.Pointer(&racer)) + + // Propagate panics and goexits from seq. + if panicValue != nil { + if panicValue == goexitPanicValue { + // Propagate runtime.Goexit from seq. + runtime.Goexit() + } else { + panic(panicValue) + } + } + return v, ok + } + stop = func() { + race.Write(unsafe.Pointer(&racer)) // detect races + + if !done { + done = true + race.Release(unsafe.Pointer(&racer)) + coroswitch(c) + race.Acquire(unsafe.Pointer(&racer)) + + // Propagate panics and goexits from seq. + if panicValue != nil { + if panicValue == goexitPanicValue { + // Propagate runtime.Goexit from seq. + runtime.Goexit() + } else { + panic(panicValue) + } + } + } + } + return next, stop +} + +// Pull2 converts the “push-style” iterator sequence seq +// into a “pull-style” iterator accessed by the two functions +// next and stop. +// +// Next returns the next pair in the sequence +// and a boolean indicating whether the pair is valid. +// When the sequence is over, next returns a pair of zero values and false. +// It is valid to call next after reaching the end of the sequence +// or after calling stop. These calls will continue +// to return a pair of zero values and false. +// +// Stop ends the iteration. It must be called when the caller is +// no longer interested in next values and next has not yet +// signaled that the sequence is over (with a false boolean return). +// It is valid to call stop multiple times and when next has +// already returned false. Typically, callers should “defer stop()”. +// +// It is an error to call next or stop from multiple goroutines +// simultaneously. +// +// If the iterator panics during a call to next (or stop), +// then next (or stop) itself panics with the same value. +func Pull2[K, V any](seq Seq2[K, V]) (next func() (K, V, bool), stop func()) { + var ( + k K + v V + ok bool + done bool + yieldNext bool + racer int + panicValue any + seqDone bool + ) + c := newcoro(func(c *coro) { + race.Acquire(unsafe.Pointer(&racer)) + if done { + race.Release(unsafe.Pointer(&racer)) + return + } + yield := func(k1 K, v1 V) bool { + if done { + return false + } + if !yieldNext { + panic("iter.Pull2: yield called again before next") + } + yieldNext = false + k, v, ok = k1, v1, true + race.Release(unsafe.Pointer(&racer)) + coroswitch(c) + race.Acquire(unsafe.Pointer(&racer)) + return !done + } + // Recover and propagate panics from seq. + defer func() { + if p := recover(); p != nil { + panicValue = p + } else if !seqDone { + panicValue = goexitPanicValue + } + done = true // Invalidate iterator. + race.Release(unsafe.Pointer(&racer)) + }() + seq(yield) + var k0 K + var v0 V + k, v, ok = k0, v0, false + seqDone = true + }) + next = func() (k1 K, v1 V, ok1 bool) { + race.Write(unsafe.Pointer(&racer)) // detect races + + if done { + return + } + if yieldNext { + panic("iter.Pull2: next called again before yield") + } + yieldNext = true + race.Release(unsafe.Pointer(&racer)) + coroswitch(c) + race.Acquire(unsafe.Pointer(&racer)) + + // Propagate panics and goexits from seq. + if panicValue != nil { + if panicValue == goexitPanicValue { + // Propagate runtime.Goexit from seq. + runtime.Goexit() + } else { + panic(panicValue) + } + } + return k, v, ok + } + stop = func() { + race.Write(unsafe.Pointer(&racer)) // detect races + + if !done { + done = true + race.Release(unsafe.Pointer(&racer)) + coroswitch(c) + race.Acquire(unsafe.Pointer(&racer)) + + // Propagate panics and goexits from seq. + if panicValue != nil { + if panicValue == goexitPanicValue { + // Propagate runtime.Goexit from seq. + runtime.Goexit() + } else { + panic(panicValue) + } + } + } + } + return next, stop +} + +// goexitPanicValue is a sentinel value indicating that an iterator +// exited via runtime.Goexit. +var goexitPanicValue any = new(int) diff --git a/contrib/go/_std_1.23/src/iter/ya.make b/contrib/go/_std_1.23/src/iter/ya.make new file mode 100644 index 000000000000..620cac6c9345 --- /dev/null +++ b/contrib/go/_std_1.23/src/iter/ya.make @@ -0,0 +1,7 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + iter.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/log/internal/internal.go b/contrib/go/_std_1.23/src/log/internal/internal.go similarity index 100% rename from contrib/go/_std_1.22/src/log/internal/internal.go rename to contrib/go/_std_1.23/src/log/internal/internal.go diff --git a/contrib/go/_std_1.22/src/log/internal/ya.make b/contrib/go/_std_1.23/src/log/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/internal/ya.make rename to contrib/go/_std_1.23/src/log/internal/ya.make diff --git a/contrib/go/_std_1.22/src/log/log.go b/contrib/go/_std_1.23/src/log/log.go similarity index 100% rename from contrib/go/_std_1.22/src/log/log.go rename to contrib/go/_std_1.23/src/log/log.go diff --git a/contrib/go/_std_1.22/src/log/slog/attr.go b/contrib/go/_std_1.23/src/log/slog/attr.go similarity index 97% rename from contrib/go/_std_1.22/src/log/slog/attr.go rename to contrib/go/_std_1.23/src/log/slog/attr.go index 2f459467cb6f..067c537cc973 100644 --- a/contrib/go/_std_1.22/src/log/slog/attr.go +++ b/contrib/go/_std_1.23/src/log/slog/attr.go @@ -5,7 +5,6 @@ package slog import ( - "fmt" "time" ) @@ -92,7 +91,7 @@ func (a Attr) Equal(b Attr) bool { } func (a Attr) String() string { - return fmt.Sprintf("%s=%s", a.Key, a.Value) + return a.Key + "=" + a.Value.String() } // isEmpty reports whether a has an empty key and a nil value. diff --git a/contrib/go/_std_1.22/src/log/slog/doc.go b/contrib/go/_std_1.23/src/log/slog/doc.go similarity index 97% rename from contrib/go/_std_1.22/src/log/slog/doc.go rename to contrib/go/_std_1.23/src/log/slog/doc.go index 001559326b3e..cc034ca4b976 100644 --- a/contrib/go/_std_1.22/src/log/slog/doc.go +++ b/contrib/go/_std_1.23/src/log/slog/doc.go @@ -310,8 +310,10 @@ Then use a value of that type in log calls: Now computeExpensiveValue will only be called when the line is enabled. The built-in handlers acquire a lock before calling [io.Writer.Write] -to ensure that each record is written in one piece. User-defined -handlers are responsible for their own locking. +to ensure that exactly one [Record] is written at a time in its entirety. +Although each log record has a timestamp, +the built-in handlers do not use that time to sort the written records. +User-defined handlers are responsible for their own locking and sorting. # Writing a handler diff --git a/contrib/go/_std_1.22/src/log/slog/handler.go b/contrib/go/_std_1.23/src/log/slog/handler.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/handler.go rename to contrib/go/_std_1.23/src/log/slog/handler.go diff --git a/contrib/go/_std_1.22/src/log/slog/internal/benchmarks/benchmarks.go b/contrib/go/_std_1.23/src/log/slog/internal/benchmarks/benchmarks.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/benchmarks/benchmarks.go rename to contrib/go/_std_1.23/src/log/slog/internal/benchmarks/benchmarks.go diff --git a/contrib/go/_std_1.22/src/log/slog/internal/benchmarks/handlers.go b/contrib/go/_std_1.23/src/log/slog/internal/benchmarks/handlers.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/benchmarks/handlers.go rename to contrib/go/_std_1.23/src/log/slog/internal/benchmarks/handlers.go diff --git a/contrib/go/_std_1.22/src/log/slog/internal/benchmarks/ya.make b/contrib/go/_std_1.23/src/log/slog/internal/benchmarks/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/benchmarks/ya.make rename to contrib/go/_std_1.23/src/log/slog/internal/benchmarks/ya.make diff --git a/contrib/go/_std_1.22/src/log/slog/internal/buffer/buffer.go b/contrib/go/_std_1.23/src/log/slog/internal/buffer/buffer.go similarity index 90% rename from contrib/go/_std_1.22/src/log/slog/internal/buffer/buffer.go rename to contrib/go/_std_1.23/src/log/slog/internal/buffer/buffer.go index 310ec37d4a12..110c6281ab29 100644 --- a/contrib/go/_std_1.22/src/log/slog/internal/buffer/buffer.go +++ b/contrib/go/_std_1.23/src/log/slog/internal/buffer/buffer.go @@ -7,7 +7,10 @@ package buffer import "sync" -// buffer adapted from go/src/fmt/print.go +// Buffer is a byte buffer. +// +// This implementation is adapted from the unexported type buffer +// in go/src/fmt/print.go. type Buffer []byte // Having an initial size gives a dramatic speedup. diff --git a/contrib/go/_std_1.22/src/log/slog/internal/buffer/ya.make b/contrib/go/_std_1.23/src/log/slog/internal/buffer/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/buffer/ya.make rename to contrib/go/_std_1.23/src/log/slog/internal/buffer/ya.make diff --git a/contrib/go/_std_1.22/src/log/slog/internal/ignorepc.go b/contrib/go/_std_1.23/src/log/slog/internal/ignorepc.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/ignorepc.go rename to contrib/go/_std_1.23/src/log/slog/internal/ignorepc.go diff --git a/contrib/go/_std_1.22/src/log/slog/internal/slogtest/slogtest.go b/contrib/go/_std_1.23/src/log/slog/internal/slogtest/slogtest.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/slogtest/slogtest.go rename to contrib/go/_std_1.23/src/log/slog/internal/slogtest/slogtest.go diff --git a/contrib/go/_std_1.22/src/log/slog/internal/slogtest/ya.make b/contrib/go/_std_1.23/src/log/slog/internal/slogtest/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/slogtest/ya.make rename to contrib/go/_std_1.23/src/log/slog/internal/slogtest/ya.make diff --git a/contrib/go/_std_1.22/src/log/slog/internal/ya.make b/contrib/go/_std_1.23/src/log/slog/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/internal/ya.make rename to contrib/go/_std_1.23/src/log/slog/internal/ya.make diff --git a/contrib/go/_std_1.22/src/log/slog/json_handler.go b/contrib/go/_std_1.23/src/log/slog/json_handler.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/json_handler.go rename to contrib/go/_std_1.23/src/log/slog/json_handler.go diff --git a/contrib/go/_std_1.22/src/log/slog/level.go b/contrib/go/_std_1.23/src/log/slog/level.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/level.go rename to contrib/go/_std_1.23/src/log/slog/level.go diff --git a/contrib/go/_std_1.22/src/log/slog/logger.go b/contrib/go/_std_1.23/src/log/slog/logger.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/logger.go rename to contrib/go/_std_1.23/src/log/slog/logger.go diff --git a/contrib/go/_std_1.22/src/log/slog/record.go b/contrib/go/_std_1.23/src/log/slog/record.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/record.go rename to contrib/go/_std_1.23/src/log/slog/record.go diff --git a/contrib/go/_std_1.22/src/log/slog/text_handler.go b/contrib/go/_std_1.23/src/log/slog/text_handler.go similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/text_handler.go rename to contrib/go/_std_1.23/src/log/slog/text_handler.go diff --git a/contrib/go/_std_1.22/src/log/slog/value.go b/contrib/go/_std_1.23/src/log/slog/value.go similarity index 93% rename from contrib/go/_std_1.22/src/log/slog/value.go rename to contrib/go/_std_1.23/src/log/slog/value.go index d278d9b92355..6b0768eb1dea 100644 --- a/contrib/go/_std_1.22/src/log/slog/value.go +++ b/contrib/go/_std_1.23/src/log/slog/value.go @@ -90,7 +90,7 @@ func (v Value) Kind() Kind { return x case stringptr: return KindString - case timeLocation: + case timeLocation, timeTime: return KindTime case groupptr: return KindGroup @@ -139,9 +139,14 @@ func BoolValue(v bool) Value { return Value{num: u, any: KindBool} } -// Unexported version of *time.Location, just so we can store *time.Locations in -// Values. (No user-provided value has this type.) -type timeLocation *time.Location +type ( + // Unexported version of *time.Location, just so we can store *time.Locations in + // Values. (No user-provided value has this type.) + timeLocation *time.Location + + // timeTime is for times where UnixNano is undefined. + timeTime time.Time +) // TimeValue returns a [Value] for a [time.Time]. // It discards the monotonic portion. @@ -153,7 +158,15 @@ func TimeValue(v time.Time) Value { // mistaken for any other Value, time.Time or otherwise. return Value{any: timeLocation(nil)} } - return Value{num: uint64(v.UnixNano()), any: timeLocation(v.Location())} + nsec := v.UnixNano() + t := time.Unix(0, nsec) + if v.Equal(t) { + // UnixNano correctly represents the time, so use a zero-alloc representation. + return Value{num: uint64(nsec), any: timeLocation(v.Location())} + } + // Fall back to the general form. + // Strip the monotonic portion to match the other representation. + return Value{any: timeTime(v.Round(0))} } // DurationValue returns a [Value] for a [time.Duration]. @@ -368,12 +381,19 @@ func (v Value) Time() time.Time { return v.time() } +// See TimeValue to understand how times are represented. func (v Value) time() time.Time { - loc := v.any.(timeLocation) - if loc == nil { - return time.Time{} + switch a := v.any.(type) { + case timeLocation: + if a == nil { + return time.Time{} + } + return time.Unix(0, int64(v.num)).In(a) + case timeTime: + return time.Time(a) + default: + panic(fmt.Sprintf("bad time type %T", v.any)) } - return time.Unix(0, int64(v.num)).In(loc) } // LogValuer returns v's value as a LogValuer. It panics diff --git a/contrib/go/_std_1.22/src/log/slog/ya.make b/contrib/go/_std_1.23/src/log/slog/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/slog/ya.make rename to contrib/go/_std_1.23/src/log/slog/ya.make diff --git a/contrib/go/_std_1.22/src/log/syslog/doc.go b/contrib/go/_std_1.23/src/log/syslog/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/log/syslog/doc.go rename to contrib/go/_std_1.23/src/log/syslog/doc.go diff --git a/contrib/go/_std_1.22/src/log/syslog/syslog.go b/contrib/go/_std_1.23/src/log/syslog/syslog.go similarity index 100% rename from contrib/go/_std_1.22/src/log/syslog/syslog.go rename to contrib/go/_std_1.23/src/log/syslog/syslog.go diff --git a/contrib/go/_std_1.22/src/log/syslog/syslog_unix.go b/contrib/go/_std_1.23/src/log/syslog/syslog_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/log/syslog/syslog_unix.go rename to contrib/go/_std_1.23/src/log/syslog/syslog_unix.go diff --git a/contrib/go/_std_1.22/src/log/syslog/ya.make b/contrib/go/_std_1.23/src/log/syslog/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/syslog/ya.make rename to contrib/go/_std_1.23/src/log/syslog/ya.make diff --git a/contrib/go/_std_1.22/src/log/ya.make b/contrib/go/_std_1.23/src/log/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/log/ya.make rename to contrib/go/_std_1.23/src/log/ya.make diff --git a/contrib/go/_std_1.23/src/maps/iter.go b/contrib/go/_std_1.23/src/maps/iter.go new file mode 100644 index 000000000000..32f2d514c150 --- /dev/null +++ b/contrib/go/_std_1.23/src/maps/iter.go @@ -0,0 +1,62 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package maps + +import "iter" + +// All returns an iterator over key-value pairs from m. +// The iteration order is not specified and is not guaranteed +// to be the same from one call to the next. +func All[Map ~map[K]V, K comparable, V any](m Map) iter.Seq2[K, V] { + return func(yield func(K, V) bool) { + for k, v := range m { + if !yield(k, v) { + return + } + } + } +} + +// Keys returns an iterator over keys in m. +// The iteration order is not specified and is not guaranteed +// to be the same from one call to the next. +func Keys[Map ~map[K]V, K comparable, V any](m Map) iter.Seq[K] { + return func(yield func(K) bool) { + for k := range m { + if !yield(k) { + return + } + } + } +} + +// Values returns an iterator over values in m. +// The iteration order is not specified and is not guaranteed +// to be the same from one call to the next. +func Values[Map ~map[K]V, K comparable, V any](m Map) iter.Seq[V] { + return func(yield func(V) bool) { + for _, v := range m { + if !yield(v) { + return + } + } + } +} + +// Insert adds the key-value pairs from seq to m. +// If a key in seq already exists in m, its value will be overwritten. +func Insert[Map ~map[K]V, K comparable, V any](m Map, seq iter.Seq2[K, V]) { + for k, v := range seq { + m[k] = v + } +} + +// Collect collects key-value pairs from seq into a new map +// and returns it. +func Collect[K comparable, V any](seq iter.Seq2[K, V]) map[K]V { + m := make(map[K]V) + Insert(m, seq) + return m +} diff --git a/contrib/go/_std_1.23/src/maps/maps.go b/contrib/go/_std_1.23/src/maps/maps.go new file mode 100644 index 000000000000..b712dd3fe8eb --- /dev/null +++ b/contrib/go/_std_1.23/src/maps/maps.go @@ -0,0 +1,75 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package maps defines various functions useful with maps of any type. +// +// This package does not have any special handling for non-reflexive keys +// (keys k where k != k), such as floating-point NaNs. +package maps + +import ( + _ "unsafe" +) + +// Equal reports whether two maps contain the same key/value pairs. +// Values are compared using ==. +func Equal[M1, M2 ~map[K]V, K, V comparable](m1 M1, m2 M2) bool { + if len(m1) != len(m2) { + return false + } + for k, v1 := range m1 { + if v2, ok := m2[k]; !ok || v1 != v2 { + return false + } + } + return true +} + +// EqualFunc is like Equal, but compares values using eq. +// Keys are still compared with ==. +func EqualFunc[M1 ~map[K]V1, M2 ~map[K]V2, K comparable, V1, V2 any](m1 M1, m2 M2, eq func(V1, V2) bool) bool { + if len(m1) != len(m2) { + return false + } + for k, v1 := range m1 { + if v2, ok := m2[k]; !ok || !eq(v1, v2) { + return false + } + } + return true +} + +// clone is implemented in the runtime package. +// +//go:linkname clone maps.clone +func clone(m any) any + +// Clone returns a copy of m. This is a shallow clone: +// the new keys and values are set using ordinary assignment. +func Clone[M ~map[K]V, K comparable, V any](m M) M { + // Preserve nil in case it matters. + if m == nil { + return nil + } + return clone(m).(M) +} + +// Copy copies all key/value pairs in src adding them to dst. +// When a key in src is already present in dst, +// the value in dst will be overwritten by the value associated +// with the key in src. +func Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](dst M1, src M2) { + for k, v := range src { + dst[k] = v + } +} + +// DeleteFunc deletes any key/value pairs from m for which del returns true. +func DeleteFunc[M ~map[K]V, K comparable, V any](m M, del func(K, V) bool) { + for k, v := range m { + if del(k, v) { + delete(m, k) + } + } +} diff --git a/contrib/go/_std_1.23/src/maps/ya.make b/contrib/go/_std_1.23/src/maps/ya.make new file mode 100644 index 000000000000..bfef85a6a054 --- /dev/null +++ b/contrib/go/_std_1.23/src/maps/ya.make @@ -0,0 +1,8 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + iter.go + maps.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/math/abs.go b/contrib/go/_std_1.23/src/math/abs.go similarity index 100% rename from contrib/go/_std_1.22/src/math/abs.go rename to contrib/go/_std_1.23/src/math/abs.go diff --git a/contrib/go/_std_1.22/src/math/acos_s390x.s b/contrib/go/_std_1.23/src/math/acos_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/acos_s390x.s rename to contrib/go/_std_1.23/src/math/acos_s390x.s diff --git a/contrib/go/_std_1.22/src/math/acosh.go b/contrib/go/_std_1.23/src/math/acosh.go similarity index 100% rename from contrib/go/_std_1.22/src/math/acosh.go rename to contrib/go/_std_1.23/src/math/acosh.go diff --git a/contrib/go/_std_1.22/src/math/acosh_s390x.s b/contrib/go/_std_1.23/src/math/acosh_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/acosh_s390x.s rename to contrib/go/_std_1.23/src/math/acosh_s390x.s diff --git a/contrib/go/_std_1.22/src/math/arith_s390x.go b/contrib/go/_std_1.23/src/math/arith_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/math/arith_s390x.go rename to contrib/go/_std_1.23/src/math/arith_s390x.go diff --git a/contrib/go/_std_1.22/src/math/asin.go b/contrib/go/_std_1.23/src/math/asin.go similarity index 100% rename from contrib/go/_std_1.22/src/math/asin.go rename to contrib/go/_std_1.23/src/math/asin.go diff --git a/contrib/go/_std_1.22/src/math/asin_s390x.s b/contrib/go/_std_1.23/src/math/asin_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/asin_s390x.s rename to contrib/go/_std_1.23/src/math/asin_s390x.s diff --git a/contrib/go/_std_1.22/src/math/asinh.go b/contrib/go/_std_1.23/src/math/asinh.go similarity index 100% rename from contrib/go/_std_1.22/src/math/asinh.go rename to contrib/go/_std_1.23/src/math/asinh.go diff --git a/contrib/go/_std_1.22/src/math/asinh_s390x.s b/contrib/go/_std_1.23/src/math/asinh_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/asinh_s390x.s rename to contrib/go/_std_1.23/src/math/asinh_s390x.s diff --git a/contrib/go/_std_1.22/src/math/atan.go b/contrib/go/_std_1.23/src/math/atan.go similarity index 100% rename from contrib/go/_std_1.22/src/math/atan.go rename to contrib/go/_std_1.23/src/math/atan.go diff --git a/contrib/go/_std_1.22/src/math/atan2.go b/contrib/go/_std_1.23/src/math/atan2.go similarity index 100% rename from contrib/go/_std_1.22/src/math/atan2.go rename to contrib/go/_std_1.23/src/math/atan2.go diff --git a/contrib/go/_std_1.22/src/math/atan2_s390x.s b/contrib/go/_std_1.23/src/math/atan2_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/atan2_s390x.s rename to contrib/go/_std_1.23/src/math/atan2_s390x.s diff --git a/contrib/go/_std_1.22/src/math/atan_s390x.s b/contrib/go/_std_1.23/src/math/atan_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/atan_s390x.s rename to contrib/go/_std_1.23/src/math/atan_s390x.s diff --git a/contrib/go/_std_1.22/src/math/atanh.go b/contrib/go/_std_1.23/src/math/atanh.go similarity index 100% rename from contrib/go/_std_1.22/src/math/atanh.go rename to contrib/go/_std_1.23/src/math/atanh.go diff --git a/contrib/go/_std_1.22/src/math/atanh_s390x.s b/contrib/go/_std_1.23/src/math/atanh_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/atanh_s390x.s rename to contrib/go/_std_1.23/src/math/atanh_s390x.s diff --git a/contrib/go/_std_1.22/src/math/big/accuracy_string.go b/contrib/go/_std_1.23/src/math/big/accuracy_string.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/accuracy_string.go rename to contrib/go/_std_1.23/src/math/big/accuracy_string.go diff --git a/contrib/go/_std_1.22/src/math/big/arith.go b/contrib/go/_std_1.23/src/math/big/arith.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith.go rename to contrib/go/_std_1.23/src/math/big/arith.go diff --git a/contrib/go/_std_1.22/src/math/big/arith_386.s b/contrib/go/_std_1.23/src/math/big/arith_386.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_386.s rename to contrib/go/_std_1.23/src/math/big/arith_386.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_amd64.go b/contrib/go/_std_1.23/src/math/big/arith_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_amd64.go rename to contrib/go/_std_1.23/src/math/big/arith_amd64.go diff --git a/contrib/go/_std_1.22/src/math/big/arith_amd64.s b/contrib/go/_std_1.23/src/math/big/arith_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_amd64.s rename to contrib/go/_std_1.23/src/math/big/arith_amd64.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_arm.s b/contrib/go/_std_1.23/src/math/big/arith_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_arm.s rename to contrib/go/_std_1.23/src/math/big/arith_arm.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_arm64.s b/contrib/go/_std_1.23/src/math/big/arith_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_arm64.s rename to contrib/go/_std_1.23/src/math/big/arith_arm64.s diff --git a/contrib/go/_std_1.23/src/math/big/arith_decl.go b/contrib/go/_std_1.23/src/math/big/arith_decl.go new file mode 100644 index 000000000000..3230a781a9de --- /dev/null +++ b/contrib/go/_std_1.23/src/math/big/arith_decl.go @@ -0,0 +1,98 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !math_big_pure_go + +package big + +import _ "unsafe" // for linkname + +// implemented in arith_$GOARCH.s + +// addVV should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/remyoudompheng/bigfft +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname addVV +//go:noescape +func addVV(z, x, y []Word) (c Word) + +// subVV should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/remyoudompheng/bigfft +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname subVV +//go:noescape +func subVV(z, x, y []Word) (c Word) + +// addVW should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/remyoudompheng/bigfft +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname addVW +//go:noescape +func addVW(z, x []Word, y Word) (c Word) + +// subVW should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/remyoudompheng/bigfft +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname subVW +//go:noescape +func subVW(z, x []Word, y Word) (c Word) + +// shlVU should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/remyoudompheng/bigfft +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname shlVU +//go:noescape +func shlVU(z, x []Word, s uint) (c Word) + +//go:noescape +func shrVU(z, x []Word, s uint) (c Word) + +// mulAddVWW should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/remyoudompheng/bigfft +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mulAddVWW +//go:noescape +func mulAddVWW(z, x []Word, y, r Word) (c Word) + +// addMulVVW should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/remyoudompheng/bigfft +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname addMulVVW +//go:noescape +func addMulVVW(z, x []Word, y Word) (c Word) diff --git a/contrib/go/_std_1.22/src/math/big/arith_decl_pure.go b/contrib/go/_std_1.23/src/math/big/arith_decl_pure.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_decl_pure.go rename to contrib/go/_std_1.23/src/math/big/arith_decl_pure.go diff --git a/contrib/go/_std_1.22/src/math/big/arith_decl_s390x.go b/contrib/go/_std_1.23/src/math/big/arith_decl_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_decl_s390x.go rename to contrib/go/_std_1.23/src/math/big/arith_decl_s390x.go diff --git a/contrib/go/_std_1.22/src/math/big/arith_loong64.s b/contrib/go/_std_1.23/src/math/big/arith_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_loong64.s rename to contrib/go/_std_1.23/src/math/big/arith_loong64.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_mips64x.s b/contrib/go/_std_1.23/src/math/big/arith_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_mips64x.s rename to contrib/go/_std_1.23/src/math/big/arith_mips64x.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_mipsx.s b/contrib/go/_std_1.23/src/math/big/arith_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_mipsx.s rename to contrib/go/_std_1.23/src/math/big/arith_mipsx.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_ppc64x.s b/contrib/go/_std_1.23/src/math/big/arith_ppc64x.s similarity index 84% rename from contrib/go/_std_1.22/src/math/big/arith_ppc64x.s rename to contrib/go/_std_1.23/src/math/big/arith_ppc64x.s index 9512a12270d4..82aa7fb51e44 100644 --- a/contrib/go/_std_1.22/src/math/big/arith_ppc64x.s +++ b/contrib/go/_std_1.23/src/math/big/arith_ppc64x.s @@ -18,7 +18,7 @@ TEXT ·addVV(SB), NOSPLIT, $0 MOVD z+0(FP), R10 // R10 = z[] // If z_len = 0, we are done - CMP R0, R7 + CMP R7, $0 MOVD R0, R4 BEQ done @@ -28,12 +28,12 @@ TEXT ·addVV(SB), NOSPLIT, $0 MOVD 0(R9), R12 // R12 = y[i] ADD $-1, R7 // R7 = z_len - 1 ADDC R12, R11, R15 // R15 = x[i] + y[i], set CA - CMP R0, R7 + CMP R7, $0 MOVD R15, 0(R10) // z[i] BEQ final // If z_len was 1, we are done SRD $2, R7, R5 // R5 = z_len/4 - CMP R0, R5 + CMP R5, $0 MOVD R5, CTR // Set up loop counter BEQ tail // If R5 = 0, we can't use the loop @@ -62,10 +62,10 @@ loop: MOVD R22, 24(R10) // z[i+2] MOVDU R23, 32(R10) // z[i+3] ADD $-4, R7 // R7 = z_len - 4 - BC 16, 0, loop // bdnz + BDNZ loop // We may have more elements to read - CMP R0, R7 + CMP R7, $0 BEQ final // Process the remaining elements, one at a time @@ -74,7 +74,7 @@ tail: MOVDU 8(R9), R16 // R16 = y[i] ADD $-1, R7 // R7 = z_len - 1 ADDE R11, R16, R20 // R20 = x[i] + y[i] + CA - CMP R0, R7 + CMP R7, $0 MOVDU R20, 8(R10) // z[i] BEQ final // If R7 = 0, we are done @@ -82,7 +82,7 @@ tail: MOVDU 8(R9), R16 ADD $-1, R7 ADDE R11, R16, R20 - CMP R0, R7 + CMP R7, $0 MOVDU R20, 8(R10) BEQ final @@ -107,7 +107,7 @@ TEXT ·subVV(SB), NOSPLIT, $0 MOVD z+0(FP), R10 // R10 = z[] // If z_len = 0, we are done - CMP R0, R7 + CMP R7, $0 MOVD R0, R4 BEQ done @@ -117,12 +117,12 @@ TEXT ·subVV(SB), NOSPLIT, $0 MOVD 0(R9), R12 // R12 = y[i] ADD $-1, R7 // R7 = z_len - 1 SUBC R12, R11, R15 // R15 = x[i] - y[i], set CA - CMP R0, R7 + CMP R7, $0 MOVD R15, 0(R10) // z[i] BEQ final // If z_len was 1, we are done SRD $2, R7, R5 // R5 = z_len/4 - CMP R0, R5 + CMP R5, $0 MOVD R5, CTR // Set up loop counter BEQ tail // If R5 = 0, we can't use the loop @@ -151,10 +151,10 @@ loop: MOVD R22, 24(R10) // z[i+2] MOVDU R23, 32(R10) // z[i+3] ADD $-4, R7 // R7 = z_len - 4 - BC 16, 0, loop // bdnz + BDNZ loop // We may have more elements to read - CMP R0, R7 + CMP R7, $0 BEQ final // Process the remaining elements, one at a time @@ -163,7 +163,7 @@ tail: MOVDU 8(R9), R16 // R16 = y[i] ADD $-1, R7 // R7 = z_len - 1 SUBE R16, R11, R20 // R20 = x[i] - y[i] + CA - CMP R0, R7 + CMP R7, $0 MOVDU R20, 8(R10) // z[i] BEQ final // If R7 = 0, we are done @@ -171,7 +171,7 @@ tail: MOVDU 8(R9), R16 ADD $-1, R7 SUBE R16, R11, R20 - CMP R0, R7 + CMP R7, $0 MOVDU R20, 8(R10) BEQ final @@ -195,7 +195,7 @@ TEXT ·addVW(SB), NOSPLIT, $0 MOVD y+48(FP), R4 // R4 = y = c MOVD z_len+8(FP), R11 // R11 = z_len - CMP R0, R11 // If z_len is zero, return + CMP R11, $0 // If z_len is zero, return BEQ done // We will process the first iteration out of the loop so we capture @@ -204,14 +204,13 @@ TEXT ·addVW(SB), NOSPLIT, $0 MOVD 0(R8), R20 // R20 = x[i] ADD $-1, R11 // R11 = z_len - 1 ADDC R20, R4, R6 // R6 = x[i] + c - CMP R0, R11 // If z_len was 1, we are done + CMP R11, $0 // If z_len was 1, we are done MOVD R6, 0(R10) // z[i] BEQ final // We will read 4 elements per iteration - SRD $2, R11, R9 // R9 = z_len/4 + SRDCC $2, R11, R9 // R9 = z_len/4 DCBT (R8) - CMP R0, R9 MOVD R9, CTR // Set up the loop counter BEQ tail // If R9 = 0, we can't use the loop PCALIGN $16 @@ -230,10 +229,10 @@ loop: MOVD R26, 24(R10) // z[i+2] MOVDU R27, 32(R10) // z[i+3] ADD $-4, R11 // R11 = z_len - 4 - BC 16, 0, loop // bdnz + BDNZ loop // We may have some elements to read - CMP R0, R11 + CMP R11, $0 BEQ final tail: @@ -241,14 +240,14 @@ tail: ADDZE R20, R24 ADD $-1, R11 MOVDU R24, 8(R10) - CMP R0, R11 + CMP R11, $0 BEQ final MOVDU 8(R8), R20 ADDZE R20, R24 ADD $-1, R11 MOVDU R24, 8(R10) - CMP R0, R11 + CMP R11, $0 BEQ final MOVD 8(R8), R20 @@ -268,7 +267,7 @@ TEXT ·subVW(SB), NOSPLIT, $0 MOVD y+48(FP), R4 // R4 = y = c MOVD z_len+8(FP), R11 // R11 = z_len - CMP R0, R11 // If z_len is zero, return + CMP R11, $0 // If z_len is zero, return BEQ done // We will process the first iteration out of the loop so we capture @@ -277,14 +276,13 @@ TEXT ·subVW(SB), NOSPLIT, $0 MOVD 0(R8), R20 // R20 = x[i] ADD $-1, R11 // R11 = z_len - 1 SUBC R4, R20, R6 // R6 = x[i] - c - CMP R0, R11 // If z_len was 1, we are done + CMP R11, $0 // If z_len was 1, we are done MOVD R6, 0(R10) // z[i] BEQ final // We will read 4 elements per iteration - SRD $2, R11, R9 // R9 = z_len/4 + SRDCC $2, R11, R9 // R9 = z_len/4 DCBT (R8) - CMP R0, R9 MOVD R9, CTR // Set up the loop counter BEQ tail // If R9 = 0, we can't use the loop @@ -307,10 +305,10 @@ loop: MOVD R22, 24(R10) MOVDU R23, 32(R10) ADD $-4, R11 - BC 16, 0, loop // bdnz + BDNZ loop // We may have some elements to read - CMP R0, R11 + CMP R11, $0 BEQ final tail: @@ -318,14 +316,14 @@ tail: SUBE R0, R20 ADD $-1, R11 MOVDU R20, 8(R10) - CMP R0, R11 + CMP R11, $0 BEQ final MOVDU 8(R8), R20 SUBE R0, R20 ADD $-1, R11 MOVDU R20, 8(R10) - CMP R0, R11 + CMP R11, $0 BEQ final MOVD 8(R8), R20 @@ -348,9 +346,9 @@ TEXT ·shlVU(SB), NOSPLIT, $0 MOVD s+48(FP), R9 MOVD z_len+8(FP), R4 MOVD x_len+32(FP), R7 - CMP R9, R0 // s==0 copy(z,x) + CMP R9, $0 // s==0 copy(z,x) BEQ zeroshift - CMP R4, R0 // len(z)==0 return + CMP R4, $0 // len(z)==0 return BEQ done ADD $-1, R4, R5 // len(z)-1 @@ -360,7 +358,7 @@ TEXT ·shlVU(SB), NOSPLIT, $0 ADD R3, R7, R16 // save starting address &z[len(z)-1] MOVD (R6)(R7), R14 SRD R4, R14, R7 // compute x[len(z)-1]>>ŝ into R7 - CMP R5, R0 // iterate from i=len(z)-1 to 0 + CMP R5, $0 // iterate from i=len(z)-1 to 0 BEQ loopexit // Already at end? MOVD 0(R15),R10 // x[i] PCALIGN $16 @@ -382,7 +380,7 @@ loopexit: RET zeroshift: - CMP R6, R0 // x is null, nothing to copy + CMP R6, $0 // x is null, nothing to copy BEQ done CMP R6, R3 // if x is same as z, nothing to copy BEQ done @@ -423,9 +421,9 @@ TEXT ·shrVU(SB), NOSPLIT, $0 MOVD z_len+8(FP), R4 MOVD x_len+32(FP), R7 - CMP R9, R0 // s==0, copy(z,x) + CMP R9, $0 // s==0, copy(z,x) BEQ zeroshift - CMP R4, R0 // len(z)==0 return + CMP R4, $0 // len(z)==0 return BEQ done SUBC R9, $64, R5 // ŝ=_W-s, we skip & by _W-1 as the caller ensures s < _W(64) @@ -480,7 +478,7 @@ loopexit: RET zeroshift: - CMP R6, R0 // x is null, nothing to copy + CMP R6, $0 // x is null, nothing to copy BEQ done CMP R6, R3 // if x is same as z, nothing to copy BEQ done @@ -506,7 +504,7 @@ TEXT ·mulAddVWW(SB), NOSPLIT, $0 MOVD r+56(FP), R4 // R4 = r = c MOVD z_len+8(FP), R11 // R11 = z_len - CMP R0, R11 + CMP R11, $0 BEQ done MOVD 0(R8), R20 @@ -514,16 +512,14 @@ TEXT ·mulAddVWW(SB), NOSPLIT, $0 MULLD R9, R20, R6 // R6 = z0 = Low-order(x[i]*y) MULHDU R9, R20, R7 // R7 = z1 = High-order(x[i]*y) ADDC R4, R6 // R6 = z0 + r - ADDZE R7 // R7 = z1 + CA - CMP R0, R11 - MOVD R7, R4 // R4 = c + ADDZE R7, R4 // R4 = z1 + CA + CMP R11, $0 MOVD R6, 0(R10) // z[i] BEQ done // We will read 4 elements per iteration - SRD $2, R11, R14 // R14 = z_len/4 + SRDCC $2, R11, R14 // R14 = z_len/4 DCBT (R8) - CMP R0, R14 MOVD R14, CTR // Set up the loop counter BEQ tail // If R9 = 0, we can't use the loop PCALIGN $16 @@ -536,28 +532,25 @@ loop: MULLD R9, R20, R24 // R24 = z0[i] MULHDU R9, R20, R20 // R20 = z1[i] ADDC R4, R24 // R24 = z0[i] + c - ADDZE R20 // R7 = z1[i] + CA MULLD R9, R21, R25 MULHDU R9, R21, R21 - ADDC R20, R25 - ADDZE R21 + ADDE R20, R25 MULLD R9, R22, R26 MULHDU R9, R22, R22 MULLD R9, R23, R27 MULHDU R9, R23, R23 - ADDC R21, R26 - ADDZE R22 + ADDE R21, R26 MOVD R24, 8(R10) // z[i] MOVD R25, 16(R10) // z[i+1] - ADDC R22, R27 + ADDE R22, R27 ADDZE R23,R4 // update carry MOVD R26, 24(R10) // z[i+2] MOVDU R27, 32(R10) // z[i+3] ADD $-4, R11 // R11 = z_len - 4 - BC 16, 0, loop // bdnz + BDNZ loop // We may have some elements to read - CMP R0, R11 + CMP R11, $0 BEQ done // Process the remaining elements, one at a time @@ -567,10 +560,9 @@ tail: MULHDU R9, R20, R25 // R25 = z1[i] ADD $-1, R11 // R11 = z_len - 1 ADDC R4, R24 - ADDZE R25 + ADDZE R25, R4 MOVDU R24, 8(R10) // z[i] - CMP R0, R11 - MOVD R25, R4 // R4 = c + CMP R11, $0 BEQ done // If R11 = 0, we are done MOVDU 8(R8), R20 @@ -578,10 +570,9 @@ tail: MULHDU R9, R20, R25 ADD $-1, R11 ADDC R4, R24 - ADDZE R25 + ADDZE R25, R4 MOVDU R24, 8(R10) - CMP R0, R11 - MOVD R25, R4 + CMP R11, $0 BEQ done MOVD 8(R8), R20 @@ -589,9 +580,8 @@ tail: MULHDU R9, R20, R25 ADD $-1, R11 ADDC R4, R24 - ADDZE R25 + ADDZE R25,R4 MOVD R24, 8(R10) - MOVD R25, R4 done: MOVD R4, c+64(FP) @@ -599,33 +589,80 @@ done: // func addMulVVW(z, x []Word, y Word) (c Word) TEXT ·addMulVVW(SB), NOSPLIT, $0 - MOVD z+0(FP), R10 // R10 = z[] - MOVD x+24(FP), R8 // R8 = x[] - MOVD y+48(FP), R9 // R9 = y - MOVD z_len+8(FP), R22 // R22 = z_len - - MOVD R0, R3 // R3 will be the index register - CMP R0, R22 - MOVD R0, R4 // R4 = c = 0 - MOVD R22, CTR // Initialize loop counter - BEQ done - PCALIGN $16 + MOVD z+0(FP), R3 // R3 = z[] + MOVD x+24(FP), R4 // R4 = x[] + MOVD y+48(FP), R5 // R5 = y + MOVD z_len+8(FP), R6 // R6 = z_len + + CMP R6, $4 + MOVD R0, R9 // R9 = c = 0 + BLT tail + SRD $2, R6, R7 + MOVD R7, CTR // Initialize loop counter + PCALIGN $16 loop: - MOVD (R8)(R3), R20 // Load x[i] - MOVD (R10)(R3), R21 // Load z[i] - MULLD R9, R20, R6 // R6 = Low-order(x[i]*y) - MULHDU R9, R20, R7 // R7 = High-order(x[i]*y) - ADDC R21, R6 // R6 = z0 - ADDZE R7 // R7 = z1 - ADDC R4, R6 // R6 = z0 + c + 0 - ADDZE R7, R4 // c += z1 - MOVD R6, (R10)(R3) // Store z[i] - ADD $8, R3 - BC 16, 0, loop // bdnz + MOVD 0(R4), R14 // x[i] + MOVD 8(R4), R16 // x[i+1] + MOVD 16(R4), R18 // x[i+2] + MOVD 24(R4), R20 // x[i+3] + MOVD 0(R3), R15 // z[i] + MOVD 8(R3), R17 // z[i+1] + MOVD 16(R3), R19 // z[i+2] + MOVD 24(R3), R21 // z[i+3] + MULLD R5, R14, R10 // low x[i]*y + MULHDU R5, R14, R11 // high x[i]*y + ADDC R15, R10 + ADDZE R11 + ADDC R9, R10 + ADDZE R11, R9 + MULLD R5, R16, R14 // low x[i+1]*y + MULHDU R5, R16, R15 // high x[i+1]*y + ADDC R17, R14 + ADDZE R15 + ADDC R9, R14 + ADDZE R15, R9 + MULLD R5, R18, R16 // low x[i+2]*y + MULHDU R5, R18, R17 // high x[i+2]*y + ADDC R19, R16 + ADDZE R17 + ADDC R9, R16 + ADDZE R17, R9 + MULLD R5, R20, R18 // low x[i+3]*y + MULHDU R5, R20, R19 // high x[i+3]*y + ADDC R21, R18 + ADDZE R19 + ADDC R9, R18 + ADDZE R19, R9 + MOVD R10, 0(R3) // z[i] + MOVD R14, 8(R3) // z[i+1] + MOVD R16, 16(R3) // z[i+2] + MOVD R18, 24(R3) // z[i+3] + ADD $32, R3 + ADD $32, R4 + BDNZ loop + + ANDCC $3, R6 +tail: + CMP R6, $0 + BEQ done + MOVD R6, CTR + PCALIGN $16 +tailloop: + MOVD 0(R4), R14 + MOVD 0(R3), R15 + MULLD R5, R14, R10 + MULHDU R5, R14, R11 + ADDC R15, R10 + ADDZE R11 + ADDC R9, R10 + ADDZE R11, R9 + MOVD R10, 0(R3) + ADD $8, R3 + ADD $8, R4 + BDNZ tailloop done: - MOVD R4, c+56(FP) + MOVD R9, c+56(FP) RET - diff --git a/contrib/go/_std_1.22/src/math/big/arith_riscv64.s b/contrib/go/_std_1.23/src/math/big/arith_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_riscv64.s rename to contrib/go/_std_1.23/src/math/big/arith_riscv64.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_s390x.s b/contrib/go/_std_1.23/src/math/big/arith_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_s390x.s rename to contrib/go/_std_1.23/src/math/big/arith_s390x.s diff --git a/contrib/go/_std_1.22/src/math/big/arith_wasm.s b/contrib/go/_std_1.23/src/math/big/arith_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/math/big/arith_wasm.s rename to contrib/go/_std_1.23/src/math/big/arith_wasm.s diff --git a/contrib/go/_std_1.22/src/math/big/decimal.go b/contrib/go/_std_1.23/src/math/big/decimal.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/decimal.go rename to contrib/go/_std_1.23/src/math/big/decimal.go diff --git a/contrib/go/_std_1.22/src/math/big/doc.go b/contrib/go/_std_1.23/src/math/big/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/doc.go rename to contrib/go/_std_1.23/src/math/big/doc.go diff --git a/contrib/go/_std_1.22/src/math/big/float.go b/contrib/go/_std_1.23/src/math/big/float.go similarity index 98% rename from contrib/go/_std_1.22/src/math/big/float.go rename to contrib/go/_std_1.23/src/math/big/float.go index 1c97ec98c004..813c4ebfa747 100644 --- a/contrib/go/_std_1.22/src/math/big/float.go +++ b/contrib/go/_std_1.23/src/math/big/float.go @@ -48,10 +48,10 @@ const debugFloat = false // enable for debugging // // By setting the desired precision to 24 or 53 and using matching rounding // mode (typically [ToNearestEven]), Float operations produce the same results -// as the corresponding float32 or float64 IEEE-754 arithmetic for operands +// as the corresponding float32 or float64 IEEE 754 arithmetic for operands // that correspond to normal (i.e., not denormal) float32 or float64 numbers. // Exponent underflow and overflow lead to a 0 or an Infinity for different -// values than IEEE-754 because Float exponents have a much larger range. +// values than IEEE 754 because Float exponents have a much larger range. // // The zero (uninitialized) value for a Float is ready to use and represents // the number +0.0 exactly, with precision 0 and rounding mode [ToNearestEven]. @@ -73,7 +73,7 @@ type Float struct { } // An ErrNaN panic is raised by a [Float] operation that would lead to -// a NaN under IEEE-754 rules. An ErrNaN implements the error interface. +// a NaN under IEEE 754 rules. An ErrNaN implements the error interface. type ErrNaN struct { msg string } @@ -232,10 +232,9 @@ func (x *Float) Acc() Accuracy { } // Sign returns: -// -// -1 if x < 0 -// 0 if x is ±0 -// +1 if x > 0 +// - -1 if x < 0; +// - 0 if x is ±0; +// - +1 if x > 0. func (x *Float) Sign() int { if debugFloat { x.validate() @@ -393,7 +392,7 @@ func (x *Float) validate0() string { // have before calling round. z's mantissa must be normalized (with the msb set) // or empty. // -// CAUTION: The rounding modes ToNegativeInf, ToPositiveInf are affected by the +// CAUTION: The rounding modes [ToNegativeInf], [ToPositiveInf] are affected by the // sign of z. For correct rounding, the sign of z must be set correctly before // calling round. func (z *Float) round(sbit uint) { @@ -672,9 +671,8 @@ func (z *Float) Set(x *Float) *Float { return z } -// Copy sets z to x, with the same precision, rounding mode, and -// accuracy as x, and returns z. x is not changed even if z and -// x are the same. +// Copy sets z to x, with the same precision, rounding mode, and accuracy as x. +// Copy returns z. If x and z are identical, Copy is a no-op. func (z *Float) Copy(x *Float) *Float { if debugFloat { x.validate() @@ -734,7 +732,7 @@ func msb64(x nat) uint64 { } // Uint64 returns the unsigned integer resulting from truncating x -// towards zero. If 0 <= x <= math.MaxUint64, the result is [Exact] +// towards zero. If 0 <= x <= [math.MaxUint64], the result is [Exact] // if x is an integer and [Below] otherwise. // The result is (0, [Above]) for x < 0, and ([math.MaxUint64], [Below]) // for x > [math.MaxUint64]. @@ -1674,10 +1672,9 @@ func (z *Float) Quo(x, y *Float) *Float { } // Cmp compares x and y and returns: -// -// -1 if x < y -// 0 if x == y (incl. -0 == 0, -Inf == -Inf, and +Inf == +Inf) -// +1 if x > y +// - -1 if x < y; +// - 0 if x == y (incl. -0 == 0, -Inf == -Inf, and +Inf == +Inf); +// - +1 if x > y. func (x *Float) Cmp(y *Float) int { if debugFloat { x.validate() diff --git a/contrib/go/_std_1.22/src/math/big/floatconv.go b/contrib/go/_std_1.23/src/math/big/floatconv.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/floatconv.go rename to contrib/go/_std_1.23/src/math/big/floatconv.go diff --git a/contrib/go/_std_1.22/src/math/big/floatmarsh.go b/contrib/go/_std_1.23/src/math/big/floatmarsh.go similarity index 94% rename from contrib/go/_std_1.22/src/math/big/floatmarsh.go rename to contrib/go/_std_1.23/src/math/big/floatmarsh.go index 8a908cef28ab..16be94697147 100644 --- a/contrib/go/_std_1.22/src/math/big/floatmarsh.go +++ b/contrib/go/_std_1.23/src/math/big/floatmarsh.go @@ -7,9 +7,9 @@ package big import ( - "encoding/binary" "errors" "fmt" + "internal/byteorder" ) // Gob codec version. Permits backward-compatible changes to the encoding. @@ -48,10 +48,10 @@ func (x *Float) GobEncode() ([]byte, error) { b |= 1 } buf[1] = b - binary.BigEndian.PutUint32(buf[2:], x.prec) + byteorder.BePutUint32(buf[2:], x.prec) if x.form == finite { - binary.BigEndian.PutUint32(buf[6:], uint32(x.exp)) + byteorder.BePutUint32(buf[6:], uint32(x.exp)) x.mant[len(x.mant)-n:].bytes(buf[10:]) // cut off unused trailing words } @@ -84,13 +84,13 @@ func (z *Float) GobDecode(buf []byte) error { z.acc = Accuracy((b>>3)&3) - 1 z.form = form((b >> 1) & 3) z.neg = b&1 != 0 - z.prec = binary.BigEndian.Uint32(buf[2:]) + z.prec = byteorder.BeUint32(buf[2:]) if z.form == finite { if len(buf) < 10 { return errors.New("Float.GobDecode: buffer too small for finite form float") } - z.exp = int32(binary.BigEndian.Uint32(buf[6:])) + z.exp = int32(byteorder.BeUint32(buf[6:])) z.mant = z.mant.setBytes(buf[10:]) } diff --git a/contrib/go/_std_1.22/src/math/big/ftoa.go b/contrib/go/_std_1.23/src/math/big/ftoa.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/ftoa.go rename to contrib/go/_std_1.23/src/math/big/ftoa.go diff --git a/contrib/go/_std_1.22/src/math/big/int.go b/contrib/go/_std_1.23/src/math/big/int.go similarity index 98% rename from contrib/go/_std_1.22/src/math/big/int.go rename to contrib/go/_std_1.23/src/math/big/int.go index b79b4592709f..944b70c0621a 100644 --- a/contrib/go/_std_1.22/src/math/big/int.go +++ b/contrib/go/_std_1.23/src/math/big/int.go @@ -38,10 +38,9 @@ type Int struct { var intOne = &Int{false, natOne} // Sign returns: -// -// -1 if x < 0 -// 0 if x == 0 -// +1 if x > 0 +// - -1 if x < 0; +// - 0 if x == 0; +// - +1 if x > 0. func (x *Int) Sign() int { // This function is used in cryptographic operations. It must not leak // anything but the Int's sign and bit size through side-channels. Any @@ -289,7 +288,7 @@ func (z *Int) Rem(x, y *Int) *Int { // r = x - y*q // // (See Daan Leijen, “Division and Modulus for Computer Scientists”.) -// See DivMod for Euclidean division and modulus (unlike Go). +// See [DivMod] for Euclidean division and modulus (unlike Go). func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) { z.abs, r.abs = z.abs.div(r.abs, x.abs, y.abs) z.neg, r.neg = len(z.abs) > 0 && x.neg != y.neg, len(r.abs) > 0 && x.neg // 0 has no sign @@ -366,10 +365,9 @@ func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) { } // Cmp compares x and y and returns: -// -// -1 if x < y -// 0 if x == y -// +1 if x > y +// - -1 if x < y; +// - 0 if x == y; +// - +1 if x > y. func (x *Int) Cmp(y *Int) (r int) { // x cmp y == x cmp y // x cmp (-y) == x @@ -392,10 +390,9 @@ func (x *Int) Cmp(y *Int) (r int) { } // CmpAbs compares the absolute values of x and y and returns: -// -// -1 if |x| < |y| -// 0 if |x| == |y| -// +1 if |x| > |y| +// - -1 if |x| < |y|; +// - 0 if |x| == |y|; +// - +1 if |x| > |y|. func (x *Int) CmpAbs(y *Int) int { return x.abs.cmp(y.abs) } @@ -533,10 +530,8 @@ func (x *Int) Bytes() []byte { // // If the absolute value of x doesn't fit in buf, FillBytes will panic. func (x *Int) FillBytes(buf []byte) []byte { - // Clear whole buffer. (This gets optimized into a memclr.) - for i := range buf { - buf[i] = 0 - } + // Clear whole buffer. + clear(buf) x.abs.bytes(buf) return buf } @@ -1152,9 +1147,10 @@ func (x *Int) Bit(i int) uint { } // SetBit sets z to x, with x's i'th bit set to b (0 or 1). -// That is, if b is 1 SetBit sets z = x | (1 << i); -// if b is 0 SetBit sets z = x &^ (1 << i). If b is not 0 or 1, -// SetBit will panic. +// That is, +// - if b is 1, SetBit sets z = x | (1 << i); +// - if b is 0, SetBit sets z = x &^ (1 << i); +// - if b is not 0 or 1, SetBit will panic. func (z *Int) SetBit(x *Int, i int, b uint) *Int { if i < 0 { panic("negative bit index") diff --git a/contrib/go/_std_1.22/src/math/big/intconv.go b/contrib/go/_std_1.23/src/math/big/intconv.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/intconv.go rename to contrib/go/_std_1.23/src/math/big/intconv.go diff --git a/contrib/go/_std_1.22/src/math/big/intmarsh.go b/contrib/go/_std_1.23/src/math/big/intmarsh.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/intmarsh.go rename to contrib/go/_std_1.23/src/math/big/intmarsh.go diff --git a/contrib/go/_std_1.22/src/math/big/nat.go b/contrib/go/_std_1.23/src/math/big/nat.go similarity index 98% rename from contrib/go/_std_1.22/src/math/big/nat.go rename to contrib/go/_std_1.23/src/math/big/nat.go index ecb7d363d4fb..23b2a0b8ddf0 100644 --- a/contrib/go/_std_1.22/src/math/big/nat.go +++ b/contrib/go/_std_1.23/src/math/big/nat.go @@ -14,7 +14,7 @@ package big import ( - "encoding/binary" + "internal/byteorder" "math/bits" "math/rand" "sync" @@ -44,12 +44,6 @@ func (z nat) String() string { return "0x" + string(z.itoa(false, 16)) } -func (z nat) clear() { - for i := range z { - z[i] = 0 - } -} - func (z nat) norm() nat { i := len(z) for i > 0 && z[i-1] == 0 { @@ -196,7 +190,7 @@ func (z nat) mulAddWW(x nat, y, r Word) nat { // basicMul multiplies x and y and leaves the result in z. // The (non-normalized) result is placed in z[0 : len(x) + len(y)]. func basicMul(z, x, y nat) { - z[0 : len(x)+len(y)].clear() // initialize z + clear(z[0 : len(x)+len(y)]) // initialize z for i, d := range y { if d != 0 { z[len(x)+i] = addMulVVW(z[i:i+len(x)], x, d) @@ -222,7 +216,7 @@ func (z nat) montgomery(x, y, m nat, k Word, n int) nat { panic("math/big: mismatched montgomery number lengths") } z = z.make(n * 2) - z.clear() + clear(z) var c Word for i := 0; i < n; i++ { d := y[i] @@ -443,8 +437,8 @@ func (z nat) mul(x, y nat) nat { y0 := y[0:k] // y0 is not normalized z = z.make(max(6*k, m+n)) // enough space for karatsuba of x0*y0 and full result of x*y karatsuba(z, x0, y0) - z = z[0 : m+n] // z has final length but may be incomplete - z[2*k:].clear() // upper portion of z is garbage (and 2*k <= m+n since k <= n <= m) + z = z[0 : m+n] // z has final length but may be incomplete + clear(z[2*k:]) // upper portion of z is garbage (and 2*k <= m+n since k <= n <= m) // If xh != 0 or yh != 0, add the missing terms to z. For // @@ -497,7 +491,7 @@ func basicSqr(z, x nat) { n := len(x) tp := getNat(2 * n) t := *tp // temporary variable to hold the products - t.clear() + clear(t) z[1], z[0] = mulWW(x[0], x[0]) // the initial square for i := 1; i < n; i++ { d := x[i] @@ -592,7 +586,7 @@ func (z nat) sqr(x nat) nat { z = z.make(max(6*k, 2*n)) karatsubaSqr(z, x0) // z = x0^2 z = z[0 : 2*n] - z[2*k:].clear() + clear(z[2*k:]) if k < n { tp := getNat(2 * k) @@ -723,7 +717,7 @@ func (z nat) shl(x nat, s uint) nat { n := m + int(s/_W) z = z.make(n + 1) z[n] = shlVU(z[n-m:n], x, s%_W) - z[0 : n-m].clear() + clear(z[0 : n-m]) return z.norm() } @@ -769,7 +763,7 @@ func (z nat) setBit(x nat, i uint, b uint) nat { case 1: if j >= n { z = z.make(j + 1) - z[n:].clear() + clear(z[n:]) } else { z = z.make(n) } @@ -1327,9 +1321,9 @@ func (z nat) bytes(buf []byte) (i int) { // bigEndianWord returns the contents of buf interpreted as a big-endian encoded Word value. func bigEndianWord(buf []byte) Word { if _W == 64 { - return Word(binary.BigEndian.Uint64(buf)) + return Word(byteorder.BeUint64(buf)) } - return Word(binary.BigEndian.Uint32(buf)) + return Word(byteorder.BeUint32(buf)) } // setBytes interprets buf as the bytes of a big-endian unsigned diff --git a/contrib/go/_std_1.22/src/math/big/natconv.go b/contrib/go/_std_1.23/src/math/big/natconv.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/natconv.go rename to contrib/go/_std_1.23/src/math/big/natconv.go diff --git a/contrib/go/_std_1.22/src/math/big/natdiv.go b/contrib/go/_std_1.23/src/math/big/natdiv.go similarity index 99% rename from contrib/go/_std_1.22/src/math/big/natdiv.go rename to contrib/go/_std_1.23/src/math/big/natdiv.go index 14233a2ddb57..b55f9990cd59 100644 --- a/contrib/go/_std_1.22/src/math/big/natdiv.go +++ b/contrib/go/_std_1.23/src/math/big/natdiv.go @@ -392,7 +392,7 @@ Proof that q ≤ q̂: ≥ (1/y)·((x₁ - y₁ + 1)·S - x) [above: q̂·y₁ ≥ x₁ - y₁ + 1] = (1/y)·(x₁·S - y₁·S + S - x) [distribute S] = (1/y)·(S - x₀ - y₁·S) [-x = -x₁·S - x₀] - > -y₁·S / y [x₀ < S, so S - x₀ < 0; drop it] + > -y₁·S / y [x₀ < S, so S - x₀ > 0; drop it] ≥ -1 [y₁·S ≤ y] So q̂ - q > -1. @@ -734,7 +734,7 @@ func (z nat) divRecursive(u, v nat) { tmp := getNat(3 * len(v)) temps := make([]*nat, recDepth) - z.clear() + clear(z) z.divRecursiveStep(u, v, 0, tmp, temps) // Free temporaries. @@ -758,7 +758,7 @@ func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { u = u.norm() v = v.norm() if len(u) == 0 { - z.clear() + clear(z) return } @@ -816,7 +816,7 @@ func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { // Compute the 2-by-1 guess q̂, leaving r̂ in uu[s:B+n]. qhat := *temps[depth] - qhat.clear() + clear(qhat) qhat.divRecursiveStep(uu[s:B+n], v[s:], depth+1, tmp, temps) qhat = qhat.norm() @@ -833,7 +833,7 @@ func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { // But we can do the subtraction directly, as in the comment above // and in long division, because we know that q̂ is wrong by at most one. qhatv := tmp.make(3 * n) - qhatv.clear() + clear(qhatv) qhatv = qhatv.mul(qhat, v[:s]) for i := 0; i < 2; i++ { e := qhatv.cmp(uu.norm()) @@ -864,11 +864,11 @@ func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) { // Choose shift = B-1 again. s := B - 1 qhat := *temps[depth] - qhat.clear() + clear(qhat) qhat.divRecursiveStep(u[s:].norm(), v[s:], depth+1, tmp, temps) qhat = qhat.norm() qhatv := tmp.make(3 * n) - qhatv.clear() + clear(qhatv) qhatv = qhatv.mul(qhat, v[:s]) // Set the correct remainder as before. for i := 0; i < 2; i++ { diff --git a/contrib/go/_std_1.22/src/math/big/prime.go b/contrib/go/_std_1.23/src/math/big/prime.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/prime.go rename to contrib/go/_std_1.23/src/math/big/prime.go diff --git a/contrib/go/_std_1.22/src/math/big/rat.go b/contrib/go/_std_1.23/src/math/big/rat.go similarity index 99% rename from contrib/go/_std_1.22/src/math/big/rat.go rename to contrib/go/_std_1.23/src/math/big/rat.go index cb32b783a1b0..e58433ecea33 100644 --- a/contrib/go/_std_1.22/src/math/big/rat.go +++ b/contrib/go/_std_1.23/src/math/big/rat.go @@ -388,10 +388,9 @@ func (z *Rat) Inv(x *Rat) *Rat { } // Sign returns: -// -// -1 if x < 0 -// 0 if x == 0 -// +1 if x > 0 +// - -1 if x < 0; +// - 0 if x == 0; +// - +1 if x > 0. func (x *Rat) Sign() int { return x.a.Sign() } @@ -477,10 +476,9 @@ func (z *Int) scaleDenom(x *Int, f nat) { } // Cmp compares x and y and returns: -// -// -1 if x < y -// 0 if x == y -// +1 if x > y +// - -1 if x < y; +// - 0 if x == y; +// - +1 if x > y. func (x *Rat) Cmp(y *Rat) int { var a, b Int a.scaleDenom(&x.a, y.b.abs) diff --git a/contrib/go/_std_1.22/src/math/big/ratconv.go b/contrib/go/_std_1.23/src/math/big/ratconv.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/ratconv.go rename to contrib/go/_std_1.23/src/math/big/ratconv.go diff --git a/contrib/go/_std_1.22/src/math/big/ratmarsh.go b/contrib/go/_std_1.23/src/math/big/ratmarsh.go similarity index 94% rename from contrib/go/_std_1.22/src/math/big/ratmarsh.go rename to contrib/go/_std_1.23/src/math/big/ratmarsh.go index 033fb4459df8..69628294531f 100644 --- a/contrib/go/_std_1.22/src/math/big/ratmarsh.go +++ b/contrib/go/_std_1.23/src/math/big/ratmarsh.go @@ -7,9 +7,9 @@ package big import ( - "encoding/binary" "errors" "fmt" + "internal/byteorder" "math" ) @@ -29,7 +29,7 @@ func (x *Rat) GobEncode() ([]byte, error) { // this should never happen return nil, errors.New("Rat.GobEncode: numerator too large") } - binary.BigEndian.PutUint32(buf[j-4:j], uint32(n)) + byteorder.BePutUint32(buf[j-4:j], uint32(n)) j -= 1 + 4 b := ratGobVersion << 1 // make space for sign bit if x.a.neg { @@ -54,7 +54,7 @@ func (z *Rat) GobDecode(buf []byte) error { return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1) } const j = 1 + 4 - ln := binary.BigEndian.Uint32(buf[j-4 : j]) + ln := byteorder.BeUint32(buf[j-4 : j]) if uint64(ln) > math.MaxInt-j { return errors.New("Rat.GobDecode: invalid length") } diff --git a/contrib/go/_std_1.22/src/math/big/roundingmode_string.go b/contrib/go/_std_1.23/src/math/big/roundingmode_string.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/roundingmode_string.go rename to contrib/go/_std_1.23/src/math/big/roundingmode_string.go diff --git a/contrib/go/_std_1.22/src/math/big/sqrt.go b/contrib/go/_std_1.23/src/math/big/sqrt.go similarity index 100% rename from contrib/go/_std_1.22/src/math/big/sqrt.go rename to contrib/go/_std_1.23/src/math/big/sqrt.go diff --git a/contrib/go/_std_1.22/src/math/big/ya.make b/contrib/go/_std_1.23/src/math/big/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/math/big/ya.make rename to contrib/go/_std_1.23/src/math/big/ya.make diff --git a/contrib/go/_std_1.22/src/math/bits.go b/contrib/go/_std_1.23/src/math/bits.go similarity index 100% rename from contrib/go/_std_1.22/src/math/bits.go rename to contrib/go/_std_1.23/src/math/bits.go diff --git a/contrib/go/_std_1.22/src/math/bits/bits.go b/contrib/go/_std_1.23/src/math/bits/bits.go similarity index 100% rename from contrib/go/_std_1.22/src/math/bits/bits.go rename to contrib/go/_std_1.23/src/math/bits/bits.go diff --git a/contrib/go/_std_1.22/src/math/bits/bits_errors.go b/contrib/go/_std_1.23/src/math/bits/bits_errors.go similarity index 100% rename from contrib/go/_std_1.22/src/math/bits/bits_errors.go rename to contrib/go/_std_1.23/src/math/bits/bits_errors.go diff --git a/contrib/go/_std_1.22/src/math/bits/bits_errors_bootstrap.go b/contrib/go/_std_1.23/src/math/bits/bits_errors_bootstrap.go similarity index 100% rename from contrib/go/_std_1.22/src/math/bits/bits_errors_bootstrap.go rename to contrib/go/_std_1.23/src/math/bits/bits_errors_bootstrap.go diff --git a/contrib/go/_std_1.22/src/math/bits/bits_tables.go b/contrib/go/_std_1.23/src/math/bits/bits_tables.go similarity index 100% rename from contrib/go/_std_1.22/src/math/bits/bits_tables.go rename to contrib/go/_std_1.23/src/math/bits/bits_tables.go diff --git a/contrib/go/_std_1.22/src/math/bits/make_examples.go b/contrib/go/_std_1.23/src/math/bits/make_examples.go similarity index 100% rename from contrib/go/_std_1.22/src/math/bits/make_examples.go rename to contrib/go/_std_1.23/src/math/bits/make_examples.go diff --git a/contrib/go/_std_1.22/src/math/bits/make_tables.go b/contrib/go/_std_1.23/src/math/bits/make_tables.go similarity index 100% rename from contrib/go/_std_1.22/src/math/bits/make_tables.go rename to contrib/go/_std_1.23/src/math/bits/make_tables.go diff --git a/contrib/go/_std_1.22/src/math/bits/ya.make b/contrib/go/_std_1.23/src/math/bits/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/math/bits/ya.make rename to contrib/go/_std_1.23/src/math/bits/ya.make diff --git a/contrib/go/_std_1.22/src/math/cbrt.go b/contrib/go/_std_1.23/src/math/cbrt.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cbrt.go rename to contrib/go/_std_1.23/src/math/cbrt.go diff --git a/contrib/go/_std_1.22/src/math/cbrt_s390x.s b/contrib/go/_std_1.23/src/math/cbrt_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/cbrt_s390x.s rename to contrib/go/_std_1.23/src/math/cbrt_s390x.s diff --git a/contrib/go/_std_1.22/src/math/cmplx/abs.go b/contrib/go/_std_1.23/src/math/cmplx/abs.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/abs.go rename to contrib/go/_std_1.23/src/math/cmplx/abs.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/asin.go b/contrib/go/_std_1.23/src/math/cmplx/asin.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/asin.go rename to contrib/go/_std_1.23/src/math/cmplx/asin.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/conj.go b/contrib/go/_std_1.23/src/math/cmplx/conj.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/conj.go rename to contrib/go/_std_1.23/src/math/cmplx/conj.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/exp.go b/contrib/go/_std_1.23/src/math/cmplx/exp.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/exp.go rename to contrib/go/_std_1.23/src/math/cmplx/exp.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/isinf.go b/contrib/go/_std_1.23/src/math/cmplx/isinf.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/isinf.go rename to contrib/go/_std_1.23/src/math/cmplx/isinf.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/isnan.go b/contrib/go/_std_1.23/src/math/cmplx/isnan.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/isnan.go rename to contrib/go/_std_1.23/src/math/cmplx/isnan.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/log.go b/contrib/go/_std_1.23/src/math/cmplx/log.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/log.go rename to contrib/go/_std_1.23/src/math/cmplx/log.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/phase.go b/contrib/go/_std_1.23/src/math/cmplx/phase.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/phase.go rename to contrib/go/_std_1.23/src/math/cmplx/phase.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/polar.go b/contrib/go/_std_1.23/src/math/cmplx/polar.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/polar.go rename to contrib/go/_std_1.23/src/math/cmplx/polar.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/pow.go b/contrib/go/_std_1.23/src/math/cmplx/pow.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/pow.go rename to contrib/go/_std_1.23/src/math/cmplx/pow.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/rect.go b/contrib/go/_std_1.23/src/math/cmplx/rect.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/rect.go rename to contrib/go/_std_1.23/src/math/cmplx/rect.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/sin.go b/contrib/go/_std_1.23/src/math/cmplx/sin.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/sin.go rename to contrib/go/_std_1.23/src/math/cmplx/sin.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/sqrt.go b/contrib/go/_std_1.23/src/math/cmplx/sqrt.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/sqrt.go rename to contrib/go/_std_1.23/src/math/cmplx/sqrt.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/tan.go b/contrib/go/_std_1.23/src/math/cmplx/tan.go similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/tan.go rename to contrib/go/_std_1.23/src/math/cmplx/tan.go diff --git a/contrib/go/_std_1.22/src/math/cmplx/ya.make b/contrib/go/_std_1.23/src/math/cmplx/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/math/cmplx/ya.make rename to contrib/go/_std_1.23/src/math/cmplx/ya.make diff --git a/contrib/go/_std_1.22/src/math/const.go b/contrib/go/_std_1.23/src/math/const.go similarity index 100% rename from contrib/go/_std_1.22/src/math/const.go rename to contrib/go/_std_1.23/src/math/const.go diff --git a/contrib/go/_std_1.22/src/math/copysign.go b/contrib/go/_std_1.23/src/math/copysign.go similarity index 100% rename from contrib/go/_std_1.22/src/math/copysign.go rename to contrib/go/_std_1.23/src/math/copysign.go diff --git a/contrib/go/_std_1.22/src/math/cosh_s390x.s b/contrib/go/_std_1.23/src/math/cosh_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/cosh_s390x.s rename to contrib/go/_std_1.23/src/math/cosh_s390x.s diff --git a/contrib/go/_std_1.22/src/math/dim.go b/contrib/go/_std_1.23/src/math/dim.go similarity index 100% rename from contrib/go/_std_1.22/src/math/dim.go rename to contrib/go/_std_1.23/src/math/dim.go diff --git a/contrib/go/_std_1.22/src/math/dim_amd64.s b/contrib/go/_std_1.23/src/math/dim_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/dim_amd64.s rename to contrib/go/_std_1.23/src/math/dim_amd64.s diff --git a/contrib/go/_std_1.22/src/math/dim_arm64.s b/contrib/go/_std_1.23/src/math/dim_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/dim_arm64.s rename to contrib/go/_std_1.23/src/math/dim_arm64.s diff --git a/contrib/go/_std_1.22/src/math/dim_asm.go b/contrib/go/_std_1.23/src/math/dim_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/dim_asm.go rename to contrib/go/_std_1.23/src/math/dim_asm.go diff --git a/contrib/go/_std_1.22/src/math/dim_noasm.go b/contrib/go/_std_1.23/src/math/dim_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/dim_noasm.go rename to contrib/go/_std_1.23/src/math/dim_noasm.go diff --git a/contrib/go/_std_1.22/src/math/dim_riscv64.s b/contrib/go/_std_1.23/src/math/dim_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/dim_riscv64.s rename to contrib/go/_std_1.23/src/math/dim_riscv64.s diff --git a/contrib/go/_std_1.22/src/math/dim_s390x.s b/contrib/go/_std_1.23/src/math/dim_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/dim_s390x.s rename to contrib/go/_std_1.23/src/math/dim_s390x.s diff --git a/contrib/go/_std_1.22/src/math/erf.go b/contrib/go/_std_1.23/src/math/erf.go similarity index 100% rename from contrib/go/_std_1.22/src/math/erf.go rename to contrib/go/_std_1.23/src/math/erf.go diff --git a/contrib/go/_std_1.22/src/math/erf_s390x.s b/contrib/go/_std_1.23/src/math/erf_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/erf_s390x.s rename to contrib/go/_std_1.23/src/math/erf_s390x.s diff --git a/contrib/go/_std_1.22/src/math/erfc_s390x.s b/contrib/go/_std_1.23/src/math/erfc_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/erfc_s390x.s rename to contrib/go/_std_1.23/src/math/erfc_s390x.s diff --git a/contrib/go/_std_1.22/src/math/erfinv.go b/contrib/go/_std_1.23/src/math/erfinv.go similarity index 100% rename from contrib/go/_std_1.22/src/math/erfinv.go rename to contrib/go/_std_1.23/src/math/erfinv.go diff --git a/contrib/go/_std_1.22/src/math/exp.go b/contrib/go/_std_1.23/src/math/exp.go similarity index 100% rename from contrib/go/_std_1.22/src/math/exp.go rename to contrib/go/_std_1.23/src/math/exp.go diff --git a/contrib/go/_std_1.22/src/math/exp2_asm.go b/contrib/go/_std_1.23/src/math/exp2_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/exp2_asm.go rename to contrib/go/_std_1.23/src/math/exp2_asm.go diff --git a/contrib/go/_std_1.22/src/math/exp2_noasm.go b/contrib/go/_std_1.23/src/math/exp2_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/exp2_noasm.go rename to contrib/go/_std_1.23/src/math/exp2_noasm.go diff --git a/contrib/go/_std_1.22/src/math/exp_amd64.go b/contrib/go/_std_1.23/src/math/exp_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/math/exp_amd64.go rename to contrib/go/_std_1.23/src/math/exp_amd64.go diff --git a/contrib/go/_std_1.22/src/math/exp_amd64.s b/contrib/go/_std_1.23/src/math/exp_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/exp_amd64.s rename to contrib/go/_std_1.23/src/math/exp_amd64.s diff --git a/contrib/go/_std_1.22/src/math/exp_arm64.s b/contrib/go/_std_1.23/src/math/exp_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/exp_arm64.s rename to contrib/go/_std_1.23/src/math/exp_arm64.s diff --git a/contrib/go/_std_1.22/src/math/exp_asm.go b/contrib/go/_std_1.23/src/math/exp_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/exp_asm.go rename to contrib/go/_std_1.23/src/math/exp_asm.go diff --git a/contrib/go/_std_1.22/src/math/exp_noasm.go b/contrib/go/_std_1.23/src/math/exp_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/exp_noasm.go rename to contrib/go/_std_1.23/src/math/exp_noasm.go diff --git a/contrib/go/_std_1.22/src/math/exp_s390x.s b/contrib/go/_std_1.23/src/math/exp_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/exp_s390x.s rename to contrib/go/_std_1.23/src/math/exp_s390x.s diff --git a/contrib/go/_std_1.22/src/math/expm1.go b/contrib/go/_std_1.23/src/math/expm1.go similarity index 100% rename from contrib/go/_std_1.22/src/math/expm1.go rename to contrib/go/_std_1.23/src/math/expm1.go diff --git a/contrib/go/_std_1.22/src/math/expm1_s390x.s b/contrib/go/_std_1.23/src/math/expm1_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/expm1_s390x.s rename to contrib/go/_std_1.23/src/math/expm1_s390x.s diff --git a/contrib/go/_std_1.22/src/math/floor.go b/contrib/go/_std_1.23/src/math/floor.go similarity index 100% rename from contrib/go/_std_1.22/src/math/floor.go rename to contrib/go/_std_1.23/src/math/floor.go diff --git a/contrib/go/_std_1.22/src/math/floor_386.s b/contrib/go/_std_1.23/src/math/floor_386.s similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_386.s rename to contrib/go/_std_1.23/src/math/floor_386.s diff --git a/contrib/go/_std_1.22/src/math/floor_amd64.s b/contrib/go/_std_1.23/src/math/floor_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_amd64.s rename to contrib/go/_std_1.23/src/math/floor_amd64.s diff --git a/contrib/go/_std_1.22/src/math/floor_arm64.s b/contrib/go/_std_1.23/src/math/floor_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_arm64.s rename to contrib/go/_std_1.23/src/math/floor_arm64.s diff --git a/contrib/go/_std_1.22/src/math/floor_asm.go b/contrib/go/_std_1.23/src/math/floor_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_asm.go rename to contrib/go/_std_1.23/src/math/floor_asm.go diff --git a/contrib/go/_std_1.22/src/math/floor_noasm.go b/contrib/go/_std_1.23/src/math/floor_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_noasm.go rename to contrib/go/_std_1.23/src/math/floor_noasm.go diff --git a/contrib/go/_std_1.22/src/math/floor_ppc64x.s b/contrib/go/_std_1.23/src/math/floor_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_ppc64x.s rename to contrib/go/_std_1.23/src/math/floor_ppc64x.s diff --git a/contrib/go/_std_1.22/src/math/floor_s390x.s b/contrib/go/_std_1.23/src/math/floor_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_s390x.s rename to contrib/go/_std_1.23/src/math/floor_s390x.s diff --git a/contrib/go/_std_1.22/src/math/floor_wasm.s b/contrib/go/_std_1.23/src/math/floor_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/math/floor_wasm.s rename to contrib/go/_std_1.23/src/math/floor_wasm.s diff --git a/contrib/go/_std_1.22/src/math/fma.go b/contrib/go/_std_1.23/src/math/fma.go similarity index 100% rename from contrib/go/_std_1.22/src/math/fma.go rename to contrib/go/_std_1.23/src/math/fma.go diff --git a/contrib/go/_std_1.22/src/math/frexp.go b/contrib/go/_std_1.23/src/math/frexp.go similarity index 100% rename from contrib/go/_std_1.22/src/math/frexp.go rename to contrib/go/_std_1.23/src/math/frexp.go diff --git a/contrib/go/_std_1.22/src/math/gamma.go b/contrib/go/_std_1.23/src/math/gamma.go similarity index 100% rename from contrib/go/_std_1.22/src/math/gamma.go rename to contrib/go/_std_1.23/src/math/gamma.go diff --git a/contrib/go/_std_1.22/src/math/hypot.go b/contrib/go/_std_1.23/src/math/hypot.go similarity index 100% rename from contrib/go/_std_1.22/src/math/hypot.go rename to contrib/go/_std_1.23/src/math/hypot.go diff --git a/contrib/go/_std_1.22/src/math/hypot_386.s b/contrib/go/_std_1.23/src/math/hypot_386.s similarity index 100% rename from contrib/go/_std_1.22/src/math/hypot_386.s rename to contrib/go/_std_1.23/src/math/hypot_386.s diff --git a/contrib/go/_std_1.22/src/math/hypot_amd64.s b/contrib/go/_std_1.23/src/math/hypot_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/hypot_amd64.s rename to contrib/go/_std_1.23/src/math/hypot_amd64.s diff --git a/contrib/go/_std_1.22/src/math/hypot_asm.go b/contrib/go/_std_1.23/src/math/hypot_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/hypot_asm.go rename to contrib/go/_std_1.23/src/math/hypot_asm.go diff --git a/contrib/go/_std_1.22/src/math/hypot_noasm.go b/contrib/go/_std_1.23/src/math/hypot_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/hypot_noasm.go rename to contrib/go/_std_1.23/src/math/hypot_noasm.go diff --git a/contrib/go/_std_1.22/src/math/j0.go b/contrib/go/_std_1.23/src/math/j0.go similarity index 100% rename from contrib/go/_std_1.22/src/math/j0.go rename to contrib/go/_std_1.23/src/math/j0.go diff --git a/contrib/go/_std_1.22/src/math/j1.go b/contrib/go/_std_1.23/src/math/j1.go similarity index 100% rename from contrib/go/_std_1.22/src/math/j1.go rename to contrib/go/_std_1.23/src/math/j1.go diff --git a/contrib/go/_std_1.22/src/math/jn.go b/contrib/go/_std_1.23/src/math/jn.go similarity index 100% rename from contrib/go/_std_1.22/src/math/jn.go rename to contrib/go/_std_1.23/src/math/jn.go diff --git a/contrib/go/_std_1.22/src/math/ldexp.go b/contrib/go/_std_1.23/src/math/ldexp.go similarity index 100% rename from contrib/go/_std_1.22/src/math/ldexp.go rename to contrib/go/_std_1.23/src/math/ldexp.go diff --git a/contrib/go/_std_1.22/src/math/lgamma.go b/contrib/go/_std_1.23/src/math/lgamma.go similarity index 100% rename from contrib/go/_std_1.22/src/math/lgamma.go rename to contrib/go/_std_1.23/src/math/lgamma.go diff --git a/contrib/go/_std_1.22/src/math/log.go b/contrib/go/_std_1.23/src/math/log.go similarity index 100% rename from contrib/go/_std_1.22/src/math/log.go rename to contrib/go/_std_1.23/src/math/log.go diff --git a/contrib/go/_std_1.22/src/math/log10.go b/contrib/go/_std_1.23/src/math/log10.go similarity index 100% rename from contrib/go/_std_1.22/src/math/log10.go rename to contrib/go/_std_1.23/src/math/log10.go diff --git a/contrib/go/_std_1.22/src/math/log10_s390x.s b/contrib/go/_std_1.23/src/math/log10_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/log10_s390x.s rename to contrib/go/_std_1.23/src/math/log10_s390x.s diff --git a/contrib/go/_std_1.22/src/math/log1p.go b/contrib/go/_std_1.23/src/math/log1p.go similarity index 100% rename from contrib/go/_std_1.22/src/math/log1p.go rename to contrib/go/_std_1.23/src/math/log1p.go diff --git a/contrib/go/_std_1.22/src/math/log1p_s390x.s b/contrib/go/_std_1.23/src/math/log1p_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/log1p_s390x.s rename to contrib/go/_std_1.23/src/math/log1p_s390x.s diff --git a/contrib/go/_std_1.22/src/math/log_amd64.s b/contrib/go/_std_1.23/src/math/log_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/log_amd64.s rename to contrib/go/_std_1.23/src/math/log_amd64.s diff --git a/contrib/go/_std_1.22/src/math/log_asm.go b/contrib/go/_std_1.23/src/math/log_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/log_asm.go rename to contrib/go/_std_1.23/src/math/log_asm.go diff --git a/contrib/go/_std_1.22/src/math/log_s390x.s b/contrib/go/_std_1.23/src/math/log_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/log_s390x.s rename to contrib/go/_std_1.23/src/math/log_s390x.s diff --git a/contrib/go/_std_1.22/src/math/log_stub.go b/contrib/go/_std_1.23/src/math/log_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/math/log_stub.go rename to contrib/go/_std_1.23/src/math/log_stub.go diff --git a/contrib/go/_std_1.22/src/math/logb.go b/contrib/go/_std_1.23/src/math/logb.go similarity index 100% rename from contrib/go/_std_1.22/src/math/logb.go rename to contrib/go/_std_1.23/src/math/logb.go diff --git a/contrib/go/_std_1.22/src/math/mod.go b/contrib/go/_std_1.23/src/math/mod.go similarity index 100% rename from contrib/go/_std_1.22/src/math/mod.go rename to contrib/go/_std_1.23/src/math/mod.go diff --git a/contrib/go/_std_1.22/src/math/modf.go b/contrib/go/_std_1.23/src/math/modf.go similarity index 100% rename from contrib/go/_std_1.22/src/math/modf.go rename to contrib/go/_std_1.23/src/math/modf.go diff --git a/contrib/go/_std_1.22/src/math/modf_arm64.s b/contrib/go/_std_1.23/src/math/modf_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/math/modf_arm64.s rename to contrib/go/_std_1.23/src/math/modf_arm64.s diff --git a/contrib/go/_std_1.22/src/math/modf_asm.go b/contrib/go/_std_1.23/src/math/modf_asm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/modf_asm.go rename to contrib/go/_std_1.23/src/math/modf_asm.go diff --git a/contrib/go/_std_1.22/src/math/modf_noasm.go b/contrib/go/_std_1.23/src/math/modf_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/math/modf_noasm.go rename to contrib/go/_std_1.23/src/math/modf_noasm.go diff --git a/contrib/go/_std_1.22/src/math/modf_ppc64x.s b/contrib/go/_std_1.23/src/math/modf_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/modf_ppc64x.s rename to contrib/go/_std_1.23/src/math/modf_ppc64x.s diff --git a/contrib/go/_std_1.22/src/math/nextafter.go b/contrib/go/_std_1.23/src/math/nextafter.go similarity index 100% rename from contrib/go/_std_1.22/src/math/nextafter.go rename to contrib/go/_std_1.23/src/math/nextafter.go diff --git a/contrib/go/_std_1.22/src/math/pow.go b/contrib/go/_std_1.23/src/math/pow.go similarity index 100% rename from contrib/go/_std_1.22/src/math/pow.go rename to contrib/go/_std_1.23/src/math/pow.go diff --git a/contrib/go/_std_1.22/src/math/pow10.go b/contrib/go/_std_1.23/src/math/pow10.go similarity index 100% rename from contrib/go/_std_1.22/src/math/pow10.go rename to contrib/go/_std_1.23/src/math/pow10.go diff --git a/contrib/go/_std_1.22/src/math/pow_s390x.s b/contrib/go/_std_1.23/src/math/pow_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/pow_s390x.s rename to contrib/go/_std_1.23/src/math/pow_s390x.s diff --git a/contrib/go/_std_1.22/src/math/rand/exp.go b/contrib/go/_std_1.23/src/math/rand/exp.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/exp.go rename to contrib/go/_std_1.23/src/math/rand/exp.go diff --git a/contrib/go/_std_1.22/src/math/rand/gen_cooked.go b/contrib/go/_std_1.23/src/math/rand/gen_cooked.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/gen_cooked.go rename to contrib/go/_std_1.23/src/math/rand/gen_cooked.go diff --git a/contrib/go/_std_1.22/src/math/rand/normal.go b/contrib/go/_std_1.23/src/math/rand/normal.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/normal.go rename to contrib/go/_std_1.23/src/math/rand/normal.go diff --git a/contrib/go/_std_1.22/src/math/rand/rand.go b/contrib/go/_std_1.23/src/math/rand/rand.go similarity index 99% rename from contrib/go/_std_1.22/src/math/rand/rand.go rename to contrib/go/_std_1.23/src/math/rand/rand.go index a8ed9c0cb7cf..61ff5c1b387a 100644 --- a/contrib/go/_std_1.22/src/math/rand/rand.go +++ b/contrib/go/_std_1.23/src/math/rand/rand.go @@ -474,6 +474,7 @@ func Shuffle(n int, swap func(i, j int)) { globalRand().Shuffle(n, swap) } // Read, unlike the [Rand.Read] method, is safe for concurrent use. // // Deprecated: For almost all use cases, [crypto/rand.Read] is more appropriate. +// If a deterministic source is required, use [math/rand/v2.ChaCha8.Read]. func Read(p []byte) (n int, err error) { return globalRand().Read(p) } // NormFloat64 returns a normally distributed float64 in the range diff --git a/contrib/go/_std_1.22/src/math/rand/rng.go b/contrib/go/_std_1.23/src/math/rand/rng.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/rng.go rename to contrib/go/_std_1.23/src/math/rand/rng.go diff --git a/contrib/go/_std_1.23/src/math/rand/v2/chacha8.go b/contrib/go/_std_1.23/src/math/rand/v2/chacha8.go new file mode 100644 index 000000000000..f9eaacf6017f --- /dev/null +++ b/contrib/go/_std_1.23/src/math/rand/v2/chacha8.go @@ -0,0 +1,110 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rand + +import ( + "errors" + "internal/byteorder" + "internal/chacha8rand" +) + +// A ChaCha8 is a ChaCha8-based cryptographically strong +// random number generator. +type ChaCha8 struct { + state chacha8rand.State + + // The last readLen bytes of readBuf are still to be consumed by Read. + readBuf [8]byte + readLen int // 0 <= readLen <= 8 +} + +// NewChaCha8 returns a new ChaCha8 seeded with the given seed. +func NewChaCha8(seed [32]byte) *ChaCha8 { + c := new(ChaCha8) + c.state.Init(seed) + return c +} + +// Seed resets the ChaCha8 to behave the same way as NewChaCha8(seed). +func (c *ChaCha8) Seed(seed [32]byte) { + c.state.Init(seed) + c.readLen = 0 + c.readBuf = [8]byte{} +} + +// Uint64 returns a uniformly distributed random uint64 value. +func (c *ChaCha8) Uint64() uint64 { + for { + x, ok := c.state.Next() + if ok { + return x + } + c.state.Refill() + } +} + +// Read reads exactly len(p) bytes into p. +// It always returns len(p) and a nil error. +// +// If calls to Read and Uint64 are interleaved, the order in which bits are +// returned by the two is undefined, and Read may return bits generated before +// the last call to Uint64. +func (c *ChaCha8) Read(p []byte) (n int, err error) { + if c.readLen > 0 { + n = copy(p, c.readBuf[len(c.readBuf)-c.readLen:]) + c.readLen -= n + p = p[n:] + } + for len(p) >= 8 { + byteorder.LePutUint64(p, c.Uint64()) + p = p[8:] + n += 8 + } + if len(p) > 0 { + byteorder.LePutUint64(c.readBuf[:], c.Uint64()) + n += copy(p, c.readBuf[:]) + c.readLen = 8 - len(p) + } + return +} + +// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface. +func (c *ChaCha8) UnmarshalBinary(data []byte) error { + data, ok := cutPrefix(data, []byte("readbuf:")) + if ok { + var buf []byte + buf, data, ok = readUint8LengthPrefixed(data) + if !ok { + return errors.New("invalid ChaCha8 Read buffer encoding") + } + c.readLen = copy(c.readBuf[len(c.readBuf)-len(buf):], buf) + } + return chacha8rand.Unmarshal(&c.state, data) +} + +func cutPrefix(s, prefix []byte) (after []byte, found bool) { + if len(s) < len(prefix) || string(s[:len(prefix)]) != string(prefix) { + return s, false + } + return s[len(prefix):], true +} + +func readUint8LengthPrefixed(b []byte) (buf, rest []byte, ok bool) { + if len(b) == 0 || len(b) < int(1+b[0]) { + return nil, nil, false + } + return b[1 : 1+b[0]], b[1+b[0]:], true +} + +// MarshalBinary implements the encoding.BinaryMarshaler interface. +func (c *ChaCha8) MarshalBinary() ([]byte, error) { + if c.readLen > 0 { + out := []byte("readbuf:") + out = append(out, uint8(c.readLen)) + out = append(out, c.readBuf[len(c.readBuf)-c.readLen:]...) + return append(out, chacha8rand.Marshal(&c.state)...), nil + } + return chacha8rand.Marshal(&c.state), nil +} diff --git a/contrib/go/_std_1.22/src/math/rand/v2/exp.go b/contrib/go/_std_1.23/src/math/rand/v2/exp.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/v2/exp.go rename to contrib/go/_std_1.23/src/math/rand/v2/exp.go diff --git a/contrib/go/_std_1.22/src/math/rand/v2/normal.go b/contrib/go/_std_1.23/src/math/rand/v2/normal.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/v2/normal.go rename to contrib/go/_std_1.23/src/math/rand/v2/normal.go diff --git a/contrib/go/_std_1.22/src/math/rand/v2/pcg.go b/contrib/go/_std_1.23/src/math/rand/v2/pcg.go similarity index 78% rename from contrib/go/_std_1.22/src/math/rand/v2/pcg.go rename to contrib/go/_std_1.23/src/math/rand/v2/pcg.go index 77708d799e26..4ccd5e320b97 100644 --- a/contrib/go/_std_1.22/src/math/rand/v2/pcg.go +++ b/contrib/go/_std_1.23/src/math/rand/v2/pcg.go @@ -6,6 +6,7 @@ package rand import ( "errors" + "internal/byteorder" "math/bits" ) @@ -30,32 +31,12 @@ func (p *PCG) Seed(seed1, seed2 uint64) { p.lo = seed2 } -// binary.bigEndian.Uint64, copied to avoid dependency -func beUint64(b []byte) uint64 { - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 -} - -// binary.bigEndian.PutUint64, copied to avoid dependency -func bePutUint64(b []byte, v uint64) { - _ = b[7] // early bounds check to guarantee safety of writes below - b[0] = byte(v >> 56) - b[1] = byte(v >> 48) - b[2] = byte(v >> 40) - b[3] = byte(v >> 32) - b[4] = byte(v >> 24) - b[5] = byte(v >> 16) - b[6] = byte(v >> 8) - b[7] = byte(v) -} - // MarshalBinary implements the encoding.BinaryMarshaler interface. func (p *PCG) MarshalBinary() ([]byte, error) { b := make([]byte, 20) copy(b, "pcg:") - bePutUint64(b[4:], p.hi) - bePutUint64(b[4+8:], p.lo) + byteorder.BePutUint64(b[4:], p.hi) + byteorder.BePutUint64(b[4+8:], p.lo) return b, nil } @@ -66,8 +47,8 @@ func (p *PCG) UnmarshalBinary(data []byte) error { if len(data) != 20 || string(data[:4]) != "pcg:" { return errUnmarshalPCG } - p.hi = beUint64(data[4:]) - p.lo = beUint64(data[4+8:]) + p.hi = byteorder.BeUint64(data[4:]) + p.lo = byteorder.BeUint64(data[4+8:]) return nil } diff --git a/contrib/go/_std_1.22/src/math/rand/v2/rand.go b/contrib/go/_std_1.23/src/math/rand/v2/rand.go similarity index 97% rename from contrib/go/_std_1.22/src/math/rand/v2/rand.go rename to contrib/go/_std_1.23/src/math/rand/v2/rand.go index f490408472ba..fea1e3a2ba20 100644 --- a/contrib/go/_std_1.22/src/math/rand/v2/rand.go +++ b/contrib/go/_std_1.23/src/math/rand/v2/rand.go @@ -14,7 +14,7 @@ // // This package's outputs might be easily predictable regardless of how it's // seeded. For random numbers suitable for security-sensitive work, see the -// crypto/rand package. +// [crypto/rand] package. package rand import ( @@ -56,6 +56,9 @@ func (r *Rand) Int32() int32 { return int32(r.src.Uint64() >> 33) } // Int returns a non-negative pseudo-random int. func (r *Rand) Int() int { return int(uint(r.src.Uint64()) << 1 >> 1) } +// Uint returns a pseudo-random uint. +func (r *Rand) Uint() uint { return uint(r.src.Uint64()) } + // Int64N returns, as an int64, a non-negative pseudo-random number in the half-open interval [0,n). // It panics if n <= 0. func (r *Rand) Int64N(n int64) int64 { @@ -250,7 +253,7 @@ func (r *Rand) Shuffle(n int, swap func(i, j int)) { // globalRand is the source of random numbers for the top-level // convenience functions. -var globalRand = &Rand{src: &runtimeSource{}} +var globalRand = &Rand{src: runtimeSource{}} //go:linkname runtime_rand runtime.rand func runtime_rand() uint64 @@ -258,7 +261,7 @@ func runtime_rand() uint64 // runtimeSource is a Source that uses the runtime fastrand functions. type runtimeSource struct{} -func (*runtimeSource) Uint64() uint64 { +func (runtimeSource) Uint64() uint64 { return runtime_rand() } @@ -291,6 +294,9 @@ func Int32() int32 { return globalRand.Int32() } // Int returns a non-negative pseudo-random int from the default Source. func Int() int { return globalRand.Int() } +// Uint returns a pseudo-random uint from the default Source. +func Uint() uint { return globalRand.Uint() } + // Int64N returns, as an int64, a pseudo-random number in the half-open interval [0,n) // from the default Source. // It panics if n <= 0. diff --git a/contrib/go/_std_1.22/src/math/rand/v2/ya.make b/contrib/go/_std_1.23/src/math/rand/v2/ya.make similarity index 86% rename from contrib/go/_std_1.22/src/math/rand/v2/ya.make rename to contrib/go/_std_1.23/src/math/rand/v2/ya.make index 709d17ea4d94..125d7ceabd69 100644 --- a/contrib/go/_std_1.22/src/math/rand/v2/ya.make +++ b/contrib/go/_std_1.23/src/math/rand/v2/ya.make @@ -1,5 +1,3 @@ -SUBSCRIBER(g:contrib) - GO_LIBRARY() IF (TRUE) SRCS( diff --git a/contrib/go/_std_1.22/src/math/rand/v2/zipf.go b/contrib/go/_std_1.23/src/math/rand/v2/zipf.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/v2/zipf.go rename to contrib/go/_std_1.23/src/math/rand/v2/zipf.go diff --git a/contrib/go/_std_1.22/src/math/rand/ya.make b/contrib/go/_std_1.23/src/math/rand/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/ya.make rename to contrib/go/_std_1.23/src/math/rand/ya.make diff --git a/contrib/go/_std_1.22/src/math/rand/zipf.go b/contrib/go/_std_1.23/src/math/rand/zipf.go similarity index 100% rename from contrib/go/_std_1.22/src/math/rand/zipf.go rename to contrib/go/_std_1.23/src/math/rand/zipf.go diff --git a/contrib/go/_std_1.22/src/math/remainder.go b/contrib/go/_std_1.23/src/math/remainder.go similarity index 100% rename from contrib/go/_std_1.22/src/math/remainder.go rename to contrib/go/_std_1.23/src/math/remainder.go diff --git a/contrib/go/_std_1.22/src/math/signbit.go b/contrib/go/_std_1.23/src/math/signbit.go similarity index 100% rename from contrib/go/_std_1.22/src/math/signbit.go rename to contrib/go/_std_1.23/src/math/signbit.go diff --git a/contrib/go/_std_1.22/src/math/sin.go b/contrib/go/_std_1.23/src/math/sin.go similarity index 100% rename from contrib/go/_std_1.22/src/math/sin.go rename to contrib/go/_std_1.23/src/math/sin.go diff --git a/contrib/go/_std_1.22/src/math/sin_s390x.s b/contrib/go/_std_1.23/src/math/sin_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/sin_s390x.s rename to contrib/go/_std_1.23/src/math/sin_s390x.s diff --git a/contrib/go/_std_1.22/src/math/sincos.go b/contrib/go/_std_1.23/src/math/sincos.go similarity index 100% rename from contrib/go/_std_1.22/src/math/sincos.go rename to contrib/go/_std_1.23/src/math/sincos.go diff --git a/contrib/go/_std_1.22/src/math/sinh.go b/contrib/go/_std_1.23/src/math/sinh.go similarity index 100% rename from contrib/go/_std_1.22/src/math/sinh.go rename to contrib/go/_std_1.23/src/math/sinh.go diff --git a/contrib/go/_std_1.22/src/math/sinh_s390x.s b/contrib/go/_std_1.23/src/math/sinh_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/sinh_s390x.s rename to contrib/go/_std_1.23/src/math/sinh_s390x.s diff --git a/contrib/go/_std_1.22/src/math/sqrt.go b/contrib/go/_std_1.23/src/math/sqrt.go similarity index 100% rename from contrib/go/_std_1.22/src/math/sqrt.go rename to contrib/go/_std_1.23/src/math/sqrt.go diff --git a/contrib/go/_std_1.22/src/math/stubs.go b/contrib/go/_std_1.23/src/math/stubs.go similarity index 100% rename from contrib/go/_std_1.22/src/math/stubs.go rename to contrib/go/_std_1.23/src/math/stubs.go diff --git a/contrib/go/_std_1.22/src/math/stubs_s390x.s b/contrib/go/_std_1.23/src/math/stubs_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/stubs_s390x.s rename to contrib/go/_std_1.23/src/math/stubs_s390x.s diff --git a/contrib/go/_std_1.22/src/math/tan.go b/contrib/go/_std_1.23/src/math/tan.go similarity index 100% rename from contrib/go/_std_1.22/src/math/tan.go rename to contrib/go/_std_1.23/src/math/tan.go diff --git a/contrib/go/_std_1.22/src/math/tan_s390x.s b/contrib/go/_std_1.23/src/math/tan_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/tan_s390x.s rename to contrib/go/_std_1.23/src/math/tan_s390x.s diff --git a/contrib/go/_std_1.22/src/math/tanh.go b/contrib/go/_std_1.23/src/math/tanh.go similarity index 100% rename from contrib/go/_std_1.22/src/math/tanh.go rename to contrib/go/_std_1.23/src/math/tanh.go diff --git a/contrib/go/_std_1.22/src/math/tanh_s390x.s b/contrib/go/_std_1.23/src/math/tanh_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/math/tanh_s390x.s rename to contrib/go/_std_1.23/src/math/tanh_s390x.s diff --git a/contrib/go/_std_1.22/src/math/trig_reduce.go b/contrib/go/_std_1.23/src/math/trig_reduce.go similarity index 100% rename from contrib/go/_std_1.22/src/math/trig_reduce.go rename to contrib/go/_std_1.23/src/math/trig_reduce.go diff --git a/contrib/go/_std_1.22/src/math/unsafe.go b/contrib/go/_std_1.23/src/math/unsafe.go similarity index 79% rename from contrib/go/_std_1.22/src/math/unsafe.go rename to contrib/go/_std_1.23/src/math/unsafe.go index e59f50ca62e5..e251f62a2a13 100644 --- a/contrib/go/_std_1.22/src/math/unsafe.go +++ b/contrib/go/_std_1.23/src/math/unsafe.go @@ -6,6 +6,18 @@ package math import "unsafe" +// Despite being an exported symbol, +// Float32bits is linknamed by widely used packages. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/num +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +// Note that this comment is not part of the doc comment. +// +//go:linkname Float32bits + // Float32bits returns the IEEE 754 binary representation of f, // with the sign bit of f and the result in the same bit position. // Float32bits(Float32frombits(x)) == x. diff --git a/contrib/go/_std_1.22/src/math/ya.make b/contrib/go/_std_1.23/src/math/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/math/ya.make rename to contrib/go/_std_1.23/src/math/ya.make diff --git a/contrib/go/_std_1.22/src/mime/encodedword.go b/contrib/go/_std_1.23/src/mime/encodedword.go similarity index 99% rename from contrib/go/_std_1.22/src/mime/encodedword.go rename to contrib/go/_std_1.23/src/mime/encodedword.go index e6b470b1fb0e..856433f8f3b3 100644 --- a/contrib/go/_std_1.22/src/mime/encodedword.go +++ b/contrib/go/_std_1.23/src/mime/encodedword.go @@ -226,7 +226,7 @@ func (d *WordDecoder) Decode(word string) (string, error) { } // DecodeHeader decodes all encoded-words of the given string. It returns an -// error if and only if CharsetReader of d returns an error. +// error if and only if WordDecoder.CharsetReader of d returns an error. func (d *WordDecoder) DecodeHeader(header string) (string, error) { // If there is no encoded-word, returns before creating a buffer. i := strings.Index(header, "=?") diff --git a/contrib/go/_std_1.22/src/mime/grammar.go b/contrib/go/_std_1.23/src/mime/grammar.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/grammar.go rename to contrib/go/_std_1.23/src/mime/grammar.go diff --git a/contrib/go/_std_1.22/src/mime/mediatype.go b/contrib/go/_std_1.23/src/mime/mediatype.go similarity index 98% rename from contrib/go/_std_1.22/src/mime/mediatype.go rename to contrib/go/_std_1.23/src/mime/mediatype.go index bc8d417e6289..97f3563a2d01 100644 --- a/contrib/go/_std_1.22/src/mime/mediatype.go +++ b/contrib/go/_std_1.23/src/mime/mediatype.go @@ -7,7 +7,7 @@ package mime import ( "errors" "fmt" - "sort" + "slices" "strings" "unicode" ) @@ -37,7 +37,7 @@ func FormatMediaType(t string, param map[string]string) string { for a := range param { attrs = append(attrs, a) } - sort.Strings(attrs) + slices.Sort(attrs) for _, attribute := range attrs { value := param[attribute] @@ -121,7 +121,7 @@ func checkMediaTypeDisposition(s string) error { return nil } -// ErrInvalidMediaParameter is returned by ParseMediaType if +// ErrInvalidMediaParameter is returned by [ParseMediaType] if // the media type value was found but there was an error parsing // the optional parameters var ErrInvalidMediaParameter = errors.New("mime: invalid media parameter") @@ -133,7 +133,7 @@ var ErrInvalidMediaParameter = errors.New("mime: invalid media parameter") // to lowercase and trimmed of white space and a non-nil map. // If there is an error parsing the optional parameter, // the media type will be returned along with the error -// ErrInvalidMediaParameter. +// [ErrInvalidMediaParameter]. // The returned map, params, maps from the lowercase // attribute to the attribute value with its case preserved. func ParseMediaType(v string) (mediatype string, params map[string]string, err error) { diff --git a/contrib/go/_std_1.22/src/mime/multipart/formdata.go b/contrib/go/_std_1.23/src/mime/multipart/formdata.go similarity index 92% rename from contrib/go/_std_1.22/src/mime/multipart/formdata.go rename to contrib/go/_std_1.23/src/mime/multipart/formdata.go index 85bad2a4cb63..d0e0151a6fbe 100644 --- a/contrib/go/_std_1.22/src/mime/multipart/formdata.go +++ b/contrib/go/_std_1.23/src/mime/multipart/formdata.go @@ -27,15 +27,15 @@ var ErrMessageTooLarge = errors.New("multipart: message too large") // It stores up to maxMemory bytes + 10MB (reserved for non-file parts) // in memory. File parts which can't be stored in memory will be stored on // disk in temporary files. -// It returns ErrMessageTooLarge if all non-file parts can't be stored in +// It returns [ErrMessageTooLarge] if all non-file parts can't be stored in // memory. func (r *Reader) ReadForm(maxMemory int64) (*Form, error) { return r.readForm(maxMemory) } var ( - multipartFiles = godebug.New("#multipartfiles") // TODO: document and remove # - multipartMaxParts = godebug.New("multipartmaxparts") + multipartfiles = godebug.New("#multipartfiles") // TODO: document and remove # + multipartmaxparts = godebug.New("multipartmaxparts") ) func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { @@ -46,15 +46,15 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) { ) numDiskFiles := 0 combineFiles := true - if multipartFiles.Value() == "distinct" { + if multipartfiles.Value() == "distinct" { combineFiles = false - // multipartFiles.IncNonDefault() // TODO: uncomment after documenting + // multipartfiles.IncNonDefault() // TODO: uncomment after documenting } maxParts := 1000 - if s := multipartMaxParts.Value(); s != "" { + if s := multipartmaxparts.Value(); s != "" { if v, err := strconv.Atoi(s); err == nil && v >= 0 { maxParts = v - multipartMaxParts.IncNonDefault() + multipartmaxparts.IncNonDefault() } } maxHeaders := maxMIMEHeaders() @@ -228,7 +228,7 @@ func mimeHeaderSize(h textproto.MIMEHeader) (size int64) { // Form is a parsed multipart form. // Its File parts are stored either in memory or on disk, -// and are accessible via the *FileHeader's Open method. +// and are accessible via the [*FileHeader]'s Open method. // Its Value parts are stored as strings. // Both are keyed by field name. type Form struct { @@ -236,7 +236,7 @@ type Form struct { File map[string][]*FileHeader } -// RemoveAll removes any temporary files associated with a Form. +// RemoveAll removes any temporary files associated with a [Form]. func (f *Form) RemoveAll() error { var err error for _, fhs := range f.File { @@ -264,7 +264,7 @@ type FileHeader struct { tmpshared bool } -// Open opens and returns the FileHeader's associated File. +// Open opens and returns the [FileHeader]'s associated File. func (fh *FileHeader) Open() (File, error) { if b := fh.content; b != nil { r := io.NewSectionReader(bytes.NewReader(b), 0, int64(len(b))) diff --git a/contrib/go/_std_1.22/src/mime/multipart/multipart.go b/contrib/go/_std_1.23/src/mime/multipart/multipart.go similarity index 94% rename from contrib/go/_std_1.22/src/mime/multipart/multipart.go rename to contrib/go/_std_1.23/src/mime/multipart/multipart.go index da1f45810e88..17088bc30e1b 100644 --- a/contrib/go/_std_1.22/src/mime/multipart/multipart.go +++ b/contrib/go/_std_1.23/src/mime/multipart/multipart.go @@ -15,8 +15,8 @@ bodies generated by popular browsers. To protect against malicious inputs, this package sets limits on the size of the MIME data it processes. -Reader.NextPart and Reader.NextRawPart limit the number of headers in a -part to 10000 and Reader.ReadForm limits the total number of headers in all +[Reader.NextPart] and [Reader.NextRawPart] limit the number of headers in a +part to 10000 and [Reader.ReadForm] limits the total number of headers in all FileHeaders to 10000. These limits may be adjusted with the GODEBUG=multipartmaxheaders= setting. @@ -85,7 +85,7 @@ func (p *Part) FormName() string { return p.dispositionParams["name"] } -// FileName returns the filename parameter of the Part's Content-Disposition +// FileName returns the filename parameter of the [Part]'s Content-Disposition // header. If not empty, the filename is passed through filepath.Base (which is // platform dependent) before being returned. func (p *Part) FileName() string { @@ -110,11 +110,11 @@ func (p *Part) parseContentDisposition() { } } -// NewReader creates a new multipart Reader reading from r using the +// NewReader creates a new multipart [Reader] reading from r using the // given MIME boundary. // // The boundary is usually obtained from the "boundary" parameter of -// the message's "Content-Type" header. Use mime.ParseMediaType to +// the message's "Content-Type" header. Use [mime.ParseMediaType] to // parse such headers. func NewReader(r io.Reader, boundary string) *Reader { b := []byte("\r\n--" + boundary + "--") @@ -347,15 +347,15 @@ type Reader struct { // including header keys, values, and map overhead. const maxMIMEHeaderSize = 10 << 20 -// multipartMaxHeaders is the maximum number of header entries NextPart will return, +// multipartmaxheaders is the maximum number of header entries NextPart will return, // as well as the maximum combined total of header entries Reader.ReadForm will return // in FileHeaders. -var multipartMaxHeaders = godebug.New("multipartmaxheaders") +var multipartmaxheaders = godebug.New("multipartmaxheaders") func maxMIMEHeaders() int64 { - if s := multipartMaxHeaders.Value(); s != "" { + if s := multipartmaxheaders.Value(); s != "" { if v, err := strconv.ParseInt(s, 10, 64); err == nil && v >= 0 { - multipartMaxHeaders.IncNonDefault() + multipartmaxheaders.IncNonDefault() return v } } @@ -363,7 +363,7 @@ func maxMIMEHeaders() int64 { } // NextPart returns the next part in the multipart or an error. -// When there are no more parts, the error io.EOF is returned. +// When there are no more parts, the error [io.EOF] is returned. // // As a special case, if the "Content-Transfer-Encoding" header // has a value of "quoted-printable", that header is instead @@ -373,9 +373,9 @@ func (r *Reader) NextPart() (*Part, error) { } // NextRawPart returns the next part in the multipart or an error. -// When there are no more parts, the error io.EOF is returned. +// When there are no more parts, the error [io.EOF] is returned. // -// Unlike NextPart, it does not have special handling for +// Unlike [Reader.NextPart], it does not have special handling for // "Content-Transfer-Encoding: quoted-printable". func (r *Reader) NextRawPart() (*Part, error) { return r.nextPart(true, maxMIMEHeaderSize, maxMIMEHeaders()) diff --git a/contrib/go/_std_1.22/src/mime/multipart/readmimeheader.go b/contrib/go/_std_1.23/src/mime/multipart/readmimeheader.go similarity index 87% rename from contrib/go/_std_1.22/src/mime/multipart/readmimeheader.go rename to contrib/go/_std_1.23/src/mime/multipart/readmimeheader.go index 25aa6e209286..c6825069b0b5 100644 --- a/contrib/go/_std_1.22/src/mime/multipart/readmimeheader.go +++ b/contrib/go/_std_1.23/src/mime/multipart/readmimeheader.go @@ -1,6 +1,7 @@ // Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. + package multipart import ( @@ -8,7 +9,7 @@ import ( _ "unsafe" // for go:linkname ) -// readMIMEHeader is defined in package net/textproto. +// readMIMEHeader is defined in package [net/textproto]. // //go:linkname readMIMEHeader net/textproto.readMIMEHeader func readMIMEHeader(r *textproto.Reader, maxMemory, maxHeaders int64) (textproto.MIMEHeader, error) diff --git a/contrib/go/_std_1.22/src/mime/multipart/writer.go b/contrib/go/_std_1.23/src/mime/multipart/writer.go similarity index 88% rename from contrib/go/_std_1.22/src/mime/multipart/writer.go rename to contrib/go/_std_1.23/src/mime/multipart/writer.go index d1ff151a7d1d..5e589c499b33 100644 --- a/contrib/go/_std_1.22/src/mime/multipart/writer.go +++ b/contrib/go/_std_1.23/src/mime/multipart/writer.go @@ -11,7 +11,7 @@ import ( "fmt" "io" "net/textproto" - "sort" + "slices" "strings" ) @@ -22,7 +22,7 @@ type Writer struct { lastpart *part } -// NewWriter returns a new multipart Writer with a random boundary, +// NewWriter returns a new multipart [Writer] with a random boundary, // writing to w. func NewWriter(w io.Writer) *Writer { return &Writer{ @@ -31,12 +31,12 @@ func NewWriter(w io.Writer) *Writer { } } -// Boundary returns the Writer's boundary. +// Boundary returns the [Writer]'s boundary. func (w *Writer) Boundary() string { return w.boundary } -// SetBoundary overrides the Writer's default randomly-generated +// SetBoundary overrides the [Writer]'s default randomly-generated // boundary separator with an explicit value. // // SetBoundary must be called before any parts are created, may only @@ -70,7 +70,7 @@ func (w *Writer) SetBoundary(boundary string) error { } // FormDataContentType returns the Content-Type for an HTTP -// multipart/form-data with this Writer's Boundary. +// multipart/form-data with this [Writer]'s Boundary. func (w *Writer) FormDataContentType() string { b := w.boundary // We must quote the boundary if it contains any of the @@ -92,7 +92,7 @@ func randomBoundary() string { // CreatePart creates a new multipart section with the provided // header. The body of the part should be written to the returned -// Writer. After calling CreatePart, any previous part may no longer +// [Writer]. After calling CreatePart, any previous part may no longer // be written to. func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, error) { if w.lastpart != nil { @@ -111,7 +111,7 @@ func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, error) { for k := range header { keys = append(keys, k) } - sort.Strings(keys) + slices.Sort(keys) for _, k := range keys { for _, v := range header[k] { fmt.Fprintf(&b, "%s: %s\r\n", k, v) @@ -135,7 +135,7 @@ func escapeQuotes(s string) string { return quoteEscaper.Replace(s) } -// CreateFormFile is a convenience wrapper around CreatePart. It creates +// CreateFormFile is a convenience wrapper around [Writer.CreatePart]. It creates // a new form-data header with the provided field name and file name. func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, error) { h := make(textproto.MIMEHeader) @@ -146,7 +146,7 @@ func (w *Writer) CreateFormFile(fieldname, filename string) (io.Writer, error) { return w.CreatePart(h) } -// CreateFormField calls CreatePart with a header using the +// CreateFormField calls [Writer.CreatePart] with a header using the // given field name. func (w *Writer) CreateFormField(fieldname string) (io.Writer, error) { h := make(textproto.MIMEHeader) @@ -155,7 +155,7 @@ func (w *Writer) CreateFormField(fieldname string) (io.Writer, error) { return w.CreatePart(h) } -// WriteField calls CreateFormField and then writes the given value. +// WriteField calls [Writer.CreateFormField] and then writes the given value. func (w *Writer) WriteField(fieldname, value string) error { p, err := w.CreateFormField(fieldname) if err != nil { diff --git a/contrib/go/_std_1.22/src/mime/multipart/ya.make b/contrib/go/_std_1.23/src/mime/multipart/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/mime/multipart/ya.make rename to contrib/go/_std_1.23/src/mime/multipart/ya.make diff --git a/contrib/go/_std_1.22/src/mime/quotedprintable/reader.go b/contrib/go/_std_1.23/src/mime/quotedprintable/reader.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/quotedprintable/reader.go rename to contrib/go/_std_1.23/src/mime/quotedprintable/reader.go diff --git a/contrib/go/_std_1.22/src/mime/quotedprintable/writer.go b/contrib/go/_std_1.23/src/mime/quotedprintable/writer.go similarity index 87% rename from contrib/go/_std_1.22/src/mime/quotedprintable/writer.go rename to contrib/go/_std_1.23/src/mime/quotedprintable/writer.go index 16ea0bf7d622..69b5a1123263 100644 --- a/contrib/go/_std_1.22/src/mime/quotedprintable/writer.go +++ b/contrib/go/_std_1.23/src/mime/quotedprintable/writer.go @@ -8,7 +8,7 @@ import "io" const lineMaxLen = 76 -// A Writer is a quoted-printable writer that implements io.WriteCloser. +// A Writer is a quoted-printable writer that implements [io.WriteCloser]. type Writer struct { // Binary mode treats the writer's input as pure binary and processes end of // line bytes as binary data. @@ -20,14 +20,14 @@ type Writer struct { cr bool } -// NewWriter returns a new Writer that writes to w. +// NewWriter returns a new [Writer] that writes to w. func NewWriter(w io.Writer) *Writer { return &Writer{w: w} } // Write encodes p using quoted-printable encoding and writes it to the -// underlying io.Writer. It limits line length to 76 characters. The encoded -// bytes are not necessarily flushed until the Writer is closed. +// underlying [io.Writer]. It limits line length to 76 characters. The encoded +// bytes are not necessarily flushed until the [Writer] is closed. func (w *Writer) Write(p []byte) (n int, err error) { for i, b := range p { switch { @@ -62,8 +62,8 @@ func (w *Writer) Write(p []byte) (n int, err error) { return len(p), nil } -// Close closes the Writer, flushing any unwritten data to the underlying -// io.Writer, but does not close the underlying io.Writer. +// Close closes the [Writer], flushing any unwritten data to the underlying +// [io.Writer], but does not close the underlying io.Writer. func (w *Writer) Close() error { if err := w.checkLastByte(); err != nil { return err diff --git a/contrib/go/_std_1.22/src/mime/quotedprintable/ya.make b/contrib/go/_std_1.23/src/mime/quotedprintable/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/mime/quotedprintable/ya.make rename to contrib/go/_std_1.23/src/mime/quotedprintable/ya.make diff --git a/contrib/go/_std_1.22/src/mime/type.go b/contrib/go/_std_1.23/src/mime/type.go similarity index 96% rename from contrib/go/_std_1.22/src/mime/type.go rename to contrib/go/_std_1.23/src/mime/type.go index 465ecf0d599c..c86ebd3442c1 100644 --- a/contrib/go/_std_1.22/src/mime/type.go +++ b/contrib/go/_std_1.23/src/mime/type.go @@ -7,7 +7,7 @@ package mime import ( "fmt" - "sort" + "slices" "strings" "sync" ) @@ -22,18 +22,11 @@ var ( extensions sync.Map // map[string][]string; slice values are append-only. ) -func clearSyncMap(m *sync.Map) { - m.Range(func(k, _ any) bool { - m.Delete(k) - return true - }) -} - // setMimeTypes is used by initMime's non-test path, and by tests. func setMimeTypes(lowerExt, mixExt map[string]string) { - clearSyncMap(&mimeTypes) - clearSyncMap(&mimeTypesLower) - clearSyncMap(&extensions) + mimeTypes.Clear() + mimeTypesLower.Clear() + extensions.Clear() for k, v := range lowerExt { mimeTypesLower.Store(k, v) @@ -157,7 +150,7 @@ func ExtensionsByType(typ string) ([]string, error) { return nil, nil } ret := append([]string(nil), s.([]string)...) - sort.Strings(ret) + slices.Sort(ret) return ret, nil } diff --git a/contrib/go/_std_1.22/src/mime/type_dragonfly.go b/contrib/go/_std_1.23/src/mime/type_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/type_dragonfly.go rename to contrib/go/_std_1.23/src/mime/type_dragonfly.go diff --git a/contrib/go/_std_1.22/src/mime/type_freebsd.go b/contrib/go/_std_1.23/src/mime/type_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/type_freebsd.go rename to contrib/go/_std_1.23/src/mime/type_freebsd.go diff --git a/contrib/go/_std_1.22/src/mime/type_openbsd.go b/contrib/go/_std_1.23/src/mime/type_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/type_openbsd.go rename to contrib/go/_std_1.23/src/mime/type_openbsd.go diff --git a/contrib/go/_std_1.22/src/mime/type_plan9.go b/contrib/go/_std_1.23/src/mime/type_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/type_plan9.go rename to contrib/go/_std_1.23/src/mime/type_plan9.go diff --git a/contrib/go/_std_1.22/src/mime/type_unix.go b/contrib/go/_std_1.23/src/mime/type_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/type_unix.go rename to contrib/go/_std_1.23/src/mime/type_unix.go diff --git a/contrib/go/_std_1.22/src/mime/type_windows.go b/contrib/go/_std_1.23/src/mime/type_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/mime/type_windows.go rename to contrib/go/_std_1.23/src/mime/type_windows.go diff --git a/contrib/go/_std_1.22/src/mime/ya.make b/contrib/go/_std_1.23/src/mime/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/mime/ya.make rename to contrib/go/_std_1.23/src/mime/ya.make diff --git a/contrib/go/_std_1.22/src/net/addrselect.go b/contrib/go/_std_1.23/src/net/addrselect.go similarity index 99% rename from contrib/go/_std_1.22/src/net/addrselect.go rename to contrib/go/_std_1.23/src/net/addrselect.go index 4f07032c4a01..caff09b3772f 100644 --- a/contrib/go/_std_1.22/src/net/addrselect.go +++ b/contrib/go/_std_1.23/src/net/addrselect.go @@ -42,7 +42,7 @@ func sortByRFC6724withSrcs(addrs []IPAddr, srcs []netip.Addr) { // number is irrelevant. func srcAddrs(addrs []IPAddr) []netip.Addr { srcs := make([]netip.Addr, len(addrs)) - dst := UDPAddr{Port: 9} + dst := UDPAddr{Port: 53} for i := range addrs { dst.IP = addrs[i].IP dst.Zone = addrs[i].Zone diff --git a/contrib/go/_std_1.22/src/net/cgo_aix.go b/contrib/go/_std_1.23/src/net/cgo_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_aix.go rename to contrib/go/_std_1.23/src/net/cgo_aix.go diff --git a/contrib/go/_std_1.22/src/net/cgo_android.go b/contrib/go/_std_1.23/src/net/cgo_android.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_android.go rename to contrib/go/_std_1.23/src/net/cgo_android.go diff --git a/contrib/go/_std_1.22/src/net/cgo_bsd.go b/contrib/go/_std_1.23/src/net/cgo_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_bsd.go rename to contrib/go/_std_1.23/src/net/cgo_bsd.go diff --git a/contrib/go/_std_1.22/src/net/cgo_darwin.go b/contrib/go/_std_1.23/src/net/cgo_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_darwin.go rename to contrib/go/_std_1.23/src/net/cgo_darwin.go diff --git a/contrib/go/_std_1.22/src/net/cgo_linux.go b/contrib/go/_std_1.23/src/net/cgo_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_linux.go rename to contrib/go/_std_1.23/src/net/cgo_linux.go diff --git a/contrib/go/_std_1.22/src/net/cgo_netbsd.go b/contrib/go/_std_1.23/src/net/cgo_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_netbsd.go rename to contrib/go/_std_1.23/src/net/cgo_netbsd.go diff --git a/contrib/go/_std_1.22/src/net/cgo_openbsd.go b/contrib/go/_std_1.23/src/net/cgo_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_openbsd.go rename to contrib/go/_std_1.23/src/net/cgo_openbsd.go diff --git a/contrib/go/_std_1.22/src/net/cgo_resnew.go b/contrib/go/_std_1.23/src/net/cgo_resnew.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_resnew.go rename to contrib/go/_std_1.23/src/net/cgo_resnew.go diff --git a/contrib/go/_std_1.22/src/net/cgo_resold.go b/contrib/go/_std_1.23/src/net/cgo_resold.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_resold.go rename to contrib/go/_std_1.23/src/net/cgo_resold.go diff --git a/contrib/go/_std_1.22/src/net/cgo_socknew.go b/contrib/go/_std_1.23/src/net/cgo_socknew.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_socknew.go rename to contrib/go/_std_1.23/src/net/cgo_socknew.go diff --git a/contrib/go/_std_1.22/src/net/cgo_sockold.go b/contrib/go/_std_1.23/src/net/cgo_sockold.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_sockold.go rename to contrib/go/_std_1.23/src/net/cgo_sockold.go diff --git a/contrib/go/_std_1.22/src/net/cgo_solaris.go b/contrib/go/_std_1.23/src/net/cgo_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_solaris.go rename to contrib/go/_std_1.23/src/net/cgo_solaris.go diff --git a/contrib/go/_std_1.22/src/net/cgo_stub.go b/contrib/go/_std_1.23/src/net/cgo_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/cgo_stub.go rename to contrib/go/_std_1.23/src/net/cgo_stub.go diff --git a/contrib/go/_std_1.22/src/net/cgo_unix.go b/contrib/go/_std_1.23/src/net/cgo_unix.go similarity index 85% rename from contrib/go/_std_1.22/src/net/cgo_unix.go rename to contrib/go/_std_1.23/src/net/cgo_unix.go index 7ed5daad73a6..bc374c2c7688 100644 --- a/contrib/go/_std_1.22/src/net/cgo_unix.go +++ b/contrib/go/_std_1.23/src/net/cgo_unix.go @@ -14,6 +14,7 @@ package net import ( "context" "errors" + "internal/bytealg" "net/netip" "syscall" "unsafe" @@ -40,8 +41,20 @@ func (eai addrinfoErrno) isAddrinfoErrno() {} // doBlockingWithCtx executes a blocking function in a separate goroutine when the provided // context is cancellable. It is intended for use with calls that don't support context // cancellation (cgo, syscalls). blocking func may still be running after this function finishes. -func doBlockingWithCtx[T any](ctx context.Context, blocking func() (T, error)) (T, error) { +// For the duration of the execution of the blocking function, the thread is 'acquired' using [acquireThread], +// blocking might not be executed when the context gets canceled early. +func doBlockingWithCtx[T any](ctx context.Context, lookupName string, blocking func() (T, error)) (T, error) { + if err := acquireThread(ctx); err != nil { + var zero T + return zero, &DNSError{ + Name: lookupName, + Err: mapErr(err).Error(), + IsTimeout: err == context.DeadlineExceeded, + } + } + if ctx.Done() == nil { + defer releaseThread() return blocking() } @@ -52,6 +65,7 @@ func doBlockingWithCtx[T any](ctx context.Context, blocking func() (T, error)) ( res := make(chan result, 1) go func() { + defer releaseThread() var r result r.res, r.err = blocking() res <- r @@ -62,7 +76,11 @@ func doBlockingWithCtx[T any](ctx context.Context, blocking func() (T, error)) ( return r.res, r.err case <-ctx.Done(): var zero T - return zero, mapErr(ctx.Err()) + return zero, &DNSError{ + Name: lookupName, + Err: mapErr(ctx.Err()).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } } } @@ -97,7 +115,7 @@ func cgoLookupPort(ctx context.Context, network, service string) (port int, err *_C_ai_family(&hints) = _C_AF_INET6 } - return doBlockingWithCtx(ctx, func() (int, error) { + return doBlockingWithCtx(ctx, network+"/"+service, func() (int, error) { return cgoLookupServicePort(&hints, network, service) }) } @@ -114,19 +132,17 @@ func cgoLookupServicePort(hints *_C_struct_addrinfo, network, service string) (p var res *_C_struct_addrinfo gerrno, err := _C_getaddrinfo(nil, (*_C_char)(unsafe.Pointer(&cservice[0])), hints, &res) if gerrno != 0 { - isTemporary := false switch gerrno { case _C_EAI_SYSTEM: if err == nil { // see golang.org/issue/6232 err = syscall.EMFILE } + return 0, newDNSError(err, network+"/"+service, "") case _C_EAI_SERVICE, _C_EAI_NONAME: // Darwin returns EAI_NONAME. - return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true} + return 0, newDNSError(errUnknownPort, network+"/"+service, "") default: - err = addrinfoErrno(gerrno) - isTemporary = addrinfoErrno(gerrno).Temporary() + return 0, newDNSError(addrinfoErrno(gerrno), network+"/"+service, "") } - return 0, &DNSError{Err: err.Error(), Name: network + "/" + service, IsTemporary: isTemporary} } defer _C_freeaddrinfo(res) @@ -142,13 +158,10 @@ func cgoLookupServicePort(hints *_C_struct_addrinfo, network, service string) (p return int(p[0])<<8 | int(p[1]), nil } } - return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true} + return 0, newDNSError(errUnknownPort, network+"/"+service, "") } func cgoLookupHostIP(network, name string) (addrs []IPAddr, err error) { - acquireThread() - defer releaseThread() - var hints _C_struct_addrinfo *_C_ai_flags(&hints) = cgoAddrInfoFlags *_C_ai_socktype(&hints) = _C_SOCK_STREAM @@ -167,8 +180,6 @@ func cgoLookupHostIP(network, name string) (addrs []IPAddr, err error) { var res *_C_struct_addrinfo gerrno, err := _C_getaddrinfo((*_C_char)(unsafe.Pointer(h)), nil, &hints, &res) if gerrno != 0 { - isErrorNoSuchHost := false - isTemporary := false switch gerrno { case _C_EAI_SYSTEM: if err == nil { @@ -181,15 +192,13 @@ func cgoLookupHostIP(network, name string) (addrs []IPAddr, err error) { // comes up again. golang.org/issue/6232. err = syscall.EMFILE } + return nil, newDNSError(err, name, "") case _C_EAI_NONAME, _C_EAI_NODATA: - err = errNoSuchHost - isErrorNoSuchHost = true + return nil, newDNSError(errNoSuchHost, name, "") default: - err = addrinfoErrno(gerrno) - isTemporary = addrinfoErrno(gerrno).Temporary() + return nil, newDNSError(addrinfoErrno(gerrno), name, "") } - return nil, &DNSError{Err: err.Error(), Name: name, IsNotFound: isErrorNoSuchHost, IsTemporary: isTemporary} } defer _C_freeaddrinfo(res) @@ -213,7 +222,7 @@ func cgoLookupHostIP(network, name string) (addrs []IPAddr, err error) { } func cgoLookupIP(ctx context.Context, network, name string) (addrs []IPAddr, err error) { - return doBlockingWithCtx(ctx, func() ([]IPAddr, error) { + return doBlockingWithCtx(ctx, name, func() ([]IPAddr, error) { return cgoLookupHostIP(network, name) }) } @@ -241,15 +250,12 @@ func cgoLookupPTR(ctx context.Context, addr string) (names []string, err error) return nil, &DNSError{Err: "invalid address " + ip.String(), Name: addr} } - return doBlockingWithCtx(ctx, func() ([]string, error) { + return doBlockingWithCtx(ctx, addr, func() ([]string, error) { return cgoLookupAddrPTR(addr, sa, salen) }) } func cgoLookupAddrPTR(addr string, sa *_C_struct_sockaddr, salen _C_socklen_t) (names []string, err error) { - acquireThread() - defer releaseThread() - var gerrno int var b []byte for l := nameinfoLen; l <= maxNameinfoLen; l *= 2 { @@ -260,27 +266,20 @@ func cgoLookupAddrPTR(addr string, sa *_C_struct_sockaddr, salen _C_socklen_t) ( } } if gerrno != 0 { - isErrorNoSuchHost := false - isTemporary := false switch gerrno { case _C_EAI_SYSTEM: if err == nil { // see golang.org/issue/6232 err = syscall.EMFILE } + return nil, newDNSError(err, addr, "") case _C_EAI_NONAME: - err = errNoSuchHost - isErrorNoSuchHost = true + return nil, newDNSError(errNoSuchHost, addr, "") default: - err = addrinfoErrno(gerrno) - isTemporary = addrinfoErrno(gerrno).Temporary() + return nil, newDNSError(addrinfoErrno(gerrno), addr, "") } - return nil, &DNSError{Err: err.Error(), Name: addr, IsTemporary: isTemporary, IsNotFound: isErrorNoSuchHost} } - for i := 0; i < len(b); i++ { - if b[i] == 0 { - b = b[:i] - break - } + if i := bytealg.IndexByte(b, 0); i != -1 { + b = b[:i] } return []string{absDomainName(string(b))}, nil } @@ -310,15 +309,12 @@ func cgoLookupCNAME(ctx context.Context, name string) (cname string, err error, // resSearch will make a call to the 'res_nsearch' routine in the C library // and parse the output as a slice of DNS resources. func resSearch(ctx context.Context, hostname string, rtype, class int) ([]dnsmessage.Resource, error) { - return doBlockingWithCtx(ctx, func() ([]dnsmessage.Resource, error) { + return doBlockingWithCtx(ctx, hostname, func() ([]dnsmessage.Resource, error) { return cgoResSearch(hostname, rtype, class) }) } func cgoResSearch(hostname string, rtype, class int) ([]dnsmessage.Resource, error) { - acquireThread() - defer releaseThread() - resStateSize := unsafe.Sizeof(_C_struct___res_state{}) var state *_C_struct___res_state if resStateSize > 0 { @@ -352,7 +348,7 @@ func cgoResSearch(hostname string, rtype, class int) ([]dnsmessage.Resource, err var size int for { - size, _ = _C_res_nsearch(state, (*_C_char)(unsafe.Pointer(s)), class, rtype, buf, bufSize) + size := _C_res_nsearch(state, (*_C_char)(unsafe.Pointer(s)), class, rtype, buf, bufSize) if size <= 0 || size > 0xffff { return nil, errors.New("res_nsearch failure") } diff --git a/contrib/go/_std_1.22/src/net/cgo_unix_cgo.go b/contrib/go/_std_1.23/src/net/cgo_unix_cgo.go similarity index 99% rename from contrib/go/_std_1.22/src/net/cgo_unix_cgo.go rename to contrib/go/_std_1.23/src/net/cgo_unix_cgo.go index 7c609eddbf76..d38ae0a84f2b 100644 --- a/contrib/go/_std_1.22/src/net/cgo_unix_cgo.go +++ b/contrib/go/_std_1.23/src/net/cgo_unix_cgo.go @@ -7,7 +7,7 @@ package net /* -#define _GNU_SOURCE +#define _GNU_SOURCE 1 #cgo CFLAGS: -fno-stack-protector #include diff --git a/contrib/go/_std_1.22/src/net/cgo_unix_cgo_res.go b/contrib/go/_std_1.23/src/net/cgo_unix_cgo_res.go similarity index 82% rename from contrib/go/_std_1.22/src/net/cgo_unix_cgo_res.go rename to contrib/go/_std_1.23/src/net/cgo_unix_cgo_res.go index 37bbc9a762d8..c5f30238a13c 100644 --- a/contrib/go/_std_1.22/src/net/cgo_unix_cgo_res.go +++ b/contrib/go/_std_1.23/src/net/cgo_unix_cgo_res.go @@ -32,7 +32,7 @@ func _C_res_nclose(state *_C_struct___res_state) { return } -func _C_res_nsearch(state *_C_struct___res_state, dname *_C_char, class, typ int, ans *_C_uchar, anslen int) (int, error) { - x, err := C.res_search(dname, C.int(class), C.int(typ), ans, C.int(anslen)) - return int(x), err +func _C_res_nsearch(state *_C_struct___res_state, dname *_C_char, class, typ int, ans *_C_uchar, anslen int) int { + x := C.res_search(dname, C.int(class), C.int(typ), ans, C.int(anslen)) + return int(x) } diff --git a/contrib/go/_std_1.22/src/net/cgo_unix_cgo_resn.go b/contrib/go/_std_1.23/src/net/cgo_unix_cgo_resn.go similarity index 83% rename from contrib/go/_std_1.22/src/net/cgo_unix_cgo_resn.go rename to contrib/go/_std_1.23/src/net/cgo_unix_cgo_resn.go index 4a5ff165dfae..4fc747b5a339 100644 --- a/contrib/go/_std_1.22/src/net/cgo_unix_cgo_resn.go +++ b/contrib/go/_std_1.23/src/net/cgo_unix_cgo_resn.go @@ -33,7 +33,7 @@ func _C_res_nclose(state *_C_struct___res_state) { C.res_nclose(state) } -func _C_res_nsearch(state *_C_struct___res_state, dname *_C_char, class, typ int, ans *_C_uchar, anslen int) (int, error) { - x, err := C.res_nsearch(state, dname, C.int(class), C.int(typ), ans, C.int(anslen)) - return int(x), err +func _C_res_nsearch(state *_C_struct___res_state, dname *_C_char, class, typ int, ans *_C_uchar, anslen int) int { + x := C.res_nsearch(state, dname, C.int(class), C.int(typ), ans, C.int(anslen)) + return int(x) } diff --git a/contrib/go/_std_1.22/src/net/cgo_unix_syscall.go b/contrib/go/_std_1.23/src/net/cgo_unix_syscall.go similarity index 95% rename from contrib/go/_std_1.22/src/net/cgo_unix_syscall.go rename to contrib/go/_std_1.23/src/net/cgo_unix_syscall.go index ac9aaa78fe7c..735dcdfe368b 100644 --- a/contrib/go/_std_1.22/src/net/cgo_unix_syscall.go +++ b/contrib/go/_std_1.23/src/net/cgo_unix_syscall.go @@ -73,8 +73,9 @@ func _C_res_ninit(state *_C_struct___res_state) error { return nil } -func _C_res_nsearch(state *_C_struct___res_state, dname *_C_char, class, typ int, ans *_C_char, anslen int) (int, error) { - return unix.ResNsearch(state, dname, class, typ, ans, anslen) +func _C_res_nsearch(state *_C_struct___res_state, dname *_C_char, class, typ int, ans *_C_char, anslen int) int { + x, _ := unix.ResNsearch(state, dname, class, typ, ans, anslen) + return x } func _C_res_nclose(state *_C_struct___res_state) { diff --git a/contrib/go/_std_1.22/src/net/conf.go b/contrib/go/_std_1.23/src/net/conf.go similarity index 95% rename from contrib/go/_std_1.22/src/net/conf.go rename to contrib/go/_std_1.23/src/net/conf.go index 15d73cf6ce1a..358f5434c4de 100644 --- a/contrib/go/_std_1.22/src/net/conf.go +++ b/contrib/go/_std_1.23/src/net/conf.go @@ -8,6 +8,7 @@ import ( "errors" "internal/bytealg" "internal/godebug" + "internal/stringslite" "io/fs" "os" "runtime" @@ -190,7 +191,7 @@ func (c *conf) mustUseGoResolver(r *Resolver) bool { if runtime.GOOS == "plan9" { // TODO(bradfitz): for now we only permit use of the PreferGo // implementation when there's a non-nil Resolver with a - // non-nil Dialer. This is a sign that they the code is trying + // non-nil Dialer. This is a sign that the code is trying // to use their DNS-speaking net.Conn (such as an in-memory // DNS cache) and they don't want to actually hit the network. // Once we add support for looking the default DNS servers @@ -335,16 +336,7 @@ func (c *conf) lookupOrder(r *Resolver, hostname string) (ret hostLookupOrder, d } // Canonicalize the hostname by removing any trailing dot. - if stringsHasSuffix(hostname, ".") { - hostname = hostname[:len(hostname)-1] - } - if canUseCgo && stringsHasSuffixFold(hostname, ".local") { - // Per RFC 6762, the ".local" TLD is special. And - // because Go's native resolver doesn't do mDNS or - // similar local resolution mechanisms, assume that - // libc might (via Avahi, etc) and use cgo. - return hostLookupCgo, dnsConf - } + hostname = stringslite.TrimSuffix(hostname, ".") nss := getSystemNSS() srcs := nss.sources["hosts"] @@ -403,10 +395,14 @@ func (c *conf) lookupOrder(r *Resolver, hostname string) (ret hostLookupOrder, d return hostLookupCgo, dnsConf } continue - case hostname != "" && stringsHasPrefix(src.source, "mdns"): - // e.g. "mdns4", "mdns4_minimal" - // We already returned true before if it was *.local. - // libc wouldn't have found a hit on this anyway. + case hostname != "" && stringslite.HasPrefix(src.source, "mdns"): + if stringsHasSuffixFold(hostname, ".local") { + // Per RFC 6762, the ".local" TLD is special. And + // because Go's native resolver doesn't do mDNS or + // similar local resolution mechanisms, assume that + // libc might (via Avahi, etc) and use cgo. + return hostLookupCgo, dnsConf + } // We don't parse mdns.allow files. They're rare. If one // exists, it might list other TLDs (besides .local) or even diff --git a/contrib/go/_std_1.22/src/net/dial.go b/contrib/go/_std_1.23/src/net/dial.go similarity index 94% rename from contrib/go/_std_1.22/src/net/dial.go rename to contrib/go/_std_1.23/src/net/dial.go index a6565c3ce5d1..28f346a372a7 100644 --- a/contrib/go/_std_1.22/src/net/dial.go +++ b/contrib/go/_std_1.23/src/net/dial.go @@ -14,9 +14,16 @@ import ( ) const ( - // defaultTCPKeepAlive is a default constant value for TCPKeepAlive times - // See go.dev/issue/31510 - defaultTCPKeepAlive = 15 * time.Second + // defaultTCPKeepAliveIdle is a default constant value for TCP_KEEPIDLE. + // See go.dev/issue/31510 for details. + defaultTCPKeepAliveIdle = 15 * time.Second + + // defaultTCPKeepAliveInterval is a default constant value for TCP_KEEPINTVL. + // It is the same as defaultTCPKeepAliveIdle, see go.dev/issue/31510 for details. + defaultTCPKeepAliveInterval = 15 * time.Second + + // defaultTCPKeepAliveCount is a default constant value for TCP_KEEPCNT. + defaultTCPKeepAliveCount = 9 // For the moment, MultiPath TCP is not used by default // See go.dev/issue/56539 @@ -116,13 +123,25 @@ type Dialer struct { // KeepAlive specifies the interval between keep-alive // probes for an active network connection. + // + // KeepAlive is ignored if KeepAliveConfig.Enable is true. + // // If zero, keep-alive probes are sent with a default value // (currently 15 seconds), if supported by the protocol and operating // system. Network protocols or operating systems that do - // not support keep-alives ignore this field. + // not support keep-alive ignore this field. // If negative, keep-alive probes are disabled. KeepAlive time.Duration + // KeepAliveConfig specifies the keep-alive probe configuration + // for an active network connection, when supported by the + // protocol and operating system. + // + // If KeepAliveConfig.Enable is true, keep-alive probes are enabled. + // If KeepAliveConfig.Enable is false and KeepAlive is negative, + // keep-alive probes are disabled. + KeepAliveConfig KeepAliveConfig + // Resolver optionally specifies an alternate resolver to use. Resolver *Resolver @@ -680,12 +699,24 @@ type ListenConfig struct { // KeepAlive specifies the keep-alive period for network // connections accepted by this listener. - // If zero, keep-alives are enabled if supported by the protocol + // + // KeepAlive is ignored if KeepAliveConfig.Enable is true. + // + // If zero, keep-alive are enabled if supported by the protocol // and operating system. Network protocols or operating systems - // that do not support keep-alives ignore this field. - // If negative, keep-alives are disabled. + // that do not support keep-alive ignore this field. + // If negative, keep-alive are disabled. KeepAlive time.Duration + // KeepAliveConfig specifies the keep-alive probe configuration + // for an active network connection, when supported by the + // protocol and operating system. + // + // If KeepAliveConfig.Enable is true, keep-alive probes are enabled. + // If KeepAliveConfig.Enable is false and KeepAlive is negative, + // keep-alive probes are disabled. + KeepAliveConfig KeepAliveConfig + // If mptcpStatus is set to a value allowing Multipath TCP (MPTCP) to be // used, any call to Listen with "tcp(4|6)" as network will use MPTCP if // supported by the operating system. diff --git a/contrib/go/_std_1.22/src/net/dnsclient.go b/contrib/go/_std_1.23/src/net/dnsclient.go similarity index 89% rename from contrib/go/_std_1.22/src/net/dnsclient.go rename to contrib/go/_std_1.23/src/net/dnsclient.go index 204620b2edb8..5f135cc21173 100644 --- a/contrib/go/_std_1.22/src/net/dnsclient.go +++ b/contrib/go/_std_1.23/src/net/dnsclient.go @@ -5,15 +5,17 @@ package net import ( + "cmp" "internal/bytealg" "internal/itoa" - "sort" + "slices" _ "unsafe" // for go:linkname "golang.org/x/net/dns/dnsmessage" ) // provided by runtime +// //go:linkname runtime_rand runtime.rand func runtime_rand() uint64 @@ -74,6 +76,16 @@ func equalASCIIName(x, y dnsmessage.Name) bool { // isDomainName checks if a string is a presentation-format domain name // (currently restricted to hostname-compatible "preferred name" LDH labels and // SRV-like "underscore labels"; see golang.org/issue/12421). +// +// isDomainName should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/sagernet/sing +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname isDomainName func isDomainName(s string) bool { // The root domain name is valid. See golang.org/issue/45715. if s == "." { @@ -159,12 +171,6 @@ type SRV struct { // byPriorityWeight sorts SRV records by ascending priority and weight. type byPriorityWeight []*SRV -func (s byPriorityWeight) Len() int { return len(s) } -func (s byPriorityWeight) Less(i, j int) bool { - return s[i].Priority < s[j].Priority || (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight) -} -func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - // shuffleByWeight shuffles SRV records by weight using the algorithm // described in RFC 2782. func (addrs byPriorityWeight) shuffleByWeight() { @@ -191,7 +197,12 @@ func (addrs byPriorityWeight) shuffleByWeight() { // sort reorders SRV records as specified in RFC 2782. func (addrs byPriorityWeight) sort() { - sort.Sort(addrs) + slices.SortFunc(addrs, func(a, b *SRV) int { + if r := cmp.Compare(a.Priority, b.Priority); r != 0 { + return r + } + return cmp.Compare(a.Weight, b.Weight) + }) i := 0 for j := 1; j < len(addrs); j++ { if addrs[i].Priority != addrs[j].Priority { @@ -208,20 +219,18 @@ type MX struct { Pref uint16 } -// byPref implements sort.Interface to sort MX records by preference +// byPref sorts MX records by preference type byPref []*MX -func (s byPref) Len() int { return len(s) } -func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref } -func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - // sort reorders MX records as specified in RFC 5321. func (s byPref) sort() { for i := range s { j := randIntn(i + 1) s[i], s[j] = s[j], s[i] } - sort.Sort(s) + slices.SortFunc(s, func(a, b *MX) int { + return cmp.Compare(a.Pref, b.Pref) + }) } // An NS represents a single DNS NS record. diff --git a/contrib/go/_std_1.22/src/net/dnsclient_unix.go b/contrib/go/_std_1.23/src/net/dnsclient_unix.go similarity index 92% rename from contrib/go/_std_1.22/src/net/dnsclient_unix.go rename to contrib/go/_std_1.23/src/net/dnsclient_unix.go index 8821641a0162..54c7dc83bac6 100644 --- a/contrib/go/_std_1.22/src/net/dnsclient_unix.go +++ b/contrib/go/_std_1.23/src/net/dnsclient_unix.go @@ -49,7 +49,7 @@ var ( // errServerTemporarilyMisbehaving is like errServerMisbehaving, except // that when it gets translated to a DNSError, the IsTemporary field // gets set to true. - errServerTemporarilyMisbehaving = errors.New("server misbehaving") + errServerTemporarilyMisbehaving = &temporaryError{"server misbehaving"} ) // netedns0 controls whether we send an EDNS0 additional header. @@ -202,7 +202,14 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que if err := p.SkipQuestion(); err != dnsmessage.ErrSectionDone { return dnsmessage.Parser{}, dnsmessage.Header{}, errInvalidDNSResponse } - if h.Truncated { // see RFC 5966 + // RFC 5966 indicates that when a client receives a UDP response with + // the TC flag set, it should take the TC flag as an indication that it + // should retry over TCP instead. + // The case when the TC flag is set in a TCP response is not well specified, + // so this implements the glibc resolver behavior, returning the existing + // dns response instead of returning a "errNoAnswerFromDNSServer" error. + // See go.dev/issue/64896 + if h.Truncated && network == "udp" { continue } return p, h, nil @@ -212,7 +219,7 @@ func (r *Resolver) exchange(ctx context.Context, server string, q dnsmessage.Que // checkHeader performs basic sanity checks on the header. func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error { - rcode := extractExtendedRCode(*p, h) + rcode, hasAdd := extractExtendedRCode(*p, h) if rcode == dnsmessage.RCodeNameError { return errNoSuchHost @@ -225,7 +232,7 @@ func checkHeader(p *dnsmessage.Parser, h dnsmessage.Header) error { // libresolv continues to the next server when it receives // an invalid referral response. See golang.org/issue/15434. - if rcode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone { + if rcode == dnsmessage.RCodeSuccess && !h.Authoritative && !h.RecursionAvailable && err == dnsmessage.ErrSectionDone && !hasAdd { return errLameReferral } @@ -264,19 +271,22 @@ func skipToAnswer(p *dnsmessage.Parser, qtype dnsmessage.Type) error { // extractExtendedRCode extracts the extended RCode from the OPT resource (EDNS(0)) // If an OPT record is not found, the RCode from the hdr is returned. -func extractExtendedRCode(p dnsmessage.Parser, hdr dnsmessage.Header) dnsmessage.RCode { +// Another return value indicates whether an additional resource was found. +func extractExtendedRCode(p dnsmessage.Parser, hdr dnsmessage.Header) (dnsmessage.RCode, bool) { p.SkipAllAnswers() p.SkipAllAuthorities() + hasAdd := false for { ahdr, err := p.AdditionalHeader() if err != nil { - return hdr.RCode + return hdr.RCode, hasAdd } + hasAdd = true if ahdr.Type == dnsmessage.TypeOPT { - return ahdr.ExtendedRCode(hdr.RCode) + return ahdr.ExtendedRCode(hdr.RCode), hasAdd } if err := p.SkipAdditional(); err != nil { - return hdr.RCode + return hdr.RCode, hasAdd } } } @@ -290,7 +300,7 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, n, err := dnsmessage.NewName(name) if err != nil { - return dnsmessage.Parser{}, "", errCannotMarshalDNSMessage + return dnsmessage.Parser{}, "", &DNSError{Err: errCannotMarshalDNSMessage.Error(), Name: name} } q := dnsmessage.Question{ Name: n, @@ -304,14 +314,7 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, p, h, err := r.exchange(ctx, server, q, cfg.timeout, cfg.useTCP, cfg.trustAD) if err != nil { - dnsErr := &DNSError{ - Err: err.Error(), - Name: name, - Server: server, - } - if nerr, ok := err.(Error); ok && nerr.Timeout() { - dnsErr.IsTimeout = true - } + dnsErr := newDNSError(err, name, server) // Set IsTemporary for socket-level errors. Note that this flag // may also be used to indicate a SERVFAIL response. if _, ok := err.(*OpError); ok { @@ -322,41 +325,26 @@ func (r *Resolver) tryOneName(ctx context.Context, cfg *dnsConfig, name string, } if err := checkHeader(&p, h); err != nil { - dnsErr := &DNSError{ - Err: err.Error(), - Name: name, - Server: server, - } - if err == errServerTemporarilyMisbehaving { - dnsErr.IsTemporary = true - } if err == errNoSuchHost { // The name does not exist, so trying // another server won't help. - - dnsErr.IsNotFound = true - return p, server, dnsErr + return p, server, newDNSError(errNoSuchHost, name, server) } - lastErr = dnsErr + lastErr = newDNSError(err, name, server) continue } - err = skipToAnswer(&p, qtype) - if err == nil { - return p, server, nil - } - lastErr = &DNSError{ - Err: err.Error(), - Name: name, - Server: server, + if err := skipToAnswer(&p, qtype); err != nil { + if err == errNoSuchHost { + // The name does not exist, so trying + // another server won't help. + return p, server, newDNSError(errNoSuchHost, name, server) + } + lastErr = newDNSError(err, name, server) + continue } - if err == errNoSuchHost { - // The name does not exist, so trying another - // server won't help. - lastErr.(*DNSError).IsNotFound = true - return p, server, lastErr - } + return p, server, nil } } return dnsmessage.Parser{}, "", lastErr @@ -456,7 +444,7 @@ func (r *Resolver) lookup(ctx context.Context, name string, qtype dnsmessage.Typ // Other lookups might allow broader name syntax // (for example Multicast DNS allows UTF-8; see RFC 6762). // For consistency with libc resolvers, report no such host. - return dnsmessage.Parser{}, "", &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} + return dnsmessage.Parser{}, "", newDNSError(errNoSuchHost, name, "") } if conf == nil { @@ -584,7 +572,7 @@ func (r *Resolver) goLookupHostOrder(ctx context.Context, name string, order hos } if order == hostLookupFiles { - return nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} + return nil, newDNSError(errNoSuchHost, name, "") } } ips, _, err := r.goLookupIPCNAMEOrder(ctx, "ip", name, order, conf) @@ -634,13 +622,13 @@ func (r *Resolver) goLookupIPCNAMEOrder(ctx context.Context, network, name strin } if order == hostLookupFiles { - return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} + return nil, dnsmessage.Name{}, newDNSError(errNoSuchHost, name, "") } } if !isDomainName(name) { // See comment in func lookup above about use of errNoSuchHost. - return nil, dnsmessage.Name{}, &DNSError{Err: errNoSuchHost.Error(), Name: name, IsNotFound: true} + return nil, dnsmessage.Name{}, newDNSError(errNoSuchHost, name, "") } type result struct { p dnsmessage.Parser @@ -845,7 +833,7 @@ func (r *Resolver) goLookupPTR(ctx context.Context, addr string, order hostLooku } if order == hostLookupFiles { - return nil, &DNSError{Err: errNoSuchHost.Error(), Name: addr, IsNotFound: true} + return nil, newDNSError(errNoSuchHost, addr, "") } } diff --git a/contrib/go/_std_1.22/src/net/dnsconfig.go b/contrib/go/_std_1.23/src/net/dnsconfig.go similarity index 74% rename from contrib/go/_std_1.22/src/net/dnsconfig.go rename to contrib/go/_std_1.23/src/net/dnsconfig.go index c86a70be5afd..7919c3c3b551 100644 --- a/contrib/go/_std_1.22/src/net/dnsconfig.go +++ b/contrib/go/_std_1.23/src/net/dnsconfig.go @@ -8,12 +8,25 @@ import ( "os" "sync/atomic" "time" + _ "unsafe" ) -var ( - defaultNS = []string{"127.0.0.1:53", "[::1]:53"} - getHostname = os.Hostname // variable for testing -) +// defaultNS is the default name servers to use in the absence of DNS configuration. +// +// defaultNS should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/pojntfx/hydrapp/hydrapp +// - github.com/mtibben/androiddnsfix +// - github.com/metacubex/mihomo +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname defaultNS +var defaultNS = []string{"127.0.0.1:53", "[::1]:53"} + +var getHostname = os.Hostname // variable for testing type dnsConfig struct { servers []string // server addresses (in host:port form) to use diff --git a/contrib/go/_std_1.22/src/net/dnsconfig_unix.go b/contrib/go/_std_1.23/src/net/dnsconfig_unix.go similarity index 95% rename from contrib/go/_std_1.22/src/net/dnsconfig_unix.go rename to contrib/go/_std_1.23/src/net/dnsconfig_unix.go index b0a318279b99..0fcf2c6cc384 100644 --- a/contrib/go/_std_1.22/src/net/dnsconfig_unix.go +++ b/contrib/go/_std_1.23/src/net/dnsconfig_unix.go @@ -10,6 +10,7 @@ package net import ( "internal/bytealg" + "internal/stringslite" "net/netip" "time" ) @@ -75,7 +76,7 @@ func dnsReadConfig(filename string) *dnsConfig { case "options": // magic options for _, s := range f[1:] { switch { - case hasPrefix(s, "ndots:"): + case stringslite.HasPrefix(s, "ndots:"): n, _, _ := dtoi(s[6:]) if n < 0 { n = 0 @@ -83,13 +84,13 @@ func dnsReadConfig(filename string) *dnsConfig { n = 15 } conf.ndots = n - case hasPrefix(s, "timeout:"): + case stringslite.HasPrefix(s, "timeout:"): n, _, _ := dtoi(s[8:]) if n < 1 { n = 1 } conf.timeout = time.Duration(n) * time.Second - case hasPrefix(s, "attempts:"): + case stringslite.HasPrefix(s, "attempts:"): n, _, _ := dtoi(s[9:]) if n < 1 { n = 1 @@ -155,10 +156,6 @@ func dnsDefaultSearch() []string { return nil } -func hasPrefix(s, prefix string) bool { - return len(s) >= len(prefix) && s[:len(prefix)] == prefix -} - func ensureRooted(s string) string { if len(s) > 0 && s[len(s)-1] == '.' { return s diff --git a/contrib/go/_std_1.22/src/net/dnsconfig_windows.go b/contrib/go/_std_1.23/src/net/dnsconfig_windows.go similarity index 68% rename from contrib/go/_std_1.22/src/net/dnsconfig_windows.go rename to contrib/go/_std_1.23/src/net/dnsconfig_windows.go index f3d242366ae2..34455309dbb2 100644 --- a/contrib/go/_std_1.22/src/net/dnsconfig_windows.go +++ b/contrib/go/_std_1.23/src/net/dnsconfig_windows.go @@ -25,16 +25,19 @@ func dnsReadConfig(ignoredFilename string) (conf *dnsConfig) { if err != nil { return } - // TODO(bradfitz): this just collects all the DNS servers on all - // the interfaces in some random order. It should order it by - // default route, or only use the default route(s) instead. - // In practice, however, it mostly works. + for _, aa := range aas { + // Only take interfaces whose OperStatus is IfOperStatusUp(0x01) into DNS configs. + if aa.OperStatus != windows.IfOperStatusUp { + continue + } + + // Only take interfaces which have at least one gateway + if aa.FirstGatewayAddress == nil { + continue + } + for dns := aa.FirstDnsServerAddress; dns != nil; dns = dns.Next { - // Only take interfaces whose OperStatus is IfOperStatusUp(0x01) into DNS configs. - if aa.OperStatus != windows.IfOperStatusUp { - continue - } sa, err := dns.Address.Sockaddr.Sockaddr() if err != nil { continue @@ -47,9 +50,11 @@ func dnsReadConfig(ignoredFilename string) (conf *dnsConfig) { ip = make(IP, IPv6len) copy(ip, sa.Addr[:]) if ip[0] == 0xfe && ip[1] == 0xc0 { - // Ignore these fec0/10 ones. Windows seems to - // populate them as defaults on its misc rando - // interfaces. + // fec0/10 IPv6 addresses are site local anycast DNS + // addresses Microsoft sets by default if no other + // IPv6 DNS address is set. Site local anycast is + // deprecated since 2004, see + // https://datatracker.ietf.org/doc/html/rfc3879 continue } default: diff --git a/contrib/go/_std_1.22/src/net/error_plan9.go b/contrib/go/_std_1.23/src/net/error_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/error_plan9.go rename to contrib/go/_std_1.23/src/net/error_plan9.go diff --git a/contrib/go/_std_1.22/src/net/error_posix.go b/contrib/go/_std_1.23/src/net/error_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/error_posix.go rename to contrib/go/_std_1.23/src/net/error_posix.go diff --git a/contrib/go/_std_1.22/src/net/error_unix.go b/contrib/go/_std_1.23/src/net/error_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/error_unix.go rename to contrib/go/_std_1.23/src/net/error_unix.go diff --git a/contrib/go/_std_1.22/src/net/error_windows.go b/contrib/go/_std_1.23/src/net/error_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/error_windows.go rename to contrib/go/_std_1.23/src/net/error_windows.go diff --git a/contrib/go/_std_1.22/src/net/fd_fake.go b/contrib/go/_std_1.23/src/net/fd_fake.go similarity index 100% rename from contrib/go/_std_1.22/src/net/fd_fake.go rename to contrib/go/_std_1.23/src/net/fd_fake.go diff --git a/contrib/go/_std_1.22/src/net/fd_js.go b/contrib/go/_std_1.23/src/net/fd_js.go similarity index 100% rename from contrib/go/_std_1.22/src/net/fd_js.go rename to contrib/go/_std_1.23/src/net/fd_js.go diff --git a/contrib/go/_std_1.22/src/net/fd_plan9.go b/contrib/go/_std_1.23/src/net/fd_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/fd_plan9.go rename to contrib/go/_std_1.23/src/net/fd_plan9.go diff --git a/contrib/go/_std_1.22/src/net/fd_posix.go b/contrib/go/_std_1.23/src/net/fd_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/fd_posix.go rename to contrib/go/_std_1.23/src/net/fd_posix.go diff --git a/contrib/go/_std_1.22/src/net/fd_unix.go b/contrib/go/_std_1.23/src/net/fd_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/fd_unix.go rename to contrib/go/_std_1.23/src/net/fd_unix.go diff --git a/contrib/go/_std_1.22/src/net/fd_wasip1.go b/contrib/go/_std_1.23/src/net/fd_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/net/fd_wasip1.go rename to contrib/go/_std_1.23/src/net/fd_wasip1.go diff --git a/contrib/go/_std_1.22/src/net/fd_windows.go b/contrib/go/_std_1.23/src/net/fd_windows.go similarity index 97% rename from contrib/go/_std_1.22/src/net/fd_windows.go rename to contrib/go/_std_1.23/src/net/fd_windows.go index 45a10cf1eb01..5d7a1d54c31a 100644 --- a/contrib/go/_std_1.22/src/net/fd_windows.go +++ b/contrib/go/_std_1.23/src/net/fd_windows.go @@ -23,6 +23,10 @@ const ( writeMsgSyscallName = "wsasendmsg" ) +func init() { + poll.InitWSA() +} + // canUseConnectEx reports whether we can use the ConnectEx Windows API call // for the given network type. func canUseConnectEx(net string) bool { @@ -131,7 +135,7 @@ func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (syscall. Rtt: windows.TCP_INITIAL_RTO_UNSPECIFIED_RTT, // use the default or overridden by the Administrator MaxSynRetransmissions: 1, // minimum possible value before Windows 10.0.16299 } - if windows.Support_TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS() { + if windows.SupportTCPInitialRTONoSYNRetransmissions() { // In Windows 10.0.16299 TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS makes ConnectEx() fails instantly. params.MaxSynRetransmissions = windows.TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS } @@ -212,6 +216,6 @@ func (fd *netFD) accept() (*netFD, error) { // Unimplemented functions. func (fd *netFD) dup() (*os.File, error) { - // TODO: Implement this + // TODO: Implement this, perhaps using internal/poll.DupCloseOnExec. return nil, syscall.EWINDOWS } diff --git a/contrib/go/_std_1.22/src/net/file.go b/contrib/go/_std_1.23/src/net/file.go similarity index 100% rename from contrib/go/_std_1.22/src/net/file.go rename to contrib/go/_std_1.23/src/net/file.go diff --git a/contrib/go/_std_1.22/src/net/file_plan9.go b/contrib/go/_std_1.23/src/net/file_plan9.go similarity index 95% rename from contrib/go/_std_1.22/src/net/file_plan9.go rename to contrib/go/_std_1.23/src/net/file_plan9.go index 64aabf93ee54..6c2151c4098a 100644 --- a/contrib/go/_std_1.22/src/net/file_plan9.go +++ b/contrib/go/_std_1.23/src/net/file_plan9.go @@ -100,7 +100,7 @@ func fileConn(f *os.File) (Conn, error) { switch fd.laddr.(type) { case *TCPAddr: - return newTCPConn(fd, defaultTCPKeepAlive, testHookSetKeepAlive), nil + return newTCPConn(fd, defaultTCPKeepAliveIdle, KeepAliveConfig{}, testPreHookSetKeepAlive, testHookSetKeepAlive), nil case *UDPAddr: return newUDPConn(fd), nil } diff --git a/contrib/go/_std_1.22/src/net/file_stub.go b/contrib/go/_std_1.23/src/net/file_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/file_stub.go rename to contrib/go/_std_1.23/src/net/file_stub.go diff --git a/contrib/go/_std_1.22/src/net/file_unix.go b/contrib/go/_std_1.23/src/net/file_unix.go similarity index 95% rename from contrib/go/_std_1.22/src/net/file_unix.go rename to contrib/go/_std_1.23/src/net/file_unix.go index 8b9fc38916f7..c0212cef65db 100644 --- a/contrib/go/_std_1.22/src/net/file_unix.go +++ b/contrib/go/_std_1.23/src/net/file_unix.go @@ -74,7 +74,7 @@ func fileConn(f *os.File) (Conn, error) { } switch fd.laddr.(type) { case *TCPAddr: - return newTCPConn(fd, defaultTCPKeepAlive, testHookSetKeepAlive), nil + return newTCPConn(fd, defaultTCPKeepAliveIdle, KeepAliveConfig{}, testPreHookSetKeepAlive, testHookSetKeepAlive), nil case *UDPAddr: return newUDPConn(fd), nil case *IPAddr: diff --git a/contrib/go/_std_1.22/src/net/file_wasip1.go b/contrib/go/_std_1.23/src/net/file_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/net/file_wasip1.go rename to contrib/go/_std_1.23/src/net/file_wasip1.go diff --git a/contrib/go/_std_1.22/src/net/file_windows.go b/contrib/go/_std_1.23/src/net/file_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/file_windows.go rename to contrib/go/_std_1.23/src/net/file_windows.go diff --git a/contrib/go/_std_1.22/src/net/hook.go b/contrib/go/_std_1.23/src/net/hook.go similarity index 89% rename from contrib/go/_std_1.22/src/net/hook.go rename to contrib/go/_std_1.23/src/net/hook.go index eded34d48abe..08d1aa893481 100644 --- a/contrib/go/_std_1.22/src/net/hook.go +++ b/contrib/go/_std_1.23/src/net/hook.go @@ -6,7 +6,6 @@ package net import ( "context" - "time" ) var ( @@ -21,7 +20,8 @@ var ( ) ([]IPAddr, error) { return fn(ctx, network, host) } - testHookSetKeepAlive = func(time.Duration) {} + testPreHookSetKeepAlive = func(*netFD) {} + testHookSetKeepAlive = func(KeepAliveConfig) {} // testHookStepTime sleeps until time has moved forward by a nonzero amount. // This helps to avoid flakes in timeout tests by ensuring that an implausibly diff --git a/contrib/go/_std_1.22/src/net/hook_plan9.go b/contrib/go/_std_1.23/src/net/hook_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/hook_plan9.go rename to contrib/go/_std_1.23/src/net/hook_plan9.go diff --git a/contrib/go/_std_1.22/src/net/hook_unix.go b/contrib/go/_std_1.23/src/net/hook_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/hook_unix.go rename to contrib/go/_std_1.23/src/net/hook_unix.go diff --git a/contrib/go/_std_1.22/src/net/hook_windows.go b/contrib/go/_std_1.23/src/net/hook_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/hook_windows.go rename to contrib/go/_std_1.23/src/net/hook_windows.go diff --git a/contrib/go/_std_1.22/src/net/hosts.go b/contrib/go/_std_1.23/src/net/hosts.go similarity index 100% rename from contrib/go/_std_1.22/src/net/hosts.go rename to contrib/go/_std_1.23/src/net/hosts.go diff --git a/contrib/go/_std_1.22/src/net/http/cgi/cgi_main.go b/contrib/go/_std_1.23/src/net/http/cgi/cgi_main.go similarity index 98% rename from contrib/go/_std_1.22/src/net/http/cgi/cgi_main.go rename to contrib/go/_std_1.23/src/net/http/cgi/cgi_main.go index 8997d66a117d..033036d07fb1 100644 --- a/contrib/go/_std_1.22/src/net/http/cgi/cgi_main.go +++ b/contrib/go/_std_1.23/src/net/http/cgi/cgi_main.go @@ -10,7 +10,7 @@ import ( "net/http" "os" "path" - "sort" + "slices" "strings" "time" ) @@ -67,7 +67,7 @@ func testCGI() { for k := range params { keys = append(keys, k) } - sort.Strings(keys) + slices.Sort(keys) for _, key := range keys { fmt.Printf("param-%s=%s\r\n", key, params.Get(key)) } @@ -77,7 +77,7 @@ func testCGI() { for k := range envs { keys = append(keys, k) } - sort.Strings(keys) + slices.Sort(keys) for _, key := range keys { fmt.Printf("env-%s=%s\r\n", key, envs[key]) } diff --git a/contrib/go/_std_1.22/src/net/http/cgi/child.go b/contrib/go/_std_1.23/src/net/http/cgi/child.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/cgi/child.go rename to contrib/go/_std_1.23/src/net/http/cgi/child.go diff --git a/contrib/go/_std_1.22/src/net/http/cgi/host.go b/contrib/go/_std_1.23/src/net/http/cgi/host.go similarity index 99% rename from contrib/go/_std_1.22/src/net/http/cgi/host.go rename to contrib/go/_std_1.23/src/net/http/cgi/host.go index ef222ab73a75..c03fabb80772 100644 --- a/contrib/go/_std_1.22/src/net/http/cgi/host.go +++ b/contrib/go/_std_1.23/src/net/http/cgi/host.go @@ -277,7 +277,7 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { headerLines++ header, val, ok := strings.Cut(string(line), ":") if !ok { - h.printf("cgi: bogus header line: %s", string(line)) + h.printf("cgi: bogus header line: %s", line) continue } if !httpguts.ValidHeaderFieldName(header) { diff --git a/contrib/go/_std_1.22/src/net/http/cgi/ya.make b/contrib/go/_std_1.23/src/net/http/cgi/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/cgi/ya.make rename to contrib/go/_std_1.23/src/net/http/cgi/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/client.go b/contrib/go/_std_1.23/src/net/http/client.go similarity index 95% rename from contrib/go/_std_1.22/src/net/http/client.go rename to contrib/go/_std_1.23/src/net/http/client.go index 8fc348fe5d36..f8892c2bc2ea 100644 --- a/contrib/go/_std_1.22/src/net/http/client.go +++ b/contrib/go/_std_1.23/src/net/http/client.go @@ -20,7 +20,7 @@ import ( "net/http/internal/ascii" "net/url" "reflect" - "sort" + "slices" "strings" "sync" "sync/atomic" @@ -603,6 +603,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { Err: errors.New("http: nil Request.URL"), } } + _ = *c // panic early if c is nil; see go.dev/issue/53521 var ( deadline = c.deadline() @@ -612,8 +613,9 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { reqBodyClosed = false // have we closed the current req.Body? // Redirect behavior: - redirectMethod string - includeBody bool + redirectMethod string + includeBody = true + stripSensitiveHeaders = false ) uerr := func(err error) error { // the body may have been closed already by c.send() @@ -680,7 +682,12 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { // in case the user set Referer on their first request. // If they really want to override, they can do it in // their CheckRedirect func. - copyHeaders(req) + if !stripSensitiveHeaders && reqs[0].URL.Host != req.URL.Host { + if !shouldCopyHeaderOnRedirect(reqs[0].URL, req.URL) { + stripSensitiveHeaders = true + } + } + copyHeaders(req, stripSensitiveHeaders) // Add the Referer header from the most recent // request URL to the new one, if it's not https->http: @@ -725,10 +732,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { // c.send() always closes req.Body reqBodyClosed = true if !deadline.IsZero() && didTimeout() { - err = &httpError{ - err: err.Error() + " (Client.Timeout exceeded while awaiting headers)", - timeout: true, - } + err = &timeoutError{err.Error() + " (Client.Timeout exceeded while awaiting headers)"} } return nil, uerr(err) } @@ -746,7 +750,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { // makeHeadersCopier makes a function that copies headers from the // initial Request, ireq. For every redirect, this function must be called // so that it can copy headers into the upcoming Request. -func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { +func (c *Client) makeHeadersCopier(ireq *Request) func(req *Request, stripSensitiveHeaders bool) { // The headers to copy are from the very initial request. // We use a closured callback to keep a reference to these original headers. var ( @@ -760,8 +764,7 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { } } - preq := ireq // The previous request - return func(req *Request) { + return func(req *Request, stripSensitiveHeaders bool) { // If Jar is present and there was some initial cookies provided // via the request header, then we may need to alter the initial // cookies as we follow redirects since each redirect may end up @@ -790,7 +793,7 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { ss = append(ss, c.Name+"="+c.Value) } } - sort.Strings(ss) // Ensure deterministic headers + slices.Sort(ss) // Ensure deterministic headers ireqhdr.Set("Cookie", strings.Join(ss, "; ")) } } @@ -798,12 +801,15 @@ func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { // Copy the initial request's Header values // (at least the safe ones). for k, vv := range ireqhdr { - if shouldCopyHeaderOnRedirect(k, preq.URL, req.URL) { + sensitive := false + switch CanonicalHeaderKey(k) { + case "Authorization", "Www-Authenticate", "Cookie", "Cookie2": + sensitive = true + } + if !(sensitive && stripSensitiveHeaders) { req.Header[k] = vv } } - - preq = req // Update previous Request with the current request } } @@ -968,10 +974,7 @@ func (b *cancelTimerBody) Read(p []byte) (n int, err error) { return n, err } if b.reqDidTimeout() { - err = &httpError{ - err: err.Error() + " (Client.Timeout or context cancellation while reading body)", - timeout: true, - } + err = &timeoutError{err.Error() + " (Client.Timeout or context cancellation while reading body)"} } return n, err } @@ -982,28 +985,23 @@ func (b *cancelTimerBody) Close() error { return err } -func shouldCopyHeaderOnRedirect(headerKey string, initial, dest *url.URL) bool { - switch CanonicalHeaderKey(headerKey) { - case "Authorization", "Www-Authenticate", "Cookie", "Cookie2": - // Permit sending auth/cookie headers from "foo.com" - // to "sub.foo.com". - - // Note that we don't send all cookies to subdomains - // automatically. This function is only used for - // Cookies set explicitly on the initial outgoing - // client request. Cookies automatically added via the - // CookieJar mechanism continue to follow each - // cookie's scope as set by Set-Cookie. But for - // outgoing requests with the Cookie header set - // directly, we don't know their scope, so we assume - // it's for *.domain.com. - - ihost := idnaASCIIFromURL(initial) - dhost := idnaASCIIFromURL(dest) - return isDomainOrSubdomain(dhost, ihost) - } - // All other headers are copied: - return true +func shouldCopyHeaderOnRedirect(initial, dest *url.URL) bool { + // Permit sending auth/cookie headers from "foo.com" + // to "sub.foo.com". + + // Note that we don't send all cookies to subdomains + // automatically. This function is only used for + // Cookies set explicitly on the initial outgoing + // client request. Cookies automatically added via the + // CookieJar mechanism continue to follow each + // cookie's scope as set by Set-Cookie. But for + // outgoing requests with the Cookie header set + // directly, we don't know their scope, so we assume + // it's for *.domain.com. + + ihost := idnaASCIIFromURL(initial) + dhost := idnaASCIIFromURL(dest) + return isDomainOrSubdomain(dhost, ihost) } // isDomainOrSubdomain reports whether sub is a subdomain (or exact diff --git a/contrib/go/_std_1.22/src/net/http/clone.go b/contrib/go/_std_1.23/src/net/http/clone.go similarity index 51% rename from contrib/go/_std_1.22/src/net/http/clone.go rename to contrib/go/_std_1.23/src/net/http/clone.go index 3a3375bff716..71f424227313 100644 --- a/contrib/go/_std_1.22/src/net/http/clone.go +++ b/contrib/go/_std_1.23/src/net/http/clone.go @@ -8,8 +8,18 @@ import ( "mime/multipart" "net/textproto" "net/url" + _ "unsafe" // for linkname ) +// cloneURLValues should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/searKing/golang +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cloneURLValues func cloneURLValues(v url.Values) url.Values { if v == nil { return nil @@ -19,6 +29,15 @@ func cloneURLValues(v url.Values) url.Values { return url.Values(Header(v).Clone()) } +// cloneURL should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/searKing/golang +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cloneURL func cloneURL(u *url.URL) *url.URL { if u == nil { return nil @@ -32,6 +51,15 @@ func cloneURL(u *url.URL) *url.URL { return u2 } +// cloneMultipartForm should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/searKing/golang +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cloneMultipartForm func cloneMultipartForm(f *multipart.Form) *multipart.Form { if f == nil { return nil @@ -53,6 +81,15 @@ func cloneMultipartForm(f *multipart.Form) *multipart.Form { return f2 } +// cloneMultipartFileHeader should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/searKing/golang +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cloneMultipartFileHeader func cloneMultipartFileHeader(fh *multipart.FileHeader) *multipart.FileHeader { if fh == nil { return nil @@ -65,6 +102,16 @@ func cloneMultipartFileHeader(fh *multipart.FileHeader) *multipart.FileHeader { // cloneOrMakeHeader invokes Header.Clone but if the // result is nil, it'll instead make and return a non-nil Header. +// +// cloneOrMakeHeader should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/searKing/golang +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cloneOrMakeHeader func cloneOrMakeHeader(hdr Header) Header { clone := hdr.Clone() if clone == nil { diff --git a/contrib/go/_std_1.22/src/net/http/cookie.go b/contrib/go/_std_1.23/src/net/http/cookie.go similarity index 66% rename from contrib/go/_std_1.22/src/net/http/cookie.go rename to contrib/go/_std_1.23/src/net/http/cookie.go index c22897f3f99e..3483e1638190 100644 --- a/contrib/go/_std_1.22/src/net/http/cookie.go +++ b/contrib/go/_std_1.23/src/net/http/cookie.go @@ -21,8 +21,9 @@ import ( // // See https://tools.ietf.org/html/rfc6265 for details. type Cookie struct { - Name string - Value string + Name string + Value string + Quoted bool // indicates whether the Value was originally quoted Path string // optional Domain string // optional @@ -32,12 +33,13 @@ type Cookie struct { // MaxAge=0 means no 'Max-Age' attribute specified. // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' // MaxAge>0 means Max-Age attribute present and given in seconds - MaxAge int - Secure bool - HttpOnly bool - SameSite SameSite - Raw string - Unparsed []string // Raw text of unparsed attribute-value pairs + MaxAge int + Secure bool + HttpOnly bool + SameSite SameSite + Partitioned bool + Raw string + Unparsed []string // Raw text of unparsed attribute-value pairs } // SameSite allows a server to define a cookie attribute making it impossible for @@ -55,110 +57,156 @@ const ( SameSiteNoneMode ) -// readSetCookies parses all "Set-Cookie" values from -// the header h and returns the successfully parsed Cookies. -func readSetCookies(h Header) []*Cookie { - cookieCount := len(h["Set-Cookie"]) - if cookieCount == 0 { - return []*Cookie{} - } - cookies := make([]*Cookie, 0, cookieCount) - for _, line := range h["Set-Cookie"] { - parts := strings.Split(textproto.TrimString(line), ";") - if len(parts) == 1 && parts[0] == "" { - continue +var ( + errBlankCookie = errors.New("http: blank cookie") + errEqualNotFoundInCookie = errors.New("http: '=' not found in cookie") + errInvalidCookieName = errors.New("http: invalid cookie name") + errInvalidCookieValue = errors.New("http: invalid cookie value") +) + +// ParseCookie parses a Cookie header value and returns all the cookies +// which were set in it. Since the same cookie name can appear multiple times +// the returned Values can contain more than one value for a given key. +func ParseCookie(line string) ([]*Cookie, error) { + parts := strings.Split(textproto.TrimString(line), ";") + if len(parts) == 1 && parts[0] == "" { + return nil, errBlankCookie + } + cookies := make([]*Cookie, 0, len(parts)) + for _, s := range parts { + s = textproto.TrimString(s) + name, value, found := strings.Cut(s, "=") + if !found { + return nil, errEqualNotFoundInCookie } - parts[0] = textproto.TrimString(parts[0]) - name, value, ok := strings.Cut(parts[0], "=") - if !ok { + if !isCookieNameValid(name) { + return nil, errInvalidCookieName + } + value, quoted, found := parseCookieValue(value, true) + if !found { + return nil, errInvalidCookieValue + } + cookies = append(cookies, &Cookie{Name: name, Value: value, Quoted: quoted}) + } + return cookies, nil +} + +// ParseSetCookie parses a Set-Cookie header value and returns a cookie. +// It returns an error on syntax error. +func ParseSetCookie(line string) (*Cookie, error) { + parts := strings.Split(textproto.TrimString(line), ";") + if len(parts) == 1 && parts[0] == "" { + return nil, errBlankCookie + } + parts[0] = textproto.TrimString(parts[0]) + name, value, ok := strings.Cut(parts[0], "=") + if !ok { + return nil, errEqualNotFoundInCookie + } + name = textproto.TrimString(name) + if !isCookieNameValid(name) { + return nil, errInvalidCookieName + } + value, quoted, ok := parseCookieValue(value, true) + if !ok { + return nil, errInvalidCookieValue + } + c := &Cookie{ + Name: name, + Value: value, + Quoted: quoted, + Raw: line, + } + for i := 1; i < len(parts); i++ { + parts[i] = textproto.TrimString(parts[i]) + if len(parts[i]) == 0 { continue } - name = textproto.TrimString(name) - if !isCookieNameValid(name) { + + attr, val, _ := strings.Cut(parts[i], "=") + lowerAttr, isASCII := ascii.ToLower(attr) + if !isASCII { continue } - value, ok = parseCookieValue(value, true) + val, _, ok = parseCookieValue(val, false) if !ok { + c.Unparsed = append(c.Unparsed, parts[i]) continue } - c := &Cookie{ - Name: name, - Value: value, - Raw: line, - } - for i := 1; i < len(parts); i++ { - parts[i] = textproto.TrimString(parts[i]) - if len(parts[i]) == 0 { - continue - } - attr, val, _ := strings.Cut(parts[i], "=") - lowerAttr, isASCII := ascii.ToLower(attr) - if !isASCII { + switch lowerAttr { + case "samesite": + lowerVal, ascii := ascii.ToLower(val) + if !ascii { + c.SameSite = SameSiteDefaultMode continue } - val, ok = parseCookieValue(val, false) - if !ok { - c.Unparsed = append(c.Unparsed, parts[i]) - continue + switch lowerVal { + case "lax": + c.SameSite = SameSiteLaxMode + case "strict": + c.SameSite = SameSiteStrictMode + case "none": + c.SameSite = SameSiteNoneMode + default: + c.SameSite = SameSiteDefaultMode } - - switch lowerAttr { - case "samesite": - lowerVal, ascii := ascii.ToLower(val) - if !ascii { - c.SameSite = SameSiteDefaultMode - continue - } - switch lowerVal { - case "lax": - c.SameSite = SameSiteLaxMode - case "strict": - c.SameSite = SameSiteStrictMode - case "none": - c.SameSite = SameSiteNoneMode - default: - c.SameSite = SameSiteDefaultMode - } - continue - case "secure": - c.Secure = true - continue - case "httponly": - c.HttpOnly = true - continue - case "domain": - c.Domain = val - continue - case "max-age": - secs, err := strconv.Atoi(val) - if err != nil || secs != 0 && val[0] == '0' { - break - } - if secs <= 0 { - secs = -1 - } - c.MaxAge = secs - continue - case "expires": - c.RawExpires = val - exptime, err := time.Parse(time.RFC1123, val) + continue + case "secure": + c.Secure = true + continue + case "httponly": + c.HttpOnly = true + continue + case "domain": + c.Domain = val + continue + case "max-age": + secs, err := strconv.Atoi(val) + if err != nil || secs != 0 && val[0] == '0' { + break + } + if secs <= 0 { + secs = -1 + } + c.MaxAge = secs + continue + case "expires": + c.RawExpires = val + exptime, err := time.Parse(time.RFC1123, val) + if err != nil { + exptime, err = time.Parse("Mon, 02-Jan-2006 15:04:05 MST", val) if err != nil { - exptime, err = time.Parse("Mon, 02-Jan-2006 15:04:05 MST", val) - if err != nil { - c.Expires = time.Time{} - break - } + c.Expires = time.Time{} + break } - c.Expires = exptime.UTC() - continue - case "path": - c.Path = val - continue } - c.Unparsed = append(c.Unparsed, parts[i]) + c.Expires = exptime.UTC() + continue + case "path": + c.Path = val + continue + case "partitioned": + c.Partitioned = true + continue + } + c.Unparsed = append(c.Unparsed, parts[i]) + } + return c, nil +} + +// readSetCookies parses all "Set-Cookie" values from +// the header h and returns the successfully parsed Cookies. +func readSetCookies(h Header) []*Cookie { + cookieCount := len(h["Set-Cookie"]) + if cookieCount == 0 { + return []*Cookie{} + } + cookies := make([]*Cookie, 0, cookieCount) + for _, line := range h["Set-Cookie"] { + if cookie, err := ParseSetCookie(line); err == nil { + cookies = append(cookies, cookie) } - cookies = append(cookies, c) } return cookies } @@ -187,7 +235,7 @@ func (c *Cookie) String() string { b.Grow(len(c.Name) + len(c.Value) + len(c.Domain) + len(c.Path) + extraCookieLength) b.WriteString(c.Name) b.WriteRune('=') - b.WriteString(sanitizeCookieValue(c.Value)) + b.WriteString(sanitizeCookieValue(c.Value, c.Quoted)) if len(c.Path) > 0 { b.WriteString("; Path=") @@ -236,6 +284,9 @@ func (c *Cookie) String() string { case SameSiteStrictMode: b.WriteString("; SameSite=Strict") } + if c.Partitioned { + b.WriteString("; Partitioned") + } return b.String() } @@ -267,6 +318,11 @@ func (c *Cookie) Valid() error { return errors.New("http: invalid Cookie.Domain") } } + if c.Partitioned { + if !c.Secure { + return errors.New("http: partitioned cookies must be set with Secure") + } + } return nil } @@ -299,11 +355,11 @@ func readCookies(h Header, filter string) []*Cookie { if filter != "" && filter != name { continue } - val, ok := parseCookieValue(val, true) + val, quoted, ok := parseCookieValue(val, true) if !ok { continue } - cookies = append(cookies, &Cookie{Name: name, Value: val}) + cookies = append(cookies, &Cookie{Name: name, Value: val, Quoted: quoted}) } } return cookies @@ -388,6 +444,8 @@ func sanitizeCookieName(n string) string { } // sanitizeCookieValue produces a suitable cookie-value from v. +// It receives a quoted bool indicating whether the value was originally +// quoted. // https://tools.ietf.org/html/rfc6265#section-4.1.1 // // cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) @@ -397,15 +455,14 @@ func sanitizeCookieName(n string) string { // ; and backslash // // We loosen this as spaces and commas are common in cookie values -// but we produce a quoted cookie-value if and only if v contains -// commas or spaces. +// thus we produce a quoted cookie-value if v contains commas or spaces. // See https://golang.org/issue/7243 for the discussion. -func sanitizeCookieValue(v string) string { +func sanitizeCookieValue(v string, quoted bool) string { v = sanitizeOrWarn("Cookie.Value", validCookieValueByte, v) if len(v) == 0 { return v } - if strings.ContainsAny(v, " ,") { + if strings.ContainsAny(v, " ,") || quoted { return `"` + v + `"` } return v @@ -447,17 +504,27 @@ func sanitizeOrWarn(fieldName string, valid func(byte) bool, v string) string { return string(buf) } -func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) { +// parseCookieValue parses a cookie value according to RFC 6265. +// If allowDoubleQuote is true, parseCookieValue will consider that it +// is parsing the cookie-value; +// otherwise, it will consider that it is parsing a cookie-av value +// (cookie attribute-value). +// +// It returns the parsed cookie value, a boolean indicating whether the +// parsing was successful, and a boolean indicating whether the parsed +// value was enclosed in double quotes. +func parseCookieValue(raw string, allowDoubleQuote bool) (value string, quoted, ok bool) { // Strip the quotes, if present. if allowDoubleQuote && len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' { raw = raw[1 : len(raw)-1] + quoted = true } for i := 0; i < len(raw); i++ { if !validCookieValueByte(raw[i]) { - return "", false + return "", quoted, false } } - return raw, true + return raw, quoted, true } func isCookieNameValid(raw string) bool { diff --git a/contrib/go/_std_1.22/src/net/http/cookiejar/jar.go b/contrib/go/_std_1.23/src/net/http/cookiejar/jar.go similarity index 97% rename from contrib/go/_std_1.22/src/net/http/cookiejar/jar.go rename to contrib/go/_std_1.23/src/net/http/cookiejar/jar.go index e7f5ddd4d009..2eec1a3e745b 100644 --- a/contrib/go/_std_1.22/src/net/http/cookiejar/jar.go +++ b/contrib/go/_std_1.23/src/net/http/cookiejar/jar.go @@ -6,13 +6,14 @@ package cookiejar import ( + "cmp" "errors" "fmt" "net" "net/http" "net/http/internal/ascii" "net/url" - "sort" + "slices" "strings" "sync" "time" @@ -92,6 +93,7 @@ func New(o *Options) (*Jar, error) { type entry struct { Name string Value string + Quoted bool Domain string Path string SameSite string @@ -209,18 +211,17 @@ func (j *Jar) cookies(u *url.URL, now time.Time) (cookies []*http.Cookie) { // sort according to RFC 6265 section 5.4 point 2: by longest // path and then by earliest creation time. - sort.Slice(selected, func(i, j int) bool { - s := selected - if len(s[i].Path) != len(s[j].Path) { - return len(s[i].Path) > len(s[j].Path) + slices.SortFunc(selected, func(a, b entry) int { + if r := cmp.Compare(b.Path, a.Path); r != 0 { + return r } - if ret := s[i].Creation.Compare(s[j].Creation); ret != 0 { - return ret < 0 + if r := a.Creation.Compare(b.Creation); r != 0 { + return r } - return s[i].seqNum < s[j].seqNum + return cmp.Compare(a.seqNum, b.seqNum) }) for _, e := range selected { - cookies = append(cookies, &http.Cookie{Name: e.Name, Value: e.Value}) + cookies = append(cookies, &http.Cookie{Name: e.Name, Value: e.Value, Quoted: e.Quoted}) } return cookies @@ -366,7 +367,7 @@ func isIP(host string) bool { // Probable IPv6 address. // Hostnames can't contain : or %, so this is definitely not a valid host. // Treating it as an IP is the more conservative option, and avoids the risk - // of interpeting ::1%.www.example.com as a subtomain of www.example.com. + // of interpreting ::1%.www.example.com as a subdomain of www.example.com. return true } return net.ParseIP(host) != nil @@ -429,6 +430,7 @@ func (j *Jar) newEntry(c *http.Cookie, now time.Time, defPath, host string) (e e } e.Value = c.Value + e.Quoted = c.Quoted e.Secure = c.Secure e.HttpOnly = c.HttpOnly diff --git a/contrib/go/_std_1.22/src/net/http/cookiejar/punycode.go b/contrib/go/_std_1.23/src/net/http/cookiejar/punycode.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/cookiejar/punycode.go rename to contrib/go/_std_1.23/src/net/http/cookiejar/punycode.go diff --git a/contrib/go/_std_1.22/src/net/http/cookiejar/ya.make b/contrib/go/_std_1.23/src/net/http/cookiejar/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/cookiejar/ya.make rename to contrib/go/_std_1.23/src/net/http/cookiejar/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/doc.go b/contrib/go/_std_1.23/src/net/http/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/doc.go rename to contrib/go/_std_1.23/src/net/http/doc.go diff --git a/contrib/go/_std_1.22/src/net/http/fcgi/child.go b/contrib/go/_std_1.23/src/net/http/fcgi/child.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/fcgi/child.go rename to contrib/go/_std_1.23/src/net/http/fcgi/child.go diff --git a/contrib/go/_std_1.22/src/net/http/fcgi/fcgi.go b/contrib/go/_std_1.23/src/net/http/fcgi/fcgi.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/fcgi/fcgi.go rename to contrib/go/_std_1.23/src/net/http/fcgi/fcgi.go diff --git a/contrib/go/_std_1.22/src/net/http/fcgi/ya.make b/contrib/go/_std_1.23/src/net/http/fcgi/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/fcgi/ya.make rename to contrib/go/_std_1.23/src/net/http/fcgi/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/filetransport.go b/contrib/go/_std_1.23/src/net/http/filetransport.go similarity index 98% rename from contrib/go/_std_1.22/src/net/http/filetransport.go rename to contrib/go/_std_1.23/src/net/http/filetransport.go index 7384b22fbe92..b08bae63487d 100644 --- a/contrib/go/_std_1.22/src/net/http/filetransport.go +++ b/contrib/go/_std_1.23/src/net/http/filetransport.go @@ -35,7 +35,7 @@ func NewFileTransport(fs FileSystem) RoundTripper { // NewFileTransportFS returns a new [RoundTripper], serving the provided // file system fsys. The returned RoundTripper ignores the URL host in its // incoming requests, as well as most other properties of the -// request. +// request. The files provided by fsys must implement [io.Seeker]. // // The typical use case for NewFileTransportFS is to register the "file" // protocol with a [Transport], as in: diff --git a/contrib/go/_std_1.22/src/net/http/fs.go b/contrib/go/_std_1.23/src/net/http/fs.go similarity index 90% rename from contrib/go/_std_1.22/src/net/http/fs.go rename to contrib/go/_std_1.23/src/net/http/fs.go index af7511a7a4bd..3a716fbd2cc7 100644 --- a/contrib/go/_std_1.22/src/net/http/fs.go +++ b/contrib/go/_std_1.23/src/net/http/fs.go @@ -9,7 +9,7 @@ package http import ( "errors" "fmt" - "internal/safefilepath" + "internal/godebug" "io" "io/fs" "mime" @@ -29,7 +29,7 @@ import ( // specific directory tree. // // While the [FileSystem.Open] method takes '/'-separated paths, a Dir's string -// value is a filename on the native file system, not a URL, so it is separated +// value is a directory path on the native file system, not a URL, so it is separated // by [filepath.Separator], which isn't necessarily '/'. // // Note that Dir could expose sensitive files and directories. Dir will follow @@ -70,7 +70,11 @@ func mapOpenError(originalErr error, name string, sep rune, stat func(string) (f // Open implements [FileSystem] using [os.Open], opening files for reading rooted // and relative to the directory d. func (d Dir) Open(name string) (File, error) { - path, err := safefilepath.FromFS(path.Clean("/" + name)) + path := path.Clean("/" + name)[1:] + if path == "" { + path = "." + } + path, err := filepath.Localize(path) if err != nil { return nil, errors.New("http: invalid or unsafe file path") } @@ -151,6 +155,8 @@ func dirList(w ResponseWriter, r *Request, f File) { sort.Slice(dirs, func(i, j int) bool { return dirs.name(i) < dirs.name(j) }) w.Header().Set("Content-Type", "text/html; charset=utf-8") + fmt.Fprintf(w, "\n") + fmt.Fprintf(w, "\n") fmt.Fprintf(w, "
\n")
 	for i, n := 0, dirs.len(); i < n; i++ {
 		name := dirs.name(i)
@@ -166,6 +172,40 @@ func dirList(w ResponseWriter, r *Request, f File) {
 	fmt.Fprintf(w, "
\n") } +// GODEBUG=httpservecontentkeepheaders=1 restores the pre-1.23 behavior of not deleting +// Cache-Control, Content-Encoding, Etag, or Last-Modified headers on ServeContent errors. +var httpservecontentkeepheaders = godebug.New("httpservecontentkeepheaders") + +// serveError serves an error from ServeFile, ServeFileFS, and ServeContent. +// Because those can all be configured by the caller by setting headers like +// Etag, Last-Modified, and Cache-Control to send on a successful response, +// the error path needs to clear them, since they may not be meant for errors. +func serveError(w ResponseWriter, text string, code int) { + h := w.Header() + + nonDefault := false + for _, k := range []string{ + "Cache-Control", + "Content-Encoding", + "Etag", + "Last-Modified", + } { + if !h.has(k) { + continue + } + if httpservecontentkeepheaders.Value() == "1" { + nonDefault = true + } else { + h.Del(k) + } + } + if nonDefault { + httpservecontentkeepheaders.IncNonDefault() + } + + Error(w, text, code) +} + // ServeContent replies to the request using the content in the // provided ReadSeeker. The main benefit of ServeContent over [io.Copy] // is that it handles Range requests properly, sets the MIME type, and @@ -186,11 +226,17 @@ func dirList(w ResponseWriter, r *Request, f File) { // // The content's Seek method must work: ServeContent uses // a seek to the end of the content to determine its size. +// Note that [*os.File] implements the [io.ReadSeeker] interface. // // If the caller has set w's ETag header formatted per RFC 7232, section 2.3, // ServeContent uses it to handle requests using If-Match, If-None-Match, or If-Range. // -// Note that [*os.File] implements the [io.ReadSeeker] interface. +// If an error occurs when serving the request (for example, when +// handling an invalid range request), ServeContent responds with an +// error message. By default, ServeContent strips the Cache-Control, +// Content-Encoding, ETag, and Last-Modified headers from error responses. +// The GODEBUG setting httpservecontentkeepheaders=1 causes ServeContent +// to preserve these headers. func ServeContent(w ResponseWriter, req *Request, name string, modtime time.Time, content io.ReadSeeker) { sizeFunc := func() (int64, error) { size, err := content.Seek(0, io.SeekEnd) @@ -242,7 +288,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, ctype = DetectContentType(buf[:n]) _, err := content.Seek(0, io.SeekStart) // rewind to output whole file if err != nil { - Error(w, "seeker can't seek", StatusInternalServerError) + serveError(w, "seeker can't seek", StatusInternalServerError) return } } @@ -253,12 +299,12 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, size, err := sizeFunc() if err != nil { - Error(w, err.Error(), StatusInternalServerError) + serveError(w, err.Error(), StatusInternalServerError) return } if size < 0 { // Should never happen but just to be sure - Error(w, "negative content size computed", StatusInternalServerError) + serveError(w, "negative content size computed", StatusInternalServerError) return } @@ -280,7 +326,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", size)) fallthrough default: - Error(w, err.Error(), StatusRequestedRangeNotSatisfiable) + serveError(w, err.Error(), StatusRequestedRangeNotSatisfiable) return } @@ -306,7 +352,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, // multipart responses." ra := ranges[0] if _, err := content.Seek(ra.start, io.SeekStart); err != nil { - Error(w, err.Error(), StatusRequestedRangeNotSatisfiable) + serveError(w, err.Error(), StatusRequestedRangeNotSatisfiable) return } sendSize = ra.length @@ -639,7 +685,7 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec f, err := fs.Open(name) if err != nil { msg, code := toHTTPError(err) - Error(w, msg, code) + serveError(w, msg, code) return } defer f.Close() @@ -647,7 +693,7 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec d, err := f.Stat() if err != nil { msg, code := toHTTPError(err) - Error(w, msg, code) + serveError(w, msg, code) return } @@ -660,11 +706,16 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec localRedirect(w, r, path.Base(url)+"/") return } - } else { - if url[len(url)-1] == '/' { - localRedirect(w, r, "../"+path.Base(url)) + } else if url[len(url)-1] == '/' { + base := path.Base(url) + if base == "/" || base == "." { + // The FileSystem maps a path like "/" or "/./" to a file instead of a directory. + msg := "http: attempting to traverse a non-directory" + serveError(w, msg, StatusInternalServerError) return } + localRedirect(w, r, "../"+base) + return } } @@ -737,7 +788,7 @@ func localRedirect(w ResponseWriter, r *Request, newPath string) { // If the provided file or directory name is a relative path, it is // interpreted relative to the current directory and may ascend to // parent directories. If the provided name is constructed from user -// input, it should be sanitized before calling ServeFile. +// input, it should be sanitized before calling [ServeFile]. // // As a precaution, ServeFile will reject requests where r.URL.Path // contains a ".." path element; this protects against callers who @@ -759,7 +810,7 @@ func ServeFile(w ResponseWriter, r *Request, name string) { // here and ".." may not be wanted. // Note that name might not contain "..", for example if code (still // incorrectly) used filepath.Join(myDir, r.URL.Path). - Error(w, "invalid URL path", StatusBadRequest) + serveError(w, "invalid URL path", StatusBadRequest) return } dir, file := filepath.Split(name) @@ -768,23 +819,22 @@ func ServeFile(w ResponseWriter, r *Request, name string) { // ServeFileFS replies to the request with the contents // of the named file or directory from the file system fsys. +// The files provided by fsys must implement [io.Seeker]. // -// If the provided file or directory name is a relative path, it is -// interpreted relative to the current directory and may ascend to -// parent directories. If the provided name is constructed from user -// input, it should be sanitized before calling [ServeFile]. +// If the provided name is constructed from user input, it should be +// sanitized before calling [ServeFileFS]. // -// As a precaution, ServeFile will reject requests where r.URL.Path +// As a precaution, ServeFileFS will reject requests where r.URL.Path // contains a ".." path element; this protects against callers who // might unsafely use [filepath.Join] on r.URL.Path without sanitizing // it and then use that filepath.Join result as the name argument. // -// As another special case, ServeFile redirects any request where r.URL.Path +// As another special case, ServeFileFS redirects any request where r.URL.Path // ends in "/index.html" to the same path, without the final // "index.html". To avoid such redirects either modify the path or -// use ServeContent. +// use [ServeContent]. // -// Outside of those two special cases, ServeFile does not use +// Outside of those two special cases, ServeFileFS does not use // r.URL.Path for selecting the file or directory to serve; only the // file or directory provided in the name argument is used. func ServeFileFS(w ResponseWriter, r *Request, fsys fs.FS, name string) { @@ -794,7 +844,7 @@ func ServeFileFS(w ResponseWriter, r *Request, fsys fs.FS, name string) { // here and ".." may not be wanted. // Note that name might not contain "..", for example if code (still // incorrectly) used filepath.Join(myDir, r.URL.Path). - Error(w, "invalid URL path", StatusBadRequest) + serveError(w, "invalid URL path", StatusBadRequest) return } serveFile(w, r, FS(fsys), name, false) @@ -916,6 +966,7 @@ func FileServer(root FileSystem) Handler { // FileServerFS returns a handler that serves HTTP requests // with the contents of the file system fsys. +// The files provided by fsys must implement [io.Seeker]. // // As a special case, the returned file server redirects any request // ending in "/index.html" to the same path, without the final diff --git a/contrib/go/_std_1.22/src/net/http/h2_bundle.go b/contrib/go/_std_1.23/src/net/http/h2_bundle.go similarity index 97% rename from contrib/go/_std_1.22/src/net/http/h2_bundle.go rename to contrib/go/_std_1.23/src/net/http/h2_bundle.go index c1a2e76ea4d3..0b305844ae2c 100644 --- a/contrib/go/_std_1.22/src/net/http/h2_bundle.go +++ b/contrib/go/_std_1.23/src/net/http/h2_bundle.go @@ -15,6 +15,10 @@ // // See https://http2.golang.org/ for a test server running this code. // +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// package http @@ -2917,13 +2921,12 @@ func (mh *http2MetaHeadersFrame) checkPseudos() error { } func (fr *http2Framer) maxHeaderStringLen() int { - v := fr.maxHeaderListSize() - if uint32(int(v)) == v { - return int(v) + v := int(fr.maxHeaderListSize()) + if v < 0 { + // If maxHeaderListSize overflows an int, use no limit (0). + return 0 } - // They had a crazy big number for MaxHeaderBytes anyway, - // so give them unlimited header lengths: - return 0 + return v } // readMetaFrame returns 0 or more CONTINUATION frames from fr and @@ -3522,13 +3525,6 @@ type http2stringWriter interface { WriteString(s string) (n int, err error) } -// A gate lets two goroutines coordinate their activities. -type http2gate chan struct{} - -func (g http2gate) Done() { g <- struct{}{} } - -func (g http2gate) Wait() { <-g } - // A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed). type http2closeWaiter chan struct{} @@ -3701,6 +3697,17 @@ func http2validPseudoPath(v string) bool { // any size (as long as it's first). type http2incomparable [0]func() +// synctestGroupInterface is the methods of synctestGroup used by Server and Transport. +// It's defined as an interface here to let us keep synctestGroup entirely test-only +// and not a part of non-test builds. +type http2synctestGroupInterface interface { + Join() + Now() time.Time + NewTimer(d time.Duration) http2timer + AfterFunc(d time.Duration, f func()) http2timer + ContextWithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) +} + // pipe is a goroutine-safe io.Reader/io.Writer pair. It's like // io.Pipe except there are no PipeReader/PipeWriter halves, and the // underlying buffer is an interface. (io.Pipe is always unbuffered) @@ -3768,7 +3775,10 @@ func (p *http2pipe) Read(d []byte) (n int, err error) { } } -var http2errClosedPipeWrite = errors.New("write on closed buffer") +var ( + http2errClosedPipeWrite = errors.New("write on closed buffer") + http2errUninitializedPipeWrite = errors.New("write on uninitialized buffer") +) // Write copies bytes from p into the buffer and wakes a reader. // It is an error to write more data than the buffer can hold. @@ -3782,6 +3792,12 @@ func (p *http2pipe) Write(d []byte) (n int, err error) { if p.err != nil || p.breakErr != nil { return 0, http2errClosedPipeWrite } + // pipe.setBuffer is never invoked, leaving the buffer uninitialized. + // We shouldn't try to write to an uninitialized pipe, + // but returning an error is better than panicking. + if p.b == nil { + return 0, http2errUninitializedPipeWrite + } return p.b.Write(d) } @@ -3938,6 +3954,7 @@ type http2Server struct { // IdleTimeout specifies how long until idle clients should be // closed with a GOAWAY frame. PING frames are not considered // activity for the purposes of IdleTimeout. + // If zero or negative, there is no timeout. IdleTimeout time.Duration // MaxUploadBufferPerConnection is the size of the initial flow @@ -3967,6 +3984,39 @@ type http2Server struct { // so that we don't embed a Mutex in this struct, which will make the // struct non-copyable, which might break some callers. state *http2serverInternalState + + // Synchronization group used for testing. + // Outside of tests, this is nil. + group http2synctestGroupInterface +} + +func (s *http2Server) markNewGoroutine() { + if s.group != nil { + s.group.Join() + } +} + +func (s *http2Server) now() time.Time { + if s.group != nil { + return s.group.Now() + } + return time.Now() +} + +// newTimer creates a new time.Timer, or a synthetic timer in tests. +func (s *http2Server) newTimer(d time.Duration) http2timer { + if s.group != nil { + return s.group.NewTimer(d) + } + return http2timeTimer{time.NewTimer(d)} +} + +// afterFunc creates a new time.AfterFunc timer, or a synthetic timer in tests. +func (s *http2Server) afterFunc(d time.Duration, f func()) http2timer { + if s.group != nil { + return s.group.AfterFunc(d, f) + } + return http2timeTimer{time.AfterFunc(d, f)} } func (s *http2Server) initialConnRecvWindowSize() int32 { @@ -4213,6 +4263,10 @@ func (o *http2ServeConnOpts) handler() Handler { // // The opts parameter is optional. If nil, default values are used. func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) { + s.serveConn(c, opts, nil) +} + +func (s *http2Server) serveConn(c net.Conn, opts *http2ServeConnOpts, newf func(*http2serverConn)) { baseCtx, cancel := http2serverConnBaseContext(c, opts) defer cancel() @@ -4239,6 +4293,9 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) { pushEnabled: true, sawClientPreface: opts.SawClientPreface, } + if newf != nil { + newf(sc) + } s.state.registerConn(sc) defer s.state.unregisterConn(sc) @@ -4248,7 +4305,7 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) { // passes the connection off to us with the deadline already set. // Write deadlines are set per stream in serverConn.newStream. // Disarm the net.Conn write deadline here. - if sc.hs.WriteTimeout != 0 { + if sc.hs.WriteTimeout > 0 { sc.conn.SetWriteDeadline(time.Time{}) } @@ -4412,8 +4469,8 @@ type http2serverConn struct { inFrameScheduleLoop bool // whether we're in the scheduleFrameWrite loop needToSendGoAway bool // we need to schedule a GOAWAY frame write goAwayCode http2ErrCode - shutdownTimer *time.Timer // nil until used - idleTimer *time.Timer // nil if unused + shutdownTimer http2timer // nil until used + idleTimer http2timer // nil if unused // Owned by the writeFrameAsync goroutine: headerWriteBuf bytes.Buffer @@ -4462,12 +4519,12 @@ type http2stream struct { flow http2outflow // limits writing from Handler to client inflow http2inflow // what the client is allowed to POST/etc to us state http2streamState - resetQueued bool // RST_STREAM queued for write; set by sc.resetStream - gotTrailerHeader bool // HEADER frame for trailers was seen - wroteHeaders bool // whether we wrote headers (not status 100) - readDeadline *time.Timer // nil if unused - writeDeadline *time.Timer // nil if unused - closeErr error // set before cw is closed + resetQueued bool // RST_STREAM queued for write; set by sc.resetStream + gotTrailerHeader bool // HEADER frame for trailers was seen + wroteHeaders bool // whether we wrote headers (not status 100) + readDeadline http2timer // nil if unused + writeDeadline http2timer // nil if unused + closeErr error // set before cw is closed trailer Header // accumulated trailers reqTrailer Header // handler's Request.Trailer @@ -4548,11 +4605,7 @@ func http2isClosedConnError(err error) bool { return false } - // TODO: remove this string search and be more like the Windows - // case below. That might involve modifying the standard library - // to return better error types. - str := err.Error() - if strings.Contains(str, "use of closed network connection") { + if errors.Is(err, net.ErrClosed) { return true } @@ -4631,8 +4684,9 @@ type http2readFrameResult struct { // consumer is done with the frame. // It's run on its own goroutine. func (sc *http2serverConn) readFrames() { - gate := make(http2gate) - gateDone := gate.Done + sc.srv.markNewGoroutine() + gate := make(chan struct{}) + gateDone := func() { gate <- struct{}{} } for { f, err := sc.framer.ReadFrame() select { @@ -4663,6 +4717,7 @@ type http2frameWriteResult struct { // At most one goroutine can be running writeFrameAsync at a time per // serverConn. func (sc *http2serverConn) writeFrameAsync(wr http2FrameWriteRequest, wd *http2writeData) { + sc.srv.markNewGoroutine() var err error if wd == nil { err = wr.write.writeFrame(sc) @@ -4741,14 +4796,14 @@ func (sc *http2serverConn) serve() { sc.setConnState(StateActive) sc.setConnState(StateIdle) - if sc.srv.IdleTimeout != 0 { - sc.idleTimer = time.AfterFunc(sc.srv.IdleTimeout, sc.onIdleTimer) + if sc.srv.IdleTimeout > 0 { + sc.idleTimer = sc.srv.afterFunc(sc.srv.IdleTimeout, sc.onIdleTimer) defer sc.idleTimer.Stop() } go sc.readFrames() // closed by defer sc.conn.Close above - settingsTimer := time.AfterFunc(http2firstSettingsTimeout, sc.onSettingsTimer) + settingsTimer := sc.srv.afterFunc(http2firstSettingsTimeout, sc.onSettingsTimer) defer settingsTimer.Stop() loopNum := 0 @@ -4879,10 +4934,10 @@ func (sc *http2serverConn) readPreface() error { errc <- nil } }() - timer := time.NewTimer(http2prefaceTimeout) // TODO: configurable on *Server? + timer := sc.srv.newTimer(http2prefaceTimeout) // TODO: configurable on *Server? defer timer.Stop() select { - case <-timer.C: + case <-timer.C(): return http2errPrefaceTimeout case err := <-errc: if err == nil { @@ -5247,7 +5302,7 @@ func (sc *http2serverConn) goAway(code http2ErrCode) { func (sc *http2serverConn) shutDownIn(d time.Duration) { sc.serveG.check() - sc.shutdownTimer = time.AfterFunc(d, sc.onShutdownTimer) + sc.shutdownTimer = sc.srv.afterFunc(d, sc.onShutdownTimer) } func (sc *http2serverConn) resetStream(se http2StreamError) { @@ -5461,7 +5516,7 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) { delete(sc.streams, st.id) if len(sc.streams) == 0 { sc.setConnState(StateIdle) - if sc.srv.IdleTimeout != 0 { + if sc.srv.IdleTimeout > 0 && sc.idleTimer != nil { sc.idleTimer.Reset(sc.srv.IdleTimeout) } if http2h1ServerKeepAlivesDisabled(sc.hs) { @@ -5483,6 +5538,7 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) { } } st.closeErr = err + st.cancelCtx() st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc sc.writeSched.CloseStream(st.id) } @@ -5841,9 +5897,9 @@ func (sc *http2serverConn) processHeaders(f *http2MetaHeadersFrame) error { // similar to how the http1 server works. Here it's // technically more like the http1 Server's ReadHeaderTimeout // (in Go 1.8), though. That's a more sane option anyway. - if sc.hs.ReadTimeout != 0 { + if sc.hs.ReadTimeout > 0 { sc.conn.SetReadDeadline(time.Time{}) - st.readDeadline = time.AfterFunc(sc.hs.ReadTimeout, st.onReadTimeout) + st.readDeadline = sc.srv.afterFunc(sc.hs.ReadTimeout, st.onReadTimeout) } return sc.scheduleHandler(id, rw, req, handler) @@ -5862,7 +5918,7 @@ func (sc *http2serverConn) upgradeRequest(req *Request) { // Disable any read deadline set by the net/http package // prior to the upgrade. - if sc.hs.ReadTimeout != 0 { + if sc.hs.ReadTimeout > 0 { sc.conn.SetReadDeadline(time.Time{}) } @@ -5940,8 +5996,8 @@ func (sc *http2serverConn) newStream(id, pusherID uint32, state http2streamState st.flow.conn = &sc.flow // link to conn-level counter st.flow.add(sc.initialStreamSendWindowSize) st.inflow.init(sc.srv.initialStreamRecvWindowSize()) - if sc.hs.WriteTimeout != 0 { - st.writeDeadline = time.AfterFunc(sc.hs.WriteTimeout, st.onWriteTimeout) + if sc.hs.WriteTimeout > 0 { + st.writeDeadline = sc.srv.afterFunc(sc.hs.WriteTimeout, st.onWriteTimeout) } sc.streams[id] = st @@ -6165,6 +6221,7 @@ func (sc *http2serverConn) handlerDone() { // Run on its own goroutine. func (sc *http2serverConn) runHandler(rw *http2responseWriter, req *Request, handler func(ResponseWriter, *Request)) { + sc.srv.markNewGoroutine() defer sc.sendServeMsg(http2handlerDoneMsg) didPanic := true defer func() { @@ -6461,7 +6518,7 @@ func (rws *http2responseWriterState) writeChunk(p []byte) (n int, err error) { var date string if _, ok := rws.snapHeader["Date"]; !ok { // TODO(bradfitz): be faster here, like net/http? measure. - date = time.Now().UTC().Format(TimeFormat) + date = rws.conn.srv.now().UTC().Format(TimeFormat) } for _, v := range rws.snapHeader["Trailer"] { @@ -6583,7 +6640,7 @@ func (rws *http2responseWriterState) promoteUndeclaredTrailers() { func (w *http2responseWriter) SetReadDeadline(deadline time.Time) error { st := w.rws.stream - if !deadline.IsZero() && deadline.Before(time.Now()) { + if !deadline.IsZero() && deadline.Before(w.rws.conn.srv.now()) { // If we're setting a deadline in the past, reset the stream immediately // so writes after SetWriteDeadline returns will fail. st.onReadTimeout() @@ -6599,9 +6656,9 @@ func (w *http2responseWriter) SetReadDeadline(deadline time.Time) error { if deadline.IsZero() { st.readDeadline = nil } else if st.readDeadline == nil { - st.readDeadline = time.AfterFunc(deadline.Sub(time.Now()), st.onReadTimeout) + st.readDeadline = sc.srv.afterFunc(deadline.Sub(sc.srv.now()), st.onReadTimeout) } else { - st.readDeadline.Reset(deadline.Sub(time.Now())) + st.readDeadline.Reset(deadline.Sub(sc.srv.now())) } }) return nil @@ -6609,7 +6666,7 @@ func (w *http2responseWriter) SetReadDeadline(deadline time.Time) error { func (w *http2responseWriter) SetWriteDeadline(deadline time.Time) error { st := w.rws.stream - if !deadline.IsZero() && deadline.Before(time.Now()) { + if !deadline.IsZero() && deadline.Before(w.rws.conn.srv.now()) { // If we're setting a deadline in the past, reset the stream immediately // so writes after SetWriteDeadline returns will fail. st.onWriteTimeout() @@ -6625,9 +6682,9 @@ func (w *http2responseWriter) SetWriteDeadline(deadline time.Time) error { if deadline.IsZero() { st.writeDeadline = nil } else if st.writeDeadline == nil { - st.writeDeadline = time.AfterFunc(deadline.Sub(time.Now()), st.onWriteTimeout) + st.writeDeadline = sc.srv.afterFunc(deadline.Sub(sc.srv.now()), st.onWriteTimeout) } else { - st.writeDeadline.Reset(deadline.Sub(time.Now())) + st.writeDeadline.Reset(deadline.Sub(sc.srv.now())) } }) return nil @@ -7103,6 +7160,20 @@ func (sc *http2serverConn) countError(name string, err error) error { return err } +// A timer is a time.Timer, as an interface which can be replaced in tests. +type http2timer = interface { + C() <-chan time.Time + Reset(d time.Duration) bool + Stop() bool +} + +// timeTimer adapts a time.Timer to the timer interface. +type http2timeTimer struct { + *time.Timer +} + +func (t http2timeTimer) C() <-chan time.Time { return t.Timer.C } + const ( // transportDefaultConnFlow is how many connection-level flow control // tokens we give the server at start-up, past the default 64k. @@ -7212,6 +7283,12 @@ type http2Transport struct { // waiting for their turn. StrictMaxConcurrentStreams bool + // IdleConnTimeout is the maximum amount of time an idle + // (keep-alive) connection will remain idle before closing + // itself. + // Zero means no limit. + IdleConnTimeout time.Duration + // ReadIdleTimeout is the timeout after which a health check using ping // frame will be carried out if no frame is received on the connection. // Note that a ping response will is considered a received frame, so if @@ -7243,6 +7320,46 @@ type http2Transport struct { connPoolOnce sync.Once connPoolOrDef http2ClientConnPool // non-nil version of ConnPool + + *http2transportTestHooks +} + +// Hook points used for testing. +// Outside of tests, t.transportTestHooks is nil and these all have minimal implementations. +// Inside tests, see the testSyncHooks function docs. + +type http2transportTestHooks struct { + newclientconn func(*http2ClientConn) + group http2synctestGroupInterface +} + +func (t *http2Transport) markNewGoroutine() { + if t != nil && t.http2transportTestHooks != nil { + t.http2transportTestHooks.group.Join() + } +} + +// newTimer creates a new time.Timer, or a synthetic timer in tests. +func (t *http2Transport) newTimer(d time.Duration) http2timer { + if t.http2transportTestHooks != nil { + return t.http2transportTestHooks.group.NewTimer(d) + } + return http2timeTimer{time.NewTimer(d)} +} + +// afterFunc creates a new time.AfterFunc timer, or a synthetic timer in tests. +func (t *http2Transport) afterFunc(d time.Duration, f func()) http2timer { + if t.http2transportTestHooks != nil { + return t.http2transportTestHooks.group.AfterFunc(d, f) + } + return http2timeTimer{time.AfterFunc(d, f)} +} + +func (t *http2Transport) contextWithTimeout(ctx context.Context, d time.Duration) (context.Context, context.CancelFunc) { + if t.http2transportTestHooks != nil { + return t.http2transportTestHooks.group.ContextWithTimeout(ctx, d) + } + return context.WithTimeout(ctx, d) } func (t *http2Transport) maxHeaderListSize() uint32 { @@ -7367,7 +7484,7 @@ type http2ClientConn struct { readerErr error // set before readerDone is closed idleTimeout time.Duration // or 0 for never - idleTimer *time.Timer + idleTimer http2timer mu sync.Mutex // guards following cond *sync.Cond // hold mu; broadcast on flow/closed changes @@ -7511,6 +7628,7 @@ func (cs *http2clientStream) closeReqBodyLocked() { cs.reqBodyClosed = make(chan struct{}) reqBodyClosed := cs.reqBodyClosed go func() { + cs.cc.t.markNewGoroutine() cs.reqBody.Close() close(reqBodyClosed) }() @@ -7603,15 +7721,6 @@ func http2authorityAddr(scheme string, authority string) (addr string) { return net.JoinHostPort(host, port) } -var http2retryBackoffHook func(time.Duration) *time.Timer - -func http2backoffNewTimer(d time.Duration) *time.Timer { - if http2retryBackoffHook != nil { - return http2retryBackoffHook(d) - } - return time.NewTimer(d) -} - // RoundTripOpt is like RoundTrip, but takes options. func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Response, error) { if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) { @@ -7639,13 +7748,13 @@ func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Res backoff := float64(uint(1) << (uint(retry) - 1)) backoff += backoff * (0.1 * mathrand.Float64()) d := time.Second * time.Duration(backoff) - timer := http2backoffNewTimer(d) + tm := t.newTimer(d) select { - case <-timer.C: + case <-tm.C(): t.vlogf("RoundTrip retrying after failure: %v", roundTripErr) continue case <-req.Context().Done(): - timer.Stop() + tm.Stop() err = req.Context().Err() } } @@ -7724,6 +7833,9 @@ func http2canRetryError(err error) bool { } func (t *http2Transport) dialClientConn(ctx context.Context, addr string, singleUse bool) (*http2ClientConn, error) { + if t.http2transportTestHooks != nil { + return t.newClientConn(nil, singleUse) + } host, _, err := net.SplitHostPort(addr) if err != nil { return nil, err @@ -7817,9 +7929,10 @@ func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2Client pings: make(map[[8]byte]chan struct{}), reqHeaderMu: make(chan struct{}, 1), } - if d := t.idleConnTimeout(); d != 0 { - cc.idleTimeout = d - cc.idleTimer = time.AfterFunc(d, cc.onIdleTimeout) + if t.http2transportTestHooks != nil { + t.markNewGoroutine() + t.http2transportTestHooks.newclientconn(cc) + c = cc.tconn } if http2VerboseLogs { t.vlogf("http2: Transport creating client conn %p to %v", cc, c.RemoteAddr()) @@ -7884,6 +7997,12 @@ func (t *http2Transport) newClientConn(c net.Conn, singleUse bool) (*http2Client return nil, cc.werr } + // Start the idle timer after the connection is fully initialized. + if d := t.idleConnTimeout(); d != 0 { + cc.idleTimeout = d + cc.idleTimer = t.afterFunc(d, cc.onIdleTimeout) + } + go cc.readLoop() return cc, nil } @@ -7892,7 +8011,7 @@ func (cc *http2ClientConn) healthCheck() { pingTimeout := cc.t.pingTimeout() // We don't need to periodically ping in the health check, because the readLoop of ClientConn will // trigger the healthCheck again if there is no frame received. - ctx, cancel := context.WithTimeout(context.Background(), pingTimeout) + ctx, cancel := cc.t.contextWithTimeout(context.Background(), pingTimeout) defer cancel() cc.vlogf("http2: Transport sending health check") err := cc.Ping(ctx) @@ -7927,7 +8046,20 @@ func (cc *http2ClientConn) setGoAway(f *http2GoAwayFrame) { } last := f.LastStreamID for streamID, cs := range cc.streams { - if streamID > last { + if streamID <= last { + // The server's GOAWAY indicates that it received this stream. + // It will either finish processing it, or close the connection + // without doing so. Either way, leave the stream alone for now. + continue + } + if streamID == 1 && cc.goAway.ErrCode != http2ErrCodeNo { + // Don't retry the first stream on a connection if we get a non-NO error. + // If the server is sending an error on a new connection, + // retrying the request on a new one probably isn't going to work. + cs.abortStreamLocked(fmt.Errorf("http2: Transport received GOAWAY from server ErrCode:%v", cc.goAway.ErrCode)) + } else { + // Aborting the stream with errClentConnGotGoAway indicates that + // the request should be retried on a new connection. cs.abortStreamLocked(http2errClientConnGotGoAway) } } @@ -8123,6 +8255,7 @@ func (cc *http2ClientConn) Shutdown(ctx context.Context) error { done := make(chan struct{}) cancelled := false // guarded by cc.mu go func() { + cc.t.markNewGoroutine() cc.mu.Lock() defer cc.mu.Unlock() for { @@ -8281,6 +8414,10 @@ func (cc *http2ClientConn) decrStreamReservationsLocked() { } func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { + return cc.roundTrip(req, nil) +} + +func (cc *http2ClientConn) roundTrip(req *Request, streamf func(*http2clientStream)) (*Response, error) { ctx := req.Context() cs := &http2clientStream{ cc: cc, @@ -8295,7 +8432,28 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { respHeaderRecv: make(chan struct{}), donec: make(chan struct{}), } - go cs.doRequest(req) + + // TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere? + if !cc.t.disableCompression() && + req.Header.Get("Accept-Encoding") == "" && + req.Header.Get("Range") == "" && + !cs.isHead { + // Request gzip only, not deflate. Deflate is ambiguous and + // not as universally supported anyway. + // See: https://zlib.net/zlib_faq.html#faq39 + // + // Note that we don't request this for HEAD requests, + // due to a bug in nginx: + // http://trac.nginx.org/nginx/ticket/358 + // https://golang.org/issue/5522 + // + // We don't request gzip if the request is for a range, since + // auto-decoding a portion of a gzipped document will just fail + // anyway. See https://golang.org/issue/8923 + cs.requestedGzip = true + } + + go cs.doRequest(req, streamf) waitDone := func() error { select { @@ -8388,8 +8546,9 @@ func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { // doRequest runs for the duration of the request lifetime. // // It sends the request and performs post-request cleanup (closing Request.Body, etc.). -func (cs *http2clientStream) doRequest(req *Request) { - err := cs.writeRequest(req) +func (cs *http2clientStream) doRequest(req *Request, streamf func(*http2clientStream)) { + cs.cc.t.markNewGoroutine() + err := cs.writeRequest(req, streamf) cs.cleanupWriteRequest(err) } @@ -8400,7 +8559,7 @@ func (cs *http2clientStream) doRequest(req *Request) { // // It returns non-nil if the request ends otherwise. // If the returned error is StreamError, the error Code may be used in resetting the stream. -func (cs *http2clientStream) writeRequest(req *Request) (err error) { +func (cs *http2clientStream) writeRequest(req *Request, streamf func(*http2clientStream)) (err error) { cc := cs.cc ctx := cs.ctx @@ -8438,24 +8597,8 @@ func (cs *http2clientStream) writeRequest(req *Request) (err error) { } cc.mu.Unlock() - // TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere? - if !cc.t.disableCompression() && - req.Header.Get("Accept-Encoding") == "" && - req.Header.Get("Range") == "" && - !cs.isHead { - // Request gzip only, not deflate. Deflate is ambiguous and - // not as universally supported anyway. - // See: https://zlib.net/zlib_faq.html#faq39 - // - // Note that we don't request this for HEAD requests, - // due to a bug in nginx: - // http://trac.nginx.org/nginx/ticket/358 - // https://golang.org/issue/5522 - // - // We don't request gzip if the request is for a range, since - // auto-decoding a portion of a gzipped document will just fail - // anyway. See https://golang.org/issue/8923 - cs.requestedGzip = true + if streamf != nil { + streamf(cs) } continueTimeout := cc.t.expectContinueTimeout() @@ -8518,9 +8661,9 @@ func (cs *http2clientStream) writeRequest(req *Request) (err error) { var respHeaderTimer <-chan time.Time var respHeaderRecv chan struct{} if d := cc.responseHeaderTimeout(); d != 0 { - timer := time.NewTimer(d) + timer := cc.t.newTimer(d) defer timer.Stop() - respHeaderTimer = timer.C + respHeaderTimer = timer.C() respHeaderRecv = cs.respHeaderRecv } // Wait until the peer half-closes its end of the stream, @@ -8942,6 +9085,22 @@ func (cs *http2clientStream) awaitFlowControl(maxBytes int) (taken int32, err er } } +func http2validateHeaders(hdrs Header) string { + for k, vv := range hdrs { + if !httpguts.ValidHeaderFieldName(k) { + return fmt.Sprintf("name %q", k) + } + for _, v := range vv { + if !httpguts.ValidHeaderFieldValue(v) { + // Don't include the value in the error, + // because it may be sensitive. + return fmt.Sprintf("value for header %q", k) + } + } + } + return "" +} + var http2errNilRequestURL = errors.New("http2: Request.URI is nil") // requires cc.wmu be held. @@ -8979,19 +9138,14 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail } } - // Check for any invalid headers and return an error before we + // Check for any invalid headers+trailers and return an error before we // potentially pollute our hpack state. (We want to be able to // continue to reuse the hpack encoder for future requests) - for k, vv := range req.Header { - if !httpguts.ValidHeaderFieldName(k) { - return nil, fmt.Errorf("invalid HTTP header name %q", k) - } - for _, v := range vv { - if !httpguts.ValidHeaderFieldValue(v) { - // Don't include the value in the error, because it may be sensitive. - return nil, fmt.Errorf("invalid HTTP header value for header %q", k) - } - } + if err := http2validateHeaders(req.Header); err != "" { + return nil, fmt.Errorf("invalid HTTP header %s", err) + } + if err := http2validateHeaders(req.Trailer); err != "" { + return nil, fmt.Errorf("invalid HTTP trailer %s", err) } enumerateHeaders := func(f func(name, value string)) { @@ -9232,6 +9386,7 @@ type http2clientConnReadLoop struct { // readLoop runs in its own goroutine and reads and dispatches frames. func (cc *http2ClientConn) readLoop() { + cc.t.markNewGoroutine() rl := &http2clientConnReadLoop{cc: cc} defer rl.cleanup() cc.readerErr = rl.run() @@ -9333,10 +9488,9 @@ func (rl *http2clientConnReadLoop) run() error { cc := rl.cc gotSettings := false readIdleTimeout := cc.t.ReadIdleTimeout - var t *time.Timer + var t http2timer if readIdleTimeout != 0 { - t = time.AfterFunc(readIdleTimeout, cc.healthCheck) - defer t.Stop() + t = cc.t.afterFunc(readIdleTimeout, cc.healthCheck) } for { f, err := cc.fr.ReadFrame() @@ -9978,6 +10132,15 @@ func (rl *http2clientConnReadLoop) processWindowUpdate(f *http2WindowUpdateFrame fl = &cs.flow } if !fl.add(int32(f.Increment)) { + // For stream, the sender sends RST_STREAM with an error code of FLOW_CONTROL_ERROR + if cs != nil { + rl.endStreamError(cs, http2StreamError{ + StreamID: f.StreamID, + Code: http2ErrCodeFlowControl, + }) + return nil + } + return http2ConnectionError(http2ErrCodeFlowControl) } cc.cond.Broadcast() @@ -10022,24 +10185,26 @@ func (cc *http2ClientConn) Ping(ctx context.Context) error { } cc.mu.Unlock() } - errc := make(chan error, 1) + var pingError error + errc := make(chan struct{}) go func() { + cc.t.markNewGoroutine() cc.wmu.Lock() defer cc.wmu.Unlock() - if err := cc.fr.WritePing(false, p); err != nil { - errc <- err + if pingError = cc.fr.WritePing(false, p); pingError != nil { + close(errc) return } - if err := cc.bw.Flush(); err != nil { - errc <- err + if pingError = cc.bw.Flush(); pingError != nil { + close(errc) return } }() select { case <-c: return nil - case err := <-errc: - return err + case <-errc: + return pingError case <-ctx.Done(): return ctx.Err() case <-cc.readerDone: @@ -10211,9 +10376,17 @@ func (rt http2noDialH2RoundTripper) RoundTrip(req *Request) (*Response, error) { } func (t *http2Transport) idleConnTimeout() time.Duration { + // to keep things backwards compatible, we use non-zero values of + // IdleConnTimeout, followed by using the IdleConnTimeout on the underlying + // http1 transport, followed by 0 + if t.IdleConnTimeout != 0 { + return t.IdleConnTimeout + } + if t.t1 != nil { return t.t1.IdleConnTimeout } + return 0 } @@ -11340,8 +11513,8 @@ func (ws *http2priorityWriteScheduler) addClosedOrIdleNode(list *[]*http2priorit } func (ws *http2priorityWriteScheduler) removeNode(n *http2priorityNode) { - for k := n.kids; k != nil; k = k.next { - k.setParent(n.parent) + for n.kids != nil { + n.kids.setParent(n.parent) } n.setParent(nil) delete(ws.nodes, n.id) diff --git a/contrib/go/_std_1.22/src/net/http/h2_error.go b/contrib/go/_std_1.23/src/net/http/h2_error.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/h2_error.go rename to contrib/go/_std_1.23/src/net/http/h2_error.go diff --git a/contrib/go/_std_1.22/src/net/http/header.go b/contrib/go/_std_1.23/src/net/http/header.go similarity index 94% rename from contrib/go/_std_1.22/src/net/http/header.go rename to contrib/go/_std_1.23/src/net/http/header.go index 9d0f3a125d64..b8b080bece92 100644 --- a/contrib/go/_std_1.22/src/net/http/header.go +++ b/contrib/go/_std_1.23/src/net/http/header.go @@ -9,7 +9,7 @@ import ( "net/http/httptrace" "net/http/internal/ascii" "net/textproto" - "sort" + "slices" "strings" "sync" "time" @@ -152,17 +152,11 @@ type keyValues struct { values []string } -// A headerSorter implements sort.Interface by sorting a []keyValues -// by key. It's used as a pointer, so it can fit in a sort.Interface -// interface value without allocation. +// headerSorter contains a slice of keyValues sorted by keyValues.key. type headerSorter struct { kvs []keyValues } -func (s *headerSorter) Len() int { return len(s.kvs) } -func (s *headerSorter) Swap(i, j int) { s.kvs[i], s.kvs[j] = s.kvs[j], s.kvs[i] } -func (s *headerSorter) Less(i, j int) bool { return s.kvs[i].key < s.kvs[j].key } - var headerSorterPool = sync.Pool{ New: func() any { return new(headerSorter) }, } @@ -182,7 +176,7 @@ func (h Header) sortedKeyValues(exclude map[string]bool) (kvs []keyValues, hs *h } } hs.kvs = kvs - sort.Sort(hs) + slices.SortFunc(hs.kvs, func(a, b keyValues) int { return strings.Compare(a.key, b.key) }) return kvs, hs } diff --git a/contrib/go/_std_1.22/src/net/http/http.go b/contrib/go/_std_1.23/src/net/http/http.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/http.go rename to contrib/go/_std_1.23/src/net/http/http.go diff --git a/contrib/go/_std_1.22/src/net/http/httptest/httptest.go b/contrib/go/_std_1.23/src/net/http/httptest/httptest.go similarity index 86% rename from contrib/go/_std_1.22/src/net/http/httptest/httptest.go rename to contrib/go/_std_1.23/src/net/http/httptest/httptest.go index f0ca64362d7f..0c0dbb40e89b 100644 --- a/contrib/go/_std_1.22/src/net/http/httptest/httptest.go +++ b/contrib/go/_std_1.23/src/net/http/httptest/httptest.go @@ -8,13 +8,19 @@ package httptest import ( "bufio" "bytes" + "context" "crypto/tls" "io" "net/http" "strings" ) -// NewRequest returns a new incoming server Request, suitable +// NewRequest wraps NewRequestWithContext using context.Background. +func NewRequest(method, target string, body io.Reader) *http.Request { + return NewRequestWithContext(context.Background(), method, target, body) +} + +// NewRequestWithContext returns a new incoming server Request, suitable // for passing to an [http.Handler] for testing. // // The target is the RFC 7230 "request-target": it may be either a @@ -37,7 +43,7 @@ import ( // // To generate a client HTTP request instead of a server request, see // the NewRequest function in the net/http package. -func NewRequest(method, target string, body io.Reader) *http.Request { +func NewRequestWithContext(ctx context.Context, method, target string, body io.Reader) *http.Request { if method == "" { method = "GET" } @@ -45,6 +51,7 @@ func NewRequest(method, target string, body io.Reader) *http.Request { if err != nil { panic("invalid NewRequest arguments; " + err.Error()) } + req = req.WithContext(ctx) // HTTP/1.0 was used above to avoid needing a Host field. Change it to 1.1 here. req.Proto = "HTTP/1.1" diff --git a/contrib/go/_std_1.22/src/net/http/httptest/recorder.go b/contrib/go/_std_1.23/src/net/http/httptest/recorder.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httptest/recorder.go rename to contrib/go/_std_1.23/src/net/http/httptest/recorder.go diff --git a/contrib/go/_std_1.22/src/net/http/httptest/server.go b/contrib/go/_std_1.23/src/net/http/httptest/server.go similarity index 99% rename from contrib/go/_std_1.22/src/net/http/httptest/server.go rename to contrib/go/_std_1.23/src/net/http/httptest/server.go index 5095b438ec94..fa5492317969 100644 --- a/contrib/go/_std_1.22/src/net/http/httptest/server.go +++ b/contrib/go/_std_1.23/src/net/http/httptest/server.go @@ -299,6 +299,7 @@ func (s *Server) Certificate() *x509.Certificate { // Client returns an HTTP client configured for making requests to the server. // It is configured to trust the server's TLS test certificate and will // close its idle connections on [Server.Close]. +// Use Server.URL as the base URL to send requests to the server. func (s *Server) Client() *http.Client { return s.client } diff --git a/contrib/go/_std_1.22/src/net/http/httptest/ya.make b/contrib/go/_std_1.23/src/net/http/httptest/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httptest/ya.make rename to contrib/go/_std_1.23/src/net/http/httptest/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/httptrace/trace.go b/contrib/go/_std_1.23/src/net/http/httptrace/trace.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httptrace/trace.go rename to contrib/go/_std_1.23/src/net/http/httptrace/trace.go diff --git a/contrib/go/_std_1.22/src/net/http/httptrace/ya.make b/contrib/go/_std_1.23/src/net/http/httptrace/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httptrace/ya.make rename to contrib/go/_std_1.23/src/net/http/httptrace/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/httputil/dump.go b/contrib/go/_std_1.23/src/net/http/httputil/dump.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httputil/dump.go rename to contrib/go/_std_1.23/src/net/http/httputil/dump.go diff --git a/contrib/go/_std_1.22/src/net/http/httputil/httputil.go b/contrib/go/_std_1.23/src/net/http/httputil/httputil.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httputil/httputil.go rename to contrib/go/_std_1.23/src/net/http/httputil/httputil.go diff --git a/contrib/go/_std_1.22/src/net/http/httputil/persist.go b/contrib/go/_std_1.23/src/net/http/httputil/persist.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httputil/persist.go rename to contrib/go/_std_1.23/src/net/http/httputil/persist.go diff --git a/contrib/go/_std_1.22/src/net/http/httputil/reverseproxy.go b/contrib/go/_std_1.23/src/net/http/httputil/reverseproxy.go similarity index 98% rename from contrib/go/_std_1.22/src/net/http/httputil/reverseproxy.go rename to contrib/go/_std_1.23/src/net/http/httputil/reverseproxy.go index 5c70f0d27bb1..04248d5f531e 100644 --- a/contrib/go/_std_1.22/src/net/http/httputil/reverseproxy.go +++ b/contrib/go/_std_1.23/src/net/http/httputil/reverseproxy.go @@ -454,8 +454,19 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { outreq.Header.Set("User-Agent", "") } + var ( + roundTripMutex sync.Mutex + roundTripDone bool + ) trace := &httptrace.ClientTrace{ Got1xxResponse: func(code int, header textproto.MIMEHeader) error { + roundTripMutex.Lock() + defer roundTripMutex.Unlock() + if roundTripDone { + // If RoundTrip has returned, don't try to further modify + // the ResponseWriter's header map. + return nil + } h := rw.Header() copyHeader(h, http.Header(header)) rw.WriteHeader(code) @@ -468,6 +479,9 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { outreq = outreq.WithContext(httptrace.WithClientTrace(outreq.Context(), trace)) res, err := transport.RoundTrip(outreq) + roundTripMutex.Lock() + roundTripDone = true + roundTripMutex.Unlock() if err != nil { p.getErrorHandler()(rw, outreq, err) return diff --git a/contrib/go/_std_1.22/src/net/http/httputil/ya.make b/contrib/go/_std_1.23/src/net/http/httputil/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/httputil/ya.make rename to contrib/go/_std_1.23/src/net/http/httputil/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/internal/ascii/print.go b/contrib/go/_std_1.23/src/net/http/internal/ascii/print.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/internal/ascii/print.go rename to contrib/go/_std_1.23/src/net/http/internal/ascii/print.go diff --git a/contrib/go/_std_1.22/src/net/http/internal/ascii/ya.make b/contrib/go/_std_1.23/src/net/http/internal/ascii/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/internal/ascii/ya.make rename to contrib/go/_std_1.23/src/net/http/internal/ascii/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/internal/chunked.go b/contrib/go/_std_1.23/src/net/http/internal/chunked.go similarity index 92% rename from contrib/go/_std_1.22/src/net/http/internal/chunked.go rename to contrib/go/_std_1.23/src/net/http/internal/chunked.go index 196b5d892589..0b08a97a0831 100644 --- a/contrib/go/_std_1.22/src/net/http/internal/chunked.go +++ b/contrib/go/_std_1.23/src/net/http/internal/chunked.go @@ -164,6 +164,19 @@ func readChunkLine(b *bufio.Reader) ([]byte, error) { } return nil, err } + + // RFC 9112 permits parsers to accept a bare \n as a line ending in headers, + // but not in chunked encoding lines. See https://www.rfc-editor.org/errata/eid7633, + // which explicitly rejects a clarification permitting \n as a chunk terminator. + // + // Verify that the line ends in a CRLF, and that no CRs appear before the end. + if idx := bytes.IndexByte(p, '\r'); idx == -1 { + return nil, errors.New("chunked line ends with bare LF") + } else if idx != len(p)-2 { + return nil, errors.New("invalid CR in chunked line") + } + p = p[:len(p)-2] // trim CRLF + if len(p) >= maxLineLength { return nil, ErrLineTooLong } @@ -171,14 +184,14 @@ func readChunkLine(b *bufio.Reader) ([]byte, error) { } func trimTrailingWhitespace(b []byte) []byte { - for len(b) > 0 && isASCIISpace(b[len(b)-1]) { + for len(b) > 0 && isOWS(b[len(b)-1]) { b = b[:len(b)-1] } return b } -func isASCIISpace(b byte) bool { - return b == ' ' || b == '\t' || b == '\n' || b == '\r' +func isOWS(b byte) bool { + return b == ' ' || b == '\t' } var semi = []byte(";") diff --git a/contrib/go/_std_1.23/src/net/http/internal/testcert/testcert.go b/contrib/go/_std_1.23/src/net/http/internal/testcert/testcert.go new file mode 100644 index 000000000000..78ce42e22826 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/http/internal/testcert/testcert.go @@ -0,0 +1,65 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package testcert contains a test-only localhost certificate. +package testcert + +import "strings" + +// LocalhostCert is a PEM-encoded TLS cert with SAN IPs +// "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT. +// generated from src/crypto/tls: +// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com,*.example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h +var LocalhostCert = []byte(`-----BEGIN CERTIFICATE----- +MIIDSDCCAjCgAwIBAgIQEP/md970HysdBTpuzDOf0DANBgkqhkiG9w0BAQsFADAS +MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw +MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxcl69ROJdxjN+MJZnbFrYxyQooADCsJ6VDkuMyNQIix/Hk15Nk/u +FyBX1Me++aEpGmY3RIY4fUvELqT/srvAHsTXwVVSttMcY8pcAFmXSqo3x4MuUTG/ +jCX3Vftj0r3EM5M8ImY1rzA/jqTTLJg00rD+DmuDABcqQvoXw/RV8w1yTRi5BPoH +DFD/AWTt/YgMvk1l2Yq/xI8VbMUIpjBoGXxWsSevQ5i2s1mk9/yZzu0Ysp1tTlzD +qOPa4ysFjBitdXiwfxjxtv5nXqOCP5rheKO0sWLk0fetMp1OV5JSJMAJw6c2ZMkl +U2WMqAEpRjdE/vHfIuNg+yGaRRqI07NZRQIDAQABo4GXMIGUMA4GA1UdDwEB/wQE +AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBQR5QIzmacmw78ZI1C4MXw7Q0wJ1jA9BgNVHREENjA0ggtleGFtcGxlLmNv +bYINKi5leGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG +9w0BAQsFAAOCAQEACrRNgiioUDzxQftd0fwOa6iRRcPampZRDtuaF68yNHoNWbOu +LUwc05eOWxRq3iABGSk2xg+FXM3DDeW4HhAhCFptq7jbVZ+4Jj6HeJG9mYRatAxR +Y/dEpa0D0EHhDxxVg6UzKOXB355n0IetGE/aWvyTV9SiDs6QsaC57Q9qq1/mitx5 +2GFBoapol9L5FxCc77bztzK8CpLujkBi25Vk6GAFbl27opLfpyxkM+rX/T6MXCPO +6/YBacNZ7ff1/57Etg4i5mNA6ubCpuc4Gi9oYqCNNohftr2lkJr7REdDR6OW0lsL +rF7r4gUnKeC7mYIH1zypY7laskopiLFAfe96Kg== +-----END CERTIFICATE-----`) + +// LocalhostKey is the private key for LocalhostCert. +var LocalhostKey = []byte(testingKey(`-----BEGIN RSA TESTING KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFyXr1E4l3GM34 +wlmdsWtjHJCigAMKwnpUOS4zI1AiLH8eTXk2T+4XIFfUx775oSkaZjdEhjh9S8Qu +pP+yu8AexNfBVVK20xxjylwAWZdKqjfHgy5RMb+MJfdV+2PSvcQzkzwiZjWvMD+O +pNMsmDTSsP4Oa4MAFypC+hfD9FXzDXJNGLkE+gcMUP8BZO39iAy+TWXZir/EjxVs +xQimMGgZfFaxJ69DmLazWaT3/JnO7RiynW1OXMOo49rjKwWMGK11eLB/GPG2/mde +o4I/muF4o7SxYuTR960ynU5XklIkwAnDpzZkySVTZYyoASlGN0T+8d8i42D7IZpF +GojTs1lFAgMBAAECggEAIYthUi1lFBDd5gG4Rzlu+BlBIn5JhcqkCqLEBiJIFfOr +/4yuMRrvS3bNzqWt6xJ9MSAC4ZlN/VobRLnxL/QNymoiGYUKCT3Ww8nvPpPzR9OE +sE68TUL9tJw/zZJcRMKwgvrGqSLimfq53MxxkE+kLdOc0v9C8YH8Re26mB5ZcWYa +7YFyZQpKsQYnsmu/05cMbpOQrQWhtmIqRoyn8mG/par2s3NzjtpSE9NINyz26uFc +k/3ovFJQIHkUmTS7KHD3BgY5vuCqP98HramYnOysJ0WoYgvSDNCWw3037s5CCwJT +gCKuM+Ow6liFrj83RrdKBpm5QUGjfNpYP31o+QNP4QKBgQDSrUQ2XdgtAnibAV7u +7kbxOxro0EhIKso0Y/6LbDQgcXgxLqltkmeqZgG8nC3Z793lhlSasz2snhzzooV5 +5fTy1y8ikXqjhG0nNkInFyOhsI0auE28CFoDowaQd+5cmCatpN4Grqo5PNRXxm1w +HktfPEgoP11NNCFHvvN5fEKbbQKBgQDwVlOaV20IvW3IPq7cXZyiyabouFF9eTRo +VJka1Uv+JtyvL2P0NKkjYHOdN8gRblWqxQtJoTNk020rVA4UP1heiXALy50gvj/p +hMcybPTLYSPOhAGx838KIcvGR5oskP1aUCmFbFQzGELxhJ9diVVjxUtbG2DuwPKd +tD9TLxT2OQKBgQCcdlHSjp+dzdgERmBa0ludjGfPv9/uuNizUBAbO6D690psPFtY +JQMYaemgSd1DngEOFVWADt4e9M5Lose+YCoqr+UxpxmNlyv5kzJOFcFAs/4XeglB +PHKdgNW/NVKxMc6H54l9LPr+x05sYdGlEtqnP/3W5jhEvhJ5Vjc8YiyVgQKBgQCl +zwjyrGo+42GACy7cPYE5FeIfIDqoVByB9guC5bD98JXEDu/opQQjsgFRcBCJZhOY +M0UsURiB8ROaFu13rpQq9KrmmF0ZH+g8FSzQbzcbsTLg4VXCDXmR5esOKowFPypr +Sm667BfTAGP++D5ya7MLmCv6+RKQ5XD8uEQQAaV2kQKBgAD8qeJuWIXZT0VKkQrn +nIhgtzGERF/6sZdQGW2LxTbUDWG74AfFkkEbeBfwEkCZXY/xmnYqYABhvlSex8jU +supU6Eea21esIxIub2zv/Np0ojUb6rlqTPS4Ox1E27D787EJ3VOXpriSD10vyNnZ +jel6uj2FOP9g54s+GzlSVg/T +-----END RSA TESTING KEY-----`)) + +func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") } diff --git a/contrib/go/_std_1.22/src/net/http/internal/testcert/ya.make b/contrib/go/_std_1.23/src/net/http/internal/testcert/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/internal/testcert/ya.make rename to contrib/go/_std_1.23/src/net/http/internal/testcert/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/internal/ya.make b/contrib/go/_std_1.23/src/net/http/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/internal/ya.make rename to contrib/go/_std_1.23/src/net/http/internal/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/jar.go b/contrib/go/_std_1.23/src/net/http/jar.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/jar.go rename to contrib/go/_std_1.23/src/net/http/jar.go diff --git a/contrib/go/_std_1.22/src/net/http/mapping.go b/contrib/go/_std_1.23/src/net/http/mapping.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/mapping.go rename to contrib/go/_std_1.23/src/net/http/mapping.go diff --git a/contrib/go/_std_1.22/src/net/http/method.go b/contrib/go/_std_1.23/src/net/http/method.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/method.go rename to contrib/go/_std_1.23/src/net/http/method.go diff --git a/contrib/go/_std_1.22/src/net/http/omithttp2.go b/contrib/go/_std_1.23/src/net/http/omithttp2.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/omithttp2.go rename to contrib/go/_std_1.23/src/net/http/omithttp2.go diff --git a/contrib/go/_std_1.22/src/net/http/pattern.go b/contrib/go/_std_1.23/src/net/http/pattern.go similarity index 98% rename from contrib/go/_std_1.22/src/net/http/pattern.go rename to contrib/go/_std_1.23/src/net/http/pattern.go index f6af19b0f443..8fd120e7775c 100644 --- a/contrib/go/_std_1.22/src/net/http/pattern.go +++ b/contrib/go/_std_1.23/src/net/http/pattern.go @@ -76,7 +76,7 @@ type segment struct { // a literal or a wildcard of the form "{name}", "{name...}", or "{$}". // // METHOD, HOST and PATH are all optional; that is, the string can be "/". -// If METHOD is present, it must be followed by a single space. +// If METHOD is present, it must be followed by at least one space or tab. // Wildcard names must be valid Go identifiers. // The "{$}" and "{name...}" wildcard must occur at the end of PATH. // PATH may end with a '/'. @@ -92,7 +92,10 @@ func parsePattern(s string) (_ *pattern, err error) { } }() - method, rest, found := strings.Cut(s, " ") + method, rest, found := s, "", false + if i := strings.IndexAny(s, " \t"); i >= 0 { + method, rest, found = s[:i], strings.TrimLeft(s[i+1:], " \t"), true + } if !found { rest = method method = "" diff --git a/contrib/go/_std_1.22/src/net/http/pprof/pprof.go b/contrib/go/_std_1.23/src/net/http/pprof/pprof.go similarity index 94% rename from contrib/go/_std_1.22/src/net/http/pprof/pprof.go rename to contrib/go/_std_1.23/src/net/http/pprof/pprof.go index bc48f1183413..cf4b8415ca3a 100644 --- a/contrib/go/_std_1.22/src/net/http/pprof/pprof.go +++ b/contrib/go/_std_1.23/src/net/http/pprof/pprof.go @@ -8,6 +8,7 @@ // The package is typically only imported for the side effect of // registering its HTTP handlers. // The handled paths all begin with /debug/pprof/. +// As of Go 1.22, all the paths must be requested with GET. // // To use pprof, link this package into your program: // @@ -75,6 +76,7 @@ import ( "context" "fmt" "html" + "internal/godebug" "internal/profile" "io" "log" @@ -91,11 +93,15 @@ import ( ) func init() { - http.HandleFunc("/debug/pprof/", Index) - http.HandleFunc("/debug/pprof/cmdline", Cmdline) - http.HandleFunc("/debug/pprof/profile", Profile) - http.HandleFunc("/debug/pprof/symbol", Symbol) - http.HandleFunc("/debug/pprof/trace", Trace) + prefix := "" + if godebug.New("httpmuxgo121").Value() != "1" { + prefix = "GET " + } + http.HandleFunc(prefix+"/debug/pprof/", Index) + http.HandleFunc(prefix+"/debug/pprof/cmdline", Cmdline) + http.HandleFunc(prefix+"/debug/pprof/profile", Profile) + http.HandleFunc(prefix+"/debug/pprof/symbol", Symbol) + http.HandleFunc(prefix+"/debug/pprof/trace", Trace) } // Cmdline responds with the running program's @@ -114,9 +120,14 @@ func sleep(r *http.Request, d time.Duration) { } } -func durationExceedsWriteTimeout(r *http.Request, seconds float64) bool { +func configureWriteDeadline(w http.ResponseWriter, r *http.Request, seconds float64) { srv, ok := r.Context().Value(http.ServerContextKey).(*http.Server) - return ok && srv.WriteTimeout != 0 && seconds >= srv.WriteTimeout.Seconds() + if ok && srv.WriteTimeout > 0 { + timeout := srv.WriteTimeout + time.Duration(seconds*float64(time.Second)) + + rc := http.NewResponseController(w) + rc.SetWriteDeadline(time.Now().Add(timeout)) + } } func serveError(w http.ResponseWriter, status int, txt string) { @@ -137,10 +148,7 @@ func Profile(w http.ResponseWriter, r *http.Request) { sec = 30 } - if durationExceedsWriteTimeout(r, float64(sec)) { - serveError(w, http.StatusBadRequest, "profile duration exceeds server's WriteTimeout") - return - } + configureWriteDeadline(w, r, float64(sec)) // Set Content Type assuming StartCPUProfile will work, // because if it does it starts writing. @@ -166,10 +174,7 @@ func Trace(w http.ResponseWriter, r *http.Request) { sec = 1 } - if durationExceedsWriteTimeout(r, sec) { - serveError(w, http.StatusBadRequest, "profile duration exceeds server's WriteTimeout") - return - } + configureWriteDeadline(w, r, sec) // Set Content Type assuming trace.Start will work, // because if it does it starts writing. @@ -273,15 +278,14 @@ func (name handler) serveDeltaProfile(w http.ResponseWriter, r *http.Request, p serveError(w, http.StatusBadRequest, `invalid value for "seconds" - must be a positive integer`) return } + // 'name' should be a key in profileSupportsDelta. if !profileSupportsDelta[name] { serveError(w, http.StatusBadRequest, `"seconds" parameter is not supported for this profile type`) return } - // 'name' should be a key in profileSupportsDelta. - if durationExceedsWriteTimeout(r, float64(sec)) { - serveError(w, http.StatusBadRequest, "profile duration exceeds server's WriteTimeout") - return - } + + configureWriteDeadline(w, r, float64(sec)) + debug, _ := strconv.Atoi(r.FormValue("debug")) if debug != 0 { serveError(w, http.StatusBadRequest, "seconds and debug params are incompatible") diff --git a/contrib/go/_std_1.22/src/net/http/pprof/ya.make b/contrib/go/_std_1.23/src/net/http/pprof/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/pprof/ya.make rename to contrib/go/_std_1.23/src/net/http/pprof/ya.make diff --git a/contrib/go/_std_1.22/src/net/http/request.go b/contrib/go/_std_1.23/src/net/http/request.go similarity index 97% rename from contrib/go/_std_1.22/src/net/http/request.go rename to contrib/go/_std_1.23/src/net/http/request.go index 99fdebcf9bb8..ad1b5a620b07 100644 --- a/contrib/go/_std_1.22/src/net/http/request.go +++ b/contrib/go/_std_1.23/src/net/http/request.go @@ -25,6 +25,7 @@ import ( "strconv" "strings" "sync" + _ "unsafe" // for linkname "golang.org/x/net/http/httpguts" "golang.org/x/net/idna" @@ -320,6 +321,10 @@ type Request struct { // redirects. Response *Response + // Pattern is the [ServeMux] pattern that matched the request. + // It is empty if the request was not matched against a pattern. + Pattern string + // ctx is either the client or server context. It should only // be modified via copying the whole Request using Clone or WithContext. // It is unexported to prevent people from using Context wrong @@ -372,6 +377,8 @@ func (r *Request) WithContext(ctx context.Context) *Request { // Clone returns a deep copy of r with its context changed to ctx. // The provided ctx must be non-nil. // +// Clone only makes a shallow copy of the Body field. +// // For an outgoing client request, the context controls the entire // lifetime of a request and its response: obtaining a connection, // sending the request, and reading the response headers and body. @@ -431,6 +438,15 @@ func (r *Request) Cookies() []*Cookie { return readCookies(r.Header, "") } +// CookiesNamed parses and returns the named HTTP cookies sent with the request +// or an empty slice if none matched. +func (r *Request) CookiesNamed(name string) []*Cookie { + if name == "" { + return []*Cookie{} + } + return readCookies(r.Header, name) +} + // ErrNoCookie is returned by Request's Cookie method when a cookie is not found. var ErrNoCookie = errors.New("http: named cookie not present") @@ -455,7 +471,7 @@ func (r *Request) Cookie(name string) (*Cookie, error) { // AddCookie only sanitizes c's name and value, and does not sanitize // a Cookie header already present in the request. func (r *Request) AddCookie(c *Cookie) { - s := fmt.Sprintf("%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value)) + s := fmt.Sprintf("%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value, c.Quoted)) if c := r.Header.Get("Cookie"); c != "" { r.Header.Set("Cookie", c+"; "+s) } else { @@ -973,6 +989,16 @@ func (r *Request) BasicAuth() (username, password string, ok bool) { // parseBasicAuth parses an HTTP Basic Authentication string. // "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true). +// +// parseBasicAuth should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/sagernet/sing +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname parseBasicAuth func parseBasicAuth(auth string) (username, password string, ok bool) { const prefix = "Basic " // Case insensitive prefix match. See Issue 22736. @@ -1048,6 +1074,17 @@ func ReadRequest(b *bufio.Reader) (*Request, error) { return req, err } +// readRequest should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/sagernet/sing +// - github.com/v2fly/v2ray-core/v4 +// - github.com/v2fly/v2ray-core/v5 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname readRequest func readRequest(b *bufio.Reader) (req *Request, err error) { tp := newTextprotoReader(b) defer putTextprotoReader(tp) diff --git a/contrib/go/_std_1.22/src/net/http/response.go b/contrib/go/_std_1.23/src/net/http/response.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/response.go rename to contrib/go/_std_1.23/src/net/http/response.go diff --git a/contrib/go/_std_1.22/src/net/http/responsecontroller.go b/contrib/go/_std_1.23/src/net/http/responsecontroller.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/responsecontroller.go rename to contrib/go/_std_1.23/src/net/http/responsecontroller.go diff --git a/contrib/go/_std_1.22/src/net/http/roundtrip.go b/contrib/go/_std_1.23/src/net/http/roundtrip.go similarity index 57% rename from contrib/go/_std_1.22/src/net/http/roundtrip.go rename to contrib/go/_std_1.23/src/net/http/roundtrip.go index 08c270179afb..6674b8419f3d 100644 --- a/contrib/go/_std_1.22/src/net/http/roundtrip.go +++ b/contrib/go/_std_1.23/src/net/http/roundtrip.go @@ -6,6 +6,19 @@ package http +import _ "unsafe" // for linkname + +// RoundTrip should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/erda-project/erda-infra +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname badRoundTrip net/http.(*Transport).RoundTrip +func badRoundTrip(*Transport, *Request) (*Response, error) + // RoundTrip implements the [RoundTripper] interface. // // For higher-level HTTP client support (such as handling of cookies diff --git a/contrib/go/_std_1.22/src/net/http/roundtrip_js.go b/contrib/go/_std_1.23/src/net/http/roundtrip_js.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/roundtrip_js.go rename to contrib/go/_std_1.23/src/net/http/roundtrip_js.go diff --git a/contrib/go/_std_1.22/src/net/http/routing_index.go b/contrib/go/_std_1.23/src/net/http/routing_index.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/routing_index.go rename to contrib/go/_std_1.23/src/net/http/routing_index.go diff --git a/contrib/go/_std_1.22/src/net/http/routing_tree.go b/contrib/go/_std_1.23/src/net/http/routing_tree.go similarity index 98% rename from contrib/go/_std_1.22/src/net/http/routing_tree.go rename to contrib/go/_std_1.23/src/net/http/routing_tree.go index 8812ed04e249..fdc58ab6924e 100644 --- a/contrib/go/_std_1.22/src/net/http/routing_tree.go +++ b/contrib/go/_std_1.23/src/net/http/routing_tree.go @@ -34,8 +34,8 @@ type routingNode struct { // special children keys: // "/" trailing slash (resulting from {$}) // "" single wildcard - // "*" multi wildcard children mapping[string, *routingNode] + multiChild *routingNode // child with multi wildcard emptyChild *routingNode // optimization: child with key "" } @@ -63,7 +63,9 @@ func (n *routingNode) addSegments(segs []segment, p *pattern, h Handler) { if len(segs) != 1 { panic("multi wildcard not last") } - n.addChild("*").set(p, h) + c := &routingNode{} + n.multiChild = c + c.set(p, h) } else if seg.wild { n.addChild("").addSegments(segs[1:], p, h) } else { @@ -185,7 +187,7 @@ func (n *routingNode) matchPath(path string, matches []string) (*routingNode, [] } // Lastly, match the pattern (there can be at most one) that has a multi // wildcard in this position to the rest of the path. - if c := n.findChild("*"); c != nil { + if c := n.multiChild; c != nil { // Don't record a match for a nameless wildcard (which arises from a // trailing slash in the pattern). if c.pattern.lastSegment().s != "" { diff --git a/contrib/go/_std_1.22/src/net/http/servemux121.go b/contrib/go/_std_1.23/src/net/http/servemux121.go similarity index 96% rename from contrib/go/_std_1.22/src/net/http/servemux121.go rename to contrib/go/_std_1.23/src/net/http/servemux121.go index c0a4b7701056..923a28fb4406 100644 --- a/contrib/go/_std_1.22/src/net/http/servemux121.go +++ b/contrib/go/_std_1.23/src/net/http/servemux121.go @@ -10,6 +10,10 @@ package http // Changes are minimal: aside from the different receiver type, // they mostly involve renaming functions, usually by unexporting them. +// servemux121.go exists solely to provide a snapshot of +// the pre-Go 1.22 ServeMux implementation for backwards compatibility. +// Do not modify this file, it should remain frozen. + import ( "internal/godebug" "net/url" diff --git a/contrib/go/_std_1.22/src/net/http/server.go b/contrib/go/_std_1.23/src/net/http/server.go similarity index 95% rename from contrib/go/_std_1.22/src/net/http/server.go rename to contrib/go/_std_1.23/src/net/http/server.go index 23a603a83dd7..1ff72a04550c 100644 --- a/contrib/go/_std_1.22/src/net/http/server.go +++ b/contrib/go/_std_1.23/src/net/http/server.go @@ -16,6 +16,7 @@ import ( "internal/godebug" "io" "log" + "maps" "math/rand" "net" "net/textproto" @@ -23,12 +24,13 @@ import ( urlpkg "net/url" "path" "runtime" - "sort" + "slices" "strconv" "strings" "sync" "sync/atomic" "time" + _ "unsafe" // for linkname "golang.org/x/net/http/httpguts" ) @@ -224,7 +226,7 @@ type CloseNotifier interface { // that the channel receives a value. // // If the protocol is HTTP/1.1 and CloseNotify is called while - // processing an idempotent request (such a GET) while + // processing an idempotent request (such as GET) while // HTTP/1.1 pipelining is in use, the arrival of a subsequent // pipelined request may cause a value to be sent on the // returned channel. In practice HTTP/1.1 pipelining is not @@ -425,7 +427,6 @@ type response struct { reqBody io.ReadCloser cancelCtx context.CancelFunc // when ServeHTTP exits wroteHeader bool // a non-1xx header has been (logically) written - wroteContinue bool // 100 Continue response was written wants10KeepAlive bool // HTTP/1.0 w/ Connection "keep-alive" wantsClose bool // HTTP request has Connection "close" @@ -436,8 +437,8 @@ type response struct { // These two fields together synchronize the body reader (the // expectContinueReader, which wants to write 100 Continue) // against the main writer. - canWriteContinue atomic.Bool writeContinueMu sync.Mutex + canWriteContinue atomic.Bool w *bufio.Writer // buffers output in chunks to chunkWriter cw chunkWriter @@ -565,6 +566,14 @@ func (w *response) requestTooLarge() { } } +// disableWriteContinue stops Request.Body.Read from sending an automatic 100-Continue. +// If a 100-Continue is being written, it waits for it to complete before continuing. +func (w *response) disableWriteContinue() { + w.writeContinueMu.Lock() + w.canWriteContinue.Store(false) + w.writeContinueMu.Unlock() +} + // writerOnly hides an io.Writer value's optional ReadFrom method // from io.Copy. type writerOnly struct { @@ -830,6 +839,15 @@ func bufioWriterPool(size int) *sync.Pool { return nil } +// newBufioReader should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/gobwas/ws +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname newBufioReader func newBufioReader(r io.Reader) *bufio.Reader { if v := bufioReaderPool.Get(); v != nil { br := v.(*bufio.Reader) @@ -841,11 +859,29 @@ func newBufioReader(r io.Reader) *bufio.Reader { return bufio.NewReader(r) } +// putBufioReader should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/gobwas/ws +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname putBufioReader func putBufioReader(br *bufio.Reader) { br.Reset(nil) bufioReaderPool.Put(br) } +// newBufioWriterSize should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/gobwas/ws +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname newBufioWriterSize func newBufioWriterSize(w io.Writer, size int) *bufio.Writer { pool := bufioWriterPool(size) if pool != nil { @@ -858,6 +894,15 @@ func newBufioWriterSize(w io.Writer, size int) *bufio.Writer { return bufio.NewWriterSize(w, size) } +// putBufioWriter should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/gobwas/ws +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname putBufioWriter func putBufioWriter(bw *bufio.Writer) { bw.Reset(nil) if pool := bufioWriterPool(bw.Available()); pool != nil { @@ -917,8 +962,7 @@ func (ecr *expectContinueReader) Read(p []byte) (n int, err error) { return 0, ErrBodyReadAfterClose } w := ecr.resp - if !w.wroteContinue && w.canWriteContinue.Load() && !w.conn.hijacked() { - w.wroteContinue = true + if w.canWriteContinue.Load() { w.writeContinueMu.Lock() if w.canWriteContinue.Load() { w.conn.bufw.WriteString("HTTP/1.1 100 Continue\r\n\r\n") @@ -1102,9 +1146,9 @@ func (w *response) Header() Header { // maxPostHandlerReadBytes is the max number of Request.Body bytes not // consumed by a handler that the server will read from the client -// in order to keep a connection alive. If there are more bytes than -// this then the server to be paranoid instead sends a "Connection: -// close" response. +// in order to keep a connection alive. If there are more bytes +// than this, the server, to be paranoid, instead sends a +// "Connection close" response. // // This number is approximately what a typical machine's TCP buffer // size is anyway. (if we have the bytes on the machine, we might as @@ -1159,18 +1203,17 @@ func (w *response) WriteHeader(code int) { } checkWriteHeaderCode(code) + if code < 101 || code > 199 { + // Sending a 100 Continue or any non-1xx header disables the + // automatically-sent 100 Continue from Request.Body.Read. + w.disableWriteContinue() + } + // Handle informational headers. // // We shouldn't send any further headers after 101 Switching Protocols, // so it takes the non-informational path. if code >= 100 && code <= 199 && code != StatusSwitchingProtocols { - // Prevent a potential race with an automatically-sent 100 Continue triggered by Request.Body.Read() - if code == 100 && w.canWriteContinue.Load() { - w.writeContinueMu.Lock() - w.canWriteContinue.Store(false) - w.writeContinueMu.Unlock() - } - writeStatusLine(w.conn.bufw, w.req.ProtoAtLeast(1, 1), code, w.statusBuf[:]) // Per RFC 8297 we must not clear the current header map @@ -1383,14 +1426,20 @@ func (cw *chunkWriter) writeHeader(p []byte) { // // If full duplex mode has been enabled with ResponseController.EnableFullDuplex, // then leave the request body alone. + // + // We don't take this path when w.closeAfterReply is set. + // We may not need to consume the request to get ready for the next one + // (since we're closing the conn), but a client which sends a full request + // before reading a response may deadlock in this case. + // This behavior has been present since CL 5268043 (2011), however, + // so it doesn't seem to be causing problems. if w.req.ContentLength != 0 && !w.closeAfterReply && !w.fullDuplex { var discard, tooBig bool switch bdy := w.req.Body.(type) { case *expectContinueReader: - if bdy.resp.wroteContinue { - discard = true - } + // We only get here if we have already fully consumed the request body + // (see above). case *body: bdy.mu.Lock() switch { @@ -1631,13 +1680,8 @@ func (w *response) write(lenData int, dataB []byte, dataS string) (n int, err er } if w.canWriteContinue.Load() { - // Body reader wants to write 100 Continue but hasn't yet. - // Tell it not to. The store must be done while holding the lock - // because the lock makes sure that there is not an active write - // this very moment. - w.writeContinueMu.Lock() - w.canWriteContinue.Store(false) - w.writeContinueMu.Unlock() + // Body reader wants to write 100 Continue but hasn't yet. Tell it not to. + w.disableWriteContinue() } if !w.wroteHeader { @@ -1905,6 +1949,7 @@ func (c *conn) serve(ctx context.Context) { } if inFlightResponse != nil { inFlightResponse.cancelCtx() + inFlightResponse.disableWriteContinue() } if !c.hijacked() { if inFlightResponse != nil { @@ -1927,12 +1972,15 @@ func (c *conn) serve(ctx context.Context) { // If the handshake failed due to the client not speaking // TLS, assume they're speaking plaintext HTTP and write a // 400 response on the TLS conn's underlying net.Conn. + var reason string if re, ok := err.(tls.RecordHeaderError); ok && re.Conn != nil && tlsRecordHeaderLooksLikeHTTP(re.RecordHeader) { io.WriteString(re.Conn, "HTTP/1.0 400 Bad Request\r\n\r\nClient sent an HTTP request to an HTTPS server.\n") re.Conn.Close() - return + reason = "client sent an HTTP request to an HTTPS server" + } else { + reason = err.Error() } - c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err) + c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), reason) return } // Restore Conn-level deadlines. @@ -2066,7 +2114,7 @@ func (c *conn) serve(ctx context.Context) { return } - if d := c.server.idleTimeout(); d != 0 { + if d := c.server.idleTimeout(); d > 0 { c.rwc.SetReadDeadline(time.Now().Add(d)) } else { c.rwc.SetReadDeadline(time.Time{}) @@ -2108,6 +2156,7 @@ func (w *response) Hijack() (rwc net.Conn, buf *bufio.ReadWriter, err error) { if w.handlerDone.Load() { panic("net/http: Hijack called after ServeHTTP finished") } + w.disableWriteContinue() if w.wroteHeader { w.cw.flush() } @@ -2177,9 +2226,28 @@ func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { // It does not otherwise end the request; the caller should ensure no further // writes are done to w. // The error message should be plain text. +// +// Error deletes the Content-Length header, +// sets Content-Type to “text/plain; charset=utf-8”, +// and sets X-Content-Type-Options to “nosniff”. +// This configures the header properly for the error message, +// in case the caller had set it up expecting a successful output. func Error(w ResponseWriter, error string, code int) { - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - w.Header().Set("X-Content-Type-Options", "nosniff") + h := w.Header() + + // Delete the Content-Length header, which might be for some other content. + // Assuming the error string fits in the writer's buffer, we'll figure + // out the correct Content-Length for it later. + // + // We don't delete Content-Encoding, because some middleware sets + // Content-Encoding: gzip and wraps the ResponseWriter to compress on-the-fly. + // See https://go.dev/issue/66343. + h.Del("Content-Length") + + // There might be content type already set, but we reset it to + // text/plain for the error message. + h.Set("Content-Type", "text/plain; charset=utf-8") + h.Set("X-Content-Type-Options", "nosniff") w.WriteHeader(code) fmt.Fprintln(w, error) } @@ -2340,7 +2408,7 @@ func RedirectHandler(url string, code int) Handler { // [METHOD ][HOST]/[PATH] // // All three parts are optional; "/" is a valid pattern. -// If METHOD is present, it must be followed by a single space. +// If METHOD is present, it must be followed by at least one space or tab. // // Literal (that is, non-wildcard) parts of a pattern match // the corresponding parts of a request case-sensitively. @@ -2383,7 +2451,7 @@ func RedirectHandler(url string, code int) Handler { // There is one exception to this rule, for backwards compatibility: // if two patterns would otherwise conflict and one has a host while the other does not, // then the pattern with the host takes precedence. -// If a pattern passed [ServeMux.Handle] or [ServeMux.HandleFunc] conflicts with +// If a pattern passed to [ServeMux.Handle] or [ServeMux.HandleFunc] conflicts with // another pattern that is already registered, those functions panic. // // As an example of the general rule, "/images/thumbnails/" is more specific than "/images/", @@ -2582,8 +2650,8 @@ func (mux *ServeMux) matchOrRedirect(host, method, path string, u *url.URL) (_ * n, matches := mux.tree.match(host, method, path) // If we have an exact match, or we were asked not to try trailing-slash redirection, - // then we're done. - if !exactMatch(n, path) && u != nil { + // or the URL already has a trailing slash, then we're done. + if !exactMatch(n, path) && u != nil && !strings.HasSuffix(path, "/") { // If there is an exact match with a trailing slash, then redirect. path += "/" n2, _ := mux.tree.match(host, method, path) @@ -2654,19 +2722,10 @@ func (mux *ServeMux) matchingMethods(host, path string) []string { ms := map[string]bool{} mux.tree.matchingMethods(host, path, ms) // matchOrRedirect will try appending a trailing slash if there is no match. - mux.tree.matchingMethods(host, path+"/", ms) - methods := mapKeys(ms) - sort.Strings(methods) - return methods -} - -// TODO(jba): replace with maps.Keys when it is defined. -func mapKeys[K comparable, V any](m map[K]V) []K { - var ks []K - for k := range m { - ks = append(ks, k) + if !strings.HasSuffix(path, "/") { + mux.tree.matchingMethods(host, path+"/", ms) } - return ks + return slices.Sorted(maps.Keys(ms)) } // ServeHTTP dispatches the request to the handler whose @@ -2683,7 +2742,7 @@ func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { if use121 { h, _ = mux.mux121.findHandler(r) } else { - h, _, r.pat, r.matches = mux.findHandler(r) + h, r.Pattern, r.pat, r.matches = mux.findHandler(r) } h.ServeHTTP(w, r) } @@ -2853,9 +2912,9 @@ type Server struct { // ReadHeaderTimeout is the amount of time allowed to read // request headers. The connection's read deadline is reset // after reading the headers and the Handler can decide what - // is considered too slow for the body. If ReadHeaderTimeout - // is zero, the value of ReadTimeout is used. If both are - // zero, there is no timeout. + // is considered too slow for the body. If zero, the value of + // ReadTimeout is used. If negative, or if zero and ReadTimeout + // is zero or negative, there is no timeout. ReadHeaderTimeout time.Duration // WriteTimeout is the maximum duration before timing out @@ -2866,9 +2925,9 @@ type Server struct { WriteTimeout time.Duration // IdleTimeout is the maximum amount of time to wait for the - // next request when keep-alives are enabled. If IdleTimeout - // is zero, the value of ReadTimeout is used. If both are - // zero, there is no timeout. + // next request when keep-alives are enabled. If zero, the value + // of ReadTimeout is used. If negative, or if zero and ReadTimeout + // is zero or negative, there is no timeout. IdleTimeout time.Duration // MaxHeaderBytes controls the maximum number of bytes the @@ -3130,6 +3189,15 @@ type serverHandler struct { srv *Server } +// ServeHTTP should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/erda-project/erda-infra +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname badServeHTTP net/http.serverHandler.ServeHTTP func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { handler := sh.srv.Handler if handler == nil { @@ -3142,6 +3210,8 @@ func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { handler.ServeHTTP(rw, req) } +func badServeHTTP(serverHandler, ResponseWriter, *Request) + // AllowQuerySemicolons returns a handler that serves requests by converting any // unescaped semicolons in the URL query to ampersands, and invoking the handler h. // @@ -3210,7 +3280,7 @@ func (srv *Server) shouldConfigureHTTP2ForServe() bool { // passed this tls.Config to tls.NewListener. And if they did, // it's too late anyway to fix it. It would only be potentially racy. // See Issue 15908. - return strSliceContains(srv.TLSConfig.NextProtos, http2NextProtoTLS) + return slices.Contains(srv.TLSConfig.NextProtos, http2NextProtoTLS) } // ErrServerClosed is returned by the [Server.Serve], [ServeTLS], [ListenAndServe], @@ -3297,7 +3367,8 @@ func (srv *Server) Serve(l net.Listener) error { // // Files containing a certificate and matching private key for the // server must be provided if neither the [Server]'s -// TLSConfig.Certificates nor TLSConfig.GetCertificate are populated. +// TLSConfig.Certificates, TLSConfig.GetCertificate nor +// config.GetConfigForClient are populated. // If the certificate is signed by a certificate authority, the // certFile should be the concatenation of the server's certificate, // any intermediates, and the CA's certificate. @@ -3312,11 +3383,11 @@ func (srv *Server) ServeTLS(l net.Listener, certFile, keyFile string) error { } config := cloneTLSConfig(srv.TLSConfig) - if !strSliceContains(config.NextProtos, "http/1.1") { + if !slices.Contains(config.NextProtos, "http/1.1") { config.NextProtos = append(config.NextProtos, "http/1.1") } - configHasCert := len(config.Certificates) > 0 || config.GetCertificate != nil + configHasCert := len(config.Certificates) > 0 || config.GetCertificate != nil || config.GetConfigForClient != nil if !configHasCert || certFile != "" || keyFile != "" { var err error config.Certificates = make([]tls.Certificate, 1) @@ -3530,9 +3601,7 @@ func (srv *Server) onceSetNextProtoDefaults() { // Enable HTTP/2 by default if the user hasn't otherwise // configured their TLSNextProto map. if srv.TLSNextProto == nil { - conf := &http2Server{ - NewWriteScheduler: func() http2WriteScheduler { return http2NewPriorityWriteScheduler(nil) }, - } + conf := &http2Server{} srv.nextProtoErr = http2ConfigureServer(srv, conf) } } @@ -3819,15 +3888,6 @@ func numLeadingCRorLF(v []byte) (n int) { return } -func strSliceContains(ss []string, s string) bool { - for _, v := range ss { - if v == s { - return true - } - } - return false -} - // tlsRecordHeaderLooksLikeHTTP reports whether a TLS record header // looks like it might've been a misdirected plaintext HTTP request. func tlsRecordHeaderLooksLikeHTTP(hdr [5]byte) bool { diff --git a/contrib/go/_std_1.22/src/net/http/sniff.go b/contrib/go/_std_1.23/src/net/http/sniff.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/sniff.go rename to contrib/go/_std_1.23/src/net/http/sniff.go diff --git a/contrib/go/_std_1.22/src/net/http/socks_bundle.go b/contrib/go/_std_1.23/src/net/http/socks_bundle.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/socks_bundle.go rename to contrib/go/_std_1.23/src/net/http/socks_bundle.go diff --git a/contrib/go/_std_1.22/src/net/http/status.go b/contrib/go/_std_1.23/src/net/http/status.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/status.go rename to contrib/go/_std_1.23/src/net/http/status.go diff --git a/contrib/go/_std_1.22/src/net/http/transfer.go b/contrib/go/_std_1.23/src/net/http/transfer.go similarity index 96% rename from contrib/go/_std_1.22/src/net/http/transfer.go rename to contrib/go/_std_1.23/src/net/http/transfer.go index 315c6e2723a2..5a3c6ceff578 100644 --- a/contrib/go/_std_1.22/src/net/http/transfer.go +++ b/contrib/go/_std_1.23/src/net/http/transfer.go @@ -16,7 +16,7 @@ import ( "net/http/internal/ascii" "net/textproto" "reflect" - "sort" + "slices" "strconv" "strings" "sync" @@ -318,7 +318,7 @@ func (t *transferWriter) writeHeader(w io.Writer, trace *httptrace.ClientTrace) keys = append(keys, k) } if len(keys) > 0 { - sort.Strings(keys) + slices.Sort(keys) // TODO: could do better allocation-wise here, but trailers are rare, // so being lazy for now. if _, err := io.WriteString(w, "Trailer: "+strings.Join(keys, ",")+"\r\n"); err != nil { @@ -650,19 +650,6 @@ func (t *transferReader) parseTransferEncoding() error { return &unsupportedTEError{fmt.Sprintf("unsupported transfer encoding: %q", raw[0])} } - // RFC 7230 3.3.2 says "A sender MUST NOT send a Content-Length header field - // in any message that contains a Transfer-Encoding header field." - // - // but also: "If a message is received with both a Transfer-Encoding and a - // Content-Length header field, the Transfer-Encoding overrides the - // Content-Length. Such a message might indicate an attempt to perform - // request smuggling (Section 9.5) or response splitting (Section 9.4) and - // ought to be handled as an error. A sender MUST remove the received - // Content-Length field prior to forwarding such a message downstream." - // - // Reportedly, these appear in the wild. - delete(t.Header, "Content-Length") - t.Chunked = true return nil } @@ -670,7 +657,7 @@ func (t *transferReader) parseTransferEncoding() error { // Determine the expected body length, using RFC 7230 Section 3.3. This // function is not a method, because ultimately it should be shared by // ReadResponse and ReadRequest. -func fixLength(isResponse bool, status int, requestMethod string, header Header, chunked bool) (int64, error) { +func fixLength(isResponse bool, status int, requestMethod string, header Header, chunked bool) (n int64, err error) { isRequest := !isResponse contentLens := header["Content-Length"] @@ -694,6 +681,14 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header, contentLens = header["Content-Length"] } + // Reject requests with invalid Content-Length headers. + if len(contentLens) > 0 { + n, err = parseContentLength(contentLens) + if err != nil { + return -1, err + } + } + // Logic based on response type or status if isResponse && noResponseBodyExpected(requestMethod) { return 0, nil @@ -706,17 +701,26 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header, return 0, nil } + // According to RFC 9112, "If a message is received with both a + // Transfer-Encoding and a Content-Length header field, the Transfer-Encoding + // overrides the Content-Length. Such a message might indicate an attempt to + // perform request smuggling (Section 11.2) or response splitting (Section 11.1) + // and ought to be handled as an error. An intermediary that chooses to forward + // the message MUST first remove the received Content-Length field and process + // the Transfer-Encoding (as described below) prior to forwarding the message downstream." + // + // Chunked-encoding requests with either valid Content-Length + // headers or no Content-Length headers are accepted after removing + // the Content-Length field from header. + // // Logic based on Transfer-Encoding if chunked { + header.Del("Content-Length") return -1, nil } + // Logic based on Content-Length if len(contentLens) > 0 { - // Logic based on Content-Length - n, err := parseContentLength(contentLens) - if err != nil { - return -1, err - } return n, nil } @@ -1039,7 +1043,7 @@ func (bl bodyLocked) Read(p []byte) (n int, err error) { return bl.b.readLocked(p) } -var laxContentLength = godebug.New("httplaxcontentlength") +var httplaxcontentlength = godebug.New("httplaxcontentlength") // parseContentLength checks that the header is valid and then trims // whitespace. It returns -1 if no value is set otherwise the value @@ -1053,8 +1057,8 @@ func parseContentLength(clHeaders []string) (int64, error) { // The Content-Length must be a valid numeric value. // See: https://datatracker.ietf.org/doc/html/rfc2616/#section-14.13 if cl == "" { - if laxContentLength.Value() == "1" { - laxContentLength.IncNonDefault() + if httplaxcontentlength.Value() == "1" { + httplaxcontentlength.IncNonDefault() return -1, nil } return 0, badStringError("invalid empty Content-Length", cl) diff --git a/contrib/go/_std_1.22/src/net/http/transport.go b/contrib/go/_std_1.23/src/net/http/transport.go similarity index 88% rename from contrib/go/_std_1.22/src/net/http/transport.go rename to contrib/go/_std_1.23/src/net/http/transport.go index 66c54ef5ac95..da9163a27ae6 100644 --- a/contrib/go/_std_1.22/src/net/http/transport.go +++ b/contrib/go/_std_1.23/src/net/http/transport.go @@ -30,6 +30,7 @@ import ( "sync" "sync/atomic" "time" + _ "unsafe" "golang.org/x/net/http/httpguts" "golang.org/x/net/http/httpproxy" @@ -100,7 +101,7 @@ type Transport struct { idleLRU connLRU reqMu sync.Mutex - reqCanceler map[cancelKey]func(error) + reqCanceler map[*Request]context.CancelCauseFunc altMu sync.Mutex // guards changing altProto only altProto atomic.Value // of nil or map[string]RoundTripper, key is URI scheme @@ -108,14 +109,16 @@ type Transport struct { connsPerHostMu sync.Mutex connsPerHost map[connectMethodKey]int connsPerHostWait map[connectMethodKey]wantConnQueue // waiting getConns + dialsInProgress wantConnQueue // Proxy specifies a function to return a proxy for a given // Request. If the function returns a non-nil error, the // request is aborted with the provided error. // // The proxy type is determined by the URL scheme. "http", - // "https", and "socks5" are supported. If the scheme is empty, + // "https", "socks5", and "socks5h" are supported. If the scheme is empty, // "http" is assumed. + // "socks5" is treated the same as "socks5h". // // If the proxy URL contains a userinfo subcomponent, // the proxy request will pass the username and password @@ -292,13 +295,6 @@ type Transport struct { ForceAttemptHTTP2 bool } -// A cancelKey is the key of the reqCanceler map. -// We wrap the *Request in this type since we want to use the original request, -// not any transient one created by roundTrip. -type cancelKey struct { - req *Request -} - func (t *Transport) writeBufferSize() int { if t.WriteBufferSize > 0 { return t.WriteBufferSize @@ -440,7 +436,6 @@ func (t *Transport) onceSetNextProtoDefaults() { // // The environment values may be either a complete URL or a // "host[:port]", in which case the "http" scheme is assumed. -// The schemes "http", "https", and "socks5" are supported. // An error is returned if the value is a different form. // // A nil URL and nil error are returned if no proxy is defined in the @@ -465,10 +460,12 @@ func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error) { // optional extra headers to write and stores any error to return // from roundTrip. type transportRequest struct { - *Request // original request, not to be mutated - extra Header // extra headers to write, or nil - trace *httptrace.ClientTrace // optional - cancelKey cancelKey + *Request // original request, not to be mutated + extra Header // extra headers to write, or nil + trace *httptrace.ClientTrace // optional + + ctx context.Context // canceled when we are done with the request + cancel context.CancelCauseFunc mu sync.Mutex // guards err err error // first setError value for mapRoundTripError to consider @@ -513,8 +510,24 @@ func (t *Transport) alternateRoundTripper(req *Request) RoundTripper { return altProto[req.URL.Scheme] } +func validateHeaders(hdrs Header) string { + for k, vv := range hdrs { + if !httpguts.ValidHeaderFieldName(k) { + return fmt.Sprintf("field name %q", k) + } + for _, v := range vv { + if !httpguts.ValidHeaderFieldValue(v) { + // Don't include the value in the error, + // because it may be sensitive. + return fmt.Sprintf("field value for %q", k) + } + } + } + return "" +} + // roundTrip implements a RoundTripper over HTTP. -func (t *Transport) roundTrip(req *Request) (*Response, error) { +func (t *Transport) roundTrip(req *Request) (_ *Response, err error) { t.nextProtoOnce.Do(t.onceSetNextProtoDefaults) ctx := req.Context() trace := httptrace.ContextClientTrace(ctx) @@ -530,23 +543,20 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) { scheme := req.URL.Scheme isHTTP := scheme == "http" || scheme == "https" if isHTTP { - for k, vv := range req.Header { - if !httpguts.ValidHeaderFieldName(k) { - req.closeBody() - return nil, fmt.Errorf("net/http: invalid header field name %q", k) - } - for _, v := range vv { - if !httpguts.ValidHeaderFieldValue(v) { - req.closeBody() - // Don't include the value in the error, because it may be sensitive. - return nil, fmt.Errorf("net/http: invalid header field value for %q", k) - } - } + // Validate the outgoing headers. + if err := validateHeaders(req.Header); err != "" { + req.closeBody() + return nil, fmt.Errorf("net/http: invalid header %s", err) + } + + // Validate the outgoing trailers too. + if err := validateHeaders(req.Trailer); err != "" { + req.closeBody() + return nil, fmt.Errorf("net/http: invalid trailer %s", err) } } origReq := req - cancelKey := cancelKey{origReq} req = setupRewindBody(req) if altRT := t.alternateRoundTripper(req); altRT != nil { @@ -572,16 +582,44 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) { return nil, errors.New("http: no Host in request URL") } + // Transport request context. + // + // If RoundTrip returns an error, it cancels this context before returning. + // + // If RoundTrip returns no error: + // - For an HTTP/1 request, persistConn.readLoop cancels this context + // after reading the request body. + // - For an HTTP/2 request, RoundTrip cancels this context after the HTTP/2 + // RoundTripper returns. + ctx, cancel := context.WithCancelCause(req.Context()) + + // Convert Request.Cancel into context cancelation. + if origReq.Cancel != nil { + go awaitLegacyCancel(ctx, cancel, origReq) + } + + // Convert Transport.CancelRequest into context cancelation. + // + // This is lamentably expensive. CancelRequest has been deprecated for a long time + // and doesn't work on HTTP/2 requests. Perhaps we should drop support for it entirely. + cancel = t.prepareTransportCancel(origReq, cancel) + + defer func() { + if err != nil { + cancel(err) + } + }() + for { select { case <-ctx.Done(): req.closeBody() - return nil, ctx.Err() + return nil, context.Cause(ctx) default: } // treq gets modified by roundTrip, so we need to recreate for each retry. - treq := &transportRequest{Request: req, trace: trace, cancelKey: cancelKey} + treq := &transportRequest{Request: req, trace: trace, ctx: ctx, cancel: cancel} cm, err := t.connectMethodForRequest(treq) if err != nil { req.closeBody() @@ -594,7 +632,6 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) { // to send it requests. pconn, err := t.getConn(treq, cm) if err != nil { - t.setReqCanceler(cancelKey, nil) req.closeBody() return nil, err } @@ -602,12 +639,19 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) { var resp *Response if pconn.alt != nil { // HTTP/2 path. - t.setReqCanceler(cancelKey, nil) // not cancelable with CancelRequest resp, err = pconn.alt.RoundTrip(req) } else { resp, err = pconn.roundTrip(treq) } if err == nil { + if pconn.alt != nil { + // HTTP/2 requests are not cancelable with CancelRequest, + // so we have no further need for the request context. + // + // On the HTTP/1 path, roundTrip takes responsibility for + // canceling the context after the response body is read. + cancel(errRequestDone) + } resp.Request = origReq return resp, nil } @@ -644,6 +688,14 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) { } } +func awaitLegacyCancel(ctx context.Context, cancel context.CancelCauseFunc, req *Request) { + select { + case <-req.Cancel: + cancel(errRequestCanceled) + case <-ctx.Done(): + } +} + var errCannotRewind = errors.New("net/http: cannot rewind body after connection loss") type readTrackingBody struct { @@ -793,35 +845,54 @@ func (t *Transport) CloseIdleConnections() { pconn.close(errCloseIdleConns) } } + t.connsPerHostMu.Lock() + t.dialsInProgress.all(func(w *wantConn) { + if w.cancelCtx != nil && !w.waiting() { + w.cancelCtx() + } + }) + t.connsPerHostMu.Unlock() if t2 := t.h2transport; t2 != nil { t2.CloseIdleConnections() } } +// prepareTransportCancel sets up state to convert Transport.CancelRequest into context cancelation. +func (t *Transport) prepareTransportCancel(req *Request, origCancel context.CancelCauseFunc) context.CancelCauseFunc { + // Historically, RoundTrip has not modified the Request in any way. + // We could avoid the need to keep a map of all in-flight requests by adding + // a field to the Request containing its cancel func, and setting that field + // while the request is in-flight. Callers aren't supposed to reuse a Request + // until after the response body is closed, so this wouldn't violate any + // concurrency guarantees. + cancel := func(err error) { + origCancel(err) + t.reqMu.Lock() + delete(t.reqCanceler, req) + t.reqMu.Unlock() + } + t.reqMu.Lock() + if t.reqCanceler == nil { + t.reqCanceler = make(map[*Request]context.CancelCauseFunc) + } + t.reqCanceler[req] = cancel + t.reqMu.Unlock() + return cancel +} + // CancelRequest cancels an in-flight request by closing its connection. // CancelRequest should only be called after [Transport.RoundTrip] has returned. // // Deprecated: Use [Request.WithContext] to create a request with a // cancelable context instead. CancelRequest cannot cancel HTTP/2 -// requests. +// requests. This may become a no-op in a future release of Go. func (t *Transport) CancelRequest(req *Request) { - t.cancelRequest(cancelKey{req}, errRequestCanceled) -} - -// Cancel an in-flight request, recording the error value. -// Returns whether the request was canceled. -func (t *Transport) cancelRequest(key cancelKey, err error) bool { - // This function must not return until the cancel func has completed. - // See: https://golang.org/issue/34658 t.reqMu.Lock() - defer t.reqMu.Unlock() - cancel := t.reqCanceler[key] - delete(t.reqCanceler, key) + cancel := t.reqCanceler[req] + t.reqMu.Unlock() if cancel != nil { - cancel(err) + cancel(errRequestCanceled) } - - return cancel != nil } // @@ -957,7 +1028,7 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error { // Loop over the waiting list until we find a w that isn't done already, and hand it pconn. for q.len() > 0 { w := q.popFront() - if w.tryDeliver(pconn, nil) { + if w.tryDeliver(pconn, nil, time.Time{}) { done = true break } @@ -969,7 +1040,7 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error { // list unconditionally, for any future clients too. for q.len() > 0 { w := q.popFront() - w.tryDeliver(pconn, nil) + w.tryDeliver(pconn, nil, time.Time{}) } } if q.len() == 0 { @@ -1073,7 +1144,7 @@ func (t *Transport) queueForIdleConn(w *wantConn) (delivered bool) { list = list[:len(list)-1] continue } - delivered = w.tryDeliver(pconn, nil) + delivered = w.tryDeliver(pconn, nil, pconn.idleAt) if delivered { if pconn.alt != nil { // HTTP/2: multiple clients can share pconn. @@ -1102,7 +1173,7 @@ func (t *Transport) queueForIdleConn(w *wantConn) (delivered bool) { t.idleConnWait = make(map[connectMethodKey]wantConnQueue) } q := t.idleConnWait[w.key] - q.cleanFront() + q.cleanFrontNotWaiting() q.pushBack(w) t.idleConnWait[w.key] = q return false @@ -1148,38 +1219,6 @@ func (t *Transport) removeIdleConnLocked(pconn *persistConn) bool { return removed } -func (t *Transport) setReqCanceler(key cancelKey, fn func(error)) { - t.reqMu.Lock() - defer t.reqMu.Unlock() - if t.reqCanceler == nil { - t.reqCanceler = make(map[cancelKey]func(error)) - } - if fn != nil { - t.reqCanceler[key] = fn - } else { - delete(t.reqCanceler, key) - } -} - -// replaceReqCanceler replaces an existing cancel function. If there is no cancel function -// for the request, we don't set the function and return false. -// Since CancelRequest will clear the canceler, we can use the return value to detect if -// the request was canceled since the last setReqCancel call. -func (t *Transport) replaceReqCanceler(key cancelKey, fn func(error)) bool { - t.reqMu.Lock() - defer t.reqMu.Unlock() - _, ok := t.reqCanceler[key] - if !ok { - return false - } - if fn != nil { - t.reqCanceler[key] = fn - } else { - delete(t.reqCanceler, key) - } - return true -} - var zeroDialer net.Dialer func (t *Transport) dial(ctx context.Context, network, addr string) (net.Conn, error) { @@ -1207,9 +1246,8 @@ func (t *Transport) dial(ctx context.Context, network, addr string) (net.Conn, e // These three options are racing against each other and use // wantConn to coordinate and agree about the winning outcome. type wantConn struct { - cm connectMethod - key connectMethodKey // cm.key() - ready chan struct{} // closed when pc, err pair is delivered + cm connectMethod + key connectMethodKey // cm.key() // hooks for testing to know when dials are done // beforeDial is called in the getConn goroutine when the dial is queued. @@ -1217,45 +1255,52 @@ type wantConn struct { beforeDial func() afterDial func() - mu sync.Mutex // protects ctx, pc, err, close(ready) - ctx context.Context // context for dial, cleared after delivered or canceled - pc *persistConn - err error + mu sync.Mutex // protects ctx, done and sending of the result + ctx context.Context // context for dial, cleared after delivered or canceled + cancelCtx context.CancelFunc + done bool // true after delivered or canceled + result chan connOrError // channel to deliver connection or error +} + +type connOrError struct { + pc *persistConn + err error + idleAt time.Time } // waiting reports whether w is still waiting for an answer (connection or error). func (w *wantConn) waiting() bool { - select { - case <-w.ready: - return false - default: - return true - } + w.mu.Lock() + defer w.mu.Unlock() + + return !w.done } // getCtxForDial returns context for dial or nil if connection was delivered or canceled. func (w *wantConn) getCtxForDial() context.Context { w.mu.Lock() defer w.mu.Unlock() + return w.ctx } // tryDeliver attempts to deliver pc, err to w and reports whether it succeeded. -func (w *wantConn) tryDeliver(pc *persistConn, err error) bool { +func (w *wantConn) tryDeliver(pc *persistConn, err error, idleAt time.Time) bool { w.mu.Lock() defer w.mu.Unlock() - if w.pc != nil || w.err != nil { + if w.done { return false } - - w.ctx = nil - w.pc = pc - w.err = err - if w.pc == nil && w.err == nil { + if (pc == nil) == (err == nil) { panic("net/http: internal error: misuse of tryDeliver") } - close(w.ready) + w.ctx = nil + w.done = true + + w.result <- connOrError{pc: pc, err: err, idleAt: idleAt} + close(w.result) + return true } @@ -1263,13 +1308,16 @@ func (w *wantConn) tryDeliver(pc *persistConn, err error) bool { // If a connection has been delivered already, cancel returns it with t.putOrCloseIdleConn. func (w *wantConn) cancel(t *Transport, err error) { w.mu.Lock() - if w.pc == nil && w.err == nil { - close(w.ready) // catch misbehavior in future delivery + var pc *persistConn + if w.done { + if r, ok := <-w.result; ok { + pc = r.pc + } + } else { + close(w.result) } - pc := w.pc w.ctx = nil - w.pc = nil - w.err = err + w.done = true w.mu.Unlock() if pc != nil { @@ -1330,9 +1378,9 @@ func (q *wantConnQueue) peekFront() *wantConn { return nil } -// cleanFront pops any wantConns that are no longer waiting from the head of the +// cleanFrontNotWaiting pops any wantConns that are no longer waiting from the head of the // queue, reporting whether any were popped. -func (q *wantConnQueue) cleanFront() (cleaned bool) { +func (q *wantConnQueue) cleanFrontNotWaiting() (cleaned bool) { for { w := q.peekFront() if w == nil || w.waiting() { @@ -1343,6 +1391,28 @@ func (q *wantConnQueue) cleanFront() (cleaned bool) { } } +// cleanFrontCanceled pops any wantConns with canceled dials from the head of the queue. +func (q *wantConnQueue) cleanFrontCanceled() { + for { + w := q.peekFront() + if w == nil || w.cancelCtx != nil { + return + } + q.popFront() + } +} + +// all iterates over all wantConns in the queue. +// The caller must not modify the queue while iterating. +func (q *wantConnQueue) all(f func(*wantConn)) { + for _, w := range q.head[q.headPos:] { + f(w) + } + for _, w := range q.tail { + f(w) + } +} + func (t *Transport) customDialTLS(ctx context.Context, network, addr string) (conn net.Conn, err error) { if t.DialTLSContext != nil { conn, err = t.DialTLSContext(ctx, network, addr) @@ -1359,7 +1429,7 @@ func (t *Transport) customDialTLS(ctx context.Context, network, addr string) (co // specified in the connectMethod. This includes doing a proxy CONNECT // and/or setting up TLS. If this doesn't return an error, the persistConn // is ready to write requests to. -func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persistConn, err error) { +func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (_ *persistConn, err error) { req := treq.Request trace := treq.trace ctx := req.Context() @@ -1367,11 +1437,19 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persi trace.GetConn(cm.addr()) } + // Detach from the request context's cancellation signal. + // The dial should proceed even if the request is canceled, + // because a future request may be able to make use of the connection. + // + // We retain the request context's values. + dialCtx, dialCancel := context.WithCancel(context.WithoutCancel(ctx)) + w := &wantConn{ cm: cm, key: cm.key(), - ctx: ctx, - ready: make(chan struct{}, 1), + ctx: dialCtx, + cancelCtx: dialCancel, + result: make(chan connOrError, 1), beforeDial: testHookPrePendingDial, afterDial: testHookPostPendingDial, } @@ -1382,44 +1460,33 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persi }() // Queue for idle connection. - if delivered := t.queueForIdleConn(w); delivered { - pc := w.pc - // Trace only for HTTP/1. - // HTTP/2 calls trace.GotConn itself. - if pc.alt == nil && trace != nil && trace.GotConn != nil { - trace.GotConn(pc.gotIdleConnTrace(pc.idleAt)) - } - // set request canceler to some non-nil function so we - // can detect whether it was cleared between now and when - // we enter roundTrip - t.setReqCanceler(treq.cancelKey, func(error) {}) - return pc, nil + if delivered := t.queueForIdleConn(w); !delivered { + t.queueForDial(w) } - cancelc := make(chan error, 1) - t.setReqCanceler(treq.cancelKey, func(err error) { cancelc <- err }) - - // Queue for permission to dial. - t.queueForDial(w) - // Wait for completion or cancellation. select { - case <-w.ready: + case r := <-w.result: // Trace success but only for HTTP/1. // HTTP/2 calls trace.GotConn itself. - if w.pc != nil && w.pc.alt == nil && trace != nil && trace.GotConn != nil { - trace.GotConn(httptrace.GotConnInfo{Conn: w.pc.conn, Reused: w.pc.isReused()}) + if r.pc != nil && r.pc.alt == nil && trace != nil && trace.GotConn != nil { + info := httptrace.GotConnInfo{ + Conn: r.pc.conn, + Reused: r.pc.isReused(), + } + if !r.idleAt.IsZero() { + info.WasIdle = true + info.IdleTime = time.Since(r.idleAt) + } + trace.GotConn(info) } - if w.err != nil { + if r.err != nil { // If the request has been canceled, that's probably - // what caused w.err; if so, prefer to return the + // what caused r.err; if so, prefer to return the // cancellation error (see golang.org/issue/16049). select { - case <-req.Cancel: - return nil, errRequestCanceledConn - case <-req.Context().Done(): - return nil, req.Context().Err() - case err := <-cancelc: + case <-treq.ctx.Done(): + err := context.Cause(treq.ctx) if err == errRequestCanceled { err = errRequestCanceledConn } @@ -1428,12 +1495,9 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persi // return below } } - return w.pc, w.err - case <-req.Cancel: - return nil, errRequestCanceledConn - case <-req.Context().Done(): - return nil, req.Context().Err() - case err := <-cancelc: + return r.pc, r.err + case <-treq.ctx.Done(): + err := context.Cause(treq.ctx) if err == errRequestCanceled { err = errRequestCanceledConn } @@ -1445,20 +1509,21 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (pc *persi // Once w receives permission to dial, it will do so in a separate goroutine. func (t *Transport) queueForDial(w *wantConn) { w.beforeDial() - if t.MaxConnsPerHost <= 0 { - go t.dialConnFor(w) - return - } t.connsPerHostMu.Lock() defer t.connsPerHostMu.Unlock() + if t.MaxConnsPerHost <= 0 { + t.startDialConnForLocked(w) + return + } + if n := t.connsPerHost[w.key]; n < t.MaxConnsPerHost { if t.connsPerHost == nil { t.connsPerHost = make(map[connectMethodKey]int) } t.connsPerHost[w.key] = n + 1 - go t.dialConnFor(w) + t.startDialConnForLocked(w) return } @@ -1466,11 +1531,24 @@ func (t *Transport) queueForDial(w *wantConn) { t.connsPerHostWait = make(map[connectMethodKey]wantConnQueue) } q := t.connsPerHostWait[w.key] - q.cleanFront() + q.cleanFrontNotWaiting() q.pushBack(w) t.connsPerHostWait[w.key] = q } +// startDialConnFor calls dialConn in a new goroutine. +// t.connsPerHostMu must be held. +func (t *Transport) startDialConnForLocked(w *wantConn) { + t.dialsInProgress.cleanFrontCanceled() + t.dialsInProgress.pushBack(w) + go func() { + t.dialConnFor(w) + t.connsPerHostMu.Lock() + defer t.connsPerHostMu.Unlock() + w.cancelCtx = nil + }() +} + // dialConnFor dials on behalf of w and delivers the result to w. // dialConnFor has received permission to dial w.cm and is counted in t.connCount[w.cm.key()]. // If the dial is canceled or unsuccessful, dialConnFor decrements t.connCount[w.cm.key()]. @@ -1483,7 +1561,7 @@ func (t *Transport) dialConnFor(w *wantConn) { } pc, err := t.dialConn(ctx, w.cm) - delivered := w.tryDeliver(pc, err) + delivered := w.tryDeliver(pc, err, time.Time{}) if err == nil && (!delivered || pc.alt != nil) { // pconn was not passed to w, // or it is HTTP/2 and can be shared. @@ -1520,7 +1598,7 @@ func (t *Transport) decConnsPerHost(key connectMethodKey) { for q.len() > 0 { w := q.popFront() if w.waiting() { - go t.dialConnFor(w) + t.startDialConnForLocked(w) done = true break } @@ -1601,6 +1679,8 @@ type erringRoundTripper interface { RoundTripErr() error } +var testHookProxyConnectTimeout = context.WithTimeout + func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *persistConn, err error) { pconn = &persistConn{ t: t, @@ -1665,7 +1745,7 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers switch { case cm.proxyURL == nil: // Do nothing. Not using a proxy. - case cm.proxyURL.Scheme == "socks5": + case cm.proxyURL.Scheme == "socks5" || cm.proxyURL.Scheme == "socks5h": conn := pconn.conn d := socksNewDialer("tcp", conn.RemoteAddr().String()) if u := cm.proxyURL.User; u != nil { @@ -1717,17 +1797,11 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers Header: hdr, } - // If there's no done channel (no deadline or cancellation - // from the caller possible), at least set some (long) - // timeout here. This will make sure we don't block forever - // and leak a goroutine if the connection stops replying - // after the TCP connect. - connectCtx := ctx - if ctx.Done() == nil { - newCtx, cancel := context.WithTimeout(ctx, 1*time.Minute) - defer cancel() - connectCtx = newCtx - } + // Set a (long) timeout here to make sure we don't block forever + // and leak a goroutine if the connection stops replying after + // the TCP connect. + connectCtx, cancel := testHookProxyConnectTimeout(ctx, 1*time.Minute) + defer cancel() didReadResponse := make(chan struct{}) // closed after CONNECT write+read is done or fails var ( @@ -1762,6 +1836,7 @@ func (t *Transport) dialConn(ctx context.Context, cm connectMethod) (pconn *pers if t.OnProxyConnectResponse != nil { err = t.OnProxyConnectResponse(ctx, cm.proxyURL, connectReq, resp) if err != nil { + conn.Close() return nil, err } } @@ -2006,18 +2081,6 @@ func (pc *persistConn) isReused() bool { return r } -func (pc *persistConn) gotIdleConnTrace(idleAt time.Time) (t httptrace.GotConnInfo) { - pc.mu.Lock() - defer pc.mu.Unlock() - t.Reused = pc.reused - t.Conn = pc.conn - t.WasIdle = true - if !idleAt.IsZero() { - t.IdleTime = time.Since(idleAt) - } - return -} - func (pc *persistConn) cancelRequest(err error) { pc.mu.Lock() defer pc.mu.Unlock() @@ -2110,7 +2173,8 @@ func (pc *persistConn) readLoop() { pc.t.removeIdleConn(pc) }() - tryPutIdleConn := func(trace *httptrace.ClientTrace) bool { + tryPutIdleConn := func(treq *transportRequest) bool { + trace := treq.trace if err := pc.t.tryPutIdleConn(pc); err != nil { closeErr = err if trace != nil && trace.PutIdleConn != nil && err != errKeepAlivesDisabled { @@ -2149,7 +2213,7 @@ func (pc *persistConn) readLoop() { pc.mu.Unlock() rc := <-pc.reqch - trace := httptrace.ContextClientTrace(rc.req.Context()) + trace := rc.treq.trace var resp *Response if err == nil { @@ -2178,9 +2242,9 @@ func (pc *persistConn) readLoop() { pc.mu.Unlock() bodyWritable := resp.bodyIsWritable() - hasBody := rc.req.Method != "HEAD" && resp.ContentLength != 0 + hasBody := rc.treq.Request.Method != "HEAD" && resp.ContentLength != 0 - if resp.Close || rc.req.Close || resp.StatusCode <= 199 || bodyWritable { + if resp.Close || rc.treq.Request.Close || resp.StatusCode <= 199 || bodyWritable { // Don't do keep-alive on error if either party requested a close // or we get an unexpected informational (1xx) response. // StatusCode 100 is already handled above. @@ -2188,8 +2252,6 @@ func (pc *persistConn) readLoop() { } if !hasBody || bodyWritable { - replaced := pc.t.replaceReqCanceler(rc.cancelKey, nil) - // Put the idle conn back into the pool before we send the response // so if they process it quickly and make another request, they'll // get this same conn. But we use the unbuffered channel 'rc' @@ -2198,7 +2260,7 @@ func (pc *persistConn) readLoop() { alive = alive && !pc.sawEOF && pc.wroteRequest() && - replaced && tryPutIdleConn(trace) + tryPutIdleConn(rc.treq) if bodyWritable { closeErr = errCallerOwnsConn @@ -2210,6 +2272,8 @@ func (pc *persistConn) readLoop() { return } + rc.treq.cancel(errRequestDone) + // Now that they've read from the unbuffered channel, they're safely // out of the select that also waits on this goroutine to die, so // we're allowed to exit now if needed (if alive is false) @@ -2260,25 +2324,22 @@ func (pc *persistConn) readLoop() { // reading the response body. (or for cancellation or death) select { case bodyEOF := <-waitForBodyRead: - replaced := pc.t.replaceReqCanceler(rc.cancelKey, nil) // before pc might return to idle pool alive = alive && bodyEOF && !pc.sawEOF && pc.wroteRequest() && - replaced && tryPutIdleConn(trace) + tryPutIdleConn(rc.treq) if bodyEOF { eofc <- struct{}{} } - case <-rc.req.Cancel: + case <-rc.treq.ctx.Done(): alive = false - pc.t.cancelRequest(rc.cancelKey, errRequestCanceled) - case <-rc.req.Context().Done(): - alive = false - pc.t.cancelRequest(rc.cancelKey, rc.req.Context().Err()) + pc.cancelRequest(context.Cause(rc.treq.ctx)) case <-pc.closech: alive = false } + rc.treq.cancel(errRequestDone) testHookReadLoopBeforeNextRead() } } @@ -2331,7 +2392,7 @@ func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTr continueCh := rc.continueCh for { - resp, err = ReadResponse(pc.br, rc.req) + resp, err = ReadResponse(pc.br, rc.treq.Request) if err != nil { return } @@ -2377,7 +2438,7 @@ func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTr // Conceivably, it's one that doesn't need us to send the body. // Given that we'll send the body if ExpectContinueTimeout expires, // be consistent and always send it if we aren't closing the connection. - if resp.Close || rc.req.Close { + if resp.Close || rc.treq.Request.Close { close(continueCh) // don't send the body; the connection will close } else { continueCh <- struct{}{} // send the body @@ -2537,10 +2598,9 @@ type responseAndError struct { } type requestAndChan struct { - _ incomparable - req *Request - cancelKey cancelKey - ch chan responseAndError // unbuffered; always send in select on callerGone + _ incomparable + treq *transportRequest + ch chan responseAndError // unbuffered; always send in select on callerGone // whether the Transport (as opposed to the user client code) // added the Accept-Encoding gzip header. If the Transport @@ -2570,22 +2630,28 @@ type writeRequest struct { continueCh <-chan struct{} } -type httpError struct { - err string - timeout bool +// httpTimeoutError represents a timeout. +// It implements net.Error and wraps context.DeadlineExceeded. +type timeoutError struct { + err string } -func (e *httpError) Error() string { return e.err } -func (e *httpError) Timeout() bool { return e.timeout } -func (e *httpError) Temporary() bool { return true } +func (e *timeoutError) Error() string { return e.err } +func (e *timeoutError) Timeout() bool { return true } +func (e *timeoutError) Temporary() bool { return true } +func (e *timeoutError) Is(err error) bool { return err == context.DeadlineExceeded } -var errTimeout error = &httpError{err: "net/http: timeout awaiting response headers", timeout: true} +var errTimeout error = &timeoutError{"net/http: timeout awaiting response headers"} // errRequestCanceled is set to be identical to the one from h2 to facilitate // testing. var errRequestCanceled = http2errRequestCanceled var errRequestCanceledConn = errors.New("net/http: request canceled while waiting for connection") // TODO: unify? +// errRequestDone is used to cancel the round trip Context after a request is successfully done. +// It should not be seen by the user. +var errRequestDone = errors.New("net/http: request completed") + func nop() {} // testHooks. Always non-nil. @@ -2602,10 +2668,6 @@ var ( func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) { testHookEnterRoundTrip() - if !pc.t.replaceReqCanceler(req.cancelKey, pc.cancelRequest) { - pc.t.putOrCloseIdleConn(pc) - return nil, errRequestCanceled - } pc.mu.Lock() pc.numExpectedResponses++ headerFn := pc.mutateHeaderFunc @@ -2654,12 +2716,6 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err gone := make(chan struct{}) defer close(gone) - defer func() { - if err != nil { - pc.t.setReqCanceler(req.cancelKey, nil) - } - }() - const debugRoundTrip = false // Write the request concurrently with waiting for a response, @@ -2671,25 +2727,35 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err resc := make(chan responseAndError) pc.reqch <- requestAndChan{ - req: req.Request, - cancelKey: req.cancelKey, + treq: req, ch: resc, addedGzip: requestedGzip, continueCh: continueCh, callerGone: gone, } + handleResponse := func(re responseAndError) (*Response, error) { + if (re.res == nil) == (re.err == nil) { + panic(fmt.Sprintf("internal error: exactly one of res or err should be set; nil=%v", re.res == nil)) + } + if debugRoundTrip { + req.logf("resc recv: %p, %T/%#v", re.res, re.err, re.err) + } + if re.err != nil { + return nil, pc.mapRoundTripError(req, startBytesWritten, re.err) + } + return re.res, nil + } + var respHeaderTimer <-chan time.Time - cancelChan := req.Request.Cancel - ctxDoneChan := req.Context().Done() + ctxDoneChan := req.ctx.Done() pcClosed := pc.closech - canceled := false for { testHookWaitResLoop() select { case err := <-writeErrCh: if debugRoundTrip { - req.logf("writeErrCh resv: %T/%#v", err, err) + req.logf("writeErrCh recv: %T/%#v", err, err) } if err != nil { pc.close(fmt.Errorf("write error: %w", err)) @@ -2704,13 +2770,18 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err respHeaderTimer = timer.C } case <-pcClosed: - pcClosed = nil - if canceled || pc.t.replaceReqCanceler(req.cancelKey, nil) { - if debugRoundTrip { - req.logf("closech recv: %T %#v", pc.closed, pc.closed) - } - return nil, pc.mapRoundTripError(req, startBytesWritten, pc.closed) + select { + case re := <-resc: + // The pconn closing raced with the response to the request, + // probably after the server wrote a response and immediately + // closed the connection. Use the response. + return handleResponse(re) + default: } + if debugRoundTrip { + req.logf("closech recv: %T %#v", pc.closed, pc.closed) + } + return nil, pc.mapRoundTripError(req, startBytesWritten, pc.closed) case <-respHeaderTimer: if debugRoundTrip { req.logf("timeout waiting for response headers.") @@ -2718,23 +2789,17 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err pc.close(errTimeout) return nil, errTimeout case re := <-resc: - if (re.res == nil) == (re.err == nil) { - panic(fmt.Sprintf("internal error: exactly one of res or err should be set; nil=%v", re.res == nil)) - } - if debugRoundTrip { - req.logf("resc recv: %p, %T/%#v", re.res, re.err, re.err) - } - if re.err != nil { - return nil, pc.mapRoundTripError(req, startBytesWritten, re.err) - } - return re.res, nil - case <-cancelChan: - canceled = pc.t.cancelRequest(req.cancelKey, errRequestCanceled) - cancelChan = nil + return handleResponse(re) case <-ctxDoneChan: - canceled = pc.t.cancelRequest(req.cancelKey, req.Context().Err()) - cancelChan = nil - ctxDoneChan = nil + select { + case re := <-resc: + // readLoop is responsible for canceling req.ctx after + // it reads the response body. Check for a response racing + // the context close, and use the response if available. + return handleResponse(re) + default: + } + pc.cancelRequest(context.Cause(req.ctx)) } } } @@ -2789,9 +2854,10 @@ func (pc *persistConn) closeLocked(err error) { } var portMap = map[string]string{ - "http": "80", - "https": "443", - "socks5": "1080", + "http": "80", + "https": "443", + "socks5": "1080", + "socks5h": "1080", } func idnaASCIIFromURL(url *url.URL) string { @@ -2932,6 +2998,16 @@ func (fakeLocker) Unlock() {} // cloneTLSConfig returns a shallow clone of cfg, or a new zero tls.Config if // cfg is nil. This is safe to call even if cfg is in active use by a TLS // client or server. +// +// cloneTLSConfig should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/searKing/golang +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cloneTLSConfig func cloneTLSConfig(cfg *tls.Config) *tls.Config { if cfg == nil { return &tls.Config{} diff --git a/contrib/go/_std_1.22/src/net/http/transport_default_other.go b/contrib/go/_std_1.23/src/net/http/transport_default_other.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/transport_default_other.go rename to contrib/go/_std_1.23/src/net/http/transport_default_other.go diff --git a/contrib/go/_std_1.22/src/net/http/transport_default_wasm.go b/contrib/go/_std_1.23/src/net/http/transport_default_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/transport_default_wasm.go rename to contrib/go/_std_1.23/src/net/http/transport_default_wasm.go diff --git a/contrib/go/_std_1.22/src/net/http/triv.go b/contrib/go/_std_1.23/src/net/http/triv.go similarity index 100% rename from contrib/go/_std_1.22/src/net/http/triv.go rename to contrib/go/_std_1.23/src/net/http/triv.go diff --git a/contrib/go/_std_1.22/src/net/http/ya.make b/contrib/go/_std_1.23/src/net/http/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/http/ya.make rename to contrib/go/_std_1.23/src/net/http/ya.make diff --git a/contrib/go/_std_1.22/src/net/interface.go b/contrib/go/_std_1.23/src/net/interface.go similarity index 95% rename from contrib/go/_std_1.22/src/net/interface.go rename to contrib/go/_std_1.23/src/net/interface.go index 20ac07d31a4a..74bb4f0e1c61 100644 --- a/contrib/go/_std_1.22/src/net/interface.go +++ b/contrib/go/_std_1.23/src/net/interface.go @@ -9,6 +9,7 @@ import ( "internal/itoa" "sync" "time" + _ "unsafe" ) // BUG(mikio): On JS, methods and functions related to @@ -17,6 +18,16 @@ import ( // BUG(mikio): On AIX, DragonFly BSD, NetBSD, OpenBSD, Plan 9 and // Solaris, the MulticastAddrs method of Interface is not implemented. +// errNoSuchInterface should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/sagernet/sing +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname errNoSuchInterface + var ( errInvalidInterface = errors.New("invalid network interface") errInvalidInterfaceIndex = errors.New("invalid network interface index") diff --git a/contrib/go/_std_1.22/src/net/interface_aix.go b/contrib/go/_std_1.23/src/net/interface_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_aix.go rename to contrib/go/_std_1.23/src/net/interface_aix.go diff --git a/contrib/go/_std_1.22/src/net/interface_bsd.go b/contrib/go/_std_1.23/src/net/interface_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_bsd.go rename to contrib/go/_std_1.23/src/net/interface_bsd.go diff --git a/contrib/go/_std_1.22/src/net/interface_bsdvar.go b/contrib/go/_std_1.23/src/net/interface_bsdvar.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_bsdvar.go rename to contrib/go/_std_1.23/src/net/interface_bsdvar.go diff --git a/contrib/go/_std_1.22/src/net/interface_darwin.go b/contrib/go/_std_1.23/src/net/interface_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_darwin.go rename to contrib/go/_std_1.23/src/net/interface_darwin.go diff --git a/contrib/go/_std_1.22/src/net/interface_freebsd.go b/contrib/go/_std_1.23/src/net/interface_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_freebsd.go rename to contrib/go/_std_1.23/src/net/interface_freebsd.go diff --git a/contrib/go/_std_1.22/src/net/interface_linux.go b/contrib/go/_std_1.23/src/net/interface_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_linux.go rename to contrib/go/_std_1.23/src/net/interface_linux.go diff --git a/contrib/go/_std_1.22/src/net/interface_plan9.go b/contrib/go/_std_1.23/src/net/interface_plan9.go similarity index 98% rename from contrib/go/_std_1.22/src/net/interface_plan9.go rename to contrib/go/_std_1.23/src/net/interface_plan9.go index 92b2eed2591b..7c44566acf01 100644 --- a/contrib/go/_std_1.22/src/net/interface_plan9.go +++ b/contrib/go/_std_1.23/src/net/interface_plan9.go @@ -7,6 +7,7 @@ package net import ( "errors" "internal/itoa" + "internal/stringslite" "os" ) @@ -70,7 +71,7 @@ func readInterface(i int) (*Interface, error) { ifc.MTU = mtu // Not a loopback device ("/dev/null") or packet interface (e.g. "pkt2") - if stringsHasPrefix(device, netdir+"/") { + if stringslite.HasPrefix(device, netdir+"/") { deviceaddrf, err := open(device + "/addr") if err != nil { return nil, err diff --git a/contrib/go/_std_1.22/src/net/interface_solaris.go b/contrib/go/_std_1.23/src/net/interface_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_solaris.go rename to contrib/go/_std_1.23/src/net/interface_solaris.go diff --git a/contrib/go/_std_1.22/src/net/interface_stub.go b/contrib/go/_std_1.23/src/net/interface_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/interface_stub.go rename to contrib/go/_std_1.23/src/net/interface_stub.go diff --git a/contrib/go/_std_1.22/src/net/interface_windows.go b/contrib/go/_std_1.23/src/net/interface_windows.go similarity index 96% rename from contrib/go/_std_1.22/src/net/interface_windows.go rename to contrib/go/_std_1.23/src/net/interface_windows.go index 22a13128499b..1b487dc47482 100644 --- a/contrib/go/_std_1.22/src/net/interface_windows.go +++ b/contrib/go/_std_1.23/src/net/interface_windows.go @@ -20,7 +20,8 @@ func adapterAddresses() ([]*windows.IpAdapterAddresses, error) { l := uint32(15000) // recommended initial size for { b = make([]byte, l) - err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l) + const flags = windows.GAA_FLAG_INCLUDE_PREFIX | windows.GAA_FLAG_INCLUDE_GATEWAYS + err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, flags, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l) if err == nil { if l == 0 { return nil, nil diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/switch.go b/contrib/go/_std_1.23/src/net/internal/socktest/switch.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/switch.go rename to contrib/go/_std_1.23/src/net/internal/socktest/switch.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/switch_posix.go b/contrib/go/_std_1.23/src/net/internal/socktest/switch_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/switch_posix.go rename to contrib/go/_std_1.23/src/net/internal/socktest/switch_posix.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/switch_stub.go b/contrib/go/_std_1.23/src/net/internal/socktest/switch_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/switch_stub.go rename to contrib/go/_std_1.23/src/net/internal/socktest/switch_stub.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/switch_unix.go b/contrib/go/_std_1.23/src/net/internal/socktest/switch_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/switch_unix.go rename to contrib/go/_std_1.23/src/net/internal/socktest/switch_unix.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/switch_windows.go b/contrib/go/_std_1.23/src/net/internal/socktest/switch_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/switch_windows.go rename to contrib/go/_std_1.23/src/net/internal/socktest/switch_windows.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/sys_cloexec.go b/contrib/go/_std_1.23/src/net/internal/socktest/sys_cloexec.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/sys_cloexec.go rename to contrib/go/_std_1.23/src/net/internal/socktest/sys_cloexec.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/sys_unix.go b/contrib/go/_std_1.23/src/net/internal/socktest/sys_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/sys_unix.go rename to contrib/go/_std_1.23/src/net/internal/socktest/sys_unix.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/sys_windows.go b/contrib/go/_std_1.23/src/net/internal/socktest/sys_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/sys_windows.go rename to contrib/go/_std_1.23/src/net/internal/socktest/sys_windows.go diff --git a/contrib/go/_std_1.22/src/net/internal/socktest/ya.make b/contrib/go/_std_1.23/src/net/internal/socktest/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/socktest/ya.make rename to contrib/go/_std_1.23/src/net/internal/socktest/ya.make diff --git a/contrib/go/_std_1.22/src/net/internal/ya.make b/contrib/go/_std_1.23/src/net/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/internal/ya.make rename to contrib/go/_std_1.23/src/net/internal/ya.make diff --git a/contrib/go/_std_1.22/src/net/ip.go b/contrib/go/_std_1.23/src/net/ip.go similarity index 98% rename from contrib/go/_std_1.22/src/net/ip.go rename to contrib/go/_std_1.23/src/net/ip.go index 6083dd8bf9f6..3e0e85e168a7 100644 --- a/contrib/go/_std_1.22/src/net/ip.go +++ b/contrib/go/_std_1.23/src/net/ip.go @@ -15,6 +15,7 @@ package net import ( "internal/bytealg" "internal/itoa" + "internal/stringslite" "net/netip" ) @@ -490,7 +491,8 @@ func (n *IPNet) String() string { // The string s can be in IPv4 dotted decimal ("192.0.2.1"), IPv6 // ("2001:db8::68"), or IPv4-mapped IPv6 ("::ffff:192.0.2.1") form. // If s is not a valid textual representation of an IP address, -// ParseIP returns nil. +// ParseIP returns nil. The returned address is always 16 bytes, +// IPv4 addresses are returned in IPv4-mapped IPv6 form. func ParseIP(s string) IP { if addr, valid := parseIP(s); valid { return IP(addr[:]) @@ -515,11 +517,10 @@ func parseIP(s string) ([16]byte, bool) { // For example, ParseCIDR("192.0.2.1/24") returns the IP address // 192.0.2.1 and the network 192.0.2.0/24. func ParseCIDR(s string) (IP, *IPNet, error) { - i := bytealg.IndexByteString(s, '/') - if i < 0 { + addr, mask, found := stringslite.Cut(s, "/") + if !found { return nil, nil, &ParseError{Type: "CIDR address", Text: s} } - addr, mask := s[:i], s[i+1:] ipAddr, err := netip.ParseAddr(addr) if err != nil || ipAddr.Zone() != "" { diff --git a/contrib/go/_std_1.22/src/net/iprawsock.go b/contrib/go/_std_1.23/src/net/iprawsock.go similarity index 100% rename from contrib/go/_std_1.22/src/net/iprawsock.go rename to contrib/go/_std_1.23/src/net/iprawsock.go diff --git a/contrib/go/_std_1.22/src/net/iprawsock_plan9.go b/contrib/go/_std_1.23/src/net/iprawsock_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/iprawsock_plan9.go rename to contrib/go/_std_1.23/src/net/iprawsock_plan9.go diff --git a/contrib/go/_std_1.22/src/net/iprawsock_posix.go b/contrib/go/_std_1.23/src/net/iprawsock_posix.go similarity index 95% rename from contrib/go/_std_1.22/src/net/iprawsock_posix.go rename to contrib/go/_std_1.23/src/net/iprawsock_posix.go index 73b41ab5226a..b25cb648c3dc 100644 --- a/contrib/go/_std_1.22/src/net/iprawsock_posix.go +++ b/contrib/go/_std_1.23/src/net/iprawsock_posix.go @@ -124,7 +124,7 @@ func (sd *sysDialer) dialIP(ctx context.Context, laddr, raddr *IPAddr) (*IPConn, } ctrlCtxFn := sd.Dialer.ControlContext if ctrlCtxFn == nil && sd.Dialer.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sd.Dialer.Control(network, address, c) } } @@ -145,9 +145,9 @@ func (sl *sysListener) listenIP(ctx context.Context, laddr *IPAddr) (*IPConn, er default: return nil, UnknownNetworkError(sl.network) } - var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error + var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error if sl.ListenConfig.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sl.ListenConfig.Control(network, address, c) } } diff --git a/contrib/go/_std_1.22/src/net/ipsock.go b/contrib/go/_std_1.23/src/net/ipsock.go similarity index 95% rename from contrib/go/_std_1.22/src/net/ipsock.go rename to contrib/go/_std_1.23/src/net/ipsock.go index 176dbc748e66..496faf346ec1 100644 --- a/contrib/go/_std_1.22/src/net/ipsock.go +++ b/contrib/go/_std_1.23/src/net/ipsock.go @@ -9,6 +9,7 @@ import ( "internal/bytealg" "runtime" "sync" + _ "unsafe" // for linkname ) // BUG(rsc,mikio): On DragonFly BSD and OpenBSD, listening on the @@ -307,6 +308,17 @@ func (r *Resolver) internetAddrList(ctx context.Context, net, addr string) (addr return filterAddrList(filter, ips, inetaddr, host) } +// loopbackIP should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/database64128/tfo-go/v2 +// - github.com/metacubex/tfo-go +// - github.com/sagernet/tfo-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname loopbackIP func loopbackIP(net string) IP { if net != "" && net[len(net)-1] == '6' { return IPv6loopback diff --git a/contrib/go/_std_1.22/src/net/ipsock_plan9.go b/contrib/go/_std_1.23/src/net/ipsock_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/ipsock_plan9.go rename to contrib/go/_std_1.23/src/net/ipsock_plan9.go diff --git a/contrib/go/_std_1.22/src/net/ipsock_posix.go b/contrib/go/_std_1.23/src/net/ipsock_posix.go similarity index 91% rename from contrib/go/_std_1.22/src/net/ipsock_posix.go rename to contrib/go/_std_1.23/src/net/ipsock_posix.go index 67ce1479c647..2aeabd44873f 100644 --- a/contrib/go/_std_1.22/src/net/ipsock_posix.go +++ b/contrib/go/_std_1.23/src/net/ipsock_posix.go @@ -12,6 +12,7 @@ import ( "net/netip" "runtime" "syscall" + _ "unsafe" // for linkname ) // probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication @@ -118,6 +119,18 @@ func (p *ipStackCapabilities) probe() { // Note that the latest DragonFly BSD and OpenBSD kernels allow // neither "net.inet6.ip6.v6only=1" change nor IPPROTO_IPV6 level // IPV6_V6ONLY socket option setting. +// +// favoriteAddrFamily should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/database64128/tfo-go/v2 +// - github.com/metacubex/tfo-go +// - github.com/sagernet/tfo-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname favoriteAddrFamily func favoriteAddrFamily(network string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) { switch network[len(network)-1] { case '4': @@ -192,6 +205,17 @@ func ipToSockaddrInet6(ip IP, port int, zone string) (syscall.SockaddrInet6, err return sa, nil } +// ipToSockaddr should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/database64128/tfo-go/v2 +// - github.com/metacubex/tfo-go +// - github.com/sagernet/tfo-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname ipToSockaddr func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, error) { switch family { case syscall.AF_INET: diff --git a/contrib/go/_std_1.22/src/net/lookup.go b/contrib/go/_std_1.23/src/net/lookup.go similarity index 97% rename from contrib/go/_std_1.22/src/net/lookup.go rename to contrib/go/_std_1.23/src/net/lookup.go index 3ec266078609..b04dfa23b987 100644 --- a/contrib/go/_std_1.22/src/net/lookup.go +++ b/contrib/go/_std_1.23/src/net/lookup.go @@ -105,7 +105,7 @@ func lookupPortMapWithNetwork(network, errNetwork, service string) (port int, er if port, ok := m[string(lowerService[:n])]; ok && n == len(service) { return port, nil } - return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true} + return 0, newDNSError(errUnknownPort, errNetwork+"/"+service, "") } return 0, &DNSError{Err: "unknown network", Name: errNetwork + "/" + service} } @@ -192,7 +192,7 @@ func LookupHost(host string) (addrs []string, err error) { func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) { // Make sure that no matter what we do later, host=="" is rejected. if host == "" { - return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} + return nil, newDNSError(errNoSuchHost, host, "") } if _, err := netip.ParseAddr(host); err == nil { return []string{host}, nil @@ -236,7 +236,7 @@ func (r *Resolver) LookupIP(ctx context.Context, network, host string) ([]IP, er } if host == "" { - return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} + return nil, newDNSError(errNoSuchHost, host, "") } addrs, err := r.internetAddrList(ctx, afnet, host) if err != nil { @@ -304,7 +304,7 @@ func withUnexpiredValuesPreserved(lookupCtx context.Context) context.Context { func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IPAddr, error) { // Make sure that no matter what we do later, host=="" is rejected. if host == "" { - return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} + return nil, newDNSError(errNoSuchHost, host, "") } if ip, err := netip.ParseAddr(host); err == nil { return []IPAddr{{IP: IP(ip.AsSlice()).To16(), Zone: ip.Zone()}}, nil @@ -354,12 +354,7 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IP } else { go dnsWaitGroupDone(ch, lookupGroupCancel) } - ctxErr := ctx.Err() - err := &DNSError{ - Err: mapErr(ctxErr).Error(), - Name: host, - IsTimeout: ctxErr == context.DeadlineExceeded, - } + err := newDNSError(mapErr(ctx.Err()), host, "") if trace != nil && trace.DNSDone != nil { trace.DNSDone(nil, false, err) } @@ -370,17 +365,7 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IP err := r.Err if err != nil { if _, ok := err.(*DNSError); !ok { - isTimeout := false - if err == context.DeadlineExceeded { - isTimeout = true - } else if terr, ok := err.(timeout); ok { - isTimeout = terr.Timeout() - } - err = &DNSError{ - Err: err.Error(), - Name: host, - IsTimeout: isTimeout, - } + err = newDNSError(mapErr(err), host, "") } } if trace != nil && trace.DNSDone != nil { diff --git a/contrib/go/_std_1.22/src/net/lookup_plan9.go b/contrib/go/_std_1.23/src/net/lookup_plan9.go similarity index 93% rename from contrib/go/_std_1.22/src/net/lookup_plan9.go rename to contrib/go/_std_1.23/src/net/lookup_plan9.go index 8cfc4f6bb3b0..e3e371611f44 100644 --- a/contrib/go/_std_1.22/src/net/lookup_plan9.go +++ b/contrib/go/_std_1.23/src/net/lookup_plan9.go @@ -9,6 +9,7 @@ import ( "errors" "internal/bytealg" "internal/itoa" + "internal/stringslite" "io" "os" ) @@ -107,19 +108,13 @@ func queryDNS(ctx context.Context, addr string, typ string) (res []string, err e } func handlePlan9DNSError(err error, name string) error { - if stringsHasSuffix(err.Error(), "dns: name does not exist") || - stringsHasSuffix(err.Error(), "dns: resource does not exist; negrcode 0") || - stringsHasSuffix(err.Error(), "dns: resource does not exist; negrcode") { - return &DNSError{ - Err: errNoSuchHost.Error(), - Name: name, - IsNotFound: true, - } - } - return &DNSError{ - Err: err.Error(), - Name: name, + if stringslite.HasSuffix(err.Error(), "dns: name does not exist") || + stringslite.HasSuffix(err.Error(), "dns: resource does not exist; negrcode 0") || + stringslite.HasSuffix(err.Error(), "dns: resource does not exist; negrcode") || + stringslite.HasSuffix(err.Error(), "dns failure") { + err = errNoSuchHost } + return newDNSError(err, name, "") } // toLower returns a lower-case version of in. Restricting us to @@ -169,9 +164,6 @@ func (*Resolver) lookupHost(ctx context.Context, host string) (addrs []string, e // host names in local network (e.g. from /lib/ndb/local) lines, err := queryCS(ctx, "net", host, "1") if err != nil { - if stringsHasSuffix(err.Error(), "dns failure") { - return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true} - } return nil, handlePlan9DNSError(err, host) } loop: @@ -236,7 +228,7 @@ func (r *Resolver) lookupPort(ctx context.Context, network, service string) (por func (*Resolver) lookupPortWithNetwork(ctx context.Context, network, errNetwork, service string) (port int, err error) { lines, err := queryCS(ctx, network, "127.0.0.1", toLower(service)) if err != nil { - if stringsHasSuffix(err.Error(), "can't translate service") { + if stringslite.HasSuffix(err.Error(), "can't translate service") { return 0, &DNSError{Err: "unknown port", Name: errNetwork + "/" + service, IsNotFound: true} } return @@ -265,7 +257,9 @@ func (r *Resolver) lookupCNAME(ctx context.Context, name string) (cname string, lines, err := queryDNS(ctx, name, "cname") if err != nil { - if stringsHasSuffix(err.Error(), "dns failure") || stringsHasSuffix(err.Error(), "resource does not exist; negrcode 0") { + if stringslite.HasSuffix(err.Error(), "dns failure") || + stringslite.HasSuffix(err.Error(), "resource does not exist; negrcode 0") || + stringslite.HasSuffix(err.Error(), "resource does not exist; negrcode") { return absDomainName(name), nil } return "", handlePlan9DNSError(err, cname) diff --git a/contrib/go/_std_1.22/src/net/lookup_unix.go b/contrib/go/_std_1.23/src/net/lookup_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/lookup_unix.go rename to contrib/go/_std_1.23/src/net/lookup_unix.go diff --git a/contrib/go/_std_1.22/src/net/lookup_windows.go b/contrib/go/_std_1.23/src/net/lookup_windows.go similarity index 81% rename from contrib/go/_std_1.22/src/net/lookup_windows.go rename to contrib/go/_std_1.23/src/net/lookup_windows.go index 3048f3269b00..7d415bee4f07 100644 --- a/contrib/go/_std_1.22/src/net/lookup_windows.go +++ b/contrib/go/_std_1.23/src/net/lookup_windows.go @@ -54,7 +54,10 @@ func lookupProtocol(ctx context.Context, name string) (int, error) { } ch := make(chan result) // unbuffered go func() { - acquireThread() + if err := acquireThread(ctx); err != nil { + ch <- result{err: mapErr(err)} + return + } defer releaseThread() runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -70,12 +73,7 @@ func lookupProtocol(ctx context.Context, name string) (int, error) { if proto, err := lookupProtocolMap(name); err == nil { return proto, nil } - - dnsError := &DNSError{Err: r.err.Error(), Name: name} - if r.err == errNoSuchHost { - dnsError.IsNotFound = true - } - r.err = dnsError + r.err = newDNSError(r.err, name, "") } return r.proto, r.err case <-ctx.Done(): @@ -111,7 +109,13 @@ func (r *Resolver) lookupIP(ctx context.Context, network, name string) ([]IPAddr } getaddr := func() ([]IPAddr, error) { - acquireThread() + if err := acquireThread(ctx); err != nil { + return nil, &DNSError{ + Name: name, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() hints := syscall.AddrinfoW{ Family: family, @@ -121,7 +125,7 @@ func (r *Resolver) lookupIP(ctx context.Context, network, name string) ([]IPAddr var result *syscall.AddrinfoW name16p, err := syscall.UTF16PtrFromString(name) if err != nil { - return nil, &DNSError{Name: name, Err: err.Error()} + return nil, newDNSError(err, name, "") } dnsConf := getSystemDNSConfig() @@ -135,12 +139,7 @@ func (r *Resolver) lookupIP(ctx context.Context, network, name string) ([]IPAddr } } if e != nil { - err := winError("getaddrinfow", e) - dnsError := &DNSError{Err: err.Error(), Name: name} - if err == errNoSuchHost { - dnsError.IsNotFound = true - } - return nil, dnsError + return nil, newDNSError(winError("getaddrinfow", e), name, "") } defer syscall.FreeAddrInfoW(result) addrs := make([]IPAddr, 0, 5) @@ -155,7 +154,7 @@ func (r *Resolver) lookupIP(ctx context.Context, network, name string) ([]IPAddr zone := zoneCache.name(int((*syscall.RawSockaddrInet6)(addr).Scope_id)) addrs = append(addrs, IPAddr{IP: copyIP(a[:]), Zone: zone}) default: - return nil, &DNSError{Err: syscall.EWINDOWS.Error(), Name: name} + return nil, newDNSError(syscall.EWINDOWS, name, "") } } return addrs, nil @@ -187,11 +186,7 @@ func (r *Resolver) lookupIP(ctx context.Context, network, name string) ([]IPAddr // // For now we just let it finish and write to the // buffered channel. - return nil, &DNSError{ - Name: name, - Err: ctx.Err().Error(), - IsTimeout: ctx.Err() == context.DeadlineExceeded, - } + return nil, newDNSError(mapErr(ctx.Err()), name, "") } } @@ -200,8 +195,14 @@ func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int return lookupPortMap(network, service) } - // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this. - acquireThread() + // TODO(bradfitz): finish ctx plumbing + if err := acquireThread(ctx); err != nil { + return 0, &DNSError{ + Name: network + "/" + service, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() var hints syscall.AddrinfoW @@ -237,14 +238,13 @@ func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int // for _WSAHOST_NOT_FOUND here to match the cgo (unix) version // cgo_unix.go (cgoLookupServicePort). if e == _WSATYPE_NOT_FOUND || e == _WSAHOST_NOT_FOUND { - return 0, &DNSError{Err: "unknown port", Name: network + "/" + service, IsNotFound: true} + return 0, newDNSError(errUnknownPort, network+"/"+service, "") } - err := os.NewSyscallError("getaddrinfow", e) - return 0, &DNSError{Err: err.Error(), Name: network + "/" + service} + return 0, newDNSError(winError("getaddrinfow", e), network+"/"+service, "") } defer syscall.FreeAddrInfoW(result) if result == nil { - return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service} + return 0, newDNSError(syscall.EINVAL, network+"/"+service, "") } addr := unsafe.Pointer(result.Addr) switch result.Family { @@ -255,7 +255,7 @@ func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int a := (*syscall.RawSockaddrInet6)(addr) return int(syscall.Ntohs(a.Port)), nil } - return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service} + return 0, newDNSError(syscall.EINVAL, network+"/"+service, "") } func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) { @@ -263,8 +263,14 @@ func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) return r.goLookupCNAME(ctx, name, order, conf) } - // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this. - acquireThread() + // TODO(bradfitz): finish ctx plumbing + if err := acquireThread(ctx); err != nil { + return "", &DNSError{ + Name: name, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() var rec *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &rec, nil) @@ -274,8 +280,7 @@ func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) return absDomainName(name), nil } if e != nil { - err := winError("dnsquery", e) - return "", &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} + return "", newDNSError(winError("dnsquery", e), name, "") } defer syscall.DnsRecordListFree(rec, 1) @@ -288,8 +293,14 @@ func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) ( if systemConf().mustUseGoResolver(r) { return r.goLookupSRV(ctx, service, proto, name) } - // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this. - acquireThread() + // TODO(bradfitz): finish ctx plumbing + if err := acquireThread(ctx); err != nil { + return "", nil, &DNSError{ + Name: name, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() var target string if service == "" && proto == "" { @@ -300,8 +311,7 @@ func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) ( var rec *syscall.DNSRecord e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &rec, nil) if e != nil { - err := winError("dnsquery", e) - return "", nil, &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} + return "", nil, newDNSError(winError("dnsquery", e), name, "") } defer syscall.DnsRecordListFree(rec, 1) @@ -318,14 +328,19 @@ func (r *Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) { if systemConf().mustUseGoResolver(r) { return r.goLookupMX(ctx, name) } - // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this. - acquireThread() + // TODO(bradfitz): finish ctx plumbing. + if err := acquireThread(ctx); err != nil { + return nil, &DNSError{ + Name: name, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() var rec *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &rec, nil) if e != nil { - err := winError("dnsquery", e) - return nil, &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} + return nil, newDNSError(winError("dnsquery", e), name, "") } defer syscall.DnsRecordListFree(rec, 1) @@ -342,14 +357,19 @@ func (r *Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) { if systemConf().mustUseGoResolver(r) { return r.goLookupNS(ctx, name) } - // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this. - acquireThread() + // TODO(bradfitz): finish ctx plumbing. + if err := acquireThread(ctx); err != nil { + return nil, &DNSError{ + Name: name, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() var rec *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_NS, 0, nil, &rec, nil) if e != nil { - err := winError("dnsquery", e) - return nil, &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} + return nil, newDNSError(winError("dnsquery", e), name, "") } defer syscall.DnsRecordListFree(rec, 1) @@ -365,14 +385,19 @@ func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) if systemConf().mustUseGoResolver(r) { return r.goLookupTXT(ctx, name) } - // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this. - acquireThread() + // TODO(bradfitz): finish ctx plumbing. + if err := acquireThread(ctx); err != nil { + return nil, &DNSError{ + Name: name, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() var rec *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &rec, nil) if e != nil { - err := winError("dnsquery", e) - return nil, &DNSError{Err: err.Error(), Name: name, IsNotFound: err == errNoSuchHost} + return nil, newDNSError(winError("dnsquery", e), name, "") } defer syscall.DnsRecordListFree(rec, 1) @@ -393,8 +418,14 @@ func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error return r.goLookupPTR(ctx, addr, order, conf) } - // TODO(bradfitz): finish ctx plumbing. Nothing currently depends on this. - acquireThread() + // TODO(bradfitz): finish ctx plumbing. + if err := acquireThread(ctx); err != nil { + return nil, &DNSError{ + Name: addr, + Err: mapErr(err).Error(), + IsTimeout: ctx.Err() == context.DeadlineExceeded, + } + } defer releaseThread() arpa, err := reverseaddr(addr) if err != nil { @@ -403,8 +434,7 @@ func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error var rec *syscall.DNSRecord e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &rec, nil) if e != nil { - err := winError("dnsquery", e) - return nil, &DNSError{Err: err.Error(), Name: addr, IsNotFound: err == errNoSuchHost} + return nil, newDNSError(winError("dnsquery", e), addr, "") } defer syscall.DnsRecordListFree(rec, 1) diff --git a/contrib/go/_std_1.22/src/net/mac.go b/contrib/go/_std_1.23/src/net/mac.go similarity index 100% rename from contrib/go/_std_1.22/src/net/mac.go rename to contrib/go/_std_1.23/src/net/mac.go diff --git a/contrib/go/_std_1.22/src/net/mail/message.go b/contrib/go/_std_1.23/src/net/mail/message.go similarity index 93% rename from contrib/go/_std_1.22/src/net/mail/message.go rename to contrib/go/_std_1.23/src/net/mail/message.go index fc2a9e46f811..21b075e78aff 100644 --- a/contrib/go/_std_1.22/src/net/mail/message.go +++ b/contrib/go/_std_1.23/src/net/mail/message.go @@ -13,7 +13,6 @@ Notable divergences: - The full range of spacing (the CFWS syntax element) is not supported, such as breaking addresses across lines. - No unicode normalization is performed. - - The special characters ()[]:;@\, are allowed to appear unquoted in names. - A leading From line is permitted, as in mbox format (RFC 4155). */ package mail @@ -25,6 +24,7 @@ import ( "io" "log" "mime" + "net" "net/textproto" "strings" "sync" @@ -554,10 +554,19 @@ func (p *addrParser) consumeAddrSpec() (spec string, err error) { if p.empty() { return "", errors.New("mail: no domain in addr-spec") } - // TODO(dsymonds): Handle domain-literal - domain, err = p.consumeAtom(true, false) - if err != nil { - return "", err + + if p.peek() == '[' { + // domain-literal + domain, err = p.consumeDomainLiteral() + if err != nil { + return "", err + } + } else { + // dot-atom + domain, err = p.consumeAtom(true, false) + if err != nil { + return "", err + } } return localPart + "@" + domain, nil @@ -708,6 +717,48 @@ Loop: return atom, nil } +// consumeDomainLiteral parses an RFC 5322 domain-literal at the start of p. +func (p *addrParser) consumeDomainLiteral() (string, error) { + // Skip the leading [ + if !p.consume('[') { + return "", errors.New(`mail: missing "[" in domain-literal`) + } + + // Parse the dtext + var dtext string + for { + if p.empty() { + return "", errors.New("mail: unclosed domain-literal") + } + if p.peek() == ']' { + break + } + + r, size := utf8.DecodeRuneInString(p.s) + if size == 1 && r == utf8.RuneError { + return "", fmt.Errorf("mail: invalid utf-8 in domain-literal: %q", p.s) + } + if !isDtext(r) { + return "", fmt.Errorf("mail: bad character in domain-literal: %q", r) + } + + dtext += p.s[:size] + p.s = p.s[size:] + } + + // Skip the trailing ] + if !p.consume(']') { + return "", errors.New("mail: unclosed domain-literal") + } + + // Check if the domain literal is an IP address + if net.ParseIP(dtext) == nil { + return "", fmt.Errorf("mail: invalid IP address in domain-literal: %q", dtext) + } + + return "[" + dtext + "]", nil +} + func (p *addrParser) consumeDisplayNameComment() (string, error) { if !p.consume('(') { return "", errors.New("mail: comment does not start with (") @@ -913,3 +964,12 @@ func isMultibyte(r rune) bool { func isWSP(r rune) bool { return r == ' ' || r == '\t' } + +// isDtext reports whether r is an RFC 5322 dtext character. +func isDtext(r rune) bool { + // Printable US-ASCII, excluding "[", "]", or "\". + if r == '[' || r == ']' || r == '\\' { + return false + } + return isVchar(r) +} diff --git a/contrib/go/_std_1.22/src/net/mail/ya.make b/contrib/go/_std_1.23/src/net/mail/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/mail/ya.make rename to contrib/go/_std_1.23/src/net/mail/ya.make diff --git a/contrib/go/_std_1.22/src/net/mptcpsock_linux.go b/contrib/go/_std_1.23/src/net/mptcpsock_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/net/mptcpsock_linux.go rename to contrib/go/_std_1.23/src/net/mptcpsock_linux.go diff --git a/contrib/go/_std_1.22/src/net/mptcpsock_stub.go b/contrib/go/_std_1.23/src/net/mptcpsock_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/mptcpsock_stub.go rename to contrib/go/_std_1.23/src/net/mptcpsock_stub.go diff --git a/contrib/go/_std_1.22/src/net/net.go b/contrib/go/_std_1.23/src/net/net.go similarity index 90% rename from contrib/go/_std_1.22/src/net/net.go rename to contrib/go/_std_1.23/src/net/net.go index 2dd1b5865e5d..f8b5834acba5 100644 --- a/contrib/go/_std_1.22/src/net/net.go +++ b/contrib/go/_std_1.23/src/net/net.go @@ -46,16 +46,19 @@ It can use a pure Go resolver that sends DNS requests directly to the servers listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C library routines such as getaddrinfo and getnameinfo. -By default the pure Go resolver is used, because a blocked DNS request consumes -only a goroutine, while a blocked C call consumes an operating system thread. +On Unix the pure Go resolver is preferred over the cgo resolver, because a blocked DNS +request consumes only a goroutine, while a blocked C call consumes an operating system thread. When cgo is available, the cgo-based resolver is used instead under a variety of conditions: on systems that do not let programs make direct DNS requests (OS X), when the LOCALDOMAIN environment variable is present (even if empty), when the RES_OPTIONS or HOSTALIASES environment variable is non-empty, when the ASR_CONFIG environment variable is non-empty (OpenBSD only), when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the -Go resolver does not implement, and when the name being looked up ends in .local -or is an mDNS name. +Go resolver does not implement. + +On all systems (except Plan 9), when the cgo resolver is being used +this package applies a concurrent cgo lookup limit to prevent the system +from running out of system threads. Currently, it is limited to 500 concurrent lookups. The resolver decision can be overridden by setting the netdns value of the GODEBUG environment variable (see package runtime) to go or cgo, as in: @@ -97,6 +100,7 @@ import ( "sync" "syscall" "time" + _ "unsafe" // for linkname ) // Addr represents a network end point address. @@ -375,6 +379,18 @@ var listenerBacklogCache struct { } // listenerBacklog is a caching wrapper around maxListenerBacklog. +// +// listenerBacklog should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/database64128/tfo-go/v2 +// - github.com/metacubex/tfo-go +// - github.com/sagernet/tfo-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname listenerBacklog func listenerBacklog() int { listenerBacklogCache.Do(func() { listenerBacklogCache.val = maxListenerBacklog() }) return listenerBacklogCache.val @@ -620,11 +636,27 @@ func (e *DNSConfigError) Temporary() bool { return false } // Various errors contained in DNSError. var ( - errNoSuchHost = errors.New("no such host") + errNoSuchHost = ¬FoundError{"no such host"} + errUnknownPort = ¬FoundError{"unknown port"} ) +// notFoundError is a special error understood by the newDNSError function, +// which causes a creation of a DNSError with IsNotFound field set to true. +type notFoundError struct{ s string } + +func (e *notFoundError) Error() string { return e.s } + +// temporaryError is an error type that implements the [Error] interface. +// It returns true from the Temporary method. +type temporaryError struct{ s string } + +func (e *temporaryError) Error() string { return e.s } +func (e *temporaryError) Temporary() bool { return true } +func (e *temporaryError) Timeout() bool { return false } + // DNSError represents a DNS lookup error. type DNSError struct { + UnwrapErr error // error returned by the [DNSError.Unwrap] method, might be nil Err string // description of the error Name string // name looked for Server string // server used @@ -637,6 +669,41 @@ type DNSError struct { IsNotFound bool } +// newDNSError creates a new *DNSError. +// Based on the err, it sets the UnwrapErr, IsTimeout, IsTemporary, IsNotFound fields. +func newDNSError(err error, name, server string) *DNSError { + var ( + isTimeout bool + isTemporary bool + unwrapErr error + ) + + if err, ok := err.(Error); ok { + isTimeout = err.Timeout() + isTemporary = err.Temporary() + } + + // At this time, the only errors we wrap are context errors, to allow + // users to check for canceled/timed out requests. + if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) { + unwrapErr = err + } + + _, isNotFound := err.(*notFoundError) + return &DNSError{ + UnwrapErr: unwrapErr, + Err: err.Error(), + Name: name, + Server: server, + IsTimeout: isTimeout, + IsTemporary: isTemporary, + IsNotFound: isNotFound, + } +} + +// Unwrap returns e.UnwrapErr. +func (e *DNSError) Unwrap() error { return e.UnwrapErr } + func (e *DNSError) Error() string { if e == nil { return "" @@ -729,11 +796,16 @@ var threadLimit chan struct{} var threadOnce sync.Once -func acquireThread() { +func acquireThread(ctx context.Context) error { threadOnce.Do(func() { threadLimit = make(chan struct{}, concurrentThreadsLimit()) }) - threadLimit <- struct{}{} + select { + case threadLimit <- struct{}{}: + return nil + case <-ctx.Done(): + return ctx.Err() + } } func releaseThread() { diff --git a/contrib/go/_std_1.22/src/net/net_fake.go b/contrib/go/_std_1.23/src/net/net_fake.go similarity index 96% rename from contrib/go/_std_1.22/src/net/net_fake.go rename to contrib/go/_std_1.23/src/net/net_fake.go index 525ff3229683..f7eb28e01ac3 100644 --- a/contrib/go/_std_1.22/src/net/net_fake.go +++ b/contrib/go/_std_1.23/src/net/net_fake.go @@ -14,7 +14,6 @@ import ( "errors" "io" "os" - "runtime" "sync" "sync/atomic" "syscall" @@ -23,7 +22,6 @@ import ( var ( sockets sync.Map // fakeSockAddr → *netFD - fakeSocketIDs sync.Map // fakeNetFD.id → *netFD fakePorts sync.Map // int (port #) → *netFD nextPortCounter atomic.Int32 ) @@ -326,14 +324,27 @@ func (ffd *fakeNetFD) accept(laddr Addr) (*netFD, error) { incoming []*netFD ok bool ) + expired := ffd.readDeadline.Load().expired select { - case <-ffd.readDeadline.Load().expired: + case <-expired: return nil, os.ErrDeadlineExceeded case incoming, ok = <-ffd.incoming: if !ok { return nil, ErrClosed } + select { + case <-expired: + ffd.incoming <- incoming + return nil, os.ErrDeadlineExceeded + default: + } case incoming, ok = <-ffd.incomingFull: + select { + case <-expired: + ffd.incomingFull <- incoming + return nil, os.ErrDeadlineExceeded + default: + } } peer := incoming[0] @@ -448,16 +459,6 @@ func (pq *packetQueue) put(q packetQueueState) { func (pq *packetQueue) closeRead() error { q := pq.get() - - // Discard any unread packets. - for q.head != nil { - p := q.head - q.head = p.next - p.clear() - packetPool.Put(p) - } - q.nBytes = 0 - q.readClosed = true pq.put(q) return nil @@ -515,14 +516,6 @@ func (pq *packetQueue) send(dt *deadlineTimer, b []byte, from sockaddr, block bo full = pq.full } - // Before we check dt.expired, yield to other goroutines. - // This may help to prevent starvation of the goroutine that runs the - // deadlineTimer's time.After callback. - // - // TODO(#65178): Remove this when the runtime scheduler no longer starves - // runnable goroutines. - runtime.Gosched() - select { case <-dt.expired: return 0, os.ErrDeadlineExceeded @@ -545,7 +538,7 @@ func (pq *packetQueue) send(dt *deadlineTimer, b []byte, from sockaddr, block bo } if q.writeClosed { return 0, ErrClosed - } else if q.readClosed { + } else if q.readClosed && q.nBytes >= q.readBufferBytes { return 0, os.NewSyscallError("send", syscall.ECONNRESET) } @@ -574,14 +567,6 @@ func (pq *packetQueue) recvfrom(dt *deadlineTimer, b []byte, wholePacket bool, c empty = pq.empty } - // Before we check dt.expired, yield to other goroutines. - // This may help to prevent starvation of the goroutine that runs the - // deadlineTimer's time.After callback. - // - // TODO(#65178): Remove this when the runtime scheduler no longer starves - // runnable goroutines. - runtime.Gosched() - select { case <-dt.expired: return 0, nil, os.ErrDeadlineExceeded @@ -591,11 +576,13 @@ func (pq *packetQueue) recvfrom(dt *deadlineTimer, b []byte, wholePacket bool, c } defer func() { pq.put(q) }() + if q.readClosed { + return 0, nil, ErrClosed + } + p := q.head if p == nil { switch { - case q.readClosed: - return 0, nil, ErrClosed case q.writeClosed: if q.noLinger { return 0, nil, os.NewSyscallError("recvfrom", syscall.ECONNRESET) diff --git a/contrib/go/_std_1.22/src/net/netcgo_off.go b/contrib/go/_std_1.23/src/net/netcgo_off.go similarity index 100% rename from contrib/go/_std_1.22/src/net/netcgo_off.go rename to contrib/go/_std_1.23/src/net/netcgo_off.go diff --git a/contrib/go/_std_1.22/src/net/netcgo_on.go b/contrib/go/_std_1.23/src/net/netcgo_on.go similarity index 100% rename from contrib/go/_std_1.22/src/net/netcgo_on.go rename to contrib/go/_std_1.23/src/net/netcgo_on.go diff --git a/contrib/go/_std_1.22/src/net/netgo_netcgo.go b/contrib/go/_std_1.23/src/net/netgo_netcgo.go similarity index 100% rename from contrib/go/_std_1.22/src/net/netgo_netcgo.go rename to contrib/go/_std_1.23/src/net/netgo_netcgo.go diff --git a/contrib/go/_std_1.22/src/net/netgo_off.go b/contrib/go/_std_1.23/src/net/netgo_off.go similarity index 100% rename from contrib/go/_std_1.22/src/net/netgo_off.go rename to contrib/go/_std_1.23/src/net/netgo_off.go diff --git a/contrib/go/_std_1.22/src/net/netgo_on.go b/contrib/go/_std_1.23/src/net/netgo_on.go similarity index 100% rename from contrib/go/_std_1.22/src/net/netgo_on.go rename to contrib/go/_std_1.23/src/net/netgo_on.go diff --git a/contrib/go/_std_1.22/src/net/netip/netip.go b/contrib/go/_std_1.23/src/net/netip/netip.go similarity index 91% rename from contrib/go/_std_1.22/src/net/netip/netip.go rename to contrib/go/_std_1.23/src/net/netip/netip.go index 92cb57efef9a..a1e93cb29bfb 100644 --- a/contrib/go/_std_1.22/src/net/netip/netip.go +++ b/contrib/go/_std_1.23/src/net/netip/netip.go @@ -14,12 +14,12 @@ package netip import ( "cmp" "errors" - "math" - "strconv" - "internal/bytealg" - "internal/intern" + "internal/byteorder" "internal/itoa" + "math" + "strconv" + "unique" ) // Sizes: (64-bit) @@ -53,22 +53,22 @@ type Addr struct { // bytewise processing. addr uint128 - // z is a combination of the address family and the IPv6 zone. - // - // nil means invalid IP address (for a zero Addr). - // z4 means an IPv4 address. - // z6noz means an IPv6 address without a zone. - // - // Otherwise it's the interned zone name string. - z *intern.Value + // Details about the address, wrapped up together and canonicalized. + z unique.Handle[addrDetail] +} + +// addrDetail represents the details of an Addr, like address family and IPv6 zone. +type addrDetail struct { + isV6 bool // IPv4 is false, IPv6 is true. + zoneV6 string // != "" only if IsV6 is true. } // z0, z4, and z6noz are sentinel Addr.z values. // See the Addr type's field docs. var ( - z0 = (*intern.Value)(nil) - z4 = new(intern.Value) - z6noz = new(intern.Value) + z0 unique.Handle[addrDetail] + z4 = unique.Make(addrDetail{}) + z6noz = unique.Make(addrDetail{isV6: true}) ) // IPv6LinkLocalAllNodes returns the IPv6 link-local all nodes multicast @@ -102,8 +102,8 @@ func AddrFrom4(addr [4]byte) Addr { func AddrFrom16(addr [16]byte) Addr { return Addr{ addr: uint128{ - beUint64(addr[:8]), - beUint64(addr[8:]), + byteorder.BeUint64(addr[:8]), + byteorder.BeUint64(addr[8:]), }, z: z6noz, } @@ -152,44 +152,53 @@ func (err parseAddrError) Error() string { return "ParseAddr(" + q(err.in) + "): " + err.msg } -// parseIPv4 parses s as an IPv4 address (in form "192.168.0.1"). -func parseIPv4(s string) (ip Addr, err error) { - var fields [4]uint8 +func parseIPv4Fields(in string, off, end int, fields []uint8) error { var val, pos int var digLen int // number of digits in current octet + s := in[off:end] for i := 0; i < len(s); i++ { if s[i] >= '0' && s[i] <= '9' { if digLen == 1 && val == 0 { - return Addr{}, parseAddrError{in: s, msg: "IPv4 field has octet with leading zero"} + return parseAddrError{in: in, msg: "IPv4 field has octet with leading zero"} } val = val*10 + int(s[i]) - '0' digLen++ if val > 255 { - return Addr{}, parseAddrError{in: s, msg: "IPv4 field has value >255"} + return parseAddrError{in: in, msg: "IPv4 field has value >255"} } } else if s[i] == '.' { // .1.2.3 // 1.2.3. // 1..2.3 if i == 0 || i == len(s)-1 || s[i-1] == '.' { - return Addr{}, parseAddrError{in: s, msg: "IPv4 field must have at least one digit", at: s[i:]} + return parseAddrError{in: in, msg: "IPv4 field must have at least one digit", at: s[i:]} } // 1.2.3.4.5 if pos == 3 { - return Addr{}, parseAddrError{in: s, msg: "IPv4 address too long"} + return parseAddrError{in: in, msg: "IPv4 address too long"} } fields[pos] = uint8(val) pos++ val = 0 digLen = 0 } else { - return Addr{}, parseAddrError{in: s, msg: "unexpected character", at: s[i:]} + return parseAddrError{in: in, msg: "unexpected character", at: s[i:]} } } if pos < 3 { - return Addr{}, parseAddrError{in: s, msg: "IPv4 address too short"} + return parseAddrError{in: in, msg: "IPv4 address too short"} } fields[3] = uint8(val) + return nil +} + +// parseIPv4 parses s as an IPv4 address (in form "192.168.0.1"). +func parseIPv4(s string) (ip Addr, err error) { + var fields [4]uint8 + err = parseIPv4Fields(s, 0, len(s), fields[:]) + if err != nil { + return Addr{}, err + } return AddrFrom4(fields), nil } @@ -242,6 +251,10 @@ func parseIPv6(in string) (Addr, error) { } else { break } + if off > 3 { + //more than 4 digits in group, fail. + return Addr{}, parseAddrError{in: in, msg: "each group must have 4 or less digits", at: s} + } if acc > math.MaxUint16 { // Overflow, fail. return Addr{}, parseAddrError{in: in, msg: "IPv6 field has value >=2^16", at: s} @@ -262,17 +275,15 @@ func parseIPv6(in string) (Addr, error) { // Not enough room. return Addr{}, parseAddrError{in: in, msg: "too many hex fields to fit an embedded IPv4 at the end of the address", at: s} } - // TODO: could make this a bit faster by having a helper - // that parses to a [4]byte, and have both parseIPv4 and - // parseIPv6 use it. - ip4, err := parseIPv4(s) + + end := len(in) + if len(zone) > 0 { + end -= len(zone) + 1 + } + err := parseIPv4Fields(in, end-len(s), end, ip[i:i+4]) if err != nil { - return Addr{}, parseAddrError{in: in, msg: err.Error(), at: s} + return Addr{}, err } - ip[i] = ip4.v4(0) - ip[i+1] = ip4.v4(1) - ip[i+2] = ip4.v4(2) - ip[i+3] = ip4.v4(3) s = "" i += 4 break @@ -324,9 +335,7 @@ func parseIPv6(in string) (Addr, error) { for j := i - 1; j >= ellipsis; j-- { ip[j+n] = ip[j] } - for j := ellipsis + n - 1; j >= ellipsis; j-- { - ip[j] = 0 - } + clear(ip[ellipsis : ellipsis+n]) } else if ellipsis >= 0 { // Ellipsis must represent at least one 0 group. return Addr{}, parseAddrError{in: in, msg: "the :: must expand to at least one field of zeros"} @@ -398,11 +407,10 @@ func (ip Addr) BitLen() int { // Zone returns ip's IPv6 scoped addressing zone, if any. func (ip Addr) Zone() string { - if ip.z == nil { + if ip.z == z0 { return "" } - zone, _ := ip.z.Get().(string) - return zone + return ip.z.Value().zoneV6 } // Compare returns an integer comparing two IPs. @@ -487,7 +495,7 @@ func (ip Addr) WithZone(zone string) Addr { ip.z = z6noz return ip } - ip.z = intern.GetByString(zone) + ip.z = unique.Make(addrDetail{isV6: true, zoneV6: zone}) return ip } @@ -692,8 +700,8 @@ func (ip Addr) Prefix(b int) (Prefix, error) { // [Addr.Zone] method to get it). // The ip zero value returns all zeroes. func (ip Addr) As16() (a16 [16]byte) { - bePutUint64(a16[:8], ip.addr.hi) - bePutUint64(a16[8:], ip.addr.lo) + byteorder.BePutUint64(a16[:8], ip.addr.hi) + byteorder.BePutUint64(a16[8:], ip.addr.lo) return a16 } @@ -702,7 +710,7 @@ func (ip Addr) As16() (a16 [16]byte) { // Note that 0.0.0.0 is not the zero Addr. func (ip Addr) As4() (a4 [4]byte) { if ip.z == z4 || ip.Is4In6() { - bePutUint32(a4[:], uint32(ip.addr.lo)) + byteorder.BePutUint32(a4[:], uint32(ip.addr.lo)) return a4 } if ip.z == z0 { @@ -718,12 +726,12 @@ func (ip Addr) AsSlice() []byte { return nil case z4: var ret [4]byte - bePutUint32(ret[:], uint32(ip.addr.lo)) + byteorder.BePutUint32(ret[:], uint32(ip.addr.lo)) return ret[:] default: var ret [16]byte - bePutUint64(ret[:8], ip.addr.hi) - bePutUint64(ret[8:], ip.addr.lo) + byteorder.BePutUint64(ret[:8], ip.addr.hi) + byteorder.BePutUint64(ret[8:], ip.addr.lo) return ret[:] } } @@ -780,11 +788,7 @@ func (ip Addr) String() string { return ip.string4() default: if ip.Is4In6() { - if z := ip.Zone(); z != "" { - return "::ffff:" + ip.Unmap().string4() + "%" + z - } else { - return "::ffff:" + ip.Unmap().string4() - } + return ip.string4In6() } return ip.string6() } @@ -801,13 +805,7 @@ func (ip Addr) AppendTo(b []byte) []byte { return ip.appendTo4(b) default: if ip.Is4In6() { - b = append(b, "::ffff:"...) - b = ip.Unmap().appendTo4(b) - if z := ip.Zone(); z != "" { - b = append(b, '%') - b = append(b, z...) - } - return b + return ip.appendTo4In6(b) } return ip.appendTo6(b) } @@ -871,6 +869,23 @@ func (ip Addr) appendTo4(ret []byte) []byte { return ret } +func (ip Addr) string4In6() string { + const max = len("::ffff:255.255.255.255%enp5s0") + ret := make([]byte, 0, max) + ret = ip.appendTo4In6(ret) + return string(ret) +} + +func (ip Addr) appendTo4In6(ret []byte) []byte { + ret = append(ret, "::ffff:"...) + ret = ip.Unmap().appendTo4(ret) + if ip.z != z6noz { + ret = append(ret, '%') + ret = append(ret, ip.Zone()...) + } + return ret +} + // string6 formats ip in IPv6 textual representation. It follows the // guidelines in section 4 of RFC 5952 // (https://tools.ietf.org/html/rfc5952#section-4): no unnecessary @@ -963,20 +978,15 @@ func (ip Addr) MarshalText() ([]byte, error) { b := make([]byte, 0, max) return ip.appendTo4(b), nil default: - max := len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0") - b := make([]byte, 0, max) if ip.Is4In6() { - b = append(b, "::ffff:"...) - b = ip.Unmap().appendTo4(b) - if z := ip.Zone(); z != "" { - b = append(b, '%') - b = append(b, z...) - } - return b, nil + max := len("::ffff:255.255.255.255%enp5s0") + b := make([]byte, 0, max) + return ip.appendTo4In6(b), nil } + max := len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0") + b := make([]byte, 0, max) return ip.appendTo6(b), nil } - } // UnmarshalText implements the encoding.TextUnmarshaler interface. @@ -1001,12 +1011,12 @@ func (ip Addr) marshalBinaryWithTrailingBytes(trailingBytes int) []byte { b = make([]byte, trailingBytes) case z4: b = make([]byte, 4+trailingBytes) - bePutUint32(b, uint32(ip.addr.lo)) + byteorder.BePutUint32(b, uint32(ip.addr.lo)) default: z := ip.Zone() b = make([]byte, 16+len(z)+trailingBytes) - bePutUint64(b[:8], ip.addr.hi) - bePutUint64(b[8:], ip.addr.lo) + byteorder.BePutUint64(b[:8], ip.addr.hi) + byteorder.BePutUint64(b[8:], ip.addr.lo) copy(b[16:], z) } return b @@ -1138,20 +1148,31 @@ func (p AddrPort) Compare(p2 AddrPort) int { } func (p AddrPort) String() string { + var b []byte switch p.ip.z { case z0: return "invalid AddrPort" case z4: const max = len("255.255.255.255:65535") - buf := make([]byte, 0, max) - buf = p.ip.appendTo4(buf) - buf = append(buf, ':') - buf = strconv.AppendUint(buf, uint64(p.port), 10) - return string(buf) + b = make([]byte, 0, max) + b = p.ip.appendTo4(b) default: - // TODO: this could be more efficient allocation-wise: - return "[" + p.ip.String() + "]:" + itoa.Uitoa(uint(p.port)) + if p.ip.Is4In6() { + const max = len("[::ffff:255.255.255.255%enp5s0]:65535") + b = make([]byte, 0, max) + b = append(b, '[') + b = p.ip.appendTo4In6(b) + } else { + const max = len("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0]:65535") + b = make([]byte, 0, max) + b = append(b, '[') + b = p.ip.appendTo6(b) + } + b = append(b, ']') } + b = append(b, ':') + b = strconv.AppendUint(b, uint64(p.port), 10) + return string(b) } // AppendTo appends a text encoding of p, @@ -1164,15 +1185,10 @@ func (p AddrPort) AppendTo(b []byte) []byte { case z4: b = p.ip.appendTo4(b) default: + b = append(b, '[') if p.ip.Is4In6() { - b = append(b, "[::ffff:"...) - b = p.ip.Unmap().appendTo4(b) - if z := p.ip.Zone(); z != "" { - b = append(b, '%') - b = append(b, z...) - } + b = p.ip.appendTo4In6(b) } else { - b = append(b, '[') b = p.ip.appendTo6(b) } b = append(b, ']') @@ -1217,7 +1233,7 @@ func (p *AddrPort) UnmarshalText(text []byte) error { // containing the port in little-endian. func (p AddrPort) MarshalBinary() ([]byte, error) { b := p.Addr().marshalBinaryWithTrailingBytes(2) - lePutUint16(b[len(b)-2:], p.Port()) + byteorder.LePutUint16(b[len(b)-2:], p.Port()) return b, nil } @@ -1232,7 +1248,7 @@ func (p *AddrPort) UnmarshalBinary(b []byte) error { if err != nil { return err } - *p = AddrPortFrom(addr, leUint16(b[len(b)-2:])) + *p = AddrPortFrom(addr, byteorder.LeUint16(b[len(b)-2:])) return nil } @@ -1303,6 +1319,15 @@ func (p Prefix) compare(p2 Prefix) int { return p.Addr().Compare(p2.Addr()) } +type parsePrefixError struct { + in string // the string given to ParsePrefix + msg string // an explanation of the parse failure +} + +func (err parsePrefixError) Error() string { + return "netip.ParsePrefix(" + strconv.Quote(err.in) + "): " + err.msg +} + // ParsePrefix parses s as an IP address prefix. // The string can be in the form "192.168.1.0/24" or "2001:db8::/32", // the CIDR notation defined in RFC 4632 and RFC 4291. @@ -1313,34 +1338,34 @@ func (p Prefix) compare(p2 Prefix) int { func ParsePrefix(s string) (Prefix, error) { i := bytealg.LastIndexByteString(s, '/') if i < 0 { - return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): no '/'") + return Prefix{}, parsePrefixError{in: s, msg: "no '/'"} } ip, err := ParseAddr(s[:i]) if err != nil { - return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): " + err.Error()) + return Prefix{}, parsePrefixError{in: s, msg: err.Error()} } // IPv6 zones are not allowed: https://go.dev/issue/51899 if ip.Is6() && ip.z != z6noz { - return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): IPv6 zones cannot be present in a prefix") + return Prefix{}, parsePrefixError{in: s, msg: "IPv6 zones cannot be present in a prefix"} } bitsStr := s[i+1:] // strconv.Atoi accepts a leading sign and leading zeroes, but we don't want that. if len(bitsStr) > 1 && (bitsStr[0] < '1' || bitsStr[0] > '9') { - return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): bad bits after slash: " + strconv.Quote(bitsStr)) + return Prefix{}, parsePrefixError{in: s, msg: "bad bits after slash: " + strconv.Quote(bitsStr)} } bits, err := strconv.Atoi(bitsStr) if err != nil { - return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): bad bits after slash: " + strconv.Quote(bitsStr)) + return Prefix{}, parsePrefixError{in: s, msg: "bad bits after slash: " + strconv.Quote(bitsStr)} } maxBits := 32 if ip.Is6() { maxBits = 128 } if bits < 0 || bits > maxBits { - return Prefix{}, errors.New("netip.ParsePrefix(" + strconv.Quote(s) + "): prefix length out of range") + return Prefix{}, parsePrefixError{in: s, msg: "prefix length out of range"} } return PrefixFrom(ip, bits), nil } diff --git a/contrib/go/_std_1.22/src/net/netip/uint128.go b/contrib/go/_std_1.23/src/net/netip/uint128.go similarity index 100% rename from contrib/go/_std_1.22/src/net/netip/uint128.go rename to contrib/go/_std_1.23/src/net/netip/uint128.go diff --git a/contrib/go/_std_1.22/src/net/netip/ya.make b/contrib/go/_std_1.23/src/net/netip/ya.make similarity index 80% rename from contrib/go/_std_1.22/src/net/netip/ya.make rename to contrib/go/_std_1.23/src/net/netip/ya.make index 644b119e6d34..7042672f0897 100644 --- a/contrib/go/_std_1.22/src/net/netip/ya.make +++ b/contrib/go/_std_1.23/src/net/netip/ya.make @@ -1,7 +1,6 @@ GO_LIBRARY() IF (TRUE) SRCS( - leaf_alts.go netip.go uint128.go ) diff --git a/contrib/go/_std_1.22/src/net/nss.go b/contrib/go/_std_1.23/src/net/nss.go similarity index 100% rename from contrib/go/_std_1.22/src/net/nss.go rename to contrib/go/_std_1.23/src/net/nss.go diff --git a/contrib/go/_std_1.22/src/net/parse.go b/contrib/go/_std_1.23/src/net/parse.go similarity index 93% rename from contrib/go/_std_1.22/src/net/parse.go rename to contrib/go/_std_1.23/src/net/parse.go index 29dffad43cf4..106a303dfada 100644 --- a/contrib/go/_std_1.22/src/net/parse.go +++ b/contrib/go/_std_1.23/src/net/parse.go @@ -251,23 +251,12 @@ func foreachField(x string, fn func(field string) error) error { return nil } -// stringsHasSuffix is strings.HasSuffix. It reports whether s ends in -// suffix. -func stringsHasSuffix(s, suffix string) bool { - return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix -} - // stringsHasSuffixFold reports whether s ends in suffix, // ASCII-case-insensitively. func stringsHasSuffixFold(s, suffix string) bool { return len(s) >= len(suffix) && stringsEqualFold(s[len(s)-len(suffix):], suffix) } -// stringsHasPrefix is strings.HasPrefix. It reports whether s begins with prefix. -func stringsHasPrefix(s, prefix string) bool { - return len(s) >= len(prefix) && s[:len(prefix)] == prefix -} - // stringsEqualFold is strings.EqualFold, ASCII only. It reports whether s and t // are equal, ASCII-case-insensitively. func stringsEqualFold(s, t string) bool { diff --git a/contrib/go/_std_1.22/src/net/pipe.go b/contrib/go/_std_1.23/src/net/pipe.go similarity index 100% rename from contrib/go/_std_1.22/src/net/pipe.go rename to contrib/go/_std_1.23/src/net/pipe.go diff --git a/contrib/go/_std_1.22/src/net/port.go b/contrib/go/_std_1.23/src/net/port.go similarity index 100% rename from contrib/go/_std_1.22/src/net/port.go rename to contrib/go/_std_1.23/src/net/port.go diff --git a/contrib/go/_std_1.22/src/net/port_unix.go b/contrib/go/_std_1.23/src/net/port_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/port_unix.go rename to contrib/go/_std_1.23/src/net/port_unix.go diff --git a/contrib/go/_std_1.22/src/net/rawconn.go b/contrib/go/_std_1.23/src/net/rawconn.go similarity index 100% rename from contrib/go/_std_1.22/src/net/rawconn.go rename to contrib/go/_std_1.23/src/net/rawconn.go diff --git a/contrib/go/_std_1.22/src/net/rlimit_js.go b/contrib/go/_std_1.23/src/net/rlimit_js.go similarity index 100% rename from contrib/go/_std_1.22/src/net/rlimit_js.go rename to contrib/go/_std_1.23/src/net/rlimit_js.go diff --git a/contrib/go/_std_1.22/src/net/rlimit_unix.go b/contrib/go/_std_1.23/src/net/rlimit_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/rlimit_unix.go rename to contrib/go/_std_1.23/src/net/rlimit_unix.go diff --git a/contrib/go/_std_1.22/src/net/rpc/client.go b/contrib/go/_std_1.23/src/net/rpc/client.go similarity index 100% rename from contrib/go/_std_1.22/src/net/rpc/client.go rename to contrib/go/_std_1.23/src/net/rpc/client.go diff --git a/contrib/go/_std_1.22/src/net/rpc/debug.go b/contrib/go/_std_1.23/src/net/rpc/debug.go similarity index 86% rename from contrib/go/_std_1.22/src/net/rpc/debug.go rename to contrib/go/_std_1.23/src/net/rpc/debug.go index 9e499fd984de..81d4ea368563 100644 --- a/contrib/go/_std_1.22/src/net/rpc/debug.go +++ b/contrib/go/_std_1.23/src/net/rpc/debug.go @@ -13,7 +13,8 @@ import ( "fmt" "html/template" "net/http" - "sort" + "slices" + "strings" ) const debugText = ` @@ -51,7 +52,7 @@ type methodArray []debugMethod type debugService struct { Service *service Name string - Method methodArray + Method []debugMethod } type serviceArray []debugService @@ -74,15 +75,19 @@ func (server debugHTTP) ServeHTTP(w http.ResponseWriter, req *http.Request) { var services serviceArray server.serviceMap.Range(func(snamei, svci any) bool { svc := svci.(*service) - ds := debugService{svc, snamei.(string), make(methodArray, 0, len(svc.method))} + ds := debugService{svc, snamei.(string), make([]debugMethod, 0, len(svc.method))} for mname, method := range svc.method { ds.Method = append(ds.Method, debugMethod{method, mname}) } - sort.Sort(ds.Method) + slices.SortFunc(ds.Method, func(a, b debugMethod) int { + return strings.Compare(a.Name, b.Name) + }) services = append(services, ds) return true }) - sort.Sort(services) + slices.SortFunc(services, func(a, b debugService) int { + return strings.Compare(a.Name, b.Name) + }) err := debug.Execute(w, services) if err != nil { fmt.Fprintln(w, "rpc: error executing template:", err.Error()) diff --git a/contrib/go/_std_1.22/src/net/rpc/jsonrpc/client.go b/contrib/go/_std_1.23/src/net/rpc/jsonrpc/client.go similarity index 100% rename from contrib/go/_std_1.22/src/net/rpc/jsonrpc/client.go rename to contrib/go/_std_1.23/src/net/rpc/jsonrpc/client.go diff --git a/contrib/go/_std_1.22/src/net/rpc/jsonrpc/server.go b/contrib/go/_std_1.23/src/net/rpc/jsonrpc/server.go similarity index 100% rename from contrib/go/_std_1.22/src/net/rpc/jsonrpc/server.go rename to contrib/go/_std_1.23/src/net/rpc/jsonrpc/server.go diff --git a/contrib/go/_std_1.22/src/net/rpc/jsonrpc/ya.make b/contrib/go/_std_1.23/src/net/rpc/jsonrpc/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/rpc/jsonrpc/ya.make rename to contrib/go/_std_1.23/src/net/rpc/jsonrpc/ya.make diff --git a/contrib/go/_std_1.22/src/net/rpc/server.go b/contrib/go/_std_1.23/src/net/rpc/server.go similarity index 100% rename from contrib/go/_std_1.22/src/net/rpc/server.go rename to contrib/go/_std_1.23/src/net/rpc/server.go diff --git a/contrib/go/_std_1.22/src/net/rpc/ya.make b/contrib/go/_std_1.23/src/net/rpc/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/rpc/ya.make rename to contrib/go/_std_1.23/src/net/rpc/ya.make diff --git a/contrib/go/_std_1.22/src/net/sendfile_linux.go b/contrib/go/_std_1.23/src/net/sendfile_linux.go similarity index 97% rename from contrib/go/_std_1.22/src/net/sendfile_linux.go rename to contrib/go/_std_1.23/src/net/sendfile_linux.go index 9a7d0058032f..f8a7bec8d381 100644 --- a/contrib/go/_std_1.22/src/net/sendfile_linux.go +++ b/contrib/go/_std_1.23/src/net/sendfile_linux.go @@ -10,6 +10,8 @@ import ( "os" ) +const supportsSendfile = true + // sendFile copies the contents of r to c using the sendfile // system call to minimize copies. // diff --git a/contrib/go/_std_1.22/src/net/sendfile_stub.go b/contrib/go/_std_1.23/src/net/sendfile_stub.go similarity index 70% rename from contrib/go/_std_1.22/src/net/sendfile_stub.go rename to contrib/go/_std_1.23/src/net/sendfile_stub.go index a4fdd99ffec2..7f31cc63e1ed 100644 --- a/contrib/go/_std_1.22/src/net/sendfile_stub.go +++ b/contrib/go/_std_1.23/src/net/sendfile_stub.go @@ -2,12 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build aix || js || netbsd || openbsd || ios || wasip1 +//go:build !(linux || (darwin && !ios) || dragonfly || freebsd || solaris || windows) package net import "io" +const supportsSendfile = false + func sendFile(c *netFD, r io.Reader) (n int64, err error, handled bool) { return 0, nil, false } diff --git a/contrib/go/_std_1.22/src/net/sendfile_unix_alt.go b/contrib/go/_std_1.23/src/net/sendfile_unix_alt.go similarity index 84% rename from contrib/go/_std_1.22/src/net/sendfile_unix_alt.go rename to contrib/go/_std_1.23/src/net/sendfile_unix_alt.go index 5cb65ee7670c..4056856f3061 100644 --- a/contrib/go/_std_1.22/src/net/sendfile_unix_alt.go +++ b/contrib/go/_std_1.23/src/net/sendfile_unix_alt.go @@ -9,9 +9,12 @@ package net import ( "internal/poll" "io" - "os" + "io/fs" + "syscall" ) +const supportsSendfile = true + // sendFile copies the contents of r to c using the sendfile // system call to minimize copies. // @@ -34,7 +37,13 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { return 0, nil, true } } - f, ok := r.(*os.File) + // r might be an *os.File or an os.fileWithoutWriteTo. + // Type assert to an interface rather than *os.File directly to handle the latter case. + f, ok := r.(interface { + fs.File + io.Seeker + syscall.Conn + }) if !ok { return 0, nil, false } @@ -44,6 +53,9 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { if err != nil { return 0, err, false } + if fi.Mode()&(fs.ModeSymlink|fs.ModeDevice|fs.ModeCharDevice|fs.ModeIrregular) != 0 { + return 0, nil, false + } remain = fi.Size() } diff --git a/contrib/go/_std_1.22/src/net/sendfile_windows.go b/contrib/go/_std_1.23/src/net/sendfile_windows.go similarity index 97% rename from contrib/go/_std_1.22/src/net/sendfile_windows.go rename to contrib/go/_std_1.23/src/net/sendfile_windows.go index 59b1b0d5c1dd..0377a485daa0 100644 --- a/contrib/go/_std_1.22/src/net/sendfile_windows.go +++ b/contrib/go/_std_1.23/src/net/sendfile_windows.go @@ -11,6 +11,8 @@ import ( "syscall" ) +const supportsSendfile = true + // sendFile copies the contents of r to c using the TransmitFile // system call to minimize copies. // diff --git a/contrib/go/_std_1.22/src/net/smtp/auth.go b/contrib/go/_std_1.23/src/net/smtp/auth.go similarity index 100% rename from contrib/go/_std_1.22/src/net/smtp/auth.go rename to contrib/go/_std_1.23/src/net/smtp/auth.go diff --git a/contrib/go/_std_1.22/src/net/smtp/smtp.go b/contrib/go/_std_1.23/src/net/smtp/smtp.go similarity index 98% rename from contrib/go/_std_1.22/src/net/smtp/smtp.go rename to contrib/go/_std_1.23/src/net/smtp/smtp.go index b7877936da57..d750a2854cbf 100644 --- a/contrib/go/_std_1.22/src/net/smtp/smtp.go +++ b/contrib/go/_std_1.23/src/net/smtp/smtp.go @@ -206,7 +206,7 @@ func (c *Client) Auth(a Auth) error { } resp64 := make([]byte, encoding.EncodedLen(len(resp))) encoding.Encode(resp64, resp) - code, msg64, err := c.cmd(0, strings.TrimSpace(fmt.Sprintf("AUTH %s %s", mech, resp64))) + code, msg64, err := c.cmd(0, "%s", strings.TrimSpace(fmt.Sprintf("AUTH %s %s", mech, resp64))) for err == nil { var msg []byte switch code { @@ -232,7 +232,7 @@ func (c *Client) Auth(a Auth) error { } resp64 = make([]byte, encoding.EncodedLen(len(resp))) encoding.Encode(resp64, resp) - code, msg64, err = c.cmd(0, string(resp64)) + code, msg64, err = c.cmd(0, "%s", resp64) } return err } diff --git a/contrib/go/_std_1.22/src/net/smtp/ya.make b/contrib/go/_std_1.23/src/net/smtp/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/smtp/ya.make rename to contrib/go/_std_1.23/src/net/smtp/ya.make diff --git a/contrib/go/_std_1.22/src/net/sock_bsd.go b/contrib/go/_std_1.23/src/net/sock_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sock_bsd.go rename to contrib/go/_std_1.23/src/net/sock_bsd.go diff --git a/contrib/go/_std_1.23/src/net/sock_cloexec.go b/contrib/go/_std_1.23/src/net/sock_cloexec.go new file mode 100644 index 000000000000..043522f0b6e1 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/sock_cloexec.go @@ -0,0 +1,25 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements sysSocket for platforms that provide a fast path for +// setting SetNonblock and CloseOnExec. + +//go:build dragonfly || freebsd || linux || netbsd || openbsd + +package net + +import ( + "os" + "syscall" +) + +// Wrapper around the socket system call that marks the returned file +// descriptor as nonblocking and close-on-exec. +func sysSocket(family, sotype, proto int) (int, error) { + s, err := socketFunc(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto) + if err != nil { + return -1, os.NewSyscallError("socket", err) + } + return s, nil +} diff --git a/contrib/go/_std_1.22/src/net/sock_cloexec.go b/contrib/go/_std_1.23/src/net/sock_cloexec_solaris.go similarity index 55% rename from contrib/go/_std_1.22/src/net/sock_cloexec.go rename to contrib/go/_std_1.23/src/net/sock_cloexec_solaris.go index 9eeb89746b9e..04c3cdf25437 100644 --- a/contrib/go/_std_1.22/src/net/sock_cloexec.go +++ b/contrib/go/_std_1.23/src/net/sock_cloexec_solaris.go @@ -1,16 +1,18 @@ -// Copyright 2013 The Go Authors. All rights reserved. +// Copyright 2024 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // This file implements sysSocket for platforms that provide a fast path for -// setting SetNonblock and CloseOnExec. - -//go:build dragonfly || freebsd || linux || netbsd || openbsd || solaris +// setting SetNonblock and CloseOnExec, but don't necessarily support it. +// Support for SOCK_* flags as part of the type parameter was added to Oracle +// Solaris in the 11.4 release. Thus, on releases prior to 11.4, we fall back +// to the combination of socket(3c) and fcntl(2). package net import ( "internal/poll" + "internal/syscall/unix" "os" "syscall" ) @@ -18,21 +20,18 @@ import ( // Wrapper around the socket system call that marks the returned file // descriptor as nonblocking and close-on-exec. func sysSocket(family, sotype, proto int) (int, error) { - s, err := socketFunc(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto) - // TODO: We can remove the fallback on Linux and *BSD, - // as currently supported versions all support accept4 - // with SOCK_CLOEXEC, but Solaris does not. See issue #59359. - switch err { - case nil: + // Perform a cheap test and try the fast path first. + if unix.SupportSockNonblockCloexec() { + s, err := socketFunc(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto) + if err != nil { + return -1, os.NewSyscallError("socket", err) + } return s, nil - default: - return -1, os.NewSyscallError("socket", err) - case syscall.EPROTONOSUPPORT, syscall.EINVAL: } // See ../syscall/exec_unix.go for description of ForkLock. syscall.ForkLock.RLock() - s, err = socketFunc(family, sotype, proto) + s, err := socketFunc(family, sotype, proto) if err == nil { syscall.CloseOnExec(s) } diff --git a/contrib/go/_std_1.22/src/net/sock_linux.go b/contrib/go/_std_1.23/src/net/sock_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sock_linux.go rename to contrib/go/_std_1.23/src/net/sock_linux.go diff --git a/contrib/go/_std_1.22/src/net/sock_plan9.go b/contrib/go/_std_1.23/src/net/sock_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sock_plan9.go rename to contrib/go/_std_1.23/src/net/sock_plan9.go diff --git a/contrib/go/_std_1.22/src/net/sock_posix.go b/contrib/go/_std_1.23/src/net/sock_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sock_posix.go rename to contrib/go/_std_1.23/src/net/sock_posix.go diff --git a/contrib/go/_std_1.22/src/net/sock_stub.go b/contrib/go/_std_1.23/src/net/sock_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sock_stub.go rename to contrib/go/_std_1.23/src/net/sock_stub.go diff --git a/contrib/go/_std_1.22/src/net/sock_windows.go b/contrib/go/_std_1.23/src/net/sock_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sock_windows.go rename to contrib/go/_std_1.23/src/net/sock_windows.go diff --git a/contrib/go/_std_1.22/src/net/sockaddr_posix.go b/contrib/go/_std_1.23/src/net/sockaddr_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockaddr_posix.go rename to contrib/go/_std_1.23/src/net/sockaddr_posix.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_aix.go b/contrib/go/_std_1.23/src/net/sockopt_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_aix.go rename to contrib/go/_std_1.23/src/net/sockopt_aix.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_bsd.go b/contrib/go/_std_1.23/src/net/sockopt_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_bsd.go rename to contrib/go/_std_1.23/src/net/sockopt_bsd.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_fake.go b/contrib/go/_std_1.23/src/net/sockopt_fake.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_fake.go rename to contrib/go/_std_1.23/src/net/sockopt_fake.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_linux.go b/contrib/go/_std_1.23/src/net/sockopt_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_linux.go rename to contrib/go/_std_1.23/src/net/sockopt_linux.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_plan9.go b/contrib/go/_std_1.23/src/net/sockopt_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_plan9.go rename to contrib/go/_std_1.23/src/net/sockopt_plan9.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_posix.go b/contrib/go/_std_1.23/src/net/sockopt_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_posix.go rename to contrib/go/_std_1.23/src/net/sockopt_posix.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_solaris.go b/contrib/go/_std_1.23/src/net/sockopt_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_solaris.go rename to contrib/go/_std_1.23/src/net/sockopt_solaris.go diff --git a/contrib/go/_std_1.22/src/net/sockopt_windows.go b/contrib/go/_std_1.23/src/net/sockopt_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockopt_windows.go rename to contrib/go/_std_1.23/src/net/sockopt_windows.go diff --git a/contrib/go/_std_1.22/src/net/sockoptip_bsdvar.go b/contrib/go/_std_1.23/src/net/sockoptip_bsdvar.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockoptip_bsdvar.go rename to contrib/go/_std_1.23/src/net/sockoptip_bsdvar.go diff --git a/contrib/go/_std_1.22/src/net/sockoptip_linux.go b/contrib/go/_std_1.23/src/net/sockoptip_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockoptip_linux.go rename to contrib/go/_std_1.23/src/net/sockoptip_linux.go diff --git a/contrib/go/_std_1.22/src/net/sockoptip_posix.go b/contrib/go/_std_1.23/src/net/sockoptip_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockoptip_posix.go rename to contrib/go/_std_1.23/src/net/sockoptip_posix.go diff --git a/contrib/go/_std_1.22/src/net/sockoptip_stub.go b/contrib/go/_std_1.23/src/net/sockoptip_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockoptip_stub.go rename to contrib/go/_std_1.23/src/net/sockoptip_stub.go diff --git a/contrib/go/_std_1.22/src/net/sockoptip_windows.go b/contrib/go/_std_1.23/src/net/sockoptip_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sockoptip_windows.go rename to contrib/go/_std_1.23/src/net/sockoptip_windows.go diff --git a/contrib/go/_std_1.22/src/net/splice_linux.go b/contrib/go/_std_1.23/src/net/splice_linux.go similarity index 84% rename from contrib/go/_std_1.22/src/net/splice_linux.go rename to contrib/go/_std_1.23/src/net/splice_linux.go index bdafcb59ab84..b62e8a722db8 100644 --- a/contrib/go/_std_1.22/src/net/splice_linux.go +++ b/contrib/go/_std_1.23/src/net/splice_linux.go @@ -9,6 +9,8 @@ import ( "io" ) +var pollSplice = poll.Splice + // spliceFrom transfers data from r to c using the splice system call to minimize // copies from and to userspace. c must be a TCP connection. // Currently, spliceFrom is only enabled if r is a TCP or a stream-oriented Unix connection. @@ -39,11 +41,11 @@ func spliceFrom(c *netFD, r io.Reader) (written int64, err error, handled bool) return 0, nil, false } - written, handled, sc, err := poll.Splice(&c.pfd, &s.pfd, remain) + written, handled, err = pollSplice(&c.pfd, &s.pfd, remain) if lr != nil { lr.N -= written } - return written, wrapSyscallError(sc, err), handled + return written, wrapSyscallError("splice", err), handled } // spliceTo transfers data from c to w using the splice system call to minimize @@ -57,6 +59,6 @@ func spliceTo(w io.Writer, c *netFD) (written int64, err error, handled bool) { return } - written, handled, sc, err := poll.Splice(&uc.fd.pfd, &c.pfd, 1<<63-1) - return written, wrapSyscallError(sc, err), handled + written, handled, err = pollSplice(&uc.fd.pfd, &c.pfd, 1<<63-1) + return written, wrapSyscallError("splice", err), handled } diff --git a/contrib/go/_std_1.22/src/net/splice_stub.go b/contrib/go/_std_1.23/src/net/splice_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/net/splice_stub.go rename to contrib/go/_std_1.23/src/net/splice_stub.go diff --git a/contrib/go/_std_1.22/src/net/sys_cloexec.go b/contrib/go/_std_1.23/src/net/sys_cloexec.go similarity index 100% rename from contrib/go/_std_1.22/src/net/sys_cloexec.go rename to contrib/go/_std_1.23/src/net/sys_cloexec.go diff --git a/contrib/go/_std_1.22/src/net/tcpsock.go b/contrib/go/_std_1.23/src/net/tcpsock.go similarity index 83% rename from contrib/go/_std_1.22/src/net/tcpsock.go rename to contrib/go/_std_1.23/src/net/tcpsock.go index 590516bff130..f5df502f0fd0 100644 --- a/contrib/go/_std_1.22/src/net/tcpsock.go +++ b/contrib/go/_std_1.23/src/net/tcpsock.go @@ -113,6 +113,41 @@ type TCPConn struct { conn } +// KeepAliveConfig contains TCP keep-alive options. +// +// If the Idle, Interval, or Count fields are zero, a default value is chosen. +// If a field is negative, the corresponding socket-level option will be left unchanged. +// +// Note that prior to Windows 10 version 1709, neither setting Idle and Interval +// separately nor changing Count (which is usually 10) is supported. +// Therefore, it's recommended to set both Idle and Interval to non-negative values +// in conjunction with a -1 for Count on those old Windows if you intend to customize +// the TCP keep-alive settings. +// By contrast, if only one of Idle and Interval is set to a non-negative value, +// the other will be set to the system default value, and ultimately, +// set both Idle and Interval to negative values if you want to leave them unchanged. +// +// Note that Solaris and its derivatives do not support setting Interval to a non-negative value +// and Count to a negative value, or vice-versa. +type KeepAliveConfig struct { + // If Enable is true, keep-alive probes are enabled. + Enable bool + + // Idle is the time that the connection must be idle before + // the first keep-alive probe is sent. + // If zero, a default value of 15 seconds is used. + Idle time.Duration + + // Interval is the time between keep-alive probes. + // If zero, a default value of 15 seconds is used. + Interval time.Duration + + // Count is the maximum number of keep-alive probes that + // can go unanswered before dropping a connection. + // If zero, a default value of 9 is used. + Count int +} + // SyscallConn returns a raw network connection. // This implements the [syscall.Conn] interface. func (c *TCPConn) SyscallConn() (syscall.RawConn, error) { @@ -206,12 +241,16 @@ func (c *TCPConn) SetKeepAlive(keepalive bool) error { return nil } -// SetKeepAlivePeriod sets period between keep-alives. +// SetKeepAlivePeriod sets the duration the connection needs to +// remain idle before TCP starts sending keepalive probes. +// +// Note that calling this method on Windows prior to Windows 10 version 1709 +// will reset the KeepAliveInterval to the default system value, which is normally 1 second. func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error { if !c.ok() { return syscall.EINVAL } - if err := setKeepAlivePeriod(c.fd, d); err != nil { + if err := setKeepAliveIdle(c.fd, d); err != nil { return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} } return nil @@ -247,19 +286,25 @@ func (c *TCPConn) MultipathTCP() (bool, error) { return isUsingMultipathTCP(c.fd), nil } -func newTCPConn(fd *netFD, keepAlive time.Duration, keepAliveHook func(time.Duration)) *TCPConn { +func newTCPConn(fd *netFD, keepAliveIdle time.Duration, keepAliveCfg KeepAliveConfig, preKeepAliveHook func(*netFD), keepAliveHook func(KeepAliveConfig)) *TCPConn { setNoDelay(fd, true) - if keepAlive == 0 { - keepAlive = defaultTCPKeepAlive + if !keepAliveCfg.Enable && keepAliveIdle >= 0 { + keepAliveCfg = KeepAliveConfig{ + Enable: true, + Idle: keepAliveIdle, + } } - if keepAlive > 0 { - setKeepAlive(fd, true) - setKeepAlivePeriod(fd, keepAlive) + c := &TCPConn{conn{fd}} + if keepAliveCfg.Enable { + if preKeepAliveHook != nil { + preKeepAliveHook(fd) + } + c.SetKeepAliveConfig(keepAliveCfg) if keepAliveHook != nil { - keepAliveHook(keepAlive) + keepAliveHook(keepAliveCfg) } } - return &TCPConn{conn{fd}} + return c } // DialTCP acts like [Dial] for TCP networks. diff --git a/contrib/go/_std_1.22/src/net/tcpsock_plan9.go b/contrib/go/_std_1.23/src/net/tcpsock_plan9.go similarity index 89% rename from contrib/go/_std_1.22/src/net/tcpsock_plan9.go rename to contrib/go/_std_1.23/src/net/tcpsock_plan9.go index 463dedcf44cd..430ed29ed42d 100644 --- a/contrib/go/_std_1.22/src/net/tcpsock_plan9.go +++ b/contrib/go/_std_1.23/src/net/tcpsock_plan9.go @@ -46,7 +46,7 @@ func (sd *sysDialer) doDialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCP if err != nil { return nil, err } - return newTCPConn(fd, sd.Dialer.KeepAlive, testHookSetKeepAlive), nil + return newTCPConn(fd, sd.Dialer.KeepAlive, sd.Dialer.KeepAliveConfig, testPreHookSetKeepAlive, testHookSetKeepAlive), nil } func (ln *TCPListener) ok() bool { return ln != nil && ln.fd != nil && ln.fd.ctl != nil } @@ -56,7 +56,7 @@ func (ln *TCPListener) accept() (*TCPConn, error) { if err != nil { return nil, err } - return newTCPConn(fd, ln.lc.KeepAlive, nil), nil + return newTCPConn(fd, ln.lc.KeepAlive, ln.lc.KeepAliveConfig, testPreHookSetKeepAlive, testHookSetKeepAlive), nil } func (ln *TCPListener) close() error { diff --git a/contrib/go/_std_1.22/src/net/tcpsock_posix.go b/contrib/go/_std_1.23/src/net/tcpsock_posix.go similarity index 93% rename from contrib/go/_std_1.22/src/net/tcpsock_posix.go rename to contrib/go/_std_1.23/src/net/tcpsock_posix.go index 01b5ec9ed056..7bca8dca555f 100644 --- a/contrib/go/_std_1.22/src/net/tcpsock_posix.go +++ b/contrib/go/_std_1.23/src/net/tcpsock_posix.go @@ -78,7 +78,7 @@ func (sd *sysDialer) doDialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCP func (sd *sysDialer) doDialTCPProto(ctx context.Context, laddr, raddr *TCPAddr, proto int) (*TCPConn, error) { ctrlCtxFn := sd.Dialer.ControlContext if ctrlCtxFn == nil && sd.Dialer.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sd.Dialer.Control(network, address, c) } } @@ -118,7 +118,7 @@ func (sd *sysDialer) doDialTCPProto(ctx context.Context, laddr, raddr *TCPAddr, if err != nil { return nil, err } - return newTCPConn(fd, sd.Dialer.KeepAlive, testHookSetKeepAlive), nil + return newTCPConn(fd, sd.Dialer.KeepAlive, sd.Dialer.KeepAliveConfig, testPreHookSetKeepAlive, testHookSetKeepAlive), nil } func selfConnect(fd *netFD, err error) bool { @@ -160,7 +160,7 @@ func (ln *TCPListener) accept() (*TCPConn, error) { if err != nil { return nil, err } - return newTCPConn(fd, ln.lc.KeepAlive, nil), nil + return newTCPConn(fd, ln.lc.KeepAlive, ln.lc.KeepAliveConfig, testPreHookSetKeepAlive, testHookSetKeepAlive), nil } func (ln *TCPListener) close() error { @@ -180,9 +180,9 @@ func (sl *sysListener) listenTCP(ctx context.Context, laddr *TCPAddr) (*TCPListe } func (sl *sysListener) listenTCPProto(ctx context.Context, laddr *TCPAddr, proto int) (*TCPListener, error) { - var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error + var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error if sl.ListenConfig.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sl.ListenConfig.Control(network, address, c) } } diff --git a/contrib/go/_std_1.23/src/net/tcpsock_solaris.go b/contrib/go/_std_1.23/src/net/tcpsock_solaris.go new file mode 100644 index 000000000000..924e2f74002b --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsock_solaris.go @@ -0,0 +1,38 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !illumos + +package net + +import ( + "internal/syscall/unix" + "syscall" +) + +// SetKeepAliveConfig configures keep-alive messages sent by the operating system. +func (c *TCPConn) SetKeepAliveConfig(config KeepAliveConfig) error { + if !c.ok() { + return syscall.EINVAL + } + + if err := setKeepAlive(c.fd, config.Enable); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if unix.SupportTCPKeepAliveIdleIntvlCNT() { + if err := setKeepAliveIdle(c.fd, config.Idle); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if err := setKeepAliveInterval(c.fd, config.Interval); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if err := setKeepAliveCount(c.fd, config.Count); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + } else if err := setKeepAliveIdleAndIntervalAndCount(c.fd, config.Idle, config.Interval, config.Count); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + + return nil +} diff --git a/contrib/go/_std_1.23/src/net/tcpsock_unix.go b/contrib/go/_std_1.23/src/net/tcpsock_unix.go new file mode 100644 index 000000000000..01879e38eeb6 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsock_unix.go @@ -0,0 +1,31 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (!windows && !solaris) || illumos + +package net + +import "syscall" + +// SetKeepAliveConfig configures keep-alive messages sent by the operating system. +func (c *TCPConn) SetKeepAliveConfig(config KeepAliveConfig) error { + if !c.ok() { + return syscall.EINVAL + } + + if err := setKeepAlive(c.fd, config.Enable); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if err := setKeepAliveIdle(c.fd, config.Idle); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if err := setKeepAliveInterval(c.fd, config.Interval); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if err := setKeepAliveCount(c.fd, config.Count); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + + return nil +} diff --git a/contrib/go/_std_1.23/src/net/tcpsock_windows.go b/contrib/go/_std_1.23/src/net/tcpsock_windows.go new file mode 100644 index 000000000000..70e8ea23e5b7 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsock_windows.go @@ -0,0 +1,36 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "internal/syscall/windows" + "syscall" +) + +// SetKeepAliveConfig configures keep-alive messages sent by the operating system. +func (c *TCPConn) SetKeepAliveConfig(config KeepAliveConfig) error { + if !c.ok() { + return syscall.EINVAL + } + + if err := setKeepAlive(c.fd, config.Enable); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if windows.SupportTCPKeepAliveIdle() && windows.SupportTCPKeepAliveInterval() { + if err := setKeepAliveIdle(c.fd, config.Idle); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if err := setKeepAliveInterval(c.fd, config.Interval); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + } else if err := setKeepAliveIdleAndInterval(c.fd, config.Idle, config.Interval); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + if err := setKeepAliveCount(c.fd, config.Count); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + + return nil +} diff --git a/contrib/go/_std_1.23/src/net/tcpsockopt_darwin.go b/contrib/go/_std_1.23/src/net/tcpsockopt_darwin.go new file mode 100644 index 000000000000..efe7f63323f0 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsockopt_darwin.go @@ -0,0 +1,57 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "runtime" + "syscall" + "time" +) + +// syscall.TCP_KEEPINTVL and syscall.TCP_KEEPCNT might be missing on some darwin architectures. +const ( + sysTCP_KEEPINTVL = 0x101 + sysTCP_KEEPCNT = 0x102 +) + +func setKeepAliveIdle(fd *netFD, d time.Duration) error { + if d == 0 { + d = defaultTCPKeepAliveIdle + } else if d < 0 { + return nil + } + + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE, secs) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setKeepAliveInterval(fd *netFD, d time.Duration) error { + if d == 0 { + d = defaultTCPKeepAliveInterval + } else if d < 0 { + return nil + } + + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPINTVL, secs) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setKeepAliveCount(fd *netFD, n int) error { + if n == 0 { + n = defaultTCPKeepAliveCount + } else if n < 0 { + return nil + } + + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPCNT, n) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} diff --git a/contrib/go/_std_1.23/src/net/tcpsockopt_openbsd.go b/contrib/go/_std_1.23/src/net/tcpsockopt_openbsd.go new file mode 100644 index 000000000000..d21b77c40688 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsockopt_openbsd.go @@ -0,0 +1,37 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "syscall" + "time" +) + +func setKeepAliveIdle(_ *netFD, d time.Duration) error { + if d < 0 { + return nil + } + // OpenBSD has no user-settable per-socket TCP keepalive + // options. + return syscall.ENOPROTOOPT +} + +func setKeepAliveInterval(_ *netFD, d time.Duration) error { + if d < 0 { + return nil + } + // OpenBSD has no user-settable per-socket TCP keepalive + // options. + return syscall.ENOPROTOOPT +} + +func setKeepAliveCount(_ *netFD, n int) error { + if n < 0 { + return nil + } + // OpenBSD has no user-settable per-socket TCP keepalive + // options. + return syscall.ENOPROTOOPT +} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_plan9.go b/contrib/go/_std_1.23/src/net/tcpsockopt_plan9.go similarity index 54% rename from contrib/go/_std_1.22/src/net/tcpsockopt_plan9.go rename to contrib/go/_std_1.23/src/net/tcpsockopt_plan9.go index 264359dcf3da..017e87518aeb 100644 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_plan9.go +++ b/contrib/go/_std_1.23/src/net/tcpsockopt_plan9.go @@ -12,13 +12,31 @@ import ( "time" ) -func setNoDelay(fd *netFD, noDelay bool) error { +func setNoDelay(_ *netFD, _ bool) error { return syscall.EPLAN9 } // Set keep alive period. -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { +func setKeepAliveIdle(fd *netFD, d time.Duration) error { + if d < 0 { + return nil + } + cmd := "keepalive " + itoa.Itoa(int(d/time.Millisecond)) _, e := fd.ctl.WriteAt([]byte(cmd), 0) return e } + +func setKeepAliveInterval(_ *netFD, d time.Duration) error { + if d < 0 { + return nil + } + return syscall.EPLAN9 +} + +func setKeepAliveCount(_ *netFD, n int) error { + if n < 0 { + return nil + } + return syscall.EPLAN9 +} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_posix.go b/contrib/go/_std_1.23/src/net/tcpsockopt_posix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/tcpsockopt_posix.go rename to contrib/go/_std_1.23/src/net/tcpsockopt_posix.go diff --git a/contrib/go/_std_1.23/src/net/tcpsockopt_solaris.go b/contrib/go/_std_1.23/src/net/tcpsockopt_solaris.go new file mode 100644 index 000000000000..df2ddbd11311 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsockopt_solaris.go @@ -0,0 +1,119 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !illumos + +package net + +import ( + "internal/syscall/unix" + "runtime" + "syscall" + "time" +) + +// Some macros of TCP Keep-Alive options on Solaris 11.4 may +// differ from those on OpenSolaris-based derivatives. +const ( + sysTCP_KEEPIDLE = 0x1D + sysTCP_KEEPINTVL = 0x1E + sysTCP_KEEPCNT = 0x1F +) + +func setKeepAliveIdle(fd *netFD, d time.Duration) error { + if !unix.SupportTCPKeepAliveIdleIntvlCNT() { + return setKeepAliveIdleAndIntervalAndCount(fd, d, -1, -1) + } + + if d == 0 { + d = defaultTCPKeepAliveIdle + } else if d < 0 { + return nil + } + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPIDLE, secs) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setKeepAliveInterval(fd *netFD, d time.Duration) error { + if !unix.SupportTCPKeepAliveIdleIntvlCNT() { + return syscall.EPROTOTYPE + } + + if d == 0 { + d = defaultTCPKeepAliveInterval + } else if d < 0 { + return nil + } + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPINTVL, secs) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setKeepAliveCount(fd *netFD, n int) error { + if !unix.SupportTCPKeepAliveIdleIntvlCNT() { + return syscall.EPROTOTYPE + } + + if n == 0 { + n = defaultTCPKeepAliveCount + } else if n < 0 { + return nil + } + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, sysTCP_KEEPCNT, n) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +// setKeepAliveIdleAndIntervalAndCount serves for Solaris prior to 11.4 by simulating +// the TCP_KEEPIDLE, TCP_KEEPINTVL, and TCP_KEEPCNT with `TCP_KEEPALIVE_THRESHOLD` + `TCP_KEEPALIVE_ABORT_THRESHOLD`. +func setKeepAliveIdleAndIntervalAndCount(fd *netFD, idle, interval time.Duration, count int) error { + if idle == 0 { + idle = defaultTCPKeepAliveIdle + } + + // The kernel expects milliseconds so round to next highest + // millisecond. + if idle > 0 { + msecs := int(roundDurationUp(idle, time.Millisecond)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD, msecs) + runtime.KeepAlive(fd) + if err != nil { + return wrapSyscallError("setsockopt", err) + } + } + + if interval == 0 { + interval = defaultTCPKeepAliveInterval + } + if count == 0 { + count = defaultTCPKeepAliveCount + } + // TCP_KEEPINTVL and TCP_KEEPCNT are not available on Solaris + // prior to 11.4, so it's pointless to "leave it unchanged" + // with negative value for only one of them. On the other hand, + // setting both to negative values should pragmatically leave the + // TCP_KEEPALIVE_ABORT_THRESHOLD unchanged. + abortIdle := int(roundDurationUp(interval, time.Millisecond)) * count + if abortIdle < 0 { + return syscall.ENOPROTOOPT + } + if interval < 0 && count < 0 { + abortIdle = -1 + } + + if abortIdle > 0 { + // Note that the consequent probes will not be sent at equal intervals on Solaris, + // but will be sent using the exponential backoff algorithm. + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_ABORT_THRESHOLD, abortIdle) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) + } + + return nil +} diff --git a/contrib/go/_std_1.22/src/net/tcpsockopt_stub.go b/contrib/go/_std_1.23/src/net/tcpsockopt_stub.go similarity index 59% rename from contrib/go/_std_1.22/src/net/tcpsockopt_stub.go rename to contrib/go/_std_1.23/src/net/tcpsockopt_stub.go index cef07cd6484e..b789e0ae934e 100644 --- a/contrib/go/_std_1.22/src/net/tcpsockopt_stub.go +++ b/contrib/go/_std_1.23/src/net/tcpsockopt_stub.go @@ -15,6 +15,14 @@ func setNoDelay(fd *netFD, noDelay bool) error { return syscall.ENOPROTOOPT } -func setKeepAlivePeriod(fd *netFD, d time.Duration) error { +func setKeepAliveIdle(fd *netFD, d time.Duration) error { + return syscall.ENOPROTOOPT +} + +func setKeepAliveInterval(fd *netFD, d time.Duration) error { + return syscall.ENOPROTOOPT +} + +func setKeepAliveCount(fd *netFD, n int) error { return syscall.ENOPROTOOPT } diff --git a/contrib/go/_std_1.23/src/net/tcpsockopt_unix.go b/contrib/go/_std_1.23/src/net/tcpsockopt_unix.go new file mode 100644 index 000000000000..1f7617897a4d --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsockopt_unix.go @@ -0,0 +1,53 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build aix || dragonfly || freebsd || illumos || linux || netbsd + +package net + +import ( + "runtime" + "syscall" + "time" +) + +func setKeepAliveIdle(fd *netFD, d time.Duration) error { + if d == 0 { + d = defaultTCPKeepAliveIdle + } else if d < 0 { + return nil + } + + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, secs) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setKeepAliveInterval(fd *netFD, d time.Duration) error { + if d == 0 { + d = defaultTCPKeepAliveInterval + } else if d < 0 { + return nil + } + + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} + +func setKeepAliveCount(fd *netFD, n int) error { + if n == 0 { + n = defaultTCPKeepAliveCount + } else if n < 0 { + return nil + } + + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, syscall.TCP_KEEPCNT, n) + runtime.KeepAlive(fd) + return wrapSyscallError("setsockopt", err) +} diff --git a/contrib/go/_std_1.23/src/net/tcpsockopt_windows.go b/contrib/go/_std_1.23/src/net/tcpsockopt_windows.go new file mode 100644 index 000000000000..f635d47999a4 --- /dev/null +++ b/contrib/go/_std_1.23/src/net/tcpsockopt_windows.go @@ -0,0 +1,118 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "internal/syscall/windows" + "os" + "runtime" + "syscall" + "time" + "unsafe" +) + +// Default values of KeepAliveTime and KeepAliveInterval on Windows, +// check out https://learn.microsoft.com/en-us/windows/win32/winsock/sio-keepalive-vals#remarks for details. +const ( + defaultKeepAliveIdle = 2 * time.Hour + defaultKeepAliveInterval = time.Second +) + +func setKeepAliveIdle(fd *netFD, d time.Duration) error { + if !windows.SupportTCPKeepAliveIdle() { + return setKeepAliveIdleAndInterval(fd, d, -1) + } + + if d == 0 { + d = defaultTCPKeepAliveIdle + } else if d < 0 { + return nil + } + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, windows.TCP_KEEPIDLE, secs) + runtime.KeepAlive(fd) + return os.NewSyscallError("setsockopt", err) +} + +func setKeepAliveInterval(fd *netFD, d time.Duration) error { + if !windows.SupportTCPKeepAliveInterval() { + return setKeepAliveIdleAndInterval(fd, -1, d) + } + + if d == 0 { + d = defaultTCPKeepAliveInterval + } else if d < 0 { + return nil + } + // The kernel expects seconds so round to next highest second. + secs := int(roundDurationUp(d, time.Second)) + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, windows.TCP_KEEPINTVL, secs) + runtime.KeepAlive(fd) + return os.NewSyscallError("setsockopt", err) +} + +func setKeepAliveCount(fd *netFD, n int) error { + if n == 0 { + n = defaultTCPKeepAliveCount + } else if n < 0 { + return nil + } + + err := fd.pfd.SetsockoptInt(syscall.IPPROTO_TCP, windows.TCP_KEEPCNT, n) + runtime.KeepAlive(fd) + return os.NewSyscallError("setsockopt", err) +} + +// setKeepAliveIdleAndInterval serves for kernels prior to Windows 10, version 1709. +func setKeepAliveIdleAndInterval(fd *netFD, idle, interval time.Duration) error { + // WSAIoctl with SIO_KEEPALIVE_VALS control code requires all fields in + // `tcp_keepalive` struct to be provided. + // Otherwise, if any of the fields were not provided, just leaving them + // zero will knock off any existing values of keep-alive. + // Unfortunately, Windows doesn't support retrieving current keep-alive + // settings in any form programmatically, which disable us to first retrieve + // the current keep-alive settings, then set it without unwanted corruption. + switch { + case idle < 0 && interval >= 0: + // Given that we can't set KeepAliveInterval alone, and this code path + // is new, it doesn't exist before, so we just return an error. + return syscall.WSAENOPROTOOPT + case idle >= 0 && interval < 0: + // Although we can't set KeepAliveTime alone either, this existing code + // path had been backing up [SetKeepAlivePeriod] which used to be set both + // KeepAliveTime and KeepAliveInterval to 15 seconds. + // Now we will use the default of KeepAliveInterval on Windows if user doesn't + // provide one. + interval = defaultKeepAliveInterval + case idle < 0 && interval < 0: + // Nothing to do, just bail out. + return nil + case idle >= 0 && interval >= 0: + // Go ahead. + } + + if idle == 0 { + idle = defaultTCPKeepAliveIdle + } + if interval == 0 { + interval = defaultTCPKeepAliveInterval + } + + // The kernel expects milliseconds so round to next highest + // millisecond. + tcpKeepAliveIdle := uint32(roundDurationUp(idle, time.Millisecond)) + tcpKeepAliveInterval := uint32(roundDurationUp(interval, time.Millisecond)) + ka := syscall.TCPKeepalive{ + OnOff: 1, + Time: tcpKeepAliveIdle, + Interval: tcpKeepAliveInterval, + } + ret := uint32(0) + size := uint32(unsafe.Sizeof(ka)) + err := fd.pfd.WSAIoctl(syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0) + runtime.KeepAlive(fd) + return os.NewSyscallError("wsaioctl", err) +} diff --git a/contrib/go/_std_1.22/src/net/textproto/header.go b/contrib/go/_std_1.23/src/net/textproto/header.go similarity index 100% rename from contrib/go/_std_1.22/src/net/textproto/header.go rename to contrib/go/_std_1.23/src/net/textproto/header.go diff --git a/contrib/go/_std_1.22/src/net/textproto/pipeline.go b/contrib/go/_std_1.23/src/net/textproto/pipeline.go similarity index 100% rename from contrib/go/_std_1.22/src/net/textproto/pipeline.go rename to contrib/go/_std_1.23/src/net/textproto/pipeline.go diff --git a/contrib/go/_std_1.22/src/net/textproto/reader.go b/contrib/go/_std_1.23/src/net/textproto/reader.go similarity index 98% rename from contrib/go/_std_1.22/src/net/textproto/reader.go rename to contrib/go/_std_1.23/src/net/textproto/reader.go index 793021101b30..f98e05bd1d86 100644 --- a/contrib/go/_std_1.22/src/net/textproto/reader.go +++ b/contrib/go/_std_1.23/src/net/textproto/reader.go @@ -14,6 +14,7 @@ import ( "strconv" "strings" "sync" + _ "unsafe" // for linkname ) // TODO: This should be a distinguishable error (ErrMessageTooLarge) @@ -501,6 +502,9 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { return readMIMEHeader(r, math.MaxInt64, math.MaxInt64) } +// readMIMEHeader is accessed from mime/multipart. +//go:linkname readMIMEHeader + // readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size. // It is called by the mime/multipart package. func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) { @@ -555,13 +559,6 @@ func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) } } - // As per RFC 7230 field-name is a token, tokens consist of one or more chars. - // We could return a ProtocolError here, but better to be liberal in what we - // accept, so if we get an empty key, skip it. - if key == "" { - continue - } - maxHeaders-- if maxHeaders < 0 { return nil, errMessageTooLarge @@ -743,6 +740,10 @@ func validHeaderValueByte(c byte) bool { // ReadMIMEHeader accepts header keys containing spaces, but does not // canonicalize them. func canonicalMIMEHeaderKey(a []byte) (_ string, ok bool) { + if len(a) == 0 { + return "", false + } + // See if a looks like a header key. If not, return it unchanged. noCanon := false for _, c := range a { diff --git a/contrib/go/_std_1.22/src/net/textproto/textproto.go b/contrib/go/_std_1.23/src/net/textproto/textproto.go similarity index 100% rename from contrib/go/_std_1.22/src/net/textproto/textproto.go rename to contrib/go/_std_1.23/src/net/textproto/textproto.go diff --git a/contrib/go/_std_1.22/src/net/textproto/writer.go b/contrib/go/_std_1.23/src/net/textproto/writer.go similarity index 100% rename from contrib/go/_std_1.22/src/net/textproto/writer.go rename to contrib/go/_std_1.23/src/net/textproto/writer.go diff --git a/contrib/go/_std_1.22/src/net/textproto/ya.make b/contrib/go/_std_1.23/src/net/textproto/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/textproto/ya.make rename to contrib/go/_std_1.23/src/net/textproto/ya.make diff --git a/contrib/go/_std_1.22/src/net/udpsock.go b/contrib/go/_std_1.23/src/net/udpsock.go similarity index 100% rename from contrib/go/_std_1.22/src/net/udpsock.go rename to contrib/go/_std_1.23/src/net/udpsock.go diff --git a/contrib/go/_std_1.22/src/net/udpsock_plan9.go b/contrib/go/_std_1.23/src/net/udpsock_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/udpsock_plan9.go rename to contrib/go/_std_1.23/src/net/udpsock_plan9.go diff --git a/contrib/go/_std_1.22/src/net/udpsock_posix.go b/contrib/go/_std_1.23/src/net/udpsock_posix.go similarity index 95% rename from contrib/go/_std_1.22/src/net/udpsock_posix.go rename to contrib/go/_std_1.23/src/net/udpsock_posix.go index 50350598317e..3cd1d0a76241 100644 --- a/contrib/go/_std_1.22/src/net/udpsock_posix.go +++ b/contrib/go/_std_1.23/src/net/udpsock_posix.go @@ -205,7 +205,7 @@ func (c *UDPConn) writeMsgAddrPort(b, oob []byte, addr netip.AddrPort) (n, oobn func (sd *sysDialer) dialUDP(ctx context.Context, laddr, raddr *UDPAddr) (*UDPConn, error) { ctrlCtxFn := sd.Dialer.ControlContext if ctrlCtxFn == nil && sd.Dialer.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sd.Dialer.Control(network, address, c) } } @@ -217,9 +217,9 @@ func (sd *sysDialer) dialUDP(ctx context.Context, laddr, raddr *UDPAddr) (*UDPCo } func (sl *sysListener) listenUDP(ctx context.Context, laddr *UDPAddr) (*UDPConn, error) { - var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error + var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error if sl.ListenConfig.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sl.ListenConfig.Control(network, address, c) } } @@ -231,9 +231,9 @@ func (sl *sysListener) listenUDP(ctx context.Context, laddr *UDPAddr) (*UDPConn, } func (sl *sysListener) listenMulticastUDP(ctx context.Context, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) { - var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error + var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error if sl.ListenConfig.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sl.ListenConfig.Control(network, address, c) } } diff --git a/contrib/go/_std_1.22/src/net/unixsock.go b/contrib/go/_std_1.23/src/net/unixsock.go similarity index 100% rename from contrib/go/_std_1.22/src/net/unixsock.go rename to contrib/go/_std_1.23/src/net/unixsock.go diff --git a/contrib/go/_std_1.22/src/net/unixsock_plan9.go b/contrib/go/_std_1.23/src/net/unixsock_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/net/unixsock_plan9.go rename to contrib/go/_std_1.23/src/net/unixsock_plan9.go diff --git a/contrib/go/_std_1.22/src/net/unixsock_posix.go b/contrib/go/_std_1.23/src/net/unixsock_posix.go similarity index 95% rename from contrib/go/_std_1.22/src/net/unixsock_posix.go rename to contrib/go/_std_1.23/src/net/unixsock_posix.go index f6c8e8f0b0e7..dc01b3874a6e 100644 --- a/contrib/go/_std_1.22/src/net/unixsock_posix.go +++ b/contrib/go/_std_1.23/src/net/unixsock_posix.go @@ -157,7 +157,7 @@ func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err err func (sd *sysDialer) dialUnix(ctx context.Context, laddr, raddr *UnixAddr) (*UnixConn, error) { ctrlCtxFn := sd.Dialer.ControlContext if ctrlCtxFn == nil && sd.Dialer.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sd.Dialer.Control(network, address, c) } } @@ -217,9 +217,9 @@ func (l *UnixListener) SetUnlinkOnClose(unlink bool) { } func (sl *sysListener) listenUnix(ctx context.Context, laddr *UnixAddr) (*UnixListener, error) { - var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error + var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error if sl.ListenConfig.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sl.ListenConfig.Control(network, address, c) } } @@ -231,9 +231,9 @@ func (sl *sysListener) listenUnix(ctx context.Context, laddr *UnixAddr) (*UnixLi } func (sl *sysListener) listenUnixgram(ctx context.Context, laddr *UnixAddr) (*UnixConn, error) { - var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error + var ctrlCtxFn func(ctx context.Context, network, address string, c syscall.RawConn) error if sl.ListenConfig.Control != nil { - ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { + ctrlCtxFn = func(ctx context.Context, network, address string, c syscall.RawConn) error { return sl.ListenConfig.Control(network, address, c) } } diff --git a/contrib/go/_std_1.22/src/net/unixsock_readmsg_cloexec.go b/contrib/go/_std_1.23/src/net/unixsock_readmsg_cloexec.go similarity index 100% rename from contrib/go/_std_1.22/src/net/unixsock_readmsg_cloexec.go rename to contrib/go/_std_1.23/src/net/unixsock_readmsg_cloexec.go diff --git a/contrib/go/_std_1.22/src/net/unixsock_readmsg_cmsg_cloexec.go b/contrib/go/_std_1.23/src/net/unixsock_readmsg_cmsg_cloexec.go similarity index 100% rename from contrib/go/_std_1.22/src/net/unixsock_readmsg_cmsg_cloexec.go rename to contrib/go/_std_1.23/src/net/unixsock_readmsg_cmsg_cloexec.go diff --git a/contrib/go/_std_1.22/src/net/unixsock_readmsg_other.go b/contrib/go/_std_1.23/src/net/unixsock_readmsg_other.go similarity index 100% rename from contrib/go/_std_1.22/src/net/unixsock_readmsg_other.go rename to contrib/go/_std_1.23/src/net/unixsock_readmsg_other.go diff --git a/contrib/go/_std_1.22/src/net/url/url.go b/contrib/go/_std_1.23/src/net/url/url.go similarity index 97% rename from contrib/go/_std_1.22/src/net/url/url.go rename to contrib/go/_std_1.23/src/net/url/url.go index f362958edd72..7beaef1ba663 100644 --- a/contrib/go/_std_1.22/src/net/url/url.go +++ b/contrib/go/_std_1.23/src/net/url/url.go @@ -14,9 +14,10 @@ import ( "errors" "fmt" "path" - "sort" + "slices" "strconv" "strings" + _ "unsafe" // for linkname ) // Error reports an error and the operation and URL that caused it. @@ -677,6 +678,16 @@ func parseHost(host string) (string, error) { // - setPath("/foo%2fbar") will set Path="/foo/bar" and RawPath="/foo%2fbar" // setPath will return an error only if the provided path contains an invalid // escaping. +// +// setPath should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/sagernet/sing +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname badSetPath net/url.(*URL).setPath func (u *URL) setPath(p string) error { path, err := unescape(p, encodePath) if err != nil { @@ -692,6 +703,9 @@ func (u *URL) setPath(p string) error { return nil } +// for linkname because we cannot linkname methods directly +func badSetPath(*URL, string) error + // EscapedPath returns the escaped form of u.Path. // In general there are multiple possible escaped forms of any path. // EscapedPath returns u.RawPath when it is a valid escaping of u.Path. @@ -814,6 +828,22 @@ func validOptionalPort(port string) bool { // - if u.Fragment is empty, #fragment is omitted. func (u *URL) String() string { var buf strings.Builder + + n := len(u.Scheme) + if u.Opaque != "" { + n += len(u.Opaque) + } else { + if !u.OmitHost && (u.Scheme != "" || u.Host != "" || u.User != nil) { + username := u.User.Username() + password, _ := u.User.Password() + n += len(username) + len(password) + len(u.Host) + } + n += len(u.Path) + } + n += len(u.RawQuery) + len(u.RawFragment) + n += len(":" + "//" + "//" + ":" + "@" + "/" + "./" + "?" + "#") + buf.Grow(n) + if u.Scheme != "" { buf.WriteString(u.Scheme) buf.WriteByte(':') @@ -978,7 +1008,7 @@ func (v Values) Encode() string { for k := range v { keys = append(keys, k) } - sort.Strings(keys) + slices.Sort(keys) for _, k := range keys { vs := v[k] keyEscaped := QueryEscape(k) @@ -1108,6 +1138,13 @@ func (u *URL) ResolveReference(ref *URL) *URL { url.RawFragment = u.RawFragment } } + if ref.Path == "" && u.Opaque != "" { + url.Opaque = u.Opaque + url.User = nil + url.Host = "" + url.Path = "" + return &url + } // The "abs_path" or "rel_path" cases. url.Host = u.Host url.User = u.User diff --git a/contrib/go/_std_1.22/src/net/url/ya.make b/contrib/go/_std_1.23/src/net/url/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/net/url/ya.make rename to contrib/go/_std_1.23/src/net/url/ya.make diff --git a/contrib/go/_std_1.22/src/net/writev_unix.go b/contrib/go/_std_1.23/src/net/writev_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/net/writev_unix.go rename to contrib/go/_std_1.23/src/net/writev_unix.go diff --git a/contrib/go/_std_1.22/src/net/ya.make b/contrib/go/_std_1.23/src/net/ya.make similarity index 76% rename from contrib/go/_std_1.22/src/net/ya.make rename to contrib/go/_std_1.23/src/net/ya.make index a6cdbd8d6caf..ea68d08ce9b3 100644 --- a/contrib/go/_std_1.22/src/net/ya.make +++ b/contrib/go/_std_1.23/src/net/ya.make @@ -1,75 +1,5 @@ GO_LIBRARY() -IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED) - SRCS( - addrselect.go - cgo_darwin.go - cgo_unix.go - cgo_unix_syscall.go - conf.go - dial.go - dnsclient.go - dnsclient_unix.go - dnsconfig.go - dnsconfig_unix.go - error_posix.go - error_unix.go - fd_posix.go - fd_unix.go - file.go - file_unix.go - hook.go - hook_unix.go - hosts.go - interface.go - interface_bsd.go - interface_darwin.go - ip.go - iprawsock.go - iprawsock_posix.go - ipsock.go - ipsock_posix.go - lookup.go - lookup_unix.go - mac.go - mptcpsock_stub.go - net.go - netcgo_off.go - netgo_off.go - nss.go - parse.go - pipe.go - port.go - port_unix.go - rawconn.go - rlimit_unix.go - sendfile_unix_alt.go - sock_bsd.go - sock_posix.go - sockaddr_posix.go - sockopt_bsd.go - sockopt_posix.go - sockoptip_bsdvar.go - sockoptip_posix.go - splice_stub.go - sys_cloexec.go - tcpsock.go - tcpsock_posix.go - tcpsockopt_darwin.go - tcpsockopt_posix.go - udpsock.go - udpsock_posix.go - unixsock.go - unixsock_posix.go - unixsock_readmsg_cloexec.go - writev_unix.go - ) - -IF (CGO_ENABLED) - CGO_SRCS( - cgo_unix_cgo_darwin.go - ) -ENDIF() -ELSEIF (OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( addrselect.go cgo_darwin.go @@ -124,6 +54,7 @@ ELSEIF (OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND A sys_cloexec.go tcpsock.go tcpsock_posix.go + tcpsock_unix.go tcpsockopt_darwin.go tcpsockopt_posix.go udpsock.go @@ -185,6 +116,7 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ splice_linux.go tcpsock.go tcpsock_posix.go + tcpsock_unix.go tcpsockopt_posix.go tcpsockopt_unix.go udpsock.go @@ -256,6 +188,7 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND A splice_linux.go tcpsock.go tcpsock_posix.go + tcpsock_unix.go tcpsockopt_posix.go tcpsockopt_unix.go udpsock.go @@ -313,6 +246,7 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND AR splice_stub.go tcpsock.go tcpsock_posix.go + tcpsock_windows.go tcpsockopt_posix.go tcpsockopt_windows.go udpsock.go diff --git a/contrib/go/_std_1.22/src/os/dir.go b/contrib/go/_std_1.23/src/os/dir.go similarity index 62% rename from contrib/go/_std_1.22/src/os/dir.go rename to contrib/go/_std_1.23/src/os/dir.go index 5306bcb3ba7c..04392193aa6b 100644 --- a/contrib/go/_std_1.22/src/os/dir.go +++ b/contrib/go/_std_1.23/src/os/dir.go @@ -5,8 +5,11 @@ package os import ( + "internal/bytealg" + "internal/filepathlite" + "io" "io/fs" - "sort" + "slices" ) type readdirMode int @@ -18,13 +21,13 @@ const ( ) // Readdir reads the contents of the directory associated with file and -// returns a slice of up to n FileInfo values, as would be returned -// by Lstat, in directory order. Subsequent calls on the same file will yield +// returns a slice of up to n [FileInfo] values, as would be returned +// by [Lstat], in directory order. Subsequent calls on the same file will yield // further FileInfos. // // If n > 0, Readdir returns at most n FileInfo structures. In this case, if // Readdir returns an empty slice, it will return a non-nil error -// explaining why. At the end of a directory, the error is io.EOF. +// explaining why. At the end of a directory, the error is [io.EOF]. // // If n <= 0, Readdir returns all the FileInfo from the directory in // a single slice. In this case, if Readdir succeeds (reads all @@ -55,7 +58,7 @@ func (f *File) Readdir(n int) ([]FileInfo, error) { // // If n > 0, Readdirnames returns at most n names. In this case, if // Readdirnames returns an empty slice, it will return a non-nil error -// explaining why. At the end of a directory, the error is io.EOF. +// explaining why. At the end of a directory, the error is [io.EOF]. // // If n <= 0, Readdirnames returns all the names from the directory in // a single slice. In this case, if Readdirnames succeeds (reads all @@ -78,16 +81,16 @@ func (f *File) Readdirnames(n int) (names []string, err error) { } // A DirEntry is an entry read from a directory -// (using the ReadDir function or a File's ReadDir method). +// (using the [ReadDir] function or a [File.ReadDir] method). type DirEntry = fs.DirEntry // ReadDir reads the contents of the directory associated with the file f -// and returns a slice of DirEntry values in directory order. +// and returns a slice of [DirEntry] values in directory order. // Subsequent calls on the same file will yield later DirEntry records in the directory. // // If n > 0, ReadDir returns at most n DirEntry records. // In this case, if ReadDir returns an empty slice, it will return an error explaining why. -// At the end of a directory, the error is io.EOF. +// At the end of a directory, the error is [io.EOF]. // // If n <= 0, ReadDir returns all the DirEntry records remaining in the directory. // When it succeeds, it returns a nil error (not io.EOF). @@ -113,13 +116,76 @@ var testingForceReadDirLstat bool // ReadDir returns the entries it was able to read before the error, // along with the error. func ReadDir(name string) ([]DirEntry, error) { - f, err := Open(name) + f, err := openDir(name) if err != nil { return nil, err } defer f.Close() dirs, err := f.ReadDir(-1) - sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() }) + slices.SortFunc(dirs, func(a, b DirEntry) int { + return bytealg.CompareString(a.Name(), b.Name()) + }) return dirs, err } + +// CopyFS copies the file system fsys into the directory dir, +// creating dir if necessary. +// +// Files are created with mode 0o666 plus any execute permissions +// from the source, and directories are created with mode 0o777 +// (before umask). +// +// CopyFS will not overwrite existing files. If a file name in fsys +// already exists in the destination, CopyFS will return an error +// such that errors.Is(err, fs.ErrExist) will be true. +// +// Symbolic links in fsys are not supported. A *PathError with Err set +// to ErrInvalid is returned when copying from a symbolic link. +// +// Symbolic links in dir are followed. +// +// Copying stops at and returns the first error encountered. +func CopyFS(dir string, fsys fs.FS) error { + return fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + fpath, err := filepathlite.Localize(path) + if err != nil { + return err + } + newPath := joinPath(dir, fpath) + if d.IsDir() { + return MkdirAll(newPath, 0777) + } + + // TODO(panjf2000): handle symlinks with the help of fs.ReadLinkFS + // once https://go.dev/issue/49580 is done. + // we also need filepathlite.IsLocal from https://go.dev/cl/564295. + if !d.Type().IsRegular() { + return &PathError{Op: "CopyFS", Path: path, Err: ErrInvalid} + } + + r, err := fsys.Open(path) + if err != nil { + return err + } + defer r.Close() + info, err := r.Stat() + if err != nil { + return err + } + w, err := OpenFile(newPath, O_CREATE|O_EXCL|O_WRONLY, 0666|info.Mode()&0777) + if err != nil { + return err + } + + if _, err := io.Copy(w, r); err != nil { + w.Close() + return &PathError{Op: "Copy", Path: newPath, Err: err} + } + return w.Close() + }) +} diff --git a/contrib/go/_std_1.22/src/os/dir_darwin.go b/contrib/go/_std_1.23/src/os/dir_darwin.go similarity index 93% rename from contrib/go/_std_1.22/src/os/dir_darwin.go rename to contrib/go/_std_1.23/src/os/dir_darwin.go index e6d5bda24bdd..91b67d8d61d1 100644 --- a/contrib/go/_std_1.22/src/os/dir_darwin.go +++ b/contrib/go/_std_1.23/src/os/dir_darwin.go @@ -25,16 +25,24 @@ func (d *dirInfo) close() { } func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) { - if f.dirinfo == nil { + // If this file has no dirinfo, create one. + var d *dirInfo + for { + d = f.dirinfo.Load() + if d != nil { + break + } dir, call, errno := f.pfd.OpenDir() if errno != nil { return nil, nil, nil, &PathError{Op: call, Path: f.name, Err: errno} } - f.dirinfo = &dirInfo{ - dir: dir, + d = &dirInfo{dir: dir} + if f.dirinfo.CompareAndSwap(nil, d) { + break } + // We lost the race: try again. + d.close() } - d := f.dirinfo size := n if size <= 0 { diff --git a/contrib/go/_std_1.22/src/os/dir_plan9.go b/contrib/go/_std_1.23/src/os/dir_plan9.go similarity index 94% rename from contrib/go/_std_1.22/src/os/dir_plan9.go rename to contrib/go/_std_1.23/src/os/dir_plan9.go index 6ea5940e71df..ab5c1efce5b0 100644 --- a/contrib/go/_std_1.22/src/os/dir_plan9.go +++ b/contrib/go/_std_1.23/src/os/dir_plan9.go @@ -12,10 +12,14 @@ import ( func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) { // If this file has no dirinfo, create one. - if file.dirinfo == nil { - file.dirinfo = new(dirInfo) + d := file.dirinfo.Load() + if d == nil { + d = new(dirInfo) + file.dirinfo.Store(d) } - d := file.dirinfo + d.mu.Lock() + defer d.mu.Unlock() + size := n if size <= 0 { size = 100 diff --git a/contrib/go/_std_1.22/src/os/dir_unix.go b/contrib/go/_std_1.23/src/os/dir_unix.go similarity index 78% rename from contrib/go/_std_1.22/src/os/dir_unix.go rename to contrib/go/_std_1.23/src/os/dir_unix.go index 266a78acafce..d8b4faa05788 100644 --- a/contrib/go/_std_1.22/src/os/dir_unix.go +++ b/contrib/go/_std_1.23/src/os/dir_unix.go @@ -7,6 +7,8 @@ package os import ( + "internal/byteorder" + "internal/goarch" "io" "runtime" "sync" @@ -16,6 +18,7 @@ import ( // Auxiliary information if the File describes a directory type dirInfo struct { + mu sync.Mutex buf *[]byte // buffer for directory I/O nbuf int // length of buf; return value from Getdirentries bufp int // location of next record in buf. @@ -42,12 +45,17 @@ func (d *dirInfo) close() { } func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) { - // If this file has no dirinfo, create one. - if f.dirinfo == nil { - f.dirinfo = new(dirInfo) - f.dirinfo.buf = dirBufPool.Get().(*[]byte) + // If this file has no dirInfo, create one. + d := f.dirinfo.Load() + if d == nil { + d = new(dirInfo) + f.dirinfo.Store(d) + } + d.mu.Lock() + defer d.mu.Unlock() + if d.buf == nil { + d.buf = dirBufPool.Get().(*[]byte) } - d := f.dirinfo // Change the meaning of n for the implementation below. // @@ -73,6 +81,9 @@ func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEn return names, dirents, infos, &PathError{Op: "readdirent", Path: f.name, Err: errno} } if d.nbuf <= 0 { + // Optimization: we can return the buffer to the pool, there is nothing else to read. + dirBufPool.Put(d.buf) + d.buf = nil break // EOF } } @@ -153,7 +164,7 @@ func readInt(b []byte, off, size uintptr) (u uint64, ok bool) { if len(b) < int(off+size) { return 0, false } - if isBigEndian { + if goarch.BigEndian { return readIntBE(b[off:], size), true } return readIntLE(b[off:], size), true @@ -164,15 +175,11 @@ func readIntBE(b []byte, size uintptr) uint64 { case 1: return uint64(b[0]) case 2: - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[1]) | uint64(b[0])<<8 + return uint64(byteorder.BeUint16(b)) case 4: - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24 + return uint64(byteorder.BeUint32(b)) case 8: - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 + return uint64(byteorder.BeUint64(b)) default: panic("syscall: readInt with unsupported size") } @@ -183,15 +190,11 @@ func readIntLE(b []byte, size uintptr) uint64 { case 1: return uint64(b[0]) case 2: - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 + return uint64(byteorder.LeUint16(b)) case 4: - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 + return uint64(byteorder.LeUint32(b)) case 8: - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | - uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + return uint64(byteorder.LeUint64(b)) default: panic("syscall: readInt with unsupported size") } diff --git a/contrib/go/_std_1.22/src/os/dir_windows.go b/contrib/go/_std_1.23/src/os/dir_windows.go similarity index 70% rename from contrib/go/_std_1.22/src/os/dir_windows.go rename to contrib/go/_std_1.23/src/os/dir_windows.go index 4485dffdb184..52d5acda2afd 100644 --- a/contrib/go/_std_1.22/src/os/dir_windows.go +++ b/contrib/go/_std_1.23/src/os/dir_windows.go @@ -16,11 +16,13 @@ import ( // Auxiliary information if the File describes a directory type dirInfo struct { + mu sync.Mutex // buf is a slice pointer so the slice header // does not escape to the heap when returning // buf to dirBufPool. buf *[]byte // buffer for directory I/O bufp int // location of next record in buf + h syscall.Handle vol uint32 class uint32 // type of entries in buf path string // absolute directory path, empty if the file system supports FILE_ID_BOTH_DIR_INFO @@ -45,6 +47,7 @@ var dirBufPool = sync.Pool{ } func (d *dirInfo) close() { + d.h = 0 if d.buf != nil { dirBufPool.Put(d.buf) d.buf = nil @@ -56,44 +59,62 @@ func (d *dirInfo) close() { // Useful for testing purposes. var allowReadDirFileID = true +func (d *dirInfo) init(h syscall.Handle) { + d.h = h + d.class = windows.FileFullDirectoryRestartInfo + // The previous settings are enough to read the directory entries. + // The following code is only needed to support os.SameFile. + + // It is safe to query d.vol once and reuse the value. + // Hard links are not allowed to reference files in other volumes. + // Junctions and symbolic links can reference files and directories in other volumes, + // but the reparse point should still live in the parent volume. + var flags uint32 + err := windows.GetVolumeInformationByHandle(h, nil, 0, &d.vol, nil, &flags, nil, 0) + if err != nil { + d.vol = 0 // Set to zero in case Windows writes garbage to it. + // If we can't get the volume information, we can't use os.SameFile, + // but we can still read the directory entries. + return + } + if flags&windows.FILE_SUPPORTS_OBJECT_IDS == 0 { + // The file system does not support object IDs, no need to continue. + return + } + if allowReadDirFileID && flags&windows.FILE_SUPPORTS_OPEN_BY_FILE_ID != 0 { + // Use FileIdBothDirectoryRestartInfo if available as it returns the file ID + // without the need to open the file. + d.class = windows.FileIdBothDirectoryRestartInfo + } else { + // If FileIdBothDirectoryRestartInfo is not available but objects IDs are supported, + // get the directory path so that os.SameFile can use it to open the file + // and retrieve the file ID. + d.path, _ = windows.FinalPath(h, windows.FILE_NAME_OPENED) + } +} + func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEntry, infos []FileInfo, err error) { - // If this file has no dirinfo, create one. - if file.dirinfo == nil { - // vol is used by os.SameFile. - // It is safe to query it once and reuse the value. - // Hard links are not allowed to reference files in other volumes. - // Junctions and symbolic links can reference files and directories in other volumes, - // but the reparse point should still live in the parent volume. - var vol, flags uint32 - err = windows.GetVolumeInformationByHandle(file.pfd.Sysfd, nil, 0, &vol, nil, &flags, nil, 0) - runtime.KeepAlive(file) - if err != nil { - err = &PathError{Op: "readdir", Path: file.name, Err: err} - return + // If this file has no dirInfo, create one. + var d *dirInfo + for { + d = file.dirinfo.Load() + if d != nil { + break } - file.dirinfo = new(dirInfo) - file.dirinfo.buf = dirBufPool.Get().(*[]byte) - file.dirinfo.vol = vol - if allowReadDirFileID && flags&windows.FILE_SUPPORTS_OPEN_BY_FILE_ID != 0 { - file.dirinfo.class = windows.FileIdBothDirectoryRestartInfo - } else { - file.dirinfo.class = windows.FileFullDirectoryRestartInfo - // Set the directory path for use by os.SameFile, as it is possible that - // the file system supports retrieving the file ID using GetFileInformationByHandle. - file.dirinfo.path = file.name - if !isAbs(file.dirinfo.path) { - // If the path is relative, we need to convert it to an absolute path - // in case the current directory changes between this call and a - // call to os.SameFile. - file.dirinfo.path, err = syscall.FullPath(file.dirinfo.path) - if err != nil { - err = &PathError{Op: "readdir", Path: file.name, Err: err} - return - } - } + d = new(dirInfo) + d.init(file.pfd.Sysfd) + if file.dirinfo.CompareAndSwap(nil, d) { + break } + // We lost the race: try again. + d.close() } - d := file.dirinfo + d.mu.Lock() + defer d.mu.Unlock() + if d.buf == nil { + d.buf = dirBufPool.Get().(*[]byte) + } + wantAll := n <= 0 if wantAll { n = -1 @@ -105,6 +126,9 @@ func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []Di runtime.KeepAlive(file) if err != nil { if err == syscall.ERROR_NO_MORE_FILES { + // Optimization: we can return the buffer to the pool, there is nothing else to read. + dirBufPool.Put(d.buf) + d.buf = nil break } if err == syscall.ERROR_FILE_NOT_FOUND && @@ -167,11 +191,13 @@ func (file *File) readdir(n int, mode readdirMode) (names []string, dirents []Di f = newFileStatFromFileIDBothDirInfo((*windows.FILE_ID_BOTH_DIR_INFO)(entry)) } else { f = newFileStatFromFileFullDirInfo((*windows.FILE_FULL_DIR_INFO)(entry)) - // Defer appending the entry name to the parent directory path until - // it is really needed, to avoid allocating a string that may not be used. - // It is currently only used in os.SameFile. - f.appendNameToPath = true - f.path = d.path + if d.path != "" { + // Defer appending the entry name to the parent directory path until + // it is really needed, to avoid allocating a string that may not be used. + // It is currently only used in os.SameFile. + f.appendNameToPath = true + f.path = d.path + } } f.name = name f.vol = d.vol diff --git a/contrib/go/_std_1.22/src/os/dirent_aix.go b/contrib/go/_std_1.23/src/os/dirent_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_aix.go rename to contrib/go/_std_1.23/src/os/dirent_aix.go diff --git a/contrib/go/_std_1.22/src/os/dirent_dragonfly.go b/contrib/go/_std_1.23/src/os/dirent_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_dragonfly.go rename to contrib/go/_std_1.23/src/os/dirent_dragonfly.go diff --git a/contrib/go/_std_1.22/src/os/dirent_freebsd.go b/contrib/go/_std_1.23/src/os/dirent_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_freebsd.go rename to contrib/go/_std_1.23/src/os/dirent_freebsd.go diff --git a/contrib/go/_std_1.22/src/os/dirent_js.go b/contrib/go/_std_1.23/src/os/dirent_js.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_js.go rename to contrib/go/_std_1.23/src/os/dirent_js.go diff --git a/contrib/go/_std_1.22/src/os/dirent_linux.go b/contrib/go/_std_1.23/src/os/dirent_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_linux.go rename to contrib/go/_std_1.23/src/os/dirent_linux.go diff --git a/contrib/go/_std_1.22/src/os/dirent_netbsd.go b/contrib/go/_std_1.23/src/os/dirent_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_netbsd.go rename to contrib/go/_std_1.23/src/os/dirent_netbsd.go diff --git a/contrib/go/_std_1.22/src/os/dirent_openbsd.go b/contrib/go/_std_1.23/src/os/dirent_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_openbsd.go rename to contrib/go/_std_1.23/src/os/dirent_openbsd.go diff --git a/contrib/go/_std_1.22/src/os/dirent_solaris.go b/contrib/go/_std_1.23/src/os/dirent_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_solaris.go rename to contrib/go/_std_1.23/src/os/dirent_solaris.go diff --git a/contrib/go/_std_1.22/src/os/dirent_wasip1.go b/contrib/go/_std_1.23/src/os/dirent_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/os/dirent_wasip1.go rename to contrib/go/_std_1.23/src/os/dirent_wasip1.go diff --git a/contrib/go/_std_1.22/src/os/env.go b/contrib/go/_std_1.23/src/os/env.go similarity index 97% rename from contrib/go/_std_1.22/src/os/env.go rename to contrib/go/_std_1.23/src/os/env.go index 63ad5ab4bd5f..9ac62451ae39 100644 --- a/contrib/go/_std_1.22/src/os/env.go +++ b/contrib/go/_std_1.23/src/os/env.go @@ -12,7 +12,7 @@ import ( ) // Expand replaces ${var} or $var in the string based on the mapping function. -// For example, os.ExpandEnv(s) is equivalent to os.Expand(s, os.Getenv). +// For example, [os.ExpandEnv](s) is equivalent to [os.Expand](s, [os.Getenv]). func Expand(s string, mapping func(string) string) string { var buf []byte // ${} is all ASCII, so bytes are fine for this operation. @@ -97,7 +97,7 @@ func getShellName(s string) (string, int) { // Getenv retrieves the value of the environment variable named by the key. // It returns the value, which will be empty if the variable is not present. -// To distinguish between an empty value and an unset value, use LookupEnv. +// To distinguish between an empty value and an unset value, use [LookupEnv]. func Getenv(key string) string { testlog.Getenv(key) v, _ := syscall.Getenv(key) diff --git a/contrib/go/_std_1.22/src/os/error.go b/contrib/go/_std_1.23/src/os/error.go similarity index 80% rename from contrib/go/_std_1.22/src/os/error.go rename to contrib/go/_std_1.23/src/os/error.go index 62ede9ded3bc..284b9e992cd4 100644 --- a/contrib/go/_std_1.22/src/os/error.go +++ b/contrib/go/_std_1.23/src/os/error.go @@ -12,7 +12,7 @@ import ( // Portable analogs of some common system call errors. // // Errors returned from this package may be tested against these errors -// with errors.Is. +// with [errors.Is]. var ( // ErrInvalid indicates an invalid argument. // Methods on File will return this error when the receiver is nil. @@ -61,7 +61,7 @@ func (e *SyscallError) Timeout() bool { return ok && t.Timeout() } -// NewSyscallError returns, as an error, a new SyscallError +// NewSyscallError returns, as an error, a new [SyscallError] // with the given system call name and error details. // As a convenience, if err is nil, NewSyscallError returns nil. func NewSyscallError(syscall string, err error) error { @@ -71,44 +71,44 @@ func NewSyscallError(syscall string, err error) error { return &SyscallError{syscall, err} } -// IsExist returns a boolean indicating whether the error is known to report -// that a file or directory already exists. It is satisfied by ErrExist as +// IsExist returns a boolean indicating whether its argument is known to report +// that a file or directory already exists. It is satisfied by [ErrExist] as // well as some syscall errors. // -// This function predates errors.Is. It only supports errors returned by +// This function predates [errors.Is]. It only supports errors returned by // the os package. New code should use errors.Is(err, fs.ErrExist). func IsExist(err error) bool { return underlyingErrorIs(err, ErrExist) } -// IsNotExist returns a boolean indicating whether the error is known to +// IsNotExist returns a boolean indicating whether its argument is known to // report that a file or directory does not exist. It is satisfied by -// ErrNotExist as well as some syscall errors. +// [ErrNotExist] as well as some syscall errors. // -// This function predates errors.Is. It only supports errors returned by +// This function predates [errors.Is]. It only supports errors returned by // the os package. New code should use errors.Is(err, fs.ErrNotExist). func IsNotExist(err error) bool { return underlyingErrorIs(err, ErrNotExist) } -// IsPermission returns a boolean indicating whether the error is known to -// report that permission is denied. It is satisfied by ErrPermission as well +// IsPermission returns a boolean indicating whether its argument is known to +// report that permission is denied. It is satisfied by [ErrPermission] as well // as some syscall errors. // -// This function predates errors.Is. It only supports errors returned by +// This function predates [errors.Is]. It only supports errors returned by // the os package. New code should use errors.Is(err, fs.ErrPermission). func IsPermission(err error) bool { return underlyingErrorIs(err, ErrPermission) } -// IsTimeout returns a boolean indicating whether the error is known +// IsTimeout returns a boolean indicating whether its argument is known // to report that a timeout occurred. // -// This function predates errors.Is, and the notion of whether an +// This function predates [errors.Is], and the notion of whether an // error indicates a timeout can be ambiguous. For example, the Unix // error EWOULDBLOCK sometimes indicates a timeout and sometimes does not. // New code should use errors.Is with a value appropriate to the call -// returning the error, such as os.ErrDeadlineExceeded. +// returning the error, such as [os.ErrDeadlineExceeded]. func IsTimeout(err error) bool { terr, ok := underlyingError(err).(timeout) return ok && terr.Timeout() diff --git a/contrib/go/_std_1.22/src/os/error_errno.go b/contrib/go/_std_1.23/src/os/error_errno.go similarity index 100% rename from contrib/go/_std_1.22/src/os/error_errno.go rename to contrib/go/_std_1.23/src/os/error_errno.go diff --git a/contrib/go/_std_1.22/src/os/error_plan9.go b/contrib/go/_std_1.23/src/os/error_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/error_plan9.go rename to contrib/go/_std_1.23/src/os/error_plan9.go diff --git a/contrib/go/_std_1.23/src/os/exec.go b/contrib/go/_std_1.23/src/os/exec.go new file mode 100644 index 000000000000..1220761df5ee --- /dev/null +++ b/contrib/go/_std_1.23/src/os/exec.go @@ -0,0 +1,404 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "errors" + "internal/testlog" + "runtime" + "sync" + "sync/atomic" + "syscall" + "time" +) + +// ErrProcessDone indicates a [Process] has finished. +var ErrProcessDone = errors.New("os: process already finished") + +type processMode uint8 + +const ( + // modePID means that Process operations such use the raw PID from the + // Pid field. handle is not used. + // + // This may be due to the host not supporting handles, or because + // Process was created as a literal, leaving handle unset. + // + // This must be the zero value so Process literals get modePID. + modePID processMode = iota + + // modeHandle means that Process operations use handle, which is + // initialized with an OS process handle. + // + // Note that Release and Wait will deactivate and eventually close the + // handle, so acquire may fail, indicating the reason. + modeHandle +) + +type processStatus uint64 + +const ( + // PID/handle OK to use. + statusOK processStatus = 0 + + // statusDone indicates that the PID/handle should not be used because + // the process is done (has been successfully Wait'd on). + statusDone processStatus = 1 << 62 + + // statusReleased indicates that the PID/handle should not be used + // because the process is released. + statusReleased processStatus = 1 << 63 + + processStatusMask = 0x3 << 62 +) + +// Process stores the information about a process created by [StartProcess]. +type Process struct { + Pid int + + mode processMode + + // State contains the atomic process state. + // + // In modePID, this consists only of the processStatus fields, which + // indicate if the process is done/released. + // + // In modeHandle, the lower bits also contain a reference count for the + // handle field. + // + // The Process itself initially holds 1 persistent reference. Any + // operation that uses the handle with a system call temporarily holds + // an additional transient reference. This prevents the handle from + // being closed prematurely, which could result in the OS allocating a + // different handle with the same value, leading to Process' methods + // operating on the wrong process. + // + // Release and Wait both drop the Process' persistent reference, but + // other concurrent references may delay actually closing the handle + // because they hold a transient reference. + // + // Regardless, we want new method calls to immediately treat the handle + // as unavailable after Release or Wait to avoid extending this delay. + // This is achieved by setting either processStatus flag when the + // Process' persistent reference is dropped. The only difference in the + // flags is the reason the handle is unavailable, which affects the + // errors returned by concurrent calls. + state atomic.Uint64 + + // Used only in modePID. + sigMu sync.RWMutex // avoid race between wait and signal + + // handle is the OS handle for process actions, used only in + // modeHandle. + // + // handle must be accessed only via the handleTransientAcquire method + // (or during closeHandle), not directly! handle is immutable. + // + // On Windows, it is a handle from OpenProcess. + // On Linux, it is a pidfd. + // It is unused on other GOOSes. + handle uintptr +} + +func newPIDProcess(pid int) *Process { + p := &Process{ + Pid: pid, + mode: modePID, + } + runtime.SetFinalizer(p, (*Process).Release) + return p +} + +func newHandleProcess(pid int, handle uintptr) *Process { + p := &Process{ + Pid: pid, + mode: modeHandle, + handle: handle, + } + p.state.Store(1) // 1 persistent reference + runtime.SetFinalizer(p, (*Process).Release) + return p +} + +func newDoneProcess(pid int) *Process { + p := &Process{ + Pid: pid, + mode: modeHandle, + // N.B Since we set statusDone, handle will never actually be + // used, so its value doesn't matter. + } + p.state.Store(uint64(statusDone)) // No persistent reference, as there is no handle. + runtime.SetFinalizer(p, (*Process).Release) + return p +} + +func (p *Process) handleTransientAcquire() (uintptr, processStatus) { + if p.mode != modeHandle { + panic("handleTransientAcquire called in invalid mode") + } + + for { + refs := p.state.Load() + if refs&processStatusMask != 0 { + return 0, processStatus(refs & processStatusMask) + } + new := refs + 1 + if !p.state.CompareAndSwap(refs, new) { + continue + } + return p.handle, statusOK + } +} + +func (p *Process) handleTransientRelease() { + if p.mode != modeHandle { + panic("handleTransientRelease called in invalid mode") + } + + for { + state := p.state.Load() + refs := state &^ processStatusMask + status := processStatus(state & processStatusMask) + if refs == 0 { + // This should never happen because + // handleTransientRelease is always paired with + // handleTransientAcquire. + panic("release of handle with refcount 0") + } + if refs == 1 && status == statusOK { + // Process holds a persistent reference and always sets + // a status when releasing that reference + // (handlePersistentRelease). Thus something has gone + // wrong if this is the last release but a status has + // not always been set. + panic("final release of handle without processStatus") + } + new := state - 1 + if !p.state.CompareAndSwap(state, new) { + continue + } + if new&^processStatusMask == 0 { + p.closeHandle() + } + return + } +} + +// Drop the Process' persistent reference on the handle, deactivating future +// Wait/Signal calls with the passed reason. +// +// Returns the status prior to this call. If this is not statusOK, then the +// reference was not dropped or status changed. +func (p *Process) handlePersistentRelease(reason processStatus) processStatus { + if p.mode != modeHandle { + panic("handlePersistentRelease called in invalid mode") + } + + for { + refs := p.state.Load() + status := processStatus(refs & processStatusMask) + if status != statusOK { + // Both Release and successful Wait will drop the + // Process' persistent reference on the handle. We + // can't allow concurrent calls to drop the reference + // twice, so we use the status as a guard to ensure the + // reference is dropped exactly once. + return status + } + if refs == 0 { + // This should never happen because dropping the + // persistent reference always sets a status. + panic("release of handle with refcount 0") + } + new := (refs - 1) | uint64(reason) + if !p.state.CompareAndSwap(refs, new) { + continue + } + if new&^processStatusMask == 0 { + p.closeHandle() + } + return status + } +} + +func (p *Process) pidStatus() processStatus { + if p.mode != modePID { + panic("pidStatus called in invalid mode") + } + + return processStatus(p.state.Load()) +} + +func (p *Process) pidDeactivate(reason processStatus) { + if p.mode != modePID { + panic("pidDeactivate called in invalid mode") + } + + // Both Release and successful Wait will deactivate the PID. Only one + // of those should win, so nothing left to do here if the compare + // fails. + // + // N.B. This means that results can be inconsistent. e.g., with a + // racing Release and Wait, Wait may successfully wait on the process, + // returning the wait status, while future calls error with "process + // released" rather than "process done". + p.state.CompareAndSwap(0, uint64(reason)) +} + +// ProcAttr holds the attributes that will be applied to a new process +// started by StartProcess. +type ProcAttr struct { + // If Dir is non-empty, the child changes into the directory before + // creating the process. + Dir string + // If Env is non-nil, it gives the environment variables for the + // new process in the form returned by Environ. + // If it is nil, the result of Environ will be used. + Env []string + // Files specifies the open files inherited by the new process. The + // first three entries correspond to standard input, standard output, and + // standard error. An implementation may support additional entries, + // depending on the underlying operating system. A nil entry corresponds + // to that file being closed when the process starts. + // On Unix systems, StartProcess will change these File values + // to blocking mode, which means that SetDeadline will stop working + // and calling Close will not interrupt a Read or Write. + Files []*File + + // Operating system-specific process creation attributes. + // Note that setting this field means that your program + // may not execute properly or even compile on some + // operating systems. + Sys *syscall.SysProcAttr +} + +// A Signal represents an operating system signal. +// The usual underlying implementation is operating system-dependent: +// on Unix it is syscall.Signal. +type Signal interface { + String() string + Signal() // to distinguish from other Stringers +} + +// Getpid returns the process id of the caller. +func Getpid() int { return syscall.Getpid() } + +// Getppid returns the process id of the caller's parent. +func Getppid() int { return syscall.Getppid() } + +// FindProcess looks for a running process by its pid. +// +// The [Process] it returns can be used to obtain information +// about the underlying operating system process. +// +// On Unix systems, FindProcess always succeeds and returns a Process +// for the given pid, regardless of whether the process exists. To test whether +// the process actually exists, see whether p.Signal(syscall.Signal(0)) reports +// an error. +func FindProcess(pid int) (*Process, error) { + return findProcess(pid) +} + +// StartProcess starts a new process with the program, arguments and attributes +// specified by name, argv and attr. The argv slice will become [os.Args] in the +// new process, so it normally starts with the program name. +// +// If the calling goroutine has locked the operating system thread +// with [runtime.LockOSThread] and modified any inheritable OS-level +// thread state (for example, Linux or Plan 9 name spaces), the new +// process will inherit the caller's thread state. +// +// StartProcess is a low-level interface. The [os/exec] package provides +// higher-level interfaces. +// +// If there is an error, it will be of type [*PathError]. +func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) { + testlog.Open(name) + return startProcess(name, argv, attr) +} + +// Release releases any resources associated with the [Process] p, +// rendering it unusable in the future. +// Release only needs to be called if [Process.Wait] is not. +func (p *Process) Release() error { + // Note to future authors: the Release API is cursed. + // + // On Unix and Plan 9, Release sets p.Pid = -1. This is the only part of the + // Process API that is not thread-safe, but it can't be changed now. + // + // On Windows, Release does _not_ modify p.Pid. + // + // On Windows, Wait calls Release after successfully waiting to + // proactively clean up resources. + // + // On Unix and Plan 9, Wait also proactively cleans up resources, but + // can not call Release, as Wait does not set p.Pid = -1. + // + // On Unix and Plan 9, calling Release a second time has no effect. + // + // On Windows, calling Release a second time returns EINVAL. + return p.release() +} + +// Kill causes the [Process] to exit immediately. Kill does not wait until +// the Process has actually exited. This only kills the Process itself, +// not any other processes it may have started. +func (p *Process) Kill() error { + return p.kill() +} + +// Wait waits for the [Process] to exit, and then returns a +// ProcessState describing its status and an error, if any. +// Wait releases any resources associated with the Process. +// On most operating systems, the Process must be a child +// of the current process or an error will be returned. +func (p *Process) Wait() (*ProcessState, error) { + return p.wait() +} + +// Signal sends a signal to the [Process]. +// Sending [Interrupt] on Windows is not implemented. +func (p *Process) Signal(sig Signal) error { + return p.signal(sig) +} + +// UserTime returns the user CPU time of the exited process and its children. +func (p *ProcessState) UserTime() time.Duration { + return p.userTime() +} + +// SystemTime returns the system CPU time of the exited process and its children. +func (p *ProcessState) SystemTime() time.Duration { + return p.systemTime() +} + +// Exited reports whether the program has exited. +// On Unix systems this reports true if the program exited due to calling exit, +// but false if the program terminated due to a signal. +func (p *ProcessState) Exited() bool { + return p.exited() +} + +// Success reports whether the program exited successfully, +// such as with exit status 0 on Unix. +func (p *ProcessState) Success() bool { + return p.success() +} + +// Sys returns system-dependent exit information about +// the process. Convert it to the appropriate underlying +// type, such as [syscall.WaitStatus] on Unix, to access its contents. +func (p *ProcessState) Sys() any { + return p.sys() +} + +// SysUsage returns system-dependent resource usage information about +// the exited process. Convert it to the appropriate underlying +// type, such as [*syscall.Rusage] on Unix, to access its contents. +// (On Unix, *syscall.Rusage matches struct rusage as defined in the +// getrusage(2) manual page.) +func (p *ProcessState) SysUsage() any { + return p.sysUsage() +} diff --git a/contrib/go/_std_1.22/src/os/exec/exec.go b/contrib/go/_std_1.23/src/os/exec/exec.go similarity index 91% rename from contrib/go/_std_1.22/src/os/exec/exec.go rename to contrib/go/_std_1.23/src/os/exec/exec.go index a52b75f69cde..da9f68fe28f1 100644 --- a/contrib/go/_std_1.22/src/os/exec/exec.go +++ b/contrib/go/_std_1.23/src/os/exec/exec.go @@ -12,7 +12,7 @@ // pipelines, or redirections typically done by shells. The package // behaves more like C's "exec" family of functions. To expand glob // patterns, either call the shell directly, taking care to escape any -// dangerous input, or use the path/filepath package's Glob function. +// dangerous input, or use the [path/filepath] package's Glob function. // To expand environment variables, use package os's ExpandEnv. // // Note that the examples in this package assume a Unix system. @@ -21,7 +21,7 @@ // // # Executables in the current directory // -// The functions Command and LookPath look for a program +// The functions [Command] and [LookPath] look for a program // in the directories listed in the current path, following the // conventions of the host operating system. // Operating systems have for decades included the current @@ -32,10 +32,10 @@ // // To avoid those security problems, as of Go 1.19, this package will not resolve a program // using an implicit or explicit path entry relative to the current directory. -// That is, if you run exec.LookPath("go"), it will not successfully return +// That is, if you run [LookPath]("go"), it will not successfully return // ./go on Unix nor .\go.exe on Windows, no matter how the path is configured. // Instead, if the usual path algorithms would result in that answer, -// these functions return an error err satisfying errors.Is(err, ErrDot). +// these functions return an error err satisfying [errors.Is](err, [ErrDot]). // // For example, consider these two program snippets: // @@ -106,7 +106,7 @@ import ( "time" ) -// Error is returned by LookPath when it fails to classify a file as an +// Error is returned by [LookPath] when it fails to classify a file as an // executable. type Error struct { // Name is the file name for which the error occurred. @@ -121,7 +121,7 @@ func (e *Error) Error() string { func (e *Error) Unwrap() error { return e.Err } -// ErrWaitDelay is returned by (*Cmd).Wait if the process exits with a +// ErrWaitDelay is returned by [Cmd.Wait] if the process exits with a // successful status code but its output pipes are not closed before the // command's WaitDelay expires. var ErrWaitDelay = errors.New("exec: WaitDelay expired before I/O complete") @@ -142,7 +142,7 @@ func (w wrappedError) Unwrap() error { // Cmd represents an external command being prepared or run. // -// A Cmd cannot be reused after calling its Run, Output or CombinedOutput +// A Cmd cannot be reused after calling its [Cmd.Run], [Cmd.Output] or [Cmd.CombinedOutput] // methods. type Cmd struct { // Path is the path of the command to run. @@ -334,8 +334,10 @@ type Cmd struct { lookPathErr error // cachedLookExtensions caches the result of calling lookExtensions. + // It is set when Command is called with an absolute path, letting it do + // the work of resolving the extension, so Start doesn't need to do it again. // This is only used on Windows. - cachedLookExtensions string + cachedLookExtensions struct{ in, out string } } // A ctxResult reports the result of watching the Context associated with a @@ -355,12 +357,12 @@ type ctxResult struct { var execwait = godebug.New("#execwait") var execerrdot = godebug.New("execerrdot") -// Command returns the Cmd struct to execute the named program with +// Command returns the [Cmd] struct to execute the named program with // the given arguments. // // It sets only the Path and Args in the returned structure. // -// If name contains no path separators, Command uses LookPath to +// If name contains no path separators, Command uses [LookPath] to // resolve name to a complete path if possible. Otherwise it uses name // directly as Path. // @@ -436,22 +438,22 @@ func Command(name string, arg ...string) *Cmd { // Since the path is absolute, its extension should be unambiguous // and independent of cmd.Dir, and we can go ahead and cache the lookup now. // - // Note that we cannot add an extension here for relative paths, because - // cmd.Dir may be set after we return from this function and that may cause - // the command to resolve to a different extension. - lp, err := lookExtensions(name, "") - cmd.cachedLookExtensions = lp - if err != nil { + // Note that we don't cache anything here for relative paths, because + // cmd.Dir may be set after we return from this function and that may + // cause the command to resolve to a different extension. + if lp, err := lookExtensions(name, ""); err == nil { + cmd.cachedLookExtensions.in, cmd.cachedLookExtensions.out = name, lp + } else { cmd.Err = err } } return cmd } -// CommandContext is like Command but includes a context. +// CommandContext is like [Command] but includes a context. // // The provided context is used to interrupt the process -// (by calling cmd.Cancel or os.Process.Kill) +// (by calling cmd.Cancel or [os.Process.Kill]) // if the context becomes done before the command completes on its own. // // CommandContext sets the command's Cancel function to invoke the Kill method @@ -595,10 +597,10 @@ func closeDescriptors(closers []io.Closer) { // status. // // If the command starts but does not complete successfully, the error is of -// type *ExitError. Other error types may be returned for other situations. +// type [*ExitError]. Other error types may be returned for other situations. // // If the calling goroutine has locked the operating system thread -// with runtime.LockOSThread and modified any inheritable OS-level +// with [runtime.LockOSThread] and modified any inheritable OS-level // thread state (for example, Linux or Plan 9 name spaces), the new // process will inherit the caller's thread state. func (c *Cmd) Run() error { @@ -612,7 +614,7 @@ func (c *Cmd) Run() error { // // If Start returns successfully, the c.Process field will be set. // -// After a successful call to Start the Wait method must be called in +// After a successful call to Start the [Cmd.Wait] method must be called in // order to release associated system resources. func (c *Cmd) Start() error { // Check for doubled Start calls before we defer failure cleanup. If the prior @@ -642,29 +644,32 @@ func (c *Cmd) Start() error { return c.Err } lp := c.Path - if c.cachedLookExtensions != "" { - lp = c.cachedLookExtensions - } - if runtime.GOOS == "windows" && c.cachedLookExtensions == "" { - // If c.Path is relative, we had to wait until now - // to resolve it in case c.Dir was changed. - // (If it is absolute, we already resolved its extension in Command - // and shouldn't need to do so again.) - // - // Unfortunately, we cannot write the result back to c.Path because programs - // may assume that they can call Start concurrently with reading the path. - // (It is safe and non-racy to do so on Unix platforms, and users might not - // test with the race detector on all platforms; - // see https://go.dev/issue/62596.) - // - // So we will pass the fully resolved path to os.StartProcess, but leave - // c.Path as is: missing a bit of logging information seems less harmful - // than triggering a surprising data race, and if the user really cares - // about that bit of logging they can always use LookPath to resolve it. - var err error - lp, err = lookExtensions(c.Path, c.Dir) - if err != nil { - return err + if runtime.GOOS == "windows" { + if c.Path == c.cachedLookExtensions.in { + // If Command was called with an absolute path, we already resolved + // its extension and shouldn't need to do so again (provided c.Path + // wasn't set to another value between the calls to Command and Start). + lp = c.cachedLookExtensions.out + } else { + // If *Cmd was made without using Command at all, or if Command was + // called with a relative path, we had to wait until now to resolve + // it in case c.Dir was changed. + // + // Unfortunately, we cannot write the result back to c.Path because programs + // may assume that they can call Start concurrently with reading the path. + // (It is safe and non-racy to do so on Unix platforms, and users might not + // test with the race detector on all platforms; + // see https://go.dev/issue/62596.) + // + // So we will pass the fully resolved path to os.StartProcess, but leave + // c.Path as is: missing a bit of logging information seems less harmful + // than triggering a surprising data race, and if the user really cares + // about that bit of logging they can always use LookPath to resolve it. + var err error + lp, err = lookExtensions(c.Path, c.Dir) + if err != nil { + return err + } } } if c.Cancel != nil && c.ctx == nil { @@ -781,7 +786,7 @@ func (c *Cmd) watchCtx(resultc chan<- ctxResult) { } else if errors.Is(interruptErr, os.ErrProcessDone) { // The process already finished: we just didn't notice it yet. // (Perhaps c.Wait hadn't been called, or perhaps it happened to race with - // c.ctx being cancelled.) Don't inject a needless error. + // c.ctx being canceled.) Don't inject a needless error. } else { err = wrappedError{ prefix: "exec: canceling Cmd", @@ -876,20 +881,20 @@ func (e *ExitError) Error() string { // Wait waits for the command to exit and waits for any copying to // stdin or copying from stdout or stderr to complete. // -// The command must have been started by Start. +// The command must have been started by [Cmd.Start]. // // The returned error is nil if the command runs, has no problems // copying stdin, stdout, and stderr, and exits with a zero exit // status. // // If the command fails to run or doesn't complete successfully, the -// error is of type *ExitError. Other error types may be +// error is of type [*ExitError]. Other error types may be // returned for I/O problems. // -// If any of c.Stdin, c.Stdout or c.Stderr are not an *os.File, Wait also waits +// If any of c.Stdin, c.Stdout or c.Stderr are not an [*os.File], Wait also waits // for the respective I/O loop copying to or from the process to complete. // -// Wait releases any resources associated with the Cmd. +// Wait releases any resources associated with the [Cmd]. func (c *Cmd) Wait() error { if c.Process == nil { return errors.New("exec: not started") @@ -978,8 +983,8 @@ func (c *Cmd) awaitGoroutines(timer *time.Timer) error { } // Output runs the command and returns its standard output. -// Any returned error will usually be of type *ExitError. -// If c.Stderr was nil, Output populates ExitError.Stderr. +// Any returned error will usually be of type [*ExitError]. +// If c.Stderr was nil, Output populates [ExitError.Stderr]. func (c *Cmd) Output() ([]byte, error) { if c.Stdout != nil { return nil, errors.New("exec: Stdout already set") @@ -1019,7 +1024,7 @@ func (c *Cmd) CombinedOutput() ([]byte, error) { // StdinPipe returns a pipe that will be connected to the command's // standard input when the command starts. -// The pipe will be closed automatically after Wait sees the command exit. +// The pipe will be closed automatically after [Cmd.Wait] sees the command exit. // A caller need only call Close to force the pipe to close sooner. // For example, if the command being run will not exit until standard input // is closed, the caller must close the pipe. @@ -1043,10 +1048,10 @@ func (c *Cmd) StdinPipe() (io.WriteCloser, error) { // StdoutPipe returns a pipe that will be connected to the command's // standard output when the command starts. // -// Wait will close the pipe after seeing the command exit, so most callers +// [Cmd.Wait] will close the pipe after seeing the command exit, so most callers // need not close the pipe themselves. It is thus incorrect to call Wait // before all reads from the pipe have completed. -// For the same reason, it is incorrect to call Run when using StdoutPipe. +// For the same reason, it is incorrect to call [Cmd.Run] when using StdoutPipe. // See the example for idiomatic usage. func (c *Cmd) StdoutPipe() (io.ReadCloser, error) { if c.Stdout != nil { @@ -1068,10 +1073,10 @@ func (c *Cmd) StdoutPipe() (io.ReadCloser, error) { // StderrPipe returns a pipe that will be connected to the command's // standard error when the command starts. // -// Wait will close the pipe after seeing the command exit, so most callers +// [Cmd.Wait] will close the pipe after seeing the command exit, so most callers // need not close the pipe themselves. It is thus incorrect to call Wait // before all reads from the pipe have completed. -// For the same reason, it is incorrect to use Run when using StderrPipe. +// For the same reason, it is incorrect to use [Cmd.Run] when using StderrPipe. // See the StdoutPipe example for idiomatic usage. func (c *Cmd) StderrPipe() (io.ReadCloser, error) { if c.Stderr != nil { diff --git a/contrib/go/_std_1.22/src/os/exec/exec_plan9.go b/contrib/go/_std_1.23/src/os/exec/exec_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/exec_plan9.go rename to contrib/go/_std_1.23/src/os/exec/exec_plan9.go diff --git a/contrib/go/_std_1.22/src/os/exec/exec_unix.go b/contrib/go/_std_1.23/src/os/exec/exec_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/exec_unix.go rename to contrib/go/_std_1.23/src/os/exec/exec_unix.go diff --git a/contrib/go/_std_1.22/src/os/exec/exec_windows.go b/contrib/go/_std_1.23/src/os/exec/exec_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/exec_windows.go rename to contrib/go/_std_1.23/src/os/exec/exec_windows.go diff --git a/contrib/go/_std_1.22/src/os/exec/internal/fdtest/exists_plan9.go b/contrib/go/_std_1.23/src/os/exec/internal/fdtest/exists_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/internal/fdtest/exists_plan9.go rename to contrib/go/_std_1.23/src/os/exec/internal/fdtest/exists_plan9.go diff --git a/contrib/go/_std_1.22/src/os/exec/internal/fdtest/exists_unix.go b/contrib/go/_std_1.23/src/os/exec/internal/fdtest/exists_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/internal/fdtest/exists_unix.go rename to contrib/go/_std_1.23/src/os/exec/internal/fdtest/exists_unix.go diff --git a/contrib/go/_std_1.22/src/os/exec/internal/fdtest/exists_windows.go b/contrib/go/_std_1.23/src/os/exec/internal/fdtest/exists_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/internal/fdtest/exists_windows.go rename to contrib/go/_std_1.23/src/os/exec/internal/fdtest/exists_windows.go diff --git a/contrib/go/_std_1.22/src/os/exec/internal/fdtest/ya.make b/contrib/go/_std_1.23/src/os/exec/internal/fdtest/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/internal/fdtest/ya.make rename to contrib/go/_std_1.23/src/os/exec/internal/fdtest/ya.make diff --git a/contrib/go/_std_1.22/src/os/exec/internal/ya.make b/contrib/go/_std_1.23/src/os/exec/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/internal/ya.make rename to contrib/go/_std_1.23/src/os/exec/internal/ya.make diff --git a/contrib/go/_std_1.22/src/os/exec/lp_plan9.go b/contrib/go/_std_1.23/src/os/exec/lp_plan9.go similarity index 96% rename from contrib/go/_std_1.22/src/os/exec/lp_plan9.go rename to contrib/go/_std_1.23/src/os/exec/lp_plan9.go index dffdbac35f8e..87359b3551d3 100644 --- a/contrib/go/_std_1.22/src/os/exec/lp_plan9.go +++ b/contrib/go/_std_1.23/src/os/exec/lp_plan9.go @@ -34,7 +34,7 @@ func findExecutable(file string) error { // // In older versions of Go, LookPath could return a path relative to the current directory. // As of Go 1.19, LookPath will instead return that path along with an error satisfying -// errors.Is(err, ErrDot). See the package documentation for more details. +// [errors.Is](err, [ErrDot]). See the package documentation for more details. func LookPath(file string) (string, error) { // skip the path lookup for these prefixes skip := []string{"/", "#", "./", "../"} diff --git a/contrib/go/_std_1.22/src/os/exec/lp_unix.go b/contrib/go/_std_1.23/src/os/exec/lp_unix.go similarity index 96% rename from contrib/go/_std_1.22/src/os/exec/lp_unix.go rename to contrib/go/_std_1.23/src/os/exec/lp_unix.go index 37871320786a..8617d45e983e 100644 --- a/contrib/go/_std_1.22/src/os/exec/lp_unix.go +++ b/contrib/go/_std_1.23/src/os/exec/lp_unix.go @@ -48,7 +48,7 @@ func findExecutable(file string) error { // // In older versions of Go, LookPath could return a path relative to the current directory. // As of Go 1.19, LookPath will instead return that path along with an error satisfying -// errors.Is(err, ErrDot). See the package documentation for more details. +// [errors.Is](err, [ErrDot]). See the package documentation for more details. func LookPath(file string) (string, error) { // NOTE(rsc): I wish we could use the Plan 9 behavior here // (only bypass the path if file begins with / or ./ or ../) diff --git a/contrib/go/_std_1.22/src/os/exec/lp_wasm.go b/contrib/go/_std_1.23/src/os/exec/lp_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/lp_wasm.go rename to contrib/go/_std_1.23/src/os/exec/lp_wasm.go diff --git a/contrib/go/_std_1.22/src/os/exec/lp_windows.go b/contrib/go/_std_1.23/src/os/exec/lp_windows.go similarity index 98% rename from contrib/go/_std_1.22/src/os/exec/lp_windows.go rename to contrib/go/_std_1.23/src/os/exec/lp_windows.go index 698a97c40f6f..0e058d41b0c1 100644 --- a/contrib/go/_std_1.22/src/os/exec/lp_windows.go +++ b/contrib/go/_std_1.23/src/os/exec/lp_windows.go @@ -66,7 +66,7 @@ func findExecutable(file string, exts []string) (string, error) { // // In older versions of Go, LookPath could return a path relative to the current directory. // As of Go 1.19, LookPath will instead return that path along with an error satisfying -// errors.Is(err, ErrDot). See the package documentation for more details. +// [errors.Is](err, [ErrDot]). See the package documentation for more details. func LookPath(file string) (string, error) { return lookPath(file, pathExt()) } diff --git a/contrib/go/_std_1.22/src/os/exec/read3.go b/contrib/go/_std_1.23/src/os/exec/read3.go similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/read3.go rename to contrib/go/_std_1.23/src/os/exec/read3.go diff --git a/contrib/go/_std_1.22/src/os/exec/ya.make b/contrib/go/_std_1.23/src/os/exec/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/os/exec/ya.make rename to contrib/go/_std_1.23/src/os/exec/ya.make diff --git a/contrib/go/_std_1.23/src/os/exec_linux.go b/contrib/go/_std_1.23/src/os/exec_linux.go new file mode 100644 index 000000000000..b47c6cb19198 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/exec_linux.go @@ -0,0 +1,13 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "syscall" +) + +func (p *Process) closeHandle() { + syscall.Close(int(p.handle)) +} diff --git a/contrib/go/_std_1.23/src/os/exec_nohandle.go b/contrib/go/_std_1.23/src/os/exec_nohandle.go new file mode 100644 index 000000000000..d06f4091c3eb --- /dev/null +++ b/contrib/go/_std_1.23/src/os/exec_nohandle.go @@ -0,0 +1,9 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !linux && !windows + +package os + +func (p *Process) closeHandle() {} diff --git a/contrib/go/_std_1.22/src/os/exec_plan9.go b/contrib/go/_std_1.23/src/os/exec_plan9.go similarity index 88% rename from contrib/go/_std_1.22/src/os/exec_plan9.go rename to contrib/go/_std_1.23/src/os/exec_plan9.go index 69714ff79830..bc7a9cdcbc5f 100644 --- a/contrib/go/_std_1.22/src/os/exec_plan9.go +++ b/contrib/go/_std_1.23/src/os/exec_plan9.go @@ -14,7 +14,7 @@ import ( // The only signal values guaranteed to be present in the os package // on all systems are Interrupt (send the process an interrupt) and // Kill (force the process to exit). Interrupt is not implemented on -// Windows; using it with os.Process.Signal will return an error. +// Windows; using it with [os.Process.Signal] will return an error. var ( Interrupt Signal = syscall.Note("interrupt") Kill Signal = syscall.Note("kill") @@ -32,12 +32,12 @@ func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e sysattr.Files = append(sysattr.Files, f.Fd()) } - pid, h, e := syscall.StartProcess(name, argv, sysattr) + pid, _, e := syscall.StartProcess(name, argv, sysattr) if e != nil { return nil, &PathError{Op: "fork/exec", Path: name, Err: e} } - return newProcess(pid, h), nil + return newPIDProcess(pid), nil } func (p *Process) writeProcFile(file string, data string) error { @@ -51,9 +51,13 @@ func (p *Process) writeProcFile(file string, data string) error { } func (p *Process) signal(sig Signal) error { - if p.done() { + switch p.pidStatus() { + case statusDone: return ErrProcessDone + case statusReleased: + return syscall.ENOENT } + if e := p.writeProcFile("note", sig.String()); e != nil { return NewSyscallError("signal", e) } @@ -67,15 +71,17 @@ func (p *Process) kill() error { func (p *Process) wait() (ps *ProcessState, err error) { var waitmsg syscall.Waitmsg - if p.Pid == -1 { + switch p.pidStatus() { + case statusReleased: return nil, ErrInvalid } + err = syscall.WaitProcess(p.Pid, &waitmsg) if err != nil { return nil, NewSyscallError("wait", err) } - p.setDone() + p.pidDeactivate(statusDone) ps = &ProcessState{ pid: waitmsg.Pid, status: &waitmsg, @@ -84,8 +90,11 @@ func (p *Process) wait() (ps *ProcessState, err error) { } func (p *Process) release() error { - // NOOP for Plan 9. p.Pid = -1 + + // Just mark the PID unusable. + p.pidDeactivate(statusReleased) + // no need for a finalizer anymore runtime.SetFinalizer(p, nil) return nil @@ -93,7 +102,7 @@ func (p *Process) release() error { func findProcess(pid int) (p *Process, err error) { // NOOP for Plan 9. - return newProcess(pid, 0), nil + return newPIDProcess(pid), nil } // ProcessState stores information about a process, as reported by Wait. diff --git a/contrib/go/_std_1.22/src/os/exec_posix.go b/contrib/go/_std_1.23/src/os/exec_posix.go similarity index 91% rename from contrib/go/_std_1.22/src/os/exec_posix.go rename to contrib/go/_std_1.23/src/os/exec_posix.go index 4f9ea08cde51..ff51247d56b7 100644 --- a/contrib/go/_std_1.22/src/os/exec_posix.go +++ b/contrib/go/_std_1.23/src/os/exec_posix.go @@ -35,10 +35,11 @@ func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e } } + attrSys, shouldDupPidfd := ensurePidfd(attr.Sys) sysattr := &syscall.ProcAttr{ Dir: attr.Dir, Env: attr.Env, - Sys: attr.Sys, + Sys: attrSys, } if sysattr.Env == nil { sysattr.Env, err = execenv.Default(sysattr.Sys) @@ -60,7 +61,16 @@ func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e return nil, &PathError{Op: "fork/exec", Path: name, Err: e} } - return newProcess(pid, h), nil + // For Windows, syscall.StartProcess above already returned a process handle. + if runtime.GOOS != "windows" { + var ok bool + h, ok = getPidfd(sysattr.Sys, shouldDupPidfd) + if !ok { + return newPIDProcess(pid), nil + } + } + + return newHandleProcess(pid, h), nil } func (p *Process) kill() error { diff --git a/contrib/go/_std_1.23/src/os/exec_unix.go b/contrib/go/_std_1.23/src/os/exec_unix.go new file mode 100644 index 000000000000..ba6146ada11b --- /dev/null +++ b/contrib/go/_std_1.23/src/os/exec_unix.go @@ -0,0 +1,178 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix || (js && wasm) || wasip1 + +package os + +import ( + "errors" + "runtime" + "syscall" + "time" +) + +const ( + // Special values for Process.Pid. + pidUnset = 0 + pidReleased = -1 +) + +func (p *Process) wait() (ps *ProcessState, err error) { + // Which type of Process do we have? + switch p.mode { + case modeHandle: + // pidfd + return p.pidfdWait() + case modePID: + // Regular PID + return p.pidWait() + default: + panic("unreachable") + } +} + +func (p *Process) pidWait() (*ProcessState, error) { + // TODO(go.dev/issue/67642): When there are concurrent Wait calls, one + // may wait on the wrong process if the PID is reused after the + // completes its wait. + // + // Checking for statusDone here would not be a complete fix, as the PID + // could still be waited on and reused prior to blockUntilWaitable. + switch p.pidStatus() { + case statusReleased: + return nil, syscall.EINVAL + } + + // If we can block until Wait4 will succeed immediately, do so. + ready, err := p.blockUntilWaitable() + if err != nil { + return nil, err + } + if ready { + // Mark the process done now, before the call to Wait4, + // so that Process.pidSignal will not send a signal. + p.pidDeactivate(statusDone) + // Acquire a write lock on sigMu to wait for any + // active call to the signal method to complete. + p.sigMu.Lock() + p.sigMu.Unlock() + } + + var ( + status syscall.WaitStatus + rusage syscall.Rusage + pid1 int + e error + ) + for { + pid1, e = syscall.Wait4(p.Pid, &status, 0, &rusage) + if e != syscall.EINTR { + break + } + } + if e != nil { + return nil, NewSyscallError("wait", e) + } + p.pidDeactivate(statusDone) + return &ProcessState{ + pid: pid1, + status: status, + rusage: &rusage, + }, nil +} + +func (p *Process) signal(sig Signal) error { + s, ok := sig.(syscall.Signal) + if !ok { + return errors.New("os: unsupported signal type") + } + + // Which type of Process do we have? + switch p.mode { + case modeHandle: + // pidfd + return p.pidfdSendSignal(s) + case modePID: + // Regular PID + return p.pidSignal(s) + default: + panic("unreachable") + } +} + +func (p *Process) pidSignal(s syscall.Signal) error { + if p.Pid == pidReleased { + return errors.New("os: process already released") + } + if p.Pid == pidUnset { + return errors.New("os: process not initialized") + } + + p.sigMu.RLock() + defer p.sigMu.RUnlock() + + switch p.pidStatus() { + case statusDone: + return ErrProcessDone + case statusReleased: + return errors.New("os: process already released") + } + + return convertESRCH(syscall.Kill(p.Pid, s)) +} + +func convertESRCH(err error) error { + if err == syscall.ESRCH { + return ErrProcessDone + } + return err +} + +func (p *Process) release() error { + // We clear the Pid field only for API compatibility. On Unix, Release + // has always set Pid to -1. Internally, the implementation relies + // solely on statusReleased to determine that the Process is released. + p.Pid = pidReleased + + switch p.mode { + case modeHandle: + // Drop the Process' reference and mark handle unusable for + // future calls. + // + // Ignore the return value: we don't care if this was a no-op + // racing with Wait, or a double Release. + p.handlePersistentRelease(statusReleased) + case modePID: + // Just mark the PID unusable. + p.pidDeactivate(statusReleased) + } + // no need for a finalizer anymore + runtime.SetFinalizer(p, nil) + return nil +} + +func findProcess(pid int) (p *Process, err error) { + h, err := pidfdFind(pid) + if err == ErrProcessDone { + // We can't return an error here since users are not expecting + // it. Instead, return a process with a "done" state already + // and let a subsequent Signal or Wait call catch that. + return newDoneProcess(pid), nil + } else if err != nil { + // Ignore other errors from pidfdFind, as the callers + // do not expect them. Fall back to using the PID. + return newPIDProcess(pid), nil + } + // Use the handle. + return newHandleProcess(pid, h), nil +} + +func (p *ProcessState) userTime() time.Duration { + return time.Duration(p.rusage.Utime.Nano()) * time.Nanosecond +} + +func (p *ProcessState) systemTime() time.Duration { + return time.Duration(p.rusage.Stime.Nano()) * time.Nanosecond +} diff --git a/contrib/go/_std_1.22/src/os/exec_windows.go b/contrib/go/_std_1.23/src/os/exec_windows.go similarity index 83% rename from contrib/go/_std_1.22/src/os/exec_windows.go rename to contrib/go/_std_1.23/src/os/exec_windows.go index 061a12b10f3d..ab2dae1d7185 100644 --- a/contrib/go/_std_1.22/src/os/exec_windows.go +++ b/contrib/go/_std_1.23/src/os/exec_windows.go @@ -8,13 +8,23 @@ import ( "errors" "internal/syscall/windows" "runtime" - "sync/atomic" "syscall" "time" ) +// Note that Process.mode is always modeHandle because Windows always requires +// a handle. A manually-created Process literal is not valid. + func (p *Process) wait() (ps *ProcessState, err error) { - handle := atomic.LoadUintptr(&p.handle) + handle, status := p.handleTransientAcquire() + switch status { + case statusDone: + return nil, ErrProcessDone + case statusReleased: + return nil, syscall.EINVAL + } + defer p.handleTransientRelease() + s, e := syscall.WaitForSingleObject(syscall.Handle(handle), syscall.INFINITE) switch s { case syscall.WAIT_OBJECT_0: @@ -34,19 +44,20 @@ func (p *Process) wait() (ps *ProcessState, err error) { if e != nil { return nil, NewSyscallError("GetProcessTimes", e) } - p.setDone() defer p.Release() return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil } func (p *Process) signal(sig Signal) error { - handle := atomic.LoadUintptr(&p.handle) - if handle == uintptr(syscall.InvalidHandle) { - return syscall.EINVAL - } - if p.done() { + handle, status := p.handleTransientAcquire() + switch status { + case statusDone: return ErrProcessDone + case statusReleased: + return syscall.EINVAL } + defer p.handleTransientRelease() + if sig == Kill { var terminationHandle syscall.Handle e := syscall.DuplicateHandle(^syscall.Handle(0), syscall.Handle(handle), ^syscall.Handle(0), &terminationHandle, syscall.PROCESS_TERMINATE, false, 0) @@ -63,19 +74,24 @@ func (p *Process) signal(sig Signal) error { } func (p *Process) release() error { - handle := atomic.SwapUintptr(&p.handle, uintptr(syscall.InvalidHandle)) - if handle == uintptr(syscall.InvalidHandle) { + // Drop the Process' reference and mark handle unusable for + // future calls. + // + // The API on Windows expects EINVAL if Release is called multiple + // times. + if old := p.handlePersistentRelease(statusReleased); old == statusReleased { return syscall.EINVAL } - e := syscall.CloseHandle(syscall.Handle(handle)) - if e != nil { - return NewSyscallError("CloseHandle", e) - } + // no need for a finalizer anymore runtime.SetFinalizer(p, nil) return nil } +func (p *Process) closeHandle() { + syscall.CloseHandle(syscall.Handle(p.handle)) +} + func findProcess(pid int) (p *Process, err error) { const da = syscall.STANDARD_RIGHTS_READ | syscall.PROCESS_QUERY_INFORMATION | syscall.SYNCHRONIZE @@ -83,7 +99,7 @@ func findProcess(pid int) (p *Process, err error) { if e != nil { return nil, NewSyscallError("OpenProcess", e) } - return newProcess(pid, uintptr(h)), nil + return newHandleProcess(pid, uintptr(h)), nil } func init() { diff --git a/contrib/go/_std_1.22/src/os/executable.go b/contrib/go/_std_1.23/src/os/executable.go similarity index 93% rename from contrib/go/_std_1.22/src/os/executable.go rename to contrib/go/_std_1.23/src/os/executable.go index cc3134af1c1e..ae7ec139c368 100644 --- a/contrib/go/_std_1.22/src/os/executable.go +++ b/contrib/go/_std_1.23/src/os/executable.go @@ -9,7 +9,7 @@ package os // pointing to the correct executable. If a symlink was used to start // the process, depending on the operating system, the result might // be the symlink or the path it pointed to. If a stable result is -// needed, path/filepath.EvalSymlinks might help. +// needed, [path/filepath.EvalSymlinks] might help. // // Executable returns an absolute path unless an error occurred. // diff --git a/contrib/go/_std_1.22/src/os/executable_darwin.go b/contrib/go/_std_1.23/src/os/executable_darwin.go similarity index 88% rename from contrib/go/_std_1.22/src/os/executable_darwin.go rename to contrib/go/_std_1.23/src/os/executable_darwin.go index dae9f4ee18ec..2bb50ab3fef4 100644 --- a/contrib/go/_std_1.22/src/os/executable_darwin.go +++ b/contrib/go/_std_1.23/src/os/executable_darwin.go @@ -4,8 +4,12 @@ package os -import "errors" +import ( + "errors" + _ "unsafe" // for linkname +) +//go:linkname executablePath var executablePath string // set by ../runtime/os_darwin.go var initCwd, initCwdErr = Getwd() diff --git a/contrib/go/_std_1.22/src/os/executable_dragonfly.go b/contrib/go/_std_1.23/src/os/executable_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/os/executable_dragonfly.go rename to contrib/go/_std_1.23/src/os/executable_dragonfly.go diff --git a/contrib/go/_std_1.22/src/os/executable_freebsd.go b/contrib/go/_std_1.23/src/os/executable_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/executable_freebsd.go rename to contrib/go/_std_1.23/src/os/executable_freebsd.go diff --git a/contrib/go/_std_1.22/src/os/executable_path.go b/contrib/go/_std_1.23/src/os/executable_path.go similarity index 100% rename from contrib/go/_std_1.22/src/os/executable_path.go rename to contrib/go/_std_1.23/src/os/executable_path.go diff --git a/contrib/go/_std_1.22/src/os/executable_plan9.go b/contrib/go/_std_1.23/src/os/executable_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/executable_plan9.go rename to contrib/go/_std_1.23/src/os/executable_plan9.go diff --git a/contrib/go/_std_1.22/src/os/executable_procfs.go b/contrib/go/_std_1.23/src/os/executable_procfs.go similarity index 70% rename from contrib/go/_std_1.22/src/os/executable_procfs.go rename to contrib/go/_std_1.23/src/os/executable_procfs.go index 94e674e36486..6a2cd10be7c4 100644 --- a/contrib/go/_std_1.22/src/os/executable_procfs.go +++ b/contrib/go/_std_1.23/src/os/executable_procfs.go @@ -8,6 +8,7 @@ package os import ( "errors" + "internal/stringslite" "runtime" ) @@ -25,13 +26,5 @@ func executable() (string, error) { // When the executable has been deleted then Readlink returns a // path appended with " (deleted)". - return stringsTrimSuffix(path, " (deleted)"), err -} - -// stringsTrimSuffix is the same as strings.TrimSuffix. -func stringsTrimSuffix(s, suffix string) string { - if len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix { - return s[:len(s)-len(suffix)] - } - return s + return stringslite.TrimSuffix(path, " (deleted)"), err } diff --git a/contrib/go/_std_1.22/src/os/executable_solaris.go b/contrib/go/_std_1.23/src/os/executable_solaris.go similarity index 89% rename from contrib/go/_std_1.22/src/os/executable_solaris.go rename to contrib/go/_std_1.23/src/os/executable_solaris.go index b145980c5656..8ee897f4b0e5 100644 --- a/contrib/go/_std_1.22/src/os/executable_solaris.go +++ b/contrib/go/_std_1.23/src/os/executable_solaris.go @@ -4,8 +4,12 @@ package os -import "syscall" +import ( + "syscall" + _ "unsafe" // for linkname +) +//go:linkname executablePath var executablePath string // set by sysauxv in ../runtime/os3_solaris.go var initCwd, initCwdErr = Getwd() diff --git a/contrib/go/_std_1.22/src/os/executable_sysctl.go b/contrib/go/_std_1.23/src/os/executable_sysctl.go similarity index 100% rename from contrib/go/_std_1.22/src/os/executable_sysctl.go rename to contrib/go/_std_1.23/src/os/executable_sysctl.go diff --git a/contrib/go/_std_1.22/src/os/executable_wasm.go b/contrib/go/_std_1.23/src/os/executable_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/os/executable_wasm.go rename to contrib/go/_std_1.23/src/os/executable_wasm.go diff --git a/contrib/go/_std_1.22/src/os/executable_windows.go b/contrib/go/_std_1.23/src/os/executable_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/os/executable_windows.go rename to contrib/go/_std_1.23/src/os/executable_windows.go diff --git a/contrib/go/_std_1.22/src/os/file.go b/contrib/go/_std_1.23/src/os/file.go similarity index 95% rename from contrib/go/_std_1.22/src/os/file.go rename to contrib/go/_std_1.23/src/os/file.go index 090ffba4dc73..ad869fc4938d 100644 --- a/contrib/go/_std_1.22/src/os/file.go +++ b/contrib/go/_std_1.23/src/os/file.go @@ -6,9 +6,9 @@ // functionality. The design is Unix-like, although the error handling is // Go-like; failing calls return values of type error rather than error numbers. // Often, more information is available within the error. For example, -// if a call that takes a file name fails, such as Open or Stat, the error +// if a call that takes a file name fails, such as [Open] or [Stat], the error // will include the failing file name when printed and will be of type -// *PathError, which may be unpacked for more information. +// [*PathError], which may be unpacked for more information. // // The os interface is intended to be uniform across all operating systems. // Features not generally available appear in the system-specific package syscall. @@ -34,15 +34,19 @@ // } // fmt.Printf("read %d bytes: %q\n", count, data[:count]) // -// Note: The maximum number of concurrent operations on a File may be limited by -// the OS or the system. The number should be high, but exceeding it may degrade -// performance or cause other issues. +// # Concurrency +// +// The methods of [File] correspond to file system operations. All are +// safe for concurrent use. The maximum number of concurrent +// operations on a File may be limited by the OS or the system. The +// number should be high, but exceeding it may degrade performance or +// cause other issues. package os import ( "errors" + "internal/filepathlite" "internal/poll" - "internal/safefilepath" "internal/testlog" "io" "io/fs" @@ -53,6 +57,8 @@ import ( ) // Name returns the name of the file as presented to Open. +// +// It is safe to call Name after [Close]. func (f *File) Name() string { return f.name } // Stdin, Stdout, and Stderr are open Files pointing to the standard input, @@ -279,7 +285,7 @@ func (f *File) Seek(offset int64, whence int) (ret int64, err error) { return 0, err } r, e := f.seek(offset, whence) - if e == nil && f.dirinfo != nil && r != 0 { + if e == nil && f.dirinfo.Load() != nil && r != 0 { e = syscall.EISDIR } if e != nil { @@ -337,6 +343,11 @@ func Chdir(dir string) error { testlog.Open(dir) // observe likely non-existent directory return &PathError{Op: "chdir", Path: dir, Err: e} } + if runtime.GOOS == "windows" { + getwdCache.Lock() + getwdCache.dir = dir + getwdCache.Unlock() + } if log := testlog.Logger(); log != nil { wd, err := Getwd() if err == nil { @@ -355,7 +366,7 @@ func Open(name string) (*File, error) { } // Create creates or truncates the named file. If the file already exists, -// it is truncated. If the file does not exist, it is created with mode 0666 +// it is truncated. If the file does not exist, it is created with mode 0o666 // (before umask). If successful, methods on the returned File can // be used for I/O; the associated file descriptor has mode O_RDWR. // If there is an error, it will be of type *PathError. @@ -380,6 +391,14 @@ func OpenFile(name string, flag int, perm FileMode) (*File, error) { return f, nil } +// openDir opens a file which is assumed to be a directory. As such, it skips +// the syscalls that make the file descriptor non-blocking as these take time +// and will fail on file descriptors for directories. +func openDir(name string) (*File, error) { + testlog.Open(name) + return openDirNolog(name) +} + // lstat is overridden in tests. var lstat = Lstat @@ -583,11 +602,11 @@ func UserHomeDir() (string, error) { // On Unix, the mode's permission bits, ModeSetuid, ModeSetgid, and // ModeSticky are used. // -// On Windows, only the 0200 bit (owner writable) of mode is used; it +// On Windows, only the 0o200 bit (owner writable) of mode is used; it // controls whether the file's read-only attribute is set or cleared. // The other bits are currently unused. For compatibility with Go 1.12 -// and earlier, use a non-zero mode. Use mode 0400 for a read-only -// file and 0600 for a readable+writable file. +// and earlier, use a non-zero mode. Use mode 0o400 for a read-only +// file and 0o600 for a readable+writable file. // // On Plan 9, the mode's permission bits, ModeAppend, ModeExclusive, // and ModeTemporary are used. @@ -747,10 +766,7 @@ func (dir dirFS) join(name string) (string, error) { if dir == "" { return "", errors.New("os: DirFS with empty root") } - if !fs.ValidPath(name) { - return "", ErrInvalid - } - name, err := safefilepath.FromFS(name) + name, err := filepathlite.Localize(name) if err != nil { return "", ErrInvalid } diff --git a/contrib/go/_std_1.22/src/os/file_mutex_plan9.go b/contrib/go/_std_1.23/src/os/file_mutex_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/file_mutex_plan9.go rename to contrib/go/_std_1.23/src/os/file_mutex_plan9.go diff --git a/contrib/go/_std_1.22/src/os/file_open_unix.go b/contrib/go/_std_1.23/src/os/file_open_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/file_open_unix.go rename to contrib/go/_std_1.23/src/os/file_open_unix.go diff --git a/contrib/go/_std_1.22/src/os/file_open_wasip1.go b/contrib/go/_std_1.23/src/os/file_open_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/os/file_open_wasip1.go rename to contrib/go/_std_1.23/src/os/file_open_wasip1.go diff --git a/contrib/go/_std_1.22/src/os/file_plan9.go b/contrib/go/_std_1.23/src/os/file_plan9.go similarity index 96% rename from contrib/go/_std_1.22/src/os/file_plan9.go rename to contrib/go/_std_1.23/src/os/file_plan9.go index c0ee6b33f9f9..ef277deccce0 100644 --- a/contrib/go/_std_1.22/src/os/file_plan9.go +++ b/contrib/go/_std_1.23/src/os/file_plan9.go @@ -7,8 +7,11 @@ package os import ( "internal/bytealg" "internal/poll" + "internal/stringslite" "io" "runtime" + "sync" + "sync/atomic" "syscall" "time" ) @@ -26,15 +29,15 @@ type file struct { fdmu poll.FDMutex fd int name string - dirinfo *dirInfo // nil unless directory being read - appendMode bool // whether file is opened for appending + dirinfo atomic.Pointer[dirInfo] // nil unless directory being read + appendMode bool // whether file is opened for appending } // Fd returns the integer Plan 9 file descriptor referencing the open file. // If f is closed, the file descriptor becomes invalid. // If f is garbage collected, a finalizer may close the file descriptor, -// making it invalid; see runtime.SetFinalizer for more information on when -// a finalizer might be run. On Unix systems this will cause the SetDeadline +// making it invalid; see [runtime.SetFinalizer] for more information on when +// a finalizer might be run. On Unix systems this will cause the [File.SetDeadline] // methods to stop working. // // As an alternative, see the f.SyscallConn method. @@ -60,6 +63,7 @@ func NewFile(fd uintptr, name string) *File { // Auxiliary information if the File describes a directory type dirInfo struct { + mu sync.Mutex buf [syscall.STATMAX]byte // buffer for directory I/O nbuf int // length of buf; return value from Read bufp int // location of next record in buf. @@ -139,6 +143,10 @@ func openFileNolog(name string, flag int, perm FileMode) (*File, error) { return NewFile(uintptr(fd), name), nil } +func openDirNolog(name string) (*File, error) { + return openFileNolog(name, O_RDONLY, 0) +} + // Close closes the File, rendering it unusable for I/O. // On files that support SetDeadline, any pending I/O operations will // be canceled and return immediately with an ErrClosed error. @@ -345,11 +353,9 @@ func (f *File) seek(offset int64, whence int) (ret int64, err error) { return 0, err } defer f.decref() - if f.dirinfo != nil { - // Free cached dirinfo, so we allocate a new one if we - // access this file as a directory again. See #35767 and #37161. - f.dirinfo = nil - } + // Free cached dirinfo, so we allocate a new one if we + // access this file as a directory again. See #35767 and #37161. + f.dirinfo.Store(nil) return syscall.Seek(f.fd, offset, whence) } @@ -382,14 +388,9 @@ func Remove(name string) error { return nil } -// hasPrefix from the strings package. -func hasPrefix(s, prefix string) bool { - return len(s) >= len(prefix) && s[0:len(prefix)] == prefix -} - func rename(oldname, newname string) error { dirname := oldname[:bytealg.LastIndexByteString(oldname, '/')+1] - if hasPrefix(newname, dirname) { + if stringslite.HasPrefix(newname, dirname) { newname = newname[len(dirname):] } else { return &LinkError{"rename", oldname, newname, ErrInvalid} diff --git a/contrib/go/_std_1.22/src/os/file_posix.go b/contrib/go/_std_1.23/src/os/file_posix.go similarity index 88% rename from contrib/go/_std_1.22/src/os/file_posix.go rename to contrib/go/_std_1.23/src/os/file_posix.go index 569265775337..8ff0ada46290 100644 --- a/contrib/go/_std_1.22/src/os/file_posix.go +++ b/contrib/go/_std_1.23/src/os/file_posix.go @@ -12,9 +12,9 @@ import ( "time" ) -// Close closes the File, rendering it unusable for I/O. -// On files that support SetDeadline, any pending I/O operations will -// be canceled and return immediately with an ErrClosed error. +// Close closes the [File], rendering it unusable for I/O. +// On files that support [File.SetDeadline], any pending I/O operations will +// be canceled and return immediately with an [ErrClosed] error. // Close will return an error if it has already been called. func (f *File) Close() error { if f == nil { @@ -98,9 +98,9 @@ func (f *File) chmod(mode FileMode) error { // Chown changes the numeric uid and gid of the named file. // If the file is a symbolic link, it changes the uid and gid of the link's target. // A uid or gid of -1 means to not change that value. -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. // -// On Windows or Plan 9, Chown always returns the syscall.EWINDOWS or +// On Windows or Plan 9, Chown always returns the [syscall.EWINDOWS] or // EPLAN9 error, wrapped in *PathError. func Chown(name string, uid, gid int) error { e := ignoringEINTR(func() error { @@ -114,9 +114,9 @@ func Chown(name string, uid, gid int) error { // Lchown changes the numeric uid and gid of the named file. // If the file is a symbolic link, it changes the uid and gid of the link itself. -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. // -// On Windows, it always returns the syscall.EWINDOWS error, wrapped +// On Windows, it always returns the [syscall.EWINDOWS] error, wrapped // in *PathError. func Lchown(name string, uid, gid int) error { e := ignoringEINTR(func() error { @@ -129,9 +129,9 @@ func Lchown(name string, uid, gid int) error { } // Chown changes the numeric uid and gid of the named file. -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. // -// On Windows, it always returns the syscall.EWINDOWS error, wrapped +// On Windows, it always returns the [syscall.EWINDOWS] error, wrapped // in *PathError. func (f *File) Chown(uid, gid int) error { if err := f.checkValid("chown"); err != nil { @@ -145,7 +145,7 @@ func (f *File) Chown(uid, gid int) error { // Truncate changes the size of the file. // It does not change the I/O offset. -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. func (f *File) Truncate(size int64) error { if err := f.checkValid("truncate"); err != nil { return err @@ -171,11 +171,11 @@ func (f *File) Sync() error { // Chtimes changes the access and modification times of the named // file, similar to the Unix utime() or utimes() functions. -// A zero time.Time value will leave the corresponding file time unchanged. +// A zero [time.Time] value will leave the corresponding file time unchanged. // // The underlying filesystem may truncate or round the values to a // less precise time unit. -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. func Chtimes(name string, atime time.Time, mtime time.Time) error { var utimes [2]syscall.Timespec set := func(i int, t time.Time) { @@ -195,7 +195,7 @@ func Chtimes(name string, atime time.Time, mtime time.Time) error { // Chdir changes the current working directory to the file, // which must be a directory. -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. func (f *File) Chdir() error { if err := f.checkValid("chdir"); err != nil { return err diff --git a/contrib/go/_std_1.22/src/os/file_unix.go b/contrib/go/_std_1.23/src/os/file_unix.go similarity index 82% rename from contrib/go/_std_1.22/src/os/file_unix.go rename to contrib/go/_std_1.23/src/os/file_unix.go index 649ec3ebb591..37bfaa1a72df 100644 --- a/contrib/go/_std_1.22/src/os/file_unix.go +++ b/contrib/go/_std_1.23/src/os/file_unix.go @@ -11,6 +11,7 @@ import ( "internal/syscall/unix" "io/fs" "runtime" + "sync/atomic" "syscall" _ "unsafe" // for go:linkname ) @@ -58,20 +59,20 @@ func rename(oldname, newname string) error { type file struct { pfd poll.FD name string - dirinfo *dirInfo // nil unless directory being read - nonblock bool // whether we set nonblocking mode - stdoutOrErr bool // whether this is stdout or stderr - appendMode bool // whether file is opened for appending + dirinfo atomic.Pointer[dirInfo] // nil unless directory being read + nonblock bool // whether we set nonblocking mode + stdoutOrErr bool // whether this is stdout or stderr + appendMode bool // whether file is opened for appending } // Fd returns the integer Unix file descriptor referencing the open file. // If f is closed, the file descriptor becomes invalid. // If f is garbage collected, a finalizer may close the file descriptor, -// making it invalid; see runtime.SetFinalizer for more information on when -// a finalizer might be run. On Unix systems this will cause the SetDeadline +// making it invalid; see [runtime.SetFinalizer] for more information on when +// a finalizer might be run. On Unix systems this will cause the [File.SetDeadline] // methods to stop working. // Because file descriptors can be reused, the returned file descriptor may -// only be closed through the Close method of f, or by its finalizer during +// only be closed through the [File.Close] method of f, or by its finalizer during // garbage collection. Otherwise, during garbage collection the finalizer // may close an unrelated file descriptor with the same (reused) number. // @@ -108,16 +109,12 @@ func NewFile(fd uintptr, name string) *File { return nil } - kind := kindNewFile - appendMode := false - if flags, err := unix.Fcntl(fdi, syscall.F_GETFL, 0); err == nil { - if unix.HasNonblockFlag(flags) { - kind = kindNonBlock - } - appendMode = flags&syscall.O_APPEND != 0 + flags, err := unix.Fcntl(fdi, syscall.F_GETFL, 0) + if err != nil { + flags = 0 } - f := newFile(fdi, name, kind) - f.appendMode = appendMode + f := newFile(fdi, name, kindNewFile, unix.HasNonblockFlag(flags)) + f.appendMode = flags&syscall.O_APPEND != 0 return f } @@ -136,9 +133,7 @@ func net_newUnixFile(fd int, name string) *File { panic("invalid FD") } - f := newFile(fd, name, kindNonBlock) - f.nonblock = true // tell Fd to return blocking descriptor - return f + return newFile(fd, name, kindSock, true) } // newFileKind describes the kind of file to newFile. @@ -148,23 +143,23 @@ const ( // kindNewFile means that the descriptor was passed to us via NewFile. kindNewFile newFileKind = iota // kindOpenFile means that the descriptor was opened using - // Open, Create, or OpenFile (without O_NONBLOCK). + // Open, Create, or OpenFile. kindOpenFile // kindPipe means that the descriptor was opened using Pipe. kindPipe - // kindNonBlock means that the descriptor is already in - // non-blocking mode. - kindNonBlock + // kindSock means that the descriptor is a network file descriptor + // that was created from net package and was opened using net_newUnixFile. + kindSock // kindNoPoll means that we should not put the descriptor into // non-blocking mode, because we know it is not a pipe or FIFO. - // Used by openDirAt for directories. + // Used by openDirAt and openDirNolog for directories. kindNoPoll ) // newFile is like NewFile, but if called from OpenFile or Pipe // (as passed in the kind parameter) it tries to add the file to // the runtime poller. -func newFile(fd int, name string, kind newFileKind) *File { +func newFile(fd int, name string, kind newFileKind, nonBlocking bool) *File { f := &File{&file{ pfd: poll.FD{ Sysfd: fd, @@ -175,11 +170,16 @@ func newFile(fd int, name string, kind newFileKind) *File { stdoutOrErr: fd == 1 || fd == 2, }} - pollable := kind == kindOpenFile || kind == kindPipe || kind == kindNonBlock + pollable := kind == kindOpenFile || kind == kindPipe || kind == kindSock || nonBlocking - // If the caller passed a non-blocking filedes (kindNonBlock), - // we assume they know what they are doing so we allow it to be - // used with kqueue. + // Things like regular files and FIFOs in kqueue on *BSD/Darwin + // may not work properly (or accurately according to its manual). + // As a result, we should avoid adding those to the kqueue-based + // netpoller. Check out #19093, #24164, and #66239 for more contexts. + // + // If the fd was passed to us via any path other than OpenFile, + // we assume those callers know what they were doing, so we won't + // perform this check and allow it to be added to the kqueue. if kind == kindOpenFile { switch runtime.GOOS { case "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd": @@ -211,10 +211,14 @@ func newFile(fd int, name string, kind newFileKind) *File { clearNonBlock := false if pollable { - if kind == kindNonBlock { - // The descriptor is already in non-blocking mode. - // We only set f.nonblock if we put the file into - // non-blocking mode. + // The descriptor is already in non-blocking mode. + // We only set f.nonblock if we put the file into + // non-blocking mode. + if nonBlocking { + // See the comments on net_newUnixFile. + if kind == kindSock { + f.nonblock = true // tell Fd to return blocking descriptor + } } else if err := syscall.SetNonblock(fd, true); err == nil { f.nonblock = true clearNonBlock = true @@ -256,7 +260,7 @@ func epipecheck(file *File, e error) { const DevNull = "/dev/null" // openFileNolog is the Unix implementation of OpenFile. -// Changes here should be reflected in openDirAt, if relevant. +// Changes here should be reflected in openDirAt and openDirNolog, if relevant. func openFileNolog(name string, flag int, perm FileMode) (*File, error) { setSticky := false if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 { @@ -265,20 +269,17 @@ func openFileNolog(name string, flag int, perm FileMode) (*File, error) { } } - var r int - var s poll.SysFile - for { - var e error + var ( + r int + s poll.SysFile + e error + ) + // We have to check EINTR here, per issues 11180 and 39237. + ignoringEINTR(func() error { r, s, e = open(name, flag|syscall.O_CLOEXEC, syscallMode(perm)) - if e == nil { - break - } - - // We have to check EINTR here, per issues 11180 and 39237. - if e == syscall.EINTR { - continue - } - + return e + }) + if e != nil { return nil, &PathError{Op: "open", Path: name, Err: e} } @@ -293,12 +294,30 @@ func openFileNolog(name string, flag int, perm FileMode) (*File, error) { syscall.CloseOnExec(r) } - kind := kindOpenFile - if unix.HasNonblockFlag(flag) { - kind = kindNonBlock + f := newFile(r, name, kindOpenFile, unix.HasNonblockFlag(flag)) + f.pfd.SysFile = s + return f, nil +} + +func openDirNolog(name string) (*File, error) { + var ( + r int + s poll.SysFile + e error + ) + ignoringEINTR(func() error { + r, s, e = open(name, O_RDONLY|syscall.O_CLOEXEC, 0) + return e + }) + if e != nil { + return nil, &PathError{Op: "open", Path: name, Err: e} + } + + if !supportsCloseOnExec { + syscall.CloseOnExec(r) } - f := newFile(r, name, kind) + f := newFile(r, name, kindNoPoll, false) f.pfd.SysFile = s return f, nil } @@ -307,9 +326,8 @@ func (file *file) close() error { if file == nil { return syscall.EINVAL } - if file.dirinfo != nil { - file.dirinfo.close() - file.dirinfo = nil + if info := file.dirinfo.Swap(nil); info != nil { + info.close() } var err error if e := file.pfd.Close(); e != nil { @@ -329,11 +347,10 @@ func (file *file) close() error { // relative to the current offset, and 2 means relative to the end. // It returns the new offset and an error, if any. func (f *File) seek(offset int64, whence int) (ret int64, err error) { - if f.dirinfo != nil { + if info := f.dirinfo.Swap(nil); info != nil { // Free cached dirinfo, so we allocate a new one if we // access this file as a directory again. See #35767 and #37161. - f.dirinfo.close() - f.dirinfo = nil + info.close() } ret, err = f.pfd.Seek(offset, whence) runtime.KeepAlive(f) diff --git a/contrib/go/_std_1.22/src/os/file_wasip1.go b/contrib/go/_std_1.23/src/os/file_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/os/file_wasip1.go rename to contrib/go/_std_1.23/src/os/file_wasip1.go diff --git a/contrib/go/_std_1.22/src/os/file_windows.go b/contrib/go/_std_1.23/src/os/file_windows.go similarity index 89% rename from contrib/go/_std_1.22/src/os/file_windows.go rename to contrib/go/_std_1.23/src/os/file_windows.go index 8b04ed6e47e3..cf652ca1bb3f 100644 --- a/contrib/go/_std_1.22/src/os/file_windows.go +++ b/contrib/go/_std_1.23/src/os/file_windows.go @@ -6,10 +6,13 @@ package os import ( "errors" + "internal/filepathlite" + "internal/godebug" "internal/poll" "internal/syscall/windows" "runtime" "sync" + "sync/atomic" "syscall" "unsafe" ) @@ -24,15 +27,15 @@ const _UTIME_OMIT = -1 type file struct { pfd poll.FD name string - dirinfo *dirInfo // nil unless directory being read - appendMode bool // whether file is opened for appending + dirinfo atomic.Pointer[dirInfo] // nil unless directory being read + appendMode bool // whether file is opened for appending } // Fd returns the Windows handle referencing the open file. // If f is closed, the file descriptor becomes invalid. // If f is garbage collected, a finalizer may close the file descriptor, -// making it invalid; see runtime.SetFinalizer for more information on when -// a finalizer might be run. On Unix systems this will cause the SetDeadline +// making it invalid; see [runtime.SetFinalizer] for more information on when +// a finalizer might be run. On Unix systems this will cause the [File.SetDeadline] // methods to stop working. func (file *File) Fd() uintptr { if file == nil { @@ -115,20 +118,19 @@ func openFileNolog(name string, flag int, perm FileMode) (*File, error) { } return nil, &PathError{Op: "open", Path: name, Err: e} } - f, e := newFile(r, name, "file"), nil - if e != nil { - return nil, &PathError{Op: "open", Path: name, Err: e} - } - return f, nil + return newFile(r, name, "file"), nil +} + +func openDirNolog(name string) (*File, error) { + return openFileNolog(name, O_RDONLY, 0) } func (file *file) close() error { if file == nil { return syscall.EINVAL } - if file.dirinfo != nil { - file.dirinfo.close() - file.dirinfo = nil + if info := file.dirinfo.Swap(nil); info != nil { + info.close() } var err error if e := file.pfd.Close(); e != nil { @@ -148,11 +150,10 @@ func (file *file) close() error { // relative to the current offset, and 2 means relative to the end. // It returns the new offset and an error, if any. func (f *File) seek(offset int64, whence int) (ret int64, err error) { - if f.dirinfo != nil { + if info := f.dirinfo.Swap(nil); info != nil { // Free cached dirinfo, so we allocate a new one if we // access this file as a directory again. See #35767 and #37161. - f.dirinfo.close() - f.dirinfo = nil + info.close() } ret, err = f.pfd.Seek(offset, whence) runtime.KeepAlive(f) @@ -287,14 +288,14 @@ func Link(oldname, newname string) error { // If there is an error, it will be of type *LinkError. func Symlink(oldname, newname string) error { // '/' does not work in link's content - oldname = fromSlash(oldname) + oldname = filepathlite.FromSlash(oldname) // need the exact location of the oldname when it's relative to determine if it's a directory destpath := oldname - if v := volumeName(oldname); v == "" { + if v := filepathlite.VolumeName(oldname); v == "" { if len(oldname) > 0 && IsPathSeparator(oldname[0]) { // oldname is relative to the volume containing newname. - if v = volumeName(newname); v != "" { + if v = filepathlite.VolumeName(newname); v != "" { // Prepend the volume explicitly, because it may be different from the // volume of the current working directory. destpath = v + oldname @@ -312,7 +313,18 @@ func Symlink(oldname, newname string) error { if err != nil { return &LinkError{"symlink", oldname, newname, err} } - o, err := syscall.UTF16PtrFromString(fixLongPath(oldname)) + var o *uint16 + if filepathlite.IsAbs(oldname) { + o, err = syscall.UTF16PtrFromString(fixLongPath(oldname)) + } else { + // Do not use fixLongPath on oldname for relative symlinks, + // as it would turn the name into an absolute path thus making + // an absolute symlink instead. + // Notice that CreateSymbolicLinkW does not fail for relative + // symlinks beyond MAX_PATH, so this does not prevent the + // creation of an arbitrary long path name. + o, err = syscall.UTF16PtrFromString(oldname) + } if err != nil { return &LinkError{"symlink", oldname, newname, err} } @@ -353,6 +365,8 @@ func openSymlink(path string) (syscall.Handle, error) { return h, nil } +var winreadlinkvolume = godebug.New("winreadlinkvolume") + // normaliseLinkPath converts absolute paths returned by // DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, ...) // into paths acceptable by all Windows APIs. @@ -360,7 +374,7 @@ func openSymlink(path string) (syscall.Handle, error) { // // \??\C:\foo\bar into C:\foo\bar // \??\UNC\foo\bar into \\foo\bar -// \??\Volume{abc}\ into C:\ +// \??\Volume{abc}\ into \\?\Volume{abc}\ func normaliseLinkPath(path string) (string, error) { if len(path) < 4 || path[:4] != `\??\` { // unexpected path, return it as is @@ -375,7 +389,11 @@ func normaliseLinkPath(path string) (string, error) { return `\\` + s[4:], nil } - // handle paths, like \??\Volume{abc}\... + // \??\Volume{abc}\ + if winreadlinkvolume.Value() != "0" { + return `\\?\` + path[4:], nil + } + winreadlinkvolume.IncNonDefault() h, err := openSymlink(path) if err != nil { diff --git a/contrib/go/_std_1.22/src/os/getwd.go b/contrib/go/_std_1.23/src/os/getwd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/getwd.go rename to contrib/go/_std_1.23/src/os/getwd.go diff --git a/contrib/go/_std_1.22/src/os/path.go b/contrib/go/_std_1.23/src/os/path.go similarity index 93% rename from contrib/go/_std_1.22/src/os/path.go rename to contrib/go/_std_1.23/src/os/path.go index 6ac4cbe20f78..42de603ae1af 100644 --- a/contrib/go/_std_1.22/src/os/path.go +++ b/contrib/go/_std_1.23/src/os/path.go @@ -5,6 +5,7 @@ package os import ( + "internal/filepathlite" "syscall" ) @@ -43,7 +44,7 @@ func MkdirAll(path string, perm FileMode) error { // If there is a parent directory, and it is not the volume name, // recurse to ensure parent directory exists. - if parent := path[:i]; len(parent) > len(volumeName(path)) { + if parent := path[:i]; len(parent) > len(filepathlite.VolumeName(path)) { err = MkdirAll(parent, perm) if err != nil { return err @@ -68,7 +69,7 @@ func MkdirAll(path string, perm FileMode) error { // It removes everything it can but returns the first error // it encounters. If the path does not exist, RemoveAll // returns nil (no error). -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. func RemoveAll(path string) error { return removeAll(path) } diff --git a/contrib/go/_std_1.22/src/os/path_plan9.go b/contrib/go/_std_1.23/src/os/path_plan9.go similarity index 90% rename from contrib/go/_std_1.22/src/os/path_plan9.go rename to contrib/go/_std_1.23/src/os/path_plan9.go index f1c9dbc048c1..b09b53a3d828 100644 --- a/contrib/go/_std_1.22/src/os/path_plan9.go +++ b/contrib/go/_std_1.23/src/os/path_plan9.go @@ -13,7 +13,3 @@ const ( func IsPathSeparator(c uint8) bool { return PathSeparator == c } - -func volumeName(p string) string { - return "" -} diff --git a/contrib/go/_std_1.22/src/os/path_unix.go b/contrib/go/_std_1.23/src/os/path_unix.go similarity index 74% rename from contrib/go/_std_1.22/src/os/path_unix.go rename to contrib/go/_std_1.23/src/os/path_unix.go index 1c80fa91f8be..0189bcd2a1ee 100644 --- a/contrib/go/_std_1.22/src/os/path_unix.go +++ b/contrib/go/_std_1.23/src/os/path_unix.go @@ -16,24 +16,6 @@ func IsPathSeparator(c uint8) bool { return PathSeparator == c } -// basename removes trailing slashes and the leading directory name from path name. -func basename(name string) string { - i := len(name) - 1 - // Remove trailing slashes - for ; i > 0 && name[i] == '/'; i-- { - name = name[:i] - } - // Remove leading directory name - for i--; i >= 0; i-- { - if name[i] == '/' { - name = name[i+1:] - break - } - } - - return name -} - // splitPath returns the base name and parent directory. func splitPath(path string) (string, string) { // if no better parent is found, the path is relative from "here" @@ -69,7 +51,3 @@ func splitPath(path string) (string, string) { return dirname, basename } - -func volumeName(p string) string { - return "" -} diff --git a/contrib/go/_std_1.23/src/os/path_windows.go b/contrib/go/_std_1.23/src/os/path_windows.go new file mode 100644 index 000000000000..f585aa5ee6de --- /dev/null +++ b/contrib/go/_std_1.23/src/os/path_windows.go @@ -0,0 +1,152 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "internal/filepathlite" + "internal/syscall/windows" + "syscall" +) + +const ( + PathSeparator = '\\' // OS-specific path separator + PathListSeparator = ';' // OS-specific path list separator +) + +// IsPathSeparator reports whether c is a directory separator character. +func IsPathSeparator(c uint8) bool { + // NOTE: Windows accepts / as path separator. + return c == '\\' || c == '/' +} + +func dirname(path string) string { + vol := filepathlite.VolumeName(path) + i := len(path) - 1 + for i >= len(vol) && !IsPathSeparator(path[i]) { + i-- + } + dir := path[len(vol) : i+1] + last := len(dir) - 1 + if last > 0 && IsPathSeparator(dir[last]) { + dir = dir[:last] + } + if dir == "" { + dir = "." + } + return vol + dir +} + +// fixLongPath returns the extended-length (\\?\-prefixed) form of +// path when needed, in order to avoid the default 260 character file +// path limit imposed by Windows. If the path is short enough or already +// has the extended-length prefix, fixLongPath returns path unmodified. +// If the path is relative and joining it with the current working +// directory results in a path that is too long, fixLongPath returns +// the absolute path with the extended-length prefix. +// +// See https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation +func fixLongPath(path string) string { + if windows.CanUseLongPaths { + return path + } + return addExtendedPrefix(path) +} + +// addExtendedPrefix adds the extended path prefix (\\?\) to path. +func addExtendedPrefix(path string) string { + if len(path) >= 4 { + if path[:4] == `\??\` { + // Already extended with \??\ + return path + } + if IsPathSeparator(path[0]) && IsPathSeparator(path[1]) && path[2] == '?' && IsPathSeparator(path[3]) { + // Already extended with \\?\ or any combination of directory separators. + return path + } + } + + // Do nothing (and don't allocate) if the path is "short". + // Empirically (at least on the Windows Server 2013 builder), + // the kernel is arbitrarily okay with < 248 bytes. That + // matches what the docs above say: + // "When using an API to create a directory, the specified + // path cannot be so long that you cannot append an 8.3 file + // name (that is, the directory name cannot exceed MAX_PATH + // minus 12)." Since MAX_PATH is 260, 260 - 12 = 248. + // + // The MSDN docs appear to say that a normal path that is 248 bytes long + // will work; empirically the path must be less then 248 bytes long. + pathLength := len(path) + if !filepathlite.IsAbs(path) { + // If the path is relative, we need to prepend the working directory + // plus a separator to the path before we can determine if it's too long. + // We don't want to call syscall.Getwd here, as that call is expensive to do + // every time fixLongPath is called with a relative path, so we use a cache. + // Note that getwdCache might be outdated if the working directory has been + // changed without using os.Chdir, i.e. using syscall.Chdir directly or cgo. + // This is fine, as the worst that can happen is that we fail to fix the path. + getwdCache.Lock() + if getwdCache.dir == "" { + // Init the working directory cache. + getwdCache.dir, _ = syscall.Getwd() + } + pathLength += len(getwdCache.dir) + 1 + getwdCache.Unlock() + } + + if pathLength < 248 { + // Don't fix. (This is how Go 1.7 and earlier worked, + // not automatically generating the \\?\ form) + return path + } + + var isUNC, isDevice bool + if len(path) >= 2 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) { + if len(path) >= 4 && path[2] == '.' && IsPathSeparator(path[3]) { + // Starts with //./ + isDevice = true + } else { + // Starts with // + isUNC = true + } + } + var prefix []uint16 + if isUNC { + // UNC path, prepend the \\?\UNC\ prefix. + prefix = []uint16{'\\', '\\', '?', '\\', 'U', 'N', 'C', '\\'} + } else if isDevice { + // Don't add the extended prefix to device paths, as it would + // change its meaning. + } else { + prefix = []uint16{'\\', '\\', '?', '\\'} + } + + p, err := syscall.UTF16FromString(path) + if err != nil { + return path + } + // Estimate the required buffer size using the path length plus the null terminator. + // pathLength includes the working directory. This should be accurate unless + // the working directory has changed without using os.Chdir. + n := uint32(pathLength) + 1 + var buf []uint16 + for { + buf = make([]uint16, n+uint32(len(prefix))) + n, err = syscall.GetFullPathName(&p[0], n, &buf[len(prefix)], nil) + if err != nil { + return path + } + if n <= uint32(len(buf)-len(prefix)) { + buf = buf[:n+uint32(len(prefix))] + break + } + } + if isUNC { + // Remove leading \\. + buf = buf[2:] + } + copy(buf, prefix) + return syscall.UTF16ToString(buf) +} diff --git a/contrib/go/_std_1.23/src/os/pidfd_linux.go b/contrib/go/_std_1.23/src/os/pidfd_linux.go new file mode 100644 index 000000000000..0bfef7759cc6 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/pidfd_linux.go @@ -0,0 +1,210 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Support for pidfd was added during the course of a few Linux releases: +// v5.1: pidfd_send_signal syscall; +// v5.2: CLONE_PIDFD flag for clone syscall; +// v5.3: pidfd_open syscall, clone3 syscall; +// v5.4: P_PIDFD idtype support for waitid syscall; +// v5.6: pidfd_getfd syscall. +// +// N.B. Alternative Linux implementations may not follow this ordering. e.g., +// QEMU user mode 7.2 added pidfd_open, but CLONE_PIDFD was not added until +// 8.0. + +package os + +import ( + "errors" + "internal/syscall/unix" + "runtime" + "sync" + "syscall" + "unsafe" +) + +// ensurePidfd initializes the PidFD field in sysAttr if it is not already set. +// It returns the original or modified SysProcAttr struct and a flag indicating +// whether the PidFD should be duplicated before using. +func ensurePidfd(sysAttr *syscall.SysProcAttr) (*syscall.SysProcAttr, bool) { + if !pidfdWorks() { + return sysAttr, false + } + + var pidfd int + + if sysAttr == nil { + return &syscall.SysProcAttr{ + PidFD: &pidfd, + }, false + } + if sysAttr.PidFD == nil { + newSys := *sysAttr // copy + newSys.PidFD = &pidfd + return &newSys, false + } + + return sysAttr, true +} + +// getPidfd returns the value of sysAttr.PidFD (or its duplicate if needDup is +// set) and a flag indicating whether the value can be used. +func getPidfd(sysAttr *syscall.SysProcAttr, needDup bool) (uintptr, bool) { + if !pidfdWorks() { + return 0, false + } + + h := *sysAttr.PidFD + if needDup { + dupH, e := unix.Fcntl(h, syscall.F_DUPFD_CLOEXEC, 0) + if e != nil { + return 0, false + } + h = dupH + } + return uintptr(h), true +} + +func pidfdFind(pid int) (uintptr, error) { + if !pidfdWorks() { + return 0, syscall.ENOSYS + } + + h, err := unix.PidFDOpen(pid, 0) + if err != nil { + return 0, convertESRCH(err) + } + return h, nil +} + +// _P_PIDFD is used as idtype argument to waitid syscall. +const _P_PIDFD = 3 + +func (p *Process) pidfdWait() (*ProcessState, error) { + // When pidfd is used, there is no wait/kill race (described in CL 23967) + // because the PID recycle issue doesn't exist (IOW, pidfd, unlike PID, + // is guaranteed to refer to one particular process). Thus, there is no + // need for the workaround (blockUntilWaitable + sigMu) from pidWait. + // + // We _do_ need to be careful about reuse of the pidfd FD number when + // closing the pidfd. See handle for more details. + handle, status := p.handleTransientAcquire() + switch status { + case statusDone: + // Process already completed Wait, or was not found by + // pidfdFind. Return ECHILD for consistency with what the wait + // syscall would return. + return nil, NewSyscallError("wait", syscall.ECHILD) + case statusReleased: + return nil, syscall.EINVAL + } + defer p.handleTransientRelease() + + var ( + info unix.SiginfoChild + rusage syscall.Rusage + e syscall.Errno + ) + for { + _, _, e = syscall.Syscall6(syscall.SYS_WAITID, _P_PIDFD, handle, uintptr(unsafe.Pointer(&info)), syscall.WEXITED, uintptr(unsafe.Pointer(&rusage)), 0) + if e != syscall.EINTR { + break + } + } + if e != 0 { + return nil, NewSyscallError("waitid", e) + } + // Release the Process' handle reference, in addition to the reference + // we took above. + p.handlePersistentRelease(statusDone) + return &ProcessState{ + pid: int(info.Pid), + status: info.WaitStatus(), + rusage: &rusage, + }, nil +} + +func (p *Process) pidfdSendSignal(s syscall.Signal) error { + handle, status := p.handleTransientAcquire() + switch status { + case statusDone: + return ErrProcessDone + case statusReleased: + return errors.New("os: process already released") + } + defer p.handleTransientRelease() + + return convertESRCH(unix.PidFDSendSignal(handle, s)) +} + +func pidfdWorks() bool { + return checkPidfdOnce() == nil +} + +var checkPidfdOnce = sync.OnceValue(checkPidfd) + +// checkPidfd checks whether all required pidfd-related syscalls work. This +// consists of pidfd_open and pidfd_send_signal syscalls, waitid syscall with +// idtype of P_PIDFD, and clone(CLONE_PIDFD). +// +// Reasons for non-working pidfd syscalls include an older kernel and an +// execution environment in which the above system calls are restricted by +// seccomp or a similar technology. +func checkPidfd() error { + // In Android version < 12, pidfd-related system calls are not allowed + // by seccomp and trigger the SIGSYS signal. See issue #69065. + if runtime.GOOS == "android" { + ignoreSIGSYS() + defer restoreSIGSYS() + } + + // Get a pidfd of the current process (opening of "/proc/self" won't + // work for waitid). + fd, err := unix.PidFDOpen(syscall.Getpid(), 0) + if err != nil { + return NewSyscallError("pidfd_open", err) + } + defer syscall.Close(int(fd)) + + // Check waitid(P_PIDFD) works. + for { + _, _, err = syscall.Syscall6(syscall.SYS_WAITID, _P_PIDFD, fd, 0, syscall.WEXITED, 0, 0) + if err != syscall.EINTR { + break + } + } + // Expect ECHILD from waitid since we're not our own parent. + if err != syscall.ECHILD { + return NewSyscallError("pidfd_wait", err) + } + + // Check pidfd_send_signal works (should be able to send 0 to itself). + if err := unix.PidFDSendSignal(fd, 0); err != nil { + return NewSyscallError("pidfd_send_signal", err) + } + + // Verify that clone(CLONE_PIDFD) works. + // + // This shouldn't be necessary since pidfd_open was added in Linux 5.3, + // after CLONE_PIDFD in Linux 5.2, but some alternative Linux + // implementations may not adhere to this ordering. + if err := checkClonePidfd(); err != nil { + return err + } + + return nil +} + +// Provided by syscall. +// +//go:linkname checkClonePidfd +func checkClonePidfd() error + +// Provided by runtime. +// +//go:linkname ignoreSIGSYS +func ignoreSIGSYS() + +//go:linkname restoreSIGSYS +func restoreSIGSYS() diff --git a/contrib/go/_std_1.23/src/os/pidfd_other.go b/contrib/go/_std_1.23/src/os/pidfd_other.go new file mode 100644 index 000000000000..ba9cbcb93830 --- /dev/null +++ b/contrib/go/_std_1.23/src/os/pidfd_other.go @@ -0,0 +1,31 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build (unix && !linux) || (js && wasm) || wasip1 || windows + +package os + +import "syscall" + +func ensurePidfd(sysAttr *syscall.SysProcAttr) (*syscall.SysProcAttr, bool) { + return sysAttr, false +} + +func getPidfd(_ *syscall.SysProcAttr, _ bool) (uintptr, bool) { + return 0, false +} + +func pidfdFind(_ int) (uintptr, error) { + return 0, syscall.ENOSYS +} + +func (p *Process) pidfdRelease() {} + +func (_ *Process) pidfdWait() (*ProcessState, error) { + panic("unreachable") +} + +func (_ *Process) pidfdSendSignal(_ syscall.Signal) error { + panic("unreachable") +} diff --git a/contrib/go/_std_1.22/src/os/pipe2_unix.go b/contrib/go/_std_1.23/src/os/pipe2_unix.go similarity index 86% rename from contrib/go/_std_1.22/src/os/pipe2_unix.go rename to contrib/go/_std_1.23/src/os/pipe2_unix.go index 2d293fdb4d96..dca83a529bb0 100644 --- a/contrib/go/_std_1.22/src/os/pipe2_unix.go +++ b/contrib/go/_std_1.23/src/os/pipe2_unix.go @@ -18,5 +18,5 @@ func Pipe() (r *File, w *File, err error) { return nil, nil, NewSyscallError("pipe2", e) } - return newFile(p[0], "|0", kindPipe), newFile(p[1], "|1", kindPipe), nil + return newFile(p[0], "|0", kindPipe, false), newFile(p[1], "|1", kindPipe, false), nil } diff --git a/contrib/go/_std_1.22/src/os/pipe_unix.go b/contrib/go/_std_1.23/src/os/pipe_unix.go similarity index 88% rename from contrib/go/_std_1.22/src/os/pipe_unix.go rename to contrib/go/_std_1.23/src/os/pipe_unix.go index 2eb11a04cb2d..5c1a953fda4c 100644 --- a/contrib/go/_std_1.22/src/os/pipe_unix.go +++ b/contrib/go/_std_1.23/src/os/pipe_unix.go @@ -24,5 +24,5 @@ func Pipe() (r *File, w *File, err error) { syscall.CloseOnExec(p[1]) syscall.ForkLock.RUnlock() - return newFile(p[0], "|0", kindPipe), newFile(p[1], "|1", kindPipe), nil + return newFile(p[0], "|0", kindPipe, false), newFile(p[1], "|1", kindPipe, false), nil } diff --git a/contrib/go/_std_1.22/src/os/pipe_wasm.go b/contrib/go/_std_1.23/src/os/pipe_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/os/pipe_wasm.go rename to contrib/go/_std_1.23/src/os/pipe_wasm.go diff --git a/contrib/go/_std_1.22/src/os/proc.go b/contrib/go/_std_1.23/src/os/proc.go similarity index 96% rename from contrib/go/_std_1.22/src/os/proc.go rename to contrib/go/_std_1.23/src/os/proc.go index 3aae5680eea5..ea029158eecc 100644 --- a/contrib/go/_std_1.22/src/os/proc.go +++ b/contrib/go/_std_1.23/src/os/proc.go @@ -47,7 +47,7 @@ func Getegid() int { return syscall.Getegid() } // Getgroups returns a list of the numeric ids of groups that the caller belongs to. // -// On Windows, it returns syscall.EWINDOWS. See the os/user package +// On Windows, it returns [syscall.EWINDOWS]. See the [os/user] package // for a possible alternative. func Getgroups() ([]int, error) { gids, e := syscall.Getgroups() diff --git a/contrib/go/_std_1.22/src/os/rawconn.go b/contrib/go/_std_1.23/src/os/rawconn.go similarity index 100% rename from contrib/go/_std_1.22/src/os/rawconn.go rename to contrib/go/_std_1.23/src/os/rawconn.go diff --git a/contrib/go/_std_1.22/src/os/removeall_at.go b/contrib/go/_std_1.23/src/os/removeall_at.go similarity index 97% rename from contrib/go/_std_1.22/src/os/removeall_at.go rename to contrib/go/_std_1.23/src/os/removeall_at.go index 774ca15823bb..cc254e0043fc 100644 --- a/contrib/go/_std_1.22/src/os/removeall_at.go +++ b/contrib/go/_std_1.23/src/os/removeall_at.go @@ -88,7 +88,7 @@ func removeAllFrom(parent *File, base string) error { if IsNotExist(err) { return nil } - if err == syscall.ENOTDIR { + if err == syscall.ENOTDIR || err == unix.NoFollowErrno { // Not a directory; return the error from the unix.Unlinkat. return &PathError{Op: "unlinkat", Path: base, Err: uErr} } @@ -187,5 +187,5 @@ func openDirAt(dirfd int, name string) (*File, error) { } // We use kindNoPoll because we know that this is a directory. - return newFile(r, name, kindNoPoll), nil + return newFile(r, name, kindNoPoll, false), nil } diff --git a/contrib/go/_std_1.22/src/os/removeall_noat.go b/contrib/go/_std_1.23/src/os/removeall_noat.go similarity index 100% rename from contrib/go/_std_1.22/src/os/removeall_noat.go rename to contrib/go/_std_1.23/src/os/removeall_noat.go diff --git a/contrib/go/_std_1.22/src/os/signal/doc.go b/contrib/go/_std_1.23/src/os/signal/doc.go similarity index 97% rename from contrib/go/_std_1.22/src/os/signal/doc.go rename to contrib/go/_std_1.23/src/os/signal/doc.go index a2a7525ef0ae..1d3e6eb573a5 100644 --- a/contrib/go/_std_1.22/src/os/signal/doc.go +++ b/contrib/go/_std_1.23/src/os/signal/doc.go @@ -68,15 +68,15 @@ signals SIGTSTP, SIGTTIN, and SIGTTOU, in which case the system default behavior does not occur. It also applies to some signals that otherwise cause no action: SIGUSR1, SIGUSR2, SIGPIPE, SIGALRM, SIGCHLD, SIGCONT, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGWINCH, -SIGIO, SIGPWR, SIGSYS, SIGINFO, SIGTHR, SIGWAITING, SIGLWP, SIGFREEZE, +SIGIO, SIGPWR, SIGINFO, SIGTHR, SIGWAITING, SIGLWP, SIGFREEZE, SIGTHAW, SIGLOST, SIGXRES, SIGJVM1, SIGJVM2, and any real time signals used on the system. Note that not all of these signals are available on all systems. -If the program was started with SIGHUP or SIGINT ignored, and Notify +If the program was started with SIGHUP or SIGINT ignored, and [Notify] is called for either signal, a signal handler will be installed for -that signal and it will no longer be ignored. If, later, Reset or -Ignore is called for that signal, or Stop is called on all channels +that signal and it will no longer be ignored. If, later, [Reset] or +[Ignore] is called for that signal, or [Stop] is called on all channels passed to Notify for that signal, the signal will once again be ignored. Reset will restore the system default behavior for the signal, while Ignore will cause the system to ignore the signal @@ -146,8 +146,8 @@ Go behavior described above will not occur. This can be an issue with the SIGPROF signal in particular. The non-Go code should not change the signal mask on any threads -created by the Go runtime. If the non-Go code starts new threads of -its own, it may set the signal mask as it pleases. +created by the Go runtime. If the non-Go code starts new threads +itself, those threads may set the signal mask as they please. If the non-Go code starts a new thread, changes the signal mask, and then invokes a Go function in that thread, the Go runtime will diff --git a/contrib/go/_std_1.22/src/os/signal/sig.s b/contrib/go/_std_1.23/src/os/signal/sig.s similarity index 100% rename from contrib/go/_std_1.22/src/os/signal/sig.s rename to contrib/go/_std_1.23/src/os/signal/sig.s diff --git a/contrib/go/_std_1.22/src/os/signal/signal.go b/contrib/go/_std_1.23/src/os/signal/signal.go similarity index 95% rename from contrib/go/_std_1.22/src/os/signal/signal.go rename to contrib/go/_std_1.23/src/os/signal/signal.go index 4250a7e0de60..9a4cd64fb75e 100644 --- a/contrib/go/_std_1.22/src/os/signal/signal.go +++ b/contrib/go/_std_1.23/src/os/signal/signal.go @@ -81,7 +81,7 @@ func cancel(sigs []os.Signal, action func(int)) { // Ignore causes the provided signals to be ignored. If they are received by // the program, nothing will happen. Ignore undoes the effect of any prior -// calls to Notify for the provided signals. +// calls to [Notify] for the provided signals. // If no signals are provided, all incoming signals will be ignored. func Ignore(sig ...os.Signal) { cancel(sig, ignoreSignal) @@ -113,7 +113,7 @@ var ( // // It is allowed to call Notify multiple times with the same channel: // each call expands the set of signals sent to that channel. -// The only way to remove signals from the set is to call Stop. +// The only way to remove signals from the set is to call [Stop]. // // It is allowed to call Notify multiple times with different channels // and the same signals: each channel receives copies of incoming @@ -167,7 +167,7 @@ func Notify(c chan<- os.Signal, sig ...os.Signal) { } } -// Reset undoes the effect of any prior calls to Notify for the provided +// Reset undoes the effect of any prior calls to [Notify] for the provided // signals. // If no signals are provided, all signal handlers will be reset. func Reset(sig ...os.Signal) { @@ -175,7 +175,7 @@ func Reset(sig ...os.Signal) { } // Stop causes package signal to stop relaying incoming signals to c. -// It undoes the effect of all prior calls to Notify using c. +// It undoes the effect of all prior calls to [Notify] using c. // When Stop returns, it is guaranteed that c will receive no more signals. func Stop(c chan<- os.Signal) { handlers.Lock() @@ -264,9 +264,9 @@ func process(sig os.Signal) { // when the returned stop function is called, or when the parent context's // Done channel is closed, whichever happens first. // -// The stop function unregisters the signal behavior, which, like signal.Reset, +// The stop function unregisters the signal behavior, which, like [signal.Reset], // may restore the default behavior for a given signal. For example, the default -// behavior of a Go program receiving os.Interrupt is to exit. Calling +// behavior of a Go program receiving [os.Interrupt] is to exit. Calling // NotifyContext(parent, os.Interrupt) will change the behavior to cancel // the returned context. Future interrupts received will not trigger the default // (exit) behavior until the returned stop function is called. diff --git a/contrib/go/_std_1.22/src/os/signal/signal_plan9.go b/contrib/go/_std_1.23/src/os/signal/signal_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/signal/signal_plan9.go rename to contrib/go/_std_1.23/src/os/signal/signal_plan9.go diff --git a/contrib/go/_std_1.22/src/os/signal/signal_unix.go b/contrib/go/_std_1.23/src/os/signal/signal_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/signal/signal_unix.go rename to contrib/go/_std_1.23/src/os/signal/signal_unix.go diff --git a/contrib/go/_std_1.22/src/os/signal/ya.make b/contrib/go/_std_1.23/src/os/signal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/os/signal/ya.make rename to contrib/go/_std_1.23/src/os/signal/ya.make diff --git a/contrib/go/_std_1.22/src/os/stat.go b/contrib/go/_std_1.23/src/os/stat.go similarity index 76% rename from contrib/go/_std_1.22/src/os/stat.go rename to contrib/go/_std_1.23/src/os/stat.go index 11d9efa4573f..50acb6dbdd12 100644 --- a/contrib/go/_std_1.22/src/os/stat.go +++ b/contrib/go/_std_1.23/src/os/stat.go @@ -6,17 +6,17 @@ package os import "internal/testlog" -// Stat returns a FileInfo describing the named file. -// If there is an error, it will be of type *PathError. +// Stat returns a [FileInfo] describing the named file. +// If there is an error, it will be of type [*PathError]. func Stat(name string) (FileInfo, error) { testlog.Stat(name) return statNolog(name) } -// Lstat returns a FileInfo describing the named file. +// Lstat returns a [FileInfo] describing the named file. // If the file is a symbolic link, the returned FileInfo // describes the symbolic link. Lstat makes no attempt to follow the link. -// If there is an error, it will be of type *PathError. +// If there is an error, it will be of type [*PathError]. // // On Windows, if the file is a reparse point that is a surrogate for another // named entity (such as a symbolic link or mounted folder), the returned diff --git a/contrib/go/_std_1.22/src/os/stat_aix.go b/contrib/go/_std_1.23/src/os/stat_aix.go similarity index 95% rename from contrib/go/_std_1.22/src/os/stat_aix.go rename to contrib/go/_std_1.23/src/os/stat_aix.go index a37c9fdae41a..574e3d26ffd0 100644 --- a/contrib/go/_std_1.22/src/os/stat_aix.go +++ b/contrib/go/_std_1.23/src/os/stat_aix.go @@ -5,12 +5,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = int64(fs.sys.Size) fs.modTime = stTimespecToTime(fs.sys.Mtim) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_darwin.go b/contrib/go/_std_1.23/src/os/stat_darwin.go similarity index 94% rename from contrib/go/_std_1.22/src/os/stat_darwin.go rename to contrib/go/_std_1.23/src/os/stat_darwin.go index b92ffd4a0a6f..70c5345aacde 100644 --- a/contrib/go/_std_1.22/src/os/stat_darwin.go +++ b/contrib/go/_std_1.23/src/os/stat_darwin.go @@ -5,12 +5,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtimespec.Unix()) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_dragonfly.go b/contrib/go/_std_1.23/src/os/stat_dragonfly.go similarity index 94% rename from contrib/go/_std_1.22/src/os/stat_dragonfly.go rename to contrib/go/_std_1.23/src/os/stat_dragonfly.go index 316c26c7cab7..01f2a14e2768 100644 --- a/contrib/go/_std_1.22/src/os/stat_dragonfly.go +++ b/contrib/go/_std_1.23/src/os/stat_dragonfly.go @@ -5,12 +5,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtim.Unix()) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_freebsd.go b/contrib/go/_std_1.23/src/os/stat_freebsd.go similarity index 94% rename from contrib/go/_std_1.22/src/os/stat_freebsd.go rename to contrib/go/_std_1.23/src/os/stat_freebsd.go index 919ee44dd6b5..7b786940454b 100644 --- a/contrib/go/_std_1.22/src/os/stat_freebsd.go +++ b/contrib/go/_std_1.23/src/os/stat_freebsd.go @@ -5,12 +5,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtimespec.Unix()) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_js.go b/contrib/go/_std_1.23/src/os/stat_js.go similarity index 94% rename from contrib/go/_std_1.22/src/os/stat_js.go rename to contrib/go/_std_1.23/src/os/stat_js.go index a137172e66de..d63461d6955f 100644 --- a/contrib/go/_std_1.22/src/os/stat_js.go +++ b/contrib/go/_std_1.23/src/os/stat_js.go @@ -7,12 +7,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtime, fs.sys.MtimeNsec) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_linux.go b/contrib/go/_std_1.23/src/os/stat_linux.go similarity index 94% rename from contrib/go/_std_1.22/src/os/stat_linux.go rename to contrib/go/_std_1.23/src/os/stat_linux.go index 316c26c7cab7..01f2a14e2768 100644 --- a/contrib/go/_std_1.22/src/os/stat_linux.go +++ b/contrib/go/_std_1.23/src/os/stat_linux.go @@ -5,12 +5,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtim.Unix()) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_netbsd.go b/contrib/go/_std_1.23/src/os/stat_netbsd.go similarity index 94% rename from contrib/go/_std_1.22/src/os/stat_netbsd.go rename to contrib/go/_std_1.23/src/os/stat_netbsd.go index 919ee44dd6b5..7b786940454b 100644 --- a/contrib/go/_std_1.22/src/os/stat_netbsd.go +++ b/contrib/go/_std_1.23/src/os/stat_netbsd.go @@ -5,12 +5,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtimespec.Unix()) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_openbsd.go b/contrib/go/_std_1.23/src/os/stat_openbsd.go similarity index 94% rename from contrib/go/_std_1.22/src/os/stat_openbsd.go rename to contrib/go/_std_1.23/src/os/stat_openbsd.go index 316c26c7cab7..01f2a14e2768 100644 --- a/contrib/go/_std_1.22/src/os/stat_openbsd.go +++ b/contrib/go/_std_1.23/src/os/stat_openbsd.go @@ -5,12 +5,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtim.Unix()) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_plan9.go b/contrib/go/_std_1.23/src/os/stat_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/stat_plan9.go rename to contrib/go/_std_1.23/src/os/stat_plan9.go diff --git a/contrib/go/_std_1.22/src/os/stat_solaris.go b/contrib/go/_std_1.23/src/os/stat_solaris.go similarity index 95% rename from contrib/go/_std_1.22/src/os/stat_solaris.go rename to contrib/go/_std_1.23/src/os/stat_solaris.go index 4e00ecb075f3..447044e2e267 100644 --- a/contrib/go/_std_1.22/src/os/stat_solaris.go +++ b/contrib/go/_std_1.23/src/os/stat_solaris.go @@ -5,6 +5,7 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) @@ -18,7 +19,7 @@ const ( ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = fs.sys.Size fs.modTime = time.Unix(fs.sys.Mtim.Unix()) fs.mode = FileMode(fs.sys.Mode & 0777) diff --git a/contrib/go/_std_1.22/src/os/stat_unix.go b/contrib/go/_std_1.23/src/os/stat_unix.go similarity index 86% rename from contrib/go/_std_1.22/src/os/stat_unix.go rename to contrib/go/_std_1.23/src/os/stat_unix.go index 431df33faef9..9a1f21211ca0 100644 --- a/contrib/go/_std_1.22/src/os/stat_unix.go +++ b/contrib/go/_std_1.23/src/os/stat_unix.go @@ -10,8 +10,8 @@ import ( "syscall" ) -// Stat returns the FileInfo structure describing file. -// If there is an error, it will be of type *PathError. +// Stat returns the [FileInfo] structure describing file. +// If there is an error, it will be of type [*PathError]. func (f *File) Stat() (FileInfo, error) { if f == nil { return nil, ErrInvalid @@ -19,7 +19,7 @@ func (f *File) Stat() (FileInfo, error) { var fs fileStat err := f.pfd.Fstat(&fs.sys) if err != nil { - return nil, &PathError{Op: "stat", Path: f.name, Err: err} + return nil, f.wrapErr("stat", err) } fillFileStatFromSys(&fs, f.name) return &fs, nil diff --git a/contrib/go/_std_1.22/src/os/stat_wasip1.go b/contrib/go/_std_1.23/src/os/stat_wasip1.go similarity index 93% rename from contrib/go/_std_1.22/src/os/stat_wasip1.go rename to contrib/go/_std_1.23/src/os/stat_wasip1.go index a4f0a20430b5..85a364988992 100644 --- a/contrib/go/_std_1.22/src/os/stat_wasip1.go +++ b/contrib/go/_std_1.23/src/os/stat_wasip1.go @@ -7,12 +7,13 @@ package os import ( + "internal/filepathlite" "syscall" "time" ) func fillFileStatFromSys(fs *fileStat, name string) { - fs.name = basename(name) + fs.name = filepathlite.Base(name) fs.size = int64(fs.sys.Size) fs.mode = FileMode(fs.sys.Mode) fs.modTime = time.Unix(0, int64(fs.sys.Mtime)) diff --git a/contrib/go/_std_1.22/src/os/stat_windows.go b/contrib/go/_std_1.23/src/os/stat_windows.go similarity index 84% rename from contrib/go/_std_1.22/src/os/stat_windows.go rename to contrib/go/_std_1.23/src/os/stat_windows.go index 668255f74adf..160a3893ce56 100644 --- a/contrib/go/_std_1.22/src/os/stat_windows.go +++ b/contrib/go/_std_1.23/src/os/stat_windows.go @@ -5,13 +5,14 @@ package os import ( + "internal/filepathlite" "internal/syscall/windows" "syscall" "unsafe" ) -// Stat returns the FileInfo structure describing file. -// If there is an error, it will be of type *PathError. +// Stat returns the [FileInfo] structure describing file. +// If there is an error, it will be of type [*PathError]. func (file *File) Stat() (FileInfo, error) { if file == nil { return nil, ErrInvalid @@ -33,6 +34,15 @@ func stat(funcname, name string, followSurrogates bool) (FileInfo, error) { // See https://golang.org/issues/19922#issuecomment-300031421 for details. var fa syscall.Win32FileAttributeData err = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fa))) + if err == nil && fa.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 { + // Not a surrogate for another named entity, because it isn't any kind of reparse point. + // The information we got from GetFileAttributesEx is good enough for now. + fs := newFileStatFromWin32FileAttributeData(&fa) + if err := fs.saveInfoFromPath(name); err != nil { + return nil, err + } + return fs, nil + } // GetFileAttributesEx fails with ERROR_SHARING_VIOLATION error for // files like c:\pagefile.sys. Use FindFirstFile for such files. @@ -53,28 +63,20 @@ func stat(funcname, name string, followSurrogates bool) (FileInfo, error) { } } - if err == nil && fa.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 { - // Not a surrogate for another named entity, because it isn't any kind of reparse point. - // The information we got from GetFileAttributesEx is good enough for now. - fs := &fileStat{ - FileAttributes: fa.FileAttributes, - CreationTime: fa.CreationTime, - LastAccessTime: fa.LastAccessTime, - LastWriteTime: fa.LastWriteTime, - FileSizeHigh: fa.FileSizeHigh, - FileSizeLow: fa.FileSizeLow, - } - if err := fs.saveInfoFromPath(name); err != nil { - return nil, err - } - return fs, nil - } - // Use CreateFile to determine whether the file is a name surrogate and, if so, // save information about the link target. // Set FILE_FLAG_BACKUP_SEMANTICS so that CreateFile will create the handle // even if name refers to a directory. - h, err := syscall.CreateFile(namep, 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0) + var flags uint32 = syscall.FILE_FLAG_BACKUP_SEMANTICS | syscall.FILE_FLAG_OPEN_REPARSE_POINT + h, err := syscall.CreateFile(namep, 0, 0, nil, syscall.OPEN_EXISTING, flags, 0) + + if err == windows.ERROR_INVALID_PARAMETER { + // Console handles, like "\\.\con", require generic read access. See + // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#consoles. + // We haven't set it previously because it is normally not required + // to read attributes and some files may not allow it. + h, err = syscall.CreateFile(namep, syscall.GENERIC_READ, 0, nil, syscall.OPEN_EXISTING, flags, 0) + } if err != nil { // Since CreateFile failed, we can't determine whether name refers to a // name surrogate, or some other kind of reparse point. Since we can't return a @@ -106,7 +108,7 @@ func statHandle(name string, h syscall.Handle) (FileInfo, error) { } switch ft { case syscall.FILE_TYPE_PIPE, syscall.FILE_TYPE_CHAR: - return &fileStat{name: basename(name), filetype: ft}, nil + return &fileStat{name: filepathlite.Base(name), filetype: ft}, nil } fs, err := newFileStatFromGetFileInformationByHandle(name, h) if err != nil { diff --git a/contrib/go/_std_1.22/src/os/sticky_bsd.go b/contrib/go/_std_1.23/src/os/sticky_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sticky_bsd.go rename to contrib/go/_std_1.23/src/os/sticky_bsd.go diff --git a/contrib/go/_std_1.22/src/os/sticky_notbsd.go b/contrib/go/_std_1.23/src/os/sticky_notbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sticky_notbsd.go rename to contrib/go/_std_1.23/src/os/sticky_notbsd.go diff --git a/contrib/go/_std_1.22/src/os/sys.go b/contrib/go/_std_1.23/src/os/sys.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys.go rename to contrib/go/_std_1.23/src/os/sys.go diff --git a/contrib/go/_std_1.22/src/os/sys_aix.go b/contrib/go/_std_1.23/src/os/sys_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_aix.go rename to contrib/go/_std_1.23/src/os/sys_aix.go diff --git a/contrib/go/_std_1.22/src/os/sys_bsd.go b/contrib/go/_std_1.23/src/os/sys_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_bsd.go rename to contrib/go/_std_1.23/src/os/sys_bsd.go diff --git a/contrib/go/_std_1.22/src/os/sys_js.go b/contrib/go/_std_1.23/src/os/sys_js.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_js.go rename to contrib/go/_std_1.23/src/os/sys_js.go diff --git a/contrib/go/_std_1.22/src/os/sys_linux.go b/contrib/go/_std_1.23/src/os/sys_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_linux.go rename to contrib/go/_std_1.23/src/os/sys_linux.go diff --git a/contrib/go/_std_1.22/src/os/sys_plan9.go b/contrib/go/_std_1.23/src/os/sys_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_plan9.go rename to contrib/go/_std_1.23/src/os/sys_plan9.go diff --git a/contrib/go/_std_1.22/src/os/sys_solaris.go b/contrib/go/_std_1.23/src/os/sys_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_solaris.go rename to contrib/go/_std_1.23/src/os/sys_solaris.go diff --git a/contrib/go/_std_1.22/src/os/sys_unix.go b/contrib/go/_std_1.23/src/os/sys_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_unix.go rename to contrib/go/_std_1.23/src/os/sys_unix.go diff --git a/contrib/go/_std_1.22/src/os/sys_wasip1.go b/contrib/go/_std_1.23/src/os/sys_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_wasip1.go rename to contrib/go/_std_1.23/src/os/sys_wasip1.go diff --git a/contrib/go/_std_1.22/src/os/sys_windows.go b/contrib/go/_std_1.23/src/os/sys_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/os/sys_windows.go rename to contrib/go/_std_1.23/src/os/sys_windows.go diff --git a/contrib/go/_std_1.22/src/os/tempfile.go b/contrib/go/_std_1.23/src/os/tempfile.go similarity index 95% rename from contrib/go/_std_1.22/src/os/tempfile.go rename to contrib/go/_std_1.23/src/os/tempfile.go index 66c65e6c783c..af70b360b3a0 100644 --- a/contrib/go/_std_1.22/src/os/tempfile.go +++ b/contrib/go/_std_1.23/src/os/tempfile.go @@ -15,6 +15,7 @@ import ( // We generate random temporary file names so that there's a good // chance the file doesn't exist yet - keeps the number of tries in // TempFile to a minimum. +// //go:linkname runtime_rand runtime.rand func runtime_rand() uint64 @@ -26,7 +27,8 @@ func nextRandom() string { // opens the file for reading and writing, and returns the resulting file. // The filename is generated by taking pattern and adding a random string to the end. // If pattern includes a "*", the random string replaces the last "*". -// If dir is the empty string, CreateTemp uses the default directory for temporary files, as returned by TempDir. +// The file is created with mode 0o600 (before umask). +// If dir is the empty string, CreateTemp uses the default directory for temporary files, as returned by [TempDir]. // Multiple programs or goroutines calling CreateTemp simultaneously will not choose the same file. // The caller can use the file's Name method to find the pathname of the file. // It is the caller's responsibility to remove the file when it is no longer needed. @@ -77,6 +79,7 @@ func prefixAndSuffix(pattern string) (prefix, suffix string, err error) { // and returns the pathname of the new directory. // The new directory's name is generated by adding a random string to the end of pattern. // If pattern includes a "*", the random string replaces the last "*" instead. +// The directory is created with mode 0o700 (before umask). // If dir is the empty string, MkdirTemp uses the default directory for temporary files, as returned by TempDir. // Multiple programs or goroutines calling MkdirTemp simultaneously will not choose the same directory. // It is the caller's responsibility to remove the directory when it is no longer needed. diff --git a/contrib/go/_std_1.22/src/os/types.go b/contrib/go/_std_1.23/src/os/types.go similarity index 90% rename from contrib/go/_std_1.22/src/os/types.go rename to contrib/go/_std_1.23/src/os/types.go index d8edd98b68d7..d51a458f44f9 100644 --- a/contrib/go/_std_1.22/src/os/types.go +++ b/contrib/go/_std_1.23/src/os/types.go @@ -13,21 +13,23 @@ import ( func Getpagesize() int { return syscall.Getpagesize() } // File represents an open file descriptor. +// +// The methods of File are safe for concurrent use. type File struct { *file // os specific } -// A FileInfo describes a file and is returned by Stat and Lstat. +// A FileInfo describes a file and is returned by [Stat] and [Lstat]. type FileInfo = fs.FileInfo // A FileMode represents a file's mode and permission bits. // The bits have the same definition on all systems, so that // information about files can be moved from one system // to another portably. Not all bits apply to all systems. -// The only required bit is ModeDir for directories. +// The only required bit is [ModeDir] for directories. type FileMode = fs.FileMode -// The defined file mode bits are the most significant bits of the FileMode. +// The defined file mode bits are the most significant bits of the [FileMode]. // The nine least-significant bits are the standard Unix rwxrwxrwx permissions. // The values of these bits should be considered part of the public API and // may be used in wire protocols or disk representations: they must not be @@ -62,7 +64,7 @@ func (fs *fileStat) IsDir() bool { return fs.Mode().IsDir() } // For example, on Unix this means that the device and inode fields // of the two underlying structures are identical; on other systems // the decision may be based on the path names. -// SameFile only applies to results returned by this package's Stat. +// SameFile only applies to results returned by this package's [Stat]. // It returns false in other cases. func SameFile(fi1, fi2 FileInfo) bool { fs1, ok1 := fi1.(*fileStat) diff --git a/contrib/go/_std_1.22/src/os/types_plan9.go b/contrib/go/_std_1.23/src/os/types_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/types_plan9.go rename to contrib/go/_std_1.23/src/os/types_plan9.go diff --git a/contrib/go/_std_1.22/src/os/types_unix.go b/contrib/go/_std_1.23/src/os/types_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/types_unix.go rename to contrib/go/_std_1.23/src/os/types_unix.go diff --git a/contrib/go/_std_1.22/src/os/types_windows.go b/contrib/go/_std_1.23/src/os/types_windows.go similarity index 72% rename from contrib/go/_std_1.22/src/os/types_windows.go rename to contrib/go/_std_1.23/src/os/types_windows.go index 6b9fef6c123f..34648e796a87 100644 --- a/contrib/go/_std_1.22/src/os/types_windows.go +++ b/contrib/go/_std_1.23/src/os/types_windows.go @@ -5,6 +5,8 @@ package os import ( + "internal/filepathlite" + "internal/godebug" "internal/syscall/windows" "sync" "syscall" @@ -48,22 +50,18 @@ func newFileStatFromGetFileInformationByHandle(path string, h syscall.Handle) (f return nil, &PathError{Op: "GetFileInformationByHandle", Path: path, Err: err} } - var ti windows.FILE_ATTRIBUTE_TAG_INFO - err = windows.GetFileInformationByHandleEx(h, windows.FileAttributeTagInfo, (*byte)(unsafe.Pointer(&ti)), uint32(unsafe.Sizeof(ti))) - if err != nil { - if errno, ok := err.(syscall.Errno); ok && errno == windows.ERROR_INVALID_PARAMETER { - // It appears calling GetFileInformationByHandleEx with - // FILE_ATTRIBUTE_TAG_INFO fails on FAT file system with - // ERROR_INVALID_PARAMETER. Clear ti.ReparseTag in that - // instance to indicate no symlinks are possible. - ti.ReparseTag = 0 - } else { + var reparseTag uint32 + if d.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 { + var ti windows.FILE_ATTRIBUTE_TAG_INFO + err = windows.GetFileInformationByHandleEx(h, windows.FileAttributeTagInfo, (*byte)(unsafe.Pointer(&ti)), uint32(unsafe.Sizeof(ti))) + if err != nil { return nil, &PathError{Op: "GetFileInformationByHandleEx", Path: path, Err: err} } + reparseTag = ti.ReparseTag } return &fileStat{ - name: basename(path), + name: filepathlite.Base(path), FileAttributes: d.FileAttributes, CreationTime: d.CreationTime, LastAccessTime: d.LastAccessTime, @@ -73,13 +71,26 @@ func newFileStatFromGetFileInformationByHandle(path string, h syscall.Handle) (f vol: d.VolumeSerialNumber, idxhi: d.FileIndexHigh, idxlo: d.FileIndexLow, - ReparseTag: ti.ReparseTag, + ReparseTag: reparseTag, // fileStat.path is used by os.SameFile to decide if it needs // to fetch vol, idxhi and idxlo. But these are already set, // so set fileStat.path to "" to prevent os.SameFile doing it again. }, nil } +// newFileStatFromWin32FileAttributeData copies all required information +// from syscall.Win32FileAttributeData d into the newly created fileStat. +func newFileStatFromWin32FileAttributeData(d *syscall.Win32FileAttributeData) *fileStat { + return &fileStat{ + FileAttributes: d.FileAttributes, + CreationTime: d.CreationTime, + LastAccessTime: d.LastAccessTime, + LastWriteTime: d.LastWriteTime, + FileSizeHigh: d.FileSizeHigh, + FileSizeLow: d.FileSizeLow, + } +} + // newFileStatFromFileIDBothDirInfo copies all required information // from windows.FILE_ID_BOTH_DIR_INFO d into the newly created fileStat. func newFileStatFromFileIDBothDirInfo(d *windows.FILE_ID_BOTH_DIR_INFO) *fileStat { @@ -142,50 +153,63 @@ func newFileStatFromWin32finddata(d *syscall.Win32finddata) *fileStat { // and https://learn.microsoft.com/en-us/windows/win32/fileio/reparse-point-tags. func (fs *fileStat) isReparseTagNameSurrogate() bool { // True for IO_REPARSE_TAG_SYMLINK and IO_REPARSE_TAG_MOUNT_POINT. - return fs.ReparseTag&0x20000000 != 0 -} - -func (fs *fileStat) isSymlink() bool { - // As of https://go.dev/cl/86556, we treat MOUNT_POINT reparse points as - // symlinks because otherwise certain directory junction tests in the - // path/filepath package would fail. - // - // However, - // https://learn.microsoft.com/en-us/windows/win32/fileio/hard-links-and-junctions - // seems to suggest that directory junctions should be treated like hard - // links, not symlinks. - // - // TODO(bcmills): Get more input from Microsoft on what the behavior ought to - // be for MOUNT_POINT reparse points. - - return fs.ReparseTag == syscall.IO_REPARSE_TAG_SYMLINK || - fs.ReparseTag == windows.IO_REPARSE_TAG_MOUNT_POINT + return fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 && fs.ReparseTag&0x20000000 != 0 } func (fs *fileStat) Size() int64 { return int64(fs.FileSizeHigh)<<32 + int64(fs.FileSizeLow) } -func (fs *fileStat) Mode() (m FileMode) { +var winsymlink = godebug.New("winsymlink") + +func (fs *fileStat) Mode() FileMode { + m := fs.mode() + if winsymlink.Value() == "0" { + old := fs.modePreGo1_23() + if old != m { + winsymlink.IncNonDefault() + m = old + } + } + return m +} + +func (fs *fileStat) mode() (m FileMode) { if fs.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 { m |= 0444 } else { m |= 0666 } - if fs.isSymlink() { - return m | ModeSymlink - } - if fs.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { - m |= ModeDir | 0111 - } - switch fs.filetype { - case syscall.FILE_TYPE_PIPE: - m |= ModeNamedPipe - case syscall.FILE_TYPE_CHAR: - m |= ModeDevice | ModeCharDevice + + // Windows reports the FILE_ATTRIBUTE_DIRECTORY bit for reparse points + // that refer to directories, such as symlinks and mount points. + // However, we follow symlink POSIX semantics and do not set the mode bits. + // This allows users to walk directories without following links + // by just calling "fi, err := os.Lstat(name); err == nil && fi.IsDir()". + // Note that POSIX only defines the semantics for symlinks, not for + // mount points or other surrogate reparse points, but we treat them + // the same way for consistency. Also, mount points can contain infinite + // loops, so it is not safe to walk them without special handling. + if !fs.isReparseTagNameSurrogate() { + if fs.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { + m |= ModeDir | 0111 + } + + switch fs.filetype { + case syscall.FILE_TYPE_PIPE: + m |= ModeNamedPipe + case syscall.FILE_TYPE_CHAR: + m |= ModeDevice | ModeCharDevice + } } - if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 && m&ModeType == 0 { - if fs.ReparseTag == windows.IO_REPARSE_TAG_DEDUP { + + if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 { + switch fs.ReparseTag { + case syscall.IO_REPARSE_TAG_SYMLINK: + m |= ModeSymlink + case windows.IO_REPARSE_TAG_AF_UNIX: + m |= ModeSocket + case windows.IO_REPARSE_TAG_DEDUP: // If the Data Deduplication service is enabled on Windows Server, its // Optimization job may convert regular files to IO_REPARSE_TAG_DEDUP // whenever that job runs. @@ -199,10 +223,48 @@ func (fs *fileStat) Mode() (m FileMode) { // raw device files on Linux, POSIX FIFO special files, and so on), so // to avoid files changing unpredictably from regular to irregular we will // consider DEDUP files to be close enough to regular to treat as such. - } else { + default: m |= ModeIrregular } } + return +} + +// modePreGo1_23 returns the FileMode for the fileStat, using the pre-Go 1.23 +// logic for determining the file mode. +// The logic is subtle and not well-documented, so it is better to keep it +// separate from the new logic. +func (fs *fileStat) modePreGo1_23() (m FileMode) { + if fs.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 { + m |= 0444 + } else { + m |= 0666 + } + if fs.ReparseTag == syscall.IO_REPARSE_TAG_SYMLINK || + fs.ReparseTag == windows.IO_REPARSE_TAG_MOUNT_POINT { + return m | ModeSymlink + } + if fs.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { + m |= ModeDir | 0111 + } + switch fs.filetype { + case syscall.FILE_TYPE_PIPE: + m |= ModeNamedPipe + case syscall.FILE_TYPE_CHAR: + m |= ModeDevice | ModeCharDevice + } + if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 { + if fs.ReparseTag == windows.IO_REPARSE_TAG_AF_UNIX { + m |= ModeSocket + } + if m&ModeType == 0 { + if fs.ReparseTag == windows.IO_REPARSE_TAG_DEDUP { + // See comment in fs.Mode. + } else { + m |= ModeIrregular + } + } + } return m } @@ -277,14 +339,14 @@ func (fs *fileStat) loadFileId() error { // and set name from path. func (fs *fileStat) saveInfoFromPath(path string) error { fs.path = path - if !isAbs(fs.path) { + if !filepathlite.IsAbs(fs.path) { var err error fs.path, err = syscall.FullPath(fs.path) if err != nil { return &PathError{Op: "FullPath", Path: path, Err: err} } } - fs.name = basename(path) + fs.name = filepathlite.Base(path) return nil } diff --git a/contrib/go/_std_1.22/src/os/user/cgo_listgroups_unix.go b/contrib/go/_std_1.23/src/os/user/cgo_listgroups_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/cgo_listgroups_unix.go rename to contrib/go/_std_1.23/src/os/user/cgo_listgroups_unix.go diff --git a/contrib/go/_std_1.22/src/os/user/cgo_lookup_cgo.go b/contrib/go/_std_1.23/src/os/user/cgo_lookup_cgo.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/cgo_lookup_cgo.go rename to contrib/go/_std_1.23/src/os/user/cgo_lookup_cgo.go diff --git a/contrib/go/_std_1.22/src/os/user/cgo_lookup_syscall.go b/contrib/go/_std_1.23/src/os/user/cgo_lookup_syscall.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/cgo_lookup_syscall.go rename to contrib/go/_std_1.23/src/os/user/cgo_lookup_syscall.go diff --git a/contrib/go/_std_1.22/src/os/user/cgo_lookup_unix.go b/contrib/go/_std_1.23/src/os/user/cgo_lookup_unix.go similarity index 95% rename from contrib/go/_std_1.22/src/os/user/cgo_lookup_unix.go rename to contrib/go/_std_1.23/src/os/user/cgo_lookup_unix.go index 402429ba4ac5..458d8cd453ac 100644 --- a/contrib/go/_std_1.22/src/os/user/cgo_lookup_unix.go +++ b/contrib/go/_std_1.23/src/os/user/cgo_lookup_unix.go @@ -31,12 +31,12 @@ func lookupUser(username string) (*User, error) { (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf))) return errno }) + if err == syscall.ENOENT || (err == nil && !found) { + return nil, UnknownUserError(username) + } if err != nil { return nil, fmt.Errorf("user: lookup username %s: %v", username, err) } - if !found { - return nil, UnknownUserError(username) - } return buildUser(&pwd), err } @@ -58,12 +58,12 @@ func lookupUnixUid(uid int) (*User, error) { (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf))) return errno }) + if err == syscall.ENOENT || (err == nil && !found) { + return nil, UnknownUserIdError(uid) + } if err != nil { return nil, fmt.Errorf("user: lookup userid %d: %v", uid, err) } - if !found { - return nil, UnknownUserIdError(uid) - } return buildUser(&pwd), nil } @@ -96,12 +96,12 @@ func lookupGroup(groupname string) (*Group, error) { (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf))) return errno }) + if err == syscall.ENOENT || (err == nil && !found) { + return nil, UnknownGroupError(groupname) + } if err != nil { return nil, fmt.Errorf("user: lookup groupname %s: %v", groupname, err) } - if !found { - return nil, UnknownGroupError(groupname) - } return buildGroup(&grp), nil } @@ -123,12 +123,12 @@ func lookupUnixGid(gid int) (*Group, error) { (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf))) return syscall.Errno(errno) }) + if err == syscall.ENOENT || (err == nil && !found) { + return nil, UnknownGroupIdError(strconv.Itoa(gid)) + } if err != nil { return nil, fmt.Errorf("user: lookup groupid %d: %v", gid, err) } - if !found { - return nil, UnknownGroupIdError(strconv.Itoa(gid)) - } return buildGroup(&grp), nil } diff --git a/contrib/go/_std_1.22/src/os/user/getgrouplist_syscall.go b/contrib/go/_std_1.23/src/os/user/getgrouplist_syscall.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/getgrouplist_syscall.go rename to contrib/go/_std_1.23/src/os/user/getgrouplist_syscall.go diff --git a/contrib/go/_std_1.22/src/os/user/getgrouplist_unix.go b/contrib/go/_std_1.23/src/os/user/getgrouplist_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/getgrouplist_unix.go rename to contrib/go/_std_1.23/src/os/user/getgrouplist_unix.go diff --git a/contrib/go/_std_1.22/src/os/user/listgroups_stub.go b/contrib/go/_std_1.23/src/os/user/listgroups_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/listgroups_stub.go rename to contrib/go/_std_1.23/src/os/user/listgroups_stub.go diff --git a/contrib/go/_std_1.22/src/os/user/listgroups_unix.go b/contrib/go/_std_1.23/src/os/user/listgroups_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/listgroups_unix.go rename to contrib/go/_std_1.23/src/os/user/listgroups_unix.go diff --git a/contrib/go/_std_1.22/src/os/user/lookup.go b/contrib/go/_std_1.23/src/os/user/lookup.go similarity index 89% rename from contrib/go/_std_1.22/src/os/user/lookup.go rename to contrib/go/_std_1.23/src/os/user/lookup.go index ed33d0c7cd17..fb10b53938bd 100644 --- a/contrib/go/_std_1.22/src/os/user/lookup.go +++ b/contrib/go/_std_1.23/src/os/user/lookup.go @@ -35,7 +35,7 @@ var cache struct { } // Lookup looks up a user by username. If the user cannot be found, the -// returned error is of type UnknownUserError. +// returned error is of type [UnknownUserError]. func Lookup(username string) (*User, error) { if u, err := Current(); err == nil && u.Username == username { return u, err @@ -44,7 +44,7 @@ func Lookup(username string) (*User, error) { } // LookupId looks up a user by userid. If the user cannot be found, the -// returned error is of type UnknownUserIdError. +// returned error is of type [UnknownUserIdError]. func LookupId(uid string) (*User, error) { if u, err := Current(); err == nil && u.Uid == uid { return u, err @@ -53,13 +53,13 @@ func LookupId(uid string) (*User, error) { } // LookupGroup looks up a group by name. If the group cannot be found, the -// returned error is of type UnknownGroupError. +// returned error is of type [UnknownGroupError]. func LookupGroup(name string) (*Group, error) { return lookupGroup(name) } // LookupGroupId looks up a group by groupid. If the group cannot be found, the -// returned error is of type UnknownGroupIdError. +// returned error is of type [UnknownGroupIdError]. func LookupGroupId(gid string) (*Group, error) { return lookupGroupId(gid) } diff --git a/contrib/go/_std_1.22/src/os/user/lookup_android.go b/contrib/go/_std_1.23/src/os/user/lookup_android.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/lookup_android.go rename to contrib/go/_std_1.23/src/os/user/lookup_android.go diff --git a/contrib/go/_std_1.22/src/os/user/lookup_plan9.go b/contrib/go/_std_1.23/src/os/user/lookup_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/lookup_plan9.go rename to contrib/go/_std_1.23/src/os/user/lookup_plan9.go diff --git a/contrib/go/_std_1.22/src/os/user/lookup_stubs.go b/contrib/go/_std_1.23/src/os/user/lookup_stubs.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/lookup_stubs.go rename to contrib/go/_std_1.23/src/os/user/lookup_stubs.go diff --git a/contrib/go/_std_1.22/src/os/user/lookup_unix.go b/contrib/go/_std_1.23/src/os/user/lookup_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/lookup_unix.go rename to contrib/go/_std_1.23/src/os/user/lookup_unix.go diff --git a/contrib/go/_std_1.22/src/os/user/lookup_windows.go b/contrib/go/_std_1.23/src/os/user/lookup_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/os/user/lookup_windows.go rename to contrib/go/_std_1.23/src/os/user/lookup_windows.go diff --git a/contrib/go/_std_1.22/src/os/user/user.go b/contrib/go/_std_1.23/src/os/user/user.go similarity index 91% rename from contrib/go/_std_1.22/src/os/user/user.go rename to contrib/go/_std_1.23/src/os/user/user.go index 0307d2ad6a12..952da3d8bdab 100644 --- a/contrib/go/_std_1.22/src/os/user/user.go +++ b/contrib/go/_std_1.23/src/os/user/user.go @@ -63,14 +63,14 @@ type Group struct { Name string // group name } -// UnknownUserIdError is returned by LookupId when a user cannot be found. +// UnknownUserIdError is returned by [LookupId] when a user cannot be found. type UnknownUserIdError int func (e UnknownUserIdError) Error() string { return "user: unknown userid " + strconv.Itoa(int(e)) } -// UnknownUserError is returned by Lookup when +// UnknownUserError is returned by [Lookup] when // a user cannot be found. type UnknownUserError string @@ -78,7 +78,7 @@ func (e UnknownUserError) Error() string { return "user: unknown user " + string(e) } -// UnknownGroupIdError is returned by LookupGroupId when +// UnknownGroupIdError is returned by [LookupGroupId] when // a group cannot be found. type UnknownGroupIdError string @@ -86,7 +86,7 @@ func (e UnknownGroupIdError) Error() string { return "group: unknown groupid " + string(e) } -// UnknownGroupError is returned by LookupGroup when +// UnknownGroupError is returned by [LookupGroup] when // a group cannot be found. type UnknownGroupError string diff --git a/contrib/go/_std_1.22/src/os/user/ya.make b/contrib/go/_std_1.23/src/os/user/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/os/user/ya.make rename to contrib/go/_std_1.23/src/os/user/ya.make diff --git a/contrib/go/_std_1.22/src/os/wait6_dragonfly.go b/contrib/go/_std_1.23/src/os/wait6_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait6_dragonfly.go rename to contrib/go/_std_1.23/src/os/wait6_dragonfly.go diff --git a/contrib/go/_std_1.22/src/os/wait6_freebsd64.go b/contrib/go/_std_1.23/src/os/wait6_freebsd64.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait6_freebsd64.go rename to contrib/go/_std_1.23/src/os/wait6_freebsd64.go diff --git a/contrib/go/_std_1.22/src/os/wait6_freebsd_386.go b/contrib/go/_std_1.23/src/os/wait6_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait6_freebsd_386.go rename to contrib/go/_std_1.23/src/os/wait6_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/os/wait6_freebsd_arm.go b/contrib/go/_std_1.23/src/os/wait6_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait6_freebsd_arm.go rename to contrib/go/_std_1.23/src/os/wait6_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/os/wait6_netbsd.go b/contrib/go/_std_1.23/src/os/wait6_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait6_netbsd.go rename to contrib/go/_std_1.23/src/os/wait6_netbsd.go diff --git a/contrib/go/_std_1.22/src/os/wait_unimp.go b/contrib/go/_std_1.23/src/os/wait_unimp.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait_unimp.go rename to contrib/go/_std_1.23/src/os/wait_unimp.go diff --git a/contrib/go/_std_1.22/src/os/wait_wait6.go b/contrib/go/_std_1.23/src/os/wait_wait6.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait_wait6.go rename to contrib/go/_std_1.23/src/os/wait_wait6.go diff --git a/contrib/go/_std_1.22/src/os/wait_waitid.go b/contrib/go/_std_1.23/src/os/wait_waitid.go similarity index 100% rename from contrib/go/_std_1.22/src/os/wait_waitid.go rename to contrib/go/_std_1.23/src/os/wait_waitid.go diff --git a/contrib/go/_std_1.22/src/os/ya.make b/contrib/go/_std_1.23/src/os/ya.make similarity index 95% rename from contrib/go/_std_1.22/src/os/ya.make rename to contrib/go/_std_1.23/src/os/ya.make index 8911bf552df5..77583b07bac1 100644 --- a/contrib/go/_std_1.22/src/os/ya.make +++ b/contrib/go/_std_1.23/src/os/ya.make @@ -3,12 +3,11 @@ IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM6 SRCS( dir.go dir_darwin.go - endian_little.go env.go error.go error_errno.go - error_posix.go exec.go + exec_nohandle.go exec_posix.go exec_unix.go executable.go @@ -20,6 +19,7 @@ IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM6 getwd.go path.go path_unix.go + pidfd_other.go pipe_unix.go proc.go rawconn.go @@ -42,12 +42,11 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ dir.go dir_unix.go dirent_linux.go - endian_little.go env.go error.go error_errno.go - error_posix.go exec.go + exec_linux.go exec_posix.go exec_unix.go executable.go @@ -59,6 +58,7 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ getwd.go path.go path_unix.go + pidfd_linux.go pipe2_unix.go proc.go rawconn.go @@ -80,11 +80,9 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND AR SRCS( dir.go dir_windows.go - endian_little.go env.go error.go error_errno.go - error_posix.go exec.go exec_posix.go exec_windows.go @@ -96,6 +94,7 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND AR getwd.go path.go path_windows.go + pidfd_other.go proc.go rawconn.go removeall_noat.go diff --git a/contrib/go/_std_1.22/src/os/zero_copy_linux.go b/contrib/go/_std_1.23/src/os/zero_copy_linux.go similarity index 89% rename from contrib/go/_std_1.22/src/os/zero_copy_linux.go rename to contrib/go/_std_1.23/src/os/zero_copy_linux.go index 7c45aefeee86..0afc19e125a2 100644 --- a/contrib/go/_std_1.22/src/os/zero_copy_linux.go +++ b/contrib/go/_std_1.23/src/os/zero_copy_linux.go @@ -13,9 +13,17 @@ import ( var ( pollCopyFileRange = poll.CopyFileRange pollSplice = poll.Splice - pollSendFile = poll.SendFile ) +// wrapSyscallError takes an error and a syscall name. If the error is +// a syscall.Errno, it wraps it in an os.SyscallError using the syscall name. +func wrapSyscallError(name string, err error) error { + if _, ok := err.(syscall.Errno); ok { + err = NewSyscallError(name, err) + } + return err +} + func (f *File) writeTo(w io.Writer) (written int64, handled bool, err error) { pfd, network := getPollFDAndNetwork(w) // TODO(panjf2000): same as File.spliceToFile. @@ -29,7 +37,7 @@ func (f *File) writeTo(w io.Writer) (written int64, handled bool, err error) { } rerr := sc.Read(func(fd uintptr) (done bool) { - written, err, handled = pollSendFile(pfd, int(fd), 1<<63-1) + written, err, handled = poll.SendFile(pfd, int(fd), 1<<63-1) return true }) @@ -78,14 +86,13 @@ func (f *File) spliceToFile(r io.Reader) (written int64, handled bool, err error return } - var syscallName string - written, handled, syscallName, err = pollSplice(&f.pfd, pfd, remain) + written, handled, err = pollSplice(&f.pfd, pfd, remain) if lr != nil { lr.N = remain - written } - return written, handled, wrapSyscallError(syscallName, err) + return written, handled, wrapSyscallError("splice", err) } func (f *File) copyFileRange(r io.Reader) (written int64, handled bool, err error) { diff --git a/contrib/go/_std_1.22/src/os/zero_copy_stub.go b/contrib/go/_std_1.23/src/os/zero_copy_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/os/zero_copy_stub.go rename to contrib/go/_std_1.23/src/os/zero_copy_stub.go diff --git a/contrib/go/_std_1.22/src/path/filepath/match.go b/contrib/go/_std_1.23/src/path/filepath/match.go similarity index 98% rename from contrib/go/_std_1.22/src/path/filepath/match.go rename to contrib/go/_std_1.23/src/path/filepath/match.go index 12f0bfa7d3e8..b93e89adb03a 100644 --- a/contrib/go/_std_1.22/src/path/filepath/match.go +++ b/contrib/go/_std_1.23/src/path/filepath/match.go @@ -6,9 +6,10 @@ package filepath import ( "errors" + "internal/filepathlite" "os" "runtime" - "sort" + "slices" "strings" "unicode/utf8" ) @@ -307,7 +308,7 @@ func cleanGlobPath(path string) string { // cleanGlobPathWindows is windows version of cleanGlobPath. func cleanGlobPathWindows(path string) (prefixLen int, cleaned string) { - vollen := volumeNameLen(path) + vollen := filepathlite.VolumeNameLen(path) switch { case path == "": return 0, "." @@ -344,7 +345,7 @@ func glob(dir, pattern string, matches []string) (m []string, e error) { defer d.Close() names, _ := d.Readdirnames(-1) - sort.Strings(names) + slices.Sort(names) for _, n := range names { matched, err := Match(pattern, n) diff --git a/contrib/go/_std_1.22/src/path/filepath/path.go b/contrib/go/_std_1.23/src/path/filepath/path.go similarity index 76% rename from contrib/go/_std_1.22/src/path/filepath/path.go rename to contrib/go/_std_1.23/src/path/filepath/path.go index 2af0f5b04cfc..5ffd9f0b6c3f 100644 --- a/contrib/go/_std_1.22/src/path/filepath/path.go +++ b/contrib/go/_std_1.23/src/path/filepath/path.go @@ -13,57 +13,13 @@ package filepath import ( "errors" + "internal/bytealg" + "internal/filepathlite" "io/fs" "os" "slices" - "sort" - "strings" ) -// A lazybuf is a lazily constructed path buffer. -// It supports append, reading previously appended bytes, -// and retrieving the final string. It does not allocate a buffer -// to hold the output until that output diverges from s. -type lazybuf struct { - path string - buf []byte - w int - volAndPath string - volLen int -} - -func (b *lazybuf) index(i int) byte { - if b.buf != nil { - return b.buf[i] - } - return b.path[i] -} - -func (b *lazybuf) append(c byte) { - if b.buf == nil { - if b.w < len(b.path) && b.path[b.w] == c { - b.w++ - return - } - b.buf = make([]byte, len(b.path)) - copy(b.buf, b.path[:b.w]) - } - b.buf[b.w] = c - b.w++ -} - -func (b *lazybuf) prepend(prefix ...byte) { - b.buf = slices.Insert(b.buf, 0, prefix...) - b.w += len(prefix) -} - -func (b *lazybuf) string() string { - if b.buf == nil { - return b.volAndPath[:b.volLen+b.w] - } - return b.volAndPath[:b.volLen] + string(b.buf[:b.w]) -} - const ( Separator = os.PathSeparator ListSeparator = os.PathListSeparator @@ -97,78 +53,7 @@ const ( // Getting Dot-Dot Right,” // https://9p.io/sys/doc/lexnames.html func Clean(path string) string { - originalPath := path - volLen := volumeNameLen(path) - path = path[volLen:] - if path == "" { - if volLen > 1 && os.IsPathSeparator(originalPath[0]) && os.IsPathSeparator(originalPath[1]) { - // should be UNC - return FromSlash(originalPath) - } - return originalPath + "." - } - rooted := os.IsPathSeparator(path[0]) - - // Invariants: - // reading from path; r is index of next byte to process. - // writing to buf; w is index of next byte to write. - // dotdot is index in buf where .. must stop, either because - // it is the leading slash or it is a leading ../../.. prefix. - n := len(path) - out := lazybuf{path: path, volAndPath: originalPath, volLen: volLen} - r, dotdot := 0, 0 - if rooted { - out.append(Separator) - r, dotdot = 1, 1 - } - - for r < n { - switch { - case os.IsPathSeparator(path[r]): - // empty path element - r++ - case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])): - // . element - r++ - case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])): - // .. element: remove to last separator - r += 2 - switch { - case out.w > dotdot: - // can backtrack - out.w-- - for out.w > dotdot && !os.IsPathSeparator(out.index(out.w)) { - out.w-- - } - case !rooted: - // cannot backtrack, but not rooted, so append .. element. - if out.w > 0 { - out.append(Separator) - } - out.append('.') - out.append('.') - dotdot = out.w - } - default: - // real path element. - // add slash if needed - if rooted && out.w != 1 || !rooted && out.w != 0 { - out.append(Separator) - } - // copy element - for ; r < n && !os.IsPathSeparator(path[r]); r++ { - out.append(path[r]) - } - } - } - - // Turn empty string into "." - if out.w == 0 { - out.append('.') - } - - postClean(&out) // avoid creating absolute paths on Windows - return FromSlash(out.string()) + return filepathlite.Clean(path) } // IsLocal reports whether path, using lexical analysis only, has all of these properties: @@ -186,49 +71,36 @@ func Clean(path string) string { // In particular, it does not account for the effect of any symbolic links // that may exist in the filesystem. func IsLocal(path string) bool { - return isLocal(path) + return filepathlite.IsLocal(path) } -func unixIsLocal(path string) bool { - if IsAbs(path) || path == "" { - return false - } - hasDots := false - for p := path; p != ""; { - var part string - part, p, _ = strings.Cut(p, "/") - if part == "." || part == ".." { - hasDots = true - break - } - } - if hasDots { - path = Clean(path) - } - if path == ".." || strings.HasPrefix(path, "../") { - return false - } - return true +// Localize converts a slash-separated path into an operating system path. +// The input path must be a valid path as reported by [io/fs.ValidPath]. +// +// Localize returns an error if the path cannot be represented by the operating system. +// For example, the path a\b is rejected on Windows, on which \ is a separator +// character and cannot be part of a filename. +// +// The path returned by Localize will always be local, as reported by IsLocal. +func Localize(path string) (string, error) { + return filepathlite.Localize(path) } // ToSlash returns the result of replacing each separator character // in path with a slash ('/') character. Multiple separators are // replaced by multiple slashes. func ToSlash(path string) string { - if Separator == '/' { - return path - } - return strings.ReplaceAll(path, string(Separator), "/") + return filepathlite.ToSlash(path) } // FromSlash returns the result of replacing each slash ('/') character // in path with a separator character. Multiple slashes are replaced // by multiple separators. +// +// See also the Localize function, which converts a slash-separated path +// as used by the io/fs package to an operating system path. func FromSlash(path string) string { - if Separator == '/' { - return path - } - return strings.ReplaceAll(path, "/", string(Separator)) + return filepathlite.FromSlash(path) } // SplitList splits a list of paths joined by the OS-specific [ListSeparator], @@ -245,12 +117,7 @@ func SplitList(path string) []string { // and file set to path. // The returned values have the property that path = dir+file. func Split(path string) (dir, file string) { - vol := VolumeName(path) - i := len(path) - 1 - for i >= len(vol) && !os.IsPathSeparator(path[i]) { - i-- - } - return path[:i+1], path[i+1:] + return filepathlite.Split(path) } // Join joins any number of path elements into a single path, @@ -269,12 +136,7 @@ func Join(elem ...string) string { // in the final element of path; it is empty if there is // no dot. func Ext(path string) string { - for i := len(path) - 1; i >= 0 && !os.IsPathSeparator(path[i]); i-- { - if path[i] == '.' { - return path[i:] - } - } - return "" + return filepathlite.Ext(path) } // EvalSymlinks returns the path name after the evaluation of any symbolic @@ -286,6 +148,11 @@ func EvalSymlinks(path string) (string, error) { return evalSymlinks(path) } +// IsAbs reports whether the path is absolute. +func IsAbs(path string) bool { + return filepathlite.IsAbs(path) +} + // Abs returns an absolute representation of path. // If the path is not absolute it will be joined with the current // working directory to turn it into an absolute path. The absolute @@ -326,7 +193,7 @@ func Rel(basepath, targpath string) (string, error) { targ = targ[len(targVol):] if base == "." { base = "" - } else if base == "" && volumeNameLen(baseVol) > 2 /* isUNC */ { + } else if base == "" && filepathlite.VolumeNameLen(baseVol) > 2 /* isUNC */ { // Treat any targetpath matching `\\host\share` basepath as absolute path. base = string(Separator) } @@ -365,7 +232,7 @@ func Rel(basepath, targpath string) (string, error) { } if b0 != bl { // Base elements left. Must go up before going down. - seps := strings.Count(base[b0:bl], string(Separator)) + seps := bytealg.CountString(base[b0:bl], Separator) size := 2 + seps*3 if tl != t0 { size += 1 + tl - t0 @@ -577,7 +444,7 @@ func readDirNames(dirname string) ([]string, error) { if err != nil { return nil, err } - sort.Strings(names) + slices.Sort(names) return names, nil } @@ -586,28 +453,7 @@ func readDirNames(dirname string) ([]string, error) { // If the path is empty, Base returns ".". // If the path consists entirely of separators, Base returns a single separator. func Base(path string) string { - if path == "" { - return "." - } - // Strip trailing slashes. - for len(path) > 0 && os.IsPathSeparator(path[len(path)-1]) { - path = path[0 : len(path)-1] - } - // Throw away volume name - path = path[len(VolumeName(path)):] - // Find the last element - i := len(path) - 1 - for i >= 0 && !os.IsPathSeparator(path[i]) { - i-- - } - if i >= 0 { - path = path[i+1:] - } - // If empty now, it had only slashes. - if path == "" { - return string(Separator) - } - return path + return filepathlite.Base(path) } // Dir returns all but the last element of path, typically the path's directory. @@ -617,17 +463,7 @@ func Base(path string) string { // If the path consists entirely of separators, Dir returns a single separator. // The returned path does not end in a separator unless it is the root directory. func Dir(path string) string { - vol := VolumeName(path) - i := len(path) - 1 - for i >= len(vol) && !os.IsPathSeparator(path[i]) { - i-- - } - dir := Clean(path[len(vol) : i+1]) - if dir == "." && len(vol) > 2 { - // must be UNC - return vol - } - return vol + dir + return filepathlite.Dir(path) } // VolumeName returns leading volume name. @@ -635,5 +471,5 @@ func Dir(path string) string { // Given "\\host\share\foo" it returns "\\host\share". // On other platforms it returns "". func VolumeName(path string) string { - return FromSlash(path[:volumeNameLen(path)]) + return filepathlite.VolumeName(path) } diff --git a/contrib/go/_std_1.22/src/path/filepath/path_plan9.go b/contrib/go/_std_1.23/src/path/filepath/path_plan9.go similarity index 70% rename from contrib/go/_std_1.22/src/path/filepath/path_plan9.go rename to contrib/go/_std_1.23/src/path/filepath/path_plan9.go index 453206aee3e0..0e5147b90b6c 100644 --- a/contrib/go/_std_1.22/src/path/filepath/path_plan9.go +++ b/contrib/go/_std_1.23/src/path/filepath/path_plan9.go @@ -4,22 +4,9 @@ package filepath -import "strings" - -func isLocal(path string) bool { - return unixIsLocal(path) -} - -// IsAbs reports whether the path is absolute. -func IsAbs(path string) bool { - return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#") -} - -// volumeNameLen returns length of the leading volume name on Windows. -// It returns 0 elsewhere. -func volumeNameLen(path string) int { - return 0 -} +import ( + "strings" +) // HasPrefix exists for historical compatibility and should not be used. // diff --git a/contrib/go/_std_1.22/src/path/filepath/path_unix.go b/contrib/go/_std_1.23/src/path/filepath/path_unix.go similarity index 73% rename from contrib/go/_std_1.22/src/path/filepath/path_unix.go rename to contrib/go/_std_1.23/src/path/filepath/path_unix.go index 57e621743434..6bc974db3fbe 100644 --- a/contrib/go/_std_1.22/src/path/filepath/path_unix.go +++ b/contrib/go/_std_1.23/src/path/filepath/path_unix.go @@ -6,22 +6,9 @@ package filepath -import "strings" - -func isLocal(path string) bool { - return unixIsLocal(path) -} - -// IsAbs reports whether the path is absolute. -func IsAbs(path string) bool { - return strings.HasPrefix(path, "/") -} - -// volumeNameLen returns length of the leading volume name on Windows. -// It returns 0 elsewhere. -func volumeNameLen(path string) int { - return 0 -} +import ( + "strings" +) // HasPrefix exists for historical compatibility and should not be used. // diff --git a/contrib/go/_std_1.23/src/path/filepath/path_windows.go b/contrib/go/_std_1.23/src/path/filepath/path_windows.go new file mode 100644 index 000000000000..d53f87f1ac1a --- /dev/null +++ b/contrib/go/_std_1.23/src/path/filepath/path_windows.go @@ -0,0 +1,114 @@ +package filepath + +import ( + "os" + "strings" + "syscall" +) + +// HasPrefix exists for historical compatibility and should not be used. +// +// Deprecated: HasPrefix does not respect path boundaries and +// does not ignore case when required. +func HasPrefix(p, prefix string) bool { + if strings.HasPrefix(p, prefix) { + return true + } + return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix)) +} + +func splitList(path string) []string { + // The same implementation is used in LookPath in os/exec; + // consider changing os/exec when changing this. + + if path == "" { + return []string{} + } + + // Split path, respecting but preserving quotes. + list := []string{} + start := 0 + quo := false + for i := 0; i < len(path); i++ { + switch c := path[i]; { + case c == '"': + quo = !quo + case c == ListSeparator && !quo: + list = append(list, path[start:i]) + start = i + 1 + } + } + list = append(list, path[start:]) + + // Remove quotes. + for i, s := range list { + list[i] = strings.ReplaceAll(s, `"`, ``) + } + + return list +} + +func abs(path string) (string, error) { + if path == "" { + // syscall.FullPath returns an error on empty path, because it's not a valid path. + // To implement Abs behavior of returning working directory on empty string input, + // special-case empty path by changing it to "." path. See golang.org/issue/24441. + path = "." + } + fullPath, err := syscall.FullPath(path) + if err != nil { + return "", err + } + return Clean(fullPath), nil +} + +func join(elem []string) string { + var b strings.Builder + var lastChar byte + for _, e := range elem { + switch { + case b.Len() == 0: + // Add the first non-empty path element unchanged. + case os.IsPathSeparator(lastChar): + // If the path ends in a slash, strip any leading slashes from the next + // path element to avoid creating a UNC path (any path starting with "\\") + // from non-UNC elements. + // + // The correct behavior for Join when the first element is an incomplete UNC + // path (for example, "\\") is underspecified. We currently join subsequent + // elements so Join("\\", "host", "share") produces "\\host\share". + for len(e) > 0 && os.IsPathSeparator(e[0]) { + e = e[1:] + } + // If the path is \ and the next path element is ??, + // add an extra .\ to create \.\?? rather than \??\ + // (a Root Local Device path). + if b.Len() == 1 && strings.HasPrefix(e, "??") && (len(e) == len("??") || os.IsPathSeparator(e[2])) { + b.WriteString(`.\`) + } + case lastChar == ':': + // If the path ends in a colon, keep the path relative to the current directory + // on a drive and don't add a separator. Preserve leading slashes in the next + // path element, which may make the path absolute. + // + // Join(`C:`, `f`) = `C:f` + // Join(`C:`, `\f`) = `C:\f` + default: + // In all other cases, add a separator between elements. + b.WriteByte('\\') + lastChar = '\\' + } + if len(e) > 0 { + b.WriteString(e) + lastChar = e[len(e)-1] + } + } + if b.Len() == 0 { + return "" + } + return Clean(b.String()) +} + +func sameWord(a, b string) bool { + return strings.EqualFold(a, b) +} diff --git a/contrib/go/_std_1.22/src/path/filepath/symlink.go b/contrib/go/_std_1.23/src/path/filepath/symlink.go similarity index 91% rename from contrib/go/_std_1.22/src/path/filepath/symlink.go rename to contrib/go/_std_1.23/src/path/filepath/symlink.go index f9435e0d5b90..a6047ae44437 100644 --- a/contrib/go/_std_1.22/src/path/filepath/symlink.go +++ b/contrib/go/_std_1.23/src/path/filepath/symlink.go @@ -6,6 +6,7 @@ package filepath import ( "errors" + "internal/filepathlite" "io/fs" "os" "runtime" @@ -13,7 +14,7 @@ import ( ) func walkSymlinks(path string) (string, error) { - volLen := volumeNameLen(path) + volLen := filepathlite.VolumeNameLen(path) pathSeparator := string(os.PathSeparator) if volLen < len(path) && os.IsPathSeparator(path[volLen]) { @@ -34,7 +35,7 @@ func walkSymlinks(path string) (string, error) { // On Windows, "." can be a symlink. // We look it up, and use the value if it is absolute. // If not, we just return ".". - isWindowsDot := runtime.GOOS == "windows" && path[volumeNameLen(path):] == "." + isWindowsDot := runtime.GOOS == "windows" && path[filepathlite.VolumeNameLen(path):] == "." // The next path component is in path[start:end]. if end == start { @@ -73,7 +74,7 @@ func walkSymlinks(path string) (string, error) { // Ordinary path component. Add it to result. - if len(dest) > volumeNameLen(dest) && !os.IsPathSeparator(dest[len(dest)-1]) { + if len(dest) > filepathlite.VolumeNameLen(dest) && !os.IsPathSeparator(dest[len(dest)-1]) { dest += pathSeparator } @@ -113,7 +114,7 @@ func walkSymlinks(path string) (string, error) { path = link + path[end:] - v := volumeNameLen(link) + v := filepathlite.VolumeNameLen(link) if v > 0 { // Symlink to drive name is an absolute path. if v < len(link) && os.IsPathSeparator(link[v]) { diff --git a/contrib/go/_std_1.22/src/path/filepath/symlink_plan9.go b/contrib/go/_std_1.23/src/path/filepath/symlink_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/path/filepath/symlink_plan9.go rename to contrib/go/_std_1.23/src/path/filepath/symlink_plan9.go diff --git a/contrib/go/_std_1.22/src/path/filepath/symlink_unix.go b/contrib/go/_std_1.23/src/path/filepath/symlink_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/path/filepath/symlink_unix.go rename to contrib/go/_std_1.23/src/path/filepath/symlink_unix.go diff --git a/contrib/go/_std_1.22/src/path/filepath/symlink_windows.go b/contrib/go/_std_1.23/src/path/filepath/symlink_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/path/filepath/symlink_windows.go rename to contrib/go/_std_1.23/src/path/filepath/symlink_windows.go diff --git a/contrib/go/_std_1.22/src/path/filepath/ya.make b/contrib/go/_std_1.23/src/path/filepath/ya.make similarity index 98% rename from contrib/go/_std_1.22/src/path/filepath/ya.make rename to contrib/go/_std_1.23/src/path/filepath/ya.make index 40919fc1b05e..15a3e27a3a35 100644 --- a/contrib/go/_std_1.22/src/path/filepath/ya.make +++ b/contrib/go/_std_1.23/src/path/filepath/ya.make @@ -3,7 +3,6 @@ IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM6 SRCS( match.go path.go - path_nonwindows.go path_unix.go symlink.go symlink_unix.go diff --git a/contrib/go/_std_1.22/src/path/match.go b/contrib/go/_std_1.23/src/path/match.go similarity index 100% rename from contrib/go/_std_1.22/src/path/match.go rename to contrib/go/_std_1.23/src/path/match.go diff --git a/contrib/go/_std_1.22/src/path/path.go b/contrib/go/_std_1.23/src/path/path.go similarity index 100% rename from contrib/go/_std_1.22/src/path/path.go rename to contrib/go/_std_1.23/src/path/path.go diff --git a/contrib/go/_std_1.22/src/path/ya.make b/contrib/go/_std_1.23/src/path/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/path/ya.make rename to contrib/go/_std_1.23/src/path/ya.make diff --git a/contrib/go/_std_1.22/src/reflect/abi.go b/contrib/go/_std_1.23/src/reflect/abi.go similarity index 99% rename from contrib/go/_std_1.22/src/reflect/abi.go rename to contrib/go/_std_1.23/src/reflect/abi.go index 2b5f40538057..b67d8217430d 100644 --- a/contrib/go/_std_1.22/src/reflect/abi.go +++ b/contrib/go/_std_1.23/src/reflect/abi.go @@ -166,7 +166,7 @@ func (a *abiSeq) addRcvr(rcvr *abi.Type) (*abiStep, bool) { // The receiver is always one word. a.valueStart = append(a.valueStart, len(a.steps)) var ok, ptr bool - if ifaceIndir(rcvr) || rcvr.Pointers() { + if rcvr.IfaceIndir() || rcvr.Pointers() { ok = a.assignIntN(0, goarch.PtrSize, 1, 0b1) ptr = true } else { diff --git a/contrib/go/_std_1.22/src/reflect/arena.go b/contrib/go/_std_1.23/src/reflect/arena.go similarity index 77% rename from contrib/go/_std_1.22/src/reflect/arena.go rename to contrib/go/_std_1.23/src/reflect/arena.go index cac1a1da5eaa..769f8ebc7401 100644 --- a/contrib/go/_std_1.22/src/reflect/arena.go +++ b/contrib/go/_std_1.23/src/reflect/arena.go @@ -8,9 +8,9 @@ package reflect import "arena" -// ArenaNew returns a Value representing a pointer to a new zero value for the +// ArenaNew returns a [Value] representing a pointer to a new zero value for the // specified type, allocating storage for it in the provided arena. That is, -// the returned Value's Type is PointerTo(typ). +// the returned Value's Type is [PointerTo](typ). func ArenaNew(a *arena.Arena, typ Type) Value { return ValueOf(arena_New(a, PointerTo(typ))) } diff --git a/contrib/go/_std_1.22/src/reflect/asm_386.s b/contrib/go/_std_1.23/src/reflect/asm_386.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_386.s rename to contrib/go/_std_1.23/src/reflect/asm_386.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_amd64.s b/contrib/go/_std_1.23/src/reflect/asm_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_amd64.s rename to contrib/go/_std_1.23/src/reflect/asm_amd64.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_arm.s b/contrib/go/_std_1.23/src/reflect/asm_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_arm.s rename to contrib/go/_std_1.23/src/reflect/asm_arm.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_arm64.s b/contrib/go/_std_1.23/src/reflect/asm_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_arm64.s rename to contrib/go/_std_1.23/src/reflect/asm_arm64.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_loong64.s b/contrib/go/_std_1.23/src/reflect/asm_loong64.s similarity index 94% rename from contrib/go/_std_1.22/src/reflect/asm_loong64.s rename to contrib/go/_std_1.23/src/reflect/asm_loong64.s index 520f0afdd516..c0dc24449766 100644 --- a/contrib/go/_std_1.22/src/reflect/asm_loong64.s +++ b/contrib/go/_std_1.23/src/reflect/asm_loong64.s @@ -34,13 +34,8 @@ TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$432 JAL runtime·spillArgs(SB) MOVV REGCTXT, 32(R3) // save REGCTXT > args of moveMakeFuncArgPtrs < LOCAL_REGARGS -#ifdef GOEXPERIMENT_regabiargs MOVV REGCTXT, R4 MOVV R25, R5 -#else - MOVV REGCTXT, 8(R3) - MOVV R25, 16(R3) -#endif JAL ·moveMakeFuncArgPtrs(SB) MOVV 32(R3), REGCTXT // restore REGCTXT @@ -66,13 +61,8 @@ TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$432 ADDV $LOCAL_REGARGS, R3, R25 // spillArgs using R25 JAL runtime·spillArgs(SB) MOVV REGCTXT, 32(R3) // save REGCTXT > args of moveMakeFuncArgPtrs < LOCAL_REGARGS -#ifdef GOEXPERIMENT_regabiargs MOVV REGCTXT, R4 MOVV R25, R5 -#else - MOVV REGCTXT, 8(R3) - MOVV R25, 16(R3) -#endif JAL ·moveMakeFuncArgPtrs(SB) MOVV 32(R3), REGCTXT // restore REGCTXT MOVV REGCTXT, 8(R3) diff --git a/contrib/go/_std_1.22/src/reflect/asm_mips64x.s b/contrib/go/_std_1.23/src/reflect/asm_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_mips64x.s rename to contrib/go/_std_1.23/src/reflect/asm_mips64x.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_mipsx.s b/contrib/go/_std_1.23/src/reflect/asm_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_mipsx.s rename to contrib/go/_std_1.23/src/reflect/asm_mipsx.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_ppc64x.s b/contrib/go/_std_1.23/src/reflect/asm_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_ppc64x.s rename to contrib/go/_std_1.23/src/reflect/asm_ppc64x.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_riscv64.s b/contrib/go/_std_1.23/src/reflect/asm_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_riscv64.s rename to contrib/go/_std_1.23/src/reflect/asm_riscv64.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_s390x.s b/contrib/go/_std_1.23/src/reflect/asm_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_s390x.s rename to contrib/go/_std_1.23/src/reflect/asm_s390x.s diff --git a/contrib/go/_std_1.22/src/reflect/asm_wasm.s b/contrib/go/_std_1.23/src/reflect/asm_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/asm_wasm.s rename to contrib/go/_std_1.23/src/reflect/asm_wasm.s diff --git a/contrib/go/_std_1.23/src/reflect/badlinkname.go b/contrib/go/_std_1.23/src/reflect/badlinkname.go new file mode 100644 index 000000000000..eb701bff033d --- /dev/null +++ b/contrib/go/_std_1.23/src/reflect/badlinkname.go @@ -0,0 +1,130 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package reflect + +import ( + "internal/abi" + "unsafe" + _ "unsafe" +) + +// Widely used packages access these symbols using linkname, +// most notably: +// - github.com/goccy/go-json +// - github.com/goccy/go-reflect +// - github.com/sohaha/zlsgo +// - github.com/undefinedlabs/go-mpatch +// +// Do not remove or change the type signature. +// See go.dev/issue/67401 +// and go.dev/issue/67279. + +// ifaceIndir reports whether t is stored indirectly in an interface value. +// It is no longer used by this package and is here entirely for the +// linkname uses. +// +//go:linkname unusedIfaceIndir reflect.ifaceIndir +func unusedIfaceIndir(t *abi.Type) bool { + return t.Kind_&abi.KindDirectIface == 0 +} + +//go:linkname valueInterface + +// The compiler doesn't allow linknames on methods, for good reasons. +// We use this trick to push linknames of the methods. +// Do not call them in this package. + +//go:linkname badlinkname_rtype_Align reflect.(*rtype).Align +func badlinkname_rtype_Align(*rtype) int + +//go:linkname badlinkname_rtype_AssignableTo reflect.(*rtype).AssignableTo +func badlinkname_rtype_AssignableTo(*rtype, Type) bool + +//go:linkname badlinkname_rtype_Bits reflect.(*rtype).Bits +func badlinkname_rtype_Bits(*rtype) int + +//go:linkname badlinkname_rtype_ChanDir reflect.(*rtype).ChanDir +func badlinkname_rtype_ChanDir(*rtype) ChanDir + +//go:linkname badlinkname_rtype_Comparable reflect.(*rtype).Comparable +func badlinkname_rtype_Comparable(*rtype) bool + +//go:linkname badlinkname_rtype_ConvertibleTo reflect.(*rtype).ConvertibleTo +func badlinkname_rtype_ConvertibleTo(*rtype, Type) bool + +//go:linkname badlinkname_rtype_Elem reflect.(*rtype).Elem +func badlinkname_rtype_Elem(*rtype) Type + +//go:linkname badlinkname_rtype_Field reflect.(*rtype).Field +func badlinkname_rtype_Field(*rtype, int) StructField + +//go:linkname badlinkname_rtype_FieldAlign reflect.(*rtype).FieldAlign +func badlinkname_rtype_FieldAlign(*rtype) int + +//go:linkname badlinkname_rtype_FieldByIndex reflect.(*rtype).FieldByIndex +func badlinkname_rtype_FieldByIndex(*rtype, []int) StructField + +//go:linkname badlinkname_rtype_FieldByName reflect.(*rtype).FieldByName +func badlinkname_rtype_FieldByName(*rtype, string) (StructField, bool) + +//go:linkname badlinkname_rtype_FieldByNameFunc reflect.(*rtype).FieldByNameFunc +func badlinkname_rtype_FieldByNameFunc(*rtype, func(string) bool) (StructField, bool) + +//go:linkname badlinkname_rtype_Implements reflect.(*rtype).Implements +func badlinkname_rtype_Implements(*rtype, Type) bool + +//go:linkname badlinkname_rtype_In reflect.(*rtype).In +func badlinkname_rtype_In(*rtype, int) Type + +//go:linkname badlinkname_rtype_IsVariadic reflect.(*rtype).IsVariadic +func badlinkname_rtype_IsVariadic(*rtype) bool + +//go:linkname badlinkname_rtype_Key reflect.(*rtype).Key +func badlinkname_rtype_Key(*rtype) Type + +//go:linkname badlinkname_rtype_Kind reflect.(*rtype).Kind +func badlinkname_rtype_Kind(*rtype) Kind + +//go:linkname badlinkname_rtype_Len reflect.(*rtype).Len +func badlinkname_rtype_Len(*rtype) int + +//go:linkname badlinkname_rtype_Method reflect.(*rtype).Method +func badlinkname_rtype_Method(*rtype, int) Method + +//go:linkname badlinkname_rtype_MethodByName reflect.(*rtype).MethodByName +func badlinkname_rtype_MethodByName(*rtype, string) (Method, bool) + +//go:linkname badlinkname_rtype_Name reflect.(*rtype).Name +func badlinkname_rtype_Name(*rtype) string + +//go:linkname badlinkname_rtype_NumField reflect.(*rtype).NumField +func badlinkname_rtype_NumField(*rtype) int + +//go:linkname badlinkname_rtype_NumIn reflect.(*rtype).NumIn +func badlinkname_rtype_NumIn(*rtype) int + +//go:linkname badlinkname_rtype_NumMethod reflect.(*rtype).NumMethod +func badlinkname_rtype_NumMethod(*rtype) int + +//go:linkname badlinkname_rtype_NumOut reflect.(*rtype).NumOut +func badlinkname_rtype_NumOut(*rtype) int + +//go:linkname badlinkname_rtype_Out reflect.(*rtype).Out +func badlinkname_rtype_Out(*rtype, int) Type + +//go:linkname badlinkname_rtype_PkgPath reflect.(*rtype).PkgPath +func badlinkname_rtype_PkgPath(*rtype) string + +//go:linkname badlinkname_rtype_Size reflect.(*rtype).Size +func badlinkname_rtype_Size(*rtype) uintptr + +//go:linkname badlinkname_rtype_String reflect.(*rtype).String +func badlinkname_rtype_String(*rtype) string + +//go:linkname badlinkname_rtype_ptrTo reflect.(*rtype).ptrTo +func badlinkname_rtype_ptrTo(*rtype) *abi.Type + +//go:linkname badlinkname_Value_pointer reflect.(*Value).pointer +func badlinkname_Value_pointer(Value) unsafe.Pointer diff --git a/contrib/go/_std_1.22/src/reflect/deepequal.go b/contrib/go/_std_1.23/src/reflect/deepequal.go similarity index 99% rename from contrib/go/_std_1.22/src/reflect/deepequal.go rename to contrib/go/_std_1.23/src/reflect/deepequal.go index 961e17011839..502ea9f146be 100644 --- a/contrib/go/_std_1.22/src/reflect/deepequal.go +++ b/contrib/go/_std_1.23/src/reflect/deepequal.go @@ -39,7 +39,7 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool { hard := func(v1, v2 Value) bool { switch v1.Kind() { case Pointer: - if v1.typ().PtrBytes == 0 { + if !v1.typ().Pointers() { // not-in-heap pointers can't be cyclic. // At least, all of our current uses of runtime/internal/sys.NotInHeap // have that property. The runtime ones aren't cyclic (and we don't use diff --git a/contrib/go/_std_1.22/src/reflect/float32reg_generic.go b/contrib/go/_std_1.23/src/reflect/float32reg_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/reflect/float32reg_generic.go rename to contrib/go/_std_1.23/src/reflect/float32reg_generic.go diff --git a/contrib/go/_std_1.22/src/reflect/float32reg_ppc64x.s b/contrib/go/_std_1.23/src/reflect/float32reg_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/float32reg_ppc64x.s rename to contrib/go/_std_1.23/src/reflect/float32reg_ppc64x.s diff --git a/contrib/go/_std_1.22/src/reflect/float32reg_riscv64.s b/contrib/go/_std_1.23/src/reflect/float32reg_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/reflect/float32reg_riscv64.s rename to contrib/go/_std_1.23/src/reflect/float32reg_riscv64.s diff --git a/contrib/go/_std_1.22/src/reflect/internal/example1/example.go b/contrib/go/_std_1.23/src/reflect/internal/example1/example.go similarity index 100% rename from contrib/go/_std_1.22/src/reflect/internal/example1/example.go rename to contrib/go/_std_1.23/src/reflect/internal/example1/example.go diff --git a/contrib/go/_std_1.22/src/reflect/internal/example1/ya.make b/contrib/go/_std_1.23/src/reflect/internal/example1/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/reflect/internal/example1/ya.make rename to contrib/go/_std_1.23/src/reflect/internal/example1/ya.make diff --git a/contrib/go/_std_1.22/src/reflect/internal/example2/example.go b/contrib/go/_std_1.23/src/reflect/internal/example2/example.go similarity index 100% rename from contrib/go/_std_1.22/src/reflect/internal/example2/example.go rename to contrib/go/_std_1.23/src/reflect/internal/example2/example.go diff --git a/contrib/go/_std_1.22/src/reflect/internal/example2/ya.make b/contrib/go/_std_1.23/src/reflect/internal/example2/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/reflect/internal/example2/ya.make rename to contrib/go/_std_1.23/src/reflect/internal/example2/ya.make diff --git a/contrib/go/_std_1.22/src/reflect/internal/ya.make b/contrib/go/_std_1.23/src/reflect/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/reflect/internal/ya.make rename to contrib/go/_std_1.23/src/reflect/internal/ya.make diff --git a/contrib/go/_std_1.23/src/reflect/iter.go b/contrib/go/_std_1.23/src/reflect/iter.go new file mode 100644 index 000000000000..03df87b17882 --- /dev/null +++ b/contrib/go/_std_1.23/src/reflect/iter.go @@ -0,0 +1,173 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package reflect + +import ( + "iter" +) + +func rangeNum[T int8 | int16 | int32 | int64 | int | + uint8 | uint16 | uint32 | uint64 | uint | + uintptr, N int64 | uint64](num N, t Type) iter.Seq[Value] { + return func(yield func(v Value) bool) { + convert := t.PkgPath() != "" + // cannot use range T(v) because no core type. + for i := T(0); i < T(num); i++ { + tmp := ValueOf(i) + // if the iteration value type is define by + // type T built-in type. + if convert { + tmp = tmp.Convert(t) + } + if !yield(tmp) { + return + } + } + } +} + +// Seq returns an iter.Seq[Value] that loops over the elements of v. +// If v's kind is Func, it must be a function that has no results and +// that takes a single argument of type func(T) bool for some type T. +// If v's kind is Pointer, the pointer element type must have kind Array. +// Otherwise v's kind must be Int, Int8, Int16, Int32, Int64, +// Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, +// Array, Chan, Map, Slice, or String. +func (v Value) Seq() iter.Seq[Value] { + if canRangeFunc(v.abiType()) { + return func(yield func(Value) bool) { + rf := MakeFunc(v.Type().In(0), func(in []Value) []Value { + return []Value{ValueOf(yield(in[0]))} + }) + v.Call([]Value{rf}) + } + } + switch v.kind() { + case Int: + return rangeNum[int](v.Int(), v.Type()) + case Int8: + return rangeNum[int8](v.Int(), v.Type()) + case Int16: + return rangeNum[int16](v.Int(), v.Type()) + case Int32: + return rangeNum[int32](v.Int(), v.Type()) + case Int64: + return rangeNum[int64](v.Int(), v.Type()) + case Uint: + return rangeNum[uint](v.Uint(), v.Type()) + case Uint8: + return rangeNum[uint8](v.Uint(), v.Type()) + case Uint16: + return rangeNum[uint16](v.Uint(), v.Type()) + case Uint32: + return rangeNum[uint32](v.Uint(), v.Type()) + case Uint64: + return rangeNum[uint64](v.Uint(), v.Type()) + case Uintptr: + return rangeNum[uintptr](v.Uint(), v.Type()) + case Pointer: + if v.Elem().kind() != Array { + break + } + return func(yield func(Value) bool) { + v = v.Elem() + for i := range v.Len() { + if !yield(ValueOf(i)) { + return + } + } + } + case Array, Slice: + return func(yield func(Value) bool) { + for i := range v.Len() { + if !yield(ValueOf(i)) { + return + } + } + } + case String: + return func(yield func(Value) bool) { + for i := range v.String() { + if !yield(ValueOf(i)) { + return + } + } + } + case Map: + return func(yield func(Value) bool) { + i := v.MapRange() + for i.Next() { + if !yield(i.Key()) { + return + } + } + } + case Chan: + return func(yield func(Value) bool) { + for value, ok := v.Recv(); ok; value, ok = v.Recv() { + if !yield(value) { + return + } + } + } + } + panic("reflect: " + v.Type().String() + " cannot produce iter.Seq[Value]") +} + +// Seq2 returns an iter.Seq2[Value, Value] that loops over the elements of v. +// If v's kind is Func, it must be a function that has no results and +// that takes a single argument of type func(K, V) bool for some type K, V. +// If v's kind is Pointer, the pointer element type must have kind Array. +// Otherwise v's kind must be Array, Map, Slice, or String. +func (v Value) Seq2() iter.Seq2[Value, Value] { + if canRangeFunc2(v.abiType()) { + return func(yield func(Value, Value) bool) { + rf := MakeFunc(v.Type().In(0), func(in []Value) []Value { + return []Value{ValueOf(yield(in[0], in[1]))} + }) + v.Call([]Value{rf}) + } + } + switch v.Kind() { + case Pointer: + if v.Elem().kind() != Array { + break + } + return func(yield func(Value, Value) bool) { + v = v.Elem() + for i := range v.Len() { + if !yield(ValueOf(i), v.Index(i)) { + return + } + } + } + case Array, Slice: + return func(yield func(Value, Value) bool) { + for i := range v.Len() { + if !yield(ValueOf(i), v.Index(i)) { + return + } + } + } + case String: + return func(yield func(Value, Value) bool) { + for i, v := range v.String() { + if !yield(ValueOf(i), ValueOf(v)) { + return + } + } + } + case Map: + return func(yield func(Value, Value) bool) { + i := v.MapRange() + for i.Next() { + if !yield(i.Key(), i.Value()) { + return + } + } + } + } + panic("reflect: " + v.Type().String() + " cannot produce iter.Seq2[Value, Value]") +} diff --git a/contrib/go/_std_1.22/src/reflect/makefunc.go b/contrib/go/_std_1.23/src/reflect/makefunc.go similarity index 96% rename from contrib/go/_std_1.22/src/reflect/makefunc.go rename to contrib/go/_std_1.23/src/reflect/makefunc.go index 2ed7f3890588..5da6cd2ec7d4 100644 --- a/contrib/go/_std_1.22/src/reflect/makefunc.go +++ b/contrib/go/_std_1.23/src/reflect/makefunc.go @@ -22,7 +22,7 @@ type makeFuncImpl struct { fn func([]Value) []Value } -// MakeFunc returns a new function of the given Type +// MakeFunc returns a new function of the given [Type] // that wraps the function fn. When called, that new function // does the following: // @@ -30,14 +30,14 @@ type makeFuncImpl struct { // - runs results := fn(args). // - returns the results as a slice of Values, one per formal result. // -// The implementation fn can assume that the argument Value slice +// The implementation fn can assume that the argument [Value] slice // has the number and type of arguments given by typ. // If typ describes a variadic function, the final Value is itself // a slice representing the variadic arguments, as in the // body of a variadic function. The result Value slice returned by fn // must have the number and type of results given by typ. // -// The Value.Call method allows the caller to invoke a typed function +// The [Value.Call] method allows the caller to invoke a typed function // in terms of Values; in contrast, MakeFunc allows the caller to implement // a typed function in terms of Values. // diff --git a/contrib/go/_std_1.22/src/reflect/stubs_ppc64x.go b/contrib/go/_std_1.23/src/reflect/stubs_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/reflect/stubs_ppc64x.go rename to contrib/go/_std_1.23/src/reflect/stubs_ppc64x.go diff --git a/contrib/go/_std_1.22/src/reflect/stubs_riscv64.go b/contrib/go/_std_1.23/src/reflect/stubs_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/reflect/stubs_riscv64.go rename to contrib/go/_std_1.23/src/reflect/stubs_riscv64.go diff --git a/contrib/go/_std_1.22/src/reflect/swapper.go b/contrib/go/_std_1.23/src/reflect/swapper.go similarity index 98% rename from contrib/go/_std_1.22/src/reflect/swapper.go rename to contrib/go/_std_1.23/src/reflect/swapper.go index 1e8f4ed16364..78f6a19e4a99 100644 --- a/contrib/go/_std_1.22/src/reflect/swapper.go +++ b/contrib/go/_std_1.23/src/reflect/swapper.go @@ -34,7 +34,7 @@ func Swapper(slice any) func(i, j int) { typ := v.Type().Elem().common() size := typ.Size() - hasPtr := typ.PtrBytes != 0 + hasPtr := typ.Pointers() // Some common & small cases, without using memmove: if hasPtr { diff --git a/contrib/go/_std_1.22/src/reflect/type.go b/contrib/go/_std_1.23/src/reflect/type.go similarity index 91% rename from contrib/go/_std_1.22/src/reflect/type.go rename to contrib/go/_std_1.23/src/reflect/type.go index 89c501553023..07e2bf16447b 100644 --- a/contrib/go/_std_1.22/src/reflect/type.go +++ b/contrib/go/_std_1.23/src/reflect/type.go @@ -225,6 +225,28 @@ type Type interface { // It panics if i is not in the range [0, NumOut()). Out(i int) Type + // OverflowComplex reports whether the complex128 x cannot be represented by type t. + // It panics if t's Kind is not Complex64 or Complex128. + OverflowComplex(x complex128) bool + + // OverflowFloat reports whether the float64 x cannot be represented by type t. + // It panics if t's Kind is not Float32 or Float64. + OverflowFloat(x float64) bool + + // OverflowInt reports whether the int64 x cannot be represented by type t. + // It panics if t's Kind is not Int, Int8, Int16, Int32, or Int64. + OverflowInt(x int64) bool + + // OverflowUint reports whether the uint64 x cannot be represented by type t. + // It panics if t's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64. + OverflowUint(x uint64) bool + + // CanSeq reports whether a [Value] with this type can be iterated over using [Value.Seq]. + CanSeq() bool + + // CanSeq2 reports whether a [Value] with this type can be iterated over using [Value.Seq2]. + CanSeq2() bool + common() *abi.Type uncommon() *uncommonType } @@ -438,12 +460,6 @@ func (m Method) IsExported() bool { return m.PkgPath == "" } -const ( - kindDirectIface = 1 << 5 - kindGCProg = 1 << 6 // Type.gc points to GC program - kindMask = (1 << 5) - 1 -) - // String returns the name of k. func (k Kind) String() string { if uint(k) < uint(len(kindNames)) { @@ -507,6 +523,15 @@ func resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer // It returns a new ID that can be used as a typeOff or textOff, and will // be resolved correctly. Implemented in the runtime package. // +// addReflectOff should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goplus/reflectx +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname addReflectOff //go:noescape func addReflectOff(ptr unsafe.Pointer) int32 @@ -812,6 +837,106 @@ func (t *rtype) IsVariadic() bool { return tt.IsVariadic() } +func (t *rtype) OverflowComplex(x complex128) bool { + k := t.Kind() + switch k { + case Complex64: + return overflowFloat32(real(x)) || overflowFloat32(imag(x)) + case Complex128: + return false + } + panic("reflect: OverflowComplex of non-complex type " + t.String()) +} + +func (t *rtype) OverflowFloat(x float64) bool { + k := t.Kind() + switch k { + case Float32: + return overflowFloat32(x) + case Float64: + return false + } + panic("reflect: OverflowFloat of non-float type " + t.String()) +} + +func (t *rtype) OverflowInt(x int64) bool { + k := t.Kind() + switch k { + case Int, Int8, Int16, Int32, Int64: + bitSize := t.Size() * 8 + trunc := (x << (64 - bitSize)) >> (64 - bitSize) + return x != trunc + } + panic("reflect: OverflowInt of non-int type " + t.String()) +} + +func (t *rtype) OverflowUint(x uint64) bool { + k := t.Kind() + switch k { + case Uint, Uintptr, Uint8, Uint16, Uint32, Uint64: + bitSize := t.Size() * 8 + trunc := (x << (64 - bitSize)) >> (64 - bitSize) + return x != trunc + } + panic("reflect: OverflowUint of non-uint type " + t.String()) +} + +func (t *rtype) CanSeq() bool { + switch t.Kind() { + case Int8, Int16, Int32, Int64, Int, Uint8, Uint16, Uint32, Uint64, Uint, Uintptr, Array, Slice, Chan, String, Map: + return true + case Func: + return canRangeFunc(&t.t) + case Pointer: + return t.Elem().Kind() == Array + } + return false +} + +func canRangeFunc(t *abi.Type) bool { + if t.Kind() != abi.Func { + return false + } + f := t.FuncType() + if f.InCount != 1 || f.OutCount != 0 { + return false + } + y := f.In(0) + if y.Kind() != abi.Func { + return false + } + yield := y.FuncType() + return yield.InCount == 1 && yield.OutCount == 1 && yield.Out(0).Kind() == abi.Bool +} + +func (t *rtype) CanSeq2() bool { + switch t.Kind() { + case Array, Slice, String, Map: + return true + case Func: + return canRangeFunc2(&t.t) + case Pointer: + return t.Elem().Kind() == Array + } + return false +} + +func canRangeFunc2(t *abi.Type) bool { + if t.Kind() != abi.Func { + return false + } + f := t.FuncType() + if f.InCount != 1 || f.OutCount != 0 { + return false + } + y := f.In(0) + if y.Kind() != abi.Func { + return false + } + yield := y.FuncType() + return yield.InCount == 2 && yield.OutCount == 1 && yield.Out(0).Kind() == abi.Bool +} + // add returns p+x. // // The whySafe string is ignored, so that the function still inlines @@ -819,6 +944,17 @@ func (t *rtype) IsVariadic() bool { // record why the addition is safe, which is to say why the addition // does not cause x to advance to the very end of p's allocation // and therefore point incorrectly at the next block in memory. +// +// add should be an internal detail (and is trivially copyable), +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/pinpoint-apm/pinpoint-go-agent +// - github.com/vmware/govmomi +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname add func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { return unsafe.Pointer(uintptr(p) + x) } @@ -908,7 +1044,7 @@ type StructTag string // If there is no such key in the tag, Get returns the empty string. // If the tag does not have the conventional format, the value // returned by Get is unspecified. To determine whether a tag is -// explicitly set to the empty string, use Lookup. +// explicitly set to the empty string, use [StructTag.Lookup]. func (tag StructTag) Get(key string) string { v, _ := tag.Lookup(key) return v @@ -1158,16 +1294,12 @@ func (t *structType) FieldByName(name string) (f StructField, present bool) { // TypeOf returns the reflection [Type] that represents the dynamic type of i. // If i is a nil interface value, TypeOf returns nil. func TypeOf(i any) Type { - eface := *(*emptyInterface)(unsafe.Pointer(&i)) - // Noescape so this doesn't make i to escape. See the comment - // at Value.typ for why this is safe. - return toType((*abi.Type)(noescape(unsafe.Pointer(eface.typ)))) + return toType(abi.TypeOf(i)) } // rtypeOf directly extracts the *rtype of the provided value. func rtypeOf(i any) *abi.Type { - eface := *(*emptyInterface)(unsafe.Pointer(&i)) - return eface.typ + return abi.TypeOf(i) } // ptrMap is the cache for PointerTo. @@ -1520,6 +1652,15 @@ func haveIdenticalUnderlyingType(T, V *abi.Type, cmpTags bool) bool { // pointers, channels, maps, slices, and arrays. func typelinks() (sections []unsafe.Pointer, offset [][]int32) +// rtypeOff should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goccy/go-json +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname rtypeOff func rtypeOff(section unsafe.Pointer, off int32) *abi.Type { return (*abi.Type)(add(section, uintptr(off), "sizeof(rtype) > 0")) } @@ -1528,6 +1669,17 @@ func rtypeOff(section unsafe.Pointer, off int32) *abi.Type { // the given string representation. // It may be empty (no known types with that string) or may have // multiple elements (multiple types with that string). +// +// typesByString should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/aristanetworks/goarista +// - fortio.org/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname typesByString func typesByString(s string) []*abi.Type { sections, offset := typelinks() var ret []*abi.Type @@ -1694,13 +1846,13 @@ func MapOf(key, elem Type) Type { return typehash(ktyp, p, seed) } mt.Flags = 0 - if ktyp.Size_ > maxKeySize { + if ktyp.Size_ > abi.MapMaxKeyBytes { mt.KeySize = uint8(goarch.PtrSize) mt.Flags |= 1 // indirect key } else { mt.KeySize = uint8(ktyp.Size_) } - if etyp.Size_ > maxValSize { + if etyp.Size_ > abi.MapMaxElemBytes { mt.ValueSize = uint8(goarch.PtrSize) mt.Flags |= 2 // indirect value } else { @@ -1954,21 +2106,11 @@ func hashMightPanic(t *abi.Type) bool { } } -// Make sure these routines stay in sync with ../runtime/map.go! -// These types exist only for GC, so we only fill out GC relevant info. -// Currently, that's just size and the GC program. We also fill in string -// for possible debugging use. -const ( - bucketSize uintptr = abi.MapBucketCount - maxKeySize uintptr = abi.MapMaxKeyBytes - maxValSize uintptr = abi.MapMaxElemBytes -) - func bucketOf(ktyp, etyp *abi.Type) *abi.Type { - if ktyp.Size_ > maxKeySize { + if ktyp.Size_ > abi.MapMaxKeyBytes { ktyp = ptrTo(ktyp) } - if etyp.Size_ > maxValSize { + if etyp.Size_ > abi.MapMaxElemBytes { etyp = ptrTo(etyp) } @@ -1980,29 +2122,29 @@ func bucketOf(ktyp, etyp *abi.Type) *abi.Type { var gcdata *byte var ptrdata uintptr - size := bucketSize*(1+ktyp.Size_+etyp.Size_) + goarch.PtrSize + size := abi.MapBucketCount*(1+ktyp.Size_+etyp.Size_) + goarch.PtrSize if size&uintptr(ktyp.Align_-1) != 0 || size&uintptr(etyp.Align_-1) != 0 { panic("reflect: bad size computation in MapOf") } - if ktyp.PtrBytes != 0 || etyp.PtrBytes != 0 { - nptr := (bucketSize*(1+ktyp.Size_+etyp.Size_) + goarch.PtrSize) / goarch.PtrSize + if ktyp.Pointers() || etyp.Pointers() { + nptr := (abi.MapBucketCount*(1+ktyp.Size_+etyp.Size_) + goarch.PtrSize) / goarch.PtrSize n := (nptr + 7) / 8 // Runtime needs pointer masks to be a multiple of uintptr in size. n = (n + goarch.PtrSize - 1) &^ (goarch.PtrSize - 1) mask := make([]byte, n) - base := bucketSize / goarch.PtrSize + base := uintptr(abi.MapBucketCount / goarch.PtrSize) - if ktyp.PtrBytes != 0 { - emitGCMask(mask, base, ktyp, bucketSize) + if ktyp.Pointers() { + emitGCMask(mask, base, ktyp, abi.MapBucketCount) } - base += bucketSize * ktyp.Size_ / goarch.PtrSize + base += abi.MapBucketCount * ktyp.Size_ / goarch.PtrSize - if etyp.PtrBytes != 0 { - emitGCMask(mask, base, etyp, bucketSize) + if etyp.Pointers() { + emitGCMask(mask, base, etyp, abi.MapBucketCount) } - base += bucketSize * etyp.Size_ / goarch.PtrSize + base += abi.MapBucketCount * etyp.Size_ / goarch.PtrSize word := base mask[word/8] |= 1 << (word % 8) @@ -2018,7 +2160,7 @@ func bucketOf(ktyp, etyp *abi.Type) *abi.Type { b := &abi.Type{ Align_: goarch.PtrSize, Size_: size, - Kind_: uint8(Struct), + Kind_: abi.Struct, PtrBytes: ptrdata, GCData: gcdata, } @@ -2034,7 +2176,7 @@ func (t *rtype) gcSlice(begin, end uintptr) []byte { // emitGCMask writes the GC mask for [n]typ into out, starting at bit // offset base. func emitGCMask(out []byte, base uintptr, typ *abi.Type, n uintptr) { - if typ.Kind_&kindGCProg != 0 { + if typ.Kind_&abi.KindGCProg != 0 { panic("reflect: unexpected GC program") } ptrs := typ.PtrBytes / goarch.PtrSize @@ -2053,7 +2195,7 @@ func emitGCMask(out []byte, base uintptr, typ *abi.Type, n uintptr) { // appendGCProg appends the GC program for the first ptrdata bytes of // typ to dst and returns the extended slice. func appendGCProg(dst []byte, typ *abi.Type) []byte { - if typ.Kind_&kindGCProg != 0 { + if typ.Kind_&abi.KindGCProg != 0 { // Element has GC program; emit one element. n := uintptr(*(*uint32)(unsafe.Pointer(typ.GCData))) prog := typ.GcSlice(4, 4+n-1) @@ -2152,6 +2294,51 @@ func isValidFieldName(fieldName string) bool { return len(fieldName) > 0 } +// This must match cmd/compile/internal/compare.IsRegularMemory +func isRegularMemory(t Type) bool { + switch t.Kind() { + case Array: + elem := t.Elem() + if isRegularMemory(elem) { + return true + } + return elem.Comparable() && t.Len() == 0 + case Int8, Int16, Int32, Int64, Int, Uint8, Uint16, Uint32, Uint64, Uint, Uintptr, Chan, Pointer, Bool, UnsafePointer: + return true + case Struct: + num := t.NumField() + switch num { + case 0: + return true + case 1: + field := t.Field(0) + if field.Name == "_" { + return false + } + return isRegularMemory(field.Type) + default: + for i := range num { + field := t.Field(i) + if field.Name == "_" || !isRegularMemory(field.Type) || isPaddedField(t, i) { + return false + } + } + return true + } + } + return false +} + +// isPaddedField reports whether the i'th field of struct type t is followed +// by padding. +func isPaddedField(t Type, i int) bool { + field := t.Field(i) + if i+1 < t.NumField() { + return field.Offset+field.Type.Size() != t.Field(i+1).Offset + } + return field.Offset+field.Type.Size() != t.Size() +} + // StructOf returns the struct type containing fields. // The Offset and Index fields are ignored and computed as they would be // by the compiler. @@ -2188,7 +2375,7 @@ func StructOf(fields []StructField) Type { } f, fpkgpath := runtimeStructField(field) ft := f.Typ - if ft.Kind_&kindGCProg != 0 { + if ft.Kind_&abi.KindGCProg != 0 { hasGCProg = true } if fpkgpath != "" { @@ -2202,8 +2389,9 @@ func StructOf(fields []StructField) Type { // Update string and hash name := f.Name.Name() hash = fnv1(hash, []byte(name)...) - repr = append(repr, (" " + name)...) - if f.Embedded() { + if !f.Embedded() { + repr = append(repr, (" " + name)...) + } else { // Embedded field if f.Typ.Kind() == abi.Pointer { // Embedded ** and *interface{} are illegal @@ -2277,7 +2465,7 @@ func StructOf(fields []StructField) Type { // Issue 15924. panic("reflect: embedded type with methods not implemented if type is not first field") } - if len(fields) > 1 && ft.Kind_&kindDirectIface != 0 { + if len(fields) > 1 && ft.Kind_&abi.KindDirectIface != 0 { panic("reflect: embedded type with methods not implemented for non-pointer type") } for _, m := range unt.Methods() { @@ -2445,7 +2633,11 @@ func StructOf(fields []StructField) Type { } typ.Str = resolveReflectName(newName(str, "", false, false)) - typ.TFlag = 0 // TODO: set tflagRegularMemory + if isRegularMemory(toType(&typ.Type)) { + typ.TFlag = abi.TFlagRegularMemory + } else { + typ.TFlag = 0 + } typ.Hash = hash typ.Size_ = size typ.PtrBytes = typeptrdata(&typ.Type) @@ -2491,10 +2683,10 @@ func StructOf(fields []StructField) Type { } prog = append(prog, 0) *(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4) - typ.Kind_ |= kindGCProg + typ.Kind_ |= abi.KindGCProg typ.GCData = &prog[0] } else { - typ.Kind_ &^= kindGCProg + typ.Kind_ &^= abi.KindGCProg bv := new(bitVector) addTypeBits(bv, 0, &typ.Type) if len(bv.data) > 0 { @@ -2516,11 +2708,11 @@ func StructOf(fields []StructField) Type { } switch { - case len(fs) == 1 && !ifaceIndir(fs[0].Typ): + case len(fs) == 1 && !fs[0].Typ.IfaceIndir(): // structs of 1 direct iface type can be direct - typ.Kind_ |= kindDirectIface + typ.Kind_ |= abi.KindDirectIface default: - typ.Kind_ &^= kindDirectIface + typ.Kind_ &^= abi.KindDirectIface } return addToCache(toType(&typ.Type)) @@ -2582,9 +2774,6 @@ func typeptrdata(t *abi.Type) uintptr { } } -// See cmd/compile/internal/reflectdata/reflect.go for derivation of constant. -const maxPtrmaskBytes = 2048 - // ArrayOf returns the array type with the given length and element type. // For example, if t represents int, ArrayOf(5, t) represents [5]int. // @@ -2633,7 +2822,7 @@ func ArrayOf(length int, elem Type) Type { } } array.Size_ = typ.Size_ * uintptr(length) - if length > 0 && typ.PtrBytes != 0 { + if length > 0 && typ.Pointers() { array.PtrBytes = typ.Size_*uintptr(length-1) + typ.PtrBytes } array.Align_ = typ.Align_ @@ -2642,18 +2831,18 @@ func ArrayOf(length int, elem Type) Type { array.Slice = &(SliceOf(elem).(*rtype).t) switch { - case typ.PtrBytes == 0 || array.Size_ == 0: + case !typ.Pointers() || array.Size_ == 0: // No pointers. array.GCData = nil array.PtrBytes = 0 case length == 1: // In memory, 1-element array looks just like the element. - array.Kind_ |= typ.Kind_ & kindGCProg + array.Kind_ |= typ.Kind_ & abi.KindGCProg array.GCData = typ.GCData array.PtrBytes = typ.PtrBytes - case typ.Kind_&kindGCProg == 0 && array.Size_ <= maxPtrmaskBytes*8*goarch.PtrSize: + case typ.Kind_&abi.KindGCProg == 0 && array.Size_ <= abi.MaxPtrmaskBytes*8*goarch.PtrSize: // Element is small with pointer mask; array is still small. // Create direct pointer mask by turning each 1 bit in elem // into length 1 bits in larger mask. @@ -2690,7 +2879,7 @@ func ArrayOf(length int, elem Type) Type { prog = appendVarint(prog, uintptr(length)-1) prog = append(prog, 0) *(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4) - array.Kind_ |= kindGCProg + array.Kind_ |= abi.KindGCProg array.GCData = &prog[0] array.PtrBytes = array.Size_ // overestimate but ok; must match program } @@ -2714,11 +2903,11 @@ func ArrayOf(length int, elem Type) Type { } switch { - case length == 1 && !ifaceIndir(typ): + case length == 1 && !typ.IfaceIndir(): // array of 1 direct iface type can be direct - array.Kind_ |= kindDirectIface + array.Kind_ |= abi.KindDirectIface default: - array.Kind_ &^= kindDirectIface + array.Kind_ &^= abi.KindDirectIface } ti, _ := lookupCache.LoadOrStore(ckey, toRType(&array.Type)) @@ -2738,6 +2927,19 @@ func appendVarint(x []byte, v uintptr) []byte { // a nil *rtype must be replaced by a nil Type, but in gccgo this // function takes care of ensuring that multiple *rtype for the same // type are coalesced into a single Type. +// +// toType should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - fortio.org/log +// - github.com/goccy/go-json +// - github.com/goccy/go-reflect +// - github.com/sohaha/zlsgo +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname toType func toType(t *abi.Type) Type { if t == nil { return nil @@ -2816,11 +3018,6 @@ func funcLayout(t *funcType, rcvr *abi.Type) (frametype *abi.Type, framePool *sy return lt.t, lt.framePool, lt.abid } -// ifaceIndir reports whether t is stored indirectly in an interface value. -func ifaceIndir(t *abi.Type) bool { - return t.Kind_&kindDirectIface == 0 -} - // Note: this type must agree with runtime.bitvector. type bitVector struct { n uint32 // number of bits @@ -2842,21 +3039,21 @@ func (bv *bitVector) append(bit uint8) { } func addTypeBits(bv *bitVector, offset uintptr, t *abi.Type) { - if t.PtrBytes == 0 { + if !t.Pointers() { return } - switch Kind(t.Kind_ & kindMask) { + switch Kind(t.Kind_ & abi.KindMask) { case Chan, Func, Map, Pointer, Slice, String, UnsafePointer: // 1 pointer at start of representation - for bv.n < uint32(offset/uintptr(goarch.PtrSize)) { + for bv.n < uint32(offset/goarch.PtrSize) { bv.append(0) } bv.append(1) case Interface: // 2 pointers - for bv.n < uint32(offset/uintptr(goarch.PtrSize)) { + for bv.n < uint32(offset/goarch.PtrSize) { bv.append(0) } bv.append(1) @@ -2881,5 +3078,9 @@ func addTypeBits(bv *bitVector, offset uintptr, t *abi.Type) { // TypeFor returns the [Type] that represents the type argument T. func TypeFor[T any]() Type { - return TypeOf((*T)(nil)).Elem() + var v T + if t := TypeOf(v); t != nil { + return t // optimize for T being a non-interface kind + } + return TypeOf((*T)(nil)).Elem() // only for an interface kind } diff --git a/contrib/go/_std_1.22/src/reflect/value.go b/contrib/go/_std_1.23/src/reflect/value.go similarity index 97% rename from contrib/go/_std_1.22/src/reflect/value.go rename to contrib/go/_std_1.23/src/reflect/value.go index 06f22f742813..6e8e46aa594c 100644 --- a/contrib/go/_std_1.22/src/reflect/value.go +++ b/contrib/go/_std_1.23/src/reflect/value.go @@ -24,7 +24,7 @@ import ( // inappropriate to the kind of type causes a run time panic. // // The zero Value represents no value. -// Its IsValid method returns false, its Kind method returns Invalid, +// Its [Value.IsValid] method returns false, its Kind method returns [Invalid], // its String method returns "", and all other methods panic. // Most functions and methods never return an invalid value. // If one does, its documentation states the conditions explicitly. @@ -93,13 +93,16 @@ func (f flag) ro() flag { return 0 } +// typ returns the *abi.Type stored in the Value. This method is fast, +// but it doesn't always return the correct type for the Value. +// See abiType and Type, which do return the correct type. func (v Value) typ() *abi.Type { // Types are either static (for compiler-created types) or // heap-allocated but always reachable (for reflection-created // types, held in the central map). So there is no need to // escape types. noescape here help avoid unnecessary escape // of v. - return (*abi.Type)(noescape(unsafe.Pointer(v.typ_))) + return (*abi.Type)(abi.NoEscape(unsafe.Pointer(v.typ_))) } // pointer returns the underlying pointer represented by v. @@ -119,7 +122,7 @@ func (v Value) pointer() unsafe.Pointer { func packEface(v Value) any { t := v.typ() var i any - e := (*emptyInterface)(unsafe.Pointer(&i)) + e := (*abi.EmptyInterface)(unsafe.Pointer(&i)) // First, fill in the data portion of the interface. switch { case t.IfaceIndir(): @@ -129,34 +132,32 @@ func packEface(v Value) any { // Value is indirect, and so is the interface we're making. ptr := v.ptr if v.flag&flagAddr != 0 { - // TODO: pass safe boolean from valueInterface so - // we don't need to copy if safe==true? c := unsafe_New(t) typedmemmove(t, c, ptr) ptr = c } - e.word = ptr + e.Data = ptr case v.flag&flagIndir != 0: // Value is indirect, but interface is direct. We need // to load the data at v.ptr into the interface data word. - e.word = *(*unsafe.Pointer)(v.ptr) + e.Data = *(*unsafe.Pointer)(v.ptr) default: // Value is direct, and so is the interface. - e.word = v.ptr + e.Data = v.ptr } // Now, fill in the type portion. We're very careful here not // to have any operation between the e.word and e.typ assignments // that would let the garbage collector observe the partially-built // interface value. - e.typ = t + e.Type = t return i } // unpackEface converts the empty interface i to a Value. func unpackEface(i any) Value { - e := (*emptyInterface)(unsafe.Pointer(&i)) + e := (*abi.EmptyInterface)(unsafe.Pointer(&i)) // NOTE: don't read e.word until we know whether it is really a pointer or not. - t := e.typ + t := e.Type if t == nil { return Value{} } @@ -164,7 +165,7 @@ func unpackEface(i any) Value { if t.IfaceIndir() { f |= flagIndir } - return Value{t, e.word, f} + return Value{t, e.Data, f} } // A ValueError occurs when a Value method is invoked on @@ -202,22 +203,9 @@ func valueMethodName() string { return "unknown method" } -// emptyInterface is the header for an interface{} value. -type emptyInterface struct { - typ *abi.Type - word unsafe.Pointer -} - // nonEmptyInterface is the header for an interface value with methods. type nonEmptyInterface struct { - // see ../runtime/iface.go:/Itab - itab *struct { - ityp *abi.Type // static interface type - typ *abi.Type // dynamic concrete type - hash uint32 // copy of typ.hash - _ [4]byte - fun [100000]unsafe.Pointer // method table - } + itab *abi.ITab word unsafe.Pointer } @@ -639,7 +627,7 @@ func (v Value) call(op string, in []Value) []Value { } // Handle pointers passed in registers. - if !ifaceIndir(tv) { + if !tv.IfaceIndir() { // Pointer-valued data gets put directly // into v.ptr. if steps[0].kind != abiStepPointer { @@ -729,7 +717,7 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool, regs v := Value{typ, nil, flag(typ.Kind())} steps := abid.call.stepsForValue(i) if st := steps[0]; st.kind == abiStepStack { - if ifaceIndir(typ) { + if typ.IfaceIndir() { // value cannot be inlined in interface data. // Must make a copy, because f might keep a reference to it, // and we cannot let f keep a reference to the stack frame @@ -743,7 +731,7 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool, regs v.ptr = *(*unsafe.Pointer)(add(ptr, st.stkOff, "1-ptr")) } } else { - if ifaceIndir(typ) { + if typ.IfaceIndir() { // All that's left is values passed in registers that we need to // create space for the values. v.flag |= flagIndir @@ -899,8 +887,8 @@ func methodReceiver(op string, v Value, methodIndex int) (rcvrtype *abi.Type, t if iface.itab == nil { panic("reflect: " + op + " of method on nil interface value") } - rcvrtype = iface.itab.typ - fn = unsafe.Pointer(&iface.itab.fun[i]) + rcvrtype = iface.itab.Type + fn = unsafe.Pointer(&unsafe.Slice(&iface.itab.Fun[0], i+1)[i]) t = (*funcType)(unsafe.Pointer(tt.typeOff(m.Typ))) } else { rcvrtype = v.typ() @@ -929,7 +917,7 @@ func storeRcvr(v Value, p unsafe.Pointer) { // the interface data word becomes the receiver word iface := (*nonEmptyInterface)(v.ptr) *(*unsafe.Pointer)(p) = iface.word - } else if v.flag&flagIndir != 0 && !ifaceIndir(t) { + } else if v.flag&flagIndir != 0 && !t.IfaceIndir() { *(*unsafe.Pointer)(p) = *(*unsafe.Pointer)(v.ptr) } else { *(*unsafe.Pointer)(p) = v.ptr @@ -954,7 +942,7 @@ func align(x, n uintptr) uintptr { // so that the linker can make it work correctly for panic and recover. // The gc compilers know to do that for the name "reflect.callMethod". // -// ctxt is the "closure" generated by makeVethodValue. +// ctxt is the "closure" generated by makeMethodValue. // frame is a pointer to the arguments to that closure on the stack. // retValid points to a boolean which should be set when the results // section of frame is set. @@ -1247,7 +1235,7 @@ func (v Value) Elem() Value { case Pointer: ptr := v.ptr if v.flag&flagIndir != 0 { - if ifaceIndir(v.typ()) { + if v.typ().IfaceIndir() { // This is a pointer to a not-in-heap object. ptr points to a uintptr // in the heap. That uintptr is the address of a not-in-heap object. // In general, pointers to not-in-heap objects can be total junk. @@ -1522,7 +1510,6 @@ func valueInterface(v Value, safe bool) any { })(v.ptr) } - // TODO: pass safe to packEface so we don't need to copy if safe==true? return packEface(v) } @@ -1551,7 +1538,7 @@ func (v Value) InterfaceData() [2]uintptr { // a chan, func, interface, map, pointer, or slice value; if it is // not, IsNil panics. Note that IsNil is not always equivalent to a // regular comparison with nil in Go. For example, if v was created -// by calling ValueOf with an uninitialized interface variable i, +// by calling [ValueOf] with an uninitialized interface variable i, // i==nil will be true but v.IsNil will panic as v will be the zero // Value. func (v Value) IsNil() bool { @@ -1576,7 +1563,7 @@ func (v Value) IsNil() bool { // IsValid reports whether v represents a value. // It returns false if v is the zero Value. -// If IsValid returns false, all other methods except String panic. +// If [Value.IsValid] returns false, all other methods except String panic. // Most functions and methods never return an invalid Value. // If one does, its documentation states the conditions explicitly. func (v Value) IsValid() bool { @@ -1607,7 +1594,7 @@ func (v Value) IsZero() bool { // v.ptr doesn't escape, as Equal functions are compiler generated // and never escape. The escape analysis doesn't know, as it is a // function pointer call. - return typ.Equal(noescape(v.ptr), unsafe.Pointer(&zeroVal[0])) + return typ.Equal(abi.NoEscape(v.ptr), unsafe.Pointer(&zeroVal[0])) } if typ.TFlag&abi.TFlagRegularMemory != 0 { // For some types where the zero value is a value where all bits of this type are 0 @@ -1633,7 +1620,7 @@ func (v Value) IsZero() bool { // If the type is comparable, then compare directly with zero. if typ.Equal != nil && typ.Size() <= abi.ZeroValSize { // See noescape justification above. - return typ.Equal(noescape(v.ptr), unsafe.Pointer(&zeroVal[0])) + return typ.Equal(abi.NoEscape(v.ptr), unsafe.Pointer(&zeroVal[0])) } if typ.TFlag&abi.TFlagRegularMemory != 0 { // For some types where the zero value is a value where all bits of this type are 0 @@ -1746,7 +1733,7 @@ func (v Value) SetZero() { case Slice: *(*unsafeheader.Slice)(v.ptr) = unsafeheader.Slice{} case Interface: - *(*emptyInterface)(v.ptr) = emptyInterface{} + *(*abi.EmptyInterface)(v.ptr) = abi.EmptyInterface{} case Chan, Func, Map, Pointer, UnsafePointer: *(*unsafe.Pointer)(v.ptr) = nil case Array, Struct: @@ -1814,7 +1801,7 @@ func (v Value) MapIndex(key Value) Value { // of unexported fields. var e unsafe.Pointer - if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= maxValSize { + if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= abi.MapMaxElemBytes { k := *(*string)(key.ptr) e = mapaccess_faststr(v.typ(), v.pointer(), k) } else { @@ -2194,7 +2181,7 @@ func (v Value) OverflowUint(x uint64) bool { // and make an exception. // Pointer returns v's value as a uintptr. -// It panics if v's Kind is not [Chan], [Func], [Map], [Pointer], [Slice], or [UnsafePointer]. +// It panics if v's Kind is not [Chan], [Func], [Map], [Pointer], [Slice], [String], or [UnsafePointer]. // // If v's Kind is [Func], the returned pointer is an underlying // code pointer, but not necessarily enough to identify a @@ -2205,6 +2192,9 @@ func (v Value) OverflowUint(x uint64) bool { // element of the slice. If the slice is nil the returned value // is 0. If the slice is empty but non-nil the return value is non-zero. // +// If v's Kind is [String], the returned pointer is to the first +// element of the underlying bytes of string. +// // It's preferred to use uintptr(Value.UnsafePointer()) to get the equivalent result. func (v Value) Pointer() uintptr { // The compiler loses track as it converts to uintptr. Force escape. @@ -2213,7 +2203,7 @@ func (v Value) Pointer() uintptr { k := v.kind() switch k { case Pointer: - if v.typ().PtrBytes == 0 { + if !v.typ().Pointers() { val := *(*uintptr)(v.ptr) // Since it is a not-in-heap pointer, all pointers to the heap are // forbidden! See comment in Value.Elem and issue #48399. @@ -2242,9 +2232,10 @@ func (v Value) Pointer() uintptr { p = *(*unsafe.Pointer)(p) } return uintptr(p) - case Slice: return uintptr((*unsafeheader.Slice)(v.ptr).Data) + case String: + return uintptr((*unsafeheader.String)(v.ptr).Data) } panic(&ValueError{"reflect.Value.Pointer", v.kind()}) } @@ -2270,7 +2261,7 @@ func (v Value) recv(nb bool) (val Value, ok bool) { t := tt.Elem val = Value{t, nil, flag(t.Kind())} var p unsafe.Pointer - if ifaceIndir(t) { + if t.IfaceIndir() { p = unsafe_New(t) val.ptr = p val.flag |= flagIndir @@ -2450,7 +2441,7 @@ func (v Value) SetMapIndex(key, elem Value) { key.mustBeExported() tt := (*mapType)(unsafe.Pointer(v.typ())) - if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= maxValSize { + if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= abi.MapMaxElemBytes { k := *(*string)(key.ptr) if elem.typ() == nil { mapdelete_faststr(v.typ(), v.pointer(), k) @@ -2513,7 +2504,7 @@ func (v Value) SetUint(x uint64) { } // SetPointer sets the [unsafe.Pointer] value v to x. -// It panics if v's Kind is not UnsafePointer. +// It panics if v's Kind is not [UnsafePointer]. func (v Value) SetPointer(x unsafe.Pointer) { v.mustBeAssignable() v.mustBe(UnsafePointer) @@ -2694,14 +2685,26 @@ func (v Value) Type() Type { return v.typeSlow() } +//go:noinline func (v Value) typeSlow() Type { + return toRType(v.abiTypeSlow()) +} + +func (v Value) abiType() *abi.Type { + if v.flag != 0 && v.flag&flagMethod == 0 { + return v.typ() + } + return v.abiTypeSlow() +} + +func (v Value) abiTypeSlow() *abi.Type { if v.flag == 0 { panic(&ValueError{"reflect.Value.Type", Invalid}) } typ := v.typ() if v.flag&flagMethod == 0 { - return toRType(v.typ()) + return v.typ() } // Method value. @@ -2714,7 +2717,7 @@ func (v Value) typeSlow() Type { panic("reflect: internal error: invalid method index") } m := &tt.Methods[i] - return toRType(typeOffFor(typ, m.Typ)) + return typeOffFor(typ, m.Typ) } // Method on concrete type. ms := typ.ExportedMethods() @@ -2722,7 +2725,7 @@ func (v Value) typeSlow() Type { panic("reflect: internal error: invalid method index") } m := ms[i] - return toRType(typeOffFor(typ, m.Mtyp)) + return typeOffFor(typ, m.Mtyp) } // CanUint reports whether [Value.Uint] can be used without panicking. @@ -2779,7 +2782,7 @@ func (v Value) UnsafeAddr() uintptr { } // UnsafePointer returns v's value as a [unsafe.Pointer]. -// It panics if v's Kind is not [Chan], [Func], [Map], [Pointer], [Slice], or [UnsafePointer]. +// It panics if v's Kind is not [Chan], [Func], [Map], [Pointer], [Slice], [String] or [UnsafePointer]. // // If v's Kind is [Func], the returned pointer is an underlying // code pointer, but not necessarily enough to identify a @@ -2789,11 +2792,14 @@ func (v Value) UnsafeAddr() uintptr { // If v's Kind is [Slice], the returned pointer is to the first // element of the slice. If the slice is nil the returned value // is nil. If the slice is empty but non-nil the return value is non-nil. +// +// If v's Kind is [String], the returned pointer is to the first +// element of the underlying bytes of string. func (v Value) UnsafePointer() unsafe.Pointer { k := v.kind() switch k { case Pointer: - if v.typ().PtrBytes == 0 { + if !v.typ().Pointers() { // Since it is a not-in-heap pointer, all pointers to the heap are // forbidden! See comment in Value.Elem and issue #48399. if !verifyNotInHeapPtr(*(*uintptr)(v.ptr)) { @@ -2822,9 +2828,10 @@ func (v Value) UnsafePointer() unsafe.Pointer { p = *(*unsafe.Pointer)(p) } return p - case Slice: return (*unsafeheader.Slice)(v.ptr).Data + case String: + return (*unsafeheader.String)(v.ptr).Data } panic(&ValueError{"reflect.Value.UnsafePointer", v.kind()}) } @@ -3064,7 +3071,7 @@ const ( // then the case is ignored, and the field Send will also be ignored and may be either zero // or non-zero. // -// If Dir is SelectRecv, the case represents a receive operation. +// If Dir is [SelectRecv], the case represents a receive operation. // Normally Chan's underlying value must be a channel and Send must be a zero Value. // If Chan is a zero Value, then the case is ignored, but Send must still be a zero Value. // When a receive operation is selected, the received Value is returned by Select. @@ -3213,6 +3220,16 @@ func MakeSlice(typ Type, len, cap int) Value { return Value{&typ.(*rtype).t, unsafe.Pointer(&s), flagIndir | flag(Slice)} } +// SliceAt returns a [Value] representing a slice whose underlying +// data starts at p, with length and capacity equal to n. +// +// This is like [unsafe.Slice]. +func SliceAt(typ Type, p unsafe.Pointer, n int) Value { + unsafeslice(typ.common(), p, n) + s := unsafeheader.Slice{Data: p, Len: n, Cap: n} + return Value{SliceOf(typ).common(), unsafe.Pointer(&s), flagIndir | flag(Slice)} +} + // MakeChan creates a new channel with the specified type and buffer size. func MakeChan(typ Type, buffer int) Value { if typ.Kind() != Chan { @@ -3291,14 +3308,14 @@ func Zero(typ Type) Value { var zeroVal [abi.ZeroValSize]byte // New returns a Value representing a pointer to a new zero value -// for the specified type. That is, the returned Value's Type is PointerTo(typ). +// for the specified type. That is, the returned Value's Type is [PointerTo](typ). func New(typ Type) Value { if typ == nil { panic("reflect: New(nil)") } t := &typ.(*rtype).t pt := ptrTo(t) - if ifaceIndir(pt) { + if pt.IfaceIndir() { // This is a pointer to a not-in-heap type. panic("reflect: New of type that may not be allocated in heap (possibly undefined cgo C type)") } @@ -3416,7 +3433,7 @@ func (v Value) Comparable() bool { return v.Type().Comparable() case Interface: - return v.Elem().Comparable() + return v.IsNil() || v.Elem().Comparable() case Struct: for i := 0; i < v.NumField(); i++ { @@ -3871,6 +3888,16 @@ func mapaccess_faststr(t *abi.Type, m unsafe.Pointer, key string) (val unsafe.Po //go:noescape func mapassign0(t *abi.Type, m unsafe.Pointer, key, val unsafe.Pointer) +// mapassign should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/modern-go/reflect2 +// - github.com/goccy/go-json +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapassign func mapassign(t *abi.Type, m unsafe.Pointer, key, val unsafe.Pointer) { contentEscapes(key) contentEscapes(val) @@ -3980,6 +4007,9 @@ func verifyNotInHeapPtr(p uintptr) bool //go:noescape func growslice(t *abi.Type, old unsafeheader.Slice, num int) unsafeheader.Slice +//go:noescape +func unsafeslice(t *abi.Type, ptr unsafe.Pointer, len int) + // Dummy annotation marking that the value x escapes, // for use in cases where the reflect code is so clever that // the compiler cannot follow. @@ -4004,8 +4034,12 @@ func contentEscapes(x unsafe.Pointer) { } } +// This is just a wrapper around abi.NoEscape. The inlining heuristics are +// finnicky and for whatever reason treat the local call to noescape as much +// lower cost with respect to the inliner budget. (That is, replacing calls to +// noescape with abi.NoEscape will cause inlining tests to fail.) +// //go:nosplit func noescape(p unsafe.Pointer) unsafe.Pointer { - x := uintptr(p) - return unsafe.Pointer(x ^ 0) + return abi.NoEscape(p) } diff --git a/contrib/go/_std_1.22/src/reflect/visiblefields.go b/contrib/go/_std_1.23/src/reflect/visiblefields.go similarity index 100% rename from contrib/go/_std_1.22/src/reflect/visiblefields.go rename to contrib/go/_std_1.23/src/reflect/visiblefields.go diff --git a/contrib/go/_std_1.22/src/reflect/ya.make b/contrib/go/_std_1.23/src/reflect/ya.make similarity index 95% rename from contrib/go/_std_1.22/src/reflect/ya.make rename to contrib/go/_std_1.23/src/reflect/ya.make index 49ccadde8e51..814d2c6924e4 100644 --- a/contrib/go/_std_1.22/src/reflect/ya.make +++ b/contrib/go/_std_1.23/src/reflect/ya.make @@ -3,8 +3,10 @@ IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM6 SRCS( abi.go asm_arm64.s + badlinkname.go deepequal.go float32reg_generic.go + iter.go makefunc.go swapper.go type.go @@ -15,8 +17,10 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH SRCS( abi.go asm_amd64.s + badlinkname.go deepequal.go float32reg_generic.go + iter.go makefunc.go swapper.go type.go diff --git a/contrib/go/_std_1.22/src/regexp/backtrack.go b/contrib/go/_std_1.23/src/regexp/backtrack.go similarity index 100% rename from contrib/go/_std_1.22/src/regexp/backtrack.go rename to contrib/go/_std_1.23/src/regexp/backtrack.go diff --git a/contrib/go/_std_1.22/src/regexp/exec.go b/contrib/go/_std_1.23/src/regexp/exec.go similarity index 100% rename from contrib/go/_std_1.22/src/regexp/exec.go rename to contrib/go/_std_1.23/src/regexp/exec.go diff --git a/contrib/go/_std_1.22/src/regexp/onepass.go b/contrib/go/_std_1.23/src/regexp/onepass.go similarity index 97% rename from contrib/go/_std_1.22/src/regexp/onepass.go rename to contrib/go/_std_1.23/src/regexp/onepass.go index b3066e88ee43..53cbd9583941 100644 --- a/contrib/go/_std_1.22/src/regexp/onepass.go +++ b/contrib/go/_std_1.23/src/regexp/onepass.go @@ -6,7 +6,7 @@ package regexp import ( "regexp/syntax" - "sort" + "slices" "strings" "unicode" "unicode/utf8" @@ -282,13 +282,6 @@ func onePassCopy(prog *syntax.Prog) *onePassProg { return p } -// runeSlice exists to permit sorting the case-folded rune sets. -type runeSlice []rune - -func (p runeSlice) Len() int { return len(p) } -func (p runeSlice) Less(i, j int) bool { return p[i] < p[j] } -func (p runeSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } - var anyRuneNotNL = []rune{0, '\n' - 1, '\n' + 1, unicode.MaxRune} var anyRune = []rune{0, unicode.MaxRune} @@ -383,7 +376,7 @@ func makeOnePass(p *onePassProg) *onePassProg { for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) { runes = append(runes, r1, r1) } - sort.Sort(runeSlice(runes)) + slices.Sort(runes) } else { runes = append(runes, inst.Rune...) } @@ -407,7 +400,7 @@ func makeOnePass(p *onePassProg) *onePassProg { for r1 := unicode.SimpleFold(r0); r1 != r0; r1 = unicode.SimpleFold(r1) { runes = append(runes, r1, r1) } - sort.Sort(runeSlice(runes)) + slices.Sort(runes) } else { runes = append(runes, inst.Rune[0], inst.Rune[0]) } diff --git a/contrib/go/_std_1.22/src/regexp/regexp.go b/contrib/go/_std_1.23/src/regexp/regexp.go similarity index 98% rename from contrib/go/_std_1.22/src/regexp/regexp.go rename to contrib/go/_std_1.23/src/regexp/regexp.go index 462f235b1bb1..e06099425ebc 100644 --- a/contrib/go/_std_1.22/src/regexp/regexp.go +++ b/contrib/go/_std_1.23/src/regexp/regexp.go @@ -14,10 +14,7 @@ // guaranteed to run in time linear in the size of the input. // (This is a property not guaranteed by most open source // implementations of regular expressions.) For more information -// about this property, see -// -// https://swtch.com/~rsc/regexp/regexp1.html -// +// about this property, see https://swtch.com/~rsc/regexp/regexp1.html // or any book about automata theory. // // All characters are UTF-8-encoded code points. @@ -54,14 +51,13 @@ // subexpression did not match any string in the input. For 'String' versions // an empty string means either no match or an empty match. // -// There is also a subset of the methods that can be applied to text read -// from a RuneReader: -// -// MatchReader, FindReaderIndex, FindReaderSubmatchIndex +// There is also a subset of the methods that can be applied to text read from +// an [io.RuneReader]: [Regexp.MatchReader], [Regexp.FindReaderIndex], +// [Regexp.FindReaderSubmatchIndex]. // // This set may grow. Note that regular expression matches may need to // examine text beyond the text returned by a match, so the methods that -// match text from a RuneReader may read arbitrarily far into the input +// match text from an [io.RuneReader] may read arbitrarily far into the input // before returning. // // (There are a few other methods that do not match this pattern.) @@ -537,7 +533,7 @@ func (re *Regexp) Match(b []byte) bool { return re.doMatch(nil, b, "") } -// MatchReader reports whether the text returned by the RuneReader +// MatchReader reports whether the text returned by the [io.RuneReader] // contains any match of the regular expression pattern. // More complicated queries need to use [Compile] and the full [Regexp] interface. func MatchReader(pattern string, r io.RuneReader) (matched bool, err error) { @@ -1074,7 +1070,7 @@ func (re *Regexp) FindReaderSubmatchIndex(r io.RuneReader) []int { const startSize = 10 // The size at which to start a slice in the 'All' routines. -// FindAll is the 'All' version of Find; it returns a slice of all successive +// FindAll is the 'All' version of [Regexp.Find]; it returns a slice of all successive // matches of the expression, as defined by the 'All' description in the // package comment. // A return value of nil indicates no match. @@ -1244,10 +1240,9 @@ func (re *Regexp) FindAllStringSubmatchIndex(s string, n int) [][]int { // // s: ["", "b", "b", "c", "cadaaae"] // // The count determines the number of substrings to return: -// -// n > 0: at most n substrings; the last substring will be the unsplit remainder. -// n == 0: the result is nil (zero substrings) -// n < 0: all substrings +// - n > 0: at most n substrings; the last substring will be the unsplit remainder; +// - n == 0: the result is nil (zero substrings); +// - n < 0: all substrings. func (re *Regexp) Split(s string, n int) []string { if n == 0 { diff --git a/contrib/go/_std_1.22/src/regexp/syntax/compile.go b/contrib/go/_std_1.23/src/regexp/syntax/compile.go similarity index 100% rename from contrib/go/_std_1.22/src/regexp/syntax/compile.go rename to contrib/go/_std_1.23/src/regexp/syntax/compile.go diff --git a/contrib/go/_std_1.22/src/regexp/syntax/doc.go b/contrib/go/_std_1.23/src/regexp/syntax/doc.go similarity index 94% rename from contrib/go/_std_1.22/src/regexp/syntax/doc.go rename to contrib/go/_std_1.23/src/regexp/syntax/doc.go index eb8a971c7348..877f1043ddda 100644 --- a/contrib/go/_std_1.22/src/regexp/syntax/doc.go +++ b/contrib/go/_std_1.23/src/regexp/syntax/doc.go @@ -2,17 +2,17 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// DO NOT EDIT. This file is generated by mksyntaxgo from the RE2 distribution. +// Code generated by mksyntaxgo from the RE2 distribution. DO NOT EDIT. /* Package syntax parses regular expressions into parse trees and compiles parse trees into programs. Most clients of regular expressions will use the -facilities of package regexp (such as Compile and Match) instead of this package. +facilities of package [regexp] (such as [regexp.Compile] and [regexp.Match]) instead of this package. # Syntax -The regular expression syntax understood by this package when parsing with the Perl flag is as follows. -Parts of the syntax can be disabled by passing alternate flags to Parse. +The regular expression syntax understood by this package when parsing with the [Perl] flag is as follows. +Parts of the syntax can be disabled by passing alternate flags to [Parse]. Single characters: @@ -137,6 +137,6 @@ ASCII character classes: [[:word:]] word characters (== [0-9A-Za-z_]) [[:xdigit:]] hex digit (== [0-9A-Fa-f]) -Unicode character classes are those in unicode.Categories and unicode.Scripts. +Unicode character classes are those in [unicode.Categories] and [unicode.Scripts]. */ package syntax diff --git a/contrib/go/_std_1.22/src/regexp/syntax/make_perl_groups.pl b/contrib/go/_std_1.23/src/regexp/syntax/make_perl_groups.pl similarity index 83% rename from contrib/go/_std_1.22/src/regexp/syntax/make_perl_groups.pl rename to contrib/go/_std_1.23/src/regexp/syntax/make_perl_groups.pl index 80a2c9ae6b9a..fafa41cf2cfa 100755 --- a/contrib/go/_std_1.22/src/regexp/syntax/make_perl_groups.pl +++ b/contrib/go/_std_1.23/src/regexp/syntax/make_perl_groups.pl @@ -11,7 +11,10 @@ # Perl about each letter from 0-128 and write down # its answer. -@posixclasses = ( +use strict; +use warnings; + +my @posixclasses = ( "[:alnum:]", "[:alpha:]", "[:ascii:]", @@ -28,13 +31,13 @@ "[:xdigit:]", ); -@perlclasses = ( +my @perlclasses = ( "\\d", "\\s", "\\w", ); -%overrides = ( +my %overrides = ( # Prior to Perl 5.18, \s did not match vertical tab. # RE2 preserves that original behaviour. "\\s:11" => 0, @@ -70,7 +73,7 @@ ($$@) } print "}\n\n"; my $n = @ranges; - $negname = $name; + my $negname = $name; if ($negname =~ /:/) { $negname =~ s/:/:^/; } else { @@ -97,13 +100,25 @@ ($@) my $count = @entries; } +# Prepare gofmt command +my $gofmt; + +if (@ARGV > 0 && $ARGV[0] =~ /\.go$/) { + # Send the output of gofmt to the given file + open($gofmt, '|-', 'gofmt >'.$ARGV[0]) or die; +} else { + open($gofmt, '|-', 'gofmt') or die; +} + +# Redirect STDOUT to gofmt input +select $gofmt; + print <perl_groups.go +// Code generated by make_perl_groups.pl; DO NOT EDIT. package syntax diff --git a/contrib/go/_std_1.22/src/regexp/syntax/op_string.go b/contrib/go/_std_1.23/src/regexp/syntax/op_string.go similarity index 100% rename from contrib/go/_std_1.22/src/regexp/syntax/op_string.go rename to contrib/go/_std_1.23/src/regexp/syntax/op_string.go diff --git a/contrib/go/_std_1.22/src/regexp/syntax/parse.go b/contrib/go/_std_1.23/src/regexp/syntax/parse.go similarity index 99% rename from contrib/go/_std_1.22/src/regexp/syntax/parse.go rename to contrib/go/_std_1.23/src/regexp/syntax/parse.go index 6a11b53fb180..26242902f1eb 100644 --- a/contrib/go/_std_1.22/src/regexp/syntax/parse.go +++ b/contrib/go/_std_1.23/src/regexp/syntax/parse.go @@ -249,9 +249,7 @@ func (p *parser) calcSize(re *Regexp, force bool) int64 { size = int64(re.Max)*sub + int64(re.Max-re.Min) } - if size < 1 { - size = 1 - } + size = max(1, size) p.size[re] = size return size } @@ -943,9 +941,7 @@ func parse(s string, flags Flags) (_ *Regexp, err error) { p.op(opLeftParen).Cap = p.numCap t = t[1:] case '|': - if err = p.parseVerticalBar(); err != nil { - return nil, err - } + p.parseVerticalBar() t = t[1:] case ')': if err = p.parseRightParen(); err != nil { @@ -1330,7 +1326,7 @@ func matchRune(re *Regexp, r rune) bool { } // parseVerticalBar handles a | in the input. -func (p *parser) parseVerticalBar() error { +func (p *parser) parseVerticalBar() { p.concat() // The concatenation we just parsed is on top of the stack. @@ -1340,8 +1336,6 @@ func (p *parser) parseVerticalBar() error { if !p.swapVerticalBar() { p.op(opVerticalBar) } - - return nil } // mergeCharClass makes dst = dst|src. @@ -1582,6 +1576,8 @@ type charGroup struct { class []rune } +//go:generate perl make_perl_groups.pl perl_groups.go + // parsePerlClassEscape parses a leading Perl character class escape like \d // from the beginning of s. If one is present, it appends the characters to r // and returns the new slice r and the remainder of the string. diff --git a/contrib/go/_std_1.22/src/regexp/syntax/perl_groups.go b/contrib/go/_std_1.23/src/regexp/syntax/perl_groups.go similarity index 96% rename from contrib/go/_std_1.22/src/regexp/syntax/perl_groups.go rename to contrib/go/_std_1.23/src/regexp/syntax/perl_groups.go index effe4e686275..675466e5a0c3 100644 --- a/contrib/go/_std_1.22/src/regexp/syntax/perl_groups.go +++ b/contrib/go/_std_1.23/src/regexp/syntax/perl_groups.go @@ -2,8 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// GENERATED BY make_perl_groups.pl; DO NOT EDIT. -// make_perl_groups.pl >perl_groups.go +// Code generated by make_perl_groups.pl; DO NOT EDIT. package syntax diff --git a/contrib/go/_std_1.22/src/regexp/syntax/prog.go b/contrib/go/_std_1.23/src/regexp/syntax/prog.go similarity index 97% rename from contrib/go/_std_1.22/src/regexp/syntax/prog.go rename to contrib/go/_std_1.23/src/regexp/syntax/prog.go index d69ae1a12d2d..6a3705ec8f90 100644 --- a/contrib/go/_std_1.22/src/regexp/syntax/prog.go +++ b/contrib/go/_std_1.23/src/regexp/syntax/prog.go @@ -191,7 +191,7 @@ Loop: const noMatch = -1 // MatchRune reports whether the instruction matches (and consumes) r. -// It should only be called when i.Op == InstRune. +// It should only be called when i.Op == [InstRune]. func (i *Inst) MatchRune(r rune) bool { return i.MatchRunePos(r) != noMatch } @@ -200,7 +200,7 @@ func (i *Inst) MatchRune(r rune) bool { // If so, MatchRunePos returns the index of the matching rune pair // (or, when len(i.Rune) == 1, rune singleton). // If not, MatchRunePos returns -1. -// MatchRunePos should only be called when i.Op == InstRune. +// MatchRunePos should only be called when i.Op == [InstRune]. func (i *Inst) MatchRunePos(r rune) int { rune := i.Rune @@ -262,7 +262,7 @@ func (i *Inst) MatchRunePos(r rune) int { // MatchEmptyWidth reports whether the instruction matches // an empty string between the runes before and after. -// It should only be called when i.Op == InstEmptyWidth. +// It should only be called when i.Op == [InstEmptyWidth]. func (i *Inst) MatchEmptyWidth(before rune, after rune) bool { switch EmptyOp(i.Arg) { case EmptyBeginLine: diff --git a/contrib/go/_std_1.22/src/regexp/syntax/regexp.go b/contrib/go/_std_1.23/src/regexp/syntax/regexp.go similarity index 97% rename from contrib/go/_std_1.22/src/regexp/syntax/regexp.go rename to contrib/go/_std_1.23/src/regexp/syntax/regexp.go index 4fa7d0e2f833..f15d20512304 100644 --- a/contrib/go/_std_1.22/src/regexp/syntax/regexp.go +++ b/contrib/go/_std_1.23/src/regexp/syntax/regexp.go @@ -8,6 +8,7 @@ package syntax // In this package, re is always a *Regexp and r is always a rune. import ( + "slices" "strconv" "strings" "unicode" @@ -75,24 +76,10 @@ func (x *Regexp) Equal(y *Regexp) bool { } case OpLiteral, OpCharClass: - if len(x.Rune) != len(y.Rune) { - return false - } - for i, r := range x.Rune { - if r != y.Rune[i] { - return false - } - } + return slices.Equal(x.Rune, y.Rune) case OpAlternate, OpConcat: - if len(x.Sub) != len(y.Sub) { - return false - } - for i, sub := range x.Sub { - if !sub.Equal(y.Sub[i]) { - return false - } - } + return slices.EqualFunc(x.Sub, y.Sub, (*Regexp).Equal) case OpStar, OpPlus, OpQuest: if x.Flags&NonGreedy != y.Flags&NonGreedy || !x.Sub[0].Equal(y.Sub[0]) { diff --git a/contrib/go/_std_1.22/src/regexp/syntax/simplify.go b/contrib/go/_std_1.23/src/regexp/syntax/simplify.go similarity index 100% rename from contrib/go/_std_1.22/src/regexp/syntax/simplify.go rename to contrib/go/_std_1.23/src/regexp/syntax/simplify.go diff --git a/contrib/go/_std_1.22/src/regexp/syntax/ya.make b/contrib/go/_std_1.23/src/regexp/syntax/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/regexp/syntax/ya.make rename to contrib/go/_std_1.23/src/regexp/syntax/ya.make diff --git a/contrib/go/_std_1.22/src/regexp/ya.make b/contrib/go/_std_1.23/src/regexp/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/regexp/ya.make rename to contrib/go/_std_1.23/src/regexp/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/HACKING.md b/contrib/go/_std_1.23/src/runtime/HACKING.md similarity index 99% rename from contrib/go/_std_1.22/src/runtime/HACKING.md rename to contrib/go/_std_1.23/src/runtime/HACKING.md index ce0b42a354ae..e1a43ba88e3d 100644 --- a/contrib/go/_std_1.22/src/runtime/HACKING.md +++ b/contrib/go/_std_1.23/src/runtime/HACKING.md @@ -173,7 +173,7 @@ In summary, Atomics ======= -The runtime uses its own atomics package at `runtime/internal/atomic`. +The runtime uses its own atomics package at `internal/runtime/atomic`. This corresponds to `sync/atomic`, but functions have different names for historical reasons and there are a few additional functions needed by the runtime. diff --git a/contrib/go/_std_1.22/src/runtime/Makefile b/contrib/go/_std_1.23/src/runtime/Makefile similarity index 100% rename from contrib/go/_std_1.22/src/runtime/Makefile rename to contrib/go/_std_1.23/src/runtime/Makefile diff --git a/contrib/go/_std_1.22/src/runtime/alg.go b/contrib/go/_std_1.23/src/runtime/alg.go similarity index 77% rename from contrib/go/_std_1.22/src/runtime/alg.go rename to contrib/go/_std_1.23/src/runtime/alg.go index ef4f859c231e..bfb9fa1d297b 100644 --- a/contrib/go/_std_1.22/src/runtime/alg.go +++ b/contrib/go/_std_1.23/src/runtime/alg.go @@ -45,9 +45,66 @@ func memhash_varlen(p unsafe.Pointer, h uintptr) uintptr { var useAeshash bool // in asm_*.s + +// memhash should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/aacfactory/fns +// - github.com/dgraph-io/ristretto +// - github.com/minio/simdjson-go +// - github.com/nbd-wtf/go-nostr +// - github.com/outcaste-io/ristretto +// - github.com/puzpuzpuz/xsync/v2 +// - github.com/puzpuzpuz/xsync/v3 +// - github.com/segmentio/parquet-go +// - github.com/parquet-go/parquet-go +// - github.com/authzed/spicedb +// - github.com/pingcap/badger +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname memhash func memhash(p unsafe.Pointer, h, s uintptr) uintptr + +// memhash32 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/segmentio/parquet-go +// - github.com/parquet-go/parquet-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname memhash32 func memhash32(p unsafe.Pointer, h uintptr) uintptr + +// memhash64 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/segmentio/parquet-go +// - github.com/parquet-go/parquet-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname memhash64 func memhash64(p unsafe.Pointer, h uintptr) uintptr + +// strhash should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/aristanetworks/goarista +// - github.com/bytedance/sonic +// - github.com/bytedance/go-tagexpr/v2 +// - github.com/cloudwego/frugal +// - github.com/cloudwego/dynamicgo +// - github.com/v2fly/v2ray-core/v5 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname strhash func strhash(p unsafe.Pointer, h uintptr) uintptr func strhashFallback(a unsafe.Pointer, h uintptr) uintptr { @@ -100,7 +157,7 @@ func interhash(p unsafe.Pointer, h uintptr) uintptr { if tab == nil { return h } - t := tab._type + t := tab.Type if t.Equal == nil { // Check hashability here. We could do this check inside // typehash, but we want to report the topmost type in @@ -115,6 +172,16 @@ func interhash(p unsafe.Pointer, h uintptr) uintptr { } } +// nilinterhash should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/anacrolix/stm +// - github.com/aristanetworks/goarista +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname nilinterhash func nilinterhash(p unsafe.Pointer, h uintptr) uintptr { a := (*eface)(p) t := a._type @@ -142,6 +209,17 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr { // maps generated by reflect.MapOf (reflect_typehash, below). // Note: this function must match the compiler generated // functions exactly. See issue 37716. +// +// typehash should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/puzpuzpuz/xsync/v2 +// - github.com/puzpuzpuz/xsync/v3 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname typehash func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { if t.TFlag&abi.TFlagRegularMemory != 0 { // Handle ptr sizes specially, see issue 37086. @@ -154,30 +232,30 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { return memhash(p, h, t.Size_) } } - switch t.Kind_ & kindMask { - case kindFloat32: + switch t.Kind_ & abi.KindMask { + case abi.Float32: return f32hash(p, h) - case kindFloat64: + case abi.Float64: return f64hash(p, h) - case kindComplex64: + case abi.Complex64: return c64hash(p, h) - case kindComplex128: + case abi.Complex128: return c128hash(p, h) - case kindString: + case abi.String: return strhash(p, h) - case kindInterface: + case abi.Interface: i := (*interfacetype)(unsafe.Pointer(t)) if len(i.Methods) == 0 { return nilinterhash(p, h) } return interhash(p, h) - case kindArray: + case abi.Array: a := (*arraytype)(unsafe.Pointer(t)) for i := uintptr(0); i < a.Len; i++ { h = typehash(a.Elem, add(p, i*a.Elem.Size_), h) } return h - case kindStruct: + case abi.Struct: s := (*structtype)(unsafe.Pointer(t)) for _, f := range s.Fields { if f.Name.IsBlank() { @@ -204,10 +282,10 @@ func mapKeyError2(t *_type, p unsafe.Pointer) error { if t.TFlag&abi.TFlagRegularMemory != 0 { return nil } - switch t.Kind_ & kindMask { - case kindFloat32, kindFloat64, kindComplex64, kindComplex128, kindString: + switch t.Kind_ & abi.KindMask { + case abi.Float32, abi.Float64, abi.Complex64, abi.Complex128, abi.String: return nil - case kindInterface: + case abi.Interface: i := (*interfacetype)(unsafe.Pointer(t)) var t *_type var pdata *unsafe.Pointer @@ -223,7 +301,7 @@ func mapKeyError2(t *_type, p unsafe.Pointer) error { if a.tab == nil { return nil } - t = a.tab._type + t = a.tab.Type pdata = &a.data } @@ -236,7 +314,7 @@ func mapKeyError2(t *_type, p unsafe.Pointer) error { } else { return mapKeyError2(t, *pdata) } - case kindArray: + case abi.Array: a := (*arraytype)(unsafe.Pointer(t)) for i := uintptr(0); i < a.Len; i++ { if err := mapKeyError2(a.Elem, add(p, i*a.Elem.Size_)); err != nil { @@ -244,7 +322,7 @@ func mapKeyError2(t *_type, p unsafe.Pointer) error { } } return nil - case kindStruct: + case abi.Struct: s := (*structtype)(unsafe.Pointer(t)) for _, f := range s.Fields { if f.Name.IsBlank() { @@ -329,7 +407,7 @@ func ifaceeq(tab *itab, x, y unsafe.Pointer) bool { if tab == nil { return true } - t := tab._type + t := tab.Type eq := t.Equal if eq == nil { panic(errorString("comparing uncomparable type " + toRType(t).string())) @@ -342,6 +420,16 @@ func ifaceeq(tab *itab, x, y unsafe.Pointer) bool { } // Testing adapters for hash quality tests (see hash_test.go) +// +// stringHash should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/k14s/starlark-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname stringHash func stringHash(s string, seed uintptr) uintptr { return strhash(noescape(unsafe.Pointer(&s)), seed) } @@ -391,7 +479,7 @@ func alginit() { return } for i := range hashkey { - hashkey[i] = uintptr(bootstrapRand()) | 1 // make sure these numbers are odd + hashkey[i] = uintptr(bootstrapRand()) } } diff --git a/contrib/go/_std_1.22/src/runtime/arena.go b/contrib/go/_std_1.23/src/runtime/arena.go similarity index 79% rename from contrib/go/_std_1.22/src/runtime/arena.go rename to contrib/go/_std_1.23/src/runtime/arena.go index e943817ceeab..cd9a9dfae10a 100644 --- a/contrib/go/_std_1.22/src/runtime/arena.go +++ b/contrib/go/_std_1.23/src/runtime/arena.go @@ -83,10 +83,11 @@ package runtime import ( + "internal/abi" "internal/goarch" - "internal/goexperiment" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/math" + "runtime/internal/sys" "unsafe" ) @@ -110,7 +111,7 @@ func arena_newArena() unsafe.Pointer { //go:linkname arena_arena_New arena.runtime_arena_arena_New func arena_arena_New(arena unsafe.Pointer, typ any) any { t := (*_type)(efaceOf(&typ).data) - if t.Kind_&kindMask != kindPtr { + if t.Kind_&abi.KindMask != abi.Pointer { throw("arena_New: non-pointer type") } te := (*ptrtype)(unsafe.Pointer(t)).Elem @@ -144,12 +145,12 @@ func arena_heapify(s any) any { var v unsafe.Pointer e := efaceOf(&s) t := e._type - switch t.Kind_ & kindMask { - case kindString: + switch t.Kind_ & abi.KindMask { + case abi.String: v = stringStructOf((*string)(e.data)).str - case kindSlice: + case abi.Slice: v = (*slice)(e.data).array - case kindPtr: + case abi.Pointer: v = e.data default: panic("arena: Clone only supports pointers, slices, and strings") @@ -161,13 +162,13 @@ func arena_heapify(s any) any { } // Heap-allocate storage for a copy. var x any - switch t.Kind_ & kindMask { - case kindString: + switch t.Kind_ & abi.KindMask { + case abi.String: s1 := s.(string) s2, b := rawstring(len(s1)) copy(b, s1) x = s2 - case kindSlice: + case abi.Slice: len := (*slice)(e.data).len et := (*slicetype)(unsafe.Pointer(t)).Elem sl := new(slice) @@ -175,7 +176,7 @@ func arena_heapify(s any) any { xe := efaceOf(&x) xe._type = t xe.data = unsafe.Pointer(sl) - case kindPtr: + case abi.Pointer: et := (*ptrtype)(unsafe.Pointer(t)).Elem e2 := newobject(et) typedmemmove(et, e2, e.data) @@ -223,18 +224,15 @@ func init() { // userArenaChunkReserveBytes returns the amount of additional bytes to reserve for // heap metadata. func userArenaChunkReserveBytes() uintptr { - if goexperiment.AllocHeaders { - // In the allocation headers experiment, we reserve the end of the chunk for - // a pointer/scalar bitmap. We also reserve space for a dummy _type that - // refers to the bitmap. The PtrBytes field of the dummy _type indicates how - // many of those bits are valid. - return userArenaChunkBytes/goarch.PtrSize/8 + unsafe.Sizeof(_type{}) - } - return 0 + // In the allocation headers experiment, we reserve the end of the chunk for + // a pointer/scalar bitmap. We also reserve space for a dummy _type that + // refers to the bitmap. The PtrBytes field of the dummy _type indicates how + // many of those bits are valid. + return userArenaChunkBytes/goarch.PtrSize/8 + unsafe.Sizeof(_type{}) } type userArena struct { - // full is a list of full chunks that have not enough free memory left, and + // fullList is a list of full chunks that have not enough free memory left, and // that we'll free once this user arena is freed. // // Can't use mSpanList here because it's not-in-heap. @@ -295,11 +293,11 @@ func (a *userArena) slice(sl any, cap int) { } i := efaceOf(&sl) typ := i._type - if typ.Kind_&kindMask != kindPtr { + if typ.Kind_&abi.KindMask != abi.Pointer { panic("slice result of non-ptr type") } typ = (*ptrtype)(unsafe.Pointer(typ)).Elem - if typ.Kind_&kindMask != kindSlice { + if typ.Kind_&abi.KindMask != abi.Slice { panic("slice of non-ptr-to-slice type") } typ = (*slicetype)(unsafe.Pointer(typ)).Elem @@ -482,7 +480,7 @@ func (s *mspan) userArenaNextFree(typ *_type, cap int) unsafe.Pointer { mp.mallocing = 1 var ptr unsafe.Pointer - if typ.PtrBytes == 0 { + if !typ.Pointers() { // Allocate pointer-less objects from the tail end of the chunk. v, ok := s.userArenaChunkFree.takeFromBack(size, typ.Align_) if ok { @@ -504,7 +502,7 @@ func (s *mspan) userArenaNextFree(typ *_type, cap int) unsafe.Pointer { throw("arena chunk needs zeroing, but should already be zeroed") } // Set up heap bitmap and do extra accounting. - if typ.PtrBytes != 0 { + if typ.Pointers() { if cap >= 0 { userArenaHeapBitsSetSliceType(typ, cap, ptr, s) } else { @@ -548,6 +546,202 @@ func userArenaHeapBitsSetSliceType(typ *_type, n int, ptr unsafe.Pointer, s *msp } } +// userArenaHeapBitsSetType is the equivalent of heapSetType but for +// non-slice-backing-store Go values allocated in a user arena chunk. It +// sets up the type metadata for the value with type typ allocated at address ptr. +// base is the base address of the arena chunk. +func userArenaHeapBitsSetType(typ *_type, ptr unsafe.Pointer, s *mspan) { + base := s.base() + h := s.writeUserArenaHeapBits(uintptr(ptr)) + + p := typ.GCData // start of 1-bit pointer mask (or GC program) + var gcProgBits uintptr + if typ.Kind_&abi.KindGCProg != 0 { + // Expand gc program, using the object itself for storage. + gcProgBits = runGCProg(addb(p, 4), (*byte)(ptr)) + p = (*byte)(ptr) + } + nb := typ.PtrBytes / goarch.PtrSize + + for i := uintptr(0); i < nb; i += ptrBits { + k := nb - i + if k > ptrBits { + k = ptrBits + } + // N.B. On big endian platforms we byte swap the data that we + // read from GCData, which is always stored in little-endian order + // by the compiler. writeUserArenaHeapBits handles data in + // a platform-ordered way for efficiency, but stores back the + // data in little endian order, since we expose the bitmap through + // a dummy type. + h = h.write(s, readUintptr(addb(p, i/8)), k) + } + // Note: we call pad here to ensure we emit explicit 0 bits + // for the pointerless tail of the object. This ensures that + // there's only a single noMorePtrs mark for the next object + // to clear. We don't need to do this to clear stale noMorePtrs + // markers from previous uses because arena chunk pointer bitmaps + // are always fully cleared when reused. + h = h.pad(s, typ.Size_-typ.PtrBytes) + h.flush(s, uintptr(ptr), typ.Size_) + + if typ.Kind_&abi.KindGCProg != 0 { + // Zero out temporary ptrmask buffer inside object. + memclrNoHeapPointers(ptr, (gcProgBits+7)/8) + } + + // Update the PtrBytes value in the type information. After this + // point, the GC will observe the new bitmap. + s.largeType.PtrBytes = uintptr(ptr) - base + typ.PtrBytes + + // Double-check that the bitmap was written out correctly. + const doubleCheck = false + if doubleCheck { + doubleCheckHeapPointersInterior(uintptr(ptr), uintptr(ptr), typ.Size_, typ.Size_, typ, &s.largeType, s) + } +} + +type writeUserArenaHeapBits struct { + offset uintptr // offset in span that the low bit of mask represents the pointer state of. + mask uintptr // some pointer bits starting at the address addr. + valid uintptr // number of bits in buf that are valid (including low) + low uintptr // number of low-order bits to not overwrite +} + +func (s *mspan) writeUserArenaHeapBits(addr uintptr) (h writeUserArenaHeapBits) { + offset := addr - s.base() + + // We start writing bits maybe in the middle of a heap bitmap word. + // Remember how many bits into the word we started, so we can be sure + // not to overwrite the previous bits. + h.low = offset / goarch.PtrSize % ptrBits + + // round down to heap word that starts the bitmap word. + h.offset = offset - h.low*goarch.PtrSize + + // We don't have any bits yet. + h.mask = 0 + h.valid = h.low + + return +} + +// write appends the pointerness of the next valid pointer slots +// using the low valid bits of bits. 1=pointer, 0=scalar. +func (h writeUserArenaHeapBits) write(s *mspan, bits, valid uintptr) writeUserArenaHeapBits { + if h.valid+valid <= ptrBits { + // Fast path - just accumulate the bits. + h.mask |= bits << h.valid + h.valid += valid + return h + } + // Too many bits to fit in this word. Write the current word + // out and move on to the next word. + + data := h.mask | bits<> (ptrBits - h.valid) // leftover for next word + h.valid += valid - ptrBits // have h.valid+valid bits, writing ptrBits of them + + // Flush mask to the memory bitmap. + idx := h.offset / (ptrBits * goarch.PtrSize) + m := uintptr(1)< ptrBits { + h = h.write(s, 0, ptrBits) + words -= ptrBits + } + return h.write(s, 0, words) +} + +// Flush the bits that have been written, and add zeros as needed +// to cover the full object [addr, addr+size). +func (h writeUserArenaHeapBits) flush(s *mspan, addr, size uintptr) { + offset := addr - s.base() + + // zeros counts the number of bits needed to represent the object minus the + // number of bits we've already written. This is the number of 0 bits + // that need to be added. + zeros := (offset+size-h.offset)/goarch.PtrSize - h.valid + + // Add zero bits up to the bitmap word boundary + if zeros > 0 { + z := ptrBits - h.valid + if z > zeros { + z = zeros + } + h.valid += z + zeros -= z + } + + // Find word in bitmap that we're going to write. + bitmap := s.heapBits() + idx := h.offset / (ptrBits * goarch.PtrSize) + + // Write remaining bits. + if h.valid != h.low { + m := uintptr(1)<(SB),NOSPLIT,$0-0 RET -#ifndef GOARCH_amd64 -#ifndef GOARCH_arm64 -#ifndef GOARCH_mips64 -#ifndef GOARCH_mips64le -#ifndef GOARCH_ppc64 -#ifndef GOARCH_ppc64le -#ifndef GOARCH_riscv64 -#ifndef GOARCH_wasm -// stub to appease shared build mode. -TEXT ·switchToCrashStack0(SB),NOSPLIT,$0-0 - UNDEF -#endif -#endif -#endif -#endif -#endif -#endif -#endif -#endif diff --git a/contrib/go/_std_1.22/src/runtime/asm_386.s b/contrib/go/_std_1.23/src/runtime/asm_386.s similarity index 98% rename from contrib/go/_std_1.22/src/runtime/asm_386.s rename to contrib/go/_std_1.23/src/runtime/asm_386.s index 67ffc243539e..5aafe14be9a1 100644 --- a/contrib/go/_std_1.22/src/runtime/asm_386.s +++ b/contrib/go/_std_1.23/src/runtime/asm_386.s @@ -398,6 +398,35 @@ bad: CALL AX INT $3 +// func switchToCrashStack0(fn func()) +TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-4 + MOVL fn+0(FP), AX + + get_tls(CX) + MOVL g(CX), BX // BX = g + MOVL g_m(BX), DX // DX = curm + + // set g to gcrash + LEAL runtime·gcrash(SB), BX // g = &gcrash + MOVL DX, g_m(BX) // g.m = curm + MOVL BX, m_g0(DX) // curm.g0 = g + get_tls(CX) + MOVL BX, g(CX) + + // switch to crashstack + MOVL (g_stack+stack_hi)(BX), DX + SUBL $(4*8), DX + MOVL DX, SP + + // call target function + MOVL AX, DX + MOVL 0(AX), AX + CALL AX + + // should never return + CALL runtime·abort(SB) + UNDEF + /* * support for morestack */ @@ -408,11 +437,19 @@ bad: // the top of a stack (for example, morestack calling newstack // calling the scheduler calling newm calling gc), so we must // record an argument size. For that purpose, it has no arguments. -TEXT runtime·morestack(SB),NOSPLIT,$0-0 +TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 // Cannot grow scheduler stack (m->g0). get_tls(CX) - MOVL g(CX), BX - MOVL g_m(BX), BX + MOVL g(CX), DI + MOVL g_m(DI), BX + + // Set g->sched to context in f. + MOVL 0(SP), AX // f's PC + MOVL AX, (g_sched+gobuf_pc)(DI) + LEAL 4(SP), AX // f's SP + MOVL AX, (g_sched+gobuf_sp)(DI) + MOVL DX, (g_sched+gobuf_ctxt)(DI) + MOVL m_g0(BX), SI CMPL g(CX), SI JNE 3(PC) @@ -437,13 +474,6 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0 MOVL g(CX), SI MOVL SI, (m_morebuf+gobuf_g)(BX) - // Set g->sched to context in f. - MOVL 0(SP), AX // f's PC - MOVL AX, (g_sched+gobuf_pc)(SI) - LEAL 4(SP), AX // f's SP - MOVL AX, (g_sched+gobuf_sp)(SI) - MOVL DX, (g_sched+gobuf_ctxt)(SI) - // Call newstack on m->g0's stack. MOVL m_g0(BX), BP MOVL BP, g(CX) diff --git a/contrib/go/_std_1.22/src/runtime/asm_amd64.h b/contrib/go/_std_1.23/src/runtime/asm_amd64.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asm_amd64.h rename to contrib/go/_std_1.23/src/runtime/asm_amd64.h diff --git a/contrib/go/_std_1.22/src/runtime/asm_amd64.s b/contrib/go/_std_1.23/src/runtime/asm_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/runtime/asm_amd64.s rename to contrib/go/_std_1.23/src/runtime/asm_amd64.s index 1071d270c1b8..cdf9874a7f93 100644 --- a/contrib/go/_std_1.22/src/runtime/asm_amd64.s +++ b/contrib/go/_std_1.23/src/runtime/asm_amd64.s @@ -371,8 +371,9 @@ bad_cpu: // show that the program requires a certain microarchitecture level. CALL runtime·abort(SB) RET - // Prevent dead-code elimination of debugCallV2, which is + // Prevent dead-code elimination of debugCallV2 and debugPinnerV1, which are // intended to be called by debuggers. + MOVQ $runtime·debugPinnerV1(SB), AX MOVQ $runtime·debugCallV2(SB), AX RET @@ -456,6 +457,10 @@ goodm: PUSHQ AX // open up space for fn's arg spill slot MOVQ 0(DX), R12 CALL R12 // fn(g) + // The Windows native stack unwinder incorrectly classifies the next instruction + // as part of the function epilogue, producing a wrong call stack. + // Add a NOP to work around this issue. See go.dev/issue/67007. + BYTE $0x90 POPQ AX JMP runtime·badmcall2(SB) RET diff --git a/contrib/go/_std_1.22/src/runtime/asm_arm.s b/contrib/go/_std_1.23/src/runtime/asm_arm.s similarity index 98% rename from contrib/go/_std_1.22/src/runtime/asm_arm.s rename to contrib/go/_std_1.23/src/runtime/asm_arm.s index 31a0584fb5d8..4d57ec6062ce 100644 --- a/contrib/go/_std_1.22/src/runtime/asm_arm.s +++ b/contrib/go/_std_1.23/src/runtime/asm_arm.s @@ -333,6 +333,30 @@ noswitch: MOVW.P 4(R13), R14 // restore LR B (R0) +// func switchToCrashStack0(fn func()) +TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-4 + MOVW fn+0(FP), R7 // context register + MOVW g_m(g), R1 // curm + + // set g to gcrash + MOVW $runtime·gcrash(SB), R0 + BL setg<>(SB) // g = &gcrash + MOVW R1, g_m(g) // g.m = curm + MOVW g, m_g0(R1) // curm.g0 = g + + // switch to crashstack + MOVW (g_stack+stack_hi)(g), R1 + SUB $(4*8), R1 + MOVW R1, R13 + + // call target function + MOVW 0(R7), R0 + BL (R0) + + // should never return + CALL runtime·abort(SB) + UNDEF + /* * support for morestack */ @@ -349,6 +373,14 @@ TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 // Cannot grow scheduler stack (m->g0). MOVW g_m(g), R8 MOVW m_g0(R8), R4 + + // Called from f. + // Set g->sched to context in f. + MOVW R13, (g_sched+gobuf_sp)(g) + MOVW LR, (g_sched+gobuf_pc)(g) + MOVW R3, (g_sched+gobuf_lr)(g) + MOVW R7, (g_sched+gobuf_ctxt)(g) + CMP g, R4 BNE 3(PC) BL runtime·badmorestackg0(SB) @@ -361,13 +393,6 @@ TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 BL runtime·badmorestackgsignal(SB) B runtime·abort(SB) - // Called from f. - // Set g->sched to context in f. - MOVW R13, (g_sched+gobuf_sp)(g) - MOVW LR, (g_sched+gobuf_pc)(g) - MOVW R3, (g_sched+gobuf_lr)(g) - MOVW R7, (g_sched+gobuf_ctxt)(g) - // Called from f. // Set m->morebuf to f's caller. MOVW R3, (m_morebuf+gobuf_pc)(R8) // f's caller's PC diff --git a/contrib/go/_std_1.22/src/runtime/asm_arm64.s b/contrib/go/_std_1.23/src/runtime/asm_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/runtime/asm_arm64.s rename to contrib/go/_std_1.23/src/runtime/asm_arm64.s index 6d77b08a1b90..64a188058939 100644 --- a/contrib/go/_std_1.22/src/runtime/asm_arm64.s +++ b/contrib/go/_std_1.23/src/runtime/asm_arm64.s @@ -96,8 +96,9 @@ nocgo: // start this M BL runtime·mstart(SB) - // Prevent dead-code elimination of debugCallV2, which is + // Prevent dead-code elimination of debugCallV2 and debugPinnerV1, which are // intended to be called by debuggers. + MOVD $runtime·debugPinnerV1(SB), R0 MOVD $runtime·debugCallV2(SB), R0 MOVD $0, R0 diff --git a/contrib/go/_std_1.22/src/runtime/asm_loong64.s b/contrib/go/_std_1.23/src/runtime/asm_loong64.s similarity index 94% rename from contrib/go/_std_1.22/src/runtime/asm_loong64.s rename to contrib/go/_std_1.23/src/runtime/asm_loong64.s index 586bd23ed478..c16b27a0f276 100644 --- a/contrib/go/_std_1.22/src/runtime/asm_loong64.s +++ b/contrib/go/_std_1.23/src/runtime/asm_loong64.s @@ -124,12 +124,7 @@ TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0 // Fn must never return. It should gogo(&g->sched) // to keep running g. TEXT runtime·mcall(SB), NOSPLIT|NOFRAME, $0-8 -#ifdef GOEXPERIMENT_regabiargs MOVV R4, REGCTXT -#else - MOVV fn+0(FP), REGCTXT -#endif - // Save caller state in g->sched MOVV R3, (g_sched+gobuf_sp)(g) MOVV R1, (g_sched+gobuf_pc)(g) @@ -213,6 +208,29 @@ noswitch: ADDV $8, R3 JMP (R4) +// func switchToCrashStack0(fn func()) +TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-8 + MOVV fn+0(FP), REGCTXT // context register + MOVV g_m(g), R4 // curm + + // set g to gcrash + MOVV $runtime·gcrash(SB), g // g = &gcrash + JAL runtime·save_g(SB) + MOVV R4, g_m(g) // g.m = curm + MOVV g, m_g0(R4) // curm.g0 = g + + // switch to crashstack + MOVV (g_stack+stack_hi)(g), R4 + ADDV $(-4*8), R4, R3 + + // call target function + MOVV 0(REGCTXT), R6 + JAL (R6) + + // should never return + JAL runtime·abort(SB) + UNDEF + /* * support for morestack */ @@ -226,6 +244,13 @@ noswitch: // calling the scheduler calling newm calling gc), so we must // record an argument size. For that purpose, it has no arguments. TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 + // Called from f. + // Set g->sched to context in f. + MOVV R3, (g_sched+gobuf_sp)(g) + MOVV R1, (g_sched+gobuf_pc)(g) + MOVV R31, (g_sched+gobuf_lr)(g) + MOVV REGCTXT, (g_sched+gobuf_ctxt)(g) + // Cannot grow scheduler stack (m->g0). MOVV g_m(g), R7 MOVV m_g0(R7), R8 @@ -239,13 +264,6 @@ TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 JAL runtime·badmorestackgsignal(SB) JAL runtime·abort(SB) - // Called from f. - // Set g->sched to context in f. - MOVV R3, (g_sched+gobuf_sp)(g) - MOVV R1, (g_sched+gobuf_pc)(g) - MOVV R31, (g_sched+gobuf_lr)(g) - MOVV REGCTXT, (g_sched+gobuf_ctxt)(g) - // Called from f. // Set m->morebuf to f's caller. MOVV R31, (m_morebuf+gobuf_pc)(R7) // f's caller's PC @@ -670,7 +688,6 @@ TEXT ·checkASM(SB),NOSPLIT,$0-1 MOVB R19, ret+0(FP) RET -#ifdef GOEXPERIMENT_regabiargs // spillArgs stores return values from registers to a *internal/abi.RegArgs in R25. TEXT ·spillArgs(SB),NOSPLIT,$0-0 MOVV R4, (0*8)(R25) @@ -742,13 +759,6 @@ TEXT ·unspillArgs(SB),NOSPLIT,$0-0 MOVD (30*8)(R25), F14 MOVD (31*8)(R25), F15 RET -#else -TEXT ·spillArgs(SB),NOSPLIT,$0-0 - RET - -TEXT ·unspillArgs(SB),NOSPLIT,$0-0 - RET -#endif // gcWriteBarrier informs the GC about heap pointer writes. // @@ -878,155 +888,70 @@ TEXT runtime·gcWriteBarrier8(SB),NOSPLIT,$0 // then tail call to the corresponding runtime handler. // The tail call makes these stubs disappear in backtraces. TEXT runtime·panicIndex(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R20, R4 MOVV R21, R5 -#else - MOVV R20, x+0(FP) - MOVV R21, y+8(FP) -#endif JMP runtime·goPanicIndex(SB) TEXT runtime·panicIndexU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R20, R4 MOVV R21, R5 -#else - MOVV R20, x+0(FP) - MOVV R21, y+8(FP) -#endif JMP runtime·goPanicIndexU(SB) TEXT runtime·panicSliceAlen(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R21, R4 MOVV R23, R5 -#else - MOVV R21, x+0(FP) - MOVV R23, y+8(FP) -#endif JMP runtime·goPanicSliceAlen(SB) TEXT runtime·panicSliceAlenU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R21, R4 MOVV R23, R5 -#else - MOVV R21, x+0(FP) - MOVV R23, y+8(FP) -#endif JMP runtime·goPanicSliceAlenU(SB) TEXT runtime·panicSliceAcap(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R21, R4 MOVV R23, R5 -#else - MOVV R21, x+0(FP) - MOVV R23, y+8(FP) -#endif JMP runtime·goPanicSliceAcap(SB) TEXT runtime·panicSliceAcapU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R21, R4 MOVV R23, R5 -#else - MOVV R21, x+0(FP) - MOVV R23, y+8(FP) -#endif JMP runtime·goPanicSliceAcapU(SB) TEXT runtime·panicSliceB(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R20, R4 MOVV R21, R5 -#else - MOVV R20, x+0(FP) - MOVV R21, y+8(FP) -#endif JMP runtime·goPanicSliceB(SB) TEXT runtime·panicSliceBU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R20, R4 MOVV R21, R5 -#else - MOVV R20, x+0(FP) - MOVV R21, y+8(FP) -#endif JMP runtime·goPanicSliceBU(SB) TEXT runtime·panicSlice3Alen(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R23, R4 MOVV R24, R5 -#else - MOVV R23, x+0(FP) - MOVV R24, y+8(FP) -#endif JMP runtime·goPanicSlice3Alen(SB) TEXT runtime·panicSlice3AlenU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R23, R4 MOVV R24, R5 -#else - MOVV R23, x+0(FP) - MOVV R24, y+8(FP) -#endif JMP runtime·goPanicSlice3AlenU(SB) TEXT runtime·panicSlice3Acap(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R23, R4 MOVV R24, R5 -#else - MOVV R23, x+0(FP) - MOVV R24, y+8(FP) -#endif JMP runtime·goPanicSlice3Acap(SB) TEXT runtime·panicSlice3AcapU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R23, R4 MOVV R24, R5 -#else - MOVV R23, x+0(FP) - MOVV R24, y+8(FP) -#endif JMP runtime·goPanicSlice3AcapU(SB) TEXT runtime·panicSlice3B(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R21, R4 MOVV R23, R5 -#else - MOVV R21, x+0(FP) - MOVV R23, y+8(FP) -#endif JMP runtime·goPanicSlice3B(SB) TEXT runtime·panicSlice3BU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R21, R4 MOVV R23, R5 -#else - MOVV R21, x+0(FP) - MOVV R23, y+8(FP) -#endif JMP runtime·goPanicSlice3BU(SB) TEXT runtime·panicSlice3C(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R20, R4 MOVV R21, R5 -#else - MOVV R20, x+0(FP) - MOVV R21, y+8(FP) -#endif JMP runtime·goPanicSlice3C(SB) TEXT runtime·panicSlice3CU(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R20, R4 MOVV R21, R5 -#else - MOVV R20, x+0(FP) - MOVV R21, y+8(FP) -#endif JMP runtime·goPanicSlice3CU(SB) TEXT runtime·panicSliceConvert(SB),NOSPLIT,$0-16 -#ifdef GOEXPERIMENT_regabiargs MOVV R23, R4 MOVV R24, R5 -#else - MOVV R23, x+0(FP) - MOVV R24, y+8(FP) -#endif JMP runtime·goPanicSliceConvert(SB) diff --git a/contrib/go/_std_1.22/src/runtime/asm_mips64x.s b/contrib/go/_std_1.23/src/runtime/asm_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asm_mips64x.s rename to contrib/go/_std_1.23/src/runtime/asm_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/asm_mipsx.s b/contrib/go/_std_1.23/src/runtime/asm_mipsx.s similarity index 98% rename from contrib/go/_std_1.22/src/runtime/asm_mipsx.s rename to contrib/go/_std_1.23/src/runtime/asm_mipsx.s index eed4a05b38b9..ca95f22bd67f 100644 --- a/contrib/go/_std_1.22/src/runtime/asm_mipsx.s +++ b/contrib/go/_std_1.23/src/runtime/asm_mipsx.s @@ -204,6 +204,29 @@ noswitch: ADD $4, R29 JMP (R4) +// func switchToCrashStack0(fn func()) +TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-4 + MOVW fn+0(FP), REGCTXT // context register + MOVW g_m(g), R2 // curm + + // set g to gcrash + MOVW $runtime·gcrash(SB), g // g = &gcrash + CALL runtime·save_g(SB) + MOVW R2, g_m(g) // g.m = curm + MOVW g, m_g0(R2) // curm.g0 = g + + // switch to crashstack + MOVW (g_stack+stack_hi)(g), R2 + ADDU $(-4*8), R2, R29 + + // call target function + MOVW 0(REGCTXT), R25 + JAL (R25) + + // should never return + CALL runtime·abort(SB) + UNDEF + /* * support for morestack */ @@ -217,6 +240,13 @@ noswitch: // calling the scheduler calling newm calling gc), so we must // record an argument size. For that purpose, it has no arguments. TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 + // Called from f. + // Set g->sched to context in f. + MOVW R29, (g_sched+gobuf_sp)(g) + MOVW R31, (g_sched+gobuf_pc)(g) + MOVW R3, (g_sched+gobuf_lr)(g) + MOVW REGCTXT, (g_sched+gobuf_ctxt)(g) + // Cannot grow scheduler stack (m->g0). MOVW g_m(g), R7 MOVW m_g0(R7), R8 @@ -230,13 +260,6 @@ TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 JAL runtime·badmorestackgsignal(SB) JAL runtime·abort(SB) - // Called from f. - // Set g->sched to context in f. - MOVW R29, (g_sched+gobuf_sp)(g) - MOVW R31, (g_sched+gobuf_pc)(g) - MOVW R3, (g_sched+gobuf_lr)(g) - MOVW REGCTXT, (g_sched+gobuf_ctxt)(g) - // Called from f. // Set m->morebuf to f's caller. MOVW R3, (m_morebuf+gobuf_pc)(R7) // f's caller's PC diff --git a/contrib/go/_std_1.22/src/runtime/asm_ppc64x.h b/contrib/go/_std_1.23/src/runtime/asm_ppc64x.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asm_ppc64x.h rename to contrib/go/_std_1.23/src/runtime/asm_ppc64x.h diff --git a/contrib/go/_std_1.22/src/runtime/asm_ppc64x.s b/contrib/go/_std_1.23/src/runtime/asm_ppc64x.s similarity index 98% rename from contrib/go/_std_1.22/src/runtime/asm_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/asm_ppc64x.s index ff9b736430cc..2b8c4d42a3de 100644 --- a/contrib/go/_std_1.22/src/runtime/asm_ppc64x.s +++ b/contrib/go/_std_1.23/src/runtime/asm_ppc64x.s @@ -40,7 +40,7 @@ TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 // If there is a _cgo_init, call it using the gcc ABI. MOVD _cgo_init(SB), R12 - CMP R0, R12 + CMP R12, $0 BEQ nocgo #ifdef GO_PPC64X_HAS_FUNCDESC @@ -98,9 +98,10 @@ nocgo: // start this M BL runtime·mstart(SB) - // Prevent dead-code elimination of debugCallV2, which is + // Prevent dead-code elimination of debugCallV2 and debugPinnerV1, which are // intended to be called by debuggers. #ifdef GOARCH_ppc64le + MOVD $runtime·debugPinnerV1(SB), R31 MOVD $runtime·debugCallV2(SB), R31 #endif MOVD R0, 0(R0) @@ -465,7 +466,7 @@ callfn: \ #ifdef GOOS_aix \ /* AIX won't trigger a SIGSEGV if R11 = nil */ \ /* So it manually triggers it */ \ - CMP R0, R11 \ + CMP R11, $0 \ BNE 2(PC) \ MOVD R0, 0(R0) \ #endif \ @@ -563,7 +564,7 @@ TEXT gosave_systemstack_switch<>(SB),NOSPLIT|NOFRAME,$0 MOVD R0, (g_sched+gobuf_ret)(g) // Assert ctxt is zero. See func save. MOVD (g_sched+gobuf_ctxt)(g), R31 - CMP R0, R31 + CMP R31, $0 BEQ 2(PC) BL runtime·abort(SB) RET @@ -615,9 +616,9 @@ TEXT ·asmcgocall_no_g(SB),NOSPLIT,$0-16 // Call fn(arg) on the scheduler stack, // aligned appropriately for the gcc ABI. // See cgocall.go for more details. -TEXT ·asmcgocall(SB),NOSPLIT,$0-20 - MOVD fn+0(FP), R3 - MOVD arg+8(FP), R4 +TEXT ·asmcgocall(SB),NOSPLIT,$0-20 + // R3 = fn + // R4 = arg MOVD R1, R7 // save original stack pointer CMP $0, g @@ -651,8 +652,11 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20 #endif // Save room for two of our pointers, plus the callee // save area that lives on the caller stack. - SUB $(asmcgocallSaveOffset+16), R1 - RLDCR $0, R1, $~15, R1 // 16-byte alignment for gcc ABI + // Do arithmetics in R10 to hide from the assembler + // counting it as SP delta, which is irrelevant as we are + // on the system stack. + SUB $(asmcgocallSaveOffset+16), R1, R10 + RLDCR $0, R10, $~15, R1 // 16-byte alignment for gcc ABI MOVD R5, (asmcgocallSaveOffset+8)(R1) // save old g on stack MOVD (g_stack+stack_hi)(R5), R5 SUB R7, R5 @@ -689,7 +693,7 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20 MOVD R5, R1 BL runtime·save_g(SB) - MOVW R3, ret+16(FP) + // ret = R3 RET nosave: @@ -703,8 +707,8 @@ nosave: // Using this code for all "already on system stack" calls exercises it more, // which should help keep it correct. - SUB $(asmcgocallSaveOffset+8), R1 - RLDCR $0, R1, $~15, R1 // 16-byte alignment for gcc ABI + SUB $(asmcgocallSaveOffset+8), R1, R10 + RLDCR $0, R10, $~15, R1 // 16-byte alignment for gcc ABI MOVD R7, asmcgocallSaveOffset(R1) // Save original stack pointer. MOVD R3, R12 // fn @@ -724,7 +728,7 @@ nosave: #ifndef GOOS_aix MOVD 24(R1), R2 #endif - MOVW R3, ret+16(FP) + // ret = R3 RET // func cgocallback(fn, frame unsafe.Pointer, ctxt uintptr) @@ -1231,7 +1235,7 @@ TEXT runtime·debugCallV2(SB), NOSPLIT|NOFRAME, $0-0 CALL runtime·debugCallCheck(SB) MOVD 40(R1), R22 XOR R0, R0 - CMP R22, R0 + CMP R22, $0 BEQ good MOVD 48(R1), R22 MOVD $8, R20 diff --git a/contrib/go/_std_1.22/src/runtime/asm_riscv64.s b/contrib/go/_std_1.23/src/runtime/asm_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asm_riscv64.s rename to contrib/go/_std_1.23/src/runtime/asm_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/asm_s390x.s b/contrib/go/_std_1.23/src/runtime/asm_s390x.s similarity index 98% rename from contrib/go/_std_1.22/src/runtime/asm_s390x.s rename to contrib/go/_std_1.23/src/runtime/asm_s390x.s index a8e1424bf181..f2354a6d5361 100644 --- a/contrib/go/_std_1.22/src/runtime/asm_s390x.s +++ b/contrib/go/_std_1.23/src/runtime/asm_s390x.s @@ -292,6 +292,29 @@ noswitch: ADD $8, R15 BR (R3) +// func switchToCrashStack0(fn func()) +TEXT runtime·switchToCrashStack0(SB), NOSPLIT, $0-8 + MOVD fn+0(FP), R12 // context + MOVD g_m(g), R4 // curm + + // set g to gcrash + MOVD $runtime·gcrash(SB), g // g = &gcrash + BL runtime·save_g(SB) + MOVD R4, g_m(g) // g.m = curm + MOVD g, m_g0(R4) // curm.g0 = g + + // switch to crashstack + MOVD (g_stack+stack_hi)(g), R4 + ADD $(-4*8), R4, R15 + + // call target function + MOVD 0(R12), R3 // code pointer + BL (R3) + + // should never return + BL runtime·abort(SB) + UNDEF + /* * support for morestack */ @@ -305,6 +328,14 @@ noswitch: // calling the scheduler calling newm calling gc), so we must // record an argument size. For that purpose, it has no arguments. TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 + // Called from f. + // Set g->sched to context in f. + MOVD R15, (g_sched+gobuf_sp)(g) + MOVD LR, R8 + MOVD R8, (g_sched+gobuf_pc)(g) + MOVD R5, (g_sched+gobuf_lr)(g) + MOVD R12, (g_sched+gobuf_ctxt)(g) + // Cannot grow scheduler stack (m->g0). MOVD g_m(g), R7 MOVD m_g0(R7), R8 @@ -319,14 +350,6 @@ TEXT runtime·morestack(SB),NOSPLIT|NOFRAME,$0-0 BL runtime·badmorestackgsignal(SB) BL runtime·abort(SB) - // Called from f. - // Set g->sched to context in f. - MOVD R15, (g_sched+gobuf_sp)(g) - MOVD LR, R8 - MOVD R8, (g_sched+gobuf_pc)(g) - MOVD R5, (g_sched+gobuf_lr)(g) - MOVD R12, (g_sched+gobuf_ctxt)(g) - // Called from f. // Set m->morebuf to f's caller. MOVD R5, (m_morebuf+gobuf_pc)(R7) // f's caller's PC diff --git a/contrib/go/_std_1.22/src/runtime/asm_wasm.s b/contrib/go/_std_1.23/src/runtime/asm_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/asm_wasm.s rename to contrib/go/_std_1.23/src/runtime/asm_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/atomic_arm64.s b/contrib/go/_std_1.23/src/runtime/atomic_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/atomic_arm64.s rename to contrib/go/_std_1.23/src/runtime/atomic_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/atomic_loong64.s b/contrib/go/_std_1.23/src/runtime/atomic_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/atomic_loong64.s rename to contrib/go/_std_1.23/src/runtime/atomic_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/atomic_mips64x.s b/contrib/go/_std_1.23/src/runtime/atomic_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/atomic_mips64x.s rename to contrib/go/_std_1.23/src/runtime/atomic_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/atomic_mipsx.s b/contrib/go/_std_1.23/src/runtime/atomic_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/atomic_mipsx.s rename to contrib/go/_std_1.23/src/runtime/atomic_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/atomic_pointer.go b/contrib/go/_std_1.23/src/runtime/atomic_pointer.go similarity index 88% rename from contrib/go/_std_1.22/src/runtime/atomic_pointer.go rename to contrib/go/_std_1.23/src/runtime/atomic_pointer.go index b61bf0b8b2a1..df067ede77f8 100644 --- a/contrib/go/_std_1.22/src/runtime/atomic_pointer.go +++ b/contrib/go/_std_1.23/src/runtime/atomic_pointer.go @@ -6,7 +6,7 @@ package runtime import ( "internal/goexperiment" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -18,6 +18,16 @@ import ( // atomicwb performs a write barrier before an atomic pointer write. // The caller should guard the call with "if writeBarrier.enabled". // +// atomicwb should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname atomicwb //go:nosplit func atomicwb(ptr *unsafe.Pointer, new unsafe.Pointer) { slot := (*uintptr)(unsafe.Pointer(ptr)) @@ -43,7 +53,7 @@ func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) { // (like StoreNoWB but with the write barrier). // //go:nosplit -//go:linkname atomic_storePointer runtime/internal/atomic.storePointer +//go:linkname atomic_storePointer internal/runtime/atomic.storePointer func atomic_storePointer(ptr *unsafe.Pointer, new unsafe.Pointer) { atomicstorep(unsafe.Pointer(ptr), new) } @@ -52,7 +62,7 @@ func atomic_storePointer(ptr *unsafe.Pointer, new unsafe.Pointer) { // (like CompareAndSwapNoWB but with the write barrier). // //go:nosplit -//go:linkname atomic_casPointer runtime/internal/atomic.casPointer +//go:linkname atomic_casPointer internal/runtime/atomic.casPointer func atomic_casPointer(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool { if writeBarrier.enabled { atomicwb(ptr, new) diff --git a/contrib/go/_std_1.22/src/runtime/atomic_ppc64x.s b/contrib/go/_std_1.23/src/runtime/atomic_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/atomic_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/atomic_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/atomic_riscv64.s b/contrib/go/_std_1.23/src/runtime/atomic_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/atomic_riscv64.s rename to contrib/go/_std_1.23/src/runtime/atomic_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/auxv_none.go b/contrib/go/_std_1.23/src/runtime/auxv_none.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/auxv_none.go rename to contrib/go/_std_1.23/src/runtime/auxv_none.go diff --git a/contrib/go/_std_1.23/src/runtime/badlinkname.go b/contrib/go/_std_1.23/src/runtime/badlinkname.go new file mode 100644 index 000000000000..b195bebbda69 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/badlinkname.go @@ -0,0 +1,22 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import _ "unsafe" + +// These should be an internal details +// but widely used packages access them using linkname. +// Do not remove or change the type signature. +// See go.dev/issue/67401. + +// Notable members of the hall of shame include: +// - github.com/dgraph-io/ristretto +// - github.com/outcaste-io/ristretto +// - github.com/clubpay/ronykit +//go:linkname cputicks + +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor (from assembly) +//go:linkname sched diff --git a/contrib/go/_std_1.23/src/runtime/badlinkname_linux.go b/contrib/go/_std_1.23/src/runtime/badlinkname_linux.go new file mode 100644 index 000000000000..ad74528da28c --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/badlinkname_linux.go @@ -0,0 +1,17 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build amd64 || arm64 + +package runtime + +import _ "unsafe" + +// As of Go 1.22, the symbols below are found to be pulled via +// linkname in the wild. We provide a push linkname here, to +// keep them accessible with pull linknames. +// This may change in the future. Please do not depend on them +// in new code. + +//go:linkname vdsoClockgettimeSym diff --git a/contrib/go/_std_1.22/src/runtime/cgo.go b/contrib/go/_std_1.23/src/runtime/cgo.go similarity index 81% rename from contrib/go/_std_1.22/src/runtime/cgo.go rename to contrib/go/_std_1.23/src/runtime/cgo.go index 40c8c748d3e5..8285d87fcf67 100644 --- a/contrib/go/_std_1.22/src/runtime/cgo.go +++ b/contrib/go/_std_1.23/src/runtime/cgo.go @@ -35,9 +35,28 @@ var ( ) // iscgo is set to true by the runtime/cgo package +// +// iscgo should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ebitengine/purego +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname iscgo var iscgo bool // set_crosscall2 is set by the runtime/cgo package +// set_crosscall2 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ebitengine/purego +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname set_crosscall2 var set_crosscall2 func() // cgoHasExtraM is set on startup when an extra M is created for cgo. diff --git a/contrib/go/_std_1.22/src/runtime/cgo/abi_amd64.h b/contrib/go/_std_1.23/src/runtime/cgo/abi_amd64.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/abi_amd64.h rename to contrib/go/_std_1.23/src/runtime/cgo/abi_amd64.h diff --git a/contrib/go/_std_1.22/src/runtime/cgo/abi_arm64.h b/contrib/go/_std_1.23/src/runtime/cgo/abi_arm64.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/abi_arm64.h rename to contrib/go/_std_1.23/src/runtime/cgo/abi_arm64.h diff --git a/contrib/go/_std_1.22/src/runtime/cgo/abi_loong64.h b/contrib/go/_std_1.23/src/runtime/cgo/abi_loong64.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/abi_loong64.h rename to contrib/go/_std_1.23/src/runtime/cgo/abi_loong64.h diff --git a/contrib/go/_std_1.22/src/runtime/cgo/abi_ppc64x.h b/contrib/go/_std_1.23/src/runtime/cgo/abi_ppc64x.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/abi_ppc64x.h rename to contrib/go/_std_1.23/src/runtime/cgo/abi_ppc64x.h diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_386.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_386.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_386.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_amd64.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_amd64.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_arm.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_arm.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_arm64.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_arm64.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_loong64.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_loong64.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_mips64x.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_mips64x.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_mipsx.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_mipsx.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_ppc64x.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_riscv64.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_riscv64.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_s390x.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_s390x.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_s390x.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/asm_wasm.s b/contrib/go/_std_1.23/src/runtime/cgo/asm_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/asm_wasm.s rename to contrib/go/_std_1.23/src/runtime/cgo/asm_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/callbacks.go b/contrib/go/_std_1.23/src/runtime/cgo/callbacks.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/callbacks.go rename to contrib/go/_std_1.23/src/runtime/cgo/callbacks.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/callbacks_aix.go b/contrib/go/_std_1.23/src/runtime/cgo/callbacks_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/callbacks_aix.go rename to contrib/go/_std_1.23/src/runtime/cgo/callbacks_aix.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/callbacks_traceback.go b/contrib/go/_std_1.23/src/runtime/cgo/callbacks_traceback.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/callbacks_traceback.go rename to contrib/go/_std_1.23/src/runtime/cgo/callbacks_traceback.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/cgo.go b/contrib/go/_std_1.23/src/runtime/cgo/cgo.go similarity index 87% rename from contrib/go/_std_1.22/src/runtime/cgo/cgo.go rename to contrib/go/_std_1.23/src/runtime/cgo/cgo.go index 1e3a50291838..6b0acf70235d 100644 --- a/contrib/go/_std_1.22/src/runtime/cgo/cgo.go +++ b/contrib/go/_std_1.23/src/runtime/cgo/cgo.go @@ -25,7 +25,8 @@ package cgo // Use -fno-stack-protector to avoid problems locating the // proper support functions. See issues #52919, #54313, #58385. -#cgo CFLAGS: -Wall -Werror -fno-stack-protector +// Use -Wdeclaration-after-statement because some CI builds use it. +#cgo CFLAGS: -Wall -Werror -fno-stack-protector -Wdeclaration-after-statement #cgo solaris CPPFLAGS: -D_POSIX_PTHREAD_SEMANTICS diff --git a/contrib/go/_std_1.22/src/runtime/cgo/dragonfly.go b/contrib/go/_std_1.23/src/runtime/cgo/dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/dragonfly.go rename to contrib/go/_std_1.23/src/runtime/cgo/dragonfly.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/freebsd.go b/contrib/go/_std_1.23/src/runtime/cgo/freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/freebsd.go rename to contrib/go/_std_1.23/src/runtime/cgo/freebsd.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_386.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_386.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_386.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_386.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_aix_ppc64.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_aix_ppc64.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_aix_ppc64.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_aix_ppc64.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_aix_ppc64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_aix_ppc64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_aix_ppc64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_aix_ppc64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_amd64.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_amd64.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_amd64.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_amd64.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_android.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_android.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_android.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_android.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_arm.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_arm.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_arm.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_arm.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_arm64.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_arm64.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_arm64.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_arm64.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_context.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_context.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_context.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_context.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_darwin_amd64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_darwin_amd64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_darwin_amd64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_darwin_amd64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_darwin_arm64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_darwin_arm64.c similarity index 86% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_darwin_arm64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_darwin_arm64.c index f1344de8e19b..7e313767ac39 100644 --- a/contrib/go/_std_1.22/src/runtime/cgo/gcc_darwin_arm64.c +++ b/contrib/go/_std_1.23/src/runtime/cgo/gcc_darwin_arm64.c @@ -75,19 +75,27 @@ threadentry(void *v) static void init_working_dir() { - CFBundleRef bundle = CFBundleGetMainBundle(); + CFBundleRef bundle; + CFURLRef url_ref; + CFStringRef url_str_ref; + char buf[MAXPATHLEN]; + Boolean res; + int url_len; + char *dir; + CFStringRef wd_ref; + + bundle = CFBundleGetMainBundle(); if (bundle == NULL) { fprintf(stderr, "runtime/cgo: no main bundle\n"); return; } - CFURLRef url_ref = CFBundleCopyResourceURL(bundle, CFSTR("Info"), CFSTR("plist"), NULL); + url_ref = CFBundleCopyResourceURL(bundle, CFSTR("Info"), CFSTR("plist"), NULL); if (url_ref == NULL) { // No Info.plist found. It can happen on Corellium virtual devices. return; } - CFStringRef url_str_ref = CFURLGetString(url_ref); - char buf[MAXPATHLEN]; - Boolean res = CFStringGetCString(url_str_ref, buf, sizeof(buf), kCFStringEncodingUTF8); + url_str_ref = CFURLGetString(url_ref); + res = CFStringGetCString(url_str_ref, buf, sizeof(buf), kCFStringEncodingUTF8); CFRelease(url_ref); if (!res) { fprintf(stderr, "runtime/cgo: cannot get URL string\n"); @@ -96,13 +104,13 @@ init_working_dir() // url is of the form "file:///path/to/Info.plist". // strip it down to the working directory "/path/to". - int url_len = strlen(buf); + url_len = strlen(buf); if (url_len < sizeof("file://")+sizeof("/Info.plist")) { fprintf(stderr, "runtime/cgo: bad URL: %s\n", buf); return; } buf[url_len-sizeof("/Info.plist")+1] = 0; - char *dir = &buf[0] + sizeof("file://")-1; + dir = &buf[0] + sizeof("file://")-1; if (chdir(dir) != 0) { fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", dir); @@ -110,7 +118,7 @@ init_working_dir() // The test harness in go_ios_exec passes the relative working directory // in the GoExecWrapperWorkingDirectory property of the app bundle. - CFStringRef wd_ref = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("GoExecWrapperWorkingDirectory")); + wd_ref = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("GoExecWrapperWorkingDirectory")); if (wd_ref != NULL) { if (!CFStringGetCString(wd_ref, buf, sizeof(buf), kCFStringEncodingUTF8)) { fprintf(stderr, "runtime/cgo: cannot get GoExecWrapperWorkingDirectory string\n"); diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_dragonfly_amd64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_dragonfly_amd64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_dragonfly_amd64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_dragonfly_amd64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_fatalf.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_fatalf.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_fatalf.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_fatalf.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_freebsd.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_freebsd.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_freebsd.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_freebsd.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_freebsd_amd64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_freebsd_amd64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_freebsd_amd64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_freebsd_amd64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_freebsd_sigaction.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_freebsd_sigaction.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_freebsd_sigaction.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_freebsd_sigaction.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_libinit.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_libinit.c similarity index 94% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_libinit.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_libinit.c index 68f4a023795d..6cceae34c6c3 100644 --- a/contrib/go/_std_1.22/src/runtime/cgo/gcc_libinit.c +++ b/contrib/go/_std_1.23/src/runtime/cgo/gcc_libinit.c @@ -4,6 +4,13 @@ //go:build unix +// When cross-compiling with clang to linux/armv5, atomics are emulated +// and cause a compiler warning. This results in a build failure since +// cgo uses -Werror. See #65290. +#pragma GCC diagnostic ignored "-Wpragmas" +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +#pragma GCC diagnostic ignored "-Watomic-alignment" + #include #include #include @@ -41,9 +48,11 @@ x_cgo_sys_thread_create(void* (*func)(void*), void* arg) { uintptr_t _cgo_wait_runtime_init_done(void) { void (*pfn)(struct context_arg*); + int done; + pfn = __atomic_load_n(&cgo_context_function, __ATOMIC_CONSUME); - int done = 2; + done = 2; if (__atomic_load_n(&runtime_init_done, __ATOMIC_CONSUME) != done) { pthread_mutex_lock(&runtime_init_mu); while (__atomic_load_n(&runtime_init_done, __ATOMIC_CONSUME) == 0) { diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_libinit_windows.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_libinit_windows.c similarity index 98% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_libinit_windows.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_libinit_windows.c index 9a8c65ea291a..d43d12a24ae2 100644 --- a/contrib/go/_std_1.22/src/runtime/cgo/gcc_libinit_windows.c +++ b/contrib/go/_std_1.23/src/runtime/cgo/gcc_libinit_windows.c @@ -69,8 +69,10 @@ x_cgo_sys_thread_create(void (*func)(void*), void* arg) { int _cgo_is_runtime_initialized() { + int status; + EnterCriticalSection(&runtime_init_cs); - int status = runtime_init_done; + status = runtime_init_done; LeaveCriticalSection(&runtime_init_cs); return status; } diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_linux.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_linux.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_linux.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_linux.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_amd64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_amd64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_amd64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_amd64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_arm64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_arm64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_arm64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_arm64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_ppc64x.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_ppc64x.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_ppc64x.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_ppc64x.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_s390x.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_s390x.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_linux_s390x.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_linux_s390x.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_loong64.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_loong64.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_loong64.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_loong64.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_mips64x.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_mips64x.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_mips64x.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_mips64x.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_mipsx.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_mipsx.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_mipsx.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_mipsx.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_mmap.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_mmap.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_mmap.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_mmap.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_netbsd.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_netbsd.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_netbsd.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_netbsd.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_openbsd.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_openbsd.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_openbsd.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_openbsd.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_ppc64x.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_ppc64x.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_ppc64x.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_ppc64x.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_riscv64.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_riscv64.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_riscv64.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_riscv64.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_s390x.S b/contrib/go/_std_1.23/src/runtime/cgo/gcc_s390x.S similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_s390x.S rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_s390x.S diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_setenv.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_setenv.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_setenv.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_setenv.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_sigaction.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_sigaction.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_sigaction.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_sigaction.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_signal2_ios_arm64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_signal2_ios_arm64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_signal2_ios_arm64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_signal2_ios_arm64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_signal_ios_arm64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_signal_ios_arm64.c similarity index 98% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_signal_ios_arm64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_signal_ios_arm64.c index 87055e942243..3872f62de130 100644 --- a/contrib/go/_std_1.22/src/runtime/cgo/gcc_signal_ios_arm64.c +++ b/contrib/go/_std_1.23/src/runtime/cgo/gcc_signal_ios_arm64.c @@ -168,7 +168,7 @@ mach_exception_handler(void *port) { // Calls catch_exception_raise. extern boolean_t exc_server(); - mach_msg_server(exc_server, 2048, (mach_port_t)port, 0); + mach_msg_server(exc_server, 2048, (mach_port_t)(uintptr_t)port, 0); abort(); // never returns } diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_signal_ios_nolldb.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_signal_ios_nolldb.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_signal_ios_nolldb.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_signal_ios_nolldb.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_solaris_amd64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_solaris_amd64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_solaris_amd64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_solaris_amd64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_stack_darwin.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_stack_darwin.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_stack_darwin.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_stack_darwin.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_stack_unix.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_stack_unix.c similarity index 89% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_stack_unix.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_stack_unix.c index 884281dc1566..df0049a4f37a 100644 --- a/contrib/go/_std_1.22/src/runtime/cgo/gcc_stack_unix.c +++ b/contrib/go/_std_1.23/src/runtime/cgo/gcc_stack_unix.c @@ -31,8 +31,11 @@ x_cgo_getstackbound(uintptr bounds[2]) pthread_attr_get_np(pthread_self(), &attr); pthread_attr_getstack(&attr, &addr, &size); // low address #else - pthread_attr_getstacksize(&attr, &size); - addr = __builtin_frame_address(0) + 4096 - size; + // We don't know how to get the current stacks, leave it as + // 0 and the caller will use an estimate based on the current + // SP. + addr = 0; + size = 0; #endif pthread_attr_destroy(&attr); diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_stack_windows.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_stack_windows.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_stack_windows.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_stack_windows.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_traceback.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_traceback.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_traceback.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_traceback.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_util.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_util.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_util.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_util.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_windows_386.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_windows_386.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_windows_386.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_windows_386.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_windows_amd64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_windows_amd64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_windows_amd64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_windows_amd64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/gcc_windows_arm64.c b/contrib/go/_std_1.23/src/runtime/cgo/gcc_windows_arm64.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/gcc_windows_arm64.c rename to contrib/go/_std_1.23/src/runtime/cgo/gcc_windows_arm64.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/handle.go b/contrib/go/_std_1.23/src/runtime/cgo/handle.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/handle.go rename to contrib/go/_std_1.23/src/runtime/cgo/handle.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/iscgo.go b/contrib/go/_std_1.23/src/runtime/cgo/iscgo.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/iscgo.go rename to contrib/go/_std_1.23/src/runtime/cgo/iscgo.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/libcgo.h b/contrib/go/_std_1.23/src/runtime/cgo/libcgo.h similarity index 98% rename from contrib/go/_std_1.22/src/runtime/cgo/libcgo.h rename to contrib/go/_std_1.23/src/runtime/cgo/libcgo.h index 295c12c53c11..26da68fadb67 100644 --- a/contrib/go/_std_1.22/src/runtime/cgo/libcgo.h +++ b/contrib/go/_std_1.23/src/runtime/cgo/libcgo.h @@ -76,7 +76,7 @@ void x_cgo_getstackbound(uintptr bounds[2]); /* * Prints error then calls abort. For linux and android. */ -void fatalf(const char* format, ...); +void fatalf(const char* format, ...) __attribute__ ((noreturn)); /* * Registers the current mach thread port for EXC_BAD_ACCESS processing. diff --git a/contrib/go/_std_1.22/src/runtime/cgo/libcgo_unix.h b/contrib/go/_std_1.23/src/runtime/cgo/libcgo_unix.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/libcgo_unix.h rename to contrib/go/_std_1.23/src/runtime/cgo/libcgo_unix.h diff --git a/contrib/go/_std_1.22/src/runtime/cgo/libcgo_windows.h b/contrib/go/_std_1.23/src/runtime/cgo/libcgo_windows.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/libcgo_windows.h rename to contrib/go/_std_1.23/src/runtime/cgo/libcgo_windows.h diff --git a/contrib/go/_std_1.22/src/runtime/cgo/linux.go b/contrib/go/_std_1.23/src/runtime/cgo/linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/linux.go rename to contrib/go/_std_1.23/src/runtime/cgo/linux.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/linux_syscall.c b/contrib/go/_std_1.23/src/runtime/cgo/linux_syscall.c similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/linux_syscall.c rename to contrib/go/_std_1.23/src/runtime/cgo/linux_syscall.c diff --git a/contrib/go/_std_1.22/src/runtime/cgo/mmap.go b/contrib/go/_std_1.23/src/runtime/cgo/mmap.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/mmap.go rename to contrib/go/_std_1.23/src/runtime/cgo/mmap.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/netbsd.go b/contrib/go/_std_1.23/src/runtime/cgo/netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/netbsd.go rename to contrib/go/_std_1.23/src/runtime/cgo/netbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/openbsd.go b/contrib/go/_std_1.23/src/runtime/cgo/openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/openbsd.go rename to contrib/go/_std_1.23/src/runtime/cgo/openbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/setenv.go b/contrib/go/_std_1.23/src/runtime/cgo/setenv.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/setenv.go rename to contrib/go/_std_1.23/src/runtime/cgo/setenv.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/sigaction.go b/contrib/go/_std_1.23/src/runtime/cgo/sigaction.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/sigaction.go rename to contrib/go/_std_1.23/src/runtime/cgo/sigaction.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/signal_ios_arm64.go b/contrib/go/_std_1.23/src/runtime/cgo/signal_ios_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/signal_ios_arm64.go rename to contrib/go/_std_1.23/src/runtime/cgo/signal_ios_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo/signal_ios_arm64.s b/contrib/go/_std_1.23/src/runtime/cgo/signal_ios_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/signal_ios_arm64.s rename to contrib/go/_std_1.23/src/runtime/cgo/signal_ios_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/cgo/ya.make b/contrib/go/_std_1.23/src/runtime/cgo/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo/ya.make rename to contrib/go/_std_1.23/src/runtime/cgo/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/cgo_mmap.go b/contrib/go/_std_1.23/src/runtime/cgo_mmap.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo_mmap.go rename to contrib/go/_std_1.23/src/runtime/cgo_mmap.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo_ppc64x.go b/contrib/go/_std_1.23/src/runtime/cgo_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo_ppc64x.go rename to contrib/go/_std_1.23/src/runtime/cgo_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/cgo_sigaction.go b/contrib/go/_std_1.23/src/runtime/cgo_sigaction.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgo_sigaction.go rename to contrib/go/_std_1.23/src/runtime/cgo_sigaction.go diff --git a/contrib/go/_std_1.22/src/runtime/cgocall.go b/contrib/go/_std_1.23/src/runtime/cgocall.go similarity index 84% rename from contrib/go/_std_1.22/src/runtime/cgocall.go rename to contrib/go/_std_1.23/src/runtime/cgocall.go index 0d3cc40903a3..375e9d6d4a12 100644 --- a/contrib/go/_std_1.22/src/runtime/cgocall.go +++ b/contrib/go/_std_1.23/src/runtime/cgocall.go @@ -85,6 +85,7 @@ package runtime import ( + "internal/abi" "internal/goarch" "internal/goexperiment" "runtime/internal/sys" @@ -120,6 +121,15 @@ var ncgocall uint64 // number of cgo calls in total for dead m // platforms. Syscalls may have untyped arguments on the stack, so // it's not safe to grow or scan the stack. // +// cgocall should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ebitengine/purego +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cgocall //go:nosplit func cgocall(fn, arg unsafe.Pointer) int32 { if !iscgo && GOOS != "solaris" && GOOS != "illumos" && GOOS != "windows" { @@ -181,8 +191,14 @@ func cgocall(fn, arg unsafe.Pointer) int32 { osPreemptExtExit(mp) + // Save current syscall parameters, so m.winsyscall can be + // used again if callback decide to make syscall. + winsyscall := mp.winsyscall + exitsyscall() + getg().m.winsyscall = winsyscall + // Note that raceacquire must be called only after exitsyscall has // wired this M to a P. if raceenabled { @@ -215,34 +231,6 @@ func cgocall(fn, arg unsafe.Pointer) int32 { func callbackUpdateSystemStack(mp *m, sp uintptr, signal bool) { g0 := mp.g0 - inBound := sp > g0.stack.lo && sp <= g0.stack.hi - if mp.ncgo > 0 && !inBound { - // ncgo > 0 indicates that this M was in Go further up the stack - // (it called C and is now receiving a callback). - // - // !inBound indicates that we were called with SP outside the - // expected system stack bounds (C changed the stack out from - // under us between the cgocall and cgocallback?). - // - // It is not safe for the C call to change the stack out from - // under us, so throw. - - // Note that this case isn't possible for signal == true, as - // that is always passing a new M from needm. - - // Stack is bogus, but reset the bounds anyway so we can print. - hi := g0.stack.hi - lo := g0.stack.lo - g0.stack.hi = sp + 1024 - g0.stack.lo = sp - 32*1024 - g0.stackguard0 = g0.stack.lo + stackGuard - g0.stackguard1 = g0.stackguard0 - - print("M ", mp.id, " procid ", mp.procid, " runtime: cgocallback with sp=", hex(sp), " out of bounds [", hex(lo), ", ", hex(hi), "]") - print("\n") - exit(2) - } - if !mp.isextra { // We allocated the stack for standard Ms. Don't replace the // stack bounds with estimated ones when we already initialized @@ -250,26 +238,37 @@ func callbackUpdateSystemStack(mp *m, sp uintptr, signal bool) { return } - // This M does not have Go further up the stack. However, it may have - // previously called into Go, initializing the stack bounds. Between - // that call returning and now the stack may have changed (perhaps the - // C thread is running a coroutine library). We need to update the - // stack bounds for this case. + inBound := sp > g0.stack.lo && sp <= g0.stack.hi + if inBound && mp.g0StackAccurate { + // This M has called into Go before and has the stack bounds + // initialized. We have the accurate stack bounds, and the SP + // is in bounds. We expect it continues to run within the same + // bounds. + return + } + + // We don't have an accurate stack bounds (either it never calls + // into Go before, or we couldn't get the accurate bounds), or the + // current SP is not within the previous bounds (the stack may have + // changed between calls). We need to update the stack bounds. // // N.B. we need to update the stack bounds even if SP appears to - // already be in bounds. Our "bounds" may actually be estimated dummy - // bounds (below). The actual stack bounds could have shifted but still - // have partial overlap with our dummy bounds. If we failed to update - // in that case, we could find ourselves seemingly called near the - // bottom of the stack bounds, where we quickly run out of space. + // already be in bounds, if our bounds are estimated dummy bounds + // (below). We may be in a different region within the same actual + // stack bounds, but our estimates were not accurate. Or the actual + // stack bounds could have shifted but still have partial overlap with + // our dummy bounds. If we failed to update in that case, we could find + // ourselves seemingly called near the bottom of the stack bounds, where + // we quickly run out of space. // Set the stack bounds to match the current stack. If we don't // actually know how big the stack is, like we don't know how big any // scheduling stack is, but we assume there's at least 32 kB. If we // can get a more accurate stack bound from pthread, use that, provided - // it actually contains SP.. + // it actually contains SP. g0.stack.hi = sp + 1024 g0.stack.lo = sp - 32*1024 + mp.g0StackAccurate = false if !signal && _cgo_getstackbound != nil { // Don't adjust if called from the signal handler. // We are on the signal stack, not the pthread stack. @@ -280,12 +279,16 @@ func callbackUpdateSystemStack(mp *m, sp uintptr, signal bool) { asmcgocall(_cgo_getstackbound, unsafe.Pointer(&bounds)) // getstackbound is an unsupported no-op on Windows. // + // On Unix systems, if the API to get accurate stack bounds is + // not available, it returns zeros. + // // Don't use these bounds if they don't contain SP. Perhaps we // were called by something not using the standard thread // stack. if bounds[0] != 0 && sp > bounds[0] && sp <= bounds[1] { g0.stack.lo = bounds[0] g0.stack.hi = bounds[1] + mp.g0StackAccurate = true } } g0.stackguard0 = g0.stack.lo + stackGuard @@ -303,6 +306,8 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) { } sp := gp.m.g0.sched.sp // system sp saved by cgocallback. + oldStack := gp.m.g0.stack + oldAccurate := gp.m.g0StackAccurate callbackUpdateSystemStack(gp.m, sp, false) // The call from C is on gp.m's g0 stack, so we must ensure @@ -314,16 +319,22 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) { checkm := gp.m - // Save current syscall parameters, so m.syscall can be + // Save current syscall parameters, so m.winsyscall can be // used again if callback decide to make syscall. - syscall := gp.m.syscall + winsyscall := gp.m.winsyscall // entersyscall saves the caller's SP to allow the GC to trace the Go // stack. However, since we're returning to an earlier stack frame and // need to pair with the entersyscall() call made by cgocall, we must // save syscall* and let reentersyscall restore them. + // + // Note: savedsp and savedbp MUST be held in locals as an unsafe.Pointer. + // When we call into Go, the stack is free to be moved. If these locals + // aren't visible in the stack maps, they won't get updated properly, + // and will end up being stale when restored by reentersyscall. savedsp := unsafe.Pointer(gp.syscallsp) savedpc := gp.syscallpc + savedbp := unsafe.Pointer(gp.syscallbp) exitsyscall() // coming out of cgo call gp.m.incgo = false if gp.m.isextra { @@ -344,7 +355,9 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) { gp.m.incgo = true unlockOSThread() - if gp.m.isextra { + if gp.m.isextra && gp.m.ncgo == 0 { + // There are no active cgocalls above this frame (ncgo == 0), + // thus there can't be more Go frames above this frame. gp.m.isExtraInC = true } @@ -355,9 +368,15 @@ func cgocallbackg(fn, frame unsafe.Pointer, ctxt uintptr) { osPreemptExtEnter(gp.m) // going back to cgo call - reentersyscall(savedpc, uintptr(savedsp)) + reentersyscall(savedpc, uintptr(savedsp), uintptr(savedbp)) - gp.m.syscall = syscall + gp.m.winsyscall = winsyscall + + // Restore the old g0 stack bounds + gp.m.g0.stack = oldStack + gp.m.g0.stackguard0 = oldStack.lo + stackGuard + gp.m.g0.stackguard1 = gp.m.g0.stackguard0 + gp.m.g0StackAccurate = oldAccurate } func cgocallbackg1(fn, frame unsafe.Pointer, ctxt uintptr) { @@ -512,29 +531,29 @@ func cgoCheckPointer(ptr any, arg any) { t := ep._type top := true - if arg != nil && (t.Kind_&kindMask == kindPtr || t.Kind_&kindMask == kindUnsafePointer) { + if arg != nil && (t.Kind_&abi.KindMask == abi.Pointer || t.Kind_&abi.KindMask == abi.UnsafePointer) { p := ep.data - if t.Kind_&kindDirectIface == 0 { + if t.Kind_&abi.KindDirectIface == 0 { p = *(*unsafe.Pointer)(p) } if p == nil || !cgoIsGoPointer(p) { return } aep := efaceOf(&arg) - switch aep._type.Kind_ & kindMask { - case kindBool: - if t.Kind_&kindMask == kindUnsafePointer { + switch aep._type.Kind_ & abi.KindMask { + case abi.Bool: + if t.Kind_&abi.KindMask == abi.UnsafePointer { // We don't know the type of the element. break } pt := (*ptrtype)(unsafe.Pointer(t)) cgoCheckArg(pt.Elem, p, true, false, cgoCheckPointerFail) return - case kindSlice: + case abi.Slice: // Check the slice rather than the pointer. ep = aep t = ep._type - case kindArray: + case abi.Array: // Check the array rather than the pointer. // Pass top as false since we have a pointer // to the array. @@ -546,7 +565,7 @@ func cgoCheckPointer(ptr any, arg any) { } } - cgoCheckArg(t, ep.data, t.Kind_&kindDirectIface == 0, top, cgoCheckPointerFail) + cgoCheckArg(t, ep.data, t.Kind_&abi.KindDirectIface == 0, top, cgoCheckPointerFail) } const cgoCheckPointerFail = "cgo argument has Go pointer to unpinned Go pointer" @@ -558,33 +577,33 @@ const cgoResultFail = "cgo result is unpinned Go pointer or points to unpinned G // level, where Go pointers are allowed. Go pointers to pinned objects are // allowed as long as they don't reference other unpinned pointers. func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) { - if t.PtrBytes == 0 || p == nil { + if !t.Pointers() || p == nil { // If the type has no pointers there is nothing to do. return } - switch t.Kind_ & kindMask { + switch t.Kind_ & abi.KindMask { default: throw("can't happen") - case kindArray: + case abi.Array: at := (*arraytype)(unsafe.Pointer(t)) if !indir { if at.Len != 1 { throw("can't happen") } - cgoCheckArg(at.Elem, p, at.Elem.Kind_&kindDirectIface == 0, top, msg) + cgoCheckArg(at.Elem, p, at.Elem.Kind_&abi.KindDirectIface == 0, top, msg) return } for i := uintptr(0); i < at.Len; i++ { cgoCheckArg(at.Elem, p, true, top, msg) p = add(p, at.Elem.Size_) } - case kindChan, kindMap: + case abi.Chan, abi.Map: // These types contain internal pointers that will // always be allocated in the Go heap. It's never OK // to pass them to C. panic(errorString(msg)) - case kindFunc: + case abi.Func: if indir { p = *(*unsafe.Pointer)(p) } @@ -592,7 +611,7 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) { return } panic(errorString(msg)) - case kindInterface: + case abi.Interface: it := *(**_type)(p) if it == nil { return @@ -610,8 +629,8 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) { if !top && !isPinned(p) { panic(errorString(msg)) } - cgoCheckArg(it, p, it.Kind_&kindDirectIface == 0, false, msg) - case kindSlice: + cgoCheckArg(it, p, it.Kind_&abi.KindDirectIface == 0, false, msg) + case abi.Slice: st := (*slicetype)(unsafe.Pointer(t)) s := (*slice)(p) p = s.array @@ -621,14 +640,14 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) { if !top && !isPinned(p) { panic(errorString(msg)) } - if st.Elem.PtrBytes == 0 { + if !st.Elem.Pointers() { return } for i := 0; i < s.cap; i++ { cgoCheckArg(st.Elem, p, true, false, msg) p = add(p, st.Elem.Size_) } - case kindString: + case abi.String: ss := (*stringStruct)(p) if !cgoIsGoPointer(ss.str) { return @@ -636,22 +655,22 @@ func cgoCheckArg(t *_type, p unsafe.Pointer, indir, top bool, msg string) { if !top && !isPinned(ss.str) { panic(errorString(msg)) } - case kindStruct: + case abi.Struct: st := (*structtype)(unsafe.Pointer(t)) if !indir { if len(st.Fields) != 1 { throw("can't happen") } - cgoCheckArg(st.Fields[0].Typ, p, st.Fields[0].Typ.Kind_&kindDirectIface == 0, top, msg) + cgoCheckArg(st.Fields[0].Typ, p, st.Fields[0].Typ.Kind_&abi.KindDirectIface == 0, top, msg) return } for _, f := range st.Fields { - if f.Typ.PtrBytes == 0 { + if !f.Typ.Pointers() { continue } cgoCheckArg(f.Typ, add(p, f.Offset), true, top, msg) } - case kindPtr, kindUnsafePointer: + case abi.Pointer, abi.UnsafePointer: if indir { p = *(*unsafe.Pointer)(p) if p == nil { @@ -681,30 +700,15 @@ func cgoCheckUnknownPointer(p unsafe.Pointer, msg string) (base, i uintptr) { if base == 0 { return } - if goexperiment.AllocHeaders { - tp := span.typePointersOfUnchecked(base) - for { - var addr uintptr - if tp, addr = tp.next(base + span.elemsize); addr == 0 { - break - } - pp := *(*unsafe.Pointer)(unsafe.Pointer(addr)) - if cgoIsGoPointer(pp) && !isPinned(pp) { - panic(errorString(msg)) - } + tp := span.typePointersOfUnchecked(base) + for { + var addr uintptr + if tp, addr = tp.next(base + span.elemsize); addr == 0 { + break } - } else { - n := span.elemsize - hbits := heapBitsForAddr(base, n) - for { - var addr uintptr - if hbits, addr = hbits.next(); addr == 0 { - break - } - pp := *(*unsafe.Pointer)(unsafe.Pointer(addr)) - if cgoIsGoPointer(pp) && !isPinned(pp) { - panic(errorString(msg)) - } + pp := *(*unsafe.Pointer)(unsafe.Pointer(addr)) + if cgoIsGoPointer(pp) && !isPinned(pp) { + panic(errorString(msg)) } } return @@ -765,5 +769,5 @@ func cgoCheckResult(val any) { ep := efaceOf(&val) t := ep._type - cgoCheckArg(t, ep.data, t.Kind_&kindDirectIface == 0, false, cgoResultFail) + cgoCheckArg(t, ep.data, t.Kind_&abi.KindDirectIface == 0, false, cgoResultFail) } diff --git a/contrib/go/_std_1.22/src/runtime/cgocallback.go b/contrib/go/_std_1.23/src/runtime/cgocallback.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cgocallback.go rename to contrib/go/_std_1.23/src/runtime/cgocallback.go diff --git a/contrib/go/_std_1.22/src/runtime/cgocheck.go b/contrib/go/_std_1.23/src/runtime/cgocheck.go similarity index 90% rename from contrib/go/_std_1.22/src/runtime/cgocheck.go rename to contrib/go/_std_1.23/src/runtime/cgocheck.go index 3d6de4f855dc..3f2c271953db 100644 --- a/contrib/go/_std_1.22/src/runtime/cgocheck.go +++ b/contrib/go/_std_1.23/src/runtime/cgocheck.go @@ -8,8 +8,8 @@ package runtime import ( + "internal/abi" "internal/goarch" - "internal/goexperiment" "unsafe" ) @@ -90,7 +90,7 @@ func cgoCheckMemmove(typ *_type, dst, src unsafe.Pointer) { //go:nosplit //go:nowritebarrier func cgoCheckMemmove2(typ *_type, dst, src unsafe.Pointer, off, size uintptr) { - if typ.PtrBytes == 0 { + if !typ.Pointers() { return } if !cgoIsGoPointer(src) { @@ -111,7 +111,7 @@ func cgoCheckMemmove2(typ *_type, dst, src unsafe.Pointer, off, size uintptr) { //go:nosplit //go:nowritebarrier func cgoCheckSliceCopy(typ *_type, dst, src unsafe.Pointer, n int) { - if typ.PtrBytes == 0 { + if !typ.Pointers() { return } if !cgoIsGoPointer(src) { @@ -142,7 +142,7 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) { size = ptrdataSize } - if typ.Kind_&kindGCProg == 0 { + if typ.Kind_&abi.KindGCProg == 0 { cgoCheckBits(src, typ.GCData, off, size) return } @@ -177,29 +177,15 @@ func cgoCheckTypedBlock(typ *_type, src unsafe.Pointer, off, size uintptr) { } // src must be in the regular heap. - if goexperiment.AllocHeaders { - tp := s.typePointersOf(uintptr(src), size) - for { - var addr uintptr - if tp, addr = tp.next(uintptr(src) + size); addr == 0 { - break - } - v := *(*unsafe.Pointer)(unsafe.Pointer(addr)) - if cgoIsGoPointer(v) && !isPinned(v) { - throw(cgoWriteBarrierFail) - } + tp := s.typePointersOf(uintptr(src), size) + for { + var addr uintptr + if tp, addr = tp.next(uintptr(src) + size); addr == 0 { + break } - } else { - hbits := heapBitsForAddr(uintptr(src), size) - for { - var addr uintptr - if hbits, addr = hbits.next(); addr == 0 { - break - } - v := *(*unsafe.Pointer)(unsafe.Pointer(addr)) - if cgoIsGoPointer(v) && !isPinned(v) { - throw(cgoWriteBarrierFail) - } + v := *(*unsafe.Pointer)(unsafe.Pointer(addr)) + if cgoIsGoPointer(v) && !isPinned(v) { + throw(cgoWriteBarrierFail) } } } @@ -247,7 +233,7 @@ func cgoCheckBits(src unsafe.Pointer, gcbits *byte, off, size uintptr) { //go:nowritebarrier //go:systemstack func cgoCheckUsingType(typ *_type, src unsafe.Pointer, off, size uintptr) { - if typ.PtrBytes == 0 { + if !typ.Pointers() { return } @@ -259,14 +245,14 @@ func cgoCheckUsingType(typ *_type, src unsafe.Pointer, off, size uintptr) { size = ptrdataSize } - if typ.Kind_&kindGCProg == 0 { + if typ.Kind_&abi.KindGCProg == 0 { cgoCheckBits(src, typ.GCData, off, size) return } - switch typ.Kind_ & kindMask { + switch typ.Kind_ & abi.KindMask { default: throw("can't happen") - case kindArray: + case abi.Array: at := (*arraytype)(unsafe.Pointer(typ)) for i := uintptr(0); i < at.Len; i++ { if off < at.Elem.Size_ { @@ -284,7 +270,7 @@ func cgoCheckUsingType(typ *_type, src unsafe.Pointer, off, size uintptr) { } size -= checked } - case kindStruct: + case abi.Struct: st := (*structtype)(unsafe.Pointer(typ)) for _, f := range st.Fields { if off < f.Typ.Size_ { diff --git a/contrib/go/_std_1.22/src/runtime/chan.go b/contrib/go/_std_1.23/src/runtime/chan.go similarity index 90% rename from contrib/go/_std_1.22/src/runtime/chan.go rename to contrib/go/_std_1.23/src/runtime/chan.go index ff9e2a9155af..f1cd74a3fd16 100644 --- a/contrib/go/_std_1.22/src/runtime/chan.go +++ b/contrib/go/_std_1.23/src/runtime/chan.go @@ -19,7 +19,7 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/math" "unsafe" ) @@ -36,6 +36,7 @@ type hchan struct { buf unsafe.Pointer // points to an array of dataqsiz elements elemsize uint16 closed uint32 + timer *timer // timer feeding this chan elemtype *_type // element type sendx uint // send index recvx uint // receive index @@ -96,7 +97,7 @@ func makechan(t *chantype, size int) *hchan { c = (*hchan)(mallocgc(hchanSize, nil, true)) // Race detector uses this location for synchronization. c.buf = c.raceaddr() - case elem.PtrBytes == 0: + case !elem.Pointers(): // Elements do not contain pointers. // Allocate hchan and buf in one call. c = (*hchan)(mallocgc(hchanSize+mem, nil, true)) @@ -119,6 +120,16 @@ func makechan(t *chantype, size int) *hchan { } // chanbuf(c, i) is pointer to the i'th slot in the buffer. +// +// chanbuf should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/fjl/memsize +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname chanbuf func chanbuf(c *hchan, i uint) unsafe.Pointer { return add(c.buf, uintptr(i)*uintptr(c.elemsize)) } @@ -322,6 +333,35 @@ func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func(), skip int) { goready(gp, skip+1) } +// timerchandrain removes all elements in channel c's buffer. +// It reports whether any elements were removed. +// Because it is only intended for timers, it does not +// handle waiting senders at all (all timer channels +// use non-blocking sends to fill the buffer). +func timerchandrain(c *hchan) bool { + // Note: Cannot use empty(c) because we are called + // while holding c.timer.sendLock, and empty(c) will + // call c.timer.maybeRunChan, which will deadlock. + // We are emptying the channel, so we only care about + // the count, not about potentially filling it up. + if atomic.Loaduint(&c.qcount) == 0 { + return false + } + lock(&c.lock) + any := false + for c.qcount > 0 { + any = true + typedmemclr(c.elemtype, chanbuf(c, c.recvx)) + c.recvx++ + if c.recvx == c.dataqsiz { + c.recvx = 0 + } + c.qcount-- + } + unlock(&c.lock) + return any +} + // Sends and receives on unbuffered or empty-buffered channels are the // only operations where one running goroutine writes to the stack of // another running goroutine. The GC assumes that stack writes only @@ -426,12 +466,19 @@ func closechan(c *hchan) { } // empty reports whether a read from c would block (that is, the channel is -// empty). It uses a single atomic read of mutable state. +// empty). It is atomically correct and sequentially consistent at the moment +// it returns, but since the channel is unlocked, the channel may become +// non-empty immediately afterward. func empty(c *hchan) bool { // c.dataqsiz is immutable. if c.dataqsiz == 0 { return atomic.Loadp(unsafe.Pointer(&c.sendq.first)) == nil } + // c.timer is also immutable (it is set after make(chan) but before any channel operations). + // All timer channels have dataqsiz > 0. + if c.timer != nil { + c.timer.maybeRunChan() + } return atomic.Loaduint(&c.qcount) == 0 } @@ -470,6 +517,10 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) throw("unreachable") } + if c.timer != nil { + c.timer.maybeRunChan() + } + // Fast path: check for failed non-blocking operation without acquiring the lock. if !block && empty(c) { // After observing that the channel is not ready for receiving, we observe whether the @@ -570,11 +621,16 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) mysg.elem = ep mysg.waitlink = nil gp.waiting = mysg + mysg.g = gp mysg.isSelect = false mysg.c = c gp.param = nil c.recvq.enqueue(mysg) + if c.timer != nil { + blockTimerChan(c) + } + // Signal to anyone trying to shrink our stack that we're about // to park on a channel. The window between when this G's status // changes and when we set gp.activeStackChans is not safe for @@ -586,6 +642,9 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) if mysg != gp.waiting { throw("G waiting list is corrupted") } + if c.timer != nil { + unblockTimerChan(c) + } gp.waiting = nil gp.activeStackChans = false if mysg.releasetime > 0 { @@ -724,28 +783,53 @@ func reflect_chanrecv(c *hchan, nb bool, elem unsafe.Pointer) (selected bool, re return chanrecv(c, elem, !nb) } -//go:linkname reflect_chanlen reflect.chanlen -func reflect_chanlen(c *hchan) int { +func chanlen(c *hchan) int { if c == nil { return 0 } + async := debug.asynctimerchan.Load() != 0 + if c.timer != nil && async { + c.timer.maybeRunChan() + } + if c.timer != nil && !async { + // timer channels have a buffered implementation + // but present to users as unbuffered, so that we can + // undo sends without users noticing. + return 0 + } return int(c.qcount) } -//go:linkname reflectlite_chanlen internal/reflectlite.chanlen -func reflectlite_chanlen(c *hchan) int { +func chancap(c *hchan) int { if c == nil { return 0 } - return int(c.qcount) + if c.timer != nil { + async := debug.asynctimerchan.Load() != 0 + if async { + return int(c.dataqsiz) + } + // timer channels have a buffered implementation + // but present to users as unbuffered, so that we can + // undo sends without users noticing. + return 0 + } + return int(c.dataqsiz) +} + +//go:linkname reflect_chanlen reflect.chanlen +func reflect_chanlen(c *hchan) int { + return chanlen(c) +} + +//go:linkname reflectlite_chanlen internal/reflectlite.chanlen +func reflectlite_chanlen(c *hchan) int { + return chanlen(c) } //go:linkname reflect_chancap reflect.chancap func reflect_chancap(c *hchan) int { - if c == nil { - return 0 - } - return int(c.dataqsiz) + return chancap(c) } //go:linkname reflect_chanclose reflect.chanclose diff --git a/contrib/go/_std_1.22/src/runtime/checkptr.go b/contrib/go/_std_1.23/src/runtime/checkptr.go similarity index 90% rename from contrib/go/_std_1.22/src/runtime/checkptr.go rename to contrib/go/_std_1.23/src/runtime/checkptr.go index 3c49645a446f..be64ae7f0cb8 100644 --- a/contrib/go/_std_1.22/src/runtime/checkptr.go +++ b/contrib/go/_std_1.23/src/runtime/checkptr.go @@ -16,7 +16,7 @@ func checkptrAlignment(p unsafe.Pointer, elem *_type, n uintptr) { // Note that we allow unaligned pointers if the types they point to contain // no pointers themselves. See issue 37298. // TODO(mdempsky): What about fieldAlign? - if elem.PtrBytes != 0 && uintptr(p)&(uintptr(elem.Align_)-1) != 0 { + if elem.Pointers() && uintptr(p)&(uintptr(elem.Align_)-1) != 0 { throw("checkptr: misaligned pointer conversion") } @@ -76,6 +76,16 @@ func checkptrArithmetic(p unsafe.Pointer, originals []unsafe.Pointer) { // checkptrBase(p1) == checkptrBase(p2). However, the converse/inverse // is not necessarily true as allocations can have trailing padding, // and multiple variables may be packed into a single allocation. +// +// checkptrBase should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname checkptrBase func checkptrBase(p unsafe.Pointer) uintptr { // stack if gp := getg(); gp.stack.lo <= uintptr(p) && uintptr(p) < gp.stack.hi { diff --git a/contrib/go/_std_1.22/src/runtime/compiler.go b/contrib/go/_std_1.23/src/runtime/compiler.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/compiler.go rename to contrib/go/_std_1.23/src/runtime/compiler.go diff --git a/contrib/go/_std_1.22/src/runtime/complex.go b/contrib/go/_std_1.23/src/runtime/complex.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/complex.go rename to contrib/go/_std_1.23/src/runtime/complex.go diff --git a/contrib/go/_std_1.22/src/runtime/coro.go b/contrib/go/_std_1.23/src/runtime/coro.go similarity index 56% rename from contrib/go/_std_1.22/src/runtime/coro.go rename to contrib/go/_std_1.23/src/runtime/coro.go index 0d6666e343b5..d93817f92f1c 100644 --- a/contrib/go/_std_1.22/src/runtime/coro.go +++ b/contrib/go/_std_1.23/src/runtime/coro.go @@ -24,6 +24,11 @@ import "unsafe" type coro struct { gp guintptr f func(*coro) + + // State for validating thread-lock interactions. + mp *m + lockedExt uint32 // mp's external LockOSThread counter at coro creation time. + lockedInt uint32 // mp's internal lockOSThread counter at coro creation time. } //go:linkname newcoro @@ -37,19 +42,24 @@ func newcoro(f func(*coro)) *coro { pc := getcallerpc() gp := getg() systemstack(func() { + mp := gp.m start := corostart startfv := *(**funcval)(unsafe.Pointer(&start)) - gp = newproc1(startfv, gp, pc) + gp = newproc1(startfv, gp, pc, true, waitReasonCoroutine) + + // Scribble down locked thread state if needed and/or donate + // thread-lock state to the new goroutine. + if mp.lockedExt+mp.lockedInt != 0 { + c.mp = mp + c.lockedExt = mp.lockedExt + c.lockedInt = mp.lockedInt + } }) gp.coroarg = c - gp.waitreason = waitReasonCoroutine - casgstatus(gp, _Grunnable, _Gwaiting) c.gp.set(gp) return c } -//go:linkname corostart - // corostart is the entry func for a new coroutine. // It runs the coroutine user function f passed to corostart // and then calls coroexit to remove the extra concurrency. @@ -58,8 +68,8 @@ func corostart() { c := gp.coroarg gp.coroarg = nil + defer coroexit(c) c.f(c) - coroexit(c) } // coroexit is like coroswitch but closes the coro @@ -94,18 +104,48 @@ func coroswitch(c *coro) { // It is important not to add more atomic operations or other // expensive operations to the fast path. func coroswitch_m(gp *g) { - // TODO(rsc,mknyszek): add tracing support in a lightweight manner. - // Probably the tracer will need a global bool (set and cleared during STW) - // that this code can check to decide whether to use trace.gen.Load(); - // we do not want to do the atomic load all the time, especially when - // tracer use is relatively rare. c := gp.coroarg gp.coroarg = nil exit := gp.coroexit gp.coroexit = false mp := gp.m + // Track and validate thread-lock interactions. + // + // The rules with thread-lock interactions are simple. When a coro goroutine is switched to, + // the same thread must be used, and the locked state must match with the thread-lock state of + // the goroutine which called newcoro. Thread-lock state consists of the thread and the number + // of internal (cgo callback, etc.) and external (LockOSThread) thread locks. + locked := gp.lockedm != 0 + if c.mp != nil || locked { + if mp != c.mp || mp.lockedInt != c.lockedInt || mp.lockedExt != c.lockedExt { + print("coro: got thread ", unsafe.Pointer(mp), ", want ", unsafe.Pointer(c.mp), "\n") + print("coro: got lock internal ", mp.lockedInt, ", want ", c.lockedInt, "\n") + print("coro: got lock external ", mp.lockedExt, ", want ", c.lockedExt, "\n") + throw("coro: OS thread locking must match locking at coroutine creation") + } + } + + // Acquire tracer for writing for the duration of this call. + // + // There's a lot of state manipulation performed with shortcuts + // but we need to make sure the tracer can only observe the + // start and end states to maintain a coherent model and avoid + // emitting an event for every single transition. + trace := traceAcquire() + + if locked { + // Detach the goroutine from the thread; we'll attach to the goroutine we're + // switching to before returning. + gp.lockedm.set(nil) + } + if exit { + // The M might have a non-zero OS thread lock count when we get here, gdestroy + // will avoid destroying the M if the G isn't explicitly locked to it via lockedm, + // which we cleared above. It's fine to gdestroy here also, even when locked to + // the thread, because we'll be switching back to another goroutine anyway, which + // will take back its thread-lock state before returning. gdestroy(gp) gp = nil } else { @@ -148,11 +188,38 @@ func coroswitch_m(gp *g) { } } + // Check if we're switching to ourselves. This case is able to break our + // thread-lock invariants and an unbuffered channel implementation of + // coroswitch would deadlock. It's clear that this case should just not + // work. + if gnext == gp { + throw("coroswitch of a goroutine to itself") + } + + // Emit the trace event after getting gnext but before changing curg. + // GoSwitch expects that the current G is running and that we haven't + // switched yet for correct status emission. + if trace.ok() { + trace.GoSwitch(gnext, exit) + } + // Start running next, without heavy scheduling machinery. // Set mp.curg and gnext.m and then update scheduling state // directly if possible. setGNoWB(&mp.curg, gnext) setMNoWB(&gnext.m, mp) + + // Synchronize with any out-standing goroutine profile. We're about to start + // executing, and an invariant of the profiler is that we tryRecordGoroutineProfile + // whenever a goroutine is about to start running. + // + // N.B. We must do this before transitioning to _Grunning but after installing gnext + // in curg, so that we have a valid curg for allocation (tryRecordGoroutineProfile + // may allocate). + if goroutineProfile.active { + tryRecordGoroutineProfile(gnext, nil, osyield) + } + if !gnext.atomicstatus.CompareAndSwap(_Gwaiting, _Grunning) { // The CAS failed: use casgstatus, which will take care of // coordinating with the garbage collector about the state change. @@ -160,6 +227,17 @@ func coroswitch_m(gp *g) { casgstatus(gnext, _Grunnable, _Grunning) } + // Donate locked state. + if locked { + mp.lockedg.set(gnext) + gnext.lockedm.set(mp) + } + + // Release the trace locker. We've completed all the necessary transitions.. + if trace.ok() { + traceRelease(trace) + } + // Switch to gnext. Does not return. gogo(&gnext.sched) } diff --git a/contrib/go/_std_1.23/src/runtime/coverage/coverage.go b/contrib/go/_std_1.23/src/runtime/coverage/coverage.go new file mode 100644 index 000000000000..6b99a0bce6e6 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/coverage/coverage.go @@ -0,0 +1,66 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package coverage + +import ( + "internal/coverage/cfile" + "io" +) + +// initHook is invoked from main.init in programs built with -cover. +// The call is emitted by the compiler. +func initHook(istest bool) { + cfile.InitHook(istest) +} + +// WriteMetaDir writes a coverage meta-data file for the currently +// running program to the directory specified in 'dir'. An error will +// be returned if the operation can't be completed successfully (for +// example, if the currently running program was not built with +// "-cover", or if the directory does not exist). +func WriteMetaDir(dir string) error { + return cfile.WriteMetaDir(dir) +} + +// WriteMeta writes the meta-data content (the payload that would +// normally be emitted to a meta-data file) for the currently running +// program to the writer 'w'. An error will be returned if the +// operation can't be completed successfully (for example, if the +// currently running program was not built with "-cover", or if a +// write fails). +func WriteMeta(w io.Writer) error { + return cfile.WriteMeta(w) +} + +// WriteCountersDir writes a coverage counter-data file for the +// currently running program to the directory specified in 'dir'. An +// error will be returned if the operation can't be completed +// successfully (for example, if the currently running program was not +// built with "-cover", or if the directory does not exist). The +// counter data written will be a snapshot taken at the point of the +// call. +func WriteCountersDir(dir string) error { + return cfile.WriteCountersDir(dir) +} + +// WriteCounters writes coverage counter-data content for the +// currently running program to the writer 'w'. An error will be +// returned if the operation can't be completed successfully (for +// example, if the currently running program was not built with +// "-cover", or if a write fails). The counter data written will be a +// snapshot taken at the point of the invocation. +func WriteCounters(w io.Writer) error { + return cfile.WriteCounters(w) +} + +// ClearCounters clears/resets all coverage counter variables in the +// currently running program. It returns an error if the program in +// question was not built with the "-cover" flag. Clearing of coverage +// counters is also not supported for programs not using atomic +// counter mode (see more detailed comments below for the rationale +// here). +func ClearCounters() error { + return cfile.ClearCounters() +} diff --git a/contrib/go/_std_1.23/src/runtime/coverage/ya.make b/contrib/go/_std_1.23/src/runtime/coverage/ya.make new file mode 100644 index 000000000000..abbf058eef1e --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/coverage/ya.make @@ -0,0 +1,9 @@ +SUBSCRIBER(g:contrib) + +GO_LIBRARY() +IF (TRUE) + SRCS( + coverage.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/runtime/covercounter.go b/contrib/go/_std_1.23/src/runtime/covercounter.go similarity index 79% rename from contrib/go/_std_1.22/src/runtime/covercounter.go rename to contrib/go/_std_1.23/src/runtime/covercounter.go index 72842bdd94c8..6dbc882d16e7 100644 --- a/contrib/go/_std_1.22/src/runtime/covercounter.go +++ b/contrib/go/_std_1.23/src/runtime/covercounter.go @@ -9,8 +9,8 @@ import ( "unsafe" ) -//go:linkname runtime_coverage_getCovCounterList runtime/coverage.getCovCounterList -func runtime_coverage_getCovCounterList() []rtcov.CovCounterBlob { +//go:linkname coverage_getCovCounterList internal/coverage/cfile.getCovCounterList +func coverage_getCovCounterList() []rtcov.CovCounterBlob { res := []rtcov.CovCounterBlob{} u32sz := unsafe.Sizeof(uint32(0)) for datap := &firstmoduledata; datap != nil; datap = datap.next { diff --git a/contrib/go/_std_1.23/src/runtime/covermeta.go b/contrib/go/_std_1.23/src/runtime/covermeta.go new file mode 100644 index 000000000000..57a6b29e9154 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/covermeta.go @@ -0,0 +1,20 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "internal/coverage/rtcov" + "unsafe" +) + +// The compiler emits calls to runtime.addCovMeta +// but this code has moved to rtcov.AddMeta. +func addCovMeta(p unsafe.Pointer, dlen uint32, hash [16]byte, pkgpath string, pkgid int, cmode uint8, cgran uint8) uint32 { + id := rtcov.AddMeta(p, dlen, hash, pkgpath, pkgid, cmode, cgran) + if id == 0 { + throw("runtime.addCovMeta: coverage package map collision") + } + return id +} diff --git a/contrib/go/_std_1.22/src/runtime/cpuflags.go b/contrib/go/_std_1.23/src/runtime/cpuflags.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cpuflags.go rename to contrib/go/_std_1.23/src/runtime/cpuflags.go diff --git a/contrib/go/_std_1.22/src/runtime/cpuflags_amd64.go b/contrib/go/_std_1.23/src/runtime/cpuflags_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cpuflags_amd64.go rename to contrib/go/_std_1.23/src/runtime/cpuflags_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/cpuflags_arm64.go b/contrib/go/_std_1.23/src/runtime/cpuflags_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cpuflags_arm64.go rename to contrib/go/_std_1.23/src/runtime/cpuflags_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/cpuprof.go b/contrib/go/_std_1.23/src/runtime/cpuprof.go similarity index 91% rename from contrib/go/_std_1.22/src/runtime/cpuprof.go rename to contrib/go/_std_1.23/src/runtime/cpuprof.go index b2898ba9094e..100a78258a2c 100644 --- a/contrib/go/_std_1.22/src/runtime/cpuprof.go +++ b/contrib/go/_std_1.23/src/runtime/cpuprof.go @@ -209,8 +209,17 @@ func CPUProfile() []byte { panic("CPUProfile no longer available") } -//go:linkname runtime_pprof_runtime_cyclesPerSecond runtime/pprof.runtime_cyclesPerSecond -func runtime_pprof_runtime_cyclesPerSecond() int64 { +// runtime/pprof.runtime_cyclesPerSecond should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/grafana/pyroscope-go/godeltaprof +// - github.com/pyroscope-io/godeltaprof +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname pprof_cyclesPerSecond runtime/pprof.runtime_cyclesPerSecond +func pprof_cyclesPerSecond() int64 { return ticksPerSecond() } @@ -222,6 +231,14 @@ func runtime_pprof_runtime_cyclesPerSecond() int64 { // The returned data contains a whole number of records, and tags contains // exactly one entry per record. // +// runtime_pprof_readProfile should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/pyroscope-io/pyroscope +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname runtime_pprof_readProfile runtime/pprof.readProfile func runtime_pprof_readProfile() ([]uint64, []unsafe.Pointer, bool) { lock(&cpuprof.lock) diff --git a/contrib/go/_std_1.22/src/runtime/cputicks.go b/contrib/go/_std_1.23/src/runtime/cputicks.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/cputicks.go rename to contrib/go/_std_1.23/src/runtime/cputicks.go diff --git a/contrib/go/_std_1.22/src/runtime/create_file_nounix.go b/contrib/go/_std_1.23/src/runtime/create_file_nounix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/create_file_nounix.go rename to contrib/go/_std_1.23/src/runtime/create_file_nounix.go diff --git a/contrib/go/_std_1.22/src/runtime/create_file_unix.go b/contrib/go/_std_1.23/src/runtime/create_file_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/create_file_unix.go rename to contrib/go/_std_1.23/src/runtime/create_file_unix.go diff --git a/contrib/go/_std_1.22/src/runtime/debug.go b/contrib/go/_std_1.23/src/runtime/debug.go similarity index 83% rename from contrib/go/_std_1.22/src/runtime/debug.go rename to contrib/go/_std_1.23/src/runtime/debug.go index 3233ce8ee737..c477e2b9f6e4 100644 --- a/contrib/go/_std_1.22/src/runtime/debug.go +++ b/contrib/go/_std_1.23/src/runtime/debug.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -124,3 +124,22 @@ func mayMoreStackMove() { gp.stackguard0 = stackForceMove } } + +// debugPinnerKeepUnpin is used to make runtime.(*Pinner).Unpin reachable. +var debugPinnerKeepUnpin bool = false + +// debugPinnerV1 returns a new Pinner that pins itself. This function can be +// used by debuggers to easily obtain a Pinner that will not be garbage +// collected (or moved in memory) even if no references to it exist in the +// target program. This pinner in turn can be used to extend this property +// to other objects, which debuggers can use to simplify the evaluation of +// expressions involving multiple call injections. +func debugPinnerV1() *Pinner { + p := new(Pinner) + p.Pin(unsafe.Pointer(p)) + if debugPinnerKeepUnpin { + // Make Unpin reachable. + p.Unpin() + } + return p +} diff --git a/contrib/go/_std_1.22/src/runtime/debug/debug.s b/contrib/go/_std_1.23/src/runtime/debug/debug.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/debug/debug.s rename to contrib/go/_std_1.23/src/runtime/debug/debug.s diff --git a/contrib/go/_std_1.22/src/runtime/debug/garbage.go b/contrib/go/_std_1.23/src/runtime/debug/garbage.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/debug/garbage.go rename to contrib/go/_std_1.23/src/runtime/debug/garbage.go index cb3248d64d4a..ec74ba0165a0 100644 --- a/contrib/go/_std_1.22/src/runtime/debug/garbage.go +++ b/contrib/go/_std_1.23/src/runtime/debug/garbage.go @@ -6,7 +6,7 @@ package debug import ( "runtime" - "sort" + "slices" "time" ) @@ -63,15 +63,13 @@ func ReadGCStats(stats *GCStats) { if len(stats.PauseQuantiles) > 0 { if n == 0 { - for i := range stats.PauseQuantiles { - stats.PauseQuantiles[i] = 0 - } + clear(stats.PauseQuantiles) } else { // There's room for a second copy of the data in stats.Pause. // See the allocation at the top of the function. sorted := stats.Pause[n : n+n] copy(sorted, stats.Pause) - sort.Slice(sorted, func(i, j int) bool { return sorted[i] < sorted[j] }) + slices.Sort(sorted) nq := len(stats.PauseQuantiles) - 1 for i := 0; i < nq; i++ { stats.PauseQuantiles[i] = sorted[len(sorted)*i/nq] diff --git a/contrib/go/_std_1.22/src/runtime/debug/mod.go b/contrib/go/_std_1.23/src/runtime/debug/mod.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/debug/mod.go rename to contrib/go/_std_1.23/src/runtime/debug/mod.go diff --git a/contrib/go/_std_1.23/src/runtime/debug/stack.go b/contrib/go/_std_1.23/src/runtime/debug/stack.go new file mode 100644 index 000000000000..d7a860b7dc94 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/debug/stack.go @@ -0,0 +1,93 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package debug contains facilities for programs to debug themselves while +// they are running. +package debug + +import ( + "internal/poll" + "os" + "runtime" + _ "unsafe" // for linkname +) + +// PrintStack prints to standard error the stack trace returned by runtime.Stack. +func PrintStack() { + os.Stderr.Write(Stack()) +} + +// Stack returns a formatted stack trace of the goroutine that calls it. +// It calls [runtime.Stack] with a large enough buffer to capture the entire trace. +func Stack() []byte { + buf := make([]byte, 1024) + for { + n := runtime.Stack(buf, false) + if n < len(buf) { + return buf[:n] + } + buf = make([]byte, 2*len(buf)) + } +} + +// CrashOptions provides options that control the formatting of the +// fatal crash message. +type CrashOptions struct { + /* for future expansion */ +} + +// SetCrashOutput configures a single additional file where unhandled +// panics and other fatal errors are printed, in addition to standard error. +// There is only one additional file: calling SetCrashOutput again overrides +// any earlier call. +// SetCrashOutput duplicates f's file descriptor, so the caller may safely +// close f as soon as SetCrashOutput returns. +// To disable this additional crash output, call SetCrashOutput(nil). +// If called concurrently with a crash, some in-progress output may be written +// to the old file even after an overriding SetCrashOutput returns. +func SetCrashOutput(f *os.File, opts CrashOptions) error { + fd := ^uintptr(0) + if f != nil { + // The runtime will write to this file descriptor from + // low-level routines during a panic, possibly without + // a G, so we must call f.Fd() eagerly. This creates a + // danger that that the file descriptor is no longer + // valid at the time of the write, because the caller + // (incorrectly) called f.Close() and the kernel + // reissued the fd in a later call to open(2), leading + // to crashes being written to the wrong file. + // + // So, we duplicate the fd to obtain a private one + // that cannot be closed by the user. + // This also alleviates us from concerns about the + // lifetime and finalization of f. + // (DupCloseOnExec returns an fd, not a *File, so + // there is no finalizer, and we are responsible for + // closing it.) + // + // The new fd must be close-on-exec, otherwise if the + // crash monitor is a child process, it may inherit + // it, so it will never see EOF from the pipe even + // when this process crashes. + // + // A side effect of Fd() is that it calls SetBlocking, + // which is important so that writes of a crash report + // to a full pipe buffer don't get lost. + fd2, _, err := poll.DupCloseOnExec(int(f.Fd())) + if err != nil { + return err + } + runtime.KeepAlive(f) // prevent finalization before dup + fd = uintptr(fd2) + } + if prev := runtime_setCrashFD(fd); prev != ^uintptr(0) { + // We use NewFile+Close because it is portable + // unlike syscall.Close, whose parameter type varies. + os.NewFile(prev, "").Close() // ignore error + } + return nil +} + +//go:linkname runtime_setCrashFD runtime.setCrashFD +func runtime_setCrashFD(uintptr) uintptr diff --git a/contrib/go/_std_1.22/src/runtime/debug/stubs.go b/contrib/go/_std_1.23/src/runtime/debug/stubs.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/debug/stubs.go rename to contrib/go/_std_1.23/src/runtime/debug/stubs.go diff --git a/contrib/go/_std_1.22/src/runtime/debug/ya.make b/contrib/go/_std_1.23/src/runtime/debug/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/debug/ya.make rename to contrib/go/_std_1.23/src/runtime/debug/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/debugcall.go b/contrib/go/_std_1.23/src/runtime/debugcall.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/debugcall.go rename to contrib/go/_std_1.23/src/runtime/debugcall.go index 5dd83063ff9c..fee4116aa5e7 100644 --- a/contrib/go/_std_1.22/src/runtime/debugcall.go +++ b/contrib/go/_std_1.23/src/runtime/debugcall.go @@ -124,7 +124,7 @@ func debugCallWrap(dispatch uintptr) { // closure and start the goroutine with that closure, but the compiler disallows // implicit closure allocation in the runtime. fn := debugCallWrap1 - newg := newproc1(*(**funcval)(unsafe.Pointer(&fn)), gp, callerpc) + newg := newproc1(*(**funcval)(unsafe.Pointer(&fn)), gp, callerpc, false, waitReasonZero) args := &debugCallWrapArgs{ dispatch: dispatch, callingG: gp, @@ -167,9 +167,14 @@ func debugCallWrap(dispatch uintptr) { // Park the calling goroutine. trace := traceAcquire() - casGToWaiting(gp, _Grunning, waitReasonDebugCall) if trace.ok() { + // Trace the event before the transition. It may take a + // stack trace, but we won't own the stack after the + // transition anymore. trace.GoPark(traceBlockDebugCall, 1) + } + casGToWaiting(gp, _Grunning, waitReasonDebugCall) + if trace.ok() { traceRelease(trace) } dropg() @@ -228,9 +233,14 @@ func debugCallWrap1() { // the scheduler will schedule us again and we'll // finish exiting. trace := traceAcquire() - casgstatus(gp, _Grunning, _Grunnable) if trace.ok() { + // Trace the event before the transition. It may take a + // stack trace, but we won't own the stack after the + // transition anymore. trace.GoSched() + } + casgstatus(gp, _Grunning, _Grunnable) + if trace.ok() { traceRelease(trace) } dropg() diff --git a/contrib/go/_std_1.22/src/runtime/debuglog.go b/contrib/go/_std_1.23/src/runtime/debuglog.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/debuglog.go rename to contrib/go/_std_1.23/src/runtime/debuglog.go index 873f1b45bddc..695cd204f592 100644 --- a/contrib/go/_std_1.22/src/runtime/debuglog.go +++ b/contrib/go/_std_1.23/src/runtime/debuglog.go @@ -16,7 +16,8 @@ package runtime import ( - "runtime/internal/atomic" + "internal/abi" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -277,8 +278,8 @@ func (l *dlogger) p(x any) *dlogger { l.w.uvarint(0) } else { v := efaceOf(&x) - switch v._type.Kind_ & kindMask { - case kindChan, kindFunc, kindMap, kindPtr, kindUnsafePointer: + switch v._type.Kind_ & abi.KindMask { + case abi.Chan, abi.Func, abi.Map, abi.Pointer, abi.UnsafePointer: l.w.uvarint(uint64(uintptr(v.data))) default: throw("not a pointer type") diff --git a/contrib/go/_std_1.22/src/runtime/debuglog_off.go b/contrib/go/_std_1.23/src/runtime/debuglog_off.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/debuglog_off.go rename to contrib/go/_std_1.23/src/runtime/debuglog_off.go diff --git a/contrib/go/_std_1.22/src/runtime/debuglog_on.go b/contrib/go/_std_1.23/src/runtime/debuglog_on.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/debuglog_on.go rename to contrib/go/_std_1.23/src/runtime/debuglog_on.go diff --git a/contrib/go/_std_1.22/src/runtime/defs1_linux.go b/contrib/go/_std_1.23/src/runtime/defs1_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs1_linux.go rename to contrib/go/_std_1.23/src/runtime/defs1_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_386.go b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_386.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs1_netbsd_386.go rename to contrib/go/_std_1.23/src/runtime/defs1_netbsd_386.go index f7fe45b4ab64..16c55def9269 100644 --- a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_386.go +++ b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_386.go @@ -84,12 +84,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = 0x0 _EVFILT_WRITE = 0x1 + _EVFILT_USER = 0x8 + + _NOTE_TRIGGER = 0x1000000 ) type sigset struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_amd64.go b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_amd64.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs1_netbsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs1_netbsd_amd64.go index 80908cd93185..7a035a99c80b 100644 --- a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_amd64.go +++ b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_amd64.go @@ -84,12 +84,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = 0x0 _EVFILT_WRITE = 0x1 + _EVFILT_USER = 0x8 + + _NOTE_TRIGGER = 0x1000000 ) type sigset struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_arm.go b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_arm.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs1_netbsd_arm.go rename to contrib/go/_std_1.23/src/runtime/defs1_netbsd_arm.go index c63e592ff145..77a59d4a05bf 100644 --- a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_arm.go +++ b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_arm.go @@ -84,12 +84,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = 0x0 _EVFILT_WRITE = 0x1 + _EVFILT_USER = 0x8 + + _NOTE_TRIGGER = 0x1000000 ) type sigset struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_arm64.go b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_arm64.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs1_netbsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/defs1_netbsd_arm64.go index 804b5b0b3f67..0720461f26cb 100644 --- a/contrib/go/_std_1.22/src/runtime/defs1_netbsd_arm64.go +++ b/contrib/go/_std_1.23/src/runtime/defs1_netbsd_arm64.go @@ -84,12 +84,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = 0x0 _EVFILT_WRITE = 0x1 + _EVFILT_USER = 0x8 + + _NOTE_TRIGGER = 0x1000000 ) type sigset struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs1_solaris_amd64.go b/contrib/go/_std_1.23/src/runtime/defs1_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs1_solaris_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs1_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs2_linux.go b/contrib/go/_std_1.23/src/runtime/defs2_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs2_linux.go rename to contrib/go/_std_1.23/src/runtime/defs2_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/defs3_linux.go b/contrib/go/_std_1.23/src/runtime/defs3_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs3_linux.go rename to contrib/go/_std_1.23/src/runtime/defs3_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_aix.go b/contrib/go/_std_1.23/src/runtime/defs_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_aix.go rename to contrib/go/_std_1.23/src/runtime/defs_aix.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_aix_ppc64.go b/contrib/go/_std_1.23/src/runtime/defs_aix_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_aix_ppc64.go rename to contrib/go/_std_1.23/src/runtime/defs_aix_ppc64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_arm_linux.go b/contrib/go/_std_1.23/src/runtime/defs_arm_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_arm_linux.go rename to contrib/go/_std_1.23/src/runtime/defs_arm_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_darwin.go b/contrib/go/_std_1.23/src/runtime/defs_darwin.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs_darwin.go rename to contrib/go/_std_1.23/src/runtime/defs_darwin.go index e37443307f37..9de59be20ba8 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_darwin.go +++ b/contrib/go/_std_1.23/src/runtime/defs_darwin.go @@ -106,12 +106,17 @@ const ( EV_ADD = C.EV_ADD EV_DELETE = C.EV_DELETE + EV_ENABLE = C.EV_ENABLE + EV_DISABLE = C.EV_DISABLE EV_CLEAR = C.EV_CLEAR EV_RECEIPT = C.EV_RECEIPT EV_ERROR = C.EV_ERROR EV_EOF = C.EV_EOF EVFILT_READ = C.EVFILT_READ EVFILT_WRITE = C.EVFILT_WRITE + EVFILT_USER = C.EVFILT_USER + + NOTE_TRIGGER = C.NOTE_TRIGGER PTHREAD_CREATE_DETACHED = C.PTHREAD_CREATE_DETACHED diff --git a/contrib/go/_std_1.22/src/runtime/defs_darwin_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_darwin_amd64.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/defs_darwin_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_darwin_amd64.go index f998b0be9118..c0ca16d46309 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_darwin_amd64.go +++ b/contrib/go/_std_1.23/src/runtime/defs_darwin_amd64.go @@ -85,12 +85,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0x40 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0xa + + _NOTE_TRIGGER = 0x1000000 _PTHREAD_CREATE_DETACHED = 0x2 diff --git a/contrib/go/_std_1.22/src/runtime/defs_darwin_arm64.go b/contrib/go/_std_1.23/src/runtime/defs_darwin_arm64.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs_darwin_arm64.go rename to contrib/go/_std_1.23/src/runtime/defs_darwin_arm64.go index e07b08e0eec9..cb534cacda4f 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_darwin_arm64.go +++ b/contrib/go/_std_1.23/src/runtime/defs_darwin_arm64.go @@ -85,12 +85,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0x40 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0xa + + _NOTE_TRIGGER = 0x1000000 _PTHREAD_CREATE_DETACHED = 0x2 diff --git a/contrib/go/_std_1.22/src/runtime/defs_dragonfly.go b/contrib/go/_std_1.23/src/runtime/defs_dragonfly.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/defs_dragonfly.go rename to contrib/go/_std_1.23/src/runtime/defs_dragonfly.go index 0463f1f116ae..d94461fe473d 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_dragonfly.go +++ b/contrib/go/_std_1.23/src/runtime/defs_dragonfly.go @@ -109,11 +109,16 @@ const ( EV_ADD = C.EV_ADD EV_DELETE = C.EV_DELETE + EV_ENABLE = C.EV_ENABLE + EV_DISABLE = C.EV_DISABLE EV_CLEAR = C.EV_CLEAR EV_ERROR = C.EV_ERROR EV_EOF = C.EV_EOF EVFILT_READ = C.EVFILT_READ EVFILT_WRITE = C.EVFILT_WRITE + EVFILT_USER = C.EVFILT_USER + + NOTE_TRIGGER = C.NOTE_TRIGGER ) type Rtprio C.struct_rtprio diff --git a/contrib/go/_std_1.22/src/runtime/defs_dragonfly_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_dragonfly_amd64.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs_dragonfly_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_dragonfly_amd64.go index 41bfb085d1ac..b142ae1d14d1 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_dragonfly_amd64.go +++ b/contrib/go/_std_1.23/src/runtime/defs_dragonfly_amd64.go @@ -88,11 +88,16 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0x9 + + _NOTE_TRIGGER = 0x1000000 ) type rtprio struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs_freebsd.go b/contrib/go/_std_1.23/src/runtime/defs_freebsd.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs_freebsd.go rename to contrib/go/_std_1.23/src/runtime/defs_freebsd.go index d86ae9133afa..70d82b90dae8 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_freebsd.go +++ b/contrib/go/_std_1.23/src/runtime/defs_freebsd.go @@ -136,12 +136,17 @@ const ( EV_ADD = C.EV_ADD EV_DELETE = C.EV_DELETE + EV_ENABLE = C.EV_ENABLE + EV_DISABLE = C.EV_DISABLE EV_CLEAR = C.EV_CLEAR EV_RECEIPT = C.EV_RECEIPT EV_ERROR = C.EV_ERROR EV_EOF = C.EV_EOF EVFILT_READ = C.EVFILT_READ EVFILT_WRITE = C.EVFILT_WRITE + EVFILT_USER = C.EVFILT_USER + + NOTE_TRIGGER = C.NOTE_TRIGGER ) type Rtprio C.struct_rtprio diff --git a/contrib/go/_std_1.22/src/runtime/defs_freebsd_386.go b/contrib/go/_std_1.23/src/runtime/defs_freebsd_386.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/defs_freebsd_386.go rename to contrib/go/_std_1.23/src/runtime/defs_freebsd_386.go index ee8274188ae6..42a0faf74dcc 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_freebsd_386.go +++ b/contrib/go/_std_1.23/src/runtime/defs_freebsd_386.go @@ -104,12 +104,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0x40 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0xb + + _NOTE_TRIGGER = 0x1000000 ) type rtprio struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs_freebsd_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_freebsd_amd64.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/defs_freebsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_freebsd_amd64.go index 9003f9201565..8f0b08d48aed 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_freebsd_amd64.go +++ b/contrib/go/_std_1.23/src/runtime/defs_freebsd_amd64.go @@ -104,12 +104,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0x40 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0xb + + _NOTE_TRIGGER = 0x1000000 ) type rtprio struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs_freebsd_arm.go b/contrib/go/_std_1.23/src/runtime/defs_freebsd_arm.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs_freebsd_arm.go rename to contrib/go/_std_1.23/src/runtime/defs_freebsd_arm.go index 68cc1b9545b7..dbb54da51bd2 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_freebsd_arm.go +++ b/contrib/go/_std_1.23/src/runtime/defs_freebsd_arm.go @@ -104,12 +104,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0x40 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0xb + + _NOTE_TRIGGER = 0x1000000 ) type rtprio struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs_freebsd_arm64.go b/contrib/go/_std_1.23/src/runtime/defs_freebsd_arm64.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs_freebsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/defs_freebsd_arm64.go index 1d6723621ae7..83b639381be3 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_freebsd_arm64.go +++ b/contrib/go/_std_1.23/src/runtime/defs_freebsd_arm64.go @@ -104,12 +104,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0x40 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0xb + + _NOTE_TRIGGER = 0x1000000 ) type rtprio struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs_freebsd_riscv64.go b/contrib/go/_std_1.23/src/runtime/defs_freebsd_riscv64.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/defs_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/runtime/defs_freebsd_riscv64.go index b977bde5515e..5d9a5ac7fda8 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_freebsd_riscv64.go +++ b/contrib/go/_std_1.23/src/runtime/defs_freebsd_riscv64.go @@ -103,12 +103,17 @@ const ( _EV_ADD = 0x1 _EV_DELETE = 0x2 + _EV_ENABLE = 0x4 + _EV_DISABLE = 0x8 _EV_CLEAR = 0x20 _EV_RECEIPT = 0x40 _EV_ERROR = 0x4000 _EV_EOF = 0x8000 _EVFILT_READ = -0x1 _EVFILT_WRITE = -0x2 + _EVFILT_USER = -0xb + + _NOTE_TRIGGER = 0x1000000 ) type rtprio struct { diff --git a/contrib/go/_std_1.22/src/runtime/defs_illumos_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_illumos_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_illumos_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_illumos_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux.go b/contrib/go/_std_1.23/src/runtime/defs_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux.go rename to contrib/go/_std_1.23/src/runtime/defs_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_386.go b/contrib/go/_std_1.23/src/runtime/defs_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_386.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_386.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_linux_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_arm.go b/contrib/go/_std_1.23/src/runtime/defs_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_arm.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_arm64.go b/contrib/go/_std_1.23/src/runtime/defs_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_arm64.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_loong64.go b/contrib/go/_std_1.23/src/runtime/defs_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_loong64.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_mips64x.go b/contrib/go/_std_1.23/src/runtime/defs_linux_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_mips64x.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_mips64x.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_mipsx.go b/contrib/go/_std_1.23/src/runtime/defs_linux_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_mipsx.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_mipsx.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_ppc64.go b/contrib/go/_std_1.23/src/runtime/defs_linux_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_ppc64.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_ppc64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_ppc64le.go b/contrib/go/_std_1.23/src/runtime/defs_linux_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_ppc64le.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_ppc64le.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_riscv64.go b/contrib/go/_std_1.23/src/runtime/defs_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_riscv64.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_linux_s390x.go b/contrib/go/_std_1.23/src/runtime/defs_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_linux_s390x.go rename to contrib/go/_std_1.23/src/runtime/defs_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_netbsd.go b/contrib/go/_std_1.23/src/runtime/defs_netbsd.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/defs_netbsd.go rename to contrib/go/_std_1.23/src/runtime/defs_netbsd.go index 43923e3075b7..ec4d796bd325 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_netbsd.go +++ b/contrib/go/_std_1.23/src/runtime/defs_netbsd.go @@ -110,12 +110,17 @@ const ( EV_ADD = C.EV_ADD EV_DELETE = C.EV_DELETE + EV_ENABLE = C.EV_ENABLE + EV_DISABLE = C.EV_DISABLE EV_CLEAR = C.EV_CLEAR EV_RECEIPT = 0 EV_ERROR = C.EV_ERROR EV_EOF = C.EV_EOF EVFILT_READ = C.EVFILT_READ EVFILT_WRITE = C.EVFILT_WRITE + EVFILT_USER = C.EVFILT_USER + + NOTE_TRIGGER = C.NOTE_TRIGGER ) type Sigset C.sigset_t diff --git a/contrib/go/_std_1.22/src/runtime/defs_netbsd_386.go b/contrib/go/_std_1.23/src/runtime/defs_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_netbsd_386.go rename to contrib/go/_std_1.23/src/runtime/defs_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_netbsd_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_netbsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_netbsd_arm.go b/contrib/go/_std_1.23/src/runtime/defs_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_netbsd_arm.go rename to contrib/go/_std_1.23/src/runtime/defs_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd_386.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd_386.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd_386.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd_arm.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd_arm.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd_arm64.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd_mips64.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd_mips64.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd_ppc64.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd_ppc64.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd_ppc64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_openbsd_riscv64.go b/contrib/go/_std_1.23/src/runtime/defs_openbsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_openbsd_riscv64.go rename to contrib/go/_std_1.23/src/runtime/defs_openbsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_plan9_386.go b/contrib/go/_std_1.23/src/runtime/defs_plan9_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_plan9_386.go rename to contrib/go/_std_1.23/src/runtime/defs_plan9_386.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_plan9_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_plan9_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_plan9_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_plan9_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_plan9_arm.go b/contrib/go/_std_1.23/src/runtime/defs_plan9_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_plan9_arm.go rename to contrib/go/_std_1.23/src/runtime/defs_plan9_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_solaris.go b/contrib/go/_std_1.23/src/runtime/defs_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_solaris.go rename to contrib/go/_std_1.23/src/runtime/defs_solaris.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_solaris_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_solaris_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_windows.go b/contrib/go/_std_1.23/src/runtime/defs_windows.go similarity index 88% rename from contrib/go/_std_1.22/src/runtime/defs_windows.go rename to contrib/go/_std_1.23/src/runtime/defs_windows.go index 2dbe1446898e..2f09afbe1fef 100644 --- a/contrib/go/_std_1.22/src/runtime/defs_windows.go +++ b/contrib/go/_std_1.23/src/runtime/defs_windows.go @@ -89,3 +89,13 @@ type memoryBasicInformation struct { protect uint32 type_ uint32 } + +// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow +type _OSVERSIONINFOW struct { + osVersionInfoSize uint32 + majorVersion uint32 + minorVersion uint32 + buildNumber uint32 + platformId uint32 + csdVersion [128]uint16 +} diff --git a/contrib/go/_std_1.22/src/runtime/defs_windows_386.go b/contrib/go/_std_1.23/src/runtime/defs_windows_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_windows_386.go rename to contrib/go/_std_1.23/src/runtime/defs_windows_386.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_windows_amd64.go b/contrib/go/_std_1.23/src/runtime/defs_windows_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_windows_amd64.go rename to contrib/go/_std_1.23/src/runtime/defs_windows_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_windows_arm.go b/contrib/go/_std_1.23/src/runtime/defs_windows_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_windows_arm.go rename to contrib/go/_std_1.23/src/runtime/defs_windows_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/defs_windows_arm64.go b/contrib/go/_std_1.23/src/runtime/defs_windows_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/defs_windows_arm64.go rename to contrib/go/_std_1.23/src/runtime/defs_windows_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/duff_386.s b/contrib/go/_std_1.23/src/runtime/duff_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_386.s rename to contrib/go/_std_1.23/src/runtime/duff_386.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_amd64.s b/contrib/go/_std_1.23/src/runtime/duff_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_amd64.s rename to contrib/go/_std_1.23/src/runtime/duff_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_arm.s b/contrib/go/_std_1.23/src/runtime/duff_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_arm.s rename to contrib/go/_std_1.23/src/runtime/duff_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_arm64.s b/contrib/go/_std_1.23/src/runtime/duff_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_arm64.s rename to contrib/go/_std_1.23/src/runtime/duff_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_loong64.s b/contrib/go/_std_1.23/src/runtime/duff_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_loong64.s rename to contrib/go/_std_1.23/src/runtime/duff_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_mips64x.s b/contrib/go/_std_1.23/src/runtime/duff_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_mips64x.s rename to contrib/go/_std_1.23/src/runtime/duff_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_ppc64x.s b/contrib/go/_std_1.23/src/runtime/duff_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/duff_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_riscv64.s b/contrib/go/_std_1.23/src/runtime/duff_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_riscv64.s rename to contrib/go/_std_1.23/src/runtime/duff_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/duff_s390x.s b/contrib/go/_std_1.23/src/runtime/duff_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/duff_s390x.s rename to contrib/go/_std_1.23/src/runtime/duff_s390x.s diff --git a/contrib/go/_std_1.22/src/runtime/env_plan9.go b/contrib/go/_std_1.23/src/runtime/env_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/env_plan9.go rename to contrib/go/_std_1.23/src/runtime/env_plan9.go diff --git a/contrib/go/_std_1.22/src/runtime/env_posix.go b/contrib/go/_std_1.23/src/runtime/env_posix.go similarity index 70% rename from contrib/go/_std_1.22/src/runtime/env_posix.go rename to contrib/go/_std_1.23/src/runtime/env_posix.go index 0eb4f0d7a3b8..323ce7de9a0f 100644 --- a/contrib/go/_std_1.22/src/runtime/env_posix.go +++ b/contrib/go/_std_1.23/src/runtime/env_posix.go @@ -42,7 +42,26 @@ func lowerASCII(c byte) byte { return c } -var _cgo_setenv unsafe.Pointer // pointer to C function +// _cgo_setenv should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ebitengine/purego +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname _cgo_setenv +var _cgo_setenv unsafe.Pointer // pointer to C function + +// _cgo_unsetenv should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ebitengine/purego +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname _cgo_unsetenv var _cgo_unsetenv unsafe.Pointer // pointer to C function // Update the C environment if cgo is loaded. diff --git a/contrib/go/_std_1.22/src/runtime/error.go b/contrib/go/_std_1.23/src/runtime/error.go similarity index 89% rename from contrib/go/_std_1.22/src/runtime/error.go rename to contrib/go/_std_1.23/src/runtime/error.go index b507f25e185d..406f36ca5f9d 100644 --- a/contrib/go/_std_1.22/src/runtime/error.go +++ b/contrib/go/_std_1.23/src/runtime/error.go @@ -4,7 +4,10 @@ package runtime -import "internal/bytealg" +import ( + "internal/abi" + "internal/bytealg" +) // The Error interface identifies a run time error. type Error interface { @@ -208,11 +211,16 @@ type stringer interface { String() string } -// printany prints an argument passed to panic. +// printpanicval prints an argument passed to panic. // If panic is called with a value that has a String or Error method, // it has already been converted into a string by preprintpanics. -func printany(i any) { - switch v := i.(type) { +// +// To ensure that the traceback can be unambiguously parsed even when +// the panic value contains "\ngoroutine" and other stack-like +// strings, newlines in the string representation of v are replaced by +// "\n\t". +func printpanicval(v any) { + switch v := v.(type) { case nil: print("nil") case bool: @@ -248,56 +256,74 @@ func printany(i any) { case complex128: print(v) case string: - print(v) + printindented(v) default: - printanycustomtype(i) + printanycustomtype(v) } } +// Invariant: each newline in the string representation is followed by a tab. func printanycustomtype(i any) { eface := efaceOf(&i) typestring := toRType(eface._type).string() switch eface._type.Kind_ { - case kindString: - print(typestring, `("`, *(*string)(eface.data), `")`) - case kindBool: + case abi.String: + print(typestring, `("`) + printindented(*(*string)(eface.data)) + print(`")`) + case abi.Bool: print(typestring, "(", *(*bool)(eface.data), ")") - case kindInt: + case abi.Int: print(typestring, "(", *(*int)(eface.data), ")") - case kindInt8: + case abi.Int8: print(typestring, "(", *(*int8)(eface.data), ")") - case kindInt16: + case abi.Int16: print(typestring, "(", *(*int16)(eface.data), ")") - case kindInt32: + case abi.Int32: print(typestring, "(", *(*int32)(eface.data), ")") - case kindInt64: + case abi.Int64: print(typestring, "(", *(*int64)(eface.data), ")") - case kindUint: + case abi.Uint: print(typestring, "(", *(*uint)(eface.data), ")") - case kindUint8: + case abi.Uint8: print(typestring, "(", *(*uint8)(eface.data), ")") - case kindUint16: + case abi.Uint16: print(typestring, "(", *(*uint16)(eface.data), ")") - case kindUint32: + case abi.Uint32: print(typestring, "(", *(*uint32)(eface.data), ")") - case kindUint64: + case abi.Uint64: print(typestring, "(", *(*uint64)(eface.data), ")") - case kindUintptr: + case abi.Uintptr: print(typestring, "(", *(*uintptr)(eface.data), ")") - case kindFloat32: + case abi.Float32: print(typestring, "(", *(*float32)(eface.data), ")") - case kindFloat64: + case abi.Float64: print(typestring, "(", *(*float64)(eface.data), ")") - case kindComplex64: + case abi.Complex64: print(typestring, *(*complex64)(eface.data)) - case kindComplex128: + case abi.Complex128: print(typestring, *(*complex128)(eface.data)) default: print("(", typestring, ") ", eface.data) } } +// printindented prints s, replacing "\n" with "\n\t". +func printindented(s string) { + for { + i := bytealg.IndexByteString(s, '\n') + if i < 0 { + break + } + i += len("\n") + print(s[:i]) + print("\t") + s = s[i:] + } + print(s) +} + // panicwrap generates a panic for a call to a wrapped value method // with a nil pointer receiver. // diff --git a/contrib/go/_std_1.22/src/runtime/extern.go b/contrib/go/_std_1.23/src/runtime/extern.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/extern.go rename to contrib/go/_std_1.23/src/runtime/extern.go index e42122fd3a1c..2019be4ddec4 100644 --- a/contrib/go/_std_1.22/src/runtime/extern.go +++ b/contrib/go/_std_1.23/src/runtime/extern.go @@ -35,9 +35,6 @@ time. The GODEBUG variable controls debugging variables within the runtime. It is a comma-separated list of name=val pairs setting these named variables: - allocfreetrace: setting allocfreetrace=1 causes every allocation to be - profiled and a stack trace printed on each object's allocation and free. - clobberfree: setting clobberfree=1 causes the garbage collector to clobber the memory content of an object with bad content when it frees the object. @@ -145,6 +142,13 @@ It is a comma-separated list of name=val pairs setting these named variables: When set to 0 memory profiling is disabled. Refer to the description of MemProfileRate for the default value. + profstackdepth: profstackdepth=128 (the default) will set the maximum stack + depth used by all pprof profilers except for the CPU profiler to 128 frames. + Stack traces that exceed this limit will be truncated to the limit starting + from the leaf frame. Setting profstackdepth to any value above 1024 will + silently default to 1024. Future versions of Go may remove this limitation + and extend profstackdepth to apply to the CPU profiler and execution tracer. + pagetrace: setting pagetrace=/path/to/file will write out a trace of page events that can be viewed, analyzed, and visualized using the x/debug/cmd/pagetrace tool. Build your program with GOEXPERIMENT=pagetrace to enable this functionality. Do not @@ -198,9 +202,8 @@ It is a comma-separated list of name=val pairs setting these named variables: tracebackancestors: setting tracebackancestors=N extends tracebacks with the stacks at which goroutines were created, where N limits the number of ancestor goroutines to - report. This also extends the information returned by runtime.Stack. Ancestor's goroutine - IDs will refer to the ID of the goroutine at the time of creation; it's possible for this - ID to be reused for another goroutine. Setting N to 0 will report no ancestry information. + report. This also extends the information returned by runtime.Stack. + Setting N to 0 will report no ancestry information. tracefpunwindoff: setting tracefpunwindoff=1 forces the execution tracer to use the runtime's default stack unwinder instead of frame pointer unwinding. @@ -211,6 +214,9 @@ It is a comma-separated list of name=val pairs setting these named variables: applies if a program is built with GOEXPERIMENT=exectracer2. Used primarily for testing and debugging the execution tracer. + tracecheckstackownership: setting tracecheckstackownership=1 enables a debug check in the + execution tracer to double-check stack ownership before taking a stack trace. + asyncpreemptoff: asyncpreemptoff=1 disables signal-based asynchronous goroutine preemption. This makes some loops non-preemptible for long periods, which may delay GC and @@ -294,7 +300,7 @@ import ( // call. The boolean ok is false if it was not possible to recover the information. func Caller(skip int) (pc uintptr, file string, line int, ok bool) { rpc := make([]uintptr, 1) - n := callers(skip+1, rpc[:]) + n := callers(skip+1, rpc) if n < 1 { return } diff --git a/contrib/go/_std_1.22/src/runtime/fastlog2.go b/contrib/go/_std_1.23/src/runtime/fastlog2.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/fastlog2.go rename to contrib/go/_std_1.23/src/runtime/fastlog2.go diff --git a/contrib/go/_std_1.22/src/runtime/fastlog2table.go b/contrib/go/_std_1.23/src/runtime/fastlog2table.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/fastlog2table.go rename to contrib/go/_std_1.23/src/runtime/fastlog2table.go diff --git a/contrib/go/_std_1.22/src/runtime/fds_nonunix.go b/contrib/go/_std_1.23/src/runtime/fds_nonunix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/fds_nonunix.go rename to contrib/go/_std_1.23/src/runtime/fds_nonunix.go diff --git a/contrib/go/_std_1.22/src/runtime/fds_unix.go b/contrib/go/_std_1.23/src/runtime/fds_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/fds_unix.go rename to contrib/go/_std_1.23/src/runtime/fds_unix.go diff --git a/contrib/go/_std_1.22/src/runtime/float.go b/contrib/go/_std_1.23/src/runtime/float.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/float.go rename to contrib/go/_std_1.23/src/runtime/float.go diff --git a/contrib/go/_std_1.22/src/runtime/funcdata.h b/contrib/go/_std_1.23/src/runtime/funcdata.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/funcdata.h rename to contrib/go/_std_1.23/src/runtime/funcdata.h diff --git a/contrib/go/_std_1.22/src/runtime/go_tls.h b/contrib/go/_std_1.23/src/runtime/go_tls.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/go_tls.h rename to contrib/go/_std_1.23/src/runtime/go_tls.h diff --git a/contrib/go/_std_1.22/src/runtime/hash32.go b/contrib/go/_std_1.23/src/runtime/hash32.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/hash32.go rename to contrib/go/_std_1.23/src/runtime/hash32.go diff --git a/contrib/go/_std_1.22/src/runtime/hash64.go b/contrib/go/_std_1.23/src/runtime/hash64.go similarity index 76% rename from contrib/go/_std_1.22/src/runtime/hash64.go rename to contrib/go/_std_1.23/src/runtime/hash64.go index 2864a4b963dd..05cdb8111372 100644 --- a/contrib/go/_std_1.22/src/runtime/hash64.go +++ b/contrib/go/_std_1.23/src/runtime/hash64.go @@ -15,16 +15,12 @@ import ( ) const ( - m1 = 0xa0761d6478bd642f - m2 = 0xe7037ed1a0b428db - m3 = 0x8ebc6af09c88c6e3 - m4 = 0x589965cc75374cc3 m5 = 0x1d8e4e27c47d124f ) func memhashFallback(p unsafe.Pointer, seed, s uintptr) uintptr { var a, b uintptr - seed ^= hashkey[0] ^ m1 + seed ^= hashkey[0] switch { case s == 0: return seed @@ -50,32 +46,32 @@ func memhashFallback(p unsafe.Pointer, seed, s uintptr) uintptr { seed1 := seed seed2 := seed for ; l > 48; l -= 48 { - seed = mix(r8(p)^m2, r8(add(p, 8))^seed) - seed1 = mix(r8(add(p, 16))^m3, r8(add(p, 24))^seed1) - seed2 = mix(r8(add(p, 32))^m4, r8(add(p, 40))^seed2) + seed = mix(r8(p)^hashkey[1], r8(add(p, 8))^seed) + seed1 = mix(r8(add(p, 16))^hashkey[2], r8(add(p, 24))^seed1) + seed2 = mix(r8(add(p, 32))^hashkey[3], r8(add(p, 40))^seed2) p = add(p, 48) } seed ^= seed1 ^ seed2 } for ; l > 16; l -= 16 { - seed = mix(r8(p)^m2, r8(add(p, 8))^seed) + seed = mix(r8(p)^hashkey[1], r8(add(p, 8))^seed) p = add(p, 16) } a = r8(add(p, l-16)) b = r8(add(p, l-8)) } - return mix(m5^s, mix(a^m2, b^seed)) + return mix(m5^s, mix(a^hashkey[1], b^seed)) } func memhash32Fallback(p unsafe.Pointer, seed uintptr) uintptr { a := r4(p) - return mix(m5^4, mix(a^m2, a^seed^hashkey[0]^m1)) + return mix(m5^4, mix(a^hashkey[1], a^seed^hashkey[0])) } func memhash64Fallback(p unsafe.Pointer, seed uintptr) uintptr { a := r8(p) - return mix(m5^8, mix(a^m2, a^seed^hashkey[0]^m1)) + return mix(m5^8, mix(a^hashkey[1], a^seed^hashkey[0])) } func mix(a, b uintptr) uintptr { diff --git a/contrib/go/_std_1.22/src/runtime/heapdump.go b/contrib/go/_std_1.23/src/runtime/heapdump.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/heapdump.go rename to contrib/go/_std_1.23/src/runtime/heapdump.go index 276c5bfaf615..95fb62dc425c 100644 --- a/contrib/go/_std_1.22/src/runtime/heapdump.go +++ b/contrib/go/_std_1.23/src/runtime/heapdump.go @@ -14,7 +14,6 @@ package runtime import ( "internal/abi" "internal/goarch" - "internal/goexperiment" "unsafe" ) @@ -206,7 +205,7 @@ func dumptype(t *_type) { dwritebyte('.') dwrite(unsafe.Pointer(unsafe.StringData(name)), uintptr(len(name))) } - dumpbool(t.Kind_&kindDirectIface == 0 || t.PtrBytes != 0) + dumpbool(t.Kind_&abi.KindDirectIface == 0 || t.PtrBytes != 0) } // dump an object. @@ -540,7 +539,7 @@ func dumpparams() { } func itab_callback(tab *itab) { - t := tab._type + t := tab.Type dumptype(t) dumpint(tagItab) dumpint(uint64(uintptr(unsafe.Pointer(tab)))) @@ -735,31 +734,16 @@ func makeheapobjbv(p uintptr, size uintptr) bitvector { tmpbuf = (*[1 << 30]byte)(p)[:n] } // Convert heap bitmap to pointer bitmap. - for i := uintptr(0); i < nptr/8+1; i++ { - tmpbuf[i] = 0 - } - if goexperiment.AllocHeaders { - s := spanOf(p) - tp := s.typePointersOf(p, size) - for { - var addr uintptr - if tp, addr = tp.next(p + size); addr == 0 { - break - } - i := (addr - p) / goarch.PtrSize - tmpbuf[i/8] |= 1 << (i % 8) - } - } else { - hbits := heapBitsForAddr(p, size) - for { - var addr uintptr - hbits, addr = hbits.next() - if addr == 0 { - break - } - i := (addr - p) / goarch.PtrSize - tmpbuf[i/8] |= 1 << (i % 8) + clear(tmpbuf[:nptr/8+1]) + s := spanOf(p) + tp := s.typePointersOf(p, size) + for { + var addr uintptr + if tp, addr = tp.next(p + size); addr == 0 { + break } + i := (addr - p) / goarch.PtrSize + tmpbuf[i/8] |= 1 << (i % 8) } return bitvector{int32(nptr), &tmpbuf[0]} } diff --git a/contrib/go/_std_1.22/src/runtime/histogram.go b/contrib/go/_std_1.23/src/runtime/histogram.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/histogram.go rename to contrib/go/_std_1.23/src/runtime/histogram.go index f243667b5542..95230d1f39d5 100644 --- a/contrib/go/_std_1.22/src/runtime/histogram.go +++ b/contrib/go/_std_1.23/src/runtime/histogram.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/iface.go b/contrib/go/_std_1.23/src/runtime/iface.go similarity index 89% rename from contrib/go/_std_1.22/src/runtime/iface.go rename to contrib/go/_std_1.23/src/runtime/iface.go index bad49a346e86..41a10ae01215 100644 --- a/contrib/go/_std_1.22/src/runtime/iface.go +++ b/contrib/go/_std_1.23/src/runtime/iface.go @@ -7,7 +7,7 @@ package runtime import ( "internal/abi" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -32,6 +32,15 @@ func itabHashFunc(inter *interfacetype, typ *_type) uintptr { return uintptr(inter.Type.Hash ^ typ.Hash) } +// getitab should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname getitab func getitab(inter *interfacetype, typ *_type, canfail bool) *itab { if len(inter.Methods) == 0 { throw("internal error - misuse of itab") @@ -66,19 +75,19 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab { // Entry doesn't exist yet. Make a new entry & add it. m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.Methods)-1)*goarch.PtrSize, 0, &memstats.other_sys)) - m.inter = inter - m._type = typ + m.Inter = inter + m.Type = typ // The hash is used in type switches. However, compiler statically generates itab's // for all interface/type pairs used in switches (which are added to itabTable // in itabsinit). The dynamically-generated itab's never participate in type switches, // and thus the hash is irrelevant. - // Note: m.hash is _not_ the hash used for the runtime itabTable hash table. - m.hash = 0 - m.init() + // Note: m.Hash is _not_ the hash used for the runtime itabTable hash table. + m.Hash = 0 + itabInit(m, true) itabAdd(m) unlock(&itabLock) finish: - if m.fun[0] != 0 { + if m.Fun[0] != 0 { return m } if canfail { @@ -90,7 +99,7 @@ finish: // The cached result doesn't record which // interface function was missing, so initialize // the itab again to get the missing function name. - panic(&TypeAssertionError{concrete: typ, asserted: &inter.Type, missingMethod: m.init()}) + panic(&TypeAssertionError{concrete: typ, asserted: &inter.Type, missingMethod: itabInit(m, false)}) } // find finds the given interface/type pair in t. @@ -110,7 +119,7 @@ func (t *itabTableType) find(inter *interfacetype, typ *_type) *itab { if m == nil { return nil } - if m.inter == inter && m._type == typ { + if m.Inter == inter && m.Type == typ { return m } h += i @@ -161,7 +170,7 @@ func (t *itabTableType) add(m *itab) { // See comment in find about the probe sequence. // Insert new itab in the first empty spot in the probe sequence. mask := t.size - 1 - h := itabHashFunc(m.inter, m._type) & mask + h := itabHashFunc(m.Inter, m.Type) & mask for i := uintptr(1); ; i++ { p := (**itab)(add(unsafe.Pointer(&t.entries), h*goarch.PtrSize)) m2 := *p @@ -186,13 +195,15 @@ func (t *itabTableType) add(m *itab) { } } -// init fills in the m.fun array with all the code pointers for -// the m.inter/m._type pair. If the type does not implement the interface, -// it sets m.fun[0] to 0 and returns the name of an interface function that is missing. -// It is ok to call this multiple times on the same m, even concurrently. -func (m *itab) init() string { - inter := m.inter - typ := m._type +// itabInit fills in the m.Fun array with all the code pointers for +// the m.Inter/m.Type pair. If the type does not implement the interface, +// it sets m.Fun[0] to 0 and returns the name of an interface function that is missing. +// If !firstTime, itabInit will not write anything to m.Fun (see issue 65962). +// It is ok to call this multiple times on the same m, even concurrently +// (although it will only be called once with firstTime==true). +func itabInit(m *itab, firstTime bool) string { + inter := m.Inter + typ := m.Type x := typ.Uncommon() // both inter and typ have method sorted by name, @@ -203,7 +214,7 @@ func (m *itab) init() string { nt := int(x.Mcount) xmhdr := (*[1 << 16]abi.Method)(add(unsafe.Pointer(x), uintptr(x.Moff)))[:nt:nt] j := 0 - methods := (*[1 << 16]unsafe.Pointer)(unsafe.Pointer(&m.fun[0]))[:ni:ni] + methods := (*[1 << 16]unsafe.Pointer)(unsafe.Pointer(&m.Fun[0]))[:ni:ni] var fun0 unsafe.Pointer imethods: for k := 0; k < ni; k++ { @@ -227,8 +238,8 @@ imethods: if tname.IsExported() || pkgPath == ipkg { ifn := rtyp.textOff(t.Ifn) if k == 0 { - fun0 = ifn // we'll set m.fun[0] at the end - } else { + fun0 = ifn // we'll set m.Fun[0] at the end + } else if firstTime { methods[k] = ifn } continue imethods @@ -236,10 +247,12 @@ imethods: } } // didn't find method - m.fun[0] = 0 + // Leaves m.Fun[0] set to 0. return iname } - m.fun[0] = uintptr(fun0) + if firstTime { + m.Fun[0] = uintptr(fun0) + } return "" } @@ -267,7 +280,7 @@ func panicdottypeE(have, want, iface *_type) { func panicdottypeI(have *itab, want, iface *_type) { var t *_type if have != nil { - t = have._type + t = have.Type } panicdottypeE(t, want, iface) } @@ -375,6 +388,15 @@ func convT32(val uint32) (x unsafe.Pointer) { return } +// convT64 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname convT64 func convT64(val uint64) (x unsafe.Pointer) { if val < uint64(len(staticuint64s)) { x = unsafe.Pointer(&staticuint64s[val]) @@ -385,6 +407,15 @@ func convT64(val uint64) (x unsafe.Pointer) { return } +// convTstring should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname convTstring func convTstring(val string) (x unsafe.Pointer) { if val == "" { x = unsafe.Pointer(&zeroVal[0]) @@ -395,6 +426,15 @@ func convTstring(val string) (x unsafe.Pointer) { return } +// convTslice should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname convTslice func convTslice(val []byte) (x unsafe.Pointer) { // Note: this must work for any element type, not just byte. if (*slice)(unsafe.Pointer(&val)).array == nil { @@ -620,6 +660,15 @@ func buildInterfaceSwitchCache(oldC *abi.InterfaceSwitchCache, typ *_type, case_ // causes a cache lookup to fail immediately.) var emptyInterfaceSwitchCache = abi.InterfaceSwitchCache{Mask: 0} +// reflect_ifaceE2I is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// //go:linkname reflect_ifaceE2I reflect.ifaceE2I func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) { *dst = iface{assertE2I(inter, e._type), e.data} diff --git a/contrib/go/_std_1.22/src/runtime/internal/math/math.go b/contrib/go/_std_1.23/src/runtime/internal/math/math.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/math/math.go rename to contrib/go/_std_1.23/src/runtime/internal/math/math.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/math/ya.make b/contrib/go/_std_1.23/src/runtime/internal/math/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/math/ya.make rename to contrib/go/_std_1.23/src/runtime/internal/math/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/internal/startlinetest/func_amd64.go b/contrib/go/_std_1.23/src/runtime/internal/startlinetest/func_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/startlinetest/func_amd64.go rename to contrib/go/_std_1.23/src/runtime/internal/startlinetest/func_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/startlinetest/func_amd64.s b/contrib/go/_std_1.23/src/runtime/internal/startlinetest/func_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/startlinetest/func_amd64.s rename to contrib/go/_std_1.23/src/runtime/internal/startlinetest/func_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/internal/startlinetest/ya.make b/contrib/go/_std_1.23/src/runtime/internal/startlinetest/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/startlinetest/ya.make rename to contrib/go/_std_1.23/src/runtime/internal/startlinetest/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/consts.go b/contrib/go/_std_1.23/src/runtime/internal/sys/consts.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/consts.go rename to contrib/go/_std_1.23/src/runtime/internal/sys/consts.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/consts_norace.go b/contrib/go/_std_1.23/src/runtime/internal/sys/consts_norace.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/consts_norace.go rename to contrib/go/_std_1.23/src/runtime/internal/sys/consts_norace.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/consts_race.go b/contrib/go/_std_1.23/src/runtime/internal/sys/consts_race.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/consts_race.go rename to contrib/go/_std_1.23/src/runtime/internal/sys/consts_race.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/intrinsics.go b/contrib/go/_std_1.23/src/runtime/internal/sys/intrinsics.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/intrinsics.go rename to contrib/go/_std_1.23/src/runtime/internal/sys/intrinsics.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/nih.go b/contrib/go/_std_1.23/src/runtime/internal/sys/nih.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/nih.go rename to contrib/go/_std_1.23/src/runtime/internal/sys/nih.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/sys.go b/contrib/go/_std_1.23/src/runtime/internal/sys/sys.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/sys.go rename to contrib/go/_std_1.23/src/runtime/internal/sys/sys.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/ya.make b/contrib/go/_std_1.23/src/runtime/internal/sys/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/ya.make rename to contrib/go/_std_1.23/src/runtime/internal/sys/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/internal/sys/zversion.go b/contrib/go/_std_1.23/src/runtime/internal/sys/zversion.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/sys/zversion.go rename to contrib/go/_std_1.23/src/runtime/internal/sys/zversion.go diff --git a/contrib/go/_std_1.22/src/runtime/internal/wasitest/ya.make b/contrib/go/_std_1.23/src/runtime/internal/wasitest/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/wasitest/ya.make rename to contrib/go/_std_1.23/src/runtime/internal/wasitest/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/internal/ya.make b/contrib/go/_std_1.23/src/runtime/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/internal/ya.make rename to contrib/go/_std_1.23/src/runtime/internal/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/lfstack.go b/contrib/go/_std_1.23/src/runtime/lfstack.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/lfstack.go rename to contrib/go/_std_1.23/src/runtime/lfstack.go index a91ae64e5383..cbec6e844726 100644 --- a/contrib/go/_std_1.22/src/runtime/lfstack.go +++ b/contrib/go/_std_1.23/src/runtime/lfstack.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/libfuzzer.go b/contrib/go/_std_1.23/src/runtime/libfuzzer.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/libfuzzer.go rename to contrib/go/_std_1.23/src/runtime/libfuzzer.go diff --git a/contrib/go/_std_1.22/src/runtime/libfuzzer_amd64.s b/contrib/go/_std_1.23/src/runtime/libfuzzer_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/libfuzzer_amd64.s rename to contrib/go/_std_1.23/src/runtime/libfuzzer_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/libfuzzer_arm64.s b/contrib/go/_std_1.23/src/runtime/libfuzzer_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/libfuzzer_arm64.s rename to contrib/go/_std_1.23/src/runtime/libfuzzer_arm64.s diff --git a/contrib/go/_std_1.23/src/runtime/linkname.go b/contrib/go/_std_1.23/src/runtime/linkname.go new file mode 100644 index 000000000000..dd7f67425103 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/linkname.go @@ -0,0 +1,34 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import _ "unsafe" + +// used in internal/godebug and syscall +//go:linkname write + +// used by cgo +//go:linkname _cgo_panic_internal +//go:linkname cgoAlwaysFalse +//go:linkname cgoUse +//go:linkname cgoCheckPointer +//go:linkname cgoCheckResult +//go:linkname cgoNoCallback +//go:linkname gobytes +//go:linkname gostringn + +// used in plugin +//go:linkname doInit + +// used in math/bits +//go:linkname overflowError +//go:linkname divideError + +// used in tests +//go:linkname extraMInUse +//go:linkname blockevent +//go:linkname haveHighResSleep +//go:linkname blockUntilEmptyFinalizerQueue +//go:linkname lockedOSThread diff --git a/contrib/go/_std_1.23/src/runtime/linkname_unix.go b/contrib/go/_std_1.23/src/runtime/linkname_unix.go new file mode 100644 index 000000000000..65f876fa4baf --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/linkname_unix.go @@ -0,0 +1,12 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix + +package runtime + +import _ "unsafe" + +// used in internal/syscall/unix +//go:linkname fcntl diff --git a/contrib/go/_std_1.22/src/runtime/lock_futex.go b/contrib/go/_std_1.23/src/runtime/lock_futex.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/lock_futex.go rename to contrib/go/_std_1.23/src/runtime/lock_futex.go index 867e2b34d066..58690e45e4d5 100644 --- a/contrib/go/_std_1.22/src/runtime/lock_futex.go +++ b/contrib/go/_std_1.23/src/runtime/lock_futex.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/lock_js.go b/contrib/go/_std_1.23/src/runtime/lock_js.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/lock_js.go rename to contrib/go/_std_1.23/src/runtime/lock_js.go diff --git a/contrib/go/_std_1.22/src/runtime/lock_sema.go b/contrib/go/_std_1.23/src/runtime/lock_sema.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/lock_sema.go rename to contrib/go/_std_1.23/src/runtime/lock_sema.go index 073e7d410e4c..32d2235ad3ab 100644 --- a/contrib/go/_std_1.22/src/runtime/lock_sema.go +++ b/contrib/go/_std_1.23/src/runtime/lock_sema.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/lock_wasip1.go b/contrib/go/_std_1.23/src/runtime/lock_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/lock_wasip1.go rename to contrib/go/_std_1.23/src/runtime/lock_wasip1.go diff --git a/contrib/go/_std_1.23/src/runtime/lockrank.go b/contrib/go/_std_1.23/src/runtime/lockrank.go new file mode 100644 index 000000000000..373838332f56 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/lockrank.go @@ -0,0 +1,227 @@ +// Code generated by mklockrank.go; DO NOT EDIT. + +package runtime + +type lockRank int + +// Constants representing the ranks of all non-leaf runtime locks, in rank order. +// Locks with lower rank must be taken before locks with higher rank, +// in addition to satisfying the partial order in lockPartialOrder. +// A few ranks allow self-cycles, which are specified in lockPartialOrder. +const ( + lockRankUnknown lockRank = iota + + lockRankSysmon + lockRankScavenge + lockRankForcegc + lockRankDefer + lockRankSweepWaiters + lockRankAssistQueue + lockRankStrongFromWeakQueue + lockRankSweep + lockRankTestR + lockRankTestW + lockRankTimerSend + lockRankAllocmW + lockRankExecW + lockRankCpuprof + lockRankPollCache + lockRankPollDesc + lockRankWakeableSleep + lockRankHchan + // SCHED + lockRankAllocmR + lockRankExecR + lockRankSched + lockRankAllg + lockRankAllp + lockRankNotifyList + lockRankSudog + lockRankTimers + lockRankTimer + lockRankNetpollInit + lockRankRoot + lockRankItab + lockRankReflectOffs + lockRankUserArenaState + // TRACEGLOBAL + lockRankTraceBuf + lockRankTraceStrings + // MALLOC + lockRankFin + lockRankSpanSetSpine + lockRankMspanSpecial + lockRankTraceTypeTab + // MPROF + lockRankGcBitsArenas + lockRankProfInsert + lockRankProfBlock + lockRankProfMemActive + lockRankProfMemFuture + // STACKGROW + lockRankGscan + lockRankStackpool + lockRankStackLarge + lockRankHchanLeaf + // WB + lockRankWbufSpans + lockRankMheap + lockRankMheapSpecial + lockRankGlobalAlloc + // TRACE + lockRankTrace + lockRankTraceStackTab + lockRankPanic + lockRankDeadlock + lockRankRaceFini + lockRankAllocmRInternal + lockRankExecRInternal + lockRankTestRInternal +) + +// lockRankLeafRank is the rank of lock that does not have a declared rank, +// and hence is a leaf lock. +const lockRankLeafRank lockRank = 1000 + +// lockNames gives the names associated with each of the above ranks. +var lockNames = []string{ + lockRankSysmon: "sysmon", + lockRankScavenge: "scavenge", + lockRankForcegc: "forcegc", + lockRankDefer: "defer", + lockRankSweepWaiters: "sweepWaiters", + lockRankAssistQueue: "assistQueue", + lockRankStrongFromWeakQueue: "strongFromWeakQueue", + lockRankSweep: "sweep", + lockRankTestR: "testR", + lockRankTestW: "testW", + lockRankTimerSend: "timerSend", + lockRankAllocmW: "allocmW", + lockRankExecW: "execW", + lockRankCpuprof: "cpuprof", + lockRankPollCache: "pollCache", + lockRankPollDesc: "pollDesc", + lockRankWakeableSleep: "wakeableSleep", + lockRankHchan: "hchan", + lockRankAllocmR: "allocmR", + lockRankExecR: "execR", + lockRankSched: "sched", + lockRankAllg: "allg", + lockRankAllp: "allp", + lockRankNotifyList: "notifyList", + lockRankSudog: "sudog", + lockRankTimers: "timers", + lockRankTimer: "timer", + lockRankNetpollInit: "netpollInit", + lockRankRoot: "root", + lockRankItab: "itab", + lockRankReflectOffs: "reflectOffs", + lockRankUserArenaState: "userArenaState", + lockRankTraceBuf: "traceBuf", + lockRankTraceStrings: "traceStrings", + lockRankFin: "fin", + lockRankSpanSetSpine: "spanSetSpine", + lockRankMspanSpecial: "mspanSpecial", + lockRankTraceTypeTab: "traceTypeTab", + lockRankGcBitsArenas: "gcBitsArenas", + lockRankProfInsert: "profInsert", + lockRankProfBlock: "profBlock", + lockRankProfMemActive: "profMemActive", + lockRankProfMemFuture: "profMemFuture", + lockRankGscan: "gscan", + lockRankStackpool: "stackpool", + lockRankStackLarge: "stackLarge", + lockRankHchanLeaf: "hchanLeaf", + lockRankWbufSpans: "wbufSpans", + lockRankMheap: "mheap", + lockRankMheapSpecial: "mheapSpecial", + lockRankGlobalAlloc: "globalAlloc", + lockRankTrace: "trace", + lockRankTraceStackTab: "traceStackTab", + lockRankPanic: "panic", + lockRankDeadlock: "deadlock", + lockRankRaceFini: "raceFini", + lockRankAllocmRInternal: "allocmRInternal", + lockRankExecRInternal: "execRInternal", + lockRankTestRInternal: "testRInternal", +} + +func (rank lockRank) String() string { + if rank == 0 { + return "UNKNOWN" + } + if rank == lockRankLeafRank { + return "LEAF" + } + if rank < 0 || int(rank) >= len(lockNames) { + return "BAD RANK" + } + return lockNames[rank] +} + +// lockPartialOrder is the transitive closure of the lock rank graph. +// An entry for rank X lists all of the ranks that can already be held +// when rank X is acquired. +// +// Lock ranks that allow self-cycles list themselves. +var lockPartialOrder [][]lockRank = [][]lockRank{ + lockRankSysmon: {}, + lockRankScavenge: {lockRankSysmon}, + lockRankForcegc: {lockRankSysmon}, + lockRankDefer: {}, + lockRankSweepWaiters: {}, + lockRankAssistQueue: {}, + lockRankStrongFromWeakQueue: {}, + lockRankSweep: {}, + lockRankTestR: {}, + lockRankTestW: {}, + lockRankTimerSend: {}, + lockRankAllocmW: {}, + lockRankExecW: {}, + lockRankCpuprof: {}, + lockRankPollCache: {}, + lockRankPollDesc: {}, + lockRankWakeableSleep: {}, + lockRankHchan: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankWakeableSleep, lockRankHchan}, + lockRankAllocmR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan}, + lockRankExecR: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan}, + lockRankSched: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR}, + lockRankAllg: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched}, + lockRankAllp: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched}, + lockRankNotifyList: {}, + lockRankSudog: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankWakeableSleep, lockRankHchan, lockRankNotifyList}, + lockRankTimers: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers}, + lockRankTimer: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers}, + lockRankNetpollInit: {lockRankSysmon, lockRankScavenge, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankTimers, lockRankTimer}, + lockRankRoot: {}, + lockRankItab: {}, + lockRankReflectOffs: {lockRankItab}, + lockRankUserArenaState: {}, + lockRankTraceBuf: {lockRankSysmon, lockRankScavenge}, + lockRankTraceStrings: {lockRankSysmon, lockRankScavenge, lockRankTraceBuf}, + lockRankFin: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankTraceTypeTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankMspanSpecial}, + lockRankProfInsert: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankProfBlock: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankProfMemActive: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings}, + lockRankProfMemFuture: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankProfMemActive}, + lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture}, + lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, + lockRankStackLarge: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, + lockRankHchanLeaf: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankHchanLeaf}, + lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan}, + lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans}, + lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, + lockRankGlobalAlloc: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankMheapSpecial}, + lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap}, + lockRankTraceStackTab: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankDefer, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollCache, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR, lockRankExecR, lockRankSched, lockRankAllg, lockRankAllp, lockRankNotifyList, lockRankSudog, lockRankTimers, lockRankTimer, lockRankNetpollInit, lockRankRoot, lockRankItab, lockRankReflectOffs, lockRankUserArenaState, lockRankTraceBuf, lockRankTraceStrings, lockRankFin, lockRankSpanSetSpine, lockRankMspanSpecial, lockRankGcBitsArenas, lockRankProfInsert, lockRankProfBlock, lockRankProfMemActive, lockRankProfMemFuture, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankWbufSpans, lockRankMheap, lockRankTrace}, + lockRankPanic: {}, + lockRankDeadlock: {lockRankPanic, lockRankDeadlock}, + lockRankRaceFini: {lockRankPanic}, + lockRankAllocmRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankAllocmW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankAllocmR}, + lockRankExecRInternal: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankStrongFromWeakQueue, lockRankSweep, lockRankTestR, lockRankTimerSend, lockRankExecW, lockRankCpuprof, lockRankPollDesc, lockRankWakeableSleep, lockRankHchan, lockRankExecR}, + lockRankTestRInternal: {lockRankTestR, lockRankTestW}, +} diff --git a/contrib/go/_std_1.22/src/runtime/lockrank_off.go b/contrib/go/_std_1.23/src/runtime/lockrank_off.go similarity index 84% rename from contrib/go/_std_1.22/src/runtime/lockrank_off.go rename to contrib/go/_std_1.23/src/runtime/lockrank_off.go index c86726f3dd7d..18aef6bd2b3f 100644 --- a/contrib/go/_std_1.22/src/runtime/lockrank_off.go +++ b/contrib/go/_std_1.23/src/runtime/lockrank_off.go @@ -27,7 +27,8 @@ func lockWithRank(l *mutex, rank lockRank) { // This function may be called in nosplit context and thus must be nosplit. // //go:nosplit -func acquireLockRank(rank lockRank) { +func acquireLockRankAndM(rank lockRank) { + acquirem() } func unlockWithRank(l *mutex) { @@ -37,9 +38,13 @@ func unlockWithRank(l *mutex) { // This function may be called in nosplit context and thus must be nosplit. // //go:nosplit -func releaseLockRank(rank lockRank) { +func releaseLockRankAndM(rank lockRank) { + releasem(getg().m) } +// This function may be called in nosplit context and thus must be nosplit. +// +//go:nosplit func lockWithRankMayAcquire(l *mutex, rank lockRank) { } diff --git a/contrib/go/_std_1.22/src/runtime/lockrank_on.go b/contrib/go/_std_1.23/src/runtime/lockrank_on.go similarity index 94% rename from contrib/go/_std_1.22/src/runtime/lockrank_on.go rename to contrib/go/_std_1.23/src/runtime/lockrank_on.go index b1d99997947a..120ebc21fae5 100644 --- a/contrib/go/_std_1.22/src/runtime/lockrank_on.go +++ b/contrib/go/_std_1.23/src/runtime/lockrank_on.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -104,12 +104,16 @@ func printHeldLocks(gp *g) { } } -// acquireLockRank acquires a rank which is not associated with a mutex lock +// acquireLockRankAndM acquires a rank which is not associated with a mutex +// lock. To maintain the invariant that an M with m.locks==0 does not hold any +// lock-like resources, it also acquires the M. // // This function may be called in nosplit context and thus must be nosplit. // //go:nosplit -func acquireLockRank(rank lockRank) { +func acquireLockRankAndM(rank lockRank) { + acquirem() + gp := getg() // Log the new class. See comment on lockWithRank. systemstack(func() { @@ -189,12 +193,14 @@ func unlockWithRank(l *mutex) { }) } -// releaseLockRank releases a rank which is not associated with a mutex lock +// releaseLockRankAndM releases a rank which is not associated with a mutex +// lock. To maintain the invariant that an M with m.locks==0 does not hold any +// lock-like resources, it also releases the M. // // This function may be called in nosplit context and thus must be nosplit. // //go:nosplit -func releaseLockRank(rank lockRank) { +func releaseLockRankAndM(rank lockRank) { gp := getg() systemstack(func() { found := false @@ -211,6 +217,8 @@ func releaseLockRank(rank lockRank) { throw("lockRank release without matching lockRank acquire") } }) + + releasem(getg().m) } // nosplit because it may be called from nosplit contexts. diff --git a/contrib/go/_std_1.22/src/runtime/malloc.go b/contrib/go/_std_1.23/src/runtime/malloc.go similarity index 94% rename from contrib/go/_std_1.22/src/runtime/malloc.go rename to contrib/go/_std_1.23/src/runtime/malloc.go index e2cb2e456e86..b92a213245d4 100644 --- a/contrib/go/_std_1.22/src/runtime/malloc.go +++ b/contrib/go/_std_1.23/src/runtime/malloc.go @@ -102,9 +102,8 @@ package runtime import ( "internal/goarch" - "internal/goexperiment" "internal/goos" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/math" "runtime/internal/sys" "unsafe" @@ -425,26 +424,24 @@ func mallocinit() { print("pagesPerArena (", pagesPerArena, ") is not divisible by pagesPerReclaimerChunk (", pagesPerReclaimerChunk, ")\n") throw("bad pagesPerReclaimerChunk") } - if goexperiment.AllocHeaders { - // Check that the minimum size (exclusive) for a malloc header is also - // a size class boundary. This is important to making sure checks align - // across different parts of the runtime. - minSizeForMallocHeaderIsSizeClass := false - for i := 0; i < len(class_to_size); i++ { - if minSizeForMallocHeader == uintptr(class_to_size[i]) { - minSizeForMallocHeaderIsSizeClass = true - break - } - } - if !minSizeForMallocHeaderIsSizeClass { - throw("min size of malloc header is not a size class boundary") - } - // Check that the pointer bitmap for all small sizes without a malloc header - // fits in a word. - if minSizeForMallocHeader/goarch.PtrSize > 8*goarch.PtrSize { - throw("max pointer/scan bitmap size for headerless objects is too large") + // Check that the minimum size (exclusive) for a malloc header is also + // a size class boundary. This is important to making sure checks align + // across different parts of the runtime. + minSizeForMallocHeaderIsSizeClass := false + for i := 0; i < len(class_to_size); i++ { + if minSizeForMallocHeader == uintptr(class_to_size[i]) { + minSizeForMallocHeaderIsSizeClass = true + break } } + if !minSizeForMallocHeaderIsSizeClass { + throw("min size of malloc header is not a size class boundary") + } + // Check that the pointer bitmap for all small sizes without a malloc header + // fits in a word. + if minSizeForMallocHeader/goarch.PtrSize > 8*goarch.PtrSize { + throw("max pointer/scan bitmap size for headerless objects is too large") + } if minTagBits > taggedPointerBits { throw("taggedPointerbits too small") @@ -968,6 +965,21 @@ func (c *mcache) nextFree(spc spanClass) (v gclinkptr, s *mspan, shouldhelpgc bo // Allocate an object of size bytes. // Small objects are allocated from the per-P cache's free lists. // Large objects (> 32 kB) are allocated straight from the heap. +// +// mallocgc should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/cockroachdb/cockroach +// - github.com/cockroachdb/pebble +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mallocgc func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { if gcphase == _GCmarktermination { throw("mallocgc called with gcphase == _GCmarktermination") @@ -1043,7 +1055,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { var span *mspan var header **_type var x unsafe.Pointer - noscan := typ == nil || typ.PtrBytes == 0 + noscan := typ == nil || !typ.Pointers() // In some cases block zeroing can profitably (for latency reduction purposes) // be delayed till preemption is possible; delayedZeroing tracks that state. delayedZeroing := false @@ -1132,7 +1144,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { size = maxTinySize } else { hasHeader := !noscan && !heapBitsInSpan(size) - if goexperiment.AllocHeaders && hasHeader { + if hasHeader { size += mallocHeaderSize } var sizeclass uint8 @@ -1152,7 +1164,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { if needzero && span.needzero != 0 { memclrNoHeapPointers(x, size) } - if goexperiment.AllocHeaders && hasHeader { + if hasHeader { header = (**_type)(x) x = add(x, mallocHeaderSize) size -= mallocHeaderSize @@ -1168,34 +1180,16 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { size = span.elemsize x = unsafe.Pointer(span.base()) if needzero && span.needzero != 0 { - if noscan { - delayedZeroing = true - } else { - memclrNoHeapPointers(x, size) - } + delayedZeroing = true } - if goexperiment.AllocHeaders && !noscan { + if !noscan { + // Tell the GC not to look at this yet. + span.largeType = nil header = &span.largeType } } - if !noscan { - if goexperiment.AllocHeaders { - c.scanAlloc += heapSetType(uintptr(x), dataSize, typ, header, span) - } else { - var scanSize uintptr - heapBitsSetType(uintptr(x), size, dataSize, typ) - if dataSize > typ.Size_ { - // Array allocation. If there are any - // pointers, GC has to scan to the last - // element. - if typ.PtrBytes != 0 { - scanSize = dataSize - typ.Size_ + typ.PtrBytes - } - } else { - scanSize = typ.PtrBytes - } - c.scanAlloc += scanSize - } + if !noscan && !delayedZeroing { + c.scanAlloc += heapSetType(uintptr(x), dataSize, typ, header, span) } // Ensure that the stores above that initialize x to @@ -1243,19 +1237,11 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { asanunpoison(x, userSize) } - // If !goexperiment.AllocHeaders, "size" doesn't include the - // allocation header, so use span.elemsize as the "full" size - // for various computations below. - // // TODO(mknyszek): We should really count the header as part - // of gc_sys or something, but it's risky to change the - // accounting so much right now. Just pretend its internal - // fragmentation and match the GC's accounting by using the - // whole allocation slot. - fullSize := size - if goexperiment.AllocHeaders { - fullSize = span.elemsize - } + // of gc_sys or something. The code below just pretends it is + // internal fragmentation and matches the GC's accounting by + // using the whole allocation slot. + fullSize := span.elemsize if rate := MemProfileRate; rate > 0 { // Note cache c only valid while m acquired; see #47302 // @@ -1270,28 +1256,38 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer { mp.mallocing = 0 releasem(mp) - // Pointerfree data can be zeroed late in a context where preemption can occur. + // Objects can be zeroed late in a context where preemption can occur. + // If the object contains pointers, its pointer data must be cleared + // or otherwise indicate that the GC shouldn't scan it. // x will keep the memory alive. if delayedZeroing { - if !noscan { - throw("delayed zeroing on data that may contain pointers") - } - if goexperiment.AllocHeaders && header != nil { - throw("unexpected malloc header in delayed zeroing of large object") - } // N.B. size == fullSize always in this case. memclrNoHeapPointersChunked(size, x) // This is a possible preemption point: see #47302 - } - if debug.malloc { - if debug.allocfreetrace != 0 { - tracealloc(x, size, typ) + // Finish storing the type information for this case. + if !noscan { + mp := acquirem() + getMCache(mp).scanAlloc += heapSetType(uintptr(x), dataSize, typ, header, span) + + // Publish the type information with the zeroed memory. + publicationBarrier() + releasem(mp) } + } + if debug.malloc { if inittrace.active && inittrace.id == getg().goid { // Init functions are executed sequentially in a single goroutine. inittrace.bytes += uint64(fullSize) } + + if traceAllocFreeEnabled() { + trace := traceAcquire() + if trace.ok() { + trace.HeapObjectAlloc(uintptr(x), typ) + traceRelease(trace) + } + } } if assistG != nil { @@ -1390,6 +1386,17 @@ func newobject(typ *_type) unsafe.Pointer { return mallocgc(typ.Size_, typ, true) } +// reflect_unsafe_New is meant for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/goccy/json +// - github.com/modern-go/reflect2 +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_unsafe_New reflect.unsafe_New func reflect_unsafe_New(typ *_type) unsafe.Pointer { return mallocgc(typ.Size_, typ, true) @@ -1401,6 +1408,18 @@ func reflectlite_unsafe_New(typ *_type) unsafe.Pointer { } // newarray allocates an array of n elements of type typ. +// +// newarray should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname newarray func newarray(typ *_type, n int) unsafe.Pointer { if n == 1 { return mallocgc(typ.Size_, typ, true) @@ -1412,6 +1431,20 @@ func newarray(typ *_type, n int) unsafe.Pointer { return mallocgc(mem, typ, true) } +// reflect_unsafe_NewArray is meant for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/bytedance/sonic +// - github.com/goccy/json +// - github.com/modern-go/reflect2 +// - github.com/segmentio/encoding +// - github.com/segmentio/kafka-go +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_unsafe_NewArray reflect.unsafe_NewArray func reflect_unsafe_NewArray(typ *_type, n int) unsafe.Pointer { return newarray(typ, n) @@ -1423,7 +1456,7 @@ func profilealloc(mp *m, x unsafe.Pointer, size uintptr) { throw("profilealloc called without a P or outside bootstrapping") } c.nextSample = nextSample() - mProf_Malloc(x, size) + mProf_Malloc(mp, x, size) } // nextSample returns the next sampling point for heap profiling. The goal is diff --git a/contrib/go/_std_1.22/src/runtime/map.go b/contrib/go/_std_1.23/src/runtime/map.go similarity index 83% rename from contrib/go/_std_1.22/src/runtime/map.go rename to contrib/go/_std_1.23/src/runtime/map.go index cd3f838fa19c..52d56fb57a4d 100644 --- a/contrib/go/_std_1.22/src/runtime/map.go +++ b/contrib/go/_std_1.23/src/runtime/map.go @@ -56,7 +56,7 @@ package runtime import ( "internal/abi" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/math" "unsafe" ) @@ -64,20 +64,12 @@ import ( const ( // Maximum number of key/elem pairs a bucket can hold. bucketCntBits = abi.MapBucketCountBits - bucketCnt = abi.MapBucketCount // Maximum average load of a bucket that triggers growth is bucketCnt*13/16 (about 80% full) // Because of minimum alignment rules, bucketCnt is known to be at least 8. // Represent as loadFactorNum/loadFactorDen, to allow integer math. loadFactorDen = 2 - loadFactorNum = loadFactorDen * bucketCnt * 13 / 16 - - // Maximum key or elem size to keep inline (instead of mallocing per element). - // Must fit in a uint8. - // Fast versions cannot handle big elems - the cutoff size for - // fast versions in cmd/compile/internal/gc/walk.go must be at most this elem. - maxKeySize = abi.MapMaxKeyBytes - maxElemSize = abi.MapMaxElemBytes + loadFactorNum = loadFactorDen * abi.MapBucketCount * 13 / 16 // data offset should be the size of the bmap struct, but needs to be // aligned correctly. For amd64p32 this means 64-bit alignment @@ -152,7 +144,7 @@ type bmap struct { // tophash generally contains the top byte of the hash value // for each key in this bucket. If tophash[0] < minTopHash, // tophash[0] is a bucket evacuation state instead. - tophash [bucketCnt]uint8 + tophash [abi.MapBucketCount]uint8 // Followed by bucketCnt keys and then bucketCnt elems. // NOTE: packing all the keys together and then all the elems together makes the // code a bit more complicated than alternating key/elem/key/elem/... but it allows @@ -264,7 +256,7 @@ func (h *hmap) newoverflow(t *maptype, b *bmap) *bmap { ovf = (*bmap)(newobject(t.Bucket)) } h.incrnoverflow() - if t.Bucket.PtrBytes == 0 { + if !t.Bucket.Pointers() { h.createOverflow() *h.extra.overflow = append(*h.extra.overflow, ovf) } @@ -291,6 +283,16 @@ func makemap64(t *maptype, hint int64, h *hmap) *hmap { // makemap_small implements Go map creation for make(map[k]v) and // make(map[k]v, hint) when hint is known to be at most bucketCnt // at compile time and the map needs to be allocated on the heap. +// +// makemap_small should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname makemap_small func makemap_small() *hmap { h := new(hmap) h.hash0 = uint32(rand()) @@ -302,6 +304,17 @@ func makemap_small() *hmap { // can be created on the stack, h and/or bucket may be non-nil. // If h != nil, the map can be created directly in h. // If h.buckets != nil, bucket pointed to can be used as the first bucket. +// +// makemap should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname makemap func makemap(t *maptype, hint int, h *hmap) *hmap { mem, overflow := math.MulUintptr(uintptr(hint), t.Bucket.Size_) if overflow || mem > maxAlloc { @@ -354,7 +367,7 @@ func makeBucketArray(t *maptype, b uint8, dirtyalloc unsafe.Pointer) (buckets un // used with this value of b. nbuckets += bucketShift(b - 4) sz := t.Bucket.Size_ * nbuckets - up := roundupsize(sz, t.Bucket.PtrBytes == 0) + up := roundupsize(sz, !t.Bucket.Pointers()) if up != sz { nbuckets = up / t.Bucket.Size_ } @@ -368,7 +381,7 @@ func makeBucketArray(t *maptype, b uint8, dirtyalloc unsafe.Pointer) (buckets un // but may not be empty. buckets = dirtyalloc size := t.Bucket.Size_ * nbuckets - if t.Bucket.PtrBytes != 0 { + if t.Bucket.Pointers() { memclrHasPointers(buckets, size) } else { memclrNoHeapPointers(buckets, size) @@ -431,7 +444,7 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { top := tophash(hash) bucketloop: for ; b != nil; b = b.overflow(t) { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if b.tophash[i] != top { if b.tophash[i] == emptyRest { break bucketloop @@ -443,7 +456,7 @@ bucketloop: k = *((*unsafe.Pointer)(k)) } if t.Key.Equal(key, k) { - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) if t.IndirectElem() { e = *((*unsafe.Pointer)(e)) } @@ -454,6 +467,15 @@ bucketloop: return unsafe.Pointer(&zeroVal[0]) } +// mapaccess2 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapaccess2 func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) { if raceenabled && h != nil { callerpc := getcallerpc() @@ -492,7 +514,7 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) top := tophash(hash) bucketloop: for ; b != nil; b = b.overflow(t) { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if b.tophash[i] != top { if b.tophash[i] == emptyRest { break bucketloop @@ -504,7 +526,7 @@ bucketloop: k = *((*unsafe.Pointer)(k)) } if t.Key.Equal(key, k) { - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) if t.IndirectElem() { e = *((*unsafe.Pointer)(e)) } @@ -536,7 +558,7 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe top := tophash(hash) bucketloop: for ; b != nil; b = b.overflow(t) { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if b.tophash[i] != top { if b.tophash[i] == emptyRest { break bucketloop @@ -548,7 +570,7 @@ bucketloop: k = *((*unsafe.Pointer)(k)) } if t.Key.Equal(key, k) { - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) if t.IndirectElem() { e = *((*unsafe.Pointer)(e)) } @@ -576,6 +598,20 @@ func mapaccess2_fat(t *maptype, h *hmap, key, zero unsafe.Pointer) (unsafe.Point } // Like mapaccess, but allocates a slot for the key if it is not present in the map. +// +// mapassign should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapassign func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { if h == nil { panic(plainError("assignment to entry in nil map")) @@ -618,12 +654,12 @@ again: var elem unsafe.Pointer bucketloop: for { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if b.tophash[i] != top { if isEmpty(b.tophash[i]) && inserti == nil { inserti = &b.tophash[i] insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(t.KeySize)) - elem = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) + elem = add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) } if b.tophash[i] == emptyRest { break bucketloop @@ -641,7 +677,7 @@ bucketloop: if t.NeedKeyUpdate() { typedmemmove(t.Key, k, key) } - elem = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) + elem = add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) goto done } ovf := b.overflow(t) @@ -665,7 +701,7 @@ bucketloop: newb := h.newoverflow(t, b) inserti = &newb.tophash[0] insertk = add(unsafe.Pointer(newb), dataOffset) - elem = add(insertk, bucketCnt*uintptr(t.KeySize)) + elem = add(insertk, abi.MapBucketCount*uintptr(t.KeySize)) } // store new key/elem at insert position @@ -693,6 +729,15 @@ done: return elem } +// mapdelete should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapdelete func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { if raceenabled && h != nil { callerpc := getcallerpc() @@ -731,7 +776,7 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { top := tophash(hash) search: for ; b != nil; b = b.overflow(t) { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if b.tophash[i] != top { if b.tophash[i] == emptyRest { break search @@ -749,13 +794,13 @@ search: // Only clear key if there are pointers in it. if t.IndirectKey() { *(*unsafe.Pointer)(k) = nil - } else if t.Key.PtrBytes != 0 { + } else if t.Key.Pointers() { memclrHasPointers(k, t.Key.Size_) } - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) if t.IndirectElem() { *(*unsafe.Pointer)(e) = nil - } else if t.Elem.PtrBytes != 0 { + } else if t.Elem.Pointers() { memclrHasPointers(e, t.Elem.Size_) } else { memclrNoHeapPointers(e, t.Elem.Size_) @@ -765,7 +810,7 @@ search: // change those to emptyRest states. // It would be nice to make this a separate function, but // for loops are not currently inlineable. - if i == bucketCnt-1 { + if i == abi.MapBucketCount-1 { if b.overflow(t) != nil && b.overflow(t).tophash[0] != emptyRest { goto notLast } @@ -784,7 +829,7 @@ search: c := b for b = bOrig; b.overflow(t) != c; b = b.overflow(t) { } - i = bucketCnt - 1 + i = abi.MapBucketCount - 1 } else { i-- } @@ -813,6 +858,22 @@ search: // The hiter struct pointed to by 'it' is allocated on the stack // by the compilers order pass or on the heap by reflect_mapiterinit. // Both need to have zeroed hiter since the struct contains pointers. +// +// mapiterinit should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/goccy/go-json +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/ugorji/go/codec +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapiterinit func mapiterinit(t *maptype, h *hmap, it *hiter) { if raceenabled && h != nil { callerpc := getcallerpc() @@ -832,7 +893,7 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) { // grab snapshot of bucket state it.B = h.B it.buckets = h.buckets - if t.Bucket.PtrBytes == 0 { + if !t.Bucket.Pointers() { // Allocate the current slice and remember pointers to both current and old. // This preserves all relevant overflow buckets alive even if // the table grows and/or overflow buckets are added to the table @@ -845,7 +906,7 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) { // decide where to start r := uintptr(rand()) it.startBucket = r & bucketMask(h.B) - it.offset = uint8(r >> h.B & (bucketCnt - 1)) + it.offset = uint8(r >> h.B & (abi.MapBucketCount - 1)) // iterator state it.bucket = it.startBucket @@ -859,6 +920,20 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) { mapiternext(it) } +// mapiternext should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/ugorji/go/codec +// - gonum.org/v1/gonum +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapiternext func mapiternext(it *hiter) { h := it.h if raceenabled { @@ -906,8 +981,8 @@ next: } i = 0 } - for ; i < bucketCnt; i++ { - offi := (i + it.offset) & (bucketCnt - 1) + for ; i < abi.MapBucketCount; i++ { + offi := (i + it.offset) & (abi.MapBucketCount - 1) if isEmpty(b.tophash[offi]) || b.tophash[offi] == evacuatedEmpty { // TODO: emptyRest is hard to use here, as we start iterating // in the middle of a bucket. It's feasible, just tricky. @@ -917,7 +992,7 @@ next: if t.IndirectKey() { k = *((*unsafe.Pointer)(k)) } - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+uintptr(offi)*uintptr(t.ValueSize)) + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+uintptr(offi)*uintptr(t.ValueSize)) if checkBucket != noCheck && !h.sameSizeGrow() { // Special case: iterator was started during a grow to a larger size // and the grow is not done yet. We're working on a bucket whose @@ -986,6 +1061,17 @@ next: } // mapclear deletes all keys from a map. +// It is called by the compiler. +// +// mapclear should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapclear func mapclear(t *maptype, h *hmap) { if raceenabled && h != nil { callerpc := getcallerpc() @@ -1008,7 +1094,7 @@ func mapclear(t *maptype, h *hmap) { for i := uintptr(0); i <= mask; i++ { b := (*bmap)(add(bucket, i*uintptr(t.BucketSize))) for ; b != nil; b = b.overflow(t) { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { b.tophash[i] = emptyRest } } @@ -1095,7 +1181,7 @@ func hashGrow(t *maptype, h *hmap) { // overLoadFactor reports whether count items placed in 1< bucketCnt && uintptr(count) > loadFactorNum*(bucketShift(B)/loadFactorDen) + return count > abi.MapBucketCount && uintptr(count) > loadFactorNum*(bucketShift(B)/loadFactorDen) } // tooManyOverflowBuckets reports whether noverflow buckets is too many for a map with 1< maxKeySize && (!t.IndirectKey() || t.KeySize != uint8(goarch.PtrSize)) || - t.Key.Size_ <= maxKeySize && (t.IndirectKey() || t.KeySize != uint8(t.Key.Size_)) { + if t.Key.Size_ > abi.MapMaxKeyBytes && (!t.IndirectKey() || t.KeySize != uint8(goarch.PtrSize)) || + t.Key.Size_ <= abi.MapMaxKeyBytes && (t.IndirectKey() || t.KeySize != uint8(t.Key.Size_)) { throw("key size wrong") } - if t.Elem.Size_ > maxElemSize && (!t.IndirectElem() || t.ValueSize != uint8(goarch.PtrSize)) || - t.Elem.Size_ <= maxElemSize && (t.IndirectElem() || t.ValueSize != uint8(t.Elem.Size_)) { + if t.Elem.Size_ > abi.MapMaxElemBytes && (!t.IndirectElem() || t.ValueSize != uint8(goarch.PtrSize)) || + t.Elem.Size_ <= abi.MapMaxElemBytes && (t.IndirectElem() || t.ValueSize != uint8(t.Elem.Size_)) { throw("elem size wrong") } - if t.Key.Align_ > bucketCnt { + if t.Key.Align_ > abi.MapBucketCount { throw("key align too big") } - if t.Elem.Align_ > bucketCnt { + if t.Elem.Align_ > abi.MapBucketCount { throw("elem align too big") } if t.Key.Size_%uintptr(t.Key.Align_) != 0 { @@ -1327,7 +1431,7 @@ func reflect_makemap(t *maptype, cap int) *hmap { if t.Elem.Size_%uintptr(t.Elem.Align_) != 0 { throw("elem size not a multiple of elem align") } - if bucketCnt < 8 { + if abi.MapBucketCount < 8 { throw("bucketsize too small for proper alignment") } if dataOffset%uintptr(t.Key.Align_) != 0 { @@ -1340,6 +1444,16 @@ func reflect_makemap(t *maptype, cap int) *hmap { return makemap(t, cap, nil) } +// reflect_mapaccess is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_mapaccess reflect.mapaccess func reflect_mapaccess(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { elem, ok := mapaccess2(t, h, key) @@ -1360,6 +1474,14 @@ func reflect_mapaccess_faststr(t *maptype, h *hmap, key string) unsafe.Pointer { return elem } +// reflect_mapassign is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// //go:linkname reflect_mapassign reflect.mapassign0 func reflect_mapassign(t *maptype, h *hmap, key unsafe.Pointer, elem unsafe.Pointer) { p := mapassign(t, h, key) @@ -1382,26 +1504,76 @@ func reflect_mapdelete_faststr(t *maptype, h *hmap, key string) { mapdelete_faststr(t, h, key) } +// reflect_mapiterinit is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/modern-go/reflect2 +// - gitee.com/quant1x/gox +// - github.com/v2pro/plz +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_mapiterinit reflect.mapiterinit func reflect_mapiterinit(t *maptype, h *hmap, it *hiter) { mapiterinit(t, h, it) } +// reflect_mapiternext is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/goccy/go-json +// - github.com/v2pro/plz +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_mapiternext reflect.mapiternext func reflect_mapiternext(it *hiter) { mapiternext(it) } +// reflect_mapiterkey is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goccy/go-json +// - gonum.org/v1/gonum +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_mapiterkey reflect.mapiterkey func reflect_mapiterkey(it *hiter) unsafe.Pointer { return it.key } +// reflect_mapiterelem is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goccy/go-json +// - gonum.org/v1/gonum +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_mapiterelem reflect.mapiterelem func reflect_mapiterelem(it *hiter) unsafe.Pointer { return it.elem } +// reflect_maplen is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/goccy/go-json +// - github.com/wI2L/jettison +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_maplen reflect.maplen func reflect_maplen(h *hmap) int { if h == nil { @@ -1431,8 +1603,6 @@ func reflectlite_maplen(h *hmap) int { return h.count } -var zeroVal [abi.ZeroValSize]byte - // mapinitnoop is a no-op function known the Go linker; if a given global // map (of the right size) is determined to be dead, the linker will // rewrite the relocation (from the package init func) from the outlined @@ -1452,26 +1622,26 @@ func mapclone(m any) any { // moveToBmap moves a bucket from src to dst. It returns the destination bucket or new destination bucket if it overflows // and the pos that the next key/value will be written, if pos == bucketCnt means needs to written in overflow bucket. func moveToBmap(t *maptype, h *hmap, dst *bmap, pos int, src *bmap) (*bmap, int) { - for i := 0; i < bucketCnt; i++ { + for i := 0; i < abi.MapBucketCount; i++ { if isEmpty(src.tophash[i]) { continue } - for ; pos < bucketCnt; pos++ { + for ; pos < abi.MapBucketCount; pos++ { if isEmpty(dst.tophash[pos]) { break } } - if pos == bucketCnt { + if pos == abi.MapBucketCount { dst = h.newoverflow(t, dst) pos = 0 } srcK := add(unsafe.Pointer(src), dataOffset+uintptr(i)*uintptr(t.KeySize)) - srcEle := add(unsafe.Pointer(src), dataOffset+bucketCnt*uintptr(t.KeySize)+uintptr(i)*uintptr(t.ValueSize)) + srcEle := add(unsafe.Pointer(src), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+uintptr(i)*uintptr(t.ValueSize)) dstK := add(unsafe.Pointer(dst), dataOffset+uintptr(pos)*uintptr(t.KeySize)) - dstEle := add(unsafe.Pointer(dst), dataOffset+bucketCnt*uintptr(t.KeySize)+uintptr(pos)*uintptr(t.ValueSize)) + dstEle := add(unsafe.Pointer(dst), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+uintptr(pos)*uintptr(t.ValueSize)) dst.tophash[pos] = src.tophash[i] if t.IndirectKey() { @@ -1503,10 +1673,19 @@ func moveToBmap(t *maptype, h *hmap, dst *bmap, pos int, src *bmap) (*bmap, int) } func mapclone2(t *maptype, src *hmap) *hmap { - dst := makemap(t, src.count, nil) + hint := src.count + if overLoadFactor(hint, src.B) { + // Note: in rare cases (e.g. during a same-sized grow) the map + // can be overloaded. Make sure we don't allocate a destination + // bucket array larger than the source bucket array. + // This will cause the cloned map to be overloaded also, + // but that's better than crashing. See issue 69110. + hint = int(loadFactorNum * (bucketShift(src.B) / loadFactorDen)) + } + dst := makemap(t, hint, nil) dst.hash0 = src.hash0 dst.nevacuate = 0 - //flags do not need to be copied here, just like a new map has no flags. + // flags do not need to be copied here, just like a new map has no flags. if src.count == 0 { return dst @@ -1575,7 +1754,7 @@ func mapclone2(t *maptype, src *hmap) *hmap { // Process entries one at a time. for srcBmap != nil { // move from oldBlucket to new bucket - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if isEmpty(srcBmap.tophash[i]) { continue } @@ -1589,7 +1768,7 @@ func mapclone2(t *maptype, src *hmap) *hmap { srcK = *((*unsafe.Pointer)(srcK)) } - srcEle := add(unsafe.Pointer(srcBmap), dataOffset+bucketCnt*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) + srcEle := add(unsafe.Pointer(srcBmap), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+i*uintptr(t.ValueSize)) if t.IndirectElem() { srcEle = *((*unsafe.Pointer)(srcEle)) } @@ -1615,7 +1794,7 @@ func keys(m any, p unsafe.Pointer) { } s := (*slice)(p) r := int(rand()) - offset := uint8(r >> h.B & (bucketCnt - 1)) + offset := uint8(r >> h.B & (abi.MapBucketCount - 1)) if h.B == 0 { copyKeys(t, h, (*bmap)(h.buckets), s, offset) return @@ -1644,8 +1823,8 @@ func keys(m any, p unsafe.Pointer) { func copyKeys(t *maptype, h *hmap, b *bmap, s *slice, offset uint8) { for b != nil { - for i := uintptr(0); i < bucketCnt; i++ { - offi := (i + uintptr(offset)) & (bucketCnt - 1) + for i := uintptr(0); i < abi.MapBucketCount; i++ { + offi := (i + uintptr(offset)) & (abi.MapBucketCount - 1) if isEmpty(b.tophash[offi]) { continue } @@ -1678,7 +1857,7 @@ func values(m any, p unsafe.Pointer) { } s := (*slice)(p) r := int(rand()) - offset := uint8(r >> h.B & (bucketCnt - 1)) + offset := uint8(r >> h.B & (abi.MapBucketCount - 1)) if h.B == 0 { copyValues(t, h, (*bmap)(h.buckets), s, offset) return @@ -1707,8 +1886,8 @@ func values(m any, p unsafe.Pointer) { func copyValues(t *maptype, h *hmap, b *bmap, s *slice, offset uint8) { for b != nil { - for i := uintptr(0); i < bucketCnt; i++ { - offi := (i + uintptr(offset)) & (bucketCnt - 1) + for i := uintptr(0); i < abi.MapBucketCount; i++ { + offi := (i + uintptr(offset)) & (abi.MapBucketCount - 1) if isEmpty(b.tophash[offi]) { continue } @@ -1717,7 +1896,7 @@ func copyValues(t *maptype, h *hmap, b *bmap, s *slice, offset uint8) { fatal("concurrent map read and map write") } - ele := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.KeySize)+offi*uintptr(t.ValueSize)) + ele := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*uintptr(t.KeySize)+offi*uintptr(t.ValueSize)) if t.IndirectElem() { ele = *((*unsafe.Pointer)(ele)) } diff --git a/contrib/go/_std_1.22/src/runtime/map_fast32.go b/contrib/go/_std_1.23/src/runtime/map_fast32.go similarity index 81% rename from contrib/go/_std_1.22/src/runtime/map_fast32.go rename to contrib/go/_std_1.23/src/runtime/map_fast32.go index e1dd495365b3..0eb8562f5102 100644 --- a/contrib/go/_std_1.22/src/runtime/map_fast32.go +++ b/contrib/go/_std_1.23/src/runtime/map_fast32.go @@ -41,15 +41,24 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { } } for ; b != nil; b = b.overflow(t) { - for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 4) { + for i, k := uintptr(0), b.keys(); i < abi.MapBucketCount; i, k = i+1, add(k, 4) { if *(*uint32)(k) == key && !isEmpty(b.tophash[i]) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.ValueSize)) + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*4+i*uintptr(t.ValueSize)) } } } return unsafe.Pointer(&zeroVal[0]) } +// mapaccess2_fast32 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapaccess2_fast32 func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) { if raceenabled && h != nil { callerpc := getcallerpc() @@ -81,15 +90,26 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) { } } for ; b != nil; b = b.overflow(t) { - for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 4) { + for i, k := uintptr(0), b.keys(); i < abi.MapBucketCount; i, k = i+1, add(k, 4) { if *(*uint32)(k) == key && !isEmpty(b.tophash[i]) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.ValueSize)), true + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*4+i*uintptr(t.ValueSize)), true } } } return unsafe.Pointer(&zeroVal[0]), false } +// mapassign_fast32 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapassign_fast32 func mapassign_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { if h == nil { panic(plainError("assignment to entry in nil map")) @@ -123,7 +143,7 @@ again: bucketloop: for { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if isEmpty(b.tophash[i]) { if insertb == nil { inserti = i @@ -163,7 +183,7 @@ bucketloop: insertb = h.newoverflow(t, b) inserti = 0 // not necessary, but avoids needlessly spilling inserti } - insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash) // mask inserti to avoid bounds checks + insertb.tophash[inserti&(abi.MapBucketCount-1)] = tophash(hash) // mask inserti to avoid bounds checks insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*4) // store new key at insert position @@ -172,7 +192,7 @@ bucketloop: h.count++ done: - elem := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*4+inserti*uintptr(t.ValueSize)) + elem := add(unsafe.Pointer(insertb), dataOffset+abi.MapBucketCount*4+inserti*uintptr(t.ValueSize)) if h.flags&hashWriting == 0 { fatal("concurrent map writes") } @@ -180,6 +200,15 @@ done: return elem } +// mapassign_fast32ptr should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapassign_fast32ptr func mapassign_fast32ptr(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { if h == nil { panic(plainError("assignment to entry in nil map")) @@ -213,7 +242,7 @@ again: bucketloop: for { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if isEmpty(b.tophash[i]) { if insertb == nil { inserti = i @@ -253,7 +282,7 @@ bucketloop: insertb = h.newoverflow(t, b) inserti = 0 // not necessary, but avoids needlessly spilling inserti } - insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash) // mask inserti to avoid bounds checks + insertb.tophash[inserti&(abi.MapBucketCount-1)] = tophash(hash) // mask inserti to avoid bounds checks insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*4) // store new key at insert position @@ -262,7 +291,7 @@ bucketloop: h.count++ done: - elem := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*4+inserti*uintptr(t.ValueSize)) + elem := add(unsafe.Pointer(insertb), dataOffset+abi.MapBucketCount*4+inserti*uintptr(t.ValueSize)) if h.flags&hashWriting == 0 { fatal("concurrent map writes") } @@ -295,20 +324,20 @@ func mapdelete_fast32(t *maptype, h *hmap, key uint32) { bOrig := b search: for ; b != nil; b = b.overflow(t) { - for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 4) { + for i, k := uintptr(0), b.keys(); i < abi.MapBucketCount; i, k = i+1, add(k, 4) { if key != *(*uint32)(k) || isEmpty(b.tophash[i]) { continue } // Only clear key if there are pointers in it. // This can only happen if pointers are 32 bit // wide as 64 bit pointers do not fit into a 32 bit key. - if goarch.PtrSize == 4 && t.Key.PtrBytes != 0 { + if goarch.PtrSize == 4 && t.Key.Pointers() { // The key must be a pointer as we checked pointers are // 32 bits wide and the key is 32 bits wide also. *(*unsafe.Pointer)(k) = nil } - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.ValueSize)) - if t.Elem.PtrBytes != 0 { + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*4+i*uintptr(t.ValueSize)) + if t.Elem.Pointers() { memclrHasPointers(e, t.Elem.Size_) } else { memclrNoHeapPointers(e, t.Elem.Size_) @@ -316,7 +345,7 @@ search: b.tophash[i] = emptyOne // If the bucket now ends in a bunch of emptyOne states, // change those to emptyRest states. - if i == bucketCnt-1 { + if i == abi.MapBucketCount-1 { if b.overflow(t) != nil && b.overflow(t).tophash[0] != emptyRest { goto notLast } @@ -335,7 +364,7 @@ search: c := b for b = bOrig; b.overflow(t) != c; b = b.overflow(t) { } - i = bucketCnt - 1 + i = abi.MapBucketCount - 1 } else { i-- } @@ -383,7 +412,7 @@ func evacuate_fast32(t *maptype, h *hmap, oldbucket uintptr) { x := &xy[0] x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.BucketSize))) x.k = add(unsafe.Pointer(x.b), dataOffset) - x.e = add(x.k, bucketCnt*4) + x.e = add(x.k, abi.MapBucketCount*4) if !h.sameSizeGrow() { // Only calculate y pointers if we're growing bigger. @@ -391,13 +420,13 @@ func evacuate_fast32(t *maptype, h *hmap, oldbucket uintptr) { y := &xy[1] y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.BucketSize))) y.k = add(unsafe.Pointer(y.b), dataOffset) - y.e = add(y.k, bucketCnt*4) + y.e = add(y.k, abi.MapBucketCount*4) } for ; b != nil; b = b.overflow(t) { k := add(unsafe.Pointer(b), dataOffset) - e := add(k, bucketCnt*4) - for i := 0; i < bucketCnt; i, k, e = i+1, add(k, 4), add(e, uintptr(t.ValueSize)) { + e := add(k, abi.MapBucketCount*4) + for i := 0; i < abi.MapBucketCount; i, k, e = i+1, add(k, 4), add(e, uintptr(t.ValueSize)) { top := b.tophash[i] if isEmpty(top) { b.tophash[i] = evacuatedEmpty @@ -419,16 +448,16 @@ func evacuate_fast32(t *maptype, h *hmap, oldbucket uintptr) { b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY, enforced in makemap dst := &xy[useY] // evacuation destination - if dst.i == bucketCnt { + if dst.i == abi.MapBucketCount { dst.b = h.newoverflow(t, dst.b) dst.i = 0 dst.k = add(unsafe.Pointer(dst.b), dataOffset) - dst.e = add(dst.k, bucketCnt*4) + dst.e = add(dst.k, abi.MapBucketCount*4) } - dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check + dst.b.tophash[dst.i&(abi.MapBucketCount-1)] = top // mask dst.i as an optimization, to avoid a bounds check // Copy key. - if goarch.PtrSize == 4 && t.Key.PtrBytes != 0 && writeBarrier.enabled { + if goarch.PtrSize == 4 && t.Key.Pointers() && writeBarrier.enabled { // Write with a write barrier. *(*unsafe.Pointer)(dst.k) = *(*unsafe.Pointer)(k) } else { @@ -446,7 +475,7 @@ func evacuate_fast32(t *maptype, h *hmap, oldbucket uintptr) { } } // Unlink the overflow buckets & clear key/elem to help GC. - if h.flags&oldIterator == 0 && t.Bucket.PtrBytes != 0 { + if h.flags&oldIterator == 0 && t.Bucket.Pointers() { b := add(h.oldbuckets, oldbucket*uintptr(t.BucketSize)) // Preserve b.tophash because the evacuation // state is maintained there. diff --git a/contrib/go/_std_1.22/src/runtime/map_fast64.go b/contrib/go/_std_1.23/src/runtime/map_fast64.go similarity index 81% rename from contrib/go/_std_1.22/src/runtime/map_fast64.go rename to contrib/go/_std_1.23/src/runtime/map_fast64.go index 7ca35ec6cb13..aca60eb2a80b 100644 --- a/contrib/go/_std_1.22/src/runtime/map_fast64.go +++ b/contrib/go/_std_1.23/src/runtime/map_fast64.go @@ -41,15 +41,24 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer { } } for ; b != nil; b = b.overflow(t) { - for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 8) { + for i, k := uintptr(0), b.keys(); i < abi.MapBucketCount; i, k = i+1, add(k, 8) { if *(*uint64)(k) == key && !isEmpty(b.tophash[i]) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.ValueSize)) + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*8+i*uintptr(t.ValueSize)) } } } return unsafe.Pointer(&zeroVal[0]) } +// mapaccess2_fast64 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapaccess2_fast64 func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) { if raceenabled && h != nil { callerpc := getcallerpc() @@ -81,15 +90,26 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) { } } for ; b != nil; b = b.overflow(t) { - for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 8) { + for i, k := uintptr(0), b.keys(); i < abi.MapBucketCount; i, k = i+1, add(k, 8) { if *(*uint64)(k) == key && !isEmpty(b.tophash[i]) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.ValueSize)), true + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*8+i*uintptr(t.ValueSize)), true } } } return unsafe.Pointer(&zeroVal[0]), false } +// mapassign_fast64 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapassign_fast64 func mapassign_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer { if h == nil { panic(plainError("assignment to entry in nil map")) @@ -123,7 +143,7 @@ again: bucketloop: for { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if isEmpty(b.tophash[i]) { if insertb == nil { insertb = b @@ -163,7 +183,7 @@ bucketloop: insertb = h.newoverflow(t, b) inserti = 0 // not necessary, but avoids needlessly spilling inserti } - insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash) // mask inserti to avoid bounds checks + insertb.tophash[inserti&(abi.MapBucketCount-1)] = tophash(hash) // mask inserti to avoid bounds checks insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*8) // store new key at insert position @@ -172,7 +192,7 @@ bucketloop: h.count++ done: - elem := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*8+inserti*uintptr(t.ValueSize)) + elem := add(unsafe.Pointer(insertb), dataOffset+abi.MapBucketCount*8+inserti*uintptr(t.ValueSize)) if h.flags&hashWriting == 0 { fatal("concurrent map writes") } @@ -180,6 +200,17 @@ done: return elem } +// mapassign_fast64ptr should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapassign_fast64ptr func mapassign_fast64ptr(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { if h == nil { panic(plainError("assignment to entry in nil map")) @@ -213,7 +244,7 @@ again: bucketloop: for { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if isEmpty(b.tophash[i]) { if insertb == nil { insertb = b @@ -253,7 +284,7 @@ bucketloop: insertb = h.newoverflow(t, b) inserti = 0 // not necessary, but avoids needlessly spilling inserti } - insertb.tophash[inserti&(bucketCnt-1)] = tophash(hash) // mask inserti to avoid bounds checks + insertb.tophash[inserti&(abi.MapBucketCount-1)] = tophash(hash) // mask inserti to avoid bounds checks insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*8) // store new key at insert position @@ -262,7 +293,7 @@ bucketloop: h.count++ done: - elem := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*8+inserti*uintptr(t.ValueSize)) + elem := add(unsafe.Pointer(insertb), dataOffset+abi.MapBucketCount*8+inserti*uintptr(t.ValueSize)) if h.flags&hashWriting == 0 { fatal("concurrent map writes") } @@ -295,12 +326,12 @@ func mapdelete_fast64(t *maptype, h *hmap, key uint64) { bOrig := b search: for ; b != nil; b = b.overflow(t) { - for i, k := uintptr(0), b.keys(); i < bucketCnt; i, k = i+1, add(k, 8) { + for i, k := uintptr(0), b.keys(); i < abi.MapBucketCount; i, k = i+1, add(k, 8) { if key != *(*uint64)(k) || isEmpty(b.tophash[i]) { continue } // Only clear key if there are pointers in it. - if t.Key.PtrBytes != 0 { + if t.Key.Pointers() { if goarch.PtrSize == 8 { *(*unsafe.Pointer)(k) = nil } else { @@ -309,8 +340,8 @@ search: memclrHasPointers(k, 8) } } - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.ValueSize)) - if t.Elem.PtrBytes != 0 { + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*8+i*uintptr(t.ValueSize)) + if t.Elem.Pointers() { memclrHasPointers(e, t.Elem.Size_) } else { memclrNoHeapPointers(e, t.Elem.Size_) @@ -318,7 +349,7 @@ search: b.tophash[i] = emptyOne // If the bucket now ends in a bunch of emptyOne states, // change those to emptyRest states. - if i == bucketCnt-1 { + if i == abi.MapBucketCount-1 { if b.overflow(t) != nil && b.overflow(t).tophash[0] != emptyRest { goto notLast } @@ -337,7 +368,7 @@ search: c := b for b = bOrig; b.overflow(t) != c; b = b.overflow(t) { } - i = bucketCnt - 1 + i = abi.MapBucketCount - 1 } else { i-- } @@ -385,7 +416,7 @@ func evacuate_fast64(t *maptype, h *hmap, oldbucket uintptr) { x := &xy[0] x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.BucketSize))) x.k = add(unsafe.Pointer(x.b), dataOffset) - x.e = add(x.k, bucketCnt*8) + x.e = add(x.k, abi.MapBucketCount*8) if !h.sameSizeGrow() { // Only calculate y pointers if we're growing bigger. @@ -393,13 +424,13 @@ func evacuate_fast64(t *maptype, h *hmap, oldbucket uintptr) { y := &xy[1] y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.BucketSize))) y.k = add(unsafe.Pointer(y.b), dataOffset) - y.e = add(y.k, bucketCnt*8) + y.e = add(y.k, abi.MapBucketCount*8) } for ; b != nil; b = b.overflow(t) { k := add(unsafe.Pointer(b), dataOffset) - e := add(k, bucketCnt*8) - for i := 0; i < bucketCnt; i, k, e = i+1, add(k, 8), add(e, uintptr(t.ValueSize)) { + e := add(k, abi.MapBucketCount*8) + for i := 0; i < abi.MapBucketCount; i, k, e = i+1, add(k, 8), add(e, uintptr(t.ValueSize)) { top := b.tophash[i] if isEmpty(top) { b.tophash[i] = evacuatedEmpty @@ -421,16 +452,16 @@ func evacuate_fast64(t *maptype, h *hmap, oldbucket uintptr) { b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY, enforced in makemap dst := &xy[useY] // evacuation destination - if dst.i == bucketCnt { + if dst.i == abi.MapBucketCount { dst.b = h.newoverflow(t, dst.b) dst.i = 0 dst.k = add(unsafe.Pointer(dst.b), dataOffset) - dst.e = add(dst.k, bucketCnt*8) + dst.e = add(dst.k, abi.MapBucketCount*8) } - dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check + dst.b.tophash[dst.i&(abi.MapBucketCount-1)] = top // mask dst.i as an optimization, to avoid a bounds check // Copy key. - if t.Key.PtrBytes != 0 && writeBarrier.enabled { + if t.Key.Pointers() && writeBarrier.enabled { if goarch.PtrSize == 8 { // Write with a write barrier. *(*unsafe.Pointer)(dst.k) = *(*unsafe.Pointer)(k) @@ -454,7 +485,7 @@ func evacuate_fast64(t *maptype, h *hmap, oldbucket uintptr) { } } // Unlink the overflow buckets & clear key/elem to help GC. - if h.flags&oldIterator == 0 && t.Bucket.PtrBytes != 0 { + if h.flags&oldIterator == 0 && t.Bucket.Pointers() { b := add(h.oldbuckets, oldbucket*uintptr(t.BucketSize)) // Preserve b.tophash because the evacuation // state is maintained there. diff --git a/contrib/go/_std_1.22/src/runtime/map_faststr.go b/contrib/go/_std_1.23/src/runtime/map_faststr.go similarity index 77% rename from contrib/go/_std_1.22/src/runtime/map_faststr.go rename to contrib/go/_std_1.23/src/runtime/map_faststr.go index 22e1f61f0660..5461a9f81e81 100644 --- a/contrib/go/_std_1.22/src/runtime/map_faststr.go +++ b/contrib/go/_std_1.23/src/runtime/map_faststr.go @@ -27,7 +27,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { b := (*bmap)(h.buckets) if key.len < 32 { // short key, doing lots of comparisons is ok - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < abi.MapBucketCount; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || isEmpty(b.tophash[i]) { if b.tophash[i] == emptyRest { @@ -36,14 +36,14 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { continue } if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.ValueSize)) + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+i*uintptr(t.ValueSize)) } } return unsafe.Pointer(&zeroVal[0]) } // long key, try not to do more comparisons than necessary - keymaybe := uintptr(bucketCnt) - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { + keymaybe := uintptr(abi.MapBucketCount) + for i, kptr := uintptr(0), b.keys(); i < abi.MapBucketCount; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || isEmpty(b.tophash[i]) { if b.tophash[i] == emptyRest { @@ -52,7 +52,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { continue } if k.str == key.str { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.ValueSize)) + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+i*uintptr(t.ValueSize)) } // check first 4 bytes if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) { @@ -62,16 +62,16 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { if *((*[4]byte)(add(key.str, uintptr(key.len)-4))) != *((*[4]byte)(add(k.str, uintptr(key.len)-4))) { continue } - if keymaybe != bucketCnt { + if keymaybe != abi.MapBucketCount { // Two keys are potential matches. Use hash to distinguish them. goto dohash } keymaybe = i } - if keymaybe != bucketCnt { + if keymaybe != abi.MapBucketCount { k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*goarch.PtrSize)) if memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+keymaybe*uintptr(t.ValueSize)) + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+keymaybe*uintptr(t.ValueSize)) } } return unsafe.Pointer(&zeroVal[0]) @@ -92,19 +92,28 @@ dohash: } top := tophash(hash) for ; b != nil; b = b.overflow(t) { - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < abi.MapBucketCount; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || b.tophash[i] != top { continue } if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.ValueSize)) + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+i*uintptr(t.ValueSize)) } } } return unsafe.Pointer(&zeroVal[0]) } +// mapaccess2_faststr should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapaccess2_faststr func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { if raceenabled && h != nil { callerpc := getcallerpc() @@ -122,7 +131,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { b := (*bmap)(h.buckets) if key.len < 32 { // short key, doing lots of comparisons is ok - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < abi.MapBucketCount; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || isEmpty(b.tophash[i]) { if b.tophash[i] == emptyRest { @@ -131,14 +140,14 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { continue } if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.ValueSize)), true + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+i*uintptr(t.ValueSize)), true } } return unsafe.Pointer(&zeroVal[0]), false } // long key, try not to do more comparisons than necessary - keymaybe := uintptr(bucketCnt) - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { + keymaybe := uintptr(abi.MapBucketCount) + for i, kptr := uintptr(0), b.keys(); i < abi.MapBucketCount; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || isEmpty(b.tophash[i]) { if b.tophash[i] == emptyRest { @@ -147,7 +156,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { continue } if k.str == key.str { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.ValueSize)), true + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+i*uintptr(t.ValueSize)), true } // check first 4 bytes if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) { @@ -157,16 +166,16 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { if *((*[4]byte)(add(key.str, uintptr(key.len)-4))) != *((*[4]byte)(add(k.str, uintptr(key.len)-4))) { continue } - if keymaybe != bucketCnt { + if keymaybe != abi.MapBucketCount { // Two keys are potential matches. Use hash to distinguish them. goto dohash } keymaybe = i } - if keymaybe != bucketCnt { + if keymaybe != abi.MapBucketCount { k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*goarch.PtrSize)) if memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+keymaybe*uintptr(t.ValueSize)), true + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+keymaybe*uintptr(t.ValueSize)), true } } return unsafe.Pointer(&zeroVal[0]), false @@ -187,19 +196,30 @@ dohash: } top := tophash(hash) for ; b != nil; b = b.overflow(t) { - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < abi.MapBucketCount; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || b.tophash[i] != top { continue } if k.str == key.str || memequal(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.ValueSize)), true + return add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+i*uintptr(t.ValueSize)), true } } } return unsafe.Pointer(&zeroVal[0]), false } +// mapassign_faststr should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mapassign_faststr func mapassign_faststr(t *maptype, h *hmap, s string) unsafe.Pointer { if h == nil { panic(plainError("assignment to entry in nil map")) @@ -235,7 +255,7 @@ again: bucketloop: for { - for i := uintptr(0); i < bucketCnt; i++ { + for i := uintptr(0); i < abi.MapBucketCount; i++ { if b.tophash[i] != top { if isEmpty(b.tophash[i]) && insertb == nil { insertb = b @@ -282,7 +302,7 @@ bucketloop: insertb = h.newoverflow(t, b) inserti = 0 // not necessary, but avoids needlessly spilling inserti } - insertb.tophash[inserti&(bucketCnt-1)] = top // mask inserti to avoid bounds checks + insertb.tophash[inserti&(abi.MapBucketCount-1)] = top // mask inserti to avoid bounds checks insertk = add(unsafe.Pointer(insertb), dataOffset+inserti*2*goarch.PtrSize) // store new key at insert position @@ -290,7 +310,7 @@ bucketloop: h.count++ done: - elem := add(unsafe.Pointer(insertb), dataOffset+bucketCnt*2*goarch.PtrSize+inserti*uintptr(t.ValueSize)) + elem := add(unsafe.Pointer(insertb), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+inserti*uintptr(t.ValueSize)) if h.flags&hashWriting == 0 { fatal("concurrent map writes") } @@ -325,7 +345,7 @@ func mapdelete_faststr(t *maptype, h *hmap, ky string) { top := tophash(hash) search: for ; b != nil; b = b.overflow(t) { - for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { + for i, kptr := uintptr(0), b.keys(); i < abi.MapBucketCount; i, kptr = i+1, add(kptr, 2*goarch.PtrSize) { k := (*stringStruct)(kptr) if k.len != key.len || b.tophash[i] != top { continue @@ -335,8 +355,8 @@ search: } // Clear key's pointer. k.str = nil - e := add(unsafe.Pointer(b), dataOffset+bucketCnt*2*goarch.PtrSize+i*uintptr(t.ValueSize)) - if t.Elem.PtrBytes != 0 { + e := add(unsafe.Pointer(b), dataOffset+abi.MapBucketCount*2*goarch.PtrSize+i*uintptr(t.ValueSize)) + if t.Elem.Pointers() { memclrHasPointers(e, t.Elem.Size_) } else { memclrNoHeapPointers(e, t.Elem.Size_) @@ -344,7 +364,7 @@ search: b.tophash[i] = emptyOne // If the bucket now ends in a bunch of emptyOne states, // change those to emptyRest states. - if i == bucketCnt-1 { + if i == abi.MapBucketCount-1 { if b.overflow(t) != nil && b.overflow(t).tophash[0] != emptyRest { goto notLast } @@ -363,7 +383,7 @@ search: c := b for b = bOrig; b.overflow(t) != c; b = b.overflow(t) { } - i = bucketCnt - 1 + i = abi.MapBucketCount - 1 } else { i-- } @@ -411,7 +431,7 @@ func evacuate_faststr(t *maptype, h *hmap, oldbucket uintptr) { x := &xy[0] x.b = (*bmap)(add(h.buckets, oldbucket*uintptr(t.BucketSize))) x.k = add(unsafe.Pointer(x.b), dataOffset) - x.e = add(x.k, bucketCnt*2*goarch.PtrSize) + x.e = add(x.k, abi.MapBucketCount*2*goarch.PtrSize) if !h.sameSizeGrow() { // Only calculate y pointers if we're growing bigger. @@ -419,13 +439,13 @@ func evacuate_faststr(t *maptype, h *hmap, oldbucket uintptr) { y := &xy[1] y.b = (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.BucketSize))) y.k = add(unsafe.Pointer(y.b), dataOffset) - y.e = add(y.k, bucketCnt*2*goarch.PtrSize) + y.e = add(y.k, abi.MapBucketCount*2*goarch.PtrSize) } for ; b != nil; b = b.overflow(t) { k := add(unsafe.Pointer(b), dataOffset) - e := add(k, bucketCnt*2*goarch.PtrSize) - for i := 0; i < bucketCnt; i, k, e = i+1, add(k, 2*goarch.PtrSize), add(e, uintptr(t.ValueSize)) { + e := add(k, abi.MapBucketCount*2*goarch.PtrSize) + for i := 0; i < abi.MapBucketCount; i, k, e = i+1, add(k, 2*goarch.PtrSize), add(e, uintptr(t.ValueSize)) { top := b.tophash[i] if isEmpty(top) { b.tophash[i] = evacuatedEmpty @@ -447,13 +467,13 @@ func evacuate_faststr(t *maptype, h *hmap, oldbucket uintptr) { b.tophash[i] = evacuatedX + useY // evacuatedX + 1 == evacuatedY, enforced in makemap dst := &xy[useY] // evacuation destination - if dst.i == bucketCnt { + if dst.i == abi.MapBucketCount { dst.b = h.newoverflow(t, dst.b) dst.i = 0 dst.k = add(unsafe.Pointer(dst.b), dataOffset) - dst.e = add(dst.k, bucketCnt*2*goarch.PtrSize) + dst.e = add(dst.k, abi.MapBucketCount*2*goarch.PtrSize) } - dst.b.tophash[dst.i&(bucketCnt-1)] = top // mask dst.i as an optimization, to avoid a bounds check + dst.b.tophash[dst.i&(abi.MapBucketCount-1)] = top // mask dst.i as an optimization, to avoid a bounds check // Copy key. *(*string)(dst.k) = *(*string)(k) @@ -469,7 +489,7 @@ func evacuate_faststr(t *maptype, h *hmap, oldbucket uintptr) { } } // Unlink the overflow buckets & clear key/elem to help GC. - if h.flags&oldIterator == 0 && t.Bucket.PtrBytes != 0 { + if h.flags&oldIterator == 0 && t.Bucket.Pointers() { b := add(h.oldbuckets, oldbucket*uintptr(t.BucketSize)) // Preserve b.tophash because the evacuation // state is maintained there. diff --git a/contrib/go/_std_1.22/src/runtime/mbarrier.go b/contrib/go/_std_1.23/src/runtime/mbarrier.go similarity index 85% rename from contrib/go/_std_1.22/src/runtime/mbarrier.go rename to contrib/go/_std_1.23/src/runtime/mbarrier.go index c4b6c2a789cd..7dc8a1a5e56d 100644 --- a/contrib/go/_std_1.22/src/runtime/mbarrier.go +++ b/contrib/go/_std_1.23/src/runtime/mbarrier.go @@ -148,12 +148,22 @@ import ( // TODO: Perfect for go:nosplitrec since we can't have a safe point // anywhere in the bulk barrier or memmove. // +// typedmemmove should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname typedmemmove //go:nosplit func typedmemmove(typ *abi.Type, dst, src unsafe.Pointer) { if dst == src { return } - if writeBarrier.enabled && typ.PtrBytes != 0 { + if writeBarrier.enabled && typ.Pointers() { // This always copies a full value of type typ so it's safe // to pass typ along as an optimization. See the comment on // bulkBarrierPreWrite. @@ -199,6 +209,18 @@ func wbMove(typ *_type, dst, src unsafe.Pointer) { bulkBarrierPreWrite(uintptr(dst), uintptr(src), typ.PtrBytes, typ) } +// reflect_typedmemmove is meant for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/goccy/json +// - github.com/modern-go/reflect2 +// - github.com/ugorji/go/codec +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_typedmemmove reflect.typedmemmove func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) { if raceenabled { @@ -232,7 +254,7 @@ func reflectlite_typedmemmove(typ *_type, dst, src unsafe.Pointer) { // //go:nosplit func reflectcallmove(typ *_type, dst, src unsafe.Pointer, size uintptr, regs *abi.RegArgs) { - if writeBarrier.enabled && typ != nil && typ.PtrBytes != 0 && size >= goarch.PtrSize { + if writeBarrier.enabled && typ != nil && typ.Pointers() && size >= goarch.PtrSize { // Pass nil for the type. dst does not point to value of type typ, // but rather points into one, so applying the optimization is not // safe. See the comment on this function. @@ -248,6 +270,15 @@ func reflectcallmove(typ *_type, dst, src unsafe.Pointer, size uintptr, regs *ab } } +// typedslicecopy should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/segmentio/encoding +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname typedslicecopy //go:nosplit func typedslicecopy(typ *_type, dstPtr unsafe.Pointer, dstLen int, srcPtr unsafe.Pointer, srcLen int) int { n := dstLen @@ -303,9 +334,21 @@ func typedslicecopy(typ *_type, dstPtr unsafe.Pointer, dstLen int, srcPtr unsafe return n } +// reflect_typedslicecopy is meant for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/RomiChan/protobuf +// - github.com/segmentio/encoding +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_typedslicecopy reflect.typedslicecopy func reflect_typedslicecopy(elemType *_type, dst, src slice) int { - if elemType.PtrBytes == 0 { + if !elemType.Pointers() { return slicecopy(dst.array, dst.len, src.array, src.len, elemType.Size_) } return typedslicecopy(elemType, dst.array, dst.len, src.array, src.len) @@ -323,7 +366,7 @@ func reflect_typedslicecopy(elemType *_type, dst, src slice) int { // //go:nosplit func typedmemclr(typ *_type, ptr unsafe.Pointer) { - if writeBarrier.enabled && typ.PtrBytes != 0 { + if writeBarrier.enabled && typ.Pointers() { // This always clears a whole value of type typ, so it's // safe to pass a type here and apply the optimization. // See the comment on bulkBarrierPreWrite. @@ -332,6 +375,14 @@ func typedmemclr(typ *_type, ptr unsafe.Pointer) { memclrNoHeapPointers(ptr, typ.Size_) } +// reflect_typedslicecopy is meant for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_typedmemclr reflect.typedmemclr func reflect_typedmemclr(typ *_type, ptr unsafe.Pointer) { typedmemclr(typ, ptr) @@ -339,7 +390,7 @@ func reflect_typedmemclr(typ *_type, ptr unsafe.Pointer) { //go:linkname reflect_typedmemclrpartial reflect.typedmemclrpartial func reflect_typedmemclrpartial(typ *_type, ptr unsafe.Pointer, off, size uintptr) { - if writeBarrier.enabled && typ.PtrBytes != 0 { + if writeBarrier.enabled && typ.Pointers() { // Pass nil for the type. ptr does not point to value of type typ, // but rather points into one so it's not safe to apply the optimization. // See the comment on this function in the reflect package and the @@ -352,7 +403,7 @@ func reflect_typedmemclrpartial(typ *_type, ptr unsafe.Pointer, off, size uintpt //go:linkname reflect_typedarrayclear reflect.typedarrayclear func reflect_typedarrayclear(typ *_type, ptr unsafe.Pointer, len int) { size := typ.Size_ * uintptr(len) - if writeBarrier.enabled && typ.PtrBytes != 0 { + if writeBarrier.enabled && typ.Pointers() { // This always clears whole elements of an array, so it's // safe to pass a type here. See the comment on bulkBarrierPreWrite. bulkBarrierPreWrite(uintptr(ptr), 0, size, typ) @@ -365,6 +416,15 @@ func reflect_typedarrayclear(typ *_type, ptr unsafe.Pointer, len int) { // pointers, usually by checking typ.PtrBytes. However, ptr // does not have to point to the start of the allocation. // +// memclrHasPointers should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname memclrHasPointers //go:nosplit func memclrHasPointers(ptr unsafe.Pointer, n uintptr) { // Pass nil for the type since we don't have one here anyway. diff --git a/contrib/go/_std_1.22/src/runtime/mbitmap_allocheaders.go b/contrib/go/_std_1.23/src/runtime/mbitmap.go similarity index 62% rename from contrib/go/_std_1.22/src/runtime/mbitmap_allocheaders.go rename to contrib/go/_std_1.23/src/runtime/mbitmap.go index 1ec055352e78..689fac103ccf 100644 --- a/contrib/go/_std_1.22/src/runtime/mbitmap_allocheaders.go +++ b/contrib/go/_std_1.23/src/runtime/mbitmap.go @@ -1,9 +1,7 @@ -// Copyright 2023 The Go Authors. All rights reserved. +// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build goexperiment.allocheaders - // Garbage collector: type and heap bitmaps. // // Stack, data, and bss bitmaps @@ -60,6 +58,7 @@ package runtime import ( "internal/abi" "internal/goarch" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -116,11 +115,6 @@ func heapBitsInSpan(userSize uintptr) bool { return userSize <= minSizeForMallocHeader } -// heapArenaPtrScalar contains the per-heapArena pointer/scalar metadata for the GC. -type heapArenaPtrScalar struct { - // N.B. This is no longer necessary with allocation headers. -} - // typePointers is an iterator over the pointers in a heap object. // // Iteration through this type implements the tiling algorithm described at the @@ -198,6 +192,10 @@ func (span *mspan) typePointersOfUnchecked(addr uintptr) typePointers { addr += mallocHeaderSize } else { typ = span.largeType + if typ == nil { + // Allow a nil type here for delayed zeroing. See mallocgc. + return typePointers{} + } } gcdata := typ.GCData return typePointers{elem: addr, addr: addr, mask: readUintptr(gcdata), typ: typ} @@ -215,7 +213,7 @@ func (span *mspan) typePointersOfUnchecked(addr uintptr) typePointers { //go:nosplit func (span *mspan) typePointersOfType(typ *abi.Type, addr uintptr) typePointers { const doubleCheck = false - if doubleCheck && (typ == nil || typ.Kind_&kindGCProg != 0) { + if doubleCheck && (typ == nil || typ.Kind_&abi.KindGCProg != 0) { throw("bad type passed to typePointersOfType") } if span.spanclass.noscan() { @@ -459,7 +457,7 @@ func bulkBarrierPreWrite(dst, src, size uintptr, typ *abi.Type) { } var tp typePointers - if typ != nil && typ.Kind_&kindGCProg == 0 { + if typ != nil && typ.Kind_&abi.KindGCProg == 0 { tp = s.typePointersOfType(typ, dst) } else { tp = s.typePointersOf(dst, size) @@ -520,7 +518,7 @@ func bulkBarrierPreWriteSrcOnly(dst, src, size uintptr, typ *abi.Type) { } var tp typePointers - if typ != nil && typ.Kind_&kindGCProg == 0 { + if typ != nil && typ.Kind_&abi.KindGCProg == 0 { tp = s.typePointersOfType(typ, dst) } else { tp = s.typePointersOf(dst, size) @@ -544,150 +542,7 @@ func bulkBarrierPreWriteSrcOnly(dst, src, size uintptr, typ *abi.Type) { func (s *mspan) initHeapBits(forceClear bool) { if (!s.spanclass.noscan() && heapBitsInSpan(s.elemsize)) || s.isUserArenaChunk { b := s.heapBits() - for i := range b { - b[i] = 0 - } - } -} - -// bswapIfBigEndian swaps the byte order of the uintptr on goarch.BigEndian platforms, -// and leaves it alone elsewhere. -func bswapIfBigEndian(x uintptr) uintptr { - if goarch.BigEndian { - if goarch.PtrSize == 8 { - return uintptr(sys.Bswap64(uint64(x))) - } - return uintptr(sys.Bswap32(uint32(x))) - } - return x -} - -type writeUserArenaHeapBits struct { - offset uintptr // offset in span that the low bit of mask represents the pointer state of. - mask uintptr // some pointer bits starting at the address addr. - valid uintptr // number of bits in buf that are valid (including low) - low uintptr // number of low-order bits to not overwrite -} - -func (s *mspan) writeUserArenaHeapBits(addr uintptr) (h writeUserArenaHeapBits) { - offset := addr - s.base() - - // We start writing bits maybe in the middle of a heap bitmap word. - // Remember how many bits into the word we started, so we can be sure - // not to overwrite the previous bits. - h.low = offset / goarch.PtrSize % ptrBits - - // round down to heap word that starts the bitmap word. - h.offset = offset - h.low*goarch.PtrSize - - // We don't have any bits yet. - h.mask = 0 - h.valid = h.low - - return -} - -// write appends the pointerness of the next valid pointer slots -// using the low valid bits of bits. 1=pointer, 0=scalar. -func (h writeUserArenaHeapBits) write(s *mspan, bits, valid uintptr) writeUserArenaHeapBits { - if h.valid+valid <= ptrBits { - // Fast path - just accumulate the bits. - h.mask |= bits << h.valid - h.valid += valid - return h - } - // Too many bits to fit in this word. Write the current word - // out and move on to the next word. - - data := h.mask | bits<> (ptrBits - h.valid) // leftover for next word - h.valid += valid - ptrBits // have h.valid+valid bits, writing ptrBits of them - - // Flush mask to the memory bitmap. - idx := h.offset / (ptrBits * goarch.PtrSize) - m := uintptr(1)< ptrBits { - h = h.write(s, 0, ptrBits) - words -= ptrBits - } - return h.write(s, 0, words) -} - -// Flush the bits that have been written, and add zeros as needed -// to cover the full object [addr, addr+size). -func (h writeUserArenaHeapBits) flush(s *mspan, addr, size uintptr) { - offset := addr - s.base() - - // zeros counts the number of bits needed to represent the object minus the - // number of bits we've already written. This is the number of 0 bits - // that need to be added. - zeros := (offset+size-h.offset)/goarch.PtrSize - h.valid - - // Add zero bits up to the bitmap word boundary - if zeros > 0 { - z := ptrBits - h.valid - if z > zeros { - z = zeros - } - h.valid += z - zeros -= z - } - - // Find word in bitmap that we're going to write. - bitmap := s.heapBits() - idx := h.offset / (ptrBits * goarch.PtrSize) - - // Write remaining bits. - if h.valid != h.low { - m := uintptr(1)< snelems { + throw("s.freeindex > s.nelems") + } + + aCache := s.allocCache + + bitIndex := sys.TrailingZeros64(aCache) + for bitIndex == 64 { + // Move index to start of next cached bits. + sfreeindex = (sfreeindex + 64) &^ (64 - 1) + if sfreeindex >= snelems { + s.freeindex = snelems + return snelems + } + whichByte := sfreeindex / 8 + // Refill s.allocCache with the next 64 alloc bits. + s.refillAllocCache(whichByte) + aCache = s.allocCache + bitIndex = sys.TrailingZeros64(aCache) + // nothing available in cached bits + // grab the next 8 bytes and try again. + } + result := sfreeindex + uint16(bitIndex) + if result >= snelems { + s.freeindex = snelems + return snelems + } + + s.allocCache >>= uint(bitIndex + 1) + sfreeindex = result + 1 + + if sfreeindex%64 == 0 && sfreeindex != snelems { + // We just incremented s.freeindex so it isn't 0. + // As each 1 in s.allocCache was encountered and used for allocation + // it was shifted away. At this point s.allocCache contains all 0s. + // Refill s.allocCache so that it corresponds + // to the bits at s.allocBits starting at s.freeindex. + whichByte := sfreeindex / 8 + s.refillAllocCache(whichByte) + } + s.freeindex = sfreeindex + return result +} + +// isFree reports whether the index'th object in s is unallocated. +// +// The caller must ensure s.state is mSpanInUse, and there must have +// been no preemption points since ensuring this (which could allow a +// GC transition, which would allow the state to change). +func (s *mspan) isFree(index uintptr) bool { + if index < uintptr(s.freeIndexForScan) { + return false + } + bytep, mask := s.allocBits.bitp(index) + return *bytep&mask == 0 +} + +// divideByElemSize returns n/s.elemsize. +// n must be within [0, s.npages*_PageSize), +// or may be exactly s.npages*_PageSize +// if s.elemsize is from sizeclasses.go. +// +// nosplit, because it is called by objIndex, which is nosplit +// +//go:nosplit +func (s *mspan) divideByElemSize(n uintptr) uintptr { + const doubleCheck = false + + // See explanation in mksizeclasses.go's computeDivMagic. + q := uintptr((uint64(n) * uint64(s.divMul)) >> 32) + + if doubleCheck && q != n/s.elemsize { + println(n, "/", s.elemsize, "should be", n/s.elemsize, "but got", q) + throw("bad magic division") + } + return q +} + +// nosplit, because it is called by other nosplit code like findObject +// +//go:nosplit +func (s *mspan) objIndex(p uintptr) uintptr { + return s.divideByElemSize(p - s.base()) +} + +func markBitsForAddr(p uintptr) markBits { + s := spanOf(p) + objIndex := s.objIndex(p) + return s.markBitsForIndex(objIndex) +} + +func (s *mspan) markBitsForIndex(objIndex uintptr) markBits { + bytep, mask := s.gcmarkBits.bitp(objIndex) + return markBits{bytep, mask, objIndex} +} + +func (s *mspan) markBitsForBase() markBits { + return markBits{&s.gcmarkBits.x, uint8(1), 0} +} + +// isMarked reports whether mark bit m is set. +func (m markBits) isMarked() bool { + return *m.bytep&m.mask != 0 +} + +// setMarked sets the marked bit in the markbits, atomically. +func (m markBits) setMarked() { + // Might be racing with other updates, so use atomic update always. + // We used to be clever here and use a non-atomic update in certain + // cases, but it's not worth the risk. + atomic.Or8(m.bytep, m.mask) +} + +// setMarkedNonAtomic sets the marked bit in the markbits, non-atomically. +func (m markBits) setMarkedNonAtomic() { + *m.bytep |= m.mask +} + +// clearMarked clears the marked bit in the markbits, atomically. +func (m markBits) clearMarked() { + // Might be racing with other updates, so use atomic update always. + // We used to be clever here and use a non-atomic update in certain + // cases, but it's not worth the risk. + atomic.And8(m.bytep, ^m.mask) +} + +// markBitsForSpan returns the markBits for the span base address base. +func markBitsForSpan(base uintptr) (mbits markBits) { + mbits = markBitsForAddr(base) + if mbits.mask != 1 { + throw("markBitsForSpan: unaligned start") + } + return mbits +} + +// advance advances the markBits to the next object in the span. +func (m *markBits) advance() { + if m.mask == 1<<7 { + m.bytep = (*uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(m.bytep)) + 1)) + m.mask = 1 + } else { + m.mask = m.mask << 1 + } + m.index++ +} + +// clobberdeadPtr is a special value that is used by the compiler to +// clobber dead stack slots, when -clobberdead flag is set. +const clobberdeadPtr = uintptr(0xdeaddead | 0xdeaddead<<((^uintptr(0)>>63)*32)) + +// badPointer throws bad pointer in heap panic. +func badPointer(s *mspan, p, refBase, refOff uintptr) { + // Typically this indicates an incorrect use + // of unsafe or cgo to store a bad pointer in + // the Go heap. It may also indicate a runtime + // bug. + // + // TODO(austin): We could be more aggressive + // and detect pointers to unallocated objects + // in allocated spans. + printlock() + print("runtime: pointer ", hex(p)) + if s != nil { + state := s.state.get() + if state != mSpanInUse { + print(" to unallocated span") + } else { + print(" to unused region of span") + } + print(" span.base()=", hex(s.base()), " span.limit=", hex(s.limit), " span.state=", state) + } + print("\n") + if refBase != 0 { + print("runtime: found in object at *(", hex(refBase), "+", hex(refOff), ")\n") + gcDumpObject("object", refBase, refOff) + } + getg().m.traceback = 2 + throw("found bad pointer in Go heap (incorrect use of unsafe or cgo?)") +} + +// findObject returns the base address for the heap object containing +// the address p, the object's span, and the index of the object in s. +// If p does not point into a heap object, it returns base == 0. +// +// If p points is an invalid heap pointer and debug.invalidptr != 0, +// findObject panics. +// +// refBase and refOff optionally give the base address of the object +// in which the pointer p was found and the byte offset at which it +// was found. These are used for error reporting. +// +// It is nosplit so it is safe for p to be a pointer to the current goroutine's stack. +// Since p is a uintptr, it would not be adjusted if the stack were to move. +// +// findObject should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname findObject +//go:nosplit +func findObject(p, refBase, refOff uintptr) (base uintptr, s *mspan, objIndex uintptr) { + s = spanOf(p) + // If s is nil, the virtual address has never been part of the heap. + // This pointer may be to some mmap'd region, so we allow it. + if s == nil { + if (GOARCH == "amd64" || GOARCH == "arm64") && p == clobberdeadPtr && debug.invalidptr != 0 { + // Crash if clobberdeadPtr is seen. Only on AMD64 and ARM64 for now, + // as they are the only platform where compiler's clobberdead mode is + // implemented. On these platforms clobberdeadPtr cannot be a valid address. + badPointer(s, p, refBase, refOff) + } + return + } + // If p is a bad pointer, it may not be in s's bounds. + // + // Check s.state to synchronize with span initialization + // before checking other fields. See also spanOfHeap. + if state := s.state.get(); state != mSpanInUse || p < s.base() || p >= s.limit { + // Pointers into stacks are also ok, the runtime manages these explicitly. + if state == mSpanManual { + return + } + // The following ensures that we are rigorous about what data + // structures hold valid pointers. + if debug.invalidptr != 0 { + badPointer(s, p, refBase, refOff) + } + return + } + + objIndex = s.objIndex(p) + base = s.base() + objIndex*s.elemsize + return +} + +// reflect_verifyNotInHeapPtr reports whether converting the not-in-heap pointer into a unsafe.Pointer is ok. +// +//go:linkname reflect_verifyNotInHeapPtr reflect.verifyNotInHeapPtr +func reflect_verifyNotInHeapPtr(p uintptr) bool { + // Conversion to a pointer is ok as long as findObject above does not call badPointer. + // Since we're already promised that p doesn't point into the heap, just disallow heap + // pointers and the special clobbered pointer. + return spanOf(p) == nil && p != clobberdeadPtr +} + +const ptrBits = 8 * goarch.PtrSize + +// bulkBarrierBitmap executes write barriers for copying from [src, +// src+size) to [dst, dst+size) using a 1-bit pointer bitmap. src is +// assumed to start maskOffset bytes into the data covered by the +// bitmap in bits (which may not be a multiple of 8). +// +// This is used by bulkBarrierPreWrite for writes to data and BSS. +// +//go:nosplit +func bulkBarrierBitmap(dst, src, size, maskOffset uintptr, bits *uint8) { + word := maskOffset / goarch.PtrSize + bits = addb(bits, word/8) + mask := uint8(1) << (word % 8) + + buf := &getg().m.p.ptr().wbBuf + for i := uintptr(0); i < size; i += goarch.PtrSize { + if mask == 0 { + bits = addb(bits, 1) + if *bits == 0 { + // Skip 8 words. + i += 7 * goarch.PtrSize + continue + } + mask = 1 + } + if *bits&mask != 0 { + dstx := (*uintptr)(unsafe.Pointer(dst + i)) + if src == 0 { + p := buf.get1() + p[0] = *dstx + } else { + srcx := (*uintptr)(unsafe.Pointer(src + i)) + p := buf.get2() + p[0] = *dstx + p[1] = *srcx + } + } + mask <<= 1 + } +} + +// typeBitsBulkBarrier executes a write barrier for every +// pointer that would be copied from [src, src+size) to [dst, +// dst+size) by a memmove using the type bitmap to locate those +// pointer slots. +// +// The type typ must correspond exactly to [src, src+size) and [dst, dst+size). +// dst, src, and size must be pointer-aligned. +// The type typ must have a plain bitmap, not a GC program. +// The only use of this function is in channel sends, and the +// 64 kB channel element limit takes care of this for us. +// +// Must not be preempted because it typically runs right before memmove, +// and the GC must observe them as an atomic action. +// +// Callers must perform cgo checks if goexperiment.CgoCheck2. +// +//go:nosplit +func typeBitsBulkBarrier(typ *_type, dst, src, size uintptr) { + if typ == nil { + throw("runtime: typeBitsBulkBarrier without type") + } + if typ.Size_ != size { + println("runtime: typeBitsBulkBarrier with type ", toRType(typ).string(), " of size ", typ.Size_, " but memory size", size) + throw("runtime: invalid typeBitsBulkBarrier") + } + if typ.Kind_&abi.KindGCProg != 0 { + println("runtime: typeBitsBulkBarrier with type ", toRType(typ).string(), " with GC prog") + throw("runtime: invalid typeBitsBulkBarrier") + } + if !writeBarrier.enabled { + return + } + ptrmask := typ.GCData + buf := &getg().m.p.ptr().wbBuf + var bits uint32 + for i := uintptr(0); i < typ.PtrBytes; i += goarch.PtrSize { + if i&(goarch.PtrSize*8-1) == 0 { + bits = uint32(*ptrmask) + ptrmask = addb(ptrmask, 1) + } else { + bits = bits >> 1 + } + if bits&1 != 0 { + dstx := (*uintptr)(unsafe.Pointer(dst + i)) + srcx := (*uintptr)(unsafe.Pointer(src + i)) + p := buf.get2() + p[0] = *dstx + p[1] = *srcx + } + } +} + +// countAlloc returns the number of objects allocated in span s by +// scanning the mark bitmap. +func (s *mspan) countAlloc() int { + count := 0 + bytes := divRoundUp(uintptr(s.nelems), 8) + // Iterate over each 8-byte chunk and count allocations + // with an intrinsic. Note that newMarkBits guarantees that + // gcmarkBits will be 8-byte aligned, so we don't have to + // worry about edge cases, irrelevant bits will simply be zero. + for i := uintptr(0); i < bytes; i += 8 { + // Extract 64 bits from the byte pointer and get a OnesCount. + // Note that the unsafe cast here doesn't preserve endianness, + // but that's OK. We only care about how many bits are 1, not + // about the order we discover them in. + mrkBits := *(*uint64)(unsafe.Pointer(s.gcmarkBits.bytep(i))) + count += sys.OnesCount64(mrkBits) + } + return count +} + +// Read the bytes starting at the aligned pointer p into a uintptr. +// Read is little-endian. +func readUintptr(p *byte) uintptr { + x := *(*uintptr)(unsafe.Pointer(p)) + if goarch.BigEndian { + if goarch.PtrSize == 8 { + return uintptr(sys.Bswap64(uint64(x))) + } + return uintptr(sys.Bswap32(uint32(x))) + } + return x +} + +var debugPtrmask struct { + lock mutex + data *byte +} + +// progToPointerMask returns the 1-bit pointer mask output by the GC program prog. +// size the size of the region described by prog, in bytes. +// The resulting bitvector will have no more than size/goarch.PtrSize bits. +func progToPointerMask(prog *byte, size uintptr) bitvector { + n := (size/goarch.PtrSize + 7) / 8 + x := (*[1 << 30]byte)(persistentalloc(n+1, 1, &memstats.buckhash_sys))[:n+1] + x[len(x)-1] = 0xa1 // overflow check sentinel + n = runGCProg(prog, &x[0]) + if x[len(x)-1] != 0xa1 { + throw("progToPointerMask: overflow") + } + return bitvector{int32(n), &x[0]} +} + +// Packed GC pointer bitmaps, aka GC programs. +// +// For large types containing arrays, the type information has a +// natural repetition that can be encoded to save space in the +// binary and in the memory representation of the type information. +// +// The encoding is a simple Lempel-Ziv style bytecode machine +// with the following instructions: +// +// 00000000: stop +// 0nnnnnnn: emit n bits copied from the next (n+7)/8 bytes +// 10000000 n c: repeat the previous n bits c times; n, c are varints +// 1nnnnnnn c: repeat the previous n bits c times; c is a varint + +// runGCProg returns the number of 1-bit entries written to memory. +func runGCProg(prog, dst *byte) uintptr { + dstStart := dst + + // Bits waiting to be written to memory. + var bits uintptr + var nbits uintptr + + p := prog +Run: + for { + // Flush accumulated full bytes. + // The rest of the loop assumes that nbits <= 7. + for ; nbits >= 8; nbits -= 8 { + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 + } + + // Process one instruction. + inst := uintptr(*p) + p = add1(p) + n := inst & 0x7F + if inst&0x80 == 0 { + // Literal bits; n == 0 means end of program. + if n == 0 { + // Program is over. + break Run + } + nbyte := n / 8 + for i := uintptr(0); i < nbyte; i++ { + bits |= uintptr(*p) << nbits + p = add1(p) + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 + } + if n %= 8; n > 0 { + bits |= uintptr(*p) << nbits + p = add1(p) + nbits += n + } + continue Run + } + + // Repeat. If n == 0, it is encoded in a varint in the next bytes. + if n == 0 { + for off := uint(0); ; off += 7 { + x := uintptr(*p) + p = add1(p) + n |= (x & 0x7F) << off + if x&0x80 == 0 { + break + } + } + } + + // Count is encoded in a varint in the next bytes. + c := uintptr(0) + for off := uint(0); ; off += 7 { + x := uintptr(*p) + p = add1(p) + c |= (x & 0x7F) << off + if x&0x80 == 0 { + break + } + } + c *= n // now total number of bits to copy + + // If the number of bits being repeated is small, load them + // into a register and use that register for the entire loop + // instead of repeatedly reading from memory. + // Handling fewer than 8 bits here makes the general loop simpler. + // The cutoff is goarch.PtrSize*8 - 7 to guarantee that when we add + // the pattern to a bit buffer holding at most 7 bits (a partial byte) + // it will not overflow. + src := dst + const maxBits = goarch.PtrSize*8 - 7 + if n <= maxBits { + // Start with bits in output buffer. + pattern := bits + npattern := nbits + + // If we need more bits, fetch them from memory. + src = subtract1(src) + for npattern < n { + pattern <<= 8 + pattern |= uintptr(*src) + src = subtract1(src) + npattern += 8 + } + + // We started with the whole bit output buffer, + // and then we loaded bits from whole bytes. + // Either way, we might now have too many instead of too few. + // Discard the extra. + if npattern > n { + pattern >>= npattern - n + npattern = n + } + + // Replicate pattern to at most maxBits. + if npattern == 1 { + // One bit being repeated. + // If the bit is 1, make the pattern all 1s. + // If the bit is 0, the pattern is already all 0s, + // but we can claim that the number of bits + // in the word is equal to the number we need (c), + // because right shift of bits will zero fill. + if pattern == 1 { + pattern = 1<8 bits, there will be full bytes to flush + // on each iteration. + for ; c >= npattern; c -= npattern { + bits |= pattern << nbits + nbits += npattern + for nbits >= 8 { + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 + nbits -= 8 + } + } + + // Add final fragment to bit buffer. + if c > 0 { + pattern &= 1< nbits because n > maxBits and nbits <= 7 + // Leading src fragment. + src = subtractb(src, (off+7)/8) + if frag := off & 7; frag != 0 { + bits |= uintptr(*src) >> (8 - frag) << nbits + src = add1(src) + nbits += frag + c -= frag + } + // Main loop: load one byte, write another. + // The bits are rotating through the bit buffer. + for i := c / 8; i > 0; i-- { + bits |= uintptr(*src) << nbits + src = add1(src) + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 + } + // Final src fragment. + if c %= 8; c > 0 { + bits |= (uintptr(*src) & (1< 0; nbits -= 8 { + *dst = uint8(bits) + dst = add1(dst) + bits >>= 8 + } + return totalBits +} + +// materializeGCProg allocates space for the (1-bit) pointer bitmask +// for an object of size ptrdata. Then it fills that space with the +// pointer bitmask specified by the program prog. +// The bitmask starts at s.startAddr. +// The result must be deallocated with dematerializeGCProg. +func materializeGCProg(ptrdata uintptr, prog *byte) *mspan { + // Each word of ptrdata needs one bit in the bitmap. + bitmapBytes := divRoundUp(ptrdata, 8*goarch.PtrSize) + // Compute the number of pages needed for bitmapBytes. + pages := divRoundUp(bitmapBytes, pageSize) + s := mheap_.allocManual(pages, spanAllocPtrScalarBits) + runGCProg(addb(prog, 4), (*byte)(unsafe.Pointer(s.startAddr))) + return s +} +func dematerializeGCProg(s *mspan) { + mheap_.freeManual(s, spanAllocPtrScalarBits) +} + +func dumpGCProg(p *byte) { + nptr := 0 + for { + x := *p + p = add1(p) + if x == 0 { + print("\t", nptr, " end\n") + break + } + if x&0x80 == 0 { + print("\t", nptr, " lit ", x, ":") + n := int(x+7) / 8 + for i := 0; i < n; i++ { + print(" ", hex(*p)) + p = add1(p) + } + print("\n") + nptr += int(x) + } else { + nbit := int(x &^ 0x80) + if nbit == 0 { + for nb := uint(0); ; nb += 7 { + x := *p + p = add1(p) + nbit |= int(x&0x7f) << nb + if x&0x80 == 0 { + break + } + } + } + count := 0 + for nb := uint(0); ; nb += 7 { + x := *p + p = add1(p) + count |= int(x&0x7f) << nb + if x&0x80 == 0 { + break + } + } + print("\t", nptr, " repeat ", nbit, " × ", count, "\n") + nptr += nbit * count + } + } +} + // Testing. +// reflect_gcbits returns the GC type info for x, for testing. +// The result is the bitmap entries (0 or 1), one entry per byte. +// +//go:linkname reflect_gcbits reflect.gcbits +func reflect_gcbits(x any) []byte { + return getgcmask(x) +} + // Returns GC type info for the pointer stored in ep for testing. // If ep points to the stack, only static live information will be returned // (i.e. not for objects which are only dynamically live stack objects). @@ -1132,7 +1753,7 @@ func getgcmask(ep any) (mask []byte) { t := e._type var et *_type - if t.Kind_&kindMask != kindPtr { + if t.Kind_&abi.KindMask != abi.Pointer { throw("bad argument to getgcmask: expected type to be a pointer to the value type whose mask is being queried") } et = (*ptrtype)(unsafe.Pointer(t)).Elem @@ -1202,7 +1823,7 @@ func getgcmask(ep any) (mask []byte) { maskFromHeap = maskFromHeap[:len(maskFromHeap)-1] } - if et.Kind_&kindGCProg == 0 { + if et.Kind_&abi.KindGCProg == 0 { // Unroll again, but this time from the type information. maskFromType := make([]byte, (limit-base)/goarch.PtrSize) tp = s.typePointersOfType(et, base) @@ -1289,88 +1910,3 @@ func getgcmask(ep any) (mask []byte) { // must not have pointers return } - -// userArenaHeapBitsSetType is the equivalent of heapSetType but for -// non-slice-backing-store Go values allocated in a user arena chunk. It -// sets up the type metadata for the value with type typ allocated at address ptr. -// base is the base address of the arena chunk. -func userArenaHeapBitsSetType(typ *_type, ptr unsafe.Pointer, s *mspan) { - base := s.base() - h := s.writeUserArenaHeapBits(uintptr(ptr)) - - p := typ.GCData // start of 1-bit pointer mask (or GC program) - var gcProgBits uintptr - if typ.Kind_&kindGCProg != 0 { - // Expand gc program, using the object itself for storage. - gcProgBits = runGCProg(addb(p, 4), (*byte)(ptr)) - p = (*byte)(ptr) - } - nb := typ.PtrBytes / goarch.PtrSize - - for i := uintptr(0); i < nb; i += ptrBits { - k := nb - i - if k > ptrBits { - k = ptrBits - } - // N.B. On big endian platforms we byte swap the data that we - // read from GCData, which is always stored in little-endian order - // by the compiler. writeUserArenaHeapBits handles data in - // a platform-ordered way for efficiency, but stores back the - // data in little endian order, since we expose the bitmap through - // a dummy type. - h = h.write(s, readUintptr(addb(p, i/8)), k) - } - // Note: we call pad here to ensure we emit explicit 0 bits - // for the pointerless tail of the object. This ensures that - // there's only a single noMorePtrs mark for the next object - // to clear. We don't need to do this to clear stale noMorePtrs - // markers from previous uses because arena chunk pointer bitmaps - // are always fully cleared when reused. - h = h.pad(s, typ.Size_-typ.PtrBytes) - h.flush(s, uintptr(ptr), typ.Size_) - - if typ.Kind_&kindGCProg != 0 { - // Zero out temporary ptrmask buffer inside object. - memclrNoHeapPointers(ptr, (gcProgBits+7)/8) - } - - // Update the PtrBytes value in the type information. After this - // point, the GC will observe the new bitmap. - s.largeType.PtrBytes = uintptr(ptr) - base + typ.PtrBytes - - // Double-check that the bitmap was written out correctly. - const doubleCheck = false - if doubleCheck { - doubleCheckHeapPointersInterior(uintptr(ptr), uintptr(ptr), typ.Size_, typ.Size_, typ, &s.largeType, s) - } -} - -// For !goexperiment.AllocHeaders, to pass TestIntendedInlining. -func writeHeapBitsForAddr() { - panic("not implemented") -} - -// For !goexperiment.AllocHeaders. -type heapBits struct { -} - -// For !goexperiment.AllocHeaders. -// -//go:nosplit -func heapBitsForAddr(addr, size uintptr) heapBits { - panic("not implemented") -} - -// For !goexperiment.AllocHeaders. -// -//go:nosplit -func (h heapBits) next() (heapBits, uintptr) { - panic("not implemented") -} - -// For !goexperiment.AllocHeaders. -// -//go:nosplit -func (h heapBits) nextFast() (heapBits, uintptr) { - panic("not implemented") -} diff --git a/contrib/go/_std_1.22/src/runtime/mcache.go b/contrib/go/_std_1.23/src/runtime/mcache.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mcache.go rename to contrib/go/_std_1.23/src/runtime/mcache.go index d4b6eef13ac4..e8da133a6949 100644 --- a/contrib/go/_std_1.22/src/runtime/mcache.go +++ b/contrib/go/_std_1.23/src/runtime/mcache.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/mcentral.go b/contrib/go/_std_1.23/src/runtime/mcentral.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mcentral.go rename to contrib/go/_std_1.23/src/runtime/mcentral.go index e190b56c86b3..bf597e1936da 100644 --- a/contrib/go/_std_1.22/src/runtime/mcentral.go +++ b/contrib/go/_std_1.23/src/runtime/mcentral.go @@ -13,7 +13,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" ) diff --git a/contrib/go/_std_1.22/src/runtime/mcheckmark.go b/contrib/go/_std_1.23/src/runtime/mcheckmark.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/mcheckmark.go rename to contrib/go/_std_1.23/src/runtime/mcheckmark.go index 73c1a10d23bc..258f8892727c 100644 --- a/contrib/go/_std_1.22/src/runtime/mcheckmark.go +++ b/contrib/go/_std_1.23/src/runtime/mcheckmark.go @@ -14,7 +14,7 @@ package runtime import ( "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -52,9 +52,7 @@ func startCheckmarks() { arena.checkmarks = bitmap } else { // Otherwise clear the existing bitmap. - for i := range bitmap.b { - bitmap.b[i] = 0 - } + clear(bitmap.b[:]) } } // Enable checkmarking. diff --git a/contrib/go/_std_1.22/src/runtime/mem.go b/contrib/go/_std_1.23/src/runtime/mem.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem.go rename to contrib/go/_std_1.23/src/runtime/mem.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_aix.go b/contrib/go/_std_1.23/src/runtime/mem_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_aix.go rename to contrib/go/_std_1.23/src/runtime/mem_aix.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_bsd.go b/contrib/go/_std_1.23/src/runtime/mem_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_bsd.go rename to contrib/go/_std_1.23/src/runtime/mem_bsd.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_darwin.go b/contrib/go/_std_1.23/src/runtime/mem_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_darwin.go rename to contrib/go/_std_1.23/src/runtime/mem_darwin.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_js.go b/contrib/go/_std_1.23/src/runtime/mem_js.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_js.go rename to contrib/go/_std_1.23/src/runtime/mem_js.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_linux.go b/contrib/go/_std_1.23/src/runtime/mem_linux.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/mem_linux.go rename to contrib/go/_std_1.23/src/runtime/mem_linux.go index d63c38c209d8..9aaa57ac9e71 100644 --- a/contrib/go/_std_1.22/src/runtime/mem_linux.go +++ b/contrib/go/_std_1.23/src/runtime/mem_linux.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -150,7 +150,8 @@ func sysFreeOS(v unsafe.Pointer, n uintptr) { } func sysFaultOS(v unsafe.Pointer, n uintptr) { - mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE|_MAP_FIXED, -1, 0) + mprotect(v, n, _PROT_NONE) + madvise(v, n, _MADV_DONTNEED) } func sysReserveOS(v unsafe.Pointer, n uintptr) unsafe.Pointer { diff --git a/contrib/go/_std_1.22/src/runtime/mem_plan9.go b/contrib/go/_std_1.23/src/runtime/mem_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_plan9.go rename to contrib/go/_std_1.23/src/runtime/mem_plan9.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_sbrk.go b/contrib/go/_std_1.23/src/runtime/mem_sbrk.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_sbrk.go rename to contrib/go/_std_1.23/src/runtime/mem_sbrk.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_wasip1.go b/contrib/go/_std_1.23/src/runtime/mem_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_wasip1.go rename to contrib/go/_std_1.23/src/runtime/mem_wasip1.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_wasm.go b/contrib/go/_std_1.23/src/runtime/mem_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_wasm.go rename to contrib/go/_std_1.23/src/runtime/mem_wasm.go diff --git a/contrib/go/_std_1.22/src/runtime/mem_windows.go b/contrib/go/_std_1.23/src/runtime/mem_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mem_windows.go rename to contrib/go/_std_1.23/src/runtime/mem_windows.go diff --git a/contrib/go/_std_1.22/src/runtime/memclr_386.s b/contrib/go/_std_1.23/src/runtime/memclr_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_386.s rename to contrib/go/_std_1.23/src/runtime/memclr_386.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_amd64.s b/contrib/go/_std_1.23/src/runtime/memclr_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_amd64.s rename to contrib/go/_std_1.23/src/runtime/memclr_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_arm.s b/contrib/go/_std_1.23/src/runtime/memclr_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_arm.s rename to contrib/go/_std_1.23/src/runtime/memclr_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_arm64.s b/contrib/go/_std_1.23/src/runtime/memclr_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_arm64.s rename to contrib/go/_std_1.23/src/runtime/memclr_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_loong64.s b/contrib/go/_std_1.23/src/runtime/memclr_loong64.s similarity index 90% rename from contrib/go/_std_1.22/src/runtime/memclr_loong64.s rename to contrib/go/_std_1.23/src/runtime/memclr_loong64.s index 313e4d4f3379..1d45e82d498d 100644 --- a/contrib/go/_std_1.22/src/runtime/memclr_loong64.s +++ b/contrib/go/_std_1.23/src/runtime/memclr_loong64.s @@ -7,10 +7,6 @@ // func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) TEXT runtime·memclrNoHeapPointers(SB),NOSPLIT,$0-16 -#ifndef GOEXPERIMENT_regabiargs - MOVV ptr+0(FP), R4 - MOVV n+8(FP), R5 -#endif ADDV R4, R5, R6 // if less than 8 bytes, do one byte at a time diff --git a/contrib/go/_std_1.22/src/runtime/memclr_mips64x.s b/contrib/go/_std_1.23/src/runtime/memclr_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_mips64x.s rename to contrib/go/_std_1.23/src/runtime/memclr_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_mipsx.s b/contrib/go/_std_1.23/src/runtime/memclr_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_mipsx.s rename to contrib/go/_std_1.23/src/runtime/memclr_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_plan9_386.s b/contrib/go/_std_1.23/src/runtime/memclr_plan9_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_plan9_386.s rename to contrib/go/_std_1.23/src/runtime/memclr_plan9_386.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_plan9_amd64.s b/contrib/go/_std_1.23/src/runtime/memclr_plan9_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_plan9_amd64.s rename to contrib/go/_std_1.23/src/runtime/memclr_plan9_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_ppc64x.s b/contrib/go/_std_1.23/src/runtime/memclr_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/memclr_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_riscv64.s b/contrib/go/_std_1.23/src/runtime/memclr_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_riscv64.s rename to contrib/go/_std_1.23/src/runtime/memclr_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_s390x.s b/contrib/go/_std_1.23/src/runtime/memclr_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_s390x.s rename to contrib/go/_std_1.23/src/runtime/memclr_s390x.s diff --git a/contrib/go/_std_1.22/src/runtime/memclr_wasm.s b/contrib/go/_std_1.23/src/runtime/memclr_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memclr_wasm.s rename to contrib/go/_std_1.23/src/runtime/memclr_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_386.s b/contrib/go/_std_1.23/src/runtime/memmove_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_386.s rename to contrib/go/_std_1.23/src/runtime/memmove_386.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_amd64.s b/contrib/go/_std_1.23/src/runtime/memmove_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_amd64.s rename to contrib/go/_std_1.23/src/runtime/memmove_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_arm.s b/contrib/go/_std_1.23/src/runtime/memmove_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_arm.s rename to contrib/go/_std_1.23/src/runtime/memmove_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_arm64.s b/contrib/go/_std_1.23/src/runtime/memmove_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_arm64.s rename to contrib/go/_std_1.23/src/runtime/memmove_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_loong64.s b/contrib/go/_std_1.23/src/runtime/memmove_loong64.s similarity index 94% rename from contrib/go/_std_1.22/src/runtime/memmove_loong64.s rename to contrib/go/_std_1.23/src/runtime/memmove_loong64.s index 5b7aeba698c3..a94cf999bc4a 100644 --- a/contrib/go/_std_1.22/src/runtime/memmove_loong64.s +++ b/contrib/go/_std_1.23/src/runtime/memmove_loong64.s @@ -8,11 +8,6 @@ // func memmove(to, from unsafe.Pointer, n uintptr) TEXT runtime·memmove(SB), NOSPLIT|NOFRAME, $0-24 -#ifndef GOEXPERIMENT_regabiargs - MOVV to+0(FP), R4 - MOVV from+8(FP), R5 - MOVV n+16(FP), R6 -#endif BNE R6, check RET diff --git a/contrib/go/_std_1.22/src/runtime/memmove_mips64x.s b/contrib/go/_std_1.23/src/runtime/memmove_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_mips64x.s rename to contrib/go/_std_1.23/src/runtime/memmove_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_mipsx.s b/contrib/go/_std_1.23/src/runtime/memmove_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_mipsx.s rename to contrib/go/_std_1.23/src/runtime/memmove_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_plan9_386.s b/contrib/go/_std_1.23/src/runtime/memmove_plan9_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_plan9_386.s rename to contrib/go/_std_1.23/src/runtime/memmove_plan9_386.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_plan9_amd64.s b/contrib/go/_std_1.23/src/runtime/memmove_plan9_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_plan9_amd64.s rename to contrib/go/_std_1.23/src/runtime/memmove_plan9_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_ppc64x.s b/contrib/go/_std_1.23/src/runtime/memmove_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/memmove_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_riscv64.s b/contrib/go/_std_1.23/src/runtime/memmove_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_riscv64.s rename to contrib/go/_std_1.23/src/runtime/memmove_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_s390x.s b/contrib/go/_std_1.23/src/runtime/memmove_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_s390x.s rename to contrib/go/_std_1.23/src/runtime/memmove_s390x.s diff --git a/contrib/go/_std_1.22/src/runtime/memmove_wasm.s b/contrib/go/_std_1.23/src/runtime/memmove_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/memmove_wasm.s rename to contrib/go/_std_1.23/src/runtime/memmove_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/metrics.go b/contrib/go/_std_1.23/src/runtime/metrics.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/metrics.go rename to contrib/go/_std_1.23/src/runtime/metrics.go index f97a3804ab32..417f1071bb70 100644 --- a/contrib/go/_std_1.22/src/runtime/metrics.go +++ b/contrib/go/_std_1.23/src/runtime/metrics.go @@ -95,77 +95,77 @@ func initMetrics() { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.gcAssistTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.GCAssistTime)) }, }, "/cpu/classes/gc/mark/dedicated:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.gcDedicatedTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.GCDedicatedTime)) }, }, "/cpu/classes/gc/mark/idle:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.gcIdleTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.GCIdleTime)) }, }, "/cpu/classes/gc/pause:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.gcPauseTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.GCPauseTime)) }, }, "/cpu/classes/gc/total:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.gcTotalTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.GCTotalTime)) }, }, "/cpu/classes/idle:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.idleTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.IdleTime)) }, }, "/cpu/classes/scavenge/assist:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.scavengeAssistTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.ScavengeAssistTime)) }, }, "/cpu/classes/scavenge/background:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.scavengeBgTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.ScavengeBgTime)) }, }, "/cpu/classes/scavenge/total:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.scavengeTotalTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.ScavengeTotalTime)) }, }, "/cpu/classes/total:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.totalTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.TotalTime)) }, }, "/cpu/classes/user:cpu-seconds": { deps: makeStatDepSet(cpuStatsDep), compute: func(in *statAggregate, out *metricValue) { out.kind = metricKindFloat64 - out.scalar = float64bits(nsToSec(in.cpuStats.userTime)) + out.scalar = float64bits(nsToSec(in.cpuStats.UserTime)) }, }, "/gc/cycles/automatic:gc-cycles": { diff --git a/contrib/go/_std_1.22/src/runtime/metrics/description.go b/contrib/go/_std_1.23/src/runtime/metrics/description.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/metrics/description.go rename to contrib/go/_std_1.23/src/runtime/metrics/description.go diff --git a/contrib/go/_std_1.22/src/runtime/metrics/doc.go b/contrib/go/_std_1.23/src/runtime/metrics/doc.go similarity index 93% rename from contrib/go/_std_1.22/src/runtime/metrics/doc.go rename to contrib/go/_std_1.23/src/runtime/metrics/doc.go index 85f256d65a29..da3d956d480b 100644 --- a/contrib/go/_std_1.22/src/runtime/metrics/doc.go +++ b/contrib/go/_std_1.23/src/runtime/metrics/doc.go @@ -230,6 +230,10 @@ Below is the full list of supported metrics, ordered lexicographically. /gc/stack/starting-size:bytes The stack size of new goroutines. + /godebug/non-default-behavior/asynctimerchan:events + The number of non-default behaviors executed by the time package + due to a non-default GODEBUG=asynctimerchan=... setting. + /godebug/non-default-behavior/execerrdot:events The number of non-default behaviors executed by the os/exec package due to a non-default GODEBUG=execerrdot=... setting. @@ -267,15 +271,15 @@ Below is the full list of supported metrics, ordered lexicographically. The number of non-default behaviors executed by the net/http package due to a non-default GODEBUG=httpmuxgo121=... setting. + /godebug/non-default-behavior/httpservecontentkeepheaders:events + The number of non-default behaviors executed + by the net/http package due to a non-default + GODEBUG=httpservecontentkeepheaders=... setting. + /godebug/non-default-behavior/installgoroot:events The number of non-default behaviors executed by the go/build package due to a non-default GODEBUG=installgoroot=... setting. - /godebug/non-default-behavior/jstmpllitinterp:events - The number of non-default behaviors executed by - the html/template package due to a non-default - GODEBUG=jstmpllitinterp=... setting. - /godebug/non-default-behavior/multipartmaxheaders:events The number of non-default behaviors executed by the mime/multipart package due to a non-default @@ -311,6 +315,10 @@ Below is the full list of supported metrics, ordered lexicographically. The number of non-default behaviors executed by the crypto/tls package due to a non-default GODEBUG=tls10server=... setting. + /godebug/non-default-behavior/tls3des:events + The number of non-default behaviors executed by the crypto/tls + package due to a non-default GODEBUG=tls3des=... setting. + /godebug/non-default-behavior/tlsmaxrsasize:events The number of non-default behaviors executed by the crypto/tls package due to a non-default GODEBUG=tlsmaxrsasize=... setting. @@ -323,6 +331,24 @@ Below is the full list of supported metrics, ordered lexicographically. The number of non-default behaviors executed by the crypto/tls package due to a non-default GODEBUG=tlsunsafeekm=... setting. + /godebug/non-default-behavior/winreadlinkvolume:events + The number of non-default behaviors executed by the os package + due to a non-default GODEBUG=winreadlinkvolume=... setting. + + /godebug/non-default-behavior/winsymlink:events + The number of non-default behaviors executed by the os package + due to a non-default GODEBUG=winsymlink=... setting. + + /godebug/non-default-behavior/x509keypairleaf:events + The number of non-default behaviors executed by the crypto/tls + package due to a non-default GODEBUG=x509keypairleaf=... + setting. + + /godebug/non-default-behavior/x509negativeserial:events + The number of non-default behaviors executed by the crypto/x509 + package due to a non-default GODEBUG=x509negativeserial=... + setting. + /godebug/non-default-behavior/x509sha1:events The number of non-default behaviors executed by the crypto/x509 package due to a non-default GODEBUG=x509sha1=... setting. diff --git a/contrib/go/_std_1.22/src/runtime/metrics/histogram.go b/contrib/go/_std_1.23/src/runtime/metrics/histogram.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/metrics/histogram.go rename to contrib/go/_std_1.23/src/runtime/metrics/histogram.go diff --git a/contrib/go/_std_1.22/src/runtime/metrics/sample.go b/contrib/go/_std_1.23/src/runtime/metrics/sample.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/metrics/sample.go rename to contrib/go/_std_1.23/src/runtime/metrics/sample.go diff --git a/contrib/go/_std_1.22/src/runtime/metrics/value.go b/contrib/go/_std_1.23/src/runtime/metrics/value.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/metrics/value.go rename to contrib/go/_std_1.23/src/runtime/metrics/value.go diff --git a/contrib/go/_std_1.22/src/runtime/metrics/ya.make b/contrib/go/_std_1.23/src/runtime/metrics/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/metrics/ya.make rename to contrib/go/_std_1.23/src/runtime/metrics/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/mfinal.go b/contrib/go/_std_1.23/src/runtime/mfinal.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/mfinal.go rename to contrib/go/_std_1.23/src/runtime/mfinal.go index 7d9d547c0f99..78313fb74c6b 100644 --- a/contrib/go/_std_1.22/src/runtime/mfinal.go +++ b/contrib/go/_std_1.23/src/runtime/mfinal.go @@ -9,8 +9,7 @@ package runtime import ( "internal/abi" "internal/goarch" - "internal/goexperiment" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -235,11 +234,11 @@ func runfinq() { // confusing the write barrier. *(*[2]uintptr)(frame) = [2]uintptr{} } - switch f.fint.Kind_ & kindMask { - case kindPtr: + switch f.fint.Kind_ & abi.KindMask { + case abi.Pointer: // direct use of pointer *(*unsafe.Pointer)(r) = f.arg - case kindInterface: + case abi.Interface: ityp := (*interfacetype)(unsafe.Pointer(f.fint)) // set up with empty interface (*eface)(r)._type = &f.ot.Type @@ -378,9 +377,11 @@ func blockUntilEmptyFinalizerQueue(timeout int64) bool { // In order to use finalizers correctly, the program must ensure that // the object is reachable until it is no longer required. // Objects stored in global variables, or that can be found by tracing -// pointers from a global variable, are reachable. For other objects, -// pass the object to a call of the [KeepAlive] function to mark the -// last point in the function where the object must be reachable. +// pointers from a global variable, are reachable. A function argument or +// receiver may become unreachable at the last point where the function +// mentions it. To make an unreachable object reachable, pass the object +// to a call of the [KeepAlive] function to mark the last point in the +// function where the object must be reachable. // // For example, if p points to a struct, such as os.File, that contains // a file descriptor d, and p has a finalizer that closes that file @@ -418,7 +419,7 @@ func SetFinalizer(obj any, finalizer any) { if etyp == nil { throw("runtime.SetFinalizer: first argument is nil") } - if etyp.Kind_&kindMask != kindPtr { + if etyp.Kind_&abi.KindMask != abi.Pointer { throw("runtime.SetFinalizer: first argument is " + toRType(etyp).string() + ", not pointer") } ot := (*ptrtype)(unsafe.Pointer(etyp)) @@ -442,14 +443,14 @@ func SetFinalizer(obj any, finalizer any) { } // Move base forward if we've got an allocation header. - if goexperiment.AllocHeaders && !span.spanclass.noscan() && !heapBitsInSpan(span.elemsize) && span.spanclass.sizeclass() != 0 { + if !span.spanclass.noscan() && !heapBitsInSpan(span.elemsize) && span.spanclass.sizeclass() != 0 { base += mallocHeaderSize } if uintptr(e.data) != base { // As an implementation detail we allow to set finalizers for an inner byte // of an object if it could come from tiny alloc (see mallocgc for details). - if ot.Elem == nil || ot.Elem.PtrBytes != 0 || ot.Elem.Size_ >= maxTinySize { + if ot.Elem == nil || ot.Elem.Pointers() || ot.Elem.Size_ >= maxTinySize { throw("runtime.SetFinalizer: pointer not at beginning of allocated block") } } @@ -464,7 +465,7 @@ func SetFinalizer(obj any, finalizer any) { return } - if ftyp.Kind_&kindMask != kindFunc { + if ftyp.Kind_&abi.KindMask != abi.Func { throw("runtime.SetFinalizer: second argument is " + toRType(ftyp).string() + ", not a function") } ft := (*functype)(unsafe.Pointer(ftyp)) @@ -479,13 +480,13 @@ func SetFinalizer(obj any, finalizer any) { case fint == etyp: // ok - same type goto okarg - case fint.Kind_&kindMask == kindPtr: + case fint.Kind_&abi.KindMask == abi.Pointer: if (fint.Uncommon() == nil || etyp.Uncommon() == nil) && (*ptrtype)(unsafe.Pointer(fint)).Elem == ot.Elem { // ok - not same type, but both pointers, // one or the other is unnamed, and same element type, so assignable. goto okarg } - case fint.Kind_&kindMask == kindInterface: + case fint.Kind_&abi.KindMask == abi.Interface: ityp := (*interfacetype)(unsafe.Pointer(fint)) if len(ityp.Methods) == 0 { // ok - satisfies empty interface diff --git a/contrib/go/_std_1.22/src/runtime/mfixalloc.go b/contrib/go/_std_1.23/src/runtime/mfixalloc.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mfixalloc.go rename to contrib/go/_std_1.23/src/runtime/mfixalloc.go diff --git a/contrib/go/_std_1.22/src/runtime/mgc.go b/contrib/go/_std_1.23/src/runtime/mgc.go similarity index 90% rename from contrib/go/_std_1.22/src/runtime/mgc.go rename to contrib/go/_std_1.23/src/runtime/mgc.go index 6c51517522a1..f72edc2afe95 100644 --- a/contrib/go/_std_1.22/src/runtime/mgc.go +++ b/contrib/go/_std_1.23/src/runtime/mgc.go @@ -130,7 +130,7 @@ package runtime import ( "internal/cpu" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -190,6 +190,7 @@ func gcinit() { work.markDoneSema = 1 lockInit(&work.sweepWaiters.lock, lockRankSweepWaiters) lockInit(&work.assistQueue.lock, lockRankAssistQueue) + lockInit(&work.strongFromWeak.lock, lockRankStrongFromWeakQueue) lockInit(&work.wbufSpans.lock, lockRankWbufSpans) } @@ -215,6 +216,17 @@ var gcphase uint32 // If you change it, you must change builtin/runtime.go, too. // If you change the first four bytes, you must also change the write // barrier insertion code. +// +// writeBarrier should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname writeBarrier var writeBarrier struct { enabled bool // compiler emits a check of this before calling write barrier pad [3]byte // compiler uses 32-bit load for "enabled" field @@ -378,8 +390,7 @@ type workType struct { // markDoneSema protects transitions from mark to mark termination. markDoneSema uint32 - bgMarkReady note // signal background mark worker has started - bgMarkDone uint32 // cas to 1 when at a background mark completion point + bgMarkDone uint32 // cas to 1 when at a background mark completion point // Background mark completion signaling // mode is the concurrency mode of the current GC cycle. @@ -408,6 +419,26 @@ type workType struct { list gList } + // strongFromWeak controls how the GC interacts with weak->strong + // pointer conversions. + strongFromWeak struct { + // block is a flag set during mark termination that prevents + // new weak->strong conversions from executing by blocking the + // goroutine and enqueuing it onto q. + // + // Mutated only by one goroutine at a time in gcMarkDone, + // with globally-synchronizing events like forEachP and + // stopTheWorld. + block bool + + // q is a queue of goroutines that attempted to perform a + // weak->strong conversion during mark termination. + // + // Protected by lock. + lock mutex + q gQueue + } + // cycles is the number of completed GC cycles, where a GC // cycle is sweep termination, mark, mark termination, and // sweep. This differs from memstats.numgc, which is @@ -418,7 +449,10 @@ type workType struct { stwprocs, maxprocs int32 tSweepTerm, tMark, tMarkTerm, tEnd int64 // nanotime() of phase start - pauseNS int64 // total STW time this cycle + // pauseNS is the total STW time this cycle, measured as the time between + // when stopping began (just before trying to stop Ps) and just after the + // world started again. + pauseNS int64 // debug.gctrace heap sizes for this cycle. heap0, heap1, heap2 uint64 @@ -680,6 +714,10 @@ func gcStart(trigger gcTrigger) { systemstack(func() { stw = stopTheWorldWithSema(stwGCSweepTerm) }) + + // Accumulate fine-grained stopping time. + work.cpuStats.accumulateGCPauseTime(stw.stoppingCPUTime, 1) + // Finish sweep before we start concurrent scan. systemstack(func() { finishsweep_m() @@ -742,16 +780,19 @@ func gcStart(trigger gcTrigger) { // returns, so make sure we're not preemptible. mp = acquirem() + // Update the CPU stats pause time. + // + // Use maxprocs instead of stwprocs here because the total time + // computed in the CPU stats is based on maxprocs, and we want them + // to be comparable. + work.cpuStats.accumulateGCPauseTime(nanotime()-stw.finishedStopping, work.maxprocs) + // Concurrent mark. systemstack(func() { now = startTheWorldWithSema(0, stw) - work.pauseNS += now - stw.start + work.pauseNS += now - stw.startedStopping work.tMark = now - sweepTermCpu := int64(work.stwprocs) * (work.tMark - work.tSweepTerm) - work.cpuStats.gcPauseTime += sweepTermCpu - work.cpuStats.gcTotalTime += sweepTermCpu - // Release the CPU limiter. gcCPULimiter.finishGCTransition(now) }) @@ -780,6 +821,19 @@ func gcStart(trigger gcTrigger) { // This is protected by markDoneSema. var gcMarkDoneFlushed uint32 +// gcDebugMarkDone contains fields used to debug/test mark termination. +var gcDebugMarkDone struct { + // spinAfterRaggedBarrier forces gcMarkDone to spin after it executes + // the ragged barrier. + spinAfterRaggedBarrier atomic.Bool + + // restartedDueTo27993 indicates that we restarted mark termination + // due to the bug described in issue #27993. + // + // Protected by worldsema. + restartedDueTo27993 bool +} + // gcMarkDone transitions the GC from mark to mark termination if all // reachable objects have been marked (that is, there are no grey // objects and can be no more in the future). Otherwise, it flushes @@ -822,6 +876,10 @@ top: // stop the world later, so acquire worldsema now. semacquire(&worldsema) + // Prevent weak->strong conversions from generating additional + // GC work. forEachP will guarantee that it is observed globally. + work.strongFromWeak.block = true + // Flush all local buffers and collect flushedWork flags. gcMarkDoneFlushed = 0 forEachP(waitReasonGCMarkTermination, func(pp *p) { @@ -852,6 +910,10 @@ top: goto top } + // For debugging/testing. + for gcDebugMarkDone.spinAfterRaggedBarrier.Load() { + } + // There was no global work, no local work, and no Ps // communicated work since we took markDoneSema. Therefore // there are no grey objects and no more objects can be @@ -867,6 +929,9 @@ top: // below. The important thing is that the wb remains active until // all marking is complete. This includes writes made by the GC. + // Accumulate fine-grained stopping time. + work.cpuStats.accumulateGCPauseTime(stw.stoppingCPUTime, 1) + // There is sometimes work left over when we enter mark termination due // to write barriers performed after the completion barrier above. // Detect this and resume concurrent mark. This is obviously @@ -887,10 +952,16 @@ top: } }) if restart { + gcDebugMarkDone.restartedDueTo27993 = true + getg().m.preemptoff = "" systemstack(func() { + // Accumulate the time we were stopped before we had to start again. + work.cpuStats.accumulateGCPauseTime(nanotime()-stw.finishedStopping, work.maxprocs) + + // Start the world again. now := startTheWorldWithSema(0, stw) - work.pauseNS += now - stw.start + work.pauseNS += now - stw.startedStopping }) semrelease(&worldsema) goto top @@ -909,6 +980,11 @@ top: // start the world again. gcWakeAllAssists() + // Wake all blocked weak->strong conversions. These will run + // when we start the world again. + work.strongFromWeak.block = false + gcWakeAllStrongFromWeak() + // Likewise, release the transition lock. Blocked // workers and assists will run when we start the // world again. @@ -943,7 +1019,7 @@ func gcMarkTermination(stw worldStop) { // N.B. The execution tracer is not aware of this status // transition and handles it specially based on the // wait reason. - casGToWaiting(curgp, _Grunning, waitReasonGarbageCollection) + casGToWaitingForGC(curgp, _Grunning, waitReasonGarbageCollection) // Run gc on the g0 stack. We do this so that the g stack // we're currently running on will no longer change. Cuts @@ -1010,7 +1086,7 @@ func gcMarkTermination(stw worldStop) { now := nanotime() sec, nsec, _ := time_now() unixNow := sec*1e9 + int64(nsec) - work.pauseNS += now - stw.start + work.pauseNS += now - stw.startedStopping work.tEnd = now atomic.Store64(&memstats.last_gc_unix, uint64(unixNow)) // must be Unix time to make sense to user atomic.Store64(&memstats.last_gc_nanotime, uint64(now)) // monotonic time for us @@ -1018,18 +1094,20 @@ func gcMarkTermination(stw worldStop) { memstats.pause_end[memstats.numgc%uint32(len(memstats.pause_end))] = uint64(unixNow) memstats.pause_total_ns += uint64(work.pauseNS) - markTermCpu := int64(work.stwprocs) * (work.tEnd - work.tMarkTerm) - work.cpuStats.gcPauseTime += markTermCpu - work.cpuStats.gcTotalTime += markTermCpu - // Accumulate CPU stats. // - // Pass gcMarkPhase=true so we can get all the latest GC CPU stats in there too. + // Use maxprocs instead of stwprocs for GC pause time because the total time + // computed in the CPU stats is based on maxprocs, and we want them to be + // comparable. + // + // Pass gcMarkPhase=true to accumulate so we can get all the latest GC CPU stats + // in there too. + work.cpuStats.accumulateGCPauseTime(now-stw.finishedStopping, work.maxprocs) work.cpuStats.accumulate(now, true) // Compute overall GC CPU utilization. // Omit idle marking time from the overall utilization here since it's "free". - memstats.gc_cpu_fraction = float64(work.cpuStats.gcTotalTime-work.cpuStats.gcIdleTime) / float64(work.cpuStats.totalTime) + memstats.gc_cpu_fraction = float64(work.cpuStats.GCTotalTime-work.cpuStats.GCIdleTime) / float64(work.cpuStats.TotalTime) // Reset assist time and background time stats. // @@ -1167,7 +1245,7 @@ func gcMarkTermination(stw worldStop) { gcController.assistTime.Load(), gcController.dedicatedMarkTime.Load() + gcController.fractionalMarkTime.Load(), gcController.idleMarkTime.Load(), - markTermCpu, + int64(work.stwprocs) * (work.tEnd - work.tMarkTerm), } { if i == 2 || i == 3 { // Separate mark time components with /. @@ -1230,11 +1308,34 @@ func gcBgMarkStartWorkers() { // // Worker Gs don't exit if gomaxprocs is reduced. If it is raised // again, we can reuse the old workers; no need to create new workers. + if gcBgMarkWorkerCount >= gomaxprocs { + return + } + + // Increment mp.locks when allocating. We are called within gcStart, + // and thus must not trigger another gcStart via an allocation. gcStart + // bails when allocating with locks held, so simulate that for these + // allocations. + // + // TODO(prattmic): cleanup gcStart to use a more explicit "in gcStart" + // check for bailing. + mp := acquirem() + ready := make(chan struct{}, 1) + releasem(mp) + for gcBgMarkWorkerCount < gomaxprocs { - go gcBgMarkWorker() + mp := acquirem() // See above, we allocate a closure here. + go gcBgMarkWorker(ready) + releasem(mp) - notetsleepg(&work.bgMarkReady, -1) - noteclear(&work.bgMarkReady) + // N.B. we intentionally wait on each goroutine individually + // rather than starting all in a batch and then waiting once + // afterwards. By running one goroutine at a time, we can take + // advantage of runnext to bounce back and forth between + // workers and this goroutine. In an overloaded application, + // this can reduce GC start latency by prioritizing these + // goroutines rather than waiting on the end of the run queue. + <-ready // The worker is now guaranteed to be added to the pool before // its P's next findRunnableGCWorker. @@ -1273,7 +1374,7 @@ type gcBgMarkWorkerNode struct { m muintptr } -func gcBgMarkWorker() { +func gcBgMarkWorker(ready chan struct{}) { gp := getg() // We pass node to a gopark unlock function, so it can't be on @@ -1286,7 +1387,8 @@ func gcBgMarkWorker() { node.gp.set(gp) node.m.set(acquirem()) - notewakeup(&work.bgMarkReady) + + ready <- struct{}{} // After this point, the background mark worker is generally scheduled // cooperatively by gcController.findRunnableGCWorker. While performing // work on the P, preemption is disabled because we are working on @@ -1299,10 +1401,10 @@ func gcBgMarkWorker() { // fine; it will eventually gopark again for further scheduling via // findRunnableGCWorker. // - // Since we disable preemption before notifying bgMarkReady, we - // guarantee that this G will be in the worker pool for the next - // findRunnableGCWorker. This isn't strictly necessary, but it reduces - // latency between _GCmark starting and the workers starting. + // Since we disable preemption before notifying ready, we guarantee that + // this G will be in the worker pool for the next findRunnableGCWorker. + // This isn't strictly necessary, but it reduces latency between + // _GCmark starting and the workers starting. for { // Go to sleep until woken by @@ -1379,7 +1481,7 @@ func gcBgMarkWorker() { // N.B. The execution tracer is not aware of this status // transition and handles it specially based on the // wait reason. - casGToWaiting(gp, _Grunning, waitReasonGCWorkerActive) + casGToWaitingForGC(gp, _Grunning, waitReasonGCWorkerActive) switch pp.gcMarkWorkerMode { default: throw("gcBgMarkWorker: unexpected gcMarkWorkerMode") @@ -1468,10 +1570,6 @@ func gcMarkWorkAvailable(p *p) bool { // All gcWork caches must be empty. // STW is in effect at this point. func gcMark(startTime int64) { - if debug.allocfreetrace > 0 { - tracegc() - } - if gcphase != _GCmarktermination { throw("in gcMark expecting to see gcphase as _GCmarktermination") } @@ -1642,9 +1740,7 @@ func gcResetMarkState() { unlock(&mheap_.lock) for _, ai := range arenas { ha := mheap_.arenas[ai.l1()][ai.l2()] - for i := range ha.pageMarks { - ha.pageMarks[i] = 0 - } + clear(ha.pageMarks[:]) } work.bytesMarked = 0 @@ -1654,8 +1750,18 @@ func gcResetMarkState() { // Hooks for other packages var poolcleanup func() -var boringCaches []unsafe.Pointer // for crypto/internal/boring - +var boringCaches []unsafe.Pointer // for crypto/internal/boring +var uniqueMapCleanup chan struct{} // for unique + +// sync_runtime_registerPoolCleanup should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname sync_runtime_registerPoolCleanup sync.runtime_registerPoolCleanup func sync_runtime_registerPoolCleanup(f func()) { poolcleanup = f @@ -1666,6 +1772,18 @@ func boring_registerCache(p unsafe.Pointer) { boringCaches = append(boringCaches, p) } +//go:linkname unique_runtime_registerUniqueMapCleanup unique.runtime_registerUniqueMapCleanup +func unique_runtime_registerUniqueMapCleanup(f func()) { + // Start the goroutine in the runtime so it's counted as a system goroutine. + uniqueMapCleanup = make(chan struct{}, 1) + go func(cleanup func()) { + for { + <-uniqueMapCleanup + cleanup() + } + }(f) +} + func clearpools() { // clear sync.Pools if poolcleanup != nil { @@ -1677,6 +1795,14 @@ func clearpools() { atomicstorep(p, nil) } + // clear unique maps + if uniqueMapCleanup != nil { + select { + case uniqueMapCleanup <- struct{}{}: + default: + } + } + // Clear central sudog cache. // Leave per-P caches alone, they have strictly bounded size. // Disconnect cached list before dropping it on the floor, diff --git a/contrib/go/_std_1.22/src/runtime/mgclimit.go b/contrib/go/_std_1.23/src/runtime/mgclimit.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mgclimit.go rename to contrib/go/_std_1.23/src/runtime/mgclimit.go index ef3cc081cec3..ad86fbd65bce 100644 --- a/contrib/go/_std_1.22/src/runtime/mgclimit.go +++ b/contrib/go/_std_1.23/src/runtime/mgclimit.go @@ -4,7 +4,7 @@ package runtime -import "runtime/internal/atomic" +import "internal/runtime/atomic" // gcCPULimiter is a mechanism to limit GC CPU utilization in situations // where it might become excessive and inhibit application progress (e.g. @@ -33,16 +33,6 @@ type gcCPULimiterState struct { lock atomic.Uint32 enabled atomic.Bool - bucket struct { - // Invariants: - // - fill >= 0 - // - capacity >= 0 - // - fill <= capacity - fill, capacity uint64 - } - // overflow is the cumulative amount of GC CPU time that we tried to fill the - // bucket with but exceeded its capacity. - overflow uint64 // gcEnabled is an internal copy of gcBlackenEnabled that determines // whether the limiter tracks total assist time. @@ -55,6 +45,20 @@ type gcCPULimiterState struct { // the mark and sweep phases. transitioning bool + // test indicates whether this instance of the struct was made for testing purposes. + test bool + + bucket struct { + // Invariants: + // - fill >= 0 + // - capacity >= 0 + // - fill <= capacity + fill, capacity uint64 + } + // overflow is the cumulative amount of GC CPU time that we tried to fill the + // bucket with but exceeded its capacity. + overflow uint64 + // assistTimePool is the accumulated assist time since the last update. assistTimePool atomic.Int64 @@ -77,9 +81,6 @@ type gcCPULimiterState struct { // // gomaxprocs isn't used directly so as to keep this structure unit-testable. nprocs int32 - - // test indicates whether this instance of the struct was made for testing purposes. - test bool } // limiting returns true if the CPU limiter is currently enabled, meaning the Go GC diff --git a/contrib/go/_std_1.22/src/runtime/mgcmark.go b/contrib/go/_std_1.23/src/runtime/mgcmark.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/mgcmark.go rename to contrib/go/_std_1.23/src/runtime/mgcmark.go index b515568eb003..61e917df4108 100644 --- a/contrib/go/_std_1.22/src/runtime/mgcmark.go +++ b/contrib/go/_std_1.23/src/runtime/mgcmark.go @@ -9,8 +9,7 @@ package runtime import ( "internal/abi" "internal/goarch" - "internal/goexperiment" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -73,9 +72,7 @@ func gcMarkRootPrepare() { if nDataRoots > work.nDataRoots { work.nDataRoots = nDataRoots } - } - for _, datap := range activeModules() { nBSSRoots := nBlocks(datap.ebss - datap.bss) if nBSSRoots > work.nBSSRoots { work.nBSSRoots = nBSSRoots @@ -220,7 +217,7 @@ func markroot(gcw *gcWork, i uint32, flushBgCredit bool) int64 { userG := getg().m.curg selfScan := gp == userG && readgstatus(userG) == _Grunning if selfScan { - casGToWaiting(userG, _Grunning, waitReasonGarbageCollectionScan) + casGToWaitingForGC(userG, _Grunning, waitReasonGarbageCollectionScan) } // TODO: suspendG blocks (and spins) until gp @@ -331,6 +328,13 @@ func markrootSpans(gcw *gcWork, shard int) { // 2) Finalizer specials (which are not in the garbage // collected heap) are roots. In practice, this means the fn // field must be scanned. + // + // Objects with weak handles have only one invariant related + // to this function: weak handle specials (which are not in the + // garbage collected heap) are roots. In practice, this means + // the handle field must be scanned. Note that the value the + // handle pointer referenced does *not* need to be scanned. See + // the definition of specialWeakHandle for details. sg := mheap_.sweepgen // Find the arena and page index into that arena for this shard. @@ -376,24 +380,28 @@ func markrootSpans(gcw *gcWork, shard int) { // removed from the list while we're traversing it. lock(&s.speciallock) for sp := s.specials; sp != nil; sp = sp.next { - if sp.kind != _KindSpecialFinalizer { - continue - } - // don't mark finalized object, but scan it so we - // retain everything it points to. - spf := (*specialfinalizer)(unsafe.Pointer(sp)) - // A finalizer can be set for an inner byte of an object, find object beginning. - p := s.base() + uintptr(spf.special.offset)/s.elemsize*s.elemsize - - // Mark everything that can be reached from - // the object (but *not* the object itself or - // we'll never collect it). - if !s.spanclass.noscan() { - scanobject(p, gcw) - } + switch sp.kind { + case _KindSpecialFinalizer: + // don't mark finalized object, but scan it so we + // retain everything it points to. + spf := (*specialfinalizer)(unsafe.Pointer(sp)) + // A finalizer can be set for an inner byte of an object, find object beginning. + p := s.base() + uintptr(spf.special.offset)/s.elemsize*s.elemsize + + // Mark everything that can be reached from + // the object (but *not* the object itself or + // we'll never collect it). + if !s.spanclass.noscan() { + scanobject(p, gcw) + } - // The special itself is a root. - scanblock(uintptr(unsafe.Pointer(&spf.fn)), goarch.PtrSize, &oneptrmask[0], gcw, nil) + // The special itself is a root. + scanblock(uintptr(unsafe.Pointer(&spf.fn)), goarch.PtrSize, &oneptrmask[0], gcw, nil) + case _KindSpecialWeakHandle: + // The special itself is a root. + spw := (*specialWeakHandle)(unsafe.Pointer(sp)) + scanblock(uintptr(unsafe.Pointer(&spw.handle)), goarch.PtrSize, &oneptrmask[0], gcw, nil) + } } unlock(&s.speciallock) } @@ -417,15 +425,9 @@ func gcAssistAlloc(gp *g) { // This extremely verbose boolean indicates whether we've // entered mark assist from the perspective of the tracer. // - // In the old tracer, this is just before we call gcAssistAlloc1 - // *and* tracing is enabled. Because the old tracer doesn't - // do any extra tracking, we need to be careful to not emit an - // "end" event if there was no corresponding "begin" for the - // mark assist. - // - // In the new tracer, this is just before we call gcAssistAlloc1 + // In the tracer, this is just before we call gcAssistAlloc1 // *regardless* of whether tracing is enabled. This is because - // the new tracer allows for tracing to begin (and advance + // the tracer allows for tracing to begin (and advance // generations) in the middle of a GC mark phase, so we need to // record some state so that the tracer can pick it up to ensure // a consistent trace result. @@ -521,18 +523,6 @@ retry: if !enteredMarkAssistForTracing { trace := traceAcquire() if trace.ok() { - if !goexperiment.ExecTracer2 { - // In the old tracer, enter mark assist tracing only - // if we actually traced an event. Otherwise a goroutine - // waking up from mark assist post-GC might end up - // writing a stray "end" event. - // - // This means inMarkAssist will not be meaningful - // in the old tracer; that's OK, it's unused. - // - // See the comment on enteredMarkAssistForTracing. - enteredMarkAssistForTracing = true - } trace.GCMarkAssistStart() // Set this *after* we trace the start, otherwise we may // emit an in-progress event for an assist we're about to start. @@ -541,14 +531,12 @@ retry: } else { gp.inMarkAssist = true } - if goexperiment.ExecTracer2 { - // In the new tracer, set enter mark assist tracing if we - // ever pass this point, because we must manage inMarkAssist - // correctly. - // - // See the comment on enteredMarkAssistForTracing. - enteredMarkAssistForTracing = true - } + // In the new tracer, set enter mark assist tracing if we + // ever pass this point, because we must manage inMarkAssist + // correctly. + // + // See the comment on enteredMarkAssistForTracing. + enteredMarkAssistForTracing = true } // Perform assist work @@ -657,7 +645,7 @@ func gcAssistAlloc1(gp *g, scanWork int64) { } // gcDrainN requires the caller to be preemptible. - casGToWaiting(gp, _Grunning, waitReasonGCAssistMarking) + casGToWaitingForGC(gp, _Grunning, waitReasonGCAssistMarking) // drain own cached work first in the hopes that it // will be more cache friendly. @@ -1437,34 +1425,18 @@ func scanobject(b uintptr, gcw *gcWork) { // of the object. n = s.base() + s.elemsize - b n = min(n, maxObletBytes) - if goexperiment.AllocHeaders { - tp = s.typePointersOfUnchecked(s.base()) - tp = tp.fastForward(b-tp.addr, b+n) - } + tp = s.typePointersOfUnchecked(s.base()) + tp = tp.fastForward(b-tp.addr, b+n) } else { - if goexperiment.AllocHeaders { - tp = s.typePointersOfUnchecked(b) - } + tp = s.typePointersOfUnchecked(b) } - var hbits heapBits - if !goexperiment.AllocHeaders { - hbits = heapBitsForAddr(b, n) - } var scanSize uintptr for { var addr uintptr - if goexperiment.AllocHeaders { - if tp, addr = tp.nextFast(); addr == 0 { - if tp, addr = tp.next(b + n); addr == 0 { - break - } - } - } else { - if hbits, addr = hbits.nextFast(); addr == 0 { - if hbits, addr = hbits.next(); addr == 0 { - break - } + if tp, addr = tp.nextFast(); addr == 0 { + if tp, addr = tp.next(b + n); addr == 0 { + break } } diff --git a/contrib/go/_std_1.22/src/runtime/mgcpacer.go b/contrib/go/_std_1.23/src/runtime/mgcpacer.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mgcpacer.go rename to contrib/go/_std_1.23/src/runtime/mgcpacer.go index e9af3d60cdc2..cda87fe94844 100644 --- a/contrib/go/_std_1.22/src/runtime/mgcpacer.go +++ b/contrib/go/_std_1.23/src/runtime/mgcpacer.go @@ -7,7 +7,7 @@ package runtime import ( "internal/cpu" "internal/goexperiment" - "runtime/internal/atomic" + "internal/runtime/atomic" _ "unsafe" // for go:linkname ) diff --git a/contrib/go/_std_1.22/src/runtime/mgcscavenge.go b/contrib/go/_std_1.23/src/runtime/mgcscavenge.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mgcscavenge.go rename to contrib/go/_std_1.23/src/runtime/mgcscavenge.go index 86c2103f1868..4f0bd9c28dc0 100644 --- a/contrib/go/_std_1.22/src/runtime/mgcscavenge.go +++ b/contrib/go/_std_1.23/src/runtime/mgcscavenge.go @@ -92,7 +92,7 @@ package runtime import ( "internal/goos" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -281,15 +281,19 @@ type scavengerState struct { // g is the goroutine the scavenger is bound to. g *g - // parked is whether or not the scavenger is parked. - parked bool - // timer is the timer used for the scavenger to sleep. timer *timer // sysmonWake signals to sysmon that it should wake the scavenger. sysmonWake atomic.Uint32 + // parked is whether or not the scavenger is parked. + parked bool + + // printControllerReset instructs printScavTrace to signal that + // the controller was reset. + printControllerReset bool + // targetCPUFraction is the target CPU overhead for the scavenger. targetCPUFraction float64 @@ -312,10 +316,6 @@ type scavengerState struct { // value. Used if the controller's assumptions fail to hold. controllerCooldown int64 - // printControllerReset instructs printScavTrace to signal that - // the controller was reset. - printControllerReset bool - // sleepStub is a stub used for testing to avoid actually having // the scavenger sleep. // @@ -361,10 +361,10 @@ func (s *scavengerState) init() { s.g = getg() s.timer = new(timer) - s.timer.arg = s - s.timer.f = func(s any, _ uintptr) { + f := func(s any, _ uintptr, _ int64) { s.(*scavengerState).wake() } + s.timer.init(f, s) // input: fraction of CPU time actually used. // setpoint: ideal CPU fraction. @@ -497,7 +497,7 @@ func (s *scavengerState) sleep(worked float64) { // because we can't close over any variables without // failing escape analysis. start := nanotime() - resetTimer(s.timer, start+sleepTime) + s.timer.reset(start+sleepTime, 0) // Mark ourselves as asleep and go to sleep. s.parked = true @@ -512,7 +512,7 @@ func (s *scavengerState) sleep(worked float64) { // reason we might fail is that we've already woken up, but the timer // might be in the process of firing on some other P; essentially we're // racing with it. That's totally OK. Double wake-ups are perfectly safe. - stopTimer(s.timer) + s.timer.stop() unlock(&s.lock) } else { unlock(&s.lock) @@ -773,8 +773,6 @@ func (p *pageAlloc) scavengeOne(ci chunkIdx, searchIdx uint, max uintptr) uintpt unlock(p.mheapLock) if !p.test { - pageTraceScav(getg().m.p.ptr(), 0, addr, uintptr(npages)) - // Only perform sys* operations if we're not in a test. // It's dangerous to do so otherwise. sysUnused(unsafe.Pointer(addr), uintptr(npages)*pageSize) diff --git a/contrib/go/_std_1.22/src/runtime/mgcstack.go b/contrib/go/_std_1.23/src/runtime/mgcstack.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mgcstack.go rename to contrib/go/_std_1.23/src/runtime/mgcstack.go diff --git a/contrib/go/_std_1.22/src/runtime/mgcsweep.go b/contrib/go/_std_1.23/src/runtime/mgcsweep.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/mgcsweep.go rename to contrib/go/_std_1.23/src/runtime/mgcsweep.go index 35be7949472f..f53330a5b976 100644 --- a/contrib/go/_std_1.22/src/runtime/mgcsweep.go +++ b/contrib/go/_std_1.23/src/runtime/mgcsweep.go @@ -26,8 +26,7 @@ package runtime import ( "internal/abi" - "internal/goexperiment" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -553,31 +552,44 @@ func (sl *sweepLocked) sweep(preserve bool) bool { mbits := s.markBitsForIndex(objIndex) if !mbits.isMarked() { // This object is not marked and has at least one special record. - // Pass 1: see if it has at least one finalizer. - hasFin := false + // Pass 1: see if it has a finalizer. + hasFinAndRevived := false endOffset := p - s.base() + size for tmp := siter.s; tmp != nil && uintptr(tmp.offset) < endOffset; tmp = tmp.next { if tmp.kind == _KindSpecialFinalizer { // Stop freeing of object if it has a finalizer. mbits.setMarkedNonAtomic() - hasFin = true + hasFinAndRevived = true break } } - // Pass 2: queue all finalizers _or_ handle profile record. - for siter.valid() && uintptr(siter.s.offset) < endOffset { - // Find the exact byte for which the special was setup - // (as opposed to object beginning). - special := siter.s - p := s.base() + uintptr(special.offset) - if special.kind == _KindSpecialFinalizer || !hasFin { + if hasFinAndRevived { + // Pass 2: queue all finalizers and clear any weak handles. Weak handles are cleared + // before finalization as specified by the internal/weak package. See the documentation + // for that package for more details. + for siter.valid() && uintptr(siter.s.offset) < endOffset { + // Find the exact byte for which the special was setup + // (as opposed to object beginning). + special := siter.s + p := s.base() + uintptr(special.offset) + if special.kind == _KindSpecialFinalizer || special.kind == _KindSpecialWeakHandle { + siter.unlinkAndNext() + freeSpecial(special, unsafe.Pointer(p), size) + } else { + // All other specials only apply when an object is freed, + // so just keep the special record. + siter.next() + } + } + } else { + // Pass 2: the object is truly dead, free (and handle) all specials. + for siter.valid() && uintptr(siter.s.offset) < endOffset { + // Find the exact byte for which the special was setup + // (as opposed to object beginning). + special := siter.s + p := s.base() + uintptr(special.offset) siter.unlinkAndNext() freeSpecial(special, unsafe.Pointer(p), size) - } else { - // The object has finalizers, so we're keeping it alive. - // All other specials only apply when an object is freed, - // so just keep the special record. - siter.next() } } } else { @@ -596,16 +608,19 @@ func (sl *sweepLocked) sweep(preserve bool) bool { spanHasNoSpecials(s) } - if debug.allocfreetrace != 0 || debug.clobberfree != 0 || raceenabled || msanenabled || asanenabled { - // Find all newly freed objects. This doesn't have to - // efficient; allocfreetrace has massive overhead. + if traceAllocFreeEnabled() || debug.clobberfree != 0 || raceenabled || msanenabled || asanenabled { + // Find all newly freed objects. mbits := s.markBitsForBase() abits := s.allocBitsForIndex(0) for i := uintptr(0); i < uintptr(s.nelems); i++ { if !mbits.isMarked() && (abits.index < uintptr(s.freeindex) || abits.isMarked()) { x := s.base() + i*s.elemsize - if debug.allocfreetrace != 0 { - tracefree(unsafe.Pointer(x), size) + if traceAllocFreeEnabled() { + trace := traceAcquire() + if trace.ok() { + trace.HeapObjectFree(x) + traceRelease(trace) + } } if debug.clobberfree != 0 { clobberfree(unsafe.Pointer(x), size) @@ -803,8 +818,8 @@ func (sl *sweepLocked) sweep(preserve bool) bool { } else { mheap_.freeSpan(s) } - if goexperiment.AllocHeaders && s.largeType != nil && s.largeType.TFlag&abi.TFlagUnrolledBitmap != 0 { - // In the allocheaders experiment, the unrolled GCProg bitmap is allocated separately. + if s.largeType != nil && s.largeType.TFlag&abi.TFlagUnrolledBitmap != 0 { + // The unrolled GCProg bitmap is allocated separately. // Free the space for the unrolled bitmap. systemstack(func() { s := spanOf(uintptr(unsafe.Pointer(s.largeType))) diff --git a/contrib/go/_std_1.22/src/runtime/mgcwork.go b/contrib/go/_std_1.23/src/runtime/mgcwork.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mgcwork.go rename to contrib/go/_std_1.23/src/runtime/mgcwork.go index 7ab89754d42a..b91a6bd464d7 100644 --- a/contrib/go/_std_1.22/src/runtime/mgcwork.go +++ b/contrib/go/_std_1.23/src/runtime/mgcwork.go @@ -6,7 +6,7 @@ package runtime import ( "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/mheap.go b/contrib/go/_std_1.23/src/runtime/mheap.go similarity index 89% rename from contrib/go/_std_1.22/src/runtime/mheap.go rename to contrib/go/_std_1.23/src/runtime/mheap.go index 00693283467b..bfca2d105b74 100644 --- a/contrib/go/_std_1.22/src/runtime/mheap.go +++ b/contrib/go/_std_1.23/src/runtime/mheap.go @@ -11,8 +11,7 @@ package runtime import ( "internal/cpu" "internal/goarch" - "internal/goexperiment" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -208,6 +207,7 @@ type mheap struct { specialprofilealloc fixalloc // allocator for specialprofile* specialReachableAlloc fixalloc // allocator for specialReachable specialPinCounterAlloc fixalloc // allocator for specialPinCounter + specialWeakHandleAlloc fixalloc // allocator for specialWeakHandle speciallock mutex // lock for special record allocators. arenaHintAlloc fixalloc // allocator for arenaHints @@ -240,9 +240,6 @@ var mheap_ mheap type heapArena struct { _ sys.NotInHeap - // heapArenaPtrScalar contains pointer/scalar data about the heap for this heap arena. - heapArenaPtrScalar - // spans maps from virtual address page ID within this arena to *mspan. // For allocated spans, their pages map to the span itself. // For free spans, only the lowest and highest pages map to the span itself. @@ -749,6 +746,7 @@ func (h *mheap) init() { h.specialprofilealloc.init(unsafe.Sizeof(specialprofile{}), nil, nil, &memstats.other_sys) h.specialReachableAlloc.init(unsafe.Sizeof(specialReachable{}), nil, nil, &memstats.other_sys) h.specialPinCounterAlloc.init(unsafe.Sizeof(specialPinCounter{}), nil, nil, &memstats.other_sys) + h.specialWeakHandleAlloc.init(unsafe.Sizeof(specialWeakHandle{}), nil, nil, &memstats.gcMiscSys) h.arenaHintAlloc.init(unsafe.Sizeof(arenaHint{}), nil, nil, &memstats.other_sys) // Don't zero mspan allocations. Background sweeping can @@ -1368,7 +1366,14 @@ HaveSpan: } memstats.heapStats.release() - pageTraceAlloc(pp, now, base, npages) + // Trace the span alloc. + if traceAllocFreeEnabled() { + trace := traceTryAcquire() + if trace.ok() { + trace.SpanAlloc(s) + traceRelease(trace) + } + } return s } @@ -1397,8 +1402,8 @@ func (h *mheap) initSpan(s *mspan, typ spanAllocType, spanclass spanClass, base, s.divMul = 0 } else { s.elemsize = uintptr(class_to_size[sizeclass]) - if goexperiment.AllocHeaders && !s.spanclass.noscan() && heapBitsInSpan(s.elemsize) { - // In the allocheaders experiment, reserve space for the pointer/scan bitmap at the end. + if !s.spanclass.noscan() && heapBitsInSpan(s.elemsize) { + // Reserve space for the pointer/scan bitmap at the end. s.nelems = uint16((nbytes - (nbytes / goarch.PtrSize / 8)) / s.elemsize) } else { s.nelems = uint16(nbytes / s.elemsize) @@ -1549,7 +1554,14 @@ func (h *mheap) grow(npage uintptr) (uintptr, bool) { // Free the span back into the heap. func (h *mheap) freeSpan(s *mspan) { systemstack(func() { - pageTraceFree(getg().m.p.ptr(), 0, s.base(), s.npages) + // Trace the span free. + if traceAllocFreeEnabled() { + trace := traceTryAcquire() + if trace.ok() { + trace.SpanFree(s) + traceRelease(trace) + } + } lock(&h.lock) if msanenabled { @@ -1581,7 +1593,14 @@ func (h *mheap) freeSpan(s *mspan) { // //go:systemstack func (h *mheap) freeManual(s *mspan, typ spanAllocType) { - pageTraceFree(getg().m.p.ptr(), 0, s.base(), s.npages) + // Trace the span free. + if traceAllocFreeEnabled() { + trace := traceTryAcquire() + if trace.ok() { + trace.SpanFree(s) + traceRelease(trace) + } + } s.needzero = 1 lock(&h.lock) @@ -1793,18 +1812,18 @@ func (list *mSpanList) takeAll(other *mSpanList) { } const ( + // _KindSpecialFinalizer is for tracking finalizers. _KindSpecialFinalizer = 1 - _KindSpecialProfile = 2 + // _KindSpecialWeakHandle is used for creating weak pointers. + _KindSpecialWeakHandle = 2 + // _KindSpecialProfile is for memory profiling. + _KindSpecialProfile = 3 // _KindSpecialReachable is a special used for tracking // reachability during testing. - _KindSpecialReachable = 3 + _KindSpecialReachable = 4 // _KindSpecialPinCounter is a special used for objects that are pinned // multiple times - _KindSpecialPinCounter = 4 - // Note: The finalizer special must be first because if we're freeing - // an object, a finalizer special will cause the freeing operation - // to abort, and we want to keep the other special records around - // if that happens. + _KindSpecialPinCounter = 5 ) type special struct { @@ -1989,6 +2008,235 @@ func removefinalizer(p unsafe.Pointer) { unlock(&mheap_.speciallock) } +// The described object has a weak pointer. +// +// Weak pointers in the GC have the following invariants: +// +// - Strong-to-weak conversions must ensure the strong pointer +// remains live until the weak handle is installed. This ensures +// that creating a weak pointer cannot fail. +// +// - Weak-to-strong conversions require the weakly-referenced +// object to be swept before the conversion may proceed. This +// ensures that weak-to-strong conversions cannot resurrect +// dead objects by sweeping them before that happens. +// +// - Weak handles are unique and canonical for each byte offset into +// an object that a strong pointer may point to, until an object +// becomes unreachable. +// +// - Weak handles contain nil as soon as an object becomes unreachable +// the first time, before a finalizer makes it reachable again. New +// weak handles created after resurrection are newly unique. +// +// specialWeakHandle is allocated from non-GC'd memory, so any heap +// pointers must be specially handled. +type specialWeakHandle struct { + _ sys.NotInHeap + special special + // handle is a reference to the actual weak pointer. + // It is always heap-allocated and must be explicitly kept + // live so long as this special exists. + handle *atomic.Uintptr +} + +//go:linkname internal_weak_runtime_registerWeakPointer internal/weak.runtime_registerWeakPointer +func internal_weak_runtime_registerWeakPointer(p unsafe.Pointer) unsafe.Pointer { + return unsafe.Pointer(getOrAddWeakHandle(unsafe.Pointer(p))) +} + +//go:linkname internal_weak_runtime_makeStrongFromWeak internal/weak.runtime_makeStrongFromWeak +func internal_weak_runtime_makeStrongFromWeak(u unsafe.Pointer) unsafe.Pointer { + handle := (*atomic.Uintptr)(u) + + // Prevent preemption. We want to make sure that another GC cycle can't start + // and that work.strongFromWeak.block can't change out from under us. + mp := acquirem() + + // Yield to the GC if necessary. + if work.strongFromWeak.block { + releasem(mp) + + // Try to park and wait for mark termination. + // N.B. gcParkStrongFromWeak calls acquirem before returning. + mp = gcParkStrongFromWeak() + } + + p := handle.Load() + if p == 0 { + releasem(mp) + return nil + } + // Be careful. p may or may not refer to valid memory anymore, as it could've been + // swept and released already. It's always safe to ensure a span is swept, though, + // even if it's just some random span. + span := spanOfHeap(p) + if span == nil { + // The span probably got swept and released. + releasem(mp) + return nil + } + // Ensure the span is swept. + span.ensureSwept() + + // Now we can trust whatever we get from handle, so make a strong pointer. + // + // Even if we just swept some random span that doesn't contain this object, because + // this object is long dead and its memory has since been reused, we'll just observe nil. + ptr := unsafe.Pointer(handle.Load()) + + // This is responsible for maintaining the same GC-related + // invariants as the Yuasa part of the write barrier. During + // the mark phase, it's possible that we just created the only + // valid pointer to the object pointed to by ptr. If it's only + // ever referenced from our stack, and our stack is blackened + // already, we could fail to mark it. So, mark it now. + if gcphase != _GCoff { + shade(uintptr(ptr)) + } + releasem(mp) + + // Explicitly keep ptr alive. This seems unnecessary since we return ptr, + // but let's be explicit since it's important we keep ptr alive across the + // call to shade. + KeepAlive(ptr) + return ptr +} + +// gcParkStrongFromWeak puts the current goroutine on the weak->strong queue and parks. +func gcParkStrongFromWeak() *m { + // Prevent preemption as we check strongFromWeak, so it can't change out from under us. + mp := acquirem() + + for work.strongFromWeak.block { + lock(&work.strongFromWeak.lock) + releasem(mp) // N.B. Holding the lock prevents preemption. + + // Queue ourselves up. + work.strongFromWeak.q.pushBack(getg()) + + // Park. + goparkunlock(&work.strongFromWeak.lock, waitReasonGCWeakToStrongWait, traceBlockGCWeakToStrongWait, 2) + + // Re-acquire the current M since we're going to check the condition again. + mp = acquirem() + + // Re-check condition. We may have awoken in the next GC's mark termination phase. + } + return mp +} + +// gcWakeAllStrongFromWeak wakes all currently blocked weak->strong +// conversions. This is used at the end of a GC cycle. +// +// work.strongFromWeak.block must be false to prevent woken goroutines +// from immediately going back to sleep. +func gcWakeAllStrongFromWeak() { + lock(&work.strongFromWeak.lock) + list := work.strongFromWeak.q.popList() + injectglist(&list) + unlock(&work.strongFromWeak.lock) +} + +// Retrieves or creates a weak pointer handle for the object p. +func getOrAddWeakHandle(p unsafe.Pointer) *atomic.Uintptr { + // First try to retrieve without allocating. + if handle := getWeakHandle(p); handle != nil { + // Keep p alive for the duration of the function to ensure + // that it cannot die while we're trying to do this. + KeepAlive(p) + return handle + } + + lock(&mheap_.speciallock) + s := (*specialWeakHandle)(mheap_.specialWeakHandleAlloc.alloc()) + unlock(&mheap_.speciallock) + + handle := new(atomic.Uintptr) + s.special.kind = _KindSpecialWeakHandle + s.handle = handle + handle.Store(uintptr(p)) + if addspecial(p, &s.special) { + // This is responsible for maintaining the same + // GC-related invariants as markrootSpans in any + // situation where it's possible that markrootSpans + // has already run but mark termination hasn't yet. + if gcphase != _GCoff { + mp := acquirem() + gcw := &mp.p.ptr().gcw + // Mark the weak handle itself, since the + // special isn't part of the GC'd heap. + scanblock(uintptr(unsafe.Pointer(&s.handle)), goarch.PtrSize, &oneptrmask[0], gcw, nil) + releasem(mp) + } + + // Keep p alive for the duration of the function to ensure + // that it cannot die while we're trying to do this. + // + // Same for handle, which is only stored in the special. + // There's a window where it might die if we don't keep it + // alive explicitly. Returning it here is probably good enough, + // but let's be defensive and explicit. See #70455. + KeepAlive(p) + KeepAlive(handle) + return handle + } + + // There was an existing handle. Free the special + // and try again. We must succeed because we're explicitly + // keeping p live until the end of this function. Either + // we, or someone else, must have succeeded, because we can + // only fail in the event of a race, and p will still be + // be valid no matter how much time we spend here. + lock(&mheap_.speciallock) + mheap_.specialWeakHandleAlloc.free(unsafe.Pointer(s)) + unlock(&mheap_.speciallock) + + handle = getWeakHandle(p) + if handle == nil { + throw("failed to get or create weak handle") + } + + // Keep p alive for the duration of the function to ensure + // that it cannot die while we're trying to do this. + // + // Same for handle, just to be defensive. + KeepAlive(p) + KeepAlive(handle) + return handle +} + +func getWeakHandle(p unsafe.Pointer) *atomic.Uintptr { + span := spanOfHeap(uintptr(p)) + if span == nil { + throw("getWeakHandle on invalid pointer") + } + + // Ensure that the span is swept. + // Sweeping accesses the specials list w/o locks, so we have + // to synchronize with it. And it's just much safer. + mp := acquirem() + span.ensureSwept() + + offset := uintptr(p) - span.base() + + lock(&span.speciallock) + + // Find the existing record and return the handle if one exists. + var handle *atomic.Uintptr + iter, exists := span.specialFindSplicePoint(offset, _KindSpecialWeakHandle) + if exists { + handle = ((*specialWeakHandle)(unsafe.Pointer(*iter))).handle + } + unlock(&span.speciallock) + releasem(mp) + + // Keep p alive for the duration of the function to ensure + // that it cannot die while we're trying to do this. + KeepAlive(p) + return handle +} + // The described object is being heap profiled. type specialprofile struct { _ sys.NotInHeap @@ -2060,6 +2308,12 @@ func freeSpecial(s *special, p unsafe.Pointer, size uintptr) { lock(&mheap_.speciallock) mheap_.specialfinalizeralloc.free(unsafe.Pointer(sf)) unlock(&mheap_.speciallock) + case _KindSpecialWeakHandle: + sw := (*specialWeakHandle)(unsafe.Pointer(s)) + sw.handle.Store(0) + lock(&mheap_.speciallock) + mheap_.specialWeakHandleAlloc.free(unsafe.Pointer(s)) + unlock(&mheap_.speciallock) case _KindSpecialProfile: sp := (*specialprofile)(unsafe.Pointer(s)) mProf_Free(sp.b, size) diff --git a/contrib/go/_std_1.22/src/runtime/minmax.go b/contrib/go/_std_1.23/src/runtime/minmax.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/minmax.go rename to contrib/go/_std_1.23/src/runtime/minmax.go diff --git a/contrib/go/_std_1.22/src/runtime/mkduff.go b/contrib/go/_std_1.23/src/runtime/mkduff.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mkduff.go rename to contrib/go/_std_1.23/src/runtime/mkduff.go diff --git a/contrib/go/_std_1.22/src/runtime/mkfastlog2table.go b/contrib/go/_std_1.23/src/runtime/mkfastlog2table.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mkfastlog2table.go rename to contrib/go/_std_1.23/src/runtime/mkfastlog2table.go diff --git a/contrib/go/_std_1.22/src/runtime/mklockrank.go b/contrib/go/_std_1.23/src/runtime/mklockrank.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/mklockrank.go rename to contrib/go/_std_1.23/src/runtime/mklockrank.go index c8e34d8f00a0..3391afc65725 100644 --- a/contrib/go/_std_1.22/src/runtime/mklockrank.go +++ b/contrib/go/_std_1.23/src/runtime/mklockrank.go @@ -50,23 +50,24 @@ NONE < defer; NONE < sweepWaiters, assistQueue, + strongFromWeakQueue, sweep; # Test only NONE < testR, testW; +NONE < timerSend; + # Scheduler, timers, netpoll -NONE < - allocmW, - execW, - cpuprof, - pollDesc, - wakeableSleep; +NONE < allocmW, execW, cpuprof, pollCache, pollDesc, wakeableSleep; +scavenge, sweep, testR, wakeableSleep, timerSend < hchan; assistQueue, cpuprof, forcegc, + hchan, pollDesc, # pollDesc can interact with timers, which can lock sched. scavenge, + strongFromWeakQueue, sweep, sweepWaiters, testR, @@ -75,17 +76,17 @@ assistQueue, < SCHED # Below SCHED is the scheduler implementation. < allocmR, - execR -< sched; + execR; +allocmR, execR, hchan < sched; sched < allg, allp; -allp, wakeableSleep < timers; -timers < netpollInit; # Channels -scavenge, sweep, testR, wakeableSleep < hchan; NONE < notifyList; hchan, notifyList < sudog; +hchan, pollDesc, wakeableSleep < timers; +timers, timerSend < timer < netpollInit; + # Semaphores NONE < root; @@ -111,12 +112,13 @@ traceBuf < traceStrings; # Malloc allg, allocmR, + allp, # procresize execR, # May grow stack execW, # May allocate after BeforeFork hchan, notifyList, reflectOffs, - timers, + timer, traceStrings, userArenaState # Above MALLOC are things that can allocate memory. @@ -125,6 +127,7 @@ allg, < fin, spanSetSpine, mspanSpecial, + traceTypeTab, MPROF; # We can acquire gcBitsArenas for pinner bits, and @@ -161,7 +164,9 @@ gscan < hchanLeaf; defer, gscan, mspanSpecial, - sudog + pollCache, + sudog, + timer # Anything that can have write barriers can acquire WB. # Above WB, we can have write barriers. < WB diff --git a/contrib/go/_std_1.22/src/runtime/mkpreempt.go b/contrib/go/_std_1.23/src/runtime/mkpreempt.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mkpreempt.go rename to contrib/go/_std_1.23/src/runtime/mkpreempt.go diff --git a/contrib/go/_std_1.22/src/runtime/mksizeclasses.go b/contrib/go/_std_1.23/src/runtime/mksizeclasses.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mksizeclasses.go rename to contrib/go/_std_1.23/src/runtime/mksizeclasses.go index 26ca49e6eb13..bb06ba1eddc3 100644 --- a/contrib/go/_std_1.22/src/runtime/mksizeclasses.go +++ b/contrib/go/_std_1.23/src/runtime/mksizeclasses.go @@ -75,6 +75,7 @@ func main() { const ( // Constants that we use and will transfer to the runtime. + minHeapAlign = 8 maxSmallSize = 32 << 10 smallSizeDiv = 8 smallSizeMax = 1024 @@ -99,7 +100,7 @@ func makeClasses() []class { classes = append(classes, class{}) // class #0 is a dummy entry - align := 8 + align := minHeapAlign for size := align; size <= maxSmallSize; size += align { if powerOfTwo(size) { // bump alignment once in a while if size >= 2048 { @@ -288,6 +289,7 @@ func maxObjsPerSpan(classes []class) int { func printClasses(w io.Writer, classes []class) { fmt.Fprintln(w, "const (") + fmt.Fprintf(w, "minHeapAlign = %d\n", minHeapAlign) fmt.Fprintf(w, "_MaxSmallSize = %d\n", maxSmallSize) fmt.Fprintf(w, "smallSizeDiv = %d\n", smallSizeDiv) fmt.Fprintf(w, "smallSizeMax = %d\n", smallSizeMax) diff --git a/contrib/go/_std_1.22/src/runtime/mmap.go b/contrib/go/_std_1.23/src/runtime/mmap.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mmap.go rename to contrib/go/_std_1.23/src/runtime/mmap.go diff --git a/contrib/go/_std_1.22/src/runtime/mpagealloc.go b/contrib/go/_std_1.23/src/runtime/mpagealloc.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mpagealloc.go rename to contrib/go/_std_1.23/src/runtime/mpagealloc.go index d533f84180fb..46d3ebacaf8a 100644 --- a/contrib/go/_std_1.22/src/runtime/mpagealloc.go +++ b/contrib/go/_std_1.23/src/runtime/mpagealloc.go @@ -48,7 +48,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -511,10 +511,7 @@ func (p *pageAlloc) update(base, npages uintptr, contig, alloc bool) { // either totally allocated or freed. whole := p.summary[len(p.summary)-1][sc+1 : ec] if alloc { - // Should optimize into a memclr. - for i := range whole { - whole[i] = 0 - } + clear(whole) } else { for i := range whole { whole[i] = freeChunkSum diff --git a/contrib/go/_std_1.22/src/runtime/mpagealloc_32bit.go b/contrib/go/_std_1.23/src/runtime/mpagealloc_32bit.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mpagealloc_32bit.go rename to contrib/go/_std_1.23/src/runtime/mpagealloc_32bit.go diff --git a/contrib/go/_std_1.22/src/runtime/mpagealloc_64bit.go b/contrib/go/_std_1.23/src/runtime/mpagealloc_64bit.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mpagealloc_64bit.go rename to contrib/go/_std_1.23/src/runtime/mpagealloc_64bit.go diff --git a/contrib/go/_std_1.22/src/runtime/mpagecache.go b/contrib/go/_std_1.23/src/runtime/mpagecache.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/mpagecache.go rename to contrib/go/_std_1.23/src/runtime/mpagecache.go diff --git a/contrib/go/_std_1.22/src/runtime/mpallocbits.go b/contrib/go/_std_1.23/src/runtime/mpallocbits.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mpallocbits.go rename to contrib/go/_std_1.23/src/runtime/mpallocbits.go index 6b5f15dbd8ed..d8a9d25789d6 100644 --- a/contrib/go/_std_1.22/src/runtime/mpallocbits.go +++ b/contrib/go/_std_1.23/src/runtime/mpallocbits.go @@ -85,18 +85,14 @@ func (b *pageBits) clearRange(i, n uint) { _ = b[j/64] // Clear leading bits. b[i/64] &^= ^uint64(0) << (i % 64) - for k := i/64 + 1; k < j/64; k++ { - b[k] = 0 - } + clear(b[i/64+1 : j/64]) // Clear trailing bits. b[j/64] &^= (uint64(1) << (j%64 + 1)) - 1 } // clearAll frees all the bits of b. func (b *pageBits) clearAll() { - for i := range b { - b[i] = 0 - } + clear(b[:]) } // clearBlock64 clears the 64-bit aligned block of bits containing the i'th bit that @@ -328,7 +324,6 @@ func (b *pallocBits) findLargeN(npages uintptr, searchIdx uint) (uint, uint) { } s := uint(sys.TrailingZeros64(x)) if s+size >= uint(npages) { - size += s return start, newSearchIdx } if s < 64 { diff --git a/contrib/go/_std_1.22/src/runtime/mprof.go b/contrib/go/_std_1.23/src/runtime/mprof.go similarity index 75% rename from contrib/go/_std_1.22/src/runtime/mprof.go rename to contrib/go/_std_1.23/src/runtime/mprof.go index abdd2f3e8c9d..ee3e59a9aa99 100644 --- a/contrib/go/_std_1.22/src/runtime/mprof.go +++ b/contrib/go/_std_1.23/src/runtime/mprof.go @@ -9,7 +9,9 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/goarch" + "internal/profilerecord" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -39,11 +41,20 @@ const ( // size of bucket hash table buckHashSize = 179999 - // maxStack is the max depth of stack to record in bucket. - // Note that it's only used internally as a guard against - // wildly out-of-bounds slicing of the PCs that come after - // a bucket struct, and it could increase in the future. - maxStack = 32 + // maxSkip is to account for deferred inline expansion + // when using frame pointer unwinding. We record the stack + // with "physical" frame pointers but handle skipping "logical" + // frames at some point after collecting the stack. So + // we need extra space in order to avoid getting fewer than the + // desired maximum number of frames after expansion. + // This should be at least as large as the largest skip value + // used for profiling; otherwise stacks may be truncated inconsistently + maxSkip = 5 + + // maxProfStackDepth is the highest valid value for debug.profstackdepth. + // It's used for the bucket.stk func. + // TODO(fg): can we get rid of this? + maxProfStackDepth = 1024 ) type bucketType int @@ -231,10 +242,11 @@ func newBucket(typ bucketType, nstk int) *bucket { return b } -// stk returns the slice in b holding the stack. +// stk returns the slice in b holding the stack. The caller can asssume that the +// backing array is immutable. func (b *bucket) stk() []uintptr { - stk := (*[maxStack]uintptr)(add(unsafe.Pointer(b), unsafe.Sizeof(*b))) - if b.nstk > maxStack { + stk := (*[maxProfStackDepth]uintptr)(add(unsafe.Pointer(b), unsafe.Sizeof(*b))) + if b.nstk > maxProfStackDepth { // prove that slicing works; otherwise a failure requires a P throw("bad profile stack count") } @@ -422,15 +434,22 @@ func mProf_PostSweep() { } // Called by malloc to record a profiled block. -func mProf_Malloc(p unsafe.Pointer, size uintptr) { - var stk [maxStack]uintptr - nstk := callers(4, stk[:]) - +func mProf_Malloc(mp *m, p unsafe.Pointer, size uintptr) { + if mp.profStack == nil { + // mp.profStack is nil if we happen to sample an allocation during the + // initialization of mp. This case is rare, so we just ignore such + // allocations. Change MemProfileRate to 1 if you need to reproduce such + // cases for testing purposes. + return + } + // Only use the part of mp.profStack we need and ignore the extra space + // reserved for delayed inline expansion with frame pointer unwinding. + nstk := callers(4, mp.profStack[:debug.profstackdepth]) index := (mProfCycle.read() + 2) % uint32(len(memRecord{}.future)) - b := stkbucket(memProfile, size, stk[:nstk], true) - mp := b.mp() - mpc := &mp.future[index] + b := stkbucket(memProfile, size, mp.profStack[:nstk], true) + mr := b.mp() + mpc := &mr.future[index] lock(&profMemFutureLock[index]) mpc.allocs++ @@ -504,17 +523,98 @@ func blocksampled(cycles, rate int64) bool { return true } +// saveblockevent records a profile event of the type specified by which. +// cycles is the quantity associated with this event and rate is the sampling rate, +// used to adjust the cycles value in the manner determined by the profile type. +// skip is the number of frames to omit from the traceback associated with the event. +// The traceback will be recorded from the stack of the goroutine associated with the current m. +// skip should be positive if this event is recorded from the current stack +// (e.g. when this is not called from a system stack) func saveblockevent(cycles, rate int64, skip int, which bucketType) { + if debug.profstackdepth == 0 { + // profstackdepth is set to 0 by the user, so mp.profStack is nil and we + // can't record a stack trace. + return + } + if skip > maxSkip { + print("requested skip=", skip) + throw("invalid skip value") + } gp := getg() + mp := acquirem() // we must not be preempted while accessing profstack + var nstk int - var stk [maxStack]uintptr - if gp.m.curg == nil || gp.m.curg == gp { - nstk = callers(skip, stk[:]) + if tracefpunwindoff() || gp.m.hasCgoOnStack() { + if gp.m.curg == nil || gp.m.curg == gp { + nstk = callers(skip, mp.profStack) + } else { + nstk = gcallers(gp.m.curg, skip, mp.profStack) + } } else { - nstk = gcallers(gp.m.curg, skip, stk[:]) + if gp.m.curg == nil || gp.m.curg == gp { + if skip > 0 { + // We skip one fewer frame than the provided value for frame + // pointer unwinding because the skip value includes the current + // frame, whereas the saved frame pointer will give us the + // caller's return address first (so, not including + // saveblockevent) + skip -= 1 + } + nstk = fpTracebackPartialExpand(skip, unsafe.Pointer(getfp()), mp.profStack) + } else { + mp.profStack[0] = gp.m.curg.sched.pc + nstk = 1 + fpTracebackPartialExpand(skip, unsafe.Pointer(gp.m.curg.sched.bp), mp.profStack[1:]) + } } - saveBlockEventStack(cycles, rate, stk[:nstk], which) + saveBlockEventStack(cycles, rate, mp.profStack[:nstk], which) + releasem(mp) +} + +// fpTracebackPartialExpand records a call stack obtained starting from fp. +// This function will skip the given number of frames, properly accounting for +// inlining, and save remaining frames as "physical" return addresses. The +// consumer should later use CallersFrames or similar to expand inline frames. +func fpTracebackPartialExpand(skip int, fp unsafe.Pointer, pcBuf []uintptr) int { + var n int + lastFuncID := abi.FuncIDNormal + skipOrAdd := func(retPC uintptr) bool { + if skip > 0 { + skip-- + } else if n < len(pcBuf) { + pcBuf[n] = retPC + n++ + } + return n < len(pcBuf) + } + for n < len(pcBuf) && fp != nil { + // return addr sits one word above the frame pointer + pc := *(*uintptr)(unsafe.Pointer(uintptr(fp) + goarch.PtrSize)) + + if skip > 0 { + callPC := pc - 1 + fi := findfunc(callPC) + u, uf := newInlineUnwinder(fi, callPC) + for ; uf.valid(); uf = u.next(uf) { + sf := u.srcFunc(uf) + if sf.funcID == abi.FuncIDWrapper && elideWrapperCalling(lastFuncID) { + // ignore wrappers + } else if more := skipOrAdd(uf.pc + 1); !more { + return n + } + lastFuncID = sf.funcID + } + } else { + // We've skipped the desired number of frames, so no need + // to perform further inline expansion now. + pcBuf[n] = pc + n++ + } + + // follow the frame pointer to the next one + fp = unsafe.Pointer(*(*uintptr)(fp)) + } + return n } // lockTimer assists with profiling contention on runtime-internal locks. @@ -613,12 +713,12 @@ func (lt *lockTimer) end() { } type mLockProfile struct { - waitTime atomic.Int64 // total nanoseconds spent waiting in runtime.lockWithRank - stack [maxStack]uintptr // stack that experienced contention in runtime.lockWithRank - pending uintptr // *mutex that experienced contention (to be traceback-ed) - cycles int64 // cycles attributable to "pending" (if set), otherwise to "stack" - cyclesLost int64 // contention for which we weren't able to record a call stack - disabled bool // attribute all time to "lost" + waitTime atomic.Int64 // total nanoseconds spent waiting in runtime.lockWithRank + stack []uintptr // stack that experienced contention in runtime.lockWithRank + pending uintptr // *mutex that experienced contention (to be traceback-ed) + cycles int64 // cycles attributable to "pending" (if set), otherwise to "stack" + cyclesLost int64 // contention for which we weren't able to record a call stack + disabled bool // attribute all time to "lost" } func (prof *mLockProfile) recordLock(cycles int64, l *mutex) { @@ -675,6 +775,12 @@ func (prof *mLockProfile) recordUnlock(l *mutex) { } func (prof *mLockProfile) captureStack() { + if debug.profstackdepth == 0 { + // profstackdepth is set to 0 by the user, so mp.profStack is nil and we + // can't record a stack trace. + return + } + skip := 3 // runtime.(*mLockProfile).recordUnlock runtime.unlock2 runtime.unlockWithRank if staticLockRanking { // When static lock ranking is enabled, we'll always be on the system @@ -690,9 +796,10 @@ func (prof *mLockProfile) captureStack() { } prof.pending = 0 + prof.stack[0] = logicalStackSentinel if debug.runtimeContentionStacks.Load() == 0 { - prof.stack[0] = abi.FuncPCABIInternal(_LostContendedRuntimeLock) + sys.PCQuantum - prof.stack[1] = 0 + prof.stack[1] = abi.FuncPCABIInternal(_LostContendedRuntimeLock) + sys.PCQuantum + prof.stack[2] = 0 return } @@ -703,7 +810,7 @@ func (prof *mLockProfile) captureStack() { systemstack(func() { var u unwinder u.initAt(pc, sp, 0, gp, unwindSilentErrors|unwindJumpStack) - nstk = tracebackPCs(&u, skip, prof.stack[:]) + nstk = 1 + tracebackPCs(&u, skip, prof.stack[1:]) }) if nstk < len(prof.stack) { prof.stack[nstk] = 0 @@ -718,7 +825,7 @@ func (prof *mLockProfile) store() { mp := acquirem() prof.disabled = true - nstk := maxStack + nstk := int(debug.profstackdepth) for i := 0; i < nstk; i++ { if pc := prof.stack[i]; pc == 0 { nstk = i @@ -733,6 +840,7 @@ func (prof *mLockProfile) store() { saveBlockEventStack(cycles, rate, prof.stack[:nstk], mutexProfile) if lost > 0 { lostStk := [...]uintptr{ + logicalStackSentinel, abi.FuncPCABIInternal(_LostContendedRuntimeLock) + sys.PCQuantum, } saveBlockEventStack(lost, rate, lostStk[:], mutexProfile) @@ -829,9 +937,10 @@ func (r *StackRecord) Stack() []uintptr { // at the beginning of main). var MemProfileRate int = 512 * 1024 -// disableMemoryProfiling is set by the linker if runtime.MemProfile +// disableMemoryProfiling is set by the linker if memory profiling // is not used and the link type guarantees nobody else could use it // elsewhere. +// We check if the runtime.memProfileInternal symbol is present. var disableMemoryProfiling bool // A MemProfileRecord describes the live objects allocated @@ -883,6 +992,23 @@ func (r *MemProfileRecord) Stack() []uintptr { // the testing package's -test.memprofile flag instead // of calling MemProfile directly. func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) { + return memProfileInternal(len(p), inuseZero, func(r profilerecord.MemProfileRecord) { + copyMemProfileRecord(&p[0], r) + p = p[1:] + }) +} + +// memProfileInternal returns the number of records n in the profile. If there +// are less than size records, copyFn is invoked for each record, and ok returns +// true. +// +// The linker set disableMemoryProfiling to true to disable memory profiling +// if this function is not reachable. Mark it noinline to ensure the symbol exists. +// (This function is big and normally not inlined anyway.) +// See also disableMemoryProfiling above and cmd/link/internal/ld/lib.go:linksetup. +// +//go:noinline +func memProfileInternal(size int, inuseZero bool, copyFn func(profilerecord.MemProfileRecord)) (n int, ok bool) { cycle := mProfCycle.read() // If we're between mProf_NextCycle and mProf_Flush, take care // of flushing to the active profile so we only have to look @@ -922,14 +1048,19 @@ func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) { } } } - if n <= len(p) { + if n <= size { ok = true - idx := 0 for b := head; b != nil; b = b.allnext { mp := b.mp() if inuseZero || mp.active.alloc_bytes != mp.active.free_bytes { - record(&p[idx], b) - idx++ + r := profilerecord.MemProfileRecord{ + AllocBytes: int64(mp.active.alloc_bytes), + FreeBytes: int64(mp.active.free_bytes), + AllocObjects: int64(mp.active.allocs), + FreeObjects: int64(mp.active.frees), + Stack: b.stk(), + } + copyFn(r) } } } @@ -937,26 +1068,30 @@ func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) { return } -// Write b's data to r. -func record(r *MemProfileRecord, b *bucket) { - mp := b.mp() - r.AllocBytes = int64(mp.active.alloc_bytes) - r.FreeBytes = int64(mp.active.free_bytes) - r.AllocObjects = int64(mp.active.allocs) - r.FreeObjects = int64(mp.active.frees) +func copyMemProfileRecord(dst *MemProfileRecord, src profilerecord.MemProfileRecord) { + dst.AllocBytes = src.AllocBytes + dst.FreeBytes = src.FreeBytes + dst.AllocObjects = src.AllocObjects + dst.FreeObjects = src.FreeObjects if raceenabled { - racewriterangepc(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0), getcallerpc(), abi.FuncPCABIInternal(MemProfile)) + racewriterangepc(unsafe.Pointer(&dst.Stack0[0]), unsafe.Sizeof(dst.Stack0), getcallerpc(), abi.FuncPCABIInternal(MemProfile)) } if msanenabled { - msanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0)) + msanwrite(unsafe.Pointer(&dst.Stack0[0]), unsafe.Sizeof(dst.Stack0)) } if asanenabled { - asanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0)) - } - copy(r.Stack0[:], b.stk()) - for i := int(b.nstk); i < len(r.Stack0); i++ { - r.Stack0[i] = 0 + asanwrite(unsafe.Pointer(&dst.Stack0[0]), unsafe.Sizeof(dst.Stack0)) } + i := copy(dst.Stack0[:], src.Stack) + clear(dst.Stack0[i:]) +} + +//go:linkname pprof_memProfileInternal +func pprof_memProfileInternal(p []profilerecord.MemProfileRecord, inuseZero bool) (n int, ok bool) { + return memProfileInternal(len(p), inuseZero, func(r profilerecord.MemProfileRecord) { + p[0] = r + p = p[1:] + }) } func iterate_memprof(fn func(*bucket, uintptr, *uintptr, uintptr, uintptr, uintptr)) { @@ -985,43 +1120,98 @@ type BlockProfileRecord struct { // the [testing] package's -test.blockprofile flag instead // of calling BlockProfile directly. func BlockProfile(p []BlockProfileRecord) (n int, ok bool) { + var m int + n, ok = blockProfileInternal(len(p), func(r profilerecord.BlockProfileRecord) { + copyBlockProfileRecord(&p[m], r) + m++ + }) + if ok { + expandFrames(p[:n]) + } + return +} + +func expandFrames(p []BlockProfileRecord) { + expandedStack := makeProfStack() + for i := range p { + cf := CallersFrames(p[i].Stack()) + j := 0 + for j < len(expandedStack) { + f, more := cf.Next() + // f.PC is a "call PC", but later consumers will expect + // "return PCs" + expandedStack[j] = f.PC + 1 + j++ + if !more { + break + } + } + k := copy(p[i].Stack0[:], expandedStack[:j]) + clear(p[i].Stack0[k:]) + } +} + +// blockProfileInternal returns the number of records n in the profile. If there +// are less than size records, copyFn is invoked for each record, and ok returns +// true. +func blockProfileInternal(size int, copyFn func(profilerecord.BlockProfileRecord)) (n int, ok bool) { lock(&profBlockLock) head := (*bucket)(bbuckets.Load()) for b := head; b != nil; b = b.allnext { n++ } - if n <= len(p) { + if n <= size { ok = true for b := head; b != nil; b = b.allnext { bp := b.bp() - r := &p[0] - r.Count = int64(bp.count) + r := profilerecord.BlockProfileRecord{ + Count: int64(bp.count), + Cycles: bp.cycles, + Stack: b.stk(), + } // Prevent callers from having to worry about division by zero errors. // See discussion on http://golang.org/cl/299991. if r.Count == 0 { r.Count = 1 } - r.Cycles = bp.cycles - if raceenabled { - racewriterangepc(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0), getcallerpc(), abi.FuncPCABIInternal(BlockProfile)) - } - if msanenabled { - msanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0)) - } - if asanenabled { - asanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0)) - } - i := copy(r.Stack0[:], b.stk()) - for ; i < len(r.Stack0); i++ { - r.Stack0[i] = 0 - } - p = p[1:] + copyFn(r) } } unlock(&profBlockLock) return } +// copyBlockProfileRecord copies the sample values and call stack from src to dst. +// The call stack is copied as-is. The caller is responsible for handling inline +// expansion, needed when the call stack was collected with frame pointer unwinding. +func copyBlockProfileRecord(dst *BlockProfileRecord, src profilerecord.BlockProfileRecord) { + dst.Count = src.Count + dst.Cycles = src.Cycles + if raceenabled { + racewriterangepc(unsafe.Pointer(&dst.Stack0[0]), unsafe.Sizeof(dst.Stack0), getcallerpc(), abi.FuncPCABIInternal(BlockProfile)) + } + if msanenabled { + msanwrite(unsafe.Pointer(&dst.Stack0[0]), unsafe.Sizeof(dst.Stack0)) + } + if asanenabled { + asanwrite(unsafe.Pointer(&dst.Stack0[0]), unsafe.Sizeof(dst.Stack0)) + } + // We just copy the stack here without inline expansion + // (needed if frame pointer unwinding is used) + // since this function is called under the profile lock, + // and doing something that might allocate can violate lock ordering. + i := copy(dst.Stack0[:], src.Stack) + clear(dst.Stack0[i:]) +} + +//go:linkname pprof_blockProfileInternal +func pprof_blockProfileInternal(p []profilerecord.BlockProfileRecord) (n int, ok bool) { + return blockProfileInternal(len(p), func(r profilerecord.BlockProfileRecord) { + p[0] = r + p = p[1:] + }) +} + // MutexProfile returns n, the number of records in the current mutex profile. // If len(p) >= n, MutexProfile copies the profile into p and returns n, true. // Otherwise, MutexProfile does not change p, and returns n, false. @@ -1029,29 +1219,50 @@ func BlockProfile(p []BlockProfileRecord) (n int, ok bool) { // Most clients should use the [runtime/pprof] package // instead of calling MutexProfile directly. func MutexProfile(p []BlockProfileRecord) (n int, ok bool) { + var m int + n, ok = mutexProfileInternal(len(p), func(r profilerecord.BlockProfileRecord) { + copyBlockProfileRecord(&p[m], r) + m++ + }) + if ok { + expandFrames(p[:n]) + } + return +} + +// mutexProfileInternal returns the number of records n in the profile. If there +// are less than size records, copyFn is invoked for each record, and ok returns +// true. +func mutexProfileInternal(size int, copyFn func(profilerecord.BlockProfileRecord)) (n int, ok bool) { lock(&profBlockLock) head := (*bucket)(xbuckets.Load()) for b := head; b != nil; b = b.allnext { n++ } - if n <= len(p) { + if n <= size { ok = true for b := head; b != nil; b = b.allnext { bp := b.bp() - r := &p[0] - r.Count = int64(bp.count) - r.Cycles = bp.cycles - i := copy(r.Stack0[:], b.stk()) - for ; i < len(r.Stack0); i++ { - r.Stack0[i] = 0 + r := profilerecord.BlockProfileRecord{ + Count: int64(bp.count), + Cycles: bp.cycles, + Stack: b.stk(), } - p = p[1:] + copyFn(r) } } unlock(&profBlockLock) return } +//go:linkname pprof_mutexProfileInternal +func pprof_mutexProfileInternal(p []profilerecord.BlockProfileRecord) (n int, ok bool) { + return mutexProfileInternal(len(p), func(r profilerecord.BlockProfileRecord) { + p[0] = r + p = p[1:] + }) +} + // ThreadCreateProfile returns n, the number of records in the thread creation profile. // If len(p) >= n, ThreadCreateProfile copies the profile into p and returns n, true. // If len(p) < n, ThreadCreateProfile does not change p and returns n, false. @@ -1059,28 +1270,46 @@ func MutexProfile(p []BlockProfileRecord) (n int, ok bool) { // Most clients should use the runtime/pprof package instead // of calling ThreadCreateProfile directly. func ThreadCreateProfile(p []StackRecord) (n int, ok bool) { + return threadCreateProfileInternal(len(p), func(r profilerecord.StackRecord) { + i := copy(p[0].Stack0[:], r.Stack) + clear(p[0].Stack0[i:]) + p = p[1:] + }) +} + +// threadCreateProfileInternal returns the number of records n in the profile. +// If there are less than size records, copyFn is invoked for each record, and +// ok returns true. +func threadCreateProfileInternal(size int, copyFn func(profilerecord.StackRecord)) (n int, ok bool) { first := (*m)(atomic.Loadp(unsafe.Pointer(&allm))) for mp := first; mp != nil; mp = mp.alllink { n++ } - if n <= len(p) { + if n <= size { ok = true - i := 0 for mp := first; mp != nil; mp = mp.alllink { - p[i].Stack0 = mp.createstack - i++ + r := profilerecord.StackRecord{Stack: mp.createstack[:]} + copyFn(r) } } return } -//go:linkname runtime_goroutineProfileWithLabels runtime/pprof.runtime_goroutineProfileWithLabels -func runtime_goroutineProfileWithLabels(p []StackRecord, labels []unsafe.Pointer) (n int, ok bool) { +//go:linkname pprof_threadCreateInternal +func pprof_threadCreateInternal(p []profilerecord.StackRecord) (n int, ok bool) { + return threadCreateProfileInternal(len(p), func(r profilerecord.StackRecord) { + p[0] = r + p = p[1:] + }) +} + +//go:linkname pprof_goroutineProfileWithLabels +func pprof_goroutineProfileWithLabels(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) { return goroutineProfileWithLabels(p, labels) } // labels may be nil. If labels is non-nil, it must have the same length as p. -func goroutineProfileWithLabels(p []StackRecord, labels []unsafe.Pointer) (n int, ok bool) { +func goroutineProfileWithLabels(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) { if labels != nil && len(labels) != len(p) { labels = nil } @@ -1092,7 +1321,7 @@ var goroutineProfile = struct { sema uint32 active bool offset atomic.Int64 - records []StackRecord + records []profilerecord.StackRecord labels []unsafe.Pointer }{ sema: 1, @@ -1131,11 +1360,20 @@ func (p *goroutineProfileStateHolder) CompareAndSwap(old, new goroutineProfileSt return (*atomic.Uint32)(p).CompareAndSwap(uint32(old), uint32(new)) } -func goroutineProfileWithLabelsConcurrent(p []StackRecord, labels []unsafe.Pointer) (n int, ok bool) { +func goroutineProfileWithLabelsConcurrent(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) { + if len(p) == 0 { + // An empty slice is obviously too small. Return a rough + // allocation estimate without bothering to STW. As long as + // this is close, then we'll only need to STW once (on the next + // call). + return int(gcount()), false + } + semacquire(&goroutineProfile.sema) ourg := getg() + pcbuf := makeProfStack() // see saveg() for explanation stw := stopTheWorld(stwGoroutineProfile) // Using gcount while the world is stopped should give us a consistent view // of the number of live goroutines, minus the number of goroutines that are @@ -1162,7 +1400,7 @@ func goroutineProfileWithLabelsConcurrent(p []StackRecord, labels []unsafe.Point sp := getcallersp() pc := getcallerpc() systemstack(func() { - saveg(pc, sp, ourg, &p[0]) + saveg(pc, sp, ourg, &p[0], pcbuf) }) if labels != nil { labels[0] = ourg.labels @@ -1184,7 +1422,7 @@ func goroutineProfileWithLabelsConcurrent(p []StackRecord, labels []unsafe.Point if fing != nil { fing.goroutineProfiled.Store(goroutineProfileSatisfied) if readgstatus(fing) != _Gdead && !isSystemGoroutine(fing, false) { - doRecordGoroutineProfile(fing) + doRecordGoroutineProfile(fing, pcbuf) } } startTheWorld(stw) @@ -1201,7 +1439,7 @@ func goroutineProfileWithLabelsConcurrent(p []StackRecord, labels []unsafe.Point // call will start by adding itself to the profile (before the act of // executing can cause any changes in its stack). forEachGRace(func(gp1 *g) { - tryRecordGoroutineProfile(gp1, Gosched) + tryRecordGoroutineProfile(gp1, pcbuf, Gosched) }) stw = stopTheWorld(stwGoroutineProfileCleanup) @@ -1245,13 +1483,13 @@ func tryRecordGoroutineProfileWB(gp1 *g) { if getg().m.p.ptr() == nil { throw("no P available, write barriers are forbidden") } - tryRecordGoroutineProfile(gp1, osyield) + tryRecordGoroutineProfile(gp1, nil, osyield) } // tryRecordGoroutineProfile ensures that gp1 has the appropriate representation // in the current goroutine profile: either that it should not be profiled, or // that a snapshot of its call stack and labels are now in the profile. -func tryRecordGoroutineProfile(gp1 *g, yield func()) { +func tryRecordGoroutineProfile(gp1 *g, pcbuf []uintptr, yield func()) { if readgstatus(gp1) == _Gdead { // Dead goroutines should not appear in the profile. Goroutines that // start while profile collection is active will get goroutineProfiled @@ -1286,7 +1524,7 @@ func tryRecordGoroutineProfile(gp1 *g, yield func()) { // in this limbo. mp := acquirem() if gp1.goroutineProfiled.CompareAndSwap(goroutineProfileAbsent, goroutineProfileInProgress) { - doRecordGoroutineProfile(gp1) + doRecordGoroutineProfile(gp1, pcbuf) gp1.goroutineProfiled.Store(goroutineProfileSatisfied) } releasem(mp) @@ -1300,7 +1538,7 @@ func tryRecordGoroutineProfile(gp1 *g, yield func()) { // goroutine that is coordinating the goroutine profile (running on its own // stack), or from the scheduler in preparation to execute gp1 (running on the // system stack). -func doRecordGoroutineProfile(gp1 *g) { +func doRecordGoroutineProfile(gp1 *g, pcbuf []uintptr) { if readgstatus(gp1) == _Grunning { print("doRecordGoroutineProfile gp1=", gp1.goid, "\n") throw("cannot read stack of running goroutine") @@ -1323,14 +1561,14 @@ func doRecordGoroutineProfile(gp1 *g) { // set gp1.goroutineProfiled to goroutineProfileInProgress and so are still // preventing it from being truly _Grunnable. So we'll use the system stack // to avoid schedule delays. - systemstack(func() { saveg(^uintptr(0), ^uintptr(0), gp1, &goroutineProfile.records[offset]) }) + systemstack(func() { saveg(^uintptr(0), ^uintptr(0), gp1, &goroutineProfile.records[offset], pcbuf) }) if goroutineProfile.labels != nil { goroutineProfile.labels[offset] = gp1.labels } } -func goroutineProfileWithLabelsSync(p []StackRecord, labels []unsafe.Pointer) (n int, ok bool) { +func goroutineProfileWithLabelsSync(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) { gp := getg() isOK := func(gp1 *g) bool { @@ -1339,6 +1577,7 @@ func goroutineProfileWithLabelsSync(p []StackRecord, labels []unsafe.Pointer) (n return gp1 != gp && readgstatus(gp1) != _Gdead && !isSystemGoroutine(gp1, false) } + pcbuf := makeProfStack() // see saveg() for explanation stw := stopTheWorld(stwGoroutineProfile) // World is stopped, no locking required. @@ -1357,7 +1596,7 @@ func goroutineProfileWithLabelsSync(p []StackRecord, labels []unsafe.Pointer) (n sp := getcallersp() pc := getcallerpc() systemstack(func() { - saveg(pc, sp, gp, &r[0]) + saveg(pc, sp, gp, &r[0], pcbuf) }) r = r[1:] @@ -1382,7 +1621,7 @@ func goroutineProfileWithLabelsSync(p []StackRecord, labels []unsafe.Pointer) (n // The world is stopped, so it cannot use cgocall (which will be // blocked at exitsyscall). Do it on the system stack so it won't // call into the schedular (see traceback.go:cgoContextPCs). - systemstack(func() { saveg(^uintptr(0), ^uintptr(0), gp1, &r[0]) }) + systemstack(func() { saveg(^uintptr(0), ^uintptr(0), gp1, &r[0], pcbuf) }) if labels != nil { lbl[0] = gp1.labels lbl = lbl[1:] @@ -1406,17 +1645,42 @@ func goroutineProfileWithLabelsSync(p []StackRecord, labels []unsafe.Pointer) (n // Most clients should use the [runtime/pprof] package instead // of calling GoroutineProfile directly. func GoroutineProfile(p []StackRecord) (n int, ok bool) { + records := make([]profilerecord.StackRecord, len(p)) + n, ok = goroutineProfileInternal(records) + if !ok { + return + } + for i, mr := range records[0:n] { + l := copy(p[i].Stack0[:], mr.Stack) + clear(p[i].Stack0[l:]) + } + return +} +func goroutineProfileInternal(p []profilerecord.StackRecord) (n int, ok bool) { return goroutineProfileWithLabels(p, nil) } -func saveg(pc, sp uintptr, gp *g, r *StackRecord) { +func saveg(pc, sp uintptr, gp *g, r *profilerecord.StackRecord, pcbuf []uintptr) { + // To reduce memory usage, we want to allocate a r.Stack that is just big + // enough to hold gp's stack trace. Naively we might achieve this by + // recording our stack trace into mp.profStack, and then allocating a + // r.Stack of the right size. However, mp.profStack is also used for + // allocation profiling, so it could get overwritten if the slice allocation + // gets profiled. So instead we record the stack trace into a temporary + // pcbuf which is usually given to us by our caller. When it's not, we have + // to allocate one here. This will only happen for goroutines that were in a + // syscall when the goroutine profile started or for goroutines that manage + // to execute before we finish iterating over all the goroutines. + if pcbuf == nil { + pcbuf = makeProfStack() + } + var u unwinder u.initAt(pc, sp, 0, gp, unwindSilentErrors) - n := tracebackPCs(&u, 0, r.Stack0[:]) - if n < len(r.Stack0) { - r.Stack0[n] = 0 - } + n := tracebackPCs(&u, 0, pcbuf) + r.Stack = make([]uintptr, n) + copy(r.Stack, pcbuf) } // Stack formats a stack trace of the calling goroutine into buf @@ -1457,61 +1721,3 @@ func Stack(buf []byte, all bool) int { } return n } - -// Tracing of alloc/free/gc. - -var tracelock mutex - -func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) { - lock(&tracelock) - gp := getg() - gp.m.traceback = 2 - if typ == nil { - print("tracealloc(", p, ", ", hex(size), ")\n") - } else { - print("tracealloc(", p, ", ", hex(size), ", ", toRType(typ).string(), ")\n") - } - if gp.m.curg == nil || gp == gp.m.curg { - goroutineheader(gp) - pc := getcallerpc() - sp := getcallersp() - systemstack(func() { - traceback(pc, sp, 0, gp) - }) - } else { - goroutineheader(gp.m.curg) - traceback(^uintptr(0), ^uintptr(0), 0, gp.m.curg) - } - print("\n") - gp.m.traceback = 0 - unlock(&tracelock) -} - -func tracefree(p unsafe.Pointer, size uintptr) { - lock(&tracelock) - gp := getg() - gp.m.traceback = 2 - print("tracefree(", p, ", ", hex(size), ")\n") - goroutineheader(gp) - pc := getcallerpc() - sp := getcallersp() - systemstack(func() { - traceback(pc, sp, 0, gp) - }) - print("\n") - gp.m.traceback = 0 - unlock(&tracelock) -} - -func tracegc() { - lock(&tracelock) - gp := getg() - gp.m.traceback = 2 - print("tracegc()\n") - // running on m->g0 stack; show all non-g0 goroutines - tracebackothers(gp) - print("end tracegc\n") - print("\n") - gp.m.traceback = 0 - unlock(&tracelock) -} diff --git a/contrib/go/_std_1.22/src/runtime/mranges.go b/contrib/go/_std_1.23/src/runtime/mranges.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mranges.go rename to contrib/go/_std_1.23/src/runtime/mranges.go index 6dd1a7524732..85795a941884 100644 --- a/contrib/go/_std_1.22/src/runtime/mranges.go +++ b/contrib/go/_std_1.23/src/runtime/mranges.go @@ -11,7 +11,7 @@ package runtime import ( "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/msan.go b/contrib/go/_std_1.23/src/runtime/msan.go similarity index 92% rename from contrib/go/_std_1.22/src/runtime/msan.go rename to contrib/go/_std_1.23/src/runtime/msan.go index 5e2aae1bd161..cb740dc2d86a 100644 --- a/contrib/go/_std_1.22/src/runtime/msan.go +++ b/contrib/go/_std_1.23/src/runtime/msan.go @@ -29,6 +29,7 @@ const msanenabled = true // anyhow for values on the stack. Just ignore msanread when running // on the system stack. The other msan functions are fine. // +//go:linkname msanread //go:nosplit func msanread(addr unsafe.Pointer, sz uintptr) { gp := getg() @@ -41,15 +42,19 @@ func msanread(addr unsafe.Pointer, sz uintptr) { //go:noescape func domsanread(addr unsafe.Pointer, sz uintptr) +//go:linkname msanwrite //go:noescape func msanwrite(addr unsafe.Pointer, sz uintptr) +//go:linkname msanmalloc //go:noescape func msanmalloc(addr unsafe.Pointer, sz uintptr) +//go:linkname msanfree //go:noescape func msanfree(addr unsafe.Pointer, sz uintptr) +//go:linkname msanmove //go:noescape func msanmove(dst, src unsafe.Pointer, sz uintptr) diff --git a/contrib/go/_std_1.22/src/runtime/msan/msan.go b/contrib/go/_std_1.23/src/runtime/msan/msan.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/msan/msan.go rename to contrib/go/_std_1.23/src/runtime/msan/msan.go diff --git a/contrib/go/_std_1.22/src/runtime/msan/ya.make b/contrib/go/_std_1.23/src/runtime/msan/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/msan/ya.make rename to contrib/go/_std_1.23/src/runtime/msan/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/msan0.go b/contrib/go/_std_1.23/src/runtime/msan0.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/msan0.go rename to contrib/go/_std_1.23/src/runtime/msan0.go diff --git a/contrib/go/_std_1.22/src/runtime/msan_amd64.s b/contrib/go/_std_1.23/src/runtime/msan_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/msan_amd64.s rename to contrib/go/_std_1.23/src/runtime/msan_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/msan_arm64.s b/contrib/go/_std_1.23/src/runtime/msan_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/msan_arm64.s rename to contrib/go/_std_1.23/src/runtime/msan_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/msan_loong64.s b/contrib/go/_std_1.23/src/runtime/msan_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/msan_loong64.s rename to contrib/go/_std_1.23/src/runtime/msan_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/msize_allocheaders.go b/contrib/go/_std_1.23/src/runtime/msize.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/msize_allocheaders.go rename to contrib/go/_std_1.23/src/runtime/msize.go index 6873ec66d9dd..64d1531ab098 100644 --- a/contrib/go/_std_1.22/src/runtime/msize_allocheaders.go +++ b/contrib/go/_std_1.23/src/runtime/msize.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build goexperiment.allocheaders - // Malloc small size classes. // // See malloc.go for overview. diff --git a/contrib/go/_std_1.22/src/runtime/mspanset.go b/contrib/go/_std_1.23/src/runtime/mspanset.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mspanset.go rename to contrib/go/_std_1.23/src/runtime/mspanset.go index 5687627e3a20..3aa2b5b3937f 100644 --- a/contrib/go/_std_1.22/src/runtime/mspanset.go +++ b/contrib/go/_std_1.23/src/runtime/mspanset.go @@ -7,7 +7,7 @@ package runtime import ( "internal/cpu" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/mstats.go b/contrib/go/_std_1.23/src/runtime/mstats.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/mstats.go rename to contrib/go/_std_1.23/src/runtime/mstats.go index 87afec47c868..c10ca402217c 100644 --- a/contrib/go/_std_1.22/src/runtime/mstats.go +++ b/contrib/go/_std_1.23/src/runtime/mstats.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -905,20 +905,30 @@ type cpuStats struct { // they don't accurately compute on-CPU time (so some of the time // could be spent scheduled away by the OS). - gcAssistTime int64 // GC assists - gcDedicatedTime int64 // GC dedicated mark workers + pauses - gcIdleTime int64 // GC idle mark workers - gcPauseTime int64 // GC pauses (all GOMAXPROCS, even if just 1 is running) - gcTotalTime int64 + GCAssistTime int64 // GC assists + GCDedicatedTime int64 // GC dedicated mark workers + pauses + GCIdleTime int64 // GC idle mark workers + GCPauseTime int64 // GC pauses (all GOMAXPROCS, even if just 1 is running) + GCTotalTime int64 - scavengeAssistTime int64 // background scavenger - scavengeBgTime int64 // scavenge assists - scavengeTotalTime int64 + ScavengeAssistTime int64 // background scavenger + ScavengeBgTime int64 // scavenge assists + ScavengeTotalTime int64 - idleTime int64 // Time Ps spent in _Pidle. - userTime int64 // Time Ps spent in _Prunning or _Psyscall that's not any of the above. + IdleTime int64 // Time Ps spent in _Pidle. + UserTime int64 // Time Ps spent in _Prunning or _Psyscall that's not any of the above. - totalTime int64 // GOMAXPROCS * (monotonic wall clock time elapsed) + TotalTime int64 // GOMAXPROCS * (monotonic wall clock time elapsed) +} + +// accumulateGCPauseTime add dt*stwProcs to the GC CPU pause time stats. dt should be +// the actual time spent paused, for orthogonality. maxProcs should be GOMAXPROCS, +// not work.stwprocs, since this number must be comparable to a total time computed +// from GOMAXPROCS. +func (s *cpuStats) accumulateGCPauseTime(dt int64, maxProcs int32) { + cpu := dt * int64(maxProcs) + s.GCPauseTime += cpu + s.GCTotalTime += cpu } // accumulate takes a cpuStats and adds in the current state of all GC CPU @@ -951,19 +961,19 @@ func (s *cpuStats) accumulate(now int64, gcMarkPhase bool) { scavBgCpu := scavenge.backgroundTime.Load() // Update cumulative GC CPU stats. - s.gcAssistTime += markAssistCpu - s.gcDedicatedTime += markDedicatedCpu + markFractionalCpu - s.gcIdleTime += markIdleCpu - s.gcTotalTime += markAssistCpu + markDedicatedCpu + markFractionalCpu + markIdleCpu + s.GCAssistTime += markAssistCpu + s.GCDedicatedTime += markDedicatedCpu + markFractionalCpu + s.GCIdleTime += markIdleCpu + s.GCTotalTime += markAssistCpu + markDedicatedCpu + markFractionalCpu + markIdleCpu // Update cumulative scavenge CPU stats. - s.scavengeAssistTime += scavAssistCpu - s.scavengeBgTime += scavBgCpu - s.scavengeTotalTime += scavAssistCpu + scavBgCpu + s.ScavengeAssistTime += scavAssistCpu + s.ScavengeBgTime += scavBgCpu + s.ScavengeTotalTime += scavAssistCpu + scavBgCpu // Update total CPU. - s.totalTime = sched.totaltime + (now-sched.procresizetime)*int64(gomaxprocs) - s.idleTime += sched.idleTime.Load() + s.TotalTime = sched.totaltime + (now-sched.procresizetime)*int64(gomaxprocs) + s.IdleTime += sched.idleTime.Load() // Compute userTime. We compute this indirectly as everything that's not the above. // @@ -973,5 +983,5 @@ func (s *cpuStats) accumulate(now int64, gcMarkPhase bool) { // else via sysmon. Meanwhile if we subtract GC time from whatever's left, we get non-GC // _Prunning time. Note that this still leaves time spent in sweeping and in the scheduler, // but that's fine. The overwhelming majority of this time will be actual user time. - s.userTime = s.totalTime - (s.gcTotalTime + s.scavengeTotalTime + s.idleTime) + s.UserTime = s.TotalTime - (s.GCTotalTime + s.ScavengeTotalTime + s.IdleTime) } diff --git a/contrib/go/_std_1.22/src/runtime/mwbbuf.go b/contrib/go/_std_1.23/src/runtime/mwbbuf.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/mwbbuf.go rename to contrib/go/_std_1.23/src/runtime/mwbbuf.go index 7419bd291dbf..b998d2b2bdf5 100644 --- a/contrib/go/_std_1.22/src/runtime/mwbbuf.go +++ b/contrib/go/_std_1.23/src/runtime/mwbbuf.go @@ -24,7 +24,7 @@ package runtime import ( "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/nbpipe_pipe.go b/contrib/go/_std_1.23/src/runtime/nbpipe_pipe.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/nbpipe_pipe.go rename to contrib/go/_std_1.23/src/runtime/nbpipe_pipe.go diff --git a/contrib/go/_std_1.22/src/runtime/nbpipe_pipe2.go b/contrib/go/_std_1.23/src/runtime/nbpipe_pipe2.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/nbpipe_pipe2.go rename to contrib/go/_std_1.23/src/runtime/nbpipe_pipe2.go diff --git a/contrib/go/_std_1.22/src/runtime/net_plan9.go b/contrib/go/_std_1.23/src/runtime/net_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/net_plan9.go rename to contrib/go/_std_1.23/src/runtime/net_plan9.go diff --git a/contrib/go/_std_1.22/src/runtime/netpoll.go b/contrib/go/_std_1.23/src/runtime/netpoll.go similarity index 94% rename from contrib/go/_std_1.22/src/runtime/netpoll.go rename to contrib/go/_std_1.23/src/runtime/netpoll.go index 9c2e40ce8a56..7b37d91b24a4 100644 --- a/contrib/go/_std_1.22/src/runtime/netpoll.go +++ b/contrib/go/_std_1.23/src/runtime/netpoll.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -102,9 +102,11 @@ type pollDesc struct { lock mutex // protects the following fields closing bool + rrun bool // whether rt is running + wrun bool // whether wt is running user uint32 // user settable cookie rseq uintptr // protects from stale read timers - rt timer // read deadline timer (set if rt.f != nil) + rt timer // read deadline timer rd int64 // read deadline (a nanotime in the future, -1 when expired) wseq uintptr // protects from stale write timers wt timer // write deadline timer @@ -205,6 +207,9 @@ var ( netpollWaiters atomic.Uint32 ) +// netpollWaiters is accessed in tests +//go:linkname netpollWaiters + //go:linkname poll_runtime_pollServerInit internal/poll.runtime_pollServerInit func poll_runtime_pollServerInit() { netpollGenericInit() @@ -213,6 +218,7 @@ func poll_runtime_pollServerInit() { func netpollGenericInit() { if netpollInited.Load() == 0 { lockInit(&netpollInitLock, lockRankNetpollInit) + lockInit(&pollcache.lock, lockRankPollCache) lock(&netpollInitLock) if netpollInited.Load() == 0 { netpollinit() @@ -391,39 +397,35 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) { if combo { rtf = netpollDeadline } - if pd.rt.f == nil { + if !pd.rrun { if pd.rd > 0 { - pd.rt.f = rtf // Copy current seq into the timer arg. // Timer func will check the seq against current descriptor seq, // if they differ the descriptor was reused or timers were reset. - pd.rt.arg = pd.makeArg() - pd.rt.seq = pd.rseq - resettimer(&pd.rt, pd.rd) + pd.rt.modify(pd.rd, 0, rtf, pd.makeArg(), pd.rseq) + pd.rrun = true } } else if pd.rd != rd0 || combo != combo0 { pd.rseq++ // invalidate current timers if pd.rd > 0 { - modtimer(&pd.rt, pd.rd, 0, rtf, pd.makeArg(), pd.rseq) + pd.rt.modify(pd.rd, 0, rtf, pd.makeArg(), pd.rseq) } else { - deltimer(&pd.rt) - pd.rt.f = nil + pd.rt.stop() + pd.rrun = false } } - if pd.wt.f == nil { + if !pd.wrun { if pd.wd > 0 && !combo { - pd.wt.f = netpollWriteDeadline - pd.wt.arg = pd.makeArg() - pd.wt.seq = pd.wseq - resettimer(&pd.wt, pd.wd) + pd.wt.modify(pd.wd, 0, netpollWriteDeadline, pd.makeArg(), pd.wseq) + pd.wrun = true } } else if pd.wd != wd0 || combo != combo0 { pd.wseq++ // invalidate current timers if pd.wd > 0 && !combo { - modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd.makeArg(), pd.wseq) + pd.wt.modify(pd.wd, 0, netpollWriteDeadline, pd.makeArg(), pd.wseq) } else { - deltimer(&pd.wt) - pd.wt.f = nil + pd.wt.stop() + pd.wrun = false } } // If we set the new deadline in the past, unblock currently pending IO if any. @@ -460,13 +462,13 @@ func poll_runtime_pollUnblock(pd *pollDesc) { delta := int32(0) rg = netpollunblock(pd, 'r', false, &delta) wg = netpollunblock(pd, 'w', false, &delta) - if pd.rt.f != nil { - deltimer(&pd.rt) - pd.rt.f = nil + if pd.rrun { + pd.rt.stop() + pd.rrun = false } - if pd.wt.f != nil { - deltimer(&pd.wt) - pd.wt.f = nil + if pd.wrun { + pd.wt.stop() + pd.wrun = false } unlock(&pd.lock) if rg != nil { @@ -633,7 +635,7 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) { delta := int32(0) var rg *g if read { - if pd.rd <= 0 || pd.rt.f == nil { + if pd.rd <= 0 || !pd.rrun { throw("runtime: inconsistent read deadline") } pd.rd = -1 @@ -642,7 +644,7 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) { } var wg *g if write { - if pd.wd <= 0 || pd.wt.f == nil && !read { + if pd.wd <= 0 || !pd.wrun && !read { throw("runtime: inconsistent write deadline") } pd.wd = -1 @@ -659,15 +661,15 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) { netpollAdjustWaiters(delta) } -func netpollDeadline(arg any, seq uintptr) { +func netpollDeadline(arg any, seq uintptr, delta int64) { netpolldeadlineimpl(arg.(*pollDesc), seq, true, true) } -func netpollReadDeadline(arg any, seq uintptr) { +func netpollReadDeadline(arg any, seq uintptr, delta int64) { netpolldeadlineimpl(arg.(*pollDesc), seq, true, false) } -func netpollWriteDeadline(arg any, seq uintptr) { +func netpollWriteDeadline(arg any, seq uintptr, delta int64) { netpolldeadlineimpl(arg.(*pollDesc), seq, false, true) } @@ -696,13 +698,15 @@ func (c *pollCache) alloc() *pollDesc { mem := persistentalloc(n*pdSize, 0, &memstats.other_sys) for i := uintptr(0); i < n; i++ { pd := (*pollDesc)(add(mem, i*pdSize)) + lockInit(&pd.lock, lockRankPollDesc) + pd.rt.init(nil, nil) + pd.wt.init(nil, nil) pd.link = c.first c.first = pd } } pd := c.first c.first = pd.link - lockInit(&pd.lock, lockRankPollDesc) unlock(&c.lock) return pd } diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_aix.go b/contrib/go/_std_1.23/src/runtime/netpoll_aix.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/netpoll_aix.go rename to contrib/go/_std_1.23/src/runtime/netpoll_aix.go index a34b4d8bcfba..2df5a5711145 100644 --- a/contrib/go/_std_1.22/src/runtime/netpoll_aix.go +++ b/contrib/go/_std_1.23/src/runtime/netpoll_aix.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_epoll.go b/contrib/go/_std_1.23/src/runtime/netpoll_epoll.go similarity index 73% rename from contrib/go/_std_1.22/src/runtime/netpoll_epoll.go rename to contrib/go/_std_1.23/src/runtime/netpoll_epoll.go index cda19fbc2787..ff6e0b5f89cc 100644 --- a/contrib/go/_std_1.22/src/runtime/netpoll_epoll.go +++ b/contrib/go/_std_1.23/src/runtime/netpoll_epoll.go @@ -7,17 +7,15 @@ package runtime import ( - "runtime/internal/atomic" - "runtime/internal/syscall" + "internal/runtime/atomic" + "internal/runtime/syscall" "unsafe" ) var ( - epfd int32 = -1 // epoll descriptor - - netpollBreakRd, netpollBreakWr uintptr // for netpollBreak - - netpollWakeSig atomic.Uint32 // used to avoid duplicate calls of netpollBreak + epfd int32 = -1 // epoll descriptor + netpollEventFd uintptr // eventfd for netpollBreak + netpollWakeSig atomic.Uint32 // used to avoid duplicate calls of netpollBreak ) func netpollinit() { @@ -27,26 +25,25 @@ func netpollinit() { println("runtime: epollcreate failed with", errno) throw("runtime: netpollinit failed") } - r, w, errpipe := nonblockingPipe() - if errpipe != 0 { - println("runtime: pipe failed with", -errpipe) - throw("runtime: pipe failed") + efd, errno := syscall.Eventfd(0, syscall.EFD_CLOEXEC|syscall.EFD_NONBLOCK) + if errno != 0 { + println("runtime: eventfd failed with", -errno) + throw("runtime: eventfd failed") } ev := syscall.EpollEvent{ Events: syscall.EPOLLIN, } - *(**uintptr)(unsafe.Pointer(&ev.Data)) = &netpollBreakRd - errno = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, r, &ev) + *(**uintptr)(unsafe.Pointer(&ev.Data)) = &netpollEventFd + errno = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, efd, &ev) if errno != 0 { println("runtime: epollctl failed with", errno) throw("runtime: epollctl failed") } - netpollBreakRd = uintptr(r) - netpollBreakWr = uintptr(w) + netpollEventFd = uintptr(efd) } func netpollIsPollDescriptor(fd uintptr) bool { - return fd == uintptr(epfd) || fd == netpollBreakRd || fd == netpollBreakWr + return fd == uintptr(epfd) || fd == netpollEventFd } func netpollopen(fd uintptr, pd *pollDesc) uintptr { @@ -73,10 +70,11 @@ func netpollBreak() { return } + var one uint64 = 1 + oneSize := int32(unsafe.Sizeof(one)) for { - var b byte - n := write(netpollBreakWr, unsafe.Pointer(&b), 1) - if n == 1 { + n := write(netpollEventFd, noescape(unsafe.Pointer(&one)), oneSize) + if n == oneSize { break } if n == -_EINTR { @@ -136,17 +134,19 @@ retry: continue } - if *(**uintptr)(unsafe.Pointer(&ev.Data)) == &netpollBreakRd { + if *(**uintptr)(unsafe.Pointer(&ev.Data)) == &netpollEventFd { if ev.Events != syscall.EPOLLIN { - println("runtime: netpoll: break fd ready for", ev.Events) - throw("runtime: netpoll: break fd ready for something unexpected") + println("runtime: netpoll: eventfd ready for", ev.Events) + throw("runtime: netpoll: eventfd ready for something unexpected") } if delay != 0 { // netpollBreak could be picked up by a - // nonblocking poll. Only read the byte - // if blocking. - var tmp [16]byte - read(int32(netpollBreakRd), noescape(unsafe.Pointer(&tmp[0])), int32(len(tmp))) + // nonblocking poll. Only read the 8-byte + // integer if blocking. + // Since EFD_SEMAPHORE was not specified, + // the eventfd counter will be reset to 0. + var one uint64 + read(int32(netpollEventFd), noescape(unsafe.Pointer(&one)), int32(unsafe.Sizeof(one))) netpollWakeSig.Store(0) } continue diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_fake.go b/contrib/go/_std_1.23/src/runtime/netpoll_fake.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/netpoll_fake.go rename to contrib/go/_std_1.23/src/runtime/netpoll_fake.go diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_kqueue.go b/contrib/go/_std_1.23/src/runtime/netpoll_kqueue.go similarity index 76% rename from contrib/go/_std_1.22/src/runtime/netpoll_kqueue.go rename to contrib/go/_std_1.23/src/runtime/netpoll_kqueue.go index d774dce3034c..6cd80d5c30d1 100644 --- a/contrib/go/_std_1.22/src/runtime/netpoll_kqueue.go +++ b/contrib/go/_std_1.23/src/runtime/netpoll_kqueue.go @@ -10,15 +10,12 @@ package runtime import ( "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) var ( - kq int32 = -1 - - netpollBreakRd, netpollBreakWr uintptr // for netpollBreak - + kq int32 = -1 netpollWakeSig atomic.Uint32 // used to avoid duplicate calls of netpollBreak ) @@ -29,27 +26,7 @@ func netpollinit() { throw("runtime: netpollinit failed") } closeonexec(kq) - r, w, errno := nonblockingPipe() - if errno != 0 { - println("runtime: pipe failed with", -errno) - throw("runtime: pipe failed") - } - ev := keventt{ - filter: _EVFILT_READ, - flags: _EV_ADD, - } - *(*uintptr)(unsafe.Pointer(&ev.ident)) = uintptr(r) - n := kevent(kq, &ev, 1, nil, 0, nil) - if n < 0 { - println("runtime: kevent failed with", -n) - throw("runtime: kevent failed") - } - netpollBreakRd = uintptr(r) - netpollBreakWr = uintptr(w) -} - -func netpollIsPollDescriptor(fd uintptr) bool { - return fd == uintptr(kq) || fd == netpollBreakRd || fd == netpollBreakWr + addWakeupEvent(kq) } func netpollopen(fd uintptr, pd *pollDesc) int32 { @@ -99,18 +76,7 @@ func netpollBreak() { return } - for { - var b byte - n := write(netpollBreakWr, unsafe.Pointer(&b), 1) - if n == 1 || n == -_EAGAIN { - break - } - if n == -_EINTR { - continue - } - println("runtime: netpollBreak write failed with", -n) - throw("runtime: netpollBreak write failed") - } + wakeNetpoll(kq) } // netpoll checks for ready network connections. @@ -159,17 +125,11 @@ retry: for i := 0; i < int(n); i++ { ev := &events[i] - if uintptr(ev.ident) == netpollBreakRd { - if ev.filter != _EVFILT_READ { - println("runtime: netpoll: break fd ready for", ev.filter) - throw("runtime: netpoll: break fd ready for something unexpected") - } + if isWakeup(ev) { if delay != 0 { - // netpollBreak could be picked up by a - // nonblocking poll. Only read the byte - // if blocking. - var tmp [16]byte - read(int32(netpollBreakRd), noescape(unsafe.Pointer(&tmp[0])), int32(len(tmp))) + // netpollBreak could be picked up by a nonblocking poll. + // Only call drainWakeupEvent and reset the netpollWakeSig if blocking. + drainWakeupEvent(kq) netpollWakeSig.Store(0) } continue diff --git a/contrib/go/_std_1.23/src/runtime/netpoll_kqueue_event.go b/contrib/go/_std_1.23/src/runtime/netpoll_kqueue_event.go new file mode 100644 index 000000000000..d5f783e607e8 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/netpoll_kqueue_event.go @@ -0,0 +1,80 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin || dragonfly || freebsd + +package runtime + +// Magic number of identifier used for EVFILT_USER. +// This number had zero Google results when it's created. +// That way, people will be directed here when this number +// get printed somehow and they search for it. +const kqIdent = 0xee1eb9f4 + +func addWakeupEvent(kq int32) { + ev := keventt{ + ident: kqIdent, + filter: _EVFILT_USER, + flags: _EV_ADD, + } + for { + n := kevent(kq, &ev, 1, nil, 0, nil) + if n == 0 { + break + } + if n == -_EINTR { + // All changes contained in the changelist should have been applied + // before returning EINTR. But let's be skeptical and retry it anyway, + // to make a 100% commitment. + continue + } + println("runtime: kevent for EVFILT_USER failed with", -n) + throw("runtime: kevent failed") + } +} + +func wakeNetpoll(kq int32) { + ev := keventt{ + ident: kqIdent, + filter: _EVFILT_USER, + flags: _EV_ENABLE, + fflags: _NOTE_TRIGGER, + } + for { + n := kevent(kq, &ev, 1, nil, 0, nil) + if n == 0 { + break + } + if n == -_EINTR { + // Check out the comment in addWakeupEvent. + continue + } + println("runtime: netpollBreak write failed with", -n) + throw("runtime: netpollBreak write failed") + } +} + +func isWakeup(ev *keventt) bool { + if ev.filter == _EVFILT_USER { + if ev.ident == kqIdent { + return true + } + println("runtime: netpoll: break fd ready for", ev.ident) + throw("runtime: netpoll: break fd ready for something unexpected") + } + return false +} + +func drainWakeupEvent(kq int32) { + ev := keventt{ + ident: kqIdent, + filter: _EVFILT_USER, + flags: _EV_DISABLE, + } + kevent(kq, &ev, 1, nil, 0, nil) +} + +func netpollIsPollDescriptor(fd uintptr) bool { + return fd == uintptr(kq) +} diff --git a/contrib/go/_std_1.23/src/runtime/netpoll_kqueue_pipe.go b/contrib/go/_std_1.23/src/runtime/netpoll_kqueue_pipe.go new file mode 100644 index 000000000000..98f73e84d29f --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/netpoll_kqueue_pipe.go @@ -0,0 +1,73 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build netbsd || openbsd + +package runtime + +import "unsafe" + +// TODO(panjf2000): NetBSD didn't implement EVFILT_USER for user-established events +// until NetBSD 10.0, check out https://www.netbsd.org/releases/formal-10/NetBSD-10.0.html +// Therefore we use the pipe to wake up the kevent on NetBSD at this point. Get back here +// and switch to EVFILT_USER when we bump up the minimal requirement of NetBSD to 10.0. +// Alternatively, maybe we can use EVFILT_USER on the NetBSD by checking the kernel version +// via uname(3) and fall back to the pipe if the kernel version is older than 10.0. + +var netpollBreakRd, netpollBreakWr uintptr // for netpollBreak + +func addWakeupEvent(kq int32) { + r, w, errno := nonblockingPipe() + if errno != 0 { + println("runtime: pipe failed with", -errno) + throw("runtime: pipe failed") + } + ev := keventt{ + filter: _EVFILT_READ, + flags: _EV_ADD, + } + *(*uintptr)(unsafe.Pointer(&ev.ident)) = uintptr(r) + n := kevent(kq, &ev, 1, nil, 0, nil) + if n < 0 { + println("runtime: kevent failed with", -n) + throw("runtime: kevent failed") + } + netpollBreakRd = uintptr(r) + netpollBreakWr = uintptr(w) +} + +func wakeNetpoll(_ int32) { + for { + var b byte + n := write(netpollBreakWr, unsafe.Pointer(&b), 1) + if n == 1 || n == -_EAGAIN { + break + } + if n == -_EINTR { + continue + } + println("runtime: netpollBreak write failed with", -n) + throw("runtime: netpollBreak write failed") + } +} + +func isWakeup(ev *keventt) bool { + if uintptr(ev.ident) == netpollBreakRd { + if ev.filter == _EVFILT_READ { + return true + } + println("runtime: netpoll: break fd ready for", ev.filter) + throw("runtime: netpoll: break fd ready for something unexpected") + } + return false +} + +func drainWakeupEvent(_ int32) { + var buf [16]byte + read(int32(netpollBreakRd), noescape(unsafe.Pointer(&buf[0])), int32(len(buf))) +} + +func netpollIsPollDescriptor(fd uintptr) bool { + return fd == uintptr(kq) || fd == netpollBreakRd || fd == netpollBreakWr +} diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_solaris.go b/contrib/go/_std_1.23/src/runtime/netpoll_solaris.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/netpoll_solaris.go rename to contrib/go/_std_1.23/src/runtime/netpoll_solaris.go index 41f145c86692..fddc29000b78 100644 --- a/contrib/go/_std_1.22/src/runtime/netpoll_solaris.go +++ b/contrib/go/_std_1.23/src/runtime/netpoll_solaris.go @@ -6,7 +6,7 @@ package runtime import ( "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_stub.go b/contrib/go/_std_1.23/src/runtime/netpoll_stub.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/netpoll_stub.go rename to contrib/go/_std_1.23/src/runtime/netpoll_stub.go index d950661acf3d..c1bda3fa8b0d 100644 --- a/contrib/go/_std_1.22/src/runtime/netpoll_stub.go +++ b/contrib/go/_std_1.23/src/runtime/netpoll_stub.go @@ -6,7 +6,7 @@ package runtime -import "runtime/internal/atomic" +import "internal/runtime/atomic" var netpollInited atomic.Uint32 diff --git a/contrib/go/_std_1.22/src/runtime/netpoll_wasip1.go b/contrib/go/_std_1.23/src/runtime/netpoll_wasip1.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/netpoll_wasip1.go rename to contrib/go/_std_1.23/src/runtime/netpoll_wasip1.go index 9903726809f8..e6b299a20fa8 100644 --- a/contrib/go/_std_1.22/src/runtime/netpoll_wasip1.go +++ b/contrib/go/_std_1.23/src/runtime/netpoll_wasip1.go @@ -205,9 +205,7 @@ func netpoll(delay int64) (gList, int32) { } evts = evts[:len(pollsubs)] - for i := range evts { - evts[i] = event{} - } + clear(evts) retry: var nevents size diff --git a/contrib/go/_std_1.23/src/runtime/netpoll_windows.go b/contrib/go/_std_1.23/src/runtime/netpoll_windows.go new file mode 100644 index 000000000000..c3c10af72379 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/netpoll_windows.go @@ -0,0 +1,284 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "internal/goarch" + "internal/runtime/atomic" + "unsafe" +) + +const _DWORD_MAX = 0xffffffff + +const _INVALID_HANDLE_VALUE = ^uintptr(0) + +// Sources are used to identify the event that created an overlapped entry. +// The source values are arbitrary. There is no risk of collision with user +// defined values because the only way to set the key of an overlapped entry +// is using the iocphandle, which is not accessible to user code. +const ( + netpollSourceReady = iota + 1 + netpollSourceBreak + netpollSourceTimer +) + +const ( + // sourceBits is the number of bits needed to represent a source. + // 4 bits can hold 16 different sources, which is more than enough. + // It is set to a low value so the overlapped entry key can + // contain as much bits as possible for the pollDesc pointer. + sourceBits = 4 // 4 bits can hold 16 different sources, which is more than enough. + sourceMasks = 1< (1< 0: block for up to that many nanoseconds +func netpoll(delay int64) (gList, int32) { + if iocphandle == _INVALID_HANDLE_VALUE { + return gList{}, 0 + } + + var entries [64]overlappedEntry + var wait uint32 + var toRun gList + mp := getg().m + + if delay >= 1e15 { + // An arbitrary cap on how long to wait for a timer. + // 1e15 ns == ~11.5 days. + delay = 1e15 + } + + if delay > 0 && mp.waitIocpHandle != 0 { + // GetQueuedCompletionStatusEx doesn't use a high resolution timer internally, + // so we use a separate higher resolution timer associated with a wait completion + // packet to wake up the poller. Note that the completion packet can be delivered + // to another thread, and the Go scheduler expects netpoll to only block up to delay, + // so we still need to use a timeout with GetQueuedCompletionStatusEx. + // TODO: Improve the Go scheduler to support non-blocking timers. + signaled := netpollQueueTimer(delay) + if signaled { + // There is a small window between the SetWaitableTimer and the NtAssociateWaitCompletionPacket + // where the timer can expire. We can return immediately in this case. + return gList{}, 0 + } + } + if delay < 0 { + wait = _INFINITE + } else if delay == 0 { + wait = 0 + } else if delay < 1e6 { + wait = 1 + } else { + wait = uint32(delay / 1e6) + } + n := len(entries) / int(gomaxprocs) + if n < 8 { + n = 8 + } + if delay != 0 { + mp.blocked = true + } + if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 { + mp.blocked = false + errno := getlasterror() + if errno == _WAIT_TIMEOUT { + return gList{}, 0 + } + println("runtime: GetQueuedCompletionStatusEx failed (errno=", errno, ")") + throw("runtime: netpoll failed") + } + mp.blocked = false + delta := int32(0) + for i := 0; i < n; i++ { + e := &entries[i] + switch unpackNetpollSource(e.key) { + case netpollSourceReady: + op := pollOperationFromOverlappedEntry(e) + if op == nil { + // Entry from outside the Go runtime and internal/poll, ignore. + continue + } + // Entry from internal/poll. + mode := op.mode + if mode != 'r' && mode != 'w' { + println("runtime: GetQueuedCompletionStatusEx returned net_op with invalid mode=", mode) + throw("runtime: netpoll failed") + } + delta += netpollready(&toRun, op.pd, mode) + case netpollSourceBreak: + netpollWakeSig.Store(0) + if delay == 0 { + // Forward the notification to the blocked poller. + netpollBreak() + } + case netpollSourceTimer: + // TODO: We could avoid calling NtCancelWaitCompletionPacket for expired wait completion packets. + default: + println("runtime: GetQueuedCompletionStatusEx returned net_op with invalid key=", e.key) + throw("runtime: netpoll failed") + } + } + return toRun, delta +} + +// netpollQueueTimer queues a timer to wake up the poller after the given delay. +// It returns true if the timer expired during this call. +func netpollQueueTimer(delay int64) (signaled bool) { + const ( + STATUS_SUCCESS = 0x00000000 + STATUS_PENDING = 0x00000103 + STATUS_CANCELLED = 0xC0000120 + ) + mp := getg().m + // A wait completion packet can only be associated with one timer at a time, + // so we need to cancel the previous one if it exists. This wouldn't be necessary + // if the poller would only be woken up by the timer, in which case the association + // would be automatically canceled, but it can also be woken up by other events, + // such as a netpollBreak, so we can get to this point with a timer that hasn't + // expired yet. In this case, the completion packet can still be picked up by + // another thread, so defer the cancellation until it is really necessary. + errno := stdcall2(_NtCancelWaitCompletionPacket, mp.waitIocpHandle, 1) + switch errno { + case STATUS_CANCELLED: + // STATUS_CANCELLED is returned when the associated timer has already expired, + // in which automatically cancels the wait completion packet. + fallthrough + case STATUS_SUCCESS: + dt := -delay / 100 // relative sleep (negative), 100ns units + if stdcall6(_SetWaitableTimer, mp.waitIocpTimer, uintptr(unsafe.Pointer(&dt)), 0, 0, 0, 0) == 0 { + println("runtime: SetWaitableTimer failed; errno=", getlasterror()) + throw("runtime: netpoll failed") + } + key := packNetpollKey(netpollSourceTimer, nil) + if errno := stdcall8(_NtAssociateWaitCompletionPacket, mp.waitIocpHandle, iocphandle, mp.waitIocpTimer, key, 0, 0, 0, uintptr(unsafe.Pointer(&signaled))); errno != 0 { + println("runtime: NtAssociateWaitCompletionPacket failed; errno=", errno) + throw("runtime: netpoll failed") + } + case STATUS_PENDING: + // STATUS_PENDING is returned if the wait operation can't be canceled yet. + // This can happen if this thread was woken up by another event, such as a netpollBreak, + // and the timer expired just while calling NtCancelWaitCompletionPacket, in which case + // this call fails to cancel the association to avoid a race condition. + // This is a rare case, so we can just avoid using the high resolution timer this time. + default: + println("runtime: NtCancelWaitCompletionPacket failed; errno=", errno) + throw("runtime: netpoll failed") + } + return signaled +} diff --git a/contrib/go/_std_1.22/src/runtime/nonwindows_stub.go b/contrib/go/_std_1.23/src/runtime/nonwindows_stub.go similarity index 75% rename from contrib/go/_std_1.22/src/runtime/nonwindows_stub.go rename to contrib/go/_std_1.23/src/runtime/nonwindows_stub.go index 033f026c4217..859ae48004ff 100644 --- a/contrib/go/_std_1.22/src/runtime/nonwindows_stub.go +++ b/contrib/go/_std_1.23/src/runtime/nonwindows_stub.go @@ -12,6 +12,8 @@ package runtime // timer precision to keep the timer error acceptable. const osRelaxMinNS = 0 +var haveHighResSleep = true + // osRelax is called by the scheduler when transitioning to and from // all Ps being idle. func osRelax(relax bool) {} @@ -19,3 +21,8 @@ func osRelax(relax bool) {} // enableWER is called by setTraceback("wer"). // Windows Error Reporting (WER) is only supported on Windows. func enableWER() {} + +// winlibcall is not implemented on non-Windows systems, +// but it is used in non-OS-specific parts of the runtime. +// Define it as an empty struct to avoid wasting stack space. +type winlibcall struct{} diff --git a/contrib/go/_std_1.22/src/runtime/os2_aix.go b/contrib/go/_std_1.23/src/runtime/os2_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os2_aix.go rename to contrib/go/_std_1.23/src/runtime/os2_aix.go diff --git a/contrib/go/_std_1.22/src/runtime/os2_freebsd.go b/contrib/go/_std_1.23/src/runtime/os2_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os2_freebsd.go rename to contrib/go/_std_1.23/src/runtime/os2_freebsd.go diff --git a/contrib/go/_std_1.22/src/runtime/os2_openbsd.go b/contrib/go/_std_1.23/src/runtime/os2_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os2_openbsd.go rename to contrib/go/_std_1.23/src/runtime/os2_openbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/os2_plan9.go b/contrib/go/_std_1.23/src/runtime/os2_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os2_plan9.go rename to contrib/go/_std_1.23/src/runtime/os2_plan9.go diff --git a/contrib/go/_std_1.22/src/runtime/os2_solaris.go b/contrib/go/_std_1.23/src/runtime/os2_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os2_solaris.go rename to contrib/go/_std_1.23/src/runtime/os2_solaris.go diff --git a/contrib/go/_std_1.22/src/runtime/os3_plan9.go b/contrib/go/_std_1.23/src/runtime/os3_plan9.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/os3_plan9.go rename to contrib/go/_std_1.23/src/runtime/os3_plan9.go index 8c9cbe28ec2f..dd1570561803 100644 --- a/contrib/go/_std_1.22/src/runtime/os3_plan9.go +++ b/contrib/go/_std_1.23/src/runtime/os3_plan9.go @@ -7,6 +7,7 @@ package runtime import ( "internal/abi" "internal/goarch" + "internal/stringslite" "unsafe" ) @@ -47,7 +48,7 @@ func sighandler(_ureg *ureg, note *byte, gp *g) int { // level by the program but will otherwise be ignored. flags = _SigNotify for sig, t = range sigtable { - if hasPrefix(notestr, t.name) { + if stringslite.HasPrefix(notestr, t.name) { flags = t.flags break } diff --git a/contrib/go/_std_1.22/src/runtime/os3_solaris.go b/contrib/go/_std_1.23/src/runtime/os3_solaris.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/os3_solaris.go rename to contrib/go/_std_1.23/src/runtime/os3_solaris.go index 92daf13b1a2d..cf163a6bf401 100644 --- a/contrib/go/_std_1.22/src/runtime/os3_solaris.go +++ b/contrib/go/_std_1.23/src/runtime/os3_solaris.go @@ -7,7 +7,7 @@ package runtime import ( "internal/abi" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/os_aix.go b/contrib/go/_std_1.23/src/runtime/os_aix.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/os_aix.go rename to contrib/go/_std_1.23/src/runtime/os_aix.go index 3a5078a64c45..93464cb997f3 100644 --- a/contrib/go/_std_1.22/src/runtime/os_aix.go +++ b/contrib/go/_std_1.23/src/runtime/os_aix.go @@ -8,7 +8,7 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/os_android.go b/contrib/go/_std_1.23/src/runtime/os_android.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_android.go rename to contrib/go/_std_1.23/src/runtime/os_android.go diff --git a/contrib/go/_std_1.22/src/runtime/os_darwin.go b/contrib/go/_std_1.23/src/runtime/os_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_darwin.go rename to contrib/go/_std_1.23/src/runtime/os_darwin.go diff --git a/contrib/go/_std_1.22/src/runtime/os_darwin_arm64.go b/contrib/go/_std_1.23/src/runtime/os_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_darwin_arm64.go rename to contrib/go/_std_1.23/src/runtime/os_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_dragonfly.go b/contrib/go/_std_1.23/src/runtime/os_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_dragonfly.go rename to contrib/go/_std_1.23/src/runtime/os_dragonfly.go diff --git a/contrib/go/_std_1.22/src/runtime/os_freebsd.go b/contrib/go/_std_1.23/src/runtime/os_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_freebsd.go rename to contrib/go/_std_1.23/src/runtime/os_freebsd.go diff --git a/contrib/go/_std_1.22/src/runtime/os_freebsd2.go b/contrib/go/_std_1.23/src/runtime/os_freebsd2.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_freebsd2.go rename to contrib/go/_std_1.23/src/runtime/os_freebsd2.go diff --git a/contrib/go/_std_1.22/src/runtime/os_freebsd_amd64.go b/contrib/go/_std_1.23/src/runtime/os_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_freebsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/os_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_freebsd_arm.go b/contrib/go/_std_1.23/src/runtime/os_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_freebsd_arm.go rename to contrib/go/_std_1.23/src/runtime/os_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/os_freebsd_arm64.go b/contrib/go/_std_1.23/src/runtime/os_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_freebsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/os_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_freebsd_noauxv.go b/contrib/go/_std_1.23/src/runtime/os_freebsd_noauxv.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_freebsd_noauxv.go rename to contrib/go/_std_1.23/src/runtime/os_freebsd_noauxv.go diff --git a/contrib/go/_std_1.22/src/runtime/os_freebsd_riscv64.go b/contrib/go/_std_1.23/src/runtime/os_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/runtime/os_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_illumos.go b/contrib/go/_std_1.23/src/runtime/os_illumos.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_illumos.go rename to contrib/go/_std_1.23/src/runtime/os_illumos.go diff --git a/contrib/go/_std_1.22/src/runtime/os_js.go b/contrib/go/_std_1.23/src/runtime/os_js.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_js.go rename to contrib/go/_std_1.23/src/runtime/os_js.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux.go b/contrib/go/_std_1.23/src/runtime/os_linux.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/os_linux.go rename to contrib/go/_std_1.23/src/runtime/os_linux.go index 0ba607fe1f18..e80d390e0d09 100644 --- a/contrib/go/_std_1.22/src/runtime/os_linux.go +++ b/contrib/go/_std_1.23/src/runtime/os_linux.go @@ -7,8 +7,8 @@ package runtime import ( "internal/abi" "internal/goarch" - "runtime/internal/atomic" - "runtime/internal/syscall" + "internal/runtime/atomic" + "internal/runtime/syscall" "unsafe" ) @@ -402,9 +402,9 @@ func unminit() { func mdestroy(mp *m) { } -//#ifdef GOARCH_386 -//#define sa_handler k_sa_handler -//#endif +// #ifdef GOARCH_386 +// #define sa_handler k_sa_handler +// #endif func sigreturn__sigaction() func sigtramp() // Called via C ABI @@ -879,8 +879,9 @@ func runPerThreadSyscall() { } const ( - _SI_USER = 0 - _SI_TKILL = -6 + _SI_USER = 0 + _SI_TKILL = -6 + _SYS_SECCOMP = 1 ) // sigFromUser reports whether the signal was sent because of a call @@ -891,3 +892,17 @@ func (c *sigctxt) sigFromUser() bool { code := int32(c.sigcode()) return code == _SI_USER || code == _SI_TKILL } + +// sigFromSeccomp reports whether the signal was sent from seccomp. +// +//go:nosplit +func (c *sigctxt) sigFromSeccomp() bool { + code := int32(c.sigcode()) + return code == _SYS_SECCOMP +} + +//go:nosplit +func mprotect(addr unsafe.Pointer, n uintptr, prot int32) (ret int32, errno int32) { + r, _, err := syscall.Syscall6(syscall.SYS_MPROTECT, uintptr(addr), n, uintptr(prot), 0, 0, 0) + return int32(r), int32(err) +} diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_arm.go b/contrib/go/_std_1.23/src/runtime/os_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_arm.go rename to contrib/go/_std_1.23/src/runtime/os_linux_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_arm64.go b/contrib/go/_std_1.23/src/runtime/os_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_arm64.go rename to contrib/go/_std_1.23/src/runtime/os_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_be64.go b/contrib/go/_std_1.23/src/runtime/os_linux_be64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_be64.go rename to contrib/go/_std_1.23/src/runtime/os_linux_be64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_generic.go b/contrib/go/_std_1.23/src/runtime/os_linux_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_generic.go rename to contrib/go/_std_1.23/src/runtime/os_linux_generic.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_loong64.go b/contrib/go/_std_1.23/src/runtime/os_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_loong64.go rename to contrib/go/_std_1.23/src/runtime/os_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_mips64x.go b/contrib/go/_std_1.23/src/runtime/os_linux_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_mips64x.go rename to contrib/go/_std_1.23/src/runtime/os_linux_mips64x.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_mipsx.go b/contrib/go/_std_1.23/src/runtime/os_linux_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_mipsx.go rename to contrib/go/_std_1.23/src/runtime/os_linux_mipsx.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_noauxv.go b/contrib/go/_std_1.23/src/runtime/os_linux_noauxv.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_noauxv.go rename to contrib/go/_std_1.23/src/runtime/os_linux_noauxv.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_novdso.go b/contrib/go/_std_1.23/src/runtime/os_linux_novdso.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_novdso.go rename to contrib/go/_std_1.23/src/runtime/os_linux_novdso.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_ppc64x.go b/contrib/go/_std_1.23/src/runtime/os_linux_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_ppc64x.go rename to contrib/go/_std_1.23/src/runtime/os_linux_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_riscv64.go b/contrib/go/_std_1.23/src/runtime/os_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_riscv64.go rename to contrib/go/_std_1.23/src/runtime/os_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_s390x.go b/contrib/go/_std_1.23/src/runtime/os_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_s390x.go rename to contrib/go/_std_1.23/src/runtime/os_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/runtime/os_linux_x86.go b/contrib/go/_std_1.23/src/runtime/os_linux_x86.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_linux_x86.go rename to contrib/go/_std_1.23/src/runtime/os_linux_x86.go diff --git a/contrib/go/_std_1.22/src/runtime/os_netbsd.go b/contrib/go/_std_1.23/src/runtime/os_netbsd.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/os_netbsd.go rename to contrib/go/_std_1.23/src/runtime/os_netbsd.go index 8abb688aae37..735ace25adb3 100644 --- a/contrib/go/_std_1.22/src/runtime/os_netbsd.go +++ b/contrib/go/_std_1.23/src/runtime/os_netbsd.go @@ -7,7 +7,7 @@ package runtime import ( "internal/abi" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/os_netbsd_386.go b/contrib/go/_std_1.23/src/runtime/os_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_netbsd_386.go rename to contrib/go/_std_1.23/src/runtime/os_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/runtime/os_netbsd_amd64.go b/contrib/go/_std_1.23/src/runtime/os_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_netbsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/os_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_netbsd_arm.go b/contrib/go/_std_1.23/src/runtime/os_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_netbsd_arm.go rename to contrib/go/_std_1.23/src/runtime/os_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/os_netbsd_arm64.go b/contrib/go/_std_1.23/src/runtime/os_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_netbsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/os_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_nonopenbsd.go b/contrib/go/_std_1.23/src/runtime/os_nonopenbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_nonopenbsd.go rename to contrib/go/_std_1.23/src/runtime/os_nonopenbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/os_only_solaris.go b/contrib/go/_std_1.23/src/runtime/os_only_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_only_solaris.go rename to contrib/go/_std_1.23/src/runtime/os_only_solaris.go diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd.go b/contrib/go/_std_1.23/src/runtime/os_openbsd.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/os_openbsd.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd.go index 856979910a9f..9a21d6a8d052 100644 --- a/contrib/go/_std_1.22/src/runtime/os_openbsd.go +++ b/contrib/go/_std_1.23/src/runtime/os_openbsd.go @@ -6,7 +6,7 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd_arm.go b/contrib/go/_std_1.23/src/runtime/os_openbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_openbsd_arm.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd_arm64.go b/contrib/go/_std_1.23/src/runtime/os_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_openbsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd_libc.go b/contrib/go/_std_1.23/src/runtime/os_openbsd_libc.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_openbsd_libc.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd_libc.go diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd_mips64.go b/contrib/go/_std_1.23/src/runtime/os_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_openbsd_mips64.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd_syscall.go b/contrib/go/_std_1.23/src/runtime/os_openbsd_syscall.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_openbsd_syscall.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd_syscall.go diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd_syscall1.go b/contrib/go/_std_1.23/src/runtime/os_openbsd_syscall1.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_openbsd_syscall1.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd_syscall1.go diff --git a/contrib/go/_std_1.22/src/runtime/os_openbsd_syscall2.go b/contrib/go/_std_1.23/src/runtime/os_openbsd_syscall2.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/os_openbsd_syscall2.go rename to contrib/go/_std_1.23/src/runtime/os_openbsd_syscall2.go index 0b796ade43a6..072f53320dc5 100644 --- a/contrib/go/_std_1.22/src/runtime/os_openbsd_syscall2.go +++ b/contrib/go/_std_1.23/src/runtime/os_openbsd_syscall2.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/os_plan9.go b/contrib/go/_std_1.23/src/runtime/os_plan9.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/os_plan9.go rename to contrib/go/_std_1.23/src/runtime/os_plan9.go index 77446d09d3b5..2dbb42ad037d 100644 --- a/contrib/go/_std_1.22/src/runtime/os_plan9.go +++ b/contrib/go/_std_1.23/src/runtime/os_plan9.go @@ -6,7 +6,8 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/runtime/atomic" + "internal/stringslite" "unsafe" ) @@ -124,7 +125,7 @@ func indexNoFloat(s, t string) int { return 0 } for i := 0; i < len(s); i++ { - if s[i] == t[0] && hasPrefix(s[i:], t) { + if s[i] == t[0] && stringslite.HasPrefix(s[i:], t) { return i } } @@ -132,20 +133,20 @@ func indexNoFloat(s, t string) int { } func atolwhex(p string) int64 { - for hasPrefix(p, " ") || hasPrefix(p, "\t") { + for stringslite.HasPrefix(p, " ") || stringslite.HasPrefix(p, "\t") { p = p[1:] } neg := false - if hasPrefix(p, "-") || hasPrefix(p, "+") { + if stringslite.HasPrefix(p, "-") || stringslite.HasPrefix(p, "+") { neg = p[0] == '-' p = p[1:] - for hasPrefix(p, " ") || hasPrefix(p, "\t") { + for stringslite.HasPrefix(p, " ") || stringslite.HasPrefix(p, "\t") { p = p[1:] } } var n int64 switch { - case hasPrefix(p, "0x"), hasPrefix(p, "0X"): + case stringslite.HasPrefix(p, "0x"), stringslite.HasPrefix(p, "0X"): p = p[2:] for ; len(p) > 0; p = p[1:] { if '0' <= p[0] && p[0] <= '9' { @@ -158,7 +159,7 @@ func atolwhex(p string) int64 { break } } - case hasPrefix(p, "0"): + case stringslite.HasPrefix(p, "0"): for ; len(p) > 0 && '0' <= p[0] && p[0] <= '7'; p = p[1:] { n = n*8 + int64(p[0]-'0') } diff --git a/contrib/go/_std_1.22/src/runtime/os_plan9_arm.go b/contrib/go/_std_1.23/src/runtime/os_plan9_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_plan9_arm.go rename to contrib/go/_std_1.23/src/runtime/os_plan9_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/os_solaris.go b/contrib/go/_std_1.23/src/runtime/os_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_solaris.go rename to contrib/go/_std_1.23/src/runtime/os_solaris.go diff --git a/contrib/go/_std_1.22/src/runtime/os_unix.go b/contrib/go/_std_1.23/src/runtime/os_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_unix.go rename to contrib/go/_std_1.23/src/runtime/os_unix.go diff --git a/contrib/go/_std_1.22/src/runtime/os_unix_nonlinux.go b/contrib/go/_std_1.23/src/runtime/os_unix_nonlinux.go similarity index 72% rename from contrib/go/_std_1.22/src/runtime/os_unix_nonlinux.go rename to contrib/go/_std_1.23/src/runtime/os_unix_nonlinux.go index b98753b8fe12..0e8b61c3b11a 100644 --- a/contrib/go/_std_1.22/src/runtime/os_unix_nonlinux.go +++ b/contrib/go/_std_1.23/src/runtime/os_unix_nonlinux.go @@ -13,3 +13,10 @@ package runtime func (c *sigctxt) sigFromUser() bool { return c.sigcode() == _SI_USER } + +// sigFromSeccomp reports whether the signal was sent from seccomp. +// +//go:nosplit +func (c *sigctxt) sigFromSeccomp() bool { + return false +} diff --git a/contrib/go/_std_1.22/src/runtime/os_wasip1.go b/contrib/go/_std_1.23/src/runtime/os_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_wasip1.go rename to contrib/go/_std_1.23/src/runtime/os_wasip1.go diff --git a/contrib/go/_std_1.22/src/runtime/os_wasm.go b/contrib/go/_std_1.23/src/runtime/os_wasm.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/os_wasm.go rename to contrib/go/_std_1.23/src/runtime/os_wasm.go index ce260de67e5c..fbafc319b988 100644 --- a/contrib/go/_std_1.22/src/runtime/os_wasm.go +++ b/contrib/go/_std_1.23/src/runtime/os_wasm.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/os_windows.go b/contrib/go/_std_1.23/src/runtime/os_windows.go similarity index 90% rename from contrib/go/_std_1.22/src/runtime/os_windows.go rename to contrib/go/_std_1.23/src/runtime/os_windows.go index 6533b6400490..4aabc29644e6 100644 --- a/contrib/go/_std_1.22/src/runtime/os_windows.go +++ b/contrib/go/_std_1.23/src/runtime/os_windows.go @@ -7,7 +7,7 @@ package runtime import ( "internal/abi" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -20,7 +20,6 @@ const ( //go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler%2 "kernel32.dll" //go:cgo_import_dynamic runtime._CloseHandle CloseHandle%1 "kernel32.dll" //go:cgo_import_dynamic runtime._CreateEventA CreateEventA%4 "kernel32.dll" -//go:cgo_import_dynamic runtime._CreateFileA CreateFileA%7 "kernel32.dll" //go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll" //go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll" //go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll" @@ -44,6 +43,7 @@ const ( //go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll" //go:cgo_import_dynamic runtime._PostQueuedCompletionStatus PostQueuedCompletionStatus%4 "kernel32.dll" //go:cgo_import_dynamic runtime._QueryPerformanceCounter QueryPerformanceCounter%1 "kernel32.dll" +//go:cgo_import_dynamic runtime._QueryPerformanceFrequency QueryPerformanceFrequency%1 "kernel32.dll" //go:cgo_import_dynamic runtime._RaiseFailFastException RaiseFailFastException%3 "kernel32.dll" //go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll" //go:cgo_import_dynamic runtime._RtlLookupFunctionEntry RtlLookupFunctionEntry%3 "kernel32.dll" @@ -78,7 +78,6 @@ var ( _AddVectoredExceptionHandler, _CloseHandle, _CreateEventA, - _CreateFileA, _CreateIoCompletionPort, _CreateThread, _CreateWaitableTimerA, @@ -102,6 +101,7 @@ var ( _LoadLibraryW, _PostQueuedCompletionStatus, _QueryPerformanceCounter, + _QueryPerformanceFrequency, _RaiseFailFastException, _ResumeThread, _RtlLookupFunctionEntry, @@ -133,13 +133,15 @@ var ( // Load ntdll.dll manually during startup, otherwise Mingw // links wrong printf function to cgo executable (see issue // 12030 for details). - _RtlGetCurrentPeb stdFunction - _RtlGetNtVersionNumbers stdFunction + _NtCreateWaitCompletionPacket stdFunction + _NtAssociateWaitCompletionPacket stdFunction + _NtCancelWaitCompletionPacket stdFunction + _RtlGetCurrentPeb stdFunction + _RtlGetVersion stdFunction // These are from non-kernel32.dll, so we prefer to LoadLibraryEx them. _timeBeginPeriod, _timeEndPeriod, - _WSAGetOverlappedResult, _ stdFunction ) @@ -148,7 +150,6 @@ var ( ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0} powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0} winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0} - ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0} ) // Function to be called by windows CreateThread @@ -165,7 +166,9 @@ type mOS struct { waitsema uintptr // semaphore for parking on locks resumesema uintptr // semaphore to indicate suspend/resume - highResTimer uintptr // high resolution timer handle used in usleep + highResTimer uintptr // high resolution timer handle used in usleep + waitIocpTimer uintptr // high resolution timer handle used in netpoll + waitIocpHandle uintptr // wait completion handle used in netpoll // preemptExtLock synchronizes preemptM with entry/exit from // external C code. @@ -213,6 +216,8 @@ func asmstdcall(fn unsafe.Pointer) var asmstdcallAddr unsafe.Pointer +type winlibcall libcall + func windowsFindfunc(lib uintptr, name []byte) stdFunction { if name[len(name)-1] != 0 { throw("usage") @@ -243,6 +248,20 @@ func windowsLoadSystemLib(name []uint16) uintptr { return stdcall3(_LoadLibraryExW, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32) } +//go:linkname windows_QueryPerformanceCounter internal/syscall/windows.QueryPerformanceCounter +func windows_QueryPerformanceCounter() int64 { + var counter int64 + stdcall1(_QueryPerformanceCounter, uintptr(unsafe.Pointer(&counter))) + return counter +} + +//go:linkname windows_QueryPerformanceFrequency internal/syscall/windows.QueryPerformanceFrequency +func windows_QueryPerformanceFrequency() int64 { + var frequency int64 + stdcall1(_QueryPerformanceFrequency, uintptr(unsafe.Pointer(&frequency))) + return frequency +} + func loadOptionalSyscalls() { bcryptPrimitives := windowsLoadSystemLib(bcryptprimitivesdll[:]) if bcryptPrimitives == 0 { @@ -254,27 +273,20 @@ func loadOptionalSyscalls() { if n32 == 0 { throw("ntdll.dll not found") } - _RtlGetCurrentPeb = windowsFindfunc(n32, []byte("RtlGetCurrentPeb\000")) - _RtlGetNtVersionNumbers = windowsFindfunc(n32, []byte("RtlGetNtVersionNumbers\000")) - - m32 := windowsLoadSystemLib(winmmdll[:]) - if m32 == 0 { - throw("winmm.dll not found") - } - _timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000")) - _timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000")) - if _timeBeginPeriod == nil || _timeEndPeriod == nil { - throw("timeBegin/EndPeriod not found") - } - - ws232 := windowsLoadSystemLib(ws2_32dll[:]) - if ws232 == 0 { - throw("ws2_32.dll not found") - } - _WSAGetOverlappedResult = windowsFindfunc(ws232, []byte("WSAGetOverlappedResult\000")) - if _WSAGetOverlappedResult == nil { - throw("WSAGetOverlappedResult not found") + _NtCreateWaitCompletionPacket = windowsFindfunc(n32, []byte("NtCreateWaitCompletionPacket\000")) + if _NtCreateWaitCompletionPacket != nil { + // These functions should exists if NtCreateWaitCompletionPacket exists. + _NtAssociateWaitCompletionPacket = windowsFindfunc(n32, []byte("NtAssociateWaitCompletionPacket\000")) + if _NtAssociateWaitCompletionPacket == nil { + throw("NtCreateWaitCompletionPacket exists but NtAssociateWaitCompletionPacket does not") + } + _NtCancelWaitCompletionPacket = windowsFindfunc(n32, []byte("NtCancelWaitCompletionPacket\000")) + if _NtCancelWaitCompletionPacket == nil { + throw("NtCreateWaitCompletionPacket exists but NtCancelWaitCompletionPacket does not") + } } + _RtlGetCurrentPeb = windowsFindfunc(n32, []byte("RtlGetCurrentPeb\000")) + _RtlGetVersion = windowsFindfunc(n32, []byte("RtlGetVersion\000")) } func monitorSuspendResume() { @@ -310,21 +322,6 @@ func monitorSuspendResume() { uintptr(unsafe.Pointer(¶ms)), uintptr(unsafe.Pointer(&handle))) } -//go:nosplit -func getLoadLibrary() uintptr { - return uintptr(unsafe.Pointer(_LoadLibraryW)) -} - -//go:nosplit -func getLoadLibraryEx() uintptr { - return uintptr(unsafe.Pointer(_LoadLibraryExW)) -} - -//go:nosplit -func getGetProcAddress() uintptr { - return uintptr(unsafe.Pointer(_GetProcAddress)) -} - func getproccount() int32 { var mask, sysmask uintptr ret := stdcall3(_GetProcessAffinityMask, currentProcess, uintptr(unsafe.Pointer(&mask)), uintptr(unsafe.Pointer(&sysmask))) @@ -397,6 +394,13 @@ func osRelax(relax bool) uint32 { // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag is available. var haveHighResTimer = false +// haveHighResSleep indicates that NtCreateWaitCompletionPacket +// exists and haveHighResTimer is true. +// NtCreateWaitCompletionPacket has been available since Windows 10, +// but has just been publicly documented, so some platforms, like Wine, +// doesn't support it yet. +var haveHighResSleep = false + // createHighResTimer calls CreateWaitableTimerEx with // CREATE_WAITABLE_TIMER_HIGH_RESOLUTION flag to create high // resolution timer. createHighResTimer returns new timer @@ -420,78 +424,50 @@ func initHighResTimer() { h := createHighResTimer() if h != 0 { haveHighResTimer = true + haveHighResSleep = _NtCreateWaitCompletionPacket != nil stdcall1(_CloseHandle, h) + } else { + // Only load winmm.dll if we need it. + // This avoids a dependency on winmm.dll for Go programs + // that run on new Windows versions. + m32 := windowsLoadSystemLib(winmmdll[:]) + if m32 == 0 { + print("runtime: LoadLibraryExW failed; errno=", getlasterror(), "\n") + throw("winmm.dll not found") + } + _timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000")) + _timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000")) + if _timeBeginPeriod == nil || _timeEndPeriod == nil { + print("runtime: GetProcAddress failed; errno=", getlasterror(), "\n") + throw("timeBegin/EndPeriod not found") + } } } -//go:linkname canUseLongPaths os.canUseLongPaths +//go:linkname canUseLongPaths internal/syscall/windows.CanUseLongPaths var canUseLongPaths bool -// We want this to be large enough to hold the contents of sysDirectory, *plus* -// a slash and another component that itself is greater than MAX_PATH. -var longFileName [(_MAX_PATH+1)*2 + 1]byte - -// initLongPathSupport initializes the canUseLongPaths variable, which is -// linked into os.canUseLongPaths for determining whether or not long paths -// need to be fixed up. In the best case, this function is running on newer -// Windows 10 builds, which have a bit field member of the PEB called -// "IsLongPathAwareProcess." When this is set, we don't need to go through the -// error-prone fixup function in order to access long paths. So this init -// function first checks the Windows build number, sets the flag, and then -// tests to see if it's actually working. If everything checks out, then -// canUseLongPaths is set to true, and later when called, os.fixLongPath -// returns early without doing work. +// initLongPathSupport enables long path support. func initLongPathSupport() { const ( IsLongPathAwareProcess = 0x80 PebBitFieldOffset = 3 - OPEN_EXISTING = 3 - ERROR_PATH_NOT_FOUND = 3 ) // Check that we're ≥ 10.0.15063. - var maj, min, build uint32 - stdcall3(_RtlGetNtVersionNumbers, uintptr(unsafe.Pointer(&maj)), uintptr(unsafe.Pointer(&min)), uintptr(unsafe.Pointer(&build))) - if maj < 10 || (maj == 10 && min == 0 && build&0xffff < 15063) { + info := _OSVERSIONINFOW{} + info.osVersionInfoSize = uint32(unsafe.Sizeof(info)) + stdcall1(_RtlGetVersion, uintptr(unsafe.Pointer(&info))) + if info.majorVersion < 10 || (info.majorVersion == 10 && info.minorVersion == 0 && info.buildNumber < 15063) { return } // Set the IsLongPathAwareProcess flag of the PEB's bit field. + // This flag is not documented, but it's known to be used + // by Windows to enable long path support. bitField := (*byte)(unsafe.Pointer(stdcall0(_RtlGetCurrentPeb) + PebBitFieldOffset)) - originalBitField := *bitField *bitField |= IsLongPathAwareProcess - // Check that this actually has an effect, by constructing a large file - // path and seeing whether we get ERROR_PATH_NOT_FOUND, rather than - // some other error, which would indicate the path is too long, and - // hence long path support is not successful. This whole section is NOT - // strictly necessary, but is a nice validity check for the near to - // medium term, when this functionality is still relatively new in - // Windows. - targ := longFileName[len(longFileName)-33 : len(longFileName)-1] - if readRandom(targ) != len(targ) { - readTimeRandom(targ) - } - start := copy(longFileName[:], sysDirectory[:sysDirectoryLen]) - const dig = "0123456789abcdef" - for i := 0; i < 32; i++ { - longFileName[start+i*2] = dig[longFileName[len(longFileName)-33+i]>>4] - longFileName[start+i*2+1] = dig[longFileName[len(longFileName)-33+i]&0xf] - } - start += 64 - for i := start; i < len(longFileName)-1; i++ { - longFileName[i] = 'A' - } - stdcall7(_CreateFileA, uintptr(unsafe.Pointer(&longFileName[0])), 0, 0, 0, OPEN_EXISTING, 0, 0) - // The ERROR_PATH_NOT_FOUND error value is distinct from - // ERROR_FILE_NOT_FOUND or ERROR_INVALID_NAME, the latter of which we - // expect here due to the final component being too long. - if getlasterror() == ERROR_PATH_NOT_FOUND { - *bitField = originalBitField - println("runtime: warning: IsLongPathAwareProcess failed to enable long paths; proceeding in fixup mode") - return - } - canUseLongPaths = true } @@ -850,7 +826,7 @@ func sigblock(exiting bool) { } // Called to initialize a new m (including the bootstrap m). -// Called on the new thread, cannot allocate memory. +// Called on the new thread, cannot allocate Go memory. func minit() { var thandle uintptr if stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS) == 0 { @@ -871,6 +847,19 @@ func minit() { throw("CreateWaitableTimerEx when creating timer failed") } } + if mp.waitIocpHandle == 0 && haveHighResSleep { + mp.waitIocpTimer = createHighResTimer() + if mp.waitIocpTimer == 0 { + print("runtime: CreateWaitableTimerEx failed; errno=", getlasterror(), "\n") + throw("CreateWaitableTimerEx when creating timer failed") + } + const GENERIC_ALL = 0x10000000 + errno := stdcall3(_NtCreateWaitCompletionPacket, uintptr(unsafe.Pointer(&mp.waitIocpHandle)), GENERIC_ALL, 0) + if mp.waitIocpHandle == 0 { + print("runtime: NtCreateWaitCompletionPacket failed; errno=", errno, "\n") + throw("NtCreateWaitCompletionPacket failed") + } + } unlock(&mp.threadLock) // Query the true stack base from the OS. Currently we're @@ -925,6 +914,14 @@ func mdestroy(mp *m) { stdcall1(_CloseHandle, mp.highResTimer) mp.highResTimer = 0 } + if mp.waitIocpTimer != 0 { + stdcall1(_CloseHandle, mp.waitIocpTimer) + mp.waitIocpTimer = 0 + } + if mp.waitIocpHandle != 0 { + stdcall1(_CloseHandle, mp.waitIocpHandle) + mp.waitIocpHandle = 0 + } if mp.waitsema != 0 { stdcall1(_CloseHandle, mp.waitsema) mp.waitsema = 0 diff --git a/contrib/go/_std_1.22/src/runtime/os_windows_arm.go b/contrib/go/_std_1.23/src/runtime/os_windows_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_windows_arm.go rename to contrib/go/_std_1.23/src/runtime/os_windows_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/os_windows_arm64.go b/contrib/go/_std_1.23/src/runtime/os_windows_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/os_windows_arm64.go rename to contrib/go/_std_1.23/src/runtime/os_windows_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/panic.go b/contrib/go/_std_1.23/src/runtime/panic.go similarity index 92% rename from contrib/go/_std_1.22/src/runtime/panic.go rename to contrib/go/_std_1.23/src/runtime/panic.go index 36d658aa4c9d..12bbf96a2136 100644 --- a/contrib/go/_std_1.22/src/runtime/panic.go +++ b/contrib/go/_std_1.23/src/runtime/panic.go @@ -7,7 +7,8 @@ package runtime import ( "internal/abi" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" + "internal/stringslite" "runtime/internal/sys" "unsafe" ) @@ -53,7 +54,7 @@ const ( // pc should be the program counter of the compiler-generated code that // triggered this panic. func panicCheck1(pc uintptr, msg string) { - if goarch.IsWasm == 0 && hasPrefix(funcname(findfunc(pc)), "runtime.") { + if goarch.IsWasm == 0 && stringslite.HasPrefix(funcname(findfunc(pc)), "runtime.") { // Note: wasm can't tail call, so we can't get the original caller's pc. throw(msg) } @@ -296,11 +297,24 @@ func deferproc(fn func()) { // been set and must not be clobbered. } -var rangeExitError = error(errorString("range function continued iteration after exit")) +var rangeDoneError = error(errorString("range function continued iteration after function for loop body returned false")) +var rangePanicError = error(errorString("range function continued iteration after loop body panic")) +var rangeExhaustedError = error(errorString("range function continued iteration after whole loop exit")) +var rangeMissingPanicError = error(errorString("range function recovered a loop body panic and did not resume panicking")) //go:noinline -func panicrangeexit() { - panic(rangeExitError) +func panicrangestate(state int) { + switch abi.RF_State(state) { + case abi.RF_DONE: + panic(rangeDoneError) + case abi.RF_PANIC: + panic(rangePanicError) + case abi.RF_EXHAUSTED: + panic(rangeExhaustedError) + case abi.RF_MISSING_PANIC: + panic(rangeMissingPanicError) + } + throw("unexpected state passed to panicrangestate") } // deferrangefunc is called by functions that are about to @@ -377,10 +391,16 @@ func deferrangefunc() any { throw("defer on system stack") } + fn := findfunc(getcallerpc()) + if fn.deferreturn == 0 { + throw("no deferreturn") + } + d := newdefer() d.link = gp._defer gp._defer = d - d.pc = getcallerpc() + + d.pc = fn.entry() + uintptr(fn.deferreturn) // We must not be preempted between calling getcallersp and // storing it to d.sp because getcallersp's result is a // uintptr stack pointer. @@ -420,17 +440,18 @@ func deferprocat(fn func(), frame any) { return0() } -// deferconvert converts a rangefunc defer list into an ordinary list. +// deferconvert converts the rangefunc defer list of d0 into an ordinary list +// following d0. // See the doc comment for deferrangefunc for details. -func deferconvert(d *_defer) *_defer { - head := d.head +func deferconvert(d0 *_defer) { + head := d0.head if raceenabled { racereadpc(unsafe.Pointer(head), getcallerpc(), abi.FuncPCABIInternal(deferconvert)) } - tail := d.link - d.rangefunc = false - d0 := d + tail := d0.link + d0.rangefunc = false + var d *_defer for { d = head.Load() if head.CompareAndSwap(d, badDefer()) { @@ -438,8 +459,7 @@ func deferconvert(d *_defer) *_defer { } } if d == nil { - freedefer(d0) - return tail + return } for d1 := d; ; d1 = d1.link { d1.sp = d0.sp @@ -449,8 +469,8 @@ func deferconvert(d *_defer) *_defer { break } } - freedefer(d0) - return d + d0.link = d + return } // deferprocStack queues a new deferred function with a defer record on the stack. @@ -528,22 +548,18 @@ func newdefer() *_defer { return d } -// Free the given defer. -// The defer cannot be used after this call. -// -// This is nosplit because the incoming defer is in a perilous state. -// It's not on any defer list, so stack copying won't adjust stack -// pointers in it (namely, d.link). Hence, if we were to copy the -// stack, d could then contain a stale pointer. -// -//go:nosplit -func freedefer(d *_defer) { +// popDefer pops the head of gp's defer list and frees it. +func popDefer(gp *g) { + d := gp._defer + d.fn = nil // Can in theory point to the stack + // We must not copy the stack between the updating gp._defer and setting + // d.link to nil. Between these two steps, d is not on any defer list, so + // stack copying won't adjust stack pointers in it (namely, d.link). Hence, + // if we were to copy the stack, d could then contain a stale pointer. + gp._defer = d.link d.link = nil // After this point we can copy the stack. - if d.fn != nil { - freedeferfn() - } if !d.heap { return } @@ -579,13 +595,6 @@ func freedefer(d *_defer) { mp, pp = nil, nil } -// Separate function so that it can split stack. -// Windows otherwise runs out of stack space. -func freedeferfn() { - // fn must be cleared before d is unlinked from gp. - throw("freedefer with d.fn != nil") -} - // deferreturn runs deferred functions for the caller's frame. // The compiler inserts a call to this at the end of any // function which calls defer. @@ -667,7 +676,7 @@ func printpanics(p *_panic) { return } print("panic: ") - printany(p.arg) + printpanicval(p.arg) if p.recovered { print(" [recovered]") } @@ -717,6 +726,18 @@ func (*PanicNilError) RuntimeError() {} var panicnil = &godebugInc{name: "panicnil"} // The implementation of the predeclared function panic. +// The compiler emits calls to this function. +// +// gopanic should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - go.undefinedlabs.com/scopeagent +// - github.com/goplus/igop +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname gopanic func gopanic(e any) { if e == nil { if debug.panicnil.Load() != 1 { @@ -729,20 +750,20 @@ func gopanic(e any) { gp := getg() if gp.m.curg != gp { print("panic: ") - printany(e) + printpanicval(e) print("\n") throw("panic on system stack") } if gp.m.mallocing != 0 { print("panic: ") - printany(e) + printpanicval(e) print("\n") throw("panic during malloc") } if gp.m.preemptoff != "" { print("panic: ") - printany(e) + printpanicval(e) print("\n") print("preempt off reason: ") print(gp.m.preemptoff) @@ -751,7 +772,7 @@ func gopanic(e any) { } if gp.m.locks != 0 { print("panic: ") - printany(e) + printpanicval(e) print("\n") throw("panic holding locks") } @@ -770,6 +791,16 @@ func gopanic(e any) { fn() } + // If we're tracing, flush the current generation to make the trace more + // readable. + // + // TODO(aktau): Handle a panic from within traceAdvance more gracefully. + // Currently it would hang. Not handled now because it is very unlikely, and + // already unrecoverable. + if traceEnabled() { + traceAdvance(false) + } + // ran out of deferred calls - old-school panic now // Because it is unsafe to call arbitrary user code after freezing // the world, we call preprintpanics to invoke all necessary Error @@ -876,12 +907,12 @@ func (p *_panic) nextDefer() (func(), bool) { Recheck: if d := gp._defer; d != nil && d.sp == uintptr(p.sp) { if d.rangefunc { - gp._defer = deferconvert(d) + deferconvert(d) + popDefer(gp) goto Recheck } fn := d.fn - d.fn = nil // TODO(mdempsky): Instead of having each deferproc call have // its own "deferreturn(); return" sequence, we should just make @@ -889,8 +920,7 @@ func (p *_panic) nextDefer() (func(), bool) { p.retpc = d.pc // Unlink and free. - gp._defer = d.link - freedefer(d) + popDefer(gp) return fn, true } @@ -1012,12 +1042,32 @@ func sync_fatal(s string) { // throw should be used for runtime-internal fatal errors where Go itself, // rather than user code, may be at fault for the failure. // +// NOTE: temporarily marked "go:noinline" pending investigation/fix of +// issue #67274, so as to fix longtest builders. +// +// throw should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cockroachdb/pebble +// - github.com/dgraph-io/ristretto +// - github.com/outcaste-io/ristretto +// - github.com/pingcap/br +// - gvisor.dev/gvisor +// - github.com/sagernet/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname throw //go:nosplit func throw(s string) { // Everything throw does should be recursively nosplit so it // can be called even when it's unsafe to grow the stack. systemstack(func() { - print("fatal error: ", s, "\n") + print("fatal error: ") + printindented(s) // logically printpanicval(s), but avoids convTstring write barrier + print("\n") }) fatalthrow(throwTypeRuntime) @@ -1036,7 +1086,9 @@ func fatal(s string) { // Everything fatal does should be recursively nosplit so it // can be called even when it's unsafe to grow the stack. systemstack(func() { - print("fatal error: ", s, "\n") + print("fatal error: ") + printindented(s) // logically printpanicval(s), but avoids convTstring write barrier + print("\n") }) fatalthrow(throwTypeUser) @@ -1169,6 +1221,8 @@ func recovery(gp *g) { // only gets us to the caller's fp. gp.sched.bp = sp - goarch.PtrSize } + // The value in ret is delivered IN A REGISTER, even if there is a + // stack ABI. gp.sched.ret = 1 gogo(&gp.sched) } diff --git a/contrib/go/_std_1.22/src/runtime/panic32.go b/contrib/go/_std_1.23/src/runtime/panic32.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/panic32.go rename to contrib/go/_std_1.23/src/runtime/panic32.go diff --git a/contrib/go/_std_1.22/src/runtime/pinner.go b/contrib/go/_std_1.23/src/runtime/pinner.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/pinner.go rename to contrib/go/_std_1.23/src/runtime/pinner.go index 1ede1113eecf..7a9c3815803b 100644 --- a/contrib/go/_std_1.22/src/runtime/pinner.go +++ b/contrib/go/_std_1.23/src/runtime/pinner.go @@ -5,7 +5,8 @@ package runtime import ( - "runtime/internal/atomic" + "internal/abi" + "internal/runtime/atomic" "unsafe" ) @@ -107,7 +108,7 @@ func pinnerGetPtr(i *any) unsafe.Pointer { if etyp == nil { panic(errorString("runtime.Pinner: argument is nil")) } - if kind := etyp.Kind_ & kindMask; kind != kindPtr && kind != kindUnsafePointer { + if kind := etyp.Kind_ & abi.KindMask; kind != abi.Pointer && kind != abi.UnsafePointer { panic(errorString("runtime.Pinner: argument is not a pointer: " + toRType(etyp).string())) } if inUserArenaChunk(uintptr(e.data)) { @@ -271,7 +272,7 @@ func (s *mspan) pinnerBitSize() uintptr { } // newPinnerBits returns a pointer to 8 byte aligned bytes to be used for this -// span's pinner bits. newPinneBits is used to mark objects that are pinned. +// span's pinner bits. newPinnerBits is used to mark objects that are pinned. // They are copied when the span is swept. func (s *mspan) newPinnerBits() *pinnerBits { return (*pinnerBits)(newMarkBits(uintptr(s.nelems) * 2)) diff --git a/contrib/go/_std_1.22/src/runtime/plugin.go b/contrib/go/_std_1.23/src/runtime/plugin.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/plugin.go rename to contrib/go/_std_1.23/src/runtime/plugin.go index 40dfefde1701..4b6821b1fbbc 100644 --- a/contrib/go/_std_1.22/src/runtime/plugin.go +++ b/contrib/go/_std_1.23/src/runtime/plugin.go @@ -4,7 +4,10 @@ package runtime -import "unsafe" +import ( + "internal/abi" + "unsafe" +) //go:linkname plugin_lastmoduleinit plugin.lastmoduleinit func plugin_lastmoduleinit() (path string, syms map[string]any, initTasks []*initTask, errstr string) { @@ -85,7 +88,7 @@ func plugin_lastmoduleinit() (path string, syms map[string]any, initTasks []*ini (*valp)[0] = unsafe.Pointer(t) name := symName.Name() - if t.Kind_&kindMask == kindFunc { + if t.Kind_&abi.KindMask == abi.Func { name = "." + name } syms[name] = val diff --git a/contrib/go/_std_1.22/src/runtime/pprof/defs_darwin.go b/contrib/go/_std_1.23/src/runtime/pprof/defs_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/defs_darwin.go rename to contrib/go/_std_1.23/src/runtime/pprof/defs_darwin.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/defs_darwin_amd64.go b/contrib/go/_std_1.23/src/runtime/pprof/defs_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/defs_darwin_amd64.go rename to contrib/go/_std_1.23/src/runtime/pprof/defs_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/defs_darwin_arm64.go b/contrib/go/_std_1.23/src/runtime/pprof/defs_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/defs_darwin_arm64.go rename to contrib/go/_std_1.23/src/runtime/pprof/defs_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/elf.go b/contrib/go/_std_1.23/src/runtime/pprof/elf.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/elf.go rename to contrib/go/_std_1.23/src/runtime/pprof/elf.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/label.go b/contrib/go/_std_1.23/src/runtime/pprof/label.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/pprof/label.go rename to contrib/go/_std_1.23/src/runtime/pprof/label.go index 3684ae34e51c..41eece2f74c0 100644 --- a/contrib/go/_std_1.22/src/runtime/pprof/label.go +++ b/contrib/go/_std_1.23/src/runtime/pprof/label.go @@ -7,7 +7,7 @@ package pprof import ( "context" "fmt" - "sort" + "slices" "strings" ) @@ -49,7 +49,7 @@ func (l *labelMap) String() string { keyVals = append(keyVals, fmt.Sprintf("%q:%q", k, v)) } - sort.Strings(keyVals) + slices.Sort(keyVals) return "{" + strings.Join(keyVals, ", ") + "}" } diff --git a/contrib/go/_std_1.22/src/runtime/pprof/map.go b/contrib/go/_std_1.23/src/runtime/pprof/map.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/map.go rename to contrib/go/_std_1.23/src/runtime/pprof/map.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/pe.go b/contrib/go/_std_1.23/src/runtime/pprof/pe.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/pe.go rename to contrib/go/_std_1.23/src/runtime/pprof/pe.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/pprof.go b/contrib/go/_std_1.23/src/runtime/pprof/pprof.go similarity index 88% rename from contrib/go/_std_1.22/src/runtime/pprof/pprof.go rename to contrib/go/_std_1.23/src/runtime/pprof/pprof.go index a4dcf3350826..4b7a9f63c650 100644 --- a/contrib/go/_std_1.22/src/runtime/pprof/pprof.go +++ b/contrib/go/_std_1.23/src/runtime/pprof/pprof.go @@ -74,10 +74,13 @@ package pprof import ( "bufio" + "cmp" "fmt" "internal/abi" + "internal/profilerecord" "io" "runtime" + "slices" "sort" "strings" "sync" @@ -278,7 +281,9 @@ func Profiles() []*Profile { all = append(all, p) } - sort.Slice(all, func(i, j int) bool { return all[i].name < all[j].name }) + slices.SortFunc(all, func(a, b *Profile) int { + return strings.Compare(a.name, b.name) + }) return all } @@ -352,7 +357,7 @@ func (p *Profile) Remove(value any) { // // The debug parameter enables additional output. // Passing debug=0 writes the gzip-compressed protocol buffer described -// in https://github.com/google/pprof/tree/master/proto#overview. +// in https://github.com/google/pprof/tree/main/proto#overview. // Passing debug=1 writes the legacy text format with comments // translating addresses to function names and line numbers, so that a // programmer can read the profile without tools. @@ -378,15 +383,7 @@ func (p *Profile) WriteTo(w io.Writer, debug int) error { p.mu.Unlock() // Map order is non-deterministic; make output deterministic. - sort.Slice(all, func(i, j int) bool { - t, u := all[i], all[j] - for k := 0; k < len(t) && k < len(u); k++ { - if t[k] != u[k] { - return t[k] < u[k] - } - } - return len(t) < len(u) - }) + slices.SortFunc(all, slices.Compare) return printCountProfile(w, debug, p.name, stackProfile(all)) } @@ -407,11 +404,30 @@ type countProfile interface { Label(i int) *labelMap } +// expandInlinedFrames copies the call stack from pcs into dst, expanding any +// PCs corresponding to inlined calls into the corresponding PCs for the inlined +// functions. Returns the number of frames copied to dst. +func expandInlinedFrames(dst, pcs []uintptr) int { + cf := runtime.CallersFrames(pcs) + var n int + for n < len(dst) { + f, more := cf.Next() + // f.PC is a "call PC", but later consumers will expect + // "return PCs" + dst[n] = f.PC + 1 + n++ + if !more { + break + } + } + return n +} + // printCountCycleProfile outputs block profile records (for block or mutex profiles) // as the pprof-proto format output. Translations from cycle count to time duration // are done because The proto expects count and time (nanoseconds) instead of count // and the number of cycles for block, contention profiles. -func printCountCycleProfile(w io.Writer, countName, cycleName string, records []runtime.BlockProfileRecord) error { +func printCountCycleProfile(w io.Writer, countName, cycleName string, records []profilerecord.BlockProfileRecord) error { // Output profile in protobuf form. b := newProfileBuilder(w) b.pbValueType(tagProfile_PeriodType, countName, "count") @@ -419,16 +435,18 @@ func printCountCycleProfile(w io.Writer, countName, cycleName string, records [] b.pbValueType(tagProfile_SampleType, countName, "count") b.pbValueType(tagProfile_SampleType, cycleName, "nanoseconds") - cpuGHz := float64(runtime_cyclesPerSecond()) / 1e9 + cpuGHz := float64(pprof_cyclesPerSecond()) / 1e9 values := []int64{0, 0} var locs []uint64 + expandedStack := pprof_makeProfStack() for _, r := range records { values[0] = r.Count values[1] = int64(float64(r.Cycles) / cpuGHz) // For count profiles, all stack addresses are // return PCs, which is what appendLocsForStack expects. - locs = b.appendLocsForStack(locs[:0], r.Stack()) + n := expandInlinedFrames(expandedStack, r.Stack) + locs = b.appendLocsForStack(locs[:0], expandedStack[:n]) b.pbSample(values, locs, nil) } b.build() @@ -587,20 +605,21 @@ func writeHeapInternal(w io.Writer, debug int, defaultSampleType string) error { runtime.ReadMemStats(memStats) } - // Find out how many records there are (MemProfile(nil, true)), + // Find out how many records there are (the call + // pprof_memProfileInternal(nil, true) below), // allocate that many records, and get the data. // There's a race—more records might be added between // the two calls—so allocate a few extra records for safety // and also try again if we're very unlucky. // The loop should only execute one iteration in the common case. - var p []runtime.MemProfileRecord - n, ok := runtime.MemProfile(nil, true) + var p []profilerecord.MemProfileRecord + n, ok := pprof_memProfileInternal(nil, true) for { // Allocate room for a slightly bigger profile, // in case a few more entries have been added // since the call to MemProfile. - p = make([]runtime.MemProfileRecord, n+50) - n, ok = runtime.MemProfile(p, true) + p = make([]profilerecord.MemProfileRecord, n+50) + n, ok = pprof_memProfileInternal(p, true) if ok { p = p[0:n] break @@ -612,7 +631,9 @@ func writeHeapInternal(w io.Writer, debug int, defaultSampleType string) error { return writeHeapProto(w, p, int64(runtime.MemProfileRate), defaultSampleType) } - sort.Slice(p, func(i, j int) bool { return p[i].InUseBytes() > p[j].InUseBytes() }) + slices.SortFunc(p, func(a, b profilerecord.MemProfileRecord) int { + return cmp.Compare(a.InUseBytes(), b.InUseBytes()) + }) b := bufio.NewWriter(w) tw := tabwriter.NewWriter(b, 1, 8, 1, '\t', 0) @@ -654,11 +675,11 @@ func writeHeapInternal(w io.Writer, debug int, defaultSampleType string) error { fmt.Fprintf(w, "%d: %d [%d: %d] @", r.InUseObjects(), r.InUseBytes(), r.AllocObjects, r.AllocBytes) - for _, pc := range r.Stack() { + for _, pc := range r.Stack { fmt.Fprintf(w, " %#x", pc) } fmt.Fprintf(w, "\n") - printStackRecord(w, r.Stack(), false) + printStackRecord(w, r.Stack, false) } // Print memstats information too. @@ -713,8 +734,8 @@ func writeThreadCreate(w io.Writer, debug int) error { // Until https://golang.org/issues/6104 is addressed, wrap // ThreadCreateProfile because there's no point in tracking labels when we // don't get any stack-traces. - return writeRuntimeProfile(w, debug, "threadcreate", func(p []runtime.StackRecord, _ []unsafe.Pointer) (n int, ok bool) { - return runtime.ThreadCreateProfile(p) + return writeRuntimeProfile(w, debug, "threadcreate", func(p []profilerecord.StackRecord, _ []unsafe.Pointer) (n int, ok bool) { + return pprof_threadCreateInternal(p) }) } @@ -723,15 +744,12 @@ func countGoroutine() int { return runtime.NumGoroutine() } -// runtime_goroutineProfileWithLabels is defined in runtime/mprof.go -func runtime_goroutineProfileWithLabels(p []runtime.StackRecord, labels []unsafe.Pointer) (n int, ok bool) - // writeGoroutine writes the current runtime GoroutineProfile to w. func writeGoroutine(w io.Writer, debug int) error { if debug >= 2 { return writeGoroutineStacks(w) } - return writeRuntimeProfile(w, debug, "goroutine", runtime_goroutineProfileWithLabels) + return writeRuntimeProfile(w, debug, "goroutine", pprof_goroutineProfileWithLabels) } func writeGoroutineStacks(w io.Writer) error { @@ -755,21 +773,22 @@ func writeGoroutineStacks(w io.Writer) error { return err } -func writeRuntimeProfile(w io.Writer, debug int, name string, fetch func([]runtime.StackRecord, []unsafe.Pointer) (int, bool)) error { +func writeRuntimeProfile(w io.Writer, debug int, name string, fetch func([]profilerecord.StackRecord, []unsafe.Pointer) (int, bool)) error { // Find out how many records there are (fetch(nil)), // allocate that many records, and get the data. // There's a race—more records might be added between // the two calls—so allocate a few extra records for safety // and also try again if we're very unlucky. // The loop should only execute one iteration in the common case. - var p []runtime.StackRecord + var p []profilerecord.StackRecord var labels []unsafe.Pointer n, ok := fetch(nil, nil) + for { // Allocate room for a slightly bigger profile, // in case a few more entries have been added // since the call to ThreadProfile. - p = make([]runtime.StackRecord, n+10) + p = make([]profilerecord.StackRecord, n+10) labels = make([]unsafe.Pointer, n+10) n, ok = fetch(p, labels) if ok { @@ -783,12 +802,12 @@ func writeRuntimeProfile(w io.Writer, debug int, name string, fetch func([]runti } type runtimeProfile struct { - stk []runtime.StackRecord + stk []profilerecord.StackRecord labels []unsafe.Pointer } func (p *runtimeProfile) Len() int { return len(p.stk) } -func (p *runtimeProfile) Stack(i int) []uintptr { return p.stk[i].Stack() } +func (p *runtimeProfile) Stack(i int) []uintptr { return p.stk[i].Stack } func (p *runtimeProfile) Label(i int) *labelMap { return (*labelMap)(p.labels[i]) } var cpu struct { @@ -893,20 +912,20 @@ func countMutex() int { // writeBlock writes the current blocking profile to w. func writeBlock(w io.Writer, debug int) error { - return writeProfileInternal(w, debug, "contention", runtime.BlockProfile) + return writeProfileInternal(w, debug, "contention", pprof_blockProfileInternal) } // writeMutex writes the current mutex profile to w. func writeMutex(w io.Writer, debug int) error { - return writeProfileInternal(w, debug, "mutex", runtime.MutexProfile) + return writeProfileInternal(w, debug, "mutex", pprof_mutexProfileInternal) } // writeProfileInternal writes the current blocking or mutex profile depending on the passed parameters. -func writeProfileInternal(w io.Writer, debug int, name string, runtimeProfile func([]runtime.BlockProfileRecord) (int, bool)) error { - var p []runtime.BlockProfileRecord +func writeProfileInternal(w io.Writer, debug int, name string, runtimeProfile func([]profilerecord.BlockProfileRecord) (int, bool)) error { + var p []profilerecord.BlockProfileRecord n, ok := runtimeProfile(nil) for { - p = make([]runtime.BlockProfileRecord, n+50) + p = make([]profilerecord.BlockProfileRecord, n+50) n, ok = runtimeProfile(p) if ok { p = p[:n] @@ -914,7 +933,9 @@ func writeProfileInternal(w io.Writer, debug int, name string, runtimeProfile fu } } - sort.Slice(p, func(i, j int) bool { return p[i].Cycles > p[j].Cycles }) + slices.SortFunc(p, func(a, b profilerecord.BlockProfileRecord) int { + return cmp.Compare(b.Cycles, a.Cycles) + }) if debug <= 0 { return printCountCycleProfile(w, "contentions", "delay", p) @@ -925,19 +946,22 @@ func writeProfileInternal(w io.Writer, debug int, name string, runtimeProfile fu w = tw fmt.Fprintf(w, "--- %v:\n", name) - fmt.Fprintf(w, "cycles/second=%v\n", runtime_cyclesPerSecond()) + fmt.Fprintf(w, "cycles/second=%v\n", pprof_cyclesPerSecond()) if name == "mutex" { fmt.Fprintf(w, "sampling period=%d\n", runtime.SetMutexProfileFraction(-1)) } + expandedStack := pprof_makeProfStack() for i := range p { r := &p[i] fmt.Fprintf(w, "%v %v @", r.Cycles, r.Count) - for _, pc := range r.Stack() { + n := expandInlinedFrames(expandedStack, r.Stack) + stack := expandedStack[:n] + for _, pc := range stack { fmt.Fprintf(w, " %#x", pc) } fmt.Fprint(w, "\n") if debug > 0 { - printStackRecord(w, r.Stack(), true) + printStackRecord(w, stack, true) } } @@ -947,4 +971,26 @@ func writeProfileInternal(w io.Writer, debug int, name string, runtimeProfile fu return b.Flush() } -func runtime_cyclesPerSecond() int64 +//go:linkname pprof_goroutineProfileWithLabels runtime.pprof_goroutineProfileWithLabels +func pprof_goroutineProfileWithLabels(p []profilerecord.StackRecord, labels []unsafe.Pointer) (n int, ok bool) + +//go:linkname pprof_cyclesPerSecond runtime/pprof.runtime_cyclesPerSecond +func pprof_cyclesPerSecond() int64 + +//go:linkname pprof_memProfileInternal runtime.pprof_memProfileInternal +func pprof_memProfileInternal(p []profilerecord.MemProfileRecord, inuseZero bool) (n int, ok bool) + +//go:linkname pprof_blockProfileInternal runtime.pprof_blockProfileInternal +func pprof_blockProfileInternal(p []profilerecord.BlockProfileRecord) (n int, ok bool) + +//go:linkname pprof_mutexProfileInternal runtime.pprof_mutexProfileInternal +func pprof_mutexProfileInternal(p []profilerecord.BlockProfileRecord) (n int, ok bool) + +//go:linkname pprof_threadCreateInternal runtime.pprof_threadCreateInternal +func pprof_threadCreateInternal(p []profilerecord.StackRecord) (n int, ok bool) + +//go:linkname pprof_fpunwindExpand runtime.pprof_fpunwindExpand +func pprof_fpunwindExpand(dst, src []uintptr) int + +//go:linkname pprof_makeProfStack runtime.pprof_makeProfStack +func pprof_makeProfStack() []uintptr diff --git a/contrib/go/_std_1.22/src/runtime/pprof/pprof_norusage.go b/contrib/go/_std_1.23/src/runtime/pprof/pprof_norusage.go similarity index 71% rename from contrib/go/_std_1.22/src/runtime/pprof/pprof_norusage.go rename to contrib/go/_std_1.23/src/runtime/pprof/pprof_norusage.go index 8de38086c716..ef3cef42bdda 100644 --- a/contrib/go/_std_1.22/src/runtime/pprof/pprof_norusage.go +++ b/contrib/go/_std_1.23/src/runtime/pprof/pprof_norusage.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows +//go:build !unix && !windows package pprof diff --git a/contrib/go/_std_1.22/src/runtime/pprof/pprof_rusage.go b/contrib/go/_std_1.23/src/runtime/pprof/pprof_rusage.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/pprof_rusage.go rename to contrib/go/_std_1.23/src/runtime/pprof/pprof_rusage.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/pprof_windows.go b/contrib/go/_std_1.23/src/runtime/pprof/pprof_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/pprof_windows.go rename to contrib/go/_std_1.23/src/runtime/pprof/pprof_windows.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/proto.go b/contrib/go/_std_1.23/src/runtime/pprof/proto.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/proto.go rename to contrib/go/_std_1.23/src/runtime/pprof/proto.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/proto_darwin.go b/contrib/go/_std_1.23/src/runtime/pprof/proto_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/proto_darwin.go rename to contrib/go/_std_1.23/src/runtime/pprof/proto_darwin.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/proto_other.go b/contrib/go/_std_1.23/src/runtime/pprof/proto_other.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/proto_other.go rename to contrib/go/_std_1.23/src/runtime/pprof/proto_other.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/proto_windows.go b/contrib/go/_std_1.23/src/runtime/pprof/proto_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/proto_windows.go rename to contrib/go/_std_1.23/src/runtime/pprof/proto_windows.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/protobuf.go b/contrib/go/_std_1.23/src/runtime/pprof/protobuf.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/protobuf.go rename to contrib/go/_std_1.23/src/runtime/pprof/protobuf.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/protomem.go b/contrib/go/_std_1.23/src/runtime/pprof/protomem.go similarity index 94% rename from contrib/go/_std_1.22/src/runtime/pprof/protomem.go rename to contrib/go/_std_1.23/src/runtime/pprof/protomem.go index fa75a28c6263..ab3550f43f9a 100644 --- a/contrib/go/_std_1.22/src/runtime/pprof/protomem.go +++ b/contrib/go/_std_1.23/src/runtime/pprof/protomem.go @@ -5,6 +5,7 @@ package pprof import ( + "internal/profilerecord" "io" "math" "runtime" @@ -12,7 +13,7 @@ import ( ) // writeHeapProto writes the current heap profile in protobuf format to w. -func writeHeapProto(w io.Writer, p []runtime.MemProfileRecord, rate int64, defaultSampleType string) error { +func writeHeapProto(w io.Writer, p []profilerecord.MemProfileRecord, rate int64, defaultSampleType string) error { b := newProfileBuilder(w) b.pbValueType(tagProfile_PeriodType, "space", "bytes") b.pb.int64Opt(tagProfile_Period, rate) @@ -29,7 +30,7 @@ func writeHeapProto(w io.Writer, p []runtime.MemProfileRecord, rate int64, defau for _, r := range p { hideRuntime := true for tries := 0; tries < 2; tries++ { - stk := r.Stack() + stk := r.Stack // For heap profiles, all stack // addresses are return PCs, which is // what appendLocsForStack expects. diff --git a/contrib/go/_std_1.22/src/runtime/pprof/runtime.go b/contrib/go/_std_1.23/src/runtime/pprof/runtime.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/runtime.go rename to contrib/go/_std_1.23/src/runtime/pprof/runtime.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/vminfo_darwin.go b/contrib/go/_std_1.23/src/runtime/pprof/vminfo_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/vminfo_darwin.go rename to contrib/go/_std_1.23/src/runtime/pprof/vminfo_darwin.go diff --git a/contrib/go/_std_1.22/src/runtime/pprof/ya.make b/contrib/go/_std_1.23/src/runtime/pprof/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/pprof/ya.make rename to contrib/go/_std_1.23/src/runtime/pprof/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/preempt.go b/contrib/go/_std_1.23/src/runtime/preempt.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/preempt.go rename to contrib/go/_std_1.23/src/runtime/preempt.go index 82d85cd70761..839f3875be31 100644 --- a/contrib/go/_std_1.22/src/runtime/preempt.go +++ b/contrib/go/_std_1.23/src/runtime/preempt.go @@ -55,6 +55,7 @@ package runtime import ( "internal/abi" "internal/goarch" + "internal/stringslite" ) type suspendGState struct { @@ -416,16 +417,23 @@ func isAsyncSafePoint(gp *g, pc, sp, lr uintptr) (bool, uintptr) { // Check the inner-most name u, uf := newInlineUnwinder(f, pc) name := u.srcFunc(uf).name() - if hasPrefix(name, "runtime.") || - hasPrefix(name, "runtime/internal/") || - hasPrefix(name, "reflect.") { + if stringslite.HasPrefix(name, "runtime.") || + stringslite.HasPrefix(name, "runtime/internal/") || + stringslite.HasPrefix(name, "internal/runtime/") || + stringslite.HasPrefix(name, "reflect.") { // For now we never async preempt the runtime or // anything closely tied to the runtime. Known issues // include: various points in the scheduler ("don't // preempt between here and here"), much of the defer // implementation (untyped info on stack), bulk write - // barriers (write barrier check), - // reflect.{makeFuncStub,methodValueCall}. + // barriers (write barrier check), atomic functions in + // internal/runtime/atomic, reflect.{makeFuncStub,methodValueCall}. + // + // Note that this is a subset of the runtimePkgs in pkgspecial.go + // and these checks are theoretically redundant because the compiler + // marks "all points" in runtime functions as unsafe for async preemption. + // But for some reason, we can't eliminate these checks until https://go.dev/issue/72031 + // is resolved. // // TODO(austin): We should improve this, or opt things // in incrementally. diff --git a/contrib/go/_std_1.22/src/runtime/preempt_386.s b/contrib/go/_std_1.23/src/runtime/preempt_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_386.s rename to contrib/go/_std_1.23/src/runtime/preempt_386.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_amd64.s b/contrib/go/_std_1.23/src/runtime/preempt_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_amd64.s rename to contrib/go/_std_1.23/src/runtime/preempt_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_arm.s b/contrib/go/_std_1.23/src/runtime/preempt_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_arm.s rename to contrib/go/_std_1.23/src/runtime/preempt_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_arm64.s b/contrib/go/_std_1.23/src/runtime/preempt_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_arm64.s rename to contrib/go/_std_1.23/src/runtime/preempt_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_loong64.s b/contrib/go/_std_1.23/src/runtime/preempt_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_loong64.s rename to contrib/go/_std_1.23/src/runtime/preempt_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_mips64x.s b/contrib/go/_std_1.23/src/runtime/preempt_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_mips64x.s rename to contrib/go/_std_1.23/src/runtime/preempt_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_mipsx.s b/contrib/go/_std_1.23/src/runtime/preempt_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_mipsx.s rename to contrib/go/_std_1.23/src/runtime/preempt_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_nonwindows.go b/contrib/go/_std_1.23/src/runtime/preempt_nonwindows.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_nonwindows.go rename to contrib/go/_std_1.23/src/runtime/preempt_nonwindows.go diff --git a/contrib/go/_std_1.22/src/runtime/preempt_ppc64x.s b/contrib/go/_std_1.23/src/runtime/preempt_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/preempt_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_riscv64.s b/contrib/go/_std_1.23/src/runtime/preempt_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_riscv64.s rename to contrib/go/_std_1.23/src/runtime/preempt_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_s390x.s b/contrib/go/_std_1.23/src/runtime/preempt_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_s390x.s rename to contrib/go/_std_1.23/src/runtime/preempt_s390x.s diff --git a/contrib/go/_std_1.22/src/runtime/preempt_wasm.s b/contrib/go/_std_1.23/src/runtime/preempt_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/preempt_wasm.s rename to contrib/go/_std_1.23/src/runtime/preempt_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/print.go b/contrib/go/_std_1.23/src/runtime/print.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/print.go rename to contrib/go/_std_1.23/src/runtime/print.go diff --git a/contrib/go/_std_1.22/src/runtime/proc.go b/contrib/go/_std_1.23/src/runtime/proc.go similarity index 92% rename from contrib/go/_std_1.22/src/runtime/proc.go rename to contrib/go/_std_1.23/src/runtime/proc.go index 061673150f5d..e3cdf71911be 100644 --- a/contrib/go/_std_1.22/src/runtime/proc.go +++ b/contrib/go/_std_1.23/src/runtime/proc.go @@ -8,9 +8,10 @@ import ( "internal/abi" "internal/cpu" "internal/goarch" - "internal/goexperiment" "internal/goos" - "runtime/internal/atomic" + "internal/runtime/atomic" + "internal/runtime/exithook" + "internal/stringslite" "runtime/internal/sys" "unsafe" ) @@ -167,7 +168,7 @@ func main() { // Allow newproc to start new Ms. mainStarted = true - if GOARCH != "wasm" { // no threads on wasm yet, so no sysmon + if haveSysmon { systemstack(func() { newm(sysmon, nil, -1) }) @@ -309,6 +310,16 @@ func os_beforeExit(exitCode int) { } } +func init() { + exithook.Gosched = Gosched + exithook.Goid = func() uint64 { return getg().goid } + exithook.Throw = throw +} + +func runExitHooks(code int) { + exithook.Run(code) +} + // start forcegc helper goroutine func init() { go forcegchelper() @@ -382,6 +393,17 @@ func goschedIfBusy() { // Reason explains why the goroutine has been parked. It is displayed in stack // traces and heap dumps. Reasons should be unique and descriptive. Do not // re-use reasons, add new ones. +// +// gopark should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// - github.com/sagernet/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname gopark func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason waitReason, traceReason traceBlockReason, traceskip int) { if reason != waitReasonSleep { checkTimeouts() // timeouts may expire while two goroutines keep the scheduler busy @@ -408,6 +430,16 @@ func goparkunlock(lock *mutex, reason waitReason, traceReason traceBlockReason, gopark(parkunlock_c, unsafe.Pointer(lock), reason, traceReason, traceskip) } +// goready should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// - github.com/sagernet/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname goready func goready(gp *g, traceskip int) { systemstack(func() { ready(gp, traceskip, true) @@ -579,7 +611,7 @@ func switchToCrashStack(fn func()) { // Disable crash stack on Windows for now. Apparently, throwing an exception // on a non-system-allocated crash stack causes EXCEPTION_STACK_OVERFLOW and // hangs the process (see issue 63938). -const crashStackImplemented = (GOARCH == "amd64" || GOARCH == "arm64" || GOARCH == "mips64" || GOARCH == "mips64le" || GOARCH == "ppc64" || GOARCH == "ppc64le" || GOARCH == "riscv64" || GOARCH == "wasm") && GOOS != "windows" +const crashStackImplemented = GOOS != "windows" //go:noescape func switchToCrashStack0(fn func()) // in assembly @@ -730,7 +762,7 @@ func getGodebugEarly() string { p := argv_index(argv, argc+1+i) s := unsafe.String(p, findnull(p)) - if hasPrefix(s, prefix) { + if stringslite.HasPrefix(s, prefix) { env = gostring(p)[len(prefix):] break } @@ -775,6 +807,7 @@ func schedinit() { } sched.maxmcount = 10000 + crashFD.Store(^uintptr(0)) // The world starts stopped. worldStopped() @@ -784,10 +817,9 @@ func schedinit() { stackinit() mallocinit() godebug := getGodebugEarly() - initPageTrace(godebug) // must run after mallocinit but before anything allocates - cpuinit(godebug) // must run before alginit - randinit() // must run before alginit, mcommoninit - alginit() // maps, hash, rand must not be used before this call + cpuinit(godebug) // must run before alginit + randinit() // must run before alginit, mcommoninit + alginit() // maps, hash, rand must not be used before this call mcommoninit(gp.m, -1) modulesinit() // provides activeModules typelinksinit() // uses maps, activeModules @@ -818,6 +850,9 @@ func schedinit() { MemProfileRate = 0 } + // mcommoninit runs before parsedebugvars, so init profstacks again. + mProfStackInit(gp.m) + lock(&sched.lock) sched.lastpoll.Store(nanotime()) procs := ncpu @@ -922,8 +957,43 @@ func mcommoninit(mp *m, id int64) { if iscgo || GOOS == "solaris" || GOOS == "illumos" || GOOS == "windows" { mp.cgoCallers = new(cgoCallers) } + mProfStackInit(mp) +} + +// mProfStackInit is used to eagerly initialize stack trace buffers for +// profiling. Lazy allocation would have to deal with reentrancy issues in +// malloc and runtime locks for mLockProfile. +// TODO(mknyszek): Implement lazy allocation if this becomes a problem. +func mProfStackInit(mp *m) { + if debug.profstackdepth == 0 { + // debug.profstack is set to 0 by the user, or we're being called from + // schedinit before parsedebugvars. + return + } + mp.profStack = makeProfStackFP() + mp.mLockProfile.stack = makeProfStackFP() } +// makeProfStackFP creates a buffer large enough to hold a maximum-sized stack +// trace as well as any additional frames needed for frame pointer unwinding +// with delayed inline expansion. +func makeProfStackFP() []uintptr { + // The "1" term is to account for the first stack entry being + // taken up by a "skip" sentinel value for profilers which + // defer inline frame expansion until the profile is reported. + // The "maxSkip" term is for frame pointer unwinding, where we + // want to end up with debug.profstackdebth frames but will discard + // some "physical" frames to account for skipping. + return make([]uintptr, 1+maxSkip+debug.profstackdepth) +} + +// makeProfStack returns a buffer large enough to hold a maximum-sized stack +// trace. +func makeProfStack() []uintptr { return make([]uintptr, debug.profstackdepth) } + +//go:linkname pprof_makeProfStack +func pprof_makeProfStack() []uintptr { return makeProfStack() } + func (mp *m) becomeSpinning() { mp.spinning = true sched.nmspinning.Add(1) @@ -1067,7 +1137,7 @@ func casfrom_Gscanstatus(gp *g, oldval, newval uint32) { dumpgstatus(gp) throw("casfrom_Gscanstatus: gp->status is not in scan state") } - releaseLockRank(lockRankGscan) + releaseLockRankAndM(lockRankGscan) } // This will return false if the gp is not in the expected status and the cas fails. @@ -1081,7 +1151,7 @@ func castogscanstatus(gp *g, oldval, newval uint32) bool { if newval == oldval|_Gscan { r := gp.atomicstatus.CompareAndSwap(oldval, newval) if r { - acquireLockRank(lockRankGscan) + acquireLockRankAndM(lockRankGscan) } return r @@ -1105,13 +1175,14 @@ var casgstatusAlwaysTrack = false func casgstatus(gp *g, oldval, newval uint32) { if (oldval&_Gscan != 0) || (newval&_Gscan != 0) || oldval == newval { systemstack(func() { + // Call on the systemstack to prevent print and throw from counting + // against the nosplit stack reservation. print("runtime: casgstatus: oldval=", hex(oldval), " newval=", hex(newval), "\n") throw("casgstatus: bad incoming values") }) } - acquireLockRank(lockRankGscan) - releaseLockRank(lockRankGscan) + lockWithRankMayAcquire(nil, lockRankGscan) // See https://golang.org/cl/21503 for justification of the yield delay. const yieldDelay = 5 * 1000 @@ -1121,7 +1192,11 @@ func casgstatus(gp *g, oldval, newval uint32) { // GC time to finish and change the state to oldval. for i := 0; !gp.atomicstatus.CompareAndSwap(oldval, newval); i++ { if oldval == _Gwaiting && gp.atomicstatus.Load() == _Grunnable { - throw("casgstatus: waiting for Gwaiting but is Grunnable") + systemstack(func() { + // Call on the systemstack to prevent throw from counting + // against the nosplit stack reservation. + throw("casgstatus: waiting for Gwaiting but is Grunnable") + }) } if i == 0 { nextYield = nanotime() + yieldDelay @@ -1207,6 +1282,17 @@ func casGToWaiting(gp *g, old uint32, reason waitReason) { casgstatus(gp, old, _Gwaiting) } +// casGToWaitingForGC transitions gp from old to _Gwaiting, and sets the wait reason. +// The wait reason must be a valid isWaitingForGC wait reason. +// +// Use this over casgstatus when possible to ensure that a waitreason is set. +func casGToWaitingForGC(gp *g, old uint32, reason waitReason) { + if !reason.isWaitingForGC() { + throw("casGToWaitingForGC with non-isWaitingForGC wait reason") + } + casGToWaiting(gp, old, reason) +} + // casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable. // Returns old status. Cannot call casgstatus directly, because we are racing with an // async wakeup that might come in from netpoll. If we see Gwaiting from the readgstatus, @@ -1234,7 +1320,7 @@ func casGToPreemptScan(gp *g, old, new uint32) { if old != _Grunning || new != _Gscan|_Gpreempted { throw("bad g transition") } - acquireLockRank(lockRankGscan) + acquireLockRankAndM(lockRankGscan) for !gp.atomicstatus.CompareAndSwap(_Grunning, _Gscan|_Gpreempted) { } } @@ -1310,8 +1396,10 @@ var stwReasonStrings = [...]string{ // worldStop provides context from the stop-the-world required by the // start-the-world. type worldStop struct { - reason stwReason - start int64 + reason stwReason + startedStopping int64 + finishedStopping int64 + stoppingCPUTime int64 } // Temporary variable for stopTheWorld, when it can't write to the stack. @@ -1355,7 +1443,7 @@ func stopTheWorld(reason stwReason) worldStop { // N.B. The execution tracer is not aware of this status // transition and handles it specially based on the // wait reason. - casGToWaiting(gp, _Grunning, waitReasonStoppingTheWorld) + casGToWaitingForGC(gp, _Grunning, waitReasonStoppingTheWorld) stopTheWorldContext = stopTheWorldWithSema(reason) // avoid write to stack casgstatus(gp, _Gwaiting, _Grunning) }) @@ -1467,6 +1555,7 @@ func stopTheWorldWithSema(reason stwReason) worldStop { preemptall() // stop current P gp.m.p.ptr().status = _Pgcstop // Pgcstop is only diagnostic. + gp.m.p.ptr().gcStopTime = start sched.stopwait-- // try to retake all P's in Psyscall status trace = traceAcquire() @@ -1474,10 +1563,10 @@ func stopTheWorldWithSema(reason stwReason) worldStop { s := pp.status if s == _Psyscall && atomic.Cas(&pp.status, s, _Pgcstop) { if trace.ok() { - trace.GoSysBlock(pp) trace.ProcSteal(pp, false) } pp.syscalltick++ + pp.gcStopTime = nanotime() sched.stopwait-- } } @@ -1493,6 +1582,7 @@ func stopTheWorldWithSema(reason stwReason) worldStop { break } pp.status = _Pgcstop + pp.gcStopTime = nanotime() sched.stopwait-- } wait := sched.stopwait > 0 @@ -1510,14 +1600,19 @@ func stopTheWorldWithSema(reason stwReason) worldStop { } } - startTime := nanotime() - start + finish := nanotime() + startTime := finish - start if reason.isGC() { sched.stwStoppingTimeGC.record(startTime) } else { sched.stwStoppingTimeOther.record(startTime) } - // sanity checks + // Double-check we actually stopped everything, and all the invariants hold. + // Also accumulate all the time spent by each P in _Pgcstop up to the point + // where everything was stopped. This will be accumulated into the total pause + // CPU time by the caller. + stoppingCPUTime := int64(0) bad := "" if sched.stopwait != 0 { bad = "stopTheWorld: not stopped (stopwait != 0)" @@ -1526,6 +1621,11 @@ func stopTheWorldWithSema(reason stwReason) worldStop { if pp.status != _Pgcstop { bad = "stopTheWorld: not stopped (status != _Pgcstop)" } + if pp.gcStopTime == 0 && bad == "" { + bad = "stopTheWorld: broken CPU time accounting" + } + stoppingCPUTime += finish - pp.gcStopTime + pp.gcStopTime = 0 } } if freezing.Load() { @@ -1542,7 +1642,12 @@ func stopTheWorldWithSema(reason stwReason) worldStop { worldStopped() - return worldStop{reason: reason, start: start} + return worldStop{ + reason: reason, + startedStopping: start, + finishedStopping: finish, + stoppingCPUTime: stoppingCPUTime, + } } // reason is the same STW reason passed to stopTheWorld. start is the start @@ -1598,7 +1703,7 @@ func startTheWorldWithSema(now int64, w worldStop) int64 { if now == 0 { now = nanotime() } - totalTime := now - w.start + totalTime := now - w.startedStopping if w.reason.isGC() { sched.stwTotalTimeGC.record(totalTime) } else { @@ -1902,7 +2007,7 @@ func forEachP(reason waitReason, fn func(*p)) { // N.B. The execution tracer is not aware of this status // transition and handles it specially based on the // wait reason. - casGToWaiting(gp, _Grunning, reason) + casGToWaitingForGC(gp, _Grunning, reason) forEachPInternal(fn) casgstatus(gp, _Gwaiting, _Grunning) }) @@ -1966,7 +2071,6 @@ func forEachPInternal(fn func(*p)) { if s == _Psyscall && p2.runSafePointFn == 1 && atomic.Cas(&p2.status, s, _Pidle) { if trace.ok() { // It's important that we traceRelease before we call handoffp, which may also traceAcquire. - trace.GoSysBlock(p2) trace.ProcSteal(p2, false) traceRelease(trace) } @@ -2227,12 +2331,12 @@ func needm(signal bool) { minit() // Emit a trace event for this dead -> syscall transition, - // but only in the new tracer and only if we're not in a signal handler. + // but only if we're not in a signal handler. // // N.B. the tracer can run on a bare M just fine, we just have // to make sure to do this before setg(nil) and unminit. var trace traceLocker - if goexperiment.ExecTracer2 && !signal { + if !signal { trace = traceAcquire() } @@ -2240,7 +2344,7 @@ func needm(signal bool) { casgstatus(mp.curg, _Gdead, _Gsyscall) sched.ngsys.Add(-1) - if goexperiment.ExecTracer2 && !signal { + if !signal { if trace.ok() { trace.GoCreateSyscall(mp.curg) traceRelease(trace) @@ -2309,11 +2413,6 @@ func oneNewExtraM() { if raceenabled { gp.racectx = racegostart(abi.FuncPCABIInternal(newextram) + sys.PCQuantum) } - trace := traceAcquire() - if trace.ok() { - trace.OneNewExtraM(gp) - traceRelease(trace) - } // put on allg for garbage collector allgadd(gp) @@ -2366,13 +2465,12 @@ func dropm() { // with no pointer manipulation. mp := getg().m - // Emit a trace event for this syscall -> dead transition, - // but only in the new tracer. + // Emit a trace event for this syscall -> dead transition. // // N.B. the tracer can run on a bare M just fine, we just have // to make sure to do this before setg(nil) and unminit. var trace traceLocker - if goexperiment.ExecTracer2 && !mp.isExtraInSig { + if !mp.isExtraInSig { trace = traceAcquire() } @@ -2381,29 +2479,27 @@ func dropm() { mp.curg.preemptStop = false sched.ngsys.Add(1) - if goexperiment.ExecTracer2 && !mp.isExtraInSig { + if !mp.isExtraInSig { if trace.ok() { trace.GoDestroySyscall() traceRelease(trace) } } - if goexperiment.ExecTracer2 { - // Trash syscalltick so that it doesn't line up with mp.old.syscalltick anymore. - // - // In the new tracer, we model needm and dropm and a goroutine being created and - // destroyed respectively. The m then might get reused with a different procid but - // still with a reference to oldp, and still with the same syscalltick. The next - // time a G is "created" in needm, it'll return and quietly reacquire its P from a - // different m with a different procid, which will confuse the trace parser. By - // trashing syscalltick, we ensure that it'll appear as if we lost the P to the - // tracer parser and that we just reacquired it. - // - // Trash the value by decrementing because that gets us as far away from the value - // the syscall exit code expects as possible. Setting to zero is risky because - // syscalltick could already be zero (and in fact, is initialized to zero). - mp.syscalltick-- - } + // Trash syscalltick so that it doesn't line up with mp.old.syscalltick anymore. + // + // In the new tracer, we model needm and dropm and a goroutine being created and + // destroyed respectively. The m then might get reused with a different procid but + // still with a reference to oldp, and still with the same syscalltick. The next + // time a G is "created" in needm, it'll return and quietly reacquire its P from a + // different m with a different procid, which will confuse the trace parser. By + // trashing syscalltick, we ensure that it'll appear as if we lost the P to the + // tracer parser and that we just reacquired it. + // + // Trash the value by decrementing because that gets us as far away from the value + // the syscall exit code expects as possible. Setting to zero is risky because + // syscalltick could already be zero (and in fact, is initialized to zero). + mp.syscalltick-- // Reset trace state unconditionally. This goroutine is being 'destroyed' // from the perspective of the tracer. @@ -2412,10 +2508,7 @@ func dropm() { // Flush all the M's buffers. This is necessary because the M might // be used on a different thread with a different procid, so we have // to make sure we don't write into the same buffer. - // - // N.B. traceThreadDestroy is a no-op in the old tracer, so avoid the - // unnecessary acquire/release of the lock. - if goexperiment.ExecTracer2 && (traceEnabled() || traceShuttingDown()) { + if traceEnabled() || traceShuttingDown() { // Acquire sched.lock across thread destruction. One of the invariants of the tracer // is that a thread cannot disappear from the tracer's view (allm or freem) without // it noticing, so it requires that sched.lock be held over traceThreadDestroy. @@ -2446,6 +2539,7 @@ func dropm() { g0.stack.lo = 0 g0.stackguard0 = 0 g0.stackguard1 = 0 + mp.g0StackAccurate = false putExtraM(mp) @@ -2486,6 +2580,16 @@ func cgoBindM() { } // A helper function for EnsureDropM. +// +// getm should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - fortio.org/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname getm func getm() uintptr { return uintptr(unsafe.Pointer(getg().m)) } @@ -2931,6 +3035,7 @@ func handoffp(pp *p) { lock(&sched.lock) if sched.gcwaiting.Load() { pp.status = _Pgcstop + pp.gcStopTime = nanotime() sched.stopwait-- if sched.stopwait == 0 { notewakeup(&sched.stopnote) @@ -2960,7 +3065,7 @@ func handoffp(pp *p) { // The scheduler lock cannot be held when calling wakeNetPoller below // because wakeNetPoller may call wakep which may call startm. - when := nobarrierWakeTime(pp) + when := pp.timers.wakeTime() pidleput(pp, 0) unlock(&sched.lock) @@ -2972,6 +3077,16 @@ func handoffp(pp *p) { // Tries to add one more P to execute G's. // Called when a G is made runnable (newproc, ready). // Must be called with a P. +// +// wakep should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname wakep func wakep() { // Be conservative about spinning threads, only start one if none exist // already. @@ -3073,6 +3188,7 @@ func gcstopm() { pp := releasep() lock(&sched.lock) pp.status = _Pgcstop + pp.gcStopTime = nanotime() sched.stopwait-- if sched.stopwait == 0 { notewakeup(&sched.stopnote) @@ -3097,7 +3213,7 @@ func execute(gp *g, inheritTime bool) { // Make sure that gp has had its stack written out to the goroutine // profile, exactly as it was when the goroutine profiler first stopped // the world. - tryRecordGoroutineProfile(gp, osyield) + tryRecordGoroutineProfile(gp, nil, osyield) } // Assign gp.m before entering _Grunning so running Gs have an @@ -3120,11 +3236,6 @@ func execute(gp *g, inheritTime bool) { trace := traceAcquire() if trace.ok() { - // GoSysExit has to happen when we have a P, but before GoStart. - // So we emit it here. - if !goexperiment.ExecTracer2 && gp.syscallsp != 0 { - trace.GoSysExit(true) - } trace.GoStart() traceRelease(trace) } @@ -3157,7 +3268,7 @@ top: // which may steal timers. It's important that between now // and then, nothing blocks, so these numbers remain mostly // relevant. - now, pollUntil, _ := checkTimers(pp, 0) + now, pollUntil, _ := pp.timers.check(0) // Try to schedule the trace reader. if traceEnabled() || traceShuttingDown() { @@ -3574,7 +3685,7 @@ func stealWork(now int64) (gp *g, inheritTime bool, rnow, pollUntil int64, newWo // timerpMask tells us whether the P may have timers at all. If it // can't, no need to check at all. if stealTimersOrRunNextG && timerpMask.read(enum.position()) { - tnow, w, ran := checkTimers(p2, now) + tnow, w, ran := p2.timers.check(now) now = tnow if w != 0 && (pollUntil == 0 || w < pollUntil) { pollUntil = w @@ -3640,7 +3751,7 @@ func checkRunqsNoP(allpSnapshot []*p, idlepMaskSnapshot pMask) *p { func checkTimersNoP(allpSnapshot []*p, timerpMaskSnapshot pMask, pollUntil int64) int64 { for id, p2 := range allpSnapshot { if timerpMaskSnapshot.read(uint32(id)) { - w := nobarrierWakeTime(p2) + w := p2.timers.wakeTime() if w != 0 && (pollUntil == 0 || w < pollUntil) { pollUntil = w } @@ -3762,23 +3873,23 @@ func injectglist(glist *gList) { if glist.empty() { return } - trace := traceAcquire() - if trace.ok() { - for gp := glist.head.ptr(); gp != nil; gp = gp.schedlink.ptr() { - trace.GoUnpark(gp, 0) - } - traceRelease(trace) - } // Mark all the goroutines as runnable before we put them // on the run queues. head := glist.head.ptr() var tail *g qsize := 0 + trace := traceAcquire() for gp := head; gp != nil; gp = gp.schedlink.ptr() { tail = gp qsize++ casgstatus(gp, _Gwaiting, _Grunnable) + if trace.ok() { + trace.GoUnpark(gp, 0) + } + } + if trace.ok() { + traceRelease(trace) } // Turn the gList into a gQueue. @@ -3815,8 +3926,10 @@ func injectglist(glist *gList) { } npidle := int(sched.npidle.Load()) - var globq gQueue - var n int + var ( + globq gQueue + n int + ) for n = 0; n < npidle && !q.empty(); n++ { g := q.pop() globq.pushBack(g) @@ -3832,6 +3945,21 @@ func injectglist(glist *gList) { if !q.empty() { runqputbatch(pp, &q, qsize) } + + // Some P's might have become idle after we loaded `sched.npidle` + // but before any goroutines were added to the queue, which could + // lead to idle P's when there is work available in the global queue. + // That could potentially last until other goroutines become ready + // to run. That said, we need to find a way to hedge + // + // Calling wakep() here is the best bet, it will do nothing in the + // common case (no racing on `sched.npidle`), while it could wake one + // more P to execute G's, which might end up with >1 P's: the first one + // wakes another P and so forth until there is no more work, but this + // ought to be an extremely rare case. + // + // Also see "Worker thread parking/unparking" comment at the top of the file for details. + wakep() } // One round of scheduler: find a runnable goroutine and execute it. @@ -3932,72 +4060,6 @@ func dropg() { setGNoWB(&gp.m.curg, nil) } -// checkTimers runs any timers for the P that are ready. -// If now is not 0 it is the current time. -// It returns the passed time or the current time if now was passed as 0. -// and the time when the next timer should run or 0 if there is no next timer, -// and reports whether it ran any timers. -// If the time when the next timer should run is not 0, -// it is always larger than the returned time. -// We pass now in and out to avoid extra calls of nanotime. -// -//go:yeswritebarrierrec -func checkTimers(pp *p, now int64) (rnow, pollUntil int64, ran bool) { - // If it's not yet time for the first timer, or the first adjusted - // timer, then there is nothing to do. - next := pp.timer0When.Load() - nextAdj := pp.timerModifiedEarliest.Load() - if next == 0 || (nextAdj != 0 && nextAdj < next) { - next = nextAdj - } - - if next == 0 { - // No timers to run or adjust. - return now, 0, false - } - - if now == 0 { - now = nanotime() - } - if now < next { - // Next timer is not ready to run, but keep going - // if we would clear deleted timers. - // This corresponds to the condition below where - // we decide whether to call clearDeletedTimers. - if pp != getg().m.p.ptr() || int(pp.deletedTimers.Load()) <= int(pp.numTimers.Load()/4) { - return now, next, false - } - } - - lock(&pp.timersLock) - - if len(pp.timers) > 0 { - adjusttimers(pp, now) - for len(pp.timers) > 0 { - // Note that runtimer may temporarily unlock - // pp.timersLock. - if tw := runtimer(pp, now); tw != 0 { - if tw > 0 { - pollUntil = tw - } - break - } - ran = true - } - } - - // If this is the local P, and there are a lot of deleted timers, - // clear them out. We only do this for the local P to reduce - // lock contention on timersLock. - if pp == getg().m.p.ptr() && int(pp.deletedTimers.Load()) > len(pp.timers)/4 { - clearDeletedTimers(pp) - } - - unlock(&pp.timersLock) - - return now, pollUntil, ran -} - func parkunlock_c(gp *g, lock unsafe.Pointer) bool { unlock((*mutex)(lock)) return true @@ -4009,11 +4071,16 @@ func park_m(gp *g) { trace := traceAcquire() + if trace.ok() { + // Trace the event before the transition. It may take a + // stack trace, but we won't own the stack after the + // transition anymore. + trace.GoPark(mp.waitTraceBlockReason, mp.waitTraceSkip) + } // N.B. Not using casGToWaiting here because the waitreason is // set by park_m's caller. casgstatus(gp, _Grunning, _Gwaiting) if trace.ok() { - trace.GoPark(mp.waitTraceBlockReason, mp.waitTraceSkip) traceRelease(trace) } @@ -4043,13 +4110,18 @@ func goschedImpl(gp *g, preempted bool) { dumpgstatus(gp) throw("bad g status") } - casgstatus(gp, _Grunning, _Grunnable) if trace.ok() { + // Trace the event before the transition. It may take a + // stack trace, but we won't own the stack after the + // transition anymore. if preempted { trace.GoPreempt() } else { trace.GoSched() } + } + casgstatus(gp, _Grunning, _Grunnable) + if trace.ok() { traceRelease(trace) } @@ -4144,6 +4216,17 @@ func preemptPark(gp *g) { // goyield is like Gosched, but it: // - emits a GoPreempt trace event instead of a GoSched trace event // - puts the current G on the runq of the current P instead of the globrunq +// +// goyield should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// - github.com/sagernet/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname goyield func goyield() { checkTimeouts() mcall(goyield_m) @@ -4152,9 +4235,14 @@ func goyield() { func goyield_m(gp *g) { trace := traceAcquire() pp := gp.m.p.ptr() - casgstatus(gp, _Grunning, _Grunnable) if trace.ok() { + // Trace the event before the transition. It may take a + // stack trace, but we won't own the stack after the + // transition anymore. trace.GoPreempt() + } + casgstatus(gp, _Grunning, _Grunnable) + if trace.ok() { traceRelease(trace) } dropg() @@ -4221,9 +4309,9 @@ func gdestroy(gp *g) { return } - if mp.lockedInt != 0 { - print("invalid m->lockedInt = ", mp.lockedInt, "\n") - throw("internal lockOSThread error") + if locked && mp.lockedInt != 0 { + print("runtime: mp.lockedInt = ", mp.lockedInt, "\n") + throw("exited a goroutine internally locked to the OS thread") } gfput(pp, gp) if locked { @@ -4251,7 +4339,7 @@ func gdestroy(gp *g) { // //go:nosplit //go:nowritebarrierrec -func save(pc, sp uintptr) { +func save(pc, sp, bp uintptr) { gp := getg() if gp == gp.m.g0 || gp == gp.m.gsignal { @@ -4267,6 +4355,7 @@ func save(pc, sp uintptr) { gp.sched.sp = sp gp.sched.lr = 0 gp.sched.ret = 0 + gp.sched.bp = bp // We need to ensure ctxt is zero, but can't have a write // barrier here. However, it should always already be zero. // Assert that. @@ -4298,21 +4387,8 @@ func save(pc, sp uintptr) { // must always point to a valid stack frame. entersyscall below is the normal // entry point for syscalls, which obtains the SP and PC from the caller. // -// Syscall tracing (old tracer): -// At the start of a syscall we emit traceGoSysCall to capture the stack trace. -// If the syscall does not block, that is it, we do not emit any other events. -// If the syscall blocks (that is, P is retaken), retaker emits traceGoSysBlock; -// when syscall returns we emit traceGoSysExit and when the goroutine starts running -// (potentially instantly, if exitsyscallfast returns true) we emit traceGoStart. -// To ensure that traceGoSysExit is emitted strictly after traceGoSysBlock, -// we remember current value of syscalltick in m (gp.m.syscalltick = gp.m.p.ptr().syscalltick), -// whoever emits traceGoSysBlock increments p.syscalltick afterwards; -// and we wait for the increment before emitting traceGoSysExit. -// Note that the increment is done even if tracing is not enabled, -// because tracing can be enabled in the middle of syscall. We don't want the wait to hang. -// //go:nosplit -func reentersyscall(pc, sp uintptr) { +func reentersyscall(pc, sp, bp uintptr) { trace := traceAcquire() gp := getg() @@ -4328,18 +4404,25 @@ func reentersyscall(pc, sp uintptr) { gp.throwsplit = true // Leave SP around for GC and traceback. - save(pc, sp) + save(pc, sp, bp) gp.syscallsp = sp gp.syscallpc = pc + gp.syscallbp = bp casgstatus(gp, _Grunning, _Gsyscall) if staticLockRanking { // When doing static lock ranking casgstatus can call // systemstack which clobbers g.sched. - save(pc, sp) + save(pc, sp, bp) } if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp { systemstack(func() { - print("entersyscall inconsistent ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") + print("entersyscall inconsistent sp ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") + throw("entersyscall") + }) + } + if gp.syscallbp != 0 && gp.syscallbp < gp.stack.lo || gp.stack.hi < gp.syscallbp { + systemstack(func() { + print("entersyscall inconsistent bp ", hex(gp.syscallbp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") throw("entersyscall") }) } @@ -4352,18 +4435,18 @@ func reentersyscall(pc, sp uintptr) { // systemstack itself clobbers g.sched.{pc,sp} and we might // need them later when the G is genuinely blocked in a // syscall - save(pc, sp) + save(pc, sp, bp) } if sched.sysmonwait.Load() { systemstack(entersyscall_sysmon) - save(pc, sp) + save(pc, sp, bp) } if gp.m.p.ptr().runSafePointFn != 0 { // runSafePointFn may stack split if run on this stack systemstack(runSafePointFn) - save(pc, sp) + save(pc, sp, bp) } gp.m.syscalltick = gp.m.p.ptr().syscalltick @@ -4374,7 +4457,7 @@ func reentersyscall(pc, sp uintptr) { atomic.Store(&pp.status, _Psyscall) if sched.gcwaiting.Load() { systemstack(entersyscall_gcwait) - save(pc, sp) + save(pc, sp, bp) } gp.m.locks-- @@ -4384,10 +4467,23 @@ func reentersyscall(pc, sp uintptr) { // // This is exported via linkname to assembly in the syscall package and x/sys. // +// Other packages should not be accessing entersyscall directly, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:nosplit //go:linkname entersyscall func entersyscall() { - reentersyscall(getcallerpc(), getcallersp()) + // N.B. getcallerfp cannot be written directly as argument in the call + // to reentersyscall because it forces spilling the other arguments to + // the stack. This results in exceeding the nosplit stack requirements + // on some platforms. + fp := getcallerfp() + reentersyscall(getcallerpc(), getcallersp(), fp) } func entersyscall_sysmon() { @@ -4407,23 +4503,19 @@ func entersyscall_gcwait() { trace := traceAcquire() if sched.stopwait > 0 && atomic.Cas(&pp.status, _Psyscall, _Pgcstop) { if trace.ok() { - if goexperiment.ExecTracer2 { - // This is a steal in the new tracer. While it's very likely - // that we were the ones to put this P into _Psyscall, between - // then and now it's totally possible it had been stolen and - // then put back into _Psyscall for us to acquire here. In such - // case ProcStop would be incorrect. - // - // TODO(mknyszek): Consider emitting a ProcStop instead when - // gp.m.syscalltick == pp.syscalltick, since then we know we never - // lost the P. - trace.ProcSteal(pp, true) - } else { - trace.GoSysBlock(pp) - trace.ProcStop(pp) - } + // This is a steal in the new tracer. While it's very likely + // that we were the ones to put this P into _Psyscall, between + // then and now it's totally possible it had been stolen and + // then put back into _Psyscall for us to acquire here. In such + // case ProcStop would be incorrect. + // + // TODO(mknyszek): Consider emitting a ProcStop instead when + // gp.m.syscalltick == pp.syscalltick, since then we know we never + // lost the P. + trace.ProcSteal(pp, true) traceRelease(trace) } + pp.gcStopTime = nanotime() pp.syscalltick++ if sched.stopwait--; sched.stopwait == 0 { notewakeup(&sched.stopnote) @@ -4435,7 +4527,16 @@ func entersyscall_gcwait() { } // The same as entersyscall(), but with a hint that the syscall is blocking. + +// entersyscallblock should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. // +//go:linkname entersyscallblock //go:nosplit func entersyscallblock() { gp := getg() @@ -4449,22 +4550,30 @@ func entersyscallblock() { // Leave SP around for GC and traceback. pc := getcallerpc() sp := getcallersp() - save(pc, sp) + bp := getcallerfp() + save(pc, sp, bp) gp.syscallsp = gp.sched.sp gp.syscallpc = gp.sched.pc + gp.syscallbp = gp.sched.bp if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp { sp1 := sp sp2 := gp.sched.sp sp3 := gp.syscallsp systemstack(func() { - print("entersyscallblock inconsistent ", hex(sp1), " ", hex(sp2), " ", hex(sp3), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") + print("entersyscallblock inconsistent sp ", hex(sp1), " ", hex(sp2), " ", hex(sp3), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") throw("entersyscallblock") }) } casgstatus(gp, _Grunning, _Gsyscall) if gp.syscallsp < gp.stack.lo || gp.stack.hi < gp.syscallsp { systemstack(func() { - print("entersyscallblock inconsistent ", hex(sp), " ", hex(gp.sched.sp), " ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") + print("entersyscallblock inconsistent sp ", hex(sp), " ", hex(gp.sched.sp), " ", hex(gp.syscallsp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") + throw("entersyscallblock") + }) + } + if gp.syscallbp != 0 && gp.syscallbp < gp.stack.lo || gp.stack.hi < gp.syscallbp { + systemstack(func() { + print("entersyscallblock inconsistent bp ", hex(bp), " ", hex(gp.sched.bp), " ", hex(gp.syscallbp), " [", hex(gp.stack.lo), ",", hex(gp.stack.hi), "]\n") throw("entersyscallblock") }) } @@ -4472,7 +4581,7 @@ func entersyscallblock() { systemstack(entersyscallblock_handoff) // Resave for traceback during blocked call. - save(getcallerpc(), getcallersp()) + save(getcallerpc(), getcallersp(), getcallerfp()) gp.m.locks-- } @@ -4481,7 +4590,6 @@ func entersyscallblock_handoff() { trace := traceAcquire() if trace.ok() { trace.GoSysCall() - trace.GoSysBlock(getg().m.p.ptr()) traceRelease(trace) } handoffp(releasep()) @@ -4496,6 +4604,14 @@ func entersyscallblock_handoff() { // // This is exported via linkname to assembly in the syscall package. // +// exitsyscall should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:nosplit //go:nowritebarrierrec //go:linkname exitsyscall @@ -4525,13 +4641,11 @@ func exitsyscall() { if trace.ok() { lostP := oldp != gp.m.p.ptr() || gp.m.syscalltick != gp.m.p.ptr().syscalltick systemstack(func() { - if goexperiment.ExecTracer2 { - // Write out syscall exit eagerly in the experiment. - // - // It's important that we write this *after* we know whether we - // lost our P or not (determined by exitsyscallfast). - trace.GoSysExit(lostP) - } + // Write out syscall exit eagerly. + // + // It's important that we write this *after* we know whether we + // lost our P or not (determined by exitsyscallfast). + trace.GoSysExit(lostP) if lostP { // We lost the P at some point, even though we got it back here. // Trace that we're starting again, because there was a traceGoSysBlock @@ -4570,17 +4684,6 @@ func exitsyscall() { return } - if !goexperiment.ExecTracer2 { - // In the old tracer, because we don't have a P we can't - // actually record the true time we exited the syscall. - // Record it. - trace := traceAcquire() - if trace.ok() { - trace.RecordSyscallExitedTime(gp, oldp) - traceRelease(trace) - } - } - gp.m.locks-- // Call the scheduler. @@ -4599,8 +4702,6 @@ func exitsyscall() { //go:nosplit func exitsyscallfast(oldp *p) bool { - gp := getg() - // Freezetheworld sets stopwait but does not retake P's. if sched.stopwait == freezeStopWait { return false @@ -4626,22 +4727,6 @@ func exitsyscallfast(oldp *p) bool { var ok bool systemstack(func() { ok = exitsyscallfast_pidle() - if ok && !goexperiment.ExecTracer2 { - trace := traceAcquire() - if trace.ok() { - if oldp != nil { - // Wait till traceGoSysBlock event is emitted. - // This ensures consistency of the trace (the goroutine is started after it is blocked). - for oldp.syscalltick == gp.m.syscalltick { - osyield() - } - } - // In the experiment, we write this in exitsyscall. - // Don't write it here unless the experiment is off. - trace.GoSysExit(true) - traceRelease(trace) - } - } }) if ok { return true @@ -4663,17 +4748,10 @@ func exitsyscallfast_reacquired(trace traceLocker) { // traceGoSysBlock for this syscall was already emitted, // but here we effectively retake the p from the new syscall running on the same p. systemstack(func() { - if goexperiment.ExecTracer2 { - // In the experiment, we're stealing the P. It's treated - // as if it temporarily stopped running. Then, start running. - trace.ProcSteal(gp.m.p.ptr(), true) - trace.ProcStart() - } else { - // Denote blocking of the new syscall. - trace.GoSysBlock(gp.m.p.ptr()) - // Denote completion of the current syscall. - trace.GoSysExit(true) - } + // We're stealing the P. It's treated + // as if it temporarily stopped running. Then, start running. + trace.ProcSteal(gp.m.p.ptr(), true) + trace.ProcStart() }) } gp.m.p.ptr().syscalltick++ @@ -4703,21 +4781,17 @@ func exitsyscallfast_pidle() bool { //go:nowritebarrierrec func exitsyscall0(gp *g) { var trace traceLocker - if goexperiment.ExecTracer2 { - traceExitingSyscall() - trace = traceAcquire() - } + traceExitingSyscall() + trace = traceAcquire() casgstatus(gp, _Gsyscall, _Grunnable) - if goexperiment.ExecTracer2 { - traceExitedSyscall() - if trace.ok() { - // Write out syscall exit eagerly in the experiment. - // - // It's important that we write this *after* we know whether we - // lost our P or not (determined by exitsyscallfast). - trace.GoSysExit(true) - traceRelease(trace) - } + traceExitedSyscall() + if trace.ok() { + // Write out syscall exit eagerly. + // + // It's important that we write this *after* we know whether we + // lost our P or not (determined by exitsyscallfast). + trace.GoSysExit(true) + traceRelease(trace) } dropg() lock(&sched.lock) @@ -4758,6 +4832,15 @@ func exitsyscall0(gp *g) { // Called from syscall package before fork. // +// syscall_runtime_BeforeFork is for package syscall, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/containerd/containerd +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname syscall_runtime_BeforeFork syscall.runtime_BeforeFork //go:nosplit func syscall_runtime_BeforeFork() { @@ -4779,6 +4862,15 @@ func syscall_runtime_BeforeFork() { // Called from syscall package after fork in parent. // +// syscall_runtime_AfterFork is for package syscall, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/containerd/containerd +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname syscall_runtime_AfterFork syscall.runtime_AfterFork //go:nosplit func syscall_runtime_AfterFork() { @@ -4804,6 +4896,15 @@ var inForkedChild bool // temporarily sharing address space with the parent process, this must // not change any global variables or calling into C code that may do so. // +// syscall_runtime_AfterForkInChild is for package syscall, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/containerd/containerd +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname syscall_runtime_AfterForkInChild syscall.runtime_AfterForkInChild //go:nosplit //go:nowritebarrierrec @@ -4875,7 +4976,7 @@ func newproc(fn *funcval) { gp := getg() pc := getcallerpc() systemstack(func() { - newg := newproc1(fn, gp, pc) + newg := newproc1(fn, gp, pc, false, waitReasonZero) pp := getg().m.p.ptr() runqput(pp, newg, true) @@ -4886,10 +4987,10 @@ func newproc(fn *funcval) { }) } -// Create a new g in state _Grunnable, starting at fn. callerpc is the -// address of the go statement that created this. The caller is responsible -// for adding the new g to the scheduler. -func newproc1(fn *funcval, callergp *g, callerpc uintptr) *g { +// Create a new g in state _Grunnable (or _Gwaiting if parked is true), starting at fn. +// callerpc is the address of the go statement that created this. The caller is responsible +// for adding the new g to the scheduler. If parked is true, waitreason must be non-zero. +func newproc1(fn *funcval, callergp *g, callerpc uintptr, parked bool, waitreason waitReason) *g { if fn == nil { fatal("go of nil func value") } @@ -4958,7 +5059,12 @@ func newproc1(fn *funcval, callergp *g, callerpc uintptr) *g { // Get a goid and switch to runnable. Make all this atomic to the tracer. trace := traceAcquire() - casgstatus(newg, _Gdead, _Grunnable) + var status uint32 = _Grunnable + if parked { + status = _Gwaiting + newg.waitreason = waitreason + } + casgstatus(newg, _Gdead, status) if pp.goidcache == pp.goidcacheend { // Sched.goidgen is the last allocated id, // this batch must be [sched.goidgen+1, sched.goidgen+GoidCacheBatch]. @@ -4971,7 +5077,7 @@ func newproc1(fn *funcval, callergp *g, callerpc uintptr) *g { pp.goidcache++ newg.trace.reset() if trace.ok() { - trace.GoCreate(newg, newg.startpc) + trace.GoCreate(newg, newg.startpc, parked) traceRelease(trace) } @@ -5312,22 +5418,22 @@ func sigprof(pc, sp, lr uintptr, gp *g, mp *m) { } // On mips{,le}/arm, 64bit atomics are emulated with spinlocks, in - // runtime/internal/atomic. If SIGPROF arrives while the program is inside + // internal/runtime/atomic. If SIGPROF arrives while the program is inside // the critical section, it creates a deadlock (when writing the sample). // As a workaround, create a counter of SIGPROFs while in critical section // to store the count, and pass it to sigprof.add() later when SIGPROF is // received from somewhere else (with _LostSIGPROFDuringAtomic64 as pc). if GOARCH == "mips" || GOARCH == "mipsle" || GOARCH == "arm" { if f := findfunc(pc); f.valid() { - if hasPrefix(funcname(f), "runtime/internal/atomic") { + if stringslite.HasPrefix(funcname(f), "internal/runtime/atomic") { cpuprof.lostAtomic++ return } } if GOARCH == "arm" && goarm < 7 && GOOS == "linux" && pc&0xffff0000 == 0xffff0000 { - // runtime/internal/atomic functions call into kernel + // internal/runtime/atomic functions call into kernel // helpers on arm < 7. See - // runtime/internal/atomic/sys_linux_arm.s. + // internal/runtime/atomic/sys_linux_arm.s. cpuprof.lostAtomic++ return } @@ -5483,7 +5589,7 @@ func (pp *p) init(id int32) { pp.raceprocctx = raceproccreate() } } - lockInit(&pp.timersLock, lockRankTimers) + lockInit(&pp.timers.mu, lockRankTimers) // This P may get timers when it starts running. Set the mask here // since the P may not go through pidleget (notably P 0 on startup). @@ -5513,22 +5619,10 @@ func (pp *p) destroy() { globrunqputhead(pp.runnext.ptr()) pp.runnext = 0 } - if len(pp.timers) > 0 { - plocal := getg().m.p.ptr() - // The world is stopped, but we acquire timersLock to - // protect against sysmon calling timeSleepUntil. - // This is the only case where we hold the timersLock of - // more than one P, so there are no deadlock concerns. - lock(&plocal.timersLock) - lock(&pp.timersLock) - moveTimers(plocal, pp.timers) - pp.timers = nil - pp.numTimers.Store(0) - pp.deletedTimers.Store(0) - pp.timer0When.Store(0) - unlock(&pp.timersLock) - unlock(&plocal.timersLock) - } + + // Move all timers to the local P. + getg().m.p.ptr().timers.take(&pp.timers) + // Flush p's write barrier buffer. if gcphase != _GCoff { wbBufFlush1(pp) @@ -5556,9 +5650,8 @@ func (pp *p) destroy() { freemcache(pp.mcache) pp.mcache = nil gfpurge(pp) - traceProcFree(pp) if raceenabled { - if pp.timerRaceCtx != 0 { + if pp.timers.raceCtx != 0 { // The race detector code uses a callback to fetch // the proc context, so arrange for that callback // to see the right thing. @@ -5568,8 +5661,8 @@ func (pp *p) destroy() { phold := mp.p.ptr() mp.p.set(pp) - racectxend(pp.timerRaceCtx) - pp.timerRaceCtx = 0 + racectxend(pp.timers.raceCtx) + pp.timers.raceCtx = 0 mp.p.set(phold) } @@ -5668,7 +5761,7 @@ func procresize(nprocs int32) *p { if trace.ok() { // Pretend that we were descheduled // and then scheduled again to keep - // the trace sane. + // the trace consistent. trace.GoSched() trace.ProcStop(gp.m.p.ptr()) traceRelease(trace) @@ -5920,7 +6013,7 @@ func checkdead() { // There are no goroutines running, so we can look at the P's. for _, pp := range allp { - if len(pp.timers) > 0 { + if len(pp.timers.heap) > 0 { return } } @@ -5940,6 +6033,11 @@ var forcegcperiod int64 = 2 * 60 * 1e9 // golang.org/issue/42515 is needed on NetBSD. var needSysmonWorkaround bool = false +// haveSysmon indicates whether there is sysmon thread support. +// +// No threads on wasm yet, so no sysmon. +const haveSysmon = GOARCH != "wasm" + // Always runs without a P, so write barriers are not allowed. // //go:nowritebarrierrec @@ -6092,8 +6190,8 @@ func sysmon() { type sysmontick struct { schedtick uint32 - schedwhen int64 syscalltick uint32 + schedwhen int64 syscallwhen int64 } @@ -6120,7 +6218,10 @@ func retake(now int64) uint32 { s := pp.status sysretake := false if s == _Prunning || s == _Psyscall { - // Preempt G if it's running for too long. + // Preempt G if it's running on the same schedtick for + // too long. This could be from a single long-running + // goroutine or a sequence of goroutines run via + // runnext, which share a single schedtick time slice. t := int64(pp.schedtick) if int64(pd.schedtick) != t { pd.schedtick = uint32(t) @@ -6156,7 +6257,6 @@ func retake(now int64) uint32 { trace := traceAcquire() if atomic.Cas(&pp.status, s, _Pidle) { if trace.ok() { - trace.GoSysBlock(pp) trace.ProcSteal(pp, false) traceRelease(trace) } @@ -6256,7 +6356,7 @@ func schedtrace(detailed bool) { } else { print("nil") } - print(" runqsize=", t-h, " gfreecnt=", pp.gFree.n, " timerslen=", len(pp.timers), "\n") + print(" runqsize=", t-h, " gfreecnt=", pp.gFree.n, " timerslen=", len(pp.timers.heap), "\n") } else { // In non-detailed mode format lengths of per-P run queues as: // [len1 len2 len3 len4] @@ -6478,46 +6578,6 @@ func (p pMask) clear(id int32) { atomic.And(&p[word], ^mask) } -// updateTimerPMask clears pp's timer mask if it has no timers on its heap. -// -// Ideally, the timer mask would be kept immediately consistent on any timer -// operations. Unfortunately, updating a shared global data structure in the -// timer hot path adds too much overhead in applications frequently switching -// between no timers and some timers. -// -// As a compromise, the timer mask is updated only on pidleget / pidleput. A -// running P (returned by pidleget) may add a timer at any time, so its mask -// must be set. An idle P (passed to pidleput) cannot add new timers while -// idle, so if it has no timers at that time, its mask may be cleared. -// -// Thus, we get the following effects on timer-stealing in findrunnable: -// -// - Idle Ps with no timers when they go idle are never checked in findrunnable -// (for work- or timer-stealing; this is the ideal case). -// - Running Ps must always be checked. -// - Idle Ps whose timers are stolen must continue to be checked until they run -// again, even after timer expiration. -// -// When the P starts running again, the mask should be set, as a timer may be -// added at any time. -// -// TODO(prattmic): Additional targeted updates may improve the above cases. -// e.g., updating the mask when stealing a timer. -func updateTimerPMask(pp *p) { - if pp.numTimers.Load() > 0 { - return - } - - // Looks like there are no timers, however another P may transiently - // decrement numTimers when handling a timerModified timer in - // checkTimers. We must take timersLock to serialize with these changes. - lock(&pp.timersLock) - if pp.numTimers.Load() == 0 { - timerpMask.clear(pp.id) - } - unlock(&pp.timersLock) -} - // pidleput puts p on the _Pidle list. now must be a relatively recent call // to nanotime or zero. Returns now or the current time if now was zero. // @@ -6538,7 +6598,9 @@ func pidleput(pp *p, now int64) int64 { if now == 0 { now = nanotime() } - updateTimerPMask(pp) // clear if there are no timers. + if pp.timers.len.Load() == 0 { + timerpMask.clear(pp.id) + } idlepMask.set(pp.id) pp.link = sched.pidle sched.pidle.set(pp) @@ -6633,6 +6695,17 @@ const randomizeScheduler = raceenabled // If the run queue is full, runnext puts g on the global queue. // Executed only by the owner P. func runqput(pp *p, gp *g, next bool) { + if !haveSysmon && next { + // A runnext goroutine shares the same time slice as the + // current goroutine (inheritTime from runqget). To prevent a + // ping-pong pair of goroutines from starving all others, we + // depend on sysmon to preempt "long-running goroutines". That + // is, any set of goroutines sharing the same time slice. + // + // If there is no sysmon, we must avoid runnext entirely or + // risk starvation. + next = false + } if randomizeScheduler && next && randn(2) == 0 { next = false } @@ -6999,6 +7072,17 @@ func setMaxThreads(in int) (out int) { return } +// procPin should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/choleraehyq/pid +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname procPin //go:nosplit func procPin() int { gp := getg() @@ -7008,6 +7092,17 @@ func procPin() int { return int(mp.p.ptr().id) } +// procUnpin should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/choleraehyq/pid +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname procUnpin //go:nosplit func procUnpin() { gp := getg() @@ -7040,6 +7135,16 @@ func sync_atomic_runtime_procUnpin() { // Active spinning for sync.Mutex. // +// sync_runtime_canSpin should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/livekit/protocol +// - github.com/sagernet/gvisor +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname sync_runtime_canSpin sync.runtime_canSpin //go:nosplit func sync_runtime_canSpin(i int) bool { @@ -7057,6 +7162,16 @@ func sync_runtime_canSpin(i int) bool { return true } +// sync_runtime_doSpin should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/livekit/protocol +// - github.com/sagernet/gvisor +// - gvisor.dev/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname sync_runtime_doSpin sync.runtime_doSpin //go:nosplit func sync_runtime_doSpin() { diff --git a/contrib/go/_std_1.22/src/runtime/profbuf.go b/contrib/go/_std_1.23/src/runtime/profbuf.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/profbuf.go rename to contrib/go/_std_1.23/src/runtime/profbuf.go index d3afbcd8c745..8ae626b1b085 100644 --- a/contrib/go/_std_1.22/src/runtime/profbuf.go +++ b/contrib/go/_std_1.23/src/runtime/profbuf.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -367,10 +367,8 @@ func (b *profBuf) write(tagPtr *unsafe.Pointer, now int64, hdr []uint64, stk []u data[0] = uint64(2 + b.hdrsize + uintptr(len(stk))) // length data[1] = uint64(now) // time stamp // header, zero-padded - i := uintptr(copy(data[2:2+b.hdrsize], hdr)) - for ; i < b.hdrsize; i++ { - data[2+i] = 0 - } + i := copy(data[2:2+b.hdrsize], hdr) + clear(data[2+i : 2+b.hdrsize]) for i, pc := range stk { data[2+b.hdrsize+uintptr(i)] = uint64(pc) } @@ -469,9 +467,7 @@ Read: dst := b.overflowBuf dst[0] = uint64(2 + b.hdrsize + 1) dst[1] = time - for i := uintptr(0); i < b.hdrsize; i++ { - dst[2+i] = 0 - } + clear(dst[2 : 2+b.hdrsize]) dst[2+b.hdrsize] = uint64(count) return dst[:2+b.hdrsize+1], overflowTag[:1], false } diff --git a/contrib/go/_std_1.22/src/runtime/proflabel.go b/contrib/go/_std_1.23/src/runtime/proflabel.go similarity index 70% rename from contrib/go/_std_1.22/src/runtime/proflabel.go rename to contrib/go/_std_1.23/src/runtime/proflabel.go index b2a161729eff..1a5e7e5e2f14 100644 --- a/contrib/go/_std_1.22/src/runtime/proflabel.go +++ b/contrib/go/_std_1.23/src/runtime/proflabel.go @@ -8,6 +8,15 @@ import "unsafe" var labelSync uintptr +// runtime_setProfLabel should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/localsession +// - github.com/DataDog/datadog-agent +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname runtime_setProfLabel runtime/pprof.runtime_setProfLabel func runtime_setProfLabel(labels unsafe.Pointer) { // Introduce race edge for read-back via profile. @@ -34,6 +43,15 @@ func runtime_setProfLabel(labels unsafe.Pointer) { getg().labels = labels } +// runtime_getProfLabel should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/localsession +// - github.com/DataDog/datadog-agent +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel func runtime_getProfLabel() unsafe.Pointer { return getg().labels diff --git a/contrib/go/_std_1.22/src/runtime/race.go b/contrib/go/_std_1.23/src/runtime/race.go similarity index 91% rename from contrib/go/_std_1.22/src/runtime/race.go rename to contrib/go/_std_1.23/src/runtime/race.go index ca4f05197990..7d5cbce49ee2 100644 --- a/contrib/go/_std_1.22/src/runtime/race.go +++ b/contrib/go/_std_1.23/src/runtime/race.go @@ -93,8 +93,8 @@ const raceenabled = true // callerpc is a return PC of the function that calls this function, // pc is start PC of the function that calls this function. func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { - kind := t.Kind_ & kindMask - if kind == kindArray || kind == kindStruct { + kind := t.Kind_ & abi.KindMask + if kind == abi.Array || kind == abi.Struct { // for composite objects we have to read every address // because a write might happen to any subobject. racereadrangepc(addr, t.Size_, callerpc, pc) @@ -106,8 +106,8 @@ func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { } func raceWriteObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { - kind := t.Kind_ & kindMask - if kind == kindArray || kind == kindStruct { + kind := t.Kind_ & abi.KindMask + if kind == abi.Array || kind == abi.Struct { // for composite objects we have to write every address // because a write might happen to any subobject. racewriterangepc(addr, t.Size_, callerpc, pc) @@ -323,6 +323,10 @@ var __tsan_report_count byte //go:cgo_import_static __tsan_go_atomic64_exchange //go:cgo_import_static __tsan_go_atomic32_fetch_add //go:cgo_import_static __tsan_go_atomic64_fetch_add +//go:cgo_import_static __tsan_go_atomic32_fetch_and +//go:cgo_import_static __tsan_go_atomic64_fetch_and +//go:cgo_import_static __tsan_go_atomic32_fetch_or +//go:cgo_import_static __tsan_go_atomic64_fetch_or //go:cgo_import_static __tsan_go_atomic32_compare_exchange //go:cgo_import_static __tsan_go_atomic64_compare_exchange @@ -642,6 +646,36 @@ func abigen_sync_atomic_AddUint64(addr *uint64, delta uint64) (new uint64) //go:linkname abigen_sync_atomic_AddUintptr sync/atomic.AddUintptr func abigen_sync_atomic_AddUintptr(addr *uintptr, delta uintptr) (new uintptr) +//go:linkname abigen_sync_atomic_AndInt32 sync/atomic.AndInt32 +func abigen_sync_atomic_AndInt32(addr *int32, mask int32) (old int32) + +//go:linkname abigen_sync_atomic_AndUint32 sync/atomic.AndUint32 +func abigen_sync_atomic_AndUint32(addr *uint32, mask uint32) (old uint32) + +//go:linkname abigen_sync_atomic_AndInt64 sync/atomic.AndInt64 +func abigen_sync_atomic_AndInt64(addr *int64, mask int64) (old int64) + +//go:linkname abigen_sync_atomic_AndUint64 sync/atomic.AndUint64 +func abigen_sync_atomic_AndUint64(addr *uint64, mask uint64) (old uint64) + +//go:linkname abigen_sync_atomic_AndUintptr sync/atomic.AndUintptr +func abigen_sync_atomic_AndUintptr(addr *uintptr, mask uintptr) (old uintptr) + +//go:linkname abigen_sync_atomic_OrInt32 sync/atomic.OrInt32 +func abigen_sync_atomic_OrInt32(addr *int32, mask int32) (old int32) + +//go:linkname abigen_sync_atomic_OrUint32 sync/atomic.OrUint32 +func abigen_sync_atomic_OrUint32(addr *uint32, mask uint32) (old uint32) + +//go:linkname abigen_sync_atomic_OrInt64 sync/atomic.OrInt64 +func abigen_sync_atomic_OrInt64(addr *int64, mask int64) (old int64) + +//go:linkname abigen_sync_atomic_OrUint64 sync/atomic.OrUint64 +func abigen_sync_atomic_OrUint64(addr *uint64, mask uint64) (old uint64) + +//go:linkname abigen_sync_atomic_OrUintptr sync/atomic.OrUintptr +func abigen_sync_atomic_OrUintptr(addr *uintptr, mask uintptr) (old uintptr) + //go:linkname abigen_sync_atomic_CompareAndSwapInt32 sync/atomic.CompareAndSwapInt32 func abigen_sync_atomic_CompareAndSwapInt32(addr *int32, old, new int32) (swapped bool) diff --git a/contrib/go/_std_1.22/src/runtime/race/README b/contrib/go/_std_1.23/src/runtime/race/README similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/README rename to contrib/go/_std_1.23/src/runtime/race/README diff --git a/contrib/go/_std_1.22/src/runtime/race/doc.go b/contrib/go/_std_1.23/src/runtime/race/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/doc.go rename to contrib/go/_std_1.23/src/runtime/race/doc.go diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/doc.go b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/doc.go rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/doc.go diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_darwin.syso b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_darwin.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_darwin.syso rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_darwin.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_freebsd.syso b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_freebsd.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_freebsd.syso rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_freebsd.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_linux.syso b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_linux.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_linux.syso rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_linux.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_netbsd.syso b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_netbsd.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_netbsd.syso rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_netbsd.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_openbsd.syso b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_openbsd.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_openbsd.syso rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_openbsd.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_windows.syso b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_windows.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/race_windows.syso rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/race_windows.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/ya.make b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v1/ya.make rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v1/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v3/doc.go b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v3/doc.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v3/doc.go rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v3/doc.go diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v3/race_linux.syso b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v3/race_linux.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v3/race_linux.syso rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v3/race_linux.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/amd64v3/ya.make b/contrib/go/_std_1.23/src/runtime/race/internal/amd64v3/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/amd64v3/ya.make rename to contrib/go/_std_1.23/src/runtime/race/internal/amd64v3/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/race/internal/ya.make b/contrib/go/_std_1.23/src/runtime/race/internal/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/internal/ya.make rename to contrib/go/_std_1.23/src/runtime/race/internal/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/race/race.go b/contrib/go/_std_1.23/src/runtime/race/race.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race.go rename to contrib/go/_std_1.23/src/runtime/race/race.go diff --git a/contrib/go/_std_1.22/src/runtime/race/race_darwin_amd64.go b/contrib/go/_std_1.23/src/runtime/race/race_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_darwin_amd64.go rename to contrib/go/_std_1.23/src/runtime/race/race_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/race/race_darwin_arm64.go b/contrib/go/_std_1.23/src/runtime/race/race_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_darwin_arm64.go rename to contrib/go/_std_1.23/src/runtime/race/race_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/race/race_darwin_arm64.syso b/contrib/go/_std_1.23/src/runtime/race/race_darwin_arm64.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_darwin_arm64.syso rename to contrib/go/_std_1.23/src/runtime/race/race_darwin_arm64.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/race_linux_arm64.syso b/contrib/go/_std_1.23/src/runtime/race/race_linux_arm64.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_linux_arm64.syso rename to contrib/go/_std_1.23/src/runtime/race/race_linux_arm64.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/race_linux_ppc64le.syso b/contrib/go/_std_1.23/src/runtime/race/race_linux_ppc64le.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_linux_ppc64le.syso rename to contrib/go/_std_1.23/src/runtime/race/race_linux_ppc64le.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/race_linux_s390x.syso b/contrib/go/_std_1.23/src/runtime/race/race_linux_s390x.syso similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_linux_s390x.syso rename to contrib/go/_std_1.23/src/runtime/race/race_linux_s390x.syso diff --git a/contrib/go/_std_1.22/src/runtime/race/race_v1_amd64.go b/contrib/go/_std_1.23/src/runtime/race/race_v1_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_v1_amd64.go rename to contrib/go/_std_1.23/src/runtime/race/race_v1_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/race/race_v3_amd64.go b/contrib/go/_std_1.23/src/runtime/race/race_v3_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/race_v3_amd64.go rename to contrib/go/_std_1.23/src/runtime/race/race_v3_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/race/ya.make b/contrib/go/_std_1.23/src/runtime/race/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race/ya.make rename to contrib/go/_std_1.23/src/runtime/race/ya.make diff --git a/contrib/go/_std_1.22/src/runtime/race0.go b/contrib/go/_std_1.23/src/runtime/race0.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/race0.go rename to contrib/go/_std_1.23/src/runtime/race0.go diff --git a/contrib/go/_std_1.22/src/runtime/race_amd64.s b/contrib/go/_std_1.23/src/runtime/race_amd64.s similarity index 92% rename from contrib/go/_std_1.22/src/runtime/race_amd64.s rename to contrib/go/_std_1.23/src/runtime/race_amd64.s index 45c1255509c8..c4a6d493162c 100644 --- a/contrib/go/_std_1.22/src/runtime/race_amd64.s +++ b/contrib/go/_std_1.23/src/runtime/race_amd64.s @@ -303,6 +303,57 @@ TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24 GO_ARGS JMP sync∕atomic·AddInt64(SB) +// And +TEXT sync∕atomic·AndInt32(SB), NOSPLIT|NOFRAME, $0-20 + GO_ARGS + MOVQ $__tsan_go_atomic32_fetch_and(SB), AX + CALL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·AndInt64(SB), NOSPLIT|NOFRAME, $0-24 + GO_ARGS + MOVQ $__tsan_go_atomic64_fetch_and(SB), AX + CALL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·AndUint32(SB), NOSPLIT, $0-20 + GO_ARGS + JMP sync∕atomic·AndInt32(SB) + +TEXT sync∕atomic·AndUint64(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·AndInt64(SB) + +TEXT sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·AndInt64(SB) + +// Or +TEXT sync∕atomic·OrInt32(SB), NOSPLIT|NOFRAME, $0-20 + GO_ARGS + MOVQ $__tsan_go_atomic32_fetch_or(SB), AX + CALL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·OrInt64(SB), NOSPLIT|NOFRAME, $0-24 + GO_ARGS + MOVQ $__tsan_go_atomic64_fetch_or(SB), AX + CALL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·OrUint32(SB), NOSPLIT, $0-20 + GO_ARGS + JMP sync∕atomic·OrInt32(SB) + +TEXT sync∕atomic·OrUint64(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·OrInt64(SB) + +TEXT sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·OrInt64(SB) + + // CompareAndSwap TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT|NOFRAME, $0-17 GO_ARGS diff --git a/contrib/go/_std_1.22/src/runtime/race_arm64.s b/contrib/go/_std_1.23/src/runtime/race_arm64.s similarity index 91% rename from contrib/go/_std_1.22/src/runtime/race_arm64.s rename to contrib/go/_std_1.23/src/runtime/race_arm64.s index c818345852f6..c42a6c137752 100644 --- a/contrib/go/_std_1.22/src/runtime/race_arm64.s +++ b/contrib/go/_std_1.23/src/runtime/race_arm64.s @@ -312,6 +312,56 @@ TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24 GO_ARGS JMP sync∕atomic·AddInt64(SB) +// And +TEXT sync∕atomic·AndInt32(SB), NOSPLIT, $0-20 + GO_ARGS + MOVD $__tsan_go_atomic32_fetch_and(SB), R9 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·AndInt64(SB), NOSPLIT, $0-24 + GO_ARGS + MOVD $__tsan_go_atomic64_fetch_and(SB), R9 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·AndUint32(SB), NOSPLIT, $0-20 + GO_ARGS + JMP sync∕atomic·AndInt32(SB) + +TEXT sync∕atomic·AndUint64(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·AndInt64(SB) + +TEXT sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·AndInt64(SB) + +// Or +TEXT sync∕atomic·OrInt32(SB), NOSPLIT, $0-20 + GO_ARGS + MOVD $__tsan_go_atomic32_fetch_or(SB), R9 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·OrInt64(SB), NOSPLIT, $0-24 + GO_ARGS + MOVD $__tsan_go_atomic64_fetch_or(SB), R9 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·OrUint32(SB), NOSPLIT, $0-20 + GO_ARGS + JMP sync∕atomic·OrInt32(SB) + +TEXT sync∕atomic·OrUint64(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·OrInt64(SB) + +TEXT sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·OrInt64(SB) + // CompareAndSwap TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17 GO_ARGS @@ -419,6 +469,10 @@ TEXT racecall<>(SB), NOSPLIT|NOFRAME, $0-0 MOVD (g_sched+gobuf_sp)(R11), R12 MOVD R12, RSP call: + // Decrement SP past where the frame pointer is saved in the Go arm64 + // ABI (one word below the stack pointer) so the race detector library + // code doesn't clobber it + SUB $16, RSP BL R9 MOVD R19, RSP JMP (R20) diff --git a/contrib/go/_std_1.22/src/runtime/race_ppc64le.s b/contrib/go/_std_1.23/src/runtime/race_ppc64le.s similarity index 93% rename from contrib/go/_std_1.22/src/runtime/race_ppc64le.s rename to contrib/go/_std_1.23/src/runtime/race_ppc64le.s index 39cfffc39bbe..43829479bde8 100644 --- a/contrib/go/_std_1.22/src/runtime/race_ppc64le.s +++ b/contrib/go/_std_1.23/src/runtime/race_ppc64le.s @@ -325,6 +325,52 @@ TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24 GO_ARGS BR sync∕atomic·AddInt64(SB) +// And +TEXT sync∕atomic·AndInt32(SB), NOSPLIT, $0-20 + GO_ARGS + MOVD $__tsan_go_atomic32_fetch_and(SB), R8 + BR racecallatomic<>(SB) + +TEXT sync∕atomic·AndInt64(SB), NOSPLIT, $0-24 + GO_ARGS + MOVD $__tsan_go_atomic64_fetch_and(SB), R8 + BR racecallatomic<>(SB) + +TEXT sync∕atomic·AndUint32(SB), NOSPLIT, $0-20 + GO_ARGS + BR sync∕atomic·AndInt32(SB) + +TEXT sync∕atomic·AndUint64(SB), NOSPLIT, $0-24 + GO_ARGS + BR sync∕atomic·AndInt64(SB) + +TEXT sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + BR sync∕atomic·AndInt64(SB) + +// Or +TEXT sync∕atomic·OrInt32(SB), NOSPLIT, $0-20 + GO_ARGS + MOVD $__tsan_go_atomic32_fetch_or(SB), R8 + BR racecallatomic<>(SB) + +TEXT sync∕atomic·OrInt64(SB), NOSPLIT, $0-24 + GO_ARGS + MOVD $__tsan_go_atomic64_fetch_or(SB), R8 + BR racecallatomic<>(SB) + +TEXT sync∕atomic·OrUint32(SB), NOSPLIT, $0-20 + GO_ARGS + BR sync∕atomic·OrInt32(SB) + +TEXT sync∕atomic·OrUint64(SB), NOSPLIT, $0-24 + GO_ARGS + BR sync∕atomic·OrInt64(SB) + +TEXT sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + BR sync∕atomic·OrInt64(SB) + // CompareAndSwap in tsan TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17 GO_ARGS diff --git a/contrib/go/_std_1.22/src/runtime/race_s390x.s b/contrib/go/_std_1.23/src/runtime/race_s390x.s similarity index 91% rename from contrib/go/_std_1.22/src/runtime/race_s390x.s rename to contrib/go/_std_1.23/src/runtime/race_s390x.s index dadc12f4dbfb..8e6a5d576ab4 100644 --- a/contrib/go/_std_1.22/src/runtime/race_s390x.s +++ b/contrib/go/_std_1.23/src/runtime/race_s390x.s @@ -274,6 +274,56 @@ TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-24 GO_ARGS JMP sync∕atomic·AddInt64(SB) +// And +TEXT sync∕atomic·AndInt32(SB), NOSPLIT, $0-20 + GO_ARGS + MOVD $__tsan_go_atomic32_fetch_and(SB), R1 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·AndInt64(SB), NOSPLIT, $0-24 + GO_ARGS + MOVD $__tsan_go_atomic64_fetch_and(SB), R1 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·AndUint32(SB), NOSPLIT, $0-20 + GO_ARGS + JMP sync∕atomic·AndInt32(SB) + +TEXT sync∕atomic·AndUint64(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·AndInt64(SB) + +TEXT sync∕atomic·AndUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·AndInt64(SB) + +// Or +TEXT sync∕atomic·OrInt32(SB), NOSPLIT, $0-20 + GO_ARGS + MOVD $__tsan_go_atomic32_fetch_or(SB), R1 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·OrInt64(SB), NOSPLIT, $0-24 + GO_ARGS + MOVD $__tsan_go_atomic64_fetch_or(SB), R1 + BL racecallatomic<>(SB) + RET + +TEXT sync∕atomic·OrUint32(SB), NOSPLIT, $0-20 + GO_ARGS + JMP sync∕atomic·OrInt32(SB) + +TEXT sync∕atomic·OrUint64(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·OrInt64(SB) + +TEXT sync∕atomic·OrUintptr(SB), NOSPLIT, $0-24 + GO_ARGS + JMP sync∕atomic·OrInt64(SB) + // CompareAndSwap TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-17 diff --git a/contrib/go/_std_1.22/src/runtime/rand.go b/contrib/go/_std_1.23/src/runtime/rand.go similarity index 89% rename from contrib/go/_std_1.22/src/runtime/rand.go rename to contrib/go/_std_1.23/src/runtime/rand.go index 10cd116fadea..a66553feebe3 100644 --- a/contrib/go/_std_1.22/src/runtime/rand.go +++ b/contrib/go/_std_1.23/src/runtime/rand.go @@ -115,6 +115,7 @@ func bootstrapRandReseed() { } // rand32 is uint32(rand()), called from compiler-generated code. +// //go:nosplit func rand32() uint32 { return uint32(rand()) @@ -122,6 +123,7 @@ func rand32() uint32 { // rand returns a random uint64 from the per-m chacha8 state. // Do not change signature: used via linkname from other packages. +// //go:nosplit //go:linkname rand func rand() uint64 { @@ -159,6 +161,7 @@ func mrandinit(mp *m) { // randn is like rand() % n but faster. // Do not change signature: used via linkname from other packages. +// //go:nosplit //go:linkname randn func randn(n uint32) uint32 { @@ -174,6 +177,16 @@ func randn(n uint32) uint32 { // cheaprand must not be exported to other packages: // the rule is that other packages using runtime-provided // randomness must always use rand. +// +// cheaprand should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cheaprand //go:nosplit func cheaprand() uint32 { mp := getg().m @@ -208,6 +221,16 @@ func cheaprand() uint32 { // cheaprand64 must not be exported to other packages: // the rule is that other packages using runtime-provided // randomness must always use rand. +// +// cheaprand64 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/zhangyunhao116/fastrand +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cheaprand64 //go:nosplit func cheaprand64() int64 { return int64(cheaprand())<<31 ^ int64(cheaprand()) @@ -218,6 +241,16 @@ func cheaprand64() int64 { // cheaprandn must not be exported to other packages: // the rule is that other packages using runtime-provided // randomness must always use randn. +// +// cheaprandn should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname cheaprandn //go:nosplit func cheaprandn(n uint32) uint32 { // See https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ diff --git a/contrib/go/_std_1.22/src/runtime/rdebug.go b/contrib/go/_std_1.23/src/runtime/rdebug.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rdebug.go rename to contrib/go/_std_1.23/src/runtime/rdebug.go diff --git a/contrib/go/_std_1.22/src/runtime/retry.go b/contrib/go/_std_1.23/src/runtime/retry.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/retry.go rename to contrib/go/_std_1.23/src/runtime/retry.go diff --git a/contrib/go/_std_1.22/src/runtime/rt0_aix_ppc64.s b/contrib/go/_std_1.23/src/runtime/rt0_aix_ppc64.s similarity index 52% rename from contrib/go/_std_1.22/src/runtime/rt0_aix_ppc64.s rename to contrib/go/_std_1.23/src/runtime/rt0_aix_ppc64.s index 1670a809862a..74c57bb1dc91 100644 --- a/contrib/go/_std_1.22/src/runtime/rt0_aix_ppc64.s +++ b/contrib/go/_std_1.23/src/runtime/rt0_aix_ppc64.s @@ -41,6 +41,8 @@ TEXT _main(SB),NOSPLIT,$-8 MOVD R12, CTR BR (CTR) +// Paramater save space required to cross-call into _cgo_sys_thread_create +#define PARAM_SPACE 16 TEXT _rt0_ppc64_aix_lib(SB),NOSPLIT,$-8 // Start with standard C stack frame layout and linkage. @@ -49,45 +51,45 @@ TEXT _rt0_ppc64_aix_lib(SB),NOSPLIT,$-8 MOVW CR, R0 // Save CR in caller's frame MOVD R0, 8(R1) - MOVDU R1, -344(R1) // Allocate frame. + MOVDU R1, -344-PARAM_SPACE(R1) // Allocate frame. // Preserve callee-save registers. - MOVD R14, 48(R1) - MOVD R15, 56(R1) - MOVD R16, 64(R1) - MOVD R17, 72(R1) - MOVD R18, 80(R1) - MOVD R19, 88(R1) - MOVD R20, 96(R1) - MOVD R21,104(R1) - MOVD R22, 112(R1) - MOVD R23, 120(R1) - MOVD R24, 128(R1) - MOVD R25, 136(R1) - MOVD R26, 144(R1) - MOVD R27, 152(R1) - MOVD R28, 160(R1) - MOVD R29, 168(R1) - MOVD g, 176(R1) // R30 - MOVD R31, 184(R1) - FMOVD F14, 192(R1) - FMOVD F15, 200(R1) - FMOVD F16, 208(R1) - FMOVD F17, 216(R1) - FMOVD F18, 224(R1) - FMOVD F19, 232(R1) - FMOVD F20, 240(R1) - FMOVD F21, 248(R1) - FMOVD F22, 256(R1) - FMOVD F23, 264(R1) - FMOVD F24, 272(R1) - FMOVD F25, 280(R1) - FMOVD F26, 288(R1) - FMOVD F27, 296(R1) - FMOVD F28, 304(R1) - FMOVD F29, 312(R1) - FMOVD F30, 320(R1) - FMOVD F31, 328(R1) + MOVD R14, 48+PARAM_SPACE(R1) + MOVD R15, 56+PARAM_SPACE(R1) + MOVD R16, 64+PARAM_SPACE(R1) + MOVD R17, 72+PARAM_SPACE(R1) + MOVD R18, 80+PARAM_SPACE(R1) + MOVD R19, 88+PARAM_SPACE(R1) + MOVD R20, 96+PARAM_SPACE(R1) + MOVD R21,104+PARAM_SPACE(R1) + MOVD R22, 112+PARAM_SPACE(R1) + MOVD R23, 120+PARAM_SPACE(R1) + MOVD R24, 128+PARAM_SPACE(R1) + MOVD R25, 136+PARAM_SPACE(R1) + MOVD R26, 144+PARAM_SPACE(R1) + MOVD R27, 152+PARAM_SPACE(R1) + MOVD R28, 160+PARAM_SPACE(R1) + MOVD R29, 168+PARAM_SPACE(R1) + MOVD g, 176+PARAM_SPACE(R1) // R30 + MOVD R31, 184+PARAM_SPACE(R1) + FMOVD F14, 192+PARAM_SPACE(R1) + FMOVD F15, 200+PARAM_SPACE(R1) + FMOVD F16, 208+PARAM_SPACE(R1) + FMOVD F17, 216+PARAM_SPACE(R1) + FMOVD F18, 224+PARAM_SPACE(R1) + FMOVD F19, 232+PARAM_SPACE(R1) + FMOVD F20, 240+PARAM_SPACE(R1) + FMOVD F21, 248+PARAM_SPACE(R1) + FMOVD F22, 256+PARAM_SPACE(R1) + FMOVD F23, 264+PARAM_SPACE(R1) + FMOVD F24, 272+PARAM_SPACE(R1) + FMOVD F25, 280+PARAM_SPACE(R1) + FMOVD F26, 288+PARAM_SPACE(R1) + FMOVD F27, 296+PARAM_SPACE(R1) + FMOVD F28, 304+PARAM_SPACE(R1) + FMOVD F29, 312+PARAM_SPACE(R1) + FMOVD F30, 320+PARAM_SPACE(R1) + FMOVD F31, 328+PARAM_SPACE(R1) // Synchronous initialization. MOVD $runtime·reginit(SB), R12 @@ -130,44 +132,44 @@ nocgo: done: // Restore saved registers. - MOVD 48(R1), R14 - MOVD 56(R1), R15 - MOVD 64(R1), R16 - MOVD 72(R1), R17 - MOVD 80(R1), R18 - MOVD 88(R1), R19 - MOVD 96(R1), R20 - MOVD 104(R1), R21 - MOVD 112(R1), R22 - MOVD 120(R1), R23 - MOVD 128(R1), R24 - MOVD 136(R1), R25 - MOVD 144(R1), R26 - MOVD 152(R1), R27 - MOVD 160(R1), R28 - MOVD 168(R1), R29 - MOVD 176(R1), g // R30 - MOVD 184(R1), R31 - FMOVD 196(R1), F14 - FMOVD 200(R1), F15 - FMOVD 208(R1), F16 - FMOVD 216(R1), F17 - FMOVD 224(R1), F18 - FMOVD 232(R1), F19 - FMOVD 240(R1), F20 - FMOVD 248(R1), F21 - FMOVD 256(R1), F22 - FMOVD 264(R1), F23 - FMOVD 272(R1), F24 - FMOVD 280(R1), F25 - FMOVD 288(R1), F26 - FMOVD 296(R1), F27 - FMOVD 304(R1), F28 - FMOVD 312(R1), F29 - FMOVD 320(R1), F30 - FMOVD 328(R1), F31 - - ADD $344, R1 + MOVD 48+PARAM_SPACE(R1), R14 + MOVD 56+PARAM_SPACE(R1), R15 + MOVD 64+PARAM_SPACE(R1), R16 + MOVD 72+PARAM_SPACE(R1), R17 + MOVD 80+PARAM_SPACE(R1), R18 + MOVD 88+PARAM_SPACE(R1), R19 + MOVD 96+PARAM_SPACE(R1), R20 + MOVD 104+PARAM_SPACE(R1), R21 + MOVD 112+PARAM_SPACE(R1), R22 + MOVD 120+PARAM_SPACE(R1), R23 + MOVD 128+PARAM_SPACE(R1), R24 + MOVD 136+PARAM_SPACE(R1), R25 + MOVD 144+PARAM_SPACE(R1), R26 + MOVD 152+PARAM_SPACE(R1), R27 + MOVD 160+PARAM_SPACE(R1), R28 + MOVD 168+PARAM_SPACE(R1), R29 + MOVD 176+PARAM_SPACE(R1), g // R30 + MOVD 184+PARAM_SPACE(R1), R31 + FMOVD 196+PARAM_SPACE(R1), F14 + FMOVD 200+PARAM_SPACE(R1), F15 + FMOVD 208+PARAM_SPACE(R1), F16 + FMOVD 216+PARAM_SPACE(R1), F17 + FMOVD 224+PARAM_SPACE(R1), F18 + FMOVD 232+PARAM_SPACE(R1), F19 + FMOVD 240+PARAM_SPACE(R1), F20 + FMOVD 248+PARAM_SPACE(R1), F21 + FMOVD 256+PARAM_SPACE(R1), F22 + FMOVD 264+PARAM_SPACE(R1), F23 + FMOVD 272+PARAM_SPACE(R1), F24 + FMOVD 280+PARAM_SPACE(R1), F25 + FMOVD 288+PARAM_SPACE(R1), F26 + FMOVD 296+PARAM_SPACE(R1), F27 + FMOVD 304+PARAM_SPACE(R1), F28 + FMOVD 312+PARAM_SPACE(R1), F29 + FMOVD 320+PARAM_SPACE(R1), F30 + FMOVD 328+PARAM_SPACE(R1), F31 + + ADD $344+PARAM_SPACE, R1 MOVD 8(R1), R0 MOVFL R0, $0xff diff --git a/contrib/go/_std_1.22/src/runtime/rt0_android_386.s b/contrib/go/_std_1.23/src/runtime/rt0_android_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_android_386.s rename to contrib/go/_std_1.23/src/runtime/rt0_android_386.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_android_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_android_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_android_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_android_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_android_arm.s b/contrib/go/_std_1.23/src/runtime/rt0_android_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_android_arm.s rename to contrib/go/_std_1.23/src/runtime/rt0_android_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_android_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_android_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_android_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_android_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_darwin_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_darwin_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_darwin_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_darwin_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_darwin_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_darwin_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_darwin_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_darwin_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_dragonfly_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_dragonfly_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_dragonfly_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_dragonfly_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_freebsd_386.s b/contrib/go/_std_1.23/src/runtime/rt0_freebsd_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_freebsd_386.s rename to contrib/go/_std_1.23/src/runtime/rt0_freebsd_386.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_freebsd_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_freebsd_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_freebsd_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_freebsd_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_freebsd_arm.s b/contrib/go/_std_1.23/src/runtime/rt0_freebsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_freebsd_arm.s rename to contrib/go/_std_1.23/src/runtime/rt0_freebsd_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_freebsd_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_freebsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_freebsd_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_freebsd_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_freebsd_riscv64.s b/contrib/go/_std_1.23/src/runtime/rt0_freebsd_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_freebsd_riscv64.s rename to contrib/go/_std_1.23/src/runtime/rt0_freebsd_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_illumos_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_illumos_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_illumos_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_illumos_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_ios_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_ios_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_ios_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_ios_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_ios_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_ios_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_ios_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_ios_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_js_wasm.s b/contrib/go/_std_1.23/src/runtime/rt0_js_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_js_wasm.s rename to contrib/go/_std_1.23/src/runtime/rt0_js_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_386.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_386.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_386.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_arm.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_arm.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_loong64.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_loong64.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_mips64x.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_mips64x.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_mipsx.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_mipsx.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_ppc64.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_ppc64.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_ppc64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_ppc64le.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_ppc64le.s similarity index 99% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_ppc64le.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_ppc64le.s index 417ada21bf0c..4b7d8e1b940a 100644 --- a/contrib/go/_std_1.22/src/runtime/rt0_linux_ppc64le.s +++ b/contrib/go/_std_1.23/src/runtime/rt0_linux_ppc64le.s @@ -78,7 +78,7 @@ TEXT _main<>(SB),NOSPLIT,$-8 // passes argc/argv similar to the linux kernel, R13 (TLS) is // initialized, and R3/R4 are undefined. MOVD (R1), R12 - CMP R0, R12 + CMP R12, $0 BEQ tls_and_argcv_in_reg // Arguments are passed via the stack (musl loader or a static binary) @@ -86,7 +86,7 @@ TEXT _main<>(SB),NOSPLIT,$-8 ADD $8, R1, R4 // argv // Did the TLS pointer get set? If so, don't change it (e.g musl). - CMP R0, R13 + CMP R13, $0 BNE tls_and_argcv_in_reg MOVD $runtime·m0+m_tls(SB), R13 // TLS diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_riscv64.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_riscv64.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_linux_s390x.s b/contrib/go/_std_1.23/src/runtime/rt0_linux_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_linux_s390x.s rename to contrib/go/_std_1.23/src/runtime/rt0_linux_s390x.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_netbsd_386.s b/contrib/go/_std_1.23/src/runtime/rt0_netbsd_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_netbsd_386.s rename to contrib/go/_std_1.23/src/runtime/rt0_netbsd_386.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_netbsd_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_netbsd_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_netbsd_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_netbsd_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_netbsd_arm.s b/contrib/go/_std_1.23/src/runtime/rt0_netbsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_netbsd_arm.s rename to contrib/go/_std_1.23/src/runtime/rt0_netbsd_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_netbsd_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_netbsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_netbsd_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_netbsd_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_openbsd_386.s b/contrib/go/_std_1.23/src/runtime/rt0_openbsd_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_openbsd_386.s rename to contrib/go/_std_1.23/src/runtime/rt0_openbsd_386.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_openbsd_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_openbsd_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_openbsd_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_openbsd_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_openbsd_arm.s b/contrib/go/_std_1.23/src/runtime/rt0_openbsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_openbsd_arm.s rename to contrib/go/_std_1.23/src/runtime/rt0_openbsd_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_openbsd_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_openbsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_openbsd_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_openbsd_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_openbsd_mips64.s b/contrib/go/_std_1.23/src/runtime/rt0_openbsd_mips64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_openbsd_mips64.s rename to contrib/go/_std_1.23/src/runtime/rt0_openbsd_mips64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_openbsd_ppc64.s b/contrib/go/_std_1.23/src/runtime/rt0_openbsd_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_openbsd_ppc64.s rename to contrib/go/_std_1.23/src/runtime/rt0_openbsd_ppc64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_openbsd_riscv64.s b/contrib/go/_std_1.23/src/runtime/rt0_openbsd_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_openbsd_riscv64.s rename to contrib/go/_std_1.23/src/runtime/rt0_openbsd_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_plan9_386.s b/contrib/go/_std_1.23/src/runtime/rt0_plan9_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_plan9_386.s rename to contrib/go/_std_1.23/src/runtime/rt0_plan9_386.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_plan9_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_plan9_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_plan9_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_plan9_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_plan9_arm.s b/contrib/go/_std_1.23/src/runtime/rt0_plan9_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_plan9_arm.s rename to contrib/go/_std_1.23/src/runtime/rt0_plan9_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_solaris_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_solaris_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_solaris_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_solaris_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_wasip1_wasm.s b/contrib/go/_std_1.23/src/runtime/rt0_wasip1_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_wasip1_wasm.s rename to contrib/go/_std_1.23/src/runtime/rt0_wasip1_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_windows_386.s b/contrib/go/_std_1.23/src/runtime/rt0_windows_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_windows_386.s rename to contrib/go/_std_1.23/src/runtime/rt0_windows_386.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_windows_amd64.s b/contrib/go/_std_1.23/src/runtime/rt0_windows_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_windows_amd64.s rename to contrib/go/_std_1.23/src/runtime/rt0_windows_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_windows_arm.s b/contrib/go/_std_1.23/src/runtime/rt0_windows_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_windows_arm.s rename to contrib/go/_std_1.23/src/runtime/rt0_windows_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/rt0_windows_arm64.s b/contrib/go/_std_1.23/src/runtime/rt0_windows_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/rt0_windows_arm64.s rename to contrib/go/_std_1.23/src/runtime/rt0_windows_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/runtime-gdb.py b/contrib/go/_std_1.23/src/runtime/runtime-gdb.py similarity index 100% rename from contrib/go/_std_1.22/src/runtime/runtime-gdb.py rename to contrib/go/_std_1.23/src/runtime/runtime-gdb.py diff --git a/contrib/go/_std_1.22/src/runtime/runtime.go b/contrib/go/_std_1.23/src/runtime/runtime.go similarity index 69% rename from contrib/go/_std_1.22/src/runtime/runtime.go rename to contrib/go/_std_1.23/src/runtime/runtime.go index c70a76e40905..e8e614815d23 100644 --- a/contrib/go/_std_1.22/src/runtime/runtime.go +++ b/contrib/go/_std_1.23/src/runtime/runtime.go @@ -5,7 +5,8 @@ package runtime import ( - "runtime/internal/atomic" + "internal/abi" + "internal/runtime/atomic" "unsafe" ) @@ -217,10 +218,75 @@ func syscall_runtimeUnsetenv(key string) { } // writeErrStr writes a string to descriptor 2. +// If SetCrashOutput(f) was called, it also writes to f. // //go:nosplit func writeErrStr(s string) { - write(2, unsafe.Pointer(unsafe.StringData(s)), int32(len(s))) + writeErrData(unsafe.StringData(s), int32(len(s))) +} + +// writeErrData is the common parts of writeErr{,Str}. +// +//go:nosplit +func writeErrData(data *byte, n int32) { + write(2, unsafe.Pointer(data), n) + + // If crashing, print a copy to the SetCrashOutput fd. + gp := getg() + if gp != nil && gp.m.dying > 0 || + gp == nil && panicking.Load() > 0 { + if fd := crashFD.Load(); fd != ^uintptr(0) { + write(fd, unsafe.Pointer(data), n) + } + } +} + +// crashFD is an optional file descriptor to use for fatal panics, as +// set by debug.SetCrashOutput (see #42888). If it is a valid fd (not +// all ones), writeErr and related functions write to it in addition +// to standard error. +// +// Initialized to -1 in schedinit. +var crashFD atomic.Uintptr + +//go:linkname setCrashFD +func setCrashFD(fd uintptr) uintptr { + // Don't change the crash FD if a crash is already in progress. + // + // Unlike the case below, this is not required for correctness, but it + // is generally nicer to have all of the crash output go to the same + // place rather than getting split across two different FDs. + if panicking.Load() > 0 { + return ^uintptr(0) + } + + old := crashFD.Swap(fd) + + // If we are panicking, don't return the old FD to runtime/debug for + // closing. writeErrData may have already read the old FD from crashFD + // before the swap and closing it would cause the write to be lost [1]. + // The old FD will never be closed, but we are about to crash anyway. + // + // On the writeErrData thread, panicking.Add(1) happens-before + // crashFD.Load() [2]. + // + // On this thread, swapping old FD for new in crashFD happens-before + // panicking.Load() > 0. + // + // Therefore, if panicking.Load() == 0 here (old FD will be closed), it + // is impossible for the writeErrData thread to observe + // crashFD.Load() == old FD. + // + // [1] Or, if really unlucky, another concurrent open could reuse the + // FD, sending the write into an unrelated file. + // + // [2] If gp != nil, it occurs when incrementing gp.m.dying in + // startpanic_m. If gp == nil, we read panicking.Load() > 0, so an Add + // must have happened-before. + if panicking.Load() > 0 { + return ^uintptr(0) + } + return old } // auxv is populated on relevant platforms but defined here for all platforms @@ -230,4 +296,30 @@ func writeErrStr(s string) { // It contains an even number of elements, (tag, value) pairs. var auxv []uintptr -func getAuxv() []uintptr { return auxv } // accessed from x/sys/cpu; see issue 57336 +// golang.org/x/sys/cpu uses getAuxv via linkname. +// Do not remove or change the type signature. +// (See go.dev/issue/57336.) +// +// getAuxv should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cilium/ebpf +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname getAuxv +func getAuxv() []uintptr { return auxv } + +// zeroVal is used by reflect via linkname. +// +// zeroVal should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname zeroVal +var zeroVal [abi.ZeroValSize]byte diff --git a/contrib/go/_std_1.22/src/runtime/runtime1.go b/contrib/go/_std_1.23/src/runtime/runtime1.go similarity index 81% rename from contrib/go/_std_1.22/src/runtime/runtime1.go rename to contrib/go/_std_1.23/src/runtime/runtime1.go index afe1bdd298b9..03ef74b8dc4b 100644 --- a/contrib/go/_std_1.22/src/runtime/runtime1.go +++ b/contrib/go/_std_1.23/src/runtime/runtime1.go @@ -7,7 +7,7 @@ package runtime import ( "internal/bytealg" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -307,44 +307,66 @@ type dbgVar struct { // existing int var for that value, which may // already have an initial value. var debug struct { - cgocheck int32 - clobberfree int32 - disablethp int32 - dontfreezetheworld int32 - efence int32 - gccheckmark int32 - gcpacertrace int32 - gcshrinkstackoff int32 - gcstoptheworld int32 - gctrace int32 - invalidptr int32 - madvdontneed int32 // for Linux; issue 28466 - runtimeContentionStacks atomic.Int32 - scavtrace int32 - scheddetail int32 - schedtrace int32 - tracebackancestors int32 - asyncpreemptoff int32 - harddecommit int32 - adaptivestackstart int32 - tracefpunwindoff int32 - traceadvanceperiod int32 + cgocheck int32 + clobberfree int32 + disablethp int32 + dontfreezetheworld int32 + efence int32 + gccheckmark int32 + gcpacertrace int32 + gcshrinkstackoff int32 + gcstoptheworld int32 + gctrace int32 + invalidptr int32 + madvdontneed int32 // for Linux; issue 28466 + runtimeContentionStacks atomic.Int32 + scavtrace int32 + scheddetail int32 + schedtrace int32 + tracebackancestors int32 + asyncpreemptoff int32 + harddecommit int32 + adaptivestackstart int32 + tracefpunwindoff int32 + traceadvanceperiod int32 + traceCheckStackOwnership int32 + profstackdepth int32 // debug.malloc is used as a combined debug check // in the malloc function and should be set // if any of the below debug options is != 0. - malloc bool - allocfreetrace int32 - inittrace int32 - sbrk int32 + malloc bool + inittrace int32 + sbrk int32 + // traceallocfree controls whether execution traces contain + // detailed trace data about memory allocation. This value + // affects debug.malloc only if it is != 0 and the execution + // tracer is enabled, in which case debug.malloc will be + // set to "true" if it isn't already while tracing is enabled. + // It will be set while the world is stopped, so it's safe. + // The value of traceallocfree can be changed any time in response + // to os.Setenv("GODEBUG"). + traceallocfree atomic.Int32 panicnil atomic.Int32 + + // asynctimerchan controls whether timer channels + // behave asynchronously (as in Go 1.22 and earlier) + // instead of their Go 1.23+ synchronous behavior. + // The value can change at any time (in response to os.Setenv("GODEBUG")) + // and affects all extant timer channels immediately. + // Programs wouldn't normally change over an execution, + // but allowing it is convenient for testing and for programs + // that do an os.Setenv in main.init or main.main. + asynctimerchan atomic.Int32 } var dbgvars = []*dbgVar{ - {name: "allocfreetrace", value: &debug.allocfreetrace}, - {name: "clobberfree", value: &debug.clobberfree}, + {name: "adaptivestackstart", value: &debug.adaptivestackstart}, + {name: "asyncpreemptoff", value: &debug.asyncpreemptoff}, + {name: "asynctimerchan", atomic: &debug.asynctimerchan}, {name: "cgocheck", value: &debug.cgocheck}, + {name: "clobberfree", value: &debug.clobberfree}, {name: "disablethp", value: &debug.disablethp}, {name: "dontfreezetheworld", value: &debug.dontfreezetheworld}, {name: "efence", value: &debug.efence}, @@ -353,21 +375,22 @@ var dbgvars = []*dbgVar{ {name: "gcshrinkstackoff", value: &debug.gcshrinkstackoff}, {name: "gcstoptheworld", value: &debug.gcstoptheworld}, {name: "gctrace", value: &debug.gctrace}, + {name: "harddecommit", value: &debug.harddecommit}, + {name: "inittrace", value: &debug.inittrace}, {name: "invalidptr", value: &debug.invalidptr}, {name: "madvdontneed", value: &debug.madvdontneed}, + {name: "panicnil", atomic: &debug.panicnil}, + {name: "profstackdepth", value: &debug.profstackdepth, def: 128}, {name: "runtimecontentionstacks", atomic: &debug.runtimeContentionStacks}, {name: "sbrk", value: &debug.sbrk}, {name: "scavtrace", value: &debug.scavtrace}, {name: "scheddetail", value: &debug.scheddetail}, {name: "schedtrace", value: &debug.schedtrace}, + {name: "traceadvanceperiod", value: &debug.traceadvanceperiod}, + {name: "traceallocfree", atomic: &debug.traceallocfree}, + {name: "tracecheckstackownership", value: &debug.traceCheckStackOwnership}, {name: "tracebackancestors", value: &debug.tracebackancestors}, - {name: "asyncpreemptoff", value: &debug.asyncpreemptoff}, - {name: "inittrace", value: &debug.inittrace}, - {name: "harddecommit", value: &debug.harddecommit}, - {name: "adaptivestackstart", value: &debug.adaptivestackstart}, {name: "tracefpunwindoff", value: &debug.tracefpunwindoff}, - {name: "panicnil", atomic: &debug.panicnil}, - {name: "traceadvanceperiod", value: &debug.traceadvanceperiod}, } func parsedebugvars() { @@ -412,7 +435,8 @@ func parsedebugvars() { // apply environment settings parsegodebug(godebug, nil) - debug.malloc = (debug.allocfreetrace | debug.inittrace | debug.sbrk) != 0 + debug.malloc = (debug.inittrace | debug.sbrk) != 0 + debug.profstackdepth = min(debug.profstackdepth, maxProfStackDepth) setTraceback(gogetenv("GOTRACEBACK")) traceback_env = traceback_cache @@ -592,6 +616,20 @@ func releasem(mp *m) { } } +// reflect_typelinks is meant for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/goccy/json +// - github.com/modern-go/reflect2 +// - github.com/vmware/govmomi +// - github.com/pinpoint-apm/pinpoint-go-agent +// - github.com/timandy/routine +// - github.com/v2pro/plz +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_typelinks reflect.typelinks func reflect_typelinks() ([]unsafe.Pointer, [][]int32) { modules := activeModules() @@ -606,6 +644,14 @@ func reflect_typelinks() ([]unsafe.Pointer, [][]int32) { // reflect_resolveNameOff resolves a name offset from a base pointer. // +// reflect_resolveNameOff is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/agiledragon/gomonkey/v2 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_resolveNameOff reflect.resolveNameOff func reflect_resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointer { return unsafe.Pointer(resolveNameOff(ptrInModule, nameOff(off)).Bytes) @@ -613,6 +659,17 @@ func reflect_resolveNameOff(ptrInModule unsafe.Pointer, off int32) unsafe.Pointe // reflect_resolveTypeOff resolves an *rtype offset from a base type. // +// reflect_resolveTypeOff is meant for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/modern-go/reflect2 +// - github.com/v2pro/plz +// - github.com/timandy/routine +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_resolveTypeOff reflect.resolveTypeOff func reflect_resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer { return unsafe.Pointer(toRType((*_type)(rtype)).typeOff(typeOff(off))) @@ -620,6 +677,15 @@ func reflect_resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer { // reflect_resolveTextOff resolves a function pointer offset from a base type. // +// reflect_resolveTextOff is for package reflect, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// - github.com/agiledragon/gomonkey/v2 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_resolveTextOff reflect.resolveTextOff func reflect_resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer { return toRType((*_type)(rtype)).textOff(textOff(off)) diff --git a/contrib/go/_std_1.22/src/runtime/runtime2.go b/contrib/go/_std_1.23/src/runtime/runtime2.go similarity index 88% rename from contrib/go/_std_1.22/src/runtime/runtime2.go rename to contrib/go/_std_1.23/src/runtime/runtime2.go index 63320d4a8a30..ca69719db0e2 100644 --- a/contrib/go/_std_1.22/src/runtime/runtime2.go +++ b/contrib/go/_std_1.23/src/runtime/runtime2.go @@ -8,7 +8,7 @@ import ( "internal/abi" "internal/chacha8rand" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -437,6 +437,7 @@ type g struct { sched gobuf syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc + syscallbp uintptr // if status==Gsyscall, syscallbp = sched.bp to use in fpTraceback stktopsp uintptr // expected sp at top of stack, to check in traceback // param is a generic pointer parameter field used to pass // values in particular contexts where other storage for the @@ -506,14 +507,15 @@ type g struct { cgoCtxt []uintptr // cgo traceback context labels unsafe.Pointer // profiler labels timer *timer // cached timer for time.Sleep + sleepWhen int64 // when to sleep until selectDone atomic.Uint32 // are we participating in a select and did someone win the race? - coroarg *coro // argument during coroutine transfers - // goroutineProfiled indicates the status of this goroutine's stack for the // current in-progress goroutine profile goroutineProfiled goroutineProfileStateHolder + coroarg *coro // argument during coroutine transfers + // Per-G tracer state. trace gTraceState @@ -554,56 +556,58 @@ type m struct { _ uint32 // align next field to 8 bytes // Fields not known to debuggers. - procid uint64 // for debuggers, but offset not hard-coded - gsignal *g // signal-handling g - goSigStack gsignalStack // Go-allocated signal handling stack - sigmask sigset // storage for saved signal mask - tls [tlsSlots]uintptr // thread-local storage (for x86 extern register) - mstartfn func() - curg *g // current running goroutine - caughtsig guintptr // goroutine running during fatal signal - p puintptr // attached p for executing go code (nil if not executing go code) - nextp puintptr - oldp puintptr // the p that was attached before executing a syscall - id int64 - mallocing int32 - throwing throwType - preemptoff string // if != "", keep curg running on this m - locks int32 - dying int32 - profilehz int32 - spinning bool // m is out of work and is actively looking for work - blocked bool // m is blocked on a note - newSigstack bool // minit on C thread called sigaltstack - printlock int8 - incgo bool // m is executing a cgo call - isextra bool // m is an extra m - isExtraInC bool // m is an extra m that is not executing Go code - isExtraInSig bool // m is an extra m in a signal handler - freeWait atomic.Uint32 // Whether it is safe to free g0 and delete m (one of freeMRef, freeMStack, freeMWait) - needextram bool - traceback uint8 - ncgocall uint64 // number of cgo calls in total - ncgo int32 // number of cgo calls currently in progress - cgoCallersUse atomic.Uint32 // if non-zero, cgoCallers in use temporarily - cgoCallers *cgoCallers // cgo traceback if crashing in cgo call - park note - alllink *m // on allm - schedlink muintptr - lockedg guintptr - createstack [32]uintptr // stack that created this thread, it's used for StackRecord.Stack0, so it must align with it. - lockedExt uint32 // tracking for external LockOSThread - lockedInt uint32 // tracking for internal lockOSThread - nextwaitm muintptr // next m waiting for lock + procid uint64 // for debuggers, but offset not hard-coded + gsignal *g // signal-handling g + goSigStack gsignalStack // Go-allocated signal handling stack + sigmask sigset // storage for saved signal mask + tls [tlsSlots]uintptr // thread-local storage (for x86 extern register) + mstartfn func() + curg *g // current running goroutine + caughtsig guintptr // goroutine running during fatal signal + p puintptr // attached p for executing go code (nil if not executing go code) + nextp puintptr + oldp puintptr // the p that was attached before executing a syscall + id int64 + mallocing int32 + throwing throwType + preemptoff string // if != "", keep curg running on this m + locks int32 + dying int32 + profilehz int32 + spinning bool // m is out of work and is actively looking for work + blocked bool // m is blocked on a note + newSigstack bool // minit on C thread called sigaltstack + printlock int8 + incgo bool // m is executing a cgo call + isextra bool // m is an extra m + isExtraInC bool // m is an extra m that does not have any Go frames + isExtraInSig bool // m is an extra m in a signal handler + freeWait atomic.Uint32 // Whether it is safe to free g0 and delete m (one of freeMRef, freeMStack, freeMWait) + needextram bool + g0StackAccurate bool // whether the g0 stack has accurate bounds + traceback uint8 + ncgocall uint64 // number of cgo calls in total + ncgo int32 // number of cgo calls currently in progress + cgoCallersUse atomic.Uint32 // if non-zero, cgoCallers in use temporarily + cgoCallers *cgoCallers // cgo traceback if crashing in cgo call + park note + alllink *m // on allm + schedlink muintptr + lockedg guintptr + createstack [32]uintptr // stack that created this thread, it's used for StackRecord.Stack0, so it must align with it. + lockedExt uint32 // tracking for external LockOSThread + lockedInt uint32 // tracking for internal lockOSThread + nextwaitm muintptr // next m waiting for lock mLockProfile mLockProfile // fields relating to runtime.lock contention + profStack []uintptr // used for memory/block/mutex stack traces // wait* are used to carry arguments from gopark into park_m, because // there's no stack to put them on. That is their sole purpose. waitunlockf func(*g, unsafe.Pointer) bool waitlock unsafe.Pointer - waitTraceBlockReason traceBlockReason waitTraceSkip int + waitTraceBlockReason traceBlockReason syscalltick uint32 freelink *m // on sched.freem @@ -611,11 +615,11 @@ type m struct { // these are here because they are too large to be on the stack // of low-level NOSPLIT functions. - libcall libcall - libcallpc uintptr // for cpu profiler - libcallsp uintptr - libcallg guintptr - syscall libcall // stores syscall parameters on windows + libcall libcall + libcallpc uintptr // for cpu profiler + libcallsp uintptr + libcallg guintptr + winsyscall winlibcall // stores syscall parameters on windows vdsoSP uintptr // SP for traceback while in VDSO call (0 if not in call) vdsoPC uintptr // PC for traceback while in VDSO call @@ -708,16 +712,6 @@ type p struct { palloc persistentAlloc // per-P to avoid mutex - // The when field of the first entry on the timer heap. - // This is 0 if the timer heap is empty. - timer0When atomic.Int64 - - // The earliest known nextwhen field of a timer with - // timerModifiedEarlier status. Because the timer may have been - // modified again, there need not be any timer with this value. - // This is 0 if there are no timerModifiedEarlier timers. - timerModifiedEarliest atomic.Int64 - // Per-P GC state gcAssistTime int64 // Nanoseconds in assistAlloc gcFractionalMarkTime int64 // Nanoseconds in fractional mark worker (atomic) @@ -751,23 +745,8 @@ type p struct { // writing any stats. Its value is even when not, odd when it is. statsSeq atomic.Uint32 - // Lock for timers. We normally access the timers while running - // on this P, but the scheduler can also do it from a different P. - timersLock mutex - - // Actions to take at some time. This is used to implement the - // standard library's time package. - // Must hold timersLock to access. - timers []*timer - - // Number of timers in P's heap. - numTimers atomic.Uint32 - - // Number of timerDeleted timers in P's heap. - deletedTimers atomic.Uint32 - - // Race context used while executing timer functions. - timerRaceCtx uintptr + // Timer heap. + timers timers // maxStackScanDelta accumulates the amount of stack space held by // live goroutines (i.e. those eligible for stack scanning). @@ -787,10 +766,8 @@ type p struct { // scheduler ASAP (regardless of what G is running on it). preempt bool - // pageTraceBuf is a buffer for writing out page allocation/free/scavenge traces. - // - // Used only if GOEXPERIMENT=pagetrace. - pageTraceBuf pageTraceBuf + // gcStopTime is the nanotime timestamp that this P last entered _Pgcstop. + gcStopTime int64 // Padding is no longer needed. False sharing is now not a worry because p is large enough // that its size class is an integer multiple of the cache line size (for any of our architectures). @@ -990,17 +967,7 @@ type funcinl struct { startLine int32 } -// layout of Itab known to compilers -// allocated in non-garbage-collected memory -// Needs to be in sync with -// ../cmd/compile/internal/reflectdata/reflect.go:/^func.WritePluginTable. -type itab struct { - inter *interfacetype - _type *_type - hash uint32 // copy of _type.hash. Used for type switches. - _ [4]byte - fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter. -} +type itab = abi.ITab // Lock-free stack node. // Also known to export_test.go. @@ -1129,6 +1096,7 @@ const ( waitReasonTraceProcStatus // "trace proc status" waitReasonPageTraceFlush // "page trace flush" waitReasonCoroutine // "coroutine" + waitReasonGCWeakToStrongWait // "GC weak to strong wait" ) var waitReasonStrings = [...]string{ @@ -1169,6 +1137,7 @@ var waitReasonStrings = [...]string{ waitReasonTraceProcStatus: "trace proc status", waitReasonPageTraceFlush: "page trace flush", waitReasonCoroutine: "coroutine", + waitReasonGCWeakToStrongWait: "GC weak to strong wait", } func (w waitReason) String() string { @@ -1184,6 +1153,29 @@ func (w waitReason) isMutexWait() bool { w == waitReasonSyncRWMutexLock } +func (w waitReason) isWaitingForGC() bool { + return isWaitingForGC[w] +} + +// isWaitingForGC indicates that a goroutine is only entering _Gwaiting and +// setting a waitReason because it needs to be able to let the GC take ownership +// of its stack. The G is always actually executing on the system stack, in +// these cases. +// +// TODO(mknyszek): Consider replacing this with a new dedicated G status. +var isWaitingForGC = [len(waitReasonStrings)]bool{ + waitReasonStoppingTheWorld: true, + waitReasonGCMarkTermination: true, + waitReasonGarbageCollection: true, + waitReasonGarbageCollectionScan: true, + waitReasonTraceGoroutineStatus: true, + waitReasonTraceProcStatus: true, + waitReasonPageTraceFlush: true, + waitReasonGCAssistMarking: true, + waitReasonGCWorkerActive: true, + waitReasonFlushProcCaches: true, +} + var ( allm *m gomaxprocs int32 @@ -1191,13 +1183,17 @@ var ( forcegc forcegcstate sched schedt newprocs int32 +) +var ( // allpLock protects P-less reads and size changes of allp, idlepMask, // and timerpMask, and all writes to allp. allpLock mutex + // len(allp) == gomaxprocs; may change at safe points, otherwise // immutable. allp []*p + // Bitmask of Ps in _Pidle list, one bit per P. Reads and writes must // be atomic. Length may change at safe points. // @@ -1209,10 +1205,41 @@ var ( // // N.B., procresize takes ownership of all Ps in stopTheWorldWithSema. idlepMask pMask + // Bitmask of Ps that may have a timer, one bit per P. Reads and writes // must be atomic. Length may change at safe points. + // + // Ideally, the timer mask would be kept immediately consistent on any timer + // operations. Unfortunately, updating a shared global data structure in the + // timer hot path adds too much overhead in applications frequently switching + // between no timers and some timers. + // + // As a compromise, the timer mask is updated only on pidleget / pidleput. A + // running P (returned by pidleget) may add a timer at any time, so its mask + // must be set. An idle P (passed to pidleput) cannot add new timers while + // idle, so if it has no timers at that time, its mask may be cleared. + // + // Thus, we get the following effects on timer-stealing in findrunnable: + // + // - Idle Ps with no timers when they go idle are never checked in findrunnable + // (for work- or timer-stealing; this is the ideal case). + // - Running Ps must always be checked. + // - Idle Ps whose timers are stolen must continue to be checked until they run + // again, even after timer expiration. + // + // When the P starts running again, the mask should be set, as a timer may be + // added at any time. + // + // TODO(prattmic): Additional targeted updates may improve the above cases. + // e.g., updating the mask when stealing a timer. timerpMask pMask +) + +// goarmsoftfp is used by runtime/cgo assembly. +// +//go:linkname goarmsoftfp +var ( // Pool of GC parked background workers. Entries are type // *gcBgMarkWorkerNode. gcBgMarkWorkerPool lfstack @@ -1226,8 +1253,21 @@ var ( // Set on startup in asm_{386,amd64}.s processorVersionInfo uint32 isIntel bool +) - // set by cmd/link on arm systems +// set by cmd/link on arm systems +// accessed using linkname by internal/runtime/atomic. +// +// goarm should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/creativeprojects/go-selfupdate +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname goarm +var ( goarm uint8 goarmsoftfp uint8 ) @@ -1240,3 +1280,17 @@ var ( // Must agree with internal/buildcfg.FramePointerEnabled. const framepointer_enabled = GOARCH == "amd64" || GOARCH == "arm64" + +// getcallerfp returns the frame pointer of the caller of the caller +// of this function. +// +//go:nosplit +//go:noinline +func getcallerfp() uintptr { + fp := getfp() // This frame's FP. + if fp != 0 { + fp = *(*uintptr)(unsafe.Pointer(fp)) // The caller's FP. + fp = *(*uintptr)(unsafe.Pointer(fp)) // The caller's caller's FP. + } + return fp +} diff --git a/contrib/go/_std_1.22/src/runtime/runtime_boring.go b/contrib/go/_std_1.23/src/runtime/runtime_boring.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/runtime_boring.go rename to contrib/go/_std_1.23/src/runtime/runtime_boring.go diff --git a/contrib/go/_std_1.22/src/runtime/rwmutex.go b/contrib/go/_std_1.23/src/runtime/rwmutex.go similarity index 90% rename from contrib/go/_std_1.22/src/runtime/rwmutex.go rename to contrib/go/_std_1.23/src/runtime/rwmutex.go index 34d8f675c179..4f9585f98d6b 100644 --- a/contrib/go/_std_1.22/src/runtime/rwmutex.go +++ b/contrib/go/_std_1.23/src/runtime/rwmutex.go @@ -5,7 +5,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" ) // This is a copy of sync/rwmutex.go rewritten to work in the runtime. @@ -26,7 +26,7 @@ type rwmutex struct { readerCount atomic.Int32 // number of pending readers readerWait atomic.Int32 // number of departing readers - readRank lockRank // semantic lock rank for read locking + readRank lockRank // semantic lock rank for read locking } // Lock ranking an rwmutex has two aspects: @@ -50,13 +50,13 @@ type rwmutex struct { // acquire of readRank for the duration of a read lock. // // The lock ranking must document this ordering: -// - readRankInternal is a leaf lock. -// - readRank is taken before readRankInternal. -// - writeRank is taken before readRankInternal. -// - readRank is placed in the lock order wherever a read lock of this rwmutex -// belongs. -// - writeRank is placed in the lock order wherever a write lock of this -// rwmutex belongs. +// - readRankInternal is a leaf lock. +// - readRank is taken before readRankInternal. +// - writeRank is taken before readRankInternal. +// - readRank is placed in the lock order wherever a read lock of this rwmutex +// belongs. +// - writeRank is placed in the lock order wherever a write lock of this +// rwmutex belongs. func (rw *rwmutex) init(readRank, readRankInternal, writeRank lockRank) { rw.readRank = readRank @@ -72,9 +72,7 @@ func (rw *rwmutex) rlock() { // things blocking on the lock may consume all of the Ps and // deadlock (issue #20903). Alternatively, we could drop the P // while sleeping. - acquirem() - - acquireLockRank(rw.readRank) + acquireLockRankAndM(rw.readRank) lockWithRankMayAcquire(&rw.rLock, getLockRank(&rw.rLock)) if rw.readerCount.Add(1) < 0 { @@ -116,8 +114,7 @@ func (rw *rwmutex) runlock() { unlock(&rw.rLock) } } - releaseLockRank(rw.readRank) - releasem(getg().m) + releaseLockRankAndM(rw.readRank) } // lock locks rw for writing. diff --git a/contrib/go/_std_1.22/src/runtime/security_aix.go b/contrib/go/_std_1.23/src/runtime/security_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/security_aix.go rename to contrib/go/_std_1.23/src/runtime/security_aix.go diff --git a/contrib/go/_std_1.22/src/runtime/security_issetugid.go b/contrib/go/_std_1.23/src/runtime/security_issetugid.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/security_issetugid.go rename to contrib/go/_std_1.23/src/runtime/security_issetugid.go diff --git a/contrib/go/_std_1.22/src/runtime/security_linux.go b/contrib/go/_std_1.23/src/runtime/security_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/security_linux.go rename to contrib/go/_std_1.23/src/runtime/security_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/security_nonunix.go b/contrib/go/_std_1.23/src/runtime/security_nonunix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/security_nonunix.go rename to contrib/go/_std_1.23/src/runtime/security_nonunix.go diff --git a/contrib/go/_std_1.22/src/runtime/security_unix.go b/contrib/go/_std_1.23/src/runtime/security_unix.go similarity index 89% rename from contrib/go/_std_1.22/src/runtime/security_unix.go rename to contrib/go/_std_1.23/src/runtime/security_unix.go index fa54090df248..6ef3b5b328c6 100644 --- a/contrib/go/_std_1.22/src/runtime/security_unix.go +++ b/contrib/go/_std_1.23/src/runtime/security_unix.go @@ -6,6 +6,10 @@ package runtime +import ( + "internal/stringslite" +) + func secure() { initSecureMode() @@ -25,7 +29,7 @@ func secure() { func secureEnv() { var hasTraceback bool for i := 0; i < len(envs); i++ { - if hasPrefix(envs[i], "GOTRACEBACK=") { + if stringslite.HasPrefix(envs[i], "GOTRACEBACK=") { hasTraceback = true envs[i] = "GOTRACEBACK=none" } diff --git a/contrib/go/_std_1.22/src/runtime/select.go b/contrib/go/_std_1.23/src/runtime/select.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/select.go rename to contrib/go/_std_1.23/src/runtime/select.go index b3a3085cb03b..17c49d7484a3 100644 --- a/contrib/go/_std_1.22/src/runtime/select.go +++ b/contrib/go/_std_1.23/src/runtime/select.go @@ -173,6 +173,10 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo continue } + if cas.c.timer != nil { + cas.c.timer.maybeRunChan() + } + j := cheaprandn(uint32(norder + 1)) pollorder[norder] = pollorder[j] pollorder[j] = uint16(i) @@ -315,6 +319,10 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo } else { c.recvq.enqueue(sg) } + + if c.timer != nil { + blockTimerChan(c) + } } // wait for someone to wake us up @@ -351,6 +359,9 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo for _, casei := range lockorder { k = &scases[casei] + if k.c.timer != nil { + unblockTimerChan(k.c) + } if sg == sglist { // sg has already been dequeued by the G that woke us up. casi = int(casei) diff --git a/contrib/go/_std_1.22/src/runtime/sema.go b/contrib/go/_std_1.23/src/runtime/sema.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/sema.go rename to contrib/go/_std_1.23/src/runtime/sema.go index c87fc7658e9a..f6b1b84f5f12 100644 --- a/contrib/go/_std_1.22/src/runtime/sema.go +++ b/contrib/go/_std_1.23/src/runtime/sema.go @@ -21,7 +21,7 @@ package runtime import ( "internal/cpu" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -57,6 +57,15 @@ func (t *semTable) rootFor(addr *uint32) *semaRoot { return &t[(uintptr(unsafe.Pointer(addr))>>3)%semTabSize].root } +// sync_runtime_Semacquire should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// - github.com/sagernet/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname sync_runtime_Semacquire sync.runtime_Semacquire func sync_runtime_Semacquire(addr *uint32) { semacquire1(addr, false, semaBlockProfile, 0, waitReasonSemacquire) @@ -67,6 +76,15 @@ func poll_runtime_Semacquire(addr *uint32) { semacquire1(addr, false, semaBlockProfile, 0, waitReasonSemacquire) } +// sync_runtime_Semrelease should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gvisor.dev/gvisor +// - github.com/sagernet/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname sync_runtime_Semrelease sync.runtime_Semrelease func sync_runtime_Semrelease(addr *uint32, handoff bool, skipframes int) { semrelease1(addr, handoff, skipframes) diff --git a/contrib/go/_std_1.22/src/runtime/sigaction.go b/contrib/go/_std_1.23/src/runtime/sigaction.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sigaction.go rename to contrib/go/_std_1.23/src/runtime/sigaction.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_386.go b/contrib/go/_std_1.23/src/runtime/signal_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_386.go rename to contrib/go/_std_1.23/src/runtime/signal_386.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_aix_ppc64.go b/contrib/go/_std_1.23/src/runtime/signal_aix_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_aix_ppc64.go rename to contrib/go/_std_1.23/src/runtime/signal_aix_ppc64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_arm.go b/contrib/go/_std_1.23/src/runtime/signal_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_arm.go rename to contrib/go/_std_1.23/src/runtime/signal_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_arm64.go b/contrib/go/_std_1.23/src/runtime/signal_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_arm64.go rename to contrib/go/_std_1.23/src/runtime/signal_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_darwin.go b/contrib/go/_std_1.23/src/runtime/signal_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_darwin.go rename to contrib/go/_std_1.23/src/runtime/signal_darwin.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_darwin_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_darwin_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_darwin_arm64.go b/contrib/go/_std_1.23/src/runtime/signal_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_darwin_arm64.go rename to contrib/go/_std_1.23/src/runtime/signal_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_dragonfly.go b/contrib/go/_std_1.23/src/runtime/signal_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_dragonfly.go rename to contrib/go/_std_1.23/src/runtime/signal_dragonfly.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_dragonfly_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_dragonfly_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_dragonfly_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_dragonfly_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_freebsd.go b/contrib/go/_std_1.23/src/runtime/signal_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_freebsd.go rename to contrib/go/_std_1.23/src/runtime/signal_freebsd.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_freebsd_386.go b/contrib/go/_std_1.23/src/runtime/signal_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_freebsd_386.go rename to contrib/go/_std_1.23/src/runtime/signal_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_freebsd_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_freebsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_freebsd_arm.go b/contrib/go/_std_1.23/src/runtime/signal_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_freebsd_arm.go rename to contrib/go/_std_1.23/src/runtime/signal_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_freebsd_arm64.go b/contrib/go/_std_1.23/src/runtime/signal_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_freebsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/signal_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_freebsd_riscv64.go b/contrib/go/_std_1.23/src/runtime/signal_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/runtime/signal_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_386.go b/contrib/go/_std_1.23/src/runtime/signal_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_386.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_386.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_linux_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_arm.go b/contrib/go/_std_1.23/src/runtime/signal_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_arm.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_arm64.go b/contrib/go/_std_1.23/src/runtime/signal_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_arm64.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_loong64.go b/contrib/go/_std_1.23/src/runtime/signal_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_loong64.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_mips64x.go b/contrib/go/_std_1.23/src/runtime/signal_linux_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_mips64x.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_mips64x.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_mipsx.go b/contrib/go/_std_1.23/src/runtime/signal_linux_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_mipsx.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_mipsx.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_ppc64x.go b/contrib/go/_std_1.23/src/runtime/signal_linux_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_ppc64x.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_riscv64.go b/contrib/go/_std_1.23/src/runtime/signal_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_riscv64.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_linux_s390x.go b/contrib/go/_std_1.23/src/runtime/signal_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_linux_s390x.go rename to contrib/go/_std_1.23/src/runtime/signal_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_loong64.go b/contrib/go/_std_1.23/src/runtime/signal_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_loong64.go rename to contrib/go/_std_1.23/src/runtime/signal_loong64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_mips64x.go b/contrib/go/_std_1.23/src/runtime/signal_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_mips64x.go rename to contrib/go/_std_1.23/src/runtime/signal_mips64x.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_mipsx.go b/contrib/go/_std_1.23/src/runtime/signal_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_mipsx.go rename to contrib/go/_std_1.23/src/runtime/signal_mipsx.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_netbsd.go b/contrib/go/_std_1.23/src/runtime/signal_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_netbsd.go rename to contrib/go/_std_1.23/src/runtime/signal_netbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_netbsd_386.go b/contrib/go/_std_1.23/src/runtime/signal_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_netbsd_386.go rename to contrib/go/_std_1.23/src/runtime/signal_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_netbsd_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_netbsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_netbsd_arm.go b/contrib/go/_std_1.23/src/runtime/signal_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_netbsd_arm.go rename to contrib/go/_std_1.23/src/runtime/signal_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_netbsd_arm64.go b/contrib/go/_std_1.23/src/runtime/signal_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_netbsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/signal_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd_386.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd_386.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd_386.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd_arm.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd_arm.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd_arm64.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd_mips64.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd_mips64.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd_ppc64.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd_ppc64.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd_ppc64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_openbsd_riscv64.go b/contrib/go/_std_1.23/src/runtime/signal_openbsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_openbsd_riscv64.go rename to contrib/go/_std_1.23/src/runtime/signal_openbsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_plan9.go b/contrib/go/_std_1.23/src/runtime/signal_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_plan9.go rename to contrib/go/_std_1.23/src/runtime/signal_plan9.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_ppc64x.go b/contrib/go/_std_1.23/src/runtime/signal_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_ppc64x.go rename to contrib/go/_std_1.23/src/runtime/signal_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_riscv64.go b/contrib/go/_std_1.23/src/runtime/signal_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_riscv64.go rename to contrib/go/_std_1.23/src/runtime/signal_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_solaris.go b/contrib/go/_std_1.23/src/runtime/signal_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_solaris.go rename to contrib/go/_std_1.23/src/runtime/signal_solaris.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_solaris_amd64.go b/contrib/go/_std_1.23/src/runtime/signal_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_solaris_amd64.go rename to contrib/go/_std_1.23/src/runtime/signal_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/signal_unix.go b/contrib/go/_std_1.23/src/runtime/signal_unix.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/signal_unix.go rename to contrib/go/_std_1.23/src/runtime/signal_unix.go index 84391d58ed7f..6f40f440e807 100644 --- a/contrib/go/_std_1.22/src/runtime/signal_unix.go +++ b/contrib/go/_std_1.23/src/runtime/signal_unix.go @@ -8,7 +8,7 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -605,6 +605,19 @@ var crashing atomic.Int32 var testSigtrap func(info *siginfo, ctxt *sigctxt, gp *g) bool var testSigusr1 func(gp *g) bool +// sigsysIgnored is non-zero if we are currently ignoring SIGSYS. See issue #69065. +var sigsysIgnored uint32 + +//go:linkname ignoreSIGSYS os.ignoreSIGSYS +func ignoreSIGSYS() { + atomic.Store(&sigsysIgnored, 1) +} + +//go:linkname restoreSIGSYS os.restoreSIGSYS +func restoreSIGSYS() { + atomic.Store(&sigsysIgnored, 0) +} + // sighandler is invoked when a signal occurs. The global g will be // set to a gsignal goroutine and we will be running on the alternate // signal stack. The parameter gp will be the value of the global g @@ -715,6 +728,10 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) { return } + if sig == _SIGSYS && c.sigFromSeccomp() && atomic.Load(&sigsysIgnored) != 0 { + return + } + if flags&_SigKill != 0 { dieFromSignal(sig) } @@ -752,6 +769,9 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) { } if docrash { + var crashSleepMicros uint32 = 5000 + var watchdogTimeoutMicros uint32 = 2000 * crashSleepMicros + isCrashThread := false if crashing.CompareAndSwap(0, 1) { isCrashThread = true @@ -769,19 +789,35 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) { // The faulting m is crashing first so it is the faulting thread in the core dump (see issue #63277): // in expected operation, the first m will wait until the last m has received the SIGQUIT, // and then run crash/exit and the process is gone. - // However, if it spends more than 5 seconds to send SIGQUIT to all ms, - // any of ms may crash/exit the process after waiting for 5 seconds. + // However, if it spends more than 10 seconds to send SIGQUIT to all ms, + // any of ms may crash/exit the process after waiting for 10 seconds. print("\n-----\n\n") raiseproc(_SIGQUIT) } if isCrashThread { - i := 0 - for (crashing.Load() < mcount()-int32(extraMLength.Load())) && i < 10 { - i++ - usleep(500 * 1000) + // Sleep for short intervals so that we can crash quickly after all ms have received SIGQUIT. + // Reset the timer whenever we see more ms received SIGQUIT + // to make it have enough time to crash (see issue #64752). + timeout := watchdogTimeoutMicros + maxCrashing := crashing.Load() + for timeout > 0 && (crashing.Load() < mcount()-int32(extraMLength.Load())) { + usleep(crashSleepMicros) + timeout -= crashSleepMicros + + if c := crashing.Load(); c > maxCrashing { + // We make progress, so reset the watchdog timeout + maxCrashing = c + timeout = watchdogTimeoutMicros + } } } else { - usleep(5 * 1000 * 1000) + maxCrashing := int32(0) + c := crashing.Load() + for c > maxCrashing { + maxCrashing = c + usleep(watchdogTimeoutMicros) + c = crashing.Load() + } } printDebugLog() crash() @@ -953,10 +989,17 @@ func raisebadsignal(sig uint32, c *sigctxt) { } var handler uintptr + var flags int32 if sig >= _NSIG { handler = _SIG_DFL } else { handler = atomic.Loaduintptr(&fwdSig[sig]) + flags = sigtable[sig].flags + } + + // If the signal is ignored, raising the signal is no-op. + if handler == _SIG_IGN || (handler == _SIG_DFL && flags&_SigIgn != 0) { + return } // Reset the signal handler and raise the signal. diff --git a/contrib/go/_std_1.22/src/runtime/signal_windows.go b/contrib/go/_std_1.23/src/runtime/signal_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/signal_windows.go rename to contrib/go/_std_1.23/src/runtime/signal_windows.go diff --git a/contrib/go/_std_1.22/src/runtime/sigqueue.go b/contrib/go/_std_1.23/src/runtime/sigqueue.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/sigqueue.go rename to contrib/go/_std_1.23/src/runtime/sigqueue.go index 51e424d55b64..62a8e8a70226 100644 --- a/contrib/go/_std_1.22/src/runtime/sigqueue.go +++ b/contrib/go/_std_1.23/src/runtime/sigqueue.go @@ -33,7 +33,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" _ "unsafe" // for go:linkname ) diff --git a/contrib/go/_std_1.22/src/runtime/sigqueue_note.go b/contrib/go/_std_1.23/src/runtime/sigqueue_note.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sigqueue_note.go rename to contrib/go/_std_1.23/src/runtime/sigqueue_note.go diff --git a/contrib/go/_std_1.22/src/runtime/sigqueue_plan9.go b/contrib/go/_std_1.23/src/runtime/sigqueue_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sigqueue_plan9.go rename to contrib/go/_std_1.23/src/runtime/sigqueue_plan9.go diff --git a/contrib/go/_std_1.22/src/runtime/sigtab_aix.go b/contrib/go/_std_1.23/src/runtime/sigtab_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sigtab_aix.go rename to contrib/go/_std_1.23/src/runtime/sigtab_aix.go diff --git a/contrib/go/_std_1.22/src/runtime/sigtab_linux_generic.go b/contrib/go/_std_1.23/src/runtime/sigtab_linux_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sigtab_linux_generic.go rename to contrib/go/_std_1.23/src/runtime/sigtab_linux_generic.go diff --git a/contrib/go/_std_1.22/src/runtime/sigtab_linux_mipsx.go b/contrib/go/_std_1.23/src/runtime/sigtab_linux_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sigtab_linux_mipsx.go rename to contrib/go/_std_1.23/src/runtime/sigtab_linux_mipsx.go diff --git a/contrib/go/_std_1.22/src/runtime/sizeclasses.go b/contrib/go/_std_1.23/src/runtime/sizeclasses.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/sizeclasses.go rename to contrib/go/_std_1.23/src/runtime/sizeclasses.go index 931462345311..bbcaa9e983fd 100644 --- a/contrib/go/_std_1.22/src/runtime/sizeclasses.go +++ b/contrib/go/_std_1.23/src/runtime/sizeclasses.go @@ -82,6 +82,7 @@ package runtime // 8192 13 32768 const ( + minHeapAlign = 8 _MaxSmallSize = 32768 smallSizeDiv = 8 smallSizeMax = 1024 diff --git a/contrib/go/_std_1.22/src/runtime/slice.go b/contrib/go/_std_1.23/src/runtime/slice.go similarity index 90% rename from contrib/go/_std_1.22/src/runtime/slice.go rename to contrib/go/_std_1.23/src/runtime/slice.go index eb628bb1694c..78475735af3d 100644 --- a/contrib/go/_std_1.22/src/runtime/slice.go +++ b/contrib/go/_std_1.23/src/runtime/slice.go @@ -53,7 +53,7 @@ func makeslicecopy(et *_type, tolen int, fromlen int, from unsafe.Pointer) unsaf } var to unsafe.Pointer - if et.PtrBytes == 0 { + if !et.Pointers() { to = mallocgc(tomem, nil, false) if copymem < tomem { memclrNoHeapPointers(add(to, copymem), tomem-copymem) @@ -89,6 +89,15 @@ func makeslicecopy(et *_type, tolen int, fromlen int, from unsafe.Pointer) unsaf return to } +// makeslice should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname makeslice func makeslice(et *_type, len, cap int) unsafe.Pointer { mem, overflow := math.MulUintptr(et.Size_, uintptr(cap)) if overflow || mem > maxAlloc || len < 0 || len > cap { @@ -152,6 +161,19 @@ func makeslice64(et *_type, len64, cap64 int64) unsafe.Pointer { // new length so that the old length is not live (does not need to be // spilled/restored) and the new length is returned (also does not need // to be spilled/restored). +// +// growslice should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/chenzhuoyu/iasm +// - github.com/cloudwego/dynamicgo +// - github.com/ugorji/go/codec +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname growslice func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice { oldLen := newLen - num if raceenabled { @@ -183,7 +205,7 @@ func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice // For 1 we don't need any division/multiplication. // For goarch.PtrSize, compiler will optimize division/multiplication into a shift by a constant. // For powers of 2, use a variable shift. - noscan := et.PtrBytes == 0 + noscan := !et.Pointers() switch { case et.Size_ == 1: lenmem = uintptr(oldLen) @@ -238,7 +260,7 @@ func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice } var p unsafe.Pointer - if et.PtrBytes == 0 { + if !et.Pointers() { p = mallocgc(capmem, nil, false) // The append() that calls growslice is going to overwrite from oldLen to newLen. // Only clear the part that will not be overwritten. @@ -298,6 +320,14 @@ func nextslicecap(newLen, oldCap int) int { return newcap } +// reflect_growslice should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/dynamicgo +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname reflect_growslice reflect.growslice func reflect_growslice(et *_type, old slice, num int) slice { // Semantically equivalent to slices.Grow, except that the caller @@ -308,7 +338,7 @@ func reflect_growslice(et *_type, old slice, num int) slice { // the memory will be overwritten by an append() that called growslice. // Since the caller of reflect_growslice is not append(), // zero out this region before returning the slice to the reflect package. - if et.PtrBytes == 0 { + if !et.Pointers() { oldcapmem := uintptr(old.cap) * et.Size_ newlenmem := uintptr(new.len) * et.Size_ memclrNoHeapPointers(add(new.array, oldcapmem), newlenmem-oldcapmem) @@ -366,5 +396,6 @@ func bytealg_MakeNoZero(len int) []byte { if uintptr(len) > maxAlloc { panicmakeslicelen() } - return unsafe.Slice((*byte)(mallocgc(uintptr(len), nil, false)), len) + cap := roundupsize(uintptr(len), true) + return unsafe.Slice((*byte)(mallocgc(uintptr(cap), nil, false)), cap)[:len] } diff --git a/contrib/go/_std_1.22/src/runtime/softfloat64.go b/contrib/go/_std_1.23/src/runtime/softfloat64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/softfloat64.go rename to contrib/go/_std_1.23/src/runtime/softfloat64.go diff --git a/contrib/go/_std_1.22/src/runtime/stack.go b/contrib/go/_std_1.23/src/runtime/stack.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/stack.go rename to contrib/go/_std_1.23/src/runtime/stack.go index 61cd0a0fddd6..d43c6ace4ffc 100644 --- a/contrib/go/_std_1.22/src/runtime/stack.go +++ b/contrib/go/_std_1.23/src/runtime/stack.go @@ -9,7 +9,7 @@ import ( "internal/cpu" "internal/goarch" "internal/goos" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -69,7 +69,7 @@ const ( // to each stack below the usual guard area for OS-specific // purposes like signal handling. Used on Windows, Plan 9, // and iOS because they do not use a separate stack. - stackSystem = goos.IsWindows*512*goarch.PtrSize + goos.IsPlan9*512 + goos.IsIos*goarch.IsArm64*1024 + stackSystem = goos.IsWindows*4096 + goos.IsPlan9*512 + goos.IsIos*goarch.IsArm64*1024 // The minimum size of stack used by Go code stackMin = 2048 @@ -415,6 +415,13 @@ func stackalloc(n uint32) stack { v = unsafe.Pointer(s.base()) } + if traceAllocFreeEnabled() { + trace := traceTryAcquire() + if trace.ok() { + trace.GoroutineStackAlloc(uintptr(v), uintptr(n)) + traceRelease(trace) + } + } if raceenabled { racemalloc(v, uintptr(n)) } @@ -458,6 +465,13 @@ func stackfree(stk stack) { } return } + if traceAllocFreeEnabled() { + trace := traceTryAcquire() + if trace.ok() { + trace.GoroutineStackFree(uintptr(v)) + traceRelease(trace) + } + } if msanenabled { msanfree(v, n) } @@ -1136,21 +1150,40 @@ func gostartcallfn(gobuf *gobuf, fv *funcval) { // isShrinkStackSafe returns whether it's safe to attempt to shrink // gp's stack. Shrinking the stack is only safe when we have precise -// pointer maps for all frames on the stack. +// pointer maps for all frames on the stack. The caller must hold the +// _Gscan bit for gp or must be running gp itself. func isShrinkStackSafe(gp *g) bool { // We can't copy the stack if we're in a syscall. // The syscall might have pointers into the stack and // often we don't have precise pointer maps for the innermost // frames. - // + if gp.syscallsp != 0 { + return false + } // We also can't copy the stack if we're at an asynchronous // safe-point because we don't have precise pointer maps for // all frames. - // + if gp.asyncSafePoint { + return false + } // We also can't *shrink* the stack in the window between the // goroutine calling gopark to park on a channel and // gp.activeStackChans being set. - return gp.syscallsp == 0 && !gp.asyncSafePoint && !gp.parkingOnChan.Load() + if gp.parkingOnChan.Load() { + return false + } + // We also can't copy the stack while tracing is enabled, and + // gp is in _Gwaiting solely to make itself available to the GC. + // In these cases, the G is actually executing on the system + // stack, and the execution tracer may want to take a stack trace + // of the G's stack. Note: it's safe to access gp.waitreason here. + // We're only checking if this is true if we took ownership of the + // G with the _Gscan bit. This prevents the goroutine from transitioning, + // which prevents gp.waitreason from changing. + if traceEnabled() && readgstatus(gp)&^_Gscan == _Gwaiting && gp.waitreason.isWaitingForGC() { + return false + } + return true } // Maybe shrink the stack being used by gp. @@ -1297,7 +1330,7 @@ func morestackc() { } // startingStackSize is the amount of stack that new goroutines start with. -// It is a power of 2, and between _FixedStack and maxstacksize, inclusive. +// It is a power of 2, and between fixedStack and maxstacksize, inclusive. // startingStackSize is updated every GC by tracking the average size of // stacks scanned during the GC. var startingStackSize uint32 = fixedStack diff --git a/contrib/go/_std_1.22/src/runtime/stkframe.go b/contrib/go/_std_1.23/src/runtime/stkframe.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/stkframe.go rename to contrib/go/_std_1.23/src/runtime/stkframe.go index becb729e598a..42b69477511d 100644 --- a/contrib/go/_std_1.22/src/runtime/stkframe.go +++ b/contrib/go/_std_1.23/src/runtime/stkframe.go @@ -264,7 +264,7 @@ var methodValueCallFrameObjs [1]stackObjectRecord // initialized in stackobjecti func stkobjinit() { var abiRegArgsEface any = abi.RegArgs{} abiRegArgsType := efaceOf(&abiRegArgsEface)._type - if abiRegArgsType.Kind_&kindGCProg != 0 { + if abiRegArgsType.Kind_&abi.KindGCProg != 0 { throw("abiRegArgsType needs GC Prog, update methodValueCallFrameObjs") } // Set methodValueCallFrameObjs[0].gcdataoff so that diff --git a/contrib/go/_std_1.22/src/runtime/string.go b/contrib/go/_std_1.23/src/runtime/string.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/string.go rename to contrib/go/_std_1.23/src/runtime/string.go index e01b7fc74448..5bdb25b9db7c 100644 --- a/contrib/go/_std_1.22/src/runtime/string.go +++ b/contrib/go/_std_1.23/src/runtime/string.go @@ -78,6 +78,16 @@ func concatstring5(buf *tmpBuf, a0, a1, a2, a3, a4 string) string { // n is the length of the slice. // Buf is a fixed-size buffer for the result, // it is not nil if the result does not escape. +// +// slicebytetostring should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname slicebytetostring func slicebytetostring(buf *tmpBuf, ptr *byte, n int) string { if n == 0 { // Turns out to be a relatively common case. @@ -312,7 +322,7 @@ func gobytes(p *byte, n int) (b []byte) { return } -// This is exported via linkname to assembly in syscall (for Plan9). +// This is exported via linkname to assembly in syscall (for Plan9) and cgo. // //go:linkname gostring func gostring(p *byte) string { @@ -341,14 +351,6 @@ func gostringn(p *byte, l int) string { return s } -func hasPrefix(s, prefix string) bool { - return len(s) >= len(prefix) && s[:len(prefix)] == prefix -} - -func hasSuffix(s, suffix string) bool { - return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix -} - const ( maxUint64 = ^uint64(0) maxInt64 = int64(maxUint64 >> 1) diff --git a/contrib/go/_std_1.22/src/runtime/stubs.go b/contrib/go/_std_1.23/src/runtime/stubs.go similarity index 85% rename from contrib/go/_std_1.22/src/runtime/stubs.go rename to contrib/go/_std_1.23/src/runtime/stubs.go index 34984d86ffaf..2aeb4774b972 100644 --- a/contrib/go/_std_1.22/src/runtime/stubs.go +++ b/contrib/go/_std_1.23/src/runtime/stubs.go @@ -11,6 +11,15 @@ import ( // Should be a built-in for unsafe.Pointer? // +// add should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - fortio.org/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname add //go:nosplit func add(p unsafe.Pointer, x uintptr) unsafe.Pointer { return unsafe.Pointer(uintptr(p) + x) @@ -83,6 +92,19 @@ func badsystemstack() { // // The (CPU-specific) implementations of this function are in memclr_*.s. // +// memclrNoHeapPointers should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/chenzhuoyu/iasm +// - github.com/cloudwego/frugal +// - github.com/dgraph-io/ristretto +// - github.com/outcaste-io/ristretto +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname memclrNoHeapPointers //go:noescape func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) @@ -103,12 +125,26 @@ func reflect_memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) { // // Implementations are in memmove_*.s. // -//go:noescape -func memmove(to, from unsafe.Pointer, n uintptr) - -// Outside assembly calls memmove. Make sure it has ABI wrappers. +// Outside assembly calls memmove. +// +// memmove should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/dynamicgo +// - github.com/cloudwego/frugal +// - github.com/ebitengine/purego +// - github.com/tetratelabs/wazero +// - github.com/ugorji/go/codec +// - gvisor.dev/gvisor +// - github.com/sagernet/gvisor +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. // //go:linkname memmove +//go:noescape +func memmove(to, from unsafe.Pointer, n uintptr) //go:linkname reflect_memmove reflect.memmove func reflect_memmove(to, from unsafe.Pointer, n uintptr) { @@ -120,6 +156,15 @@ const hashLoad = float32(loadFactorNum) / float32(loadFactorDen) // in internal/bytealg/equal_*.s // +// memequal should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname memequal //go:noescape func memequal(a, b unsafe.Pointer, size uintptr) bool @@ -129,6 +174,19 @@ func memequal(a, b unsafe.Pointer, size uintptr) bool // compiles down to zero instructions. // USE CAREFULLY! // +// noescape should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/ebitengine/purego +// - github.com/hamba/avro/v2 +// - github.com/puzpuzpuz/xsync/v3 +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname noescape //go:nosplit func noescape(p unsafe.Pointer) unsafe.Pointer { x := uintptr(p) @@ -207,6 +265,17 @@ func breakpoint() //go:noescape func reflectcall(stackArgsType *_type, fn, stackArgs unsafe.Pointer, stackArgsSize, stackRetOffset, frameSize uint32, regArgs *abi.RegArgs) +// procyield should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/sagernet/sing-tun +// - github.com/slackhq/nebula +// - github.com/tailscale/wireguard-go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname procyield func procyield(cycles uint32) type neverCallThisFunction struct{} @@ -295,7 +364,18 @@ func getclosureptr() uintptr func asmcgocall(fn, arg unsafe.Pointer) int32 func morestack() + +// morestack_noctxt should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname morestack_noctxt func morestack_noctxt() + func rt0_go() // return0 is a stub used to return 0 from deferproc. @@ -380,7 +460,19 @@ func abort() // Called from compiled code; declared for vet; do NOT call from Go. func gcWriteBarrier1() + +// gcWriteBarrier2 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/sonic +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname gcWriteBarrier2 func gcWriteBarrier2() + func gcWriteBarrier3() func gcWriteBarrier4() func gcWriteBarrier5() diff --git a/contrib/go/_std_1.22/src/runtime/stubs2.go b/contrib/go/_std_1.23/src/runtime/stubs2.go similarity index 97% rename from contrib/go/_std_1.22/src/runtime/stubs2.go rename to contrib/go/_std_1.23/src/runtime/stubs2.go index 9637347a3555..39bde15b1caa 100644 --- a/contrib/go/_std_1.22/src/runtime/stubs2.go +++ b/contrib/go/_std_1.23/src/runtime/stubs2.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/stubs3.go b/contrib/go/_std_1.23/src/runtime/stubs3.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs3.go rename to contrib/go/_std_1.23/src/runtime/stubs3.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_386.go b/contrib/go/_std_1.23/src/runtime/stubs_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_386.go rename to contrib/go/_std_1.23/src/runtime/stubs_386.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_amd64.go b/contrib/go/_std_1.23/src/runtime/stubs_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_amd64.go rename to contrib/go/_std_1.23/src/runtime/stubs_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_arm.go b/contrib/go/_std_1.23/src/runtime/stubs_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_arm.go rename to contrib/go/_std_1.23/src/runtime/stubs_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_arm64.go b/contrib/go/_std_1.23/src/runtime/stubs_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_arm64.go rename to contrib/go/_std_1.23/src/runtime/stubs_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_linux.go b/contrib/go/_std_1.23/src/runtime/stubs_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_linux.go rename to contrib/go/_std_1.23/src/runtime/stubs_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_loong64.go b/contrib/go/_std_1.23/src/runtime/stubs_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_loong64.go rename to contrib/go/_std_1.23/src/runtime/stubs_loong64.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_mips64x.go b/contrib/go/_std_1.23/src/runtime/stubs_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_mips64x.go rename to contrib/go/_std_1.23/src/runtime/stubs_mips64x.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_mipsx.go b/contrib/go/_std_1.23/src/runtime/stubs_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_mipsx.go rename to contrib/go/_std_1.23/src/runtime/stubs_mipsx.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_nonlinux.go b/contrib/go/_std_1.23/src/runtime/stubs_nonlinux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_nonlinux.go rename to contrib/go/_std_1.23/src/runtime/stubs_nonlinux.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_ppc64.go b/contrib/go/_std_1.23/src/runtime/stubs_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_ppc64.go rename to contrib/go/_std_1.23/src/runtime/stubs_ppc64.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_ppc64x.go b/contrib/go/_std_1.23/src/runtime/stubs_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_ppc64x.go rename to contrib/go/_std_1.23/src/runtime/stubs_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_riscv64.go b/contrib/go/_std_1.23/src/runtime/stubs_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_riscv64.go rename to contrib/go/_std_1.23/src/runtime/stubs_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/stubs_s390x.go b/contrib/go/_std_1.23/src/runtime/stubs_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/stubs_s390x.go rename to contrib/go/_std_1.23/src/runtime/stubs_s390x.go diff --git a/contrib/go/_std_1.22/src/runtime/symtab.go b/contrib/go/_std_1.23/src/runtime/symtab.go similarity index 85% rename from contrib/go/_std_1.22/src/runtime/symtab.go rename to contrib/go/_std_1.23/src/runtime/symtab.go index edf800f5198e..10cdcf9c6ee8 100644 --- a/contrib/go/_std_1.22/src/runtime/symtab.go +++ b/contrib/go/_std_1.23/src/runtime/symtab.go @@ -7,7 +7,7 @@ package runtime import ( "internal/abi" "internal/goarch" - "runtime/internal/atomic" + "internal/runtime/atomic" "runtime/internal/sys" "unsafe" ) @@ -18,6 +18,9 @@ type Frames struct { // callers is a slice of PCs that have not yet been expanded to frames. callers []uintptr + // nextPC is a next PC to expand ahead of processing callers. + nextPC uintptr + // frames is a slice of Frames that have yet to be returned. frames []Frame frameStore [2]Frame @@ -96,8 +99,12 @@ func (ci *Frames) Next() (frame Frame, more bool) { if len(ci.callers) == 0 { break } - pc := ci.callers[0] - ci.callers = ci.callers[1:] + var pc uintptr + if ci.nextPC != 0 { + pc, ci.nextPC = ci.nextPC, 0 + } else { + pc, ci.callers = ci.callers[0], ci.callers[1:] + } funcInfo := findfunc(pc) if !funcInfo.valid() { if cgoSymbolizer != nil { @@ -125,6 +132,29 @@ func (ci *Frames) Next() (frame Frame, more bool) { // Note: entry is not modified. It always refers to a real frame, not an inlined one. // File/line from funcline1 below are already correct. f = nil + + // When CallersFrame is invoked using the PC list returned by Callers, + // the PC list includes virtual PCs corresponding to each outer frame + // around an innermost real inlined PC. + // We also want to support code passing in a PC list extracted from a + // stack trace, and there only the real PCs are printed, not the virtual ones. + // So check to see if the implied virtual PC for this PC (obtained from the + // unwinder itself) is the next PC in ci.callers. If not, insert it. + // The +1 here correspond to the pc-- above: the output of Callers + // and therefore the input to CallersFrames is return PCs from the stack; + // The pc-- backs up into the CALL instruction (not the first byte of the CALL + // instruction, but good enough to find it nonetheless). + // There are no cycles in implied virtual PCs (some number of frames were + // inlined, but that number is finite), so this unpacking cannot cause an infinite loop. + for unext := u.next(uf); unext.valid() && len(ci.callers) > 0 && ci.callers[0] != unext.pc+1; unext = u.next(unext) { + snext := u.srcFunc(unext) + if snext.funcID == abi.FuncIDWrapper && elideWrapperCalling(sf.funcID) { + // Skip, because tracebackPCs (inside runtime.Callers) would too. + continue + } + ci.nextPC = unext.pc + 1 + break + } } ci.frames = append(ci.frames, Frame{ PC: pc, @@ -166,6 +196,14 @@ func (ci *Frames) Next() (frame Frame, more bool) { // runtime_FrameStartLine returns the start line of the function in a Frame. // +// runtime_FrameStartLine should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/grafana/pyroscope-go/godeltaprof +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname runtime_FrameStartLine runtime/pprof.runtime_FrameStartLine func runtime_FrameStartLine(f *Frame) int { return f.startLine @@ -175,6 +213,14 @@ func runtime_FrameStartLine(f *Frame) int { // For generic functions this differs from f.Function in that this doesn't replace // the shape name to "...". // +// runtime_FrameSymbolName should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/grafana/pyroscope-go/godeltaprof +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname runtime_FrameSymbolName runtime/pprof.runtime_FrameSymbolName func runtime_FrameSymbolName(f *Frame) string { if !f.funcInfo.valid() { @@ -188,6 +234,15 @@ func runtime_FrameSymbolName(f *Frame) string { // runtime_expandFinalInlineFrame expands the final pc in stk to include all // "callers" if pc is inline. // +// runtime_expandFinalInlineFrame should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/grafana/pyroscope-go/godeltaprof +// - github.com/pyroscope-io/godeltaprof +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname runtime_expandFinalInlineFrame runtime/pprof.runtime_expandFinalInlineFrame func runtime_expandFinalInlineFrame(stk []uintptr) []uintptr { // TODO: It would be more efficient to report only physical PCs to pprof and @@ -371,13 +426,12 @@ type moduledata struct { modulehashes []modulehash hasmain uint8 // 1 if module contains the main function, 0 otherwise + bad bool // module failed to load and should be ignored gcdatamask, gcbssmask bitvector typemap map[typeOff]*_type // offset to *_rtype in previous module - bad bool // module failed to load and should be ignored - next *moduledata } @@ -408,8 +462,19 @@ type modulehash struct { // To make sure the map isn't collected, we keep a second reference here. var pinnedTypemaps []map[typeOff]*_type -var firstmoduledata moduledata // linker symbol +var firstmoduledata moduledata // linker symbol + +// lastmoduledatap should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname lastmoduledatap var lastmoduledatap *moduledata // linker symbol + var modulesSlice *[]*moduledata // see activeModules // activeModules returns a slice of active modules. @@ -497,9 +562,6 @@ type textsect struct { baseaddr uintptr // relocated section address } -const minfunc = 16 // minimum function size -const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table - // findfuncbucket is an array of these structures. // Each bucket represents 4096 bytes of the text segment. // Each subbucket represents 256 bytes of the text segment. @@ -521,6 +583,15 @@ func moduledataverify() { const debugPcln = false +// moduledataverify1 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname moduledataverify1 func moduledataverify1(datap *moduledata) { // Check that the pclntab's format is valid. hdr := datap.pcHeader @@ -648,6 +719,16 @@ func (md *moduledata) funcName(nameOff int32) string { // If pc represents multiple functions because of inlining, it returns // the *Func describing the innermost function, but with an entry of // the outermost function. +// +// For completely unclear reasons, even though they can import runtime, +// some widely used packages access this using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname FuncForPC func FuncForPC(pc uintptr) *Func { f := findfunc(pc) if !f.valid() { @@ -758,16 +839,37 @@ func (f *_func) isInlined() bool { } // entry returns the entry PC for f. +// +// entry should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. func (f funcInfo) entry() uintptr { return f.datap.textAddr(f.entryOff) } +//go:linkname badFuncInfoEntry runtime.funcInfo.entry +func badFuncInfoEntry(funcInfo) uintptr + // findfunc looks up function metadata for a PC. // // It is nosplit because it's part of the isgoexception // implementation. // +// findfunc should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:nosplit +//go:linkname findfunc func findfunc(pc uintptr) funcInfo { datap := findmoduledatap(pc) if datap == nil { @@ -781,8 +883,8 @@ func findfunc(pc uintptr) funcInfo { } x := uintptr(pcOff) + datap.text - datap.minpc // TODO: are datap.text and datap.minpc always equal? - b := x / pcbucketsize - i := x % pcbucketsize / (pcbucketsize / nsub) + b := x / abi.FuncTabBucketSize + i := x % abi.FuncTabBucketSize / (abi.FuncTabBucketSize / nsub) ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{}))) idx := ffb.idx + uint32(ffb.subbuckets[i]) @@ -813,6 +915,13 @@ func (f funcInfo) srcFunc() srcFunc { return srcFunc{f.datap, f.nameOff, f.startLine, f.funcID} } +// name should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. func (s srcFunc) name() string { if s.datap == nil { return "" @@ -820,6 +929,9 @@ func (s srcFunc) name() string { return s.datap.funcName(s.nameOff) } +//go:linkname badSrcFuncName runtime.srcFunc.name +func badSrcFuncName(srcFunc) string + type pcvalueCache struct { entries [2][8]pcvalueCacheEnt inUse int @@ -1009,6 +1121,15 @@ func funcfile(f funcInfo, fileno int32) string { return "?" } +// funcline1 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname funcline1 func funcline1(f funcInfo, targetpc uintptr, strict bool) (file string, line int32) { datap := f.datap if !f.valid() { @@ -1075,6 +1196,16 @@ func pcdatavalue1(f funcInfo, table uint32, targetpc uintptr, strict bool) int32 } // Like pcdatavalue, but also return the start PC of this PCData value. +// +// pcdatavalue2 should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname pcdatavalue2 func pcdatavalue2(f funcInfo, table uint32, targetpc uintptr) (int32, uintptr) { if table >= f.npcdata { return -1, 0 @@ -1103,6 +1234,16 @@ func funcdata(f funcInfo, i uint8) unsafe.Pointer { } // step advances to the next pc, value pair in the encoded table. +// +// step should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname step func step(p []byte, pc *uintptr, val *int32, first bool) (newp []byte, ok bool) { // For both uvdelta and pcdelta, the common case (~70%) // is that they are a single byte. If so, avoid calling readvarint. @@ -1148,6 +1289,15 @@ type stackmap struct { bytedata [1]byte // bitmaps, each starting on a byte boundary } +// stackmapdata should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname stackmapdata //go:nowritebarrier func stackmapdata(stkmap *stackmap, n int32) bitvector { // Check this invariant only when stackDebug is on at all. diff --git a/contrib/go/_std_1.22/src/runtime/symtabinl.go b/contrib/go/_std_1.23/src/runtime/symtabinl.go similarity index 83% rename from contrib/go/_std_1.22/src/runtime/symtabinl.go rename to contrib/go/_std_1.23/src/runtime/symtabinl.go index 9273b49b11e5..faa01decb9f7 100644 --- a/contrib/go/_std_1.22/src/runtime/symtabinl.go +++ b/contrib/go/_std_1.23/src/runtime/symtabinl.go @@ -4,7 +4,10 @@ package runtime -import "internal/abi" +import ( + "internal/abi" + _ "unsafe" // for linkname +) // inlinedCall is the encoding of entries in the FUNCDATA_InlTree table. type inlinedCall struct { @@ -51,6 +54,16 @@ type inlineFrame struct { // This unwinder uses non-strict handling of PC because it's assumed this is // only ever used for symbolic debugging. If things go really wrong, it'll just // fall back to the outermost frame. +// +// newInlineUnwinder should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname newInlineUnwinder func newInlineUnwinder(f funcInfo, pc uintptr) (inlineUnwinder, inlineFrame) { inldata := funcdata(f, abi.FUNCDATA_InlTree) if inldata == nil { @@ -90,6 +103,16 @@ func (u *inlineUnwinder) isInlined(uf inlineFrame) bool { } // srcFunc returns the srcFunc representing the given frame. +// +// srcFunc should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +// The go:linkname is below. func (u *inlineUnwinder) srcFunc(uf inlineFrame) srcFunc { if uf.index < 0 { return u.f.srcFunc() @@ -103,6 +126,9 @@ func (u *inlineUnwinder) srcFunc(uf inlineFrame) srcFunc { } } +//go:linkname badSrcFunc runtime.(*inlineUnwinder).srcFunc +func badSrcFunc(*inlineUnwinder, inlineFrame) srcFunc + // fileLine returns the file name and line number of the call within the given // frame. As a convenience, for the innermost frame, it returns the file and // line of the PC this unwinder was started at (often this is a call to another diff --git a/contrib/go/_std_1.22/src/runtime/sys_aix_ppc64.s b/contrib/go/_std_1.23/src/runtime/sys_aix_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_aix_ppc64.s rename to contrib/go/_std_1.23/src/runtime/sys_aix_ppc64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_arm.go b/contrib/go/_std_1.23/src/runtime/sys_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_arm.go rename to contrib/go/_std_1.23/src/runtime/sys_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_arm64.go b/contrib/go/_std_1.23/src/runtime/sys_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_arm64.go rename to contrib/go/_std_1.23/src/runtime/sys_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_darwin.go b/contrib/go/_std_1.23/src/runtime/sys_darwin.go similarity index 94% rename from contrib/go/_std_1.22/src/runtime/sys_darwin.go rename to contrib/go/_std_1.23/src/runtime/sys_darwin.go index 45175d86632a..1e4b2ac79efd 100644 --- a/contrib/go/_std_1.22/src/runtime/sys_darwin.go +++ b/contrib/go/_std_1.23/src/runtime/sys_darwin.go @@ -6,7 +6,7 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -16,6 +16,10 @@ import ( // and we need to know whether to check 32 or 64 bits of the result. // (Some libc functions that return 32 bits put junk in the upper 32 bits of AX.) +// golang.org/x/sys linknames syscall_syscall +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_syscall syscall.syscall //go:nosplit func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { @@ -38,6 +42,17 @@ func syscall_syscallX(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { } func syscallX() +// golang.org/x/sys linknames syscall.syscall6 +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// +// syscall.syscall6 is meant for package syscall (and x/sys), +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/tetratelabs/wazero +// +// See go.dev/issue/67401. +// //go:linkname syscall_syscall6 syscall.syscall6 //go:nosplit func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { @@ -49,6 +64,10 @@ func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) } func syscall6() +// golang.org/x/sys linknames syscall.syscall9 +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_syscall9 syscall.syscall9 //go:nosplit //go:cgo_unsafe_args @@ -71,6 +90,10 @@ func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) } func syscall6X() +// golang.org/x/sys linknames syscall.syscallPtr +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_syscallPtr syscall.syscallPtr //go:nosplit func syscall_syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { @@ -82,6 +105,10 @@ func syscall_syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { } func syscallPtr() +// golang.org/x/sys linknames syscall_rawSyscall +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_rawSyscall syscall.rawSyscall //go:nosplit func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { @@ -90,6 +117,10 @@ func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { return args.r1, args.r2, args.err } +// golang.org/x/sys linknames syscall_rawSyscall6 +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_rawSyscall6 syscall.rawSyscall6 //go:nosplit func syscall_rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { @@ -349,6 +380,15 @@ func nanotime1() int64 { } func nanotime_trampoline() +// walltime should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname walltime //go:nosplit //go:cgo_unsafe_args func walltime() (int64, int32) { diff --git a/contrib/go/_std_1.22/src/runtime/sys_darwin_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_darwin_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_darwin_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_darwin_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_darwin_arm64.go b/contrib/go/_std_1.23/src/runtime/sys_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_darwin_arm64.go rename to contrib/go/_std_1.23/src/runtime/sys_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_darwin_arm64.s b/contrib/go/_std_1.23/src/runtime/sys_darwin_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_darwin_arm64.s rename to contrib/go/_std_1.23/src/runtime/sys_darwin_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_dragonfly_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_dragonfly_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_dragonfly_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_dragonfly_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_freebsd_386.s b/contrib/go/_std_1.23/src/runtime/sys_freebsd_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_freebsd_386.s rename to contrib/go/_std_1.23/src/runtime/sys_freebsd_386.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_freebsd_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_freebsd_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_freebsd_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_freebsd_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_freebsd_arm.s b/contrib/go/_std_1.23/src/runtime/sys_freebsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_freebsd_arm.s rename to contrib/go/_std_1.23/src/runtime/sys_freebsd_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_freebsd_arm64.s b/contrib/go/_std_1.23/src/runtime/sys_freebsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_freebsd_arm64.s rename to contrib/go/_std_1.23/src/runtime/sys_freebsd_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_freebsd_riscv64.s b/contrib/go/_std_1.23/src/runtime/sys_freebsd_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_freebsd_riscv64.s rename to contrib/go/_std_1.23/src/runtime/sys_freebsd_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_libc.go b/contrib/go/_std_1.23/src/runtime/sys_libc.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_libc.go rename to contrib/go/_std_1.23/src/runtime/sys_libc.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_386.s b/contrib/go/_std_1.23/src/runtime/sys_linux_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_386.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_386.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_linux_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_arm.s b/contrib/go/_std_1.23/src/runtime/sys_linux_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_arm.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_arm64.s b/contrib/go/_std_1.23/src/runtime/sys_linux_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_arm64.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_loong64.s b/contrib/go/_std_1.23/src/runtime/sys_linux_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_loong64.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_mips64x.s b/contrib/go/_std_1.23/src/runtime/sys_linux_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_mips64x.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_mipsx.s b/contrib/go/_std_1.23/src/runtime/sys_linux_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_mipsx.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_ppc64x.s b/contrib/go/_std_1.23/src/runtime/sys_linux_ppc64x.s similarity index 99% rename from contrib/go/_std_1.22/src/runtime/sys_linux_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_ppc64x.s index d105585b7e88..ba4988b72332 100644 --- a/contrib/go/_std_1.22/src/runtime/sys_linux_ppc64x.s +++ b/contrib/go/_std_1.23/src/runtime/sys_linux_ppc64x.s @@ -211,7 +211,7 @@ TEXT runtime·walltime(SB),NOSPLIT,$16-12 MOVD $0, R3 // CLOCK_REALTIME MOVD runtime·vdsoClockgettimeSym(SB), R12 // Check for VDSO availability - CMP R12, R0 + CMP R12, $0 BEQ fallback // Set vdsoPC and vdsoSP for SIGPROF traceback. @@ -305,7 +305,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$16-8 MOVD g_m(g), R21 // R21 = m MOVD runtime·vdsoClockgettimeSym(SB), R12 // Check for VDSO availability - CMP R12, R0 + CMP R12, $0 BEQ fallback // Set vdsoPC and vdsoSP for SIGPROF traceback. diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_riscv64.s b/contrib/go/_std_1.23/src/runtime/sys_linux_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_linux_riscv64.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_linux_s390x.s b/contrib/go/_std_1.23/src/runtime/sys_linux_s390x.s similarity index 99% rename from contrib/go/_std_1.22/src/runtime/sys_linux_s390x.s rename to contrib/go/_std_1.23/src/runtime/sys_linux_s390x.s index adf5612c3cfb..59e2f2ab31f2 100644 --- a/contrib/go/_std_1.22/src/runtime/sys_linux_s390x.s +++ b/contrib/go/_std_1.23/src/runtime/sys_linux_s390x.s @@ -112,9 +112,10 @@ TEXT runtime·usleep(SB),NOSPLIT,$16-4 MOVW $1000000, R3 DIVD R3, R2 MOVD R2, 8(R15) - MOVW $1000, R3 - MULLD R2, R3 + MULLD R2, R3 // Convert sec to usec and subtract SUB R3, R4 + MOVW $1000, R3 + MULLD R3, R4 // Convert remaining usec into nsec. MOVD R4, 16(R15) // nanosleep(&ts, 0) diff --git a/contrib/go/_std_1.22/src/runtime/sys_loong64.go b/contrib/go/_std_1.23/src/runtime/sys_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_loong64.go rename to contrib/go/_std_1.23/src/runtime/sys_loong64.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_mips64x.go b/contrib/go/_std_1.23/src/runtime/sys_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_mips64x.go rename to contrib/go/_std_1.23/src/runtime/sys_mips64x.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_mipsx.go b/contrib/go/_std_1.23/src/runtime/sys_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_mipsx.go rename to contrib/go/_std_1.23/src/runtime/sys_mipsx.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_netbsd_386.s b/contrib/go/_std_1.23/src/runtime/sys_netbsd_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_netbsd_386.s rename to contrib/go/_std_1.23/src/runtime/sys_netbsd_386.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_netbsd_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_netbsd_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_netbsd_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_netbsd_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_netbsd_arm.s b/contrib/go/_std_1.23/src/runtime/sys_netbsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_netbsd_arm.s rename to contrib/go/_std_1.23/src/runtime/sys_netbsd_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_netbsd_arm64.s b/contrib/go/_std_1.23/src/runtime/sys_netbsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_netbsd_arm64.s rename to contrib/go/_std_1.23/src/runtime/sys_netbsd_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_nonppc64x.go b/contrib/go/_std_1.23/src/runtime/sys_nonppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_nonppc64x.go rename to contrib/go/_std_1.23/src/runtime/sys_nonppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd.go b/contrib/go/_std_1.23/src/runtime/sys_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd.go rename to contrib/go/_std_1.23/src/runtime/sys_openbsd.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd1.go b/contrib/go/_std_1.23/src/runtime/sys_openbsd1.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd1.go rename to contrib/go/_std_1.23/src/runtime/sys_openbsd1.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd2.go b/contrib/go/_std_1.23/src/runtime/sys_openbsd2.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd2.go rename to contrib/go/_std_1.23/src/runtime/sys_openbsd2.go index b38e49ee6f59..8f5242018dd0 100644 --- a/contrib/go/_std_1.22/src/runtime/sys_openbsd2.go +++ b/contrib/go/_std_1.23/src/runtime/sys_openbsd2.go @@ -8,7 +8,7 @@ package runtime import ( "internal/abi" - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd3.go b/contrib/go/_std_1.23/src/runtime/sys_openbsd3.go similarity index 82% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd3.go rename to contrib/go/_std_1.23/src/runtime/sys_openbsd3.go index 269bf86f10de..de09ec5e2581 100644 --- a/contrib/go/_std_1.22/src/runtime/sys_openbsd3.go +++ b/contrib/go/_std_1.23/src/runtime/sys_openbsd3.go @@ -17,6 +17,10 @@ import ( // and we need to know whether to check 32 or 64 bits of the result. // (Some libc functions that return 32 bits put junk in the upper 32 bits of AX.) +// golang.org/x/sys linknames syscall_syscall +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_syscall syscall.syscall //go:nosplit //go:cgo_unsafe_args @@ -39,6 +43,10 @@ func syscall_syscallX(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { } func syscallX() +// golang.org/x/sys linknames syscall.syscall6 +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_syscall6 syscall.syscall6 //go:nosplit //go:cgo_unsafe_args @@ -61,6 +69,10 @@ func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) } func syscall6X() +// golang.org/x/sys linknames syscall.syscall10 +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_syscall10 syscall.syscall10 //go:nosplit //go:cgo_unsafe_args @@ -83,6 +95,10 @@ func syscall_syscall10X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10 uintptr) (r1 } func syscall10X() +// golang.org/x/sys linknames syscall_rawSyscall +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_rawSyscall syscall.rawSyscall //go:nosplit //go:cgo_unsafe_args @@ -91,6 +107,10 @@ func syscall_rawSyscall(fn, a1, a2, a3 uintptr) (r1, r2, err uintptr) { return } +// golang.org/x/sys linknames syscall_rawSyscall6 +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_rawSyscall6 syscall.rawSyscall6 //go:nosplit //go:cgo_unsafe_args diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd_386.s b/contrib/go/_std_1.23/src/runtime/sys_openbsd_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd_386.s rename to contrib/go/_std_1.23/src/runtime/sys_openbsd_386.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_openbsd_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_openbsd_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd_arm.s b/contrib/go/_std_1.23/src/runtime/sys_openbsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd_arm.s rename to contrib/go/_std_1.23/src/runtime/sys_openbsd_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd_arm64.s b/contrib/go/_std_1.23/src/runtime/sys_openbsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd_arm64.s rename to contrib/go/_std_1.23/src/runtime/sys_openbsd_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd_mips64.s b/contrib/go/_std_1.23/src/runtime/sys_openbsd_mips64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd_mips64.s rename to contrib/go/_std_1.23/src/runtime/sys_openbsd_mips64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd_ppc64.s b/contrib/go/_std_1.23/src/runtime/sys_openbsd_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd_ppc64.s rename to contrib/go/_std_1.23/src/runtime/sys_openbsd_ppc64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_openbsd_riscv64.s b/contrib/go/_std_1.23/src/runtime/sys_openbsd_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_openbsd_riscv64.s rename to contrib/go/_std_1.23/src/runtime/sys_openbsd_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_plan9_386.s b/contrib/go/_std_1.23/src/runtime/sys_plan9_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_plan9_386.s rename to contrib/go/_std_1.23/src/runtime/sys_plan9_386.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_plan9_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_plan9_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_plan9_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_plan9_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_plan9_arm.s b/contrib/go/_std_1.23/src/runtime/sys_plan9_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_plan9_arm.s rename to contrib/go/_std_1.23/src/runtime/sys_plan9_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_ppc64x.go b/contrib/go/_std_1.23/src/runtime/sys_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_ppc64x.go rename to contrib/go/_std_1.23/src/runtime/sys_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_riscv64.go b/contrib/go/_std_1.23/src/runtime/sys_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_riscv64.go rename to contrib/go/_std_1.23/src/runtime/sys_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_s390x.go b/contrib/go/_std_1.23/src/runtime/sys_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_s390x.go rename to contrib/go/_std_1.23/src/runtime/sys_s390x.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_solaris_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_solaris_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_solaris_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_solaris_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_wasm.go b/contrib/go/_std_1.23/src/runtime/sys_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_wasm.go rename to contrib/go/_std_1.23/src/runtime/sys_wasm.go diff --git a/contrib/go/_std_1.22/src/runtime/sys_wasm.s b/contrib/go/_std_1.23/src/runtime/sys_wasm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_wasm.s rename to contrib/go/_std_1.23/src/runtime/sys_wasm.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_windows_386.s b/contrib/go/_std_1.23/src/runtime/sys_windows_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_windows_386.s rename to contrib/go/_std_1.23/src/runtime/sys_windows_386.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_windows_amd64.s b/contrib/go/_std_1.23/src/runtime/sys_windows_amd64.s similarity index 98% rename from contrib/go/_std_1.22/src/runtime/sys_windows_amd64.s rename to contrib/go/_std_1.23/src/runtime/sys_windows_amd64.s index c1b78e39769e..56a2dc0bcf24 100644 --- a/contrib/go/_std_1.22/src/runtime/sys_windows_amd64.s +++ b/contrib/go/_std_1.23/src/runtime/sys_windows_amd64.s @@ -33,14 +33,12 @@ TEXT runtime·asmstdcall(SB),NOSPLIT,$16 SUBQ $(const_maxArgs*8), SP // room for args - // Fast version, do not store args on the stack nor - // load them into registers. - CMPL CX, $0 - JE docall - // Fast version, do not store args on the stack. - CMPL CX, $4 - JLE loadregs + CMPL CX, $0; JE _0args + CMPL CX, $1; JE _1args + CMPL CX, $2; JE _2args + CMPL CX, $3; JE _3args + CMPL CX, $4; JE _4args // Check we have enough room for args. CMPL CX, $const_maxArgs @@ -53,22 +51,25 @@ TEXT runtime·asmstdcall(SB),NOSPLIT,$16 REP; MOVSQ MOVQ SP, SI -loadregs: // Load first 4 args into correspondent registers. - MOVQ 0(SI), CX - MOVQ 8(SI), DX - MOVQ 16(SI), R8 - MOVQ 24(SI), R9 // Floating point arguments are passed in the XMM // registers. Set them here in case any of the arguments // are floating point values. For details see // https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170 - MOVQ CX, X0 - MOVQ DX, X1 - MOVQ R8, X2 +_4args: + MOVQ 24(SI), R9 MOVQ R9, X3 +_3args: + MOVQ 16(SI), R8 + MOVQ R8, X2 +_2args: + MOVQ 8(SI), DX + MOVQ DX, X1 +_1args: + MOVQ 0(SI), CX + MOVQ CX, X0 +_0args: -docall: // Call stdcall function. CALL AX diff --git a/contrib/go/_std_1.22/src/runtime/sys_windows_arm.s b/contrib/go/_std_1.23/src/runtime/sys_windows_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_windows_arm.s rename to contrib/go/_std_1.23/src/runtime/sys_windows_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_windows_arm64.s b/contrib/go/_std_1.23/src/runtime/sys_windows_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_windows_arm64.s rename to contrib/go/_std_1.23/src/runtime/sys_windows_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/sys_x86.go b/contrib/go/_std_1.23/src/runtime/sys_x86.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/sys_x86.go rename to contrib/go/_std_1.23/src/runtime/sys_x86.go diff --git a/contrib/go/_std_1.22/src/runtime/syscall2_solaris.go b/contrib/go/_std_1.23/src/runtime/syscall2_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/syscall2_solaris.go rename to contrib/go/_std_1.23/src/runtime/syscall2_solaris.go diff --git a/contrib/go/_std_1.22/src/runtime/syscall_aix.go b/contrib/go/_std_1.23/src/runtime/syscall_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/syscall_aix.go rename to contrib/go/_std_1.23/src/runtime/syscall_aix.go diff --git a/contrib/go/_std_1.22/src/runtime/syscall_solaris.go b/contrib/go/_std_1.23/src/runtime/syscall_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/syscall_solaris.go rename to contrib/go/_std_1.23/src/runtime/syscall_solaris.go diff --git a/contrib/go/_std_1.22/src/runtime/syscall_windows.go b/contrib/go/_std_1.23/src/runtime/syscall_windows.go similarity index 85% rename from contrib/go/_std_1.22/src/runtime/syscall_windows.go rename to contrib/go/_std_1.23/src/runtime/syscall_windows.go index ba88e93d7dc9..85b1b8c9024a 100644 --- a/contrib/go/_std_1.22/src/runtime/syscall_windows.go +++ b/contrib/go/_std_1.23/src/runtime/syscall_windows.go @@ -103,7 +103,7 @@ func (p *abiDesc) assignArg(t *_type) { // registers and the stack. panic("compileCallback: argument size is larger than uintptr") } - if k := t.Kind_ & kindMask; GOARCH != "386" && (k == kindFloat32 || k == kindFloat64) { + if k := t.Kind_ & abi.KindMask; GOARCH != "386" && (k == abi.Float32 || k == abi.Float64) { // In fastcall, floating-point arguments in // the first four positions are passed in // floating-point registers, which we don't @@ -174,21 +174,21 @@ func (p *abiDesc) assignArg(t *_type) { // // Returns whether the assignment succeeded. func (p *abiDesc) tryRegAssignArg(t *_type, offset uintptr) bool { - switch k := t.Kind_ & kindMask; k { - case kindBool, kindInt, kindInt8, kindInt16, kindInt32, kindUint, kindUint8, kindUint16, kindUint32, kindUintptr, kindPtr, kindUnsafePointer: + switch k := t.Kind_ & abi.KindMask; k { + case abi.Bool, abi.Int, abi.Int8, abi.Int16, abi.Int32, abi.Uint, abi.Uint8, abi.Uint16, abi.Uint32, abi.Uintptr, abi.Pointer, abi.UnsafePointer: // Assign a register for all these types. return p.assignReg(t.Size_, offset) - case kindInt64, kindUint64: + case abi.Int64, abi.Uint64: // Only register-assign if the registers are big enough. if goarch.PtrSize == 8 { return p.assignReg(t.Size_, offset) } - case kindArray: + case abi.Array: at := (*arraytype)(unsafe.Pointer(t)) if at.Len == 1 { return p.tryRegAssignArg(at.Elem, offset) // TODO fix when runtime is fully commoned up w/ abi.Type } - case kindStruct: + case abi.Struct: st := (*structtype)(unsafe.Pointer(t)) for i := range st.Fields { f := &st.Fields[i] @@ -269,7 +269,7 @@ func compileCallback(fn eface, cdecl bool) (code uintptr) { cdecl = false } - if fn._type == nil || (fn._type.Kind_&kindMask) != kindFunc { + if fn._type == nil || (fn._type.Kind_&abi.KindMask) != abi.Func { panic("compileCallback: expected function with one uintptr-sized result") } ft := (*functype)(unsafe.Pointer(fn._type)) @@ -290,7 +290,7 @@ func compileCallback(fn eface, cdecl bool) (code uintptr) { if ft.OutSlice()[0].Size_ != goarch.PtrSize { panic("compileCallback: expected function with one uintptr-sized result") } - if k := ft.OutSlice()[0].Kind_ & kindMask; k == kindFloat32 || k == kindFloat64 { + if k := ft.OutSlice()[0].Kind_ & abi.KindMask; k == abi.Float32 || k == abi.Float64 { // In cdecl and stdcall, float results are returned in // ST(0). In fastcall, they're returned in XMM0. // Either way, it's not AX. @@ -414,64 +414,39 @@ func callbackWrap(a *callbackArgs) { const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800 //go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary -//go:nosplit -//go:cgo_unsafe_args func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) { - lockOSThread() - c := &getg().m.syscall - c.fn = getLoadLibraryEx() - c.n = 3 - args := struct { - lpFileName *uint16 - hFile uintptr // always 0 - flags uint32 - }{filename, 0, _LOAD_LIBRARY_SEARCH_SYSTEM32} - c.args = uintptr(noescape(unsafe.Pointer(&args))) - - cgocall(asmstdcallAddr, unsafe.Pointer(c)) + handle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_LoadLibraryExW)), uintptr(unsafe.Pointer(filename)), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32) KeepAlive(filename) - handle = c.r1 - if handle == 0 { - err = c.err + if handle != 0 { + err = 0 } - unlockOSThread() // not defer'd after the lockOSThread above to save stack frame size. return } +// golang.org/x/sys linknames syscall.loadlibrary +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_loadlibrary syscall.loadlibrary -//go:nosplit -//go:cgo_unsafe_args func syscall_loadlibrary(filename *uint16) (handle, err uintptr) { - lockOSThread() - defer unlockOSThread() - c := &getg().m.syscall - c.fn = getLoadLibrary() - c.n = 1 - c.args = uintptr(noescape(unsafe.Pointer(&filename))) - cgocall(asmstdcallAddr, unsafe.Pointer(c)) + handle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_LoadLibraryW)), uintptr(unsafe.Pointer(filename))) KeepAlive(filename) - handle = c.r1 - if handle == 0 { - err = c.err + if handle != 0 { + err = 0 } return } +// golang.org/x/sys linknames syscall.getprocaddress +// (in addition to standard package syscall). +// Do not remove or change the type signature. +// //go:linkname syscall_getprocaddress syscall.getprocaddress -//go:nosplit -//go:cgo_unsafe_args func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) { - lockOSThread() - defer unlockOSThread() - c := &getg().m.syscall - c.fn = getGetProcAddress() - c.n = 2 - c.args = uintptr(noescape(unsafe.Pointer(&handle))) - cgocall(asmstdcallAddr, unsafe.Pointer(c)) + outhandle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_GetProcAddress)), handle, uintptr(unsafe.Pointer(procname))) KeepAlive(procname) - outhandle = c.r1 - if outhandle == 0 { - err = c.err + if outhandle != 0 { + err = 0 } return } @@ -479,37 +454,37 @@ func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uint //go:linkname syscall_Syscall syscall.Syscall //go:nosplit func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) { - return syscall_SyscallN(fn, a1, a2, a3) + return syscall_syscalln(fn, nargs, a1, a2, a3) } //go:linkname syscall_Syscall6 syscall.Syscall6 //go:nosplit func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { - return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6) + return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6) } //go:linkname syscall_Syscall9 syscall.Syscall9 //go:nosplit func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) { - return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9) + return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9) } //go:linkname syscall_Syscall12 syscall.Syscall12 //go:nosplit func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) { - return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) + return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) } //go:linkname syscall_Syscall15 syscall.Syscall15 //go:nosplit func syscall_Syscall15(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) { - return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) + return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) } //go:linkname syscall_Syscall18 syscall.Syscall18 //go:nosplit func syscall_Syscall18(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2, err uintptr) { - return syscall_SyscallN(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18) + return syscall_syscalln(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18) } // maxArgs should be divisible by 2, as Windows stack @@ -521,26 +496,32 @@ const maxArgs = 42 //go:linkname syscall_SyscallN syscall.SyscallN //go:nosplit -func syscall_SyscallN(trap uintptr, args ...uintptr) (r1, r2, err uintptr) { - nargs := len(args) - - // asmstdcall expects it can access the first 4 arguments - // to load them into registers. - var tmp [4]uintptr - switch { - case nargs < 4: - copy(tmp[:], args) - args = tmp[:] - case nargs > maxArgs: +func syscall_SyscallN(fn uintptr, args ...uintptr) (r1, r2, err uintptr) { + return syscall_syscalln(fn, uintptr(len(args)), args...) +} + +//go:nosplit +func syscall_syscalln(fn, n uintptr, args ...uintptr) (r1, r2, err uintptr) { + if n > uintptr(len(args)) { + panic("syscall: n > len(args)") // should not be reachable from user code + } + if n > maxArgs { panic("runtime: SyscallN has too many arguments") } - lockOSThread() - defer unlockOSThread() - c := &getg().m.syscall - c.fn = trap - c.n = uintptr(nargs) - c.args = uintptr(noescape(unsafe.Pointer(&args[0]))) + // The cgocall parameters are stored in m instead of in + // the stack because the stack can move during fn if it + // calls back into Go. + c := &getg().m.winsyscall + c.fn = fn + c.n = n + if c.n != 0 { + c.args = uintptr(noescape(unsafe.Pointer(&args[0]))) + } cgocall(asmstdcallAddr, unsafe.Pointer(c)) + // cgocall may reschedule us on to a different M, + // but it copies the return values into the new M's + // so we can read them from there. + c = &getg().m.winsyscall return c.r1, c.r2, c.err } diff --git a/contrib/go/_std_1.22/src/runtime/tagptr.go b/contrib/go/_std_1.23/src/runtime/tagptr.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tagptr.go rename to contrib/go/_std_1.23/src/runtime/tagptr.go diff --git a/contrib/go/_std_1.22/src/runtime/tagptr_32bit.go b/contrib/go/_std_1.23/src/runtime/tagptr_32bit.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tagptr_32bit.go rename to contrib/go/_std_1.23/src/runtime/tagptr_32bit.go diff --git a/contrib/go/_std_1.22/src/runtime/tagptr_64bit.go b/contrib/go/_std_1.23/src/runtime/tagptr_64bit.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tagptr_64bit.go rename to contrib/go/_std_1.23/src/runtime/tagptr_64bit.go diff --git a/contrib/go/_std_1.22/src/runtime/test_amd64.go b/contrib/go/_std_1.23/src/runtime/test_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/test_amd64.go rename to contrib/go/_std_1.23/src/runtime/test_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/test_amd64.s b/contrib/go/_std_1.23/src/runtime/test_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/test_amd64.s rename to contrib/go/_std_1.23/src/runtime/test_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/test_stubs.go b/contrib/go/_std_1.23/src/runtime/test_stubs.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/test_stubs.go rename to contrib/go/_std_1.23/src/runtime/test_stubs.go diff --git a/contrib/go/_std_1.22/src/runtime/textflag.h b/contrib/go/_std_1.23/src/runtime/textflag.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/textflag.h rename to contrib/go/_std_1.23/src/runtime/textflag.h diff --git a/contrib/go/_std_1.23/src/runtime/time.go b/contrib/go/_std_1.23/src/runtime/time.go new file mode 100644 index 000000000000..7b344a349610 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/time.go @@ -0,0 +1,1377 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Time-related runtime and pieces of package time. + +package runtime + +import ( + "internal/abi" + "internal/runtime/atomic" + "runtime/internal/sys" + "unsafe" +) + +// A timer is a potentially repeating trigger for calling t.f(t.arg, t.seq). +// Timers are allocated by client code, often as part of other data structures. +// Each P has a heap of pointers to timers that it manages. +// +// A timer is expected to be used by only one client goroutine at a time, +// but there will be concurrent access by the P managing that timer. +// Timer accesses are protected by the lock t.mu, with a snapshot of +// t's state bits published in t.astate to enable certain fast paths to make +// decisions about a timer without acquiring the lock. +type timer struct { + // mu protects reads and writes to all fields, with exceptions noted below. + mu mutex + + astate atomic.Uint8 // atomic copy of state bits at last unlock + state uint8 // state bits + isChan bool // timer has a channel; immutable; can be read without lock + + blocked uint32 // number of goroutines blocked on timer's channel + + // Timer wakes up at when, and then at when+period, ... (period > 0 only) + // each time calling f(arg, seq, delay) in the timer goroutine, so f must be + // a well-behaved function and not block. + // + // The arg and seq are client-specified opaque arguments passed back to f. + // When used from netpoll, arg and seq have meanings defined by netpoll + // and are completely opaque to this code; in that context, seq is a sequence + // number to recognize and squech stale function invocations. + // When used from package time, arg is a channel (for After, NewTicker) + // or the function to call (for AfterFunc) and seq is unused (0). + // + // Package time does not know about seq, but if this is a channel timer (t.isChan == true), + // this file uses t.seq as a sequence number to recognize and squelch + // sends that correspond to an earlier (stale) timer configuration, + // similar to its use in netpoll. In this usage (that is, when t.isChan == true), + // writes to seq are protected by both t.mu and t.sendLock, + // so reads are allowed when holding either of the two mutexes. + // + // The delay argument is nanotime() - t.when, meaning the delay in ns between + // when the timer should have gone off and now. Normally that amount is + // small enough not to matter, but for channel timers that are fed lazily, + // the delay can be arbitrarily long; package time subtracts it out to make + // it look like the send happened earlier than it actually did. + // (No one looked at the channel since then, or the send would have + // not happened so late, so no one can tell the difference.) + when int64 + period int64 + f func(arg any, seq uintptr, delay int64) + arg any + seq uintptr + + // If non-nil, the timers containing t. + ts *timers + + // sendLock protects sends on the timer's channel. + // Not used for async (pre-Go 1.23) behavior when debug.asynctimerchan.Load() != 0. + sendLock mutex + + // isSending is used to handle races between running a + // channel timer and stopping or resetting the timer. + // It is used only for channel timers (t.isChan == true). + // It is not used for tickers. + // The value is incremented when about to send a value on the channel, + // and decremented after sending the value. + // The stop/reset code uses this to detect whether it + // stopped the channel send. + // + // isSending is incremented only when t.mu is held. + // isSending is decremented only when t.sendLock is held. + // isSending is read only when both t.mu and t.sendLock are held. + isSending atomic.Int32 +} + +// init initializes a newly allocated timer t. +// Any code that allocates a timer must call t.init before using it. +// The arg and f can be set during init, or they can be nil in init +// and set by a future call to t.modify. +func (t *timer) init(f func(arg any, seq uintptr, delay int64), arg any) { + lockInit(&t.mu, lockRankTimer) + t.f = f + t.arg = arg +} + +// A timers is a per-P set of timers. +type timers struct { + // mu protects timers; timers are per-P, but the scheduler can + // access the timers of another P, so we have to lock. + mu mutex + + // heap is the set of timers, ordered by heap[i].when. + // Must hold lock to access. + heap []timerWhen + + // len is an atomic copy of len(heap). + len atomic.Uint32 + + // zombies is the number of timers in the heap + // that are marked for removal. + zombies atomic.Int32 + + // raceCtx is the race context used while executing timer functions. + raceCtx uintptr + + // minWhenHeap is the minimum heap[i].when value (= heap[0].when). + // The wakeTime method uses minWhenHeap and minWhenModified + // to determine the next wake time. + // If minWhenHeap = 0, it means there are no timers in the heap. + minWhenHeap atomic.Int64 + + // minWhenModified is a lower bound on the minimum + // heap[i].when over timers with the timerModified bit set. + // If minWhenModified = 0, it means there are no timerModified timers in the heap. + minWhenModified atomic.Int64 +} + +type timerWhen struct { + timer *timer + when int64 +} + +func (ts *timers) lock() { + lock(&ts.mu) +} + +func (ts *timers) unlock() { + // Update atomic copy of len(ts.heap). + // We only update at unlock so that the len is always + // the most recent unlocked length, not an ephemeral length. + // This matters if we lock ts, delete the only timer from the heap, + // add it back, and unlock. We want ts.len.Load to return 1 the + // entire time, never 0. This is important for pidleput deciding + // whether ts is empty. + ts.len.Store(uint32(len(ts.heap))) + + unlock(&ts.mu) +} + +// Timer state field. +const ( + // timerHeaped is set when the timer is stored in some P's heap. + timerHeaped uint8 = 1 << iota + + // timerModified is set when t.when has been modified + // but the heap's heap[i].when entry still needs to be updated. + // That change waits until the heap in which + // the timer appears can be locked and rearranged. + // timerModified is only set when timerHeaped is also set. + timerModified + + // timerZombie is set when the timer has been stopped + // but is still present in some P's heap. + // Only set when timerHeaped is also set. + // It is possible for timerModified and timerZombie to both + // be set, meaning that the timer was modified and then stopped. + // A timer sending to a channel may be placed in timerZombie + // to take it out of the heap even though the timer is not stopped, + // as long as nothing is reading from the channel. + timerZombie +) + +// timerDebug enables printing a textual debug trace of all timer operations to stderr. +const timerDebug = false + +func (t *timer) trace(op string) { + if timerDebug { + t.trace1(op) + } +} + +func (t *timer) trace1(op string) { + if !timerDebug { + return + } + bits := [4]string{"h", "m", "z", "c"} + for i := range 3 { + if t.state&(1< 0 { + // If timer should have triggered already (but nothing looked at it yet), + // trigger now, so that a receive after the stop sees the "old" value + // that should be there. + // (It is possible to have t.blocked > 0 if there is a racing receive + // in blockTimerChan, but timerHeaped not being set means + // it hasn't run t.maybeAdd yet; in that case, running the + // timer ourselves now is fine.) + if now := nanotime(); t.when <= now { + systemstack(func() { + t.unlockAndRun(now) // resets t.when + }) + t.lock() + } + } +} + +// stop stops the timer t. It may be on some other P, so we can't +// actually remove it from the timers heap. We can only mark it as stopped. +// It will be removed in due course by the P whose heap it is on. +// Reports whether the timer was stopped before it was run. +func (t *timer) stop() bool { + async := debug.asynctimerchan.Load() != 0 + if !async && t.isChan { + lock(&t.sendLock) + } + + t.lock() + t.trace("stop") + if async { + t.maybeRunAsync() + } + if t.state&timerHeaped != 0 { + t.state |= timerModified + if t.state&timerZombie == 0 { + t.state |= timerZombie + t.ts.zombies.Add(1) + } + } + pending := t.when > 0 + t.when = 0 + + if !async && t.isChan { + // Stop any future sends with stale values. + // See timer.unlockAndRun. + t.seq++ + + // If there is currently a send in progress, + // incrementing seq is going to prevent that + // send from actually happening. That means + // that we should return true: the timer was + // stopped, even though t.when may be zero. + if t.period == 0 && t.isSending.Load() > 0 { + pending = true + } + } + t.unlock() + if !async && t.isChan { + unlock(&t.sendLock) + if timerchandrain(t.hchan()) { + pending = true + } + } + + return pending +} + +// deleteMin removes timer 0 from ts. +// ts must be locked. +func (ts *timers) deleteMin() { + assertLockHeld(&ts.mu) + t := ts.heap[0].timer + if t.ts != ts { + throw("wrong timers") + } + t.ts = nil + last := len(ts.heap) - 1 + if last > 0 { + ts.heap[0] = ts.heap[last] + } + ts.heap[last] = timerWhen{} + ts.heap = ts.heap[:last] + if last > 0 { + ts.siftDown(0) + } + ts.updateMinWhenHeap() + if last == 0 { + // If there are no timers, then clearly there are no timerModified timers. + ts.minWhenModified.Store(0) + } +} + +// modify modifies an existing timer. +// This is called by the netpoll code or time.Ticker.Reset or time.Timer.Reset. +// Reports whether the timer was modified before it was run. +// If f == nil, then t.f, t.arg, and t.seq are not modified. +func (t *timer) modify(when, period int64, f func(arg any, seq uintptr, delay int64), arg any, seq uintptr) bool { + if when <= 0 { + throw("timer when must be positive") + } + if period < 0 { + throw("timer period must be non-negative") + } + async := debug.asynctimerchan.Load() != 0 + + if !async && t.isChan { + lock(&t.sendLock) + } + + t.lock() + if async { + t.maybeRunAsync() + } + t.trace("modify") + oldPeriod := t.period + t.period = period + if f != nil { + t.f = f + t.arg = arg + t.seq = seq + } + + wake := false + pending := t.when > 0 + t.when = when + if t.state&timerHeaped != 0 { + t.state |= timerModified + if t.state&timerZombie != 0 { + // In the heap but marked for removal (by a Stop). + // Unmark it, since it has been Reset and will be running again. + t.ts.zombies.Add(-1) + t.state &^= timerZombie + } + // The corresponding heap[i].when is updated later. + // See comment in type timer above and in timers.adjust below. + if min := t.ts.minWhenModified.Load(); min == 0 || when < min { + wake = true + // Force timerModified bit out to t.astate before updating t.minWhenModified, + // to synchronize with t.ts.adjust. See comment in adjust. + t.astate.Store(t.state) + t.ts.updateMinWhenModified(when) + } + } + + add := t.needsAdd() + + if !async && t.isChan { + // Stop any future sends with stale values. + // See timer.unlockAndRun. + t.seq++ + + // If there is currently a send in progress, + // incrementing seq is going to prevent that + // send from actually happening. That means + // that we should return true: the timer was + // stopped, even though t.when may be zero. + if oldPeriod == 0 && t.isSending.Load() > 0 { + pending = true + } + } + t.unlock() + if !async && t.isChan { + if timerchandrain(t.hchan()) { + pending = true + } + unlock(&t.sendLock) + } + + if add { + t.maybeAdd() + } + if wake { + wakeNetPoller(when) + } + + return pending +} + +// needsAdd reports whether t needs to be added to a timers heap. +// t must be locked. +func (t *timer) needsAdd() bool { + assertLockHeld(&t.mu) + need := t.state&timerHeaped == 0 && t.when > 0 && (!t.isChan || t.blocked > 0) + if need { + t.trace("needsAdd+") + } else { + t.trace("needsAdd-") + } + return need +} + +// maybeAdd adds t to the local timers heap if it needs to be in a heap. +// The caller must not hold t's lock nor any timers heap lock. +// The caller probably just unlocked t, but that lock must be dropped +// in order to acquire a ts.lock, to avoid lock inversions. +// (timers.adjust holds ts.lock while acquiring each t's lock, +// so we cannot hold any t's lock while acquiring ts.lock). +// +// Strictly speaking it *might* be okay to hold t.lock and +// acquire ts.lock at the same time, because we know that +// t is not in any ts.heap, so nothing holding a ts.lock would +// be acquiring the t.lock at the same time, meaning there +// isn't a possible deadlock. But it is easier and safer not to be +// too clever and respect the static ordering. +// (If we don't, we have to change the static lock checking of t and ts.) +// +// Concurrent calls to time.Timer.Reset or blockTimerChan +// may result in concurrent calls to t.maybeAdd, +// so we cannot assume that t is not in a heap on entry to t.maybeAdd. +func (t *timer) maybeAdd() { + // Note: Not holding any locks on entry to t.maybeAdd, + // so the current g can be rescheduled to a different M and P + // at any time, including between the ts := assignment and the + // call to ts.lock. If a reschedule happened then, we would be + // adding t to some other P's timers, perhaps even a P that the scheduler + // has marked as idle with no timers, in which case the timer could + // go unnoticed until long after t.when. + // Calling acquirem instead of using getg().m makes sure that + // we end up locking and inserting into the current P's timers. + mp := acquirem() + ts := &mp.p.ptr().timers + ts.lock() + ts.cleanHead() + t.lock() + t.trace("maybeAdd") + when := int64(0) + wake := false + if t.needsAdd() { + t.state |= timerHeaped + when = t.when + wakeTime := ts.wakeTime() + wake = wakeTime == 0 || when < wakeTime + ts.addHeap(t) + } + t.unlock() + ts.unlock() + releasem(mp) + if wake { + wakeNetPoller(when) + } +} + +// reset resets the time when a timer should fire. +// If used for an inactive timer, the timer will become active. +// Reports whether the timer was active and was stopped. +func (t *timer) reset(when, period int64) bool { + return t.modify(when, period, nil, nil, 0) +} + +// cleanHead cleans up the head of the timer queue. This speeds up +// programs that create and delete timers; leaving them in the heap +// slows down heap operations. +// The caller must have locked ts. +func (ts *timers) cleanHead() { + ts.trace("cleanHead") + assertLockHeld(&ts.mu) + gp := getg() + for { + if len(ts.heap) == 0 { + return + } + + // This loop can theoretically run for a while, and because + // it is holding timersLock it cannot be preempted. + // If someone is trying to preempt us, just return. + // We can clean the timers later. + if gp.preemptStop { + return + } + + // Delete zombies from tail of heap. It requires no heap adjustments at all, + // and doing so increases the chances that when we swap out a zombie + // in heap[0] for the tail of the heap, we'll get a non-zombie timer, + // shortening this loop. + n := len(ts.heap) + if t := ts.heap[n-1].timer; t.astate.Load()&timerZombie != 0 { + t.lock() + if t.state&timerZombie != 0 { + t.state &^= timerHeaped | timerZombie | timerModified + t.ts = nil + ts.zombies.Add(-1) + ts.heap[n-1] = timerWhen{} + ts.heap = ts.heap[:n-1] + } + t.unlock() + continue + } + + t := ts.heap[0].timer + if t.ts != ts { + throw("bad ts") + } + + if t.astate.Load()&(timerModified|timerZombie) == 0 { + // Fast path: head of timers does not need adjustment. + return + } + + t.lock() + updated := t.updateHeap() + t.unlock() + if !updated { + // Head of timers does not need adjustment. + return + } + } +} + +// take moves any timers from src into ts +// and then clears the timer state from src, +// because src is being destroyed. +// The caller must not have locked either timers. +// For now this is only called when the world is stopped. +func (ts *timers) take(src *timers) { + ts.trace("take") + assertWorldStopped() + if len(src.heap) > 0 { + // The world is stopped, so we ignore the locking of ts and src here. + // That would introduce a sched < timers lock ordering, + // which we'd rather avoid in the static ranking. + for _, tw := range src.heap { + t := tw.timer + t.ts = nil + if t.state&timerZombie != 0 { + t.state &^= timerHeaped | timerZombie | timerModified + } else { + t.state &^= timerModified + ts.addHeap(t) + } + } + src.heap = nil + src.zombies.Store(0) + src.minWhenHeap.Store(0) + src.minWhenModified.Store(0) + src.len.Store(0) + ts.len.Store(uint32(len(ts.heap))) + } +} + +// adjust looks through the timers in ts.heap for +// any timers that have been modified to run earlier, and puts them in +// the correct place in the heap. While looking for those timers, +// it also moves timers that have been modified to run later, +// and removes deleted timers. The caller must have locked ts. +func (ts *timers) adjust(now int64, force bool) { + ts.trace("adjust") + assertLockHeld(&ts.mu) + // If we haven't yet reached the time of the earliest modified + // timer, don't do anything. This speeds up programs that adjust + // a lot of timers back and forth if the timers rarely expire. + // We'll postpone looking through all the adjusted timers until + // one would actually expire. + if !force { + first := ts.minWhenModified.Load() + if first == 0 || first > now { + if verifyTimers { + ts.verify() + } + return + } + } + + // minWhenModified is a lower bound on the earliest t.when + // among the timerModified timers. We want to make it more precise: + // we are going to scan the heap and clean out all the timerModified bits, + // at which point minWhenModified can be set to 0 (indicating none at all). + // + // Other P's can be calling ts.wakeTime concurrently, and we'd like to + // keep ts.wakeTime returning an accurate value throughout this entire process. + // + // Setting minWhenModified = 0 *before* the scan could make wakeTime + // return an incorrect value: if minWhenModified < minWhenHeap, then clearing + // it to 0 will make wakeTime return minWhenHeap (too late) until the scan finishes. + // To avoid that, we want to set minWhenModified to 0 *after* the scan. + // + // Setting minWhenModified = 0 *after* the scan could result in missing + // concurrent timer modifications in other goroutines; those will lock + // the specific timer, set the timerModified bit, and set t.when. + // To avoid that, we want to set minWhenModified to 0 *before* the scan. + // + // The way out of this dilemma is to preserve wakeTime a different way. + // wakeTime is min(minWhenHeap, minWhenModified), and minWhenHeap + // is protected by ts.lock, which we hold, so we can modify it however we like + // in service of keeping wakeTime accurate. + // + // So we can: + // + // 1. Set minWhenHeap = min(minWhenHeap, minWhenModified) + // 2. Set minWhenModified = 0 + // (Other goroutines may modify timers and update minWhenModified now.) + // 3. Scan timers + // 4. Set minWhenHeap = heap[0].when + // + // That order preserves a correct value of wakeTime throughout the entire + // operation: + // Step 1 “locks in” an accurate wakeTime even with minWhenModified cleared. + // Step 2 makes sure concurrent t.when updates are not lost during the scan. + // Step 3 processes all modified timer values, justifying minWhenModified = 0. + // Step 4 corrects minWhenHeap to a precise value. + // + // The wakeTime method implementation reads minWhenModified *before* minWhenHeap, + // so that if the minWhenModified is observed to be 0, that means the minWhenHeap that + // follows will include the information that was zeroed out of it. + // + // Originally Step 3 locked every timer, which made sure any timer update that was + // already in progress during Steps 1+2 completed and was observed by Step 3. + // All that locking was too expensive, so now we do an atomic load of t.astate to + // decide whether we need to do a full lock. To make sure that we still observe any + // timer update already in progress during Steps 1+2, t.modify sets timerModified + // in t.astate *before* calling t.updateMinWhenModified. That ensures that the + // overwrite in Step 2 cannot lose an update: if it does overwrite an update, Step 3 + // will see the timerModified and do a full lock. + ts.minWhenHeap.Store(ts.wakeTime()) + ts.minWhenModified.Store(0) + + changed := false + for i := 0; i < len(ts.heap); i++ { + tw := &ts.heap[i] + t := tw.timer + if t.ts != ts { + throw("bad ts") + } + + if t.astate.Load()&(timerModified|timerZombie) == 0 { + // Does not need adjustment. + continue + } + + t.lock() + switch { + case t.state&timerHeaped == 0: + badTimer() + + case t.state&timerZombie != 0: + ts.zombies.Add(-1) + t.state &^= timerHeaped | timerZombie | timerModified + n := len(ts.heap) + ts.heap[i] = ts.heap[n-1] + ts.heap[n-1] = timerWhen{} + ts.heap = ts.heap[:n-1] + t.ts = nil + i-- + changed = true + + case t.state&timerModified != 0: + tw.when = t.when + t.state &^= timerModified + changed = true + } + t.unlock() + } + + if changed { + ts.initHeap() + } + ts.updateMinWhenHeap() + + if verifyTimers { + ts.verify() + } +} + +// wakeTime looks at ts's timers and returns the time when we +// should wake up the netpoller. It returns 0 if there are no timers. +// This function is invoked when dropping a P, so it must run without +// any write barriers. +// +//go:nowritebarrierrec +func (ts *timers) wakeTime() int64 { + // Note that the order of these two loads matters: + // adjust updates minWhen to make it safe to clear minNextWhen. + // We read minWhen after reading minNextWhen so that + // if we see a cleared minNextWhen, we are guaranteed to see + // the updated minWhen. + nextWhen := ts.minWhenModified.Load() + when := ts.minWhenHeap.Load() + if when == 0 || (nextWhen != 0 && nextWhen < when) { + when = nextWhen + } + return when +} + +// check runs any timers in ts that are ready. +// If now is not 0 it is the current time. +// It returns the passed time or the current time if now was passed as 0. +// and the time when the next timer should run or 0 if there is no next timer, +// and reports whether it ran any timers. +// If the time when the next timer should run is not 0, +// it is always larger than the returned time. +// We pass now in and out to avoid extra calls of nanotime. +// +//go:yeswritebarrierrec +func (ts *timers) check(now int64) (rnow, pollUntil int64, ran bool) { + ts.trace("check") + // If it's not yet time for the first timer, or the first adjusted + // timer, then there is nothing to do. + next := ts.wakeTime() + if next == 0 { + // No timers to run or adjust. + return now, 0, false + } + + if now == 0 { + now = nanotime() + } + + // If this is the local P, and there are a lot of deleted timers, + // clear them out. We only do this for the local P to reduce + // lock contention on timersLock. + zombies := ts.zombies.Load() + if zombies < 0 { + badTimer() + } + force := ts == &getg().m.p.ptr().timers && int(zombies) > int(ts.len.Load())/4 + + if now < next && !force { + // Next timer is not ready to run, and we don't need to clear deleted timers. + return now, next, false + } + + ts.lock() + if len(ts.heap) > 0 { + ts.adjust(now, false) + for len(ts.heap) > 0 { + // Note that runtimer may temporarily unlock ts. + if tw := ts.run(now); tw != 0 { + if tw > 0 { + pollUntil = tw + } + break + } + ran = true + } + + // Note: Delaying the forced adjustment until after the ts.run + // (as opposed to calling ts.adjust(now, force) above) + // is significantly faster under contention, such as in + // package time's BenchmarkTimerAdjust10000, + // though we do not fully understand why. + force = ts == &getg().m.p.ptr().timers && int(ts.zombies.Load()) > int(ts.len.Load())/4 + if force { + ts.adjust(now, true) + } + } + ts.unlock() + + return now, pollUntil, ran +} + +// run examines the first timer in ts. If it is ready based on now, +// it runs the timer and removes or updates it. +// Returns 0 if it ran a timer, -1 if there are no more timers, or the time +// when the first timer should run. +// The caller must have locked ts. +// If a timer is run, this will temporarily unlock ts. +// +//go:systemstack +func (ts *timers) run(now int64) int64 { + ts.trace("run") + assertLockHeld(&ts.mu) +Redo: + if len(ts.heap) == 0 { + return -1 + } + tw := ts.heap[0] + t := tw.timer + if t.ts != ts { + throw("bad ts") + } + + if t.astate.Load()&(timerModified|timerZombie) == 0 && tw.when > now { + // Fast path: not ready to run. + return tw.when + } + + t.lock() + if t.updateHeap() { + t.unlock() + goto Redo + } + + if t.state&timerHeaped == 0 || t.state&timerModified != 0 { + badTimer() + } + + if t.when > now { + // Not ready to run. + t.unlock() + return t.when + } + + t.unlockAndRun(now) + assertLockHeld(&ts.mu) // t is unlocked now, but not ts + return 0 +} + +// unlockAndRun unlocks and runs the timer t (which must be locked). +// If t is in a timer set (t.ts != nil), the caller must also have locked the timer set, +// and this call will temporarily unlock the timer set while running the timer function. +// unlockAndRun returns with t unlocked and t.ts (re-)locked. +// +//go:systemstack +func (t *timer) unlockAndRun(now int64) { + t.trace("unlockAndRun") + assertLockHeld(&t.mu) + if t.ts != nil { + assertLockHeld(&t.ts.mu) + } + if raceenabled { + // Note that we are running on a system stack, + // so there is no chance of getg().m being reassigned + // out from under us while this function executes. + tsLocal := &getg().m.p.ptr().timers + if tsLocal.raceCtx == 0 { + tsLocal.raceCtx = racegostart(abi.FuncPCABIInternal((*timers).run) + sys.PCQuantum) + } + raceacquirectx(tsLocal.raceCtx, unsafe.Pointer(t)) + } + + if t.state&(timerModified|timerZombie) != 0 { + badTimer() + } + + f := t.f + arg := t.arg + seq := t.seq + var next int64 + delay := now - t.when + if t.period > 0 { + // Leave in heap but adjust next time to fire. + next = t.when + t.period*(1+delay/t.period) + if next < 0 { // check for overflow. + next = maxWhen + } + } else { + next = 0 + } + ts := t.ts + t.when = next + if t.state&timerHeaped != 0 { + t.state |= timerModified + if next == 0 { + t.state |= timerZombie + t.ts.zombies.Add(1) + } + t.updateHeap() + } + + async := debug.asynctimerchan.Load() != 0 + if !async && t.isChan && t.period == 0 { + // Tell Stop/Reset that we are sending a value. + if t.isSending.Add(1) < 0 { + throw("too many concurrent timer firings") + } + } + + t.unlock() + + if raceenabled { + // Temporarily use the current P's racectx for g0. + gp := getg() + if gp.racectx != 0 { + throw("unexpected racectx") + } + gp.racectx = gp.m.p.ptr().timers.raceCtx + } + + if ts != nil { + ts.unlock() + } + + if !async && t.isChan { + // For a timer channel, we want to make sure that no stale sends + // happen after a t.stop or t.modify, but we cannot hold t.mu + // during the actual send (which f does) due to lock ordering. + // It can happen that we are holding t's lock above, we decide + // it's time to send a time value (by calling f), grab the parameters, + // unlock above, and then a t.stop or t.modify changes the timer + // and returns. At that point, the send needs not to happen after all. + // The way we arrange for it not to happen is that t.stop and t.modify + // both increment t.seq while holding both t.mu and t.sendLock. + // We copied the seq value above while holding t.mu. + // Now we can acquire t.sendLock (which will be held across the send) + // and double-check that t.seq is still the seq value we saw above. + // If not, the timer has been updated and we should skip the send. + // We skip the send by reassigning f to a no-op function. + // + // The isSending field tells t.stop or t.modify that we have + // started to send the value. That lets them correctly return + // true meaning that no value was sent. + lock(&t.sendLock) + + if t.period == 0 { + // We are committed to possibly sending a value + // based on seq, so no need to keep telling + // stop/modify that we are sending. + if t.isSending.Add(-1) < 0 { + throw("mismatched isSending updates") + } + } + + if t.seq != seq { + f = func(any, uintptr, int64) {} + } + } + + f(arg, seq, delay) + + if !async && t.isChan { + unlock(&t.sendLock) + } + + if ts != nil { + ts.lock() + } + + if raceenabled { + gp := getg() + gp.racectx = 0 + } +} + +// verifyTimerHeap verifies that the timers is in a valid state. +// This is only for debugging, and is only called if verifyTimers is true. +// The caller must have locked ts. +func (ts *timers) verify() { + assertLockHeld(&ts.mu) + for i, tw := range ts.heap { + if i == 0 { + // First timer has no parent. + continue + } + + // The heap is timerHeapN-ary. See siftupTimer and siftdownTimer. + p := int(uint(i-1) / timerHeapN) + if tw.when < ts.heap[p].when { + print("bad timer heap at ", i, ": ", p, ": ", ts.heap[p].when, ", ", i, ": ", tw.when, "\n") + throw("bad timer heap") + } + } + if n := int(ts.len.Load()); len(ts.heap) != n { + println("timer heap len", len(ts.heap), "!= atomic len", n) + throw("bad timer heap len") + } +} + +// updateMinWhenHeap sets ts.minWhenHeap to ts.heap[0].when. +// The caller must have locked ts or the world must be stopped. +func (ts *timers) updateMinWhenHeap() { + assertWorldStoppedOrLockHeld(&ts.mu) + if len(ts.heap) == 0 { + ts.minWhenHeap.Store(0) + } else { + ts.minWhenHeap.Store(ts.heap[0].when) + } +} + +// updateMinWhenModified updates ts.minWhenModified to be <= when. +// ts need not be (and usually is not) locked. +func (ts *timers) updateMinWhenModified(when int64) { + for { + old := ts.minWhenModified.Load() + if old != 0 && old < when { + return + } + if ts.minWhenModified.CompareAndSwap(old, when) { + return + } + } +} + +// timeSleepUntil returns the time when the next timer should fire. Returns +// maxWhen if there are no timers. +// This is only called by sysmon and checkdead. +func timeSleepUntil() int64 { + next := int64(maxWhen) + + // Prevent allp slice changes. This is like retake. + lock(&allpLock) + for _, pp := range allp { + if pp == nil { + // This can happen if procresize has grown + // allp but not yet created new Ps. + continue + } + + if w := pp.timers.wakeTime(); w != 0 { + next = min(next, w) + } + } + unlock(&allpLock) + + return next +} + +const timerHeapN = 4 + +// Heap maintenance algorithms. +// These algorithms check for slice index errors manually. +// Slice index error can happen if the program is using racy +// access to timers. We don't want to panic here, because +// it will cause the program to crash with a mysterious +// "panic holding locks" message. Instead, we panic while not +// holding a lock. + +// siftUp puts the timer at position i in the right place +// in the heap by moving it up toward the top of the heap. +func (ts *timers) siftUp(i int) { + heap := ts.heap + if i >= len(heap) { + badTimer() + } + tw := heap[i] + when := tw.when + if when <= 0 { + badTimer() + } + for i > 0 { + p := int(uint(i-1) / timerHeapN) // parent + if when >= heap[p].when { + break + } + heap[i] = heap[p] + i = p + } + if heap[i].timer != tw.timer { + heap[i] = tw + } +} + +// siftDown puts the timer at position i in the right place +// in the heap by moving it down toward the bottom of the heap. +func (ts *timers) siftDown(i int) { + heap := ts.heap + n := len(heap) + if i >= n { + badTimer() + } + if i*timerHeapN+1 >= n { + return + } + tw := heap[i] + when := tw.when + if when <= 0 { + badTimer() + } + for { + leftChild := i*timerHeapN + 1 + if leftChild >= n { + break + } + w := when + c := -1 + for j, tw := range heap[leftChild:min(leftChild+timerHeapN, n)] { + if tw.when < w { + w = tw.when + c = leftChild + j + } + } + if c < 0 { + break + } + heap[i] = heap[c] + i = c + } + if heap[i].timer != tw.timer { + heap[i] = tw + } +} + +// initHeap reestablishes the heap order in the slice ts.heap. +// It takes O(n) time for n=len(ts.heap), not the O(n log n) of n repeated add operations. +func (ts *timers) initHeap() { + // Last possible element that needs sifting down is parent of last element; + // last element is len(t)-1; parent of last element is (len(t)-1-1)/timerHeapN. + if len(ts.heap) <= 1 { + return + } + for i := int(uint(len(ts.heap)-1-1) / timerHeapN); i >= 0; i-- { + ts.siftDown(i) + } +} + +// badTimer is called if the timer data structures have been corrupted, +// presumably due to racy use by the program. We panic here rather than +// panicking due to invalid slice access while holding locks. +// See issue #25686. +func badTimer() { + throw("timer data corruption") +} + +// Timer channels. + +// maybeRunChan checks whether the timer needs to run +// to send a value to its associated channel. If so, it does. +// The timer must not be locked. +func (t *timer) maybeRunChan() { + if t.astate.Load()&timerHeaped != 0 { + // If the timer is in the heap, the ordinary timer code + // is in charge of sending when appropriate. + return + } + + t.lock() + now := nanotime() + if t.state&timerHeaped != 0 || t.when == 0 || t.when > now { + t.trace("maybeRunChan-") + // Timer in the heap, or not running at all, or not triggered. + t.unlock() + return + } + t.trace("maybeRunChan+") + systemstack(func() { + t.unlockAndRun(now) + }) +} + +// blockTimerChan is called when a channel op has decided to block on c. +// The caller holds the channel lock for c and possibly other channels. +// blockTimerChan makes sure that c is in a timer heap, +// adding it if needed. +func blockTimerChan(c *hchan) { + t := c.timer + t.lock() + t.trace("blockTimerChan") + if !t.isChan { + badTimer() + } + + t.blocked++ + + // If this is the first enqueue after a recent dequeue, + // the timer may still be in the heap but marked as a zombie. + // Unmark it in this case, if the timer is still pending. + if t.state&timerHeaped != 0 && t.state&timerZombie != 0 && t.when > 0 { + t.state &^= timerZombie + t.ts.zombies.Add(-1) + } + + // t.maybeAdd must be called with t unlocked, + // because it needs to lock t.ts before t. + // Then it will do nothing if t.needsAdd(state) is false. + // Check that now before the unlock, + // avoiding the extra lock-lock-unlock-unlock + // inside maybeAdd when t does not need to be added. + add := t.needsAdd() + t.unlock() + if add { + t.maybeAdd() + } +} + +// unblockTimerChan is called when a channel op that was blocked on c +// is no longer blocked. Every call to blockTimerChan must be paired with +// a call to unblockTimerChan. +// The caller holds the channel lock for c and possibly other channels. +// unblockTimerChan removes c from the timer heap when nothing is +// blocked on it anymore. +func unblockTimerChan(c *hchan) { + t := c.timer + t.lock() + t.trace("unblockTimerChan") + if !t.isChan || t.blocked == 0 { + badTimer() + } + t.blocked-- + if t.blocked == 0 && t.state&timerHeaped != 0 && t.state&timerZombie == 0 { + // Last goroutine that was blocked on this timer. + // Mark for removal from heap but do not clear t.when, + // so that we know what time it is still meant to trigger. + t.state |= timerZombie + t.ts.zombies.Add(1) + } + t.unlock() +} diff --git a/contrib/go/_std_1.22/src/runtime/time_fake.go b/contrib/go/_std_1.23/src/runtime/time_fake.go similarity index 99% rename from contrib/go/_std_1.22/src/runtime/time_fake.go rename to contrib/go/_std_1.23/src/runtime/time_fake.go index 9e24f7093105..aad1950c4837 100644 --- a/contrib/go/_std_1.22/src/runtime/time_fake.go +++ b/contrib/go/_std_1.23/src/runtime/time_fake.go @@ -31,6 +31,7 @@ var faketimeState struct { lastfd uintptr } +//go:linkname nanotime //go:nosplit func nanotime() int64 { return faketime diff --git a/contrib/go/_std_1.22/src/runtime/time_linux_amd64.s b/contrib/go/_std_1.23/src/runtime/time_linux_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/time_linux_amd64.s rename to contrib/go/_std_1.23/src/runtime/time_linux_amd64.s diff --git a/contrib/go/_std_1.23/src/runtime/time_nofake.go b/contrib/go/_std_1.23/src/runtime/time_nofake.go new file mode 100644 index 000000000000..130ff1281662 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/time_nofake.go @@ -0,0 +1,58 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !faketime + +package runtime + +import "unsafe" + +// faketime is the simulated time in nanoseconds since 1970 for the +// playground. +// +// Zero means not to use faketime. +var faketime int64 + +// Exported via linkname for use by time and internal/poll. +// +// Many external packages also linkname nanotime for a fast monotonic time. +// Such code should be updated to use: +// +// var start = time.Now() // at init time +// +// and then replace nanotime() with time.Since(start), which is equally fast. +// +// However, all the code linknaming nanotime is never going to go away. +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname nanotime +//go:nosplit +func nanotime() int64 { + return nanotime1() +} + +// overrideWrite allows write to be redirected externally, by +// linkname'ing this and set it to a write function. +// +// overrideWrite should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - golang.zx2c4.com/wireguard/windows +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname overrideWrite +var overrideWrite func(fd uintptr, p unsafe.Pointer, n int32) int32 + +// write must be nosplit on Windows (see write1) +// +//go:nosplit +func write(fd uintptr, p unsafe.Pointer, n int32) int32 { + if overrideWrite != nil { + return overrideWrite(fd, noescape(p), n) + } + return write1(fd, p, n) +} diff --git a/contrib/go/_std_1.22/src/runtime/time_windows.h b/contrib/go/_std_1.23/src/runtime/time_windows.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/time_windows.h rename to contrib/go/_std_1.23/src/runtime/time_windows.h diff --git a/contrib/go/_std_1.22/src/runtime/time_windows_386.s b/contrib/go/_std_1.23/src/runtime/time_windows_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/time_windows_386.s rename to contrib/go/_std_1.23/src/runtime/time_windows_386.s diff --git a/contrib/go/_std_1.22/src/runtime/time_windows_amd64.s b/contrib/go/_std_1.23/src/runtime/time_windows_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/time_windows_amd64.s rename to contrib/go/_std_1.23/src/runtime/time_windows_amd64.s diff --git a/contrib/go/_std_1.22/src/runtime/time_windows_arm.s b/contrib/go/_std_1.23/src/runtime/time_windows_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/time_windows_arm.s rename to contrib/go/_std_1.23/src/runtime/time_windows_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/time_windows_arm64.s b/contrib/go/_std_1.23/src/runtime/time_windows_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/time_windows_arm64.s rename to contrib/go/_std_1.23/src/runtime/time_windows_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/timeasm.go b/contrib/go/_std_1.23/src/runtime/timeasm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/timeasm.go rename to contrib/go/_std_1.23/src/runtime/timeasm.go diff --git a/contrib/go/_std_1.22/src/runtime/timestub.go b/contrib/go/_std_1.23/src/runtime/timestub.go similarity index 59% rename from contrib/go/_std_1.22/src/runtime/timestub.go rename to contrib/go/_std_1.23/src/runtime/timestub.go index 1d2926b43dc3..da8699b5ee60 100644 --- a/contrib/go/_std_1.22/src/runtime/timestub.go +++ b/contrib/go/_std_1.23/src/runtime/timestub.go @@ -11,6 +11,17 @@ package runtime import _ "unsafe" // for go:linkname +// time_now should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - gitee.com/quant1x/gox +// - github.com/phuslu/log +// - github.com/sethvargo/go-limiter +// - github.com/ulule/limiter/v3 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// //go:linkname time_now time.now func time_now() (sec int64, nsec int32, mono int64) { sec, nsec = walltime() diff --git a/contrib/go/_std_1.22/src/runtime/timestub2.go b/contrib/go/_std_1.23/src/runtime/timestub2.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/timestub2.go rename to contrib/go/_std_1.23/src/runtime/timestub2.go diff --git a/contrib/go/_std_1.22/src/runtime/tls_arm.s b/contrib/go/_std_1.23/src/runtime/tls_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_arm.s rename to contrib/go/_std_1.23/src/runtime/tls_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_arm64.h b/contrib/go/_std_1.23/src/runtime/tls_arm64.h similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_arm64.h rename to contrib/go/_std_1.23/src/runtime/tls_arm64.h diff --git a/contrib/go/_std_1.22/src/runtime/tls_arm64.s b/contrib/go/_std_1.23/src/runtime/tls_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_arm64.s rename to contrib/go/_std_1.23/src/runtime/tls_arm64.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_loong64.s b/contrib/go/_std_1.23/src/runtime/tls_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_loong64.s rename to contrib/go/_std_1.23/src/runtime/tls_loong64.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_mips64x.s b/contrib/go/_std_1.23/src/runtime/tls_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_mips64x.s rename to contrib/go/_std_1.23/src/runtime/tls_mips64x.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_mipsx.s b/contrib/go/_std_1.23/src/runtime/tls_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_mipsx.s rename to contrib/go/_std_1.23/src/runtime/tls_mipsx.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_ppc64x.s b/contrib/go/_std_1.23/src/runtime/tls_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_ppc64x.s rename to contrib/go/_std_1.23/src/runtime/tls_ppc64x.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_riscv64.s b/contrib/go/_std_1.23/src/runtime/tls_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_riscv64.s rename to contrib/go/_std_1.23/src/runtime/tls_riscv64.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_s390x.s b/contrib/go/_std_1.23/src/runtime/tls_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_s390x.s rename to contrib/go/_std_1.23/src/runtime/tls_s390x.s diff --git a/contrib/go/_std_1.22/src/runtime/tls_stub.go b/contrib/go/_std_1.23/src/runtime/tls_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_stub.go rename to contrib/go/_std_1.23/src/runtime/tls_stub.go diff --git a/contrib/go/_std_1.22/src/runtime/tls_windows_amd64.go b/contrib/go/_std_1.23/src/runtime/tls_windows_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/tls_windows_amd64.go rename to contrib/go/_std_1.23/src/runtime/tls_windows_amd64.go diff --git a/contrib/go/_std_1.22/src/runtime/trace2.go b/contrib/go/_std_1.23/src/runtime/trace.go similarity index 87% rename from contrib/go/_std_1.22/src/runtime/trace2.go rename to contrib/go/_std_1.23/src/runtime/trace.go index 673205dda8a4..adf7b0951dce 100644 --- a/contrib/go/_std_1.22/src/runtime/trace2.go +++ b/contrib/go/_std_1.23/src/runtime/trace.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build goexperiment.exectracer2 - // Go execution tracer. // The tracer captures a wide range of execution events like goroutine // creation/blocking/unblocking, syscall enter/exit/block, GC-related events, @@ -22,7 +20,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) @@ -69,6 +67,7 @@ var trace struct { // There are 2 of each: one for gen%2, one for 1-gen%2. stackTab [2]traceStackTable // maps stack traces to unique ids stringTab [2]traceStringTable // maps strings to unique ids + typeTab [2]traceTypeTable // maps type pointers to unique ids // cpuLogRead accepts CPU profile samples from the signal handler where // they're generated. There are two profBufs here: one for gen%2, one for @@ -98,6 +97,24 @@ var trace struct { goStopReasons [2][len(traceGoStopReasonStrings)]traceArg goBlockReasons [2][len(traceBlockReasonStrings)]traceArg + // enabled indicates whether tracing is enabled, but it is only an optimization, + // NOT the source of truth on whether tracing is enabled. Tracing is only truly + // enabled if gen != 0. This is used as an optimistic fast path check. + // + // Transitioning this value from true -> false is easy (once gen is 0) + // because it's OK for enabled to have a stale "true" value. traceAcquire will + // always double-check gen. + // + // Transitioning this value from false -> true is harder. We need to make sure + // this is observable as true strictly before gen != 0. To maintain this invariant + // we only make this transition with the world stopped and use the store to gen + // as a publication barrier. + enabled bool + + // enabledWithAllocFree is set if debug.traceallocfree is != 0 when tracing begins. + // It follows the same synchronization protocol as enabled. + enabledWithAllocFree bool + // Trace generation counter. gen atomic.Uintptr lastNonZeroGen uintptr // last non-zero value of gen @@ -114,6 +131,12 @@ var trace struct { // // Mutated only during stop-the-world. seqGC uint64 + + // minPageHeapAddr is the minimum address of the page heap when tracing started. + minPageHeapAddr uint64 + + // debugMalloc is the value of debug.malloc before tracing began. + debugMalloc bool } // Trace public API. @@ -204,6 +227,10 @@ func StartTrace() error { // Prevent sysmon from running any code that could generate events. lock(&sched.sysmonlock) + // Grab the minimum page heap address. All Ps are stopped, so it's safe to read this since + // nothing can allocate heap memory. + trace.minPageHeapAddr = uint64(mheap_.pages.inUse.ranges[0].base.addr()) + // Reset mSyscallID on all Ps while we have them stationary and the trace is disabled. for _, pp := range allp { pp.trace.mSyscallID = -1 @@ -211,8 +238,25 @@ func StartTrace() error { // Start tracing. // - // After this executes, other Ms may start creating trace buffers and emitting + // Set trace.enabled. This is *very* subtle. We need to maintain the invariant that if + // trace.gen != 0, then trace.enabled is always observed as true. Simultaneously, for + // performance, we need trace.enabled to be read without any synchronization. + // + // We ensure this is safe by stopping the world, which acts a global barrier on almost + // every M, and explicitly synchronize with any other Ms that could be running concurrently + // with us. Today, there are only two such cases: + // - sysmon, which we synchronized with by acquiring sysmonlock. + // - goroutines exiting syscalls, which we synchronize with via trace.exitingSyscall. + // + // After trace.gen is updated, other Ms may start creating trace buffers and emitting // data into them. + trace.enabled = true + if debug.traceallocfree.Load() != 0 { + // Enable memory events since the GODEBUG is set. + trace.debugMalloc = debug.malloc + trace.enabledWithAllocFree = true + debug.malloc = true + } trace.gen.Store(firstGen) // Wait for exitingSyscall to drain. @@ -222,8 +266,9 @@ func StartTrace() error { // goroutines to run on. // // Because we set gen before checking this, and because exitingSyscall is always incremented - // *after* traceAcquire (which checks gen), we can be certain that when exitingSyscall is zero - // that any goroutine that goes to exit a syscall from then on *must* observe the new gen. + // *before* traceAcquire (which checks gen), we can be certain that when exitingSyscall is zero + // that any goroutine that goes to exit a syscall from then on *must* observe the new gen as + // well as trace.enabled being set to true. // // The critical section on each goroutine here is going to be quite short, so the likelihood // that we observe a zero value is high. @@ -243,6 +288,11 @@ func StartTrace() error { tl.GCActive() } + // Dump a snapshot of memory, if enabled. + if trace.enabledWithAllocFree { + traceSnapshotMemory(firstGen) + } + // Record the heap goal so we have it at the very beginning of the trace. tl.HeapGoal() @@ -273,6 +323,10 @@ func StopTrace() { // altogether instead of advancing to the next generation. // // traceAdvanceSema must not be held. +// +// traceAdvance is called by golang.org/x/exp/trace using linkname. +// +//go:linkname traceAdvance func traceAdvance(stopTrace bool) { semacquire(&traceAdvanceSema) @@ -297,6 +351,7 @@ func traceAdvance(stopTrace bool) { gp *g goid uint64 mid int64 + stackID uint64 status uint32 waitreason waitReason inMarkAssist bool @@ -320,7 +375,7 @@ func traceAdvance(stopTrace bool) { me := getg().m.curg // We don't have to handle this G status transition because we // already eliminated ourselves from consideration above. - casGToWaiting(me, _Grunning, waitReasonTraceGoroutineStatus) + casGToWaitingForGC(me, _Grunning, waitReasonTraceGoroutineStatus) // We need to suspend and take ownership of the G to safely read its // goid. Note that we can't actually emit the event at this point // because we might stop the G in a window where it's unsafe to write @@ -340,6 +395,7 @@ func traceAdvance(stopTrace bool) { ug.status = readgstatus(s.g) &^ _Gscan ug.waitreason = s.g.waitreason ug.inMarkAssist = s.g.inMarkAssist + ug.stackID = traceStack(0, gp, gen) } resumeG(s) casgstatus(me, _Gwaiting, _Grunning) @@ -376,6 +432,10 @@ func traceAdvance(stopTrace bool) { trace.shutdown.Store(true) trace.gen.Store(0) unlock(&trace.lock) + + // Clear trace.enabled. It is totally OK for this value to be stale, + // because traceAcquire will always double-check gen. + trace.enabled = false }) } else { trace.gen.Store(traceNextGen(gen)) @@ -512,34 +572,60 @@ func traceAdvance(stopTrace bool) { // traced in gen between when we recorded it and now. If that's true, the goid // and status we recorded then is exactly what we want right now. status := goStatusToTraceGoStatus(ug.status, ug.waitreason) - statusWriter = statusWriter.writeGoStatus(ug.goid, ug.mid, status, ug.inMarkAssist) + statusWriter = statusWriter.writeGoStatus(ug.goid, ug.mid, status, ug.inMarkAssist, ug.stackID) } statusWriter.flush().end() // Read everything out of the last gen's CPU profile buffer. traceReadCPU(gen) + // Flush CPU samples, stacks, and strings for the last generation. This is safe, + // because we're now certain no M is writing to the last generation. + // + // Ordering is important here. traceCPUFlush may generate new stacks and dumping + // stacks may generate new strings. + traceCPUFlush(gen) + trace.stackTab[gen%2].dump(gen) + trace.typeTab[gen%2].dump(gen) + trace.stringTab[gen%2].reset(gen) + + // That's it. This generation is done producing buffers. systemstack(func() { - // Flush CPU samples, stacks, and strings for the last generation. This is safe, - // because we're now certain no M is writing to the last generation. - // - // Ordering is important here. traceCPUFlush may generate new stacks and dumping - // stacks may generate new strings. - traceCPUFlush(gen) - trace.stackTab[gen%2].dump(gen) - trace.stringTab[gen%2].reset(gen) - - // That's it. This generation is done producing buffers. lock(&trace.lock) trace.flushedGen.Store(gen) unlock(&trace.lock) }) + // Perform status reset on dead Ps because they just appear as idle. + // + // Preventing preemption is sufficient to access allp safely. allp is only + // mutated by GOMAXPROCS calls, which require a STW. + // + // TODO(mknyszek): Consider explicitly emitting ProcCreate and ProcDestroy + // events to indicate whether a P exists, rather than just making its + // existence implicit. + mp = acquirem() + for _, pp := range allp[len(allp):cap(allp)] { + pp.trace.readyNextGen(traceNextGen(gen)) + } + releasem(mp) + if stopTrace { + // Acquire the shutdown sema to begin the shutdown process. semacquire(&traceShutdownSema) // Finish off CPU profile reading. traceStopReadCPU() + + // Reset debug.malloc if necessary. Note that this is set in a racy + // way; that's OK. Some mallocs may still enter into the debug.malloc + // block, but they won't generate events because tracing is disabled. + // That is, it's OK if mallocs read a stale debug.malloc or + // trace.enabledWithAllocFree value. + if trace.enabledWithAllocFree { + trace.enabledWithAllocFree = false + debug.malloc = trace.debugMalloc + } } else { // Go over each P and emit a status event for it if necessary. // @@ -556,16 +642,6 @@ func traceAdvance(stopTrace bool) { } traceRelease(tl) }) - // Perform status reset on dead Ps because they just appear as idle. - // - // Holding worldsema prevents allp from changing. - // - // TODO(mknyszek): Consider explicitly emitting ProcCreate and ProcDestroy - // events to indicate whether a P exists, rather than just making its - // existence implicit. - for _, pp := range allp[len(allp):cap(allp)] { - pp.trace.readyNextGen(traceNextGen(gen)) - } semrelease(&worldsema) } @@ -743,7 +819,7 @@ func readTrace0() (buf []byte, park bool) { if !trace.headerWritten { trace.headerWritten = true unlock(&trace.lock) - return []byte("go 1.22 trace\x00\x00\x00"), false + return []byte("go 1.23 trace\x00\x00\x00"), false } // Read the next buffer. @@ -920,10 +996,10 @@ func newWakeableSleep() *wakeableSleep { lockInit(&s.lock, lockRankWakeableSleep) s.wakeup = make(chan struct{}, 1) s.timer = new(timer) - s.timer.arg = s - s.timer.f = func(s any, _ uintptr) { + f := func(s any, _ uintptr, _ int64) { s.(*wakeableSleep).wake() } + s.timer.init(f, s) return s } @@ -933,7 +1009,7 @@ func newWakeableSleep() *wakeableSleep { // Must not be called by more than one goroutine at a time and // must not be called concurrently with close. func (s *wakeableSleep) sleep(ns int64) { - resetTimer(s.timer, nanotime()+ns) + s.timer.reset(nanotime()+ns, 0) lock(&s.lock) if raceenabled { raceacquire(unsafe.Pointer(&s.lock)) @@ -944,7 +1020,7 @@ func (s *wakeableSleep) sleep(ns int64) { } unlock(&s.lock) <-wakeup - stopTimer(s.timer) + s.timer.stop() } // wake awakens any goroutine sleeping on the timer. diff --git a/contrib/go/_std_1.22/src/runtime/trace/annotation.go b/contrib/go/_std_1.23/src/runtime/trace/annotation.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/trace/annotation.go rename to contrib/go/_std_1.23/src/runtime/trace/annotation.go diff --git a/contrib/go/_std_1.22/src/runtime/trace/trace.go b/contrib/go/_std_1.23/src/runtime/trace/trace.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/trace/trace.go rename to contrib/go/_std_1.23/src/runtime/trace/trace.go diff --git a/contrib/go/_std_1.22/src/runtime/trace/ya.make b/contrib/go/_std_1.23/src/runtime/trace/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/runtime/trace/ya.make rename to contrib/go/_std_1.23/src/runtime/trace/ya.make diff --git a/contrib/go/_std_1.23/src/runtime/traceallocfree.go b/contrib/go/_std_1.23/src/runtime/traceallocfree.go new file mode 100644 index 000000000000..e6a2a79c691b --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/traceallocfree.go @@ -0,0 +1,162 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Runtime -> tracer API for memory events. + +package runtime + +import ( + "internal/abi" + "runtime/internal/sys" +) + +// Batch type values for the alloc/free experiment. +const ( + traceAllocFreeTypesBatch = iota // Contains types. [{id, address, size, ptrspan, name length, name string} ...] + traceAllocFreeInfoBatch // Contains info for interpreting events. [min heap addr, page size, min heap align, min stack align] +) + +// traceSnapshotMemory takes a snapshot of all runtime memory that there are events for +// (heap spans, heap objects, goroutine stacks, etc.) and writes out events for them. +// +// The world must be stopped and tracing must be enabled when this function is called. +func traceSnapshotMemory(gen uintptr) { + assertWorldStopped() + + // Write a batch containing information that'll be necessary to + // interpret the events. + var flushed bool + w := unsafeTraceExpWriter(gen, nil, traceExperimentAllocFree) + w, flushed = w.ensure(1 + 4*traceBytesPerNumber) + if flushed { + // Annotate the batch as containing additional info. + w.byte(byte(traceAllocFreeInfoBatch)) + } + + // Emit info. + w.varint(uint64(trace.minPageHeapAddr)) + w.varint(uint64(pageSize)) + w.varint(uint64(minHeapAlign)) + w.varint(uint64(fixedStack)) + + // Finish writing the batch. + w.flush().end() + + // Start tracing. + trace := traceAcquire() + if !trace.ok() { + throw("traceSnapshotMemory: tracing is not enabled") + } + + // Write out all the heap spans and heap objects. + for _, s := range mheap_.allspans { + if s.state.get() == mSpanDead { + continue + } + // It's some kind of span, so trace that it exists. + trace.SpanExists(s) + + // Write out allocated objects if it's a heap span. + if s.state.get() != mSpanInUse { + continue + } + + // Find all allocated objects. + abits := s.allocBitsForIndex(0) + for i := uintptr(0); i < uintptr(s.nelems); i++ { + if abits.index < uintptr(s.freeindex) || abits.isMarked() { + x := s.base() + i*s.elemsize + trace.HeapObjectExists(x, s.typePointersOfUnchecked(x).typ) + } + abits.advance() + } + } + + // Write out all the goroutine stacks. + forEachGRace(func(gp *g) { + trace.GoroutineStackExists(gp.stack.lo, gp.stack.hi-gp.stack.lo) + }) + traceRelease(trace) +} + +func traceSpanTypeAndClass(s *mspan) traceArg { + if s.state.get() == mSpanInUse { + return traceArg(s.spanclass) << 1 + } + return traceArg(1) +} + +// SpanExists records an event indicating that the span exists. +func (tl traceLocker) SpanExists(s *mspan) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvSpan, traceSpanID(s), traceArg(s.npages), traceSpanTypeAndClass(s)) +} + +// SpanAlloc records an event indicating that the span has just been allocated. +func (tl traceLocker) SpanAlloc(s *mspan) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvSpanAlloc, traceSpanID(s), traceArg(s.npages), traceSpanTypeAndClass(s)) +} + +// SpanFree records an event indicating that the span is about to be freed. +func (tl traceLocker) SpanFree(s *mspan) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvSpanFree, traceSpanID(s)) +} + +// traceSpanID creates a trace ID for the span s for the trace. +func traceSpanID(s *mspan) traceArg { + return traceArg(uint64(s.base())-trace.minPageHeapAddr) / pageSize +} + +// HeapObjectExists records that an object already exists at addr with the provided type. +// The type is optional, and the size of the slot occupied the object is inferred from the +// span containing it. +func (tl traceLocker) HeapObjectExists(addr uintptr, typ *abi.Type) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapObject, traceHeapObjectID(addr), tl.rtype(typ)) +} + +// HeapObjectAlloc records that an object was newly allocated at addr with the provided type. +// The type is optional, and the size of the slot occupied the object is inferred from the +// span containing it. +func (tl traceLocker) HeapObjectAlloc(addr uintptr, typ *abi.Type) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapObjectAlloc, traceHeapObjectID(addr), tl.rtype(typ)) +} + +// HeapObjectFree records that an object at addr is about to be freed. +func (tl traceLocker) HeapObjectFree(addr uintptr) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapObjectFree, traceHeapObjectID(addr)) +} + +// traceHeapObjectID creates a trace ID for a heap object at address addr. +func traceHeapObjectID(addr uintptr) traceArg { + return traceArg(uint64(addr)-trace.minPageHeapAddr) / minHeapAlign +} + +// GoroutineStackExists records that a goroutine stack already exists at address base with the provided size. +func (tl traceLocker) GoroutineStackExists(base, size uintptr) { + order := traceCompressStackSize(size) + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoroutineStack, traceGoroutineStackID(base), order) +} + +// GoroutineStackAlloc records that a goroutine stack was newly allocated at address base with the provided size.. +func (tl traceLocker) GoroutineStackAlloc(base, size uintptr) { + order := traceCompressStackSize(size) + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoroutineStackAlloc, traceGoroutineStackID(base), order) +} + +// GoroutineStackFree records that a goroutine stack at address base is about to be freed. +func (tl traceLocker) GoroutineStackFree(base uintptr) { + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoroutineStackFree, traceGoroutineStackID(base)) +} + +// traceGoroutineStackID creates a trace ID for the goroutine stack from its base address. +func traceGoroutineStackID(base uintptr) traceArg { + return traceArg(uint64(base)-trace.minPageHeapAddr) / fixedStack +} + +// traceCompressStackSize assumes size is a power of 2 and returns log2(size). +func traceCompressStackSize(size uintptr) traceArg { + if size&(size-1) != 0 { + throw("goroutine stack size is not a power of 2") + } + return traceArg(sys.Len64(uint64(size))) +} diff --git a/contrib/go/_std_1.22/src/runtime/traceback.go b/contrib/go/_std_1.23/src/runtime/traceback.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/traceback.go rename to contrib/go/_std_1.23/src/runtime/traceback.go index 1e5afc6bdde6..03c02f77713a 100644 --- a/contrib/go/_std_1.22/src/runtime/traceback.go +++ b/contrib/go/_std_1.23/src/runtime/traceback.go @@ -8,6 +8,7 @@ import ( "internal/abi" "internal/bytealg" "internal/goarch" + "internal/stringslite" "runtime/internal/sys" "unsafe" ) @@ -182,8 +183,8 @@ func (u *unwinder) initAt(pc0, sp0, lr0 uintptr, gp *g, flags unwindFlags) { } } - // runtime/internal/atomic functions call into kernel helpers on - // arm < 7. See runtime/internal/atomic/sys_linux_arm.s. + // internal/runtime/atomic functions call into kernel helpers on + // arm < 7. See internal/runtime/atomic/sys_linux_arm.s. // // Start in the caller's frame. if GOARCH == "arm" && goarm < 7 && GOOS == "linux" && frame.pc&0xffff0000 == 0xffff0000 { @@ -632,8 +633,11 @@ func tracebackPCs(u *unwinder, skip int, pcBuf []uintptr) int { skip-- } else { // Callers expect the pc buffer to contain return addresses - // and do the -1 themselves, so we add 1 to the call PC to - // create a return PC. + // and do the -1 themselves, so we add 1 to the call pc to + // create a "return pc". Since there is no actual call, here + // "return pc" just means a pc you subtract 1 from to get + // the pc of the "call". The actual no-op we insert may or + // may not be 1 byte. pcBuf[n] = uf.pc + 1 n++ } @@ -650,25 +654,7 @@ func tracebackPCs(u *unwinder, skip int, pcBuf []uintptr) int { // printArgs prints function arguments in traceback. func printArgs(f funcInfo, argp unsafe.Pointer, pc uintptr) { - // The "instruction" of argument printing is encoded in _FUNCDATA_ArgInfo. - // See cmd/compile/internal/ssagen.emitArgInfo for the description of the - // encoding. - // These constants need to be in sync with the compiler. - const ( - _endSeq = 0xff - _startAgg = 0xfe - _endAgg = 0xfd - _dotdotdot = 0xfc - _offsetTooLarge = 0xfb - ) - - const ( - limit = 10 // print no more than 10 args/components - maxDepth = 5 // no more than 5 layers of nesting - maxLen = (maxDepth*3+2)*limit + 1 // max length of _FUNCDATA_ArgInfo (see the compiler side for reasoning) - ) - - p := (*[maxLen]uint8)(funcdata(f, abi.FUNCDATA_ArgInfo)) + p := (*[abi.TraceArgsMaxLen]uint8)(funcdata(f, abi.FUNCDATA_ArgInfo)) if p == nil { return } @@ -721,19 +707,19 @@ printloop: o := p[pi] pi++ switch o { - case _endSeq: + case abi.TraceArgsEndSeq: break printloop - case _startAgg: + case abi.TraceArgsStartAgg: printcomma() print("{") start = true continue - case _endAgg: + case abi.TraceArgsEndAgg: print("}") - case _dotdotdot: + case abi.TraceArgsDotdotdot: printcomma() print("...") - case _offsetTooLarge: + case abi.TraceArgsOffsetTooLarge: printcomma() print("_") default: @@ -1093,6 +1079,16 @@ func printAncestorTracebackFuncInfo(f funcInfo, pc uintptr) { print("\n") } +// callers should be an internal detail, +// (and is almost identical to Callers), +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname callers func callers(skip int, pcbuf []uintptr) int { sp := getcallersp() pc := getcallerpc() @@ -1146,15 +1142,37 @@ func showfuncinfo(sf srcFunc, firstFrame bool, calleeID abi.FuncID) bool { return true } - return bytealg.IndexByteString(name, '.') >= 0 && (!hasPrefix(name, "runtime.") || isExportedRuntime(name)) + return bytealg.IndexByteString(name, '.') >= 0 && (!stringslite.HasPrefix(name, "runtime.") || isExportedRuntime(name)) } // isExportedRuntime reports whether name is an exported runtime function. // It is only for runtime functions, so ASCII A-Z is fine. -// TODO: this handles exported functions but not exported methods. func isExportedRuntime(name string) bool { - const n = len("runtime.") - return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z' + // Check and remove package qualifier. + n := len("runtime.") + if len(name) <= n || name[:n] != "runtime." { + return false + } + name = name[n:] + rcvr := "" + + // Extract receiver type, if any. + // For example, runtime.(*Func).Entry + i := len(name) - 1 + for i >= 0 && name[i] != '.' { + i-- + } + if i >= 0 { + rcvr = name[:i] + name = name[i+1:] + // Remove parentheses and star for pointer receivers. + if len(rcvr) >= 3 && rcvr[0] == '(' && rcvr[1] == '*' && rcvr[len(rcvr)-1] == ')' { + rcvr = rcvr[2 : len(rcvr)-1] + } + } + + // Exported functions and exported methods on exported types. + return len(name) > 0 && 'A' <= name[0] && name[0] <= 'Z' && (len(rcvr) == 0 || 'A' <= rcvr[0] && rcvr[0] <= 'Z') } // elideWrapperCalling reports whether a wrapper function that called @@ -1335,7 +1353,7 @@ func isSystemGoroutine(gp *g, fixed bool) bool { } return fingStatus.Load()&fingRunningFinalizer == 0 } - return hasPrefix(funcname(f), "runtime.") + return stringslite.HasPrefix(funcname(f), "runtime.") } // SetCgoTraceback records three C functions to use to gather diff --git a/contrib/go/_std_1.22/src/runtime/trace2buf.go b/contrib/go/_std_1.23/src/runtime/tracebuf.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/trace2buf.go rename to contrib/go/_std_1.23/src/runtime/tracebuf.go index 54de5e1df613..db4adf53e986 100644 --- a/contrib/go/_std_1.22/src/runtime/trace2buf.go +++ b/contrib/go/_std_1.23/src/runtime/tracebuf.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build goexperiment.exectracer2 - // Trace buffer management. package runtime @@ -61,7 +59,7 @@ func (w traceWriter) end() { func (w traceWriter) ensure(maxSize int) (traceWriter, bool) { refill := w.traceBuf == nil || !w.available(maxSize) if refill { - w = w.refill() + w = w.refill(traceNoExperiment) } return w, refill } @@ -80,7 +78,9 @@ func (w traceWriter) flush() traceWriter { } // refill puts w.traceBuf on the queue of full buffers and refresh's w's buffer. -func (w traceWriter) refill() traceWriter { +// +// exp indicates whether the refilled batch should be EvExperimentalBatch. +func (w traceWriter) refill(exp traceExperiment) traceWriter { systemstack(func() { lock(&trace.lock) if w.traceBuf != nil { @@ -114,7 +114,12 @@ func (w traceWriter) refill() traceWriter { } // Write the buffer's header. - w.byte(byte(traceEvEventBatch)) + if exp == traceNoExperiment { + w.byte(byte(traceEvEventBatch)) + } else { + w.byte(byte(traceEvExperimentalBatch)) + w.byte(byte(exp)) + } w.varint(uint64(w.gen)) w.varint(uint64(mID)) w.varint(uint64(ts)) diff --git a/contrib/go/_std_1.22/src/runtime/trace2cpu.go b/contrib/go/_std_1.23/src/runtime/tracecpu.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/trace2cpu.go rename to contrib/go/_std_1.23/src/runtime/tracecpu.go index 4635662c08d5..c8a6f56ff2f6 100644 --- a/contrib/go/_std_1.22/src/runtime/trace2cpu.go +++ b/contrib/go/_std_1.23/src/runtime/tracecpu.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build goexperiment.exectracer2 - // CPU profile -> trace package runtime @@ -195,18 +193,15 @@ func traceReadCPU(gen uintptr) bool { // traceCPUFlush flushes trace.cpuBuf[gen%2]. The caller must be certain that gen // has completed and that there are no more writers to it. -// -// Must run on the systemstack because it flushes buffers and acquires trace.lock -// to do so. -// -//go:systemstack func traceCPUFlush(gen uintptr) { // Flush any remaining trace buffers containing CPU samples. if buf := trace.cpuBuf[gen%2]; buf != nil { - lock(&trace.lock) - traceBufFlush(buf, gen) - unlock(&trace.lock) - trace.cpuBuf[gen%2] = nil + systemstack(func() { + lock(&trace.lock) + traceBufFlush(buf, gen) + unlock(&trace.lock) + trace.cpuBuf[gen%2] = nil + }) } } @@ -261,9 +256,7 @@ func traceCPUSample(gp *g, mp *m, pp *p, stk []uintptr) { if gp != nil { hdr[1] = gp.goid } - if mp != nil { - hdr[2] = uint64(mp.procid) - } + hdr[2] = uint64(mp.procid) // Allow only one writer at a time for !trace.signalLock.CompareAndSwap(0, 1) { diff --git a/contrib/go/_std_1.22/src/runtime/trace2event.go b/contrib/go/_std_1.23/src/runtime/traceevent.go similarity index 89% rename from contrib/go/_std_1.22/src/runtime/trace2event.go rename to contrib/go/_std_1.23/src/runtime/traceevent.go index 1f2a9f754be1..2a869fb51509 100644 --- a/contrib/go/_std_1.22/src/runtime/trace2event.go +++ b/contrib/go/_std_1.23/src/runtime/traceevent.go @@ -2,13 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build goexperiment.exectracer2 - // Trace event writing API for trace2runtime.go. package runtime import ( + "internal/abi" "runtime/internal/sys" ) @@ -81,6 +80,17 @@ const ( traceEvUserRegionBegin // trace.{Start,With}Region [timestamp, internal task ID, name string ID, stack ID] traceEvUserRegionEnd // trace.{End,With}Region [timestamp, internal task ID, name string ID, stack ID] traceEvUserLog // trace.Log [timestamp, internal task ID, key string ID, stack, value string ID] + + // Coroutines. + traceEvGoSwitch // goroutine switch (coroswitch) [timestamp, goroutine ID, goroutine seq] + traceEvGoSwitchDestroy // goroutine switch and destroy [timestamp, goroutine ID, goroutine seq] + traceEvGoCreateBlocked // goroutine creation (starts blocked) [timestamp, new goroutine ID, new stack ID, stack ID] + + // GoStatus with stack. + traceEvGoStatusStack // goroutine status at the start of a generation, with a stack [timestamp, goroutine ID, M ID, status, stack ID] + + // Batch event for an experimental batch with a custom format. + traceEvExperimentalBatch // start of extra data [experiment ID, generation, M ID, timestamp, batch length, batch data...] ) // traceArg is a simple wrapper type to help ensure that arguments passed @@ -114,7 +124,7 @@ func (tl traceLocker) eventWriter(goStatus traceGoStatus, procStatus traceProcSt w = w.writeProcStatus(uint64(pp.id), procStatus, pp.trace.inSweep) } if gp := tl.mp.curg; gp != nil && !gp.trace.statusWasTraced(tl.gen) && gp.trace.acquireStatus(tl.gen) { - w = w.writeGoStatus(uint64(gp.goid), int64(tl.mp.procid), goStatus, gp.inMarkAssist) + w = w.writeGoStatus(uint64(gp.goid), int64(tl.mp.procid), goStatus, gp.inMarkAssist, 0 /* no stack */) } return traceEventWriter{w} } @@ -163,7 +173,7 @@ func (w traceWriter) event(ev traceEv, args ...traceArg) traceWriter { // It then returns a traceArg representing that stack which may be // passed to write. func (tl traceLocker) stack(skip int) traceArg { - return traceArg(traceStack(skip, tl.mp, tl.gen)) + return traceArg(traceStack(skip, nil, tl.gen)) } // startPC takes a start PC for a goroutine and produces a unique @@ -192,3 +202,8 @@ func (tl traceLocker) string(s string) traceArg { func (tl traceLocker) uniqueString(s string) traceArg { return traceArg(trace.stringTab[tl.gen%2].emit(tl.gen, s)) } + +// rtype returns a traceArg representing typ which may be passed to write. +func (tl traceLocker) rtype(typ *abi.Type) traceArg { + return traceArg(trace.typeTab[tl.gen%2].put(typ)) +} diff --git a/contrib/go/_std_1.23/src/runtime/traceexp.go b/contrib/go/_std_1.23/src/runtime/traceexp.go new file mode 100644 index 000000000000..9fc85df5a8e9 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/traceexp.go @@ -0,0 +1,68 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +// traceExpWriter is a wrapper around trace writer that produces traceEvExperimentalBatch +// batches. This means that the data written to the writer need not conform to the standard +// trace format. +type traceExpWriter struct { + traceWriter + exp traceExperiment +} + +// unsafeTraceExpWriter produces a traceExpWriter that doesn't lock the trace. +// +// It should only be used in contexts where either: +// - Another traceLocker is held. +// - trace.gen is prevented from advancing. +// +// buf may be nil. +func unsafeTraceExpWriter(gen uintptr, buf *traceBuf, exp traceExperiment) traceExpWriter { + return traceExpWriter{traceWriter{traceLocker: traceLocker{gen: gen}, traceBuf: buf}, exp} +} + +// ensure makes sure that at least maxSize bytes are available to write. +// +// Returns whether the buffer was flushed. +func (w traceExpWriter) ensure(maxSize int) (traceExpWriter, bool) { + refill := w.traceBuf == nil || !w.available(maxSize) + if refill { + w.traceWriter = w.traceWriter.refill(w.exp) + } + return w, refill +} + +// traceExperiment is an enumeration of the different kinds of experiments supported for tracing. +type traceExperiment uint8 + +const ( + // traceNoExperiment indicates no experiment. + traceNoExperiment traceExperiment = iota + + // traceExperimentAllocFree is an experiment to add alloc/free events to the trace. + traceExperimentAllocFree +) + +// Experimental events. +const ( + _ traceEv = 127 + iota + + // Experimental events for ExperimentAllocFree. + + // Experimental heap span events. IDs map reversibly to base addresses. + traceEvSpan // heap span exists [timestamp, id, npages, type/class] + traceEvSpanAlloc // heap span alloc [timestamp, id, npages, type/class] + traceEvSpanFree // heap span free [timestamp, id] + + // Experimental heap object events. IDs map reversibly to addresses. + traceEvHeapObject // heap object exists [timestamp, id, type] + traceEvHeapObjectAlloc // heap object alloc [timestamp, id, type] + traceEvHeapObjectFree // heap object free [timestamp, id] + + // Experimental goroutine stack events. IDs map reversibly to addresses. + traceEvGoroutineStack // stack exists [timestamp, id, order] + traceEvGoroutineStackAlloc // stack alloc [timestamp, id, order] + traceEvGoroutineStackFree // stack free [timestamp, id] +) diff --git a/contrib/go/_std_1.23/src/runtime/tracemap.go b/contrib/go/_std_1.23/src/runtime/tracemap.go new file mode 100644 index 000000000000..5b2718c8d685 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/tracemap.go @@ -0,0 +1,140 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Simple append-only thread-safe hash map for tracing. +// Provides a mapping between variable-length data and a +// unique ID. Subsequent puts of the same data will return +// the same ID. The zero value is ready to use. +// +// Uses a region-based allocation scheme internally, and +// reset clears the whole map. +// +// It avoids doing any high-level Go operations so it's safe +// to use even in sensitive contexts. + +package runtime + +import ( + "internal/cpu" + "internal/goarch" + "internal/runtime/atomic" + "runtime/internal/sys" + "unsafe" +) + +type traceMap struct { + root atomic.UnsafePointer // *traceMapNode (can't use generics because it's notinheap) + _ cpu.CacheLinePad + seq atomic.Uint64 + _ cpu.CacheLinePad + mem traceRegionAlloc +} + +// traceMapNode is an implementation of a lock-free append-only hash-trie +// (a trie of the hash bits). +// +// Key features: +// - 4-ary trie. Child nodes are indexed by the upper 2 (remaining) bits of the hash. +// For example, top level uses bits [63:62], next level uses [61:60] and so on. +// - New nodes are placed at the first empty level encountered. +// - When the first child is added to a node, the existing value is not moved into a child. +// This means that you must check the key at each level, not just at the leaf. +// - No deletion or rebalancing. +// - Intentionally devolves into a linked list on hash collisions (the hash bits will all +// get shifted out during iteration, and new nodes will just be appended to the 0th child). +type traceMapNode struct { + _ sys.NotInHeap + + children [4]atomic.UnsafePointer // *traceMapNode (can't use generics because it's notinheap) + hash uintptr + id uint64 + data []byte +} + +// stealID steals an ID from the table, ensuring that it will not +// appear in the table anymore. +func (tab *traceMap) stealID() uint64 { + return tab.seq.Add(1) +} + +// put inserts the data into the table. +// +// It's always safe for callers to noescape data because put copies its bytes. +// +// Returns a unique ID for the data and whether this is the first time +// the data has been added to the map. +func (tab *traceMap) put(data unsafe.Pointer, size uintptr) (uint64, bool) { + if size == 0 { + return 0, false + } + hash := memhash(data, 0, size) + + var newNode *traceMapNode + m := &tab.root + hashIter := hash + for { + n := (*traceMapNode)(m.Load()) + if n == nil { + // Try to insert a new map node. We may end up discarding + // this node if we fail to insert because it turns out the + // value is already in the map. + // + // The discard will only happen if two threads race on inserting + // the same value. Both might create nodes, but only one will + // succeed on insertion. If two threads race to insert two + // different values, then both nodes will *always* get inserted, + // because the equality checking below will always fail. + // + // Performance note: contention on insertion is likely to be + // higher for small maps, but since this data structure is + // append-only, either the map stays small because there isn't + // much activity, or the map gets big and races to insert on + // the same node are much less likely. + if newNode == nil { + newNode = tab.newTraceMapNode(data, size, hash, tab.seq.Add(1)) + } + if m.CompareAndSwapNoWB(nil, unsafe.Pointer(newNode)) { + return newNode.id, true + } + // Reload n. Because pointers are only stored once, + // we must have lost the race, and therefore n is not nil + // anymore. + n = (*traceMapNode)(m.Load()) + } + if n.hash == hash && uintptr(len(n.data)) == size { + if memequal(unsafe.Pointer(&n.data[0]), data, size) { + return n.id, false + } + } + m = &n.children[hashIter>>(8*goarch.PtrSize-2)] + hashIter <<= 2 + } +} + +func (tab *traceMap) newTraceMapNode(data unsafe.Pointer, size, hash uintptr, id uint64) *traceMapNode { + // Create data array. + sl := notInHeapSlice{ + array: tab.mem.alloc(size), + len: int(size), + cap: int(size), + } + memmove(unsafe.Pointer(sl.array), data, size) + + // Create metadata structure. + meta := (*traceMapNode)(unsafe.Pointer(tab.mem.alloc(unsafe.Sizeof(traceMapNode{})))) + *(*notInHeapSlice)(unsafe.Pointer(&meta.data)) = sl + meta.id = id + meta.hash = hash + return meta +} + +// reset drops all allocated memory from the table and resets it. +// +// The caller must ensure that there are no put operations executing concurrently +// with this function. +func (tab *traceMap) reset() { + tab.root.Store(nil) + tab.seq.Store(0) + tab.mem.drop() +} diff --git a/contrib/go/_std_1.23/src/runtime/traceregion.go b/contrib/go/_std_1.23/src/runtime/traceregion.go new file mode 100644 index 000000000000..43eef9c92bb9 --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/traceregion.go @@ -0,0 +1,112 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Simple not-in-heap bump-pointer traceRegion allocator. + +package runtime + +import ( + "internal/runtime/atomic" + "runtime/internal/sys" + "unsafe" +) + +// traceRegionAlloc is a thread-safe region allocator. +// It holds a linked list of traceRegionAllocBlock. +type traceRegionAlloc struct { + lock mutex + dropping atomic.Bool // For checking invariants. + current atomic.UnsafePointer // *traceRegionAllocBlock + full *traceRegionAllocBlock +} + +// traceRegionAllocBlock is a block in traceRegionAlloc. +// +// traceRegionAllocBlock is allocated from non-GC'd memory, so it must not +// contain heap pointers. Writes to pointers to traceRegionAllocBlocks do +// not need write barriers. +type traceRegionAllocBlock struct { + _ sys.NotInHeap + traceRegionAllocBlockHeader + data [traceRegionAllocBlockData]byte +} + +type traceRegionAllocBlockHeader struct { + next *traceRegionAllocBlock + off atomic.Uintptr +} + +const traceRegionAllocBlockData = 64<<10 - unsafe.Sizeof(traceRegionAllocBlockHeader{}) + +// alloc allocates n-byte block. The block is always aligned to 8 bytes, regardless of platform. +func (a *traceRegionAlloc) alloc(n uintptr) *notInHeap { + n = alignUp(n, 8) + if n > traceRegionAllocBlockData { + throw("traceRegion: alloc too large") + } + if a.dropping.Load() { + throw("traceRegion: alloc with concurrent drop") + } + + // Try to bump-pointer allocate into the current block. + block := (*traceRegionAllocBlock)(a.current.Load()) + if block != nil { + r := block.off.Add(n) + if r <= uintptr(len(block.data)) { + return (*notInHeap)(unsafe.Pointer(&block.data[r-n])) + } + } + + // Try to install a new block. + lock(&a.lock) + + // Check block again under the lock. Someone may + // have gotten here first. + block = (*traceRegionAllocBlock)(a.current.Load()) + if block != nil { + r := block.off.Add(n) + if r <= uintptr(len(block.data)) { + unlock(&a.lock) + return (*notInHeap)(unsafe.Pointer(&block.data[r-n])) + } + + // Add the existing block to the full list. + block.next = a.full + a.full = block + } + + // Allocate a new block. + block = (*traceRegionAllocBlock)(sysAlloc(unsafe.Sizeof(traceRegionAllocBlock{}), &memstats.other_sys)) + if block == nil { + throw("traceRegion: out of memory") + } + + // Allocate space for our current request, so we always make + // progress. + block.off.Store(n) + x := (*notInHeap)(unsafe.Pointer(&block.data[0])) + + // Publish the new block. + a.current.Store(unsafe.Pointer(block)) + unlock(&a.lock) + return x +} + +// drop frees all previously allocated memory and resets the allocator. +// +// drop is not safe to call concurrently with other calls to drop or with calls to alloc. The caller +// must ensure that it is not possible for anything else to be using the same structure. +func (a *traceRegionAlloc) drop() { + a.dropping.Store(true) + for a.full != nil { + block := a.full + a.full = block.next + sysFree(unsafe.Pointer(block), unsafe.Sizeof(traceRegionAllocBlock{}), &memstats.other_sys) + } + if current := a.current.Load(); current != nil { + sysFree(current, unsafe.Sizeof(traceRegionAllocBlock{}), &memstats.other_sys) + a.current.Store(nil) + } + a.dropping.Store(false) +} diff --git a/contrib/go/_std_1.22/src/runtime/trace2runtime.go b/contrib/go/_std_1.23/src/runtime/traceruntime.go similarity index 83% rename from contrib/go/_std_1.22/src/runtime/trace2runtime.go rename to contrib/go/_std_1.23/src/runtime/traceruntime.go index 512e53907e60..7c4cb5502377 100644 --- a/contrib/go/_std_1.22/src/runtime/trace2runtime.go +++ b/contrib/go/_std_1.23/src/runtime/traceruntime.go @@ -2,14 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build goexperiment.exectracer2 - // Runtime -> tracer API. package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" _ "unsafe" // for go:linkname ) @@ -56,11 +54,13 @@ func traceLockInit() { // Sharing a lock rank here is fine because they should never be accessed // together. If they are, we want to find out immediately. lockInit(&trace.stringTab[0].lock, lockRankTraceStrings) - lockInit(&trace.stringTab[0].tab.lock, lockRankTraceStrings) + lockInit(&trace.stringTab[0].tab.mem.lock, lockRankTraceStrings) lockInit(&trace.stringTab[1].lock, lockRankTraceStrings) - lockInit(&trace.stringTab[1].tab.lock, lockRankTraceStrings) - lockInit(&trace.stackTab[0].tab.lock, lockRankTraceStackTab) - lockInit(&trace.stackTab[1].tab.lock, lockRankTraceStackTab) + lockInit(&trace.stringTab[1].tab.mem.lock, lockRankTraceStrings) + lockInit(&trace.stackTab[0].tab.mem.lock, lockRankTraceStackTab) + lockInit(&trace.stackTab[1].tab.mem.lock, lockRankTraceStackTab) + lockInit(&trace.typeTab[0].tab.mem.lock, lockRankTraceTypeTab) + lockInit(&trace.typeTab[1].tab.mem.lock, lockRankTraceTypeTab) lockInit(&trace.lock, lockRankTrace) } @@ -99,24 +99,26 @@ const ( traceBlockDebugCall traceBlockUntilGCEnds traceBlockSleep + traceBlockGCWeakToStrongWait ) var traceBlockReasonStrings = [...]string{ - traceBlockGeneric: "unspecified", - traceBlockForever: "forever", - traceBlockNet: "network", - traceBlockSelect: "select", - traceBlockCondWait: "sync.(*Cond).Wait", - traceBlockSync: "sync", - traceBlockChanSend: "chan send", - traceBlockChanRecv: "chan receive", - traceBlockGCMarkAssist: "GC mark assist wait for work", - traceBlockGCSweep: "GC background sweeper wait", - traceBlockSystemGoroutine: "system goroutine wait", - traceBlockPreempted: "preempted", - traceBlockDebugCall: "wait for debug call", - traceBlockUntilGCEnds: "wait until GC ends", - traceBlockSleep: "sleep", + traceBlockGeneric: "unspecified", + traceBlockForever: "forever", + traceBlockNet: "network", + traceBlockSelect: "select", + traceBlockCondWait: "sync.(*Cond).Wait", + traceBlockSync: "sync", + traceBlockChanSend: "chan send", + traceBlockChanRecv: "chan receive", + traceBlockGCMarkAssist: "GC mark assist wait for work", + traceBlockGCSweep: "GC background sweeper wait", + traceBlockSystemGoroutine: "system goroutine wait", + traceBlockPreempted: "preempted", + traceBlockDebugCall: "wait for debug call", + traceBlockUntilGCEnds: "wait until GC ends", + traceBlockSleep: "sleep", + traceBlockGCWeakToStrongWait: "GC weak to strong wait", } // traceGoStopReason is an enumeration of reasons a goroutine might yield. @@ -141,7 +143,15 @@ var traceGoStopReasonStrings = [...]string{ // //go:nosplit func traceEnabled() bool { - return trace.gen.Load() != 0 + return trace.enabled +} + +// traceAllocFreeEnabled returns true if the trace is currently enabled +// and alloc/free events are also enabled. +// +//go:nosplit +func traceAllocFreeEnabled() bool { + return trace.enabledWithAllocFree } // traceShuttingDown returns true if the trace is currently shutting down. @@ -176,6 +186,22 @@ func traceAcquire() traceLocker { return traceAcquireEnabled() } +// traceTryAcquire is like traceAcquire, but may return an invalid traceLocker even +// if tracing is enabled. For example, it will return !ok if traceAcquire is being +// called with an active traceAcquire on the M (reentrant locking). This exists for +// optimistically emitting events in the few contexts where tracing is now allowed. +// +// nosplit for alignment with traceTryAcquire, so it can be used in the +// same contexts. +// +//go:nosplit +func traceTryAcquire() traceLocker { + if !traceEnabled() { + return traceLocker{} + } + return traceTryAcquireEnabled() +} + // traceAcquireEnabled is the traceEnabled path for traceAcquire. It's explicitly // broken out to make traceAcquire inlineable to keep the overhead of the tracer // when it's disabled low. @@ -220,6 +246,26 @@ func traceAcquireEnabled() traceLocker { return traceLocker{mp, gen} } +// traceTryAcquireEnabled is like traceAcquireEnabled but may return an invalid +// traceLocker under some conditions. See traceTryAcquire for more details. +// +// nosplit for alignment with traceAcquireEnabled, so it can be used in the +// same contexts. +// +//go:nosplit +func traceTryAcquireEnabled() traceLocker { + // Any time we acquire a traceLocker, we may flush a trace buffer. But + // buffer flushes are rare. Record the lock edge even if it doesn't happen + // this time. + lockRankMayTraceFlush() + + // Check if we're already locked. If so, return an invalid traceLocker. + if getg().m.trace.seqlock.Load()%2 == 1 { + return traceLocker{} + } + return traceAcquireEnabled() +} + // ok returns true if the traceLocker is valid (i.e. tracing is enabled). // // nosplit because it's called on the syscall path when stack movement is forbidden. @@ -389,9 +435,13 @@ func (tl traceLocker) GCMarkAssistDone() { } // GoCreate emits a GoCreate event. -func (tl traceLocker) GoCreate(newg *g, pc uintptr) { +func (tl traceLocker) GoCreate(newg *g, pc uintptr, blocked bool) { newg.trace.setStatusTraced(tl.gen) - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoCreate, traceArg(newg.goid), tl.startPC(pc), tl.stack(2)) + ev := traceEvGoCreate + if blocked { + ev = traceEvGoCreateBlocked + } + tl.eventWriter(traceGoRunning, traceProcRunning).commit(ev, traceArg(newg.goid), tl.startPC(pc), tl.stack(2)) } // GoStart emits a GoStart event. @@ -442,37 +492,47 @@ func (tl traceLocker) GoPark(reason traceBlockReason, skip int) { func (tl traceLocker) GoUnpark(gp *g, skip int) { // Emit a GoWaiting status if necessary for the unblocked goroutine. w := tl.eventWriter(traceGoRunning, traceProcRunning) - if !gp.trace.statusWasTraced(tl.gen) && gp.trace.acquireStatus(tl.gen) { - // Careful: don't use the event writer. We never want status or in-progress events - // to trigger more in-progress events. - w.w = w.w.writeGoStatus(gp.goid, -1, traceGoWaiting, gp.inMarkAssist) - } + // Careful: don't use the event writer. We never want status or in-progress events + // to trigger more in-progress events. + w.w = emitUnblockStatus(w.w, gp, tl.gen) w.commit(traceEvGoUnblock, traceArg(gp.goid), gp.trace.nextSeq(tl.gen), tl.stack(skip)) } +// GoCoroswitch emits a GoSwitch event. If destroy is true, the calling goroutine +// is simultaneously being destroyed. +func (tl traceLocker) GoSwitch(nextg *g, destroy bool) { + // Emit a GoWaiting status if necessary for the unblocked goroutine. + w := tl.eventWriter(traceGoRunning, traceProcRunning) + // Careful: don't use the event writer. We never want status or in-progress events + // to trigger more in-progress events. + w.w = emitUnblockStatus(w.w, nextg, tl.gen) + ev := traceEvGoSwitch + if destroy { + ev = traceEvGoSwitchDestroy + } + w.commit(ev, traceArg(nextg.goid), nextg.trace.nextSeq(tl.gen)) +} + +// emitUnblockStatus emits a GoStatus GoWaiting event for a goroutine about to be +// unblocked to the trace writer. +func emitUnblockStatus(w traceWriter, gp *g, gen uintptr) traceWriter { + if !gp.trace.statusWasTraced(gen) && gp.trace.acquireStatus(gen) { + // TODO(go.dev/issue/65634): Although it would be nice to add a stack trace here of gp, + // we cannot safely do so. gp is in _Gwaiting and so we don't have ownership of its stack. + // We can fix this by acquiring the goroutine's scan bit. + w = w.writeGoStatus(gp.goid, -1, traceGoWaiting, gp.inMarkAssist, 0) + } + return w +} + // GoSysCall emits a GoSyscallBegin event. // // Must be called with a valid P. func (tl traceLocker) GoSysCall() { - var skip int - switch { - case tracefpunwindoff(): - // Unwind by skipping 1 frame relative to gp.syscallsp which is captured 3 - // results by hard coding the number of frames in between our caller and the - // actual syscall, see cases below. - // TODO(felixge): Implement gp.syscallbp to avoid this workaround? - skip = 1 - case GOOS == "solaris" || GOOS == "illumos": - // These platforms don't use a libc_read_trampoline. - skip = 3 - default: - // Skip the extra trampoline frame used on most systems. - skip = 4 - } // Scribble down the M that the P is currently attached to. pp := tl.mp.p.ptr() pp.trace.mSyscallID = int64(tl.mp.procid) - tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoSyscallBegin, pp.trace.nextSeq(tl.gen), tl.stack(skip)) + tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvGoSyscallBegin, pp.trace.nextSeq(tl.gen), tl.stack(1)) } // GoSysExit emits a GoSyscallEnd event, possibly along with a GoSyscallBlocked event @@ -533,10 +593,6 @@ func (tl traceLocker) ProcSteal(pp *p, inSyscall bool) { w.commit(traceEvProcSteal, traceArg(pp.id), pp.trace.nextSeq(tl.gen), traceArg(mStolenFrom)) } -// GoSysBlock is a no-op in the new tracer. -func (tl traceLocker) GoSysBlock(pp *p) { -} - // HeapAlloc emits a HeapAlloc event. func (tl traceLocker) HeapAlloc(live uint64) { tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapAlloc, traceArg(live)) @@ -552,11 +608,6 @@ func (tl traceLocker) HeapGoal() { tl.eventWriter(traceGoRunning, traceProcRunning).commit(traceEvHeapGoal, traceArg(heapGoal)) } -// OneNewExtraM is a no-op in the new tracer. This is worth keeping around though because -// it's a good place to insert a thread-level event about the new extra M. -func (tl traceLocker) OneNewExtraM(_ *g) { -} - // GoCreateSyscall indicates that a goroutine has transitioned from dead to GoSyscall. // // Unlike GoCreate, the caller must be running on gp. @@ -649,14 +700,6 @@ func trace_userLog(id uint64, category, message string) { traceRelease(tl) } -// traceProcFree is called when a P is destroyed. -// -// This must run on the system stack to match the old tracer. -// -//go:systemstack -func traceProcFree(_ *p) { -} - // traceThreadDestroy is called when a thread is removed from // sched.freem. // @@ -695,10 +738,3 @@ func traceThreadDestroy(mp *m) { throw("bad use of trace.seqlock") } } - -// Not used in the new tracer; solely for compatibility with the old tracer. -// nosplit because it's called from exitsyscall without a P. -// -//go:nosplit -func (_ traceLocker) RecordSyscallExitedTime(_ *g, _ *p) { -} diff --git a/contrib/go/_std_1.22/src/runtime/trace2stack.go b/contrib/go/_std_1.23/src/runtime/tracestack.go similarity index 59% rename from contrib/go/_std_1.22/src/runtime/trace2stack.go rename to contrib/go/_std_1.23/src/runtime/tracestack.go index af6638fa8f08..225566d1020f 100644 --- a/contrib/go/_std_1.22/src/runtime/trace2stack.go +++ b/contrib/go/_std_1.23/src/runtime/tracestack.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build goexperiment.exectracer2 - // Trace stack table and acquisition. package runtime @@ -27,8 +25,9 @@ const ( logicalStackSentinel = ^uintptr(0) ) -// traceStack captures a stack trace and registers it in the trace stack table. -// It then returns its unique ID. +// traceStack captures a stack trace from a goroutine and registers it in the trace +// stack table. It then returns its unique ID. If gp == nil, then traceStack will +// attempt to use the current execution context. // // skip controls the number of leaf frames to omit in order to hide tracer internals // from stack traces, see CL 5523. @@ -36,13 +35,45 @@ const ( // Avoid calling this function directly. gen needs to be the current generation // that this stack trace is being written out for, which needs to be synchronized with // generations moving forward. Prefer traceEventWriter.stack. -func traceStack(skip int, mp *m, gen uintptr) uint64 { +func traceStack(skip int, gp *g, gen uintptr) uint64 { var pcBuf [traceStackSize]uintptr - gp := getg() - curgp := gp.m.curg + // Figure out gp and mp for the backtrace. + var mp *m + if gp == nil { + mp = getg().m + gp = mp.curg + } + + // Double-check that we own the stack we're about to trace. + if debug.traceCheckStackOwnership != 0 && gp != nil { + status := readgstatus(gp) + // If the scan bit is set, assume we're the ones that acquired it. + if status&_Gscan == 0 { + // Use the trace status to check this. There are a number of cases + // where a running goroutine might be in _Gwaiting, and these cases + // are totally fine for taking a stack trace. They're captured + // correctly in goStatusToTraceGoStatus. + switch goStatusToTraceGoStatus(status, gp.waitreason) { + case traceGoRunning, traceGoSyscall: + if getg() == gp || mp.curg == gp { + break + } + fallthrough + default: + print("runtime: gp=", unsafe.Pointer(gp), " gp.goid=", gp.goid, " status=", gStatusStrings[status], "\n") + throw("attempted to trace stack of a goroutine this thread does not own") + } + } + } + + if gp != nil && mp == nil { + // We're getting the backtrace for a G that's not currently executing. + // It may still have an M, if it's locked to some M. + mp = gp.lockedm.ptr() + } nstk := 1 - if tracefpunwindoff() || mp.hasCgoOnStack() { + if tracefpunwindoff() || (mp != nil && mp.hasCgoOnStack()) { // Slow path: Unwind using default unwinder. Used when frame pointer // unwinding is unavailable or disabled (tracefpunwindoff), or might // produce incomplete results or crashes (hasCgoOnStack). Note that no @@ -50,30 +81,46 @@ func traceStack(skip int, mp *m, gen uintptr) uint64 { // motivation is to take advantage of a potentially registered cgo // symbolizer. pcBuf[0] = logicalStackSentinel - if curgp == gp { + if getg() == gp { nstk += callers(skip+1, pcBuf[1:]) - } else if curgp != nil { - nstk += gcallers(curgp, skip, pcBuf[1:]) + } else if gp != nil { + nstk += gcallers(gp, skip, pcBuf[1:]) } } else { // Fast path: Unwind using frame pointers. pcBuf[0] = uintptr(skip) - if curgp == gp { + if getg() == gp { nstk += fpTracebackPCs(unsafe.Pointer(getfp()), pcBuf[1:]) - } else if curgp != nil { - // We're called on the g0 stack through mcall(fn) or systemstack(fn). To + } else if gp != nil { + // Three cases: + // + // (1) We're called on the g0 stack through mcall(fn) or systemstack(fn). To // behave like gcallers above, we start unwinding from sched.bp, which // points to the caller frame of the leaf frame on g's stack. The return // address of the leaf frame is stored in sched.pc, which we manually // capture here. - pcBuf[1] = curgp.sched.pc - nstk += 1 + fpTracebackPCs(unsafe.Pointer(curgp.sched.bp), pcBuf[2:]) + // + // (2) We're called against a gp that we're not currently executing on, but that isn't + // in a syscall, in which case it's currently not executing. gp.sched contains the most + // up-to-date information about where it stopped, and like case (1), we match gcallers + // here. + // + // (3) We're called against a gp that we're not currently executing on, but that is in + // a syscall, in which case gp.syscallsp != 0. gp.syscall* contains the most up-to-date + // information about where it stopped, and like case (1), we match gcallers here. + if gp.syscallsp != 0 { + pcBuf[1] = gp.syscallpc + nstk += 1 + fpTracebackPCs(unsafe.Pointer(gp.syscallbp), pcBuf[2:]) + } else { + pcBuf[1] = gp.sched.pc + nstk += 1 + fpTracebackPCs(unsafe.Pointer(gp.sched.bp), pcBuf[2:]) + } } } if nstk > 0 { nstk-- // skip runtime.goexit } - if nstk > 0 && curgp.goid == 1 { + if nstk > 0 && gp.goid == 1 { nstk-- // skip runtime.main } id := trace.stackTab[gen%2].put(pcBuf[:nstk]) @@ -99,67 +146,59 @@ func (t *traceStackTable) put(pcs []uintptr) uint64 { // dump writes all previously cached stacks to trace buffers, // releases all memory and resets state. It must only be called once the caller // can guarantee that there are no more writers to the table. -// -// This must run on the system stack because it flushes buffers and thus -// may acquire trace.lock. -// -//go:systemstack func (t *traceStackTable) dump(gen uintptr) { + stackBuf := make([]uintptr, traceStackSize) w := unsafeTraceWriter(gen, nil) + if root := (*traceMapNode)(t.tab.root.Load()); root != nil { + w = dumpStacksRec(root, w, stackBuf) + } + w.flush().end() + t.tab.reset() +} - // Iterate over the table. - // - // Do not acquire t.tab.lock. There's a conceptual lock cycle between acquiring this lock - // here and allocation-related locks. Specifically, this lock may be acquired when an event - // is emitted in allocation paths. Simultaneously, we might allocate here with the lock held, - // creating a cycle. In practice, this cycle is never exercised. Because the table is only - // dumped once there are no more writers, it's not possible for the cycle to occur. However - // the lockrank mode is not sophisticated enough to identify this, and if it's not possible - // for that cycle to happen, then it's also not possible for this to race with writers to - // the table. - for i := range t.tab.tab { - stk := t.tab.bucket(i) - for ; stk != nil; stk = stk.next() { - stack := unsafe.Slice((*uintptr)(unsafe.Pointer(&stk.data[0])), uintptr(len(stk.data))/unsafe.Sizeof(uintptr(0))) +func dumpStacksRec(node *traceMapNode, w traceWriter, stackBuf []uintptr) traceWriter { + stack := unsafe.Slice((*uintptr)(unsafe.Pointer(&node.data[0])), uintptr(len(node.data))/unsafe.Sizeof(uintptr(0))) - // N.B. This might allocate, but that's OK because we're not writing to the M's buffer, - // but one we're about to create (with ensure). - frames := makeTraceFrames(gen, fpunwindExpand(stack)) + // N.B. This might allocate, but that's OK because we're not writing to the M's buffer, + // but one we're about to create (with ensure). + n := fpunwindExpand(stackBuf, stack) + frames := makeTraceFrames(w.gen, stackBuf[:n]) - // Returns the maximum number of bytes required to hold the encoded stack, given that - // it contains N frames. - maxBytes := 1 + (2+4*len(frames))*traceBytesPerNumber + // The maximum number of bytes required to hold the encoded stack, given that + // it contains N frames. + maxBytes := 1 + (2+4*len(frames))*traceBytesPerNumber - // Estimate the size of this record. This - // bound is pretty loose, but avoids counting - // lots of varint sizes. - // - // Add 1 because we might also write traceEvStacks. - var flushed bool - w, flushed = w.ensure(1 + maxBytes) - if flushed { - w.byte(byte(traceEvStacks)) - } + // Estimate the size of this record. This + // bound is pretty loose, but avoids counting + // lots of varint sizes. + // + // Add 1 because we might also write traceEvStacks. + var flushed bool + w, flushed = w.ensure(1 + maxBytes) + if flushed { + w.byte(byte(traceEvStacks)) + } - // Emit stack event. - w.byte(byte(traceEvStack)) - w.varint(uint64(stk.id)) - w.varint(uint64(len(frames))) - for _, frame := range frames { - w.varint(uint64(frame.PC)) - w.varint(frame.funcID) - w.varint(frame.fileID) - w.varint(frame.line) - } - } + // Emit stack event. + w.byte(byte(traceEvStack)) + w.varint(uint64(node.id)) + w.varint(uint64(len(frames))) + for _, frame := range frames { + w.varint(uint64(frame.PC)) + w.varint(frame.funcID) + w.varint(frame.fileID) + w.varint(frame.line) } - // Still, hold the lock over reset. The callee expects it, even though it's - // not strictly necessary. - lock(&t.tab.lock) - t.tab.reset() - unlock(&t.tab.lock) - w.flush().end() + // Recursively walk all child nodes. + for i := range node.children { + child := node.children[i].Load() + if child == nil { + continue + } + w = dumpStacksRec((*traceMapNode)(child), w, stackBuf) + } + return w } // makeTraceFrames returns the frames corresponding to pcs. It may @@ -223,31 +262,43 @@ func fpTracebackPCs(fp unsafe.Pointer, pcBuf []uintptr) (i int) { return i } +//go:linkname pprof_fpunwindExpand +func pprof_fpunwindExpand(dst, src []uintptr) int { + return fpunwindExpand(dst, src) +} + +// fpunwindExpand expands a call stack from pcBuf into dst, +// returning the number of PCs written to dst. +// pcBuf and dst should not overlap. +// // fpunwindExpand checks if pcBuf contains logical frames (which include inlined // frames) or physical frames (produced by frame pointer unwinding) using a // sentinel value in pcBuf[0]. Logical frames are simply returned without the // sentinel. Physical frames are turned into logical frames via inline unwinding // and by applying the skip value that's stored in pcBuf[0]. -func fpunwindExpand(pcBuf []uintptr) []uintptr { - if len(pcBuf) > 0 && pcBuf[0] == logicalStackSentinel { +func fpunwindExpand(dst, pcBuf []uintptr) int { + if len(pcBuf) == 0 { + return 0 + } else if len(pcBuf) > 0 && pcBuf[0] == logicalStackSentinel { // pcBuf contains logical rather than inlined frames, skip has already been // applied, just return it without the sentinel value in pcBuf[0]. - return pcBuf[1:] + return copy(dst, pcBuf[1:]) } var ( + n int lastFuncID = abi.FuncIDNormal - newPCBuf = make([]uintptr, 0, traceStackSize) skip = pcBuf[0] // skipOrAdd skips or appends retPC to newPCBuf and returns true if more // pcs can be added. skipOrAdd = func(retPC uintptr) bool { if skip > 0 { skip-- - } else { - newPCBuf = append(newPCBuf, retPC) + } else if n < len(dst) { + dst[n] = retPC + n++ } - return len(newPCBuf) < cap(newPCBuf) + return n < len(dst) } ) @@ -275,7 +326,7 @@ outer: lastFuncID = sf.funcID } } - return newPCBuf + return n } // startPCForTrace returns the start PC of a goroutine for tracing purposes. diff --git a/contrib/go/_std_1.22/src/runtime/trace2status.go b/contrib/go/_std_1.23/src/runtime/tracestatus.go similarity index 93% rename from contrib/go/_std_1.22/src/runtime/trace2status.go rename to contrib/go/_std_1.23/src/runtime/tracestatus.go index 5016e086560a..77ccdd139841 100644 --- a/contrib/go/_std_1.22/src/runtime/trace2status.go +++ b/contrib/go/_std_1.23/src/runtime/tracestatus.go @@ -2,13 +2,11 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build goexperiment.exectracer2 - // Trace goroutine and P status management. package runtime -import "runtime/internal/atomic" +import "internal/runtime/atomic" // traceGoStatus is the status of a goroutine. // @@ -48,7 +46,7 @@ const ( ) // writeGoStatus emits a GoStatus event as well as any active ranges on the goroutine. -func (w traceWriter) writeGoStatus(goid uint64, mid int64, status traceGoStatus, markAssist bool) traceWriter { +func (w traceWriter) writeGoStatus(goid uint64, mid int64, status traceGoStatus, markAssist bool, stackID uint64) traceWriter { // The status should never be bad. Some invariant must have been violated. if status == traceGoBad { print("runtime: goid=", goid, "\n") @@ -56,7 +54,11 @@ func (w traceWriter) writeGoStatus(goid uint64, mid int64, status traceGoStatus, } // Trace the status. - w = w.event(traceEvGoStatus, traceArg(goid), traceArg(uint64(mid)), traceArg(status)) + if stackID == 0 { + w = w.event(traceEvGoStatus, traceArg(goid), traceArg(uint64(mid)), traceArg(status)) + } else { + w = w.event(traceEvGoStatusStack, traceArg(goid), traceArg(uint64(mid)), traceArg(status), traceArg(stackID)) + } // Trace any special ranges that are in-progress. if markAssist { @@ -142,13 +144,7 @@ func goStatusToTraceGoStatus(status uint32, wr waitReason) traceGoStatus { // emit an event, and we want these goroutines to appear in // the final trace as if they're running, not blocked. tgs = traceGoWaiting - if status == _Gwaiting && - wr == waitReasonStoppingTheWorld || - wr == waitReasonGCMarkTermination || - wr == waitReasonGarbageCollection || - wr == waitReasonTraceProcStatus || - wr == waitReasonPageTraceFlush || - wr == waitReasonGCWorkerActive { + if status == _Gwaiting && wr.isWaitingForGC() { tgs = traceGoRunning } case _Gdead: diff --git a/contrib/go/_std_1.22/src/runtime/trace2string.go b/contrib/go/_std_1.23/src/runtime/tracestring.go similarity index 84% rename from contrib/go/_std_1.22/src/runtime/trace2string.go rename to contrib/go/_std_1.23/src/runtime/tracestring.go index cbb0ecfb3743..2585c69cc0b7 100644 --- a/contrib/go/_std_1.22/src/runtime/trace2string.go +++ b/contrib/go/_std_1.23/src/runtime/tracestring.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build goexperiment.exectracer2 - // Trace string management. package runtime @@ -49,7 +47,7 @@ func (t *traceStringTable) emit(gen uintptr, s string) uint64 { // writeString writes the string to t.buf. // -// Must run on the systemstack because it may flush buffers and thus could acquire trace.lock. +// Must run on the systemstack because it acquires t.lock. // //go:systemstack func (t *traceStringTable) writeString(gen uintptr, id uint64, s string) { @@ -75,7 +73,7 @@ func (t *traceStringTable) writeString(gen uintptr, id uint64, s string) { w.varint(uint64(len(s))) w.stringData(s) - // Store back buf if it was updated during ensure. + // Store back buf in case it was updated during ensure. t.buf = w.traceBuf unlock(&t.lock) } @@ -84,21 +82,16 @@ func (t *traceStringTable) writeString(gen uintptr, id uint64, s string) { // // Must be called only once the caller is certain nothing else will be // added to this table. -// -// Because it flushes buffers, this may acquire trace.lock and thus -// must run on the systemstack. -// -//go:systemstack func (t *traceStringTable) reset(gen uintptr) { if t.buf != nil { - lock(&trace.lock) - traceBufFlush(t.buf, gen) - unlock(&trace.lock) + systemstack(func() { + lock(&trace.lock) + traceBufFlush(t.buf, gen) + unlock(&trace.lock) + }) t.buf = nil } // Reset the table. - lock(&t.tab.lock) t.tab.reset() - unlock(&t.tab.lock) } diff --git a/contrib/go/_std_1.22/src/runtime/trace2time.go b/contrib/go/_std_1.23/src/runtime/tracetime.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/trace2time.go rename to contrib/go/_std_1.23/src/runtime/tracetime.go index 7a7a53e7d8d5..571012413fff 100644 --- a/contrib/go/_std_1.22/src/runtime/trace2time.go +++ b/contrib/go/_std_1.23/src/runtime/tracetime.go @@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build goexperiment.exectracer2 - // Trace time and clock. package runtime -import "internal/goarch" +import ( + "internal/goarch" + _ "unsafe" +) // Timestamps in trace are produced through either nanotime or cputicks // and divided by traceTimeDiv. nanotime is used everywhere except on @@ -48,6 +49,9 @@ type traceTime uint64 // // nosplit because it's called from exitsyscall, which is nosplit. // +// traceClockNow is called by golang.org/x/exp/trace using linkname. +// +//go:linkname traceClockNow //go:nosplit func traceClockNow() traceTime { if osHasLowResClock { diff --git a/contrib/go/_std_1.23/src/runtime/tracetype.go b/contrib/go/_std_1.23/src/runtime/tracetype.go new file mode 100644 index 000000000000..b27a6909168b --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/tracetype.go @@ -0,0 +1,82 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Trace stack table and acquisition. + +package runtime + +import ( + "internal/abi" + "internal/goarch" + "unsafe" +) + +// traceTypeTable maps stack traces (arrays of PC's) to unique uint32 ids. +// It is lock-free for reading. +type traceTypeTable struct { + tab traceMap +} + +// put returns a unique id for the type typ and caches it in the table, +// if it's seeing it for the first time. +// +// N.B. typ must be kept alive forever for this to work correctly. +func (t *traceTypeTable) put(typ *abi.Type) uint64 { + if typ == nil { + return 0 + } + // Insert the pointer to the type itself. + id, _ := t.tab.put(noescape(unsafe.Pointer(&typ)), goarch.PtrSize) + return id +} + +// dump writes all previously cached types to trace buffers and +// releases all memory and resets state. It must only be called once the caller +// can guarantee that there are no more writers to the table. +func (t *traceTypeTable) dump(gen uintptr) { + w := unsafeTraceExpWriter(gen, nil, traceExperimentAllocFree) + if root := (*traceMapNode)(t.tab.root.Load()); root != nil { + w = dumpTypesRec(root, w) + } + w.flush().end() + t.tab.reset() +} + +func dumpTypesRec(node *traceMapNode, w traceExpWriter) traceExpWriter { + typ := (*abi.Type)(*(*unsafe.Pointer)(unsafe.Pointer(&node.data[0]))) + typName := toRType(typ).string() + + // The maximum number of bytes required to hold the encoded type. + maxBytes := 1 + 5*traceBytesPerNumber + len(typName) + + // Estimate the size of this record. This + // bound is pretty loose, but avoids counting + // lots of varint sizes. + // + // Add 1 because we might also write a traceAllocFreeTypesBatch byte. + var flushed bool + w, flushed = w.ensure(1 + maxBytes) + if flushed { + // Annotate the batch as containing types. + w.byte(byte(traceAllocFreeTypesBatch)) + } + + // Emit type. + w.varint(uint64(node.id)) + w.varint(uint64(uintptr(unsafe.Pointer(typ)))) + w.varint(uint64(typ.Size())) + w.varint(uint64(typ.PtrBytes)) + w.varint(uint64(len(typName))) + w.stringData(typName) + + // Recursively walk all child nodes. + for i := range node.children { + child := node.children[i].Load() + if child == nil { + continue + } + w = dumpTypesRec((*traceMapNode)(child), w) + } + return w +} diff --git a/contrib/go/_std_1.22/src/runtime/type.go b/contrib/go/_std_1.23/src/runtime/type.go similarity index 92% rename from contrib/go/_std_1.22/src/runtime/type.go rename to contrib/go/_std_1.23/src/runtime/type.go index 1150a53208c3..201340752b81 100644 --- a/contrib/go/_std_1.22/src/runtime/type.go +++ b/contrib/go/_std_1.23/src/runtime/type.go @@ -61,11 +61,11 @@ func (t rtype) pkgpath() string { if u := t.uncommon(); u != nil { return t.nameOff(u.PkgPath).Name() } - switch t.Kind_ & kindMask { - case kindStruct: + switch t.Kind_ & abi.KindMask { + case abi.Struct: st := (*structtype)(unsafe.Pointer(t.Type)) return st.PkgPath.Name() - case kindInterface: + case abi.Interface: it := (*interfacetype)(unsafe.Pointer(t.Type)) return it.PkgPath.Name() } @@ -106,6 +106,15 @@ func reflectOffsUnlock() { unlock(&reflectOffs.lock) } +// resolveNameOff should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname resolveNameOff func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name { if off == 0 { return name{} @@ -140,6 +149,15 @@ func (t rtype) nameOff(off nameOff) name { return resolveNameOff(unsafe.Pointer(t.Type), off) } +// resolveTypeOff should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/cloudwego/frugal +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname resolveTypeOff func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type { if off == 0 || off == -1 { // -1 is the sentinel value for unreachable code. @@ -338,8 +356,8 @@ func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool { if t == v { return true } - kind := t.Kind_ & kindMask - if kind != v.Kind_&kindMask { + kind := t.Kind_ & abi.KindMask + if kind != v.Kind_&abi.KindMask { return false } rt, rv := toRType(t), toRType(v) @@ -358,21 +376,21 @@ func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool { return false } } - if kindBool <= kind && kind <= kindComplex128 { + if abi.Bool <= kind && kind <= abi.Complex128 { return true } switch kind { - case kindString, kindUnsafePointer: + case abi.String, abi.UnsafePointer: return true - case kindArray: + case abi.Array: at := (*arraytype)(unsafe.Pointer(t)) av := (*arraytype)(unsafe.Pointer(v)) return typesEqual(at.Elem, av.Elem, seen) && at.Len == av.Len - case kindChan: + case abi.Chan: ct := (*chantype)(unsafe.Pointer(t)) cv := (*chantype)(unsafe.Pointer(v)) return ct.Dir == cv.Dir && typesEqual(ct.Elem, cv.Elem, seen) - case kindFunc: + case abi.Func: ft := (*functype)(unsafe.Pointer(t)) fv := (*functype)(unsafe.Pointer(v)) if ft.OutCount != fv.OutCount || ft.InCount != fv.InCount { @@ -391,7 +409,7 @@ func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool { } } return true - case kindInterface: + case abi.Interface: it := (*interfacetype)(unsafe.Pointer(t)) iv := (*interfacetype)(unsafe.Pointer(v)) if it.PkgPath.Name() != iv.PkgPath.Name() { @@ -420,19 +438,19 @@ func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool { } } return true - case kindMap: + case abi.Map: mt := (*maptype)(unsafe.Pointer(t)) mv := (*maptype)(unsafe.Pointer(v)) return typesEqual(mt.Key, mv.Key, seen) && typesEqual(mt.Elem, mv.Elem, seen) - case kindPtr: + case abi.Pointer: pt := (*ptrtype)(unsafe.Pointer(t)) pv := (*ptrtype)(unsafe.Pointer(v)) return typesEqual(pt.Elem, pv.Elem, seen) - case kindSlice: + case abi.Slice: st := (*slicetype)(unsafe.Pointer(t)) sv := (*slicetype)(unsafe.Pointer(v)) return typesEqual(st.Elem, sv.Elem, seen) - case kindStruct: + case abi.Struct: st := (*structtype)(unsafe.Pointer(t)) sv := (*structtype)(unsafe.Pointer(v)) if len(st.Fields) != len(sv.Fields) { diff --git a/contrib/go/_std_1.23/src/runtime/typekind.go b/contrib/go/_std_1.23/src/runtime/typekind.go new file mode 100644 index 000000000000..4920a7cf146c --- /dev/null +++ b/contrib/go/_std_1.23/src/runtime/typekind.go @@ -0,0 +1,12 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import "internal/abi" + +// isDirectIface reports whether t is stored directly in an interface value. +func isDirectIface(t *_type) bool { + return t.Kind_&abi.KindDirectIface != 0 +} diff --git a/contrib/go/_std_1.22/src/runtime/unsafe.go b/contrib/go/_std_1.23/src/runtime/unsafe.go similarity index 95% rename from contrib/go/_std_1.22/src/runtime/unsafe.go rename to contrib/go/_std_1.23/src/runtime/unsafe.go index 6675264f5977..ca428b56e079 100644 --- a/contrib/go/_std_1.22/src/runtime/unsafe.go +++ b/contrib/go/_std_1.23/src/runtime/unsafe.go @@ -112,3 +112,8 @@ func panicunsafeslicenilptr1(pc uintptr) { panicCheck1(pc, "unsafe.Slice: ptr is nil and len is not zero") panic(errorString("unsafe.Slice: ptr is nil and len is not zero")) } + +//go:linkname reflect_unsafeslice reflect.unsafeslice +func reflect_unsafeslice(et *_type, ptr unsafe.Pointer, len int) { + unsafeslice(et, ptr, len) +} diff --git a/contrib/go/_std_1.22/src/runtime/utf8.go b/contrib/go/_std_1.23/src/runtime/utf8.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/utf8.go rename to contrib/go/_std_1.23/src/runtime/utf8.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_elf32.go b/contrib/go/_std_1.23/src/runtime/vdso_elf32.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_elf32.go rename to contrib/go/_std_1.23/src/runtime/vdso_elf32.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_elf64.go b/contrib/go/_std_1.23/src/runtime/vdso_elf64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_elf64.go rename to contrib/go/_std_1.23/src/runtime/vdso_elf64.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_freebsd.go b/contrib/go/_std_1.23/src/runtime/vdso_freebsd.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/vdso_freebsd.go rename to contrib/go/_std_1.23/src/runtime/vdso_freebsd.go index 0fe21cf64704..feecada03571 100644 --- a/contrib/go/_std_1.22/src/runtime/vdso_freebsd.go +++ b/contrib/go/_std_1.23/src/runtime/vdso_freebsd.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/vdso_freebsd_arm.go b/contrib/go/_std_1.23/src/runtime/vdso_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_freebsd_arm.go rename to contrib/go/_std_1.23/src/runtime/vdso_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_freebsd_arm64.go b/contrib/go/_std_1.23/src/runtime/vdso_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_freebsd_arm64.go rename to contrib/go/_std_1.23/src/runtime/vdso_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_freebsd_riscv64.go b/contrib/go/_std_1.23/src/runtime/vdso_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/runtime/vdso_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_freebsd_x86.go b/contrib/go/_std_1.23/src/runtime/vdso_freebsd_x86.go similarity index 98% rename from contrib/go/_std_1.22/src/runtime/vdso_freebsd_x86.go rename to contrib/go/_std_1.23/src/runtime/vdso_freebsd_x86.go index 66d1c654885a..7ac09cb9f19b 100644 --- a/contrib/go/_std_1.22/src/runtime/vdso_freebsd_x86.go +++ b/contrib/go/_std_1.23/src/runtime/vdso_freebsd_x86.go @@ -7,7 +7,7 @@ package runtime import ( - "runtime/internal/atomic" + "internal/runtime/atomic" "unsafe" ) diff --git a/contrib/go/_std_1.22/src/runtime/vdso_in_none.go b/contrib/go/_std_1.23/src/runtime/vdso_in_none.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_in_none.go rename to contrib/go/_std_1.23/src/runtime/vdso_in_none.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux.go b/contrib/go/_std_1.23/src/runtime/vdso_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_386.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_386.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_386.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_amd64.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_amd64.go similarity index 83% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_amd64.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_amd64.go index 4e9f748f4a1a..9c564091377e 100644 --- a/contrib/go/_std_1.22/src/runtime/vdso_linux_amd64.go +++ b/contrib/go/_std_1.23/src/runtime/vdso_linux_amd64.go @@ -4,6 +4,8 @@ package runtime +import _ "unsafe" // for linkname + const ( // vdsoArrayMax is the byte-size of a maximally sized array on this architecture. // See cmd/compile/internal/amd64/galign.go arch.MAXWIDTH initialization. @@ -21,3 +23,6 @@ var ( vdsoGettimeofdaySym uintptr vdsoClockgettimeSym uintptr ) + +// vdsoGettimeofdaySym is accessed from the syscall package. +//go:linkname vdsoGettimeofdaySym diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_arm.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_arm.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_arm.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_arm64.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_arm64.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_loong64.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_loong64.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_mips64x.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_mips64x.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_mips64x.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_ppc64x.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_ppc64x.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_ppc64x.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_riscv64.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_riscv64.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/runtime/vdso_linux_s390x.go b/contrib/go/_std_1.23/src/runtime/vdso_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vdso_linux_s390x.go rename to contrib/go/_std_1.23/src/runtime/vdso_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/runtime/vlop_386.s b/contrib/go/_std_1.23/src/runtime/vlop_386.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vlop_386.s rename to contrib/go/_std_1.23/src/runtime/vlop_386.s diff --git a/contrib/go/_std_1.22/src/runtime/vlop_arm.s b/contrib/go/_std_1.23/src/runtime/vlop_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vlop_arm.s rename to contrib/go/_std_1.23/src/runtime/vlop_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/vlrt.go b/contrib/go/_std_1.23/src/runtime/vlrt.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/vlrt.go rename to contrib/go/_std_1.23/src/runtime/vlrt.go diff --git a/contrib/go/_std_1.22/src/runtime/wincallback.go b/contrib/go/_std_1.23/src/runtime/wincallback.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/wincallback.go rename to contrib/go/_std_1.23/src/runtime/wincallback.go diff --git a/contrib/go/_std_1.22/src/runtime/write_err.go b/contrib/go/_std_1.23/src/runtime/write_err.go similarity index 76% rename from contrib/go/_std_1.22/src/runtime/write_err.go rename to contrib/go/_std_1.23/src/runtime/write_err.go index 81ae872e9c03..11ca6bbb94d9 100644 --- a/contrib/go/_std_1.22/src/runtime/write_err.go +++ b/contrib/go/_std_1.23/src/runtime/write_err.go @@ -6,8 +6,9 @@ package runtime -import "unsafe" - +//go:nosplit func writeErr(b []byte) { - write(2, unsafe.Pointer(&b[0]), int32(len(b))) + if len(b) > 0 { + writeErrData(&b[0], int32(len(b))) + } } diff --git a/contrib/go/_std_1.22/src/runtime/write_err_android.go b/contrib/go/_std_1.23/src/runtime/write_err_android.go similarity index 96% rename from contrib/go/_std_1.22/src/runtime/write_err_android.go rename to contrib/go/_std_1.23/src/runtime/write_err_android.go index a876900c9548..34de106b5092 100644 --- a/contrib/go/_std_1.22/src/runtime/write_err_android.go +++ b/contrib/go/_std_1.23/src/runtime/write_err_android.go @@ -34,6 +34,10 @@ const ( var logger loggerType func writeErr(b []byte) { + if len(b) == 0 { + return + } + if logger == unknown { // Use logd if /dev/socket/logdw is available. if v := uintptr(access(&writeLogd[0], 0x02 /* W_OK */)); v == 0 { @@ -45,8 +49,9 @@ func writeErr(b []byte) { } } - // Write to stderr for command-line programs. - write(2, unsafe.Pointer(&b[0]), int32(len(b))) + // Write to stderr for command-line programs, + // and optionally to SetCrashOutput file. + writeErrData(&b[0], int32(len(b))) // Log format: "
\x00\x00" // @@ -75,9 +80,7 @@ func writeErr(b []byte) { if v == '\n' || writePos == len(dst)-1 { dst[writePos] = 0 write(writeFD, unsafe.Pointer(&writeBuf[0]), int32(hlen+writePos)) - for i := range dst { - dst[i] = 0 - } + clear(dst) writePos = 0 } } diff --git a/contrib/go/_std_1.22/src/runtime/ya.make b/contrib/go/_std_1.23/src/runtime/ya.make similarity index 89% rename from contrib/go/_std_1.22/src/runtime/ya.make rename to contrib/go/_std_1.23/src/runtime/ya.make index 4405653b1781..48181c52f559 100644 --- a/contrib/go/_std_1.22/src/runtime/ya.make +++ b/contrib/go/_std_1.23/src/runtime/ya.make @@ -20,6 +20,7 @@ IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM6 asm_arm64.s atomic_arm64.s atomic_pointer.go + badlinkname.go cgo.go cgocall.go cgocallback.go @@ -43,7 +44,6 @@ IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM6 duff_arm64.s env_posix.go error.go - exithook.go extern.go fastlog2.go fastlog2table.go @@ -54,6 +54,8 @@ IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM6 histogram.go iface.go lfstack.go + linkname.go + linkname_unix.go lock_sema.go lockrank.go lockrank_off.go @@ -64,7 +66,6 @@ IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM6 map_faststr.go mbarrier.go mbitmap.go - mbitmap_noallocheaders.go mcache.go mcentral.go mcheckmark.go @@ -91,20 +92,20 @@ IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM6 mpallocbits.go mprof.go mranges.go - msize_noallocheaders.go + msize.go mspanset.go mstats.go mwbbuf.go nbpipe_pipe.go netpoll.go netpoll_kqueue.go + netpoll_kqueue_event.go nonwindows_stub.go os_darwin.go os_darwin_arm64.go os_nonopenbsd.go os_unix.go os_unix_nonlinux.go - pagetrace_off.go panic.go pinner.go plugin.go @@ -161,7 +162,20 @@ IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM6 tls_arm64.s tls_stub.go trace.go + traceallocfree.go traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go type.go typekind.go unsafe.go @@ -177,6 +191,7 @@ ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND A asm_arm64.s atomic_arm64.s atomic_pointer.go + badlinkname.go cgo.go cgocall.go cgocallback.go @@ -200,7 +215,6 @@ ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND A duff_arm64.s env_posix.go error.go - exithook.go extern.go fastlog2.go fastlog2table.go @@ -211,6 +225,8 @@ ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND A histogram.go iface.go lfstack.go + linkname.go + linkname_unix.go lock_sema.go lockrank.go lockrank_off.go @@ -221,7 +237,6 @@ ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND A map_faststr.go mbarrier.go mbitmap.go - mbitmap_noallocheaders.go mcache.go mcentral.go mcheckmark.go @@ -248,20 +263,20 @@ ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND A mpallocbits.go mprof.go mranges.go - msize_noallocheaders.go + msize.go mspanset.go mstats.go mwbbuf.go nbpipe_pipe.go netpoll.go netpoll_kqueue.go + netpoll_kqueue_event.go nonwindows_stub.go os_darwin.go os_darwin_arm64.go os_nonopenbsd.go os_unix.go os_unix_nonlinux.go - pagetrace_off.go panic.go pinner.go plugin.go @@ -317,7 +332,20 @@ ELSEIF (OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND A tls_arm64.s tls_stub.go trace.go + traceallocfree.go traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go type.go typekind.go unsafe.go @@ -332,6 +360,7 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH asm.s asm_amd64.s atomic_pointer.go + badlinkname.go cgo.go cgocall.go cgocallback.go @@ -356,7 +385,6 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH duff_amd64.s env_posix.go error.go - exithook.go extern.go fastlog2.go fastlog2table.go @@ -367,6 +395,8 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH histogram.go iface.go lfstack.go + linkname.go + linkname_unix.go lock_sema.go lockrank.go lockrank_off.go @@ -377,7 +407,6 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH map_faststr.go mbarrier.go mbitmap.go - mbitmap_noallocheaders.go mcache.go mcentral.go mcheckmark.go @@ -404,19 +433,19 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH mpallocbits.go mprof.go mranges.go - msize_noallocheaders.go + msize.go mspanset.go mstats.go mwbbuf.go nbpipe_pipe.go netpoll.go netpoll_kqueue.go + netpoll_kqueue_event.go nonwindows_stub.go os_darwin.go os_nonopenbsd.go os_unix.go os_unix_nonlinux.go - pagetrace_off.go panic.go pinner.go plugin.go @@ -472,7 +501,20 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH timestub.go tls_stub.go trace.go + traceallocfree.go traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go type.go typekind.go unsafe.go @@ -487,6 +529,7 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND asm.s asm_amd64.s atomic_pointer.go + badlinkname.go cgo.go cgocall.go cgocallback.go @@ -511,7 +554,6 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND duff_amd64.s env_posix.go error.go - exithook.go extern.go fastlog2.go fastlog2table.go @@ -522,6 +564,8 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND histogram.go iface.go lfstack.go + linkname.go + linkname_unix.go lock_sema.go lockrank.go lockrank_off.go @@ -532,7 +576,6 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND map_faststr.go mbarrier.go mbitmap.go - mbitmap_noallocheaders.go mcache.go mcentral.go mcheckmark.go @@ -559,19 +602,19 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND mpallocbits.go mprof.go mranges.go - msize_noallocheaders.go + msize.go mspanset.go mstats.go mwbbuf.go nbpipe_pipe.go netpoll.go netpoll_kqueue.go + netpoll_kqueue_event.go nonwindows_stub.go os_darwin.go os_nonopenbsd.go os_unix.go os_unix_nonlinux.go - pagetrace_off.go panic.go pinner.go plugin.go @@ -626,7 +669,20 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND timestub.go tls_stub.go trace.go + traceallocfree.go traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go type.go typekind.go unsafe.go @@ -642,6 +698,8 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ asm_arm64.s atomic_arm64.s atomic_pointer.go + badlinkname.go + badlinkname_linux.go cgo.go cgo_mmap.go cgo_sigaction.go @@ -667,7 +725,6 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ duff_arm64.s env_posix.go error.go - exithook.go extern.go fastlog2.go fastlog2table.go @@ -678,6 +735,8 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ histogram.go iface.go lfstack.go + linkname.go + linkname_unix.go lock_futex.go lockrank.go lockrank_off.go @@ -688,7 +747,6 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ map_faststr.go mbarrier.go mbitmap.go - mbitmap_noallocheaders.go mcache.go mcentral.go mcheckmark.go @@ -715,7 +773,7 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ mpallocbits.go mprof.go mranges.go - msize_noallocheaders.go + msize.go mspanset.go mstats.go mwbbuf.go @@ -728,7 +786,6 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ os_linux_generic.go os_nonopenbsd.go os_unix.go - pagetrace_off.go panic.go pinner.go plugin.go @@ -786,7 +843,20 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ tls_arm64.s tls_stub.go trace.go + traceallocfree.go traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go type.go typekind.go unsafe.go @@ -804,6 +874,8 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND A asm_arm64.s atomic_arm64.s atomic_pointer.go + badlinkname.go + badlinkname_linux.go cgo.go cgo_mmap.go cgo_sigaction.go @@ -829,7 +901,6 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND A duff_arm64.s env_posix.go error.go - exithook.go extern.go fastlog2.go fastlog2table.go @@ -840,6 +911,8 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND A histogram.go iface.go lfstack.go + linkname.go + linkname_unix.go lock_futex.go lockrank.go lockrank_off.go @@ -850,7 +923,6 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND A map_faststr.go mbarrier.go mbitmap.go - mbitmap_noallocheaders.go mcache.go mcentral.go mcheckmark.go @@ -877,7 +949,7 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND A mpallocbits.go mprof.go mranges.go - msize_noallocheaders.go + msize.go mspanset.go mstats.go mwbbuf.go @@ -890,7 +962,6 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND A os_linux_generic.go os_nonopenbsd.go os_unix.go - pagetrace_off.go panic.go pinner.go plugin.go @@ -947,7 +1018,20 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND A tls_arm64.s tls_stub.go trace.go + traceallocfree.go traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go type.go typekind.go unsafe.go @@ -964,6 +1048,8 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X asm.s asm_amd64.s atomic_pointer.go + badlinkname.go + badlinkname_linux.go cgo.go cgo_mmap.go cgo_sigaction.go @@ -990,7 +1076,6 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X duff_amd64.s env_posix.go error.go - exithook.go extern.go fastlog2.go fastlog2table.go @@ -1001,6 +1086,8 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X histogram.go iface.go lfstack.go + linkname.go + linkname_unix.go lock_futex.go lockrank.go lockrank_off.go @@ -1011,7 +1098,6 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X map_faststr.go mbarrier.go mbitmap.go - mbitmap_noallocheaders.go mcache.go mcentral.go mcheckmark.go @@ -1038,7 +1124,7 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X mpallocbits.go mprof.go mranges.go - msize_noallocheaders.go + msize.go mspanset.go mstats.go mwbbuf.go @@ -1052,7 +1138,6 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X os_linux_x86.go os_nonopenbsd.go os_unix.go - pagetrace_off.go panic.go pinner.go plugin.go @@ -1110,7 +1195,20 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X timeasm.go tls_stub.go trace.go + traceallocfree.go traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go type.go typekind.go unsafe.go @@ -1127,6 +1225,8 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND AR asm.s asm_amd64.s atomic_pointer.go + badlinkname.go + badlinkname_linux.go cgo.go cgo_mmap.go cgo_sigaction.go @@ -1153,7 +1253,6 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND AR duff_amd64.s env_posix.go error.go - exithook.go extern.go fastlog2.go fastlog2table.go @@ -1164,6 +1263,8 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND AR histogram.go iface.go lfstack.go + linkname.go + linkname_unix.go lock_futex.go lockrank.go lockrank_off.go @@ -1174,7 +1275,6 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND AR map_faststr.go mbarrier.go mbitmap.go - mbitmap_noallocheaders.go mcache.go mcentral.go mcheckmark.go @@ -1201,7 +1301,7 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND AR mpallocbits.go mprof.go mranges.go - msize_noallocheaders.go + msize.go mspanset.go mstats.go mwbbuf.go @@ -1215,7 +1315,6 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND AR os_linux_x86.go os_nonopenbsd.go os_unix.go - pagetrace_off.go panic.go pinner.go plugin.go @@ -1272,7 +1371,20 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND AR timeasm.go tls_stub.go trace.go + traceallocfree.go traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go type.go typekind.go unsafe.go @@ -1290,6 +1402,7 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND AR asm_amd64.s atomic_pointer.go auxv_none.go + badlinkname.go cgo.go cgocall.go cgocallback.go @@ -1315,7 +1428,6 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND AR duff_amd64.s env_posix.go error.go - exithook.go extern.go fastlog2.go fastlog2table.go @@ -1326,6 +1438,7 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND AR histogram.go iface.go lfstack.go + linkname.go lock_sema.go lockrank.go lockrank_off.go @@ -1336,7 +1449,6 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND AR map_faststr.go mbarrier.go mbitmap.go - mbitmap_noallocheaders.go mcache.go mcentral.go mcheckmark.go @@ -1363,7 +1475,7 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND AR mpallocbits.go mprof.go mranges.go - msize_noallocheaders.go + msize.go mspanset.go mstats.go mwbbuf.go @@ -1371,7 +1483,6 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND AR netpoll_windows.go os_nonopenbsd.go os_windows.go - pagetrace_off.go panic.go pinner.go plugin.go @@ -1423,7 +1534,20 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND AR timeasm.go tls_windows_amd64.go trace.go + traceallocfree.go traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go type.go typekind.go unsafe.go @@ -1441,6 +1565,7 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AN asm_amd64.s atomic_pointer.go auxv_none.go + badlinkname.go cgo.go cgocall.go cgocallback.go @@ -1466,7 +1591,6 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AN duff_amd64.s env_posix.go error.go - exithook.go extern.go fastlog2.go fastlog2table.go @@ -1477,6 +1601,7 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AN histogram.go iface.go lfstack.go + linkname.go lock_sema.go lockrank.go lockrank_off.go @@ -1487,7 +1612,6 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AN map_faststr.go mbarrier.go mbitmap.go - mbitmap_noallocheaders.go mcache.go mcentral.go mcheckmark.go @@ -1514,7 +1638,7 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AN mpallocbits.go mprof.go mranges.go - msize_noallocheaders.go + msize.go mspanset.go mstats.go mwbbuf.go @@ -1522,7 +1646,6 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AN netpoll_windows.go os_nonopenbsd.go os_windows.go - pagetrace_off.go panic.go pinner.go plugin.go @@ -1573,7 +1696,20 @@ ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AN timeasm.go tls_windows_amd64.go trace.go + traceallocfree.go traceback.go + tracebuf.go + tracecpu.go + traceevent.go + traceexp.go + tracemap.go + traceregion.go + traceruntime.go + tracestack.go + tracestatus.go + tracestring.go + tracetime.go + tracetype.go type.go typekind.go unsafe.go diff --git a/contrib/go/_std_1.22/src/runtime/zcallback_windows.go b/contrib/go/_std_1.23/src/runtime/zcallback_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/runtime/zcallback_windows.go rename to contrib/go/_std_1.23/src/runtime/zcallback_windows.go diff --git a/contrib/go/_std_1.22/src/runtime/zcallback_windows.s b/contrib/go/_std_1.23/src/runtime/zcallback_windows.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/zcallback_windows.s rename to contrib/go/_std_1.23/src/runtime/zcallback_windows.s diff --git a/contrib/go/_std_1.22/src/runtime/zcallback_windows_arm.s b/contrib/go/_std_1.23/src/runtime/zcallback_windows_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/zcallback_windows_arm.s rename to contrib/go/_std_1.23/src/runtime/zcallback_windows_arm.s diff --git a/contrib/go/_std_1.22/src/runtime/zcallback_windows_arm64.s b/contrib/go/_std_1.23/src/runtime/zcallback_windows_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/runtime/zcallback_windows_arm64.s rename to contrib/go/_std_1.23/src/runtime/zcallback_windows_arm64.s diff --git a/contrib/go/_std_1.23/src/slices/iter.go b/contrib/go/_std_1.23/src/slices/iter.go new file mode 100644 index 000000000000..cd8f308ca08e --- /dev/null +++ b/contrib/go/_std_1.23/src/slices/iter.go @@ -0,0 +1,109 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package slices + +import ( + "cmp" + "iter" +) + +// All returns an iterator over index-value pairs in the slice +// in the usual order. +func All[Slice ~[]E, E any](s Slice) iter.Seq2[int, E] { + return func(yield func(int, E) bool) { + for i, v := range s { + if !yield(i, v) { + return + } + } + } +} + +// Backward returns an iterator over index-value pairs in the slice, +// traversing it backward with descending indices. +func Backward[Slice ~[]E, E any](s Slice) iter.Seq2[int, E] { + return func(yield func(int, E) bool) { + for i := len(s) - 1; i >= 0; i-- { + if !yield(i, s[i]) { + return + } + } + } +} + +// Values returns an iterator that yields the slice elements in order. +func Values[Slice ~[]E, E any](s Slice) iter.Seq[E] { + return func(yield func(E) bool) { + for _, v := range s { + if !yield(v) { + return + } + } + } +} + +// AppendSeq appends the values from seq to the slice and +// returns the extended slice. +func AppendSeq[Slice ~[]E, E any](s Slice, seq iter.Seq[E]) Slice { + for v := range seq { + s = append(s, v) + } + return s +} + +// Collect collects values from seq into a new slice and returns it. +func Collect[E any](seq iter.Seq[E]) []E { + return AppendSeq([]E(nil), seq) +} + +// Sorted collects values from seq into a new slice, sorts the slice, +// and returns it. +func Sorted[E cmp.Ordered](seq iter.Seq[E]) []E { + s := Collect(seq) + Sort(s) + return s +} + +// SortedFunc collects values from seq into a new slice, sorts the slice +// using the comparison function, and returns it. +func SortedFunc[E any](seq iter.Seq[E], cmp func(E, E) int) []E { + s := Collect(seq) + SortFunc(s, cmp) + return s +} + +// SortedStableFunc collects values from seq into a new slice. +// It then sorts the slice while keeping the original order of equal elements, +// using the comparison function to compare elements. +// It returns the new slice. +func SortedStableFunc[E any](seq iter.Seq[E], cmp func(E, E) int) []E { + s := Collect(seq) + SortStableFunc(s, cmp) + return s +} + +// Chunk returns an iterator over consecutive sub-slices of up to n elements of s. +// All but the last sub-slice will have size n. +// All sub-slices are clipped to have no capacity beyond the length. +// If s is empty, the sequence is empty: there is no empty slice in the sequence. +// Chunk panics if n is less than 1. +func Chunk[Slice ~[]E, E any](s Slice, n int) iter.Seq[Slice] { + if n < 1 { + panic("cannot be less than 1") + } + + return func(yield func(Slice) bool) { + for i := 0; i < len(s); i += n { + // Clamp the last chunk to the slice bound as necessary. + end := min(n, len(s[i:])) + + // Set the capacity of each chunk so that appending to a chunk does + // not modify the original slice. + if !yield(s[i : i+end : i+end]) { + return + } + } + } +} diff --git a/contrib/go/_std_1.22/src/slices/slices.go b/contrib/go/_std_1.23/src/slices/slices.go similarity index 89% rename from contrib/go/_std_1.22/src/slices/slices.go rename to contrib/go/_std_1.23/src/slices/slices.go index b0f048a65660..b3cd4e2c0540 100644 --- a/contrib/go/_std_1.22/src/slices/slices.go +++ b/contrib/go/_std_1.23/src/slices/slices.go @@ -7,6 +7,7 @@ package slices import ( "cmp" + "math/bits" "unsafe" ) @@ -14,6 +15,7 @@ import ( // elements equal. If the lengths are different, Equal returns false. // Otherwise, the elements are compared in increasing index order, and the // comparison stops at the first unequal pair. +// Empty and nil slices are considered equal. // Floating point NaNs are not considered equal. func Equal[S ~[]E, E comparable](s1, s2 S) bool { if len(s1) != len(s2) { @@ -258,7 +260,11 @@ func Replace[S ~[]E, E any](s S, i, j int, v ...E) S { return Insert(s, i, v...) } if j == len(s) { - return append(s[:i], v...) + s2 := append(s[:i], v...) + if len(s2) < len(s) { + clear(s[len(s2):]) // zero/nil out the obsolete elements, for GC + } + return s2 } tot := len(s[:i]) + len(v) + len(s[j:]) @@ -338,6 +344,7 @@ func Replace[S ~[]E, E any](s S, i, j int, v ...E) S { // Clone returns a copy of the slice. // The elements are copied using assignment, so this is a shallow clone. +// The result may have additional unused capacity. func Clone[S ~[]E, E any](s S) S { // The s[:0:0] preserves nil in case it matters. return append(s[:0:0], s...) @@ -352,17 +359,21 @@ func Compact[S ~[]E, E comparable](s S) S { if len(s) < 2 { return s } - i := 1 for k := 1; k < len(s); k++ { - if s[k] != s[k-1] { - if i != k { - s[i] = s[k] + if s[k] == s[k-1] { + s2 := s[k:] + for k2 := 1; k2 < len(s2); k2++ { + if s2[k2] != s2[k2-1] { + s[k] = s2[k2] + k++ + } } - i++ + + clear(s[k:]) // zero/nil out the obsolete elements, for GC + return s[:k] } } - clear(s[i:]) // zero/nil out the obsolete elements, for GC - return s[:i] + return s } // CompactFunc is like [Compact] but uses an equality function to compare elements. @@ -372,17 +383,21 @@ func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S { if len(s) < 2 { return s } - i := 1 for k := 1; k < len(s); k++ { - if !eq(s[k], s[k-1]) { - if i != k { - s[i] = s[k] + if eq(s[k], s[k-1]) { + s2 := s[k:] + for k2 := 1; k2 < len(s2); k2++ { + if !eq(s2[k2], s2[k2-1]) { + s[k] = s2[k2] + k++ + } } - i++ + + clear(s[k:]) // zero/nil out the obsolete elements, for GC + return s[:k] } } - clear(s[i:]) // zero/nil out the obsolete elements, for GC - return s[:i] + return s } // Grow increases the slice's capacity, if necessary, to guarantee space for @@ -404,65 +419,21 @@ func Clip[S ~[]E, E any](s S) S { return s[:len(s):len(s)] } -// Rotation algorithm explanation: -// -// rotate left by 2 -// start with -// 0123456789 -// split up like this -// 01 234567 89 -// swap first 2 and last 2 -// 89 234567 01 -// join first parts -// 89234567 01 -// recursively rotate first left part by 2 -// 23456789 01 -// join at the end -// 2345678901 -// -// rotate left by 8 -// start with -// 0123456789 -// split up like this -// 01 234567 89 -// swap first 2 and last 2 -// 89 234567 01 -// join last parts -// 89 23456701 -// recursively rotate second part left by 6 -// 89 01234567 -// join at the end -// 8901234567 - // TODO: There are other rotate algorithms. -// This algorithm has the desirable property that it moves each element exactly twice. -// The triple-reverse algorithm is simpler and more cache friendly, but takes more writes. +// This algorithm has the desirable property that it moves each element at most twice. // The follow-cycles algorithm can be 1-write but it is not very cache friendly. -// rotateLeft rotates b left by n spaces. +// rotateLeft rotates s left by r spaces. // s_final[i] = s_orig[i+r], wrapping around. func rotateLeft[E any](s []E, r int) { - for r != 0 && r != len(s) { - if r*2 <= len(s) { - swap(s[:r], s[len(s)-r:]) - s = s[:len(s)-r] - } else { - swap(s[:len(s)-r], s[r:]) - s, r = s[len(s)-r:], r*2-len(s) - } - } + Reverse(s[:r]) + Reverse(s[r:]) + Reverse(s) } func rotateRight[E any](s []E, r int) { rotateLeft(s, len(s)-r) } -// swap swaps the contents of x and y. x and y must be equal length and disjoint. -func swap[E any](x, y []E) { - for i := 0; i < len(x); i++ { - x[i], y[i] = y[i], x[i] - } -} - // overlaps reports whether the memory ranges a[0:len(a)] and b[0:len(b)] overlap. func overlaps[E any](a, b []E) bool { if len(a) == 0 || len(b) == 0 { @@ -513,3 +484,26 @@ func Concat[S ~[]E, E any](slices ...S) S { } return newslice } + +// Repeat returns a new slice that repeats the provided slice the given number of times. +// The result has length and capacity (len(x) * count). +// The result is never nil. +// Repeat panics if count is negative or if the result of (len(x) * count) +// overflows. +func Repeat[S ~[]E, E any](x S, count int) S { + if count < 0 { + panic("cannot be negative") + } + + const maxInt = ^uint(0) >> 1 + if hi, lo := bits.Mul(uint(len(x)), uint(count)); hi > 0 || lo > maxInt { + panic("the result of (len(x) * count) overflows") + } + + newslice := make(S, len(x)*count) + n := copy(newslice, x) + for n < len(newslice) { + n += copy(newslice[n:], newslice[:n]) + } + return newslice +} diff --git a/contrib/go/_std_1.22/src/slices/sort.go b/contrib/go/_std_1.23/src/slices/sort.go similarity index 93% rename from contrib/go/_std_1.22/src/slices/sort.go rename to contrib/go/_std_1.23/src/slices/sort.go index d5e998ce1e2c..f713ffe09473 100644 --- a/contrib/go/_std_1.22/src/slices/sort.go +++ b/contrib/go/_std_1.23/src/slices/sort.go @@ -21,10 +21,12 @@ func Sort[S ~[]E, E cmp.Ordered](x S) { // SortFunc sorts the slice x in ascending order as determined by the cmp // function. This sort is not guaranteed to be stable. // cmp(a, b) should return a negative number when a < b, a positive number when -// a > b and zero when a == b. +// a > b and zero when a == b or a and b are incomparable in the sense of +// a strict weak ordering. // // SortFunc requires that cmp is a strict weak ordering. // See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings. +// The function should return 0 for incomparable items. func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) { n := len(x) pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp) @@ -117,10 +119,10 @@ func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E { return m } -// BinarySearch searches for target in a sorted slice and returns the position -// where target is found, or the position where target would appear in the -// sort order; it also returns a bool saying whether the target is really found -// in the slice. The slice must be sorted in increasing order. +// BinarySearch searches for target in a sorted slice and returns the earliest +// position where target is found, or the position where target would appear +// in the sort order; it also returns a bool saying whether the target is +// really found in the slice. The slice must be sorted in increasing order. func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool) { // Inlining is faster than calling BinarySearchFunc with a lambda. n := len(x) diff --git a/contrib/go/_std_1.22/src/slices/ya.make b/contrib/go/_std_1.23/src/slices/ya.make similarity index 89% rename from contrib/go/_std_1.22/src/slices/ya.make rename to contrib/go/_std_1.23/src/slices/ya.make index 4d251376d86f..f94289df8269 100644 --- a/contrib/go/_std_1.22/src/slices/ya.make +++ b/contrib/go/_std_1.23/src/slices/ya.make @@ -1,6 +1,7 @@ GO_LIBRARY() IF (TRUE) SRCS( + iter.go slices.go sort.go zsortanyfunc.go diff --git a/contrib/go/_std_1.22/src/slices/zsortanyfunc.go b/contrib/go/_std_1.23/src/slices/zsortanyfunc.go similarity index 100% rename from contrib/go/_std_1.22/src/slices/zsortanyfunc.go rename to contrib/go/_std_1.23/src/slices/zsortanyfunc.go diff --git a/contrib/go/_std_1.22/src/slices/zsortordered.go b/contrib/go/_std_1.23/src/slices/zsortordered.go similarity index 100% rename from contrib/go/_std_1.22/src/slices/zsortordered.go rename to contrib/go/_std_1.23/src/slices/zsortordered.go diff --git a/contrib/go/_std_1.22/src/sort/gen_sort_variants.go b/contrib/go/_std_1.23/src/sort/gen_sort_variants.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/gen_sort_variants.go rename to contrib/go/_std_1.23/src/sort/gen_sort_variants.go diff --git a/contrib/go/_std_1.22/src/sort/search.go b/contrib/go/_std_1.23/src/sort/search.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/search.go rename to contrib/go/_std_1.23/src/sort/search.go diff --git a/contrib/go/_std_1.22/src/sort/slice.go b/contrib/go/_std_1.23/src/sort/slice.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/slice.go rename to contrib/go/_std_1.23/src/sort/slice.go diff --git a/contrib/go/_std_1.22/src/sort/sort.go b/contrib/go/_std_1.23/src/sort/sort.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/sort.go rename to contrib/go/_std_1.23/src/sort/sort.go diff --git a/contrib/go/_std_1.22/src/sort/sort_impl_120.go b/contrib/go/_std_1.23/src/sort/sort_impl_120.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/sort_impl_120.go rename to contrib/go/_std_1.23/src/sort/sort_impl_120.go diff --git a/contrib/go/_std_1.22/src/sort/sort_impl_go121.go b/contrib/go/_std_1.23/src/sort/sort_impl_go121.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/sort_impl_go121.go rename to contrib/go/_std_1.23/src/sort/sort_impl_go121.go diff --git a/contrib/go/_std_1.22/src/sort/ya.make b/contrib/go/_std_1.23/src/sort/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/sort/ya.make rename to contrib/go/_std_1.23/src/sort/ya.make diff --git a/contrib/go/_std_1.22/src/sort/zsortfunc.go b/contrib/go/_std_1.23/src/sort/zsortfunc.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/zsortfunc.go rename to contrib/go/_std_1.23/src/sort/zsortfunc.go diff --git a/contrib/go/_std_1.22/src/sort/zsortinterface.go b/contrib/go/_std_1.23/src/sort/zsortinterface.go similarity index 100% rename from contrib/go/_std_1.22/src/sort/zsortinterface.go rename to contrib/go/_std_1.23/src/sort/zsortinterface.go diff --git a/contrib/go/_std_1.22/src/strconv/atob.go b/contrib/go/_std_1.23/src/strconv/atob.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/atob.go rename to contrib/go/_std_1.23/src/strconv/atob.go diff --git a/contrib/go/_std_1.22/src/strconv/atoc.go b/contrib/go/_std_1.23/src/strconv/atoc.go similarity index 93% rename from contrib/go/_std_1.22/src/strconv/atoc.go rename to contrib/go/_std_1.23/src/strconv/atoc.go index f6fdd14e6496..560bd7920df0 100644 --- a/contrib/go/_std_1.22/src/strconv/atoc.go +++ b/contrib/go/_std_1.23/src/strconv/atoc.go @@ -4,6 +4,8 @@ package strconv +import "internal/stringslite" + const fnParseComplex = "ParseComplex" // convErr splits an error returned by parseFloatPrefix @@ -11,7 +13,7 @@ const fnParseComplex = "ParseComplex" func convErr(err error, s string) (syntax, range_ error) { if x, ok := err.(*NumError); ok { x.Func = fnParseComplex - x.Num = cloneString(s) + x.Num = stringslite.Clone(s) if x.Err == ErrRange { return nil, x } @@ -25,13 +27,13 @@ func convErr(err error, s string) (syntax, range_ error) { // convertible to complex64 without changing its value. // // The number represented by s must be of the form N, Ni, or N±Ni, where N stands -// for a floating-point number as recognized by ParseFloat, and i is the imaginary +// for a floating-point number as recognized by [ParseFloat], and i is the imaginary // component. If the second N is unsigned, a + sign is required between the two components // as indicated by the ±. If the second N is NaN, only a + sign is accepted. // The form may be parenthesized and cannot contain any spaces. // The resulting complex number consists of the two components converted by ParseFloat. // -// The errors that ParseComplex returns have concrete type *NumError +// The errors that ParseComplex returns have concrete type [*NumError] // and include err.Num = s. // // If s is not syntactically well-formed, ParseComplex returns err.Err = ErrSyntax. diff --git a/contrib/go/_std_1.22/src/strconv/atof.go b/contrib/go/_std_1.23/src/strconv/atof.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/atof.go rename to contrib/go/_std_1.23/src/strconv/atof.go diff --git a/contrib/go/_std_1.22/src/strconv/atoi.go b/contrib/go/_std_1.23/src/strconv/atoi.go similarity index 89% rename from contrib/go/_std_1.22/src/strconv/atoi.go rename to contrib/go/_std_1.23/src/strconv/atoi.go index 520d826323bf..599ad9b89508 100644 --- a/contrib/go/_std_1.22/src/strconv/atoi.go +++ b/contrib/go/_std_1.23/src/strconv/atoi.go @@ -4,7 +4,10 @@ package strconv -import "errors" +import ( + "errors" + "internal/stringslite" +) // lower(c) is a lower-case letter if and only if // c is either that lower-case letter or the equivalent upper-case letter. @@ -33,8 +36,6 @@ func (e *NumError) Error() string { func (e *NumError) Unwrap() error { return e.Err } -// cloneString returns a string copy of x. -// // All ParseXXX functions allow the input string to escape to the error value. // This hurts strconv.ParseXXX(string(b)) calls where b is []byte since // the conversion from []byte must allocate a string on the heap. @@ -42,27 +43,21 @@ func (e *NumError) Unwrap() error { return e.Err } // back to the output by copying it first. This allows the compiler to call // strconv.ParseXXX without a heap allocation for most []byte to string // conversions, since it can now prove that the string cannot escape Parse. -// -// TODO: Use strings.Clone instead? However, we cannot depend on "strings" -// since it incurs a transitive dependency on "unicode". -// Either move strings.Clone to an internal/bytealg or make the -// "strings" to "unicode" dependency lighter (see https://go.dev/issue/54098). -func cloneString(x string) string { return string([]byte(x)) } func syntaxError(fn, str string) *NumError { - return &NumError{fn, cloneString(str), ErrSyntax} + return &NumError{fn, stringslite.Clone(str), ErrSyntax} } func rangeError(fn, str string) *NumError { - return &NumError{fn, cloneString(str), ErrRange} + return &NumError{fn, stringslite.Clone(str), ErrRange} } func baseError(fn, str string, base int) *NumError { - return &NumError{fn, cloneString(str), errors.New("invalid base " + Itoa(base))} + return &NumError{fn, stringslite.Clone(str), errors.New("invalid base " + Itoa(base))} } func bitSizeError(fn, str string, bitSize int) *NumError { - return &NumError{fn, cloneString(str), errors.New("invalid bit size " + Itoa(bitSize))} + return &NumError{fn, stringslite.Clone(str), errors.New("invalid bit size " + Itoa(bitSize))} } const intSize = 32 << (^uint(0) >> 63) @@ -72,7 +67,7 @@ const IntSize = intSize const maxUint64 = 1<<64 - 1 -// ParseUint is like ParseInt but for unsigned numbers. +// ParseUint is like [ParseInt] but for unsigned numbers. // // A sign prefix is not permitted. func ParseUint(s string, base int, bitSize int) (uint64, error) { @@ -190,11 +185,11 @@ func ParseUint(s string, base int, bitSize int) (uint64, error) { // correspond to int, int8, int16, int32, and int64. // If bitSize is below 0 or above 64, an error is returned. // -// The errors that ParseInt returns have concrete type *NumError +// The errors that ParseInt returns have concrete type [*NumError] // and include err.Num = s. If s is empty or contains invalid -// digits, err.Err = ErrSyntax and the returned value is 0; +// digits, err.Err = [ErrSyntax] and the returned value is 0; // if the value corresponding to s cannot be represented by a -// signed integer of the given size, err.Err = ErrRange and the +// signed integer of the given size, err.Err = [ErrRange] and the // returned value is the maximum magnitude integer of the // appropriate bitSize and sign. // @@ -221,7 +216,7 @@ func ParseInt(s string, base int, bitSize int) (i int64, err error) { un, err = ParseUint(s, base, bitSize) if err != nil && err.(*NumError).Err != ErrRange { err.(*NumError).Func = fnParseInt - err.(*NumError).Num = cloneString(s0) + err.(*NumError).Num = stringslite.Clone(s0) return 0, err } diff --git a/contrib/go/_std_1.22/src/strconv/bytealg.go b/contrib/go/_std_1.23/src/strconv/bytealg.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/bytealg.go rename to contrib/go/_std_1.23/src/strconv/bytealg.go diff --git a/contrib/go/_std_1.22/src/strconv/bytealg_bootstrap.go b/contrib/go/_std_1.23/src/strconv/bytealg_bootstrap.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/bytealg_bootstrap.go rename to contrib/go/_std_1.23/src/strconv/bytealg_bootstrap.go diff --git a/contrib/go/_std_1.22/src/strconv/ctoa.go b/contrib/go/_std_1.23/src/strconv/ctoa.go similarity index 98% rename from contrib/go/_std_1.22/src/strconv/ctoa.go rename to contrib/go/_std_1.23/src/strconv/ctoa.go index c16a2e579cf1..fd7f941d7034 100644 --- a/contrib/go/_std_1.22/src/strconv/ctoa.go +++ b/contrib/go/_std_1.23/src/strconv/ctoa.go @@ -8,7 +8,7 @@ package strconv // form (a+bi) where a and b are the real and imaginary parts, // formatted according to the format fmt and precision prec. // -// The format fmt and precision prec have the same meaning as in FormatFloat. +// The format fmt and precision prec have the same meaning as in [FormatFloat]. // It rounds the result assuming that the original was obtained from a complex // value of bitSize bits, which must be 64 for complex64 and 128 for complex128. func FormatComplex(c complex128, fmt byte, prec, bitSize int) string { diff --git a/contrib/go/_std_1.22/src/strconv/decimal.go b/contrib/go/_std_1.23/src/strconv/decimal.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/decimal.go rename to contrib/go/_std_1.23/src/strconv/decimal.go diff --git a/contrib/go/_std_1.22/src/strconv/doc.go b/contrib/go/_std_1.23/src/strconv/doc.go similarity index 95% rename from contrib/go/_std_1.22/src/strconv/doc.go rename to contrib/go/_std_1.23/src/strconv/doc.go index fa20f902d0a2..51033a62f6a0 100644 --- a/contrib/go/_std_1.22/src/strconv/doc.go +++ b/contrib/go/_std_1.23/src/strconv/doc.go @@ -7,7 +7,7 @@ // // # Numeric Conversions // -// The most common numeric conversions are Atoi (string to int) and Itoa (int to string). +// The most common numeric conversions are [Atoi] (string to int) and [Itoa] (int to string). // // i, err := strconv.Atoi("-42") // s := strconv.Itoa(-42) diff --git a/contrib/go/_std_1.22/src/strconv/eisel_lemire.go b/contrib/go/_std_1.23/src/strconv/eisel_lemire.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/eisel_lemire.go rename to contrib/go/_std_1.23/src/strconv/eisel_lemire.go diff --git a/contrib/go/_std_1.22/src/strconv/ftoa.go b/contrib/go/_std_1.23/src/strconv/ftoa.go similarity index 99% rename from contrib/go/_std_1.22/src/strconv/ftoa.go rename to contrib/go/_std_1.23/src/strconv/ftoa.go index c514e663da19..220869898f83 100644 --- a/contrib/go/_std_1.22/src/strconv/ftoa.go +++ b/contrib/go/_std_1.23/src/strconv/ftoa.go @@ -49,7 +49,7 @@ func FormatFloat(f float64, fmt byte, prec, bitSize int) string { } // AppendFloat appends the string form of the floating-point number f, -// as generated by FormatFloat, to dst and returns the extended buffer. +// as generated by [FormatFloat], to dst and returns the extended buffer. func AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte { return genericFtoa(dst, f, fmt, prec, bitSize) } diff --git a/contrib/go/_std_1.22/src/strconv/ftoaryu.go b/contrib/go/_std_1.23/src/strconv/ftoaryu.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/ftoaryu.go rename to contrib/go/_std_1.23/src/strconv/ftoaryu.go diff --git a/contrib/go/_std_1.22/src/strconv/isprint.go b/contrib/go/_std_1.23/src/strconv/isprint.go similarity index 100% rename from contrib/go/_std_1.22/src/strconv/isprint.go rename to contrib/go/_std_1.23/src/strconv/isprint.go diff --git a/contrib/go/_std_1.22/src/strconv/itoa.go b/contrib/go/_std_1.23/src/strconv/itoa.go similarity index 96% rename from contrib/go/_std_1.22/src/strconv/itoa.go rename to contrib/go/_std_1.23/src/strconv/itoa.go index b0c2666e7cb7..29fec41fe2e4 100644 --- a/contrib/go/_std_1.22/src/strconv/itoa.go +++ b/contrib/go/_std_1.23/src/strconv/itoa.go @@ -30,13 +30,13 @@ func FormatInt(i int64, base int) string { return s } -// Itoa is equivalent to FormatInt(int64(i), 10). +// Itoa is equivalent to [FormatInt](int64(i), 10). func Itoa(i int) string { return FormatInt(int64(i), 10) } // AppendInt appends the string form of the integer i, -// as generated by FormatInt, to dst and returns the extended buffer. +// as generated by [FormatInt], to dst and returns the extended buffer. func AppendInt(dst []byte, i int64, base int) []byte { if fastSmalls && 0 <= i && i < nSmalls && base == 10 { return append(dst, small(int(i))...) @@ -46,7 +46,7 @@ func AppendInt(dst []byte, i int64, base int) []byte { } // AppendUint appends the string form of the unsigned integer i, -// as generated by FormatUint, to dst and returns the extended buffer. +// as generated by [FormatUint], to dst and returns the extended buffer. func AppendUint(dst []byte, i uint64, base int) []byte { if fastSmalls && i < nSmalls && base == 10 { return append(dst, small(int(i))...) diff --git a/contrib/go/_std_1.22/src/strconv/makeisprint.go b/contrib/go/_std_1.23/src/strconv/makeisprint.go similarity index 84% rename from contrib/go/_std_1.22/src/strconv/makeisprint.go rename to contrib/go/_std_1.23/src/strconv/makeisprint.go index ff361e7b41fb..767448067b72 100644 --- a/contrib/go/_std_1.22/src/strconv/makeisprint.go +++ b/contrib/go/_std_1.23/src/strconv/makeisprint.go @@ -19,6 +19,7 @@ import ( "go/format" "log" "os" + "slices" "unicode" ) @@ -31,36 +32,6 @@ var ( except32 []uint32 ) -// bsearch16 returns the smallest i such that a[i] >= x. -// If there is no such i, bsearch16 returns len(a). -func bsearch16(a []uint16, x uint16) int { - i, j := 0, len(a) - for i < j { - h := i + (j-i)>>1 - if a[h] < x { - i = h + 1 - } else { - j = h - } - } - return i -} - -// bsearch32 returns the smallest i such that a[i] >= x. -// If there is no such i, bsearch32 returns len(a). -func bsearch32(a []uint32, x uint32) int { - i, j := 0, len(a) - for i < j { - h := i + (j-i)>>1 - if a[h] < x { - i = h + 1 - } else { - j = h - } - } - return i -} - func isPrint(r rune) bool { // Same algorithm, either on uint16 or uint32 value. // First, find first i such that rang[i] >= x. @@ -70,21 +41,21 @@ func isPrint(r rune) bool { if 0 <= r && r < 1<<16 { rr, rang, except := uint16(r), range16, except16 - i := bsearch16(rang, rr) + i, _ := slices.BinarySearch(rang, rr) if i >= len(rang) || rr < rang[i&^1] || rang[i|1] < rr { return false } - j := bsearch16(except, rr) - return j >= len(except) || except[j] != rr + _, found := slices.BinarySearch(except, rr) + return !found } rr, rang, except := uint32(r), range32, except32 - i := bsearch32(rang, rr) + i, _ := slices.BinarySearch(rang, rr) if i >= len(rang) || rr < rang[i&^1] || rang[i|1] < rr { return false } - j := bsearch32(except, rr) - return j >= len(except) || except[j] != rr + _, found := slices.BinarySearch(except, rr) + return !found } func scan(min, max rune) (rang, except []uint32) { diff --git a/contrib/go/_std_1.22/src/strconv/quote.go b/contrib/go/_std_1.23/src/strconv/quote.go similarity index 90% rename from contrib/go/_std_1.22/src/strconv/quote.go rename to contrib/go/_std_1.23/src/strconv/quote.go index 7c384336795f..d626cd0837aa 100644 --- a/contrib/go/_std_1.22/src/strconv/quote.go +++ b/contrib/go/_std_1.23/src/strconv/quote.go @@ -121,47 +121,47 @@ func appendEscapedRune(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bo // Quote returns a double-quoted Go string literal representing s. The // returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for // control characters and non-printable characters as defined by -// IsPrint. +// [IsPrint]. func Quote(s string) string { return quoteWith(s, '"', false, false) } // AppendQuote appends a double-quoted Go string literal representing s, -// as generated by Quote, to dst and returns the extended buffer. +// as generated by [Quote], to dst and returns the extended buffer. func AppendQuote(dst []byte, s string) []byte { return appendQuotedWith(dst, s, '"', false, false) } // QuoteToASCII returns a double-quoted Go string literal representing s. // The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for -// non-ASCII characters and non-printable characters as defined by IsPrint. +// non-ASCII characters and non-printable characters as defined by [IsPrint]. func QuoteToASCII(s string) string { return quoteWith(s, '"', true, false) } // AppendQuoteToASCII appends a double-quoted Go string literal representing s, -// as generated by QuoteToASCII, to dst and returns the extended buffer. +// as generated by [QuoteToASCII], to dst and returns the extended buffer. func AppendQuoteToASCII(dst []byte, s string) []byte { return appendQuotedWith(dst, s, '"', true, false) } // QuoteToGraphic returns a double-quoted Go string literal representing s. // The returned string leaves Unicode graphic characters, as defined by -// IsGraphic, unchanged and uses Go escape sequences (\t, \n, \xFF, \u0100) +// [IsGraphic], unchanged and uses Go escape sequences (\t, \n, \xFF, \u0100) // for non-graphic characters. func QuoteToGraphic(s string) string { return quoteWith(s, '"', false, true) } // AppendQuoteToGraphic appends a double-quoted Go string literal representing s, -// as generated by QuoteToGraphic, to dst and returns the extended buffer. +// as generated by [QuoteToGraphic], to dst and returns the extended buffer. func AppendQuoteToGraphic(dst []byte, s string) []byte { return appendQuotedWith(dst, s, '"', false, true) } // QuoteRune returns a single-quoted Go character literal representing the // rune. The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) -// for control characters and non-printable characters as defined by IsPrint. +// for control characters and non-printable characters as defined by [IsPrint]. // If r is not a valid Unicode code point, it is interpreted as the Unicode // replacement character U+FFFD. func QuoteRune(r rune) string { @@ -169,7 +169,7 @@ func QuoteRune(r rune) string { } // AppendQuoteRune appends a single-quoted Go character literal representing the rune, -// as generated by QuoteRune, to dst and returns the extended buffer. +// as generated by [QuoteRune], to dst and returns the extended buffer. func AppendQuoteRune(dst []byte, r rune) []byte { return appendQuotedRuneWith(dst, r, '\'', false, false) } @@ -177,7 +177,7 @@ func AppendQuoteRune(dst []byte, r rune) []byte { // QuoteRuneToASCII returns a single-quoted Go character literal representing // the rune. The returned string uses Go escape sequences (\t, \n, \xFF, // \u0100) for non-ASCII characters and non-printable characters as defined -// by IsPrint. +// by [IsPrint]. // If r is not a valid Unicode code point, it is interpreted as the Unicode // replacement character U+FFFD. func QuoteRuneToASCII(r rune) string { @@ -185,14 +185,14 @@ func QuoteRuneToASCII(r rune) string { } // AppendQuoteRuneToASCII appends a single-quoted Go character literal representing the rune, -// as generated by QuoteRuneToASCII, to dst and returns the extended buffer. +// as generated by [QuoteRuneToASCII], to dst and returns the extended buffer. func AppendQuoteRuneToASCII(dst []byte, r rune) []byte { return appendQuotedRuneWith(dst, r, '\'', true, false) } // QuoteRuneToGraphic returns a single-quoted Go character literal representing // the rune. If the rune is not a Unicode graphic character, -// as defined by IsGraphic, the returned string will use a Go escape sequence +// as defined by [IsGraphic], the returned string will use a Go escape sequence // (\t, \n, \xFF, \u0100). // If r is not a valid Unicode code point, it is interpreted as the Unicode // replacement character U+FFFD. @@ -201,7 +201,7 @@ func QuoteRuneToGraphic(r rune) string { } // AppendQuoteRuneToGraphic appends a single-quoted Go character literal representing the rune, -// as generated by QuoteRuneToGraphic, to dst and returns the extended buffer. +// as generated by [QuoteRuneToGraphic], to dst and returns the extended buffer. func AppendQuoteRuneToGraphic(dst []byte, r rune) []byte { return appendQuotedRuneWith(dst, r, '\'', false, true) } @@ -367,7 +367,7 @@ func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, return } -// QuotedPrefix returns the quoted string (as understood by Unquote) at the prefix of s. +// QuotedPrefix returns the quoted string (as understood by [Unquote]) at the prefix of s. // If s does not start with a valid quoted string, QuotedPrefix returns an error. func QuotedPrefix(s string) (string, error) { out, _, err := unquote(s, false) @@ -493,34 +493,20 @@ func unquote(in string, unescape bool) (out, rem string, err error) { } } -// bsearch16 returns the smallest i such that a[i] >= x. -// If there is no such i, bsearch16 returns len(a). -func bsearch16(a []uint16, x uint16) int { - i, j := 0, len(a) +// bsearch is semantically the same as [slices.BinarySearch] (without NaN checks) +// We copied this function because we can not import "slices" here. +func bsearch[S ~[]E, E ~uint16 | ~uint32](s S, v E) (int, bool) { + n := len(s) + i, j := 0, n for i < j { h := i + (j-i)>>1 - if a[h] < x { + if s[h] < v { i = h + 1 } else { j = h } } - return i -} - -// bsearch32 returns the smallest i such that a[i] >= x. -// If there is no such i, bsearch32 returns len(a). -func bsearch32(a []uint32, x uint32) int { - i, j := 0, len(a) - for i < j { - h := i + (j-i)>>1 - if a[h] < x { - i = h + 1 - } else { - j = h - } - } - return i + return i, i < n && s[i] == v } // TODO: IsPrint is a local implementation of unicode.IsPrint, verified by the tests @@ -530,7 +516,7 @@ func bsearch32(a []uint32, x uint32) int { // That would be nice. // IsPrint reports whether the rune is defined as printable by Go, with -// the same definition as unicode.IsPrint: letters, numbers, punctuation, +// the same definition as [unicode.IsPrint]: letters, numbers, punctuation, // symbols and ASCII space. func IsPrint(r rune) bool { // Fast check for Latin-1 @@ -554,16 +540,16 @@ func IsPrint(r rune) bool { if 0 <= r && r < 1<<16 { rr, isPrint, isNotPrint := uint16(r), isPrint16, isNotPrint16 - i := bsearch16(isPrint, rr) + i, _ := bsearch(isPrint, rr) if i >= len(isPrint) || rr < isPrint[i&^1] || isPrint[i|1] < rr { return false } - j := bsearch16(isNotPrint, rr) - return j >= len(isNotPrint) || isNotPrint[j] != rr + _, found := bsearch(isNotPrint, rr) + return !found } rr, isPrint, isNotPrint := uint32(r), isPrint32, isNotPrint32 - i := bsearch32(isPrint, rr) + i, _ := bsearch(isPrint, rr) if i >= len(isPrint) || rr < isPrint[i&^1] || isPrint[i|1] < rr { return false } @@ -571,8 +557,8 @@ func IsPrint(r rune) bool { return true } r -= 0x10000 - j := bsearch16(isNotPrint, uint16(r)) - return j >= len(isNotPrint) || isNotPrint[j] != uint16(r) + _, found := bsearch(isNotPrint, uint16(r)) + return !found } // IsGraphic reports whether the rune is defined as a Graphic by Unicode. Such @@ -593,7 +579,6 @@ func isInGraphicList(r rune) bool { if r > 0xFFFF { return false } - rr := uint16(r) - i := bsearch16(isGraphic, rr) - return i < len(isGraphic) && rr == isGraphic[i] + _, found := bsearch(isGraphic, uint16(r)) + return found } diff --git a/contrib/go/_std_1.22/src/strconv/ya.make b/contrib/go/_std_1.23/src/strconv/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/strconv/ya.make rename to contrib/go/_std_1.23/src/strconv/ya.make diff --git a/contrib/go/_std_1.22/src/strings/builder.go b/contrib/go/_std_1.23/src/strings/builder.go similarity index 85% rename from contrib/go/_std_1.22/src/strings/builder.go rename to contrib/go/_std_1.23/src/strings/builder.go index 189dadb1e7f4..e6df08c6f479 100644 --- a/contrib/go/_std_1.22/src/strings/builder.go +++ b/contrib/go/_std_1.23/src/strings/builder.go @@ -5,6 +5,7 @@ package strings import ( + "internal/abi" "internal/bytealg" "unicode/utf8" "unsafe" @@ -15,20 +16,11 @@ import ( // Do not copy a non-zero Builder. type Builder struct { addr *Builder // of receiver, to detect copies by value - buf []byte -} -// noescape hides a pointer from escape analysis. It is the identity function -// but escape analysis doesn't think the output depends on the input. -// noescape is inlined and currently compiles down to zero instructions. -// USE CAREFULLY! -// This was copied from the runtime; see issues 23382 and 7921. -// -//go:nosplit -//go:nocheckptr -func noescape(p unsafe.Pointer) unsafe.Pointer { - x := uintptr(p) - return unsafe.Pointer(x ^ 0) + // External users should never get direct access to this buffer, since + // the slice at some point will be converted to a string using unsafe, also + // data between len(buf) and cap(buf) might be uninitialized. + buf []byte } func (b *Builder) copyCheck() { @@ -38,7 +30,7 @@ func (b *Builder) copyCheck() { // See issue 23382. // TODO: once issue 7921 is fixed, this should be reverted to // just "b.addr = b". - b.addr = (*Builder)(noescape(unsafe.Pointer(b))) + b.addr = (*Builder)(abi.NoEscape(unsafe.Pointer(b))) } else if b.addr != b { panic("strings: illegal use of non-zero Builder copied by value") } diff --git a/contrib/go/_std_1.22/src/strings/clone.go b/contrib/go/_std_1.23/src/strings/clone.go similarity index 86% rename from contrib/go/_std_1.22/src/strings/clone.go rename to contrib/go/_std_1.23/src/strings/clone.go index d14df11d4979..f965b5963a3b 100644 --- a/contrib/go/_std_1.22/src/strings/clone.go +++ b/contrib/go/_std_1.23/src/strings/clone.go @@ -5,7 +5,7 @@ package strings import ( - "unsafe" + "internal/stringslite" ) // Clone returns a fresh copy of s. @@ -19,10 +19,5 @@ import ( // For strings of length zero the string "" will be returned // and no allocation is made. func Clone(s string) string { - if len(s) == 0 { - return "" - } - b := make([]byte, len(s)) - copy(b, s) - return unsafe.String(&b[0], len(b)) + return stringslite.Clone(s) } diff --git a/contrib/go/_std_1.23/src/strings/compare.go b/contrib/go/_std_1.23/src/strings/compare.go new file mode 100644 index 000000000000..dcf442471af6 --- /dev/null +++ b/contrib/go/_std_1.23/src/strings/compare.go @@ -0,0 +1,17 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings + +import "internal/bytealg" + +// Compare returns an integer comparing two strings lexicographically. +// The result will be 0 if a == b, -1 if a < b, and +1 if a > b. +// +// Use Compare when you need to perform a three-way comparison (with +// [slices.SortFunc], for example). It is usually clearer and always faster +// to use the built-in string comparison operators ==, <, >, and so on. +func Compare(a, b string) int { + return bytealg.CompareString(a, b) +} diff --git a/contrib/go/_std_1.22/src/strings/reader.go b/contrib/go/_std_1.23/src/strings/reader.go similarity index 100% rename from contrib/go/_std_1.22/src/strings/reader.go rename to contrib/go/_std_1.23/src/strings/reader.go diff --git a/contrib/go/_std_1.22/src/strings/replace.go b/contrib/go/_std_1.23/src/strings/replace.go similarity index 99% rename from contrib/go/_std_1.22/src/strings/replace.go rename to contrib/go/_std_1.23/src/strings/replace.go index 3b17a55b915d..ae127288003d 100644 --- a/contrib/go/_std_1.22/src/strings/replace.go +++ b/contrib/go/_std_1.23/src/strings/replace.go @@ -299,7 +299,7 @@ func makeGenericReplacer(oldnew []string) *genericReplacer { type appendSliceWriter []byte -// Write writes to the buffer to satisfy io.Writer. +// Write writes to the buffer to satisfy [io.Writer]. func (w *appendSliceWriter) Write(p []byte) (int, error) { *w = append(*w, p...) return len(p), nil diff --git a/contrib/go/_std_1.22/src/strings/search.go b/contrib/go/_std_1.23/src/strings/search.go similarity index 100% rename from contrib/go/_std_1.22/src/strings/search.go rename to contrib/go/_std_1.23/src/strings/search.go diff --git a/contrib/go/_std_1.22/src/strings/strings.go b/contrib/go/_std_1.23/src/strings/strings.go similarity index 91% rename from contrib/go/_std_1.22/src/strings/strings.go rename to contrib/go/_std_1.23/src/strings/strings.go index f3f0723721f6..0bd3c1c23378 100644 --- a/contrib/go/_std_1.22/src/strings/strings.go +++ b/contrib/go/_std_1.23/src/strings/strings.go @@ -9,6 +9,7 @@ package strings import ( "internal/bytealg" + "internal/stringslite" "unicode" "unicode/utf8" ) @@ -115,12 +116,12 @@ func LastIndex(s, substr string) int { // IndexByte returns the index of the first instance of c in s, or -1 if c is not present in s. func IndexByte(s string, c byte) int { - return bytealg.IndexByteString(s, c) + return stringslite.IndexByte(s, c) } // IndexRune returns the index of the first instance of the Unicode code point // r, or -1 if rune is not present in s. -// If r is utf8.RuneError, it returns the first instance of any +// If r is [utf8.RuneError], it returns the first instance of any // invalid UTF-8 byte sequence. func IndexRune(s string, r rune) int { switch { @@ -266,28 +267,26 @@ func genSplit(s, sep string, sepSave, n int) []string { // the substrings between those separators. // // The count determines the number of substrings to return: -// -// n > 0: at most n substrings; the last substring will be the unsplit remainder. -// n == 0: the result is nil (zero substrings) -// n < 0: all substrings +// - n > 0: at most n substrings; the last substring will be the unsplit remainder; +// - n == 0: the result is nil (zero substrings); +// - n < 0: all substrings. // // Edge cases for s and sep (for example, empty strings) are handled // as described in the documentation for [Split]. // -// To split around the first instance of a separator, see Cut. +// To split around the first instance of a separator, see [Cut]. func SplitN(s, sep string, n int) []string { return genSplit(s, sep, 0, n) } // SplitAfterN slices s into substrings after each instance of sep and // returns a slice of those substrings. // // The count determines the number of substrings to return: -// -// n > 0: at most n substrings; the last substring will be the unsplit remainder. -// n == 0: the result is nil (zero substrings) -// n < 0: all substrings +// - n > 0: at most n substrings; the last substring will be the unsplit remainder; +// - n == 0: the result is nil (zero substrings); +// - n < 0: all substrings. // // Edge cases for s and sep (for example, empty strings) are handled -// as described in the documentation for SplitAfter. +// as described in the documentation for [SplitAfter]. func SplitAfterN(s, sep string, n int) []string { return genSplit(s, sep, len(sep), n) } @@ -303,7 +302,7 @@ func SplitAfterN(s, sep string, n int) []string { // // It is equivalent to [SplitN] with a count of -1. // -// To split around the first instance of a separator, see Cut. +// To split around the first instance of a separator, see [Cut]. func Split(s, sep string) []string { return genSplit(s, sep, 0, -1) } // SplitAfter slices s into all substrings after each instance of sep and @@ -323,7 +322,7 @@ func SplitAfter(s, sep string) []string { var asciiSpace = [256]uint8{'\t': 1, '\n': 1, '\v': 1, '\f': 1, '\r': 1, ' ': 1} // Fields splits the string s around each instance of one or more consecutive white space -// characters, as defined by unicode.IsSpace, returning a slice of substrings of s or an +// characters, as defined by [unicode.IsSpace], returning a slice of substrings of s or an // empty slice if s contains only white space. func Fields(s string) []string { // First count the fields. @@ -460,12 +459,12 @@ func Join(elems []string, sep string) string { // HasPrefix reports whether the string s begins with prefix. func HasPrefix(s, prefix string) bool { - return len(s) >= len(prefix) && s[0:len(prefix)] == prefix + return stringslite.HasPrefix(s, prefix) } // HasSuffix reports whether the string s ends with suffix. func HasSuffix(s, suffix string) bool { - return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix + return stringslite.HasSuffix(s, suffix) } // Map returns a copy of the string s with all its characters modified @@ -530,6 +529,27 @@ func Map(mapping func(rune) rune, s string) string { return b.String() } +// According to static analysis, spaces, dashes, zeros, equals, and tabs +// are the most commonly repeated string literal, +// often used for display on fixed-width terminal windows. +// Pre-declare constants for these for O(1) repetition in the common-case. +const ( + repeatedSpaces = "" + + " " + + " " + repeatedDashes = "" + + "----------------------------------------------------------------" + + "----------------------------------------------------------------" + repeatedZeroes = "" + + "0000000000000000000000000000000000000000000000000000000000000000" + repeatedEquals = "" + + "================================================================" + + "================================================================" + repeatedTabs = "" + + "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" + + "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t" +) + // Repeat returns a new string consisting of count copies of the string s. // // It panics if count is negative or if the result of (len(s) * count) @@ -548,7 +568,7 @@ func Repeat(s string, count int) string { if count < 0 { panic("strings: negative Repeat count") } - if len(s) >= maxInt/count { + if len(s) > maxInt/count { panic("strings: Repeat output length overflow") } n := len(s) * count @@ -557,6 +577,23 @@ func Repeat(s string, count int) string { return "" } + // Optimize for commonly repeated strings of relatively short length. + switch s[0] { + case ' ', '-', '0', '=', '\t': + switch { + case n <= len(repeatedSpaces) && HasPrefix(repeatedSpaces, s): + return repeatedSpaces[:n] + case n <= len(repeatedDashes) && HasPrefix(repeatedDashes, s): + return repeatedDashes[:n] + case n <= len(repeatedZeroes) && HasPrefix(repeatedZeroes, s): + return repeatedZeroes[:n] + case n <= len(repeatedEquals) && HasPrefix(repeatedEquals, s): + return repeatedEquals[:n] + case n <= len(repeatedTabs) && HasPrefix(repeatedTabs, s): + return repeatedTabs[:n] + } + } + // Past a certain chunk size it is counterproductive to use // larger chunks as the source of the write, as when the source // is too large we are basically just thrashing the CPU D-cache. @@ -1036,19 +1073,13 @@ func TrimSpace(s string) string { // TrimPrefix returns s without the provided leading prefix string. // If s doesn't start with prefix, s is returned unchanged. func TrimPrefix(s, prefix string) string { - if HasPrefix(s, prefix) { - return s[len(prefix):] - } - return s + return stringslite.TrimPrefix(s, prefix) } // TrimSuffix returns s without the provided trailing suffix string. // If s doesn't end with suffix, s is returned unchanged. func TrimSuffix(s, suffix string) string { - if HasSuffix(s, suffix) { - return s[:len(s)-len(suffix)] - } - return s + return stringslite.TrimSuffix(s, suffix) } // Replace returns a copy of the string s with the first n @@ -1187,83 +1218,7 @@ hasUnicode: // Index returns the index of the first instance of substr in s, or -1 if substr is not present in s. func Index(s, substr string) int { - n := len(substr) - switch { - case n == 0: - return 0 - case n == 1: - return IndexByte(s, substr[0]) - case n == len(s): - if substr == s { - return 0 - } - return -1 - case n > len(s): - return -1 - case n <= bytealg.MaxLen: - // Use brute force when s and substr both are small - if len(s) <= bytealg.MaxBruteForce { - return bytealg.IndexString(s, substr) - } - c0 := substr[0] - c1 := substr[1] - i := 0 - t := len(s) - n + 1 - fails := 0 - for i < t { - if s[i] != c0 { - // IndexByte is faster than bytealg.IndexString, so use it as long as - // we're not getting lots of false positives. - o := IndexByte(s[i+1:t], c0) - if o < 0 { - return -1 - } - i += o + 1 - } - if s[i+1] == c1 && s[i:i+n] == substr { - return i - } - fails++ - i++ - // Switch to bytealg.IndexString when IndexByte produces too many false positives. - if fails > bytealg.Cutover(i) { - r := bytealg.IndexString(s[i:], substr) - if r >= 0 { - return r + i - } - return -1 - } - } - return -1 - } - c0 := substr[0] - c1 := substr[1] - i := 0 - t := len(s) - n + 1 - fails := 0 - for i < t { - if s[i] != c0 { - o := IndexByte(s[i+1:t], c0) - if o < 0 { - return -1 - } - i += o + 1 - } - if s[i+1] == c1 && s[i:i+n] == substr { - return i - } - i++ - fails++ - if fails >= 4+i>>4 && i < t { - // See comment in ../bytes/bytes.go. - j := bytealg.IndexRabinKarp(s[i:], substr) - if j < 0 { - return -1 - } - return i + j - } - } - return -1 + return stringslite.Index(s, substr) } // Cut slices s around the first instance of sep, @@ -1271,10 +1226,7 @@ func Index(s, substr string) int { // The found result reports whether sep appears in s. // If sep does not appear in s, cut returns s, "", false. func Cut(s, sep string) (before, after string, found bool) { - if i := Index(s, sep); i >= 0 { - return s[:i], s[i+len(sep):], true - } - return s, "", false + return stringslite.Cut(s, sep) } // CutPrefix returns s without the provided leading prefix string @@ -1282,10 +1234,7 @@ func Cut(s, sep string) (before, after string, found bool) { // If s doesn't start with prefix, CutPrefix returns s, false. // If prefix is the empty string, CutPrefix returns s, true. func CutPrefix(s, prefix string) (after string, found bool) { - if !HasPrefix(s, prefix) { - return s, false - } - return s[len(prefix):], true + return stringslite.CutPrefix(s, prefix) } // CutSuffix returns s without the provided ending suffix string @@ -1293,8 +1242,5 @@ func CutPrefix(s, prefix string) (after string, found bool) { // If s doesn't end with suffix, CutSuffix returns s, false. // If suffix is the empty string, CutSuffix returns s, true. func CutSuffix(s, suffix string) (before string, found bool) { - if !HasSuffix(s, suffix) { - return s, false - } - return s[:len(s)-len(suffix)], true + return stringslite.CutSuffix(s, suffix) } diff --git a/contrib/go/_std_1.22/src/strings/ya.make b/contrib/go/_std_1.23/src/strings/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/strings/ya.make rename to contrib/go/_std_1.23/src/strings/ya.make diff --git a/contrib/go/_std_1.23/src/sync/atomic/asm.s b/contrib/go/_std_1.23/src/sync/atomic/asm.s new file mode 100644 index 000000000000..c46869ede7f4 --- /dev/null +++ b/contrib/go/_std_1.23/src/sync/atomic/asm.s @@ -0,0 +1,115 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !race + +#include "textflag.h" + +TEXT ·SwapInt32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xchg(SB) + +TEXT ·SwapUint32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xchg(SB) + +TEXT ·SwapInt64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xchg64(SB) + +TEXT ·SwapUint64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xchg64(SB) + +TEXT ·SwapUintptr(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xchguintptr(SB) + +TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Cas(SB) + +TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Cas(SB) + +TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Casuintptr(SB) + +TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Cas64(SB) + +TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Cas64(SB) + +TEXT ·AddInt32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xadd(SB) + +TEXT ·AddUint32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xadd(SB) + +TEXT ·AddUintptr(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xadduintptr(SB) + +TEXT ·AddInt64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xadd64(SB) + +TEXT ·AddUint64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Xadd64(SB) + +TEXT ·LoadInt32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Load(SB) + +TEXT ·LoadUint32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Load(SB) + +TEXT ·LoadInt64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Load64(SB) + +TEXT ·LoadUint64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Load64(SB) + +TEXT ·LoadUintptr(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Loaduintptr(SB) + +TEXT ·LoadPointer(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Loadp(SB) + +TEXT ·StoreInt32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Store(SB) + +TEXT ·StoreUint32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Store(SB) + +TEXT ·StoreInt64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Store64(SB) + +TEXT ·StoreUint64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Store64(SB) + +TEXT ·StoreUintptr(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Storeuintptr(SB) + +TEXT ·AndInt32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·And32(SB) + +TEXT ·AndUint32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·And32(SB) + +TEXT ·AndUintptr(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Anduintptr(SB) + +TEXT ·AndInt64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·And64(SB) + +TEXT ·AndUint64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·And64(SB) + +TEXT ·OrInt32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Or32(SB) + +TEXT ·OrUint32(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Or32(SB) + +TEXT ·OrUintptr(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Oruintptr(SB) + +TEXT ·OrInt64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Or64(SB) + +TEXT ·OrUint64(SB),NOSPLIT,$0 + JMP internal∕runtime∕atomic·Or64(SB) diff --git a/contrib/go/_std_1.22/src/sync/atomic/doc.go b/contrib/go/_std_1.23/src/sync/atomic/doc.go similarity index 76% rename from contrib/go/_std_1.22/src/sync/atomic/doc.go rename to contrib/go/_std_1.23/src/sync/atomic/doc.go index c22d1159affa..7f9d64b74e62 100644 --- a/contrib/go/_std_1.22/src/sync/atomic/doc.go +++ b/contrib/go/_std_1.23/src/sync/atomic/doc.go @@ -37,13 +37,15 @@ // functions, are the atomic equivalents of "return *addr" and // "*addr = val". // -// In the terminology of the Go memory model, if the effect of +// In the terminology of [the Go memory model], if the effect of // an atomic operation A is observed by atomic operation B, // then A “synchronizes before” B. // Additionally, all the atomic operations executed in a program // behave as though executed in some sequentially consistent order. // This definition provides the same semantics as // C++'s sequentially consistent atomics and Java's volatile variables. +// +// [the Go memory model]: https://go.dev/ref/mem package atomic import ( @@ -139,6 +141,56 @@ func AddUint64(addr *uint64, delta uint64) (new uint64) // Consider using the more ergonomic and less error-prone [Uintptr.Add] instead. func AddUintptr(addr *uintptr, delta uintptr) (new uintptr) +// AndInt32 atomically performs a bitwise AND operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Int32.And] instead. +func AndInt32(addr *int32, mask int32) (old int32) + +// AndUint32 atomically performs a bitwise AND operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Uint32.And] instead. +func AndUint32(addr *uint32, mask uint32) (old uint32) + +// AndInt64 atomically performs a bitwise AND operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Int64.And] instead. +func AndInt64(addr *int64, mask int64) (old int64) + +// AndUint64 atomically performs a bitwise AND operation on *addr using the bitmask provided as mask +// and returns the old. +// Consider using the more ergonomic and less error-prone [Uint64.And] instead. +func AndUint64(addr *uint64, mask uint64) (old uint64) + +// AndUintptr atomically performs a bitwise AND operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Uintptr.And] instead. +func AndUintptr(addr *uintptr, mask uintptr) (old uintptr) + +// OrInt32 atomically performs a bitwise OR operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Int32.Or] instead. +func OrInt32(addr *int32, mask int32) (old int32) + +// OrUint32 atomically performs a bitwise OR operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Uint32.Or] instead. +func OrUint32(addr *uint32, mask uint32) (old uint32) + +// OrInt64 atomically performs a bitwise OR operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Int64.Or] instead. +func OrInt64(addr *int64, mask int64) (old int64) + +// OrUint64 atomically performs a bitwise OR operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Uint64.Or] instead. +func OrUint64(addr *uint64, mask uint64) (old uint64) + +// OrUintptr atomically performs a bitwise OR operation on *addr using the bitmask provided as mask +// and returns the old value. +// Consider using the more ergonomic and less error-prone [Uintptr.Or] instead. +func OrUintptr(addr *uintptr, mask uintptr) (old uintptr) + // LoadInt32 atomically loads *addr. // Consider using the more ergonomic and less error-prone [Int32.Load] instead. func LoadInt32(addr *int32) (val int32) diff --git a/contrib/go/_std_1.22/src/sync/atomic/race.s b/contrib/go/_std_1.23/src/sync/atomic/race.s similarity index 100% rename from contrib/go/_std_1.22/src/sync/atomic/race.s rename to contrib/go/_std_1.23/src/sync/atomic/race.s diff --git a/contrib/go/_std_1.22/src/sync/atomic/type.go b/contrib/go/_std_1.23/src/sync/atomic/type.go similarity index 76% rename from contrib/go/_std_1.22/src/sync/atomic/type.go rename to contrib/go/_std_1.23/src/sync/atomic/type.go index 179fa93092be..f487cb9c5f7e 100644 --- a/contrib/go/_std_1.22/src/sync/atomic/type.go +++ b/contrib/go/_std_1.23/src/sync/atomic/type.go @@ -87,6 +87,14 @@ func (x *Int32) CompareAndSwap(old, new int32) (swapped bool) { // Add atomically adds delta to x and returns the new value. func (x *Int32) Add(delta int32) (new int32) { return AddInt32(&x.v, delta) } +// And atomically performs a bitwise AND operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Int32) And(mask int32) (old int32) { return AndInt32(&x.v, mask) } + +// Or atomically performs a bitwise OR operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Int32) Or(mask int32) (old int32) { return OrInt32(&x.v, mask) } + // An Int64 is an atomic int64. The zero value is zero. type Int64 struct { _ noCopy @@ -111,6 +119,14 @@ func (x *Int64) CompareAndSwap(old, new int64) (swapped bool) { // Add atomically adds delta to x and returns the new value. func (x *Int64) Add(delta int64) (new int64) { return AddInt64(&x.v, delta) } +// And atomically performs a bitwise AND operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Int64) And(mask int64) (old int64) { return AndInt64(&x.v, mask) } + +// Or atomically performs a bitwise OR operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Int64) Or(mask int64) (old int64) { return OrInt64(&x.v, mask) } + // A Uint32 is an atomic uint32. The zero value is zero. type Uint32 struct { _ noCopy @@ -134,6 +150,14 @@ func (x *Uint32) CompareAndSwap(old, new uint32) (swapped bool) { // Add atomically adds delta to x and returns the new value. func (x *Uint32) Add(delta uint32) (new uint32) { return AddUint32(&x.v, delta) } +// And atomically performs a bitwise AND operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Uint32) And(mask uint32) (old uint32) { return AndUint32(&x.v, mask) } + +// Or atomically performs a bitwise OR operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Uint32) Or(mask uint32) (old uint32) { return OrUint32(&x.v, mask) } + // A Uint64 is an atomic uint64. The zero value is zero. type Uint64 struct { _ noCopy @@ -158,6 +182,14 @@ func (x *Uint64) CompareAndSwap(old, new uint64) (swapped bool) { // Add atomically adds delta to x and returns the new value. func (x *Uint64) Add(delta uint64) (new uint64) { return AddUint64(&x.v, delta) } +// And atomically performs a bitwise AND operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Uint64) And(mask uint64) (old uint64) { return AndUint64(&x.v, mask) } + +// Or atomically performs a bitwise OR operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Uint64) Or(mask uint64) (old uint64) { return OrUint64(&x.v, mask) } + // A Uintptr is an atomic uintptr. The zero value is zero. type Uintptr struct { _ noCopy @@ -181,6 +213,14 @@ func (x *Uintptr) CompareAndSwap(old, new uintptr) (swapped bool) { // Add atomically adds delta to x and returns the new value. func (x *Uintptr) Add(delta uintptr) (new uintptr) { return AddUintptr(&x.v, delta) } +// And atomically performs a bitwise AND operation on x using the bitmask +// provided as mask and returns the old value. +func (x *Uintptr) And(mask uintptr) (old uintptr) { return AndUintptr(&x.v, mask) } + +// Or atomically performs a bitwise OR operation on x using the bitmask +// provided as mask and returns the updated value after the OR operation. +func (x *Uintptr) Or(mask uintptr) (old uintptr) { return OrUintptr(&x.v, mask) } + // noCopy may be added to structs which must not be copied // after the first use. // diff --git a/contrib/go/_std_1.22/src/sync/atomic/value.go b/contrib/go/_std_1.23/src/sync/atomic/value.go similarity index 96% rename from contrib/go/_std_1.22/src/sync/atomic/value.go rename to contrib/go/_std_1.23/src/sync/atomic/value.go index a57b08a6b877..0cfc5f9496c8 100644 --- a/contrib/go/_std_1.22/src/sync/atomic/value.go +++ b/contrib/go/_std_1.23/src/sync/atomic/value.go @@ -9,8 +9,8 @@ import ( ) // A Value provides an atomic load and store of a consistently typed value. -// The zero value for a Value returns nil from Load. -// Once Store has been called, a Value must not be copied. +// The zero value for a Value returns nil from [Value.Load]. +// Once [Value.Store] has been called, a Value must not be copied. // // A Value must not be copied after first use. type Value struct { @@ -41,7 +41,7 @@ func (v *Value) Load() (val any) { var firstStoreInProgress byte -// Store sets the value of the Value v to val. +// Store sets the value of the [Value] v to val. // All calls to Store for a given Value must use values of the same concrete type. // Store of an inconsistent type panics, as does Store(nil). func (v *Value) Store(val any) { @@ -127,7 +127,7 @@ func (v *Value) Swap(new any) (old any) { } } -// CompareAndSwap executes the compare-and-swap operation for the Value. +// CompareAndSwap executes the compare-and-swap operation for the [Value]. // // All calls to CompareAndSwap for a given Value must use values of the same // concrete type. CompareAndSwap of an inconsistent type panics, as does diff --git a/contrib/go/_std_1.22/src/sync/atomic/ya.make b/contrib/go/_std_1.23/src/sync/atomic/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/sync/atomic/ya.make rename to contrib/go/_std_1.23/src/sync/atomic/ya.make diff --git a/contrib/go/_std_1.22/src/sync/cond.go b/contrib/go/_std_1.23/src/sync/cond.go similarity index 88% rename from contrib/go/_std_1.22/src/sync/cond.go rename to contrib/go/_std_1.23/src/sync/cond.go index 7ef3188a1ee8..2c53b6801a15 100644 --- a/contrib/go/_std_1.22/src/sync/cond.go +++ b/contrib/go/_std_1.23/src/sync/cond.go @@ -13,24 +13,25 @@ import ( // for goroutines waiting for or announcing the occurrence // of an event. // -// Each Cond has an associated Locker L (often a *Mutex or *RWMutex), +// Each Cond has an associated Locker L (often a [*Mutex] or [*RWMutex]), // which must be held when changing the condition and -// when calling the Wait method. +// when calling the [Cond.Wait] method. // // A Cond must not be copied after first use. // -// In the terminology of the Go memory model, Cond arranges that -// a call to Broadcast or Signal “synchronizes before” any Wait call +// In the terminology of [the Go memory model], Cond arranges that +// a call to [Cond.Broadcast] or [Cond.Signal] “synchronizes before” any Wait call // that it unblocks. // // For many simple use cases, users will be better off using channels than a // Cond (Broadcast corresponds to closing a channel, and Signal corresponds to // sending on a channel). // -// For more on replacements for sync.Cond, see [Roberto Clapis's series on +// For more on replacements for [sync.Cond], see [Roberto Clapis's series on // advanced concurrency patterns], as well as [Bryan Mills's talk on concurrency // patterns]. // +// [the Go memory model]: https://go.dev/ref/mem // [Roberto Clapis's series on advanced concurrency patterns]: https://blogtitle.github.io/categories/concurrency/ // [Bryan Mills's talk on concurrency patterns]: https://drive.google.com/file/d/1nPdvhB0PutEJzdCq5ms6UI58dp50fcAN/view type Cond struct { @@ -51,7 +52,7 @@ func NewCond(l Locker) *Cond { // Wait atomically unlocks c.L and suspends execution // of the calling goroutine. After later resuming execution, // Wait locks c.L before returning. Unlike in other systems, -// Wait cannot return unless awoken by Broadcast or Signal. +// Wait cannot return unless awoken by [Cond.Broadcast] or [Cond.Signal]. // // Because c.L is not locked while Wait is waiting, the caller // typically cannot assume that the condition is true when diff --git a/contrib/go/_std_1.22/src/sync/map.go b/contrib/go/_std_1.23/src/sync/map.go similarity index 92% rename from contrib/go/_std_1.22/src/sync/map.go rename to contrib/go/_std_1.23/src/sync/map.go index 7a9eebdce39d..33bc8141abd4 100644 --- a/contrib/go/_std_1.22/src/sync/map.go +++ b/contrib/go/_std_1.23/src/sync/map.go @@ -20,18 +20,21 @@ import ( // key is only ever written once but read many times, as in caches that only grow, // or (2) when multiple goroutines read, write, and overwrite entries for disjoint // sets of keys. In these two cases, use of a Map may significantly reduce lock -// contention compared to a Go map paired with a separate Mutex or RWMutex. +// contention compared to a Go map paired with a separate [Mutex] or [RWMutex]. // // The zero Map is empty and ready for use. A Map must not be copied after first use. // -// In the terminology of the Go memory model, Map arranges that a write operation +// In the terminology of [the Go memory model], Map arranges that a write operation // “synchronizes before” any read operation that observes the effect of the write, where // read and write operations are defined as follows. -// Load, LoadAndDelete, LoadOrStore, Swap, CompareAndSwap, and CompareAndDelete -// are read operations; Delete, LoadAndDelete, Store, and Swap are write operations; -// LoadOrStore is a write operation when it returns loaded set to false; -// CompareAndSwap is a write operation when it returns swapped set to true; -// and CompareAndDelete is a write operation when it returns deleted set to true. +// [Map.Load], [Map.LoadAndDelete], [Map.LoadOrStore], [Map.Swap], [Map.CompareAndSwap], +// and [Map.CompareAndDelete] are read operations; +// [Map.Delete], [Map.LoadAndDelete], [Map.Store], and [Map.Swap] are write operations; +// [Map.LoadOrStore] is a write operation when it returns loaded set to false; +// [Map.CompareAndSwap] is a write operation when it returns swapped set to true; +// and [Map.CompareAndDelete] is a write operation when it returns deleted set to true. +// +// [the Go memory model]: https://go.dev/ref/mem type Map struct { mu Mutex @@ -155,6 +158,27 @@ func (m *Map) Store(key, value any) { _, _ = m.Swap(key, value) } +// Clear deletes all the entries, resulting in an empty Map. +func (m *Map) Clear() { + read := m.loadReadOnly() + if len(read.m) == 0 && !read.amended { + // Avoid allocating a new readOnly when the map is already clear. + return + } + + m.mu.Lock() + defer m.mu.Unlock() + + read = m.loadReadOnly() + if len(read.m) > 0 || read.amended { + m.read.Store(&readOnly{}) + } + + clear(m.dirty) + // Don't immediately promote the newly-cleared dirty map on the next operation. + m.misses = 0 +} + // tryCompareAndSwap compare the entry with the given old value and swaps // it with a new value if the entry is equal to the old value, and the entry // has not been expunged. @@ -371,7 +395,7 @@ func (m *Map) Swap(key, value any) (previous any, loaded bool) { // CompareAndSwap swaps the old and new values for key // if the value stored in the map is equal to old. // The old value must be of a comparable type. -func (m *Map) CompareAndSwap(key, old, new any) bool { +func (m *Map) CompareAndSwap(key, old, new any) (swapped bool) { read := m.loadReadOnly() if e, ok := read.m[key]; ok { return e.tryCompareAndSwap(old, new) @@ -382,7 +406,7 @@ func (m *Map) CompareAndSwap(key, old, new any) bool { m.mu.Lock() defer m.mu.Unlock() read = m.loadReadOnly() - swapped := false + swapped = false if e, ok := read.m[key]; ok { swapped = e.tryCompareAndSwap(old, new) } else if e, ok := m.dirty[key]; ok { diff --git a/contrib/go/_std_1.22/src/sync/mutex.go b/contrib/go/_std_1.23/src/sync/mutex.go similarity index 95% rename from contrib/go/_std_1.22/src/sync/mutex.go rename to contrib/go/_std_1.23/src/sync/mutex.go index 2ea024e58564..e4ed47c75c2a 100644 --- a/contrib/go/_std_1.22/src/sync/mutex.go +++ b/contrib/go/_std_1.23/src/sync/mutex.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // Package sync provides basic synchronization primitives such as mutual -// exclusion locks. Other than the Once and WaitGroup types, most are intended +// exclusion locks. Other than the [Once] and [WaitGroup] types, most are intended // for use by low-level library routines. Higher-level synchronization is // better done via channels and communication. // @@ -25,12 +25,14 @@ func fatal(string) // // A Mutex must not be copied after first use. // -// In the terminology of the Go memory model, -// the n'th call to Unlock “synchronizes before” the m'th call to Lock +// In the terminology of [the Go memory model], +// the n'th call to [Mutex.Unlock] “synchronizes before” the m'th call to [Mutex.Lock] // for any n < m. -// A successful call to TryLock is equivalent to a call to Lock. +// A successful call to [Mutex.TryLock] is equivalent to a call to Lock. // A failed call to TryLock does not establish any “synchronizes before” // relation at all. +// +// [the Go memory model]: https://go.dev/ref/mem type Mutex struct { state int32 sema uint32 @@ -206,7 +208,7 @@ func (m *Mutex) lockSlow() { // Unlock unlocks m. // It is a run-time error if m is not locked on entry to Unlock. // -// A locked Mutex is not associated with a particular goroutine. +// A locked [Mutex] is not associated with a particular goroutine. // It is allowed for one goroutine to lock a Mutex and then // arrange for another goroutine to unlock it. func (m *Mutex) Unlock() { diff --git a/contrib/go/_std_1.22/src/sync/once.go b/contrib/go/_std_1.23/src/sync/once.go similarity index 93% rename from contrib/go/_std_1.22/src/sync/once.go rename to contrib/go/_std_1.23/src/sync/once.go index 3f58707e1cfc..168c7bbdd38f 100644 --- a/contrib/go/_std_1.22/src/sync/once.go +++ b/contrib/go/_std_1.23/src/sync/once.go @@ -12,9 +12,11 @@ import ( // // A Once must not be copied after first use. // -// In the terminology of the Go memory model, +// In the terminology of [the Go memory model], // the return from f “synchronizes before” // the return from any call of once.Do(f). +// +// [the Go memory model]: https://go.dev/ref/mem type Once struct { // done indicates whether the action has been performed. // It is first in the struct because it is used in the hot path. @@ -26,7 +28,7 @@ type Once struct { } // Do calls the function f if and only if Do is being called for the -// first time for this instance of Once. In other words, given +// first time for this instance of [Once]. In other words, given // // var once Once // diff --git a/contrib/go/_std_1.22/src/sync/oncefunc.go b/contrib/go/_std_1.23/src/sync/oncefunc.go similarity index 100% rename from contrib/go/_std_1.22/src/sync/oncefunc.go rename to contrib/go/_std_1.23/src/sync/oncefunc.go diff --git a/contrib/go/_std_1.22/src/sync/pool.go b/contrib/go/_std_1.23/src/sync/pool.go similarity index 91% rename from contrib/go/_std_1.22/src/sync/pool.go rename to contrib/go/_std_1.23/src/sync/pool.go index 3359aba57b31..0fa8f8cdaa02 100644 --- a/contrib/go/_std_1.22/src/sync/pool.go +++ b/contrib/go/_std_1.23/src/sync/pool.go @@ -42,10 +42,12 @@ import ( // // A Pool must not be copied after first use. // -// In the terminology of the Go memory model, a call to Put(x) “synchronizes before” -// a call to Get returning that same value x. +// In the terminology of [the Go memory model], a call to Put(x) “synchronizes before” +// a call to [Pool.Get] returning that same value x. // Similarly, a call to New returning x “synchronizes before” // a call to Get returning that same value x. +// +// [the Go memory model]: https://go.dev/ref/mem type Pool struct { noCopy noCopy @@ -76,6 +78,7 @@ type poolLocal struct { } // from runtime +// //go:linkname runtime_randn runtime.randn func runtime_randn(n uint32) uint32 @@ -117,10 +120,10 @@ func (p *Pool) Put(x any) { } } -// Get selects an arbitrary item from the Pool, removes it from the +// Get selects an arbitrary item from the [Pool], removes it from the // Pool, and returns it to the caller. // Get may choose to ignore the pool and treat it as empty. -// Callers should not assume any relation between values passed to Put and +// Callers should not assume any relation between values passed to [Pool.Put] and // the values returned by Get. // // If Get would otherwise return nil and p.New is non-nil, Get returns @@ -241,6 +244,16 @@ func (p *Pool) pinSlow() (*poolLocal, int) { return &local[pid], pid } +// poolCleanup should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/bytedance/gopkg +// - github.com/songzhibin97/gkit +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname poolCleanup func poolCleanup() { // This function is called with the world stopped, at the beginning of a garbage collection. // It must not allocate and probably should not call any runtime functions. @@ -294,12 +307,12 @@ func runtime_registerPoolCleanup(cleanup func()) func runtime_procPin() int func runtime_procUnpin() -// The below are implemented in runtime/internal/atomic and the +// The below are implemented in internal/runtime/atomic and the // compiler also knows to intrinsify the symbol we linkname into this // package. -//go:linkname runtime_LoadAcquintptr runtime/internal/atomic.LoadAcquintptr +//go:linkname runtime_LoadAcquintptr internal/runtime/atomic.LoadAcquintptr func runtime_LoadAcquintptr(ptr *uintptr) uintptr -//go:linkname runtime_StoreReluintptr runtime/internal/atomic.StoreReluintptr +//go:linkname runtime_StoreReluintptr internal/runtime/atomic.StoreReluintptr func runtime_StoreReluintptr(ptr *uintptr, val uintptr) uintptr diff --git a/contrib/go/_std_1.22/src/sync/poolqueue.go b/contrib/go/_std_1.23/src/sync/poolqueue.go similarity index 92% rename from contrib/go/_std_1.22/src/sync/poolqueue.go rename to contrib/go/_std_1.23/src/sync/poolqueue.go index 5c640f988a39..e9593f8c4442 100644 --- a/contrib/go/_std_1.22/src/sync/poolqueue.go +++ b/contrib/go/_std_1.23/src/sync/poolqueue.go @@ -198,7 +198,7 @@ type poolChain struct { // tail is the poolDequeue to popTail from. This is accessed // by consumers, so reads and writes must be atomic. - tail *poolChainElt + tail atomic.Pointer[poolChainElt] } type poolChainElt struct { @@ -214,15 +214,7 @@ type poolChainElt struct { // prev is written atomically by the consumer and read // atomically by the producer. It only transitions from // non-nil to nil. - next, prev *poolChainElt -} - -func storePoolChainElt(pp **poolChainElt, v *poolChainElt) { - atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(pp)), unsafe.Pointer(v)) -} - -func loadPoolChainElt(pp **poolChainElt) *poolChainElt { - return (*poolChainElt)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(pp)))) + next, prev atomic.Pointer[poolChainElt] } func (c *poolChain) pushHead(val any) { @@ -233,7 +225,7 @@ func (c *poolChain) pushHead(val any) { d = new(poolChainElt) d.vals = make([]eface, initSize) c.head = d - storePoolChainElt(&c.tail, d) + c.tail.Store(d) } if d.pushHead(val) { @@ -248,10 +240,11 @@ func (c *poolChain) pushHead(val any) { newSize = dequeueLimit } - d2 := &poolChainElt{prev: d} + d2 := &poolChainElt{} + d2.prev.Store(d) d2.vals = make([]eface, newSize) c.head = d2 - storePoolChainElt(&d.next, d2) + d.next.Store(d2) d2.pushHead(val) } @@ -263,13 +256,13 @@ func (c *poolChain) popHead() (any, bool) { } // There may still be unconsumed elements in the // previous dequeue, so try backing up. - d = loadPoolChainElt(&d.prev) + d = d.prev.Load() } return nil, false } func (c *poolChain) popTail() (any, bool) { - d := loadPoolChainElt(&c.tail) + d := c.tail.Load() if d == nil { return nil, false } @@ -281,7 +274,7 @@ func (c *poolChain) popTail() (any, bool) { // the pop and the pop fails, then d is permanently // empty, which is the only condition under which it's // safe to drop d from the chain. - d2 := loadPoolChainElt(&d.next) + d2 := d.next.Load() if val, ok := d.popTail(); ok { return val, ok @@ -297,12 +290,12 @@ func (c *poolChain) popTail() (any, bool) { // to the next dequeue. Try to drop it from the chain // so the next pop doesn't have to look at the empty // dequeue again. - if atomic.CompareAndSwapPointer((*unsafe.Pointer)(unsafe.Pointer(&c.tail)), unsafe.Pointer(d), unsafe.Pointer(d2)) { + if c.tail.CompareAndSwap(d, d2) { // We won the race. Clear the prev pointer so // the garbage collector can collect the empty // dequeue and so popHead doesn't back up // further than necessary. - storePoolChainElt(&d2.prev, nil) + d2.prev.Store(nil) } d = d2 } diff --git a/contrib/go/_std_1.22/src/sync/runtime.go b/contrib/go/_std_1.23/src/sync/runtime.go similarity index 100% rename from contrib/go/_std_1.22/src/sync/runtime.go rename to contrib/go/_std_1.23/src/sync/runtime.go diff --git a/contrib/go/_std_1.22/src/sync/runtime2.go b/contrib/go/_std_1.23/src/sync/runtime2.go similarity index 100% rename from contrib/go/_std_1.22/src/sync/runtime2.go rename to contrib/go/_std_1.23/src/sync/runtime2.go diff --git a/contrib/go/_std_1.22/src/sync/runtime2_lockrank.go b/contrib/go/_std_1.23/src/sync/runtime2_lockrank.go similarity index 100% rename from contrib/go/_std_1.22/src/sync/runtime2_lockrank.go rename to contrib/go/_std_1.23/src/sync/runtime2_lockrank.go diff --git a/contrib/go/_std_1.22/src/sync/rwmutex.go b/contrib/go/_std_1.23/src/sync/rwmutex.go similarity index 87% rename from contrib/go/_std_1.22/src/sync/rwmutex.go rename to contrib/go/_std_1.23/src/sync/rwmutex.go index f445b66fd7b0..1d5b8fde4a8c 100644 --- a/contrib/go/_std_1.22/src/sync/rwmutex.go +++ b/contrib/go/_std_1.23/src/sync/rwmutex.go @@ -19,19 +19,21 @@ import ( // // A RWMutex must not be copied after first use. // -// If any goroutine calls Lock while the lock is already held by -// one or more readers, concurrent calls to RLock will block until +// If any goroutine calls [RWMutex.Lock] while the lock is already held by +// one or more readers, concurrent calls to [RWMutex.RLock] will block until // the writer has acquired (and released) the lock, to ensure that // the lock eventually becomes available to the writer. // Note that this prohibits recursive read-locking. // -// In the terminology of the Go memory model, -// the n'th call to Unlock “synchronizes before” the m'th call to Lock -// for any n < m, just as for Mutex. +// In the terminology of [the Go memory model], +// the n'th call to [RWMutex.Unlock] “synchronizes before” the m'th call to Lock +// for any n < m, just as for [Mutex]. // For any call to RLock, there exists an n such that // the n'th call to Unlock “synchronizes before” that call to RLock, -// and the corresponding call to RUnlock “synchronizes before” +// and the corresponding call to [RWMutex.RUnlock] “synchronizes before” // the n+1'th call to Lock. +// +// [the Go memory model]: https://go.dev/ref/mem type RWMutex struct { w Mutex // held if there are pending writers writerSem uint32 // semaphore for writers to wait for completing readers @@ -59,7 +61,7 @@ const rwmutexMaxReaders = 1 << 30 // // It should not be used for recursive read locking; a blocked Lock // call excludes new readers from acquiring the lock. See the -// documentation on the RWMutex type. +// documentation on the [RWMutex] type. func (rw *RWMutex) RLock() { if race.Enabled { _ = rw.w.state @@ -103,7 +105,7 @@ func (rw *RWMutex) TryRLock() bool { } } -// RUnlock undoes a single RLock call; +// RUnlock undoes a single [RWMutex.RLock] call; // it does not affect other simultaneous readers. // It is a run-time error if rw is not locked for reading // on entry to RUnlock. @@ -191,9 +193,9 @@ func (rw *RWMutex) TryLock() bool { // Unlock unlocks rw for writing. It is a run-time error if rw is // not locked for writing on entry to Unlock. // -// As with Mutexes, a locked RWMutex is not associated with a particular -// goroutine. One goroutine may RLock (Lock) a RWMutex and then -// arrange for another goroutine to RUnlock (Unlock) it. +// As with Mutexes, a locked [RWMutex] is not associated with a particular +// goroutine. One goroutine may [RWMutex.RLock] ([RWMutex.Lock]) a RWMutex and then +// arrange for another goroutine to [RWMutex.RUnlock] ([RWMutex.Unlock]) it. func (rw *RWMutex) Unlock() { if race.Enabled { _ = rw.w.state @@ -231,8 +233,8 @@ func syscall_hasWaitingReaders(rw *RWMutex) bool { return r < 0 && r+rwmutexMaxReaders > 0 } -// RLocker returns a Locker interface that implements -// the Lock and Unlock methods by calling rw.RLock and rw.RUnlock. +// RLocker returns a [Locker] interface that implements +// the [Locker.Lock] and [Locker.Unlock] methods by calling rw.RLock and rw.RUnlock. func (rw *RWMutex) RLocker() Locker { return (*rlocker)(rw) } diff --git a/contrib/go/_std_1.22/src/sync/waitgroup.go b/contrib/go/_std_1.23/src/sync/waitgroup.go similarity index 85% rename from contrib/go/_std_1.22/src/sync/waitgroup.go rename to contrib/go/_std_1.23/src/sync/waitgroup.go index be21417f9c22..872d6d87c0dd 100644 --- a/contrib/go/_std_1.22/src/sync/waitgroup.go +++ b/contrib/go/_std_1.23/src/sync/waitgroup.go @@ -11,15 +11,17 @@ import ( ) // A WaitGroup waits for a collection of goroutines to finish. -// The main goroutine calls Add to set the number of +// The main goroutine calls [WaitGroup.Add] to set the number of // goroutines to wait for. Then each of the goroutines -// runs and calls Done when finished. At the same time, -// Wait can be used to block until all goroutines have finished. +// runs and calls [WaitGroup.Done] when finished. At the same time, +// [WaitGroup.Wait] can be used to block until all goroutines have finished. // // A WaitGroup must not be copied after first use. // -// In the terminology of the Go memory model, a call to Done +// In the terminology of [the Go memory model], a call to [WaitGroup.Done] // “synchronizes before” the return of any Wait call that it unblocks. +// +// [the Go memory model]: https://go.dev/ref/mem type WaitGroup struct { noCopy noCopy @@ -27,8 +29,8 @@ type WaitGroup struct { sema uint32 } -// Add adds delta, which may be negative, to the WaitGroup counter. -// If the counter becomes zero, all goroutines blocked on Wait are released. +// Add adds delta, which may be negative, to the [WaitGroup] counter. +// If the counter becomes zero, all goroutines blocked on [WaitGroup.Wait] are released. // If the counter goes negative, Add panics. // // Note that calls with a positive delta that occur when the counter is zero @@ -82,12 +84,12 @@ func (wg *WaitGroup) Add(delta int) { } } -// Done decrements the WaitGroup counter by one. +// Done decrements the [WaitGroup] counter by one. func (wg *WaitGroup) Done() { wg.Add(-1) } -// Wait blocks until the WaitGroup counter is zero. +// Wait blocks until the [WaitGroup] counter is zero. func (wg *WaitGroup) Wait() { if race.Enabled { race.Disable() diff --git a/contrib/go/_std_1.22/src/sync/ya.make b/contrib/go/_std_1.23/src/sync/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/sync/ya.make rename to contrib/go/_std_1.23/src/sync/ya.make diff --git a/contrib/go/_std_1.22/src/syscall/asm9_unix2_amd64.s b/contrib/go/_std_1.23/src/syscall/asm9_unix2_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm9_unix2_amd64.s rename to contrib/go/_std_1.23/src/syscall/asm9_unix2_amd64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_aix_ppc64.s b/contrib/go/_std_1.23/src/syscall/asm_aix_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_aix_ppc64.s rename to contrib/go/_std_1.23/src/syscall/asm_aix_ppc64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_darwin_amd64.s b/contrib/go/_std_1.23/src/syscall/asm_darwin_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_darwin_amd64.s rename to contrib/go/_std_1.23/src/syscall/asm_darwin_amd64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_darwin_arm64.s b/contrib/go/_std_1.23/src/syscall/asm_darwin_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_darwin_arm64.s rename to contrib/go/_std_1.23/src/syscall/asm_darwin_arm64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_freebsd_arm.s b/contrib/go/_std_1.23/src/syscall/asm_freebsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_freebsd_arm.s rename to contrib/go/_std_1.23/src/syscall/asm_freebsd_arm.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_freebsd_arm64.s b/contrib/go/_std_1.23/src/syscall/asm_freebsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_freebsd_arm64.s rename to contrib/go/_std_1.23/src/syscall/asm_freebsd_arm64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_freebsd_riscv64.s b/contrib/go/_std_1.23/src/syscall/asm_freebsd_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_freebsd_riscv64.s rename to contrib/go/_std_1.23/src/syscall/asm_freebsd_riscv64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_386.s b/contrib/go/_std_1.23/src/syscall/asm_linux_386.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_386.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_386.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_amd64.s b/contrib/go/_std_1.23/src/syscall/asm_linux_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_amd64.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_amd64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_arm.s b/contrib/go/_std_1.23/src/syscall/asm_linux_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_arm.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_arm.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_arm64.s b/contrib/go/_std_1.23/src/syscall/asm_linux_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_arm64.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_arm64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_loong64.s b/contrib/go/_std_1.23/src/syscall/asm_linux_loong64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_loong64.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_loong64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_mips64x.s b/contrib/go/_std_1.23/src/syscall/asm_linux_mips64x.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_mips64x.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_mips64x.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_mipsx.s b/contrib/go/_std_1.23/src/syscall/asm_linux_mipsx.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_mipsx.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_mipsx.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_ppc64x.s b/contrib/go/_std_1.23/src/syscall/asm_linux_ppc64x.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_ppc64x.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_ppc64x.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_riscv64.s b/contrib/go/_std_1.23/src/syscall/asm_linux_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_riscv64.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_riscv64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_linux_s390x.s b/contrib/go/_std_1.23/src/syscall/asm_linux_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_linux_s390x.s rename to contrib/go/_std_1.23/src/syscall/asm_linux_s390x.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_netbsd_arm.s b/contrib/go/_std_1.23/src/syscall/asm_netbsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_netbsd_arm.s rename to contrib/go/_std_1.23/src/syscall/asm_netbsd_arm.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_netbsd_arm64.s b/contrib/go/_std_1.23/src/syscall/asm_netbsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_netbsd_arm64.s rename to contrib/go/_std_1.23/src/syscall/asm_netbsd_arm64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_openbsd_386.s b/contrib/go/_std_1.23/src/syscall/asm_openbsd_386.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_openbsd_386.s rename to contrib/go/_std_1.23/src/syscall/asm_openbsd_386.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_openbsd_amd64.s b/contrib/go/_std_1.23/src/syscall/asm_openbsd_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_openbsd_amd64.s rename to contrib/go/_std_1.23/src/syscall/asm_openbsd_amd64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_openbsd_arm.s b/contrib/go/_std_1.23/src/syscall/asm_openbsd_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_openbsd_arm.s rename to contrib/go/_std_1.23/src/syscall/asm_openbsd_arm.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_openbsd_arm64.s b/contrib/go/_std_1.23/src/syscall/asm_openbsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_openbsd_arm64.s rename to contrib/go/_std_1.23/src/syscall/asm_openbsd_arm64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_openbsd_mips64.s b/contrib/go/_std_1.23/src/syscall/asm_openbsd_mips64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_openbsd_mips64.s rename to contrib/go/_std_1.23/src/syscall/asm_openbsd_mips64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_openbsd_ppc64.s b/contrib/go/_std_1.23/src/syscall/asm_openbsd_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_openbsd_ppc64.s rename to contrib/go/_std_1.23/src/syscall/asm_openbsd_ppc64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_openbsd_riscv64.s b/contrib/go/_std_1.23/src/syscall/asm_openbsd_riscv64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_openbsd_riscv64.s rename to contrib/go/_std_1.23/src/syscall/asm_openbsd_riscv64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_plan9_386.s b/contrib/go/_std_1.23/src/syscall/asm_plan9_386.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_plan9_386.s rename to contrib/go/_std_1.23/src/syscall/asm_plan9_386.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_plan9_amd64.s b/contrib/go/_std_1.23/src/syscall/asm_plan9_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_plan9_amd64.s rename to contrib/go/_std_1.23/src/syscall/asm_plan9_amd64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_plan9_arm.s b/contrib/go/_std_1.23/src/syscall/asm_plan9_arm.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_plan9_arm.s rename to contrib/go/_std_1.23/src/syscall/asm_plan9_arm.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_solaris_amd64.s b/contrib/go/_std_1.23/src/syscall/asm_solaris_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_solaris_amd64.s rename to contrib/go/_std_1.23/src/syscall/asm_solaris_amd64.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_unix_386.s b/contrib/go/_std_1.23/src/syscall/asm_unix_386.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_unix_386.s rename to contrib/go/_std_1.23/src/syscall/asm_unix_386.s diff --git a/contrib/go/_std_1.22/src/syscall/asm_unix_amd64.s b/contrib/go/_std_1.23/src/syscall/asm_unix_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/asm_unix_amd64.s rename to contrib/go/_std_1.23/src/syscall/asm_unix_amd64.s diff --git a/contrib/go/_std_1.23/src/syscall/badlinkname_unix.go b/contrib/go/_std_1.23/src/syscall/badlinkname_unix.go new file mode 100644 index 000000000000..4964a830b003 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/badlinkname_unix.go @@ -0,0 +1,22 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris + +package syscall + +import _ "unsafe" + +// As of Go 1.22, the symbols below are found to be pulled via +// linkname in the wild. We provide a push linkname here, to +// keep them accessible with pull linknames. +// This may change in the future. Please do not depend on them +// in new code. + +// golang.org/x/sys linknames getsockopt. +// Do not remove or change the type signature. +// +//go:linkname getsockopt + +//go:linkname setsockopt diff --git a/contrib/go/_std_1.22/src/syscall/bpf_bsd.go b/contrib/go/_std_1.23/src/syscall/bpf_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/bpf_bsd.go rename to contrib/go/_std_1.23/src/syscall/bpf_bsd.go diff --git a/contrib/go/_std_1.22/src/syscall/const_plan9.go b/contrib/go/_std_1.23/src/syscall/const_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/const_plan9.go rename to contrib/go/_std_1.23/src/syscall/const_plan9.go diff --git a/contrib/go/_std_1.22/src/syscall/dir_plan9.go b/contrib/go/_std_1.23/src/syscall/dir_plan9.go similarity index 84% rename from contrib/go/_std_1.22/src/syscall/dir_plan9.go rename to contrib/go/_std_1.23/src/syscall/dir_plan9.go index 1667cbc02f49..34869b620915 100644 --- a/contrib/go/_std_1.22/src/syscall/dir_plan9.go +++ b/contrib/go/_std_1.23/src/syscall/dir_plan9.go @@ -6,7 +6,10 @@ package syscall -import "errors" +import ( + "errors" + "internal/byteorder" +) var ( ErrShortStat = errors.New("stat buffer too short") @@ -54,12 +57,12 @@ var nullDir = Dir{ } // Null assigns special "don't touch" values to members of d to -// avoid modifying them during syscall.Wstat. +// avoid modifying them during [Wstat]. func (d *Dir) Null() { *d = nullDir } // Marshal encodes a 9P stat message corresponding to d into b // -// If there isn't enough space in b for a stat message, ErrShortStat is returned. +// If there isn't enough space in b for a stat message, [ErrShortStat] is returned. func (d *Dir) Marshal(b []byte) (n int, err error) { n = STATFIXLEN + len(d.Name) + len(d.Uid) + len(d.Gid) + len(d.Muid) if n > len(b) { @@ -92,9 +95,9 @@ func (d *Dir) Marshal(b []byte) (n int, err error) { // UnmarshalDir decodes a single 9P stat message from b and returns the resulting Dir. // -// If b is too small to hold a valid stat message, ErrShortStat is returned. +// If b is too small to hold a valid stat message, [ErrShortStat] is returned. // -// If the stat message itself is invalid, ErrBadStat is returned. +// If the stat message itself is invalid, [ErrBadStat] is returned. func UnmarshalDir(b []byte) (*Dir, error) { if len(b) < STATFIXLEN { return nil, ErrShortStat @@ -143,30 +146,19 @@ func pbit8(b []byte, v uint8) []byte { // pbit16 copies the 16-bit number v to b in little-endian order and returns the remaining slice of b. func pbit16(b []byte, v uint16) []byte { - b[0] = byte(v) - b[1] = byte(v >> 8) + byteorder.LePutUint16(b, v) return b[2:] } // pbit32 copies the 32-bit number v to b in little-endian order and returns the remaining slice of b. func pbit32(b []byte, v uint32) []byte { - b[0] = byte(v) - b[1] = byte(v >> 8) - b[2] = byte(v >> 16) - b[3] = byte(v >> 24) + byteorder.LePutUint32(b, v) return b[4:] } // pbit64 copies the 64-bit number v to b in little-endian order and returns the remaining slice of b. func pbit64(b []byte, v uint64) []byte { - b[0] = byte(v) - b[1] = byte(v >> 8) - b[2] = byte(v >> 16) - b[3] = byte(v >> 24) - b[4] = byte(v >> 32) - b[5] = byte(v >> 40) - b[6] = byte(v >> 48) - b[7] = byte(v >> 56) + byteorder.LePutUint64(b, v) return b[8:] } @@ -187,19 +179,17 @@ func gbit8(b []byte) (uint8, []byte) { // //go:nosplit func gbit16(b []byte) (uint16, []byte) { - return uint16(b[0]) | uint16(b[1])<<8, b[2:] + return byteorder.LeUint16(b), b[2:] } // gbit32 reads a 32-bit number in little-endian order from b and returns it with the remaining slice of b. func gbit32(b []byte) (uint32, []byte) { - return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24, b[4:] + return byteorder.LeUint32(b), b[4:] } // gbit64 reads a 64-bit number in little-endian order from b and returns it with the remaining slice of b. func gbit64(b []byte) (uint64, []byte) { - lo := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 - hi := uint32(b[4]) | uint32(b[5])<<8 | uint32(b[6])<<16 | uint32(b[7])<<24 - return uint64(lo) | uint64(hi)<<32, b[8:] + return byteorder.LeUint64(b), b[8:] } // gstring reads a string from b, prefixed with a 16-bit length in little-endian order. diff --git a/contrib/go/_std_1.22/src/syscall/dirent.go b/contrib/go/_std_1.23/src/syscall/dirent.go similarity index 68% rename from contrib/go/_std_1.22/src/syscall/dirent.go rename to contrib/go/_std_1.23/src/syscall/dirent.go index 1a0f1eec11bf..e4f36a191bfa 100644 --- a/contrib/go/_std_1.22/src/syscall/dirent.go +++ b/contrib/go/_std_1.23/src/syscall/dirent.go @@ -7,6 +7,8 @@ package syscall import ( + "internal/byteorder" + "internal/goarch" "runtime" "unsafe" ) @@ -16,7 +18,7 @@ func readInt(b []byte, off, size uintptr) (u uint64, ok bool) { if len(b) < int(off+size) { return 0, false } - if isBigEndian { + if goarch.BigEndian { return readIntBE(b[off:], size), true } return readIntLE(b[off:], size), true @@ -27,15 +29,11 @@ func readIntBE(b []byte, size uintptr) uint64 { case 1: return uint64(b[0]) case 2: - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[1]) | uint64(b[0])<<8 + return uint64(byteorder.BeUint16(b)) case 4: - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24 + return uint64(byteorder.BeUint32(b)) case 8: - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | - uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 + return uint64(byteorder.BeUint64(b)) default: panic("syscall: readInt with unsupported size") } @@ -46,15 +44,11 @@ func readIntLE(b []byte, size uintptr) uint64 { case 1: return uint64(b[0]) case 2: - _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 + return uint64(byteorder.LeUint16(b)) case 4: - _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 + return uint64(byteorder.LeUint32(b)) case 8: - _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 - return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | - uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 + return uint64(byteorder.LeUint64(b)) default: panic("syscall: readInt with unsupported size") } diff --git a/contrib/go/_std_1.22/src/syscall/dll_windows.go b/contrib/go/_std_1.23/src/syscall/dll_windows.go similarity index 83% rename from contrib/go/_std_1.22/src/syscall/dll_windows.go rename to contrib/go/_std_1.23/src/syscall/dll_windows.go index 5f62b5512cad..a7873e6ad8c9 100644 --- a/contrib/go/_std_1.22/src/syscall/dll_windows.go +++ b/contrib/go/_std_1.23/src/syscall/dll_windows.go @@ -24,24 +24,25 @@ func (e *DLLError) Unwrap() error { return e.Err } // Implemented in ../runtime/syscall_windows.go. -// Deprecated: Use SyscallN instead. +// Deprecated: Use [SyscallN] instead. func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) -// Deprecated: Use SyscallN instead. +// Deprecated: Use [SyscallN] instead. func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) -// Deprecated: Use SyscallN instead. +// Deprecated: Use [SyscallN] instead. func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) -// Deprecated: Use SyscallN instead. +// Deprecated: Use [SyscallN] instead. func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno) -// Deprecated: Use SyscallN instead. +// Deprecated: Use [SyscallN] instead. func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno) -// Deprecated: Use SyscallN instead. +// Deprecated: Use [SyscallN] instead. func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18 uintptr) (r1, r2 uintptr, err Errno) +//go:noescape func SyscallN(trap uintptr, args ...uintptr) (r1, r2 uintptr, err Errno) func loadlibrary(filename *uint16) (handle uintptr, err Errno) func loadsystemlibrary(filename *uint16) (handle uintptr, err Errno) @@ -59,7 +60,7 @@ type DLL struct { // Go, Windows will search for the named DLL in many locations, causing // potential DLL preloading attacks. // -// Use LazyDLL in golang.org/x/sys/windows for a secure way to +// Use [LazyDLL] in golang.org/x/sys/windows for a secure way to // load system DLLs. func LoadDLL(name string) (*DLL, error) { namep, err := UTF16PtrFromString(name) @@ -87,7 +88,7 @@ func LoadDLL(name string) (*DLL, error) { return d, nil } -// MustLoadDLL is like LoadDLL but panics if load operation fails. +// MustLoadDLL is like [LoadDLL] but panics if load operation fails. func MustLoadDLL(name string) *DLL { d, e := LoadDLL(name) if e != nil { @@ -96,7 +97,7 @@ func MustLoadDLL(name string) *DLL { return d } -// FindProc searches DLL d for procedure named name and returns *Proc +// FindProc searches [DLL] d for procedure named name and returns [*Proc] // if found. It returns an error if search fails. func (d *DLL) FindProc(name string) (proc *Proc, err error) { namep, err := BytePtrFromString(name) @@ -119,7 +120,7 @@ func (d *DLL) FindProc(name string) (proc *Proc, err error) { return p, nil } -// MustFindProc is like FindProc but panics if search fails. +// MustFindProc is like [DLL.FindProc] but panics if search fails. func (d *DLL) MustFindProc(name string) *Proc { p, e := d.FindProc(name) if e != nil { @@ -128,12 +129,12 @@ func (d *DLL) MustFindProc(name string) *Proc { return p } -// Release unloads DLL d from memory. +// Release unloads [DLL] d from memory. func (d *DLL) Release() (err error) { return FreeLibrary(d.Handle) } -// A Proc implements access to a procedure inside a DLL. +// A Proc implements access to a procedure inside a [DLL]. type Proc struct { Dll *DLL Name string @@ -151,28 +152,28 @@ func (p *Proc) Addr() uintptr { // The returned error is always non-nil, constructed from the result of GetLastError. // Callers must inspect the primary return value to decide whether an error occurred // (according to the semantics of the specific function being called) before consulting -// the error. The error always has type syscall.Errno. +// the error. The error always has type [Errno]. // // On amd64, Call can pass and return floating-point values. To pass // an argument x with C type "float", use // uintptr(math.Float32bits(x)). To pass an argument with C type // "double", use uintptr(math.Float64bits(x)). Floating-point return // values are returned in r2. The return value for C type "float" is -// math.Float32frombits(uint32(r2)). For C type "double", it is -// math.Float64frombits(uint64(r2)). +// [math.Float32frombits](uint32(r2)). For C type "double", it is +// [math.Float64frombits](uint64(r2)). // //go:uintptrescapes func (p *Proc) Call(a ...uintptr) (uintptr, uintptr, error) { return SyscallN(p.Addr(), a...) } -// A LazyDLL implements access to a single DLL. +// A LazyDLL implements access to a single [DLL]. // It will delay the load of the DLL until the first -// call to its Handle method or to one of its -// LazyProc's Addr method. +// call to its [LazyDLL.Handle] method or to one of its +// [LazyProc]'s Addr method. // // LazyDLL is subject to the same DLL preloading attacks as documented -// on LoadDLL. +// on [LoadDLL]. // // Use LazyDLL in golang.org/x/sys/windows for a secure way to // load system DLLs. @@ -217,18 +218,18 @@ func (d *LazyDLL) Handle() uintptr { return uintptr(d.dll.Handle) } -// NewProc returns a LazyProc for accessing the named procedure in the DLL d. +// NewProc returns a [LazyProc] for accessing the named procedure in the [DLL] d. func (d *LazyDLL) NewProc(name string) *LazyProc { return &LazyProc{l: d, Name: name} } -// NewLazyDLL creates new LazyDLL associated with DLL file. +// NewLazyDLL creates new [LazyDLL] associated with [DLL] file. func NewLazyDLL(name string) *LazyDLL { return &LazyDLL{Name: name} } -// A LazyProc implements access to a procedure inside a LazyDLL. -// It delays the lookup until the Addr, Call, or Find method is called. +// A LazyProc implements access to a procedure inside a [LazyDLL]. +// It delays the lookup until the [LazyProc.Addr], [LazyProc.Call], or [LazyProc.Find] method is called. type LazyProc struct { mu sync.Mutex Name string @@ -236,7 +237,7 @@ type LazyProc struct { proc *Proc } -// Find searches DLL for procedure named p.Name. It returns +// Find searches [DLL] for procedure named p.Name. It returns // an error if search fails. Find will not search procedure, // if it is already found and loaded into memory. func (p *LazyProc) Find() error { diff --git a/contrib/go/_std_1.22/src/syscall/env_unix.go b/contrib/go/_std_1.23/src/syscall/env_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/env_unix.go rename to contrib/go/_std_1.23/src/syscall/env_unix.go diff --git a/contrib/go/_std_1.22/src/syscall/env_windows.go b/contrib/go/_std_1.23/src/syscall/env_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/env_windows.go rename to contrib/go/_std_1.23/src/syscall/env_windows.go diff --git a/contrib/go/_std_1.22/src/syscall/errors_plan9.go b/contrib/go/_std_1.23/src/syscall/errors_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/errors_plan9.go rename to contrib/go/_std_1.23/src/syscall/errors_plan9.go diff --git a/contrib/go/_std_1.22/src/syscall/exec_bsd.go b/contrib/go/_std_1.23/src/syscall/exec_bsd.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/exec_bsd.go rename to contrib/go/_std_1.23/src/syscall/exec_bsd.go index 149cc2f11c12..bbdab46de48c 100644 --- a/contrib/go/_std_1.22/src/syscall/exec_bsd.go +++ b/contrib/go/_std_1.23/src/syscall/exec_bsd.go @@ -293,3 +293,8 @@ childerror: RawSyscall(SYS_EXIT, 253, 0, 0) } } + +// forkAndExecFailureCleanup cleans up after an exec failure. +func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) { + // Nothing to do. +} diff --git a/contrib/go/_std_1.22/src/syscall/exec_freebsd.go b/contrib/go/_std_1.23/src/syscall/exec_freebsd.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/exec_freebsd.go rename to contrib/go/_std_1.23/src/syscall/exec_freebsd.go index 3226cb88cd99..686fd23bef43 100644 --- a/contrib/go/_std_1.22/src/syscall/exec_freebsd.go +++ b/contrib/go/_std_1.23/src/syscall/exec_freebsd.go @@ -317,3 +317,8 @@ childerror: RawSyscall(SYS_EXIT, 253, 0, 0) } } + +// forkAndExecFailureCleanup cleans up after an exec failure. +func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) { + // Nothing to do. +} diff --git a/contrib/go/_std_1.22/src/syscall/exec_libc.go b/contrib/go/_std_1.23/src/syscall/exec_libc.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/exec_libc.go rename to contrib/go/_std_1.23/src/syscall/exec_libc.go index 768e8c131c13..0e886508737d 100644 --- a/contrib/go/_std_1.22/src/syscall/exec_libc.go +++ b/contrib/go/_std_1.23/src/syscall/exec_libc.go @@ -314,6 +314,11 @@ childerror: } } +// forkAndExecFailureCleanup cleans up after an exec failure. +func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) { + // Nothing to do. +} + func ioctlPtr(fd, req uintptr, arg unsafe.Pointer) (err Errno) { return ioctl(fd, req, uintptr(arg)) } diff --git a/contrib/go/_std_1.22/src/syscall/exec_libc2.go b/contrib/go/_std_1.23/src/syscall/exec_libc2.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/exec_libc2.go rename to contrib/go/_std_1.23/src/syscall/exec_libc2.go index 7a6750084486..a0579627a300 100644 --- a/contrib/go/_std_1.22/src/syscall/exec_libc2.go +++ b/contrib/go/_std_1.23/src/syscall/exec_libc2.go @@ -289,3 +289,8 @@ childerror: rawSyscall(abi.FuncPCABI0(libc_exit_trampoline), 253, 0, 0) } } + +// forkAndExecFailureCleanup cleans up after an exec failure. +func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) { + // Nothing to do. +} diff --git a/contrib/go/_std_1.22/src/syscall/exec_linux.go b/contrib/go/_std_1.23/src/syscall/exec_linux.go similarity index 89% rename from contrib/go/_std_1.22/src/syscall/exec_linux.go rename to contrib/go/_std_1.23/src/syscall/exec_linux.go index e6d6343ed889..d03194884527 100644 --- a/contrib/go/_std_1.22/src/syscall/exec_linux.go +++ b/contrib/go/_std_1.23/src/syscall/exec_linux.go @@ -7,6 +7,7 @@ package syscall import ( + errpkg "errors" "internal/itoa" "runtime" "unsafe" @@ -53,6 +54,10 @@ const ( // SysProcIDMap holds Container ID to Host ID mappings used for User Namespaces in Linux. // See user_namespaces(7). +// +// Note that User Namespaces are not available on a number of popular Linux +// versions (due to security issues), or are available but subject to AppArmor +// restrictions like in Ubuntu 24.04. type SysProcIDMap struct { ContainerID int // Container ID. HostID int // Host ID. @@ -324,6 +329,7 @@ func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, att if clone3 != nil { pid, err1 = rawVforkSyscall(_SYS_clone3, uintptr(unsafe.Pointer(clone3)), unsafe.Sizeof(*clone3), 0) } else { + // N.B. Keep in sync with doCheckClonePidfd. flags |= uintptr(SIGCHLD) if runtime.GOARCH == "s390x" { // On Linux/s390, the first two arguments of clone(2) are swapped. @@ -731,3 +737,95 @@ func writeUidGidMappings(pid int, sys *SysProcAttr) error { return nil } + +// forkAndExecFailureCleanup cleans up after an exec failure. +func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) { + if sys.PidFD != nil && *sys.PidFD != -1 { + Close(*sys.PidFD) + *sys.PidFD = -1 + } +} + +// checkClonePidfd verifies that clone(CLONE_PIDFD) works by actually doing a +// clone. +// +//go:linkname os_checkClonePidfd os.checkClonePidfd +func os_checkClonePidfd() error { + pidfd := int32(-1) + pid, errno := doCheckClonePidfd(&pidfd) + if errno != 0 { + return errno + } + + if pidfd == -1 { + // Bad: CLONE_PIDFD failed to provide a pidfd. Reap the process + // before returning. + + var err error + for { + var status WaitStatus + // WCLONE is an untyped constant that sets bit 31, so + // it cannot convert directly to int on 32-bit + // GOARCHes. We must convert through another type + // first. + flags := uint(WCLONE) + _, err = Wait4(int(pid), &status, int(flags), nil) + if err != EINTR { + break + } + } + if err != nil { + return err + } + + return errpkg.New("clone(CLONE_PIDFD) failed to return pidfd") + } + + // Good: CLONE_PIDFD provided a pidfd. Reap the process and close the + // pidfd. + defer Close(int(pidfd)) + + for { + const _P_PIDFD = 3 + _, _, errno = Syscall6(SYS_WAITID, _P_PIDFD, uintptr(pidfd), 0, WEXITED | WCLONE, 0, 0) + if errno != EINTR { + break + } + } + if errno != 0 { + return errno + } + + return nil +} + +// doCheckClonePidfd implements the actual clone call of os_checkClonePidfd and +// child execution. This is a separate function so we can separate the child's +// and parent's stack frames if we're using vfork. +// +// This is go:noinline because the point is to keep the stack frames of this +// and os_checkClonePidfd separate. +// +//go:noinline +func doCheckClonePidfd(pidfd *int32) (pid uintptr, errno Errno) { + flags := uintptr(CLONE_VFORK | CLONE_VM | CLONE_PIDFD) + if runtime.GOARCH == "s390x" { + // On Linux/s390, the first two arguments of clone(2) are swapped. + pid, errno = rawVforkSyscall(SYS_CLONE, 0, flags, uintptr(unsafe.Pointer(pidfd))) + } else { + pid, errno = rawVforkSyscall(SYS_CLONE, flags, 0, uintptr(unsafe.Pointer(pidfd))) + } + if errno != 0 || pid != 0 { + // If we're in the parent, we must return immediately + // so we're not in the same stack frame as the child. + // This can at most use the return PC, which the child + // will not modify, and the results of + // rawVforkSyscall, which must have been written after + // the child was replaced. + return + } + + for { + RawSyscall(SYS_EXIT_GROUP, 0, 0, 0) + } +} diff --git a/contrib/go/_std_1.22/src/syscall/exec_plan9.go b/contrib/go/_std_1.23/src/syscall/exec_plan9.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/exec_plan9.go rename to contrib/go/_std_1.23/src/syscall/exec_plan9.go index 8762237825c7..91705e175edc 100644 --- a/contrib/go/_std_1.22/src/syscall/exec_plan9.go +++ b/contrib/go/_std_1.23/src/syscall/exec_plan9.go @@ -69,7 +69,7 @@ func StringSlicePtr(ss []string) []*byte { // SlicePtrFromStrings converts a slice of strings to a slice of // pointers to NUL-terminated byte arrays. If any string contains -// a NUL byte, it returns (nil, EINVAL). +// a NUL byte, it returns (nil, [EINVAL]). func SlicePtrFromStrings(ss []string) ([]*byte, error) { var err error bb := make([]*byte, len(ss)+1) @@ -528,7 +528,7 @@ func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) return startProcess(argv0, argv, attr) } -// StartProcess wraps ForkExec for package os. +// StartProcess wraps [ForkExec] for package os. func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) { pid, err = startProcess(argv0, argv, attr) return pid, 0, err @@ -581,7 +581,7 @@ func Exec(argv0 string, argv []string, envv []string) (err error) { // WaitProcess waits until the pid of a // running process is found in the queue of // wait messages. It is used in conjunction -// with ForkExec/StartProcess to wait for a +// with [ForkExec]/[StartProcess] to wait for a // running process to exit. func WaitProcess(pid int, w *Waitmsg) (err error) { procs.Lock() diff --git a/contrib/go/_std_1.22/src/syscall/exec_unix.go b/contrib/go/_std_1.23/src/syscall/exec_unix.go similarity index 93% rename from contrib/go/_std_1.22/src/syscall/exec_unix.go rename to contrib/go/_std_1.23/src/syscall/exec_unix.go index 469b6601982d..4747fa075834 100644 --- a/contrib/go/_std_1.22/src/syscall/exec_unix.go +++ b/contrib/go/_std_1.23/src/syscall/exec_unix.go @@ -54,13 +54,13 @@ import ( // The rules for which file descriptor-creating operations use the // ForkLock are as follows: // -// - Pipe. Use pipe2 if available. Otherwise, does not block, +// - [Pipe]. Use pipe2 if available. Otherwise, does not block, // so use ForkLock. -// - Socket. Use SOCK_CLOEXEC if available. Otherwise, does not +// - [Socket]. Use SOCK_CLOEXEC if available. Otherwise, does not // block, so use ForkLock. -// - Open. Use O_CLOEXEC if available. Otherwise, may block, +// - [Open]. Use [O_CLOEXEC] if available. Otherwise, may block, // so live with the race. -// - Dup. Use F_DUPFD_CLOEXEC or dup3 if available. Otherwise, +// - [Dup]. Use [F_DUPFD_CLOEXEC] or dup3 if available. Otherwise, // does not block, so use ForkLock. var ForkLock sync.RWMutex @@ -68,7 +68,7 @@ var ForkLock sync.RWMutex // to NUL-terminated byte arrays. If any string contains a NUL byte // this function panics instead of returning an error. // -// Deprecated: Use SlicePtrFromStrings instead. +// Deprecated: Use [SlicePtrFromStrings] instead. func StringSlicePtr(ss []string) []*byte { bb := make([]*byte, len(ss)+1) for i := 0; i < len(ss); i++ { @@ -80,7 +80,7 @@ func StringSlicePtr(ss []string) []*byte { // SlicePtrFromStrings converts a slice of strings to a slice of // pointers to NUL-terminated byte arrays. If any string contains -// a NUL byte, it returns (nil, EINVAL). +// a NUL byte, it returns (nil, [EINVAL]). func SlicePtrFromStrings(ss []string) ([]*byte, error) { n := 0 for _, s := range ss { @@ -120,7 +120,7 @@ func SetNonblock(fd int, nonblocking bool) (err error) { } // Credential holds user and group identities to be assumed -// by a child process started by StartProcess. +// by a child process started by [StartProcess]. type Credential struct { Uid uint32 // User ID. Gid uint32 // Group ID. @@ -129,7 +129,7 @@ type Credential struct { } // ProcAttr holds attributes that will be applied to a new process started -// by StartProcess. +// by [StartProcess]. type ProcAttr struct { Dir string // Current working directory. Env []string // Environment. @@ -237,6 +237,10 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) for err1 == EINTR { _, err1 = Wait4(pid, &wstatus, 0, nil) } + + // OS-specific cleanup on failure. + forkAndExecFailureCleanup(attr, sys) + return 0, err } @@ -249,7 +253,7 @@ func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) return forkExec(argv0, argv, attr) } -// StartProcess wraps ForkExec for package os. +// StartProcess wraps [ForkExec] for package os. func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) { pid, err = forkExec(argv0, argv, attr) return pid, 0, err diff --git a/contrib/go/_std_1.22/src/syscall/exec_windows.go b/contrib/go/_std_1.23/src/syscall/exec_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/exec_windows.go rename to contrib/go/_std_1.23/src/syscall/exec_windows.go diff --git a/contrib/go/_std_1.22/src/syscall/flock_aix.go b/contrib/go/_std_1.23/src/syscall/flock_aix.go similarity index 84% rename from contrib/go/_std_1.22/src/syscall/flock_aix.go rename to contrib/go/_std_1.23/src/syscall/flock_aix.go index c9eab43b6bc2..d8be7ab504b1 100644 --- a/contrib/go/_std_1.22/src/syscall/flock_aix.go +++ b/contrib/go/_std_1.23/src/syscall/flock_aix.go @@ -8,7 +8,7 @@ import "unsafe" // On AIX, there is no flock() system call. -// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command. +// FcntlFlock performs a fcntl syscall for the [F_GETLK], [F_SETLK] or [F_SETLKW] command. func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) (err error) { _, _, e1 := syscall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0) if e1 != 0 { diff --git a/contrib/go/_std_1.22/src/syscall/flock_bsd.go b/contrib/go/_std_1.23/src/syscall/flock_bsd.go similarity index 80% rename from contrib/go/_std_1.22/src/syscall/flock_bsd.go rename to contrib/go/_std_1.23/src/syscall/flock_bsd.go index 68d34708483a..3be2656be7a9 100644 --- a/contrib/go/_std_1.22/src/syscall/flock_bsd.go +++ b/contrib/go/_std_1.23/src/syscall/flock_bsd.go @@ -8,7 +8,7 @@ package syscall import "unsafe" -// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command. +// FcntlFlock performs a fcntl syscall for the [F_GETLK], [F_SETLK] or [F_SETLKW] command. func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error { _, err := fcntlPtr(int(fd), cmd, unsafe.Pointer(lk)) return err diff --git a/contrib/go/_std_1.22/src/syscall/flock_linux.go b/contrib/go/_std_1.23/src/syscall/flock_linux.go similarity index 85% rename from contrib/go/_std_1.22/src/syscall/flock_linux.go rename to contrib/go/_std_1.23/src/syscall/flock_linux.go index 7d1169b42862..2e87b2e0e432 100644 --- a/contrib/go/_std_1.22/src/syscall/flock_linux.go +++ b/contrib/go/_std_1.23/src/syscall/flock_linux.go @@ -10,7 +10,7 @@ import "unsafe" // systems by flock_linux_32bit.go to be SYS_FCNTL64. var fcntl64Syscall uintptr = SYS_FCNTL -// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command. +// FcntlFlock performs a fcntl syscall for the [F_GETLK], [F_SETLK] or [F_SETLKW] command. func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error { _, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk))) if errno == 0 { diff --git a/contrib/go/_std_1.22/src/syscall/flock_linux_32bit.go b/contrib/go/_std_1.23/src/syscall/flock_linux_32bit.go similarity index 82% rename from contrib/go/_std_1.22/src/syscall/flock_linux_32bit.go rename to contrib/go/_std_1.23/src/syscall/flock_linux_32bit.go index 76a09fc47e3f..927c4dfffde8 100644 --- a/contrib/go/_std_1.22/src/syscall/flock_linux_32bit.go +++ b/contrib/go/_std_1.23/src/syscall/flock_linux_32bit.go @@ -2,9 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// If you change the build tags here, see -// internal/syscall/unix/fcntl_linux_32bit.go. - //go:build (linux && 386) || (linux && arm) || (linux && mips) || (linux && mipsle) package syscall diff --git a/contrib/go/_std_1.22/src/syscall/forkpipe.go b/contrib/go/_std_1.23/src/syscall/forkpipe.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/forkpipe.go rename to contrib/go/_std_1.23/src/syscall/forkpipe.go diff --git a/contrib/go/_std_1.22/src/syscall/forkpipe2.go b/contrib/go/_std_1.23/src/syscall/forkpipe2.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/forkpipe2.go rename to contrib/go/_std_1.23/src/syscall/forkpipe2.go diff --git a/contrib/go/_std_1.22/src/syscall/fs_js.go b/contrib/go/_std_1.23/src/syscall/fs_js.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/fs_js.go rename to contrib/go/_std_1.23/src/syscall/fs_js.go diff --git a/contrib/go/_std_1.22/src/syscall/fs_wasip1.go b/contrib/go/_std_1.23/src/syscall/fs_wasip1.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/fs_wasip1.go rename to contrib/go/_std_1.23/src/syscall/fs_wasip1.go index 4ad3f9610bcc..fc361ee89897 100644 --- a/contrib/go/_std_1.22/src/syscall/fs_wasip1.go +++ b/contrib/go/_std_1.23/src/syscall/fs_wasip1.go @@ -7,6 +7,7 @@ package syscall import ( + "internal/stringslite" "runtime" "unsafe" ) @@ -287,12 +288,18 @@ func fd_fdstat_get(fd int32, buf unsafe.Pointer) Errno //go:noescape func fd_fdstat_set_flags(fd int32, flags fdflags) Errno +// fd_fdstat_get_flags is accessed from internal/syscall/unix +//go:linkname fd_fdstat_get_flags + func fd_fdstat_get_flags(fd int) (uint32, error) { var stat fdstat errno := fd_fdstat_get(int32(fd), unsafe.Pointer(&stat)) return uint32(stat.fdflags), errnoErr(errno) } +// fd_fdstat_get_type is accessed from net +//go:linkname fd_fdstat_get_type + func fd_fdstat_get_type(fd int) (uint8, error) { var stat fdstat errno := fd_fdstat_get(int32(fd), unsafe.Pointer(&stat)) @@ -468,19 +475,11 @@ func joinPath(dir, file string) string { } func isAbs(path string) bool { - return hasPrefix(path, "/") + return stringslite.HasPrefix(path, "/") } func isDir(path string) bool { - return hasSuffix(path, "/") -} - -func hasPrefix(s, p string) bool { - return len(s) >= len(p) && s[:len(p)] == p -} - -func hasSuffix(s, x string) bool { - return len(s) >= len(x) && s[len(s)-len(x):] == x + return stringslite.HasSuffix(path, "/") } // preparePath returns the preopen file descriptor of the directory to perform @@ -500,7 +499,7 @@ func preparePath(path string) (int32, unsafe.Pointer, size) { path = joinPath(dir, path) for _, p := range preopens { - if len(p.name) > len(dirName) && hasPrefix(path, p.name) { + if len(p.name) > len(dirName) && stringslite.HasPrefix(path, p.name) { dirFd, dirName = p.fd, p.name } } @@ -566,7 +565,7 @@ func Open(path string, openmode int, perm uint32) (int, error) { if errno == EISDIR && oflags == 0 && fdflags == 0 && ((rights & writeRights) == 0) { // wasmtime and wasmedge will error if attempting to open a directory // because we are asking for too many rights. However, we cannot - // determine ahread of time if the path we are about to open is a + // determine ahead of time if the path we are about to open is a // directory, so instead we fallback to a second call to path_open with // a more limited set of rights. // diff --git a/contrib/go/_std_1.22/src/syscall/js/func.go b/contrib/go/_std_1.23/src/syscall/js/func.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/js/func.go rename to contrib/go/_std_1.23/src/syscall/js/func.go diff --git a/contrib/go/_std_1.22/src/syscall/js/js.go b/contrib/go/_std_1.23/src/syscall/js/js.go similarity index 80% rename from contrib/go/_std_1.22/src/syscall/js/js.go rename to contrib/go/_std_1.23/src/syscall/js/js.go index f7e32eb366db..74c02cdbe64a 100644 --- a/contrib/go/_std_1.22/src/syscall/js/js.go +++ b/contrib/go/_std_1.23/src/syscall/js/js.go @@ -210,7 +210,13 @@ func ValueOf(x any) Value { } } +// stringVal copies string x to Javascript and returns a ref. +// +// (noescape): This is safe because no references are maintained to the +// Go string x after the syscall returns. +// //go:wasmimport gojs syscall/js.stringVal +//go:noescape func stringVal(x string) ref // Type represents the JavaScript type of a Value. @@ -294,7 +300,13 @@ func (v Value) Get(p string) Value { return r } +// valueGet returns a ref to JavaScript property p of ref v. +// +// (noescape): This is safe because no references are maintained to the +// Go string p after the syscall returns. +// //go:wasmimport gojs syscall/js.valueGet +//go:noescape func valueGet(v ref, p string) ref // Set sets the JavaScript property p of value v to ValueOf(x). @@ -309,7 +321,13 @@ func (v Value) Set(p string, x any) { runtime.KeepAlive(xv) } +// valueSet sets property p of ref v to ref x. +// +// (noescape): This is safe because no references are maintained to the +// Go string p after the syscall returns. +// //go:wasmimport gojs syscall/js.valueSet +//go:noescape func valueSet(v ref, p string, x ref) // Delete deletes the JavaScript property p of value v. @@ -322,7 +340,13 @@ func (v Value) Delete(p string) { runtime.KeepAlive(v) } +// valueDelete deletes the JavaScript property p of ref v. +// +// (noescape): This is safe because no references are maintained to the +// Go string p after the syscall returns. +// //go:wasmimport gojs syscall/js.valueDelete +//go:noescape func valueDelete(v ref, p string) // Index returns JavaScript index i of value v. @@ -354,15 +378,36 @@ func (v Value) SetIndex(i int, x any) { //go:wasmimport gojs syscall/js.valueSetIndex func valueSetIndex(v ref, i int, x ref) -func makeArgs(args []any) ([]Value, []ref) { - argVals := make([]Value, len(args)) - argRefs := make([]ref, len(args)) +// makeArgSlices makes two slices to hold JavaScript arg data. +// It can be paired with storeArgs to make-and-store JavaScript arg slices. +// However, the two functions are separated to ensure makeArgSlices is inlined +// which will prevent the slices from being heap allocated for small (<=16) +// numbers of args. +func makeArgSlices(size int) (argVals []Value, argRefs []ref) { + // value chosen for being power of two, and enough to handle all web APIs + // in particular, note that WebGL2's texImage2D takes up to 10 arguments + const maxStackArgs = 16 + if size <= maxStackArgs { + // as long as makeArgs is inlined, these will be stack-allocated + argVals = make([]Value, size, maxStackArgs) + argRefs = make([]ref, size, maxStackArgs) + } else { + // allocates on the heap, but exceeding maxStackArgs should be rare + argVals = make([]Value, size) + argRefs = make([]ref, size) + } + return +} + +// storeArgs maps input args onto respective Value and ref slices. +// It can be paired with makeArgSlices to make-and-store JavaScript arg slices. +func storeArgs(args []any, argValsDst []Value, argRefsDst []ref) { + // would go in makeArgs if the combined func was simple enough to inline for i, arg := range args { v := ValueOf(arg) - argVals[i] = v - argRefs[i] = v.ref + argValsDst[i] = v + argRefsDst[i] = v.ref } - return argVals, argRefs } // Length returns the JavaScript property "length" of v. @@ -383,7 +428,8 @@ func valueLength(v ref) int // It panics if v has no method m. // The arguments get mapped to JavaScript values according to the ValueOf function. func (v Value) Call(m string, args ...any) Value { - argVals, argRefs := makeArgs(args) + argVals, argRefs := makeArgSlices(len(args)) + storeArgs(args, argVals, argRefs) res, ok := valueCall(v.ref, m, argRefs) runtime.KeepAlive(v) runtime.KeepAlive(argVals) @@ -399,15 +445,24 @@ func (v Value) Call(m string, args ...any) Value { return makeValue(res) } +// valueCall does a JavaScript call to the method name m of ref v with the given arguments. +// +// (noescape): This is safe because no references are maintained to the +// Go string m after the syscall returns. Additionally, the args slice +// is only used temporarily to collect the JavaScript objects for +// the JavaScript method invocation. +// //go:wasmimport gojs syscall/js.valueCall //go:nosplit +//go:noescape func valueCall(v ref, m string, args []ref) (ref, bool) // Invoke does a JavaScript call of the value v with the given arguments. // It panics if v is not a JavaScript function. // The arguments get mapped to JavaScript values according to the ValueOf function. func (v Value) Invoke(args ...any) Value { - argVals, argRefs := makeArgs(args) + argVals, argRefs := makeArgSlices(len(args)) + storeArgs(args, argVals, argRefs) res, ok := valueInvoke(v.ref, argRefs) runtime.KeepAlive(v) runtime.KeepAlive(argVals) @@ -420,14 +475,22 @@ func (v Value) Invoke(args ...any) Value { return makeValue(res) } +// valueInvoke does a JavaScript call to value v with the given arguments. +// +// (noescape): This is safe because the args slice is only used temporarily +// to collect the JavaScript objects for the JavaScript method +// invocation. +// //go:wasmimport gojs syscall/js.valueInvoke +//go:noescape func valueInvoke(v ref, args []ref) (ref, bool) // New uses JavaScript's "new" operator with value v as constructor and the given arguments. // It panics if v is not a JavaScript function. // The arguments get mapped to JavaScript values according to the ValueOf function. func (v Value) New(args ...any) Value { - argVals, argRefs := makeArgs(args) + argVals, argRefs := makeArgSlices(len(args)) + storeArgs(args, argVals, argRefs) res, ok := valueNew(v.ref, argRefs) runtime.KeepAlive(v) runtime.KeepAlive(argVals) @@ -440,7 +503,13 @@ func (v Value) New(args ...any) Value { return makeValue(res) } +// valueNew uses JavaScript's "new" operator with value v as a constructor and the given arguments. +// +// (noescape): This is safe because the args slice is only used temporarily +// to collect the JavaScript objects for the constructor execution. +// //go:wasmimport gojs syscall/js.valueNew +//go:noescape func valueNew(v ref, args []ref) (ref, bool) func (v Value) isNumber() bool { @@ -543,7 +612,13 @@ func jsString(v Value) string { //go:wasmimport gojs syscall/js.valuePrepareString func valuePrepareString(v ref) (ref, int) +// valueLoadString loads string data located at ref v into byte slice b. +// +// (noescape): This is safe because the byte slice is only used as a destination +// for storing the string data and references to it are not maintained. +// //go:wasmimport gojs syscall/js.valueLoadString +//go:noescape func valueLoadString(v ref, b []byte) // InstanceOf reports whether v is an instance of type t according to JavaScript's instanceof operator. @@ -581,7 +656,13 @@ func CopyBytesToGo(dst []byte, src Value) int { return n } +// copyBytesToGo copies bytes from src to dst. +// +// (noescape): This is safe because the dst byte slice is only used as a dst +// copy buffer and no references to it are maintained. +// //go:wasmimport gojs syscall/js.copyBytesToGo +//go:noescape func copyBytesToGo(dst []byte, src ref) (int, bool) // CopyBytesToJS copies bytes from src to dst. @@ -596,5 +677,11 @@ func CopyBytesToJS(dst Value, src []byte) int { return n } +// copyBytesToJs copies bytes from src to dst. +// +// (noescape): This is safe because the src byte slice is only used as a src +// copy buffer and no references to it are maintained. +// //go:wasmimport gojs syscall/js.copyBytesToJS +//go:noescape func copyBytesToJS(dst ref, src []byte) (int, bool) diff --git a/contrib/go/_std_1.22/src/syscall/js/js_js.s b/contrib/go/_std_1.23/src/syscall/js/js_js.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/js/js_js.s rename to contrib/go/_std_1.23/src/syscall/js/js_js.s diff --git a/contrib/go/_std_1.22/src/syscall/js/ya.make b/contrib/go/_std_1.23/src/syscall/js/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/syscall/js/ya.make rename to contrib/go/_std_1.23/src/syscall/js/ya.make diff --git a/contrib/go/_std_1.23/src/syscall/linkname_bsd.go b/contrib/go/_std_1.23/src/syscall/linkname_bsd.go new file mode 100644 index 000000000000..c3c6a5842028 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/linkname_bsd.go @@ -0,0 +1,17 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build darwin || dragonfly || freebsd || netbsd || openbsd + +package syscall + +import _ "unsafe" + +// used by internal/syscall/unix +//go:linkname ioctlPtr + +// golang.org/x/net linknames sysctl. +// Do not remove or change the type signature. +// +//go:linkname sysctl diff --git a/contrib/go/_std_1.23/src/syscall/linkname_darwin.go b/contrib/go/_std_1.23/src/syscall/linkname_darwin.go new file mode 100644 index 000000000000..2ed83a4fad2a --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/linkname_darwin.go @@ -0,0 +1,23 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package syscall + +import _ "unsafe" + +// used by os +//go:linkname closedir +//go:linkname readdir_r + +// used by internal/poll +//go:linkname fdopendir + +// used by internal/syscall/unix +//go:linkname unlinkat +//go:linkname openat +//go:linkname fstatat + +// used by cmd/link +//go:linkname msync +//go:linkname fcntl diff --git a/contrib/go/_std_1.23/src/syscall/linkname_libc.go b/contrib/go/_std_1.23/src/syscall/linkname_libc.go new file mode 100644 index 000000000000..1e7b4880d6ed --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/linkname_libc.go @@ -0,0 +1,12 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build aix || darwin || (openbsd && !mips64) || solaris + +package syscall + +import _ "unsafe" + +// used by internal/poll +//go:linkname writev diff --git a/contrib/go/_std_1.23/src/syscall/linkname_openbsd.go b/contrib/go/_std_1.23/src/syscall/linkname_openbsd.go new file mode 100644 index 000000000000..5f5c517ab585 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/linkname_openbsd.go @@ -0,0 +1,15 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build openbsd && !mips64 + +package syscall + +import _ "unsafe" + +// used by internal/syscall/unix +//go:linkname unlinkat +//go:linkname openat +//go:linkname fstatat +//go:linkname getentropy diff --git a/contrib/go/_std_1.23/src/syscall/linkname_unix.go b/contrib/go/_std_1.23/src/syscall/linkname_unix.go new file mode 100644 index 000000000000..c4d187c01f20 --- /dev/null +++ b/contrib/go/_std_1.23/src/syscall/linkname_unix.go @@ -0,0 +1,20 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build unix + +package syscall + +import _ "unsafe" // for linkname + +// mmap should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - modernc.org/memory +// - github.com/ncruces/go-sqlite3 +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname mmap diff --git a/contrib/go/_std_1.22/src/syscall/lsf_linux.go b/contrib/go/_std_1.23/src/syscall/lsf_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/lsf_linux.go rename to contrib/go/_std_1.23/src/syscall/lsf_linux.go diff --git a/contrib/go/_std_1.22/src/syscall/mkasm.go b/contrib/go/_std_1.23/src/syscall/mkasm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mkasm.go rename to contrib/go/_std_1.23/src/syscall/mkasm.go diff --git a/contrib/go/_std_1.22/src/syscall/mkpost.go b/contrib/go/_std_1.23/src/syscall/mkpost.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mkpost.go rename to contrib/go/_std_1.23/src/syscall/mkpost.go diff --git a/contrib/go/_std_1.22/src/syscall/mksyscall.pl b/contrib/go/_std_1.23/src/syscall/mksyscall.pl similarity index 98% rename from contrib/go/_std_1.22/src/syscall/mksyscall.pl rename to contrib/go/_std_1.23/src/syscall/mksyscall.pl index 47efbffcbcb1..b46a3f9438bd 100755 --- a/contrib/go/_std_1.22/src/syscall/mksyscall.pl +++ b/contrib/go/_std_1.23/src/syscall/mksyscall.pl @@ -33,6 +33,7 @@ my $libc = 0; my $tags = ""; # build tags my $newtags = ""; # new style build tags +my $stdimports = 'import "unsafe"'; my $extraimports = ""; if($ARGV[0] eq "-b32") { @@ -390,6 +391,10 @@ ($) exit 1; } +if($extraimports ne "") { + $stdimports .= "\n$extraimports"; +} + # TODO: this assumes tags are just simply comma separated. For now this is all the uses. $newtags = $tags =~ s/,/ && /r; @@ -401,8 +406,7 @@ ($) package syscall -import "unsafe" -$extraimports +$stdimports $text EOF diff --git a/contrib/go/_std_1.22/src/syscall/mksyscall_libc.pl b/contrib/go/_std_1.23/src/syscall/mksyscall_libc.pl similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksyscall_libc.pl rename to contrib/go/_std_1.23/src/syscall/mksyscall_libc.pl diff --git a/contrib/go/_std_1.22/src/syscall/mksyscall_windows.go b/contrib/go/_std_1.23/src/syscall/mksyscall_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksyscall_windows.go rename to contrib/go/_std_1.23/src/syscall/mksyscall_windows.go diff --git a/contrib/go/_std_1.22/src/syscall/mksysctl_openbsd.pl b/contrib/go/_std_1.23/src/syscall/mksysctl_openbsd.pl similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksysctl_openbsd.pl rename to contrib/go/_std_1.23/src/syscall/mksysctl_openbsd.pl diff --git a/contrib/go/_std_1.22/src/syscall/mksysnum_dragonfly.pl b/contrib/go/_std_1.23/src/syscall/mksysnum_dragonfly.pl similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksysnum_dragonfly.pl rename to contrib/go/_std_1.23/src/syscall/mksysnum_dragonfly.pl diff --git a/contrib/go/_std_1.22/src/syscall/mksysnum_freebsd.pl b/contrib/go/_std_1.23/src/syscall/mksysnum_freebsd.pl similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksysnum_freebsd.pl rename to contrib/go/_std_1.23/src/syscall/mksysnum_freebsd.pl diff --git a/contrib/go/_std_1.22/src/syscall/mksysnum_linux.pl b/contrib/go/_std_1.23/src/syscall/mksysnum_linux.pl similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksysnum_linux.pl rename to contrib/go/_std_1.23/src/syscall/mksysnum_linux.pl diff --git a/contrib/go/_std_1.22/src/syscall/mksysnum_netbsd.pl b/contrib/go/_std_1.23/src/syscall/mksysnum_netbsd.pl similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksysnum_netbsd.pl rename to contrib/go/_std_1.23/src/syscall/mksysnum_netbsd.pl diff --git a/contrib/go/_std_1.22/src/syscall/mksysnum_openbsd.pl b/contrib/go/_std_1.23/src/syscall/mksysnum_openbsd.pl similarity index 100% rename from contrib/go/_std_1.22/src/syscall/mksysnum_openbsd.pl rename to contrib/go/_std_1.23/src/syscall/mksysnum_openbsd.pl diff --git a/contrib/go/_std_1.22/src/syscall/net.go b/contrib/go/_std_1.23/src/syscall/net.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/net.go rename to contrib/go/_std_1.23/src/syscall/net.go diff --git a/contrib/go/_std_1.22/src/syscall/net_fake.go b/contrib/go/_std_1.23/src/syscall/net_fake.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/net_fake.go rename to contrib/go/_std_1.23/src/syscall/net_fake.go diff --git a/contrib/go/_std_1.22/src/syscall/net_js.go b/contrib/go/_std_1.23/src/syscall/net_js.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/net_js.go rename to contrib/go/_std_1.23/src/syscall/net_js.go diff --git a/contrib/go/_std_1.22/src/syscall/net_wasip1.go b/contrib/go/_std_1.23/src/syscall/net_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/net_wasip1.go rename to contrib/go/_std_1.23/src/syscall/net_wasip1.go diff --git a/contrib/go/_std_1.22/src/syscall/netlink_linux.go b/contrib/go/_std_1.23/src/syscall/netlink_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/netlink_linux.go rename to contrib/go/_std_1.23/src/syscall/netlink_linux.go diff --git a/contrib/go/_std_1.22/src/syscall/os_wasip1.go b/contrib/go/_std_1.23/src/syscall/os_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/os_wasip1.go rename to contrib/go/_std_1.23/src/syscall/os_wasip1.go diff --git a/contrib/go/_std_1.22/src/syscall/pwd_plan9.go b/contrib/go/_std_1.23/src/syscall/pwd_plan9.go similarity index 96% rename from contrib/go/_std_1.22/src/syscall/pwd_plan9.go rename to contrib/go/_std_1.23/src/syscall/pwd_plan9.go index 28e99565eed6..b81018873f9c 100644 --- a/contrib/go/_std_1.22/src/syscall/pwd_plan9.go +++ b/contrib/go/_std_1.23/src/syscall/pwd_plan9.go @@ -23,7 +23,7 @@ var ( ) // Ensure current working directory seen by this goroutine matches -// the most recent Chdir called in any goroutine. It's called internally +// the most recent [Chdir] called in any goroutine. It's called internally // before executing any syscall which uses a relative pathname. Must // be called with the goroutine locked to the OS thread, to prevent // rescheduling on a different thread (potentially with a different diff --git a/contrib/go/_std_1.22/src/syscall/rlimit.go b/contrib/go/_std_1.23/src/syscall/rlimit.go similarity index 94% rename from contrib/go/_std_1.22/src/syscall/rlimit.go rename to contrib/go/_std_1.23/src/syscall/rlimit.go index d77341bde9a5..8184f17ab68f 100644 --- a/contrib/go/_std_1.22/src/syscall/rlimit.go +++ b/contrib/go/_std_1.23/src/syscall/rlimit.go @@ -39,11 +39,10 @@ func init() { } func Setrlimit(resource int, rlim *Rlimit) error { - err := setrlimit(resource, rlim) - if err == nil && resource == RLIMIT_NOFILE { + if resource == RLIMIT_NOFILE { // Store nil in origRlimitNofile to tell StartProcess // to not adjust the rlimit in the child process. origRlimitNofile.Store(nil) } - return err + return setrlimit(resource, rlim) } diff --git a/contrib/go/_std_1.22/src/syscall/rlimit_darwin.go b/contrib/go/_std_1.23/src/syscall/rlimit_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/rlimit_darwin.go rename to contrib/go/_std_1.23/src/syscall/rlimit_darwin.go diff --git a/contrib/go/_std_1.22/src/syscall/rlimit_stub.go b/contrib/go/_std_1.23/src/syscall/rlimit_stub.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/rlimit_stub.go rename to contrib/go/_std_1.23/src/syscall/rlimit_stub.go diff --git a/contrib/go/_std_1.22/src/syscall/route_bsd.go b/contrib/go/_std_1.23/src/syscall/route_bsd.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/route_bsd.go rename to contrib/go/_std_1.23/src/syscall/route_bsd.go index 8e47ff888e93..46680d645a6c 100644 --- a/contrib/go/_std_1.22/src/syscall/route_bsd.go +++ b/contrib/go/_std_1.23/src/syscall/route_bsd.go @@ -325,7 +325,7 @@ func (m *InterfaceAddrMessage) sockaddr() ([]Sockaddr, error) { } // ParseRoutingMessage parses b as routing messages and returns the -// slice containing the RoutingMessage interfaces. +// slice containing the [RoutingMessage] interfaces. // // Deprecated: Use golang.org/x/net/route instead. func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) { @@ -352,7 +352,7 @@ func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) { } // ParseRoutingSockaddr parses msg's payload as raw sockaddrs and -// returns the slice containing the Sockaddr interfaces. +// returns the slice containing the [Sockaddr] interfaces. // // Deprecated: Use golang.org/x/net/route instead. func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) { diff --git a/contrib/go/_std_1.22/src/syscall/route_darwin.go b/contrib/go/_std_1.23/src/syscall/route_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/route_darwin.go rename to contrib/go/_std_1.23/src/syscall/route_darwin.go diff --git a/contrib/go/_std_1.22/src/syscall/route_dragonfly.go b/contrib/go/_std_1.23/src/syscall/route_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/route_dragonfly.go rename to contrib/go/_std_1.23/src/syscall/route_dragonfly.go diff --git a/contrib/go/_std_1.22/src/syscall/route_freebsd.go b/contrib/go/_std_1.23/src/syscall/route_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/route_freebsd.go rename to contrib/go/_std_1.23/src/syscall/route_freebsd.go diff --git a/contrib/go/_std_1.22/src/syscall/route_freebsd_32bit.go b/contrib/go/_std_1.23/src/syscall/route_freebsd_32bit.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/route_freebsd_32bit.go rename to contrib/go/_std_1.23/src/syscall/route_freebsd_32bit.go diff --git a/contrib/go/_std_1.22/src/syscall/route_freebsd_64bit.go b/contrib/go/_std_1.23/src/syscall/route_freebsd_64bit.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/route_freebsd_64bit.go rename to contrib/go/_std_1.23/src/syscall/route_freebsd_64bit.go diff --git a/contrib/go/_std_1.22/src/syscall/route_netbsd.go b/contrib/go/_std_1.23/src/syscall/route_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/route_netbsd.go rename to contrib/go/_std_1.23/src/syscall/route_netbsd.go diff --git a/contrib/go/_std_1.22/src/syscall/route_openbsd.go b/contrib/go/_std_1.23/src/syscall/route_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/route_openbsd.go rename to contrib/go/_std_1.23/src/syscall/route_openbsd.go diff --git a/contrib/go/_std_1.22/src/syscall/security_windows.go b/contrib/go/_std_1.23/src/syscall/security_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/security_windows.go rename to contrib/go/_std_1.23/src/syscall/security_windows.go diff --git a/contrib/go/_std_1.22/src/syscall/setuidgid_32_linux.go b/contrib/go/_std_1.23/src/syscall/setuidgid_32_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/setuidgid_32_linux.go rename to contrib/go/_std_1.23/src/syscall/setuidgid_32_linux.go diff --git a/contrib/go/_std_1.22/src/syscall/setuidgid_linux.go b/contrib/go/_std_1.23/src/syscall/setuidgid_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/setuidgid_linux.go rename to contrib/go/_std_1.23/src/syscall/setuidgid_linux.go diff --git a/contrib/go/_std_1.22/src/syscall/sockcmsg_dragonfly.go b/contrib/go/_std_1.23/src/syscall/sockcmsg_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/sockcmsg_dragonfly.go rename to contrib/go/_std_1.23/src/syscall/sockcmsg_dragonfly.go diff --git a/contrib/go/_std_1.22/src/syscall/sockcmsg_linux.go b/contrib/go/_std_1.23/src/syscall/sockcmsg_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/sockcmsg_linux.go rename to contrib/go/_std_1.23/src/syscall/sockcmsg_linux.go diff --git a/contrib/go/_std_1.22/src/syscall/sockcmsg_unix.go b/contrib/go/_std_1.23/src/syscall/sockcmsg_unix.go similarity index 97% rename from contrib/go/_std_1.22/src/syscall/sockcmsg_unix.go rename to contrib/go/_std_1.23/src/syscall/sockcmsg_unix.go index 6ade73e87e0f..a4b45739b89d 100644 --- a/contrib/go/_std_1.22/src/syscall/sockcmsg_unix.go +++ b/contrib/go/_std_1.23/src/syscall/sockcmsg_unix.go @@ -12,7 +12,7 @@ import ( "unsafe" ) -// CmsgLen returns the value to store in the Len field of the Cmsghdr +// CmsgLen returns the value to store in the Len field of the [Cmsghdr] // structure, taking into account any necessary alignment. func CmsgLen(datalen int) int { return cmsgAlignOf(SizeofCmsghdr) + datalen diff --git a/contrib/go/_std_1.22/src/syscall/sockcmsg_unix_other.go b/contrib/go/_std_1.23/src/syscall/sockcmsg_unix_other.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/sockcmsg_unix_other.go rename to contrib/go/_std_1.23/src/syscall/sockcmsg_unix_other.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall.go b/contrib/go/_std_1.23/src/syscall/syscall.go similarity index 95% rename from contrib/go/_std_1.22/src/syscall/syscall.go rename to contrib/go/_std_1.23/src/syscall/syscall.go index f75ba31f5fb3..a46f22ddb53c 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall.go +++ b/contrib/go/_std_1.23/src/syscall/syscall.go @@ -16,7 +16,7 @@ // the manuals for the appropriate operating system. // These calls return err == nil to indicate success; otherwise // err is an operating system error describing the failure. -// On most systems, that error has type syscall.Errno. +// On most systems, that error has type [Errno]. // // NOTE: Most of the functions, types, and constants defined in // this package are also available in the [golang.org/x/sys] package. @@ -44,7 +44,7 @@ func StringByteSlice(s string) []byte { // ByteSliceFromString returns a NUL-terminated slice of bytes // containing the text of s. If s contains a NUL byte at any -// location, it returns (nil, EINVAL). +// location, it returns (nil, [EINVAL]). func ByteSliceFromString(s string) ([]byte, error) { if bytealg.IndexByteString(s, 0) != -1 { return nil, EINVAL @@ -58,12 +58,12 @@ func ByteSliceFromString(s string) ([]byte, error) { // If s contains a NUL byte this function panics instead of returning // an error. // -// Deprecated: Use BytePtrFromString instead. +// Deprecated: Use [BytePtrFromString] instead. func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] } // BytePtrFromString returns a pointer to a NUL-terminated array of // bytes containing the text of s. If s contains a NUL byte at any -// location, it returns (nil, EINVAL). +// location, it returns (nil, [EINVAL]). func BytePtrFromString(s string) (*byte, error) { a, err := ByteSliceFromString(s) if err != nil { diff --git a/contrib/go/_std_1.22/src/syscall/syscall_aix.go b/contrib/go/_std_1.23/src/syscall/syscall_aix.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/syscall_aix.go rename to contrib/go/_std_1.23/src/syscall/syscall_aix.go index 30e6887cce5f..a9bd7a37336d 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_aix.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_aix.go @@ -222,7 +222,7 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, var status _C_int var r _Pid_t err = ERESTART - // AIX wait4 may return with ERESTART errno, while the processus is still + // AIX wait4 may return with ERESTART errno, while the process is still // active. for err == ERESTART { r, err = wait4(_Pid_t(pid), &status, options, rusage) @@ -629,6 +629,7 @@ func PtraceDetach(pid int) (err error) { return ptrace64(PT_DETACH, int64(pid), //sysnb Setegid(egid int) (err error) //sysnb Seteuid(euid int) (err error) //sysnb Setgid(gid int) (err error) +//sysnb Setuid(uid int) (err error) //sysnb Setpgid(pid int, pgid int) (err error) //sys Setpriority(which int, who int, prio int) (err error) //sysnb Setregid(rgid int, egid int) (err error) diff --git a/contrib/go/_std_1.22/src/syscall/syscall_aix_ppc64.go b/contrib/go/_std_1.23/src/syscall/syscall_aix_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_aix_ppc64.go rename to contrib/go/_std_1.23/src/syscall/syscall_aix_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_bsd.go b/contrib/go/_std_1.23/src/syscall/syscall_bsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_bsd.go rename to contrib/go/_std_1.23/src/syscall/syscall_bsd.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_darwin.go b/contrib/go/_std_1.23/src/syscall/syscall_darwin.go similarity index 97% rename from contrib/go/_std_1.22/src/syscall/syscall_darwin.go rename to contrib/go/_std_1.23/src/syscall/syscall_darwin.go index 2e13b57cd32e..5b38aeae31a6 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_darwin.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_darwin.go @@ -113,6 +113,15 @@ func libc_getfsstat_trampoline() //go:cgo_import_dynamic libc_getfsstat getfsstat "/usr/lib/libSystem.B.dylib" +// utimensat should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/tetratelabs/wazero +// +// See go.dev/issue/67401. +// +//go:linkname utimensat + //sys utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) /* diff --git a/contrib/go/_std_1.22/src/syscall/syscall_darwin_amd64.go b/contrib/go/_std_1.23/src/syscall/syscall_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_darwin_amd64.go rename to contrib/go/_std_1.23/src/syscall/syscall_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_darwin_arm64.go b/contrib/go/_std_1.23/src/syscall/syscall_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_darwin_arm64.go rename to contrib/go/_std_1.23/src/syscall/syscall_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_dragonfly.go b/contrib/go/_std_1.23/src/syscall/syscall_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_dragonfly.go rename to contrib/go/_std_1.23/src/syscall/syscall_dragonfly.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_dragonfly_amd64.go b/contrib/go/_std_1.23/src/syscall/syscall_dragonfly_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_dragonfly_amd64.go rename to contrib/go/_std_1.23/src/syscall/syscall_dragonfly_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_freebsd.go b/contrib/go/_std_1.23/src/syscall/syscall_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_freebsd.go rename to contrib/go/_std_1.23/src/syscall/syscall_freebsd.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_freebsd_386.go b/contrib/go/_std_1.23/src/syscall/syscall_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_freebsd_386.go rename to contrib/go/_std_1.23/src/syscall/syscall_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_freebsd_amd64.go b/contrib/go/_std_1.23/src/syscall/syscall_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_freebsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/syscall_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_freebsd_arm.go b/contrib/go/_std_1.23/src/syscall/syscall_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_freebsd_arm.go rename to contrib/go/_std_1.23/src/syscall/syscall_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_freebsd_arm64.go b/contrib/go/_std_1.23/src/syscall/syscall_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_freebsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/syscall_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_freebsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/syscall_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/syscall_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_illumos.go b/contrib/go/_std_1.23/src/syscall/syscall_illumos.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_illumos.go rename to contrib/go/_std_1.23/src/syscall/syscall_illumos.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_js.go b/contrib/go/_std_1.23/src/syscall/syscall_js.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/syscall_js.go rename to contrib/go/_std_1.23/src/syscall/syscall_js.go index c1b28942e8e4..0e529e034373 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_js.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_js.go @@ -48,7 +48,7 @@ const PathMax = 256 // err = errno // } // -// Errno values can be tested against error values using errors.Is. +// Errno values can be tested against error values using [errors.Is]. // For example: // // _, _, err := syscall.Syscall(...) @@ -88,7 +88,7 @@ func (e Errno) Timeout() bool { } // A Signal is a number describing a process signal. -// It implements the os.Signal interface. +// It implements the [os.Signal] interface. type Signal int const ( diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux.go b/contrib/go/_std_1.23/src/syscall/syscall_linux.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/syscall_linux.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux.go index b6e84203e8df..270697359665 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_linux.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_linux.go @@ -13,17 +13,11 @@ package syscall import ( "internal/itoa" + runtimesyscall "internal/runtime/syscall" "runtime" "unsafe" ) -// N.B. RawSyscall6 is provided via linkname by runtime/internal/syscall. -// -// Errno is uintptr and thus compatible with the runtime/internal/syscall -// definition. - -func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) - // Pull in entersyscall/exitsyscall for Syscall/Syscall6. // // Note that this can't be a push linkname because the runtime already has a @@ -40,8 +34,7 @@ func runtime_exitsyscall() // N.B. For the Syscall functions below: // // //go:uintptrkeepalive because the uintptr argument may be converted pointers -// that need to be kept alive in the caller (this is implied for RawSyscall6 -// since it has no body). +// that need to be kept alive in the caller. // // //go:nosplit because stack copying does not account for uintptrkeepalive, so // the stack must not grow. Stack copying cannot blindly assume that all @@ -62,6 +55,17 @@ func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { return RawSyscall6(trap, a1, a2, a3, 0, 0, 0) } +//go:uintptrkeepalive +//go:nosplit +//go:norace +//go:linkname RawSyscall6 +func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { + var errno uintptr + r1, r2, errno = runtimesyscall.Syscall6(trap, a1, a2, a3, a4, a5, a6) + err = Errno(errno) + return +} + //go:uintptrkeepalive //go:nosplit //go:linkname Syscall @@ -1107,7 +1111,7 @@ func runtime_doAllThreadsSyscall(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, // // AllThreadsSyscall is unaware of any threads that are launched // explicitly by cgo linked code, so the function always returns -// ENOTSUP in binaries that use cgo. +// [ENOTSUP] in binaries that use cgo. // //go:uintptrescapes func AllThreadsSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { @@ -1118,7 +1122,7 @@ func AllThreadsSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { return r1, r2, Errno(errno) } -// AllThreadsSyscall6 is like AllThreadsSyscall, but extended to six +// AllThreadsSyscall6 is like [AllThreadsSyscall], but extended to six // arguments. // //go:uintptrescapes @@ -1282,10 +1286,14 @@ func Munmap(b []byte) (err error) { // prlimit changes a resource limit. We use a single definition so that // we can tell StartProcess to not restore the original NOFILE limit. -// This is unexported but can be called from x/sys/unix. +// +// golang.org/x/sys linknames prlimit. +// Do not remove or change the type signature. +// +//go:linkname prlimit func prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) { err = prlimit1(pid, resource, newlimit, old) - if err == nil && newlimit != nil && resource == RLIMIT_NOFILE { + if err == nil && newlimit != nil && resource == RLIMIT_NOFILE && (pid == 0 || pid == Getpid()) { origRlimitNofile.Store(nil) } return err diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_386.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_386.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_386.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_accept.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_accept.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_accept.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_accept.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_accept4.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_accept4.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_accept4.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_accept4.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_amd64.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_amd64.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_arm.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_arm.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_arm64.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_arm64.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_loong64.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_loong64.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_mips64x.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_mips64x.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_mips64x.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_mipsx.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_mipsx.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_mipsx.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_ppc64x.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_ppc64x.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_ppc64x.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_riscv64.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_riscv64.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_linux_s390x.go b/contrib/go/_std_1.23/src/syscall/syscall_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_linux_s390x.go rename to contrib/go/_std_1.23/src/syscall/syscall_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_netbsd.go b/contrib/go/_std_1.23/src/syscall/syscall_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_netbsd.go rename to contrib/go/_std_1.23/src/syscall/syscall_netbsd.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_netbsd_386.go b/contrib/go/_std_1.23/src/syscall/syscall_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_netbsd_386.go rename to contrib/go/_std_1.23/src/syscall/syscall_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_netbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/syscall_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_netbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/syscall_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_netbsd_arm.go b/contrib/go/_std_1.23/src/syscall/syscall_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_netbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/syscall_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_netbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/syscall_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_netbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/syscall_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd1.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd1.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd1.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd1.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_386.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_386.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_arm.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_libc.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_libc.go similarity index 73% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_libc.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_libc.go index ddf62f4d3f4f..5dea268c3e42 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_libc.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_libc.go @@ -16,26 +16,40 @@ func init() { execveOpenBSD = execve } -//sys directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) = SYS_syscall - func syscallInternal(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { - return syscall6X(abi.FuncPCABI0(libc_syscall_trampoline), trap, a1, a2, a3, 0, 0) + // OpenBSD 7.5+ no longer supports indirect syscalls. A number of Go + // packages make use of syscall.Syscall with SYS_IOCTL since it is + // not well supported by golang.org/x/sys/unix. Reroute this system + // call number to the respective libc stub so that it continues to + // work for the time being. See #63900 for further details. + if trap == SYS_IOCTL { + return syscallX(abi.FuncPCABI0(libc_ioctl_trampoline), a1, a2, a3) + } + return 0, 0, ENOSYS } func syscall6Internal(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { - return syscall10X(abi.FuncPCABI0(libc_syscall_trampoline), trap, a1, a2, a3, a4, a5, a6, 0, 0, 0) + // OpenBSD 7.5+ no longer supports indirect syscalls. A number of Go + // packages make use of syscall.Syscall with SYS___SYSCTL since it is + // not well supported by golang.org/x/sys/unix. Reroute this system + // call number to the respective libc stub so that it continues to + // work for the time being. See #63900 for further details. + if trap == SYS___SYSCTL { + return syscall6X(abi.FuncPCABI0(libc_sysctl_trampoline), a1, a2, a3, a4, a5, a6) + } + return 0, 0, ENOSYS } func rawSyscallInternal(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { - return rawSyscall6X(abi.FuncPCABI0(libc_syscall_trampoline), trap, a1, a2, a3, 0, 0) + return 0, 0, ENOSYS } func rawSyscall6Internal(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { - return rawSyscall10X(abi.FuncPCABI0(libc_syscall_trampoline), trap, a1, a2, a3, a4, a5, a6, 0, 0, 0) + return 0, 0, ENOSYS } func syscall9Internal(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) { - return rawSyscall10X(abi.FuncPCABI0(libc_syscall_trampoline), trap, a1, a2, a3, a4, a5, a6, a7, a8, a9) + return 0, 0, ENOSYS } // Implemented in the runtime package (runtime/sys_openbsd3.go) diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_mips64.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_mips64.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_ppc64.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_ppc64.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_openbsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/syscall_openbsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_openbsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/syscall_openbsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_plan9.go b/contrib/go/_std_1.23/src/syscall/syscall_plan9.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/syscall_plan9.go rename to contrib/go/_std_1.23/src/syscall/syscall_plan9.go index 7af10ba322a8..968782008d12 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_plan9.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_plan9.go @@ -23,7 +23,7 @@ const bitSize16 = 2 // ErrorString implements Error's String method by returning itself. // -// ErrorString values can be tested against error values using errors.Is. +// ErrorString values can be tested against error values using [errors.Is]. // For example: // // _, _, err := syscall.Syscall(...) @@ -99,7 +99,7 @@ var ( ) // For testing: clients can set this flag to force -// creation of IPv6 sockets to return EAFNOSUPPORT. +// creation of IPv6 sockets to return [EAFNOSUPPORT]. var SocketDisableIPv6 bool func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err ErrorString) diff --git a/contrib/go/_std_1.22/src/syscall/syscall_solaris.go b/contrib/go/_std_1.23/src/syscall/syscall_solaris.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/syscall_solaris.go rename to contrib/go/_std_1.23/src/syscall/syscall_solaris.go index 28d3727db66f..30400b4fac84 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_solaris.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_solaris.go @@ -299,7 +299,7 @@ func UtimesNano(path string, ts []Timespec) error { //sys fcntl(fd int, cmd int, arg int) (val int, err error) -// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command. +// FcntlFlock performs a fcntl syscall for the [F_GETLK], [F_SETLK] or [F_SETLKW] command. func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0) if e1 != 0 { diff --git a/contrib/go/_std_1.22/src/syscall/syscall_solaris_amd64.go b/contrib/go/_std_1.23/src/syscall/syscall_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_solaris_amd64.go rename to contrib/go/_std_1.23/src/syscall/syscall_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_solarisonly.go b/contrib/go/_std_1.23/src/syscall/syscall_solarisonly.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/syscall_solarisonly.go rename to contrib/go/_std_1.23/src/syscall/syscall_solarisonly.go diff --git a/contrib/go/_std_1.22/src/syscall/syscall_unix.go b/contrib/go/_std_1.23/src/syscall/syscall_unix.go similarity index 93% rename from contrib/go/_std_1.22/src/syscall/syscall_unix.go rename to contrib/go/_std_1.23/src/syscall/syscall_unix.go index 4c48f29744a7..ecd5952975a7 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_unix.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_unix.go @@ -8,8 +8,10 @@ package syscall import ( errorspkg "errors" + "internal/asan" "internal/bytealg" "internal/itoa" + "internal/msan" "internal/oserror" "internal/race" "runtime" @@ -98,7 +100,7 @@ func (m *mmapper) Munmap(data []byte) (err error) { // err = errno // } // -// Errno values can be tested against error values using errors.Is. +// Errno values can be tested against error values using [errors.Is]. // For example: // // _, _, err := syscall.Syscall(...) @@ -162,7 +164,7 @@ func errnoErr(e Errno) error { } // A Signal is a number describing a process signal. -// It implements the os.Signal interface. +// It implements the [os.Signal] interface. type Signal int func (s Signal) Signal() {} @@ -187,11 +189,11 @@ func Read(fd int, p []byte) (n int, err error) { race.Acquire(unsafe.Pointer(&ioSync)) } } - if msanenabled && n > 0 { - msanWrite(unsafe.Pointer(&p[0]), n) + if msan.Enabled && n > 0 { + msan.Write(unsafe.Pointer(&p[0]), uintptr(n)) } - if asanenabled && n > 0 { - asanWrite(unsafe.Pointer(&p[0]), n) + if asan.Enabled && n > 0 { + asan.Write(unsafe.Pointer(&p[0]), uintptr(n)) } return } @@ -211,11 +213,11 @@ func Write(fd int, p []byte) (n int, err error) { if race.Enabled && n > 0 { race.ReadRange(unsafe.Pointer(&p[0]), n) } - if msanenabled && n > 0 { - msanRead(unsafe.Pointer(&p[0]), n) + if msan.Enabled && n > 0 { + msan.Read(unsafe.Pointer(&p[0]), uintptr(n)) } - if asanenabled && n > 0 { - asanRead(unsafe.Pointer(&p[0]), n) + if asan.Enabled && n > 0 { + asan.Read(unsafe.Pointer(&p[0]), uintptr(n)) } return } @@ -230,11 +232,11 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) { race.Acquire(unsafe.Pointer(&ioSync)) } } - if msanenabled && n > 0 { - msanWrite(unsafe.Pointer(&p[0]), n) + if msan.Enabled && n > 0 { + msan.Write(unsafe.Pointer(&p[0]), uintptr(n)) } - if asanenabled && n > 0 { - asanWrite(unsafe.Pointer(&p[0]), n) + if asan.Enabled && n > 0 { + asan.Write(unsafe.Pointer(&p[0]), uintptr(n)) } return } @@ -247,17 +249,17 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) { if race.Enabled && n > 0 { race.ReadRange(unsafe.Pointer(&p[0]), n) } - if msanenabled && n > 0 { - msanRead(unsafe.Pointer(&p[0]), n) + if msan.Enabled && n > 0 { + msan.Read(unsafe.Pointer(&p[0]), uintptr(n)) } - if asanenabled && n > 0 { - asanRead(unsafe.Pointer(&p[0]), n) + if asan.Enabled && n > 0 { + asan.Read(unsafe.Pointer(&p[0]), uintptr(n)) } return } // For testing: clients can set this flag to force -// creation of IPv6 sockets to return EAFNOSUPPORT. +// creation of IPv6 sockets to return [EAFNOSUPPORT]. var SocketDisableIPv6 bool type Sockaddr interface { diff --git a/contrib/go/_std_1.22/src/syscall/syscall_wasip1.go b/contrib/go/_std_1.23/src/syscall/syscall_wasip1.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/syscall_wasip1.go rename to contrib/go/_std_1.23/src/syscall/syscall_wasip1.go index e66afee5e9ad..84c6bddc0897 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_wasip1.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_wasip1.go @@ -97,7 +97,7 @@ func (e Errno) Timeout() bool { } // A Signal is a number describing a process signal. -// It implements the os.Signal interface. +// It implements the [os.Signal] interface. type Signal uint8 const ( @@ -305,7 +305,7 @@ func (w WaitStatus) Continued() bool { return false } func (w WaitStatus) StopSignal() Signal { return 0 } func (w WaitStatus) TrapCause() int { return 0 } -// Rusage is a placeholder to allow compilation of the os/exec package +// Rusage is a placeholder to allow compilation of the [os/exec] package // because we need Go programs to be portable across platforms. WASI does // not have a mechanism to to spawn processes so there is no reason for an // application to take a dependency on this type. @@ -314,7 +314,7 @@ type Rusage struct { Stime Timeval } -// ProcAttr is a placeholder to allow compilation of the os/exec package +// ProcAttr is a placeholder to allow compilation of the [os/exec] package // because we need Go programs to be portable across platforms. WASI does // not have a mechanism to to spawn processes so there is no reason for an // application to take a dependency on this type. diff --git a/contrib/go/_std_1.22/src/syscall/syscall_windows.go b/contrib/go/_std_1.23/src/syscall/syscall_windows.go similarity index 98% rename from contrib/go/_std_1.22/src/syscall/syscall_windows.go rename to contrib/go/_std_1.23/src/syscall/syscall_windows.go index d13acc5c441b..d49ee522c4fe 100644 --- a/contrib/go/_std_1.22/src/syscall/syscall_windows.go +++ b/contrib/go/_std_1.23/src/syscall/syscall_windows.go @@ -8,8 +8,10 @@ package syscall import ( errorspkg "errors" + "internal/asan" "internal/bytealg" "internal/itoa" + "internal/msan" "internal/oserror" "internal/race" "runtime" @@ -25,7 +27,7 @@ const InvalidHandle = ^Handle(0) // with a terminating NUL added. If s contains a NUL byte this // function panics instead of returning an error. // -// Deprecated: Use UTF16FromString instead. +// Deprecated: Use [UTF16FromString] instead. func StringToUTF16(s string) []uint16 { a, err := UTF16FromString(s) if err != nil { @@ -36,7 +38,7 @@ func StringToUTF16(s string) []uint16 { // UTF16FromString returns the UTF-16 encoding of the UTF-8 string // s, with a terminating NUL added. If s contains a NUL byte at any -// location, it returns (nil, EINVAL). Unpaired surrogates +// location, it returns (nil, [EINVAL]). Unpaired surrogates // are encoded using WTF-8. func UTF16FromString(s string) ([]uint16, error) { if bytealg.IndexByteString(s, 0) != -1 { @@ -102,7 +104,7 @@ func utf16PtrToString(p *uint16) string { // contains a NUL byte this function panics instead of // returning an error. // -// Deprecated: Use UTF16PtrFromString instead. +// Deprecated: Use [UTF16PtrFromString] instead. func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] } // UTF16PtrFromString returns pointer to the UTF-16 encoding of @@ -119,7 +121,7 @@ func UTF16PtrFromString(s string) (*uint16, error) { // Errno is the Windows error number. // -// Errno values can be tested against error values using errors.Is. +// Errno values can be tested against error values using [errors.Is]. // For example: // // _, _, err := syscall.Syscall(...) @@ -231,7 +233,6 @@ func NewCallbackCDecl(fn any) uintptr { //sys FreeLibrary(handle Handle) (err error) //sys GetProcAddress(module Handle, procname string) (proc uintptr, err error) //sys GetVersion() (ver uint32, err error) -//sys rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) = ntdll.RtlGetNtVersionNumbers //sys formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW //sys ExitProcess(exitcode uint32) //sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW @@ -446,11 +447,11 @@ func ReadFile(fd Handle, p []byte, done *uint32, overlapped *Overlapped) error { } race.Acquire(unsafe.Pointer(&ioSync)) } - if msanenabled && *done > 0 { - msanWrite(unsafe.Pointer(&p[0]), int(*done)) + if msan.Enabled && *done > 0 { + msan.Write(unsafe.Pointer(&p[0]), uintptr(*done)) } - if asanenabled && *done > 0 { - asanWrite(unsafe.Pointer(&p[0]), int(*done)) + if asan.Enabled && *done > 0 { + asan.Write(unsafe.Pointer(&p[0]), uintptr(*done)) } return err } @@ -463,11 +464,11 @@ func WriteFile(fd Handle, p []byte, done *uint32, overlapped *Overlapped) error if race.Enabled && *done > 0 { race.ReadRange(unsafe.Pointer(&p[0]), int(*done)) } - if msanenabled && *done > 0 { - msanRead(unsafe.Pointer(&p[0]), int(*done)) + if msan.Enabled && *done > 0 { + msan.Read(unsafe.Pointer(&p[0]), uintptr(*done)) } - if asanenabled && *done > 0 { - asanRead(unsafe.Pointer(&p[0]), int(*done)) + if asan.Enabled && *done > 0 { + asan.Read(unsafe.Pointer(&p[0]), uintptr(*done)) } return err } @@ -768,7 +769,7 @@ const socket_error = uintptr(^uint32(0)) //sys WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) [failretval==-1] = ws2_32.WSAEnumProtocolsW // For testing: clients can set this flag to force -// creation of IPv6 sockets to return EAFNOSUPPORT. +// creation of IPv6 sockets to return [EAFNOSUPPORT]. var SocketDisableIPv6 bool type RawSockaddrInet4 struct { @@ -1163,7 +1164,12 @@ type IPv6Mreq struct { Interface uint32 } -func GetsockoptInt(fd Handle, level, opt int) (int, error) { return -1, EWINDOWS } +func GetsockoptInt(fd Handle, level, opt int) (int, error) { + optval := int32(0) + optlen := int32(unsafe.Sizeof(optval)) + err := Getsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&optval)), &optlen) + return int(optval), err +} func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) { sys := sysLinger{Onoff: uint16(l.Onoff), Linger: uint16(l.Linger)} @@ -1261,7 +1267,7 @@ func Fchdir(fd Handle) (err error) { if err != nil { return err } - // When using VOLUME_NAME_DOS, the path is always pefixed by "\\?\". + // When using VOLUME_NAME_DOS, the path is always prefixed by "\\?\". // That prefix tells the Windows APIs to disable all string parsing and to send // the string that follows it straight to the file system. // Although SetCurrentDirectory and GetCurrentDirectory do support the "\\?\" prefix, @@ -1438,7 +1444,7 @@ func newProcThreadAttributeList(maxAttrCount uint32) (*_PROC_THREAD_ATTRIBUTE_LI // decrementing until index 0 is enumerated. // // Successive calls to this API must happen on the same OS thread, -// so call runtime.LockOSThread before calling this function. +// so call [runtime.LockOSThread] before calling this function. func RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) { return regEnumKeyEx(key, index, name, nameLen, reserved, class, classLen, lastWriteTime) } diff --git a/contrib/go/_std_1.22/src/syscall/tables_js.go b/contrib/go/_std_1.23/src/syscall/tables_js.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/tables_js.go rename to contrib/go/_std_1.23/src/syscall/tables_js.go diff --git a/contrib/go/_std_1.22/src/syscall/tables_wasip1.go b/contrib/go/_std_1.23/src/syscall/tables_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/tables_wasip1.go rename to contrib/go/_std_1.23/src/syscall/tables_wasip1.go diff --git a/contrib/go/_std_1.22/src/syscall/time_fake.go b/contrib/go/_std_1.23/src/syscall/time_fake.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/time_fake.go rename to contrib/go/_std_1.23/src/syscall/time_fake.go diff --git a/contrib/go/_std_1.22/src/syscall/time_nofake.go b/contrib/go/_std_1.23/src/syscall/time_nofake.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/time_nofake.go rename to contrib/go/_std_1.23/src/syscall/time_nofake.go diff --git a/contrib/go/_std_1.22/src/syscall/timestruct.go b/contrib/go/_std_1.23/src/syscall/timestruct.go similarity index 85% rename from contrib/go/_std_1.22/src/syscall/timestruct.go rename to contrib/go/_std_1.23/src/syscall/timestruct.go index 4fca63cc40cc..b1d03ef25c48 100644 --- a/contrib/go/_std_1.22/src/syscall/timestruct.go +++ b/contrib/go/_std_1.23/src/syscall/timestruct.go @@ -9,7 +9,7 @@ package syscall // TimespecToNsec returns the time stored in ts as nanoseconds. func TimespecToNsec(ts Timespec) int64 { return ts.Nano() } -// NsecToTimespec converts a number of nanoseconds into a Timespec. +// NsecToTimespec converts a number of nanoseconds into a [Timespec]. func NsecToTimespec(nsec int64) Timespec { sec := nsec / 1e9 nsec = nsec % 1e9 @@ -23,7 +23,7 @@ func NsecToTimespec(nsec int64) Timespec { // TimevalToNsec returns the time stored in tv as nanoseconds. func TimevalToNsec(tv Timeval) int64 { return tv.Nano() } -// NsecToTimeval converts a number of nanoseconds into a Timeval. +// NsecToTimeval converts a number of nanoseconds into a [Timeval]. func NsecToTimeval(nsec int64) Timeval { nsec += 999 // round up to microsecond usec := nsec % 1e9 / 1e3 diff --git a/contrib/go/_std_1.22/src/syscall/types_aix.go b/contrib/go/_std_1.23/src/syscall/types_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_aix.go rename to contrib/go/_std_1.23/src/syscall/types_aix.go diff --git a/contrib/go/_std_1.22/src/syscall/types_darwin.go b/contrib/go/_std_1.23/src/syscall/types_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_darwin.go rename to contrib/go/_std_1.23/src/syscall/types_darwin.go diff --git a/contrib/go/_std_1.22/src/syscall/types_dragonfly.go b/contrib/go/_std_1.23/src/syscall/types_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_dragonfly.go rename to contrib/go/_std_1.23/src/syscall/types_dragonfly.go diff --git a/contrib/go/_std_1.22/src/syscall/types_freebsd.go b/contrib/go/_std_1.23/src/syscall/types_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_freebsd.go rename to contrib/go/_std_1.23/src/syscall/types_freebsd.go diff --git a/contrib/go/_std_1.22/src/syscall/types_illumos_amd64.go b/contrib/go/_std_1.23/src/syscall/types_illumos_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_illumos_amd64.go rename to contrib/go/_std_1.23/src/syscall/types_illumos_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/types_linux.go b/contrib/go/_std_1.23/src/syscall/types_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_linux.go rename to contrib/go/_std_1.23/src/syscall/types_linux.go diff --git a/contrib/go/_std_1.22/src/syscall/types_netbsd.go b/contrib/go/_std_1.23/src/syscall/types_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_netbsd.go rename to contrib/go/_std_1.23/src/syscall/types_netbsd.go diff --git a/contrib/go/_std_1.22/src/syscall/types_openbsd.go b/contrib/go/_std_1.23/src/syscall/types_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_openbsd.go rename to contrib/go/_std_1.23/src/syscall/types_openbsd.go diff --git a/contrib/go/_std_1.22/src/syscall/types_solaris.go b/contrib/go/_std_1.23/src/syscall/types_solaris.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_solaris.go rename to contrib/go/_std_1.23/src/syscall/types_solaris.go diff --git a/contrib/go/_std_1.22/src/syscall/types_windows.go b/contrib/go/_std_1.23/src/syscall/types_windows.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/types_windows.go rename to contrib/go/_std_1.23/src/syscall/types_windows.go index b338ec47001f..6743675b9590 100644 --- a/contrib/go/_std_1.22/src/syscall/types_windows.go +++ b/contrib/go/_std_1.23/src/syscall/types_windows.go @@ -27,6 +27,7 @@ const ( ERROR_NOT_FOUND Errno = 1168 ERROR_PRIVILEGE_NOT_HELD Errno = 1314 WSAEACCES Errno = 10013 + WSAENOPROTOOPT Errno = 10042 WSAECONNABORTED Errno = 10053 WSAECONNRESET Errno = 10054 ) diff --git a/contrib/go/_std_1.22/src/syscall/types_windows_386.go b/contrib/go/_std_1.23/src/syscall/types_windows_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_windows_386.go rename to contrib/go/_std_1.23/src/syscall/types_windows_386.go diff --git a/contrib/go/_std_1.22/src/syscall/types_windows_amd64.go b/contrib/go/_std_1.23/src/syscall/types_windows_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_windows_amd64.go rename to contrib/go/_std_1.23/src/syscall/types_windows_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/types_windows_arm.go b/contrib/go/_std_1.23/src/syscall/types_windows_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_windows_arm.go rename to contrib/go/_std_1.23/src/syscall/types_windows_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/types_windows_arm64.go b/contrib/go/_std_1.23/src/syscall/types_windows_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/types_windows_arm64.go rename to contrib/go/_std_1.23/src/syscall/types_windows_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/wtf8_windows.go b/contrib/go/_std_1.23/src/syscall/wtf8_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/wtf8_windows.go rename to contrib/go/_std_1.23/src/syscall/wtf8_windows.go diff --git a/contrib/go/_std_1.22/src/syscall/ya.make b/contrib/go/_std_1.23/src/syscall/ya.make similarity index 92% rename from contrib/go/_std_1.22/src/syscall/ya.make rename to contrib/go/_std_1.23/src/syscall/ya.make index 41a879582683..36a55fb7f9db 100644 --- a/contrib/go/_std_1.22/src/syscall/ya.make +++ b/contrib/go/_std_1.23/src/syscall/ya.make @@ -1,28 +1,19 @@ GO_LIBRARY() - -IF(SANITIZER_TYPE == "memory") - SRCS(msan.go) -ELSE() - SRCS(msan0.go) -ENDIF() - -IF(SANITIZER_TYPE == "address") - SRCS(asan.go) -ELSE() - SRCS(asan0.go) -ENDIF() - IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( asm_darwin_arm64.s + badlinkname_unix.go bpf_bsd.go dirent.go - endian_little.go env_unix.go exec_libc2.go exec_unix.go flock_bsd.go forkpipe.go + linkname_bsd.go + linkname_darwin.go + linkname_libc.go + linkname_unix.go net.go rlimit.go rlimit_darwin.go @@ -46,14 +37,18 @@ IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM6 ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( asm_darwin_amd64.s + badlinkname_unix.go bpf_bsd.go dirent.go - endian_little.go env_unix.go exec_libc2.go exec_unix.go flock_bsd.go forkpipe.go + linkname_bsd.go + linkname_darwin.go + linkname_libc.go + linkname_unix.go net.go rlimit.go rlimit_darwin.go @@ -77,13 +72,14 @@ ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( asm_linux_arm64.s + badlinkname_unix.go dirent.go - endian_little.go env_unix.go exec_linux.go exec_unix.go flock_linux.go forkpipe2.go + linkname_unix.go lsf_linux.go net.go netlink_linux.go @@ -108,13 +104,14 @@ ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_ ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( asm_linux_amd64.s + badlinkname_unix.go dirent.go - endian_little.go env_unix.go exec_linux.go exec_unix.go flock_linux.go forkpipe2.go + linkname_unix.go lsf_linux.go net.go netlink_linux.go @@ -139,7 +136,6 @@ ELSEIF (OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( dll_windows.go - endian_little.go env_windows.go exec_windows.go net.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_aix_ppc64.go b/contrib/go/_std_1.23/src/syscall/zerrors_aix_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_aix_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_aix_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_darwin_amd64.go b/contrib/go/_std_1.23/src/syscall/zerrors_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_darwin_amd64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_darwin_arm64.go b/contrib/go/_std_1.23/src/syscall/zerrors_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_darwin_arm64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_dragonfly_amd64.go b/contrib/go/_std_1.23/src/syscall/zerrors_dragonfly_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_dragonfly_amd64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_dragonfly_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_freebsd_386.go b/contrib/go/_std_1.23/src/syscall/zerrors_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_freebsd_386.go rename to contrib/go/_std_1.23/src/syscall/zerrors_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_freebsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zerrors_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_freebsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_freebsd_arm.go b/contrib/go/_std_1.23/src/syscall/zerrors_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_freebsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zerrors_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_freebsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zerrors_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_freebsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_freebsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/zerrors_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_386.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_386.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_amd64.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_amd64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_arm.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_arm.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_arm64.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_arm64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_loong64.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_loong64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_mips.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_mips.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_mips.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_mips.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_mips64.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_mips64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_mips64le.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_mips64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_mips64le.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_mips64le.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_mipsle.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_mipsle.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_mipsle.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_mipsle.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_ppc64.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_ppc64le.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_ppc64le.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_ppc64le.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_riscv64.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_linux_s390x.go b/contrib/go/_std_1.23/src/syscall/zerrors_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_linux_s390x.go rename to contrib/go/_std_1.23/src/syscall/zerrors_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_netbsd_386.go b/contrib/go/_std_1.23/src/syscall/zerrors_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_netbsd_386.go rename to contrib/go/_std_1.23/src/syscall/zerrors_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_netbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zerrors_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_netbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_netbsd_arm.go b/contrib/go/_std_1.23/src/syscall/zerrors_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_netbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zerrors_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_netbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zerrors_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_netbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_386.go b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_386.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zerrors_openbsd_386.go rename to contrib/go/_std_1.23/src/syscall/zerrors_openbsd_386.go index d17ecb96e50c..a37d6d16346d 100644 --- a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_386.go +++ b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_386.go @@ -1330,6 +1330,7 @@ const ( EALREADY = Errno(0x25) EAUTH = Errno(0x50) EBADF = Errno(0x9) + EBADMSG = Errno(0x5c) EBADRPC = Errno(0x48) EBUSY = Errno(0x10) ECANCELED = Errno(0x58) @@ -1356,7 +1357,7 @@ const ( EIPSEC = Errno(0x52) EISCONN = Errno(0x38) EISDIR = Errno(0x15) - ELAST = Errno(0x5b) + ELAST = Errno(0x5f) ELOOP = Errno(0x3e) EMEDIUMTYPE = Errno(0x56) EMFILE = Errno(0x18) @@ -1384,12 +1385,14 @@ const ( ENOTCONN = Errno(0x39) ENOTDIR = Errno(0x14) ENOTEMPTY = Errno(0x42) + ENOTRECOVERABLE = Errno(0x5d) ENOTSOCK = Errno(0x26) ENOTSUP = Errno(0x5b) ENOTTY = Errno(0x19) ENXIO = Errno(0x6) EOPNOTSUPP = Errno(0x2d) EOVERFLOW = Errno(0x57) + EOWNERDEAD = Errno(0x5e) EPERM = Errno(0x1) EPFNOSUPPORT = Errno(0x2e) EPIPE = Errno(0x20) @@ -1397,6 +1400,7 @@ const ( EPROCUNAVAIL = Errno(0x4c) EPROGMISMATCH = Errno(0x4b) EPROGUNAVAIL = Errno(0x4a) + EPROTO = Errno(0x5f) EPROTONOSUPPORT = Errno(0x2b) EPROTOTYPE = Errno(0x29) ERANGE = Errno(0x22) @@ -1514,7 +1518,7 @@ var errors = [...]string{ 57: "socket is not connected", 58: "can't send after socket shutdown", 59: "too many references: can't splice", - 60: "connection timed out", + 60: "operation timed out", 61: "connection refused", 62: "too many levels of symbolic links", 63: "file name too long", @@ -1523,12 +1527,12 @@ var errors = [...]string{ 66: "directory not empty", 67: "too many processes", 68: "too many users", - 69: "disc quota exceeded", + 69: "disk quota exceeded", 70: "stale NFS file handle", 71: "too many levels of remote in path", 72: "RPC struct is bad", 73: "RPC version wrong", - 74: "RPC prog. not avail", + 74: "RPC program not available", 75: "program version wrong", 76: "bad procedure for program", 77: "no locks available", @@ -1546,6 +1550,10 @@ var errors = [...]string{ 89: "identifier removed", 90: "no message of desired type", 91: "not supported", + 92: "bad message", + 93: "state not recoverable", + 94: "previous owner died", + 95: "protocol error", } // Signal table @@ -1566,8 +1574,8 @@ var signals = [...]string{ 14: "alarm clock", 15: "terminated", 16: "urgent I/O condition", - 17: "stopped (signal)", - 18: "stopped", + 17: "suspended (signal)", + 18: "suspended", 19: "continued", 20: "child exited", 21: "stopped (tty input)", diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_amd64.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zerrors_openbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_openbsd_amd64.go index 4904e7614f3d..812fd950a7fc 100644 --- a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_amd64.go +++ b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_amd64.go @@ -1329,6 +1329,7 @@ const ( EALREADY = Errno(0x25) EAUTH = Errno(0x50) EBADF = Errno(0x9) + EBADMSG = Errno(0x5c) EBADRPC = Errno(0x48) EBUSY = Errno(0x10) ECANCELED = Errno(0x58) @@ -1355,7 +1356,7 @@ const ( EIPSEC = Errno(0x52) EISCONN = Errno(0x38) EISDIR = Errno(0x15) - ELAST = Errno(0x5b) + ELAST = Errno(0x5f) ELOOP = Errno(0x3e) EMEDIUMTYPE = Errno(0x56) EMFILE = Errno(0x18) @@ -1383,12 +1384,14 @@ const ( ENOTCONN = Errno(0x39) ENOTDIR = Errno(0x14) ENOTEMPTY = Errno(0x42) + ENOTRECOVERABLE = Errno(0x5d) ENOTSOCK = Errno(0x26) ENOTSUP = Errno(0x5b) ENOTTY = Errno(0x19) ENXIO = Errno(0x6) EOPNOTSUPP = Errno(0x2d) EOVERFLOW = Errno(0x57) + EOWNERDEAD = Errno(0x5e) EPERM = Errno(0x1) EPFNOSUPPORT = Errno(0x2e) EPIPE = Errno(0x20) @@ -1396,6 +1399,7 @@ const ( EPROCUNAVAIL = Errno(0x4c) EPROGMISMATCH = Errno(0x4b) EPROGUNAVAIL = Errno(0x4a) + EPROTO = Errno(0x5f) EPROTONOSUPPORT = Errno(0x2b) EPROTOTYPE = Errno(0x29) ERANGE = Errno(0x22) @@ -1513,7 +1517,7 @@ var errors = [...]string{ 57: "socket is not connected", 58: "can't send after socket shutdown", 59: "too many references: can't splice", - 60: "connection timed out", + 60: "operation timed out", 61: "connection refused", 62: "too many levels of symbolic links", 63: "file name too long", @@ -1522,12 +1526,12 @@ var errors = [...]string{ 66: "directory not empty", 67: "too many processes", 68: "too many users", - 69: "disc quota exceeded", + 69: "disk quota exceeded", 70: "stale NFS file handle", 71: "too many levels of remote in path", 72: "RPC struct is bad", 73: "RPC version wrong", - 74: "RPC prog. not avail", + 74: "RPC program not available", 75: "program version wrong", 76: "bad procedure for program", 77: "no locks available", @@ -1545,6 +1549,10 @@ var errors = [...]string{ 89: "identifier removed", 90: "no message of desired type", 91: "not supported", + 92: "bad message", + 93: "state not recoverable", + 94: "previous owner died", + 95: "protocol error", } // Signal table @@ -1565,8 +1573,8 @@ var signals = [...]string{ 14: "alarm clock", 15: "terminated", 16: "urgent I/O condition", - 17: "stopped (signal)", - 18: "stopped", + 17: "suspended (signal)", + 18: "suspended", 19: "continued", 20: "child exited", 21: "stopped (tty input)", diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_arm.go b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_arm.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zerrors_openbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zerrors_openbsd_arm.go index 76ac9173a93f..2e19672b05a2 100644 --- a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_arm.go +++ b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_arm.go @@ -1329,6 +1329,7 @@ const ( EALREADY = Errno(0x25) EAUTH = Errno(0x50) EBADF = Errno(0x9) + EBADMSG = Errno(0x5c) EBADRPC = Errno(0x48) EBUSY = Errno(0x10) ECANCELED = Errno(0x58) @@ -1355,7 +1356,7 @@ const ( EIPSEC = Errno(0x52) EISCONN = Errno(0x38) EISDIR = Errno(0x15) - ELAST = Errno(0x5b) + ELAST = Errno(0x5f) ELOOP = Errno(0x3e) EMEDIUMTYPE = Errno(0x56) EMFILE = Errno(0x18) @@ -1383,12 +1384,14 @@ const ( ENOTCONN = Errno(0x39) ENOTDIR = Errno(0x14) ENOTEMPTY = Errno(0x42) + ENOTRECOVERABLE = Errno(0x5d) ENOTSOCK = Errno(0x26) ENOTSUP = Errno(0x5b) ENOTTY = Errno(0x19) ENXIO = Errno(0x6) EOPNOTSUPP = Errno(0x2d) EOVERFLOW = Errno(0x57) + EOWNERDEAD = Errno(0x5e) EPERM = Errno(0x1) EPFNOSUPPORT = Errno(0x2e) EPIPE = Errno(0x20) @@ -1396,6 +1399,7 @@ const ( EPROCUNAVAIL = Errno(0x4c) EPROGMISMATCH = Errno(0x4b) EPROGUNAVAIL = Errno(0x4a) + EPROTO = Errno(0x5f) EPROTONOSUPPORT = Errno(0x2b) EPROTOTYPE = Errno(0x29) ERANGE = Errno(0x22) @@ -1513,7 +1517,7 @@ var errors = [...]string{ 57: "socket is not connected", 58: "can't send after socket shutdown", 59: "too many references: can't splice", - 60: "connection timed out", + 60: "operation timed out", 61: "connection refused", 62: "too many levels of symbolic links", 63: "file name too long", @@ -1522,12 +1526,12 @@ var errors = [...]string{ 66: "directory not empty", 67: "too many processes", 68: "too many users", - 69: "disc quota exceeded", + 69: "disk quota exceeded", 70: "stale NFS file handle", 71: "too many levels of remote in path", 72: "RPC struct is bad", 73: "RPC version wrong", - 74: "RPC prog. not avail", + 74: "RPC program not available", 75: "program version wrong", 76: "bad procedure for program", 77: "no locks available", @@ -1545,6 +1549,10 @@ var errors = [...]string{ 89: "identifier removed", 90: "no message of desired type", 91: "not supported", + 92: "bad message", + 93: "state not recoverable", + 94: "previous owner died", + 95: "protocol error", } // Signal table @@ -1565,8 +1573,8 @@ var signals = [...]string{ 14: "alarm clock", 15: "terminated", 16: "urgent I/O condition", - 17: "stopped (signal)", - 18: "stopped", + 17: "suspended (signal)", + 18: "suspended", 19: "continued", 20: "child exited", 21: "stopped (tty input)", diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_openbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_mips64.go b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_openbsd_mips64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_ppc64.go b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_openbsd_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_openbsd_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_openbsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/zerrors_openbsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_openbsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_openbsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_solaris_amd64.go b/contrib/go/_std_1.23/src/syscall/zerrors_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_solaris_amd64.go rename to contrib/go/_std_1.23/src/syscall/zerrors_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zerrors_windows.go b/contrib/go/_std_1.23/src/syscall/zerrors_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zerrors_windows.go rename to contrib/go/_std_1.23/src/syscall/zerrors_windows.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_aix_ppc64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_aix_ppc64.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_aix_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_aix_ppc64.go index 111e6711d7de..27657aa1e9ce 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_aix_ppc64.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_aix_ppc64.go @@ -83,6 +83,7 @@ import "unsafe" //go:cgo_import_dynamic libc_Setegid setegid "libc.a/shr_64.o" //go:cgo_import_dynamic libc_Seteuid seteuid "libc.a/shr_64.o" //go:cgo_import_dynamic libc_Setgid setgid "libc.a/shr_64.o" +//go:cgo_import_dynamic libc_Setuid setuid "libc.a/shr_64.o" //go:cgo_import_dynamic libc_Setpgid setpgid "libc.a/shr_64.o" //go:cgo_import_dynamic libc_Setpriority setpriority "libc.a/shr_64.o" //go:cgo_import_dynamic libc_Setregid setregid "libc.a/shr_64.o" @@ -177,6 +178,7 @@ import "unsafe" //go:linkname libc_Setegid libc_Setegid //go:linkname libc_Seteuid libc_Seteuid //go:linkname libc_Setgid libc_Setgid +//go:linkname libc_Setuid libc_Setuid //go:linkname libc_Setpgid libc_Setpgid //go:linkname libc_Setpriority libc_Setpriority //go:linkname libc_Setregid libc_Setregid @@ -274,6 +276,7 @@ var ( libc_Setegid, libc_Seteuid, libc_Setgid, + libc_Setuid, libc_Setpgid, libc_Setpriority, libc_Setregid, @@ -1231,6 +1234,16 @@ func Setgid(gid int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Setuid(uid int) (err error) { + _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setuid)), 1, uintptr(uid), 0, 0, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setpgid(pid int, pgid int) (err error) { _, _, e1 := rawSyscall6(uintptr(unsafe.Pointer(&libc_Setpgid)), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0) if e1 != 0 { diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_darwin_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_darwin_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_darwin_amd64.s b/contrib/go/_std_1.23/src/syscall/zsyscall_darwin_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_darwin_amd64.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_darwin_amd64.s diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_darwin_arm64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_darwin_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_darwin_arm64.s b/contrib/go/_std_1.23/src/syscall/zsyscall_darwin_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_darwin_arm64.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_darwin_arm64.s diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_dragonfly_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_dragonfly_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_dragonfly_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_dragonfly_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_386.go b/contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_386.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_arm.go b/contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_386.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_386.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_arm.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_arm.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_arm64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_loong64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_loong64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_mips.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_mips.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_mips.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_mips.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_mips64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_mips64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_mips64le.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_mips64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_mips64le.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_mips64le.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_mipsle.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_mipsle.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_mipsle.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_mipsle.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_ppc64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_ppc64le.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_ppc64le.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_ppc64le.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_riscv64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_linux_s390x.go b/contrib/go/_std_1.23/src/syscall/zsyscall_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_linux_s390x.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_386.go b/contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_386.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_arm.go b/contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_netbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_386.go b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_386.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_386.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_386.go index 084b4b78e53a..d2bd3ea0125a 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_386.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_386.go @@ -1729,21 +1729,6 @@ func libc_utimensat_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) { - r0, _, e1 := syscall6(abi.FuncPCABI0(libc_syscall_trampoline), uintptr(trap), uintptr(a1), uintptr(a2), uintptr(a3), uintptr(a4), uintptr(a5)) - ret = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_syscall_trampoline() - -//go:cgo_import_dynamic libc_syscall syscall "libc.so" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func readlen(fd int, buf *byte, nbuf int) (n int, err error) { r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_386.s b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_386.s similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_386.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_386.s index 319ad205c0ba..9a820e9f3eb9 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_386.s +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_386.s @@ -213,8 +213,6 @@ TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_getfsstat(SB) TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimensat(SB) -TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 - JMP libc_syscall(SB) TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_amd64.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_amd64.go index 5a7b4c1122b4..170a74b457ba 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_amd64.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_amd64.go @@ -1729,21 +1729,6 @@ func libc_utimensat_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) { - r0, _, e1 := syscall6X(abi.FuncPCABI0(libc_syscall_trampoline), uintptr(trap), uintptr(a1), uintptr(a2), uintptr(a3), uintptr(a4), uintptr(a5)) - ret = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_syscall_trampoline() - -//go:cgo_import_dynamic libc_syscall syscall "libc.so" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func readlen(fd int, buf *byte, nbuf int) (n int, err error) { r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_amd64.s b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_amd64.s similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_amd64.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_amd64.s index c0e397728af3..9b70dc096e12 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_amd64.s +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_amd64.s @@ -213,8 +213,6 @@ TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_getfsstat(SB) TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimensat(SB) -TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 - JMP libc_syscall(SB) TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm.go b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm.go index 66a322717523..e75bd0b443b9 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm.go @@ -1729,21 +1729,6 @@ func libc_utimensat_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) { - r0, _, e1 := syscall6(abi.FuncPCABI0(libc_syscall_trampoline), uintptr(trap), uintptr(a1), uintptr(a2), uintptr(a3), uintptr(a4), uintptr(a5)) - ret = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_syscall_trampoline() - -//go:cgo_import_dynamic libc_syscall syscall "libc.so" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func readlen(fd int, buf *byte, nbuf int) (n int, err error) { r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm.s b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm.s similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm.s index 73b6a092ef3c..0333377b8b71 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm.s +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm.s @@ -213,8 +213,6 @@ TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_getfsstat(SB) TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimensat(SB) -TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 - JMP libc_syscall(SB) TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm64.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm64.go index a90f14436905..bc027b44755f 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm64.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm64.go @@ -1729,21 +1729,6 @@ func libc_utimensat_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) { - r0, _, e1 := syscall6X(abi.FuncPCABI0(libc_syscall_trampoline), uintptr(trap), uintptr(a1), uintptr(a2), uintptr(a3), uintptr(a4), uintptr(a5)) - ret = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_syscall_trampoline() - -//go:cgo_import_dynamic libc_syscall syscall "libc.so" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func readlen(fd int, buf *byte, nbuf int) (n int, err error) { r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm64.s b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm64.s similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm64.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm64.s index 66656695d58e..654e6c69a353 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_arm64.s +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_arm64.s @@ -213,8 +213,6 @@ TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_getfsstat(SB) TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimensat(SB) -TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 - JMP libc_syscall(SB) TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_mips64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_mips64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_ppc64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_ppc64.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_ppc64.go index 661c8959a631..6808092a5a27 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_ppc64.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_ppc64.go @@ -1729,21 +1729,6 @@ func libc_utimensat_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) { - r0, _, e1 := syscall6X(abi.FuncPCABI0(libc_syscall_trampoline), uintptr(trap), uintptr(a1), uintptr(a2), uintptr(a3), uintptr(a4), uintptr(a5)) - ret = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_syscall_trampoline() - -//go:cgo_import_dynamic libc_syscall syscall "libc.so" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func readlen(fd int, buf *byte, nbuf int) (n int, err error) { r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_ppc64.s b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_ppc64.s similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_ppc64.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_ppc64.s index 8f3ff9a28c4e..86a5745c0ae6 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_ppc64.s +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_ppc64.s @@ -319,9 +319,6 @@ TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 CALL libc_utimensat(SB) RET -TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 - CALL libc_syscall(SB) - RET TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 CALL libc_lseek(SB) RET diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_riscv64.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_riscv64.go index a24fcba11310..2979ff78c25b 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_riscv64.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_riscv64.go @@ -1729,21 +1729,6 @@ func libc_utimensat_trampoline() // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func directSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 uintptr) (ret uintptr, err error) { - r0, _, e1 := syscall6X(abi.FuncPCABI0(libc_syscall_trampoline), uintptr(trap), uintptr(a1), uintptr(a2), uintptr(a3), uintptr(a4), uintptr(a5)) - ret = uintptr(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -func libc_syscall_trampoline() - -//go:cgo_import_dynamic libc_syscall syscall "libc.so" - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func readlen(fd int, buf *byte, nbuf int) (n int, err error) { r0, _, e1 := syscall(abi.FuncPCABI0(libc_read_trampoline), uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf)) n = int(r0) diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_riscv64.s b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_riscv64.s similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_riscv64.s rename to contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_riscv64.s index 4f787ee2751e..c8728190e555 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_openbsd_riscv64.s +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_openbsd_riscv64.s @@ -213,8 +213,6 @@ TEXT ·libc_getfsstat_trampoline(SB),NOSPLIT,$0-0 JMP libc_getfsstat(SB) TEXT ·libc_utimensat_trampoline(SB),NOSPLIT,$0-0 JMP libc_utimensat(SB) -TEXT ·libc_syscall_trampoline(SB),NOSPLIT,$0-0 - JMP libc_syscall(SB) TEXT ·libc_lseek_trampoline(SB),NOSPLIT,$0-0 JMP libc_lseek(SB) TEXT ·libc_getcwd_trampoline(SB),NOSPLIT,$0-0 diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_plan9_386.go b/contrib/go/_std_1.23/src/syscall/zsyscall_plan9_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_plan9_386.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_plan9_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_plan9_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_plan9_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_plan9_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_plan9_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_plan9_arm.go b/contrib/go/_std_1.23/src/syscall/zsyscall_plan9_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_plan9_arm.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_plan9_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_solaris_amd64.go b/contrib/go/_std_1.23/src/syscall/zsyscall_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsyscall_solaris_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsyscall_windows.go b/contrib/go/_std_1.23/src/syscall/zsyscall_windows.go similarity index 99% rename from contrib/go/_std_1.22/src/syscall/zsyscall_windows.go rename to contrib/go/_std_1.23/src/syscall/zsyscall_windows.go index 630270812db4..d8d8594a5561 100644 --- a/contrib/go/_std_1.22/src/syscall/zsyscall_windows.go +++ b/contrib/go/_std_1.23/src/syscall/zsyscall_windows.go @@ -43,7 +43,6 @@ var ( modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll")) modmswsock = NewLazyDLL(sysdll.Add("mswsock.dll")) modnetapi32 = NewLazyDLL(sysdll.Add("netapi32.dll")) - modntdll = NewLazyDLL(sysdll.Add("ntdll.dll")) modsecur32 = NewLazyDLL(sysdll.Add("secur32.dll")) modshell32 = NewLazyDLL(sysdll.Add("shell32.dll")) moduserenv = NewLazyDLL(sysdll.Add("userenv.dll")) @@ -168,7 +167,6 @@ var ( procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree") procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation") procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo") - procRtlGetNtVersionNumbers = modntdll.NewProc("RtlGetNtVersionNumbers") procGetUserNameExW = modsecur32.NewProc("GetUserNameExW") procTranslateNameW = modsecur32.NewProc("TranslateNameW") procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW") @@ -1212,11 +1210,6 @@ func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **by return } -func rtlGetNtVersionNumbers(majorVersion *uint32, minorVersion *uint32, buildNumber *uint32) { - Syscall(procRtlGetNtVersionNumbers.Addr(), 3, uintptr(unsafe.Pointer(majorVersion)), uintptr(unsafe.Pointer(minorVersion)), uintptr(unsafe.Pointer(buildNumber))) - return -} - func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err error) { r1, _, e1 := Syscall(procGetUserNameExW.Addr(), 3, uintptr(nameFormat), uintptr(unsafe.Pointer(nameBuffre)), uintptr(unsafe.Pointer(nSize))) if r1&0xff == 0 { diff --git a/contrib/go/_std_1.22/src/syscall/zsysctl_openbsd.go b/contrib/go/_std_1.23/src/syscall/zsysctl_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysctl_openbsd.go rename to contrib/go/_std_1.23/src/syscall/zsysctl_openbsd.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_darwin_amd64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_darwin_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_darwin_arm64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_darwin_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_dragonfly_amd64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_dragonfly_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_dragonfly_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_dragonfly_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_386.go b/contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_386.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_arm.go b/contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_386.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_386.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_amd64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_arm.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_arm.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_arm64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_loong64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_loong64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_mips.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_mips.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_mips.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_mips.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_mips64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_mips64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_mips64le.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_mips64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_mips64le.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_mips64le.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_mipsle.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_mipsle.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_mipsle.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_mipsle.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_ppc64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_ppc64le.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_ppc64le.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_ppc64le.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_riscv64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_linux_s390x.go b/contrib/go/_std_1.23/src/syscall/zsysnum_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_linux_s390x.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_386.go b/contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_386.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_arm.go b/contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_netbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_386.go b/contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_386.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_arm.go b/contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_mips64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_mips64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_ppc64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_ppc64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_openbsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_openbsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_plan9.go b/contrib/go/_std_1.23/src/syscall/zsysnum_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_plan9.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_plan9.go diff --git a/contrib/go/_std_1.22/src/syscall/zsysnum_solaris_amd64.go b/contrib/go/_std_1.23/src/syscall/zsysnum_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/zsysnum_solaris_amd64.go rename to contrib/go/_std_1.23/src/syscall/zsysnum_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_aix_ppc64.go b/contrib/go/_std_1.23/src/syscall/ztypes_aix_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_aix_ppc64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_aix_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_darwin_amd64.go b/contrib/go/_std_1.23/src/syscall/ztypes_darwin_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_darwin_amd64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_darwin_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_darwin_arm64.go b/contrib/go/_std_1.23/src/syscall/ztypes_darwin_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_darwin_arm64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_darwin_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_dragonfly_amd64.go b/contrib/go/_std_1.23/src/syscall/ztypes_dragonfly_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_dragonfly_amd64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_dragonfly_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_freebsd_386.go b/contrib/go/_std_1.23/src/syscall/ztypes_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_freebsd_386.go rename to contrib/go/_std_1.23/src/syscall/ztypes_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_freebsd_amd64.go b/contrib/go/_std_1.23/src/syscall/ztypes_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_freebsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_freebsd_arm.go b/contrib/go/_std_1.23/src/syscall/ztypes_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_freebsd_arm.go rename to contrib/go/_std_1.23/src/syscall/ztypes_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_freebsd_arm64.go b/contrib/go/_std_1.23/src/syscall/ztypes_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_freebsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_freebsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/ztypes_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_386.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_386.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_386.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_amd64.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_amd64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_arm.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_arm.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_arm64.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_arm64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_loong64.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_loong64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_loong64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_mips.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_mips.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_mips.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_mips.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_mips64.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_mips64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_mips64le.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_mips64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_mips64le.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_mips64le.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_mipsle.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_mipsle.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_mipsle.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_mipsle.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_ppc64.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_ppc64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_ppc64le.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_ppc64le.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_ppc64le.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_riscv64.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_riscv64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_linux_s390x.go b/contrib/go/_std_1.23/src/syscall/ztypes_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_linux_s390x.go rename to contrib/go/_std_1.23/src/syscall/ztypes_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_netbsd_386.go b/contrib/go/_std_1.23/src/syscall/ztypes_netbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_netbsd_386.go rename to contrib/go/_std_1.23/src/syscall/ztypes_netbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_netbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/ztypes_netbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_netbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_netbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_netbsd_arm.go b/contrib/go/_std_1.23/src/syscall/ztypes_netbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_netbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/ztypes_netbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_netbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/ztypes_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_netbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_openbsd_386.go b/contrib/go/_std_1.23/src/syscall/ztypes_openbsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_openbsd_386.go rename to contrib/go/_std_1.23/src/syscall/ztypes_openbsd_386.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_openbsd_amd64.go b/contrib/go/_std_1.23/src/syscall/ztypes_openbsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_openbsd_amd64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_openbsd_amd64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_openbsd_arm.go b/contrib/go/_std_1.23/src/syscall/ztypes_openbsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_openbsd_arm.go rename to contrib/go/_std_1.23/src/syscall/ztypes_openbsd_arm.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_openbsd_arm64.go b/contrib/go/_std_1.23/src/syscall/ztypes_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_openbsd_arm64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_openbsd_mips64.go b/contrib/go/_std_1.23/src/syscall/ztypes_openbsd_mips64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_openbsd_mips64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_openbsd_mips64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_openbsd_ppc64.go b/contrib/go/_std_1.23/src/syscall/ztypes_openbsd_ppc64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_openbsd_ppc64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_openbsd_ppc64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_openbsd_riscv64.go b/contrib/go/_std_1.23/src/syscall/ztypes_openbsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_openbsd_riscv64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_openbsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/syscall/ztypes_solaris_amd64.go b/contrib/go/_std_1.23/src/syscall/ztypes_solaris_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/syscall/ztypes_solaris_amd64.go rename to contrib/go/_std_1.23/src/syscall/ztypes_solaris_amd64.go diff --git a/contrib/go/_std_1.22/src/text/tabwriter/tabwriter.go b/contrib/go/_std_1.23/src/text/tabwriter/tabwriter.go similarity index 96% rename from contrib/go/_std_1.22/src/text/tabwriter/tabwriter.go rename to contrib/go/_std_1.23/src/text/tabwriter/tabwriter.go index d4cfcf556a40..976ad251aaea 100644 --- a/contrib/go/_std_1.22/src/text/tabwriter/tabwriter.go +++ b/contrib/go/_std_1.23/src/text/tabwriter/tabwriter.go @@ -12,6 +12,7 @@ package tabwriter import ( + "fmt" "io" "unicode/utf8" ) @@ -59,7 +60,7 @@ type cell struct { // this may not be true in some fonts or if the string contains combining // characters. // -// If DiscardEmptyColumns is set, empty columns that are terminated +// If [DiscardEmptyColumns] is set, empty columns that are terminated // entirely by vertical (or "soft") tabs are discarded. Columns // terminated by horizontal (or "hard") tabs are not affected by // this flag. @@ -68,24 +69,24 @@ type cell struct { // are passed through. The widths of tags and entities are // assumed to be zero (tags) and one (entities) for formatting purposes. // -// A segment of text may be escaped by bracketing it with Escape +// A segment of text may be escaped by bracketing it with [Escape] // characters. The tabwriter passes escaped text segments through // unchanged. In particular, it does not interpret any tabs or line -// breaks within the segment. If the StripEscape flag is set, the +// breaks within the segment. If the [StripEscape] flag is set, the // Escape characters are stripped from the output; otherwise they // are passed through as well. For the purpose of formatting, the // width of the escaped text is always computed excluding the Escape // characters. // // The formfeed character acts like a newline but it also terminates -// all columns in the current line (effectively calling Flush). Tab- +// all columns in the current line (effectively calling [Writer.Flush]). Tab- // terminated cells in the next line start new columns. Unless found // inside an HTML tag or inside an escaped text segment, formfeed // characters appear as newlines in the output. // // The Writer must buffer input internally, because proper spacing // of one line may depend on the cells in future lines. Clients must -// call Flush when done calling Write. +// call Flush when done calling [Writer.Write]. type Writer struct { // configuration output io.Writer @@ -192,7 +193,7 @@ const ( Debug ) -// A Writer must be initialized with a call to Init. The first parameter (output) +// A [Writer] must be initialized with a call to Init. The first parameter (output) // specifies the filter output. The remaining parameters control the formatting: // // minwidth minimal cell width including any padding @@ -476,12 +477,12 @@ func (b *Writer) handlePanic(err *error, op string) { *err = nerr.err return } - panic("tabwriter: panic during " + op) + panic(fmt.Sprintf("tabwriter: panic during %s (%v)", op, e)) } } -// Flush should be called after the last call to Write to ensure -// that any data buffered in the Writer is written to output. Any +// Flush should be called after the last call to [Writer.Write] to ensure +// that any data buffered in the [Writer] is written to output. Any // incomplete escape sequence at the end is considered // complete for formatting purposes. func (b *Writer) Flush() error { @@ -593,7 +594,7 @@ func (b *Writer) Write(buf []byte) (n int, err error) { return } -// NewWriter allocates and initializes a new tabwriter.Writer. +// NewWriter allocates and initializes a new [Writer]. // The parameters are the same as for the Init function. func NewWriter(output io.Writer, minwidth, tabwidth, padding int, padchar byte, flags uint) *Writer { return new(Writer).Init(output, minwidth, tabwidth, padding, padchar, flags) diff --git a/contrib/go/_std_1.22/src/text/tabwriter/ya.make b/contrib/go/_std_1.23/src/text/tabwriter/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/text/tabwriter/ya.make rename to contrib/go/_std_1.23/src/text/tabwriter/ya.make diff --git a/contrib/go/_std_1.22/src/text/template/doc.go b/contrib/go/_std_1.23/src/text/template/doc.go similarity index 98% rename from contrib/go/_std_1.22/src/text/template/doc.go rename to contrib/go/_std_1.23/src/text/template/doc.go index 032784bc3f0c..b3ffaabb153c 100644 --- a/contrib/go/_std_1.22/src/text/template/doc.go +++ b/contrib/go/_std_1.23/src/text/template/doc.go @@ -144,6 +144,13 @@ data, defined in detail in the corresponding sections that follow. is executed; otherwise, dot is set to the value of the pipeline and T1 is executed. + {{with pipeline}} T1 {{else with pipeline}} T0 {{end}} + To simplify the appearance of with-else chains, the else action + of a with may include another with directly; the effect is exactly + the same as writing + {{with pipeline}} T1 {{else}}{{with pipeline}} T0 {{end}}{{end}} + + Arguments An argument is a simple value, denoted by one of the following. diff --git a/contrib/go/_std_1.22/src/text/template/exec.go b/contrib/go/_std_1.23/src/text/template/exec.go similarity index 98% rename from contrib/go/_std_1.22/src/text/template/exec.go rename to contrib/go/_std_1.23/src/text/template/exec.go index 2b778fff696f..5b35b3e5a85b 100644 --- a/contrib/go/_std_1.22/src/text/template/exec.go +++ b/contrib/go/_std_1.23/src/text/template/exec.go @@ -201,8 +201,8 @@ func (t *Template) ExecuteTemplate(wr io.Writer, name string, data any) error { // A template may be executed safely in parallel, although if parallel // executions share a Writer the output may be interleaved. // -// If data is a reflect.Value, the template applies to the concrete -// value that the reflect.Value holds, as in fmt.Print. +// If data is a [reflect.Value], the template applies to the concrete +// value that the reflect.Value holds, as in [fmt.Print]. func (t *Template) Execute(wr io.Writer, data any) error { return t.execute(wr, data) } @@ -228,7 +228,7 @@ func (t *Template) execute(wr io.Writer, data any) (err error) { // DefinedTemplates returns a string listing the defined templates, // prefixed by the string "; defined templates are: ". If there are none, // it returns the empty string. For generating an error message here -// and in html/template. +// and in [html/template]. func (t *Template) DefinedTemplates() string { if t.common == nil { return "" @@ -408,8 +408,8 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) { break } om := fmtsort.Sort(val) - for i, key := range om.Key { - oneIteration(key, om.Value[i]) + for _, m := range om { + oneIteration(m.Key, m.Value) } return case reflect.Chan: @@ -479,7 +479,7 @@ func (s *state) evalPipeline(dot reflect.Value, pipe *parse.PipeNode) (value ref value = s.evalCommand(dot, cmd, value) // previous value is this one's final arg. // If the object has type interface{}, dig down one level to the thing inside. if value.Kind() == reflect.Interface && value.Type().NumMethod() == 0 { - value = reflect.ValueOf(value.Interface()) // lovely! + value = value.Elem() } } for _, variable := range pipe.Decl { @@ -734,9 +734,8 @@ func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node } else if numIn != typ.NumIn() { s.errorf("wrong number of args for %s: want %d got %d", name, typ.NumIn(), numIn) } - if !goodFunc(typ) { - // TODO: This could still be a confusing error; maybe goodFunc should provide info. - s.errorf("can't call method/function %q with %d results", name, typ.NumOut()) + if err := goodFunc(name, typ); err != nil { + s.errorf("%v", err) } unwrap := func(v reflect.Value) reflect.Value { @@ -800,6 +799,15 @@ func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node } argv[i] = s.validateType(final, t) } + + // Special case for the "call" builtin. + // Insert the name of the callee function as the first argument. + if isBuiltin && name == "call" { + calleeName := args[0].String() + argv = append([]reflect.Value{reflect.ValueOf(calleeName)}, argv...) + fun = reflect.ValueOf(call) + } + v, err := safeCall(fun, argv) // If we have an error that is not nil, stop execution and return that // error to the caller. diff --git a/contrib/go/_std_1.22/src/text/template/funcs.go b/contrib/go/_std_1.23/src/text/template/funcs.go similarity index 93% rename from contrib/go/_std_1.22/src/text/template/funcs.go rename to contrib/go/_std_1.23/src/text/template/funcs.go index a949f896fa3d..7d63cf8b7bb6 100644 --- a/contrib/go/_std_1.22/src/text/template/funcs.go +++ b/contrib/go/_std_1.23/src/text/template/funcs.go @@ -22,14 +22,14 @@ import ( // return value evaluates to non-nil during execution, execution terminates and // Execute returns that error. // -// Errors returned by Execute wrap the underlying error; call errors.As to +// Errors returned by Execute wrap the underlying error; call [errors.As] to // unwrap them. // // When template execution invokes a function with an argument list, that list // must be assignable to the function's parameter types. Functions meant to // apply to arguments of arbitrary type can use parameters of type interface{} or -// of type reflect.Value. Similarly, functions meant to return a result of arbitrary -// type can return interface{} or reflect.Value. +// of type [reflect.Value]. Similarly, functions meant to return a result of arbitrary +// type can return interface{} or [reflect.Value]. type FuncMap map[string]any // builtins returns the FuncMap. @@ -39,7 +39,7 @@ type FuncMap map[string]any func builtins() FuncMap { return FuncMap{ "and": and, - "call": call, + "call": emptyCall, "html": HTMLEscaper, "index": index, "slice": slice, @@ -93,8 +93,8 @@ func addValueFuncs(out map[string]reflect.Value, in FuncMap) { if v.Kind() != reflect.Func { panic("value for " + name + " not a function") } - if !goodFunc(v.Type()) { - panic(fmt.Errorf("can't install method/function %q with %d results", name, v.Type().NumOut())) + if err := goodFunc(name, v.Type()); err != nil { + panic(err) } out[name] = v } @@ -109,15 +109,18 @@ func addFuncs(out, in FuncMap) { } // goodFunc reports whether the function or method has the right result signature. -func goodFunc(typ reflect.Type) bool { +func goodFunc(name string, typ reflect.Type) error { // We allow functions with 1 result or 2 results where the second is an error. - switch { - case typ.NumOut() == 1: - return true - case typ.NumOut() == 2 && typ.Out(1) == errorType: - return true + switch numOut := typ.NumOut(); { + case numOut == 1: + return nil + case numOut == 2 && typ.Out(1) == errorType: + return nil + case numOut == 2: + return fmt.Errorf("invalid function signature for %s: second return value should be error; is %s", name, typ.Out(1)) + default: + return fmt.Errorf("function %s has %d return values; should be 1 or 2", name, typ.NumOut()) } - return false } // goodName reports whether the function name is a valid identifier. @@ -309,30 +312,35 @@ func length(item reflect.Value) (int, error) { // Function invocation +func emptyCall(fn reflect.Value, args ...reflect.Value) reflect.Value { + panic("unreachable") // implemented as a special case in evalCall +} + // call returns the result of evaluating the first argument as a function. // The function must return 1 result, or 2 results, the second of which is an error. -func call(fn reflect.Value, args ...reflect.Value) (reflect.Value, error) { +func call(name string, fn reflect.Value, args ...reflect.Value) (reflect.Value, error) { fn = indirectInterface(fn) if !fn.IsValid() { return reflect.Value{}, fmt.Errorf("call of nil") } typ := fn.Type() if typ.Kind() != reflect.Func { - return reflect.Value{}, fmt.Errorf("non-function of type %s", typ) + return reflect.Value{}, fmt.Errorf("non-function %s of type %s", name, typ) } - if !goodFunc(typ) { - return reflect.Value{}, fmt.Errorf("function called with %d args; should be 1 or 2", typ.NumOut()) + + if err := goodFunc(name, typ); err != nil { + return reflect.Value{}, err } numIn := typ.NumIn() var dddType reflect.Type if typ.IsVariadic() { if len(args) < numIn-1 { - return reflect.Value{}, fmt.Errorf("wrong number of args: got %d want at least %d", len(args), numIn-1) + return reflect.Value{}, fmt.Errorf("wrong number of args for %s: got %d want at least %d", name, len(args), numIn-1) } dddType = typ.In(numIn - 1).Elem() } else { if len(args) != numIn { - return reflect.Value{}, fmt.Errorf("wrong number of args: got %d want %d", len(args), numIn) + return reflect.Value{}, fmt.Errorf("wrong number of args for %s: got %d want %d", name, len(args), numIn) } } argv := make([]reflect.Value, len(args)) diff --git a/contrib/go/_std_1.22/src/text/template/helper.go b/contrib/go/_std_1.23/src/text/template/helper.go similarity index 80% rename from contrib/go/_std_1.22/src/text/template/helper.go rename to contrib/go/_std_1.23/src/text/template/helper.go index 48af3928b39d..81b55538e57c 100644 --- a/contrib/go/_std_1.22/src/text/template/helper.go +++ b/contrib/go/_std_1.23/src/text/template/helper.go @@ -16,7 +16,7 @@ import ( // Functions and methods to parse templates. -// Must is a helper that wraps a call to a function returning (*Template, error) +// Must is a helper that wraps a call to a function returning ([*Template], error) // and panics if the error is non-nil. It is intended for use in variable // initializations such as // @@ -28,7 +28,7 @@ func Must(t *Template, err error) *Template { return t } -// ParseFiles creates a new Template and parses the template definitions from +// ParseFiles creates a new [Template] and parses the template definitions from // the named files. The returned template's name will have the base name and // parsed contents of the first file. There must be at least one file. // If an error occurs, parsing stops and the returned *Template is nil. @@ -45,9 +45,9 @@ func ParseFiles(filenames ...string) (*Template, error) { // t. If an error occurs, parsing stops and the returned template is nil; // otherwise it is t. There must be at least one file. // Since the templates created by ParseFiles are named by the base -// names of the argument files, t should usually have the name of one -// of the (base) names of the files. If it does not, depending on t's -// contents before calling ParseFiles, t.Execute may fail. In that +// (see [filepath.Base]) names of the argument files, t should usually have the +// name of one of the (base) names of the files. If it does not, depending on +// t's contents before calling ParseFiles, t.Execute may fail. In that // case use t.ExecuteTemplate to execute a valid template. // // When parsing multiple files with the same name in different directories, @@ -93,12 +93,12 @@ func parseFiles(t *Template, readFile func(string) (string, []byte, error), file return t, nil } -// ParseGlob creates a new Template and parses the template definitions from +// ParseGlob creates a new [Template] and parses the template definitions from // the files identified by the pattern. The files are matched according to the -// semantics of filepath.Match, and the pattern must match at least one file. -// The returned template will have the (base) name and (parsed) contents of the -// first file matched by the pattern. ParseGlob is equivalent to calling -// ParseFiles with the list of files matched by the pattern. +// semantics of [filepath.Match], and the pattern must match at least one file. +// The returned template will have the [filepath.Base] name and (parsed) +// contents of the first file matched by the pattern. ParseGlob is equivalent to +// calling [ParseFiles] with the list of files matched by the pattern. // // When parsing multiple files with the same name in different directories, // the last one mentioned will be the one that results. @@ -108,9 +108,9 @@ func ParseGlob(pattern string) (*Template, error) { // ParseGlob parses the template definitions in the files identified by the // pattern and associates the resulting templates with t. The files are matched -// according to the semantics of filepath.Match, and the pattern must match at -// least one file. ParseGlob is equivalent to calling t.ParseFiles with the -// list of files matched by the pattern. +// according to the semantics of [filepath.Match], and the pattern must match at +// least one file. ParseGlob is equivalent to calling [Template.ParseFiles] with +// the list of files matched by the pattern. // // When parsing multiple files with the same name in different directories, // the last one mentioned will be the one that results. @@ -131,17 +131,17 @@ func parseGlob(t *Template, pattern string) (*Template, error) { return parseFiles(t, readFileOS, filenames...) } -// ParseFS is like ParseFiles or ParseGlob but reads from the file system fsys +// ParseFS is like [Template.ParseFiles] or [Template.ParseGlob] but reads from the file system fsys // instead of the host operating system's file system. -// It accepts a list of glob patterns. +// It accepts a list of glob patterns (see [path.Match]). // (Note that most file names serve as glob patterns matching only themselves.) func ParseFS(fsys fs.FS, patterns ...string) (*Template, error) { return parseFS(nil, fsys, patterns) } -// ParseFS is like ParseFiles or ParseGlob but reads from the file system fsys +// ParseFS is like [Template.ParseFiles] or [Template.ParseGlob] but reads from the file system fsys // instead of the host operating system's file system. -// It accepts a list of glob patterns. +// It accepts a list of glob patterns (see [path.Match]). // (Note that most file names serve as glob patterns matching only themselves.) func (t *Template) ParseFS(fsys fs.FS, patterns ...string) (*Template, error) { t.init() diff --git a/contrib/go/_std_1.22/src/text/template/option.go b/contrib/go/_std_1.23/src/text/template/option.go similarity index 100% rename from contrib/go/_std_1.22/src/text/template/option.go rename to contrib/go/_std_1.23/src/text/template/option.go diff --git a/contrib/go/_std_1.22/src/text/template/parse/lex.go b/contrib/go/_std_1.23/src/text/template/parse/lex.go similarity index 100% rename from contrib/go/_std_1.22/src/text/template/parse/lex.go rename to contrib/go/_std_1.23/src/text/template/parse/lex.go diff --git a/contrib/go/_std_1.22/src/text/template/parse/node.go b/contrib/go/_std_1.23/src/text/template/parse/node.go similarity index 98% rename from contrib/go/_std_1.22/src/text/template/parse/node.go rename to contrib/go/_std_1.23/src/text/template/parse/node.go index c36688825c20..a31309874d9d 100644 --- a/contrib/go/_std_1.22/src/text/template/parse/node.go +++ b/contrib/go/_std_1.23/src/text/template/parse/node.go @@ -217,7 +217,11 @@ func (p *PipeNode) writeTo(sb *strings.Builder) { } v.writeTo(sb) } - sb.WriteString(" := ") + if p.IsAssign { + sb.WriteString(" = ") + } else { + sb.WriteString(" := ") + } } for i, c := range p.Cmds { if i > 0 { @@ -346,12 +350,12 @@ type IdentifierNode struct { Ident string // The identifier's name. } -// NewIdentifier returns a new IdentifierNode with the given identifier name. +// NewIdentifier returns a new [IdentifierNode] with the given identifier name. func NewIdentifier(ident string) *IdentifierNode { return &IdentifierNode{NodeType: NodeIdentifier, Ident: ident} } -// SetPos sets the position. NewIdentifier is a public method so we can't modify its signature. +// SetPos sets the position. [NewIdentifier] is a public method so we can't modify its signature. // Chained for convenience. // TODO: fix one day? func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode { @@ -359,7 +363,7 @@ func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode { return i } -// SetTree sets the parent tree for the node. NewIdentifier is a public method so we can't modify its signature. +// SetTree sets the parent tree for the node. [NewIdentifier] is a public method so we can't modify its signature. // Chained for convenience. // TODO: fix one day? func (i *IdentifierNode) SetTree(t *Tree) *IdentifierNode { diff --git a/contrib/go/_std_1.22/src/text/template/parse/parse.go b/contrib/go/_std_1.23/src/text/template/parse/parse.go similarity index 92% rename from contrib/go/_std_1.22/src/text/template/parse/parse.go rename to contrib/go/_std_1.23/src/text/template/parse/parse.go index d43d5334ba04..27c84f31eb3a 100644 --- a/contrib/go/_std_1.22/src/text/template/parse/parse.go +++ b/contrib/go/_std_1.23/src/text/template/parse/parse.go @@ -42,7 +42,7 @@ const ( SkipFuncCheck // do not check that functions are defined ) -// Copy returns a copy of the Tree. Any parsing state is discarded. +// Copy returns a copy of the [Tree]. Any parsing state is discarded. func (t *Tree) Copy() *Tree { if t == nil { return nil @@ -55,7 +55,7 @@ func (t *Tree) Copy() *Tree { } } -// Parse returns a map from template name to parse.Tree, created by parsing the +// Parse returns a map from template name to [Tree], created by parsing the // templates described in the argument string. The top-level template will be // given the specified name. If an error is encountered, parsing stops and an // empty map is returned with the error. @@ -521,7 +521,7 @@ func (t *Tree) checkPipeline(pipe *PipeNode, context string) { } } -func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) { +func (t *Tree) parseControl(context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) { defer t.popVars(len(t.vars)) pipe = t.pipeline(context, itemRightDelim) if context == "range" { @@ -535,27 +535,30 @@ func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int switch next.Type() { case nodeEnd: //done case nodeElse: - if allowElseIf { - // Special case for "else if". If the "else" is followed immediately by an "if", - // the elseControl will have left the "if" token pending. Treat - // {{if a}}_{{else if b}}_{{end}} - // as - // {{if a}}_{{else}}{{if b}}_{{end}}{{end}}. - // To do this, parse the if as usual and stop at it {{end}}; the subsequent{{end}} - // is assumed. This technique works even for long if-else-if chains. - // TODO: Should we allow else-if in with and range? - if t.peek().typ == itemIf { - t.next() // Consume the "if" token. - elseList = t.newList(next.Position()) - elseList.append(t.ifControl()) - // Do not consume the next item - only one {{end}} required. - break + // Special case for "else if" and "else with". + // If the "else" is followed immediately by an "if" or "with", + // the elseControl will have left the "if" or "with" token pending. Treat + // {{if a}}_{{else if b}}_{{end}} + // {{with a}}_{{else with b}}_{{end}} + // as + // {{if a}}_{{else}}{{if b}}_{{end}}{{end}} + // {{with a}}_{{else}}{{with b}}_{{end}}{{end}}. + // To do this, parse the "if" or "with" as usual and stop at it {{end}}; + // the subsequent{{end}} is assumed. This technique works even for long if-else-if chains. + if context == "if" && t.peek().typ == itemIf { + t.next() // Consume the "if" token. + elseList = t.newList(next.Position()) + elseList.append(t.ifControl()) + } else if context == "with" && t.peek().typ == itemWith { + t.next() + elseList = t.newList(next.Position()) + elseList.append(t.withControl()) + } else { + elseList, next = t.itemList() + if next.Type() != nodeEnd { + t.errorf("expected end; found %s", next) } } - elseList, next = t.itemList() - if next.Type() != nodeEnd { - t.errorf("expected end; found %s", next) - } } return pipe.Position(), pipe.Line, pipe, list, elseList } @@ -567,7 +570,7 @@ func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int // // If keyword is past. func (t *Tree) ifControl() Node { - return t.newIf(t.parseControl(true, "if")) + return t.newIf(t.parseControl("if")) } // Range: @@ -577,7 +580,7 @@ func (t *Tree) ifControl() Node { // // Range keyword is past. func (t *Tree) rangeControl() Node { - r := t.newRange(t.parseControl(false, "range")) + r := t.newRange(t.parseControl("range")) return r } @@ -588,7 +591,7 @@ func (t *Tree) rangeControl() Node { // // If keyword is past. func (t *Tree) withControl() Node { - return t.newWith(t.parseControl(false, "with")) + return t.newWith(t.parseControl("with")) } // End: @@ -606,10 +609,11 @@ func (t *Tree) endControl() Node { // // Else keyword is past. func (t *Tree) elseControl() Node { - // Special case for "else if". peek := t.peekNonSpace() - if peek.typ == itemIf { - // We see "{{else if ... " but in effect rewrite it to {{else}}{{if ... ". + // The "{{else if ... " and "{{else with ..." will be + // treated as "{{else}}{{if ..." and "{{else}}{{with ...". + // So return the else node here. + if peek.typ == itemIf || peek.typ == itemWith { return t.newElse(peek.pos, peek.line) } token := t.expect(itemRightDelim, "else") diff --git a/contrib/go/_std_1.22/src/text/template/parse/ya.make b/contrib/go/_std_1.23/src/text/template/parse/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/text/template/parse/ya.make rename to contrib/go/_std_1.23/src/text/template/parse/ya.make diff --git a/contrib/go/_std_1.22/src/text/template/template.go b/contrib/go/_std_1.23/src/text/template/template.go similarity index 96% rename from contrib/go/_std_1.22/src/text/template/template.go rename to contrib/go/_std_1.23/src/text/template/template.go index 776be9cd075d..86fd3f122a12 100644 --- a/contrib/go/_std_1.22/src/text/template/template.go +++ b/contrib/go/_std_1.23/src/text/template/template.go @@ -24,7 +24,7 @@ type common struct { } // Template is the representation of a parsed template. The *parse.Tree -// field is exported only for use by html/template and should be treated +// field is exported only for use by [html/template] and should be treated // as unexported by all other clients. type Template struct { name string @@ -79,7 +79,7 @@ func (t *Template) init() { // Clone returns a duplicate of the template, including all associated // templates. The actual representation is not copied, but the name space of -// associated templates is, so further calls to Parse in the copy will add +// associated templates is, so further calls to [Template.Parse] in the copy will add // templates to the copy but not to the original. Clone can be used to prepare // common templates and use them with variant definitions for other templates // by adding the variants after the clone is made. @@ -157,7 +157,7 @@ func (t *Template) Templates() []*Template { } // Delims sets the action delimiters to the specified strings, to be used in -// subsequent calls to Parse, ParseFiles, or ParseGlob. Nested template +// subsequent calls to [Template.Parse], [Template.ParseFiles], or [Template.ParseGlob]. Nested template // definitions will inherit the settings. An empty delimiter stands for the // corresponding default: {{ or }}. // The return value is the template, so calls can be chained. diff --git a/contrib/go/_std_1.22/src/text/template/ya.make b/contrib/go/_std_1.23/src/text/template/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/text/template/ya.make rename to contrib/go/_std_1.23/src/text/template/ya.make diff --git a/contrib/go/_std_1.22/src/time/embed.go b/contrib/go/_std_1.23/src/time/embed.go similarity index 100% rename from contrib/go/_std_1.22/src/time/embed.go rename to contrib/go/_std_1.23/src/time/embed.go diff --git a/contrib/go/_std_1.22/src/time/format.go b/contrib/go/_std_1.23/src/time/format.go similarity index 94% rename from contrib/go/_std_1.22/src/time/format.go rename to contrib/go/_std_1.23/src/time/format.go index 7fbeddb54065..c9e68b3eb254 100644 --- a/contrib/go/_std_1.22/src/time/format.go +++ b/contrib/go/_std_1.23/src/time/format.go @@ -4,15 +4,19 @@ package time -import "errors" +import ( + "errors" + "internal/stringslite" + _ "unsafe" // for linkname +) -// These are predefined layouts for use in Time.Format and time.Parse. +// These are predefined layouts for use in [Time.Format] and [time.Parse]. // The reference time used in these layouts is the specific time stamp: // // 01/02 03:04:05PM '06 -0700 // // (January 2, 15:04:05, 2006, in time zone seven hours west of GMT). -// That value is recorded as the constant named Layout, listed below. As a Unix +// That value is recorded as the constant named [Layout], listed below. As a Unix // time, this is 1136239445. Since MST is GMT-0700, the reference would be // printed by the Unix date command as: // @@ -24,16 +28,20 @@ import "errors" // The example for Time.Format demonstrates the working of the layout string // in detail and is a good reference. // -// Note that the RFC822, RFC850, and RFC1123 formats should be applied +// Note that the [RFC822], [RFC850], and [RFC1123] formats should be applied // only to local times. Applying them to UTC times will use "UTC" as the // time zone abbreviation, while strictly speaking those RFCs require the // use of "GMT" in that case. -// In general RFC1123Z should be used instead of RFC1123 for servers -// that insist on that format, and RFC3339 should be preferred for new protocols. -// RFC3339, RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for formatting; +// When using the [RFC1123] or [RFC1123Z] formats for parsing, note that these +// formats define a leading zero for the day-in-month portion, which is not +// strictly allowed by RFC 1123. This will result in an error when parsing +// date strings that occur in the first 9 days of a given month. +// In general [RFC1123Z] should be used instead of [RFC1123] for servers +// that insist on that format, and [RFC3339] should be preferred for new protocols. +// [RFC3339], [RFC822], [RFC822Z], [RFC1123], and [RFC1123Z] are useful for formatting; // when used with time.Parse they do not accept all the time formats // permitted by the RFCs and they do accept time formats not formally defined. -// The RFC3339Nano format removes trailing zeros from the seconds field +// The [RFC3339Nano] format removes trailing zeros from the seconds field // and thus may not sort correctly once formatted. // // Most programs can use one of the defined constants as the layout passed to @@ -41,8 +49,8 @@ import "errors" // creating a custom layout string. // // To define your own format, write down what the reference time would look like -// formatted your way; see the values of constants like ANSIC, StampMicro or -// Kitchen for examples. The model is to demonstrate what the reference time +// formatted your way; see the values of constants like [ANSIC], [StampMicro] or +// [Kitchen] for examples. The model is to demonstrate what the reference time // looks like so that the Format and Parse methods can apply the same // transformation to a general time value. // @@ -181,6 +189,16 @@ func startsWithLowerCase(str string) bool { // nextStdChunk finds the first occurrence of a std string in // layout and returns the text before, the std string, and the text after. +// +// nextStdChunk should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/searKing/golang/go +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname nextStdChunk func nextStdChunk(layout string) (prefix string, std int, suffix string) { for i := 0; i < len(layout); i++ { switch c := int(layout[i]); c { @@ -553,7 +571,7 @@ func (t Time) String() string { return s } -// GoString implements fmt.GoStringer and formats t to be printed in Go source +// GoString implements [fmt.GoStringer] and formats t to be printed in Go source // code. func (t Time) GoString() string { abs := t.abs() @@ -613,9 +631,9 @@ func (t Time) GoString() string { // Format returns a textual representation of the time value formatted according // to the layout defined by the argument. See the documentation for the -// constant called Layout to see how to represent the layout format. +// constant called [Layout] to see how to represent the layout format. // -// The executable example for Time.Format demonstrates the working +// The executable example for [Time.Format] demonstrates the working // of the layout string in detail and is a good reference. func (t Time) Format(layout string) string { const bufSize = 64 @@ -631,7 +649,7 @@ func (t Time) Format(layout string) string { return string(b) } -// AppendFormat is like Format but appends the textual +// AppendFormat is like [Time.Format] but appends the textual // representation to b and returns the extended buffer. func (t Time) AppendFormat(b []byte, layout string) []byte { // Optimize for RFC3339 as it accounts for over half of all representations. @@ -827,17 +845,11 @@ type ParseError struct { // newParseError creates a new ParseError. // The provided value and valueElem are cloned to avoid escaping their values. func newParseError(layout, value, layoutElem, valueElem, message string) *ParseError { - valueCopy := cloneString(value) - valueElemCopy := cloneString(valueElem) + valueCopy := stringslite.Clone(value) + valueElemCopy := stringslite.Clone(valueElem) return &ParseError{layout, valueCopy, layoutElem, valueElemCopy, message} } -// cloneString returns a string copy of s. -// Do not use strings.Clone to avoid dependency on strings package. -func cloneString(s string) string { - return string([]byte(s)) -} - // These are borrowed from unicode/utf8 and strconv and replicate behavior in // that package, since we can't take a dependency on either. const ( @@ -963,11 +975,11 @@ func skip(value, prefix string) (string, error) { } // Parse parses a formatted string and returns the time value it represents. -// See the documentation for the constant called Layout to see how to +// See the documentation for the constant called [Layout] to see how to // represent the format. The second argument must be parseable using // the format string (layout) provided as the first argument. // -// The example for Time.Format demonstrates the working of the layout string +// The example for [Time.Format] demonstrates the working of the layout string // in detail and is a good reference. // // When parsing (only), the input may contain a fractional second @@ -991,7 +1003,7 @@ func skip(value, prefix string) (string, error) { // In the absence of a time zone indicator, Parse returns a time in UTC. // // When parsing a time with a zone offset like -0700, if the offset corresponds -// to a time zone used by the current location (Local), then Parse uses that +// to a time zone used by the current location ([Local]), then Parse uses that // location and zone in the returned time. Otherwise it records the time as // being in a fabricated location with time fixed at the given zone offset. // @@ -1003,7 +1015,7 @@ func skip(value, prefix string) (string, error) { // This choice means that such a time can be parsed and reformatted with the // same layout losslessly, but the exact instant used in the representation will // differ by the actual zone offset. To avoid such problems, prefer time layouts -// that use a numeric zone offset, or use ParseInLocation. +// that use a numeric zone offset, or use [ParseInLocation]. func Parse(layout, value string) (Time, error) { // Optimize for RFC3339 as it accounts for over half of all representations. if layout == RFC3339 || layout == RFC3339Nano { @@ -1191,12 +1203,14 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error) default: err = errBad } - case stdISO8601TZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ShortTZ, stdISO8601ColonSecondsTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ: - if (std == stdISO8601TZ || std == stdISO8601ShortTZ || std == stdISO8601ColonTZ) && len(value) >= 1 && value[0] == 'Z' { + case stdISO8601TZ, stdISO8601ShortTZ, stdISO8601ColonTZ, stdISO8601SecondsTZ, stdISO8601ColonSecondsTZ: + if len(value) >= 1 && value[0] == 'Z' { value = value[1:] z = UTC break } + fallthrough + case stdNumTZ, stdNumShortTZ, stdNumColonTZ, stdNumSecondsTz, stdNumColonSecondsTZ: var sign, hour, min, seconds string if std == stdISO8601ColonTZ || std == stdNumColonTZ { if len(value) < 6 { @@ -1245,6 +1259,20 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error) if err == nil { ss, _, err = getnum(seconds, true) } + + // The range test use > rather than >=, + // as some people do write offsets of 24 hours + // or 60 minutes or 60 seconds. + if hr > 24 { + rangeErrString = "time zone offset hour" + } + if mm > 60 { + rangeErrString = "time zone offset minute" + } + if ss > 60 { + rangeErrString = "time zone offset second" + } + zoneOffset = (hr*60+mm)*60 + ss // offset is in seconds switch sign[0] { case '+': @@ -1368,7 +1396,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error) } // Otherwise create fake zone to record offset. - zoneNameCopy := cloneString(zoneName) // avoid leaking the input value + zoneNameCopy := stringslite.Clone(zoneName) // avoid leaking the input value t.setLoc(FixedZone(zoneNameCopy, zoneOffset)) return t, nil } @@ -1389,7 +1417,7 @@ func parse(layout, value string, defaultLocation, local *Location) (Time, error) offset, _ = atoi(zoneName[3:]) // Guaranteed OK by parseGMT. offset *= 3600 } - zoneNameCopy := cloneString(zoneName) // avoid leaking the input value + zoneNameCopy := stringslite.Clone(zoneName) // avoid leaking the input value t.setLoc(FixedZone(zoneNameCopy, offset)) return t, nil } diff --git a/contrib/go/_std_1.22/src/time/format_rfc3339.go b/contrib/go/_std_1.23/src/time/format_rfc3339.go similarity index 100% rename from contrib/go/_std_1.22/src/time/format_rfc3339.go rename to contrib/go/_std_1.23/src/time/format_rfc3339.go diff --git a/contrib/go/_std_1.22/src/time/genzabbrs.go b/contrib/go/_std_1.23/src/time/genzabbrs.go similarity index 96% rename from contrib/go/_std_1.22/src/time/genzabbrs.go rename to contrib/go/_std_1.23/src/time/genzabbrs.go index 7dbd22f4ea3f..765771782551 100644 --- a/contrib/go/_std_1.22/src/time/genzabbrs.go +++ b/contrib/go/_std_1.23/src/time/genzabbrs.go @@ -21,7 +21,8 @@ import ( "log" "net/http" "os" - "sort" + "slices" + "strings" "text/template" "time" ) @@ -109,8 +110,8 @@ func main() { if err != nil { log.Fatal(err) } - sort.Slice(zs, func(i, j int) bool { - return zs[i].UnixName < zs[j].UnixName + slices.SortFunc(zs, func(a, b *zone) int { + return strings.Compare(a.UnixName, b.UnixName) }) var v = struct { URL string diff --git a/contrib/go/_std_1.23/src/time/sleep.go b/contrib/go/_std_1.23/src/time/sleep.go new file mode 100644 index 000000000000..7e2fa0c20af4 --- /dev/null +++ b/contrib/go/_std_1.23/src/time/sleep.go @@ -0,0 +1,216 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package time + +import ( + "internal/godebug" + "unsafe" +) + +// Sleep pauses the current goroutine for at least the duration d. +// A negative or zero duration causes Sleep to return immediately. +func Sleep(d Duration) + +var asynctimerchan = godebug.New("asynctimerchan") + +// syncTimer returns c as an unsafe.Pointer, for passing to newTimer. +// If the GODEBUG asynctimerchan has disabled the async timer chan +// code, then syncTimer always returns nil, to disable the special +// channel code paths in the runtime. +func syncTimer(c chan Time) unsafe.Pointer { + // If asynctimerchan=1, we don't even tell the runtime + // about channel timers, so that we get the pre-Go 1.23 code paths. + if asynctimerchan.Value() == "1" { + asynctimerchan.IncNonDefault() + return nil + } + + // Otherwise pass to runtime. + // This handles asynctimerchan=0, which is the default Go 1.23 behavior, + // as well as asynctimerchan=2, which is like asynctimerchan=1 + // but implemented entirely by the runtime. + // The only reason to use asynctimerchan=2 is for debugging + // a problem fixed by asynctimerchan=1: it enables the new + // GC-able timer channels (#61542) but not the sync channels (#37196). + // + // If we decide to roll back the sync channels, we will still have + // a fully tested async runtime implementation (asynctimerchan=2) + // and can make this function always return c. + // + // If we decide to keep the sync channels, we can delete all the + // handling of asynctimerchan in the runtime and keep just this + // function to handle asynctimerchan=1. + return *(*unsafe.Pointer)(unsafe.Pointer(&c)) +} + +// when is a helper function for setting the 'when' field of a runtimeTimer. +// It returns what the time will be, in nanoseconds, Duration d in the future. +// If d is negative, it is ignored. If the returned value would be less than +// zero because of an overflow, MaxInt64 is returned. +func when(d Duration) int64 { + if d <= 0 { + return runtimeNano() + } + t := runtimeNano() + int64(d) + if t < 0 { + // N.B. runtimeNano() and d are always positive, so addition + // (including overflow) will never result in t == 0. + t = 1<<63 - 1 // math.MaxInt64 + } + return t +} + +// These functions are pushed to package time from package runtime. + +// The arg cp is a chan Time, but the declaration in runtime uses a pointer, +// so we use a pointer here too. This keeps some tools that aggressively +// compare linknamed symbol definitions happier. +// +//go:linkname newTimer +func newTimer(when, period int64, f func(any, uintptr, int64), arg any, cp unsafe.Pointer) *Timer + +//go:linkname stopTimer +func stopTimer(*Timer) bool + +//go:linkname resetTimer +func resetTimer(t *Timer, when, period int64) bool + +// Note: The runtime knows the layout of struct Timer, since newTimer allocates it. +// The runtime also knows that Ticker and Timer have the same layout. +// There are extra fields after the channel, reserved for the runtime +// and inaccessible to users. + +// The Timer type represents a single event. +// When the Timer expires, the current time will be sent on C, +// unless the Timer was created by [AfterFunc]. +// A Timer must be created with [NewTimer] or AfterFunc. +type Timer struct { + C <-chan Time + initTimer bool +} + +// Stop prevents the [Timer] from firing. +// It returns true if the call stops the timer, false if the timer has already +// expired or been stopped. +// +// For a func-based timer created with [AfterFunc](d, f), +// if t.Stop returns false, then the timer has already expired +// and the function f has been started in its own goroutine; +// Stop does not wait for f to complete before returning. +// If the caller needs to know whether f is completed, +// it must coordinate with f explicitly. +// +// For a chan-based timer created with NewTimer(d), as of Go 1.23, +// any receive from t.C after Stop has returned is guaranteed to block +// rather than receive a stale time value from before the Stop; +// if the program has not received from t.C already and the timer is +// running, Stop is guaranteed to return true. +// Before Go 1.23, the only safe way to use Stop was insert an extra +// <-t.C if Stop returned false to drain a potential stale value. +// See the [NewTimer] documentation for more details. +func (t *Timer) Stop() bool { + if !t.initTimer { + panic("time: Stop called on uninitialized Timer") + } + return stopTimer(t) +} + +// NewTimer creates a new Timer that will send +// the current time on its channel after at least duration d. +// +// Before Go 1.23, the garbage collector did not recover +// timers that had not yet expired or been stopped, so code often +// immediately deferred t.Stop after calling NewTimer, to make +// the timer recoverable when it was no longer needed. +// As of Go 1.23, the garbage collector can recover unreferenced +// timers, even if they haven't expired or been stopped. +// The Stop method is no longer necessary to help the garbage collector. +// (Code may of course still want to call Stop to stop the timer for other reasons.) +// +// Before Go 1.23, the channel associated with a Timer was +// asynchronous (buffered, capacity 1), which meant that +// stale time values could be received even after [Timer.Stop] +// or [Timer.Reset] returned. +// As of Go 1.23, the channel is synchronous (unbuffered, capacity 0), +// eliminating the possibility of those stale values. +// +// The GODEBUG setting asynctimerchan=1 restores both pre-Go 1.23 +// behaviors: when set, unexpired timers won't be garbage collected, and +// channels will have buffered capacity. This setting may be removed +// in Go 1.27 or later. +func NewTimer(d Duration) *Timer { + c := make(chan Time, 1) + t := (*Timer)(newTimer(when(d), 0, sendTime, c, syncTimer(c))) + t.C = c + return t +} + +// Reset changes the timer to expire after duration d. +// It returns true if the timer had been active, false if the timer had +// expired or been stopped. +// +// For a func-based timer created with [AfterFunc](d, f), Reset either reschedules +// when f will run, in which case Reset returns true, or schedules f +// to run again, in which case it returns false. +// When Reset returns false, Reset neither waits for the prior f to +// complete before returning nor does it guarantee that the subsequent +// goroutine running f does not run concurrently with the prior +// one. If the caller needs to know whether the prior execution of +// f is completed, it must coordinate with f explicitly. +// +// For a chan-based timer created with NewTimer, as of Go 1.23, +// any receive from t.C after Reset has returned is guaranteed not +// to receive a time value corresponding to the previous timer settings; +// if the program has not received from t.C already and the timer is +// running, Reset is guaranteed to return true. +// Before Go 1.23, the only safe way to use Reset was to [Stop] and +// explicitly drain the timer first. +// See the [NewTimer] documentation for more details. +func (t *Timer) Reset(d Duration) bool { + if !t.initTimer { + panic("time: Reset called on uninitialized Timer") + } + w := when(d) + return resetTimer(t, w, 0) +} + +// sendTime does a non-blocking send of the current time on c. +func sendTime(c any, seq uintptr, delta int64) { + // delta is how long ago the channel send was supposed to happen. + // The current time can be arbitrarily far into the future, because the runtime + // can delay a sendTime call until a goroutines tries to receive from + // the channel. Subtract delta to go back to the old time that we + // used to send. + select { + case c.(chan Time) <- Now().Add(Duration(-delta)): + default: + } +} + +// After waits for the duration to elapse and then sends the current time +// on the returned channel. +// It is equivalent to [NewTimer](d).C. +// +// Before Go 1.23, this documentation warned that the underlying +// [Timer] would not be recovered by the garbage collector until the +// timer fired, and that if efficiency was a concern, code should use +// NewTimer instead and call [Timer.Stop] if the timer is no longer needed. +// As of Go 1.23, the garbage collector can recover unreferenced, +// unstopped timers. There is no reason to prefer NewTimer when After will do. +func After(d Duration) <-chan Time { + return NewTimer(d).C +} + +// AfterFunc waits for the duration to elapse and then calls f +// in its own goroutine. It returns a [Timer] that can +// be used to cancel the call using its Stop method. +// The returned Timer's C field is not used and will be nil. +func AfterFunc(d Duration, f func()) *Timer { + return (*Timer)(newTimer(when(d), 0, goFunc, f, nil)) +} + +func goFunc(arg any, seq uintptr, delta int64) { + go arg.(func())() +} diff --git a/contrib/go/_std_1.22/src/time/sys_plan9.go b/contrib/go/_std_1.23/src/time/sys_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/time/sys_plan9.go rename to contrib/go/_std_1.23/src/time/sys_plan9.go diff --git a/contrib/go/_std_1.22/src/time/sys_unix.go b/contrib/go/_std_1.23/src/time/sys_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/time/sys_unix.go rename to contrib/go/_std_1.23/src/time/sys_unix.go diff --git a/contrib/go/_std_1.22/src/time/sys_windows.go b/contrib/go/_std_1.23/src/time/sys_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/time/sys_windows.go rename to contrib/go/_std_1.23/src/time/sys_windows.go diff --git a/contrib/go/_std_1.23/src/time/tick.go b/contrib/go/_std_1.23/src/time/tick.go new file mode 100644 index 000000000000..057a9069ea51 --- /dev/null +++ b/contrib/go/_std_1.23/src/time/tick.go @@ -0,0 +1,91 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package time + +import "unsafe" + +// Note: The runtime knows the layout of struct Ticker, since newTimer allocates it. +// Note also that Ticker and Timer have the same layout, so that newTimer can handle both. +// The initTimer and initTicker fields are named differently so that +// users cannot convert between the two without unsafe. + +// A Ticker holds a channel that delivers “ticks” of a clock +// at intervals. +type Ticker struct { + C <-chan Time // The channel on which the ticks are delivered. + initTicker bool +} + +// NewTicker returns a new [Ticker] containing a channel that will send +// the current time on the channel after each tick. The period of the +// ticks is specified by the duration argument. The ticker will adjust +// the time interval or drop ticks to make up for slow receivers. +// The duration d must be greater than zero; if not, NewTicker will +// panic. +// +// Before Go 1.23, the garbage collector did not recover +// tickers that had not yet expired or been stopped, so code often +// immediately deferred t.Stop after calling NewTicker, to make +// the ticker recoverable when it was no longer needed. +// As of Go 1.23, the garbage collector can recover unreferenced +// tickers, even if they haven't been stopped. +// The Stop method is no longer necessary to help the garbage collector. +// (Code may of course still want to call Stop to stop the ticker for other reasons.) +func NewTicker(d Duration) *Ticker { + if d <= 0 { + panic("non-positive interval for NewTicker") + } + // Give the channel a 1-element time buffer. + // If the client falls behind while reading, we drop ticks + // on the floor until the client catches up. + c := make(chan Time, 1) + t := (*Ticker)(unsafe.Pointer(newTimer(when(d), int64(d), sendTime, c, syncTimer(c)))) + t.C = c + return t +} + +// Stop turns off a ticker. After Stop, no more ticks will be sent. +// Stop does not close the channel, to prevent a concurrent goroutine +// reading from the channel from seeing an erroneous "tick". +func (t *Ticker) Stop() { + if !t.initTicker { + // This is misuse, and the same for time.Timer would panic, + // but this didn't always panic, and we keep it not panicking + // to avoid breaking old programs. See issue 21874. + return + } + stopTimer((*Timer)(unsafe.Pointer(t))) +} + +// Reset stops a ticker and resets its period to the specified duration. +// The next tick will arrive after the new period elapses. The duration d +// must be greater than zero; if not, Reset will panic. +func (t *Ticker) Reset(d Duration) { + if d <= 0 { + panic("non-positive interval for Ticker.Reset") + } + if !t.initTicker { + panic("time: Reset called on uninitialized Ticker") + } + resetTimer((*Timer)(unsafe.Pointer(t)), when(d), int64(d)) +} + +// Tick is a convenience wrapper for [NewTicker] providing access to the ticking +// channel only. Unlike NewTicker, Tick will return nil if d <= 0. +// +// Before Go 1.23, this documentation warned that the underlying +// [Ticker] would never be recovered by the garbage collector, and that +// if efficiency was a concern, code should use NewTicker instead and +// call [Ticker.Stop] when the ticker is no longer needed. +// As of Go 1.23, the garbage collector can recover unreferenced +// tickers, even if they haven't been stopped. +// The Stop method is no longer necessary to help the garbage collector. +// There is no longer any reason to prefer NewTicker when Tick will do. +func Tick(d Duration) <-chan Time { + if d <= 0 { + return nil + } + return NewTicker(d).C +} diff --git a/contrib/go/_std_1.22/src/time/time.go b/contrib/go/_std_1.23/src/time/time.go similarity index 94% rename from contrib/go/_std_1.22/src/time/time.go rename to contrib/go/_std_1.23/src/time/time.go index 9d4c6e919e58..43efe4b11d0d 100644 --- a/contrib/go/_std_1.22/src/time/time.go +++ b/contrib/go/_std_1.23/src/time/time.go @@ -13,7 +13,7 @@ // changes for clock synchronization, and a “monotonic clock,” which is // not. The general rule is that the wall clock is for telling time and // the monotonic clock is for measuring time. Rather than split the API, -// in this package the Time returned by time.Now contains both a wall +// in this package the Time returned by [time.Now] contains both a wall // clock reading and a monotonic clock reading; later time-telling // operations use the wall clock reading, but later time-measuring // operations, specifically comparisons and subtractions, use the @@ -28,7 +28,7 @@ // t := time.Now() // elapsed := t.Sub(start) // -// Other idioms, such as time.Since(start), time.Until(deadline), and +// Other idioms, such as [time.Since](start), [time.Until](deadline), and // time.Now().Before(deadline), are similarly robust against wall clock // resets. // @@ -53,23 +53,26 @@ // // On some systems the monotonic clock will stop if the computer goes to sleep. // On such a system, t.Sub(u) may not accurately reflect the actual -// time that passed between t and u. +// time that passed between t and u. The same applies to other functions and +// methods that subtract times, such as [Since], [Until], [Before], [After], +// [Add], [Sub], [Equal] and [Compare]. In some cases, you may need to strip +// the monotonic clock to get accurate results. // // Because the monotonic clock reading has no meaning outside // the current process, the serialized forms generated by t.GobEncode, // t.MarshalBinary, t.MarshalJSON, and t.MarshalText omit the monotonic // clock reading, and t.Format provides no format for it. Similarly, the -// constructors time.Date, time.Parse, time.ParseInLocation, and time.Unix, +// constructors [time.Date], [time.Parse], [time.ParseInLocation], and [time.Unix], // as well as the unmarshalers t.GobDecode, t.UnmarshalBinary. // t.UnmarshalJSON, and t.UnmarshalText always create times with // no monotonic clock reading. // -// The monotonic clock reading exists only in Time values. It is not -// a part of Duration values or the Unix times returned by t.Unix and +// The monotonic clock reading exists only in [Time] values. It is not +// a part of [Duration] values or the Unix times returned by t.Unix and // friends. // // Note that the Go == operator compares not just the time instant but -// also the Location and the monotonic clock reading. See the +// also the [Location] and the monotonic clock reading. See the // documentation for the Time type for a discussion of equality // testing for Time values. // @@ -79,10 +82,11 @@ // // # Timer Resolution // -// Timer resolution varies depending on the Go runtime, the operating system +// [Timer] resolution varies depending on the Go runtime, the operating system // and the underlying hardware. -// On Unix, the resolution is approximately 1ms. -// On Windows, the default resolution is approximately 16ms, but +// On Unix, the resolution is ~1ms. +// On Windows version 1803 and newer, the resolution is ~0.5ms. +// On older Windows versions, the default resolution is ~16ms, but // a higher resolution may be requested using [golang.org/x/sys/windows.TimeBeginPeriod]. package time @@ -95,27 +99,27 @@ import ( // // Programs using times should typically store and pass them as values, // not pointers. That is, time variables and struct fields should be of -// type time.Time, not *time.Time. +// type [time.Time], not *time.Time. // // A Time value can be used by multiple goroutines simultaneously except -// that the methods GobDecode, UnmarshalBinary, UnmarshalJSON and -// UnmarshalText are not concurrency-safe. +// that the methods [Time.GobDecode], [Time.UnmarshalBinary], [Time.UnmarshalJSON] and +// [Time.UnmarshalText] are not concurrency-safe. // -// Time instants can be compared using the Before, After, and Equal methods. -// The Sub method subtracts two instants, producing a Duration. -// The Add method adds a Time and a Duration, producing a Time. +// Time instants can be compared using the [Time.Before], [Time.After], and [Time.Equal] methods. +// The [Time.Sub] method subtracts two instants, producing a [Duration]. +// The [Time.Add] method adds a Time and a Duration, producing a Time. // // The zero value of type Time is January 1, year 1, 00:00:00.000000000 UTC. -// As this time is unlikely to come up in practice, the IsZero method gives +// As this time is unlikely to come up in practice, the [Time.IsZero] method gives // a simple way of detecting a time that has not been initialized explicitly. // -// Each time has an associated Location. The methods Local, UTC, and In return a +// Each time has an associated [Location]. The methods [Time.Local], [Time.UTC], and Time.In return a // Time with a specific Location. Changing the Location of a Time value with // these methods does not change the actual instant it represents, only the time // zone in which to interpret it. // -// Representations of a Time value saved by the GobEncode, MarshalBinary, -// MarshalJSON, and MarshalText methods store the Time.Location's offset, but not +// Representations of a Time value saved by the [Time.GobEncode], [Time.MarshalBinary], +// [Time.MarshalJSON], and [Time.MarshalText] methods store the [Time.Location]'s offset, but not // the location name. They therefore lose information about Daylight Saving Time. // // In addition to the required “wall clock” reading, a Time may contain an optional @@ -575,6 +579,16 @@ func (t Time) Clock() (hour, min, sec int) { } // absClock is like clock but operates on an absolute time. +// +// absClock should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname absClock func absClock(abs uint64) (hour, min, sec int) { sec = int(abs % secondsPerDay) hour = sec / secondsPerHour @@ -625,7 +639,7 @@ const ( // Common durations. There is no definition for units of Day or larger // to avoid confusion across daylight savings time zone transitions. // -// To count the number of units in a Duration, divide: +// To count the number of units in a [Duration], divide: // // second := time.Second // fmt.Print(int64(second/time.Millisecond)) // prints 1000 @@ -828,7 +842,7 @@ func lessThanHalf(x, y Duration) bool { // Round returns the result of rounding d to the nearest multiple of m. // The rounding behavior for halfway values is to round away from zero. // If the result exceeds the maximum (or minimum) -// value that can be stored in a Duration, +// value that can be stored in a [Duration], // Round returns the maximum (or minimum) duration. // If m <= 0, Round returns d unchanged. func (d Duration) Round(m Duration) Duration { @@ -856,7 +870,7 @@ func (d Duration) Round(m Duration) Duration { } // Abs returns the absolute value of d. -// As a special case, math.MinInt64 is converted to math.MaxInt64. +// As a special case, [math.MinInt64] is converted to [math.MaxInt64]. func (d Duration) Abs() Duration { switch { case d >= 0: @@ -894,7 +908,7 @@ func (t Time) Add(d Duration) Time { } // Sub returns the duration t-u. If the result exceeds the maximum (or minimum) -// value that can be stored in a Duration, the maximum (or minimum) duration +// value that can be stored in a [Duration], the maximum (or minimum) duration // will be returned. // To compute t-d for a duration d, use t.Add(-d). func (t Time) Sub(u Time) Duration { @@ -984,6 +998,17 @@ func (t Time) date(full bool) (year int, month Month, day int, yday int) { } // absDate is like date but operates on an absolute time. +// +// absDate should be an internal detail, +// but widely used packages access it using linkname. +// Notable members of the hall of shame include: +// - github.com/phuslu/log +// - gitee.com/quant1x/gox +// +// Do not remove or change the type signature. +// See go.dev/issue/67401. +// +//go:linkname absDate func absDate(abs uint64, full bool) (year int, month Month, day int, yday int) { // Split into time and day. d := abs / secondsPerDay @@ -1127,6 +1152,9 @@ func runtimeNano() int64 // (Callers may want to use 0 as "time not set".) var startNano int64 = runtimeNano() - 1 +// x/tools uses a linkname of time.Now in its tests. No harm done. +//go:linkname Now + // Now returns the current local time. func Now() Time { sec, nsec, mono := now() @@ -1357,7 +1385,7 @@ func (t *Time) GobDecode(data []byte) error { return t.UnmarshalBinary(data) } -// MarshalJSON implements the json.Marshaler interface. +// MarshalJSON implements the [json.Marshaler] interface. // The time is a quoted string in the RFC 3339 format with sub-second precision. // If the timestamp cannot be represented as valid RFC 3339 // (e.g., the year is out of range), then an error is reported. @@ -1372,7 +1400,7 @@ func (t Time) MarshalJSON() ([]byte, error) { return b, nil } -// UnmarshalJSON implements the json.Unmarshaler interface. +// UnmarshalJSON implements the [json.Unmarshaler] interface. // The time must be a quoted string in the RFC 3339 format. func (t *Time) UnmarshalJSON(data []byte) error { if string(data) == "null" { @@ -1388,7 +1416,7 @@ func (t *Time) UnmarshalJSON(data []byte) error { return err } -// MarshalText implements the encoding.TextMarshaler interface. +// MarshalText implements the [encoding.TextMarshaler] interface. // The time is formatted in RFC 3339 format with sub-second precision. // If the timestamp cannot be represented as valid RFC 3339 // (e.g., the year is out of range), then an error is reported. @@ -1401,7 +1429,7 @@ func (t Time) MarshalText() ([]byte, error) { return b, nil } -// UnmarshalText implements the encoding.TextUnmarshaler interface. +// UnmarshalText implements the [encoding.TextUnmarshaler] interface. // The time must be in the RFC 3339 format. func (t *Time) UnmarshalText(data []byte) error { var err error diff --git a/contrib/go/_std_1.22/src/time/tzdata/tzdata.go b/contrib/go/_std_1.23/src/time/tzdata/tzdata.go similarity index 100% rename from contrib/go/_std_1.22/src/time/tzdata/tzdata.go rename to contrib/go/_std_1.23/src/time/tzdata/tzdata.go diff --git a/contrib/go/_std_1.22/src/time/tzdata/ya.make b/contrib/go/_std_1.23/src/time/tzdata/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/time/tzdata/ya.make rename to contrib/go/_std_1.23/src/time/tzdata/ya.make diff --git a/contrib/go/_std_1.22/src/time/tzdata/zzipdata.go b/contrib/go/_std_1.23/src/time/tzdata/zzipdata.go similarity index 99% rename from contrib/go/_std_1.22/src/time/tzdata/zzipdata.go rename to contrib/go/_std_1.23/src/time/tzdata/zzipdata.go index 43275ebae317..f13a3488f695 100644 --- a/contrib/go/_std_1.22/src/time/tzdata/zzipdata.go +++ b/contrib/go/_std_1.23/src/time/tzdata/zzipdata.go @@ -1,3 +1,5 @@ +// Code generated by go tool dist; DO NOT EDIT. + package tzdata const zipdata = "PK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0e\x00\x00\x00Africa/AbidjanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0c\x00\x00\x00Africa/AccraTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x12\x00\x00\x00Africa/Addis_AbabaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\x8a\x0e\xc0\xd6\x01\x00\x00\xd6\x01\x00\x00\x0e\x00\x00\x00Africa/AlgiersTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\x00\x00\x00\x06\x00\x00\x00\x1a\xff\xff\xff\xffk\xc9\x9b$\xff\xff\xff\xff\x91`PO\xff\xff\xff\xff\x9bGx\xf0\xff\xff\xff\xff\x9b\xd7,p\xff\xff\xff\xff\x9c\xbc\x91p\xff\xff\xff\xff\x9d\xc0H\xf0\xff\xff\xff\xff\x9e\x89\xfep\xff\xff\xff\xff\x9f\xa0*\xf0\xff\xff\xff\xff\xa0`\xa5\xf0\xff\xff\xff\xff\xa1\x80\x0c\xf0\xff\xff\xff\xff\xa2.\x12\xf0\xff\xff\xff\xff\xa3zL\xf0\xff\xff\xff\xff\xa45\x81\xf0\xff\xff\xff\xff\xa4\xb8\x06p\xff\xff\xff\xff\xc6\xff\x06p\xff\xff\xff\xff\xc7X\xba\x80\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x8a\x00\x00\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2N$p\xff\xff\xff\xff\xd4K\x07p\xff\xff\xff\xff\xe5\xce\xd3\x00\xff\xff\xff\xff\xf3\x5c\xb0\xf0\x00\x00\x00\x00\x02x\xc1\xf0\x00\x00\x00\x00\x03C\xc8\xf0\x00\x00\x00\x00\x0d\xcf\xd7\x00\x00\x00\x00\x00\x0e\xadD\xf0\x00\x00\x00\x00\x0fxZ\x00\x00\x00\x00\x00\x10hY\x10\x00\x00\x00\x00\x12vCp\x00\x00\x00\x00\x13fB\x80\x00\x00\x00\x00\x14_|\x10\x00\x00\x00\x00\x15O_\x00\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x04\x05\x04\x05\x03\x05\x03\x02\x03\x02\x05\x04\x05\x03\x02\x03\x05\x00\x00\x02\xdc\x00\x00\x00\x00\x021\x00\x04\x00\x00\x0e\x10\x01\x08\x00\x00\x00\x00\x00\x0d\x00\x00\x1c \x01\x11\x00\x00\x0e\x10\x00\x16LMT\x00PMT\x00WEST\x00WET\x00CEST\x00CET\x00\x0aCET-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0d\x00\x00\x00Africa/AsmaraTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0d\x00\x00\x00Africa/AsmeraTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0d\x00\x00\x00Africa/BamakoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00Africa/BanguiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0d\x00\x00\x00Africa/BanjulTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca>\xd5\xe0\x95\x00\x00\x00\x95\x00\x00\x00\x0d\x00\x00\x00Africa/BissauTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x92\xe6\x9c\x90\x00\x00\x00\x00\x09ga\x10\x01\x02\xff\xff\xf1d\x00\x00\xff\xff\xf1\xf0\x00\x04\x00\x00\x00\x00\x00\x08LMT\x00-01\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0f\x00\x00\x00Africa/BlantyreTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x12\x00\x00\x00Africa/BrazzavilleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x10\x00\x00\x00Africa/BujumburaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5#)\x16\x1d\x05\x00\x00\x1d\x05\x00\x00\x0c\x00\x00\x00Africa/CairoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xff}\xbdM\xab\xff\xff\xff\xff\xc8\x93\xb4\xe0\xff\xff\xff\xff\xc8\xfa{\xd0\xff\xff\xff\xff\xc9\xfc\xef\xe0\xff\xff\xff\xff\xca\xc7\xe8\xd0\xff\xff\xff\xff\xcb\xcb\xae`\xff\xff\xff\xff\xcc\xdf)\xd0\xff\xff\xff\xff\xcd\xac\xe1\xe0\xff\xff\xff\xff\xce\xc6\xf4\xd0\xff\xff\xff\xff\xcf\x8ff\xe0\xff\xff\xff\xff\xd0\xa9y\xd0\xff\xff\xff\xff\xd1\x84`\xe0\xff\xff\xff\xff\xd2\x8a\xadP\xff\xff\xff\xff\xe86c`\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\x0b\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xfa\xf0\xff\xff\xff\xff\xec\xb5m\x00\xff\xff\xff\xff\xed\xcf\x7f\xf0\xff\xff\xff\xff\xee\x97\xf2\x00\xff\xff\xff\xff\xef\xb0\xb3p\xff\xff\xff\xff\xf0y%\x80\xff\xff\xff\xff\xf1\x91\xe6\xf0\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3s\x1ap\xff\xff\xff\xff\xf4;\x8c\x80\xff\xff\xff\xff\xf5U\x9fp\xff\xff\xff\xff\xf6\x1e\x11\x80\xff\xff\xff\xff\xf76\xd2\xf0\xff\xff\xff\xff\xf7\xffE\x00\xff\xff\xff\xff\xf9\x18\x06p\xff\xff\xff\xff\xf9\xe1\xca\x00\xff\xff\xff\xff\xfa\xf99\xf0\xff\xff\xff\xff\xfb\xc2\xfd\x80\xff\xff\xff\xff\xfc\xdb\xbe\xf0\xff\xff\xff\xff\xfd\xa5\x82\x80\xff\xff\xff\xff\xfe\xbc\xf2p\xff\xff\xff\xff\xff\x86\xb6\x00\x00\x00\x00\x00\x00\x9e%\xf0\x00\x00\x00\x00\x01g\xe9\x80\x00\x00\x00\x00\x02\x7fYp\x00\x00\x00\x00\x03I\x1d\x00\x00\x00\x00\x00\x04a\xdep\x00\x00\x00\x00\x05+\xa2\x00\x00\x00\x00\x00\x06C\x11\xf0\x00\x00\x00\x00\x07\x0c\xd5\x80\x00\x00\x00\x00\x08$Ep\x00\x00\x00\x00\x08\xee\x09\x00\x00\x00\x00\x00\x0a\x05x\xf0\x00\x00\x00\x00\x0a\xcf<\x80\x00\x00\x00\x00\x0b\xe7\xfd\xf0\x00\x00\x00\x00\x0c\xb1\xc1\x80\x00\x00\x00\x00\x0d\xc91p\x00\x00\x00\x00\x0e\x92\xf5\x00\x00\x00\x00\x00\x0f\xaad\xf0\x00\x00\x00\x00\x10t(\x80\x00\x00\x00\x00\x11\x8b\x98p\x00\x00\x00\x00\x12U\x5c\x00\x00\x00\x00\x00\x13n\x1dp\x00\x00\x00\x00\x147\xe1\x00\x00\x00\x00\x00\x15OP\xf0\x00\x00\x00\x00\x16\x19\x14\x80\x00\x00\x00\x00\x17\xa0\x93\xf0\x00\x00\x00\x00\x17\xfaH\x00\x00\x00\x00\x00\x19p\xa3\xf0\x00\x00\x00\x00\x19\xdb{\x80\x00\x00\x00\x00\x1a\xf4<\xf0\x00\x00\x00\x00\x1b\xbe\x00\x80\x00\x00\x00\x00\x1c\xd5pp\x00\x00\x00\x00\x1d\x9f4\x00\x00\x00\x00\x00\x1e\xb6\xa3\xf0\x00\x00\x00\x00\x1f\x80g\x80\x00\x00\x00\x00 \x97\xd7p\x00\x00\x00\x00!a\x9b\x00\x00\x00\x00\x00\x22z\x5cp\x00\x00\x00\x00#D \x00\x00\x00\x00\x00$b'p\x00\x00\x00\x00%%S\x80\x00\x00\x00\x00&<\xc3p\x00\x00\x00\x00'\x06\x87\x00\x00\x00\x00\x00(\x1d\xf6\xf0\x00\x00\x00\x00(\xe7\xba\x80\x00\x00\x00\x00*\x00{\xf0\x00\x00\x00\x00*\xca?\x80\x00\x00\x00\x00+\xe1\xafp\x00\x00\x00\x00,\xabs\x00\x00\x00\x00\x00-\xc2\xe2\xf0\x00\x00\x00\x00.\x8c\xa6\x80\x00\x00\x00\x00/\xa0\x13\xe0\x00\x00\x00\x000k\x0c\xd0\x00\x00\x00\x001\x7f\xf5\xe0\x00\x00\x00\x002J\xee\xd0\x00\x00\x00\x003_\xd7\xe0\x00\x00\x00\x004*\xd0\xd0\x00\x00\x00\x005?\xb9\xe0\x00\x00\x00\x006\x0a\xb2\xd0\x00\x00\x00\x007(\xd6`\x00\x00\x00\x007\xf3\xcfP\x00\x00\x00\x009\x08\xb8`\x00\x00\x00\x009\xd3\xb1P\x00\x00\x00\x00:\xe8\x9a`\x00\x00\x00\x00;\xb3\x93P\x00\x00\x00\x00<\xc8|`\x00\x00\x00\x00=\x93uP\x00\x00\x00\x00>\xa8^`\x00\x00\x00\x00?sWP\x00\x00\x00\x00@\x91z\xe0\x00\x00\x00\x00A\x5cs\xd0\x00\x00\x00\x00Bq\x5c\xe0\x00\x00\x00\x00C\xe0\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F1 \xe0\x00\x00\x00\x00F\xe0jP\x00\x00\x00\x00H\x11\x02\xe0\x00\x00\x00\x00H\xb7\x11\xd0\x00\x00\x00\x00I\xf0\xe4\xe0\x00\x00\x00\x00J\x8d\xb9P\x00\x00\x00\x00K\xda\x01`\x00\x00\x00\x00La\xbd\xd0\x00\x00\x00\x00L\x89X\xe0\x00\x00\x00\x00L\xa4\xfaP\x00\x00\x00\x00Su8\xe0\x00\x00\x00\x00S\xac\x89\xd0\x00\x00\x00\x00S\xda\xbc`\x00\x00\x00\x00T$\x82P\x00\x00\x00\x00dJ\xf0`\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\x1dU\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09LMT\x00EEST\x00EET\x00\x0aEET-2EEST,M4.5.5/0,M10.5.4/24\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001B\xb0;\x7f\x07\x00\x00\x7f\x07\x00\x00\x11\x00\x00\x00Africa/CasablancaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\x00\x00\x00\x05\x00\x00\x00\x0c\xff\xff\xff\xff\x96Q\xf9\x9c\xff\xff\xff\xff\xc6\xff\x14\x80\xff\xff\xff\xff\xc7X\xacp\xff\xff\xff\xff\xc7\xd9\xed\x80\xff\xff\xff\xff\xd2\xa12\xf0\xff\xff\xff\xff\xdb5\xa4\x00\xff\xff\xff\xff\xdb\xee'\xf0\xff\xff\xff\xff\xfb%r@\xff\xff\xff\xff\xfb\xc2\xefp\x00\x00\x00\x00\x08k\x84\x80\x00\x00\x00\x00\x08\xc6m\xf0\x00\x00\x00\x00\x0b\xe8\x0c\x00\x00\x00\x00\x00\x0caG\xf0\x00\x00\x00\x00\x0d\xc9?\x80\x00\x00\x00\x00\x0e\x8e\xf2p\x00\x00\x00\x00\x0f\xd3Q\x80\x00\x00\x00\x00\x10'\xa3p\x00\x00\x00\x00\x1a\xb7\xa6\x00\x00\x00\x00\x00\x1e\x18o\xf0\x00\x00\x00\x00HA\xe6\x80\x00\x00\x00\x00H\xbb\x22p\x00\x00\x00\x00J#\x1a\x00\x00\x00\x00\x00J\x8d\xd5p\x00\x00\x00\x00K\xdc\xc0\x80\x00\x00\x00\x00L]\xe5p\x00\x00\x00\x00M\x97\xb8\x80\x00\x00\x00\x00N4\x8c\xf0\x00\x00\x00\x00O\x9c\xa0\xa0\x00\x00\x00\x00P\x08\xbb\xa0\x00\x00\x00\x00P1\x9a \x00\x00\x00\x00Pg\xa7\xa0\x00\x00\x00\x00Q|\x82\xa0\x00\x00\x00\x00Q\xd8\xcb\xa0\x00\x00\x00\x00R\x05\x9e\xa0\x00\x00\x00\x00Rls\xa0\x00\x00\x00\x00S7z\xa0\x00\x00\x00\x00S\xae!\xa0\x00\x00\x00\x00S\xdcF \x00\x00\x00\x00TLU\xa0\x00\x00\x00\x00U\x17\x5c\xa0\x00\x00\x00\x00U|\xe0 \x00\x00\x00\x00U\xab\x04\xa0\x00\x00\x00\x00V,7\xa0\x00\x00\x00\x00V\xf7>\xa0\x00\x00\x00\x00WS\x87\xa0\x00\x00\x00\x00W\x81\xac \x00\x00\x00\x00X\x15T \x00\x00\x00\x00X\xd7 \xa0\x00\x00\x00\x00Y \xf4\xa0\x00\x00\x00\x00YXS\xa0\x00\x00\x00\x00Y\xf56 \x00\x00\x00\x00Z\xb7\x02\xa0\x00\x00\x00\x00Z\xf7\x9c \x00\x00\x00\x00[%\xc0\xa0\x00\x00\x00\x00[\xd5\x18 \x00\x00\x00\x00\x5c\xceC\xa0\x00\x00\x00\x00\x5c\xfch \x00\x00\x00\x00^\x9b\xb0\xa0\x00\x00\x00\x00^\xd3\x0f\xa0\x00\x00\x00\x00`rX \x00\x00\x00\x00`\xa0|\xa0\x00\x00\x00\x00b?\xc5 \x00\x00\x00\x00bw$ \x00\x00\x00\x00d\x16l\xa0\x00\x00\x00\x00dD\x91 \x00\x00\x00\x00e\xed\x14 \x00\x00\x00\x00f\x1b8\xa0\x00\x00\x00\x00g\xba\x81 \x00\x00\x00\x00g\xf1\xe0 \x00\x00\x00\x00i\x91(\xa0\x00\x00\x00\x00i\xbfM \x00\x00\x00\x00kg\xd0 \x00\x00\x00\x00k\x95\xf4\xa0\x00\x00\x00\x00m5= \x00\x00\x00\x00ml\x9c \x00\x00\x00\x00o\x0b\xe4\xa0\x00\x00\x00\x00o:\x09 \x00\x00\x00\x00p\xd9Q\xa0\x00\x00\x00\x00q\x10\xb0\xa0\x00\x00\x00\x00r\xaf\xf9 \x00\x00\x00\x00r\xde\x1d\xa0\x00\x00\x00\x00t\x86\xa0\xa0\x00\x00\x00\x00t\xb4\xc5 \x00\x00\x00\x00vT\x0d\xa0\x00\x00\x00\x00v\x8bl\xa0\x00\x00\x00\x00x*\xb5 \x00\x00\x00\x00xX\xd9\xa0\x00\x00\x00\x00y\xf8\x22 \x00\x00\x00\x00z/\x81 \x00\x00\x00\x00{\xce\xc9\xa0\x00\x00\x00\x00|\x06(\xa0\x00\x00\x00\x00}\xa5q \x00\x00\x00\x00}\xd3\x95\xa0\x00\x00\x00\x00\x7fr\xde \x00\x00\x00\x00\x7f\xaa= \x00\x00\x00\x00\x81I\x85\xa0\x00\x00\x00\x00\x81w\xaa \x00\x00\x00\x00\x83 - \x00\x00\x00\x00\x83NQ\xa0\x00\x00\x00\x00\x84\xed\x9a \x00\x00\x00\x00\x85$\xf9 \x00\x00\x00\x00\x86\xc4A\xa0\x00\x00\x00\x00\x86\xf2f \x00\x00\x00\x00\x88\x91\xae\xa0\x00\x00\x00\x00\x88\xc9\x0d\xa0\x00\x00\x00\x00\x8ahV \x00\x00\x00\x00\x8a\x9f\xb5 \x00\x00\x00\x00\x8c>\xfd\xa0\x00\x00\x00\x00\x8cm\x22 \x00\x00\x00\x00\x8e\x0cj\xa0\x00\x00\x00\x00\x8eC\xc9\xa0\x00\x00\x00\x00\x8f\xe3\x12 \x00\x00\x00\x00\x90\x116\xa0\x00\x00\x00\x00\x91\xb9\xb9\xa0\x00\x00\x00\x00\x91\xe7\xde \x00\x00\x00\x00\x93\x87&\xa0\x00\x00\x00\x00\x93\xbe\x85\xa0\x00\x00\x00\x00\x95]\xce \x00\x00\x00\x00\x95\x8b\xf2\xa0\x00\x00\x00\x00\x97+; \x00\x00\x00\x00\x97b\x9a \x00\x00\x00\x00\x99\x01\xe2\xa0\x00\x00\x00\x00\x999A\xa0\x00\x00\x00\x00\x9a\xd8\x8a \x00\x00\x00\x00\x9b\x06\xae\xa0\x00\x00\x00\x00\x9c\xa5\xf7 \x00\x00\x00\x00\x9c\xddV \x00\x00\x00\x00\x9e|\x9e\xa0\x00\x00\x00\x00\x9e\xaa\xc3 \x00\x00\x00\x00\xa0SF \x00\x00\x00\x00\xa0\x81j\xa0\x00\x00\x00\x00\xa2 \xb3 \x00\x00\x00\x00\xa2X\x12 \x00\x00\x00\x00\xa3\xf7Z\xa0\x00\x00\x00\x00\xa4%\x7f \x00\x00\x00\x00\xa5\xc4\xc7\xa0\x00\x00\x00\x00\xa5\xfc&\xa0\x00\x00\x00\x00\xa7\x9bo \x00\x00\x00\x00\xa7\xd2\xce \x00\x00\x00\x00\xa9r\x16\xa0\x00\x00\x00\x00\xa9\xa0; \x00\x00\x00\x00\xab?\x83\xa0\x00\x00\x00\x00\xabv\xe2\xa0\x00\x00\x00\x00\xad\x16+ \x00\x00\x00\x00\xadDO\xa0\x00\x00\x00\x00\xae\xec\xd2\xa0\x00\x00\x00\x00\xaf\x1a\xf7 \x00\x00\x00\x00\xb0\xba?\xa0\x00\x00\x00\x00\xb0\xf1\x9e\xa0\x00\x00\x00\x00\xb2\x90\xe7 \x00\x00\x00\x00\xb2\xbf\x0b\xa0\x00\x00\x00\x00\xb4^T \x00\x00\x00\x00\xb4\x95\xb3 \x00\x00\x00\x00\xb64\xfb\xa0\x00\x00\x00\x00\xb6lZ\xa0\x00\x00\x00\x00\xb8\x0b\xa3 \x00\x00\x00\x00\xb89\xc7\xa0\x00\x00\x00\x00\xb9\xd9\x10 \x00\x00\x00\x00\xba\x10o \x00\x00\x00\x00\xbb\xaf\xb7\xa0\x00\x00\x00\x00\xbb\xdd\xdc \x00\x00\x00\x00\xbd\x86_ \x00\x00\x00\x00\xbd\xb4\x83\xa0\x00\x00\x00\x00\xbfS\xcc \x00\x00\x00\x00\xbf\x8b+ \x00\x00\x00\x00\xc1*s\xa0\x00\x00\x00\x00\xc1X\x98 \x00\x00\x00\x00\xc2\xf7\xe0\xa0\x00\x00\x00\x00\xc3/?\xa0\x00\x00\x00\x00\xc4\xce\x88 \x00\x00\x00\x00\xc5\x05\xe7 \x00\x00\x00\x00\xc6\xa5/\xa0\x00\x00\x00\x00\xc6\xd3T \x00\x00\x00\x00\xc8r\x9c\xa0\x00\x00\x00\x00\xc8\xa9\xfb\xa0\x00\x00\x00\x00\xcaID \x00\x00\x00\x00\xcawh\xa0\x00\x00\x00\x00\xcc\x1f\xeb\xa0\x00\x00\x00\x00\xccN\x10 \x00\x00\x00\x00\xcd\xedX\xa0\x00\x00\x00\x00\xce$\xb7\xa0\x00\x00\x00\x00\xcf\xc4\x00 \x00\x00\x00\x00\xcf\xf2$\xa0\x00\x00\x00\x00\xd1\x91m \x00\x00\x00\x00\xd1\xc8\xcc \x00\x00\x00\x00\xd3h\x14\xa0\x00\x00\x00\x00\xd3\x969 \x00\x00\x00\x00\xd5>\xbc \x00\x00\x00\x00\xd5l\xe0\xa0\x00\x00\x00\x00\xd7\x0c) \x00\x00\x00\x00\xd7C\x88 \x00\x00\x00\x00\xd8\xe2\xd0\xa0\x00\x00\x00\x00\xd9\x10\xf5 \x00\x00\x00\x00\xda\xb9x \x00\x00\x00\x00\xda\xe7\x9c\xa0\x00\x00\x00\x00\xdc\x86\xe5 \x00\x00\x00\x00\xdc\xbeD \x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\xff\xff\xf8\xe4\x00\x00\x00\x00\x0e\x10\x01\x04\x00\x00\x00\x00\x00\x08\x00\x00\x0e\x10\x00\x04\x00\x00\x00\x00\x01\x08LMT\x00+01\x00+00\x00\x0a<+01>-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f\x1b\xeb\xdd2\x02\x00\x002\x02\x00\x00\x0c\x00\x00\x00Africa/CeutaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00\x05\x00\x00\x00\x16\xff\xff\xff\xff~6\xb5\x00\xff\xff\xff\xff\x9e\xd6up\xff\xff\xff\xff\x9f\xa1n`\xff\xff\xff\xff\xaa\x05\xefp\xff\xff\xff\xff\xaa\xe7n\x00\xff\xff\xff\xff\xad\xc9\xa7\xf0\xff\xff\xff\xff\xae\xa72\x00\xff\xff\xff\xff\xaf\xa0Op\xff\xff\xff\xff\xb0\x87\x14\x00\xff\xff\xff\xff\xb1\x89z\x00\xff\xff\xff\xff\xb2p0\x80\xff\xff\xff\xff\xfb%r@\xff\xff\xff\xff\xfb\xc2\xefp\x00\x00\x00\x00\x08k\x84\x80\x00\x00\x00\x00\x08\xc6m\xf0\x00\x00\x00\x00\x0b\xe8\x0c\x00\x00\x00\x00\x00\x0caG\xf0\x00\x00\x00\x00\x0d\xc9?\x80\x00\x00\x00\x00\x0e\x8e\xf2p\x00\x00\x00\x00\x0f\xd3Q\x80\x00\x00\x00\x00\x10'\xa3p\x00\x00\x00\x00\x1a\xb7\xa6\x00\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\xa0\x00\x00\x00\x00WS\x87\xa0\x00\x00\x00\x00W\x81\xac \x00\x00\x00\x00X\x15T \x00\x00\x00\x00X\xd7 \xa0\x00\x00\x00\x00Y \xf4\xa0\x00\x00\x00\x00YXS\xa0\x00\x00\x00\x00Y\xf56 \x00\x00\x00\x00Z\xb7\x02\xa0\x00\x00\x00\x00Z\xf7\x9c \x00\x00\x00\x00[%\xc0\xa0\x00\x00\x00\x00[\xd5\x18 \x00\x00\x00\x00\x5c\xceC\xa0\x00\x00\x00\x00\x5c\xfch \x00\x00\x00\x00^\x9b\xb0\xa0\x00\x00\x00\x00^\xd3\x0f\xa0\x00\x00\x00\x00`rX \x00\x00\x00\x00`\xa0|\xa0\x00\x00\x00\x00b?\xc5 \x00\x00\x00\x00bw$ \x00\x00\x00\x00d\x16l\xa0\x00\x00\x00\x00dD\x91 \x00\x00\x00\x00e\xed\x14 \x00\x00\x00\x00f\x1b8\xa0\x00\x00\x00\x00g\xba\x81 \x00\x00\x00\x00g\xf1\xe0 \x00\x00\x00\x00i\x91(\xa0\x00\x00\x00\x00i\xbfM \x00\x00\x00\x00kg\xd0 \x00\x00\x00\x00k\x95\xf4\xa0\x00\x00\x00\x00m5= \x00\x00\x00\x00ml\x9c \x00\x00\x00\x00o\x0b\xe4\xa0\x00\x00\x00\x00o:\x09 \x00\x00\x00\x00p\xd9Q\xa0\x00\x00\x00\x00q\x10\xb0\xa0\x00\x00\x00\x00r\xaf\xf9 \x00\x00\x00\x00r\xde\x1d\xa0\x00\x00\x00\x00t\x86\xa0\xa0\x00\x00\x00\x00t\xb4\xc5 \x00\x00\x00\x00vT\x0d\xa0\x00\x00\x00\x00v\x8bl\xa0\x00\x00\x00\x00x*\xb5 \x00\x00\x00\x00xX\xd9\xa0\x00\x00\x00\x00y\xf8\x22 \x00\x00\x00\x00z/\x81 \x00\x00\x00\x00{\xce\xc9\xa0\x00\x00\x00\x00|\x06(\xa0\x00\x00\x00\x00}\xa5q \x00\x00\x00\x00}\xd3\x95\xa0\x00\x00\x00\x00\x7fr\xde \x00\x00\x00\x00\x7f\xaa= \x00\x00\x00\x00\x81I\x85\xa0\x00\x00\x00\x00\x81w\xaa \x00\x00\x00\x00\x83 - \x00\x00\x00\x00\x83NQ\xa0\x00\x00\x00\x00\x84\xed\x9a \x00\x00\x00\x00\x85$\xf9 \x00\x00\x00\x00\x86\xc4A\xa0\x00\x00\x00\x00\x86\xf2f \x00\x00\x00\x00\x88\x91\xae\xa0\x00\x00\x00\x00\x88\xc9\x0d\xa0\x00\x00\x00\x00\x8ahV \x00\x00\x00\x00\x8a\x9f\xb5 \x00\x00\x00\x00\x8c>\xfd\xa0\x00\x00\x00\x00\x8cm\x22 \x00\x00\x00\x00\x8e\x0cj\xa0\x00\x00\x00\x00\x8eC\xc9\xa0\x00\x00\x00\x00\x8f\xe3\x12 \x00\x00\x00\x00\x90\x116\xa0\x00\x00\x00\x00\x91\xb9\xb9\xa0\x00\x00\x00\x00\x91\xe7\xde \x00\x00\x00\x00\x93\x87&\xa0\x00\x00\x00\x00\x93\xbe\x85\xa0\x00\x00\x00\x00\x95]\xce \x00\x00\x00\x00\x95\x8b\xf2\xa0\x00\x00\x00\x00\x97+; \x00\x00\x00\x00\x97b\x9a \x00\x00\x00\x00\x99\x01\xe2\xa0\x00\x00\x00\x00\x999A\xa0\x00\x00\x00\x00\x9a\xd8\x8a \x00\x00\x00\x00\x9b\x06\xae\xa0\x00\x00\x00\x00\x9c\xa5\xf7 \x00\x00\x00\x00\x9c\xddV \x00\x00\x00\x00\x9e|\x9e\xa0\x00\x00\x00\x00\x9e\xaa\xc3 \x00\x00\x00\x00\xa0SF \x00\x00\x00\x00\xa0\x81j\xa0\x00\x00\x00\x00\xa2 \xb3 \x00\x00\x00\x00\xa2X\x12 \x00\x00\x00\x00\xa3\xf7Z\xa0\x00\x00\x00\x00\xa4%\x7f \x00\x00\x00\x00\xa5\xc4\xc7\xa0\x00\x00\x00\x00\xa5\xfc&\xa0\x00\x00\x00\x00\xa7\x9bo \x00\x00\x00\x00\xa7\xd2\xce \x00\x00\x00\x00\xa9r\x16\xa0\x00\x00\x00\x00\xa9\xa0; \x00\x00\x00\x00\xab?\x83\xa0\x00\x00\x00\x00\xabv\xe2\xa0\x00\x00\x00\x00\xad\x16+ \x00\x00\x00\x00\xadDO\xa0\x00\x00\x00\x00\xae\xec\xd2\xa0\x00\x00\x00\x00\xaf\x1a\xf7 \x00\x00\x00\x00\xb0\xba?\xa0\x00\x00\x00\x00\xb0\xf1\x9e\xa0\x00\x00\x00\x00\xb2\x90\xe7 \x00\x00\x00\x00\xb2\xbf\x0b\xa0\x00\x00\x00\x00\xb4^T \x00\x00\x00\x00\xb4\x95\xb3 \x00\x00\x00\x00\xb64\xfb\xa0\x00\x00\x00\x00\xb6lZ\xa0\x00\x00\x00\x00\xb8\x0b\xa3 \x00\x00\x00\x00\xb89\xc7\xa0\x00\x00\x00\x00\xb9\xd9\x10 \x00\x00\x00\x00\xba\x10o \x00\x00\x00\x00\xbb\xaf\xb7\xa0\x00\x00\x00\x00\xbb\xdd\xdc \x00\x00\x00\x00\xbd\x86_ \x00\x00\x00\x00\xbd\xb4\x83\xa0\x00\x00\x00\x00\xbfS\xcc \x00\x00\x00\x00\xbf\x8b+ \x00\x00\x00\x00\xc1*s\xa0\x00\x00\x00\x00\xc1X\x98 \x00\x00\x00\x00\xc2\xf7\xe0\xa0\x00\x00\x00\x00\xc3/?\xa0\x00\x00\x00\x00\xc4\xce\x88 \x00\x00\x00\x00\xc5\x05\xe7 \x00\x00\x00\x00\xc6\xa5/\xa0\x00\x00\x00\x00\xc6\xd3T \x00\x00\x00\x00\xc8r\x9c\xa0\x00\x00\x00\x00\xc8\xa9\xfb\xa0\x00\x00\x00\x00\xcaID \x00\x00\x00\x00\xcawh\xa0\x00\x00\x00\x00\xcc\x1f\xeb\xa0\x00\x00\x00\x00\xccN\x10 \x00\x00\x00\x00\xcd\xedX\xa0\x00\x00\x00\x00\xce$\xb7\xa0\x00\x00\x00\x00\xcf\xc4\x00 \x00\x00\x00\x00\xcf\xf2$\xa0\x00\x00\x00\x00\xd1\x91m \x00\x00\x00\x00\xd1\xc8\xcc \x00\x00\x00\x00\xd3h\x14\xa0\x00\x00\x00\x00\xd3\x969 \x00\x00\x00\x00\xd5>\xbc \x00\x00\x00\x00\xd5l\xe0\xa0\x00\x00\x00\x00\xd7\x0c) \x00\x00\x00\x00\xd7C\x88 \x00\x00\x00\x00\xd8\xe2\xd0\xa0\x00\x00\x00\x00\xd9\x10\xf5 \x00\x00\x00\x00\xda\xb9x \x00\x00\x00\x00\xda\xe7\x9c\xa0\x00\x00\x00\x00\xdc\x86\xe5 \x00\x00\x00\x00\xdc\xbeD \x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\xff\xff\xf3\xa0\x00\x00\xff\xff\xf1\xf0\x00\x04\x00\x00\x0e\x10\x01\x08\x00\x00\x00\x00\x00\x0c\x00\x00\x00\x00\x01\x0c\x00\x00\x0e\x10\x00\x08LMT\x00-01\x00+01\x00+00\x00\x0a<+01>-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0f\x00\x00\x00Africa/FreetownTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0f\x00\x00\x00Africa/GaboroneTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00Africa/HarareTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcc\x0cT\xce\xbe\x00\x00\x00\xbe\x00\x00\x00\x13\x00\x00\x00Africa/JohannesburgTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x09\xff\xff\xff\xffm{A@\xff\xff\xff\xff\x82F\xcfh\xff\xff\xff\xff\xcc\xae\x8c\x80\xff\xff\xff\xff\xcd\x9eop\xff\xff\xff\xff\xce\x8en\x80\xff\xff\xff\xff\xcf~Qp\x01\x03\x02\x03\x02\x03\x00\x00\x1a@\x00\x00\x00\x00\x15\x18\x00\x04\x00\x00*0\x01\x04\x00\x00\x1c \x00\x04LMT\x00SAST\x00\x0aSAST-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\xcf\x10n\xca\x01\x00\x00\xca\x01\x00\x00\x0b\x00\x00\x00Africa/JubaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xb6\xa3\xda\xdc\x00\x00\x00\x00\x00\x9e\x17\xe0\x00\x00\x00\x00\x01z4P\x00\x00\x00\x00\x02}\xf9\xe0\x00\x00\x00\x00\x03[g\xd0\x00\x00\x00\x00\x04`~\xe0\x00\x00\x00\x00\x05=\xec\xd0\x00\x00\x00\x00\x06@`\xe0\x00\x00\x00\x00\x07\x1f P\x00\x00\x00\x00\x08 B\xe0\x00\x00\x00\x00\x09\x00S\xd0\x00\x00\x00\x00\x0a\x00$\xe0\x00\x00\x00\x00\x0a\xe1\x87P\x00\x00\x00\x00\x0b\xe0\x06\xe0\x00\x00\x00\x00\x0c\xc4\x0cP\x00\x00\x00\x00\x0d\xbf\xe8\xe0\x00\x00\x00\x00\x0e\xa5?\xd0\x00\x00\x00\x00\x0f\xa9\x05`\x00\x00\x00\x00\x10\x86sP\x00\x00\x00\x00\x11\x88\xe7`\x00\x00\x00\x00\x12g\xa6\xd0\x00\x00\x00\x00\x13h\xc9`\x00\x00\x00\x00\x14J+\xd0\x00\x00\x00\x00\x15H\xab`\x00\x00\x00\x00\x16+_P\x00\x00\x00\x00\x17(\x8d`\x00\x00\x00\x00\x18\x0c\x92\xd0\x00\x00\x00\x00\x19\x08o`\x00\x00\x00\x00\x19\xed\xc6P\x00\x00\x00\x00\x1a\xf1\x8b\xe0\x00\x00\x00\x00\x1b\xd0KP\x00\x00\x00\x00\x1c\xd1m\xe0\x00\x00\x00\x00\x1d\xb1~\xd0\x00\x00\x00\x008\x80E \x00\x00\x00\x00`\x17\x1aP\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\x00\x00\x1d\xa4\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09\x00\x00*0\x00\x0dLMT\x00CAST\x00CAT\x00EAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0e\x00\x00\x00Africa/KampalaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\xadD\xef\xca\x01\x00\x00\xca\x01\x00\x00\x0f\x00\x00\x00Africa/KhartoumTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xb6\xa3\xda\x00\x00\x00\x00\x00\x00\x9e\x17\xe0\x00\x00\x00\x00\x01z4P\x00\x00\x00\x00\x02}\xf9\xe0\x00\x00\x00\x00\x03[g\xd0\x00\x00\x00\x00\x04`~\xe0\x00\x00\x00\x00\x05=\xec\xd0\x00\x00\x00\x00\x06@`\xe0\x00\x00\x00\x00\x07\x1f P\x00\x00\x00\x00\x08 B\xe0\x00\x00\x00\x00\x09\x00S\xd0\x00\x00\x00\x00\x0a\x00$\xe0\x00\x00\x00\x00\x0a\xe1\x87P\x00\x00\x00\x00\x0b\xe0\x06\xe0\x00\x00\x00\x00\x0c\xc4\x0cP\x00\x00\x00\x00\x0d\xbf\xe8\xe0\x00\x00\x00\x00\x0e\xa5?\xd0\x00\x00\x00\x00\x0f\xa9\x05`\x00\x00\x00\x00\x10\x86sP\x00\x00\x00\x00\x11\x88\xe7`\x00\x00\x00\x00\x12g\xa6\xd0\x00\x00\x00\x00\x13h\xc9`\x00\x00\x00\x00\x14J+\xd0\x00\x00\x00\x00\x15H\xab`\x00\x00\x00\x00\x16+_P\x00\x00\x00\x00\x17(\x8d`\x00\x00\x00\x00\x18\x0c\x92\xd0\x00\x00\x00\x00\x19\x08o`\x00\x00\x00\x00\x19\xed\xc6P\x00\x00\x00\x00\x1a\xf1\x8b\xe0\x00\x00\x00\x00\x1b\xd0KP\x00\x00\x00\x00\x1c\xd1m\xe0\x00\x00\x00\x00\x1d\xb1~\xd0\x00\x00\x00\x008\x80E \x00\x00\x00\x00Y\xf8\xe4P\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\x00\x00\x1e\x80\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09\x00\x00*0\x00\x0dLMT\x00CAST\x00CAT\x00EAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00Africa/KigaliTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0f\x00\x00\x00Africa/KinshasaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0c\x00\x00\x00Africa/LagosTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x11\x00\x00\x00Africa/LibrevilleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0b\x00\x00\x00Africa/LomeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00Africa/LuandaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x11\x00\x00\x00Africa/LubumbashiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00Africa/LusakaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00Africa/MalaboTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00Africa/MaputoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x82F\xc5\xf4\x01\x00\x00\x1e\x8c\x00\x00\x00\x00\x1c \x00\x04LMT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcc\x0cT\xce\xbe\x00\x00\x00\xbe\x00\x00\x00\x0d\x00\x00\x00Africa/MaseruTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x09\xff\xff\xff\xffm{A@\xff\xff\xff\xff\x82F\xcfh\xff\xff\xff\xff\xcc\xae\x8c\x80\xff\xff\xff\xff\xcd\x9eop\xff\xff\xff\xff\xce\x8en\x80\xff\xff\xff\xff\xcf~Qp\x01\x03\x02\x03\x02\x03\x00\x00\x1a@\x00\x00\x00\x00\x15\x18\x00\x04\x00\x00*0\x01\x04\x00\x00\x1c \x00\x04LMT\x00SAST\x00\x0aSAST-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcc\x0cT\xce\xbe\x00\x00\x00\xbe\x00\x00\x00\x0e\x00\x00\x00Africa/MbabaneTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x09\xff\xff\xff\xffm{A@\xff\xff\xff\xff\x82F\xcfh\xff\xff\xff\xff\xcc\xae\x8c\x80\xff\xff\xff\xff\xcd\x9eop\xff\xff\xff\xff\xce\x8en\x80\xff\xff\xff\xff\xcf~Qp\x01\x03\x02\x03\x02\x03\x00\x00\x1a@\x00\x00\x00\x00\x15\x18\x00\x04\x00\x00*0\x01\x04\x00\x00\x1c \x00\x04LMT\x00SAST\x00\x0aSAST-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x10\x00\x00\x00Africa/MogadishuTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\x99rU\xa4\x00\x00\x00\xa4\x00\x00\x00\x0f\x00\x00\x00Africa/MonroviaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xffZz\xa6\x9c\xff\xff\xff\xff\xa0_l\x9c\x00\x00\x00\x00\x03\xcaZn\x01\x02\x03\xff\xff\xf5\xe4\x00\x00\xff\xff\xf5\xe4\x00\x04\xff\xff\xf5\x92\x00\x04\x00\x00\x00\x00\x00\x08LMT\x00MMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0e\x00\x00\x00Africa/NairobiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa\x81\x09\x03\xa0\x00\x00\x00\xa0\x00\x00\x00\x0f\x00\x00\x00Africa/NdjamenaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xff\x92\xe6\x80d\x00\x00\x00\x00\x12fqp\x00\x00\x00\x00\x13&\xde`\x01\x02\x01\x00\x00\x0e\x1c\x00\x00\x00\x00\x0e\x10\x00\x04\x00\x00\x1c \x01\x08LMT\x00WAT\x00WAST\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00Africa/NiameyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x11\x00\x00\x00Africa/NouakchottTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x12\x00\x00\x00Africa/OuagadougouTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x11\x00\x00\x00Africa/Porto-NovoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x86\xabp\xd1\xff\xff\xff\xff\x8cP`\x00\xff\xff\xff\xff\x96\xaaC\xd1\xff\xff\xff\xff\xa1Q\xefx\x01\x00\x02\x03\x00\x00\x03/\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x07\x08\x00\x08\x00\x00\x0e\x10\x00\x0eLMT\x00GMT\x00+0030\x00WAT\x00\x0aWAT-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc1\x0a\x8a\x84\xad\x00\x00\x00\xad\x00\x00\x00\x0f\x00\x00\x00Africa/Sao_TomeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff^<\xfd0\xff\xff\xff\xff\x92\xe6\x8e\x80\x00\x00\x00\x00ZI\x88\x10\x00\x00\x00\x00\x5c*\xbb\x90\x01\x02\x03\x02\x00\x00\x06P\x00\x00\xff\xff\xf7c\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x0e\x10\x00\x08LMT\x00GMT\x00WAT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0f\x00\x00\x00Africa/TimbuktuTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\x7f2[\xaf\x01\x00\x00\xaf\x01\x00\x00\x0e\x00\x00\x00Africa/TripoliTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xa1\xf2\xc1$\xff\xff\xff\xff\xdd\xbb\xb1\x10\xff\xff\xff\xff\xde#\xad`\xff\xff\xff\xff\xe1x\xd2\x10\xff\xff\xff\xff\xe1\xe7e\xe0\xff\xff\xff\xff\xe5/?p\xff\xff\xff\xff\xe5\xa9\xcc\xe0\xff\xff\xff\xff\xebN\xc6\xf0\x00\x00\x00\x00\x16\x92B`\x00\x00\x00\x00\x17\x08\xf7p\x00\x00\x00\x00\x17\xfa+\xe0\x00\x00\x00\x00\x18\xea*\xf0\x00\x00\x00\x00\x19\xdb_`\x00\x00\x00\x00\x1a\xcc\xaf\xf0\x00\x00\x00\x00\x1b\xbd\xe4`\x00\x00\x00\x00\x1c\xb4z\xf0\x00\x00\x00\x00\x1d\x9f\x17\xe0\x00\x00\x00\x00\x1e\x93\x0bp\x00\x00\x00\x00\x1f\x82\xee`\x00\x00\x00\x00 pJp\x00\x00\x00\x00!a~\xe0\x00\x00\x00\x00\x22R\xcfp\x00\x00\x00\x00#D\x03\xe0\x00\x00\x00\x00$4\x02\xf0\x00\x00\x00\x00%%7`\x00\x00\x00\x00&@\xb7\xf0\x00\x00\x00\x002N\xf1`\x00\x00\x00\x003D6p\x00\x00\x00\x0045j\xe0\x00\x00\x00\x00P\x9d\x99\x00\x00\x00\x00\x00QT\xd9\x80\x00\x00\x00\x00Ri\xb4\x80\x02\x01\x02\x01\x02\x01\x02\x03\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\x01\x03\x02\x01\x03\x00\x00\x0c\x5c\x00\x00\x00\x00\x1c \x01\x04\x00\x00\x0e\x10\x00\x09\x00\x00\x1c \x00\x0dLMT\x00CEST\x00CET\x00EET\x00\x0aEET-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x93\xf4\x94\x0b\xc1\x01\x00\x00\xc1\x01\x00\x00\x0c\x00\x00\x00Africa/TunisTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xffYF\x13\xf4\xff\xff\xff\xff\x91`PO\xff\xff\xff\xff\xc6:\x88\xe0\xff\xff\xff\xff\xc7X\x9e`\xff\xff\xff\xff\xc7\xdb\x22\xe0\xff\xff\xff\xff\xca\xe2T\xe0\xff\xff\xff\xff\xcb\xadi\xf0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xcd\xc2\x16\x00\xff\xff\xff\xff\xcd\xcc\xb0\x10\xff\xff\xff\xff\xce\xa25\x00\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x89\xe3\xe0\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2N\x16`\x00\x00\x00\x00\x0d\xc7\xdf\xf0\x00\x00\x00\x00\x0e\x89\xacp\x00\x00\x00\x00\x0f\xaad\xf0\x00\x00\x00\x00\x10t\x1ap\x00\x00\x00\x00\x22\xa3:\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&<\xc3p\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00Bt\x0d\xf0\x00\x00\x00\x00C<\x80\x00\x00\x00\x00\x00D%\xe7\x90\x00\x00\x00\x00EC\xfd\x10\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00\x09\x8c\x00\x00\x00\x00\x021\x00\x04\x00\x00\x1c \x01\x08\x00\x00\x0e\x10\x00\x0dLMT\x00PMT\x00CEST\x00CET\x00\x0aCET-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00m)\xb8P~\x02\x00\x00~\x02\x00\x00\x0f\x00\x00\x00Africa/WindhoekTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x00\x00\x00\x06\x00\x00\x00\x17\xff\xff\xff\xffm{Kx\xff\xff\xff\xff\x82F\xcfh\xff\xff\xff\xff\xcc\xae\x8c\x80\xff\xff\xff\xff\xcd\x9eop\x00\x00\x00\x00&\x06\xa7\xe0\x00\x00\x00\x00-\x8c\xc7`\x00\x00\x00\x00.i\x1c\x10\x00\x00\x00\x00/}\xe9\x00\x00\x00\x00\x000H\xfe\x10\x00\x00\x00\x001g\x05\x80\x00\x00\x00\x002(\xe0\x10\x00\x00\x00\x003F\xe7\x80\x00\x00\x00\x004\x11\xfc\x90\x00\x00\x00\x005&\xc9\x80\x00\x00\x00\x005\xf1\xde\x90\x00\x00\x00\x007\x06\xab\x80\x00\x00\x00\x007\xd1\xc0\x90\x00\x00\x00\x008\xe6\x8d\x80\x00\x00\x00\x009\xb1\xa2\x90\x00\x00\x00\x00:\xc6o\x80\x00\x00\x00\x00;\x91\x84\x90\x00\x00\x00\x00<\xaf\x8c\x00\x00\x00\x00\x00=qf\x90\x00\x00\x00\x00>\x8fn\x00\x00\x00\x00\x00?Z\x83\x10\x00\x00\x00\x00@oP\x00\x00\x00\x00\x00A:e\x10\x00\x00\x00\x00BO2\x00\x00\x00\x00\x00C\x1aG\x10\x00\x00\x00\x00D/\x14\x00\x00\x00\x00\x00D\xfa)\x10\x00\x00\x00\x00F\x0e\xf6\x00\x00\x00\x00\x00F\xda\x0b\x10\x00\x00\x00\x00G\xf8\x12\x80\x00\x00\x00\x00H\xc3'\x90\x00\x00\x00\x00I\xd7\xf4\x80\x00\x00\x00\x00J\xa3\x09\x90\x00\x00\x00\x00K\xb7\xd6\x80\x00\x00\x00\x00L\x82\xeb\x90\x00\x00\x00\x00M\x97\xb8\x80\x00\x00\x00\x00Nb\xcd\x90\x00\x00\x00\x00Ow\x9a\x80\x00\x00\x00\x00PB\xaf\x90\x00\x00\x00\x00Q`\xb7\x00\x00\x00\x00\x00R\x22\x91\x90\x00\x00\x00\x00S@\x99\x00\x00\x00\x00\x00T\x0b\xae\x10\x00\x00\x00\x00U {\x00\x00\x00\x00\x00U\xeb\x90\x10\x00\x00\x00\x00W\x00]\x00\x00\x00\x00\x00W\xcbr\x10\x00\x00\x00\x00X\xe0?\x00\x00\x00\x00\x00Y\xabT\x10\x01\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x00\x00\x10\x08\x00\x00\x00\x00\x15\x18\x00\x04\x00\x00\x1c \x00\x0a\x00\x00*0\x01\x0a\x00\x00\x0e\x10\x01\x0f\x00\x00\x1c \x00\x13LMT\x00+0130\x00SAST\x00WAT\x00CAT\x00\x0aCAT-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae,\xa44\xc9\x03\x00\x00\xc9\x03\x00\x00\x0c\x00\x00\x00America/AdakTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x0a\x00\x00\x00!\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x87Z^\xff\xff\xff\xff\xcb\x89D\xd0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aP@\xff\xff\xff\xff\xfa\xd2U\xb0\xff\xff\xff\xff\xfe\xb8qP\xff\xff\xff\xff\xff\xa8T@\x00\x00\x00\x00\x00\x98SP\x00\x00\x00\x00\x01\x886@\x00\x00\x00\x00\x02x5P\x00\x00\x00\x00\x03qR\xc0\x00\x00\x00\x00\x04aQ\xd0\x00\x00\x00\x00\x05Q4\xc0\x00\x00\x00\x00\x06A3\xd0\x00\x00\x00\x00\x071\x16\xc0\x00\x00\x00\x00\x07\x8dm\xd0\x00\x00\x00\x00\x09\x10\xf8\xc0\x00\x00\x00\x00\x09\xad\xe9P\x00\x00\x00\x00\x0a\xf0\xda\xc0\x00\x00\x00\x00\x0b\xe0\xd9\xd0\x00\x00\x00\x00\x0c\xd9\xf7@\x00\x00\x00\x00\x0d\xc0\xbb\xd0\x00\x00\x00\x00\x0e\xb9\xd9@\x00\x00\x00\x00\x0f\xa9\xd8P\x00\x00\x00\x00\x10\x99\xbb@\x00\x00\x00\x00\x11\x89\xbaP\x00\x00\x00\x00\x12y\x9d@\x00\x00\x00\x00\x13i\x9cP\x00\x00\x00\x00\x14Y\x7f@\x00\x00\x00\x00\x15I~P\x00\x00\x00\x00\x169a@\x00\x00\x00\x00\x17)`P\x00\x00\x00\x00\x18\x22}\xc0\x00\x00\x00\x00\x19\x09BP\x00\x00\x00\x00\x1a\x02_\xc0\x00\x00\x00\x00\x1a+\x22 \x00\x00\x00\x00\x1a\xf2P\xc0\x00\x00\x00\x00\x1b\xe23\xb0\x00\x00\x00\x00\x1c\xd22\xc0\x00\x00\x00\x00\x1d\xc2\x15\xb0\x00\x00\x00\x00\x1e\xb2\x14\xc0\x00\x00\x00\x00\x1f\xa1\xf7\xb0\x00\x00\x00\x00 vG@\x00\x00\x00\x00!\x81\xd9\xb0\x00\x00\x00\x00\x22V)@\x00\x00\x00\x00#j\xf60\x00\x00\x00\x00$6\x0b@\x00\x00\x00\x00%J\xd80\x00\x00\x00\x00&\x15\xed@\x00\x00\x00\x00'*\xba0\x00\x00\x00\x00'\xff\x09\xc0\x00\x00\x00\x00)\x0a\x9c0\x00\x00\x00\x00)\xde\xeb\xc0\x00\x00\x00\x00*\xea~0\x00\x00\x00\x00+\xbe\xcd\xc0\x00\x00\x00\x00,\xd3\x9a\xb0\x00\x00\x00\x00-\x9e\xaf\xc0\x00\x00\x00\x00.\xb3|\xb0\x00\x00\x00\x00/~\x91\xc0\x00\x00\x00\x000\x93^\xb0\x00\x00\x00\x001g\xae@\x00\x00\x00\x002s@\xb0\x00\x00\x00\x003G\x90@\x00\x00\x00\x004S\x22\xb0\x00\x00\x00\x005'r@\x00\x00\x00\x0063\x04\xb0\x00\x00\x00\x007\x07T@\x00\x00\x00\x008\x1c!0\x00\x00\x00\x008\xe76@\x00\x00\x00\x009\xfc\x030\x00\x00\x00\x00:\xc7\x18@\x00\x00\x00\x00;\xdb\xe50\x00\x00\x00\x00<\xb04\xc0\x00\x00\x00\x00=\xbb\xc70\x00\x00\x00\x00>\x90\x16\xc0\x00\x00\x00\x00?\x9b\xa90\x00\x00\x00\x00@o\xf8\xc0\x00\x00\x00\x00A\x84\xc5\xb0\x00\x00\x00\x00BO\xda\xc0\x00\x00\x00\x00Cd\xa7\xb0\x00\x00\x00\x00D/\xbc\xc0\x00\x00\x00\x00ED\x89\xb0\x00\x00\x00\x00E\xf3\xef@\x01\x02\x03\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x07\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x00\x00\xab\xe2\x00\x00\xff\xffZb\x00\x00\xff\xffeP\x00\x04\xff\xffs`\x01\x08\xff\xffs`\x01\x0c\xff\xffeP\x00\x10\xff\xffs`\x01\x14\xff\xffs`\x00\x18\xff\xff\x81p\x01\x1d\xff\xffs`\x00\x19LMT\x00NST\x00NWT\x00NPT\x00BST\x00BDT\x00AHST\x00HDT\x00\x0aHST10HDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x11Q\x06\xd1\x03\x00\x00\xd1\x03\x00\x00\x11\x00\x00\x00America/AnchorageTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x0a\x00\x00\x00(\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x87AH\xff\xff\xff\xff\xcb\x896\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aB0\xff\xff\xff\xff\xfa\xd2G\xa0\xff\xff\xff\xff\xfe\xb8c@\xff\xff\xff\xff\xff\xa8F0\x00\x00\x00\x00\x00\x98E@\x00\x00\x00\x00\x01\x88(0\x00\x00\x00\x00\x02x'@\x00\x00\x00\x00\x03qD\xb0\x00\x00\x00\x00\x04aC\xc0\x00\x00\x00\x00\x05Q&\xb0\x00\x00\x00\x00\x06A%\xc0\x00\x00\x00\x00\x071\x08\xb0\x00\x00\x00\x00\x07\x8d_\xc0\x00\x00\x00\x00\x09\x10\xea\xb0\x00\x00\x00\x00\x09\xad\xdb@\x00\x00\x00\x00\x0a\xf0\xcc\xb0\x00\x00\x00\x00\x0b\xe0\xcb\xc0\x00\x00\x00\x00\x0c\xd9\xe90\x00\x00\x00\x00\x0d\xc0\xad\xc0\x00\x00\x00\x00\x0e\xb9\xcb0\x00\x00\x00\x00\x0f\xa9\xca@\x00\x00\x00\x00\x10\x99\xad0\x00\x00\x00\x00\x11\x89\xac@\x00\x00\x00\x00\x12y\x8f0\x00\x00\x00\x00\x13i\x8e@\x00\x00\x00\x00\x14Yq0\x00\x00\x00\x00\x15Ip@\x00\x00\x00\x00\x169S0\x00\x00\x00\x00\x17)R@\x00\x00\x00\x00\x18\x22o\xb0\x00\x00\x00\x00\x19\x094@\x00\x00\x00\x00\x1a\x02Q\xb0\x00\x00\x00\x00\x1a+\x14\x10\x00\x00\x00\x00\x1a\xf2B\xb0\x00\x00\x00\x00\x1b\xe2%\xa0\x00\x00\x00\x00\x1c\xd2$\xb0\x00\x00\x00\x00\x1d\xc2\x07\xa0\x00\x00\x00\x00\x1e\xb2\x06\xb0\x00\x00\x00\x00\x1f\xa1\xe9\xa0\x00\x00\x00\x00 v90\x00\x00\x00\x00!\x81\xcb\xa0\x00\x00\x00\x00\x22V\x1b0\x00\x00\x00\x00#j\xe8 \x00\x00\x00\x00$5\xfd0\x00\x00\x00\x00%J\xca \x00\x00\x00\x00&\x15\xdf0\x00\x00\x00\x00'*\xac \x00\x00\x00\x00'\xfe\xfb\xb0\x00\x00\x00\x00)\x0a\x8e \x00\x00\x00\x00)\xde\xdd\xb0\x00\x00\x00\x00*\xeap \x00\x00\x00\x00+\xbe\xbf\xb0\x00\x00\x00\x00,\xd3\x8c\xa0\x00\x00\x00\x00-\x9e\xa1\xb0\x00\x00\x00\x00.\xb3n\xa0\x00\x00\x00\x00/~\x83\xb0\x00\x00\x00\x000\x93P\xa0\x00\x00\x00\x001g\xa00\x00\x00\x00\x002s2\xa0\x00\x00\x00\x003G\x820\x00\x00\x00\x004S\x14\xa0\x00\x00\x00\x005'd0\x00\x00\x00\x0062\xf6\xa0\x00\x00\x00\x007\x07F0\x00\x00\x00\x008\x1c\x13 \x00\x00\x00\x008\xe7(0\x00\x00\x00\x009\xfb\xf5 \x00\x00\x00\x00:\xc7\x0a0\x00\x00\x00\x00;\xdb\xd7 \x00\x00\x00\x00<\xb0&\xb0\x00\x00\x00\x00=\xbb\xb9 \x00\x00\x00\x00>\x90\x08\xb0\x00\x00\x00\x00?\x9b\x9b \x00\x00\x00\x00@o\xea\xb0\x00\x00\x00\x00A\x84\xb7\xa0\x00\x00\x00\x00BO\xcc\xb0\x00\x00\x00\x00Cd\x99\xa0\x00\x00\x00\x00D/\xae\xb0\x00\x00\x00\x00ED{\xa0\x00\x00\x00\x00E\xf3\xe10\x01\x02\x03\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x07\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x00\x00\xc4\xf8\x00\x00\xff\xffsx\x00\x00\xff\xffs`\x00\x04\xff\xff\x81p\x01\x08\xff\xff\x81p\x01\x0c\xff\xffs`\x00\x10\xff\xff\x81p\x01\x15\xff\xff\x81p\x00\x1a\xff\xff\x8f\x80\x01\x1e\xff\xff\x81p\x00#LMT\x00AST\x00AWT\x00APT\x00AHST\x00AHDT\x00YST\x00AKDT\x00AKST\x00\x0aAKST9AKDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00America/AnguillaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00America/AntiguaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x01V\x0dP\x02\x00\x00P\x02\x00\x00\x11\x00\x00\x00America/AraguainaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaat0\xff\xff\xff\xff\xb8\x0fI\xe0\xff\xff\xff\xff\xb8\xfd@\xa0\xff\xff\xff\xff\xb9\xf140\xff\xff\xff\xff\xba\xdet \xff\xff\xff\xff\xda8\xae0\xff\xff\xff\xff\xda\xeb\xfa0\xff\xff\xff\xff\xdc\x19\xe1\xb0\xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xfb\x150\xff\xff\xff\xff\xde\x9b\xde \xff\xff\xff\xff\xdf\xdd\x9a0\xff\xff\xff\xff\xe0T3 \xff\xff\xff\xff\xf4\x97\xff\xb0\xff\xff\xff\xff\xf5\x05^ \xff\xff\xff\xff\xf6\xc0d0\xff\xff\xff\xff\xf7\x0e\x1e\xa0\xff\xff\xff\xff\xf8Q,0\xff\xff\xff\xff\xf8\xc7\xc5 \xff\xff\xff\xff\xfa\x0a\xd2\xb0\xff\xff\xff\xff\xfa\xa8\xf8\xa0\xff\xff\xff\xff\xfb\xec\x060\xff\xff\xff\xff\xfc\x8b}\xa0\x00\x00\x00\x00\x1d\xc9\x8e0\x00\x00\x00\x00\x1ex\xd7\xa0\x00\x00\x00\x00\x1f\xa05\xb0\x00\x00\x00\x00 3\xcf\xa0\x00\x00\x00\x00!\x81i0\x00\x00\x00\x00\x22\x0b\xc8\xa0\x00\x00\x00\x00#X\x10\xb0\x00\x00\x00\x00#\xe2p \x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xd4\xc7 \x00\x00\x00\x000\x80y0\x00\x00\x00\x001\x1dM\xa0\x00\x00\x00\x002W \xb0\x00\x00\x00\x003\x06j \x00\x00\x00\x0048T0\x00\x00\x00\x004\xf8\xc1 \x00\x00\x00\x006 \x1f0\x00\x00\x00\x006\xcfh\xa0\x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xb8\x85 \x00\x00\x00\x009\xdf\xe30\x00\x00\x00\x00:\x8f,\xa0\x00\x00\x00\x00;\xc8\xff\xb0\x00\x00\x00\x00N\xf0\xa0\x00\x00\x00\x00P\x83e0\x00\x00\x00\x00Q 9\xa0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xd2\xd0\x00\x00\xff\xff\xe3\xe0\x01\x04\xff\xff\xd5\xd0\x00\x08LMT\x00-02\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\xbf\xf5\xe5\xc4\x02\x00\x00\xc4\x02\x00\x00\x1e\x00\x00\x00America/Argentina/Buenos_AiresTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xa8L\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x00\x00\x00\x00H\xfa\xa2\xb0\x00\x00\x00\x00I\xbca \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x03\x05\x04\x05\x04\x05\xff\xff\xc94\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\xc8\xd9\xf6\xc4\x02\x00\x00\xc4\x02\x00\x00\x1b\x00\x00\x00America/Argentina/CatamarcaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xaf,\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xbb\xf10\x00\x00\x00\x00@\xd5\x0b\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xc2T\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\xc8\xd9\xf6\xc4\x02\x00\x00\xc4\x02\x00\x00 \x00\x00\x00America/Argentina/ComodRivadaviaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xaf,\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xbb\xf10\x00\x00\x00\x00@\xd5\x0b\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xc2T\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef\xf0R\x8a\xc4\x02\x00\x00\xc4\x02\x00\x00\x19\x00\x00\x00America/Argentina/CordobaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xad\xb0\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x00\x00\x00\x00H\xfa\xa2\xb0\x00\x00\x00\x00I\xbca \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x04\x05\x04\x05\x03\x05\x04\x05\x04\x05\xff\xff\xc3\xd0\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00utZ\x1a\xb2\x02\x00\x00\xb2\x02\x00\x00\x17\x00\x00\x00America/Argentina/JujuyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xae\xb8\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'*W\xc0\x00\x00\x00\x00'\xe2\xdb\xb0\x00\x00\x00\x00(\xee\x8a@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x02\x03\x02\x04\x05\x04\x05\x03\x05\x04\x05\xff\xff\xc2\xc8\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00m\x07D\x0e\xcd\x02\x00\x00\xcd\x02\x00\x00\x1a\x00\x00\x00America/Argentina/La_RiojaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xb0,\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xcd\xb5\xa0\x00\x00\x00\x00(&&@\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xbb\xf10\x00\x00\x00\x00@\xd5\x0b\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x05\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xc1T\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\x92Z\x8c\xc4\x02\x00\x00\xc4\x02\x00\x00\x19\x00\x00\x00America/Argentina/MendozaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xb2\x04\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'\x194@\x00\x00\x00\x00'\xcd\xc3\xb0\x00\x00\x00\x00(\xfag\xc0\x00\x00\x00\x00)\xb0H\xb0\x00\x00\x00\x00*\xe0\xe1@\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xb0\x13\xb0\x00\x00\x00\x00AV>\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x02\x03\x02\x03\x02\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xbf|\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8ep\xb4c\xc4\x02\x00\x00\xc4\x02\x00\x00\x1e\x00\x00\x00America/Argentina/Rio_GallegosTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xb2d\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xbb\xf10\x00\x00\x00\x00@\xd5\x0b\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xbf\x1c\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t*\x9b!\xb2\x02\x00\x00\xb2\x02\x00\x00\x17\x00\x00\x00America/Argentina/SaltaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xae\xd4\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x04\x05\x04\x05\x03\x05\x04\x05\xff\xff\xc2\xac\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfcz=\xe1\xcd\x02\x00\x00\xcd\x02\x00\x00\x1a\x00\x00\x00America/Argentina/San_JuanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xb1\xbc\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xcd\xb5\xa0\x00\x00\x00\x00(&&@\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xba\x9f\xb0\x00\x00\x00\x00A\x030@\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x05\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xbf\xc4\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x80\xb9\x5c\xcd\x02\x00\x00\xcd\x02\x00\x00\x1a\x00\x00\x00America/Argentina/San_LuisTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xaf\xb4\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xfd\xa5\xa0\x00\x00\x00\x00'\x194@\x00\x00\x00\x00'\xcd\xc3\xb0\x00\x00\x00\x00(G\x1b\xc0\x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xba\x9f\xb0\x00\x00\x00\x00A\x030@\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\x93\xfc\xa0\x00\x00\x00\x00G\xd3R\xb0\x00\x00\x00\x00H\xf1v@\x00\x00\x00\x00I\xb34\xb0\x00\x00\x00\x00J\xd1X@\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x02\x03\x02\x05\x03\x05\x02\x05\x04\x03\x02\x03\x02\x05\xff\xff\xc1\xcc\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd8\xd6\xad\xd6\x02\x00\x00\xd6\x02\x00\x00\x19\x00\x00\x00America/Argentina/TucumanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xae\xa4\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xbb\xf10\x00\x00\x00\x00@\xcb\xd1@\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x00\x00\x00\x00H\xfa\xa2\xb0\x00\x00\x00\x00I\xbca \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\x04\x05\xff\xff\xc2\xdc\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8b}\xb6\x1e\xc4\x02\x00\x00\xc4\x02\x00\x00\x19\x00\x00\x00America/Argentina/UshuaiaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xb1\x88\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xb9N0\x00\x00\x00\x00@\xd5\x0b\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xbf\xf8\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0d\x00\x00\x00America/ArubaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\xa9y\x9at\x03\x00\x00t\x03\x00\x00\x10\x00\x00\x00America/AsuncionTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xffi\x87\x11\x90\xff\xff\xff\xff\xb8\x17\xf5\x90\x00\x00\x00\x00\x05+\xda@\x00\x00\x00\x00\x07\xfc\xf0\xb0\x00\x00\x00\x00\x0a\xcft\xc0\x00\x00\x00\x00\x0b\x97\xca\xb0\x00\x00\x00\x00\x0c\xb1\xf9\xc0\x00\x00\x00\x00\x0dx\xfe0\x00\x00\x00\x00\x0e\x93-@\x00\x00\x00\x00\x0fZ1\xb0\x00\x00\x00\x00\x10t`\xc0\x00\x00\x00\x00\x11dC\xb0\x00\x00\x00\x00\x12U\x94@\x00\x00\x00\x00\x13F\xc8\xb0\x00\x00\x00\x00\x148\x19@\x00\x00\x00\x00\x15'\xfc0\x00\x00\x00\x00\x16\x19L\xc0\x00\x00\x00\x00\x17\x09/\xb0\x00\x00\x00\x00\x17\xfa\x80@\x00\x00\x00\x00\x18\xeac0\x00\x00\x00\x00\x19\xdb\xb3\xc0\x00\x00\x00\x00\x1a\xcc\xe80\x00\x00\x00\x00\x1b\xbe8\xc0\x00\x00\x00\x00\x1c\xae\x1b\xb0\x00\x00\x00\x00\x1d\x9fl@\x00\x00\x00\x00\x1e\x8fO0\x00\x00\x00\x00\x1f\x80\x9f\xc0\x00\x00\x00\x00 p\x82\xb0\x00\x00\x00\x00!a\xd3@\x00\x00\x00\x00\x22S\x07\xb0\x00\x00\x00\x00#DX@\x00\x00\x00\x00$4;0\x00\x00\x00\x00%A;@\x00\x00\x00\x00&\x15n\xb0\x00\x00\x00\x00'\x06\xbf@\x00\x00\x00\x00'\xf6\xa20\x00\x00\x00\x00(\xee\x8a@\x00\x00\x00\x00)\xb0H\xb0\x00\x00\x00\x00*\xcf\xbd\xc0\x00\x00\x00\x00+\xb9\x090\x00\x00\x00\x00,\xab\xab@\x00\x00\x00\x00-p\x0c\xb0\x00\x00\x00\x00.\x8c\xde\xc0\x00\x00\x00\x00/O\xee\xb0\x00\x00\x00\x000n\x12@\x00\x00\x00\x0016h0\x00\x00\x00\x002W.\xc0\x00\x00\x00\x003\x0f\xb2\xb0\x00\x00\x00\x0047\x10\xc0\x00\x00\x00\x004\xf8\xcf0\x00\x00\x00\x006\x16\xf2\xc0\x00\x00\x00\x006\xe1\xeb\xb0\x00\x00\x00\x007\xf6\xd4\xc0\x00\x00\x00\x008\xc1\xcd\xb0\x00\x00\x00\x009\xd6\xb6\xc0\x00\x00\x00\x00:\xa1\xaf\xb0\x00\x00\x00\x00;\xbf\xd3@\x00\x00\x00\x00<\xaf\xb60\x00\x00\x00\x00=q\x90\xc0\x00\x00\x00\x00>\x8f\x980\x00\x00\x00\x00?Z\xad@\x00\x00\x00\x00@oz0\x00\x00\x00\x00Aq\xee@\x00\x00\x00\x00B3\xac\xb0\x00\x00\x00\x00CQ\xd0@\x00\x00\x00\x00D\x13\x8e\xb0\x00\x00\x00\x00E1\xb2@\x00\x00\x00\x00E\xf3p\xb0\x00\x00\x00\x00G\x1a\xce\xc0\x00\x00\x00\x00G\xd3R\xb0\x00\x00\x00\x00H\xfa\xb0\xc0\x00\x00\x00\x00I\xb34\xb0\x00\x00\x00\x00J\xda\x92\xc0\x00\x00\x00\x00K\xc1;0\x00\x00\x00\x00L\xa7\xff\xc0\x00\x00\x00\x00M\xa1\x1d0\x00\x00\x00\x00N\x87\xe1\xc0\x00\x00\x00\x00O\x80\xff0\x00\x00\x00\x00Pp\xfe@\x01\x02\x03\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\xff\xff\xc9\xf0\x00\x00\xff\xff\xc9\xf0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x00\x0c\xff\xff\xd5\xd0\x01\x0cLMT\x00AMT\x00-04\x00-03\x00\x0a<-04>4<-03>,M10.1.0/0,M3.4.0/0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4\xbe\xe7#\x95\x00\x00\x00\x95\x00\x00\x00\x10\x00\x00\x00America/AtikokanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffi\x87&\x10\xff\xff\xff\xff\x8b\xf4a\xe8\x01\x02\xff\xff\xb5p\x00\x00\xff\xff\xb5\x18\x00\x04\xff\xff\xb9\xb0\x00\x08LMT\x00CMT\x00EST\x00\x0aEST5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae,\xa44\xc9\x03\x00\x00\xc9\x03\x00\x00\x0c\x00\x00\x00America/AtkaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x0a\x00\x00\x00!\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x87Z^\xff\xff\xff\xff\xcb\x89D\xd0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aP@\xff\xff\xff\xff\xfa\xd2U\xb0\xff\xff\xff\xff\xfe\xb8qP\xff\xff\xff\xff\xff\xa8T@\x00\x00\x00\x00\x00\x98SP\x00\x00\x00\x00\x01\x886@\x00\x00\x00\x00\x02x5P\x00\x00\x00\x00\x03qR\xc0\x00\x00\x00\x00\x04aQ\xd0\x00\x00\x00\x00\x05Q4\xc0\x00\x00\x00\x00\x06A3\xd0\x00\x00\x00\x00\x071\x16\xc0\x00\x00\x00\x00\x07\x8dm\xd0\x00\x00\x00\x00\x09\x10\xf8\xc0\x00\x00\x00\x00\x09\xad\xe9P\x00\x00\x00\x00\x0a\xf0\xda\xc0\x00\x00\x00\x00\x0b\xe0\xd9\xd0\x00\x00\x00\x00\x0c\xd9\xf7@\x00\x00\x00\x00\x0d\xc0\xbb\xd0\x00\x00\x00\x00\x0e\xb9\xd9@\x00\x00\x00\x00\x0f\xa9\xd8P\x00\x00\x00\x00\x10\x99\xbb@\x00\x00\x00\x00\x11\x89\xbaP\x00\x00\x00\x00\x12y\x9d@\x00\x00\x00\x00\x13i\x9cP\x00\x00\x00\x00\x14Y\x7f@\x00\x00\x00\x00\x15I~P\x00\x00\x00\x00\x169a@\x00\x00\x00\x00\x17)`P\x00\x00\x00\x00\x18\x22}\xc0\x00\x00\x00\x00\x19\x09BP\x00\x00\x00\x00\x1a\x02_\xc0\x00\x00\x00\x00\x1a+\x22 \x00\x00\x00\x00\x1a\xf2P\xc0\x00\x00\x00\x00\x1b\xe23\xb0\x00\x00\x00\x00\x1c\xd22\xc0\x00\x00\x00\x00\x1d\xc2\x15\xb0\x00\x00\x00\x00\x1e\xb2\x14\xc0\x00\x00\x00\x00\x1f\xa1\xf7\xb0\x00\x00\x00\x00 vG@\x00\x00\x00\x00!\x81\xd9\xb0\x00\x00\x00\x00\x22V)@\x00\x00\x00\x00#j\xf60\x00\x00\x00\x00$6\x0b@\x00\x00\x00\x00%J\xd80\x00\x00\x00\x00&\x15\xed@\x00\x00\x00\x00'*\xba0\x00\x00\x00\x00'\xff\x09\xc0\x00\x00\x00\x00)\x0a\x9c0\x00\x00\x00\x00)\xde\xeb\xc0\x00\x00\x00\x00*\xea~0\x00\x00\x00\x00+\xbe\xcd\xc0\x00\x00\x00\x00,\xd3\x9a\xb0\x00\x00\x00\x00-\x9e\xaf\xc0\x00\x00\x00\x00.\xb3|\xb0\x00\x00\x00\x00/~\x91\xc0\x00\x00\x00\x000\x93^\xb0\x00\x00\x00\x001g\xae@\x00\x00\x00\x002s@\xb0\x00\x00\x00\x003G\x90@\x00\x00\x00\x004S\x22\xb0\x00\x00\x00\x005'r@\x00\x00\x00\x0063\x04\xb0\x00\x00\x00\x007\x07T@\x00\x00\x00\x008\x1c!0\x00\x00\x00\x008\xe76@\x00\x00\x00\x009\xfc\x030\x00\x00\x00\x00:\xc7\x18@\x00\x00\x00\x00;\xdb\xe50\x00\x00\x00\x00<\xb04\xc0\x00\x00\x00\x00=\xbb\xc70\x00\x00\x00\x00>\x90\x16\xc0\x00\x00\x00\x00?\x9b\xa90\x00\x00\x00\x00@o\xf8\xc0\x00\x00\x00\x00A\x84\xc5\xb0\x00\x00\x00\x00BO\xda\xc0\x00\x00\x00\x00Cd\xa7\xb0\x00\x00\x00\x00D/\xbc\xc0\x00\x00\x00\x00ED\x89\xb0\x00\x00\x00\x00E\xf3\xef@\x01\x02\x03\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x07\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x00\x00\xab\xe2\x00\x00\xff\xffZb\x00\x00\xff\xffeP\x00\x04\xff\xffs`\x01\x08\xff\xffs`\x01\x0c\xff\xffeP\x00\x10\xff\xffs`\x01\x14\xff\xffs`\x00\x18\xff\xff\x81p\x01\x1d\xff\xffs`\x00\x19LMT\x00NST\x00NWT\x00NPT\x00BST\x00BDT\x00AHST\x00HDT\x00\x0aHST10HDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00OKj\xc7\xaa\x02\x00\x00\xaa\x02\x00\x00\x0d\x00\x00\x00America/BahiaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaak\x1c\xff\xff\xff\xff\xb8\x0fI\xe0\xff\xff\xff\xff\xb8\xfd@\xa0\xff\xff\xff\xff\xb9\xf140\xff\xff\xff\xff\xba\xdet \xff\xff\xff\xff\xda8\xae0\xff\xff\xff\xff\xda\xeb\xfa0\xff\xff\xff\xff\xdc\x19\xe1\xb0\xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xfb\x150\xff\xff\xff\xff\xde\x9b\xde \xff\xff\xff\xff\xdf\xdd\x9a0\xff\xff\xff\xff\xe0T3 \xff\xff\xff\xff\xf4\x97\xff\xb0\xff\xff\xff\xff\xf5\x05^ \xff\xff\xff\xff\xf6\xc0d0\xff\xff\xff\xff\xf7\x0e\x1e\xa0\xff\xff\xff\xff\xf8Q,0\xff\xff\xff\xff\xf8\xc7\xc5 \xff\xff\xff\xff\xfa\x0a\xd2\xb0\xff\xff\xff\xff\xfa\xa8\xf8\xa0\xff\xff\xff\xff\xfb\xec\x060\xff\xff\xff\xff\xfc\x8b}\xa0\x00\x00\x00\x00\x1d\xc9\x8e0\x00\x00\x00\x00\x1ex\xd7\xa0\x00\x00\x00\x00\x1f\xa05\xb0\x00\x00\x00\x00 3\xcf\xa0\x00\x00\x00\x00!\x81i0\x00\x00\x00\x00\x22\x0b\xc8\xa0\x00\x00\x00\x00#X\x10\xb0\x00\x00\x00\x00#\xe2p \x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xd4\xc7 \x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xbd\xe3\xa0\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\x94\x8b \x00\x00\x00\x00*\xea\x0d\xb0\x00\x00\x00\x00+k2\xa0\x00\x00\x00\x00,\xc0\xb50\x00\x00\x00\x00-f\xc4 \x00\x00\x00\x00.\xa0\x970\x00\x00\x00\x00/F\xa6 \x00\x00\x00\x000\x80y0\x00\x00\x00\x001\x1dM\xa0\x00\x00\x00\x002W \xb0\x00\x00\x00\x003\x06j \x00\x00\x00\x0048T0\x00\x00\x00\x004\xf8\xc1 \x00\x00\x00\x006 \x1f0\x00\x00\x00\x006\xcfh\xa0\x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xb8\x85 \x00\x00\x00\x009\xdf\xe30\x00\x00\x00\x00:\x8f,\xa0\x00\x00\x00\x00;\xc8\xff\xb0\x00\x00\x00\x00N\xf0\xa0\x00\x00\x00\x00N\x9aH\xb0\x00\x00\x00\x00OI\x92 \x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xdb\xe4\x00\x00\xff\xff\xe3\xe0\x01\x04\xff\xff\xd5\xd0\x00\x08LMT\x00-02\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x0e\x01n\xd8\x02\x00\x00\xd8\x02\x00\x00\x16\x00\x00\x00America/Bahia_BanderasTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\xff\xff\xff\xff\xcb\xeaq`\xff\xff\xff\xff\xd8\x91\xb4\xf0\x00\x00\x00\x00\x00\x00p\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xf5\x12\x90\x00\x00\x00\x00;\xb6\xd1\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00F\x0ft\x90\x00\x00\x00\x00G$A\x80\x00\x00\x00\x00G\xf8\x91\x10\x00\x00\x00\x00I\x04#\x80\x00\x00\x00\x00I\xd8s\x10\x00\x00\x00\x00J\xe4\x05\x80\x00\x00\x00\x00K\xb8U\x10\x00\x00\x00\x00L\xcd\x13\xf0\x00\x00\x00\x00M\x98)\x00\x00\x00\x00\x00N\xac\xf5\xf0\x00\x00\x00\x00Ox\x0b\x00\x00\x00\x00\x00P\x8c\xd7\xf0\x00\x00\x00\x00Qa'\x80\x00\x00\x00\x00Rl\xb9\xf0\x00\x00\x00\x00SA\x09\x80\x00\x00\x00\x00TL\x9b\xf0\x00\x00\x00\x00U \xeb\x80\x00\x00\x00\x00V,}\xf0\x00\x00\x00\x00W\x00\xcd\x80\x00\x00\x00\x00X\x15\x9ap\x00\x00\x00\x00X\xe0\xaf\x80\x00\x00\x00\x00Y\xf5|p\x00\x00\x00\x00Z\xc0\x91\x80\x00\x00\x00\x00[\xd5^p\x00\x00\x00\x00\x5c\xa9\xae\x00\x00\x00\x00\x00]\xb5@p\x00\x00\x00\x00^\x89\x90\x00\x00\x00\x00\x00_\x95\x22p\x00\x00\x00\x00`ir\x00\x00\x00\x00\x00a~>\xf0\x00\x00\x00\x00bIT\x00\x00\x00\x00\x00c^ \xf0\x01\x02\x01\x03\x01\x02\x01\x04\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\xff\xff\x9dT\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\x8f\x80\x00\x10\xff\xff\xb9\xb0\x01\x14LMT\x00MST\x00CST\x00MDT\x00PST\x00CDT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00l=\xad\xbe\x16\x01\x00\x00\x16\x01\x00\x00\x10\x00\x00\x00America/BarbadosTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x92@\xa9e\xff\xff\xff\xff\xcb\xe3\xcb\xd0\xff\xff\xff\xff\xcc\x94\x82\xe0\xff\xff\xff\xff\xcd\xd6\x22\xd0\xff\xff\xff\xff\xce|M\xe0\xff\xff\xff\xff\xcf\x9b\xa6\xd0\xff\xff\xff\xff\xd0ej`\x00\x00\x00\x00\x0e\x00\xf2\xe0\x00\x00\x00\x00\x0e\x94\x8c\xd0\x00\x00\x00\x00\x0f\x97\x00\xe0\x00\x00\x00\x00\x10tn\xd0\x00\x00\x00\x00\x11v\xe2\xe0\x00\x00\x00\x00\x12TP\xd0\x00\x00\x00\x00\x13_\xff`\x00\x00\x00\x00\x140>P\x02\x01\x02\x01\x02\x03\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xc8\x1b\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xce\xc8\x01\x0cLMT\x00ADT\x00AST\x00-0330\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85-\xb9\xf8\x8a\x01\x00\x00\x8a\x01\x00\x00\x0d\x00\x00\x00America/BelemTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaatt\xff\xff\xff\xff\xb8\x0fI\xe0\xff\xff\xff\xff\xb8\xfd@\xa0\xff\xff\xff\xff\xb9\xf140\xff\xff\xff\xff\xba\xdet \xff\xff\xff\xff\xda8\xae0\xff\xff\xff\xff\xda\xeb\xfa0\xff\xff\xff\xff\xdc\x19\xe1\xb0\xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xfb\x150\xff\xff\xff\xff\xde\x9b\xde \xff\xff\xff\xff\xdf\xdd\x9a0\xff\xff\xff\xff\xe0T3 \xff\xff\xff\xff\xf4\x97\xff\xb0\xff\xff\xff\xff\xf5\x05^ \xff\xff\xff\xff\xf6\xc0d0\xff\xff\xff\xff\xf7\x0e\x1e\xa0\xff\xff\xff\xff\xf8Q,0\xff\xff\xff\xff\xf8\xc7\xc5 \xff\xff\xff\xff\xfa\x0a\xd2\xb0\xff\xff\xff\xff\xfa\xa8\xf8\xa0\xff\xff\xff\xff\xfb\xec\x060\xff\xff\xff\xff\xfc\x8b}\xa0\x00\x00\x00\x00\x1d\xc9\x8e0\x00\x00\x00\x00\x1ex\xd7\xa0\x00\x00\x00\x00\x1f\xa05\xb0\x00\x00\x00\x00 3\xcf\xa0\x00\x00\x00\x00!\x81i0\x00\x00\x00\x00\x22\x0b\xc8\xa0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xd2\x8c\x00\x00\xff\xff\xe3\xe0\x01\x04\xff\xff\xd5\xd0\x00\x08LMT\x00-02\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x89\xd8\xba\xee\x15\x04\x00\x00\x15\x04\x00\x00\x0e\x00\x00\x00America/BelizeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\x00\x00\x00\x06\x00\x00\x00\x1a\xff\xff\xff\xff\x93^\xd9\xb0\xff\xff\xff\xff\x9f\x9f;\xe0\xff\xff\xff\xff\xa0EQ\xd8\xff\xff\xff\xff\xa1\x7f\x1d\xe0\xff\xff\xff\xff\xa2.nX\xff\xff\xff\xff\xa3^\xff\xe0\xff\xff\xff\xff\xa4\x0ePX\xff\xff\xff\xff\xa5>\xe1\xe0\xff\xff\xff\xff\xa5\xee2X\xff\xff\xff\xff\xa7'\xfe`\xff\xff\xff\xff\xa7\xce\x14X\xff\xff\xff\xff\xa9\x07\xe0`\xff\xff\xff\xff\xa9\xad\xf6X\xff\xff\xff\xff\xaa\xe7\xc2`\xff\xff\xff\xff\xab\x97\x12\xd8\xff\xff\xff\xff\xac\xc7\xa4`\xff\xff\xff\xff\xadv\xf4\xd8\xff\xff\xff\xff\xae\xa7\x86`\xff\xff\xff\xff\xafV\xd6\xd8\xff\xff\xff\xff\xb0\x87h`\xff\xff\xff\xff\xb16\xb8\xd8\xff\xff\xff\xff\xb2p\x84\xe0\xff\xff\xff\xff\xb3\x16\x9a\xd8\xff\xff\xff\xff\xb4Pf\xe0\xff\xff\xff\xff\xb4\xf6|\xd8\xff\xff\xff\xff\xb60H\xe0\xff\xff\xff\xff\xb6\xdf\x99X\xff\xff\xff\xff\xb8\x10*\xe0\xff\xff\xff\xff\xb8\xbf{X\xff\xff\xff\xff\xb9\xf0\x0c\xe0\xff\xff\xff\xff\xba\x9f]X\xff\xff\xff\xff\xbb\xd9)`\xff\xff\xff\xff\xbc\x7f?X\xff\xff\xff\xff\xbd\xb9\x0b`\xff\xff\xff\xff\xbe_!X\xff\xff\xff\xff\xbf\x98\xed`\xff\xff\xff\xff\xc0?\x03X\xff\xff\xff\xff\xc1x\xcf`\xff\xff\xff\xff\xc2(\x1f\xd8\xff\xff\xff\xff\xc3X\xb1`\xff\xff\xff\xff\xc4\x08\x01\xd8\xff\xff\xff\xff\xc58\x93`\xff\xff\xff\xff\xc5\xe7\xe3\xd8\xff\xff\xff\xff\xc7!\xaf\xe0\xff\xff\xff\xff\xc7\xc7\xc5\xd8\xff\xff\xff\xff\xc9\x01\x91\xe0\xff\xff\xff\xff\xc9\xa7\xa7\xd8\xff\xff\xff\xff\xca\xe1s\xe0\xff\xff\xff\xff\xcb\x90\xc4X\xff\xff\xff\xff\xcc@\x22\xe0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2\xc6qP\xff\xff\xff\xff\xd6)\xfa`\xff\xff\xff\xff\xd6\xd9J\xd8\xff\xff\xff\xff\xd8\x09\xdc`\xff\xff\xff\xff\xd8\xb9,\xd8\xff\xff\xff\xff\xd9\xe9\xbe`\xff\xff\xff\xff\xda\x99\x0e\xd8\xff\xff\xff\xff\xdb\xd2\xda\xe0\xff\xff\xff\xff\xdcx\xf0\xd8\xff\xff\xff\xff\xdd\xb2\xbc\xe0\xff\xff\xff\xff\xdeX\xd2\xd8\xff\xff\xff\xff\xdf\x92\x9e\xe0\xff\xff\xff\xff\xe0A\xefX\xff\xff\xff\xff\xe1r\x80\xe0\xff\xff\xff\xff\xe2!\xd1X\xff\xff\xff\xff\xe3Rb\xe0\xff\xff\xff\xff\xe4\x01\xb3X\xff\xff\xff\xff\xe52D\xe0\xff\xff\xff\xff\xe5\xe1\x95X\xff\xff\xff\xff\xe7\x1ba`\xff\xff\xff\xff\xe7\xc1wX\xff\xff\xff\xff\xe8\xfbC`\xff\xff\xff\xff\xe9\xa1YX\xff\xff\xff\xff\xea\xdb%`\xff\xff\xff\xff\xeb\x8au\xd8\xff\xff\xff\xff\xec\xbb\x07`\xff\xff\xff\xff\xedjW\xd8\xff\xff\xff\xff\xee\x9a\xe9`\xff\xff\xff\xff\xefJ9\xd8\xff\xff\xff\xff\xf0\x84\x05\xe0\xff\xff\xff\xff\xf1*\x1b\xd8\xff\xff\xff\xff\xf2c\xe7\xe0\xff\xff\xff\xff\xf3\x09\xfd\xd8\xff\xff\xff\xff\xf4C\xc9\xe0\xff\xff\xff\xff\xf4\xe9\xdf\xd8\xff\xff\xff\xff\xf6#\xab\xe0\xff\xff\xff\xff\xf6\xd2\xfcX\xff\xff\xff\xff\xf8\x03\x8d\xe0\xff\xff\xff\xff\xf8\xb2\xdeX\xff\xff\xff\xff\xf9\xe3o\xe0\xff\xff\xff\xff\xfa\x92\xc0X\xff\xff\xff\xff\xfb\xcc\x8c`\xff\xff\xff\xff\xfcr\xa2X\x00\x00\x00\x00\x07b\xdb`\x00\x00\x00\x00\x07\xb9\xd0P\x00\x00\x00\x00\x18aq`\x00\x00\x00\x00\x18\xab7P\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x05\x02\xff\xff\xadP\x00\x00\xff\xff\xb2\xa8\x01\x04\xff\xff\xab\xa0\x00\x0a\xff\xff\xb9\xb0\x01\x0e\xff\xff\xb9\xb0\x01\x12\xff\xff\xb9\xb0\x01\x16LMT\x00-0530\x00CST\x00CWT\x00CPT\x00CDT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x14\x00\x00\x00America/Blanc-SablonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8Dz\x97\xae\x01\x00\x00\xae\x01\x00\x00\x11\x00\x00\x00America/Boa_VistaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa\x7f\xe0\xff\xff\xff\xff\xb8\x0fW\xf0\xff\xff\xff\xff\xb8\xfdN\xb0\xff\xff\xff\xff\xb9\xf1B@\xff\xff\xff\xff\xba\xde\x820\xff\xff\xff\xff\xda8\xbc@\xff\xff\xff\xff\xda\xec\x08@\xff\xff\xff\xff\xdc\x19\xef\xc0\xff\xff\xff\xff\xdc\xb9g0\xff\xff\xff\xff\xdd\xfb#@\xff\xff\xff\xff\xde\x9b\xec0\xff\xff\xff\xff\xdf\xdd\xa8@\xff\xff\xff\xff\xe0TA0\xff\xff\xff\xff\xf4\x98\x0d\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf6\xc0r@\xff\xff\xff\xff\xf7\x0e,\xb0\xff\xff\xff\xff\xf8Q:@\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xfa\x0a\xe0\xc0\xff\xff\xff\xff\xfa\xa9\x06\xb0\xff\xff\xff\xff\xfb\xec\x14@\xff\xff\xff\xff\xfc\x8b\x8b\xb0\x00\x00\x00\x00\x1d\xc9\x9c@\x00\x00\x00\x00\x1ex\xe5\xb0\x00\x00\x00\x00\x1f\xa0C\xc0\x00\x00\x00\x00 3\xdd\xb0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22\x0b\xd6\xb0\x00\x00\x00\x007\xf6\xd4\xc0\x00\x00\x00\x008\xb8\x930\x00\x00\x00\x009\xdf\xf1@\x00\x00\x00\x009\xe9\x1d\xb0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xc7 \x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08LMT\x00-03\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,g\xec\xec\xb3\x00\x00\x00\xb3\x00\x00\x00\x0e\x00\x00\x00America/BogotaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff^\x9c4\xf0\xff\xff\xff\xff\x98XUp\x00\x00\x00\x00*\x03sP\x00\x00\x00\x00+t\x89@\x01\x03\x02\x03\xff\xff\xba\x90\x00\x00\xff\xff\xba\x90\x00\x04\xff\xff\xc7\xc0\x01\x08\xff\xff\xb9\xb0\x00\x0cLMT\x00BMT\x00-04\x00-05\x00\x0a<-05>5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.\xbe\x1a>\xe7\x03\x00\x00\xe7\x03\x00\x00\x0d\x00\x00\x00America/BoiseTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Z\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x04\x1a\xc0\xff\xff\xff\xff\x9e\xa6H\xa0\xff\xff\xff\xff\x9f\xbb\x15\x90\xff\xff\xff\xff\xa0\x86*\xa0\xff\xff\xff\xff\xa1\x9a\xf7\x90\xff\xff\xff\xff\xa8FL \xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8W\x10\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb89\x10\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x1b\x10\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xfd\x10\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x07\xb2\x1f\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x09\xad\xb1\x10\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x05\x03\x04\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\xff\xff\x93\x0f\x00\x00\xff\xff\x9d\x90\x01\x04\xff\xff\x8f\x80\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\x9d\x90\x00\x14\xff\xff\xab\xa0\x01\x18LMT\x00PDT\x00PST\x00MWT\x00MPT\x00MST\x00MDT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\xbf\xf5\xe5\xc4\x02\x00\x00\xc4\x02\x00\x00\x14\x00\x00\x00America/Buenos_AiresTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xa8L\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x00\x00\x00\x00H\xfa\xa2\xb0\x00\x00\x00\x00I\xbca \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x03\x05\x04\x05\x04\x05\xff\xff\xc94\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\xba\xb2\x94s\x03\x00\x00s\x03\x00\x00\x15\x00\x00\x00America/Cambridge_BayTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L\x00\x00\x00\x08\x00\x00\x00 \xff\xff\xff\xff\xa1\xf2\xcd\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x08 \xdd\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x0a\x00\xbf\x90\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\x04\xe9P\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x03\x01\x02\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x06\x05\x07\x06\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x00\x00\x00\x00\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\xab\xa0\x01\x08\xff\xff\x9d\x90\x00\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\xb9\xb0\x01\x14\xff\xff\xab\xa0\x00\x18\xff\xff\xb9\xb0\x00\x1c-00\x00MWT\x00MPT\x00MST\x00MDT\x00CDT\x00CST\x00EST\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\xfbn\xdb\xb8\x03\x00\x00\xb8\x03\x00\x00\x14\x00\x00\x00America/Campo_GrandeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaaz4\xff\xff\xff\xff\xb8\x0fW\xf0\xff\xff\xff\xff\xb8\xfdN\xb0\xff\xff\xff\xff\xb9\xf1B@\xff\xff\xff\xff\xba\xde\x820\xff\xff\xff\xff\xda8\xbc@\xff\xff\xff\xff\xda\xec\x08@\xff\xff\xff\xff\xdc\x19\xef\xc0\xff\xff\xff\xff\xdc\xb9g0\xff\xff\xff\xff\xdd\xfb#@\xff\xff\xff\xff\xde\x9b\xec0\xff\xff\xff\xff\xdf\xdd\xa8@\xff\xff\xff\xff\xe0TA0\xff\xff\xff\xff\xf4\x98\x0d\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf6\xc0r@\xff\xff\xff\xff\xf7\x0e,\xb0\xff\xff\xff\xff\xf8Q:@\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xfa\x0a\xe0\xc0\xff\xff\xff\xff\xfa\xa9\x06\xb0\xff\xff\xff\xff\xfb\xec\x14@\xff\xff\xff\xff\xfc\x8b\x8b\xb0\x00\x00\x00\x00\x1d\xc9\x9c@\x00\x00\x00\x00\x1ex\xe5\xb0\x00\x00\x00\x00\x1f\xa0C\xc0\x00\x00\x00\x00 3\xdd\xb0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22\x0b\xd6\xb0\x00\x00\x00\x00#X\x1e\xc0\x00\x00\x00\x00#\xe2~0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xd4\xd50\x00\x00\x00\x00'!\x1d@\x00\x00\x00\x00'\xbd\xf1\xb0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\x94\x990\x00\x00\x00\x00*\xea\x1b\xc0\x00\x00\x00\x00+k@\xb0\x00\x00\x00\x00,\xc0\xc3@\x00\x00\x00\x00-f\xd20\x00\x00\x00\x00.\xa0\xa5@\x00\x00\x00\x00/F\xb40\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001\x1d[\xb0\x00\x00\x00\x002W.\xc0\x00\x00\x00\x003\x06x0\x00\x00\x00\x0048b@\x00\x00\x00\x004\xf8\xcf0\x00\x00\x00\x006 -@\x00\x00\x00\x006\xcfv\xb0\x00\x00\x00\x007\xf6\xd4\xc0\x00\x00\x00\x008\xb8\x930\x00\x00\x00\x009\xdf\xf1@\x00\x00\x00\x00:\x8f:\xb0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00N\xfe\xb0\x00\x00\x00\x00?\x92\x0c@\x00\x00\x00\x00@.\xe0\xb0\x00\x00\x00\x00A\x87\x06@\x00\x00\x00\x00B\x17\xfd0\x00\x00\x00\x00CQ\xd0@\x00\x00\x00\x00C\xf7\xdf0\x00\x00\x00\x00EMa\xc0\x00\x00\x00\x00E\xe0\xfb\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xb7\xa30\x00\x00\x00\x00H\xfa\xb0\xc0\x00\x00\x00\x00I\x97\x850\x00\x00\x00\x00J\xda\x92\xc0\x00\x00\x00\x00K\x80\xa1\xb0\x00\x00\x00\x00L\xbat\xc0\x00\x00\x00\x00M`\x83\xb0\x00\x00\x00\x00N\x9aV\xc0\x00\x00\x00\x00OI\xa00\x00\x00\x00\x00P\x83s@\x00\x00\x00\x00Q G\xb0\x00\x00\x00\x00RcU@\x00\x00\x00\x00S\x00)\xb0\x00\x00\x00\x00TC7@\x00\x00\x00\x00T\xe9F0\x00\x00\x00\x00V#\x19@\x00\x00\x00\x00V\xc9(0\x00\x00\x00\x00X\x02\xfb@\x00\x00\x00\x00X\xa9\x0a0\x00\x00\x00\x00Y\xe2\xdd@\x00\x00\x00\x00Z\x88\xec0\x00\x00\x00\x00[\xden\xc0\x00\x00\x00\x00\x5ch\xce0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xcc\xcc\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08LMT\x00-03\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf2\x04\xde\xdd\x11\x02\x00\x00\x11\x02\x00\x00\x0e\x00\x00\x00America/CancunTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xa5\xb6\xda`\x00\x00\x00\x00\x16\x86\xd5`\x00\x00\x00\x001gg\xf0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003GI\xf0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x005'+\xf0\x00\x00\x00\x005\xc4\x00`\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xf5\x04\x80\x00\x00\x00\x00;\xb6\xc2\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00F\x0ff\x80\x00\x00\x00\x00G$3p\x00\x00\x00\x00G\xf8\x83\x00\x00\x00\x00\x00I\x04\x15p\x00\x00\x00\x00I\xd8e\x00\x00\x00\x00\x00J\xe3\xf7p\x00\x00\x00\x00K\xb8G\x00\x00\x00\x00\x00L\xcd\x13\xf0\x00\x00\x00\x00M\x98)\x00\x00\x00\x00\x00N\xac\xf5\xf0\x00\x00\x00\x00Ox\x0b\x00\x00\x00\x00\x00P\x8c\xd7\xf0\x00\x00\x00\x00Qa'\x80\x00\x00\x00\x00Rl\xb9\xf0\x00\x00\x00\x00SA\x09\x80\x00\x00\x00\x00TL\x9b\xf0\x00\x00\x00\x00T\xcd\xdd\x00\x01\x03\x02\x03\x02\x03\x02\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x03\xff\xff\xae\xa8\x00\x00\xff\xff\xab\xa0\x00\x04\xff\xff\xc7\xc0\x01\x08\xff\xff\xb9\xb0\x00\x0c\xff\xff\xb9\xb0\x01\x10LMT\x00CST\x00EDT\x00EST\x00CDT\x00\x0aEST5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x8e\xee\x13\xbe\x00\x00\x00\xbe\x00\x00\x00\x0f\x00\x00\x00America/CaracasTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffi\x87\x1a@\xff\xff\xff\xff\x93\x1e,<\xff\xff\xff\xff\xf6\x98\xecH\x00\x00\x00\x00G[\x92p\x00\x00\x00\x00W%\xa9p\x01\x02\x03\x02\x03\xff\xff\xc1@\x00\x00\xff\xff\xc1D\x00\x04\xff\xff\xc0\xb8\x00\x08\xff\xff\xc7\xc0\x00\x0eLMT\x00CMT\x00-0430\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\xc8\xd9\xf6\xc4\x02\x00\x00\xc4\x02\x00\x00\x11\x00\x00\x00America/CatamarcaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xaf,\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xbb\xf10\x00\x00\x00\x00@\xd5\x0b\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x04\x05\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xc2T\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1'\x07\xbd\x97\x00\x00\x00\x97\x00\x00\x00\x0f\x00\x00\x00America/CayenneTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x91\xf4+\x90\xff\xff\xff\xff\xfb\xc35\xc0\x01\x02\xff\xff\xce\xf0\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x00\x08LMT\x00-04\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4\xbe\xe7#\x95\x00\x00\x00\x95\x00\x00\x00\x0e\x00\x00\x00America/CaymanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffi\x87&\x10\xff\xff\xff\xff\x8b\xf4a\xe8\x01\x02\xff\xff\xb5p\x00\x00\xff\xff\xb5\x18\x00\x04\xff\xff\xb9\xb0\x00\x08LMT\x00CMT\x00EST\x00\x0aEST5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xdc\xa9=\xda\x06\x00\x00\xda\x06\x00\x00\x0f\x00\x00\x00America/ChicagoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xa2\xcbt\x00\xff\xff\xff\xff\xa3\x83\xf7\xf0\xff\xff\xff\xff\xa4E\xd2\x80\xff\xff\xff\xff\xa5c\xd9\xf0\xff\xff\xff\xff\xa6S\xd9\x00\xff\xff\xff\xff\xa7\x15\x97p\xff\xff\xff\xff\xa83\xbb\x00\xff\xff\xff\xff\xa8\xfe\xb3\xf0\xff\xff\xff\xff\xaa\x13\x9d\x00\xff\xff\xff\xff\xaa\xde\x95\xf0\xff\xff\xff\xff\xab\xf3\x7f\x00\xff\xff\xff\xff\xac\xbew\xf0\xff\xff\xff\xff\xad\xd3a\x00\xff\xff\xff\xff\xae\x9eY\xf0\xff\xff\xff\xff\xaf\xb3C\x00\xff\xff\xff\xff\xb0~;\xf0\xff\xff\xff\xff\xb1\x9c_\x80\xff\xff\xff\xff\xb2gXp\xff\xff\xff\xff\xb3|A\x80\xff\xff\xff\xff\xb4G:p\xff\xff\xff\xff\xb5\x5c#\x80\xff\xff\xff\xff\xb6'\x1cp\xff\xff\xff\xff\xb7<\x05\x80\xff\xff\xff\xff\xb8\x06\xfep\xff\xff\xff\xff\xb9\x1b\xe7\x80\xff\xff\xff\xff\xb9\xe6\xe0p\xff\xff\xff\xff\xbb\x05\x04\x00\xff\xff\xff\xff\xbb\xc6\xc2p\xff\xff\xff\xff\xbc\xe4\xe6\x00\xff\xff\xff\xff\xbd\xaf\xde\xf0\xff\xff\xff\xff\xbe\xc4\xc8\x00\xff\xff\xff\xff\xbf\x8f\xc0\xf0\xff\xff\xff\xff\xc0Z\xd6\x00\xff\xff\xff\xff\xc1\xb0\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x04\x05\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xad\xd4\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x00\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x01\x14LMT\x00CDT\x00CST\x00EST\x00CWT\x00CPT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x111\x04q\xb3\x02\x00\x00\xb3\x02\x00\x00\x11\x00\x00\x00America/ChihuahuaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xf5\x12\x90\x00\x00\x00\x00;\xb6\xd1\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00F\x0ft\x90\x00\x00\x00\x00G$A\x80\x00\x00\x00\x00G\xf8\x91\x10\x00\x00\x00\x00I\x04#\x80\x00\x00\x00\x00I\xd8s\x10\x00\x00\x00\x00J\xe4\x05\x80\x00\x00\x00\x00K\xb8U\x10\x00\x00\x00\x00L\xcd\x22\x00\x00\x00\x00\x00M\x987\x10\x00\x00\x00\x00N\xad\x04\x00\x00\x00\x00\x00Ox\x19\x10\x00\x00\x00\x00P\x8c\xe6\x00\x00\x00\x00\x00Qa5\x90\x00\x00\x00\x00Rl\xc8\x00\x00\x00\x00\x00SA\x17\x90\x00\x00\x00\x00TL\xaa\x00\x00\x00\x00\x00U \xf9\x90\x00\x00\x00\x00V,\x8c\x00\x00\x00\x00\x00W\x00\xdb\x90\x00\x00\x00\x00X\x15\xa8\x80\x00\x00\x00\x00X\xe0\xbd\x90\x00\x00\x00\x00Y\xf5\x8a\x80\x00\x00\x00\x00Z\xc0\x9f\x90\x00\x00\x00\x00[\xd5l\x80\x00\x00\x00\x00\x5c\xa9\xbc\x10\x00\x00\x00\x00]\xb5N\x80\x00\x00\x00\x00^\x89\x9e\x10\x00\x00\x00\x00_\x950\x80\x00\x00\x00\x00`i\x80\x10\x00\x00\x00\x00a~M\x00\x00\x00\x00\x00bIb\x10\x00\x00\x00\x00c^/\x00\x01\x02\x01\x03\x01\x02\x04\x02\x04\x02\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x02\xff\xff\x9c\x8c\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xb9\xb0\x01\x10LMT\x00MST\x00CST\x00MDT\x00CDT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xad\xf2L\x06\xce\x02\x00\x00\xce\x02\x00\x00\x15\x00\x00\x00America/Ciudad_JuarezTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xf5\x12\x90\x00\x00\x00\x00;\xb6\xd1\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00F\x0ft\x90\x00\x00\x00\x00G$A\x80\x00\x00\x00\x00G\xf8\x91\x10\x00\x00\x00\x00I\x04#\x80\x00\x00\x00\x00I\xd8s\x10\x00\x00\x00\x00J\xe4\x05\x80\x00\x00\x00\x00K\x9c\xa5\x90\x00\x00\x00\x00L\xd6\x5c\x80\x00\x00\x00\x00M|\x87\x90\x00\x00\x00\x00N\xb6>\x80\x00\x00\x00\x00O\x5ci\x90\x00\x00\x00\x00P\x96 \x80\x00\x00\x00\x00Q3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb1\xdd\x82x\xe8\x00\x00\x00\xe8\x00\x00\x00\x12\x00\x00\x00America/Costa_RicaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xffi\x87*M\xff\xff\xff\xff\xa3\xe8\x16M\x00\x00\x00\x00\x116I`\x00\x00\x00\x00\x11\xb7nP\x00\x00\x00\x00\x13\x16+`\x00\x00\x00\x00\x13\x97PP\x00\x00\x00\x00'\x97\xe0`\x00\x00\x00\x00(n\xb6\xd0\x00\x00\x00\x00)w\xc2`\x00\x00\x00\x00)\xc2\xd9\xd0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\xff\xff\xb13\x00\x00\xff\xff\xb13\x00\x04\xff\xff\xb9\xb0\x01\x09\xff\xff\xab\xa0\x00\x0dLMT\x00SJMT\x00CDT\x00CST\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\xb8\xab\x9b\xf0\x00\x00\x00\xf0\x00\x00\x00\x0f\x00\x00\x00America/CrestonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xcf\x17\xdf\x1c\xff\xff\xff\xff\xcf\x8f\xe5\xac\xff\xff\xff\xff\xd0\x81\x1a\x1c\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\x02\x01\x02\x01\x02\x03\x02\x03\x02\x01\x02\xff\xff\x96\xee\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0cLMT\x00MDT\x00MST\x00MWT\x00\x0aMST7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f$*\xa0\xa6\x03\x00\x00\xa6\x03\x00\x00\x0e\x00\x00\x00America/CuiabaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa{\x94\xff\xff\xff\xff\xb8\x0fW\xf0\xff\xff\xff\xff\xb8\xfdN\xb0\xff\xff\xff\xff\xb9\xf1B@\xff\xff\xff\xff\xba\xde\x820\xff\xff\xff\xff\xda8\xbc@\xff\xff\xff\xff\xda\xec\x08@\xff\xff\xff\xff\xdc\x19\xef\xc0\xff\xff\xff\xff\xdc\xb9g0\xff\xff\xff\xff\xdd\xfb#@\xff\xff\xff\xff\xde\x9b\xec0\xff\xff\xff\xff\xdf\xdd\xa8@\xff\xff\xff\xff\xe0TA0\xff\xff\xff\xff\xf4\x98\x0d\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf6\xc0r@\xff\xff\xff\xff\xf7\x0e,\xb0\xff\xff\xff\xff\xf8Q:@\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xfa\x0a\xe0\xc0\xff\xff\xff\xff\xfa\xa9\x06\xb0\xff\xff\xff\xff\xfb\xec\x14@\xff\xff\xff\xff\xfc\x8b\x8b\xb0\x00\x00\x00\x00\x1d\xc9\x9c@\x00\x00\x00\x00\x1ex\xe5\xb0\x00\x00\x00\x00\x1f\xa0C\xc0\x00\x00\x00\x00 3\xdd\xb0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22\x0b\xd6\xb0\x00\x00\x00\x00#X\x1e\xc0\x00\x00\x00\x00#\xe2~0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xd4\xd50\x00\x00\x00\x00'!\x1d@\x00\x00\x00\x00'\xbd\xf1\xb0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\x94\x990\x00\x00\x00\x00*\xea\x1b\xc0\x00\x00\x00\x00+k@\xb0\x00\x00\x00\x00,\xc0\xc3@\x00\x00\x00\x00-f\xd20\x00\x00\x00\x00.\xa0\xa5@\x00\x00\x00\x00/F\xb40\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001\x1d[\xb0\x00\x00\x00\x002W.\xc0\x00\x00\x00\x003\x06x0\x00\x00\x00\x0048b@\x00\x00\x00\x004\xf8\xcf0\x00\x00\x00\x006 -@\x00\x00\x00\x006\xcfv\xb0\x00\x00\x00\x007\xf6\xd4\xc0\x00\x00\x00\x008\xb8\x930\x00\x00\x00\x009\xdf\xf1@\x00\x00\x00\x00:\x8f:\xb0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00N\xfe\xb0\x00\x00\x00\x00A\x87\x06@\x00\x00\x00\x00B\x17\xfd0\x00\x00\x00\x00CQ\xd0@\x00\x00\x00\x00C\xf7\xdf0\x00\x00\x00\x00EMa\xc0\x00\x00\x00\x00E\xe0\xfb\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xb7\xa30\x00\x00\x00\x00H\xfa\xb0\xc0\x00\x00\x00\x00I\x97\x850\x00\x00\x00\x00J\xda\x92\xc0\x00\x00\x00\x00K\x80\xa1\xb0\x00\x00\x00\x00L\xbat\xc0\x00\x00\x00\x00M`\x83\xb0\x00\x00\x00\x00N\x9aV\xc0\x00\x00\x00\x00OI\xa00\x00\x00\x00\x00P\x83s@\x00\x00\x00\x00Q G\xb0\x00\x00\x00\x00RcU@\x00\x00\x00\x00S\x00)\xb0\x00\x00\x00\x00TC7@\x00\x00\x00\x00T\xe9F0\x00\x00\x00\x00V#\x19@\x00\x00\x00\x00V\xc9(0\x00\x00\x00\x00X\x02\xfb@\x00\x00\x00\x00X\xa9\x0a0\x00\x00\x00\x00Y\xe2\xdd@\x00\x00\x00\x00Z\x88\xec0\x00\x00\x00\x00[\xden\xc0\x00\x00\x00\x00\x5ch\xce0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xcbl\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08LMT\x00-03\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00America/CuracaoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00k\xc2\x0dx\xbf\x01\x00\x00\xbf\x01\x00\x00\x14\x00\x00\x00America/DanmarkshavnTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\x9b\x80I\x00\x00\x00\x00\x00\x13M|P\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x00\x00\x00\x00G-\x8a\x10\x00\x00\x00\x00G\xd3\xb5 \x00\x00\x00\x00I\x0dl\x10\x00\x00\x00\x00I\xb3\x97 \x00\x00\x00\x00J\xedN\x10\x00\x00\x00\x00K\x9c\xb3\xa0\x00\x00\x00\x00L\xd6j\x90\x00\x00\x00\x00M|\x95\xa0\x00\x00\x00\x00N\xb6L\x90\x00\x00\x00\x00O\x5cw\xa0\x00\x00\x00\x00P\x96.\x90\x00\x00\x00\x00Q\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x9d\x94\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10LMT\x00MDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x14\xe7\x03\x83\x03\x00\x00\x83\x03\x00\x00\x0f\x00\x00\x00America/DetroitTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\x85\xbd\x22[\xff\xff\xff\xff\x99<\x94\x00\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xfb3\x90\x8c\xff\xff\xff\xff\xfb\xe8;\xe0\xff\xff\xff\xff\xfc\xd8:\xf0\xff\xff\xff\xff\xfd\xc8\x1d\xe0\x00\x00\x00\x00\x06@\xdfp\x00\x00\x00\x00\x070\xc2`\x00\x00\x00\x00\x07\x8d\x19p\x00\x00\x00\x00\x09\x10\xa4`\x00\x00\x00\x00\x0a\x00\xa3p\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00\x0b\xe0\x85p\x00\x00\x00\x00\x0c\xd9\xa2\xe0\x00\x00\x00\x00\x0d\xc0gp\x00\x00\x00\x00\x0e\xb9\x84\xe0\x00\x00\x00\x00\x0f\xa9\x83\xf0\x00\x00\x00\x00\x10\x99f\xe0\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x00\x00\x00\x00\x1a\xf2\x0ap\x00\x00\x00\x00\x1b\xe1\xed`\x00\x00\x00\x00\x1c\xd1\xecp\x00\x00\x00\x00\x1d\xc1\xcf`\x00\x00\x00\x00\x1e\xb1\xcep\x00\x00\x00\x00\x1f\xa1\xb1`\x00\x00\x00\x00 v\x00\xf0\x00\x00\x00\x00!\x81\x93`\x00\x00\x00\x00\x22U\xe2\xf0\x00\x00\x00\x00#j\xaf\xe0\x00\x00\x00\x00$5\xc4\xf0\x00\x00\x00\x00%J\x91\xe0\x00\x00\x00\x00&\x15\xa6\xf0\x00\x00\x00\x00'*s\xe0\x00\x00\x00\x00'\xfe\xc3p\x00\x00\x00\x00)\x0aU\xe0\x00\x00\x00\x00)\xde\xa5p\x00\x00\x00\x00*\xea7\xe0\x00\x00\x00\x00+\xbe\x87p\x00\x00\x00\x00,\xd3T`\x00\x00\x00\x00-\x9eip\x00\x00\x00\x00.\xb36`\x00\x00\x00\x00/~Kp\x00\x00\x00\x000\x93\x18`\x00\x00\x00\x001gg\xf0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003GI\xf0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x005'+\xf0\x00\x00\x00\x0062\xbe`\x00\x00\x00\x007\x07\x0d\xf0\x00\x00\x00\x008\x1b\xda\xe0\x00\x00\x00\x008\xe6\xef\xf0\x00\x00\x00\x009\xfb\xbc\xe0\x00\x00\x00\x00:\xc6\xd1\xf0\x00\x00\x00\x00;\xdb\x9e\xe0\x00\x00\x00\x00<\xaf\xeep\x00\x00\x00\x00=\xbb\x80\xe0\x00\x00\x00\x00>\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x01\x02\x03\x04\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\xff\xff\xb2%\x00\x00\xff\xff\xab\xa0\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10\xff\xff\xc7\xc0\x01\x14LMT\x00CST\x00EST\x00EWT\x00EPT\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00America/DominicaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\x07\x07\xdc\xca\x03\x00\x00\xca\x03\x00\x00\x10\x00\x00\x00America/EdmontonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x88\xde\xce\xe0\xff\xff\xff\xff\x9e\xb8\xaf\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x98\x91\x90\xff\xff\xff\xff\xa0\xd2\x85\x80\xff\xff\xff\xff\xa2\x8a\xe8\x90\xff\xff\xff\xff\xa3\x84\x06\x00\xff\xff\xff\xff\xa4j\xca\x90\xff\xff\xff\xff\xa55\xc3\x80\xff\xff\xff\xff\xa6S\xe7\x10\xff\xff\xff\xff\xa7\x15\xa5\x80\xff\xff\xff\xff\xa83\xc9\x10\xff\xff\xff\xff\xa8\xfe\xc2\x00\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xd5U\xe3\x10\xff\xff\xff\xff\xd6 \xdc\x00\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x08 \xdd\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x0a\x00\xbf\x90\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x95\xa0\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10LMT\x00MDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\xb0\xeau\xb4\x01\x00\x00\xb4\x01\x00\x00\x10\x00\x00\x00America/EirunepeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa\x88\x80\xff\xff\xff\xff\xb8\x0ff\x00\xff\xff\xff\xff\xb8\xfd\x5c\xc0\xff\xff\xff\xff\xb9\xf1PP\xff\xff\xff\xff\xba\xde\x90@\xff\xff\xff\xff\xda8\xcaP\xff\xff\xff\xff\xda\xec\x16P\xff\xff\xff\xff\xdc\x19\xfd\xd0\xff\xff\xff\xff\xdc\xb9u@\xff\xff\xff\xff\xdd\xfb1P\xff\xff\xff\xff\xde\x9b\xfa@\xff\xff\xff\xff\xdf\xdd\xb6P\xff\xff\xff\xff\xe0TO@\xff\xff\xff\xff\xf4\x98\x1b\xd0\xff\xff\xff\xff\xf5\x05z@\xff\xff\xff\xff\xf6\xc0\x80P\xff\xff\xff\xff\xf7\x0e:\xc0\xff\xff\xff\xff\xf8QHP\xff\xff\xff\xff\xf8\xc7\xe1@\xff\xff\xff\xff\xfa\x0a\xee\xd0\xff\xff\xff\xff\xfa\xa9\x14\xc0\xff\xff\xff\xff\xfb\xec\x22P\xff\xff\xff\xff\xfc\x8b\x99\xc0\x00\x00\x00\x00\x1d\xc9\xaaP\x00\x00\x00\x00\x1ex\xf3\xc0\x00\x00\x00\x00\x1f\xa0Q\xd0\x00\x00\x00\x00 3\xeb\xc0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22\x0b\xe4\xc0\x00\x00\x00\x00,\xc0\xd1P\x00\x00\x00\x00-f\xe0@\x00\x00\x00\x00H`\x7fP\x00\x00\x00\x00R\x7f\x04\xc0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\xff\xff\xbe\x80\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x00\x04LMT\x00-04\x00-05\x00\x0a<-05>5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xea$\xc1\xbf\xb0\x00\x00\x00\xb0\x00\x00\x00\x13\x00\x00\x00America/El_SalvadorTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xa3\xd5\xa6 \x00\x00\x00\x00 \x9a\xdc\xe0\x00\x00\x00\x00!\x5c\x9bP\x00\x00\x00\x00\x22z\xbe\xe0\x00\x00\x00\x00#<}P\x02\x01\x02\x01\x02\xff\xff\xac`\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08LMT\x00CDT\x00CST\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x10\x00\x00\x00America/EnsenadaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xa9yOp\xff\xff\xff\xff\xaf\xf2|\xf0\xff\xff\xff\xff\xb6fdp\xff\xff\xff\xff\xb7\x1b\x10\x00\xff\xff\xff\xff\xb8\x0a\xf2\xf0\xff\xff\xff\xff\xcb\xea\x8d\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2\x99\xbap\xff\xff\xff\xff\xd7\x1bY\x00\xff\xff\xff\xff\xd8\x91\xb4\xf0\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x0e\x10\xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xd2\x10\xff\xff\xff\xff\xee\x91\xd9\x10\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00F\x0f\x82\xa0\x00\x00\x00\x00G$O\x90\x00\x00\x00\x00G\xf8\x9f \x00\x00\x00\x00I\x041\x90\x00\x00\x00\x00I\xd8\x81 \x00\x00\x00\x00J\xe4\x13\x90\x00\x00\x00\x00K=\xab\x80\x01\x02\x01\x02\x03\x02\x04\x05\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x02\xff\xff\x92L\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10\xff\xff\x9d\x90\x01\x14LMT\x00MST\x00PST\x00PDT\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6@\x0dm\xa8\x05\x00\x00\xa8\x05\x00\x00\x13\x00\x00\x00America/Fort_NelsonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8f\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^=v\x87\xff\xff\xff\xff\x9e\xb8\xbd\xa0\xff\xff\xff\xff\x9f\xbb\x15\x90\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xd5U\xf1 \xff\xff\xff\xff\xd6 \xea\x10\xff\xff\xff\xff\xd75\xd3 \xff\xff\xff\xff\xd8\x00\xcc\x10\xff\xff\xff\xff\xd9\x15\xb5 \xff\xff\xff\xff\xd9\xe0\xae\x10\xff\xff\xff\xff\xda\xfe\xd1\xa0\xff\xff\xff\xff\xdb\xc0\x90\x10\xff\xff\xff\xff\xdc\xde\xb3\xa0\xff\xff\xff\xff\xdd\xa9\xac\x90\xff\xff\xff\xff\xde\xbe\x95\xa0\xff\xff\xff\xff\xdf\x89\x8e\x90\xff\xff\xff\xff\xe0\x9ew\xa0\xff\xff\xff\xff\xe1ip\x90\xff\xff\xff\xff\xe2~Y\xa0\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^;\xa0\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GX \xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8': \xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x1c \xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xfe \xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xe0 \xff\xff\xff\xff\xee\x91\xd9\x10\xff\xff\xff\xff\xef\xaf\xfc\xa0\xff\xff\xff\xff\xf0q\xbb\x10\xff\xff\xff\xff\xf1\x8f\xde\xa0\xff\xff\xff\xff\xf2\x7f\xc1\x90\xff\xff\xff\xff\xf3o\xc0\xa0\xff\xff\xff\xff\xf4_\xa3\x90\xff\xff\xff\xff\xf5O\xa2\xa0\xff\xff\xff\xff\xf6?\x85\x90\xff\xff\xff\xff\xf7/\x84\xa0\xff\xff\xff\xff\xf8(\xa2\x10\xff\xff\xff\xff\xf9\x0ff\xa0\xff\xff\xff\xff\xfa\x08\x84\x10\xff\xff\xff\xff\xfa\xf8\x83 \xff\xff\xff\xff\xfb\xe8f\x10\xff\xff\xff\xff\xfc\xd8e \xff\xff\xff\xff\xfd\xc8H\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x08 \xeb\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x0a\x00\xcd\xa0\x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x00\x00\x00\x00G-\x8a\x10\x00\x00\x00\x00G\xd3\xb5 \x00\x00\x00\x00I\x0dl\x10\x00\x00\x00\x00I\xb3\x97 \x00\x00\x00\x00J\xedN\x10\x00\x00\x00\x00K\x9c\xb3\xa0\x00\x00\x00\x00L\xd6j\x90\x00\x00\x00\x00M|\x95\xa0\x00\x00\x00\x00N\xb6L\x90\x00\x00\x00\x00O\x5cw\xa0\x00\x00\x00\x00P\x96.\x90\x00\x00\x00\x00Q3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M\x94\xc7Kp\x03\x00\x00p\x03\x00\x00\x11\x00\x00\x00America/Glace_BayTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x80\xf1\xa84\xff\xff\xff\xff\x9e\xb8\x85`\xff\xff\xff\xff\x9f\xba\xddP\xff\xff\xff\xff\xcb\x88\xe2`\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\xff\xff\xff\xff\xe0\x9e?`\xff\xff\xff\xff\xe1i8P\x00\x00\x00\x00\x04`\xef`\x00\x00\x00\x00\x05P\xd2P\x00\x00\x00\x00\x06@\xd1`\x00\x00\x00\x00\x070\xb4P\x00\x00\x00\x00\x08 \xb3`\x00\x00\x00\x00\x09\x10\x96P\x00\x00\x00\x00\x0a\x00\x95`\x00\x00\x00\x00\x0a\xf0xP\x00\x00\x00\x00\x0b\xe0w`\x00\x00\x00\x00\x0c\xd9\x94\xd0\x00\x00\x00\x00\x0d\xc0Y`\x00\x00\x00\x00\x0e\xb9v\xd0\x00\x00\x00\x00\x0f\xa9u\xe0\x00\x00\x00\x00\x10\x99X\xd0\x00\x00\x00\x00\x11\x89W\xe0\x00\x00\x00\x00\x12y:\xd0\x00\x00\x00\x00\x13i9\xe0\x00\x00\x00\x00\x14Y\x1c\xd0\x00\x00\x00\x00\x15I\x1b\xe0\x00\x00\x00\x00\x168\xfe\xd0\x00\x00\x00\x00\x17(\xfd\xe0\x00\x00\x00\x00\x18\x22\x1bP\x00\x00\x00\x00\x19\x08\xdf\xe0\x00\x00\x00\x00\x1a\x01\xfdP\x00\x00\x00\x00\x1a\xf1\xfc`\x00\x00\x00\x00\x1b\xe1\xdfP\x00\x00\x00\x00\x1c\xd1\xde`\x00\x00\x00\x00\x1d\xc1\xc1P\x00\x00\x00\x00\x1e\xb1\xc0`\x00\x00\x00\x00\x1f\xa1\xa3P\x00\x00\x00\x00 u\xf2\xe0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22U\xd4\xe0\x00\x00\x00\x00#j\xa1\xd0\x00\x00\x00\x00$5\xb6\xe0\x00\x00\x00\x00%J\x83\xd0\x00\x00\x00\x00&\x15\x98\xe0\x00\x00\x00\x00'*e\xd0\x00\x00\x00\x00'\xfe\xb5`\x00\x00\x00\x00)\x0aG\xd0\x00\x00\x00\x00)\xde\x97`\x00\x00\x00\x00*\xea)\xd0\x00\x00\x00\x00+\xbey`\x00\x00\x00\x00,\xd3FP\x00\x00\x00\x00-\x9e[`\x00\x00\x00\x00.\xb3(P\x00\x00\x00\x00/~=`\x00\x00\x00\x000\x93\x0aP\x00\x00\x00\x001gY\xe0\x00\x00\x00\x002r\xecP\x00\x00\x00\x003G;\xe0\x00\x00\x00\x004R\xceP\x00\x00\x00\x005'\x1d\xe0\x00\x00\x00\x0062\xb0P\x00\x00\x00\x007\x06\xff\xe0\x00\x00\x00\x008\x1b\xcc\xd0\x00\x00\x00\x008\xe6\xe1\xe0\x00\x00\x00\x009\xfb\xae\xd0\x00\x00\x00\x00:\xc6\xc3\xe0\x00\x00\x00\x00;\xdb\x90\xd0\x00\x00\x00\x00<\xaf\xe0`\x00\x00\x00\x00=\xbbr\xd0\x00\x00\x00\x00>\x8f\xc2`\x00\x00\x00\x00?\x9bT\xd0\x00\x00\x00\x00@o\xa4`\x00\x00\x00\x00A\x84qP\x00\x00\x00\x00BO\x86`\x00\x00\x00\x00CdSP\x00\x00\x00\x00D/h`\x00\x00\x00\x00ED5P\x00\x00\x00\x00E\xf3\x9a\xe0\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xc7\xcc\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xd5\xd0\x01\x10LMT\x00ADT\x00AST\x00AWT\x00APT\x00\x0aAST4ADT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xf9v\x14\xc5\x03\x00\x00\xc5\x03\x00\x00\x0f\x00\x00\x00America/GodthabTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\x9b\x80h\x00\x00\x00\x00\x00\x13M|P\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x86A\x90\x00\x00\x00\x00?\x9b\x1c\x90\x00\x00\x00\x00@f#\x90\x00\x00\x00\x00A\x849\x10\x00\x00\x00\x00BF\x05\x90\x00\x00\x00\x00Cd\x1b\x10\x00\x00\x00\x00D%\xe7\x90\x00\x00\x00\x00EC\xfd\x10\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8e\x8c\x10\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S7l\x90\x00\x00\x00\x00TLG\x90\x00\x00\x00\x00U\x17N\x90\x00\x00\x00\x00V,)\x90\x00\x00\x00\x00V\xf70\x90\x00\x00\x00\x00X\x15F\x10\x00\x00\x00\x00X\xd7\x12\x90\x00\x00\x00\x00Y\xf5(\x10\x00\x00\x00\x00Z\xb6\xf4\x90\x00\x00\x00\x00[\xd5\x0a\x10\x00\x00\x00\x00\x5c\xa0\x11\x10\x00\x00\x00\x00]\xb4\xec\x10\x00\x00\x00\x00^\x7f\xf3\x10\x00\x00\x00\x00_\x94\xce\x10\x00\x00\x00\x00`_\xd5\x10\x00\x00\x00\x00a}\xea\x90\x00\x00\x00\x00b?\xb7\x10\x00\x00\x00\x00c]\xcc\x90\x00\x00\x00\x00d\x1f\x99\x10\x00\x00\x00\x00e=\xae\x90\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x03\xff\xff\xcf\x80\x00\x00\xff\xff\xd5\xd0\x00\x04\xff\xff\xe3\xe0\x01\x08\xff\xff\xe3\xe0\x00\x08LMT\x00-03\x00-02\x00\x0a<-02>2<-01>,M3.5.0/-1,M10.5.0/0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdb\x85\xf6\xd1,\x06\x00\x00,\x06\x00\x00\x11\x00\x00\x00America/Goose_BayTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x98\x00\x00\x00\x0a\x00\x00\x00!\xff\xff\xff\xff^=<$\xff\xff\xff\xff\x9e\xb8~\x8c\xff\xff\xff\xff\x9f\xba\xd6|\xff\xff\xff\xff\xbe\x9eMl\xff\xff\xff\xff\xc0\xb818\xff\xff\xff\xff\xc1y\xef\xa8\xff\xff\xff\xff\xc2\x98\x138\xff\xff\xff\xff\xc3Y\xd1\xa8\xff\xff\xff\xff\xc4w\xf58\xff\xff\xff\xff\xc59\xb3\xa8\xff\xff\xff\xff\xc6a\x11\xb8\xff\xff\xff\xff\xc7\x19\x95\xa8\xff\xff\xff\xff\xc8@\xf3\xb8\xff\xff\xff\xff\xc9\x02\xb2(\xff\xff\xff\xff\xca \xd5\xb8\xff\xff\xff\xff\xca\xe2\x94(\xff\xff\xff\xff\xcc\x00\xb7\xb8\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xe6\xc8\xff\xff\xff\xff\xd3\x88D\xd8\xff\xff\xff\xff\xd4J\x03H\xff\xff\xff\xff\xd5h&\xd8\xff\xff\xff\xff\xd6)\xe5H\xff\xff\xff\xff\xd7H\x08\xd8\xff\xff\xff\xff\xd8\x09\xc7H\xff\xff\xff\xff\xd9'\xea\xd8\xff\xff\xff\xff\xd9\xe9\xa9H\xff\xff\xff\xff\xdb\x11\x07X\xff\xff\xff\xff\xdb\xd2\xc5\xc8\xff\xff\xff\xff\xdc\xdetX\xff\xff\xff\xff\xdd\xa9mH\xff\xff\xff\xff\xde\xbeVX\xff\xff\xff\xff\xdf\x89OH\xff\xff\xff\xff\xe0\x9e8X\xff\xff\xff\xff\xe1i1H\xff\xff\xff\xff\xe2~\x1aX\xff\xff\xff\xff\xe3I\x13H\xff\xff\xff\xff\xe4]\xfcX\xff\xff\xff\xff\xe5(\xf5H\xff\xff\xff\xff\xe6G\x18\xd8\xff\xff\xff\xff\xe7\x12\x11\xc8\xff\xff\xff\xff\xe8&\xfa\xd8\xff\xff\xff\xff\xe8\xf1\xf3\xc8\xff\xff\xff\xff\xea\x06\xdc\xd8\xff\xff\xff\xff\xea\xd1\xd5\xc8\xff\xff\xff\xff\xeb\xe6\xbe\xd8\xff\xff\xff\xff\xec\xb1\xb7\xc8\xff\xff\xff\xff\xed\xc6\xa0\xd8\xff\xff\xff\xff\xee\xbf\xbeH\xff\xff\xff\xff\xef\xaf\xbdX\xff\xff\xff\xff\xf0\x9f\xa0H\xff\xff\xff\xff\xf1\x8f\x9fX\xff\xff\xff\xff\xf2\x7f\x82H\xff\xff\xff\xff\xf3o\x81X\xff\xff\xff\xff\xf4_dH\xff\xff\xff\xff\xf5OcX\xff\xff\xff\xff\xf6?FH\xff\xff\xff\xff\xf7/EX\xff\xff\xff\xff\xf8(b\xc8\xff\xff\xff\xff\xf8\xdakX\xff\xff\xff\xff\xf9\x0f.`\xff\xff\xff\xff\xfa\x08K\xd0\xff\xff\xff\xff\xfa\xf8J\xe0\xff\xff\xff\xff\xfb\xe8-\xd0\xff\xff\xff\xff\xfc\xd8,\xe0\xff\xff\xff\xff\xfd\xc8\x0f\xd0\xff\xff\xff\xff\xfe\xb8\x0e\xe0\xff\xff\xff\xff\xff\xa7\xf1\xd0\x00\x00\x00\x00\x00\x97\xf0\xe0\x00\x00\x00\x00\x01\x87\xd3\xd0\x00\x00\x00\x00\x02w\xd2\xe0\x00\x00\x00\x00\x03p\xf0P\x00\x00\x00\x00\x04`\xef`\x00\x00\x00\x00\x05P\xd2P\x00\x00\x00\x00\x06@\xd1`\x00\x00\x00\x00\x070\xb4P\x00\x00\x00\x00\x08 \xb3`\x00\x00\x00\x00\x09\x10\x96P\x00\x00\x00\x00\x0a\x00\x95`\x00\x00\x00\x00\x0a\xf0xP\x00\x00\x00\x00\x0b\xe0w`\x00\x00\x00\x00\x0c\xd9\x94\xd0\x00\x00\x00\x00\x0d\xc0Y`\x00\x00\x00\x00\x0e\xb9v\xd0\x00\x00\x00\x00\x0f\xa9u\xe0\x00\x00\x00\x00\x10\x99X\xd0\x00\x00\x00\x00\x11\x89W\xe0\x00\x00\x00\x00\x12y:\xd0\x00\x00\x00\x00\x13i9\xe0\x00\x00\x00\x00\x14Y\x1c\xd0\x00\x00\x00\x00\x15I\x1b\xe0\x00\x00\x00\x00\x168\xfe\xd0\x00\x00\x00\x00\x17(\xfd\xe0\x00\x00\x00\x00\x18\x22\x1bP\x00\x00\x00\x00\x19\x08\xdf\xe0\x00\x00\x00\x00\x1a\x01\xfdP\x00\x00\x00\x00\x1a\xf1\xfc`\x00\x00\x00\x00\x1b\xe1\xdfP\x00\x00\x00\x00\x1c\xd1\xde`\x00\x00\x00\x00\x1d\xc1\xc1P\x00\x00\x00\x00\x1e\xb1\xc0`\x00\x00\x00\x00\x1f\xa1\xa3P\x00\x00\x00\x00 u\xd6\xfc\x00\x00\x00\x00!\x81il\x00\x00\x00\x00\x22U\xb8\xfc\x00\x00\x00\x00#jw\xdc\x00\x00\x00\x00$5\x9a\xfc\x00\x00\x00\x00%Jg\xec\x00\x00\x00\x00&\x15|\xfc\x00\x00\x00\x00'*I\xec\x00\x00\x00\x00'\xfe\x99|\x00\x00\x00\x00)\x0a+\xec\x00\x00\x00\x00)\xde{|\x00\x00\x00\x00*\xea\x0d\xec\x00\x00\x00\x00+\xbe]|\x00\x00\x00\x00,\xd3*l\x00\x00\x00\x00-\x9e?|\x00\x00\x00\x00.\xb3\x0cl\x00\x00\x00\x00/~!|\x00\x00\x00\x000\x92\xeel\x00\x00\x00\x001g=\xfc\x00\x00\x00\x002r\xd0l\x00\x00\x00\x003G\x1f\xfc\x00\x00\x00\x004R\xb2l\x00\x00\x00\x005'\x01\xfc\x00\x00\x00\x0062\x94l\x00\x00\x00\x007\x06\xe3\xfc\x00\x00\x00\x008\x1b\xb0\xec\x00\x00\x00\x008\xe6\xc5\xfc\x00\x00\x00\x009\xfb\x92\xec\x00\x00\x00\x00:\xc6\xa7\xfc\x00\x00\x00\x00;\xdbt\xec\x00\x00\x00\x00<\xaf\xc4|\x00\x00\x00\x00=\xbbV\xec\x00\x00\x00\x00>\x8f\xa6|\x00\x00\x00\x00?\x9b8\xec\x00\x00\x00\x00@o\x88|\x00\x00\x00\x00A\x84Ul\x00\x00\x00\x00BOj|\x00\x00\x00\x00Cd7l\x00\x00\x00\x00D/L|\x00\x00\x00\x00ED\x19l\x00\x00\x00\x00E\xf3~\xfc\x00\x00\x00\x00G-5\xec\x00\x00\x00\x00G\xd3`\xfc\x00\x00\x00\x00I\x0d\x17\xec\x00\x00\x00\x00I\xb3B\xfc\x00\x00\x00\x00J\xec\xf9\xec\x00\x00\x00\x00K\x9c_|\x00\x00\x00\x00L\xd6\x16l\x00\x00\x00\x00M|A|\x00\x00\x00\x00N\xaf`\xb0\x01\x02\x01\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x06\x05\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x09\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x07\xff\xff\xc7\x5c\x00\x00\xff\xff\xce\x94\x00\x04\xff\xff\xdc\xa4\x01\x08\xff\xff\xce\xc8\x00\x04\xff\xff\xdc\xd8\x01\x08\xff\xff\xdc\xd8\x01\x0c\xff\xff\xdc\xd8\x01\x10\xff\xff\xd5\xd0\x01\x14\xff\xff\xc7\xc0\x00\x18\xff\xff\xe3\xe0\x01\x1cLMT\x00NST\x00NDT\x00NPT\x00NWT\x00ADT\x00AST\x00ADDT\x00\x0aAST4ADT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe3\xc9I\xd0U\x03\x00\x00U\x03\x00\x00\x12\x00\x00\x00America/Grand_TurkTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffi\x87\x1e0\xff\xff\xff\xff\x93\x0f\xb4\xfe\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x00\x00\x00\x00\x1a\xf2\x0ap\x00\x00\x00\x00\x1b\xe1\xed`\x00\x00\x00\x00\x1c\xd1\xecp\x00\x00\x00\x00\x1d\xc1\xcf`\x00\x00\x00\x00\x1e\xb1\xcep\x00\x00\x00\x00\x1f\xa1\xb1`\x00\x00\x00\x00 v\x00\xf0\x00\x00\x00\x00!\x81\x93`\x00\x00\x00\x00\x22U\xe2\xf0\x00\x00\x00\x00#j\xaf\xe0\x00\x00\x00\x00$5\xc4\xf0\x00\x00\x00\x00%J\x91\xe0\x00\x00\x00\x00&\x15\xa6\xf0\x00\x00\x00\x00'*s\xe0\x00\x00\x00\x00'\xfe\xc3p\x00\x00\x00\x00)\x0aU\xe0\x00\x00\x00\x00)\xde\xa5p\x00\x00\x00\x00*\xea7\xe0\x00\x00\x00\x00+\xbe\x87p\x00\x00\x00\x00,\xd3T`\x00\x00\x00\x00-\x9eip\x00\x00\x00\x00.\xb36`\x00\x00\x00\x00/~Kp\x00\x00\x00\x000\x93\x18`\x00\x00\x00\x001gg\xf0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003GI\xf0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x005'+\xf0\x00\x00\x00\x0062\xbe`\x00\x00\x00\x007\x07\x0d\xf0\x00\x00\x00\x008\x1b\xda\xe0\x00\x00\x00\x008\xe6\xef\xf0\x00\x00\x00\x009\xfb\xbc\xe0\x00\x00\x00\x00:\xc6\xd1\xf0\x00\x00\x00\x00;\xdb\x9e\xe0\x00\x00\x00\x00<\xaf\xeep\x00\x00\x00\x00=\xbb\x80\xe0\x00\x00\x00\x00>\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x00\x00\x00\x00G-_\xe0\x00\x00\x00\x00G\xd3\x8a\xf0\x00\x00\x00\x00I\x0dA\xe0\x00\x00\x00\x00I\xb3l\xf0\x00\x00\x00\x00J\xed#\xe0\x00\x00\x00\x00K\x9c\x89p\x00\x00\x00\x00L\xd6@`\x00\x00\x00\x00M|kp\x00\x00\x00\x00N\xb6\x22`\x00\x00\x00\x00O\x5cMp\x00\x00\x00\x00P\x96\x04`\x00\x00\x00\x00Q5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x05\xf3\x89\xb5\x00\x00\x00\xb5\x00\x00\x00\x0e\x00\x00\x00America/GuyanaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\x92\x1d\x0f\x87\xff\xff\xff\xff\x98\xd9{@\x00\x00\x00\x00\x0a\x7f\x05\xbc\x00\x00\x00\x00)\xd5@\xc0\x01\x02\x03\x01\xff\xff\xc9y\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xcbD\x00\x08\xff\xff\xd5\xd0\x00\x0eLMT\x00-04\x00-0345\x00-03\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00):\x17-\x88\x06\x00\x00\x88\x06\x00\x00\x0f\x00\x00\x00America/HalifaxTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x80\xf1\xab\xa0\xff\xff\xff\xff\x9a\xe4\xde\xc0\xff\xff\xff\xff\x9b\xd6\x130\xff\xff\xff\xff\x9e\xb8\x85`\xff\xff\xff\xff\x9f\xba\xddP\xff\xff\xff\xff\xa2\x9d\x17@\xff\xff\xff\xff\xa30\xb10\xff\xff\xff\xff\xa4zV@\xff\xff\xff\xff\xa5\x1b\x1f0\xff\xff\xff\xff\xa6S\xa0\xc0\xff\xff\xff\xff\xa6\xfcR\xb0\xff\xff\xff\xff\xa8<\xbd@\xff\xff\xff\xff\xa8\xdc4\xb0\xff\xff\xff\xff\xaa\x1c\x9f@\xff\xff\xff\xff\xaa\xcd:0\xff\xff\xff\xff\xab\xfc\x81@\xff\xff\xff\xff\xac\xbf\x910\xff\xff\xff\xff\xad\xee\xd8@\xff\xff\xff\xff\xae\x8c\xfe0\xff\xff\xff\xff\xaf\xbcE@\xff\xff\xff\xff\xb0\x7fU0\xff\xff\xff\xff\xb1\xae\x9c@\xff\xff\xff\xff\xb2Kp\xb0\xff\xff\xff\xff\xb3\x8e~@\xff\xff\xff\xff\xb4$\xbb0\xff\xff\xff\xff\xb5n`@\xff\xff\xff\xff\xb6\x15\xc0\xb0\xff\xff\xff\xff\xb7NB@\xff\xff\xff\xff\xb8\x08\x17\xb0\xff\xff\xff\xff\xb9$\xe9\xc0\xff\xff\xff\xff\xb9\xe7\xf9\xb0\xff\xff\xff\xff\xbb\x04\xcb\xc0\xff\xff\xff\xff\xbb\xd1\x160\xff\xff\xff\xff\xbd\x00]@\xff\xff\xff\xff\xbd\x9d1\xb0\xff\xff\xff\xff\xbe\xf2\xb4@\xff\xff\xff\xff\xbf\x90\xda0\xff\xff\xff\xff\xc0\xd3\xe7\xc0\xff\xff\xff\xff\xc1^G0\xff\xff\xff\xff\xc2\x8d\x8e@\xff\xff\xff\xff\xc3P\x9e0\xff\xff\xff\xff\xc4mp@\xff\xff\xff\xff\xc50\x800\xff\xff\xff\xff\xc6r<@\xff\xff\xff\xff\xc7\x10b0\xff\xff\xff\xff\xc86n\xc0\xff\xff\xff\xff\xc8\xf9~\xb0\xff\xff\xff\xff\xca\x16P\xc0\xff\xff\xff\xff\xca\xd9`\xb0\xff\xff\xff\xff\xcb\x88\xe2`\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\xff\xff\xff\xff\xd3u\xd6\xe0\xff\xff\xff\xff\xd4@\xcf\xd0\xff\xff\xff\xff\xd5U\xb8\xe0\xff\xff\xff\xff\xd6 \xb1\xd0\xff\xff\xff\xff\xd75\x9a\xe0\xff\xff\xff\xff\xd8\x00\x93\xd0\xff\xff\xff\xff\xd9\x15|\xe0\xff\xff\xff\xff\xd9\xe0u\xd0\xff\xff\xff\xff\xdc\xde{`\xff\xff\xff\xff\xdd\xa9tP\xff\xff\xff\xff\xde\xbe]`\xff\xff\xff\xff\xdf\x89VP\xff\xff\xff\xff\xe0\x9e?`\xff\xff\xff\xff\xe1i8P\xff\xff\xff\xff\xe2~!`\xff\xff\xff\xff\xe3I\x1aP\xff\xff\xff\xff\xe6G\x1f\xe0\xff\xff\xff\xff\xe7\x12\x18\xd0\xff\xff\xff\xff\xe8'\x01\xe0\xff\xff\xff\xff\xe8\xf1\xfa\xd0\xff\xff\xff\xff\xea\x06\xe3\xe0\xff\xff\xff\xff\xea\xd1\xdc\xd0\xff\xff\xff\xff\xeb\xe6\xc5\xe0\xff\xff\xff\xff\xec\xb1\xbe\xd0\xff\xff\xff\xff\xf1\x8f\xa6`\xff\xff\xff\xff\xf2\x7f\x89P\xff\xff\xff\xff\xf3o\x88`\xff\xff\xff\xff\xf4_kP\xff\xff\xff\xff\xf5Oj`\xff\xff\xff\xff\xf6?MP\xff\xff\xff\xff\xf7/L`\xff\xff\xff\xff\xf8(i\xd0\xff\xff\xff\xff\xf9\x0f.`\xff\xff\xff\xff\xfa\x08K\xd0\xff\xff\xff\xff\xfa\xf8J\xe0\xff\xff\xff\xff\xfb\xe8-\xd0\xff\xff\xff\xff\xfc\xd8,\xe0\xff\xff\xff\xff\xfd\xc8\x0f\xd0\xff\xff\xff\xff\xfe\xb8\x0e\xe0\xff\xff\xff\xff\xff\xa7\xf1\xd0\x00\x00\x00\x00\x00\x97\xf0\xe0\x00\x00\x00\x00\x01\x87\xd3\xd0\x00\x00\x00\x00\x02w\xd2\xe0\x00\x00\x00\x00\x03p\xf0P\x00\x00\x00\x00\x04`\xef`\x00\x00\x00\x00\x05P\xd2P\x00\x00\x00\x00\x06@\xd1`\x00\x00\x00\x00\x070\xb4P\x00\x00\x00\x00\x08 \xb3`\x00\x00\x00\x00\x09\x10\x96P\x00\x00\x00\x00\x0a\x00\x95`\x00\x00\x00\x00\x0a\xf0xP\x00\x00\x00\x00\x0b\xe0w`\x00\x00\x00\x00\x0c\xd9\x94\xd0\x00\x00\x00\x00\x0d\xc0Y`\x00\x00\x00\x00\x0e\xb9v\xd0\x00\x00\x00\x00\x0f\xa9u\xe0\x00\x00\x00\x00\x10\x99X\xd0\x00\x00\x00\x00\x11\x89W\xe0\x00\x00\x00\x00\x12y:\xd0\x00\x00\x00\x00\x13i9\xe0\x00\x00\x00\x00\x14Y\x1c\xd0\x00\x00\x00\x00\x15I\x1b\xe0\x00\x00\x00\x00\x168\xfe\xd0\x00\x00\x00\x00\x17(\xfd\xe0\x00\x00\x00\x00\x18\x22\x1bP\x00\x00\x00\x00\x19\x08\xdf\xe0\x00\x00\x00\x00\x1a\x01\xfdP\x00\x00\x00\x00\x1a\xf1\xfc`\x00\x00\x00\x00\x1b\xe1\xdfP\x00\x00\x00\x00\x1c\xd1\xde`\x00\x00\x00\x00\x1d\xc1\xc1P\x00\x00\x00\x00\x1e\xb1\xc0`\x00\x00\x00\x00\x1f\xa1\xa3P\x00\x00\x00\x00 u\xf2\xe0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22U\xd4\xe0\x00\x00\x00\x00#j\xa1\xd0\x00\x00\x00\x00$5\xb6\xe0\x00\x00\x00\x00%J\x83\xd0\x00\x00\x00\x00&\x15\x98\xe0\x00\x00\x00\x00'*e\xd0\x00\x00\x00\x00'\xfe\xb5`\x00\x00\x00\x00)\x0aG\xd0\x00\x00\x00\x00)\xde\x97`\x00\x00\x00\x00*\xea)\xd0\x00\x00\x00\x00+\xbey`\x00\x00\x00\x00,\xd3FP\x00\x00\x00\x00-\x9e[`\x00\x00\x00\x00.\xb3(P\x00\x00\x00\x00/~=`\x00\x00\x00\x000\x93\x0aP\x00\x00\x00\x001gY\xe0\x00\x00\x00\x002r\xecP\x00\x00\x00\x003G;\xe0\x00\x00\x00\x004R\xceP\x00\x00\x00\x005'\x1d\xe0\x00\x00\x00\x0062\xb0P\x00\x00\x00\x007\x06\xff\xe0\x00\x00\x00\x008\x1b\xcc\xd0\x00\x00\x00\x008\xe6\xe1\xe0\x00\x00\x00\x009\xfb\xae\xd0\x00\x00\x00\x00:\xc6\xc3\xe0\x00\x00\x00\x00;\xdb\x90\xd0\x00\x00\x00\x00<\xaf\xe0`\x00\x00\x00\x00=\xbbr\xd0\x00\x00\x00\x00>\x8f\xc2`\x00\x00\x00\x00?\x9bT\xd0\x00\x00\x00\x00@o\xa4`\x00\x00\x00\x00A\x84qP\x00\x00\x00\x00BO\x86`\x00\x00\x00\x00CdSP\x00\x00\x00\x00D/h`\x00\x00\x00\x00ED5P\x00\x00\x00\x00E\xf3\x9a\xe0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xc4`\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xd5\xd0\x01\x10LMT\x00ADT\x00AST\x00AWT\x00APT\x00\x0aAST4ADT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x1c\x9e\x9a]\x04\x00\x00]\x04\x00\x00\x0e\x00\x00\x00America/HavanaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffi\x87(\xb8\xff\xff\xff\xff\xacb\xc2\x80\xff\xff\xff\xff\xb1\xd3\x94P\xff\xff\xff\xff\xb2t]@\xff\xff\xff\xff\xc8[f\xd0\xff\xff\xff\xff\xc8\xd3Q@\xff\xff\xff\xff\xca;H\xd0\xff\xff\xff\xff\xca\xbcm\xc0\xff\xff\xff\xff\xcc$eP\xff\xff\xff\xff\xcc\x9cO\xc0\xff\xff\xff\xff\xd1\xc4\x0bP\xff\xff\xff\xff\xd2;\xf5\xc0\xff\xff\xff\xff\xd3\xa3\xedP\xff\xff\xff\xff\xd4\x1b\xd7\xc0\xff\xff\xff\xff\xf7`\x05\xd0\xff\xff\xff\xff\xf7\xff}@\xff\xff\xff\xff\xf9=D\xd0\xff\xff\xff\xff\xf9\xe3S\xc0\xff\xff\xff\xff\xfa\xdb;\xd0\xff\xff\xff\xff\xfb\xa7\x86@\xff\xff\xff\xff\xfc\xc5\xa9\xd0\xff\xff\xff\xff\xfd\x87h@\xff\xff\xff\xff\xfe\xb8\x00\xd0\xff\xff\xff\xff\xff\xa7\xe3\xc0\x00\x00\x00\x00\x00\x97\xe2\xd0\x00\x00\x00\x00\x01\x87\xc5\xc0\x00\x00\x00\x00\x02w\xc4\xd0\x00\x00\x00\x00\x03p\xe2@\x00\x00\x00\x00\x04`\xe1P\x00\x00\x00\x00\x055\x14\xc0\x00\x00\x00\x00\x06@\xc3P\x00\x00\x00\x00\x07\x16H@\x00\x00\x00\x00\x08 \xa5P\x00\x00\x00\x00\x08\xf7{\xc0\x00\x00\x00\x00\x0a\x00\x87P\x00\x00\x00\x00\x0a\xf0j@\x00\x00\x00\x00\x0b\xe0iP\x00\x00\x00\x00\x0c\xd9\x86\xc0\x00\x00\x00\x00\x0d\xc0KP\x00\x00\x00\x00\x0e\xb9h\xc0\x00\x00\x00\x00\x0f\xb2\xa2P\x00\x00\x00\x00\x10}\x9b@\x00\x00\x00\x00\x11Q\xea\xd0\x00\x00\x00\x00\x12f\xb7\xc0\x00\x00\x00\x00\x131\xcc\xd0\x00\x00\x00\x00\x14F\x99\xc0\x00\x00\x00\x00\x15[\x82\xd0\x00\x00\x00\x00\x16&{\xc0\x00\x00\x00\x00\x17;d\xd0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x19\x1bF\xd0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xfb(\xd0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\xdb\x0a\xd0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ezSP\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 Z5P\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x22CQ\xd0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$#3\xd0\x00\x00\x00\x00%.\xc6@\x00\x00\x00\x00&\x15\x8a\xd0\x00\x00\x00\x00'\x17\xe2\xc0\x00\x00\x00\x00'\xfe\xa7P\x00\x00\x00\x00(\xf7\xd2\xd0\x00\x00\x00\x00)\xde\x89P\x00\x00\x00\x00*\xd7\xb4\xd0\x00\x00\x00\x00+\xbekP\x00\x00\x00\x00,\xb7\x96\xd0\x00\x00\x00\x00-\x9eMP\x00\x00\x00\x00.\x97x\xd0\x00\x00\x00\x00/~/P\x00\x00\x00\x000wZ\xd0\x00\x00\x00\x001gK\xd0\x00\x00\x00\x002W<\xd0\x00\x00\x00\x003G-\xd0\x00\x00\x00\x004@YP\x00\x00\x00\x005\x1d\xd5P\x00\x00\x00\x0062\xb0P\x00\x00\x00\x006\xfd\xb7P\x00\x00\x00\x008\x1b\xcc\xd0\x00\x00\x00\x008\xe6\xd3\xd0\x00\x00\x00\x009\xfb\xae\xd0\x00\x00\x00\x00:\xc6\xb5\xd0\x00\x00\x00\x00;\xdb\x90\xd0\x00\x00\x00\x00<\xaf\xd2P\x00\x00\x00\x00=\xbbr\xd0\x00\x00\x00\x00>\x8f\xb4P\x00\x00\x00\x00?\x9bT\xd0\x00\x00\x00\x00@f[\xd0\x00\x00\x00\x00ED5P\x00\x00\x00\x00E\xf3\x8c\xd0\x00\x00\x00\x00G$\x17P\x00\x00\x00\x00G\xdc\xa9P\x00\x00\x00\x00I\x03\xf9P\x00\x00\x00\x00I\xb3P\xd0\x00\x00\x00\x00J\xe3\xdbP\x00\x00\x00\x00K\x9cmP\x00\x00\x00\x00L\xcc\xf7\xd0\x00\x00\x00\x00M\x85\x89\xd0\x00\x00\x00\x00N\xbfN\xd0\x00\x00\x00\x00Ow\xe0\xd0\x00\x00\x00\x00P\x95\xf6P\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\xff\xff\xb2\xc8\x00\x00\xff\xff\xb2\xc0\x00\x04\xff\xff\xc7\xc0\x01\x08\xff\xff\xb9\xb0\x00\x0cLMT\x00HMT\x00CDT\x00CST\x00\x0aCST5CDT,M3.2.0/0,M11.1.0/1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4MS\x99\x1e\x01\x00\x00\x1e\x01\x00\x00\x12\x00\x00\x00America/HermosilloTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\xff\xff\xff\xff\xcb\xeaq`\xff\xff\xff\xff\xd8\x91\xb4\xf0\x00\x00\x00\x00\x00\x00p\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x01\x02\x01\x03\x01\x02\x01\x04\x01\x03\x01\x03\x01\x03\x01\xff\xff\x97\xf8\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\x8f\x80\x00\x10LMT\x00MST\x00CST\x00MDT\x00PST\x00\x0aMST7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xb6{\xc9\x13\x02\x00\x00\x13\x02\x00\x00\x1c\x00\x00\x00America/Indiana/IndianapolisTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcaW\x22\x80\xff\xff\xff\xff\xca\xd8Gp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xf3\x00\xff\xff\xff\xff\xd4@\xeb\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x05\x06\x05\x06\x05\x06\x05\x06\xff\xff\xaf:\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$ \x873\xf8\x03\x00\x00\xf8\x03\x00\x00\x14\x00\x00\x00America/Indiana/KnoxTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5W<\xf0\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe77\x1e\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xd6\xc4\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\xbf\xe1p\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0\x9f\xc3p\xff\xff\xff\xff\xf1\x8f\xc2\x80\xff\xff\xff\xff\xf4_\x87p\xff\xff\xff\xff\xfa\xf8g\x00\xff\xff\xff\xff\xfb\xe8I\xf0\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8+\xf0\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa8\x0d\xf0\x00\x00\x00\x00\x00\x98\x0d\x00\x00\x00\x00\x00\x01\x87\xef\xf0\x00\x00\x00\x00\x02w\xef\x00\x00\x00\x00\x00\x03q\x0cp\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xeep\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x07\x8d'\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\xa3\x00\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99t\xf0\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12yV\xf0\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14Y8\xf0\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169\x1a\xf0\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x227p\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02\x19p\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe1\xfbp\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xddp\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xbfp\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xa1p\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\x9f\xf0\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x81\xf0\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ac\xf0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x05\x01\x02\x01\xff\xff\xae\xca\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M/U\x9f7\x02\x00\x007\x02\x00\x00\x17\x00\x00\x00America/Indiana/MarengoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe7\x124\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xb1\xda\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\x91\xbc\xf0\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00\x02w\xe0\xf0\x00\x00\x00\x00\x03p\xfe`\x00\x00\x00\x00\x04`\xfdp\x00\x00\x00\x00\x05P\xe0`\x00\x00\x00\x00\x06@\xdfp\x00\x00\x00\x00\x070\xc2`\x00\x00\x00\x00\x07\x8d\x19p\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\x94\xf0\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x01\x05\x06\x05\x06\x05\x06\xff\xff\xaf\x0d\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xd8N\x8c\xab\x02\x00\x00\xab\x02\x00\x00\x1a\x00\x00\x00America/Indiana/PetersburgTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xe4g=\xe0\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe7\x124\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xb1\xda\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\x91\xbc\xf0\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0\x9f\xc3p\xff\xff\xff\xff\xf1\x8f\xc2\x80\xff\xff\xff\xff\xf2\x7f\xa5p\xff\xff\xff\xff\xf3o\xa4\x80\xff\xff\xff\xff\xf4_\x87p\xff\xff\xff\xff\xf5O\x86\x80\xff\xff\xff\xff\xf6?ip\xff\xff\xff\xff\xf7/h\x80\xff\xff\xff\xff\xfa\x08g\xf0\xff\xff\xff\xff\xfa\xf8g\x00\xff\xff\xff\xff\xfb\xe8I\xf0\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8+\xf0\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa8\x0d\xf0\x00\x00\x00\x00\x00\x98\x0d\x00\x00\x00\x00\x00\x01\x87\xef\xf0\x00\x00\x00\x00\x02w\xef\x00\x00\x00\x00\x00\x03q\x0cp\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xeep\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x07\x8d'\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\xa3\x00\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x00\x00\x00\x00G-m\xf0\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x05\x01\x02\x01\x05\xff\xff\xae-\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd8\xb5K\xa6\x0a\x02\x00\x00\x0a\x02\x00\x00\x19\x00\x00\x00America/Indiana/Tell_CityTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xe4g=\xe0\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe7\x124\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xb1\xda\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\x91\xbc\xf0\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0\x9f\xc3p\xff\xff\xff\xff\xf1\x8f\xc2\x80\xff\xff\xff\xff\xf2\x7f\xa5p\xff\xff\xff\xff\xf3o\xa4\x80\xff\xff\xff\xff\xf4_\x87p\xff\xff\xff\xff\xf5O\x86\x80\xff\xff\xff\xff\xfb\xe8I\xf0\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8+\xf0\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x01\x02\x06\x05\x06\x05\x01\x02\x01\xff\xff\xae\xa9\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x17\x89}q\x01\x00\x00q\x01\x00\x00\x15\x00\x00\x00America/Indiana/VevayTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00\x02w\xe0\xf0\x00\x00\x00\x00\x03p\xfe`\x00\x00\x00\x00\x04`\xfdp\x00\x00\x00\x00\x05P\xe0`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x03\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\xff\xff\xb0@\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\xedsp.\x02\x00\x00.\x02\x00\x00\x19\x00\x00\x00America/Indiana/VincennesTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xf3\x00\xff\xff\xff\xff\xd4@\xeb\xf0\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4g=\xe0\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe7\x124\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xb1\xda\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\xbf\xe1p\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0q\x9e\xf0\xff\xff\xff\xff\xf1\x8f\xc2\x80\xff\xff\xff\xff\xf2\x7f\xa5p\xff\xff\xff\xff\xf3o\xa4\x80\xff\xff\xff\xff\xf4_\x87p\xff\xff\xff\xff\xf5O\x86\x80\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x00\x00\x00\x00G-m\xf0\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x06\x05\x06\x05\x01\x02\x01\x05\xff\xff\xad\xf1\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfdH\xb79[\x02\x00\x00[\x02\x00\x00\x17\x00\x00\x00America/Indiana/WinamacTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xf3\x00\xff\xff\xff\xff\xd4@\xeb\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5W<\xf0\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe77\x1e\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xb1\xda\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\x91\xbc\xf0\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x06\x05\x06\x05\x01\x02\x06\xff\xff\xae\xcf\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xb6{\xc9\x13\x02\x00\x00\x13\x02\x00\x00\x14\x00\x00\x00America/IndianapolisTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcaW\x22\x80\xff\xff\xff\xff\xca\xd8Gp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xf3\x00\xff\xff\xff\xff\xd4@\xeb\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x05\x06\x05\x06\x05\x06\x05\x06\xff\xff\xaf:\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xbc\x09o1\x03\x00\x001\x03\x00\x00\x0e\x00\x00\x00America/InuvikTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xe0\x06N\x80\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x08 \xeb\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x0a\x00\xcd\xa0\x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x00\x00\x00\x00\x00\x00\xff\xff\x9d\x90\x01\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x00\x0c\xff\xff\xab\xa0\x01\x10-00\x00PDT\x00PST\x00MST\x00MDT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xa0\xd6\x05W\x03\x00\x00W\x03\x00\x00\x0f\x00\x00\x00America/IqaluitTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00J\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff\xccl\xa1\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\x00\x00\x00\x00\x04`\xfdp\x00\x00\x00\x00\x05P\xe0`\x00\x00\x00\x00\x06@\xdfp\x00\x00\x00\x00\x070\xc2`\x00\x00\x00\x00\x08 \xc1p\x00\x00\x00\x00\x09\x10\xa4`\x00\x00\x00\x00\x0a\x00\xa3p\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00\x0b\xe0\x85p\x00\x00\x00\x00\x0c\xd9\xa2\xe0\x00\x00\x00\x00\x0d\xc0gp\x00\x00\x00\x00\x0e\xb9\x84\xe0\x00\x00\x00\x00\x0f\xa9\x83\xf0\x00\x00\x00\x00\x10\x99f\xe0\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x00\x00\x00\x00\x1a\xf2\x0ap\x00\x00\x00\x00\x1b\xe1\xed`\x00\x00\x00\x00\x1c\xd1\xecp\x00\x00\x00\x00\x1d\xc1\xcf`\x00\x00\x00\x00\x1e\xb1\xcep\x00\x00\x00\x00\x1f\xa1\xb1`\x00\x00\x00\x00 v\x00\xf0\x00\x00\x00\x00!\x81\x93`\x00\x00\x00\x00\x22U\xe2\xf0\x00\x00\x00\x00#j\xaf\xe0\x00\x00\x00\x00$5\xc4\xf0\x00\x00\x00\x00%J\x91\xe0\x00\x00\x00\x00&\x15\xa6\xf0\x00\x00\x00\x00'*s\xe0\x00\x00\x00\x00'\xfe\xc3p\x00\x00\x00\x00)\x0aU\xe0\x00\x00\x00\x00)\xde\xa5p\x00\x00\x00\x00*\xea7\xe0\x00\x00\x00\x00+\xbe\x87p\x00\x00\x00\x00,\xd3T`\x00\x00\x00\x00-\x9eip\x00\x00\x00\x00.\xb36`\x00\x00\x00\x00/~Kp\x00\x00\x00\x000\x93\x18`\x00\x00\x00\x001gg\xf0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003GI\xf0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x005'+\xf0\x00\x00\x00\x0062\xbe`\x00\x00\x00\x007\x07\x0d\xf0\x00\x00\x00\x008\x1b\xda\xe0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xc6\xd1\xf0\x00\x00\x00\x00;\xdb\x9e\xe0\x00\x00\x00\x00<\xaf\xeep\x00\x00\x00\x00=\xbb\x80\xe0\x00\x00\x00\x00>\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x04\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x06\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00\x00\x00\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10\xff\xff\xab\xa0\x00\x14\xff\xff\xb9\xb0\x01\x18-00\x00EPT\x00EST\x00EDT\x00EWT\x00CST\x00CDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%J\xd5\xebS\x01\x00\x00S\x01\x00\x00\x0f\x00\x00\x00America/JamaicaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffi\x87#~\xff\xff\xff\xff\x93\x0f\xb4\xfe\x00\x00\x00\x00\x07\x8d\x19p\x00\x00\x00\x00\x09\x10\xa4`\x00\x00\x00\x00\x09\xad\x94\xf0\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00\x0b\xe0\x85p\x00\x00\x00\x00\x0c\xd9\xa2\xe0\x00\x00\x00\x00\x0d\xc0gp\x00\x00\x00\x00\x0e\xb9\x84\xe0\x00\x00\x00\x00\x0f\xa9\x83\xf0\x00\x00\x00\x00\x10\x99f\xe0\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\xff\xff\xb8\x02\x00\x00\xff\xff\xb8\x02\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0cLMT\x00KMT\x00EST\x00EDT\x00\x0aEST5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00utZ\x1a\xb2\x02\x00\x00\xb2\x02\x00\x00\x0d\x00\x00\x00America/JujuyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xae\xb8\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'*W\xc0\x00\x00\x00\x00'\xe2\xdb\xb0\x00\x00\x00\x00(\xee\x8a@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x02\x03\x02\x04\x05\x04\x05\x03\x05\x04\x05\xff\xff\xc2\xc8\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xc9\x1c\xd4\xc6\x03\x00\x00\xc6\x03\x00\x00\x0e\x00\x00\x00America/JuneauTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x0a\x00\x00\x00&\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x872\xc5\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x07\x8dC\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x09\xad\xbf \x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14Yc \x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a+\x14\x10\x00\x00\x00\x00\x1a\xf2B\xb0\x00\x00\x00\x00\x1b\xe2%\xa0\x00\x00\x00\x00\x1c\xd2$\xb0\x00\x00\x00\x00\x1d\xc2\x07\xa0\x00\x00\x00\x00\x1e\xb2\x06\xb0\x00\x00\x00\x00\x1f\xa1\xe9\xa0\x00\x00\x00\x00 v90\x00\x00\x00\x00!\x81\xcb\xa0\x00\x00\x00\x00\x22V\x1b0\x00\x00\x00\x00#j\xe8 \x00\x00\x00\x00$5\xfd0\x00\x00\x00\x00%J\xca \x00\x00\x00\x00&\x15\xdf0\x00\x00\x00\x00'*\xac \x00\x00\x00\x00'\xfe\xfb\xb0\x00\x00\x00\x00)\x0a\x8e \x00\x00\x00\x00)\xde\xdd\xb0\x00\x00\x00\x00*\xeap \x00\x00\x00\x00+\xbe\xbf\xb0\x00\x00\x00\x00,\xd3\x8c\xa0\x00\x00\x00\x00-\x9e\xa1\xb0\x00\x00\x00\x00.\xb3n\xa0\x00\x00\x00\x00/~\x83\xb0\x00\x00\x00\x000\x93P\xa0\x00\x00\x00\x001g\xa00\x00\x00\x00\x002s2\xa0\x00\x00\x00\x003G\x820\x00\x00\x00\x004S\x14\xa0\x00\x00\x00\x005'd0\x00\x00\x00\x0062\xf6\xa0\x00\x00\x00\x007\x07F0\x00\x00\x00\x008\x1c\x13 \x00\x00\x00\x008\xe7(0\x00\x00\x00\x009\xfb\xf5 \x00\x00\x00\x00:\xc7\x0a0\x00\x00\x00\x00;\xdb\xd7 \x00\x00\x00\x00<\xb0&\xb0\x00\x00\x00\x00=\xbb\xb9 \x00\x00\x00\x00>\x90\x08\xb0\x00\x00\x00\x00?\x9b\x9b \x00\x00\x00\x00@o\xea\xb0\x00\x00\x00\x00A\x84\xb7\xa0\x00\x00\x00\x00BO\xcc\xb0\x00\x00\x00\x00Cd\x99\xa0\x00\x00\x00\x00D/\xae\xb0\x00\x00\x00\x00ED{\xa0\x00\x00\x00\x00E\xf3\xe10\x01\x02\x03\x04\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x06\x02\x05\x02\x05\x02\x05\x07\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x00\x00\xd3{\x00\x00\xff\xff\x81\xfb\x00\x00\xff\xff\x8f\x80\x00\x04\xff\xff\x9d\x90\x01\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10\xff\xff\x8f\x80\x01\x14\xff\xff\x81p\x00\x18\xff\xff\x8f\x80\x01\x1c\xff\xff\x81p\x00!LMT\x00PST\x00PWT\x00PPT\x00PDT\x00YDT\x00YST\x00AKDT\x00AKST\x00\x0aAKST9AKDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdf\xe5\x8d\xc4\xda\x04\x00\x00\xda\x04\x00\x00\x1b\x00\x00\x00America/Kentucky/LouisvilleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xa4s\xf7\x00\xff\xff\xff\xff\xa5\x16\x11p\xff\xff\xff\xff\xca\x0dN\x80\xff\xff\xff\xff\xca\xd8Gp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xd7\x1c\xff\xff\xff\xff\xd3\xa4\x09p\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe77\x1e\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe9\x17\x00\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xf6\xe2\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xd6\xc4\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\xbf\xe1p\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0\x1e\x90p\xff\xff\xff\xff\xfc\xd8:\xf0\xff\xff\xff\xff\xfd\xc8\x1d\xe0\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00\x02w\xe0\xf0\x00\x00\x00\x00\x03p\xfe`\x00\x00\x00\x00\x04`\xfdp\x00\x00\x00\x00\x05P\xe0`\x00\x00\x00\x00\x06@\xdfp\x00\x00\x00\x00\x070\xc2`\x00\x00\x00\x00\x07\x8d\x19p\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\x94\xf0\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00\x0b\xe0\x85p\x00\x00\x00\x00\x0c\xd9\xa2\xe0\x00\x00\x00\x00\x0d\xc0gp\x00\x00\x00\x00\x0e\xb9\x84\xe0\x00\x00\x00\x00\x0f\xa9\x83\xf0\x00\x00\x00\x00\x10\x99f\xe0\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x00\x00\x00\x00\x1a\xf2\x0ap\x00\x00\x00\x00\x1b\xe1\xed`\x00\x00\x00\x00\x1c\xd1\xecp\x00\x00\x00\x00\x1d\xc1\xcf`\x00\x00\x00\x00\x1e\xb1\xcep\x00\x00\x00\x00\x1f\xa1\xb1`\x00\x00\x00\x00 v\x00\xf0\x00\x00\x00\x00!\x81\x93`\x00\x00\x00\x00\x22U\xe2\xf0\x00\x00\x00\x00#j\xaf\xe0\x00\x00\x00\x00$5\xc4\xf0\x00\x00\x00\x00%J\x91\xe0\x00\x00\x00\x00&\x15\xa6\xf0\x00\x00\x00\x00'*s\xe0\x00\x00\x00\x00'\xfe\xc3p\x00\x00\x00\x00)\x0aU\xe0\x00\x00\x00\x00)\xde\xa5p\x00\x00\x00\x00*\xea7\xe0\x00\x00\x00\x00+\xbe\x87p\x00\x00\x00\x00,\xd3T`\x00\x00\x00\x00-\x9eip\x00\x00\x00\x00.\xb36`\x00\x00\x00\x00/~Kp\x00\x00\x00\x000\x93\x18`\x00\x00\x00\x001gg\xf0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003GI\xf0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x005'+\xf0\x00\x00\x00\x0062\xbe`\x00\x00\x00\x007\x07\x0d\xf0\x00\x00\x00\x008\x1b\xda\xe0\x00\x00\x00\x008\xe6\xef\xf0\x00\x00\x00\x009\xfb\xbc\xe0\x00\x00\x00\x00:\xc6\xd1\xf0\x00\x00\x00\x00;\xdb\x9e\xe0\x00\x00\x00\x00<\xaf\xeep\x00\x00\x00\x00=\xbb\x80\xe0\x00\x00\x00\x00>\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x01\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\xff\xff\xaf\x9a\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x1a|J\xcc\x03\x00\x00\xcc\x03\x00\x00\x1b\x00\x00\x00America/Kentucky/MonticelloTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8+\xf0\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa8\x0d\xf0\x00\x00\x00\x00\x00\x98\x0d\x00\x00\x00\x00\x00\x01\x87\xef\xf0\x00\x00\x00\x00\x02w\xef\x00\x00\x00\x00\x00\x03q\x0cp\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xeep\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x07\x8d'\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\xa3\x00\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99t\xf0\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12yV\xf0\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14Y8\xf0\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169\x1a\xf0\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x227p\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02\x19p\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe1\xfbp\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xddp\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xbfp\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xa1p\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\x9f\xf0\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x81\xf0\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ac\xf0\x00\x00\x00\x00)\xde\xb3\x80\x00\x00\x00\x00*\xeaE\xf0\x00\x00\x00\x00+\xbe\x95\x80\x00\x00\x00\x00,\xd3bp\x00\x00\x00\x00-\x9ew\x80\x00\x00\x00\x00.\xb3Dp\x00\x00\x00\x00/~Y\x80\x00\x00\x00\x000\x93&p\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xc6\xd1\xf0\x00\x00\x00\x00;\xdb\x9e\xe0\x00\x00\x00\x00<\xaf\xeep\x00\x00\x00\x00=\xbb\x80\xe0\x00\x00\x00\x00>\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\xff\xff\xb0t\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xc7\xc0\x01\x14\xff\xff\xb9\xb0\x00\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EDT\x00EST\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$ \x873\xf8\x03\x00\x00\xf8\x03\x00\x00\x0f\x00\x00\x00America/Knox_INTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5W<\xf0\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe77\x1e\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xd6\xc4\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\xbf\xe1p\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0\x9f\xc3p\xff\xff\xff\xff\xf1\x8f\xc2\x80\xff\xff\xff\xff\xf4_\x87p\xff\xff\xff\xff\xfa\xf8g\x00\xff\xff\xff\xff\xfb\xe8I\xf0\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8+\xf0\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa8\x0d\xf0\x00\x00\x00\x00\x00\x98\x0d\x00\x00\x00\x00\x00\x01\x87\xef\xf0\x00\x00\x00\x00\x02w\xef\x00\x00\x00\x00\x00\x03q\x0cp\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xeep\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x07\x8d'\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\xa3\x00\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99t\xf0\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12yV\xf0\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14Y8\xf0\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169\x1a\xf0\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x227p\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02\x19p\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe1\xfbp\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xddp\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xbfp\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xa1p\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\x9f\xf0\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x81\xf0\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ac\xf0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x05\x01\x02\x01\xff\xff\xae\xca\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x12\x00\x00\x00America/KralendijkTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xad`\x12\xe9\xaa\x00\x00\x00\xaa\x00\x00\x00\x0e\x00\x00\x00America/La_PazTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffi\x87\x1bd\xff\xff\xff\xff\xb8\x1e\x96\xe4\xff\xff\xff\xff\xb8\xee\xd5\xd4\x01\x02\x03\xff\xff\xc0\x1c\x00\x00\xff\xff\xc0\x1c\x00\x04\xff\xff\xce,\x01\x08\xff\xff\xc7\xc0\x00\x0cLMT\x00CMT\x00BST\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe7\xa1\x87\x1b\x01\x00\x00\x1b\x01\x00\x00\x0c\x00\x00\x00America/LimaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xffi\x87#\xbc\xff\xff\xff\xff\x8ct@\xd4\xff\xff\xff\xff\xc3\xcfJP\xff\xff\xff\xff\xc4E\xe3@\xff\xff\xff\xff\xc5/J\xd0\xff\xff\xff\xff\xc6\x1f-\xc0\xff\xff\xff\xff\xc7\x0f,\xd0\xff\xff\xff\xff\xc7\xff\x0f\xc0\x00\x00\x00\x00\x1e\x18\xc4P\x00\x00\x00\x00\x1e\x8f]@\x00\x00\x00\x00\x1f\xf9\xf7\xd0\x00\x00\x00\x00 p\x90\xc0\x00\x00\x00\x00%\x9e\xe3\xd0\x00\x00\x00\x00&\x15|\xc0\x00\x00\x00\x00-%\x03P\x00\x00\x00\x00-\x9b\x9c@\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\xff\xff\xb7\xc4\x00\x00\xff\xff\xb7\xac\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08LMT\x00-04\x00-05\x00\x0a<-05>5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x22\x12\xfe\x0e\x05\x00\x00\x0e\x05\x00\x00\x13\x00\x00\x00America/Los_AngelesTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^\x04\x1a\xc0\xff\xff\xff\xff\x9e\xa6H\xa0\xff\xff\xff\xff\x9f\xbb\x15\x90\xff\xff\xff\xff\xa0\x86*\xa0\xff\xff\xff\xff\xa1\x9a\xf7\x90\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xd6\xfet\x5c\xff\xff\xff\xff\xd8\x80\xad\x90\xff\xff\xff\xff\xda\xfe\xc3\x90\xff\xff\xff\xff\xdb\xc0\x90\x10\xff\xff\xff\xff\xdc\xde\xa5\x90\xff\xff\xff\xff\xdd\xa9\xac\x90\xff\xff\xff\xff\xde\xbe\x87\x90\xff\xff\xff\xff\xdf\x89\x8e\x90\xff\xff\xff\xff\xe0\x9ei\x90\xff\xff\xff\xff\xe1ip\x90\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x0e\x10\xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xd2\x10\xff\xff\xff\xff\xee\x91\xd9\x10\xff\xff\xff\xff\xef\xaf\xee\x90\xff\xff\xff\xff\xf0q\xbb\x10\xff\xff\xff\xff\xf1\x8f\xd0\x90\xff\xff\xff\xff\xf2\x7f\xc1\x90\xff\xff\xff\xff\xf3o\xb2\x90\xff\xff\xff\xff\xf4_\xa3\x90\xff\xff\xff\xff\xf5O\x94\x90\xff\xff\xff\xff\xf6?\x85\x90\xff\xff\xff\xff\xf7/v\x90\xff\xff\xff\xff\xf8(\xa2\x10\xff\xff\xff\xff\xf9\x0fX\x90\xff\xff\xff\xff\xfa\x08\x84\x10\xff\xff\xff\xff\xfa\xf8\x83 \xff\xff\xff\xff\xfb\xe8f\x10\xff\xff\xff\xff\xfc\xd8e \xff\xff\xff\xff\xfd\xc8H\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x07\x8dC\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x09\xad\xbf \x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x91&\x00\x00\xff\xff\x9d\x90\x01\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10LMT\x00PDT\x00PST\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdf\xe5\x8d\xc4\xda\x04\x00\x00\xda\x04\x00\x00\x12\x00\x00\x00America/LouisvilleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xa4s\xf7\x00\xff\xff\xff\xff\xa5\x16\x11p\xff\xff\xff\xff\xca\x0dN\x80\xff\xff\xff\xff\xca\xd8Gp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xd7\x1c\xff\xff\xff\xff\xd3\xa4\x09p\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe77\x1e\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe9\x17\x00\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xf6\xe2\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xd6\xc4\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\xbf\xe1p\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0\x1e\x90p\xff\xff\xff\xff\xfc\xd8:\xf0\xff\xff\xff\xff\xfd\xc8\x1d\xe0\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00\x02w\xe0\xf0\x00\x00\x00\x00\x03p\xfe`\x00\x00\x00\x00\x04`\xfdp\x00\x00\x00\x00\x05P\xe0`\x00\x00\x00\x00\x06@\xdfp\x00\x00\x00\x00\x070\xc2`\x00\x00\x00\x00\x07\x8d\x19p\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\x94\xf0\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00\x0b\xe0\x85p\x00\x00\x00\x00\x0c\xd9\xa2\xe0\x00\x00\x00\x00\x0d\xc0gp\x00\x00\x00\x00\x0e\xb9\x84\xe0\x00\x00\x00\x00\x0f\xa9\x83\xf0\x00\x00\x00\x00\x10\x99f\xe0\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x00\x00\x00\x00\x1a\xf2\x0ap\x00\x00\x00\x00\x1b\xe1\xed`\x00\x00\x00\x00\x1c\xd1\xecp\x00\x00\x00\x00\x1d\xc1\xcf`\x00\x00\x00\x00\x1e\xb1\xcep\x00\x00\x00\x00\x1f\xa1\xb1`\x00\x00\x00\x00 v\x00\xf0\x00\x00\x00\x00!\x81\x93`\x00\x00\x00\x00\x22U\xe2\xf0\x00\x00\x00\x00#j\xaf\xe0\x00\x00\x00\x00$5\xc4\xf0\x00\x00\x00\x00%J\x91\xe0\x00\x00\x00\x00&\x15\xa6\xf0\x00\x00\x00\x00'*s\xe0\x00\x00\x00\x00'\xfe\xc3p\x00\x00\x00\x00)\x0aU\xe0\x00\x00\x00\x00)\xde\xa5p\x00\x00\x00\x00*\xea7\xe0\x00\x00\x00\x00+\xbe\x87p\x00\x00\x00\x00,\xd3T`\x00\x00\x00\x00-\x9eip\x00\x00\x00\x00.\xb36`\x00\x00\x00\x00/~Kp\x00\x00\x00\x000\x93\x18`\x00\x00\x00\x001gg\xf0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003GI\xf0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x005'+\xf0\x00\x00\x00\x0062\xbe`\x00\x00\x00\x007\x07\x0d\xf0\x00\x00\x00\x008\x1b\xda\xe0\x00\x00\x00\x008\xe6\xef\xf0\x00\x00\x00\x009\xfb\xbc\xe0\x00\x00\x00\x00:\xc6\xd1\xf0\x00\x00\x00\x00;\xdb\x9e\xe0\x00\x00\x00\x00<\xaf\xeep\x00\x00\x00\x00=\xbb\x80\xe0\x00\x00\x00\x00>\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x01\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\xff\xff\xaf\x9a\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x15\x00\x00\x00America/Lower_PrincesTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x8c\x8b\x92\xf6\x01\x00\x00\xf6\x01\x00\x00\x0e\x00\x00\x00America/MaceioTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaah|\xff\xff\xff\xff\xb8\x0fI\xe0\xff\xff\xff\xff\xb8\xfd@\xa0\xff\xff\xff\xff\xb9\xf140\xff\xff\xff\xff\xba\xdet \xff\xff\xff\xff\xda8\xae0\xff\xff\xff\xff\xda\xeb\xfa0\xff\xff\xff\xff\xdc\x19\xe1\xb0\xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xfb\x150\xff\xff\xff\xff\xde\x9b\xde \xff\xff\xff\xff\xdf\xdd\x9a0\xff\xff\xff\xff\xe0T3 \xff\xff\xff\xff\xf4\x97\xff\xb0\xff\xff\xff\xff\xf5\x05^ \xff\xff\xff\xff\xf6\xc0d0\xff\xff\xff\xff\xf7\x0e\x1e\xa0\xff\xff\xff\xff\xf8Q,0\xff\xff\xff\xff\xf8\xc7\xc5 \xff\xff\xff\xff\xfa\x0a\xd2\xb0\xff\xff\xff\xff\xfa\xa8\xf8\xa0\xff\xff\xff\xff\xfb\xec\x060\xff\xff\xff\xff\xfc\x8b}\xa0\x00\x00\x00\x00\x1d\xc9\x8e0\x00\x00\x00\x00\x1ex\xd7\xa0\x00\x00\x00\x00\x1f\xa05\xb0\x00\x00\x00\x00 3\xcf\xa0\x00\x00\x00\x00!\x81i0\x00\x00\x00\x00\x22\x0b\xc8\xa0\x00\x00\x00\x00#X\x10\xb0\x00\x00\x00\x00#\xe2p \x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xd4\xc7 \x00\x00\x00\x000\x80y0\x00\x00\x00\x001\x1dM\xa0\x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xb8\x85 \x00\x00\x00\x009\xdf\xe30\x00\x00\x00\x009\xf2J \x00\x00\x00\x00;\xc8\xff\xb0\x00\x00\x00\x003\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5s\xb3\x5c'\x01\x00\x00'\x01\x00\x00\x0f\x00\x00\x00America/ManaguaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffi\x87,d\xff\xff\xff\xff\xbd-H\xe8\x00\x00\x00\x00\x06Ct`\x00\x00\x00\x00\x09\xa4>P\x00\x00\x00\x00\x11Q\xf8\xe0\x00\x00\x00\x00\x11\xd4oP\x00\x00\x00\x00\x131\xda\xe0\x00\x00\x00\x00\x13\xb4QP\x00\x00\x00\x00)a\x91 \x00\x00\x00\x00*\xc1KP\x00\x00\x00\x00+C\xdd\xe0\x00\x00\x00\x002\xc9\xefP\x00\x00\x00\x00BX\xc0\xe0\x00\x00\x00\x00C?iP\x00\x00\x00\x00DTn\x80\x00\x00\x00\x00E\x1fY`\x01\x02\x03\x02\x04\x02\x04\x02\x03\x02\x03\x02\x04\x02\x04\x02\xff\xff\xaf\x1c\x00\x00\xff\xff\xaf\x18\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x00\x0c\xff\xff\xb9\xb0\x01\x10LMT\x00MMT\x00CST\x00EST\x00CDT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\xcb'\xe9\x9c\x01\x00\x00\x9c\x01\x00\x00\x0e\x00\x00\x00America/ManausTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa\x7fD\xff\xff\xff\xff\xb8\x0fW\xf0\xff\xff\xff\xff\xb8\xfdN\xb0\xff\xff\xff\xff\xb9\xf1B@\xff\xff\xff\xff\xba\xde\x820\xff\xff\xff\xff\xda8\xbc@\xff\xff\xff\xff\xda\xec\x08@\xff\xff\xff\xff\xdc\x19\xef\xc0\xff\xff\xff\xff\xdc\xb9g0\xff\xff\xff\xff\xdd\xfb#@\xff\xff\xff\xff\xde\x9b\xec0\xff\xff\xff\xff\xdf\xdd\xa8@\xff\xff\xff\xff\xe0TA0\xff\xff\xff\xff\xf4\x98\x0d\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf6\xc0r@\xff\xff\xff\xff\xf7\x0e,\xb0\xff\xff\xff\xff\xf8Q:@\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xfa\x0a\xe0\xc0\xff\xff\xff\xff\xfa\xa9\x06\xb0\xff\xff\xff\xff\xfb\xec\x14@\xff\xff\xff\xff\xfc\x8b\x8b\xb0\x00\x00\x00\x00\x1d\xc9\x9c@\x00\x00\x00\x00\x1ex\xe5\xb0\x00\x00\x00\x00\x1f\xa0C\xc0\x00\x00\x00\x00 3\xdd\xb0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22\x0b\xd6\xb0\x00\x00\x00\x00,\xc0\xc3@\x00\x00\x00\x00-f\xd20\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xc7\xbc\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08LMT\x00-03\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00America/MarigotTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x17j\xd2\xb2\x00\x00\x00\xb2\x00\x00\x00\x12\x00\x00\x00America/MartiniqueTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xffi\x87\x14\xc4\xff\xff\xff\xff\x91\xa3\xc8D\x00\x00\x00\x00\x13Mn@\x00\x00\x00\x00\x144\x16\xb0\x01\x02\x03\x02\xff\xff\xc6\xbc\x00\x00\xff\xff\xc6\xbc\x00\x04\xff\xff\xc7\xc0\x00\x09\xff\xff\xd5\xd0\x01\x0dLMT\x00FFMT\x00AST\x00ADT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00y\xb7\xe2]\xb5\x01\x00\x00\xb5\x01\x00\x00\x11\x00\x00\x00America/MatamorosTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xa5\xb6\xda`\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xf5\x04\x80\x00\x00\x00\x00;\xb6\xc2\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00F\x0ff\x80\x00\x00\x00\x00G$3p\x00\x00\x00\x00G\xf8\x83\x00\x00\x00\x00\x00I\x04\x15p\x00\x00\x00\x00I\xd8e\x00\x00\x00\x00\x00J\xe3\xf7p\x00\x00\x00\x00K=\x8f`\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x01\xff\xff\xa4\x98\x00\x00\xff\xff\xab\xa0\x00\x04\xff\xff\xb9\xb0\x01\x08LMT\x00CST\x00CDT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xad=\x98\xce\x02\x00\x00\xce\x02\x00\x00\x10\x00\x00\x00America/MazatlanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\xff\xff\xff\xff\xcb\xeaq`\xff\xff\xff\xff\xd8\x91\xb4\xf0\x00\x00\x00\x00\x00\x00p\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xf5\x12\x90\x00\x00\x00\x00;\xb6\xd1\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00F\x0ft\x90\x00\x00\x00\x00G$A\x80\x00\x00\x00\x00G\xf8\x91\x10\x00\x00\x00\x00I\x04#\x80\x00\x00\x00\x00I\xd8s\x10\x00\x00\x00\x00J\xe4\x05\x80\x00\x00\x00\x00K\xb8U\x10\x00\x00\x00\x00L\xcd\x22\x00\x00\x00\x00\x00M\x987\x10\x00\x00\x00\x00N\xad\x04\x00\x00\x00\x00\x00Ox\x19\x10\x00\x00\x00\x00P\x8c\xe6\x00\x00\x00\x00\x00Qa5\x90\x00\x00\x00\x00Rl\xc8\x00\x00\x00\x00\x00SA\x17\x90\x00\x00\x00\x00TL\xaa\x00\x00\x00\x00\x00U \xf9\x90\x00\x00\x00\x00V,\x8c\x00\x00\x00\x00\x00W\x00\xdb\x90\x00\x00\x00\x00X\x15\xa8\x80\x00\x00\x00\x00X\xe0\xbd\x90\x00\x00\x00\x00Y\xf5\x8a\x80\x00\x00\x00\x00Z\xc0\x9f\x90\x00\x00\x00\x00[\xd5l\x80\x00\x00\x00\x00\x5c\xa9\xbc\x10\x00\x00\x00\x00]\xb5N\x80\x00\x00\x00\x00^\x89\x9e\x10\x00\x00\x00\x00_\x950\x80\x00\x00\x00\x00`i\x80\x10\x00\x00\x00\x00a~M\x00\x00\x00\x00\x00bIb\x10\x00\x00\x00\x00c^/\x00\x01\x02\x01\x03\x01\x02\x01\x04\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\xff\xff\x9c<\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\x8f\x80\x00\x10LMT\x00MST\x00CST\x00MDT\x00PST\x00\x0aMST7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\x92Z\x8c\xc4\x02\x00\x00\xc4\x02\x00\x00\x0f\x00\x00\x00America/MendozaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xb2\x04\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'\x194@\x00\x00\x00\x00'\xcd\xc3\xb0\x00\x00\x00\x00(\xfag\xc0\x00\x00\x00\x00)\xb0H\xb0\x00\x00\x00\x00*\xe0\xe1@\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00@\xb0\x13\xb0\x00\x00\x00\x00AV>\xc0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x02\x03\x02\x03\x02\x04\x05\x03\x05\x02\x05\x04\x05\xff\xff\xbf|\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008O:\xbf\x95\x03\x00\x00\x95\x03\x00\x00\x11\x00\x00\x00America/MenomineeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xffawIc\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xf3\x00\xff\xff\xff\xff\xd4@\xeb\xf0\xff\xff\xff\xff\xf9\x0fJ\x80\xff\xff\xff\xff\xfa\x08g\xf0\xff\xff\xff\xff\xfe\xb8+\x00\x00\x00\x00\x00\x06@\xdfp\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x07\x8d'\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\xa3\x00\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99t\xf0\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12yV\xf0\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14Y8\xf0\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169\x1a\xf0\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x227p\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02\x19p\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe1\xfbp\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xddp\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xbfp\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xa1p\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\x9f\xf0\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x81\xf0\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ac\xf0\x00\x00\x00\x00)\xde\xb3\x80\x00\x00\x00\x00*\xeaE\xf0\x00\x00\x00\x00+\xbe\x95\x80\x00\x00\x00\x00,\xd3bp\x00\x00\x00\x00-\x9ew\x80\x00\x00\x00\x00.\xb3Dp\x00\x00\x00\x00/~Y\x80\x00\x00\x00\x000\x93&p\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xc6\xe0\x00\x00\x00\x00\x00;\xdb\xac\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x05\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xad\xdd\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xbd\x809\x8e\x02\x00\x00\x8e\x02\x00\x00\x0e\x00\x00\x00America/MeridaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\xa5\xb6\xda`\x00\x00\x00\x00\x16\x86\xd5`\x00\x00\x00\x00\x18LKP\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xf5\x04\x80\x00\x00\x00\x00;\xb6\xc2\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00F\x0ff\x80\x00\x00\x00\x00G$3p\x00\x00\x00\x00G\xf8\x83\x00\x00\x00\x00\x00I\x04\x15p\x00\x00\x00\x00I\xd8e\x00\x00\x00\x00\x00J\xe3\xf7p\x00\x00\x00\x00K\xb8G\x00\x00\x00\x00\x00L\xcd\x13\xf0\x00\x00\x00\x00M\x98)\x00\x00\x00\x00\x00N\xac\xf5\xf0\x00\x00\x00\x00Ox\x0b\x00\x00\x00\x00\x00P\x8c\xd7\xf0\x00\x00\x00\x00Qa'\x80\x00\x00\x00\x00Rl\xb9\xf0\x00\x00\x00\x00SA\x09\x80\x00\x00\x00\x00TL\x9b\xf0\x00\x00\x00\x00U \xeb\x80\x00\x00\x00\x00V,}\xf0\x00\x00\x00\x00W\x00\xcd\x80\x00\x00\x00\x00X\x15\x9ap\x00\x00\x00\x00X\xe0\xaf\x80\x00\x00\x00\x00Y\xf5|p\x00\x00\x00\x00Z\xc0\x91\x80\x00\x00\x00\x00[\xd5^p\x00\x00\x00\x00\x5c\xa9\xae\x00\x00\x00\x00\x00]\xb5@p\x00\x00\x00\x00^\x89\x90\x00\x00\x00\x00\x00_\x95\x22p\x00\x00\x00\x00`ir\x00\x00\x00\x00\x00a~>\xf0\x00\x00\x00\x00bIT\x00\x00\x00\x00\x00c^ \xf0\x01\x02\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\xff\xff\xab\xfc\x00\x00\xff\xff\xab\xa0\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xb9\xb0\x01\x0cLMT\x00CST\x00EST\x00CDT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x87n\x14J\x02\x00\x00J\x02\x00\x00\x12\x00\x00\x00America/MetlakatlaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00\x08\x00\x00\x00\x1e\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x870\x1a\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x07\x8dC\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x09\xad\xbf \x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00V5\xe2\xa0\x00\x00\x00\x00V\xe5H0\x00\x00\x00\x00X\x1e\xff \x00\x00\x00\x00X\xc5*0\x00\x00\x00\x00Y\xfe\xe1 \x00\x00\x00\x00Z\xa5\x0c0\x00\x00\x00\x00[\xde\xc3 \x00\x00\x00\x00\x5cDF\xa0\x01\x02\x03\x04\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x06\x07\x06\x07\x06\x07\x02\x06\x00\x00\xd6&\x00\x00\xff\xff\x84\xa6\x00\x00\xff\xff\x8f\x80\x00\x04\xff\xff\x9d\x90\x01\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10\xff\xff\x81p\x00\x14\xff\xff\x8f\x80\x01\x19LMT\x00PST\x00PWT\x00PPT\x00PDT\x00AKST\x00AKDT\x00\x0aAKST9AKDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd5\x08\x89\x8c\x05\x03\x00\x00\x05\x03\x00\x00\x13\x00\x00\x00America/Mexico_CityTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\xff\xff\xff\xff\xc5\xde\xb0`\xff\xff\xff\xff\xc6\x974P\xff\xff\xff\xff\xc9U\xf1\xe0\xff\xff\xff\xff\xc9\xea\xddP\xff\xff\xff\xff\xcf\x02\xc6\xe0\xff\xff\xff\xff\xcf\xb7VP\xff\xff\xff\xff\xda\x99\x15\xe0\xff\xff\xff\xff\xdbv\x83\xd0\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xf5\x04\x80\x00\x00\x00\x00;\xb6\xc2\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00F\x0ff\x80\x00\x00\x00\x00G$3p\x00\x00\x00\x00G\xf8\x83\x00\x00\x00\x00\x00I\x04\x15p\x00\x00\x00\x00I\xd8e\x00\x00\x00\x00\x00J\xe3\xf7p\x00\x00\x00\x00K\xb8G\x00\x00\x00\x00\x00L\xcd\x13\xf0\x00\x00\x00\x00M\x98)\x00\x00\x00\x00\x00N\xac\xf5\xf0\x00\x00\x00\x00Ox\x0b\x00\x00\x00\x00\x00P\x8c\xd7\xf0\x00\x00\x00\x00Qa'\x80\x00\x00\x00\x00Rl\xb9\xf0\x00\x00\x00\x00SA\x09\x80\x00\x00\x00\x00TL\x9b\xf0\x00\x00\x00\x00U \xeb\x80\x00\x00\x00\x00V,}\xf0\x00\x00\x00\x00W\x00\xcd\x80\x00\x00\x00\x00X\x15\x9ap\x00\x00\x00\x00X\xe0\xaf\x80\x00\x00\x00\x00Y\xf5|p\x00\x00\x00\x00Z\xc0\x91\x80\x00\x00\x00\x00[\xd5^p\x00\x00\x00\x00\x5c\xa9\xae\x00\x00\x00\x00\x00]\xb5@p\x00\x00\x00\x00^\x89\x90\x00\x00\x00\x00\x00_\x95\x22p\x00\x00\x00\x00`ir\x00\x00\x00\x00\x00a~>\xf0\x00\x00\x00\x00bIT\x00\x00\x00\x00\x00c^ \xf0\x01\x02\x01\x03\x01\x02\x04\x02\x04\x02\x05\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\xff\xff\xa3\x0c\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x01\x14LMT\x00MST\x00CST\x00MDT\x00CDT\x00CWT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\xea\x94Y&\x02\x00\x00&\x02\x00\x00\x10\x00\x00\x00America/MiquelonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\x91\xdf\x17(\x00\x00\x00\x00\x13nc\xc0\x00\x00\x00\x00 u\xe4\xd0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22U\xc6\xd0\x00\x00\x00\x00#j\x93\xc0\x00\x00\x00\x00$5\xa8\xd0\x00\x00\x00\x00%Ju\xc0\x00\x00\x00\x00&\x15\x8a\xd0\x00\x00\x00\x00'*W\xc0\x00\x00\x00\x00'\xfe\xa7P\x00\x00\x00\x00)\x0a9\xc0\x00\x00\x00\x00)\xde\x89P\x00\x00\x00\x00*\xea\x1b\xc0\x00\x00\x00\x00+\xbekP\x00\x00\x00\x00,\xd38@\x00\x00\x00\x00-\x9eMP\x00\x00\x00\x00.\xb3\x1a@\x00\x00\x00\x00/~/P\x00\x00\x00\x000\x92\xfc@\x00\x00\x00\x001gK\xd0\x00\x00\x00\x002r\xde@\x00\x00\x00\x003G-\xd0\x00\x00\x00\x004R\xc0@\x00\x00\x00\x005'\x0f\xd0\x00\x00\x00\x0062\xa2@\x00\x00\x00\x007\x06\xf1\xd0\x00\x00\x00\x008\x1b\xbe\xc0\x00\x00\x00\x008\xe6\xd3\xd0\x00\x00\x00\x009\xfb\xa0\xc0\x00\x00\x00\x00:\xc6\xb5\xd0\x00\x00\x00\x00;\xdb\x82\xc0\x00\x00\x00\x00<\xaf\xd2P\x00\x00\x00\x00=\xbbd\xc0\x00\x00\x00\x00>\x8f\xb4P\x00\x00\x00\x00?\x9bF\xc0\x00\x00\x00\x00@o\x96P\x00\x00\x00\x00A\x84c@\x00\x00\x00\x00BOxP\x00\x00\x00\x00CdE@\x00\x00\x00\x00D/ZP\x00\x00\x00\x00ED'@\x00\x00\x00\x00E\xf3\x8c\xd0\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\xff\xff\xcbX\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x00\x08\xff\xff\xe3\xe0\x01\x0cLMT\x00AST\x00-03\x00-02\x00\x0a<-03>3<-02>,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xad\x8a\xf3O\xd5\x05\x00\x00\xd5\x05\x00\x00\x0f\x00\x00\x00America/MonctonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x92\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x1e\xed\xbc\xff\xff\xff\xff\x80\xf1\xb6P\xff\xff\xff\xff\x9e\xb8\x85`\xff\xff\xff\xff\x9f\xba\xddP\xff\xff\xff\xff\xbb<8\xd0\xff\xff\xff\xff\xbb\xb4#@\xff\xff\xff\xff\xbd\x1c\x1a\xd0\xff\xff\xff\xff\xbd\x94\x05@\xff\xff\xff\xff\xbe\xfb\xfc\xd0\xff\xff\xff\xff\xbfs\xe7@\xff\xff\xff\xff\xc0\xdb\xde\xd0\xff\xff\xff\xff\xc1S\xc9@\xff\xff\xff\xff\xc2\xbb\xc0\xd0\xff\xff\xff\xff\xc33\xab@\xff\xff\xff\xff\xc4\x9b\xa2\xd0\xff\xff\xff\xff\xc5\x13\x8d@\xff\xff\xff\xff\xc6p\xf8\xd0\xff\xff\xff\xff\xc7\x0d\xcd@\xff\xff\xff\xff\xc8H\xf1\xd0\xff\xff\xff\xff\xc8\xed\xaf@\xff\xff\xff\xff\xca\x16^\xd0\xff\xff\xff\xff\xca\xd6\xcb\xc0\xff\xff\xff\xff\xcb\x88\xe2`\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\xff\xff\xff\xff\xd3u\xd6\xe0\xff\xff\xff\xff\xd4@\xcf\xd0\xff\xff\xff\xff\xd5U\xb8\xe0\xff\xff\xff\xff\xd6 \xb1\xd0\xff\xff\xff\xff\xd75\x9a\xe0\xff\xff\xff\xff\xd8\x00\x93\xd0\xff\xff\xff\xff\xd9\x15|\xe0\xff\xff\xff\xff\xd9\xe0u\xd0\xff\xff\xff\xff\xda\xfe\x99`\xff\xff\xff\xff\xdb\xc0W\xd0\xff\xff\xff\xff\xdc\xde{`\xff\xff\xff\xff\xdd\xa9tP\xff\xff\xff\xff\xde\xbe]`\xff\xff\xff\xff\xdf\x89VP\xff\xff\xff\xff\xe0\x9e?`\xff\xff\xff\xff\xe1i8P\xff\xff\xff\xff\xe2~!`\xff\xff\xff\xff\xe3I\x1aP\xff\xff\xff\xff\xe4^\x03`\xff\xff\xff\xff\xe5(\xfcP\xff\xff\xff\xff\xe6G\x1f\xe0\xff\xff\xff\xff\xe7\x12\x18\xd0\xff\xff\xff\xff\xe8'\x01\xe0\xff\xff\xff\xff\xe9\x16\xe4\xd0\xff\xff\xff\xff\xea\x06\xe3\xe0\xff\xff\xff\xff\xea\xf6\xc6\xd0\xff\xff\xff\xff\xeb\xe6\xc5\xe0\xff\xff\xff\xff\xec\xd6\xa8\xd0\xff\xff\xff\xff\xed\xc6\xa7\xe0\xff\xff\xff\xff\xee\xbf\xc5P\xff\xff\xff\xff\xef\xaf\xc4`\xff\xff\xff\xff\xf0\x9f\xa7P\xff\xff\xff\xff\xf1\x8f\xa6`\xff\xff\xff\xff\xf2\x7f\x89P\xff\xff\xff\xff\xf3o\x88`\xff\xff\xff\xff\xf4_kP\xff\xff\xff\xff\xf5Oj`\xff\xff\xff\xff\xf6?MP\xff\xff\xff\xff\xf7/L`\xff\xff\xff\xff\xf8(i\xd0\xff\xff\xff\xff\xf9\x0f.`\xff\xff\xff\xff\xfa\x08K\xd0\xff\xff\xff\xff\xfa\xf8J\xe0\xff\xff\xff\xff\xfb\xe8-\xd0\xff\xff\xff\xff\xfc\xd8,\xe0\xff\xff\xff\xff\xfd\xc8\x0f\xd0\xff\xff\xff\xff\xfe\xb8\x0e\xe0\xff\xff\xff\xff\xff\xa7\xf1\xd0\x00\x00\x00\x00\x00\x97\xf0\xe0\x00\x00\x00\x00\x01\x87\xd3\xd0\x00\x00\x00\x00\x02w\xd2\xe0\x00\x00\x00\x00\x03p\xf0P\x00\x00\x00\x00\x04`\xef`\x00\x00\x00\x00\x05P\xd2P\x00\x00\x00\x00\x08 \xb3`\x00\x00\x00\x00\x09\x10\x96P\x00\x00\x00\x00\x0a\x00\x95`\x00\x00\x00\x00\x0a\xf0xP\x00\x00\x00\x00\x0b\xe0w`\x00\x00\x00\x00\x0c\xd9\x94\xd0\x00\x00\x00\x00\x0d\xc0Y`\x00\x00\x00\x00\x0e\xb9v\xd0\x00\x00\x00\x00\x0f\xa9u\xe0\x00\x00\x00\x00\x10\x99X\xd0\x00\x00\x00\x00\x11\x89W\xe0\x00\x00\x00\x00\x12y:\xd0\x00\x00\x00\x00\x13i9\xe0\x00\x00\x00\x00\x14Y\x1c\xd0\x00\x00\x00\x00\x15I\x1b\xe0\x00\x00\x00\x00\x168\xfe\xd0\x00\x00\x00\x00\x17(\xfd\xe0\x00\x00\x00\x00\x18\x22\x1bP\x00\x00\x00\x00\x19\x08\xdf\xe0\x00\x00\x00\x00\x1a\x01\xfdP\x00\x00\x00\x00\x1a\xf1\xfc`\x00\x00\x00\x00\x1b\xe1\xdfP\x00\x00\x00\x00\x1c\xd1\xde`\x00\x00\x00\x00\x1d\xc1\xc1P\x00\x00\x00\x00\x1e\xb1\xc0`\x00\x00\x00\x00\x1f\xa1\xa3P\x00\x00\x00\x00 u\xf2\xe0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22U\xd4\xe0\x00\x00\x00\x00#j\xa1\xd0\x00\x00\x00\x00$5\xb6\xe0\x00\x00\x00\x00%J\x83\xd0\x00\x00\x00\x00&\x15\x98\xe0\x00\x00\x00\x00'*e\xd0\x00\x00\x00\x00'\xfe\xb5`\x00\x00\x00\x00)\x0aG\xd0\x00\x00\x00\x00)\xde\x97`\x00\x00\x00\x00*\xea)\xd0\x00\x00\x00\x00+\xbe]|\x00\x00\x00\x00,\xd3*l\x00\x00\x00\x00-\x9e?|\x00\x00\x00\x00.\xb3\x0cl\x00\x00\x00\x00/~!|\x00\x00\x00\x000\x92\xeel\x00\x00\x00\x001g=\xfc\x00\x00\x00\x002r\xd0l\x00\x00\x00\x003G\x1f\xfc\x00\x00\x00\x004R\xb2l\x00\x00\x00\x005'\x01\xfc\x00\x00\x00\x0062\x94l\x00\x00\x00\x007\x06\xe3\xfc\x00\x00\x00\x008\x1b\xb0\xec\x00\x00\x00\x008\xe6\xc5\xfc\x00\x00\x00\x009\xfb\x92\xec\x00\x00\x00\x00:\xc6\xa7\xfc\x00\x00\x00\x00;\xdbt\xec\x00\x00\x00\x00<\xaf\xc4|\x00\x00\x00\x00=\xbbV\xec\x00\x00\x00\x00>\x8f\xa6|\x00\x00\x00\x00?\x9b8\xec\x00\x00\x00\x00@o\x88|\x00\x00\x00\x00A\x84Ul\x00\x00\x00\x00BOj|\x00\x00\x00\x00Cd7l\x00\x00\x00\x00D/L|\x00\x00\x00\x00ED\x19l\x00\x00\x00\x00E\x98\x87@\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x05\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x03\xff\xff\xc3D\x00\x00\xff\xff\xb9\xb0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xc7\xc0\x00\x0c\xff\xff\xd5\xd0\x01\x10\xff\xff\xd5\xd0\x01\x14LMT\x00EST\x00ADT\x00AST\x00AWT\x00APT\x00\x0aAST4ADT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L+\xe3u\x84\x02\x00\x00\x84\x02\x00\x00\x11\x00\x00\x00America/MonterreyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xa5\xb6\xda`\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xf5\x04\x80\x00\x00\x00\x00;\xb6\xc2\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00F\x0ff\x80\x00\x00\x00\x00G$3p\x00\x00\x00\x00G\xf8\x83\x00\x00\x00\x00\x00I\x04\x15p\x00\x00\x00\x00I\xd8e\x00\x00\x00\x00\x00J\xe3\xf7p\x00\x00\x00\x00K\xb8G\x00\x00\x00\x00\x00L\xcd\x13\xf0\x00\x00\x00\x00M\x98)\x00\x00\x00\x00\x00N\xac\xf5\xf0\x00\x00\x00\x00Ox\x0b\x00\x00\x00\x00\x00P\x8c\xd7\xf0\x00\x00\x00\x00Qa'\x80\x00\x00\x00\x00Rl\xb9\xf0\x00\x00\x00\x00SA\x09\x80\x00\x00\x00\x00TL\x9b\xf0\x00\x00\x00\x00U \xeb\x80\x00\x00\x00\x00V,}\xf0\x00\x00\x00\x00W\x00\xcd\x80\x00\x00\x00\x00X\x15\x9ap\x00\x00\x00\x00X\xe0\xaf\x80\x00\x00\x00\x00Y\xf5|p\x00\x00\x00\x00Z\xc0\x91\x80\x00\x00\x00\x00[\xd5^p\x00\x00\x00\x00\x5c\xa9\xae\x00\x00\x00\x00\x00]\xb5@p\x00\x00\x00\x00^\x89\x90\x00\x00\x00\x00\x00_\x95\x22p\x00\x00\x00\x00`ir\x00\x00\x00\x00\x00a~>\xf0\x00\x00\x00\x00bIT\x00\x00\x00\x00\x00c^ \xf0\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xa1\xf4\x00\x00\xff\xff\xab\xa0\x00\x04\xff\xff\xb9\xb0\x01\x08LMT\x00CST\x00CDT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\x98\x00\x08\xc9\x03\x00\x00\xc9\x03\x00\x00\x12\x00\x00\x00America/MontevideoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x00\x00\x00\x09\x00\x00\x00&\xff\xff\xff\xff\x8c4\xe53\xff\xff\xff\xff\xa2\x92\x87\xb3\xff\xff\xff\xff\xa8\xff\xdb@\xff\xff\xff\xff\xa9\xf1\x0f\xb0\xff\xff\xff\xff\xaa\xe2Y8\xff\xff\xff\xff\xab\xd2C0\xff\xff\xff\xff\xac\xc3\x8c\xb8\xff\xff\xff\xff\xad\xb3v\xb0\xff\xff\xff\xff\xbb\xf4\xb5\xb8\xff\xff\xff\xff\xbc\xbf\xb5\xb0\xff\xff\xff\xff\xbd\xd4\x97\xb8\xff\xff\xff\xff\xbe\x9f\x97\xb0\xff\xff\xff\xff\xbf\xb4y\xb8\xff\xff\xff\xff\xc0\x7fy\xb0\xff\xff\xff\xff\xc1\x94[\xb8\xff\xff\xff\xff\xc2_[\xb0\xff\xff\xff\xff\xc3}x8\xff\xff\xff\xff\xc4?=\xb0\xff\xff\xff\xff\xc5]Z8\xff\xff\xff\xff\xc6\x1f\x1f\xb0\xff\xff\xff\xff\xc7\x18R8\xff\xff\xff\xff\xc8\x08<0\xff\xff\xff\xff\xc9\x1d\x1e8\xff\xff\xff\xff\xc9\xe8\x1e0\xff\xff\xff\xff\xca\x8b\x9f8\xff\xff\xff\xff\xcd\x1e\xc60\xff\xff\xff\xff\xcd\x95f(\xff\xff\xff\xff\xec\x0b\x85\xb0\xff\xff\xff\xff\xec\xf25(\xff\xff\xff\xff\xedEJ\xb0\xff\xff\xff\xff\xed\x85\xd6 \xff\xff\xff\xff\xf7\x13r\xb0\xff\xff\xff\xff\xf7\xfa\x1b \xff\xff\xff\xff\xfc\xfe>0\xff\xff\xff\xff\xfd\xf6\x11(\x00\x00\x00\x00\x00\x96u0\x00\x00\x00\x00\x00\xd8R \x00\x00\x00\x00\x04W\x8a\xb0\x00\x00\x00\x00\x04\xc6:\xa0\x00\x00\x00\x00\x07\x96\x1b\xb0\x00\x00\x00\x00\x07\xdf\xda\x98\x00\x00\x00\x00\x08\xc6\x9f(\x00\x00\x00\x00\x09ZN0\x00\x00\x00\x00\x09\xdbs \x00\x00\x00\x00\x0d\x1a\x120\x00\x00\x00\x00\x0d\x7f\x87\xa0\x00\x00\x00\x00\x0e\xe7\x7f0\x00\x00\x00\x00\x0f_i\xa0\x00\x00\x00\x00\x10\xd9\xd60\x00\x00\x00\x00\x11?K\xa0\x00\x00\x00\x00\x11\x89-\xb0\x00\x00\x00\x00\x131\xa2\xa0\x00\x00\x00\x00!\xc3T0\x00\x00\x00\x00\x22'x \x00\x00\x00\x00#\xa1\xe4\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%Jg\xb0\x00\x00\x00\x00%\xe7< \x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x0a+\xb0\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x90\x1c\xa0\x00\x00\x00\x00AL\xf60\x00\x00\x00\x00BF/\xc0\x00\x00\x00\x00CH\xa3\xd0\x00\x00\x00\x00D\x13\x9c\xc0\x00\x00\x00\x00E\x1fKP\x00\x00\x00\x00E\xf3~\xc0\x00\x00\x00\x00G\x08g\xd0\x00\x00\x00\x00G\xd3`\xc0\x00\x00\x00\x00H\xe8I\xd0\x00\x00\x00\x00I\xb3B\xc0\x00\x00\x00\x00J\xc8+\xd0\x00\x00\x00\x00K\x9c_@\x00\x00\x00\x00L\xa8\x0d\xd0\x00\x00\x00\x00M|A@\x00\x00\x00\x00N\x87\xef\xd0\x00\x00\x00\x00O\x5c#@\x00\x00\x00\x00Pq\x0cP\x00\x00\x00\x00Q<\x05@\x00\x00\x00\x00RP\xeeP\x00\x00\x00\x00S\x1b\xe7@\x00\x00\x00\x00T0\xd0P\x00\x00\x00\x00T\xfb\xc9@\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x06\x05\x06\x05\x07\x05\x07\x05\x06\x05\x07\x05\x07\x05\x08\x06\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\xff\xff\xcbM\x00\x00\xff\xff\xcbM\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xce\xc8\x00\x0c\xff\xff\xd5\xd0\x01\x12\xff\xff\xd5\xd0\x00\x12\xff\xff\xdc\xd8\x01\x16\xff\xff\xe3\xe0\x01\x1c\xff\xff\xea\xe8\x01 LMT\x00MMT\x00-04\x00-0330\x00-03\x00-0230\x00-02\x00-0130\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x10\x00\x00\x00America/MontrealTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffr\xeex\xec\xff\xff\xff\xff\x9e\xb8\x93p\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x87.\xc8\xff\xff\xff\xff\xa1\x9a\xb1@\xff\xff\xff\xff\xa2\x94\x06\xf0\xff\xff\xff\xff\xa3U\xa9@\xff\xff\xff\xff\xa4\x86]\xf0\xff\xff\xff\xff\xa5(x`\xff\xff\xff\xff\xa6f?\xf0\xff\xff\xff\xff\xa7\x0cN\xe0\xff\xff\xff\xff\xa8F!\xf0\xff\xff\xff\xff\xa8\xec0\xe0\xff\xff\xff\xff\xaa\x1c\xc9p\xff\xff\xff\xff\xaa\xd5M`\xff\xff\xff\xff\xab\xfc\xabp\xff\xff\xff\xff\xac\xb5/`\xff\xff\xff\xff\xad\xdc\x8dp\xff\xff\xff\xff\xae\x95\x11`\xff\xff\xff\xff\xaf\xbcop\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xda3\x92`\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdc\x13t`\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5)\x0a`\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe7\x12&\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xb5\x94\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x12\x00\x00\x00America/MontserratTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0e\x00\x00\x00America/NassauTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffr\xeex\xec\xff\xff\xff\xff\x9e\xb8\x93p\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x87.\xc8\xff\xff\xff\xff\xa1\x9a\xb1@\xff\xff\xff\xff\xa2\x94\x06\xf0\xff\xff\xff\xff\xa3U\xa9@\xff\xff\xff\xff\xa4\x86]\xf0\xff\xff\xff\xff\xa5(x`\xff\xff\xff\xff\xa6f?\xf0\xff\xff\xff\xff\xa7\x0cN\xe0\xff\xff\xff\xff\xa8F!\xf0\xff\xff\xff\xff\xa8\xec0\xe0\xff\xff\xff\xff\xaa\x1c\xc9p\xff\xff\xff\xff\xaa\xd5M`\xff\xff\xff\xff\xab\xfc\xabp\xff\xff\xff\xff\xac\xb5/`\xff\xff\xff\xff\xad\xdc\x8dp\xff\xff\xff\xff\xae\x95\x11`\xff\xff\xff\xff\xaf\xbcop\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xda3\x92`\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdc\x13t`\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5)\x0a`\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe7\x12&\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xb5\x94\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x9aG\xc8\xd0\x06\x00\x00\xd0\x06\x00\x00\x10\x00\x00\x00America/New_YorkTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^\x03\xf0\x90\xff\xff\xff\xff\x9e\xa6\x1ep\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x86\x00p\xff\xff\xff\xff\xa1\x9a\xcd`\xff\xff\xff\xff\xa2e\xe2p\xff\xff\xff\xff\xa3\x83\xe9\xe0\xff\xff\xff\xff\xa4j\xaep\xff\xff\xff\xff\xa55\xa7`\xff\xff\xff\xff\xa6S\xca\xf0\xff\xff\xff\xff\xa7\x15\x89`\xff\xff\xff\xff\xa83\xac\xf0\xff\xff\xff\xff\xa8\xfe\xa5\xe0\xff\xff\xff\xff\xaa\x13\x8e\xf0\xff\xff\xff\xff\xaa\xde\x87\xe0\xff\xff\xff\xff\xab\xf3p\xf0\xff\xff\xff\xff\xac\xbei\xe0\xff\xff\xff\xff\xad\xd3R\xf0\xff\xff\xff\xff\xae\x9eK\xe0\xff\xff\xff\xff\xaf\xb34\xf0\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9\x1b\xd9p\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xc6\xb4`\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xc8\xf8W`\xff\xff\xff\xff\xca\x0d@p\xff\xff\xff\xff\xca\xd89`\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xd9\xe0\x83\xe0\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdb\xc0e\xe0\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5W.\xe0\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe77\x10\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xba\x9e\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0f\x00\x00\x00America/NipigonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffr\xeex\xec\xff\xff\xff\xff\x9e\xb8\x93p\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x87.\xc8\xff\xff\xff\xff\xa1\x9a\xb1@\xff\xff\xff\xff\xa2\x94\x06\xf0\xff\xff\xff\xff\xa3U\xa9@\xff\xff\xff\xff\xa4\x86]\xf0\xff\xff\xff\xff\xa5(x`\xff\xff\xff\xff\xa6f?\xf0\xff\xff\xff\xff\xa7\x0cN\xe0\xff\xff\xff\xff\xa8F!\xf0\xff\xff\xff\xff\xa8\xec0\xe0\xff\xff\xff\xff\xaa\x1c\xc9p\xff\xff\xff\xff\xaa\xd5M`\xff\xff\xff\xff\xab\xfc\xabp\xff\xff\xff\xff\xac\xb5/`\xff\xff\xff\xff\xad\xdc\x8dp\xff\xff\xff\xff\xae\x95\x11`\xff\xff\xff\xff\xaf\xbcop\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xda3\x92`\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdc\x13t`\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5)\x0a`\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe7\x12&\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xb5\x94\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\xab\xd5\xf9\xcf\x03\x00\x00\xcf\x03\x00\x00\x0c\x00\x00\x00America/NomeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x0a\x00\x00\x00&\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x87O\xd2\xff\xff\xff\xff\xcb\x89D\xd0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aP@\xff\xff\xff\xff\xfa\xd2U\xb0\xff\xff\xff\xff\xfe\xb8qP\xff\xff\xff\xff\xff\xa8T@\x00\x00\x00\x00\x00\x98SP\x00\x00\x00\x00\x01\x886@\x00\x00\x00\x00\x02x5P\x00\x00\x00\x00\x03qR\xc0\x00\x00\x00\x00\x04aQ\xd0\x00\x00\x00\x00\x05Q4\xc0\x00\x00\x00\x00\x06A3\xd0\x00\x00\x00\x00\x071\x16\xc0\x00\x00\x00\x00\x07\x8dm\xd0\x00\x00\x00\x00\x09\x10\xf8\xc0\x00\x00\x00\x00\x09\xad\xe9P\x00\x00\x00\x00\x0a\xf0\xda\xc0\x00\x00\x00\x00\x0b\xe0\xd9\xd0\x00\x00\x00\x00\x0c\xd9\xf7@\x00\x00\x00\x00\x0d\xc0\xbb\xd0\x00\x00\x00\x00\x0e\xb9\xd9@\x00\x00\x00\x00\x0f\xa9\xd8P\x00\x00\x00\x00\x10\x99\xbb@\x00\x00\x00\x00\x11\x89\xbaP\x00\x00\x00\x00\x12y\x9d@\x00\x00\x00\x00\x13i\x9cP\x00\x00\x00\x00\x14Y\x7f@\x00\x00\x00\x00\x15I~P\x00\x00\x00\x00\x169a@\x00\x00\x00\x00\x17)`P\x00\x00\x00\x00\x18\x22}\xc0\x00\x00\x00\x00\x19\x09BP\x00\x00\x00\x00\x1a\x02_\xc0\x00\x00\x00\x00\x1a+\x14\x10\x00\x00\x00\x00\x1a\xf2B\xb0\x00\x00\x00\x00\x1b\xe2%\xa0\x00\x00\x00\x00\x1c\xd2$\xb0\x00\x00\x00\x00\x1d\xc2\x07\xa0\x00\x00\x00\x00\x1e\xb2\x06\xb0\x00\x00\x00\x00\x1f\xa1\xe9\xa0\x00\x00\x00\x00 v90\x00\x00\x00\x00!\x81\xcb\xa0\x00\x00\x00\x00\x22V\x1b0\x00\x00\x00\x00#j\xe8 \x00\x00\x00\x00$5\xfd0\x00\x00\x00\x00%J\xca \x00\x00\x00\x00&\x15\xdf0\x00\x00\x00\x00'*\xac \x00\x00\x00\x00'\xfe\xfb\xb0\x00\x00\x00\x00)\x0a\x8e \x00\x00\x00\x00)\xde\xdd\xb0\x00\x00\x00\x00*\xeap \x00\x00\x00\x00+\xbe\xbf\xb0\x00\x00\x00\x00,\xd3\x8c\xa0\x00\x00\x00\x00-\x9e\xa1\xb0\x00\x00\x00\x00.\xb3n\xa0\x00\x00\x00\x00/~\x83\xb0\x00\x00\x00\x000\x93P\xa0\x00\x00\x00\x001g\xa00\x00\x00\x00\x002s2\xa0\x00\x00\x00\x003G\x820\x00\x00\x00\x004S\x14\xa0\x00\x00\x00\x005'd0\x00\x00\x00\x0062\xf6\xa0\x00\x00\x00\x007\x07F0\x00\x00\x00\x008\x1c\x13 \x00\x00\x00\x008\xe7(0\x00\x00\x00\x009\xfb\xf5 \x00\x00\x00\x00:\xc7\x0a0\x00\x00\x00\x00;\xdb\xd7 \x00\x00\x00\x00<\xb0&\xb0\x00\x00\x00\x00=\xbb\xb9 \x00\x00\x00\x00>\x90\x08\xb0\x00\x00\x00\x00?\x9b\x9b \x00\x00\x00\x00@o\xea\xb0\x00\x00\x00\x00A\x84\xb7\xa0\x00\x00\x00\x00BO\xcc\xb0\x00\x00\x00\x00Cd\x99\xa0\x00\x00\x00\x00D/\xae\xb0\x00\x00\x00\x00ED{\xa0\x00\x00\x00\x00E\xf3\xe10\x01\x02\x03\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x07\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x00\x00\xb6n\x00\x00\xff\xffd\xee\x00\x00\xff\xffeP\x00\x04\xff\xffs`\x01\x08\xff\xffs`\x01\x0c\xff\xffeP\x00\x10\xff\xffs`\x01\x14\xff\xff\x81p\x00\x18\xff\xff\x8f\x80\x01\x1c\xff\xff\x81p\x00!LMT\x00NST\x00NWT\x00NPT\x00BST\x00BDT\x00YST\x00AKDT\x00AKST\x00\x0aAKST9AKDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7-2f\xe4\x01\x00\x00\xe4\x01\x00\x00\x0f\x00\x00\x00America/NoronhaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaaed\xff\xff\xff\xff\xb8\x0f;\xd0\xff\xff\xff\xff\xb8\xfd2\x90\xff\xff\xff\xff\xb9\xf1& \xff\xff\xff\xff\xba\xdef\x10\xff\xff\xff\xff\xda8\xa0 \xff\xff\xff\xff\xda\xeb\xec \xff\xff\xff\xff\xdc\x19\xd3\xa0\xff\xff\xff\xff\xdc\xb9K\x10\xff\xff\xff\xff\xdd\xfb\x07 \xff\xff\xff\xff\xde\x9b\xd0\x10\xff\xff\xff\xff\xdf\xdd\x8c \xff\xff\xff\xff\xe0T%\x10\xff\xff\xff\xff\xf4\x97\xf1\xa0\xff\xff\xff\xff\xf5\x05P\x10\xff\xff\xff\xff\xf6\xc0V \xff\xff\xff\xff\xf7\x0e\x10\x90\xff\xff\xff\xff\xf8Q\x1e \xff\xff\xff\xff\xf8\xc7\xb7\x10\xff\xff\xff\xff\xfa\x0a\xc4\xa0\xff\xff\xff\xff\xfa\xa8\xea\x90\xff\xff\xff\xff\xfb\xeb\xf8 \xff\xff\xff\xff\xfc\x8bo\x90\x00\x00\x00\x00\x1d\xc9\x80 \x00\x00\x00\x00\x1ex\xc9\x90\x00\x00\x00\x00\x1f\xa0'\xa0\x00\x00\x00\x00 3\xc1\x90\x00\x00\x00\x00!\x81[ \x00\x00\x00\x00\x22\x0b\xba\x90\x00\x00\x00\x00#X\x02\xa0\x00\x00\x00\x00#\xe2b\x10\x00\x00\x00\x00%7\xe4\xa0\x00\x00\x00\x00%\xd4\xb9\x10\x00\x00\x00\x007\xf6\xb8\xa0\x00\x00\x00\x008\xb8w\x10\x00\x00\x00\x009\xdf\xd5 \x00\x00\x00\x009\xe9\x01\x90\x00\x00\x00\x00;\xc8\xf1\xa0\x00\x00\x00\x002\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7.\xb6*\x13\x04\x00\x00\x13\x04\x00\x00\x1b\x00\x00\x00America/North_Dakota/BeulahTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8W\x10\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb89\x10\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x1b\x10\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xfd\x10\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x07\x8d5\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x09\xad\xb1\x10\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x00\x00\x00\x00G-|\x00\x00\x00\x00\x00G\xd3\xa7\x10\x00\x00\x00\x00I\x0d^\x00\x00\x00\x00\x00I\xb3\x89\x10\x00\x00\x00\x00J\xed@\x00\x00\x00\x00\x00K\x9c\xa5\x90\x00\x00\x00\x00L\xd6\x5c\x80\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x05\xff\xff\xa0\x95\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\xab\xa0\x00\x14LMT\x00MDT\x00MST\x00MWT\x00MPT\x00CST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\xeam\xef\xde\x03\x00\x00\xde\x03\x00\x00\x1b\x00\x00\x00America/North_Dakota/CenterTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8W\x10\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb89\x10\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x1b\x10\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xfd\x10\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x07\x8d5\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x09\xad\xb1\x10\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\x95\x80\x00\x00\x00\x00,\xd3bp\x00\x00\x00\x00-\x9ew\x80\x00\x00\x00\x00.\xb3Dp\x00\x00\x00\x00/~Y\x80\x00\x00\x00\x000\x93&p\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xc6\xe0\x00\x00\x00\x00\x00;\xdb\xac\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\xff\xff\xa1\x08\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\xb9\xb0\x01\x14\xff\xff\xab\xa0\x00\x18LMT\x00MDT\x00MST\x00MWT\x00MPT\x00CDT\x00CST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x1b\x8b(\xde\x03\x00\x00\xde\x03\x00\x00\x1e\x00\x00\x00America/North_Dakota/New_SalemTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8W\x10\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb89\x10\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x1b\x10\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xfd\x10\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x07\x8d5\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x09\xad\xb1\x10\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x06\x05\x06\x05\x06\x05\x06\x05\xff\xff\xa0\xed\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\xb9\xb0\x01\x14\xff\xff\xab\xa0\x00\x18LMT\x00MDT\x00MST\x00MWT\x00MPT\x00CDT\x00CST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xf9v\x14\xc5\x03\x00\x00\xc5\x03\x00\x00\x0c\x00\x00\x00America/NuukTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\x9b\x80h\x00\x00\x00\x00\x00\x13M|P\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x86A\x90\x00\x00\x00\x00?\x9b\x1c\x90\x00\x00\x00\x00@f#\x90\x00\x00\x00\x00A\x849\x10\x00\x00\x00\x00BF\x05\x90\x00\x00\x00\x00Cd\x1b\x10\x00\x00\x00\x00D%\xe7\x90\x00\x00\x00\x00EC\xfd\x10\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8e\x8c\x10\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S7l\x90\x00\x00\x00\x00TLG\x90\x00\x00\x00\x00U\x17N\x90\x00\x00\x00\x00V,)\x90\x00\x00\x00\x00V\xf70\x90\x00\x00\x00\x00X\x15F\x10\x00\x00\x00\x00X\xd7\x12\x90\x00\x00\x00\x00Y\xf5(\x10\x00\x00\x00\x00Z\xb6\xf4\x90\x00\x00\x00\x00[\xd5\x0a\x10\x00\x00\x00\x00\x5c\xa0\x11\x10\x00\x00\x00\x00]\xb4\xec\x10\x00\x00\x00\x00^\x7f\xf3\x10\x00\x00\x00\x00_\x94\xce\x10\x00\x00\x00\x00`_\xd5\x10\x00\x00\x00\x00a}\xea\x90\x00\x00\x00\x00b?\xb7\x10\x00\x00\x00\x00c]\xcc\x90\x00\x00\x00\x00d\x1f\x99\x10\x00\x00\x00\x00e=\xae\x90\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x03\xff\xff\xcf\x80\x00\x00\xff\xff\xd5\xd0\x00\x04\xff\xff\xe3\xe0\x01\x08\xff\xff\xe3\xe0\x00\x08LMT\x00-03\x00-02\x00\x0a<-02>2<-01>,M3.5.0/-1,M10.5.0/0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1w\xb9\xca\xce\x02\x00\x00\xce\x02\x00\x00\x0f\x00\x00\x00America/OjinagaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xf5\x12\x90\x00\x00\x00\x00;\xb6\xd1\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00F\x0ft\x90\x00\x00\x00\x00G$A\x80\x00\x00\x00\x00G\xf8\x91\x10\x00\x00\x00\x00I\x04#\x80\x00\x00\x00\x00I\xd8s\x10\x00\x00\x00\x00J\xe4\x05\x80\x00\x00\x00\x00K\x9c\xa5\x90\x00\x00\x00\x00L\xd6\x5c\x80\x00\x00\x00\x00M|\x87\x90\x00\x00\x00\x00N\xb6>\x80\x00\x00\x00\x00O\x5ci\x90\x00\x00\x00\x00P\x96 \x80\x00\x00\x00\x00Q\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x04\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x06\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00\x00\x00\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10\xff\xff\xab\xa0\x00\x14\xff\xff\xb9\xb0\x01\x18-00\x00EPT\x00EST\x00EDT\x00EWT\x00CST\x00CDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xf9\x1d\xc9\xbb\x00\x00\x00\xbb\x00\x00\x00\x12\x00\x00\x00America/ParamariboTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x12\xff\xff\xff\xff\x91\x05\x8e\xb8\xff\xff\xff\xff\xbe*K\xc4\xff\xff\xff\xff\xd2b,\xb4\x00\x00\x00\x00\x1b\xbe1\xb8\x01\x02\x03\x04\xff\xff\xccH\x00\x00\xff\xff\xcc<\x00\x04\xff\xff\xccL\x00\x04\xff\xff\xce\xc8\x00\x08\xff\xff\xd5\xd0\x00\x0eLMT\x00PMT\x00-0330\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\xb8\xab\x9b\xf0\x00\x00\x00\xf0\x00\x00\x00\x0f\x00\x00\x00America/PhoenixTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xcf\x17\xdf\x1c\xff\xff\xff\xff\xcf\x8f\xe5\xac\xff\xff\xff\xff\xd0\x81\x1a\x1c\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\x02\x01\x02\x01\x02\x03\x02\x03\x02\x01\x02\xff\xff\x96\xee\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0cLMT\x00MDT\x00MST\x00MWT\x00\x0aMST7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4T\xbd\xeb5\x02\x00\x005\x02\x00\x00\x16\x00\x00\x00America/Port-au-PrinceTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xffi\x87\x1fP\xff\xff\xff\xff\x9cnq\xfc\x00\x00\x00\x00\x19\x1bF\xd0\x00\x00\x00\x00\x1a\x01\xef@\x00\x00\x00\x00\x1a\xf1\xeeP\x00\x00\x00\x00\x1b\xe1\xd1@\x00\x00\x00\x00\x1c\xd1\xd0P\x00\x00\x00\x00\x1d\xc1\xb3@\x00\x00\x00\x00\x1e\xb1\xb2P\x00\x00\x00\x00\x1f\xa1\x95@\x00\x00\x00\x00 \x91\x94P\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22U\xd4\xe0\x00\x00\x00\x00#j\xaf\xe0\x00\x00\x00\x00$5\xb6\xe0\x00\x00\x00\x00%J\x91\xe0\x00\x00\x00\x00&\x15\x98\xe0\x00\x00\x00\x00'*s\xe0\x00\x00\x00\x00'\xfe\xb5`\x00\x00\x00\x00)\x0aU\xe0\x00\x00\x00\x00)\xde\x97`\x00\x00\x00\x00*\xea7\xe0\x00\x00\x00\x00+\xbey`\x00\x00\x00\x00,\xd3T`\x00\x00\x00\x00-\x9e[`\x00\x00\x00\x00.\xb36`\x00\x00\x00\x00/~=`\x00\x00\x00\x000\x93\x18`\x00\x00\x00\x001gY\xe0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003G;\xe0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x00BOxP\x00\x00\x00\x00CdE@\x00\x00\x00\x00D/ZP\x00\x00\x00\x00ED'@\x00\x00\x00\x00O\x5cMp\x00\x00\x00\x00P\x96\x04`\x00\x00\x00\x00Q5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\x81-\xa9\x8a\x01\x00\x00\x8a\x01\x00\x00\x13\x00\x00\x00America/Porto_VelhoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa\x82\xe8\xff\xff\xff\xff\xb8\x0fW\xf0\xff\xff\xff\xff\xb8\xfdN\xb0\xff\xff\xff\xff\xb9\xf1B@\xff\xff\xff\xff\xba\xde\x820\xff\xff\xff\xff\xda8\xbc@\xff\xff\xff\xff\xda\xec\x08@\xff\xff\xff\xff\xdc\x19\xef\xc0\xff\xff\xff\xff\xdc\xb9g0\xff\xff\xff\xff\xdd\xfb#@\xff\xff\xff\xff\xde\x9b\xec0\xff\xff\xff\xff\xdf\xdd\xa8@\xff\xff\xff\xff\xe0TA0\xff\xff\xff\xff\xf4\x98\x0d\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf6\xc0r@\xff\xff\xff\xff\xf7\x0e,\xb0\xff\xff\xff\xff\xf8Q:@\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xfa\x0a\xe0\xc0\xff\xff\xff\xff\xfa\xa9\x06\xb0\xff\xff\xff\xff\xfb\xec\x14@\xff\xff\xff\xff\xfc\x8b\x8b\xb0\x00\x00\x00\x00\x1d\xc9\x9c@\x00\x00\x00\x00\x1ex\xe5\xb0\x00\x00\x00\x00\x1f\xa0C\xc0\x00\x00\x00\x00 3\xdd\xb0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22\x0b\xd6\xb0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xc4\x18\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08LMT\x00-03\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x13\x00\x00\x00America/Puerto_RicoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x13\x9b\xb1\xc2\x04\x00\x00\xc2\x04\x00\x00\x14\x00\x00\x00America/Punta_ArenasTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u\x00\x00\x00\x07\x00\x00\x00\x14\xff\xff\xff\xffi\x87\x1d\xfc\xff\xff\xff\xff\x8f0GE\xff\xff\xff\xff\x9b\x5c\xe5P\xff\xff\xff\xff\x9f|\xe2\xc5\xff\xff\xff\xff\xa1\x00q\xc0\xff\xff\xff\xff\xb0^w\xc5\xff\xff\xff\xff\xb1w=@\xff\xff\xff\xff\xb2A\x00\xd0\xff\xff\xff\xff\xb3Xp\xc0\xff\xff\xff\xff\xb4\x224P\xff\xff\xff\xff\xb59\xa4@\xff\xff\xff\xff\xb6\x03g\xd0\xff\xff\xff\xff\xb7\x1a\xd7\xc0\xff\xff\xff\xff\xb7\xe4\x9bP\xff\xff\xff\xff\xb8\xfd\x5c\xc0\xff\xff\xff\xff\xb9\xc7 P\xff\xff\xff\xff\xcc\x1cn@\xff\xff\xff\xff\xccl\xe7\xd0\xff\xff\xff\xff\xd4\x17\xe3@\xff\xff\xff\xff\xd53U\xc0\xff\xff\xff\xff\xd5v\x92@\xff\xff\xff\xff\xfd\xd1<@\xff\xff\xff\xff\xfe\x92\xfa\xb0\xff\xff\xff\xff\xff\xcc\xcd\xc0\x00\x00\x00\x00\x00r\xdc\xb0\x00\x00\x00\x00\x01uP\xc0\x00\x00\x00\x00\x02@I\xb0\x00\x00\x00\x00\x03U2\xc0\x00\x00\x00\x00\x04 +\xb0\x00\x00\x00\x00\x05>O@\x00\x00\x00\x00\x06\x00\x0d\xb0\x00\x00\x00\x00\x07\x0b\xbc@\x00\x00\x00\x00\x07\xdf\xef\xb0\x00\x00\x00\x00\x08\xfe\x13@\x00\x00\x00\x00\x09\xbf\xd1\xb0\x00\x00\x00\x00\x0a\xdd\xf5@\x00\x00\x00\x00\x0b\xa8\xee0\x00\x00\x00\x00\x0c\xbd\xd7@\x00\x00\x00\x00\x0d\x88\xd00\x00\x00\x00\x00\x0e\x9d\xb9@\x00\x00\x00\x00\x0fh\xb20\x00\x00\x00\x00\x10\x86\xd5\xc0\x00\x00\x00\x00\x11H\x940\x00\x00\x00\x00\x12f\xb7\xc0\x00\x00\x00\x00\x13(v0\x00\x00\x00\x00\x14F\x99\xc0\x00\x00\x00\x00\x15\x11\x92\xb0\x00\x00\x00\x00\x16&{\xc0\x00\x00\x00\x00\x16\xf1t\xb0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x18\xd1V\xb0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xb18\xb0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\x91\x1a\xb0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ep\xfc\xb0\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 \x7f\x030\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x229\xfb0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$\x19\xdd0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xf9\xbf0\x00\x00\x00\x00&\xf2\xf8\xc0\x00\x00\x00\x00'\xd9\xa10\x00\x00\x00\x00(\xf7\xc4\xc0\x00\x00\x00\x00)\xc2\xbd\xb0\x00\x00\x00\x00*\xd7\xa6\xc0\x00\x00\x00\x00+\xa2\x9f\xb0\x00\x00\x00\x00,\xb7\x88\xc0\x00\x00\x00\x00-\x82\x81\xb0\x00\x00\x00\x00.\x97j\xc0\x00\x00\x00\x00/bc\xb0\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001BE\xb0\x00\x00\x00\x002`i@\x00\x00\x00\x003=\xd70\x00\x00\x00\x004@K@\x00\x00\x00\x005\x0bD0\x00\x00\x00\x006\x0d\xb8@\x00\x00\x00\x007\x06\xd5\xb0\x00\x00\x00\x008\x00\x0f@\x00\x00\x00\x008\xcb\x080\x00\x00\x00\x009\xe9+\xc0\x00\x00\x00\x00:\xaa\xea0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00<\x8a\xcc0\x00\x00\x00\x00=\xa8\xef\xc0\x00\x00\x00\x00>j\xae0\x00\x00\x00\x00?\x88\xd1\xc0\x00\x00\x00\x00@S\xca\xb0\x00\x00\x00\x00Ah\xb3\xc0\x00\x00\x00\x00B3\xac\xb0\x00\x00\x00\x00CH\x95\xc0\x00\x00\x00\x00D\x13\x8e\xb0\x00\x00\x00\x00E1\xb2@\x00\x00\x00\x00E\xf3p\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xef\x020\x00\x00\x00\x00H\xf1v@\x00\x00\x00\x00I\xbco0\x00\x00\x00\x00J\xd1X@\x00\x00\x00\x00K\xb8\x00\xb0\x00\x00\x00\x00L\xb1:@\x00\x00\x00\x00M\xc6\x070\x00\x00\x00\x00NP\x82\xc0\x00\x00\x00\x00O\x9c\xae\xb0\x00\x00\x00\x00PB\xd9\xc0\x00\x00\x00\x00Q|\x90\xb0\x00\x00\x00\x00R+\xf6@\x00\x00\x00\x00S\x5cr\xb0\x00\x00\x00\x00T\x0b\xd8@\x00\x00\x00\x00W7\xe60\x00\x00\x00\x00W\xaf\xec\xc0\x00\x00\x00\x00XC\x86\xb0\x01\x02\x01\x03\x01\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x03\x02\x03\x04\x02\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x06\xff\xff\xbd\x84\x00\x00\xff\xff\xbd\xbb\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x00\x0c\xff\xff\xc7\xc0\x01\x0c\xff\xff\xd5\xd0\x01\x10\xff\xff\xd5\xd0\x00\x10LMT\x00SMT\x00-05\x00-04\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?_p\x99\x0e\x05\x00\x00\x0e\x05\x00\x00\x13\x00\x00\x00America/Rainy_RiverTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffd\xe4\xb0\x94\xff\xff\xff\xff\x9b\x01\xfb\xe0\xff\xff\xff\xff\x9b\xc3\xbaP\xff\xff\xff\xff\x9e\xb8\xa1\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xc2\xa0;\x80\xff\xff\xff\xff\xc3O\x84\xf0\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3\x88h\x00\xff\xff\xff\xff\xd4S`\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xdb\x00\x07\x00\xff\xff\xff\xff\xdb\xc8\x5c\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe7\x124\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xd6\xc4\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\x91\xbc\xf0\xff\xff\xff\xff\xf3o\xa4\x80\xff\xff\xff\xff\xf41b\xf0\xff\xff\xff\xff\xf9\x0fJ\x80\xff\xff\xff\xff\xfa\x08v\x00\xff\xff\xff\xff\xfa\xf8g\x00\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x0d\x00\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xef\x00\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x08 \xcf\x80\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x0a\x00\xb1\x80\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xb3\x80\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\x95\x80\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9ew\x80\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~Y\x80\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xe0\x00\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xa4\xec\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10LMT\x00CDT\x00CST\x00CWT\x00CPT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xdfH\x0d'\x03\x00\x00'\x03\x00\x00\x14\x00\x00\x00America/Rankin_InletTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\xe7\x8cn\x00\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xeep\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x08 \xcf\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x0a\x00\xb1\x80\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99t\xf0\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12yV\xf0\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14Y8\xf0\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169\x1a\xf0\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x227p\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02\x19p\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe1\xfbp\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xddp\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xbfp\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xa1p\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\x9f\xf0\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x81\xf0\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ac\xf0\x00\x00\x00\x00)\xde\xb3\x80\x00\x00\x00\x00*\xeaE\xf0\x00\x00\x00\x00+\xbe\x95\x80\x00\x00\x00\x00,\xd3bp\x00\x00\x00\x00-\x9ew\x80\x00\x00\x00\x00.\xb3Dp\x00\x00\x00\x00/~Y\x80\x00\x00\x00\x000\x93&p\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xc6\xe0\x00\x00\x00\x00\x00;\xdb\xac\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\x00\x00\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x00\x0c-00\x00CDT\x00CST\x00EST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\x03u\xf3\xe4\x01\x00\x00\xe4\x01\x00\x00\x0e\x00\x00\x00America/RecifeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaag\xb8\xff\xff\xff\xff\xb8\x0fI\xe0\xff\xff\xff\xff\xb8\xfd@\xa0\xff\xff\xff\xff\xb9\xf140\xff\xff\xff\xff\xba\xdet \xff\xff\xff\xff\xda8\xae0\xff\xff\xff\xff\xda\xeb\xfa0\xff\xff\xff\xff\xdc\x19\xe1\xb0\xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xfb\x150\xff\xff\xff\xff\xde\x9b\xde \xff\xff\xff\xff\xdf\xdd\x9a0\xff\xff\xff\xff\xe0T3 \xff\xff\xff\xff\xf4\x97\xff\xb0\xff\xff\xff\xff\xf5\x05^ \xff\xff\xff\xff\xf6\xc0d0\xff\xff\xff\xff\xf7\x0e\x1e\xa0\xff\xff\xff\xff\xf8Q,0\xff\xff\xff\xff\xf8\xc7\xc5 \xff\xff\xff\xff\xfa\x0a\xd2\xb0\xff\xff\xff\xff\xfa\xa8\xf8\xa0\xff\xff\xff\xff\xfb\xec\x060\xff\xff\xff\xff\xfc\x8b}\xa0\x00\x00\x00\x00\x1d\xc9\x8e0\x00\x00\x00\x00\x1ex\xd7\xa0\x00\x00\x00\x00\x1f\xa05\xb0\x00\x00\x00\x00 3\xcf\xa0\x00\x00\x00\x00!\x81i0\x00\x00\x00\x00\x22\x0b\xc8\xa0\x00\x00\x00\x00#X\x10\xb0\x00\x00\x00\x00#\xe2p \x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xd4\xc7 \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xb8\x85 \x00\x00\x00\x009\xdf\xe30\x00\x00\x00\x009\xe9\x0f\xa0\x00\x00\x00\x00;\xc8\xff\xb0\x00\x00\x00\x003\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc2\x96dK~\x02\x00\x00~\x02\x00\x00\x0e\x00\x00\x00America/ReginaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\x86\xfd\x93\x1c\xff\xff\xff\xff\x9e\xb8\xaf\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xb5eO\xf0\xff\xff\xff\xff\xb60H\xe0\xff\xff\xff\xff\xb7E1\xf0\xff\xff\xff\xff\xb8\x10*\xe0\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xf0\x0c\xe0\xff\xff\xff\xff\xbb\x0e0p\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xee\x12p\xff\xff\xff\xff\xbd\xb9\x0b`\xff\xff\xff\xff\xc2r\x08\xf0\xff\xff\xff\xff\xc3a\xeb\xe0\xff\xff\xff\xff\xc4Q\xea\xf0\xff\xff\xff\xff\xc58\x93`\xff\xff\xff\xff\xc61\xcc\xf0\xff\xff\xff\xff\xc7!\xaf\xe0\xff\xff\xff\xff\xc8\x1a\xe9p\xff\xff\xff\xff\xc9\x0a\xcc`\xff\xff\xff\xff\xc9\xfa\xcbp\xff\xff\xff\xff\xca\xea\xae`\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xd3c\x8c\x10\xff\xff\xff\xff\xd4So\x00\xff\xff\xff\xff\xd5U\xe3\x10\xff\xff\xff\xff\xd6 \xdc\x00\xff\xff\xff\xff\xd75\xc5\x10\xff\xff\xff\xff\xd8\x00\xbe\x00\xff\xff\xff\xff\xd9\x15\xa7\x10\xff\xff\xff\xff\xd9\xe0\xa0\x00\xff\xff\xff\xff\xda\xfe\xc3\x90\xff\xff\xff\xff\xdb\xc0\x82\x00\xff\xff\xff\xff\xdc\xde\xa5\x90\xff\xff\xff\xff\xdd\xa9\x9e\x80\xff\xff\xff\xff\xde\xbe\x87\x90\xff\xff\xff\xff\xdf\x89\x80\x80\xff\xff\xff\xff\xe0\x9ei\x90\xff\xff\xff\xff\xe1ib\x80\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3ID\x80\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)&\x80\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12C\x00\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf2%\x00\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xd6\xd3\x00\xff\xff\xff\xff\xed\xc6\xd2\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\xff\xff\x9d\xe4\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\xab\xa0\x00\x14LMT\x00MDT\x00MST\x00MWT\x00MPT\x00CST\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0I~D'\x03\x00\x00'\x03\x00\x00\x10\x00\x00\x00America/ResoluteTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\xd5\xfb\x81\x80\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xeep\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x08 \xcf\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x0a\x00\xb1\x80\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99t\xf0\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12yV\xf0\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14Y8\xf0\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169\x1a\xf0\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x227p\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02\x19p\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe1\xfbp\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xddp\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xbfp\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xa1p\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\x9f\xf0\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x81\xf0\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ac\xf0\x00\x00\x00\x00)\xde\xb3\x80\x00\x00\x00\x00*\xeaE\xf0\x00\x00\x00\x00+\xbe\x95\x80\x00\x00\x00\x00,\xd3bp\x00\x00\x00\x00-\x9ew\x80\x00\x00\x00\x00.\xb3Dp\x00\x00\x00\x00/~Y\x80\x00\x00\x00\x000\x93&p\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xc6\xe0\x00\x00\x00\x00\x00;\xdb\xac\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x00\x00\x00\x00\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x00\x0c-00\x00CDT\x00CST\x00EST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xf5K\x89\xa2\x01\x00\x00\xa2\x01\x00\x00\x12\x00\x00\x00America/Rio_BrancoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa\x86\x90\xff\xff\xff\xff\xb8\x0ff\x00\xff\xff\xff\xff\xb8\xfd\x5c\xc0\xff\xff\xff\xff\xb9\xf1PP\xff\xff\xff\xff\xba\xde\x90@\xff\xff\xff\xff\xda8\xcaP\xff\xff\xff\xff\xda\xec\x16P\xff\xff\xff\xff\xdc\x19\xfd\xd0\xff\xff\xff\xff\xdc\xb9u@\xff\xff\xff\xff\xdd\xfb1P\xff\xff\xff\xff\xde\x9b\xfa@\xff\xff\xff\xff\xdf\xdd\xb6P\xff\xff\xff\xff\xe0TO@\xff\xff\xff\xff\xf4\x98\x1b\xd0\xff\xff\xff\xff\xf5\x05z@\xff\xff\xff\xff\xf6\xc0\x80P\xff\xff\xff\xff\xf7\x0e:\xc0\xff\xff\xff\xff\xf8QHP\xff\xff\xff\xff\xf8\xc7\xe1@\xff\xff\xff\xff\xfa\x0a\xee\xd0\xff\xff\xff\xff\xfa\xa9\x14\xc0\xff\xff\xff\xff\xfb\xec\x22P\xff\xff\xff\xff\xfc\x8b\x99\xc0\x00\x00\x00\x00\x1d\xc9\xaaP\x00\x00\x00\x00\x1ex\xf3\xc0\x00\x00\x00\x00\x1f\xa0Q\xd0\x00\x00\x00\x00 3\xeb\xc0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22\x0b\xe4\xc0\x00\x00\x00\x00H`\x7fP\x00\x00\x00\x00R\x7f\x04\xc0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\xff\xff\xc0p\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x00\x04LMT\x00-04\x00-05\x00\x0a<-05>5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef\xf0R\x8a\xc4\x02\x00\x00\xc4\x02\x00\x00\x0f\x00\x00\x00America/RosarioTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffr\x9c\xad\xb0\xff\xff\xff\xff\xa2\x92\x8f0\xff\xff\xff\xff\xb6{R@\xff\xff\xff\xff\xb7\x1a\xc9\xb0\xff\xff\xff\xff\xb8\x1e\x8f@\xff\xff\xff\xff\xb8\xd4p0\xff\xff\xff\xff\xba\x17}\xc0\xff\xff\xff\xff\xba\xb5\xa3\xb0\xff\xff\xff\xff\xbb\xf8\xb1@\xff\xff\xff\xff\xbc\x96\xd70\xff\xff\xff\xff\xbd\xd9\xe4\xc0\xff\xff\xff\xff\xbex\x0a\xb0\xff\xff\xff\xff\xbf\xbb\x18@\xff\xff\xff\xff\xc0Z\x8f\xb0\xff\xff\xff\xff\xc1\x9d\x9d@\xff\xff\xff\xff\xc2;\xc30\xff\xff\xff\xff\xc3~\xd0\xc0\xff\xff\xff\xff\xc4\x1c\xf6\xb0\xff\xff\xff\xff\xc5`\x04@\xff\xff\xff\xff\xc5\xfe*0\xff\xff\xff\xff\xc7A7\xc0\xff\xff\xff\xff\xc7\xe0\xaf0\xff\xff\xff\xff\xc8\x81\x94@\xff\xff\xff\xff\xcaM\xa1\xb0\xff\xff\xff\xff\xca\xee\x86\xc0\xff\xff\xff\xff\xceM\xff0\xff\xff\xff\xff\xce\xb0\xed\xc0\xff\xff\xff\xff\xd3)5\xb0\xff\xff\xff\xff\xd4Cd\xc0\xff\xff\xff\xff\xf4=\x080\xff\xff\xff\xff\xf4\x9f\xf6\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf62\x10@\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00#\x94\xb5\xb0\x00\x00\x00\x00$\x10\x94\xa0\x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xf0v\xa0\x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xd0X\xa0\x00\x00\x00\x00)\x00\xff@\x00\x00\x00\x00)\xb0:\xa0\x00\x00\x00\x00*\xe0\xd30\x00\x00\x00\x00+\x99W \x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xbf*\xb0\x00\x00\x00\x00Gw\x09\xb0\x00\x00\x00\x00G\xdc\x7f \x00\x00\x00\x00H\xfa\xa2\xb0\x00\x00\x00\x00I\xbca \x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x04\x05\x04\x05\x04\x05\x04\x02\x04\x05\x04\x05\x03\x05\x04\x05\x04\x05\xff\xff\xc3\xd0\x00\x00\xff\xff\xc3\xd0\x00\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x0cLMT\x00CMT\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x14\x00\x00\x00America/Santa_IsabelTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xa9yOp\xff\xff\xff\xff\xaf\xf2|\xf0\xff\xff\xff\xff\xb6fdp\xff\xff\xff\xff\xb7\x1b\x10\x00\xff\xff\xff\xff\xb8\x0a\xf2\xf0\xff\xff\xff\xff\xcb\xea\x8d\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2\x99\xbap\xff\xff\xff\xff\xd7\x1bY\x00\xff\xff\xff\xff\xd8\x91\xb4\xf0\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x0e\x10\xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xd2\x10\xff\xff\xff\xff\xee\x91\xd9\x10\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00F\x0f\x82\xa0\x00\x00\x00\x00G$O\x90\x00\x00\x00\x00G\xf8\x9f \x00\x00\x00\x00I\x041\x90\x00\x00\x00\x00I\xd8\x81 \x00\x00\x00\x00J\xe4\x13\x90\x00\x00\x00\x00K=\xab\x80\x01\x02\x01\x02\x03\x02\x04\x05\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x02\xff\xff\x92L\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10\xff\xff\x9d\x90\x01\x14LMT\x00MST\x00PST\x00PDT\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04,2h\x99\x01\x00\x00\x99\x01\x00\x00\x10\x00\x00\x00America/SantaremTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaazH\xff\xff\xff\xff\xb8\x0fW\xf0\xff\xff\xff\xff\xb8\xfdN\xb0\xff\xff\xff\xff\xb9\xf1B@\xff\xff\xff\xff\xba\xde\x820\xff\xff\xff\xff\xda8\xbc@\xff\xff\xff\xff\xda\xec\x08@\xff\xff\xff\xff\xdc\x19\xef\xc0\xff\xff\xff\xff\xdc\xb9g0\xff\xff\xff\xff\xdd\xfb#@\xff\xff\xff\xff\xde\x9b\xec0\xff\xff\xff\xff\xdf\xdd\xa8@\xff\xff\xff\xff\xe0TA0\xff\xff\xff\xff\xf4\x98\x0d\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf6\xc0r@\xff\xff\xff\xff\xf7\x0e,\xb0\xff\xff\xff\xff\xf8Q:@\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xfa\x0a\xe0\xc0\xff\xff\xff\xff\xfa\xa9\x06\xb0\xff\xff\xff\xff\xfb\xec\x14@\xff\xff\xff\xff\xfc\x8b\x8b\xb0\x00\x00\x00\x00\x1d\xc9\x9c@\x00\x00\x00\x00\x1ex\xe5\xb0\x00\x00\x00\x00\x1f\xa0C\xc0\x00\x00\x00\x00 3\xdd\xb0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22\x0b\xd6\xb0\x00\x00\x00\x00H`q@\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\xff\xff\xcc\xb8\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x00\x04LMT\x00-03\x00-04\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x22_WJ\x05\x00\x00J\x05\x00\x00\x10\x00\x00\x00America/SantiagoTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffi\x87\x1d\xc5\xff\xff\xff\xff\x8f0GE\xff\xff\xff\xff\x9b\x5c\xe5P\xff\xff\xff\xff\x9f|\xe2\xc5\xff\xff\xff\xff\xa1\x00q\xc0\xff\xff\xff\xff\xb0^w\xc5\xff\xff\xff\xff\xb1w=@\xff\xff\xff\xff\xb2A\x00\xd0\xff\xff\xff\xff\xb3Xp\xc0\xff\xff\xff\xff\xb4\x224P\xff\xff\xff\xff\xb59\xa4@\xff\xff\xff\xff\xb6\x03g\xd0\xff\xff\xff\xff\xb7\x1a\xd7\xc0\xff\xff\xff\xff\xb7\xe4\x9bP\xff\xff\xff\xff\xb8\xfd\x5c\xc0\xff\xff\xff\xff\xb9\xc7 P\xff\xff\xff\xff\xcc\x1cn@\xff\xff\xff\xff\xccl\xe7\xd0\xff\xff\xff\xff\xd3\xdc\x8f\xc0\xff\xff\xff\xff\xd4\x17\xd50\xff\xff\xff\xff\xd53U\xc0\xff\xff\xff\xff\xd5v\x92@\xff\xff\xff\xff\xfd\xd1<@\xff\xff\xff\xff\xfe\x92\xfa\xb0\xff\xff\xff\xff\xff\xcc\xcd\xc0\x00\x00\x00\x00\x00r\xdc\xb0\x00\x00\x00\x00\x01uP\xc0\x00\x00\x00\x00\x02@I\xb0\x00\x00\x00\x00\x03U2\xc0\x00\x00\x00\x00\x04 +\xb0\x00\x00\x00\x00\x05>O@\x00\x00\x00\x00\x06\x00\x0d\xb0\x00\x00\x00\x00\x07\x0b\xbc@\x00\x00\x00\x00\x07\xdf\xef\xb0\x00\x00\x00\x00\x08\xfe\x13@\x00\x00\x00\x00\x09\xbf\xd1\xb0\x00\x00\x00\x00\x0a\xdd\xf5@\x00\x00\x00\x00\x0b\xa8\xee0\x00\x00\x00\x00\x0c\xbd\xd7@\x00\x00\x00\x00\x0d\x88\xd00\x00\x00\x00\x00\x0e\x9d\xb9@\x00\x00\x00\x00\x0fh\xb20\x00\x00\x00\x00\x10\x86\xd5\xc0\x00\x00\x00\x00\x11H\x940\x00\x00\x00\x00\x12f\xb7\xc0\x00\x00\x00\x00\x13(v0\x00\x00\x00\x00\x14F\x99\xc0\x00\x00\x00\x00\x15\x11\x92\xb0\x00\x00\x00\x00\x16&{\xc0\x00\x00\x00\x00\x16\xf1t\xb0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x18\xd1V\xb0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xb18\xb0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\x91\x1a\xb0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ep\xfc\xb0\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 \x7f\x030\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x229\xfb0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$\x19\xdd0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xf9\xbf0\x00\x00\x00\x00&\xf2\xf8\xc0\x00\x00\x00\x00'\xd9\xa10\x00\x00\x00\x00(\xf7\xc4\xc0\x00\x00\x00\x00)\xc2\xbd\xb0\x00\x00\x00\x00*\xd7\xa6\xc0\x00\x00\x00\x00+\xa2\x9f\xb0\x00\x00\x00\x00,\xb7\x88\xc0\x00\x00\x00\x00-\x82\x81\xb0\x00\x00\x00\x00.\x97j\xc0\x00\x00\x00\x00/bc\xb0\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001BE\xb0\x00\x00\x00\x002`i@\x00\x00\x00\x003=\xd70\x00\x00\x00\x004@K@\x00\x00\x00\x005\x0bD0\x00\x00\x00\x006\x0d\xb8@\x00\x00\x00\x007\x06\xd5\xb0\x00\x00\x00\x008\x00\x0f@\x00\x00\x00\x008\xcb\x080\x00\x00\x00\x009\xe9+\xc0\x00\x00\x00\x00:\xaa\xea0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00<\x8a\xcc0\x00\x00\x00\x00=\xa8\xef\xc0\x00\x00\x00\x00>j\xae0\x00\x00\x00\x00?\x88\xd1\xc0\x00\x00\x00\x00@S\xca\xb0\x00\x00\x00\x00Ah\xb3\xc0\x00\x00\x00\x00B3\xac\xb0\x00\x00\x00\x00CH\x95\xc0\x00\x00\x00\x00D\x13\x8e\xb0\x00\x00\x00\x00E1\xb2@\x00\x00\x00\x00E\xf3p\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xef\x020\x00\x00\x00\x00H\xf1v@\x00\x00\x00\x00I\xbco0\x00\x00\x00\x00J\xd1X@\x00\x00\x00\x00K\xb8\x00\xb0\x00\x00\x00\x00L\xb1:@\x00\x00\x00\x00M\xc6\x070\x00\x00\x00\x00NP\x82\xc0\x00\x00\x00\x00O\x9c\xae\xb0\x00\x00\x00\x00PB\xd9\xc0\x00\x00\x00\x00Q|\x90\xb0\x00\x00\x00\x00R+\xf6@\x00\x00\x00\x00S\x5cr\xb0\x00\x00\x00\x00T\x0b\xd8@\x00\x00\x00\x00W7\xe60\x00\x00\x00\x00W\xaf\xec\xc0\x00\x00\x00\x00Y\x17\xc80\x00\x00\x00\x00Y\x8f\xce\xc0\x00\x00\x00\x00Z\xf7\xaa0\x00\x00\x00\x00[o\xb0\xc0\x00\x00\x00\x00\x5c\xa9g\xb0\x00\x00\x00\x00]t|\xc0\x00\x00\x00\x00^\x89I\xb0\x00\x00\x00\x00_T^\xc0\x00\x00\x00\x00`i+\xb0\x00\x00\x00\x00a4@\xc0\x00\x00\x00\x00bI\x0d\xb0\x00\x00\x00\x00c\x1d]@\x00\x00\x00\x00d(\xef\xb0\x01\x02\x01\x03\x01\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x03\x02\x03\x05\x04\x02\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\xff\xff\xbd\xbb\x00\x00\xff\xff\xbd\xbb\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x00\x0c\xff\xff\xc7\xc0\x01\x0c\xff\xff\xd5\xd0\x01\x10LMT\x00SMT\x00-05\x00-04\x00-03\x00\x0a<-04>4<-03>,M9.1.6/24,M4.1.6/24\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x0f(\x08=\x01\x00\x00=\x01\x00\x00\x15\x00\x00\x00America/Santo_DomingoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x06\x00\x00\x00\x1b\xff\xff\xff\xffi\x87\x1d\x08\xff\xff\xff\xff\xba\xdfB`\xff\xff\xff\xff\xfa\x08K\xd0\xff\xff\xff\xff\xfa\xa7\xc3@\xff\xff\xff\xff\xff\xa7\xf1\xd0\x00\x00\x00\x00\x00C{\xc8\x00\x00\x00\x00\x01\x87\xd3\xd0\x00\x00\x00\x00\x01\xfa\x7fH\x00\x00\x00\x00\x03p\xf0P\x00\x00\x00\x00\x03\xdd\x04H\x00\x00\x00\x00\x05P\xd2P\x00\x00\x00\x00\x05\xbf\x89H\x00\x00\x00\x00\x070\xb4P\x00\x00\x00\x00\x07\xa0\xbc\xc8\x00\x00\x00\x00\x09\x10\x96P\x00\x00\x00\x009\xfb\xbc\xe0\x00\x00\x00\x00:)\xe1`\x01\x03\x02\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x05\x03\x05\xff\xff\xbex\x00\x00\xff\xff\xbe`\x00\x04\xff\xff\xc7\xc0\x01\x09\xff\xff\xb9\xb0\x00\x0d\xff\xff\xc0\xb8\x01\x11\xff\xff\xc7\xc0\x00\x17LMT\x00SDMT\x00EDT\x00EST\x00-0430\x00AST\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9d?\xdf\xda\xb8\x03\x00\x00\xb8\x03\x00\x00\x11\x00\x00\x00America/Sao_PauloTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaar\xb4\xff\xff\xff\xff\xb8\x0fI\xe0\xff\xff\xff\xff\xb8\xfd@\xa0\xff\xff\xff\xff\xb9\xf140\xff\xff\xff\xff\xba\xdet \xff\xff\xff\xff\xda8\xae0\xff\xff\xff\xff\xda\xeb\xfa0\xff\xff\xff\xff\xdc\x19\xe1\xb0\xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xfb\x150\xff\xff\xff\xff\xde\x9b\xde \xff\xff\xff\xff\xdf\xdd\x9a0\xff\xff\xff\xff\xe0T3 \xff\xff\xff\xff\xf4Z\x090\xff\xff\xff\xff\xf5\x05^ \xff\xff\xff\xff\xf6\xc0d0\xff\xff\xff\xff\xf7\x0e\x1e\xa0\xff\xff\xff\xff\xf8Q,0\xff\xff\xff\xff\xf8\xc7\xc5 \xff\xff\xff\xff\xfa\x0a\xd2\xb0\xff\xff\xff\xff\xfa\xa8\xf8\xa0\xff\xff\xff\xff\xfb\xec\x060\xff\xff\xff\xff\xfc\x8b}\xa0\x00\x00\x00\x00\x1d\xc9\x8e0\x00\x00\x00\x00\x1ex\xd7\xa0\x00\x00\x00\x00\x1f\xa05\xb0\x00\x00\x00\x00 3\xcf\xa0\x00\x00\x00\x00!\x81i0\x00\x00\x00\x00\x22\x0b\xc8\xa0\x00\x00\x00\x00#X\x10\xb0\x00\x00\x00\x00#\xe2p \x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xd4\xc7 \x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xbd\xe3\xa0\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\x94\x8b \x00\x00\x00\x00*\xea\x0d\xb0\x00\x00\x00\x00+k2\xa0\x00\x00\x00\x00,\xc0\xb50\x00\x00\x00\x00-f\xc4 \x00\x00\x00\x00.\xa0\x970\x00\x00\x00\x00/F\xa6 \x00\x00\x00\x000\x80y0\x00\x00\x00\x001\x1dM\xa0\x00\x00\x00\x002W \xb0\x00\x00\x00\x003\x06j \x00\x00\x00\x0048T0\x00\x00\x00\x004\xf8\xc1 \x00\x00\x00\x006 \x1f0\x00\x00\x00\x006\xcfh\xa0\x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xb8\x85 \x00\x00\x00\x009\xdf\xe30\x00\x00\x00\x00:\x8f,\xa0\x00\x00\x00\x00;\xc8\xff\xb0\x00\x00\x00\x00N\xf0\xa0\x00\x00\x00\x00?\x91\xfe0\x00\x00\x00\x00@.\xd2\xa0\x00\x00\x00\x00A\x86\xf80\x00\x00\x00\x00B\x17\xef \x00\x00\x00\x00CQ\xc20\x00\x00\x00\x00C\xf7\xd1 \x00\x00\x00\x00EMS\xb0\x00\x00\x00\x00E\xe0\xed\xa0\x00\x00\x00\x00G\x11\x860\x00\x00\x00\x00G\xb7\x95 \x00\x00\x00\x00H\xfa\xa2\xb0\x00\x00\x00\x00I\x97w \x00\x00\x00\x00J\xda\x84\xb0\x00\x00\x00\x00K\x80\x93\xa0\x00\x00\x00\x00L\xbaf\xb0\x00\x00\x00\x00M`u\xa0\x00\x00\x00\x00N\x9aH\xb0\x00\x00\x00\x00OI\x92 \x00\x00\x00\x00P\x83e0\x00\x00\x00\x00Q 9\xa0\x00\x00\x00\x00RcG0\x00\x00\x00\x00S\x00\x1b\xa0\x00\x00\x00\x00TC)0\x00\x00\x00\x00T\xe98 \x00\x00\x00\x00V#\x0b0\x00\x00\x00\x00V\xc9\x1a \x00\x00\x00\x00X\x02\xed0\x00\x00\x00\x00X\xa8\xfc \x00\x00\x00\x00Y\xe2\xcf0\x00\x00\x00\x00Z\x88\xde \x00\x00\x00\x00[\xde`\xb0\x00\x00\x00\x00\x5ch\xc0 \x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xd4L\x00\x00\xff\xff\xe3\xe0\x01\x04\xff\xff\xd5\xd0\x00\x08LMT\x00-02\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19a\x7f\x0a\xd8\x03\x00\x00\xd8\x03\x00\x00\x14\x00\x00\x00America/ScoresbysundTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Z\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\x9b\x80L\x18\x00\x00\x00\x00\x13Mn@\x00\x00\x00\x00\x144$\xc0\x00\x00\x00\x00\x15#\xf9\xa0\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x86A\x90\x00\x00\x00\x00?\x9b\x1c\x90\x00\x00\x00\x00@f#\x90\x00\x00\x00\x00A\x849\x10\x00\x00\x00\x00BF\x05\x90\x00\x00\x00\x00Cd\x1b\x10\x00\x00\x00\x00D%\xe7\x90\x00\x00\x00\x00EC\xfd\x10\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8e\x8c\x10\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S7l\x90\x00\x00\x00\x00TLG\x90\x00\x00\x00\x00U\x17N\x90\x00\x00\x00\x00V,)\x90\x00\x00\x00\x00V\xf70\x90\x00\x00\x00\x00X\x15F\x10\x00\x00\x00\x00X\xd7\x12\x90\x00\x00\x00\x00Y\xf5(\x10\x00\x00\x00\x00Z\xb6\xf4\x90\x00\x00\x00\x00[\xd5\x0a\x10\x00\x00\x00\x00\x5c\xa0\x11\x10\x00\x00\x00\x00]\xb4\xec\x10\x00\x00\x00\x00^\x7f\xf3\x10\x00\x00\x00\x00_\x94\xce\x10\x00\x00\x00\x00`_\xd5\x10\x00\x00\x00\x00a}\xea\x90\x00\x00\x00\x00b?\xb7\x10\x00\x00\x00\x00c]\xcc\x90\x00\x00\x00\x00d\x1f\x99\x10\x00\x00\x00\x00e=\xae\x90\x00\x00\x00\x00f\x08\xb5\x90\x01\x02\x01\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x02\xff\xff\xebh\x00\x00\xff\xff\xe3\xe0\x00\x04\xff\xff\xf1\xf0\x01\x08\xff\xff\xf1\xf0\x00\x08\x00\x00\x00\x00\x01\x0cLMT\x00-02\x00-01\x00+00\x00\x0a<-02>2<-01>,M3.5.0/-1,M10.5.0/0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x80\x94@\x12\x04\x00\x00\x12\x04\x00\x00\x10\x00\x00\x00America/ShiprockTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xa2e\xfe\x90\xff\xff\xff\xff\xa3\x84\x06\x00\xff\xff\xff\xff\xa4E\xe0\x90\xff\xff\xff\xff\xa4\x8f\xa6\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xf7/v\x90\xff\xff\xff\xff\xf8(\x94\x00\xff\xff\xff\xff\xf9\x0fX\x90\xff\xff\xff\xff\xfa\x08v\x00\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8W\x10\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb89\x10\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x1b\x10\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xfd\x10\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x07\x8d5\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x09\xad\xb1\x10\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x9d\x94\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10LMT\x00MDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81{\xc1\x92\xbc\x03\x00\x00\xbc\x03\x00\x00\x0d\x00\x00\x00America/SitkaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x09\x00\x00\x00\x22\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x873\x99\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x07\x8dC\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x09\xad\xbf \x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a+\x14\x10\x00\x00\x00\x00\x1a\xf2B\xb0\x00\x00\x00\x00\x1b\xe2%\xa0\x00\x00\x00\x00\x1c\xd2$\xb0\x00\x00\x00\x00\x1d\xc2\x07\xa0\x00\x00\x00\x00\x1e\xb2\x06\xb0\x00\x00\x00\x00\x1f\xa1\xe9\xa0\x00\x00\x00\x00 v90\x00\x00\x00\x00!\x81\xcb\xa0\x00\x00\x00\x00\x22V\x1b0\x00\x00\x00\x00#j\xe8 \x00\x00\x00\x00$5\xfd0\x00\x00\x00\x00%J\xca \x00\x00\x00\x00&\x15\xdf0\x00\x00\x00\x00'*\xac \x00\x00\x00\x00'\xfe\xfb\xb0\x00\x00\x00\x00)\x0a\x8e \x00\x00\x00\x00)\xde\xdd\xb0\x00\x00\x00\x00*\xeap \x00\x00\x00\x00+\xbe\xbf\xb0\x00\x00\x00\x00,\xd3\x8c\xa0\x00\x00\x00\x00-\x9e\xa1\xb0\x00\x00\x00\x00.\xb3n\xa0\x00\x00\x00\x00/~\x83\xb0\x00\x00\x00\x000\x93P\xa0\x00\x00\x00\x001g\xa00\x00\x00\x00\x002s2\xa0\x00\x00\x00\x003G\x820\x00\x00\x00\x004S\x14\xa0\x00\x00\x00\x005'd0\x00\x00\x00\x0062\xf6\xa0\x00\x00\x00\x007\x07F0\x00\x00\x00\x008\x1c\x13 \x00\x00\x00\x008\xe7(0\x00\x00\x00\x009\xfb\xf5 \x00\x00\x00\x00:\xc7\x0a0\x00\x00\x00\x00;\xdb\xd7 \x00\x00\x00\x00<\xb0&\xb0\x00\x00\x00\x00=\xbb\xb9 \x00\x00\x00\x00>\x90\x08\xb0\x00\x00\x00\x00?\x9b\x9b \x00\x00\x00\x00@o\xea\xb0\x00\x00\x00\x00A\x84\xb7\xa0\x00\x00\x00\x00BO\xcc\xb0\x00\x00\x00\x00Cd\x99\xa0\x00\x00\x00\x00D/\xae\xb0\x00\x00\x00\x00ED{\xa0\x00\x00\x00\x00E\xf3\xe10\x01\x02\x03\x04\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x06\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x00\x00\xd2\xa7\x00\x00\xff\xff\x81'\x00\x00\xff\xff\x8f\x80\x00\x04\xff\xff\x9d\x90\x01\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10\xff\xff\x81p\x00\x14\xff\xff\x8f\x80\x01\x18\xff\xff\x81p\x00\x1dLMT\x00PST\x00PWT\x00PPT\x00PDT\x00YST\x00AKDT\x00AKST\x00\x0aAKST9AKDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x15\x00\x00\x00America/St_BarthelemyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeah\x06\xd2V\x07\x00\x00V\x07\x00\x00\x10\x00\x00\x00America/St_JohnsTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbb\x00\x00\x00\x08\x00\x00\x00\x19\xff\xff\xff\xff^=4\xec\xff\xff\xff\xff\x9c\xcfb\x0c\xff\xff\xff\xff\x9d\xa4\xe6\xfc\xff\xff\xff\xff\x9e\xb8~\x8c\xff\xff\xff\xff\x9f\xba\xd6|\xff\xff\xff\xff\xa0\xb6\x88\xdc\xff\xff\xff\xff\xa18\xffL\xff\xff\xff\xff\xa2\x95\x19\x5c\xff\xff\xff\xff\xa3\x84\xfcL\xff\xff\xff\xff\xa4t\xfb\x5c\xff\xff\xff\xff\xa5d\xdeL\xff\xff\xff\xff\xa6^\x17\xdc\xff\xff\xff\xff\xa7D\xc0L\xff\xff\xff\xff\xa8=\xf9\xdc\xff\xff\xff\xff\xa9$\xa2L\xff\xff\xff\xff\xaa\x1d\xdb\xdc\xff\xff\xff\xff\xab\x04\x84L\xff\xff\xff\xff\xab\xfd\xbd\xdc\xff\xff\xff\xff\xac\xe4fL\xff\xff\xff\xff\xad\xdd\x9f\xdc\xff\xff\xff\xff\xae\xcd\x82\xcc\xff\xff\xff\xff\xaf\xbd\x81\xdc\xff\xff\xff\xff\xb0\xadd\xcc\xff\xff\xff\xff\xb1\xa6\x9e\x5c\xff\xff\xff\xff\xb2\x8dF\xcc\xff\xff\xff\xff\xb3\x86\x80\x5c\xff\xff\xff\xff\xb4m(\xcc\xff\xff\xff\xff\xb5fb\x5c\xff\xff\xff\xff\xb6M\x0a\xcc\xff\xff\xff\xff\xb7FD\x5c\xff\xff\xff\xff\xb8,\xec\xcc\xff\xff\xff\xff\xb9&&\x5c\xff\xff\xff\xff\xba\x16\x09L\xff\xff\xff\xff\xbb\x0fB\xdc\xff\xff\xff\xff\xbb\xf5\xebL\xff\xff\xff\xff\xbc\xef$\xdc\xff\xff\xff\xff\xbd\xd5\xcdL\xff\xff\xff\xff\xbe\x9eMl\xff\xff\xff\xff\xbe\xcf\x06\xa8\xff\xff\xff\xff\xbf\xb5\xaf\x18\xff\xff\xff\xff\xc0\xb818\xff\xff\xff\xff\xc1y\xef\xa8\xff\xff\xff\xff\xc2\x98\x138\xff\xff\xff\xff\xc3Y\xd1\xa8\xff\xff\xff\xff\xc4w\xf58\xff\xff\xff\xff\xc59\xb3\xa8\xff\xff\xff\xff\xc6a\x11\xb8\xff\xff\xff\xff\xc7\x19\x95\xa8\xff\xff\xff\xff\xc8@\xf3\xb8\xff\xff\xff\xff\xc9\x02\xb2(\xff\xff\xff\xff\xca \xd5\xb8\xff\xff\xff\xff\xca\xe2\x94(\xff\xff\xff\xff\xcc\x00\xb7\xb8\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xe6\xc8\xff\xff\xff\xff\xd3\x88D\xd8\xff\xff\xff\xff\xd4J\x03H\xff\xff\xff\xff\xd5h&\xd8\xff\xff\xff\xff\xd6)\xe5H\xff\xff\xff\xff\xd7H\x08\xd8\xff\xff\xff\xff\xd8\x09\xc7H\xff\xff\xff\xff\xd9'\xea\xd8\xff\xff\xff\xff\xd9\xe9\xa9H\xff\xff\xff\xff\xdb\x11\x07X\xff\xff\xff\xff\xdb\xd2\xc5\xc8\xff\xff\xff\xff\xdc\xdetX\xff\xff\xff\xff\xdd\xa9mH\xff\xff\xff\xff\xde\xbeVX\xff\xff\xff\xff\xdf\x89OH\xff\xff\xff\xff\xe0\x9e8X\xff\xff\xff\xff\xe1i1H\xff\xff\xff\xff\xe2~\x1aX\xff\xff\xff\xff\xe3I\x13H\xff\xff\xff\xff\xe4]\xfcX\xff\xff\xff\xff\xe5(\xf5H\xff\xff\xff\xff\xe6G\x18\xd8\xff\xff\xff\xff\xe7\x12\x11\xc8\xff\xff\xff\xff\xe8&\xfa\xd8\xff\xff\xff\xff\xe8\xf1\xf3\xc8\xff\xff\xff\xff\xea\x06\xdc\xd8\xff\xff\xff\xff\xea\xd1\xd5\xc8\xff\xff\xff\xff\xeb\xe6\xbe\xd8\xff\xff\xff\xff\xec\xb1\xb7\xc8\xff\xff\xff\xff\xed\xc6\xa0\xd8\xff\xff\xff\xff\xee\xbf\xbeH\xff\xff\xff\xff\xef\xaf\xbdX\xff\xff\xff\xff\xf0\x9f\xa0H\xff\xff\xff\xff\xf1\x8f\x9fX\xff\xff\xff\xff\xf2\x7f\x82H\xff\xff\xff\xff\xf3o\x81X\xff\xff\xff\xff\xf4_dH\xff\xff\xff\xff\xf5OcX\xff\xff\xff\xff\xf6?FH\xff\xff\xff\xff\xf7/EX\xff\xff\xff\xff\xf8(b\xc8\xff\xff\xff\xff\xf9\x0f'X\xff\xff\xff\xff\xfa\x08D\xc8\xff\xff\xff\xff\xfa\xf8C\xd8\xff\xff\xff\xff\xfb\xe8&\xc8\xff\xff\xff\xff\xfc\xd8%\xd8\xff\xff\xff\xff\xfd\xc8\x08\xc8\xff\xff\xff\xff\xfe\xb8\x07\xd8\xff\xff\xff\xff\xff\xa7\xea\xc8\x00\x00\x00\x00\x00\x97\xe9\xd8\x00\x00\x00\x00\x01\x87\xcc\xc8\x00\x00\x00\x00\x02w\xcb\xd8\x00\x00\x00\x00\x03p\xe9H\x00\x00\x00\x00\x04`\xe8X\x00\x00\x00\x00\x05P\xcbH\x00\x00\x00\x00\x06@\xcaX\x00\x00\x00\x00\x070\xadH\x00\x00\x00\x00\x08 \xacX\x00\x00\x00\x00\x09\x10\x8fH\x00\x00\x00\x00\x0a\x00\x8eX\x00\x00\x00\x00\x0a\xf0qH\x00\x00\x00\x00\x0b\xe0pX\x00\x00\x00\x00\x0c\xd9\x8d\xc8\x00\x00\x00\x00\x0d\xc0RX\x00\x00\x00\x00\x0e\xb9o\xc8\x00\x00\x00\x00\x0f\xa9n\xd8\x00\x00\x00\x00\x10\x99Q\xc8\x00\x00\x00\x00\x11\x89P\xd8\x00\x00\x00\x00\x12y3\xc8\x00\x00\x00\x00\x13i2\xd8\x00\x00\x00\x00\x14Y\x15\xc8\x00\x00\x00\x00\x15I\x14\xd8\x00\x00\x00\x00\x168\xf7\xc8\x00\x00\x00\x00\x17(\xf6\xd8\x00\x00\x00\x00\x18\x22\x14H\x00\x00\x00\x00\x19\x08\xd8\xd8\x00\x00\x00\x00\x1a\x01\xf6H\x00\x00\x00\x00\x1a\xf1\xf5X\x00\x00\x00\x00\x1b\xe1\xd8H\x00\x00\x00\x00\x1c\xd1\xd7X\x00\x00\x00\x00\x1d\xc1\xbaH\x00\x00\x00\x00\x1e\xb1\xb9X\x00\x00\x00\x00\x1f\xa1\x9cH\x00\x00\x00\x00 u\xcf\xf4\x00\x00\x00\x00!\x81bd\x00\x00\x00\x00\x22U\xb1\xf4\x00\x00\x00\x00#jp\xd4\x00\x00\x00\x00$5\x93\xf4\x00\x00\x00\x00%J`\xe4\x00\x00\x00\x00&\x15u\xf4\x00\x00\x00\x00'*B\xe4\x00\x00\x00\x00'\xfe\x92t\x00\x00\x00\x00)\x0a$\xe4\x00\x00\x00\x00)\xdett\x00\x00\x00\x00*\xea\x06\xe4\x00\x00\x00\x00+\xbeVt\x00\x00\x00\x00,\xd3#d\x00\x00\x00\x00-\x9e8t\x00\x00\x00\x00.\xb3\x05d\x00\x00\x00\x00/~\x1at\x00\x00\x00\x000\x92\xe7d\x00\x00\x00\x001g6\xf4\x00\x00\x00\x002r\xc9d\x00\x00\x00\x003G\x18\xf4\x00\x00\x00\x004R\xabd\x00\x00\x00\x005&\xfa\xf4\x00\x00\x00\x0062\x8dd\x00\x00\x00\x007\x06\xdc\xf4\x00\x00\x00\x008\x1b\xa9\xe4\x00\x00\x00\x008\xe6\xbe\xf4\x00\x00\x00\x009\xfb\x8b\xe4\x00\x00\x00\x00:\xc6\xa0\xf4\x00\x00\x00\x00;\xdbm\xe4\x00\x00\x00\x00<\xaf\xbdt\x00\x00\x00\x00=\xbbO\xe4\x00\x00\x00\x00>\x8f\x9ft\x00\x00\x00\x00?\x9b1\xe4\x00\x00\x00\x00@o\x81t\x00\x00\x00\x00A\x84Nd\x00\x00\x00\x00BOct\x00\x00\x00\x00Cd0d\x00\x00\x00\x00D/Et\x00\x00\x00\x00ED\x12d\x00\x00\x00\x00E\xf3w\xf4\x00\x00\x00\x00G-.\xe4\x00\x00\x00\x00G\xd3Y\xf4\x00\x00\x00\x00I\x0d\x10\xe4\x00\x00\x00\x00I\xb3;\xf4\x00\x00\x00\x00J\xec\xf2\xe4\x00\x00\x00\x00K\x9cXt\x00\x00\x00\x00L\xd6\x0fd\x00\x00\x00\x00M|:t\x00\x00\x00\x00N\xafY\xa8\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x06\x05\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x07\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x03\xff\xff\xce\x94\x00\x00\xff\xff\xdc\xa4\x01\x04\xff\xff\xce\x94\x00\x08\xff\xff\xdc\xd8\x01\x04\xff\xff\xce\xc8\x00\x08\xff\xff\xdc\xd8\x01\x0c\xff\xff\xdc\xd8\x01\x10\xff\xff\xea\xe8\x01\x14LMT\x00NDT\x00NST\x00NPT\x00NWT\x00NDDT\x00\x0aNST3:30NDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00America/St_KittsTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00America/St_LuciaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x11\x00\x00\x00America/St_ThomasTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x12\x00\x00\x00America/St_VincentTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\xd8\x19\x9dp\x01\x00\x00p\x01\x00\x00\x15\x00\x00\x00America/Swift_CurrentTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\x86\xfd\x96\x18\xff\xff\xff\xff\x9e\xb8\xaf\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xd3v\x01\x10\xff\xff\xff\xff\xd4So\x00\xff\xff\xff\xff\xd5U\xe3\x10\xff\xff\xff\xff\xd6 \xdc\x00\xff\xff\xff\xff\xd75\xc5\x10\xff\xff\xff\xff\xd8\x00\xbe\x00\xff\xff\xff\xff\xd9\x15\xa7\x10\xff\xff\xff\xff\xd9\xe0\xa0\x00\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe9\x17\x0f\x00\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xd6\xd3\x00\xff\xff\xff\xff\xed\xc6\xd2\x10\xff\xff\xff\xff\xee\x91\xcb\x00\xff\xff\xff\xff\xef\xaf\xee\x90\xff\xff\xff\xff\xf0q\xad\x00\x00\x00\x00\x00\x04a\x19\x90\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\xff\xff\x9a\xe8\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\xab\xa0\x00\x14LMT\x00MDT\x00MST\x00MWT\x00MPT\x00CST\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x13z\xe2\xc2\x00\x00\x00\xc2\x00\x00\x00\x13\x00\x00\x00America/TegucigalpaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xa4LKD\x00\x00\x00\x00 \x9a\xdc\xe0\x00\x00\x00\x00!\x5c\x9bP\x00\x00\x00\x00\x22z\xbe\xe0\x00\x00\x00\x00#<}P\x00\x00\x00\x00D]\x8c\xe0\x00\x00\x00\x00D\xd6\xc8\xd0\x02\x01\x02\x01\x02\x01\x02\xff\xff\xae<\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08LMT\x00CDT\x00CST\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x0d\xf7\xd3\xc7\x01\x00\x00\xc7\x01\x00\x00\x0d\x00\x00\x00America/ThuleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x9b\x80w\xfc\x00\x00\x00\x00'\xf5z\xe0\x00\x00\x00\x00(\xe5]\xd0\x00\x00\x00\x00)\xd5\x5c\xe0\x00\x00\x00\x00*\xc5?\xd0\x00\x00\x00\x00+\xbey`\x00\x00\x00\x00,\xd3FP\x00\x00\x00\x00-\x9e[`\x00\x00\x00\x00.\xb3(P\x00\x00\x00\x00/~=`\x00\x00\x00\x000\x93\x0aP\x00\x00\x00\x001gY\xe0\x00\x00\x00\x002r\xecP\x00\x00\x00\x003G;\xe0\x00\x00\x00\x004R\xceP\x00\x00\x00\x005'\x1d\xe0\x00\x00\x00\x0062\xb0P\x00\x00\x00\x007\x06\xff\xe0\x00\x00\x00\x008\x1b\xcc\xd0\x00\x00\x00\x008\xe6\xe1\xe0\x00\x00\x00\x009\xfb\xae\xd0\x00\x00\x00\x00:\xc6\xc3\xe0\x00\x00\x00\x00;\xdb\x90\xd0\x00\x00\x00\x00<\xaf\xe0`\x00\x00\x00\x00=\xbbr\xd0\x00\x00\x00\x00>\x8f\xc2`\x00\x00\x00\x00?\x9bT\xd0\x00\x00\x00\x00@o\xa4`\x00\x00\x00\x00A\x84qP\x00\x00\x00\x00BO\x86`\x00\x00\x00\x00CdSP\x00\x00\x00\x00D/h`\x00\x00\x00\x00ED5P\x00\x00\x00\x00E\xf3\x9a\xe0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xbf\x84\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08LMT\x00ADT\x00AST\x00\x0aAST4ADT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x13\x00\x00\x00America/Thunder_BayTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffr\xeex\xec\xff\xff\xff\xff\x9e\xb8\x93p\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x87.\xc8\xff\xff\xff\xff\xa1\x9a\xb1@\xff\xff\xff\xff\xa2\x94\x06\xf0\xff\xff\xff\xff\xa3U\xa9@\xff\xff\xff\xff\xa4\x86]\xf0\xff\xff\xff\xff\xa5(x`\xff\xff\xff\xff\xa6f?\xf0\xff\xff\xff\xff\xa7\x0cN\xe0\xff\xff\xff\xff\xa8F!\xf0\xff\xff\xff\xff\xa8\xec0\xe0\xff\xff\xff\xff\xaa\x1c\xc9p\xff\xff\xff\xff\xaa\xd5M`\xff\xff\xff\xff\xab\xfc\xabp\xff\xff\xff\xff\xac\xb5/`\xff\xff\xff\xff\xad\xdc\x8dp\xff\xff\xff\xff\xae\x95\x11`\xff\xff\xff\xff\xaf\xbcop\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xda3\x92`\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdc\x13t`\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5)\x0a`\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe7\x12&\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xb5\x94\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x0f\x00\x00\x00America/TijuanaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xa9yOp\xff\xff\xff\xff\xaf\xf2|\xf0\xff\xff\xff\xff\xb6fdp\xff\xff\xff\xff\xb7\x1b\x10\x00\xff\xff\xff\xff\xb8\x0a\xf2\xf0\xff\xff\xff\xff\xcb\xea\x8d\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2\x99\xbap\xff\xff\xff\xff\xd7\x1bY\x00\xff\xff\xff\xff\xd8\x91\xb4\xf0\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x0e\x10\xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xd2\x10\xff\xff\xff\xff\xee\x91\xd9\x10\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00F\x0f\x82\xa0\x00\x00\x00\x00G$O\x90\x00\x00\x00\x00G\xf8\x9f \x00\x00\x00\x00I\x041\x90\x00\x00\x00\x00I\xd8\x81 \x00\x00\x00\x00J\xe4\x13\x90\x00\x00\x00\x00K=\xab\x80\x01\x02\x01\x02\x03\x02\x04\x05\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x02\xff\xff\x92L\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10\xff\xff\x9d\x90\x01\x14LMT\x00MST\x00PST\x00PDT\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0f\x00\x00\x00America/TorontoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffr\xeex\xec\xff\xff\xff\xff\x9e\xb8\x93p\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x87.\xc8\xff\xff\xff\xff\xa1\x9a\xb1@\xff\xff\xff\xff\xa2\x94\x06\xf0\xff\xff\xff\xff\xa3U\xa9@\xff\xff\xff\xff\xa4\x86]\xf0\xff\xff\xff\xff\xa5(x`\xff\xff\xff\xff\xa6f?\xf0\xff\xff\xff\xff\xa7\x0cN\xe0\xff\xff\xff\xff\xa8F!\xf0\xff\xff\xff\xff\xa8\xec0\xe0\xff\xff\xff\xff\xaa\x1c\xc9p\xff\xff\xff\xff\xaa\xd5M`\xff\xff\xff\xff\xab\xfc\xabp\xff\xff\xff\xff\xac\xb5/`\xff\xff\xff\xff\xad\xdc\x8dp\xff\xff\xff\xff\xae\x95\x11`\xff\xff\xff\xff\xaf\xbcop\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xda3\x92`\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdc\x13t`\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5)\x0a`\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe7\x12&\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xb5\x94\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00America/TortolaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U9#\xbe2\x05\x00\x002\x05\x00\x00\x11\x00\x00\x00America/VancouverTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^=v\xec\xff\xff\xff\xff\x9e\xb8\xbd\xa0\xff\xff\xff\xff\x9f\xbb\x15\x90\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xd3v\x0f \xff\xff\xff\xff\xd4A\x08\x10\xff\xff\xff\xff\xd5U\xf1 \xff\xff\xff\xff\xd6 \xea\x10\xff\xff\xff\xff\xd75\xd3 \xff\xff\xff\xff\xd8\x00\xcc\x10\xff\xff\xff\xff\xd9\x15\xb5 \xff\xff\xff\xff\xd9\xe0\xae\x10\xff\xff\xff\xff\xda\xfe\xd1\xa0\xff\xff\xff\xff\xdb\xc0\x90\x10\xff\xff\xff\xff\xdc\xde\xb3\xa0\xff\xff\xff\xff\xdd\xa9\xac\x90\xff\xff\xff\xff\xde\xbe\x95\xa0\xff\xff\xff\xff\xdf\x89\x8e\x90\xff\xff\xff\xff\xe0\x9ew\xa0\xff\xff\xff\xff\xe1ip\x90\xff\xff\xff\xff\xe2~Y\xa0\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^;\xa0\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GX \xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8': \xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x1c \xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xfe \xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xe0 \xff\xff\xff\xff\xee\x91\xd9\x10\xff\xff\xff\xff\xef\xaf\xfc\xa0\xff\xff\xff\xff\xf0q\xbb\x10\xff\xff\xff\xff\xf1\x8f\xde\xa0\xff\xff\xff\xff\xf2\x7f\xc1\x90\xff\xff\xff\xff\xf3o\xc0\xa0\xff\xff\xff\xff\xf4_\xa3\x90\xff\xff\xff\xff\xf5O\xa2\xa0\xff\xff\xff\xff\xf6?\x85\x90\xff\xff\xff\xff\xf7/\x84\xa0\xff\xff\xff\xff\xf8(\xa2\x10\xff\xff\xff\xff\xf9\x0ff\xa0\xff\xff\xff\xff\xfa\x08\x84\x10\xff\xff\xff\xff\xfa\xf8\x83 \xff\xff\xff\xff\xfb\xe8f\x10\xff\xff\xff\xff\xfc\xd8e \xff\xff\xff\xff\xfd\xc8H\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x08 \xeb\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x0a\x00\xcd\xa0\x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x8c\x94\x00\x00\xff\xff\x9d\x90\x01\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10LMT\x00PDT\x00PST\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0e\x00\x00\x00America/VirginTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffz\xe6\x95\xb9\xff\xff\xff\xff\xcb\xf62\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\x01\x03\x02\x01\xff\xff\xc2\x07\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xd5\xd0\x01\x0cLMT\x00AST\x00APT\x00AWT\x00\x0aAST4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\x1d\xee\x91\x05\x04\x00\x00\x05\x04\x00\x00\x12\x00\x00\x00America/WhitehorseTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x00\x00\x00\x09\x00\x00\x00%\xff\xff\xff\xff}\x86\x8a\x9c\xff\xff\xff\xff\x9e\xb8\xcb\xb0\xff\xff\xff\xff\x9f\xbb#\xa0\xff\xff\xff\xff\xa0\xd0\x0c\xb0\xff\xff\xff\xff\xa1\xa2\xd2\x80\xff\xff\xff\xff\xcb\x89(\xb0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a4 \xff\xff\xff\xff\xf7/v\x90\xff\xff\xff\xff\xf8(\xa2\x10\xff\xff\xff\xff\xf8\xc5\x84\x90\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x00\x00\x00\x00G-\x8a\x10\x00\x00\x00\x00G\xd3\xb5 \x00\x00\x00\x00I\x0dl\x10\x00\x00\x00\x00I\xb3\x97 \x00\x00\x00\x00J\xedN\x10\x00\x00\x00\x00K\x9c\xb3\xa0\x00\x00\x00\x00L\xd6j\x90\x00\x00\x00\x00M|\x95\xa0\x00\x00\x00\x00N\xb6L\x90\x00\x00\x00\x00O\x5cw\xa0\x00\x00\x00\x00P\x96.\x90\x00\x00\x00\x00Q\x8f\xde\x80\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xa4\xec\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10LMT\x00CDT\x00CST\x00CWT\x00CPT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,\xdb~\xab\xb2\x03\x00\x00\xb2\x03\x00\x00\x0f\x00\x00\x00America/YakutatTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x08\x00\x00\x00\x1e\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x877\xbf\xff\xff\xff\xff\xcb\x89(\xb0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a4 \xff\xff\xff\xff\xfe\xb8U0\xff\xff\xff\xff\xff\xa88 \x00\x00\x00\x00\x00\x9870\x00\x00\x00\x00\x01\x88\x1a \x00\x00\x00\x00\x02x\x190\x00\x00\x00\x00\x03q6\xa0\x00\x00\x00\x00\x04a5\xb0\x00\x00\x00\x00\x05Q\x18\xa0\x00\x00\x00\x00\x06A\x17\xb0\x00\x00\x00\x00\x070\xfa\xa0\x00\x00\x00\x00\x07\x8dQ\xb0\x00\x00\x00\x00\x09\x10\xdc\xa0\x00\x00\x00\x00\x09\xad\xcd0\x00\x00\x00\x00\x0a\xf0\xbe\xa0\x00\x00\x00\x00\x0b\xe0\xbd\xb0\x00\x00\x00\x00\x0c\xd9\xdb \x00\x00\x00\x00\x0d\xc0\x9f\xb0\x00\x00\x00\x00\x0e\xb9\xbd \x00\x00\x00\x00\x0f\xa9\xbc0\x00\x00\x00\x00\x10\x99\x9f \x00\x00\x00\x00\x11\x89\x9e0\x00\x00\x00\x00\x12y\x81 \x00\x00\x00\x00\x13i\x800\x00\x00\x00\x00\x14Yc \x00\x00\x00\x00\x15Ib0\x00\x00\x00\x00\x169E \x00\x00\x00\x00\x17)D0\x00\x00\x00\x00\x18\x22a\xa0\x00\x00\x00\x00\x19\x09&0\x00\x00\x00\x00\x1a\x02C\xa0\x00\x00\x00\x00\x1a+\x14\x10\x00\x00\x00\x00\x1a\xf2B\xb0\x00\x00\x00\x00\x1b\xe2%\xa0\x00\x00\x00\x00\x1c\xd2$\xb0\x00\x00\x00\x00\x1d\xc2\x07\xa0\x00\x00\x00\x00\x1e\xb2\x06\xb0\x00\x00\x00\x00\x1f\xa1\xe9\xa0\x00\x00\x00\x00 v90\x00\x00\x00\x00!\x81\xcb\xa0\x00\x00\x00\x00\x22V\x1b0\x00\x00\x00\x00#j\xe8 \x00\x00\x00\x00$5\xfd0\x00\x00\x00\x00%J\xca \x00\x00\x00\x00&\x15\xdf0\x00\x00\x00\x00'*\xac \x00\x00\x00\x00'\xfe\xfb\xb0\x00\x00\x00\x00)\x0a\x8e \x00\x00\x00\x00)\xde\xdd\xb0\x00\x00\x00\x00*\xeap \x00\x00\x00\x00+\xbe\xbf\xb0\x00\x00\x00\x00,\xd3\x8c\xa0\x00\x00\x00\x00-\x9e\xa1\xb0\x00\x00\x00\x00.\xb3n\xa0\x00\x00\x00\x00/~\x83\xb0\x00\x00\x00\x000\x93P\xa0\x00\x00\x00\x001g\xa00\x00\x00\x00\x002s2\xa0\x00\x00\x00\x003G\x820\x00\x00\x00\x004S\x14\xa0\x00\x00\x00\x005'd0\x00\x00\x00\x0062\xf6\xa0\x00\x00\x00\x007\x07F0\x00\x00\x00\x008\x1c\x13 \x00\x00\x00\x008\xe7(0\x00\x00\x00\x009\xfb\xf5 \x00\x00\x00\x00:\xc7\x0a0\x00\x00\x00\x00;\xdb\xd7 \x00\x00\x00\x00<\xb0&\xb0\x00\x00\x00\x00=\xbb\xb9 \x00\x00\x00\x00>\x90\x08\xb0\x00\x00\x00\x00?\x9b\x9b \x00\x00\x00\x00@o\xea\xb0\x00\x00\x00\x00A\x84\xb7\xa0\x00\x00\x00\x00BO\xcc\xb0\x00\x00\x00\x00Cd\x99\xa0\x00\x00\x00\x00D/\xae\xb0\x00\x00\x00\x00ED{\xa0\x00\x00\x00\x00E\xf3\xe10\x01\x02\x03\x04\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x00\x00\xce\x81\x00\x00\xff\xff}\x01\x00\x00\xff\xff\x81p\x00\x04\xff\xff\x8f\x80\x01\x08\xff\xff\x8f\x80\x01\x0c\xff\xff\x8f\x80\x01\x10\xff\xff\x8f\x80\x01\x14\xff\xff\x81p\x00\x19LMT\x00YST\x00YWT\x00YPT\x00YDT\x00AKDT\x00AKST\x00\x0aAKST9AKDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\x07\x07\xdc\xca\x03\x00\x00\xca\x03\x00\x00\x13\x00\x00\x00America/YellowknifeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x88\xde\xce\xe0\xff\xff\xff\xff\x9e\xb8\xaf\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x98\x91\x90\xff\xff\xff\xff\xa0\xd2\x85\x80\xff\xff\xff\xff\xa2\x8a\xe8\x90\xff\xff\xff\xff\xa3\x84\x06\x00\xff\xff\xff\xff\xa4j\xca\x90\xff\xff\xff\xff\xa55\xc3\x80\xff\xff\xff\xff\xa6S\xe7\x10\xff\xff\xff\xff\xa7\x15\xa5\x80\xff\xff\xff\xff\xa83\xc9\x10\xff\xff\xff\xff\xa8\xfe\xc2\x00\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xd5U\xe3\x10\xff\xff\xff\xff\xd6 \xdc\x00\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x08 \xdd\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x0a\x00\xbf\x90\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x95\xa0\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10LMT\x00MDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8\x83\xf2b\x1f\x01\x00\x00\x1f\x01\x00\x00\x10\x00\x00\x00Antarctica/CaseyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xfe\x1e\xcc\x80\x00\x00\x00\x00J\xda\x06 \x00\x00\x00\x00K\x8f\xca\xf0\x00\x00\x00\x00N\xa9\x9c \x00\x00\x00\x00OC\xcd\x90\x00\x00\x00\x00X\x0a;\x80\x00\x00\x00\x00Z\xa4\x0f\x10\x00\x00\x00\x00[\xb9\x14@\x00\x00\x00\x00\x5c\x8d\x1d\x80\x00\x00\x00\x00]\x96E0\x00\x00\x00\x00^c\xc5\x00\x00\x00\x00\x00_x\xa0<\x00\x00\x00\x00`L\xb7P\x00\x00\x00\x00aX\x82<\x00\x00\x00\x00b,\x99P\x00\x00\x00\x00c8d<\x00\x00\x00\x00d\x08\xb1\x00\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00p\x80\x00\x04\x00\x00\x9a\xb0\x00\x08-00\x00+08\x00+11\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95\xea\x06\xd3\xc5\x00\x00\x00\xc5\x00\x00\x00\x10\x00\x00\x00Antarctica/DavisTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xe7\x9c@\x00\xff\xff\xff\xff\xf6G\xdf\x10\xff\xff\xff\xff\xfeG\xab\x00\x00\x00\x00\x00J\xda\x140\x00\x00\x00\x00K\x97\xfa@\x00\x00\x00\x00N\xa9\xaa0\x00\x00\x00\x00OC\xf7\xc0\x01\x00\x01\x02\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00bp\x00\x04\x00\x00FP\x00\x08-00\x00+07\x00+05\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x19\x00\x00\x00Antarctica/DumontDUrvilleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xffV\xb6Z\x08\xff\xff\xff\xffr\xed\xa4\x90\x01\x02\x00\x00\x89\xf8\x00\x00\x00\x00\x89\xf0\x00\x04\x00\x00\x8c\xa0\x00\x09LMT\x00PMMT\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d?\xb2\x14\xd0\x03\x00\x00\xd0\x03\x00\x00\x14\x00\x00\x00Antarctica/MacquarieTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xff|\x05\x16\x00\xff\xff\xff\xff\x9b\xd5x\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xa0\x87\xb4`\xff\xff\xff\xff\xd7\x0ch\x00\xff\xff\xff\xff\xfb\xc2\x8d\x00\xff\xff\xff\xff\xfc\xb2~\x00\xff\xff\xff\xff\xfd\xc7Y\x00\xff\xff\xff\xff\xfev\xb0\x80\xff\xff\xff\xff\xff\xa7;\x00\x00\x00\x00\x00\x00V\x92\x80\x00\x00\x00\x00\x01\x87\x1d\x00\x00\x00\x00\x00\x02?\xaf\x00\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x03O\x00\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xe31\x00\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1eg'\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00&\x02_\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xf4\xb6\x00\x00\x00\x00\x00(\xed\xe1\x80\x00\x00\x00\x00)\xd4\x98\x00\x00\x00\x00\x00*\xcd\xc3\x80\x00\x00\x00\x00+\xb4z\x00\x00\x00\x00\x00,\xad\xa5\x80\x00\x00\x00\x00-\x94\x5c\x00\x00\x00\x00\x00.\x8d\x87\x80\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000mi\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002V\x86\x00\x00\x00\x00\x003=<\x80\x00\x00\x00\x0046h\x00\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x006\x16J\x00\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x007\xf6,\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xbf*\x80\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\x9f\x0c\x80\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?~\xee\x80\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A^\xd0\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00C>\xb2\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00E\x1e\x94\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G\x07\xb1\x00\x00\x00\x00\x00G\xf7\xa2\x00\x00\x00\x00\x00H\xe7\x93\x00\x00\x00\x00\x00I\xd7\x84\x00\x00\x00\x00\x00J\xc7u\x00\x00\x00\x00\x00M\x1d\xd3\xd0\x01\x02\x01\x00\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x02\x00\x00\x00\x00\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00\x9a\xb0\x01\x09-00\x00AEST\x00AEDT\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd7N\xab\x8b\x98\x00\x00\x00\x98\x00\x00\x00\x11\x00\x00\x00Antarctica/MawsonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xe2 2\x80\x00\x00\x00\x00J\xda\x22@\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00T`\x00\x04\x00\x00FP\x00\x08-00\x00+06\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x12\x00\x00\x00Antarctica/McMurdoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x06\x00\x00\x00\x13\xff\xff\xff\xffA\xb7L\xa8\xff\xff\xff\xff\xb0\xb4\xb2\xe8\xff\xff\xff\xff\xb1Q\x87X\xff\xff\xff\xff\xb2x\xe5h\xff\xff\xff\xff\xb3C\xe5`\xff\xff\xff\xff\xb4X\xc7h\xff\xff\xff\xff\xb5#\xc7`\xff\xff\xff\xff\xb68\xa9h\xff\xff\xff\xff\xb7\x03\xa9`\xff\xff\xff\xff\xb8\x18\x8bh\xff\xff\xff\xff\xb8\xec\xc5\xe0\xff\xff\xff\xff\xb9\xf8mh\xff\xff\xff\xff\xba\xcc\xa7\xe0\xff\xff\xff\xff\xbb\xd8Oh\xff\xff\xff\xff\xbc\xe3\xe8\xe0\xff\xff\xff\xff\xbd\xae\xf6\xe8\xff\xff\xff\xff\xbe\xc3\xca\xe0\xff\xff\xff\xff\xbf\x8e\xd8\xe8\xff\xff\xff\xff\xc0\xa3\xac\xe0\xff\xff\xff\xff\xc1n\xba\xe8\xff\xff\xff\xff\xc2\x83\x8e\xe0\xff\xff\xff\xff\xc3N\x9c\xe8\xff\xff\xff\xff\xc4cp\xe0\xff\xff\xff\xff\xc5.~\xe8\xff\xff\xff\xff\xc6L\x8d`\xff\xff\xff\xff\xc7\x0e`\xe8\xff\xff\xff\xff\xc8,o`\xff\xff\xff\xff\xc8\xf7}h\xff\xff\xff\xff\xd2\xda\x9a@\x00\x00\x00\x00\x09\x18\xfd\xe0\x00\x00\x00\x00\x09\xac\xa5\xe0\x00\x00\x00\x00\x0a\xef\xa5`\x00\x00\x00\x00\x0b\x9e\xfc\xe0\x00\x00\x00\x00\x0c\xd8\xc1\xe0\x00\x00\x00\x00\x0d~\xde\xe0\x00\x00\x00\x00\x0e\xb8\xa3\xe0\x00\x00\x00\x00\x0f^\xc0\xe0\x00\x00\x00\x00\x10\x98\x85\xe0\x00\x00\x00\x00\x11>\xa2\xe0\x00\x00\x00\x00\x12xg\xe0\x00\x00\x00\x00\x13\x1e\x84\xe0\x00\x00\x00\x00\x14XI\xe0\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168+\xe0\x00\x00\x00\x00\x16\xe7\x83`\x00\x00\x00\x00\x18!H`\x00\x00\x00\x00\x18\xc7e`\x00\x00\x00\x00\x1a\x01*`\x00\x00\x00\x00\x1a\xa7G`\x00\x00\x00\x00\x1b\xe1\x0c`\x00\x00\x00\x00\x1c\x87)`\x00\x00\x00\x00\x1d\xc0\xee`\x00\x00\x00\x00\x1eg\x0b`\x00\x00\x00\x00\x1f\xa0\xd0`\x00\x00\x00\x00 F\xed`\x00\x00\x00\x00!\x80\xb2`\x00\x00\x00\x00\x220\x09\xe0\x00\x00\x00\x00#i\xce\xe0\x00\x00\x00\x00$\x0f\xeb\xe0\x00\x00\x00\x00%.\x01`\x00\x00\x00\x00&\x02B\xe0\x00\x00\x00\x00'\x0d\xe3`\x00\x00\x00\x00'\xe2$\xe0\x00\x00\x00\x00(\xed\xc5`\x00\x00\x00\x00)\xc2\x06\xe0\x00\x00\x00\x00*\xcd\xa7`\x00\x00\x00\x00+\xab#`\x00\x00\x00\x00,\xad\x89`\x00\x00\x00\x00-\x8b\x05`\x00\x00\x00\x00.\x8dk`\x00\x00\x00\x00/j\xe7`\x00\x00\x00\x000mM`\x00\x00\x00\x001J\xc9`\x00\x00\x00\x002Vi\xe0\x00\x00\x00\x003*\xab`\x00\x00\x00\x0046K\xe0\x00\x00\x00\x005\x0a\x8d`\x00\x00\x00\x006\x16-\xe0\x00\x00\x00\x006\xf3\xa9\xe0\x00\x00\x00\x007\xf6\x0f\xe0\x00\x00\x00\x008\xd3\x8b\xe0\x00\x00\x00\x009\xd5\xf1\xe0\x00\x00\x00\x00:\xb3m\xe0\x00\x00\x00\x00;\xbf\x0e`\x00\x00\x00\x00<\x93O\xe0\x00\x00\x00\x00=\x9e\xf0`\x00\x00\x00\x00>s1\xe0\x00\x00\x00\x00?~\xd2`\x00\x00\x00\x00@\x5cN`\x00\x00\x00\x00A^\xb4`\x00\x00\x00\x00B<0`\x00\x00\x00\x00C>\x96`\x00\x00\x00\x00D\x1c\x12`\x00\x00\x00\x00E\x1ex`\x00\x00\x00\x00E\xfb\xf4`\x00\x00\x00\x00F\xfeZ`\x02\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x00\x00\xa3\xd8\x00\x00\x00\x00\xaf\xc8\x01\x04\x00\x00\xa1\xb8\x00\x09\x00\x00\xa8\xc0\x01\x04\x00\x00\xb6\xd0\x01\x0e\x00\x00\xa8\xc0\x00\x04LMT\x00NZST\x00NZMT\x00NZDT\x00\x0aNZST-12NZDT,M9.5.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95{\xf3\xa9w\x03\x00\x00w\x03\x00\x00\x11\x00\x00\x00Antarctica/PalmerTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xf6\x98\xad\x00\xff\xff\xff\xff\xf6\xe6\x9f\xb0\xff\xff\xff\xff\xf8\x13C\xc0\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xf9\xf4w@\xff\xff\xff\xff\xfa\xd36\xb0\xff\xff\xff\xff\xfb\xc35\xc0\xff\xff\xff\xff\xfc\xbcS0\xff\xff\xff\xff\xfd\xacR@\xff\xff\xff\xff\xfe\x9c50\xff\xff\xff\xff\xff\x8c4@\x00\x00\x00\x00\x07\xa3J\xb0\x00\x00\x00\x00\x08$o\xa0\x00\x00\x00\x00\x170\xbc\xb0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x18\xd1V\xb0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xb18\xb0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\x91\x1a\xb0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ep\xfc\xb0\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 \x7f\x030\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x229\xfb0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$\x19\xdd0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xf9\xbf0\x00\x00\x00\x00&\xf2\xf8\xc0\x00\x00\x00\x00'\xd9\xa10\x00\x00\x00\x00(\xf7\xc4\xc0\x00\x00\x00\x00)\xc2\xbd\xb0\x00\x00\x00\x00*\xd7\xa6\xc0\x00\x00\x00\x00+\xa2\x9f\xb0\x00\x00\x00\x00,\xb7\x88\xc0\x00\x00\x00\x00-\x82\x81\xb0\x00\x00\x00\x00.\x97j\xc0\x00\x00\x00\x00/bc\xb0\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001BE\xb0\x00\x00\x00\x002`i@\x00\x00\x00\x003=\xd70\x00\x00\x00\x004@K@\x00\x00\x00\x005\x0bD0\x00\x00\x00\x006\x0d\xb8@\x00\x00\x00\x007\x06\xd5\xb0\x00\x00\x00\x008\x00\x0f@\x00\x00\x00\x008\xcb\x080\x00\x00\x00\x009\xe9+\xc0\x00\x00\x00\x00:\xaa\xea0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00<\x8a\xcc0\x00\x00\x00\x00=\xa8\xef\xc0\x00\x00\x00\x00>j\xae0\x00\x00\x00\x00?\x88\xd1\xc0\x00\x00\x00\x00@S\xca\xb0\x00\x00\x00\x00Ah\xb3\xc0\x00\x00\x00\x00B3\xac\xb0\x00\x00\x00\x00CH\x95\xc0\x00\x00\x00\x00D\x13\x8e\xb0\x00\x00\x00\x00E1\xb2@\x00\x00\x00\x00E\xf3p\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xef\x020\x00\x00\x00\x00H\xf1v@\x00\x00\x00\x00I\xbco0\x00\x00\x00\x00J\xd1X@\x00\x00\x00\x00K\xb8\x00\xb0\x00\x00\x00\x00L\xb1:@\x00\x00\x00\x00M\xc6\x070\x00\x00\x00\x00NP\x82\xc0\x00\x00\x00\x00O\x9c\xae\xb0\x00\x00\x00\x00PB\xd9\xc0\x00\x00\x00\x00Q|\x90\xb0\x00\x00\x00\x00R+\xf6@\x00\x00\x00\x00S\x5cr\xb0\x00\x00\x00\x00T\x0b\xd8@\x00\x00\x00\x00W7\xe60\x00\x00\x00\x00W\xaf\xec\xc0\x00\x00\x00\x00XC\x86\xb0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x03\x04\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x04\x00\x00\x00\x00\x00\x00\xff\xff\xc7\xc0\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xe3\xe0\x01\x0c\xff\xff\xd5\xd0\x00\x08-00\x00-04\x00-03\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6\x89\xf71\x84\x00\x00\x00\x84\x00\x00\x00\x12\x00\x00\x00Antarctica/RotheraTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\x00\x00\x00\x00\x0d\x02-\x00\x01\x00\x00\x00\x00\x00\x00\xff\xff\xd5\xd0\x00\x04-00\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x15\x00\x00\x00Antarctica/South_PoleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x06\x00\x00\x00\x13\xff\xff\xff\xffA\xb7L\xa8\xff\xff\xff\xff\xb0\xb4\xb2\xe8\xff\xff\xff\xff\xb1Q\x87X\xff\xff\xff\xff\xb2x\xe5h\xff\xff\xff\xff\xb3C\xe5`\xff\xff\xff\xff\xb4X\xc7h\xff\xff\xff\xff\xb5#\xc7`\xff\xff\xff\xff\xb68\xa9h\xff\xff\xff\xff\xb7\x03\xa9`\xff\xff\xff\xff\xb8\x18\x8bh\xff\xff\xff\xff\xb8\xec\xc5\xe0\xff\xff\xff\xff\xb9\xf8mh\xff\xff\xff\xff\xba\xcc\xa7\xe0\xff\xff\xff\xff\xbb\xd8Oh\xff\xff\xff\xff\xbc\xe3\xe8\xe0\xff\xff\xff\xff\xbd\xae\xf6\xe8\xff\xff\xff\xff\xbe\xc3\xca\xe0\xff\xff\xff\xff\xbf\x8e\xd8\xe8\xff\xff\xff\xff\xc0\xa3\xac\xe0\xff\xff\xff\xff\xc1n\xba\xe8\xff\xff\xff\xff\xc2\x83\x8e\xe0\xff\xff\xff\xff\xc3N\x9c\xe8\xff\xff\xff\xff\xc4cp\xe0\xff\xff\xff\xff\xc5.~\xe8\xff\xff\xff\xff\xc6L\x8d`\xff\xff\xff\xff\xc7\x0e`\xe8\xff\xff\xff\xff\xc8,o`\xff\xff\xff\xff\xc8\xf7}h\xff\xff\xff\xff\xd2\xda\x9a@\x00\x00\x00\x00\x09\x18\xfd\xe0\x00\x00\x00\x00\x09\xac\xa5\xe0\x00\x00\x00\x00\x0a\xef\xa5`\x00\x00\x00\x00\x0b\x9e\xfc\xe0\x00\x00\x00\x00\x0c\xd8\xc1\xe0\x00\x00\x00\x00\x0d~\xde\xe0\x00\x00\x00\x00\x0e\xb8\xa3\xe0\x00\x00\x00\x00\x0f^\xc0\xe0\x00\x00\x00\x00\x10\x98\x85\xe0\x00\x00\x00\x00\x11>\xa2\xe0\x00\x00\x00\x00\x12xg\xe0\x00\x00\x00\x00\x13\x1e\x84\xe0\x00\x00\x00\x00\x14XI\xe0\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168+\xe0\x00\x00\x00\x00\x16\xe7\x83`\x00\x00\x00\x00\x18!H`\x00\x00\x00\x00\x18\xc7e`\x00\x00\x00\x00\x1a\x01*`\x00\x00\x00\x00\x1a\xa7G`\x00\x00\x00\x00\x1b\xe1\x0c`\x00\x00\x00\x00\x1c\x87)`\x00\x00\x00\x00\x1d\xc0\xee`\x00\x00\x00\x00\x1eg\x0b`\x00\x00\x00\x00\x1f\xa0\xd0`\x00\x00\x00\x00 F\xed`\x00\x00\x00\x00!\x80\xb2`\x00\x00\x00\x00\x220\x09\xe0\x00\x00\x00\x00#i\xce\xe0\x00\x00\x00\x00$\x0f\xeb\xe0\x00\x00\x00\x00%.\x01`\x00\x00\x00\x00&\x02B\xe0\x00\x00\x00\x00'\x0d\xe3`\x00\x00\x00\x00'\xe2$\xe0\x00\x00\x00\x00(\xed\xc5`\x00\x00\x00\x00)\xc2\x06\xe0\x00\x00\x00\x00*\xcd\xa7`\x00\x00\x00\x00+\xab#`\x00\x00\x00\x00,\xad\x89`\x00\x00\x00\x00-\x8b\x05`\x00\x00\x00\x00.\x8dk`\x00\x00\x00\x00/j\xe7`\x00\x00\x00\x000mM`\x00\x00\x00\x001J\xc9`\x00\x00\x00\x002Vi\xe0\x00\x00\x00\x003*\xab`\x00\x00\x00\x0046K\xe0\x00\x00\x00\x005\x0a\x8d`\x00\x00\x00\x006\x16-\xe0\x00\x00\x00\x006\xf3\xa9\xe0\x00\x00\x00\x007\xf6\x0f\xe0\x00\x00\x00\x008\xd3\x8b\xe0\x00\x00\x00\x009\xd5\xf1\xe0\x00\x00\x00\x00:\xb3m\xe0\x00\x00\x00\x00;\xbf\x0e`\x00\x00\x00\x00<\x93O\xe0\x00\x00\x00\x00=\x9e\xf0`\x00\x00\x00\x00>s1\xe0\x00\x00\x00\x00?~\xd2`\x00\x00\x00\x00@\x5cN`\x00\x00\x00\x00A^\xb4`\x00\x00\x00\x00B<0`\x00\x00\x00\x00C>\x96`\x00\x00\x00\x00D\x1c\x12`\x00\x00\x00\x00E\x1ex`\x00\x00\x00\x00E\xfb\xf4`\x00\x00\x00\x00F\xfeZ`\x02\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x00\x00\xa3\xd8\x00\x00\x00\x00\xaf\xc8\x01\x04\x00\x00\xa1\xb8\x00\x09\x00\x00\xa8\xc0\x01\x04\x00\x00\xb6\xd0\x01\x0e\x00\x00\xa8\xc0\x00\x04LMT\x00NZST\x00NZMT\x00NZDT\x00\x0aNZST-12NZDT,M9.5.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xd7\x87\xe1\x85\x00\x00\x00\x85\x00\x00\x00\x10\x00\x00\x00Antarctica/SyowaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xd5\x1b6\xb4\x01\x00\x00+\xcc\x00\x00\x00\x00*0\x00\x04LMT\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf54\x89F\x9e\x00\x00\x00\x9e\x00\x00\x00\x10\x00\x00\x00Antarctica/TrollTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\x00\x00\x00\x00B\x0dG\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04-00\x00+00\x00\x0a<+00>0<+02>-2,M3.5.0/1,M10.5.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x16\xf4\xe0\xaa\x00\x00\x00\xaa\x00\x00\x00\x11\x00\x00\x00Antarctica/VostokTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xe9X\x89\x80\x00\x00\x00\x00-M9\x10\x00\x00\x00\x00.\xb5\x85\x00\x00\x00\x00\x00e\x7fE0\x01\x00\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00bp\x00\x04\x00\x00FP\x00\x08-00\x00+07\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17S\x91\xb3\xc1\x02\x00\x00\xc1\x02\x00\x00\x13\x00\x00\x00Arctic/LongyearbyenTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\x09q\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd1\xb6\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xff\xd2\xa1O\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xff\xd5\xa8s\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c9f;j\x02\x00\x00j\x02\x00\x00\x0b\x00\x00\x00Asia/AlmatyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19{\xdc\xff\xff\xff\xff\xb5\xa3\xef0\x00\x00\x00\x00\x15'}\xa0\x00\x00\x00\x00\x16\x18\xb2\x10\x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xe5\x90\x00\x00\x00\x00\x18\xe9\xe4\xa0\x00\x00\x00\x00\x19\xdb\x19\x10\x00\x00\x00\x00\x1a\xcci\xa0\x00\x00\x00\x00\x1b\xbcv\xc0\x00\x00\x00\x00\x1c\xacg\xc0\x00\x00\x00\x00\x1d\x9cX\xc0\x00\x00\x00\x00\x1e\x8cI\xc0\x00\x00\x00\x00\x1f|:\xc0\x00\x00\x00\x00 l+\xc0\x00\x00\x00\x00!\x5c\x1c\xc0\x00\x00\x00\x00\x22L\x0d\xc0\x00\x00\x00\x00#;\xfe\xc0\x00\x00\x00\x00$+\xef\xc0\x00\x00\x00\x00%\x1b\xe0\xc0\x00\x00\x00\x00&\x0b\xd1\xc0\x00\x00\x00\x00'\x04\xfd@\x00\x00\x00\x00'\xf4\xee@\x00\x00\x00\x00(\xe4\xedP\x00\x00\x00\x00)x\x95P\x00\x00\x00\x00)\xd4\xd0@\x00\x00\x00\x00*\xc4\xc1@\x00\x00\x00\x00+\xb4\xb2@\x00\x00\x00\x00,\xa4\xa3@\x00\x00\x00\x00-\x94\x94@\x00\x00\x00\x00.\x84\x85@\x00\x00\x00\x00/tv@\x00\x00\x00\x000dg@\x00\x00\x00\x001]\x92\xc0\x00\x00\x00\x002rm\xc0\x00\x00\x00\x003=t\xc0\x00\x00\x00\x004RO\xc0\x00\x00\x00\x005\x1dV\xc0\x00\x00\x00\x00621\xc0\x00\x00\x00\x006\xfd8\xc0\x00\x00\x00\x008\x1bN@\x00\x00\x00\x008\xdd\x1a\xc0\x00\x00\x00\x009\xfb0@\x00\x00\x00\x00:\xbc\xfc\xc0\x00\x00\x00\x00;\xdb\x12@\x00\x00\x00\x00<\xa6\x19@\x00\x00\x00\x00=\xba\xf4@\x00\x00\x00\x00>\x85\xfb@\x00\x00\x00\x00?\x9a\xd6@\x00\x00\x00\x00@e\xdd@\x00\x00\x00\x00A\x83\xf2\xc0\x00\x00\x00\x00e\xe0\xc6 \x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x01\x00\x00H$\x00\x00\x00\x00FP\x00\x04\x00\x00bp\x01\x08\x00\x00T`\x00\x0c\x00\x00T`\x01\x0cLMT\x00+05\x00+07\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf\x0ds\xad\xa0\x03\x00\x00\xa0\x03\x00\x00\x0a\x00\x00\x00Asia/AmmanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xb6\xa3\xd6\xd0\x00\x00\x00\x00\x06ry\xe0\x00\x00\x00\x00\x07\x0c\xabP\x00\x00\x00\x00\x08$7`\x00\x00\x00\x00\x08\xed\xde\xd0\x00\x00\x00\x00\x0a\x05j\xe0\x00\x00\x00\x00\x0a\xcf\x12P\x00\x00\x00\x00\x0b\xe7\xef\xe0\x00\x00\x00\x00\x0c\xdau\xd0\x00\x00\x00\x00\x0d\xc9#`\x00\x00\x00\x00\x0e\x92\xca\xd0\x00\x00\x00\x00\x0f\xa9\x05`\x00\x00\x00\x00\x10r\xac\xd0\x00\x00\x00\x00\x1c\xad\xd5`\x00\x00\x00\x00\x1d\x9f\x09\xd0\x00\x00\x00\x00\x1e\x92\xfd`\x00\x00\x00\x00\x1f\x82\xe0P\x00\x00\x00\x00 r\xdf`\x00\x00\x00\x00!b\xc2P\x00\x00\x00\x00\x22R\xc1`\x00\x00\x00\x00#K\xde\xd0\x00\x00\x00\x00$d\xbc`\x00\x00\x00\x00%+\xc0\xd0\x00\x00\x00\x00&7o`\x00\x00\x00\x00'\x0b\xa2\xd0\x00\x00\x00\x00(\x0bs\xe0\x00\x00\x00\x00(\xe2JP\x00\x00\x00\x00)\xe4\xbe`\x00\x00\x00\x00*\xcbf\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\xabH\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00.x\xb5\xd0\x00\x00\x00\x00/\x84d`\x00\x00\x00\x000X\xa5\xe0\x00\x00\x00\x001dF`\x00\x00\x00\x002A\xc2`\x00\x00\x00\x003D(`\x00\x00\x00\x004!\xa4`\x00\x00\x00\x005$\x0a`\x00\x00\x00\x006\x01\x86`\x00\x00\x00\x007z\x93`\x00\x00\x00\x007\xea\xa2\xe0\x00\x00\x00\x008\xe2|\xe0\x00\x00\x00\x009\xd3\xbf`\x00\x00\x00\x00:\xc2^\xe0\x00\x00\x00\x00;\xb3\xa1`\x00\x00\x00\x00<\xa3\x92`\x00\x00\x00\x00=\x93\x83`\x00\x00\x00\x00>\x83t`\x00\x00\x00\x00?\x98O`\x00\x00\x00\x00@cV`\x00\x00\x00\x00An\xf6\xe0\x00\x00\x00\x00BLr\xe0\x00\x00\x00\x00C-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\xe0\xe7!\xe7\x02\x00\x00\xe7\x02\x00\x00\x0b\x00\x00\x00Asia/AnadyrTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x07\x00\x00\x00\x14\xff\xff\xff\xff\xaa\x19\x1d\x9c\xff\xff\xff\xff\xb5\xa3\x8c\xc0\x00\x00\x00\x00\x15'\x1b0\x00\x00\x00\x00\x16\x18O\xa0\x00\x00\x00\x00\x17\x08N\xb0\x00\x00\x00\x00\x17\xf9\x910\x00\x00\x00\x00\x18\xe9\x90@\x00\x00\x00\x00\x19\xda\xc4\xb0\x00\x00\x00\x00\x1a\xcc\x15@\x00\x00\x00\x00\x1b\xbc\x22`\x00\x00\x00\x00\x1c\xac\x13`\x00\x00\x00\x00\x1d\x9c\x04`\x00\x00\x00\x00\x1e\x8b\xf5`\x00\x00\x00\x00\x1f{\xe6`\x00\x00\x00\x00 k\xd7`\x00\x00\x00\x00![\xc8`\x00\x00\x00\x00\x22K\xb9`\x00\x00\x00\x00#;\xaa`\x00\x00\x00\x00$+\x9b`\x00\x00\x00\x00%\x1b\x8c`\x00\x00\x00\x00&\x0b}`\x00\x00\x00\x00'\x04\xa8\xe0\x00\x00\x00\x00'\xf4\x99\xe0\x00\x00\x00\x00(\xe4\x98\xf0\x00\x00\x00\x00)x@\xf0\x00\x00\x00\x00)\xd4{\xe0\x00\x00\x00\x00*\xc4l\xe0\x00\x00\x00\x00+\xb4]\xe0\x00\x00\x00\x00,\xa4N\xe0\x00\x00\x00\x00-\x94?\xe0\x00\x00\x00\x00.\x840\xe0\x00\x00\x00\x00/t!\xe0\x00\x00\x00\x000d\x12\xe0\x00\x00\x00\x001]>`\x00\x00\x00\x002r\x19`\x00\x00\x00\x003= `\x00\x00\x00\x004Q\xfb`\x00\x00\x00\x005\x1d\x02`\x00\x00\x00\x0061\xdd`\x00\x00\x00\x006\xfc\xe4`\x00\x00\x00\x008\x1a\xf9\xe0\x00\x00\x00\x008\xdc\xc6`\x00\x00\x00\x009\xfa\xdb\xe0\x00\x00\x00\x00:\xbc\xa8`\x00\x00\x00\x00;\xda\xbd\xe0\x00\x00\x00\x00<\xa5\xc4\xe0\x00\x00\x00\x00=\xba\x9f\xe0\x00\x00\x00\x00>\x85\xa6\xe0\x00\x00\x00\x00?\x9a\x81\xe0\x00\x00\x00\x00@e\x88\xe0\x00\x00\x00\x00A\x83\x9e`\x00\x00\x00\x00BEj\xe0\x00\x00\x00\x00Cc\x80`\x00\x00\x00\x00D%L\xe0\x00\x00\x00\x00ECb`\x00\x00\x00\x00F\x05.\xe0\x00\x00\x00\x00G#D`\x00\x00\x00\x00G\xeeK`\x00\x00\x00\x00I\x03&`\x00\x00\x00\x00I\xce-`\x00\x00\x00\x00J\xe3\x08`\x00\x00\x00\x00K\xae\x0f`\x00\x00\x00\x00L\xcc2\xf0\x00\x00\x00\x00M\x8d\xffp\x01\x03\x02\x03\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x05\x06\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x05\x06\x01\x00\x00\xa6d\x00\x00\x00\x00\xa8\xc0\x00\x04\x00\x00\xc4\xe0\x01\x08\x00\x00\xb6\xd0\x00\x0c\x00\x00\xb6\xd0\x01\x0c\x00\x00\xa8\xc0\x01\x04\x00\x00\x9a\xb0\x00\x10LMT\x00+12\x00+14\x00+13\x00+11\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x81\x18G^\x02\x00\x00^\x02\x00\x00\x0a\x00\x00\x00Asia/AqtauTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x94\xe0\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x00\x00\x00\x00)\xd4\xdeP\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xc0P\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xa2P\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000d\x83`\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002r\x89\xe0\x00\x00\x00\x003=\x90\xe0\x00\x00\x00\x004Rk\xe0\x00\x00\x00\x005\x1dr\xe0\x00\x00\x00\x0062M\xe0\x00\x00\x00\x006\xfdT\xe0\x00\x00\x00\x008\x1bj`\x00\x00\x00\x008\xdd6\xe0\x00\x00\x00\x009\xfbL`\x00\x00\x00\x00:\xbd\x18\xe0\x00\x00\x00\x00;\xdb.`\x00\x00\x00\x00<\xa65`\x00\x00\x00\x00=\xbb\x10`\x00\x00\x00\x00>\x86\x17`\x00\x00\x00\x00?\x9a\xf2`\x00\x00\x00\x00@e\xf9`\x00\x00\x00\x00A\x84\x0e\xe0\x01\x02\x03\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x05\x01\x02\x04\x02\x04\x02\x04\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x02\x00\x00/ \x00\x00\x00\x008@\x00\x04\x00\x00FP\x00\x08\x00\x00T`\x00\x0c\x00\x00T`\x01\x0c\x00\x00FP\x01\x08LMT\x00+04\x00+05\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdb\xfa\xb5\xbeg\x02\x00\x00g\x02\x00\x00\x0b\x00\x00\x00Asia/AqtobeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x8eh\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x00\x00\x00\x00)\xd4\xdeP\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xc0P\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xa2P\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x84P\x00\x00\x00\x000duP\x00\x00\x00\x001]\xa0\xd0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x003=\x82\xd0\x00\x00\x00\x004R]\xd0\x00\x00\x00\x005\x1dd\xd0\x00\x00\x00\x0062?\xd0\x00\x00\x00\x006\xfdF\xd0\x00\x00\x00\x008\x1b\x5cP\x00\x00\x00\x008\xdd(\xd0\x00\x00\x00\x009\xfb>P\x00\x00\x00\x00:\xbd\x0a\xd0\x00\x00\x00\x00;\xdb P\x00\x00\x00\x00<\xa6'P\x00\x00\x00\x00=\xbb\x02P\x00\x00\x00\x00>\x86\x09P\x00\x00\x00\x00?\x9a\xe4P\x00\x00\x00\x00@e\xebP\x00\x00\x00\x00A\x84\x00\xd0\x01\x02\x03\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x005\x98\x00\x00\x00\x008@\x00\x04\x00\x00FP\x00\x08\x00\x00T`\x01\x0c\x00\x00T`\x00\x0c\x00\x00FP\x01\x08LMT\x00+04\x00+05\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\x1bb2w\x01\x00\x00w\x01\x00\x00\x0d\x00\x00\x00Asia/AshgabatTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x8dD\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xbf0\x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x00\x006\xbc\x00\x00\x00\x008@\x00\x04\x00\x00T`\x01\x08\x00\x00FP\x00\x0c\x00\x00FP\x01\x0cLMT\x00+04\x00+06\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\x1bb2w\x01\x00\x00w\x01\x00\x00\x0e\x00\x00\x00Asia/AshkhabadTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x8dD\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xbf0\x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x00\x006\xbc\x00\x00\x00\x008@\x00\x04\x00\x00T`\x01\x08\x00\x00FP\x00\x0c\x00\x00FP\x01\x0cLMT\x00+04\x00+06\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xa7^\xfah\x02\x00\x00h\x02\x00\x00\x0b\x00\x00\x00Asia/AtyrauTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x00\x00\x00\x07\x00\x00\x00\x14\xff\xff\xff\xff\xaa\x19\x93P\xff\xff\xff\xff\xb5\xa4\x0bP\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x00\x00\x00\x00)\xd4\xdeP\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xc0P\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xa2P\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x84P\x00\x00\x00\x000duP\x00\x00\x00\x001]\xa0\xd0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x003=\x82\xd0\x00\x00\x00\x004R]\xd0\x00\x00\x00\x005\x1dd\xd0\x00\x00\x00\x0062?\xd0\x00\x00\x00\x006\xfdF\xd0\x00\x00\x00\x008\x1bj`\x00\x00\x00\x008\xdd6\xe0\x00\x00\x00\x009\xfbL`\x00\x00\x00\x00:\xbd\x18\xe0\x00\x00\x00\x00;\xdb.`\x00\x00\x00\x00<\xa65`\x00\x00\x00\x00=\xbb\x10`\x00\x00\x00\x00>\x86\x17`\x00\x00\x00\x00?\x9a\xf2`\x00\x00\x00\x00@e\xf9`\x00\x00\x00\x00A\x84\x0e\xe0\x01\x02\x03\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x05\x06\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x02\x00\x000\xb0\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x00\x08\x00\x00T`\x00\x0c\x00\x00T`\x01\x0c\x00\x00FP\x01\x08\x00\x008@\x00\x10LMT\x00+03\x00+05\x00+06\x00+04\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd7e&uv\x02\x00\x00v\x02\x00\x00\x0c\x00\x00\x00Asia/BaghdadTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffi\x86\xb1\xdc\xff\xff\xff\xff\x9e0<\xe0\x00\x00\x00\x00\x170hP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xe8\xbdP\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbd\xc8@\x00\x00\x00\x00\x1c\xad\xc7P\x00\x00\x00\x00\x1d\x9ct\xe0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|V\xe0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c8\xe0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x1a\xe0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1b\xfc\xe0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x19`\x00\x00\x00\x00'\xf6x\x00\x00\x00\x00\x00(\xe7\xba\x80\x00\x00\x00\x00)\xd8\xfd\x00\x00\x00\x00\x00*\xca?\x80\x00\x00\x00\x00+\xba0\x80\x00\x00\x00\x00,\xabs\x00\x00\x00\x00\x00-\x9bd\x00\x00\x00\x00\x00.\x8c\xa6\x80\x00\x00\x00\x00/|\x97\x80\x00\x00\x00\x000m\xda\x00\x00\x00\x00\x001_\x1c\x80\x00\x00\x00\x002P_\x00\x00\x00\x00\x003@P\x00\x00\x00\x00\x0041\x92\x80\x00\x00\x00\x005!\x83\x80\x00\x00\x00\x006\x12\xc6\x00\x00\x00\x00\x007\x02\xb7\x00\x00\x00\x00\x007\xf3\xf9\x80\x00\x00\x00\x008\xe5<\x00\x00\x00\x00\x009\xd6~\x80\x00\x00\x00\x00:\xc6o\x80\x00\x00\x00\x00;\xb7\xb2\x00\x00\x00\x00\x00<\xa7\xa3\x00\x00\x00\x00\x00=\x98\xe5\x80\x00\x00\x00\x00>\x88\xd6\x80\x00\x00\x00\x00?z\x19\x00\x00\x00\x00\x00@k[\x80\x00\x00\x00\x00A\x5c\x9e\x00\x00\x00\x00\x00BL\x8f\x00\x00\x00\x00\x00C=\xd1\x80\x00\x00\x00\x00D-\xc2\x80\x00\x00\x00\x00E\x1f\x05\x00\x00\x00\x00\x00F\x0e\xf6\x00\x00\x00\x00\x00G\x008\x80\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x00)\xa4\x00\x00\x00\x00)\xa0\x00\x04\x00\x00*0\x00\x08\x00\x008@\x01\x0cLMT\x00BMT\x00+03\x00+04\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdav\x19z\x98\x00\x00\x00\x98\x00\x00\x00\x0c\x00\x00\x00Asia/BahrainTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xa1\xf2\x9d0\x00\x00\x00\x00\x04\x8a\x92\xc0\x01\x02\x00\x000P\x00\x00\x00\x008@\x00\x04\x00\x00*0\x00\x08LMT\x00+04\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x87\xb3<\xe8\x02\x00\x00\xe8\x02\x00\x00\x09\x00\x00\x00Asia/BakuTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x95D\xff\xff\xff\xff\xe7\xda\x0cP\x00\x00\x00\x00\x15'\x99\xc0\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xcd@\x00\x00\x00\x00\x17\xfa\x01\xb0\x00\x00\x00\x00\x18\xea\x00\xc0\x00\x00\x00\x00\x19\xdb50\x00\x00\x00\x00\x1a\xcc\x85\xc0\x00\x00\x00\x00\x1b\xbc\x92\xe0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9ct\xe0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|V\xe0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c8\xe0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x1a\xe0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1b\xfc\xe0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x19`\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe5\x09p\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x001]\xd9\x10\x00\x00\x00\x002r\xb4\x10\x00\x00\x00\x003=\xad\x00\x00\x00\x00\x004R\x88\x00\x00\x00\x00\x005\x1d\x8f\x00\x00\x00\x00\x0062j\x00\x00\x00\x00\x006\xfdq\x00\x00\x00\x00\x008\x1b\x86\x80\x00\x00\x00\x008\xddS\x00\x00\x00\x00\x009\xfbh\x80\x00\x00\x00\x00:\xbd5\x00\x00\x00\x00\x00;\xdbJ\x80\x00\x00\x00\x00<\xa6Q\x80\x00\x00\x00\x00=\xbb,\x80\x00\x00\x00\x00>\x863\x80\x00\x00\x00\x00?\x9b\x0e\x80\x00\x00\x00\x00@f\x15\x80\x00\x00\x00\x00A\x84+\x00\x00\x00\x00\x00BE\xf7\x80\x00\x00\x00\x00Cd\x0d\x00\x00\x00\x00\x00D%\xd9\x80\x00\x00\x00\x00EC\xef\x00\x00\x00\x00\x00F\x05\xbb\x80\x00\x00\x00\x00G#\xd1\x00\x00\x00\x00\x00G\xee\xd8\x00\x00\x00\x00\x00I\x03\xb3\x00\x00\x00\x00\x00I\xce\xba\x00\x00\x00\x00\x00J\xe3\x95\x00\x00\x00\x00\x00K\xae\x9c\x00\x00\x00\x00\x00L\xcc\xb1\x80\x00\x00\x00\x00M\x8e~\x00\x00\x00\x00\x00N\xac\x93\x80\x00\x00\x00\x00On`\x00\x00\x00\x00\x00P\x8cu\x80\x00\x00\x00\x00QW|\x80\x00\x00\x00\x00RlW\x80\x00\x00\x00\x00S7^\x80\x00\x00\x00\x00TL9\x80\x00\x00\x00\x00U\x17@\x80\x00\x00\x00\x00V,\x1b\x80\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00.\xbc\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x01\x08\x00\x008@\x00\x0c\x00\x008@\x01\x0cLMT\x00+03\x00+05\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x0c\x00\x00\x00Asia/BangkokTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffV\xb6\x85\xc4\xff\xff\xff\xff\xa2jg\xc4\x01\x02\x00\x00^<\x00\x00\x00\x00^<\x00\x04\x00\x00bp\x00\x08LMT\x00BMT\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87\xbd\xedL\xf1\x02\x00\x00\xf1\x02\x00\x00\x0c\x00\x00\x00Asia/BarnaulTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xd5}\xfc\xff\xff\xff\xff\xb5\xa3\xe1 \x00\x00\x00\x00\x15'o\x90\x00\x00\x00\x00\x16\x18\xa4\x00\x00\x00\x00\x00\x17\x08\xa3\x10\x00\x00\x00\x00\x17\xf9\xd7\x80\x00\x00\x00\x00\x18\xe9\xd6\x90\x00\x00\x00\x00\x19\xdb\x0b\x00\x00\x00\x00\x00\x1a\xcc[\x90\x00\x00\x00\x00\x1b\xbch\xb0\x00\x00\x00\x00\x1c\xacY\xb0\x00\x00\x00\x00\x1d\x9cJ\xb0\x00\x00\x00\x00\x1e\x8c;\xb0\x00\x00\x00\x00\x1f|,\xb0\x00\x00\x00\x00 l\x1d\xb0\x00\x00\x00\x00!\x5c\x0e\xb0\x00\x00\x00\x00\x22K\xff\xb0\x00\x00\x00\x00#;\xf0\xb0\x00\x00\x00\x00$+\xe1\xb0\x00\x00\x00\x00%\x1b\xd2\xb0\x00\x00\x00\x00&\x0b\xc3\xb0\x00\x00\x00\x00'\x04\xef0\x00\x00\x00\x00'\xf4\xe00\x00\x00\x00\x00(\xe4\xdf@\x00\x00\x00\x00)x\x87@\x00\x00\x00\x00)\xd4\xc20\x00\x00\x00\x00*\xc4\xb30\x00\x00\x00\x00+\xb4\xa40\x00\x00\x00\x00,\xa4\x950\x00\x00\x00\x00-\x94\x860\x00\x00\x00\x00.\x84w0\x00\x00\x00\x00/th0\x00\x00\x00\x00/\xc7L\x80\x00\x00\x00\x000dg@\x00\x00\x00\x001]\x92\xc0\x00\x00\x00\x002rm\xc0\x00\x00\x00\x003=t\xc0\x00\x00\x00\x004RO\xc0\x00\x00\x00\x005\x1dV\xc0\x00\x00\x00\x00621\xc0\x00\x00\x00\x006\xfd8\xc0\x00\x00\x00\x008\x1bN@\x00\x00\x00\x008\xdd\x1a\xc0\x00\x00\x00\x009\xfb0@\x00\x00\x00\x00:\xbc\xfc\xc0\x00\x00\x00\x00;\xdb\x12@\x00\x00\x00\x00<\xa6\x19@\x00\x00\x00\x00=\xba\xf4@\x00\x00\x00\x00>\x85\xfb@\x00\x00\x00\x00?\x9a\xd6@\x00\x00\x00\x00@e\xdd@\x00\x00\x00\x00A\x83\xf2\xc0\x00\x00\x00\x00BE\xbf@\x00\x00\x00\x00Cc\xd4\xc0\x00\x00\x00\x00D%\xa1@\x00\x00\x00\x00EC\xb6\xc0\x00\x00\x00\x00F\x05\x83@\x00\x00\x00\x00G#\x98\xc0\x00\x00\x00\x00G\xee\x9f\xc0\x00\x00\x00\x00I\x03z\xc0\x00\x00\x00\x00I\xce\x81\xc0\x00\x00\x00\x00J\xe3\x5c\xc0\x00\x00\x00\x00K\xaec\xc0\x00\x00\x00\x00L\xccy@\x00\x00\x00\x00M\x8eE\xc0\x00\x00\x00\x00TK\xf30\x00\x00\x00\x00V\xf6\xea@\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x03\x01\x03\x00\x00N\x84\x00\x00\x00\x00T`\x00\x04\x00\x00p\x80\x01\x08\x00\x00bp\x00\x0c\x00\x00bp\x01\x0cLMT\x00+06\x00+08\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7\x11\xe1[\xdc\x02\x00\x00\xdc\x02\x00\x00\x0b\x00\x00\x00Asia/BeirutTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xffV\xb6\xc2\xb8\xff\xff\xff\xff\xa2ec\xe0\xff\xff\xff\xff\xa3{\x82P\xff\xff\xff\xff\xa4N\x80`\xff\xff\xff\xff\xa5?\xb4\xd0\xff\xff\xff\xff\xa6%'\xe0\xff\xff\xff\xff\xa7'\x7f\xd0\xff\xff\xff\xff\xa8)\xf3\xe0\xff\xff\xff\xff\xa8\xeb\xb2P\xff\xff\xff\xff\xe8*\x85\xe0\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\x0b\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xec\xe0\xff\xff\xff\xff\xec\xb6\x94P\xff\xff\xff\xff\xed\xcfq\xe0\xff\xff\xff\xff\xee\x99\x19P\xff\xff\xff\xff\xef\xb0\xa5`\xff\xff\xff\xff\xf0zL\xd0\x00\x00\x00\x00\x04\xa6^`\x00\x00\x00\x00\x05+w\xd0\x00\x00\x00\x00\x06C\x03\xe0\x00\x00\x00\x00\x07\x0c\xabP\x00\x00\x00\x00\x08$7`\x00\x00\x00\x00\x08\xed\xde\xd0\x00\x00\x00\x00\x0a\x05j\xe0\x00\x00\x00\x00\x0a\xcf\x12P\x00\x00\x00\x00\x0b\xe7\xef\xe0\x00\x00\x00\x00\x0c\xb1\x97P\x00\x00\x00\x00\x0d\xc9#`\x00\x00\x00\x00\x0e\x92\xca\xd0\x00\x00\x00\x00\x0f\xa9\x05`\x00\x00\x00\x00\x10r\xac\xd0\x00\x00\x00\x00\x1a\xf4.\xe0\x00\x00\x00\x00\x1b\xd1\x9c\xd0\x00\x00\x00\x00\x1c\xd5b`\x00\x00\x00\x00\x1d\xb2\xd0P\x00\x00\x00\x00\x1e\xb6\x95\xe0\x00\x00\x00\x00\x1f\x94\x03\xd0\x00\x00\x00\x00 \x97\xc9`\x00\x00\x00\x00!u7P\x00\x00\x00\x00\x22\xa3,\xe0\x00\x00\x00\x00#W\xbcP\x00\x00\x00\x00$g_`\x00\x00\x00\x00%8\xef\xd0\x00\x00\x00\x00&<\xb5`\x00\x00\x00\x00'\x1a#P\x00\x00\x00\x00(\x1d\xe8\xe0\x00\x00\x00\x00(\xfbV\xd0\x00\x00\x00\x00*\x00m\xe0\x00\x00\x00\x00*\xce\x09\xd0\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000duP\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002M\x91\xd0\x00\x00\x00\x003=\x90\xe0\x00\x00\x00\x004-s\xd0\x00\x00\x00\x005\x1dr\xe0\x00\x00\x00\x006\x0dU\xd0\x00\x00\x00\x006\xfdT\xe0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00!H\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09LMT\x00EEST\x00EET\x00\x0aEET-2EEST,M3.5.0/0,M10.5.0/0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000]*\x1bj\x02\x00\x00j\x02\x00\x00\x0c\x00\x00\x00Asia/BishkekTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19~\x10\xff\xff\xff\xff\xb5\xa3\xef0\x00\x00\x00\x00\x15'}\xa0\x00\x00\x00\x00\x16\x18\xb2\x10\x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xe5\x90\x00\x00\x00\x00\x18\xe9\xe4\xa0\x00\x00\x00\x00\x19\xdb\x19\x10\x00\x00\x00\x00\x1a\xcci\xa0\x00\x00\x00\x00\x1b\xbcv\xc0\x00\x00\x00\x00\x1c\xacg\xc0\x00\x00\x00\x00\x1d\x9cX\xc0\x00\x00\x00\x00\x1e\x8cI\xc0\x00\x00\x00\x00\x1f|:\xc0\x00\x00\x00\x00 l+\xc0\x00\x00\x00\x00!\x5c\x1c\xc0\x00\x00\x00\x00\x22L\x0d\xc0\x00\x00\x00\x00#;\xfe\xc0\x00\x00\x00\x00$+\xef\xc0\x00\x00\x00\x00%\x1b\xe0\xc0\x00\x00\x00\x00&\x0b\xd1\xc0\x00\x00\x00\x00'\x04\xfd@\x00\x00\x00\x00'\xf4\xee@\x00\x00\x00\x00(\xbe\xa3\xc0\x00\x00\x00\x00)\xe770\x00\x00\x00\x00*\xc4\xa5 \x00\x00\x00\x00+\xc7\x190\x00\x00\x00\x00,\xa4\x87 \x00\x00\x00\x00-\xa6\xfb0\x00\x00\x00\x00.\x84i \x00\x00\x00\x00/\x86\xdd0\x00\x00\x00\x000dK \x00\x00\x00\x001f\xbf0\x00\x00\x00\x002Mg\xa0\x00\x00\x00\x003=\x89\xd8\x00\x00\x00\x004RV\xc8\x00\x00\x00\x005\x1dk\xd8\x00\x00\x00\x00628\xc8\x00\x00\x00\x006\xfdM\xd8\x00\x00\x00\x008\x1bUH\x00\x00\x00\x008\xdd/\xd8\x00\x00\x00\x009\xfb7H\x00\x00\x00\x00:\xbd\x11\xd8\x00\x00\x00\x00;\xdb\x19H\x00\x00\x00\x00<\xa6.X\x00\x00\x00\x00=\xba\xfbH\x00\x00\x00\x00>\x86\x10X\x00\x00\x00\x00?\x9a\xddH\x00\x00\x00\x00@e\xf2X\x00\x00\x00\x00A\x83\xf9\xc8\x00\x00\x00\x00BE\xd4X\x00\x00\x00\x00B\xfb\x92 \x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x03\x00\x00E\xf0\x00\x00\x00\x00FP\x00\x04\x00\x00bp\x01\x08\x00\x00T`\x00\x0c\x00\x00T`\x01\x0cLMT\x00+05\x00+07\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7f^]@\x01\x00\x00@\x01\x00\x00\x0b\x00\x00\x00Asia/BruneiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00\x00\x05\x00\x00\x00\x18\xff\xff\xff\xff\xad\x8a\x06\x90\xff\xff\xff\xff\xbagG\x88\xff\xff\xff\xff\xbf{'\x80\xff\xff\xff\xff\xbf\xf3\x1bP\xff\xff\xff\xff\xc1]\xac\x80\xff\xff\xff\xff\xc1\xd5\xa0P\xff\xff\xff\xff\xc3>\xe0\x00\xff\xff\xff\xff\xc3\xb6\xd3\xd0\xff\xff\xff\xff\xc5 \x13\x80\xff\xff\xff\xff\xc5\x98\x07P\xff\xff\xff\xff\xc7\x01G\x00\xff\xff\xff\xff\xc7y:\xd0\xff\xff\xff\xff\xc8\xe3\xcc\x00\xff\xff\xff\xff\xc9[\xbf\xd0\xff\xff\xff\xff\xca\xc4\xff\x80\xff\xff\xff\xff\xcb<\xf3P\xff\xff\xff\xff\xcb\x91X\x00\xff\xff\xff\xff\xd2Hm\xf0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x03\x00\x00gp\x00\x00\x00\x00ix\x00\x04\x00\x00u0\x01\x0a\x00\x00p\x80\x00\x10\x00\x00~\x90\x00\x14LMT\x00+0730\x00+0820\x00+08\x00+09\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x1a\xdc\xca\xdc\x00\x00\x00\xdc\x00\x00\x00\x0d\x00\x00\x00Asia/CalcuttaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x05\x00\x00\x00\x16\xff\xff\xff\xff&\xba\x18(\xff\xff\xff\xffC\xe7\xeb0\xff\xff\xff\xff\x87\x9d\xbc\xba\xff\xff\xff\xff\xca\xdb\x8c(\xff\xff\xff\xff\xcc\x05q\x18\xff\xff\xff\xff\xcc\x952\xa8\xff\xff\xff\xff\xd2t\x12\x98\x01\x02\x03\x04\x03\x04\x03\x00\x00R\xd8\x00\x00\x00\x00R\xd0\x00\x04\x00\x00KF\x00\x08\x00\x00MX\x00\x0c\x00\x00[h\x01\x10LMT\x00HMT\x00MMT\x00IST\x00+0630\x00\x0aIST-5:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xab\xcd\xdf\x05\xee\x02\x00\x00\xee\x02\x00\x00\x0a\x00\x00\x00Asia/ChitaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xdb\xf9\xa0\xff\xff\xff\xff\xb5\xa3\xc5\x00\x00\x00\x00\x00\x15'Sp\x00\x00\x00\x00\x16\x18\x87\xe0\x00\x00\x00\x00\x17\x08\x86\xf0\x00\x00\x00\x00\x17\xf9\xbb`\x00\x00\x00\x00\x18\xe9\xbap\x00\x00\x00\x00\x19\xda\xee\xe0\x00\x00\x00\x00\x1a\xcc?p\x00\x00\x00\x00\x1b\xbcL\x90\x00\x00\x00\x00\x1c\xac=\x90\x00\x00\x00\x00\x1d\x9c.\x90\x00\x00\x00\x00\x1e\x8c\x1f\x90\x00\x00\x00\x00\x1f|\x10\x90\x00\x00\x00\x00 l\x01\x90\x00\x00\x00\x00![\xf2\x90\x00\x00\x00\x00\x22K\xe3\x90\x00\x00\x00\x00#;\xd4\x90\x00\x00\x00\x00$+\xc5\x90\x00\x00\x00\x00%\x1b\xb6\x90\x00\x00\x00\x00&\x0b\xa7\x90\x00\x00\x00\x00'\x04\xd3\x10\x00\x00\x00\x00'\xf4\xc4\x10\x00\x00\x00\x00(\xe4\xc3 \x00\x00\x00\x00)xk \x00\x00\x00\x00)\xd4\xa6\x10\x00\x00\x00\x00*\xc4\x97\x10\x00\x00\x00\x00+\xb4\x88\x10\x00\x00\x00\x00,\xa4y\x10\x00\x00\x00\x00-\x94j\x10\x00\x00\x00\x00.\x84[\x10\x00\x00\x00\x00/tL\x10\x00\x00\x00\x000d=\x10\x00\x00\x00\x001]h\x90\x00\x00\x00\x002rC\x90\x00\x00\x00\x003=J\x90\x00\x00\x00\x004R%\x90\x00\x00\x00\x005\x1d,\x90\x00\x00\x00\x0062\x07\x90\x00\x00\x00\x006\xfd\x0e\x90\x00\x00\x00\x008\x1b$\x10\x00\x00\x00\x008\xdc\xf0\x90\x00\x00\x00\x009\xfb\x06\x10\x00\x00\x00\x00:\xbc\xd2\x90\x00\x00\x00\x00;\xda\xe8\x10\x00\x00\x00\x00<\xa5\xef\x10\x00\x00\x00\x00=\xba\xca\x10\x00\x00\x00\x00>\x85\xd1\x10\x00\x00\x00\x00?\x9a\xac\x10\x00\x00\x00\x00@e\xb3\x10\x00\x00\x00\x00A\x83\xc8\x90\x00\x00\x00\x00BE\x95\x10\x00\x00\x00\x00Cc\xaa\x90\x00\x00\x00\x00D%w\x10\x00\x00\x00\x00EC\x8c\x90\x00\x00\x00\x00F\x05Y\x10\x00\x00\x00\x00G#n\x90\x00\x00\x00\x00G\xeeu\x90\x00\x00\x00\x00I\x03P\x90\x00\x00\x00\x00I\xceW\x90\x00\x00\x00\x00J\xe32\x90\x00\x00\x00\x00K\xae9\x90\x00\x00\x00\x00L\xccO\x10\x00\x00\x00\x00M\x8e\x1b\x90\x00\x00\x00\x00TK\xc9\x00\x00\x00\x00\x00V\xf6\xce \x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x01\x03\x00\x00j`\x00\x00\x00\x00p\x80\x00\x04\x00\x00\x8c\xa0\x01\x08\x00\x00~\x90\x00\x0c\x00\x00~\x90\x01\x0c\x00\x00\x8c\xa0\x00\x08LMT\x00+08\x00+10\x00+09\x00\x0a<+09>-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81z&\x80k\x02\x00\x00k\x02\x00\x00\x0f\x00\x00\x00Asia/ChoibalsanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xff\x86\xd3\xe7(\x00\x00\x00\x00\x0f\x0b\xdc\x90\x00\x00\x00\x00\x18\xe9\xc8\x80\x00\x00\x00\x00\x19\xda\xee\xe0\x00\x00\x00\x00\x1a\xcc?p\x00\x00\x00\x00\x1b\xbc\x22`\x00\x00\x00\x00\x1c\xac!p\x00\x00\x00\x00\x1d\x9c\x04`\x00\x00\x00\x00\x1e\x8c\x03p\x00\x00\x00\x00\x1f{\xe6`\x00\x00\x00\x00 k\xe5p\x00\x00\x00\x00![\xc8`\x00\x00\x00\x00\x22K\xc7p\x00\x00\x00\x00#;\xaa`\x00\x00\x00\x00$+\xa9p\x00\x00\x00\x00%\x1b\x8c`\x00\x00\x00\x00&\x0b\x8bp\x00\x00\x00\x00'\x04\xa8\xe0\x00\x00\x00\x00'\xf4\xa7\xf0\x00\x00\x00\x00(\xe4\x8a\xe0\x00\x00\x00\x00)\xd4\x89\xf0\x00\x00\x00\x00*\xc4l\xe0\x00\x00\x00\x00+\xb4k\xf0\x00\x00\x00\x00,\xa4N\xe0\x00\x00\x00\x00-\x94M\xf0\x00\x00\x00\x00.\x840\xe0\x00\x00\x00\x00/t/\xf0\x00\x00\x00\x000d\x12\xe0\x00\x00\x00\x001]Lp\x00\x00\x00\x002M/`\x00\x00\x00\x003=.p\x00\x00\x00\x004-\x11`\x00\x00\x00\x005\x1d\x10p\x00\x00\x00\x006\x0c\xf3`\x00\x00\x00\x00:\xe9\xa5\x90\x00\x00\x00\x00;\xb4\x9e\x80\x00\x00\x00\x00<\xa4\x9d\x90\x00\x00\x00\x00=\x94\x80\x80\x00\x00\x00\x00>\x84\x7f\x90\x00\x00\x00\x00?tb\x80\x00\x00\x00\x00@da\x90\x00\x00\x00\x00ATD\x80\x00\x00\x00\x00BDC\x90\x00\x00\x00\x00C4&\x80\x00\x00\x00\x00D$%\x90\x00\x00\x00\x00E\x1dC\x00\x00\x00\x00\x00G\xef\xaa\xf0\x00\x00\x00\x00U\x15\x9a\xa0\x00\x00\x00\x00V\x05ap\x00\x00\x00\x00V\xf5|\xa0\x00\x00\x00\x00W\xe5Cp\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x02\x05\x02\x05\x02\x00\x00kX\x00\x00\x00\x00bp\x00\x04\x00\x00p\x80\x00\x08\x00\x00~\x90\x00\x0c\x00\x00\x8c\xa0\x01\x10\x00\x00~\x90\x01\x0cLMT\x00+07\x00+08\x00+09\x00+10\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0e\x00\x00\x00Asia/ChongqingTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff~6C)\xff\xff\xff\xff\xa0\x97\xa2\x80\xff\xff\xff\xff\xa1y\x04\xf0\xff\xff\xff\xff\xc8Y^\x80\xff\xff\xff\xff\xc9\x09\xf9p\xff\xff\xff\xff\xc9\xd3\xbd\x00\xff\xff\xff\xff\xcb\x05\x8a\xf0\xff\xff\xff\xff\xcb|@\x00\xff\xff\xff\xff\xd2;>\xf0\xff\xff\xff\xff\xd3\x8b{\x80\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5E\x22\x00\xff\xff\xff\xff\xd6L\xbf\xf0\xff\xff\xff\xff\xd7<\xbf\x00\xff\xff\xff\xff\xd8\x06fp\xff\xff\xff\xff\xd9\x1d\xf2\x80\xff\xff\xff\xff\xd9A|\xf0\x00\x00\x00\x00\x1e\xbaR \x00\x00\x00\x00\x1fi\x9b\x90\x00\x00\x00\x00 ~\x84\xa0\x00\x00\x00\x00!I}\x90\x00\x00\x00\x00\x22g\xa1 \x00\x00\x00\x00#)_\x90\x00\x00\x00\x00$G\x83 \x00\x00\x00\x00%\x12|\x10\x00\x00\x00\x00&'e \x00\x00\x00\x00&\xf2^\x10\x00\x00\x00\x00(\x07G \x00\x00\x00\x00(\xd2@\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00q\xd7\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x08LMT\x00CDT\x00CST\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0e\x00\x00\x00Asia/ChungkingTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff~6C)\xff\xff\xff\xff\xa0\x97\xa2\x80\xff\xff\xff\xff\xa1y\x04\xf0\xff\xff\xff\xff\xc8Y^\x80\xff\xff\xff\xff\xc9\x09\xf9p\xff\xff\xff\xff\xc9\xd3\xbd\x00\xff\xff\xff\xff\xcb\x05\x8a\xf0\xff\xff\xff\xff\xcb|@\x00\xff\xff\xff\xff\xd2;>\xf0\xff\xff\xff\xff\xd3\x8b{\x80\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5E\x22\x00\xff\xff\xff\xff\xd6L\xbf\xf0\xff\xff\xff\xff\xd7<\xbf\x00\xff\xff\xff\xff\xd8\x06fp\xff\xff\xff\xff\xd9\x1d\xf2\x80\xff\xff\xff\xff\xd9A|\xf0\x00\x00\x00\x00\x1e\xbaR \x00\x00\x00\x00\x1fi\x9b\x90\x00\x00\x00\x00 ~\x84\xa0\x00\x00\x00\x00!I}\x90\x00\x00\x00\x00\x22g\xa1 \x00\x00\x00\x00#)_\x90\x00\x00\x00\x00$G\x83 \x00\x00\x00\x00%\x12|\x10\x00\x00\x00\x00&'e \x00\x00\x00\x00&\xf2^\x10\x00\x00\x00\x00(\x07G \x00\x00\x00\x00(\xd2@\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00q\xd7\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x08LMT\x00CDT\x00CST\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5c\x91\x87\xbb\xf7\x00\x00\x00\xf7\x00\x00\x00\x0c\x00\x00\x00Asia/ColomboTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x07\x00\x00\x00\x18\xff\xff\xff\xffV\xb6\x99$\xff\xff\xff\xff\x87\x9d\xbd\x1c\xff\xff\xff\xff\xcbZ\x1c(\xff\xff\xff\xff\xcc\x95+\xa0\xff\xff\xff\xff\xd2u\x808\x00\x00\x00\x001\xa6\x00(\x00\x00\x00\x002q\x00 \x00\x00\x00\x00D?\xea(\x01\x02\x03\x04\x02\x05\x06\x02\x00\x00J\xdc\x00\x00\x00\x00J\xe4\x00\x04\x00\x00MX\x00\x08\x00\x00T`\x01\x0e\x00\x00[h\x01\x12\x00\x00[h\x00\x12\x00\x00T`\x00\x0eLMT\x00MMT\x00+0530\x00+06\x00+0630\x00\x0a<+0530>-5:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?Y\xaf\x19\xe7\x00\x00\x00\xe7\x00\x00\x00\x0a\x00\x00\x00Asia/DaccaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x1c\xff\xff\xff\xffi\x86\x86\xbc\xff\xff\xff\xff\xca\xdb\x86\xb0\xff\xff\xff\xff\xcc\x05q\x18\xff\xff\xff\xff\xcc\x952\xa8\xff\xff\xff\xff\xdd\xa8\xd2\x98\x00\x00\x00\x00J;\xc4\x10\x00\x00\x00\x00K<\xd8\x90\x01\x02\x03\x02\x04\x05\x04\x00\x00T\xc4\x00\x00\x00\x00R\xd0\x00\x04\x00\x00[h\x00\x08\x00\x00MX\x00\x0e\x00\x00T`\x00\x14\x00\x00bp\x01\x18LMT\x00HMT\x00+0630\x00+0530\x00+06\x00+07\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87\x07\xeci\xd2\x04\x00\x00\xd2\x04\x00\x00\x0d\x00\x00\x00Asia/DamascusTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00y\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xa1\xf2\xabx\xff\xff\xff\xff\xa2\x81/\x80\xff\xff\xff\xff\xa3^\x9dp\xff\xff\xff\xff\xa4a\x11\x80\xff\xff\xff\xff\xa5>\x7fp\xff\xff\xff\xff\xa6@\xf3\x80\xff\xff\xff\xff\xa7\x1eap\xff\xff\xff\xff\xa8 \xd5\x80\xff\xff\xff\xff\xa9\x07}\xf0\xff\xff\xff\xff\xf1\x8fR\x00\xff\xff\xff\xff\xf2[\x9cp\xff\xff\xff\xff\xf3s(\x80\xff\xff\xff\xff\xf4;~p\xff\xff\xff\xff\xf5U\xad\x80\xff\xff\xff\xff\xf6\x1fT\xf0\xff\xff\xff\xff\xf76\xe1\x00\xff\xff\xff\xff\xf7\xff6\xf0\xff\xff\xff\xff\xf9\x0e\xda\x00\xff\xff\xff\xff\xf9\xe1\xbb\xf0\xff\xff\xff\xff\xfa\xf9H\x00\xff\xff\xff\xff\xfb\xc2\xefp\xff\xff\xff\xff\xfc\xdb\xcd\x00\xff\xff\xff\xff\xfd\xa5tp\xff\xff\xff\xff\xfe\xbd\x00\x80\xff\xff\xff\xff\xff\x86\xa7\xf0\x00\x00\x00\x00\x00\x9e4\x00\x00\x00\x00\x00\x01g\xdbp\x00\x00\x00\x00\x02\x7fg\x80\x00\x00\x00\x00\x03I\x0e\xf0\x00\x00\x00\x00\x04a\xec\x80\x00\x00\x00\x00\x05+\x93\xf0\x00\x00\x00\x00\x06C \x00\x00\x00\x00\x00\x07\x0c\xc7p\x00\x00\x00\x00\x08$S\x80\x00\x00\x00\x00\x08\xed\xfa\xf0\x00\x00\x00\x00\x0a\x05\x87\x00\x00\x00\x00\x00\x0a\xcf.p\x00\x00\x00\x00\x0b\xe8\x0c\x00\x00\x00\x00\x00\x0c\xb1\xb3p\x00\x00\x00\x00\x0d\xc9?\x80\x00\x00\x00\x00\x0ekY\xf0\x00\x00\x00\x00\x0f\xaas\x00\x00\x00\x00\x00\x10L\x8dp\x00\x00\x00\x00\x18\xf4\xc5\x00\x00\x00\x00\x00\x19\xdbmp\x00\x00\x00\x00\x1a\xd7J\x00\x00\x00\x00\x00\x1b\xbd\xf2p\x00\x00\x00\x00\x1eU#\x00\x00\x00\x00\x00\x1f\x8a\xe5p\x00\x00\x00\x00 Gz\x00\x00\x00\x00\x00!\x89\x19\xf0\x00\x00\x00\x00\x22\xe2`\x00\x00\x00\x0041hP\x00\x00\x00\x005\x1e\xc4`\x00\x00\x00\x006\x12\x9b\xd0\x00\x00\x00\x007\x02\x9a\xe0\x00\x00\x00\x007\xf3\xcfP\x00\x00\x00\x008\xe5\x1f\xe0\x00\x00\x00\x009\xd6TP\x00\x00\x00\x00:\xc6S`\x00\x00\x00\x00;\xb7\x87\xd0\x00\x00\x00\x00<\xa7\x86\xe0\x00\x00\x00\x00=\x98\xbbP\x00\x00\x00\x00>\x88\xba`\x00\x00\x00\x00?y\xee\xd0\x00\x00\x00\x00@k?`\x00\x00\x00\x00A\x5cs\xd0\x00\x00\x00\x00BLr\xe0\x00\x00\x00\x00C=\xa7P\x00\x00\x00\x00D-\xa6`\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F\x0c6\xe0\x00\x00\x00\x00G*>P\x00\x00\x00\x00G\xf5S`\x00\x00\x00\x00I\x0bq\xd0\x00\x00\x00\x00I\xcb\xfa\xe0\x00\x00\x00\x00J\xea\x02P\x00\x00\x00\x00K\xb5\x17`\x00\x00\x00\x00L\xc9\xe4P\x00\x00\x00\x00M\x94\xf9`\x00\x00\x00\x00N\xa9\xc6P\x00\x00\x00\x00Ot\xdb`\x00\x00\x00\x00P\x89\xa8P\x00\x00\x00\x00QT\xbd`\x00\x00\x00\x00Ri\x8aP\x00\x00\x00\x00S4\x9f`\x00\x00\x00\x00TR\xa6\xd0\x00\x00\x00\x00U\x14\x81`\x00\x00\x00\x00V2\x88\xd0\x00\x00\x00\x00V\xf4c`\x00\x00\x00\x00X\x12j\xd0\x00\x00\x00\x00X\xdd\x7f\xe0\x00\x00\x00\x00Y\xf2L\xd0\x00\x00\x00\x00Z\xbda\xe0\x00\x00\x00\x00[\xd2.\xd0\x00\x00\x00\x00\x5c\x9dC\xe0\x00\x00\x00\x00]\xb2\x10\xd0\x00\x00\x00\x00^}%\xe0\x00\x00\x00\x00_\x9b-P\x00\x00\x00\x00`]\x07\xe0\x00\x00\x00\x00a{\x0fP\x00\x00\x00\x00b<\xe9\xe0\x00\x00\x00\x00cZ\xf1P\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x00\x00\x22\x08\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09\x00\x00*0\x00\x0dLMT\x00EEST\x00EET\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?Y\xaf\x19\xe7\x00\x00\x00\xe7\x00\x00\x00\x0a\x00\x00\x00Asia/DhakaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x1c\xff\xff\xff\xffi\x86\x86\xbc\xff\xff\xff\xff\xca\xdb\x86\xb0\xff\xff\xff\xff\xcc\x05q\x18\xff\xff\xff\xff\xcc\x952\xa8\xff\xff\xff\xff\xdd\xa8\xd2\x98\x00\x00\x00\x00J;\xc4\x10\x00\x00\x00\x00K<\xd8\x90\x01\x02\x03\x02\x04\x05\x04\x00\x00T\xc4\x00\x00\x00\x00R\xd0\x00\x04\x00\x00[h\x00\x08\x00\x00MX\x00\x0e\x00\x00T`\x00\x14\x00\x00bp\x01\x18LMT\x00HMT\x00+0630\x00+0530\x00+06\x00+07\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x92\x1a\x8c\xaa\x00\x00\x00\xaa\x00\x00\x00\x09\x00\x00\x00Asia/DiliTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x92\xe6\x18\xc4\xff\xff\xff\xff\xcb\x992\xf0\x00\x00\x00\x00\x0b\xea0p\x00\x00\x00\x009\xc3\x99\x00\x01\x02\x01\x02\x00\x00u\xbc\x00\x00\x00\x00p\x80\x00\x04\x00\x00~\x90\x00\x08LMT\x00+08\x00+09\x00\x0a<+09>-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0a\x00\x00\x00Asia/DubaiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xa1\xf2\x99\xa8\x01\x00\x003\xd8\x00\x00\x00\x008@\x00\x04LMT\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00's\x96\x1en\x01\x00\x00n\x01\x00\x00\x0d\x00\x00\x00Asia/DushanbeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x83\x80\xff\xff\xff\xff\xb5\xa3\xef0\x00\x00\x00\x00\x15'}\xa0\x00\x00\x00\x00\x16\x18\xb2\x10\x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xe5\x90\x00\x00\x00\x00\x18\xe9\xe4\xa0\x00\x00\x00\x00\x19\xdb\x19\x10\x00\x00\x00\x00\x1a\xcci\xa0\x00\x00\x00\x00\x1b\xbcv\xc0\x00\x00\x00\x00\x1c\xacg\xc0\x00\x00\x00\x00\x1d\x9cX\xc0\x00\x00\x00\x00\x1e\x8cI\xc0\x00\x00\x00\x00\x1f|:\xc0\x00\x00\x00\x00 l+\xc0\x00\x00\x00\x00!\x5c\x1c\xc0\x00\x00\x00\x00\x22L\x0d\xc0\x00\x00\x00\x00#;\xfe\xc0\x00\x00\x00\x00$+\xef\xc0\x00\x00\x00\x00%\x1b\xe0\xc0\x00\x00\x00\x00&\x0b\xd1\xc0\x00\x00\x00\x00'\x04\xfd@\x00\x00\x00\x00'\xf4\xee@\x00\x00\x00\x00(\xca\x8fP\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x00\x00@\x80\x00\x00\x00\x00FP\x00\x04\x00\x00bp\x01\x08\x00\x00T`\x00\x0c\x00\x00T`\x01\x0cLMT\x00+05\x00+07\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]S\xbb\x12\xac\x03\x00\x00\xac\x03\x00\x00\x0e\x00\x00\x00Asia/FamagustaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xa5w\x1e,\x00\x00\x00\x00\x09\xed\xaf\xe0\x00\x00\x00\x00\x0a\xdd\x92\xd0\x00\x00\x00\x00\x0b\xfad\xe0\x00\x00\x00\x00\x0c\xbe\xc6P\x00\x00\x00\x00\x0d\xa49`\x00\x00\x00\x00\x0e\x8a\xe1\xd0\x00\x00\x00\x00\x0f\x84\x1b`\x00\x00\x00\x00\x10uO\xd0\x00\x00\x00\x00\x11c\xfd`\x00\x00\x00\x00\x12S\xe0P\x00\x00\x00\x00\x13M\x19\xe0\x00\x00\x00\x00\x143\xc2P\x00\x00\x00\x00\x15#\xc1`\x00\x00\x00\x00\x16\x13\xa4P\x00\x00\x00\x00\x17\x03\xa3`\x00\x00\x00\x00\x17\xf3\x86P\x00\x00\x00\x00\x18\xe3\x85`\x00\x00\x00\x00\x19\xd3hP\x00\x00\x00\x00\x1a\xc3g`\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe4\xedP\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000duP\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002M\x91\xd0\x00\x00\x00\x003=\x90\xe0\x00\x00\x00\x004-s\xd0\x00\x00\x00\x005\x1dr\xe0\x00\x00\x00\x0062x\x10\x00\x00\x00\x006\xfd\x7f\x10\x00\x00\x00\x008\x1b\x94\x90\x00\x00\x00\x008\xdda\x10\x00\x00\x00\x009\xfbv\x90\x00\x00\x00\x00:\xbdC\x10\x00\x00\x00\x00;\xdbX\x90\x00\x00\x00\x00<\xa6_\x90\x00\x00\x00\x00=\xbb:\x90\x00\x00\x00\x00>\x86A\x90\x00\x00\x00\x00?\x9b\x1c\x90\x00\x00\x00\x00@f#\x90\x00\x00\x00\x00A\x849\x10\x00\x00\x00\x00BF\x05\x90\x00\x00\x00\x00Cd\x1b\x10\x00\x00\x00\x00D%\xe7\x90\x00\x00\x00\x00EC\xfd\x10\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8e\x8c\x10\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S7l\x90\x00\x00\x00\x00TLG\x90\x00\x00\x00\x00U\x17N\x90\x00\x00\x00\x00V,)\x90\x00\x00\x00\x00V\xf70\x90\x00\x00\x00\x00W\xd0\x7f\xd0\x00\x00\x00\x00Y\xf5(\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x02\x00\x00\x1f\xd4\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09\x00\x00*0\x00\x0dLMT\x00EEST\x00EET\x00+03\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\xae\xc2\xd6\x86\x0b\x00\x00\x86\x0b\x00\x00\x09\x00\x00\x00Asia/GazaTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x014\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff}\xbdJ\xb0\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xff\xcd\xac\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xff\xcf\x8f\x83\x00\xff\xff\xff\xff\xd0\xa9\xa4\x00\xff\xff\xff\xff\xd1\x84}\x00\xff\xff\xff\xff\xd2\x8a\xd7\x80\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\x0b\x00\xff\xff\xff\xff\xe86c`\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\x0b\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xfa\xf0\xff\xff\xff\xff\xec\xb5m\x00\xff\xff\xff\xff\xed\xcf\x7f\xf0\xff\xff\xff\xff\xee\x97\xf2\x00\xff\xff\xff\xff\xef\xb0\xb3p\xff\xff\xff\xff\xf0y%\x80\xff\xff\xff\xff\xf1\x91\xe6\xf0\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3s\x1ap\xff\xff\xff\xff\xf4;\x8c\x80\xff\xff\xff\xff\xf5U\x9fp\xff\xff\xff\xff\xf6\x1e\x11\x80\xff\xff\xff\xff\xf76\xd2\xf0\xff\xff\xff\xff\xf7\xffE\x00\xff\xff\xff\xff\xf9\x18\x06p\xff\xff\xff\xff\xf9\xe1\xca\x00\xff\xff\xff\xff\xfa\xf99\xf0\xff\xff\xff\xff\xfb'BP\x00\x00\x00\x00\x08|\x8b\xe0\x00\x00\x00\x00\x08\xfd\xb0\xd0\x00\x00\x00\x00\x09\xf6\xea`\x00\x00\x00\x00\x0a\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\x22^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x000\xe7\x07\xe0\x00\x00\x00\x001dF`\x00\x00\x00\x002A\xc2`\x00\x00\x00\x003D(`\x00\x00\x00\x004!\xa4`\x00\x00\x00\x005$\x0a`\x00\x00\x00\x006\x01\x86`\x00\x00\x00\x007\x16a`\x00\x00\x00\x008\x06DP\x00\x00\x00\x008\xff}\xe0\x00\x00\x00\x009\xef`\xd0\x00\x00\x00\x00:\xdf_\xe0\x00\x00\x00\x00;\xcfB\xd0\x00\x00\x00\x00<\xbfA\xe0\x00\x00\x00\x00=\xaf$\xd0\x00\x00\x00\x00>\x9f#\xe0\x00\x00\x00\x00?\x8f\x06\xd0\x00\x00\x00\x00@\x7f\x05\xe0\x00\x00\x00\x00A\x5c\x81\xe0\x00\x00\x00\x00B^\xe7\xe0\x00\x00\x00\x00CA\xb7\xf0\x00\x00\x00\x00D-\xa6`\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F\x0e\xd9\xe0\x00\x00\x00\x00F\xe8op\x00\x00\x00\x00G\xec\x18\xe0\x00\x00\x00\x00H\xb7\x11\xd0\x00\x00\x00\x00I\xcb\xfa\xe0\x00\x00\x00\x00J\xa0<`\x00\x00\x00\x00K\xad.\x9c\x00\x00\x00\x00La\xbd\xd0\x00\x00\x00\x00M\x94\xf9\x9c\x00\x00\x00\x00N5\xc2P\x00\x00\x00\x00Ot\xdb`\x00\x00\x00\x00P[\x91\xe0\x00\x00\x00\x00QT\xbd`\x00\x00\x00\x00RD\xa0P\x00\x00\x00\x00S4\x9f`\x00\x00\x00\x00TIlP\x00\x00\x00\x00U\x15\xd2\xe0\x00\x00\x00\x00V)\x5c`\x00\x00\x00\x00V\xf5\xc2\xf0\x00\x00\x00\x00X\x13\xca`\x00\x00\x00\x00X\xd5\xa4\xf0\x00\x00\x00\x00Y\xf3\xac`\x00\x00\x00\x00Z\xb5\x86\xf0\x00\x00\x00\x00[\xd3\x8e`\x00\x00\x00\x00\x5c\x9dC\xe0\x00\x00\x00\x00]\xb3bP\x00\x00\x00\x00^~w`\x00\x00\x00\x00_\x93R`\x00\x00\x00\x00`^Y`\x00\x00\x00\x00a{\x1d`\x00\x00\x00\x00b?\x8c\xe0\x00\x00\x00\x00c\x5c^\xf0\x00\x00\x00\x00dL^\x00\x00\x00\x00\x00e<@\xf0\x00\x00\x00\x00f#\x05\x80\x00\x00\x00\x00g\x1c\x22\xf0\x00\x00\x00\x00g\xf9\xad\x00\x00\x00\x00\x00h\xfc\x04\xf0\x00\x00\x00\x00i\xc7\x1a\x00\x00\x00\x00\x00j\xdb\xe6\xf0\x00\x00\x00\x00k\xa6\xfc\x00\x00\x00\x00\x00l\xc5\x03p\x00\x00\x00\x00m\x86\xde\x00\x00\x00\x00\x00n\xa4\xe5p\x00\x00\x00\x00of\xc0\x00\x00\x00\x00\x00p\x84\xc7p\x00\x00\x00\x00qO\xdc\x80\x00\x00\x00\x00rd\xa9p\x00\x00\x00\x00s/\xbe\x80\x00\x00\x00\x00tD\x8bp\x00\x00\x00\x00u\x0f\xa0\x80\x00\x00\x00\x00v-\xa7\xf0\x00\x00\x00\x00v\xef\x82\x80\x00\x00\x00\x00x\x0d\x89\xf0\x00\x00\x00\x00x\xcfd\x80\x00\x00\x00\x00y\xedk\xf0\x00\x00\x00\x00z\xafF\x80\x00\x00\x00\x00{\xcdM\xf0\x00\x00\x00\x00|\x98c\x00\x00\x00\x00\x00}\xa3\xf5p\x00\x00\x00\x00~xE\x00\x00\x00\x00\x00\x7fz\x9c\xf0\x00\x00\x00\x00\x80X'\x00\x00\x00\x00\x00\x81H\x09\xf0\x00\x00\x00\x00\x828\x09\x00\x00\x00\x00\x00\x83\x1e\xb1p\x00\x00\x00\x00\x84\x17\xeb\x00\x00\x00\x00\x00\x84\xec\x1ep\x00\x00\x00\x00\x85,\xc6\x00\x00\x00\x00\x00\x855\xf2p\x00\x00\x00\x00\x86\x01\x07\x80\x00\x00\x00\x00\x86\xc2\xc5\xf0\x00\x00\x00\x00\x86\xfa3\x00\x00\x00\x00\x00\x87\x15\xd4p\x00\x00\x00\x00\x87\xe0\xe9\x80\x00\x00\x00\x00\x88\x99mp\x00\x00\x00\x00\x88\xd0\xda\x80\x00\x00\x00\x00\x88\xf5\xb6p\x00\x00\x00\x00\x89\xc0\xcb\x80\x00\x00\x00\x00\x8af\xdap\x00\x00\x00\x00\x8a\xa7\x82\x00\x00\x00\x00\x00\x8a\xd5\x98p\x00\x00\x00\x00\x8b\xa0\xad\x80\x00\x00\x00\x00\x8c=\x81\xf0\x00\x00\x00\x00\x8ct\xef\x00\x00\x00\x00\x00\x8c\xbe\xb4\xf0\x00\x00\x00\x00\x8d\x80\x8f\x80\x00\x00\x00\x00\x8e\x14)p\x00\x00\x00\x00\x8eK\x96\x80\x00\x00\x00\x00\x8e\x9e\x96\xf0\x00\x00\x00\x00\x8f`q\x80\x00\x00\x00\x00\x8f\xe1\x96p\x00\x00\x00\x00\x90\x22>\x00\x00\x00\x00\x00\x90~x\xf0\x00\x00\x00\x00\x91I\x8e\x00\x00\x00\x00\x00\x91\xb8=\xf0\x00\x00\x00\x00\x91\xef\xab\x00\x00\x00\x00\x00\x92^Z\xf0\x00\x00\x00\x00\x93)p\x00\x00\x00\x00\x00\x93\x85\xaa\xf0\x00\x00\x00\x00\x93\xc6R\x80\x00\x00\x00\x00\x94><\xf0\x00\x00\x00\x00\x95\x09R\x00\x00\x00\x00\x00\x95\x5cRp\x00\x00\x00\x00\x95\x93\xbf\x80\x00\x00\x00\x00\x96'Yp\x00\x00\x00\x00\x96\xe94\x00\x00\x00\x00\x00\x972\xf9\xf0\x00\x00\x00\x00\x97jg\x00\x00\x00\x00\x00\x98\x07;p\x00\x00\x00\x00\x98\xc9\x16\x00\x00\x00\x00\x00\x99\x00f\xf0\x00\x00\x00\x00\x99A\x0e\x80\x00\x00\x00\x00\x99\xe7\x1dp\x00\x00\x00\x00\x9a\xb22\x80\x00\x00\x00\x00\x9a\xd7\x0ep\x00\x00\x00\x00\x9b\x0e{\x80\x00\x00\x00\x00\x9b\xc6\xffp\x00\x00\x00\x00\x9c\x92\x14\x80\x00\x00\x00\x00\x9c\xa4{p\x00\x00\x00\x00\x9c\xe5#\x00\x00\x00\x00\x00\x9d\xa6\xe1p\x00\x00\x00\x00\x9eq\xf6\x80\x00\x00\x00\x00\x9e{\x22\xf0\x00\x00\x00\x00\x9e\xbb\xca\x80\x00\x00\x00\x00\x9f\x86\xc3p\x00\x00\x00\x00\xa0\x897\x80\x00\x00\x00\x00\xa1o\xdf\xf0\x00\x00\x00\x00\xa2_\xdf\x00\x00\x00\x00\x00\xa3O\xc1\xf0\x00\x00\x00\x00\xa4-L\x00\x00\x00\x00\x00\xa5/\xa3\xf0\x00\x00\x00\x00\xa6\x03\xf3\x80\x00\x00\x00\x00\xa7\x0f\x85\xf0\x00\x00\x00\x00\xa7\xda\x9b\x00\x00\x00\x00\x00\xa8\xefg\xf0\x00\x00\x00\x00\xa9\xba}\x00\x00\x00\x00\x00\xaa\xd8\x84p\x00\x00\x00\x00\xab\x9a_\x00\x00\x00\x00\x00\xac\xb8fp\x00\x00\x00\x00\xadzA\x00\x00\x00\x00\x00\xae\x98Hp\x00\x00\x00\x00\xafZ#\x00\x00\x00\x00\x00\xb0x*p\x00\x00\x00\x00\xb1C?\x80\x00\x00\x00\x00\xb2X\x0cp\x00\x00\x00\x00\xb3#!\x80\x00\x00\x00\x00\xb47\xeep\x00\x00\x00\x00\xb5\x03\x03\x80\x00\x00\x00\x00\xb6!\x0a\xf0\x00\x00\x00\x00\xb6\xe2\xe5\x80\x00\x00\x00\x00\xb8\x00\xec\xf0\x00\x00\x00\x00\xb8\xc2\xc7\x80\x00\x00\x00\x00\xb9\xd7\x94p\x00\x00\x00\x00\xba\xab\xe4\x00\x00\x00\x00\x00\xbb\xae;\xf0\x00\x00\x00\x00\xbc\x8b\xc6\x00\x00\x00\x00\x00\xbd\x84\xe3p\x00\x00\x00\x00\xbek\xa8\x00\x00\x00\x00\x00\xbfRPp\x00\x00\x00\x00\xc0K\x8a\x00\x00\x00\x00\x00\xc1(\xf7\xf0\x00\x00\x00\x00\xc1`e\x00\x00\x00\x00\x00\xc1i\x91p\x00\x00\x00\x00\xc2+l\x00\x00\x00\x00\x00\xc2\xff\x9fp\x00\x00\x00\x00\xc37\x0c\x80\x00\x00\x00\x00\xc3Isp\x00\x00\x00\x00\xc4\x0bN\x00\x00\x00\x00\x00\xc4\xcd\x0cp\x00\x00\x00\x00\xc5\x0d\xb4\x00\x00\x00\x00\x00\xc5)Up\x00\x00\x00\x00\xc5\xf4j\x80\x00\x00\x00\x00\xc6\xa3\xb3\xf0\x00\x00\x00\x00\xc6\xdb!\x00\x00\x00\x00\x00\xc7\x097p\x00\x00\x00\x00\xc7\xd4L\x80\x00\x00\x00\x00\xc8q \xf0\x00\x00\x00\x00\xc8\xb1\xc8\x80\x00\x00\x00\x00\xc8\xe9\x19p\x00\x00\x00\x00\xc9\xb4.\x80\x00\x00\x00\x00\xcaG\xc8p\x00\x00\x00\x00\xca\x88p\x00\x00\x00\x00\x00\xca\xd25\xf0\x00\x00\x00\x00\xcb\x94\x10\x80\x00\x00\x00\x00\xcc\x1eo\xf0\x00\x00\x00\x00\xccU\xdd\x00\x00\x00\x00\x00\xcc\xb2\x17\xf0\x00\x00\x00\x00\xcds\xf2\x80\x00\x00\x00\x00\xcd\xeb\xdc\xf0\x00\x00\x00\x00\xce,\x84\x80\x00\x00\x00\x00\xce\x91\xf9\xf0\x00\x00\x00\x00\xcf]\x0f\x00\x00\x00\x00\x00\xcf\xc2\x84p\x00\x00\x00\x00\xcf\xf9\xf1\x80\x00\x00\x00\x00\xd0q\xdb\xf0\x00\x00\x00\x00\xd1<\xf1\x00\x00\x00\x00\x00\xd1\x99+\xf0\x00\x00\x00\x00\xd1\xd0\x99\x00\x00\x00\x00\x00\xd2Q\xbd\xf0\x00\x00\x00\x00\xd3\x1c\xd3\x00\x00\x00\x00\x00\xd3f\x98\xf0\x00\x00\x00\x00\xd3\xa7@\x80\x00\x00\x00\x00\xd41\x9f\xf0\x00\x00\x00\x00\xd4\xfc\xb5\x00\x00\x00\x00\x00\xd5=@p\x00\x00\x00\x00\xd5t\xad\x80\x00\x00\x00\x00\xd6\x1a\xbcp\x00\x00\x00\x00\xd6\xdc\x97\x00\x00\x00\x00\x00\xd7\x0a\xadp\x00\x00\x00\x00\xd7KU\x00\x00\x00\x00\x00\xd7\xfa\x9ep\x00\x00\x00\x00\xd8\xbcy\x00\x00\x00\x00\x00\xd8\xe1T\xf0\x00\x00\x00\x00\xd9!\xfc\x80\x00\x00\x00\x00\xd9\xda\x80p\x00\x00\x00\x00\xda\xa5\x95\x80\x00\x00\x00\x00\xda\xb7\xfcp\x00\x00\x00\x00\xda\xefi\x80\x00\x00\x00\x00\xdb\xbabp\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00 P\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09\x00\x00*0\x01\x0d\x00\x00\x1c \x00\x11LMT\x00EEST\x00EET\x00IDT\x00IST\x00\x0aEET-2EEST,M3.4.4/50,M10.4.4/50\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0b\x00\x00\x00Asia/HarbinTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff~6C)\xff\xff\xff\xff\xa0\x97\xa2\x80\xff\xff\xff\xff\xa1y\x04\xf0\xff\xff\xff\xff\xc8Y^\x80\xff\xff\xff\xff\xc9\x09\xf9p\xff\xff\xff\xff\xc9\xd3\xbd\x00\xff\xff\xff\xff\xcb\x05\x8a\xf0\xff\xff\xff\xff\xcb|@\x00\xff\xff\xff\xff\xd2;>\xf0\xff\xff\xff\xff\xd3\x8b{\x80\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5E\x22\x00\xff\xff\xff\xff\xd6L\xbf\xf0\xff\xff\xff\xff\xd7<\xbf\x00\xff\xff\xff\xff\xd8\x06fp\xff\xff\xff\xff\xd9\x1d\xf2\x80\xff\xff\xff\xff\xd9A|\xf0\x00\x00\x00\x00\x1e\xbaR \x00\x00\x00\x00\x1fi\x9b\x90\x00\x00\x00\x00 ~\x84\xa0\x00\x00\x00\x00!I}\x90\x00\x00\x00\x00\x22g\xa1 \x00\x00\x00\x00#)_\x90\x00\x00\x00\x00$G\x83 \x00\x00\x00\x00%\x12|\x10\x00\x00\x00\x00&'e \x00\x00\x00\x00&\xf2^\x10\x00\x00\x00\x00(\x07G \x00\x00\x00\x00(\xd2@\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00q\xd7\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x08LMT\x00CDT\x00CST\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d2\x08\xd6\x98\x0b\x00\x00\x98\x0b\x00\x00\x0b\x00\x00\x00Asia/HebronTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x016\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff}\xbdJ\x19\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xff\xcd\xac\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xff\xcf\x8f\x83\x00\xff\xff\xff\xff\xd0\xa9\xa4\x00\xff\xff\xff\xff\xd1\x84}\x00\xff\xff\xff\xff\xd2\x8a\xd7\x80\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\x0b\x00\xff\xff\xff\xff\xe86c`\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\x0b\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xfa\xf0\xff\xff\xff\xff\xec\xb5m\x00\xff\xff\xff\xff\xed\xcf\x7f\xf0\xff\xff\xff\xff\xee\x97\xf2\x00\xff\xff\xff\xff\xef\xb0\xb3p\xff\xff\xff\xff\xf0y%\x80\xff\xff\xff\xff\xf1\x91\xe6\xf0\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3s\x1ap\xff\xff\xff\xff\xf4;\x8c\x80\xff\xff\xff\xff\xf5U\x9fp\xff\xff\xff\xff\xf6\x1e\x11\x80\xff\xff\xff\xff\xf76\xd2\xf0\xff\xff\xff\xff\xf7\xffE\x00\xff\xff\xff\xff\xf9\x18\x06p\xff\xff\xff\xff\xf9\xe1\xca\x00\xff\xff\xff\xff\xfa\xf99\xf0\xff\xff\xff\xff\xfb'BP\x00\x00\x00\x00\x08|\x8b\xe0\x00\x00\x00\x00\x08\xfd\xb0\xd0\x00\x00\x00\x00\x09\xf6\xea`\x00\x00\x00\x00\x0a\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\x22^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x000\xe7\x07\xe0\x00\x00\x00\x001dF`\x00\x00\x00\x002A\xc2`\x00\x00\x00\x003D(`\x00\x00\x00\x004!\xa4`\x00\x00\x00\x005$\x0a`\x00\x00\x00\x006\x01\x86`\x00\x00\x00\x007\x16a`\x00\x00\x00\x008\x06DP\x00\x00\x00\x008\xff}\xe0\x00\x00\x00\x009\xef`\xd0\x00\x00\x00\x00:\xdf_\xe0\x00\x00\x00\x00;\xcfB\xd0\x00\x00\x00\x00<\xbfA\xe0\x00\x00\x00\x00=\xaf$\xd0\x00\x00\x00\x00>\x9f#\xe0\x00\x00\x00\x00?\x8f\x06\xd0\x00\x00\x00\x00@\x7f\x05\xe0\x00\x00\x00\x00A\x5c\x81\xe0\x00\x00\x00\x00B^\xe7\xe0\x00\x00\x00\x00CA\xb7\xf0\x00\x00\x00\x00D-\xa6`\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F\x0e\xd9\xe0\x00\x00\x00\x00F\xe8op\x00\x00\x00\x00G\xec\x18\xe0\x00\x00\x00\x00H\xbb\x06P\x00\x00\x00\x00I\xcb\xfa\xe0\x00\x00\x00\x00J\xa0<`\x00\x00\x00\x00K\xab\xdc\xe0\x00\x00\x00\x00La\xbd\xd0\x00\x00\x00\x00M\x94\xf9\x9c\x00\x00\x00\x00N5\xc2P\x00\x00\x00\x00N\x5c\x0b\xe0\x00\x00\x00\x00N\x84\xdcP\x00\x00\x00\x00Ot\xdb`\x00\x00\x00\x00P[\x91\xe0\x00\x00\x00\x00QT\xbd`\x00\x00\x00\x00RD\xa0P\x00\x00\x00\x00S4\x9f`\x00\x00\x00\x00TIlP\x00\x00\x00\x00U\x15\xd2\xe0\x00\x00\x00\x00V)\x5c`\x00\x00\x00\x00V\xf5\xc2\xf0\x00\x00\x00\x00X\x13\xca`\x00\x00\x00\x00X\xd5\xa4\xf0\x00\x00\x00\x00Y\xf3\xac`\x00\x00\x00\x00Z\xb5\x86\xf0\x00\x00\x00\x00[\xd3\x8e`\x00\x00\x00\x00\x5c\x9dC\xe0\x00\x00\x00\x00]\xb3bP\x00\x00\x00\x00^~w`\x00\x00\x00\x00_\x93R`\x00\x00\x00\x00`^Y`\x00\x00\x00\x00a{\x1d`\x00\x00\x00\x00b?\x8c\xe0\x00\x00\x00\x00c\x5c^\xf0\x00\x00\x00\x00dL^\x00\x00\x00\x00\x00e<@\xf0\x00\x00\x00\x00f#\x05\x80\x00\x00\x00\x00g\x1c\x22\xf0\x00\x00\x00\x00g\xf9\xad\x00\x00\x00\x00\x00h\xfc\x04\xf0\x00\x00\x00\x00i\xc7\x1a\x00\x00\x00\x00\x00j\xdb\xe6\xf0\x00\x00\x00\x00k\xa6\xfc\x00\x00\x00\x00\x00l\xc5\x03p\x00\x00\x00\x00m\x86\xde\x00\x00\x00\x00\x00n\xa4\xe5p\x00\x00\x00\x00of\xc0\x00\x00\x00\x00\x00p\x84\xc7p\x00\x00\x00\x00qO\xdc\x80\x00\x00\x00\x00rd\xa9p\x00\x00\x00\x00s/\xbe\x80\x00\x00\x00\x00tD\x8bp\x00\x00\x00\x00u\x0f\xa0\x80\x00\x00\x00\x00v-\xa7\xf0\x00\x00\x00\x00v\xef\x82\x80\x00\x00\x00\x00x\x0d\x89\xf0\x00\x00\x00\x00x\xcfd\x80\x00\x00\x00\x00y\xedk\xf0\x00\x00\x00\x00z\xafF\x80\x00\x00\x00\x00{\xcdM\xf0\x00\x00\x00\x00|\x98c\x00\x00\x00\x00\x00}\xa3\xf5p\x00\x00\x00\x00~xE\x00\x00\x00\x00\x00\x7fz\x9c\xf0\x00\x00\x00\x00\x80X'\x00\x00\x00\x00\x00\x81H\x09\xf0\x00\x00\x00\x00\x828\x09\x00\x00\x00\x00\x00\x83\x1e\xb1p\x00\x00\x00\x00\x84\x17\xeb\x00\x00\x00\x00\x00\x84\xec\x1ep\x00\x00\x00\x00\x85,\xc6\x00\x00\x00\x00\x00\x855\xf2p\x00\x00\x00\x00\x86\x01\x07\x80\x00\x00\x00\x00\x86\xc2\xc5\xf0\x00\x00\x00\x00\x86\xfa3\x00\x00\x00\x00\x00\x87\x15\xd4p\x00\x00\x00\x00\x87\xe0\xe9\x80\x00\x00\x00\x00\x88\x99mp\x00\x00\x00\x00\x88\xd0\xda\x80\x00\x00\x00\x00\x88\xf5\xb6p\x00\x00\x00\x00\x89\xc0\xcb\x80\x00\x00\x00\x00\x8af\xdap\x00\x00\x00\x00\x8a\xa7\x82\x00\x00\x00\x00\x00\x8a\xd5\x98p\x00\x00\x00\x00\x8b\xa0\xad\x80\x00\x00\x00\x00\x8c=\x81\xf0\x00\x00\x00\x00\x8ct\xef\x00\x00\x00\x00\x00\x8c\xbe\xb4\xf0\x00\x00\x00\x00\x8d\x80\x8f\x80\x00\x00\x00\x00\x8e\x14)p\x00\x00\x00\x00\x8eK\x96\x80\x00\x00\x00\x00\x8e\x9e\x96\xf0\x00\x00\x00\x00\x8f`q\x80\x00\x00\x00\x00\x8f\xe1\x96p\x00\x00\x00\x00\x90\x22>\x00\x00\x00\x00\x00\x90~x\xf0\x00\x00\x00\x00\x91I\x8e\x00\x00\x00\x00\x00\x91\xb8=\xf0\x00\x00\x00\x00\x91\xef\xab\x00\x00\x00\x00\x00\x92^Z\xf0\x00\x00\x00\x00\x93)p\x00\x00\x00\x00\x00\x93\x85\xaa\xf0\x00\x00\x00\x00\x93\xc6R\x80\x00\x00\x00\x00\x94><\xf0\x00\x00\x00\x00\x95\x09R\x00\x00\x00\x00\x00\x95\x5cRp\x00\x00\x00\x00\x95\x93\xbf\x80\x00\x00\x00\x00\x96'Yp\x00\x00\x00\x00\x96\xe94\x00\x00\x00\x00\x00\x972\xf9\xf0\x00\x00\x00\x00\x97jg\x00\x00\x00\x00\x00\x98\x07;p\x00\x00\x00\x00\x98\xc9\x16\x00\x00\x00\x00\x00\x99\x00f\xf0\x00\x00\x00\x00\x99A\x0e\x80\x00\x00\x00\x00\x99\xe7\x1dp\x00\x00\x00\x00\x9a\xb22\x80\x00\x00\x00\x00\x9a\xd7\x0ep\x00\x00\x00\x00\x9b\x0e{\x80\x00\x00\x00\x00\x9b\xc6\xffp\x00\x00\x00\x00\x9c\x92\x14\x80\x00\x00\x00\x00\x9c\xa4{p\x00\x00\x00\x00\x9c\xe5#\x00\x00\x00\x00\x00\x9d\xa6\xe1p\x00\x00\x00\x00\x9eq\xf6\x80\x00\x00\x00\x00\x9e{\x22\xf0\x00\x00\x00\x00\x9e\xbb\xca\x80\x00\x00\x00\x00\x9f\x86\xc3p\x00\x00\x00\x00\xa0\x897\x80\x00\x00\x00\x00\xa1o\xdf\xf0\x00\x00\x00\x00\xa2_\xdf\x00\x00\x00\x00\x00\xa3O\xc1\xf0\x00\x00\x00\x00\xa4-L\x00\x00\x00\x00\x00\xa5/\xa3\xf0\x00\x00\x00\x00\xa6\x03\xf3\x80\x00\x00\x00\x00\xa7\x0f\x85\xf0\x00\x00\x00\x00\xa7\xda\x9b\x00\x00\x00\x00\x00\xa8\xefg\xf0\x00\x00\x00\x00\xa9\xba}\x00\x00\x00\x00\x00\xaa\xd8\x84p\x00\x00\x00\x00\xab\x9a_\x00\x00\x00\x00\x00\xac\xb8fp\x00\x00\x00\x00\xadzA\x00\x00\x00\x00\x00\xae\x98Hp\x00\x00\x00\x00\xafZ#\x00\x00\x00\x00\x00\xb0x*p\x00\x00\x00\x00\xb1C?\x80\x00\x00\x00\x00\xb2X\x0cp\x00\x00\x00\x00\xb3#!\x80\x00\x00\x00\x00\xb47\xeep\x00\x00\x00\x00\xb5\x03\x03\x80\x00\x00\x00\x00\xb6!\x0a\xf0\x00\x00\x00\x00\xb6\xe2\xe5\x80\x00\x00\x00\x00\xb8\x00\xec\xf0\x00\x00\x00\x00\xb8\xc2\xc7\x80\x00\x00\x00\x00\xb9\xd7\x94p\x00\x00\x00\x00\xba\xab\xe4\x00\x00\x00\x00\x00\xbb\xae;\xf0\x00\x00\x00\x00\xbc\x8b\xc6\x00\x00\x00\x00\x00\xbd\x84\xe3p\x00\x00\x00\x00\xbek\xa8\x00\x00\x00\x00\x00\xbfRPp\x00\x00\x00\x00\xc0K\x8a\x00\x00\x00\x00\x00\xc1(\xf7\xf0\x00\x00\x00\x00\xc1`e\x00\x00\x00\x00\x00\xc1i\x91p\x00\x00\x00\x00\xc2+l\x00\x00\x00\x00\x00\xc2\xff\x9fp\x00\x00\x00\x00\xc37\x0c\x80\x00\x00\x00\x00\xc3Isp\x00\x00\x00\x00\xc4\x0bN\x00\x00\x00\x00\x00\xc4\xcd\x0cp\x00\x00\x00\x00\xc5\x0d\xb4\x00\x00\x00\x00\x00\xc5)Up\x00\x00\x00\x00\xc5\xf4j\x80\x00\x00\x00\x00\xc6\xa3\xb3\xf0\x00\x00\x00\x00\xc6\xdb!\x00\x00\x00\x00\x00\xc7\x097p\x00\x00\x00\x00\xc7\xd4L\x80\x00\x00\x00\x00\xc8q \xf0\x00\x00\x00\x00\xc8\xb1\xc8\x80\x00\x00\x00\x00\xc8\xe9\x19p\x00\x00\x00\x00\xc9\xb4.\x80\x00\x00\x00\x00\xcaG\xc8p\x00\x00\x00\x00\xca\x88p\x00\x00\x00\x00\x00\xca\xd25\xf0\x00\x00\x00\x00\xcb\x94\x10\x80\x00\x00\x00\x00\xcc\x1eo\xf0\x00\x00\x00\x00\xccU\xdd\x00\x00\x00\x00\x00\xcc\xb2\x17\xf0\x00\x00\x00\x00\xcds\xf2\x80\x00\x00\x00\x00\xcd\xeb\xdc\xf0\x00\x00\x00\x00\xce,\x84\x80\x00\x00\x00\x00\xce\x91\xf9\xf0\x00\x00\x00\x00\xcf]\x0f\x00\x00\x00\x00\x00\xcf\xc2\x84p\x00\x00\x00\x00\xcf\xf9\xf1\x80\x00\x00\x00\x00\xd0q\xdb\xf0\x00\x00\x00\x00\xd1<\xf1\x00\x00\x00\x00\x00\xd1\x99+\xf0\x00\x00\x00\x00\xd1\xd0\x99\x00\x00\x00\x00\x00\xd2Q\xbd\xf0\x00\x00\x00\x00\xd3\x1c\xd3\x00\x00\x00\x00\x00\xd3f\x98\xf0\x00\x00\x00\x00\xd3\xa7@\x80\x00\x00\x00\x00\xd41\x9f\xf0\x00\x00\x00\x00\xd4\xfc\xb5\x00\x00\x00\x00\x00\xd5=@p\x00\x00\x00\x00\xd5t\xad\x80\x00\x00\x00\x00\xd6\x1a\xbcp\x00\x00\x00\x00\xd6\xdc\x97\x00\x00\x00\x00\x00\xd7\x0a\xadp\x00\x00\x00\x00\xd7KU\x00\x00\x00\x00\x00\xd7\xfa\x9ep\x00\x00\x00\x00\xd8\xbcy\x00\x00\x00\x00\x00\xd8\xe1T\xf0\x00\x00\x00\x00\xd9!\xfc\x80\x00\x00\x00\x00\xd9\xda\x80p\x00\x00\x00\x00\xda\xa5\x95\x80\x00\x00\x00\x00\xda\xb7\xfcp\x00\x00\x00\x00\xda\xefi\x80\x00\x00\x00\x00\xdb\xbabp\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00 \xe7\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09\x00\x00*0\x01\x0d\x00\x00\x1c \x00\x11LMT\x00EEST\x00EET\x00IDT\x00IST\x00\x0aEET-2EEST,M3.4.4/50,M10.4.4/50\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8!YF\xec\x00\x00\x00\xec\x00\x00\x00\x10\x00\x00\x00Asia/Ho_Chi_MinhTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff\x88\x8cC\x8a\xff\xff\xff\xff\x91\xa3+\x0a\xff\xff\xff\xff\xcd5\xe6\x80\xff\xff\xff\xff\xd1Y\xcep\xff\xff\xff\xff\xd2;>\xf0\xff\xff\xff\xff\xd52\xbb\x10\xff\xff\xff\xff\xe4\xb6\xf2\x90\xff\xff\xff\xff\xed/\x98\x00\x00\x00\x00\x00\x0a=\xc7\x00\x01\x02\x03\x04\x02\x03\x02\x03\x02\x00\x00c\xf6\x00\x00\x00\x00c\xf6\x00\x04\x00\x00bp\x00\x09\x00\x00p\x80\x00\x0d\x00\x00~\x90\x00\x11LMT\x00PLMT\x00+07\x00+08\x00+09\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x09\xfa-\x07\x03\x00\x00\x07\x03\x00\x00\x0e\x00\x00\x00Asia/Hong_KongTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x00\x00\x00\x05\x00\x00\x00\x16\xff\xff\xff\xff\x85ic\x90\xff\xff\xff\xff\xcaM10\xff\xff\xff\xff\xca\xdb\x930\xff\xff\xff\xff\xcbKqx\xff\xff\xff\xff\xd2\xa0\xde\x90\xff\xff\xff\xff\xd3k\xd7\x80\xff\xff\xff\xff\xd4\x93X\xb8\xff\xff\xff\xff\xd5B\xb08\xff\xff\xff\xff\xd6s:\xb8\xff\xff\xff\xff\xd7>A\xb8\xff\xff\xff\xff\xd8.2\xb8\xff\xff\xff\xff\xd8\xf99\xb8\xff\xff\xff\xff\xda\x0e\x14\xb8\xff\xff\xff\xff\xda\xd9\x1b\xb8\xff\xff\xff\xff\xdb\xed\xf6\xb8\xff\xff\xff\xff\xdc\xb8\xfd\xb8\xff\xff\xff\xff\xdd\xcd\xd8\xb8\xff\xff\xff\xff\xde\xa2\x1a8\xff\xff\xff\xff\xdf\xb6\xf58\xff\xff\xff\xff\xe0\x81\xfc8\xff\xff\xff\xff\xe1\x96\xc9(\xff\xff\xff\xff\xe2Oi8\xff\xff\xff\xff\xe3v\xab(\xff\xff\xff\xff\xe4/K8\xff\xff\xff\xff\xe5_\xc7\xa8\xff\xff\xff\xff\xe6\x0f-8\xff\xff\xff\xff\xe7?\xa9\xa8\xff\xff\xff\xff\xe7\xf8I\xb8\xff\xff\xff\xff\xe9\x1f\x8b\xa8\xff\xff\xff\xff\xe9\xd8+\xb8\xff\xff\xff\xff\xea\xffm\xa8\xff\xff\xff\xff\xeb\xb8\x0d\xb8\xff\xff\xff\xff\xec\xdfO\xa8\xff\xff\xff\xff\xed\x97\xef\xb8\xff\xff\xff\xff\xee\xc8l(\xff\xff\xff\xff\xefw\xd1\xb8\xff\xff\xff\xff\xf0\xa8N(\xff\xff\xff\xff\xf1W\xb3\xb8\xff\xff\xff\xff\xf2\x880(\xff\xff\xff\xff\xf3@\xd08\xff\xff\xff\xff\xf4h\x12(\xff\xff\xff\xff\xf5 \xb28\xff\xff\xff\xff\xf6G\xf4(\xff\xff\xff\xff\xf7%~8\xff\xff\xff\xff\xf8\x15a(\xff\xff\xff\xff\xf9\x05`8\xff\xff\xff\xff\xf9\xf5C(\xff\xff\xff\xff\xfa\xe5B8\xff\xff\xff\xff\xfb\xde_\xa8\xff\xff\xff\xff\xfc\xce^\xb8\xff\xff\xff\xff\xfd\xbeA\xa8\xff\xff\xff\xff\xfe\xae@\xb8\xff\xff\xff\xff\xff\x9e#\xa8\x00\x00\x00\x00\x00\x8e\x22\xb8\x00\x00\x00\x00\x01~\x05\xa8\x00\x00\x00\x00\x02n\x04\xb8\x00\x00\x00\x00\x03]\xe7\xa8\x00\x00\x00\x00\x04M\xe6\xb8\x00\x00\x00\x00\x05G\x04(\x00\x00\x00\x00\x067\x038\x00\x00\x00\x00\x07&\xe6(\x00\x00\x00\x00\x07\x83=8\x00\x00\x00\x00\x09\x06\xc8(\x00\x00\x00\x00\x09\xf6\xc78\x00\x00\x00\x00\x0a\xe6\xaa(\x00\x00\x00\x00\x0b\xd6\xa98\x00\x00\x00\x00\x0c\xc6\x8c(\x00\x00\x00\x00\x11\x9b98\x00\x00\x00\x00\x12ol\xa8\x01\x02\x03\x04\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00k\x0a\x00\x00\x00\x00p\x80\x00\x04\x00\x00~\x90\x01\x08\x00\x00w\x88\x01\x0d\x00\x00~\x90\x00\x12LMT\x00HKT\x00HKST\x00HKWT\x00JST\x00\x0aHKT-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xba\xa3b\xc1R\x02\x00\x00R\x02\x00\x00\x09\x00\x00\x00Asia/HovdTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\x86\xd3\xfc\x94\x00\x00\x00\x00\x0f\x0b\xea\xa0\x00\x00\x00\x00\x18\xe9\xd6\x90\x00\x00\x00\x00\x19\xdb\x0b\x00\x00\x00\x00\x00\x1a\xcc[\x90\x00\x00\x00\x00\x1b\xbc>\x80\x00\x00\x00\x00\x1c\xac=\x90\x00\x00\x00\x00\x1d\x9c \x80\x00\x00\x00\x00\x1e\x8c\x1f\x90\x00\x00\x00\x00\x1f|\x02\x80\x00\x00\x00\x00 l\x01\x90\x00\x00\x00\x00![\xe4\x80\x00\x00\x00\x00\x22K\xe3\x90\x00\x00\x00\x00#;\xc6\x80\x00\x00\x00\x00$+\xc5\x90\x00\x00\x00\x00%\x1b\xa8\x80\x00\x00\x00\x00&\x0b\xa7\x90\x00\x00\x00\x00'\x04\xc5\x00\x00\x00\x00\x00'\xf4\xc4\x10\x00\x00\x00\x00(\xe4\xa7\x00\x00\x00\x00\x00)\xd4\xa6\x10\x00\x00\x00\x00*\xc4\x89\x00\x00\x00\x00\x00+\xb4\x88\x10\x00\x00\x00\x00,\xa4k\x00\x00\x00\x00\x00-\x94j\x10\x00\x00\x00\x00.\x84M\x00\x00\x00\x00\x00/tL\x10\x00\x00\x00\x000d/\x00\x00\x00\x00\x001]h\x90\x00\x00\x00\x002MK\x80\x00\x00\x00\x003=J\x90\x00\x00\x00\x004--\x80\x00\x00\x00\x005\x1d,\x90\x00\x00\x00\x006\x0d\x0f\x80\x00\x00\x00\x00:\xe9\xc1\xb0\x00\x00\x00\x00;\xb4\xba\xa0\x00\x00\x00\x00<\xa4\xb9\xb0\x00\x00\x00\x00=\x94\x9c\xa0\x00\x00\x00\x00>\x84\x9b\xb0\x00\x00\x00\x00?t~\xa0\x00\x00\x00\x00@d}\xb0\x00\x00\x00\x00AT`\xa0\x00\x00\x00\x00BD_\xb0\x00\x00\x00\x00C4B\xa0\x00\x00\x00\x00D$A\xb0\x00\x00\x00\x00E\x1d_ \x00\x00\x00\x00U\x15\xa8\xb0\x00\x00\x00\x00V\x05o\x80\x00\x00\x00\x00V\xf5\x8a\xb0\x00\x00\x00\x00W\xe5Q\x80\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00U\xec\x00\x00\x00\x00T`\x00\x04\x00\x00p\x80\x01\x08\x00\x00bp\x00\x0cLMT\x00+06\x00+08\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf9l\x03\x12\xf8\x02\x00\x00\xf8\x02\x00\x00\x0c\x00\x00\x00Asia/IrkutskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x07\x00\x00\x00\x14\xff\xff\xff\xffV\xb6\x82?\xff\xff\xff\xff\xa2\x12\x0f\xbf\xff\xff\xff\xff\xb5\xa3\xd3\x10\x00\x00\x00\x00\x15'a\x80\x00\x00\x00\x00\x16\x18\x95\xf0\x00\x00\x00\x00\x17\x08\x95\x00\x00\x00\x00\x00\x17\xf9\xc9p\x00\x00\x00\x00\x18\xe9\xc8\x80\x00\x00\x00\x00\x19\xda\xfc\xf0\x00\x00\x00\x00\x1a\xccM\x80\x00\x00\x00\x00\x1b\xbcZ\xa0\x00\x00\x00\x00\x1c\xacK\xa0\x00\x00\x00\x00\x1d\x9c<\xa0\x00\x00\x00\x00\x1e\x8c-\xa0\x00\x00\x00\x00\x1f|\x1e\xa0\x00\x00\x00\x00 l\x0f\xa0\x00\x00\x00\x00!\x5c\x00\xa0\x00\x00\x00\x00\x22K\xf1\xa0\x00\x00\x00\x00#;\xe2\xa0\x00\x00\x00\x00$+\xd3\xa0\x00\x00\x00\x00%\x1b\xc4\xa0\x00\x00\x00\x00&\x0b\xb5\xa0\x00\x00\x00\x00'\x04\xe1 \x00\x00\x00\x00'\xf4\xd2 \x00\x00\x00\x00(\xe4\xd10\x00\x00\x00\x00)xy0\x00\x00\x00\x00)\xd4\xb4 \x00\x00\x00\x00*\xc4\xa5 \x00\x00\x00\x00+\xb4\x96 \x00\x00\x00\x00,\xa4\x87 \x00\x00\x00\x00-\x94x \x00\x00\x00\x00.\x84i \x00\x00\x00\x00/tZ \x00\x00\x00\x000dK \x00\x00\x00\x001]v\xa0\x00\x00\x00\x002rQ\xa0\x00\x00\x00\x003=X\xa0\x00\x00\x00\x004R3\xa0\x00\x00\x00\x005\x1d:\xa0\x00\x00\x00\x0062\x15\xa0\x00\x00\x00\x006\xfd\x1c\xa0\x00\x00\x00\x008\x1b2 \x00\x00\x00\x008\xdc\xfe\xa0\x00\x00\x00\x009\xfb\x14 \x00\x00\x00\x00:\xbc\xe0\xa0\x00\x00\x00\x00;\xda\xf6 \x00\x00\x00\x00<\xa5\xfd \x00\x00\x00\x00=\xba\xd8 \x00\x00\x00\x00>\x85\xdf \x00\x00\x00\x00?\x9a\xba \x00\x00\x00\x00@e\xc1 \x00\x00\x00\x00A\x83\xd6\xa0\x00\x00\x00\x00BE\xa3 \x00\x00\x00\x00Cc\xb8\xa0\x00\x00\x00\x00D%\x85 \x00\x00\x00\x00EC\x9a\xa0\x00\x00\x00\x00F\x05g \x00\x00\x00\x00G#|\xa0\x00\x00\x00\x00G\xee\x83\xa0\x00\x00\x00\x00I\x03^\xa0\x00\x00\x00\x00I\xcee\xa0\x00\x00\x00\x00J\xe3@\xa0\x00\x00\x00\x00K\xaeG\xa0\x00\x00\x00\x00L\xcc] \x00\x00\x00\x00M\x8e)\xa0\x00\x00\x00\x00TK\xd7\x10\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x05\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x06\x04\x00\x00a\xc1\x00\x00\x00\x00a\xc1\x00\x04\x00\x00bp\x00\x08\x00\x00~\x90\x01\x0c\x00\x00p\x80\x00\x10\x00\x00p\x80\x01\x10\x00\x00~\x90\x00\x0cLMT\x00IMT\x00+07\x00+09\x00+08\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07W\x10\xd1\xb0\x04\x00\x00\xb0\x04\x00\x00\x0d\x00\x00\x00Asia/IstanbulTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\x00\x00\x00\x06\x00\x00\x00\x19\xff\xff\xff\xffV\xb6\xc8\xd8\xff\xff\xff\xff\x90\x8b\xf5\x98\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xbe\xd0\xff\xff\xff\xff\xa2ec\xe0\xff\xff\xff\xff\xa3{\x82P\xff\xff\xff\xff\xa4N\x80`\xff\xff\xff\xff\xa5?\xb4\xd0\xff\xff\xff\xff\xa6%'\xe0\xff\xff\xff\xff\xa7'\x7f\xd0\xff\xff\xff\xff\xaa((`\xff\xff\xff\xff\xaa\xe1\xfd\xd0\xff\xff\xff\xff\xab\xf9\x89\xe0\xff\xff\xff\xff\xac\xc31P\xff\xff\xff\xff\xc8\x81?\xe0\xff\xff\xff\xff\xc9\x01\x13P\xff\xff\xff\xff\xc9J\xf5`\xff\xff\xff\xff\xca\xce\x80P\xff\xff\xff\xff\xcb\xcb\xae`\xff\xff\xff\xff\xd2k\x09P\xff\xff\xff\xff\xd3\xa29`\xff\xff\xff\xff\xd4C\x02P\xff\xff\xff\xff\xd5L\x0d\xe0\xff\xff\xff\xff\xd6){\xd0\xff\xff\xff\xff\xd7+\xef\xe0\xff\xff\xff\xff\xd8\x09]\xd0\xff\xff\xff\xff\xd9\x02\x97`\xff\xff\xff\xff\xd9\xe9?\xd0\xff\xff\xff\xff\xda\xeb\xb3\xe0\xff\xff\xff\xff\xdb\xd2\x5cP\xff\xff\xff\xff\xdc\xd4\xd0`\xff\xff\xff\xff\xdd\xb2>P\xff\xff\xff\xff\xf1\xf4\xb9`\xff\xff\xff\xff\xf4b\xefP\xff\xff\xff\xff\xf5h\x06`\xff\xff\xff\xff\xf6\x1f8\xd0\x00\x00\x00\x00\x06n\x93p\x00\x00\x00\x00\x079\x9ap\x00\x00\x00\x00\x07\xfbu\x00\x00\x00\x00\x00\x09\x19|p\x00\x00\x00\x00\x09\xd0\xcb\x00\x00\x00\x00\x00\x0a\xf9^p\x00\x00\x00\x00\x0b\xb1\xfe\x80\x00\x00\x00\x00\x0c\xd9@p\x00\x00\x00\x00\x0d\xa4U\x80\x00\x00\x00\x00\x0e\xa6\xadp\x00\x00\x00\x00\x0f\x847\x80\x00\x00\x00\x00\x0f\xf8\x11P\x00\x00\x00\x00\x19\x89\xb0p\x00\x00\x00\x00\x19\xdc\xb0\xe0\x00\x00\x00\x00\x1b\xe6\xd0\xf0\x00\x00\x00\x00\x1c\xc6\xef\xf0\x00\x00\x00\x00\x1d\x9b1p\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00(\xe5\x09p\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x8b\x83\xf0\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8f\xdd\x90\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S8\xbe\x10\x00\x00\x00\x00TLG\x90\x00\x00\x00\x00U\x17N\x90\x00\x00\x00\x00V>\x9e\x90\x00\x00\x00\x00V\xf70\x90\x00\x00\x00\x00W\xcf.P\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x05\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x00\x00\x1b(\x00\x00\x00\x00\x1bh\x00\x04\x00\x00*0\x01\x08\x00\x00\x1c \x00\x0d\x00\x00*0\x00\x11\x00\x008@\x01\x15LMT\x00IMT\x00EEST\x00EET\x00+03\x00+04\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xad\xc5\xb1\xf8\x00\x00\x00\xf8\x00\x00\x00\x0c\x00\x00\x00Asia/JakartaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x07\x00\x00\x00 \xff\xff\xff\xff?fI`\xff\xff\xff\xff\xa9x\x85\xe0\xff\xff\xff\xff\xba\x16\xde`\xff\xff\xff\xff\xcb\xbf\x83\x88\xff\xff\xff\xff\xd2V\xeep\xff\xff\xff\xff\xd7<\xc6\x08\xff\xff\xff\xff\xda\xff&\x00\xff\xff\xff\xff\xf4\xb5\xbe\x88\x01\x02\x03\x04\x03\x05\x03\x06\x00\x00d \x00\x00\x00\x00d \x00\x04\x00\x00g \x00\x08\x00\x00ix\x00\x0e\x00\x00~\x90\x00\x14\x00\x00p\x80\x00\x18\x00\x00bp\x00\x1cLMT\x00BMT\x00+0720\x00+0730\x00+09\x00+08\x00WIB\x00\x0aWIB-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.>[K\xab\x00\x00\x00\xab\x00\x00\x00\x0d\x00\x00\x00Asia/JayapuraTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\xba\x16\xc1\x98\xff\xff\xff\xff\xd0X\xb9\xf0\xff\xff\xff\xff\xf4\xb5\xa2h\x01\x02\x03\x00\x00\x83\xe8\x00\x00\x00\x00~\x90\x00\x04\x00\x00\x85\x98\x00\x08\x00\x00~\x90\x00\x0eLMT\x00+09\x00+0930\x00WIT\x00\x0aWIT-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xe2\x9c\xb32\x04\x00\x002\x04\x00\x00\x0e\x00\x00\x00Asia/JerusalemTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xffV\xb6\xc2\xfa\xff\xff\xff\xff\x9e0E\x88\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xff\xcd\xac\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xff\xcf\x8f\x83\x00\xff\xff\xff\xff\xd0\xa9\xa4\x00\xff\xff\xff\xff\xd1\x84}\x00\xff\xff\xff\xff\xd2\x8a\xd7\x80\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\x0b\x00\xff\xff\xff\xff\xd7Z0\x80\xff\xff\xff\xff\xd7\xdfX\x00\xff\xff\xff\xff\xd8/\xc3\x80\xff\xff\xff\xff\xd9\x1ec\x00\xff\xff\xff\xff\xda\x10\xf7\x00\xff\xff\xff\xff\xda\xeb\xd0\x00\xff\xff\xff\xff\xdb\xb44\x00\xff\xff\xff\xff\xdc\xb9=\x00\xff\xff\xff\xff\xdd\xe0\x8d\x00\xff\xff\xff\xff\xde\xb4\xce\x80\xff\xff\xff\xff\xdf\xa4\xbf\x80\xff\xff\xff\xff\xe0\x8bv\x00\xff\xff\xff\xff\xe1V}\x00\xff\xff\xff\xff\xe2\xbef\x80\xff\xff\xff\xff\xe36_\x00\xff\xff\xff\xff\xe4\x9eH\x80\xff\xff\xff\xff\xe5\x16A\x00\xff\xff\xff\xff\xe6t\xf0\x00\xff\xff\xff\xff\xe7\x11\xd2\x80\xff\xff\xff\xff\xe8&\xad\x80\xff\xff\xff\xff\xe8\xe8z\x00\x00\x00\x00\x00\x08|\x8b\xe0\x00\x00\x00\x00\x08\xfd\xb0\xd0\x00\x00\x00\x00\x09\xf6\xea`\x00\x00\x00\x00\x0a\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\x22^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x001H\x96\xe0\x00\x00\x00\x002\x83\x82p\x00\x00\x00\x00?|\x9f\xe0\x00\x00\x00\x00@s6p\x00\x00\x00\x00AP\xa4`\x00\x00\x00\x00BL\x8f\x00\x00\x00\x00\x00CHOp\x00\x00\x00\x00D,q\x00\x00\x00\x00\x00E\x1e\xf6\xf0\x00\x00\x00\x00F\x0cS\x00\x00\x00\x00\x00F\xecc\xf0\x00\x00\x00\x00G\xec5\x00\x00\x00\x00\x00H\xe7\xf5p\x00\x00\x00\x00I\xcc\x17\x00\x00\x00\x00\x00J\xbe\x9c\xf0\x00\x00\x00\x00K\xab\xf9\x00\x00\x00\x00\x00L\x8c\x09\xf0\x00\x00\x00\x00M\x95\x15\x80\x00\x00\x00\x00N\x87\x9bp\x00\x00\x00\x00Ot\xf7\x80\x00\x00\x00\x00P^B\xf0\x00\x00\x00\x00QT\xd9\x80\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x00!\x06\x00\x00\x00\x00 \xf8\x00\x04\x00\x00*0\x01\x08\x00\x00\x1c \x00\x0c\x00\x008@\x01\x10LMT\x00JMT\x00IDT\x00IST\x00IDDT\x00\x0aIST-2IDT,M3.4.4/26,M10.5.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\xe2\x5c\xff\x9f\x00\x00\x00\x9f\x00\x00\x00\x0a\x00\x00\x00Asia/KabulTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffi\x86\x9a\xa0\xff\xff\xff\xff\xd0\xf9\xd7@\x01\x02\x00\x00@\xe0\x00\x00\x00\x008@\x00\x04\x00\x00?H\x00\x08LMT\x00+04\x00+0430\x00\x0a<+0430>-4:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x9cf>\xd7\x02\x00\x00\xd7\x02\x00\x00\x0e\x00\x00\x00Asia/KamchatkaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xa7R\x96\xc4\xff\xff\xff\xff\xb5\xa3\x9a\xd0\x00\x00\x00\x00\x15')@\x00\x00\x00\x00\x16\x18]\xb0\x00\x00\x00\x00\x17\x08\x5c\xc0\x00\x00\x00\x00\x17\xf9\x910\x00\x00\x00\x00\x18\xe9\x90@\x00\x00\x00\x00\x19\xda\xc4\xb0\x00\x00\x00\x00\x1a\xcc\x15@\x00\x00\x00\x00\x1b\xbc\x22`\x00\x00\x00\x00\x1c\xac\x13`\x00\x00\x00\x00\x1d\x9c\x04`\x00\x00\x00\x00\x1e\x8b\xf5`\x00\x00\x00\x00\x1f{\xe6`\x00\x00\x00\x00 k\xd7`\x00\x00\x00\x00![\xc8`\x00\x00\x00\x00\x22K\xb9`\x00\x00\x00\x00#;\xaa`\x00\x00\x00\x00$+\x9b`\x00\x00\x00\x00%\x1b\x8c`\x00\x00\x00\x00&\x0b}`\x00\x00\x00\x00'\x04\xa8\xe0\x00\x00\x00\x00'\xf4\x99\xe0\x00\x00\x00\x00(\xe4\x98\xf0\x00\x00\x00\x00)x@\xf0\x00\x00\x00\x00)\xd4{\xe0\x00\x00\x00\x00*\xc4l\xe0\x00\x00\x00\x00+\xb4]\xe0\x00\x00\x00\x00,\xa4N\xe0\x00\x00\x00\x00-\x94?\xe0\x00\x00\x00\x00.\x840\xe0\x00\x00\x00\x00/t!\xe0\x00\x00\x00\x000d\x12\xe0\x00\x00\x00\x001]>`\x00\x00\x00\x002r\x19`\x00\x00\x00\x003= `\x00\x00\x00\x004Q\xfb`\x00\x00\x00\x005\x1d\x02`\x00\x00\x00\x0061\xdd`\x00\x00\x00\x006\xfc\xe4`\x00\x00\x00\x008\x1a\xf9\xe0\x00\x00\x00\x008\xdc\xc6`\x00\x00\x00\x009\xfa\xdb\xe0\x00\x00\x00\x00:\xbc\xa8`\x00\x00\x00\x00;\xda\xbd\xe0\x00\x00\x00\x00<\xa5\xc4\xe0\x00\x00\x00\x00=\xba\x9f\xe0\x00\x00\x00\x00>\x85\xa6\xe0\x00\x00\x00\x00?\x9a\x81\xe0\x00\x00\x00\x00@e\x88\xe0\x00\x00\x00\x00A\x83\x9e`\x00\x00\x00\x00BEj\xe0\x00\x00\x00\x00Cc\x80`\x00\x00\x00\x00D%L\xe0\x00\x00\x00\x00ECb`\x00\x00\x00\x00F\x05.\xe0\x00\x00\x00\x00G#D`\x00\x00\x00\x00G\xeeK`\x00\x00\x00\x00I\x03&`\x00\x00\x00\x00I\xce-`\x00\x00\x00\x00J\xe3\x08`\x00\x00\x00\x00K\xae\x0f`\x00\x00\x00\x00L\xcc2\xf0\x00\x00\x00\x00M\x8d\xffp\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x00\x00\x94\xbc\x00\x00\x00\x00\x9a\xb0\x00\x04\x00\x00\xb6\xd0\x01\x08\x00\x00\xa8\xc0\x00\x0c\x00\x00\xa8\xc0\x01\x0cLMT\x00+11\x00+13\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009Y\xb7\xf1\x0a\x01\x00\x00\x0a\x01\x00\x00\x0c\x00\x00\x00Asia/KarachiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x06\x00\x00\x00\x1d\xff\xff\xff\xff\x89~\xfc\xa4\xff\xff\xff\xff\xcc\x952\xa8\xff\xff\xff\xff\xd2t\x12\x98\xff\xff\xff\xff\xdd\xa8\xe0\xa8\x00\x00\x00\x00\x02O\xab0\x00\x00\x00\x00<\xafE\xb0\x00\x00\x00\x00=\x9f(\xa0\x00\x00\x00\x00HA\xa00\x00\x00\x00\x00I\x0bG\xa0\x00\x00\x00\x00I\xe4\xdd0\x00\x00\x00\x00J\xec{ \x01\x02\x01\x03\x05\x04\x05\x04\x05\x04\x05\x00\x00>\xdc\x00\x00\x00\x00MX\x00\x04\x00\x00[h\x01\x0a\x00\x00FP\x00\x10\x00\x00T`\x01\x14\x00\x00FP\x00\x19LMT\x00+0530\x00+0630\x00+05\x00PKST\x00PKT\x00\x0aPKT-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x1d\xc6\x1b\x85\x00\x00\x00\x85\x00\x00\x00\x0c\x00\x00\x00Asia/KashgarTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xb0\xfe\xbad\x01\x00\x00R\x1c\x00\x00\x00\x00T`\x00\x04LMT\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8bSnT\xa1\x00\x00\x00\xa1\x00\x00\x00\x0e\x00\x00\x00Asia/KathmanduTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xf2}\x84\x00\x00\x00\x00\x1e\x180\xa8\x01\x02\x00\x00O\xfc\x00\x00\x00\x00MX\x00\x04\x00\x00P\xdc\x00\x0aLMT\x00+0530\x00+0545\x00\x0a<+0545>-5:45\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8bSnT\xa1\x00\x00\x00\xa1\x00\x00\x00\x0d\x00\x00\x00Asia/KatmanduTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xf2}\x84\x00\x00\x00\x00\x1e\x180\xa8\x01\x02\x00\x00O\xfc\x00\x00\x00\x00MX\x00\x04\x00\x00P\xdc\x00\x0aLMT\x00+0530\x00+0545\x00\x0a<+0545>-5:45\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x83g\x95M\x07\x03\x00\x00\x07\x03\x00\x00\x0d\x00\x00\x00Asia/KhandygaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C\x00\x00\x00\x08\x00\x00\x00\x14\xff\xff\xff\xff\xa1\xdb\xe4\xeb\xff\xff\xff\xff\xb5\xa3\xc5\x00\x00\x00\x00\x00\x15'Sp\x00\x00\x00\x00\x16\x18\x87\xe0\x00\x00\x00\x00\x17\x08\x86\xf0\x00\x00\x00\x00\x17\xf9\xbb`\x00\x00\x00\x00\x18\xe9\xbap\x00\x00\x00\x00\x19\xda\xee\xe0\x00\x00\x00\x00\x1a\xcc?p\x00\x00\x00\x00\x1b\xbcL\x90\x00\x00\x00\x00\x1c\xac=\x90\x00\x00\x00\x00\x1d\x9c.\x90\x00\x00\x00\x00\x1e\x8c\x1f\x90\x00\x00\x00\x00\x1f|\x10\x90\x00\x00\x00\x00 l\x01\x90\x00\x00\x00\x00![\xf2\x90\x00\x00\x00\x00\x22K\xe3\x90\x00\x00\x00\x00#;\xd4\x90\x00\x00\x00\x00$+\xc5\x90\x00\x00\x00\x00%\x1b\xb6\x90\x00\x00\x00\x00&\x0b\xa7\x90\x00\x00\x00\x00'\x04\xd3\x10\x00\x00\x00\x00'\xf4\xc4\x10\x00\x00\x00\x00(\xe4\xc3 \x00\x00\x00\x00)xk \x00\x00\x00\x00)\xd4\xa6\x10\x00\x00\x00\x00*\xc4\x97\x10\x00\x00\x00\x00+\xb4\x88\x10\x00\x00\x00\x00,\xa4y\x10\x00\x00\x00\x00-\x94j\x10\x00\x00\x00\x00.\x84[\x10\x00\x00\x00\x00/tL\x10\x00\x00\x00\x000d=\x10\x00\x00\x00\x001]h\x90\x00\x00\x00\x002rC\x90\x00\x00\x00\x003=J\x90\x00\x00\x00\x004R%\x90\x00\x00\x00\x005\x1d,\x90\x00\x00\x00\x0062\x07\x90\x00\x00\x00\x006\xfd\x0e\x90\x00\x00\x00\x008\x1b$\x10\x00\x00\x00\x008\xdc\xf0\x90\x00\x00\x00\x009\xfb\x06\x10\x00\x00\x00\x00:\xbc\xd2\x90\x00\x00\x00\x00;\xda\xe8\x10\x00\x00\x00\x00<\xa5\xef\x10\x00\x00\x00\x00=\xba\xca\x10\x00\x00\x00\x00>\x85\xd1\x10\x00\x00\x00\x00?\x9a\xac\x10\x00\x00\x00\x00?\xf2\xe4p\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D%i\x00\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xeeg\x80\x00\x00\x00\x00I\x03B\x80\x00\x00\x00\x00I\xceI\x80\x00\x00\x00\x00J\xe3$\x80\x00\x00\x00\x00K\xae+\x80\x00\x00\x00\x00L\xccA\x00\x00\x00\x00\x00M\x8e\x0d\x80\x00\x00\x00\x00Nn\x02P\x00\x00\x00\x00TK\xc9\x00\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x07\x06\x03\x00\x00\x7f\x15\x00\x00\x00\x00p\x80\x00\x04\x00\x00\x8c\xa0\x01\x08\x00\x00~\x90\x00\x0c\x00\x00~\x90\x01\x0c\x00\x00\x9a\xb0\x01\x10\x00\x00\x8c\xa0\x00\x08\x00\x00\x9a\xb0\x00\x10LMT\x00+08\x00+10\x00+09\x00+11\x00\x0a<+09>-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x1a\xdc\xca\xdc\x00\x00\x00\xdc\x00\x00\x00\x0c\x00\x00\x00Asia/KolkataTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x05\x00\x00\x00\x16\xff\xff\xff\xff&\xba\x18(\xff\xff\xff\xffC\xe7\xeb0\xff\xff\xff\xff\x87\x9d\xbc\xba\xff\xff\xff\xff\xca\xdb\x8c(\xff\xff\xff\xff\xcc\x05q\x18\xff\xff\xff\xff\xcc\x952\xa8\xff\xff\xff\xff\xd2t\x12\x98\x01\x02\x03\x04\x03\x04\x03\x00\x00R\xd8\x00\x00\x00\x00R\xd0\x00\x04\x00\x00KF\x00\x08\x00\x00MX\x00\x0c\x00\x00[h\x01\x10LMT\x00HMT\x00MMT\x00IST\x00+0630\x00\x0aIST-5:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L\xe0\x91y\xe5\x02\x00\x00\xe5\x02\x00\x00\x10\x00\x00\x00Asia/KrasnoyarskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xf9\x0d\xf2\xff\xff\xff\xff\xb5\xa3\xe1 \x00\x00\x00\x00\x15'o\x90\x00\x00\x00\x00\x16\x18\xa4\x00\x00\x00\x00\x00\x17\x08\xa3\x10\x00\x00\x00\x00\x17\xf9\xd7\x80\x00\x00\x00\x00\x18\xe9\xd6\x90\x00\x00\x00\x00\x19\xdb\x0b\x00\x00\x00\x00\x00\x1a\xcc[\x90\x00\x00\x00\x00\x1b\xbch\xb0\x00\x00\x00\x00\x1c\xacY\xb0\x00\x00\x00\x00\x1d\x9cJ\xb0\x00\x00\x00\x00\x1e\x8c;\xb0\x00\x00\x00\x00\x1f|,\xb0\x00\x00\x00\x00 l\x1d\xb0\x00\x00\x00\x00!\x5c\x0e\xb0\x00\x00\x00\x00\x22K\xff\xb0\x00\x00\x00\x00#;\xf0\xb0\x00\x00\x00\x00$+\xe1\xb0\x00\x00\x00\x00%\x1b\xd2\xb0\x00\x00\x00\x00&\x0b\xc3\xb0\x00\x00\x00\x00'\x04\xef0\x00\x00\x00\x00'\xf4\xe00\x00\x00\x00\x00(\xe4\xdf@\x00\x00\x00\x00)x\x87@\x00\x00\x00\x00)\xd4\xc20\x00\x00\x00\x00*\xc4\xb30\x00\x00\x00\x00+\xb4\xa40\x00\x00\x00\x00,\xa4\x950\x00\x00\x00\x00-\x94\x860\x00\x00\x00\x00.\x84w0\x00\x00\x00\x00/th0\x00\x00\x00\x000dY0\x00\x00\x00\x001]\x84\xb0\x00\x00\x00\x002r_\xb0\x00\x00\x00\x003=f\xb0\x00\x00\x00\x004RA\xb0\x00\x00\x00\x005\x1dH\xb0\x00\x00\x00\x0062#\xb0\x00\x00\x00\x006\xfd*\xb0\x00\x00\x00\x008\x1b@0\x00\x00\x00\x008\xdd\x0c\xb0\x00\x00\x00\x009\xfb\x220\x00\x00\x00\x00:\xbc\xee\xb0\x00\x00\x00\x00;\xdb\x040\x00\x00\x00\x00<\xa6\x0b0\x00\x00\x00\x00=\xba\xe60\x00\x00\x00\x00>\x85\xed0\x00\x00\x00\x00?\x9a\xc80\x00\x00\x00\x00@e\xcf0\x00\x00\x00\x00A\x83\xe4\xb0\x00\x00\x00\x00BE\xb10\x00\x00\x00\x00Cc\xc6\xb0\x00\x00\x00\x00D%\x930\x00\x00\x00\x00EC\xa8\xb0\x00\x00\x00\x00F\x05u0\x00\x00\x00\x00G#\x8a\xb0\x00\x00\x00\x00G\xee\x91\xb0\x00\x00\x00\x00I\x03l\xb0\x00\x00\x00\x00I\xces\xb0\x00\x00\x00\x00J\xe3N\xb0\x00\x00\x00\x00K\xaeU\xb0\x00\x00\x00\x00L\xcck0\x00\x00\x00\x00M\x8e7\xb0\x00\x00\x00\x00TK\xe5 \x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x03\x00\x00W\x0e\x00\x00\x00\x00T`\x00\x04\x00\x00p\x80\x01\x08\x00\x00bp\x00\x0c\x00\x00bp\x01\x0c\x00\x00p\x80\x00\x08LMT\x00+06\x00+08\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F7k\x1c\x00\x01\x00\x00\x00\x01\x00\x00\x11\x00\x00\x00Asia/Kuala_LumpurTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00 \xff\xff\xff\xff~6S\xa3\xff\xff\xff\xff\x86\x83\x85\xa3\xff\xff\xff\xff\xbagN\x90\xff\xff\xff\xff\xc0\x0a\xe4`\xff\xff\xff\xff\xca\xb3\xe5`\xff\xff\xff\xff\xcb\x91_\x08\xff\xff\xff\xff\xd2Hm\xf0\x00\x00\x00\x00\x16\x91\xee\x00\x01\x02\x03\x04\x05\x06\x05\x07\x00\x00a]\x00\x00\x00\x00a]\x00\x04\x00\x00bp\x00\x08\x00\x00g \x01\x0c\x00\x00g \x00\x0c\x00\x00ix\x00\x12\x00\x00~\x90\x00\x18\x00\x00p\x80\x00\x1cLMT\x00SMT\x00+07\x00+0720\x00+0730\x00+09\x00+08\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7f^]@\x01\x00\x00@\x01\x00\x00\x0c\x00\x00\x00Asia/KuchingTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12\x00\x00\x00\x05\x00\x00\x00\x18\xff\xff\xff\xff\xad\x8a\x06\x90\xff\xff\xff\xff\xbagG\x88\xff\xff\xff\xff\xbf{'\x80\xff\xff\xff\xff\xbf\xf3\x1bP\xff\xff\xff\xff\xc1]\xac\x80\xff\xff\xff\xff\xc1\xd5\xa0P\xff\xff\xff\xff\xc3>\xe0\x00\xff\xff\xff\xff\xc3\xb6\xd3\xd0\xff\xff\xff\xff\xc5 \x13\x80\xff\xff\xff\xff\xc5\x98\x07P\xff\xff\xff\xff\xc7\x01G\x00\xff\xff\xff\xff\xc7y:\xd0\xff\xff\xff\xff\xc8\xe3\xcc\x00\xff\xff\xff\xff\xc9[\xbf\xd0\xff\xff\xff\xff\xca\xc4\xff\x80\xff\xff\xff\xff\xcb<\xf3P\xff\xff\xff\xff\xcb\x91X\x00\xff\xff\xff\xff\xd2Hm\xf0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x03\x00\x00gp\x00\x00\x00\x00ix\x00\x04\x00\x00u0\x01\x0a\x00\x00p\x80\x00\x10\x00\x00~\x90\x00\x14LMT\x00+0730\x00+0820\x00+08\x00+09\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xd7\x87\xe1\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00Asia/KuwaitTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xd5\x1b6\xb4\x01\x00\x00+\xcc\x00\x00\x00\x00*0\x00\x04LMT\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d?v\x0c\x17\x03\x00\x00\x17\x03\x00\x00\x0a\x00\x00\x00Asia/MacaoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x85i[\x8e\xff\xff\xff\xff\xcbGu\xf0\xff\xff\xff\xff\xcb\xf2\xca\xe0\xff\xff\xff\xff\xcc\xfb\xbaP\xff\xff\xff\xff\xcd\xd3\xfe`\xff\xff\xff\xff\xce\x9d\xa5\xd0\xff\xff\xff\xff\xd2azp\xff\xff\xff\xff\xd3x\xf8p\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5K\xabp\xff\xff\xff\xff\xd6tL\xf0\xff\xff\xff\xff\xd7?S\xf0\xff\xff\xff\xff\xd8/D\xf0\xff\xff\xff\xff\xd8\xf8\xfap\xff\xff\xff\xff\xda\x0d\xd5p\xff\xff\xff\xff\xda\xd8\xdcp\xff\xff\xff\xff\xdb\xed\xb7p\xff\xff\xff\xff\xdc\xb8\xbep\xff\xff\xff\xff\xdd\xce\xea\xf0\xff\xff\xff\xff\xde\xa1\xda\xf0\xff\xff\xff\xff\xdf\xb6\xb5\xf0\xff\xff\xff\xff\xe0\x81\xbc\xf0\xff\xff\xff\xff\xe1\x96\x97\xf0\xff\xff\xff\xff\xe2O)\xf0\xff\xff\xff\xff\xe3vy\xf0\xff\xff\xff\xff\xe4/\x0b\xf0\xff\xff\xff\xff\xe5_\x96p\xff\xff\xff\xff\xe6\x0e\xed\xf0\xff\xff\xff\xff\xe7?\xa9\xa8\xff\xff\xff\xff\xe7\xf8I\xb8\xff\xff\xff\xff\xe9\x1f\x8b\xa8\xff\xff\xff\xff\xe9\xd8+\xb8\xff\xff\xff\xff\xea\xffm\xa8\xff\xff\xff\xff\xeb\xb8\x0d\xb8\xff\xff\xff\xff\xec\xdfO\xa8\xff\xff\xff\xff\xed\x97\xef\xb8\xff\xff\xff\xff\xee\xc8l(\xff\xff\xff\xff\xefw\xd1\xb8\xff\xff\xff\xff\xf0\xa8N(\xff\xff\xff\xff\xf1W\xb3\xb8\xff\xff\xff\xff\xf2\x880(\xff\xff\xff\xff\xf3@\xd08\xff\xff\xff\xff\xf4h\x12(\xff\xff\xff\xff\xf5 \xb28\xff\xff\xff\xff\xf6G\xf4(\xff\xff\xff\xff\xf7%~8\xff\xff\xff\xff\xf8\x15S\x18\xff\xff\xff\xff\xf9\x05`8\xff\xff\xff\xff\xf9\xf55\x18\xff\xff\xff\xff\xfa\xe5B8\xff\xff\xff\xff\xfb\xde_\xa8\xff\xff\xff\xff\xfc\xce^\xb8\xff\xff\xff\xff\xfd\xbeA\xa8\xff\xff\xff\xff\xfe\xae@\xb8\xff\xff\xff\xff\xff\x9e#\xa8\x00\x00\x00\x00\x00\x8e\x22\xb8\x00\x00\x00\x00\x01~\x05\xa8\x00\x00\x00\x00\x02n\x04\xb8\x00\x00\x00\x00\x03]\xe7\xa8\x00\x00\x00\x00\x04M\xe6\xb8\x00\x00\x00\x00\x05G\x04(\x00\x00\x00\x00\x067\x038\x00\x00\x00\x00\x07&\xe6(\x00\x00\x00\x00\x07\x83=8\x00\x00\x00\x00\x09\x06\xc8(\x00\x00\x00\x00\x09\xf6\xc78\x00\x00\x00\x00\x0a\xe6\xaa(\x00\x00\x00\x00\x0b\xd6\xa98\x00\x00\x00\x00\x0c\xc6\x8c(\x00\x00\x00\x00\x11\x9b98\x00\x00\x00\x00\x12ol\xa8\x01\x03\x02\x03\x02\x03\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x00\x00jr\x00\x00\x00\x00p\x80\x00\x04\x00\x00\x8c\xa0\x01\x08\x00\x00~\x90\x00\x0c\x00\x00~\x90\x01\x10LMT\x00CST\x00+10\x00+09\x00CDT\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d?v\x0c\x17\x03\x00\x00\x17\x03\x00\x00\x0a\x00\x00\x00Asia/MacauTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x85i[\x8e\xff\xff\xff\xff\xcbGu\xf0\xff\xff\xff\xff\xcb\xf2\xca\xe0\xff\xff\xff\xff\xcc\xfb\xbaP\xff\xff\xff\xff\xcd\xd3\xfe`\xff\xff\xff\xff\xce\x9d\xa5\xd0\xff\xff\xff\xff\xd2azp\xff\xff\xff\xff\xd3x\xf8p\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5K\xabp\xff\xff\xff\xff\xd6tL\xf0\xff\xff\xff\xff\xd7?S\xf0\xff\xff\xff\xff\xd8/D\xf0\xff\xff\xff\xff\xd8\xf8\xfap\xff\xff\xff\xff\xda\x0d\xd5p\xff\xff\xff\xff\xda\xd8\xdcp\xff\xff\xff\xff\xdb\xed\xb7p\xff\xff\xff\xff\xdc\xb8\xbep\xff\xff\xff\xff\xdd\xce\xea\xf0\xff\xff\xff\xff\xde\xa1\xda\xf0\xff\xff\xff\xff\xdf\xb6\xb5\xf0\xff\xff\xff\xff\xe0\x81\xbc\xf0\xff\xff\xff\xff\xe1\x96\x97\xf0\xff\xff\xff\xff\xe2O)\xf0\xff\xff\xff\xff\xe3vy\xf0\xff\xff\xff\xff\xe4/\x0b\xf0\xff\xff\xff\xff\xe5_\x96p\xff\xff\xff\xff\xe6\x0e\xed\xf0\xff\xff\xff\xff\xe7?\xa9\xa8\xff\xff\xff\xff\xe7\xf8I\xb8\xff\xff\xff\xff\xe9\x1f\x8b\xa8\xff\xff\xff\xff\xe9\xd8+\xb8\xff\xff\xff\xff\xea\xffm\xa8\xff\xff\xff\xff\xeb\xb8\x0d\xb8\xff\xff\xff\xff\xec\xdfO\xa8\xff\xff\xff\xff\xed\x97\xef\xb8\xff\xff\xff\xff\xee\xc8l(\xff\xff\xff\xff\xefw\xd1\xb8\xff\xff\xff\xff\xf0\xa8N(\xff\xff\xff\xff\xf1W\xb3\xb8\xff\xff\xff\xff\xf2\x880(\xff\xff\xff\xff\xf3@\xd08\xff\xff\xff\xff\xf4h\x12(\xff\xff\xff\xff\xf5 \xb28\xff\xff\xff\xff\xf6G\xf4(\xff\xff\xff\xff\xf7%~8\xff\xff\xff\xff\xf8\x15S\x18\xff\xff\xff\xff\xf9\x05`8\xff\xff\xff\xff\xf9\xf55\x18\xff\xff\xff\xff\xfa\xe5B8\xff\xff\xff\xff\xfb\xde_\xa8\xff\xff\xff\xff\xfc\xce^\xb8\xff\xff\xff\xff\xfd\xbeA\xa8\xff\xff\xff\xff\xfe\xae@\xb8\xff\xff\xff\xff\xff\x9e#\xa8\x00\x00\x00\x00\x00\x8e\x22\xb8\x00\x00\x00\x00\x01~\x05\xa8\x00\x00\x00\x00\x02n\x04\xb8\x00\x00\x00\x00\x03]\xe7\xa8\x00\x00\x00\x00\x04M\xe6\xb8\x00\x00\x00\x00\x05G\x04(\x00\x00\x00\x00\x067\x038\x00\x00\x00\x00\x07&\xe6(\x00\x00\x00\x00\x07\x83=8\x00\x00\x00\x00\x09\x06\xc8(\x00\x00\x00\x00\x09\xf6\xc78\x00\x00\x00\x00\x0a\xe6\xaa(\x00\x00\x00\x00\x0b\xd6\xa98\x00\x00\x00\x00\x0c\xc6\x8c(\x00\x00\x00\x00\x11\x9b98\x00\x00\x00\x00\x12ol\xa8\x01\x03\x02\x03\x02\x03\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x00\x00jr\x00\x00\x00\x00p\x80\x00\x04\x00\x00\x8c\xa0\x01\x08\x00\x00~\x90\x00\x0c\x00\x00~\x90\x01\x10LMT\x00CST\x00+10\x00+09\x00CDT\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4_P\x18\xef\x02\x00\x00\xef\x02\x00\x00\x0c\x00\x00\x00Asia/MagadanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x196\xa0\xff\xff\xff\xff\xb5\xa3\xa8\xe0\x00\x00\x00\x00\x15'7P\x00\x00\x00\x00\x16\x18k\xc0\x00\x00\x00\x00\x17\x08j\xd0\x00\x00\x00\x00\x17\xf9\x9f@\x00\x00\x00\x00\x18\xe9\x9eP\x00\x00\x00\x00\x19\xda\xd2\xc0\x00\x00\x00\x00\x1a\xcc#P\x00\x00\x00\x00\x1b\xbc0p\x00\x00\x00\x00\x1c\xac!p\x00\x00\x00\x00\x1d\x9c\x12p\x00\x00\x00\x00\x1e\x8c\x03p\x00\x00\x00\x00\x1f{\xf4p\x00\x00\x00\x00 k\xe5p\x00\x00\x00\x00![\xd6p\x00\x00\x00\x00\x22K\xc7p\x00\x00\x00\x00#;\xb8p\x00\x00\x00\x00$+\xa9p\x00\x00\x00\x00%\x1b\x9ap\x00\x00\x00\x00&\x0b\x8bp\x00\x00\x00\x00'\x04\xb6\xf0\x00\x00\x00\x00'\xf4\xa7\xf0\x00\x00\x00\x00(\xe4\xa7\x00\x00\x00\x00\x00)xO\x00\x00\x00\x00\x00)\xd4\x89\xf0\x00\x00\x00\x00*\xc4z\xf0\x00\x00\x00\x00+\xb4k\xf0\x00\x00\x00\x00,\xa4\x5c\xf0\x00\x00\x00\x00-\x94M\xf0\x00\x00\x00\x00.\x84>\xf0\x00\x00\x00\x00/t/\xf0\x00\x00\x00\x000d \xf0\x00\x00\x00\x001]Lp\x00\x00\x00\x002r'p\x00\x00\x00\x003=.p\x00\x00\x00\x004R\x09p\x00\x00\x00\x005\x1d\x10p\x00\x00\x00\x0061\xebp\x00\x00\x00\x006\xfc\xf2p\x00\x00\x00\x008\x1b\x07\xf0\x00\x00\x00\x008\xdc\xd4p\x00\x00\x00\x009\xfa\xe9\xf0\x00\x00\x00\x00:\xbc\xb6p\x00\x00\x00\x00;\xda\xcb\xf0\x00\x00\x00\x00<\xa5\xd2\xf0\x00\x00\x00\x00=\xba\xad\xf0\x00\x00\x00\x00>\x85\xb4\xf0\x00\x00\x00\x00?\x9a\x8f\xf0\x00\x00\x00\x00@e\x96\xf0\x00\x00\x00\x00A\x83\xacp\x00\x00\x00\x00BEx\xf0\x00\x00\x00\x00Cc\x8ep\x00\x00\x00\x00D%Z\xf0\x00\x00\x00\x00ECpp\x00\x00\x00\x00F\x05<\xf0\x00\x00\x00\x00G#Rp\x00\x00\x00\x00G\xeeYp\x00\x00\x00\x00I\x034p\x00\x00\x00\x00I\xce;p\x00\x00\x00\x00J\xe3\x16p\x00\x00\x00\x00K\xae\x1dp\x00\x00\x00\x00L\xcc2\xf0\x00\x00\x00\x00M\x8d\xffp\x00\x00\x00\x00TK\xac\xe0\x00\x00\x00\x00W\x1b\x9c\x00\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x01\x03\x00\x00\x8d`\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00\xa8\xc0\x01\x08\x00\x00\x9a\xb0\x00\x0c\x00\x00\x9a\xb0\x01\x0c\x00\x00\xa8\xc0\x00\x08LMT\x00+10\x00+12\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\xc9\xd4\x5c\xbe\x00\x00\x00\xbe\x00\x00\x00\x0d\x00\x00\x00Asia/MakassarTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff\xa1\xf2]\x90\xff\xff\xff\xff\xba\x16\xd5\x90\xff\xff\xff\xff\xcb\x88\x1d\x80\xff\xff\xff\xff\xd2V\xeep\x01\x02\x03\x04\x00\x00o\xf0\x00\x00\x00\x00o\xf0\x00\x04\x00\x00p\x80\x00\x08\x00\x00~\x90\x00\x0c\x00\x00p\x80\x00\x10LMT\x00MMT\x00+08\x00+09\x00WITA\x00\x0aWITA-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7\xaf\xdf\x1c\xee\x00\x00\x00\xee\x00\x00\x00\x0b\x00\x00\x00Asia/ManilaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\x14\xe1\xdc\x10\xff\xff\xff\xff{\x1f?\x90\xff\xff\xff\xff\xc1\x9c\xf4\x80\xff\xff\xff\xff\xc2\x160p\xff\xff\xff\xff\xcb\xf2\xe7\x00\xff\xff\xff\xff\xd0\xa9%p\xff\xff\xff\xff\xe2l9\x00\xff\xff\xff\xff\xe2\xd5\xa2\xf0\x00\x00\x00\x00\x0fuF\x80\x00\x00\x00\x00\x10fz\xf0\x01\x03\x02\x03\x04\x03\x02\x03\x02\x03\xff\xff\x1f\xf0\x00\x00\x00\x00qp\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x08\x00\x00~\x90\x00\x0cLMT\x00PDT\x00PST\x00JST\x00\x0aPST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00Asia/MuscatTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xa1\xf2\x99\xa8\x01\x00\x003\xd8\x00\x00\x00\x008@\x00\x04LMT\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1eX\xc3aU\x02\x00\x00U\x02\x00\x00\x0c\x00\x00\x00Asia/NicosiaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xff\xa5w\x1e\xb8\x00\x00\x00\x00\x09\xed\xaf\xe0\x00\x00\x00\x00\x0a\xdd\x92\xd0\x00\x00\x00\x00\x0b\xfad\xe0\x00\x00\x00\x00\x0c\xbe\xc6P\x00\x00\x00\x00\x0d\xa49`\x00\x00\x00\x00\x0e\x8a\xe1\xd0\x00\x00\x00\x00\x0f\x84\x1b`\x00\x00\x00\x00\x10uO\xd0\x00\x00\x00\x00\x11c\xfd`\x00\x00\x00\x00\x12S\xe0P\x00\x00\x00\x00\x13M\x19\xe0\x00\x00\x00\x00\x143\xc2P\x00\x00\x00\x00\x15#\xc1`\x00\x00\x00\x00\x16\x13\xa4P\x00\x00\x00\x00\x17\x03\xa3`\x00\x00\x00\x00\x17\xf3\x86P\x00\x00\x00\x00\x18\xe3\x85`\x00\x00\x00\x00\x19\xd3hP\x00\x00\x00\x00\x1a\xc3g`\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe4\xedP\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000duP\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002M\x91\xd0\x00\x00\x00\x003=\x90\xe0\x00\x00\x00\x004-s\xd0\x00\x00\x00\x005\x1dr\xe0\x00\x00\x00\x005\xeb\x0e\xd0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x01\x00\x00\x1fH\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09LMT\x00EEST\x00EET\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a\x9a\x90\xf7\xd6\x02\x00\x00\xd6\x02\x00\x00\x11\x00\x00\x00Asia/NovokuznetskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x18 \xc0\xff\xff\xff\xff\xb5\xa3\xe1 \x00\x00\x00\x00\x15'o\x90\x00\x00\x00\x00\x16\x18\xa4\x00\x00\x00\x00\x00\x17\x08\xa3\x10\x00\x00\x00\x00\x17\xf9\xd7\x80\x00\x00\x00\x00\x18\xe9\xd6\x90\x00\x00\x00\x00\x19\xdb\x0b\x00\x00\x00\x00\x00\x1a\xcc[\x90\x00\x00\x00\x00\x1b\xbch\xb0\x00\x00\x00\x00\x1c\xacY\xb0\x00\x00\x00\x00\x1d\x9cJ\xb0\x00\x00\x00\x00\x1e\x8c;\xb0\x00\x00\x00\x00\x1f|,\xb0\x00\x00\x00\x00 l\x1d\xb0\x00\x00\x00\x00!\x5c\x0e\xb0\x00\x00\x00\x00\x22K\xff\xb0\x00\x00\x00\x00#;\xf0\xb0\x00\x00\x00\x00$+\xe1\xb0\x00\x00\x00\x00%\x1b\xd2\xb0\x00\x00\x00\x00&\x0b\xc3\xb0\x00\x00\x00\x00'\x04\xef0\x00\x00\x00\x00'\xf4\xe00\x00\x00\x00\x00(\xe4\xdf@\x00\x00\x00\x00)x\x87@\x00\x00\x00\x00)\xd4\xc20\x00\x00\x00\x00*\xc4\xb30\x00\x00\x00\x00+\xb4\xa40\x00\x00\x00\x00,\xa4\x950\x00\x00\x00\x00-\x94\x860\x00\x00\x00\x00.\x84w0\x00\x00\x00\x00/th0\x00\x00\x00\x000dY0\x00\x00\x00\x001]\x84\xb0\x00\x00\x00\x002r_\xb0\x00\x00\x00\x003=f\xb0\x00\x00\x00\x004RA\xb0\x00\x00\x00\x005\x1dH\xb0\x00\x00\x00\x0062#\xb0\x00\x00\x00\x006\xfd*\xb0\x00\x00\x00\x008\x1b@0\x00\x00\x00\x008\xdd\x0c\xb0\x00\x00\x00\x009\xfb\x220\x00\x00\x00\x00:\xbc\xee\xb0\x00\x00\x00\x00;\xdb\x040\x00\x00\x00\x00<\xa6\x0b0\x00\x00\x00\x00=\xba\xe60\x00\x00\x00\x00>\x85\xed0\x00\x00\x00\x00?\x9a\xc80\x00\x00\x00\x00@e\xcf0\x00\x00\x00\x00A\x83\xe4\xb0\x00\x00\x00\x00BE\xb10\x00\x00\x00\x00Cc\xc6\xb0\x00\x00\x00\x00D%\x930\x00\x00\x00\x00EC\xa8\xb0\x00\x00\x00\x00F\x05u0\x00\x00\x00\x00G#\x8a\xb0\x00\x00\x00\x00G\xee\x91\xb0\x00\x00\x00\x00I\x03l\xb0\x00\x00\x00\x00I\xces\xb0\x00\x00\x00\x00J\xe3N\xb0\x00\x00\x00\x00K\xaeU\xb0\x00\x00\x00\x00L\xccy@\x00\x00\x00\x00M\x8eE\xc0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x00\x00Q\xc0\x00\x00\x00\x00T`\x00\x04\x00\x00p\x80\x01\x08\x00\x00bp\x00\x0c\x00\x00bp\x01\x0cLMT\x00+06\x00+08\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)p\x1cX\xf1\x02\x00\x00\xf1\x02\x00\x00\x10\x00\x00\x00Asia/NovosibirskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xdb\x19$\xff\xff\xff\xff\xb5\xa3\xe1 \x00\x00\x00\x00\x15'o\x90\x00\x00\x00\x00\x16\x18\xa4\x00\x00\x00\x00\x00\x17\x08\xa3\x10\x00\x00\x00\x00\x17\xf9\xd7\x80\x00\x00\x00\x00\x18\xe9\xd6\x90\x00\x00\x00\x00\x19\xdb\x0b\x00\x00\x00\x00\x00\x1a\xcc[\x90\x00\x00\x00\x00\x1b\xbch\xb0\x00\x00\x00\x00\x1c\xacY\xb0\x00\x00\x00\x00\x1d\x9cJ\xb0\x00\x00\x00\x00\x1e\x8c;\xb0\x00\x00\x00\x00\x1f|,\xb0\x00\x00\x00\x00 l\x1d\xb0\x00\x00\x00\x00!\x5c\x0e\xb0\x00\x00\x00\x00\x22K\xff\xb0\x00\x00\x00\x00#;\xf0\xb0\x00\x00\x00\x00$+\xe1\xb0\x00\x00\x00\x00%\x1b\xd2\xb0\x00\x00\x00\x00&\x0b\xc3\xb0\x00\x00\x00\x00'\x04\xef0\x00\x00\x00\x00'\xf4\xe00\x00\x00\x00\x00(\xe4\xdf@\x00\x00\x00\x00)x\x87@\x00\x00\x00\x00)\xd4\xc20\x00\x00\x00\x00*\xc4\xb30\x00\x00\x00\x00+\xb4\xa40\x00\x00\x00\x00+\xfeN\x00\x00\x00\x00\x00,\xa4\xa3@\x00\x00\x00\x00-\x94\x94@\x00\x00\x00\x00.\x84\x85@\x00\x00\x00\x00/tv@\x00\x00\x00\x000dg@\x00\x00\x00\x001]\x92\xc0\x00\x00\x00\x002rm\xc0\x00\x00\x00\x003=t\xc0\x00\x00\x00\x004RO\xc0\x00\x00\x00\x005\x1dV\xc0\x00\x00\x00\x00621\xc0\x00\x00\x00\x006\xfd8\xc0\x00\x00\x00\x008\x1bN@\x00\x00\x00\x008\xdd\x1a\xc0\x00\x00\x00\x009\xfb0@\x00\x00\x00\x00:\xbc\xfc\xc0\x00\x00\x00\x00;\xdb\x12@\x00\x00\x00\x00<\xa6\x19@\x00\x00\x00\x00=\xba\xf4@\x00\x00\x00\x00>\x85\xfb@\x00\x00\x00\x00?\x9a\xd6@\x00\x00\x00\x00@e\xdd@\x00\x00\x00\x00A\x83\xf2\xc0\x00\x00\x00\x00BE\xbf@\x00\x00\x00\x00Cc\xd4\xc0\x00\x00\x00\x00D%\xa1@\x00\x00\x00\x00EC\xb6\xc0\x00\x00\x00\x00F\x05\x83@\x00\x00\x00\x00G#\x98\xc0\x00\x00\x00\x00G\xee\x9f\xc0\x00\x00\x00\x00I\x03z\xc0\x00\x00\x00\x00I\xce\x81\xc0\x00\x00\x00\x00J\xe3\x5c\xc0\x00\x00\x00\x00K\xaec\xc0\x00\x00\x00\x00L\xccy@\x00\x00\x00\x00M\x8eE\xc0\x00\x00\x00\x00TK\xf30\x00\x00\x00\x00W\x93\xcc\xc0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x03\x01\x03\x00\x00M\xbc\x00\x00\x00\x00T`\x00\x04\x00\x00p\x80\x01\x08\x00\x00bp\x00\x0c\x00\x00bp\x01\x0cLMT\x00+06\x00+08\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:\x11\xea\xa2\xe5\x02\x00\x00\xe5\x02\x00\x00\x09\x00\x00\x00Asia/OmskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xb3@\xb6\xff\xff\xff\xff\xb5\xa3\xef0\x00\x00\x00\x00\x15'}\xa0\x00\x00\x00\x00\x16\x18\xb2\x10\x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xe5\x90\x00\x00\x00\x00\x18\xe9\xe4\xa0\x00\x00\x00\x00\x19\xdb\x19\x10\x00\x00\x00\x00\x1a\xcci\xa0\x00\x00\x00\x00\x1b\xbcv\xc0\x00\x00\x00\x00\x1c\xacg\xc0\x00\x00\x00\x00\x1d\x9cX\xc0\x00\x00\x00\x00\x1e\x8cI\xc0\x00\x00\x00\x00\x1f|:\xc0\x00\x00\x00\x00 l+\xc0\x00\x00\x00\x00!\x5c\x1c\xc0\x00\x00\x00\x00\x22L\x0d\xc0\x00\x00\x00\x00#;\xfe\xc0\x00\x00\x00\x00$+\xef\xc0\x00\x00\x00\x00%\x1b\xe0\xc0\x00\x00\x00\x00&\x0b\xd1\xc0\x00\x00\x00\x00'\x04\xfd@\x00\x00\x00\x00'\xf4\xee@\x00\x00\x00\x00(\xe4\xedP\x00\x00\x00\x00)x\x95P\x00\x00\x00\x00)\xd4\xd0@\x00\x00\x00\x00*\xc4\xc1@\x00\x00\x00\x00+\xb4\xb2@\x00\x00\x00\x00,\xa4\xa3@\x00\x00\x00\x00-\x94\x94@\x00\x00\x00\x00.\x84\x85@\x00\x00\x00\x00/tv@\x00\x00\x00\x000dg@\x00\x00\x00\x001]\x92\xc0\x00\x00\x00\x002rm\xc0\x00\x00\x00\x003=t\xc0\x00\x00\x00\x004RO\xc0\x00\x00\x00\x005\x1dV\xc0\x00\x00\x00\x00621\xc0\x00\x00\x00\x006\xfd8\xc0\x00\x00\x00\x008\x1bN@\x00\x00\x00\x008\xdd\x1a\xc0\x00\x00\x00\x009\xfb0@\x00\x00\x00\x00:\xbc\xfc\xc0\x00\x00\x00\x00;\xdb\x12@\x00\x00\x00\x00<\xa6\x19@\x00\x00\x00\x00=\xba\xf4@\x00\x00\x00\x00>\x85\xfb@\x00\x00\x00\x00?\x9a\xd6@\x00\x00\x00\x00@e\xdd@\x00\x00\x00\x00A\x83\xf2\xc0\x00\x00\x00\x00BE\xbf@\x00\x00\x00\x00Cc\xd4\xc0\x00\x00\x00\x00D%\xa1@\x00\x00\x00\x00EC\xb6\xc0\x00\x00\x00\x00F\x05\x83@\x00\x00\x00\x00G#\x98\xc0\x00\x00\x00\x00G\xee\x9f\xc0\x00\x00\x00\x00I\x03z\xc0\x00\x00\x00\x00I\xce\x81\xc0\x00\x00\x00\x00J\xe3\x5c\xc0\x00\x00\x00\x00K\xaec\xc0\x00\x00\x00\x00L\xccy@\x00\x00\x00\x00M\x8eE\xc0\x00\x00\x00\x00TK\xf30\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x03\x00\x00D\xca\x00\x00\x00\x00FP\x00\x04\x00\x00bp\x01\x08\x00\x00T`\x00\x0c\x00\x00T`\x01\x0c\x00\x00bp\x00\x08LMT\x00+05\x00+07\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&\xe9\xd1\xd8q\x02\x00\x00q\x02\x00\x00\x09\x00\x00\x00Asia/OralTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x00\x00\x00\x07\x00\x00\x00\x14\xff\xff\xff\xff\xaa\x19\x93\xdc\xff\xff\xff\xff\xb5\xa4\x0bP\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xfc\xe0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x19`\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x00\x00\x00\x00)\xd4\xdeP\x00\x00\x00\x00*\xc4\xdd`\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xbf`\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\xa1`\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000d\x83`\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002r\x89\xe0\x00\x00\x00\x003=\x90\xe0\x00\x00\x00\x004Rk\xe0\x00\x00\x00\x005\x1dr\xe0\x00\x00\x00\x0062M\xe0\x00\x00\x00\x006\xfdT\xe0\x00\x00\x00\x008\x1bj`\x00\x00\x00\x008\xdd6\xe0\x00\x00\x00\x009\xfbL`\x00\x00\x00\x00:\xbd\x18\xe0\x00\x00\x00\x00;\xdb.`\x00\x00\x00\x00<\xa65`\x00\x00\x00\x00=\xbb\x10`\x00\x00\x00\x00>\x86\x17`\x00\x00\x00\x00?\x9a\xf2`\x00\x00\x00\x00@e\xf9`\x00\x00\x00\x00A\x84\x0e\xe0\x01\x02\x03\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x06\x05\x06\x05\x06\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x02\x00\x000$\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x00\x08\x00\x00T`\x01\x0c\x00\x00T`\x00\x0c\x00\x00FP\x01\x08\x00\x008@\x00\x10LMT\x00+03\x00+05\x00+06\x00+04\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x0f\x00\x00\x00Asia/Phnom_PenhTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffV\xb6\x85\xc4\xff\xff\xff\xff\xa2jg\xc4\x01\x02\x00\x00^<\x00\x00\x00\x00^<\x00\x04\x00\x00bp\x00\x08LMT\x00BMT\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\xa5\x81e\xf7\x00\x00\x00\xf7\x00\x00\x00\x0e\x00\x00\x00Asia/PontianakTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x07\x00\x00\x00\x1f\xff\xff\xff\xff\x8b\xff\x8e\x00\xff\xff\xff\xff\xba\x16\xdf\x00\xff\xff\xff\xff\xcby\xa4\x08\xff\xff\xff\xff\xd2V\xeep\xff\xff\xff\xff\xd7<\xc6\x08\xff\xff\xff\xff\xda\xff&\x00\xff\xff\xff\xff\xf4\xb5\xbe\x88\x00\x00\x00\x00!\xdat\x80\x01\x02\x03\x02\x04\x02\x05\x06\x00\x00f\x80\x00\x00\x00\x00f\x80\x00\x04\x00\x00ix\x00\x08\x00\x00~\x90\x00\x0e\x00\x00p\x80\x00\x12\x00\x00p\x80\x00\x16\x00\x00bp\x00\x1bLMT\x00PMT\x00+0730\x00+09\x00+08\x00WITA\x00WIB\x00\x0aWIB-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a\xc1\x1eB\xb7\x00\x00\x00\xb7\x00\x00\x00\x0e\x00\x00\x00Asia/PyongyangTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\x8b\xd7\xf1\x9c\xff\xff\xff\xff\x92\xe6\x16\xf8\xff\xff\xff\xff\xd2/ap\x00\x00\x00\x00U\xce\x02p\x00\x00\x00\x00Z\xecup\x01\x02\x03\x01\x03\x00\x00u\xe4\x00\x00\x00\x00w\x88\x00\x04\x00\x00~\x90\x00\x08\x00\x00~\x90\x00\x04LMT\x00KST\x00JST\x00\x0aKST-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdav\x19z\x98\x00\x00\x00\x98\x00\x00\x00\x0a\x00\x00\x00Asia/QatarTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\xa1\xf2\x9d0\x00\x00\x00\x00\x04\x8a\x92\xc0\x01\x02\x00\x000P\x00\x00\x00\x008@\x00\x04\x00\x00*0\x00\x08LMT\x00+04\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb5\xc4\x8f\x9cp\x02\x00\x00p\x02\x00\x00\x0d\x00\x00\x00Asia/QostanayTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x88\x5c\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x00\x00\x00\x00)\xd4\xdeP\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xc0P\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xa2P\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x84P\x00\x00\x00\x000duP\x00\x00\x00\x001]\xa0\xd0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x003=\x82\xd0\x00\x00\x00\x004R]\xd0\x00\x00\x00\x005\x1dd\xd0\x00\x00\x00\x0062?\xd0\x00\x00\x00\x006\xfdF\xd0\x00\x00\x00\x008\x1b\x5cP\x00\x00\x00\x008\xdd(\xd0\x00\x00\x00\x009\xfb>P\x00\x00\x00\x00:\xbd\x0a\xd0\x00\x00\x00\x00;\xdb P\x00\x00\x00\x00<\xa6'P\x00\x00\x00\x00=\xbb\x02P\x00\x00\x00\x00>\x86\x09P\x00\x00\x00\x00?\x9a\xe4P\x00\x00\x00\x00@e\xebP\x00\x00\x00\x00A\x84\x00\xd0\x00\x00\x00\x00e\xe0\xc6 \x01\x02\x03\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x02\x00\x00;\xa4\x00\x00\x00\x008@\x00\x04\x00\x00FP\x00\x08\x00\x00T`\x01\x0c\x00\x00T`\x00\x0c\x00\x00FP\x01\x08LMT\x00+04\x00+05\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd5\xce\x9cGp\x02\x00\x00p\x02\x00\x00\x0e\x00\x00\x00Asia/QyzylordaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x86\xa0\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\x95P\x00\x00\x00\x00)\xd4\xd0@\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xc0P\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xa2P\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x84P\x00\x00\x00\x000duP\x00\x00\x00\x001]\xa0\xd0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x003=\x82\xd0\x00\x00\x00\x004R]\xd0\x00\x00\x00\x005\x1dd\xd0\x00\x00\x00\x0062?\xd0\x00\x00\x00\x006\xfdF\xd0\x00\x00\x00\x008\x1b\x5cP\x00\x00\x00\x008\xdd(\xd0\x00\x00\x00\x009\xfb>P\x00\x00\x00\x00:\xbd\x0a\xd0\x00\x00\x00\x00;\xdb P\x00\x00\x00\x00<\xa6'P\x00\x00\x00\x00=\xbb\x02P\x00\x00\x00\x00>\x86\x09P\x00\x00\x00\x00?\x9a\xe4P\x00\x00\x00\x00@e\xebP\x00\x00\x00\x00A\x84\x00\xd0\x00\x00\x00\x00\x5c\x1b\xd8\xa0\x01\x02\x03\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x05\x02\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x02\x00\x00=`\x00\x00\x00\x008@\x00\x04\x00\x00FP\x00\x08\x00\x00T`\x01\x0c\x00\x00T`\x00\x0c\x00\x00FP\x01\x08LMT\x00+04\x00+05\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\x87{_\xbb\x00\x00\x00\xbb\x00\x00\x00\x0c\x00\x00\x00Asia/RangoonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffV\xb6\x89\xd1\xff\xff\xff\xff\xa1\xf2sQ\xff\xff\xff\xff\xcb\xf2\xfc\x18\xff\xff\xff\xff\xd1\x9ag\xf0\x01\x02\x03\x02\x00\x00Z/\x00\x00\x00\x00Z/\x00\x04\x00\x00[h\x00\x08\x00\x00~\x90\x00\x0eLMT\x00RMT\x00+0630\x00+09\x00\x0a<+0630>-6:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xd7\x87\xe1\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00Asia/RiyadhTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xd5\x1b6\xb4\x01\x00\x00+\xcc\x00\x00\x00\x00*0\x00\x04LMT\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8!YF\xec\x00\x00\x00\xec\x00\x00\x00\x0b\x00\x00\x00Asia/SaigonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff\x88\x8cC\x8a\xff\xff\xff\xff\x91\xa3+\x0a\xff\xff\xff\xff\xcd5\xe6\x80\xff\xff\xff\xff\xd1Y\xcep\xff\xff\xff\xff\xd2;>\xf0\xff\xff\xff\xff\xd52\xbb\x10\xff\xff\xff\xff\xe4\xb6\xf2\x90\xff\xff\xff\xff\xed/\x98\x00\x00\x00\x00\x00\x0a=\xc7\x00\x01\x02\x03\x04\x02\x03\x02\x03\x02\x00\x00c\xf6\x00\x00\x00\x00c\xf6\x00\x04\x00\x00bp\x00\x09\x00\x00p\x80\x00\x0d\x00\x00~\x90\x00\x11LMT\x00PLMT\x00+07\x00+08\x00+09\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\x15II\xf3\x02\x00\x00\xf3\x02\x00\x00\x0d\x00\x00\x00Asia/SakhalinTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xff\x86\xf0\xcd\xb8\xff\xff\xff\xff\xd20\xb2\xf0\x00\x00\x00\x00\x15'7P\x00\x00\x00\x00\x16\x18k\xc0\x00\x00\x00\x00\x17\x08j\xd0\x00\x00\x00\x00\x17\xf9\x9f@\x00\x00\x00\x00\x18\xe9\x9eP\x00\x00\x00\x00\x19\xda\xd2\xc0\x00\x00\x00\x00\x1a\xcc#P\x00\x00\x00\x00\x1b\xbc0p\x00\x00\x00\x00\x1c\xac!p\x00\x00\x00\x00\x1d\x9c\x12p\x00\x00\x00\x00\x1e\x8c\x03p\x00\x00\x00\x00\x1f{\xf4p\x00\x00\x00\x00 k\xe5p\x00\x00\x00\x00![\xd6p\x00\x00\x00\x00\x22K\xc7p\x00\x00\x00\x00#;\xb8p\x00\x00\x00\x00$+\xa9p\x00\x00\x00\x00%\x1b\x9ap\x00\x00\x00\x00&\x0b\x8bp\x00\x00\x00\x00'\x04\xb6\xf0\x00\x00\x00\x00'\xf4\xa7\xf0\x00\x00\x00\x00(\xe4\xa7\x00\x00\x00\x00\x00)xO\x00\x00\x00\x00\x00)\xd4\x89\xf0\x00\x00\x00\x00*\xc4z\xf0\x00\x00\x00\x00+\xb4k\xf0\x00\x00\x00\x00,\xa4\x5c\xf0\x00\x00\x00\x00-\x94M\xf0\x00\x00\x00\x00.\x84>\xf0\x00\x00\x00\x00/t/\xf0\x00\x00\x00\x000d \xf0\x00\x00\x00\x001]Lp\x00\x00\x00\x002r'p\x00\x00\x00\x003=.p\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xfa\xf8\x00\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D%i\x00\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xeeg\x80\x00\x00\x00\x00I\x03B\x80\x00\x00\x00\x00I\xceI\x80\x00\x00\x00\x00J\xe3$\x80\x00\x00\x00\x00K\xae+\x80\x00\x00\x00\x00L\xccA\x00\x00\x00\x00\x00M\x8e\x0d\x80\x00\x00\x00\x00TK\xba\xf0\x00\x00\x00\x00V\xf6\xb2\x00\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x05\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x03\x05\x03\x00\x00\x85\xc8\x00\x00\x00\x00~\x90\x00\x04\x00\x00\xa8\xc0\x01\x08\x00\x00\x9a\xb0\x00\x0c\x00\x00\x9a\xb0\x01\x0c\x00\x00\x8c\xa0\x00\x10LMT\x00+09\x00+12\x00+11\x00+10\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00w\x0dD\x07n\x01\x00\x00n\x01\x00\x00\x0e\x00\x00\x00Asia/SamarkandTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x857\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xedP\x01\x02\x03\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x00>\xc9\x00\x00\x00\x008@\x00\x04\x00\x00FP\x00\x08\x00\x00T`\x01\x0c\x00\x00T`\x00\x0cLMT\x00+04\x00+05\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7X,Y\x9f\x01\x00\x00\x9f\x01\x00\x00\x0a\x00\x00\x00Asia/SeoulTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\x8b\xd7\xf0x\xff\xff\xff\xff\x92\xe6\x16\xf8\xff\xff\xff\xff\xd2C'\xf0\xff\xff\xff\xff\xd7e\x8fp\xff\xff\xff\xff\xd7\xee\x9d`\xff\xff\xff\xff\xd8\xf8\xfap\xff\xff\xff\xff\xd9\xcd-\xe0\xff\xff\xff\xff\xda\xd7\x8a\xf0\xff\xff\xff\xff\xdb\xad\x0f\xe0\xff\xff\xff\xff\xdc\xe6\xe2\xf0\xff\xff\xff\xff\xdd\x8c\xf1\xe0\xff\xff\xff\xff\xe2O)\xf0\xff\xff\xff\xff\xe4k\xb7\xf8\xff\xff\xff\xff\xe5\x13\x18h\xff\xff\xff\xff\xe6b\x03x\xff\xff\xff\xff\xe7\x11L\xe8\xff\xff\xff\xff\xe8/px\xff\xff\xff\xff\xe8\xe7\xf4h\xff\xff\xff\xff\xea\x0fRx\xff\xff\xff\xff\xea\xc7\xd6h\xff\xff\xff\xff\xeb\xef4x\xff\xff\xff\xff\xec\xa7\xb8h\xff\xff\xff\xff\xed\xcf\x16x\xff\xff\xff\xff\xee\x87\x9ah\xff\xff\xff\xff\xf05qx\x00\x00\x00\x00 \xa3`\x90\x00\x00\x00\x00!ng\x90\x00\x00\x00\x00\x22\x83B\x90\x00\x00\x00\x00#NI\x90\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x04\x03\x04\x03\x04\x00\x00w\x08\x00\x00\x00\x00w\x88\x00\x04\x00\x00~\x90\x00\x08\x00\x00\x8c\xa0\x01\x0c\x00\x00~\x90\x00\x04\x00\x00\x85\x98\x01\x0cLMT\x00KST\x00JST\x00KDT\x00\x0aKST-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0d\x00\x00\x00Asia/ShanghaiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff~6C)\xff\xff\xff\xff\xa0\x97\xa2\x80\xff\xff\xff\xff\xa1y\x04\xf0\xff\xff\xff\xff\xc8Y^\x80\xff\xff\xff\xff\xc9\x09\xf9p\xff\xff\xff\xff\xc9\xd3\xbd\x00\xff\xff\xff\xff\xcb\x05\x8a\xf0\xff\xff\xff\xff\xcb|@\x00\xff\xff\xff\xff\xd2;>\xf0\xff\xff\xff\xff\xd3\x8b{\x80\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5E\x22\x00\xff\xff\xff\xff\xd6L\xbf\xf0\xff\xff\xff\xff\xd7<\xbf\x00\xff\xff\xff\xff\xd8\x06fp\xff\xff\xff\xff\xd9\x1d\xf2\x80\xff\xff\xff\xff\xd9A|\xf0\x00\x00\x00\x00\x1e\xbaR \x00\x00\x00\x00\x1fi\x9b\x90\x00\x00\x00\x00 ~\x84\xa0\x00\x00\x00\x00!I}\x90\x00\x00\x00\x00\x22g\xa1 \x00\x00\x00\x00#)_\x90\x00\x00\x00\x00$G\x83 \x00\x00\x00\x00%\x12|\x10\x00\x00\x00\x00&'e \x00\x00\x00\x00&\xf2^\x10\x00\x00\x00\x00(\x07G \x00\x00\x00\x00(\xd2@\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00q\xd7\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x08LMT\x00CDT\x00CST\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F7k\x1c\x00\x01\x00\x00\x00\x01\x00\x00\x0e\x00\x00\x00Asia/SingaporeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00 \xff\xff\xff\xff~6S\xa3\xff\xff\xff\xff\x86\x83\x85\xa3\xff\xff\xff\xff\xbagN\x90\xff\xff\xff\xff\xc0\x0a\xe4`\xff\xff\xff\xff\xca\xb3\xe5`\xff\xff\xff\xff\xcb\x91_\x08\xff\xff\xff\xff\xd2Hm\xf0\x00\x00\x00\x00\x16\x91\xee\x00\x01\x02\x03\x04\x05\x06\x05\x07\x00\x00a]\x00\x00\x00\x00a]\x00\x04\x00\x00bp\x00\x08\x00\x00g \x01\x0c\x00\x00g \x00\x0c\x00\x00ix\x00\x12\x00\x00~\x90\x00\x18\x00\x00p\x80\x00\x1cLMT\x00SMT\x00+07\x00+0720\x00+0730\x00+09\x00+08\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4Z\xdf\x90\xe6\x02\x00\x00\xe6\x02\x00\x00\x12\x00\x00\x00Asia/SrednekolymskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x193\xe4\xff\xff\xff\xff\xb5\xa3\xa8\xe0\x00\x00\x00\x00\x15'7P\x00\x00\x00\x00\x16\x18k\xc0\x00\x00\x00\x00\x17\x08j\xd0\x00\x00\x00\x00\x17\xf9\x9f@\x00\x00\x00\x00\x18\xe9\x9eP\x00\x00\x00\x00\x19\xda\xd2\xc0\x00\x00\x00\x00\x1a\xcc#P\x00\x00\x00\x00\x1b\xbc0p\x00\x00\x00\x00\x1c\xac!p\x00\x00\x00\x00\x1d\x9c\x12p\x00\x00\x00\x00\x1e\x8c\x03p\x00\x00\x00\x00\x1f{\xf4p\x00\x00\x00\x00 k\xe5p\x00\x00\x00\x00![\xd6p\x00\x00\x00\x00\x22K\xc7p\x00\x00\x00\x00#;\xb8p\x00\x00\x00\x00$+\xa9p\x00\x00\x00\x00%\x1b\x9ap\x00\x00\x00\x00&\x0b\x8bp\x00\x00\x00\x00'\x04\xb6\xf0\x00\x00\x00\x00'\xf4\xa7\xf0\x00\x00\x00\x00(\xe4\xa7\x00\x00\x00\x00\x00)xO\x00\x00\x00\x00\x00)\xd4\x89\xf0\x00\x00\x00\x00*\xc4z\xf0\x00\x00\x00\x00+\xb4k\xf0\x00\x00\x00\x00,\xa4\x5c\xf0\x00\x00\x00\x00-\x94M\xf0\x00\x00\x00\x00.\x84>\xf0\x00\x00\x00\x00/t/\xf0\x00\x00\x00\x000d \xf0\x00\x00\x00\x001]Lp\x00\x00\x00\x002r'p\x00\x00\x00\x003=.p\x00\x00\x00\x004R\x09p\x00\x00\x00\x005\x1d\x10p\x00\x00\x00\x0061\xebp\x00\x00\x00\x006\xfc\xf2p\x00\x00\x00\x008\x1b\x07\xf0\x00\x00\x00\x008\xdc\xd4p\x00\x00\x00\x009\xfa\xe9\xf0\x00\x00\x00\x00:\xbc\xb6p\x00\x00\x00\x00;\xda\xcb\xf0\x00\x00\x00\x00<\xa5\xd2\xf0\x00\x00\x00\x00=\xba\xad\xf0\x00\x00\x00\x00>\x85\xb4\xf0\x00\x00\x00\x00?\x9a\x8f\xf0\x00\x00\x00\x00@e\x96\xf0\x00\x00\x00\x00A\x83\xacp\x00\x00\x00\x00BEx\xf0\x00\x00\x00\x00Cc\x8ep\x00\x00\x00\x00D%Z\xf0\x00\x00\x00\x00ECpp\x00\x00\x00\x00F\x05<\xf0\x00\x00\x00\x00G#Rp\x00\x00\x00\x00G\xeeYp\x00\x00\x00\x00I\x034p\x00\x00\x00\x00I\xce;p\x00\x00\x00\x00J\xe3\x16p\x00\x00\x00\x00K\xae\x1dp\x00\x00\x00\x00L\xcc2\xf0\x00\x00\x00\x00M\x8d\xffp\x00\x00\x00\x00TK\xac\xe0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x03\x00\x00\x90\x1c\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00\xa8\xc0\x01\x08\x00\x00\x9a\xb0\x00\x0c\x00\x00\x9a\xb0\x01\x0c\x00\x00\xa8\xc0\x00\x08LMT\x00+10\x00+12\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xee\xf0BB\xff\x01\x00\x00\xff\x01\x00\x00\x0b\x00\x00\x00Asia/TaipeiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xfft\xce\xf0\x18\xff\xff\xff\xff\xc3UI\x80\xff\xff\xff\xff\xd2TY\x80\xff\xff\xff\xff\xd3\x8b{\x80\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5E\x22\x00\xff\xff\xff\xff\xd6L\xbf\xf0\xff\xff\xff\xff\xd7<\xbf\x00\xff\xff\xff\xff\xd8\x06fp\xff\xff\xff\xff\xd9\x1d\xf2\x80\xff\xff\xff\xff\xd9\xe7\x99\xf0\xff\xff\xff\xff\xda\xff&\x00\xff\xff\xff\xff\xdb\xc8\xcdp\xff\xff\xff\xff\xdc\xe0Y\x80\xff\xff\xff\xff\xdd\xaa\x00\xf0\xff\xff\xff\xff\xders\x00\xff\xff\xff\xff\xdf\xb5dp\xff\xff\xff\xff\xe0|\x85\x00\xff\xff\xff\xff\xe1\x96\x97\xf0\xff\xff\xff\xff\xe2]\xb8\x80\xff\xff\xff\xff\xe3w\xcbp\xff\xff\xff\xff\xe4>\xec\x00\xff\xff\xff\xff\xe50 p\xff\xff\xff\xff\xe6!q\x00\xff\xff\xff\xff\xe7\x12\xa5p\xff\xff\xff\xff\xe8\x02\xa4\x80\xff\xff\xff\xff\xe8\xf3\xd8\xf0\xff\xff\xff\xff\xe9\xe3\xd8\x00\xff\xff\xff\xff\xea\xd5\x0cp\xff\xff\xff\xff\xeb\xc5\x0b\x80\xff\xff\xff\xff\xec\xb6?\xf0\xff\xff\xff\xff\xed\xf7\xfc\x00\xff\xff\xff\xff\xee\x98\xc4\xf0\xff\xff\xff\xff\xef\xd9/\x80\xff\xff\xff\xff\xf0y\xf8p\x00\x00\x00\x00\x07\xfcV\x00\x00\x00\x00\x00\x08\xed\x8ap\x00\x00\x00\x00\x09\xdd\x89\x80\x00\x00\x00\x00\x0a\xce\xbd\xf0\x00\x00\x00\x00\x11\xdb\xa1\x80\x00\x00\x00\x00\x12T\xddp\x01\x02\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x00\x00q\xe8\x00\x00\x00\x00p\x80\x00\x04\x00\x00~\x90\x00\x08\x00\x00~\x90\x01\x0cLMT\x00CST\x00JST\x00CDT\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xe27Yn\x01\x00\x00n\x01\x00\x00\x0d\x00\x00\x00Asia/TashkentTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x83\x09\xff\xff\xff\xff\xb5\xa3\xef0\x00\x00\x00\x00\x15'}\xa0\x00\x00\x00\x00\x16\x18\xb2\x10\x00\x00\x00\x00\x17\x08\xb1 \x00\x00\x00\x00\x17\xf9\xe5\x90\x00\x00\x00\x00\x18\xe9\xe4\xa0\x00\x00\x00\x00\x19\xdb\x19\x10\x00\x00\x00\x00\x1a\xcci\xa0\x00\x00\x00\x00\x1b\xbcv\xc0\x00\x00\x00\x00\x1c\xacg\xc0\x00\x00\x00\x00\x1d\x9cX\xc0\x00\x00\x00\x00\x1e\x8cI\xc0\x00\x00\x00\x00\x1f|:\xc0\x00\x00\x00\x00 l+\xc0\x00\x00\x00\x00!\x5c\x1c\xc0\x00\x00\x00\x00\x22L\x0d\xc0\x00\x00\x00\x00#;\xfe\xc0\x00\x00\x00\x00$+\xef\xc0\x00\x00\x00\x00%\x1b\xe0\xc0\x00\x00\x00\x00&\x0b\xd1\xc0\x00\x00\x00\x00'\x04\xfd@\x00\x00\x00\x00'\xf4\xee@\x00\x00\x00\x00(\xe4\xedP\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x00\x00@\xf7\x00\x00\x00\x00FP\x00\x04\x00\x00bp\x01\x08\x00\x00T`\x00\x0c\x00\x00T`\x01\x0cLMT\x00+05\x00+07\x00+06\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\xbe\xa8\xc7u\x02\x00\x00u\x02\x00\x00\x0c\x00\x00\x00Asia/TbilisiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x00\x00\x00\x06\x00\x00\x00\x15\xff\xff\xff\xffV\xb6\xba\x01\xff\xff\xff\xff\xaa\x19\x9a\x01\xff\xff\xff\xff\xe7\xda\x0cP\x00\x00\x00\x00\x15'\x99\xc0\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xcd@\x00\x00\x00\x00\x17\xfa\x01\xb0\x00\x00\x00\x00\x18\xea\x00\xc0\x00\x00\x00\x00\x19\xdb50\x00\x00\x00\x00\x1a\xcc\x85\xc0\x00\x00\x00\x00\x1b\xbc\x92\xe0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9ct\xe0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|V\xe0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c8\xe0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x1a\xe0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1b\xfc\xe0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x19`\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe5\x09p\x00\x00\x00\x00)\xd4\xdeP\x00\x00\x00\x00*\xc4\xc1@\x00\x00\x00\x00+\xb4\xc0P\x00\x00\x00\x00,\xa4\xa3@\x00\x00\x00\x00-\x94\xa2P\x00\x00\x00\x00.\x84\x85@\x00\x00\x00\x00/tv@\x00\x00\x00\x000dY0\x00\x00\x00\x001]\x92\xc0\x00\x00\x00\x003=f\xb0\x00\x00\x00\x004RA\xb0\x00\x00\x00\x005\x1dV\xc0\x00\x00\x00\x0062#\xb0\x00\x00\x00\x006\xfd8\xc0\x00\x00\x00\x008\x1b@0\x00\x00\x00\x008\xdd\x1a\xc0\x00\x00\x00\x009\xfb\x220\x00\x00\x00\x00:\xbc\xfc\xc0\x00\x00\x00\x00;\xdb\x040\x00\x00\x00\x00<\xa6\x19@\x00\x00\x00\x00=\xba\xe60\x00\x00\x00\x00>\x85\xfb@\x00\x00\x00\x00?\x9a\xc80\x00\x00\x00\x00@e\xdd@\x00\x00\x00\x00@\xdd\xc7\xb0\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x05\x02\x05\x02\x05\x02\x05\x04\x03\x04\x03\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x05\x02\x04\x00\x00)\xff\x00\x00\x00\x00)\xff\x00\x04\x00\x00*0\x00\x09\x00\x00FP\x01\x0d\x00\x008@\x00\x11\x00\x008@\x01\x11LMT\x00TBMT\x00+03\x00+05\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\xdb?\xec,\x03\x00\x00,\x03\x00\x00\x0b\x00\x00\x00Asia/TehranTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x06\x00\x00\x00\x1c\xff\xff\xff\xff\x9al}\xc8\xff\xff\xff\xff\xbf\x00\xccH\x00\x00\x00\x00\x0d\x94D8\x00\x00\x00\x00\x0e\xad\x13\xb8\x00\x00\x00\x00\x0fys@\x00\x00\x00\x00\x10(\xca\xc0\x00\x00\x00\x00\x10\xed:@\x00\x00\x00\x00\x11\xad\xbcH\x00\x00\x00\x00\x12EJ\xb8\x00\x00\x00\x00\x137\xec\xc8\x00\x00\x00\x00\x14-\x15\xb8\x00\x00\x00\x00( v\xc8\x00\x00\x00\x00(\xdb\x9d\xb8\x00\x00\x00\x00)\xcb\x9c\xc8\x00\x00\x00\x00*\xbe\x22\xb8\x00\x00\x00\x00+\xac\xd0H\x00\x00\x00\x00,\x9fV8\x00\x00\x00\x00-\x8e\x03\xc8\x00\x00\x00\x00.\x80\x89\xb8\x00\x00\x00\x00/o7H\x00\x00\x00\x000a\xbd8\x00\x00\x00\x001Pj\xc8\x00\x00\x00\x002B\xf0\xb8\x00\x00\x00\x0032\xef\xc8\x00\x00\x00\x004%u\xb8\x00\x00\x00\x005\x14#H\x00\x00\x00\x006\x06\xa98\x00\x00\x00\x006\xf5V\xc8\x00\x00\x00\x007\xe7\xdc\xb8\x00\x00\x00\x008\xd6\x8aH\x00\x00\x00\x009\xc9\x108\x00\x00\x00\x00:\xb9\x0fH\x00\x00\x00\x00;\xab\x958\x00\x00\x00\x00<\x9aB\xc8\x00\x00\x00\x00=\x8c\xc8\xb8\x00\x00\x00\x00>{vH\x00\x00\x00\x00?m\xfc8\x00\x00\x00\x00@\x5c\xa9\xc8\x00\x00\x00\x00AO/\xb8\x00\x00\x00\x00B?.\xc8\x00\x00\x00\x00C1\xb4\xb8\x00\x00\x00\x00G\xe2\xc9H\x00\x00\x00\x00H\xd5O8\x00\x00\x00\x00I\xc5NH\x00\x00\x00\x00J\xb7\xd48\x00\x00\x00\x00K\xa6\x81\xc8\x00\x00\x00\x00L\x99\x07\xb8\x00\x00\x00\x00M\x87\xb5H\x00\x00\x00\x00Nz;8\x00\x00\x00\x00Oh\xe8\xc8\x00\x00\x00\x00P[n\xb8\x00\x00\x00\x00QKm\xc8\x00\x00\x00\x00R=\xf3\xb8\x00\x00\x00\x00S,\xa1H\x00\x00\x00\x00T\x1f'8\x00\x00\x00\x00U\x0d\xd4\xc8\x00\x00\x00\x00V\x00Z\xb8\x00\x00\x00\x00V\xef\x08H\x00\x00\x00\x00W\xe1\x8e8\x00\x00\x00\x00X\xd1\x8dH\x00\x00\x00\x00Y\xc4\x138\x00\x00\x00\x00Z\xb2\xc0\xc8\x00\x00\x00\x00[\xa5F\xb8\x00\x00\x00\x00\x5c\x93\xf4H\x00\x00\x00\x00]\x86z8\x00\x00\x00\x00^u'\xc8\x00\x00\x00\x00_g\xad\xb8\x00\x00\x00\x00`W\xac\xc8\x00\x00\x00\x00aJ2\xb8\x00\x00\x00\x00b8\xe0H\x00\x00\x00\x00c+f8\x01\x03\x02\x05\x04\x05\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x0008\x00\x00\x00\x0008\x00\x04\x00\x00?H\x01\x08\x00\x0018\x00\x0e\x00\x00FP\x01\x14\x00\x008@\x00\x18LMT\x00TMT\x00+0430\x00+0330\x00+05\x00+04\x00\x0a<+0330>-3:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xe2\x9c\xb32\x04\x00\x002\x04\x00\x00\x0d\x00\x00\x00Asia/Tel_AvivTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xffV\xb6\xc2\xfa\xff\xff\xff\xff\x9e0E\x88\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xff\xcd\xac\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xff\xcf\x8f\x83\x00\xff\xff\xff\xff\xd0\xa9\xa4\x00\xff\xff\xff\xff\xd1\x84}\x00\xff\xff\xff\xff\xd2\x8a\xd7\x80\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\x0b\x00\xff\xff\xff\xff\xd7Z0\x80\xff\xff\xff\xff\xd7\xdfX\x00\xff\xff\xff\xff\xd8/\xc3\x80\xff\xff\xff\xff\xd9\x1ec\x00\xff\xff\xff\xff\xda\x10\xf7\x00\xff\xff\xff\xff\xda\xeb\xd0\x00\xff\xff\xff\xff\xdb\xb44\x00\xff\xff\xff\xff\xdc\xb9=\x00\xff\xff\xff\xff\xdd\xe0\x8d\x00\xff\xff\xff\xff\xde\xb4\xce\x80\xff\xff\xff\xff\xdf\xa4\xbf\x80\xff\xff\xff\xff\xe0\x8bv\x00\xff\xff\xff\xff\xe1V}\x00\xff\xff\xff\xff\xe2\xbef\x80\xff\xff\xff\xff\xe36_\x00\xff\xff\xff\xff\xe4\x9eH\x80\xff\xff\xff\xff\xe5\x16A\x00\xff\xff\xff\xff\xe6t\xf0\x00\xff\xff\xff\xff\xe7\x11\xd2\x80\xff\xff\xff\xff\xe8&\xad\x80\xff\xff\xff\xff\xe8\xe8z\x00\x00\x00\x00\x00\x08|\x8b\xe0\x00\x00\x00\x00\x08\xfd\xb0\xd0\x00\x00\x00\x00\x09\xf6\xea`\x00\x00\x00\x00\x0a\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\x22^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x001H\x96\xe0\x00\x00\x00\x002\x83\x82p\x00\x00\x00\x00?|\x9f\xe0\x00\x00\x00\x00@s6p\x00\x00\x00\x00AP\xa4`\x00\x00\x00\x00BL\x8f\x00\x00\x00\x00\x00CHOp\x00\x00\x00\x00D,q\x00\x00\x00\x00\x00E\x1e\xf6\xf0\x00\x00\x00\x00F\x0cS\x00\x00\x00\x00\x00F\xecc\xf0\x00\x00\x00\x00G\xec5\x00\x00\x00\x00\x00H\xe7\xf5p\x00\x00\x00\x00I\xcc\x17\x00\x00\x00\x00\x00J\xbe\x9c\xf0\x00\x00\x00\x00K\xab\xf9\x00\x00\x00\x00\x00L\x8c\x09\xf0\x00\x00\x00\x00M\x95\x15\x80\x00\x00\x00\x00N\x87\x9bp\x00\x00\x00\x00Ot\xf7\x80\x00\x00\x00\x00P^B\xf0\x00\x00\x00\x00QT\xd9\x80\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x00!\x06\x00\x00\x00\x00 \xf8\x00\x04\x00\x00*0\x01\x08\x00\x00\x1c \x00\x0c\x00\x008@\x01\x10LMT\x00JMT\x00IDT\x00IST\x00IDDT\x00\x0aIST-2IDT,M3.4.4/26,M10.5.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j$\xcd\xf4\x9a\x00\x00\x00\x9a\x00\x00\x00\x0b\x00\x00\x00Asia/ThimbuTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xff\xd5\xe6\x15t\x00\x00\x00\x00!aM\xa8\x01\x02\x00\x00T\x0c\x00\x00\x00\x00MX\x00\x04\x00\x00T`\x00\x0aLMT\x00+0530\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j$\xcd\xf4\x9a\x00\x00\x00\x9a\x00\x00\x00\x0c\x00\x00\x00Asia/ThimphuTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xff\xd5\xe6\x15t\x00\x00\x00\x00!aM\xa8\x01\x02\x00\x00T\x0c\x00\x00\x00\x00MX\x00\x04\x00\x00T`\x00\x0aLMT\x00+0530\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xf4\xaeg\xd5\x00\x00\x00\xd5\x00\x00\x00\x0a\x00\x00\x00Asia/TokyoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffe\xc2\xa4p\xff\xff\xff\xff\xd7>\x02p\xff\xff\xff\xff\xd7\xedY\xf0\xff\xff\xff\xff\xd8\xf8\xfap\xff\xff\xff\xff\xd9\xcd;\xf0\xff\xff\xff\xff\xdb\x07\x00\xf0\xff\xff\xff\xff\xdb\xad\x1d\xf0\xff\xff\xff\xff\xdc\xe6\xe2\xf0\xff\xff\xff\xff\xdd\x8c\xff\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x83\x03\x00\x00\x00\x00\x8c\xa0\x01\x04\x00\x00~\x90\x00\x08LMT\x00JDT\x00JST\x00\x0aJST-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[u\x99q\xf1\x02\x00\x00\xf1\x02\x00\x00\x0a\x00\x00\x00Asia/TomskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xe5N\xd9\xff\xff\xff\xff\xb5\xa3\xe1 \x00\x00\x00\x00\x15'o\x90\x00\x00\x00\x00\x16\x18\xa4\x00\x00\x00\x00\x00\x17\x08\xa3\x10\x00\x00\x00\x00\x17\xf9\xd7\x80\x00\x00\x00\x00\x18\xe9\xd6\x90\x00\x00\x00\x00\x19\xdb\x0b\x00\x00\x00\x00\x00\x1a\xcc[\x90\x00\x00\x00\x00\x1b\xbch\xb0\x00\x00\x00\x00\x1c\xacY\xb0\x00\x00\x00\x00\x1d\x9cJ\xb0\x00\x00\x00\x00\x1e\x8c;\xb0\x00\x00\x00\x00\x1f|,\xb0\x00\x00\x00\x00 l\x1d\xb0\x00\x00\x00\x00!\x5c\x0e\xb0\x00\x00\x00\x00\x22K\xff\xb0\x00\x00\x00\x00#;\xf0\xb0\x00\x00\x00\x00$+\xe1\xb0\x00\x00\x00\x00%\x1b\xd2\xb0\x00\x00\x00\x00&\x0b\xc3\xb0\x00\x00\x00\x00'\x04\xef0\x00\x00\x00\x00'\xf4\xe00\x00\x00\x00\x00(\xe4\xdf@\x00\x00\x00\x00)x\x87@\x00\x00\x00\x00)\xd4\xc20\x00\x00\x00\x00*\xc4\xb30\x00\x00\x00\x00+\xb4\xa40\x00\x00\x00\x00,\xa4\x950\x00\x00\x00\x00-\x94\x860\x00\x00\x00\x00.\x84w0\x00\x00\x00\x00/th0\x00\x00\x00\x000dY0\x00\x00\x00\x001]\x84\xb0\x00\x00\x00\x002r_\xb0\x00\x00\x00\x003=f\xb0\x00\x00\x00\x004RA\xb0\x00\x00\x00\x005\x1dH\xb0\x00\x00\x00\x0062#\xb0\x00\x00\x00\x006\xfd*\xb0\x00\x00\x00\x008\x1b@0\x00\x00\x00\x008\xdd\x0c\xb0\x00\x00\x00\x009\xfb\x220\x00\x00\x00\x00:\xbc\xee\xb0\x00\x00\x00\x00;\xdb\x040\x00\x00\x00\x00<\xa6\x0b0\x00\x00\x00\x00<\xce\xe9\xb0\x00\x00\x00\x00=\xba\xf4@\x00\x00\x00\x00>\x85\xfb@\x00\x00\x00\x00?\x9a\xd6@\x00\x00\x00\x00@e\xdd@\x00\x00\x00\x00A\x83\xf2\xc0\x00\x00\x00\x00BE\xbf@\x00\x00\x00\x00Cc\xd4\xc0\x00\x00\x00\x00D%\xa1@\x00\x00\x00\x00EC\xb6\xc0\x00\x00\x00\x00F\x05\x83@\x00\x00\x00\x00G#\x98\xc0\x00\x00\x00\x00G\xee\x9f\xc0\x00\x00\x00\x00I\x03z\xc0\x00\x00\x00\x00I\xce\x81\xc0\x00\x00\x00\x00J\xe3\x5c\xc0\x00\x00\x00\x00K\xaec\xc0\x00\x00\x00\x00L\xccy@\x00\x00\x00\x00M\x8eE\xc0\x00\x00\x00\x00TK\xf30\x00\x00\x00\x00WI\xf8\xc0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x03\x01\x03\x00\x00O\xa7\x00\x00\x00\x00T`\x00\x04\x00\x00p\x80\x01\x08\x00\x00bp\x00\x0c\x00\x00bp\x01\x0cLMT\x00+06\x00+08\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\xc9\xd4\x5c\xbe\x00\x00\x00\xbe\x00\x00\x00\x12\x00\x00\x00Asia/Ujung_PandangTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xff\xa1\xf2]\x90\xff\xff\xff\xff\xba\x16\xd5\x90\xff\xff\xff\xff\xcb\x88\x1d\x80\xff\xff\xff\xff\xd2V\xeep\x01\x02\x03\x04\x00\x00o\xf0\x00\x00\x00\x00o\xf0\x00\x04\x00\x00p\x80\x00\x08\x00\x00~\x90\x00\x0c\x00\x00p\x80\x00\x10LMT\x00MMT\x00+08\x00+09\x00WITA\x00\x0aWITA-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xb9\xf4\xb6R\x02\x00\x00R\x02\x00\x00\x10\x00\x00\x00Asia/UlaanbaatarTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\x86\xd3\xeeL\x00\x00\x00\x00\x0f\x0b\xdc\x90\x00\x00\x00\x00\x18\xe9\xc8\x80\x00\x00\x00\x00\x19\xda\xfc\xf0\x00\x00\x00\x00\x1a\xccM\x80\x00\x00\x00\x00\x1b\xbc0p\x00\x00\x00\x00\x1c\xac/\x80\x00\x00\x00\x00\x1d\x9c\x12p\x00\x00\x00\x00\x1e\x8c\x11\x80\x00\x00\x00\x00\x1f{\xf4p\x00\x00\x00\x00 k\xf3\x80\x00\x00\x00\x00![\xd6p\x00\x00\x00\x00\x22K\xd5\x80\x00\x00\x00\x00#;\xb8p\x00\x00\x00\x00$+\xb7\x80\x00\x00\x00\x00%\x1b\x9ap\x00\x00\x00\x00&\x0b\x99\x80\x00\x00\x00\x00'\x04\xb6\xf0\x00\x00\x00\x00'\xf4\xb6\x00\x00\x00\x00\x00(\xe4\x98\xf0\x00\x00\x00\x00)\xd4\x98\x00\x00\x00\x00\x00*\xc4z\xf0\x00\x00\x00\x00+\xb4z\x00\x00\x00\x00\x00,\xa4\x5c\xf0\x00\x00\x00\x00-\x94\x5c\x00\x00\x00\x00\x00.\x84>\xf0\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000d \xf0\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002M=p\x00\x00\x00\x003=<\x80\x00\x00\x00\x004-\x1fp\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x006\x0d\x01p\x00\x00\x00\x00:\xe9\xb3\xa0\x00\x00\x00\x00;\xb4\xac\x90\x00\x00\x00\x00<\xa4\xab\xa0\x00\x00\x00\x00=\x94\x8e\x90\x00\x00\x00\x00>\x84\x8d\xa0\x00\x00\x00\x00?tp\x90\x00\x00\x00\x00@do\xa0\x00\x00\x00\x00ATR\x90\x00\x00\x00\x00BDQ\xa0\x00\x00\x00\x00C44\x90\x00\x00\x00\x00D$3\xa0\x00\x00\x00\x00E\x1dQ\x10\x00\x00\x00\x00U\x15\x9a\xa0\x00\x00\x00\x00V\x05ap\x00\x00\x00\x00V\xf5|\xa0\x00\x00\x00\x00W\xe5Cp\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00d4\x00\x00\x00\x00bp\x00\x04\x00\x00~\x90\x01\x08\x00\x00p\x80\x00\x0cLMT\x00+07\x00+09\x00+08\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xb9\xf4\xb6R\x02\x00\x00R\x02\x00\x00\x0f\x00\x00\x00Asia/Ulan_BatorTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\x86\xd3\xeeL\x00\x00\x00\x00\x0f\x0b\xdc\x90\x00\x00\x00\x00\x18\xe9\xc8\x80\x00\x00\x00\x00\x19\xda\xfc\xf0\x00\x00\x00\x00\x1a\xccM\x80\x00\x00\x00\x00\x1b\xbc0p\x00\x00\x00\x00\x1c\xac/\x80\x00\x00\x00\x00\x1d\x9c\x12p\x00\x00\x00\x00\x1e\x8c\x11\x80\x00\x00\x00\x00\x1f{\xf4p\x00\x00\x00\x00 k\xf3\x80\x00\x00\x00\x00![\xd6p\x00\x00\x00\x00\x22K\xd5\x80\x00\x00\x00\x00#;\xb8p\x00\x00\x00\x00$+\xb7\x80\x00\x00\x00\x00%\x1b\x9ap\x00\x00\x00\x00&\x0b\x99\x80\x00\x00\x00\x00'\x04\xb6\xf0\x00\x00\x00\x00'\xf4\xb6\x00\x00\x00\x00\x00(\xe4\x98\xf0\x00\x00\x00\x00)\xd4\x98\x00\x00\x00\x00\x00*\xc4z\xf0\x00\x00\x00\x00+\xb4z\x00\x00\x00\x00\x00,\xa4\x5c\xf0\x00\x00\x00\x00-\x94\x5c\x00\x00\x00\x00\x00.\x84>\xf0\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000d \xf0\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002M=p\x00\x00\x00\x003=<\x80\x00\x00\x00\x004-\x1fp\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x006\x0d\x01p\x00\x00\x00\x00:\xe9\xb3\xa0\x00\x00\x00\x00;\xb4\xac\x90\x00\x00\x00\x00<\xa4\xab\xa0\x00\x00\x00\x00=\x94\x8e\x90\x00\x00\x00\x00>\x84\x8d\xa0\x00\x00\x00\x00?tp\x90\x00\x00\x00\x00@do\xa0\x00\x00\x00\x00ATR\x90\x00\x00\x00\x00BDQ\xa0\x00\x00\x00\x00C44\x90\x00\x00\x00\x00D$3\xa0\x00\x00\x00\x00E\x1dQ\x10\x00\x00\x00\x00U\x15\x9a\xa0\x00\x00\x00\x00V\x05ap\x00\x00\x00\x00V\xf5|\xa0\x00\x00\x00\x00W\xe5Cp\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00d4\x00\x00\x00\x00bp\x00\x04\x00\x00~\x90\x01\x08\x00\x00p\x80\x00\x0cLMT\x00+07\x00+09\x00+08\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x1d\xc6\x1b\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00Asia/UrumqiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xb0\xfe\xbad\x01\x00\x00R\x1c\x00\x00\x00\x00T`\x00\x04LMT\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00w\x86\x8d^\x03\x03\x00\x00\x03\x03\x00\x00\x0d\x00\x00\x00Asia/Ust-NeraTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x08\x00\x00\x00\x18\xff\xff\xff\xff\xa1\xdb\xdd\xba\xff\xff\xff\xff\xb5\xa3\xc5\x00\x00\x00\x00\x00\x15'Sp\x00\x00\x00\x00\x16\x18k\xc0\x00\x00\x00\x00\x17\x08j\xd0\x00\x00\x00\x00\x17\xf9\x9f@\x00\x00\x00\x00\x18\xe9\x9eP\x00\x00\x00\x00\x19\xda\xd2\xc0\x00\x00\x00\x00\x1a\xcc#P\x00\x00\x00\x00\x1b\xbc0p\x00\x00\x00\x00\x1c\xac!p\x00\x00\x00\x00\x1d\x9c\x12p\x00\x00\x00\x00\x1e\x8c\x03p\x00\x00\x00\x00\x1f{\xf4p\x00\x00\x00\x00 k\xe5p\x00\x00\x00\x00![\xd6p\x00\x00\x00\x00\x22K\xc7p\x00\x00\x00\x00#;\xb8p\x00\x00\x00\x00$+\xa9p\x00\x00\x00\x00%\x1b\x9ap\x00\x00\x00\x00&\x0b\x8bp\x00\x00\x00\x00'\x04\xb6\xf0\x00\x00\x00\x00'\xf4\xa7\xf0\x00\x00\x00\x00(\xe4\xa7\x00\x00\x00\x00\x00)xO\x00\x00\x00\x00\x00)\xd4\x89\xf0\x00\x00\x00\x00*\xc4z\xf0\x00\x00\x00\x00+\xb4k\xf0\x00\x00\x00\x00,\xa4\x5c\xf0\x00\x00\x00\x00-\x94M\xf0\x00\x00\x00\x00.\x84>\xf0\x00\x00\x00\x00/t/\xf0\x00\x00\x00\x000d \xf0\x00\x00\x00\x001]Lp\x00\x00\x00\x002r'p\x00\x00\x00\x003=.p\x00\x00\x00\x004R\x09p\x00\x00\x00\x005\x1d\x10p\x00\x00\x00\x0061\xebp\x00\x00\x00\x006\xfc\xf2p\x00\x00\x00\x008\x1b\x07\xf0\x00\x00\x00\x008\xdc\xd4p\x00\x00\x00\x009\xfa\xe9\xf0\x00\x00\x00\x00:\xbc\xb6p\x00\x00\x00\x00;\xda\xcb\xf0\x00\x00\x00\x00<\xa5\xd2\xf0\x00\x00\x00\x00=\xba\xad\xf0\x00\x00\x00\x00>\x85\xb4\xf0\x00\x00\x00\x00?\x9a\x8f\xf0\x00\x00\x00\x00@e\x96\xf0\x00\x00\x00\x00A\x83\xacp\x00\x00\x00\x00BEx\xf0\x00\x00\x00\x00Cc\x8ep\x00\x00\x00\x00D%Z\xf0\x00\x00\x00\x00ECpp\x00\x00\x00\x00F\x05<\xf0\x00\x00\x00\x00G#Rp\x00\x00\x00\x00G\xeeYp\x00\x00\x00\x00I\x034p\x00\x00\x00\x00I\xce;p\x00\x00\x00\x00J\xe3\x16p\x00\x00\x00\x00K\xae\x1dp\x00\x00\x00\x00L\xcc2\xf0\x00\x00\x00\x00M\x8d\xffp\x00\x00\x00\x00Nm\xf4@\x00\x00\x00\x00TK\xba\xf0\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x05\x06\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x07\x03\x06\x00\x00\x86F\x00\x00\x00\x00p\x80\x00\x04\x00\x00~\x90\x00\x08\x00\x00\x9a\xb0\x00\x0c\x00\x00\xa8\xc0\x01\x10\x00\x00\x9a\xb0\x01\x0c\x00\x00\x8c\xa0\x00\x14\x00\x00\xa8\xc0\x00\x10LMT\x00+08\x00+09\x00+11\x00+12\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x0e\x00\x00\x00Asia/VientianeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffV\xb6\x85\xc4\xff\xff\xff\xff\xa2jg\xc4\x01\x02\x00\x00^<\x00\x00\x00\x00^<\x00\x04\x00\x00bp\x00\x08LMT\x00BMT\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d%\x05\xd8\xe6\x02\x00\x00\xe6\x02\x00\x00\x10\x00\x00\x00Asia/VladivostokTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xa7YG]\xff\xff\xff\xff\xb5\xa3\xb6\xf0\x00\x00\x00\x00\x15'E`\x00\x00\x00\x00\x16\x18y\xd0\x00\x00\x00\x00\x17\x08x\xe0\x00\x00\x00\x00\x17\xf9\xadP\x00\x00\x00\x00\x18\xe9\xac`\x00\x00\x00\x00\x19\xda\xe0\xd0\x00\x00\x00\x00\x1a\xcc1`\x00\x00\x00\x00\x1b\xbc>\x80\x00\x00\x00\x00\x1c\xac/\x80\x00\x00\x00\x00\x1d\x9c \x80\x00\x00\x00\x00\x1e\x8c\x11\x80\x00\x00\x00\x00\x1f|\x02\x80\x00\x00\x00\x00 k\xf3\x80\x00\x00\x00\x00![\xe4\x80\x00\x00\x00\x00\x22K\xd5\x80\x00\x00\x00\x00#;\xc6\x80\x00\x00\x00\x00$+\xb7\x80\x00\x00\x00\x00%\x1b\xa8\x80\x00\x00\x00\x00&\x0b\x99\x80\x00\x00\x00\x00'\x04\xc5\x00\x00\x00\x00\x00'\xf4\xb6\x00\x00\x00\x00\x00(\xe4\xb5\x10\x00\x00\x00\x00)x]\x10\x00\x00\x00\x00)\xd4\x98\x00\x00\x00\x00\x00*\xc4\x89\x00\x00\x00\x00\x00+\xb4z\x00\x00\x00\x00\x00,\xa4k\x00\x00\x00\x00\x00-\x94\x5c\x00\x00\x00\x00\x00.\x84M\x00\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000d/\x00\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002r5\x80\x00\x00\x00\x003=<\x80\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xfa\xf8\x00\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D%i\x00\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xeeg\x80\x00\x00\x00\x00I\x03B\x80\x00\x00\x00\x00I\xceI\x80\x00\x00\x00\x00J\xe3$\x80\x00\x00\x00\x00K\xae+\x80\x00\x00\x00\x00L\xccA\x00\x00\x00\x00\x00M\x8e\x0d\x80\x00\x00\x00\x00TK\xba\xf0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x03\x00\x00{\xa3\x00\x00\x00\x00~\x90\x00\x04\x00\x00\x9a\xb0\x01\x08\x00\x00\x8c\xa0\x00\x0c\x00\x00\x8c\xa0\x01\x0c\x00\x00\x9a\xb0\x00\x08LMT\x00+09\x00+11\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O\xb0\x03\xe9\xe5\x02\x00\x00\xe5\x02\x00\x00\x0c\x00\x00\x00Asia/YakutskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\xa1\xdb\xea^\xff\xff\xff\xff\xb5\xa3\xc5\x00\x00\x00\x00\x00\x15'Sp\x00\x00\x00\x00\x16\x18\x87\xe0\x00\x00\x00\x00\x17\x08\x86\xf0\x00\x00\x00\x00\x17\xf9\xbb`\x00\x00\x00\x00\x18\xe9\xbap\x00\x00\x00\x00\x19\xda\xee\xe0\x00\x00\x00\x00\x1a\xcc?p\x00\x00\x00\x00\x1b\xbcL\x90\x00\x00\x00\x00\x1c\xac=\x90\x00\x00\x00\x00\x1d\x9c.\x90\x00\x00\x00\x00\x1e\x8c\x1f\x90\x00\x00\x00\x00\x1f|\x10\x90\x00\x00\x00\x00 l\x01\x90\x00\x00\x00\x00![\xf2\x90\x00\x00\x00\x00\x22K\xe3\x90\x00\x00\x00\x00#;\xd4\x90\x00\x00\x00\x00$+\xc5\x90\x00\x00\x00\x00%\x1b\xb6\x90\x00\x00\x00\x00&\x0b\xa7\x90\x00\x00\x00\x00'\x04\xd3\x10\x00\x00\x00\x00'\xf4\xc4\x10\x00\x00\x00\x00(\xe4\xc3 \x00\x00\x00\x00)xk \x00\x00\x00\x00)\xd4\xa6\x10\x00\x00\x00\x00*\xc4\x97\x10\x00\x00\x00\x00+\xb4\x88\x10\x00\x00\x00\x00,\xa4y\x10\x00\x00\x00\x00-\x94j\x10\x00\x00\x00\x00.\x84[\x10\x00\x00\x00\x00/tL\x10\x00\x00\x00\x000d=\x10\x00\x00\x00\x001]h\x90\x00\x00\x00\x002rC\x90\x00\x00\x00\x003=J\x90\x00\x00\x00\x004R%\x90\x00\x00\x00\x005\x1d,\x90\x00\x00\x00\x0062\x07\x90\x00\x00\x00\x006\xfd\x0e\x90\x00\x00\x00\x008\x1b$\x10\x00\x00\x00\x008\xdc\xf0\x90\x00\x00\x00\x009\xfb\x06\x10\x00\x00\x00\x00:\xbc\xd2\x90\x00\x00\x00\x00;\xda\xe8\x10\x00\x00\x00\x00<\xa5\xef\x10\x00\x00\x00\x00=\xba\xca\x10\x00\x00\x00\x00>\x85\xd1\x10\x00\x00\x00\x00?\x9a\xac\x10\x00\x00\x00\x00@e\xb3\x10\x00\x00\x00\x00A\x83\xc8\x90\x00\x00\x00\x00BE\x95\x10\x00\x00\x00\x00Cc\xaa\x90\x00\x00\x00\x00D%w\x10\x00\x00\x00\x00EC\x8c\x90\x00\x00\x00\x00F\x05Y\x10\x00\x00\x00\x00G#n\x90\x00\x00\x00\x00G\xeeu\x90\x00\x00\x00\x00I\x03P\x90\x00\x00\x00\x00I\xceW\x90\x00\x00\x00\x00J\xe32\x90\x00\x00\x00\x00K\xae9\x90\x00\x00\x00\x00L\xccO\x10\x00\x00\x00\x00M\x8e\x1b\x90\x00\x00\x00\x00TK\xc9\x00\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x03\x00\x00y\xa2\x00\x00\x00\x00p\x80\x00\x04\x00\x00\x8c\xa0\x01\x08\x00\x00~\x90\x00\x0c\x00\x00~\x90\x01\x0c\x00\x00\x8c\xa0\x00\x08LMT\x00+08\x00+10\x00+09\x00\x0a<+09>-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\x87{_\xbb\x00\x00\x00\xbb\x00\x00\x00\x0b\x00\x00\x00Asia/YangonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffV\xb6\x89\xd1\xff\xff\xff\xff\xa1\xf2sQ\xff\xff\xff\xff\xcb\xf2\xfc\x18\xff\xff\xff\xff\xd1\x9ag\xf0\x01\x02\x03\x02\x00\x00Z/\x00\x00\x00\x00Z/\x00\x04\x00\x00[h\x00\x08\x00\x00~\x90\x00\x0eLMT\x00RMT\x00+0630\x00+09\x00\x0a<+0630>-6:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\xea\x18\xd4\xf8\x02\x00\x00\xf8\x02\x00\x00\x12\x00\x00\x00Asia/YekaterinburgTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x07\x00\x00\x00\x14\xff\xff\xff\xff\x9b_\x09'\xff\xff\xff\xff\xa1\x12\xb1\xff\xff\xff\xff\xff\xb5\xa3\xfd@\x00\x00\x00\x00\x15'\x8b\xb0\x00\x00\x00\x00\x16\x18\xc0 \x00\x00\x00\x00\x17\x08\xbf0\x00\x00\x00\x00\x17\xf9\xf3\xa0\x00\x00\x00\x00\x18\xe9\xf2\xb0\x00\x00\x00\x00\x19\xdb' \x00\x00\x00\x00\x1a\xccw\xb0\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xacu\xd0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8cW\xd0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 l9\xd0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L\x1b\xd0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$+\xfd\xd0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xdf\xd0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf4\xfcP\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)x\xa3`\x00\x00\x00\x00)\xd4\xdeP\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xc0P\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xa2P\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x84P\x00\x00\x00\x000duP\x00\x00\x00\x001]\xa0\xd0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x003=\x82\xd0\x00\x00\x00\x004R]\xd0\x00\x00\x00\x005\x1dd\xd0\x00\x00\x00\x0062?\xd0\x00\x00\x00\x006\xfdF\xd0\x00\x00\x00\x008\x1b\x5cP\x00\x00\x00\x008\xdd(\xd0\x00\x00\x00\x009\xfb>P\x00\x00\x00\x00:\xbd\x0a\xd0\x00\x00\x00\x00;\xdb P\x00\x00\x00\x00<\xa6'P\x00\x00\x00\x00=\xbb\x02P\x00\x00\x00\x00>\x86\x09P\x00\x00\x00\x00?\x9a\xe4P\x00\x00\x00\x00@e\xebP\x00\x00\x00\x00A\x84\x00\xd0\x00\x00\x00\x00BE\xcdP\x00\x00\x00\x00Cc\xe2\xd0\x00\x00\x00\x00D%\xafP\x00\x00\x00\x00EC\xc4\xd0\x00\x00\x00\x00F\x05\x91P\x00\x00\x00\x00G#\xa6\xd0\x00\x00\x00\x00G\xee\xad\xd0\x00\x00\x00\x00I\x03\x88\xd0\x00\x00\x00\x00I\xce\x8f\xd0\x00\x00\x00\x00J\xe3j\xd0\x00\x00\x00\x00K\xaeq\xd0\x00\x00\x00\x00L\xcc\x87P\x00\x00\x00\x00M\x8eS\xd0\x00\x00\x00\x00TL\x01@\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x05\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x06\x04\x00\x008\xd9\x00\x00\x00\x004\xc1\x00\x04\x00\x008@\x00\x08\x00\x00T`\x01\x0c\x00\x00FP\x00\x10\x00\x00FP\x01\x10\x00\x00T`\x00\x0cLMT\x00PMT\x00+04\x00+06\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x95-\xad\xc4\x02\x00\x00\xc4\x02\x00\x00\x0c\x00\x00\x00Asia/YerevanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x00\x00\x00\x05\x00\x00\x00\x10\xff\xff\xff\xff\xaa\x19\x9aH\xff\xff\xff\xff\xe7\xda\x0cP\x00\x00\x00\x00\x15'\x99\xc0\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xcd@\x00\x00\x00\x00\x17\xfa\x01\xb0\x00\x00\x00\x00\x18\xea\x00\xc0\x00\x00\x00\x00\x19\xdb50\x00\x00\x00\x00\x1a\xcc\x85\xc0\x00\x00\x00\x00\x1b\xbc\x92\xe0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9ct\xe0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|V\xe0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c8\xe0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x1a\xe0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1b\xfc\xe0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x19`\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe5\x09p\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x94\xbep\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x003=\x90\xe0\x00\x00\x00\x004Rk\xe0\x00\x00\x00\x005\x1dr\xe0\x00\x00\x00\x0062M\xe0\x00\x00\x00\x006\xfdT\xe0\x00\x00\x00\x008\x1bj`\x00\x00\x00\x008\xdd6\xe0\x00\x00\x00\x009\xfbL`\x00\x00\x00\x00:\xbd\x18\xe0\x00\x00\x00\x00;\xdb.`\x00\x00\x00\x00<\xa65`\x00\x00\x00\x00=\xbb\x10`\x00\x00\x00\x00>\x86\x17`\x00\x00\x00\x00?\x9a\xf2`\x00\x00\x00\x00@e\xf9`\x00\x00\x00\x00A\x84\x0e\xe0\x00\x00\x00\x00BE\xdb`\x00\x00\x00\x00Cc\xf0\xe0\x00\x00\x00\x00D%\xbd`\x00\x00\x00\x00EC\xd2\xe0\x00\x00\x00\x00F\x05\x9f`\x00\x00\x00\x00G#\xb4\xe0\x00\x00\x00\x00G\xee\xbb\xe0\x00\x00\x00\x00I\x03\x96\xe0\x00\x00\x00\x00I\xce\x9d\xe0\x00\x00\x00\x00J\xe3x\xe0\x00\x00\x00\x00K\xae\x7f\xe0\x00\x00\x00\x00L\xcc\x95`\x00\x00\x00\x00M\x8ea\xe0\x00\x00\x00\x00N\xacw`\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x04\x01\x04\x01\x04\x01\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00)\xb8\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x01\x08\x00\x008@\x00\x0c\x00\x008@\x01\x0cLMT\x00+03\x00+05\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x8dY\x80\xad\x05\x00\x00\xad\x05\x00\x00\x0f\x00\x00\x00Atlantic/AzoresTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x00\x00\x00\x07\x00\x00\x00\x18\xff\xff\xff\xff^=\x1b\x90\xff\xff\xff\xff\x92\xe6\xaa\xa0\xff\xff\xff\xff\x9bK\x89\x90\xff\xff\xff\xff\x9b\xfe\xe3\xa0\xff\xff\xff\xff\x9c\x9d\x09\x90\xff\xff\xff\xff\x9d\xc9\x9f\x90\xff\xff\xff\xff\x9e\x7f\x8e\x90\xff\xff\xff\xff\x9f\xaa\xd3\x10\xff\xff\xff\xff\xa0_p\x90\xff\xff\xff\xff\xa1\x8c\x06\x90\xff\xff\xff\xff\xa2A\xf5\x90\xff\xff\xff\xff\xa3n\x8b\x90\xff\xff\xff\xff\xa4#)\x10\xff\xff\xff\xff\xa5O\xbf\x10\xff\xff\xff\xff\xaa\x06\x0b\x90\xff\xff\xff\xff\xaa\xf4\xab\x10\xff\xff\xff\xff\xad\xc9\xc4\x10\xff\xff\xff\xff\xae\xa7@\x10\xff\xff\xff\xff\xaf\xa0k\x90\xff\xff\xff\xff\xb0\x87\x22\x10\xff\xff\xff\xff\xb1\x89\x88\x10\xff\xff\xff\xff\xb2p>\x90\xff\xff\xff\xff\xb3r\xa4\x90\xff\xff\xff\xff\xb4P \x90\xff\xff\xff\xff\xb72h\x90\xff\xff\xff\xff\xb8\x0f\xe4\x90\xff\xff\xff\xff\xb8\xff\xd5\x90\xff\xff\xff\xff\xb9\xef\xc6\x90\xff\xff\xff\xff\xbc\xc8\xd4\x10\xff\xff\xff\xff\xbd\xb8\xc5\x10\xff\xff\xff\xff\xbe\x9f{\x90\xff\xff\xff\xff\xbf\x98\xa7\x10\xff\xff\xff\xff\xc0\x9b\x0d\x10\xff\xff\xff\xff\xc1x\x89\x10\xff\xff\xff\xff\xc2hz\x10\xff\xff\xff\xff\xc3Xk\x10\xff\xff\xff\xff\xc4?!\x90\xff\xff\xff\xff\xc58M\x10\xff\xff\xff\xff\xc6:\xb3\x10\xff\xff\xff\xff\xc7X\xc8\x90\xff\xff\xff\xff\xc7\xd9\xfb\x90\xff\xff\xff\xff\xc9\x01K\x90\xff\xff\xff\xff\xc9\xf1<\x90\xff\xff\xff\xff\xca\xe2\x7f\x10\xff\xff\xff\xff\xcb\xb5o\x10\xff\xff\xff\xff\xcb\xec\xc0\x00\xff\xff\xff\xff\xcc\x80h\x00\xff\xff\xff\xff\xcc\xdc\xbf\x10\xff\xff\xff\xff\xcd\x95Q\x10\xff\xff\xff\xff\xcd\xc3g\x80\xff\xff\xff\xff\xcer\xbf\x00\xff\xff\xff\xff\xce\xc5\xdb\x90\xff\xff\xff\xff\xcfu3\x10\xff\xff\xff\xff\xcf\xac\x84\x00\xff\xff\xff\xff\xd0R\xa1\x00\xff\xff\xff\xff\xd0\xa5\xbd\x90\xff\xff\xff\xff\xd1U\x15\x10\xff\xff\xff\xff\xd1\x8cf\x00\xff\xff\xff\xff\xd22\x83\x00\xff\xff\xff\xff\xd2\x85\x9f\x90\xff\xff\xff\xff\xd3Y\xe1\x10\xff\xff\xff\xff\xd4I\xd2\x10\xff\xff\xff\xff\xd59\xed@\xff\xff\xff\xff\xd6)\xde@\xff\xff\xff\xff\xd7\x19\xcf@\xff\xff\xff\xff\xd8\x09\xc0@\xff\xff\xff\xff\xd8\xf9\xb1@\xff\xff\xff\xff\xd9\xe9\xa2@\xff\xff\xff\xff\xda\xd9\x93@\xff\xff\xff\xff\xdb\xc9\x84@\xff\xff\xff\xff\xdc\xb9u@\xff\xff\xff\xff\xdd\xb2\xa0\xc0\xff\xff\xff\xff\xde\xa2\x91\xc0\xff\xff\xff\xff\xdf\x92\x82\xc0\xff\xff\xff\xff\xe0\x82s\xc0\xff\xff\xff\xff\xe1rd\xc0\xff\xff\xff\xff\xe2bU\xc0\xff\xff\xff\xff\xe3RF\xc0\xff\xff\xff\xff\xe4B7\xc0\xff\xff\xff\xff\xe52(\xc0\xff\xff\xff\xff\xe6\x22\x19\xc0\xff\xff\xff\xff\xe7\x1bE@\xff\xff\xff\xff\xe8\x0b6@\xff\xff\xff\xff\xe8\xfb'@\xff\xff\xff\xff\xe9\xeb\x18@\xff\xff\xff\xff\xea\xdb\x09@\xff\xff\xff\xff\xeb\xca\xfa@\xff\xff\xff\xff\xec\xba\xeb@\xff\xff\xff\xff\xed\xaa\xdc@\xff\xff\xff\xff\xee\x9a\xcd@\xff\xff\xff\xff\xef\x8a\xbe@\xff\xff\xff\xff\xf0z\xaf@\xff\xff\xff\xff\xf1j\xa0@\xff\xff\xff\xff\xf2c\xcb\xc0\xff\xff\xff\xff\xf3S\xbc\xc0\xff\xff\xff\xff\xf4C\xad\xc0\xff\xff\xff\xff\xf53\x9e\xc0\xff\xff\xff\xff\xf6#\x8f\xc0\xff\xff\xff\xff\xf7\x13\x80\xc0\xff\xff\xff\xff\xf8\x03q\xc0\xff\xff\xff\xff\xf8\xf3b\xc0\x00\x00\x00\x00\x0d\x9b)\x10\x00\x00\x00\x00\x0e\x8b\x1a\x10\x00\x00\x00\x00\x0f\x84E\x90\x00\x00\x00\x00\x10t6\x90\x00\x00\x00\x00\x11d'\x90\x00\x00\x00\x00\x12T&\xa0\x00\x00\x00\x00\x13D\x09\x90\x00\x00\x00\x00\x144\x08\xa0\x00\x00\x00\x00\x15#\xf9\xa0\x00\x00\x00\x00\x16\x13\xea\xa0\x00\x00\x00\x00\x17\x03\xdb\xa0\x00\x00\x00\x00\x17\xf3\xcc\xa0\x00\x00\x00\x00\x18\xe3\xcb\xb0\x00\x00\x00\x00\x19\xd3\xae\xa0\x00\x00\x00\x00\x1a\xc3\x9f\xa0\x00\x00\x00\x00\x1b\xbc\xcb \x00\x00\x00\x00\x1c\xac\xbc \x00\x00\x00\x00\x1d\x9c\xad \x00\x00\x00\x00\x1e\x8c\x9e \x00\x00\x00\x00\x1f|\x8f \x00\x00\x00\x00 l\x80 \x00\x00\x00\x00!\x5cq \x00\x00\x00\x00\x22Lb \x00\x00\x00\x00#1<+00>,M3.5.0/0,M10.5.0/1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00l&\x04\x99\x00\x04\x00\x00\x00\x04\x00\x00\x10\x00\x00\x00Atlantic/BermudaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffi\x87\x18F\xff\xff\xff\xff\x9c\xcc\xaeF\xff\xff\xff\xff\x9d\xb7K6\xff\xff\xff\xff\x9e\xb8m\xc6\xff\xff\xff\xff\x9f\x84\xb86\xff\xff\xff\xff\xb4\xc3\x1d\xe6\xff\xff\xff\xff\xcbb\xa6\xe0\xff\xff\xff\xff\xcc\xd3\xbc\xd0\xff\xff\xff\xff\xcd\x9e\xd1\xe0\xff\xff\xff\xff\xce\xc6\x13\xd0\xff\xff\xff\xff\xcfuy`\xff\xff\xff\xff\xd0\xaf0P\xff\xff\xff\xff\xd1U[`\xff\xff\xff\xff\xd2\x8f\x12P\xff\xff\xff\xff\xd5qh`\xff\xff\xff\xff\xd6\x0e<\xd0\xff\xff\xff\xff\xd7Z\x84\xe0\xff\xff\xff\xff\xd7\xe4\xe4P\xff\xff\xff\xff\xd9:f\xe0\xff\xff\xff\xff\xd9\xc4\xc6P\xff\xff\xff\xff\xdb#\x83`\xff\xff\xff\xff\xdb\xa4\xa8P\xff\xff\xff\xff\xdd\x03e`\xff\xff\xff\xff\xdd\x84\x8aP\xff\xff\xff\xff\xde\xe3G`\xff\xff\xff\xff\xdfm\xa6\xd0\xff\xff\xff\xff\xe6l\x09\xe0\xff\xff\xff\xff\xe77\x02\xd0\x00\x00\x00\x00\x08 \xb3`\x00\x00\x00\x00\x09\x10\x96P\x00\x00\x00\x00\x0a\x00\x95`\x00\x00\x00\x00\x0a\xf0xP\x00\x00\x00\x00\x0b\xe0w`\x00\x00\x00\x00\x0c\xd9\x94\xd0\x00\x00\x00\x00\x0d\xc0Y`\x00\x00\x00\x00\x0e\xb9v\xd0\x00\x00\x00\x00\x0f\xa9u\xe0\x00\x00\x00\x00\x10\x99X\xd0\x00\x00\x00\x00\x11\x89W\xe0\x00\x00\x00\x00\x12y:\xd0\x00\x00\x00\x00\x13i9\xe0\x00\x00\x00\x00\x14Y\x1c\xd0\x00\x00\x00\x00\x15I\x1b\xe0\x00\x00\x00\x00\x168\xfe\xd0\x00\x00\x00\x00\x17(\xfd\xe0\x00\x00\x00\x00\x18\x22\x1bP\x00\x00\x00\x00\x19\x08\xdf\xe0\x00\x00\x00\x00\x1a\x01\xfdP\x00\x00\x00\x00\x1a\xf1\xfc`\x00\x00\x00\x00\x1b\xe1\xdfP\x00\x00\x00\x00\x1c\xd1\xde`\x00\x00\x00\x00\x1d\xc1\xc1P\x00\x00\x00\x00\x1e\xb1\xc0`\x00\x00\x00\x00\x1f\xa1\xa3P\x00\x00\x00\x00 u\xf2\xe0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22U\xd4\xe0\x00\x00\x00\x00#j\xa1\xd0\x00\x00\x00\x00$5\xb6\xe0\x00\x00\x00\x00%J\x83\xd0\x00\x00\x00\x00&\x15\x98\xe0\x00\x00\x00\x00'*e\xd0\x00\x00\x00\x00'\xfe\xb5`\x00\x00\x00\x00)\x0aG\xd0\x00\x00\x00\x00)\xde\x97`\x00\x00\x00\x00*\xea)\xd0\x00\x00\x00\x00+\xbey`\x00\x00\x00\x00,\xd3FP\x00\x00\x00\x00-\x9e[`\x00\x00\x00\x00.\xb3(P\x00\x00\x00\x00/~=`\x00\x00\x00\x000\x93\x0aP\x00\x00\x00\x001gY\xe0\x00\x00\x00\x002r\xecP\x00\x00\x00\x003G;\xe0\x00\x00\x00\x004R\xceP\x00\x00\x00\x005'\x1d\xe0\x00\x00\x00\x0062\xb0P\x00\x00\x00\x007\x06\xff\xe0\x00\x00\x00\x008\x1b\xcc\xd0\x00\x00\x00\x008\xe6\xe1\xe0\x00\x00\x00\x009\xfb\xae\xd0\x00\x00\x00\x00:\xc6\xc3\xe0\x00\x00\x00\x00;\xdb\x90\xd0\x00\x00\x00\x00<\xaf\xe0`\x00\x00\x00\x00=\xbbr\xd0\x00\x00\x00\x00>\x8f\xc2`\x00\x00\x00\x00?\x9bT\xd0\x00\x00\x00\x00@o\xa4`\x00\x00\x00\x00A\x84qP\x00\x00\x00\x00BO\x86`\x00\x00\x00\x00CdSP\x00\x00\x00\x00D/h`\x00\x00\x00\x00ED5P\x00\x00\x00\x00E\xf3\x9a\xe0\x02\x01\x02\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\xff\xff\xc3:\x00\x00\xff\xff\xd1J\x01\x04\xff\xff\xc3:\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xc7\xc0\x00\x10LMT\x00BST\x00BMT\x00ADT\x00AST\x00\x0aAST4ADT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf|7\xb3\xde\x01\x00\x00\xde\x01\x00\x00\x0f\x00\x00\x00Atlantic/CanaryTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xa6\x04\x5c\xf0\xff\xff\xff\xff\xd4A\xf7 \x00\x00\x00\x00\x13M6\x00\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\x0e\xbdm\xb9\x01\x00\x00\xb9\x01\x00\x00\x0f\x00\x00\x00Atlantic/FaeroeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xff\x8bm\xa4X\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x12\x00\x00\x00Atlantic/St_HelenaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7\xcf^\xb0\x15\x03\x00\x00\x15\x03\x00\x00\x10\x00\x00\x00Atlantic/StanleyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffi\x87\x11\xbc\xff\xff\xff\xff\x93D_<\xff\xff\xff\xff\xc3OZ\xc0\xff\xff\xff\xff\xc46\x030\xff\xff\xff\xff\xc5/<\xc0\xff\xff\xff\xff\xc6\x15\xe50\xff\xff\xff\xff\xc7\x18Y@\xff\xff\xff\xff\xc7\xff\x01\xb0\xff\xff\xff\xff\xc8\xf8;@\xff\xff\xff\xff\xc9\xde\xe3\xb0\xff\xff\xff\xff\xca\xd8\x1d@\xff\xff\xff\xff\xcb\xbe\xc5\xb0\xff\xff\xff\xff\xcc\xb7\xff@\xff\xff\xff\xff\xcd6\x810\x00\x00\x00\x00\x19\x11\xfe@\x00\x00\x00\x00\x19\xd3\xbc\xb0\x00\x00\x00\x00\x1a\xf1\xc4 \x00\x00\x00\x00\x1b\xaad0\x00\x00\x00\x00\x1c\xd1\xa6 \x00\x00\x00\x00\x1d\x8aF0\x00\x00\x00\x00\x1e\xa8[\xb0\x00\x00\x00\x00\x1fj6@\x00\x00\x00\x00 \x88=\xb0\x00\x00\x00\x00!J\x18@\x00\x00\x00\x00\x22h\x1f\xb0\x00\x00\x00\x00#)\xfa@\x00\x00\x00\x00$H\x01\xb0\x00\x00\x00\x00%\x09\xdc@\x00\x00\x00\x00&1\x1e0\x00\x00\x00\x00&\xe9\xbe@\x00\x00\x00\x00(\x11\x000\x00\x00\x00\x00(\xd2\xda\xc0\x00\x00\x00\x00)\xf0\xe20\x00\x00\x00\x00*\xb2\xbc\xc0\x00\x00\x00\x00+\xd0\xc40\x00\x00\x00\x00,\x92\x9e\xc0\x00\x00\x00\x00-\xb0\xa60\x00\x00\x00\x00.r\x80\xc0\x00\x00\x00\x00/\x90\x880\x00\x00\x00\x000Rb\xc0\x00\x00\x00\x001y\xa4\xb0\x00\x00\x00\x002;\x7f@\x00\x00\x00\x003Y\x86\xb0\x00\x00\x00\x004\x1ba@\x00\x00\x00\x0059h\xb0\x00\x00\x00\x005\xfbC@\x00\x00\x00\x007\x19J\xb0\x00\x00\x00\x007\xdb%@\x00\x00\x00\x008\xf9,\xb0\x00\x00\x00\x009\xbb\x07@\x00\x00\x00\x00:\xd9*\xd0\x00\x00\x00\x00;\x91\xca\xe0\x00\x00\x00\x00<\xc2GP\x00\x00\x00\x00=q\xac\xe0\x00\x00\x00\x00>\xa2)P\x00\x00\x00\x00?Z\xc9`\x00\x00\x00\x00@\x82\x0bP\x00\x00\x00\x00A:\xab`\x00\x00\x00\x00Ba\xedP\x00\x00\x00\x00C\x1a\x8d`\x00\x00\x00\x00DA\xcfP\x00\x00\x00\x00D\xfao`\x00\x00\x00\x00F!\xb1P\x00\x00\x00\x00F\xdaQ`\x00\x00\x00\x00H\x0a\xcd\xd0\x00\x00\x00\x00H\xc3m\xe0\x00\x00\x00\x00I\xea\xaf\xd0\x00\x00\x00\x00J\xa3O\xe0\x00\x00\x00\x00K\xca\x91\xd0\x00\x00\x00\x00L\x831\xe0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x04\x05\x04\x05\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\xff\xff\xc9\xc4\x00\x00\xff\xff\xc9\xc4\x00\x04\xff\xff\xd5\xd0\x01\x08\xff\xff\xc7\xc0\x00\x0c\xff\xff\xe3\xe0\x01\x10\xff\xff\xd5\xd0\x00\x08LMT\x00SMT\x00-03\x00-04\x00-02\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x0d\x00\x00\x00Australia/ACTTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x7f<\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x0c\x89\x80\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xc7\x81\x80\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1ey\x9c\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00%\xef\xea\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x00\x00\x00\x00*\xe9s\x00\x00\x00\x00\x00+\x98\xca\x80\x00\x00\x00\x00,\xd2\x8f\x80\x00\x00\x00\x00-x\xac\x80\x00\x00\x00\x00.\xb2q\x80\x00\x00\x00\x00/X\x8e\x80\x00\x00\x00\x000\x92S\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002r5\x80\x00\x00\x00\x003=<\x80\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xf7\xa2\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x8d\xc4\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8ff~\xd5\x99\x03\x00\x00\x99\x03\x00\x00\x12\x00\x00\x00Australia/AdelaideTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x04\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x8b\x14\xff\xff\xff\xff{\x12\x03p\xff\xff\xff\xff\x9cN\xc9\x88\xff\xff\xff\xff\x9c\xbc6\x08\xff\xff\xff\xff\xcbT\xba\x08\xff\xff\xff\xff\xcb\xc7l\x88\xff\xff\xff\xff\xcc\xb7]\x88\xff\xff\xff\xff\xcd\xa7N\x88\xff\xff\xff\xff\xce\xa0z\x08\xff\xff\xff\xff\xcf\x870\x88\x00\x00\x00\x00\x03p@\x88\x00\x00\x00\x00\x04\x0d#\x08\x00\x00\x00\x00\x05P\x22\x88\x00\x00\x00\x00\x05\xf6?\x88\x00\x00\x00\x00\x070\x04\x88\x00\x00\x00\x00\x07\xd6!\x88\x00\x00\x00\x00\x09\x0f\xe6\x88\x00\x00\x00\x00\x09\xb6\x03\x88\x00\x00\x00\x00\x0a\xef\xc8\x88\x00\x00\x00\x00\x0b\x9f \x08\x00\x00\x00\x00\x0c\xd8\xe5\x08\x00\x00\x00\x00\x0d\x7f\x02\x08\x00\x00\x00\x00\x0e\xb8\xc7\x08\x00\x00\x00\x00\x0f^\xe4\x08\x00\x00\x00\x00\x10\x98\xa9\x08\x00\x00\x00\x00\x11>\xc6\x08\x00\x00\x00\x00\x12x\x8b\x08\x00\x00\x00\x00\x13\x1e\xa8\x08\x00\x00\x00\x00\x14Xm\x08\x00\x00\x00\x00\x14\xfe\x8a\x08\x00\x00\x00\x00\x168O\x08\x00\x00\x00\x00\x16\xe7\xa6\x88\x00\x00\x00\x00\x18!k\x88\x00\x00\x00\x00\x18\xc7\x88\x88\x00\x00\x00\x00\x1a\x01M\x88\x00\x00\x00\x00\x1a\xa7j\x88\x00\x00\x00\x00\x1b\xe1/\x88\x00\x00\x00\x00\x1c\x87L\x88\x00\x00\x00\x00\x1d\xc1\x11\x88\x00\x00\x00\x00\x1ey\xa3\x88\x00\x00\x00\x00\x1f\x97\xb9\x08\x00\x00\x00\x00 Y\x85\x88\x00\x00\x00\x00!\x80\xd5\x88\x00\x00\x00\x00\x22B\xa2\x08\x00\x00\x00\x00#i\xf2\x08\x00\x00\x00\x00$\x22\x84\x08\x00\x00\x00\x00%I\xd4\x08\x00\x00\x00\x00&\x02f\x08\x00\x00\x00\x00')\xb6\x08\x00\x00\x00\x00'\xcf\xd3\x08\x00\x00\x00\x00)\x09\x98\x08\x00\x00\x00\x00)\xcbd\x88\x00\x00\x00\x00*\xe9z\x08\x00\x00\x00\x00+\x98\xd1\x88\x00\x00\x00\x00,\xd2\x96\x88\x00\x00\x00\x00-\x8b(\x88\x00\x00\x00\x00.\xb2x\x88\x00\x00\x00\x00/tE\x08\x00\x00\x00\x000\x92Z\x88\x00\x00\x00\x001]a\x88\x00\x00\x00\x002r<\x88\x00\x00\x00\x003=C\x88\x00\x00\x00\x004R\x1e\x88\x00\x00\x00\x005\x1d%\x88\x00\x00\x00\x0062\x00\x88\x00\x00\x00\x006\xfd\x07\x88\x00\x00\x00\x008\x1b\x1d\x08\x00\x00\x00\x008\xdc\xe9\x88\x00\x00\x00\x009\xfa\xff\x08\x00\x00\x00\x00:\xbc\xcb\x88\x00\x00\x00\x00;\xda\xe1\x08\x00\x00\x00\x00<\xa5\xe8\x08\x00\x00\x00\x00=\xba\xc3\x08\x00\x00\x00\x00>\x85\xca\x08\x00\x00\x00\x00?\x9a\xa5\x08\x00\x00\x00\x00@e\xac\x08\x00\x00\x00\x00A\x83\xc1\x88\x00\x00\x00\x00BE\x8e\x08\x00\x00\x00\x00Cc\xa3\x88\x00\x00\x00\x00D.\xaa\x88\x00\x00\x00\x00EC\x85\x88\x00\x00\x00\x00F\x05R\x08\x00\x00\x00\x00G#g\x88\x00\x00\x00\x00G\xf7\xa9\x08\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00\x81\xec\x00\x00\x00\x00~\x90\x00\x04\x00\x00\x93\xa8\x01\x09\x00\x00\x85\x98\x00\x04LMT\x00ACST\x00ACDT\x00\x0aACST-9:30ACDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\xba\xde\xd3!\x01\x00\x00!\x01\x00\x00\x12\x00\x00\x00Australia/BrisbaneTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffr\xed\x9f\x08\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00%\xef\xea\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x8fx\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbd\xca#\x7f\xad\x03\x00\x00\xad\x03\x00\x00\x15\x00\x00\x00Australia/Broken_HillTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x00\x00\x00\x05\x00\x00\x00\x13\xff\xff\xff\xffs\x16\x88d\xff\xff\xff\xffv\x04\xa5\xe0\xff\xff\xff\xff{\x12\x03p\xff\xff\xff\xff\x9cN\xc9\x88\xff\xff\xff\xff\x9c\xbc6\x08\xff\xff\xff\xff\xcbT\xba\x08\xff\xff\xff\xff\xcb\xc7l\x88\xff\xff\xff\xff\xcc\xb7]\x88\xff\xff\xff\xff\xcd\xa7N\x88\xff\xff\xff\xff\xce\xa0z\x08\xff\xff\xff\xff\xcf\x870\x88\x00\x00\x00\x00\x03p@\x88\x00\x00\x00\x00\x04\x0d#\x08\x00\x00\x00\x00\x05P\x22\x88\x00\x00\x00\x00\x05\xf6?\x88\x00\x00\x00\x00\x070\x04\x88\x00\x00\x00\x00\x07\xd6!\x88\x00\x00\x00\x00\x09\x0f\xe6\x88\x00\x00\x00\x00\x09\xb6\x03\x88\x00\x00\x00\x00\x0a\xef\xc8\x88\x00\x00\x00\x00\x0b\x9f \x08\x00\x00\x00\x00\x0c\xd8\xe5\x08\x00\x00\x00\x00\x0d\x7f\x02\x08\x00\x00\x00\x00\x0e\xb8\xc7\x08\x00\x00\x00\x00\x0f^\xe4\x08\x00\x00\x00\x00\x10\x98\xa9\x08\x00\x00\x00\x00\x11>\xc6\x08\x00\x00\x00\x00\x12x\x8b\x08\x00\x00\x00\x00\x13\x1e\xa8\x08\x00\x00\x00\x00\x14Xm\x08\x00\x00\x00\x00\x14\xfe\x8a\x08\x00\x00\x00\x00\x168O\x08\x00\x00\x00\x00\x17\x0c\x90\x88\x00\x00\x00\x00\x18!k\x88\x00\x00\x00\x00\x18\xc7\x88\x88\x00\x00\x00\x00\x1a\x01M\x88\x00\x00\x00\x00\x1a\xa7j\x88\x00\x00\x00\x00\x1b\xe1/\x88\x00\x00\x00\x00\x1c\x87L\x88\x00\x00\x00\x00\x1d\xc1\x11\x88\x00\x00\x00\x00\x1ey\xa3\x88\x00\x00\x00\x00\x1f\x97\xb9\x08\x00\x00\x00\x00 Y\x85\x88\x00\x00\x00\x00!\x80\xd5\x88\x00\x00\x00\x00\x22B\xa2\x08\x00\x00\x00\x00#i\xf2\x08\x00\x00\x00\x00$\x22\x84\x08\x00\x00\x00\x00%I\xd4\x08\x00\x00\x00\x00%\xef\xf1\x08\x00\x00\x00\x00')\xb6\x08\x00\x00\x00\x00'\xcf\xd3\x08\x00\x00\x00\x00)\x09\x98\x08\x00\x00\x00\x00)\xaf\xb5\x08\x00\x00\x00\x00*\xe9z\x08\x00\x00\x00\x00+\x98\xd1\x88\x00\x00\x00\x00,\xd2\x96\x88\x00\x00\x00\x00-x\xb3\x88\x00\x00\x00\x00.\xb2x\x88\x00\x00\x00\x00/X\x95\x88\x00\x00\x00\x000\x92Z\x88\x00\x00\x00\x001]a\x88\x00\x00\x00\x002r<\x88\x00\x00\x00\x003=C\x88\x00\x00\x00\x004R\x1e\x88\x00\x00\x00\x005\x1d%\x88\x00\x00\x00\x0062\x00\x88\x00\x00\x00\x006\xfd\x07\x88\x00\x00\x00\x008\x1b\x1d\x08\x00\x00\x00\x008\xdc\xe9\x88\x00\x00\x00\x009\xfa\xff\x08\x00\x00\x00\x00:\xbc\xcb\x88\x00\x00\x00\x00;\xda\xe1\x08\x00\x00\x00\x00<\xa5\xe8\x08\x00\x00\x00\x00=\xba\xc3\x08\x00\x00\x00\x00>\x85\xca\x08\x00\x00\x00\x00?\x9a\xa5\x08\x00\x00\x00\x00@e\xac\x08\x00\x00\x00\x00A\x83\xc1\x88\x00\x00\x00\x00BE\x8e\x08\x00\x00\x00\x00Cc\xa3\x88\x00\x00\x00\x00D.\xaa\x88\x00\x00\x00\x00EC\x85\x88\x00\x00\x00\x00F\x05R\x08\x00\x00\x00\x00G#g\x88\x00\x00\x00\x00G\xf7\xa9\x08\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x00\x00\x84\x9c\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00~\x90\x00\x09\x00\x00\x93\xa8\x01\x0e\x00\x00\x85\x98\x00\x09LMT\x00AEST\x00ACST\x00ACDT\x00\x0aACST-9:30ACDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x12\x00\x00\x00Australia/CanberraTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x7f<\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x0c\x89\x80\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xc7\x81\x80\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1ey\x9c\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00%\xef\xea\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x00\x00\x00\x00*\xe9s\x00\x00\x00\x00\x00+\x98\xca\x80\x00\x00\x00\x00,\xd2\x8f\x80\x00\x00\x00\x00-x\xac\x80\x00\x00\x00\x00.\xb2q\x80\x00\x00\x00\x00/X\x8e\x80\x00\x00\x00\x000\x92S\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002r5\x80\x00\x00\x00\x003=<\x80\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xf7\xa2\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x8d\xc4\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\xf2\xe6Z\xeb\x03\x00\x00\xeb\x03\x00\x00\x10\x00\x00\x00Australia/CurrieTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xfft.\x00\xe4\xff\xff\xff\xff\x9b\xd5x\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\x9d\xdaD\x80\xff\xff\xff\xff\x9e\x80a\x80\xff\xff\xff\xff\x9f\xba&\x80\xff\xff\xff\xff\xa0`C\x80\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\xff\xff\xff\xff\xfb\xc2\x8d\x00\xff\xff\xff\xff\xfc\xb2~\x00\xff\xff\xff\xff\xfd\xc7Y\x00\xff\xff\xff\xff\xfev\xb0\x80\xff\xff\xff\xff\xff\xa7;\x00\x00\x00\x00\x00\x00V\x92\x80\x00\x00\x00\x00\x01\x87\x1d\x00\x00\x00\x00\x00\x02?\xaf\x00\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x03O\x00\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xe31\x00\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1eg'\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00&\x02_\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xf4\xb6\x00\x00\x00\x00\x00(\xed\xe1\x80\x00\x00\x00\x00)\xd4\x98\x00\x00\x00\x00\x00*\xcd\xc3\x80\x00\x00\x00\x00+\xb4z\x00\x00\x00\x00\x00,\xad\xa5\x80\x00\x00\x00\x00-\x94\x5c\x00\x00\x00\x00\x00.\x8d\x87\x80\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000mi\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002V\x86\x00\x00\x00\x00\x003=<\x80\x00\x00\x00\x0046h\x00\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x006\x16J\x00\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x007\xf6,\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xbf*\x80\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\x9f\x0c\x80\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?~\xee\x80\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A^\xd0\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00C>\xb2\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00E\x1e\x94\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G\x07\xb1\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\x8a\x1c\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8R\x1a\x1b\xea\x00\x00\x00\xea\x00\x00\x00\x10\x00\x00\x00Australia/DarwinTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x04\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x92X\xff\xff\xff\xff{\x12\x03p\xff\xff\xff\xff\x9cN\xc9\x88\xff\xff\xff\xff\x9c\xbc6\x08\xff\xff\xff\xff\xcbT\xba\x08\xff\xff\xff\xff\xcb\xc7l\x88\xff\xff\xff\xff\xcc\xb7]\x88\xff\xff\xff\xff\xcd\xa7N\x88\xff\xff\xff\xff\xce\xa0z\x08\xff\xff\xff\xff\xcf\x870\x88\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00z\xa8\x00\x00\x00\x00~\x90\x00\x04\x00\x00\x93\xa8\x01\x09\x00\x00\x85\x98\x00\x04LMT\x00ACST\x00ACDT\x00\x0aACST-9:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa2\xdc\xba\xca:\x01\x00\x00:\x01\x00\x00\x0f\x00\x00\x00Australia/EuclaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x03\x00\x00\x00\x10\xff\xff\xff\xfft\xa6\x0a\xb0\xff\xff\xff\xff\x9cN\xd4\x14\xff\xff\xff\xff\x9c\xbc@\x94\xff\xff\xff\xff\xcbT\xc4\x94\xff\xff\xff\xff\xcb\xc7w\x14\xff\xff\xff\xff\xcc\xb7h\x14\xff\xff\xff\xff\xcd\xa7Y\x14\x00\x00\x00\x00\x09\x0f\xf1\x14\x00\x00\x00\x00\x09\xb6\x0e\x14\x00\x00\x00\x00\x1a\x01X\x14\x00\x00\x00\x00\x1a\xa7u\x14\x00\x00\x00\x00)%R\x14\x00\x00\x00\x00)\xaf\xbf\x94\x00\x00\x00\x00Eq\xb4\x94\x00\x00\x00\x00F\x05\x5c\x94\x00\x00\x00\x00G#r\x14\x00\x00\x00\x00G\xeey\x14\x00\x00\x00\x00I\x03T\x14\x00\x00\x00\x00I\xce[\x14\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00x\xd0\x00\x00\x00\x00\x89\x1c\x01\x04\x00\x00{\x0c\x00\x0aLMT\x00+0945\x00+0845\x00\x0a<+0845>-8:45\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\xf2\xe6Z\xeb\x03\x00\x00\xeb\x03\x00\x00\x10\x00\x00\x00Australia/HobartTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xfft.\x00\xe4\xff\xff\xff\xff\x9b\xd5x\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\x9d\xdaD\x80\xff\xff\xff\xff\x9e\x80a\x80\xff\xff\xff\xff\x9f\xba&\x80\xff\xff\xff\xff\xa0`C\x80\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\xff\xff\xff\xff\xfb\xc2\x8d\x00\xff\xff\xff\xff\xfc\xb2~\x00\xff\xff\xff\xff\xfd\xc7Y\x00\xff\xff\xff\xff\xfev\xb0\x80\xff\xff\xff\xff\xff\xa7;\x00\x00\x00\x00\x00\x00V\x92\x80\x00\x00\x00\x00\x01\x87\x1d\x00\x00\x00\x00\x00\x02?\xaf\x00\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x03O\x00\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xe31\x00\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1eg'\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00&\x02_\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xf4\xb6\x00\x00\x00\x00\x00(\xed\xe1\x80\x00\x00\x00\x00)\xd4\x98\x00\x00\x00\x00\x00*\xcd\xc3\x80\x00\x00\x00\x00+\xb4z\x00\x00\x00\x00\x00,\xad\xa5\x80\x00\x00\x00\x00-\x94\x5c\x00\x00\x00\x00\x00.\x8d\x87\x80\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000mi\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002V\x86\x00\x00\x00\x00\x003=<\x80\x00\x00\x00\x0046h\x00\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x006\x16J\x00\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x007\xf6,\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xbf*\x80\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\x9f\x0c\x80\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?~\xee\x80\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A^\xd0\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00C>\xb2\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00E\x1e\x94\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G\x07\xb1\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\x8a\x1c\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o3\xdaR\xb4\x02\x00\x00\xb4\x02\x00\x00\x0d\x00\x00\x00Australia/LHITZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x05\x00\x00\x00\x19\xff\xff\xff\xffs\x16w\xdc\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168@\xf8\x00\x00\x00\x00\x16\xe7\x8ah\x00\x00\x00\x00\x18!]x\x00\x00\x00\x00\x18\xc7lh\x00\x00\x00\x00\x1a\x01?x\x00\x00\x00\x00\x1a\xa7Nh\x00\x00\x00\x00\x1b\xe1!x\x00\x00\x00\x00\x1c\x870h\x00\x00\x00\x00\x1d\xc1\x03x\x00\x00\x00\x00\x1ey\x8ep\x00\x00\x00\x00\x1f\x97\xaa\xf8\x00\x00\x00\x00 Ypp\x00\x00\x00\x00!\x80\xc7x\x00\x00\x00\x00\x22B\x8c\xf0\x00\x00\x00\x00#i\xe3\xf8\x00\x00\x00\x00$\x22n\xf0\x00\x00\x00\x00%I\xc5\xf8\x00\x00\x00\x00%\xef\xdb\xf0\x00\x00\x00\x00')\xa7\xf8\x00\x00\x00\x00'\xcf\xbd\xf0\x00\x00\x00\x00)\x09\x89\xf8\x00\x00\x00\x00)\xaf\x9f\xf0\x00\x00\x00\x00*\xe9k\xf8\x00\x00\x00\x00+\x98\xbcp\x00\x00\x00\x00,\xd2\x88x\x00\x00\x00\x00-x\x9ep\x00\x00\x00\x00.\xb2jx\x00\x00\x00\x00/X\x80p\x00\x00\x00\x000\x92Lx\x00\x00\x00\x001]Lp\x00\x00\x00\x002r.x\x00\x00\x00\x003=.p\x00\x00\x00\x004R\x10x\x00\x00\x00\x005\x1d\x10p\x00\x00\x00\x0061\xf2x\x00\x00\x00\x006\xfc\xf2p\x00\x00\x00\x008\x1b\x0e\xf8\x00\x00\x00\x008\xdc\xd4p\x00\x00\x00\x009\xa7\xe2x\x00\x00\x00\x00:\xbc\xb6p\x00\x00\x00\x00;\xda\xd2\xf8\x00\x00\x00\x00<\xa5\xd2\xf0\x00\x00\x00\x00=\xba\xb4\xf8\x00\x00\x00\x00>\x85\xb4\xf0\x00\x00\x00\x00?\x9a\x96\xf8\x00\x00\x00\x00@e\x96\xf0\x00\x00\x00\x00A\x83\xb3x\x00\x00\x00\x00BEx\xf0\x00\x00\x00\x00Cc\x95x\x00\x00\x00\x00D.\x95p\x00\x00\x00\x00ECwx\x00\x00\x00\x00F\x05<\xf0\x00\x00\x00\x00G#Yx\x00\x00\x00\x00G\xf7\x93\xf0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x00\x00\x95$\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00\xa1\xb8\x01\x09\x00\x00\x93\xa8\x00\x0f\x00\x00\x9a\xb0\x01\x15LMT\x00AEST\x00+1130\x00+1030\x00+11\x00\x0a<+1030>-10:30<+11>-11,M10.1.0,M4.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x95\xbd\x12E\x01\x00\x00E\x01\x00\x00\x12\x00\x00\x00Australia/LindemanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffr\xed\xa2\xd4\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00%\xef\xea\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x00\x00\x00\x00*\xe9s\x00\x00\x00\x00\x00+\x98\xca\x80\x00\x00\x00\x00,\xd2\x8f\x80\x00\x00\x00\x00-x\xac\x80\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x8b\xac\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o3\xdaR\xb4\x02\x00\x00\xb4\x02\x00\x00\x13\x00\x00\x00Australia/Lord_HoweTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008\x00\x00\x00\x05\x00\x00\x00\x19\xff\xff\xff\xffs\x16w\xdc\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168@\xf8\x00\x00\x00\x00\x16\xe7\x8ah\x00\x00\x00\x00\x18!]x\x00\x00\x00\x00\x18\xc7lh\x00\x00\x00\x00\x1a\x01?x\x00\x00\x00\x00\x1a\xa7Nh\x00\x00\x00\x00\x1b\xe1!x\x00\x00\x00\x00\x1c\x870h\x00\x00\x00\x00\x1d\xc1\x03x\x00\x00\x00\x00\x1ey\x8ep\x00\x00\x00\x00\x1f\x97\xaa\xf8\x00\x00\x00\x00 Ypp\x00\x00\x00\x00!\x80\xc7x\x00\x00\x00\x00\x22B\x8c\xf0\x00\x00\x00\x00#i\xe3\xf8\x00\x00\x00\x00$\x22n\xf0\x00\x00\x00\x00%I\xc5\xf8\x00\x00\x00\x00%\xef\xdb\xf0\x00\x00\x00\x00')\xa7\xf8\x00\x00\x00\x00'\xcf\xbd\xf0\x00\x00\x00\x00)\x09\x89\xf8\x00\x00\x00\x00)\xaf\x9f\xf0\x00\x00\x00\x00*\xe9k\xf8\x00\x00\x00\x00+\x98\xbcp\x00\x00\x00\x00,\xd2\x88x\x00\x00\x00\x00-x\x9ep\x00\x00\x00\x00.\xb2jx\x00\x00\x00\x00/X\x80p\x00\x00\x00\x000\x92Lx\x00\x00\x00\x001]Lp\x00\x00\x00\x002r.x\x00\x00\x00\x003=.p\x00\x00\x00\x004R\x10x\x00\x00\x00\x005\x1d\x10p\x00\x00\x00\x0061\xf2x\x00\x00\x00\x006\xfc\xf2p\x00\x00\x00\x008\x1b\x0e\xf8\x00\x00\x00\x008\xdc\xd4p\x00\x00\x00\x009\xa7\xe2x\x00\x00\x00\x00:\xbc\xb6p\x00\x00\x00\x00;\xda\xd2\xf8\x00\x00\x00\x00<\xa5\xd2\xf0\x00\x00\x00\x00=\xba\xb4\xf8\x00\x00\x00\x00>\x85\xb4\xf0\x00\x00\x00\x00?\x9a\x96\xf8\x00\x00\x00\x00@e\x96\xf0\x00\x00\x00\x00A\x83\xb3x\x00\x00\x00\x00BEx\xf0\x00\x00\x00\x00Cc\x95x\x00\x00\x00\x00D.\x95p\x00\x00\x00\x00ECwx\x00\x00\x00\x00F\x05<\xf0\x00\x00\x00\x00G#Yx\x00\x00\x00\x00G\xf7\x93\xf0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x00\x00\x95$\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00\xa1\xb8\x01\x09\x00\x00\x93\xa8\x00\x0f\x00\x00\x9a\xb0\x01\x15LMT\x00AEST\x00+1130\x00+1030\x00+11\x00\x0a<+1030>-10:30<+11>-11,M10.1.0,M4.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xe1\xc1\xa9\x88\x03\x00\x00\x88\x03\x00\x00\x13\x00\x00\x00Australia/MelbourneTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x85\x18\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x16\xe7\x9f\x80\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xc7\x81\x80\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1ey\x9c\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!w\x94\x00\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00&\x02_\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x00\x00\x00\x00*\xe9s\x00\x00\x00\x00\x00+\x98\xca\x80\x00\x00\x00\x00,\xd2\x8f\x80\x00\x00\x00\x00-x\xac\x80\x00\x00\x00\x00.\xb2q\x80\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000\x92S\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002r5\x80\x00\x00\x00\x003=<\x80\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xf7\xa2\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x87\xe8\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x0d\x00\x00\x00Australia/NSWTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x7f<\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x0c\x89\x80\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xc7\x81\x80\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1ey\x9c\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00%\xef\xea\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x00\x00\x00\x00*\xe9s\x00\x00\x00\x00\x00+\x98\xca\x80\x00\x00\x00\x00,\xd2\x8f\x80\x00\x00\x00\x00-x\xac\x80\x00\x00\x00\x00.\xb2q\x80\x00\x00\x00\x00/X\x8e\x80\x00\x00\x00\x000\x92S\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002r5\x80\x00\x00\x00\x003=<\x80\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xf7\xa2\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x8d\xc4\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8R\x1a\x1b\xea\x00\x00\x00\xea\x00\x00\x00\x0f\x00\x00\x00Australia/NorthTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x04\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x92X\xff\xff\xff\xff{\x12\x03p\xff\xff\xff\xff\x9cN\xc9\x88\xff\xff\xff\xff\x9c\xbc6\x08\xff\xff\xff\xff\xcbT\xba\x08\xff\xff\xff\xff\xcb\xc7l\x88\xff\xff\xff\xff\xcc\xb7]\x88\xff\xff\xff\xff\xcd\xa7N\x88\xff\xff\xff\xff\xce\xa0z\x08\xff\xff\xff\xff\xcf\x870\x88\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00z\xa8\x00\x00\x00\x00~\x90\x00\x04\x00\x00\x93\xa8\x01\x09\x00\x00\x85\x98\x00\x04LMT\x00ACST\x00ACDT\x00\x0aACST-9:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xbb\xca\x1a2\x01\x00\x002\x01\x00\x00\x0f\x00\x00\x00Australia/PerthTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xfft\xa6\x16\xe4\xff\xff\xff\xff\x9cN\xde\xa0\xff\xff\xff\xff\x9c\xbcK \xff\xff\xff\xff\xcbT\xcf \xff\xff\xff\xff\xcb\xc7\x81\xa0\xff\xff\xff\xff\xcc\xb7r\xa0\xff\xff\xff\xff\xcd\xa7c\xa0\x00\x00\x00\x00\x09\x0f\xfb\xa0\x00\x00\x00\x00\x09\xb6\x18\xa0\x00\x00\x00\x00\x1a\x01b\xa0\x00\x00\x00\x00\x1a\xa7\x7f\xa0\x00\x00\x00\x00)%\x5c\xa0\x00\x00\x00\x00)\xaf\xca \x00\x00\x00\x00Eq\xbf \x00\x00\x00\x00F\x05g \x00\x00\x00\x00G#|\xa0\x00\x00\x00\x00G\xee\x83\xa0\x00\x00\x00\x00I\x03^\xa0\x00\x00\x00\x00I\xcee\xa0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00l\x9c\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x09LMT\x00AWDT\x00AWST\x00\x0aAWST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\xba\xde\xd3!\x01\x00\x00!\x01\x00\x00\x14\x00\x00\x00Australia/QueenslandTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffr\xed\x9f\x08\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00%\xef\xea\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x8fx\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8ff~\xd5\x99\x03\x00\x00\x99\x03\x00\x00\x0f\x00\x00\x00Australia/SouthTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x04\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x8b\x14\xff\xff\xff\xff{\x12\x03p\xff\xff\xff\xff\x9cN\xc9\x88\xff\xff\xff\xff\x9c\xbc6\x08\xff\xff\xff\xff\xcbT\xba\x08\xff\xff\xff\xff\xcb\xc7l\x88\xff\xff\xff\xff\xcc\xb7]\x88\xff\xff\xff\xff\xcd\xa7N\x88\xff\xff\xff\xff\xce\xa0z\x08\xff\xff\xff\xff\xcf\x870\x88\x00\x00\x00\x00\x03p@\x88\x00\x00\x00\x00\x04\x0d#\x08\x00\x00\x00\x00\x05P\x22\x88\x00\x00\x00\x00\x05\xf6?\x88\x00\x00\x00\x00\x070\x04\x88\x00\x00\x00\x00\x07\xd6!\x88\x00\x00\x00\x00\x09\x0f\xe6\x88\x00\x00\x00\x00\x09\xb6\x03\x88\x00\x00\x00\x00\x0a\xef\xc8\x88\x00\x00\x00\x00\x0b\x9f \x08\x00\x00\x00\x00\x0c\xd8\xe5\x08\x00\x00\x00\x00\x0d\x7f\x02\x08\x00\x00\x00\x00\x0e\xb8\xc7\x08\x00\x00\x00\x00\x0f^\xe4\x08\x00\x00\x00\x00\x10\x98\xa9\x08\x00\x00\x00\x00\x11>\xc6\x08\x00\x00\x00\x00\x12x\x8b\x08\x00\x00\x00\x00\x13\x1e\xa8\x08\x00\x00\x00\x00\x14Xm\x08\x00\x00\x00\x00\x14\xfe\x8a\x08\x00\x00\x00\x00\x168O\x08\x00\x00\x00\x00\x16\xe7\xa6\x88\x00\x00\x00\x00\x18!k\x88\x00\x00\x00\x00\x18\xc7\x88\x88\x00\x00\x00\x00\x1a\x01M\x88\x00\x00\x00\x00\x1a\xa7j\x88\x00\x00\x00\x00\x1b\xe1/\x88\x00\x00\x00\x00\x1c\x87L\x88\x00\x00\x00\x00\x1d\xc1\x11\x88\x00\x00\x00\x00\x1ey\xa3\x88\x00\x00\x00\x00\x1f\x97\xb9\x08\x00\x00\x00\x00 Y\x85\x88\x00\x00\x00\x00!\x80\xd5\x88\x00\x00\x00\x00\x22B\xa2\x08\x00\x00\x00\x00#i\xf2\x08\x00\x00\x00\x00$\x22\x84\x08\x00\x00\x00\x00%I\xd4\x08\x00\x00\x00\x00&\x02f\x08\x00\x00\x00\x00')\xb6\x08\x00\x00\x00\x00'\xcf\xd3\x08\x00\x00\x00\x00)\x09\x98\x08\x00\x00\x00\x00)\xcbd\x88\x00\x00\x00\x00*\xe9z\x08\x00\x00\x00\x00+\x98\xd1\x88\x00\x00\x00\x00,\xd2\x96\x88\x00\x00\x00\x00-\x8b(\x88\x00\x00\x00\x00.\xb2x\x88\x00\x00\x00\x00/tE\x08\x00\x00\x00\x000\x92Z\x88\x00\x00\x00\x001]a\x88\x00\x00\x00\x002r<\x88\x00\x00\x00\x003=C\x88\x00\x00\x00\x004R\x1e\x88\x00\x00\x00\x005\x1d%\x88\x00\x00\x00\x0062\x00\x88\x00\x00\x00\x006\xfd\x07\x88\x00\x00\x00\x008\x1b\x1d\x08\x00\x00\x00\x008\xdc\xe9\x88\x00\x00\x00\x009\xfa\xff\x08\x00\x00\x00\x00:\xbc\xcb\x88\x00\x00\x00\x00;\xda\xe1\x08\x00\x00\x00\x00<\xa5\xe8\x08\x00\x00\x00\x00=\xba\xc3\x08\x00\x00\x00\x00>\x85\xca\x08\x00\x00\x00\x00?\x9a\xa5\x08\x00\x00\x00\x00@e\xac\x08\x00\x00\x00\x00A\x83\xc1\x88\x00\x00\x00\x00BE\x8e\x08\x00\x00\x00\x00Cc\xa3\x88\x00\x00\x00\x00D.\xaa\x88\x00\x00\x00\x00EC\x85\x88\x00\x00\x00\x00F\x05R\x08\x00\x00\x00\x00G#g\x88\x00\x00\x00\x00G\xf7\xa9\x08\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x00\x81\xec\x00\x00\x00\x00~\x90\x00\x04\x00\x00\x93\xa8\x01\x09\x00\x00\x85\x98\x00\x04LMT\x00ACST\x00ACDT\x00\x0aACST-9:30ACDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x10\x00\x00\x00Australia/SydneyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x7f<\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x0c\x89\x80\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xc7\x81\x80\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1ey\x9c\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00%\xef\xea\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x00\x00\x00\x00*\xe9s\x00\x00\x00\x00\x00+\x98\xca\x80\x00\x00\x00\x00,\xd2\x8f\x80\x00\x00\x00\x00-x\xac\x80\x00\x00\x00\x00.\xb2q\x80\x00\x00\x00\x00/X\x8e\x80\x00\x00\x00\x000\x92S\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002r5\x80\x00\x00\x00\x003=<\x80\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xf7\xa2\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x8d\xc4\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\xf2\xe6Z\xeb\x03\x00\x00\xeb\x03\x00\x00\x12\x00\x00\x00Australia/TasmaniaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xfft.\x00\xe4\xff\xff\xff\xff\x9b\xd5x\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\x9d\xdaD\x80\xff\xff\xff\xff\x9e\x80a\x80\xff\xff\xff\xff\x9f\xba&\x80\xff\xff\xff\xff\xa0`C\x80\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\xff\xff\xff\xff\xfb\xc2\x8d\x00\xff\xff\xff\xff\xfc\xb2~\x00\xff\xff\xff\xff\xfd\xc7Y\x00\xff\xff\xff\xff\xfev\xb0\x80\xff\xff\xff\xff\xff\xa7;\x00\x00\x00\x00\x00\x00V\x92\x80\x00\x00\x00\x00\x01\x87\x1d\x00\x00\x00\x00\x00\x02?\xaf\x00\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x17\x03O\x00\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xe31\x00\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1eg'\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!\x80\xce\x80\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00&\x02_\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xf4\xb6\x00\x00\x00\x00\x00(\xed\xe1\x80\x00\x00\x00\x00)\xd4\x98\x00\x00\x00\x00\x00*\xcd\xc3\x80\x00\x00\x00\x00+\xb4z\x00\x00\x00\x00\x00,\xad\xa5\x80\x00\x00\x00\x00-\x94\x5c\x00\x00\x00\x00\x00.\x8d\x87\x80\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000mi\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002V\x86\x00\x00\x00\x00\x003=<\x80\x00\x00\x00\x0046h\x00\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x006\x16J\x00\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x007\xf6,\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xbf*\x80\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\x9f\x0c\x80\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?~\xee\x80\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A^\xd0\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00C>\xb2\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00E\x1e\x94\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G\x07\xb1\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\x8a\x1c\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xe1\xc1\xa9\x88\x03\x00\x00\x88\x03\x00\x00\x12\x00\x00\x00Australia/VictoriaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xffs\x16\x85\x18\xff\xff\xff\xff\x9cN\xc2\x80\xff\xff\xff\xff\x9c\xbc/\x00\xff\xff\xff\xff\xcbT\xb3\x00\xff\xff\xff\xff\xcb\xc7e\x80\xff\xff\xff\xff\xcc\xb7V\x80\xff\xff\xff\xff\xcd\xa7G\x80\xff\xff\xff\xff\xce\xa0s\x00\xff\xff\xff\xff\xcf\x87)\x80\x00\x00\x00\x00\x03p9\x80\x00\x00\x00\x00\x04\x0d\x1c\x00\x00\x00\x00\x00\x05P\x1b\x80\x00\x00\x00\x00\x05\xf68\x80\x00\x00\x00\x00\x07/\xfd\x80\x00\x00\x00\x00\x07\xd6\x1a\x80\x00\x00\x00\x00\x09\x0f\xdf\x80\x00\x00\x00\x00\x09\xb5\xfc\x80\x00\x00\x00\x00\x0a\xef\xc1\x80\x00\x00\x00\x00\x0b\x9f\x19\x00\x00\x00\x00\x00\x0c\xd8\xde\x00\x00\x00\x00\x00\x0d~\xfb\x00\x00\x00\x00\x00\x0e\xb8\xc0\x00\x00\x00\x00\x00\x0f^\xdd\x00\x00\x00\x00\x00\x10\x98\xa2\x00\x00\x00\x00\x00\x11>\xbf\x00\x00\x00\x00\x00\x12x\x84\x00\x00\x00\x00\x00\x13\x1e\xa1\x00\x00\x00\x00\x00\x14Xf\x00\x00\x00\x00\x00\x14\xfe\x83\x00\x00\x00\x00\x00\x168H\x00\x00\x00\x00\x00\x16\xe7\x9f\x80\x00\x00\x00\x00\x18!d\x80\x00\x00\x00\x00\x18\xc7\x81\x80\x00\x00\x00\x00\x1a\x01F\x80\x00\x00\x00\x00\x1a\xa7c\x80\x00\x00\x00\x00\x1b\xe1(\x80\x00\x00\x00\x00\x1c\x87E\x80\x00\x00\x00\x00\x1d\xc1\x0a\x80\x00\x00\x00\x00\x1ey\x9c\x80\x00\x00\x00\x00\x1f\x97\xb2\x00\x00\x00\x00\x00 Y~\x80\x00\x00\x00\x00!w\x94\x00\x00\x00\x00\x00\x22B\x9b\x00\x00\x00\x00\x00#i\xeb\x00\x00\x00\x00\x00$\x22}\x00\x00\x00\x00\x00%I\xcd\x00\x00\x00\x00\x00&\x02_\x00\x00\x00\x00\x00')\xaf\x00\x00\x00\x00\x00'\xcf\xcc\x00\x00\x00\x00\x00)\x09\x91\x00\x00\x00\x00\x00)\xaf\xae\x00\x00\x00\x00\x00*\xe9s\x00\x00\x00\x00\x00+\x98\xca\x80\x00\x00\x00\x00,\xd2\x8f\x80\x00\x00\x00\x00-x\xac\x80\x00\x00\x00\x00.\xb2q\x80\x00\x00\x00\x00/t>\x00\x00\x00\x00\x000\x92S\x80\x00\x00\x00\x001]Z\x80\x00\x00\x00\x002r5\x80\x00\x00\x00\x003=<\x80\x00\x00\x00\x004R\x17\x80\x00\x00\x00\x005\x1d\x1e\x80\x00\x00\x00\x0061\xf9\x80\x00\x00\x00\x006\xfd\x00\x80\x00\x00\x00\x008\x1b\x16\x00\x00\x00\x00\x008\xdc\xe2\x80\x00\x00\x00\x009\xa7\xe9\x80\x00\x00\x00\x00:\xbc\xc4\x80\x00\x00\x00\x00;\xda\xda\x00\x00\x00\x00\x00<\xa5\xe1\x00\x00\x00\x00\x00=\xba\xbc\x00\x00\x00\x00\x00>\x85\xc3\x00\x00\x00\x00\x00?\x9a\x9e\x00\x00\x00\x00\x00@e\xa5\x00\x00\x00\x00\x00A\x83\xba\x80\x00\x00\x00\x00BE\x87\x00\x00\x00\x00\x00Cc\x9c\x80\x00\x00\x00\x00D.\xa3\x80\x00\x00\x00\x00EC~\x80\x00\x00\x00\x00F\x05K\x00\x00\x00\x00\x00G#`\x80\x00\x00\x00\x00G\xf7\xa2\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x87\xe8\x00\x00\x00\x00\x9a\xb0\x01\x04\x00\x00\x8c\xa0\x00\x09LMT\x00AEDT\x00AEST\x00\x0aAEST-10AEDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xbb\xca\x1a2\x01\x00\x002\x01\x00\x00\x0e\x00\x00\x00Australia/WestTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xfft\xa6\x16\xe4\xff\xff\xff\xff\x9cN\xde\xa0\xff\xff\xff\xff\x9c\xbcK \xff\xff\xff\xff\xcbT\xcf \xff\xff\xff\xff\xcb\xc7\x81\xa0\xff\xff\xff\xff\xcc\xb7r\xa0\xff\xff\xff\xff\xcd\xa7c\xa0\x00\x00\x00\x00\x09\x0f\xfb\xa0\x00\x00\x00\x00\x09\xb6\x18\xa0\x00\x00\x00\x00\x1a\x01b\xa0\x00\x00\x00\x00\x1a\xa7\x7f\xa0\x00\x00\x00\x00)%\x5c\xa0\x00\x00\x00\x00)\xaf\xca \x00\x00\x00\x00Eq\xbf \x00\x00\x00\x00F\x05g \x00\x00\x00\x00G#|\xa0\x00\x00\x00\x00G\xee\x83\xa0\x00\x00\x00\x00I\x03^\xa0\x00\x00\x00\x00I\xcee\xa0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00l\x9c\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x09LMT\x00AWDT\x00AWST\x00\x0aAWST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbd\xca#\x7f\xad\x03\x00\x00\xad\x03\x00\x00\x14\x00\x00\x00Australia/YancowinnaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x00\x00\x00\x05\x00\x00\x00\x13\xff\xff\xff\xffs\x16\x88d\xff\xff\xff\xffv\x04\xa5\xe0\xff\xff\xff\xff{\x12\x03p\xff\xff\xff\xff\x9cN\xc9\x88\xff\xff\xff\xff\x9c\xbc6\x08\xff\xff\xff\xff\xcbT\xba\x08\xff\xff\xff\xff\xcb\xc7l\x88\xff\xff\xff\xff\xcc\xb7]\x88\xff\xff\xff\xff\xcd\xa7N\x88\xff\xff\xff\xff\xce\xa0z\x08\xff\xff\xff\xff\xcf\x870\x88\x00\x00\x00\x00\x03p@\x88\x00\x00\x00\x00\x04\x0d#\x08\x00\x00\x00\x00\x05P\x22\x88\x00\x00\x00\x00\x05\xf6?\x88\x00\x00\x00\x00\x070\x04\x88\x00\x00\x00\x00\x07\xd6!\x88\x00\x00\x00\x00\x09\x0f\xe6\x88\x00\x00\x00\x00\x09\xb6\x03\x88\x00\x00\x00\x00\x0a\xef\xc8\x88\x00\x00\x00\x00\x0b\x9f \x08\x00\x00\x00\x00\x0c\xd8\xe5\x08\x00\x00\x00\x00\x0d\x7f\x02\x08\x00\x00\x00\x00\x0e\xb8\xc7\x08\x00\x00\x00\x00\x0f^\xe4\x08\x00\x00\x00\x00\x10\x98\xa9\x08\x00\x00\x00\x00\x11>\xc6\x08\x00\x00\x00\x00\x12x\x8b\x08\x00\x00\x00\x00\x13\x1e\xa8\x08\x00\x00\x00\x00\x14Xm\x08\x00\x00\x00\x00\x14\xfe\x8a\x08\x00\x00\x00\x00\x168O\x08\x00\x00\x00\x00\x17\x0c\x90\x88\x00\x00\x00\x00\x18!k\x88\x00\x00\x00\x00\x18\xc7\x88\x88\x00\x00\x00\x00\x1a\x01M\x88\x00\x00\x00\x00\x1a\xa7j\x88\x00\x00\x00\x00\x1b\xe1/\x88\x00\x00\x00\x00\x1c\x87L\x88\x00\x00\x00\x00\x1d\xc1\x11\x88\x00\x00\x00\x00\x1ey\xa3\x88\x00\x00\x00\x00\x1f\x97\xb9\x08\x00\x00\x00\x00 Y\x85\x88\x00\x00\x00\x00!\x80\xd5\x88\x00\x00\x00\x00\x22B\xa2\x08\x00\x00\x00\x00#i\xf2\x08\x00\x00\x00\x00$\x22\x84\x08\x00\x00\x00\x00%I\xd4\x08\x00\x00\x00\x00%\xef\xf1\x08\x00\x00\x00\x00')\xb6\x08\x00\x00\x00\x00'\xcf\xd3\x08\x00\x00\x00\x00)\x09\x98\x08\x00\x00\x00\x00)\xaf\xb5\x08\x00\x00\x00\x00*\xe9z\x08\x00\x00\x00\x00+\x98\xd1\x88\x00\x00\x00\x00,\xd2\x96\x88\x00\x00\x00\x00-x\xb3\x88\x00\x00\x00\x00.\xb2x\x88\x00\x00\x00\x00/X\x95\x88\x00\x00\x00\x000\x92Z\x88\x00\x00\x00\x001]a\x88\x00\x00\x00\x002r<\x88\x00\x00\x00\x003=C\x88\x00\x00\x00\x004R\x1e\x88\x00\x00\x00\x005\x1d%\x88\x00\x00\x00\x0062\x00\x88\x00\x00\x00\x006\xfd\x07\x88\x00\x00\x00\x008\x1b\x1d\x08\x00\x00\x00\x008\xdc\xe9\x88\x00\x00\x00\x009\xfa\xff\x08\x00\x00\x00\x00:\xbc\xcb\x88\x00\x00\x00\x00;\xda\xe1\x08\x00\x00\x00\x00<\xa5\xe8\x08\x00\x00\x00\x00=\xba\xc3\x08\x00\x00\x00\x00>\x85\xca\x08\x00\x00\x00\x00?\x9a\xa5\x08\x00\x00\x00\x00@e\xac\x08\x00\x00\x00\x00A\x83\xc1\x88\x00\x00\x00\x00BE\x8e\x08\x00\x00\x00\x00Cc\xa3\x88\x00\x00\x00\x00D.\xaa\x88\x00\x00\x00\x00EC\x85\x88\x00\x00\x00\x00F\x05R\x08\x00\x00\x00\x00G#g\x88\x00\x00\x00\x00G\xf7\xa9\x08\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x00\x00\x84\x9c\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00~\x90\x00\x09\x00\x00\x93\xa8\x01\x0e\x00\x00\x85\x98\x00\x09LMT\x00AEST\x00ACST\x00ACDT\x00\x0aACST-9:30ACDT,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xf5K\x89\xa2\x01\x00\x00\xa2\x01\x00\x00\x0b\x00\x00\x00Brazil/AcreTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa\x86\x90\xff\xff\xff\xff\xb8\x0ff\x00\xff\xff\xff\xff\xb8\xfd\x5c\xc0\xff\xff\xff\xff\xb9\xf1PP\xff\xff\xff\xff\xba\xde\x90@\xff\xff\xff\xff\xda8\xcaP\xff\xff\xff\xff\xda\xec\x16P\xff\xff\xff\xff\xdc\x19\xfd\xd0\xff\xff\xff\xff\xdc\xb9u@\xff\xff\xff\xff\xdd\xfb1P\xff\xff\xff\xff\xde\x9b\xfa@\xff\xff\xff\xff\xdf\xdd\xb6P\xff\xff\xff\xff\xe0TO@\xff\xff\xff\xff\xf4\x98\x1b\xd0\xff\xff\xff\xff\xf5\x05z@\xff\xff\xff\xff\xf6\xc0\x80P\xff\xff\xff\xff\xf7\x0e:\xc0\xff\xff\xff\xff\xf8QHP\xff\xff\xff\xff\xf8\xc7\xe1@\xff\xff\xff\xff\xfa\x0a\xee\xd0\xff\xff\xff\xff\xfa\xa9\x14\xc0\xff\xff\xff\xff\xfb\xec\x22P\xff\xff\xff\xff\xfc\x8b\x99\xc0\x00\x00\x00\x00\x1d\xc9\xaaP\x00\x00\x00\x00\x1ex\xf3\xc0\x00\x00\x00\x00\x1f\xa0Q\xd0\x00\x00\x00\x00 3\xeb\xc0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22\x0b\xe4\xc0\x00\x00\x00\x00H`\x7fP\x00\x00\x00\x00R\x7f\x04\xc0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\xff\xff\xc0p\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x00\x04LMT\x00-04\x00-05\x00\x0a<-05>5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7-2f\xe4\x01\x00\x00\xe4\x01\x00\x00\x10\x00\x00\x00Brazil/DeNoronhaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaaed\xff\xff\xff\xff\xb8\x0f;\xd0\xff\xff\xff\xff\xb8\xfd2\x90\xff\xff\xff\xff\xb9\xf1& \xff\xff\xff\xff\xba\xdef\x10\xff\xff\xff\xff\xda8\xa0 \xff\xff\xff\xff\xda\xeb\xec \xff\xff\xff\xff\xdc\x19\xd3\xa0\xff\xff\xff\xff\xdc\xb9K\x10\xff\xff\xff\xff\xdd\xfb\x07 \xff\xff\xff\xff\xde\x9b\xd0\x10\xff\xff\xff\xff\xdf\xdd\x8c \xff\xff\xff\xff\xe0T%\x10\xff\xff\xff\xff\xf4\x97\xf1\xa0\xff\xff\xff\xff\xf5\x05P\x10\xff\xff\xff\xff\xf6\xc0V \xff\xff\xff\xff\xf7\x0e\x10\x90\xff\xff\xff\xff\xf8Q\x1e \xff\xff\xff\xff\xf8\xc7\xb7\x10\xff\xff\xff\xff\xfa\x0a\xc4\xa0\xff\xff\xff\xff\xfa\xa8\xea\x90\xff\xff\xff\xff\xfb\xeb\xf8 \xff\xff\xff\xff\xfc\x8bo\x90\x00\x00\x00\x00\x1d\xc9\x80 \x00\x00\x00\x00\x1ex\xc9\x90\x00\x00\x00\x00\x1f\xa0'\xa0\x00\x00\x00\x00 3\xc1\x90\x00\x00\x00\x00!\x81[ \x00\x00\x00\x00\x22\x0b\xba\x90\x00\x00\x00\x00#X\x02\xa0\x00\x00\x00\x00#\xe2b\x10\x00\x00\x00\x00%7\xe4\xa0\x00\x00\x00\x00%\xd4\xb9\x10\x00\x00\x00\x007\xf6\xb8\xa0\x00\x00\x00\x008\xb8w\x10\x00\x00\x00\x009\xdf\xd5 \x00\x00\x00\x009\xe9\x01\x90\x00\x00\x00\x00;\xc8\xf1\xa0\x00\x00\x00\x002\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9d?\xdf\xda\xb8\x03\x00\x00\xb8\x03\x00\x00\x0b\x00\x00\x00Brazil/EastTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaar\xb4\xff\xff\xff\xff\xb8\x0fI\xe0\xff\xff\xff\xff\xb8\xfd@\xa0\xff\xff\xff\xff\xb9\xf140\xff\xff\xff\xff\xba\xdet \xff\xff\xff\xff\xda8\xae0\xff\xff\xff\xff\xda\xeb\xfa0\xff\xff\xff\xff\xdc\x19\xe1\xb0\xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xfb\x150\xff\xff\xff\xff\xde\x9b\xde \xff\xff\xff\xff\xdf\xdd\x9a0\xff\xff\xff\xff\xe0T3 \xff\xff\xff\xff\xf4Z\x090\xff\xff\xff\xff\xf5\x05^ \xff\xff\xff\xff\xf6\xc0d0\xff\xff\xff\xff\xf7\x0e\x1e\xa0\xff\xff\xff\xff\xf8Q,0\xff\xff\xff\xff\xf8\xc7\xc5 \xff\xff\xff\xff\xfa\x0a\xd2\xb0\xff\xff\xff\xff\xfa\xa8\xf8\xa0\xff\xff\xff\xff\xfb\xec\x060\xff\xff\xff\xff\xfc\x8b}\xa0\x00\x00\x00\x00\x1d\xc9\x8e0\x00\x00\x00\x00\x1ex\xd7\xa0\x00\x00\x00\x00\x1f\xa05\xb0\x00\x00\x00\x00 3\xcf\xa0\x00\x00\x00\x00!\x81i0\x00\x00\x00\x00\x22\x0b\xc8\xa0\x00\x00\x00\x00#X\x10\xb0\x00\x00\x00\x00#\xe2p \x00\x00\x00\x00%7\xf2\xb0\x00\x00\x00\x00%\xd4\xc7 \x00\x00\x00\x00'!\x0f0\x00\x00\x00\x00'\xbd\xe3\xa0\x00\x00\x00\x00)\x00\xf10\x00\x00\x00\x00)\x94\x8b \x00\x00\x00\x00*\xea\x0d\xb0\x00\x00\x00\x00+k2\xa0\x00\x00\x00\x00,\xc0\xb50\x00\x00\x00\x00-f\xc4 \x00\x00\x00\x00.\xa0\x970\x00\x00\x00\x00/F\xa6 \x00\x00\x00\x000\x80y0\x00\x00\x00\x001\x1dM\xa0\x00\x00\x00\x002W \xb0\x00\x00\x00\x003\x06j \x00\x00\x00\x0048T0\x00\x00\x00\x004\xf8\xc1 \x00\x00\x00\x006 \x1f0\x00\x00\x00\x006\xcfh\xa0\x00\x00\x00\x007\xf6\xc6\xb0\x00\x00\x00\x008\xb8\x85 \x00\x00\x00\x009\xdf\xe30\x00\x00\x00\x00:\x8f,\xa0\x00\x00\x00\x00;\xc8\xff\xb0\x00\x00\x00\x00N\xf0\xa0\x00\x00\x00\x00?\x91\xfe0\x00\x00\x00\x00@.\xd2\xa0\x00\x00\x00\x00A\x86\xf80\x00\x00\x00\x00B\x17\xef \x00\x00\x00\x00CQ\xc20\x00\x00\x00\x00C\xf7\xd1 \x00\x00\x00\x00EMS\xb0\x00\x00\x00\x00E\xe0\xed\xa0\x00\x00\x00\x00G\x11\x860\x00\x00\x00\x00G\xb7\x95 \x00\x00\x00\x00H\xfa\xa2\xb0\x00\x00\x00\x00I\x97w \x00\x00\x00\x00J\xda\x84\xb0\x00\x00\x00\x00K\x80\x93\xa0\x00\x00\x00\x00L\xbaf\xb0\x00\x00\x00\x00M`u\xa0\x00\x00\x00\x00N\x9aH\xb0\x00\x00\x00\x00OI\x92 \x00\x00\x00\x00P\x83e0\x00\x00\x00\x00Q 9\xa0\x00\x00\x00\x00RcG0\x00\x00\x00\x00S\x00\x1b\xa0\x00\x00\x00\x00TC)0\x00\x00\x00\x00T\xe98 \x00\x00\x00\x00V#\x0b0\x00\x00\x00\x00V\xc9\x1a \x00\x00\x00\x00X\x02\xed0\x00\x00\x00\x00X\xa8\xfc \x00\x00\x00\x00Y\xe2\xcf0\x00\x00\x00\x00Z\x88\xde \x00\x00\x00\x00[\xde`\xb0\x00\x00\x00\x00\x5ch\xc0 \x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xd4L\x00\x00\xff\xff\xe3\xe0\x01\x04\xff\xff\xd5\xd0\x00\x08LMT\x00-02\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\xcb'\xe9\x9c\x01\x00\x00\x9c\x01\x00\x00\x0b\x00\x00\x00Brazil/WestTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x96\xaa\x7fD\xff\xff\xff\xff\xb8\x0fW\xf0\xff\xff\xff\xff\xb8\xfdN\xb0\xff\xff\xff\xff\xb9\xf1B@\xff\xff\xff\xff\xba\xde\x820\xff\xff\xff\xff\xda8\xbc@\xff\xff\xff\xff\xda\xec\x08@\xff\xff\xff\xff\xdc\x19\xef\xc0\xff\xff\xff\xff\xdc\xb9g0\xff\xff\xff\xff\xdd\xfb#@\xff\xff\xff\xff\xde\x9b\xec0\xff\xff\xff\xff\xdf\xdd\xa8@\xff\xff\xff\xff\xe0TA0\xff\xff\xff\xff\xf4\x98\x0d\xc0\xff\xff\xff\xff\xf5\x05l0\xff\xff\xff\xff\xf6\xc0r@\xff\xff\xff\xff\xf7\x0e,\xb0\xff\xff\xff\xff\xf8Q:@\xff\xff\xff\xff\xf8\xc7\xd30\xff\xff\xff\xff\xfa\x0a\xe0\xc0\xff\xff\xff\xff\xfa\xa9\x06\xb0\xff\xff\xff\xff\xfb\xec\x14@\xff\xff\xff\xff\xfc\x8b\x8b\xb0\x00\x00\x00\x00\x1d\xc9\x9c@\x00\x00\x00\x00\x1ex\xe5\xb0\x00\x00\x00\x00\x1f\xa0C\xc0\x00\x00\x00\x00 3\xdd\xb0\x00\x00\x00\x00!\x81w@\x00\x00\x00\x00\x22\x0b\xd6\xb0\x00\x00\x00\x00,\xc0\xc3@\x00\x00\x00\x00-f\xd20\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\xff\xff\xc7\xbc\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08LMT\x00-03\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x9aM\xbem\x02\x00\x00m\x02\x00\x00\x03\x00\x00\x00CETTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x00\x00\x00\x02\x00\x00\x00\x09\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\x09q\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2N@\x90\x00\x00\x00\x00\x0d\xa4c\x90\x00\x00\x00\x00\x0e\x8b\x1a\x10\x00\x00\x00\x00\x0f\x84E\x90\x00\x00\x00\x00\x10t6\x90\x00\x00\x00\x00\x11d'\x90\x00\x00\x00\x00\x12T\x18\x90\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x01\x00\x01\x00\x02\x03\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\xff\xff\xab\xa0\x00\x04\xff\xff\xb9\xb0\x01\x00\xff\xff\xb9\xb0\x01\x08\xff\xff\xb9\xb0\x01\x0cCDT\x00CST\x00CWT\x00CPT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00):\x17-\x88\x06\x00\x00\x88\x06\x00\x00\x0f\x00\x00\x00Canada/AtlanticTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x80\xf1\xab\xa0\xff\xff\xff\xff\x9a\xe4\xde\xc0\xff\xff\xff\xff\x9b\xd6\x130\xff\xff\xff\xff\x9e\xb8\x85`\xff\xff\xff\xff\x9f\xba\xddP\xff\xff\xff\xff\xa2\x9d\x17@\xff\xff\xff\xff\xa30\xb10\xff\xff\xff\xff\xa4zV@\xff\xff\xff\xff\xa5\x1b\x1f0\xff\xff\xff\xff\xa6S\xa0\xc0\xff\xff\xff\xff\xa6\xfcR\xb0\xff\xff\xff\xff\xa8<\xbd@\xff\xff\xff\xff\xa8\xdc4\xb0\xff\xff\xff\xff\xaa\x1c\x9f@\xff\xff\xff\xff\xaa\xcd:0\xff\xff\xff\xff\xab\xfc\x81@\xff\xff\xff\xff\xac\xbf\x910\xff\xff\xff\xff\xad\xee\xd8@\xff\xff\xff\xff\xae\x8c\xfe0\xff\xff\xff\xff\xaf\xbcE@\xff\xff\xff\xff\xb0\x7fU0\xff\xff\xff\xff\xb1\xae\x9c@\xff\xff\xff\xff\xb2Kp\xb0\xff\xff\xff\xff\xb3\x8e~@\xff\xff\xff\xff\xb4$\xbb0\xff\xff\xff\xff\xb5n`@\xff\xff\xff\xff\xb6\x15\xc0\xb0\xff\xff\xff\xff\xb7NB@\xff\xff\xff\xff\xb8\x08\x17\xb0\xff\xff\xff\xff\xb9$\xe9\xc0\xff\xff\xff\xff\xb9\xe7\xf9\xb0\xff\xff\xff\xff\xbb\x04\xcb\xc0\xff\xff\xff\xff\xbb\xd1\x160\xff\xff\xff\xff\xbd\x00]@\xff\xff\xff\xff\xbd\x9d1\xb0\xff\xff\xff\xff\xbe\xf2\xb4@\xff\xff\xff\xff\xbf\x90\xda0\xff\xff\xff\xff\xc0\xd3\xe7\xc0\xff\xff\xff\xff\xc1^G0\xff\xff\xff\xff\xc2\x8d\x8e@\xff\xff\xff\xff\xc3P\x9e0\xff\xff\xff\xff\xc4mp@\xff\xff\xff\xff\xc50\x800\xff\xff\xff\xff\xc6r<@\xff\xff\xff\xff\xc7\x10b0\xff\xff\xff\xff\xc86n\xc0\xff\xff\xff\xff\xc8\xf9~\xb0\xff\xff\xff\xff\xca\x16P\xc0\xff\xff\xff\xff\xca\xd9`\xb0\xff\xff\xff\xff\xcb\x88\xe2`\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xed\xd0\xff\xff\xff\xff\xd3u\xd6\xe0\xff\xff\xff\xff\xd4@\xcf\xd0\xff\xff\xff\xff\xd5U\xb8\xe0\xff\xff\xff\xff\xd6 \xb1\xd0\xff\xff\xff\xff\xd75\x9a\xe0\xff\xff\xff\xff\xd8\x00\x93\xd0\xff\xff\xff\xff\xd9\x15|\xe0\xff\xff\xff\xff\xd9\xe0u\xd0\xff\xff\xff\xff\xdc\xde{`\xff\xff\xff\xff\xdd\xa9tP\xff\xff\xff\xff\xde\xbe]`\xff\xff\xff\xff\xdf\x89VP\xff\xff\xff\xff\xe0\x9e?`\xff\xff\xff\xff\xe1i8P\xff\xff\xff\xff\xe2~!`\xff\xff\xff\xff\xe3I\x1aP\xff\xff\xff\xff\xe6G\x1f\xe0\xff\xff\xff\xff\xe7\x12\x18\xd0\xff\xff\xff\xff\xe8'\x01\xe0\xff\xff\xff\xff\xe8\xf1\xfa\xd0\xff\xff\xff\xff\xea\x06\xe3\xe0\xff\xff\xff\xff\xea\xd1\xdc\xd0\xff\xff\xff\xff\xeb\xe6\xc5\xe0\xff\xff\xff\xff\xec\xb1\xbe\xd0\xff\xff\xff\xff\xf1\x8f\xa6`\xff\xff\xff\xff\xf2\x7f\x89P\xff\xff\xff\xff\xf3o\x88`\xff\xff\xff\xff\xf4_kP\xff\xff\xff\xff\xf5Oj`\xff\xff\xff\xff\xf6?MP\xff\xff\xff\xff\xf7/L`\xff\xff\xff\xff\xf8(i\xd0\xff\xff\xff\xff\xf9\x0f.`\xff\xff\xff\xff\xfa\x08K\xd0\xff\xff\xff\xff\xfa\xf8J\xe0\xff\xff\xff\xff\xfb\xe8-\xd0\xff\xff\xff\xff\xfc\xd8,\xe0\xff\xff\xff\xff\xfd\xc8\x0f\xd0\xff\xff\xff\xff\xfe\xb8\x0e\xe0\xff\xff\xff\xff\xff\xa7\xf1\xd0\x00\x00\x00\x00\x00\x97\xf0\xe0\x00\x00\x00\x00\x01\x87\xd3\xd0\x00\x00\x00\x00\x02w\xd2\xe0\x00\x00\x00\x00\x03p\xf0P\x00\x00\x00\x00\x04`\xef`\x00\x00\x00\x00\x05P\xd2P\x00\x00\x00\x00\x06@\xd1`\x00\x00\x00\x00\x070\xb4P\x00\x00\x00\x00\x08 \xb3`\x00\x00\x00\x00\x09\x10\x96P\x00\x00\x00\x00\x0a\x00\x95`\x00\x00\x00\x00\x0a\xf0xP\x00\x00\x00\x00\x0b\xe0w`\x00\x00\x00\x00\x0c\xd9\x94\xd0\x00\x00\x00\x00\x0d\xc0Y`\x00\x00\x00\x00\x0e\xb9v\xd0\x00\x00\x00\x00\x0f\xa9u\xe0\x00\x00\x00\x00\x10\x99X\xd0\x00\x00\x00\x00\x11\x89W\xe0\x00\x00\x00\x00\x12y:\xd0\x00\x00\x00\x00\x13i9\xe0\x00\x00\x00\x00\x14Y\x1c\xd0\x00\x00\x00\x00\x15I\x1b\xe0\x00\x00\x00\x00\x168\xfe\xd0\x00\x00\x00\x00\x17(\xfd\xe0\x00\x00\x00\x00\x18\x22\x1bP\x00\x00\x00\x00\x19\x08\xdf\xe0\x00\x00\x00\x00\x1a\x01\xfdP\x00\x00\x00\x00\x1a\xf1\xfc`\x00\x00\x00\x00\x1b\xe1\xdfP\x00\x00\x00\x00\x1c\xd1\xde`\x00\x00\x00\x00\x1d\xc1\xc1P\x00\x00\x00\x00\x1e\xb1\xc0`\x00\x00\x00\x00\x1f\xa1\xa3P\x00\x00\x00\x00 u\xf2\xe0\x00\x00\x00\x00!\x81\x85P\x00\x00\x00\x00\x22U\xd4\xe0\x00\x00\x00\x00#j\xa1\xd0\x00\x00\x00\x00$5\xb6\xe0\x00\x00\x00\x00%J\x83\xd0\x00\x00\x00\x00&\x15\x98\xe0\x00\x00\x00\x00'*e\xd0\x00\x00\x00\x00'\xfe\xb5`\x00\x00\x00\x00)\x0aG\xd0\x00\x00\x00\x00)\xde\x97`\x00\x00\x00\x00*\xea)\xd0\x00\x00\x00\x00+\xbey`\x00\x00\x00\x00,\xd3FP\x00\x00\x00\x00-\x9e[`\x00\x00\x00\x00.\xb3(P\x00\x00\x00\x00/~=`\x00\x00\x00\x000\x93\x0aP\x00\x00\x00\x001gY\xe0\x00\x00\x00\x002r\xecP\x00\x00\x00\x003G;\xe0\x00\x00\x00\x004R\xceP\x00\x00\x00\x005'\x1d\xe0\x00\x00\x00\x0062\xb0P\x00\x00\x00\x007\x06\xff\xe0\x00\x00\x00\x008\x1b\xcc\xd0\x00\x00\x00\x008\xe6\xe1\xe0\x00\x00\x00\x009\xfb\xae\xd0\x00\x00\x00\x00:\xc6\xc3\xe0\x00\x00\x00\x00;\xdb\x90\xd0\x00\x00\x00\x00<\xaf\xe0`\x00\x00\x00\x00=\xbbr\xd0\x00\x00\x00\x00>\x8f\xc2`\x00\x00\x00\x00?\x9bT\xd0\x00\x00\x00\x00@o\xa4`\x00\x00\x00\x00A\x84qP\x00\x00\x00\x00BO\x86`\x00\x00\x00\x00CdSP\x00\x00\x00\x00D/h`\x00\x00\x00\x00ED5P\x00\x00\x00\x00E\xf3\x9a\xe0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xc4`\x00\x00\xff\xff\xd5\xd0\x01\x04\xff\xff\xc7\xc0\x00\x08\xff\xff\xd5\xd0\x01\x0c\xff\xff\xd5\xd0\x01\x10LMT\x00ADT\x00AST\x00AWT\x00APT\x00\x0aAST4ADT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?_p\x99\x0e\x05\x00\x00\x0e\x05\x00\x00\x0e\x00\x00\x00Canada/CentralTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffd\xe4\xb0\x94\xff\xff\xff\xff\x9b\x01\xfb\xe0\xff\xff\xff\xff\x9b\xc3\xbaP\xff\xff\xff\xff\x9e\xb8\xa1\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xc2\xa0;\x80\xff\xff\xff\xff\xc3O\x84\xf0\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3\x88h\x00\xff\xff\xff\xff\xd4S`\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xdb\x00\x07\x00\xff\xff\xff\xff\xdb\xc8\x5c\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5)\x18p\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe7\x124\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xd6\xc4\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\x91\xbc\xf0\xff\xff\xff\xff\xf3o\xa4\x80\xff\xff\xff\xff\xf41b\xf0\xff\xff\xff\xff\xf9\x0fJ\x80\xff\xff\xff\xff\xfa\x08v\x00\xff\xff\xff\xff\xfa\xf8g\x00\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x0d\x00\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xef\x00\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x08 \xcf\x80\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x0a\x00\xb1\x80\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xb3\x80\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\x95\x80\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9ew\x80\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~Y\x80\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xe0\x00\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xa4\xec\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10LMT\x00CDT\x00CST\x00CWT\x00CPT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0e\x00\x00\x00Canada/EasternTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xffr\xeex\xec\xff\xff\xff\xff\x9e\xb8\x93p\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x87.\xc8\xff\xff\xff\xff\xa1\x9a\xb1@\xff\xff\xff\xff\xa2\x94\x06\xf0\xff\xff\xff\xff\xa3U\xa9@\xff\xff\xff\xff\xa4\x86]\xf0\xff\xff\xff\xff\xa5(x`\xff\xff\xff\xff\xa6f?\xf0\xff\xff\xff\xff\xa7\x0cN\xe0\xff\xff\xff\xff\xa8F!\xf0\xff\xff\xff\xff\xa8\xec0\xe0\xff\xff\xff\xff\xaa\x1c\xc9p\xff\xff\xff\xff\xaa\xd5M`\xff\xff\xff\xff\xab\xfc\xabp\xff\xff\xff\xff\xac\xb5/`\xff\xff\xff\xff\xad\xdc\x8dp\xff\xff\xff\xff\xae\x95\x11`\xff\xff\xff\xff\xaf\xbcop\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xda3\x92`\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdc\x13t`\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5)\x0a`\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe7\x12&\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xb5\x94\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\x07\x07\xdc\xca\x03\x00\x00\xca\x03\x00\x00\x0f\x00\x00\x00Canada/MountainTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\x88\xde\xce\xe0\xff\xff\xff\xff\x9e\xb8\xaf\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x98\x91\x90\xff\xff\xff\xff\xa0\xd2\x85\x80\xff\xff\xff\xff\xa2\x8a\xe8\x90\xff\xff\xff\xff\xa3\x84\x06\x00\xff\xff\xff\xff\xa4j\xca\x90\xff\xff\xff\xff\xa55\xc3\x80\xff\xff\xff\xff\xa6S\xe7\x10\xff\xff\xff\xff\xa7\x15\xa5\x80\xff\xff\xff\xff\xa83\xc9\x10\xff\xff\xff\xff\xa8\xfe\xc2\x00\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xd5U\xe3\x10\xff\xff\xff\xff\xd6 \xdc\x00\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x08 \xdd\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x0a\x00\xbf\x90\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x95\xa0\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10LMT\x00MDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeah\x06\xd2V\x07\x00\x00V\x07\x00\x00\x13\x00\x00\x00Canada/NewfoundlandTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbb\x00\x00\x00\x08\x00\x00\x00\x19\xff\xff\xff\xff^=4\xec\xff\xff\xff\xff\x9c\xcfb\x0c\xff\xff\xff\xff\x9d\xa4\xe6\xfc\xff\xff\xff\xff\x9e\xb8~\x8c\xff\xff\xff\xff\x9f\xba\xd6|\xff\xff\xff\xff\xa0\xb6\x88\xdc\xff\xff\xff\xff\xa18\xffL\xff\xff\xff\xff\xa2\x95\x19\x5c\xff\xff\xff\xff\xa3\x84\xfcL\xff\xff\xff\xff\xa4t\xfb\x5c\xff\xff\xff\xff\xa5d\xdeL\xff\xff\xff\xff\xa6^\x17\xdc\xff\xff\xff\xff\xa7D\xc0L\xff\xff\xff\xff\xa8=\xf9\xdc\xff\xff\xff\xff\xa9$\xa2L\xff\xff\xff\xff\xaa\x1d\xdb\xdc\xff\xff\xff\xff\xab\x04\x84L\xff\xff\xff\xff\xab\xfd\xbd\xdc\xff\xff\xff\xff\xac\xe4fL\xff\xff\xff\xff\xad\xdd\x9f\xdc\xff\xff\xff\xff\xae\xcd\x82\xcc\xff\xff\xff\xff\xaf\xbd\x81\xdc\xff\xff\xff\xff\xb0\xadd\xcc\xff\xff\xff\xff\xb1\xa6\x9e\x5c\xff\xff\xff\xff\xb2\x8dF\xcc\xff\xff\xff\xff\xb3\x86\x80\x5c\xff\xff\xff\xff\xb4m(\xcc\xff\xff\xff\xff\xb5fb\x5c\xff\xff\xff\xff\xb6M\x0a\xcc\xff\xff\xff\xff\xb7FD\x5c\xff\xff\xff\xff\xb8,\xec\xcc\xff\xff\xff\xff\xb9&&\x5c\xff\xff\xff\xff\xba\x16\x09L\xff\xff\xff\xff\xbb\x0fB\xdc\xff\xff\xff\xff\xbb\xf5\xebL\xff\xff\xff\xff\xbc\xef$\xdc\xff\xff\xff\xff\xbd\xd5\xcdL\xff\xff\xff\xff\xbe\x9eMl\xff\xff\xff\xff\xbe\xcf\x06\xa8\xff\xff\xff\xff\xbf\xb5\xaf\x18\xff\xff\xff\xff\xc0\xb818\xff\xff\xff\xff\xc1y\xef\xa8\xff\xff\xff\xff\xc2\x98\x138\xff\xff\xff\xff\xc3Y\xd1\xa8\xff\xff\xff\xff\xc4w\xf58\xff\xff\xff\xff\xc59\xb3\xa8\xff\xff\xff\xff\xc6a\x11\xb8\xff\xff\xff\xff\xc7\x19\x95\xa8\xff\xff\xff\xff\xc8@\xf3\xb8\xff\xff\xff\xff\xc9\x02\xb2(\xff\xff\xff\xff\xca \xd5\xb8\xff\xff\xff\xff\xca\xe2\x94(\xff\xff\xff\xff\xcc\x00\xb7\xb8\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xe6\xc8\xff\xff\xff\xff\xd3\x88D\xd8\xff\xff\xff\xff\xd4J\x03H\xff\xff\xff\xff\xd5h&\xd8\xff\xff\xff\xff\xd6)\xe5H\xff\xff\xff\xff\xd7H\x08\xd8\xff\xff\xff\xff\xd8\x09\xc7H\xff\xff\xff\xff\xd9'\xea\xd8\xff\xff\xff\xff\xd9\xe9\xa9H\xff\xff\xff\xff\xdb\x11\x07X\xff\xff\xff\xff\xdb\xd2\xc5\xc8\xff\xff\xff\xff\xdc\xdetX\xff\xff\xff\xff\xdd\xa9mH\xff\xff\xff\xff\xde\xbeVX\xff\xff\xff\xff\xdf\x89OH\xff\xff\xff\xff\xe0\x9e8X\xff\xff\xff\xff\xe1i1H\xff\xff\xff\xff\xe2~\x1aX\xff\xff\xff\xff\xe3I\x13H\xff\xff\xff\xff\xe4]\xfcX\xff\xff\xff\xff\xe5(\xf5H\xff\xff\xff\xff\xe6G\x18\xd8\xff\xff\xff\xff\xe7\x12\x11\xc8\xff\xff\xff\xff\xe8&\xfa\xd8\xff\xff\xff\xff\xe8\xf1\xf3\xc8\xff\xff\xff\xff\xea\x06\xdc\xd8\xff\xff\xff\xff\xea\xd1\xd5\xc8\xff\xff\xff\xff\xeb\xe6\xbe\xd8\xff\xff\xff\xff\xec\xb1\xb7\xc8\xff\xff\xff\xff\xed\xc6\xa0\xd8\xff\xff\xff\xff\xee\xbf\xbeH\xff\xff\xff\xff\xef\xaf\xbdX\xff\xff\xff\xff\xf0\x9f\xa0H\xff\xff\xff\xff\xf1\x8f\x9fX\xff\xff\xff\xff\xf2\x7f\x82H\xff\xff\xff\xff\xf3o\x81X\xff\xff\xff\xff\xf4_dH\xff\xff\xff\xff\xf5OcX\xff\xff\xff\xff\xf6?FH\xff\xff\xff\xff\xf7/EX\xff\xff\xff\xff\xf8(b\xc8\xff\xff\xff\xff\xf9\x0f'X\xff\xff\xff\xff\xfa\x08D\xc8\xff\xff\xff\xff\xfa\xf8C\xd8\xff\xff\xff\xff\xfb\xe8&\xc8\xff\xff\xff\xff\xfc\xd8%\xd8\xff\xff\xff\xff\xfd\xc8\x08\xc8\xff\xff\xff\xff\xfe\xb8\x07\xd8\xff\xff\xff\xff\xff\xa7\xea\xc8\x00\x00\x00\x00\x00\x97\xe9\xd8\x00\x00\x00\x00\x01\x87\xcc\xc8\x00\x00\x00\x00\x02w\xcb\xd8\x00\x00\x00\x00\x03p\xe9H\x00\x00\x00\x00\x04`\xe8X\x00\x00\x00\x00\x05P\xcbH\x00\x00\x00\x00\x06@\xcaX\x00\x00\x00\x00\x070\xadH\x00\x00\x00\x00\x08 \xacX\x00\x00\x00\x00\x09\x10\x8fH\x00\x00\x00\x00\x0a\x00\x8eX\x00\x00\x00\x00\x0a\xf0qH\x00\x00\x00\x00\x0b\xe0pX\x00\x00\x00\x00\x0c\xd9\x8d\xc8\x00\x00\x00\x00\x0d\xc0RX\x00\x00\x00\x00\x0e\xb9o\xc8\x00\x00\x00\x00\x0f\xa9n\xd8\x00\x00\x00\x00\x10\x99Q\xc8\x00\x00\x00\x00\x11\x89P\xd8\x00\x00\x00\x00\x12y3\xc8\x00\x00\x00\x00\x13i2\xd8\x00\x00\x00\x00\x14Y\x15\xc8\x00\x00\x00\x00\x15I\x14\xd8\x00\x00\x00\x00\x168\xf7\xc8\x00\x00\x00\x00\x17(\xf6\xd8\x00\x00\x00\x00\x18\x22\x14H\x00\x00\x00\x00\x19\x08\xd8\xd8\x00\x00\x00\x00\x1a\x01\xf6H\x00\x00\x00\x00\x1a\xf1\xf5X\x00\x00\x00\x00\x1b\xe1\xd8H\x00\x00\x00\x00\x1c\xd1\xd7X\x00\x00\x00\x00\x1d\xc1\xbaH\x00\x00\x00\x00\x1e\xb1\xb9X\x00\x00\x00\x00\x1f\xa1\x9cH\x00\x00\x00\x00 u\xcf\xf4\x00\x00\x00\x00!\x81bd\x00\x00\x00\x00\x22U\xb1\xf4\x00\x00\x00\x00#jp\xd4\x00\x00\x00\x00$5\x93\xf4\x00\x00\x00\x00%J`\xe4\x00\x00\x00\x00&\x15u\xf4\x00\x00\x00\x00'*B\xe4\x00\x00\x00\x00'\xfe\x92t\x00\x00\x00\x00)\x0a$\xe4\x00\x00\x00\x00)\xdett\x00\x00\x00\x00*\xea\x06\xe4\x00\x00\x00\x00+\xbeVt\x00\x00\x00\x00,\xd3#d\x00\x00\x00\x00-\x9e8t\x00\x00\x00\x00.\xb3\x05d\x00\x00\x00\x00/~\x1at\x00\x00\x00\x000\x92\xe7d\x00\x00\x00\x001g6\xf4\x00\x00\x00\x002r\xc9d\x00\x00\x00\x003G\x18\xf4\x00\x00\x00\x004R\xabd\x00\x00\x00\x005&\xfa\xf4\x00\x00\x00\x0062\x8dd\x00\x00\x00\x007\x06\xdc\xf4\x00\x00\x00\x008\x1b\xa9\xe4\x00\x00\x00\x008\xe6\xbe\xf4\x00\x00\x00\x009\xfb\x8b\xe4\x00\x00\x00\x00:\xc6\xa0\xf4\x00\x00\x00\x00;\xdbm\xe4\x00\x00\x00\x00<\xaf\xbdt\x00\x00\x00\x00=\xbbO\xe4\x00\x00\x00\x00>\x8f\x9ft\x00\x00\x00\x00?\x9b1\xe4\x00\x00\x00\x00@o\x81t\x00\x00\x00\x00A\x84Nd\x00\x00\x00\x00BOct\x00\x00\x00\x00Cd0d\x00\x00\x00\x00D/Et\x00\x00\x00\x00ED\x12d\x00\x00\x00\x00E\xf3w\xf4\x00\x00\x00\x00G-.\xe4\x00\x00\x00\x00G\xd3Y\xf4\x00\x00\x00\x00I\x0d\x10\xe4\x00\x00\x00\x00I\xb3;\xf4\x00\x00\x00\x00J\xec\xf2\xe4\x00\x00\x00\x00K\x9cXt\x00\x00\x00\x00L\xd6\x0fd\x00\x00\x00\x00M|:t\x00\x00\x00\x00N\xafY\xa8\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x06\x05\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x07\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x03\xff\xff\xce\x94\x00\x00\xff\xff\xdc\xa4\x01\x04\xff\xff\xce\x94\x00\x08\xff\xff\xdc\xd8\x01\x04\xff\xff\xce\xc8\x00\x08\xff\xff\xdc\xd8\x01\x0c\xff\xff\xdc\xd8\x01\x10\xff\xff\xea\xe8\x01\x14LMT\x00NDT\x00NST\x00NPT\x00NWT\x00NDDT\x00\x0aNST3:30NDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U9#\xbe2\x05\x00\x002\x05\x00\x00\x0e\x00\x00\x00Canada/PacificTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^=v\xec\xff\xff\xff\xff\x9e\xb8\xbd\xa0\xff\xff\xff\xff\x9f\xbb\x15\x90\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xd3v\x0f \xff\xff\xff\xff\xd4A\x08\x10\xff\xff\xff\xff\xd5U\xf1 \xff\xff\xff\xff\xd6 \xea\x10\xff\xff\xff\xff\xd75\xd3 \xff\xff\xff\xff\xd8\x00\xcc\x10\xff\xff\xff\xff\xd9\x15\xb5 \xff\xff\xff\xff\xd9\xe0\xae\x10\xff\xff\xff\xff\xda\xfe\xd1\xa0\xff\xff\xff\xff\xdb\xc0\x90\x10\xff\xff\xff\xff\xdc\xde\xb3\xa0\xff\xff\xff\xff\xdd\xa9\xac\x90\xff\xff\xff\xff\xde\xbe\x95\xa0\xff\xff\xff\xff\xdf\x89\x8e\x90\xff\xff\xff\xff\xe0\x9ew\xa0\xff\xff\xff\xff\xe1ip\x90\xff\xff\xff\xff\xe2~Y\xa0\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^;\xa0\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GX \xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8': \xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x1c \xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xfe \xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xe0 \xff\xff\xff\xff\xee\x91\xd9\x10\xff\xff\xff\xff\xef\xaf\xfc\xa0\xff\xff\xff\xff\xf0q\xbb\x10\xff\xff\xff\xff\xf1\x8f\xde\xa0\xff\xff\xff\xff\xf2\x7f\xc1\x90\xff\xff\xff\xff\xf3o\xc0\xa0\xff\xff\xff\xff\xf4_\xa3\x90\xff\xff\xff\xff\xf5O\xa2\xa0\xff\xff\xff\xff\xf6?\x85\x90\xff\xff\xff\xff\xf7/\x84\xa0\xff\xff\xff\xff\xf8(\xa2\x10\xff\xff\xff\xff\xf9\x0ff\xa0\xff\xff\xff\xff\xfa\x08\x84\x10\xff\xff\xff\xff\xfa\xf8\x83 \xff\xff\xff\xff\xfb\xe8f\x10\xff\xff\xff\xff\xfc\xd8e \xff\xff\xff\xff\xfd\xc8H\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x08 \xeb\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x0a\x00\xcd\xa0\x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x8c\x94\x00\x00\xff\xff\x9d\x90\x01\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10LMT\x00PDT\x00PST\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc2\x96dK~\x02\x00\x00~\x02\x00\x00\x13\x00\x00\x00Canada/SaskatchewanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\x86\xfd\x93\x1c\xff\xff\xff\xff\x9e\xb8\xaf\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xb5eO\xf0\xff\xff\xff\xff\xb60H\xe0\xff\xff\xff\xff\xb7E1\xf0\xff\xff\xff\xff\xb8\x10*\xe0\xff\xff\xff\xff\xb9%\x13\xf0\xff\xff\xff\xff\xb9\xf0\x0c\xe0\xff\xff\xff\xff\xbb\x0e0p\xff\xff\xff\xff\xbb\xcf\xee\xe0\xff\xff\xff\xff\xbc\xee\x12p\xff\xff\xff\xff\xbd\xb9\x0b`\xff\xff\xff\xff\xc2r\x08\xf0\xff\xff\xff\xff\xc3a\xeb\xe0\xff\xff\xff\xff\xc4Q\xea\xf0\xff\xff\xff\xff\xc58\x93`\xff\xff\xff\xff\xc61\xcc\xf0\xff\xff\xff\xff\xc7!\xaf\xe0\xff\xff\xff\xff\xc8\x1a\xe9p\xff\xff\xff\xff\xc9\x0a\xcc`\xff\xff\xff\xff\xc9\xfa\xcbp\xff\xff\xff\xff\xca\xea\xae`\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xd3c\x8c\x10\xff\xff\xff\xff\xd4So\x00\xff\xff\xff\xff\xd5U\xe3\x10\xff\xff\xff\xff\xd6 \xdc\x00\xff\xff\xff\xff\xd75\xc5\x10\xff\xff\xff\xff\xd8\x00\xbe\x00\xff\xff\xff\xff\xd9\x15\xa7\x10\xff\xff\xff\xff\xd9\xe0\xa0\x00\xff\xff\xff\xff\xda\xfe\xc3\x90\xff\xff\xff\xff\xdb\xc0\x82\x00\xff\xff\xff\xff\xdc\xde\xa5\x90\xff\xff\xff\xff\xdd\xa9\x9e\x80\xff\xff\xff\xff\xde\xbe\x87\x90\xff\xff\xff\xff\xdf\x89\x80\x80\xff\xff\xff\xff\xe0\x9ei\x90\xff\xff\xff\xff\xe1ib\x80\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3ID\x80\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)&\x80\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12C\x00\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf2%\x00\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xd6\xd3\x00\xff\xff\xff\xff\xed\xc6\xd2\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\xff\xff\x9d\xe4\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10\xff\xff\xab\xa0\x00\x14LMT\x00MDT\x00MST\x00MWT\x00MPT\x00CST\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\x1d\xee\x91\x05\x04\x00\x00\x05\x04\x00\x00\x0c\x00\x00\x00Canada/YukonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x00\x00\x00\x09\x00\x00\x00%\xff\xff\xff\xff}\x86\x8a\x9c\xff\xff\xff\xff\x9e\xb8\xcb\xb0\xff\xff\xff\xff\x9f\xbb#\xa0\xff\xff\xff\xff\xa0\xd0\x0c\xb0\xff\xff\xff\xff\xa1\xa2\xd2\x80\xff\xff\xff\xff\xcb\x89(\xb0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a4 \xff\xff\xff\xff\xf7/v\x90\xff\xff\xff\xff\xf8(\xa2\x10\xff\xff\xff\xff\xf8\xc5\x84\x90\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x00\x00\x00\x00G-\x8a\x10\x00\x00\x00\x00G\xd3\xb5 \x00\x00\x00\x00I\x0dl\x10\x00\x00\x00\x00I\xb3\x97 \x00\x00\x00\x00J\xedN\x10\x00\x00\x00\x00K\x9c\xb3\xa0\x00\x00\x00\x00L\xd6j\x90\x00\x00\x00\x00M|\x95\xa0\x00\x00\x00\x00N\xb6L\x90\x00\x00\x00\x00O\x5cw\xa0\x00\x00\x00\x00P\x96.\x90\x00\x00\x00\x00QO@\x00\x00\x00\x00\x06\x00\x0d\xb0\x00\x00\x00\x00\x07\x0b\xbc@\x00\x00\x00\x00\x07\xdf\xef\xb0\x00\x00\x00\x00\x08\xfe\x13@\x00\x00\x00\x00\x09\xbf\xd1\xb0\x00\x00\x00\x00\x0a\xdd\xf5@\x00\x00\x00\x00\x0b\xa8\xee0\x00\x00\x00\x00\x0c\xbd\xd7@\x00\x00\x00\x00\x0d\x88\xd00\x00\x00\x00\x00\x0e\x9d\xb9@\x00\x00\x00\x00\x0fh\xb20\x00\x00\x00\x00\x10\x86\xd5\xc0\x00\x00\x00\x00\x11H\x940\x00\x00\x00\x00\x12f\xb7\xc0\x00\x00\x00\x00\x13(v0\x00\x00\x00\x00\x14F\x99\xc0\x00\x00\x00\x00\x15\x11\x92\xb0\x00\x00\x00\x00\x16&{\xc0\x00\x00\x00\x00\x16\xf1t\xb0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x18\xd1V\xb0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xb18\xb0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\x91\x1a\xb0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ep\xfc\xb0\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 \x7f\x030\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x229\xfb0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$\x19\xdd0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xf9\xbf0\x00\x00\x00\x00&\xf2\xf8\xc0\x00\x00\x00\x00'\xd9\xa10\x00\x00\x00\x00(\xf7\xc4\xc0\x00\x00\x00\x00)\xc2\xbd\xb0\x00\x00\x00\x00*\xd7\xa6\xc0\x00\x00\x00\x00+\xa2\x9f\xb0\x00\x00\x00\x00,\xb7\x88\xc0\x00\x00\x00\x00-\x82\x81\xb0\x00\x00\x00\x00.\x97j\xc0\x00\x00\x00\x00/bc\xb0\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001BE\xb0\x00\x00\x00\x002`i@\x00\x00\x00\x003=\xd70\x00\x00\x00\x004@K@\x00\x00\x00\x005\x0bD0\x00\x00\x00\x006\x0d\xb8@\x00\x00\x00\x007\x06\xd5\xb0\x00\x00\x00\x008\x00\x0f@\x00\x00\x00\x008\xcb\x080\x00\x00\x00\x009\xe9+\xc0\x00\x00\x00\x00:\xaa\xea0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00<\x8a\xcc0\x00\x00\x00\x00=\xa8\xef\xc0\x00\x00\x00\x00>j\xae0\x00\x00\x00\x00?\x88\xd1\xc0\x00\x00\x00\x00@S\xca\xb0\x00\x00\x00\x00Ah\xb3\xc0\x00\x00\x00\x00B3\xac\xb0\x00\x00\x00\x00CH\x95\xc0\x00\x00\x00\x00D\x13\x8e\xb0\x00\x00\x00\x00E1\xb2@\x00\x00\x00\x00E\xf3p\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xef\x020\x00\x00\x00\x00H\xf1v@\x00\x00\x00\x00I\xbco0\x00\x00\x00\x00J\xd1X@\x00\x00\x00\x00K\xb8\x00\xb0\x00\x00\x00\x00L\xb1:@\x00\x00\x00\x00M\xc6\x070\x00\x00\x00\x00NP\x82\xc0\x00\x00\x00\x00O\x9c\xae\xb0\x00\x00\x00\x00PB\xd9\xc0\x00\x00\x00\x00Q|\x90\xb0\x00\x00\x00\x00R+\xf6@\x00\x00\x00\x00S\x5cr\xb0\x00\x00\x00\x00T\x0b\xd8@\x00\x00\x00\x00W7\xe60\x00\x00\x00\x00W\xaf\xec\xc0\x00\x00\x00\x00Y\x17\xc80\x00\x00\x00\x00Y\x8f\xce\xc0\x00\x00\x00\x00Z\xf7\xaa0\x00\x00\x00\x00[o\xb0\xc0\x00\x00\x00\x00\x5c\xa9g\xb0\x00\x00\x00\x00]t|\xc0\x00\x00\x00\x00^\x89I\xb0\x00\x00\x00\x00_T^\xc0\x00\x00\x00\x00`i+\xb0\x00\x00\x00\x00a4@\xc0\x00\x00\x00\x00bI\x0d\xb0\x00\x00\x00\x00c\x1d]@\x00\x00\x00\x00d(\xef\xb0\x01\x02\x01\x03\x01\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x03\x02\x03\x05\x04\x02\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\xff\xff\xbd\xbb\x00\x00\xff\xff\xbd\xbb\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x00\x0c\xff\xff\xc7\xc0\x01\x0c\xff\xff\xd5\xd0\x01\x10LMT\x00SMT\x00-05\x00-04\x00-03\x00\x0a<-04>4<-03>,M9.1.6/24,M4.1.6/24\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?X'\x8e\x96\x04\x00\x00\x96\x04\x00\x00\x12\x00\x00\x00Chile/EasterIslandTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffi\x87B\x08\xff\xff\xff\xff\xb9\xc7@\x88\xff\xff\xff\xff\xfd\xd1<@\xff\xff\xff\xff\xfe\x92\xfa\xb0\xff\xff\xff\xff\xff\xcc\xcd\xc0\x00\x00\x00\x00\x00r\xdc\xb0\x00\x00\x00\x00\x01uP\xc0\x00\x00\x00\x00\x02@I\xb0\x00\x00\x00\x00\x03U2\xc0\x00\x00\x00\x00\x04 +\xb0\x00\x00\x00\x00\x05>O@\x00\x00\x00\x00\x06\x00\x0d\xb0\x00\x00\x00\x00\x07\x0b\xbc@\x00\x00\x00\x00\x07\xdf\xef\xb0\x00\x00\x00\x00\x08\xfe\x13@\x00\x00\x00\x00\x09\xbf\xd1\xb0\x00\x00\x00\x00\x0a\xdd\xf5@\x00\x00\x00\x00\x0b\xa8\xee0\x00\x00\x00\x00\x0c\xbd\xd7@\x00\x00\x00\x00\x0d\x88\xd00\x00\x00\x00\x00\x0e\x9d\xb9@\x00\x00\x00\x00\x0fh\xb20\x00\x00\x00\x00\x10\x86\xd5\xc0\x00\x00\x00\x00\x11H\x940\x00\x00\x00\x00\x12f\xb7\xc0\x00\x00\x00\x00\x13(v0\x00\x00\x00\x00\x14F\x99\xc0\x00\x00\x00\x00\x15\x11\x92\xb0\x00\x00\x00\x00\x16&{\xc0\x00\x00\x00\x00\x16\xf1t\xb0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x18\xd1V\xb0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xb18\xb0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\x91\x1a\xb0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ep\xfc\xb0\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 \x7f\x030\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x229\xfb0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$\x19\xdd0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xf9\xbf0\x00\x00\x00\x00&\xf2\xf8\xc0\x00\x00\x00\x00'\xd9\xa10\x00\x00\x00\x00(\xf7\xc4\xc0\x00\x00\x00\x00)\xc2\xbd\xb0\x00\x00\x00\x00*\xd7\xa6\xc0\x00\x00\x00\x00+\xa2\x9f\xb0\x00\x00\x00\x00,\xb7\x88\xc0\x00\x00\x00\x00-\x82\x81\xb0\x00\x00\x00\x00.\x97j\xc0\x00\x00\x00\x00/bc\xb0\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001BE\xb0\x00\x00\x00\x002`i@\x00\x00\x00\x003=\xd70\x00\x00\x00\x004@K@\x00\x00\x00\x005\x0bD0\x00\x00\x00\x006\x0d\xb8@\x00\x00\x00\x007\x06\xd5\xb0\x00\x00\x00\x008\x00\x0f@\x00\x00\x00\x008\xcb\x080\x00\x00\x00\x009\xe9+\xc0\x00\x00\x00\x00:\xaa\xea0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00<\x8a\xcc0\x00\x00\x00\x00=\xa8\xef\xc0\x00\x00\x00\x00>j\xae0\x00\x00\x00\x00?\x88\xd1\xc0\x00\x00\x00\x00@S\xca\xb0\x00\x00\x00\x00Ah\xb3\xc0\x00\x00\x00\x00B3\xac\xb0\x00\x00\x00\x00CH\x95\xc0\x00\x00\x00\x00D\x13\x8e\xb0\x00\x00\x00\x00E1\xb2@\x00\x00\x00\x00E\xf3p\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xef\x020\x00\x00\x00\x00H\xf1v@\x00\x00\x00\x00I\xbco0\x00\x00\x00\x00J\xd1X@\x00\x00\x00\x00K\xb8\x00\xb0\x00\x00\x00\x00L\xb1:@\x00\x00\x00\x00M\xc6\x070\x00\x00\x00\x00NP\x82\xc0\x00\x00\x00\x00O\x9c\xae\xb0\x00\x00\x00\x00PB\xd9\xc0\x00\x00\x00\x00Q|\x90\xb0\x00\x00\x00\x00R+\xf6@\x00\x00\x00\x00S\x5cr\xb0\x00\x00\x00\x00T\x0b\xd8@\x00\x00\x00\x00W7\xe60\x00\x00\x00\x00W\xaf\xec\xc0\x00\x00\x00\x00Y\x17\xc80\x00\x00\x00\x00Y\x8f\xce\xc0\x00\x00\x00\x00Z\xf7\xaa0\x00\x00\x00\x00[o\xb0\xc0\x00\x00\x00\x00\x5c\xa9g\xb0\x00\x00\x00\x00]t|\xc0\x00\x00\x00\x00^\x89I\xb0\x00\x00\x00\x00_T^\xc0\x00\x00\x00\x00`i+\xb0\x00\x00\x00\x00a4@\xc0\x00\x00\x00\x00bI\x0d\xb0\x00\x00\x00\x00c\x1d]@\x00\x00\x00\x00d(\xef\xb0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\xff\xff\x99x\x00\x00\xff\xff\x99x\x00\x04\xff\xff\xab\xa0\x01\x08\xff\xff\x9d\x90\x00\x0c\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x10LMT\x00EMT\x00-06\x00-07\x00-05\x00\x0a<-06>6<-05>,M9.1.6/22,M4.1.6/22\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x1c\x9e\x9a]\x04\x00\x00]\x04\x00\x00\x04\x00\x00\x00CubaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffi\x87(\xb8\xff\xff\xff\xff\xacb\xc2\x80\xff\xff\xff\xff\xb1\xd3\x94P\xff\xff\xff\xff\xb2t]@\xff\xff\xff\xff\xc8[f\xd0\xff\xff\xff\xff\xc8\xd3Q@\xff\xff\xff\xff\xca;H\xd0\xff\xff\xff\xff\xca\xbcm\xc0\xff\xff\xff\xff\xcc$eP\xff\xff\xff\xff\xcc\x9cO\xc0\xff\xff\xff\xff\xd1\xc4\x0bP\xff\xff\xff\xff\xd2;\xf5\xc0\xff\xff\xff\xff\xd3\xa3\xedP\xff\xff\xff\xff\xd4\x1b\xd7\xc0\xff\xff\xff\xff\xf7`\x05\xd0\xff\xff\xff\xff\xf7\xff}@\xff\xff\xff\xff\xf9=D\xd0\xff\xff\xff\xff\xf9\xe3S\xc0\xff\xff\xff\xff\xfa\xdb;\xd0\xff\xff\xff\xff\xfb\xa7\x86@\xff\xff\xff\xff\xfc\xc5\xa9\xd0\xff\xff\xff\xff\xfd\x87h@\xff\xff\xff\xff\xfe\xb8\x00\xd0\xff\xff\xff\xff\xff\xa7\xe3\xc0\x00\x00\x00\x00\x00\x97\xe2\xd0\x00\x00\x00\x00\x01\x87\xc5\xc0\x00\x00\x00\x00\x02w\xc4\xd0\x00\x00\x00\x00\x03p\xe2@\x00\x00\x00\x00\x04`\xe1P\x00\x00\x00\x00\x055\x14\xc0\x00\x00\x00\x00\x06@\xc3P\x00\x00\x00\x00\x07\x16H@\x00\x00\x00\x00\x08 \xa5P\x00\x00\x00\x00\x08\xf7{\xc0\x00\x00\x00\x00\x0a\x00\x87P\x00\x00\x00\x00\x0a\xf0j@\x00\x00\x00\x00\x0b\xe0iP\x00\x00\x00\x00\x0c\xd9\x86\xc0\x00\x00\x00\x00\x0d\xc0KP\x00\x00\x00\x00\x0e\xb9h\xc0\x00\x00\x00\x00\x0f\xb2\xa2P\x00\x00\x00\x00\x10}\x9b@\x00\x00\x00\x00\x11Q\xea\xd0\x00\x00\x00\x00\x12f\xb7\xc0\x00\x00\x00\x00\x131\xcc\xd0\x00\x00\x00\x00\x14F\x99\xc0\x00\x00\x00\x00\x15[\x82\xd0\x00\x00\x00\x00\x16&{\xc0\x00\x00\x00\x00\x17;d\xd0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x19\x1bF\xd0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xfb(\xd0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\xdb\x0a\xd0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ezSP\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 Z5P\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x22CQ\xd0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$#3\xd0\x00\x00\x00\x00%.\xc6@\x00\x00\x00\x00&\x15\x8a\xd0\x00\x00\x00\x00'\x17\xe2\xc0\x00\x00\x00\x00'\xfe\xa7P\x00\x00\x00\x00(\xf7\xd2\xd0\x00\x00\x00\x00)\xde\x89P\x00\x00\x00\x00*\xd7\xb4\xd0\x00\x00\x00\x00+\xbekP\x00\x00\x00\x00,\xb7\x96\xd0\x00\x00\x00\x00-\x9eMP\x00\x00\x00\x00.\x97x\xd0\x00\x00\x00\x00/~/P\x00\x00\x00\x000wZ\xd0\x00\x00\x00\x001gK\xd0\x00\x00\x00\x002W<\xd0\x00\x00\x00\x003G-\xd0\x00\x00\x00\x004@YP\x00\x00\x00\x005\x1d\xd5P\x00\x00\x00\x0062\xb0P\x00\x00\x00\x006\xfd\xb7P\x00\x00\x00\x008\x1b\xcc\xd0\x00\x00\x00\x008\xe6\xd3\xd0\x00\x00\x00\x009\xfb\xae\xd0\x00\x00\x00\x00:\xc6\xb5\xd0\x00\x00\x00\x00;\xdb\x90\xd0\x00\x00\x00\x00<\xaf\xd2P\x00\x00\x00\x00=\xbbr\xd0\x00\x00\x00\x00>\x8f\xb4P\x00\x00\x00\x00?\x9bT\xd0\x00\x00\x00\x00@f[\xd0\x00\x00\x00\x00ED5P\x00\x00\x00\x00E\xf3\x8c\xd0\x00\x00\x00\x00G$\x17P\x00\x00\x00\x00G\xdc\xa9P\x00\x00\x00\x00I\x03\xf9P\x00\x00\x00\x00I\xb3P\xd0\x00\x00\x00\x00J\xe3\xdbP\x00\x00\x00\x00K\x9cmP\x00\x00\x00\x00L\xcc\xf7\xd0\x00\x00\x00\x00M\x85\x89\xd0\x00\x00\x00\x00N\xbfN\xd0\x00\x00\x00\x00Ow\xe0\xd0\x00\x00\x00\x00P\x95\xf6P\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\xff\xff\xb2\xc8\x00\x00\xff\xff\xb2\xc0\x00\x04\xff\xff\xc7\xc0\x01\x08\xff\xff\xb9\xb0\x00\x0cLMT\x00HMT\x00CDT\x00CST\x00\x0aCST5CDT,M3.2.0/0,M11.1.0/1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`l\x8d~\xf1\x01\x00\x00\xf1\x01\x00\x00\x03\x00\x00\x00EETTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x02\x00\x00\x00\x09\x00\x00\x00\x00\x0d\xa4c\x90\x00\x00\x00\x00\x0e\x8b\x1a\x10\x00\x00\x00\x00\x0f\x84E\x90\x00\x00\x00\x00\x10t6\x90\x00\x00\x00\x00\x11d'\x90\x00\x00\x00\x00\x12T\x18\x90\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x01\x00\x01\x00\x02\x03\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\xff\xff\xb9\xb0\x00\x04\xff\xff\xc7\xc0\x01\x00\xff\xff\xc7\xc0\x01\x08\xff\xff\xc7\xc0\x01\x0cEDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5#)\x16\x1d\x05\x00\x00\x1d\x05\x00\x00\x05\x00\x00\x00EgyptTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xff}\xbdM\xab\xff\xff\xff\xff\xc8\x93\xb4\xe0\xff\xff\xff\xff\xc8\xfa{\xd0\xff\xff\xff\xff\xc9\xfc\xef\xe0\xff\xff\xff\xff\xca\xc7\xe8\xd0\xff\xff\xff\xff\xcb\xcb\xae`\xff\xff\xff\xff\xcc\xdf)\xd0\xff\xff\xff\xff\xcd\xac\xe1\xe0\xff\xff\xff\xff\xce\xc6\xf4\xd0\xff\xff\xff\xff\xcf\x8ff\xe0\xff\xff\xff\xff\xd0\xa9y\xd0\xff\xff\xff\xff\xd1\x84`\xe0\xff\xff\xff\xff\xd2\x8a\xadP\xff\xff\xff\xff\xe86c`\xff\xff\xff\xff\xe8\xf4-P\xff\xff\xff\xff\xea\x0b\xb9`\xff\xff\xff\xff\xea\xd5`\xd0\xff\xff\xff\xff\xeb\xec\xfa\xf0\xff\xff\xff\xff\xec\xb5m\x00\xff\xff\xff\xff\xed\xcf\x7f\xf0\xff\xff\xff\xff\xee\x97\xf2\x00\xff\xff\xff\xff\xef\xb0\xb3p\xff\xff\xff\xff\xf0y%\x80\xff\xff\xff\xff\xf1\x91\xe6\xf0\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3s\x1ap\xff\xff\xff\xff\xf4;\x8c\x80\xff\xff\xff\xff\xf5U\x9fp\xff\xff\xff\xff\xf6\x1e\x11\x80\xff\xff\xff\xff\xf76\xd2\xf0\xff\xff\xff\xff\xf7\xffE\x00\xff\xff\xff\xff\xf9\x18\x06p\xff\xff\xff\xff\xf9\xe1\xca\x00\xff\xff\xff\xff\xfa\xf99\xf0\xff\xff\xff\xff\xfb\xc2\xfd\x80\xff\xff\xff\xff\xfc\xdb\xbe\xf0\xff\xff\xff\xff\xfd\xa5\x82\x80\xff\xff\xff\xff\xfe\xbc\xf2p\xff\xff\xff\xff\xff\x86\xb6\x00\x00\x00\x00\x00\x00\x9e%\xf0\x00\x00\x00\x00\x01g\xe9\x80\x00\x00\x00\x00\x02\x7fYp\x00\x00\x00\x00\x03I\x1d\x00\x00\x00\x00\x00\x04a\xdep\x00\x00\x00\x00\x05+\xa2\x00\x00\x00\x00\x00\x06C\x11\xf0\x00\x00\x00\x00\x07\x0c\xd5\x80\x00\x00\x00\x00\x08$Ep\x00\x00\x00\x00\x08\xee\x09\x00\x00\x00\x00\x00\x0a\x05x\xf0\x00\x00\x00\x00\x0a\xcf<\x80\x00\x00\x00\x00\x0b\xe7\xfd\xf0\x00\x00\x00\x00\x0c\xb1\xc1\x80\x00\x00\x00\x00\x0d\xc91p\x00\x00\x00\x00\x0e\x92\xf5\x00\x00\x00\x00\x00\x0f\xaad\xf0\x00\x00\x00\x00\x10t(\x80\x00\x00\x00\x00\x11\x8b\x98p\x00\x00\x00\x00\x12U\x5c\x00\x00\x00\x00\x00\x13n\x1dp\x00\x00\x00\x00\x147\xe1\x00\x00\x00\x00\x00\x15OP\xf0\x00\x00\x00\x00\x16\x19\x14\x80\x00\x00\x00\x00\x17\xa0\x93\xf0\x00\x00\x00\x00\x17\xfaH\x00\x00\x00\x00\x00\x19p\xa3\xf0\x00\x00\x00\x00\x19\xdb{\x80\x00\x00\x00\x00\x1a\xf4<\xf0\x00\x00\x00\x00\x1b\xbe\x00\x80\x00\x00\x00\x00\x1c\xd5pp\x00\x00\x00\x00\x1d\x9f4\x00\x00\x00\x00\x00\x1e\xb6\xa3\xf0\x00\x00\x00\x00\x1f\x80g\x80\x00\x00\x00\x00 \x97\xd7p\x00\x00\x00\x00!a\x9b\x00\x00\x00\x00\x00\x22z\x5cp\x00\x00\x00\x00#D \x00\x00\x00\x00\x00$b'p\x00\x00\x00\x00%%S\x80\x00\x00\x00\x00&<\xc3p\x00\x00\x00\x00'\x06\x87\x00\x00\x00\x00\x00(\x1d\xf6\xf0\x00\x00\x00\x00(\xe7\xba\x80\x00\x00\x00\x00*\x00{\xf0\x00\x00\x00\x00*\xca?\x80\x00\x00\x00\x00+\xe1\xafp\x00\x00\x00\x00,\xabs\x00\x00\x00\x00\x00-\xc2\xe2\xf0\x00\x00\x00\x00.\x8c\xa6\x80\x00\x00\x00\x00/\xa0\x13\xe0\x00\x00\x00\x000k\x0c\xd0\x00\x00\x00\x001\x7f\xf5\xe0\x00\x00\x00\x002J\xee\xd0\x00\x00\x00\x003_\xd7\xe0\x00\x00\x00\x004*\xd0\xd0\x00\x00\x00\x005?\xb9\xe0\x00\x00\x00\x006\x0a\xb2\xd0\x00\x00\x00\x007(\xd6`\x00\x00\x00\x007\xf3\xcfP\x00\x00\x00\x009\x08\xb8`\x00\x00\x00\x009\xd3\xb1P\x00\x00\x00\x00:\xe8\x9a`\x00\x00\x00\x00;\xb3\x93P\x00\x00\x00\x00<\xc8|`\x00\x00\x00\x00=\x93uP\x00\x00\x00\x00>\xa8^`\x00\x00\x00\x00?sWP\x00\x00\x00\x00@\x91z\xe0\x00\x00\x00\x00A\x5cs\xd0\x00\x00\x00\x00Bq\x5c\xe0\x00\x00\x00\x00C\xe0\x00\x00\x00\x00E\x12\xfdP\x00\x00\x00\x00F1 \xe0\x00\x00\x00\x00F\xe0jP\x00\x00\x00\x00H\x11\x02\xe0\x00\x00\x00\x00H\xb7\x11\xd0\x00\x00\x00\x00I\xf0\xe4\xe0\x00\x00\x00\x00J\x8d\xb9P\x00\x00\x00\x00K\xda\x01`\x00\x00\x00\x00La\xbd\xd0\x00\x00\x00\x00L\x89X\xe0\x00\x00\x00\x00L\xa4\xfaP\x00\x00\x00\x00Su8\xe0\x00\x00\x00\x00S\xac\x89\xd0\x00\x00\x00\x00S\xda\xbc`\x00\x00\x00\x00T$\x82P\x00\x00\x00\x00dJ\xf0`\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00\x1dU\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09LMT\x00EEST\x00EET\x00\x0aEET-2EEST,M4.5.5/0,M10.5.4/24\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1\xd6jL\xd8\x05\x00\x00\xd8\x05\x00\x00\x04\x00\x00\x00EireTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x91\x00\x00\x00\x08\x00\x00\x00\x14\xff\xff\xff\xffW\xd1\x0a\xf1\xff\xff\xff\xff\x9b&\xb3\x91\xff\xff\xff\xff\x9b\xd6\x0b\x11\xff\xff\xff\xff\x9c\xcf0\xa0\xff\xff\xff\xff\x9d\xa4\xc3\xa0\xff\xff\xff\xff\x9e\x9c\x9d\xa0\xff\xff\xff\xff\x9f\x97\x1a\xa0\xff\xff\xff\xff\xa0\x85\xba \xff\xff\xff\xff\xa1v\xfc\xa0\xff\xff\xff\xff\xa2e\x9c \xff\xff\xff\xff\xa3{\xc8\xa0\xff\xff\xff\xff\xa4N\xb8\xa0\xff\xff\xff\xff\xa5?\xfb \xff\xff\xff\xff\xa6%` \xff\xff\xff\xff\xa7'\xc6 \xff\xff\xff\xff\xa8*, \xff\xff\xff\xff\xa8\xeb\xf8\xa0\xff\xff\xff\xff\xaa\x00\xd3\xa0\xff\xff\xff\xff\xaa\xd5\x15 \xff\xff\xff\xff\xab\xe9\xf0 \xff\xff\xff\xff\xac\xc7l \xff\xff\xff\xff\xad\xc9\xd2 \xff\xff\xff\xff\xae\xa7N \xff\xff\xff\xff\xaf\xa0y\xa0\xff\xff\xff\xff\xb0\x870 \xff\xff\xff\xff\xb1\x92\xd0\xa0\xff\xff\xff\xff\xb2pL\xa0\xff\xff\xff\xff\xb3r\xb2\xa0\xff\xff\xff\xff\xb4P.\xa0\xff\xff\xff\xff\xb5IZ \xff\xff\xff\xff\xb60\x10\xa0\xff\xff\xff\xff\xb72v\xa0\xff\xff\xff\xff\xb8\x0f\xf2\xa0\xff\xff\xff\xff\xb9\x12X\xa0\xff\xff\xff\xff\xb9\xef\xd4\xa0\xff\xff\xff\xff\xba\xe9\x00 \xff\xff\xff\xff\xbb\xd8\xf1 \xff\xff\xff\xff\xbc\xdbW \xff\xff\xff\xff\xbd\xb8\xd3 \xff\xff\xff\xff\xbe\xb1\xfe\xa0\xff\xff\xff\xff\xbf\x98\xb5 \xff\xff\xff\xff\xc0\x9b\x1b \xff\xff\xff\xff\xc1x\x97 \xff\xff\xff\xff\xc2z\xfd \xff\xff\xff\xff\xc3Xy \xff\xff\xff\xff\xc4Q\xa4\xa0\xff\xff\xff\xff\xc58[ \xff\xff\xff\xff\xc6:\xc1 \xff\xff\xff\xff\xc7X\xd6\xa0\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xd4I\xe0 \xff\xff\xff\xff\xd5\x1e!\xa0\xff\xff\xff\xff\xd6N\xac \xff\xff\xff\xff\xd7,( \xff\xff\xff\xff\xd8.\x8e \xff\xff\xff\xff\xd8\xf9\x95 \xff\xff\xff\xff\xda\x0ep \xff\xff\xff\xff\xda\xeb\xec \xff\xff\xff\xff\xdb\xe5\x17\xa0\xff\xff\xff\xff\xdc\xcb\xce \xff\xff\xff\xff\xdd\xc4\xf9\xa0\xff\xff\xff\xff\xde\xb4\xea\xa0\xff\xff\xff\xff\xdf\xae\x16 \xff\xff\xff\xff\xe0\x94\xcc\xa0\xff\xff\xff\xff\xe1rH\xa0\xff\xff\xff\xff\xe2kt \xff\xff\xff\xff\xe3R*\xa0\xff\xff\xff\xff\xe4T\x90\xa0\xff\xff\xff\xff\xe52\x0c\xa0\xff\xff\xff\xff\xe6=\xad \xff\xff\xff\xff\xe7\x1b) \xff\xff\xff\xff\xe8\x14T\xa0\xff\xff\xff\xff\xe8\xfb\x0b \xff\xff\xff\xff\xe9\xfdq \xff\xff\xff\xff\xea\xda\xed \xff\xff\xff\xff\xeb\xddS \xff\xff\xff\xff\xec\xba\xcf \xff\xff\xff\xff\xed\xb3\xfa\xa0\xff\xff\xff\xff\xee\x9a\xb1 \xff\xff\xff\xff\xef\x81g\xa0\xff\xff\xff\xff\xf0\x9f} \xff\xff\xff\xff\xf1aI\xa0\xff\xff\xff\xff\xf2\x7f_ \xff\xff\xff\xff\xf3Jf \xff\xff\xff\xff\xf4_A \xff\xff\xff\xff\xf5!\x0d\xa0\xff\xff\xff\xff\xf6?# \xff\xff\xff\xff\xf7\x00\xef\xa0\xff\xff\xff\xff\xf8\x1f\x05 \xff\xff\xff\xff\xf8\xe0\xd1\xa0\xff\xff\xff\xff\xf9\xfe\xe7 \xff\xff\xff\xff\xfa\xc0\xb3\xa0\xff\xff\xff\xff\xfb\xe8\x03\xa0\xff\xff\xff\xff\xfc{\xab\xa0\xff\xff\xff\xff\xfd\xc7\xbbp\x00\x00\x00\x00\x03p\xc6 \x00\x00\x00\x00\x04)X \x00\x00\x00\x00\x05P\xa8 \x00\x00\x00\x00\x06\x09: \x00\x00\x00\x00\x070\x8a \x00\x00\x00\x00\x07\xe9\x1c \x00\x00\x00\x00\x09\x10l \x00\x00\x00\x00\x09\xc8\xfe \x00\x00\x00\x00\x0a\xf0N \x00\x00\x00\x00\x0b\xb2\x1a\xa0\x00\x00\x00\x00\x0c\xd00 \x00\x00\x00\x00\x0d\x91\xfc\xa0\x00\x00\x00\x00\x0e\xb0\x12 \x00\x00\x00\x00\x0fq\xde\xa0\x00\x00\x00\x00\x10\x99.\xa0\x00\x00\x00\x00\x11Q\xc0\xa0\x00\x00\x00\x00\x12y\x10\xa0\x00\x00\x00\x00\x131\xa2\xa0\x00\x00\x00\x00\x14X\xf2\xa0\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x168\xc6\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x18\x18\xa8\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xf8\x8a\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xe1\xa7\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\xc1\x89\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f\xa1k\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x81M\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#a/\x10\x00\x00\x00\x00$,6\x10\x00\x00\x00\x00%JK\x90\x00\x00\x00\x00&\x0c\x18\x10\x00\x00\x00\x00'*-\x90\x00\x00\x00\x00'\xf54\x90\x00\x00\x00\x00)\x0a\x0f\x90\x00\x00\x00\x00)\xd5\x16\x90\x00\x00\x00\x00*\xe9\xf1\x90\x00\x00\x00\x00+\xb4\xf8\x90\x00\x00\x00\x00,\xc9\xd3\x90\x00\x00\x00\x00-\x94\xda\x90\x00\x00\x00\x00.\xa9\xb5\x90\x00\x00\x00\x00/t\xbc\x90\x00\x00\x00\x000\x89\x97\x90\x00\x00\x00\x001]\xd9\x10\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\x06\x07\xff\xff\xfa\x0f\x00\x00\xff\xff\xfa\x0f\x00\x04\x00\x00\x08\x1f\x01\x08\x00\x00\x0e\x10\x01\x0c\x00\x00\x00\x00\x00\x10\x00\x00\x0e\x10\x01\x08\x00\x00\x00\x00\x01\x10\x00\x00\x0e\x10\x00\x08LMT\x00DMT\x00IST\x00BST\x00GMT\x00\x0aIST-1GMT0,M10.5.0,M3.5.0/1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x07\x00\x00\x00Etc/GMTTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00Etc/GMT+0TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\xb8\xe8\x86q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+1TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\xf1\xf0\x00\x00-01\x00\x0a<-01>1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8e\x1569r\x00\x00\x00r\x00\x00\x00\x0a\x00\x00\x00Etc/GMT+10TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xffs`\x00\x00-10\x00\x0a<-10>10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\xb9\xbe\x9dr\x00\x00\x00r\x00\x00\x00\x0a\x00\x00\x00Etc/GMT+11TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xffeP\x00\x00-11\x00\x0a<-11>11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5\xf38cr\x00\x00\x00r\x00\x00\x00\x0a\x00\x00\x00Etc/GMT+12TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xffW@\x00\x00-12\x00\x0a<-12>12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9{\xa2qq\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+2TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\xe3\xe0\x00\x00-02\x00\x0a<-02>2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\xcb\xe9Qq\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+3TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\xd5\xd0\x00\x00-03\x00\x0a<-03>3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd0\xfaFDq\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+4TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\xc7\xc0\x00\x00-04\x00\x0a<-04>4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4X\x9b\xf3q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+5TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\xb9\xb0\x00\x00-05\x00\x0a<-05>5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\x9b\xd1\x04q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+6TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\xab\xa0\x00\x00-06\x00\x0a<-06>6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x84+\x9a$q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+7TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\x9d\x90\x00\x00-07\x00\x0a<-07>7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\xf8\x8f/q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+8TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\x8f\x80\x00\x00-08\x00\x0a<-08>8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x84\x19\xb3\x09q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00Etc/GMT+9TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xff\x81p\x00\x00-09\x00\x0a<-09>9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00Etc/GMT-0TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf7\x1ac\xc3r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-1TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x0e\x10\x00\x00+01\x00\x0a<+01>-1\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9|\xbd7s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00Etc/GMT-10TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x8c\xa0\x00\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xab\xd1Is\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00Etc/GMT-11TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x9a\xb0\x00\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf7\x19s\x81s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00Etc/GMT-12TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\xa8\xc0\x00\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90`N\xe8s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00Etc/GMT-13TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\xb6\xd0\x00\x00+13\x00\x0a<+13>-13\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,{\xdc;s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00Etc/GMT-14TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\xc4\xe0\x00\x00+14\x00\x0a<+14>-14\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbc\x19y\x04r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-2TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x1c \x00\x00+02\x00\x0a<+02>-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9c\xfcm\x99r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-3TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00*0\x00\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00k\x19-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\xd6~wr\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-5TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00FP\x00\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j\xd5d\xb0r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-6TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00T`\x00\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00J0p-r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-7TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00bp\x00\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\x18\xb6\xfbr\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-8TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00p\x80\x00\x00+08\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc\x19@\xb9r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00Etc/GMT-9TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00~\x90\x00\x00+09\x00\x0a<+09>-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x08\x00\x00\x00Etc/GMT0TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x0d\x00\x00\x00Etc/GreenwichTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x07\x00\x00\x00Etc/UCTTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00UTC\x00\x0aUTC0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x07\x00\x00\x00Etc/UTCTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00UTC\x00\x0aUTC0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x0d\x00\x00\x00Etc/UniversalTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00UTC\x00\x0aUTC0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x08\x00\x00\x00Etc/ZuluTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00UTC\x00\x0aUTC0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o\xbc\x831O\x04\x00\x00O\x04\x00\x00\x10\x00\x00\x00Europe/AmsterdamTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\x00\x00\x00\x06\x00\x00\x00\x1a\xff\xff\xff\xffV\xb6\xdf\xe6\xff\xff\xff\xffm\xe8\xc8\x00\xff\xff\xff\xff\x98DI\x80\xff\xff\xff\xff\x9b\x0c%p\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\x9f\xce\xf80\xff\xff\xff\xff\xa0`\xa5\xf0\xff\xff\xff\xff\xa1~\xbbp\xff\xff\xff\xff\xa2.\x12\xf0\xff\xff\xff\xff\xa3zL\xf0\xff\xff\xff\xff\xa45\x81\xf0\xff\xff\xff\xff\xa5^#p\xff\xff\xff\xff\xa6%5\xf0\xff\xff\xff\xff\xa7'\x9b\xf0\xff\xff\xff\xff\xa8*\x01\xf0\xff\xff\xff\xff\xa9\x07}\xf0\xff\xff\xff\xff\xa9\xee4p\xff\xff\xff\xff\xaa\xe7_\xf0\xff\xff\xff\xff\xab\xd7P\xf0\xff\xff\xff\xff\xac\xc7A\xf0\xff\xff\xff\xff\xad\xc9\xa7\xf0\xff\xff\xff\xff\xae\xa7#\xf0\xff\xff\xff\xff\xaf\xa0Op\xff\xff\xff\xff\xb0\x87\x05\xf0\xff\xff\xff\xff\xb1\x89k\xf0\xff\xff\xff\xff\xb2pL\xa0\xff\xff\xff\xff\xb3r\xb2\xa0\xff\xff\xff\xff\xb4P.\xa0\xff\xff\xff\xff\xb5IZ \xff\xff\xff\xff\xb60\x10\xa0\xff\xff\xff\xff\xb72v\xa0\xff\xff\xff\xff\xb8\x0f\xf2\xa0\xff\xff\xff\xff\xb8\xff\xe3\xa0\xff\xff\xff\xff\xb9\xef\xd4\xa0\xff\xff\xff\xff\xba\xd6\x8b \xff\xff\xff\xff\xbb\xd8\xf1 \xff\xff\xff\xff\xbc\xc8\xe2 \xff\xff\xff\xff\xbd\xb8\xd3 \xff\xff\xff\xff\xbe\x9f\x89\xa0\xff\xff\xff\xff\xbf\x98\xb5 \xff\xff\xff\xff\xc0\x9b\x1b \xff\xff\xff\xff\xc1x\x97 \xff\xff\xff\xff\xc2h\x88 \xff\xff\xff\xff\xc3Xy \xff\xff\xff\xff\xc4?/\xa0\xff\xff\xff\xff\xc58[ \xff\xff\xff\xff\xc6:\xc1 \xff\xff\xff\xff\xc7X\xd6\xa0\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xc8J\x19 \xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0n^\x90\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2N@\x90\xff\xff\xff\xff\xd3\x91@\x10\xff\xff\xff\xff\xd4K#\x90\x00\x00\x00\x00\x0d\xa4c\x90\x00\x00\x00\x00\x0e\x8b\x1a\x10\x00\x00\x00\x00\x0f\x84E\x90\x00\x00\x00\x00\x10t6\x90\x00\x00\x00\x00\x11d'\x90\x00\x00\x00\x00\x12T\x18\x90\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xadp\x00\x00\x00\x00G#\xc2\xf0\x00\x00\x00\x00G\xee\xc9\xf0\x00\x00\x00\x00I\x03\xa4\xf0\x00\x00\x00\x00I\xce\xab\xf0\x00\x00\x00\x00J\xe3\x86\xf0\x00\x00\x00\x00K\xae\x8d\xf0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x00\x00\x00\x00TL\x1d`\x00\x00\x00\x00V\xf7\x14p\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x04\x01\x03\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x03\x01\x03\x00\x00-\x0c\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x01\x08\x00\x008@\x00\x0c\x00\x008@\x01\x0cLMT\x00+03\x00+05\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcb*j\x8f\xaa\x02\x00\x00\xaa\x02\x00\x00\x0d\x00\x00\x00Europe/AthensTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x007\x00\x00\x00\x06\x00\x00\x00\x1a\xff\xff\xff\xfft?\x98D\xff\xff\xff\xff\x9b\x80!\x80\xff\xff\xff\xff\xb9|\xe9\xe0\xff\xff\xff\xff\xb9\xc6\xaf\xd0\xff\xff\xff\xff\xc9\xf2c\xe0\xff\xff\xff\xff\xca\x10\xa8P\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xaaL\xf0\xff\xff\xff\xff\xce\xa2\x18\xe0\xff\xff\xff\xff\xcf\x93ip\xff\xff\xff\xff\xdf\x13\x9e`\xff\xff\xff\xff\xdf\xb7\x0aP\x00\x00\x00\x00\x09\xec^`\x00\x00\x00\x00\x0b\x18\xf4`\x00\x00\x00\x00\x0b\xcd\xae\x00\x00\x00\x00\x00\x0c\xbd\x9f\x00\x00\x00\x00\x00\x0d\xa4U\x80\x00\x00\x00\x00\x0e\x8c]\x80\x00\x00\x00\x00\x0f\x847\x80\x00\x00\x00\x00\x10j\xfc\x10\x00\x00\x00\x00\x11d{\xf0\x00\x00\x00\x00\x12R\xaa\xf0\x00\x00\x00\x00\x13F\x82`\x00\x00\x00\x00\x143\xc2P\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\xf3`\xff\xff\xff\xff\xb9\xef\x9c`\xff\xff\xff\xff\xba\xdf\x8d`\xff\xff\xff\xff\xbb\xcf~`\xff\xff\xff\xff\xbc\xc8\xa9\xe0\xff\xff\xff\xff\xbd\xb8\x9a\xe0\xff\xff\xff\xff\xbe\xa8\x8b\xe0\xff\xff\xff\xff\xbf\x98|\xe0\xff\xff\xff\xff\xc0\x88m\xe0\xff\xff\xff\xff\xc1x^\xe0\xff\xff\xff\xff\xc2hO\xe0\xff\xff\xff\xff\xc3X@\xe0\xff\xff\xff\xff\xc4H1\xe0\xff\xff\xff\xff\xc58\x22\xe0\xff\xff\xff\xff\xc6(\x13\xe0\xff\xff\xff\xff\xc7\x18\x04\xe0\x00\x00\x00\x00\x11\xad\xd1`\x00\x00\x00\x00\x12S\xe0P\x00\x00\x00\x00\x13M\x0b\xd0\x00\x00\x00\x00\x143\xd0`\x00\x00\x00\x00\x15#\xdd\x80\x00\x00\x00\x00\x16\x13\xce\x80\x00\x00\x00\x00\x17\x03\xbf\x80\x00\x00\x00\x00\x17\xf3\xb0\x80\x00\x00\x00\x00\x18\xe3\xa1\x80\x00\x00\x00\x00\x19\xd3\x92\x80\x00\x00\x00\x00\x1a\xc3\x83\x80\x00\x00\x00\x00\x1b\xbc\xaf\x00\x00\x00\x00\x00\x1c\xac\xa0\x00\x00\x00\x00\x00\x1d\x9c\x91\x00\x00\x00\x00\x00\x1e\x8c\x82\x00\x00\x00\x00\x00\x1f|s\x00\x00\x00\x00\x00 ld\x00\x00\x00\x00\x00!\x5cU\x00\x00\x00\x00\x00\x22LF\x00\x00\x00\x00\x00#<7\x00\x00\x00\x00\x00$,(\x00\x00\x00\x00\x00%\x1c\x19\x00\x00\x00\x00\x00&\x0c\x0a\x00\x00\x00\x00\x00'\x055\x80\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe4\xfb`\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xdd`\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xbf`\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000duP\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x002\xc9\x8c\xe0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x03\x00\x00\x18x\x00\x00\x00\x00\x18x\x00\x04\x00\x00*0\x01\x08\x00\x00\x1c \x00\x0dLMT\x00BMT\x00EEST\x00EET\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6Kf\xab\xfe\x02\x00\x00\xfe\x02\x00\x00\x0f\x00\x00\x00Europe/BudapestTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xffk\x17\x91\x9c\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xa0\x9a\xc4\x10\xff\xff\xff\xff\xa1dy\x90\xff\xff\xff\xff\xa2p\x1a\x10\xff\xff\xff\xff\xa3M\x96\x10\xff\xff\xff\xff\xc9\xf3\xb5`\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1\x99x\xe0\xff\xff\xff\xff\xd2\x8a\xc9p\xff\xff\xff\xff\xd3P\xa6\x90\xff\xff\xff\xff\xd4K\x15\x80\xff\xff\xff\xff\xd59\xc3\x10\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7\x19\xa5\x10\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\xff\xff\xff\xff\xe2\xa2\xa8\xf0\xff\xff\xff\xff\xe3Q\xf2`\xff\xff\xff\xff\xe4\x82\xa7\x10\xff\xff\xff\xff\xe51\xfe\x90\xff\xff\xff\xff\xe6t\xfe\x10\xff\xff\xff\xff\xe7\x11\xe0\x90\xff\xff\xff\xff\xe8T\xe0\x10\xff\xff\xff\xff\xe8\xf1\xc2\x90\x00\x00\x00\x00\x13M'\xf0\x00\x00\x00\x00\x143\xdep\x00\x00\x00\x00\x15#\xcfp\x00\x00\x00\x00\x16\x13\xc0p\x00\x00\x00\x00\x17\x03\xb1p\x00\x00\x00\x00\x17\xf3\xa2p\x00\x00\x00\x00\x18\xe3\x93p\x00\x00\x00\x00\x19\xd3\x84p\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\xf3`\xff\xff\xff\xff\xb9\xef\x9c`\xff\xff\xff\xff\xba\xdf\x8d`\xff\xff\xff\xff\xbb\xcf~`\xff\xff\xff\xff\xbc\xc8\xa9\xe0\xff\xff\xff\xff\xbd\xb8\x9a\xe0\xff\xff\xff\xff\xbe\xa8\x8b\xe0\xff\xff\xff\xff\xbf\x98|\xe0\xff\xff\xff\xff\xc0\x88m\xe0\xff\xff\xff\xff\xc1x^\xe0\xff\xff\xff\xff\xc2hO\xe0\xff\xff\xff\xff\xc3X@\xe0\xff\xff\xff\xff\xc4H1\xe0\xff\xff\xff\xff\xc58\x22\xe0\xff\xff\xff\xff\xc6(\x13\xe0\xff\xff\xff\xff\xc7\x18\x04\xe0\xff\xff\xff\xff\xc8\xbc\x93`\xff\xff\xff\xff\xcaw}P\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0N\x90`\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00&CL\xe0\x00\x00\x00\x00'\x055\x80\x00\x00\x00\x00'\xf5&\x80\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000duP\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x002\xc9\x8c\xe0\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x06\x05\x06\x05\x06\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x04\x00\x00\x1b\x08\x00\x00\x00\x00\x1a\xf4\x00\x04\x00\x00\x18x\x00\x08\x00\x00*0\x01\x0c\x00\x00\x1c \x00\x11\x00\x00\x0e\x10\x00\x15\x00\x00\x1c \x01\x19\x00\x008@\x01\x1e\x00\x00*0\x00\x22LMT\x00CMT\x00BMT\x00EEST\x00EET\x00CET\x00CEST\x00MSD\x00MSK\x00\x0aEET-2EEST,M3.5.0,M10.5.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17S\x91\xb3\xc1\x02\x00\x00\xc1\x02\x00\x00\x11\x00\x00\x00Europe/CopenhagenTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\x09q\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd1\xb6\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xff\xd2\xa1O\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xff\xd5\xa8s\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#P\xff\xff\xff\xff\xf1\xf4\xb9`\xff\xff\xff\xff\xf4b\xefP\xff\xff\xff\xff\xf5h\x06`\xff\xff\xff\xff\xf6\x1f8\xd0\x00\x00\x00\x00\x06n\x93p\x00\x00\x00\x00\x079\x9ap\x00\x00\x00\x00\x07\xfbu\x00\x00\x00\x00\x00\x09\x19|p\x00\x00\x00\x00\x09\xd0\xcb\x00\x00\x00\x00\x00\x0a\xf9^p\x00\x00\x00\x00\x0b\xb1\xfe\x80\x00\x00\x00\x00\x0c\xd9@p\x00\x00\x00\x00\x0d\xa4U\x80\x00\x00\x00\x00\x0e\xa6\xadp\x00\x00\x00\x00\x0f\x847\x80\x00\x00\x00\x00\x0f\xf8\x11P\x00\x00\x00\x00\x19\x89\xb0p\x00\x00\x00\x00\x19\xdc\xb0\xe0\x00\x00\x00\x00\x1b\xe6\xd0\xf0\x00\x00\x00\x00\x1c\xc6\xef\xf0\x00\x00\x00\x00\x1d\x9b1p\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00(\xe5\x09p\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x8b\x83\xf0\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8f\xdd\x90\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S8\xbe\x10\x00\x00\x00\x00TLG\x90\x00\x00\x00\x00U\x17N\x90\x00\x00\x00\x00V>\x9e\x90\x00\x00\x00\x00V\xf70\x90\x00\x00\x00\x00W\xcf.P\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x05\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x00\x00\x1b(\x00\x00\x00\x00\x1bh\x00\x04\x00\x00*0\x01\x08\x00\x00\x1c \x00\x0d\x00\x00*0\x00\x11\x00\x008@\x01\x15LMT\x00IMT\x00EEST\x00EET\x00+03\x00+04\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\xff\x01\xfe?\x06\x00\x00?\x06\x00\x00\x0d\x00\x00\x00Europe/JerseyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f\x00\x00\x00\x05\x00\x00\x00\x11\xff\xff\xff\xff\x1a]\x09\xcb\xff\xff\xff\xff\x9b&\xad\xa0\xff\xff\xff\xff\x9b\xd6\x05 \xff\xff\xff\xff\x9c\xcf0\xa0\xff\xff\xff\xff\x9d\xa4\xc3\xa0\xff\xff\xff\xff\x9e\x9c\x9d\xa0\xff\xff\xff\xff\x9f\x97\x1a\xa0\xff\xff\xff\xff\xa0\x85\xba \xff\xff\xff\xff\xa1v\xfc\xa0\xff\xff\xff\xff\xa2e\x9c \xff\xff\xff\xff\xa3{\xc8\xa0\xff\xff\xff\xff\xa4N\xb8\xa0\xff\xff\xff\xff\xa5?\xfb \xff\xff\xff\xff\xa6%` \xff\xff\xff\xff\xa7'\xc6 \xff\xff\xff\xff\xa8*, \xff\xff\xff\xff\xa8\xeb\xf8\xa0\xff\xff\xff\xff\xaa\x00\xd3\xa0\xff\xff\xff\xff\xaa\xd5\x15 \xff\xff\xff\xff\xab\xe9\xf0 \xff\xff\xff\xff\xac\xc7l \xff\xff\xff\xff\xad\xc9\xd2 \xff\xff\xff\xff\xae\xa7N \xff\xff\xff\xff\xaf\xa0y\xa0\xff\xff\xff\xff\xb0\x870 \xff\xff\xff\xff\xb1\x92\xd0\xa0\xff\xff\xff\xff\xb2pL\xa0\xff\xff\xff\xff\xb3r\xb2\xa0\xff\xff\xff\xff\xb4P.\xa0\xff\xff\xff\xff\xb5IZ \xff\xff\xff\xff\xb60\x10\xa0\xff\xff\xff\xff\xb72v\xa0\xff\xff\xff\xff\xb8\x0f\xf2\xa0\xff\xff\xff\xff\xb9\x12X\xa0\xff\xff\xff\xff\xb9\xef\xd4\xa0\xff\xff\xff\xff\xba\xe9\x00 \xff\xff\xff\xff\xbb\xd8\xf1 \xff\xff\xff\xff\xbc\xdbW \xff\xff\xff\xff\xbd\xb8\xd3 \xff\xff\xff\xff\xbe\xb1\xfe\xa0\xff\xff\xff\xff\xbf\x98\xb5 \xff\xff\xff\xff\xc0\x9b\x1b \xff\xff\xff\xff\xc1x\x97 \xff\xff\xff\xff\xc2z\xfd \xff\xff\xff\xff\xc3Xy \xff\xff\xff\xff\xc4Q\xa4\xa0\xff\xff\xff\xff\xc58[ \xff\xff\xff\xff\xc6:\xc1 \xff\xff\xff\xff\xc7X\xd6\xa0\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xca\x16&\x90\xff\xff\xff\xff\xca\x97Y\x90\xff\xff\xff\xff\xcb\xd1\x1e\x90\xff\xff\xff\xff\xccw;\x90\xff\xff\xff\xff\xcd\xb1\x00\x90\xff\xff\xff\xff\xce`X\x10\xff\xff\xff\xff\xcf\x90\xe2\x90\xff\xff\xff\xff\xd0n^\x90\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd1\xfb2\x10\xff\xff\xff\xff\xd2i\xfe \xff\xff\xff\xff\xd3c)\xa0\xff\xff\xff\xff\xd4I\xe0 \xff\xff\xff\xff\xd5\x1e!\xa0\xff\xff\xff\xff\xd5B\xfd\x90\xff\xff\xff\xff\xd5\xdf\xe0\x10\xff\xff\xff\xff\xd6N\xac \xff\xff\xff\xff\xd6\xfe\x03\xa0\xff\xff\xff\xff\xd8.\x8e \xff\xff\xff\xff\xd8\xf9\x95 \xff\xff\xff\xff\xda\x0ep \xff\xff\xff\xff\xda\xeb\xec \xff\xff\xff\xff\xdb\xe5\x17\xa0\xff\xff\xff\xff\xdc\xcb\xce \xff\xff\xff\xff\xdd\xc4\xf9\xa0\xff\xff\xff\xff\xde\xb4\xea\xa0\xff\xff\xff\xff\xdf\xae\x16 \xff\xff\xff\xff\xe0\x94\xcc\xa0\xff\xff\xff\xff\xe1rH\xa0\xff\xff\xff\xff\xe2kt \xff\xff\xff\xff\xe3R*\xa0\xff\xff\xff\xff\xe4T\x90\xa0\xff\xff\xff\xff\xe52\x0c\xa0\xff\xff\xff\xff\xe6=\xad \xff\xff\xff\xff\xe7\x1b) \xff\xff\xff\xff\xe8\x14T\xa0\xff\xff\xff\xff\xe8\xfb\x0b \xff\xff\xff\xff\xe9\xfdq \xff\xff\xff\xff\xea\xda\xed \xff\xff\xff\xff\xeb\xddS \xff\xff\xff\xff\xec\xba\xcf \xff\xff\xff\xff\xed\xb3\xfa\xa0\xff\xff\xff\xff\xee\x9a\xb1 \xff\xff\xff\xff\xef\x81g\xa0\xff\xff\xff\xff\xf0\x9f} \xff\xff\xff\xff\xf1aI\xa0\xff\xff\xff\xff\xf2\x7f_ \xff\xff\xff\xff\xf3Jf \xff\xff\xff\xff\xf4_A \xff\xff\xff\xff\xf5!\x0d\xa0\xff\xff\xff\xff\xf6?# \xff\xff\xff\xff\xf7\x00\xef\xa0\xff\xff\xff\xff\xf8\x1f\x05 \xff\xff\xff\xff\xf8\xe0\xd1\xa0\xff\xff\xff\xff\xf9\xfe\xe7 \xff\xff\xff\xff\xfa\xc0\xb3\xa0\xff\xff\xff\xff\xfb\xe8\x03\xa0\xff\xff\xff\xff\xfc{\xab\xa0\xff\xff\xff\xff\xfd\xc7\xbbp\x00\x00\x00\x00\x03p\xc6 \x00\x00\x00\x00\x04)X \x00\x00\x00\x00\x05P\xa8 \x00\x00\x00\x00\x06\x09: \x00\x00\x00\x00\x070\x8a \x00\x00\x00\x00\x07\xe9\x1c \x00\x00\x00\x00\x09\x10l \x00\x00\x00\x00\x09\xc8\xfe \x00\x00\x00\x00\x0a\xf0N \x00\x00\x00\x00\x0b\xb2\x1a\xa0\x00\x00\x00\x00\x0c\xd00 \x00\x00\x00\x00\x0d\x91\xfc\xa0\x00\x00\x00\x00\x0e\xb0\x12 \x00\x00\x00\x00\x0fq\xde\xa0\x00\x00\x00\x00\x10\x99.\xa0\x00\x00\x00\x00\x11Q\xc0\xa0\x00\x00\x00\x00\x12y\x10\xa0\x00\x00\x00\x00\x131\xa2\xa0\x00\x00\x00\x00\x14X\xf2\xa0\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x168\xc6\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x18\x18\xa8\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xf8\x8a\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xe1\xa7\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\xc1\x89\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f\xa1k\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x81M\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#a/\x10\x00\x00\x00\x00$,6\x10\x00\x00\x00\x00%JK\x90\x00\x00\x00\x00&\x0c\x18\x10\x00\x00\x00\x00'*-\x90\x00\x00\x00\x00'\xf54\x90\x00\x00\x00\x00)\x0a\x0f\x90\x00\x00\x00\x00)\xd5\x16\x90\x00\x00\x00\x00*\xe9\xf1\x90\x00\x00\x00\x00+\xb4\xf8\x90\x00\x00\x00\x00,\xc9\xd3\x90\x00\x00\x00\x00-\x94\xda\x90\x00\x00\x00\x00.\xa9\xb5\x90\x00\x00\x00\x00/t\xbc\x90\x00\x00\x00\x000\x89\x97\x90\x00\x00\x00\x000\xe7$\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x02\xff\xff\xff\xb5\x00\x00\x00\x00\x0e\x10\x01\x04\x00\x00\x00\x00\x00\x08\x00\x00\x1c \x01\x0c\x00\x00\x0e\x10\x00\x04LMT\x00BST\x00GMT\x00BDST\x00\x0aGMT0BST,M3.5.0/1,M10.5.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O+j\x94\x88\x03\x00\x00\x88\x03\x00\x00\x12\x00\x00\x00Europe/KaliningradTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x00\x00\x00\x08\x00\x00\x00\x22\xff\xff\xff\xffo\xa2[H\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\x09q\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd1|w\xe0\xff\xff\xff\xff\xd1\x95\x84`\xff\xff\xff\xff\xd2\x8a\xadP\xff\xff\xff\xff\xd3Y\xb6\xe0\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x19\x00\x00\x00\x00\x00&\x0c\x0a\x00\x00\x00\x00\x00'\x055\x80\x00\x00\x00\x00'\xf5&\x80\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)\xd5\x08\x80\x00\x00\x00\x00*\xc4\xf9\x80\x00\x00\x00\x00+\xb4\xea\x80\x00\x00\x00\x00,\xa4\xdb\x80\x00\x00\x00\x00-\x94\xcc\x80\x00\x00\x00\x00.\x84\xbd\x80\x00\x00\x00\x00/t\xae\x80\x00\x00\x00\x000d\x9f\x80\x00\x00\x00\x001]\xcb\x00\x00\x00\x00\x002r\xa6\x00\x00\x00\x00\x003=\xad\x00\x00\x00\x00\x004R\x88\x00\x00\x00\x00\x005\x1d\x8f\x00\x00\x00\x00\x0062j\x00\x00\x00\x00\x006\xfdq\x00\x00\x00\x00\x008\x1b\x86\x80\x00\x00\x00\x008\xddS\x00\x00\x00\x00\x009\xfbh\x80\x00\x00\x00\x00:\xbd5\x00\x00\x00\x00\x00;\xdbJ\x80\x00\x00\x00\x00<\xa6Q\x80\x00\x00\x00\x00=\xbb,\x80\x00\x00\x00\x00>\x863\x80\x00\x00\x00\x00?\x9b\x0e\x80\x00\x00\x00\x00@f\x15\x80\x00\x00\x00\x00A\x84+\x00\x00\x00\x00\x00BE\xf7\x80\x00\x00\x00\x00Cd\x0d\x00\x00\x00\x00\x00D%\xd9\x80\x00\x00\x00\x00EC\xef\x00\x00\x00\x00\x00F\x05\xbb\x80\x00\x00\x00\x00G#\xd1\x00\x00\x00\x00\x00G\xee\xd8\x00\x00\x00\x00\x00I\x03\xb3\x00\x00\x00\x00\x00I\xce\xba\x00\x00\x00\x00\x00J\xe3\x95\x00\x00\x00\x00\x00K\xae\x9c\x00\x00\x00\x00\x00L\xcc\xb1\x80\x00\x00\x00\x00M\x8e~\x00\x00\x00\x00\x00TL+p\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x03\x04\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x07\x04\x00\x00\x138\x00\x00\x00\x00\x1c \x01\x04\x00\x00\x0e\x10\x00\x09\x00\x00*0\x01\x0d\x00\x00\x1c \x00\x12\x00\x008@\x01\x16\x00\x00*0\x00\x1a\x00\x00*0\x00\x1eLMT\x00CEST\x00CET\x00EEST\x00EET\x00MSD\x00MSK\x00+03\x00\x0aEET-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x81\xbf~.\x02\x00\x00.\x02\x00\x00\x0b\x00\x00\x00Europe/KievTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x08\x00\x00\x00\x22\xff\xff\xff\xffV\xb6\xc7d\xff\xff\xff\xff\xaa\x19\xa7d\xff\xff\xff\xff\xb5\xa4\x19`\xff\xff\xff\xff\xca\xcd.\xd0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xce\xcd\xa8p\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00&\x8d \xe0\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)\xd5\x08\x80\x00\x00\x00\x00*\xc4\xf9\x80\x00\x00\x00\x00+\xb4\xea\x80\x00\x00\x00\x00,\xa4\xdb\x80\x00\x00\x00\x00-\x94\xcc\x80\x00\x00\x00\x00.\x84\xbd\x80\x00\x00\x00\x00/t\xae\x80\x00\x00\x00\x000d\x9f\x80\x00\x00\x00\x001]\xcb\x00\x00\x00\x00\x001\x96QP\x01\x02\x03\x05\x04\x05\x04\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x07\x00\x00\x1c\x9c\x00\x00\x00\x00\x1c\x9c\x00\x04\x00\x00\x1c \x00\x08\x00\x00*0\x00\x0c\x00\x00\x0e\x10\x00\x10\x00\x00\x1c \x01\x14\x00\x008@\x01\x19\x00\x00*0\x01\x1dLMT\x00KMT\x00EET\x00MSK\x00CET\x00CEST\x00MSD\x00EEST\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8f(NN\xdf\x02\x00\x00\xdf\x02\x00\x00\x0c\x00\x00\x00Europe/KirovTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x00\x00\x00\x07\x00\x00\x00\x18\xff\xff\xff\xff\xa1\x009\x80\xff\xff\xff\xff\xb5\xa4\x0bP\x00\x00\x00\x00\x15'\x99\xc0\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xcd@\x00\x00\x00\x00\x17\xfa\x01\xb0\x00\x00\x00\x00\x18\xea\x00\xc0\x00\x00\x00\x00\x19\xdb50\x00\x00\x00\x00\x1a\xcc\x85\xc0\x00\x00\x00\x00\x1b\xbc\x92\xe0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9ct\xe0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|V\xe0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c8\xe0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x1a\xe0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x94\xbep\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xadp\x00\x00\x00\x00G#\xc2\xf0\x00\x00\x00\x00G\xee\xc9\xf0\x00\x00\x00\x00I\x03\xa4\xf0\x00\x00\x00\x00I\xce\xab\xf0\x00\x00\x00\x00J\xe3\x86\xf0\x00\x00\x00\x00K\xae\x8d\xf0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x00\x00\x00\x00TL\x1d`\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x05\x04\x05\x03\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x06\x05\x00\x00.\x98\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x01\x08\x00\x008@\x00\x0c\x00\x008@\x01\x10\x00\x00*0\x00\x14\x00\x008@\x00\x14LMT\x00+03\x00+05\x00+04\x00MSD\x00MSK\x00\x0aMSK-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x81\xbf~.\x02\x00\x00.\x02\x00\x00\x0b\x00\x00\x00Europe/KyivTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x08\x00\x00\x00\x22\xff\xff\xff\xffV\xb6\xc7d\xff\xff\xff\xff\xaa\x19\xa7d\xff\xff\xff\xff\xb5\xa4\x19`\xff\xff\xff\xff\xca\xcd.\xd0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xce\xcd\xa8p\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00&\x8d \xe0\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)\xd5\x08\x80\x00\x00\x00\x00*\xc4\xf9\x80\x00\x00\x00\x00+\xb4\xea\x80\x00\x00\x00\x00,\xa4\xdb\x80\x00\x00\x00\x00-\x94\xcc\x80\x00\x00\x00\x00.\x84\xbd\x80\x00\x00\x00\x00/t\xae\x80\x00\x00\x00\x000d\x9f\x80\x00\x00\x00\x001]\xcb\x00\x00\x00\x00\x001\x96QP\x01\x02\x03\x05\x04\x05\x04\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x07\x00\x00\x1c\x9c\x00\x00\x00\x00\x1c\x9c\x00\x04\x00\x00\x1c \x00\x08\x00\x00*0\x00\x0c\x00\x00\x0e\x10\x00\x10\x00\x00\x1c \x01\x14\x00\x008@\x01\x19\x00\x00*0\x01\x1dLMT\x00KMT\x00EET\x00MSK\x00CET\x00CEST\x00MSD\x00EEST\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&S\x03\x09\xae\x05\x00\x00\xae\x05\x00\x00\x0d\x00\x00\x00Europe/LisbonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8d\x00\x00\x00\x06\x00\x00\x00\x1b\xff\xff\xff\xff^=\x0c\x1d\xff\xff\xff\xff\x92\xe6\x8e\x80\xff\xff\xff\xff\x9bKmp\xff\xff\xff\xff\x9b\xfe\xc7\x80\xff\xff\xff\xff\x9c\x9c\xedp\xff\xff\xff\xff\x9d\xc9\x83p\xff\xff\xff\xff\x9e\x7frp\xff\xff\xff\xff\x9f\xaa\xb6\xf0\xff\xff\xff\xff\xa0_Tp\xff\xff\xff\xff\xa1\x8b\xeap\xff\xff\xff\xff\xa2A\xd9p\xff\xff\xff\xff\xa3nop\xff\xff\xff\xff\xa4#\x0c\xf0\xff\xff\xff\xff\xa5O\xa2\xf0\xff\xff\xff\xff\xaa\x05\xefp\xff\xff\xff\xff\xaa\xf4\x8e\xf0\xff\xff\xff\xff\xad\xc9\xa7\xf0\xff\xff\xff\xff\xae\xa7#\xf0\xff\xff\xff\xff\xaf\xa0Op\xff\xff\xff\xff\xb0\x87\x05\xf0\xff\xff\xff\xff\xb1\x89k\xf0\xff\xff\xff\xff\xb2p\x22p\xff\xff\xff\xff\xb3r\x88p\xff\xff\xff\xff\xb4P\x04p\xff\xff\xff\xff\xb72Lp\xff\xff\xff\xff\xb8\x0f\xc8p\xff\xff\xff\xff\xb8\xff\xb9p\xff\xff\xff\xff\xb9\xef\xaap\xff\xff\xff\xff\xbc\xc8\xb7\xf0\xff\xff\xff\xff\xbd\xb8\xa8\xf0\xff\xff\xff\xff\xbe\x9f_p\xff\xff\xff\xff\xbf\x98\x8a\xf0\xff\xff\xff\xff\xc0\x9a\xf0\xf0\xff\xff\xff\xff\xc1xl\xf0\xff\xff\xff\xff\xc2h]\xf0\xff\xff\xff\xff\xc3XN\xf0\xff\xff\xff\xff\xc4?\x05p\xff\xff\xff\xff\xc580\xf0\xff\xff\xff\xff\xc6:\x96\xf0\xff\xff\xff\xff\xc7X\xacp\xff\xff\xff\xff\xc7\xd9\xdfp\xff\xff\xff\xff\xc9\x01/p\xff\xff\xff\xff\xc9\xf1 p\xff\xff\xff\xff\xca\xe2b\xf0\xff\xff\xff\xff\xcb\xb5R\xf0\xff\xff\xff\xff\xcb\xec\xa3\xe0\xff\xff\xff\xff\xcc\x80K\xe0\xff\xff\xff\xff\xcc\xdc\xa2\xf0\xff\xff\xff\xff\xcd\x954\xf0\xff\xff\xff\xff\xcd\xc3K`\xff\xff\xff\xff\xcer\xa2\xe0\xff\xff\xff\xff\xce\xc5\xbfp\xff\xff\xff\xff\xcfu\x16\xf0\xff\xff\xff\xff\xcf\xacg\xe0\xff\xff\xff\xff\xd0R\x84\xe0\xff\xff\xff\xff\xd0\xa5\xa1p\xff\xff\xff\xff\xd1T\xf8\xf0\xff\xff\xff\xff\xd1\x8cI\xe0\xff\xff\xff\xff\xd22f\xe0\xff\xff\xff\xff\xd2\x85\x83p\xff\xff\xff\xff\xd3Y\xc4\xf0\xff\xff\xff\xff\xd4I\xb5\xf0\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd6)\xc2 \xff\xff\xff\xff\xd7\x19\xb3 \xff\xff\xff\xff\xd8\x09\xa4 \xff\xff\xff\xff\xd8\xf9\x95 \xff\xff\xff\xff\xd9\xe9\x86 \xff\xff\xff\xff\xda\xd9w \xff\xff\xff\xff\xdb\xc9h \xff\xff\xff\xff\xdc\xb9Y \xff\xff\xff\xff\xdd\xb2\x84\xa0\xff\xff\xff\xff\xde\xa2u\xa0\xff\xff\xff\xff\xdf\x92f\xa0\xff\xff\xff\xff\xe0\x82W\xa0\xff\xff\xff\xff\xe1rH\xa0\xff\xff\xff\xff\xe2b9\xa0\xff\xff\xff\xff\xe3R*\xa0\xff\xff\xff\xff\xe4B\x1b\xa0\xff\xff\xff\xff\xe52\x0c\xa0\xff\xff\xff\xff\xe6!\xfd\xa0\xff\xff\xff\xff\xe7\x1b) \xff\xff\xff\xff\xe8\x0b\x1a \xff\xff\xff\xff\xe8\xfb\x0b \xff\xff\xff\xff\xe9\xea\xfc \xff\xff\xff\xff\xea\xda\xed \xff\xff\xff\xff\xeb\xca\xde \xff\xff\xff\xff\xec\xba\xcf \xff\xff\xff\xff\xed\xaa\xc0 \xff\xff\xff\xff\xee\x9a\xb1 \xff\xff\xff\xff\xef\x8a\xa2 \xff\xff\xff\xff\xf0z\x93 \xff\xff\xff\xff\xf1j\x84 \xff\xff\xff\xff\xf2c\xaf\xa0\xff\xff\xff\xff\xf3S\xa0\xa0\xff\xff\xff\xff\xf4C\x91\xa0\xff\xff\xff\xff\xf53\x82\xa0\xff\xff\xff\xff\xf6#s\xa0\xff\xff\xff\xff\xf7\x13d\xa0\xff\xff\xff\xff\xf8\x03U\xa0\xff\xff\xff\xff\xf8\xf3F\xa0\x00\x00\x00\x00\x0c\xab*\x00\x00\x00\x00\x00\x0d\x9b\x1b\x00\x00\x00\x00\x00\x0e\x8b\x0c\x00\x00\x00\x00\x00\x0f\x847\x80\x00\x00\x00\x00\x10t(\x80\x00\x00\x00\x00\x11d\x19\x80\x00\x00\x00\x00\x12T\x18\x90\x00\x00\x00\x00\x13C\xfb\x80\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xbd\xa0\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#1\x90\xff\xff\xff\xff\xd4I\xd2\x10\xff\xff\xff\xff\xd5\x1d\xf7p\xff\xff\xff\xff\xd6)\x97\xf0\xff\xff\xff\xff\xd6\xeb\x80\x90\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xf93\xb5\xf0\xff\xff\xff\xff\xf9\xd9\xc4\xe0\xff\xff\xff\xff\xfb\x1c\xd2p\xff\xff\xff\xff\xfb\xb9\xb4\xf0\xff\xff\xff\xff\xfc\xfc\xb4p\xff\xff\xff\xff\xfd\x99\x96\xf0\xff\xff\xff\xff\xfe\xe5\xd0\xf0\xff\xff\xff\xff\xff\x82\xb3p\x00\x00\x00\x00\x00\xc5\xb2\xf0\x00\x00\x00\x00\x01b\x95p\x00\x00\x00\x00\x02\x9cZp\x00\x00\x00\x00\x03Bwp\x00\x00\x00\x00\x04\x85v\xf0\x00\x00\x00\x00\x05+\x93\xf0\x00\x00\x00\x00\x06\x1a3p\x00\x00\x00\x00\x07\x0a$p\x00\x00\x00\x00\x08\x17\x16p\x00\x00\x00\x00\x08\xda4p\x00\x00\x00\x00\x09\xf7\x14\x90\x00\x00\x00\x00\x0a\xc2\x0d\x80\x00\x00\x00\x00\x0b\xd6\xf6\x90\x00\x00\x00\x00\x0c\xa1\xef\x80\x00\x00\x00\x00\x0d\xb6\xd8\x90\x00\x00\x00\x00\x0e\x81\xd1\x80\x00\x00\x00\x00\x0f\x96\xba\x90\x00\x00\x00\x00\x10a\xb3\x80\x00\x00\x00\x00\x11v\x9c\x90\x00\x00\x00\x00\x12A\x95\x80\x00\x00\x00\x00\x13E[\x10\x00\x00\x00\x00\x14*\xb2\x00\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x863\x80\x00\x00\x00\x00?\x9b\x0e\x80\x00\x00\x00\x00@f\x15\x80\x00\x00\x00\x00A\x84+\x00\x00\x00\x00\x00BE\xf7\x80\x00\x00\x00\x00Cd\x0d\x00\x00\x00\x00\x00D%\xd9\x80\x00\x00\x00\x00EC\xef\x00\x00\x00\x00\x00F\x05\xbb\x80\x00\x00\x00\x00G#\xd1\x00\x00\x00\x00\x00G\xee\xd8\x00\x00\x00\x00\x00I\x03\xb3\x00\x00\x00\x00\x00I\xce\xba\x00\x00\x00\x00\x00J\xe3\x95\x00\x00\x00\x00\x00K\xae\x9c\x00\x00\x00\x00\x00L\xcc\xb1\x80\x00\x00\x00\x00M\x8e~\x00\x01\x02\x03\x05\x04\x05\x04\x05\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x08\x00\x00\x19\xd8\x00\x00\x00\x00\x19\xc8\x00\x04\x00\x00\x1c \x00\x08\x00\x00*0\x00\x0c\x00\x00\x0e\x10\x00\x10\x00\x00\x1c \x01\x14\x00\x008@\x01\x19\x00\x00*0\x01\x1d\x00\x00*0\x00\x22LMT\x00MMT\x00EET\x00MSK\x00CET\x00CEST\x00MSD\x00EEST\x00+03\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7\xf5\x94\xdaQ\x04\x00\x00Q\x04\x00\x00\x0d\x00\x00\x00Europe/MonacoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\x00\x00\x00\x07\x00\x00\x00\x1f\xff\xff\xff\xffk\xc9\x9b\xcf\xff\xff\xff\xff\x91`PO\xff\xff\xff\xff\x9bGx\xf0\xff\xff\xff\xff\x9b\xd7,p\xff\xff\xff\xff\x9c\xbc\x91p\xff\xff\xff\xff\x9d\xc0H\xf0\xff\xff\xff\xff\x9e\x89\xfep\xff\xff\xff\xff\x9f\xa0*\xf0\xff\xff\xff\xff\xa0`\xa5\xf0\xff\xff\xff\xff\xa1\x80\x0c\xf0\xff\xff\xff\xff\xa2.\x12\xf0\xff\xff\xff\xff\xa3zL\xf0\xff\xff\xff\xff\xa45\x81\xf0\xff\xff\xff\xff\xa5^#p\xff\xff\xff\xff\xa6%5\xf0\xff\xff\xff\xff\xa7'\x9b\xf0\xff\xff\xff\xff\xa8X&p\xff\xff\xff\xff\xa9\x07}\xf0\xff\xff\xff\xff\xa9\xee4p\xff\xff\xff\xff\xaa\xe7_\xf0\xff\xff\xff\xff\xab\xd7P\xf0\xff\xff\xff\xff\xac\xc7A\xf0\xff\xff\xff\xff\xad\xc9\xa7\xf0\xff\xff\xff\xff\xae\xa7#\xf0\xff\xff\xff\xff\xaf\xa0Op\xff\xff\xff\xff\xb0\x87\x05\xf0\xff\xff\xff\xff\xb1\x89k\xf0\xff\xff\xff\xff\xb2p\x22p\xff\xff\xff\xff\xb3r\x88p\xff\xff\xff\xff\xb4P\x04p\xff\xff\xff\xff\xb5I/\xf0\xff\xff\xff\xff\xb6/\xe6p\xff\xff\xff\xff\xb72Lp\xff\xff\xff\xff\xb8\x0f\xc8p\xff\xff\xff\xff\xb8\xff\xb9p\xff\xff\xff\xff\xb9\xef\xaap\xff\xff\xff\xff\xba\xd6`\xf0\xff\xff\xff\xff\xbb\xd8\xc6\xf0\xff\xff\xff\xff\xbc\xc8\xb7\xf0\xff\xff\xff\xff\xbd\xb8\xa8\xf0\xff\xff\xff\xff\xbe\x9f_p\xff\xff\xff\xff\xbf\x98\x8a\xf0\xff\xff\xff\xff\xc0\x9a\xf0\xf0\xff\xff\xff\xff\xc1xl\xf0\xff\xff\xff\xff\xc2h]\xf0\xff\xff\xff\xff\xc3XN\xf0\xff\xff\xff\xff\xc4?\x05p\xff\xff\xff\xff\xc580\xf0\xff\xff\xff\xff\xc6:\x96\xf0\xff\xff\xff\xff\xc7X\xacp\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xc8l'\xe0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0O\xe1\xe0\xff\xff\xff\xff\xd0\x89\xf1\xf0\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2N@\x90\x00\x00\x00\x00\x0b\xbb9\x00\x00\x00\x00\x00\x0c\xab\x1b\xf0\x00\x00\x00\x00\x0d\xa4c\x90\x00\x00\x00\x00\x0e\x8b\x1a\x10\x00\x00\x00\x00\x0f\x84E\x90\x00\x00\x00\x00\x10t6\x90\x00\x00\x00\x00\x11d'\x90\x00\x00\x00\x00\x12T\x18\x90\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\xf2y\xff\xff\xff\xff\x9e*\xee\xf9\xff\xff\xff\xff\x9e\xf79i\xff\xff\xff\xff\x9f\x84W\xf9\xff\xff\xff\xff\xa0\xd8l\xe9\xff\xff\xff\xff\xa1\x009\x80\xff\xff\xff\xff\xa1<\xa6@\xff\xff\xff\xff\xa4\x10m\xc0\xff\xff\xff\xff\xa4=2\xb0\xff\xff\xff\xff\xa5\x15h\xb0\xff\xff\xff\xff\xa5=\x03\xc0\xff\xff\xff\xff\xa7\x1eEP\xff\xff\xff\xff\xb5\xa4\x19`\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)x\xbf\x80\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x94\xbep\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xadp\x00\x00\x00\x00G#\xc2\xf0\x00\x00\x00\x00G\xee\xc9\xf0\x00\x00\x00\x00I\x03\xa4\xf0\x00\x00\x00\x00I\xce\xab\xf0\x00\x00\x00\x00J\xe3\x86\xf0\x00\x00\x00\x00K\xae\x8d\xf0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x00\x00\x00\x00TL\x1d`\x01\x03\x02\x03\x04\x02\x04\x05\x06\x05\x07\x05\x06\x08\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x09\x08\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x0a\x06\x00\x00#9\x00\x00\x00\x00#9\x00\x04\x00\x001\x87\x01\x08\x00\x00#w\x00\x04\x00\x00?\x97\x01\x0c\x00\x008@\x01\x11\x00\x00*0\x00\x15\x00\x00FP\x01\x19\x00\x00\x1c \x00\x1d\x00\x00*0\x01!\x00\x008@\x00\x15LMT\x00MMT\x00MST\x00MDST\x00MSD\x00MSK\x00+05\x00EET\x00EEST\x00\x0aMSK-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1eX\xc3aU\x02\x00\x00U\x02\x00\x00\x0e\x00\x00\x00Europe/NicosiaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xff\xa5w\x1e\xb8\x00\x00\x00\x00\x09\xed\xaf\xe0\x00\x00\x00\x00\x0a\xdd\x92\xd0\x00\x00\x00\x00\x0b\xfad\xe0\x00\x00\x00\x00\x0c\xbe\xc6P\x00\x00\x00\x00\x0d\xa49`\x00\x00\x00\x00\x0e\x8a\xe1\xd0\x00\x00\x00\x00\x0f\x84\x1b`\x00\x00\x00\x00\x10uO\xd0\x00\x00\x00\x00\x11c\xfd`\x00\x00\x00\x00\x12S\xe0P\x00\x00\x00\x00\x13M\x19\xe0\x00\x00\x00\x00\x143\xc2P\x00\x00\x00\x00\x15#\xc1`\x00\x00\x00\x00\x16\x13\xa4P\x00\x00\x00\x00\x17\x03\xa3`\x00\x00\x00\x00\x17\xf3\x86P\x00\x00\x00\x00\x18\xe3\x85`\x00\x00\x00\x00\x19\xd3hP\x00\x00\x00\x00\x1a\xc3g`\x00\x00\x00\x00\x1b\xbc\x84\xd0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9cf\xd0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|H\xd0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c*\xd0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x0c\xd0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1b\xee\xd0\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00'\x05\x0bP\x00\x00\x00\x00'\xf5\x0a`\x00\x00\x00\x00(\xe4\xedP\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000duP\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002M\x91\xd0\x00\x00\x00\x003=\x90\xe0\x00\x00\x00\x004-s\xd0\x00\x00\x00\x005\x1dr\xe0\x00\x00\x00\x005\xeb\x0e\xd0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x01\x00\x00\x1fH\x00\x00\x00\x00*0\x01\x04\x00\x00\x1c \x00\x09LMT\x00EEST\x00EET\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17S\x91\xb3\xc1\x02\x00\x00\xc1\x02\x00\x00\x0b\x00\x00\x00Europe/OsloTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffo\xa2a\xf8\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\x09q\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd1\xb6\x96\x00\xff\xff\xff\xff\xd2X\xbe\x80\xff\xff\xff\xff\xd2\xa1O\x10\xff\xff\xff\xff\xd3c\x1b\x90\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd59\xd1 \xff\xff\xff\xff\xd5g\xe7\x90\xff\xff\xff\xff\xd5\xa8s\x00\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#(\xe8L\xff\xff\xff\xffp\xbc\x81p\xff\xff\xff\xff\x9b8\xf8p\xff\xff\xff\xff\x9b\xd5\xcc\xe0\xff\xff\xff\xff\x9c\xc5\xcb\xf0\xff\xff\xff\xff\x9d\xb7\x00`\xff\xff\xff\xff\x9e\x89\xfep\xff\xff\xff\xff\x9f\xa0\x1c\xe0\xff\xff\xff\xff\xa0`\xa5\xf0\xff\xff\xff\xff\xa1~\xad`\xff\xff\xff\xff\xa2\x5c7p\xff\xff\xff\xff\xa3L\x1a`\xff\xff\xff\xff\xc8l5\xf0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0n^\x90\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2L\xd2\xf0\xff\xff\xff\xff\xd3>1\x90\xff\xff\xff\xff\xd4I\xd2\x10\xff\xff\xff\xff\xd5\x1d\xf7p\xff\xff\xff\xff\xd6)\x97\xf0\xff\xff\xff\xff\xd6\xeb\x80\x90\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xf93\xb5\xf0\xff\xff\xff\xff\xf9\xd9\xc4\xe0\xff\xff\xff\xff\xfb\x1c\xd2p\xff\xff\xff\xff\xfb\xb9\xb4\xf0\xff\xff\xff\xff\xfc\xfc\xb4p\xff\xff\xff\xff\xfd\x99\x96\xf0\xff\xff\xff\xff\xfe\xe5\xd0\xf0\xff\xff\xff\xff\xff\x82\xb3p\x00\x00\x00\x00\x00\xc5\xb2\xf0\x00\x00\x00\x00\x01b\x95p\x00\x00\x00\x00\x02\x9cZp\x00\x00\x00\x00\x03Bwp\x00\x00\x00\x00\x04\x85v\xf0\x00\x00\x00\x00\x05+\x93\xf0\x00\x00\x00\x00\x06n\x93p\x00\x00\x00\x00\x07\x0bu\xf0\x00\x00\x00\x00\x08E:\xf0\x00\x00\x00\x00\x08\xebW\xf0\x00\x00\x00\x00\x0a.Wp\x00\x00\x00\x00\x0a\xcb9\xf0\x00\x00\x00\x00\x0c\x0e9p\x00\x00\x00\x00\x0c\xab\x1b\xf0\x00\x00\x00\x00\x0d\xe4\xe0\xf0\x00\x00\x00\x00\x0e\x8a\xfd\xf0\x00\x00\x00\x00\x0f\xcd\xfdp\x00\x00\x00\x00\x10t\x1ap\x00\x00\x00\x00\x11\xad\xdfp\x00\x00\x00\x00\x12S\xfcp\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x86\x17`\x00\x00\x00\x00?\x9a\xf2`\x00\x00\x00\x00@e\xf9`\x00\x00\x00\x00A\x84\x0e\xe0\x00\x00\x00\x00BE\xdb`\x00\x00\x00\x00Cc\xf0\xe0\x00\x00\x00\x00D%\xbd`\x00\x00\x00\x00EC\xd2\xe0\x00\x00\x00\x00F\x05\x9f`\x00\x00\x00\x00G#\xb4\xe0\x00\x00\x00\x00G\xee\xbb\xe0\x00\x00\x00\x00I\x03\x96\xe0\x00\x00\x00\x00I\xce\x9d\xe0\x00\x00\x00\x00J\xe3x\xe0\x00\x00\x00\x00K\xae\x7f\xe0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x01\x04\x01\x05\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x01\x02\x00\x00.\xf4\x00\x00\x00\x00*0\x00\x04\x00\x008@\x00\x08\x00\x00FP\x01\x0c\x00\x008@\x01\x08\x00\x00*0\x01\x04LMT\x00+03\x00+04\x00+05\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95\xb4\x9e\xe7\xb3\x03\x00\x00\xb3\x03\x00\x00\x11\x00\x00\x00Europe/San_MarinoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff>(\xe8L\xff\xff\xff\xffp\xbc\x81p\xff\xff\xff\xff\x9b8\xf8p\xff\xff\xff\xff\x9b\xd5\xcc\xe0\xff\xff\xff\xff\x9c\xc5\xcb\xf0\xff\xff\xff\xff\x9d\xb7\x00`\xff\xff\xff\xff\x9e\x89\xfep\xff\xff\xff\xff\x9f\xa0\x1c\xe0\xff\xff\xff\xff\xa0`\xa5\xf0\xff\xff\xff\xff\xa1~\xad`\xff\xff\xff\xff\xa2\x5c7p\xff\xff\xff\xff\xa3L\x1a`\xff\xff\xff\xff\xc8l5\xf0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0n^\x90\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2L\xd2\xf0\xff\xff\xff\xff\xd3>1\x90\xff\xff\xff\xff\xd4I\xd2\x10\xff\xff\xff\xff\xd5\x1d\xf7p\xff\xff\xff\xff\xd6)\x97\xf0\xff\xff\xff\xff\xd6\xeb\x80\x90\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xf93\xb5\xf0\xff\xff\xff\xff\xf9\xd9\xc4\xe0\xff\xff\xff\xff\xfb\x1c\xd2p\xff\xff\xff\xff\xfb\xb9\xb4\xf0\xff\xff\xff\xff\xfc\xfc\xb4p\xff\xff\xff\xff\xfd\x99\x96\xf0\xff\xff\xff\xff\xfe\xe5\xd0\xf0\xff\xff\xff\xff\xff\x82\xb3p\x00\x00\x00\x00\x00\xc5\xb2\xf0\x00\x00\x00\x00\x01b\x95p\x00\x00\x00\x00\x02\x9cZp\x00\x00\x00\x00\x03Bwp\x00\x00\x00\x00\x04\x85v\xf0\x00\x00\x00\x00\x05+\x93\xf0\x00\x00\x00\x00\x06n\x93p\x00\x00\x00\x00\x07\x0bu\xf0\x00\x00\x00\x00\x08E:\xf0\x00\x00\x00\x00\x08\xebW\xf0\x00\x00\x00\x00\x0a.Wp\x00\x00\x00\x00\x0a\xcb9\xf0\x00\x00\x00\x00\x0c\x0e9p\x00\x00\x00\x00\x0c\xab\x1b\xf0\x00\x00\x00\x00\x0d\xe4\xe0\xf0\x00\x00\x00\x00\x0e\x8a\xfd\xf0\x00\x00\x00\x00\x0f\xcd\xfdp\x00\x00\x00\x00\x10t\x1ap\x00\x00\x00\x00\x11\xad\xdfp\x00\x00\x00\x00\x12S\xfcp\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xadp\x00\x00\x00\x00G#\xc2\xf0\x00\x00\x00\x00G\xee\xc9\xf0\x00\x00\x00\x00I\x03\xa4\xf0\x00\x00\x00\x00I\xce\xab\xf0\x00\x00\x00\x00J\xe3\x86\xf0\x00\x00\x00\x00K\xae\x8d\xf0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x00\x00\x00\x00TL\x1d`\x00\x00\x00\x00XCNp\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x04\x01\x04\x01\x03\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x03\x01\x03\x00\x00+2\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x01\x08\x00\x008@\x00\x0c\x00\x008@\x01\x0cLMT\x00+03\x00+05\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xb4N\xb8a\x03\x00\x00a\x03\x00\x00\x11\x00\x00\x00Europe/SimferopolTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00K\x00\x00\x00\x09\x00\x00\x00\x22\xff\xff\xff\xffV\xb6\xc4\x08\xff\xff\xff\xff\xaa\x19\xa4 \xff\xff\xff\xff\xb5\xa4\x19`\xff\xff\xff\xff\xcb\x04\x8d\xd0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xcf\x9f8\xe0\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x8d.\xf0\x00\x00\x00\x00)\xd5\x08\x80\x00\x00\x00\x00*\xc4\xf9\x80\x00\x00\x00\x00+\xb4\xea\x80\x00\x00\x00\x00,\xa4\xdb\x80\x00\x00\x00\x00-\x94\xcc\x80\x00\x00\x00\x00-\xc2\xc6\xd0\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xa0\xd0\x00\x00\x00\x002r\xa6\x00\x00\x00\x00\x003=\xbb\x10\x00\x00\x00\x004R\x96\x10\x00\x00\x00\x005\x1d\x9d\x10\x00\x00\x00\x0062x\x10\x00\x00\x00\x006\xfd\x7f\x10\x00\x00\x00\x008\x1b\x94\x90\x00\x00\x00\x008\xdda\x10\x00\x00\x00\x009\xfbv\x90\x00\x00\x00\x00:\xbdC\x10\x00\x00\x00\x00;\xdbX\x90\x00\x00\x00\x00<\xa6_\x90\x00\x00\x00\x00=\xbb:\x90\x00\x00\x00\x00>\x86A\x90\x00\x00\x00\x00?\x9b\x1c\x90\x00\x00\x00\x00@f#\x90\x00\x00\x00\x00A\x849\x10\x00\x00\x00\x00BF\x05\x90\x00\x00\x00\x00Cd\x1b\x10\x00\x00\x00\x00D%\xe7\x90\x00\x00\x00\x00EC\xfd\x10\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8e\x8c\x10\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S7^\x80\x00\x00\x00\x00TL\x1d`\x01\x02\x03\x05\x04\x05\x04\x05\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x02\x07\x02\x07\x02\x07\x06\x03\x06\x03\x06\x03\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x08\x03\x00\x00\x1f\xf8\x00\x00\x00\x00\x1f\xe0\x00\x04\x00\x00\x1c \x00\x08\x00\x00*0\x00\x0c\x00\x00\x0e\x10\x00\x10\x00\x00\x1c \x01\x14\x00\x008@\x01\x19\x00\x00*0\x01\x1d\x00\x008@\x00\x0cLMT\x00SMT\x00EET\x00MSK\x00CET\x00CEST\x00MSD\x00EEST\x00\x0aMSK-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe1C\xf9\xa1\xde\x01\x00\x00\xde\x01\x00\x00\x0d\x00\x00\x00Europe/SkopjeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xff^<\xf0H\xff\xff\xff\xff\xca\x025\xe0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1\xa1\x8c\x10\xff\xff\xff\xff\xd2N@\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#`\x00\x00\x00\x00\x0a\x05x\xf0\x00\x00\x00\x00\x0a\xd0q\xe0\x00\x00\x00\x00\x0b\xe9Op\x00\x00\x00\x00\x0c\xb4H`\x00\x00\x00\x00\x0d\xd2k\xf0\x00\x00\x00\x00\x0e\x94*`\x00\x00\x00\x00\x0f\xb0\xfcp\x00\x00\x00\x00\x10t\x0c`\x00\x00\x00\x00\x11\x90\xdep\x00\x00\x00\x00\x12S\xee`\x00\x00\x00\x00\x13p\xc0p\x00\x00\x00\x00\x14;\xb9`\x00\x00\x00\x00\x15H\xb9p\x00\x00\x00\x00\x16\x13\xb2`\x00\x00\x00\x00\x171\xd5\xf0\x00\x00\x00\x00\x17\xfc\xce\xe0\x00\x00\x00\x00\x19\x00\x94p\x00\x00\x00\x00\x19\xdb_`\x00\x00\x00\x00\x1a\xcc\xaf\xf0\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\xf3`\xff\xff\xff\xff\xb9\xef\x9c`\xff\xff\xff\xff\xba\xdf\x8d`\xff\xff\xff\xff\xbb\xcf~`\xff\xff\xff\xff\xbc\xc8\xa9\xe0\xff\xff\xff\xff\xbd\xb8\x9a\xe0\xff\xff\xff\xff\xbe\xa8\x8b\xe0\xff\xff\xff\xff\xbf\x98|\xe0\xff\xff\xff\xff\xc0\x88m\xe0\xff\xff\xff\xff\xc1x^\xe0\xff\xff\xff\xff\xc2hO\xe0\xff\xff\xff\xff\xc3X@\xe0\xff\xff\xff\xff\xc4H1\xe0\xff\xff\xff\xff\xc58\x22\xe0\xff\xff\xff\xff\xc6(\x13\xe0\xff\xff\xff\xff\xc7\x18\x04\xe0\xff\xff\xff\xff\xc8\xbc\x93`\xff\xff\xff\xff\xcaw}P\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0N\x90`\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00&CL\xe0\x00\x00\x00\x00'\x055\x80\x00\x00\x00\x00'\xf5&\x80\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xcfP\x00\x00\x00\x00+\xb4\xce`\x00\x00\x00\x00,\xa4\xb1P\x00\x00\x00\x00-\x94\xb0`\x00\x00\x00\x00.\x84\x93P\x00\x00\x00\x00/t\x92`\x00\x00\x00\x000duP\x00\x00\x00\x001]\xae\xe0\x00\x00\x00\x002r{\xd0\x00\x00\x00\x002\xc9\x8c\xe0\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x06\x05\x06\x05\x06\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x08\x07\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x04\x00\x00\x1b\x08\x00\x00\x00\x00\x1a\xf4\x00\x04\x00\x00\x18x\x00\x08\x00\x00*0\x01\x0c\x00\x00\x1c \x00\x11\x00\x00\x0e\x10\x00\x15\x00\x00\x1c \x01\x19\x00\x008@\x01\x1e\x00\x00*0\x00\x22LMT\x00CMT\x00BMT\x00EEST\x00EET\x00CET\x00CEST\x00MSD\x00MSK\x00\x0aEET-2EEST,M3.5.0,M10.5.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u\xb0\xcd\xfc\xf8\x02\x00\x00\xf8\x02\x00\x00\x10\x00\x00\x00Europe/UlyanovskTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x00\x00\x00\x07\x00\x00\x00\x14\xff\xff\xff\xff\xa1\x009\x80\xff\xff\xff\xff\xb5\xa4\x0bP\x00\x00\x00\x00\x15'\x99\xc0\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xcd@\x00\x00\x00\x00\x17\xfa\x01\xb0\x00\x00\x00\x00\x18\xea\x00\xc0\x00\x00\x00\x00\x19\xdb50\x00\x00\x00\x00\x1a\xcc\x85\xc0\x00\x00\x00\x00\x1b\xbc\x92\xe0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9ct\xe0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|V\xe0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c8\xe0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<\x1a\xe0\x00\x00\x00\x00$,\x0b\xe0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)x\xbf\x80\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x94\xbep\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xadp\x00\x00\x00\x00G#\xc2\xf0\x00\x00\x00\x00G\xee\xc9\xf0\x00\x00\x00\x00I\x03\xa4\xf0\x00\x00\x00\x00I\xce\xab\xf0\x00\x00\x00\x00J\xe3\x86\xf0\x00\x00\x00\x00K\xae\x8d\xf0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x00\x00\x00\x00TL\x1d`\x00\x00\x00\x00V\xf7\x14p\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x01\x04\x01\x05\x06\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x04\x01\x03\x01\x03\x00\x00-`\x00\x00\x00\x00*0\x00\x04\x00\x00FP\x01\x08\x00\x008@\x00\x0c\x00\x008@\x01\x0c\x00\x00*0\x01\x04\x00\x00\x1c \x00\x10LMT\x00+03\x00+05\x00+04\x00+02\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x81\xbf~.\x02\x00\x00.\x02\x00\x00\x0f\x00\x00\x00Europe/UzhgorodTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x08\x00\x00\x00\x22\xff\xff\xff\xffV\xb6\xc7d\xff\xff\xff\xff\xaa\x19\xa7d\xff\xff\xff\xff\xb5\xa4\x19`\xff\xff\xff\xff\xca\xcd.\xd0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xce\xcd\xa8p\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00&\x8d \xe0\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)\xd5\x08\x80\x00\x00\x00\x00*\xc4\xf9\x80\x00\x00\x00\x00+\xb4\xea\x80\x00\x00\x00\x00,\xa4\xdb\x80\x00\x00\x00\x00-\x94\xcc\x80\x00\x00\x00\x00.\x84\xbd\x80\x00\x00\x00\x00/t\xae\x80\x00\x00\x00\x000d\x9f\x80\x00\x00\x00\x001]\xcb\x00\x00\x00\x00\x001\x96QP\x01\x02\x03\x05\x04\x05\x04\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x07\x02\x07\x02\x07\x02\x07\x02\x07\x02\x07\x07\x00\x00\x1c\x9c\x00\x00\x00\x00\x1c\x9c\x00\x04\x00\x00\x1c \x00\x08\x00\x00*0\x00\x0c\x00\x00\x0e\x10\x00\x10\x00\x00\x1c \x01\x14\x00\x008@\x01\x19\x00\x00*0\x01\x1dLMT\x00KMT\x00EET\x00MSK\x00CET\x00CEST\x00MSD\x00EEST\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Dd#\xc4\xf1\x01\x00\x00\xf1\x01\x00\x00\x0c\x00\x00\x00Europe/VaduzTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff$\xf0\xea\x80\xff\xff\xff\xffq\xd4\x06\x86\xff\xff\xff\xff\xca\x17j\x00\xff\xff\xff\xff\xca\xe2q\x00\xff\xff\xff\xff\xcb\xf7L\x00\xff\xff\xff\xff\xcc\xc2S\x00\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#(\xe8L\xff\xff\xff\xffp\xbc\x81p\xff\xff\xff\xff\x9b8\xf8p\xff\xff\xff\xff\x9b\xd5\xcc\xe0\xff\xff\xff\xff\x9c\xc5\xcb\xf0\xff\xff\xff\xff\x9d\xb7\x00`\xff\xff\xff\xff\x9e\x89\xfep\xff\xff\xff\xff\x9f\xa0\x1c\xe0\xff\xff\xff\xff\xa0`\xa5\xf0\xff\xff\xff\xff\xa1~\xad`\xff\xff\xff\xff\xa2\x5c7p\xff\xff\xff\xff\xa3L\x1a`\xff\xff\xff\xff\xc8l5\xf0\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0n^\x90\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2L\xd2\xf0\xff\xff\xff\xff\xd3>1\x90\xff\xff\xff\xff\xd4I\xd2\x10\xff\xff\xff\xff\xd5\x1d\xf7p\xff\xff\xff\xff\xd6)\x97\xf0\xff\xff\xff\xff\xd6\xeb\x80\x90\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xf93\xb5\xf0\xff\xff\xff\xff\xf9\xd9\xc4\xe0\xff\xff\xff\xff\xfb\x1c\xd2p\xff\xff\xff\xff\xfb\xb9\xb4\xf0\xff\xff\xff\xff\xfc\xfc\xb4p\xff\xff\xff\xff\xfd\x99\x96\xf0\xff\xff\xff\xff\xfe\xe5\xd0\xf0\xff\xff\xff\xff\xff\x82\xb3p\x00\x00\x00\x00\x00\xc5\xb2\xf0\x00\x00\x00\x00\x01b\x95p\x00\x00\x00\x00\x02\x9cZp\x00\x00\x00\x00\x03Bwp\x00\x00\x00\x00\x04\x85v\xf0\x00\x00\x00\x00\x05+\x93\xf0\x00\x00\x00\x00\x06n\x93p\x00\x00\x00\x00\x07\x0bu\xf0\x00\x00\x00\x00\x08E:\xf0\x00\x00\x00\x00\x08\xebW\xf0\x00\x00\x00\x00\x0a.Wp\x00\x00\x00\x00\x0a\xcb9\xf0\x00\x00\x00\x00\x0c\x0e9p\x00\x00\x00\x00\x0c\xab\x1b\xf0\x00\x00\x00\x00\x0d\xe4\xe0\xf0\x00\x00\x00\x00\x0e\x8a\xfd\xf0\x00\x00\x00\x00\x0f\xcd\xfdp\x00\x00\x00\x00\x10t\x1ap\x00\x00\x00\x00\x11\xad\xdfp\x00\x00\x00\x00\x12S\xfcp\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x12\x13`\x01\x02\x03\x04\x03\x05\x06\x03\x06\x03\x06\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x07\x05\x08\x04\x08\x04\x08\x04\x08\x04\x08\x04\x08\x04\x08\x04\x08\x04\x08\x04\x06\x03\x06\x04\x04\x00\x00\x17\xbc\x00\x00\x00\x00\x13\xb0\x00\x04\x00\x00\x16h\x00\x08\x00\x00\x0e\x10\x00\x0c\x00\x00\x1c \x00\x10\x00\x00*0\x00\x14\x00\x00\x1c \x01\x18\x00\x008@\x01\x1d\x00\x00*0\x01!LMT\x00WMT\x00KMT\x00CET\x00EET\x00MSK\x00CEST\x00MSD\x00EEST\x00\x0aEET-2EEST,M3.5.0/3,M10.5.0/4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xec\xa0%\xf1\x02\x00\x00\xf1\x02\x00\x00\x10\x00\x00\x00Europe/VolgogradTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x07\x00\x00\x00\x18\xff\xff\xff\xff\xa1\xf5F\xdc\xff\xff\xff\xff\xb5\xa4\x0bP\x00\x00\x00\x00\x15'\x99\xc0\x00\x00\x00\x00\x16\x18\xce0\x00\x00\x00\x00\x17\x08\xcd@\x00\x00\x00\x00\x17\xfa\x01\xb0\x00\x00\x00\x00\x18\xea\x00\xc0\x00\x00\x00\x00\x19\xdb50\x00\x00\x00\x00\x1a\xcc\x85\xc0\x00\x00\x00\x00\x1b\xbc\x92\xe0\x00\x00\x00\x00\x1c\xac\x83\xe0\x00\x00\x00\x00\x1d\x9ct\xe0\x00\x00\x00\x00\x1e\x8ce\xe0\x00\x00\x00\x00\x1f|V\xe0\x00\x00\x00\x00 lG\xe0\x00\x00\x00\x00!\x5c8\xe0\x00\x00\x00\x00\x22L)\xe0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x94\xbep\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xadp\x00\x00\x00\x00G#\xc2\xf0\x00\x00\x00\x00G\xee\xc9\xf0\x00\x00\x00\x00I\x03\xa4\xf0\x00\x00\x00\x00I\xce\xab\xf0\x00\x00\x00\x00J\xe3\x86\xf0\x00\x00\x00\x00K\xae\x8d\xf0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x00\x00\x00\x00TL\x1d`\x00\x00\x00\x00[\xd4\xed\xf0\x00\x00\x00\x00_\xe7\xb2`\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x05\x04\x05\x04\x05\x02\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x06\x05\x02\x05\x00\x00)\xa4\x00\x00\x00\x00*0\x00\x04\x00\x008@\x00\x08\x00\x00FP\x01\x0c\x00\x008@\x01\x10\x00\x00*0\x00\x14\x00\x008@\x00\x14LMT\x00+03\x00+04\x00+05\x00MSD\x00MSK\x00\x0aMSK-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\xfe\xe5\x9e\x9b\x03\x00\x00\x9b\x03\x00\x00\x0d\x00\x00\x00Europe/WarsawTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x00\x00\x00\x06\x00\x00\x00\x1a\xff\xff\xff\xffV\xb6\xd0P\xff\xff\xff\xff\x99\xa8*\xd0\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xa0\x9a\xb6\x00\xff\xff\xff\xff\xa1e\xbd\x00\xff\xff\xff\xff\xa6}|`\xff\xff\xff\xff\xc8v\xde\x10\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x84\xba\x00\xff\xff\xff\xff\xd1\x95\x92p\xff\xff\xff\xff\xd2\x8a\xbb`\xff\xff\xff\xff\xd3b\xffp\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd5^\xad\x10\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\xff\xff\xff\xff\xe8T\xd2\x00\xff\xff\xff\xff\xe8\xf1\xb4\x80\xff\xff\xff\xff\xe9\xe1\xa5\x80\xff\xff\xff\xff\xea\xd1\x96\x80\xff\xff\xff\xff\xec\x14\x96\x00\xff\xff\xff\xff\xec\xba\xb3\x00\xff\xff\xff\xff\xed\xaa\xa4\x00\xff\xff\xff\xff\xee\x9a\x95\x00\xff\xff\xff\xff\xef\xd4Z\x00\xff\xff\xff\xff\xf0zw\x00\xff\xff\xff\xff\xf1\xb4<\x00\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3\x94\x1e\x00\xff\xff\xff\xff\xf4:;\x00\xff\xff\xff\xff\xf5}:\x80\xff\xff\xff\xff\xf6\x1a\x1d\x00\x00\x00\x00\x00\x0d\xa4U\x80\x00\x00\x00\x00\x0e\x8b\x0c\x00\x00\x00\x00\x00\x0f\x847\x80\x00\x00\x00\x00\x10t(\x80\x00\x00\x00\x00\x11d\x19\x80\x00\x00\x00\x00\x12T\x0a\x80\x00\x00\x00\x00\x13M6\x00\x00\x00\x00\x00\x143\xec\x80\x00\x00\x00\x00\x15#\xdd\x80\x00\x00\x00\x00\x16\x13\xce\x80\x00\x00\x00\x00\x17\x03\xbf\x80\x00\x00\x00\x00\x17\xf3\xb0\x80\x00\x00\x00\x00\x18\xe3\xa1\x80\x00\x00\x00\x00\x19\xd3\x92\x80\x00\x00\x00\x00\x1a\xc3\x83\x80\x00\x00\x00\x00\x1b\xbc\xaf\x00\x00\x00\x00\x00\x1c\xac\xa0\x00\x00\x00\x00\x00\x1d\x9c\x91\x00\x00\x00\x00\x00\x1e\x8c\x82\x00\x00\x00\x00\x00\x1f|s\x00\x00\x00\x00\x00 ld\x00\x00\x00\x00\x00!\x5cU\x00\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\xff\x01\xfe?\x06\x00\x00?\x06\x00\x00\x02\x00\x00\x00GBTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f\x00\x00\x00\x05\x00\x00\x00\x11\xff\xff\xff\xff\x1a]\x09\xcb\xff\xff\xff\xff\x9b&\xad\xa0\xff\xff\xff\xff\x9b\xd6\x05 \xff\xff\xff\xff\x9c\xcf0\xa0\xff\xff\xff\xff\x9d\xa4\xc3\xa0\xff\xff\xff\xff\x9e\x9c\x9d\xa0\xff\xff\xff\xff\x9f\x97\x1a\xa0\xff\xff\xff\xff\xa0\x85\xba \xff\xff\xff\xff\xa1v\xfc\xa0\xff\xff\xff\xff\xa2e\x9c \xff\xff\xff\xff\xa3{\xc8\xa0\xff\xff\xff\xff\xa4N\xb8\xa0\xff\xff\xff\xff\xa5?\xfb \xff\xff\xff\xff\xa6%` \xff\xff\xff\xff\xa7'\xc6 \xff\xff\xff\xff\xa8*, \xff\xff\xff\xff\xa8\xeb\xf8\xa0\xff\xff\xff\xff\xaa\x00\xd3\xa0\xff\xff\xff\xff\xaa\xd5\x15 \xff\xff\xff\xff\xab\xe9\xf0 \xff\xff\xff\xff\xac\xc7l \xff\xff\xff\xff\xad\xc9\xd2 \xff\xff\xff\xff\xae\xa7N \xff\xff\xff\xff\xaf\xa0y\xa0\xff\xff\xff\xff\xb0\x870 \xff\xff\xff\xff\xb1\x92\xd0\xa0\xff\xff\xff\xff\xb2pL\xa0\xff\xff\xff\xff\xb3r\xb2\xa0\xff\xff\xff\xff\xb4P.\xa0\xff\xff\xff\xff\xb5IZ \xff\xff\xff\xff\xb60\x10\xa0\xff\xff\xff\xff\xb72v\xa0\xff\xff\xff\xff\xb8\x0f\xf2\xa0\xff\xff\xff\xff\xb9\x12X\xa0\xff\xff\xff\xff\xb9\xef\xd4\xa0\xff\xff\xff\xff\xba\xe9\x00 \xff\xff\xff\xff\xbb\xd8\xf1 \xff\xff\xff\xff\xbc\xdbW \xff\xff\xff\xff\xbd\xb8\xd3 \xff\xff\xff\xff\xbe\xb1\xfe\xa0\xff\xff\xff\xff\xbf\x98\xb5 \xff\xff\xff\xff\xc0\x9b\x1b \xff\xff\xff\xff\xc1x\x97 \xff\xff\xff\xff\xc2z\xfd \xff\xff\xff\xff\xc3Xy \xff\xff\xff\xff\xc4Q\xa4\xa0\xff\xff\xff\xff\xc58[ \xff\xff\xff\xff\xc6:\xc1 \xff\xff\xff\xff\xc7X\xd6\xa0\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xca\x16&\x90\xff\xff\xff\xff\xca\x97Y\x90\xff\xff\xff\xff\xcb\xd1\x1e\x90\xff\xff\xff\xff\xccw;\x90\xff\xff\xff\xff\xcd\xb1\x00\x90\xff\xff\xff\xff\xce`X\x10\xff\xff\xff\xff\xcf\x90\xe2\x90\xff\xff\xff\xff\xd0n^\x90\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd1\xfb2\x10\xff\xff\xff\xff\xd2i\xfe \xff\xff\xff\xff\xd3c)\xa0\xff\xff\xff\xff\xd4I\xe0 \xff\xff\xff\xff\xd5\x1e!\xa0\xff\xff\xff\xff\xd5B\xfd\x90\xff\xff\xff\xff\xd5\xdf\xe0\x10\xff\xff\xff\xff\xd6N\xac \xff\xff\xff\xff\xd6\xfe\x03\xa0\xff\xff\xff\xff\xd8.\x8e \xff\xff\xff\xff\xd8\xf9\x95 \xff\xff\xff\xff\xda\x0ep \xff\xff\xff\xff\xda\xeb\xec \xff\xff\xff\xff\xdb\xe5\x17\xa0\xff\xff\xff\xff\xdc\xcb\xce \xff\xff\xff\xff\xdd\xc4\xf9\xa0\xff\xff\xff\xff\xde\xb4\xea\xa0\xff\xff\xff\xff\xdf\xae\x16 \xff\xff\xff\xff\xe0\x94\xcc\xa0\xff\xff\xff\xff\xe1rH\xa0\xff\xff\xff\xff\xe2kt \xff\xff\xff\xff\xe3R*\xa0\xff\xff\xff\xff\xe4T\x90\xa0\xff\xff\xff\xff\xe52\x0c\xa0\xff\xff\xff\xff\xe6=\xad \xff\xff\xff\xff\xe7\x1b) \xff\xff\xff\xff\xe8\x14T\xa0\xff\xff\xff\xff\xe8\xfb\x0b \xff\xff\xff\xff\xe9\xfdq \xff\xff\xff\xff\xea\xda\xed \xff\xff\xff\xff\xeb\xddS \xff\xff\xff\xff\xec\xba\xcf \xff\xff\xff\xff\xed\xb3\xfa\xa0\xff\xff\xff\xff\xee\x9a\xb1 \xff\xff\xff\xff\xef\x81g\xa0\xff\xff\xff\xff\xf0\x9f} \xff\xff\xff\xff\xf1aI\xa0\xff\xff\xff\xff\xf2\x7f_ \xff\xff\xff\xff\xf3Jf \xff\xff\xff\xff\xf4_A \xff\xff\xff\xff\xf5!\x0d\xa0\xff\xff\xff\xff\xf6?# \xff\xff\xff\xff\xf7\x00\xef\xa0\xff\xff\xff\xff\xf8\x1f\x05 \xff\xff\xff\xff\xf8\xe0\xd1\xa0\xff\xff\xff\xff\xf9\xfe\xe7 \xff\xff\xff\xff\xfa\xc0\xb3\xa0\xff\xff\xff\xff\xfb\xe8\x03\xa0\xff\xff\xff\xff\xfc{\xab\xa0\xff\xff\xff\xff\xfd\xc7\xbbp\x00\x00\x00\x00\x03p\xc6 \x00\x00\x00\x00\x04)X \x00\x00\x00\x00\x05P\xa8 \x00\x00\x00\x00\x06\x09: \x00\x00\x00\x00\x070\x8a \x00\x00\x00\x00\x07\xe9\x1c \x00\x00\x00\x00\x09\x10l \x00\x00\x00\x00\x09\xc8\xfe \x00\x00\x00\x00\x0a\xf0N \x00\x00\x00\x00\x0b\xb2\x1a\xa0\x00\x00\x00\x00\x0c\xd00 \x00\x00\x00\x00\x0d\x91\xfc\xa0\x00\x00\x00\x00\x0e\xb0\x12 \x00\x00\x00\x00\x0fq\xde\xa0\x00\x00\x00\x00\x10\x99.\xa0\x00\x00\x00\x00\x11Q\xc0\xa0\x00\x00\x00\x00\x12y\x10\xa0\x00\x00\x00\x00\x131\xa2\xa0\x00\x00\x00\x00\x14X\xf2\xa0\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x168\xc6\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x18\x18\xa8\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xf8\x8a\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xe1\xa7\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\xc1\x89\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f\xa1k\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x81M\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#a/\x10\x00\x00\x00\x00$,6\x10\x00\x00\x00\x00%JK\x90\x00\x00\x00\x00&\x0c\x18\x10\x00\x00\x00\x00'*-\x90\x00\x00\x00\x00'\xf54\x90\x00\x00\x00\x00)\x0a\x0f\x90\x00\x00\x00\x00)\xd5\x16\x90\x00\x00\x00\x00*\xe9\xf1\x90\x00\x00\x00\x00+\xb4\xf8\x90\x00\x00\x00\x00,\xc9\xd3\x90\x00\x00\x00\x00-\x94\xda\x90\x00\x00\x00\x00.\xa9\xb5\x90\x00\x00\x00\x00/t\xbc\x90\x00\x00\x00\x000\x89\x97\x90\x00\x00\x00\x000\xe7$\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x02\xff\xff\xff\xb5\x00\x00\x00\x00\x0e\x10\x01\x04\x00\x00\x00\x00\x00\x08\x00\x00\x1c \x01\x0c\x00\x00\x0e\x10\x00\x04LMT\x00BST\x00GMT\x00BDST\x00\x0aGMT0BST,M3.5.0/1,M10.5.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\xff\x01\xfe?\x06\x00\x00?\x06\x00\x00\x07\x00\x00\x00GB-EireTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f\x00\x00\x00\x05\x00\x00\x00\x11\xff\xff\xff\xff\x1a]\x09\xcb\xff\xff\xff\xff\x9b&\xad\xa0\xff\xff\xff\xff\x9b\xd6\x05 \xff\xff\xff\xff\x9c\xcf0\xa0\xff\xff\xff\xff\x9d\xa4\xc3\xa0\xff\xff\xff\xff\x9e\x9c\x9d\xa0\xff\xff\xff\xff\x9f\x97\x1a\xa0\xff\xff\xff\xff\xa0\x85\xba \xff\xff\xff\xff\xa1v\xfc\xa0\xff\xff\xff\xff\xa2e\x9c \xff\xff\xff\xff\xa3{\xc8\xa0\xff\xff\xff\xff\xa4N\xb8\xa0\xff\xff\xff\xff\xa5?\xfb \xff\xff\xff\xff\xa6%` \xff\xff\xff\xff\xa7'\xc6 \xff\xff\xff\xff\xa8*, \xff\xff\xff\xff\xa8\xeb\xf8\xa0\xff\xff\xff\xff\xaa\x00\xd3\xa0\xff\xff\xff\xff\xaa\xd5\x15 \xff\xff\xff\xff\xab\xe9\xf0 \xff\xff\xff\xff\xac\xc7l \xff\xff\xff\xff\xad\xc9\xd2 \xff\xff\xff\xff\xae\xa7N \xff\xff\xff\xff\xaf\xa0y\xa0\xff\xff\xff\xff\xb0\x870 \xff\xff\xff\xff\xb1\x92\xd0\xa0\xff\xff\xff\xff\xb2pL\xa0\xff\xff\xff\xff\xb3r\xb2\xa0\xff\xff\xff\xff\xb4P.\xa0\xff\xff\xff\xff\xb5IZ \xff\xff\xff\xff\xb60\x10\xa0\xff\xff\xff\xff\xb72v\xa0\xff\xff\xff\xff\xb8\x0f\xf2\xa0\xff\xff\xff\xff\xb9\x12X\xa0\xff\xff\xff\xff\xb9\xef\xd4\xa0\xff\xff\xff\xff\xba\xe9\x00 \xff\xff\xff\xff\xbb\xd8\xf1 \xff\xff\xff\xff\xbc\xdbW \xff\xff\xff\xff\xbd\xb8\xd3 \xff\xff\xff\xff\xbe\xb1\xfe\xa0\xff\xff\xff\xff\xbf\x98\xb5 \xff\xff\xff\xff\xc0\x9b\x1b \xff\xff\xff\xff\xc1x\x97 \xff\xff\xff\xff\xc2z\xfd \xff\xff\xff\xff\xc3Xy \xff\xff\xff\xff\xc4Q\xa4\xa0\xff\xff\xff\xff\xc58[ \xff\xff\xff\xff\xc6:\xc1 \xff\xff\xff\xff\xc7X\xd6\xa0\xff\xff\xff\xff\xc7\xda\x09\xa0\xff\xff\xff\xff\xca\x16&\x90\xff\xff\xff\xff\xca\x97Y\x90\xff\xff\xff\xff\xcb\xd1\x1e\x90\xff\xff\xff\xff\xccw;\x90\xff\xff\xff\xff\xcd\xb1\x00\x90\xff\xff\xff\xff\xce`X\x10\xff\xff\xff\xff\xcf\x90\xe2\x90\xff\xff\xff\xff\xd0n^\x90\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd1\xfb2\x10\xff\xff\xff\xff\xd2i\xfe \xff\xff\xff\xff\xd3c)\xa0\xff\xff\xff\xff\xd4I\xe0 \xff\xff\xff\xff\xd5\x1e!\xa0\xff\xff\xff\xff\xd5B\xfd\x90\xff\xff\xff\xff\xd5\xdf\xe0\x10\xff\xff\xff\xff\xd6N\xac \xff\xff\xff\xff\xd6\xfe\x03\xa0\xff\xff\xff\xff\xd8.\x8e \xff\xff\xff\xff\xd8\xf9\x95 \xff\xff\xff\xff\xda\x0ep \xff\xff\xff\xff\xda\xeb\xec \xff\xff\xff\xff\xdb\xe5\x17\xa0\xff\xff\xff\xff\xdc\xcb\xce \xff\xff\xff\xff\xdd\xc4\xf9\xa0\xff\xff\xff\xff\xde\xb4\xea\xa0\xff\xff\xff\xff\xdf\xae\x16 \xff\xff\xff\xff\xe0\x94\xcc\xa0\xff\xff\xff\xff\xe1rH\xa0\xff\xff\xff\xff\xe2kt \xff\xff\xff\xff\xe3R*\xa0\xff\xff\xff\xff\xe4T\x90\xa0\xff\xff\xff\xff\xe52\x0c\xa0\xff\xff\xff\xff\xe6=\xad \xff\xff\xff\xff\xe7\x1b) \xff\xff\xff\xff\xe8\x14T\xa0\xff\xff\xff\xff\xe8\xfb\x0b \xff\xff\xff\xff\xe9\xfdq \xff\xff\xff\xff\xea\xda\xed \xff\xff\xff\xff\xeb\xddS \xff\xff\xff\xff\xec\xba\xcf \xff\xff\xff\xff\xed\xb3\xfa\xa0\xff\xff\xff\xff\xee\x9a\xb1 \xff\xff\xff\xff\xef\x81g\xa0\xff\xff\xff\xff\xf0\x9f} \xff\xff\xff\xff\xf1aI\xa0\xff\xff\xff\xff\xf2\x7f_ \xff\xff\xff\xff\xf3Jf \xff\xff\xff\xff\xf4_A \xff\xff\xff\xff\xf5!\x0d\xa0\xff\xff\xff\xff\xf6?# \xff\xff\xff\xff\xf7\x00\xef\xa0\xff\xff\xff\xff\xf8\x1f\x05 \xff\xff\xff\xff\xf8\xe0\xd1\xa0\xff\xff\xff\xff\xf9\xfe\xe7 \xff\xff\xff\xff\xfa\xc0\xb3\xa0\xff\xff\xff\xff\xfb\xe8\x03\xa0\xff\xff\xff\xff\xfc{\xab\xa0\xff\xff\xff\xff\xfd\xc7\xbbp\x00\x00\x00\x00\x03p\xc6 \x00\x00\x00\x00\x04)X \x00\x00\x00\x00\x05P\xa8 \x00\x00\x00\x00\x06\x09: \x00\x00\x00\x00\x070\x8a \x00\x00\x00\x00\x07\xe9\x1c \x00\x00\x00\x00\x09\x10l \x00\x00\x00\x00\x09\xc8\xfe \x00\x00\x00\x00\x0a\xf0N \x00\x00\x00\x00\x0b\xb2\x1a\xa0\x00\x00\x00\x00\x0c\xd00 \x00\x00\x00\x00\x0d\x91\xfc\xa0\x00\x00\x00\x00\x0e\xb0\x12 \x00\x00\x00\x00\x0fq\xde\xa0\x00\x00\x00\x00\x10\x99.\xa0\x00\x00\x00\x00\x11Q\xc0\xa0\x00\x00\x00\x00\x12y\x10\xa0\x00\x00\x00\x00\x131\xa2\xa0\x00\x00\x00\x00\x14X\xf2\xa0\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x168\xc6\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x18\x18\xa8\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xf8\x8a\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xe1\xa7\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\xc1\x89\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f\xa1k\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x81M\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#a/\x10\x00\x00\x00\x00$,6\x10\x00\x00\x00\x00%JK\x90\x00\x00\x00\x00&\x0c\x18\x10\x00\x00\x00\x00'*-\x90\x00\x00\x00\x00'\xf54\x90\x00\x00\x00\x00)\x0a\x0f\x90\x00\x00\x00\x00)\xd5\x16\x90\x00\x00\x00\x00*\xe9\xf1\x90\x00\x00\x00\x00+\xb4\xf8\x90\x00\x00\x00\x00,\xc9\xd3\x90\x00\x00\x00\x00-\x94\xda\x90\x00\x00\x00\x00.\xa9\xb5\x90\x00\x00\x00\x00/t\xbc\x90\x00\x00\x00\x000\x89\x97\x90\x00\x00\x00\x000\xe7$\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x02\x01\x02\x01\x03\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x02\xff\xff\xff\xb5\x00\x00\x00\x00\x0e\x10\x01\x04\x00\x00\x00\x00\x00\x08\x00\x00\x1c \x01\x0c\x00\x00\x0e\x10\x00\x04LMT\x00BST\x00GMT\x00BDST\x00\x0aGMT0BST,M3.5.0/1,M10.5.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00GMTTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x05\x00\x00\x00GMT+0TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x05\x00\x00\x00GMT-0TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x04\x00\x00\x00GMT0TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00GreenwichTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\xf7\xfawp\x00\x00\x00p\x00\x00\x00\x03\x00\x00\x00HSTTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\xff\xffs`\x00\x00HST\x00\x0aHST10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x09\xfa-\x07\x03\x00\x00\x07\x03\x00\x00\x08\x00\x00\x00HongkongTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x00\x00\x00\x05\x00\x00\x00\x16\xff\xff\xff\xff\x85ic\x90\xff\xff\xff\xff\xcaM10\xff\xff\xff\xff\xca\xdb\x930\xff\xff\xff\xff\xcbKqx\xff\xff\xff\xff\xd2\xa0\xde\x90\xff\xff\xff\xff\xd3k\xd7\x80\xff\xff\xff\xff\xd4\x93X\xb8\xff\xff\xff\xff\xd5B\xb08\xff\xff\xff\xff\xd6s:\xb8\xff\xff\xff\xff\xd7>A\xb8\xff\xff\xff\xff\xd8.2\xb8\xff\xff\xff\xff\xd8\xf99\xb8\xff\xff\xff\xff\xda\x0e\x14\xb8\xff\xff\xff\xff\xda\xd9\x1b\xb8\xff\xff\xff\xff\xdb\xed\xf6\xb8\xff\xff\xff\xff\xdc\xb8\xfd\xb8\xff\xff\xff\xff\xdd\xcd\xd8\xb8\xff\xff\xff\xff\xde\xa2\x1a8\xff\xff\xff\xff\xdf\xb6\xf58\xff\xff\xff\xff\xe0\x81\xfc8\xff\xff\xff\xff\xe1\x96\xc9(\xff\xff\xff\xff\xe2Oi8\xff\xff\xff\xff\xe3v\xab(\xff\xff\xff\xff\xe4/K8\xff\xff\xff\xff\xe5_\xc7\xa8\xff\xff\xff\xff\xe6\x0f-8\xff\xff\xff\xff\xe7?\xa9\xa8\xff\xff\xff\xff\xe7\xf8I\xb8\xff\xff\xff\xff\xe9\x1f\x8b\xa8\xff\xff\xff\xff\xe9\xd8+\xb8\xff\xff\xff\xff\xea\xffm\xa8\xff\xff\xff\xff\xeb\xb8\x0d\xb8\xff\xff\xff\xff\xec\xdfO\xa8\xff\xff\xff\xff\xed\x97\xef\xb8\xff\xff\xff\xff\xee\xc8l(\xff\xff\xff\xff\xefw\xd1\xb8\xff\xff\xff\xff\xf0\xa8N(\xff\xff\xff\xff\xf1W\xb3\xb8\xff\xff\xff\xff\xf2\x880(\xff\xff\xff\xff\xf3@\xd08\xff\xff\xff\xff\xf4h\x12(\xff\xff\xff\xff\xf5 \xb28\xff\xff\xff\xff\xf6G\xf4(\xff\xff\xff\xff\xf7%~8\xff\xff\xff\xff\xf8\x15a(\xff\xff\xff\xff\xf9\x05`8\xff\xff\xff\xff\xf9\xf5C(\xff\xff\xff\xff\xfa\xe5B8\xff\xff\xff\xff\xfb\xde_\xa8\xff\xff\xff\xff\xfc\xce^\xb8\xff\xff\xff\xff\xfd\xbeA\xa8\xff\xff\xff\xff\xfe\xae@\xb8\xff\xff\xff\xff\xff\x9e#\xa8\x00\x00\x00\x00\x00\x8e\x22\xb8\x00\x00\x00\x00\x01~\x05\xa8\x00\x00\x00\x00\x02n\x04\xb8\x00\x00\x00\x00\x03]\xe7\xa8\x00\x00\x00\x00\x04M\xe6\xb8\x00\x00\x00\x00\x05G\x04(\x00\x00\x00\x00\x067\x038\x00\x00\x00\x00\x07&\xe6(\x00\x00\x00\x00\x07\x83=8\x00\x00\x00\x00\x09\x06\xc8(\x00\x00\x00\x00\x09\xf6\xc78\x00\x00\x00\x00\x0a\xe6\xaa(\x00\x00\x00\x00\x0b\xd6\xa98\x00\x00\x00\x00\x0c\xc6\x8c(\x00\x00\x00\x00\x11\x9b98\x00\x00\x00\x00\x12ol\xa8\x01\x02\x03\x04\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x00\x00k\x0a\x00\x00\x00\x00p\x80\x00\x04\x00\x00~\x90\x01\x08\x00\x00w\x88\x01\x0d\x00\x00~\x90\x00\x12LMT\x00HKT\x00HKST\x00HKWT\x00JST\x00\x0aHKT-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x07\x00\x00\x00IcelandTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x92\xe6\x92H\x01\xff\xff\xfc8\x00\x00\x00\x00\x00\x00\x00\x04LMT\x00GMT\x00\x0aGMT0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x13\x00\x00\x00Indian/AntananarivoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\xb0W\x14\x98\x00\x00\x00\x98\x00\x00\x00\x0d\x00\x00\x00Indian/ChagosTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x89~\xf7\x9c\x00\x00\x00\x000\xe6\xdd\xb0\x01\x02\x00\x00C\xe4\x00\x00\x00\x00FP\x00\x04\x00\x00T`\x00\x08LMT\x00+05\x00+06\x00\x0a<+06>-6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x10\x00\x00\x00Indian/ChristmasTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffV\xb6\x85\xc4\xff\xff\xff\xff\xa2jg\xc4\x01\x02\x00\x00^<\x00\x00\x00\x00^<\x00\x04\x00\x00bp\x00\x08LMT\x00BMT\x00+07\x00\x0a<+07>-7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\x87{_\xbb\x00\x00\x00\xbb\x00\x00\x00\x0c\x00\x00\x00Indian/CocosTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xffV\xb6\x89\xd1\xff\xff\xff\xff\xa1\xf2sQ\xff\xff\xff\xff\xcb\xf2\xfc\x18\xff\xff\xff\xff\xd1\x9ag\xf0\x01\x02\x03\x02\x00\x00Z/\x00\x00\x00\x00Z/\x00\x04\x00\x00[h\x00\x08\x00\x00~\x90\x00\x0eLMT\x00RMT\x00+0630\x00+09\x00\x0a<+0630>-6:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0d\x00\x00\x00Indian/ComoroTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb9\xb2Z\xac\x98\x00\x00\x00\x98\x00\x00\x00\x10\x00\x00\x00Indian/KerguelenTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffV\xb6\x9f\x18\xff\xff\xff\xff\xed/\xc3\x98\x01\x02\x00\x00D\xe8\x00\x00\x00\x00D\xe8\x00\x04\x00\x00FP\x00\x08LMT\x00MMT\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00Indian/MaheTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xa1\xf2\x99\xa8\x01\x00\x003\xd8\x00\x00\x00\x008@\x00\x04LMT\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb9\xb2Z\xac\x98\x00\x00\x00\x98\x00\x00\x00\x0f\x00\x00\x00Indian/MaldivesTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffV\xb6\x9f\x18\xff\xff\xff\xff\xed/\xc3\x98\x01\x02\x00\x00D\xe8\x00\x00\x00\x00D\xe8\x00\x04\x00\x00FP\x00\x08LMT\x00MMT\x00+05\x00\x0a<+05>-5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xed=\x98\xb3\x00\x00\x00\xb3\x00\x00\x00\x10\x00\x00\x00Indian/MauritiusTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x89\x7f\x05\x98\x00\x00\x00\x00\x18\x05\xed@\x00\x00\x00\x00\x18\xdbr0\x00\x00\x00\x00I\x03\x96\xe0\x00\x00\x00\x00I\xce\x8f\xd0\x02\x01\x02\x01\x02\x00\x005\xe8\x00\x00\x00\x00FP\x01\x04\x00\x008@\x00\x08LMT\x00+05\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0e\x00\x00\x00Indian/MayotteTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x04\x00\x00\x00\x14\xff\xff\xff\xff\x8b\xff\xd1\xfc\xff\xff\xff\xff\xb1\xee\xdaX\xff\xff\xff\xff\xb4\xc7\xe0\xd0\xff\xff\xff\xff\xc1\xed\xadX\xff\xff\xff\xff\xcclz\xd4\x01\x02\x01\x03\x02\x00\x00\x22\x84\x00\x00\x00\x00#(\x00\x04\x00\x00*0\x00\x0a\x00\x00&\xac\x00\x0eLMT\x00+0230\x00EAT\x00+0245\x00\x0aEAT-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0e\x00\x00\x00Indian/ReunionTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\xa1\xf2\x99\xa8\x01\x00\x003\xd8\x00\x00\x00\x008@\x00\x04LMT\x00+04\x00\x0a<+04>-4\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\xdb?\xec,\x03\x00\x00,\x03\x00\x00\x04\x00\x00\x00IranTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00G\x00\x00\x00\x06\x00\x00\x00\x1c\xff\xff\xff\xff\x9al}\xc8\xff\xff\xff\xff\xbf\x00\xccH\x00\x00\x00\x00\x0d\x94D8\x00\x00\x00\x00\x0e\xad\x13\xb8\x00\x00\x00\x00\x0fys@\x00\x00\x00\x00\x10(\xca\xc0\x00\x00\x00\x00\x10\xed:@\x00\x00\x00\x00\x11\xad\xbcH\x00\x00\x00\x00\x12EJ\xb8\x00\x00\x00\x00\x137\xec\xc8\x00\x00\x00\x00\x14-\x15\xb8\x00\x00\x00\x00( v\xc8\x00\x00\x00\x00(\xdb\x9d\xb8\x00\x00\x00\x00)\xcb\x9c\xc8\x00\x00\x00\x00*\xbe\x22\xb8\x00\x00\x00\x00+\xac\xd0H\x00\x00\x00\x00,\x9fV8\x00\x00\x00\x00-\x8e\x03\xc8\x00\x00\x00\x00.\x80\x89\xb8\x00\x00\x00\x00/o7H\x00\x00\x00\x000a\xbd8\x00\x00\x00\x001Pj\xc8\x00\x00\x00\x002B\xf0\xb8\x00\x00\x00\x0032\xef\xc8\x00\x00\x00\x004%u\xb8\x00\x00\x00\x005\x14#H\x00\x00\x00\x006\x06\xa98\x00\x00\x00\x006\xf5V\xc8\x00\x00\x00\x007\xe7\xdc\xb8\x00\x00\x00\x008\xd6\x8aH\x00\x00\x00\x009\xc9\x108\x00\x00\x00\x00:\xb9\x0fH\x00\x00\x00\x00;\xab\x958\x00\x00\x00\x00<\x9aB\xc8\x00\x00\x00\x00=\x8c\xc8\xb8\x00\x00\x00\x00>{vH\x00\x00\x00\x00?m\xfc8\x00\x00\x00\x00@\x5c\xa9\xc8\x00\x00\x00\x00AO/\xb8\x00\x00\x00\x00B?.\xc8\x00\x00\x00\x00C1\xb4\xb8\x00\x00\x00\x00G\xe2\xc9H\x00\x00\x00\x00H\xd5O8\x00\x00\x00\x00I\xc5NH\x00\x00\x00\x00J\xb7\xd48\x00\x00\x00\x00K\xa6\x81\xc8\x00\x00\x00\x00L\x99\x07\xb8\x00\x00\x00\x00M\x87\xb5H\x00\x00\x00\x00Nz;8\x00\x00\x00\x00Oh\xe8\xc8\x00\x00\x00\x00P[n\xb8\x00\x00\x00\x00QKm\xc8\x00\x00\x00\x00R=\xf3\xb8\x00\x00\x00\x00S,\xa1H\x00\x00\x00\x00T\x1f'8\x00\x00\x00\x00U\x0d\xd4\xc8\x00\x00\x00\x00V\x00Z\xb8\x00\x00\x00\x00V\xef\x08H\x00\x00\x00\x00W\xe1\x8e8\x00\x00\x00\x00X\xd1\x8dH\x00\x00\x00\x00Y\xc4\x138\x00\x00\x00\x00Z\xb2\xc0\xc8\x00\x00\x00\x00[\xa5F\xb8\x00\x00\x00\x00\x5c\x93\xf4H\x00\x00\x00\x00]\x86z8\x00\x00\x00\x00^u'\xc8\x00\x00\x00\x00_g\xad\xb8\x00\x00\x00\x00`W\xac\xc8\x00\x00\x00\x00aJ2\xb8\x00\x00\x00\x00b8\xe0H\x00\x00\x00\x00c+f8\x01\x03\x02\x05\x04\x05\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x00\x0008\x00\x00\x00\x0008\x00\x04\x00\x00?H\x01\x08\x00\x0018\x00\x0e\x00\x00FP\x01\x14\x00\x008@\x00\x18LMT\x00TMT\x00+0430\x00+0330\x00+05\x00+04\x00\x0a<+0330>-3:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xe2\x9c\xb32\x04\x00\x002\x04\x00\x00\x06\x00\x00\x00IsraelTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xffV\xb6\xc2\xfa\xff\xff\xff\xff\x9e0E\x88\xff\xff\xff\xff\xc8Y\xcf\x00\xff\xff\xff\xff\xc8\xfa\xa6\x00\xff\xff\xff\xff\xc98\x9c\x80\xff\xff\xff\xff\xcc\xe5\xeb\x80\xff\xff\xff\xff\xcd\xac\xfe\x00\xff\xff\xff\xff\xce\xc7\x1f\x00\xff\xff\xff\xff\xcf\x8f\x83\x00\xff\xff\xff\xff\xd0\xa9\xa4\x00\xff\xff\xff\xff\xd1\x84}\x00\xff\xff\xff\xff\xd2\x8a\xd7\x80\xff\xff\xff\xff\xd3e\xb0\x80\xff\xff\xff\xff\xd4l\x0b\x00\xff\xff\xff\xff\xd7Z0\x80\xff\xff\xff\xff\xd7\xdfX\x00\xff\xff\xff\xff\xd8/\xc3\x80\xff\xff\xff\xff\xd9\x1ec\x00\xff\xff\xff\xff\xda\x10\xf7\x00\xff\xff\xff\xff\xda\xeb\xd0\x00\xff\xff\xff\xff\xdb\xb44\x00\xff\xff\xff\xff\xdc\xb9=\x00\xff\xff\xff\xff\xdd\xe0\x8d\x00\xff\xff\xff\xff\xde\xb4\xce\x80\xff\xff\xff\xff\xdf\xa4\xbf\x80\xff\xff\xff\xff\xe0\x8bv\x00\xff\xff\xff\xff\xe1V}\x00\xff\xff\xff\xff\xe2\xbef\x80\xff\xff\xff\xff\xe36_\x00\xff\xff\xff\xff\xe4\x9eH\x80\xff\xff\xff\xff\xe5\x16A\x00\xff\xff\xff\xff\xe6t\xf0\x00\xff\xff\xff\xff\xe7\x11\xd2\x80\xff\xff\xff\xff\xe8&\xad\x80\xff\xff\xff\xff\xe8\xe8z\x00\x00\x00\x00\x00\x08|\x8b\xe0\x00\x00\x00\x00\x08\xfd\xb0\xd0\x00\x00\x00\x00\x09\xf6\xea`\x00\x00\x00\x00\x0a\xa63\xd0\x00\x00\x00\x00\x13\xe9\xfc`\x00\x00\x00\x00\x14![`\x00\x00\x00\x00\x1a\xfa\xc6`\x00\x00\x00\x00\x1b\x8en`\x00\x00\x00\x00\x1c\xbe\xf8\xe0\x00\x00\x00\x00\x1dw|\xd0\x00\x00\x00\x00\x1e\xcc\xff`\x00\x00\x00\x00\x1f`\x99P\x00\x00\x00\x00 \x82\xb1`\x00\x00\x00\x00!I\xb5\xd0\x00\x00\x00\x00\x22^\x9e\xe0\x00\x00\x00\x00# ]P\x00\x00\x00\x00$Z0`\x00\x00\x00\x00%\x00?P\x00\x00\x00\x00&\x0b\xed\xe0\x00\x00\x00\x00&\xd6\xe6\xd0\x00\x00\x00\x00'\xeb\xcf\xe0\x00\x00\x00\x00(\xc0\x03P\x00\x00\x00\x00)\xd4\xec`\x00\x00\x00\x00*\xa9\x1f\xd0\x00\x00\x00\x00+\xbbe\xe0\x00\x00\x00\x00,\x89\x01\xd0\x00\x00\x00\x00-\x9bG\xe0\x00\x00\x00\x00._\xa9P\x00\x00\x00\x00/{)\xe0\x00\x00\x00\x000H\xc5\xd0\x00\x00\x00\x001H\x96\xe0\x00\x00\x00\x002\x83\x82p\x00\x00\x00\x00?|\x9f\xe0\x00\x00\x00\x00@s6p\x00\x00\x00\x00AP\xa4`\x00\x00\x00\x00BL\x8f\x00\x00\x00\x00\x00CHOp\x00\x00\x00\x00D,q\x00\x00\x00\x00\x00E\x1e\xf6\xf0\x00\x00\x00\x00F\x0cS\x00\x00\x00\x00\x00F\xecc\xf0\x00\x00\x00\x00G\xec5\x00\x00\x00\x00\x00H\xe7\xf5p\x00\x00\x00\x00I\xcc\x17\x00\x00\x00\x00\x00J\xbe\x9c\xf0\x00\x00\x00\x00K\xab\xf9\x00\x00\x00\x00\x00L\x8c\x09\xf0\x00\x00\x00\x00M\x95\x15\x80\x00\x00\x00\x00N\x87\x9bp\x00\x00\x00\x00Ot\xf7\x80\x00\x00\x00\x00P^B\xf0\x00\x00\x00\x00QT\xd9\x80\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x04\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x00!\x06\x00\x00\x00\x00 \xf8\x00\x04\x00\x00*0\x01\x08\x00\x00\x1c \x00\x0c\x00\x008@\x01\x10LMT\x00JMT\x00IDT\x00IST\x00IDDT\x00\x0aIST-2IDT,M3.4.4/26,M10.5.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%J\xd5\xebS\x01\x00\x00S\x01\x00\x00\x07\x00\x00\x00JamaicaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xffi\x87#~\xff\xff\xff\xff\x93\x0f\xb4\xfe\x00\x00\x00\x00\x07\x8d\x19p\x00\x00\x00\x00\x09\x10\xa4`\x00\x00\x00\x00\x09\xad\x94\xf0\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00\x0b\xe0\x85p\x00\x00\x00\x00\x0c\xd9\xa2\xe0\x00\x00\x00\x00\x0d\xc0gp\x00\x00\x00\x00\x0e\xb9\x84\xe0\x00\x00\x00\x00\x0f\xa9\x83\xf0\x00\x00\x00\x00\x10\x99f\xe0\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\xff\xff\xb8\x02\x00\x00\xff\xff\xb8\x02\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0cLMT\x00KMT\x00EST\x00EDT\x00\x0aEST5\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xf4\xaeg\xd5\x00\x00\x00\xd5\x00\x00\x00\x05\x00\x00\x00JapanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xffe\xc2\xa4p\xff\xff\xff\xff\xd7>\x02p\xff\xff\xff\xff\xd7\xedY\xf0\xff\xff\xff\xff\xd8\xf8\xfap\xff\xff\xff\xff\xd9\xcd;\xf0\xff\xff\xff\xff\xdb\x07\x00\xf0\xff\xff\xff\xff\xdb\xad\x1d\xf0\xff\xff\xff\xff\xdc\xe6\xe2\xf0\xff\xff\xff\xff\xdd\x8c\xff\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x83\x03\x00\x00\x00\x00\x8c\xa0\x01\x04\x00\x00~\x90\x00\x08LMT\x00JDT\x00JST\x00\x0aJST-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xe8]*\xdb\x00\x00\x00\xdb\x00\x00\x00\x09\x00\x00\x00KwajaleinTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff~6\x18 \xff\xff\xff\xff\xc1\xed5\xd0\xff\xff\xff\xff\xc9\xea\x0a`\xff\xff\xff\xff\xcfF\x81\xf0\xff\xff\xff\xff\xff\x86\x1bP\x00\x00\x00\x00,v\x0e@\x01\x02\x03\x01\x04\x05\x00\x00\x9c\xe0\x00\x00\x00\x00\x9a\xb0\x00\x04\x00\x00\x8c\xa0\x00\x08\x00\x00~\x90\x00\x0c\xff\xffW@\x00\x10\x00\x00\xa8\xc0\x00\x14LMT\x00+11\x00+10\x00+09\x00-12\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\x7f2[\xaf\x01\x00\x00\xaf\x01\x00\x00\x05\x00\x00\x00LibyaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x04\x00\x00\x00\x11\xff\xff\xff\xff\xa1\xf2\xc1$\xff\xff\xff\xff\xdd\xbb\xb1\x10\xff\xff\xff\xff\xde#\xad`\xff\xff\xff\xff\xe1x\xd2\x10\xff\xff\xff\xff\xe1\xe7e\xe0\xff\xff\xff\xff\xe5/?p\xff\xff\xff\xff\xe5\xa9\xcc\xe0\xff\xff\xff\xff\xebN\xc6\xf0\x00\x00\x00\x00\x16\x92B`\x00\x00\x00\x00\x17\x08\xf7p\x00\x00\x00\x00\x17\xfa+\xe0\x00\x00\x00\x00\x18\xea*\xf0\x00\x00\x00\x00\x19\xdb_`\x00\x00\x00\x00\x1a\xcc\xaf\xf0\x00\x00\x00\x00\x1b\xbd\xe4`\x00\x00\x00\x00\x1c\xb4z\xf0\x00\x00\x00\x00\x1d\x9f\x17\xe0\x00\x00\x00\x00\x1e\x93\x0bp\x00\x00\x00\x00\x1f\x82\xee`\x00\x00\x00\x00 pJp\x00\x00\x00\x00!a~\xe0\x00\x00\x00\x00\x22R\xcfp\x00\x00\x00\x00#D\x03\xe0\x00\x00\x00\x00$4\x02\xf0\x00\x00\x00\x00%%7`\x00\x00\x00\x00&@\xb7\xf0\x00\x00\x00\x002N\xf1`\x00\x00\x00\x003D6p\x00\x00\x00\x0045j\xe0\x00\x00\x00\x00P\x9d\x99\x00\x00\x00\x00\x00QT\xd9\x80\x00\x00\x00\x00Ri\xb4\x80\x02\x01\x02\x01\x02\x01\x02\x03\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\x01\x03\x02\x01\x03\x00\x00\x0c\x5c\x00\x00\x00\x00\x1c \x01\x04\x00\x00\x0e\x10\x00\x09\x00\x00\x1c \x00\x0dLMT\x00CEST\x00CET\x00EET\x00\x0aEET-2\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\x9d\x1b\xc9m\x02\x00\x00m\x02\x00\x00\x03\x00\x00\x00METTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x00\x00\x00\x02\x00\x00\x00\x09\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xc8\x09q\x90\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x82%\x10\xff\xff\xff\xff\xd1r\x16\x10\xff\xff\xff\xff\xd2N@\x90\x00\x00\x00\x00\x0d\xa4c\x90\x00\x00\x00\x00\x0e\x8b\x1a\x10\x00\x00\x00\x00\x0f\x84E\x90\x00\x00\x00\x00\x10t6\x90\x00\x00\x00\x00\x11d'\x90\x00\x00\x00\x00\x12T\x18\x90\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x01\x00\x01\x00\x02\x03\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x01\x00\xff\xff\xab\xa0\x01\x08\xff\xff\xab\xa0\x01\x0cMDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x10\x00\x00\x00Mexico/BajaNorteTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xa9yOp\xff\xff\xff\xff\xaf\xf2|\xf0\xff\xff\xff\xff\xb6fdp\xff\xff\xff\xff\xb7\x1b\x10\x00\xff\xff\xff\xff\xb8\x0a\xf2\xf0\xff\xff\xff\xff\xcb\xea\x8d\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2\x99\xbap\xff\xff\xff\xff\xd7\x1bY\x00\xff\xff\xff\xff\xd8\x91\xb4\xf0\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x0e\x10\xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xd2\x10\xff\xff\xff\xff\xee\x91\xd9\x10\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00F\x0f\x82\xa0\x00\x00\x00\x00G$O\x90\x00\x00\x00\x00G\xf8\x9f \x00\x00\x00\x00I\x041\x90\x00\x00\x00\x00I\xd8\x81 \x00\x00\x00\x00J\xe4\x13\x90\x00\x00\x00\x00K=\xab\x80\x01\x02\x01\x02\x03\x02\x04\x05\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x02\xff\xff\x92L\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10\xff\xff\x9d\x90\x01\x14LMT\x00MST\x00PST\x00PDT\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xad=\x98\xce\x02\x00\x00\xce\x02\x00\x00\x0e\x00\x00\x00Mexico/BajaSurTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\xff\xff\xff\xff\xcb\xeaq`\xff\xff\xff\xff\xd8\x91\xb4\xf0\x00\x00\x00\x00\x00\x00p\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xf5\x12\x90\x00\x00\x00\x00;\xb6\xd1\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00F\x0ft\x90\x00\x00\x00\x00G$A\x80\x00\x00\x00\x00G\xf8\x91\x10\x00\x00\x00\x00I\x04#\x80\x00\x00\x00\x00I\xd8s\x10\x00\x00\x00\x00J\xe4\x05\x80\x00\x00\x00\x00K\xb8U\x10\x00\x00\x00\x00L\xcd\x22\x00\x00\x00\x00\x00M\x987\x10\x00\x00\x00\x00N\xad\x04\x00\x00\x00\x00\x00Ox\x19\x10\x00\x00\x00\x00P\x8c\xe6\x00\x00\x00\x00\x00Qa5\x90\x00\x00\x00\x00Rl\xc8\x00\x00\x00\x00\x00SA\x17\x90\x00\x00\x00\x00TL\xaa\x00\x00\x00\x00\x00U \xf9\x90\x00\x00\x00\x00V,\x8c\x00\x00\x00\x00\x00W\x00\xdb\x90\x00\x00\x00\x00X\x15\xa8\x80\x00\x00\x00\x00X\xe0\xbd\x90\x00\x00\x00\x00Y\xf5\x8a\x80\x00\x00\x00\x00Z\xc0\x9f\x90\x00\x00\x00\x00[\xd5l\x80\x00\x00\x00\x00\x5c\xa9\xbc\x10\x00\x00\x00\x00]\xb5N\x80\x00\x00\x00\x00^\x89\x9e\x10\x00\x00\x00\x00_\x950\x80\x00\x00\x00\x00`i\x80\x10\x00\x00\x00\x00a~M\x00\x00\x00\x00\x00bIb\x10\x00\x00\x00\x00c^/\x00\x01\x02\x01\x03\x01\x02\x01\x04\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\xff\xff\x9c<\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\x8f\x80\x00\x10LMT\x00MST\x00CST\x00MDT\x00PST\x00\x0aMST7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd5\x08\x89\x8c\x05\x03\x00\x00\x05\x03\x00\x00\x0e\x00\x00\x00Mexico/GeneralTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\xa5\xb6\xe8p\xff\xff\xff\xff\xaf\xf2n\xe0\xff\xff\xff\xff\xb6fV`\xff\xff\xff\xff\xb7C\xd2`\xff\xff\xff\xff\xb8\x0c6`\xff\xff\xff\xff\xb8\xfd\x86\xf0\xff\xff\xff\xff\xc5\xde\xb0`\xff\xff\xff\xff\xc6\x974P\xff\xff\xff\xff\xc9U\xf1\xe0\xff\xff\xff\xff\xc9\xea\xddP\xff\xff\xff\xff\xcf\x02\xc6\xe0\xff\xff\xff\xff\xcf\xb7VP\xff\xff\xff\xff\xda\x99\x15\xe0\xff\xff\xff\xff\xdbv\x83\xd0\x00\x00\x00\x001gv\x00\x00\x00\x00\x002s\x08p\x00\x00\x00\x003GX\x00\x00\x00\x00\x004R\xeap\x00\x00\x00\x005':\x00\x00\x00\x00\x0062\xccp\x00\x00\x00\x007\x07\x1c\x00\x00\x00\x00\x008\x1b\xe8\xf0\x00\x00\x00\x008\xe6\xfe\x00\x00\x00\x00\x009\xfb\xca\xf0\x00\x00\x00\x00:\xf5\x04\x80\x00\x00\x00\x00;\xb6\xc2\xf0\x00\x00\x00\x00<\xaf\xfc\x80\x00\x00\x00\x00=\xbb\x8e\xf0\x00\x00\x00\x00>\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00F\x0ff\x80\x00\x00\x00\x00G$3p\x00\x00\x00\x00G\xf8\x83\x00\x00\x00\x00\x00I\x04\x15p\x00\x00\x00\x00I\xd8e\x00\x00\x00\x00\x00J\xe3\xf7p\x00\x00\x00\x00K\xb8G\x00\x00\x00\x00\x00L\xcd\x13\xf0\x00\x00\x00\x00M\x98)\x00\x00\x00\x00\x00N\xac\xf5\xf0\x00\x00\x00\x00Ox\x0b\x00\x00\x00\x00\x00P\x8c\xd7\xf0\x00\x00\x00\x00Qa'\x80\x00\x00\x00\x00Rl\xb9\xf0\x00\x00\x00\x00SA\x09\x80\x00\x00\x00\x00TL\x9b\xf0\x00\x00\x00\x00U \xeb\x80\x00\x00\x00\x00V,}\xf0\x00\x00\x00\x00W\x00\xcd\x80\x00\x00\x00\x00X\x15\x9ap\x00\x00\x00\x00X\xe0\xaf\x80\x00\x00\x00\x00Y\xf5|p\x00\x00\x00\x00Z\xc0\x91\x80\x00\x00\x00\x00[\xd5^p\x00\x00\x00\x00\x5c\xa9\xae\x00\x00\x00\x00\x00]\xb5@p\x00\x00\x00\x00^\x89\x90\x00\x00\x00\x00\x00_\x95\x22p\x00\x00\x00\x00`ir\x00\x00\x00\x00\x00a~>\xf0\x00\x00\x00\x00bIT\x00\x00\x00\x00\x00c^ \xf0\x01\x02\x01\x03\x01\x02\x04\x02\x04\x02\x05\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\xff\xff\xa3\x0c\x00\x00\xff\xff\x9d\x90\x00\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x01\x14LMT\x00MST\x00CST\x00MDT\x00CDT\x00CWT\x00\x0aCST6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x02\x00\x00\x00NZTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x06\x00\x00\x00\x13\xff\xff\xff\xffA\xb7L\xa8\xff\xff\xff\xff\xb0\xb4\xb2\xe8\xff\xff\xff\xff\xb1Q\x87X\xff\xff\xff\xff\xb2x\xe5h\xff\xff\xff\xff\xb3C\xe5`\xff\xff\xff\xff\xb4X\xc7h\xff\xff\xff\xff\xb5#\xc7`\xff\xff\xff\xff\xb68\xa9h\xff\xff\xff\xff\xb7\x03\xa9`\xff\xff\xff\xff\xb8\x18\x8bh\xff\xff\xff\xff\xb8\xec\xc5\xe0\xff\xff\xff\xff\xb9\xf8mh\xff\xff\xff\xff\xba\xcc\xa7\xe0\xff\xff\xff\xff\xbb\xd8Oh\xff\xff\xff\xff\xbc\xe3\xe8\xe0\xff\xff\xff\xff\xbd\xae\xf6\xe8\xff\xff\xff\xff\xbe\xc3\xca\xe0\xff\xff\xff\xff\xbf\x8e\xd8\xe8\xff\xff\xff\xff\xc0\xa3\xac\xe0\xff\xff\xff\xff\xc1n\xba\xe8\xff\xff\xff\xff\xc2\x83\x8e\xe0\xff\xff\xff\xff\xc3N\x9c\xe8\xff\xff\xff\xff\xc4cp\xe0\xff\xff\xff\xff\xc5.~\xe8\xff\xff\xff\xff\xc6L\x8d`\xff\xff\xff\xff\xc7\x0e`\xe8\xff\xff\xff\xff\xc8,o`\xff\xff\xff\xff\xc8\xf7}h\xff\xff\xff\xff\xd2\xda\x9a@\x00\x00\x00\x00\x09\x18\xfd\xe0\x00\x00\x00\x00\x09\xac\xa5\xe0\x00\x00\x00\x00\x0a\xef\xa5`\x00\x00\x00\x00\x0b\x9e\xfc\xe0\x00\x00\x00\x00\x0c\xd8\xc1\xe0\x00\x00\x00\x00\x0d~\xde\xe0\x00\x00\x00\x00\x0e\xb8\xa3\xe0\x00\x00\x00\x00\x0f^\xc0\xe0\x00\x00\x00\x00\x10\x98\x85\xe0\x00\x00\x00\x00\x11>\xa2\xe0\x00\x00\x00\x00\x12xg\xe0\x00\x00\x00\x00\x13\x1e\x84\xe0\x00\x00\x00\x00\x14XI\xe0\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168+\xe0\x00\x00\x00\x00\x16\xe7\x83`\x00\x00\x00\x00\x18!H`\x00\x00\x00\x00\x18\xc7e`\x00\x00\x00\x00\x1a\x01*`\x00\x00\x00\x00\x1a\xa7G`\x00\x00\x00\x00\x1b\xe1\x0c`\x00\x00\x00\x00\x1c\x87)`\x00\x00\x00\x00\x1d\xc0\xee`\x00\x00\x00\x00\x1eg\x0b`\x00\x00\x00\x00\x1f\xa0\xd0`\x00\x00\x00\x00 F\xed`\x00\x00\x00\x00!\x80\xb2`\x00\x00\x00\x00\x220\x09\xe0\x00\x00\x00\x00#i\xce\xe0\x00\x00\x00\x00$\x0f\xeb\xe0\x00\x00\x00\x00%.\x01`\x00\x00\x00\x00&\x02B\xe0\x00\x00\x00\x00'\x0d\xe3`\x00\x00\x00\x00'\xe2$\xe0\x00\x00\x00\x00(\xed\xc5`\x00\x00\x00\x00)\xc2\x06\xe0\x00\x00\x00\x00*\xcd\xa7`\x00\x00\x00\x00+\xab#`\x00\x00\x00\x00,\xad\x89`\x00\x00\x00\x00-\x8b\x05`\x00\x00\x00\x00.\x8dk`\x00\x00\x00\x00/j\xe7`\x00\x00\x00\x000mM`\x00\x00\x00\x001J\xc9`\x00\x00\x00\x002Vi\xe0\x00\x00\x00\x003*\xab`\x00\x00\x00\x0046K\xe0\x00\x00\x00\x005\x0a\x8d`\x00\x00\x00\x006\x16-\xe0\x00\x00\x00\x006\xf3\xa9\xe0\x00\x00\x00\x007\xf6\x0f\xe0\x00\x00\x00\x008\xd3\x8b\xe0\x00\x00\x00\x009\xd5\xf1\xe0\x00\x00\x00\x00:\xb3m\xe0\x00\x00\x00\x00;\xbf\x0e`\x00\x00\x00\x00<\x93O\xe0\x00\x00\x00\x00=\x9e\xf0`\x00\x00\x00\x00>s1\xe0\x00\x00\x00\x00?~\xd2`\x00\x00\x00\x00@\x5cN`\x00\x00\x00\x00A^\xb4`\x00\x00\x00\x00B<0`\x00\x00\x00\x00C>\x96`\x00\x00\x00\x00D\x1c\x12`\x00\x00\x00\x00E\x1ex`\x00\x00\x00\x00E\xfb\xf4`\x00\x00\x00\x00F\xfeZ`\x02\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x00\x00\xa3\xd8\x00\x00\x00\x00\xaf\xc8\x01\x04\x00\x00\xa1\xb8\x00\x09\x00\x00\xa8\xc0\x01\x04\x00\x00\xb6\xd0\x01\x0e\x00\x00\xa8\xc0\x00\x04LMT\x00NZST\x00NZMT\x00NZDT\x00\x0aNZST-12NZDT,M9.5.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xc5FF(\x03\x00\x00(\x03\x00\x00\x07\x00\x00\x00NZ-CHATTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x00\x00\x00\x04\x00\x00\x00\x16\xff\xff\xff\xffA\xb7D\x84\xff\xff\xff\xff\xd2\xda\x96\xbc\x00\x00\x00\x00\x09\x18\xfd\xe0\x00\x00\x00\x00\x09\xac\xa5\xe0\x00\x00\x00\x00\x0a\xef\xa5`\x00\x00\x00\x00\x0b\x9e\xfc\xe0\x00\x00\x00\x00\x0c\xd8\xc1\xe0\x00\x00\x00\x00\x0d~\xde\xe0\x00\x00\x00\x00\x0e\xb8\xa3\xe0\x00\x00\x00\x00\x0f^\xc0\xe0\x00\x00\x00\x00\x10\x98\x85\xe0\x00\x00\x00\x00\x11>\xa2\xe0\x00\x00\x00\x00\x12xg\xe0\x00\x00\x00\x00\x13\x1e\x84\xe0\x00\x00\x00\x00\x14XI\xe0\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168+\xe0\x00\x00\x00\x00\x16\xe7\x83`\x00\x00\x00\x00\x18!H`\x00\x00\x00\x00\x18\xc7e`\x00\x00\x00\x00\x1a\x01*`\x00\x00\x00\x00\x1a\xa7G`\x00\x00\x00\x00\x1b\xe1\x0c`\x00\x00\x00\x00\x1c\x87)`\x00\x00\x00\x00\x1d\xc0\xee`\x00\x00\x00\x00\x1eg\x0b`\x00\x00\x00\x00\x1f\xa0\xd0`\x00\x00\x00\x00 F\xed`\x00\x00\x00\x00!\x80\xb2`\x00\x00\x00\x00\x220\x09\xe0\x00\x00\x00\x00#i\xce\xe0\x00\x00\x00\x00$\x0f\xeb\xe0\x00\x00\x00\x00%.\x01`\x00\x00\x00\x00&\x02B\xe0\x00\x00\x00\x00'\x0d\xe3`\x00\x00\x00\x00'\xe2$\xe0\x00\x00\x00\x00(\xed\xc5`\x00\x00\x00\x00)\xc2\x06\xe0\x00\x00\x00\x00*\xcd\xa7`\x00\x00\x00\x00+\xab#`\x00\x00\x00\x00,\xad\x89`\x00\x00\x00\x00-\x8b\x05`\x00\x00\x00\x00.\x8dk`\x00\x00\x00\x00/j\xe7`\x00\x00\x00\x000mM`\x00\x00\x00\x001J\xc9`\x00\x00\x00\x002Vi\xe0\x00\x00\x00\x003*\xab`\x00\x00\x00\x0046K\xe0\x00\x00\x00\x005\x0a\x8d`\x00\x00\x00\x006\x16-\xe0\x00\x00\x00\x006\xf3\xa9\xe0\x00\x00\x00\x007\xf6\x0f\xe0\x00\x00\x00\x008\xd3\x8b\xe0\x00\x00\x00\x009\xd5\xf1\xe0\x00\x00\x00\x00:\xb3m\xe0\x00\x00\x00\x00;\xbf\x0e`\x00\x00\x00\x00<\x93O\xe0\x00\x00\x00\x00=\x9e\xf0`\x00\x00\x00\x00>s1\xe0\x00\x00\x00\x00?~\xd2`\x00\x00\x00\x00@\x5cN`\x00\x00\x00\x00A^\xb4`\x00\x00\x00\x00B<0`\x00\x00\x00\x00C>\x96`\x00\x00\x00\x00D\x1c\x12`\x00\x00\x00\x00E\x1ex`\x00\x00\x00\x00E\xfb\xf4`\x00\x00\x00\x00F\xfeZ`\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x00\xab\xfc\x00\x00\x00\x00\xacD\x00\x04\x00\x00\xc1\x5c\x01\x0a\x00\x00\xb3L\x00\x10LMT\x00+1215\x00+1345\x00+1245\x00\x0a<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x80\x94@\x12\x04\x00\x00\x12\x04\x00\x00\x06\x00\x00\x00NavajoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xa2e\xfe\x90\xff\xff\xff\xff\xa3\x84\x06\x00\xff\xff\xff\xff\xa4E\xe0\x90\xff\xff\xff\xff\xa4\x8f\xa6\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xf7/v\x90\xff\xff\xff\xff\xf8(\x94\x00\xff\xff\xff\xff\xf9\x0fX\x90\xff\xff\xff\xff\xfa\x08v\x00\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8W\x10\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb89\x10\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x1b\x10\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xfd\x10\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x07\x8d5\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x09\xad\xb1\x10\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x9d\x94\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10LMT\x00MDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x03\x00\x00\x00PRCTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff~6C)\xff\xff\xff\xff\xa0\x97\xa2\x80\xff\xff\xff\xff\xa1y\x04\xf0\xff\xff\xff\xff\xc8Y^\x80\xff\xff\xff\xff\xc9\x09\xf9p\xff\xff\xff\xff\xc9\xd3\xbd\x00\xff\xff\xff\xff\xcb\x05\x8a\xf0\xff\xff\xff\xff\xcb|@\x00\xff\xff\xff\xff\xd2;>\xf0\xff\xff\xff\xff\xd3\x8b{\x80\xff\xff\xff\xff\xd4B\xad\xf0\xff\xff\xff\xff\xd5E\x22\x00\xff\xff\xff\xff\xd6L\xbf\xf0\xff\xff\xff\xff\xd7<\xbf\x00\xff\xff\xff\xff\xd8\x06fp\xff\xff\xff\xff\xd9\x1d\xf2\x80\xff\xff\xff\xff\xd9A|\xf0\x00\x00\x00\x00\x1e\xbaR \x00\x00\x00\x00\x1fi\x9b\x90\x00\x00\x00\x00 ~\x84\xa0\x00\x00\x00\x00!I}\x90\x00\x00\x00\x00\x22g\xa1 \x00\x00\x00\x00#)_\x90\x00\x00\x00\x00$G\x83 \x00\x00\x00\x00%\x12|\x10\x00\x00\x00\x00&'e \x00\x00\x00\x00&\xf2^\x10\x00\x00\x00\x00(\x07G \x00\x00\x00\x00(\xd2@\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00q\xd7\x00\x00\x00\x00~\x90\x01\x04\x00\x00p\x80\x00\x08LMT\x00CDT\x00CST\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xadV\xad\xb7\x03\x00\x00\xb7\x03\x00\x00\x07\x00\x00\x00PST8PDTTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\x9e\xa6H\xa0\xff\xff\xff\xff\x9f\xbb\x15\x90\xff\xff\xff\xff\xa0\x86*\xa0\xff\xff\xff\xff\xa1\x9a\xf7\x90\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xfa\xf8\x83 \xff\xff\xff\xff\xfb\xe8f\x10\xff\xff\xff\xff\xfc\xd8e \xff\xff\xff\xff\xfd\xc8H\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x07\x8dC\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x09\xad\xbf \x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x01\x00\x01\x00\x02\x03\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\xff\xff\x8f\x80\x00\x04\xff\xff\x9d\x90\x01\x00\xff\xff\x9d\x90\x01\x08\xff\xff\x9d\x90\x01\x0cPDT\x00PST\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8A\x15\xfe\x97\x01\x00\x00\x97\x01\x00\x00\x0c\x00\x00\x00Pacific/ApiaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x07\x00\x00\x00\x1a\xff\xff\xff\xffn=\xc9\x00\xff\xff\xff\xff\x91\x05\xfc\x00\xff\xff\xff\xff\xdab\x048\x00\x00\x00\x00L\x9f'\xb0\x00\x00\x00\x00M\x97+\xe0\x00\x00\x00\x00N}\xe2`\x00\x00\x00\x00N\xfd\x8b\xa0\x00\x00\x00\x00Ow\x0d\xe0\x00\x00\x00\x00Pf\xfe\xe0\x00\x00\x00\x00Q`*`\x00\x00\x00\x00RF\xe0\xe0\x00\x00\x00\x00S@\x0c`\x00\x00\x00\x00T&\xc2\xe0\x00\x00\x00\x00U\x1f\xee`\x00\x00\x00\x00V\x06\xa4\xe0\x00\x00\x00\x00V\xff\xd0`\x00\x00\x00\x00W\xe6\x86\xe0\x00\x00\x00\x00X\xdf\xb2`\x00\x00\x00\x00Y\xc6h\xe0\x00\x00\x00\x00Z\xbf\x94`\x00\x00\x00\x00[\xaf\x85`\x00\x00\x00\x00\x5c\xa8\xb0\xe0\x00\x00\x00\x00]\x8fg`\x00\x00\x00\x00^\x88\x92\xe0\x00\x00\x00\x00_oI`\x00\x00\x00\x00`ht\xe0\x01\x02\x04\x03\x04\x03\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x00\x00\xb0\x80\x00\x00\xff\xff_\x00\x00\x00\xff\xff^H\x00\x04\xff\xffs`\x01\x0a\xff\xffeP\x00\x0e\x00\x00\xb6\xd0\x00\x12\x00\x00\xc4\xe0\x01\x16LMT\x00-1130\x00-10\x00-11\x00+13\x00+14\x00\x0a<+13>-13\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x10\x00\x00\x00Pacific/AucklandTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x06\x00\x00\x00\x13\xff\xff\xff\xffA\xb7L\xa8\xff\xff\xff\xff\xb0\xb4\xb2\xe8\xff\xff\xff\xff\xb1Q\x87X\xff\xff\xff\xff\xb2x\xe5h\xff\xff\xff\xff\xb3C\xe5`\xff\xff\xff\xff\xb4X\xc7h\xff\xff\xff\xff\xb5#\xc7`\xff\xff\xff\xff\xb68\xa9h\xff\xff\xff\xff\xb7\x03\xa9`\xff\xff\xff\xff\xb8\x18\x8bh\xff\xff\xff\xff\xb8\xec\xc5\xe0\xff\xff\xff\xff\xb9\xf8mh\xff\xff\xff\xff\xba\xcc\xa7\xe0\xff\xff\xff\xff\xbb\xd8Oh\xff\xff\xff\xff\xbc\xe3\xe8\xe0\xff\xff\xff\xff\xbd\xae\xf6\xe8\xff\xff\xff\xff\xbe\xc3\xca\xe0\xff\xff\xff\xff\xbf\x8e\xd8\xe8\xff\xff\xff\xff\xc0\xa3\xac\xe0\xff\xff\xff\xff\xc1n\xba\xe8\xff\xff\xff\xff\xc2\x83\x8e\xe0\xff\xff\xff\xff\xc3N\x9c\xe8\xff\xff\xff\xff\xc4cp\xe0\xff\xff\xff\xff\xc5.~\xe8\xff\xff\xff\xff\xc6L\x8d`\xff\xff\xff\xff\xc7\x0e`\xe8\xff\xff\xff\xff\xc8,o`\xff\xff\xff\xff\xc8\xf7}h\xff\xff\xff\xff\xd2\xda\x9a@\x00\x00\x00\x00\x09\x18\xfd\xe0\x00\x00\x00\x00\x09\xac\xa5\xe0\x00\x00\x00\x00\x0a\xef\xa5`\x00\x00\x00\x00\x0b\x9e\xfc\xe0\x00\x00\x00\x00\x0c\xd8\xc1\xe0\x00\x00\x00\x00\x0d~\xde\xe0\x00\x00\x00\x00\x0e\xb8\xa3\xe0\x00\x00\x00\x00\x0f^\xc0\xe0\x00\x00\x00\x00\x10\x98\x85\xe0\x00\x00\x00\x00\x11>\xa2\xe0\x00\x00\x00\x00\x12xg\xe0\x00\x00\x00\x00\x13\x1e\x84\xe0\x00\x00\x00\x00\x14XI\xe0\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168+\xe0\x00\x00\x00\x00\x16\xe7\x83`\x00\x00\x00\x00\x18!H`\x00\x00\x00\x00\x18\xc7e`\x00\x00\x00\x00\x1a\x01*`\x00\x00\x00\x00\x1a\xa7G`\x00\x00\x00\x00\x1b\xe1\x0c`\x00\x00\x00\x00\x1c\x87)`\x00\x00\x00\x00\x1d\xc0\xee`\x00\x00\x00\x00\x1eg\x0b`\x00\x00\x00\x00\x1f\xa0\xd0`\x00\x00\x00\x00 F\xed`\x00\x00\x00\x00!\x80\xb2`\x00\x00\x00\x00\x220\x09\xe0\x00\x00\x00\x00#i\xce\xe0\x00\x00\x00\x00$\x0f\xeb\xe0\x00\x00\x00\x00%.\x01`\x00\x00\x00\x00&\x02B\xe0\x00\x00\x00\x00'\x0d\xe3`\x00\x00\x00\x00'\xe2$\xe0\x00\x00\x00\x00(\xed\xc5`\x00\x00\x00\x00)\xc2\x06\xe0\x00\x00\x00\x00*\xcd\xa7`\x00\x00\x00\x00+\xab#`\x00\x00\x00\x00,\xad\x89`\x00\x00\x00\x00-\x8b\x05`\x00\x00\x00\x00.\x8dk`\x00\x00\x00\x00/j\xe7`\x00\x00\x00\x000mM`\x00\x00\x00\x001J\xc9`\x00\x00\x00\x002Vi\xe0\x00\x00\x00\x003*\xab`\x00\x00\x00\x0046K\xe0\x00\x00\x00\x005\x0a\x8d`\x00\x00\x00\x006\x16-\xe0\x00\x00\x00\x006\xf3\xa9\xe0\x00\x00\x00\x007\xf6\x0f\xe0\x00\x00\x00\x008\xd3\x8b\xe0\x00\x00\x00\x009\xd5\xf1\xe0\x00\x00\x00\x00:\xb3m\xe0\x00\x00\x00\x00;\xbf\x0e`\x00\x00\x00\x00<\x93O\xe0\x00\x00\x00\x00=\x9e\xf0`\x00\x00\x00\x00>s1\xe0\x00\x00\x00\x00?~\xd2`\x00\x00\x00\x00@\x5cN`\x00\x00\x00\x00A^\xb4`\x00\x00\x00\x00B<0`\x00\x00\x00\x00C>\x96`\x00\x00\x00\x00D\x1c\x12`\x00\x00\x00\x00E\x1ex`\x00\x00\x00\x00E\xfb\xf4`\x00\x00\x00\x00F\xfeZ`\x02\x01\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x00\x00\xa3\xd8\x00\x00\x00\x00\xaf\xc8\x01\x04\x00\x00\xa1\xb8\x00\x09\x00\x00\xa8\xc0\x01\x04\x00\x00\xb6\xd0\x01\x0e\x00\x00\xa8\xc0\x00\x04LMT\x00NZST\x00NZMT\x00NZDT\x00\x0aNZST-12NZDT,M9.5.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\xf2:F\xc9\x00\x00\x00\xc9\x00\x00\x00\x14\x00\x00\x00Pacific/BougainvilleTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x05\x00\x00\x00\x15\xff\xff\xff\xffV\xb6R(\xff\xff\xff\xffr\xed\xa4\x90\xff\xff\xff\xff\xccC6`\xff\xff\xff\xff\xd2+l\xf0\x00\x00\x00\x00T\x9e\xd7\x80\x01\x02\x03\x02\x04\x00\x00\x91\xd8\x00\x00\x00\x00\x89\xf0\x00\x04\x00\x00\x8c\xa0\x00\x09\x00\x00~\x90\x00\x0d\x00\x00\x9a\xb0\x00\x11LMT\x00PMMT\x00+10\x00+09\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xc5FF(\x03\x00\x00(\x03\x00\x00\x0f\x00\x00\x00Pacific/ChathamTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x00\x00\x00\x04\x00\x00\x00\x16\xff\xff\xff\xffA\xb7D\x84\xff\xff\xff\xff\xd2\xda\x96\xbc\x00\x00\x00\x00\x09\x18\xfd\xe0\x00\x00\x00\x00\x09\xac\xa5\xe0\x00\x00\x00\x00\x0a\xef\xa5`\x00\x00\x00\x00\x0b\x9e\xfc\xe0\x00\x00\x00\x00\x0c\xd8\xc1\xe0\x00\x00\x00\x00\x0d~\xde\xe0\x00\x00\x00\x00\x0e\xb8\xa3\xe0\x00\x00\x00\x00\x0f^\xc0\xe0\x00\x00\x00\x00\x10\x98\x85\xe0\x00\x00\x00\x00\x11>\xa2\xe0\x00\x00\x00\x00\x12xg\xe0\x00\x00\x00\x00\x13\x1e\x84\xe0\x00\x00\x00\x00\x14XI\xe0\x00\x00\x00\x00\x14\xfef\xe0\x00\x00\x00\x00\x168+\xe0\x00\x00\x00\x00\x16\xe7\x83`\x00\x00\x00\x00\x18!H`\x00\x00\x00\x00\x18\xc7e`\x00\x00\x00\x00\x1a\x01*`\x00\x00\x00\x00\x1a\xa7G`\x00\x00\x00\x00\x1b\xe1\x0c`\x00\x00\x00\x00\x1c\x87)`\x00\x00\x00\x00\x1d\xc0\xee`\x00\x00\x00\x00\x1eg\x0b`\x00\x00\x00\x00\x1f\xa0\xd0`\x00\x00\x00\x00 F\xed`\x00\x00\x00\x00!\x80\xb2`\x00\x00\x00\x00\x220\x09\xe0\x00\x00\x00\x00#i\xce\xe0\x00\x00\x00\x00$\x0f\xeb\xe0\x00\x00\x00\x00%.\x01`\x00\x00\x00\x00&\x02B\xe0\x00\x00\x00\x00'\x0d\xe3`\x00\x00\x00\x00'\xe2$\xe0\x00\x00\x00\x00(\xed\xc5`\x00\x00\x00\x00)\xc2\x06\xe0\x00\x00\x00\x00*\xcd\xa7`\x00\x00\x00\x00+\xab#`\x00\x00\x00\x00,\xad\x89`\x00\x00\x00\x00-\x8b\x05`\x00\x00\x00\x00.\x8dk`\x00\x00\x00\x00/j\xe7`\x00\x00\x00\x000mM`\x00\x00\x00\x001J\xc9`\x00\x00\x00\x002Vi\xe0\x00\x00\x00\x003*\xab`\x00\x00\x00\x0046K\xe0\x00\x00\x00\x005\x0a\x8d`\x00\x00\x00\x006\x16-\xe0\x00\x00\x00\x006\xf3\xa9\xe0\x00\x00\x00\x007\xf6\x0f\xe0\x00\x00\x00\x008\xd3\x8b\xe0\x00\x00\x00\x009\xd5\xf1\xe0\x00\x00\x00\x00:\xb3m\xe0\x00\x00\x00\x00;\xbf\x0e`\x00\x00\x00\x00<\x93O\xe0\x00\x00\x00\x00=\x9e\xf0`\x00\x00\x00\x00>s1\xe0\x00\x00\x00\x00?~\xd2`\x00\x00\x00\x00@\x5cN`\x00\x00\x00\x00A^\xb4`\x00\x00\x00\x00B<0`\x00\x00\x00\x00C>\x96`\x00\x00\x00\x00D\x1c\x12`\x00\x00\x00\x00E\x1ex`\x00\x00\x00\x00E\xfb\xf4`\x00\x00\x00\x00F\xfeZ`\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x00\x00\xab\xfc\x00\x00\x00\x00\xacD\x00\x04\x00\x00\xc1\x5c\x01\x0a\x00\x00\xb3L\x00\x10LMT\x00+1215\x00+1345\x00+1245\x00\x0a<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x0d\x00\x00\x00Pacific/ChuukTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xffV\xb6Z\x08\xff\xff\xff\xffr\xed\xa4\x90\x01\x02\x00\x00\x89\xf8\x00\x00\x00\x00\x89\xf0\x00\x04\x00\x00\x8c\xa0\x00\x09LMT\x00PMMT\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?X'\x8e\x96\x04\x00\x00\x96\x04\x00\x00\x0e\x00\x00\x00Pacific/EasterTZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xffi\x87B\x08\xff\xff\xff\xff\xb9\xc7@\x88\xff\xff\xff\xff\xfd\xd1<@\xff\xff\xff\xff\xfe\x92\xfa\xb0\xff\xff\xff\xff\xff\xcc\xcd\xc0\x00\x00\x00\x00\x00r\xdc\xb0\x00\x00\x00\x00\x01uP\xc0\x00\x00\x00\x00\x02@I\xb0\x00\x00\x00\x00\x03U2\xc0\x00\x00\x00\x00\x04 +\xb0\x00\x00\x00\x00\x05>O@\x00\x00\x00\x00\x06\x00\x0d\xb0\x00\x00\x00\x00\x07\x0b\xbc@\x00\x00\x00\x00\x07\xdf\xef\xb0\x00\x00\x00\x00\x08\xfe\x13@\x00\x00\x00\x00\x09\xbf\xd1\xb0\x00\x00\x00\x00\x0a\xdd\xf5@\x00\x00\x00\x00\x0b\xa8\xee0\x00\x00\x00\x00\x0c\xbd\xd7@\x00\x00\x00\x00\x0d\x88\xd00\x00\x00\x00\x00\x0e\x9d\xb9@\x00\x00\x00\x00\x0fh\xb20\x00\x00\x00\x00\x10\x86\xd5\xc0\x00\x00\x00\x00\x11H\x940\x00\x00\x00\x00\x12f\xb7\xc0\x00\x00\x00\x00\x13(v0\x00\x00\x00\x00\x14F\x99\xc0\x00\x00\x00\x00\x15\x11\x92\xb0\x00\x00\x00\x00\x16&{\xc0\x00\x00\x00\x00\x16\xf1t\xb0\x00\x00\x00\x00\x18\x06]\xc0\x00\x00\x00\x00\x18\xd1V\xb0\x00\x00\x00\x00\x19\xe6?\xc0\x00\x00\x00\x00\x1a\xb18\xb0\x00\x00\x00\x00\x1b\xcf\x5c@\x00\x00\x00\x00\x1c\x91\x1a\xb0\x00\x00\x00\x00\x1d\xaf>@\x00\x00\x00\x00\x1ep\xfc\xb0\x00\x00\x00\x00\x1f\x8f @\x00\x00\x00\x00 \x7f\x030\x00\x00\x00\x00!o\x02@\x00\x00\x00\x00\x229\xfb0\x00\x00\x00\x00#N\xe4@\x00\x00\x00\x00$\x19\xdd0\x00\x00\x00\x00%8\x00\xc0\x00\x00\x00\x00%\xf9\xbf0\x00\x00\x00\x00&\xf2\xf8\xc0\x00\x00\x00\x00'\xd9\xa10\x00\x00\x00\x00(\xf7\xc4\xc0\x00\x00\x00\x00)\xc2\xbd\xb0\x00\x00\x00\x00*\xd7\xa6\xc0\x00\x00\x00\x00+\xa2\x9f\xb0\x00\x00\x00\x00,\xb7\x88\xc0\x00\x00\x00\x00-\x82\x81\xb0\x00\x00\x00\x00.\x97j\xc0\x00\x00\x00\x00/bc\xb0\x00\x00\x00\x000\x80\x87@\x00\x00\x00\x001BE\xb0\x00\x00\x00\x002`i@\x00\x00\x00\x003=\xd70\x00\x00\x00\x004@K@\x00\x00\x00\x005\x0bD0\x00\x00\x00\x006\x0d\xb8@\x00\x00\x00\x007\x06\xd5\xb0\x00\x00\x00\x008\x00\x0f@\x00\x00\x00\x008\xcb\x080\x00\x00\x00\x009\xe9+\xc0\x00\x00\x00\x00:\xaa\xea0\x00\x00\x00\x00;\xc9\x0d\xc0\x00\x00\x00\x00<\x8a\xcc0\x00\x00\x00\x00=\xa8\xef\xc0\x00\x00\x00\x00>j\xae0\x00\x00\x00\x00?\x88\xd1\xc0\x00\x00\x00\x00@S\xca\xb0\x00\x00\x00\x00Ah\xb3\xc0\x00\x00\x00\x00B3\xac\xb0\x00\x00\x00\x00CH\x95\xc0\x00\x00\x00\x00D\x13\x8e\xb0\x00\x00\x00\x00E1\xb2@\x00\x00\x00\x00E\xf3p\xb0\x00\x00\x00\x00G\x11\x94@\x00\x00\x00\x00G\xef\x020\x00\x00\x00\x00H\xf1v@\x00\x00\x00\x00I\xbco0\x00\x00\x00\x00J\xd1X@\x00\x00\x00\x00K\xb8\x00\xb0\x00\x00\x00\x00L\xb1:@\x00\x00\x00\x00M\xc6\x070\x00\x00\x00\x00NP\x82\xc0\x00\x00\x00\x00O\x9c\xae\xb0\x00\x00\x00\x00PB\xd9\xc0\x00\x00\x00\x00Q|\x90\xb0\x00\x00\x00\x00R+\xf6@\x00\x00\x00\x00S\x5cr\xb0\x00\x00\x00\x00T\x0b\xd8@\x00\x00\x00\x00W7\xe60\x00\x00\x00\x00W\xaf\xec\xc0\x00\x00\x00\x00Y\x17\xc80\x00\x00\x00\x00Y\x8f\xce\xc0\x00\x00\x00\x00Z\xf7\xaa0\x00\x00\x00\x00[o\xb0\xc0\x00\x00\x00\x00\x5c\xa9g\xb0\x00\x00\x00\x00]t|\xc0\x00\x00\x00\x00^\x89I\xb0\x00\x00\x00\x00_T^\xc0\x00\x00\x00\x00`i+\xb0\x00\x00\x00\x00a4@\xc0\x00\x00\x00\x00bI\x0d\xb0\x00\x00\x00\x00c\x1d]@\x00\x00\x00\x00d(\xef\xb0\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\x05\x04\xff\xff\x99x\x00\x00\xff\xff\x99x\x00\x04\xff\xff\xab\xa0\x01\x08\xff\xff\x9d\x90\x00\x0c\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x10LMT\x00EMT\x00-06\x00-07\x00-05\x00\x0a<-06>6<-05>,M9.1.6/22,M4.1.6/22\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9e\x7f\xab\x95V\x01\x00\x00V\x01\x00\x00\x0d\x00\x00\x00Pacific/EfateTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x92\xf5\xc2\xb4\x00\x00\x00\x00\x07y\x99@\x00\x00\x00\x00\x07\xfa\xcc@\x00\x00\x00\x00\x19\xd2\xf7\xd0\x00\x00\x00\x00\x1a\xc2\xda\xc0\x00\x00\x00\x00\x1b\xb2\xd9\xd0\x00\x00\x00\x00\x1c\xa2\xbc\xc0\x00\x00\x00\x00\x1d\x9b\xf6P\x00\x00\x00\x00\x1e\x82\x9e\xc0\x00\x00\x00\x00\x1f{\xd8P\x00\x00\x00\x00 k\xbb@\x00\x00\x00\x00![\xbaP\x00\x00\x00\x00\x22K\x9d@\x00\x00\x00\x00#;\x9cP\x00\x00\x00\x00$+\x7f@\x00\x00\x00\x00%\x1b~P\x00\x00\x00\x00&\x0ba@\x00\x00\x00\x00&\xfb`P\x00\x00\x00\x00'\xebC@\x00\x00\x00\x00(\xe4|\xd0\x00\x00\x00\x00)\x81Q@\x00\x00\x00\x00*\xe9H\xd0\x00\x00\x00\x00+a3@\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\x9d\xcc\x00\x00\x00\x00\xa8\xc0\x01\x04\x00\x00\x9a\xb0\x00\x08LMT\x00+12\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xec =\x89\xac\x00\x00\x00\xac\x00\x00\x00\x11\x00\x00\x00Pacific/EnderburyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\xc3,\xdb\x80\x00\x00\x00\x00\x12V\x04\xc0\x00\x00\x00\x00/\x059\xb0\x01\x02\x03\x00\x00\x00\x00\x00\x00\xff\xffW@\x00\x04\xff\xffeP\x00\x08\x00\x00\xb6\xd0\x00\x0c-00\x00-12\x00-11\x00+13\x00\x0a<+13>-13\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a|\xdcU\x99\x00\x00\x00\x99\x00\x00\x00\x0f\x00\x00\x00Pacific/FakaofoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff~7U\x88\x00\x00\x00\x00N\xfd\x99\xb0\x01\x02\xff\xff_x\x00\x00\xff\xffeP\x00\x04\x00\x00\xb6\xd0\x00\x08LMT\x00-11\x00+13\x00\x0a<+13>-13\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfd_yl\x8c\x01\x00\x00\x8c\x01\x00\x00\x0c\x00\x00\x00Pacific/FijiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x9a\x13\xb1\xc0\x00\x00\x00\x006;\x17\xe0\x00\x00\x00\x006\xd7\xfa`\x00\x00\x00\x008$4`\x00\x00\x00\x008\xb7\xdc`\x00\x00\x00\x00K\x11,\xe0\x00\x00\x00\x00K\xae\x0f`\x00\x00\x00\x00L\xc2\xea`\x00\x00\x00\x00MrA\xe0\x00\x00\x00\x00N\xa2\xcc`\x00\x00\x00\x00O\x1a\xc4\xe0\x00\x00\x00\x00P\x82\xae`\x00\x00\x00\x00P\xfa\xa6\xe0\x00\x00\x00\x00Rk\xca\xe0\x00\x00\x00\x00R\xdaz\xd0\x00\x00\x00\x00TT\xe7`\x00\x00\x00\x00T\xbaj\xe0\x00\x00\x00\x00V4\xc9`\x00\x00\x00\x00V\x9aL\xe0\x00\x00\x00\x00X\x1d\xe5\xe0\x00\x00\x00\x00Xz.\xe0\x00\x00\x00\x00Y\xfd\xc7\xe0\x00\x00\x00\x00ZZ\x10\xe0\x00\x00\x00\x00[\xdd\xa9\xe0\x00\x00\x00\x00\x5c9\xf2\xe0\x00\x00\x00\x00]\xc6\xc6`\x00\x00\x00\x00^\x19\xd4\xe0\x00\x00\x00\x00_\xde\x07`\x00\x00\x00\x00`\x02\xf1`\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x00\x00\xa7\xc0\x00\x00\x00\x00\xb6\xd0\x01\x04\x00\x00\xa8\xc0\x00\x08LMT\x00+13\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x10\x00\x00\x00Pacific/FunafutiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff~6\x12\xcc\x01\x00\x00\xa24\x00\x00\x00\x00\xa8\xc0\x00\x04LMT\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\xe3w\x0a\xaf\x00\x00\x00\xaf\x00\x00\x00\x11\x00\x00\x00Pacific/GalapagosTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x0c\xff\xff\xff\xff\xb6\xa4L\x80\x00\x00\x00\x00\x1e\x18\xc4P\x00\x00\x00\x00+\x17\x0a\xe0\x00\x00\x00\x00+q\xf4P\x01\x03\x02\x03\xff\xff\xac\x00\x00\x00\xff\xff\xb9\xb0\x00\x04\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08LMT\x00-05\x00-06\x00\x0a<-06>6\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc23\xa0\xbc\x84\x00\x00\x00\x84\x00\x00\x00\x0f\x00\x00\x00Pacific/GambierTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x94PH\x04\x01\xff\xff\x81|\x00\x00\xff\xff\x81p\x00\x04LMT\x00-09\x00\x0a<-09>9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd2K|\x86\x00\x00\x00\x86\x00\x00\x00\x13\x00\x00\x00Pacific/GuadalcanalTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x94O3\x8c\x01\x00\x00\x95\xf4\x00\x00\x00\x00\x9a\xb0\x00\x04LMT\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FI\xfe\x14^\x01\x00\x00^\x01\x00\x00\x0c\x00\x00\x00Pacific/GuamTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x06\x00\x00\x00\x15\xff\xff\xff\xff\x14\xe1\xc5\xcc\xff\xff\xff\xff~6-L\xff\xff\xff\xff\xcb7\x95\xe0\xff\xff\xff\xff\xd0.\x89\xf0\xff\xff\xff\xff\xec7\xbe\x00\xff\xff\xff\xff\xef6\xf8\xf0\xff\xff\xff\xff\xfb\x9b\x00\x00\xff\xff\xff\xff\xfe?'\x8c\xff\xff\xff\xff\xff\x01\x1e\x00\xff\xff\xff\xff\xff]X\xf0\x00\x00\x00\x00\x00\x97,\x00\x00\x00\x00\x00\x01Fup\x00\x00\x00\x00\x02w\x0e\x00\x00\x00\x00\x00\x03&Wp\x00\x00\x00\x00\x07p\x97\x00\x00\x00\x00\x00\x07\xcc\xd1\xf0\x00\x00\x00\x00\x0c\x08\x91\x00\x00\x00\x00\x00\x0c|\x87,\x00\x00\x00\x00\x0d\xbf\x94\x80\x00\x00\x00\x00\x0ee\xa3p\x00\x00\x00\x00:C^`\x01\x02\x03\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x05\xff\xff64\x00\x00\x00\x00\x87\xb4\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00~\x90\x00\x08\x00\x00\x9a\xb0\x01\x0c\x00\x00\x8c\xa0\x00\x10LMT\x00GST\x00+09\x00GDT\x00ChST\x00\x0aChST-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeaK\x85v\xdd\x00\x00\x00\xdd\x00\x00\x00\x10\x00\x00\x00Pacific/HonoluluTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xfft\xe0p\xbe\xff\xff\xff\xff\xbb\x05CH\xff\xff\xff\xff\xbb!qX\xff\xff\xff\xff\xcb\x89=\xc8\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aI8\xff\xff\xff\xff\xd5\x8dsH\x01\x02\x01\x03\x04\x01\x05\xff\xffl\x02\x00\x00\xff\xfflX\x00\x04\xff\xffzh\x01\x08\xff\xffzh\x01\x0c\xff\xffzh\x01\x10\xff\xffs`\x00\x04LMT\x00HST\x00HDT\x00HWT\x00HPT\x00\x0aHST10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeaK\x85v\xdd\x00\x00\x00\xdd\x00\x00\x00\x10\x00\x00\x00Pacific/JohnstonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xfft\xe0p\xbe\xff\xff\xff\xff\xbb\x05CH\xff\xff\xff\xff\xbb!qX\xff\xff\xff\xff\xcb\x89=\xc8\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aI8\xff\xff\xff\xff\xd5\x8dsH\x01\x02\x01\x03\x04\x01\x05\xff\xffl\x02\x00\x00\xff\xfflX\x00\x04\xff\xffzh\x01\x08\xff\xffzh\x01\x0c\xff\xffzh\x01\x10\xff\xffs`\x00\x04LMT\x00HST\x00HDT\x00HWT\x00HPT\x00\x0aHST10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xec =\x89\xac\x00\x00\x00\xac\x00\x00\x00\x0e\x00\x00\x00Pacific/KantonTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff\xc3,\xdb\x80\x00\x00\x00\x00\x12V\x04\xc0\x00\x00\x00\x00/\x059\xb0\x01\x02\x03\x00\x00\x00\x00\x00\x00\xff\xffW@\x00\x04\xff\xffeP\x00\x08\x00\x00\xb6\xd0\x00\x0c-00\x00-12\x00-11\x00+13\x00\x0a<+13>-13\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8=ku\xae\x00\x00\x00\xae\x00\x00\x00\x12\x00\x00\x00Pacific/KiritimatiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff~7H\x80\x00\x00\x00\x00\x12U\xf2\x00\x00\x00\x00\x00/\x05+\xa0\x01\x02\x03\xff\xffl\x80\x00\x00\xff\xffj\x00\x00\x04\xff\xffs`\x00\x0a\x00\x00\xc4\xe0\x00\x0eLMT\x00-1040\x00-10\x00+14\x00\x0a<+14>-14\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x97n7\x1a\xf2\x00\x00\x00\xf2\x00\x00\x00\x0e\x00\x00\x00Pacific/KosraeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xff\x14\xe1\xb4\xb4\xff\xff\xff\xff~6\x1c4\xff\xff\xff\xff\x98\x11\x95\xd0\xff\xff\xff\xff\xa09\xf9\xf0\xff\xff\xff\xff\xc1\xed5\xd0\xff\xff\xff\xff\xc9\xea\x0a`\xff\xff\xff\xff\xd2\x11\x0e\xf0\xff\xff\xff\xff\xff\x86\x1bP\x00\x00\x00\x006\x8bg@\x01\x02\x03\x02\x04\x03\x02\x05\x02\xff\xffGL\x00\x00\x00\x00\x98\xcc\x00\x00\x00\x00\x9a\xb0\x00\x04\x00\x00~\x90\x00\x08\x00\x00\x8c\xa0\x00\x0c\x00\x00\xa8\xc0\x00\x10LMT\x00+11\x00+09\x00+10\x00+12\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xe8]*\xdb\x00\x00\x00\xdb\x00\x00\x00\x11\x00\x00\x00Pacific/KwajaleinTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff~6\x18 \xff\xff\xff\xff\xc1\xed5\xd0\xff\xff\xff\xff\xc9\xea\x0a`\xff\xff\xff\xff\xcfF\x81\xf0\xff\xff\xff\xff\xff\x86\x1bP\x00\x00\x00\x00,v\x0e@\x01\x02\x03\x01\x04\x05\x00\x00\x9c\xe0\x00\x00\x00\x00\x9a\xb0\x00\x04\x00\x00\x8c\xa0\x00\x08\x00\x00~\x90\x00\x0c\xff\xffW@\x00\x10\x00\x00\xa8\xc0\x00\x14LMT\x00+11\x00+10\x00+09\x00-12\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00Pacific/MajuroTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff~6\x12\xcc\x01\x00\x00\xa24\x00\x00\x00\x00\xa8\xc0\x00\x04LMT\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D6\x83\xa1\x8b\x00\x00\x00\x8b\x00\x00\x00\x11\x00\x00\x00Pacific/MarquesasTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x0a\xff\xff\xff\xff\x94PLH\x01\xff\xff}8\x00\x00\xff\xffzh\x00\x04LMT\x00-0930\x00\x0a<-0930>9:30\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x0e\x00\x00\x00Pacific/MidwayTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x08\xff\xff\xff\xffn=\xc8\x08\xff\xff\xff\xff\x91\x05\xfb\x08\x01\x02\x00\x00\xb1x\x00\x00\xff\xff_\xf8\x00\x00\xff\xffeP\x00\x04LMT\x00SST\x00\x0aSST11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe2;Z\xf7\xb7\x00\x00\x00\xb7\x00\x00\x00\x0d\x00\x00\x00Pacific/NauruTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\xa3\xe7+\x04\xff\xff\xff\xff\xcc\x90\xe9\xc8\xff\xff\xff\xff\xd2C'\xf0\x00\x00\x00\x00\x11!\xa8\xe8\x01\x02\x01\x03\x00\x00\x9c|\x00\x00\x00\x00\xa1\xb8\x00\x04\x00\x00~\x90\x00\x0a\x00\x00\xa8\xc0\x00\x0eLMT\x00+1130\x00+09\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x91\xd60\x0c\x9a\x00\x00\x00\x9a\x00\x00\x00\x0c\x00\x00\x00Pacific/NiueTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xff\xdf\xa1jL\xff\xff\xff\xff\xf5\xa6\xb8`\x01\x02\xff\xff`\xb4\x00\x00\xff\xff`\xa0\x00\x04\xff\xffeP\x00\x0aLMT\x00-1120\x00-11\x00\x0a<-11>11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xc2$\x92\xed\x00\x00\x00\xed\x00\x00\x00\x0f\x00\x00\x00Pacific/NorfolkTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x05\x00\x00\x00\x1a\xff\xff\xff\xff~6\x17\x88\xff\xff\xff\xff\xdcA\xf8\x80\x00\x00\x00\x00\x09\x0f\xcah\x00\x00\x00\x00\x09\xb5\xe7h\x00\x00\x00\x00V\x0f\xe6h\x00\x00\x00\x00]\x18\xb2P\x01\x02\x03\x02\x04\x04\x00\x00\x9dx\x00\x00\x00\x00\x9d\x80\x00\x04\x00\x00\xa1\xb8\x00\x0a\x00\x00\xaf\xc8\x01\x10\x00\x00\x9a\xb0\x00\x16LMT\x00+1112\x00+1130\x00+1230\x00+11\x00\x0a<+11>-11<+12>,M10.1.0,M4.1.0/3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\xef\x97\xc6\xc6\x00\x00\x00\xc6\x00\x00\x00\x0e\x00\x00\x00Pacific/NoumeaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x03\x00\x00\x00\x0c\xff\xff\xff\xff\x92\xf5\xc4t\x00\x00\x00\x00\x0e\xe6\xbaP\x00\x00\x00\x00\x0fV\xbb\xc0\x00\x00\x00\x00\x10\xc6\x9cP\x00\x00\x00\x00\x117\xef@\x00\x00\x00\x002\xa0K\xf0\x00\x00\x00\x003\x18Dp\x02\x01\x02\x01\x02\x01\x02\x00\x00\x9c\x0c\x00\x00\x00\x00\xa8\xc0\x01\x04\x00\x00\x9a\xb0\x00\x08LMT\x00+12\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x11\x00\x00\x00Pacific/Pago_PagoTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x08\xff\xff\xff\xffn=\xc8\x08\xff\xff\xff\xff\x91\x05\xfb\x08\x01\x02\x00\x00\xb1x\x00\x00\xff\xff_\xf8\x00\x00\xff\xffeP\x00\x04LMT\x00SST\x00\x0aSST11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\xf8v\xdc\x94\x00\x00\x00\x94\x00\x00\x00\x0d\x00\x00\x00Pacific/PalauTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x08\xff\xff\xff\xff\x14\xe1\xcfl\xff\xff\xff\xff~66\xec\x01\x02\xff\xff,\x94\x00\x00\x00\x00~\x14\x00\x00\x00\x00~\x90\x00\x04LMT\x00+09\x00\x0a<+09>-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfa\x0fA\x05\x99\x00\x00\x00\x99\x00\x00\x00\x10\x00\x00\x00Pacific/PitcairnTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0e\xff\xff\xff\xff~7.\xf4\x00\x00\x00\x005DB\x08\x01\x02\xff\xff\x86\x0c\x00\x00\xff\xff\x88x\x00\x04\xff\xff\x8f\x80\x00\x0aLMT\x00-0830\x00-08\x00\x0a<-08>8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd2K|\x86\x00\x00\x00\x86\x00\x00\x00\x0f\x00\x00\x00Pacific/PohnpeiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x94O3\x8c\x01\x00\x00\x95\xf4\x00\x00\x00\x00\x9a\xb0\x00\x04LMT\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd2K|\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00Pacific/PonapeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x94O3\x8c\x01\x00\x00\x95\xf4\x00\x00\x00\x00\x9a\xb0\x00\x04LMT\x00+11\x00\x0a<+11>-11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x14\x00\x00\x00Pacific/Port_MoresbyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xffV\xb6Z\x08\xff\xff\xff\xffr\xed\xa4\x90\x01\x02\x00\x00\x89\xf8\x00\x00\x00\x00\x89\xf0\x00\x04\x00\x00\x8c\xa0\x00\x09LMT\x00PMMT\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\xe3\xa3S\x96\x01\x00\x00\x96\x01\x00\x00\x11\x00\x00\x00Pacific/RarotongaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff|L\xdc\xc8\xff\xff\xff\xff\xdf\xa1`\xc8\x00\x00\x00\x00\x10\xac\x1b(\x00\x00\x00\x00\x11?\xb5\x18\x00\x00\x00\x00\x12y\x81 \x00\x00\x00\x00\x13\x1f\x97\x18\x00\x00\x00\x00\x14Yc \x00\x00\x00\x00\x14\xffy\x18\x00\x00\x00\x00\x169E \x00\x00\x00\x00\x16\xe8\x95\x98\x00\x00\x00\x00\x18\x22a\xa0\x00\x00\x00\x00\x18\xc8w\x98\x00\x00\x00\x00\x1a\x02C\xa0\x00\x00\x00\x00\x1a\xa8Y\x98\x00\x00\x00\x00\x1b\xe2%\xa0\x00\x00\x00\x00\x1c\x88;\x98\x00\x00\x00\x00\x1d\xc2\x07\xa0\x00\x00\x00\x00\x1eh\x1d\x98\x00\x00\x00\x00\x1f\xa1\xe9\xa0\x00\x00\x00\x00 G\xff\x98\x00\x00\x00\x00!\x81\xcb\xa0\x00\x00\x00\x00\x221\x1c\x18\x00\x00\x00\x00#j\xe8 \x00\x00\x00\x00$\x10\xfe\x18\x00\x00\x00\x00%J\xca \x00\x00\x00\x00%\xf0\xe0\x18\x00\x00\x00\x00'*\xac \x00\x00\x00\x00'\xd0\xc2\x18\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x00\x00\xbb\xb8\x00\x00\xff\xffj8\x00\x00\xff\xfflX\x00\x04\xff\xffs`\x00\x0a\xff\xffzh\x01\x0eLMT\x00-1030\x00-10\x00-0930\x00\x0a<-10>10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FI\xfe\x14^\x01\x00\x00^\x01\x00\x00\x0e\x00\x00\x00Pacific/SaipanTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x00\x00\x00\x06\x00\x00\x00\x15\xff\xff\xff\xff\x14\xe1\xc5\xcc\xff\xff\xff\xff~6-L\xff\xff\xff\xff\xcb7\x95\xe0\xff\xff\xff\xff\xd0.\x89\xf0\xff\xff\xff\xff\xec7\xbe\x00\xff\xff\xff\xff\xef6\xf8\xf0\xff\xff\xff\xff\xfb\x9b\x00\x00\xff\xff\xff\xff\xfe?'\x8c\xff\xff\xff\xff\xff\x01\x1e\x00\xff\xff\xff\xff\xff]X\xf0\x00\x00\x00\x00\x00\x97,\x00\x00\x00\x00\x00\x01Fup\x00\x00\x00\x00\x02w\x0e\x00\x00\x00\x00\x00\x03&Wp\x00\x00\x00\x00\x07p\x97\x00\x00\x00\x00\x00\x07\xcc\xd1\xf0\x00\x00\x00\x00\x0c\x08\x91\x00\x00\x00\x00\x00\x0c|\x87,\x00\x00\x00\x00\x0d\xbf\x94\x80\x00\x00\x00\x00\x0ee\xa3p\x00\x00\x00\x00:C^`\x01\x02\x03\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x04\x02\x05\xff\xff64\x00\x00\x00\x00\x87\xb4\x00\x00\x00\x00\x8c\xa0\x00\x04\x00\x00~\x90\x00\x08\x00\x00\x9a\xb0\x01\x0c\x00\x00\x8c\xa0\x00\x10LMT\x00GST\x00+09\x00GDT\x00ChST\x00\x0aChST-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x0d\x00\x00\x00Pacific/SamoaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x08\xff\xff\xff\xffn=\xc8\x08\xff\xff\xff\xff\x91\x05\xfb\x08\x01\x02\x00\x00\xb1x\x00\x00\xff\xff_\xf8\x00\x00\xff\xffeP\x00\x04LMT\x00SST\x00\x0aSST11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xea\xc1\xda\xcf\x85\x00\x00\x00\x85\x00\x00\x00\x0e\x00\x00\x00Pacific/TahitiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff\x94PU\xb8\x01\xff\xffs\xc8\x00\x00\xff\xffs`\x00\x04LMT\x00-10\x00\x0a<-10>10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00Pacific/TarawaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff~6\x12\xcc\x01\x00\x00\xa24\x00\x00\x00\x00\xa8\xc0\x00\x04LMT\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x97F\x91\xb3\xed\x00\x00\x00\xed\x00\x00\x00\x11\x00\x00\x00Pacific/TongatapuTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\x00\x00\x00\x04\x00\x00\x00\x12\xff\xff\xff\xff\xd2E\x9c@\xff\xff\xff\xff\xef\x11\xe0\x10\x00\x00\x00\x007\xfbG\xd0\x00\x00\x00\x008\xd3}\xd0\x00\x00\x00\x00:\x04\x08P\x00\x00\x00\x00:r\xb8@\x00\x00\x00\x00;\xe3\xeaP\x00\x00\x00\x00-13\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x0c\x00\x00\x00Pacific/TrukTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xffV\xb6Z\x08\xff\xff\xff\xffr\xed\xa4\x90\x01\x02\x00\x00\x89\xf8\x00\x00\x00\x00\x89\xf0\x00\x04\x00\x00\x8c\xa0\x00\x09LMT\x00PMMT\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0c\x00\x00\x00Pacific/WakeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff~6\x12\xcc\x01\x00\x00\xa24\x00\x00\x00\x00\xa8\xc0\x00\x04LMT\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00Pacific/WallisTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x08\xff\xff\xff\xff~6\x12\xcc\x01\x00\x00\xa24\x00\x00\x00\x00\xa8\xc0\x00\x04LMT\x00+12\x00\x0a<+12>-12\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x0b\x00\x00\x00Pacific/YapTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x0d\xff\xff\xff\xffV\xb6Z\x08\xff\xff\xff\xffr\xed\xa4\x90\x01\x02\x00\x00\x89\xf8\x00\x00\x00\x00\x89\xf0\x00\x04\x00\x00\x8c\xa0\x00\x09LMT\x00PMMT\x00+10\x00\x0a<+10>-10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\xfe\xe5\x9e\x9b\x03\x00\x00\x9b\x03\x00\x00\x06\x00\x00\x00PolandTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x00\x00\x00\x06\x00\x00\x00\x1a\xff\xff\xff\xffV\xb6\xd0P\xff\xff\xff\xff\x99\xa8*\xd0\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xda\xf0\xff\xff\xff\xff\x9c\xd9\xae\x90\xff\xff\xff\xff\x9d\xa4\xb5\x90\xff\xff\xff\xff\x9e\xb9\x90\x90\xff\xff\xff\xff\x9f\x84\x97\x90\xff\xff\xff\xff\xa0\x9a\xb6\x00\xff\xff\xff\xff\xa1e\xbd\x00\xff\xff\xff\xff\xa6}|`\xff\xff\xff\xff\xc8v\xde\x10\xff\xff\xff\xff\xcc\xe7K\x10\xff\xff\xff\xff\xcd\xa9\x17\x90\xff\xff\xff\xff\xce\xa2C\x10\xff\xff\xff\xff\xcf\x924\x10\xff\xff\xff\xff\xd0\x84\xba\x00\xff\xff\xff\xff\xd1\x95\x92p\xff\xff\xff\xff\xd2\x8a\xbb`\xff\xff\xff\xff\xd3b\xffp\xff\xff\xff\xff\xd4K#\x90\xff\xff\xff\xff\xd5^\xad\x10\xff\xff\xff\xff\xd6)\xb4\x10\xff\xff\xff\xff\xd7,\x1a\x10\xff\xff\xff\xff\xd8\x09\x96\x10\xff\xff\xff\xff\xd9\x02\xc1\x90\xff\xff\xff\xff\xd9\xe9x\x10\xff\xff\xff\xff\xe8T\xd2\x00\xff\xff\xff\xff\xe8\xf1\xb4\x80\xff\xff\xff\xff\xe9\xe1\xa5\x80\xff\xff\xff\xff\xea\xd1\x96\x80\xff\xff\xff\xff\xec\x14\x96\x00\xff\xff\xff\xff\xec\xba\xb3\x00\xff\xff\xff\xff\xed\xaa\xa4\x00\xff\xff\xff\xff\xee\x9a\x95\x00\xff\xff\xff\xff\xef\xd4Z\x00\xff\xff\xff\xff\xf0zw\x00\xff\xff\xff\xff\xf1\xb4<\x00\xff\xff\xff\xff\xf2ZY\x00\xff\xff\xff\xff\xf3\x94\x1e\x00\xff\xff\xff\xff\xf4:;\x00\xff\xff\xff\xff\xf5}:\x80\xff\xff\xff\xff\xf6\x1a\x1d\x00\x00\x00\x00\x00\x0d\xa4U\x80\x00\x00\x00\x00\x0e\x8b\x0c\x00\x00\x00\x00\x00\x0f\x847\x80\x00\x00\x00\x00\x10t(\x80\x00\x00\x00\x00\x11d\x19\x80\x00\x00\x00\x00\x12T\x0a\x80\x00\x00\x00\x00\x13M6\x00\x00\x00\x00\x00\x143\xec\x80\x00\x00\x00\x00\x15#\xdd\x80\x00\x00\x00\x00\x16\x13\xce\x80\x00\x00\x00\x00\x17\x03\xbf\x80\x00\x00\x00\x00\x17\xf3\xb0\x80\x00\x00\x00\x00\x18\xe3\xa1\x80\x00\x00\x00\x00\x19\xd3\x92\x80\x00\x00\x00\x00\x1a\xc3\x83\x80\x00\x00\x00\x00\x1b\xbc\xaf\x00\x00\x00\x00\x00\x1c\xac\xa0\x00\x00\x00\x00\x00\x1d\x9c\x91\x00\x00\x00\x00\x00\x1e\x8c\x82\x00\x00\x00\x00\x00\x1f|s\x00\x00\x00\x00\x00 ld\x00\x00\x00\x00\x00!\x5cU\x00\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\xec\x00\xff\xff\xff\xff\xe50 p\xff\xff\xff\xff\xe6!q\x00\xff\xff\xff\xff\xe7\x12\xa5p\xff\xff\xff\xff\xe8\x02\xa4\x80\xff\xff\xff\xff\xe8\xf3\xd8\xf0\xff\xff\xff\xff\xe9\xe3\xd8\x00\xff\xff\xff\xff\xea\xd5\x0cp\xff\xff\xff\xff\xeb\xc5\x0b\x80\xff\xff\xff\xff\xec\xb6?\xf0\xff\xff\xff\xff\xed\xf7\xfc\x00\xff\xff\xff\xff\xee\x98\xc4\xf0\xff\xff\xff\xff\xef\xd9/\x80\xff\xff\xff\xff\xf0y\xf8p\x00\x00\x00\x00\x07\xfcV\x00\x00\x00\x00\x00\x08\xed\x8ap\x00\x00\x00\x00\x09\xdd\x89\x80\x00\x00\x00\x00\x0a\xce\xbd\xf0\x00\x00\x00\x00\x11\xdb\xa1\x80\x00\x00\x00\x00\x12T\xddp\x01\x02\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x03\x01\x00\x00q\xe8\x00\x00\x00\x00p\x80\x00\x04\x00\x00~\x90\x00\x08\x00\x00~\x90\x01\x0cLMT\x00CST\x00JST\x00CDT\x00\x0aCST-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7X,Y\x9f\x01\x00\x00\x9f\x01\x00\x00\x03\x00\x00\x00ROKTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x06\x00\x00\x00\x10\xff\xff\xff\xff\x8b\xd7\xf0x\xff\xff\xff\xff\x92\xe6\x16\xf8\xff\xff\xff\xff\xd2C'\xf0\xff\xff\xff\xff\xd7e\x8fp\xff\xff\xff\xff\xd7\xee\x9d`\xff\xff\xff\xff\xd8\xf8\xfap\xff\xff\xff\xff\xd9\xcd-\xe0\xff\xff\xff\xff\xda\xd7\x8a\xf0\xff\xff\xff\xff\xdb\xad\x0f\xe0\xff\xff\xff\xff\xdc\xe6\xe2\xf0\xff\xff\xff\xff\xdd\x8c\xf1\xe0\xff\xff\xff\xff\xe2O)\xf0\xff\xff\xff\xff\xe4k\xb7\xf8\xff\xff\xff\xff\xe5\x13\x18h\xff\xff\xff\xff\xe6b\x03x\xff\xff\xff\xff\xe7\x11L\xe8\xff\xff\xff\xff\xe8/px\xff\xff\xff\xff\xe8\xe7\xf4h\xff\xff\xff\xff\xea\x0fRx\xff\xff\xff\xff\xea\xc7\xd6h\xff\xff\xff\xff\xeb\xef4x\xff\xff\xff\xff\xec\xa7\xb8h\xff\xff\xff\xff\xed\xcf\x16x\xff\xff\xff\xff\xee\x87\x9ah\xff\xff\xff\xff\xf05qx\x00\x00\x00\x00 \xa3`\x90\x00\x00\x00\x00!ng\x90\x00\x00\x00\x00\x22\x83B\x90\x00\x00\x00\x00#NI\x90\x01\x02\x04\x03\x04\x03\x04\x03\x04\x03\x04\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x05\x01\x04\x03\x04\x03\x04\x00\x00w\x08\x00\x00\x00\x00w\x88\x00\x04\x00\x00~\x90\x00\x08\x00\x00\x8c\xa0\x01\x0c\x00\x00~\x90\x00\x04\x00\x00\x85\x98\x01\x0cLMT\x00KST\x00JST\x00KDT\x00\x0aKST-9\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F7k\x1c\x00\x01\x00\x00\x00\x01\x00\x00\x09\x00\x00\x00SingaporeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x08\x00\x00\x00 \xff\xff\xff\xff~6S\xa3\xff\xff\xff\xff\x86\x83\x85\xa3\xff\xff\xff\xff\xbagN\x90\xff\xff\xff\xff\xc0\x0a\xe4`\xff\xff\xff\xff\xca\xb3\xe5`\xff\xff\xff\xff\xcb\x91_\x08\xff\xff\xff\xff\xd2Hm\xf0\x00\x00\x00\x00\x16\x91\xee\x00\x01\x02\x03\x04\x05\x06\x05\x07\x00\x00a]\x00\x00\x00\x00a]\x00\x04\x00\x00bp\x00\x08\x00\x00g \x01\x0c\x00\x00g \x00\x0c\x00\x00ix\x00\x12\x00\x00~\x90\x00\x18\x00\x00p\x80\x00\x1cLMT\x00SMT\x00+07\x00+0720\x00+0730\x00+09\x00+08\x00\x0a<+08>-8\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07W\x10\xd1\xb0\x04\x00\x00\xb0\x04\x00\x00\x06\x00\x00\x00TurkeyTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\x00\x00\x00\x06\x00\x00\x00\x19\xff\xff\xff\xffV\xb6\xc8\xd8\xff\xff\xff\xff\x90\x8b\xf5\x98\xff\xff\xff\xff\x9b\x0c\x17`\xff\xff\xff\xff\x9b\xd5\xbe\xd0\xff\xff\xff\xff\xa2ec\xe0\xff\xff\xff\xff\xa3{\x82P\xff\xff\xff\xff\xa4N\x80`\xff\xff\xff\xff\xa5?\xb4\xd0\xff\xff\xff\xff\xa6%'\xe0\xff\xff\xff\xff\xa7'\x7f\xd0\xff\xff\xff\xff\xaa((`\xff\xff\xff\xff\xaa\xe1\xfd\xd0\xff\xff\xff\xff\xab\xf9\x89\xe0\xff\xff\xff\xff\xac\xc31P\xff\xff\xff\xff\xc8\x81?\xe0\xff\xff\xff\xff\xc9\x01\x13P\xff\xff\xff\xff\xc9J\xf5`\xff\xff\xff\xff\xca\xce\x80P\xff\xff\xff\xff\xcb\xcb\xae`\xff\xff\xff\xff\xd2k\x09P\xff\xff\xff\xff\xd3\xa29`\xff\xff\xff\xff\xd4C\x02P\xff\xff\xff\xff\xd5L\x0d\xe0\xff\xff\xff\xff\xd6){\xd0\xff\xff\xff\xff\xd7+\xef\xe0\xff\xff\xff\xff\xd8\x09]\xd0\xff\xff\xff\xff\xd9\x02\x97`\xff\xff\xff\xff\xd9\xe9?\xd0\xff\xff\xff\xff\xda\xeb\xb3\xe0\xff\xff\xff\xff\xdb\xd2\x5cP\xff\xff\xff\xff\xdc\xd4\xd0`\xff\xff\xff\xff\xdd\xb2>P\xff\xff\xff\xff\xf1\xf4\xb9`\xff\xff\xff\xff\xf4b\xefP\xff\xff\xff\xff\xf5h\x06`\xff\xff\xff\xff\xf6\x1f8\xd0\x00\x00\x00\x00\x06n\x93p\x00\x00\x00\x00\x079\x9ap\x00\x00\x00\x00\x07\xfbu\x00\x00\x00\x00\x00\x09\x19|p\x00\x00\x00\x00\x09\xd0\xcb\x00\x00\x00\x00\x00\x0a\xf9^p\x00\x00\x00\x00\x0b\xb1\xfe\x80\x00\x00\x00\x00\x0c\xd9@p\x00\x00\x00\x00\x0d\xa4U\x80\x00\x00\x00\x00\x0e\xa6\xadp\x00\x00\x00\x00\x0f\x847\x80\x00\x00\x00\x00\x0f\xf8\x11P\x00\x00\x00\x00\x19\x89\xb0p\x00\x00\x00\x00\x19\xdc\xb0\xe0\x00\x00\x00\x00\x1b\xe6\xd0\xf0\x00\x00\x00\x00\x1c\xc6\xef\xf0\x00\x00\x00\x00\x1d\x9b1p\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00(\xe5\x09p\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x8b\x83\xf0\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xc9\x90\x00\x00\x00\x00G#\xdf\x10\x00\x00\x00\x00G\xee\xe6\x10\x00\x00\x00\x00I\x03\xc1\x10\x00\x00\x00\x00I\xce\xc8\x10\x00\x00\x00\x00J\xe3\xa3\x10\x00\x00\x00\x00K\xae\xaa\x10\x00\x00\x00\x00L\xcc\xbf\x90\x00\x00\x00\x00M\x8f\xdd\x90\x00\x00\x00\x00N\xac\xa1\x90\x00\x00\x00\x00Onn\x10\x00\x00\x00\x00P\x8c\x83\x90\x00\x00\x00\x00QW\x8a\x90\x00\x00\x00\x00Rle\x90\x00\x00\x00\x00S8\xbe\x10\x00\x00\x00\x00TLG\x90\x00\x00\x00\x00U\x17N\x90\x00\x00\x00\x00V>\x9e\x90\x00\x00\x00\x00V\xf70\x90\x00\x00\x00\x00W\xcf.P\x01\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x05\x04\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x04\x00\x00\x1b(\x00\x00\x00\x00\x1bh\x00\x04\x00\x00*0\x01\x08\x00\x00\x1c \x00\x0d\x00\x00*0\x00\x11\x00\x008@\x01\x15LMT\x00IMT\x00EEST\x00EET\x00+03\x00+04\x00\x0a<+03>-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00UCTTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00UTC\x00\x0aUTC0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x11Q\x06\xd1\x03\x00\x00\xd1\x03\x00\x00\x09\x00\x00\x00US/AlaskaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x0a\x00\x00\x00(\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x87AH\xff\xff\xff\xff\xcb\x896\xc0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aB0\xff\xff\xff\xff\xfa\xd2G\xa0\xff\xff\xff\xff\xfe\xb8c@\xff\xff\xff\xff\xff\xa8F0\x00\x00\x00\x00\x00\x98E@\x00\x00\x00\x00\x01\x88(0\x00\x00\x00\x00\x02x'@\x00\x00\x00\x00\x03qD\xb0\x00\x00\x00\x00\x04aC\xc0\x00\x00\x00\x00\x05Q&\xb0\x00\x00\x00\x00\x06A%\xc0\x00\x00\x00\x00\x071\x08\xb0\x00\x00\x00\x00\x07\x8d_\xc0\x00\x00\x00\x00\x09\x10\xea\xb0\x00\x00\x00\x00\x09\xad\xdb@\x00\x00\x00\x00\x0a\xf0\xcc\xb0\x00\x00\x00\x00\x0b\xe0\xcb\xc0\x00\x00\x00\x00\x0c\xd9\xe90\x00\x00\x00\x00\x0d\xc0\xad\xc0\x00\x00\x00\x00\x0e\xb9\xcb0\x00\x00\x00\x00\x0f\xa9\xca@\x00\x00\x00\x00\x10\x99\xad0\x00\x00\x00\x00\x11\x89\xac@\x00\x00\x00\x00\x12y\x8f0\x00\x00\x00\x00\x13i\x8e@\x00\x00\x00\x00\x14Yq0\x00\x00\x00\x00\x15Ip@\x00\x00\x00\x00\x169S0\x00\x00\x00\x00\x17)R@\x00\x00\x00\x00\x18\x22o\xb0\x00\x00\x00\x00\x19\x094@\x00\x00\x00\x00\x1a\x02Q\xb0\x00\x00\x00\x00\x1a+\x14\x10\x00\x00\x00\x00\x1a\xf2B\xb0\x00\x00\x00\x00\x1b\xe2%\xa0\x00\x00\x00\x00\x1c\xd2$\xb0\x00\x00\x00\x00\x1d\xc2\x07\xa0\x00\x00\x00\x00\x1e\xb2\x06\xb0\x00\x00\x00\x00\x1f\xa1\xe9\xa0\x00\x00\x00\x00 v90\x00\x00\x00\x00!\x81\xcb\xa0\x00\x00\x00\x00\x22V\x1b0\x00\x00\x00\x00#j\xe8 \x00\x00\x00\x00$5\xfd0\x00\x00\x00\x00%J\xca \x00\x00\x00\x00&\x15\xdf0\x00\x00\x00\x00'*\xac \x00\x00\x00\x00'\xfe\xfb\xb0\x00\x00\x00\x00)\x0a\x8e \x00\x00\x00\x00)\xde\xdd\xb0\x00\x00\x00\x00*\xeap \x00\x00\x00\x00+\xbe\xbf\xb0\x00\x00\x00\x00,\xd3\x8c\xa0\x00\x00\x00\x00-\x9e\xa1\xb0\x00\x00\x00\x00.\xb3n\xa0\x00\x00\x00\x00/~\x83\xb0\x00\x00\x00\x000\x93P\xa0\x00\x00\x00\x001g\xa00\x00\x00\x00\x002s2\xa0\x00\x00\x00\x003G\x820\x00\x00\x00\x004S\x14\xa0\x00\x00\x00\x005'd0\x00\x00\x00\x0062\xf6\xa0\x00\x00\x00\x007\x07F0\x00\x00\x00\x008\x1c\x13 \x00\x00\x00\x008\xe7(0\x00\x00\x00\x009\xfb\xf5 \x00\x00\x00\x00:\xc7\x0a0\x00\x00\x00\x00;\xdb\xd7 \x00\x00\x00\x00<\xb0&\xb0\x00\x00\x00\x00=\xbb\xb9 \x00\x00\x00\x00>\x90\x08\xb0\x00\x00\x00\x00?\x9b\x9b \x00\x00\x00\x00@o\xea\xb0\x00\x00\x00\x00A\x84\xb7\xa0\x00\x00\x00\x00BO\xcc\xb0\x00\x00\x00\x00Cd\x99\xa0\x00\x00\x00\x00D/\xae\xb0\x00\x00\x00\x00ED{\xa0\x00\x00\x00\x00E\xf3\xe10\x01\x02\x03\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x07\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x00\x00\xc4\xf8\x00\x00\xff\xffsx\x00\x00\xff\xffs`\x00\x04\xff\xff\x81p\x01\x08\xff\xff\x81p\x01\x0c\xff\xffs`\x00\x10\xff\xff\x81p\x01\x15\xff\xff\x81p\x00\x1a\xff\xff\x8f\x80\x01\x1e\xff\xff\x81p\x00#LMT\x00AST\x00AWT\x00APT\x00AHST\x00AHDT\x00YST\x00AKDT\x00AKST\x00\x0aAKST9AKDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae,\xa44\xc9\x03\x00\x00\xc9\x03\x00\x00\x0b\x00\x00\x00US/AleutianTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x0a\x00\x00\x00!\xff\xff\xff\xff?\xc2\xfd\xd1\xff\xff\xff\xff}\x87Z^\xff\xff\xff\xff\xcb\x89D\xd0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aP@\xff\xff\xff\xff\xfa\xd2U\xb0\xff\xff\xff\xff\xfe\xb8qP\xff\xff\xff\xff\xff\xa8T@\x00\x00\x00\x00\x00\x98SP\x00\x00\x00\x00\x01\x886@\x00\x00\x00\x00\x02x5P\x00\x00\x00\x00\x03qR\xc0\x00\x00\x00\x00\x04aQ\xd0\x00\x00\x00\x00\x05Q4\xc0\x00\x00\x00\x00\x06A3\xd0\x00\x00\x00\x00\x071\x16\xc0\x00\x00\x00\x00\x07\x8dm\xd0\x00\x00\x00\x00\x09\x10\xf8\xc0\x00\x00\x00\x00\x09\xad\xe9P\x00\x00\x00\x00\x0a\xf0\xda\xc0\x00\x00\x00\x00\x0b\xe0\xd9\xd0\x00\x00\x00\x00\x0c\xd9\xf7@\x00\x00\x00\x00\x0d\xc0\xbb\xd0\x00\x00\x00\x00\x0e\xb9\xd9@\x00\x00\x00\x00\x0f\xa9\xd8P\x00\x00\x00\x00\x10\x99\xbb@\x00\x00\x00\x00\x11\x89\xbaP\x00\x00\x00\x00\x12y\x9d@\x00\x00\x00\x00\x13i\x9cP\x00\x00\x00\x00\x14Y\x7f@\x00\x00\x00\x00\x15I~P\x00\x00\x00\x00\x169a@\x00\x00\x00\x00\x17)`P\x00\x00\x00\x00\x18\x22}\xc0\x00\x00\x00\x00\x19\x09BP\x00\x00\x00\x00\x1a\x02_\xc0\x00\x00\x00\x00\x1a+\x22 \x00\x00\x00\x00\x1a\xf2P\xc0\x00\x00\x00\x00\x1b\xe23\xb0\x00\x00\x00\x00\x1c\xd22\xc0\x00\x00\x00\x00\x1d\xc2\x15\xb0\x00\x00\x00\x00\x1e\xb2\x14\xc0\x00\x00\x00\x00\x1f\xa1\xf7\xb0\x00\x00\x00\x00 vG@\x00\x00\x00\x00!\x81\xd9\xb0\x00\x00\x00\x00\x22V)@\x00\x00\x00\x00#j\xf60\x00\x00\x00\x00$6\x0b@\x00\x00\x00\x00%J\xd80\x00\x00\x00\x00&\x15\xed@\x00\x00\x00\x00'*\xba0\x00\x00\x00\x00'\xff\x09\xc0\x00\x00\x00\x00)\x0a\x9c0\x00\x00\x00\x00)\xde\xeb\xc0\x00\x00\x00\x00*\xea~0\x00\x00\x00\x00+\xbe\xcd\xc0\x00\x00\x00\x00,\xd3\x9a\xb0\x00\x00\x00\x00-\x9e\xaf\xc0\x00\x00\x00\x00.\xb3|\xb0\x00\x00\x00\x00/~\x91\xc0\x00\x00\x00\x000\x93^\xb0\x00\x00\x00\x001g\xae@\x00\x00\x00\x002s@\xb0\x00\x00\x00\x003G\x90@\x00\x00\x00\x004S\x22\xb0\x00\x00\x00\x005'r@\x00\x00\x00\x0063\x04\xb0\x00\x00\x00\x007\x07T@\x00\x00\x00\x008\x1c!0\x00\x00\x00\x008\xe76@\x00\x00\x00\x009\xfc\x030\x00\x00\x00\x00:\xc7\x18@\x00\x00\x00\x00;\xdb\xe50\x00\x00\x00\x00<\xb04\xc0\x00\x00\x00\x00=\xbb\xc70\x00\x00\x00\x00>\x90\x16\xc0\x00\x00\x00\x00?\x9b\xa90\x00\x00\x00\x00@o\xf8\xc0\x00\x00\x00\x00A\x84\xc5\xb0\x00\x00\x00\x00BO\xda\xc0\x00\x00\x00\x00Cd\xa7\xb0\x00\x00\x00\x00D/\xbc\xc0\x00\x00\x00\x00ED\x89\xb0\x00\x00\x00\x00E\xf3\xef@\x01\x02\x03\x04\x02\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x07\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x09\x08\x00\x00\xab\xe2\x00\x00\xff\xffZb\x00\x00\xff\xffeP\x00\x04\xff\xffs`\x01\x08\xff\xffs`\x01\x0c\xff\xffeP\x00\x10\xff\xffs`\x01\x14\xff\xffs`\x00\x18\xff\xff\x81p\x01\x1d\xff\xffs`\x00\x19LMT\x00NST\x00NWT\x00NPT\x00BST\x00BDT\x00AHST\x00HDT\x00\x0aHST10HDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\xb8\xab\x9b\xf0\x00\x00\x00\xf0\x00\x00\x00\x0a\x00\x00\x00US/ArizonaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x00\x00\x00\x04\x00\x00\x00\x10\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xcf\x17\xdf\x1c\xff\xff\xff\xff\xcf\x8f\xe5\xac\xff\xff\xff\xff\xd0\x81\x1a\x1c\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\x02\x01\x02\x01\x02\x03\x02\x03\x02\x01\x02\xff\xff\x96\xee\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0cLMT\x00MDT\x00MST\x00MWT\x00\x0aMST7\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xdc\xa9=\xda\x06\x00\x00\xda\x06\x00\x00\x0a\x00\x00\x00US/CentralTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xa2\xcbt\x00\xff\xff\xff\xff\xa3\x83\xf7\xf0\xff\xff\xff\xff\xa4E\xd2\x80\xff\xff\xff\xff\xa5c\xd9\xf0\xff\xff\xff\xff\xa6S\xd9\x00\xff\xff\xff\xff\xa7\x15\x97p\xff\xff\xff\xff\xa83\xbb\x00\xff\xff\xff\xff\xa8\xfe\xb3\xf0\xff\xff\xff\xff\xaa\x13\x9d\x00\xff\xff\xff\xff\xaa\xde\x95\xf0\xff\xff\xff\xff\xab\xf3\x7f\x00\xff\xff\xff\xff\xac\xbew\xf0\xff\xff\xff\xff\xad\xd3a\x00\xff\xff\xff\xff\xae\x9eY\xf0\xff\xff\xff\xff\xaf\xb3C\x00\xff\xff\xff\xff\xb0~;\xf0\xff\xff\xff\xff\xb1\x9c_\x80\xff\xff\xff\xff\xb2gXp\xff\xff\xff\xff\xb3|A\x80\xff\xff\xff\xff\xb4G:p\xff\xff\xff\xff\xb5\x5c#\x80\xff\xff\xff\xff\xb6'\x1cp\xff\xff\xff\xff\xb7<\x05\x80\xff\xff\xff\xff\xb8\x06\xfep\xff\xff\xff\xff\xb9\x1b\xe7\x80\xff\xff\xff\xff\xb9\xe6\xe0p\xff\xff\xff\xff\xbb\x05\x04\x00\xff\xff\xff\xff\xbb\xc6\xc2p\xff\xff\xff\xff\xbc\xe4\xe6\x00\xff\xff\xff\xff\xbd\xaf\xde\xf0\xff\xff\xff\xff\xbe\xc4\xc8\x00\xff\xff\xff\xff\xbf\x8f\xc0\xf0\xff\xff\xff\xff\xc0Z\xd6\x00\xff\xff\xff\xff\xc1\xb0\x8f\xde\x80\x00\x00\x00\x00?\x9bp\xf0\x00\x00\x00\x00@o\xc0\x80\x00\x00\x00\x00A\x84\x8dp\x00\x00\x00\x00BO\xa2\x80\x00\x00\x00\x00Cdop\x00\x00\x00\x00D/\x84\x80\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x04\x05\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xad\xd4\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x00\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x01\x14LMT\x00CDT\x00CST\x00EST\x00CWT\x00CPT\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xb6{\xc9\x13\x02\x00\x00\x13\x02\x00\x00\x0f\x00\x00\x00US/East-IndianaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&\x00\x00\x00\x07\x00\x00\x00\x1c\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcaW\x22\x80\xff\xff\xff\xff\xca\xd8Gp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd3u\xf3\x00\xff\xff\xff\xff\xd4@\xeb\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xfe\xb8\x1c\xf0\xff\xff\xff\xff\xff\xa7\xff\xe0\x00\x00\x00\x00\x00\x97\xfe\xf0\x00\x00\x00\x00\x01\x87\xe1\xe0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x05\x06\x05\x06\x05\x06\x05\x06\xff\xff\xaf:\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14\xff\xff\xc7\xc0\x01\x18LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x9aG\xc8\xd0\x06\x00\x00\xd0\x06\x00\x00\x0a\x00\x00\x00US/EasternTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^\x03\xf0\x90\xff\xff\xff\xff\x9e\xa6\x1ep\xff\xff\xff\xff\x9f\xba\xeb`\xff\xff\xff\xff\xa0\x86\x00p\xff\xff\xff\xff\xa1\x9a\xcd`\xff\xff\xff\xff\xa2e\xe2p\xff\xff\xff\xff\xa3\x83\xe9\xe0\xff\xff\xff\xff\xa4j\xaep\xff\xff\xff\xff\xa55\xa7`\xff\xff\xff\xff\xa6S\xca\xf0\xff\xff\xff\xff\xa7\x15\x89`\xff\xff\xff\xff\xa83\xac\xf0\xff\xff\xff\xff\xa8\xfe\xa5\xe0\xff\xff\xff\xff\xaa\x13\x8e\xf0\xff\xff\xff\xff\xaa\xde\x87\xe0\xff\xff\xff\xff\xab\xf3p\xf0\xff\xff\xff\xff\xac\xbei\xe0\xff\xff\xff\xff\xad\xd3R\xf0\xff\xff\xff\xff\xae\x9eK\xe0\xff\xff\xff\xff\xaf\xb34\xf0\xff\xff\xff\xff\xb0~-\xe0\xff\xff\xff\xff\xb1\x9cQp\xff\xff\xff\xff\xb2gJ`\xff\xff\xff\xff\xb3|3p\xff\xff\xff\xff\xb4G,`\xff\xff\xff\xff\xb5\x5c\x15p\xff\xff\xff\xff\xb6'\x0e`\xff\xff\xff\xff\xb7;\xf7p\xff\xff\xff\xff\xb8\x06\xf0`\xff\xff\xff\xff\xb9\x1b\xd9p\xff\xff\xff\xff\xb9\xe6\xd2`\xff\xff\xff\xff\xbb\x04\xf5\xf0\xff\xff\xff\xff\xbb\xc6\xb4`\xff\xff\xff\xff\xbc\xe4\xd7\xf0\xff\xff\xff\xff\xbd\xaf\xd0\xe0\xff\xff\xff\xff\xbe\xc4\xb9\xf0\xff\xff\xff\xff\xbf\x8f\xb2\xe0\xff\xff\xff\xff\xc0\xa4\x9b\xf0\xff\xff\xff\xff\xc1o\x94\xe0\xff\xff\xff\xff\xc2\x84}\xf0\xff\xff\xff\xff\xc3Ov\xe0\xff\xff\xff\xff\xc4d_\xf0\xff\xff\xff\xff\xc5/X\xe0\xff\xff\xff\xff\xc6M|p\xff\xff\xff\xff\xc7\x0f:\xe0\xff\xff\xff\xff\xc8-^p\xff\xff\xff\xff\xc8\xf8W`\xff\xff\xff\xff\xca\x0d@p\xff\xff\xff\xff\xca\xd89`\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd3u\xe4\xf0\xff\xff\xff\xff\xd4@\xdd\xe0\xff\xff\xff\xff\xd5U\xc6\xf0\xff\xff\xff\xff\xd6 \xbf\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xd9\x15\x8a\xf0\xff\xff\xff\xff\xd9\xe0\x83\xe0\xff\xff\xff\xff\xda\xfe\xa7p\xff\xff\xff\xff\xdb\xc0e\xe0\xff\xff\xff\xff\xdc\xde\x89p\xff\xff\xff\xff\xdd\xa9\x82`\xff\xff\xff\xff\xde\xbekp\xff\xff\xff\xff\xdf\x89d`\xff\xff\xff\xff\xe0\x9eMp\xff\xff\xff\xff\xe1iF`\xff\xff\xff\xff\xe2~/p\xff\xff\xff\xff\xe3I(`\xff\xff\xff\xff\xe4^\x11p\xff\xff\xff\xff\xe5W.\xe0\xff\xff\xff\xff\xe6G-\xf0\xff\xff\xff\xff\xe77\x10\xe0\xff\xff\xff\xff\xe8'\x0f\xf0\xff\xff\xff\xff\xe9\x16\xf2\xe0\xff\xff\xff\xff\xea\x06\xf1\xf0\xff\xff\xff\xff\xea\xf6\xd4\xe0\xff\xff\xff\xff\xeb\xe6\xd3\xf0\xff\xff\xff\xff\xec\xd6\xb6\xe0\xff\xff\xff\xff\xed\xc6\xb5\xf0\xff\xff\xff\xff\xee\xbf\xd3`\xff\xff\xff\xff\xef\xaf\xd2p\xff\xff\xff\xff\xf0\x9f\xb5`\xff\xff\xff\xff\xf1\x8f\xb4p\xff\xff\xff\xff\xf2\x7f\x97`\xff\xff\xff\xff\xf3o\x96p\xff\xff\xff\xff\xf4_y`\xff\xff\xff\xff\xf5Oxp\xff\xff\xff\xff\xf6?[`\xff\xff\xff\xff\xf7/Zp\xff\xff\xff\xff\xf8(w\xe0\xff\xff\xff\xff\xf9\x0f\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\xba\x9e\x00\x00\xff\xff\xc7\xc0\x01\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10LMT\x00EDT\x00EST\x00EWT\x00EPT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeaK\x85v\xdd\x00\x00\x00\xdd\x00\x00\x00\x09\x00\x00\x00US/HawaiiTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x06\x00\x00\x00\x14\xff\xff\xff\xfft\xe0p\xbe\xff\xff\xff\xff\xbb\x05CH\xff\xff\xff\xff\xbb!qX\xff\xff\xff\xff\xcb\x89=\xc8\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2aI8\xff\xff\xff\xff\xd5\x8dsH\x01\x02\x01\x03\x04\x01\x05\xff\xffl\x02\x00\x00\xff\xfflX\x00\x04\xff\xffzh\x01\x08\xff\xffzh\x01\x0c\xff\xffzh\x01\x10\xff\xffs`\x00\x04LMT\x00HST\x00HDT\x00HWT\x00HPT\x00\x0aHST10\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$ \x873\xf8\x03\x00\x00\xf8\x03\x00\x00\x11\x00\x00\x00US/Indiana-StarkeTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff^\x03\xfe\xa0\xff\xff\xff\xff\x9e\xa6,\x80\xff\xff\xff\xff\x9f\xba\xf9p\xff\xff\xff\xff\xa0\x86\x0e\x80\xff\xff\xff\xff\xa1\x9a\xdbp\xff\xff\xff\xff\xcb\x88\xfe\x80\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x09\xf0\xff\xff\xff\xff\xd5U\xd5\x00\xff\xff\xff\xff\xd6 \xcd\xf0\xff\xff\xff\xff\xd75\xb7\x00\xff\xff\xff\xff\xd8\x00\xaf\xf0\xff\xff\xff\xff\xd9\x15\x99\x00\xff\xff\xff\xff\xd9\xe0\x91\xf0\xff\xff\xff\xff\xda\xfe\xb5\x80\xff\xff\xff\xff\xdb\xc0s\xf0\xff\xff\xff\xff\xdc\xde\x97\x80\xff\xff\xff\xff\xdd\xa9\x90p\xff\xff\xff\xff\xde\xbey\x80\xff\xff\xff\xff\xdf\x89rp\xff\xff\xff\xff\xe0\x9e[\x80\xff\xff\xff\xff\xe1iTp\xff\xff\xff\xff\xe2~=\x80\xff\xff\xff\xff\xe3I6p\xff\xff\xff\xff\xe4^\x1f\x80\xff\xff\xff\xff\xe5W<\xf0\xff\xff\xff\xff\xe6G<\x00\xff\xff\xff\xff\xe77\x1e\xf0\xff\xff\xff\xff\xe8'\x1e\x00\xff\xff\xff\xff\xe8\xf2\x16\xf0\xff\xff\xff\xff\xea\x07\x00\x00\xff\xff\xff\xff\xea\xd1\xf8\xf0\xff\xff\xff\xff\xeb\xe6\xe2\x00\xff\xff\xff\xff\xec\xd6\xc4\xf0\xff\xff\xff\xff\xed\xc6\xc4\x00\xff\xff\xff\xff\xee\xbf\xe1p\xff\xff\xff\xff\xef\xaf\xe0\x80\xff\xff\xff\xff\xf0\x9f\xc3p\xff\xff\xff\xff\xf1\x8f\xc2\x80\xff\xff\xff\xff\xf4_\x87p\xff\xff\xff\xff\xfa\xf8g\x00\xff\xff\xff\xff\xfb\xe8I\xf0\xff\xff\xff\xff\xfc\xd8I\x00\xff\xff\xff\xff\xfd\xc8+\xf0\xff\xff\xff\xff\xfe\xb8+\x00\xff\xff\xff\xff\xff\xa8\x0d\xf0\x00\x00\x00\x00\x00\x98\x0d\x00\x00\x00\x00\x00\x01\x87\xef\xf0\x00\x00\x00\x00\x02w\xef\x00\x00\x00\x00\x00\x03q\x0cp\x00\x00\x00\x00\x04a\x0b\x80\x00\x00\x00\x00\x05P\xeep\x00\x00\x00\x00\x06@\xed\x80\x00\x00\x00\x00\x070\xd0p\x00\x00\x00\x00\x07\x8d'\x80\x00\x00\x00\x00\x09\x10\xb2p\x00\x00\x00\x00\x09\xad\xa3\x00\x00\x00\x00\x00\x0a\xf0\x94p\x00\x00\x00\x00\x0b\xe0\x93\x80\x00\x00\x00\x00\x0c\xd9\xb0\xf0\x00\x00\x00\x00\x0d\xc0u\x80\x00\x00\x00\x00\x0e\xb9\x92\xf0\x00\x00\x00\x00\x0f\xa9\x92\x00\x00\x00\x00\x00\x10\x99t\xf0\x00\x00\x00\x00\x11\x89t\x00\x00\x00\x00\x00\x12yV\xf0\x00\x00\x00\x00\x13iV\x00\x00\x00\x00\x00\x14Y8\xf0\x00\x00\x00\x00\x15I8\x00\x00\x00\x00\x00\x169\x1a\xf0\x00\x00\x00\x00\x17)\x1a\x00\x00\x00\x00\x00\x18\x227p\x00\x00\x00\x00\x19\x08\xfc\x00\x00\x00\x00\x00\x1a\x02\x19p\x00\x00\x00\x00\x1a\xf2\x18\x80\x00\x00\x00\x00\x1b\xe1\xfbp\x00\x00\x00\x00\x1c\xd1\xfa\x80\x00\x00\x00\x00\x1d\xc1\xddp\x00\x00\x00\x00\x1e\xb1\xdc\x80\x00\x00\x00\x00\x1f\xa1\xbfp\x00\x00\x00\x00 v\x0f\x00\x00\x00\x00\x00!\x81\xa1p\x00\x00\x00\x00\x22U\xf1\x00\x00\x00\x00\x00#j\xbd\xf0\x00\x00\x00\x00$5\xd3\x00\x00\x00\x00\x00%J\x9f\xf0\x00\x00\x00\x00&\x15\xb5\x00\x00\x00\x00\x00'*\x81\xf0\x00\x00\x00\x00'\xfe\xd1\x80\x00\x00\x00\x00)\x0ac\xf0\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDQp\x00\x00\x00\x00E\xf3\xb7\x00\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x05\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x05\x01\x02\x01\xff\xff\xae\xca\x00\x00\xff\xff\xb9\xb0\x01\x04\xff\xff\xab\xa0\x00\x08\xff\xff\xb9\xb0\x01\x0c\xff\xff\xb9\xb0\x01\x10\xff\xff\xb9\xb0\x00\x14LMT\x00CDT\x00CST\x00CWT\x00CPT\x00EST\x00\x0aCST6CDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x14\xe7\x03\x83\x03\x00\x00\x83\x03\x00\x00\x0b\x00\x00\x00US/MichiganTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x00\x00\x00\x06\x00\x00\x00\x18\xff\xff\xff\xff\x85\xbd\x22[\xff\xff\xff\xff\x99<\x94\x00\xff\xff\xff\xff\xcb\x88\xf0p\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2`\xfb\xe0\xff\xff\xff\xff\xd75\xa8\xf0\xff\xff\xff\xff\xd8\x00\xa1\xe0\xff\xff\xff\xff\xfb3\x90\x8c\xff\xff\xff\xff\xfb\xe8;\xe0\xff\xff\xff\xff\xfc\xd8:\xf0\xff\xff\xff\xff\xfd\xc8\x1d\xe0\x00\x00\x00\x00\x06@\xdfp\x00\x00\x00\x00\x070\xc2`\x00\x00\x00\x00\x07\x8d\x19p\x00\x00\x00\x00\x09\x10\xa4`\x00\x00\x00\x00\x0a\x00\xa3p\x00\x00\x00\x00\x0a\xf0\x86`\x00\x00\x00\x00\x0b\xe0\x85p\x00\x00\x00\x00\x0c\xd9\xa2\xe0\x00\x00\x00\x00\x0d\xc0gp\x00\x00\x00\x00\x0e\xb9\x84\xe0\x00\x00\x00\x00\x0f\xa9\x83\xf0\x00\x00\x00\x00\x10\x99f\xe0\x00\x00\x00\x00\x11\x89e\xf0\x00\x00\x00\x00\x12yH\xe0\x00\x00\x00\x00\x13iG\xf0\x00\x00\x00\x00\x14Y*\xe0\x00\x00\x00\x00\x15I)\xf0\x00\x00\x00\x00\x169\x0c\xe0\x00\x00\x00\x00\x17)\x0b\xf0\x00\x00\x00\x00\x18\x22)`\x00\x00\x00\x00\x19\x08\xed\xf0\x00\x00\x00\x00\x1a\x02\x0b`\x00\x00\x00\x00\x1a\xf2\x0ap\x00\x00\x00\x00\x1b\xe1\xed`\x00\x00\x00\x00\x1c\xd1\xecp\x00\x00\x00\x00\x1d\xc1\xcf`\x00\x00\x00\x00\x1e\xb1\xcep\x00\x00\x00\x00\x1f\xa1\xb1`\x00\x00\x00\x00 v\x00\xf0\x00\x00\x00\x00!\x81\x93`\x00\x00\x00\x00\x22U\xe2\xf0\x00\x00\x00\x00#j\xaf\xe0\x00\x00\x00\x00$5\xc4\xf0\x00\x00\x00\x00%J\x91\xe0\x00\x00\x00\x00&\x15\xa6\xf0\x00\x00\x00\x00'*s\xe0\x00\x00\x00\x00'\xfe\xc3p\x00\x00\x00\x00)\x0aU\xe0\x00\x00\x00\x00)\xde\xa5p\x00\x00\x00\x00*\xea7\xe0\x00\x00\x00\x00+\xbe\x87p\x00\x00\x00\x00,\xd3T`\x00\x00\x00\x00-\x9eip\x00\x00\x00\x00.\xb36`\x00\x00\x00\x00/~Kp\x00\x00\x00\x000\x93\x18`\x00\x00\x00\x001gg\xf0\x00\x00\x00\x002r\xfa`\x00\x00\x00\x003GI\xf0\x00\x00\x00\x004R\xdc`\x00\x00\x00\x005'+\xf0\x00\x00\x00\x0062\xbe`\x00\x00\x00\x007\x07\x0d\xf0\x00\x00\x00\x008\x1b\xda\xe0\x00\x00\x00\x008\xe6\xef\xf0\x00\x00\x00\x009\xfb\xbc\xe0\x00\x00\x00\x00:\xc6\xd1\xf0\x00\x00\x00\x00;\xdb\x9e\xe0\x00\x00\x00\x00<\xaf\xeep\x00\x00\x00\x00=\xbb\x80\xe0\x00\x00\x00\x00>\x8f\xd0p\x00\x00\x00\x00?\x9bb\xe0\x00\x00\x00\x00@o\xb2p\x00\x00\x00\x00A\x84\x7f`\x00\x00\x00\x00BO\x94p\x00\x00\x00\x00Cda`\x00\x00\x00\x00D/vp\x00\x00\x00\x00EDC`\x00\x00\x00\x00E\xf3\xa8\xf0\x01\x02\x03\x04\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\x02\x05\xff\xff\xb2%\x00\x00\xff\xff\xab\xa0\x00\x04\xff\xff\xb9\xb0\x00\x08\xff\xff\xc7\xc0\x01\x0c\xff\xff\xc7\xc0\x01\x10\xff\xff\xc7\xc0\x01\x14LMT\x00CST\x00EST\x00EWT\x00EPT\x00EDT\x00\x0aEST5EDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x80\x94@\x12\x04\x00\x00\x12\x04\x00\x00\x0b\x00\x00\x00US/MountainTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^\x04\x0c\xb0\xff\xff\xff\xff\x9e\xa6:\x90\xff\xff\xff\xff\x9f\xbb\x07\x80\xff\xff\xff\xff\xa0\x86\x1c\x90\xff\xff\xff\xff\xa1\x9a\xe9\x80\xff\xff\xff\xff\xa2e\xfe\x90\xff\xff\xff\xff\xa3\x84\x06\x00\xff\xff\xff\xff\xa4E\xe0\x90\xff\xff\xff\xff\xa4\x8f\xa6\x80\xff\xff\xff\xff\xcb\x89\x0c\x90\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a\x18\x00\xff\xff\xff\xff\xf7/v\x90\xff\xff\xff\xff\xf8(\x94\x00\xff\xff\xff\xff\xf9\x0fX\x90\xff\xff\xff\xff\xfa\x08v\x00\xff\xff\xff\xff\xfa\xf8u\x10\xff\xff\xff\xff\xfb\xe8X\x00\xff\xff\xff\xff\xfc\xd8W\x10\xff\xff\xff\xff\xfd\xc8:\x00\xff\xff\xff\xff\xfe\xb89\x10\xff\xff\xff\xff\xff\xa8\x1c\x00\x00\x00\x00\x00\x00\x98\x1b\x10\x00\x00\x00\x00\x01\x87\xfe\x00\x00\x00\x00\x00\x02w\xfd\x10\x00\x00\x00\x00\x03q\x1a\x80\x00\x00\x00\x00\x04a\x19\x90\x00\x00\x00\x00\x05P\xfc\x80\x00\x00\x00\x00\x06@\xfb\x90\x00\x00\x00\x00\x070\xde\x80\x00\x00\x00\x00\x07\x8d5\x90\x00\x00\x00\x00\x09\x10\xc0\x80\x00\x00\x00\x00\x09\xad\xb1\x10\x00\x00\x00\x00\x0a\xf0\xa2\x80\x00\x00\x00\x00\x0b\xe0\xa1\x90\x00\x00\x00\x00\x0c\xd9\xbf\x00\x00\x00\x00\x00\x0d\xc0\x83\x90\x00\x00\x00\x00\x0e\xb9\xa1\x00\x00\x00\x00\x00\x0f\xa9\xa0\x10\x00\x00\x00\x00\x10\x99\x83\x00\x00\x00\x00\x00\x11\x89\x82\x10\x00\x00\x00\x00\x12ye\x00\x00\x00\x00\x00\x13id\x10\x00\x00\x00\x00\x14YG\x00\x00\x00\x00\x00\x15IF\x10\x00\x00\x00\x00\x169)\x00\x00\x00\x00\x00\x17)(\x10\x00\x00\x00\x00\x18\x22E\x80\x00\x00\x00\x00\x19\x09\x0a\x10\x00\x00\x00\x00\x1a\x02'\x80\x00\x00\x00\x00\x1a\xf2&\x90\x00\x00\x00\x00\x1b\xe2\x09\x80\x00\x00\x00\x00\x1c\xd2\x08\x90\x00\x00\x00\x00\x1d\xc1\xeb\x80\x00\x00\x00\x00\x1e\xb1\xea\x90\x00\x00\x00\x00\x1f\xa1\xcd\x80\x00\x00\x00\x00 v\x1d\x10\x00\x00\x00\x00!\x81\xaf\x80\x00\x00\x00\x00\x22U\xff\x10\x00\x00\x00\x00#j\xcc\x00\x00\x00\x00\x00$5\xe1\x10\x00\x00\x00\x00%J\xae\x00\x00\x00\x00\x00&\x15\xc3\x10\x00\x00\x00\x00'*\x90\x00\x00\x00\x00\x00'\xfe\xdf\x90\x00\x00\x00\x00)\x0ar\x00\x00\x00\x00\x00)\xde\xc1\x90\x00\x00\x00\x00*\xeaT\x00\x00\x00\x00\x00+\xbe\xa3\x90\x00\x00\x00\x00,\xd3p\x80\x00\x00\x00\x00-\x9e\x85\x90\x00\x00\x00\x00.\xb3R\x80\x00\x00\x00\x00/~g\x90\x00\x00\x00\x000\x934\x80\x00\x00\x00\x001g\x84\x10\x00\x00\x00\x002s\x16\x80\x00\x00\x00\x003Gf\x10\x00\x00\x00\x004R\xf8\x80\x00\x00\x00\x005'H\x10\x00\x00\x00\x0062\xda\x80\x00\x00\x00\x007\x07*\x10\x00\x00\x00\x008\x1b\xf7\x00\x00\x00\x00\x008\xe7\x0c\x10\x00\x00\x00\x009\xfb\xd9\x00\x00\x00\x00\x00:\xc6\xee\x10\x00\x00\x00\x00;\xdb\xbb\x00\x00\x00\x00\x00<\xb0\x0a\x90\x00\x00\x00\x00=\xbb\x9d\x00\x00\x00\x00\x00>\x8f\xec\x90\x00\x00\x00\x00?\x9b\x7f\x00\x00\x00\x00\x00@o\xce\x90\x00\x00\x00\x00A\x84\x9b\x80\x00\x00\x00\x00BO\xb0\x90\x00\x00\x00\x00Cd}\x80\x00\x00\x00\x00D/\x92\x90\x00\x00\x00\x00ED_\x80\x00\x00\x00\x00E\xf3\xc5\x10\x02\x01\x02\x01\x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x9d\x94\x00\x00\xff\xff\xab\xa0\x01\x04\xff\xff\x9d\x90\x00\x08\xff\xff\xab\xa0\x01\x0c\xff\xff\xab\xa0\x01\x10LMT\x00MDT\x00MST\x00MWT\x00MPT\x00\x0aMST7MDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x22\x12\xfe\x0e\x05\x00\x00\x0e\x05\x00\x00\x0a\x00\x00\x00US/PacificTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\x00\x00\x00\x05\x00\x00\x00\x14\xff\xff\xff\xff^\x04\x1a\xc0\xff\xff\xff\xff\x9e\xa6H\xa0\xff\xff\xff\xff\x9f\xbb\x15\x90\xff\xff\xff\xff\xa0\x86*\xa0\xff\xff\xff\xff\xa1\x9a\xf7\x90\xff\xff\xff\xff\xcb\x89\x1a\xa0\xff\xff\xff\xff\xd2#\xf4p\xff\xff\xff\xff\xd2a&\x10\xff\xff\xff\xff\xd6\xfet\x5c\xff\xff\xff\xff\xd8\x80\xad\x90\xff\xff\xff\xff\xda\xfe\xc3\x90\xff\xff\xff\xff\xdb\xc0\x90\x10\xff\xff\xff\xff\xdc\xde\xa5\x90\xff\xff\xff\xff\xdd\xa9\xac\x90\xff\xff\xff\xff\xde\xbe\x87\x90\xff\xff\xff\xff\xdf\x89\x8e\x90\xff\xff\xff\xff\xe0\x9ei\x90\xff\xff\xff\xff\xe1ip\x90\xff\xff\xff\xff\xe2~K\x90\xff\xff\xff\xff\xe3IR\x90\xff\xff\xff\xff\xe4^-\x90\xff\xff\xff\xff\xe5)4\x90\xff\xff\xff\xff\xe6GJ\x10\xff\xff\xff\xff\xe7\x12Q\x10\xff\xff\xff\xff\xe8',\x10\xff\xff\xff\xff\xe8\xf23\x10\xff\xff\xff\xff\xea\x07\x0e\x10\xff\xff\xff\xff\xea\xd2\x15\x10\xff\xff\xff\xff\xeb\xe6\xf0\x10\xff\xff\xff\xff\xec\xb1\xf7\x10\xff\xff\xff\xff\xed\xc6\xd2\x10\xff\xff\xff\xff\xee\x91\xd9\x10\xff\xff\xff\xff\xef\xaf\xee\x90\xff\xff\xff\xff\xf0q\xbb\x10\xff\xff\xff\xff\xf1\x8f\xd0\x90\xff\xff\xff\xff\xf2\x7f\xc1\x90\xff\xff\xff\xff\xf3o\xb2\x90\xff\xff\xff\xff\xf4_\xa3\x90\xff\xff\xff\xff\xf5O\x94\x90\xff\xff\xff\xff\xf6?\x85\x90\xff\xff\xff\xff\xf7/v\x90\xff\xff\xff\xff\xf8(\xa2\x10\xff\xff\xff\xff\xf9\x0fX\x90\xff\xff\xff\xff\xfa\x08\x84\x10\xff\xff\xff\xff\xfa\xf8\x83 \xff\xff\xff\xff\xfb\xe8f\x10\xff\xff\xff\xff\xfc\xd8e \xff\xff\xff\xff\xfd\xc8H\x10\xff\xff\xff\xff\xfe\xb8G \xff\xff\xff\xff\xff\xa8*\x10\x00\x00\x00\x00\x00\x98) \x00\x00\x00\x00\x01\x88\x0c\x10\x00\x00\x00\x00\x02x\x0b \x00\x00\x00\x00\x03q(\x90\x00\x00\x00\x00\x04a'\xa0\x00\x00\x00\x00\x05Q\x0a\x90\x00\x00\x00\x00\x06A\x09\xa0\x00\x00\x00\x00\x070\xec\x90\x00\x00\x00\x00\x07\x8dC\xa0\x00\x00\x00\x00\x09\x10\xce\x90\x00\x00\x00\x00\x09\xad\xbf \x00\x00\x00\x00\x0a\xf0\xb0\x90\x00\x00\x00\x00\x0b\xe0\xaf\xa0\x00\x00\x00\x00\x0c\xd9\xcd\x10\x00\x00\x00\x00\x0d\xc0\x91\xa0\x00\x00\x00\x00\x0e\xb9\xaf\x10\x00\x00\x00\x00\x0f\xa9\xae \x00\x00\x00\x00\x10\x99\x91\x10\x00\x00\x00\x00\x11\x89\x90 \x00\x00\x00\x00\x12ys\x10\x00\x00\x00\x00\x13ir \x00\x00\x00\x00\x14YU\x10\x00\x00\x00\x00\x15IT \x00\x00\x00\x00\x1697\x10\x00\x00\x00\x00\x17)6 \x00\x00\x00\x00\x18\x22S\x90\x00\x00\x00\x00\x19\x09\x18 \x00\x00\x00\x00\x1a\x025\x90\x00\x00\x00\x00\x1a\xf24\xa0\x00\x00\x00\x00\x1b\xe2\x17\x90\x00\x00\x00\x00\x1c\xd2\x16\xa0\x00\x00\x00\x00\x1d\xc1\xf9\x90\x00\x00\x00\x00\x1e\xb1\xf8\xa0\x00\x00\x00\x00\x1f\xa1\xdb\x90\x00\x00\x00\x00 v+ \x00\x00\x00\x00!\x81\xbd\x90\x00\x00\x00\x00\x22V\x0d \x00\x00\x00\x00#j\xda\x10\x00\x00\x00\x00$5\xef \x00\x00\x00\x00%J\xbc\x10\x00\x00\x00\x00&\x15\xd1 \x00\x00\x00\x00'*\x9e\x10\x00\x00\x00\x00'\xfe\xed\xa0\x00\x00\x00\x00)\x0a\x80\x10\x00\x00\x00\x00)\xde\xcf\xa0\x00\x00\x00\x00*\xeab\x10\x00\x00\x00\x00+\xbe\xb1\xa0\x00\x00\x00\x00,\xd3~\x90\x00\x00\x00\x00-\x9e\x93\xa0\x00\x00\x00\x00.\xb3`\x90\x00\x00\x00\x00/~u\xa0\x00\x00\x00\x000\x93B\x90\x00\x00\x00\x001g\x92 \x00\x00\x00\x002s$\x90\x00\x00\x00\x003Gt \x00\x00\x00\x004S\x06\x90\x00\x00\x00\x005'V \x00\x00\x00\x0062\xe8\x90\x00\x00\x00\x007\x078 \x00\x00\x00\x008\x1c\x05\x10\x00\x00\x00\x008\xe7\x1a \x00\x00\x00\x009\xfb\xe7\x10\x00\x00\x00\x00:\xc6\xfc \x00\x00\x00\x00;\xdb\xc9\x10\x00\x00\x00\x00<\xb0\x18\xa0\x00\x00\x00\x00=\xbb\xab\x10\x00\x00\x00\x00>\x8f\xfa\xa0\x00\x00\x00\x00?\x9b\x8d\x10\x00\x00\x00\x00@o\xdc\xa0\x00\x00\x00\x00A\x84\xa9\x90\x00\x00\x00\x00BO\xbe\xa0\x00\x00\x00\x00Cd\x8b\x90\x00\x00\x00\x00D/\xa0\xa0\x00\x00\x00\x00EDm\x90\x00\x00\x00\x00E\xf3\xd3 \x02\x01\x02\x01\x02\x03\x04\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\x02\x01\xff\xff\x91&\x00\x00\xff\xff\x9d\x90\x01\x04\xff\xff\x8f\x80\x00\x08\xff\xff\x9d\x90\x01\x0c\xff\xff\x9d\x90\x01\x10LMT\x00PDT\x00PST\x00PWT\x00PPT\x00\x0aPST8PDT,M3.2.0,M11.1.0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x08\x00\x00\x00US/SamoaTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x08\xff\xff\xff\xffn=\xc8\x08\xff\xff\xff\xff\x91\x05\xfb\x08\x01\x02\x00\x00\xb1x\x00\x00\xff\xff_\xf8\x00\x00\xff\xffeP\x00\x04LMT\x00SST\x00\x0aSST11\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00UTCTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00UTC\x00\x0aUTC0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00UniversalTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00UTC\x00\x0aUTC0\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe1\xc1\xeb\x05\x8c\x03\x00\x00\x8c\x03\x00\x00\x04\x00\x00\x00W-SUTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00N\x00\x00\x00\x0b\x00\x00\x00&\xff\xff\xff\xffV\xb6\xc0\xc7\xff\xff\xff\xff\x9b_\x1e\xc7\xff\xff\xff\xff\x9d>\xf2y\xff\xff\xff\xff\x9e*\xee\xf9\xff\xff\xff\xff\x9e\xf79i\xff\xff\xff\xff\x9f\x84W\xf9\xff\xff\xff\xff\xa0\xd8l\xe9\xff\xff\xff\xff\xa1\x009\x80\xff\xff\xff\xff\xa1<\xa6@\xff\xff\xff\xff\xa4\x10m\xc0\xff\xff\xff\xff\xa4=2\xb0\xff\xff\xff\xff\xa5\x15h\xb0\xff\xff\xff\xff\xa5=\x03\xc0\xff\xff\xff\xff\xa7\x1eEP\xff\xff\xff\xff\xb5\xa4\x19`\x00\x00\x00\x00\x15'\xa7\xd0\x00\x00\x00\x00\x16\x18\xdc@\x00\x00\x00\x00\x17\x08\xdbP\x00\x00\x00\x00\x17\xfa\x0f\xc0\x00\x00\x00\x00\x18\xea\x0e\xd0\x00\x00\x00\x00\x19\xdbC@\x00\x00\x00\x00\x1a\xcc\x93\xd0\x00\x00\x00\x00\x1b\xbc\xa0\xf0\x00\x00\x00\x00\x1c\xac\x91\xf0\x00\x00\x00\x00\x1d\x9c\x82\xf0\x00\x00\x00\x00\x1e\x8cs\xf0\x00\x00\x00\x00\x1f|d\xf0\x00\x00\x00\x00 lU\xf0\x00\x00\x00\x00!\x5cF\xf0\x00\x00\x00\x00\x22L7\xf0\x00\x00\x00\x00#<(\xf0\x00\x00\x00\x00$,\x19\xf0\x00\x00\x00\x00%\x1c\x0a\xf0\x00\x00\x00\x00&\x0b\xfb\xf0\x00\x00\x00\x00'\x05'p\x00\x00\x00\x00'\xf5\x18p\x00\x00\x00\x00(\xe5\x17\x80\x00\x00\x00\x00)x\xbf\x80\x00\x00\x00\x00)\xd4\xfap\x00\x00\x00\x00*\xc4\xebp\x00\x00\x00\x00+\xb4\xdcp\x00\x00\x00\x00,\xa4\xcdp\x00\x00\x00\x00-\x94\xbep\x00\x00\x00\x00.\x84\xafp\x00\x00\x00\x00/t\xa0p\x00\x00\x00\x000d\x91p\x00\x00\x00\x001]\xbc\xf0\x00\x00\x00\x002r\x97\xf0\x00\x00\x00\x003=\x9e\xf0\x00\x00\x00\x004Ry\xf0\x00\x00\x00\x005\x1d\x80\xf0\x00\x00\x00\x0062[\xf0\x00\x00\x00\x006\xfdb\xf0\x00\x00\x00\x008\x1bxp\x00\x00\x00\x008\xddD\xf0\x00\x00\x00\x009\xfbZp\x00\x00\x00\x00:\xbd&\xf0\x00\x00\x00\x00;\xdb\x86%p\x00\x00\x00\x00?\x9b\x00p\x00\x00\x00\x00@f\x07p\x00\x00\x00\x00A\x84\x1c\xf0\x00\x00\x00\x00BE\xe9p\x00\x00\x00\x00Cc\xfe\xf0\x00\x00\x00\x00D%\xcbp\x00\x00\x00\x00EC\xe0\xf0\x00\x00\x00\x00F\x05\xadp\x00\x00\x00\x00G#\xc2\xf0\x00\x00\x00\x00G\xee\xc9\xf0\x00\x00\x00\x00I\x03\xa4\xf0\x00\x00\x00\x00I\xce\xab\xf0\x00\x00\x00\x00J\xe3\x86\xf0\x00\x00\x00\x00K\xae\x8d\xf0\x00\x00\x00\x00L\xcc\xa3p\x00\x00\x00\x00M\x8eo\xf0\x00\x00\x00\x00TL\x1d`\x01\x03\x02\x03\x04\x02\x04\x05\x06\x05\x07\x05\x06\x08\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x09\x08\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x05\x06\x0a\x06\x00\x00#9\x00\x00\x00\x00#9\x00\x04\x00\x001\x87\x01\x08\x00\x00#w\x00\x04\x00\x00?\x97\x01\x0c\x00\x008@\x01\x11\x00\x00*0\x00\x15\x00\x00FP\x01\x19\x00\x00\x1c \x00\x1d\x00\x00*0\x01!\x00\x008@\x00\x15LMT\x00MMT\x00MST\x00MDST\x00MSD\x00MSK\x00+05\x00EET\x00EEST\x00\x0aMSK-3\x0aPK\x03\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x91B\xc0\xee\x01\x00\x00\xee\x01\x00\x00\x03\x00\x00\x00WETTZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00TZif2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x00\x00\x00\x02\x00\x00\x00\x09\x00\x00\x00\x00\x0d\xa4c\x90\x00\x00\x00\x00\x0e\x8b\x1a\x10\x00\x00\x00\x00\x0f\x84E\x90\x00\x00\x00\x00\x10t6\x90\x00\x00\x00\x00\x11d'\x90\x00\x00\x00\x00\x12T\x18\x90\x00\x00\x00\x00\x13MD\x10\x00\x00\x00\x00\x143\xfa\x90\x00\x00\x00\x00\x15#\xeb\x90\x00\x00\x00\x00\x16\x13\xdc\x90\x00\x00\x00\x00\x17\x03\xcd\x90\x00\x00\x00\x00\x17\xf3\xbe\x90\x00\x00\x00\x00\x18\xe3\xaf\x90\x00\x00\x00\x00\x19\xd3\xa0\x90\x00\x00\x00\x00\x1a\xc3\x91\x90\x00\x00\x00\x00\x1b\xbc\xbd\x10\x00\x00\x00\x00\x1c\xac\xae\x10\x00\x00\x00\x00\x1d\x9c\x9f\x10\x00\x00\x00\x00\x1e\x8c\x90\x10\x00\x00\x00\x00\x1f|\x81\x10\x00\x00\x00\x00 lr\x10\x00\x00\x00\x00!\x5cc\x10\x00\x00\x00\x00\x22LT\x10\x00\x00\x00\x00#\xd5\xe0\x95\x00\x00\x00\x95\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\x08\x00\x00Africa/BissauPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x09\x00\x00Africa/BlantyrePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x09\x00\x00Africa/BrazzavillePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x0a\x00\x00Africa/BujumburaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5#)\x16\x1d\x05\x00\x00\x1d\x05\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x0b\x00\x00Africa/CairoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001B\xb0;\x7f\x07\x00\x00\x7f\x07\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4\x10\x00\x00Africa/CasablancaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f\x1b\xeb\xdd2\x02\x00\x002\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x18\x00\x00Africa/CeutaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae\x1a\x00\x00Africa/ConakryPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5c\x1b\x00\x00Africa/DakarPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x1c\x00\x00Africa/Dar_es_SalaamPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf9\x1c\x00\x00Africa/DjiboutiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5\x1d\x00\x00Africa/DoualaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\xd3\xc6g&\x07\x00\x00&\x07\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc4\x1e\x00\x00Africa/El_AaiunPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17&\x00\x00Africa/FreetownPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6&\x00\x00Africa/GaboronePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00v'\x00\x00Africa/HararePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcc\x0cT\xce\xbe\x00\x00\x00\xbe\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$(\x00\x00Africa/JohannesburgPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\xcf\x10n\xca\x01\x00\x00\xca\x01\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13)\x00\x00Africa/JubaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06+\x00\x00Africa/KampalaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\xadD\xef\xca\x01\x00\x00\xca\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1+\x00\x00Africa/KhartoumPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8-\x00\x00Africa/KigaliPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96.\x00\x00Africa/KinshasaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00w/\x00\x00Africa/LagosPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U0\x00\x00Africa/LibrevillePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0081\x00\x00Africa/LomePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe31\x00\x00Africa/LuandaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc22\x00\x00Africa/LubumbashiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t3\x00\x00Africa/LusakaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x224\x00\x00Africa/MalaboPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x1b\xb0_\x83\x00\x00\x00\x83\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x015\x00\x00Africa/MaputoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcc\x0cT\xce\xbe\x00\x00\x00\xbe\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf5\x00\x00Africa/MaseruPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcc\x0cT\xce\xbe\x00\x00\x00\xbe\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x986\x00\x00Africa/MbabanePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x827\x00\x00Africa/MogadishuPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\x99rU\xa4\x00\x00\x00\xa4\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o8\x00\x00Africa/MonroviaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@9\x00\x00Africa/NairobiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa\x81\x09\x03\xa0\x00\x00\x00\xa0\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+:\x00\x00Africa/NdjamenaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8:\x00\x00Africa/NiameyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd7;\x00\x00Africa/NouakchottPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88<\x00\x00Africa/OuagadougouPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x1d\xb3c\xb4\x00\x00\x00\xb4\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:=\x00\x00Africa/Porto-NovoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc1\x0a\x8a\x84\xad\x00\x00\x00\xad\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d>\x00\x00Africa/Sao_TomePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf7>\x00\x00Africa/TimbuktuPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\x7f2[\xaf\x01\x00\x00\xaf\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6?\x00\x00Africa/TripoliPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x93\xf4\x94\x0b\xc1\x01\x00\x00\xc1\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81A\x00\x00Africa/TunisPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00m)\xb8P~\x02\x00\x00~\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00lC\x00\x00Africa/WindhoekPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae,\xa44\xc9\x03\x00\x00\xc9\x03\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17F\x00\x00America/AdakPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x11Q\x06\xd1\x03\x00\x00\xd1\x03\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0aJ\x00\x00America/AnchoragePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0aN\x00\x00America/AnguillaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe9N\x00\x00America/AntiguaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x01V\x0dP\x02\x00\x00P\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7O\x00\x00America/AraguainaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\xbf\xf5\xe5\xc4\x02\x00\x00\xc4\x02\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FR\x00\x00America/Argentina/Buenos_AiresPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\xc8\xd9\xf6\xc4\x02\x00\x00\xc4\x02\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FU\x00\x00America/Argentina/CatamarcaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\xc8\xd9\xf6\xc4\x02\x00\x00\xc4\x02\x00\x00 \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00CX\x00\x00America/Argentina/ComodRivadaviaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef\xf0R\x8a\xc4\x02\x00\x00\xc4\x02\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E[\x00\x00America/Argentina/CordobaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00utZ\x1a\xb2\x02\x00\x00\xb2\x02\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@^\x00\x00America/Argentina/JujuyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00m\x07D\x0e\xcd\x02\x00\x00\xcd\x02\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'a\x00\x00America/Argentina/La_RiojaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\x92Z\x8c\xc4\x02\x00\x00\xc4\x02\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,d\x00\x00America/Argentina/MendozaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8ep\xb4c\xc4\x02\x00\x00\xc4\x02\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'g\x00\x00America/Argentina/Rio_GallegosPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t*\x9b!\xb2\x02\x00\x00\xb2\x02\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'j\x00\x00America/Argentina/SaltaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfcz=\xe1\xcd\x02\x00\x00\xcd\x02\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0em\x00\x00America/Argentina/San_JuanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\x80\xb9\x5c\xcd\x02\x00\x00\xcd\x02\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13p\x00\x00America/Argentina/San_LuisPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd8\xd6\xad\xd6\x02\x00\x00\xd6\x02\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18s\x00\x00America/Argentina/TucumanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8b}\xb6\x1e\xc4\x02\x00\x00\xc4\x02\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%v\x00\x00America/Argentina/UshuaiaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 y\x00\x00America/ArubaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d\xa9y\x9at\x03\x00\x00t\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfcy\x00\x00America/AsuncionPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4\xbe\xe7#\x95\x00\x00\x00\x95\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9e}\x00\x00America/AtikokanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae,\xa44\xc9\x03\x00\x00\xc9\x03\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a~\x00\x00America/AtkaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00OKj\xc7\xaa\x02\x00\x00\xaa\x02\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x82\x00\x00America/BahiaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x0e\x01n\xd8\x02\x00\x00\xd8\x02\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\x85\x00\x00America/Bahia_BanderasPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00l=\xad\xbe\x16\x01\x00\x00\x16\x01\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x88\x00\x00America/BarbadosPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85-\xb9\xf8\x8a\x01\x00\x00\x8a\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00y\x89\x00\x00America/BelemPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x89\xd8\xba\xee\x15\x04\x00\x00\x15\x04\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.\x8b\x00\x00America/BelizePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o\x8f\x00\x00America/Blanc-SablonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8Dz\x97\xae\x01\x00\x00\xae\x01\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x90\x00\x00America/Boa_VistaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,g\xec\xec\xb3\x00\x00\x00\xb3\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/\x92\x00\x00America/BogotaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.\xbe\x1a>\xe7\x03\x00\x00\xe7\x03\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x93\x00\x00America/BoisePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\xbf\xf5\xe5\xc4\x02\x00\x00\xc4\x02\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x97\x00\x00America/Buenos_AiresPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\xba\xb2\x94s\x03\x00\x00s\x03\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16\x9a\x00\x00America/Cambridge_BayPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\xfbn\xdb\xb8\x03\x00\x00\xb8\x03\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbc\x9d\x00\x00America/Campo_GrandePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf2\x04\xde\xdd\x11\x02\x00\x00\x11\x02\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\xa1\x00\x00America/CancunPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x8e\xee\x13\xbe\x00\x00\x00\xbe\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe3\xa3\x00\x00America/CaracasPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\xc8\xd9\xf6\xc4\x02\x00\x00\xc4\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\xa4\x00\x00America/CatamarcaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1'\x07\xbd\x97\x00\x00\x00\x97\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc1\xa7\x00\x00America/CayennePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4\xbe\xe7#\x95\x00\x00\x00\x95\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85\xa8\x00\x00America/CaymanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xdc\xa9=\xda\x06\x00\x00\xda\x06\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F\xa9\x00\x00America/ChicagoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x111\x04q\xb3\x02\x00\x00\xb3\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M\xb0\x00\x00America/ChihuahuaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xad\xf2L\x06\xce\x02\x00\x00\xce\x02\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/\xb3\x00\x00America/Ciudad_JuarezPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4\xbe\xe7#\x95\x00\x00\x00\x95\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000\xb6\x00\x00America/Coral_HarbourPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef\xf0R\x8a\xc4\x02\x00\x00\xc4\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\xb6\x00\x00America/CordobaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb1\xdd\x82x\xe8\x00\x00\x00\xe8\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe9\xb9\x00\x00America/Costa_RicaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\xb8\xab\x9b\xf0\x00\x00\x00\xf0\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xbb\x00\x00America/CrestonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f$*\xa0\xa6\x03\x00\x00\xa6\x03\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\xbc\x00\x00America/CuiabaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xbf\x00\x00America/CuracaoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00k\xc2\x0dx\xbf\x01\x00\x00\xbf\x01\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\xc0\x00\x00America/DanmarkshavnPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xe6\xf5J\x05\x04\x00\x00\x05\x04\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\xc2\x00\x00America/DawsonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x10`\xc8\xab\x02\x00\x00\xab\x02\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xc6\x00\x00America/Dawson_CreekPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x80\x94@\x12\x04\x00\x00\x12\x04\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xc9\x00\x00America/DenverPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x14\xe7\x03\x83\x03\x00\x00\x83\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\xce\x00\x00America/DetroitPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbb\xd1\x00\x00America/DominicaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\x07\x07\xdc\xca\x03\x00\x00\xca\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\xd2\x00\x00America/EdmontonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\xb0\xeau\xb4\x01\x00\x00\xb4\x01\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x92\xd6\x00\x00America/EirunepePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xea$\xc1\xbf\xb0\x00\x00\x00\xb0\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xd8\x00\x00America/El_SalvadorPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\xd9\x00\x00America/EnsenadaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6@\x0dm\xa8\x05\x00\x00\xa8\x05\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x84\xdd\x00\x00America/Fort_NelsonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xb6{\xc9\x13\x02\x00\x00\x13\x02\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\xe3\x00\x00America/Fort_WaynePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x11Z\xde\xe4\x01\x00\x00\xe4\x01\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa0\xe5\x00\x00America/FortalezaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M\x94\xc7Kp\x03\x00\x00p\x03\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb3\xe7\x00\x00America/Glace_BayPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xf9v\x14\xc5\x03\x00\x00\xc5\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\xeb\x00\x00America/GodthabPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdb\x85\xf6\xd1,\x06\x00\x00,\x06\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D\xef\x00\x00America/Goose_BayPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe3\xc9I\xd0U\x03\x00\x00U\x03\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f\xf5\x00\x00America/Grand_TurkPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\xf9\x00\x00America/GrenadaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xfa\x00\x00America/GuadeloupePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x8a\x83S\xd4\x00\x00\x00\xd4\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe3\xfa\x00\x00America/GuatemalaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcd\xc3v\xe3\xb3\x00\x00\x00\xb3\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\xfb\x00\x00America/GuayaquilPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x05\xf3\x89\xb5\x00\x00\x00\xb5\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\xfc\x00\x00America/GuyanaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00):\x17-\x88\x06\x00\x00\x88\x06\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9\xfd\x00\x00America/HalifaxPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x1c\x9e\x9a]\x04\x00\x00]\x04\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00^\x04\x01\x00America/HavanaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4MS\x99\x1e\x01\x00\x00\x1e\x01\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7\x08\x01\x00America/HermosilloPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xb6{\xc9\x13\x02\x00\x00\x13\x02\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x0a\x01\x00America/Indiana/IndianapolisPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$ \x873\xf8\x03\x00\x00\xf8\x03\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x0c\x01\x00America/Indiana/KnoxPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M/U\x9f7\x02\x00\x007\x02\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\x10\x01\x00America/Indiana/MarengoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xd8N\x8c\xab\x02\x00\x00\xab\x02\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\x13\x01\x00America/Indiana/PetersburgPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd8\xb5K\xa6\x0a\x02\x00\x00\x0a\x02\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfb\x15\x01\x00America/Indiana/Tell_CityPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x17\x89}q\x01\x00\x00q\x01\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x18\x01\x00America/Indiana/VevayPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\xedsp.\x02\x00\x00.\x02\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x19\x01\x00America/Indiana/VincennesPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfdH\xb79[\x02\x00\x00[\x02\x00\x00\x17\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x1c\x01\x00America/Indiana/WinamacPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xb6{\xc9\x13\x02\x00\x00\x13\x02\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd5\x1e\x01\x00America/IndianapolisPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xbc\x09o1\x03\x00\x001\x03\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a!\x01\x00America/InuvikPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xa0\xd6\x05W\x03\x00\x00W\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00w$\x01\x00America/IqaluitPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%J\xd5\xebS\x01\x00\x00S\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfb'\x01\x00America/JamaicaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00utZ\x1a\xb2\x02\x00\x00\xb2\x02\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{)\x01\x00America/JujuyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xc9\x1c\xd4\xc6\x03\x00\x00\xc6\x03\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X,\x01\x00America/JuneauPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdf\xe5\x8d\xc4\xda\x04\x00\x00\xda\x04\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00J0\x01\x00America/Kentucky/LouisvillePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x1a|J\xcc\x03\x00\x00\xcc\x03\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]5\x01\x00America/Kentucky/MonticelloPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$ \x873\xf8\x03\x00\x00\xf8\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b9\x01\x00America/Knox_INPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87=\x01\x00America/KralendijkPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xad`\x12\xe9\xaa\x00\x00\x00\xaa\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h>\x01\x00America/La_PazPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe7\xa1\x87\x1b\x01\x00\x00\x1b\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>?\x01\x00America/LimaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x22\x12\xfe\x0e\x05\x00\x00\x0e\x05\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x83@\x01\x00America/Los_AngelesPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdf\xe5\x8d\xc4\xda\x04\x00\x00\xda\x04\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc2E\x01\x00America/LouisvillePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xccJ\x01\x00America/Lower_PrincesPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x8c\x8b\x92\xf6\x01\x00\x00\xf6\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0K\x01\x00America/MaceioPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5s\xb3\x5c'\x01\x00\x00'\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd2M\x01\x00America/ManaguaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\xcb'\xe9\x9c\x01\x00\x00\x9c\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&O\x01\x00America/ManausPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeeP\x01\x00America/MarigotPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x17j\xd2\xb2\x00\x00\x00\xb2\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xccQ\x01\x00America/MartiniquePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00y\xb7\xe2]\xb5\x01\x00\x00\xb5\x01\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaeR\x01\x00America/MatamorosPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xad=\x98\xce\x02\x00\x00\xce\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x92T\x01\x00America/MazatlanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\x92Z\x8c\xc4\x02\x00\x00\xc4\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8eW\x01\x00America/MendozaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008O:\xbf\x95\x03\x00\x00\x95\x03\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7fZ\x01\x00America/MenomineePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xbd\x809\x8e\x02\x00\x00\x8e\x02\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C^\x01\x00America/MeridaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x87n\x14J\x02\x00\x00J\x02\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfd`\x01\x00America/MetlakatlaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd5\x08\x89\x8c\x05\x03\x00\x00\x05\x03\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00wc\x01\x00America/Mexico_CityPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\xea\x94Y&\x02\x00\x00&\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xadf\x01\x00America/MiquelonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xad\x8a\xf3O\xd5\x05\x00\x00\xd5\x05\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01i\x01\x00America/MonctonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L+\xe3u\x84\x02\x00\x00\x84\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03o\x01\x00America/MonterreyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\x98\x00\x08\xc9\x03\x00\x00\xc9\x03\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6q\x01\x00America/MontevideoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xafu\x01\x00America/MontrealPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x92|\x01\x00America/MontserratPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s}\x01\x00America/NassauPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x9aG\xc8\xd0\x06\x00\x00\xd0\x06\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x84\x01\x00America/New_YorkPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x8b\x01\x00America/NipigonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\xab\xd5\xf9\xcf\x03\x00\x00\xcf\x03\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x92\x01\x00America/NomePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7-2f\xe4\x01\x00\x00\xe4\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-\x96\x01\x00America/NoronhaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7.\xb6*\x13\x04\x00\x00\x13\x04\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x98\x01\x00America/North_Dakota/BeulahPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\xeam\xef\xde\x03\x00\x00\xde\x03\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a\x9c\x01\x00America/North_Dakota/CenterPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x1b\x8b(\xde\x03\x00\x00\xde\x03\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1\xa0\x01\x00America/North_Dakota/New_SalemPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xf9v\x14\xc5\x03\x00\x00\xc5\x03\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbb\xa4\x01\x00America/NuukPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1w\xb9\xca\xce\x02\x00\x00\xce\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa\xa8\x01\x00America/OjinagaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4\xbe\xe7#\x95\x00\x00\x00\x95\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xab\x01\x00America/PanamaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xa0\xd6\x05W\x03\x00\x00W\x03\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f\xac\x01\x00America/PangnirtungPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xf9\x1d\xc9\xbb\x00\x00\x00\xbb\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xee\xaf\x01\x00America/ParamariboPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\xb8\xab\x9b\xf0\x00\x00\x00\xf0\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xb0\x01\x00America/PhoenixPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4T\xbd\xeb5\x02\x00\x005\x02\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xb1\x01\x00America/Port-au-PrincePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\xb4\x01\x00America/Port_of_SpainPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xf5K\x89\xa2\x01\x00\x00\xa2\x01\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C\xb5\x01\x00America/Porto_AcrePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\x81-\xa9\x8a\x01\x00\x00\x8a\x01\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\xb7\x01\x00America/Porto_VelhoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd0\xb8\x01\x00America/Puerto_RicoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x13\x9b\xb1\xc2\x04\x00\x00\xc2\x04\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xb9\x01\x00America/Punta_ArenasPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?_p\x99\x0e\x05\x00\x00\x0e\x05\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\xbe\x01\x00America/Rainy_RiverPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xdfH\x0d'\x03\x00\x00'\x03\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5\xc3\x01\x00America/Rankin_InletPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\x03u\xf3\xe4\x01\x00\x00\xe4\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\xc7\x01\x00America/RecifePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc2\x96dK~\x02\x00\x00~\x02\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00N\xc9\x01\x00America/ReginaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0I~D'\x03\x00\x00'\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8\xcb\x01\x00America/ResolutePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xf5K\x89\xa2\x01\x00\x00\xa2\x01\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M\xcf\x01\x00America/Rio_BrancoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xef\xf0R\x8a\xc4\x02\x00\x00\xc4\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\xd1\x01\x00America/RosarioPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\xd4\x01\x00America/Santa_IsabelPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04,2h\x99\x01\x00\x00\x99\x01\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C\xd8\x01\x00America/SantaremPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x22_WJ\x05\x00\x00J\x05\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\xda\x01\x00America/SantiagoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x0f(\x08=\x01\x00\x00=\x01\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\xdf\x01\x00America/Santo_DomingoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9d?\xdf\xda\xb8\x03\x00\x00\xb8\x03\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf2\xe0\x01\x00America/Sao_PauloPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19a\x7f\x0a\xd8\x03\x00\x00\xd8\x03\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xe4\x01\x00America/ScoresbysundPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x80\x94@\x12\x04\x00\x00\x12\x04\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe3\xe8\x01\x00America/ShiprockPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81{\xc1\x92\xbc\x03\x00\x00\xbc\x03\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#\xed\x01\x00America/SitkaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0a\xf1\x01\x00America/St_BarthelemyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeah\x06\xd2V\x07\x00\x00V\x07\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xee\xf1\x01\x00America/St_JohnsPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00r\xf9\x01\x00America/St_KittsPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Q\xfa\x01\x00America/St_LuciaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000\xfb\x01\x00America/St_ThomasPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\xfc\x01\x00America/St_VincentPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\xd8\x19\x9dp\x01\x00\x00p\x01\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xfc\x01\x00America/Swift_CurrentPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\x13z\xe2\xc2\x00\x00\x00\xc2\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x94\xfe\x01\x00America/TegucigalpaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x0d\xf7\xd3\xc7\x01\x00\x00\xc7\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87\xff\x01\x00America/ThulePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00y\x01\x02\x00America/Thunder_BayPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\x08\x02\x00America/TijuanaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8d\x0c\x02\x00America/TorontoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o\x13\x02\x00America/TortolaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U9#\xbe2\x05\x00\x002\x05\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M\x14\x02\x00America/VancouverPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00q\xc9*;\xb1\x00\x00\x00\xb1\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae\x19\x02\x00America/VirginPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\x1d\xee\x91\x05\x04\x00\x00\x05\x04\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8b\x1a\x02\x00America/WhitehorsePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?_p\x99\x0e\x05\x00\x00\x0e\x05\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\x1e\x02\x00America/WinnipegPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,\xdb~\xab\xb2\x03\x00\x00\xb2\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc#\x02\x00America/YakutatPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\x07\x07\xdc\xca\x03\x00\x00\xca\x03\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdb'\x02\x00America/YellowknifePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8\x83\xf2b\x1f\x01\x00\x00\x1f\x01\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd6+\x02\x00Antarctica/CaseyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95\xea\x06\xd3\xc5\x00\x00\x00\xc5\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#-\x02\x00Antarctica/DavisPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x16.\x02\x00Antarctica/DumontDUrvillePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d?\xb2\x14\xd0\x03\x00\x00\xd0\x03\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7.\x02\x00Antarctica/MacquariePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd7N\xab\x8b\x98\x00\x00\x00\x98\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe92\x02\x00Antarctica/MawsonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb03\x02\x00Antarctica/McMurdoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95{\xf3\xa9w\x03\x00\x00w\x03\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf37\x02\x00Antarctica/PalmerPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6\x89\xf71\x84\x00\x00\x00\x84\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x99;\x02\x00Antarctica/RotheraPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00M<\x02\x00Antarctica/South_PolePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xd7\x87\xe1\x85\x00\x00\x00\x85\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x93@\x02\x00Antarctica/SyowaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf54\x89F\x9e\x00\x00\x00\x9e\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FA\x02\x00Antarctica/TrollPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x16\xf4\xe0\xaa\x00\x00\x00\xaa\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x12B\x02\x00Antarctica/VostokPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17S\x91\xb3\xc1\x02\x00\x00\xc1\x02\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xebB\x02\x00Arctic/LongyearbyenPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xd7\x87\xe1\x85\x00\x00\x00\x85\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xddE\x02\x00Asia/AdenPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c9f;j\x02\x00\x00j\x02\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x89F\x02\x00Asia/AlmatyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf\x0ds\xad\xa0\x03\x00\x00\xa0\x03\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1cI\x02\x00Asia/AmmanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\xe0\xe7!\xe7\x02\x00\x00\xe7\x02\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4L\x02\x00Asia/AnadyrPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x81\x18G^\x02\x00\x00^\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4O\x02\x00Asia/AqtauPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdb\xfa\xb5\xbeg\x02\x00\x00g\x02\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00zR\x02\x00Asia/AqtobePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\x1bb2w\x01\x00\x00w\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0aU\x02\x00Asia/AshgabatPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\x1bb2w\x01\x00\x00w\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xacV\x02\x00Asia/AshkhabadPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xa7^\xfah\x02\x00\x00h\x02\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00OX\x02\x00Asia/AtyrauPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd7e&uv\x02\x00\x00v\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0Z\x02\x00Asia/BaghdadPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdav\x19z\x98\x00\x00\x00\x98\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80]\x02\x00Asia/BahrainPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x87\xb3<\xe8\x02\x00\x00\xe8\x02\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B^\x02\x00Asia/BakuPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Qa\x02\x00Asia/BangkokPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87\xbd\xedL\xf1\x02\x00\x00\xf1\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13b\x02\x00Asia/BarnaulPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7\x11\xe1[\xdc\x02\x00\x00\xdc\x02\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.e\x02\x00Asia/BeirutPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000]*\x1bj\x02\x00\x00j\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003h\x02\x00Asia/BishkekPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7f^]@\x01\x00\x00@\x01\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7j\x02\x00Asia/BruneiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x1a\xdc\xca\xdc\x00\x00\x00\xdc\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000l\x02\x00Asia/CalcuttaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xab\xcd\xdf\x05\xee\x02\x00\x00\xee\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x007m\x02\x00Asia/ChitaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81z&\x80k\x02\x00\x00k\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Mp\x02\x00Asia/ChoibalsanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5r\x02\x00Asia/ChongqingPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9at\x02\x00Asia/ChungkingPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5c\x91\x87\xbb\xf7\x00\x00\x00\xf7\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Ov\x02\x00Asia/ColomboPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?Y\xaf\x19\xe7\x00\x00\x00\xe7\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00pw\x02\x00Asia/DaccaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87\x07\xeci\xd2\x04\x00\x00\xd2\x04\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7fx\x02\x00Asia/DamascusPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?Y\xaf\x19\xe7\x00\x00\x00\xe7\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00|}\x02\x00Asia/DhakaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x92\x1a\x8c\xaa\x00\x00\x00\xaa\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8b~\x02\x00Asia/DiliPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5c\x7f\x02\x00Asia/DubaiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00's\x96\x1en\x01\x00\x00n\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\x80\x02\x00Asia/DushanbePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]S\xbb\x12\xac\x03\x00\x00\xac\x03\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa2\x81\x02\x00Asia/FamagustaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\xae\xc2\xd6\x86\x0b\x00\x00\x86\x0b\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00z\x85\x02\x00Asia/GazaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\x91\x02\x00Asia/HarbinPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d2\x08\xd6\x98\x0b\x00\x00\x98\x0b\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\x92\x02\x00Asia/HebronPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8!YF\xec\x00\x00\x00\xec\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x9e\x02\x00Asia/Ho_Chi_MinhPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x09\xfa-\x07\x03\x00\x00\x07\x03\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x9f\x02\x00Asia/Hong_KongPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xba\xa3b\xc1R\x02\x00\x00R\x02\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7\xa2\x02\x00Asia/HovdPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf9l\x03\x12\xf8\x02\x00\x00\xf8\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\xa5\x02\x00Asia/IrkutskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07W\x10\xd1\xb0\x04\x00\x00\xb0\x04\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82\xa8\x02\x00Asia/IstanbulPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xad\xc5\xb1\xf8\x00\x00\x00\xf8\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\xad\x02\x00Asia/JakartaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00.>[K\xab\x00\x00\x00\xab\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xae\x02\x00Asia/JayapuraPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xe2\x9c\xb32\x04\x00\x002\x04\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\xaf\x02\x00Asia/JerusalemPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'\xe2\x5c\xff\x9f\x00\x00\x00\x9f\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb3\xb3\x02\x00Asia/KabulPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\x9cf>\xd7\x02\x00\x00\xd7\x02\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00z\xb4\x02\x00Asia/KamchatkaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009Y\xb7\xf1\x0a\x01\x00\x00\x0a\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xb7\x02\x00Asia/KarachiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x1d\xc6\x1b\x85\x00\x00\x00\x85\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb1\xb8\x02\x00Asia/KashgarPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8bSnT\xa1\x00\x00\x00\xa1\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\xb9\x02\x00Asia/KathmanduPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8bSnT\xa1\x00\x00\x00\xa1\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-\xba\x02\x00Asia/KatmanduPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x83g\x95M\x07\x03\x00\x00\x07\x03\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf9\xba\x02\x00Asia/KhandygaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x1a\xdc\xca\xdc\x00\x00\x00\xdc\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\xbe\x02\x00Asia/KolkataPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L\xe0\x91y\xe5\x02\x00\x00\xe5\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001\xbf\x02\x00Asia/KrasnoyarskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F7k\x1c\x00\x01\x00\x00\x00\x01\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D\xc2\x02\x00Asia/Kuala_LumpurPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7f^]@\x01\x00\x00@\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\xc3\x02\x00Asia/KuchingPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xd7\x87\xe1\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdd\xc4\x02\x00Asia/KuwaitPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d?v\x0c\x17\x03\x00\x00\x17\x03\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8b\xc5\x02\x00Asia/MacaoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d?v\x0c\x17\x03\x00\x00\x17\x03\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xc8\x02\x00Asia/MacauPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4_P\x18\xef\x02\x00\x00\xef\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09\xcc\x02\x00Asia/MagadanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\xc9\xd4\x5c\xbe\x00\x00\x00\xbe\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\xcf\x02\x00Asia/MakassarPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7\xaf\xdf\x1c\xee\x00\x00\x00\xee\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\xd0\x02\x00Asia/ManilaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\xd1\x02\x00Asia/MuscatPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1eX\xc3aU\x02\x00\x00U\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd0\xd1\x02\x00Asia/NicosiaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a\x9a\x90\xf7\xd6\x02\x00\x00\xd6\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O\xd4\x02\x00Asia/NovokuznetskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)p\x1cX\xf1\x02\x00\x00\xf1\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\xd7\x02\x00Asia/NovosibirskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:\x11\xea\xa2\xe5\x02\x00\x00\xe5\x02\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s\xda\x02\x00Asia/OmskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&\xe9\xd1\xd8q\x02\x00\x00q\x02\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\xdd\x02\x00Asia/OralPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xe0\x02\x00Asia/Phnom_PenhPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\xa5\x81e\xf7\x00\x00\x00\xf7\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdc\xe0\x02\x00Asia/PontianakPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a\xc1\x1eB\xb7\x00\x00\x00\xb7\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xe1\x02\x00Asia/PyongyangPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xdav\x19z\x98\x00\x00\x00\x98\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe2\xe2\x02\x00Asia/QatarPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb5\xc4\x8f\x9cp\x02\x00\x00p\x02\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa2\xe3\x02\x00Asia/QostanayPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd5\xce\x9cGp\x02\x00\x00p\x02\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\xe6\x02\x00Asia/QyzylordaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\x87{_\xbb\x00\x00\x00\xbb\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xe8\x02\x00Asia/RangoonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xd7\x87\xe1\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbe\xe9\x02\x00Asia/RiyadhPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8!YF\xec\x00\x00\x00\xec\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00l\xea\x02\x00Asia/SaigonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\x15II\xf3\x02\x00\x00\xf3\x02\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\xeb\x02\x00Asia/SakhalinPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00w\x0dD\x07n\x01\x00\x00n\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f\xee\x02\x00Asia/SamarkandPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7X,Y\x9f\x01\x00\x00\x9f\x01\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009\xf0\x02\x00Asia/SeoulPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf2\x02\x00Asia/ShanghaiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F7k\x1c\x00\x01\x00\x00\x00\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\xf3\x02\x00Asia/SingaporePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa4Z\xdf\x90\xe6\x02\x00\x00\xe6\x02\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\xf4\x02\x00Asia/SrednekolymskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xee\xf0BB\xff\x01\x00\x00\xff\x01\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xf7\x02\x00Asia/TaipeiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xe27Yn\x01\x00\x00n\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1e\xfa\x02\x00Asia/TashkentPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\xbe\xa8\xc7u\x02\x00\x00u\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\xfb\x02\x00Asia/TbilisiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\xdb?\xec,\x03\x00\x00,\x03\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\xfe\x02\x00Asia/TehranPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xe2\x9c\xb32\x04\x00\x002\x04\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xab\x01\x03\x00Asia/Tel_AvivPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j$\xcd\xf4\x9a\x00\x00\x00\x9a\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x08\x06\x03\x00Asia/ThimbuPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00j$\xcd\xf4\x9a\x00\x00\x00\x9a\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcb\x06\x03\x00Asia/ThimphuPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xf4\xaeg\xd5\x00\x00\x00\xd5\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8f\x07\x03\x00Asia/TokyoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00[u\x99q\xf1\x02\x00\x00\xf1\x02\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\x08\x03\x00Asia/TomskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`\xc9\xd4\x5c\xbe\x00\x00\x00\xbe\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\x0b\x03\x00Asia/Ujung_PandangPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xb9\xf4\xb6R\x02\x00\x00R\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x93\x0c\x03\x00Asia/UlaanbaatarPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xb9\xf4\xb6R\x02\x00\x00R\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x0f\x03\x00Asia/Ulan_BatorPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B\x1d\xc6\x1b\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x92\x11\x03\x00Asia/UrumqiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00w\x86\x8d^\x03\x03\x00\x00\x03\x03\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@\x12\x03\x00Asia/Ust-NeraPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x15\x03\x00Asia/VientianePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00d%\x05\xd8\xe6\x02\x00\x00\xe6\x02\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x16\x03\x00Asia/VladivostokPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O\xb0\x03\xe9\xe5\x02\x00\x00\xe5\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F\x19\x03\x00Asia/YakutskPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\x87{_\xbb\x00\x00\x00\xbb\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\x1c\x03\x00Asia/YangonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\xea\x18\xd4\xf8\x02\x00\x00\xf8\x02\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x009\x1d\x03\x00Asia/YekaterinburgPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x95-\xad\xc4\x02\x00\x00\xc4\x02\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a \x03\x00Asia/YerevanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\x8dY\x80\xad\x05\x00\x00\xad\x05\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O#\x03\x00Atlantic/AzoresPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00l&\x04\x99\x00\x04\x00\x00\x00\x04\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00))\x03\x00Atlantic/BermudaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaf|7\xb3\xde\x01\x00\x00\xde\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W-\x03\x00Atlantic/CanaryPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc2\x97N\xad\xaf\x00\x00\x00\xaf\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b/\x03\x00Atlantic/Cape_VerdePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\x0e\xbdm\xb9\x01\x00\x00\xb9\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B0\x03\x00Atlantic/FaeroePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\x0e\xbdm\xb9\x01\x00\x00\xb9\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(2\x03\x00Atlantic/FaroePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17S\x91\xb3\xc1\x02\x00\x00\xc1\x02\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d4\x03\x00Atlantic/Jan_MayenPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001)7\xad\xad\x05\x00\x00\xad\x05\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe6\x03\x00Atlantic/MadeiraPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9<\x03\x00Atlantic/ReykjavikPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0f-\xad\xd7\x84\x00\x00\x00\x84\x00\x00\x00\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8b=\x03\x00Atlantic/South_GeorgiaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C>\x03\x00Atlantic/St_HelenaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7\xcf^\xb0\x15\x03\x00\x00\x15\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf5>\x03\x00Atlantic/StanleyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008B\x03\x00Australia/ACTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8ff~\xd5\x99\x03\x00\x00\x99\x03\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xebE\x03\x00Australia/AdelaidePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\xba\xde\xd3!\x01\x00\x00!\x01\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4I\x03\x00Australia/BrisbanePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbd\xca#\x7f\xad\x03\x00\x00\xad\x03\x00\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05K\x03\x00Australia/Broken_HillPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5N\x03\x00Australia/CanberraPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\xf2\xe6Z\xeb\x03\x00\x00\xeb\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9dR\x03\x00Australia/CurriePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8R\x1a\x1b\xea\x00\x00\x00\xea\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb6V\x03\x00Australia/DarwinPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa2\xdc\xba\xca:\x01\x00\x00:\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xceW\x03\x00Australia/EuclaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\xf2\xe6Z\xeb\x03\x00\x00\xeb\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005Y\x03\x00Australia/HobartPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o3\xdaR\xb4\x02\x00\x00\xb4\x02\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00N]\x03\x00Australia/LHIPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\x95\xbd\x12E\x01\x00\x00E\x01\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-`\x03\x00Australia/LindemanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00o3\xdaR\xb4\x02\x00\x00\xb4\x02\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa2a\x03\x00Australia/Lord_HowePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xe1\xc1\xa9\x88\x03\x00\x00\x88\x03\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x87d\x03\x00Australia/MelbournePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00@h\x03\x00Australia/NSWPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8R\x1a\x1b\xea\x00\x00\x00\xea\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf3k\x03\x00Australia/NorthPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xbb\xca\x1a2\x01\x00\x002\x01\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0am\x03\x00Australia/PerthPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\xba\xde\xd3!\x01\x00\x00!\x01\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00in\x03\x00Australia/QueenslandPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8ff~\xd5\x99\x03\x00\x00\x99\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbco\x03\x00Australia/SouthPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xb9\x9ap\x88\x03\x00\x00\x88\x03\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x82s\x03\x00Australia/SydneyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\xf2\xe6Z\xeb\x03\x00\x00\xeb\x03\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008w\x03\x00Australia/TasmaniaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xe1\xc1\xa9\x88\x03\x00\x00\x88\x03\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S{\x03\x00Australia/VictoriaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\xbb\xca\x1a2\x01\x00\x002\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x7f\x03\x00Australia/WestPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbd\xca#\x7f\xad\x03\x00\x00\xad\x03\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00i\x80\x03\x00Australia/YancowinnaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xf5K\x89\xa2\x01\x00\x00\xa2\x01\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\x84\x03\x00Brazil/AcrePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7-2f\xe4\x01\x00\x00\xe4\x01\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x86\x03\x00Brazil/DeNoronhaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9d?\xdf\xda\xb8\x03\x00\x00\xb8\x03\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\x88\x03\x00Brazil/EastPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00a\xcb'\xe9\x9c\x01\x00\x00\x9c\x01\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x8c\x03\x00Brazil/WestPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x9aM\xbem\x02\x00\x00m\x02\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcb\x8d\x03\x00CETPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<\x8b\x99\x1e\xb7\x03\x00\x00\xb7\x03\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\x90\x03\x00CST6CDTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00):\x17-\x88\x06\x00\x00\x88\x06\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x94\x03\x00Canada/AtlanticPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?_p\x99\x0e\x05\x00\x00\x0e\x05\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xea\x9a\x03\x00Canada/CentralPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9\xd1\x06=\xb5\x06\x00\x00\xb5\x06\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$\xa0\x03\x00Canada/EasternPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00{\x07\x07\xdc\xca\x03\x00\x00\xca\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\xa7\x03\x00Canada/MountainPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeah\x06\xd2V\x07\x00\x00V\x07\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc\xaa\x03\x00Canada/NewfoundlandPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U9#\xbe2\x05\x00\x002\x05\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x83\xb2\x03\x00Canada/PacificPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc2\x96dK~\x02\x00\x00~\x02\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe1\xb7\x03\x00Canada/SaskatchewanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\x1d\xee\x91\x05\x04\x00\x00\x05\x04\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90\xba\x03\x00Canada/YukonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x22_WJ\x05\x00\x00J\x05\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf\xbe\x03\x00Chile/ContinentalPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?X'\x8e\x96\x04\x00\x00\x96\x04\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x008\xc4\x03\x00Chile/EasterIslandPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x1c\x9e\x9a]\x04\x00\x00]\x04\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\xc8\x03\x00CubaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`l\x8d~\xf1\x01\x00\x00\xf1\x01\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xcd\x03\x00EETPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00tX\xbe\xe4o\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8f\xcf\x03\x00ESTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7/\xebT\xb7\x03\x00\x00\xb7\x03\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f\xd0\x03\x00EST5EDTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5#)\x16\x1d\x05\x00\x00\x1d\x05\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfb\xd3\x03\x00EgyptPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1\xd6jL\xd8\x05\x00\x00\xd8\x05\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\xd9\x03\x00EirePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\xdf\x03\x00Etc/GMTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc9\xdf\x03\x00Etc/GMT+0PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\xb8\xe8\x86q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\xe0\x03\x00Etc/GMT+1PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8e\x1569r\x00\x00\x00r\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf7\xe0\x03\x00Etc/GMT+10PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\xb9\xbe\x9dr\x00\x00\x00r\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x91\xe1\x03\x00Etc/GMT+11PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5\xf38cr\x00\x00\x00r\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\xe2\x03\x00Etc/GMT+12PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9{\xa2qq\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xe2\x03\x00Etc/GMT+2PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00e\xcb\xe9Qq\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\xe3\x03\x00Etc/GMT+3PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd0\xfaFDq\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf5\xe3\x03\x00Etc/GMT+4PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4X\x9b\xf3q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8d\xe4\x03\x00Etc/GMT+5PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00H\x9b\xd1\x04q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%\xe5\x03\x00Etc/GMT+6PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x84+\x9a$q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbd\xe5\x03\x00Etc/GMT+7PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x22\xf8\x8f/q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00U\xe6\x03\x00Etc/GMT+8PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x84\x19\xb3\x09q\x00\x00\x00q\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\xe6\x03\x00Etc/GMT+9PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85\xe7\x03\x00Etc/GMT-0PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf7\x1ac\xc3r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xe8\x03\x00Etc/GMT-1PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd9|\xbd7s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\xe8\x03\x00Etc/GMT-10PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xab\xd1Is\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O\xe9\x03\x00Etc/GMT-11PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf7\x19s\x81s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xea\xe9\x03\x00Etc/GMT-12PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90`N\xe8s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x85\xea\x03\x00Etc/GMT-13PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,{\xdc;s\x00\x00\x00s\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \xeb\x03\x00Etc/GMT-14PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbc\x19y\x04r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbb\xeb\x03\x00Etc/GMT-2PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9c\xfcm\x99r\x00\x00\x00r\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\xec\x03\x00Etc/GMT-3PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00k\x19\xfe\xe5\x9e\x9b\x03\x00\x00\x9b\x03\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\xc2\x04\x00Europe/WarsawPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe1C\xf9\xa1\xde\x01\x00\x00\xde\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00}\xc6\x04\x00Europe/ZagrebPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x81\xbf~.\x02\x00\x00.\x02\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x86\xc8\x04\x00Europe/ZaporozhyePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Dd#\xc4\xf1\x01\x00\x00\xf1\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe3\xca\x04\x00Europe/ZurichPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xab\x80c$q\x00\x00\x00q\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xcc\x04\x00FactoryPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\xff\x01\xfe?\x06\x00\x00?\x06\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95\xcd\x04\x00GBPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W\xff\x01\xfe?\x06\x00\x00?\x06\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4\xd3\x04\x00GB-EirePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X\xda\x04\x00GMTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe8\xda\x04\x00GMT+0PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00z\xdb\x04\x00GMT-0PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\xdc\x04\x00GMT0PK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\xda\xfa\x03o\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9d\xdc\x04\x00GreenwichPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00=\xf7\xfawp\x00\x00\x00p\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\xdd\x04\x00HSTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00E\x09\xfa-\x07\x03\x00\x00\x07\x03\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc4\xdd\x04\x00HongkongPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\x08{\x87\x82\x00\x00\x00\x82\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xe0\x04\x00IcelandPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x98\xe1\x04\x00Indian/AntananarivoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\xb0W\x14\x98\x00\x00\x00\x98\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xe2\x04\x00Indian/ChagosPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\xf6C\x84\x98\x00\x00\x00\x98\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00K\xe3\x04\x00Indian/ChristmasPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\x87{_\xbb\x00\x00\x00\xbb\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\xe4\x04\x00Indian/CocosPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xe4\x04\x00Indian/ComoroPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb9\xb2Z\xac\x98\x00\x00\x00\x98\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\xe5\x04\x00Indian/KerguelenPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa6\xe6\x04\x00Indian/MahePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb9\xb2Z\xac\x98\x00\x00\x00\x98\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\xe7\x04\x00Indian/MaldivesPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xed=\x98\xb3\x00\x00\x00\xb3\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\xe8\x04\x00Indian/MauritiusPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb4\x8d\x98\xc6\xbf\x00\x00\x00\xbf\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfa\xe8\x04\x00Indian/MayottePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xed\x8c\xf1\x91\x85\x00\x00\x00\x85\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5\xe9\x04\x00Indian/ReunionPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8c\xdb?\xec,\x03\x00\x00,\x03\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xea\x04\x00IranPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17\xe2\x9c\xb32\x04\x00\x002\x04\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe4\xed\x04\x00IsraelPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%J\xd5\xebS\x01\x00\x00S\x01\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:\xf2\x04\x00JamaicaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xf4\xaeg\xd5\x00\x00\x00\xd5\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb2\xf3\x04\x00JapanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xe8]*\xdb\x00\x00\x00\xdb\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xaa\xf4\x04\x00KwajaleinPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_\x7f2[\xaf\x01\x00\x00\xaf\x01\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xac\xf5\x04\x00LibyaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe\x9d\x1b\xc9m\x02\x00\x00m\x02\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00~\xf7\x04\x00METPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf5\x8d\x99\x92o\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\xfa\x04\x00MSTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6h\xcac\xb7\x03\x00\x00\xb7\x03\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9c\xfa\x04\x00MST7MDTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa5\xce\xe5i\x01\x04\x00\x00\x01\x04\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\xfe\x04\x00Mexico/BajaNortePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\xad=\x98\xce\x02\x00\x00\xce\x02\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa7\x02\x05\x00Mexico/BajaSurPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd5\x08\x89\x8c\x05\x03\x00\x00\x05\x03\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1\x05\x05\x00Mexico/GeneralPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd2\x08\x05\x00NZPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xc5FF(\x03\x00\x00(\x03\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x0d\x05\x00NZ-CHATPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x80\x94@\x12\x04\x00\x00\x12\x04\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00R\x10\x05\x00NavajoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00*\xe4@\xa9\x89\x01\x00\x00\x89\x01\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88\x14\x05\x00PRCPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc5\xadV\xad\xb7\x03\x00\x00\xb7\x03\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x16\x05\x00PST8PDTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa8A\x15\xfe\x97\x01\x00\x00\x97\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x1a\x05\x00Pacific/ApiaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\xb2\xaf\xf7\x13\x04\x00\x00\x13\x04\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xcf\x1b\x05\x00Pacific/AucklandPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9a\xf2:F\xc9\x00\x00\x00\xc9\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10 \x05\x00Pacific/BougainvillePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96\xc5FF(\x03\x00\x00(\x03\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b!\x05\x00Pacific/ChathamPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00`$\x05\x00Pacific/ChuukPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?X'\x8e\x96\x04\x00\x00\x96\x04\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%%\x05\x00Pacific/EasterPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9e\x7f\xab\x95V\x01\x00\x00V\x01\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe7)\x05\x00Pacific/EfatePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xec =\x89\xac\x00\x00\x00\xac\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h+\x05\x00Pacific/EnderburyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x8a|\xdcU\x99\x00\x00\x00\x99\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00C,\x05\x00Pacific/FakaofoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfd_yl\x8c\x01\x00\x00\x8c\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x09-\x05\x00Pacific/FijiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbf.\x05\x00Pacific/FunafutiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x81\xe3w\x0a\xaf\x00\x00\x00\xaf\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00s/\x05\x00Pacific/GalapagosPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc23\xa0\xbc\x84\x00\x00\x00\x84\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Q0\x05\x00Pacific/GambierPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd2K|\x86\x00\x00\x00\x86\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x021\x05\x00Pacific/GuadalcanalPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FI\xfe\x14^\x01\x00\x00^\x01\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb91\x05\x00Pacific/GuamPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeaK\x85v\xdd\x00\x00\x00\xdd\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A3\x05\x00Pacific/HonoluluPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeaK\x85v\xdd\x00\x00\x00\xdd\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00L4\x05\x00Pacific/JohnstonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xec =\x89\xac\x00\x00\x00\xac\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00W5\x05\x00Pacific/KantonPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8=ku\xae\x00\x00\x00\xae\x00\x00\x00\x12\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00/6\x05\x00Pacific/KiritimatiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x97n7\x1a\xf2\x00\x00\x00\xf2\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d7\x05\x00Pacific/KosraePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\xe8]*\xdb\x00\x00\x00\xdb\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+8\x05\x00Pacific/KwajaleinPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0059\x05\x00Pacific/MajuroPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00D6\x83\xa1\x8b\x00\x00\x00\x8b\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe79\x05\x00Pacific/MarquesasPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa1:\x05\x00Pacific/MidwayPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe2;Z\xf7\xb7\x00\x00\x00\xb7\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00_;\x05\x00Pacific/NauruPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x91\xd60\x0c\x9a\x00\x00\x00\x9a\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A<\x05\x00Pacific/NiuePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00g\xc2$\x92\xed\x00\x00\x00\xed\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05=\x05\x00Pacific/NorfolkPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb7\xef\x97\xc6\xc6\x00\x00\x00\xc6\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1f>\x05\x00Pacific/NoumeaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11?\x05\x00Pacific/Pago_PagoPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\xf8v\xdc\x94\x00\x00\x00\x94\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd2?\x05\x00Pacific/PalauPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfa\x0fA\x05\x99\x00\x00\x00\x99\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x91@\x05\x00Pacific/PitcairnPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd2K|\x86\x00\x00\x00\x86\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00XA\x05\x00Pacific/PohnpeiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Y\xd2K|\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0bB\x05\x00Pacific/PonapePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbdB\x05\x00Pacific/Port_MoresbyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c\xe3\xa3S\x96\x01\x00\x00\x96\x01\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x89C\x05\x00Pacific/RarotongaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FI\xfe\x14^\x01\x00\x00^\x01\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00NE\x05\x00Pacific/SaipanPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd8F\x05\x00Pacific/SamoaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xea\xc1\xda\xcf\x85\x00\x00\x00\x85\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95G\x05\x00Pacific/TahitiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00FH\x05\x00Pacific/TarawaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x97F\x91\xb3\xed\x00\x00\x00\xed\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf8H\x05\x00Pacific/TongatapuPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14J\x05\x00Pacific/TrukPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd8J\x05\x00Pacific/WakePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006\xb7S{\x86\x00\x00\x00\x86\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x88K\x05\x00Pacific/WallisPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00n\x04\x19y\x9a\x00\x00\x00\x9a\x00\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00:L\x05\x00Pacific/YapPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\xfe\xe5\x9e\x9b\x03\x00\x00\x9b\x03\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfdL\x05\x00PolandPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&S\x03\x09\xae\x05\x00\x00\xae\x05\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbcP\x05\x00PortugalPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xee\xf0BB\xff\x01\x00\x00\xff\x01\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x90V\x05\x00ROCPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7X,Y\x9f\x01\x00\x00\x9f\x01\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb0X\x05\x00ROKPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00F7k\x1c\x00\x01\x00\x00\x00\x01\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00pZ\x05\x00SingaporePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07W\x10\xd1\xb0\x04\x00\x00\xb0\x04\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x97[\x05\x00TurkeyPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00k`\x05\x00UCTPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x005\x11Q\x06\xd1\x03\x00\x00\xd1\x03\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfb`\x05\x00US/AlaskaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xae,\xa44\xc9\x03\x00\x00\xc9\x03\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf3d\x05\x00US/AleutianPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc3\xb8\xab\x9b\xf0\x00\x00\x00\xf0\x00\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe5h\x05\x00US/ArizonaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9b\xdc\xa9=\xda\x06\x00\x00\xda\x06\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfdi\x05\x00US/CentralPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00p\xb6{\xc9\x13\x02\x00\x00\x13\x02\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xffp\x05\x00US/East-IndianaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\x9aG\xc8\xd0\x06\x00\x00\xd0\x06\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?s\x05\x00US/EasternPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xeaK\x85v\xdd\x00\x00\x00\xdd\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x007z\x05\x00US/HawaiiPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$ \x873\xf8\x03\x00\x00\xf8\x03\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;{\x05\x00US/Indiana-StarkePK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>\x14\xe7\x03\x83\x03\x00\x00\x83\x03\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00b\x7f\x05\x00US/MichiganPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00V\x80\x94@\x12\x04\x00\x00\x12\x04\x00\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0e\x83\x05\x00US/MountainPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf6\x22\x12\xfe\x0e\x05\x00\x00\x0e\x05\x00\x00\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00I\x87\x05\x00US/PacificPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00t\xca{e\x92\x00\x00\x00\x92\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\x8c\x05\x00US/SamoaPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x007\x8d\x05\x00UTCPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc7\x8d\x05\x00UniversalPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe1\xc1\xeb\x05\x8c\x03\x00\x00\x8c\x03\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00]\x8e\x05\x00W-SUPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\x91B\xc0\xee\x01\x00\x00\xee\x01\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b\x92\x05\x00WETPK\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9f.\xe4xo\x00\x00\x00o\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1a\x94\x05\x00ZuluPK\x05\x06\x00\x00\x00\x00U\x02U\x02m\x8c\x00\x00\xab\x94\x05\x00\x00\x00" diff --git a/contrib/go/_std_1.22/src/time/ya.make b/contrib/go/_std_1.23/src/time/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/time/ya.make rename to contrib/go/_std_1.23/src/time/ya.make diff --git a/contrib/go/_std_1.22/src/time/zoneinfo.go b/contrib/go/_std_1.23/src/time/zoneinfo.go similarity index 99% rename from contrib/go/_std_1.22/src/time/zoneinfo.go rename to contrib/go/_std_1.23/src/time/zoneinfo.go index c8d176230293..0fe13630e9a2 100644 --- a/contrib/go/_std_1.22/src/time/zoneinfo.go +++ b/contrib/go/_std_1.23/src/time/zoneinfo.go @@ -99,7 +99,7 @@ func (l *Location) get() *Location { } // String returns a descriptive name for the time zone information, -// corresponding to the name argument to LoadLocation or FixedZone. +// corresponding to the name argument to [LoadLocation] or [FixedZone]. func (l *Location) String() string { return l.get().name } @@ -107,7 +107,7 @@ func (l *Location) String() string { var unnamedFixedZones []*Location var unnamedFixedZonesOnce sync.Once -// FixedZone returns a Location that always uses +// FixedZone returns a [Location] that always uses // the given zone name and offset (seconds east of UTC). func FixedZone(name string, offset int) *Location { // Most calls to FixedZone have an unnamed zone with an offset by the hour. diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_abbrs_windows.go b/contrib/go/_std_1.23/src/time/zoneinfo_abbrs_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_abbrs_windows.go rename to contrib/go/_std_1.23/src/time/zoneinfo_abbrs_windows.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_android.go b/contrib/go/_std_1.23/src/time/zoneinfo_android.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_android.go rename to contrib/go/_std_1.23/src/time/zoneinfo_android.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_goroot.go b/contrib/go/_std_1.23/src/time/zoneinfo_goroot.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_goroot.go rename to contrib/go/_std_1.23/src/time/zoneinfo_goroot.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_ios.go b/contrib/go/_std_1.23/src/time/zoneinfo_ios.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_ios.go rename to contrib/go/_std_1.23/src/time/zoneinfo_ios.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_js.go b/contrib/go/_std_1.23/src/time/zoneinfo_js.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_js.go rename to contrib/go/_std_1.23/src/time/zoneinfo_js.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_plan9.go b/contrib/go/_std_1.23/src/time/zoneinfo_plan9.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_plan9.go rename to contrib/go/_std_1.23/src/time/zoneinfo_plan9.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_read.go b/contrib/go/_std_1.23/src/time/zoneinfo_read.go similarity index 98% rename from contrib/go/_std_1.22/src/time/zoneinfo_read.go rename to contrib/go/_std_1.23/src/time/zoneinfo_read.go index 707dd1189d03..5314b6ff9a16 100644 --- a/contrib/go/_std_1.22/src/time/zoneinfo_read.go +++ b/contrib/go/_std_1.23/src/time/zoneinfo_read.go @@ -11,12 +11,16 @@ package time import ( "errors" + "internal/bytealg" "runtime" "syscall" + _ "unsafe" // for linkname ) // registerLoadFromEmbeddedTZData is called by the time/tzdata package, // if it is imported. +// +//go:linkname registerLoadFromEmbeddedTZData func registerLoadFromEmbeddedTZData(f func(string) (string, error)) { loadFromEmbeddedTZData = f } @@ -99,10 +103,8 @@ func (d *dataIO) rest() []byte { // Make a string by stopping at the first NUL func byteString(p []byte) string { - for i := 0; i < len(p); i++ { - if p[i] == 0 { - return string(p[0:i]) - } + if i := bytealg.IndexByte(p, 0); i != -1 { + p = p[:i] } return string(p) } diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_unix.go b/contrib/go/_std_1.23/src/time/zoneinfo_unix.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_unix.go rename to contrib/go/_std_1.23/src/time/zoneinfo_unix.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_wasip1.go b/contrib/go/_std_1.23/src/time/zoneinfo_wasip1.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_wasip1.go rename to contrib/go/_std_1.23/src/time/zoneinfo_wasip1.go diff --git a/contrib/go/_std_1.22/src/time/zoneinfo_windows.go b/contrib/go/_std_1.23/src/time/zoneinfo_windows.go similarity index 100% rename from contrib/go/_std_1.22/src/time/zoneinfo_windows.go rename to contrib/go/_std_1.23/src/time/zoneinfo_windows.go diff --git a/contrib/go/_std_1.22/src/unicode/casetables.go b/contrib/go/_std_1.23/src/unicode/casetables.go similarity index 100% rename from contrib/go/_std_1.22/src/unicode/casetables.go rename to contrib/go/_std_1.23/src/unicode/casetables.go diff --git a/contrib/go/_std_1.22/src/unicode/digit.go b/contrib/go/_std_1.23/src/unicode/digit.go similarity index 100% rename from contrib/go/_std_1.22/src/unicode/digit.go rename to contrib/go/_std_1.23/src/unicode/digit.go diff --git a/contrib/go/_std_1.22/src/unicode/graphic.go b/contrib/go/_std_1.23/src/unicode/graphic.go similarity index 100% rename from contrib/go/_std_1.22/src/unicode/graphic.go rename to contrib/go/_std_1.23/src/unicode/graphic.go diff --git a/contrib/go/_std_1.22/src/unicode/letter.go b/contrib/go/_std_1.23/src/unicode/letter.go similarity index 100% rename from contrib/go/_std_1.22/src/unicode/letter.go rename to contrib/go/_std_1.23/src/unicode/letter.go diff --git a/contrib/go/_std_1.22/src/unicode/tables.go b/contrib/go/_std_1.23/src/unicode/tables.go similarity index 100% rename from contrib/go/_std_1.22/src/unicode/tables.go rename to contrib/go/_std_1.23/src/unicode/tables.go diff --git a/contrib/go/_std_1.22/src/unicode/utf16/utf16.go b/contrib/go/_std_1.23/src/unicode/utf16/utf16.go similarity index 89% rename from contrib/go/_std_1.22/src/unicode/utf16/utf16.go rename to contrib/go/_std_1.23/src/unicode/utf16/utf16.go index 1c6d2c66c30c..0293bbf639bc 100644 --- a/contrib/go/_std_1.22/src/unicode/utf16/utf16.go +++ b/contrib/go/_std_1.23/src/unicode/utf16/utf16.go @@ -52,6 +52,19 @@ func EncodeRune(r rune) (r1, r2 rune) { return surr1 + (r>>10)&0x3ff, surr2 + r&0x3ff } +// RuneLen returns the number of 16-bit words in the UTF-16 encoding of the rune. +// It returns -1 if the rune is not a valid value to encode in UTF-16. +func RuneLen(r rune) int { + switch { + case 0 <= r && r < surr1, surr3 <= r && r < surrSelf: + return 1 + case surrSelf <= r && r <= maxRune: + return 2 + default: + return -1 + } +} + // Encode returns the UTF-16 encoding of the Unicode code point sequence s. func Encode(s []rune) []uint16 { n := len(s) @@ -64,13 +77,11 @@ func Encode(s []rune) []uint16 { a := make([]uint16, n) n = 0 for _, v := range s { - switch { - case 0 <= v && v < surr1, surr3 <= v && v < surrSelf: - // normal rune + switch RuneLen(v) { + case 1: // normal rune a[n] = uint16(v) n++ - case surrSelf <= v && v <= maxRune: - // needs surrogate sequence + case 2: // needs surrogate sequence r1, r2 := EncodeRune(v) a[n] = uint16(r1) a[n+1] = uint16(r2) diff --git a/contrib/go/_std_1.22/src/unicode/utf16/ya.make b/contrib/go/_std_1.23/src/unicode/utf16/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/unicode/utf16/ya.make rename to contrib/go/_std_1.23/src/unicode/utf16/ya.make diff --git a/contrib/go/_std_1.22/src/unicode/utf8/utf8.go b/contrib/go/_std_1.23/src/unicode/utf8/utf8.go similarity index 99% rename from contrib/go/_std_1.22/src/unicode/utf8/utf8.go rename to contrib/go/_std_1.23/src/unicode/utf8/utf8.go index 71d6bf18d01b..c7389d4d6f58 100644 --- a/contrib/go/_std_1.22/src/unicode/utf8/utf8.go +++ b/contrib/go/_std_1.23/src/unicode/utf8/utf8.go @@ -316,7 +316,7 @@ func DecodeLastRuneInString(s string) (r rune, size int) { return r, size } -// RuneLen returns the number of bytes required to encode the rune. +// RuneLen returns the number of bytes in the UTF-8 encoding of the rune. // It returns -1 if the rune is not a valid value to encode in UTF-8. func RuneLen(r rune) int { switch { diff --git a/contrib/go/_std_1.22/src/unicode/utf8/ya.make b/contrib/go/_std_1.23/src/unicode/utf8/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/unicode/utf8/ya.make rename to contrib/go/_std_1.23/src/unicode/utf8/ya.make diff --git a/contrib/go/_std_1.22/src/unicode/ya.make b/contrib/go/_std_1.23/src/unicode/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/unicode/ya.make rename to contrib/go/_std_1.23/src/unicode/ya.make diff --git a/contrib/go/_std_1.23/src/unique/clone.go b/contrib/go/_std_1.23/src/unique/clone.go new file mode 100644 index 000000000000..36ced14ecea0 --- /dev/null +++ b/contrib/go/_std_1.23/src/unique/clone.go @@ -0,0 +1,89 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unique + +import ( + "internal/abi" + "internal/stringslite" + "unsafe" +) + +// clone makes a copy of value, and may update string values found in value +// with a cloned version of those strings. The purpose of explicitly cloning +// strings is to avoid accidentally giving a large string a long lifetime. +// +// Note that this will clone strings in structs and arrays found in value, +// and will clone value if it itself is a string. It will not, however, clone +// strings if value is of interface or slice type (that is, found via an +// indirection). +func clone[T comparable](value T, seq *cloneSeq) T { + for _, offset := range seq.stringOffsets { + ps := (*string)(unsafe.Pointer(uintptr(unsafe.Pointer(&value)) + offset)) + *ps = stringslite.Clone(*ps) + } + return value +} + +// singleStringClone describes how to clone a single string. +var singleStringClone = cloneSeq{stringOffsets: []uintptr{0}} + +// cloneSeq describes how to clone a value of a particular type. +type cloneSeq struct { + stringOffsets []uintptr +} + +// makeCloneSeq creates a cloneSeq for a type. +func makeCloneSeq(typ *abi.Type) cloneSeq { + if typ == nil { + return cloneSeq{} + } + if typ.Kind() == abi.String { + return singleStringClone + } + var seq cloneSeq + switch typ.Kind() { + case abi.Struct: + buildStructCloneSeq(typ, &seq, 0) + case abi.Array: + buildArrayCloneSeq(typ, &seq, 0) + } + return seq +} + +// buildStructCloneSeq populates a cloneSeq for an abi.Type that has Kind abi.Struct. +func buildStructCloneSeq(typ *abi.Type, seq *cloneSeq, baseOffset uintptr) { + styp := typ.StructType() + for i := range styp.Fields { + f := &styp.Fields[i] + switch f.Typ.Kind() { + case abi.String: + seq.stringOffsets = append(seq.stringOffsets, baseOffset+f.Offset) + case abi.Struct: + buildStructCloneSeq(f.Typ, seq, baseOffset+f.Offset) + case abi.Array: + buildArrayCloneSeq(f.Typ, seq, baseOffset+f.Offset) + } + } +} + +// buildArrayCloneSeq populates a cloneSeq for an abi.Type that has Kind abi.Array. +func buildArrayCloneSeq(typ *abi.Type, seq *cloneSeq, baseOffset uintptr) { + atyp := typ.ArrayType() + etyp := atyp.Elem + offset := baseOffset + for range atyp.Len { + switch etyp.Kind() { + case abi.String: + seq.stringOffsets = append(seq.stringOffsets, offset) + case abi.Struct: + buildStructCloneSeq(etyp, seq, offset) + case abi.Array: + buildArrayCloneSeq(etyp, seq, offset) + } + offset += etyp.Size() + align := uintptr(etyp.FieldAlign()) + offset = (offset + align - 1) &^ (align - 1) + } +} diff --git a/contrib/go/_std_1.23/src/unique/doc.go b/contrib/go/_std_1.23/src/unique/doc.go new file mode 100644 index 000000000000..01337893c40a --- /dev/null +++ b/contrib/go/_std_1.23/src/unique/doc.go @@ -0,0 +1,9 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +The unique package provides facilities for canonicalizing ("interning") +comparable values. +*/ +package unique diff --git a/contrib/go/_std_1.23/src/unique/handle.go b/contrib/go/_std_1.23/src/unique/handle.go new file mode 100644 index 000000000000..abc620f60fe1 --- /dev/null +++ b/contrib/go/_std_1.23/src/unique/handle.go @@ -0,0 +1,175 @@ +// Copyright 2024 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unique + +import ( + "internal/abi" + "internal/concurrent" + "internal/weak" + "runtime" + "sync" + _ "unsafe" +) + +// Handle is a globally unique identity for some value of type T. +// +// Two handles compare equal exactly if the two values used to create the handles +// would have also compared equal. The comparison of two handles is trivial and +// typically much more efficient than comparing the values used to create them. +type Handle[T comparable] struct { + value *T +} + +// Value returns a shallow copy of the T value that produced the Handle. +func (h Handle[T]) Value() T { + return *h.value +} + +// Make returns a globally unique handle for a value of type T. Handles +// are equal if and only if the values used to produce them are equal. +func Make[T comparable](value T) Handle[T] { + // Find the map for type T. + typ := abi.TypeFor[T]() + ma, ok := uniqueMaps.Load(typ) + if !ok { + // This is a good time to initialize cleanup, since we must go through + // this path on the first use of Make, and it's not on the hot path. + setupMake.Do(registerCleanup) + ma = addUniqueMap[T](typ) + } + m := ma.(*uniqueMap[T]) + + // Keep around any values we allocate for insertion. There + // are a few different ways we can race with other threads + // and create values that we might discard. By keeping + // the first one we make around, we can avoid generating + // more than one per racing thread. + var ( + toInsert *T // Keep this around to keep it alive. + toInsertWeak weak.Pointer[T] + ) + newValue := func() (T, weak.Pointer[T]) { + if toInsert == nil { + toInsert = new(T) + *toInsert = clone(value, &m.cloneSeq) + toInsertWeak = weak.Make(toInsert) + } + return *toInsert, toInsertWeak + } + var ptr *T + for { + // Check the map. + wp, ok := m.Load(value) + if !ok { + // Try to insert a new value into the map. + k, v := newValue() + wp, _ = m.LoadOrStore(k, v) + } + // Now that we're sure there's a value in the map, let's + // try to get the pointer we need out of it. + ptr = wp.Strong() + if ptr != nil { + break + } + // The weak pointer is nil, so the old value is truly dead. + // Try to remove it and start over. + m.CompareAndDelete(value, wp) + } + runtime.KeepAlive(toInsert) + return Handle[T]{ptr} +} + +var ( + // uniqueMaps is an index of type-specific concurrent maps used for unique.Make. + // + // The two-level map might seem odd at first since the HashTrieMap could have "any" + // as its key type, but the issue is escape analysis. We do not want to force lookups + // to escape the argument, and using a type-specific map allows us to avoid that where + // possible (for example, for strings and plain-ol'-data structs). We also get the + // benefit of not cramming every different type into a single map, but that's certainly + // not enough to outweigh the cost of two map lookups. What is worth it though, is saving + // on those allocations. + uniqueMaps = concurrent.NewHashTrieMap[*abi.Type, any]() // any is always a *uniqueMap[T]. + + // cleanupFuncs are functions that clean up dead weak pointers in type-specific + // maps in uniqueMaps. We express cleanup this way because there's no way to iterate + // over the sync.Map and call functions on the type-specific data structures otherwise. + // These cleanup funcs each close over one of these type-specific maps. + // + // cleanupMu protects cleanupNotify and is held across the entire cleanup. Used for testing. + // cleanupNotify is a test-only mechanism that allow tests to wait for the cleanup to run. + cleanupMu sync.Mutex + cleanupFuncsMu sync.Mutex + cleanupFuncs []func() + cleanupNotify []func() // One-time notifications when cleanups finish. +) + +type uniqueMap[T comparable] struct { + *concurrent.HashTrieMap[T, weak.Pointer[T]] + cloneSeq +} + +func addUniqueMap[T comparable](typ *abi.Type) *uniqueMap[T] { + // Create a map for T and try to register it. We could + // race with someone else, but that's fine; it's one + // small, stray allocation. The number of allocations + // this can create is bounded by a small constant. + m := &uniqueMap[T]{ + HashTrieMap: concurrent.NewHashTrieMap[T, weak.Pointer[T]](), + cloneSeq: makeCloneSeq(typ), + } + a, loaded := uniqueMaps.LoadOrStore(typ, m) + if !loaded { + // Add a cleanup function for the new map. + cleanupFuncsMu.Lock() + cleanupFuncs = append(cleanupFuncs, func() { + // Delete all the entries whose weak references are nil and clean up + // deleted entries. + m.All()(func(key T, wp weak.Pointer[T]) bool { + if wp.Strong() == nil { + m.CompareAndDelete(key, wp) + } + return true + }) + }) + cleanupFuncsMu.Unlock() + } + return a.(*uniqueMap[T]) +} + +// setupMake is used to perform initial setup for unique.Make. +var setupMake sync.Once + +// startBackgroundCleanup sets up a background goroutine to occasionally call cleanupFuncs. +func registerCleanup() { + runtime_registerUniqueMapCleanup(func() { + // Lock for cleanup. + cleanupMu.Lock() + + // Grab funcs to run. + cleanupFuncsMu.Lock() + cf := cleanupFuncs + cleanupFuncsMu.Unlock() + + // Run cleanup. + for _, f := range cf { + f() + } + + // Run cleanup notifications. + for _, f := range cleanupNotify { + f() + } + cleanupNotify = nil + + // Finished. + cleanupMu.Unlock() + }) +} + +// Implemented in runtime. + +//go:linkname runtime_registerUniqueMapCleanup +func runtime_registerUniqueMapCleanup(cleanup func()) diff --git a/contrib/go/_std_1.23/src/unique/ya.make b/contrib/go/_std_1.23/src/unique/ya.make new file mode 100644 index 000000000000..9f3174c8742d --- /dev/null +++ b/contrib/go/_std_1.23/src/unique/ya.make @@ -0,0 +1,9 @@ +GO_LIBRARY() +IF (TRUE) + SRCS( + clone.go + doc.go + handle.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_arm64.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_generic.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_generic.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_generic.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_noasm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s similarity index 85% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s index 66aebae25885..c672ccf6986b 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_ppc64le.s @@ -33,6 +33,9 @@ #define CONSTBASE R16 #define BLOCKS R17 +// for VPERMXOR +#define MASK R18 + DATA consts<>+0x00(SB)/8, $0x3320646e61707865 DATA consts<>+0x08(SB)/8, $0x6b20657479622d32 DATA consts<>+0x10(SB)/8, $0x0000000000000001 @@ -53,7 +56,11 @@ DATA consts<>+0x80(SB)/8, $0x6b2065746b206574 DATA consts<>+0x88(SB)/8, $0x6b2065746b206574 DATA consts<>+0x90(SB)/8, $0x0000000100000000 DATA consts<>+0x98(SB)/8, $0x0000000300000002 -GLOBL consts<>(SB), RODATA, $0xa0 +DATA consts<>+0xa0(SB)/8, $0x5566774411223300 +DATA consts<>+0xa8(SB)/8, $0xddeeffcc99aabb88 +DATA consts<>+0xb0(SB)/8, $0x6677445522330011 +DATA consts<>+0xb8(SB)/8, $0xeeffccddaabb8899 +GLOBL consts<>(SB), RODATA, $0xc0 //func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32) TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40 @@ -70,6 +77,9 @@ TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40 MOVD $48, R10 MOVD $64, R11 SRD $6, LEN, BLOCKS + // for VPERMXOR + MOVD $consts<>+0xa0(SB), MASK + MOVD $16, R20 // V16 LXVW4X (CONSTBASE)(R0), VS48 ADD $80,CONSTBASE @@ -87,6 +97,10 @@ TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40 // V28 LXVW4X (CONSTBASE)(R11), VS60 + // Load mask constants for VPERMXOR + LXVW4X (MASK)(R0), V20 + LXVW4X (MASK)(R20), V21 + // splat slot from V19 -> V26 VSPLTW $0, V19, V26 @@ -97,7 +111,7 @@ TEXT ·chaCha20_ctr32_vsx(SB),NOSPLIT,$64-40 MOVD $10, R14 MOVD R14, CTR - + PCALIGN $16 loop_outer_vsx: // V0, V1, V2, V3 LXVW4X (R0)(CONSTBASE), VS32 @@ -128,22 +142,17 @@ loop_outer_vsx: VSPLTISW $12, V28 VSPLTISW $8, V29 VSPLTISW $7, V30 - + PCALIGN $16 loop_vsx: VADDUWM V0, V4, V0 VADDUWM V1, V5, V1 VADDUWM V2, V6, V2 VADDUWM V3, V7, V3 - VXOR V12, V0, V12 - VXOR V13, V1, V13 - VXOR V14, V2, V14 - VXOR V15, V3, V15 - - VRLW V12, V27, V12 - VRLW V13, V27, V13 - VRLW V14, V27, V14 - VRLW V15, V27, V15 + VPERMXOR V12, V0, V21, V12 + VPERMXOR V13, V1, V21, V13 + VPERMXOR V14, V2, V21, V14 + VPERMXOR V15, V3, V21, V15 VADDUWM V8, V12, V8 VADDUWM V9, V13, V9 @@ -165,15 +174,10 @@ loop_vsx: VADDUWM V2, V6, V2 VADDUWM V3, V7, V3 - VXOR V12, V0, V12 - VXOR V13, V1, V13 - VXOR V14, V2, V14 - VXOR V15, V3, V15 - - VRLW V12, V29, V12 - VRLW V13, V29, V13 - VRLW V14, V29, V14 - VRLW V15, V29, V15 + VPERMXOR V12, V0, V20, V12 + VPERMXOR V13, V1, V20, V13 + VPERMXOR V14, V2, V20, V14 + VPERMXOR V15, V3, V20, V15 VADDUWM V8, V12, V8 VADDUWM V9, V13, V9 @@ -195,15 +199,10 @@ loop_vsx: VADDUWM V2, V7, V2 VADDUWM V3, V4, V3 - VXOR V15, V0, V15 - VXOR V12, V1, V12 - VXOR V13, V2, V13 - VXOR V14, V3, V14 - - VRLW V15, V27, V15 - VRLW V12, V27, V12 - VRLW V13, V27, V13 - VRLW V14, V27, V14 + VPERMXOR V15, V0, V21, V15 + VPERMXOR V12, V1, V21, V12 + VPERMXOR V13, V2, V21, V13 + VPERMXOR V14, V3, V21, V14 VADDUWM V10, V15, V10 VADDUWM V11, V12, V11 @@ -225,15 +224,10 @@ loop_vsx: VADDUWM V2, V7, V2 VADDUWM V3, V4, V3 - VXOR V15, V0, V15 - VXOR V12, V1, V12 - VXOR V13, V2, V13 - VXOR V14, V3, V14 - - VRLW V15, V29, V15 - VRLW V12, V29, V12 - VRLW V13, V29, V13 - VRLW V14, V29, V14 + VPERMXOR V15, V0, V20, V15 + VPERMXOR V12, V1, V20, V12 + VPERMXOR V13, V2, V20, V13 + VPERMXOR V14, V3, V20, V14 VADDUWM V10, V15, V10 VADDUWM V11, V12, V11 @@ -249,48 +243,48 @@ loop_vsx: VRLW V6, V30, V6 VRLW V7, V30, V7 VRLW V4, V30, V4 - BC 16, LT, loop_vsx + BDNZ loop_vsx VADDUWM V12, V26, V12 - WORD $0x13600F8C // VMRGEW V0, V1, V27 - WORD $0x13821F8C // VMRGEW V2, V3, V28 + VMRGEW V0, V1, V27 + VMRGEW V2, V3, V28 - WORD $0x10000E8C // VMRGOW V0, V1, V0 - WORD $0x10421E8C // VMRGOW V2, V3, V2 + VMRGOW V0, V1, V0 + VMRGOW V2, V3, V2 - WORD $0x13A42F8C // VMRGEW V4, V5, V29 - WORD $0x13C63F8C // VMRGEW V6, V7, V30 + VMRGEW V4, V5, V29 + VMRGEW V6, V7, V30 XXPERMDI VS32, VS34, $0, VS33 XXPERMDI VS32, VS34, $3, VS35 XXPERMDI VS59, VS60, $0, VS32 XXPERMDI VS59, VS60, $3, VS34 - WORD $0x10842E8C // VMRGOW V4, V5, V4 - WORD $0x10C63E8C // VMRGOW V6, V7, V6 + VMRGOW V4, V5, V4 + VMRGOW V6, V7, V6 - WORD $0x13684F8C // VMRGEW V8, V9, V27 - WORD $0x138A5F8C // VMRGEW V10, V11, V28 + VMRGEW V8, V9, V27 + VMRGEW V10, V11, V28 XXPERMDI VS36, VS38, $0, VS37 XXPERMDI VS36, VS38, $3, VS39 XXPERMDI VS61, VS62, $0, VS36 XXPERMDI VS61, VS62, $3, VS38 - WORD $0x11084E8C // VMRGOW V8, V9, V8 - WORD $0x114A5E8C // VMRGOW V10, V11, V10 + VMRGOW V8, V9, V8 + VMRGOW V10, V11, V10 - WORD $0x13AC6F8C // VMRGEW V12, V13, V29 - WORD $0x13CE7F8C // VMRGEW V14, V15, V30 + VMRGEW V12, V13, V29 + VMRGEW V14, V15, V30 XXPERMDI VS40, VS42, $0, VS41 XXPERMDI VS40, VS42, $3, VS43 XXPERMDI VS59, VS60, $0, VS40 XXPERMDI VS59, VS60, $3, VS42 - WORD $0x118C6E8C // VMRGOW V12, V13, V12 - WORD $0x11CE7E8C // VMRGOW V14, V15, V14 + VMRGOW V12, V13, V12 + VMRGOW V14, V15, V14 VSPLTISW $4, V27 VADDUWM V26, V27, V26 @@ -431,7 +425,7 @@ tail_vsx: ADD $-1, R11, R12 ADD $-1, INP ADD $-1, OUT - + PCALIGN $16 looptail_vsx: // Copying the result to OUT // in bytes. @@ -439,7 +433,7 @@ looptail_vsx: MOVBZU 1(INP), TMP XOR KEY, TMP, KEY MOVBU KEY, 1(OUT) - BC 16, LT, looptail_vsx + BDNZ looptail_vsx // Clear the stack values STXVW4X VS48, (R11)(R0) diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/chacha_s390x.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/xor.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/xor.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/xor.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/xor.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_amd64.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_generic.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/chacha20poly1305_noasm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/xchacha20poly1305.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/chacha20poly1305/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/chacha20poly1305/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/asn1/asn1.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/asn1/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/asn1/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/asn1/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/asn1/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/builder.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/builder.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/builder.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/builder.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/string.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/string.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/string.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/string.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/cryptobyte/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/cryptobyte/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/hkdf/hkdf.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/hkdf/hkdf.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/hkdf/hkdf.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/hkdf/hkdf.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/hkdf/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/hkdf/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/hkdf/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/hkdf/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/alias/alias.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/alias/alias.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/alias/alias.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/alias/alias.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/alias/alias_purego.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/alias/alias_purego.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/alias/alias_purego.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/alias/alias_purego.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/alias/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/alias/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/alias/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/alias/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/mac_noasm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/poly1305.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_amd64.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go similarity index 91% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go index e041da5ea3e7..ec2202bd7d5f 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_generic.go @@ -7,7 +7,10 @@ package poly1305 -import "encoding/binary" +import ( + "encoding/binary" + "math/bits" +) // Poly1305 [RFC 7539] is a relatively simple algorithm: the authentication tag // for a 64 bytes message is approximately @@ -114,13 +117,13 @@ type uint128 struct { } func mul64(a, b uint64) uint128 { - hi, lo := bitsMul64(a, b) + hi, lo := bits.Mul64(a, b) return uint128{lo, hi} } func add128(a, b uint128) uint128 { - lo, c := bitsAdd64(a.lo, b.lo, 0) - hi, c := bitsAdd64(a.hi, b.hi, c) + lo, c := bits.Add64(a.lo, b.lo, 0) + hi, c := bits.Add64(a.hi, b.hi, c) if c != 0 { panic("poly1305: unexpected overflow") } @@ -155,8 +158,8 @@ func updateGeneric(state *macState, msg []byte) { // hide leading zeroes. For full chunks, that's 1 << 128, so we can just // add 1 to the most significant (2¹²⁸) limb, h2. if len(msg) >= TagSize { - h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0) - h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(msg[8:16]), c) + h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(msg[0:8]), 0) + h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(msg[8:16]), c) h2 += c + 1 msg = msg[TagSize:] @@ -165,8 +168,8 @@ func updateGeneric(state *macState, msg []byte) { copy(buf[:], msg) buf[len(msg)] = 1 - h0, c = bitsAdd64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0) - h1, c = bitsAdd64(h1, binary.LittleEndian.Uint64(buf[8:16]), c) + h0, c = bits.Add64(h0, binary.LittleEndian.Uint64(buf[0:8]), 0) + h1, c = bits.Add64(h1, binary.LittleEndian.Uint64(buf[8:16]), c) h2 += c msg = nil @@ -219,9 +222,9 @@ func updateGeneric(state *macState, msg []byte) { m3 := h2r1 t0 := m0.lo - t1, c := bitsAdd64(m1.lo, m0.hi, 0) - t2, c := bitsAdd64(m2.lo, m1.hi, c) - t3, _ := bitsAdd64(m3.lo, m2.hi, c) + t1, c := bits.Add64(m1.lo, m0.hi, 0) + t2, c := bits.Add64(m2.lo, m1.hi, c) + t3, _ := bits.Add64(m3.lo, m2.hi, c) // Now we have the result as 4 64-bit limbs, and we need to reduce it // modulo 2¹³⁰ - 5. The special shape of this Crandall prime lets us do @@ -243,14 +246,14 @@ func updateGeneric(state *macState, msg []byte) { // To add c * 5 to h, we first add cc = c * 4, and then add (cc >> 2) = c. - h0, c = bitsAdd64(h0, cc.lo, 0) - h1, c = bitsAdd64(h1, cc.hi, c) + h0, c = bits.Add64(h0, cc.lo, 0) + h1, c = bits.Add64(h1, cc.hi, c) h2 += c cc = shiftRightBy2(cc) - h0, c = bitsAdd64(h0, cc.lo, 0) - h1, c = bitsAdd64(h1, cc.hi, c) + h0, c = bits.Add64(h0, cc.lo, 0) + h1, c = bits.Add64(h1, cc.hi, c) h2 += c // h2 is at most 3 + 1 + 1 = 5, making the whole of h at most @@ -287,9 +290,9 @@ func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) { // in constant time, we compute t = h - (2¹³⁰ - 5), and select h as the // result if the subtraction underflows, and t otherwise. - hMinusP0, b := bitsSub64(h0, p0, 0) - hMinusP1, b := bitsSub64(h1, p1, b) - _, b = bitsSub64(h2, p2, b) + hMinusP0, b := bits.Sub64(h0, p0, 0) + hMinusP1, b := bits.Sub64(h1, p1, b) + _, b = bits.Sub64(h2, p2, b) // h = h if h < p else h - p h0 = select64(b, h0, hMinusP0) @@ -301,8 +304,8 @@ func finalize(out *[TagSize]byte, h *[3]uint64, s *[2]uint64) { // // by just doing a wide addition with the 128 low bits of h and discarding // the overflow. - h0, c := bitsAdd64(h0, s[0], 0) - h1, _ = bitsAdd64(h1, s[1], c) + h0, c := bits.Add64(h0, s[0], 0) + h1, _ = bits.Add64(h1, s[1], c) binary.LittleEndian.PutUint64(out[0:8], h0) binary.LittleEndian.PutUint64(out[8:16], h1) diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s similarity index 95% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s index d2ca5deeb9f5..b3c1699bff51 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_ppc64le.s @@ -19,15 +19,14 @@ #define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3, t4, t5) \ MULLD r0, h0, t0; \ - MULLD r0, h1, t4; \ MULHDU r0, h0, t1; \ + MULLD r0, h1, t4; \ MULHDU r0, h1, t5; \ ADDC t4, t1, t1; \ MULLD r0, h2, t2; \ - ADDZE t5; \ MULHDU r1, h0, t4; \ MULLD r1, h0, h0; \ - ADD t5, t2, t2; \ + ADDE t5, t2, t2; \ ADDC h0, t1, t1; \ MULLD h2, r1, t3; \ ADDZE t4, h0; \ @@ -37,13 +36,11 @@ ADDE t5, t3, t3; \ ADDC h0, t2, t2; \ MOVD $-4, t4; \ - MOVD t0, h0; \ - MOVD t1, h1; \ ADDZE t3; \ - ANDCC $3, t2, h2; \ - AND t2, t4, t0; \ + RLDICL $0, t2, $62, h2; \ + AND t2, t4, h0; \ ADDC t0, h0, h0; \ - ADDE t3, h1, h1; \ + ADDE t3, t1, h1; \ SLD $62, t3, t4; \ SRD $2, t2; \ ADDZE h2; \ @@ -75,6 +72,7 @@ TEXT ·update(SB), $0-32 loop: POLY1305_ADD(R4, R8, R9, R10, R20, R21, R22) + PCALIGN $16 multiply: POLY1305_MUL(R8, R9, R10, R11, R12, R16, R17, R18, R14, R20, R21) ADD $-16, R5 diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/sum_s390x.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/ya.make similarity index 96% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/ya.make index 431e8ade99c7..7886295c6cc8 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/crypto/internal/poly1305/ya.make +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/internal/poly1305/ya.make @@ -1,14 +1,12 @@ GO_LIBRARY() IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( - bits_go1.13.go mac_noasm.go poly1305.go sum_generic.go ) ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) SRCS( - bits_go1.13.go poly1305.go sum_amd64.go sum_amd64.s diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/doc.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/doc.go new file mode 100644 index 000000000000..decd8cf9bf74 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/doc.go @@ -0,0 +1,62 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package sha3 implements the SHA-3 fixed-output-length hash functions and +// the SHAKE variable-output-length hash functions defined by FIPS-202. +// +// Both types of hash function use the "sponge" construction and the Keccak +// permutation. For a detailed specification see http://keccak.noekeon.org/ +// +// # Guidance +// +// If you aren't sure what function you need, use SHAKE256 with at least 64 +// bytes of output. The SHAKE instances are faster than the SHA3 instances; +// the latter have to allocate memory to conform to the hash.Hash interface. +// +// If you need a secret-key MAC (message authentication code), prepend the +// secret key to the input, hash with SHAKE256 and read at least 32 bytes of +// output. +// +// # Security strengths +// +// The SHA3-x (x equals 224, 256, 384, or 512) functions have a security +// strength against preimage attacks of x bits. Since they only produce "x" +// bits of output, their collision-resistance is only "x/2" bits. +// +// The SHAKE-256 and -128 functions have a generic security strength of 256 and +// 128 bits against all attacks, provided that at least 2x bits of their output +// is used. Requesting more than 64 or 32 bytes of output, respectively, does +// not increase the collision-resistance of the SHAKE functions. +// +// # The sponge construction +// +// A sponge builds a pseudo-random function from a public pseudo-random +// permutation, by applying the permutation to a state of "rate + capacity" +// bytes, but hiding "capacity" of the bytes. +// +// A sponge starts out with a zero state. To hash an input using a sponge, up +// to "rate" bytes of the input are XORed into the sponge's state. The sponge +// is then "full" and the permutation is applied to "empty" it. This process is +// repeated until all the input has been "absorbed". The input is then padded. +// The digest is "squeezed" from the sponge in the same way, except that output +// is copied out instead of input being XORed in. +// +// A sponge is parameterized by its generic security strength, which is equal +// to half its capacity; capacity + rate is equal to the permutation's width. +// Since the KeccakF-1600 permutation is 1600 bits (200 bytes) wide, this means +// that the security strength of a sponge instance is equal to (1600 - bitrate) / 2. +// +// # Recommendations +// +// The SHAKE functions are recommended for most new uses. They can produce +// output of arbitrary length. SHAKE256, with an output length of at least +// 64 bytes, provides 256-bit security against all attacks. The Keccak team +// recommends it for most applications upgrading from SHA2-512. (NIST chose a +// much stronger, but much slower, sponge instance for SHA3-512.) +// +// The SHA-3 functions are "drop-in" replacements for the SHA-2 functions. +// They produce output of the same length, with the same security strengths +// against all attacks. This means, in particular, that SHA3-256 only has +// 128-bit collision resistance, because its output length is 32 bytes. +package sha3 // import "golang.org/x/crypto/sha3" diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/hashes.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/hashes.go new file mode 100644 index 000000000000..5eae6cb922fb --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/hashes.go @@ -0,0 +1,101 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sha3 + +// This file provides functions for creating instances of the SHA-3 +// and SHAKE hash functions, as well as utility functions for hashing +// bytes. + +import ( + "hash" +) + +// New224 creates a new SHA3-224 hash. +// Its generic security strength is 224 bits against preimage attacks, +// and 112 bits against collision attacks. +func New224() hash.Hash { + return new224() +} + +// New256 creates a new SHA3-256 hash. +// Its generic security strength is 256 bits against preimage attacks, +// and 128 bits against collision attacks. +func New256() hash.Hash { + return new256() +} + +// New384 creates a new SHA3-384 hash. +// Its generic security strength is 384 bits against preimage attacks, +// and 192 bits against collision attacks. +func New384() hash.Hash { + return new384() +} + +// New512 creates a new SHA3-512 hash. +// Its generic security strength is 512 bits against preimage attacks, +// and 256 bits against collision attacks. +func New512() hash.Hash { + return new512() +} + +func new224Generic() *state { + return &state{rate: 144, outputLen: 28, dsbyte: 0x06} +} + +func new256Generic() *state { + return &state{rate: 136, outputLen: 32, dsbyte: 0x06} +} + +func new384Generic() *state { + return &state{rate: 104, outputLen: 48, dsbyte: 0x06} +} + +func new512Generic() *state { + return &state{rate: 72, outputLen: 64, dsbyte: 0x06} +} + +// NewLegacyKeccak256 creates a new Keccak-256 hash. +// +// Only use this function if you require compatibility with an existing cryptosystem +// that uses non-standard padding. All other users should use New256 instead. +func NewLegacyKeccak256() hash.Hash { return &state{rate: 136, outputLen: 32, dsbyte: 0x01} } + +// NewLegacyKeccak512 creates a new Keccak-512 hash. +// +// Only use this function if you require compatibility with an existing cryptosystem +// that uses non-standard padding. All other users should use New512 instead. +func NewLegacyKeccak512() hash.Hash { return &state{rate: 72, outputLen: 64, dsbyte: 0x01} } + +// Sum224 returns the SHA3-224 digest of the data. +func Sum224(data []byte) (digest [28]byte) { + h := New224() + h.Write(data) + h.Sum(digest[:0]) + return +} + +// Sum256 returns the SHA3-256 digest of the data. +func Sum256(data []byte) (digest [32]byte) { + h := New256() + h.Write(data) + h.Sum(digest[:0]) + return +} + +// Sum384 returns the SHA3-384 digest of the data. +func Sum384(data []byte) (digest [48]byte) { + h := New384() + h.Write(data) + h.Sum(digest[:0]) + return +} + +// Sum512 returns the SHA3-512 digest of the data. +func Sum512(data []byte) (digest [64]byte) { + h := New512() + h.Write(data) + h.Sum(digest[:0]) + return +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/hashes_noasm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/hashes_noasm.go new file mode 100644 index 000000000000..9d85fb621446 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/hashes_noasm.go @@ -0,0 +1,23 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !gc || purego || !s390x + +package sha3 + +func new224() *state { + return new224Generic() +} + +func new256() *state { + return new256Generic() +} + +func new384() *state { + return new384Generic() +} + +func new512() *state { + return new512Generic() +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf.go new file mode 100644 index 000000000000..ce48b1dd3edd --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf.go @@ -0,0 +1,414 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !amd64 || purego || !gc + +package sha3 + +import "math/bits" + +// rc stores the round constants for use in the ι step. +var rc = [24]uint64{ + 0x0000000000000001, + 0x0000000000008082, + 0x800000000000808A, + 0x8000000080008000, + 0x000000000000808B, + 0x0000000080000001, + 0x8000000080008081, + 0x8000000000008009, + 0x000000000000008A, + 0x0000000000000088, + 0x0000000080008009, + 0x000000008000000A, + 0x000000008000808B, + 0x800000000000008B, + 0x8000000000008089, + 0x8000000000008003, + 0x8000000000008002, + 0x8000000000000080, + 0x000000000000800A, + 0x800000008000000A, + 0x8000000080008081, + 0x8000000000008080, + 0x0000000080000001, + 0x8000000080008008, +} + +// keccakF1600 applies the Keccak permutation to a 1600b-wide +// state represented as a slice of 25 uint64s. +func keccakF1600(a *[25]uint64) { + // Implementation translated from Keccak-inplace.c + // in the keccak reference code. + var t, bc0, bc1, bc2, bc3, bc4, d0, d1, d2, d3, d4 uint64 + + for i := 0; i < 24; i += 4 { + // Combines the 5 steps in each round into 2 steps. + // Unrolls 4 rounds per loop and spreads some steps across rounds. + + // Round 1 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[6] ^ d1 + bc1 = bits.RotateLeft64(t, 44) + t = a[12] ^ d2 + bc2 = bits.RotateLeft64(t, 43) + t = a[18] ^ d3 + bc3 = bits.RotateLeft64(t, 21) + t = a[24] ^ d4 + bc4 = bits.RotateLeft64(t, 14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i] + a[6] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc2 = bits.RotateLeft64(t, 3) + t = a[16] ^ d1 + bc3 = bits.RotateLeft64(t, 45) + t = a[22] ^ d2 + bc4 = bits.RotateLeft64(t, 61) + t = a[3] ^ d3 + bc0 = bits.RotateLeft64(t, 28) + t = a[9] ^ d4 + bc1 = bits.RotateLeft64(t, 20) + a[10] = bc0 ^ (bc2 &^ bc1) + a[16] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc4 = bits.RotateLeft64(t, 18) + t = a[1] ^ d1 + bc0 = bits.RotateLeft64(t, 1) + t = a[7] ^ d2 + bc1 = bits.RotateLeft64(t, 6) + t = a[13] ^ d3 + bc2 = bits.RotateLeft64(t, 25) + t = a[19] ^ d4 + bc3 = bits.RotateLeft64(t, 8) + a[20] = bc0 ^ (bc2 &^ bc1) + a[1] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc1 = bits.RotateLeft64(t, 36) + t = a[11] ^ d1 + bc2 = bits.RotateLeft64(t, 10) + t = a[17] ^ d2 + bc3 = bits.RotateLeft64(t, 15) + t = a[23] ^ d3 + bc4 = bits.RotateLeft64(t, 56) + t = a[4] ^ d4 + bc0 = bits.RotateLeft64(t, 27) + a[5] = bc0 ^ (bc2 &^ bc1) + a[11] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc3 = bits.RotateLeft64(t, 41) + t = a[21] ^ d1 + bc4 = bits.RotateLeft64(t, 2) + t = a[2] ^ d2 + bc0 = bits.RotateLeft64(t, 62) + t = a[8] ^ d3 + bc1 = bits.RotateLeft64(t, 55) + t = a[14] ^ d4 + bc2 = bits.RotateLeft64(t, 39) + a[15] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + // Round 2 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[16] ^ d1 + bc1 = bits.RotateLeft64(t, 44) + t = a[7] ^ d2 + bc2 = bits.RotateLeft64(t, 43) + t = a[23] ^ d3 + bc3 = bits.RotateLeft64(t, 21) + t = a[14] ^ d4 + bc4 = bits.RotateLeft64(t, 14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+1] + a[16] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc2 = bits.RotateLeft64(t, 3) + t = a[11] ^ d1 + bc3 = bits.RotateLeft64(t, 45) + t = a[2] ^ d2 + bc4 = bits.RotateLeft64(t, 61) + t = a[18] ^ d3 + bc0 = bits.RotateLeft64(t, 28) + t = a[9] ^ d4 + bc1 = bits.RotateLeft64(t, 20) + a[20] = bc0 ^ (bc2 &^ bc1) + a[11] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc4 = bits.RotateLeft64(t, 18) + t = a[6] ^ d1 + bc0 = bits.RotateLeft64(t, 1) + t = a[22] ^ d2 + bc1 = bits.RotateLeft64(t, 6) + t = a[13] ^ d3 + bc2 = bits.RotateLeft64(t, 25) + t = a[4] ^ d4 + bc3 = bits.RotateLeft64(t, 8) + a[15] = bc0 ^ (bc2 &^ bc1) + a[6] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc1 = bits.RotateLeft64(t, 36) + t = a[1] ^ d1 + bc2 = bits.RotateLeft64(t, 10) + t = a[17] ^ d2 + bc3 = bits.RotateLeft64(t, 15) + t = a[8] ^ d3 + bc4 = bits.RotateLeft64(t, 56) + t = a[24] ^ d4 + bc0 = bits.RotateLeft64(t, 27) + a[10] = bc0 ^ (bc2 &^ bc1) + a[1] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc3 = bits.RotateLeft64(t, 41) + t = a[21] ^ d1 + bc4 = bits.RotateLeft64(t, 2) + t = a[12] ^ d2 + bc0 = bits.RotateLeft64(t, 62) + t = a[3] ^ d3 + bc1 = bits.RotateLeft64(t, 55) + t = a[19] ^ d4 + bc2 = bits.RotateLeft64(t, 39) + a[5] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + // Round 3 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[11] ^ d1 + bc1 = bits.RotateLeft64(t, 44) + t = a[22] ^ d2 + bc2 = bits.RotateLeft64(t, 43) + t = a[8] ^ d3 + bc3 = bits.RotateLeft64(t, 21) + t = a[19] ^ d4 + bc4 = bits.RotateLeft64(t, 14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+2] + a[11] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc2 = bits.RotateLeft64(t, 3) + t = a[1] ^ d1 + bc3 = bits.RotateLeft64(t, 45) + t = a[12] ^ d2 + bc4 = bits.RotateLeft64(t, 61) + t = a[23] ^ d3 + bc0 = bits.RotateLeft64(t, 28) + t = a[9] ^ d4 + bc1 = bits.RotateLeft64(t, 20) + a[15] = bc0 ^ (bc2 &^ bc1) + a[1] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc4 = bits.RotateLeft64(t, 18) + t = a[16] ^ d1 + bc0 = bits.RotateLeft64(t, 1) + t = a[2] ^ d2 + bc1 = bits.RotateLeft64(t, 6) + t = a[13] ^ d3 + bc2 = bits.RotateLeft64(t, 25) + t = a[24] ^ d4 + bc3 = bits.RotateLeft64(t, 8) + a[5] = bc0 ^ (bc2 &^ bc1) + a[16] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc1 = bits.RotateLeft64(t, 36) + t = a[6] ^ d1 + bc2 = bits.RotateLeft64(t, 10) + t = a[17] ^ d2 + bc3 = bits.RotateLeft64(t, 15) + t = a[3] ^ d3 + bc4 = bits.RotateLeft64(t, 56) + t = a[14] ^ d4 + bc0 = bits.RotateLeft64(t, 27) + a[20] = bc0 ^ (bc2 &^ bc1) + a[6] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc3 = bits.RotateLeft64(t, 41) + t = a[21] ^ d1 + bc4 = bits.RotateLeft64(t, 2) + t = a[7] ^ d2 + bc0 = bits.RotateLeft64(t, 62) + t = a[18] ^ d3 + bc1 = bits.RotateLeft64(t, 55) + t = a[4] ^ d4 + bc2 = bits.RotateLeft64(t, 39) + a[10] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + // Round 4 + bc0 = a[0] ^ a[5] ^ a[10] ^ a[15] ^ a[20] + bc1 = a[1] ^ a[6] ^ a[11] ^ a[16] ^ a[21] + bc2 = a[2] ^ a[7] ^ a[12] ^ a[17] ^ a[22] + bc3 = a[3] ^ a[8] ^ a[13] ^ a[18] ^ a[23] + bc4 = a[4] ^ a[9] ^ a[14] ^ a[19] ^ a[24] + d0 = bc4 ^ (bc1<<1 | bc1>>63) + d1 = bc0 ^ (bc2<<1 | bc2>>63) + d2 = bc1 ^ (bc3<<1 | bc3>>63) + d3 = bc2 ^ (bc4<<1 | bc4>>63) + d4 = bc3 ^ (bc0<<1 | bc0>>63) + + bc0 = a[0] ^ d0 + t = a[1] ^ d1 + bc1 = bits.RotateLeft64(t, 44) + t = a[2] ^ d2 + bc2 = bits.RotateLeft64(t, 43) + t = a[3] ^ d3 + bc3 = bits.RotateLeft64(t, 21) + t = a[4] ^ d4 + bc4 = bits.RotateLeft64(t, 14) + a[0] = bc0 ^ (bc2 &^ bc1) ^ rc[i+3] + a[1] = bc1 ^ (bc3 &^ bc2) + a[2] = bc2 ^ (bc4 &^ bc3) + a[3] = bc3 ^ (bc0 &^ bc4) + a[4] = bc4 ^ (bc1 &^ bc0) + + t = a[5] ^ d0 + bc2 = bits.RotateLeft64(t, 3) + t = a[6] ^ d1 + bc3 = bits.RotateLeft64(t, 45) + t = a[7] ^ d2 + bc4 = bits.RotateLeft64(t, 61) + t = a[8] ^ d3 + bc0 = bits.RotateLeft64(t, 28) + t = a[9] ^ d4 + bc1 = bits.RotateLeft64(t, 20) + a[5] = bc0 ^ (bc2 &^ bc1) + a[6] = bc1 ^ (bc3 &^ bc2) + a[7] = bc2 ^ (bc4 &^ bc3) + a[8] = bc3 ^ (bc0 &^ bc4) + a[9] = bc4 ^ (bc1 &^ bc0) + + t = a[10] ^ d0 + bc4 = bits.RotateLeft64(t, 18) + t = a[11] ^ d1 + bc0 = bits.RotateLeft64(t, 1) + t = a[12] ^ d2 + bc1 = bits.RotateLeft64(t, 6) + t = a[13] ^ d3 + bc2 = bits.RotateLeft64(t, 25) + t = a[14] ^ d4 + bc3 = bits.RotateLeft64(t, 8) + a[10] = bc0 ^ (bc2 &^ bc1) + a[11] = bc1 ^ (bc3 &^ bc2) + a[12] = bc2 ^ (bc4 &^ bc3) + a[13] = bc3 ^ (bc0 &^ bc4) + a[14] = bc4 ^ (bc1 &^ bc0) + + t = a[15] ^ d0 + bc1 = bits.RotateLeft64(t, 36) + t = a[16] ^ d1 + bc2 = bits.RotateLeft64(t, 10) + t = a[17] ^ d2 + bc3 = bits.RotateLeft64(t, 15) + t = a[18] ^ d3 + bc4 = bits.RotateLeft64(t, 56) + t = a[19] ^ d4 + bc0 = bits.RotateLeft64(t, 27) + a[15] = bc0 ^ (bc2 &^ bc1) + a[16] = bc1 ^ (bc3 &^ bc2) + a[17] = bc2 ^ (bc4 &^ bc3) + a[18] = bc3 ^ (bc0 &^ bc4) + a[19] = bc4 ^ (bc1 &^ bc0) + + t = a[20] ^ d0 + bc3 = bits.RotateLeft64(t, 41) + t = a[21] ^ d1 + bc4 = bits.RotateLeft64(t, 2) + t = a[22] ^ d2 + bc0 = bits.RotateLeft64(t, 62) + t = a[23] ^ d3 + bc1 = bits.RotateLeft64(t, 55) + t = a[24] ^ d4 + bc2 = bits.RotateLeft64(t, 39) + a[20] = bc0 ^ (bc2 &^ bc1) + a[21] = bc1 ^ (bc3 &^ bc2) + a[22] = bc2 ^ (bc4 &^ bc3) + a[23] = bc3 ^ (bc0 &^ bc4) + a[24] = bc4 ^ (bc1 &^ bc0) + } +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf_amd64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf_amd64.go new file mode 100644 index 000000000000..b908696be58f --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf_amd64.go @@ -0,0 +1,13 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build amd64 && !purego && gc + +package sha3 + +// This function is implemented in keccakf_amd64.s. + +//go:noescape + +func keccakF1600(a *[25]uint64) diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf_amd64.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf_amd64.s new file mode 100644 index 000000000000..1f5393886197 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/keccakf_amd64.s @@ -0,0 +1,390 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build amd64 && !purego && gc + +// This code was translated into a form compatible with 6a from the public +// domain sources at https://github.com/gvanas/KeccakCodePackage + +// Offsets in state +#define _ba (0*8) +#define _be (1*8) +#define _bi (2*8) +#define _bo (3*8) +#define _bu (4*8) +#define _ga (5*8) +#define _ge (6*8) +#define _gi (7*8) +#define _go (8*8) +#define _gu (9*8) +#define _ka (10*8) +#define _ke (11*8) +#define _ki (12*8) +#define _ko (13*8) +#define _ku (14*8) +#define _ma (15*8) +#define _me (16*8) +#define _mi (17*8) +#define _mo (18*8) +#define _mu (19*8) +#define _sa (20*8) +#define _se (21*8) +#define _si (22*8) +#define _so (23*8) +#define _su (24*8) + +// Temporary registers +#define rT1 AX + +// Round vars +#define rpState DI +#define rpStack SP + +#define rDa BX +#define rDe CX +#define rDi DX +#define rDo R8 +#define rDu R9 + +#define rBa R10 +#define rBe R11 +#define rBi R12 +#define rBo R13 +#define rBu R14 + +#define rCa SI +#define rCe BP +#define rCi rBi +#define rCo rBo +#define rCu R15 + +#define MOVQ_RBI_RCE MOVQ rBi, rCe +#define XORQ_RT1_RCA XORQ rT1, rCa +#define XORQ_RT1_RCE XORQ rT1, rCe +#define XORQ_RBA_RCU XORQ rBa, rCu +#define XORQ_RBE_RCU XORQ rBe, rCu +#define XORQ_RDU_RCU XORQ rDu, rCu +#define XORQ_RDA_RCA XORQ rDa, rCa +#define XORQ_RDE_RCE XORQ rDe, rCe + +#define mKeccakRound(iState, oState, rc, B_RBI_RCE, G_RT1_RCA, G_RT1_RCE, G_RBA_RCU, K_RT1_RCA, K_RT1_RCE, K_RBA_RCU, M_RT1_RCA, M_RT1_RCE, M_RBE_RCU, S_RDU_RCU, S_RDA_RCA, S_RDE_RCE) \ + /* Prepare round */ \ + MOVQ rCe, rDa; \ + ROLQ $1, rDa; \ + \ + MOVQ _bi(iState), rCi; \ + XORQ _gi(iState), rDi; \ + XORQ rCu, rDa; \ + XORQ _ki(iState), rCi; \ + XORQ _mi(iState), rDi; \ + XORQ rDi, rCi; \ + \ + MOVQ rCi, rDe; \ + ROLQ $1, rDe; \ + \ + MOVQ _bo(iState), rCo; \ + XORQ _go(iState), rDo; \ + XORQ rCa, rDe; \ + XORQ _ko(iState), rCo; \ + XORQ _mo(iState), rDo; \ + XORQ rDo, rCo; \ + \ + MOVQ rCo, rDi; \ + ROLQ $1, rDi; \ + \ + MOVQ rCu, rDo; \ + XORQ rCe, rDi; \ + ROLQ $1, rDo; \ + \ + MOVQ rCa, rDu; \ + XORQ rCi, rDo; \ + ROLQ $1, rDu; \ + \ + /* Result b */ \ + MOVQ _ba(iState), rBa; \ + MOVQ _ge(iState), rBe; \ + XORQ rCo, rDu; \ + MOVQ _ki(iState), rBi; \ + MOVQ _mo(iState), rBo; \ + MOVQ _su(iState), rBu; \ + XORQ rDe, rBe; \ + ROLQ $44, rBe; \ + XORQ rDi, rBi; \ + XORQ rDa, rBa; \ + ROLQ $43, rBi; \ + \ + MOVQ rBe, rCa; \ + MOVQ rc, rT1; \ + ORQ rBi, rCa; \ + XORQ rBa, rT1; \ + XORQ rT1, rCa; \ + MOVQ rCa, _ba(oState); \ + \ + XORQ rDu, rBu; \ + ROLQ $14, rBu; \ + MOVQ rBa, rCu; \ + ANDQ rBe, rCu; \ + XORQ rBu, rCu; \ + MOVQ rCu, _bu(oState); \ + \ + XORQ rDo, rBo; \ + ROLQ $21, rBo; \ + MOVQ rBo, rT1; \ + ANDQ rBu, rT1; \ + XORQ rBi, rT1; \ + MOVQ rT1, _bi(oState); \ + \ + NOTQ rBi; \ + ORQ rBa, rBu; \ + ORQ rBo, rBi; \ + XORQ rBo, rBu; \ + XORQ rBe, rBi; \ + MOVQ rBu, _bo(oState); \ + MOVQ rBi, _be(oState); \ + B_RBI_RCE; \ + \ + /* Result g */ \ + MOVQ _gu(iState), rBe; \ + XORQ rDu, rBe; \ + MOVQ _ka(iState), rBi; \ + ROLQ $20, rBe; \ + XORQ rDa, rBi; \ + ROLQ $3, rBi; \ + MOVQ _bo(iState), rBa; \ + MOVQ rBe, rT1; \ + ORQ rBi, rT1; \ + XORQ rDo, rBa; \ + MOVQ _me(iState), rBo; \ + MOVQ _si(iState), rBu; \ + ROLQ $28, rBa; \ + XORQ rBa, rT1; \ + MOVQ rT1, _ga(oState); \ + G_RT1_RCA; \ + \ + XORQ rDe, rBo; \ + ROLQ $45, rBo; \ + MOVQ rBi, rT1; \ + ANDQ rBo, rT1; \ + XORQ rBe, rT1; \ + MOVQ rT1, _ge(oState); \ + G_RT1_RCE; \ + \ + XORQ rDi, rBu; \ + ROLQ $61, rBu; \ + MOVQ rBu, rT1; \ + ORQ rBa, rT1; \ + XORQ rBo, rT1; \ + MOVQ rT1, _go(oState); \ + \ + ANDQ rBe, rBa; \ + XORQ rBu, rBa; \ + MOVQ rBa, _gu(oState); \ + NOTQ rBu; \ + G_RBA_RCU; \ + \ + ORQ rBu, rBo; \ + XORQ rBi, rBo; \ + MOVQ rBo, _gi(oState); \ + \ + /* Result k */ \ + MOVQ _be(iState), rBa; \ + MOVQ _gi(iState), rBe; \ + MOVQ _ko(iState), rBi; \ + MOVQ _mu(iState), rBo; \ + MOVQ _sa(iState), rBu; \ + XORQ rDi, rBe; \ + ROLQ $6, rBe; \ + XORQ rDo, rBi; \ + ROLQ $25, rBi; \ + MOVQ rBe, rT1; \ + ORQ rBi, rT1; \ + XORQ rDe, rBa; \ + ROLQ $1, rBa; \ + XORQ rBa, rT1; \ + MOVQ rT1, _ka(oState); \ + K_RT1_RCA; \ + \ + XORQ rDu, rBo; \ + ROLQ $8, rBo; \ + MOVQ rBi, rT1; \ + ANDQ rBo, rT1; \ + XORQ rBe, rT1; \ + MOVQ rT1, _ke(oState); \ + K_RT1_RCE; \ + \ + XORQ rDa, rBu; \ + ROLQ $18, rBu; \ + NOTQ rBo; \ + MOVQ rBo, rT1; \ + ANDQ rBu, rT1; \ + XORQ rBi, rT1; \ + MOVQ rT1, _ki(oState); \ + \ + MOVQ rBu, rT1; \ + ORQ rBa, rT1; \ + XORQ rBo, rT1; \ + MOVQ rT1, _ko(oState); \ + \ + ANDQ rBe, rBa; \ + XORQ rBu, rBa; \ + MOVQ rBa, _ku(oState); \ + K_RBA_RCU; \ + \ + /* Result m */ \ + MOVQ _ga(iState), rBe; \ + XORQ rDa, rBe; \ + MOVQ _ke(iState), rBi; \ + ROLQ $36, rBe; \ + XORQ rDe, rBi; \ + MOVQ _bu(iState), rBa; \ + ROLQ $10, rBi; \ + MOVQ rBe, rT1; \ + MOVQ _mi(iState), rBo; \ + ANDQ rBi, rT1; \ + XORQ rDu, rBa; \ + MOVQ _so(iState), rBu; \ + ROLQ $27, rBa; \ + XORQ rBa, rT1; \ + MOVQ rT1, _ma(oState); \ + M_RT1_RCA; \ + \ + XORQ rDi, rBo; \ + ROLQ $15, rBo; \ + MOVQ rBi, rT1; \ + ORQ rBo, rT1; \ + XORQ rBe, rT1; \ + MOVQ rT1, _me(oState); \ + M_RT1_RCE; \ + \ + XORQ rDo, rBu; \ + ROLQ $56, rBu; \ + NOTQ rBo; \ + MOVQ rBo, rT1; \ + ORQ rBu, rT1; \ + XORQ rBi, rT1; \ + MOVQ rT1, _mi(oState); \ + \ + ORQ rBa, rBe; \ + XORQ rBu, rBe; \ + MOVQ rBe, _mu(oState); \ + \ + ANDQ rBa, rBu; \ + XORQ rBo, rBu; \ + MOVQ rBu, _mo(oState); \ + M_RBE_RCU; \ + \ + /* Result s */ \ + MOVQ _bi(iState), rBa; \ + MOVQ _go(iState), rBe; \ + MOVQ _ku(iState), rBi; \ + XORQ rDi, rBa; \ + MOVQ _ma(iState), rBo; \ + ROLQ $62, rBa; \ + XORQ rDo, rBe; \ + MOVQ _se(iState), rBu; \ + ROLQ $55, rBe; \ + \ + XORQ rDu, rBi; \ + MOVQ rBa, rDu; \ + XORQ rDe, rBu; \ + ROLQ $2, rBu; \ + ANDQ rBe, rDu; \ + XORQ rBu, rDu; \ + MOVQ rDu, _su(oState); \ + \ + ROLQ $39, rBi; \ + S_RDU_RCU; \ + NOTQ rBe; \ + XORQ rDa, rBo; \ + MOVQ rBe, rDa; \ + ANDQ rBi, rDa; \ + XORQ rBa, rDa; \ + MOVQ rDa, _sa(oState); \ + S_RDA_RCA; \ + \ + ROLQ $41, rBo; \ + MOVQ rBi, rDe; \ + ORQ rBo, rDe; \ + XORQ rBe, rDe; \ + MOVQ rDe, _se(oState); \ + S_RDE_RCE; \ + \ + MOVQ rBo, rDi; \ + MOVQ rBu, rDo; \ + ANDQ rBu, rDi; \ + ORQ rBa, rDo; \ + XORQ rBi, rDi; \ + XORQ rBo, rDo; \ + MOVQ rDi, _si(oState); \ + MOVQ rDo, _so(oState) \ + +// func keccakF1600(a *[25]uint64) +TEXT ·keccakF1600(SB), 0, $200-8 + MOVQ a+0(FP), rpState + + // Convert the user state into an internal state + NOTQ _be(rpState) + NOTQ _bi(rpState) + NOTQ _go(rpState) + NOTQ _ki(rpState) + NOTQ _mi(rpState) + NOTQ _sa(rpState) + + // Execute the KeccakF permutation + MOVQ _ba(rpState), rCa + MOVQ _be(rpState), rCe + MOVQ _bu(rpState), rCu + + XORQ _ga(rpState), rCa + XORQ _ge(rpState), rCe + XORQ _gu(rpState), rCu + + XORQ _ka(rpState), rCa + XORQ _ke(rpState), rCe + XORQ _ku(rpState), rCu + + XORQ _ma(rpState), rCa + XORQ _me(rpState), rCe + XORQ _mu(rpState), rCu + + XORQ _sa(rpState), rCa + XORQ _se(rpState), rCe + MOVQ _si(rpState), rDi + MOVQ _so(rpState), rDo + XORQ _su(rpState), rCu + + mKeccakRound(rpState, rpStack, $0x0000000000000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x0000000000008082, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x800000000000808a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000080008000, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000000000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000000000008a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x0000000000000088, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x0000000080008009, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x000000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000008000808b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x800000000000008b, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000000008089, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000008003, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000000008002, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000000080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x000000000000800a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x800000008000000a, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x8000000080008081, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000000008080, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpState, rpStack, $0x0000000080000001, MOVQ_RBI_RCE, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBA_RCU, XORQ_RT1_RCA, XORQ_RT1_RCE, XORQ_RBE_RCU, XORQ_RDU_RCU, XORQ_RDA_RCA, XORQ_RDE_RCE) + mKeccakRound(rpStack, rpState, $0x8000000080008008, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP) + + // Revert the internal state to the user state + NOTQ _be(rpState) + NOTQ _bi(rpState) + NOTQ _go(rpState) + NOTQ _ki(rpState) + NOTQ _mi(rpState) + NOTQ _sa(rpState) + + RET diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/register.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/register.go new file mode 100644 index 000000000000..addfd5049bb9 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/register.go @@ -0,0 +1,18 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.4 + +package sha3 + +import ( + "crypto" +) + +func init() { + crypto.RegisterHash(crypto.SHA3_224, New224) + crypto.RegisterHash(crypto.SHA3_256, New256) + crypto.RegisterHash(crypto.SHA3_384, New384) + crypto.RegisterHash(crypto.SHA3_512, New512) +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3.go new file mode 100644 index 000000000000..afedde5abf1f --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3.go @@ -0,0 +1,185 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sha3 + +// spongeDirection indicates the direction bytes are flowing through the sponge. +type spongeDirection int + +const ( + // spongeAbsorbing indicates that the sponge is absorbing input. + spongeAbsorbing spongeDirection = iota + // spongeSqueezing indicates that the sponge is being squeezed. + spongeSqueezing +) + +const ( + // maxRate is the maximum size of the internal buffer. SHAKE-256 + // currently needs the largest buffer. + maxRate = 168 +) + +type state struct { + // Generic sponge components. + a [25]uint64 // main state of the hash + rate int // the number of bytes of state to use + + // dsbyte contains the "domain separation" bits and the first bit of + // the padding. Sections 6.1 and 6.2 of [1] separate the outputs of the + // SHA-3 and SHAKE functions by appending bitstrings to the message. + // Using a little-endian bit-ordering convention, these are "01" for SHA-3 + // and "1111" for SHAKE, or 00000010b and 00001111b, respectively. Then the + // padding rule from section 5.1 is applied to pad the message to a multiple + // of the rate, which involves adding a "1" bit, zero or more "0" bits, and + // a final "1" bit. We merge the first "1" bit from the padding into dsbyte, + // giving 00000110b (0x06) and 00011111b (0x1f). + // [1] http://csrc.nist.gov/publications/drafts/fips-202/fips_202_draft.pdf + // "Draft FIPS 202: SHA-3 Standard: Permutation-Based Hash and + // Extendable-Output Functions (May 2014)" + dsbyte byte + + i, n int // storage[i:n] is the buffer, i is only used while squeezing + storage [maxRate]byte + + // Specific to SHA-3 and SHAKE. + outputLen int // the default output size in bytes + state spongeDirection // whether the sponge is absorbing or squeezing +} + +// BlockSize returns the rate of sponge underlying this hash function. +func (d *state) BlockSize() int { return d.rate } + +// Size returns the output size of the hash function in bytes. +func (d *state) Size() int { return d.outputLen } + +// Reset clears the internal state by zeroing the sponge state and +// the buffer indexes, and setting Sponge.state to absorbing. +func (d *state) Reset() { + // Zero the permutation's state. + for i := range d.a { + d.a[i] = 0 + } + d.state = spongeAbsorbing + d.i, d.n = 0, 0 +} + +func (d *state) clone() *state { + ret := *d + return &ret +} + +// permute applies the KeccakF-1600 permutation. It handles +// any input-output buffering. +func (d *state) permute() { + switch d.state { + case spongeAbsorbing: + // If we're absorbing, we need to xor the input into the state + // before applying the permutation. + xorIn(d, d.storage[:d.rate]) + d.n = 0 + keccakF1600(&d.a) + case spongeSqueezing: + // If we're squeezing, we need to apply the permutation before + // copying more output. + keccakF1600(&d.a) + d.i = 0 + copyOut(d, d.storage[:d.rate]) + } +} + +// pads appends the domain separation bits in dsbyte, applies +// the multi-bitrate 10..1 padding rule, and permutes the state. +func (d *state) padAndPermute() { + // Pad with this instance's domain-separator bits. We know that there's + // at least one byte of space in d.buf because, if it were full, + // permute would have been called to empty it. dsbyte also contains the + // first one bit for the padding. See the comment in the state struct. + d.storage[d.n] = d.dsbyte + d.n++ + for d.n < d.rate { + d.storage[d.n] = 0 + d.n++ + } + // This adds the final one bit for the padding. Because of the way that + // bits are numbered from the LSB upwards, the final bit is the MSB of + // the last byte. + d.storage[d.rate-1] ^= 0x80 + // Apply the permutation + d.permute() + d.state = spongeSqueezing + d.n = d.rate + copyOut(d, d.storage[:d.rate]) +} + +// Write absorbs more data into the hash's state. It panics if any +// output has already been read. +func (d *state) Write(p []byte) (written int, err error) { + if d.state != spongeAbsorbing { + panic("sha3: Write after Read") + } + written = len(p) + + for len(p) > 0 { + if d.n == 0 && len(p) >= d.rate { + // The fast path; absorb a full "rate" bytes of input and apply the permutation. + xorIn(d, p[:d.rate]) + p = p[d.rate:] + keccakF1600(&d.a) + } else { + // The slow path; buffer the input until we can fill the sponge, and then xor it in. + todo := d.rate - d.n + if todo > len(p) { + todo = len(p) + } + d.n += copy(d.storage[d.n:], p[:todo]) + p = p[todo:] + + // If the sponge is full, apply the permutation. + if d.n == d.rate { + d.permute() + } + } + } + + return +} + +// Read squeezes an arbitrary number of bytes from the sponge. +func (d *state) Read(out []byte) (n int, err error) { + // If we're still absorbing, pad and apply the permutation. + if d.state == spongeAbsorbing { + d.padAndPermute() + } + + n = len(out) + + // Now, do the squeezing. + for len(out) > 0 { + n := copy(out, d.storage[d.i:d.n]) + d.i += n + out = out[n:] + + // Apply the permutation if we've squeezed the sponge dry. + if d.i == d.rate { + d.permute() + } + } + + return +} + +// Sum applies padding to the hash state and then squeezes out the desired +// number of output bytes. It panics if any output has already been read. +func (d *state) Sum(in []byte) []byte { + if d.state != spongeAbsorbing { + panic("sha3: Sum after Read") + } + + // Make a copy of the original hash so that caller can keep writing + // and summing. + dup := d.clone() + hash := make([]byte, dup.outputLen, 64) // explicit cap to allow stack allocation + dup.Read(hash) + return append(in, hash...) +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3_s390x.go new file mode 100644 index 000000000000..00d8034ae627 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3_s390x.go @@ -0,0 +1,303 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc && !purego + +package sha3 + +// This file contains code for using the 'compute intermediate +// message digest' (KIMD) and 'compute last message digest' (KLMD) +// instructions to compute SHA-3 and SHAKE hashes on IBM Z. + +import ( + "hash" + + "golang.org/x/sys/cpu" +) + +// codes represent 7-bit KIMD/KLMD function codes as defined in +// the Principles of Operation. +type code uint64 + +const ( + // function codes for KIMD/KLMD + sha3_224 code = 32 + sha3_256 = 33 + sha3_384 = 34 + sha3_512 = 35 + shake_128 = 36 + shake_256 = 37 + nopad = 0x100 +) + +// kimd is a wrapper for the 'compute intermediate message digest' instruction. +// src must be a multiple of the rate for the given function code. +// +//go:noescape +func kimd(function code, chain *[200]byte, src []byte) + +// klmd is a wrapper for the 'compute last message digest' instruction. +// src padding is handled by the instruction. +// +//go:noescape +func klmd(function code, chain *[200]byte, dst, src []byte) + +type asmState struct { + a [200]byte // 1600 bit state + buf []byte // care must be taken to ensure cap(buf) is a multiple of rate + rate int // equivalent to block size + storage [3072]byte // underlying storage for buf + outputLen int // output length for full security + function code // KIMD/KLMD function code + state spongeDirection // whether the sponge is absorbing or squeezing +} + +func newAsmState(function code) *asmState { + var s asmState + s.function = function + switch function { + case sha3_224: + s.rate = 144 + s.outputLen = 28 + case sha3_256: + s.rate = 136 + s.outputLen = 32 + case sha3_384: + s.rate = 104 + s.outputLen = 48 + case sha3_512: + s.rate = 72 + s.outputLen = 64 + case shake_128: + s.rate = 168 + s.outputLen = 32 + case shake_256: + s.rate = 136 + s.outputLen = 64 + default: + panic("sha3: unrecognized function code") + } + + // limit s.buf size to a multiple of s.rate + s.resetBuf() + return &s +} + +func (s *asmState) clone() *asmState { + c := *s + c.buf = c.storage[:len(s.buf):cap(s.buf)] + return &c +} + +// copyIntoBuf copies b into buf. It will panic if there is not enough space to +// store all of b. +func (s *asmState) copyIntoBuf(b []byte) { + bufLen := len(s.buf) + s.buf = s.buf[:len(s.buf)+len(b)] + copy(s.buf[bufLen:], b) +} + +// resetBuf points buf at storage, sets the length to 0 and sets cap to be a +// multiple of the rate. +func (s *asmState) resetBuf() { + max := (cap(s.storage) / s.rate) * s.rate + s.buf = s.storage[:0:max] +} + +// Write (via the embedded io.Writer interface) adds more data to the running hash. +// It never returns an error. +func (s *asmState) Write(b []byte) (int, error) { + if s.state != spongeAbsorbing { + panic("sha3: Write after Read") + } + length := len(b) + for len(b) > 0 { + if len(s.buf) == 0 && len(b) >= cap(s.buf) { + // Hash the data directly and push any remaining bytes + // into the buffer. + remainder := len(b) % s.rate + kimd(s.function, &s.a, b[:len(b)-remainder]) + if remainder != 0 { + s.copyIntoBuf(b[len(b)-remainder:]) + } + return length, nil + } + + if len(s.buf) == cap(s.buf) { + // flush the buffer + kimd(s.function, &s.a, s.buf) + s.buf = s.buf[:0] + } + + // copy as much as we can into the buffer + n := len(b) + if len(b) > cap(s.buf)-len(s.buf) { + n = cap(s.buf) - len(s.buf) + } + s.copyIntoBuf(b[:n]) + b = b[n:] + } + return length, nil +} + +// Read squeezes an arbitrary number of bytes from the sponge. +func (s *asmState) Read(out []byte) (n int, err error) { + // The 'compute last message digest' instruction only stores the digest + // at the first operand (dst) for SHAKE functions. + if s.function != shake_128 && s.function != shake_256 { + panic("sha3: can only call Read for SHAKE functions") + } + + n = len(out) + + // need to pad if we were absorbing + if s.state == spongeAbsorbing { + s.state = spongeSqueezing + + // write hash directly into out if possible + if len(out)%s.rate == 0 { + klmd(s.function, &s.a, out, s.buf) // len(out) may be 0 + s.buf = s.buf[:0] + return + } + + // write hash into buffer + max := cap(s.buf) + if max > len(out) { + max = (len(out)/s.rate)*s.rate + s.rate + } + klmd(s.function, &s.a, s.buf[:max], s.buf) + s.buf = s.buf[:max] + } + + for len(out) > 0 { + // flush the buffer + if len(s.buf) != 0 { + c := copy(out, s.buf) + out = out[c:] + s.buf = s.buf[c:] + continue + } + + // write hash directly into out if possible + if len(out)%s.rate == 0 { + klmd(s.function|nopad, &s.a, out, nil) + return + } + + // write hash into buffer + s.resetBuf() + if cap(s.buf) > len(out) { + s.buf = s.buf[:(len(out)/s.rate)*s.rate+s.rate] + } + klmd(s.function|nopad, &s.a, s.buf, nil) + } + return +} + +// Sum appends the current hash to b and returns the resulting slice. +// It does not change the underlying hash state. +func (s *asmState) Sum(b []byte) []byte { + if s.state != spongeAbsorbing { + panic("sha3: Sum after Read") + } + + // Copy the state to preserve the original. + a := s.a + + // Hash the buffer. Note that we don't clear it because we + // aren't updating the state. + switch s.function { + case sha3_224, sha3_256, sha3_384, sha3_512: + klmd(s.function, &a, nil, s.buf) + return append(b, a[:s.outputLen]...) + case shake_128, shake_256: + d := make([]byte, s.outputLen, 64) + klmd(s.function, &a, d, s.buf) + return append(b, d[:s.outputLen]...) + default: + panic("sha3: unknown function") + } +} + +// Reset resets the Hash to its initial state. +func (s *asmState) Reset() { + for i := range s.a { + s.a[i] = 0 + } + s.resetBuf() + s.state = spongeAbsorbing +} + +// Size returns the number of bytes Sum will return. +func (s *asmState) Size() int { + return s.outputLen +} + +// BlockSize returns the hash's underlying block size. +// The Write method must be able to accept any amount +// of data, but it may operate more efficiently if all writes +// are a multiple of the block size. +func (s *asmState) BlockSize() int { + return s.rate +} + +// Clone returns a copy of the ShakeHash in its current state. +func (s *asmState) Clone() ShakeHash { + return s.clone() +} + +// new224 returns an assembly implementation of SHA3-224 if available, +// otherwise it returns a generic implementation. +func new224() hash.Hash { + if cpu.S390X.HasSHA3 { + return newAsmState(sha3_224) + } + return new224Generic() +} + +// new256 returns an assembly implementation of SHA3-256 if available, +// otherwise it returns a generic implementation. +func new256() hash.Hash { + if cpu.S390X.HasSHA3 { + return newAsmState(sha3_256) + } + return new256Generic() +} + +// new384 returns an assembly implementation of SHA3-384 if available, +// otherwise it returns a generic implementation. +func new384() hash.Hash { + if cpu.S390X.HasSHA3 { + return newAsmState(sha3_384) + } + return new384Generic() +} + +// new512 returns an assembly implementation of SHA3-512 if available, +// otherwise it returns a generic implementation. +func new512() hash.Hash { + if cpu.S390X.HasSHA3 { + return newAsmState(sha3_512) + } + return new512Generic() +} + +// newShake128 returns an assembly implementation of SHAKE-128 if available, +// otherwise it returns a generic implementation. +func newShake128() ShakeHash { + if cpu.S390X.HasSHA3 { + return newAsmState(shake_128) + } + return newShake128Generic() +} + +// newShake256 returns an assembly implementation of SHAKE-256 if available, +// otherwise it returns a generic implementation. +func newShake256() ShakeHash { + if cpu.S390X.HasSHA3 { + return newAsmState(shake_256) + } + return newShake256Generic() +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3_s390x.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3_s390x.s new file mode 100644 index 000000000000..826b862c7796 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/sha3_s390x.s @@ -0,0 +1,33 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build gc && !purego + +#include "textflag.h" + +// func kimd(function code, chain *[200]byte, src []byte) +TEXT ·kimd(SB), NOFRAME|NOSPLIT, $0-40 + MOVD function+0(FP), R0 + MOVD chain+8(FP), R1 + LMG src+16(FP), R2, R3 // R2=base, R3=len + +continue: + WORD $0xB93E0002 // KIMD --, R2 + BVS continue // continue if interrupted + MOVD $0, R0 // reset R0 for pre-go1.8 compilers + RET + +// func klmd(function code, chain *[200]byte, dst, src []byte) +TEXT ·klmd(SB), NOFRAME|NOSPLIT, $0-64 + // TODO: SHAKE support + MOVD function+0(FP), R0 + MOVD chain+8(FP), R1 + LMG dst+16(FP), R2, R3 // R2=base, R3=len + LMG src+40(FP), R4, R5 // R4=base, R5=len + +continue: + WORD $0xB93F0024 // KLMD R2, R4 + BVS continue // continue if interrupted + MOVD $0, R0 // reset R0 for pre-go1.8 compilers + RET diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/shake.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/shake.go new file mode 100644 index 000000000000..1ea9275b8b7a --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/shake.go @@ -0,0 +1,174 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sha3 + +// This file defines the ShakeHash interface, and provides +// functions for creating SHAKE and cSHAKE instances, as well as utility +// functions for hashing bytes to arbitrary-length output. +// +// +// SHAKE implementation is based on FIPS PUB 202 [1] +// cSHAKE implementations is based on NIST SP 800-185 [2] +// +// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf +// [2] https://doi.org/10.6028/NIST.SP.800-185 + +import ( + "encoding/binary" + "hash" + "io" +) + +// ShakeHash defines the interface to hash functions that support +// arbitrary-length output. When used as a plain [hash.Hash], it +// produces minimum-length outputs that provide full-strength generic +// security. +type ShakeHash interface { + hash.Hash + + // Read reads more output from the hash; reading affects the hash's + // state. (ShakeHash.Read is thus very different from Hash.Sum) + // It never returns an error, but subsequent calls to Write or Sum + // will panic. + io.Reader + + // Clone returns a copy of the ShakeHash in its current state. + Clone() ShakeHash +} + +// cSHAKE specific context +type cshakeState struct { + *state // SHA-3 state context and Read/Write operations + + // initBlock is the cSHAKE specific initialization set of bytes. It is initialized + // by newCShake function and stores concatenation of N followed by S, encoded + // by the method specified in 3.3 of [1]. + // It is stored here in order for Reset() to be able to put context into + // initial state. + initBlock []byte +} + +// Consts for configuring initial SHA-3 state +const ( + dsbyteShake = 0x1f + dsbyteCShake = 0x04 + rate128 = 168 + rate256 = 136 +) + +func bytepad(input []byte, w int) []byte { + // leftEncode always returns max 9 bytes + buf := make([]byte, 0, 9+len(input)+w) + buf = append(buf, leftEncode(uint64(w))...) + buf = append(buf, input...) + padlen := w - (len(buf) % w) + return append(buf, make([]byte, padlen)...) +} + +func leftEncode(value uint64) []byte { + var b [9]byte + binary.BigEndian.PutUint64(b[1:], value) + // Trim all but last leading zero bytes + i := byte(1) + for i < 8 && b[i] == 0 { + i++ + } + // Prepend number of encoded bytes + b[i-1] = 9 - i + return b[i-1:] +} + +func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash { + c := cshakeState{state: &state{rate: rate, outputLen: outputLen, dsbyte: dsbyte}} + + // leftEncode returns max 9 bytes + c.initBlock = make([]byte, 0, 9*2+len(N)+len(S)) + c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...) + c.initBlock = append(c.initBlock, N...) + c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...) + c.initBlock = append(c.initBlock, S...) + c.Write(bytepad(c.initBlock, c.rate)) + return &c +} + +// Reset resets the hash to initial state. +func (c *cshakeState) Reset() { + c.state.Reset() + c.Write(bytepad(c.initBlock, c.rate)) +} + +// Clone returns copy of a cSHAKE context within its current state. +func (c *cshakeState) Clone() ShakeHash { + b := make([]byte, len(c.initBlock)) + copy(b, c.initBlock) + return &cshakeState{state: c.clone(), initBlock: b} +} + +// Clone returns copy of SHAKE context within its current state. +func (c *state) Clone() ShakeHash { + return c.clone() +} + +// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash. +// Its generic security strength is 128 bits against all attacks if at +// least 32 bytes of its output are used. +func NewShake128() ShakeHash { + return newShake128() +} + +// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. +// Its generic security strength is 256 bits against all attacks if +// at least 64 bytes of its output are used. +func NewShake256() ShakeHash { + return newShake256() +} + +func newShake128Generic() *state { + return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake} +} + +func newShake256Generic() *state { + return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake} +} + +// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash, +// a customizable variant of SHAKE128. +// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is +// desired. S is a customization byte string used for domain separation - two cSHAKE +// computations on same input with different S yield unrelated outputs. +// When N and S are both empty, this is equivalent to NewShake128. +func NewCShake128(N, S []byte) ShakeHash { + if len(N) == 0 && len(S) == 0 { + return NewShake128() + } + return newCShake(N, S, rate128, 32, dsbyteCShake) +} + +// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash, +// a customizable variant of SHAKE256. +// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is +// desired. S is a customization byte string used for domain separation - two cSHAKE +// computations on same input with different S yield unrelated outputs. +// When N and S are both empty, this is equivalent to NewShake256. +func NewCShake256(N, S []byte) ShakeHash { + if len(N) == 0 && len(S) == 0 { + return NewShake256() + } + return newCShake(N, S, rate256, 64, dsbyteCShake) +} + +// ShakeSum128 writes an arbitrary-length digest of data into hash. +func ShakeSum128(hash, data []byte) { + h := NewShake128() + h.Write(data) + h.Read(hash) +} + +// ShakeSum256 writes an arbitrary-length digest of data into hash. +func ShakeSum256(hash, data []byte) { + h := NewShake256() + h.Write(data) + h.Read(hash) +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/shake_noasm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/shake_noasm.go new file mode 100644 index 000000000000..4276ba4ab2c4 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/shake_noasm.go @@ -0,0 +1,15 @@ +// Copyright 2023 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !gc || purego || !s390x + +package sha3 + +func newShake128() *state { + return newShake128Generic() +} + +func newShake256() *state { + return newShake256Generic() +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/xor.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/xor.go new file mode 100644 index 000000000000..6ada5c9574e2 --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/xor.go @@ -0,0 +1,40 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sha3 + +import ( + "crypto/subtle" + "encoding/binary" + "unsafe" + + "golang.org/x/sys/cpu" +) + +// xorIn xors the bytes in buf into the state. +func xorIn(d *state, buf []byte) { + if cpu.IsBigEndian { + for i := 0; len(buf) >= 8; i++ { + a := binary.LittleEndian.Uint64(buf) + d.a[i] ^= a + buf = buf[8:] + } + } else { + ab := (*[25 * 64 / 8]byte)(unsafe.Pointer(&d.a)) + subtle.XORBytes(ab[:], ab[:], buf) + } +} + +// copyOut copies uint64s to a byte buffer. +func copyOut(d *state, b []byte) { + if cpu.IsBigEndian { + for i := 0; len(b) >= 8; i++ { + binary.LittleEndian.PutUint64(b, d.a[i]) + b = b[8:] + } + } else { + ab := (*[25 * 64 / 8]byte)(unsafe.Pointer(&d.a)) + copy(b, ab[:]) + } +} diff --git a/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/ya.make new file mode 100644 index 000000000000..dddf27f8d89d --- /dev/null +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/crypto/sha3/ya.make @@ -0,0 +1,28 @@ +GO_LIBRARY() +IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + hashes.go + hashes_noasm.go + keccakf.go + register.go + sha3.go + shake.go + shake_noasm.go + xor.go + ) +ELSEIF (OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED) + SRCS( + doc.go + hashes.go + hashes_noasm.go + keccakf_amd64.go + keccakf_amd64.s + register.go + sha3.go + shake.go + shake_noasm.go + xor.go + ) +ENDIF() +END() diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/dns/dnsmessage/message.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/dns/dnsmessage/message.go similarity index 99% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/dns/dnsmessage/message.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/dns/dnsmessage/message.go index 42987ab7c5fe..a656efc128a6 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/dns/dnsmessage/message.go +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/dns/dnsmessage/message.go @@ -273,7 +273,6 @@ var ( errTooManyAdditionals = errors.New("too many Additionals to pack (>65535)") errNonCanonicalName = errors.New("name is not in canonical format (it must end with a .)") errStringTooLong = errors.New("character string exceeds maximum length (255)") - errCompressedSRV = errors.New("compressed name in SRV resource data") ) // Internal constants. @@ -2028,10 +2027,6 @@ func (n *Name) pack(msg []byte, compression map[string]uint16, compressionOff in // unpack unpacks a domain name. func (n *Name) unpack(msg []byte, off int) (int, error) { - return n.unpackCompressed(msg, off, true /* allowCompression */) -} - -func (n *Name) unpackCompressed(msg []byte, off int, allowCompression bool) (int, error) { // currOff is the current working offset. currOff := off @@ -2076,9 +2071,6 @@ Loop: name = append(name, '.') currOff = endOff case 0xC0: // Pointer - if !allowCompression { - return off, errCompressedSRV - } if currOff >= len(msg) { return off, errInvalidPtr } @@ -2549,7 +2541,7 @@ func unpackSRVResource(msg []byte, off int) (SRVResource, error) { return SRVResource{}, &nestedError{"Port", err} } var target Name - if _, err := target.unpackCompressed(msg, off, false /* allowCompression */); err != nil { + if _, err := target.unpack(msg, off); err != nil { return SRVResource{}, &nestedError{"Target", err} } return SRVResource{priority, weight, port, target}, nil diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/dns/dnsmessage/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/dns/dnsmessage/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/dns/dnsmessage/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/dns/dnsmessage/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpguts/guts.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpguts/guts.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpguts/guts.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpguts/guts.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpguts/httplex.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpguts/httplex.go similarity index 97% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpguts/httplex.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpguts/httplex.go index 6e071e852432..9b4de94019b4 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpguts/httplex.go +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpguts/httplex.go @@ -12,7 +12,7 @@ import ( "golang.org/x/net/idna" ) -var isTokenTable = [127]bool{ +var isTokenTable = [256]bool{ '!': true, '#': true, '$': true, @@ -93,12 +93,7 @@ var isTokenTable = [127]bool{ } func IsTokenRune(r rune) bool { - i := int(r) - return i < len(isTokenTable) && isTokenTable[i] -} - -func isNotToken(r rune) bool { - return !IsTokenRune(r) + return r < utf8.RuneSelf && isTokenTable[byte(r)] } // HeaderValuesContainsToken reports whether any string in values @@ -202,8 +197,8 @@ func ValidHeaderFieldName(v string) bool { if len(v) == 0 { return false } - for _, r := range v { - if !IsTokenRune(r) { + for i := 0; i < len(v); i++ { + if !isTokenTable[v[i]] { return false } } diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpguts/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpguts/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpguts/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpguts/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpproxy/proxy.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpproxy/proxy.go similarity index 98% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpproxy/proxy.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpproxy/proxy.go index c3bd9a1eeb55..d89c257ae723 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpproxy/proxy.go +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpproxy/proxy.go @@ -14,6 +14,7 @@ import ( "errors" "fmt" "net" + "net/netip" "net/url" "os" "strings" @@ -149,10 +150,7 @@ func parseProxy(proxy string) (*url.URL, error) { } proxyURL, err := url.Parse(proxy) - if err != nil || - (proxyURL.Scheme != "http" && - proxyURL.Scheme != "https" && - proxyURL.Scheme != "socks5") { + if err != nil || proxyURL.Scheme == "" || proxyURL.Host == "" { // proxy was bogus. Try prepending "http://" to it and // see if that parses correctly. If not, we fall // through and complain about the original one. @@ -180,8 +178,10 @@ func (cfg *config) useProxy(addr string) bool { if host == "localhost" { return false } - ip := net.ParseIP(host) - if ip != nil { + nip, err := netip.ParseAddr(host) + var ip net.IP + if err == nil { + ip = net.IP(nip.AsSlice()) if ip.IsLoopback() { return false } @@ -363,6 +363,9 @@ type domainMatch struct { } func (m domainMatch) match(host, port string, ip net.IP) bool { + if ip != nil { + return false + } if strings.HasSuffix(host, m.host) || (m.matchHost && host == m.host[1:]) { return m.port == "" || m.port == port } diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpproxy/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpproxy/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http/httpproxy/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http/httpproxy/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/encode.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/encode.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/encode.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/encode.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/hpack.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/hpack.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/hpack.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/hpack.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/huffman.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/huffman.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/huffman.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/huffman.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/static_table.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/static_table.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/static_table.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/static_table.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/tables.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/tables.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/tables.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/tables.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/http2/hpack/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/http2/hpack/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/go118.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/go118.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/go118.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/go118.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/idna10.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/idna10.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/idna10.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/idna10.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/idna9.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/idna9.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/idna9.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/idna9.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/pre_go118.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/pre_go118.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/pre_go118.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/pre_go118.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/punycode.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/punycode.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/punycode.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/punycode.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables10.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables10.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables10.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables10.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables11.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables11.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables11.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables11.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables12.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables12.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables12.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables12.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables13.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables13.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables13.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables13.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables15.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables15.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables15.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables15.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables9.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables9.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/tables9.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/tables9.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trie.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trie.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trie.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trie.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trie12.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trie12.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trie12.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trie12.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trie13.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trie13.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trie13.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trie13.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trieval.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trieval.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/trieval.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/trieval.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/idna/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/idna/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/address.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/address.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/address.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/address.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/binary.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/binary.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/binary.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/binary.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/empty.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/empty.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/empty.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/empty.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_announce.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_announce.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_announce.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_announce.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_classic.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_classic.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_classic.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_classic.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_freebsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_freebsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_freebsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_multicast.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_multicast.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_multicast.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_multicast.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_openbsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/interface_openbsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/interface_openbsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/message.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/message.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/message.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/message.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/route.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/route.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/route.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/route.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/route_classic.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/route_classic.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/route_classic.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/route_classic.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/route_openbsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/route_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/route_openbsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/route_openbsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_darwin.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_darwin.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_darwin.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_dragonfly.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_dragonfly.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_dragonfly.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_freebsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_freebsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_freebsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_freebsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_netbsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_netbsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_netbsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_openbsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/sys_openbsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/sys_openbsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/syscall.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/syscall.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/syscall.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/syscall.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_darwin.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_darwin.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_darwin.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_darwin.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_dragonfly.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_dragonfly.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_dragonfly.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_dragonfly.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_386.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_amd64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_arm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_arm64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_freebsd_riscv64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_netbsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_netbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_netbsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_netbsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_openbsd.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_openbsd.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/net/route/zsys_openbsd.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/net/route/zsys_openbsd.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/asm_aix_ppc64.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/byteorder.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/byteorder.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/byteorder.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/byteorder.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu.go similarity index 99% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu.go index 4756ad5f7951..8fa707aa4ba9 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu.go +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu.go @@ -103,6 +103,7 @@ var ARM64 struct { HasASIMDDP bool // Advanced SIMD double precision instruction set HasSHA512 bool // SHA512 hardware implementation HasSVE bool // Scalable Vector Extensions + HasSVE2 bool // Scalable Vector Extensions 2 HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32 _ CacheLinePad } diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_aix.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_aix.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_aix.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_aix.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go similarity index 95% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go index f3eb993bf24b..0e27a21e1f82 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm64.go @@ -28,6 +28,7 @@ func initOptions() { {Name: "sm3", Feature: &ARM64.HasSM3}, {Name: "sm4", Feature: &ARM64.HasSM4}, {Name: "sve", Feature: &ARM64.HasSVE}, + {Name: "sve2", Feature: &ARM64.HasSVE2}, {Name: "crc32", Feature: &ARM64.HasCRC32}, {Name: "atomics", Feature: &ARM64.HasATOMICS}, {Name: "asimdhp", Feature: &ARM64.HasASIMDHP}, @@ -164,6 +165,15 @@ func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) { switch extractBits(pfr0, 32, 35) { case 1: ARM64.HasSVE = true + + parseARM64SVERegister(getzfr0()) + } +} + +func parseARM64SVERegister(zfr0 uint64) { + switch extractBits(zfr0, 0, 3) { + case 1: + ARM64.HasSVE2 = true } } diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm64.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm64.s similarity index 80% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm64.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm64.s index fcb9a3888205..22cc99844a75 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_arm64.s +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_arm64.s @@ -29,3 +29,11 @@ TEXT ·getpfr0(SB),NOSPLIT,$0-8 WORD $0xd5380400 MOVD R0, ret+0(FP) RET + +// func getzfr0() uint64 +TEXT ·getzfr0(SB),NOSPLIT,$0-8 + // get SVE Feature Register 0 into x0 + // mrs x0, ID_AA64ZFR0_EL1 = d5380480 + WORD $0xd5380480 + MOVD R0, ret+0(FP) + RET diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go similarity index 92% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go index a8acd3e3285d..6ac6e1efb208 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gc_arm64.go @@ -9,3 +9,4 @@ package cpu func getisar0() uint64 func getisar1() uint64 func getpfr0() uint64 +func getzfr0() uint64 diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gc_s390x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gc_x86.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_arm64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_s390x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.c diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_gccgo_x86.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go similarity index 97% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go index a968b80fa6ab..3d386d0fc218 100644 --- a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go +++ b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_arm64.go @@ -35,6 +35,8 @@ const ( hwcap_SHA512 = 1 << 21 hwcap_SVE = 1 << 22 hwcap_ASIMDFHM = 1 << 23 + + hwcap2_SVE2 = 1 << 1 ) // linuxKernelCanEmulateCPUID reports whether we're running @@ -104,6 +106,9 @@ func doinit() { ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512) ARM64.HasSVE = isSet(hwCap, hwcap_SVE) ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM) + + // HWCAP2 feature bits + ARM64.HasSVE2 = isSet(hwCap2, hwcap2_SVE2) } func isSet(hwc uint, value uint) bool { diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_mips64x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_ppc64x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_loong64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_loong64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_loong64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_loong64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_mips64x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_mips64x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_mips64x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_mipsx.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_mipsx.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_mipsx.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_mipsx.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_netbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_openbsd_arm64.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_arm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_arm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_arm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_arm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_arm64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_mips64x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_ppc64x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_other_riscv64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_ppc64x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_riscv64.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_riscv64.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_riscv64.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_riscv64.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_s390x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_s390x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_s390x.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_s390x.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_s390x.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_s390x.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_wasm.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_wasm.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_wasm.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_wasm.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_x86.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_x86.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_x86.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_x86.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_x86.s b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_x86.s similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_x86.s rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_x86.s diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_zos.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_zos.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_zos.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_zos.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/cpu_zos_s390x.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/endian_big.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/endian_big.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/endian_big.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/endian_big.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/endian_little.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/endian_little.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/endian_little.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/endian_little.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/hwcap_linux.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/hwcap_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/hwcap_linux.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/hwcap_linux.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/parse.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/parse.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/parse.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/parse.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/proc_cpuinfo_linux.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/runtime_auxv.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/runtime_auxv.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/runtime_auxv.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/runtime_auxv.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/runtime_auxv_go121.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/syscall_aix_gccgo.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/syscall_aix_ppc64_gc.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/sys/cpu/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/sys/cpu/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/bidirule.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/bidirule.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/bidirule.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/bidirule.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/secure/bidirule/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/secure/bidirule/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/transform/transform.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/transform/transform.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/transform/transform.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/transform/transform.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/transform/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/transform/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/transform/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/transform/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/bidi.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/bidi.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/bidi.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/bidi.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/bracket.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/bracket.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/bracket.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/bracket.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/core.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/core.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/core.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/core.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/prop.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/prop.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/prop.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/prop.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables15.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables15.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables15.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables15.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/trieval.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/trieval.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/trieval.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/trieval.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/bidi/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/bidi/ya.make diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/composition.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/composition.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/composition.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/composition.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/forminfo.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/forminfo.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/forminfo.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/forminfo.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/input.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/input.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/input.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/input.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/iter.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/iter.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/iter.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/iter.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/normalize.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/normalize.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/normalize.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/normalize.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/readwriter.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/readwriter.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/readwriter.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/readwriter.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables11.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables11.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables11.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables11.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables12.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables12.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables12.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables12.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables13.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables13.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables13.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables13.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables15.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables15.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables15.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables15.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/transform.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/transform.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/transform.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/transform.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/trie.go b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/trie.go similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/trie.go rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/trie.go diff --git a/contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/ya.make b/contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/ya.make similarity index 100% rename from contrib/go/_std_1.22/src/vendor/golang.org/x/text/unicode/norm/ya.make rename to contrib/go/_std_1.23/src/vendor/golang.org/x/text/unicode/norm/ya.make diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md index 6444f4b7f6f3..71757151c333 100644 --- a/vendor/github.com/spf13/cobra/README.md +++ b/vendor/github.com/spf13/cobra/README.md @@ -1,4 +1,5 @@ -![cobra logo](assets/CobraMain.png) + +![cobra logo](https://github.com/user-attachments/assets/cbc3adf8-0dff-46e9-a88d-5e2d971c169e) Cobra is a library for creating powerful modern CLI applications. @@ -105,7 +106,7 @@ go install github.com/spf13/cobra-cli@latest For complete details on using the Cobra-CLI generator, please read [The Cobra Generator README](https://github.com/spf13/cobra-cli/blob/main/README.md) -For complete details on using the Cobra library, please read the [The Cobra User Guide](site/content/user_guide.md). +For complete details on using the Cobra library, please read [The Cobra User Guide](site/content/user_guide.md). # License diff --git a/vendor/github.com/spf13/cobra/active_help.go b/vendor/github.com/spf13/cobra/active_help.go index 25c30e3ccc3c..b3e2dadfed65 100644 --- a/vendor/github.com/spf13/cobra/active_help.go +++ b/vendor/github.com/spf13/cobra/active_help.go @@ -35,7 +35,7 @@ const ( // This function can be called multiple times before and/or after completions are added to // the array. Each time this function is called with the same array, the new // ActiveHelp line will be shown below the previous ones when completion is triggered. -func AppendActiveHelp(compArray []string, activeHelpStr string) []string { +func AppendActiveHelp(compArray []Completion, activeHelpStr string) []Completion { return append(compArray, fmt.Sprintf("%s%s", activeHelpMarker, activeHelpStr)) } diff --git a/vendor/github.com/spf13/cobra/bash_completionsV2.go b/vendor/github.com/spf13/cobra/bash_completionsV2.go index 1cce5c329c20..d2397aa3668c 100644 --- a/vendor/github.com/spf13/cobra/bash_completionsV2.go +++ b/vendor/github.com/spf13/cobra/bash_completionsV2.go @@ -146,7 +146,7 @@ __%[1]s_process_completion_results() { if (((directive & shellCompDirectiveFilterFileExt) != 0)); then # File extension filtering - local fullFilter filter filteringCmd + local fullFilter="" filter filteringCmd # Do not use quotes around the $completions variable or else newline # characters will be kept. @@ -177,20 +177,71 @@ __%[1]s_process_completion_results() { __%[1]s_handle_special_char "$cur" = # Print the activeHelp statements before we finish + __%[1]s_handle_activeHelp +} + +__%[1]s_handle_activeHelp() { + # Print the activeHelp statements if ((${#activeHelp[*]} != 0)); then - printf "\n"; - printf "%%s\n" "${activeHelp[@]}" - printf "\n" - - # The prompt format is only available from bash 4.4. - # We test if it is available before using it. - if (x=${PS1@P}) 2> /dev/null; then - printf "%%s" "${PS1@P}${COMP_LINE[@]}" - else - # Can't print the prompt. Just print the - # text the user had typed, it is workable enough. - printf "%%s" "${COMP_LINE[@]}" + if [ -z $COMP_TYPE ]; then + # Bash v3 does not set the COMP_TYPE variable. + printf "\n"; + printf "%%s\n" "${activeHelp[@]}" + printf "\n" + __%[1]s_reprint_commandLine + return fi + + # Only print ActiveHelp on the second TAB press + if [ $COMP_TYPE -eq 63 ]; then + printf "\n" + printf "%%s\n" "${activeHelp[@]}" + + if ((${#COMPREPLY[*]} == 0)); then + # When there are no completion choices from the program, file completion + # may kick in if the program has not disabled it; in such a case, we want + # to know if any files will match what the user typed, so that we know if + # there will be completions presented, so that we know how to handle ActiveHelp. + # To find out, we actually trigger the file completion ourselves; + # the call to _filedir will fill COMPREPLY if files match. + if (((directive & shellCompDirectiveNoFileComp) == 0)); then + __%[1]s_debug "Listing files" + _filedir + fi + fi + + if ((${#COMPREPLY[*]} != 0)); then + # If there are completion choices to be shown, print a delimiter. + # Re-printing the command-line will automatically be done + # by the shell when it prints the completion choices. + printf -- "--" + else + # When there are no completion choices at all, we need + # to re-print the command-line since the shell will + # not be doing it itself. + __%[1]s_reprint_commandLine + fi + elif [ $COMP_TYPE -eq 37 ] || [ $COMP_TYPE -eq 42 ]; then + # For completion type: menu-complete/menu-complete-backward and insert-completions + # the completions are immediately inserted into the command-line, so we first + # print the activeHelp message and reprint the command-line since the shell won't. + printf "\n" + printf "%%s\n" "${activeHelp[@]}" + + __%[1]s_reprint_commandLine + fi + fi +} + +__%[1]s_reprint_commandLine() { + # The prompt format is only available from bash 4.4. + # We test if it is available before using it. + if (x=${PS1@P}) 2> /dev/null; then + printf "%%s" "${PS1@P}${COMP_LINE[@]}" + else + # Can't print the prompt. Just print the + # text the user had typed, it is workable enough. + printf "%%s" "${COMP_LINE[@]}" fi } @@ -201,6 +252,8 @@ __%[1]s_extract_activeHelp() { local endIndex=${#activeHelpMarker} while IFS='' read -r comp; do + [[ -z $comp ]] && continue + if [[ ${comp:0:endIndex} == $activeHelpMarker ]]; then comp=${comp:endIndex} __%[1]s_debug "ActiveHelp found: $comp" @@ -223,16 +276,21 @@ __%[1]s_handle_completion_types() { # If the user requested inserting one completion at a time, or all # completions at once on the command-line we must remove the descriptions. # https://github.com/spf13/cobra/issues/1508 - local tab=$'\t' comp - while IFS='' read -r comp; do - [[ -z $comp ]] && continue - # Strip any description - comp=${comp%%%%$tab*} - # Only consider the completions that match - if [[ $comp == "$cur"* ]]; then - COMPREPLY+=("$comp") - fi - done < <(printf "%%s\n" "${completions[@]}") + + # If there are no completions, we don't need to do anything + (( ${#completions[@]} == 0 )) && return 0 + + local tab=$'\t' + + # Strip any description and escape the completion to handled special characters + IFS=$'\n' read -ra completions -d '' < <(printf "%%q\n" "${completions[@]%%%%$tab*}") + + # Only consider the completions that match + IFS=$'\n' read -ra COMPREPLY -d '' < <(IFS=$'\n'; compgen -W "${completions[*]}" -- "${cur}") + + # compgen looses the escaping so we need to escape all completions again since they will + # all be inserted on the command-line. + IFS=$'\n' read -ra COMPREPLY -d '' < <(printf "%%q\n" "${COMPREPLY[@]}") ;; *) @@ -243,11 +301,25 @@ __%[1]s_handle_completion_types() { } __%[1]s_handle_standard_completion_case() { - local tab=$'\t' comp + local tab=$'\t' + + # If there are no completions, we don't need to do anything + (( ${#completions[@]} == 0 )) && return 0 # Short circuit to optimize if we don't have descriptions if [[ "${completions[*]}" != *$tab* ]]; then - IFS=$'\n' read -ra COMPREPLY -d '' < <(compgen -W "${completions[*]}" -- "$cur") + # First, escape the completions to handle special characters + IFS=$'\n' read -ra completions -d '' < <(printf "%%q\n" "${completions[@]}") + # Only consider the completions that match what the user typed + IFS=$'\n' read -ra COMPREPLY -d '' < <(IFS=$'\n'; compgen -W "${completions[*]}" -- "${cur}") + + # compgen looses the escaping so, if there is only a single completion, we need to + # escape it again because it will be inserted on the command-line. If there are multiple + # completions, we don't want to escape them because they will be printed in a list + # and we don't want to show escape characters in that list. + if (( ${#COMPREPLY[@]} == 1 )); then + COMPREPLY[0]=$(printf "%%q" "${COMPREPLY[0]}") + fi return 0 fi @@ -256,23 +328,39 @@ __%[1]s_handle_standard_completion_case() { # Look for the longest completion so that we can format things nicely while IFS='' read -r compline; do [[ -z $compline ]] && continue - # Strip any description before checking the length - comp=${compline%%%%$tab*} + + # Before checking if the completion matches what the user typed, + # we need to strip any description and escape the completion to handle special + # characters because those escape characters are part of what the user typed. + # Don't call "printf" in a sub-shell because it will be much slower + # since we are in a loop. + printf -v comp "%%q" "${compline%%%%$tab*}" &>/dev/null || comp=$(printf "%%q" "${compline%%%%$tab*}") + # Only consider the completions that match [[ $comp == "$cur"* ]] || continue + + # The completions matches. Add it to the list of full completions including + # its description. We don't escape the completion because it may get printed + # in a list if there are more than one and we don't want show escape characters + # in that list. COMPREPLY+=("$compline") + + # Strip any description before checking the length, and again, don't escape + # the completion because this length is only used when printing the completions + # in a list and we don't want show escape characters in that list. + comp=${compline%%%%$tab*} if ((${#comp}>longest)); then longest=${#comp} fi done < <(printf "%%s\n" "${completions[@]}") - # If there is a single completion left, remove the description text + # If there is a single completion left, remove the description text and escape any special characters if ((${#COMPREPLY[*]} == 1)); then __%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}" - comp="${COMPREPLY[0]%%%%$tab*}" - __%[1]s_debug "Removed description from single completion, which is now: ${comp}" - COMPREPLY[0]=$comp - else # Format the descriptions + COMPREPLY[0]=$(printf "%%q" "${COMPREPLY[0]%%%%$tab*}") + __%[1]s_debug "Removed description from single completion, which is now: ${COMPREPLY[0]}" + else + # Format the descriptions __%[1]s_format_comp_descriptions $longest fi } diff --git a/vendor/github.com/spf13/cobra/cobra.go b/vendor/github.com/spf13/cobra/cobra.go index e0b0947b04c9..d9cd2414e237 100644 --- a/vendor/github.com/spf13/cobra/cobra.go +++ b/vendor/github.com/spf13/cobra/cobra.go @@ -176,12 +176,16 @@ func rpad(s string, padding int) string { return fmt.Sprintf(formattedString, s) } -// tmpl executes the given template text on data, writing the result to w. -func tmpl(w io.Writer, text string, data interface{}) error { - t := template.New("top") - t.Funcs(templateFuncs) - template.Must(t.Parse(text)) - return t.Execute(w, data) +func tmpl(text string) *tmplFunc { + return &tmplFunc{ + tmpl: text, + fn: func(w io.Writer, data interface{}) error { + t := template.New("top") + t.Funcs(templateFuncs) + template.Must(t.Parse(text)) + return t.Execute(w, data) + }, + } } // ld compares two strings and returns the levenshtein distance between them. diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go index 54748fc67ebd..dbb2c298ba08 100644 --- a/vendor/github.com/spf13/cobra/command.go +++ b/vendor/github.com/spf13/cobra/command.go @@ -33,6 +33,9 @@ import ( const ( FlagSetByCobraAnnotation = "cobra_annotation_flag_set_by_cobra" CommandDisplayNameAnnotation = "cobra_annotation_command_display_name" + + helpFlagName = "help" + helpCommandName = "help" ) // FParseErrWhitelist configures Flag parse errors to be ignored @@ -80,11 +83,11 @@ type Command struct { Example string // ValidArgs is list of all valid non-flag arguments that are accepted in shell completions - ValidArgs []string + ValidArgs []Completion // ValidArgsFunction is an optional function that provides valid non-flag arguments for shell completion. // It is a dynamic version of using ValidArgs. // Only one of ValidArgs and ValidArgsFunction can be used for a command. - ValidArgsFunction func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) + ValidArgsFunction CompletionFunc // Expected arguments Args PositionalArgs @@ -168,12 +171,12 @@ type Command struct { // usageFunc is usage func defined by user. usageFunc func(*Command) error // usageTemplate is usage template defined by user. - usageTemplate string + usageTemplate *tmplFunc // flagErrorFunc is func defined by user and it's called when the parsing of // flags returns an error. flagErrorFunc func(*Command, error) error // helpTemplate is help template defined by user. - helpTemplate string + helpTemplate *tmplFunc // helpFunc is help func defined by user. helpFunc func(*Command, []string) // helpCommand is command with usage 'help'. If it's not defined by user, @@ -186,7 +189,7 @@ type Command struct { completionCommandGroupID string // versionTemplate is the version template defined by user. - versionTemplate string + versionTemplate *tmplFunc // errPrefix is the error message prefix defined by user. errPrefix string @@ -281,6 +284,7 @@ func (c *Command) SetArgs(a []string) { // SetOutput sets the destination for usage and error messages. // If output is nil, os.Stderr is used. +// // Deprecated: Use SetOut and/or SetErr instead func (c *Command) SetOutput(output io.Writer) { c.outWriter = output @@ -312,7 +316,11 @@ func (c *Command) SetUsageFunc(f func(*Command) error) { // SetUsageTemplate sets usage template. Can be defined by Application. func (c *Command) SetUsageTemplate(s string) { - c.usageTemplate = s + if s == "" { + c.usageTemplate = nil + return + } + c.usageTemplate = tmpl(s) } // SetFlagErrorFunc sets a function to generate an error when flag parsing @@ -348,12 +356,20 @@ func (c *Command) SetCompletionCommandGroupID(groupID string) { // SetHelpTemplate sets help template to be used. Application can use it to set custom template. func (c *Command) SetHelpTemplate(s string) { - c.helpTemplate = s + if s == "" { + c.helpTemplate = nil + return + } + c.helpTemplate = tmpl(s) } // SetVersionTemplate sets version template to be used. Application can use it to set custom template. func (c *Command) SetVersionTemplate(s string) { - c.versionTemplate = s + if s == "" { + c.versionTemplate = nil + return + } + c.versionTemplate = tmpl(s) } // SetErrPrefix sets error message prefix to be used. Application can use it to set custom prefix. @@ -434,7 +450,8 @@ func (c *Command) UsageFunc() (f func(*Command) error) { } return func(c *Command) error { c.mergePersistentFlags() - err := tmpl(c.OutOrStderr(), c.UsageTemplate(), c) + fn := c.getUsageTemplateFunc() + err := fn(c.OutOrStderr(), c) if err != nil { c.PrintErrln(err) } @@ -442,6 +459,19 @@ func (c *Command) UsageFunc() (f func(*Command) error) { } } +// getUsageTemplateFunc returns the usage template function for the command +// going up the command tree if necessary. +func (c *Command) getUsageTemplateFunc() func(w io.Writer, data interface{}) error { + if c.usageTemplate != nil { + return c.usageTemplate.fn + } + + if c.HasParent() { + return c.parent.getUsageTemplateFunc() + } + return defaultUsageFunc +} + // Usage puts out the usage for the command. // Used when a user provides invalid input. // Can be defined by user by overriding UsageFunc. @@ -460,15 +490,30 @@ func (c *Command) HelpFunc() func(*Command, []string) { } return func(c *Command, a []string) { c.mergePersistentFlags() + fn := c.getHelpTemplateFunc() // The help should be sent to stdout // See https://github.com/spf13/cobra/issues/1002 - err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c) + err := fn(c.OutOrStdout(), c) if err != nil { c.PrintErrln(err) } } } +// getHelpTemplateFunc returns the help template function for the command +// going up the command tree if necessary. +func (c *Command) getHelpTemplateFunc() func(w io.Writer, data interface{}) error { + if c.helpTemplate != nil { + return c.helpTemplate.fn + } + + if c.HasParent() { + return c.parent.getHelpTemplateFunc() + } + + return defaultHelpFunc +} + // Help puts out the help for the command. // Used when a user calls help [command]. // Can be defined by user by overriding HelpFunc. @@ -543,71 +588,55 @@ func (c *Command) NamePadding() int { } // UsageTemplate returns usage template for the command. +// This function is kept for backwards-compatibility reasons. func (c *Command) UsageTemplate() string { - if c.usageTemplate != "" { - return c.usageTemplate + if c.usageTemplate != nil { + return c.usageTemplate.tmpl } if c.HasParent() { return c.parent.UsageTemplate() } - return `Usage:{{if .Runnable}} - {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} - {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} - -Aliases: - {{.NameAndAliases}}{{end}}{{if .HasExample}} - -Examples: -{{.Example}}{{end}}{{if .HasAvailableSubCommands}}{{$cmds := .Commands}}{{if eq (len .Groups) 0}} - -Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{else}}{{range $group := .Groups}} - -{{.Title}}{{range $cmds}}{{if (and (eq .GroupID $group.ID) (or .IsAvailableCommand (eq .Name "help")))}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}} - -Additional Commands:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} - -Flags: -{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} - -Global Flags: -{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} - -Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} - {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} - -Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} -` + return defaultUsageTemplate } // HelpTemplate return help template for the command. +// This function is kept for backwards-compatibility reasons. func (c *Command) HelpTemplate() string { - if c.helpTemplate != "" { - return c.helpTemplate + if c.helpTemplate != nil { + return c.helpTemplate.tmpl } if c.HasParent() { return c.parent.HelpTemplate() } - return `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} - -{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` + return defaultHelpTemplate } // VersionTemplate return version template for the command. +// This function is kept for backwards-compatibility reasons. func (c *Command) VersionTemplate() string { - if c.versionTemplate != "" { - return c.versionTemplate + if c.versionTemplate != nil { + return c.versionTemplate.tmpl } if c.HasParent() { return c.parent.VersionTemplate() } - return `{{with .Name}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}} -` + return defaultVersionTemplate +} + +// getVersionTemplateFunc returns the version template function for the command +// going up the command tree if necessary. +func (c *Command) getVersionTemplateFunc() func(w io.Writer, data interface{}) error { + if c.versionTemplate != nil { + return c.versionTemplate.fn + } + + if c.HasParent() { + return c.parent.getVersionTemplateFunc() + } + return defaultVersionFunc } // ErrPrefix return error message prefix for the command @@ -894,7 +923,7 @@ func (c *Command) execute(a []string) (err error) { // If help is called, regardless of other flags, return we want help. // Also say we need help if the command isn't runnable. - helpVal, err := c.Flags().GetBool("help") + helpVal, err := c.Flags().GetBool(helpFlagName) if err != nil { // should be impossible to get here as we always declare a help // flag in InitDefaultHelpFlag() @@ -914,7 +943,8 @@ func (c *Command) execute(a []string) (err error) { return err } if versionVal { - err := tmpl(c.OutOrStdout(), c.VersionTemplate(), c) + fn := c.getVersionTemplateFunc() + err := fn(c.OutOrStdout(), c) if err != nil { c.Println(err) } @@ -1068,12 +1098,6 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { // initialize help at the last point to allow for user overriding c.InitDefaultHelpCmd() - // initialize completion at the last point to allow for user overriding - c.InitDefaultCompletionCmd() - - // Now that all commands have been created, let's make sure all groups - // are properly created also - c.checkCommandGroups() args := c.args @@ -1082,9 +1106,16 @@ func (c *Command) ExecuteC() (cmd *Command, err error) { args = os.Args[1:] } - // initialize the hidden command to be used for shell completion + // initialize the __complete command to be used for shell completion c.initCompleteCmd(args) + // initialize the default completion command + c.InitDefaultCompletionCmd(args...) + + // Now that all commands have been created, let's make sure all groups + // are properly created also + c.checkCommandGroups() + var flags []string if c.TraverseChildren { cmd, flags, err = c.Traverse(args) @@ -1187,16 +1218,16 @@ func (c *Command) checkCommandGroups() { // If c already has help flag, it will do nothing. func (c *Command) InitDefaultHelpFlag() { c.mergePersistentFlags() - if c.Flags().Lookup("help") == nil { + if c.Flags().Lookup(helpFlagName) == nil { usage := "help for " - name := c.displayName() + name := c.DisplayName() if name == "" { usage += "this command" } else { usage += name } - c.Flags().BoolP("help", "h", false, usage) - _ = c.Flags().SetAnnotation("help", FlagSetByCobraAnnotation, []string{"true"}) + c.Flags().BoolP(helpFlagName, "h", false, usage) + _ = c.Flags().SetAnnotation(helpFlagName, FlagSetByCobraAnnotation, []string{"true"}) } } @@ -1215,7 +1246,7 @@ func (c *Command) InitDefaultVersionFlag() { if c.Name() == "" { usage += "this command" } else { - usage += c.Name() + usage += c.DisplayName() } if c.Flags().ShorthandLookup("v") == nil { c.Flags().BoolP("version", "v", false, usage) @@ -1239,9 +1270,9 @@ func (c *Command) InitDefaultHelpCmd() { Use: "help [command]", Short: "Help about any command", Long: `Help provides help for any command in the application. -Simply type ` + c.displayName() + ` help [path to command] for full details.`, - ValidArgsFunction: func(c *Command, args []string, toComplete string) ([]string, ShellCompDirective) { - var completions []string +Simply type ` + c.DisplayName() + ` help [path to command] for full details.`, + ValidArgsFunction: func(c *Command, args []string, toComplete string) ([]Completion, ShellCompDirective) { + var completions []Completion cmd, _, e := c.Root().Find(args) if e != nil { return nil, ShellCompDirectiveNoFileComp @@ -1253,7 +1284,7 @@ Simply type ` + c.displayName() + ` help [path to command] for full details.`, for _, subCmd := range cmd.Commands() { if subCmd.IsAvailableCommand() || subCmd == cmd.helpCommand { if strings.HasPrefix(subCmd.Name(), toComplete) { - completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short)) + completions = append(completions, CompletionWithDesc(subCmd.Name(), subCmd.Short)) } } } @@ -1430,10 +1461,12 @@ func (c *Command) CommandPath() string { if c.HasParent() { return c.Parent().CommandPath() + " " + c.Name() } - return c.displayName() + return c.DisplayName() } -func (c *Command) displayName() string { +// DisplayName returns the name to display in help text. Returns command Name() +// If CommandDisplayNameAnnoation is not set +func (c *Command) DisplayName() string { if displayName, ok := c.Annotations[CommandDisplayNameAnnotation]; ok { return displayName } @@ -1443,7 +1476,7 @@ func (c *Command) displayName() string { // UseLine puts out the full usage for a given command (including parents). func (c *Command) UseLine() string { var useline string - use := strings.Replace(c.Use, c.Name(), c.displayName(), 1) + use := strings.Replace(c.Use, c.Name(), c.DisplayName(), 1) if c.HasParent() { useline = c.parent.CommandPath() + " " + use } else { @@ -1649,7 +1682,7 @@ func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) f // to this command (local and persistent declared here and by all parents). func (c *Command) Flags() *flag.FlagSet { if c.flags == nil { - c.flags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + c.flags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } @@ -1664,7 +1697,7 @@ func (c *Command) Flags() *flag.FlagSet { func (c *Command) LocalNonPersistentFlags() *flag.FlagSet { persistentFlags := c.PersistentFlags() - out := flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + out := flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) c.LocalFlags().VisitAll(func(f *flag.Flag) { if persistentFlags.Lookup(f.Name) == nil { out.AddFlag(f) @@ -1679,7 +1712,7 @@ func (c *Command) LocalFlags() *flag.FlagSet { c.mergePersistentFlags() if c.lflags == nil { - c.lflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + c.lflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } @@ -1707,7 +1740,7 @@ func (c *Command) InheritedFlags() *flag.FlagSet { c.mergePersistentFlags() if c.iflags == nil { - c.iflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + c.iflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } @@ -1736,7 +1769,7 @@ func (c *Command) NonInheritedFlags() *flag.FlagSet { // PersistentFlags returns the persistent FlagSet specifically set in the current command. func (c *Command) PersistentFlags() *flag.FlagSet { if c.pflags == nil { - c.pflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + c.pflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) if c.flagErrorBuf == nil { c.flagErrorBuf = new(bytes.Buffer) } @@ -1749,9 +1782,9 @@ func (c *Command) PersistentFlags() *flag.FlagSet { func (c *Command) ResetFlags() { c.flagErrorBuf = new(bytes.Buffer) c.flagErrorBuf.Reset() - c.flags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + c.flags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) c.flags.SetOutput(c.flagErrorBuf) - c.pflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + c.pflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) c.pflags.SetOutput(c.flagErrorBuf) c.lflags = nil @@ -1868,7 +1901,7 @@ func (c *Command) mergePersistentFlags() { // If c.parentsPflags == nil, it makes new. func (c *Command) updateParentsPflags() { if c.parentsPflags == nil { - c.parentsPflags = flag.NewFlagSet(c.displayName(), flag.ContinueOnError) + c.parentsPflags = flag.NewFlagSet(c.DisplayName(), flag.ContinueOnError) c.parentsPflags.SetOutput(c.flagErrorBuf) c.parentsPflags.SortFlags = false } @@ -1894,3 +1927,141 @@ func commandNameMatches(s string, t string) bool { return s == t } + +// tmplFunc holds a template and a function that will execute said template. +type tmplFunc struct { + tmpl string + fn func(io.Writer, interface{}) error +} + +var defaultUsageTemplate = `Usage:{{if .Runnable}} + {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} + {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} + +Aliases: + {{.NameAndAliases}}{{end}}{{if .HasExample}} + +Examples: +{{.Example}}{{end}}{{if .HasAvailableSubCommands}}{{$cmds := .Commands}}{{if eq (len .Groups) 0}} + +Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{else}}{{range $group := .Groups}} + +{{.Title}}{{range $cmds}}{{if (and (eq .GroupID $group.ID) (or .IsAvailableCommand (eq .Name "help")))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}} + +Additional Commands:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} + +Flags: +{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} + +Global Flags: +{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} + +Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} + {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} + +Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}} +` + +// defaultUsageFunc is equivalent to executing defaultUsageTemplate. The two should be changed in sync. +func defaultUsageFunc(w io.Writer, in interface{}) error { + c := in.(*Command) + fmt.Fprint(w, "Usage:") + if c.Runnable() { + fmt.Fprintf(w, "\n %s", c.UseLine()) + } + if c.HasAvailableSubCommands() { + fmt.Fprintf(w, "\n %s [command]", c.CommandPath()) + } + if len(c.Aliases) > 0 { + fmt.Fprintf(w, "\n\nAliases:\n") + fmt.Fprintf(w, " %s", c.NameAndAliases()) + } + if c.HasExample() { + fmt.Fprintf(w, "\n\nExamples:\n") + fmt.Fprintf(w, "%s", c.Example) + } + if c.HasAvailableSubCommands() { + cmds := c.Commands() + if len(c.Groups()) == 0 { + fmt.Fprintf(w, "\n\nAvailable Commands:") + for _, subcmd := range cmds { + if subcmd.IsAvailableCommand() || subcmd.Name() == helpCommandName { + fmt.Fprintf(w, "\n %s %s", rpad(subcmd.Name(), subcmd.NamePadding()), subcmd.Short) + } + } + } else { + for _, group := range c.Groups() { + fmt.Fprintf(w, "\n\n%s", group.Title) + for _, subcmd := range cmds { + if subcmd.GroupID == group.ID && (subcmd.IsAvailableCommand() || subcmd.Name() == helpCommandName) { + fmt.Fprintf(w, "\n %s %s", rpad(subcmd.Name(), subcmd.NamePadding()), subcmd.Short) + } + } + } + if !c.AllChildCommandsHaveGroup() { + fmt.Fprintf(w, "\n\nAdditional Commands:") + for _, subcmd := range cmds { + if subcmd.GroupID == "" && (subcmd.IsAvailableCommand() || subcmd.Name() == helpCommandName) { + fmt.Fprintf(w, "\n %s %s", rpad(subcmd.Name(), subcmd.NamePadding()), subcmd.Short) + } + } + } + } + } + if c.HasAvailableLocalFlags() { + fmt.Fprintf(w, "\n\nFlags:\n") + fmt.Fprint(w, trimRightSpace(c.LocalFlags().FlagUsages())) + } + if c.HasAvailableInheritedFlags() { + fmt.Fprintf(w, "\n\nGlobal Flags:\n") + fmt.Fprint(w, trimRightSpace(c.InheritedFlags().FlagUsages())) + } + if c.HasHelpSubCommands() { + fmt.Fprintf(w, "\n\nAdditional help topcis:") + for _, subcmd := range c.Commands() { + if subcmd.IsAdditionalHelpTopicCommand() { + fmt.Fprintf(w, "\n %s %s", rpad(subcmd.CommandPath(), subcmd.CommandPathPadding()), subcmd.Short) + } + } + } + if c.HasAvailableSubCommands() { + fmt.Fprintf(w, "\n\nUse \"%s [command] --help\" for more information about a command.", c.CommandPath()) + } + fmt.Fprintln(w) + return nil +} + +var defaultHelpTemplate = `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}} + +{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` + +// defaultHelpFunc is equivalent to executing defaultHelpTemplate. The two should be changed in sync. +func defaultHelpFunc(w io.Writer, in interface{}) error { + c := in.(*Command) + usage := c.Long + if usage == "" { + usage = c.Short + } + usage = trimRightSpace(usage) + if usage != "" { + fmt.Fprintln(w, usage) + fmt.Fprintln(w) + } + if c.Runnable() || c.HasSubCommands() { + fmt.Fprint(w, c.UsageString()) + } + return nil +} + +var defaultVersionTemplate = `{{with .DisplayName}}{{printf "%s " .}}{{end}}{{printf "version %s" .Version}} +` + +// defaultVersionFunc is equivalent to executing defaultVersionTemplate. The two should be changed in sync. +func defaultVersionFunc(w io.Writer, in interface{}) error { + c := in.(*Command) + _, err := fmt.Fprintf(w, "%s version %s\n", c.DisplayName(), c.Version) + return err +} diff --git a/vendor/github.com/spf13/cobra/completions.go b/vendor/github.com/spf13/cobra/completions.go index c0c08b05721e..a1752f763175 100644 --- a/vendor/github.com/spf13/cobra/completions.go +++ b/vendor/github.com/spf13/cobra/completions.go @@ -35,7 +35,7 @@ const ( ) // Global map of flag completion functions. Make sure to use flagCompletionMutex before you try to read and write from it. -var flagCompletionFunctions = map[*pflag.Flag]func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective){} +var flagCompletionFunctions = map[*pflag.Flag]CompletionFunc{} // lock for reading and writing from flagCompletionFunctions var flagCompletionMutex = &sync.RWMutex{} @@ -117,22 +117,50 @@ type CompletionOptions struct { HiddenDefaultCmd bool } +// Completion is a string that can be used for completions +// +// two formats are supported: +// - the completion choice +// - the completion choice with a textual description (separated by a TAB). +// +// [CompletionWithDesc] can be used to create a completion string with a textual description. +// +// Note: Go type alias is used to provide a more descriptive name in the documentation, but any string can be used. +type Completion = string + +// CompletionFunc is a function that provides completion results. +type CompletionFunc = func(cmd *Command, args []string, toComplete string) ([]Completion, ShellCompDirective) + +// CompletionWithDesc returns a [Completion] with a description by using the TAB delimited format. +func CompletionWithDesc(choice string, description string) Completion { + return choice + "\t" + description +} + // NoFileCompletions can be used to disable file completion for commands that should // not trigger file completions. -func NoFileCompletions(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { +// +// This method satisfies [CompletionFunc]. +// It can be used with [Command.RegisterFlagCompletionFunc] and for [Command.ValidArgsFunction]. +func NoFileCompletions(cmd *Command, args []string, toComplete string) ([]Completion, ShellCompDirective) { return nil, ShellCompDirectiveNoFileComp } // FixedCompletions can be used to create a completion function which always // returns the same results. -func FixedCompletions(choices []string, directive ShellCompDirective) func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { - return func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) { +// +// This method returns a function that satisfies [CompletionFunc] +// It can be used with [Command.RegisterFlagCompletionFunc] and for [Command.ValidArgsFunction]. +func FixedCompletions(choices []Completion, directive ShellCompDirective) CompletionFunc { + return func(cmd *Command, args []string, toComplete string) ([]Completion, ShellCompDirective) { return choices, directive } } // RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag. -func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)) error { +// +// You can use pre-defined completion functions such as [FixedCompletions] or [NoFileCompletions], +// or you can define your own. +func (c *Command) RegisterFlagCompletionFunc(flagName string, f CompletionFunc) error { flag := c.Flag(flagName) if flag == nil { return fmt.Errorf("RegisterFlagCompletionFunc: flag '%s' does not exist", flagName) @@ -148,7 +176,7 @@ func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Comman } // GetFlagCompletionFunc returns the completion function for the given flag of the command, if available. -func (c *Command) GetFlagCompletionFunc(flagName string) (func(*Command, []string, string) ([]string, ShellCompDirective), bool) { +func (c *Command) GetFlagCompletionFunc(flagName string) (CompletionFunc, bool) { flag := c.Flag(flagName) if flag == nil { return nil, false @@ -270,7 +298,15 @@ func (c *Command) initCompleteCmd(args []string) { } } -func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDirective, error) { +// SliceValue is a reduced version of [pflag.SliceValue]. It is used to detect +// flags that accept multiple values and therefore can provide completion +// multiple times. +type SliceValue interface { + // GetSlice returns the flag value list as an array of strings. + GetSlice() []string +} + +func (c *Command) getCompletions(args []string) (*Command, []Completion, ShellCompDirective, error) { // The last argument, which is not completely typed by the user, // should not be part of the list of arguments toComplete := args[len(args)-1] @@ -298,7 +334,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi } if err != nil { // Unable to find the real command. E.g., someInvalidCmd - return c, []string{}, ShellCompDirectiveDefault, fmt.Errorf("unable to find a command for arguments: %v", trimmedArgs) + return c, []Completion{}, ShellCompDirectiveDefault, fmt.Errorf("unable to find a command for arguments: %v", trimmedArgs) } finalCmd.ctx = c.ctx @@ -328,7 +364,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi // Parse the flags early so we can check if required flags are set if err = finalCmd.ParseFlags(finalArgs); err != nil { - return finalCmd, []string{}, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error()) + return finalCmd, []Completion{}, ShellCompDirectiveDefault, fmt.Errorf("Error while parsing flags from args %v: %s", finalArgs, err.Error()) } realArgCount := finalCmd.Flags().NArg() @@ -340,14 +376,14 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi if flagErr != nil { // If error type is flagCompError and we don't want flagCompletion we should ignore the error if _, ok := flagErr.(*flagCompError); !(ok && !flagCompletion) { - return finalCmd, []string{}, ShellCompDirectiveDefault, flagErr + return finalCmd, []Completion{}, ShellCompDirectiveDefault, flagErr } } // Look for the --help or --version flags. If they are present, // there should be no further completions. if helpOrVersionFlagPresent(finalCmd) { - return finalCmd, []string{}, ShellCompDirectiveNoFileComp, nil + return finalCmd, []Completion{}, ShellCompDirectiveNoFileComp, nil } // We only remove the flags from the arguments if DisableFlagParsing is not set. @@ -376,11 +412,11 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi return finalCmd, subDir, ShellCompDirectiveFilterDirs, nil } // Directory completion - return finalCmd, []string{}, ShellCompDirectiveFilterDirs, nil + return finalCmd, []Completion{}, ShellCompDirectiveFilterDirs, nil } } - var completions []string + var completions []Completion var directive ShellCompDirective // Enforce flag groups before doing flag completions @@ -399,10 +435,14 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi // If we have not found any required flags, only then can we show regular flags if len(completions) == 0 { doCompleteFlags := func(flag *pflag.Flag) { - if !flag.Changed || + _, acceptsMultiple := flag.Value.(SliceValue) + acceptsMultiple = acceptsMultiple || strings.Contains(flag.Value.Type(), "Slice") || - strings.Contains(flag.Value.Type(), "Array") { - // If the flag is not already present, or if it can be specified multiple times (Array or Slice) + strings.Contains(flag.Value.Type(), "Array") || + strings.HasPrefix(flag.Value.Type(), "stringTo") + + if !flag.Changed || acceptsMultiple { + // If the flag is not already present, or if it can be specified multiple times (Array, Slice, or stringTo) // we suggest it as a completion completions = append(completions, getFlagNameCompletions(flag, toComplete)...) } @@ -462,7 +502,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi for _, subCmd := range finalCmd.Commands() { if subCmd.IsAvailableCommand() || subCmd == finalCmd.helpCommand { if strings.HasPrefix(subCmd.Name(), toComplete) { - completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short)) + completions = append(completions, CompletionWithDesc(subCmd.Name(), subCmd.Short)) } directive = ShellCompDirectiveNoFileComp } @@ -507,7 +547,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi } // Find the completion function for the flag or command - var completionFn func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) + var completionFn CompletionFunc if flag != nil && flagCompletion { flagCompletionMutex.RLock() completionFn = flagCompletionFunctions[flag] @@ -518,7 +558,7 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi if completionFn != nil { // Go custom completion defined for this flag or command. // Call the registered completion function to get the completions. - var comps []string + var comps []Completion comps, directive = completionFn(finalCmd, finalArgs, toComplete) completions = append(completions, comps...) } @@ -531,23 +571,23 @@ func helpOrVersionFlagPresent(cmd *Command) bool { len(versionFlag.Annotations[FlagSetByCobraAnnotation]) > 0 && versionFlag.Changed { return true } - if helpFlag := cmd.Flags().Lookup("help"); helpFlag != nil && + if helpFlag := cmd.Flags().Lookup(helpFlagName); helpFlag != nil && len(helpFlag.Annotations[FlagSetByCobraAnnotation]) > 0 && helpFlag.Changed { return true } return false } -func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string { +func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []Completion { if nonCompletableFlag(flag) { - return []string{} + return []Completion{} } - var completions []string + var completions []Completion flagName := "--" + flag.Name if strings.HasPrefix(flagName, toComplete) { // Flag without the = - completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) + completions = append(completions, CompletionWithDesc(flagName, flag.Usage)) // Why suggest both long forms: --flag and --flag= ? // This forces the user to *always* have to type either an = or a space after the flag name. @@ -559,20 +599,20 @@ func getFlagNameCompletions(flag *pflag.Flag, toComplete string) []string { // if len(flag.NoOptDefVal) == 0 { // // Flag requires a value, so it can be suffixed with = // flagName += "=" - // completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) + // completions = append(completions, CompletionWithDesc(flagName, flag.Usage)) // } } flagName = "-" + flag.Shorthand if len(flag.Shorthand) > 0 && strings.HasPrefix(flagName, toComplete) { - completions = append(completions, fmt.Sprintf("%s\t%s", flagName, flag.Usage)) + completions = append(completions, CompletionWithDesc(flagName, flag.Usage)) } return completions } -func completeRequireFlags(finalCmd *Command, toComplete string) []string { - var completions []string +func completeRequireFlags(finalCmd *Command, toComplete string) []Completion { + var completions []Completion doCompleteRequiredFlags := func(flag *pflag.Flag) { if _, present := flag.Annotations[BashCompOneRequiredFlag]; present { @@ -687,8 +727,8 @@ func checkIfFlagCompletion(finalCmd *Command, args []string, lastArg string) (*p // 1- the feature has been explicitly disabled by the program, // 2- c has no subcommands (to avoid creating one), // 3- c already has a 'completion' command provided by the program. -func (c *Command) InitDefaultCompletionCmd() { - if c.CompletionOptions.DisableDefaultCmd || !c.HasSubCommands() { +func (c *Command) InitDefaultCompletionCmd(args ...string) { + if c.CompletionOptions.DisableDefaultCmd { return } @@ -701,6 +741,16 @@ func (c *Command) InitDefaultCompletionCmd() { haveNoDescFlag := !c.CompletionOptions.DisableNoDescFlag && !c.CompletionOptions.DisableDescriptions + // Special case to know if there are sub-commands or not. + hasSubCommands := false + for _, cmd := range c.commands { + if cmd.Name() != ShellCompRequestCmd && cmd.Name() != helpCommandName { + // We found a real sub-command (not 'help' or '__complete') + hasSubCommands = true + break + } + } + completionCmd := &Command{ Use: compCmdName, Short: "Generate the autocompletion script for the specified shell", @@ -714,6 +764,22 @@ See each sub-command's help for details on how to use the generated script. } c.AddCommand(completionCmd) + if !hasSubCommands { + // If the 'completion' command will be the only sub-command, + // we only create it if it is actually being called. + // This avoids breaking programs that would suddenly find themselves with + // a subcommand, which would prevent them from accepting arguments. + // We also create the 'completion' command if the user is triggering + // shell completion for it (prog __complete completion '') + subCmd, cmdArgs, err := c.Find(args) + if err != nil || subCmd.Name() != compCmdName && + !(subCmd.Name() == ShellCompRequestCmd && len(cmdArgs) > 1 && cmdArgs[0] == compCmdName) { + // The completion command is not being called or being completed so we remove it. + c.RemoveCommand(completionCmd) + return + } + } + out := c.OutOrStdout() noDesc := c.CompletionOptions.DisableDescriptions shortDesc := "Generate the autocompletion script for %s" diff --git a/vendor/github.com/spf13/cobra/powershell_completions.go b/vendor/github.com/spf13/cobra/powershell_completions.go index a830b7bcad2e..746dcb92e3ef 100644 --- a/vendor/github.com/spf13/cobra/powershell_completions.go +++ b/vendor/github.com/spf13/cobra/powershell_completions.go @@ -162,7 +162,10 @@ filter __%[1]s_escapeStringWithSpecialChars { if (-Not $Description) { $Description = " " } - @{Name="$Name";Description="$Description"} + New-Object -TypeName PSCustomObject -Property @{ + Name = "$Name" + Description = "$Description" + } } @@ -240,7 +243,12 @@ filter __%[1]s_escapeStringWithSpecialChars { __%[1]s_debug "Only one completion left" # insert space after value - [System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)") + $CompletionText = $($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space + if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){ + [System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)", 'ParameterValue', "$($comp.Description)") + } else { + $CompletionText + } } else { # Add the proper number of spaces to align the descriptions @@ -255,7 +263,12 @@ filter __%[1]s_escapeStringWithSpecialChars { $Description = " ($($comp.Description))" } - [System.Management.Automation.CompletionResult]::new("$($comp.Name)$Description", "$($comp.Name)$Description", 'ParameterValue', "$($comp.Description)") + $CompletionText = "$($comp.Name)$Description" + if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){ + [System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)$Description", 'ParameterValue', "$($comp.Description)") + } else { + $CompletionText + } } } @@ -264,7 +277,13 @@ filter __%[1]s_escapeStringWithSpecialChars { # insert space after value # MenuComplete will automatically show the ToolTip of # the highlighted value at the bottom of the suggestions. - [System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space, "$($comp.Name)", 'ParameterValue', "$($comp.Description)") + + $CompletionText = $($comp.Name | __%[1]s_escapeStringWithSpecialChars) + $Space + if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){ + [System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)", 'ParameterValue', "$($comp.Description)") + } else { + $CompletionText + } } # TabCompleteNext and in case we get something unknown @@ -272,7 +291,13 @@ filter __%[1]s_escapeStringWithSpecialChars { # Like MenuComplete but we don't want to add a space here because # the user need to press space anyway to get the completion. # Description will not be shown because that's not possible with TabCompleteNext - [System.Management.Automation.CompletionResult]::new($($comp.Name | __%[1]s_escapeStringWithSpecialChars), "$($comp.Name)", 'ParameterValue', "$($comp.Description)") + + $CompletionText = $($comp.Name | __%[1]s_escapeStringWithSpecialChars) + if ($ExecutionContext.SessionState.LanguageMode -eq "FullLanguage"){ + [System.Management.Automation.CompletionResult]::new($CompletionText, "$($comp.Name)", 'ParameterValue', "$($comp.Description)") + } else { + $CompletionText + } } } diff --git a/vendor/github.com/spf13/cobra/ya.make b/vendor/github.com/spf13/cobra/ya.make index 2d15e11c9bfd..58aedc1bf36e 100644 --- a/vendor/github.com/spf13/cobra/ya.make +++ b/vendor/github.com/spf13/cobra/ya.make @@ -2,7 +2,7 @@ GO_LIBRARY() LICENSE(Apache-2.0) -VERSION(v1.8.1) +VERSION(v1.9.1) SRCS( active_help.go diff --git a/vendor/github.com/spf13/pflag/ip.go b/vendor/github.com/spf13/pflag/ip.go index 3d414ba69fe1..06b8bcb57215 100644 --- a/vendor/github.com/spf13/pflag/ip.go +++ b/vendor/github.com/spf13/pflag/ip.go @@ -16,6 +16,9 @@ func newIPValue(val net.IP, p *net.IP) *ipValue { func (i *ipValue) String() string { return net.IP(*i).String() } func (i *ipValue) Set(s string) error { + if s == "" { + return nil + } ip := net.ParseIP(strings.TrimSpace(s)) if ip == nil { return fmt.Errorf("failed to parse IP: %q", s) diff --git a/vendor/github.com/spf13/pflag/ya.make b/vendor/github.com/spf13/pflag/ya.make index c40c23cce934..bef4b61d6b7e 100644 --- a/vendor/github.com/spf13/pflag/ya.make +++ b/vendor/github.com/spf13/pflag/ya.make @@ -2,7 +2,7 @@ GO_LIBRARY() LICENSE(BSD-3-Clause) -VERSION(v1.0.6-0.20201009195203-85dd5c8bc61c) +VERSION(v1.0.6) SRCS( bool.go diff --git a/vendor/golang.org/x/crypto/pbkdf2/ya.make b/vendor/golang.org/x/crypto/pbkdf2/ya.make index 0c1ba119c459..707da3616c75 100644 --- a/vendor/golang.org/x/crypto/pbkdf2/ya.make +++ b/vendor/golang.org/x/crypto/pbkdf2/ya.make @@ -2,7 +2,7 @@ GO_LIBRARY() LICENSE(BSD-3-Clause) -VERSION(v0.32.0) +VERSION(v0.33.0) SRCS( pbkdf2.go diff --git a/vendor/golang.org/x/crypto/scrypt/ya.make b/vendor/golang.org/x/crypto/scrypt/ya.make index 5e20fa7c1759..5ba22b0c2d17 100644 --- a/vendor/golang.org/x/crypto/scrypt/ya.make +++ b/vendor/golang.org/x/crypto/scrypt/ya.make @@ -2,7 +2,7 @@ GO_LIBRARY() LICENSE(BSD-3-Clause) -VERSION(v0.32.0) +VERSION(v0.33.0) SRCS( scrypt.go From 773bb0cf47a16f8a9bea561e57790e46eb5c87e6 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 8 Apr 2025 09:55:54 +0200 Subject: [PATCH 038/454] add GraphShardExists setting to capabilities handler (#16895) --- ydb/core/viewer/viewer_capabilities.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ydb/core/viewer/viewer_capabilities.h b/ydb/core/viewer/viewer_capabilities.h index b4f86ad9522f..54bcfce042cc 100644 --- a/ydb/core/viewer/viewer_capabilities.h +++ b/ydb/core/viewer/viewer_capabilities.h @@ -23,10 +23,21 @@ class TViewerCapabilities : public TViewerPipeClient { NJson::TJsonValue GetSettings() { NJson::TJsonValue json; + NJson::TJsonValue& security(json["Security"]); security["IsTokenRequired"] = AppData()->EnforceUserTokenRequirement; security["UseLoginProvider"] = AppData()->AuthConfig.GetUseLoginProvider(); security["DomainLoginOnly"] = AppData()->AuthConfig.GetDomainLoginOnly(); + + if (DatabaseNavigateResponse && DatabaseNavigateResponse->IsOk()) { + if (DatabaseNavigateResponse->Get()->Request && !DatabaseNavigateResponse->Get()->Request->ResultSet.empty()) { + NJson::TJsonValue& database(json["Database"]); + TSchemeCacheNavigate::TEntry& entry = DatabaseNavigateResponse->Get()->Request->ResultSet.front(); + if (entry.DomainInfo) { + database["GraphShardExists"] = entry.DomainInfo->Params.GetGraphShard() != 0; + } + } + } return json; } From 4eb3ce84c01c1e00a17d18634f90bfa8e738f412 Mon Sep 17 00:00:00 2001 From: Kirill Rysin <35688753+naspirato@users.noreply.github.com> Date: Tue, 8 Apr 2025 10:48:49 +0200 Subject: [PATCH 039/454] Regression runs: multi-branch run support + refactoring (#16735) --- .github/actions/build_and_test_ya/action.yml | 5 + .github/actions/test_ya/action.yml | 23 +++- .github/workflows/regression_run.yml | 14 ++- .../regression_run_compatibility.yml | 12 ++- .github/workflows/regression_run_large.yml | 12 ++- .../workflows/regression_run_small_medium.yml | 12 ++- .../workflows/regression_whitelist_run.yml | 14 ++- .github/workflows/run_tests.yml | 100 +++++++++++++++--- 8 files changed, 158 insertions(+), 34 deletions(-) diff --git a/.github/actions/build_and_test_ya/action.yml b/.github/actions/build_and_test_ya/action.yml index 9dd86a4820ea..993e3c324524 100644 --- a/.github/actions/build_and_test_ya/action.yml +++ b/.github/actions/build_and_test_ya/action.yml @@ -51,6 +51,10 @@ inputs: vars: type: string default: "" + custom_branch_name: + description: "Custom branch name required when workflow branch != checkout branch" + type: string + required: false defaults: run: shell: bash @@ -88,3 +92,4 @@ runs: bazel_remote_password: ${{ fromJSON( inputs.secs ).REMOTE_CACHE_PASSWORD || '' }} put_build_results_to_cache: ${{ inputs.put_build_results_to_cache }} test_retry_count: ${{ inputs.test_retry_count }} + custom_branch_name: ${{ inputs.custom_branch_name }} diff --git a/.github/actions/test_ya/action.yml b/.github/actions/test_ya/action.yml index 97b574459858..9ccf0c29e49d 100644 --- a/.github/actions/test_ya/action.yml +++ b/.github/actions/test_ya/action.yml @@ -60,6 +60,11 @@ inputs: type: string default: "" description: "how many times to retry failed tests" + custom_branch_name: + description: "Custom branch name required when workflow branch != checkout branch" + type: string + required: false + outputs: success: value: ${{ steps.build.outputs.status }} @@ -271,8 +276,18 @@ runs: --cache-size 2TB --force-build-depends ) + echo "inputs.custom_branch_name = ${{ inputs.custom_branch_name }}" + echo "GITHUB_REF_NAME = $GITHUB_REF_NAME" + + if [ -z "${{ inputs.custom_branch_name }}" ]; then + BRANCH_NAME="${GITHUB_REF_NAME}" + else + BRANCH_NAME="${{ inputs.custom_branch_name }}" + fi + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV + echo "BRANCH_NAME is set to $BRANCH_NAME" - TESTMO_BRANCH_TAG="$GITHUB_REF_NAME" + TESTMO_BRANCH_TAG="$BRANCH_NAME" TESTMO_ARCH="${{ runner.arch == 'X64' && 'x86-64' || runner.arch == 'ARM64' && 'arm64' || 'unknown' }}" TESTMO_PR_NUMBER=${{ github.event.number }} @@ -470,7 +485,7 @@ runs: # upload tests results to YDB ydb_upload_run_name="${TESTMO_RUN_NAME// /"_"}" - result=`.github/scripts/analytics/upload_tests_results.py --test-results-file ${CURRENT_JUNIT_XML_PATH} --run-timestamp $(date +%s) --commit $(git rev-parse HEAD) --build-type ${BUILD_PRESET} --pull $ydb_upload_run_name --job-name "${{ github.workflow }}" --job-id "${{ github.run_id }}" --branch ${GITHUB_REF_NAME}` + result=`.github/scripts/analytics/upload_tests_results.py --test-results-file ${CURRENT_JUNIT_XML_PATH} --run-timestamp $(date +%s) --commit $(git rev-parse HEAD) --build-type ${BUILD_PRESET} --pull $ydb_upload_run_name --job-name "${{ github.workflow }}" --job-id "${{ github.run_id }}" --branch "${BRANCH_NAME}"` if [ ${{ inputs.testman_token }} ]; then # finish testme session @@ -573,7 +588,7 @@ runs: echo file ${file_to_check} NOT changed else echo file ${file_to_check} changed - .github/scripts/tests/get_muted_tests.py --output_folder "$PUBLIC_DIR/mute_info/" get_mute_diff --base_sha $ORIGINAL_HEAD~1 --head_sha $ORIGINAL_HEAD --job-id "${{ github.run_id }}" --branch "${GITHUB_REF_NAME}" + .github/scripts/tests/get_muted_tests.py --output_folder "$PUBLIC_DIR/mute_info/" get_mute_diff --base_sha $ORIGINAL_HEAD~1 --head_sha $ORIGINAL_HEAD --job-id "${{ github.run_id }}" --branch "${BRANCH_NAME}" FILE_PATH=$PUBLIC_DIR/mute_info/2_new_muted_tests.txt SEPARATOR="" if [ -f "$FILE_PATH" ]; then @@ -633,7 +648,7 @@ runs: run: | set -x export build_preset="${{ inputs.build_preset }}" - export branch_to_compare="$GITHUB_REF_NAME" + export branch_to_compare="$BRANCH_NAME" export yellow_treshold=102400 export red_treshold=2097152 export commit_git_sha="$(git rev-parse HEAD)" diff --git a/.github/workflows/regression_run.yml b/.github/workflows/regression_run.yml index 786ffe0f3e37..9feadcbd7fce 100644 --- a/.github/workflows/regression_run.yml +++ b/.github/workflows/regression_run.yml @@ -2,8 +2,14 @@ name: Regression-run on: schedule: - - cron: "0 23 * * *" # At 23:00 every day + - cron: "55 23 * * *" # At 23:55 every day workflow_dispatch: + inputs: + use_default_branches: + description: 'If true, start main and all current stable branches. If false, start only the selected branch.' + type: boolean + required: false + default: true jobs: main: @@ -13,8 +19,8 @@ jobs: strategy: fail-fast: false matrix: - build_preset: ["relwithdebinfo", "release-asan", "release-tsan", "release-msan"] + build_preset: ["relwithdebinfo", "release-asan", "release-tsan", "release-msan"] with: test_targets: ydb/ - build_preset: ${{ matrix.build_preset }} - + branches: ${{ inputs.use_default_branches == true && '["main", "stable-25-1", "stable-25-1-1", "stable-25-1-analytics"]' || github.ref_name }} + build_preset: ${{ matrix.build_preset }} \ No newline at end of file diff --git a/.github/workflows/regression_run_compatibility.yml b/.github/workflows/regression_run_compatibility.yml index 3d68c975562a..765ce5de05cb 100644 --- a/.github/workflows/regression_run_compatibility.yml +++ b/.github/workflows/regression_run_compatibility.yml @@ -4,6 +4,12 @@ on: schedule: - cron: "0 23 * * *" # At 23:00 every day workflow_dispatch: + inputs: + use_default_branches: + description: 'If true, start main and all current stable branches. If false, start only the selected branch.' + type: boolean + required: false + default: true jobs: main: @@ -13,8 +19,8 @@ jobs: strategy: fail-fast: false matrix: - build_preset: ["relwithdebinfo", "release-asan", "release-tsan", "release-msan"] + build_preset: ["relwithdebinfo", "release-asan", "release-tsan", "release-msan"] with: test_targets: ydb/tests/functional/compatibility/ - build_preset: ${{ matrix.build_preset }} - + branches: ${{ inputs.use_default_branches == true && '["main", "stable-25-1", "stable-25-1-1"]' || github.ref_name }} + build_preset: ${{ matrix.build_preset }} \ No newline at end of file diff --git a/.github/workflows/regression_run_large.yml b/.github/workflows/regression_run_large.yml index 8117dcabb910..008bfe56f614 100644 --- a/.github/workflows/regression_run_large.yml +++ b/.github/workflows/regression_run_large.yml @@ -2,8 +2,14 @@ name: Regression-run_Large on: schedule: - - cron: "0 23 * * *" # At 23:00 every day + - cron: "30 23 * * *" # At 23:30 every day workflow_dispatch: + inputs: + use_default_branches: + description: 'If true, start main and all current stable branches. If false, start only the selected branch.' + type: boolean + required: false + default: true jobs: main: @@ -13,9 +19,9 @@ jobs: strategy: fail-fast: false matrix: - build_preset: ["relwithdebinfo", "release-asan", "release-tsan", "release-msan"] + build_preset: ["relwithdebinfo", "release-asan", "release-tsan", "release-msan"] with: test_targets: ydb/ test_size: large + branches: ${{ inputs.use_default_branches == true && '["main", "stable-25-1", "stable-25-1-1"]' || github.ref_name }} build_preset: ${{ matrix.build_preset }} - diff --git a/.github/workflows/regression_run_small_medium.yml b/.github/workflows/regression_run_small_medium.yml index 8b3501899ca4..b13b9cf849ca 100644 --- a/.github/workflows/regression_run_small_medium.yml +++ b/.github/workflows/regression_run_small_medium.yml @@ -2,8 +2,14 @@ name: Regression-run_Small_and_Medium on: schedule: - - cron: "0 23 * * *" # At 23:00 every day + - cron: "30 23 * * *" # At 23:30 every day workflow_dispatch: + inputs: + use_default_branches: + description: 'If true, start main and all current stable branches. If false, start only the selected branch.' + type: boolean + required: false + default: true jobs: main: @@ -13,9 +19,9 @@ jobs: strategy: fail-fast: false matrix: - build_preset: ["relwithdebinfo", "release-asan", "release-tsan", "release-msan"] + build_preset: ["relwithdebinfo", "release-asan", "release-tsan", "release-msan"] with: test_targets: ydb/ test_size: small,medium + branches: ${{ inputs.use_default_branches== true && '["main", "stable-25-1", "stable-25-1-1"]' || github.ref_name }} build_preset: ${{ matrix.build_preset }} - diff --git a/.github/workflows/regression_whitelist_run.yml b/.github/workflows/regression_whitelist_run.yml index 839d0436a577..d9e425aae999 100644 --- a/.github/workflows/regression_whitelist_run.yml +++ b/.github/workflows/regression_whitelist_run.yml @@ -4,6 +4,12 @@ on: schedule: - cron: "0 23 * * *" # At 23:00 every day workflow_dispatch: + inputs: + use_default_branches: + description: 'If true, start main and all current stable branches. If false, start only the selected branch.' + type: boolean + required: false + default: true jobs: main: @@ -12,9 +18,9 @@ jobs: secrets: inherit strategy: fail-fast: false - matrix: - build_preset: ["relwithdebinfo", "release-asan", "release-tsan", "release-msan"] + matrix: + build_preset: ["relwithdebinfo", "release-asan", "release-tsan", "release-msan"] with: test_targets: ydb/tests/sql/ ydb/tests/stress ydb/tests/functional/tpc ydb/tests/functional/benchmarks_init - build_preset: ${{ matrix.build_preset }} - + branches: ${{ inputs.use_default_branches == true && '["main", "stable-25-1", "stable-25-1-1", "stable-25-1-analytics"]' || github.ref_name }} + build_preset: ${{ matrix.build_preset }} \ No newline at end of file diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index b50731cda442..a4aa66e4c962 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -9,35 +9,108 @@ on: type: string default: self-hosted test_targets: - description: 'Пути запуска' + description: 'Paths to tests for run ,example : ydb/ ydb/tests/func/suite' required: true type: string default: ydb/ test_type: - description: 'Тип тестов' + description: 'Test type (unittest,py3test,py2test,pytest)' required: false type: string default: unittest,py3test,py2test,pytest test_size: - description: 'Размер тестов' + description: 'Test size (small,medium,large)' required: false type: string default: small,medium,large additional_ya_make_args: - description: 'Дополнительные аргументы для ya make' + description: 'additional args for ya make' required: false type: string - default: -DDEBUGINFO_LINES_ONLY + default: '' build_preset: description: 'Build preset type' required: true type: string - + branches: + description: 'Branches to test (JSON array or single branch)' + required: false + type: string + default: '["main"]' + + workflow_dispatch: + inputs: + runner_label: + description: 'Label of the runner to be used' + required: false + default: self-hosted + test_targets: + description: 'Paths to tests for run ,example : ydb/ ydb/tests/func/suite' + required: true + default: ydb/ + test_type: + description: 'Test type (unittest,py3test,py2test,pytest)' + required: false + default: unittest,py3test,py2test,pytest + test_size: + description: 'Test size (small,medium,large)' + required: false + type: choice + default: small,medium,large + options: + - small + - medium, + - large + - small,medium + - small,medium,large + additional_ya_make_args: + description: 'additional args for ya make' + required: false + default: '' + build_preset: + description: 'Build preset type (relwithdebinfo, release-asan, release-msan, release-tsan)' + required: true + type: choice + options: + - relwithdebinfo + - release-asan + - release-msan + - release-tsan + default: relwithdebinfo + branches: + description: 'Branches to test (JSON array or single branch name)' + required: false + default: '["main"]' + jobs: + prepare: + runs-on: ubuntu-latest + outputs: + branch_array: ${{ steps.set-branches.outputs.branch_array }} + steps: + - name: Set branches + id: set-branches + run: | + INPUT_BRANCHES='${{ inputs.branches }}' + # Check if input is a JSON array + if [[ $INPUT_BRANCHES == \[* ]]; then + echo "branch_array=$INPUT_BRANCHES" >> $GITHUB_OUTPUT + else + # If it's a single branch, create a JSON array with one element + echo "branch_array=[\"$INPUT_BRANCHES\"]" >> $GITHUB_OUTPUT + fi + + echo "Using branches: $(cat $GITHUB_OUTPUT | grep branch_array | cut -d= -f2)" + run_tests: - name: Test ${{ github.ref_name }}:${{ inputs.build_preset }} + needs: prepare + name: ${{ matrix.branch }}:${{ inputs.build_preset }} timeout-minutes: 1200 runs-on: ${{ inputs.runner_label }} + strategy: + fail-fast: false + matrix: + branch: ${{ fromJson(needs.prepare.outputs.branch_array) }} steps: - name: Set variables based on build_preset id: set-vars @@ -59,11 +132,11 @@ jobs: exit 1 fi - - name: Checkout + - name: Checkout ${{ matrix.branch }} uses: actions/checkout@v4 with: - ref: ${{ github.ref_name }} - + ref: ${{ matrix.branch }} + - name: Setup ssh key for slice uses: webfactory/ssh-agent@v0.9.0 with: @@ -74,7 +147,7 @@ jobs: with: ci_ydb_service_account_key_file_credentials: ${{ secrets.CI_YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS }} - - name: Run YDB Tests ${{ github.ref_name }} + - name: Run YDB Tests timeout-minutes: ${{ fromJson(env.timeout) }} uses: ./.github/actions/build_and_test_ya with: @@ -87,9 +160,10 @@ jobs: test_size: ${{ inputs.test_size }} test_type: ${{ inputs.test_type }} test_threads: ${{ fromJson(env.threads_count) }} + custom_branch_name: ${{ matrix.branch }} put_build_results_to_cache: true - additional_ya_make_args: ${{ inputs.additional_ya_make_args }} + additional_ya_make_args: -DDEBUGINFO_LINES_ONLY ${{ inputs.additional_ya_make_args }} secs: ${{ format('{{"TESTMO_TOKEN2":"{0}","AWS_KEY_ID":"{1}","AWS_KEY_VALUE":"{2}","REMOTE_CACHE_USERNAME":"{3}","REMOTE_CACHE_PASSWORD":"{4}"}}', secrets.TESTMO_TOKEN2, secrets.AWS_KEY_ID, secrets.AWS_KEY_VALUE, secrets.REMOTE_CACHE_USERNAME, secrets.REMOTE_CACHE_PASSWORD ) }} vars: ${{ format('{{"AWS_BUCKET":"{0}","AWS_ENDPOINT":"{1}","REMOTE_CACHE_URL":"{2}","TESTMO_URL":"{3}","TESTMO_PROJECT_ID":"{4}"}}', - vars.AWS_BUCKET, vars.AWS_ENDPOINT, vars.REMOTE_CACHE_URL_YA, vars.TESTMO_URL, vars.TESTMO_PROJECT_ID ) }} \ No newline at end of file + vars.AWS_BUCKET, vars.AWS_ENDPOINT, vars.REMOTE_CACHE_URL_YA, vars.TESTMO_URL, vars.TESTMO_PROJECT_ID ) }} From add78ca6977707c8f7ba1d1725b9a94afcb43deb Mon Sep 17 00:00:00 2001 From: Valery Mironov Date: Tue, 8 Apr 2025 11:53:08 +0300 Subject: [PATCH 040/454] Vector index docs (#16484) Co-authored-by: azevaykin <145343289+azevaykin@users.noreply.github.com> Co-authored-by: anton-bobkov Co-authored-by: Andrey Fomichev --- .../core/concepts/_includes/vector_indexes.md | 118 +++++++++++++++++ ydb/docs/en/core/concepts/column-table.md | 1 + .../concepts/datamodel/_includes/table.md | 1 + ydb/docs/en/core/concepts/glossary.md | 4 + ydb/docs/en/core/concepts/toc_i.yaml | 2 + ydb/docs/en/core/concepts/vector_indexes.md | 1 + ydb/docs/en/core/dev/toc_p.yaml | 2 + ydb/docs/en/core/dev/vector-indexes.md | 62 +++++++++ .../reference/observability/metrics/index.md | 2 +- .../commands/_includes/secondary_index.md | 4 +- .../export-import/_includes/s3_export.md | 1 + .../export-import/_includes/tools_restore.md | 4 +- .../yql/reference/syntax/alter_table/index.md | 2 +- .../{secondary_index.md => indexes.md} | 7 +- .../reference/syntax/alter_table/toc_i.yaml | 2 +- .../reference/syntax/create_table/index.md | 1 + .../reference/syntax/create_table/toc_i.yaml | 11 +- .../syntax/create_table/vector_index.md | 68 ++++++++++ .../yql/reference/syntax/select/toc_i.yaml | 43 +++---- .../reference/syntax/select/vector_index.md | 51 ++++++++ .../core/concepts/_includes/vector_indexes.md | 119 ++++++++++++++++++ .../concepts/datamodel/_includes/table.md | 1 + ydb/docs/ru/core/concepts/glossary.md | 4 + ydb/docs/ru/core/concepts/toc_i.yaml | 2 + ydb/docs/ru/core/concepts/vector_indexes.md | 1 + ydb/docs/ru/core/dev/toc_p.yaml | 2 + ydb/docs/ru/core/dev/vector-indexes.md | 61 +++++++++ .../reference/observability/metrics/index.md | 2 +- .../commands/_includes/secondary_index.md | 4 +- .../export-import/_includes/export-s3.md | 1 + .../export-import/_includes/tools-restore.md | 4 +- .../yql/reference/syntax/alter_table/index.md | 2 +- .../{secondary_index.md => indexes.md} | 7 +- .../reference/syntax/alter_table/toc_i.yaml | 2 +- .../reference/syntax/create_table/index.md | 1 + .../reference/syntax/create_table/toc_i.yaml | 11 +- .../syntax/create_table/vector_index.md | 67 ++++++++++ .../yql/reference/syntax/select/toc_i.yaml | 43 +++---- .../reference/syntax/select/vector_index.md | 51 ++++++++ 39 files changed, 700 insertions(+), 72 deletions(-) create mode 100644 ydb/docs/en/core/concepts/_includes/vector_indexes.md create mode 100644 ydb/docs/en/core/concepts/vector_indexes.md create mode 100644 ydb/docs/en/core/dev/vector-indexes.md rename ydb/docs/en/core/yql/reference/syntax/alter_table/{secondary_index.md => indexes.md} (89%) create mode 100644 ydb/docs/en/core/yql/reference/syntax/create_table/vector_index.md create mode 100644 ydb/docs/en/core/yql/reference/syntax/select/vector_index.md create mode 100644 ydb/docs/ru/core/concepts/_includes/vector_indexes.md create mode 100644 ydb/docs/ru/core/concepts/vector_indexes.md create mode 100644 ydb/docs/ru/core/dev/vector-indexes.md rename ydb/docs/ru/core/yql/reference/syntax/alter_table/{secondary_index.md => indexes.md} (90%) create mode 100644 ydb/docs/ru/core/yql/reference/syntax/create_table/vector_index.md create mode 100644 ydb/docs/ru/core/yql/reference/syntax/select/vector_index.md diff --git a/ydb/docs/en/core/concepts/_includes/vector_indexes.md b/ydb/docs/en/core/concepts/_includes/vector_indexes.md new file mode 100644 index 000000000000..45ecec622bad --- /dev/null +++ b/ydb/docs/en/core/concepts/_includes/vector_indexes.md @@ -0,0 +1,118 @@ +# Vector indexes + +{{ ydb-short-name }} supports [vector indexes](https://en.wikipedia.org/wiki/Vector_database) to efficiently find the top k rows with vector values closest to a query vector. Unlike secondary indexes that optimize equality or range queries, vector indexes enable similarity search based on distance or similarity functions. + +Vector indexes are particularly useful for: + +* recommendation systems (finding similar items/users) +* semantic search (matching text embeddings) +* image similarity search +* anomaly detection (finding outliers) +* classification systems (finding nearest labeled examples) + +## Vector index characteristics {#characteristics} + +Vector indexes in {{ ydb-short-name }}: + +* Solve nearest neighbor search problems using similarity or distance functions +* Support multiple distance/similarity functions: "inner_product", "cosine" similarity and "cosine", "euclidean", "manhattan" distance +* Currently implement a single index type: `vector_kmeans_tree` + +### Vector index `vector_kmeans_tree` type {#vector-kmeans-tree-type} + +The `vector_kmeans_tree` index implements a hierarchical clustering structure. Its organization includes: + +1. Hierarchical clustering: + + - The index builds multiple levels of k-means clusters + - At each level, vectors are partitioned into specified number of clusters in power of level + - First level clusters the entire dataset + - Subsequent levels recursively cluster each parent cluster's contents + +2. Search process: + + - During queries, the index examines only the most promising clusters + - This search space pruning avoids exhaustive search through all vectors + +3. Parameters: + + - `levels`: The number of tree levels (typically 1-3). Controls search depth + - `clusters`: The number of clusters on each level (typically 64-512). Determines search breadth at each level + +## Vector index types {#types} + +### Basic vector index {#basic} + +The simplest form that indexes vectors without additional filtering capabilities. For example: + +```yql +ALTER TABLE my_table + ADD INDEX my_index + GLOBAL USING vector_kmeans_tree + ON (embedding) + WITH (distance=cosine, type="uint8", dimension=512, levels=2, clusters=128); +``` + +### Vector index with covered columns {#covering} + +Includes additional columns to avoid reading from the main table during queries: + +```yql +ALTER TABLE my_table + ADD INDEX my_index + GLOBAL USING vector_kmeans_tree + ON (embedding) COVER (data) + WITH (distance=cosine, type="uint8", dimension=512, levels=2, clusters=128); +``` + +### Prefixed vector index {#prefixed} + +Allows filtering by prefix columns before performing vector search: + +```yql +ALTER TABLE my_table + ADD INDEX my_index + GLOBAL USING vector_kmeans_tree + ON (user, embedding) + WITH (distance=cosine, type="uint8", dimension=512, levels=2, clusters=128); +``` + +### Prefixed vector index with covered columns {#prefixed-covering} + +Combines prefix filtering with covered columns for optimal performance: + +```yql +ALTER TABLE my_table + ADD INDEX my_index + GLOBAL USING vector_kmeans_tree + ON (user, embedding) COVER (data) + WITH (distance=cosine, type="uint8", dimension=512, levels=2, clusters=128); +``` + +## Creating vector indexes {#creation} + +Vector indexes can be created: + +* When creating a table with the YQL [`CREATE TABLE` statement](../../yql/reference/syntax/create_table/vector_index.md) +* Added to an existing table with the YQL [`ALTER TABLE` statement](../../yql/reference/syntax/alter_table/indexes.md) + +For more information about vector index parameters, see [`CREATE TABLE` statement](../../yql/reference/syntax/create_table/vector_index.md). + +## Using vector indexes {#usage} + +Query vector indexes using the VIEW syntax in YQL. For prefixed indexes, include the prefix columns in the WHERE clause: + +```yql +SELECT user, data +FROM my_table VIEW my_index +WHERE user = "..." +ORDER BY Knn::CosineSimilarity(embedding, ...) DESC +LIMIT 10; +``` + + +## Limitations {#limitations} + +Currently not supported: +* modifying rows in indexed tables +* bit vector type diff --git a/ydb/docs/en/core/concepts/column-table.md b/ydb/docs/en/core/concepts/column-table.md index 6a6483a5b496..926388448c95 100644 --- a/ydb/docs/en/core/concepts/column-table.md +++ b/ydb/docs/en/core/concepts/column-table.md @@ -22,6 +22,7 @@ What's currently not supported: * Reading data from replicas * Secondary indexes +* Vector indexes * Bloom filters * Change Data Capture * Renaming tables diff --git a/ydb/docs/en/core/concepts/datamodel/_includes/table.md b/ydb/docs/en/core/concepts/datamodel/_includes/table.md index 54a5f372b656..6728a76cb344 100644 --- a/ydb/docs/en/core/concepts/datamodel/_includes/table.md +++ b/ydb/docs/en/core/concepts/datamodel/_includes/table.md @@ -197,6 +197,7 @@ At the moment, not all functionality of column-oriented tables is implemented. T * Reading from replicas. * Secondary indexes. +* Vector indexes. * Bloom filters. * Change Data Capture. * Table renaming. diff --git a/ydb/docs/en/core/concepts/glossary.md b/ydb/docs/en/core/concepts/glossary.md index 4a10e38c7ed6..5e895c7507f5 100644 --- a/ydb/docs/en/core/concepts/glossary.md +++ b/ydb/docs/en/core/concepts/glossary.md @@ -157,6 +157,10 @@ A **primary index** or **primary key index** is the main data structure used to A **secondary index** is an additional data structure used to locate rows in a table, typically when it can't be done efficiently using the [primary index](#primary-index). Unlike the primary index, secondary indexes are managed independently from the main table data. Thus, a table might have multiple secondary indexes for different use cases. {{ ydb-short-name }}'s capabilities in terms of secondary indexes are covered in a separate article [{#T}](secondary_indexes.md). Secondary indexes can be either unique or non-unique. +#### Vector Index {#vector-index} + +A **vector index** is an additional data structure used to speed up the [nearest neighbor search](https://en.wikipedia.org/wiki/Nearest_neighbor_search), typically when the data is too large for the [index-less approach](../yql/reference/udf/list/knn.md) to handle the load. Unlike the primary index, vector indexes are managed independently of the underlying table data. Thus, a table can have multiple vector indexes for different scenarios. For more information about using vector indexes in {{ ydb-short-name }}, see [{#T}](vector_indexes.md). + #### Column family {#column-family} A **column family** or **column group** is a feature that allows storing a subset of [row-oriented table](#row-oriented-table) columns separately in a distinct family or group. The primary use case is to store some columns on different kinds of disk drives (offload less important columns to HDD) or with various compression settings. If the workload requires many column families, consider using [column-oriented tables](#column-oriented-table) instead. diff --git a/ydb/docs/en/core/concepts/toc_i.yaml b/ydb/docs/en/core/concepts/toc_i.yaml index 334dfc4bdd6d..8a412dcc03db 100644 --- a/ydb/docs/en/core/concepts/toc_i.yaml +++ b/ydb/docs/en/core/concepts/toc_i.yaml @@ -14,6 +14,8 @@ items: href: transactions.md - name: Secondary indexes href: secondary_indexes.md +- name: Vector indexes + href: vector_indexes.md - name: Change Data Capture (CDC) href: cdc.md when: feature_changefeed diff --git a/ydb/docs/en/core/concepts/vector_indexes.md b/ydb/docs/en/core/concepts/vector_indexes.md new file mode 100644 index 000000000000..1d84e130e61f --- /dev/null +++ b/ydb/docs/en/core/concepts/vector_indexes.md @@ -0,0 +1 @@ +{% include [vector_indexes.md](_includes/vector_indexes.md) %} diff --git a/ydb/docs/en/core/dev/toc_p.yaml b/ydb/docs/en/core/dev/toc_p.yaml index 30c072102005..18c3bbf2fc76 100644 --- a/ydb/docs/en/core/dev/toc_p.yaml +++ b/ydb/docs/en/core/dev/toc_p.yaml @@ -18,6 +18,8 @@ items: path: primary-key/toc_p.yaml - name: Secondary indexes href: secondary-indexes.md +- name: Vector indexes + href: vector-indexes.md - name: Query plans optimization href: query-plans-optimization.md - name: Batch upload diff --git a/ydb/docs/en/core/dev/vector-indexes.md b/ydb/docs/en/core/dev/vector-indexes.md new file mode 100644 index 000000000000..d20eefce4203 --- /dev/null +++ b/ydb/docs/en/core/dev/vector-indexes.md @@ -0,0 +1,62 @@ +# Vector indexes + +[Vector indexes](https://en.wikipedia.org/wiki/Vector_database) are specialized data structures that enable efficient similarity search in high-dimensional spaces. Unlike traditional indexes that optimize exact lookups, vector indexes allow finding the most similar items to a query vector based on mathematical distance or similarity measures. + +Data in a {{ ydb-short-name }} table is stored and sorted by a primary key, enabling efficient point lookups and range scans. Vector indexes provide similar efficiency for nearest neighbor searches in vector spaces, which is particularly valuable for working with embeddings and other high-dimensional data representations. + +This article describes practical operations with vector indexes. For conceptual information about vector index types and their characteristics, see [Vector indexes](../concepts/vector_indexes.md) in the Concepts section. + +## Creating vector indexes {#create} + +A vector index can be created with the following YQL commands: +* [`CREATE TABLE`](../yql/reference/syntax/create_table/index.md) +* [`ALTER TABLE`](../yql/reference/syntax/alter_table/index.md) + +Example of creating a prefixed vector index with covered columns: + +```yql +ALTER TABLE my_table + ADD INDEX my_index + GLOBAL USING vector_kmeans_tree + ON (user, embedding) COVER (data) + WITH (distance=cosine, type="uint8", dimension=512, levels=2, clusters=128); +``` + +Key parameters for `vector_kmeans_tree`: +* `distance`/`similarity`: Metric function ("cosine", "euclidean", etc.) +* `type`: Data type ("float", "int8", "uint8") +* `dimension`: Number of dimensions (<= 16384) +* `levels`: Tree depth +* `clusters`: Number of clusters per level (values > 1000 may impact performance) + +Since building a vector index requires processing existing data, index creation on populated tables may take significant time. This operation runs in the background, allowing continued table access during construction. The index becomes available automatically when ready. + +## Using vector indexes for similarity search {#use} + +To perform similarity searches, explicitly specify the index name in the VIEW clause. For prefixed indexes, include prefix column conditions in the WHERE clause: + +```yql +DECLARE $query_vector AS List; + +SELECT user, data +FROM my_table VIEW my_index +WHERE user = "john_doe" +ORDER BY Knn::CosineSimilarity(embedding, $query_vector) DESC +LIMIT 10; +``` + +Without the VIEW clause, the query would perform a full table scan with brute-force vector comparison. + +## Checking the cost of queries {#cost} + +Any query made in a transactional application should be checked in terms of the number of I/O operations it performed in the database and how much CPU was used to run it. You should also make sure these indicators don't continuously grow as the database volume grows. {{ ydb-short-name }} returns statistics required for the analysis after running each query. + +If you use the {{ ydb-short-name }} CLI, select the `--stats` option to enable printing statistics after executing the `yql` command. All {{ ydb-short-name }} SDKs also contain structures with statistics returned after running a query. If you make a query in the UI, you'll see a tab with statistics next to the results tab. + +{% note warning %} + +Vector indexes currently don't support data modification operations. +Any attempt to modify rows in indexed tables will fail. +This limitation will be removed in future releases. + +{% endnote %} diff --git a/ydb/docs/en/core/reference/observability/metrics/index.md b/ydb/docs/en/core/reference/observability/metrics/index.md index 33df8b74c01f..15af7e34db7f 100644 --- a/ydb/docs/en/core/reference/observability/metrics/index.md +++ b/ydb/docs/en/core/reference/observability/metrics/index.md @@ -5,7 +5,7 @@ | Metric name
Type, units of measurement | Description
Labels | | ----- | ----- | | `resources.storage.used_bytes`
`IGAUGE`, bytes | The size of user and service data stored in distributed network storage. `resources.storage.used_bytes` = `resources.storage.table.used_bytes` + `resources.storage.topic.used_bytes`. | -| `resources.storage.table.used_bytes`
`IGAUGE`, bytes | The size of user and service data stored by tables in distributed network storage. Service data includes the data of the primary and [secondary indexes](../../../concepts/secondary_indexes.md). | +| `resources.storage.table.used_bytes`
`IGAUGE`, bytes | The size of user and service data stored by tables in distributed network storage. Service data includes the data of the primary, [secondary indexes](../../../concepts/secondary_indexes.md) and [vector indexes](../../../concepts/vector_indexes.md). | | `resources.storage.topic.used_bytes`
`IGAUGE`, bytes | The size of storage used by topics. This metric sums the `topic.storage_bytes` values of all topics. | | `resources.storage.limit_bytes`
`IGAUGE`, bytes | A limit on the size of user and service data that a database can store in distributed network storage. | diff --git a/ydb/docs/en/core/reference/ydb-cli/commands/_includes/secondary_index.md b/ydb/docs/en/core/reference/ydb-cli/commands/_includes/secondary_index.md index 7e6a5366ac5a..6fe44932e2ff 100644 --- a/ydb/docs/en/core/reference/ydb-cli/commands/_includes/secondary_index.md +++ b/ydb/docs/en/core/reference/ydb-cli/commands/_includes/secondary_index.md @@ -89,9 +89,9 @@ Deleting the index-building details (use the actual operation id): {{ ydb-cli }} -p quickstart operation forget ydb://buildindex/7?id=2814749869 ``` -## Deleting a secondary index {#drop} +## Deleting a index {#drop} -Secondary indexes are deleted by the `table index drop` command: +Indexes are deleted by the `table index drop` command: ```bash {{ ydb-cli }} [connection options] table index drop --index-name STR diff --git a/ydb/docs/en/core/reference/ydb-cli/export-import/_includes/s3_export.md b/ydb/docs/en/core/reference/ydb-cli/export-import/_includes/s3_export.md index 3158c213998c..c4e4a213909f 100644 --- a/ydb/docs/en/core/reference/ydb-cli/export-import/_includes/s3_export.md +++ b/ydb/docs/en/core/reference/ydb-cli/export-import/_includes/s3_export.md @@ -13,6 +13,7 @@ The export feature is available only for objects of the following types: - [Directory](../../../../concepts/datamodel/dir.md) - [Row-oriented table](../../../../concepts/datamodel/table.md#row-oriented-tables) - [Secondary index](../../../../concepts/secondary_indexes.md) +- [Vector index](../../../../concepts/vector_indexes.md) {% endnote %} diff --git a/ydb/docs/en/core/reference/ydb-cli/export-import/_includes/tools_restore.md b/ydb/docs/en/core/reference/ydb-cli/export-import/_includes/tools_restore.md index 0bb1adb5f2a9..380117917fda 100644 --- a/ydb/docs/en/core/reference/ydb-cli/export-import/_includes/tools_restore.md +++ b/ydb/docs/en/core/reference/ydb-cli/export-import/_includes/tools_restore.md @@ -86,7 +86,7 @@ To import data to the table, use the [YQL `REPLACE` command](../../../../yql/ref - `--restore-data `: Enables/disables data import, 1 (yes) or 0 (no), defaults to 1. If set to 0, the import only creates items in the schema without populating them with data. If there's no data in the file system (only the schema has been exported), it doesn't make sense to change this option. -- `--restore-indexes `: Enables/disables import of indexes, 1 (yes) or 0 (no), defaults to 1. If set to 0, the import won't either register secondary indexes in the data schema or populate them with data. +- `--restore-indexes `: Enables/disables import of indexes, 1 (yes) or 0 (no), defaults to 1. If set to 0, the import won't either register indexes in the data schema or populate them with data. - `--restore-acl `: Enables/disables import of ACL, 1 (yes) or 0 (no), defaults to 1. If set to 0, the import creates items in the schema with an empty ACL, and their owner will be the user who started the import. @@ -97,7 +97,7 @@ To import data to the table, use the [YQL `REPLACE` command](../../../../yql/ref - `--save-partial-result`: Save the partial import result. If disabled, an import error results in reverting to the database state before the import. -- `--import-data`: Use ImportData, a more efficient method for uploading data than the default approach. This method sends data to the server partitioned by the client and in a lighter format. However, it returns an error when attempting to import exported data into an existing table that already has secondary indexes or is in the process of building them. To restore a table with secondary indexes, ensure they are not already present in the schema (for example, using the [`ydb scheme ls`](../../../../reference/ydb-cli/commands/scheme-ls.md) command). By default, ImportData is disabled. +- `--import-data`: Use ImportData, a more efficient method for uploading data than the default approach. This method sends data to the server partitioned by the client and in a lighter format. However, it returns an error when attempting to import exported data into an existing table that already has indexes or is in the process of building them. To restore a table with indexes, ensure they are not already present in the schema (for example, using the [`ydb scheme ls`](../../../../reference/ydb-cli/commands/scheme-ls.md) command). By default, ImportData is disabled. ### Workload restriction parameters {#limiters} diff --git a/ydb/docs/en/core/yql/reference/syntax/alter_table/index.md b/ydb/docs/en/core/yql/reference/syntax/alter_table/index.md index d401c387a984..0c535cb009d7 100644 --- a/ydb/docs/en/core/yql/reference/syntax/alter_table/index.md +++ b/ydb/docs/en/core/yql/reference/syntax/alter_table/index.md @@ -11,7 +11,7 @@ An action is any modification to the table, as described below: * [Renaming the table](rename.md). * Managing [columns](columns.md) of row and column tables. * Adding or removing a [changefeed](changefeed.md). -* Managing a [secondary index](secondary_index.md). +* Managing [indexes](indexes.md). * Managing [column groups](family.md) of a row table. {% if backend_name == "YDB" %} diff --git a/ydb/docs/en/core/yql/reference/syntax/alter_table/secondary_index.md b/ydb/docs/en/core/yql/reference/syntax/alter_table/indexes.md similarity index 89% rename from ydb/docs/en/core/yql/reference/syntax/alter_table/secondary_index.md rename to ydb/docs/en/core/yql/reference/syntax/alter_table/indexes.md index a527930b8ea0..57588906fcda 100644 --- a/ydb/docs/en/core/yql/reference/syntax/alter_table/secondary_index.md +++ b/ydb/docs/en/core/yql/reference/syntax/alter_table/indexes.md @@ -1,4 +1,4 @@ -# Adding, removing, and renaming a secondary index +# Adding, removing, and renaming a index {% if oss == true and backend_name == "YDB" %} @@ -14,7 +14,8 @@ ALTER TABLE `series` ADD INDEX `title_index` GLOBAL ON (`title`); ``` -You can specify any index parameters from the [`CREATE TABLE`](../create_table/secondary_index.md) command. +You can specify any secondary index parameters from the [`CREATE TABLE`](../create_table/secondary_index.md) command. +You can specify any vector index parameters from the [`CREATE TABLE`](../create_table/vector_index.md) command. {% if backend_name == "YDB" %} @@ -80,7 +81,7 @@ ALTER TABLE `series` DROP INDEX `title_index`; {% if backend_name == "YDB" %} -You can also remove a secondary index using the {{ ydb-short-name }} CLI [table index](../../../../reference/ydb-cli/commands/secondary_index.md#drop) command. +You can also remove a index using the {{ ydb-short-name }} CLI [table index](../../../../reference/ydb-cli/commands/secondary_index.md#drop) command. {% endif %} diff --git a/ydb/docs/en/core/yql/reference/syntax/alter_table/toc_i.yaml b/ydb/docs/en/core/yql/reference/syntax/alter_table/toc_i.yaml index 80343a7ed1c3..25efc276afc1 100644 --- a/ydb/docs/en/core/yql/reference/syntax/alter_table/toc_i.yaml +++ b/ydb/docs/en/core/yql/reference/syntax/alter_table/toc_i.yaml @@ -1,6 +1,6 @@ items: - { name: Overview, href: index.md } - - { name: INDEX, href: secondary_index.md, when: feature_secondary_index } + - { name: INDEX, href: indexes.md, when: feature_secondary_index } - { name: COLUMN, href: columns.md } - { name: SET, href: set.md, when: backend_name == "YDB" } - { name: CHANGEFEED, href: changefeed.md, when: feature_changefeed } diff --git a/ydb/docs/en/core/yql/reference/syntax/create_table/index.md b/ydb/docs/en/core/yql/reference/syntax/create_table/index.md index 6ce90df5e8c9..9988199ae81e 100644 --- a/ydb/docs/en/core/yql/reference/syntax/create_table/index.md +++ b/ydb/docs/en/core/yql/reference/syntax/create_table/index.md @@ -234,6 +234,7 @@ CREATE TABLE ( When creating row-oriented tables, it is possible to specify: * [A secondary index](secondary_index.md). +* [A vector index](vector_index.md). * [Column groups](family.md). * [Additional parameters](with.md). diff --git a/ydb/docs/en/core/yql/reference/syntax/create_table/toc_i.yaml b/ydb/docs/en/core/yql/reference/syntax/create_table/toc_i.yaml index 8a40a51a6220..8bc05bb97655 100644 --- a/ydb/docs/en/core/yql/reference/syntax/create_table/toc_i.yaml +++ b/ydb/docs/en/core/yql/reference/syntax/create_table/toc_i.yaml @@ -1,6 +1,7 @@ items: -- { name: Overview, href: index.md } -- { name: INDEX, href: secondary_index.md } -- { name: FAMILY, href: family.md } -- { name: TEMPORARY, href: temporary.md } -- { name: WITH, href: with.md } \ No newline at end of file +- { name: Overview, href: index.md } +- { name: SECONDARY INDEX, href: secondary_index.md } +- { name: VECTOR INDEX, href: vector_index.md } +- { name: FAMILY, href: family.md } +- { name: TEMPORARY, href: temporary.md } +- { name: WITH, href: with.md } \ No newline at end of file diff --git a/ydb/docs/en/core/yql/reference/syntax/create_table/vector_index.md b/ydb/docs/en/core/yql/reference/syntax/create_table/vector_index.md new file mode 100644 index 000000000000..e8abbf0dc71a --- /dev/null +++ b/ydb/docs/en/core/yql/reference/syntax/create_table/vector_index.md @@ -0,0 +1,68 @@ +# Vector index + +{% include [not_allow_for_olap](../../../../_includes/not_allow_for_olap_note.md) %} + +{% note warning %} + +It makes no sense to create an empty table with a vector index, because for now we don't allow mutations in tables with vector indexes. + +You should use `ALTER TABLE ... ADD INDEX` to add a vector index to an existing table. + +{% endnote %} + +The INDEX construct is used to define a {% if concept_vector_index %}[vector index]({{ concept_vector_index }}){% else %}vector index{% endif %} in a [row-oriented](../../../../concepts/datamodel/table.md#row-oriented-tables) table: + +```yql +CREATE TABLE table_name ( + ... + INDEX GLOBAL [SYNC] USING ON ( ) COVER ( ) WITH ( ), + ... +) +``` + +Where: + +* **Index_name** is the unique name of the index to be used to access data. +* **SYNC** indicates synchronous data writes to the index. If not specified, synchronous. +* **Index_type** is the index type. Only `vector_kmeans_tree` is supported now. +* **Index_columns** is a list of comma-separated column names in the created table to be used for a search in the index. The last column in the list is used as embedding, the other columns are used as prefix columns. +* **Cover_columns** is a list of comma-separated column names in the created table, which will be stored in the index in addition to the search columns, making it possible to fetch additional data without accessing the table for it. +* **Index_parameters** is a list of comma-separated key-value parameters: + * parameters for any vector **index_type**: + * `dimension` is a number of dimension in the indexed embedding (<= 16384) + * `type` is a type of value in the indexed embedding, can be `float`, `uint8`, `int8`, `bit` + * `distance` is a type of the distance function which will be used for this index. Valid values: `cosine`, `manhattan`, `euclidean`. + * `similarity` is a type of the similarity function which will be used for this index. Valid values: `inner_product`, `cosine`. + * parameters specific to `vector_kmeans_tree`: + * `clusters` is a `k` in each kmeans used for tree (values > 1000 can affect performance) + * `levels` is a level count in the tree + + +{% note warning %} + +The `distance` and `similarity` parameters can not be specified together. + +{% endnote %} + + +{% note warning %} + +The `type=bit` vector index is not supported yet. + +{% endnote %} + +## Example + +```yql +CREATE TABLE user_articles ( + article_id Uint64, + user String, + title String, + text String, + embedding String, + INDEX emb_cosine_idx GLOBAL SYNC USING vector_kmeans_tree + ON (user, embedding) COVER (title, text) + WITH (dimension=512, type="float", distance="cosine", clusters=128, levels=2), + PRIMARY KEY (article_id) +) +``` diff --git a/ydb/docs/en/core/yql/reference/syntax/select/toc_i.yaml b/ydb/docs/en/core/yql/reference/syntax/select/toc_i.yaml index 7d7852546f49..7d70ff9dccb4 100644 --- a/ydb/docs/en/core/yql/reference/syntax/select/toc_i.yaml +++ b/ydb/docs/en/core/yql/reference/syntax/select/toc_i.yaml @@ -1,22 +1,23 @@ items: -- { name: Overview, href: index.md } -- { name: TEMPORARY TABLE, href: temporary_table.md, when: feature_temp_table } -- { name: FROM, href: from.md } -- { name: FROM AS_TABLE, href: from_as_table.md } -- { name: FROM SELECT, href: from_select.md } -- { name: FOLDER, href: folder.md, when: yt } -- { name: WalkFolders, href: walk_folders.md, when: yt } -- { name: DISTINCT, href: distinct.md } -- { name: UNIQUE DISTINCT, href: unique_distinct_hints.md } -- { name: UNION, href: union.md } -- { name: CONCAT, href: concat.md, when: feature_bulk_tables } -- { name: VIEW, href: view.md, when: feature_mapreduce } -- { name: VIEW INDEX, href: secondary_index.md, when: feature_secondary_index } -- { name: WITH, href: with.md } -- { name: WITHOUT, href: without.md } -- { name: WHERE, href: where.md } -- { name: ORDER BY, href: order_by.md } -- { name: ASSUME ORDER BY, href: assume_order_by.md } -- { name: LIMIT OFFSET, href: limit_offset.md } -- { name: SAMPLE, href: sample.md } -- { name: TABLESAMPLE, href: sample.md } +- { name: Overview, href: index.md } +- { name: TEMPORARY TABLE, href: temporary_table.md, when: feature_temp_table } +- { name: FROM, href: from.md } +- { name: FROM AS_TABLE, href: from_as_table.md } +- { name: FROM SELECT, href: from_select.md } +- { name: FOLDER, href: folder.md, when: yt } +- { name: WalkFolders, href: walk_folders.md, when: yt } +- { name: DISTINCT, href: distinct.md } +- { name: UNIQUE DISTINCT, href: unique_distinct_hints.md } +- { name: UNION, href: union.md } +- { name: CONCAT, href: concat.md, when: feature_bulk_tables } +- { name: VIEW, href: view.md, when: feature_mapreduce } +- { name: VIEW SECONDARY INDEX, href: secondary_index.md, when: feature_secondary_index } +- { name: VIEW VECTOR INDEX, href: vector_index.md, when: feature_secondary_index } +- { name: WITH, href: with.md } +- { name: WITHOUT, href: without.md } +- { name: WHERE, href: where.md } +- { name: ORDER BY, href: order_by.md } +- { name: ASSUME ORDER BY, href: assume_order_by.md } +- { name: LIMIT OFFSET, href: limit_offset.md } +- { name: SAMPLE, href: sample.md } +- { name: TABLESAMPLE, href: sample.md } diff --git a/ydb/docs/en/core/yql/reference/syntax/select/vector_index.md b/ydb/docs/en/core/yql/reference/syntax/select/vector_index.md new file mode 100644 index 000000000000..e056cf63eb84 --- /dev/null +++ b/ydb/docs/en/core/yql/reference/syntax/select/vector_index.md @@ -0,0 +1,51 @@ +# VIEW (Vector index) + +{% if oss == true and backend_name == "YDB" %} + +{% note warning %} + +{% include [OLAP_not_allow_text](../../../../_includes/not_allow_for_olap_text.md) %} + +{% endnote %} + +{% endif %} + +To select data from a row-oriented table using a vector index, use the following statements: + +```yql +SELECT ... + FROM TableName VIEW IndexName + WHERE ... + ORDER BY Knn::SomeDistance(...) + LIMIT ... +``` + +```yql +SELECT ... + FROM TableName VIEW IndexName + WHERE ... + ORDER BY Knn::SomeSimilarity(...) DESC + LIMIT ... +``` + + +## Examples + +* Select all the fields from the `series` row-oriented table using the `views_index` vector index created for `embedding` and inner product similarity: + + ```yql + SELECT series_id, title, info, release_date, views, uploaded_user_id, Knn::InnerProductSimilarity(embedding, $target) as similarity + FROM series VIEW views_index + ORDER BY similarity DESC + LIMIT 10 + ``` + +* Select all the fields from the `series` row-oriented table using the `views_index2` prefixed vector index created for `embedding` and inner product similarity with prefix column `release_date`: + + ```yql + SELECT series_id, title, info, release_date, views, uploaded_user_id, Knn::InnerProductSimilarity(embedding, $target) as similarity + FROM series VIEW views_index2 + WHERE release_date = "2025-03-31" + ORDER BY Knn::InnerProductSimilarity(embedding, $TargetEmbedding) DESC + LIMIT 10 + ``` diff --git a/ydb/docs/ru/core/concepts/_includes/vector_indexes.md b/ydb/docs/ru/core/concepts/_includes/vector_indexes.md new file mode 100644 index 000000000000..860894c0dfef --- /dev/null +++ b/ydb/docs/ru/core/concepts/_includes/vector_indexes.md @@ -0,0 +1,119 @@ +# Векторные индексы + +{{ ydb-short-name }} поддерживает [векторные индексы](https://en.wikipedia.org/wiki/Vector_database) для эффективного приближенного поиска k ближайших строк к вектору запроса (ANN поиск). В отличие от вторичных индексов, оптимизирующих поиск по равенству или диапазону, векторные индексы позволяют выполнять поиск по сходству на основе функций расстояния или схожести. + +Векторные индексы особенно полезны для: + +* рекомендательных систем (поиск похожих товаров/пользователей; +* cемантического поиска (сопоставление текстовых эмбеддингов); +* поиска похожих изображений; +* обнаружения аномалий (поиск выбросов); +* классификационных систем (поиск ближайших размеченных примеров). + +## Характеристики векторных индексов {#characteristics} + +Векторные индексы в {{ ydb-short-name }} решают задачу поиска ближайших соседей с использованием функций схожести или расстояния. + +Поддерживается несколько функций расстояния/схожести: "inner_product", "cosine" (схожесть) и "cosine", "euclidean" и "manhattan" (расстояние). + +В текущей реализации доступен один тип индекса: `vector_kmeans_tree`. + +### Векторный индекс типа `vector_kmeans_tree` {#vector-kmeans-tree-type} + +Индекс `vector_kmeans_tree` реализует иерархическую кластеризацию данных. Его структура включает: + +1. Иерархическая кластеризация: + + - индекс строит несколько уровней k-means кластеров; + - на каждом уровне векторы распределяются по заданному количеству кластеров в степени уровня; + - первый уровень кластеризует весь набор данных; + - последующие уровни рекурсивно кластеризуют содержимое каждого родительского кластера. + +2. Процесс поиска: + + - поиск идет рекурсивно от первого уровня к последующим; + - при выполнении запросов индекс анализирует только наиболее перспективные кластеры; + - такое усечение пространства поиска позволяет избежать полного перебора всех векторов. + +3. Параметры: + + - `levels`: число уровней в дереве, задает глубину поиска (обычно 1-3); + - `clusters`: число кластеров в k-means, определяет ширину поиска (обычно 64-512). + +## Типы векторных индексов {#types} + +### Базовый векторный индекс {#basic} + +Глобальный векторный индекс по колонке `embedding`: + +```yql +ALTER TABLE my_table + ADD INDEX my_index + GLOBAL USING vector_kmeans_tree + ON (embedding) + WITH (distance=cosine, type="uint8", dimension=512, levels=2, clusters=128); +``` + +### Векторный индекс с покрывающими колонками {#covering} + +Покрывающий векторный индекс, включающий дополнительную колонку `data`, чтобы избежать чтения из основной таблицы при поиске: + +```yql +ALTER TABLE my_table + ADD INDEX my_index + GLOBAL USING vector_kmeans_tree + ON (embedding) COVER (data) + WITH (distance=cosine, type="uint8", dimension=512, levels=2, clusters=128); +``` + +### Векторный индекс с префиксом {#prefixed} + +Векторный индекс с префиксом, позволяющий фильтровать по префиксной колонке `user` в момент выполнения векторного поиска: + +```yql +ALTER TABLE my_table + ADD INDEX my_index + GLOBAL USING vector_kmeans_tree + ON (user, embedding) + WITH (distance=cosine, type="uint8", dimension=512, levels=2, clusters=128); +``` + +### Векторный индекс с префиксом и покрывающими колонками {#prefixed-covering} + +Векторный индекс с префиксом и покрывающими колонками: + +```yql +ALTER TABLE my_table + ADD INDEX my_index + GLOBAL USING vector_kmeans_tree + ON (user, embedding) COVER (data) + WITH (distance=cosine, type="uint8", dimension=512, levels=2, clusters=128); +``` + +## Создание векторных индексов {#creation} + +Векторные индексы можно создавать: + +* при создании таблицы с помощью YQL-оператора [CREATE TABLE](../../yql/reference/syntax/create_table/vector_index.md); +* добавлять к существующей таблице с помощью YQL-оператора [ALTER TABLE](../../yql/reference/syntax/alter_table/indexes.md). + +Подробнее про параметры создания векторного индекса смотри в [CREATE TABLE](../../yql/reference/syntax/create_table/vector_index.md) + +## Использование векторных индексов {#usage} + +Запросы к векторным индексам выполняются с использованием синтаксиса VIEW в YQL. Для индексов с префиксом укажите префиксные колонки в условии WHERE: + +```yql +SELECT user, data +FROM my_table VIEW my_index +WHERE user = "..." +ORDER BY Knn::CosineSimilarity(embedding, ...) DESC +LIMIT 10; +``` + +## Ограничения {#limitations} + +В настоящее время не поддерживается: + +* изменение строк в индексированных таблицах; +* тип битовых векторов. \ No newline at end of file diff --git a/ydb/docs/ru/core/concepts/datamodel/_includes/table.md b/ydb/docs/ru/core/concepts/datamodel/_includes/table.md index 535ce15e47b5..229d206e6738 100644 --- a/ydb/docs/ru/core/concepts/datamodel/_includes/table.md +++ b/ydb/docs/ru/core/concepts/datamodel/_includes/table.md @@ -232,6 +232,7 @@ WITH (STORE = COLUMN); * Чтение с реплик. * Вторичные индексы. +* Векторные индексы. * Фильтры Блума. * Change Data Capture. * Переименование таблиц. diff --git a/ydb/docs/ru/core/concepts/glossary.md b/ydb/docs/ru/core/concepts/glossary.md index 49951d47992c..9163f45ffbfa 100644 --- a/ydb/docs/ru/core/concepts/glossary.md +++ b/ydb/docs/ru/core/concepts/glossary.md @@ -151,6 +151,10 @@ **Вторичный индекс** или **secondary index** — это дополнительная структура данных, используемая для нахождения строк в таблице, обычно когда это нельзя эффективно сделать с помощью [первичного индекса](#primary-index). В отличие от первичного индекса, вторичные индексы управляются независимо от основных данных таблицы. Таким образом, у таблицы может быть несколько вторичных индексов для различных сценариев. Возможности {{ ydb-short-name }} в отношении вторичных индексов описаны в отдельной статье [{#T}](secondary_indexes.md). Вторичный индекс может быть как уникальным, так и неуникальным. +#### Векторный индекс {#vector-index} + +**Векторный индекс** или **vector index** — это дополнительная структура данных, используемая для ускорения решения задачи [поиска ближайшего соседа](https://en.wikipedia.org/wiki/Nearest_neighbor_search), когда данных достаточно много и [точный векторный поиск без индекса](../yql/reference/udf/list/knn.md) не работает удовлетворительно. В отличие от первичного индекса, векторные индексы управляются независимо от основных данных таблицы. Таким образом, у таблицы может быть несколько векторных индексов для различных сценариев. Возможности {{ ydb-short-name }} в отношении векторных индексов описаны в отдельной статье [{#T}](vector_indexes.md). + #### Семейство колонок {#column-family} **Семейство колонок**, **группа колонок**, **column family** или **column group** — это функция, позволяющая хранить подмножества колонок [строковой таблицы](#row-oriented-table) отдельно в отдельном семействе или группе. Основной сценарий использования — хранение части колонок на других типах дисков (перенос менее важных колонок на HDD) или с другими настройками компрессии. Если рабочая нагрузка требует многих семейств колонок, рассмотрите возможность использования [колоночных таблиц](#column-oriented-table). diff --git a/ydb/docs/ru/core/concepts/toc_i.yaml b/ydb/docs/ru/core/concepts/toc_i.yaml index 7f9e4ac5efa5..5b7b17d29f30 100644 --- a/ydb/docs/ru/core/concepts/toc_i.yaml +++ b/ydb/docs/ru/core/concepts/toc_i.yaml @@ -14,6 +14,8 @@ items: href: transactions.md - name: Вторичные индексы href: secondary_indexes.md +- name: Векторные индексы + href: vector_indexes.md - name: Change Data Capture (CDC) href: cdc.md when: feature_changefeed diff --git a/ydb/docs/ru/core/concepts/vector_indexes.md b/ydb/docs/ru/core/concepts/vector_indexes.md new file mode 100644 index 000000000000..1d84e130e61f --- /dev/null +++ b/ydb/docs/ru/core/concepts/vector_indexes.md @@ -0,0 +1 @@ +{% include [vector_indexes.md](_includes/vector_indexes.md) %} diff --git a/ydb/docs/ru/core/dev/toc_p.yaml b/ydb/docs/ru/core/dev/toc_p.yaml index c99721d2dd0c..2b3e207afc5b 100644 --- a/ydb/docs/ru/core/dev/toc_p.yaml +++ b/ydb/docs/ru/core/dev/toc_p.yaml @@ -18,6 +18,8 @@ items: path: primary-key/toc_p.yaml - name: Вторичные индексы href: secondary-indexes.md +- name: Векторные индексы + href: vector-indexes.md - name: Оптимизация планов запросов href: query-plans-optimization.md - name: Пакетная загрузка diff --git a/ydb/docs/ru/core/dev/vector-indexes.md b/ydb/docs/ru/core/dev/vector-indexes.md new file mode 100644 index 000000000000..0ba7d8148a77 --- /dev/null +++ b/ydb/docs/ru/core/dev/vector-indexes.md @@ -0,0 +1,61 @@ +# Векторные индексы + +[Векторные индексы](https://en.wikipedia.org/wiki/Vector_database) — это специализированные структуры данных, позволяющие эффективно выполнять поиск схожести в многомерных пространствах. В отличие от традиционных индексов, оптимизированных для точных совпадений, векторные индексы помогают находить наиболее похожие элементы на основе математических мер расстояния или схожести. + +Данные в таблице {{ ydb-short-name }} хранятся и сортируются по первичному ключу, что обеспечивает эффективный поиск по точному совпадению и сканирование диапазонов. Векторные индексы предоставляют аналогичную эффективность для поиска ближайших соседей в векторных пространствах, что особенно ценно при работе с эмбеддингами и другими многомерными представлениями данных. + +В этой статье описаны практические операции с векторными индексами. Концептуальную информацию о типах векторных индексов и их характеристиках см. в разделе [Векторные индексы](../concepts/vector_indexes.md) в категории "Концепции". + +## Создание векторных индексов {#create} + +Векторный индекс можно создать: +* При создании таблицы с помощью [YQL-команды `CREATE TABLE`](../yql/reference/syntax/create_table/vector_index.md) +* Добавить к существующей таблице с помощью [YQL-команды `ALTER TABLE`](../yql/reference/syntax/alter_table/vector_index.md) + +Пример создания префиксного векторного индекса с покрывающими колонками: + +```yql +ALTER TABLE my_table + ADD INDEX my_index + GLOBAL USING vector_kmeans_tree + ON (user, embedding) COVER (data) + WITH (distance=cosine, type="uint8", dimension=512, levels=2, clusters=128); +``` + +Подробное описание параметров векторного индекса смотри в [YQL-команде `CREATE TABLE`](../yql/reference/syntax/create_table/vector_index.md). + +Поскольку построение векторного индекса требует обработки существующих данных, создание индекса для заполненной таблицы может занять значительное время. Эта операция выполняется в фоновом режиме, позволяя продолжать работу с таблицей во время построения. Индекс становится доступным автоматически после завершения. + +## Использование векторных индексов для поиска схожести {#use} + +Для выполнения поиска схожести явно укажите имя индекса в предложении VIEW. Для префиксных индексов включите условия для префиксных колонок в предложение WHERE: + +```yql +DECLARE $query_vector AS List; + +SELECT user, data +FROM my_table VIEW my_index +WHERE user = "john_doe" +ORDER BY Knn::CosineSimilarity(embedding, $query_vector) DESC +LIMIT 10; +``` + +{% note info %} + +Без предложения VIEW запрос выполнит полное сканирование таблицы с попарным сравнением векторов. + +{% endnote %} + +## Проверка стоимости запросов {#cost} + +Любой запрос в транзакционном приложении должен проверяться с точки зрения количества операций ввода-вывода и используемых вычислительных ресурсов. Также необходимо убедиться, что эти показатели не растут постоянно с увеличением объема данных. {{ ydb-short-name }} [возвращает статистику](query-plans-optimization.md), необходимую для анализа, после выполнения каждого запроса. + +При использовании CLI {{ ydb-short-name }} выберите опцию `--stats`, чтобы включить вывод статистики после выполнения команды `yql`. Все SDK {{ ydb-short-name }} также содержат структуры со статистикой, возвращаемой после выполнения запроса. В пользовательском интерфейсе статистика отображается на отдельной вкладке рядом с результатами запроса. + +{% note warning %} + +В текущей версии векторные индексы не поддерживают операции модификации данных. +Любая попытка изменить строки в индексированных таблицах завершится ошибкой. +Это ограничение будет снято в будущих релизах. + +{% endnote %} \ No newline at end of file diff --git a/ydb/docs/ru/core/reference/observability/metrics/index.md b/ydb/docs/ru/core/reference/observability/metrics/index.md index 0b82c0210e4a..f166b1f03900 100644 --- a/ydb/docs/ru/core/reference/observability/metrics/index.md +++ b/ydb/docs/ru/core/reference/observability/metrics/index.md @@ -11,7 +11,7 @@ Имя метрики
Тип, единицы измерения | Описание
Метки ----- | ----- `resources.storage.used_bytes`
`IGAUGE`, байты | Размер пользовательских и служебных данных, сохраненных в распределенном сетевом хранилище. `resources.storage.used_bytes` = `resources.storage.table.used_bytes` + `resources.storage.topic.used_bytes`. -`resources.storage.table.used_bytes`
`IGAUGE`, байты | Размер пользовательских и служебных данных, сохраненных таблицами в распределенном сетевом хранилище. К служебным данным относятся данные первичного и [вторичных индексов](../../../concepts/secondary_indexes.md). +`resources.storage.table.used_bytes`
`IGAUGE`, байты | Размер пользовательских и служебных данных, сохраненных таблицами в распределенном сетевом хранилище. К служебным данным относятся данные первичного, [вторичных индексов](../../../concepts/secondary_indexes.md) и [векторных индексов](../../../concepts/vector_indexes.md). `resources.storage.topic.used_bytes`
`IGAUGE`, байты | Размер распределенного сетевого хранилища, используемого топиками. Равен сумме значений `topic.storage_bytes` всех топиков. `resources.storage.limit_bytes`
`IGAUGE`, байты | Ограничение на размер пользовательских и служебных данных, которые база данных может сохранить в распределенном сетевом хранилище. diff --git a/ydb/docs/ru/core/reference/ydb-cli/commands/_includes/secondary_index.md b/ydb/docs/ru/core/reference/ydb-cli/commands/_includes/secondary_index.md index cbb16368104d..8c53b68d62bf 100644 --- a/ydb/docs/ru/core/reference/ydb-cli/commands/_includes/secondary_index.md +++ b/ydb/docs/ru/core/reference/ydb-cli/commands/_includes/secondary_index.md @@ -91,9 +91,9 @@ {{ ydb-cli }} -p quickstart operation forget ydb://buildindex/7?id=2814749869 ``` -## Удаление вторичного индекса {#drop} +## Удаление индекса {#drop} -Удаление вторичного индекса выполняется командой `table index drop`: +Удаление индекса выполняется командой `table index drop`: ```bash {{ ydb-cli }} [connection options] table index drop
--index-name STR diff --git a/ydb/docs/ru/core/reference/ydb-cli/export-import/_includes/export-s3.md b/ydb/docs/ru/core/reference/ydb-cli/export-import/_includes/export-s3.md index 22cfddebd083..3a7e39afcdac 100644 --- a/ydb/docs/ru/core/reference/ydb-cli/export-import/_includes/export-s3.md +++ b/ydb/docs/ru/core/reference/ydb-cli/export-import/_includes/export-s3.md @@ -13,6 +13,7 @@ - [директория](../../../../concepts/datamodel/dir.md); - [строковая таблица](../../../../concepts/datamodel/table.md#row-oriented-tables); - [вторичный индекс](../../../../concepts/secondary_indexes.md). +- [векторый индекс](../../../../concepts/vector_indexes.md). {% endnote %} diff --git a/ydb/docs/ru/core/reference/ydb-cli/export-import/_includes/tools-restore.md b/ydb/docs/ru/core/reference/ydb-cli/export-import/_includes/tools-restore.md index 38c1b02cea95..4e6ca1cb4fa0 100644 --- a/ydb/docs/ru/core/reference/ydb-cli/export-import/_includes/tools-restore.md +++ b/ydb/docs/ru/core/reference/ydb-cli/export-import/_includes/tools-restore.md @@ -86,7 +86,7 @@ - `--restore-data `: Флаг загрузки данных, 1 (да) или 0 (нет), по умолчанию 1. Если флаг установлен в 0, то при загрузке будут только созданы объекты в схеме, а данные в них загружены не будут. Если в файловой системе нет данных (выгружена только схема), то изменение флага не имеет значения. -- `--restore-indexes `: Флаг загрузки индексов, 1 (да) или 0 (нет), по умолчанию 1. Если флаг установлен в 0, то при загрузке вторичные индексы не будут ни зарегистрированы в схеме данных, ни заполнены данными. +- `--restore-indexes `: Флаг загрузки индексов, 1 (да) или 0 (нет), по умолчанию 1. Если флаг установлен в 0, то при загрузке индексы не будут ни зарегистрированы в схеме данных, ни заполнены данными. - `--restore-acl `: Флаг загрузки ACL, 1 (да) или 0 (нет), по умолчанию 1. Если флаг установлен в 0, то при загрузке объекты будут созданы в схеме с пустым ACL, а их владельцем станет пользователь, запустивший загрузку. @@ -97,7 +97,7 @@ - `--save-partial-result`: Сохранять результат неполной загрузки. Без включения данной опции ошибка в процессе выполнения загрузки приведет к восстановлению состояния базы данных на момент перед началом загрузки. -- `--import-data`: Использовать ImportData – более эффективный способ загрузки данных, чем применяется по умолчанию. Этот способ передает на сервер данные, нужным образом разделённые на партиции, и в более легковесном формате. Однако ImportData вернёт ошибку при попытке импорта таблицы, имеющей вторичные индексы или находящейся в процессе их построения, в существующую таблицу. Поэтому перед импортом таблицы со вторичными индексами необходимо убедиться в том, что они отсутствуют в схеме (например, используя команду [`ydb scheme ls`](../../../../reference/ydb-cli/commands/scheme-ls.md)). По умолчанию ImportData не используется. +- `--import-data`: Использовать ImportData – более эффективный способ загрузки данных, чем применяется по умолчанию. Этот способ передает на сервер данные, нужным образом разделённые на партиции, и в более легковесном формате. Однако ImportData вернёт ошибку при попытке импорта таблицы, имеющей индексы или находящейся в процессе их построения, в существующую таблицу. Поэтому перед импортом таблицы с индексами необходимо убедиться в том, что они отсутствуют в схеме (например, используя команду [`ydb scheme ls`](../../../../reference/ydb-cli/commands/scheme-ls.md)). По умолчанию ImportData не используется. ### Параметры ограничения нагрузки {#limiters} diff --git a/ydb/docs/ru/core/yql/reference/syntax/alter_table/index.md b/ydb/docs/ru/core/yql/reference/syntax/alter_table/index.md index 85b2f705293d..d57e038e476a 100644 --- a/ydb/docs/ru/core/yql/reference/syntax/alter_table/index.md +++ b/ydb/docs/ru/core/yql/reference/syntax/alter_table/index.md @@ -12,7 +12,7 @@ ALTER TABLE table_name action1, action2, ..., actionN; * [Переименование таблицы](rename.md). * Работа с [колонками](columns.md) строковой и колоночной таблиц. * Добавление или удаление [потока изменений](changefeed.md). -* Работа со [вторичным индексом](secondary_index.md). +* Работа с [индексами](indexes.md). * Работа с [группами колонок](family.md) строковой таблицы. {% if backend_name == "YDB" and oss == true %} * Изменение [дополнительных параметров таблиц](set.md). diff --git a/ydb/docs/ru/core/yql/reference/syntax/alter_table/secondary_index.md b/ydb/docs/ru/core/yql/reference/syntax/alter_table/indexes.md similarity index 90% rename from ydb/docs/ru/core/yql/reference/syntax/alter_table/secondary_index.md rename to ydb/docs/ru/core/yql/reference/syntax/alter_table/indexes.md index f4e5b753ea1b..99ae2a6b7f5e 100644 --- a/ydb/docs/ru/core/yql/reference/syntax/alter_table/secondary_index.md +++ b/ydb/docs/ru/core/yql/reference/syntax/alter_table/indexes.md @@ -1,4 +1,4 @@ -# Добавление, удаление и переименование вторичного индекса +# Добавление, удаление и переименование индекса {% if oss == true and backend_name == "YDB" %} @@ -14,7 +14,8 @@ ALTER TABLE `series` ADD INDEX `title_index` GLOBAL ON (`title`); ``` -Могут быть указаны все параметры индекса, описанные в команде [`CREATE TABLE`](../create_table/secondary_index.md) +Могут быть указаны все параметры вторичного индекса, описанные в команде [`CREATE TABLE`](../create_table/secondary_index.md) +Могут быть указаны все параметры векторного индекса, описанные в команде [`CREATE TABLE`](../create_table/vector_index.md) {% if backend_name == "YDB" and oss == true %} @@ -79,7 +80,7 @@ ALTER TABLE `series` DROP INDEX `title_index`; {% if backend_name == "YDB" and oss == true %} -Также удалить вторичный индекс можно с помощью команды [table index](../../../../reference/ydb-cli/commands/secondary_index.md#drop) {{ ydb-short-name }} CLI. +Также удалить индекс можно с помощью команды [table index](../../../../reference/ydb-cli/commands/secondary_index.md#drop) {{ ydb-short-name }} CLI. {% endif %} diff --git a/ydb/docs/ru/core/yql/reference/syntax/alter_table/toc_i.yaml b/ydb/docs/ru/core/yql/reference/syntax/alter_table/toc_i.yaml index f894a0b80fa1..f47da653f88d 100644 --- a/ydb/docs/ru/core/yql/reference/syntax/alter_table/toc_i.yaml +++ b/ydb/docs/ru/core/yql/reference/syntax/alter_table/toc_i.yaml @@ -1,6 +1,6 @@ items: - { name: Обзор, href: index.md } -- { name: INDEX, href: secondary_index.md, when: feature_secondary_index } +- { name: INDEX, href: indexes.md, when: feature_secondary_index } - { name: COLUMN, href: columns.md } - { name: SET, href: set.md, when: backend_name == "YDB" } - { name: CHANGEFEED, href: changefeed.md, when: feature_changefeed and backend_name == "YDB" } diff --git a/ydb/docs/ru/core/yql/reference/syntax/create_table/index.md b/ydb/docs/ru/core/yql/reference/syntax/create_table/index.md index 0b89bc3791ee..e9b19453590b 100644 --- a/ydb/docs/ru/core/yql/reference/syntax/create_table/index.md +++ b/ydb/docs/ru/core/yql/reference/syntax/create_table/index.md @@ -245,6 +245,7 @@ CREATE TABLE ( При создании строковых таблиц возможно задать: * [Вторичный индекс](secondary_index.md). +* [Векторный индекс](vector_index.md). * [Группы колонок](family.md). * [Дополнительные параметры](with.md). diff --git a/ydb/docs/ru/core/yql/reference/syntax/create_table/toc_i.yaml b/ydb/docs/ru/core/yql/reference/syntax/create_table/toc_i.yaml index f15777798515..e88409aed947 100644 --- a/ydb/docs/ru/core/yql/reference/syntax/create_table/toc_i.yaml +++ b/ydb/docs/ru/core/yql/reference/syntax/create_table/toc_i.yaml @@ -1,6 +1,7 @@ items: -- { name: Обзор, href: index.md } -- { name: INDEX, href: secondary_index.md } -- { name: FAMILY, href: family.md } -- { name: TEMPORARY, href: temporary.md } -- { name: WITH, href: with.md } \ No newline at end of file +- { name: Обзор, href: index.md } +- { name: SECONDARY INDEX, href: secondary_index.md } +- { name: VECTOR INDEX, href: vector_index.md } +- { name: FAMILY, href: family.md } +- { name: TEMPORARY, href: temporary.md } +- { name: WITH, href: with.md } \ No newline at end of file diff --git a/ydb/docs/ru/core/yql/reference/syntax/create_table/vector_index.md b/ydb/docs/ru/core/yql/reference/syntax/create_table/vector_index.md new file mode 100644 index 000000000000..884313ecc5f1 --- /dev/null +++ b/ydb/docs/ru/core/yql/reference/syntax/create_table/vector_index.md @@ -0,0 +1,67 @@ +# Векторный индекс + +{% include [not_allow_for_olap](../../../../_includes/not_allow_for_olap_note.md) %} + +{% note warning %} + +Создание пустой таблицы с векторным индексом в настоящее время не имеет практического смысла, так как модификация данных в таблицах с векторными индексами пока не поддерживается. + +Следует использовать `ALTER TABLE ... ADD INDEX` для добавления векторного индекса в существующую таблицу. + +{% endnote %} + +Конструкция INDEX используется для определения {% if concept_vector_index %}[векторного индекса]({{ concept_vector_index }}){% else %}векторного индекса{% endif %} в [строчно-ориентированных](../../../../concepts/datamodel/table.md#row-oriented-tables) таблицах: + +```yql +CREATE TABLE table_name ( + ... + INDEX <имя_индекса> GLOBAL [SYNC] USING <тип_индекса> ON ( <колонки_индекса> ) COVER ( <покрывающие_колонки> ) WITH ( <параметры_индекса> ), + ... +) +``` + +Где: + +* **имя_индекса** - уникальное имя индекса для доступа к данным +* **SYNC** - указывает на синхронную запись данных в индекс. Если не указано - синхронная. +* **тип_индекса** - тип индекса, в настоящее время поддерживается только `vector_kmeans_tree` +* **колонки_индекса** - список колонок таблицы через запятую, используемых для поиска по индексу (последняя колонка используется как эмбеддинг, остальные - как префиксные колонки) +* **покрывающие_колонки** - дополнительные колонки таблицы, сохраняемые в индексе для возможности их извлечения без обращения к основной таблице +* **параметры_индекса** - список параметров в формате ключ-значение: + * общие параметры для всех векторных индексов: + * `dimension` - размерность вектора эмбеддинга (<= 16384); + * `type` - тип значений вектора (`float`, `uint8`, `int8`, `bit`); + * `distance` - функция расстояния (`cosine`, `manhattan`, `euclidean`) или `similarity` - функция схожести (`inner_product`, `cosine`). + * специфичные параметры для `vector_kmeans_tree`: + * `clusters` - количество центроидов для алгоритма k-means (значения > 1000 могут ухудшить производительность); + * `levels` - количество уровней в дереве. + + +{% note warning %} + +Параметры `distance` и `similarity` не могут быть указаны одновременно. + +{% endnote %} + + +{% note warning %} + +Векторные индексы с `type=bit` в настоящее время не поддерживаются + +{% endnote %} + +## Пример + +```yql +CREATE TABLE user_articles ( + article_id Uint64, + user String, + title String, + text String, + embedding String, + INDEX emb_cosine_idx GLOBAL SYNC USING vector_kmeans_tree + ON (user, embedding) COVER (title, text) + WITH (dimension=512, type="float", distance="cosine", clusters=128, levels=2), + PRIMARY KEY (article_id) +) +``` diff --git a/ydb/docs/ru/core/yql/reference/syntax/select/toc_i.yaml b/ydb/docs/ru/core/yql/reference/syntax/select/toc_i.yaml index e36600e0b42a..b5d9b42cd9cb 100644 --- a/ydb/docs/ru/core/yql/reference/syntax/select/toc_i.yaml +++ b/ydb/docs/ru/core/yql/reference/syntax/select/toc_i.yaml @@ -1,25 +1,26 @@ items: -- { name: Обзор, href: index.md } -- { name: TEMPORARY TABLE, href: temporary_table.md, when: feature_temp_table } -- { name: FROM, href: from.md } -- { name: FROM AS_TABLE, href: from_as_table.md } -- { name: FROM SELECT, href: from_select.md } -- { name: FOLDER, href: folder.md, when: yt } -- { name: WalkFolders, href: walk_folders.md, when: yt } -- { name: DISTINCT, href: distinct.md } -- { name: UNIQUE DISTINCT, href: unique_distinct_hints.md } -- { name: UNION, href: union.md } -- { name: CONCAT, href: concat.md, when: feature_bulk_tables } -- { name: VIEW, href: view.md, when: feature_mapreduce } -- { name: VIEW INDEX, href: secondary_index.md, when: feature_secondary_index } -- { name: WITH, href: with.md } -- { name: WITHOUT, href: without.md } -- { name: WHERE, href: where.md } -- { name: ORDER BY, href: order_by.md } -- { name: ASSUME ORDER BY, href: assume_order_by.md } -- { name: LIMIT OFFSET, href: limit_offset.md } -- { name: SAMPLE, href: sample.md } -- { name: TABLESAMPLE, href: sample.md } +- { name: Обзор, href: index.md } +- { name: TEMPORARY TABLE, href: temporary_table.md, when: feature_temp_table } +- { name: FROM, href: from.md } +- { name: FROM AS_TABLE, href: from_as_table.md } +- { name: FROM SELECT, href: from_select.md } +- { name: FOLDER, href: folder.md, when: yt } +- { name: WalkFolders, href: walk_folders.md, when: yt } +- { name: DISTINCT, href: distinct.md } +- { name: UNIQUE DISTINCT, href: unique_distinct_hints.md } +- { name: UNION, href: union.md } +- { name: CONCAT, href: concat.md, when: feature_bulk_tables } +- { name: VIEW, href: view.md, when: feature_mapreduce } +- { name: VIEW SECONDARY INDEX, href: secondary_index.md, when: feature_secondary_index } +- { name: VIEW VECTOR INDEX, href: vector_index.md, when: feature_secondary_index } +- { name: WITH, href: with.md } +- { name: WITHOUT, href: without.md } +- { name: WHERE, href: where.md } +- { name: ORDER BY, href: order_by.md } +- { name: ASSUME ORDER BY, href: assume_order_by.md } +- { name: LIMIT OFFSET, href: limit_offset.md } +- { name: SAMPLE, href: sample.md } +- { name: TABLESAMPLE, href: sample.md } diff --git a/ydb/docs/ru/core/yql/reference/syntax/select/vector_index.md b/ydb/docs/ru/core/yql/reference/syntax/select/vector_index.md new file mode 100644 index 000000000000..e8c78d687f38 --- /dev/null +++ b/ydb/docs/ru/core/yql/reference/syntax/select/vector_index.md @@ -0,0 +1,51 @@ +# VIEW (Векторный индекс) + +{% if oss == true and backend_name == "YDB" %} + +{% note warning %} + +{% include [OLAP_not_allow_text](../../../../_includes/not_allow_for_olap_text.md) %} + +{% endnote %} + +{% endif %} + +Для выполнения запроса `SELECT` с использованием векторного индекса в строчно-ориентированной таблице используйте следующий синтаксис: + +```yql +SELECT ... + FROM TableName VIEW IndexName + WHERE ... + ORDER BY Knn::DistanceFunction(...) + LIMIT ... +``` + +```yql +SELECT ... + FROM TableName VIEW IndexName + WHERE ... + ORDER BY Knn::SimilarityFunction(...) DESC + LIMIT ... +``` + + +## Примеры + +* Выбор всех полей из таблицы `series` с использованием векторного индекса `views_index`, созданного для `embedding` с мерой близости "скалярное произведение": + + ```yql + SELECT series_id, title, info, release_date, views, uploaded_user_id, Knn::InnerProductSimilarity(embedding, $target) as similarity + FROM series VIEW views_index + ORDER BY similarity DESC + LIMIT 10 + ``` + +* Выбор всех полей из таблицы `series` с использованием префиксного векторного индекса `views_index2`, созданного для `embedding` с мерой близости "скалярное произведение" и префиксной колонкой `release_date`: + + ```yql + SELECT series_id, title, info, release_date, views, uploaded_user_id, Knn::InnerProductSimilarity(embedding, $target) as similarity + FROM series VIEW views_index2 + WHERE release_date = "2025-03-31" + ORDER BY Knn::InnerProductSimilarity(embedding, $TargetEmbedding) DESC + LIMIT 10 + ``` From 664ac4a1e4b3ff64cd4018f762b4a6730fb318b3 Mon Sep 17 00:00:00 2001 From: azevaykin <145343289+azevaykin@users.noreply.github.com> Date: Tue, 8 Apr 2025 11:53:40 +0300 Subject: [PATCH 041/454] Doc for TLI sysview (#16377) --- ydb/docs/en/core/concepts/glossary.md | 9 +- ydb/docs/en/core/dev/system-views.md | 209 +++++++++++++++-------- ydb/docs/ru/core/concepts/glossary.md | 13 +- ydb/docs/ru/core/dev/system-views.md | 234 ++++++++++++++++---------- 4 files changed, 292 insertions(+), 173 deletions(-) diff --git a/ydb/docs/en/core/concepts/glossary.md b/ydb/docs/en/core/concepts/glossary.md index 5e895c7507f5..2331e5d18e4b 100644 --- a/ydb/docs/en/core/concepts/glossary.md +++ b/ydb/docs/en/core/concepts/glossary.md @@ -90,12 +90,13 @@ Technically, tablets are [actors](#actor) with a persistent state reliably saved [Tablet implementation details](#tablet-implementation) and related terms, as well as [main tablet types](#tablet-types), are covered below in the advanced section. -### Distributed transactions {#distributed-transaction} +### Transactions {#transactions} {{ ydb-short-name }} implements **transactions** on two main levels: * [Local database](#local-database) and the rest of [tablet infrastructure](#tablet-implementation) allow [tablets](#tablet) to manipulate their state using **local transactions** with [serializable isolation level](https://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Serializable). Technically, they aren't really local to a single node as such a state persists remotely in [Distributed Storage](#distributed-storage). * In the context of {{ ydb-short-name }}, the term **distributed transactions** usually refers to transactions involving multiple tablets. For example, cross-table or even cross-row transactions are often distributed. +* **Single-shard** transactions span a single tablet and are faster to complete. For example, transactions between rows in the same table partition are often single-shard. Together, these mechanisms allow {{ ydb-short-name }} to provide [strict consistency](https://en.wikipedia.org/wiki/Consistency_model#Strict_consistency). @@ -601,7 +602,7 @@ A **channel** is a logical connection between a [tablet](#tablet) and [Distribut ### Distributed transactions implementation {#distributed-transaction-implementation} -Terms related to the implementation of [distributed transactions](#distributed-transaction) are explained below. The implementation itself is described in a separate article [{#T}](../contributor/datashard-distributed-txs.md). +Terms related to the implementation of [distributed transactions](#transactions) are explained below. The implementation itself is described in a separate article [{#T}](../contributor/datashard-distributed-txs.md). #### Deterministic transactions {#deterministic-transactions} @@ -627,7 +628,7 @@ In the case of read-only transactions, similar to "read uncommitted" in other da #### Read-write set {#rw-set} -The **read-write set** or **RW set** is a set of data that will participate in executing a [distributed transaction](#distributed-transaction). It combines the read set, the data that will be read, and the write set, the data modifications to be carried out. +The **read-write set** or **RW set** is a set of data that will participate in executing a [distributed transaction](#transactions). It combines the read set, the data that will be read, and the write set, the data modifications to be carried out. #### Read set {#read-set} @@ -635,7 +636,7 @@ The **read set** or **ReadSet data** is what participating shards forward during #### Transaction proxy {#transaction-proxy} -The **transaction proxy** or `TX_PROXY` is a service that orchestrates the execution of many [distributed transactions](#distributed-transaction): sequential phases, phase execution, planning, and aggregation of results. In the case of direct orchestration by other actors (for example, KQP data transactions), it is used for caching and allocation of unique [TxIDs](#txid). +The **transaction proxy** or `TX_PROXY` is a service that orchestrates the execution of many [distributed transactions](#transactions): sequential phases, phase execution, planning, and aggregation of results. In the case of direct orchestration by other actors (for example, KQP data transactions), it is used for caching and allocation of unique [TxIDs](#txid). #### Transaction flags {#txflags} diff --git a/ydb/docs/en/core/dev/system-views.md b/ydb/docs/en/core/dev/system-views.md index 81e4a4df44ce..cf36f0b9f405 100644 --- a/ydb/docs/en/core/dev/system-views.md +++ b/ydb/docs/en/core/dev/system-views.md @@ -1,62 +1,57 @@ # Database system views -You can make queries to special service tables (system views) to monitor the DB status. These tables are accessible from the root of the database tree and use the `.sys` system path prefix. - -You can find the corresponding table's primary key field index in the descriptions of available fields below. - -DB system views contain: - -* [Details of individual DB table partitions](#partitions). -* [Top queries by certain characteristics](#top-queries). -* [Query details](#query-metrics). -* [History of overloaded partitions](#top-overload-partitions). -* [Access control entities](#auth). +To obtain service information about the state of the database, you can access system views. They are accessible from the root of the database tree and use the system path prefix `.sys`. {% note info %} -Loads caused by accessing system views are more analytical in nature. Making frequent queries to them in large DBs will consume a lot of system resources. The recommended load is no more than 1-2 RPS. +Frequent access to system views leads to additional load on the database, especially in the case of a large database size. Exceeding the frequency of 1 request per second is not recommended. {% endnote %} ## Partitions {#partitions} -The following system view stores detailed information about individual [partitions](../concepts/datamodel/table.md#partitioning) of all DB tables: +The following system view stores detailed information about [partitions](../concepts/datamodel/table.md#partitioning) of DB tables: * `partition_stats`: Contains information about instant metrics and cumulative operation counters. Instant metrics are, for example, CPU load or count of in-flight [transactions](../concepts/transactions.md). Cumulative counters, for example, count the total number of rows read. The system view is designed to detect various irregularities in the load on a table partition or show the size of table partition data. -Cumulative fields (`RowReads`, `RowUpdates`, and so on) store the accumulated values since the last start of the tablet serving the partition. +Instant metrics (`NodeID`, `AccessTime`, `CPUCores`, etc.) contain instantaneous values. +Cumulative metrics (`RowReads`, `RowUpdate`, `LockAcquired`, etc.) store accumulated values since the last launch (`StartTime`) of the tablet serving the partition. Table structure: -| Column | Description | -|--------|-------------| -| `OwnerId` | ID of the SchemeShard serving the table.
Type: `Uint64`.
Key: `0`. | -| `PathId` | ID of the SchemeShard path.
Type: `Uint64`.
Key: `1`. | -| `PartIdx` | Partition sequence number.
Type: `Uint64`.
Key: `2`. | -| `DataSize` | Approximate partition size in bytes.
Type: `Uint64`. | -| `RowCount` | Approximate number of rows.
Type: `Uint64`. | -| `IndexSize` | Partition index size in a tablet.
Type: `Uint64`. | -| `CPUCores` | Double Instant value of load per partition (CPU share) | -| `TabletId` | ID of the tablet serving the partition.
Type: `Uint64`. | -| `Path` | Full path to the table.
Type: `Utf8`. | -| `NodeId` | ID of the node that the partition is being served on.
Type: `Uint32`. | -| `StartTime` | Last time when the tablet serving the partition was started.
Type: `Timestamp`. | -| `AccessTime` | Last time when data from the partition was read.
Type: `Timestamp`. | -| `UpdateTime` | Last time when data was written to the partition.
Type: `Timestamp`. | -| `RowReads` | Number of point reads since the start of the partition tablet.
Type: `Uint64`. | -| `RowUpdates` | Number of rows written since the start.
Type: `Uint64`. | -| `RowDeletes` | Number of rows deleted since the start.
Type: `Uint64`. | -| `RangeReads` | Number of row range reads since the start.
Type: `Uint64`. | -| `RangeReadRows` | Number of rows read in the ranges since the start.
Type: `Uint64`. | -| `InFlightTxCount` | Number of in-flight transactions.
Type: `Uint64`. | -| `ImmediateTxCompleted` | Number of one-shard transactions completed since the start.
Type: `Uint64`. | -| `CoordinatedTxCompleted` | Number of coordinated transactions completed since the start.
Type: `Uint64`. | -| `TxRejectedByOverload` | Number of transactions rejected due to overload (since the start).
Type: `Uint64`. | -| `TxRejectedByOutOfStorage` | Number of transactions rejected due to lack of storage space (since the start).
Type: `Uint64`. | - -### Example queries +Column | Description | Data type | Instant/Cumulative +--- | --- | --- | --- +`OwnerId` | ID of the SchemeShard table.
Key: `0`. | `Uint64` | Instant +`PathId` | ID of the SchemeShard path.
Key: `1`. | `Uint64` | Instant +`PartIdx` | Partition sequence number.
Key: `2`. | `Uint64` | Instant +`DataSize` | Approximate partition size in bytes. | `Uint64` | Instant +`RowCount` | Approximate number of rows. | `Uint64` | Instant +`IndexSize` | Partition index size in bytes. | `Uint64` | Instant +`CPUCores` | Instantaneous value of the load on the partition (the share of the CPU core time spent by the actor of the partition). | `Double` | Instant +`TabletId` | ID of the partition tablet. | `Uint64` | Instant +`FollowerId` | ID of the partition tablet [follower](../concepts/glossary.md#tablet-follower). A value of 0 means the leader. | `Uint32` | Instant +`Path` | Full path to the table. | `Utf8` | Instant +`NodeId` | ID of the partition node. | `Uint32` | Instant +`StartTime` | Last time of the launch of the partition tablet. | `Timestamp` | Instant +`AccessTime` | Last time of reading from the partition. | `Timestamp` | Instant +`UpdateTime` | Last time of writing to the partition. | `Timestamp` | Instant +`RowReads` | Number of point reads. | `Uint64` | Cumulative +`RowUpdates` | Number of rows written. | `Uint64` | Cumulative +`RowDeletes` | Number of rows deleted. | `Uint64` | Cumulative +`RangeReads` | Number of range reads. | `Uint64` | Cumulative +`RangeReadRows` | Number of rows read in ranges. | `Uint64` | Cumulative +`InFlightTxCount` | Number of in-flight transactions. | `Uint64` | Instant +`ImmediateTxCompleted` | Number of completed [single-shard transactions](../concepts/glossary.md#transactions). | `Uint64` | Cumulative +`CoordinatedTxCompleted` | Number of completed [distributed transactions](../concepts/glossary.md#transactions). | `Uint64` | Cumulative +`TxRejectedByOverload` | Number of transactions cancelled due to [overload](../troubleshooting/performance/queries/overloaded-errors.md). | `Uint64` | Cumulative +`TxRejectedByOutOfStorage` | Number of transactions cancelled due to lack of storage space. | `Uint64` | Cumulative +`LocksAcquired` | Number of [locks](../contributor/datashard-locks-and-change-visibility.md) acquired. | `Uint64` | Cumulative +`LocksWholeShard` | The number of ["whole shard" locks](../contributor/datashard-locks-and-change-visibility.md#limitations) taken. | `Uint64` | Cumulative +`LocksBroken` | Number of [broken locks](../contributor/datashard-locks-and-change-visibility.md#high-level-overview). | `Uint64` | Cumulative + +### Example queries {#partitions-examples} Top 5 of most loaded partitions among all DB tables: @@ -83,18 +78,39 @@ FROM `.sys/partition_stats` GROUP BY Path ``` +List of DB tables with the largest number of broken locks: + +```yql +SELECT + Path, + COUNT(*) as Partitions, + SUM(LocksBroken) as TotalLocksBroken +FROM `.sys/partition_stats` +GROUP BY Path +ORDER BY TotalLocksBroken DESC +``` + ## Top queries {#top-queries} -The following system views store data for analyzing the flow of user queries: +The following system views store data for analyzing the user queries. + +Maximum total execution time: + +* `top_queries_by_duration_one_minute`: data is split into one-minute intervals, contains the history for the last 6 hours; +* `top_queries_by_duration_one_hour`: data is split into one-hour intervals, contains the history for the last 2 weeks. + +Maximum number of bytes read from the table: -* `top_queries_by_duration_one_minute`: Data is split into one-minute intervals, contains Top 5 queries with the maximum total execution time for the last 6 hours. -* `top_queries_by_duration_one_hour`: Data is split into one-hour intervals, contains Top 5 queries with the maximum total execution time for the last 2 weeks. -* `top_queries_by_read_bytes_one_minute`: Data is split into one-minute intervals, contains Top 5 queries with the maximum number of bytes read from the table for the last 6 hours. -* `top_queries_by_read_bytes_one_hour`: Data is split into one-hour intervals, contains Top 5 queries with the maximum number of bytes read from the table for the last 2 weeks. -* `top_queries_by_cpu_time_one_minute`: Data is split into one-minute intervals, contains Top 5 queries with the maximum CPU time used for the last 6 hours. -* `top_queries_by_cpu_time_one_hour`: Data is split into one-hour intervals, contains Top 5 queries with the maximum CPU time used for the last 2 weeks. +* `top_queries_by_read_bytes_one_minute`: data is split into one-minute intervals, contains the history for the last 6 hours; +* `top_queries_by_read_bytes_one_hour`: Data is split into one-hour intervals, contains the history for the last 2 weeks. -Different runs of a query with the same text are deduplicated. The top list contains information about a specific run with the maximum value of the corresponding query metric within a single interval. +Maximum CPU time: + +* `top_queries_by_cpu_time_one_minute`: Data is split into one-minute intervals, contains the history for the last 6 hours; +* `top_queries_by_cpu_time_one_hour`: Data is split into one-hour intervals, contains the history for the last 2 weeks. + +Different runs of a query with the same text are deduplicated. The query with the maximum value of the corresponding metric is included in the output. +Each time interval (minute or hour) contains the TOP 5 queries completed in that time interval. Fields that provide information about the used CPU time (...`CPUTime`) are expressed in microseconds. @@ -104,7 +120,7 @@ All tables have the same structure: | Column | Description | |--------|-------------| -| `IntervalEnd` | The end of a one-minute or one-hour interval.
Type: `Timestamp`.
Key: `0`. | +| `IntervalEnd` | The end of the minute or hour interval for which statistics are collected.
Type: `Timestamp`.
Key: `0`. | | `Rank` | Rank of a top query.
Type: `Uint32`.
Key: `1`. | | `QueryText` | Query text.
Type: `Utf8`. | | `Duration` | Total query execution time.
Type: `Interval`. | @@ -133,9 +149,9 @@ All tables have the same structure: | `CompileCPUTime` | CPU time used to compile a query.
Type: `Uint64`. | | `ProcessCPUTime` | CPU time used for overall query handling.
Type: `Uint64`. | -### Example queries +### Example queries {#top-queries-examples} -Top queries by execution time for the last minute when queries were made: +Top queries by execution time. The query is made to the `.sys/top_queries_by_duration_one_minute` view: ```yql PRAGMA AnsiInForEmptyOrNullableItemsCollections; @@ -153,7 +169,7 @@ FROM `.sys/top_queries_by_duration_one_minute` WHERE IntervalEnd IN $last ``` -Queries that read the most bytes, broken down by minute: +Queries that read the most bytes. The query is made to the `.sys/top_queries_by_read_bytes_one_minute` view: ```yql SELECT @@ -183,8 +199,8 @@ Table structure: | Column | Description | |--------|-------------| -| `IntervalEnd` | The end of a one-minute interval.
Type: `Timestamp`.
Key: `0`. | -| `Rank` | Query rank within an interval (by the SumCPUTime field).
Type: `Uint32`.
Key: `1`. | +| `IntervalEnd` | The end of the minute interval for which statistics are collected.
Type: `Timestamp`.
Key: `0`. | +| `Rank` | Query rank within an interval (by the `SumCPUTime` field).
Type: `Uint32`.
Key: `1`. | | `QueryText` | Query text.
Type: `Utf8`. | | `Count` | Number of query runs.
Type: `Uint64`. | | `SumDuration` | Total duration of queries.
Type: `Interval`. | @@ -209,8 +225,7 @@ Table structure: | `MinDeleteRows` | Minimum number of rows deleted.
Type: `Uint64`. | | `MaxDeleteRows` | Maximum number of rows deleted.
Type: `Uint64`. | - -### Example queries +### Example queries {#query-metrics-examples} Top 10 queries for the last 6 hours by the total number of rows updated per minute: @@ -247,27 +262,35 @@ The following system views (tables) store the history of points in time when the * `top_partitions_one_minute`: The data is split into one-minute intervals, contains the history for the last 6 hours. * `top_partitions_one_hour`: The data is split into one-hour intervals, contains the history for the last 2 weeks. -These tables contain partitions with peak loads of more than 70% (`CPUCores` > 0.7). Partitions within a single interval are ranked by peak load value. +These views contain partitions with peak loads of more than 70% (`CPUCores` > 0.7). Partitions within a single interval are ranked by peak load value. + +The keys of the views are: + +* `IntervalEnd` - the moment when the interval is closed; +* `Rank` - the rank of the partition according to the peak load of `CPUCores` in this interval. + +For example, if a table has 10 partitions than `top_partitions_one_hour` for the hour interval `"20.12.2024 10:00-11:00"` will return 10 rows sorted in descending order of `CPUCores`. They will have a `Rank` from 1 to 10 and the same `IntervalEnd` `"20.12.2024 11:00"`. All tables have the same structure: | Column | Description | |--------|-------------| -| `IntervalEnd` | The end of a one-minute or one-hour interval.
Type: `Timestamp`.
Key: `0`. | -| `Rank` | Partition rank within an interval (by CPUCores).
Type: `Uint32`.
Key: `1`. | +| `IntervalEnd` | The end of the minute or hour interval for which statistics are collected.
Type: `Timestamp`.
Key: `0`. | +| `Rank` | Partition rank within an interval (by `CPUCores`).
Type: `Uint32`.
Key: `1`. | | `TabletId` | ID of the tablet serving the partition.
Type: `Uint64`. | +| `FollowerId` | ID of the partition tablet [follower](../concepts/glossary.md#tablet-follower).A value of 0 means the leader.
Type: `Uint32` | | `Path` | Full path to the table.
Type: `Utf8`. | | `PeakTime` | Peak time within an interval.
Type: `Timestamp`. | -| `CPUCores` | Peak load per partition (CPU share).
Type: `Double`. | +| `CPUCores` | Peak load per partition (share of the CPU core time spent by the actor of the partition).
Type: `Double`. | | `NodeId` | ID of the node where the partition was located during the peak load.
Type: `Uint32`. | | `DataSize` | Approximate partition size, in bytes, during the peak load.
Type: `Uint64`. | | `RowCount` | Approximate row count during the peak load.
Type: `Uint64`. | | `IndexSize` | Partition index size per tablet during the peak load.
Type: `Uint64`. | | `InFlightTxCount` | The number of in-flight transactions during the peak load.
Type: `Uint32`. | -### Example queries +### Example queries {#top-overload-partitions-examples} -The following query returns partitions with CPU usage of more than 70% in the specified interval, with tablet IDs and sizes as of the time when the percentage was exceeded. The query is made to the `.sys/top_partitions_one_minute` table with data over the last six hours split into one-minute intervals: +The following query returns partitions with CPU usage of more than 70% in the specified interval, with tablet IDs and sizes as of the time when the percentage was exceeded. The query is made to the `.sys/top_partitions_one_minute` view: ```yql SELECT @@ -278,13 +301,11 @@ SELECT DataSize FROM `.sys/top_partitions_one_minute` WHERE CPUCores > 0.7 -AND IntervalEnd BETWEEN Timestamp("YYYY-MM-DDThh:mm:ss.uuuuuuZ") AND Timestamp("YYYY-MM-DDThh:mm:ss.uuuuuuZ") +AND IntervalEnd BETWEEN Timestamp("2000-01-01T00:00:00Z") AND Timestamp("2099-12-31T00:00:00Z") ORDER BY IntervalEnd desc, CPUCores desc ``` -* `"YYYY-MM-DDTHH:MM:SS.UUUUUUZ"`: Time in the UTC 0 zone (`YYYY` stands for year, `MM`, for month, `DD`, for date, `hh`, for hours, `mm`, for minutes, `ss`, for seconds, and `uuuuuu`, for microseconds). For example, `"2023-01-26T13:00:00.000000Z"`. - -The following query returns partitions with CPU usage of over 90% in the specified interval, with tablet IDs and sizes as of the time when the percentage was exceeded. The query is made to the `.sys/top_partitions_one_hour` table with data over the last two weeks split into one-hour intervals: +The following query returns partitions with CPU usage of over 90% in the specified interval, with tablet IDs and sizes as of the time when the percentage was exceeded. The query is made to the `.sys/top_partitions_one_hour` view: ```yql SELECT @@ -295,15 +316,59 @@ SELECT DataSize FROM `.sys/top_partitions_one_hour` WHERE CPUCores > 0.9 -AND IntervalEnd BETWEEN Timestamp("YYYY-MM-DDThh:mm:ss.uuuuuuZ") AND Timestamp("YYYY-MM-DDThh:mm:ss.uuuuuuZ") +AND IntervalEnd BETWEEN Timestamp("2000-01-01T00:00:00Z") AND Timestamp("2099-12-31T00:00:00Z") ORDER BY IntervalEnd desc, CPUCores desc ``` -* `"YYYY-MM-DDTHH:MM:SS.UUUUUUZ"`: Time in the UTC 0 zone (`YYYY` stands for year, `MM`, for month, `DD`, for date, `hh`, for hours, `mm`, for minutes, `ss`, for seconds, and `uuuuuu`, for microseconds). For example, `"2023-01-26T13:00:00.000000Z"`. +## History of partitions with broken locks {#top-tli-partitions} + +The following system views contain a history of moments with a non-zero number of broken [locks](../contributor/datashard-locks-and-change-visibility.md) `LocksBroken` in individual partitions of DB tables: + +* `top_partitions_by_tli_one_minute`: The data is split into one-minute intervals, contains the history for the last 6 hours. +* `top_partitions_by_tli_one_hour`: The data is split into one-hour intervals, contains the history for the last 2 weeks. + +The views provide the top 10 partitions with a non-zero number of broken locks `LocksBroken`. Within a single interval, partitions are ranked by the number of broken locks `LocksBroken`. + +The keys of the views are: + +* `IntervalEnd` - the moment of interval closure; +* `Rank` - the rank of the partition by the number of broken locks `LocksBroken` in this interval. + +For example, `top_partitions_by_tli_one_hour` for the hourly interval `"20.12.2024 10:00-11:00"` will output 10 rows, sorted in descending order by `LocksBroken`. They will have `Rank` from 1 to 10 and the same `IntervalEnd` `"20.12.2024 11:00"`. -## Access control entities {#auth} +All tables have the same structure: + +| Column | Description | +|--------|-------------| +| `IntervalEnd` | The end of the minute or hour interval for which statistics are collected.
Type: `Timestamp`.
Key: `0`. | +| `Rank` | Partition rank within an interval (by `CPUCores`).
Type: `Uint32`.
Key: `1`. | +| `TabletId` | ID of the tablet serving the partition.
Type: `Uint64`. | +| `FollowerId` | ID of the partition tablet [follower](../concepts/glossary.md#tablet-follower).A value of 0 means the leader.
Type: `Uint32` | +| `Path` | Full path to the table.
Type: `Utf8`. | +| `LocksAcquired` | Number of locks acquired "on a range of keys" in this interval.
Type: `Uint64`. | +| `LocksWholeShard` | Number of locks acquired "on the entire partition" in this interval.
Type: `Uint64`. | +| `LocksBroken` | Number of broken locks in this interval.
Type: `Uint64`. | +| `NodeId` | ID of the node where the partition was located during the peak load.
Type: `Uint32`. | +| `DataSize` | Approximate partition size, in bytes, during the peak load.
Type: `Uint64`. | +| `RowCount` | Approximate row count during the peak load.
Type: `Uint64`. | +| `IndexSize` | Partition index size per tablet during the peak load.
Type: `Uint64`. | + +### Example queries {#top-tli-partitions-examples} + +The following query returns partitions in the specified time interval, with tablet identifiers and the number of broken locks. The query is made to the `.sys/top_partitions_by_tli_one_minute` view: + +```yql +SELECT + IntervalEnd, + LocksBroken, + Path, + TabletId +FROM `.sys/top_partitions_by_tli_one_hour` +WHERE IntervalEnd BETWEEN Timestamp("2000-01-01T00:00:00Z") AND Timestamp("2099-12-31T00:00:00Z") +ORDER BY IntervalEnd desc, LocksBroken desc +``` -The following system views store data for analyzing various [access control entities](../security/authorization.md). +## Auth users, groups, permissions {#auth} ### Auth users @@ -368,7 +433,7 @@ Table structure: | `Sid` | SID of the [access subject](../concepts/glossary.md#access-subject).
Type: `Utf8`.
Key: `1`. | | `Permission` | Name of the {{ ydb-short-name }} [access right](../yql/reference/syntax/grant.md#permissions-list).
Type: `Utf8`.
Key: `2`. | -#### Example queries +#### Example queries {#auth-permissions-examples} All the directly assigned permissions for the table located at the path `my_table`: diff --git a/ydb/docs/ru/core/concepts/glossary.md b/ydb/docs/ru/core/concepts/glossary.md index 9163f45ffbfa..79ce2511a1ac 100644 --- a/ydb/docs/ru/core/concepts/glossary.md +++ b/ydb/docs/ru/core/concepts/glossary.md @@ -90,16 +90,17 @@ [Подробности реализации таблеток](#tablet-implementation) и связанные термины, а также [основные типы таблеток](#tablet-types), рассматриваются ниже. -### Распределённые транзакции {#distributed-transactions} +### Транзакции {#transactions} {{ ydb-short-name }} реализует **транзакции** (**transactions**) на двух основных уровнях: * [Локальная база данных](#local-database) и остальная [инфраструктура таблеток](#tablet-implementation) позволяют [таблеткам](#tablet) манипулировать своим состоянием, используя **локальные транзакции** с [уровнем изоляции serializable](https://ru.wikipedia.org/wiki/%D0%A3%D1%80%D0%BE%D0%B2%D0%B5%D0%BD%D1%8C_%D0%B8%D0%B7%D0%BE%D0%BB%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%BE%D1%81%D1%82%D0%B8_%D1%82%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D0%B9#Serializable_(%D1%83%D0%BF%D0%BE%D1%80%D1%8F%D0%B4%D0%BE%D1%87%D0%B8%D0%B2%D0%B0%D0%B5%D0%BC%D0%BE%D1%81%D1%82%D1%8C)). Технически они не являются локальными для одного узла, так как это состояние сохраняется удалённо в [распределённом хранилище](#distributed-storage). * В контексте {{ ydb-short-name }} термин **распределённые транзакции** обычно относится к транзакциям, охватывающим несколько таблеток. Например, транзакции между таблицами или даже строками одной таблицы часто являются распределёнными. +* **Одношардовые** транзакции охватывают одну таблетку и выполняются быстрее. Например, транзакции между строками одной партиции таблицы часто являются одношардовыми. Эти механизмы позволяют {{ ydb-short-name }} обеспечивать [строгую согласованность](https://en.wikipedia.org/wiki/Consistency_model#Strict_consistency). -{% if oss == "true" %} +{% if oss %} Реализация распределённых транзакций рассмотрена в отдельной статье [{#T}](../contributor/datashard-distributed-txs.md), а ниже приведён список нескольких [связанных терминов](#distributed-transaction-implementation). @@ -630,9 +631,9 @@ PDisk содержит планировщик, который обеспечив * Записывать больше данных, чем может содержать одна группа хранения. * Хранить различные [LogoBlob](#logoblob) в различных группах хранения, с различными свойствами, такими как кодирование с исправлением ошибок или на различных носителях (HDD, SSD, NVMe). -### Реализация распределённых транзакций {#distributed-transaction-implementation} +### Реализация распределённых транзакций {#transaction-implementation} -Ниже объяснены термины, связанные с реализацией [распределённых транзакций](#distributed-transactions).{% if oss == true %} Сама реализация описана в отдельной статье [{#T}](../contributor/datashard-distributed-txs.md).{% endif %} +Ниже объяснены термины, связанные с реализацией [распределённых транзакций](#transactions).{% if oss == true %} Сама реализация описана в отдельной статье [{#T}](../contributor/datashard-distributed-txs.md).{% endif %} #### Детерминированные транзакции {#deterministic-transactions} @@ -658,7 +659,7 @@ PDisk содержит планировщик, который обеспечив #### Набор чтения-записи {#rw-set} -**Набор чтения-записи**, **RW-набор**, **read-write set** или **RW-set** — это набор данных, который будет участвовать в выполнении [распределённой транзакции](#distributed-transactions). Он объединяет данные набора чтения, которые будут считываться, и набор записи, для которого будут выполняться модификации. +**Набор чтения-записи**, **RW-набор**, **read-write set** или **RW-set** — это набор данных, который будет участвовать в выполнении [распределённой транзакции](#transactions). Он объединяет данные набора чтения, которые будут считываться, и набор записи, для которого будут выполняться модификации. #### Набор чтения {#read-set} @@ -666,7 +667,7 @@ PDisk содержит планировщик, который обеспечив #### Транзакционные прокси {#transaction-proxy} -**Транзакционные прокси**, **transaction proxy** или `TX_PROXY` — это сервис, который оркестрирует выполнение многих [распределённых транзакций](#distributed-transactions): последовательные фазы, выполнение фаз, планирование и агрегацию результатов. В случае прямой оркестрации другими акторами (например, KQP data transactions), он используется для кэширования и выделения уникальных [TxID](#txid). +**Транзакционные прокси**, **transaction proxy** или `TX_PROXY` — это сервис, который оркестрирует выполнение многих [распределённых транзакций](#transactions): последовательные фазы, выполнение фаз, планирование и агрегацию результатов. В случае прямой оркестрации другими акторами (например, KQP data transactions), он используется для кэширования и выделения уникальных [TxID](#txid). #### Флаги транзакции {#txflags} diff --git a/ydb/docs/ru/core/dev/system-views.md b/ydb/docs/ru/core/dev/system-views.md index 118d19c8e437..12710f9da14e 100644 --- a/ydb/docs/ru/core/dev/system-views.md +++ b/ydb/docs/ru/core/dev/system-views.md @@ -1,63 +1,57 @@ # Системные представления базы данных -Вы можете отправлять запросы в специальные служебные представления (system views), чтобы следить за состоянием базы данных. Эти представления доступны из корня дерева базы данных и используют системный префикс пути `.sys`. - -Индекс поля первичного ключа соответствующего представления содержится в описаниях доступных полей далее по тексту. - -Системные представления содержат: - -* [Детальные данные об отдельных партициях таблиц БД](#partitions). -* [Топы запросов по определенным характеристикам](#top-queries). -* [Подробная информация о запросах](#query-metrics). -* [История перегруженных партиций](#top-overload-partitions). -* [Информация о пулах ресурсов](#resource_pools). -* [Сущности управления доступом](#auth). +Для получения служебной информации о состоянии базы данных можно обращаться к системным представлениям (system views). Они доступны из корня дерева базы данных и используют системный префикс пути `.sys`. {% note info %} -Обращение к системным представлениям имеет скорее аналитический характер нагрузки. Частое обращение к ним в больших базах будет существенно расходовать системные ресурсы. Рекомендуемая нагрузка не более 1-2 RPS. +Частое обращение к системным представлениям приводит к дополнительной нагрузке на базу данных, особенно в случае большого размера базы. Превышение частоты в 1 запрос в секунду не рекомендуется. {% endnote %} ## Партиции {#partitions} -Следующее системное представление хранит детализированную информацию об отдельных [партициях](../concepts/datamodel/table.md#partitioning) всех таблиц базы данных: +Следующее системное представление хранит детализированную информацию об [партициях](../concepts/datamodel/table.md#partitioning) таблиц базы данных: -* `partition_stats` — cодержит информацию о моментальных метриках и кумулятивные счетчики операций. К первым относятся, например, данные о нагрузке на CPU или количестве выполняемых [транзакций](../concepts/transactions.md). Ко вторым — общее количество прочитанных строк. +* `partition_stats` — содержит информацию о моментальных метриках и кумулятивных счетчиках операций. К первым относятся, например, данные о нагрузке на CPU или количестве выполняемых [транзакций](../concepts/transactions.md). Ко вторым — общее количество прочитанных строк. -Предназначена для выявления различных неравномерностей в нагрузке на партицию или отображения размера данных в ней. +Предназначено, например, для выявления неравномерно нагруженных партиций или отображения размера данных в них. -Кумулятивные поля (`RowReads`, `RowUpdates` и т.д.) хранят накопленные значения с момента последнего старта таблетки, обслуживающей партицию. +Моментальные метрики (`NodeId`, `AccessTime`, `CPUCores` и т.д.) содержат мгновенные значения. +Кумулятивные (не моментальные) метрики (`RowReads`, `RowUpdates`, `LocksAcquired` и т.д.) хранят накопленные значения с момента последнего старта таблетки (`StartTime`), обслуживающей партицию. Структура представления: -Колонка | Описание -------- | -------- -`OwnerId` | Идентификатор SchemeShard, обслуживающего таблицу.
Тип: `Uint64`.
Ключ: `0`. -`PathId` | Идентификатор пути в SchemeShard.
Тип: `Uint64`.
Ключ: `1`. -`PartIdx` | Порядковый номер партиции.
Тип: `Uint64`.
Ключ: `2`. -`DataSize` | Приблизительный размер партиции в байтах.
Тип: `Uint64`. -`RowCount` | Приблизительное количество строк.
Тип: `Uint64`. -`IndexSize` | Размер индекса партиции в таблетке.
Тип: `Uint64`. -`CPUCores` | Double Моментальное значение нагрузки на партицию (доля ядра) -`TabletId` | Идентификатор таблетки, обслуживающей партицию.
Тип: `Uint64`. -`Path` | Полный путь к таблице.
Тип: `Utf8`. -`NodeId` | Идентификатор ноды, на которой в данный момент обслуживается партиция.
Тип: `Uint32`. -`StartTime` | Последний момент запуска таблетки, обслуживающей партицию.
Тип: `Timestamp`. -`AccessTime` | Последний момент чтения из партиции.
Тип: `Timestamp`. -`UpdateTime` | Последний момент записи в партицию.
Тип: `Timestamp`. -`RowReads` | Количество точечных чтений с момента старта таблетки партиции.
Тип: `Uint64`. -`RowUpdates` | Количество записанных строк с момента старта.
Тип: `Uint64`. -`RowDeletes` | Количество удалённых строк с момента старта.
Тип: `Uint64`. -`RangeReads` | Количество чтений диапазонов строк с момента старта.
Тип: `Uint64`. -`RangeReadRows` | Количество строк, прочитанных в диапазонах с момента старта.
Тип: `Uint64`. -`InFlightTxCount` | Количество транзакций, находящихся в процессе исполнения.
Тип: `Uint64`. -`ImmediateTxCompleted` | Количество завершившихся одношардовых транзакций с момента старта.
Тип: `Uint64`. -`CoordinatedTxCompleted` | Количество завершившихся координируемых транзакций с момента старта.
Тип: `Uint64`. -`TxRejectedByOverload` | Количество транзакций, отменённых по причине слишком высокой нагрузки (с момента старта).
Тип: `Uint64`. -`TxRejectedByOutOfStorage` | Количество транзакций, отменённых из-за нехватки места (с момента старта).
Тип: `Uint64`. - -### Примеры запросов +Колонка | Описание | Тип данных | Моментальная/кумулятивная +--- | --- | --- | --- +`OwnerId` | Идентификатор SchemeShard таблицы.
Ключ: `0`. | `Uint64` | Моментальная +`PathId` | Идентификатор пути в SchemeShard.
Ключ: `1`. | `Uint64` | Моментальная +`PartIdx` | Порядковый номер партиции.
Ключ: `2`. | `Uint64` | Моментальная +`DataSize` | Приблизительный размер данных партиции в байтах. | `Uint64` | Моментальная +`RowCount` | Приблизительное количество строк. | `Uint64` | Моментальная +`IndexSize` | Размер индекса партиции в байтах. | `Uint64` | Моментальная +`CPUCores` | Моментальное значение нагрузки на партицию (доля времени ядра процессора, затраченного актором партиции). | `Double` | Моментальная +`TabletId` | Идентификатор таблетки партиции. | `Uint64` | Моментальная +`FollowerId` | Идентификатор [подписчика](../concepts/glossary.md#tablet-follower) таблетки партиции. Значение 0 означает лидера. | `Uint32` | Моментальная +`Path` | Полный путь к таблице. | `Utf8` | Моментальная +`NodeId` | Идентификатор ноды, на которой в данный момент обслуживается партиция. | `Uint32` | Моментальная +`StartTime` | Последний момент запуска таблетки партиции. | `Timestamp` | Моментальная +`AccessTime` | Последний момент чтения из партиции. | `Timestamp` | Моментальная +`UpdateTime` | Последний момент записи в партицию. | `Timestamp` | Моментальная +`RowReads` | Количество чтений по ключу. | `Uint64` | Кумулятивная +`RowUpdates` | Количество записанных строк . | `Uint64` | Кумулятивная +`RowDeletes` | Количество удалённых строк. | `Uint64` | Кумулятивная +`RangeReads` | Количество чтений по диапазону ключей. | `Uint64` | Кумулятивная +`RangeReadRows` | Количество строк, прочитанных в диапазонах. | `Uint64` | Кумулятивная +`InFlightTxCount` | Количество исполняющихся транзакций. | `Uint64` | Моментальная +`ImmediateTxCompleted` | Количество завершившихся [одношардовых транзакций](../concepts/glossary.md#transactions). | `Uint64` | Кумулятивная +`CoordinatedTxCompleted` | Количество завершившихся [распределенных транзакций](../concepts/glossary.md#transactions). | `Uint64` | Кумулятивная +`TxRejectedByOverload` | Количество транзакций, отменённых по причине [высокой нагрузки](../troubleshooting/performance/queries/overloaded-errors.md). | `Uint64` | Кумулятивная +`TxRejectedByOutOfStorage` | Количество транзакций, отменённых из-за нехватки места в хранилище. | `Uint64` | Кумулятивная +`LocksAcquired` | Количество установленных [блокировок](../contributor/datashard-locks-and-change-visibility.md) . | `Uint64` | Кумулятивная +`LocksWholeShard` | Количество установленных [блокировок "весь шард"](../contributor/datashard-locks-and-change-visibility.md#ограничения). | `Uint64` | Кумулятивная +`LocksBroken` | Количество [сломанных блокировок](../contributor/datashard-locks-and-change-visibility.md#высокоуровневая-схема-работы). | `Uint64` | Кумулятивная + +### Примеры запросов {#partitions-examples} Топ-5 самых загруженных партиций среди всех таблиц базы данных: @@ -84,18 +78,39 @@ FROM `.sys/partition_stats` GROUP BY Path ``` +Список таблиц базы с наибольшим числом сломанных блокировок: + +```yql +SELECT + Path, + COUNT(*) as Partitions, + SUM(LocksBroken) as TotalLocksBroken +FROM `.sys/partition_stats` +GROUP BY Path +ORDER BY TotalLocksBroken DESC +``` + ## Топы запросов {#top-queries} -Следующие системные представления хранят данные для анализа потока пользовательских запросов: +Следующие системные представления хранят данные для анализа пользовательских запросов. + +Наибольшее полное время выполнения запроса: + +* `top_queries_by_duration_one_minute` — данные разбиты на минутные интервалы, содержит данные за последние 6 часов; +* `top_queries_by_duration_one_hour` — данные разбиты на часовые интервалы, содержит данные за последние 2 недели. + +Наибольшее количество прочитанных из таблицы байт: -* `top_queries_by_duration_one_minute` — данные разбиты на минутные интервалы, содержит топ-5 запросов с наибольшим полным временем исполнения за последние 6 часов; -* `top_queries_by_duration_one_hour` — данные разбиты на часовые интервалы, содержит топ-5 запросов с наибольшим полным временем исполнения за последние 2 недели; -* `top_queries_by_read_bytes_one_minute` — данные разбиты на минутные интервалы, содержит топ-5 запросов с наибольшим количеством прочитанных из таблицы байт за последние 6 часов; -* `top_queries_by_read_bytes_one_hour` — данные разбиты на часовые интервалы, содержит топ-5 запросов с наибольшим количеством прочитанных из таблицы байт за последние 2 недели; -* `top_queries_by_cpu_time_one_minute` — данные разбиты на минутные интервалы, содержит топ-5 запросов с наибольшим затраченным процессорным временем за последние 6 часов; -* `top_queries_by_cpu_time_one_hour` — данные разбиты на часовые интервалы, содержит топ-5 запросов с наибольшим затраченным процессорным временем за последние 2 недели. +* `top_queries_by_read_bytes_one_minute` — данные разбиты на минутные интервалы, содержит данные за последние 6 часов; +* `top_queries_by_read_bytes_one_hour` — данные разбиты на часовые интервалы, содержит данные за последние 2 недели. -Различные запуски запроса с одним и тем же текстом дедуплицируются. Топ содержит информацию о конкретном запуске с максимальным значением соответствующей характеристики запроса в пределах одного временного интервала. +Наибольшее затраченное процессорное время: + +* `top_queries_by_cpu_time_one_minute` — данные разбиты на минутные интервалы, содержит данные за последние 6 часов; +* `top_queries_by_cpu_time_one_hour` — данные разбиты на часовые интервалы, содержит данные за последние 2 недели. + +Запросы с одним и тем же текстом объединяются, в выдачу попадает запрос с максимальным значением соответствующей метрики. +Каждый временной интервал (минута или час) содержит ТОП-5 запросов, выполненных в этот временной интервал. Поля, предоставляющие информацию о затраченном процессорном времени (...`CPUTime`), выражены в микросекундах. @@ -104,8 +119,8 @@ GROUP BY Path Все представления имеют одинаковую структуру: Колонка | Описание -------- | -------- -`IntervalEnd` | Момент закрытия минутного или часового интервала.
Тип: `Timestamp`.
Ключ: `0`. +--- | --- +`IntervalEnd` | Момент окончания минутного или часового интервала, за который собрана статистика.
Тип: `Timestamp`.
Ключ: `0`. `Rank` | Ранг запроса в топе.
Тип: `Uint32`.
Ключ: `1`. `QueryText` | Текст запроса.
Тип: `Utf8`. `Duration` | Полное время исполнения запроса.
Тип: `Interval`. @@ -134,10 +149,9 @@ GROUP BY Path `CompileCPUTime` | Процессорное время, затраченное на компиляцию запроса.
Тип: `Uint64`. `ProcessCPUTime` | Процессорное время, затраченное на общую обработку запроса.
Тип: `Uint64`. +### Примеры запросов {#top-queries-examples} -### Примеры запросов - -Топ запросов по времени выполнения за последнюю минуту их отправки: +Топ запросов по времени выполнения. Запрос выполняется к представлению `.sys/top_queries_by_duration_one_minute`: ```yql PRAGMA AnsiInForEmptyOrNullableItemsCollections; @@ -155,7 +169,7 @@ FROM `.sys/top_queries_by_duration_one_minute` WHERE IntervalEnd IN $last ``` -Запросы, прочитавшие больше всего байт, в разбивке по минутам: +Запросы, прочитавшие больше всего байт. Запрос выполняется к представлению `.sys/top_queries_by_read_bytes_one_minute`: ```yql SELECT @@ -174,7 +188,7 @@ WHERE Rank = 1 * `query_metrics_one_minute` — данные разбиты по минутным интервалам, содержит до 256 запросов за последние 6 часов. -Каждая строка представления содержит информацию о множестве случившихся за интервал запросов с одинаковым текстом. Поля представления предоставляют минимальное, максимальное и суммарное значение по каждой отслеживаемой характеристике запроса. В пределах интервала запросы отсортированы по убыванию суммарного потраченного процессорного времени. +Каждая строка представления содержит информацию о множестве случившихся за интервал запросов с одинаковым текстом. Поля представления содержат минимальное, максимальное и суммарное значение по каждой отслеживаемой характеристике запроса. В пределах интервала запросы отсортированы по убыванию суммарного потраченного процессорного времени. Ограничения: @@ -185,7 +199,7 @@ WHERE Rank = 1 Колонка | Описание ---|--- -`IntervalEnd` | Момент закрытия минутного интервала.
Тип: `Timestamp`.
Ключ: `0`. +`IntervalEnd` | Момент окончания минутного интервала, за который собрана статистика
Тип: `Timestamp`.
Ключ: `0`. `Rank` | Ранг запроса в пределах интервала (по полю SumCPUTime).
Тип: `Uint32`.
Ключ: `1`. `QueryText` | Текст запроса.
Тип: `Utf8`. `Count` | Количество запусков запроса.
Тип: `Uint64`. @@ -211,7 +225,7 @@ WHERE Rank = 1 `MinDeleteRows` | Минимальное количество удалённых строк.
Тип: `Uint64`. `MaxDeleteRows` | Максимальное количество удалённых строк.
Тип: `Uint64`. -### Примеры запросов +### Примеры запросов {#query-metrics-examples} Топ-10 запросов за последние 6 часов по общему количеству записанных строк в минутном интервале: @@ -250,25 +264,33 @@ LIMIT 100 В представления попадают партиции с пиковой нагрузкой более 70 % (`CPUCores` > 0,7). В пределах одного интервала партиции ранжированы по пиковому значению нагрузки. -Все представления имеют одинаковую структуру: +Оба представления содержат одинаковый набор полей: + +Ключами представления являются: + +* `IntervalEnd` - момент окончания интервала; +* `Rank` - ранг партиции по пиковой нагрузке `CPUCores` в этом интервале. + +Например, если в таблице есть 10 партиций, то `top_partitions_one_hour` для часового интервала `"20.12.2024 10:00-11:00"` выдаст 10 строк, отсортированных по порядку убывания `CPUCores`. У них будет `Rank` от 1 до 10 и одинаковый `IntervalEnd` `"20.12.2024 11:00"`. Колонка | Описание -------- | -------- -`IntervalEnd` | Момент закрытия минутного или часового интервала.
Тип: `Timestamp`.
Ключ: `0`. -`Rank` | Ранг партиции в пределах интервала (по CPUCores).
Тип: `Uint32`.
Ключ: `1`. +--- | --- +`IntervalEnd` | Момент окончания минутного или часового интервала, за который собрана статистика.
Тип: `Timestamp`.
Ключ: `0`. +`Rank` | Ранг партиции в пределах интервала (по `CPUCores`).
Тип: `Uint32`.
Ключ: `1`. `TabletId` | Идентификатор таблетки, обслуживающей партицию.
Тип: `Uint64`. +`FollowerId` | Идентификатор [подписчика](../concepts/glossary.md#tablet-follower) таблетки партиции. Значение 0 означает лидера.
Тип: `Uint32` `Path` | Полный путь к таблице.
Тип: `Utf8`. `PeakTime` | Момент пикового значения в пределах интервала.
Тип: `Timestamp`. -`CPUCores` | Пиковое значение нагрузки на партицию (доля ядра).
Тип: `Double`. +`CPUCores` | Пиковое значение нагрузки на партицию (доля времени ядра процессора, затраченного актором партиции).
Тип: `Double`. `NodeId` | Идентификатор ноды, на которой находилась партиция в момент пика.
Тип: `Uint32`. `DataSize` | Приблизительный размер партиции в байтах в момент пика.
Тип: `Uint64`. `RowCount` | Приблизительное количество строк в момент пика.
Тип: `Uint64`. `IndexSize` | Размер индекса партиции в таблетке в момент пика.
Тип: `Uint64`. `InFlightTxCount` | Количество транзакций, находящихся в процессе исполнения в момент пика.
Тип: `Uint32`. -### Примеры запросов +### Примеры запросов {#top-overload-partitions-examples} -Следующий запрос выводит партиции с потреблением CPU более 70% в указанном интервале времени, с идентификаторами таблеток и их размерами на момент превышения. Запрос выполняется к представлению `.sys/top_partitions_one_minute`, которое содержит данные за последние 6 часов с разбиением по часовым интервалам: +Следующий запрос выводит партиции с потреблением CPU более 70% в указанном интервале времени, с идентификаторами таблеток и их размерами на момент превышения. Запрос выполняется к представлению `.sys/top_partitions_one_minute`, которое содержит данные за последние 6 часов с разбиением по минутным интервалам: ```yql SELECT @@ -279,13 +301,11 @@ SELECT DataSize FROM `.sys/top_partitions_one_minute` WHERE CPUCores > 0.7 -AND IntervalEnd BETWEEN Timestamp("YYYY-MM-DDThh:mm:ss.uuuuuuZ") AND Timestamp("YYYY-MM-DDThh:mm:ss.uuuuuuZ") +AND IntervalEnd BETWEEN Timestamp("2000-01-01T00:00:00Z") AND Timestamp("2099-12-31T00:00:00Z") ORDER BY IntervalEnd desc, CPUCores desc ``` -* `"YYYY-MM-DDTHH:MM:SS.UUUUUUZ"` — время в зоне UTC 0 (`YYYY` — год, `MM` — месяц, `DD` — число, `hh` — часы, `mm` — минуты, `ss` — секунды, `uuuuuu` — микросекунды). Например, `"2023-01-26T13:00:00.000000Z"`. - -Следующий запрос выводит партиции с потреблением CPU более 90% в указанном интервале времени, с идентификаторами таблеток и их размерами на момент превышения. Запрос выполняется к представлению `.sys/top_partitions_one_hour`, которое содержит данные за последние 2 недели с разбиением по минутным интервалам: +Следующий запрос выводит партиции с потреблением CPU более 90% в указанном интервале времени, с идентификаторами таблеток и их размерами на момент превышения. Запрос выполняется к представлению `.sys/top_partitions_one_hour`, которое содержит данные за последние 2 недели с разбиением по часовым интервалам: ```yql SELECT @@ -296,11 +316,57 @@ SELECT DataSize FROM `.sys/top_partitions_one_hour` WHERE CPUCores > 0.9 -AND IntervalEnd BETWEEN Timestamp("YYYY-MM-DDThh:mm:ss.uuuuuuZ") AND Timestamp("YYYY-MM-DDThh:mm:ss.uuuuuuZ") +AND IntervalEnd BETWEEN Timestamp("2000-01-01T00:00:00Z") AND Timestamp("2099-12-31T00:00:00Z") ORDER BY IntervalEnd desc, CPUCores desc ``` -* `"YYYY-MM-DDTHH:MM:SS.UUUUUUZ"` — время в зоне UTC 0 (`YYYY` — год, `MM` — месяц, `DD` — число, `hh` — часы, `mm` — минуты, `ss` — секунды, `uuuuuu` — микросекунды). Например, `"2023-01-26T13:00:00.000000Z"`. +## История партиций со сломанными блокировками {#top-tli-partitions} + +Следующие системные представления содержат историю моментов с ненулевым числом сломанных [блокировок](../contributor/datashard-locks-and-change-visibility.md) `LocksBroken` в отдельных партициях таблиц БД: + +* `top_partitions_by_tli_one_minute` — данные разбиты на минутные интервалы, содержит историю за последние 6 часов; +* `top_partitions_by_tli_one_hour` — данные разбиты на часовые интервалы, содержит историю за последние 2 недели. + +Представления выдают топ-10 партиций с ненулевым числом сломанных блокировок `LocksBroken`. В пределах одного интервала партиции ранжированы по числу сломанных блокировок `LocksBroken`. + +Ключами представлений являются: + +* `IntervalEnd` - момент окончания интервала; +* `Rank` - ранг партиции по числу сломанных блокировок `LocksBroken` в этом интервале. + +Например, `top_partitions_by_tli_one_hour` для часового интервала `"20.12.2024 10:00-11:00"` выдаст 10 строк, отсортированных по порядку убывания `LocksBroken`. У них будет `Rank` от 1 до 10 и одинаковый `IntervalEnd` `"20.12.2024 11:00"`. + +Оба представления содержат одинаковый набор полей: + +Колонка | Описание +--- | --- +`IntervalEnd` | Момент окончания минутного или часового интервала, за который собрана статистика.
Тип: `Timestamp`.
Ключ: `0`. +`Rank` | Ранг партиции в пределах интервала (по `LocksBroken`).
Тип: `Uint32`.
Ключ: `1`. +`TabletId` | Идентификатор таблетки, обслуживающей партицию.
Тип: `Uint64`. +`FollowerId` | Идентификатор [подписчика](../concepts/glossary.md#tablet-follower) таблетки партиции. Значение 0 означает лидера.
Тип: `Uint32` +`Path` | Полный путь к таблице.
Тип: `Utf8`. +`LocksAcquired` | Число установленных блокировок "на диапазон ключей" в данном интервале.
Тип: `Uint64`. +`LocksWholeShard` | Число установленных блокировок "на всю партицию" в данном интервале.
Тип: `Uint64`. +`LocksBroken` | Число сломанных блокировок в данном интервале.
Тип: `Uint64`. +`NodeId` | Идентификатор ноды, на которой находилась партиция в момент пика.
Тип: `Uint32`. +`DataSize` | Приблизительный размер партиции в байтах в момент пика.
Тип: `Uint64`. +`RowCount` | Приблизительное количество строк в момент пика.
Тип: `Uint64`. +`IndexSize` | Размер индекса партиции в таблетке в момент пика.
Тип: `Uint64`. + +### Примеры запросов {#top-tli-partitions-examples} + +Следующий запрос выводит партиции в указанном интервале времени, с идентификаторами таблеток и числом сломанных блокировок. Запрос выполняется к представлению `.sys/top_partitions_by_tli_one_minute`: + +```yql +SELECT + IntervalEnd, + LocksBroken, + Path, + TabletId +FROM `.sys/top_partitions_by_tli_one_hour` +WHERE IntervalEnd BETWEEN Timestamp("2000-01-01T00:00:00Z") AND Timestamp("2099-12-31T00:00:00Z") +ORDER BY IntervalEnd desc, LocksBroken desc +``` {% if feature_resource_pool %} @@ -321,7 +387,7 @@ ORDER BY IntervalEnd desc, CPUCores desc `QueryCpuLimitPercentPerNode` | Процент доступного CPU на узле для одного запроса в пуле ресурсов.
Тип: `Double`. `QueryMemoryLimitPercentPerNode` | Процент доступной памяти на узле, который может использовать запрос в данном пуле ресурсов.
Тип: `Double`. -### Пример +### Пример {#resource_pools-examples} Следующий запрос выводит информацию о настройках пула ресурсов с именем `default`: @@ -339,12 +405,6 @@ FROM `.sys/resource_pools` WHERE Name = "default"; ``` -Пример выдачи: - -\# | Name | ConcurrentQueryLimit | QueueSize | DatabaseLoadCpuThreshold | ResourceWeight | TotalCpuLimitPercentPerNode | QueryCpuLimitPercentPerNode | QueryMemoryLimitPercentPerNode ---- | --- | --- | --- | --- | --- | --- | --- | --- -1 | default | -1 | -1 | -1 | -1 | -1 | -1 | -1 - {% endif %} {% if feature_resource_pool_classifier %} @@ -362,7 +422,7 @@ WHERE Name = "default"; `MemberName` | Пользователь или группа пользователей, которые будут отправлены в указанный пул ресурсов.
Тип: `Utf8`. `ResourcePool` | Имя пула ресурсов, в который будут отправлены запросы.
Тип: `Utf8`. -### Пример +### Пример {#resource_pools_classifiers-examples} Следующий запрос выводит информацию о настройках классификатора пула ресурсов с именем `olap`: @@ -376,17 +436,9 @@ FROM `.sys/resource_pools_classifiers` WHERE Name = "olap"; ``` -Пример выдачи: - -\# | Name | Rank | MemberName | ResourcePool ---- | --- | --- | --- | --- -1 | olap | 1000 | olap_group@builtin | olap - {% endif %} -## Сущности управления доступом {#auth} - -Следующие системные представления содержат информацию о различных [сущностях управления доступом](../security/authorization.md). +## Информация о пользователях, группах и их правах {#auth} ### Информация о пользователях From 04f7f3dc6e9c69f45019273a24405cc630491051 Mon Sep 17 00:00:00 2001 From: lucius Date: Tue, 8 Apr 2025 11:42:38 +0300 Subject: [PATCH 042/454] YT-24527 trying to fix dq-gateway crashes commit_hash:7662baf98f53a4d1c3b1538a80caa7101f744b0a --- yql/essentials/core/facade/yql_facade.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yql/essentials/core/facade/yql_facade.cpp b/yql/essentials/core/facade/yql_facade.cpp index 055378a3ff15..5497ff6b7bd9 100644 --- a/yql/essentials/core/facade/yql_facade.cpp +++ b/yql/essentials/core/facade/yql_facade.cpp @@ -1140,7 +1140,7 @@ TProgram::TFutureStatus TProgram::OptimizeAsyncWithConfig( dataProviders = DataProviders_; } - for (const auto& dp : DataProviders_) { + for (const auto& dp : dataProviders) { if (!dp.RemoteClusterProvider || !dp.RemoteOptimize) { continue; } @@ -1276,7 +1276,7 @@ TProgram::TFutureStatus TProgram::RunAsync( dataProviders = DataProviders_; } - for (const auto& dp : DataProviders_) { + for (const auto& dp : dataProviders) { if (!dp.RemoteClusterProvider || !dp.RemoteRun) { continue; } @@ -1355,7 +1355,7 @@ TProgram::TFutureStatus TProgram::RunAsyncWithConfig( dataProviders = DataProviders_; } - for (const auto& dp : DataProviders_) { + for (const auto& dp : dataProviders) { if (!dp.RemoteClusterProvider || !dp.RemoteRun) { continue; } From 82ae4fefcd3519d3fe80061978e7ef61ca47049a Mon Sep 17 00:00:00 2001 From: Tony-Romanov <150126326+Tony-Romanov@users.noreply.github.com> Date: Tue, 8 Apr 2025 11:58:14 +0200 Subject: [PATCH 043/454] Add TablePathPrefix. (#16894) --- ydb/apps/etcd_proxy/proxy.cpp | 13 ++++++++++--- ydb/apps/etcd_proxy/proxy.h | 2 +- ydb/apps/etcd_proxy/service/etcd_base_init.cpp | 8 ++++---- ydb/apps/etcd_proxy/service/etcd_base_init.h | 4 ++-- ydb/apps/etcd_proxy/service/etcd_impl.cpp | 1 + ydb/apps/etcd_proxy/service/etcd_shared.h | 1 + ydb/apps/etcd_proxy/service/etcd_watch.cpp | 3 +++ ydb/apps/etcd_proxy/service/ut/etcd_service_ut.cpp | 2 +- 8 files changed, 23 insertions(+), 11 deletions(-) diff --git a/ydb/apps/etcd_proxy/proxy.cpp b/ydb/apps/etcd_proxy/proxy.cpp index 9f2fc4420f7b..47206dfafc73 100644 --- a/ydb/apps/etcd_proxy/proxy.cpp +++ b/ydb/apps/etcd_proxy/proxy.cpp @@ -61,7 +61,7 @@ int TProxy::Discovery() { } int TProxy::StartServer() { - if (const auto res = Stuff->Client->ExecuteQuery(NEtcd::GetLastRevisionSQL(), NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); res.IsSuccess()) { + if (const auto res = Stuff->Client->ExecuteQuery(NEtcd::GetLastRevisionSQL(Stuff->TablePrefix), NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); res.IsSuccess()) { if (auto result = res.GetResultSetParser(0); result.TryNextRow()) { Stuff->Revision.store(NYdb::TValueParser(result.GetValue(0)).GetInt64()); } else { @@ -129,7 +129,7 @@ int TProxy::Run() { } int TProxy::InitDatabase() { - if (const auto res = Stuff->Client->ExecuteQuery(NEtcd::GetCreateTablesSQL(), NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); res.IsSuccess()) { + if (const auto res = Stuff->Client->ExecuteQuery(NEtcd::GetCreateTablesSQL(Stuff->TablePrefix), NYdb::NQuery::TTxControl::NoTx()).ExtractValueSync(); res.IsSuccess()) { std::cout << "Database " << Database << " on " << Endpoint << " was initialized." << std::endl; return 0; } else { @@ -210,7 +210,7 @@ int TProxy::ImportDatabase() { const auto driver = NYdb::TDriver(config); auto client = NYdb::NTable::TTableClient(driver); - if (const auto res = client.BulkUpsert(Database + "/content", std::move(value)).ExtractValueSync(); !res.IsSuccess()) { + if (const auto res = client.BulkUpsert(Database + Folder + "/content", std::move(value)).ExtractValueSync(); !res.IsSuccess()) { std::cout << res.GetIssues().ToString() << std::endl; return 1; } @@ -235,6 +235,7 @@ TProxy::TProxy(int argc, char** argv) opts.AddLongOption("database", "YDB etcd databse").Required().RequiredArgument("DATABASE").StoreResult(&Database); opts.AddLongOption("endpoint", "YDB endpoint to connect").Required().RequiredArgument("ENDPOINT").StoreResult(&Endpoint); + opts.AddLongOption("folder", "YDB etcd root folder").Required().RequiredArgument("FOLDER").StoreResult(&Folder); opts.AddLongOption("token", "YDB token for connection").Optional().RequiredArgument("TOKEN").StoreResult(&Token); opts.AddLongOption("ydbca", "YDB CA for connection").Optional().RequiredArgument("CA").StoreResult(&CA); @@ -256,6 +257,12 @@ TProxy::TProxy(int argc, char** argv) LockAllMemory(LockCurrentMemory); } + if (!Folder.empty()) { + std::ostringstream prefix; + prefix << "pragma TablePathPrefix = '" << Database << Folder << "';" << std::endl; + Stuff->TablePrefix = prefix.str(); + } + THolder actorSystemSetup = BuildActorSystemSetup(); TIntrusivePtr loggerSettings = BuildLoggerSettings(); diff --git a/ydb/apps/etcd_proxy/proxy.h b/ydb/apps/etcd_proxy/proxy.h index a539ea3a135d..aeb84602ba51 100644 --- a/ydb/apps/etcd_proxy/proxy.h +++ b/ydb/apps/etcd_proxy/proxy.h @@ -45,7 +45,7 @@ class TProxy { std::unique_ptr GRpcServer; bool Initialize_ = false; - std::string Database, Endpoint, Token, CA; + std::string Database, Endpoint, Token, CA, Folder; ui16 ListeningPort = 2379U; std::string Root, Cert, Key; std::string ImportFrom_, ImportPrefix_; diff --git a/ydb/apps/etcd_proxy/service/etcd_base_init.cpp b/ydb/apps/etcd_proxy/service/etcd_base_init.cpp index f60939247cb2..196a27a30669 100644 --- a/ydb/apps/etcd_proxy/service/etcd_base_init.cpp +++ b/ydb/apps/etcd_proxy/service/etcd_base_init.cpp @@ -4,12 +4,12 @@ namespace NEtcd { -std::string GetCreateTablesSQL() { - return NResource::Find("create.sql"sv); +std::string GetCreateTablesSQL(const std::string& prefix) { + return prefix + NResource::Find("create.sql"sv); } -std::string GetLastRevisionSQL() { - return "select nvl(max(`modified`), 1L) from `content`; select nvl(max(`id`), 1L) from `leases`;"; +std::string GetLastRevisionSQL(const std::string& prefix) { + return prefix + "select nvl(max(`modified`), 1L) from `content`; select nvl(max(`id`), 1L) from `leases`;"; } } diff --git a/ydb/apps/etcd_proxy/service/etcd_base_init.h b/ydb/apps/etcd_proxy/service/etcd_base_init.h index a43c300bd706..6e82372eee30 100644 --- a/ydb/apps/etcd_proxy/service/etcd_base_init.h +++ b/ydb/apps/etcd_proxy/service/etcd_base_init.h @@ -4,9 +4,9 @@ namespace NEtcd { -std::string GetCreateTablesSQL(); +std::string GetCreateTablesSQL(const std::string& prefix); -std::string GetLastRevisionSQL(); +std::string GetLastRevisionSQL(const std::string& prefix); } diff --git a/ydb/apps/etcd_proxy/service/etcd_impl.cpp b/ydb/apps/etcd_proxy/service/etcd_impl.cpp index 59adbc029c67..e760672f020c 100644 --- a/ydb/apps/etcd_proxy/service/etcd_impl.cpp +++ b/ydb/apps/etcd_proxy/service/etcd_impl.cpp @@ -816,6 +816,7 @@ class TEtcdRequestGrpc std::ostringstream sql; NYdb::TParamsBuilder params; sql << "-- " << GetRequestName() << " >>>>" << std::endl; + sql << Stuff->TablePrefix; this->MakeQueryWithParams(sql, params); sql << "-- " << GetRequestName() << " <<<<" << std::endl; // std::cout << std::endl << sql.view() << std::endl; diff --git a/ydb/apps/etcd_proxy/service/etcd_shared.h b/ydb/apps/etcd_proxy/service/etcd_shared.h index b42af880964f..e4be66321d9e 100644 --- a/ydb/apps/etcd_proxy/service/etcd_shared.h +++ b/ydb/apps/etcd_proxy/service/etcd_shared.h @@ -17,6 +17,7 @@ struct TSharedStuff { std::unique_ptr Client; std::atomic Revision = 0LL, Lease = 0LL; NActors::TActorId Watchtower; + std::string TablePrefix; }; std::string IncrementKey(std::string key); diff --git a/ydb/apps/etcd_proxy/service/etcd_watch.cpp b/ydb/apps/etcd_proxy/service/etcd_watch.cpp index 6970fd24011a..878961658efa 100644 --- a/ydb/apps/etcd_proxy/service/etcd_watch.cpp +++ b/ydb/apps/etcd_proxy/service/etcd_watch.cpp @@ -65,6 +65,7 @@ class TKeysKeeper : public TActorBootstrapped { const auto& leasePraramName = AddParam("Lease", params, ev->Get()->Record.id()); std::ostringstream sql; + sql << Stuff->TablePrefix; sql << "update `leases` set `updated` = CurrentUtcDatetime(`id`) where " << leasePraramName << " = `id`;" << std::endl; sql << "select `id`, `ttl` - unwrap(cast(CurrentUtcDatetime(`id`) - `updated` as Int64) / 1000000L) as `granted` from `leases` where " << leasePraramName << " = `id`;" << std::endl; @@ -165,6 +166,7 @@ class TWatch : public TActorBootstrapped { MakeSimplePredicate(Key, RangeEnd, where, params); std::ostringstream sql; + sql << Stuff->TablePrefix; if (WithPrevious) { sql << "select * from (select max_by(TableRow(), `modified`) from `content` where " << revName << " > `modified` and " << where.view() << " group by `key`) flatten columns union all" << std::endl; } @@ -586,6 +588,7 @@ class TWatchtower : public TActorBootstrapped { Revision = Stuff->Revision.fetch_add(1LL) + 1LL; std::ostringstream sql; + sql << Stuff->TablePrefix; NYdb::TParamsBuilder params; const auto& revName = AddParam("Revision", params, Revision); diff --git a/ydb/apps/etcd_proxy/service/ut/etcd_service_ut.cpp b/ydb/apps/etcd_proxy/service/ut/etcd_service_ut.cpp index d9b8b11f7389..b0444837113f 100644 --- a/ydb/apps/etcd_proxy/service/ut/etcd_service_ut.cpp +++ b/ydb/apps/etcd_proxy/service/ut/etcd_service_ut.cpp @@ -105,7 +105,7 @@ void MakeTables(auto &channel) { const auto stub = Ydb::Query::V1::QueryService::NewStub(channel); Ydb::Query::ExecuteQueryRequest request; request.set_exec_mode(Ydb::Query::EXEC_MODE_EXECUTE); - request.mutable_query_content()->set_text(std::string("PRAGMA TablePathPrefix='/Root';\n") + NEtcd::GetCreateTablesSQL()); + request.mutable_query_content()->set_text(NEtcd::GetCreateTablesSQL(std::string("PRAGMA TablePathPrefix='/Root';\n"))); grpc::ClientContext executeCtx; Ydb::Query::ExecuteQueryResponsePart response; From be3ac2bb7928b48dfa4693d9dba5c3bd524574a6 Mon Sep 17 00:00:00 2001 From: sabdenovch Date: Tue, 8 Apr 2025 13:32:30 +0300 Subject: [PATCH 044/454] QL joins refactoring commit_hash:bf6a38b831d4a1301e19a6524c711d7a1c17bf48 --- library/cpp/yt/memory/chunked_memory_pool.cpp | 1 + yt/yt/core/misc/mpsc_stack.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/library/cpp/yt/memory/chunked_memory_pool.cpp b/library/cpp/yt/memory/chunked_memory_pool.cpp index d8673f5d6c3d..69794dcee19b 100644 --- a/library/cpp/yt/memory/chunked_memory_pool.cpp +++ b/library/cpp/yt/memory/chunked_memory_pool.cpp @@ -58,6 +58,7 @@ TChunkedMemoryPool::TChunkedMemoryPool( , ChunkProviderHolder_(std::move(chunkProvider)) , ChunkProvider_(ChunkProviderHolder_.Get()) { + YT_VERIFY(ChunkProviderHolder_); Initialize(startChunkSize); } diff --git a/yt/yt/core/misc/mpsc_stack.h b/yt/yt/core/misc/mpsc_stack.h index f19d22991004..ad461a7ef1ab 100644 --- a/yt/yt/core/misc/mpsc_stack.h +++ b/yt/yt/core/misc/mpsc_stack.h @@ -10,7 +10,7 @@ namespace NYT { //! Multiple producer single consumer lock-free stack. template -class TMpscStack +class TMpscStack final { public: TMpscStack(const TMpscStack&) = delete; From b005f513a413516a4af89f4c341d92d3ee0ca1bd Mon Sep 17 00:00:00 2001 From: kirilltatunov Date: Tue, 8 Apr 2025 13:52:02 +0300 Subject: [PATCH 045/454] Move HPND-sell-variant to REQUIRE_CITATION MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HPND уже в REQUIRE_CITATION, а HPND-sell-variant как будто бы такая же, но разрешает больше. https://spdx.org/licenses/HPND-sell-variant.html > This license is a variant of HPND (https://spdx.org/licenses/HPND.html). This variant explicitly includes the permission to "sell" the software, which is not explicitly referenced in the HPND template, and makes a few other minor changes. commit_hash:87d4ef4529dfc8fee641b6a0f59a4a0bb1095b8b --- build/conf/licenses.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/conf/licenses.json b/build/conf/licenses.json index 72edb8cdc6a2..5e64e3511da7 100644 --- a/build/conf/licenses.json +++ b/build/conf/licenses.json @@ -60,7 +60,6 @@ "GPL-2.0-or-later WITH mif-exception", "GWT-Terms", "Hdf5", - "HPND-sell-variant", "HSQLDB-BSD-3-Clause", "Ibm-Dhcp", "Ietf-trust", @@ -244,6 +243,7 @@ "GPL-3.0-or-later WITH Bison-exception-2.2", "H2", "HPND", + "HPND-sell-variant", "IBM-pibs", "ICU", "Ietf", From 70db6dbde3225ddbcf55b8f2347d5c26c565006b Mon Sep 17 00:00:00 2001 From: Nikolay Shumkov Date: Tue, 8 Apr 2025 14:27:51 +0300 Subject: [PATCH 046/454] Fix progress stats in ydb_cli (#16912) --- ydb/public/lib/ydb_cli/commands/benchmark_utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ydb/public/lib/ydb_cli/commands/benchmark_utils.cpp b/ydb/public/lib/ydb_cli/commands/benchmark_utils.cpp index eeea746f3726..689d1c8b2fca 100644 --- a/ydb/public/lib/ydb_cli/commands/benchmark_utils.cpp +++ b/ydb/public/lib/ydb_cli/commands/benchmark_utils.cpp @@ -345,7 +345,7 @@ TQueryBenchmarkResult ExecuteImpl(const TString& query, NQuery::TQueryClient& cl } composite = MakeHolder(); composite->SetDeadlineName(benchmarkSettings.Deadline.Name); - return composite->Scan(it); + return composite->Scan(it, benchmarkSettings.PlanFileName); }, benchmarkSettings.RetrySettings); return ConstructResultByStatus(resStatus, composite, benchmarkSettings); } From d98dbe488a7e82c59beced418326acb3a5ca0431 Mon Sep 17 00:00:00 2001 From: Nikita Vasilev Date: Tue, 8 Apr 2025 14:28:55 +0300 Subject: [PATCH 047/454] Fixed move errors (#16897) --- ydb/core/kqp/runtime/kqp_write_actor.cpp | 2 +- ydb/core/kqp/runtime/kqp_write_table.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ydb/core/kqp/runtime/kqp_write_actor.cpp b/ydb/core/kqp/runtime/kqp_write_actor.cpp index 1118f45312ae..9013f6483b6f 100644 --- a/ydb/core/kqp/runtime/kqp_write_actor.cpp +++ b/ydb/core/kqp/runtime/kqp_write_actor.cpp @@ -2802,7 +2802,7 @@ class TKqpBufferWriteActor :public TActorBootstrapped, pub void UpdateTracingState(const char* name, NWilson::TTraceId traceId) { BufferWriteActorStateSpan = NWilson::TSpan(TWilsonKqp::BufferWriteActorState, std::move(traceId), name, NWilson::EFlags::AUTO_END); - if (traceId != BufferWriteActorSpan.GetTraceId()) { + if (BufferWriteActorStateSpan.GetTraceId() != BufferWriteActorSpan.GetTraceId()) { BufferWriteActorStateSpan.Link(BufferWriteActorSpan.GetTraceId()); } for (auto& [_, info] : WriteInfos) { diff --git a/ydb/core/kqp/runtime/kqp_write_table.cpp b/ydb/core/kqp/runtime/kqp_write_table.cpp index 36fb6a6eb300..9b4bda13120a 100644 --- a/ydb/core/kqp/runtime/kqp_write_table.cpp +++ b/ydb/core/kqp/runtime/kqp_write_table.cpp @@ -245,7 +245,7 @@ class TRowBatch : public IDataBatch { for (const auto& row : Rows) { AFL_ENSURE(row.size() == Rows.front().size()); const auto size = EstimateSize(row); - SerializedMemory += GetCellHeaderSize() * rows.Size() + size; + SerializedMemory += GetCellHeaderSize() * row.size() + size; Memory += size; } } From 6d04fb7aa078eea0732ee0b1415e8bed3ded5931 Mon Sep 17 00:00:00 2001 From: Semyon Date: Tue, 8 Apr 2025 14:33:38 +0300 Subject: [PATCH 048/454] use binsearch to find predicate bound in portion (#16867) --- ydb/core/formats/arrow/arrow_filter.cpp | 176 ------------------ ydb/core/formats/arrow/arrow_filter.h | 3 - ydb/core/formats/arrow/ut/ut_arrow.cpp | 47 ----- .../engines/predicate/container.cpp | 32 ++++ .../columnshard/engines/predicate/container.h | 10 +- .../columnshard/engines/predicate/filter.cpp | 9 +- .../tx/columnshard/engines/predicate/filter.h | 2 +- .../columnshard/engines/predicate/range.cpp | 4 +- .../tx/columnshard/engines/predicate/range.h | 2 +- .../reader/plain_reader/iterator/fetching.cpp | 7 +- .../simple_reader/iterator/fetching.cpp | 7 +- .../reader/sys_view/abstract/iterator.cpp | 3 +- 12 files changed, 55 insertions(+), 247 deletions(-) diff --git a/ydb/core/formats/arrow/arrow_filter.cpp b/ydb/core/formats/arrow/arrow_filter.cpp index 885899884165..1c4867d86298 100644 --- a/ydb/core/formats/arrow/arrow_filter.cpp +++ b/ydb/core/formats/arrow/arrow_filter.cpp @@ -16,127 +16,6 @@ namespace NKikimr::NArrow { #define Y_VERIFY_OK(status) Y_ABORT_UNLESS(status.ok(), "%s", status.ToString().c_str()) -namespace { -enum class ECompareResult : i8 { - LESS = -1, - BORDER = 0, - GREATER = 1 -}; - -template -inline auto GetValue(const std::shared_ptr& array, int pos) { - return array->GetView(pos); -} - -template -inline void UpdateCompare(const T& value, const T& border, ECompareResult& res) { - if (res == ECompareResult::BORDER) { - if constexpr (std::is_same_v) { - size_t minSize = (value.size() < border.size()) ? value.size() : border.size(); - int cmp = memcmp(value.data(), border.data(), minSize); - if (cmp < 0) { - res = ECompareResult::LESS; - } else if (cmp > 0) { - res = ECompareResult::GREATER; - } else { - UpdateCompare(value.size(), border.size(), res); - } - } else { - if (value < border) { - res = ECompareResult::LESS; - } else if (value > border) { - res = ECompareResult::GREATER; - } - } - } -} - -template -bool CompareImpl(const std::shared_ptr& column, const T& border, std::vector& rowsCmp) { - bool hasBorder = false; - ECompareResult* res = &rowsCmp[0]; - auto array = std::static_pointer_cast(column); - - for (int i = 0; i < array->length(); ++i, ++res) { - UpdateCompare(GetValue(array, i), border, *res); - hasBorder = hasBorder || (*res == ECompareResult::BORDER); - } - return !hasBorder; -} - -template -bool CompareImpl(const std::shared_ptr& column, const T& border, std::vector& rowsCmp) { - bool hasBorder = false; - ECompareResult* res = &rowsCmp[0]; - - for (auto& chunk : column->chunks()) { - auto array = std::static_pointer_cast(chunk); - - for (int i = 0; i < chunk->length(); ++i, ++res) { - UpdateCompare(GetValue(array, i), border, *res); - hasBorder = hasBorder || (*res == ECompareResult::BORDER); - } - } - return !hasBorder; -} - -/// @return true in case we have no borders in compare: no need for future keys, allow early exit -template -bool Compare(const arrow::Datum& column, const std::shared_ptr& borderArray, std::vector& rowsCmp) { - auto border = GetValue(std::static_pointer_cast(borderArray), 0); - - switch (column.kind()) { - case arrow::Datum::ARRAY: - return CompareImpl(column.make_array(), border, rowsCmp); - case arrow::Datum::CHUNKED_ARRAY: - return CompareImpl(column.chunked_array(), border, rowsCmp); - default: - break; - } - Y_ABORT_UNLESS(false); - return false; -} - -bool SwitchCompare(const arrow::Datum& column, const std::shared_ptr& border, std::vector& rowsCmp) { - Y_ABORT_UNLESS(border->length() == 1); - - // first time it's empty - if (rowsCmp.empty()) { - rowsCmp.resize(column.length(), ECompareResult::BORDER); - } - - return SwitchArrayType(column, [&](const auto& type) -> bool { - using TWrap = std::decay_t; - using TArray = typename arrow::TypeTraits::ArrayType; - return Compare(column, border, rowsCmp); - }); -} - -template -void CompositeCompare(std::shared_ptr some, std::shared_ptr borderBatch, std::vector& rowsCmp) { - AFL_VERIFY(some); - AFL_VERIFY(borderBatch); - auto key = borderBatch->schema()->fields(); - AFL_VERIFY(key.size()); - - for (size_t i = 0; i < key.size(); ++i) { - auto& field = key[i]; - auto typeId = field->type()->id(); - auto column = some->GetColumnByName(field->name()); - std::shared_ptr border = borderBatch->GetColumnByName(field->name()); - AFL_VERIFY(column)("schema1", some->schema()->ToString())("schema2", borderBatch->schema()->ToString())("f", field->name()); - AFL_VERIFY(border)("schema1", some->schema()->ToString())("schema2", borderBatch->schema()->ToString())("f", field->name()); - AFL_VERIFY(some->schema()->GetFieldByName(field->name())->type()->id() == typeId)("schema1", some->schema()->ToString())( - "schema2", borderBatch->schema()->ToString())("f", field->name()); - - if (SwitchCompare(column, border, rowsCmp)) { - break; // early exit in case we have all rows compared: no borders, can omit key tail - } - } -} - -} // namespace - TColumnFilter::TSlicesIterator::TSlicesIterator(const TColumnFilter& owner, const std::optional start, const std::optional count) : Owner(owner) , StartIndex(start) @@ -307,61 +186,6 @@ ui32 TColumnFilter::CrossSize(const ui32 s1, const ui32 f1, const ui32 s2, const return f - s; } -NKikimr::NArrow::TColumnFilter TColumnFilter::MakePredicateFilter( - const arrow::Datum& datum, const arrow::Datum& border, ECompareType compareType) { - std::vector cmps; - - switch (datum.kind()) { - case arrow::Datum::ARRAY: - Y_ABORT_UNLESS(border.kind() == arrow::Datum::ARRAY); - SwitchCompare(datum, border.make_array(), cmps); - break; - case arrow::Datum::CHUNKED_ARRAY: - Y_ABORT_UNLESS(border.kind() == arrow::Datum::ARRAY); - SwitchCompare(datum, border.make_array(), cmps); - break; - case arrow::Datum::RECORD_BATCH: - Y_ABORT_UNLESS(border.kind() == arrow::Datum::RECORD_BATCH); - CompositeCompare(datum.record_batch(), border.record_batch(), cmps); - break; - case arrow::Datum::TABLE: - Y_ABORT_UNLESS(border.kind() == arrow::Datum::RECORD_BATCH); - CompositeCompare(datum.table(), border.record_batch(), cmps); - break; - default: - Y_ABORT_UNLESS(false); - break; - } - - std::vector bits; - bits.reserve(cmps.size()); - - switch (compareType) { - case ECompareType::LESS: - for (size_t i = 0; i < cmps.size(); ++i) { - bits.emplace_back(cmps[i] < ECompareResult::BORDER); - } - break; - case ECompareType::LESS_OR_EQUAL: - for (size_t i = 0; i < cmps.size(); ++i) { - bits.emplace_back(cmps[i] <= ECompareResult::BORDER); - } - break; - case ECompareType::GREATER: - for (size_t i = 0; i < cmps.size(); ++i) { - bits.emplace_back(cmps[i] > ECompareResult::BORDER); - } - break; - case ECompareType::GREATER_OR_EQUAL: - for (size_t i = 0; i < cmps.size(); ++i) { - bits.emplace_back(cmps[i] >= ECompareResult::BORDER); - } - break; - } - - return NArrow::TColumnFilter(std::move(bits)); -} - template void ApplyImpl(const TColumnFilter& filter, std::shared_ptr& batch, const TColumnFilter::TApplyContext& context) { if (!batch || !batch->num_rows()) { diff --git a/ydb/core/formats/arrow/arrow_filter.h b/ydb/core/formats/arrow/arrow_filter.h index 8d4b1afad42b..95afc9836084 100644 --- a/ydb/core/formats/arrow/arrow_filter.h +++ b/ydb/core/formats/arrow/arrow_filter.h @@ -266,9 +266,6 @@ class TColumnFilter { TColumnFilter And(const TColumnFilter& extFilter) const Y_WARN_UNUSED_RESULT; TColumnFilter Or(const TColumnFilter& extFilter) const Y_WARN_UNUSED_RESULT; - // It makes a filter using composite predicate - static TColumnFilter MakePredicateFilter(const arrow::Datum& datum, const arrow::Datum& border, ECompareType compareType); - class TApplyContext { private: YDB_READONLY_DEF(std::optional, StartPos); diff --git a/ydb/core/formats/arrow/ut/ut_arrow.cpp b/ydb/core/formats/arrow/ut/ut_arrow.cpp index 6f12504187e9..bc46b4f329f7 100644 --- a/ydb/core/formats/arrow/ut/ut_arrow.cpp +++ b/ydb/core/formats/arrow/ut/ut_arrow.cpp @@ -480,21 +480,6 @@ std::vector TestRows() { return rows; } -bool CheckFilter(const std::vector& f, size_t count, bool value) { - for (size_t i = 0; i < f.size(); ++i) { - if (i < count) { - if (f[i] != value) { - return false; - } - } else { - if (f[i] == value) { - return false; - } - } - } - return true; -} - std::shared_ptr MakeTable1000() { TDataRowTableBuilder builder; @@ -672,38 +657,6 @@ Y_UNIT_TEST_SUITE(ArrowTest) { } } - Y_UNIT_TEST(KeyComparison) { - auto table = MakeTable1000(); - - std::shared_ptr border; // {2, 3, 4} - { - arrow::ScalarVector scalars{ - std::make_shared(2), - std::make_shared(3), - std::make_shared(4), - }; - - std::vector> columns; - for (auto scalar : scalars) { - auto res = arrow::MakeArrayFromScalar(*scalar, 1); - UNIT_ASSERT(res.ok()); - columns.push_back(*res); - } - - border = arrow::RecordBatch::Make(table->schema(), 1, columns); - } - - const NArrow::TColumnFilter lt = NArrow::TColumnFilter::MakePredicateFilter(table, border, NArrow::ECompareType::LESS); - const NArrow::TColumnFilter le = NArrow::TColumnFilter::MakePredicateFilter(table, border, NArrow::ECompareType::LESS_OR_EQUAL); - const NArrow::TColumnFilter gt = NArrow::TColumnFilter::MakePredicateFilter(table, border, NArrow::ECompareType::GREATER); - const NArrow::TColumnFilter ge = NArrow::TColumnFilter::MakePredicateFilter(table, border, NArrow::ECompareType::GREATER_OR_EQUAL); - - UNIT_ASSERT(CheckFilter(lt.BuildSimpleFilter(), 234, true)); - UNIT_ASSERT(CheckFilter(le.BuildSimpleFilter(), 235, true)); - UNIT_ASSERT(CheckFilter(gt.BuildSimpleFilter(), 235, false)); - UNIT_ASSERT(CheckFilter(ge.BuildSimpleFilter(), 234, false)); - } - Y_UNIT_TEST(SortWithCompositeKey) { std::shared_ptr table = Shuffle(MakeTable1000()); diff --git a/ydb/core/tx/columnshard/engines/predicate/container.cpp b/ydb/core/tx/columnshard/engines/predicate/container.cpp index 780a3390befa..0c0cf5baf79c 100644 --- a/ydb/core/tx/columnshard/engines/predicate/container.cpp +++ b/ydb/core/tx/columnshard/engines/predicate/container.cpp @@ -179,4 +179,36 @@ TConclusion TPredicateContainer::BuildPredicateTo( } } +NArrow::TColumnFilter TPredicateContainer::BuildFilter(const std::shared_ptr& data) const { + if (!Object) { + auto result = NArrow::TColumnFilter::BuildAllowFilter(); + result.Add(true, data->GetRecordsCount()); + return result; + } + if (!data->GetRecordsCount()) { + return NArrow::TColumnFilter::BuildAllowFilter(); + } + auto sortingFields = Object->Batch->schema()->field_names(); + auto position = NArrow::NMerger::TRWSortableBatchPosition(data, 0, sortingFields, {}, false); + const auto border = NArrow::NMerger::TSortableBatchPosition(Object->Batch, 0, sortingFields, {}, false); + const bool needUppedBound = CompareType == NArrow::ECompareType::LESS_OR_EQUAL || CompareType == NArrow::ECompareType::GREATER; + const auto findBound = position.FindBound(position, 0, data->GetRecordsCount() - 1, border, needUppedBound); + const ui64 rowsBeforeBound = findBound ? findBound->GetPosition() : data->GetRecordsCount(); + + auto filter = NArrow::TColumnFilter::BuildAllowFilter(); + switch (CompareType) { + case NArrow::ECompareType::LESS: + case NArrow::ECompareType::LESS_OR_EQUAL: + filter.Add(true, rowsBeforeBound); + filter.Add(false, data->GetRecordsCount() - rowsBeforeBound); + break; + case NArrow::ECompareType::GREATER: + case NArrow::ECompareType::GREATER_OR_EQUAL: + filter.Add(false, rowsBeforeBound); + filter.Add(true, data->GetRecordsCount() - rowsBeforeBound); + break; + } + return filter; } + +} // namespace NKikimr::NOlap diff --git a/ydb/core/tx/columnshard/engines/predicate/container.h b/ydb/core/tx/columnshard/engines/predicate/container.h index bb30aebc59a0..78dcb041447a 100644 --- a/ydb/core/tx/columnshard/engines/predicate/container.h +++ b/ydb/core/tx/columnshard/engines/predicate/container.h @@ -1,7 +1,10 @@ #pragma once #include "predicate.h" +#include #include +#include +#include #include #include @@ -115,12 +118,7 @@ class TPredicateContainer { static TConclusion BuildPredicateTo( std::shared_ptr object, const std::shared_ptr& pkSchema); - NKikimr::NArrow::TColumnFilter BuildFilter(const arrow::Datum& data) const { - if (!Object) { - return NArrow::TColumnFilter::BuildAllowFilter(); - } - return NArrow::TColumnFilter::MakePredicateFilter(data, Object->Batch, CompareType); - } + NArrow::TColumnFilter BuildFilter(const std::shared_ptr& data) const; }; } // namespace NKikimr::NOlap diff --git a/ydb/core/tx/columnshard/engines/predicate/filter.cpp b/ydb/core/tx/columnshard/engines/predicate/filter.cpp index 28c47e6c89a4..002988f9aadd 100644 --- a/ydb/core/tx/columnshard/engines/predicate/filter.cpp +++ b/ydb/core/tx/columnshard/engines/predicate/filter.cpp @@ -7,13 +7,14 @@ namespace NKikimr::NOlap { -NKikimr::NArrow::TColumnFilter TPKRangesFilter::BuildFilter(const arrow::Datum& data) const { +NKikimr::NArrow::TColumnFilter TPKRangesFilter::BuildFilter(const std::shared_ptr& data) const { if (SortedRanges.empty()) { return NArrow::TColumnFilter::BuildAllowFilter(); } - NArrow::TColumnFilter result = SortedRanges.front().BuildFilter(data); - for (ui32 i = 1; i < SortedRanges.size(); ++i) { - result = result.Or(SortedRanges[i].BuildFilter(data)); + + auto result = NArrow::TColumnFilter::BuildDenyFilter(); + for (const auto& range : SortedRanges) { + result = result.Or(range.BuildFilter(data)); } return result; } diff --git a/ydb/core/tx/columnshard/engines/predicate/filter.h b/ydb/core/tx/columnshard/engines/predicate/filter.h index 93a52b46a5cd..8de06ab4cfc1 100644 --- a/ydb/core/tx/columnshard/engines/predicate/filter.h +++ b/ydb/core/tx/columnshard/engines/predicate/filter.h @@ -64,7 +64,7 @@ class TPKRangesFilter { TPKRangeFilter::EUsageClass GetUsageClass(const NArrow::TReplaceKey& start, const NArrow::TReplaceKey& end) const; bool CheckPoint(const NArrow::TReplaceKey& point) const; - NArrow::TColumnFilter BuildFilter(const arrow::Datum& data) const; + NArrow::TColumnFilter BuildFilter(const std::shared_ptr& data) const; std::set GetColumnNames() const { std::set result; diff --git a/ydb/core/tx/columnshard/engines/predicate/range.cpp b/ydb/core/tx/columnshard/engines/predicate/range.cpp index b00ed126d279..f7516e32d690 100644 --- a/ydb/core/tx/columnshard/engines/predicate/range.cpp +++ b/ydb/core/tx/columnshard/engines/predicate/range.cpp @@ -34,8 +34,8 @@ std::set TPKRangeFilter::GetColumnNames() const { return result; } -NKikimr::NArrow::TColumnFilter TPKRangeFilter::BuildFilter(const arrow::Datum& data) const { - NArrow::TColumnFilter result = PredicateTo.BuildFilter(data); +NArrow::TColumnFilter TPKRangeFilter::BuildFilter(const std::shared_ptr& data) const { + auto result = PredicateTo.BuildFilter(data); return result.And(PredicateFrom.BuildFilter(data)); } diff --git a/ydb/core/tx/columnshard/engines/predicate/range.h b/ydb/core/tx/columnshard/engines/predicate/range.h index fab63a7b9bca..91e7d58c4a77 100644 --- a/ydb/core/tx/columnshard/engines/predicate/range.h +++ b/ydb/core/tx/columnshard/engines/predicate/range.h @@ -36,7 +36,7 @@ class TPKRangeFilter { static TConclusion Build(TPredicateContainer&& from, TPredicateContainer&& to); - NArrow::TColumnFilter BuildFilter(const arrow::Datum& data) const; + NArrow::TColumnFilter BuildFilter(const std::shared_ptr& data) const; bool IsUsed(const TPortionInfo& info) const; bool CheckPoint(const NArrow::TReplaceKey& point) const; diff --git a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/fetching.cpp b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/fetching.cpp index 3c74c4fd25f3..863605811344 100644 --- a/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/fetching.cpp +++ b/ydb/core/tx/columnshard/engines/reader/plain_reader/iterator/fetching.cpp @@ -14,9 +14,10 @@ namespace NKikimr::NOlap::NReader::NPlain { TConclusion TPredicateFilter::DoExecuteInplace(const std::shared_ptr& source, const TFetchingScriptCursor& /*step*/) const { auto filter = source->GetContext()->GetReadMetadata()->GetPKRangesFilter().BuildFilter( - source->GetStageData().GetTable()->ToTable(source->GetContext()->GetReadMetadata()->GetPKRangesFilter().GetColumnIds( - source->GetContext()->GetReadMetadata()->GetResultSchema()->GetIndexInfo()), - source->GetContext()->GetCommonContext()->GetResolver(), true)); + source->GetStageData().GetTable()->ToGeneralContainer(source->GetContext()->GetCommonContext()->GetResolver(), + source->GetContext()->GetReadMetadata()->GetPKRangesFilter().GetColumnIds( + source->GetContext()->GetReadMetadata()->GetResultSchema()->GetIndexInfo()), + true)); source->MutableStageData().AddFilter(filter); return true; } diff --git a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/fetching.cpp b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/fetching.cpp index fa7d86825f58..9481c3c02665 100644 --- a/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/fetching.cpp +++ b/ydb/core/tx/columnshard/engines/reader/simple_reader/iterator/fetching.cpp @@ -22,9 +22,10 @@ ui64 IFetchingStep::GetProcessingDataSize(const std::shared_ptr TPredicateFilter::DoExecuteInplace(const std::shared_ptr& source, const TFetchingScriptCursor& /*step*/) const { auto filter = source->GetContext()->GetReadMetadata()->GetPKRangesFilter().BuildFilter( - source->GetStageData().GetTable()->ToTable(source->GetContext()->GetReadMetadata()->GetPKRangesFilter().GetColumnIds( - source->GetContext()->GetReadMetadata()->GetResultSchema()->GetIndexInfo()), - source->GetContext()->GetCommonContext()->GetResolver(), true)); + source->GetStageData().GetTable()->ToGeneralContainer(source->GetContext()->GetCommonContext()->GetResolver(), + source->GetContext()->GetReadMetadata()->GetPKRangesFilter().GetColumnIds( + source->GetContext()->GetReadMetadata()->GetResultSchema()->GetIndexInfo()), + true)); source->MutableStageData().AddFilter(filter); return true; } diff --git a/ydb/core/tx/columnshard/engines/reader/sys_view/abstract/iterator.cpp b/ydb/core/tx/columnshard/engines/reader/sys_view/abstract/iterator.cpp index 09d1e7394467..26e1ebdb0950 100644 --- a/ydb/core/tx/columnshard/engines/reader/sys_view/abstract/iterator.cpp +++ b/ydb/core/tx/columnshard/engines/reader/sys_view/abstract/iterator.cpp @@ -44,7 +44,8 @@ TConclusion> TStatsIteratorBase::GetBatch() auto lastKey = keyBatch->Slice(keyBatch->num_rows() - 1, 1); { - NArrow::TColumnFilter filter = ReadMetadata->GetPKRangesFilter().BuildFilter(originalBatch); + NArrow::TColumnFilter filter = + ReadMetadata->GetPKRangesFilter().BuildFilter(std::make_shared(originalBatch)); filter.Apply(originalBatch); } From 0e810efd869af36d7195679b8a08b6a1002e0deb Mon Sep 17 00:00:00 2001 From: Vasily Gerasimov Date: Tue, 8 Apr 2025 14:57:58 +0300 Subject: [PATCH 049/454] Fix INTERNAL_ERROR on not existing resource or coordination node in rate limiter (#16901) --- ydb/core/grpc_services/rpc_rate_limiter_api.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ydb/core/grpc_services/rpc_rate_limiter_api.cpp b/ydb/core/grpc_services/rpc_rate_limiter_api.cpp index 3aeb8271ff64..fe9ad87cfc50 100644 --- a/ydb/core/grpc_services/rpc_rate_limiter_api.cpp +++ b/ydb/core/grpc_services/rpc_rate_limiter_api.cpp @@ -178,7 +178,7 @@ class TRateLimiterControlRequest : public TRateLimiterRequest navigate = std::move(ev->Get()->Request); if (navigate->ResultSet.size() != 1 || navigate->ErrorCount > 0) { - this->Reply(StatusIds::INTERNAL_ERROR, this->ActorContext()); + this->Reply(StatusIds::SCHEME_ERROR, this->ActorContext()); return; } @@ -548,7 +548,7 @@ class TDescribeRateLimiterResourceRPC : public TRateLimiterControlRequestGet()->Record.ResourcesSize() == 0) { - this->Reply(StatusIds::INTERNAL_ERROR, "No resource properties found.", NKikimrIssues::TIssuesIds::DEFAULT_ERROR, this->ActorContext()); + this->Reply(StatusIds::SCHEME_ERROR, "No resource properties found.", NKikimrIssues::TIssuesIds::DEFAULT_ERROR, this->ActorContext()); return; } CopyProps(ev->Get()->Record.GetResources(0), *result.mutable_resource()); From ab7a125e8c550f4132c8367953aca05054f61114 Mon Sep 17 00:00:00 2001 From: Alek5andr-Kotov Date: Tue, 8 Apr 2025 15:10:28 +0300 Subject: [PATCH 050/454] The message field is not used (#16910) --- ydb/core/persqueue/events/internal.h | 6 ++---- ydb/core/persqueue/partition_read.cpp | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/ydb/core/persqueue/events/internal.h b/ydb/core/persqueue/events/internal.h index 176b12f48e66..e72cbd8e1e47 100644 --- a/ydb/core/persqueue/events/internal.h +++ b/ydb/core/persqueue/events/internal.h @@ -492,15 +492,13 @@ struct TEvPQ { }; struct TEvBlobRequest : public TEventLocal { - TEvBlobRequest(const TString& user, const ui64 cookie, const NPQ::TPartitionId& partition, + TEvBlobRequest(const ui64 cookie, const NPQ::TPartitionId& partition, TVector&& blobs) - : User(user) - , Cookie(cookie) + : Cookie(cookie) , Partition(partition) , Blobs(std::move(blobs)) {} - TString User; ui64 Cookie; NPQ::TPartitionId Partition; TVector Blobs; diff --git a/ydb/core/persqueue/partition_read.cpp b/ydb/core/persqueue/partition_read.cpp index faf618176a82..767d08a3c2f9 100644 --- a/ydb/core/persqueue/partition_read.cpp +++ b/ydb/core/persqueue/partition_read.cpp @@ -1065,13 +1065,12 @@ void TPartition::ProcessRead(const TActorContext& ctx, TReadInfo&& info, const u return; } - const TString user = info.User; bool res = ReadInfo.emplace(cookie, std::move(info)).second; PQ_LOG_D("Reading cookie " << cookie << ". Send blob request."); Y_ABORT_UNLESS(res); - THolder request(new TEvPQ::TEvBlobRequest(user, cookie, Partition, - std::move(blobs))); + auto request = MakeHolder(cookie, Partition, + std::move(blobs)); ctx.Send(BlobCache, request.Release()); } From 75d743d97bd309e976e013b80fbeda5d99696bd3 Mon Sep 17 00:00:00 2001 From: hiddenpath Date: Tue, 8 Apr 2025 15:34:49 +0300 Subject: [PATCH 051/454] Add EnableRpcProxyInJobProxy option to TUserJobSpec commit_hash:066f704ba92da58c63ac8af6f9032f6c2672a9be --- yt/cpp/mapreduce/client/operation.cpp | 1 + yt/cpp/mapreduce/interface/operation.h | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/yt/cpp/mapreduce/client/operation.cpp b/yt/cpp/mapreduce/client/operation.cpp index 553b1a077769..a885657fb57e 100644 --- a/yt/cpp/mapreduce/client/operation.cpp +++ b/yt/cpp/mapreduce/client/operation.cpp @@ -782,6 +782,7 @@ void BuildUserJobFluently( }) .EndList() .Item("start_queue_consumer_registration_manager").Value(false) + .Item("enable_rpc_proxy_in_job_proxy").Value(userJobSpec.EnableRpcProxyInJobProxy_) .Item("redirect_stdout_to_stderr").Value(preparer.ShouldRedirectStdoutToStderr()); } diff --git a/yt/cpp/mapreduce/interface/operation.h b/yt/cpp/mapreduce/interface/operation.h index 50c694b5b066..1f327b4b5d64 100644 --- a/yt/cpp/mapreduce/interface/operation.h +++ b/yt/cpp/mapreduce/interface/operation.h @@ -891,6 +891,15 @@ struct TUserJobSpec /// @see https://ytsaurus.tech/docs/en/user-guide/data-processing/operations/operations-options#disk_request FLUENT_FIELD_OPTION(TDiskRequest, DiskRequest); + /// + /// @brief Activates the RPC proxy within the job proxy. + /// + /// By enabling this option, the environment variable YT_JOB_PROXY_SOCKET_PATH will be set. + /// You can use this variable to obtain the unix domain socket path and then construct a client for sending requests. + /// + /// @note Do not enable this option without prior discussion with the YTsaurus team. + FLUENT_FIELD_DEFAULT(bool, EnableRpcProxyInJobProxy, false); + private: TVector> LocalFiles_; TJobBinaryConfig JobBinary_; From 7077d90968fe79dfe126e92543d669259f02ef3a Mon Sep 17 00:00:00 2001 From: ziganshinmr Date: Tue, 8 Apr 2025 16:03:51 +0300 Subject: [PATCH 052/454] Fix keeping aggregate columns in case of distinct aggregation over window commit_hash:6aa8a8297542455d107d7debbfaac3f30f48d885 --- yql/essentials/sql/v1/aggregation.cpp | 22 +++++++++---------- .../sql/minirun/part0/canondata/result.json | 14 ++++++++++++ .../tests/sql/sql2yql/canondata/result.json | 12 ++++++++++ .../formatted.sql | 19 ++++++++++++++++ .../tests/sql/suites/window/yql-19801.sql | 18 +++++++++++++++ 5 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_window-yql-19801_/formatted.sql create mode 100644 yql/essentials/tests/sql/suites/window/yql-19801.sql diff --git a/yql/essentials/sql/v1/aggregation.cpp b/yql/essentials/sql/v1/aggregation.cpp index 875ae7d97d67..3d19862f865b 100644 --- a/yql/essentials/sql/v1/aggregation.cpp +++ b/yql/essentials/sql/v1/aggregation.cpp @@ -52,7 +52,7 @@ class TAggregationFactory : public IAggregation { BuildBind(Pos, aggMode == EAggregateMode::OverWindow || aggMode == EAggregateMode::OverWindowDistinct ? "window_module" : "aggregate_module", func) : nullptr), Multi(multi), ValidateArgs(validateArgs), DynamicFactory(!Factory) { - if (aggMode != EAggregateMode::OverWindow && !func.empty() && AggApplyFuncs.contains(func)) { + if (aggMode != EAggregateMode::OverWindow && aggMode != EAggregateMode::OverWindowDistinct && !func.empty() && AggApplyFuncs.contains(func)) { AggApplyName = func.substr(0, func.size() - 15); } @@ -112,7 +112,7 @@ class TAggregationFactory : public IAggregation { if (!isFactory) { node.Add("Member", "row", Q(Name)); - if (IsOverWindow()) { + if (IsOverWindow() || IsOverWindowDistinct()) { src->AddTmpWindowColumn(Name); } } @@ -156,7 +156,7 @@ class TAggregationFactory : public IAggregation { if (!x->Init(ctx, src)) { return false; } - if (x->IsAggregated() && !x->IsAggregationKey() && !IsOverWindow()) { + if (x->IsAggregated() && !x->IsAggregationKey() && !IsOverWindow() && !IsOverWindowDistinct()) { ctx.Error(Pos) << "Aggregation of aggregated values is forbidden"; return false; } @@ -172,7 +172,7 @@ class TAggregationFactory : public IAggregation { if (!Expr->Init(ctx, src)) { return false; } - if (Expr->IsAggregated() && !Expr->IsAggregationKey() && !IsOverWindow()) { + if (Expr->IsAggregated() && !Expr->IsAggregationKey() && !IsOverWindow() && !IsOverWindowDistinct()) { ctx.Error(Pos) << "Aggregation of aggregated values is forbidden"; return false; } @@ -292,7 +292,7 @@ class TKeyPayloadAggregationFactory final : public TAggregationFactory { if (!isFactory) { node.Add("Member", "row", Q(Name)); - if (IsOverWindow()) { + if (IsOverWindow() || IsOverWindowDistinct()) { src->AddTmpWindowColumn(Name); } } @@ -393,7 +393,7 @@ class TPayloadPredicateAggregationFactory final : public TAggregationFactory { if (!isFactory) { node.Add("Member", "row", Q(Name)); - if (IsOverWindow()) { + if (IsOverWindow() || IsOverWindowDistinct()) { src->AddTmpWindowColumn(Name); } } @@ -480,7 +480,7 @@ class TTwoArgsAggregationFactory final : public TAggregationFactory { if (!isFactory) { node.Add("Member", "row", Q(Name)); - if (IsOverWindow()) { + if (IsOverWindow() || IsOverWindowDistinct()) { src->AddTmpWindowColumn(Name); } } @@ -516,7 +516,7 @@ class TTwoArgsAggregationFactory final : public TAggregationFactory { return false; } - if ((One->IsAggregated() || Two->IsAggregated()) && !IsOverWindow()) { + if ((One->IsAggregated() || Two->IsAggregated()) && !IsOverWindow() && !IsOverWindowDistinct()) { ctx.Error(Pos) << "Aggregation of aggregated values is forbidden"; return false; } @@ -1014,7 +1014,7 @@ class TTopAggregationFactory final : public TAggregationFactory { if (!isFactory) { node.Add("Member", "row", Q(Name)); - if (IsOverWindow()) { + if (IsOverWindow() || IsOverWindowDistinct()) { src->AddTmpWindowColumn(Name); } } @@ -1130,7 +1130,7 @@ class TCountDistinctEstimateAggregationFactory final : public TAggregationFactor if (!isFactory) { node.Add("Member", "row", Q(Name)); - if (IsOverWindow()) { + if (IsOverWindow() || IsOverWindowDistinct()) { src->AddTmpWindowColumn(Name); } } @@ -1205,7 +1205,7 @@ class TListAggregationFactory final : public TAggregationFactory { if (!isFactory) { node.Add("Member", "row", Q(Name)); - if (IsOverWindow()) { + if (IsOverWindow() || IsOverWindowDistinct()) { src->AddTmpWindowColumn(Name); } } diff --git a/yql/essentials/tests/sql/minirun/part0/canondata/result.json b/yql/essentials/tests/sql/minirun/part0/canondata/result.json index 1ff158d38e33..52d9fa7481be 100644 --- a/yql/essentials/tests/sql/minirun/part0/canondata/result.json +++ b/yql/essentials/tests/sql/minirun/part0/canondata/result.json @@ -1477,5 +1477,19 @@ "size": 1452, "uri": "https://{canondata_backend}/1777230/9825a8684763af6f5aebf2f2145914be57ea6969/resource.tar.gz#test.test_window-yql-14179-default.txt-Results_/results.txt" } + ], + "test.test[window-yql-19801-default.txt-Debug]": [ + { + "checksum": "411035e2598db68705427ac77743c32a", + "size": 1396, + "uri": "https://{canondata_backend}/1920236/7066f75808999d7c9bd16ab40270eb0f41ecd22c/resource.tar.gz#test.test_window-yql-19801-default.txt-Debug_/opt.yql" + } + ], + "test.test[window-yql-19801-default.txt-Results]": [ + { + "checksum": "83fd4e361203ed32edf38dbc8ea21995", + "size": 3559, + "uri": "https://{canondata_backend}/1920236/7066f75808999d7c9bd16ab40270eb0f41ecd22c/resource.tar.gz#test.test_window-yql-19801-default.txt-Results_/results.txt" + } ] } diff --git a/yql/essentials/tests/sql/sql2yql/canondata/result.json b/yql/essentials/tests/sql/sql2yql/canondata/result.json index bd605930b7f9..400932a82b8f 100644 --- a/yql/essentials/tests/sql/sql2yql/canondata/result.json +++ b/yql/essentials/tests/sql/sql2yql/canondata/result.json @@ -7412,6 +7412,13 @@ "uri": "https://{canondata_backend}/1847551/ee61b63f66a264ad4afe7437ef7f90941caf4456/resource.tar.gz#test_sql2yql.test_window-yql-19709_/sql.yql" } ], + "test_sql2yql.test[window-yql-19801]": [ + { + "checksum": "35e09384575075270c999c01e90779ac", + "size": 2644, + "uri": "https://{canondata_backend}/1130705/f4f303dd683b2715fca90fc1337a2858da6e1467/resource.tar.gz#test_sql2yql.test_window-yql-19801_/sql.yql" + } + ], "test_sql_format.test[action-action_opt_args]": [ { "uri": "file://test_sql_format.test_action-action_opt_args_/formatted.sql" @@ -11252,6 +11259,11 @@ "uri": "file://test_sql_format.test_window-yql-19709_/formatted.sql" } ], + "test_sql_format.test[window-yql-19801]": [ + { + "uri": "file://test_sql_format.test_window-yql-19801_/formatted.sql" + } + ], "test_sql_negative.test[action-no_columns_in_do-default.txt]": [ { "checksum": "0fad6da8e4c5a2ab2c1e5a231ea430d1", diff --git a/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_window-yql-19801_/formatted.sql b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_window-yql-19801_/formatted.sql new file mode 100644 index 000000000000..e4bbbc38c8c3 --- /dev/null +++ b/yql/essentials/tests/sql/sql2yql/canondata/test_sql_format.test_window-yql-19801_/formatted.sql @@ -0,0 +1,19 @@ +/* syntax version 1 */ +/* postgres can not */ +PRAGMA DistinctOverWindow; + +$input = AsList( + AsStruct(1 AS key, 1001 AS subkey, 'AAA' AS value), + AsStruct(150 AS key, 150 AS subkey, 'AAB' AS value), + AsStruct(3 AS key, 3003 AS subkey, 'AAC' AS value), + AsStruct(150 AS key, 150 AS subkey, 'AAD' AS value), + AsStruct(5 AS key, 5005 AS subkey, 'AAE' AS value), +); + +SELECT + i.*, + count(DISTINCT key) OVER () AS cnt, + AggregateList(DISTINCT key) OVER () AS agg_list, +FROM + AS_TABLE($input) AS i +; diff --git a/yql/essentials/tests/sql/suites/window/yql-19801.sql b/yql/essentials/tests/sql/suites/window/yql-19801.sql new file mode 100644 index 000000000000..478c261c984e --- /dev/null +++ b/yql/essentials/tests/sql/suites/window/yql-19801.sql @@ -0,0 +1,18 @@ +/* syntax version 1 */ +/* postgres can not */ + +PRAGMA DistinctOverWindow; + +$input = AsList( + AsStruct(1 AS key, 1001 AS subkey, "AAA" AS value), + AsStruct(150 AS key, 150 AS subkey, "AAB" AS value), + AsStruct(3 AS key, 3003 AS subkey, "AAC" AS value), + AsStruct(150 AS key, 150 AS subkey, "AAD" AS value), + AsStruct(5 AS key, 5005 AS subkey, "AAE" AS value), +); + +SELECT + i.*, + count(DISTINCT key) OVER () AS cnt, + AggregateList(DISTINCT key) OVER () AS agg_list, +FROM AS_TABLE($input) AS i; From 2f90258cf6f1625ba0c99f6f37b6c9f336590534 Mon Sep 17 00:00:00 2001 From: vityaman Date: Tue, 8 Apr 2025 16:11:56 +0300 Subject: [PATCH 053/454] YQL-19747 Complete after PRAGMA and multi-token names - [x] Complete after PRAGMA - [x] Complete multi-token names correctly, for example, `yt.` returns only `DisableStrict`, not `yt.DisableStrict` and `DateTime::` returns `Split`, not `DateTime::Split`. I tried to implement it using `CompletedToken` edition, but not all completion environments support candidates with various `contextLen` (`Replxx` does not). So I decided that completions should rewrite only the current token, not sequences. For example, on `DateTime::Spl` rewrite only `Spl`. It makes sense as multi-token names have some namespace separated by a punctuation, so used types only namespace and gets names inside of it. --- Pull Request resolved: https://github.com/ytsaurus/ytsaurus/pull/1181 commit_hash:9d8967ac43b9348f6dbb53837d92a9dcc9b51f48 --- .../sql/v1/complete/name/name_service.h | 20 +++- .../sql/v1/complete/name/static/frequency.cpp | 8 +- .../sql/v1/complete/name/static/frequency.h | 1 + .../v1/complete/name/static/json_name_set.cpp | 5 + .../v1/complete/name/static/name_service.cpp | 49 ++++++++- .../v1/complete/name/static/name_service.h | 1 + .../sql/v1/complete/name/static/ranking.cpp | 6 + .../sql/v1/complete/name/static/ya.make | 1 + .../sql/v1/complete/sql_complete.cpp | 26 ++++- yql/essentials/sql/v1/complete/sql_complete.h | 1 + .../sql/v1/complete/sql_complete_ut.cpp | 104 ++++++++++++++++-- .../sql/v1/complete/syntax/local.cpp | 67 ++++++++++- yql/essentials/sql/v1/complete/syntax/local.h | 11 +- .../v1/complete/syntax/parser_call_stack.cpp | 14 ++- .../v1/complete/syntax/parser_call_stack.h | 2 + 15 files changed, 286 insertions(+), 30 deletions(-) diff --git a/yql/essentials/sql/v1/complete/name/name_service.h b/yql/essentials/sql/v1/complete/name/name_service.h index d3cf153341ea..6a7e38dfc208 100644 --- a/yql/essentials/sql/v1/complete/name/name_service.h +++ b/yql/essentials/sql/v1/complete/name/name_service.h @@ -13,28 +13,40 @@ namespace NSQLComplete { TString Indentifier; }; + struct TNamespaced { + TString Namespace; + }; + + struct TPragmaName: TIndentifier { + struct TConstraints: TNamespaced {}; + }; + struct TTypeName: TIndentifier { using TConstraints = std::monostate; }; struct TFunctionName: TIndentifier { - using TConstraints = std::monostate; + struct TConstraints: TNamespaced {}; }; using TGenericName = std::variant< + TPragmaName, TTypeName, TFunctionName>; struct TNameRequest { struct { - std::optional TypeName; - std::optional Function; + std::optional Pragma; + std::optional Type; + std::optional Function; } Constraints; TString Prefix = ""; size_t Limit = 128; bool IsEmpty() const { - return !Constraints.TypeName && !Constraints.Function; + return !Constraints.Pragma && + !Constraints.Type && + !Constraints.Function; } }; diff --git a/yql/essentials/sql/v1/complete/name/static/frequency.cpp b/yql/essentials/sql/v1/complete/name/static/frequency.cpp index d9c8ba9652ca..2de082e287ec 100644 --- a/yql/essentials/sql/v1/complete/name/static/frequency.cpp +++ b/yql/essentials/sql/v1/complete/name/static/frequency.cpp @@ -14,6 +14,7 @@ namespace NSQLComplete { const char* Sum = "sum"; } Key; struct { + const char* Pragma = "PRAGMA"; const char* Type = "TYPE"; const char* Func = "FUNC"; const char* Module = "MODULE"; @@ -53,14 +54,17 @@ namespace NSQLComplete { TFrequencyData Convert(TVector items) { TFrequencyData data; for (auto& item : items) { - if (item.Parent == Json.Parent.Type || + if (item.Parent == Json.Parent.Pragma || + item.Parent == Json.Parent.Type || item.Parent == Json.Parent.Func || item.Parent == Json.Parent.ModuleFunc || item.Parent == Json.Parent.Module) { item.Rule = ToLowerUTF8(item.Rule); } - if (item.Parent == Json.Parent.Type) { + if (item.Parent == Json.Parent.Pragma) { + data.Pragmas[item.Rule] += item.Sum; + } else if (item.Parent == Json.Parent.Type) { data.Types[item.Rule] += item.Sum; } else if (item.Parent == Json.Parent.Func || item.Parent == Json.Parent.ModuleFunc) { diff --git a/yql/essentials/sql/v1/complete/name/static/frequency.h b/yql/essentials/sql/v1/complete/name/static/frequency.h index 3d128f824b4e..067453bc4044 100644 --- a/yql/essentials/sql/v1/complete/name/static/frequency.h +++ b/yql/essentials/sql/v1/complete/name/static/frequency.h @@ -6,6 +6,7 @@ namespace NSQLComplete { struct TFrequencyData { + THashMap Pragmas; THashMap Types; THashMap Functions; }; diff --git a/yql/essentials/sql/v1/complete/name/static/json_name_set.cpp b/yql/essentials/sql/v1/complete/name/static/json_name_set.cpp index 29c303b3102c..9fdf314fee61 100644 --- a/yql/essentials/sql/v1/complete/name/static/json_name_set.cpp +++ b/yql/essentials/sql/v1/complete/name/static/json_name_set.cpp @@ -26,6 +26,10 @@ namespace NSQLComplete { return keys; } + TVector ParsePragmas(NJson::TJsonValue json) { + return ParseNames(json.GetArraySafe()); + } + TVector ParseTypes(NJson::TJsonValue json) { return ParseNames(json.GetArraySafe()); } @@ -48,6 +52,7 @@ namespace NSQLComplete { NameSet MakeDefaultNameSet() { return { + .Pragmas = ParsePragmas(LoadJsonResource("pragmas_opensource.json")), .Types = ParseTypes(LoadJsonResource("types.json")), .Functions = Merge( ParseFunctions(LoadJsonResource("sql_functions.json")), diff --git a/yql/essentials/sql/v1/complete/name/static/name_service.cpp b/yql/essentials/sql/v1/complete/name/static/name_service.cpp index fdb1dd4eae10..427691985793 100644 --- a/yql/essentials/sql/v1/complete/name/static/name_service.cpp +++ b/yql/essentials/sql/v1/complete/name/static/name_service.cpp @@ -35,12 +35,43 @@ namespace NSQLComplete { } } + TString Prefixed(const TStringBuf requestPrefix, const TStringBuf delimeter, const TNamespaced& namespaced) { + TString prefix; + if (!namespaced.Namespace.empty()) { + prefix += namespaced.Namespace; + prefix += delimeter; + } + prefix += requestPrefix; + return prefix; + } + + void FixPrefix(TString& name, const TStringBuf delimeter, const TNamespaced& namespaced) { + if (namespaced.Namespace.empty()) { + return; + } + name.remove(0, namespaced.Namespace.size() + delimeter.size()); + } + + void FixPrefix(TGenericName& name, const TNameRequest& request) { + std::visit([&](auto& name) -> size_t { + using T = std::decay_t; + if constexpr (std::is_same_v) { + FixPrefix(name.Indentifier, ".", *request.Constraints.Pragma); + } + if constexpr (std::is_same_v) { + FixPrefix(name.Indentifier, "::", *request.Constraints.Function); + } + return 0; + }, name); + } + class TStaticNameService: public INameService { public: explicit TStaticNameService(NameSet names, IRanking::TPtr ranking) : NameSet_(std::move(names)) , Ranking_(std::move(ranking)) { + Sort(NameSet_.Pragmas, NoCaseCompare); Sort(NameSet_.Types, NoCaseCompare); Sort(NameSet_.Functions, NoCaseCompare); } @@ -48,20 +79,30 @@ namespace NSQLComplete { TFuture Lookup(TNameRequest request) override { TNameResponse response; - if (request.Constraints.TypeName) { + if (request.Constraints.Pragma) { + auto prefix = Prefixed(request.Prefix, ".", *request.Constraints.Pragma); + auto names = FilteredByPrefix(prefix, NameSet_.Pragmas); + AppendAs(response.RankedNames, names); + } + + if (request.Constraints.Type) { AppendAs( response.RankedNames, FilteredByPrefix(request.Prefix, NameSet_.Types)); } if (request.Constraints.Function) { - AppendAs( - response.RankedNames, - FilteredByPrefix(request.Prefix, NameSet_.Functions)); + auto prefix = Prefixed(request.Prefix, "::", *request.Constraints.Function); + auto names = FilteredByPrefix(prefix, NameSet_.Functions); + AppendAs(response.RankedNames, names); } Ranking_->CropToSortedPrefix(response.RankedNames, request.Limit); + for (auto& name : response.RankedNames) { + FixPrefix(name, request); + } + return NThreading::MakeFuture(std::move(response)); } diff --git a/yql/essentials/sql/v1/complete/name/static/name_service.h b/yql/essentials/sql/v1/complete/name/static/name_service.h index a5c90465c83f..348d6ece454b 100644 --- a/yql/essentials/sql/v1/complete/name/static/name_service.h +++ b/yql/essentials/sql/v1/complete/name/static/name_service.h @@ -7,6 +7,7 @@ namespace NSQLComplete { struct NameSet { + TVector Pragmas; TVector Types; TVector Functions; }; diff --git a/yql/essentials/sql/v1/complete/name/static/ranking.cpp b/yql/essentials/sql/v1/complete/name/static/ranking.cpp index 45e6e2b2fa2f..b3d5c3c8c31a 100644 --- a/yql/essentials/sql/v1/complete/name/static/ranking.cpp +++ b/yql/essentials/sql/v1/complete/name/static/ranking.cpp @@ -59,6 +59,12 @@ namespace NSQLComplete { auto identifier = ToLowerUTF8(ContentView(name)); + if constexpr (std::is_same_v) { + if (auto weight = Frequency_.Pragmas.FindPtr(identifier)) { + return *weight; + } + } + if constexpr (std::is_same_v) { if (auto weight = Frequency_.Functions.FindPtr(identifier)) { return *weight; diff --git a/yql/essentials/sql/v1/complete/name/static/ya.make b/yql/essentials/sql/v1/complete/name/static/ya.make index 639371447af0..3c6547f3b526 100644 --- a/yql/essentials/sql/v1/complete/name/static/ya.make +++ b/yql/essentials/sql/v1/complete/name/static/ya.make @@ -13,6 +13,7 @@ PEERDIR( ) RESOURCE( + yql/essentials/data/language/pragmas_opensource.json pragmas_opensource.json yql/essentials/data/language/types.json types.json yql/essentials/data/language/sql_functions.json sql_functions.json yql/essentials/data/language/udfs_basic.json udfs_basic.json diff --git a/yql/essentials/sql/v1/complete/sql_complete.cpp b/yql/essentials/sql/v1/complete/sql_complete.cpp index ed3afa29df4a..85fcf87afd17 100644 --- a/yql/essentials/sql/v1/complete/sql_complete.cpp +++ b/yql/essentials/sql/v1/complete/sql_complete.cpp @@ -35,10 +35,10 @@ namespace NSQLComplete { << " for input size " << input.Text.size(); } - auto prefix = input.Text.Head(input.CursorPosition); - auto completedToken = GetCompletedToken(prefix); + TLocalSyntaxContext context = SyntaxAnalysis->Analyze(input); - auto context = SyntaxAnalysis->Analyze(input); + TStringBuf prefix = input.Text.Head(input.CursorPosition); + TCompletedToken completedToken = GetCompletedToken(prefix); TVector candidates; EnrichWithKeywords(candidates, std::move(context.Keywords), completedToken); @@ -85,12 +85,20 @@ namespace NSQLComplete { .Limit = Configuration.Limit - candidates.size(), }; + if (context.Pragma) { + TPragmaName::TConstraints constraints; + constraints.Namespace = context.Pragma->Namespace; + request.Constraints.Pragma = std::move(constraints); + } + if (context.IsTypeName) { - request.Constraints.TypeName = TTypeName::TConstraints(); + request.Constraints.Type = TTypeName::TConstraints(); } - if (context.IsFunctionName) { - request.Constraints.Function = TFunctionName::TConstraints(); + if (context.Function) { + TFunctionName::TConstraints constraints; + constraints.Namespace = context.Function->Namespace; + request.Constraints.Function = std::move(constraints); } if (request.IsEmpty()) { @@ -107,6 +115,9 @@ namespace NSQLComplete { for (auto& name : names) { candidates.emplace_back(std::visit([](auto&& name) -> TCandidate { using T = std::decay_t; + if constexpr (std::is_base_of_v) { + return {ECandidateKind::PragmaName, std::move(name.Indentifier)}; + } if constexpr (std::is_base_of_v) { return {ECandidateKind::TypeName, std::move(name.Indentifier)}; } @@ -162,6 +173,9 @@ void Out(IOutputStream& out, NSQLComplete::ECandid case NSQLComplete::ECandidateKind::Keyword: out << "Keyword"; break; + case NSQLComplete::ECandidateKind::PragmaName: + out << "PragmaName"; + break; case NSQLComplete::ECandidateKind::TypeName: out << "TypeName"; break; diff --git a/yql/essentials/sql/v1/complete/sql_complete.h b/yql/essentials/sql/v1/complete/sql_complete.h index b8a970efd8fb..5d0271b4dca7 100644 --- a/yql/essentials/sql/v1/complete/sql_complete.h +++ b/yql/essentials/sql/v1/complete/sql_complete.h @@ -20,6 +20,7 @@ namespace NSQLComplete { enum class ECandidateKind { Keyword, + PragmaName, TypeName, FunctionName, }; diff --git a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp index e9f5dbdfb736..7d595842afb8 100644 --- a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp +++ b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp @@ -39,6 +39,7 @@ class TSilentNameService: public INameService { Y_UNIT_TEST_SUITE(SqlCompleteTests) { using ECandidateKind::FunctionName; using ECandidateKind::Keyword; + using ECandidateKind::PragmaName; using ECandidateKind::TypeName; TLexerSupplier MakePureLexerSupplier() { @@ -55,8 +56,9 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { ISqlCompletionEngine::TPtr MakeSqlCompletionEngineUT() { TLexerSupplier lexer = MakePureLexerSupplier(); NameSet names = { + .Pragmas = {"yson.CastToString"}, .Types = {"Uint64"}, - .Functions = {"StartsWith"}, + .Functions = {"StartsWith", "DateTime::Split"}, }; auto ranking = MakeDefaultRanking({}); INameService::TPtr service = MakeStaticNameService(std::move(names), std::move(ranking)); @@ -267,12 +269,36 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { } Y_UNIT_TEST(Pragma) { - TVector expected = { - {Keyword, "ANSI"}, - }; - auto engine = MakeSqlCompletionEngineUT(); - UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"PRAGMA "}), expected); + { + TVector expected = { + {Keyword, "ANSI"}, + {PragmaName, "yson.CastToString"}}; + auto completion = engine->Complete({"PRAGMA "}); + UNIT_ASSERT_VALUES_EQUAL(completion.Candidates, expected); + UNIT_ASSERT_VALUES_EQUAL(completion.CompletedToken.Content, ""); + } + { + TVector expected = { + {PragmaName, "yson.CastToString"}}; + auto completion = engine->Complete({"PRAGMA yson"}); + UNIT_ASSERT_VALUES_EQUAL(completion.Candidates, expected); + UNIT_ASSERT_VALUES_EQUAL(completion.CompletedToken.Content, "yson"); + } + { + TVector expected = { + {PragmaName, "CastToString"}}; + auto completion = engine->Complete({"PRAGMA yson."}); + UNIT_ASSERT_VALUES_EQUAL(completion.Candidates, expected); + UNIT_ASSERT_VALUES_EQUAL(completion.CompletedToken.Content, ""); + } + { + TVector expected = { + {PragmaName, "CastToString"}}; + auto completion = engine->Complete({"PRAGMA yson.cast"}); + UNIT_ASSERT_VALUES_EQUAL(completion.Candidates, expected); + UNIT_ASSERT_VALUES_EQUAL(completion.CompletedToken.Content, "cast"); + } } Y_UNIT_TEST(Select) { @@ -307,6 +333,7 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { {Keyword, "TRUE"}, {Keyword, "TUPLE"}, {Keyword, "VARIANT"}, + {FunctionName, "DateTime::Split("}, {FunctionName, "StartsWith("}, }; @@ -344,6 +371,7 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { {Keyword, "TRUE"}, {Keyword, "TUPLE"}, {Keyword, "VARIANT"}, + {FunctionName, "DateTime::Split("}, {FunctionName, "StartsWith("}, }; @@ -402,6 +430,41 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { } } + Y_UNIT_TEST(FunctionName) { + auto engine = MakeSqlCompletionEngineUT(); + { + TVector expected = { + {FunctionName, "DateTime::Split("}, + }; + auto completion = engine->Complete({"SELECT Date"}); + UNIT_ASSERT_VALUES_EQUAL(completion.Candidates, expected); + UNIT_ASSERT_VALUES_EQUAL(completion.CompletedToken.Content, "Date"); + } + { + TVector expected = { + {FunctionName, "Split("}, + }; + auto completion = engine->Complete({"SELECT DateTime:"}); + UNIT_ASSERT(completion.Candidates.empty()); + } + { + TVector expected = { + {FunctionName, "Split("}, + }; + auto completion = engine->Complete({"SELECT DateTime::"}); + UNIT_ASSERT_VALUES_EQUAL(completion.Candidates, expected); + UNIT_ASSERT_VALUES_EQUAL(completion.CompletedToken.Content, ""); + } + { + TVector expected = { + {FunctionName, "Split("}, + }; + auto completion = engine->Complete({"SELECT DateTime::s"}); + UNIT_ASSERT_VALUES_EQUAL(completion.Candidates, expected); + UNIT_ASSERT_VALUES_EQUAL(completion.CompletedToken.Content, "s"); + } + } + Y_UNIT_TEST(UTF8Wide) { auto engine = MakeSqlCompletionEngineUT(); UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"\xF0\x9F\x98\x8A"}).size(), 0); @@ -410,9 +473,9 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { Y_UNIT_TEST(WordBreak) { auto engine = MakeSqlCompletionEngineUT(); - UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT ("}).size(), 29); - UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT (1)"}).size(), 30); - UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT 1;"}).size(), 35); + UNIT_ASSERT_GE(Complete(engine, {"SELECT ("}).size(), 29); + UNIT_ASSERT_GE(Complete(engine, {"SELECT (1)"}).size(), 30); + UNIT_ASSERT_GE(Complete(engine, {"SELECT 1;"}).size(), 35); } Y_UNIT_TEST(Typing) { @@ -481,6 +544,16 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { }; UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT OPTIONAL expected = { + {PragmaName, "yson.DisableStrict"}, + {PragmaName, "yson.AutoConvert"}, + {PragmaName, "yson.Strict"}, + {PragmaName, "yson.CastToString"}, + {PragmaName, "yson.DisableCastToString"}, + }; + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"PRAGMA yson"}), expected); + } } Y_UNIT_TEST(OnFailingNameService) { @@ -516,6 +589,10 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { Y_UNIT_TEST(Ranking) { TFrequencyData frequency = { + .Pragmas = { + {"yt.defaultmemorylimit", 16}, + {"yt.annotations", 8}, + }, .Types = { {"int32", 128}, {"int64", 64}, @@ -532,6 +609,15 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { }; auto service = MakeStaticNameService(MakeDefaultNameSet(), MakeDefaultRanking(frequency)); auto engine = MakeSqlCompletionEngine(MakePureLexerSupplier(), std::move(service)); + { + TVector expectedPrefix = { + {PragmaName, "DefaultMemoryLimit"}, + {PragmaName, "Annotations"}, + }; + auto actualPrefix = Complete(engine, {"PRAGMA yt."}); + actualPrefix.crop(expectedPrefix.size()); + UNIT_ASSERT_VALUES_EQUAL(actualPrefix, expectedPrefix); + } { TVector expected = { {TypeName, "Int32"}, diff --git a/yql/essentials/sql/v1/complete/syntax/local.cpp b/yql/essentials/sql/v1/complete/syntax/local.cpp index cac43e5a3207..28ace474f8e4 100644 --- a/yql/essentials/sql/v1/complete/syntax/local.cpp +++ b/yql/essentials/sql/v1/complete/syntax/local.cpp @@ -53,10 +53,14 @@ namespace NSQLComplete { } auto candidates = C3.Complete(prefix); + + NSQLTranslation::TParsedTokenList tokens = Tokenized(prefix); + return { .Keywords = SiftedKeywords(candidates), + .Pragma = PragmaMatch(tokens, candidates), .IsTypeName = IsTypeNameMatched(candidates), - .IsFunctionName = IsFunctionNameMatched(candidates), + .Function = FunctionMatch(tokens, candidates), }; } @@ -131,16 +135,73 @@ namespace NSQLComplete { return name; } + std::optional PragmaMatch( + const NSQLTranslation::TParsedTokenList& tokens, const TC3Candidates& candidates) { + bool isMatched = AnyOf(candidates.Rules, [&](const TMatchedRule& rule) { + return IsLikelyPragmaStack(rule.ParserCallStack); + }); + if (!isMatched) { + return std::nullopt; + } + + TLocalSyntaxContext::TPragma pragma; + if (EndsWith(tokens, {"ID_PLAIN", "DOT"})) { + pragma.Namespace = tokens[tokens.size() - 2].Content; + } else if (EndsWith(tokens, {"ID_PLAIN", "DOT", ""})) { + pragma.Namespace = tokens[tokens.size() - 3].Content; + } + return pragma; + } + bool IsTypeNameMatched(const TC3Candidates& candidates) { return AnyOf(candidates.Rules, [&](const TMatchedRule& rule) { return IsLikelyTypeStack(rule.ParserCallStack); }); } - bool IsFunctionNameMatched(const TC3Candidates& candidates) { - return AnyOf(candidates.Rules, [&](const TMatchedRule& rule) { + std::optional FunctionMatch( + const NSQLTranslation::TParsedTokenList& tokens, const TC3Candidates& candidates) { + bool isMatched = AnyOf(candidates.Rules, [&](const TMatchedRule& rule) { return IsLikelyFunctionStack(rule.ParserCallStack); }); + if (!isMatched) { + return std::nullopt; + } + + TLocalSyntaxContext::TFunction function; + if (EndsWith(tokens, {"ID_PLAIN", "NAMESPACE"})) { + function.Namespace = tokens[tokens.size() - 2].Content; + } else if (EndsWith(tokens, {"ID_PLAIN", "NAMESPACE", ""})) { + function.Namespace = tokens[tokens.size() - 3].Content; + } + return function; + } + + NSQLTranslation::TParsedTokenList Tokenized(const TStringBuf text) { + NSQLTranslation::TParsedTokenList tokens; + NYql::TIssues issues; + if (!NSQLTranslation::Tokenize( + *Lexer_, TString(text), /* queryName = */ "", + tokens, issues, /* maxErrors = */ 0)) { + return {}; + } + Y_ENSURE(!tokens.empty() && tokens.back().Name == "EOF"); + tokens.pop_back(); + return tokens; + } + + bool EndsWith( + const NSQLTranslation::TParsedTokenList& tokens, + const TVector& pattern) { + if (tokens.size() < pattern.size()) { + return false; + } + for (yssize_t i = tokens.ysize() - 1, j = pattern.ysize() - 1; 0 <= j; --i, --j) { + if (!pattern[j].empty() && tokens[i].Name != pattern[j]) { + return false; + } + } + return true; } const ISqlGrammar* Grammar; diff --git a/yql/essentials/sql/v1/complete/syntax/local.h b/yql/essentials/sql/v1/complete/syntax/local.h index 79984d00e2b8..24e78108e10e 100644 --- a/yql/essentials/sql/v1/complete/syntax/local.h +++ b/yql/essentials/sql/v1/complete/syntax/local.h @@ -10,9 +10,18 @@ namespace NSQLComplete { struct TLocalSyntaxContext { + struct TPragma { + TString Namespace; + }; + + struct TFunction { + TString Namespace; + }; + TVector Keywords; + std::optional Pragma; bool IsTypeName; - bool IsFunctionName; + std::optional Function; }; class ILocalSyntaxAnalysis { diff --git a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp index 57e058fa9008..1bfcac47266f 100644 --- a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp +++ b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp @@ -24,6 +24,11 @@ namespace NSQLComplete { RULE(Keyword_compat), }; + const TVector PragmaNameRules = { + RULE(Opt_id_prefix_or_type), + RULE(An_id), + }; + const TVector TypeNameRules = { RULE(Type_name_simple), RULE(An_id_or_type), @@ -62,6 +67,11 @@ namespace NSQLComplete { return Find(stack, rule) != std::end(stack); } + bool IsLikelyPragmaStack(const TParserCallStack& stack) { + return EndsWith({RULE(Pragma_stmt), RULE(Opt_id_prefix_or_type)}, stack) || + EndsWith({RULE(Pragma_stmt), RULE(An_id)}, stack); + } + bool IsLikelyTypeStack(const TParserCallStack& stack) { return EndsWith({RULE(Type_name_simple)}, stack) || (Contains({RULE(Invoke_expr), @@ -75,12 +85,14 @@ namespace NSQLComplete { return EndsWith({RULE(Unary_casual_subexpr), RULE(Id_expr)}, stack) || EndsWith({RULE(Unary_casual_subexpr), RULE(Atom_expr), - RULE(An_id_or_type)}, stack); + RULE(An_id_or_type)}, stack) || + EndsWith({RULE(Atom_expr), RULE(Id_or_type)}, stack); } std::unordered_set GetC3PreferredRules() { std::unordered_set preferredRules; preferredRules.insert(std::begin(KeywordRules), std::end(KeywordRules)); + preferredRules.insert(std::begin(PragmaNameRules), std::end(PragmaNameRules)); preferredRules.insert(std::begin(TypeNameRules), std::end(TypeNameRules)); preferredRules.insert(std::begin(FunctionNameRules), std::end(FunctionNameRules)); return preferredRules; diff --git a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h index 756586988dbf..94533bddaaeb 100644 --- a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h +++ b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h @@ -4,6 +4,8 @@ namespace NSQLComplete { + bool IsLikelyPragmaStack(const TParserCallStack& stack); + bool IsLikelyTypeStack(const TParserCallStack& stack); bool IsLikelyFunctionStack(const TParserCallStack& stack); From bf5ada704fd313a6b6670889763cd6b7b642fc13 Mon Sep 17 00:00:00 2001 From: Vasily Gerasimov Date: Tue, 8 Apr 2025 16:45:47 +0300 Subject: [PATCH 054/454] Fix starting of S3 recipe (#16933) --- ydb/tests/tools/s3_recipe/__main__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ydb/tests/tools/s3_recipe/__main__.py b/ydb/tests/tools/s3_recipe/__main__.py index dd6419468826..5ea6aa93e794 100644 --- a/ydb/tests/tools/s3_recipe/__main__.py +++ b/ydb/tests/tools/s3_recipe/__main__.py @@ -18,7 +18,8 @@ def start(argv): logging.debug("Starting S3 recipe") pm = PortManager() port = pm.get_port() - url = "http://localhost:{port}".format(port=port) + url = "http://localhost:{port}".format(port=port) # S3 libs require DNS name for S3 endpoint + check_url = "http://[::1]:{port}".format(port=port) cmd = [ yatest.common.binary_path(MOTO_SERVER_PATH), "s3", @@ -28,7 +29,7 @@ def start(argv): def is_s3_ready(): try: - response = requests.get(url) + response = requests.get(check_url) response.raise_for_status() return True except requests.RequestException as err: From 8814d7a73d24f222a2e046a142954c4044346a93 Mon Sep 17 00:00:00 2001 From: niksaveliev Date: Tue, 8 Apr 2025 18:56:11 +0500 Subject: [PATCH 055/454] Commit for autopartitioned topics (#11629) --- .../kqp/executer_actor/kqp_data_executer.cpp | 1 + .../kqp/session_actor/kqp_query_state.cpp | 8 +- ydb/core/kqp/session_actor/kqp_query_state.h | 2 +- .../kqp/session_actor/kqp_session_actor.cpp | 1 - ydb/core/kqp/topics/kqp_topics.cpp | 104 ++- ydb/core/kqp/topics/kqp_topics.h | 46 +- ydb/core/persqueue/events/internal.h | 10 +- ydb/core/persqueue/partition.cpp | 256 +++--- ydb/core/persqueue/partition.h | 13 +- ydb/core/persqueue/partition_read.cpp | 9 +- .../persqueue/partition_scale_manager.cpp | 2 +- .../persqueue/partition_sourcemanager.cpp | 2 +- ydb/core/persqueue/pq_impl.cpp | 14 +- .../persqueue/read_balancer__balancing.cpp | 10 +- .../read_balancer__balancing_app.cpp | 4 +- ydb/core/persqueue/read_balancer_app.cpp | 8 +- ydb/core/persqueue/transaction.cpp | 10 +- ydb/core/persqueue/user_info.cpp | 16 +- ydb/core/persqueue/user_info.h | 9 +- .../ut/common/autoscaling_ut_common.cpp | 3 +- ydb/core/persqueue/ut/partition_ut.cpp | 4 +- ydb/core/persqueue/ut/partitiongraph_ut.cpp | 32 +- ydb/core/persqueue/ut/pqtablet_ut.cpp | 4 +- .../persqueue/ut/user_action_processor_ut.cpp | 8 +- .../ut/ut_with_sdk/autoscaling_ut.cpp | 809 +++++++++++++++++- ydb/core/persqueue/utils.cpp | 54 +- ydb/core/persqueue/utils.h | 8 +- ydb/core/protos/kqp.proto | 30 +- ydb/core/protos/msgbus_pq.proto | 2 +- ydb/core/protos/pqconfig.proto | 10 +- ydb/public/api/protos/ydb_topic.proto | 3 +- .../ydb-cpp-sdk/client/topic/control_plane.h | 4 +- .../ydb-cpp-sdk/client/topic/read_events.h | 6 + .../src/client/topic/impl/read_session_impl.h | 3 + .../client/topic/impl/read_session_impl.ipp | 10 +- .../cpp/src/client/topic/impl/topic_impl.h | 4 +- .../deprecated/persqueue_v0/grpc_pq_actor.h | 2 + .../persqueue_v0/grpc_pq_read_actor.cpp | 237 +++-- ydb/services/lib/actors/type_definitions.h | 4 + .../actors/commit_offset_actor.cpp | 122 ++- .../persqueue_v1/actors/commit_offset_actor.h | 13 + .../actors/distributed_commit_helper.cpp | 126 +++ .../actors/distributed_commit_helper.h | 55 ++ ydb/services/persqueue_v1/actors/events.h | 17 +- .../persqueue_v1/actors/partition_actor.cpp | 209 +++-- .../persqueue_v1/actors/partition_actor.h | 30 +- .../actors/read_init_auth_actor.cpp | 12 +- .../actors/read_session_actor.cpp | 106 ++- .../persqueue_v1/actors/read_session_actor.h | 3 + .../update_offsets_in_transaction_actor.cpp | 17 +- ydb/services/persqueue_v1/actors/ya.make | 2 + 51 files changed, 2017 insertions(+), 457 deletions(-) create mode 100644 ydb/services/persqueue_v1/actors/distributed_commit_helper.cpp create mode 100644 ydb/services/persqueue_v1/actors/distributed_commit_helper.h diff --git a/ydb/core/kqp/executer_actor/kqp_data_executer.cpp b/ydb/core/kqp/executer_actor/kqp_data_executer.cpp index 8937cd378bf7..3469111c67cc 100644 --- a/ydb/core/kqp/executer_actor/kqp_data_executer.cpp +++ b/ydb/core/kqp/executer_actor/kqp_data_executer.cpp @@ -2162,6 +2162,7 @@ class TKqpDataExecuter : public TKqpExecuterBase consumer; if (operations.HasConsumer()) { @@ -442,7 +442,6 @@ void TKqpQueryState::AddOffsetsToTransaction() { } TopicOperations = NTopic::TTopicOperations(); - for (auto& topic : operations.GetTopics()) { auto path = CanonizePath(NPersQueue::GetFullTopicPath(GetDatabase(), topic.path())); @@ -452,8 +451,7 @@ void TKqpQueryState::AddOffsetsToTransaction() { } else { for (auto& range : partition.partition_offsets()) { YQL_ENSURE(consumer.Defined()); - - TopicOperations.AddOperation(path, partition.partition_id(), *consumer, range); + TopicOperations.AddOperation(path, partition.partition_id(), *consumer, range, partition.force_commit(), partition.kill_read_session(), partition.only_check_commited_to_finish(), partition.read_session_id()); } } } @@ -474,7 +472,7 @@ std::unique_ptr TKqpQueryState::BuildSchemeC auto navigate = std::make_unique(); navigate->DatabaseName = CanonizePath(GetDatabase()); - const auto& operations = GetTopicOperations(); + const auto& operations = GetTopicOperationsFromRequest(); TMaybe consumer; if (operations.HasConsumer()) consumer = operations.GetConsumer(); diff --git a/ydb/core/kqp/session_actor/kqp_query_state.h b/ydb/core/kqp/session_actor/kqp_query_state.h index 57411dde5964..f8df052feda1 100644 --- a/ydb/core/kqp/session_actor/kqp_query_state.h +++ b/ydb/core/kqp/session_actor/kqp_query_state.h @@ -332,7 +332,7 @@ class TKqpQueryState : public TNonCopyable { return RequestEv->GetQuery(); } - const ::NKikimrKqp::TTopicOperationsRequest& GetTopicOperations() const { + const ::NKikimrKqp::TTopicOperationsRequest& GetTopicOperationsFromRequest() const { return RequestEv->GetTopicOperations(); } diff --git a/ydb/core/kqp/session_actor/kqp_session_actor.cpp b/ydb/core/kqp/session_actor/kqp_session_actor.cpp index 4fc64ec1a1c4..071c6b6ade19 100644 --- a/ydb/core/kqp/session_actor/kqp_session_actor.cpp +++ b/ydb/core/kqp/session_actor/kqp_session_actor.cpp @@ -1358,7 +1358,6 @@ class TKqpSessionActor : public TActorBootstrapped { } } } - request.TopicOperations = std::move(txCtx.TopicOperations); } else if (QueryState->ShouldAcquireLocks(tx) && (!txCtx.HasOlapTable || Settings.TableService.GetEnableOlapSink())) { request.AcquireLocksTxId = txCtx.Locks.GetLockTxId(); diff --git a/ydb/core/kqp/topics/kqp_topics.cpp b/ydb/core/kqp/topics/kqp_topics.cpp index fcd14d18934a..7dff2f08679c 100644 --- a/ydb/core/kqp/topics/kqp_topics.cpp +++ b/ydb/core/kqp/topics/kqp_topics.cpp @@ -1,6 +1,7 @@ #include "kqp_topics.h" #include +#include #include #include @@ -26,21 +27,50 @@ static void UpdateSupportivePartition(TMaybe& lhs, const TMaybe& rhs // bool TConsumerOperations::IsValid() const { - return Offsets_.GetNumIntervals() == 1; + return Offsets_.GetNumIntervals() <= 1; } -std::pair TConsumerOperations::GetRange() const +std::pair TConsumerOperations::GetOffsetsCommitRange() const { Y_ABORT_UNLESS(IsValid()); - return {Offsets_.Min(), Offsets_.Max()}; + if (Offsets_.Empty()) { + return {0,0}; + } else { + return {Offsets_.Min(), Offsets_.Max()}; + } +} + +bool TConsumerOperations::GetForceCommit() const +{ + return ForceCommit_; +} + +bool TConsumerOperations::GetKillReadSession() const +{ + return KillReadSession_; +} + +bool TConsumerOperations::GetOnlyCheckCommitedToFinish() const +{ + return OnlyCheckCommitedToFinish_; } -void TConsumerOperations::AddOperation(const TString& consumer, const Ydb::Topic::OffsetsRange& range) +TString TConsumerOperations::GetReadSessionId() const +{ + return ReadSessionId_; +} + +void TConsumerOperations::AddOperation(const TString& consumer, + const NKikimrKqp::TTopicOperationsRequest_TopicOffsets_PartitionOffsets_OffsetsRange& range, + bool forceCommit, + bool killReadSession, + bool onlyCheckCommitedToFinish, + const TString& readSessionId) { Y_ABORT_UNLESS(Consumer_.Empty() || Consumer_ == consumer); - AddOperationImpl(consumer, range.start(), range.end()); + AddOperationImpl(consumer, range.start(), range.end(), forceCommit, killReadSession, onlyCheckCommitedToFinish, readSessionId); } void TConsumerOperations::Merge(const TConsumerOperations& rhs) @@ -48,13 +78,22 @@ void TConsumerOperations::Merge(const TConsumerOperations& rhs) Y_ABORT_UNLESS(rhs.Consumer_.Defined()); Y_ABORT_UNLESS(Consumer_.Empty() || Consumer_ == rhs.Consumer_); - for (auto& range : rhs.Offsets_) { - AddOperationImpl(*rhs.Consumer_, range.first, range.second); + if (!rhs.Offsets_.Empty()) { + for (auto& range : rhs.Offsets_) { + AddOperationImpl(*rhs.Consumer_, range.first, range.second, rhs.GetForceCommit(), rhs.GetKillReadSession(), rhs.GetOnlyCheckCommitedToFinish(), rhs.GetReadSessionId()); + } + } else { + AddOperationImpl(*rhs.Consumer_, 0, 0, rhs.GetForceCommit(), rhs.GetKillReadSession(), rhs.GetOnlyCheckCommitedToFinish(), rhs.GetReadSessionId()); } } void TConsumerOperations::AddOperationImpl(const TString& consumer, - ui64 begin, ui64 end) + ui64 begin, + ui64 end, + bool forceCommit, + bool killReadSession, + bool onlyCheckCommitedToFinish, + const TString& readSessionId) { if (Offsets_.Intersects(begin, end)) { ythrow TOffsetsRangeIntersectExpection() << "offset ranges intersect"; @@ -64,7 +103,14 @@ void TConsumerOperations::AddOperationImpl(const TString& consumer, Consumer_ = consumer; } - Offsets_.InsertInterval(begin, end); + if (end != 0) { + Offsets_.InsertInterval(begin, end); + } + + ForceCommit_ = forceCommit; + KillReadSession_ = killReadSession; + OnlyCheckCommitedToFinish_ = onlyCheckCommitedToFinish; + ReadSessionId_ = readSessionId; } // @@ -76,9 +122,14 @@ bool TTopicPartitionOperations::IsValid() const [](auto& x) { return x.second.IsValid(); }); } -void TTopicPartitionOperations::AddOperation(const TString& topic, ui32 partition, +void TTopicPartitionOperations::AddOperation(const TString& topic, + ui32 partition, const TString& consumer, - const Ydb::Topic::OffsetsRange& range) + const NKikimrKqp::TTopicOperationsRequest_TopicOffsets_PartitionOffsets_OffsetsRange& range, + bool forceCommit, + bool killReadSession, + bool onlyCheckCommitedToFinish, + const TString& readSessionId) { Y_ABORT_UNLESS(Topic_.Empty() || Topic_ == topic); Y_ABORT_UNLESS(Partition_.Empty() || Partition_ == partition); @@ -88,7 +139,7 @@ void TTopicPartitionOperations::AddOperation(const TString& topic, ui32 partitio Partition_ = partition; } - Operations_[consumer].AddOperation(consumer, range); + Operations_[consumer].AddOperation(consumer, range, forceCommit, killReadSession, onlyCheckCommitedToFinish, readSessionId); } void TTopicPartitionOperations::AddOperation(const TString& topic, ui32 partition, @@ -117,11 +168,15 @@ void TTopicPartitionOperations::BuildTopicTxs(TTopicOperationTransactions& txs) for (auto& [consumer, operations] : Operations_) { NKikimrPQ::TPartitionOperation* o = t.tx.MutableOperations()->Add(); o->SetPartitionId(*Partition_); - auto [begin, end] = operations.GetRange(); - o->SetBegin(begin); - o->SetEnd(end); + auto [begin, end] = operations.GetOffsetsCommitRange(); + o->SetCommitOffsetsBegin(begin); + o->SetCommitOffsetsEnd(end); o->SetConsumer(consumer); o->SetPath(*Topic_); + o->SetKillReadSession(operations.GetKillReadSession()); + o->SetForceCommit(operations.GetForceCommit()); + o->SetOnlyCheckCommitedToFinish(operations.GetOnlyCheckCommitedToFinish()); + o->SetReadSessionId(operations.GetReadSessionId()); } if (HasWriteOperations_) { @@ -256,14 +311,25 @@ bool TTopicOperations::TabletHasReadOperations(ui64 tabletId) const return false; } -void TTopicOperations::AddOperation(const TString& topic, ui32 partition, +void TTopicOperations::AddOperation(const TString& topic, + ui32 partition, const TString& consumer, - const Ydb::Topic::OffsetsRange& range) + const NKikimrKqp::TTopicOperationsRequest_TopicOffsets_PartitionOffsets_OffsetsRange& range, + bool forceCommit, + bool killReadSession, + bool onlyCheckCommitedToFinish, + const TString& readSessionId + ) { TTopicPartition key{topic, partition}; - Operations_[key].AddOperation(topic, partition, + Operations_[key].AddOperation(topic, + partition, consumer, - range); + range, + forceCommit, + killReadSession, + onlyCheckCommitedToFinish, + readSessionId); HasReadOperations_ = true; } diff --git a/ydb/core/kqp/topics/kqp_topics.h b/ydb/core/kqp/topics/kqp_topics.h index b04e7a186f5e..8eff402d1aa6 100644 --- a/ydb/core/kqp/topics/kqp_topics.h +++ b/ydb/core/kqp/topics/kqp_topics.h @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -26,20 +27,40 @@ class TConsumerOperations { public: bool IsValid() const; - std::pair GetRange() const; + std::pair GetOffsetsCommitRange() const; - ui64 GetBegin() const; - ui64 GetEnd() const; + ui64 GetOffsetCommitBegin() const; + ui64 GetOffsetCommitEnd() const; + + bool GetForceCommit() const; + bool GetKillReadSession() const; + bool GetOnlyCheckCommitedToFinish() const; + TString GetReadSessionId() const; + + void AddOperation(const TString& consumer, + const NKikimrKqp::TTopicOperationsRequest_TopicOffsets_PartitionOffsets_OffsetsRange& range, + bool forceCommit = false, + bool killReadSession = false, + bool onlyCheckCommitedToFinish = false, + const TString& readSessionId = {}); - void AddOperation(const TString& consumer, const Ydb::Topic::OffsetsRange& range); void Merge(const TConsumerOperations& rhs); private: void AddOperationImpl(const TString& consumer, - ui64 begin, ui64 end); + ui64 begin, + ui64 end, + bool forceCommit = false, + bool killReadSession = false, + bool onlyCheckCommitedToFinish = false, + const TString& readSessionId = {}); TMaybe Consumer_; TDisjointIntervalTree Offsets_; + bool ForceCommit_ = false; + bool KillReadSession_ = false; + bool OnlyCheckCommitedToFinish_ = false; + TString ReadSessionId_; }; struct TTopicOperationTransaction { @@ -53,9 +74,14 @@ class TTopicPartitionOperations { public: bool IsValid() const; - void AddOperation(const TString& topic, ui32 partition, + void AddOperation(const TString& topic, + ui32 partition, const TString& consumer, - const Ydb::Topic::OffsetsRange& range); + const NKikimrKqp::TTopicOperationsRequest_TopicOffsets_PartitionOffsets_OffsetsRange& range, + bool forceCommit = false, + bool killReadSession = false, + bool onlyCheckCommitedToFinish = false, + const TString& readSessionId = {}); void AddOperation(const TString& topic, ui32 partition, TMaybe supportivePartition); @@ -108,7 +134,11 @@ class TTopicOperations { void AddOperation(const TString& topic, ui32 partition, const TString& consumer, - const Ydb::Topic::OffsetsRange& range); + const NKikimrKqp::TTopicOperationsRequest_TopicOffsets_PartitionOffsets_OffsetsRange& range, + bool forceCommit, + bool killReadSession, + bool onlyCheckCommitedToFinish, + const TString& readSessionId); void AddOperation(const TString& topic, ui32 partition, TMaybe supportivePartition); diff --git a/ydb/core/persqueue/events/internal.h b/ydb/core/persqueue/events/internal.h index e72cbd8e1e47..77e2367f9bcc 100644 --- a/ydb/core/persqueue/events/internal.h +++ b/ydb/core/persqueue/events/internal.h @@ -809,11 +809,15 @@ struct TEvPQ { { } - void AddOperation(TString consumer, ui64 begin, ui64 end) { + void AddOperation(TString consumer, ui64 begin, ui64 end, bool forceCommit = false, bool killReadSession = false, bool onlyCheckCommitedToFinish = false, TString readSessionId = {}) { NKikimrPQ::TPartitionOperation operation; - operation.SetBegin(begin); - operation.SetEnd(end); + operation.SetCommitOffsetsBegin(begin); + operation.SetCommitOffsetsEnd(end); operation.SetConsumer(std::move(consumer)); + operation.SetForceCommit(forceCommit); + operation.SetKillReadSession(killReadSession); + operation.SetOnlyCheckCommitedToFinish(onlyCheckCommitedToFinish); + operation.SetReadSessionId(readSessionId); Operations.push_back(std::move(operation)); } diff --git a/ydb/core/persqueue/partition.cpp b/ydb/core/persqueue/partition.cpp index 6ca8e046216f..40796d3dffc6 100644 --- a/ydb/core/persqueue/partition.cpp +++ b/ydb/core/persqueue/partition.cpp @@ -167,15 +167,14 @@ void TPartition::ReplyOk(const TActorContext& ctx, const ui64 dst, NWilson::TSpa } void TPartition::ReplyGetClientOffsetOk(const TActorContext& ctx, const ui64 dst, const i64 offset, - const TInstant writeTimestamp, const TInstant createTimestamp) { - ctx.Send(Tablet, MakeReplyGetClientOffsetOk(dst, offset, writeTimestamp, createTimestamp).Release()); + const TInstant writeTimestamp, const TInstant createTimestamp, bool consumerHasAnyCommits) { + ctx.Send(Tablet, MakeReplyGetClientOffsetOk(dst, offset, writeTimestamp, createTimestamp, consumerHasAnyCommits).Release()); } NKikimrClient::TKeyValueRequest::EStorageChannel GetChannel(ui32 i) { return NKikimrClient::TKeyValueRequest::EStorageChannel(NKikimrClient::TKeyValueRequest::MAIN + i); } - void AddCheckDiskRequest(TEvKeyValue::TEvRequest *request, ui32 numChannels) { for (ui32 i = 0; i < numChannels; ++i) { request->Record.AddCmdGetStatus()->SetStorageChannel(GetChannel(i)); @@ -841,7 +840,7 @@ void TPartition::Handle(TEvPQ::TEvPartitionStatus::TPtr& ev, const TActorContext } } } - result.SetScaleStatus(SplitMergeEnabled(TabletConfig) ? ScaleStatus :NKikimrPQ::EScaleStatus::NORMAL); + result.SetScaleStatus(SplitMergeEnabled(TabletConfig) ? ScaleStatus : NKikimrPQ::EScaleStatus::NORMAL); ctx.Send(ev->Get()->Sender, new TEvPQ::TEvPartitionStatusResponse(result, Partition)); } @@ -1977,23 +1976,23 @@ void TPartition::ContinueProcessTxsAndUserActs(const TActorContext&) msg->WaitPreviousWriteSpan.End(); } switch (std::visit(visitor, front.Event)) { - case EProcessResult::Continue: - MoveUserActOrTxToCommitState(); - FirstEvent = false; - break; - case EProcessResult::ContinueDrop: - UserActionAndTransactionEvents.pop_front(); - break; - case EProcessResult::Break: - MoveUserActOrTxToCommitState(); - BatchingState = ETxBatchingState::Finishing; - FirstEvent = false; - break; - case EProcessResult::Blocked: - BatchingState = ETxBatchingState::Executing; - return; - case EProcessResult::NotReady: - return; + case EProcessResult::Continue: + MoveUserActOrTxToCommitState(); + FirstEvent = false; + break; + case EProcessResult::ContinueDrop: + UserActionAndTransactionEvents.pop_front(); + break; + case EProcessResult::Break: + MoveUserActOrTxToCommitState(); + BatchingState = ETxBatchingState::Finishing; + FirstEvent = false; + break; + case EProcessResult::Blocked: + BatchingState = ETxBatchingState::Executing; + return; + case EProcessResult::NotReady: + return; } CurrentBatchSize += 1; } @@ -2304,15 +2303,15 @@ bool TPartition::ExecUserActionOrTransaction(TSimpleSharedPtr& t, return true; } -TPartition::EProcessResult TPartition::BeginTransaction(const TEvPQ::TEvTxCalcPredicate& tx, TMaybe& predicate) +TPartition::EProcessResult TPartition::BeginTransaction(const TEvPQ::TEvTxCalcPredicate& tx, TMaybe& predicateOut) { if (tx.ForcePredicateFalse) { - predicate = false; + predicateOut = false; return EProcessResult::Continue; } THashSet consumers; - bool ok = true; + bool result = true; for (auto& operation : tx.Operations) { const TString& consumer = operation.GetConsumer(); if (TxAffectedConsumers.contains(consumer)) { @@ -2325,55 +2324,69 @@ TPartition::EProcessResult TPartition::BeginTransaction(const TEvPQ::TEvTxCalcPr if (AffectedUsers.contains(consumer) && !GetPendingUserIfExists(consumer)) { PQ_LOG_D("Partition " << Partition << " Consumer '" << consumer << "' has been removed"); - ok = false; + result = false; break; } if (!UsersInfoStorage->GetIfExists(consumer)) { PQ_LOG_D("Partition " << Partition << " Unknown consumer '" << consumer << "'"); - ok = false; + result = false; break; } bool isAffectedConsumer = AffectedUsers.contains(consumer); TUserInfoBase& userInfo = GetOrCreatePendingUser(consumer); - if (operation.GetBegin() > operation.GetEnd()) { - PQ_LOG_D("Partition " << Partition << - " Consumer '" << consumer << "'" << - " Bad request (invalid range) " << - " Begin " << operation.GetBegin() << - " End " << operation.GetEnd()); - ok = false; - } else if (userInfo.Offset != (i64)operation.GetBegin()) { - PQ_LOG_D("Partition " << Partition << - " Consumer '" << consumer << "'" << - " Bad request (gap) " << - " Offset " << userInfo.Offset << - " Begin " << operation.GetBegin()); - ok = false; - } else if (operation.GetEnd() > EndOffset) { + if (!operation.GetReadSessionId().empty() && operation.GetReadSessionId() != userInfo.Session) { PQ_LOG_D("Partition " << Partition << - " Consumer '" << consumer << "'" << - " Bad request (behind the last offset) " << - " EndOffset " << EndOffset << - " End " << operation.GetEnd()); - ok = false; - } + " Consumer '" << consumer << "'" << + " Bad request (session already dead) " << + " RequestSessionId '" << operation.GetReadSessionId() << + " CurrentSessionId '" << userInfo.Session << + "'"); + result = false; + } else if (operation.GetOnlyCheckCommitedToFinish()) { + if (IsActive() || static_cast(userInfo.Offset) != EndOffset) { + result = false; + } + } else { + if (!operation.GetForceCommit() && operation.GetCommitOffsetsBegin() > operation.GetCommitOffsetsEnd()) { + PQ_LOG_D("Partition " << Partition << + " Consumer '" << consumer << "'" << + " Bad request (invalid range) " << + " Begin " << operation.GetCommitOffsetsBegin() << + " End " << operation.GetCommitOffsetsEnd()); + result = false; + } else if (!operation.GetForceCommit() && userInfo.Offset != (i64)operation.GetCommitOffsetsBegin()) { + PQ_LOG_D("Partition " << Partition << + " Consumer '" << consumer << "'" << + " Bad request (gap) " << + " Offset " << userInfo.Offset << + " Begin " << operation.GetCommitOffsetsBegin()); + result = false; + } else if (!operation.GetForceCommit() && operation.GetCommitOffsetsEnd() > EndOffset) { + PQ_LOG_D("Partition " << Partition << + " Consumer '" << consumer << "'" << + " Bad request (behind the last offset) " << + " EndOffset " << EndOffset << + " End " << operation.GetCommitOffsetsEnd()); + result = false; + } - if (!ok) { - if (!isAffectedConsumer) { - AffectedUsers.erase(consumer); + if (!result) { + if (!isAffectedConsumer) { + AffectedUsers.erase(consumer); + } + break; } - break; + consumers.insert(consumer); } - consumers.insert(consumer); } - if (ok) { + if (result) { TxAffectedConsumers.insert(consumers.begin(), consumers.end()); } - predicate = ok; + predicateOut = result; return EProcessResult::Continue; } @@ -2533,12 +2546,40 @@ void TPartition::CommitTransaction(TSimpleSharedPtr& t) Y_ABORT_UNLESS(t->Predicate.Defined() && *t->Predicate); for (auto& operation : t->Tx->Operations) { + if (operation.GetOnlyCheckCommitedToFinish()) { + continue; + } + TUserInfoBase& userInfo = GetOrCreatePendingUser(operation.GetConsumer()); - Y_ABORT_UNLESS(userInfo.Offset == (i64)operation.GetBegin()); + if (!operation.GetForceCommit()) { + Y_ABORT_UNLESS(userInfo.Offset == (i64)operation.GetCommitOffsetsBegin()); + } - userInfo.Offset = operation.GetEnd(); + if ((i64)operation.GetCommitOffsetsEnd() < userInfo.Offset && !operation.GetReadSessionId().empty()) { + continue; // this is stale request, answer ok for it + } + + if (operation.GetCommitOffsetsEnd() <= StartOffset) { + userInfo.AnyCommits = false; + userInfo.Offset = StartOffset; + } else if (operation.GetCommitOffsetsEnd() > EndOffset) { + userInfo.AnyCommits = true; + userInfo.Offset = EndOffset; + } else { + userInfo.AnyCommits = true; + userInfo.Offset = operation.GetCommitOffsetsEnd(); + } + + if (operation.GetKillReadSession()) { + userInfo.Session = ""; + userInfo.PartitionSessionId = 0; + userInfo.Generation = 0; + userInfo.Step = 0; + userInfo.PipeClient = {}; + } } + CommitWriteOperations(*t); ChangePlanStepAndTxId(t->Tx->Step, t->Tx->TxId); ScheduleReplyCommitDone(t->Tx->Step, t->Tx->TxId); @@ -2660,6 +2701,9 @@ void TPartition::OnProcessTxsAndUserActsWriteComplete(const TActorContext& ctx) userInfo.Generation = actual->Generation; userInfo.Step = actual->Step; userInfo.Offset = actual->Offset; + if (userInfo.Offset <= (i64)StartOffset) { + userInfo.AnyCommits = false; + } userInfo.ReadRuleGeneration = actual->ReadRuleGeneration; userInfo.ReadFromTimestamp = actual->ReadFromTimestamp; userInfo.HasReadRule = true; @@ -2804,12 +2848,12 @@ TPartition::EProcessResult TPartition::PreProcessImmediateTx(const NKikimrPQ::TE Y_ABORT_UNLESS(tx.HasData()); THashSet consumers; for (auto& operation : tx.GetData().GetOperations()) { - if (!operation.HasBegin() || !operation.HasEnd() || !operation.HasConsumer()) { + if (!operation.HasCommitOffsetsBegin() || !operation.HasCommitOffsetsEnd() || !operation.HasConsumer()) { continue; //Write operation - handled separately via WriteInfo } - Y_ABORT_UNLESS(operation.GetBegin() <= (ui64)Max(), "Unexpected begin offset: %" PRIu64, operation.GetBegin()); - Y_ABORT_UNLESS(operation.GetEnd() <= (ui64)Max(), "Unexpected end offset: %" PRIu64, operation.GetEnd()); + Y_ABORT_UNLESS(operation.GetCommitOffsetsBegin() <= (ui64)Max(), "Unexpected begin offset: %" PRIu64, operation.GetCommitOffsetsBegin()); + Y_ABORT_UNLESS(operation.GetCommitOffsetsEnd() <= (ui64)Max(), "Unexpected end offset: %" PRIu64, operation.GetCommitOffsetsEnd()); const TString& user = operation.GetConsumer(); if (TxAffectedConsumers.contains(user)) { @@ -2822,7 +2866,7 @@ TPartition::EProcessResult TPartition::PreProcessImmediateTx(const NKikimrPQ::TE "the consumer has been deleted"); return EProcessResult::ContinueDrop; } - if (operation.GetBegin() > operation.GetEnd()) { + if (operation.GetCommitOffsetsBegin() > operation.GetCommitOffsetsEnd()) { ScheduleReplyPropose(tx, NKikimrPQ::TEvProposeTransactionResult::BAD_REQUEST, NKikimrPQ::TError::BAD_REQUEST, @@ -2853,12 +2897,12 @@ void TPartition::ExecImmediateTx(TTransaction& t) return; } for (const auto& operation : record.GetData().GetOperations()) { - if (!operation.HasBegin() || !operation.HasEnd() || !operation.HasConsumer()) { + if (!operation.HasCommitOffsetsBegin() || !operation.HasCommitOffsetsEnd() || !operation.HasConsumer()) { continue; //Write operation - handled separately via WriteInfo } - Y_ABORT_UNLESS(operation.GetBegin() <= (ui64)Max(), "Unexpected begin offset: %" PRIu64, operation.GetBegin()); - Y_ABORT_UNLESS(operation.GetEnd() <= (ui64)Max(), "Unexpected end offset: %" PRIu64, operation.GetEnd()); + Y_ABORT_UNLESS(operation.GetCommitOffsetsBegin() <= (ui64)Max(), "Unexpected begin offset: %" PRIu64, operation.GetCommitOffsetsBegin()); + Y_ABORT_UNLESS(operation.GetCommitOffsetsEnd() <= (ui64)Max(), "Unexpected end offset: %" PRIu64, operation.GetCommitOffsetsEnd()); const TString& user = operation.GetConsumer(); if (!PendingUsersInfo.contains(user) && AffectedUsers.contains(user)) { @@ -2868,9 +2912,9 @@ void TPartition::ExecImmediateTx(TTransaction& t) "the consumer has been deleted"); return; } - TUserInfoBase& userInfo = GetOrCreatePendingUser(user); + TUserInfoBase& pendingUserInfo = GetOrCreatePendingUser(user); - if (operation.GetBegin() > operation.GetEnd()) { + if (!operation.GetForceCommit() && operation.GetCommitOffsetsBegin() > operation.GetCommitOffsetsEnd()) { ScheduleReplyPropose(record, NKikimrPQ::TEvProposeTransactionResult::BAD_REQUEST, NKikimrPQ::TError::BAD_REQUEST, @@ -2878,7 +2922,7 @@ void TPartition::ExecImmediateTx(TTransaction& t) return; } - if (userInfo.Offset != (i64)operation.GetBegin()) { + if (!operation.GetForceCommit() && pendingUserInfo.Offset != (i64)operation.GetCommitOffsetsBegin()) { ScheduleReplyPropose(record, NKikimrPQ::TEvProposeTransactionResult::ABORTED, NKikimrPQ::TError::BAD_REQUEST, @@ -2886,14 +2930,14 @@ void TPartition::ExecImmediateTx(TTransaction& t) return; } - if (operation.GetEnd() > EndOffset) { + if (!operation.GetForceCommit() && operation.GetCommitOffsetsEnd() > EndOffset) { ScheduleReplyPropose(record, NKikimrPQ::TEvProposeTransactionResult::BAD_REQUEST, NKikimrPQ::TError::BAD_REQUEST, "incorrect offset range (commit to the future)"); return; } - userInfo.Offset = operation.GetEnd(); + pendingUserInfo.Offset = operation.GetCommitOffsetsEnd(); } CommitWriteOperations(t); @@ -3029,7 +3073,7 @@ void TPartition::CommitUserAct(TEvPQ::TEvSetClientInfo& act) { userInfo.PipeClient = act.PipeClient; ScheduleReplyGetClientOffsetOk(act.Cookie, userInfo.Offset, - ts.first, ts.second); + ts.first, ts.second, ui->AnyCommits); return; } @@ -3125,15 +3169,16 @@ void TPartition::EmulatePostProcessUserAct(const TEvPQ::TEvSetClientInfo& act, ui32 step = act.Step; const ui64 readRuleGeneration = act.ReadRuleGeneration; - bool setSession = act.Type == TEvPQ::TEvSetClientInfo::ESCI_CREATE_SESSION; + bool createSession = act.Type == TEvPQ::TEvSetClientInfo::ESCI_CREATE_SESSION; bool dropSession = act.Type == TEvPQ::TEvSetClientInfo::ESCI_DROP_SESSION; - bool strictCommitOffset = (act.Type == TEvPQ::TEvSetClientInfo::ESCI_OFFSET && act.SessionId.empty()); + bool commitNotFromReadSession = (act.Type == TEvPQ::TEvSetClientInfo::ESCI_OFFSET && act.SessionId.empty()); if (act.Type == TEvPQ::TEvSetClientInfo::ESCI_DROP_READ_RULE) { userInfo.ReadRuleGeneration = 0; userInfo.Session = ""; userInfo.Generation = userInfo.Step = 0; userInfo.Offset = 0; + userInfo.AnyCommits = false; PQ_LOG_D("Topic '" << TopicName() << "' partition " << Partition << " user " << user << " drop done" @@ -3149,30 +3194,31 @@ void TPartition::EmulatePostProcessUserAct(const TEvPQ::TEvSetClientInfo& act, userInfo.PartitionSessionId = 0; userInfo.Generation = userInfo.Step = 0; userInfo.Offset = 0; + userInfo.AnyCommits = false; if (userInfo.Important) { userInfo.Offset = StartOffset; } } else { - if (setSession || dropSession) { + if (createSession || dropSession) { offset = userInfo.Offset; auto *ui = UsersInfoStorage->GetIfExists(userInfo.User); auto ts = ui ? GetTime(*ui, userInfo.Offset) : std::make_pair(TInstant::Zero(), TInstant::Zero()); ScheduleReplyGetClientOffsetOk(act.Cookie, offset, - ts.first, ts.second); + ts.first, ts.second, ui ? ui->AnyCommits : false); } else { ScheduleReplyOk(act.Cookie); } - if (setSession) { + if (createSession) { userInfo.Session = session; userInfo.Generation = generation; userInfo.Step = step; userInfo.PipeClient = act.PipeClient; userInfo.PartitionSessionId = act.PartitionSessionId; - } else if ((dropSession && act.PipeClient == userInfo.PipeClient) || strictCommitOffset) { + } else if ((dropSession && act.PipeClient == userInfo.PipeClient) || commitNotFromReadSession) { userInfo.Session = ""; userInfo.PartitionSessionId = 0; userInfo.Generation = 0; @@ -3182,17 +3228,20 @@ void TPartition::EmulatePostProcessUserAct(const TEvPQ::TEvSetClientInfo& act, Y_ABORT_UNLESS(offset <= (ui64)Max(), "Unexpected Offset: %" PRIu64, offset); PQ_LOG_D("Topic '" << TopicName() << "' partition " << Partition << " user " << user - << (setSession || dropSession ? " session" : " offset") + << (createSession || dropSession ? " session" : " offset") << " is set to " << offset << " (startOffset " << StartOffset << ") session " << session ); userInfo.Offset = offset; + if (userInfo.Offset <= (i64)StartOffset) { + userInfo.AnyCommits = false; + } if (LastOffsetHasBeenCommited(userInfo)) { SendReadingFinished(user); } - auto counter = setSession ? COUNTER_PQ_CREATE_SESSION_OK : (dropSession ? COUNTER_PQ_DELETE_SESSION_OK : COUNTER_PQ_SET_CLIENT_OFFSET_OK); + auto counter = createSession ? COUNTER_PQ_CREATE_SESSION_OK : (dropSession ? COUNTER_PQ_DELETE_SESSION_OK : COUNTER_PQ_SET_CLIENT_OFFSET_OK); TabletCounters.Cumulative()[counter].Increment(1); } } @@ -3205,12 +3254,16 @@ void TPartition::ScheduleReplyOk(const ui64 dst) void TPartition::ScheduleReplyGetClientOffsetOk(const ui64 dst, const i64 offset, - const TInstant writeTimestamp, const TInstant createTimestamp) + const TInstant writeTimestamp, + const TInstant createTimestamp, + bool consumerHasAnyCommits) { Replies.emplace_back(Tablet, MakeReplyGetClientOffsetOk(dst, offset, - writeTimestamp, createTimestamp).Release()); + writeTimestamp, + createTimestamp, + consumerHasAnyCommits).Release()); } @@ -3285,7 +3338,8 @@ void TPartition::AddCmdWrite(NKikimrClient::TKeyValueRequest& request, const TKeyPrefix& ikey, const TKeyPrefix& ikeyDeprecated, ui64 offset, ui32 gen, ui32 step, const TString& session, ui64 readOffsetRewindSum, - ui64 readRuleGeneration) + ui64 readRuleGeneration, + bool anyCommits) { TBuffer idata; { @@ -3296,6 +3350,7 @@ void TPartition::AddCmdWrite(NKikimrClient::TKeyValueRequest& request, userData.SetSession(session); userData.SetOffsetRewindSum(readOffsetRewindSum); userData.SetReadRuleGeneration(readRuleGeneration); + userData.SetAnyCommits(anyCommits); TString out; Y_PROTOBUF_SUPPRESS_NODISCARD userData.SerializeToString(&out); @@ -3356,7 +3411,8 @@ void TPartition::AddCmdWriteUserInfos(NKikimrClient::TKeyValueRequest& request) userInfo->Offset, userInfo->Generation, userInfo->Step, userInfo->Session, ui ? ui->ReadOffsetRewindSum : 0, - userInfo->ReadRuleGeneration); + userInfo->ReadRuleGeneration, + userInfo->AnyCommits); } else { AddCmdDeleteRange(request, ikey, ikeyDeprecated); @@ -3385,27 +3441,27 @@ TUserInfoBase& TPartition::GetOrCreatePendingUser(const TString& user, TMaybe readRuleGeneration) { TUserInfoBase* userInfo = nullptr; - auto i = PendingUsersInfo.find(user); - if (i == PendingUsersInfo.end()) { - auto ui = UsersInfoStorage->GetIfExists(user); - auto [p, _] = PendingUsersInfo.emplace(user, UsersInfoStorage->CreateUserInfo(user, readRuleGeneration)); + auto pendingUserIt = PendingUsersInfo.find(user); + if (pendingUserIt == PendingUsersInfo.end()) { + auto userIt = UsersInfoStorage->GetIfExists(user); + auto [newPendingUserIt, _] = PendingUsersInfo.emplace(user, UsersInfoStorage->CreateUserInfo(user, readRuleGeneration)); - if (ui) { - p->second.Session = ui->Session; - p->second.PartitionSessionId = ui->PartitionSessionId; - p->second.PipeClient = ui->PipeClient; + if (userIt) { + newPendingUserIt->second.Session = userIt->Session; + newPendingUserIt->second.PartitionSessionId = userIt->PartitionSessionId; + newPendingUserIt->second.PipeClient = userIt->PipeClient; - p->second.Generation = ui->Generation; - p->second.Step = ui->Step; - p->second.Offset = ui->Offset; - p->second.ReadRuleGeneration = ui->ReadRuleGeneration; - p->second.Important = ui->Important; - p->second.ReadFromTimestamp = ui->ReadFromTimestamp; + newPendingUserIt->second.Generation = userIt->Generation; + newPendingUserIt->second.Step = userIt->Step; + newPendingUserIt->second.Offset = userIt->Offset; + newPendingUserIt->second.ReadRuleGeneration = userIt->ReadRuleGeneration; + newPendingUserIt->second.Important = userIt->Important; + newPendingUserIt->second.ReadFromTimestamp = userIt->ReadFromTimestamp; } - userInfo = &p->second; + userInfo = &newPendingUserIt->second; } else { - userInfo = &i->second; + userInfo = &pendingUserIt->second; } AffectedUsers.insert(user); @@ -3435,7 +3491,8 @@ THolder TPartition::MakeReplyOk(const ui64 dst) THolder TPartition::MakeReplyGetClientOffsetOk(const ui64 dst, const i64 offset, const TInstant writeTimestamp, - const TInstant createTimestamp) + const TInstant createTimestamp, + bool consumerHasAnyCommits) { auto response = MakeHolder(dst); NKikimrClient::TResponse& resp = *response->Response; @@ -3459,10 +3516,9 @@ THolder TPartition::MakeReplyGetClientOffsetOk(const ui } else { user->SetSizeLag(0); } - + user->SetClientHasAnyCommits(consumerHasAnyCommits); return response; } - THolder TPartition::MakeReplyError(const ui64 dst, NPersQueue::NErrorCode::EErrorCode errorCode, const TString& error) diff --git a/ydb/core/persqueue/partition.h b/ydb/core/persqueue/partition.h index cdda09f3c6d6..b801c87ab2ca 100644 --- a/ydb/core/persqueue/partition.h +++ b/ydb/core/persqueue/partition.h @@ -158,7 +158,7 @@ class TPartition : public TActorBootstrapped { NKikimrPQ::TError::EKind kind, const TString& reason); void ReplyErrorForStoredWrites(const TActorContext& ctx); - void ReplyGetClientOffsetOk(const TActorContext& ctx, const ui64 dst, const i64 offset, const TInstant writeTimestamp, const TInstant createTimestamp); + void ReplyGetClientOffsetOk(const TActorContext& ctx, const ui64 dst, const i64 offset, const TInstant writeTimestamp, const TInstant createTimestamp, bool consumerHasAnyCommits); void ReplyOk(const TActorContext& ctx, const ui64 dst); void ReplyOk(const TActorContext& ctx, const ui64 dst, NWilson::TSpan& span); void ReplyOwnerOk(const TActorContext& ctx, const ui64 dst, const TString& ownerCookie, ui64 seqNo, NWilson::TSpan& span); @@ -345,7 +345,9 @@ class TPartition : public TActorBootstrapped { void ScheduleReplyOk(const ui64 dst); void ScheduleReplyGetClientOffsetOk(const ui64 dst, const i64 offset, - const TInstant writeTimestamp, const TInstant createTimestamp); + const TInstant writeTimestamp, + const TInstant createTimestamp, + bool consumerHasAnyCommits); void ScheduleReplyError(const ui64 dst, NPersQueue::NErrorCode::EErrorCode errorCode, const TString& error); @@ -361,7 +363,8 @@ class TPartition : public TActorBootstrapped { const TKeyPrefix& ikey, const TKeyPrefix& ikeyDeprecated, ui64 offset, ui32 gen, ui32 step, const TString& session, ui64 readOffsetRewindSum, - ui64 readRuleGeneration); + ui64 readRuleGeneration, + bool anyCommits); void AddCmdWriteTxMeta(NKikimrClient::TKeyValueRequest& request); void AddCmdWriteUserInfos(NKikimrClient::TKeyValueRequest& request); void AddCmdWriteConfig(NKikimrClient::TKeyValueRequest& request); @@ -374,7 +377,9 @@ class TPartition : public TActorBootstrapped { THolder MakeReplyOk(const ui64 dst); THolder MakeReplyGetClientOffsetOk(const ui64 dst, const i64 offset, - const TInstant writeTimestamp, const TInstant createTimestamp); + const TInstant writeTimestamp, + const TInstant createTimestamp, + bool consumerHasAnyCommits); THolder MakeReplyError(const ui64 dst, NPersQueue::NErrorCode::EErrorCode errorCode, const TString& error); diff --git a/ydb/core/persqueue/partition_read.cpp b/ydb/core/persqueue/partition_read.cpp index 767d08a3c2f9..ba9355f62c4f 100644 --- a/ydb/core/persqueue/partition_read.cpp +++ b/ydb/core/persqueue/partition_read.cpp @@ -124,10 +124,10 @@ TAutoPtr TPartition::MakeHasDataInfoRespon ui32 partitionId = Partition.OriginalPartitionId; auto* node = PartitionGraph.GetPartition(partitionId); - for (auto* child : node->Children) { + for (auto* child : node->DirectChildren) { res->Record.AddChildPartitionIds(child->Id); - for (auto* p : child->Parents) { + for (auto* p : child->DirectParents) { if (p->Id != partitionId) { res->Record.AddAdjacentPartitionIds(p->Id); } @@ -252,7 +252,7 @@ void TPartition::InitUserInfoForImportantClients(const TActorContext& ctx) { } if (!userInfo) { userInfo = &UsersInfoStorage->Create( - ctx, consumer.GetName(), 0, true, "", 0, 0, 0, 0, 0, TInstant::Zero(), {} + ctx, consumer.GetName(), 0, true, "", 0, 0, 0, 0, 0, TInstant::Zero(), {}, false ); } if (userInfo->Offset < (i64)StartOffset) @@ -314,7 +314,7 @@ void TPartition::Handle(TEvPQ::TEvGetClientOffset::TPtr& ev, const TActorContext ui64 offset = Max(userInfo.Offset, 0); auto ts = GetTime(userInfo, offset); TabletCounters.Cumulative()[COUNTER_PQ_GET_CLIENT_OFFSET_OK].Increment(1); - ReplyGetClientOffsetOk(ctx, ev->Get()->Cookie, userInfo.Offset, ts.first, ts.second); + ReplyGetClientOffsetOk(ctx, ev->Get()->Cookie, userInfo.Offset, ts.first, ts.second, userInfo.AnyCommits); } void TPartition::Handle(TEvPQ::TEvSetClientInfo::TPtr& ev, const TActorContext& ctx) { @@ -776,7 +776,6 @@ void TPartition::Handle(TEvPQ::TEvRead::TPtr& ev, const TActorContext& ctx) { const TString& user = read->ClientId; auto& userInfo = UsersInfoStorage->GetOrCreate(user, ctx); - if (!read->SessionId.empty() && !userInfo.NoConsumer) { if (userInfo.Session != read->SessionId) { TabletCounters.Cumulative()[COUNTER_PQ_READ_ERROR_NO_SESSION].Increment(1); diff --git a/ydb/core/persqueue/partition_scale_manager.cpp b/ydb/core/persqueue/partition_scale_manager.cpp index 77f16ab019ea..3360752d7653 100644 --- a/ydb/core/persqueue/partition_scale_manager.cpp +++ b/ydb/core/persqueue/partition_scale_manager.cpp @@ -74,7 +74,7 @@ std::pair, std::vector> TPartition auto partitionId = PartitionsToSplit.begin(); while (allowedSplitsCount > 0 && partitionId != PartitionsToSplit.end()) { auto* node = PartitionGraph.GetPartition(*partitionId); - if (node->Children.empty()) { + if (node->DirectChildren.empty()) { auto from = node->From; auto to = node->To; auto mid = MiddleOf(from, to); diff --git a/ydb/core/persqueue/partition_sourcemanager.cpp b/ydb/core/persqueue/partition_sourcemanager.cpp index c9214300384a..c2b6d5a0edd4 100644 --- a/ydb/core/persqueue/partition_sourcemanager.cpp +++ b/ydb/core/persqueue/partition_sourcemanager.cpp @@ -50,7 +50,7 @@ TSourceIdStorage& TPartitionSourceManager::GetSourceIdStorage() const { bool TPartitionSourceManager::HasParents() const { auto node = GetPartitionNode(); - return node && !node->Parents.empty(); + return node && !node->DirectParents.empty(); } diff --git a/ydb/core/persqueue/pq_impl.cpp b/ydb/core/persqueue/pq_impl.cpp index 5447d7bc8515..cfd101855c3b 100644 --- a/ydb/core/persqueue/pq_impl.cpp +++ b/ydb/core/persqueue/pq_impl.cpp @@ -3203,7 +3203,7 @@ bool TPersQueue::CheckTxWriteOperations(const NKikimrPQ::TDataTransaction& txBod for (auto& operation : txBody.GetOperations()) { auto isWrite = [](const NKikimrPQ::TPartitionOperation& o) { - return !o.HasBegin(); + return !o.HasCommitOffsetsBegin(); }; if (isWrite(operation)) { @@ -3926,7 +3926,7 @@ TMaybe TPersQueue::FindPartitionId(const NKikimrPQ::TDataTransacti { auto hasWriteOperation = [](const auto& txBody) { for (const auto& o : txBody.GetOperations()) { - if (!o.HasBegin()) { + if (!o.HasCommitOffsetsBegin()) { return true; } } @@ -3978,10 +3978,14 @@ void TPersQueue::SendEvTxCalcPredicateToPartitions(const TActorContext& ctx, event = std::make_unique(tx.Step, tx.TxId); } - if (operation.HasBegin()) { + if (operation.HasCommitOffsetsBegin()) { event->AddOperation(operation.GetConsumer(), - operation.GetBegin(), - operation.GetEnd()); + operation.GetCommitOffsetsBegin(), + operation.GetCommitOffsetsEnd(), + operation.HasForceCommit() ? operation.GetForceCommit() : false, + operation.HasKillReadSession() ? operation.GetKillReadSession() : false, + operation.HasOnlyCheckCommitedToFinish() ? operation.GetOnlyCheckCommitedToFinish() : false, + operation.HasReadSessionId() ? operation.GetReadSessionId() : ""); } } diff --git a/ydb/core/persqueue/read_balancer__balancing.cpp b/ydb/core/persqueue/read_balancer__balancing.cpp index 79218cdff6b9..f8f97a4c4795 100644 --- a/ydb/core/persqueue/read_balancer__balancing.cpp +++ b/ydb/core/persqueue/read_balancer__balancing.cpp @@ -681,7 +681,7 @@ bool IsRoot(const TPartitionGraph::Node* node, const std::unordered_set& p if (node->IsRoot()) { return true; } - for (auto* p : node->Parents) { + for (auto* p : node->DirectParents) { if (partitions.contains(p->Id)) { return false; } @@ -966,10 +966,10 @@ bool TConsumer::IsReadable(ui32 partitionId) { } if (Partitions.empty()) { - return node->Parents.empty(); + return node->DirectParents.empty(); } - for(auto* parent : node->HierarhicalParents) { + for(auto* parent : node->AllParents) { if (!IsInactive(parent->Id)) { return false; } @@ -1035,9 +1035,9 @@ bool TConsumer::ProccessReadingFinished(ui32 partitionId, bool wasInactive, cons if (family->CanAttach(std::vector{id})) { auto* node = GetPartitionGraph().GetPartition(id); bool allParentsMerged = true; - if (node->Parents.size() > 1) { + if (node->DirectParents.size() > 1) { // The partition was obtained as a result of the merge. - for (auto* c : node->Parents) { + for (auto* c : node->DirectParents) { auto* other = FindFamily(c->Id); if (!other) { allParentsMerged = false; diff --git a/ydb/core/persqueue/read_balancer__balancing_app.cpp b/ydb/core/persqueue/read_balancer__balancing_app.cpp index fd565135d162..71c7b72150fb 100644 --- a/ydb/core/persqueue/read_balancer__balancing_app.cpp +++ b/ydb/core/persqueue/read_balancer__balancing_app.cpp @@ -76,7 +76,7 @@ void TBalancer::RenderApp(NApp::TNavigationBar& __navigationBar) const { for (auto& [partitionId, partition] : consumer->Partitions) { const auto* family = consumer->FindFamily(partitionId); const auto* node = consumer->GetPartitionGraph().GetPartition(partitionId); - TString style = node && node->Children.empty() ? "text-success" : "text-muted"; + TString style = node && node->DirectChildren.empty() ? "text-success" : "text-muted"; auto* partitionInfo = GetPartitionInfo(partitionId); TABLER() { @@ -110,7 +110,7 @@ void TBalancer::RenderApp(NApp::TNavigationBar& __navigationBar) const { } TABLED() { if (node) { - for (auto* parent : node->Parents) { + for (auto* parent : node->DirectParents) { HREF("#" + partitionAnchor(parent->Id)) { __stream << parent->Id; } __stream << ", "; } diff --git a/ydb/core/persqueue/read_balancer_app.cpp b/ydb/core/persqueue/read_balancer_app.cpp index d4f9f8abf137..9ca5c425258b 100644 --- a/ydb/core/persqueue/read_balancer_app.cpp +++ b/ydb/core/persqueue/read_balancer_app.cpp @@ -77,7 +77,7 @@ TString TPersQueueReadBalancer::GenerateStat() { for (auto& [partitionId, partitionInfo] : PartitionsInfo) { const auto& stats = AggregatedStats.Stats[partitionId]; const auto* node = PartitionGraph.GetPartition(partitionId); - TString style = node && node->Children.empty() ? "text-success" : "text-muted"; + TString style = node && node->DirectChildren.empty() ? "text-success" : "text-muted"; TABLER() { TABLED() { @@ -87,7 +87,7 @@ TString TPersQueueReadBalancer::GenerateStat() { } TABLED() { if (node) { - str << (node->Children.empty() ? "Active" : "Inactive"); + str << (node->DirectChildren.empty() ? "Active" : "Inactive"); if (node->IsRoot()) { str << " (root)"; } @@ -96,7 +96,7 @@ TString TPersQueueReadBalancer::GenerateStat() { TABLED() { HREF(TStringBuilder() << "?TabletID=" << partitionInfo.TabletId) { str << partitionInfo.TabletId; } } TABLED() { if (node) { - for (auto* parent : node->Parents) { + for (auto* parent : node->DirectParents) { HREF("#" + partitionAnchor(parent->Id)) { str << parent->Id; } str << ", "; } @@ -104,7 +104,7 @@ TString TPersQueueReadBalancer::GenerateStat() { } TABLED() { if (node) { - for (auto* child : node->Children) { + for (auto* child : node->DirectChildren) { HREF("#" + partitionAnchor(child->Id)) { str << child->Id; } str << ", "; } diff --git a/ydb/core/persqueue/transaction.cpp b/ydb/core/persqueue/transaction.cpp index 63fe2a184b20..25d5ee46f01f 100644 --- a/ydb/core/persqueue/transaction.cpp +++ b/ydb/core/persqueue/transaction.cpp @@ -77,7 +77,7 @@ void TDistributedTransaction::InitPartitions(const google::protobuf::RepeatedPtr Partitions.clear(); for (auto& o : operations) { - if (!o.HasBegin()) { + if (!o.HasCommitOffsetsBegin()) { HasWriteOperations = true; } @@ -185,16 +185,16 @@ void TDistributedTransaction::OnProposeTransaction(const NKikimrPQ::TConfigTrans continue; } - if (node->Children.empty()) { - for (const auto* r : node->Parents) { + if (node->DirectChildren.empty()) { + for (const auto* r : node->DirectParents) { if (extractTabletId != r->TabletId) { PredicatesReceived[r->TabletId].SetTabletId(r->TabletId); } } } - for (const auto* r : node->Children) { - if (r->Children.empty()) { + for (const auto* r : node->DirectChildren) { + if (r->DirectChildren.empty()) { if (extractTabletId != r->TabletId) { PredicateRecipients[r->TabletId] = false; } diff --git a/ydb/core/persqueue/user_info.cpp b/ydb/core/persqueue/user_info.cpp index 92bf080dbf5c..9b8560576756 100644 --- a/ydb/core/persqueue/user_info.cpp +++ b/ydb/core/persqueue/user_info.cpp @@ -95,7 +95,7 @@ void TUsersInfoStorage::ParseDeprecated(const TString& key, const TString& data, Y_ABORT_UNLESS(offset <= (ui64)Max(), "Offset is too big: %" PRIu64, offset); if (!userInfo) { - Create(ctx, user, 0, false, session, 0, gen, step, static_cast(offset), 0, TInstant::Zero(), {}); + Create(ctx, user, 0, false, session, 0, gen, step, static_cast(offset), 0, TInstant::Zero(), {}, false); } else { userInfo->Session = session; userInfo->Generation = gen; @@ -123,7 +123,7 @@ void TUsersInfoStorage::Parse(const TString& key, const TString& data, const TAc Create( ctx, user, userData.GetReadRuleGeneration(), false, userData.GetSession(), userData.GetPartitionSessionId(), userData.GetGeneration(), userData.GetStep(), offset, - userData.GetOffsetRewindSum(), TInstant::Zero(), {} + userData.GetOffsetRewindSum(), TInstant::Zero(), {}, userData.GetAnyCommits() ); } else { userInfo->Session = userData.GetSession(); @@ -150,7 +150,7 @@ TUserInfo& TUsersInfoStorage::GetOrCreate(const TString& user, const TActorConte if (it == UsersInfo.end()) { return Create( ctx, user, readRuleGeneration ? *readRuleGeneration : ++CurReadRuleGeneration, false, "", 0, - 0, 0, 0, 0, TInstant::Zero(), {} + 0, 0, 0, 0, TInstant::Zero(), {}, false ); } return it->second; @@ -177,7 +177,7 @@ TUserInfo TUsersInfoStorage::CreateUserInfo(const TActorContext& ctx, const TString& session, ui64 partitionSessionId, ui32 gen, ui32 step, i64 offset, ui64 readOffsetRewindSum, - TInstant readFromTimestamp, const TActorId& pipeClient) const + TInstant readFromTimestamp, const TActorId& pipeClient, bool anyCommits) const { TString defaultServiceType = AppData(ctx)->PQConfig.GetDefaultClientServiceType().GetName(); TString userServiceType = ""; @@ -195,7 +195,7 @@ TUserInfo TUsersInfoStorage::CreateUserInfo(const TActorContext& ctx, ctx, StreamCountersSubgroup, user, readRuleGeneration, important, TopicConverter, Partition, session, partitionSessionId, gen, step, offset, readOffsetRewindSum, DCId, readFromTimestamp, DbPath, - meterRead, pipeClient + meterRead, pipeClient, anyCommits }; } @@ -203,16 +203,16 @@ TUserInfoBase TUsersInfoStorage::CreateUserInfo(const TString& user, TMaybe readRuleGeneration) const { return TUserInfoBase{user, readRuleGeneration ? *readRuleGeneration : ++CurReadRuleGeneration, - "", 0, 0, 0, false, {}, 0, {}}; + "", 0, 0, 0, false, false, {}, 0, {}}; } TUserInfo& TUsersInfoStorage::Create( const TActorContext& ctx, const TString& user, const ui64 readRuleGeneration, bool important, const TString& session, ui64 partitionSessionId, ui32 gen, ui32 step, i64 offset, ui64 readOffsetRewindSum, - TInstant readFromTimestamp, const TActorId& pipeClient + TInstant readFromTimestamp, const TActorId& pipeClient, bool anyCommits ) { auto userInfo = CreateUserInfo(ctx, user, readRuleGeneration, important, session, partitionSessionId, - gen, step, offset, readOffsetRewindSum, readFromTimestamp, pipeClient); + gen, step, offset, readOffsetRewindSum, readFromTimestamp, pipeClient, anyCommits); auto result = UsersInfo.emplace(user, std::move(userInfo)); Y_ABORT_UNLESS(result.second); return result.first->second; diff --git a/ydb/core/persqueue/user_info.h b/ydb/core/persqueue/user_info.h index d93da603a10a..5aaad167d9f0 100644 --- a/ydb/core/persqueue/user_info.h +++ b/ydb/core/persqueue/user_info.h @@ -45,6 +45,7 @@ struct TUserInfoBase { ui32 Generation = 0; ui32 Step = 0; i64 Offset = 0; + bool AnyCommits = false; bool Important = false; TInstant ReadFromTimestamp; @@ -170,9 +171,9 @@ struct TUserInfo: public TUserInfoBase { const ui64 readRuleGeneration, const bool important, const NPersQueue::TTopicConverterPtr& topicConverter, const ui32 partition, const TString& session, ui64 partitionSession, ui32 gen, ui32 step, i64 offset, const ui64 readOffsetRewindSum, const TString& dcId, TInstant readFromTimestamp, - const TString& dbPath, bool meterRead, const TActorId& pipeClient + const TString& dbPath, bool meterRead, const TActorId& pipeClient, bool anyCommits ) - : TUserInfoBase{user, readRuleGeneration, session, gen, step, offset, important, + : TUserInfoBase{user, readRuleGeneration, session, gen, step, offset, anyCommits, important, readFromTimestamp, partitionSession, pipeClient} , WriteTimestamp(TAppData::TimeProvider->Now()) , CreateTimestamp(TAppData::TimeProvider->Now()) @@ -388,7 +389,7 @@ class TUsersInfoStorage { TUserInfo& Create( const TActorContext& ctx, const TString& user, const ui64 readRuleGeneration, bool important, const TString& session, ui64 partitionSessionId, ui32 gen, ui32 step, i64 offset, ui64 readOffsetRewindSum, - TInstant readFromTimestamp, const TActorId& pipeClient + TInstant readFromTimestamp, const TActorId& pipeClient, bool anyCommits ); void Clear(const TActorContext& ctx); @@ -404,7 +405,7 @@ class TUsersInfoStorage { const TString& session, ui64 partitionSessionId, ui32 gen, ui32 step, i64 offset, ui64 readOffsetRewindSum, - TInstant readFromTimestamp, const TActorId& pipeClient) const; + TInstant readFromTimestamp, const TActorId& pipeClient, bool anyCommits) const; private: THashMap UsersInfo; diff --git a/ydb/core/persqueue/ut/common/autoscaling_ut_common.cpp b/ydb/core/persqueue/ut/common/autoscaling_ut_common.cpp index dc877d041c9e..779bf4776c94 100644 --- a/ydb/core/persqueue/ut/common/autoscaling_ut_common.cpp +++ b/ydb/core/persqueue/ut/common/autoscaling_ut_common.cpp @@ -261,7 +261,6 @@ std::shared_ptr::TSdkReadSession> TTestReadS TString{message.GetData()}, impl->AutoCommit) .WithMsg(new MsgWrapper(message)); - impl->ReceivedMessages.push_back(msg); if (impl->AutoCommit) { @@ -450,7 +449,7 @@ void TTestReadSession::WaitAllMessages() { template void TTestReadSession::Commit() { - Cerr << ">>>>> " << Impl->Name << " Commit all received messages" << Endl << Flush; + Cerr << ">>>>> " << Impl->Name << "Commit all received messages" << Endl << Flush; for (auto& m : Impl->ReceivedMessages) { if (!m.Commited) { m.Msg->Commit(); diff --git a/ydb/core/persqueue/ut/partition_ut.cpp b/ydb/core/persqueue/ut/partition_ut.cpp index 3cee045ea4c7..98147f077771 100644 --- a/ydb/core/persqueue/ut/partition_ut.cpp +++ b/ydb/core/persqueue/ut/partition_ut.cpp @@ -977,8 +977,8 @@ void TPartitionFixture::SendProposeTransactionRequest(ui32 partition, auto* body = event->Record.MutableData(); auto* operation = body->MutableOperations()->Add(); operation->SetPartitionId(partition); - operation->SetBegin(begin); - operation->SetEnd(end); + operation->SetCommitOffsetsBegin(begin); + operation->SetCommitOffsetsEnd(end); operation->SetConsumer(client); operation->SetPath(topic); body->SetImmediate(immediate); diff --git a/ydb/core/persqueue/ut/partitiongraph_ut.cpp b/ydb/core/persqueue/ut/partitiongraph_ut.cpp index eb8d1cff01cf..43603f312ef8 100644 --- a/ydb/core/persqueue/ut/partitiongraph_ut.cpp +++ b/ydb/core/persqueue/ut/partitiongraph_ut.cpp @@ -59,22 +59,22 @@ Y_UNIT_TEST_SUITE(TPartitionGraphTest) { UNIT_ASSERT(n4); UNIT_ASSERT(n5); - UNIT_ASSERT_VALUES_EQUAL(n0->Parents.size(), 0); - UNIT_ASSERT_VALUES_EQUAL(n0->Children.size(), 0); - UNIT_ASSERT_VALUES_EQUAL(n0->HierarhicalParents.size(), 0); - - UNIT_ASSERT_VALUES_EQUAL(n1->Parents.size(), 0); - UNIT_ASSERT_VALUES_EQUAL(n1->Children.size(), 1); - UNIT_ASSERT_VALUES_EQUAL(n1->HierarhicalParents.size(), 0); - - UNIT_ASSERT_VALUES_EQUAL(n5->Parents.size(), 2); - UNIT_ASSERT_VALUES_EQUAL(n5->Children.size(), 0u); - UNIT_ASSERT_VALUES_EQUAL(n5->HierarhicalParents.size(), 4); - UNIT_ASSERT(std::find(n5->HierarhicalParents.cbegin(), n5->HierarhicalParents.cend(), n0) == n5->HierarhicalParents.end()); - UNIT_ASSERT(std::find(n5->HierarhicalParents.cbegin(), n5->HierarhicalParents.cend(), n1) != n5->HierarhicalParents.end()); - UNIT_ASSERT(std::find(n5->HierarhicalParents.cbegin(), n5->HierarhicalParents.cend(), n2) != n5->HierarhicalParents.end()); - UNIT_ASSERT(std::find(n5->HierarhicalParents.cbegin(), n5->HierarhicalParents.cend(), n3) != n5->HierarhicalParents.end()); - UNIT_ASSERT(std::find(n5->HierarhicalParents.cbegin(), n5->HierarhicalParents.cend(), n4) != n5->HierarhicalParents.end()); + UNIT_ASSERT_VALUES_EQUAL(n0->DirectParents.size(), 0); + UNIT_ASSERT_VALUES_EQUAL(n0->DirectChildren.size(), 0); + UNIT_ASSERT_VALUES_EQUAL(n0->AllParents.size(), 0); + + UNIT_ASSERT_VALUES_EQUAL(n1->DirectParents.size(), 0); + UNIT_ASSERT_VALUES_EQUAL(n1->DirectChildren.size(), 1); + UNIT_ASSERT_VALUES_EQUAL(n1->AllParents.size(), 0); + + UNIT_ASSERT_VALUES_EQUAL(n5->DirectParents.size(), 2); + UNIT_ASSERT_VALUES_EQUAL(n5->DirectChildren.size(), 0u); + UNIT_ASSERT_VALUES_EQUAL(n5->AllParents.size(), 4); + UNIT_ASSERT(std::find(n5->AllParents.cbegin(), n5->AllParents.cend(), n0) == n5->AllParents.end()); + UNIT_ASSERT(std::find(n5->AllParents.cbegin(), n5->AllParents.cend(), n1) != n5->AllParents.end()); + UNIT_ASSERT(std::find(n5->AllParents.cbegin(), n5->AllParents.cend(), n2) != n5->AllParents.end()); + UNIT_ASSERT(std::find(n5->AllParents.cbegin(), n5->AllParents.cend(), n3) != n5->AllParents.end()); + UNIT_ASSERT(std::find(n5->AllParents.cbegin(), n5->AllParents.cend(), n4) != n5->AllParents.end()); { std::set traversedNodes; diff --git a/ydb/core/persqueue/ut/pqtablet_ut.cpp b/ydb/core/persqueue/ut/pqtablet_ut.cpp index 86e5fe7f2df0..ad86fb76432d 100644 --- a/ydb/core/persqueue/ut/pqtablet_ut.cpp +++ b/ydb/core/persqueue/ut/pqtablet_ut.cpp @@ -331,8 +331,8 @@ void TPQTabletFixture::SendProposeTransactionRequest(const TProposeTransactionPa auto* operation = body->MutableOperations()->Add(); operation->SetPartitionId(txOp.Partition); if (txOp.Begin.Defined()) { - operation->SetBegin(*txOp.Begin); - operation->SetEnd(*txOp.End); + operation->SetCommitOffsetsBegin(*txOp.Begin); + operation->SetCommitOffsetsEnd(*txOp.End); operation->SetConsumer(*txOp.Consumer); } operation->SetPath(txOp.Path); diff --git a/ydb/core/persqueue/ut/user_action_processor_ut.cpp b/ydb/core/persqueue/ut/user_action_processor_ut.cpp index 27ed3ed4ad61..809a15874da3 100644 --- a/ydb/core/persqueue/ut/user_action_processor_ut.cpp +++ b/ydb/core/persqueue/ut/user_action_processor_ut.cpp @@ -653,8 +653,8 @@ void TUserActionProcessorFixture::SendProposeTransactionRequest(ui32 partition, auto* body = event->Record.MutableTxBody(); auto* operation = body->MutableOperations()->Add(); operation->SetPartitionId(partition); - operation->SetBegin(begin); - operation->SetEnd(end); + operation->SetCommitOffsetsBegin(begin); + operation->SetCommitOffsetsEnd(end); operation->SetConsumer(client); operation->SetPath(topic); body->SetImmediate(immediate); @@ -679,8 +679,8 @@ void TUserActionProcessorFixture::SendProposeTransactionRequest(const TProposeTr for (auto& txOp : params.TxOps) { auto* operation = body->MutableOperations()->Add(); operation->SetPartitionId(txOp.Partition); - operation->SetBegin(txOp.Begin); - operation->SetEnd(txOp.End); + operation->SetCommitOffsetsBegin(txOp.Begin); + operation->SetCommitOffsetsEnd(txOp.End); operation->SetConsumer(txOp.Consumer); operation->SetPath(txOp.Path); } diff --git a/ydb/core/persqueue/ut/ut_with_sdk/autoscaling_ut.cpp b/ydb/core/persqueue/ut/ut_with_sdk/autoscaling_ut.cpp index f101a70b5154..771eaf6cfd70 100644 --- a/ydb/core/persqueue/ut/ut_with_sdk/autoscaling_ut.cpp +++ b/ydb/core/persqueue/ut/ut_with_sdk/autoscaling_ut.cpp @@ -622,6 +622,110 @@ Y_UNIT_TEST_SUITE(TopicAutoscaling) { readSession2->Close(); } + Y_UNIT_TEST(PartitionSplit_OffsetCommit) { + TTopicSdkTestSetup setup = CreateSetup(); + TTopicClient client = setup.MakeClient(); + + TCreateTopicSettings createSettings; + createSettings + .BeginConfigurePartitioningSettings() + .MinActivePartitions(1) + .MaxActivePartitions(100) + .BeginConfigureAutoPartitioningSettings() + .UpUtilizationPercent(2) + .DownUtilizationPercent(1) + .StabilizationWindow(TDuration::Seconds(2)) + .Strategy(EAutoPartitioningStrategy::ScaleUp) + .EndConfigureAutoPartitioningSettings() + .EndConfigurePartitioningSettings(); + + TConsumerSettings consumers(createSettings, TEST_CONSUMER); + createSettings.AppendConsumers(consumers); + + client.CreateTopic(TEST_TOPIC, createSettings).Wait(); + + auto msg = TString(1_MB, 'a'); + + auto writeSession_1 = CreateWriteSession(client, "producer-1", 0, std::string{TEST_TOPIC}, false); + auto writeSession_2 = CreateWriteSession(client, "producer-2", 0, std::string{TEST_TOPIC}, false); + + { + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 1))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 2))); + Sleep(TDuration::Seconds(15)); + auto describe = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetTopicDescription().GetPartitions().size(), 1); + } + + { + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 3))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 4))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 5))); + UNIT_ASSERT(writeSession_2->Write(Msg(msg, 6))); + Sleep(TDuration::Seconds(15)); + auto describe = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetTopicDescription().GetPartitions().size(), 3); + } + + auto writeSession2_1 = CreateWriteSession(client, "producer-1", 1, std::string{TEST_TOPIC}, false); + auto writeSession2_2 = CreateWriteSession(client, "producer-2", 1, std::string{TEST_TOPIC}, false); + + { + UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 7))); + UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 8))); + UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 9))); + UNIT_ASSERT(writeSession2_2->Write(Msg(msg, 10))); + Sleep(TDuration::Seconds(15)); + auto describe2 = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe2.GetTopicDescription().GetPartitions().size(), 5); + } + + auto status = client.CommitOffset(TEST_TOPIC, 1, TEST_CONSUMER, 2).GetValueSync(); + UNIT_ASSERT(status.IsSuccess()); + + auto describeConsumerSettings = TDescribeConsumerSettings().IncludeStats(true); + auto result = client.DescribeConsumer(TEST_TOPIC, TEST_CONSUMER, describeConsumerSettings).GetValueSync(); + UNIT_ASSERT(result.IsSuccess()); + + auto description = result.GetConsumerDescription(); + UNIT_ASSERT(description.GetPartitions().size() == 5); + + auto stats_part_0_try_1 = description.GetPartitions().at(0).GetPartitionConsumerStats(); + UNIT_ASSERT(stats_part_0_try_1); + UNIT_ASSERT(stats_part_0_try_1->GetCommittedOffset() == 6); + + auto stats_part_1_try_1 = description.GetPartitions().at(1).GetPartitionConsumerStats(); + UNIT_ASSERT(stats_part_1_try_1); + UNIT_ASSERT(stats_part_1_try_1->GetCommittedOffset() == 2); + + auto stats_part_3_try_1 = description.GetPartitions().at(3).GetPartitionConsumerStats(); + UNIT_ASSERT(stats_part_3_try_1); + UNIT_ASSERT(stats_part_3_try_1->GetCommittedOffset() == 0); + + + + auto status2 = client.CommitOffset(TEST_TOPIC, 0, TEST_CONSUMER, 0).GetValueSync(); + UNIT_ASSERT(status2.IsSuccess()); + + auto result2 = client.DescribeConsumer(TEST_TOPIC, TEST_CONSUMER, describeConsumerSettings).GetValueSync(); + UNIT_ASSERT(result2.IsSuccess()); + + auto description2 = result2.GetConsumerDescription(); + UNIT_ASSERT(description2.GetPartitions().size() == 5); + + auto stats_part_0_try_2 = description.GetPartitions().at(0).GetPartitionConsumerStats(); + UNIT_ASSERT(stats_part_0_try_2); + UNIT_ASSERT(stats_part_0_try_2->GetCommittedOffset() == 6); + + auto stats_part_1_try_2 = description.GetPartitions().at(1).GetPartitionConsumerStats(); + UNIT_ASSERT(stats_part_1_try_2); + UNIT_ASSERT(stats_part_1_try_2->GetCommittedOffset() == 2); + + auto stats_part_3_try_2 = description.GetPartitions().at(3).GetPartitionConsumerStats(); + UNIT_ASSERT(stats_part_3_try_2); + UNIT_ASSERT(stats_part_3_try_2->GetCommittedOffset() == 0); + } + Y_UNIT_TEST(CommitTopPast_BeforeAutoscaleAwareSDK) { TTopicSdkTestSetup setup = CreateSetup(); setup.CreateTopicWithAutoscale(std::string{TEST_TOPIC}, std::string{TEST_CONSUMER}, 1, 100); @@ -648,7 +752,7 @@ Y_UNIT_TEST_SUITE(TopicAutoscaling) { UNIT_ASSERT_VALUES_EQUAL_C(NYdb::EStatus::SUCCESS, status.GetStatus(), "The consumer can commit at the end of the inactive partition."); status = client.CommitOffset(TEST_TOPIC, 0, TEST_CONSUMER, 0).GetValueSync(); - UNIT_ASSERT_VALUES_EQUAL_C(NYdb::EStatus::BAD_REQUEST, status.GetStatus(), "The consumer cannot commit an offset for inactive, read-to-the-end partitions."); + UNIT_ASSERT_VALUES_EQUAL_C(NYdb::EStatus::SUCCESS, status.GetStatus(), "The consumer can commit an offset for inactive, read-to-the-end partitions."); } Y_UNIT_TEST(ControlPlane_CreateAlterDescribe) { @@ -869,6 +973,703 @@ Y_UNIT_TEST_SUITE(TopicAutoscaling) { UNIT_ASSERT_VALUES_EQUAL(result.GetStatus(), NYdb::EStatus::BAD_REQUEST); } + Y_UNIT_TEST(PartitionSplit_DistributedTxCommit) { + TTopicSdkTestSetup setup = CreateSetup(); + TTopicClient client = setup.MakeClient(); + + TCreateTopicSettings createSettings; + createSettings + .BeginConfigurePartitioningSettings() + .MinActivePartitions(1) + .MaxActivePartitions(100) + .BeginConfigureAutoPartitioningSettings() + .UpUtilizationPercent(2) + .DownUtilizationPercent(1) + .StabilizationWindow(TDuration::Seconds(2)) + .Strategy(EAutoPartitioningStrategy::ScaleUp) + .EndConfigureAutoPartitioningSettings() + .EndConfigurePartitioningSettings() + .BeginAddConsumer() + .ConsumerName(TEST_CONSUMER); + client.CreateTopic(TEST_TOPIC, createSettings).Wait(); + + auto msg = TString(1_MB, 'a'); + + auto writeSession_1 = CreateWriteSession(client, "producer-1", 0, std::string{TEST_TOPIC}, false); + auto writeSession_2 = CreateWriteSession(client, "producer-2", 0, std::string{TEST_TOPIC}, false); + + { + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 1))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 2))); + Sleep(TDuration::Seconds(5)); + auto describe = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetTopicDescription().GetPartitions().size(), 1); + } + + { + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 3))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 4))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 5))); + UNIT_ASSERT(writeSession_2->Write(Msg(msg, 6))); + Sleep(TDuration::Seconds(15)); + auto describe = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetTopicDescription().GetPartitions().size(), 3); + } + + auto writeSession2_1 = CreateWriteSession(client, "producer-1", 1, std::string{TEST_TOPIC}, false); + auto writeSession2_2 = CreateWriteSession(client, "producer-2", 1, std::string{TEST_TOPIC}, false); + + { + UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 7))); + UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 8))); + UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 9))); + UNIT_ASSERT(writeSession2_2->Write(Msg(msg, 10))); + Sleep(TDuration::Seconds(15)); + auto describe2 = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe2.GetTopicDescription().GetPartitions().size(), 5); + } + + auto reader = client.CreateReadSession( + TReadSessionSettings() + .AutoPartitioningSupport(true) + .AppendTopics(TTopicReadSettings(TEST_TOPIC)) + .ConsumerName(TEST_CONSUMER)); + + TInstant deadlineTime = TInstant::Now() + TDuration::Seconds(5); + auto count = 0; + auto expected = 10; + while (deadlineTime > TInstant::Now()) { + for (auto event : reader->GetEvents(false)) { + if (auto* x = std::get_if(&event)) { + auto& messages = x->GetMessages(); + for (size_t i = 0u; i < messages.size(); ++i) { + count++; + auto& message = messages[i]; + message.Commit(); + Cerr << "SESSION EVENT read message: " << count << " from partition: " << message.GetPartitionSession()->GetPartitionId() << Endl << Flush; + } + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* sessionClosedEvent = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT" << x->DebugString() << Endl << Flush; + } else { + Cerr << "SESSION EVENT unhandled \n"; + } + + if (count == expected) { + break; + } + } + Sleep(TDuration::MilliSeconds(250)); + } + Sleep(TDuration::Seconds(5)); + UNIT_ASSERT_EQUAL(count, expected); + + auto describeConsumerSettings = TDescribeConsumerSettings().IncludeStats(true); + auto result = client.DescribeConsumer(TEST_TOPIC, TEST_CONSUMER, describeConsumerSettings).GetValueSync(); + UNIT_ASSERT(result.IsSuccess()); + + auto description = result.GetConsumerDescription(); + UNIT_ASSERT(description.GetPartitions().size() == 5); + + auto stats1 = description.GetPartitions().at(1).GetPartitionConsumerStats(); + UNIT_ASSERT(stats1); + UNIT_ASSERT(stats1->GetCommittedOffset() == 4); + } + + Y_UNIT_TEST(PartitionSplit_DistributedTxCommit_ChildFirst) { + TTopicSdkTestSetup setup = CreateSetup(); + TTopicClient client = setup.MakeClient(); + + TCreateTopicSettings createSettings; + createSettings + .BeginConfigurePartitioningSettings() + .MinActivePartitions(1) + .MaxActivePartitions(100) + .BeginConfigureAutoPartitioningSettings() + .UpUtilizationPercent(2) + .DownUtilizationPercent(1) + .StabilizationWindow(TDuration::Seconds(2)) + .Strategy(EAutoPartitioningStrategy::ScaleUp) + .EndConfigureAutoPartitioningSettings() + .EndConfigurePartitioningSettings() + .BeginAddConsumer() + .ConsumerName(TEST_CONSUMER); + + client.CreateTopic(TEST_TOPIC, createSettings).Wait(); + + auto msg = TString(1_MB, 'a'); + + auto writeSession_1 = CreateWriteSession(client, "producer-1", 0, std::string{TEST_TOPIC}, false); + auto writeSession_2 = CreateWriteSession(client, "producer-2", 0, std::string{TEST_TOPIC}, false); + + { + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 1))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 2))); + Sleep(TDuration::Seconds(5)); + auto describe = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetTopicDescription().GetPartitions().size(), 1); + } + + { + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 3))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 4))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 5))); + UNIT_ASSERT(writeSession_2->Write(Msg(msg, 6))); + Sleep(TDuration::Seconds(15)); + auto describe = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetTopicDescription().GetPartitions().size(), 3); + } + + auto writeSession2_1 = CreateWriteSession(client, "producer-1", 1, std::string{TEST_TOPIC}, false); + auto writeSession2_2 = CreateWriteSession(client, "producer-2", 1, std::string{TEST_TOPIC}, false); + + { + UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 7))); + UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 8))); + UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 9))); + UNIT_ASSERT(writeSession2_2->Write(Msg(msg, 10))); + Sleep(TDuration::Seconds(15)); + auto describe2 = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe2.GetTopicDescription().GetPartitions().size(), 5); + } + + auto reader = client.CreateReadSession( + TReadSessionSettings() + .AutoPartitioningSupport(true) + .AppendTopics(TTopicReadSettings(TEST_TOPIC)) + .ConsumerName(TEST_CONSUMER)); + + TInstant deadlineTime = TInstant::Now() + TDuration::Seconds(5); + auto count = 0; + auto expected = 10; + + std::vector partition0Messages; + + while(deadlineTime > TInstant::Now()) { + for (auto event : reader->GetEvents(false)) { + if (auto* x = std::get_if(&event)) { + auto& messages = x->GetMessages(); + for (size_t i = 0u; i < messages.size(); ++i) { + auto& message = messages[i]; + count++; + int partitionId = message.GetPartitionSession()->GetPartitionId(); + Cerr << "SESSION EVENT read message: " << count << " from partition: " << partitionId << Endl << Flush; + if (partitionId == 1) { + // Commit messages from partition 1 immediately + message.Commit(); + } else if (partitionId == 0) { + // Store messages from partition 0 for later + partition0Messages.push_back(message); + } + } + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* sessionClosedEvent = std::get_if(&event)) { + Cerr << sessionClosedEvent->DebugString() << Endl << Flush; + } else { + Cerr << "SESSION EVENT unhandled \n"; + } + + if (count == expected) { + break; + } + } + if (count == expected) { + break; + } + Sleep(TDuration::MilliSeconds(250)); + } + + UNIT_ASSERT_EQUAL(count, expected); + + Sleep(TDuration::Seconds(5)); + + auto describeConsumerSettings = TDescribeConsumerSettings().IncludeStats(true); + auto result = client.DescribeConsumer(TEST_TOPIC, TEST_CONSUMER, describeConsumerSettings).GetValueSync(); + UNIT_ASSERT(result.IsSuccess()); + + auto description = result.GetConsumerDescription(); + UNIT_ASSERT(description.GetPartitions().size() == 5); + + auto stats1 = description.GetPartitions().at(1).GetPartitionConsumerStats(); + UNIT_ASSERT(stats1); + + UNIT_ASSERT(stats1->GetCommittedOffset() == 0); + + for (auto& message : partition0Messages) { + message.Commit(); + } + + Sleep(TDuration::Seconds(5)); + + auto result2 = client.DescribeConsumer(TEST_TOPIC, TEST_CONSUMER, describeConsumerSettings).GetValueSync(); + UNIT_ASSERT(result.IsSuccess()); + + auto description2 = result2.GetConsumerDescription(); + UNIT_ASSERT(description2.GetPartitions().size() == 5); + + stats1 = description2.GetPartitions().at(1).GetPartitionConsumerStats(); + UNIT_ASSERT(stats1); + + UNIT_ASSERT(stats1->GetCommittedOffset() == 4); + } + + Y_UNIT_TEST(PartitionSplit_DistributedTxCommit_CheckSessionResetAfterCommit) { + TTopicSdkTestSetup setup = CreateSetup(); + TTopicClient client = setup.MakeClient(); + + TCreateTopicSettings createSettings; + createSettings + .BeginConfigurePartitioningSettings() + .MinActivePartitions(1) + .MaxActivePartitions(100) + .BeginConfigureAutoPartitioningSettings() + .UpUtilizationPercent(2) + .DownUtilizationPercent(1) + .StabilizationWindow(TDuration::Seconds(2)) + .Strategy(EAutoPartitioningStrategy::ScaleUp) + .EndConfigureAutoPartitioningSettings() + .EndConfigurePartitioningSettings() + .BeginAddConsumer() + .ConsumerName(TEST_CONSUMER); + + client.CreateTopic(TEST_TOPIC, createSettings).Wait(); + + auto msg = TString(1_MB, 'a'); + + auto writeSession_1 = CreateWriteSession(client, "producer-1", 0, std::string{TEST_TOPIC}, false); + auto writeSession_2 = CreateWriteSession(client, "producer-2", 0, std::string{TEST_TOPIC}, false); + auto seqNo = 1; + { + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + Sleep(TDuration::Seconds(5)); + auto describe = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetTopicDescription().GetPartitions().size(), 1); + } + + { + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_2->Write(Msg(msg, seqNo++))); + Sleep(TDuration::Seconds(15)); + auto describe = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetTopicDescription().GetPartitions().size(), 3); + } + + auto writeSession_3 = CreateWriteSession(client, "producer-2", 1, std::string{TEST_TOPIC}, false); + UNIT_ASSERT(writeSession_3->Write(Msg(TStringBuilder() << "message-" << seqNo, seqNo++))); + UNIT_ASSERT(writeSession_3->Write(Msg(TStringBuilder() << "message-" << seqNo, seqNo++))); + + auto reader = client.CreateReadSession( + TReadSessionSettings() + .AutoPartitioningSupport(true) + .AppendTopics(TTopicReadSettings(TEST_TOPIC)) + .ConsumerName(TEST_CONSUMER)); + + TInstant deadlineTime = TInstant::Now() + TDuration::Seconds(5); + + auto commitSent = false; + while(deadlineTime > TInstant::Now()) { + for (auto event : reader->GetEvents(false)) { + if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + auto& messages = x->GetMessages(); + for (size_t i = 0u; i < messages.size(); ++i) { + auto& message = messages[i]; + message.Commit(); + Cerr << "SESSION EVENT READ SeqNo: " << message.GetSeqNo() << Endl << Flush; + // check we get this SeqNo two times + if (message.GetSeqNo() == 6) { + if (!commitSent) { + commitSent = true; + Sleep(TDuration::MilliSeconds(300)); + auto status = client.CommitOffset(TEST_TOPIC, 0, TEST_CONSUMER, 0).GetValueSync(); + UNIT_ASSERT(status.IsSuccess()); + } else { + return; + } + } + } + UNIT_ASSERT(writeSession_3->Write(Msg(TStringBuilder() << "message-" << seqNo, seqNo++))); + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* sessionClosedEvent = std::get_if(&event)) { + Cerr << sessionClosedEvent->DebugString() << Endl << Flush; + } else { + Cerr << "SESSION EVENT unhandled \n"; + } + } + Sleep(TDuration::MilliSeconds(250)); + } + + UNIT_ASSERT(false); + } + + Y_UNIT_TEST(PartitionSplit_DistributedTxCommit_CheckOffsetCommitForDifferentCases_SplitedTopic) { + TTopicSdkTestSetup setup = CreateSetup(); + TTopicClient client = setup.MakeClient(); + + TCreateTopicSettings createSettings; + createSettings + .BeginConfigurePartitioningSettings() + .MinActivePartitions(1) + .MaxActivePartitions(100) + .BeginConfigureAutoPartitioningSettings() + .UpUtilizationPercent(2) + .DownUtilizationPercent(1) + .StabilizationWindow(TDuration::Seconds(2)) + .Strategy(EAutoPartitioningStrategy::ScaleUp) + .EndConfigureAutoPartitioningSettings() + .EndConfigurePartitioningSettings() + .BeginAddConsumer() + .ConsumerName(TEST_CONSUMER); + + client.CreateTopic(TEST_TOPIC, createSettings).Wait(); + + auto msg = TString(1_MB, 'a'); + + auto writeSession_1 = CreateWriteSession(client, "producer-1", 0, std::string{TEST_TOPIC}, false); + auto writeSession_2 = CreateWriteSession(client, "producer-2", 0, std::string{TEST_TOPIC}, false); + auto seqNo = 1; + { + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + Sleep(TDuration::Seconds(5)); + auto describe = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetTopicDescription().GetPartitions().size(), 1); + } + + { + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + writeSession_1->Close(); + + UNIT_ASSERT(writeSession_2->Write(Msg(msg, seqNo++))); + writeSession_2->Close(); + Sleep(TDuration::Seconds(15)); + auto describe = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetTopicDescription().GetPartitions().size(), 3); + } + + auto writeSession_3 = CreateWriteSession(client, "producer-2", 1, std::string{TEST_TOPIC}, false); + UNIT_ASSERT(writeSession_3->Write(Msg(TStringBuilder() << "message-" << seqNo, seqNo++))); + UNIT_ASSERT(writeSession_3->Write(Msg(TStringBuilder() << "message-" << seqNo, seqNo++))); + + auto reader = client.CreateReadSession( + TReadSessionSettings() + .AutoPartitioningSupport(true) + .AppendTopics(TTopicReadSettings(TEST_TOPIC)) + .ConsumerName(TEST_CONSUMER)); + + TInstant deadlineTime = TInstant::Now() + TDuration::Seconds(5); + + auto commitSent = false; + TString readSessionId = ""; + while(deadlineTime > TInstant::Now()) { + for (auto event : reader->GetEvents(false)) { + if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + auto& messages = x->GetMessages(); + for (size_t i = 0u; i < messages.size(); ++i) { + auto& message = messages[i]; + Cerr << "SESSION EVENT READ SeqNo: " << message.GetSeqNo() << Endl << Flush; + + if (commitSent) { + // read session not changed + UNIT_ASSERT_EQUAL(readSessionId, message.GetPartitionSession()->GetReadSessionId()); + } + + // check we NOT get this SeqNo two times + if (message.GetSeqNo() == 6) { + if (!commitSent) { + commitSent = true; + Sleep(TDuration::MilliSeconds(300)); + + readSessionId = message.GetPartitionSession()->GetReadSessionId(); + TCommitOffsetSettings commitSettings {.ReadSessionId_ = message.GetPartitionSession()->GetReadSessionId()}; + auto status = client.CommitOffset(TEST_TOPIC, 0, TEST_CONSUMER, 8, commitSettings).GetValueSync(); + UNIT_ASSERT(status.IsSuccess()); + + { + auto describeConsumerSettings = TDescribeConsumerSettings().IncludeStats(true); + auto result = client.DescribeConsumer(TEST_TOPIC, TEST_CONSUMER, describeConsumerSettings).GetValueSync(); + UNIT_ASSERT(result.IsSuccess()); + + auto description = result.GetConsumerDescription(); + + auto stats = description.GetPartitions().at(0).GetPartitionConsumerStats(); + UNIT_ASSERT(stats); + + UNIT_ASSERT(stats->GetCommittedOffset() == 8); + } + + // must be ignored, because commit to past + TCommitOffsetSettings commitToPastSettings {.ReadSessionId_ = message.GetPartitionSession()->GetReadSessionId()}; + auto commitToPastStatus = client.CommitOffset(TEST_TOPIC, 0, TEST_CONSUMER, 0, commitToPastSettings).GetValueSync(); + UNIT_ASSERT(commitToPastStatus.IsSuccess()); + + { + auto describeConsumerSettings = TDescribeConsumerSettings().IncludeStats(true); + auto result = client.DescribeConsumer(TEST_TOPIC, TEST_CONSUMER, describeConsumerSettings).GetValueSync(); + UNIT_ASSERT(result.IsSuccess()); + + auto description = result.GetConsumerDescription(); + + auto stats = description.GetPartitions().at(0).GetPartitionConsumerStats(); + UNIT_ASSERT(stats); + + UNIT_ASSERT(stats->GetCommittedOffset() == 8); + } + + TCommitOffsetSettings commitSettingsWrongSession {.ReadSessionId_ = "random_session"}; + auto statusWrongSession = client.CommitOffset(TEST_TOPIC, 0, TEST_CONSUMER, 0, commitSettingsWrongSession).GetValueSync(); + UNIT_ASSERT(!statusWrongSession.IsSuccess()); + + { + auto describeConsumerSettings = TDescribeConsumerSettings().IncludeStats(true); + auto result = client.DescribeConsumer(TEST_TOPIC, TEST_CONSUMER, describeConsumerSettings).GetValueSync(); + UNIT_ASSERT(result.IsSuccess()); + + auto description = result.GetConsumerDescription(); + + auto stats = description.GetPartitions().at(0).GetPartitionConsumerStats(); + UNIT_ASSERT(stats); + + UNIT_ASSERT(stats->GetCommittedOffset() == 8); + } + + } else { + UNIT_ASSERT(false); + } + } else { + message.Commit(); + } + } + UNIT_ASSERT(writeSession_3->Write(Msg(TStringBuilder() << "message-" << seqNo, seqNo++))); + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* sessionClosedEvent = std::get_if(&event)) { + Cerr << sessionClosedEvent->DebugString() << Endl << Flush; + } else { + Cerr << "SESSION EVENT unhandled \n"; + } + } + Sleep(TDuration::MilliSeconds(250)); + } + } + + Y_UNIT_TEST(PartitionSplit_DistributedTxCommit_CheckOffsetCommitForDifferentCases_NotSplitedTopic) { + TTopicSdkTestSetup setup = CreateSetup(); + TTopicClient client = setup.MakeClient(); + + TCreateTopicSettings createSettings; + createSettings + .BeginConfigurePartitioningSettings() + .MinActivePartitions(1) + .MaxActivePartitions(100) + .BeginConfigureAutoPartitioningSettings() + .UpUtilizationPercent(2) + .DownUtilizationPercent(1) + .StabilizationWindow(TDuration::Seconds(2)) + .Strategy(EAutoPartitioningStrategy::ScaleUp) + .EndConfigureAutoPartitioningSettings() + .EndConfigurePartitioningSettings() + .BeginAddConsumer() + .ConsumerName(TEST_CONSUMER); + + client.CreateTopic(TEST_TOPIC, createSettings).Wait(); + + auto msg = TString(1_MB, 'a'); + + auto writeSession_1 = CreateWriteSession(client, "producer-1", 0, std::string{TEST_TOPIC}, false); + auto seqNo = 1; + { + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, seqNo++))); + writeSession_1->Close(); + Sleep(TDuration::Seconds(15)); + auto describe = client.DescribeTopic(TEST_TOPIC).GetValueSync(); + UNIT_ASSERT_EQUAL(describe.GetTopicDescription().GetPartitions().size(), 1); + } + + auto writeSession_2 = CreateWriteSession(client, "producer-1", 0, std::string{TEST_TOPIC}, false); + auto reader = client.CreateReadSession( + TReadSessionSettings() + .AutoPartitioningSupport(true) + .AppendTopics(TTopicReadSettings(TEST_TOPIC)) + .ConsumerName(TEST_CONSUMER)); + + TInstant deadlineTime = TInstant::Now() + TDuration::Seconds(5); + + auto commitSent = false; + TString readSessionId = ""; + while(deadlineTime > TInstant::Now()) { + for (auto event : reader->GetEvents(false)) { + if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + auto& messages = x->GetMessages(); + for (size_t i = 0u; i < messages.size(); ++i) { + auto& message = messages[i]; + + if (commitSent) { + // read session not changed + UNIT_ASSERT_EQUAL(readSessionId, message.GetPartitionSession()->GetReadSessionId()); + } + + // check we NOT get this SeqNo two times + if (message.GetSeqNo() == 6) { + if (!commitSent) { + commitSent = true; + Sleep(TDuration::MilliSeconds(300)); + + readSessionId = message.GetPartitionSession()->GetReadSessionId(); + TCommitOffsetSettings commitSettings {.ReadSessionId_ = message.GetPartitionSession()->GetReadSessionId()}; + auto status = client.CommitOffset(TEST_TOPIC, 0, TEST_CONSUMER, 8, commitSettings).GetValueSync(); + UNIT_ASSERT(status.IsSuccess()); + + { + auto describeConsumerSettings = TDescribeConsumerSettings().IncludeStats(true); + auto result = client.DescribeConsumer(TEST_TOPIC, TEST_CONSUMER, describeConsumerSettings).GetValueSync(); + UNIT_ASSERT(result.IsSuccess()); + + auto description = result.GetConsumerDescription(); + + auto stats = description.GetPartitions().at(0).GetPartitionConsumerStats(); + UNIT_ASSERT(stats); + UNIT_ASSERT(stats->GetCommittedOffset() == 8); + } + + // must be ignored, because commit to past + TCommitOffsetSettings commitToPastSettings {.ReadSessionId_ = message.GetPartitionSession()->GetReadSessionId()}; + auto commitToPastStatus = client.CommitOffset(TEST_TOPIC, 0, TEST_CONSUMER, 0, commitToPastSettings).GetValueSync(); + UNIT_ASSERT(commitToPastStatus.IsSuccess()); + + { + auto describeConsumerSettings = TDescribeConsumerSettings().IncludeStats(true); + auto result = client.DescribeConsumer(TEST_TOPIC, TEST_CONSUMER, describeConsumerSettings).GetValueSync(); + UNIT_ASSERT(result.IsSuccess()); + + auto description = result.GetConsumerDescription(); + + auto stats = description.GetPartitions().at(0).GetPartitionConsumerStats(); + UNIT_ASSERT(stats); + UNIT_ASSERT(stats->GetCommittedOffset() == 8); + } + + TCommitOffsetSettings commitSettingsWrongSession {.ReadSessionId_ = "random_session"}; + auto statusWrongSession = client.CommitOffset(TEST_TOPIC, 0, TEST_CONSUMER, 0, commitSettingsWrongSession).GetValueSync(); + UNIT_ASSERT(!statusWrongSession.IsSuccess()); + + { + auto describeConsumerSettings = TDescribeConsumerSettings().IncludeStats(true); + auto result = client.DescribeConsumer(TEST_TOPIC, TEST_CONSUMER, describeConsumerSettings).GetValueSync(); + UNIT_ASSERT(result.IsSuccess()); + + auto description = result.GetConsumerDescription(); + + auto stats = description.GetPartitions().at(0).GetPartitionConsumerStats(); + UNIT_ASSERT(stats); + UNIT_ASSERT(stats->GetCommittedOffset() == 8); + } + + } else { + UNIT_ASSERT(false); + } + } else { + message.Commit(); + } + } + UNIT_ASSERT(writeSession_2->Write(Msg(msg, seqNo++))); + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* x = std::get_if(&event)) { + x->Confirm(); + Cerr << "SESSION EVENT " << x->DebugString() << Endl << Flush; + } else if (auto* sessionClosedEvent = std::get_if(&event)) { + Cerr << sessionClosedEvent->DebugString() << Endl << Flush; + } else { + Cerr << "SESSION EVENT unhandled \n"; + } + } + Sleep(TDuration::MilliSeconds(250)); + } + } + Y_UNIT_TEST(PartitionSplit_AutosplitByLoad) { TTopicSdkTestSetup setup = CreateSetup(); TTopicClient client = setup.MakeClient(); @@ -902,10 +1703,10 @@ Y_UNIT_TEST_SUITE(TopicAutoscaling) { { UNIT_ASSERT(writeSession_1->Write(Msg(msg, 3))); - UNIT_ASSERT(writeSession_2->Write(Msg(msg, 4))); + UNIT_ASSERT(writeSession_1->Write(Msg(msg, 4))); UNIT_ASSERT(writeSession_1->Write(Msg(msg, 5))); UNIT_ASSERT(writeSession_2->Write(Msg(msg, 6))); - Sleep(TDuration::Seconds(5)); + Sleep(TDuration::Seconds(15)); auto describe = client.DescribeTopic(TEST_TOPIC).GetValueSync(); UNIT_ASSERT_EQUAL(describe.GetTopicDescription().GetPartitions().size(), 3); } @@ -915,7 +1716,7 @@ Y_UNIT_TEST_SUITE(TopicAutoscaling) { { UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 7))); - UNIT_ASSERT(writeSession2_2->Write(Msg(msg, 8))); + UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 8))); UNIT_ASSERT(writeSession2_1->Write(Msg(msg, 9))); UNIT_ASSERT(writeSession2_2->Write(Msg(msg, 10))); Sleep(TDuration::Seconds(5)); diff --git a/ydb/core/persqueue/utils.cpp b/ydb/core/persqueue/utils.cpp index 7f7ca3d81e10..ccdc3ffe95c2 100644 --- a/ydb/core/persqueue/utils.cpp +++ b/ydb/core/persqueue/utils.cpp @@ -170,10 +170,10 @@ std::set TPartitionGraph::GetActiveChildren(ui32 id) const { const auto* n = queue.front(); queue.pop_front(); - if (n->Children.empty()) { + if (n->DirectChildren.empty()) { result.emplace(n->Id); } else { - queue.insert(queue.end(), n->Children.begin(), n->Children.end()); + queue.insert(queue.end(), n->DirectChildren.begin(), n->DirectChildren.end()); } } @@ -186,7 +186,7 @@ void Travers0(std::deque& queue, const std::functi queue.pop_front(); if (func(node->Id)) { - queue.insert(queue.end(), node->Children.begin(), node->Children.end()); + queue.insert(queue.end(), node->DirectChildren.begin(), node->DirectChildren.end()); } } } @@ -203,7 +203,7 @@ void TPartitionGraph::Travers(const std::function& func) const { continue; } - queue.insert(queue.end(), n.Children.begin(), n.Children.end()); + queue.insert(queue.end(), n.DirectChildren.begin(), n.DirectChildren.end()); } Travers0(queue, func); @@ -220,7 +220,7 @@ void TPartitionGraph::Travers(ui32 id, const std::function& func } std::deque queue; - queue.insert(queue.end(), n->Children.begin(), n->Children.end()); + queue.insert(queue.end(), n->DirectChildren.begin(), n->DirectChildren.end()); Travers0(queue, func); } @@ -266,17 +266,18 @@ std::unordered_map BuildGraph(const TCollection& pa } std::deque queue; - for(const auto& p : partitions) { + + for (const auto& p : partitions) { auto& node = result[GetPartitionId(p)]; - node.Children.reserve(p.ChildPartitionIdsSize()); + node.DirectChildren.reserve(p.ChildPartitionIdsSize()); for (auto id : p.GetChildPartitionIds()) { - node.Children.push_back(&result[id]); + node.DirectChildren.push_back(&result[id]); } - node.Parents.reserve(p.ParentPartitionIdsSize()); + node.DirectParents.reserve(p.ParentPartitionIdsSize()); for (auto id : p.GetParentPartitionIds()) { - node.Parents.push_back(&result[id]); + node.DirectParents.push_back(&result[id]); } if (p.GetParentPartitionIds().empty()) { @@ -284,24 +285,39 @@ std::unordered_map BuildGraph(const TCollection& pa } } - while(!queue.empty()) { + while (!queue.empty()) { auto* n = queue.front(); queue.pop_front(); bool allCompleted = true; - for(auto* c : n->Parents) { - if (c->HierarhicalParents.empty() && !c->Parents.empty()) { + for (auto* c : n->DirectParents) { + if (c->AllParents.empty() && !c->DirectParents.empty()) { allCompleted = false; break; } } if (allCompleted) { - for(auto* c : n->Parents) { - n->HierarhicalParents.insert(c->HierarhicalParents.begin(), c->HierarhicalParents.end()); - n->HierarhicalParents.insert(c); + for (auto* c : n->DirectParents) { + n->AllParents.insert(c->AllParents.begin(), c->AllParents.end()); + n->AllParents.insert(c); + } + queue.insert(queue.end(), n->DirectChildren.begin(), n->DirectChildren.end()); + } + } + + for (auto& [_, node] : result) { + queue.push_back(&node); + + while (!queue.empty()) { + auto* current = queue.front(); + queue.pop_front(); + + for (auto* child : current->DirectChildren) { + if (node.AllChildren.insert(child).second) { + queue.push_back(child); + } } - queue.insert(queue.end(), n->Children.begin(), n->Children.end()); } } @@ -316,11 +332,11 @@ TPartitionGraph::Node::Node(ui32 id, ui64 tabletId, const TString& from, const T } bool TPartitionGraph::Node::IsRoot() const { - return Parents.empty(); + return DirectParents.empty(); } bool TPartitionGraph::Node::IsParent(ui32 partitionId) const { - return AnyOf(Parents, [=](const auto& p) { + return AnyOf(DirectParents, [=](const auto& p) { return p->Id == partitionId; }); } diff --git a/ydb/core/persqueue/utils.h b/ydb/core/persqueue/utils.h index 4b4b296bdbb0..43eb519f85ef 100644 --- a/ydb/core/persqueue/utils.h +++ b/ydb/core/persqueue/utils.h @@ -44,11 +44,13 @@ class TPartitionGraph { TString To; // Direct parents of this node - std::vector Parents; + std::vector DirectParents; // Direct children of this node - std::vector Children; + std::vector DirectChildren; // All parents include parents of parents and so on - std::set HierarhicalParents; + std::set AllParents; + // All children include children of children and so on + std::set AllChildren; bool IsRoot() const; bool IsParent(ui32 partitionId) const; diff --git a/ydb/core/protos/kqp.proto b/ydb/core/protos/kqp.proto index 24b4df45df9f..5223925cd700 100644 --- a/ydb/core/protos/kqp.proto +++ b/ydb/core/protos/kqp.proto @@ -69,10 +69,38 @@ enum EIsolationLevel { message TTopicOperationsRequest { optional string Consumer = 1; - repeated Ydb.Topic.UpdateOffsetsInTransactionRequest.TopicOffsets Topics = 2; + repeated TopicOffsets Topics = 2; optional uint32 SupportivePartition = 3; + + message TopicOffsets { + // Topic path. + optional string path = 1; + + // Ranges of offsets by partitions. + repeated PartitionOffsets partitions = 2; + + message PartitionOffsets { + // Partition identifier. + optional int64 partition_id = 1; + + // List of offset ranges. + repeated OffsetsRange partition_offsets = 2; + + optional bool force_commit = 3; + optional bool kill_read_session = 4; + optional bool only_check_commited_to_finish = 5; + optional string read_session_id = 6; + + message OffsetsRange { + optional int64 start = 1; + optional int64 end = 2; + } + } + } } + + message TTopicOperationsResponse { message TWriteId { optional uint64 NodeId = 1; diff --git a/ydb/core/protos/msgbus_pq.proto b/ydb/core/protos/msgbus_pq.proto index 9e16ce29a372..ae4fe4ad0e91 100644 --- a/ydb/core/protos/msgbus_pq.proto +++ b/ydb/core/protos/msgbus_pq.proto @@ -472,7 +472,7 @@ message TPersQueuePartitionResponse { optional uint64 CreateTimestampMS = 6; //create Timestamp of record on Offset (next to be readed record); is not set if no such record exists (no lag) optional uint64 SizeLag = 7; optional uint64 WriteTimestampEstimateMS = 8; - + optional bool ClientHasAnyCommits = 9; } message TCmdGetOwnershipResult { diff --git a/ydb/core/protos/pqconfig.proto b/ydb/core/protos/pqconfig.proto index b2f9d7097285..2f27923c359e 100644 --- a/ydb/core/protos/pqconfig.proto +++ b/ydb/core/protos/pqconfig.proto @@ -904,7 +904,7 @@ message TUserInfo { optional uint64 OffsetRewindSum = 5; optional uint64 ReadRuleGeneration = 6; optional uint64 PartitionSessionId = 7; - + optional bool AnyCommits = 8; } message TPartitionClientInfo { @@ -952,11 +952,15 @@ message TYdsShardIterator { message TPartitionOperation { optional uint32 PartitionId = 1; - optional uint64 Begin = 2; - optional uint64 End = 3; + optional uint64 CommitOffsetsBegin = 2; + optional uint64 CommitOffsetsEnd = 3; optional string Consumer = 4; optional string Path = 5; // topic path optional uint32 SupportivePartition = 6; + optional bool ForceCommit = 7; + optional bool KillReadSession = 8; + optional bool OnlyCheckCommitedToFinish = 9; + optional string ReadSessionId = 10; }; message TWriteId { diff --git a/ydb/public/api/protos/ydb_topic.proto b/ydb/public/api/protos/ydb_topic.proto index a46af6cdf2bd..a45a8c673140 100644 --- a/ydb/public/api/protos/ydb_topic.proto +++ b/ydb/public/api/protos/ydb_topic.proto @@ -752,9 +752,10 @@ message CommitOffsetRequest { int64 partition_id = 3; // Path of consumer. string consumer = 4; - // Processed offset. int64 offset = 5; + // Read session identifier from StreamRead RPC. + string read_session_id = 6; } // Commit offset response sent from server to client. diff --git a/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/topic/control_plane.h b/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/topic/control_plane.h index 37ee274b22f3..c776e3f5b45a 100644 --- a/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/topic/control_plane.h +++ b/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/topic/control_plane.h @@ -766,6 +766,8 @@ struct TDescribePartitionSettings: public TOperationRequestSettings {}; +struct TCommitOffsetSettings : public TOperationRequestSettings { + FLUENT_SETTING_OPTIONAL(std::string, ReadSessionId); +}; } // namespace NYdb::NTopic diff --git a/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/topic/read_events.h b/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/topic/read_events.h index 9f4ab84f98c9..b619abeb5dc3 100644 --- a/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/topic/read_events.h +++ b/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/topic/read_events.h @@ -31,6 +31,11 @@ struct TPartitionSession: public TThrRefBase, public TPrintable { template > TPartitionStreamImpl(ui64 partitionStreamId, std::string topicPath, + std::string readSessionId, i64 partitionId, i64 assignId, i64 readOffset, @@ -617,6 +618,7 @@ class TPartitionStreamImpl : public TAPartitionStream { { TAPartitionStream::PartitionSessionId = partitionStreamId; TAPartitionStream::TopicPath = std::move(topicPath); + TAPartitionStream::ReadSessionId = std::move(readSessionId); TAPartitionStream::PartitionId = static_cast(partitionId); MaxCommittedOffset = static_cast(readOffset); } @@ -1333,6 +1335,7 @@ class TSingleClusterReadSessionImpl : public TEnableSelfContext::OnReadDoneImpl( LOG_LAZY(Log, TLOG_INFO, GetLogPrefix() << "Server session id: " << msg.session_id()); RetryState = nullptr; + ReadSessionId = msg.session_id(); // Successful init. Do nothing. ContinueReadingDataImpl(); @@ -1222,6 +1223,7 @@ inline void TSingleClusterReadSessionImpl::OnReadDoneImpl( Y_UNUSED(deferred); RetryState = nullptr; + ReadSessionId = msg.session_id(); LOG_LAZY(Log, TLOG_INFO, GetLogPrefix() << "Server session id: " << msg.session_id()); @@ -1321,8 +1323,12 @@ inline void TSingleClusterReadSessionImpl::OnReadDoneImpl( Y_ABORT_UNLESS(Lock.IsLocked()); auto partitionStream = MakeIntrusive>( - NextPartitionStreamId, msg.partition_session().path(), msg.partition_session().partition_id(), - msg.partition_session().partition_session_id(), msg.committed_offset(), + NextPartitionStreamId, + msg.partition_session().path(), + ReadSessionId, + msg.partition_session().partition_id(), + msg.partition_session().partition_session_id(), + msg.committed_offset(), SelfContext); NextPartitionStreamId += PartitionStreamIdStep; diff --git a/ydb/public/sdk/cpp/src/client/topic/impl/topic_impl.h b/ydb/public/sdk/cpp/src/client/topic/impl/topic_impl.h index 810c647c0786..5c2d927ea2fe 100644 --- a/ydb/public/sdk/cpp/src/client/topic/impl/topic_impl.h +++ b/ydb/public/sdk/cpp/src/client/topic/impl/topic_impl.h @@ -282,7 +282,9 @@ class TTopicClient::TImpl : public TClientImplCommon { request.set_partition_id(partitionId); request.set_consumer(TStringType{consumerName}); request.set_offset(offset); - + if (settings.ReadSessionId_) { + request.set_read_session_id(*settings.ReadSessionId_); + } return RunSimple( std::move(request), &Ydb::Topic::V1::TopicService::Stub::AsyncCommitOffset, diff --git a/ydb/services/deprecated/persqueue_v0/grpc_pq_actor.h b/ydb/services/deprecated/persqueue_v0/grpc_pq_actor.h index ece96617d623..80fa87a54102 100644 --- a/ydb/services/deprecated/persqueue_v0/grpc_pq_actor.h +++ b/ydb/services/deprecated/persqueue_v0/grpc_pq_actor.h @@ -943,6 +943,8 @@ class TReadSessionActor : public TActorBootstrapped { NPersQueue::TTopicsListController TopicsHandler; NPersQueue::TTopicsToConverter TopicsList; + + std::deque> Locks; }; } diff --git a/ydb/services/deprecated/persqueue_v0/grpc_pq_read_actor.cpp b/ydb/services/deprecated/persqueue_v0/grpc_pq_read_actor.cpp index 43f335ac67f0..df203a86c673 100644 --- a/ydb/services/deprecated/persqueue_v0/grpc_pq_read_actor.cpp +++ b/ydb/services/deprecated/persqueue_v0/grpc_pq_read_actor.cpp @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -144,8 +145,8 @@ TString PartitionResponseToLog(const NKikimrClient::TPersQueuePartitionResponse& class TPartitionActor : public NActors::TActorBootstrapped { public: TPartitionActor(const TActorId& parentId, const TString& clientId, const ui64 cookie, const TString& session, const ui32 generation, - const ui32 step, const NPersQueue::TTopicConverterPtr& topic, const ui32 partition, const ui64 tabletID, - const TReadSessionActor::TTopicCounters& counters, const TString& clientDC); + const ui32 step, const NPersQueue::TTopicConverterPtr& topic, const TString& database, const ui32 partition, const ui64 tabletID, + const TReadSessionActor::TTopicCounters& counters, const TString& clientDC, std::set parents); ~TPartitionActor(); void Bootstrap(const NActors::TActorContext& ctx); @@ -156,21 +157,24 @@ class TPartitionActor : public NActors::TActorBootstrapped { private: STFUNC(StateFunc) { switch (ev->GetTypeRewrite()) { - CFunc(NActors::TEvents::TSystem::Wakeup, HandleWakeup) - HFunc(TEvPQProxy::TEvDeadlineExceeded, Handle) + CFunc(NActors::TEvents::TSystem::Wakeup, HandleWakeup); + HFunc(TEvPQProxy::TEvDeadlineExceeded, Handle); - HFunc(NActors::TEvents::TEvPoisonPill, HandlePoison) - HFunc(TEvPQProxy::TEvRead, Handle) - HFunc(TEvPQProxy::TEvCommit, Handle) - HFunc(TEvPQProxy::TEvReleasePartition, Handle) - HFunc(TEvPQProxy::TEvLockPartition, Handle) - HFunc(TEvPQProxy::TEvGetStatus, Handle) - HFunc(TEvPQProxy::TEvRestartPipe, Handle) + HFunc(NActors::TEvents::TEvPoisonPill, HandlePoison); + HFunc(TEvPQProxy::TEvRead, Handle); + HFunc(TEvPQProxy::TEvCommit, Handle); + HFunc(TEvPQProxy::TEvReleasePartition, Handle); + HFunc(TEvPQProxy::TEvLockPartition, Handle); + HFunc(TEvPQProxy::TEvGetStatus, Handle); + HFunc(TEvPQProxy::TEvRestartPipe, Handle); HFunc(TEvTabletPipe::TEvClientDestroyed, Handle); HFunc(TEvTabletPipe::TEvClientConnected, Handle); HFunc(TEvPersQueue::TEvResponse, Handle); HFunc(TEvPersQueue::TEvHasDataInfoResponse, Handle); + + HFunc(NKqp::TEvKqp::TEvCreateSessionResponse, Handle); + HFunc(NKqp::TEvKqp::TEvQueryResponse, Handle); default: break; }; @@ -192,6 +196,9 @@ class TPartitionActor : public NActors::TActorBootstrapped { void Handle(TEvPersQueue::TEvResponse::TPtr& ev, const NActors::TActorContext& ctx); void Handle(TEvPersQueue::TEvHasDataInfoResponse::TPtr& ev, const NActors::TActorContext& ctx); + void Handle(NKqp::TEvKqp::TEvCreateSessionResponse::TPtr& ev, const NActors::TActorContext& ctx); + void Handle(NKqp::TEvKqp::TEvQueryResponse::TPtr& ev, const TActorContext& ctx); + void HandlePoison(NActors::TEvents::TEvPoisonPill::TPtr& ev, const NActors::TActorContext& ctx); void HandleWakeup(const NActors::TActorContext& ctx); @@ -202,6 +209,7 @@ class TPartitionActor : public NActors::TActorBootstrapped { void RestartPipe(const NActors::TActorContext& ctx, const TString& reason, const NPersQueue::NErrorCode::EErrorCode errorCode); void WaitDataInPartition(const NActors::TActorContext& ctx); void SendCommit(const ui64 readId, const ui64 offset, const TActorContext& ctx); + void CommitDone(ui64 cookie, const TActorContext& ctx); void SendPartitionReady(const TActorContext& ctx); private: @@ -214,6 +222,7 @@ class TPartitionActor : public NActors::TActorBootstrapped { const ui32 Step; NPersQueue::TTopicConverterPtr Topic; + TString Database; const ui32 Partition; const ui64 TabletID; @@ -237,6 +246,7 @@ class TPartitionActor : public NActors::TActorBootstrapped { ui64 EndOffset; ui64 SizeLag; + bool ClientHasAnyCommits = false; TString ReadGuid; // empty if not reading @@ -255,6 +265,9 @@ class TPartitionActor : public NActors::TActorBootstrapped { bool FirstRead; bool ReadingFinishedSent; + + std::unordered_map> Kqps; + std::set Parents; }; @@ -974,6 +987,7 @@ void TReadSessionActor::Handle(V1::TEvPQProxy::TEvAuthResultOk::TPtr& ev, const topicHolder.IsServerless = t.IsServerless; topicHolder.FolderId = t.FolderId; topicHolder.FullConverter = t.TopicNameConverter; + topicHolder.PartitionGraph = t.PartitionGraph; FullPathToConverter[t.TopicNameConverter->GetPrimaryPath()] = t.TopicNameConverter; const auto& second = t.TopicNameConverter->GetSecondaryPath(); if (!second.empty()) { @@ -995,14 +1009,21 @@ void TReadSessionActor::Handle(V1::TEvPQProxy::TEvAuthResultOk::TPtr& ev, const ctx.Schedule(Min(CommitInterval, CHECK_ACL_DELAY), new TEvents::TEvWakeup()); } else { for (auto& [name, t] : ev->Get()->TopicAndTablets) { - if (Topics.find(t.TopicNameConverter->GetInternalName()) == Topics.end()) { + auto it = Topics.find(t.TopicNameConverter->GetInternalName()); + if (it == Topics.end()) { CloseSession(TStringBuilder() << "list of topics changed - new topic '" << t.TopicNameConverter->GetInternalName() << "' found", NPersQueue::NErrorCode::BAD_REQUEST, ctx); return; } + it->second.PartitionGraph = t.PartitionGraph; } } + + while (!Locks.empty()) { + ctx.Send(ctx.SelfID, std::move(Locks.front())); + Locks.pop_front(); + } } @@ -1043,6 +1064,20 @@ void TReadSessionActor::Handle(TEvPersQueue::TEvLockPartition::TPtr& ev, const T ); return; } + + auto* partitionNode = jt->second.PartitionGraph->GetPartition(record.GetPartition()); + if (!partitionNode) { + LOG_DEBUG_S( + ctx, NKikimrServices::PQ_READ_PROXY, + PQ_LOG_PREFIX << " lock for unknown partition = " << record.GetPartition() + ); + Locks.push_back(ev->Release()); + if (!AuthInflight) { + SendAuthRequest(ctx); + } + return; + } + // ToDo[counters] if (NumPartitionsFromTopic[intName]++ == 0) { if (AppData(ctx)->PQConfig.GetTopicsAreFirstClassCitizen()) { @@ -1057,8 +1092,8 @@ void TReadSessionActor::Handle(TEvPersQueue::TEvLockPartition::TPtr& ev, const T IActor* partitionActor = new TPartitionActor( ctx.SelfID, InternalClientId, Cookie, Session, record.GetGeneration(), - record.GetStep(), jt->second.FullConverter, record.GetPartition(), record.GetTabletId(), it->second, - ClientDC + record.GetStep(), jt->second.FullConverter, Database.empty() ? NKikimr::NPQ::GetDatabaseFromConfig(AppData(ctx)->PQConfig) : Database, record.GetPartition(), record.GetTabletId(), it->second, + ClientDC, jt->second.PartitionGraph->GetPartition(record.GetPartition())->AllParents ); TActorId actorId = ctx.Register(partitionActor); @@ -1819,8 +1854,8 @@ void TReadSessionActor::Handle(TEvPQProxy::TEvReadingFinished::TPtr& ev, const T TPartitionActor::TPartitionActor( const TActorId& parentId, const TString& internalClientId, const ui64 cookie, const TString& session, - const ui32 generation, const ui32 step, const NPersQueue::TTopicConverterPtr& topic, const ui32 partition, - const ui64 tabletID, const TReadSessionActor::TTopicCounters& counters, const TString& clientDC + const ui32 generation, const ui32 step, const NPersQueue::TTopicConverterPtr& topic, const TString& database, const ui32 partition, + const ui64 tabletID, const TReadSessionActor::TTopicCounters& counters, const TString& clientDC, std::set parents ) : ParentId(parentId) , InternalClientId(internalClientId) @@ -1830,6 +1865,7 @@ TPartitionActor::TPartitionActor( , Generation(generation) , Step(step) , Topic(topic) + , Database(database) , Partition(partition) , TabletID(tabletID) , ReadOffset(0) @@ -1856,6 +1892,7 @@ TPartitionActor::TPartitionActor( , Counters(counters) , FirstRead(true) , ReadingFinishedSent(false) + , Parents(parents) { } @@ -1888,28 +1925,82 @@ void TPartitionActor::CheckRelease(const TActorContext& ctx) { void TPartitionActor::SendCommit(const ui64 readId, const ui64 offset, const TActorContext& ctx) { - NKikimrClient::TPersQueueRequest request; - request.MutablePartitionRequest()->SetTopic(Topic->GetClientsideName()); - request.MutablePartitionRequest()->SetPartition(Partition); - request.MutablePartitionRequest()->SetCookie(readId); + if (!ClientHasAnyCommits && Parents.size() != 0) { + std::vector commits; + for (auto& parent: Parents) { + NKikimr::NGRpcProxy::V1::TDistributedCommitHelper::TCommitInfo commit {.PartitionId = parent->Id, .Offset = Max(), .KillReadSession = false, .OnlyCheckCommitedToFinish = true, .ReadSessionId = Session}; + commits.push_back(commit); + } + NKikimr::NGRpcProxy::V1::TDistributedCommitHelper::TCommitInfo commit {.PartitionId = Partition, .Offset = (i64)offset, .KillReadSession = false, .OnlyCheckCommitedToFinish = false, .ReadSessionId = Session}; + commits.push_back(commit); + auto kqp = std::make_shared(Database, InternalClientId, Topic->GetPrimaryPath(), commits, readId); + Kqps.emplace(readId, kqp); - Y_ABORT_UNLESS(PipeClient); + kqp->SendCreateSessionRequest(ctx); + } else { + NKikimrClient::TPersQueueRequest request; + request.MutablePartitionRequest()->SetTopic(Topic->GetClientsideName()); + request.MutablePartitionRequest()->SetPartition(Partition); + request.MutablePartitionRequest()->SetCookie(readId); - ActorIdToProto(PipeClient, request.MutablePartitionRequest()->MutablePipeClient()); - auto commit = request.MutablePartitionRequest()->MutableCmdSetClientOffset(); - commit->SetClientId(InternalClientId); - commit->SetOffset(offset); - Y_ABORT_UNLESS(!Session.empty()); - commit->SetSessionId(Session); + Y_ABORT_UNLESS(PipeClient); - LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Topic->GetPrintableString() << " partition:" - << Partition << " committing to position " << offset << " prev " << CommittedOffset - << " end " << EndOffset << " by cookie " << readId); + ActorIdToProto(PipeClient, request.MutablePartitionRequest()->MutablePipeClient()); + auto commit = request.MutablePartitionRequest()->MutableCmdSetClientOffset(); + commit->SetClientId(InternalClientId); + commit->SetOffset(offset); + Y_ABORT_UNLESS(!Session.empty()); + commit->SetSessionId(Session); - TAutoPtr req(new TEvPersQueue::TEvRequest); - req->Record.Swap(&request); + LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Topic->GetPrintableString() << " partition:" + << Partition << " committing to position " << offset << " prev " << CommittedOffset + << " end " << EndOffset << " by cookie " << readId); - NTabletPipe::SendData(ctx, PipeClient, req.Release()); + TAutoPtr req(new TEvPersQueue::TEvRequest); + req->Record.Swap(&request); + + NTabletPipe::SendData(ctx, PipeClient, req.Release()); + } +} + +void TPartitionActor::CommitDone(ui64 cookie, const TActorContext& ctx) { + if (CommitsInfly.empty()) { + LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Topic->GetPrintableString() + << " partition:" << Partition + << " unwaited commit-response with cookie " << cookie << "; waiting for nothing"); + return; + } + ui64 readId = CommitsInfly.front().first; + + if (cookie != readId) { + LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Topic->GetPrintableString() + << " partition:" << Partition + << " unwaited commit-response with cookie " << cookie << "; waiting for " << readId); + return; + } + + Counters.Commits.Inc(); + ClientHasAnyCommits = true; + + CommittedOffset = CommitsInfly.front().second; + CommitsInfly.pop_front(); + if (readId != Max()) //this readId is reserved for upcommits on client skipping with ClientCommitOffset + ctx.Send(ParentId, new TEvPQProxy::TEvCommitDone(readId, Topic, Partition)); + LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Topic->GetPrintableString() + << " partition:" << Partition + << " commit done to position " << CommittedOffset << " endOffset " << EndOffset << " with cookie " << readId); + + while (!CommitsInfly.empty() && CommitsInfly.front().second == Max()) { //this is cookies that have no effect on this partition + readId = CommitsInfly.front().first; + CommitsInfly.pop_front(); + ctx.Send(ParentId, new TEvPQProxy::TEvCommitDone(readId, Topic, Partition)); + LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Topic->GetPrintableString() + << "partition :" << Partition + << " commit done with no effect with cookie " << readId); + } + + CheckRelease(ctx); + PipeGeneration = 0; //reset tries counter - all ok } void TPartitionActor::SendPartitionReady(const TActorContext& ctx) { @@ -2050,6 +2141,7 @@ void TPartitionActor::Handle(TEvPersQueue::TEvResponse::TPtr& ev, const TActorCo if (resp.HasWriteTimestampMS()) WTime = resp.GetWriteTimestampMS(); WriteTimestampEstimateMs = resp.GetWriteTimestampEstimateMS(); + ClientHasAnyCommits = resp.GetClientHasAnyCommits(); InitDone = true; PipeGeneration = 0; //reset tries counter - all ok LOG_INFO_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " INIT DONE " << Topic->GetPrintableString() @@ -2065,43 +2157,8 @@ void TPartitionActor::Handle(TEvPersQueue::TEvResponse::TPtr& ev, const TActorCo return; } - if (!result.HasCmdReadResult()) { //this is commit response - if (CommitsInfly.empty()) { - LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Topic->GetPrintableString() - << " partition:" << Partition - << " unwaited commit-response with cookie " << result.GetCookie() << "; waiting for nothing"); - return; - } - ui64 readId = CommitsInfly.front().first; - - if (result.GetCookie() != readId) { - LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Topic->GetPrintableString() - << " partition:" << Partition - << " unwaited commit-response with cookie " << result.GetCookie() << "; waiting for " << readId); - return; - } - - Counters.Commits.Inc(); - - CommittedOffset = CommitsInfly.front().second; - CommitsInfly.pop_front(); - if (readId != Max()) //this readId is reserved for upcommits on client skipping with ClientCommitOffset - ctx.Send(ParentId, new TEvPQProxy::TEvCommitDone(readId, Topic, Partition)); - LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Topic->GetPrintableString() - << " partition:" << Partition - << " commit done to position " << CommittedOffset << " endOffset " << EndOffset << " with cookie " << readId); - - while (!CommitsInfly.empty() && CommitsInfly.front().second == Max()) { //this is cookies that have no effect on this partition - readId = CommitsInfly.front().first; - CommitsInfly.pop_front(); - ctx.Send(ParentId, new TEvPQProxy::TEvCommitDone(readId, Topic, Partition)); - LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Topic->GetPrintableString() - << "partition :" << Partition - << " commit done with no effect with cookie " << readId); - } - - CheckRelease(ctx); - PipeGeneration = 0; //reset tries counter - all ok + if (!result.HasCmdReadResult()) { // this is commit response + CommitDone(result.GetCookie(), ctx); return; } @@ -2316,6 +2373,46 @@ void TPartitionActor::Handle(TEvPQProxy::TEvLockPartition::TPtr& ev, const TActo InitLockPartition(ctx); } +void TPartitionActor::Handle(NKqp::TEvKqp::TEvCreateSessionResponse::TPtr& ev, const NActors::TActorContext& ctx) { + auto kqpIt = Kqps.find(ev->Cookie); + if (kqpIt == Kqps.end()) { + ctx.Send(ParentId, new TEvPQProxy::TEvCloseSession("unexpected cookie at KQP create session response", NPersQueue::NErrorCode::ERROR)); + return; + } + + if (!kqpIt->second->Handle(ev, ctx)) { + const auto& record = ev->Get()->Record; + ctx.Send(ParentId, new TEvPQProxy::TEvCloseSession("status is not ok: " + record.GetError(), NPersQueue::NErrorCode::ERROR)); + } +} + +void TPartitionActor::Handle(NKqp::TEvKqp::TEvQueryResponse::TPtr& ev, const TActorContext& ctx) { + auto& record = ev->Get()->Record; + + auto kqpIt = Kqps.find(ev->Cookie); + if (kqpIt == Kqps.end()) { + ctx.Send(ParentId, new TEvPQProxy::TEvCloseSession("unexpected cookie at KQP query response", NPersQueue::NErrorCode::ERROR)); + return; + } + + if (record.GetYdbStatus() != Ydb::StatusIds::SUCCESS) { + + auto kqpQueryError = TStringBuilder() << "Kqp error. Status# " << record.GetYdbStatus() << ", "; + + NYql::TIssues issues; + NYql::IssuesFromMessage(record.GetResponse().GetQueryIssues(), issues); + kqpQueryError << issues.ToString(); + + ctx.Send(ParentId, new TEvPQProxy::TEvCloseSession(kqpQueryError, NPersQueue::NErrorCode::ERROR)); + return; + } + + auto step = kqpIt->second->Handle(ev, ctx); + if (step == NKikimr::NGRpcProxy::V1::TDistributedCommitHelper::ECurrentStep::DONE) { + CommitDone(ev->Cookie, ctx); + } +} + void TPartitionActor::InitStartReading(const TActorContext& ctx) { Y_ABORT_UNLESS(AllPrepareInited); diff --git a/ydb/services/lib/actors/type_definitions.h b/ydb/services/lib/actors/type_definitions.h index 6446d6965ab1..5c169e0d8948 100644 --- a/ydb/services/lib/actors/type_definitions.h +++ b/ydb/services/lib/actors/type_definitions.h @@ -1,5 +1,6 @@ #pragma once +#include "ydb/core/persqueue/utils.h" #include #include @@ -25,6 +26,7 @@ struct TTopicInitInfo { TString FolderId; NKikimrPQ::TPQTabletConfig::EMeteringMode MeteringMode; THashMap Partitions; + std::shared_ptr PartitionGraph; }; using TTopicInitInfoMap = THashMap; @@ -45,6 +47,7 @@ struct TTopicHolder { TVector Groups; THashMap Partitions; + std::shared_ptr PartitionGraph; inline static TTopicHolder FromTopicInfo(const TTopicInitInfo& info) { @@ -59,6 +62,7 @@ struct TTopicHolder { .MeteringMode = info.MeteringMode, .FullConverter = info.TopicNameConverter, .Partitions = info.Partitions, + .PartitionGraph = info.PartitionGraph }; } }; diff --git a/ydb/services/persqueue_v1/actors/commit_offset_actor.cpp b/ydb/services/persqueue_v1/actors/commit_offset_actor.cpp index 9e51df7359ec..471162c5f9ae 100644 --- a/ydb/services/persqueue_v1/actors/commit_offset_actor.cpp +++ b/ydb/services/persqueue_v1/actors/commit_offset_actor.cpp @@ -29,7 +29,6 @@ TCommitOffsetActor::TCommitOffsetActor( } - TCommitOffsetActor::~TCommitOffsetActor() = default; @@ -76,7 +75,6 @@ void TCommitOffsetActor::Bootstrap(const TActorContext& ctx) { )); } - void TCommitOffsetActor::Die(const TActorContext& ctx) { if (PipeClient) NTabletPipe::CloseClient(ctx, PipeClient); @@ -87,7 +85,6 @@ void TCommitOffsetActor::Die(const TActorContext& ctx) { } void TCommitOffsetActor::Handle(TEvPQProxy::TEvAuthResultOk::TPtr& ev, const TActorContext& ctx) { - LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, "CommitOffset auth ok, got " << ev->Get()->TopicAndTablets.size() << " topics"); TopicAndTablets = std::move(ev->Get()->TopicAndTablets); if (TopicAndTablets.empty()) { @@ -102,42 +99,64 @@ void TCommitOffsetActor::Handle(TEvPQProxy::TEvAuthResultOk::TPtr& ev, const TAc return; } - ui64 tabletId = topicInitInfo.Partitions.at(PartitionId).TabletId; + auto commitRequest = dynamic_cast(GetProtoRequest()); - NTabletPipe::TClientConfig clientConfig; - clientConfig.RetryPolicy = { - .RetryLimitCount = 6, - .MinRetryTime = TDuration::MilliSeconds(10), - .MaxRetryTime = TDuration::MilliSeconds(100), - .BackoffMultiplier = 2, - .DoFirstRetryInstantly = true - }; - - PipeClient = ctx.Register(NTabletPipe::CreateClient(ctx.SelfID, tabletId, clientConfig)); + auto* partitionNode = topicInitInfo.PartitionGraph->GetPartition(commitRequest->partition_id()); - auto client_req = dynamic_cast(GetProtoRequest()); + if (partitionNode->AllParents.size() == 0 && partitionNode->DirectChildren.size() == 0) { + SendCommit(topicInitInfo, commitRequest, ctx); + } else { + auto killReadSession = commitRequest->read_session_id().empty(); + std::vector commits; - NKikimrClient::TPersQueueRequest request; - request.MutablePartitionRequest()->SetTopic(topicInitInfo.TopicNameConverter->GetPrimaryPath()); - request.MutablePartitionRequest()->SetPartition(client_req->partition_id()); + for (auto& parent: partitionNode->AllParents) { + TDistributedCommitHelper::TCommitInfo commit {.PartitionId = parent->Id, .Offset = Max(), .KillReadSession = killReadSession, .OnlyCheckCommitedToFinish = false}; + commits.push_back(commit); + } - Y_ABORT_UNLESS(PipeClient); + for (auto& child: partitionNode->AllChildren) { + TDistributedCommitHelper::TCommitInfo commit {.PartitionId = child->Id, .Offset = 0, .KillReadSession = killReadSession, .OnlyCheckCommitedToFinish = false}; + commits.push_back(commit); + } - auto commit = request.MutablePartitionRequest()->MutableCmdSetClientOffset(); - commit->SetClientId(ClientId); - commit->SetOffset(client_req->offset()); - commit->SetStrict(true); + TDistributedCommitHelper::TCommitInfo commit {.PartitionId = partitionNode->Id, .Offset = commitRequest->offset(), .KillReadSession = killReadSession, .OnlyCheckCommitedToFinish = false}; - LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, "strict CommitOffset, partition " << client_req->partition_id() - << " committing to position " << client_req->offset() /*<< " prev " << CommittedOffset - << " end " << EndOffset << " by cookie " << readId*/); + if (!commitRequest->read_session_id().empty()) { + commit.ReadSessionId = commitRequest->read_session_id(); + } + commits.push_back(commit); - TAutoPtr req(new TEvPersQueue::TEvRequest); - req->Record.Swap(&request); + Kqp = std::make_unique(Request().GetDatabaseName().GetOrElse(TString()), ClientId, topic, commits); + Kqp->SendCreateSessionRequest(ctx); + } +} - NTabletPipe::SendData(ctx, PipeClient, req.Release()); +void TCommitOffsetActor::Handle(NKqp::TEvKqp::TEvCreateSessionResponse::TPtr& ev, const NActors::TActorContext& ctx) { + if (!Kqp->Handle(ev, ctx)) { + AnswerError(ev->Get()->Record.GetError(), PersQueue::ErrorCode::ERROR, ctx); + } } +void TCommitOffsetActor::Handle(NKqp::TEvKqp::TEvQueryResponse::TPtr& ev, const TActorContext& ctx) { + auto& record = ev->Get()->Record; + if (record.GetYdbStatus() != Ydb::StatusIds::SUCCESS) { + LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, "strict CommitOffset failed. Kqp error: " << ev->Get()->Record); + + Ydb::Topic::CommitOffsetResult result; + Request().SendResult(result, record.GetYdbStatus()); + Die(ctx); + return; + } + + auto step = Kqp->Handle(ev, ctx); + + if (step == TDistributedCommitHelper::ECurrentStep::DONE) { + Ydb::Topic::CommitOffsetResult result; + Request().SendResult(result, Ydb::StatusIds::SUCCESS); + Die(ctx); + return; + } +} void TCommitOffsetActor::Handle(TEvPersQueue::TEvResponse::TPtr& ev, const TActorContext& ctx) { if (ev->Get()->Record.GetStatus() != NMsgBusProxy::MSTATUS_OK) { @@ -157,18 +176,54 @@ void TCommitOffsetActor::Handle(TEvPersQueue::TEvResponse::TPtr& ev, const TActo Die(ctx); } +void TCommitOffsetActor::SendCommit(const TTopicInitInfo& topic, const Ydb::Topic::CommitOffsetRequest* commitRequest, const TActorContext& ctx) { + ui64 tabletId = topic.Partitions.at(PartitionId).TabletId; -void TCommitOffsetActor::AnswerError(const TString& errorReason, const PersQueue::ErrorCode::ErrorCode errorCode, const NActors::TActorContext& ctx) { + NTabletPipe::TClientConfig clientConfig; + clientConfig.RetryPolicy = { + .RetryLimitCount = 6, + .MinRetryTime = TDuration::MilliSeconds(10), + .MaxRetryTime = TDuration::MilliSeconds(100), + .BackoffMultiplier = 2, + .DoFirstRetryInstantly = true + }; + + PipeClient = ctx.Register(NTabletPipe::CreateClient(ctx.SelfID, tabletId, clientConfig)); + + NKikimrClient::TPersQueueRequest request; + request.MutablePartitionRequest()->SetTopic(topic.TopicNameConverter->GetPrimaryPath()); + request.MutablePartitionRequest()->SetPartition(commitRequest->partition_id()); + + Y_ABORT_UNLESS(PipeClient); + auto commit = request.MutablePartitionRequest()->MutableCmdSetClientOffset(); + commit->SetClientId(ClientId); + commit->SetOffset(commitRequest->offset()); + commit->SetStrict(true); + if (!commitRequest->read_session_id().empty()) { + commit->SetSessionId(commitRequest->read_session_id()); + } + + LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, "strict CommitOffset, partition " << commitRequest->partition_id() + << " committing to position " << commitRequest->offset() /*<< " prev " << CommittedOffset + << " end " << EndOffset << " by cookie " << readId*/); + + TAutoPtr req(new TEvPersQueue::TEvRequest); + req->Record.Swap(&request); + + NTabletPipe::SendData(ctx, PipeClient, req.Release()); +} + +void TCommitOffsetActor::AnswerError(const TString& errorReason, const PersQueue::ErrorCode::ErrorCode errorCode, const NActors::TActorContext& ctx) { Ydb::Topic::CommitOffsetResponse response; response.mutable_operation()->set_ready(true); auto issue = response.mutable_operation()->add_issues(); FillIssue(issue, errorCode, errorReason); - response.mutable_operation()->set_status(ConvertPersQueueInternalCodeToStatus(errorCode)); - Reply(ConvertPersQueueInternalCodeToStatus(errorCode), response.operation().issues(), ctx); + auto status = ConvertPersQueueInternalCodeToStatus(errorCode); + response.mutable_operation()->set_status(status); + Reply(status, response.operation().issues(), ctx); } - void TCommitOffsetActor::Handle(TEvPQProxy::TEvCloseSession::TPtr& ev, const TActorContext& ctx) { AnswerError(ev->Get()->Reason, ev->Get()->ErrorCode, ctx); } @@ -186,5 +241,4 @@ void TCommitOffsetActor::Handle(TEvTabletPipe::TEvClientDestroyed::TPtr& ev, con AnswerError(TStringBuilder() <<"pipe to tablet destroyed" << ev->Get()->TabletId, PersQueue::ErrorCode::TABLET_PIPE_DISCONNECTED, ctx); } - } diff --git a/ydb/services/persqueue_v1/actors/commit_offset_actor.h b/ydb/services/persqueue_v1/actors/commit_offset_actor.h index 6eefc867ebb7..6daa6df3c54d 100644 --- a/ydb/services/persqueue_v1/actors/commit_offset_actor.h +++ b/ydb/services/persqueue_v1/actors/commit_offset_actor.h @@ -1,7 +1,10 @@ #pragma once #include "events.h" +#include "distributed_commit_helper.h" + +#include #include #include @@ -52,6 +55,9 @@ class TCommitOffsetActor : public TRpcOperationRequestActor Kqp; }; } diff --git a/ydb/services/persqueue_v1/actors/distributed_commit_helper.cpp b/ydb/services/persqueue_v1/actors/distributed_commit_helper.cpp new file mode 100644 index 000000000000..eb6410dc55b2 --- /dev/null +++ b/ydb/services/persqueue_v1/actors/distributed_commit_helper.cpp @@ -0,0 +1,126 @@ +#include "distributed_commit_helper.h" +#include "ydb/core/kqp/common/simple/services.h" + +namespace NKikimr::NGRpcProxy::V1 { + +TDistributedCommitHelper::TDistributedCommitHelper(TString database, TString consumer, TString path, std::vector commits, ui64 cookie) + : DataBase(database) + , Consumer(consumer) + , Path(path) + , Commits(std::move(commits)) + , Step(BEGIN_TRANSACTION_SENDED) + , Cookie(cookie) +{} + +TDistributedCommitHelper::ECurrentStep TDistributedCommitHelper::Handle(NKqp::TEvKqp::TEvQueryResponse::TPtr& ev, const TActorContext& ctx) { + switch (Step) { + case BEGIN_TRANSACTION_SENDED: + Step = OFFSETS_SENDED; + SendCommits(ev, ctx); + break; + case OFFSETS_SENDED: + Step = COMMIT_SENDED; + CommitTx(ctx); + break; + case COMMIT_SENDED: + Step = DONE; + CloseKqpSession(ctx); + break; + case DONE: + break; + } + return Step; +} + +void TDistributedCommitHelper::SendCreateSessionRequest(const TActorContext& ctx) { + auto ev = MakeCreateSessionRequest(); + ctx.Send(NKqp::MakeKqpProxyID(ctx.SelfID.NodeId()), ev.Release(), 0, Cookie); +} + +void TDistributedCommitHelper::BeginTransaction(const NActors::TActorContext& ctx) { + auto begin = MakeHolder(); + + begin->Record.MutableRequest()->SetAction(NKikimrKqp::QUERY_ACTION_BEGIN_TX); + begin->Record.MutableRequest()->MutableTxControl()->mutable_begin_tx()->mutable_serializable_read_write(); + begin->Record.MutableRequest()->SetSessionId(KqpSessionId); + begin->Record.MutableRequest()->SetDatabase(DataBase); + + ctx.Send(NKqp::MakeKqpProxyID(ctx.SelfID.NodeId()), begin.Release(), 0, Cookie); +} + +bool TDistributedCommitHelper::Handle(NKqp::TEvKqp::TEvCreateSessionResponse::TPtr& ev, const TActorContext& ctx) { + const auto& record = ev->Get()->Record; + + if (record.GetYdbStatus() != Ydb::StatusIds::SUCCESS) { + return false; + } + + KqpSessionId = record.GetResponse().GetSessionId(); + Y_ABORT_UNLESS(!KqpSessionId.empty()); + BeginTransaction(ctx); + return true; +} + +void TDistributedCommitHelper::CloseKqpSession(const TActorContext& ctx) { + if (KqpSessionId) { + auto ev = MakeCloseSessionRequest(); + ctx.Send(NKqp::MakeKqpProxyID(ctx.SelfID.NodeId()), ev.Release(), 0, Cookie); + KqpSessionId = ""; + } +} + +THolder TDistributedCommitHelper::MakeCreateSessionRequest() { + auto ev = MakeHolder(); + ev->Record.MutableRequest()->SetDatabase(DataBase); + return ev; +} + +THolder TDistributedCommitHelper::MakeCloseSessionRequest() { + auto ev = MakeHolder(); + ev->Record.MutableRequest()->SetSessionId(KqpSessionId); + return ev; +} + +void TDistributedCommitHelper::SendCommits(NKqp::TEvKqp::TEvQueryResponse::TPtr& ev, const NActors::TActorContext& ctx) { + auto& record = ev->Get()->Record; + TxId = record.GetResponse().GetTxMeta().id(); + Y_ABORT_UNLESS(!TxId.empty()); + + auto offsets = MakeHolder(); + offsets->Record.MutableRequest()->SetDatabase(DataBase); + offsets->Record.MutableRequest()->SetSessionId(KqpSessionId); + offsets->Record.MutableRequest()->SetType(NKikimrKqp::QUERY_TYPE_UNDEFINED); + offsets->Record.MutableRequest()->SetAction(NKikimrKqp::QUERY_ACTION_TOPIC); + offsets->Record.MutableRequest()->MutableTxControl()->set_tx_id(TxId); + offsets->Record.MutableRequest()->MutableTopicOperations()->SetConsumer(Consumer); + + auto* topic = offsets->Record.MutableRequest()->MutableTopicOperations()->AddTopics(); + topic->set_path(Path); + + for(auto &commit: Commits) { + auto* partition = topic->add_partitions(); + partition->set_partition_id(commit.PartitionId); + partition->set_force_commit(true); + partition->set_kill_read_session(commit.KillReadSession); + partition->set_only_check_commited_to_finish(commit.OnlyCheckCommitedToFinish); + partition->set_read_session_id(commit.ReadSessionId); + auto* offset = partition->add_partition_offsets(); + offset->set_end(commit.Offset); + } + + ctx.Send(NKqp::MakeKqpProxyID(ctx.SelfID.NodeId()), offsets.Release(), 0, Cookie); +} + +void TDistributedCommitHelper::CommitTx(const NActors::TActorContext& ctx) { + auto commit = MakeHolder(); + + commit->Record.MutableRequest()->SetAction(NKikimrKqp::QUERY_ACTION_COMMIT_TX); + commit->Record.MutableRequest()->MutableTxControl()->set_tx_id(TxId); + commit->Record.MutableRequest()->MutableTxControl()->set_commit_tx(true); + commit->Record.MutableRequest()->SetSessionId(KqpSessionId); + commit->Record.MutableRequest()->SetDatabase(DataBase); + + ctx.Send(NKqp::MakeKqpProxyID(ctx.SelfID.NodeId()), commit.Release(), 0, Cookie); +} + +} // namespace NKikimr::NGRpcProxy::V1 diff --git a/ydb/services/persqueue_v1/actors/distributed_commit_helper.h b/ydb/services/persqueue_v1/actors/distributed_commit_helper.h new file mode 100644 index 000000000000..7b14d47c8e90 --- /dev/null +++ b/ydb/services/persqueue_v1/actors/distributed_commit_helper.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include + +namespace NKikimr::NGRpcProxy::V1 { + +using namespace NKikimr::NGRpcService; + +class TDistributedCommitHelper { +public: + enum ECurrentStep { + BEGIN_TRANSACTION_SENDED, + OFFSETS_SENDED, + COMMIT_SENDED, + DONE + }; + + struct TCommitInfo { + ui64 PartitionId; + i64 Offset; + bool KillReadSession; + bool OnlyCheckCommitedToFinish; + TString ReadSessionId; + }; + + TDistributedCommitHelper(TString database, TString consumer, TString path, std::vector commits, ui64 cookie = 0); + + ECurrentStep Handle(NKqp::TEvKqp::TEvQueryResponse::TPtr& ev, const TActorContext& ctx); + void SendCreateSessionRequest(const TActorContext& ctx); + void BeginTransaction(const NActors::TActorContext& ctx); + bool Handle(NKqp::TEvKqp::TEvCreateSessionResponse::TPtr& ev, const TActorContext& ctx); + +private: + void CloseKqpSession(const TActorContext& ctx); + THolder MakeCreateSessionRequest(); + THolder MakeCloseSessionRequest(); + void SendCommits(NKqp::TEvKqp::TEvQueryResponse::TPtr& ev, const NActors::TActorContext& ctx); + void CommitTx(const NActors::TActorContext& ctx); + +private: + TString DataBase; + TString Consumer; + TString Path; + std::vector Commits; + ECurrentStep Step; + ui64 Cookie; + + TString TxId; + TString KqpSessionId; +}; + +} // namespace NKikimr::NGRpcProxy::V1 diff --git a/ydb/services/persqueue_v1/actors/events.h b/ydb/services/persqueue_v1/actors/events.h index e19c7295dc04..bf12ade4567c 100644 --- a/ydb/services/persqueue_v1/actors/events.h +++ b/ydb/services/persqueue_v1/actors/events.h @@ -89,6 +89,7 @@ struct TEvPQProxy { EvReadingStarted, EvReadingFinished, EvAlterTopicResponse, + EvParentCommitedToFinish, EvEnd }; @@ -407,17 +408,27 @@ struct TEvPQProxy { struct TEvCommitDone : public NActors::TEventLocal { - explicit TEvCommitDone(const ui64 assignId, const ui64 startCookie, const ui64 lastCookie, const ui64 offset) + explicit TEvCommitDone(const ui64 assignId, const ui64 startCookie, const ui64 lastCookie, const ui64 offset, const ui64 endOffset) : AssignId(assignId) , StartCookie(startCookie) , LastCookie(lastCookie) , Offset(offset) + , EndOffset(endOffset) { } ui64 AssignId; ui64 StartCookie; ui64 LastCookie; ui64 Offset; + ui64 EndOffset; + }; + + struct TEvParentCommitedToFinish : public NActors::TEventLocal { + explicit TEvParentCommitedToFinish(ui64 parentPartitionId) + : ParentPartitionId(parentPartitionId) + { } + + ui64 ParentPartitionId; }; struct TEvReleasePartition : public NActors::TEventLocal { @@ -474,11 +485,12 @@ struct TEvPQProxy { }; struct TEvPartitionStatus : public NActors::TEventLocal { - TEvPartitionStatus(const TPartitionId& partition, const ui64 offset, const ui64 endOffset, const ui64 writeTimestampEstimateMs, ui64 nodeId, ui64 generation, + TEvPartitionStatus(const TPartitionId& partition, const ui64 offset, const ui64 endOffset, const ui64 writeTimestampEstimateMs, ui64 nodeId, ui64 generation, bool clientHasAnyCommits, bool init = true) : Partition(partition) , Offset(offset) , EndOffset(endOffset) + , ClientHasAnyCommits(clientHasAnyCommits) , WriteTimestampEstimateMs(writeTimestampEstimateMs) , NodeId(nodeId) , Generation(generation) @@ -488,6 +500,7 @@ struct TEvPQProxy { TPartitionId Partition; ui64 Offset; ui64 EndOffset; + bool ClientHasAnyCommits; ui64 WriteTimestampEstimateMs; ui64 NodeId; ui64 Generation; diff --git a/ydb/services/persqueue_v1/actors/partition_actor.cpp b/ydb/services/persqueue_v1/actors/partition_actor.cpp index a44de8029ab6..3f4c9ac82b2d 100644 --- a/ydb/services/persqueue_v1/actors/partition_actor.cpp +++ b/ydb/services/persqueue_v1/actors/partition_actor.cpp @@ -25,8 +25,9 @@ TPartitionActor::TPartitionActor( const TActorId& parentId, const TString& clientId, const TString& clientPath, const ui64 cookie, const TString& session, const TPartitionId& partition, const ui32 generation, const ui32 step, const ui64 tabletID, const TTopicCounters& counters, bool commitsDisabled, - const TString& clientDC, bool rangesMode, const NPersQueue::TTopicConverterPtr& topic, - bool directRead, bool useMigrationProtocol, ui32 maxTimeLagMs, ui64 readTimestampMs + const TString& clientDC, bool rangesMode, const NPersQueue::TTopicConverterPtr& topic, const TString& database, + bool directRead, bool useMigrationProtocol, ui32 maxTimeLagMs, ui64 readTimestampMs, std::set parents, + std::unordered_set notCommitedToFinishParents ) : ParentId(parentId) , ClientId(clientId) @@ -64,34 +65,35 @@ TPartitionActor::TPartitionActor( , WaitDataCookie(0) , WaitForData(false) , LockCounted(false) + , Parents(parents) , Counters(counters) , CommitsDisabled(commitsDisabled) , CommitCookie(1) , Topic(topic) + , Database(database) , DirectRead(directRead) , UseMigrationProtocol(useMigrationProtocol) , FirstRead(true) , ReadingFinishedSent(false) + , NotCommitedToFinishParents(notCommitedToFinishParents) { } void TPartitionActor::MakeCommit(const TActorContext& ctx) { ui64 offset = ClientReadOffset; - if (CommitsDisabled) - return; - if (CommitsInfly.size() > MAX_COMMITS_INFLY) + if (CommitsDisabled || NotCommitedToFinishParents.size() != 0 || CommitsInfly.size() >= MAX_COMMITS_INFLY) return; //Ranges mode if (!NextRanges.Empty() && NextRanges.Min() == ClientCommitOffset) { - auto first = NextRanges.begin(); - offset = first->second; - NextRanges.EraseInterval(first->first, first->second); + auto firstRange = NextRanges.begin(); + offset = firstRange->second; + NextRanges.EraseInterval(firstRange->first, firstRange->second); ClientCommitOffset = offset; ++CommitCookie; - CommitsInfly.push_back(std::pair(CommitCookie, {CommitCookie, offset, ctx.Now()})); + CommitsInfly.emplace_back(CommitCookie, TCommitInfo{CommitCookie, offset, ctx.Now()}); if (Counters.SLITotal) Counters.SLITotal.Inc(); @@ -106,10 +108,10 @@ void TPartitionActor::MakeCommit(const TActorContext& ctx) { if (it != NextCommits.end() && *it == 0) { //commit of readed in prev session data NextCommits.erase(NextCommits.begin()); if (ClientReadOffset <= ClientCommitOffset) { - ctx.Send(ParentId, new TEvPQProxy::TEvCommitDone(Partition.AssignId, 0, 0, CommittedOffset)); + ctx.Send(ParentId, new TEvPQProxy::TEvCommitDone(Partition.AssignId, 0, 0, CommittedOffset, EndOffset)); } else { ClientCommitOffset = ClientReadOffset; - CommitsInfly.push_back(std::pair(0, {0, ClientReadOffset, ctx.Now()})); + CommitsInfly.emplace_back(0, TCommitInfo{0, ClientReadOffset, ctx.Now()}); if (Counters.SLITotal) Counters.SLITotal.Inc(); if (PipeClient) //if not then pipe will be recreated soon and SendCommit will be done @@ -141,7 +143,7 @@ void TPartitionActor::MakeCommit(const TActorContext& ctx) { Y_ABORT_UNLESS(offset > ClientCommitOffset); ClientCommitOffset = offset; - CommitsInfly.push_back(std::pair(readId, {startReadId, offset, ctx.Now()})); + CommitsInfly.emplace_back(readId, TCommitInfo{startReadId, offset, ctx.Now()}); if (Counters.SLITotal) Counters.SLITotal.Inc(); @@ -158,28 +160,81 @@ void TPartitionActor::Bootstrap(const TActorContext& ctx) { } void TPartitionActor::SendCommit(const ui64 readId, const ui64 offset, const TActorContext& ctx) { - NKikimrClient::TPersQueueRequest request; - request.MutablePartitionRequest()->SetTopic(Topic->GetPrimaryPath()); - request.MutablePartitionRequest()->SetPartition(Partition.Partition); - request.MutablePartitionRequest()->SetCookie(readId); + if (!ClientHasAnyCommits && Parents.size() != 0) { + std::vector commits; + for (auto& parent: Parents) { + TDistributedCommitHelper::TCommitInfo commit {.PartitionId = parent->Id, .Offset = Max(), .KillReadSession = false, .OnlyCheckCommitedToFinish = true, .ReadSessionId = Session}; + commits.push_back(commit); + } + TDistributedCommitHelper::TCommitInfo commit {.PartitionId = Partition.Partition, .Offset = (i64)offset, .KillReadSession = false, .OnlyCheckCommitedToFinish = false, .ReadSessionId = Session}; + commits.push_back(commit); + auto kqp = std::make_shared(Database, ClientId, Topic->GetPrimaryPath(), commits, readId); + Kqps.emplace(readId, kqp); - Y_ABORT_UNLESS(PipeClient); + kqp->SendCreateSessionRequest(ctx); + } else { + NKikimrClient::TPersQueueRequest request; + request.MutablePartitionRequest()->SetTopic(Topic->GetPrimaryPath()); + request.MutablePartitionRequest()->SetPartition(Partition.Partition); + request.MutablePartitionRequest()->SetCookie(readId); - ActorIdToProto(PipeClient, request.MutablePartitionRequest()->MutablePipeClient()); - auto commit = request.MutablePartitionRequest()->MutableCmdSetClientOffset(); - commit->SetClientId(ClientId); - commit->SetOffset(offset); - Y_ABORT_UNLESS(!Session.empty()); - commit->SetSessionId(Session); + Y_ABORT_UNLESS(PipeClient); - LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Partition - << " committing to position " << offset << " prev " << CommittedOffset - << " end " << EndOffset << " by cookie " << readId); + ActorIdToProto(PipeClient, request.MutablePartitionRequest()->MutablePipeClient()); + auto commit = request.MutablePartitionRequest()->MutableCmdSetClientOffset(); + commit->SetClientId(ClientId); + commit->SetOffset(offset); + Y_ABORT_UNLESS(!Session.empty()); + commit->SetSessionId(Session); - TAutoPtr req(new TEvPersQueue::TEvRequest); - req->Record.Swap(&request); + LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Partition + << " committing to position " << offset << " prev " << CommittedOffset + << " end " << EndOffset << " by cookie " << readId); - NTabletPipe::SendData(ctx, PipeClient, req.Release()); + TAutoPtr req(new TEvPersQueue::TEvRequest); + req->Record.Swap(&request); + + NTabletPipe::SendData(ctx, PipeClient, req.Release()); + } +} + +void TPartitionActor::Handle(NKqp::TEvKqp::TEvCreateSessionResponse::TPtr& ev, const NActors::TActorContext& ctx) { + auto kqpIt = Kqps.find(ev->Cookie); + if (kqpIt == Kqps.end()) { + ctx.Send(ParentId, new TEvPQProxy::TEvCloseSession("unexpected cookie at KQP create session response", PersQueue::ErrorCode::ERROR)); + return; + } + + if (!kqpIt->second->Handle(ev, ctx)) { + const auto& record = ev->Get()->Record; + ctx.Send(ParentId, new TEvPQProxy::TEvCloseSession("status is not ok: " + record.GetError(), PersQueue::ErrorCode::ERROR)); + } +} + +void TPartitionActor::Handle(NKqp::TEvKqp::TEvQueryResponse::TPtr& ev, const TActorContext& ctx) { + auto& record = ev->Get()->Record; + + auto kqpIt = Kqps.find(ev->Cookie); + if (kqpIt == Kqps.end()) { + ctx.Send(ParentId, new TEvPQProxy::TEvCloseSession("unexpected cookie at KQP query response", PersQueue::ErrorCode::ERROR)); + return; + } + + if (record.GetYdbStatus() != Ydb::StatusIds::SUCCESS) { + auto kqpQueryError = TStringBuilder() << "Kqp error. Status# " << record.GetYdbStatus() << ", "; + + NYql::TIssues issues; + NYql::IssuesFromMessage(record.GetResponse().GetQueryIssues(), issues); + kqpQueryError << issues.ToString(); + + ctx.Send(ParentId, new TEvPQProxy::TEvCloseSession(kqpQueryError, PersQueue::ErrorCode::ERROR)); + return; + } + + auto step = kqpIt->second->Handle(ev, ctx); + if (step == TDistributedCommitHelper::ECurrentStep::DONE) { + CommitDone(ev->Cookie, ctx); + } } void TPartitionActor::SendPublishDirectRead(const ui64 directReadId, const TActorContext& ctx) { @@ -232,7 +287,6 @@ void TPartitionActor::SendForgetDirectRead(const ui64 directReadId, const TActor NTabletPipe::SendData(ctx, PipeClient, req.Release()); } - void TPartitionActor::RestartPipe(const TActorContext& ctx, const TString& reason, const NPersQueue::NErrorCode::EErrorCode errorCode) { if (!PipeClient) return; @@ -256,7 +310,6 @@ void TPartitionActor::RestartPipe(const TActorContext& ctx, const TString& reaso ctx.Schedule(TDuration::MilliSeconds(RESTART_PIPE_DELAY_MS), new TEvPQProxy::TEvRestartPipe()); } - void TPartitionActor::Handle(TEvPQProxy::TEvDirectReadAck::TPtr& ev, const TActorContext& ctx) { auto it = DirectReadResults.find(ev->Get()->DirectReadId); @@ -295,8 +348,6 @@ void TPartitionActor::Handle(TEvPQProxy::TEvDirectReadAck::TPtr& ev, const TActo } - - void TPartitionActor::Handle(const TEvPQProxy::TEvRestartPipe::TPtr&, const TActorContext& ctx) { Y_ABORT_UNLESS(!PipeClient); @@ -544,6 +595,10 @@ bool FillBatchedData( return hasData; } +void TPartitionActor::Handle(TEvPQProxy::TEvParentCommitedToFinish::TPtr& ev, const TActorContext& ctx) { + NotCommitedToFinishParents.erase(ev->Get()->ParentPartitionId); + MakeCommit(ctx); +} void TPartitionActor::Handle(TEvPersQueue::TEvResponse::TPtr& ev, const TActorContext& ctx) { @@ -614,6 +669,7 @@ void TPartitionActor::Handle(TEvPersQueue::TEvResponse::TPtr& ev, const TActorCo EndOffset = resp.GetEndOffset(); SizeLag = resp.GetSizeLag(); WriteTimestampEstimateMs = resp.GetWriteTimestampEstimateMS(); + ClientHasAnyCommits = resp.GetClientHasAnyCommits(); ClientCommitOffset = ReadOffset = CommittedOffset = resp.HasOffset() ? resp.GetOffset() : 0; Y_ABORT_UNLESS(EndOffset >= CommittedOffset); @@ -628,7 +684,7 @@ void TPartitionActor::Handle(TEvPersQueue::TEvResponse::TPtr& ev, const TActorCo if (!StartReading) { - ctx.Send(ParentId, new TEvPQProxy::TEvPartitionStatus(Partition, CommittedOffset, EndOffset, WriteTimestampEstimateMs, NodeId, TabletGeneration)); + ctx.Send(ParentId, new TEvPQProxy::TEvPartitionStatus(Partition, CommittedOffset, EndOffset, WriteTimestampEstimateMs, NodeId, TabletGeneration, ClientHasAnyCommits)); } else { InitStartReading(ctx); } @@ -679,42 +735,8 @@ void TPartitionActor::Handle(TEvPersQueue::TEvResponse::TPtr& ev, const TActorCo return; } - if (!(result.HasCmdReadResult() || result.HasCmdPrepareReadResult() || result.HasCmdPublishReadResult() || result.HasCmdForgetReadResult())) { //this is commit response - if (CommitsInfly.empty()) { - LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Partition - << " unwaited commit-response with cookie " << result.GetCookie() << "; waiting for nothing"); - return; - } - ui64 readId = CommitsInfly.front().first; - - if (result.GetCookie() != readId) { - LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Partition - << " unwaited commit-response with cookie " << result.GetCookie() << "; waiting for " << readId); - return; - } - - Counters.Commits.Inc(); - - ui32 commitDurationMs = (ctx.Now() - CommitsInfly.front().second.StartTime).MilliSeconds(); - if (Counters.CommitLatency) { - Counters.CommitLatency.IncFor(commitDurationMs, 1); - } - - if (Counters.SLIBigLatency && commitDurationMs >= AppData(ctx)->PQConfig.GetCommitLatencyBigMs()) { - Counters.SLIBigLatency.Inc(); - } - - CommittedOffset = CommitsInfly.front().second.Offset; - ui64 startReadId = CommitsInfly.front().second.StartReadId; - ctx.Send(ParentId, new TEvPQProxy::TEvCommitDone(Partition.AssignId, startReadId, readId, CommittedOffset)); - - CommitsInfly.pop_front(); - - LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Partition - << " commit done to position " << CommittedOffset << " endOffset " << EndOffset << " with cookie " << readId); - - PipeGeneration = 0; //reset tries counter - all ok - MakeCommit(ctx); + if (!(result.HasCmdReadResult() || result.HasCmdPrepareReadResult() || result.HasCmdPublishReadResult() || result.HasCmdForgetReadResult())) { // this is commit response + CommitDone(result.GetCookie(), ctx); return; } @@ -881,6 +903,46 @@ void TPartitionActor::Handle(TEvPersQueue::TEvResponse::TPtr& ev, const TActorCo PipeGeneration = 0; //reset tries counter - all ok } +void TPartitionActor::CommitDone(ui64 cookie, const TActorContext& ctx) { + if (CommitsInfly.empty()) { + LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Partition + << " unwaited commit-response with cookie " << cookie << "; waiting for nothing"); + return; + } + ui64 readId = CommitsInfly.front().first; + + if (cookie != readId) { + LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Partition + << " unwaited commit-response with cookie " << cookie << "; waiting for " << readId); + return; + } + + Counters.Commits.Inc(); + ClientHasAnyCommits = true; + + ui32 commitDurationMs = (ctx.Now() - CommitsInfly.front().second.StartTime).MilliSeconds(); + if (Counters.CommitLatency) { + Counters.CommitLatency.IncFor(commitDurationMs, 1); + } + + if (Counters.SLIBigLatency && commitDurationMs >= AppData(ctx)->PQConfig.GetCommitLatencyBigMs()) { + Counters.SLIBigLatency.Inc(); + } + + CommittedOffset = CommitsInfly.front().second.Offset; + ui64 startReadId = CommitsInfly.front().second.StartReadId; + ctx.Send(ParentId, new TEvPQProxy::TEvCommitDone(Partition.AssignId, startReadId, readId, CommittedOffset, EndOffset)); + + Kqps.erase(CommitsInfly.front().first); + CommitsInfly.pop_front(); + + LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Partition + << " commit done to position " << CommittedOffset << " endOffset " << EndOffset << " with cookie " << readId); + + PipeGeneration = 0; //reset tries counter - all ok + MakeCommit(ctx); +} + void TPartitionActor::SendPartitionReady(const TActorContext& ctx) { LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " " << Partition << " ready for read with readOffset " << ReadOffset << " endOffset " << EndOffset); @@ -912,13 +974,10 @@ void TPartitionActor::Handle(TEvTabletPipe::TEvClientDestroyed::TPtr& ev, const RestartPipe(ctx, TStringBuilder() << "pipe to tablet is dead " << ev->Get()->TabletId, NPersQueue::NErrorCode::TABLET_PIPE_DISCONNECTED); } - - void TPartitionActor::Handle(TEvPQProxy::TEvGetStatus::TPtr&, const TActorContext& ctx) { - ctx.Send(ParentId, new TEvPQProxy::TEvPartitionStatus(Partition, CommittedOffset, EndOffset, WriteTimestampEstimateMs, NodeId, TabletGeneration, false)); + ctx.Send(ParentId, new TEvPQProxy::TEvPartitionStatus(Partition, CommittedOffset, EndOffset, WriteTimestampEstimateMs, NodeId, TabletGeneration, ClientHasAnyCommits, false)); } - void TPartitionActor::Handle(TEvPQProxy::TEvLockPartition::TPtr& ev, const TActorContext& ctx) { ClientReadOffset = ev->Get()->ReadOffset; ClientCommitOffset = ev->Get()->CommitOffset; @@ -992,7 +1051,7 @@ void TPartitionActor::InitStartReading(const TActorContext& ctx) { return; } Y_ABORT_UNLESS(CommitsInfly.empty()); - CommitsInfly.push_back(std::pair(Max(), {Max(), ClientCommitOffset.GetOrElse(0), ctx.Now()})); + CommitsInfly.emplace_back(Max(), TCommitInfo{Max(), ClientCommitOffset.GetOrElse(0), ctx.Now()}); if (Counters.SLITotal) Counters.SLITotal.Inc(); if (PipeClient) //pipe will be recreated soon diff --git a/ydb/services/persqueue_v1/actors/partition_actor.h b/ydb/services/persqueue_v1/actors/partition_actor.h index 1cbbc5bcddf4..b2eec72172fc 100644 --- a/ydb/services/persqueue_v1/actors/partition_actor.h +++ b/ydb/services/persqueue_v1/actors/partition_actor.h @@ -1,14 +1,17 @@ #pragma once +#include #include "events.h" #include "partition_id.h" #include #include +#include #include #include #include +#include #include #include @@ -65,15 +68,16 @@ class TPartitionActor : public NActors::TActorBootstrapped { static constexpr ui32 MAX_PIPE_RESTARTS = 100; //after 100 restarts without progress kill session static constexpr ui32 RESTART_PIPE_DELAY_MS = 100; - static constexpr ui32 MAX_COMMITS_INFLY = 3; + static constexpr ui32 MAX_COMMITS_INFLY = 1; public: TPartitionActor(const TActorId& parentId, const TString& clientId, const TString& clientPath, const ui64 cookie, const TString& session, const TPartitionId& partition, ui32 generation, ui32 step, const ui64 tabletID, const TTopicCounters& counters, const bool commitsDisabled, - const TString& clientDC, bool rangesMode, const NPersQueue::TTopicConverterPtr& topic, bool directRead, - bool useMigrationProtocol, ui32 maxTimeLagMs, ui64 readTimestampMs); + const TString& clientDC, bool rangesMode, const NPersQueue::TTopicConverterPtr& topic, const TString& database, bool directRead, + bool useMigrationProtocol, ui32 maxTimeLagMs, ui64 readTimestampMs, std::set parents, + std::unordered_set notCommitedToFinishParents); ~TPartitionActor(); void Bootstrap(const NActors::TActorContext& ctx); @@ -100,6 +104,12 @@ class TPartitionActor : public NActors::TActorBootstrapped { HFunc(TEvTabletPipe::TEvClientConnected, Handle); HFunc(TEvPersQueue::TEvResponse, Handle); HFunc(TEvPersQueue::TEvHasDataInfoResponse, Handle); + + HFunc(NKqp::TEvKqp::TEvCreateSessionResponse, Handle); + HFunc(NKqp::TEvKqp::TEvQueryResponse, Handle); + + HFunc(TEvPQProxy::TEvParentCommitedToFinish, Handle); + default: break; }; @@ -123,6 +133,11 @@ class TPartitionActor : public NActors::TActorBootstrapped { void Handle(TEvPersQueue::TEvResponse::TPtr& ev, const NActors::TActorContext& ctx); void Handle(TEvPersQueue::TEvHasDataInfoResponse::TPtr& ev, const NActors::TActorContext& ctx); + void Handle(NKqp::TEvKqp::TEvCreateSessionResponse::TPtr& ev, const NActors::TActorContext& ctx); + void Handle(NKqp::TEvKqp::TEvQueryResponse::TPtr& ev, const TActorContext& ctx); + + void Handle(TEvPQProxy::TEvParentCommitedToFinish::TPtr& ev, const TActorContext& ctx); + void HandlePoison(NActors::TEvents::TEvPoisonPill::TPtr& ev, const NActors::TActorContext& ctx); void HandleWakeup(const NActors::TActorContext& ctx); void DoWakeup(const NActors::TActorContext& ctx); @@ -142,11 +157,13 @@ class TPartitionActor : public NActors::TActorBootstrapped { void SendPublishDirectRead(const ui64 directReadId, const TActorContext& ctx); void SendForgetDirectRead(const ui64 directReadId, const TActorContext& ctx); void SendPartitionReady(const TActorContext& ctx); + void CommitDone(ui64 cookie, const TActorContext& ctx); NKikimrClient::TPersQueueRequest MakeCreateSessionRequest(bool initial) const; NKikimrClient::TPersQueueRequest MakeReadRequest(ui64 readOffset, ui64 lastOffset, ui64 maxCount, ui64 maxSize, ui64 maxTimeLagMs, ui64 readTimestampMs, ui64 directReadId) const; + private: const TActorId ParentId; const TString ClientId; @@ -167,6 +184,7 @@ class TPartitionActor : public NActors::TActorBootstrapped { ui64 ReadOffset; ui64 ClientReadOffset; TMaybe ClientCommitOffset; + bool ClientHasAnyCommits; bool ClientVerifyReadOffset; ui64 CommittedOffset; ui64 WriteTimestampEstimateMs; @@ -209,12 +227,16 @@ class TPartitionActor : public NActors::TActorBootstrapped { }; std::deque> CommitsInfly; //ReadId, Offset + std::unordered_map> Kqps; + + std::set Parents; TTopicCounters Counters; bool CommitsDisabled; ui64 CommitCookie; NPersQueue::TTopicConverterPtr Topic; + TString Database; bool DirectRead = false; @@ -240,6 +262,8 @@ class TPartitionActor : public NActors::TActorBootstrapped { bool FirstRead; bool ReadingFinishedSent; + + std::unordered_set NotCommitedToFinishParents; }; diff --git a/ydb/services/persqueue_v1/actors/read_init_auth_actor.cpp b/ydb/services/persqueue_v1/actors/read_init_auth_actor.cpp index 320d8284db67..27592a7862d9 100644 --- a/ydb/services/persqueue_v1/actors/read_init_auth_actor.cpp +++ b/ydb/services/persqueue_v1/actors/read_init_auth_actor.cpp @@ -104,6 +104,7 @@ bool TReadInitAndAuthActor::ProcessTopicSchemeCacheResponse( topicsIter->second.MeteringMode = pqDescr.GetPQTabletConfig().GetMeteringMode(); topicsIter->second.DbPath = pqDescr.GetPQTabletConfig().GetYdbDatabasePath(); topicsIter->second.IsServerless = entry.DomainInfo->IsServerless(); + topicsIter->second.PartitionGraph = entry.PQGroupInfo->PartitionGraph; for (const auto& partitionDescription : pqDescr.GetPartitions()) { topicsIter->second.Partitions[partitionDescription.GetPartitionId()] = @@ -272,7 +273,16 @@ void TReadInitAndAuthActor::FinishInitialization(const TActorContext& ctx) { TTopicInitInfoMap res; for (auto& [name, holder] : Topics) { res.insert(std::make_pair(name, TTopicInitInfo{ - holder.FullConverter, holder.TabletID, holder.CloudId, holder.DbId, holder.DbPath, holder.IsServerless, holder.FolderId, holder.MeteringMode, holder.Partitions + holder.FullConverter, + holder.TabletID, + holder.CloudId, + holder.DbId, + holder.DbPath, + holder.IsServerless, + holder.FolderId, + holder.MeteringMode, + holder.Partitions, + holder.PartitionGraph })); } ctx.Send(ParentId, new TEvPQProxy::TEvAuthResultOk(std::move(res))); diff --git a/ydb/services/persqueue_v1/actors/read_session_actor.cpp b/ydb/services/persqueue_v1/actors/read_session_actor.cpp index 71c4b29852a8..4e838f22d710 100644 --- a/ydb/services/persqueue_v1/actors/read_session_actor.cpp +++ b/ydb/services/persqueue_v1/actors/read_session_actor.cpp @@ -458,7 +458,6 @@ void TReadSessionActor::Handle(TEvPQProxy::TEvAuth::TPtr& } } - template void TReadSessionActor::Handle(TEvPQProxy::TEvDirectReadAck::TPtr& ev, const TActorContext& ctx) { auto it = Partitions.find(ev->Get()->AssignId); @@ -642,14 +641,14 @@ void TReadSessionActor::Handle(TEvPQProxy::TEvCommitDone:: } auto assignId = ev->Get()->AssignId; - auto it = Partitions.find(assignId); - if (it == Partitions.end()) { + auto partitionIt = Partitions.find(assignId); + if (partitionIt == Partitions.end()) { return CloseSession(PersQueue::ErrorCode::BAD_REQUEST, TStringBuilder() << "unknown partition_session_id " << assignId << " #01", ctx); } - Y_ABORT_UNLESS(it->second.Offset < ev->Get()->Offset); - it->second.NextRanges.EraseInterval(it->second.Offset, ev->Get()->Offset); + Y_ABORT_UNLESS(partitionIt->second.Offset < ev->Get()->Offset); + partitionIt->second.NextRanges.EraseInterval(partitionIt->second.Offset, ev->Get()->Offset); if (ev->Get()->StartCookie == Max()) { // means commit at start return; @@ -664,8 +663,8 @@ void TReadSessionActor::Handle(TEvPQProxy::TEvCommitDone:: auto c = result.mutable_committed()->add_cookies(); c->set_partition_cookie(i); c->set_assign_id(ev->Get()->AssignId); - it->second.NextCommits.erase(i); - it->second.ReadIdCommitted = i; + partitionIt->second.NextCommits.erase(i); + partitionIt->second.ReadIdCommitted = i; } } else { // commit on cookies not supported in this case Y_ABORT_UNLESS(false); @@ -674,7 +673,7 @@ void TReadSessionActor::Handle(TEvPQProxy::TEvCommitDone:: if constexpr (UseMigrationProtocol) { auto c = result.mutable_committed()->add_offset_ranges(); c->set_assign_id(ev->Get()->AssignId); - c->set_start_offset(it->second.Offset); + c->set_start_offset(partitionIt->second.Offset); c->set_end_offset(ev->Get()->Offset); } else { auto c = result.mutable_commit_offset_response()->add_partitions_committed_offsets(); @@ -683,14 +682,35 @@ void TReadSessionActor::Handle(TEvPQProxy::TEvCommitDone:: } } - it->second.Offset = ev->Get()->Offset; + partitionIt->second.Offset = ev->Get()->Offset; + partitionIt->second.EndOffset = ev->Get()->EndOffset; LOG_DEBUG_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " replying for commits" << ": assignId# " << ev->Get()->AssignId << ", from# " << ev->Get()->StartCookie << ", to# " << ev->Get()->LastCookie - << ", offset# " << it->second.Offset); + << ", offset# " << partitionIt->second.Offset); WriteToStreamOrDie(ctx, std::move(result)); + + if (ev->Get()->Offset == ev->Get()->EndOffset) { + auto topicName = partitionIt->second.Topic->GetInternalName(); + auto topicIt = Topics.find(partitionIt->second.Topic->GetInternalName()); + if (topicIt == Topics.end()) { + return CloseSession(PersQueue::ErrorCode::BAD_REQUEST, TStringBuilder() + << "unknown topic partition_session_id: " << assignId, ctx); + } + + auto& topic = topicIt->second; + for (auto& child: topic.PartitionGraph->GetPartition(partitionIt->second.Partition.Partition)->DirectChildren) { + for (auto& otherPartitions: Partitions) { + if (otherPartitions.second.Partition.Partition == child->Id) { + ctx.Send(otherPartitions.second.Actor, new TEvPQProxy::TEvParentCommitedToFinish(partitionIt->second.Partition.Partition)); + } + } + } + + } + } template @@ -1086,8 +1106,14 @@ void TReadSessionActor::Handle(TEvPQProxy::TEvAuthResultOk return CloseSession(PersQueue::ErrorCode::OVERLOAD, TStringBuilder() << "metering mode of topic: " << name << " has been changed", ctx); } + it->second.PartitionGraph = t.PartitionGraph; } } + + while (!Locks.empty()) { + ctx.Send(ctx.SelfID, std::move(Locks.front())); + Locks.pop_front(); + } } template @@ -1196,29 +1222,36 @@ void TReadSessionActor::Handle(TEvPersQueue::TEvLockPartit auto& converter = converterIter->second; const auto name = converter->GetInternalName(); - { - auto it = Topics.find(name); - if (it == Topics.end() || (!ReadWithoutConsumer && it->second.PipeClient != ActorIdFromProto(record.GetPipeClient()))) { - LOG_ALERT_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " ignored ev lock" - << ": path# " << name - << ", reason# " << "topic is unknown"); - return; - } + auto topicIt = Topics.find(name); + if (topicIt == Topics.end() || (!ReadWithoutConsumer && topicIt->second.PipeClient != ActorIdFromProto(record.GetPipeClient()))) { + LOG_ALERT_S(ctx, NKikimrServices::PQ_READ_PROXY, PQ_LOG_PREFIX << " ignored ev lock" + << ": path# " << name + << ", reason# " << "topic is unknown"); + return; + } - auto& topic = it->second; + auto& topic = topicIt->second; - // TODO: counters - if (NumPartitionsFromTopic[name]++ == 0) { - if (AppData(ctx)->PQConfig.GetTopicsAreFirstClassCitizen()) { - SetupTopicCounters(converter, topic.CloudId, topic.DbId, topic.DbPath, topic.IsServerless, topic.FolderId); - } else { - SetupTopicCounters(converter); - } + auto* partitionNode = topic.PartitionGraph->GetPartition(record.GetPartition()); + if (!partitionNode) { + Locks.push_back(ev->Release()); + if (!AuthInitActor) { + RunAuthActor(ctx); } + return; + } - topic.Partitions.emplace(record.GetPartition(), NGRpcProxy::TPartitionInfo{record.GetTabletId()}); + // TODO: counters + if (NumPartitionsFromTopic[name]++ == 0) { + if (AppData(ctx)->PQConfig.GetTopicsAreFirstClassCitizen()) { + SetupTopicCounters(converter, topic.CloudId, topic.DbId, topic.DbPath, topic.IsServerless, topic.FolderId); + } else { + SetupTopicCounters(converter); + } } + topic.Partitions.emplace(record.GetPartition(), NGRpcProxy::TPartitionInfo{record.GetTabletId()}); + // TODO: counters auto it = TopicCounters.find(name); Y_ABORT_UNLESS(it != TopicCounters.end()); @@ -1234,10 +1267,19 @@ void TReadSessionActor::Handle(TEvPersQueue::TEvLockPartit return CloseSession(PersQueue::ErrorCode::ERROR, error, ctx); } + std::unordered_set notCommitedToFinishParents; + for (auto& parent: topic.PartitionGraph->GetPartition(record.GetPartition())->DirectParents) { + for (auto& otherPartitions: Partitions) { // TODO: map + if (otherPartitions.second.Partition.Partition == parent->Id && otherPartitions.second.Offset != otherPartitions.second.EndOffset) { + notCommitedToFinishParents.emplace(otherPartitions.second.Partition.Partition); + } + } + } + const TActorId actorId = ctx.Register(new TPartitionActor( ctx.SelfID, ClientId, ClientPath, Cookie, Session, partitionId, record.GetGeneration(), record.GetStep(), record.GetTabletId(), it->second, CommitsDisabled, ClientDC, RangesMode, - converterIter->second, DirectRead, UseMigrationProtocol, maxLag, readTimestampMs)); + converterIter->second, Request->GetDatabaseName().GetOrElse(AppData(ctx)->PQConfig.GetDatabase()), DirectRead, UseMigrationProtocol, maxLag, readTimestampMs, topic.PartitionGraph->GetPartition(partitionId.Partition)->AllParents, notCommitedToFinishParents)); if (SessionsActive) { PartsPerSession.DecFor(Partitions.size(), 1); @@ -1275,6 +1317,12 @@ void TReadSessionActor::Handle(TEvPQProxy::TEvPartitionSta << "unknown partition_session_id " << assignId << " #02", ctx); } + auto topicName = it->second.Topic->GetInternalName(); + auto topicIt = Topics.find(it->second.Topic->GetInternalName()); + if (topicIt == Topics.end()) { + return CloseSession(PersQueue::ErrorCode::BAD_REQUEST, TStringBuilder() + << "unknown topic partition_session_id: " << assignId, ctx); + } TServerMessage result; result.set_status(Ydb::StatusIds::SUCCESS); @@ -1286,6 +1334,8 @@ void TReadSessionActor::Handle(TEvPQProxy::TEvPartitionSta it->second.LockSent = true; it->second.Offset = ev->Get()->Offset; + it->second.ConsumerHasAnyCommits = ev->Get()->ClientHasAnyCommits; + it->second.EndOffset = ev->Get()->EndOffset; if constexpr (UseMigrationProtocol) { result.mutable_assigned()->mutable_topic()->set_path(it->second.Topic->GetFederationPath()); diff --git a/ydb/services/persqueue_v1/actors/read_session_actor.h b/ydb/services/persqueue_v1/actors/read_session_actor.h index 2f0424aca785..8dc4080a5469 100644 --- a/ydb/services/persqueue_v1/actors/read_session_actor.h +++ b/ydb/services/persqueue_v1/actors/read_session_actor.h @@ -45,11 +45,13 @@ struct TPartitionActorInfo { TSet NextCommits; TDisjointIntervalTree NextRanges; ui64 Offset; + bool ConsumerHasAnyCommits; TInstant AssignTimestamp; ui64 Generation; ui64 NodeId; + ui64 EndOffset; struct TDirectReadInfo { @@ -419,6 +421,7 @@ class TReadSessionActor TMap PartitionToControlMessages; std::deque> Reads; + std::deque> Locks; ui64 Cookie; diff --git a/ydb/services/persqueue_v1/actors/update_offsets_in_transaction_actor.cpp b/ydb/services/persqueue_v1/actors/update_offsets_in_transaction_actor.cpp index 1c05509307b9..60f6e39edd40 100644 --- a/ydb/services/persqueue_v1/actors/update_offsets_in_transaction_actor.cpp +++ b/ydb/services/persqueue_v1/actors/update_offsets_in_transaction_actor.cpp @@ -61,7 +61,22 @@ void TUpdateOffsetsInTransactionActor::Proceed(const NActors::TActorContext& ctx ev->Record.MutableRequest()->MutableTxControl()->set_tx_id(req->tx().id()); ev->Record.MutableRequest()->MutableTopicOperations()->SetConsumer(req->consumer()); - *ev->Record.MutableRequest()->MutableTopicOperations()->MutableTopics() = req->topics(); + + for (const auto& topic : req->topics()) { + auto* newTopic = ev->Record.MutableRequest()->MutableTopicOperations()->AddTopics(); + newTopic->set_path(topic.path()); + + for (const auto& partition : topic.partitions()) { + auto* newPartition = newTopic->add_partitions(); + newPartition->set_partition_id(partition.partition_id()); + + for (const auto& offsetsRange : partition.partition_offsets()) { + auto* newOffsetsRange = newPartition->add_partition_offsets(); + newOffsetsRange->set_start(offsetsRange.start()); + newOffsetsRange->set_end(offsetsRange.end()); + } + } + } ctx.Send(NKqp::MakeKqpProxyID(ctx.SelfID.NodeId()), ev.Release()); } diff --git a/ydb/services/persqueue_v1/actors/ya.make b/ydb/services/persqueue_v1/actors/ya.make index 75aafd8cc5d6..57adbeb98975 100644 --- a/ydb/services/persqueue_v1/actors/ya.make +++ b/ydb/services/persqueue_v1/actors/ya.make @@ -28,6 +28,8 @@ SRCS( codecs.cpp commit_offset_actor.h commit_offset_actor.cpp + distributed_commit_helper.h + distributed_commit_helper.cpp events.h persqueue_utils.h persqueue_utils.cpp From 884afede08ae65081fd1b0791811287469ddc5fc Mon Sep 17 00:00:00 2001 From: vvvv Date: Tue, 8 Apr 2025 17:36:45 +0300 Subject: [PATCH 056/454] YQL-19747 write all aliases for yt hints commit_hash:daa1d17f2f2569a87a9af557046c653a17a64981 --- .../data/language/statements_opensource.json | 2 +- yt/yql/providers/yt/provider/ya.make | 16 ++++++++++++++ .../yt/provider/yql_yt_op_settings.cpp | 22 ++++++++++++++++--- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/yql/essentials/data/language/statements_opensource.json b/yql/essentials/data/language/statements_opensource.json index a3bd452b1806..d26308b6a3d3 100644 --- a/yql/essentials/data/language/statements_opensource.json +++ b/yql/essentials/data/language/statements_opensource.json @@ -1 +1 @@ -{"read":{"yt":{"hints":[{"name":"infer_scheme"},{"name":"force_infer_schema"},{"name":"inline"},{"name":"xlock"},{"name":"unordered"},{"name":"non_unique"},{"name":"ignore_type_v3"}]}},"insert":{"yt":{"hints":[{"name":"truncate"},{"name":"compression_codec"},{"name":"erasure_codec"},{"name":"expiration"},{"name":"replication_factor"},{"name":"user_attrs"},{"name":"media"},{"name":"primary_medium"},{"name":"keep_meta"},{"name":"monotonic_keys"},{"name":"column_groups"},{"name":"security_tags"}]}},"replace":{},"upsert":{},"update":{},"delete":{},"create_table":{},"create_view":{}} +{"read":{"yt":{"hints":[{"name":"infer_scheme"},{"name":"inferscheme"},{"name":"infer_schema"},{"name":"inferschema"},{"name":"force_infer_schema"},{"name":"forceinferschema"},{"name":"inline"},{"name":"xlock"},{"name":"unordered"},{"name":"non_unique"},{"name":"nonUnique"},{"name":"ignore_type_v3"},{"name":"ignoretypev3"}]}},"insert":{"yt":{"hints":[{"name":"truncate"},{"name":"compression_codec"},{"name":"compressioncodec"},{"name":"erasure_codec"},{"name":"erasurecodec"},{"name":"expiration"},{"name":"replication_factor"},{"name":"replicationfactor"},{"name":"user_attrs"},{"name":"userattrs"},{"name":"media"},{"name":"primary_medium"},{"name":"primarymedium"},{"name":"keep_meta"},{"name":"keepmeta"},{"name":"monotonic_keys"},{"name":"monotonickeys"},{"name":"column_groups"},{"name":"columngroups"},{"name":"security_tags"},{"name":"securitytags"}]}},"replace":{},"upsert":{},"update":{},"delete":{},"create_table":{},"create_view":{}} diff --git a/yt/yql/providers/yt/provider/ya.make b/yt/yql/providers/yt/provider/ya.make index a40502a8b6a1..74cbe7ac426c 100644 --- a/yt/yql/providers/yt/provider/ya.make +++ b/yt/yql/providers/yt/provider/ya.make @@ -74,6 +74,7 @@ SRCS( PEERDIR( library/cpp/yson/node library/cpp/json/writer + library/cpp/json library/cpp/disjoint_sets yt/cpp/mapreduce/common yt/cpp/mapreduce/interface @@ -138,6 +139,21 @@ YQL_LAST_ABI_VERSION() GENERATE_ENUM_SERIALIZATION(yql_yt_op_settings.h) +RUN_PROGRAM( + tools/enum_parser/enum_parser + --output + ${BINDIR}/yql_yt_op_settings.unused.cpp + --json-output + ${BINDIR}/yql_yt_op_settings.json + yql_yt_op_settings.h + IN yql_yt_op_settings.h + OUT_NOAUTO ${BINDIR}/yql_yt_op_settings.json +) + +RESOURCE( + ${BINDIR}/yql_yt_op_settings.json /yql_yt_op_settings.json +) + END() RECURSE_FOR_TESTS( diff --git a/yt/yql/providers/yt/provider/yql_yt_op_settings.cpp b/yt/yql/providers/yt/provider/yql_yt_op_settings.cpp index 922307cdadb7..929fbcc9287f 100644 --- a/yt/yql/providers/yt/provider/yql_yt_op_settings.cpp +++ b/yt/yql/providers/yt/provider/yql_yt_op_settings.cpp @@ -12,6 +12,7 @@ #include #include +#include namespace NYql { @@ -1331,9 +1332,24 @@ void YtWriteHint(std::string_view name, NJsonWriter::TBuf& json) { } void YtWriteHints(EYtSettingTypes flags, NJsonWriter::TBuf& json) { - for (ui32 i = 0; i < (ui32)EYtSettingType::LAST; ++i) { - if (flags.HasFlags((EYtSettingType)i)) { - YtWriteHint(ToString((EYtSettingType)i), json); + auto res = NResource::Find("/yql_yt_op_settings.json"); + NJson::TJsonValue enumJson; + ReadJsonTree(res, &enumJson, true); + for (const auto& x : enumJson.GetArraySafe()) { + if (x["cpp_name"].GetStringSafe() != "EYtSettingType") { + continue; + } + + for (const auto& y : x["items"].GetArraySafe()) { + if (!y["str_value"].IsDefined()) { + continue; + } + + if (flags.HasFlags(FromString(y["str_value"].GetStringSafe()))) { + for (const auto& a : y["aliases"].GetArraySafe()) { + YtWriteHint(a.GetStringSafe(), json); + } + } } } } From 3321dfa2cccbc1dfe52c7db872a69bdce11f641e Mon Sep 17 00:00:00 2001 From: Dmitry Kardymon Date: Tue, 8 Apr 2025 18:10:49 +0300 Subject: [PATCH 057/454] YQ-4188 Add task controller config and add new sensors (#16437) --- ydb/core/fq/libs/actors/run_actor.cpp | 19 ++++++++++++++++--- .../fq/libs/config/protos/fq_config.proto | 2 ++ .../libs/config/protos/task_controller.proto | 12 ++++++++++++ ydb/core/fq/libs/config/protos/ya.make | 1 + .../internal/task_ping.cpp | 12 +++++++++--- .../ydb_control_plane_storage_impl.h | 2 ++ ydb/library/db_pool/db_pool.cpp | 5 ++++- ydb/tests/tools/fq_runner/kikimr_runner.py | 3 +++ 8 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 ydb/core/fq/libs/config/protos/task_controller.proto diff --git a/ydb/core/fq/libs/actors/run_actor.cpp b/ydb/core/fq/libs/actors/run_actor.cpp index cd518c31b873..d536153a0e60 100644 --- a/ydb/core/fq/libs/actors/run_actor.cpp +++ b/ydb/core/fq/libs/actors/run_actor.cpp @@ -1571,6 +1571,18 @@ class TRunActor : public NActors::TActorBootstrapped { ClearResultFormatSettings(); } + TDuration pingPeriod = TDuration::Seconds(3); + TDuration aggrPeriod = TDuration::Seconds(1); + { + const auto& taskControllerConfig = Params.Config.GetTaskController(); + if (taskControllerConfig.GetPingPeriod()) { + Y_ABORT_UNLESS(TDuration::TryParse(taskControllerConfig.GetPingPeriod(), pingPeriod)); + } + if (taskControllerConfig.GetAggrPeriod()) { + Y_ABORT_UNLESS(TDuration::TryParse(taskControllerConfig.GetAggrPeriod(), aggrPeriod)); + } + } + if (enableCheckpointCoordinator) { ControlId = Register(MakeCheckpointCoordinator( ::NFq::TCoordinatorId(Params.QueryId + "-" + ToString(DqGraphIndex), Params.PreviousQueryRevision), @@ -1587,8 +1599,8 @@ class TRunActor : public NActors::TActorBootstrapped { resultId, dqConfiguration, QueryCounters, - TDuration::Seconds(3), - TDuration::Seconds(1) + pingPeriod, + aggrPeriod ).Release()); } else { ControlId = Register(NYql::MakeTaskController( @@ -1597,7 +1609,8 @@ class TRunActor : public NActors::TActorBootstrapped { resultId, dqConfiguration, QueryCounters, - TDuration::Seconds(3) + pingPeriod, + aggrPeriod ).Release()); } diff --git a/ydb/core/fq/libs/config/protos/fq_config.proto b/ydb/core/fq/libs/config/protos/fq_config.proto index edbf50b40b65..7c819561792b 100644 --- a/ydb/core/fq/libs/config/protos/fq_config.proto +++ b/ydb/core/fq/libs/config/protos/fq_config.proto @@ -23,6 +23,7 @@ import "ydb/core/fq/libs/config/protos/rate_limiter.proto"; import "ydb/core/fq/libs/config/protos/read_actors_factory.proto"; import "ydb/core/fq/libs/config/protos/resource_manager.proto"; import "ydb/core/fq/libs/config/protos/row_dispatcher.proto"; +import "ydb/core/fq/libs/config/protos/task_controller.proto"; import "ydb/core/fq/libs/config/protos/test_connection.proto"; import "ydb/core/fq/libs/config/protos/token_accessor.proto"; import "ydb/library/folder_service/proto/config.proto"; @@ -55,4 +56,5 @@ message TConfig { bool EnableTaskCounters = 23; TComputeConfig Compute = 24; TRowDispatcherConfig RowDispatcher = 25; + TTaskControllerConfig TaskController = 26; } diff --git a/ydb/core/fq/libs/config/protos/task_controller.proto b/ydb/core/fq/libs/config/protos/task_controller.proto new file mode 100644 index 000000000000..1d97ae640826 --- /dev/null +++ b/ydb/core/fq/libs/config/protos/task_controller.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +option cc_enable_arenas = true; + +package NFq.NConfig; +option java_package = "ru.yandex.kikimr.proto"; + +//////////////////////////////////////////////////////////// + +message TTaskControllerConfig { + string PingPeriod = 1; + string AggrPeriod = 2; +} diff --git a/ydb/core/fq/libs/config/protos/ya.make b/ydb/core/fq/libs/config/protos/ya.make index a8abe477a6f5..9b693a72297c 100644 --- a/ydb/core/fq/libs/config/protos/ya.make +++ b/ydb/core/fq/libs/config/protos/ya.make @@ -24,6 +24,7 @@ SRCS( resource_manager.proto row_dispatcher.proto storage.proto + task_controller.proto test_connection.proto token_accessor.proto ) diff --git a/ydb/core/fq/libs/control_plane_storage/internal/task_ping.cpp b/ydb/core/fq/libs/control_plane_storage/internal/task_ping.cpp index 0ea26139ce77..b852d663ca75 100644 --- a/ydb/core/fq/libs/control_plane_storage/internal/task_ping.cpp +++ b/ydb/core/fq/libs/control_plane_storage/internal/task_ping.cpp @@ -65,7 +65,7 @@ TYdbControlPlaneStorageActor::TPingTaskParams TYdbControlPlaneStorageActor::Cons " WHERE `" SCOPE_COLUMN_NAME "` = $scope AND `" QUERY_ID_COLUMN_NAME "` = $query_id;\n" "SELECT `" JOB_ID_COLUMN_NAME "`, `" JOB_COLUMN_NAME "` FROM `" JOBS_TABLE_NAME "`\n" " WHERE `" SCOPE_COLUMN_NAME "` = $scope AND `" QUERY_ID_COLUMN_NAME "` = $query_id AND `" JOB_ID_COLUMN_NAME "` = $last_job_id;\n" - "SELECT `" OWNER_COLUMN_NAME "`, `" RETRY_COUNTER_COLUMN_NAME "`, `" RETRY_COUNTER_UPDATE_COLUMN_NAME "`, `" RETRY_RATE_COLUMN_NAME "`\n" + "SELECT `" OWNER_COLUMN_NAME "`, `" RETRY_COUNTER_COLUMN_NAME "`, `" RETRY_COUNTER_UPDATE_COLUMN_NAME "`, `" RETRY_RATE_COLUMN_NAME "`, `" ASSIGNED_UNTIL_COLUMN_NAME "`\n" "FROM `" PENDING_SMALL_TABLE_NAME "` WHERE `" TENANT_COLUMN_NAME "` = $tenant AND `" SCOPE_COLUMN_NAME "` = $scope AND `" QUERY_ID_COLUMN_NAME "` = $query_id;\n" ); @@ -119,6 +119,8 @@ TYdbControlPlaneStorageActor::TPingTaskParams TYdbControlPlaneStorageActor::Cons if (owner != request.owner_id()) { ythrow NYql::TCodeLineException(TIssuesIds::BAD_REQUEST) << "OWNER of QUERY ID = \"" << request.query_id().value() << "\" MISMATCHED: \"" << request.owner_id() << "\" (received) != \"" << owner << "\" (selected)"; } + auto assignedUntil = parser.ColumnParser(ASSIGNED_UNTIL_COLUMN_NAME).GetOptionalTimestamp().value_or(TInstant::Now()); + Counters.LeaseLeftMs->Collect((assignedUntil - TInstant::Now()).MilliSeconds()); retryLimiter.Assign( parser.ColumnParser(RETRY_COUNTER_COLUMN_NAME).GetOptionalUint64().value_or(0), parser.ColumnParser(RETRY_COUNTER_UPDATE_COLUMN_NAME).GetOptionalTimestamp().value_or(TInstant::Zero()), @@ -252,7 +254,7 @@ TYdbControlPlaneStorageActor::TPingTaskParams TYdbControlPlaneStorageActor::Cons readQueryBuilder.AddText( "SELECT `" INTERNAL_COLUMN_NAME "`\n" "FROM `" QUERIES_TABLE_NAME "` WHERE `" QUERY_ID_COLUMN_NAME "` = $query_id AND `" SCOPE_COLUMN_NAME "` = $scope;\n" - "SELECT `" OWNER_COLUMN_NAME "`\n" + "SELECT `" OWNER_COLUMN_NAME "`, `" ASSIGNED_UNTIL_COLUMN_NAME "`\n" "FROM `" PENDING_SMALL_TABLE_NAME "` WHERE `" TENANT_COLUMN_NAME "` = $tenant AND `" SCOPE_COLUMN_NAME "` = $scope AND `" QUERY_ID_COLUMN_NAME "` = $query_id;\n" ); @@ -285,6 +287,8 @@ TYdbControlPlaneStorageActor::TPingTaskParams TYdbControlPlaneStorageActor::Cons if (owner != request.owner_id()) { ythrow NYql::TCodeLineException(TIssuesIds::BAD_REQUEST) << "OWNER of QUERY ID = \"" << request.query_id().value() << "\" MISMATCHED: \"" << request.owner_id() << "\" (received) != \"" << owner << "\" (selected)"; } + auto assignedUntil = parser.ColumnParser(ASSIGNED_UNTIL_COLUMN_NAME).GetOptionalTimestamp().value_or(TInstant::Now()); + Counters.LeaseLeftMs->Collect((assignedUntil - TInstant::Now()).MilliSeconds()); } TInstant ttl = TInstant::Now() + Config->TaskLeaseTtl; @@ -657,7 +661,9 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvPingTaskReq std::shared_ptr response = std::make_shared(); std::shared_ptr finalStatus = std::make_shared(); - auto pingTaskParams = DoesPingTaskUpdateQueriesTable(request) ? + bool isHard = DoesPingTaskUpdateQueriesTable(request); + Counters.Counters->GetCounter(isHard ? "HardPing" : "SoftPing", true)->Inc(); + auto pingTaskParams = isHard ? ConstructHardPingTask(request, response, finalStatus, requestCounters.Common) : ConstructSoftPingTask(request, response, requestCounters.Common); auto debugInfo = Config->Proto.GetEnableDebugMode() ? std::make_shared() : TDebugInfoPtr{}; diff --git a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_impl.h b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_impl.h index c8d102ee920b..78c532bc6b43 100644 --- a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_impl.h +++ b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_impl.h @@ -522,11 +522,13 @@ class TControlPlaneStorageBase : public TControlPlaneStorageUtils { public: ::NMonitoring::TDynamicCounterPtr Counters; + ::NMonitoring::THistogramPtr LeaseLeftMs; explicit TCounters(const ::NMonitoring::TDynamicCounterPtr& counters, const ::NFq::TControlPlaneStorageConfig& config) : ScopeCounters{TTtlCacheSettings{}.SetTtl(config.MetricsTtl)} , FinalStatusCounters{TTtlCacheSettings{}.SetTtl(config.MetricsTtl)} , Counters(counters) + , LeaseLeftMs(Counters->GetHistogram("LeaseLeftMs", ::NMonitoring::ExplicitHistogram({100, 1000, 5000, 10000, 20000}))) { for (auto& request: CommonRequests) { request->Register(Counters); diff --git a/ydb/library/db_pool/db_pool.cpp b/ydb/library/db_pool/db_pool.cpp index 3397daed5fa4..f38b696aa6e1 100644 --- a/ydb/library/db_pool/db_pool.cpp +++ b/ydb/library/db_pool/db_pool.cpp @@ -22,6 +22,7 @@ class TDbPoolActor : public NActors::TActor { const NMonitoring::THistogramPtr RequestsTime; const ::NMonitoring::TDynamicCounterPtr StatusSubgroup; TMap Status; + const ::NMonitoring::TDynamicCounters::TCounterPtr IncomingRate; TCounters(const ::NMonitoring::TDynamicCounterPtr& counters) : Counters(counters) @@ -29,6 +30,7 @@ class TDbPoolActor : public NActors::TActor { , TotalInFlight(counters->GetSubgroup("subcomponent", "DbPool")->GetCounter("TotalInflight")) , RequestsTime(counters->GetSubgroup("subcomponent", "DbPool")->GetHistogram("RequestTimeMs", NMonitoring::ExponentialHistogram(6, 3, 100))) , StatusSubgroup(counters->GetSubgroup("subcomponent", "DbPool")->GetSubgroup("component", "status")) + , IncomingRate(counters->GetSubgroup("subcomponent", "DbPool")->GetCounter("IncomingRate", true)) {} ::NMonitoring::TDynamicCounters::TCounterPtr GetStatus(const NYdb::TStatus& status) { @@ -129,6 +131,7 @@ class TDbPoolActor : public NActors::TActor { void HandleRequest(TEvents::TEvDbRequest::TPtr& ev) { LOG_D("TDbPoolActor: TEvDbRequest " << SelfId() << " Queue size = " << Requests.size()); + Counters.IncomingRate->Inc(); auto request = ev->Get(); Requests.emplace_back(TRequest{ev->Sender, ev->Cookie, request->Sql, std::move(request->Params), request->Idempotent}); ProcessQueue(); @@ -152,6 +155,7 @@ class TDbPoolActor : public NActors::TActor { void HandleRequest(TEvents::TEvDbFunctionRequest::TPtr& ev) { LOG_T("TDbPoolActor: TEvDbFunctionRequest " << SelfId() << " Queue size = " << Requests.size()); + Counters.IncomingRate->Inc(); auto request = ev->Get(); Requests.emplace_back(TFunctionRequest{ev->Sender, ev->Cookie, std::move(request->Handler)}); ProcessQueue(); @@ -203,7 +207,6 @@ class TDbPoolActor : public NActors::TActor { bool RequestInProgress = false; TInstant RequestInProgressTimestamp = TInstant::Now(); std::shared_ptr State = std::make_shared(); - }; TDbPool::TDbPool( diff --git a/ydb/tests/tools/fq_runner/kikimr_runner.py b/ydb/tests/tools/fq_runner/kikimr_runner.py index 720a2371136e..c9d733314d79 100644 --- a/ydb/tests/tools/fq_runner/kikimr_runner.py +++ b/ydb/tests/tools/fq_runner/kikimr_runner.py @@ -518,6 +518,9 @@ def fill_config(self, control_plane): if len(self.config_generator.dc_mapping) > 0: fq_config['nodes_manager']['use_data_center'] = True fq_config['enable_task_counters'] = True + fq_config['task_controller'] = {} + fq_config['task_controller']['ping_period'] = "5s" # task_lease_ttl / 4 + fq_config['task_controller']['aggr_period'] = "1s" else: fq_config['nodes_manager']['enabled'] = False fq_config['pending_fetcher']['enabled'] = False From a22835a290539d8f8941f6b75353ecefeddea0e4 Mon Sep 17 00:00:00 2001 From: kungurtsev Date: Tue, 8 Apr 2025 17:24:32 +0200 Subject: [PATCH 058/454] Print expected cluster & version mismatches on configure (#16869) --- .../cms/console/console__drop_yaml_config.cpp | 8 +++++-- .../cms/console/console_configs_manager.cpp | 24 ++++++++++++++----- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/ydb/core/cms/console/console__drop_yaml_config.cpp b/ydb/core/cms/console/console__drop_yaml_config.cpp index 5ef86f0d45f5..177e945ea391 100644 --- a/ydb/core/cms/console/console__drop_yaml_config.cpp +++ b/ydb/core/cms/console/console__drop_yaml_config.cpp @@ -32,11 +32,15 @@ class TConfigsManager::TTxDropYamlConfig : public TTransactionBaseClusterName != cluster) { - ythrow yexception() << "ClusterName mismatch"; + ythrow yexception() << "ClusterName mismatch" + << " expected " << Self->ClusterName + << " but got " << cluster; } if (Version != Self->YamlVersion) { - ythrow yexception() << "Version mismatch"; + ythrow yexception() << "Version mismatch" + << " expected " << Self->YamlVersion + << " but got " << Version; } } catch (const yexception& ex) { Error = true; diff --git a/ydb/core/cms/console/console_configs_manager.cpp b/ydb/core/cms/console/console_configs_manager.cpp index 77fa7fb019a9..e561520785b0 100644 --- a/ydb/core/cms/console/console_configs_manager.cpp +++ b/ydb/core/cms/console/console_configs_manager.cpp @@ -79,11 +79,15 @@ void TConfigsManager::ValidateMainConfig(TUpdateConfigOpContext& opCtx) { auto resolved = NYamlConfig::ResolveAll(tree); if (ClusterName != opCtx.Cluster) { - ythrow yexception() << "ClusterName mismatch"; + ythrow yexception() << "ClusterName mismatch" + << " expected " << ClusterName + << " but got " << opCtx.Cluster; } if (opCtx.Version != YamlVersion) { - ythrow yexception() << "Version mismatch"; + ythrow yexception() << "Version mismatch" + << " expected " << YamlVersion + << " but got " << opCtx.Version; } TSimpleSharedPtr unknownFieldsCollector = new NYamlConfig::TBasicUnknownFieldsCollector; @@ -1073,11 +1077,15 @@ void TConfigsManager::Handle(TEvConsole::TEvAddVolatileConfigRequest::TPtr &ev, } if (ClusterName != clusterName) { - ythrow yexception() << "ClusterName mismatch"; + ythrow yexception() << "ClusterName mismatch" + << " expected " << ClusterName + << " but got " << clusterName; } if (YamlVersion != version) { - ythrow yexception() << "Version mismatch"; + ythrow yexception() << "Version mismatch" + << " expected " << YamlVersion + << " but got " << version; } VolatileYamlConfigs.try_emplace(id, cfg); @@ -1108,11 +1116,15 @@ void TConfigsManager::Handle(TEvConsole::TEvRemoveVolatileConfigRequest::TPtr &e try { if (!rec.force()) { if (ClusterName != rec.identity().cluster()) { - ythrow yexception() << "ClusterName mismatch"; + ythrow yexception() << "ClusterName mismatch" + << " expected " << ClusterName + << " but got " << rec.identity().cluster(); } if (YamlVersion != rec.identity().version()) { - ythrow yexception() << "Version mismatch"; + ythrow yexception() << "Version mismatch" + << " expected " << YamlVersion + << " but got " << rec.identity().version(); } } From 70ed290ccb8dd4c65a8dadfcee5d31c90b81cc57 Mon Sep 17 00:00:00 2001 From: Daniil Demin Date: Tue, 8 Apr 2025 18:25:53 +0300 Subject: [PATCH 059/454] refactoring in unit tests of SHOW CREATE TABLE (#16929) --- ydb/core/sys_view/ut_common.h | 2 +- ydb/core/sys_view/ut_kqp.cpp | 181 +++++++++++++++++----------------- 2 files changed, 90 insertions(+), 93 deletions(-) diff --git a/ydb/core/sys_view/ut_common.h b/ydb/core/sys_view/ut_common.h index abd34b37606a..53b6e421450a 100644 --- a/ydb/core/sys_view/ut_common.h +++ b/ydb/core/sys_view/ut_common.h @@ -23,7 +23,7 @@ struct TTestEnvSettings { bool EnableSVP = false; bool EnableForceFollowers = false; bool ShowCreateTable = false; - NKikimrProto::TAuthConfig AuthConfig; + NKikimrProto::TAuthConfig AuthConfig = {}; }; class TTestEnv { diff --git a/ydb/core/sys_view/ut_kqp.cpp b/ydb/core/sys_view/ut_kqp.cpp index c5bb53a373aa..a7b075c1df12 100644 --- a/ydb/core/sys_view/ut_kqp.cpp +++ b/ydb/core/sys_view/ut_kqp.cpp @@ -149,7 +149,7 @@ void BreakLock(TSession& session, const TString& tableName) { if (yson == "[]") { continue; } - + NKqp::CompareYson(R"([ [[55u];["Fifty five"]]; ])", yson); @@ -167,7 +167,7 @@ void BreakLock(TSession& session, const TString& tableName) { { // tx1: try to commit auto result = tx1->Commit().ExtractValueSync(); UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); - } + } } void SetupAuthEnvironment(TTestEnv& env) { @@ -256,16 +256,38 @@ void WaitForStats(TTableClient& client, const TString& tableName, const TString& break; Sleep(TDuration::Seconds(5)); } - UNIT_ASSERT_GE(rowCount, 0); + UNIT_ASSERT_GE(rowCount, 0); +} + +NQuery::TExecuteQueryResult ExecuteQuery(NQuery::TSession& session, const std::string& query) { + auto result = session.ExecuteQuery(query, NQuery::TTxControl::NoTx()).ExtractValueSync(); + UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + return result; +} + +NKikimrSchemeOp::TPathDescription DescribePath(TTestActorRuntime& runtime, TString&& path) { + if (!IsStartWithSlash(path)) { + path = CanonizePath(JoinPath({"/Root", path})); + } + auto sender = runtime.AllocateEdgeActor(); + TAutoPtr handle; + + auto request = MakeHolder(); + request->Record.MutableDescribePath()->SetPath(path); + request->Record.MutableDescribePath()->MutableOptions()->SetShowPrivateTable(true); + request->Record.MutableDescribePath()->MutableOptions()->SetReturnBoundaries(true); + runtime.Send(new IEventHandle(MakeTxProxyID(), sender, request.Release())); + return runtime.GrabEdgeEventRethrow(handle)->GetRecord().GetPathDescription(); } -class TShowCreateTableChecker { +class TShowCreateChecker { public: - explicit TShowCreateTableChecker(TTestEnv& env) + explicit TShowCreateChecker(TTestEnv& env) : Env(env) + , Runtime(*Env.GetServer().GetRuntime()) , QueryClient(NQuery::TQueryClient(Env.GetDriver())) - , TableClient(TTableClient(Env.GetDriver())) + , Session(QueryClient.GetSession().GetValueSync().GetSession()) { CreateTier("tier1"); CreateTier("tier2"); @@ -279,7 +301,7 @@ class TShowCreateTableChecker { sessionId = session.GetId(); } - CreateTable(session, query); + ExecuteQuery(session, query); auto showCreateTableQuery = ShowCreateTable(session, tableName); if (formatQuery) { @@ -290,69 +312,50 @@ class TShowCreateTableChecker { DropTable(session, tableName); - CreateTable(session, showCreateTableQuery); + ExecuteQuery(session, showCreateTableQuery); auto describeResultNew = DescribeTable(tableName, sessionId); DropTable(session, tableName); - CompareDescriptions(std::move(describeResultOrig), std::move(describeResultNew), showCreateTableQuery); + CompareDescriptions(describeResultOrig, describeResultNew, showCreateTableQuery); } private: - void CreateTable(NYdb::NQuery::TSession& session, const std::string& query) { - auto result = session.ExecuteQuery(query, NQuery::TTxControl::NoTx()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); - } - - void CreateTier(const TString& tierName) { - auto session = TableClient.CreateSession().GetValueSync().GetSession(); - auto result = session.ExecuteSchemeQuery(R"( + void CreateTier(const std::string& tierName) { + ExecuteQuery(Session, std::format(R"( UPSERT OBJECT `accessKey` (TYPE SECRET) WITH (value = `secretAccessKey`); UPSERT OBJECT `secretKey` (TYPE SECRET) WITH (value = `fakeSecret`); - CREATE EXTERNAL DATA SOURCE `)" + tierName + R"(` WITH ( - SOURCE_TYPE="ObjectStorage", - LOCATION="http://fake.fake/olap-)" + tierName + R"(", - AUTH_METHOD="AWS", - AWS_ACCESS_KEY_ID_SECRET_NAME="accessKey", - AWS_SECRET_ACCESS_KEY_SECRET_NAME="secretKey", - AWS_REGION="ru-central1" - ); - )").GetValueSync(); - UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + CREATE EXTERNAL DATA SOURCE `{}` WITH ( + SOURCE_TYPE = "ObjectStorage", + LOCATION = "http://fake.fake/olap-{}", + AUTH_METHOD = "AWS", + AWS_ACCESS_KEY_ID_SECRET_NAME = "accessKey", + AWS_SECRET_ACCESS_KEY_SECRET_NAME = "secretKey", + AWS_REGION = "ru-central1" + ); + )", tierName, tierName)); } - Ydb::Table::CreateTableRequest DescribeTable(const std::string& tableName, - std::optional sessionId = std::nullopt) { - - auto describeTable = [this](const TString& path) { - auto& runtime = *(this->Env.GetServer().GetRuntime()); - auto sender = runtime.AllocateEdgeActor(); - TAutoPtr handle; + Ydb::Table::CreateTableRequest DescribeTable(const std::string& tableName, std::optional sessionId = std::nullopt) { - auto request = MakeHolder(); - request->Record.MutableDescribePath()->SetPath(path); - request->Record.MutableDescribePath()->MutableOptions()->SetShowPrivateTable(true); - request->Record.MutableDescribePath()->MutableOptions()->SetReturnBoundaries(true); - runtime.Send(new IEventHandle(MakeTxProxyID(), sender, request.Release())); - auto reply = runtime.GrabEdgeEventRethrow(handle); - - if (reply->GetRecord().GetPathDescription().HasColumnTableDescription()) { - const auto& tableDescription = reply->GetRecord().GetPathDescription().GetColumnTableDescription(); + auto describeTable = [this](TString&& path) { + auto pathDescription = DescribePath(Runtime, std::move(path)); + if (pathDescription.HasColumnTableDescription()) { + const auto& tableDescription = pathDescription.GetColumnTableDescription(); return *GetCreateTableRequest(tableDescription); } - if (!reply->GetRecord().GetPathDescription().HasTable()) { - UNIT_ASSERT_C(false, "Invalid path type"); + if (!pathDescription.HasTable()) { + UNIT_FAIL("Invalid path type: " << pathDescription.GetSelf().GetPathType()); } - const auto& tableDescription = reply->GetRecord().GetPathDescription().GetTable(); - + const auto& tableDescription = pathDescription.GetTable(); return *GetCreateTableRequest(tableDescription); }; - TString tablePath = TString(tableName); + auto tablePath = TString(tableName); if (!IsStartWithSlash(tablePath)) { tablePath = CanonizePath(JoinPath({"/Root", tablePath})); } @@ -360,47 +363,38 @@ class TShowCreateTableChecker { auto pos = sessionId.value().find("&id="); tablePath = NKqp::GetTempTablePath("Root", sessionId.value().substr(pos + 4), tablePath); } - auto tableDesc = describeTable(tablePath); + auto tableDesc = describeTable(std::move(tablePath)); return tableDesc; } - std::string ShowCreateTable(NYdb::NQuery::TSession& session, const std::string& tableName) { - auto result = session.ExecuteQuery(TStringBuilder() << R"( - SHOW CREATE TABLE `)" << tableName << R"(`; - )", NQuery::TTxControl::NoTx()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + std::string ShowCreate(NQuery::TSession& session, std::string_view type, const std::string& path) { + const auto result = ExecuteQuery(session, std::format("SHOW CREATE {} `{}`;", type, path)); UNIT_ASSERT_VALUES_EQUAL(result.GetResultSets().size(), 1); auto resultSet = result.GetResultSet(0); auto columnsMeta = resultSet.GetColumnsMeta(); - UNIT_ASSERT(columnsMeta.size() == 3); + UNIT_ASSERT_VALUES_EQUAL(columnsMeta.size(), 3); - NYdb::TResultSetParser parser(resultSet); + TResultSetParser parser(resultSet); UNIT_ASSERT(parser.TryNextRow()); - TString tablePath = TString(tableName); - TString statement = ""; - for (size_t i = 0; i < columnsMeta.size(); i++) { - const auto& column = columnsMeta[i]; + for (const auto& column : columnsMeta) { + TValueParser parserValue(parser.GetValue(column.Name)); + parserValue.OpenOptional(); + const auto& value = parserValue.GetUtf8(); + if (column.Name == "Path") { - TValueParser parserValue(parser.GetValue(i)); - parserValue.OpenOptional(); - UNIT_ASSERT_VALUES_EQUAL(parserValue.GetUtf8(), std::string(tablePath)); - continue; + UNIT_ASSERT_VALUES_EQUAL(value, path); } else if (column.Name == "PathType") { - TValueParser parserValue(parser.GetValue(i)); - parserValue.OpenOptional(); - UNIT_ASSERT_VALUES_EQUAL(parserValue.GetUtf8(), "Table"); - continue; + auto actualType = to_upper(TString(value)); + UNIT_ASSERT_VALUES_EQUAL(actualType, type); } else if (column.Name == "Statement") { - TValueParser parserValue(parser.GetValue(i)); - parserValue.OpenOptional(); - statement = parserValue.GetUtf8(); + statement = value; } else { - UNIT_ASSERT_C(false, "Invalid column name"); + UNIT_FAIL("Invalid column name: " << column.Name); } } UNIT_ASSERT(statement); @@ -408,14 +402,16 @@ class TShowCreateTableChecker { return statement; } - void DropTable(NYdb::NQuery::TSession& session, const std::string& tableName) { - auto result = session.ExecuteQuery(TStringBuilder() << R"( - DROP TABLE `)" << tableName << R"(`; - )", NQuery::TTxControl::NoTx()).ExtractValueSync(); - UNIT_ASSERT_VALUES_EQUAL_C(result.GetStatus(), EStatus::SUCCESS, result.GetIssues().ToString()); + std::string ShowCreateTable(NQuery::TSession& session, const std::string& tableName) { + return ShowCreate(session, "TABLE", tableName); + } + + void DropTable(NQuery::TSession& session, const std::string& tableName) { + ExecuteQuery(session, std::format("DROP TABLE `{}`;", tableName)); } - void CompareDescriptions(Ydb::Table::CreateTableRequest describeResultOrig, Ydb::Table::CreateTableRequest describeResultNew, const std::string& showCreateTableQuery) { + template + void CompareDescriptions(const TProtobufDescription& describeResultOrig, const TProtobufDescription& describeResultNew, const std::string& showCreateTableQuery) { TString first; ::google::protobuf::TextFormat::PrintToString(describeResultOrig, &first); TString second; @@ -470,8 +466,9 @@ class TShowCreateTableChecker { private: TTestEnv& Env; + TTestActorRuntime& Runtime; NQuery::TQueryClient QueryClient; - TTableClient TableClient; + NQuery::TSession Session; }; class TYsonFieldChecker { @@ -705,7 +702,7 @@ Y_UNIT_TEST_SUITE(SystemView) { env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable( R"(CREATE TABLE test_show_create ( @@ -899,7 +896,7 @@ R"(CREATE TABLE `test_show_create` ( env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TABLE test_show_create ( @@ -992,7 +989,7 @@ WITH (PARTITION_AT_KEYS = ((FALSE), (FALSE, 1, 2), (TRUE, 1, 1, 1, 1, 'str'), (T env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TABLE test_show_create ( @@ -1029,7 +1026,7 @@ WITH ( env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TABLE test_show_create ( @@ -1093,7 +1090,7 @@ WITH ( env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TABLE test_show_create ( @@ -1117,7 +1114,7 @@ WITH ( env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TABLE test_show_create ( @@ -1158,7 +1155,7 @@ WITH (READ_REPLICAS_SETTINGS = 'ANY_AZ:3'); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TABLE test_show_create ( @@ -1199,7 +1196,7 @@ WITH (KEY_BLOOM_FILTER = DISABLED); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TABLE test_show_create ( @@ -1315,7 +1312,7 @@ WITH ( env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable(R"( CREATE TEMPORARY TABLE test_show_create ( @@ -1341,7 +1338,7 @@ R"(CREATE TEMPORARY TABLE `test_show_create` ( env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::KQP_YQL, NActors::NLog::PRI_TRACE); env.GetServer().GetRuntime()->SetLogPriority(NKikimrServices::SYSTEM_VIEWS, NActors::NLog::PRI_DEBUG); - TShowCreateTableChecker checker(env); + TShowCreateChecker checker(env); checker.CheckShowCreateTable( R"(CREATE TABLE `/Root/test_show_create` ( @@ -1868,7 +1865,7 @@ WITH ( TTableClient client(env.GetDriver()); auto session = client.CreateSession().GetValueSync().GetSession(); - + BreakLock(session, "/Root/Table0"); WaitForStats(client, "/Root/.sys/partition_stats", "LocksBroken != 0"); @@ -1888,7 +1885,7 @@ WITH ( check.Uint64(1); // LocksAcquired check.Uint64(0); // LocksWholeShard check.Uint64(1); // LocksBroken - } + } Y_UNIT_TEST(PartitionStatsFields) { NDataShard::gDbStatsReportInterval = TDuration::Seconds(0); @@ -2717,7 +2714,7 @@ WITH ( TTableClient client(env.GetDriver()); auto session = client.CreateSession().GetValueSync().GetSession(); - + const TString tableName = "/Root/Tenant1/Table1"; const TString viewName = "/Root/Tenant1/.sys/top_partitions_by_tli_one_minute"; From e07bd3395190c8ecc6dfc6677b4e13c02816fb13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9E=D0=BB=D0=B5=D0=B3?= <150132506+iddqdex@users.noreply.github.com> Date: Tue, 8 Apr 2025 18:38:22 +0300 Subject: [PATCH 060/454] Fix recursive remove path (#16923) --- .../lib/ydb_cli/commands/ydb_workload.cpp | 1 + .../lib/ydb_cli/common/recursive_remove.cpp | 37 ++++++++++--------- .../lib/ydb_cli/common/recursive_remove.h | 6 --- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/ydb/public/lib/ydb_cli/commands/ydb_workload.cpp b/ydb/public/lib/ydb_cli/commands/ydb_workload.cpp index 320f7f2373fa..10e3423996da 100644 --- a/ydb/public/lib/ydb_cli/commands/ydb_workload.cpp +++ b/ydb/public/lib/ydb_cli/commands/ydb_workload.cpp @@ -391,6 +391,7 @@ void TWorkloadCommandBase::CleanTables(NYdbWorkload::IWorkloadQueryGenerator& wo auto pathsToDelete = workloadGen.GetCleanPaths(); TRemoveDirectoryRecursiveSettings settings; settings.NotExistsIsOk(true); + settings.CreateProgressBar(true); for (const auto& path : pathsToDelete) { Cout << "Remove path " << path << "..." << Endl; auto fullPath = config.Database + "/" + path.c_str(); diff --git a/ydb/public/lib/ydb_cli/common/recursive_remove.cpp b/ydb/public/lib/ydb_cli/common/recursive_remove.cpp index 1876215da226..81abf77cc33d 100644 --- a/ydb/public/lib/ydb_cli/common/recursive_remove.cpp +++ b/ydb/public/lib/ydb_cli/common/recursive_remove.cpp @@ -222,38 +222,41 @@ TStatus RemoveDirectoryRecursive( TStatus RemovePathRecursive( const TDriver& driver, - const TString& path, + const TSchemeEntry& entry, const TRemoveDirectoryRecursiveSettings& settings ) { TSchemeClient schemeClient(driver); - auto entity = schemeClient.DescribePath(path).ExtractValueSync(); - if (!entity.IsSuccess()) { - if (settings.NotExistsIsOk_ && entity.GetStatus() == EStatus::SCHEME_ERROR && entity.GetIssues().ToString().find("Path not found") != TString::npos) { - return TStatus(EStatus::SUCCESS, {}); - } - return entity; - } - TTableClient tableClient(driver); TTopicClient topicClient(driver); NQuery::TQueryClient queryClient(driver); NCoordination::TClient coordinationClient(driver); auto remover = NInternal::CreateDefaultRemover(schemeClient, tableClient, topicClient, queryClient, coordinationClient, settings); - return remover(entity.GetEntry()); + return remover(entry); } TStatus RemovePathRecursive( const TDriver& driver, - const TSchemeEntry& entry, + const TString& path, const TRemoveDirectoryRecursiveSettings& settings ) { TSchemeClient schemeClient(driver); - TTableClient tableClient(driver); - TTopicClient topicClient(driver); - NQuery::TQueryClient queryClient(driver); - NCoordination::TClient coordinationClient(driver); - auto remover = NInternal::CreateDefaultRemover(schemeClient, tableClient, topicClient, queryClient, coordinationClient, settings); - return remover(entry); + const auto entity = schemeClient.DescribePath(path).ExtractValueSync(); + if (!entity.IsSuccess()) { + if (settings.NotExistsIsOk_ && entity.GetStatus() == EStatus::SCHEME_ERROR && entity.GetIssues().ToString().find("Path not found") != TString::npos) { + return TStatus(EStatus::SUCCESS, {}); + } + return entity; + } + + auto entry = entity.GetEntry(); + entry.Name = path; + switch (entry.Type) { + case NYdb::NScheme::ESchemeEntryType::ColumnStore: + case NYdb::NScheme::ESchemeEntryType::Directory: + return RemoveDirectoryRecursive(driver, path, settings); + default: + return RemovePathRecursive(driver, entity.GetEntry(), settings); + } } namespace NInternal { diff --git a/ydb/public/lib/ydb_cli/common/recursive_remove.h b/ydb/public/lib/ydb_cli/common/recursive_remove.h index f1e93e7e0871..b58b4cc098b7 100644 --- a/ydb/public/lib/ydb_cli/common/recursive_remove.h +++ b/ydb/public/lib/ydb_cli/common/recursive_remove.h @@ -41,12 +41,6 @@ TStatus RemovePathRecursive( const TRemoveDirectoryRecursiveSettings& settings = {} ); -TStatus RemovePathRecursive( - const TDriver& driver, - const NScheme::TSchemeEntry& entry, - const TRemoveDirectoryRecursiveSettings& settings = {} -); - namespace NInternal { using TRemover = std::function; From 0b84ae0cbe15d2e5bc5fb8a7c2fcff8bcfb2ee2f Mon Sep 17 00:00:00 2001 From: Vlad Kuznetsov Date: Tue, 8 Apr 2025 18:07:33 +0200 Subject: [PATCH 061/454] Fix histograms usage in KQP (#16842) --- ydb/core/kqp/counters/kqp_counters.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ydb/core/kqp/counters/kqp_counters.cpp b/ydb/core/kqp/counters/kqp_counters.cpp index a04a993eaa53..e096e5557a5b 100644 --- a/ydb/core/kqp/counters/kqp_counters.cpp +++ b/ydb/core/kqp/counters/kqp_counters.cpp @@ -325,27 +325,27 @@ void TKqpCountersBase::ReportQueryWithFullScan() { } void TKqpCountersBase::ReportQueryAffectedShards(ui64 shardsCount) { - QueryAffectedShardsCount->Collect(shardsCount > Max() ? Max() : static_cast(shardsCount)); + QueryAffectedShardsCount->Collect(shardsCount); } void TKqpCountersBase::ReportQueryReadSets(ui64 readSetsCount) { - QueryReadSetsCount->Collect(readSetsCount > Max() ? Max() : static_cast(readSetsCount)); + QueryReadSetsCount->Collect(readSetsCount); } void TKqpCountersBase::ReportQueryReadBytes(ui64 bytesCount) { - QueryReadBytes->Collect(bytesCount > Max() ? Max() : static_cast(bytesCount)); + QueryReadBytes->Collect(bytesCount); } void TKqpCountersBase::ReportQueryReadRows(ui64 rowsCount) { - QueryReadRows->Collect(rowsCount > Max() ? Max() : static_cast(rowsCount)); + QueryReadRows->Collect(rowsCount); } void TKqpCountersBase::ReportQueryMaxShardReplySize(ui64 replySize) { - QueryMaxShardReplySize->Collect(replySize > Max() ? Max() : static_cast(replySize)); + QueryMaxShardReplySize->Collect(replySize); } void TKqpCountersBase::ReportQueryMaxShardProgramSize(ui64 programSize) { - QueryMaxShardProgramSize->Collect(programSize > Max() ? Max() : static_cast(programSize)); + QueryMaxShardProgramSize->Collect(programSize); } void TKqpCountersBase::ReportResponseStatus(ui64 responseSize, Ydb::StatusIds::StatusCode ydbStatus) { From 16688838aecc0561c93778b50e9ea199673fc004 Mon Sep 17 00:00:00 2001 From: kungurtsev Date: Tue, 8 Apr 2025 19:25:21 +0200 Subject: [PATCH 062/454] Vector Index Local KMeans with one scan (#16909) --- .../datashard/datashard_ut_local_kmeans.cpp | 267 +++++++- .../datashard/datashard_ut_prefix_kmeans.cpp | 13 - ydb/core/tx/datashard/local_kmeans.cpp | 633 ++++++++++-------- ydb/core/tx/datashard/prefix_kmeans.cpp | 30 +- ydb/core/tx/datashard/reshuffle_kmeans.cpp | 4 +- ydb/core/tx/datashard/sample_k.cpp | 3 +- 6 files changed, 630 insertions(+), 320 deletions(-) diff --git a/ydb/core/tx/datashard/datashard_ut_local_kmeans.cpp b/ydb/core/tx/datashard/datashard_ut_local_kmeans.cpp index 3d081ef34add..931af10560db 100644 --- a/ydb/core/tx/datashard/datashard_ut_local_kmeans.cpp +++ b/ydb/core/tx/datashard/datashard_ut_local_kmeans.cpp @@ -90,9 +90,9 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { } static std::tuple DoLocalKMeans( - Tests::TServer::TPtr server, TActorId sender, NTableIndex::TClusterId parent, ui64 seed, ui64 k, + Tests::TServer::TPtr server, TActorId sender, NTableIndex::TClusterId parentFrom, NTableIndex::TClusterId parentTo, ui64 seed, ui64 k, NKikimrTxDataShard::EKMeansState upload, VectorIndexSettings::VectorType type, - VectorIndexSettings::Metric metric) + VectorIndexSettings::Metric metric, ui32 maxBatchRows = 50000) { auto id = sId.fetch_add(1, std::memory_order_relaxed); auto& runtime = *server->GetRuntime(); @@ -131,15 +131,17 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { rec.SetNeedsRounds(300); - rec.SetParentFrom(parent); - rec.SetParentTo(parent); - rec.SetChild(parent + 1); + rec.SetParentFrom(parentFrom); + rec.SetParentTo(parentTo); + rec.SetChild(parentTo + 1); rec.SetEmbeddingColumn("embedding"); rec.AddDataColumns("data"); rec.SetLevelName(kLevelTable); rec.SetPostingName(kPostingTable); + + rec.MutableScanSettings()->SetMaxBatchRows(maxBatchRows); }; fill(ev1); fill(ev2); @@ -158,6 +160,10 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { auto level = ReadShardedTable(server, kLevelTable); auto posting = ReadShardedTable(server, kPostingTable); + Cerr << "Level:" << Endl; + Cerr << level << Endl; + Cerr << "Posting:" << Endl; + Cerr << posting << Endl; return {std::move(level), std::move(posting)}; } @@ -223,6 +229,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { auto sender = runtime.AllocateEdgeActor(); runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); InitRoot(server, sender); @@ -310,6 +317,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { auto sender = runtime.AllocateEdgeActor(); runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); InitRoot(server, sender); @@ -346,7 +354,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { seed = 0; for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k, + auto [level, posting] = DoLocalKMeans(server, sender, 0, 0, seed, k, NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, VectorIndexSettings::VECTOR_TYPE_UINT8, distance); UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = mm\3\n" @@ -361,7 +369,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { seed = 111; for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k, + auto [level, posting] = DoLocalKMeans(server, sender, 0, 0, seed, k, NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, VectorIndexSettings::VECTOR_TYPE_UINT8, distance); UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = 11\3\n" @@ -377,7 +385,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, VectorIndexSettings::DISTANCE_COSINE}) { - auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k, + auto [level, posting] = DoLocalKMeans(server, sender, 0, 0, seed, k, NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_POSTING, VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = II\3\n"); @@ -400,6 +408,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { auto sender = runtime.AllocateEdgeActor(); runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); InitRoot(server, sender); @@ -436,7 +445,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { seed = 0; for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k, + auto [level, posting] = DoLocalKMeans(server, sender, 0, 0, seed, k, NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, distance); UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = mm\3\n" @@ -451,7 +460,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { seed = 111; for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k, + auto [level, posting] = DoLocalKMeans(server, sender, 0, 0, seed, k, NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, distance); UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = 11\3\n" @@ -467,7 +476,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, VectorIndexSettings::DISTANCE_COSINE}) { - auto [level, posting] = DoLocalKMeans(server, sender, 0, seed, k, + auto [level, posting] = DoLocalKMeans(server, sender, 0, 0, seed, k, NKikimrTxDataShard::EKMeansState::UPLOAD_MAIN_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 0, __ydb_id = 1, __ydb_centroid = II\3\n"); @@ -490,6 +499,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { auto sender = runtime.AllocateEdgeActor(); runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); InitRoot(server, sender); @@ -528,7 +538,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { seed = 0; for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k, + auto [level, posting] = DoLocalKMeans(server, sender, 40, 40, seed, k, NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, VectorIndexSettings::VECTOR_TYPE_UINT8, distance); UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = mm\3\n" @@ -543,7 +553,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { seed = 111; for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k, + auto [level, posting] = DoLocalKMeans(server, sender, 40, 40, seed, k, NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, VectorIndexSettings::VECTOR_TYPE_UINT8, distance); UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = 11\3\n" @@ -559,7 +569,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, VectorIndexSettings::DISTANCE_COSINE}) { - auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k, + auto [level, posting] = DoLocalKMeans(server, sender, 40, 40, seed, k, NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_POSTING, VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = II\3\n"); @@ -582,6 +592,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { auto sender = runtime.AllocateEdgeActor(); runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); InitRoot(server, sender); @@ -620,7 +631,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { seed = 0; for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k, + auto [level, posting] = DoLocalKMeans(server, sender, 40, 40, seed, k, NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, distance); UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = mm\3\n" @@ -635,7 +646,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { seed = 111; for (auto distance : {VectorIndexSettings::DISTANCE_MANHATTAN, VectorIndexSettings::DISTANCE_EUCLIDEAN}) { - auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k, + auto [level, posting] = DoLocalKMeans(server, sender, 40, 40, seed, k, NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, distance); UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = 11\3\n" @@ -651,7 +662,7 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { for (auto similarity : {VectorIndexSettings::SIMILARITY_INNER_PRODUCT, VectorIndexSettings::SIMILARITY_COSINE, VectorIndexSettings::DISTANCE_COSINE}) { - auto [level, posting] = DoLocalKMeans(server, sender, 40, seed, k, + auto [level, posting] = DoLocalKMeans(server, sender, 40, 40, seed, k, NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, similarity); UNIT_ASSERT_VALUES_EQUAL(level, "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = II\3\n"); @@ -663,6 +674,228 @@ Y_UNIT_TEST_SUITE (TTxDataShardLocalKMeansScan) { recreate(); } } + + Y_UNIT_TEST (BuildToBuild_Ranges) { + TPortManager pm; + TServerSettings serverSettings(pm.GetPort(2134)); + serverSettings.SetDomainName("Root"); + + Tests::TServer::TPtr server = new TServer(serverSettings); + auto& runtime = *server->GetRuntime(); + auto sender = runtime.AllocateEdgeActor(); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_DEBUG); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + InitRoot(server, sender); + + TShardedTableOptions options; + options.EnableOutOfOrder(true); // TODO(mbkkt) what is it? + options.Shards(1); + + CreateBuildTable(server, sender, options, "table-main"); + // Upsert some initial values + ExecSQL(server, sender, + R"( + UPSERT INTO `/Root/table-main` + (__ydb_parent, key, embedding, data) + VALUES )" + "(39, 1, \"\x30\x30\3\", \"one\")," + "(39, 2, \"\x32\x32\3\", \"two\")," + "(40, 1, \"\x30\x30\3\", \"one\")," + "(40, 2, \"\x31\x31\3\", \"two\")," + "(40, 3, \"\x32\x32\3\", \"three\")," + "(40, 4, \"\x65\x65\3\", \"four\")," + "(40, 5, \"\x75\x75\3\", \"five\")," + "(41, 5, \"\x75\x75\3\", \"five2\")," + "(41, 6, \"\x76\x76\3\", \"six\");"); + + auto create = [&] { + CreateLevelTable(server, sender, options); + CreateBuildTable(server, sender, options, "table-posting"); + }; + create(); + auto recreate = [&] { + DropTable(server, sender, "table-level"); + DropTable(server, sender, "table-posting"); + create(); + }; + + { // ParentFrom = 39 ParentTo = 39 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 39, 39, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 39, __ydb_id = 40, __ydb_centroid = 00\3\n" + "__ydb_parent = 39, __ydb_id = 41, __ydb_centroid = 22\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 40, key = 1, embedding = 00\3, data = one\n" + "__ydb_parent = 41, key = 2, embedding = 22\3, data = two\n"); + recreate(); + } + } + + { // ParentFrom = 40 ParentTo = 40 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 40, 40, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 40, __ydb_id = 41, __ydb_centroid = 11\3\n" + "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = mm\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 41, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 41, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 41, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 42, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 42, key = 5, embedding = \x75\x75\3, data = five\n"); + recreate(); + } + } + + { // ParentFrom = 41 ParentTo = 41 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 41, 41, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 41, __ydb_id = 42, __ydb_centroid = uu\3\n" + "__ydb_parent = 41, __ydb_id = 43, __ydb_centroid = vv\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 42, key = 5, embedding = uu\3, data = five2\n" + "__ydb_parent = 43, key = 6, embedding = vv\3, data = six\n"); + recreate(); + } + } + + { // ParentFrom = 39 ParentTo = 40 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 39, 40, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 39, __ydb_id = 41, __ydb_centroid = 00\3\n" + "__ydb_parent = 39, __ydb_id = 42, __ydb_centroid = 22\3\n" + "__ydb_parent = 40, __ydb_id = 43, __ydb_centroid = 11\3\n" + "__ydb_parent = 40, __ydb_id = 44, __ydb_centroid = mm\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 41, key = 1, embedding = 00\3, data = one\n" + "__ydb_parent = 42, key = 2, embedding = 22\3, data = two\n" + "__ydb_parent = 43, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 43, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 43, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 44, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 44, key = 5, embedding = \x75\x75\3, data = five\n"); + recreate(); + } + } + + { // ParentFrom = 40 ParentTo = 41 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 40, 41, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 40, __ydb_id = 42, __ydb_centroid = 11\3\n" + "__ydb_parent = 40, __ydb_id = 43, __ydb_centroid = mm\3\n" + "__ydb_parent = 41, __ydb_id = 44, __ydb_centroid = uu\3\n" + "__ydb_parent = 41, __ydb_id = 45, __ydb_centroid = vv\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 42, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 42, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 42, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 43, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 43, key = 5, embedding = \x75\x75\3, data = five\n" + "__ydb_parent = 44, key = 5, embedding = uu\3, data = five2\n" + "__ydb_parent = 45, key = 6, embedding = vv\3, data = six\n"); + recreate(); + } + } + + { // ParentFrom = 39 ParentTo = 41 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 39, 41, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 39, __ydb_id = 42, __ydb_centroid = 00\3\n" + "__ydb_parent = 39, __ydb_id = 43, __ydb_centroid = 22\3\n" + "__ydb_parent = 40, __ydb_id = 44, __ydb_centroid = 11\3\n" + "__ydb_parent = 40, __ydb_id = 45, __ydb_centroid = mm\3\n" + "__ydb_parent = 41, __ydb_id = 46, __ydb_centroid = uu\3\n" + "__ydb_parent = 41, __ydb_id = 47, __ydb_centroid = vv\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 42, key = 1, embedding = 00\3, data = one\n" + "__ydb_parent = 43, key = 2, embedding = 22\3, data = two\n" + "__ydb_parent = 44, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 44, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 44, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 45, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 45, key = 5, embedding = \x75\x75\3, data = five\n" + "__ydb_parent = 46, key = 5, embedding = uu\3, data = five2\n" + "__ydb_parent = 47, key = 6, embedding = vv\3, data = six\n"); + recreate(); + } + } + + { // ParentFrom = 30 ParentTo = 50 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 30, 50, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, + "__ydb_parent = 39, __ydb_id = 69, __ydb_centroid = 00\3\n" + "__ydb_parent = 39, __ydb_id = 70, __ydb_centroid = 22\3\n" + "__ydb_parent = 40, __ydb_id = 71, __ydb_centroid = 11\3\n" + "__ydb_parent = 40, __ydb_id = 72, __ydb_centroid = mm\3\n" + "__ydb_parent = 41, __ydb_id = 73, __ydb_centroid = uu\3\n" + "__ydb_parent = 41, __ydb_id = 74, __ydb_centroid = vv\3\n"); + UNIT_ASSERT_VALUES_EQUAL(posting, + "__ydb_parent = 69, key = 1, embedding = 00\3, data = one\n" + "__ydb_parent = 70, key = 2, embedding = 22\3, data = two\n" + "__ydb_parent = 71, key = 1, embedding = \x30\x30\3, data = one\n" + "__ydb_parent = 71, key = 2, embedding = \x31\x31\3, data = two\n" + "__ydb_parent = 71, key = 3, embedding = \x32\x32\3, data = three\n" + "__ydb_parent = 72, key = 4, embedding = \x65\x65\3, data = four\n" + "__ydb_parent = 72, key = 5, embedding = \x75\x75\3, data = five\n" + "__ydb_parent = 73, key = 5, embedding = uu\3, data = five2\n" + "__ydb_parent = 74, key = 6, embedding = vv\3, data = six\n"); + recreate(); + } + } + + { // ParentFrom = 30 ParentTo = 31 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 30, 31, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, ""); + UNIT_ASSERT_VALUES_EQUAL(posting, ""); + recreate(); + } + } + + { // ParentFrom = 100 ParentTo = 101 + for (ui32 maxBatchRows : {0, 1, 4, 5, 6, 50000}) { + auto [level, posting] = DoLocalKMeans(server, sender, + 100, 101, 111, 2, + NKikimrTxDataShard::EKMeansState::UPLOAD_BUILD_TO_BUILD, VectorIndexSettings::VECTOR_TYPE_UINT8, VectorIndexSettings::DISTANCE_MANHATTAN, + maxBatchRows); + UNIT_ASSERT_VALUES_EQUAL(level, ""); + UNIT_ASSERT_VALUES_EQUAL(posting, ""); + recreate(); + } + } + } } } diff --git a/ydb/core/tx/datashard/datashard_ut_prefix_kmeans.cpp b/ydb/core/tx/datashard/datashard_ut_prefix_kmeans.cpp index 4bab0e10981e..e221986fee47 100644 --- a/ydb/core/tx/datashard/datashard_ut_prefix_kmeans.cpp +++ b/ydb/core/tx/datashard/datashard_ut_prefix_kmeans.cpp @@ -291,19 +291,6 @@ Y_UNIT_TEST_SUITE (TTxDataShardPrefixKMeansScan) { DoBadRequest(server, sender, ev, 2, VectorIndexSettings::VECTOR_TYPE_FLOAT, VectorIndexSettings::METRIC_UNSPECIFIED); } - // TODO(mbkkt) For now all build_index, sample_k, build_columns, local_kmeans, prefix_kmeans doesn't really check this - // { - // auto ev = std::make_unique(); - // auto snapshotCopy = snapshot; - // snapshotCopy.Step++; - // DoBadRequest(server, sender, ev); - // } - // { - // auto ev = std::make_unique(); - // auto snapshotCopy = snapshot; - // snapshotCopy.TxId++; - // DoBadRequest(server, sender, ev); - // } } Y_UNIT_TEST (BuildToPosting) { diff --git a/ydb/core/tx/datashard/local_kmeans.cpp b/ydb/core/tx/datashard/local_kmeans.cpp index b39a09c3f600..5b83216c0df1 100644 --- a/ydb/core/tx/datashard/local_kmeans.cpp +++ b/ydb/core/tx/datashard/local_kmeans.cpp @@ -22,44 +22,6 @@ namespace NKikimr::NDataShard { using namespace NKMeans; -class TResult { -public: - explicit TResult(const TActorId& responseActorId, TAutoPtr response) - : ResponseActorId{responseActorId} - , Response{std::move(response)} { - Y_ASSERT(Response); - } - - void SizeAdd(i64 size) { - if (size != 0) { - std::lock_guard lock{Mutex}; - Size += size; - } - } - - template - void Send(const TActorContext& ctx, Func&& func) { - std::unique_lock lock{Mutex}; - if (Size <= 0) { - return; - } - if (func(Response->Record) && --Size > 0) { - return; - } - Size = 0; - lock.unlock(); - - LOG_N("Finish TLocalKMeansScan " << Response->Record.ShortDebugString()); - ctx.Send(ResponseActorId, std::move(Response)); - } - -private: - std::mutex Mutex; - i64 Size = 1; - TActorId ResponseActorId; - TAutoPtr Response; -}; - // This scan needed to run local (not distributed) kmeans. // We have this local stage because we construct kmeans tree from top to bottom. // And bottom kmeans can be constructed completely locally in datashards to avoid extra communication. @@ -81,7 +43,7 @@ class TResult { // NTable::IScan::Seek used to switch from current state to the next one. // If less than 1% of vectors are reassigned to new clusters we want to stop -// TODO(mbkkt) 1% is choosed by common sense and should be adjusted in future +// TODO(mbkkt) 1% is choosen by common sense and should be adjusted in future static constexpr double MinVectorsNeedsReassigned = 0.01; class TLocalKMeansScanBase: public TActor, public NTable::IScan { @@ -92,12 +54,13 @@ class TLocalKMeansScanBase: public TActor, public NTable:: NTableIndex::TClusterId Child = 0; ui32 Round = 0; - ui32 MaxRounds = 0; + const ui32 MaxRounds = 0; + const ui32 InitK = 0; ui32 K = 0; EState State; - EState UploadState; + const EState UploadState; IDriver* Driver = nullptr; @@ -124,14 +87,17 @@ class TLocalKMeansScanBase: public TActor, public NTable:: std::vector ClusterSizes; // Upload - std::shared_ptr TargetTypes; - std::shared_ptr NextTypes; + std::shared_ptr LevelTypes; + std::shared_ptr PostingTypes; + std::shared_ptr UploadTypes; - TString TargetTable; - TString NextTable; + const TString LevelTable; + const TString PostingTable; + TString UploadTable; - TBufferData ReadBuf; - TBufferData WriteBuf; + TBufferData LevelBuf; + TBufferData PostingBuf; + TBufferData UploadBuf; NTable::TPos EmbeddingPos = 0; NTable::TPos DataPos = 1; @@ -141,15 +107,25 @@ class TLocalKMeansScanBase: public TActor, public NTable:: TActorId Uploader; const TIndexBuildScanSettings ScanSettings; - NTable::TTag KMeansScan; - TTags UploadScan; + NTable::TTag EmbeddingTag; + TTags ScanTags; TUploadStatus UploadStatus; ui64 UploadRows = 0; ui64 UploadBytes = 0; - std::shared_ptr Result; + TActorId ResponseActorId; + TAutoPtr Response; + + // FIXME: save PrefixRows as std::vector> to avoid parsing + const ui32 PrefixColumns; + TSerializedCellVec Prefix; + TBufferData PrefixRows; + bool IsFirstPrefixFeed = true; + bool IsPrefixRowsValid = true; + + bool IsExhausted = false; public: static constexpr NKikimrServices::TActivity::EType ActorActivityType() @@ -157,38 +133,45 @@ class TLocalKMeansScanBase: public TActor, public NTable:: return NKikimrServices::TActivity::LOCAL_KMEANS_SCAN_ACTOR; } - TLocalKMeansScanBase(ui64 buildId, const TUserTable& table, TLead&& lead, NTableIndex::TClusterId parent, NTableIndex::TClusterId child, + TLocalKMeansScanBase(const TUserTable& table, const NKikimrTxDataShard::TEvLocalKMeansRequest& request, - std::shared_ptr result) + const TActorId& responseActorId, + TAutoPtr&& response, + TLead&& lead) : TActor{&TThis::StateWork} - , Parent{parent} - , Child{child} + , Parent{request.GetParentFrom()} + , Child{request.GetChild()} , MaxRounds{request.GetNeedsRounds()} + , InitK{request.GetK()} , K{request.GetK()} , State{EState::SAMPLE} , UploadState{request.GetUpload()} , Lead{std::move(lead)} - , BuildId{buildId} + , BuildId{request.GetId()} , Rng{request.GetSeed()} - , TargetTable{request.GetLevelName()} - , NextTable{request.GetPostingName()} + , LevelTable{request.GetLevelName()} + , PostingTable{request.GetPostingName()} , ScanSettings(request.GetScanSettings()) - , Result{std::move(result)} + , ResponseActorId{responseActorId} + , Response{std::move(response)} + , PrefixColumns{request.GetParentFrom() == 0 && request.GetParentTo() == 0 ? 0u : 1u} { const auto& embedding = request.GetEmbeddingColumn(); const auto& data = request.GetDataColumns(); // scan tags - UploadScan = MakeUploadTags(table, embedding, data, EmbeddingPos, DataPos, KMeansScan); + ScanTags = MakeUploadTags(table, embedding, data, EmbeddingPos, DataPos, EmbeddingTag); + Lead.SetTags(ScanTags); // upload types - if (Ydb::Type type; State <= EState::KMEANS) { - TargetTypes = std::make_shared(3); + { + Ydb::Type type; + LevelTypes = std::make_shared(3); type.set_type_id(NTableIndex::ClusterIdType); - (*TargetTypes)[0] = {NTableIndex::NTableVectorKmeansTreeIndex::ParentColumn, type}; - (*TargetTypes)[1] = {NTableIndex::NTableVectorKmeansTreeIndex::IdColumn, type}; + (*LevelTypes)[0] = {NTableIndex::NTableVectorKmeansTreeIndex::ParentColumn, type}; + (*LevelTypes)[1] = {NTableIndex::NTableVectorKmeansTreeIndex::IdColumn, type}; type.set_type_id(Ydb::Type::STRING); - (*TargetTypes)[2] = {NTableIndex::NTableVectorKmeansTreeIndex::CentroidColumn, type}; + (*LevelTypes)[2] = {NTableIndex::NTableVectorKmeansTreeIndex::CentroidColumn, type}; } - NextTypes = MakeUploadTypes(table, UploadState, embedding, data); + PostingTypes = MakeUploadTypes(table, UploadState, embedding, data); } TInitialState Prepare(IDriver* driver, TIntrusiveConstPtr) final @@ -202,30 +185,27 @@ class TLocalKMeansScanBase: public TActor, public NTable:: TAutoPtr Finish(EAbort abort) final { - LOG_D("Finish " << Debug()); - if (Uploader) { - Send(Uploader, new TEvents::TEvPoisonPill); + Send(Uploader, new TEvents::TEvPoison); Uploader = {}; } - Result->Send(TActivationContext::AsActorContext(), [&] (NKikimrTxDataShard::TEvLocalKMeansResponse& response) { - response.SetReadRows(ReadRows); - response.SetReadBytes(ReadBytes); - response.SetUploadRows(UploadRows); - response.SetUploadBytes(UploadBytes); - NYql::IssuesToMessage(UploadStatus.Issues, response.MutableIssues()); - if (abort != EAbort::None) { - response.SetStatus(NKikimrIndexBuilder::EBuildStatus::ABORTED); - return false; - } else if (UploadStatus.IsSuccess()) { - response.SetStatus(NKikimrIndexBuilder::EBuildStatus::DONE); - return true; - } else { - response.SetStatus(NKikimrIndexBuilder::EBuildStatus::BUILD_ERROR); - return false; - } - }); + auto& record = Response->Record; + record.SetReadRows(ReadRows); + record.SetReadBytes(ReadBytes); + record.SetUploadRows(UploadRows); + record.SetUploadBytes(UploadBytes); + if (abort != EAbort::None) { + record.SetStatus(NKikimrIndexBuilder::EBuildStatus::ABORTED); + } else if (UploadStatus.IsNone() || UploadStatus.IsSuccess()) { + record.SetStatus(NKikimrIndexBuilder::EBuildStatus::DONE); + } else { + record.SetStatus(NKikimrIndexBuilder::EBuildStatus::BUILD_ERROR); + } + NYql::IssuesToMessage(UploadStatus.Issues, record.MutableIssues()); + + LOG_N("Finish " << Debug() << " " << Response->Record.ShortDebugString()); + Send(ResponseActorId, Response.Release()); Driver = nullptr; this->PassAway(); @@ -240,9 +220,10 @@ class TLocalKMeansScanBase: public TActor, public NTable:: TString Debug() const { return TStringBuilder() << "TLocalKMeansScan Id: " << BuildId << " Parent: " << Parent << " Child: " << Child - << " Target: " << TargetTable << " K: " << K << " Clusters: " << Clusters.size() + << " K: " << K << " Clusters: " << Clusters.size() << " State: " << State << " Round: " << Round << " / " << MaxRounds - << " ReadBuf size: " << ReadBuf.Size() << " WriteBuf size: " << WriteBuf.Size(); + << " LevelBuf size: " << LevelBuf.Size() << " PostingBuf size: " << PostingBuf.Size() + << " UploadTable: " << UploadTable << " UploadBuf size: " << UploadBuf.Size() << " RetryCount: " << RetryCount; } EScan PageFault() final @@ -258,28 +239,31 @@ class TLocalKMeansScanBase: public TActor, public NTable:: HFunc(TEvTxUserProxy::TEvUploadRowsResponse, Handle); CFunc(TEvents::TSystem::Wakeup, HandleWakeup); default: - LOG_E("TLocalKMeansScan: StateWork unexpected event type: " << ev->GetTypeRewrite() << " event: " - << ev->ToString() << " " << Debug()); + LOG_E("StateWork unexpected event type: " << ev->GetTypeRewrite() + << " event: " << ev->ToString() << " " << Debug()); } } void HandleWakeup(const NActors::TActorContext& /*ctx*/) { - LOG_I("Retry upload " << Debug()); + LOG_D("Retry upload " << Debug()); - if (!WriteBuf.IsEmpty()) { - Upload(true); + if (UploadInProgress()) { + RetryUpload(); } } void Handle(TEvTxUserProxy::TEvUploadRowsResponse::TPtr& ev, const TActorContext& ctx) { LOG_D("Handle TEvUploadRowsResponse " << Debug() - << " Uploader: " << Uploader.ToString() << " ev->Sender: " << ev->Sender.ToString()); + << " Uploader: " << (Uploader ? Uploader.ToString() : "") + << " ev->Sender: " << ev->Sender.ToString()); if (Uploader) { - Y_ENSURE(Uploader == ev->Sender, "Mismatch Uploader: " << Uploader.ToString() << " ev->Sender: " - << ev->Sender.ToString() << Debug()); + Y_ENSURE(Uploader == ev->Sender, "Mismatch" + << " Uploader: " << Uploader.ToString() + << " Sender: " << ev->Sender.ToString()); + Uploader = {}; } else { Y_ENSURE(Driver == nullptr); return; @@ -288,81 +272,109 @@ class TLocalKMeansScanBase: public TActor, public NTable:: UploadStatus.StatusCode = ev->Get()->Status; UploadStatus.Issues = ev->Get()->Issues; if (UploadStatus.IsSuccess()) { - UploadRows += WriteBuf.GetRows(); - UploadBytes += WriteBuf.GetBytes(); - WriteBuf.Clear(); - if (HasReachedLimits(ReadBuf, ScanSettings)) { - ReadBuf.FlushTo(WriteBuf); - Upload(false); - } + UploadRows += UploadBuf.GetRows(); + UploadBytes += UploadBuf.GetBytes(); + UploadBuf.Clear(); + + TryUpload(LevelBuf, LevelTable, LevelTypes, true) + || TryUpload(PostingBuf, PostingTable, PostingTypes, true); Driver->Touch(EScan::Feed); return; } if (RetryCount < ScanSettings.GetMaxBatchRetries() && UploadStatus.IsRetriable()) { - LOG_N("Got retriable error, " << Debug() << UploadStatus.ToString()); + LOG_N("Got retriable error, " << Debug() << " " << UploadStatus.ToString()); ctx.Schedule(GetRetryWakeupTimeoutBackoff(RetryCount), new TEvents::TEvWakeup()); return; } - LOG_N("Got error, abort scan, " << Debug() << UploadStatus.ToString()); + LOG_N("Got error, abort scan, " << Debug() << " " << UploadStatus.ToString()); Driver->Touch(EScan::Final); } - EScan FeedUpload() + bool ShouldWaitUpload() { - if (!HasReachedLimits(ReadBuf, ScanSettings)) { - return EScan::Feed; + if (!HasReachedLimits(LevelBuf, ScanSettings) && !HasReachedLimits(PostingBuf, ScanSettings)) { + return false; } - if (!WriteBuf.IsEmpty()) { - return EScan::Sleep; + + if (UploadInProgress()) { + return true; } - ReadBuf.FlushTo(WriteBuf); - Upload(false); - return EScan::Feed; - } + + TryUpload(LevelBuf, LevelTable, LevelTypes, true) + || TryUpload(PostingBuf, PostingTable, PostingTypes, true); - ui64 GetProbability() - { - return Rng.GenRand64(); + return !HasReachedLimits(LevelBuf, ScanSettings) && !HasReachedLimits(PostingBuf, ScanSettings); } - void Upload(bool isRetry) + void UploadImpl() { - if (isRetry) { - ++RetryCount; - } else { - RetryCount = 0; - if (State != EState::KMEANS && NextTypes) { - TargetTypes = std::exchange(NextTypes, {}); - TargetTable = std::move(NextTable); - } - } + LOG_D("Uploading " << Debug()); + Y_ASSERT(!UploadBuf.IsEmpty()); + Y_ASSERT(!Uploader); auto actor = NTxProxy::CreateUploadRowsInternal( - this->SelfId(), TargetTable, TargetTypes, WriteBuf.GetRowsData(), + this->SelfId(), UploadTable, UploadTypes, UploadBuf.GetRowsData(), NTxProxy::EUploadRowsMode::WriteToTableShadow, true /*writeToPrivateTable*/); Uploader = this->Register(actor); } - void UploadSample() + void InitUpload(std::string_view table, std::shared_ptr types) + { + RetryCount = 0; + UploadTable = table; + UploadTypes = std::move(types); + UploadImpl(); + } + + void RetryUpload() + { + ++RetryCount; + UploadImpl(); + } + + bool UploadInProgress() + { + return !UploadBuf.IsEmpty(); + } + + bool TryUpload(TBufferData& buffer, const TString& table, const std::shared_ptr& types, bool byLimit) + { + if (Y_UNLIKELY(UploadInProgress())) { + // already uploading something + return true; + } + + if (!buffer.IsEmpty() && (!byLimit || HasReachedLimits(buffer, ScanSettings))) { + buffer.FlushTo(UploadBuf); + InitUpload(table, types); + return true; + } + + return false; + } + + void FormLevelRows() { - Y_ASSERT(ReadBuf.IsEmpty()); - Y_ASSERT(WriteBuf.IsEmpty()); std::array pk; std::array data; for (NTable::TPos pos = 0; const auto& row : Clusters) { pk[0] = TCell::Make(Parent); pk[1] = TCell::Make(Child + pos); data[0] = TCell{row}; - WriteBuf.AddRow(TSerializedCellVec{pk}, TSerializedCellVec::Serialize(data)); + LevelBuf.AddRow(TSerializedCellVec{pk}, TSerializedCellVec::Serialize(data)); ++pos; } - Upload(false); + } + + ui64 GetProbability() + { + return Rng.GenRand64(); } }; @@ -377,10 +389,29 @@ class TLocalKMeansScan final: public TLocalKMeansScanBase, private TCalculation< }; std::vector AggregatedClusters; + void StartNewPrefix() { + Round = 0; + K = InitK; + State = EState::SAMPLE; + Lead.Valid = true; + Lead.Key = TSerializedCellVec(Prefix.GetCells()); // seek to (prefix, inf) + Lead.Relation = NTable::ESeek::Upper; + Prefix = {}; + IsFirstPrefixFeed = true; + IsPrefixRowsValid = true; + PrefixRows.Clear(); + MaxProbability = std::numeric_limits::max(); + MaxRows.clear(); + Clusters.clear(); + ClusterSizes.clear(); + AggregatedClusters.clear(); + } + public: - TLocalKMeansScan(ui64 buildId, const TUserTable& table, TLead&& lead, NTableIndex::TClusterId parent, NTableIndex::TClusterId child, NKikimrTxDataShard::TEvLocalKMeansRequest& request, - std::shared_ptr result) - : TLocalKMeansScanBase{buildId, table, std::move(lead), parent, child, request, std::move(result)} + TLocalKMeansScan(const TUserTable& table, NKikimrTxDataShard::TEvLocalKMeansRequest& request, + const TActorId& responseActorId, TAutoPtr&& response, + TLead&& lead) + : TLocalKMeansScanBase{table, request, responseActorId, std::move(response), std::move(lead)} { this->Dimensions = request.GetSettings().vector_dimension(); LOG_I("Create " << Debug()); @@ -388,90 +419,143 @@ class TLocalKMeansScan final: public TLocalKMeansScanBase, private TCalculation< EScan Seek(TLead& lead, ui64 seq) final { - LOG_D("Seek " << Debug()); - if (State == UploadState) { - if (!WriteBuf.IsEmpty()) { - return EScan::Sleep; - } - if (!ReadBuf.IsEmpty()) { - ReadBuf.FlushTo(WriteBuf); - Upload(false); + LOG_D("Seek " << seq << " " << Debug()); + + if (IsExhausted) { + if (UploadInProgress() + || TryUpload(LevelBuf, LevelTable, LevelTypes, false) + || TryUpload(PostingBuf, PostingTable, PostingTypes, false)) + { return EScan::Sleep; } - if (UploadStatus.IsNone()) { - UploadStatus.StatusCode = Ydb::StatusIds::SUCCESS; - } return EScan::Final; } - if (State == EState::SAMPLE) { - lead = Lead; - lead.SetTags({&KMeansScan, 1}); - if (seq == 0) { - return EScan::Feed; + lead = Lead; + + return EScan::Feed; + } + + EScan Feed(TArrayRef key, const TRow& row) final + { + LOG_T("Feed " << Debug()); + + ++ReadRows; + ReadBytes += CountBytes(key, row); + + if (PrefixColumns && Prefix && !TCellVectorsEquals{}(Prefix.GetCells(), key.subspan(0, PrefixColumns))) { + if (!FinishPrefix()) { + // scan current prefix rows with a new state again + return EScan::Reset; } - State = EState::KMEANS; - if (!InitAggregatedClusters()) { - // We don't need to do anything, - // because this datashard doesn't have valid embeddings for this parent - if (UploadStatus.IsNone()) { - UploadStatus.StatusCode = Ydb::StatusIds::SUCCESS; - } - return EScan::Final; + } + + if (PrefixColumns && !Prefix) { + Prefix = TSerializedCellVec{key.subspan(0, PrefixColumns)}; + auto newParent = key.at(0).template AsValue(); + Child += (newParent - Parent) * InitK; + Parent = newParent; + } + + if (IsFirstPrefixFeed && IsPrefixRowsValid) { + PrefixRows.AddRow(TSerializedCellVec{key}, TSerializedCellVec::Serialize(*row)); + if (HasReachedLimits(PrefixRows, ScanSettings)) { + PrefixRows.Clear(); + IsPrefixRowsValid = false; } - ++Round; - return EScan::Feed; } - Y_ASSERT(State == EState::KMEANS); - if (RecomputeClusters()) { - lead = std::move(Lead); - lead.SetTags(UploadScan); + Feed(key, *row); + + return ShouldWaitUpload() ? EScan::Sleep : EScan::Feed; + } - UploadSample(); - State = UploadState; + EScan Exhausted() final + { + LOG_D("Exhausted " << Debug()); + + if (!FinishPrefix()) { + return EScan::Reset; + } + + IsExhausted = true; + + // call Seek to wait uploads + return EScan::Reset; + } + +private: + bool FinishPrefix() + { + if (FinishPrefixImpl()) { + StartNewPrefix(); + LOG_D("FinishPrefix finished " << Debug()); + return true; } else { - lead = Lead; - lead.SetTags({&KMeansScan, 1}); - ++Round; + IsFirstPrefixFeed = false; + + if (IsPrefixRowsValid) { + LOG_D("FinishPrefix not finished, manually feeding " << PrefixRows.Size() << " saved rows " << Debug()); + for (ui64 iteration = 0; ; iteration++) { + for (const auto& [key, row_] : *PrefixRows.GetRowsData()) { + TSerializedCellVec row(row_); + Feed(key.GetCells(), row.GetCells()); + } + if (FinishPrefixImpl()) { + StartNewPrefix(); + LOG_D("FinishPrefix finished in " << iteration << " iterations " << Debug()); + return true; + } else { + LOG_D("FinishPrefix not finished in " << iteration << " iterations " << Debug()); + } + } + } else { + LOG_D("FinishPrefix not finished, rescanning rows " << Debug()); + } + + return false; } - return EScan::Feed; } - EScan Feed(TArrayRef key, const TRow& row_) final + bool FinishPrefixImpl() { - LOG_T("Feed " << Debug()); + if (State == EState::SAMPLE) { + State = EState::KMEANS; + if (!InitAggregatedClusters()) { + // We don't need to do anything, + // because this datashard doesn't have valid embeddings for this prefix + return true; + } + Round = 1; + return false; // do KMEANS + } - ++ReadRows; - ReadBytes += CountBytes(key, row_); - auto row = *row_; - - switch (State) { - case EState::SAMPLE: - return FeedSample(row); - case EState::KMEANS: - return FeedKMeans(row); - case EState::UPLOAD_MAIN_TO_BUILD: - return FeedUploadMain2Build(key, row); - case EState::UPLOAD_MAIN_TO_POSTING: - return FeedUploadMain2Posting(key, row); - case EState::UPLOAD_BUILD_TO_BUILD: - return FeedUploadBuild2Build(key, row); - case EState::UPLOAD_BUILD_TO_POSTING: - return FeedUploadBuild2Posting(key, row); - default: - return EScan::Final; + if (State == EState::KMEANS) { + if (RecomputeClusters()) { + FormLevelRows(); + State = UploadState; + return false; // do UPLOAD_* + } else { + ++Round; + return false; // recompute KMEANS + } } + + if (State == UploadState) { + return true; + } + + Y_ASSERT(false); + return true; } -private: bool InitAggregatedClusters() { if (Clusters.size() == 0) { return false; } if (Clusters.size() < K) { - // if this datashard have smaller than K count of valid embeddings for this parent + // if this datashard have less than K valid embeddings for this parent // lets make single centroid for it K = 1; Clusters.resize(K); @@ -544,12 +628,37 @@ class TLocalKMeansScan final: public TLocalKMeansScanBase, private TCalculation< return true; } - EScan FeedSample(TArrayRef row) + void Feed(TArrayRef key, TArrayRef row) { - Y_ASSERT(row.size() == 1); - const auto embedding = row.at(0).AsRef(); + switch (State) { + case EState::SAMPLE: + FeedSample(row); + break; + case EState::KMEANS: + FeedKMeans(row); + break; + case EState::UPLOAD_MAIN_TO_BUILD: + FeedUploadMain2Build(key, row); + break; + case EState::UPLOAD_MAIN_TO_POSTING: + FeedUploadMain2Posting(key, row); + break; + case EState::UPLOAD_BUILD_TO_BUILD: + FeedUploadBuild2Build(key, row); + break; + case EState::UPLOAD_BUILD_TO_POSTING: + FeedUploadBuild2Posting(key, row); + break; + default: + Y_ASSERT(false); + } + } + + void FeedSample(TArrayRef row) + { + const auto embedding = row.at(EmbeddingPos).AsRef(); if (!this->IsExpectedSize(embedding)) { - return EScan::Feed; + return; } const auto probability = GetProbability(); @@ -568,55 +677,44 @@ class TLocalKMeansScan final: public TLocalKMeansScanBase, private TCalculation< std::push_heap(MaxRows.begin(), MaxRows.end()); MaxProbability = MaxRows.front().P; } - return MaxProbability != 0 ? EScan::Feed : EScan::Reset; } - EScan FeedKMeans(TArrayRef row) + void FeedKMeans(TArrayRef row) { - Y_ASSERT(row.size() == 1); - const ui32 pos = FeedEmbedding(*this, Clusters, row, 0); - AggregateToCluster(pos, row.at(0).Data()); - return EScan::Feed; + const ui32 pos = FeedEmbedding(*this, Clusters, row, EmbeddingPos); + AggregateToCluster(pos, row.at(EmbeddingPos).Data()); } - EScan FeedUploadMain2Build(TArrayRef key, TArrayRef row) + void FeedUploadMain2Build(TArrayRef key, TArrayRef row) { const ui32 pos = FeedEmbedding(*this, Clusters, row, EmbeddingPos); - if (pos >= K) { - return EScan::Feed; + if (pos < K) { + AddRowMain2Build(PostingBuf, Child + pos, key, row); } - AddRowMain2Build(ReadBuf, Child + pos, key, row); - return FeedUpload(); } - EScan FeedUploadMain2Posting(TArrayRef key, TArrayRef row) + void FeedUploadMain2Posting(TArrayRef key, TArrayRef row) { const ui32 pos = FeedEmbedding(*this, Clusters, row, EmbeddingPos); - if (pos >= K) { - return EScan::Feed; + if (pos < K) { + AddRowMain2Posting(PostingBuf, Child + pos, key, row, DataPos); } - AddRowMain2Posting(ReadBuf, Child + pos, key, row, DataPos); - return FeedUpload(); } - EScan FeedUploadBuild2Build(TArrayRef key, TArrayRef row) + void FeedUploadBuild2Build(TArrayRef key, TArrayRef row) { const ui32 pos = FeedEmbedding(*this, Clusters, row, EmbeddingPos); - if (pos >= K) { - return EScan::Feed; + if (pos < K) { + AddRowBuild2Build(PostingBuf, Child + pos, key, row); } - AddRowBuild2Build(ReadBuf, Child + pos, key, row); - return FeedUpload(); } - EScan FeedUploadBuild2Posting(TArrayRef key, TArrayRef row) + void FeedUploadBuild2Posting(TArrayRef key, TArrayRef row) { const ui32 pos = FeedEmbedding(*this, Clusters, row, EmbeddingPos); - if (pos >= K) { - return EScan::Feed; + if (pos < K) { + AddRowBuild2Posting(PostingBuf, Child + pos, key, row, DataPos); } - AddRowBuild2Posting(ReadBuf, Child + pos, key, row, DataPos); - return FeedUpload(); } }; @@ -671,22 +769,14 @@ void TDataShard::HandleSafe(TEvDataShard::TEvLocalKMeansRequest::TPtr& ev, const TScanRecord::TSeqNo seqNo = {request.GetSeqNoGeneration(), request.GetSeqNoRound()}; response->Record.SetRequestSeqNoGeneration(seqNo.Generation); response->Record.SetRequestSeqNoRound(seqNo.Round); - auto result = std::make_shared(ev->Sender, std::move(response)); - ui32 localTid = 0; - TScanRecord::TScanIds scanIds; auto badRequest = [&](const TString& error) { - for (auto scanId : scanIds) { - CancelScan(localTid, scanId); - } - result->Send(ctx, [&] (NKikimrTxDataShard::TEvLocalKMeansResponse& response) { - response.SetStatus(NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); - auto issue = response.AddIssues(); - issue->set_severity(NYql::TSeverityIds::S_ERROR); - issue->set_message(error); - return false; - }); - result.reset(); + response->Record.SetStatus(NKikimrIndexBuilder::EBuildStatus::BAD_REQUEST); + auto issue = response->Record.AddIssues(); + issue->set_severity(NYql::TSeverityIds::S_ERROR); + issue->set_message(error); + ctx.Send(ev->Sender, std::move(response)); + response.Reset(); }; if (const ui64 shardId = request.GetTabletId(); shardId != TabletID()) { @@ -715,8 +805,6 @@ void TDataShard::HandleSafe(TEvDataShard::TEvLocalKMeansRequest::TPtr& ev, const ScanManager.Drop(id); } - localTid = userTable.LocalTid; - if (request.HasSnapshotStep() || request.HasSnapshotTxId()) { const TSnapshotKey snapshotKey(pathId, rowVersion.Step, rowVersion.TxId); if (!SnapshotManager.FindAvailable(snapshotKey)) { @@ -743,45 +831,44 @@ void TDataShard::HandleSafe(TEvDataShard::TEvLocalKMeansRequest::TPtr& ev, const badRequest(TStringBuilder() << "Parent from " << parentFrom << " should be less or equal to parent to " << parentTo); return; } - const i64 expectedSize = parentTo - parentFrom + 1; - result->SizeAdd(expectedSize); - for (auto parent = parentFrom; parent <= parentTo; ++parent) { - TCell from, to; - const auto range = CreateRangeFrom(userTable, parent, from, to); - if (range.IsEmptyRange(userTable.KeyColumnTypes)) { - LOG_D("TEvLocalKMeansRequst " << request.GetId() << " parent " << parent << " is empty"); - continue; - } - - TAutoPtr scan; - auto createScan = [&] { - scan = new TLocalKMeansScan{ - request.GetId(), userTable, - CreateLeadFrom(range), parent, request.GetChild() + request.GetK() * (parent - parentFrom), - request, result, - }; - }; - MakeScan(request, createScan, badRequest); - if (!scan) { - Y_ASSERT(!result); + NTable::TLead lead; + if (parentFrom == 0 && parentTo == 0) { + lead.To({}, NTable::ESeek::Lower); + } else { + TCell from = TCell::Make(parentFrom - 1); + TCell to = TCell::Make(parentTo); + TTableRange range{{&from, 1}, false, {&to, 1}, true}; + auto scanRange = Intersect(userTable.KeyColumnTypes, range, userTable.Range.ToTableRange()); + if (scanRange.IsEmptyRange(userTable.KeyColumnTypes)) { + badRequest(TStringBuilder() << " requested range doesn't intersect with table range" + << " requestedRange: " << DebugPrintRange(userTable.KeyColumnTypes, range, *AppData()->TypeRegistry) + << " tableRange: " << DebugPrintRange(userTable.KeyColumnTypes, userTable.Range.ToTableRange(), *AppData()->TypeRegistry) + << " scanRange: " << DebugPrintRange(userTable.KeyColumnTypes, scanRange, *AppData()->TypeRegistry)); return; } - - TScanOptions scanOpts; - scanOpts.SetSnapshotRowVersion(rowVersion); - scanOpts.SetResourceBroker("build_index", 10); // TODO(mbkkt) Should be different group? - const auto scanId = QueueScan(userTable.LocalTid, std::move(scan), 0, scanOpts); - scanIds.push_back(scanId); + lead.To(range.From, NTable::ESeek::Upper); + lead.Until(range.To, true); } - - if (scanIds.empty()) { - badRequest("Requested range doesn't intersect with table range"); + + TAutoPtr scan; + auto createScan = [&] { + scan = new TLocalKMeansScan{ + userTable, request, ev->Sender, std::move(response), + std::move(lead) + }; + }; + MakeScan(request, createScan, badRequest); + if (!scan) { + Y_ASSERT(!response); return; } - result->SizeAdd(static_cast(scanIds.size()) - expectedSize); - result->Send(ctx, [] (auto&) { return true; }); // decrement extra one - ScanManager.Set(id, seqNo) = std::move(scanIds); + + TScanOptions scanOpts; + scanOpts.SetSnapshotRowVersion(rowVersion); + scanOpts.SetResourceBroker("build_index", 10); // TODO(mbkkt) Should be different group? + const auto scanId = QueueScan(userTable.LocalTid, std::move(scan), 0, scanOpts); + ScanManager.Set(id, seqNo).push_back(scanId); } } diff --git a/ydb/core/tx/datashard/prefix_kmeans.cpp b/ydb/core/tx/datashard/prefix_kmeans.cpp index 5a36035d782d..8742c3cf8ff0 100644 --- a/ydb/core/tx/datashard/prefix_kmeans.cpp +++ b/ydb/core/tx/datashard/prefix_kmeans.cpp @@ -101,12 +101,12 @@ class TPrefixKMeansScanBase: public TActor, public NTable TAutoPtr Response; // FIXME: save PrefixRows as std::vector> to avoid parsing - ui32 PrefixColumns; + const ui32 PrefixColumns; TSerializedCellVec Prefix; TBufferData PrefixRows; bool IsFirstPrefixFeed = true; bool IsPrefixRowsValid = true; - + bool IsExhausted = false; public: @@ -153,6 +153,7 @@ class TPrefixKMeansScanBase: public TActor, public NTable (*LevelTypes)[2] = {NTableIndex::NTableVectorKmeansTreeIndex::CentroidColumn, type}; } PostingTypes = MakeUploadTypes(table, UploadState, embedding, data, PrefixColumns); + // prefix types { auto types = GetAllTypes(table); @@ -242,8 +243,8 @@ class TPrefixKMeansScanBase: public TActor, public NTable HFunc(TEvTxUserProxy::TEvUploadRowsResponse, Handle); CFunc(TEvents::TSystem::Wakeup, HandleWakeup); default: - LOG_E("TPrefixKMeansScan: StateWork unexpected event type: " << ev->GetTypeRewrite() << " event: " - << ev->ToString() << " " << Debug()); + LOG_E("StateWork unexpected event type: " << ev->GetTypeRewrite() + << " event: " << ev->ToString() << " " << Debug()); } } @@ -299,11 +300,6 @@ class TPrefixKMeansScanBase: public TActor, public NTable Driver->Touch(EScan::Final); } - ui64 GetProbability() - { - return Rng.GenRand64(); - } - bool ShouldWaitUpload() { if (!HasReachedLimits(LevelBuf, ScanSettings) && !HasReachedLimits(PostingBuf, ScanSettings) && !HasReachedLimits(PrefixBuf, ScanSettings)) { @@ -381,6 +377,11 @@ class TPrefixKMeansScanBase: public TActor, public NTable ++pos; } } + + ui64 GetProbability() + { + return Rng.GenRand64(); + } }; template @@ -394,17 +395,13 @@ class TPrefixKMeansScan final: public TPrefixKMeansScanBase, private TCalculatio }; std::vector AggregatedClusters; - void StartNewPrefix() { Parent = Child + K; Child = Parent + 1; Round = 0; K = InitK; State = EState::SAMPLE; - // TODO(mbkkt) Upper or Lower doesn't matter here, because we seek to (prefix, inf) - // so we can choose Lower if it's faster. - // Exact seek with Lower also possible but needs to rewrite some code in Feed - Lead.To(Prefix.GetCells(), NTable::ESeek::Upper); + Lead.To(Prefix.GetCells(), NTable::ESeek::Upper); // seek to (prefix, inf) Prefix = {}; IsFirstPrefixFeed = true; IsPrefixRowsValid = true; @@ -804,6 +801,11 @@ void TDataShard::HandleSafe(TEvDataShard::TEvPrefixKMeansRequest::TPtr& ev, cons return; } + if (request.GetPrefixColumns() <= 0) { + badRequest("Should be requested on at least one prefix column"); + return; + } + TAutoPtr scan; auto createScan = [&] { scan = new TPrefixKMeansScan{ diff --git a/ydb/core/tx/datashard/reshuffle_kmeans.cpp b/ydb/core/tx/datashard/reshuffle_kmeans.cpp index f7db951e60b6..f3a7f9008761 100644 --- a/ydb/core/tx/datashard/reshuffle_kmeans.cpp +++ b/ydb/core/tx/datashard/reshuffle_kmeans.cpp @@ -189,8 +189,8 @@ class TReshuffleKMeansScanBase: public TActor, public hFunc(TEvTxUserProxy::TEvUploadRowsResponse, Handle); cFunc(TEvents::TSystem::Wakeup, HandleWakeup); default: - LOG_E("TReshuffleKMeansScan: StateWork unexpected event type: " << ev->GetTypeRewrite() << " event: " - << ev->ToString() << " " << Debug()); + LOG_E("StateWork unexpected event type: " << ev->GetTypeRewrite() + << " event: " << ev->ToString() << " " << Debug()); } } diff --git a/ydb/core/tx/datashard/sample_k.cpp b/ydb/core/tx/datashard/sample_k.cpp index e8472a4d7ec1..011418b5e8a3 100644 --- a/ydb/core/tx/datashard/sample_k.cpp +++ b/ydb/core/tx/datashard/sample_k.cpp @@ -180,7 +180,8 @@ class TSampleKScan final: public TActor, public NTable::IScan { STFUNC(StateWork) { switch (ev->GetTypeRewrite()) { default: - LOG_E("TSampleKScan: StateWork unexpected event type: " << ev->GetTypeRewrite() << " event: " << ev->ToString() << " " << Debug()); + LOG_E("StateWork unexpected event type: " << ev->GetTypeRewrite() + << " event: " << ev->ToString() << " " << Debug()); } } From 14032f4734679e3f5f879b3cc1fe9efa77bb103a Mon Sep 17 00:00:00 2001 From: YDBot Date: Tue, 8 Apr 2025 19:55:38 +0200 Subject: [PATCH 063/454] Update muted_ya.txt in main (#16947) --- .github/config/muted_ya.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/config/muted_ya.txt b/.github/config/muted_ya.txt index 4a86e11680b7..37b34790c5be 100644 --- a/.github/config/muted_ya.txt +++ b/.github/config/muted_ya.txt @@ -94,7 +94,6 @@ ydb/tests/functional/compatibility test_stress.py.TestStress.test_tpch1[mixed-ro ydb/tests/functional/hive test_drain.py.TestHive.test_drain_on_stop ydb/tests/functional/rename [test_rename.py */*] chunk chunk ydb/tests/functional/serializable sole chunk chunk -ydb/tests/functional/serializable test.py.test_local ydb/tests/functional/serverless test_serverless.py.test_database_with_disk_quotas[enable_alter_database_create_hive_first--false] ydb/tests/functional/serverless test_serverless.py.test_database_with_disk_quotas[enable_alter_database_create_hive_first--true] ydb/tests/functional/suite_tests [test_sql_logic.py */*] chunk chunk @@ -125,10 +124,13 @@ ydb/tests/functional/tpc/large test_tpcds.py.TestTpcdsS1.test_tpcds[86] ydb/tests/functional/tpc/large test_tpcds.py.TestTpcdsS1.test_tpcds[9] ydb/tests/functional/tpc/large test_tpch_spilling.py.TestTpchSpillingS10.test_tpch[7] ydb/tests/olap sole chunk chunk +ydb/tests/olap test_log_scenario.py.TestLogScenario.test ydb/tests/olap test_quota_exhaustion.py.TestYdbWorkload.test_delete -ydb/tests/olap/data_quotas test_quota_exhaustion.py.TestYdbWorkload.test_duplicates ydb/tests/olap/column_family/compression alter_compression.py.TestAlterCompression.test_all_supported_compression ydb/tests/olap/column_family/compression sole chunk chunk +ydb/tests/olap/data_quotas [*/*] chunk chunk +ydb/tests/olap/data_quotas test_quota_exhaustion.py.TestYdbWorkload.test +ydb/tests/olap/data_quotas test_quota_exhaustion.py.TestYdbWorkload.test_duplicates ydb/tests/olap/oom overlapping_portions.py.TestOverlappingPortions.test ydb/tests/olap/scenario sole chunk chunk ydb/tests/olap/scenario test_alter_compression.py.TestAlterCompression.test[alter_compression] From af8199d7471ce27ce36694743b8733a190d78105 Mon Sep 17 00:00:00 2001 From: Pisarenko Grigoriy Date: Tue, 8 Apr 2025 21:15:13 +0300 Subject: [PATCH 064/454] YQ supported compute databases in fqrun and in memory cp storage (#16821) --- ydb/core/fq/libs/compute/common/config.h | 10 +- ...compute_database_control_plane_service.cpp | 19 +- ydb/core/fq/libs/config/protos/compute.proto | 1 + .../control_plane_storage/events/events.h | 29 +- .../in_memory_control_plane_storage.cpp | 298 ++++++++-- .../ydb_control_plane_storage_bindings.cpp | 7 +- ...control_plane_storage_compute_database.cpp | 2 +- .../ydb_control_plane_storage_connections.cpp | 14 +- .../ydb_control_plane_storage_impl.h | 12 + .../in_memory_control_plane_storage_ut.cpp | 78 ++- .../fq/streaming_optimize/cfg/app_config.conf | 309 +++++++++++ .../fq/streaming_optimize/cfg/fq_config.conf | 307 ----------- .../streaming_optimize/test_sql_streaming.py | 2 +- ydb/tests/fq/tools/fqrun.py | 3 +- .../kqp_yt_import/kqprun_import_config.conf | 19 + ydb/tests/fq/yt/kqp_yt_import/test_ctas.py | 3 +- ydb/tests/tools/fqrun/README.md | 18 +- .../tools/fqrun/configuration/app_config.conf | 510 ++++++++++++++++++ .../tools/fqrun/configuration/as_config.conf | 46 -- .../tools/fqrun/configuration/fq_config.conf | 302 ----------- ydb/tests/tools/fqrun/fqrun.cpp | 96 ++-- ydb/tests/tools/fqrun/src/common.h | 20 +- ydb/tests/tools/fqrun/src/fq_runner.cpp | 38 +- ydb/tests/tools/fqrun/src/fq_runner.h | 6 +- ydb/tests/tools/fqrun/src/fq_setup.cpp | 157 +++--- ydb/tests/tools/fqrun/src/fq_setup.h | 10 +- ydb/tests/tools/fqrun/src/ya.make | 1 + .../tools/kqprun/runlib/kikimr_setup.cpp | 135 +++++ ydb/tests/tools/kqprun/runlib/kikimr_setup.h | 31 ++ ydb/tests/tools/kqprun/runlib/settings.h | 14 + ydb/tests/tools/kqprun/runlib/ya.make | 7 + ydb/tests/tools/kqprun/src/common.h | 13 - ydb/tests/tools/kqprun/src/ydb_setup.cpp | 128 +---- 33 files changed, 1607 insertions(+), 1038 deletions(-) create mode 100644 ydb/tests/fq/streaming_optimize/cfg/app_config.conf delete mode 100644 ydb/tests/fq/streaming_optimize/cfg/fq_config.conf create mode 100644 ydb/tests/tools/fqrun/configuration/app_config.conf delete mode 100644 ydb/tests/tools/fqrun/configuration/as_config.conf delete mode 100644 ydb/tests/tools/fqrun/configuration/fq_config.conf create mode 100644 ydb/tests/tools/kqprun/runlib/kikimr_setup.cpp create mode 100644 ydb/tests/tools/kqprun/runlib/kikimr_setup.h diff --git a/ydb/core/fq/libs/compute/common/config.h b/ydb/core/fq/libs/compute/common/config.h index 579869553e12..19f6325582ea 100644 --- a/ydb/core/fq/libs/compute/common/config.h +++ b/ydb/core/fq/libs/compute/common/config.h @@ -159,7 +159,10 @@ class TComputeConfig { case NConfig::TYdbComputeControlPlane::TYPE_NOT_SET: return {}; case NConfig::TYdbComputeControlPlane::kSingle: - return controlPlane.GetSingle().GetWorkloadManagerConfig(); + if (controlPlane.GetSingle().HasWorkloadManagerConfig()) { + return controlPlane.GetSingle().GetWorkloadManagerConfig(); + } + return controlPlane.GetDefaultWorkloadManagerConfig(); case NConfig::TYdbComputeControlPlane::kCms: return GetWorkloadManagerConfig(scope, controlPlane.GetCms().GetDatabaseMapping()); case NConfig::TYdbComputeControlPlane::kYdbcp: @@ -169,7 +172,10 @@ class TComputeConfig { NFq::NConfig::TWorkloadManagerConfig GetWorkloadManagerConfig(const TString& scope, const ::NFq::NConfig::TDatabaseMapping& databaseMapping) const { auto computeDatabaseConfig = GetComputeDatabaseConfig(scope, databaseMapping); - return computeDatabaseConfig.GetWorkloadManagerConfig(); + if (computeDatabaseConfig.HasWorkloadManagerConfig()) { + return computeDatabaseConfig.GetWorkloadManagerConfig(); + } + return ComputeConfig.GetYdb().GetControlPlane().GetDefaultWorkloadManagerConfig(); } NFq::NConfig::TComputeDatabaseConfig GetComputeDatabaseConfig(const TString& scope, const ::NFq::NConfig::TDatabaseMapping& databaseMapping) const { diff --git a/ydb/core/fq/libs/compute/ydb/control_plane/compute_database_control_plane_service.cpp b/ydb/core/fq/libs/compute/ydb/control_plane/compute_database_control_plane_service.cpp index 7326b1845b14..64ea30faeb36 100644 --- a/ydb/core/fq/libs/compute/ydb/control_plane/compute_database_control_plane_service.cpp +++ b/ydb/core/fq/libs/compute/ydb/control_plane/compute_database_control_plane_service.cpp @@ -89,7 +89,7 @@ class TCreateDatabaseRequestActor : public NActors::TActorBootstrappedGet()->CloudId, Request.Get()->Get()->Scope, singleConfig.GetConnection(), singleConfig.GetWorkloadManagerConfig()}); + Send(SynchronizationServiceActorId, new TEvYdbCompute::TEvSynchronizeRequest{Request.Get()->Get()->CloudId, Request.Get()->Get()->Scope, singleConfig.GetConnection(), GetWorkloadManagerConfig(singleConfig)}); } break; case NConfig::TYdbComputeControlPlane::kCms: @@ -163,7 +163,7 @@ class TCreateDatabaseRequestActor : public NActors::TActorBootstrappedGet()->CloudId, Request.Get()->Get()->Scope, Result.connection(), client->Config.GetWorkloadManagerConfig()}); + Send(SynchronizationServiceActorId, new TEvYdbCompute::TEvSynchronizeRequest{Request.Get()->Get()->CloudId, Request.Get()->Get()->Scope, Result.connection(), GetWorkloadManagerConfig(client->Config)}); } else { auto invalidateSynchronizationEvent = std::make_unique(Request->Get()->CloudId, Scope); invalidateSynchronizationEvent->Synchronized = false; @@ -199,7 +199,7 @@ class TCreateDatabaseRequestActor : public NActors::TActorBootstrappedCookie == OnlyDatabaseCreateCookie) { - Send(SynchronizationServiceActorId, new TEvYdbCompute::TEvSynchronizeRequest{Request.Get()->Get()->CloudId, Request.Get()->Get()->Scope, Result.connection(), client->Config.GetWorkloadManagerConfig()}); + Send(SynchronizationServiceActorId, new TEvYdbCompute::TEvSynchronizeRequest{Request.Get()->Get()->CloudId, Request.Get()->Get()->Scope, Result.connection(), GetWorkloadManagerConfig(client->Config)}); return; } Send(ControlPlaneStorageServiceActorId(), new TEvControlPlaneStorage::TEvCreateDatabaseRequest{Request->Get()->CloudId, Scope, Result}); @@ -266,7 +266,7 @@ class TCreateDatabaseRequestActor : public NActors::TActorBootstrappedGet()->CloudId, Request.Get()->Get()->Scope, Result.connection(), client->Config.GetWorkloadManagerConfig()}); + Send(SynchronizationServiceActorId, new TEvYdbCompute::TEvSynchronizeRequest{Request.Get()->Get()->CloudId, Request.Get()->Get()->Scope, Result.connection(), GetWorkloadManagerConfig(client->Config)}); } void Handle(TEvYdbCompute::TEvSynchronizeResponse::TPtr& ev) { @@ -298,11 +298,20 @@ class TCreateDatabaseRequestActor : public NActors::TActorBootstrapped + NConfig::TWorkloadManagerConfig GetWorkloadManagerConfig(const TComputeConfig& config) const { + if (config.HasWorkloadManagerConfig()) { + return config.GetWorkloadManagerConfig(); + } + return Config.GetYdb().GetControlPlane().GetDefaultWorkloadManagerConfig(); + } + private: TString Scope; std::shared_ptr Clients; TActorId SynchronizationServiceActorId; - NFq::NConfig::TComputeConfig Config; + NConfig::TComputeConfig Config; TEvYdbCompute::TEvCreateDatabaseRequest::TPtr Request; FederatedQuery::Internal::ComputeDatabaseInternal Result; diff --git a/ydb/core/fq/libs/config/protos/compute.proto b/ydb/core/fq/libs/config/protos/compute.proto index 172a6092b1cc..e6bfcf08e02e 100644 --- a/ydb/core/fq/libs/config/protos/compute.proto +++ b/ydb/core/fq/libs/config/protos/compute.proto @@ -86,6 +86,7 @@ message TYdbComputeControlPlane { } string DatabasePrefix = 5; string DatabasesCacheReloadPeriod = 6; + TWorkloadManagerConfig DefaultWorkloadManagerConfig = 7; } message TYdbCompute { diff --git a/ydb/core/fq/libs/control_plane_storage/events/events.h b/ydb/core/fq/libs/control_plane_storage/events/events.h index d5b83f58da3d..1cf6244f6670 100644 --- a/ydb/core/fq/libs/control_plane_storage/events/events.h +++ b/ydb/core/fq/libs/control_plane_storage/events/events.h @@ -680,31 +680,36 @@ struct TEvControlPlaneStorage { }; struct TEvCreateDatabaseRequest : NActors::TEventLocal { + using TProto = FederatedQuery::Internal::ComputeDatabaseInternal; + TEvCreateDatabaseRequest() = default; explicit TEvCreateDatabaseRequest(const TString& cloudId, const TString& scope, const FederatedQuery::Internal::ComputeDatabaseInternal& record) : CloudId(cloudId) , Scope(scope) - , Record(record) + , Request(record) {} size_t GetByteSize() const { return sizeof(*this) + CloudId.size() + Scope.size() - + Record.ByteSizeLong(); + + Request.ByteSizeLong(); } TString CloudId; TString Scope; - FederatedQuery::Internal::ComputeDatabaseInternal Record; + FederatedQuery::Internal::ComputeDatabaseInternal Request; }; struct TEvCreateDatabaseResponse : NActors::TEventLocal { + using TProto = google::protobuf::Empty; + static constexpr bool Auditable = false; - explicit TEvCreateDatabaseResponse() - {} + explicit TEvCreateDatabaseResponse(const google::protobuf::Empty& response = {}) { + Y_UNUSED(response); + } explicit TEvCreateDatabaseResponse(const NYql::TIssues& issues) : Issues(issues) @@ -721,6 +726,7 @@ struct TEvControlPlaneStorage { }; struct TEvDescribeDatabaseRequest : NActors::TEventLocal { + using TProto = google::protobuf::Empty; TEvDescribeDatabaseRequest() = default; @@ -744,6 +750,8 @@ struct TEvControlPlaneStorage { struct TEvDescribeDatabaseResponse : NActors::TEventLocal { static constexpr bool Auditable = false; + using TProto = FederatedQuery::Internal::ComputeDatabaseInternal; + explicit TEvDescribeDatabaseResponse(const FederatedQuery::Internal::ComputeDatabaseInternal& record) : Record(record) {} @@ -767,6 +775,8 @@ struct TEvControlPlaneStorage { }; struct TEvModifyDatabaseRequest : NActors::TEventLocal { + using TProto = google::protobuf::Empty; + TEvModifyDatabaseRequest() = default; explicit TEvModifyDatabaseRequest(const TString& cloudId, const TString& scope) @@ -776,10 +786,12 @@ struct TEvControlPlaneStorage { size_t GetByteSize() const { return sizeof(*this) + + Request.ByteSizeLong() + CloudId.size() + Scope.size(); } + google::protobuf::Empty Request; TString CloudId; TString Scope; TMaybe Synchronized; @@ -788,10 +800,13 @@ struct TEvControlPlaneStorage { }; struct TEvModifyDatabaseResponse : NActors::TEventLocal { + using TProto = google::protobuf::Empty; + static constexpr bool Auditable = false; - explicit TEvModifyDatabaseResponse() - {} + explicit TEvModifyDatabaseResponse(const google::protobuf::Empty& response = {}) { + Y_UNUSED(response); + } explicit TEvModifyDatabaseResponse(const NYql::TIssues& issues) : Issues(issues) diff --git a/ydb/core/fq/libs/control_plane_storage/in_memory_control_plane_storage.cpp b/ydb/core/fq/libs/control_plane_storage/in_memory_control_plane_storage.cpp index 55e67b1f1908..ea10988aa31f 100644 --- a/ydb/core/fq/libs/control_plane_storage/in_memory_control_plane_storage.cpp +++ b/ydb/core/fq/libs/control_plane_storage/in_memory_control_plane_storage.cpp @@ -146,6 +146,21 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor Values; }; + struct TComputeDatabases { + struct TKey { + TString Scope; + + std::strong_ordering operator<=>(const TKey& other) const = default; + }; + + struct TValue { + FederatedQuery::Internal::ComputeDatabaseInternal Database; + TInstant LastAccessAt; + }; + + TMap Values; + }; + using TBase = TControlPlaneStorageBase; TQueries Queries; @@ -156,6 +171,7 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor + template class TCommonRequestContext { public: using TResultType = TPrepareResponseResultType; @@ -232,9 +256,11 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor(EventPtr->Sender, issues, EventPtr->Cookie, TInstant::Now() - StartTime, RequestCounters); } @@ -286,9 +314,9 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor - class TRequestContext : public TCommonRequestContext { - using TBase = TCommonRequestContext; + template + class TRequestContext : public TCommonRequestContext { + using TBase = TCommonRequestContext; Y_HAS_MEMBER(idempotency_key); static constexpr bool HasIdempotencyKey = THasidempotency_key::value; @@ -360,26 +388,26 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor; \ - void Handle(TEvControlPlaneStorage::TEvRequest::TPtr& ev) { \ - TContext##TEvRequest ctx(*this, ev, #TEvRequest, #TEvResponse); \ - if (!ctx.Validate()) { \ - return; \ - } \ - try { \ - Process##TRequest(ctx); \ - } catch (...) { \ - const auto& backtrace = TBackTrace::FromCurrentException().PrintToString(); \ - const auto logError = TStringBuilder() << "pocess "#TEvRequest" call, back trace:\n" << backtrace; \ - ctx.Fail(logError, {NYql::TIssue(CurrentExceptionMessage())}); \ - } \ - } \ +#define HANDLE_CPS_REQUEST_IMPL(TEvRequest, TEvResponse, TContext, RTS_COUNTERS_ENUM, RTC_COUNTERS_ENUM, VALIDATE_REQUEST) \ + using TContext##TEvRequest = TContext< \ + TEvControlPlaneStorage::TEvRequest, TEvControlPlaneStorage::TEvResponse, \ + RTS_COUNTERS_ENUM, RTC_COUNTERS_ENUM, VALIDATE_REQUEST>; \ + void Handle(TEvControlPlaneStorage::TEvRequest::TPtr& ev) { \ + TContext##TEvRequest ctx(*this, ev, #TEvRequest, #TEvResponse); \ + if (!ctx.Validate()) { \ + return; \ + } \ + try { \ + Process##TRequest(ctx); \ + } catch (...) { \ + const auto& backtrace = TBackTrace::FromCurrentException().PrintToString(); \ + const auto logError = TStringBuilder() << "pocess "#TEvRequest" call, back trace:\n" << backtrace; \ + ctx.Fail(logError, {NYql::TIssue(CurrentExceptionMessage())}); \ + } \ + } \ void Process##TRequest(TContext##TEvRequest& ctx) -#define HANDLE_CPS_REQUEST(TEvRequest, TEvResponse, COUNTERS_ENUM) HANDLE_CPS_REQUEST_IMPL(TEvRequest, TEvResponse, TRequestContext, RTS_##COUNTERS_ENUM, RTC_##COUNTERS_ENUM) +#define HANDLE_CPS_REQUEST(TEvRequest, TEvResponse, COUNTERS_ENUM) HANDLE_CPS_REQUEST_IMPL(TEvRequest, TEvResponse, TRequestContext, RTS_##COUNTERS_ENUM, RTC_##COUNTERS_ENUM, true) HANDLE_CPS_REQUEST(TEvCreateQueryRequest, TEvCreateQueryResponse, CREATE_QUERY) { const auto& [query, job] = GetCreateQueryProtos(ctx.Request, ctx.User, ctx.StartTime); @@ -548,20 +576,56 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor(ev, "ListConnectionsRequest"); + HANDLE_CPS_REQUEST(TEvListConnectionsRequest, TEvListConnectionsResponse, LIST_CONNECTIONS) { + auto connections = GetEntities(Connections, ctx.Scope, ctx.User); + auto& resultConnections = *ctx.Response.mutable_connection(); + const auto& filter = ctx.Request.filter(); + + auto it = std::lower_bound(connections.begin(), connections.end(), ctx.Request.page_token(), [](const auto& l, const auto& r) { + return l.meta().id() < r; + }); + for (; it != connections.end(); ++it) { + const auto& content = it->content(); + if (const auto& nameFilter = filter.name()) { + const auto& name = content.name(); + if (ctx.Event.IsExactNameMatch ? name != nameFilter : !name.Contains(nameFilter)) { + continue; + } + } + + if (filter.created_by_me() && it->meta().created_by() != ctx.User) { + continue; + } + + if (filter.connection_type() != FederatedQuery::ConnectionSetting::CONNECTION_TYPE_UNSPECIFIED && content.setting().connection_case() != static_cast(filter.connection_type())) { + continue; + } + + if (filter.visibility() != FederatedQuery::Acl::VISIBILITY_UNSPECIFIED && content.acl().visibility() != filter.visibility()) { + continue; + } + + *resultConnections.Add() = *it; + if (resultConnections.size() == ctx.Request.limit() + 1) { + ctx.Response.set_next_page_token(ctx.Response.connection(ctx.Response.connection_size() - 1).meta().id()); + resultConnections.RemoveLast(); + break; + } + } } - void Handle(TEvControlPlaneStorage::TEvDescribeConnectionRequest::TPtr& ev) { - LOG_YQ_CONTROL_PLANE_STORAGE_CRIT("Unimplemented " << __LINE__); - SendEmptyResponse< - TEvControlPlaneStorage::TEvDescribeConnectionRequest::TPtr, - FederatedQuery::DescribeConnectionResult, - TEvControlPlaneStorage::TEvDescribeConnectionResponse>(ev, "DescribeConnectionRequest"); + HANDLE_CPS_REQUEST(TEvDescribeConnectionRequest, TEvDescribeConnectionResponse, DESCRIBE_CONNECTION) { + const auto& connection = GetEntity(Connections, {ctx.Scope, ctx.Request.connection_id()}); + if (!connection) { + return ctx.Fail("find connection", {NYql::TIssue("Connection does not exist")}); + } + + const auto& connectionProto = connection->Connection; + if (!HasViewAccess(GetPermissions(ctx.Permissions, ctx.User), connectionProto.content().acl().visibility(), connectionProto.meta().created_by(), ctx.User)) { + return ctx.Fail("check permissions", {NYql::TIssue("Permission denied")}); + } + + *ctx.Response.mutable_connection() = connectionProto; } void Handle(TEvControlPlaneStorage::TEvModifyConnectionRequest::TPtr& ev) { @@ -622,12 +686,61 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor(ev, "ListBindingsRequest"); + HANDLE_CPS_REQUEST(TEvListBindingsRequest, TEvListBindingsResponse, LIST_BINDINGS) { + auto bindings = GetEntities(Bindings, ctx.Scope, ctx.User); + auto& resultBindings = *ctx.Response.mutable_binding(); + const auto& filter = ctx.Request.filter(); + + auto it = std::lower_bound(bindings.begin(), bindings.end(), ctx.Request.page_token(), [](const auto& l, const auto& r) { + return l.meta().id() < r; + }); + for (; it != bindings.end(); ++it) { + const auto& content = it->content(); + const auto& connectionId = content.connection_id(); + if (filter.connection_id() && connectionId != filter.connection_id()) { + continue; + } + + const auto& name = content.name(); + if (const auto& nameFilter = filter.name()) { + if (ctx.Event.IsExactNameMatch ? name != nameFilter : !name.Contains(nameFilter)) { + continue; + } + } + + const auto& meta = it->meta(); + if (filter.created_by_me() && meta.created_by() != ctx.User) { + continue; + } + + const auto visibility = content.acl().visibility(); + if (filter.visibility() != FederatedQuery::Acl::VISIBILITY_UNSPECIFIED && visibility != filter.visibility()) { + continue; + } + + auto& resultBinding = *resultBindings.Add(); + resultBinding.set_name(name); + resultBinding.set_connection_id(connectionId); + resultBinding.set_visibility(visibility); + *resultBinding.mutable_meta() = meta; + + switch (content.setting().binding_case()) { + case FederatedQuery::BindingSetting::kDataStreams: + resultBinding.set_type(FederatedQuery::BindingSetting::DATA_STREAMS); + break; + case FederatedQuery::BindingSetting::kObjectStorage: + resultBinding.set_type(FederatedQuery::BindingSetting::OBJECT_STORAGE); + break; + case FederatedQuery::BindingSetting::BINDING_NOT_SET: + break; + } + + if (resultBindings.size() == ctx.Request.limit() + 1) { + ctx.Response.set_next_page_token(ctx.Response.binding(ctx.Response.binding_size() - 1).meta().id()); + resultBindings.RemoveLast(); + break; + } + } } void Handle(TEvControlPlaneStorage::TEvDescribeBindingRequest::TPtr& ev) { @@ -664,7 +777,7 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor(ev, "DescribeJobRequest"); } - HANDLE_CPS_REQUEST_IMPL(TEvWriteResultDataRequest, TEvWriteResultDataResponse, TCommonRequestContext, RTS_MAX, RTC_WRITE_RESULT_DATA) { + HANDLE_CPS_REQUEST_IMPL(TEvWriteResultDataRequest, TEvWriteResultDataResponse, TCommonRequestContext, RTS_MAX, RTC_WRITE_RESULT_DATA, true) { ctx.Response.set_request_id(ctx.Request.request_id()); const auto offset = ctx.Request.offset(); @@ -679,7 +792,7 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor tasks; @@ -696,7 +809,7 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActorStatus, finalStatus->StatusCode, finalStatus->QueryType, finalStatus->Issues, finalStatus->TransientIssues)); } - HANDLE_CPS_REQUEST_IMPL(TEvNodesHealthCheckRequest, TEvNodesHealthCheckResponse, TCommonRequestContext, RTS_MAX, RTC_NODES_HEALTH_CHECK) { + HANDLE_CPS_REQUEST_IMPL(TEvNodesHealthCheckRequest, TEvNodesHealthCheckResponse, TCommonRequestContext, RTS_MAX, RTC_NODES_HEALTH_CHECK, true) { const auto& tenant = ctx.Request.tenant(); const auto& node = ctx.Request.node(); @@ -747,6 +860,83 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor(ev, "GetQueryStatusRequest"); + } + + void Handle(TEvControlPlaneStorage::TEvCreateRateLimiterResourceRequest::TPtr& ev) { + LOG_YQ_CONTROL_PLANE_STORAGE_CRIT("Unimplemented " << __LINE__); + SendEmptyResponse< + TEvControlPlaneStorage::TEvCreateRateLimiterResourceRequest::TPtr, + Fq::Private::CreateRateLimiterResourceResult, + TEvControlPlaneStorage::TEvCreateRateLimiterResourceResponse>(ev, "CreateRateLimiterResourceRequest"); + } + + void Handle(TEvControlPlaneStorage::TEvDeleteRateLimiterResourceRequest::TPtr& ev) { + LOG_YQ_CONTROL_PLANE_STORAGE_CRIT("Unimplemented " << __LINE__); + SendEmptyResponse< + TEvControlPlaneStorage::TEvDeleteRateLimiterResourceRequest::TPtr, + Fq::Private::DeleteRateLimiterResourceResult, + TEvControlPlaneStorage::TEvDeleteRateLimiterResourceResponse>(ev, "DeleteRateLimiterResourceRequest"); + } + + void Handle(TEvQuotaService::TQuotaUsageRequest::TPtr& ev) { + LOG_YQ_CONTROL_PLANE_STORAGE_CRIT("Unimplemented " << __LINE__); + Send(ev->Sender, new TEvQuotaService::TQuotaUsageResponse(ev->Get()->SubjectType, ev->Get()->SubjectId, ev->Get()->MetricName, 0)); + } + + void Handle(TEvQuotaService::TQuotaLimitChangeRequest::TPtr& ev) { + LOG_YQ_CONTROL_PLANE_STORAGE_CRIT("Unimplemented " << __LINE__); + Send(ev->Sender, new TEvQuotaService::TQuotaLimitChangeResponse(ev->Get()->SubjectType, ev->Get()->SubjectId, ev->Get()->MetricName, ev->Get()->Limit, ev->Get()->LimitRequested)); + } + + HANDLE_CPS_REQUEST_IMPL(TEvCreateDatabaseRequest, TEvCreateDatabaseResponse, TCommonRequestContext, RTS_CREATE_DATABASE, RTC_CREATE_DATABASE, false) { + AddEntity(ComputeDatabases, {ctx.Event.Scope}, { + .Database = ctx.Request, + .LastAccessAt = TInstant::Now() + }); + } + + HANDLE_CPS_REQUEST_IMPL(TEvDescribeDatabaseRequest, TEvDescribeDatabaseResponse, TCommonRequestContext, RTS_DESCRIBE_DATABASE, RTC_DESCRIBE_DATABASE, false) { + const auto& database = GetEntity(ComputeDatabases, {ctx.Event.Scope}); + if (!database) { + NYql::TIssue issue(TStringBuilder() << "Compute database does not exist for scope " << ctx.Event.Scope); + issue.SetCode(TIssuesIds::ACCESS_DENIED, NYql::TSeverityIds::S_ERROR); + return ctx.Fail("find compute database", {issue}); + } + + ctx.Response = database->Database; + } + + HANDLE_CPS_REQUEST_IMPL(TEvModifyDatabaseRequest, TEvModifyDatabaseResponse, TCommonRequestContext, RTS_MODIFY_DATABASE, RTC_MODIFY_DATABASE, false) { + const auto it = ComputeDatabases.Values.find({ctx.Event.Scope}); + + if (const auto lastAccessAt = ctx.Event.LastAccessAt) { + if (it != ComputeDatabases.Values.end()) { + it->second.LastAccessAt = *lastAccessAt; + } + return; + } + + if (it == ComputeDatabases.Values.end()) { + NYql::TIssue issue(TStringBuilder() << "Compute database does not exist for scope " << ctx.Event.Scope); + issue.SetCode(TIssuesIds::ACCESS_DENIED, NYql::TSeverityIds::S_ERROR); + return ctx.Fail("update compute database", {issue}); + } + + if (const auto synchronized = ctx.Event.Synchronized) { + it->second.Database.set_synchronized(*synchronized); + } + + if (const auto wmSynchronized = ctx.Event.WorkloadManagerSynchronized) { + it->second.Database.set_workload_manager_synchronized(*wmSynchronized); + } + } + #undef HANDLE_CPS_REQUEST #undef HANDLE_CPS_REQUEST_IMPL @@ -857,6 +1047,16 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActorProto.GetEnablePermissions() + ? requestPermissions + : TPermissions{TPermissions::VIEW_PUBLIC}; + if (IsSuperUser(user)) { + permissions.SetAll(); + } + return permissions; + } + private: void Cleanup() { CleanupTable(Queries); @@ -926,7 +1126,7 @@ class TInMemoryControlPlaneStorageActor : public NActors::TActor AssignTask(const TCommonRequestContextTEvGetTaskRequest& ctx, TTaskInternal taskInternal) { + std::optional AssignTask(TCommonRequestContextTEvGetTaskRequest& ctx, TTaskInternal taskInternal) { auto& task = taskInternal.Task; const auto& query = GetEntity(Queries, {task.Scope, task.QueryId}); diff --git a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_bindings.cpp b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_bindings.cpp index a643a520f32e..5619ea8833c8 100644 --- a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_bindings.cpp +++ b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_bindings.cpp @@ -179,6 +179,10 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvCreateBindi }); } +NYql::TIssues TControlPlaneStorageBase::ValidateRequest(TEvControlPlaneStorage::TEvListBindingsRequest::TPtr& ev) const { + return ValidateEvent(ev); +} + void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvListBindingsRequest::TPtr& ev) { TInstant startTime = TInstant::Now(); @@ -205,8 +209,7 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvListBinding << NKikimr::MaskTicket(token) << " " << request.DebugString()); - NYql::TIssues issues = ValidateEvent(ev); - if (issues) { + if (const auto& issues = ValidateRequest(ev)) { CPS_LOG_D(MakeLogPrefix(scope, user) << "ListBindingsRequest, validation failed: " << NKikimr::MaskTicket(token) << " " diff --git a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_compute_database.cpp b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_compute_database.cpp index c0e796bb5a0a..9a446f6875c3 100644 --- a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_compute_database.cpp +++ b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_compute_database.cpp @@ -19,7 +19,7 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvCreateDatab TRequestCounters requestCounters = Counters.GetCounters(cloudId, scope, RTS_CREATE_DATABASE, RTC_CREATE_DATABASE); requestCounters.IncInFly(); requestCounters.Common->RequestBytes->Add(event.GetByteSize()); - const FederatedQuery::Internal::ComputeDatabaseInternal& request = event.Record; + const FederatedQuery::Internal::ComputeDatabaseInternal& request = event.Request; const int byteSize = request.ByteSize(); CPS_LOG_T(MakeLogPrefix(scope, "internal", request.id()) diff --git a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_connections.cpp b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_connections.cpp index 79be5ca2f107..9f749ce63185 100644 --- a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_connections.cpp +++ b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_connections.cpp @@ -217,6 +217,10 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvCreateConne }); } +NYql::TIssues TControlPlaneStorageBase::ValidateRequest(TEvControlPlaneStorage::TEvListConnectionsRequest::TPtr& ev) const { + return ValidateEvent(ev); +} + void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvListConnectionsRequest::TPtr& ev) { TInstant startTime = TInstant::Now(); @@ -245,8 +249,7 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvListConnect << NKikimr::MaskTicket(token) << " " << request.DebugString()); - NYql::TIssues issues = ValidateEvent(ev); - if (issues) { + if (const auto& issues = ValidateRequest(ev)) { CPS_LOG_D(MakeLogPrefix(scope, user) << "ListConnectionsRequest, validation failed: " << NKikimr::MaskTicket(token) << " " @@ -352,6 +355,10 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvListConnect }); } +NYql::TIssues TControlPlaneStorageBase::ValidateRequest(TEvControlPlaneStorage::TEvDescribeConnectionRequest::TPtr& ev) const { + return ValidateEvent(ev); +} + void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvDescribeConnectionRequest::TPtr& ev) { TInstant startTime = TInstant::Now(); @@ -379,8 +386,7 @@ void TYdbControlPlaneStorageActor::Handle(TEvControlPlaneStorage::TEvDescribeCon << NKikimr::MaskTicket(token) << " " << request.DebugString()); - NYql::TIssues issues = ValidateEvent(ev); - if (issues) { + if (const auto& issues = ValidateRequest(ev)) { CPS_LOG_D(MakeLogPrefix(scope, user, connectionId) << "DescribeConnectionRequest, validation failed: " << NKikimr::MaskTicket(token)<< " " diff --git a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_impl.h b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_impl.h index 78c532bc6b43..7072c57815dc 100644 --- a/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_impl.h +++ b/ydb/core/fq/libs/control_plane_storage/ydb_control_plane_storage_impl.h @@ -641,6 +641,14 @@ class TControlPlaneStorageBase : public TControlPlaneStorageUtils { std::pair GetCreateConnectionProtos( const FederatedQuery::CreateConnectionRequest& request, const TString& cloudId, const TString& user, TInstant startTime) const; + // List connections request + + NYql::TIssues ValidateRequest(TEvControlPlaneStorage::TEvListConnectionsRequest::TPtr& ev) const; + + // Describe connections request + + NYql::TIssues ValidateRequest(TEvControlPlaneStorage::TEvDescribeConnectionRequest::TPtr& ev) const; + // Create binding request NYql::TIssues ValidateRequest(TEvControlPlaneStorage::TEvCreateBindingRequest::TPtr& ev) const; @@ -650,6 +658,10 @@ class TControlPlaneStorageBase : public TControlPlaneStorageUtils { std::pair GetCreateBindingProtos( const FederatedQuery::CreateBindingRequest& request, const TString& cloudId, const TString& user, TInstant startTime) const; + // List bindings request + + NYql::TIssues ValidateRequest(TEvControlPlaneStorage::TEvListBindingsRequest::TPtr& ev) const; + // Write result data request NYql::TIssues ValidateRequest(TEvControlPlaneStorage::TEvWriteResultDataRequest::TPtr& ev) const; diff --git a/ydb/tests/fq/control_plane_storage/in_memory_control_plane_storage_ut.cpp b/ydb/tests/fq/control_plane_storage/in_memory_control_plane_storage_ut.cpp index f80031665cf4..cd7fb204f494 100644 --- a/ydb/tests/fq/control_plane_storage/in_memory_control_plane_storage_ut.cpp +++ b/ydb/tests/fq/control_plane_storage/in_memory_control_plane_storage_ut.cpp @@ -40,32 +40,45 @@ class TTestFuxture : public NUnitTest::TBaseFixture { TFqSetupSettings settings; settings.VerboseLevel = TFqSetupSettings::EVerbose::Max; + settings.EnableYdbCompute = true; - settings.LogConfig.SetDefaultLevel(NLog::EPriority::PRI_WARN); - ModifyLogPriorities({{NKikimrServices::EServiceKikimr::YQ_CONTROL_PLANE_STORAGE, NLog::EPriority::PRI_DEBUG}}, settings.LogConfig); + auto& logConfig = *settings.AppConfig.MutableLogConfig(); + logConfig.SetDefaultLevel(NLog::EPriority::PRI_WARN); + ModifyLogPriorities({ + {NKikimrServices::EServiceKikimr::YQ_CONTROL_PLANE_STORAGE, NLog::EPriority::PRI_DEBUG}, + {NKikimrServices::EServiceKikimr::FQ_RUN_ACTOR, NLog::EPriority::PRI_TRACE} + }, logConfig); - auto& cpStorageConfig = *settings.FqConfig.MutableControlPlaneStorage(); + auto& fqConfig = *settings.AppConfig.MutableFederatedQueryConfig(); + auto& cpStorageConfig = *fqConfig.MutableControlPlaneStorage(); cpStorageConfig.SetEnabled(true); cpStorageConfig.SetUseInMemory(true); - auto& privateApiConfig = *settings.FqConfig.MutablePrivateApi(); + auto& privateApiConfig = *fqConfig.MutablePrivateApi(); privateApiConfig.SetEnabled(true); privateApiConfig.SetLoopback(true); - settings.FqConfig.SetEnableDynamicNameservice(true); - settings.FqConfig.MutableControlPlaneProxy()->SetEnabled(true); - settings.FqConfig.MutableDbPool()->SetEnabled(true); - settings.FqConfig.MutableNodesManager()->SetEnabled(true); - settings.FqConfig.MutablePendingFetcher()->SetEnabled(true); - settings.FqConfig.MutablePrivateProxy()->SetEnabled(true); - settings.FqConfig.MutableGateways()->SetEnabled(true); - settings.FqConfig.MutableResourceManager()->SetEnabled(true); - settings.FqConfig.MutableCommon()->SetIdsPrefix("ut"); + fqConfig.SetEnableDynamicNameservice(true); + fqConfig.MutableControlPlaneProxy()->SetEnabled(true); + fqConfig.MutableDbPool()->SetEnabled(true); + fqConfig.MutableNodesManager()->SetEnabled(true); + fqConfig.MutablePendingFetcher()->SetEnabled(true); + fqConfig.MutablePrivateProxy()->SetEnabled(true); + fqConfig.MutableGateways()->SetEnabled(true); + fqConfig.MutableResourceManager()->SetEnabled(true); + fqConfig.MutableCommon()->SetIdsPrefix("ut"); + + auto& computeConfig = *fqConfig.MutableCompute(); + computeConfig.SetDefaultCompute(NFq::NConfig::IN_PLACE); + + auto& computeMapping = *computeConfig.AddComputeMapping(); + computeMapping.SetQueryType(FederatedQuery::QueryContent::ANALYTICS); + computeMapping.SetCompute(NFq::NConfig::YDB); + computeMapping.MutableActivation()->SetPercentage(100); FqSetup = std::make_unique(settings); } -protected: static void CheckSuccess(const TRequestResult& result) { UNIT_ASSERT_VALUES_EQUAL_C(result.Status, Ydb::StatusIds::SUCCESS, result.Issues.ToOneLineString()); } @@ -76,7 +89,7 @@ class TTestFuxture : public NUnitTest::TBaseFixture { const TInstant start = TInstant::Now(); while (TInstant::Now() - start <= timeout) { TExecutionMeta meta; - CheckSuccess(FqSetup->DescribeQuery(queryId, meta)); + CheckSuccess(FqSetup->DescribeQuery(queryId, {}, meta)); if (!IsIn({EStatus::FAILED, EStatus::COMPLETED, EStatus::ABORTED_BY_USER, EStatus::ABORTED_BY_SYSTEM}, meta.Status)) { Cerr << "Wait query execution " << TInstant::Now() - start << ": " << EStatus::ComputeStatus_Name(meta.Status) << "\n"; @@ -92,27 +105,22 @@ class TTestFuxture : public NUnitTest::TBaseFixture { return {}; } -protected: +public: std::unique_ptr FqSetup; }; } // anonymous namespace Y_UNIT_TEST_SUITE(InMemoryControlPlaneStorage) { - Y_UNIT_TEST_F(ExecuteSimpleQuery, TTestFuxture) { - TString queryId; - CheckSuccess(FqSetup->StreamRequest({ - .Query = "SELECT 42 AS result_value", - .Action = FederatedQuery::ExecuteMode::RUN - }, queryId)); + void CheckQueryResults(const TTestFuxture& ctx, const TString& queryId) { UNIT_ASSERT(queryId); - const auto meta = WaitQueryExecution(queryId); + const auto meta = ctx.WaitQueryExecution(queryId); UNIT_ASSERT_VALUES_EQUAL(meta.ResultSetSizes.size(), 1); UNIT_ASSERT_VALUES_EQUAL(meta.ResultSetSizes[0], 1); Ydb::ResultSet resultSet; - CheckSuccess(FqSetup->FetchQueryResults(queryId, 0, resultSet)); + ctx.CheckSuccess(ctx.FqSetup->FetchQueryResults(queryId, 0, {}, resultSet)); NYdb::TResultSetParser parser(resultSet); UNIT_ASSERT_VALUES_EQUAL(parser.ColumnsCount(), 1); @@ -120,6 +128,28 @@ Y_UNIT_TEST_SUITE(InMemoryControlPlaneStorage) { UNIT_ASSERT(parser.TryNextRow()); UNIT_ASSERT_VALUES_EQUAL(parser.ColumnParser("result_value").GetInt32(), 42); } + + Y_UNIT_TEST_F(ExecuteSimpleStreamQuery, TTestFuxture) { + TString queryId; + CheckSuccess(FqSetup->QueryRequest({ + .Query = "SELECT 42 AS result_value", + .Action = FederatedQuery::ExecuteMode::RUN, + .Type = FederatedQuery::QueryContent::STREAMING + }, queryId)); + + CheckQueryResults(*this, queryId); + } + + Y_UNIT_TEST_F(ExecuteSimpleAnalyticsQuery, TTestFuxture) { + TString queryId; + CheckSuccess(FqSetup->QueryRequest({ + .Query = "SELECT 42 AS result_value", + .Action = FederatedQuery::ExecuteMode::RUN, + .Type = FederatedQuery::QueryContent::ANALYTICS + }, queryId)); + + CheckQueryResults(*this, queryId); + } } } // NFq diff --git a/ydb/tests/fq/streaming_optimize/cfg/app_config.conf b/ydb/tests/fq/streaming_optimize/cfg/app_config.conf new file mode 100644 index 000000000000..be5729b3d7d6 --- /dev/null +++ b/ydb/tests/fq/streaming_optimize/cfg/app_config.conf @@ -0,0 +1,309 @@ +FederatedQueryConfig { + Enabled: true + EnableDynamicNameservice: true + EnableTaskCounters: true + + CheckpointCoordinator { + CheckpointingPeriodMillis: 30000 + MaxInflight: 1 + + CheckpointGarbageConfig { + Enabled: true + } + + Storage { + TablePrefix: "yq/checkpoints" + ClientTimeoutSec: 70 + OperationTimeoutSec: 60 + CancelAfterSec: 60 + } + } + + Common { + YdbMvpCloudEndpoint: "https://ydbc.ydb.cloud.yandex.net:8789/ydbc/cloud-prod" + MdbGateway: "https://mdb.api.cloud.yandex.net:443" + MdbTransformHost: false + ObjectStorageEndpoint: "https://storage.yandexcloud.net" + IdsPrefix: "fr" + QueryArtifactsCompressionMethod: "zstd_6" + MonitoringEndpoint: "monitoring.api.cloud.yandex.net" + KeepInternalErrors: true + UseNativeProtocolForClickHouse: true + ShowQueryTimeline: true + MaxTasksPerOperation: 400 + MaxTasksPerStage: 50 + PqReconnectPeriod: "30m" + + YdbDriverConfig { + ClientThreadsNum: 6 + NetworkThreadsNum: 6 + } + } + + ControlPlaneProxy { + Enabled: true + RequestTimeout: "1m" + } + + ControlPlaneStorage { + Enabled: true + UseInMemory: true + StatsMode: STATS_MODE_PROFILE + DumpRawStatistics: true + TasksBatchSize: 100 + NumTasksProportion: 4 + AnalyticsRetryCounterLimit: 20 + StreamingRetryCounterLimit: 20 + AnalyticsRetryCounterUpdateTime: "1d" + StreamingRetryCounterUpdateTime: "1d" + TaskLeaseTtl: "30s" + DisableCurrentIam: false + + AvailableConnection: "OBJECT_STORAGE" + AvailableConnection: "DATA_STREAMS" + AvailableConnection: "MONITORING" + AvailableConnection: "POSTGRESQL_CLUSTER" + AvailableConnection: "CLICKHOUSE_CLUSTER" + AvailableConnection: "YDB_DATABASE" + AvailableConnection: "GREENPLUM_CLUSTER" + AvailableConnection: "MYSQL_CLUSTER" + + AvailableStreamingConnection: "OBJECT_STORAGE" + AvailableStreamingConnection: "DATA_STREAMS" + AvailableStreamingConnection: "MONITORING" + AvailableStreamingConnection: "POSTGRESQL_CLUSTER" + AvailableStreamingConnection: "CLICKHOUSE_CLUSTER" + AvailableStreamingConnection: "YDB_DATABASE" + AvailableStreamingConnection: "GREENPLUM_CLUSTER" + AvailableStreamingConnection: "MYSQL_CLUSTER" + + AvailableBinding: "OBJECT_STORAGE" + AvailableBinding: "DATA_STREAMS" + + Storage { + TablePrefix: "yq/control_plane" + ClientTimeoutSec: 70 + OperationTimeoutSec: 60 + CancelAfterSec: 60 + } + + RetryPolicyMapping { + } + } + + DbPool { + Enabled: true + + Storage { + TablePrefix: "yq/db_pool" + ClientTimeoutSec: 70 + OperationTimeoutSec: 60 + CancelAfterSec: 60 + } + } + + Gateways { + Enabled: true + + Dq { + DefaultSettings { + Name: "HashShuffleTasksRatio" + Value: "1" + } + DefaultSettings { + Name: "UseFinalizeByKey" + Value: "true" + } + } + + Generic { + MdbGateway: "https://mdb.api.cloud.yandex.net:443" + + Connector { + UseSsl: false + + Endpoint { + host: "localhost" + port: 2130 + } + } + + DefaultSettings { + Name: "DateTimeFormat" + Value: "string" + } + } + + HttpGateway { + BuffersSizePerStream: 5000000 + ConnectionTimeoutSeconds: 15 + LowSpeedBytesLimit: 1024 + LowSpeedTimeSeconds: 20 + MaxInFlightCount: 2000 + MaxSimulatenousDownloadsSize: 2000000000 + RequestTimeoutSeconds: 0 + } + + Pq { + ClusterMapping { + Name: "pq" + Endpoint: "localhost:2135" + Database: "local" + ClusterType: CT_DATA_STREAMS + UseSsl: true + SharedReading: true + ReadGroup: "fqrun" + } + } + + Solomon { + ClusterMapping { + Name: "solomon" + Cluster: "${SOLOMON_ENDPOINT}" + UseSsl: false + } + DefaultSettings { + Name: "_EnableReading" + Value: "true" + } + } + + S3 { + AllowConcurrentListings: true + AllowLocalFiles: true + FileSizeLimit: 100000000000 + GeneratorPathsLimit: 50000 + ListingCallbackPerThreadQueueSize: 100 + ListingCallbackThreadCount: 1 + MaxDirectoriesAndFilesPerQuery: 500000 + MaxDiscoveryFilesPerQuery: 1000 + MaxFilesPerQuery: 500000 + MaxInflightListsPerQuery: 100 + MinDesiredDirectoriesOfFilesPerQuery: 1000 + RegexpCacheSize: 100 + + FormatSizeLimit { + Name: "parquet" + FileSizeLimit: 52428800 + } + FormatSizeLimit { + Name: "raw" + FileSizeLimit: 52428800 + } + + DefaultSettings { + Name: "AtomicUploadCommit" + Value: "true" + } + DefaultSettings { + Name: "UseBlocksSource" + Value: "true" + } + } + + YqlCore { + Flags { + Name: "_EnableMatchRecognize" + } + Flags { + Name: "_EnableStreamLookupJoin" + } + } + } + + NodesManager { + Enabled: true + } + + PendingFetcher { + Enabled: true + } + + PrivateApi { + Enabled: true + Loopback: true + } + + PrivateProxy { + Enabled: true + } + + QuotasManager { + QuotaDescriptions { + SubjectType: "cloud" + MetricName: "yq.cpuPercent.count" + HardLimit: 7500 + DefaultLimit: 3500 + } + QuotaDescriptions { + SubjectType: "cloud" + MetricName: "yq.streamingQueryDurationMinutes.count" + DefaultLimit: 10080 + } + QuotaDescriptions { + SubjectType: "cloud" + MetricName: "yq.analyticsQueryDurationMinutes.count" + HardLimit: 1440 + DefaultLimit: 30 + } + } + + RateLimiter { + Database { + TablePrefix: "yq/rate_limiter" + ClientTimeoutSec: 70 + OperationTimeoutSec: 60 + CancelAfterSec: 60 + } + + Limiters { + CoordinationNodePath: "limiter_alpha" + } + } + + ReadActorsFactoryConfig { + PqReadActorFactoryConfig { + CookieCommitMode: false + } + } + + ResourceManager { + Enabled: true + MkqlInitialMemoryLimit: 16777216 + MkqlTotalMemoryLimit: 193273528320 + MkqlAllocSize: 16777216 + MkqlTaskHardMemoryLimit: 24696061952 + } + + RowDispatcher { + Enabled: true + SendStatusPeriodSec: 10 + TimeoutBeforeStartSessionSec: 0 + MaxSessionUsedMemory: 16000000 + WithoutConsumer: false + + CompileService { + ParallelCompilationLimit: 20 + } + + Coordinator { + CoordinationNodePath: "yq/row_dispatcher" + + Database { + TablePrefix: "yq/row_dispatcher" + ClientTimeoutSec: 70 + OperationTimeoutSec: 60 + CancelAfterSec: 60 + } + } + + JsonParser { + BatchSizeBytes: 1048576 + BatchCreationTimeoutMs: 1000 + } + } + + TestConnection { + Enabled: true + } +} diff --git a/ydb/tests/fq/streaming_optimize/cfg/fq_config.conf b/ydb/tests/fq/streaming_optimize/cfg/fq_config.conf deleted file mode 100644 index 82c167b2643c..000000000000 --- a/ydb/tests/fq/streaming_optimize/cfg/fq_config.conf +++ /dev/null @@ -1,307 +0,0 @@ -Enabled: true -EnableDynamicNameservice: true -EnableTaskCounters: true - -CheckpointCoordinator { - CheckpointingPeriodMillis: 30000 - MaxInflight: 1 - - CheckpointGarbageConfig { - Enabled: true - } - - Storage { - TablePrefix: "yq/checkpoints" - ClientTimeoutSec: 70 - OperationTimeoutSec: 60 - CancelAfterSec: 60 - } -} - -Common { - YdbMvpCloudEndpoint: "https://ydbc.ydb.cloud.yandex.net:8789/ydbc/cloud-prod" - MdbGateway: "https://mdb.api.cloud.yandex.net:443" - MdbTransformHost: false - ObjectStorageEndpoint: "https://storage.yandexcloud.net" - IdsPrefix: "fr" - QueryArtifactsCompressionMethod: "zstd_6" - MonitoringEndpoint: "monitoring.api.cloud.yandex.net" - KeepInternalErrors: true - UseNativeProtocolForClickHouse: true - ShowQueryTimeline: true - MaxTasksPerOperation: 400 - MaxTasksPerStage: 50 - PqReconnectPeriod: "30m" - - YdbDriverConfig { - ClientThreadsNum: 6 - NetworkThreadsNum: 6 - } -} - -ControlPlaneProxy { - Enabled: true - RequestTimeout: "1m" -} - -ControlPlaneStorage { - Enabled: true - UseInMemory: true - StatsMode: STATS_MODE_PROFILE - DumpRawStatistics: true - TasksBatchSize: 100 - NumTasksProportion: 4 - AnalyticsRetryCounterLimit: 20 - StreamingRetryCounterLimit: 20 - AnalyticsRetryCounterUpdateTime: "1d" - StreamingRetryCounterUpdateTime: "1d" - TaskLeaseTtl: "30s" - DisableCurrentIam: false - - AvailableConnection: "OBJECT_STORAGE" - AvailableConnection: "DATA_STREAMS" - AvailableConnection: "MONITORING" - AvailableConnection: "POSTGRESQL_CLUSTER" - AvailableConnection: "CLICKHOUSE_CLUSTER" - AvailableConnection: "YDB_DATABASE" - AvailableConnection: "GREENPLUM_CLUSTER" - AvailableConnection: "MYSQL_CLUSTER" - - AvailableStreamingConnection: "OBJECT_STORAGE" - AvailableStreamingConnection: "DATA_STREAMS" - AvailableStreamingConnection: "MONITORING" - AvailableStreamingConnection: "POSTGRESQL_CLUSTER" - AvailableStreamingConnection: "CLICKHOUSE_CLUSTER" - AvailableStreamingConnection: "YDB_DATABASE" - AvailableStreamingConnection: "GREENPLUM_CLUSTER" - AvailableStreamingConnection: "MYSQL_CLUSTER" - - AvailableBinding: "OBJECT_STORAGE" - AvailableBinding: "DATA_STREAMS" - - Storage { - TablePrefix: "yq/control_plane" - ClientTimeoutSec: 70 - OperationTimeoutSec: 60 - CancelAfterSec: 60 - } - - RetryPolicyMapping { - } -} - -DbPool { - Enabled: true - - Storage { - TablePrefix: "yq/db_pool" - ClientTimeoutSec: 70 - OperationTimeoutSec: 60 - CancelAfterSec: 60 - } -} - -Gateways { - Enabled: true - - Dq { - DefaultSettings { - Name: "HashShuffleTasksRatio" - Value: "1" - } - DefaultSettings { - Name: "UseFinalizeByKey" - Value: "true" - } - } - - Generic { - MdbGateway: "https://mdb.api.cloud.yandex.net:443" - - Connector { - UseSsl: false - - Endpoint { - host: "localhost" - port: 2130 - } - } - - DefaultSettings { - Name: "DateTimeFormat" - Value: "string" - } - } - - HttpGateway { - BuffersSizePerStream: 5000000 - ConnectionTimeoutSeconds: 15 - LowSpeedBytesLimit: 1024 - LowSpeedTimeSeconds: 20 - MaxInFlightCount: 2000 - MaxSimulatenousDownloadsSize: 2000000000 - RequestTimeoutSeconds: 0 - } - - Pq { - ClusterMapping { - Name: "pq" - Endpoint: "localhost:2135" - Database: "local" - ClusterType: CT_DATA_STREAMS - UseSsl: true - SharedReading: true - ReadGroup: "fqrun" - } - } - - Solomon { - ClusterMapping { - Name: "solomon" - Cluster: "${SOLOMON_ENDPOINT}" - UseSsl: false - } - DefaultSettings { - Name: "_EnableReading" - Value: "true" - } - } - - S3 { - AllowConcurrentListings: true - AllowLocalFiles: true - FileSizeLimit: 100000000000 - GeneratorPathsLimit: 50000 - ListingCallbackPerThreadQueueSize: 100 - ListingCallbackThreadCount: 1 - MaxDirectoriesAndFilesPerQuery: 500000 - MaxDiscoveryFilesPerQuery: 1000 - MaxFilesPerQuery: 500000 - MaxInflightListsPerQuery: 100 - MinDesiredDirectoriesOfFilesPerQuery: 1000 - RegexpCacheSize: 100 - - FormatSizeLimit { - Name: "parquet" - FileSizeLimit: 52428800 - } - FormatSizeLimit { - Name: "raw" - FileSizeLimit: 52428800 - } - - DefaultSettings { - Name: "AtomicUploadCommit" - Value: "true" - } - DefaultSettings { - Name: "UseBlocksSource" - Value: "true" - } - } - - YqlCore { - Flags { - Name: "_EnableMatchRecognize" - } - Flags { - Name: "_EnableStreamLookupJoin" - } - } -} - -NodesManager { - Enabled: true -} - -PendingFetcher { - Enabled: true -} - -PrivateApi { - Enabled: true - Loopback: true -} - -PrivateProxy { - Enabled: true -} - -QuotasManager { - QuotaDescriptions { - SubjectType: "cloud" - MetricName: "yq.cpuPercent.count" - HardLimit: 7500 - DefaultLimit: 3500 - } - QuotaDescriptions { - SubjectType: "cloud" - MetricName: "yq.streamingQueryDurationMinutes.count" - DefaultLimit: 10080 - } - QuotaDescriptions { - SubjectType: "cloud" - MetricName: "yq.analyticsQueryDurationMinutes.count" - HardLimit: 1440 - DefaultLimit: 30 - } -} - -RateLimiter { - Database { - TablePrefix: "yq/rate_limiter" - ClientTimeoutSec: 70 - OperationTimeoutSec: 60 - CancelAfterSec: 60 - } - - Limiters { - CoordinationNodePath: "limiter_alpha" - } -} - -ReadActorsFactoryConfig { - PqReadActorFactoryConfig { - CookieCommitMode: false - } -} - -ResourceManager { - Enabled: true - MkqlInitialMemoryLimit: 16777216 - MkqlTotalMemoryLimit: 193273528320 - MkqlAllocSize: 16777216 - MkqlTaskHardMemoryLimit: 24696061952 -} - -RowDispatcher { - Enabled: true - SendStatusPeriodSec: 10 - TimeoutBeforeStartSessionSec: 0 - MaxSessionUsedMemory: 16000000 - WithoutConsumer: false - - CompileService { - ParallelCompilationLimit: 20 - } - - Coordinator { - CoordinationNodePath: "yq/row_dispatcher" - - Database { - TablePrefix: "yq/row_dispatcher" - ClientTimeoutSec: 70 - OperationTimeoutSec: 60 - CancelAfterSec: 60 - } - } - - JsonParser { - BatchSizeBytes: 1048576 - BatchCreationTimeoutMs: 1000 - } -} - -TestConnection { - Enabled: true -} diff --git a/ydb/tests/fq/streaming_optimize/test_sql_streaming.py b/ydb/tests/fq/streaming_optimize/test_sql_streaming.py index 8c079f2d2d69..5c2a30f60b27 100644 --- a/ydb/tests/fq/streaming_optimize/test_sql_streaming.py +++ b/ydb/tests/fq/streaming_optimize/test_sql_streaming.py @@ -14,7 +14,7 @@ @pytest.fixture def fq_run(request) -> FqRun: result = FqRun( - config_file=os.path.join('ydb/tests/fq/streaming_optimize/cfg', 'fq_config.conf'), + config_file=os.path.join('ydb/tests/fq/streaming_optimize/cfg', 'app_config.conf'), path_prefix=f"{request.function.__name__}_" ) result.replace_config(lambda config: config.replace("${SOLOMON_ENDPOINT}", os.getenv("SOLOMON_ENDPOINT"))) diff --git a/ydb/tests/fq/tools/fqrun.py b/ydb/tests/fq/tools/fqrun.py index 1db3faea032f..c269e0a705db 100644 --- a/ydb/tests/fq/tools/fqrun.py +++ b/ydb/tests/fq/tools/fqrun.py @@ -61,8 +61,7 @@ def yql_exec(self, verbose: bool = False, check_error: bool = True, action: str cmd += ( '--exclude-linked-udfs ' f'--action={action} ' - f'--fq-cfg={self.config_file} ' - '--as-cfg=- ' + f'--cfg={self.config_file} ' f'--result-file={results_file} ' f'--ast-file={ast_file} ' f'--plan-file={plan_file} ' diff --git a/ydb/tests/fq/yt/kqp_yt_import/kqprun_import_config.conf b/ydb/tests/fq/yt/kqp_yt_import/kqprun_import_config.conf index 75f9e3dae42f..c4e4433fa6a8 100644 --- a/ydb/tests/fq/yt/kqp_yt_import/kqprun_import_config.conf +++ b/ydb/tests/fq/yt/kqp_yt_import/kqprun_import_config.conf @@ -30,12 +30,31 @@ QueryServiceConfig { } } +ResourceBrokerConfig { + Queues { + Name: "queue_kqp_resource_manager" + Weight: 30 + + Limit { + Memory: 64424509440 + } + } + + ResourceLimit { + Memory: 64424509440 + } +} + TableServiceConfig { BlockChannelsMode: BLOCK_CHANNELS_FORCE EnableCreateTableAs: true EnableOlapSink: true EnablePerStatementQueryExecution: true + ResourceManager { + QueryMemoryLimit: 64424509440 + } + WriteActorSettings { MaxWriteAttempts: 1000 } diff --git a/ydb/tests/fq/yt/kqp_yt_import/test_ctas.py b/ydb/tests/fq/yt/kqp_yt_import/test_ctas.py index 86e252b23478..189b02a04b5e 100644 --- a/ydb/tests/fq/yt/kqp_yt_import/test_ctas.py +++ b/ydb/tests/fq/yt/kqp_yt_import/test_ctas.py @@ -10,7 +10,8 @@ def test_simple_ctast(self, kqp_run: KqpRun): CREATE TABLE from_yt ( PRIMARY KEY (key) ) WITH ( - STORE = COLUMN + STORE = COLUMN, + AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 10 ) AS SELECT UNWRAP(key) AS key, subkey, value FROM plato.input """) diff --git a/ydb/tests/tools/fqrun/README.md b/ydb/tests/tools/fqrun/README.md index 14c0dc9b527d..35c81eccd4fa 100644 --- a/ydb/tests/tools/fqrun/README.md +++ b/ydb/tests/tools/fqrun/README.md @@ -15,11 +15,27 @@ For profiling memory allocations build fqrun with ya make flags `-D PROFILE_MEMO ### Queries -* Run select 42: +* Stream query: ```(bash) ./fqrun -s "SELECT 42" ``` +* In place analytics query: + ```(bash) + ./fqrun -s "SELECT 42" -C analytics + ``` + +* Analytics query with remote compute database: + 1. Start shared ydb tenant: + ```(bash) + ./kqprun -G 12345 --shared db + ``` + + 1. Execute query: + ```(bash) + ./fqrun -s "SELECT 42" -C analytics --shared-compute-db /Root/db@localhost:12345 + ``` + ### Logs * Setup log settings: diff --git a/ydb/tests/tools/fqrun/configuration/app_config.conf b/ydb/tests/tools/fqrun/configuration/app_config.conf new file mode 100644 index 000000000000..c6f638862e34 --- /dev/null +++ b/ydb/tests/tools/fqrun/configuration/app_config.conf @@ -0,0 +1,510 @@ +ActorSystemConfig { + Executor { + Type: BASIC + Threads: 2 + SpinThreshold: 10 + Name: "System" + } + Executor { + Type: BASIC + Threads: 6 + SpinThreshold: 1 + Name: "User" + } + Executor { + Type: BASIC + Threads: 1 + SpinThreshold: 1 + Name: "Batch" + } + Executor { + Type: IO + Threads: 1 + Name: "IO" + } + Executor { + Type: BASIC + Threads: 2 + SpinThreshold: 10 + Name: "IC" + TimePerMailboxMicroSecs: 100 + } + Scheduler { + Resolution: 64 + SpinThreshold: 0 + ProgressThreshold: 10000 + } + SysExecutor: 0 + UserExecutor: 1 + IoExecutor: 3 + BatchExecutor: 2 + ServiceExecutor { + ServiceName: "Interconnect" + ExecutorId: 4 + } +} + +FederatedQueryConfig { + Enabled: true + EnableDynamicNameservice: true + EnableTaskCounters: true + + CheckpointCoordinator { + CheckpointingPeriodMillis: 30000 + MaxInflight: 1 + + CheckpointGarbageConfig { + Enabled: true + } + + Storage { + TablePrefix: "yq/checkpoints" + ClientTimeoutSec: 70 + OperationTimeoutSec: 60 + CancelAfterSec: 60 + } + } + + Common { + YdbMvpCloudEndpoint: "https://ydbc.ydb.cloud.yandex.net:8789/ydbc/cloud-prod" + MdbGateway: "https://mdb.api.cloud.yandex.net:443" + MdbTransformHost: false + ObjectStorageEndpoint: "https://storage.yandexcloud.net" + IdsPrefix: "fr" + QueryArtifactsCompressionMethod: "zstd_6" + MonitoringEndpoint: "monitoring.api.cloud.yandex.net" + KeepInternalErrors: true + UseNativeProtocolForClickHouse: true + ShowQueryTimeline: true + MaxTasksPerOperation: 400 + MaxTasksPerStage: 50 + PqReconnectPeriod: "30m" + + YdbDriverConfig { + ClientThreadsNum: 6 + NetworkThreadsNum: 6 + } + } + + ControlPlaneProxy { + Enabled: true + RequestTimeout: "1m" + } + + ControlPlaneStorage { + Enabled: true + UseInMemory: true + StatsMode: STATS_MODE_PROFILE + DumpRawStatistics: true + TasksBatchSize: 100 + NumTasksProportion: 4 + AnalyticsRetryCounterLimit: 20 + StreamingRetryCounterLimit: 20 + AnalyticsRetryCounterUpdateTime: "1d" + StreamingRetryCounterUpdateTime: "1d" + TaskLeaseTtl: "30s" + DisableCurrentIam: false + + AvailableConnection: "OBJECT_STORAGE" + AvailableConnection: "DATA_STREAMS" + AvailableConnection: "MONITORING" + AvailableConnection: "POSTGRESQL_CLUSTER" + AvailableConnection: "CLICKHOUSE_CLUSTER" + AvailableConnection: "YDB_DATABASE" + AvailableConnection: "GREENPLUM_CLUSTER" + AvailableConnection: "MYSQL_CLUSTER" + + AvailableStreamingConnection: "OBJECT_STORAGE" + AvailableStreamingConnection: "DATA_STREAMS" + AvailableStreamingConnection: "MONITORING" + AvailableStreamingConnection: "POSTGRESQL_CLUSTER" + AvailableStreamingConnection: "CLICKHOUSE_CLUSTER" + AvailableStreamingConnection: "YDB_DATABASE" + AvailableStreamingConnection: "GREENPLUM_CLUSTER" + AvailableStreamingConnection: "MYSQL_CLUSTER" + + AvailableBinding: "OBJECT_STORAGE" + AvailableBinding: "DATA_STREAMS" + + Storage { + TablePrefix: "yq/control_plane" + ClientTimeoutSec: 70 + OperationTimeoutSec: 60 + CancelAfterSec: 60 + } + + RetryPolicyMapping { + } + } + + DbPool { + Enabled: true + + Storage { + TablePrefix: "yq/db_pool" + ClientTimeoutSec: 70 + OperationTimeoutSec: 60 + CancelAfterSec: 60 + } + } + + Gateways { + Enabled: true + + Dq { + DefaultSettings { + Name: "HashShuffleTasksRatio" + Value: "1" + } + DefaultSettings { + Name: "UseFinalizeByKey" + Value: "true" + } + } + + Generic { + MdbGateway: "https://mdb.api.cloud.yandex.net:443" + + Connector { + UseSsl: false + + Endpoint { + host: "localhost" + port: 2130 + } + } + + DefaultSettings { + Name: "DateTimeFormat" + Value: "string" + } + } + + HttpGateway { + BuffersSizePerStream: 5000000 + ConnectionTimeoutSeconds: 15 + LowSpeedBytesLimit: 1024 + LowSpeedTimeSeconds: 20 + MaxInFlightCount: 2000 + MaxSimulatenousDownloadsSize: 2000000000 + RequestTimeoutSeconds: 0 + } + + Pq { + ClusterMapping { + Name: "pq" + Endpoint: "localhost:2135" + Database: "local" + ClusterType: CT_DATA_STREAMS + UseSsl: true + SharedReading: true + ReadGroup: "fqrun" + } + } + + Solomon { + DefaultSettings { + Name: "_EnableReading" + Value: "true" + } + } + + S3 { + AllowConcurrentListings: true + AllowLocalFiles: true + FileSizeLimit: 100000000000 + GeneratorPathsLimit: 50000 + ListingCallbackPerThreadQueueSize: 100 + ListingCallbackThreadCount: 1 + MaxDirectoriesAndFilesPerQuery: 500000 + MaxDiscoveryFilesPerQuery: 1000 + MaxFilesPerQuery: 500000 + MaxInflightListsPerQuery: 100 + MinDesiredDirectoriesOfFilesPerQuery: 1000 + RegexpCacheSize: 100 + + FormatSizeLimit { + Name: "parquet" + FileSizeLimit: 52428800 + } + FormatSizeLimit { + Name: "raw" + FileSizeLimit: 52428800 + } + + DefaultSettings { + Name: "AtomicUploadCommit" + Value: "true" + } + DefaultSettings { + Name: "UseBlocksSource" + Value: "true" + } + } + + YqlCore { + Flags { + Name: "_EnableMatchRecognize" + } + Flags { + Name: "_EnableStreamLookupJoin" + } + } + } + + NodesManager { + Enabled: true + } + + PendingFetcher { + Enabled: true + } + + PrivateApi { + Enabled: true + Loopback: true + } + + PrivateProxy { + Enabled: true + } + + QuotasManager { + QuotaDescriptions { + SubjectType: "cloud" + MetricName: "yq.cpuPercent.count" + HardLimit: 7500 + DefaultLimit: 3500 + } + QuotaDescriptions { + SubjectType: "cloud" + MetricName: "yq.streamingQueryDurationMinutes.count" + DefaultLimit: 10080 + } + QuotaDescriptions { + SubjectType: "cloud" + MetricName: "yq.analyticsQueryDurationMinutes.count" + HardLimit: 1440 + DefaultLimit: 30 + } + } + + RateLimiter { + Database { + TablePrefix: "yq/rate_limiter" + ClientTimeoutSec: 70 + OperationTimeoutSec: 60 + CancelAfterSec: 60 + } + + Limiters { + CoordinationNodePath: "limiter_alpha" + } + } + + ReadActorsFactoryConfig { + PqReadActorFactoryConfig { + CookieCommitMode: false + } + } + + ResourceManager { + Enabled: true + MkqlInitialMemoryLimit: 16777216 + MkqlTotalMemoryLimit: 193273528320 + MkqlAllocSize: 16777216 + MkqlTaskHardMemoryLimit: 24696061952 + } + + RowDispatcher { + Enabled: true + SendStatusPeriodSec: 10 + TimeoutBeforeStartSessionSec: 0 + MaxSessionUsedMemory: 16000000 + WithoutConsumer: false + + CompileService { + ParallelCompilationLimit: 20 + } + + Coordinator { + CoordinationNodePath: "yq/row_dispatcher" + + Database { + TablePrefix: "yq/row_dispatcher" + ClientTimeoutSec: 70 + OperationTimeoutSec: 60 + CancelAfterSec: 60 + } + } + + JsonParser { + BatchSizeBytes: 1048576 + BatchCreationTimeoutMs: 1000 + } + } + + TestConnection { + Enabled: true + } + + Compute { + DefaultCompute: IN_PLACE + ComputeMapping { + QueryType: ANALYTICS + Compute: YDB + Activation { + Percentage: 100 + ExcludeScopes: [ + ] + } + } + Ydb { + ControlPlane { + DatabasePrefix: "yq_" + DefaultWorkloadManagerConfig { + Enable: true + ExecutionResourcePool: "yq" + ResourcePool { + Name: "yq" + ConcurrentQueryLimit: 100 + QueueSize: 100 + DatabaseLoadCpuThreshold: 80 + TotalCpuLimitPercentPerNode: -1 + } + } + } + } + SupportedComputeYdbFeatures { + ReplaceIfExists: True + } + } +} + +FeatureFlags { + EnableExternalDataSources: true + EnableScriptExecutionOperations: true + EnableExternalSourceSchemaInference: true + EnableTempTables: true + EnableReplaceIfExistsForExternalEntities: true + EnableResourcePools: true + EnableResourcePoolsOnServerless: true + EnableResourcePoolsCounters: true +} + +LogConfig { + DefaultLevel: 2 +} + +QueryServiceConfig { + EnableMatchRecognize: true + MdbTransformHost: false + ProgressStatsPeriodMs: 1000 + QueryArtifactsCompressionMethod: "zstd_6" + ScriptResultRowsLimit: 0 + ScriptResultSizeLimit: 10485760 + AvailableExternalDataSources: "ObjectStorage" + AvailableExternalDataSources: "ClickHouse" + AvailableExternalDataSources: "PostgreSQL" + AvailableExternalDataSources: "MySQL" + AvailableExternalDataSources: "Ydb" + AvailableExternalDataSources: "YT" + AvailableExternalDataSources: "Greenplum" + AvailableExternalDataSources: "MsSQLServer" + AvailableExternalDataSources: "Oracle" + AvailableExternalDataSources: "Logging" + AvailableExternalDataSources: "Solomon" + + Generic { + MdbGateway: "https://mdb.api.cloud.yandex.net:443" + + Connector { + UseSsl: false + + Endpoint { + host: "localhost" + port: 2130 + } + } + + DefaultSettings { + Name: "UsePredicatePushdown" + Value: "true" + } + } + + HttpGateway { + BuffersSizePerStream: 5000000 + ConnectionTimeoutSeconds: 15 + LowSpeedBytesLimit: 1024 + LowSpeedTimeSeconds: 20 + MaxInFlightCount: 2000 + MaxSimulatenousDownloadsSize: 2000000000 + RequestTimeoutSeconds: 0 + } + + S3 { + AllowConcurrentListings: true + AllowLocalFiles: true + FileSizeLimit: 100000000000 + GeneratorPathsLimit: 50000 + ListingCallbackPerThreadQueueSize: 100 + ListingCallbackThreadCount: 1 + MaxDirectoriesAndFilesPerQuery: 500000 + MaxDiscoveryFilesPerQuery: 1000 + MaxFilesPerQuery: 500000 + MaxInflightListsPerQuery: 100 + MinDesiredDirectoriesOfFilesPerQuery: 1000 + RegexpCacheSize: 100 + + DefaultSettings { + Name: "AtomicUploadCommit" + Value: "true" + } + DefaultSettings { + Name: "UseBlocksSource" + Value: "true" + } + DefaultSettings { + Name: "UseRuntimeListing" + Value: "true" + } + } +} + +ResourceBrokerConfig { + Queues { + Name: "queue_kqp_resource_manager" + Weight: 30 + + Limit { + Memory: 64424509440 + } + } + + ResourceLimit { + Memory: 64424509440 + } +} + +TableServiceConfig { + ArrayBufferMinFillPercentage: 75 + BindingsMode: BM_DROP + CompileTimeoutMs: 600000 + EnableCreateTableAs: true + EnableOlapSink: true + EnablePerStatementQueryExecution: true + SessionsLimitPerNode: 1000 + + QueryLimits { + DataQueryTimeoutMs: 3600000 + } + + ResourceManager { + QueryMemoryLimit: 64424509440 + } + + WriteActorSettings { + MaxWriteAttempts: 1000 + } +} diff --git a/ydb/tests/tools/fqrun/configuration/as_config.conf b/ydb/tests/tools/fqrun/configuration/as_config.conf deleted file mode 100644 index c1f7d09e7f6a..000000000000 --- a/ydb/tests/tools/fqrun/configuration/as_config.conf +++ /dev/null @@ -1,46 +0,0 @@ -Executor { - Type: BASIC - Threads: 1 - SpinThreshold: 10 - Name: "System" -} -Executor { - Type: BASIC - Threads: 6 - SpinThreshold: 1 - Name: "User" -} -Executor { - Type: BASIC - Threads: 1 - SpinThreshold: 1 - Name: "Batch" -} -Executor { - Type: IO - Threads: 1 - Name: "IO" -} -Executor { - Type: BASIC - Threads: 2 - SpinThreshold: 10 - Name: "IC" - TimePerMailboxMicroSecs: 100 -} - -Scheduler { - Resolution: 64 - SpinThreshold: 0 - ProgressThreshold: 10000 -} - -SysExecutor: 0 -UserExecutor: 1 -IoExecutor: 3 -BatchExecutor: 2 - -ServiceExecutor { - ServiceName: "Interconnect" - ExecutorId: 4 -} diff --git a/ydb/tests/tools/fqrun/configuration/fq_config.conf b/ydb/tests/tools/fqrun/configuration/fq_config.conf deleted file mode 100644 index 6d7c90f6b172..000000000000 --- a/ydb/tests/tools/fqrun/configuration/fq_config.conf +++ /dev/null @@ -1,302 +0,0 @@ -Enabled: true -EnableDynamicNameservice: true -EnableTaskCounters: true - -CheckpointCoordinator { - CheckpointingPeriodMillis: 30000 - MaxInflight: 1 - - CheckpointGarbageConfig { - Enabled: true - } - - Storage { - TablePrefix: "yq/checkpoints" - ClientTimeoutSec: 70 - OperationTimeoutSec: 60 - CancelAfterSec: 60 - } -} - -Common { - YdbMvpCloudEndpoint: "https://ydbc.ydb.cloud.yandex.net:8789/ydbc/cloud-prod" - MdbGateway: "https://mdb.api.cloud.yandex.net:443" - MdbTransformHost: false - ObjectStorageEndpoint: "https://storage.yandexcloud.net" - IdsPrefix: "fr" - QueryArtifactsCompressionMethod: "zstd_6" - MonitoringEndpoint: "monitoring.api.cloud.yandex.net" - KeepInternalErrors: true - UseNativeProtocolForClickHouse: true - ShowQueryTimeline: true - MaxTasksPerOperation: 400 - MaxTasksPerStage: 50 - PqReconnectPeriod: "30m" - - YdbDriverConfig { - ClientThreadsNum: 6 - NetworkThreadsNum: 6 - } -} - -ControlPlaneProxy { - Enabled: true - RequestTimeout: "1m" -} - -ControlPlaneStorage { - Enabled: true - UseInMemory: true - StatsMode: STATS_MODE_PROFILE - DumpRawStatistics: true - TasksBatchSize: 100 - NumTasksProportion: 4 - AnalyticsRetryCounterLimit: 20 - StreamingRetryCounterLimit: 20 - AnalyticsRetryCounterUpdateTime: "1d" - StreamingRetryCounterUpdateTime: "1d" - TaskLeaseTtl: "30s" - DisableCurrentIam: false - - AvailableConnection: "OBJECT_STORAGE" - AvailableConnection: "DATA_STREAMS" - AvailableConnection: "MONITORING" - AvailableConnection: "POSTGRESQL_CLUSTER" - AvailableConnection: "CLICKHOUSE_CLUSTER" - AvailableConnection: "YDB_DATABASE" - AvailableConnection: "GREENPLUM_CLUSTER" - AvailableConnection: "MYSQL_CLUSTER" - - AvailableStreamingConnection: "OBJECT_STORAGE" - AvailableStreamingConnection: "DATA_STREAMS" - AvailableStreamingConnection: "MONITORING" - AvailableStreamingConnection: "POSTGRESQL_CLUSTER" - AvailableStreamingConnection: "CLICKHOUSE_CLUSTER" - AvailableStreamingConnection: "YDB_DATABASE" - AvailableStreamingConnection: "GREENPLUM_CLUSTER" - AvailableStreamingConnection: "MYSQL_CLUSTER" - - AvailableBinding: "OBJECT_STORAGE" - AvailableBinding: "DATA_STREAMS" - - Storage { - TablePrefix: "yq/control_plane" - ClientTimeoutSec: 70 - OperationTimeoutSec: 60 - CancelAfterSec: 60 - } - - RetryPolicyMapping { - } -} - -DbPool { - Enabled: true - - Storage { - TablePrefix: "yq/db_pool" - ClientTimeoutSec: 70 - OperationTimeoutSec: 60 - CancelAfterSec: 60 - } -} - -Gateways { - Enabled: true - - Dq { - DefaultSettings { - Name: "HashShuffleTasksRatio" - Value: "1" - } - DefaultSettings { - Name: "UseFinalizeByKey" - Value: "true" - } - } - - Generic { - MdbGateway: "https://mdb.api.cloud.yandex.net:443" - - Connector { - UseSsl: false - - Endpoint { - host: "localhost" - port: 2130 - } - } - - DefaultSettings { - Name: "DateTimeFormat" - Value: "string" - } - } - - HttpGateway { - BuffersSizePerStream: 5000000 - ConnectionTimeoutSeconds: 15 - LowSpeedBytesLimit: 1024 - LowSpeedTimeSeconds: 20 - MaxInFlightCount: 2000 - MaxSimulatenousDownloadsSize: 2000000000 - RequestTimeoutSeconds: 0 - } - - Pq { - ClusterMapping { - Name: "pq" - Endpoint: "localhost:2135" - Database: "local" - ClusterType: CT_DATA_STREAMS - UseSsl: true - SharedReading: true - ReadGroup: "fqrun" - } - } - - Solomon { - DefaultSettings { - Name: "_EnableReading" - Value: "true" - } - } - - S3 { - AllowConcurrentListings: true - AllowLocalFiles: true - FileSizeLimit: 100000000000 - GeneratorPathsLimit: 50000 - ListingCallbackPerThreadQueueSize: 100 - ListingCallbackThreadCount: 1 - MaxDirectoriesAndFilesPerQuery: 500000 - MaxDiscoveryFilesPerQuery: 1000 - MaxFilesPerQuery: 500000 - MaxInflightListsPerQuery: 100 - MinDesiredDirectoriesOfFilesPerQuery: 1000 - RegexpCacheSize: 100 - - FormatSizeLimit { - Name: "parquet" - FileSizeLimit: 52428800 - } - FormatSizeLimit { - Name: "raw" - FileSizeLimit: 52428800 - } - - DefaultSettings { - Name: "AtomicUploadCommit" - Value: "true" - } - DefaultSettings { - Name: "UseBlocksSource" - Value: "true" - } - } - - YqlCore { - Flags { - Name: "_EnableMatchRecognize" - } - Flags { - Name: "_EnableStreamLookupJoin" - } - } -} - -NodesManager { - Enabled: true -} - -PendingFetcher { - Enabled: true -} - -PrivateApi { - Enabled: true - Loopback: true -} - -PrivateProxy { - Enabled: true -} - -QuotasManager { - QuotaDescriptions { - SubjectType: "cloud" - MetricName: "yq.cpuPercent.count" - HardLimit: 7500 - DefaultLimit: 3500 - } - QuotaDescriptions { - SubjectType: "cloud" - MetricName: "yq.streamingQueryDurationMinutes.count" - DefaultLimit: 10080 - } - QuotaDescriptions { - SubjectType: "cloud" - MetricName: "yq.analyticsQueryDurationMinutes.count" - HardLimit: 1440 - DefaultLimit: 30 - } -} - -RateLimiter { - Database { - TablePrefix: "yq/rate_limiter" - ClientTimeoutSec: 70 - OperationTimeoutSec: 60 - CancelAfterSec: 60 - } - - Limiters { - CoordinationNodePath: "limiter_alpha" - } -} - -ReadActorsFactoryConfig { - PqReadActorFactoryConfig { - CookieCommitMode: false - } -} - -ResourceManager { - Enabled: true - MkqlInitialMemoryLimit: 16777216 - MkqlTotalMemoryLimit: 193273528320 - MkqlAllocSize: 16777216 - MkqlTaskHardMemoryLimit: 24696061952 -} - -RowDispatcher { - Enabled: true - SendStatusPeriodSec: 10 - TimeoutBeforeStartSessionSec: 0 - MaxSessionUsedMemory: 16000000 - WithoutConsumer: false - - CompileService { - ParallelCompilationLimit: 20 - } - - Coordinator { - CoordinationNodePath: "yq/row_dispatcher" - - Database { - TablePrefix: "yq/row_dispatcher" - ClientTimeoutSec: 70 - OperationTimeoutSec: 60 - CancelAfterSec: 60 - } - } - - JsonParser { - BatchSizeBytes: 1048576 - BatchCreationTimeoutMs: 1000 - } -} - -TestConnection { - Enabled: true -} diff --git a/ydb/tests/tools/fqrun/fqrun.cpp b/ydb/tests/tools/fqrun/fqrun.cpp index d65f95e2f952..ec68a177a9ab 100644 --- a/ydb/tests/tools/fqrun/fqrun.cpp +++ b/ydb/tests/tools/fqrun/fqrun.cpp @@ -22,7 +22,9 @@ namespace { struct TExecutionOptions { enum class EExecutionCase { Stream, - AsyncStream + Analytics, + AsyncStream, + AsyncAnalytics }; TString Query; @@ -35,16 +37,29 @@ struct TExecutionOptions { EExecutionCase ExecutionCase = EExecutionCase::Stream; FederatedQuery::ExecuteMode QueryAction; + TString Scope; bool HasResults() const { - return !Query.empty(); + return !Query.empty() && (ExecutionCase == EExecutionCase::Stream || ExecutionCase == EExecutionCase::Analytics); + } + + bool IsAnalitycsQuery() const { + return ExecutionCase == EExecutionCase::Analytics || ExecutionCase == EExecutionCase::AsyncAnalytics; + } + + TFqOptions GetFqOptions() const { + return { + .Scope = Scope + }; } TRequestOptions GetQueryOptions(ui64 queryId) const { return { .Query = Query, .Action = QueryAction, - .QueryId = queryId + .Type = IsAnalitycsQuery() ? FederatedQuery::QueryContent::ANALYTICS : FederatedQuery::QueryContent::STREAMING, + .QueryId = queryId, + .FqOptions = GetFqOptions() }; } @@ -94,8 +109,9 @@ void RunArgumentQuery(ui64 queryId, const TExecutionOptions& executionOptions, T NColorizer::TColors colors = NColorizer::AutoColors(Cout); switch (executionOptions.ExecutionCase) { + case TExecutionOptions::EExecutionCase::Analytics: case TExecutionOptions::EExecutionCase::Stream: { - if (!runner.ExecuteStreamQuery(executionOptions.GetQueryOptions(queryId))) { + if (!runner.ExecuteQuery(executionOptions.GetQueryOptions(queryId))) { ythrow yexception() << TInstant::Now().ToIsoStringLocal() << " Query execution failed"; } Cout << colors.Yellow() << TInstant::Now().ToIsoStringLocal() << " Fetching query results..." << colors.Default() << Endl; @@ -105,6 +121,7 @@ void RunArgumentQuery(ui64 queryId, const TExecutionOptions& executionOptions, T break; } + case TExecutionOptions::EExecutionCase::AsyncAnalytics: case TExecutionOptions::EExecutionCase::AsyncStream: { runner.ExecuteQueryAsync(executionOptions.GetQueryOptions(queryId)); break; @@ -117,14 +134,14 @@ void RunArgumentQueries(const TExecutionOptions& executionOptions, TFqRunner& ru if (!executionOptions.Connections.empty()) { Cout << colors.Yellow() << TInstant::Now().ToIsoStringLocal() << " Creating connections..." << colors.Default() << Endl; - if (!runner.CreateConnections(executionOptions.Connections)) { + if (!runner.CreateConnections(executionOptions.Connections, executionOptions.GetFqOptions())) { ythrow yexception() << TInstant::Now().ToIsoStringLocal() << " Failed to create connections"; } } if (!executionOptions.Bindings.empty()) { Cout << colors.Yellow() << TInstant::Now().ToIsoStringLocal() << " Creating bindings..." << colors.Default() << Endl; - if (!runner.CreateBindings(executionOptions.Bindings)) { + if (!runner.CreateBindings(executionOptions.Bindings, executionOptions.GetFqOptions())) { ythrow yexception() << TInstant::Now().ToIsoStringLocal() << " Failed to create bindings"; } } @@ -156,6 +173,7 @@ void RunArgumentQueries(const TExecutionOptions& executionOptions, TFqRunner& ru } } } + runner.FinalizeRunner(); if (executionOptions.HasResults()) { try { @@ -249,27 +267,12 @@ class TMain : public TMainBase { SetupAcl(binding.mutable_acl()); }); - options.AddLongOption("fq-cfg", "File with FQ config (NFq::NConfig::TConfig for FQ proxy)") + options.AddLongOption("cfg", "File with actor system config (TActorSystemConfig), use '-' for default") .RequiredArgument("file") - .DefaultValue("./configuration/fq_config.conf") + .DefaultValue("./configuration/app_config.conf") .Handler1([this](const NLastGetopt::TOptsParser* option) { - if (!google::protobuf::TextFormat::ParseFromString(LoadFile(TString(option->CurValOrDef())), &RunnerOptions.FqSettings.FqConfig)) { - ythrow yexception() << "Bad format of FQ configuration"; - } - }); - - options.AddLongOption("as-cfg", "File with actor system config (TActorSystemConfig), use '-' for default") - .RequiredArgument("file") - .DefaultValue("./configuration/as_config.conf") - .Handler1([this](const NLastGetopt::TOptsParser* option) { - const TString file(option->CurValOrDef()); - if (file == "-") { - return; - } - - RunnerOptions.FqSettings.ActorSystemConfig = NKikimrConfig::TActorSystemConfig(); - if (!google::protobuf::TextFormat::ParseFromString(LoadFile(file), &(*RunnerOptions.FqSettings.ActorSystemConfig))) { - ythrow yexception() << "Bad format of actor system configuration"; + if (!google::protobuf::TextFormat::ParseFromString(LoadFile(TString(option->CurValOrDef())), &RunnerOptions.FqSettings.AppConfig)) { + ythrow yexception() << "Bad format of app configuration"; } }); @@ -349,7 +352,9 @@ class TMain : public TMainBase { TChoices executionCase({ {"stream", TExecutionOptions::EExecutionCase::Stream}, - {"async-stream", TExecutionOptions::EExecutionCase::AsyncStream} + {"analytics", TExecutionOptions::EExecutionCase::Analytics}, + {"async-stream", TExecutionOptions::EExecutionCase::AsyncStream}, + {"async-analytics", TExecutionOptions::EExecutionCase::AsyncAnalytics} }); options.AddLongOption('C', "execution-case", "Type of query for -p argument") .RequiredArgument("query-type") @@ -411,9 +416,13 @@ class TMain : public TMainBase { .NoArgument() .SetFlag(&ExecutionOptions.ContinueAfterFail); + options.AddLongOption('S', "scope-id", "Query scope id") + .RequiredArgument("scope") + .StoreResult(&ExecutionOptions.Scope); + // Cluster settings - options.AddLongOption("cp-storage", "Start real control plane storage instead of in memory (will use local database by default), token variable CP_STORAGE_TOKEN") + options.AddLongOption("cp-storage-db", "Start real control plane storage instead of in memory (will use local database by default), token variable CP_STORAGE_TOKEN") .OptionalArgument("database@endpoint") .Handler1([this](const NLastGetopt::TOptsParser* option) { RunnerOptions.FqSettings.EnableCpStorage = true; @@ -422,7 +431,7 @@ class TMain : public TMainBase { } }); - options.AddLongOption("checkpoints", "Start checkpoint coordinator (will use local database by default), token variable CHECKPOINTS_TOKEN") + options.AddLongOption("checkpoints-db", "Start checkpoint coordinator (will use local database by default), token variable CHECKPOINTS_TOKEN") .OptionalArgument("database@endpoint") .Handler1([this](const NLastGetopt::TOptsParser* option) { RunnerOptions.FqSettings.EnableCheckpoints = true; @@ -431,7 +440,7 @@ class TMain : public TMainBase { } }); - options.AddLongOption("quotas", "Start FQ quotas service and rate limiter (will be created local rate limiter by default), token variable QUOTAS_TOKEN") + options.AddLongOption("quotas-db", "Start FQ quotas service and rate limiter (will be created local rate limiter by default), token variable QUOTAS_TOKEN") .OptionalArgument("database@endpoint") .Handler1([this](const NLastGetopt::TOptsParser* option) { RunnerOptions.FqSettings.EnableQuotas = true; @@ -440,7 +449,7 @@ class TMain : public TMainBase { } }); - options.AddLongOption("row-dispatcher", TStringBuilder() << "Use real coordinator for row dispatcher (will use local database by default), token variable ROW_DISPATCHER_TOKEN") + options.AddLongOption("row-dispatcher-db", "Use real coordinator for row dispatcher (will use local database by default), token variable ROW_DISPATCHER_TOKEN") .OptionalArgument("database@endpoint") .Handler1([this](const NLastGetopt::TOptsParser* option) { RunnerOptions.FqSettings.EnableRemoteRd = true; @@ -449,16 +458,37 @@ class TMain : public TMainBase { } }); + options.AddLongOption("single-compute-db", "Enable single compute database for analytics queries (will use local database by default), token variable YDB_COMPUTE_TOKEN") + .OptionalArgument("database@endpoint") + .Handler1([this](const NLastGetopt::TOptsParser* option) { + RunnerOptions.FqSettings.EnableYdbCompute = true; + if (const auto value = option->CurVal()) { + RunnerOptions.FqSettings.SingleComputeDatabase = TExternalDatabase::Parse(value, "YDB_COMPUTE_TOKEN"); + } + }); + + options.AddLongOption("shared-compute-db", "Add shared compute database for analytics queries, token variable YDB_COMPUTE_TOKEN") + .RequiredArgument("database@endpoint") + .Handler1([this](const NLastGetopt::TOptsParser* option) { + RunnerOptions.FqSettings.EnableYdbCompute = true; + RunnerOptions.FqSettings.SharedComputeDatabases.emplace_back(TExternalDatabase::Parse(option->CurVal(), "YDB_COMPUTE_TOKEN")); + }); + options.MutuallyExclusive("single-compute-db", "shared-compute-db"); + RegisterKikimrOptions(options, RunnerOptions.FqSettings); } int DoRun(NLastGetopt::TOptsParseResult&&) override { ExecutionOptions.Validate(RunnerOptions); + if (ExecutionOptions.IsAnalitycsQuery()) { + RunnerOptions.FqSettings.EnableYdbCompute = true; + } + RunnerOptions.FqSettings.YqlToken = GetEnv(YQL_TOKEN_VARIABLE); RunnerOptions.FqSettings.FunctionRegistry = CreateFunctionRegistry().Get(); - auto& fqConfig = RunnerOptions.FqSettings.FqConfig; + auto& fqConfig = *RunnerOptions.FqSettings.AppConfig.MutableFederatedQueryConfig(); auto& gatewayConfig = *fqConfig.mutable_gateways(); FillTokens(gatewayConfig.mutable_pq()); FillTokens(gatewayConfig.mutable_s3()); @@ -519,9 +549,7 @@ class TMain : public TMainBase { } void SetupLogsConfig() { - auto& logConfig = RunnerOptions.FqSettings.LogConfig; - - logConfig.SetDefaultLevel(DefaultLogPriority.value_or(NActors::NLog::EPriority::PRI_CRIT)); + auto& logConfig = *RunnerOptions.FqSettings.AppConfig.MutableLogConfig(); if (FqLogPriority) { std::unordered_map fqLogPriorities; diff --git a/ydb/tests/tools/fqrun/src/common.h b/ydb/tests/tools/fqrun/src/common.h index 2beebc03ccb4..54de86e338be 100644 --- a/ydb/tests/tools/fqrun/src/common.h +++ b/ydb/tests/tools/fqrun/src/common.h @@ -46,14 +46,12 @@ struct TFqSetupSettings : public NKikimrRun::TServerSettings { bool EnableRemoteRd = false; std::optional RowDispatcherDatabase; - EVerbose VerboseLevel = EVerbose::Info; + bool EnableYdbCompute = false; + std::optional SingleComputeDatabase; + std::vector SharedComputeDatabases; - TString YqlToken; + EVerbose VerboseLevel = EVerbose::Info; NYql::IPqGatewayFactory::TPtr PqGatewayFactory; - TIntrusivePtr FunctionRegistry; - NFq::NConfig::TConfig FqConfig; - NKikimrConfig::TLogConfig LogConfig; - std::optional ActorSystemConfig; NKikimrRun::TAsyncQueriesSettings AsyncQueriesSettings; }; @@ -72,10 +70,16 @@ struct TRunnerOptions { TFqSetupSettings FqSettings; }; +struct TFqOptions { + TString Scope; +}; + struct TRequestOptions { TString Query; - FederatedQuery::ExecuteMode Action; - ui64 QueryId; + FederatedQuery::ExecuteMode Action = FederatedQuery::ExecuteMode::RUN; + FederatedQuery::QueryContent::QueryType Type = FederatedQuery::QueryContent::STREAMING; + ui64 QueryId = 0; + TFqOptions FqOptions; }; void SetupAcl(FederatedQuery::Acl* acl); diff --git a/ydb/tests/tools/fqrun/src/fq_runner.cpp b/ydb/tests/tools/fqrun/src/fq_runner.cpp index f54ad05e6d4d..cdde223dd614 100644 --- a/ydb/tests/tools/fqrun/src/fq_runner.cpp +++ b/ydb/tests/tools/fqrun/src/fq_runner.cpp @@ -47,14 +47,15 @@ class TFqRunner::TImpl { , CoutColors(NColorizer::AutoColors(Cout)) {} - bool ExecuteStreamQuery(const TRequestOptions& query) { + bool ExecuteQuery(const TRequestOptions& query) { StartTraceOpt(query.QueryId); if (VerboseLevel >= EVerbose::QueriesText) { - Cout << CoutColors.Cyan() << "Starting stream request:\n" << CoutColors.Default() << query.Query << Endl; + Cout << CoutColors.Cyan() << "Starting " << FederatedQuery::QueryContent::QueryType_Name(query.Type) << " request:\n" << CoutColors.Default() << query.Query << Endl; } - const TRequestResult status = FqSetup.StreamRequest(query, StreamQueryId); + CurrentOptions = query.FqOptions; + const TRequestResult status = FqSetup.QueryRequest(query, StreamQueryId); if (!status.IsSuccess()) { Cerr << CerrColors.Red() << "Failed to start stream request execution, reason:" << CerrColors.Default() << Endl << status.ToString() << Endl; @@ -73,7 +74,7 @@ class TFqRunner::TImpl { Cerr << CerrColors.Red() << "Result set with id " << resultSetId << " have " << rowsCount << " rows, it is larger than allowed limit " << MAX_RESULT_SET_ROWS << ", results will be truncated" << CerrColors.Default() << Endl; } - const TRequestResult status = FqSetup.FetchQueryResults(StreamQueryId, resultSetId, ResultSets[resultSetId]); + const TRequestResult status = FqSetup.FetchQueryResults(StreamQueryId, resultSetId, CurrentOptions, ResultSets[resultSetId]); if (!status.IsSuccess()) { Cerr << CerrColors.Red() << "Failed to fetch result set with id " << resultSetId << ", reason:" << CerrColors.Default() << Endl << status.ToString() << Endl; return false; @@ -95,14 +96,14 @@ class TFqRunner::TImpl { } } - bool CreateConnections(const std::vector& connections) { + bool CreateConnections(const std::vector& connections, const TFqOptions& options) { for (const auto& connection : connections) { if (VerboseLevel >= EVerbose::QueriesText) { Cout << CoutColors.Cyan() << "Creating connection:\n" << CoutColors.Default() << Endl << connection.DebugString() << Endl; } TString connectionId; - const TRequestResult status = FqSetup.CreateConnection(connection, connectionId); + const TRequestResult status = FqSetup.CreateConnection(connection, options, connectionId); if (!status.IsSuccess()) { Cerr << CerrColors.Red() << "Failed to create connection '" << connection.name() << "', reason:" << CerrColors.Default() << Endl << status.ToString() << Endl; @@ -118,7 +119,7 @@ class TFqRunner::TImpl { return true; } - bool CreateBindings(const std::vector& bindings) const { + bool CreateBindings(const std::vector& bindings, const TFqOptions& options) const { for (auto binding : bindings) { if (VerboseLevel >= EVerbose::QueriesText) { Cout << CoutColors.Cyan() << "Creating binding:\n" << CoutColors.Default() << Endl << binding.DebugString() << Endl; @@ -131,7 +132,7 @@ class TFqRunner::TImpl { } binding.set_connection_id(it->second); - const TRequestResult status = FqSetup.CreateBinding(binding); + const TRequestResult status = FqSetup.CreateBinding(binding, options); if (!status.IsSuccess()) { Cerr << CerrColors.Red() << "Failed to create binding '" << binding.name() << "', reason:" << CerrColors.Default() << Endl << status.ToString() << Endl; @@ -146,7 +147,7 @@ class TFqRunner::TImpl { StartTraceOpt(query.QueryId); if (VerboseLevel >= EVerbose::QueriesText) { - Cout << CoutColors.Cyan() << "Starting async stream request:\n" << CoutColors.Default() << query.Query << Endl; + Cout << CoutColors.Cyan() << "Starting async " << FederatedQuery::QueryContent::QueryType_Name(query.Type) << " request:\n" << CoutColors.Default() << query.Query << Endl; } FqSetup.QueryRequestAsync(query, Options.PingPeriod); @@ -165,7 +166,7 @@ class TFqRunner::TImpl { while (true) { TExecutionMeta meta; - const TRequestResult status = FqSetup.DescribeQuery(StreamQueryId, meta); + const TRequestResult status = FqSetup.DescribeQuery(StreamQueryId, CurrentOptions, meta); if (meta.TransientIssues.Size() != ExecutionMeta.TransientIssues.Size() && VerboseLevel >= EVerbose::Info) { Cerr << CerrColors.Red() << "Query transient issues updated:" << CerrColors.Default() << Endl << meta.TransientIssues.ToString() << Endl; @@ -216,7 +217,7 @@ class TFqRunner::TImpl { Cout << CoutColors.Cyan() << "Writing query ast" << CoutColors.Default() << Endl; } if (Options.CanonicalOutput) { - ast = CanonizeEndpoints(ast, Options.FqSettings.FqConfig.GetGateways()); + ast = CanonizeEndpoints(ast, Options.FqSettings.AppConfig.GetFederatedQueryConfig().GetGateways()); ast = CanonizeAstLogicalId(ast); } Options.AstOutput->Write(ast); @@ -239,7 +240,7 @@ class TFqRunner::TImpl { plan = NJson::PrettifyJson(plan, false); if (Options.CanonicalOutput) { - plan = CanonizeEndpoints(plan, Options.FqSettings.FqConfig.GetGateways()); + plan = CanonizeEndpoints(plan, Options.FqSettings.AppConfig.GetFederatedQueryConfig().GetGateways()); } Options.PlanOutput->Write(plan); @@ -255,6 +256,7 @@ class TFqRunner::TImpl { TString StreamQueryId; TInstant StartTime; + TFqOptions CurrentOptions; TExecutionMeta ExecutionMeta; std::vector ResultSets; std::unordered_map ConnectionNameToId; @@ -264,8 +266,8 @@ TFqRunner::TFqRunner(const TRunnerOptions& options) : Impl(new TImpl(options)) {} -bool TFqRunner::ExecuteStreamQuery(const TRequestOptions& query) const { - return Impl->ExecuteStreamQuery(query); +bool TFqRunner::ExecuteQuery(const TRequestOptions& query) const { + return Impl->ExecuteQuery(query); } bool TFqRunner::FetchQueryResults() const { @@ -276,12 +278,12 @@ void TFqRunner::PrintQueryResults() const { Impl->PrintQueryResults(); } -bool TFqRunner::CreateConnections(const std::vector& connections) const { - return Impl->CreateConnections(connections); +bool TFqRunner::CreateConnections(const std::vector& connections, const TFqOptions& options) const { + return Impl->CreateConnections(connections, options); } -bool TFqRunner::CreateBindings(const std::vector& bindings) const { - return Impl->CreateBindings(bindings); +bool TFqRunner::CreateBindings(const std::vector& bindings, const TFqOptions& options) const { + return Impl->CreateBindings(bindings, options); } void TFqRunner::ExecuteQueryAsync(const TRequestOptions& query) const { diff --git a/ydb/tests/tools/fqrun/src/fq_runner.h b/ydb/tests/tools/fqrun/src/fq_runner.h index 153952a9559d..48e58c4fb0ef 100644 --- a/ydb/tests/tools/fqrun/src/fq_runner.h +++ b/ydb/tests/tools/fqrun/src/fq_runner.h @@ -10,15 +10,15 @@ class TFqRunner { public: explicit TFqRunner(const TRunnerOptions& options); - bool ExecuteStreamQuery(const TRequestOptions& query) const; + bool ExecuteQuery(const TRequestOptions& query) const; bool FetchQueryResults() const; void PrintQueryResults() const; - bool CreateConnections(const std::vector& connections) const; + bool CreateConnections(const std::vector& connections, const TFqOptions& options) const; - bool CreateBindings(const std::vector& bindings) const; + bool CreateBindings(const std::vector& bindings, const TFqOptions& options) const; void ExecuteQueryAsync(const TRequestOptions& query) const; diff --git a/ydb/tests/tools/fqrun/src/fq_setup.cpp b/ydb/tests/tools/fqrun/src/fq_setup.cpp index dc135030cb05..647ef74ebf17 100644 --- a/ydb/tests/tools/fqrun/src/fq_setup.cpp +++ b/ydb/tests/tools/fqrun/src/fq_setup.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -26,59 +27,13 @@ TRequestResult GetStatus(const NYql::TIssues& issues) { } // anonymous namespace -class TFqSetup::TImpl { +class TFqSetup::TImpl : public TKikimrSetupBase { + using TBase = TKikimrSetupBase; using EVerbose = TFqSetupSettings::EVerbose; private: - TAutoPtr CreateLogBackend() const { - if (Settings.LogOutputFile) { - return NActors::CreateFileBackend(Settings.LogOutputFile); - } else { - return NActors::CreateStderrBackend(); - } - } - - void SetLoggerSettings(NKikimr::Tests::TServerSettings& serverSettings) const { - auto loggerInitializer = [this](NActors::TTestActorRuntime& runtime) { - InitLogSettings(Settings.LogConfig, runtime); - runtime.SetLogBackendFactory([this]() { return CreateLogBackend(); }); - }; - - serverSettings.SetLoggerInitializer(loggerInitializer); - } - - void SetFunctionRegistry(NKikimr::Tests::TServerSettings& serverSettings) const { - if (Settings.FunctionRegistry) { - serverSettings.SetFrFactory([this](const NKikimr::NScheme::TTypeRegistry&) { - return Settings.FunctionRegistry.Get(); - }); - } - } - NKikimr::Tests::TServerSettings GetServerSettings(ui32 grpcPort) { - NKikimr::Tests::TServerSettings serverSettings(PortManager.GetPort()); - - serverSettings.SetDomainName(Settings.DomainName); - serverSettings.SetVerbose(Settings.VerboseLevel >= EVerbose::InitLogs); - - NKikimrConfig::TAppConfig config; - *config.MutableLogConfig() = Settings.LogConfig; - if (Settings.ActorSystemConfig) { - *config.MutableActorSystemConfig() = *Settings.ActorSystemConfig; - } - serverSettings.SetAppConfig(config); - - SetLoggerSettings(serverSettings); - SetFunctionRegistry(serverSettings); - - if (Settings.MonitoringEnabled) { - serverSettings.InitKikimrRunConfig(); - serverSettings.SetMonitoringPortOffset(Settings.FirstMonitoringPort, true); - serverSettings.SetNeedStatsCollectors(true); - } - - serverSettings.SetGrpcPort(grpcPort); - serverSettings.SetEnableYqGrpc(true); + auto serverSettings = TBase::GetServerSettings(grpcPort, Settings.VerboseLevel >= EVerbose::InitLogs); return serverSettings; } @@ -101,7 +56,7 @@ class TFqSetup::TImpl { } NFq::NConfig::TConfig GetFqProxyConfig(ui32 grpcPort) const { - auto fqConfig = Settings.FqConfig; + auto fqConfig = Settings.AppConfig.GetFederatedQueryConfig(); fqConfig.MutableControlPlaneStorage()->AddSuperUsers(BUILTIN_ACL_ROOT); fqConfig.MutablePrivateProxy()->AddGrantedUsers(BUILTIN_ACL_ROOT); @@ -155,11 +110,44 @@ class TFqSetup::TImpl { fillStorageConfig(rowDispatcher.MutableDatabase(), Settings.RowDispatcherDatabase); } + auto& ydbCompute = *fqConfig.MutableCompute()->MutableYdb(); + ydbCompute.SetEnable(Settings.EnableYdbCompute); + ydbCompute.MutableSynchronizationService()->SetEnable(Settings.EnableYdbCompute); + + auto& computeControlPlane = *ydbCompute.MutableControlPlane(); + computeControlPlane.SetEnable(Settings.EnableYdbCompute); + + if (Settings.SingleComputeDatabase && !Settings.SharedComputeDatabases.empty()) { + ythrow yexception() << "Expected one of single compute database or shared compute databases"; + } + for (size_t i = 0; const auto& database : Settings.SharedComputeDatabases) { + auto& databaseConfig = *computeControlPlane.MutableCms()->MutableDatabaseMapping()->AddCommon(); + databaseConfig.SetId(TStringBuilder() << "sls" << (Settings.SharedComputeDatabases.size() > 1 ? TStringBuilder() << "_" << ++i : TStringBuilder())); + databaseConfig.MutableExecutionConnection()->SetEndpoint(database.Endpoint); + fillStorageConfig(databaseConfig.MutableControlPlaneConnection(), database); + + const auto path = NKikimr::CanonizePath(database.Database); + const auto splitPos = path.rfind('/'); + if (splitPos == 0 || splitPos == TString::npos) { + ythrow yexception() << "Unexpected shared compute database: " << database.Database << ", it should not be empty or root"; + } + databaseConfig.SetTenant(path.substr(0, splitPos)); + } + if (Settings.SingleComputeDatabase || (Settings.EnableYdbCompute && computeControlPlane.GetTypeCase() == NFq::NConfig::TYdbComputeControlPlane::TYPE_NOT_SET)) { + auto& singleCompute = *computeControlPlane.MutableSingle(); + singleCompute.SetId("single"); + fillStorageConfig(singleCompute.MutableConnection(), Settings.SingleComputeDatabase); + } + return fqConfig; } void InitializeFqProxy(ui32 grpcPort) { const auto& fqConfig = GetFqProxyConfig(grpcPort); + if (Settings.VerboseLevel >= EVerbose::InitLogs) { + Cout << "FQ config:\n" << fqConfig.DebugString() << Endl; + } + const auto counters = GetRuntime()->GetAppData().Counters->GetSubgroup("counters", "yq"); YqSharedResources = NFq::CreateYqSharedResources(fqConfig, NKikimr::CreateYdbCredentialsProviderFactory, counters); @@ -184,15 +172,22 @@ class TFqSetup::TImpl { return; } - ModifyLogPriorities({{NKikimrServices::EServiceKikimr::YQL_PROXY, NActors::NLog::PRI_TRACE}}, Settings.LogConfig); + ModifyLogPriorities({{NKikimrServices::EServiceKikimr::YQL_PROXY, NActors::NLog::PRI_TRACE}}, *Settings.AppConfig.MutableLogConfig()); NYql::NLog::InitLogger(NActors::CreateNullBackend()); } public: explicit TImpl(const TFqSetupSettings& settings) - : Settings(settings) + : TBase(settings) + , Settings(settings) { const ui32 grpcPort = Settings.FirstGrpcPort ? Settings.FirstGrpcPort : PortManager.GetPort(); + if (Settings.GrpcEnabled && Settings.VerboseLevel >= EVerbose::Info) { + Cout << CoutColors.Cyan() << "Domain gRPC port: " << CoutColors.Default() << grpcPort << Endl; + } + + Settings.GrpcEnabled = true; + InitializeYqlLogger(); InitializeServer(grpcPort); InitializeFqProxy(grpcPort); @@ -200,10 +195,6 @@ class TFqSetup::TImpl { if (Settings.MonitoringEnabled && Settings.VerboseLevel >= EVerbose::Info) { Cout << CoutColors.Cyan() << "Monitoring port: " << CoutColors.Default() << GetRuntime()->GetMonPort() << Endl; } - - if (Settings.GrpcEnabled && Settings.VerboseLevel >= EVerbose::Info) { - Cout << CoutColors.Cyan() << "Domain gRPC port: " << CoutColors.Default() << grpcPort << Endl; - } } ~TImpl() { @@ -212,40 +203,40 @@ class TFqSetup::TImpl { } } - NFq::TEvControlPlaneProxy::TEvCreateQueryResponse::TPtr StreamRequest(const TRequestOptions& query) const { + NFq::TEvControlPlaneProxy::TEvCreateQueryResponse::TPtr QueryRequest(const TRequestOptions& query) const { return RunControlPlaneProxyRequest( - GetStreamRequest(query) + GetQueryRequest(query), query.FqOptions ); } - NFq::TEvControlPlaneProxy::TEvDescribeQueryResponse::TPtr DescribeQuery(const TString& queryId) const { + NFq::TEvControlPlaneProxy::TEvDescribeQueryResponse::TPtr DescribeQuery(const TString& queryId, const TFqOptions& options) const { FederatedQuery::DescribeQueryRequest request; request.set_query_id(queryId); - return RunControlPlaneProxyRequest(request); + return RunControlPlaneProxyRequest(request, options); } - NFq::TEvControlPlaneProxy::TEvGetResultDataResponse::TPtr FetchQueryResults(const TString& queryId, i32 resultSetId) const { + NFq::TEvControlPlaneProxy::TEvGetResultDataResponse::TPtr FetchQueryResults(const TString& queryId, i32 resultSetId, const TFqOptions& options) const { FederatedQuery::GetResultDataRequest request; request.set_query_id(queryId); request.set_result_set_index(resultSetId); request.set_limit(MAX_RESULT_SET_ROWS); - return RunControlPlaneProxyRequest(request); + return RunControlPlaneProxyRequest(request, options); } - NFq::TEvControlPlaneProxy::TEvCreateConnectionResponse::TPtr CreateConnection(const FederatedQuery::ConnectionContent& connection) const { + NFq::TEvControlPlaneProxy::TEvCreateConnectionResponse::TPtr CreateConnection(const FederatedQuery::ConnectionContent& connection, const TFqOptions& options) const { FederatedQuery::CreateConnectionRequest request; *request.mutable_content() = connection; - return RunControlPlaneProxyRequest(request); + return RunControlPlaneProxyRequest(request, options); } - NFq::TEvControlPlaneProxy::TEvCreateBindingResponse::TPtr CreateBinding(const FederatedQuery::BindingContent& binding) const { + NFq::TEvControlPlaneProxy::TEvCreateBindingResponse::TPtr CreateBinding(const FederatedQuery::BindingContent& binding, const TFqOptions& options) const { FederatedQuery::CreateBindingRequest request; *request.mutable_content() = binding; - return RunControlPlaneProxyRequest(request); + return RunControlPlaneProxyRequest(request, options); } void QueryRequestAsync(const TRequestOptions& query, TDuration pingPeriod) { @@ -254,7 +245,7 @@ class TFqSetup::TImpl { } TQueryRequest request = { - .Event = GetControlPlaneRequest(GetStreamRequest(query)), + .Event = GetControlPlaneRequest(GetQueryRequest(query), query.FqOptions), .PingPeriod = pingPeriod }; auto startPromise = NThreading::NewPromise(); @@ -291,12 +282,12 @@ class TFqSetup::TImpl { return Server->GetRuntime(); } - static FederatedQuery::CreateQueryRequest GetStreamRequest(const TRequestOptions& query) { + static FederatedQuery::CreateQueryRequest GetQueryRequest(const TRequestOptions& query) { FederatedQuery::CreateQueryRequest request; request.set_execute_mode(query.Action); auto& content = *request.mutable_content(); - content.set_type(FederatedQuery::QueryContent::STREAMING); + content.set_type(query.Type); content.set_text(query.Query); SetupAcl(content.mutable_acl()); @@ -304,13 +295,13 @@ class TFqSetup::TImpl { } template - std::unique_ptr GetControlPlaneRequest(const TProto& request) const { - return std::make_unique("yandexcloud://fqrun", request, BUILTIN_ACL_ROOT, Settings.YqlToken ? Settings.YqlToken : "fqrun", TVector{}); + std::unique_ptr GetControlPlaneRequest(const TProto& request, const TFqOptions& options) const { + return std::make_unique(TStringBuilder() << "yandexcloud://" << (options.Scope ? options.Scope : "fqrun"), request, BUILTIN_ACL_ROOT, Settings.YqlToken ? Settings.YqlToken : "fqrun", TVector{}); } template - typename TResponse::TPtr RunControlPlaneProxyRequest(const TProto& request) const { - return RunControlPlaneProxyRequest(GetControlPlaneRequest(request)); + typename TResponse::TPtr RunControlPlaneProxyRequest(const TProto& request, const TFqOptions& options) const { + return RunControlPlaneProxyRequest(GetControlPlaneRequest(request, options)); } template @@ -339,16 +330,16 @@ TFqSetup::TFqSetup(const TFqSetupSettings& settings) : Impl(new TImpl(settings)) {} -TRequestResult TFqSetup::StreamRequest(const TRequestOptions& query, TString& queryId) const { - const auto response = Impl->StreamRequest(query); +TRequestResult TFqSetup::QueryRequest(const TRequestOptions& query, TString& queryId) const { + const auto response = Impl->QueryRequest(query); queryId = response->Get()->Result.query_id(); return GetStatus(response->Get()->Issues); } -TRequestResult TFqSetup::DescribeQuery(const TString& queryId, TExecutionMeta& meta) const { - const auto response = Impl->DescribeQuery(queryId); +TRequestResult TFqSetup::DescribeQuery(const TString& queryId, const TFqOptions& options, TExecutionMeta& meta) const { + const auto response = Impl->DescribeQuery(queryId, options); const auto& result = response->Get()->Result.query(); meta.Status = result.meta().status(); @@ -366,24 +357,24 @@ TRequestResult TFqSetup::DescribeQuery(const TString& queryId, TExecutionMeta& m return GetStatus(response->Get()->Issues); } -TRequestResult TFqSetup::FetchQueryResults(const TString& queryId, i32 resultSetId, Ydb::ResultSet& resultSet) const { - const auto response = Impl->FetchQueryResults(queryId, resultSetId); +TRequestResult TFqSetup::FetchQueryResults(const TString& queryId, i32 resultSetId, const TFqOptions& options, Ydb::ResultSet& resultSet) const { + const auto response = Impl->FetchQueryResults(queryId, resultSetId, options); resultSet = response->Get()->Result.result_set(); return GetStatus(response->Get()->Issues); } -TRequestResult TFqSetup::CreateConnection(const FederatedQuery::ConnectionContent& connection, TString& connectionId) const { - const auto response = Impl->CreateConnection(connection); +TRequestResult TFqSetup::CreateConnection(const FederatedQuery::ConnectionContent& connection, const TFqOptions& options, TString& connectionId) const { + const auto response = Impl->CreateConnection(connection, options); connectionId = response->Get()->Result.connection_id(); return GetStatus(response->Get()->Issues); } -TRequestResult TFqSetup::CreateBinding(const FederatedQuery::BindingContent& binding) const { - const auto response = Impl->CreateBinding(binding); +TRequestResult TFqSetup::CreateBinding(const FederatedQuery::BindingContent& binding, const TFqOptions& options) const { + const auto response = Impl->CreateBinding(binding, options); return GetStatus(response->Get()->Issues); } diff --git a/ydb/tests/tools/fqrun/src/fq_setup.h b/ydb/tests/tools/fqrun/src/fq_setup.h index e93fc0afadd7..119d54587eee 100644 --- a/ydb/tests/tools/fqrun/src/fq_setup.h +++ b/ydb/tests/tools/fqrun/src/fq_setup.h @@ -22,15 +22,15 @@ class TFqSetup { public: explicit TFqSetup(const TFqSetupSettings& settings); - TRequestResult StreamRequest(const TRequestOptions& query, TString& queryId) const; + TRequestResult QueryRequest(const TRequestOptions& query, TString& queryId) const; - TRequestResult DescribeQuery(const TString& queryId, TExecutionMeta& meta) const; + TRequestResult DescribeQuery(const TString& queryId, const TFqOptions& options, TExecutionMeta& meta) const; - TRequestResult FetchQueryResults(const TString& queryId, i32 resultSetId, Ydb::ResultSet& resultSet) const; + TRequestResult FetchQueryResults(const TString& queryId, i32 resultSetId, const TFqOptions& options, Ydb::ResultSet& resultSet) const; - TRequestResult CreateConnection(const FederatedQuery::ConnectionContent& connection, TString& connectionId) const; + TRequestResult CreateConnection(const FederatedQuery::ConnectionContent& connection, const TFqOptions& options, TString& connectionId) const; - TRequestResult CreateBinding(const FederatedQuery::BindingContent& binding) const; + TRequestResult CreateBinding(const FederatedQuery::BindingContent& binding, const TFqOptions& options) const; void QueryRequestAsync(const TRequestOptions& query, TDuration pingPeriod) const; diff --git a/ydb/tests/tools/fqrun/src/ya.make b/ydb/tests/tools/fqrun/src/ya.make index bf88dd8dadfb..8bad7caa777f 100644 --- a/ydb/tests/tools/fqrun/src/ya.make +++ b/ydb/tests/tools/fqrun/src/ya.make @@ -20,6 +20,7 @@ PEERDIR( ydb/library/grpc/server/actors ydb/library/security ydb/library/yql/providers/pq/provider + ydb/library/yql/providers/s3/actors ydb/tests/tools/kqprun/runlib yql/essentials/minikql ) diff --git a/ydb/tests/tools/kqprun/runlib/kikimr_setup.cpp b/ydb/tests/tools/kqprun/runlib/kikimr_setup.cpp new file mode 100644 index 000000000000..db98a5b05abf --- /dev/null +++ b/ydb/tests/tools/kqprun/runlib/kikimr_setup.cpp @@ -0,0 +1,135 @@ +#include "kikimr_setup.h" +#include "utils.h" + +#include +#include + +#include + +namespace NKikimrRun { + +namespace { + +class TStaticCredentialsProvider : public NYdb::ICredentialsProvider { +public: + TStaticCredentialsProvider(const TString& yqlToken) + : YqlToken_(yqlToken) + {} + + std::string GetAuthInfo() const override { + return YqlToken_; + } + + bool IsValid() const override { + return true; + } + +private: + std::string YqlToken_; +}; + +class TStaticCredentialsProviderFactory : public NYdb::ICredentialsProviderFactory { +public: + TStaticCredentialsProviderFactory(const TString& yqlToken) + : YqlToken_(yqlToken) + {} + + std::shared_ptr CreateProvider() const override { + return std::make_shared(YqlToken_); + } + +private: + TString YqlToken_; +}; + +class TStaticSecuredCredentialsFactory : public NYql::ISecuredServiceAccountCredentialsFactory { +public: + TStaticSecuredCredentialsFactory(const TString& yqlToken) + : YqlToken_(yqlToken) + {} + + std::shared_ptr Create(const TString&, const TString&) override { + return std::make_shared(YqlToken_); + } + +private: + TString YqlToken_; +}; + +} // anonymous namespace + +TKikimrSetupBase::TKikimrSetupBase(const TServerSettings& settings) + : Settings(settings) +{} + +TAutoPtr TKikimrSetupBase::CreateLogBackend() const { + if (Settings.LogOutputFile) { + return NActors::CreateFileBackend(Settings.LogOutputFile); + } else { + return NActors::CreateStderrBackend(); + } +} + +NKikimr::Tests::TServerSettings TKikimrSetupBase::GetServerSettings(ui32 grpcPort, bool verbose) { + const ui32 msgBusPort = PortManager.GetPort(); + + NKikimr::Tests::TServerSettings serverSettings(msgBusPort, Settings.AppConfig.GetAuthConfig(), Settings.AppConfig.GetPQConfig()); + serverSettings.SetNodeCount(Settings.NodeCount); + + serverSettings.SetDomainName(TString(NKikimr::ExtractDomain(NKikimr::CanonizePath(Settings.DomainName)))); + serverSettings.SetAppConfig(Settings.AppConfig); + serverSettings.SetFeatureFlags(Settings.AppConfig.GetFeatureFlags()); + serverSettings.SetControls(Settings.AppConfig.GetImmediateControlsConfig()); + serverSettings.SetCompactionConfig(Settings.AppConfig.GetCompactionConfig()); + serverSettings.PQClusterDiscoveryConfig = Settings.AppConfig.GetPQClusterDiscoveryConfig(); + serverSettings.NetClassifierConfig = Settings.AppConfig.GetNetClassifierConfig(); + + const auto& kqpSettings = Settings.AppConfig.GetKQPConfig().GetSettings(); + serverSettings.SetKqpSettings({kqpSettings.begin(), kqpSettings.end()}); + + serverSettings.SetCredentialsFactory(std::make_shared(Settings.YqlToken)); + serverSettings.SetComputationFactory(Settings.ComputationFactory); + serverSettings.SetYtGateway(Settings.YtGateway); + serverSettings.S3ActorsFactory = NYql::NDq::CreateS3ActorsFactory(); + serverSettings.SetDqTaskTransformFactory(NYql::CreateYtDqTaskTransformFactory(true)); + serverSettings.SetInitializeFederatedQuerySetupFactory(true); + serverSettings.SetVerbose(verbose); + serverSettings.SetNeedStatsCollectors(true); + + SetLoggerSettings(serverSettings); + SetFunctionRegistry(serverSettings); + + if (Settings.MonitoringEnabled) { + serverSettings.InitKikimrRunConfig(); + serverSettings.SetMonitoringPortOffset(Settings.FirstMonitoringPort, true); + } + + if (Settings.GrpcEnabled) { + serverSettings.SetGrpcPort(grpcPort); + } + + return serverSettings; +} + +void TKikimrSetupBase::SetLoggerSettings(NKikimr::Tests::TServerSettings& serverSettings) const { + auto loggerInitializer = [this](NActors::TTestActorRuntime& runtime) { + InitLogSettings(Settings.AppConfig.GetLogConfig(), runtime); + runtime.SetLogBackendFactory([this]() { return CreateLogBackend(); }); + }; + + serverSettings.SetLoggerInitializer(loggerInitializer); +} + +void TKikimrSetupBase::SetFunctionRegistry(NKikimr::Tests::TServerSettings& serverSettings) const { + if (!Settings.FunctionRegistry) { + return; + } + + auto functionRegistryFactory = [this](const NKikimr::NScheme::TTypeRegistry&) { + return Settings.FunctionRegistry.Get(); + }; + + serverSettings.SetFrFactory(functionRegistryFactory); +} + +} // namespace NKikimrRun diff --git a/ydb/tests/tools/kqprun/runlib/kikimr_setup.h b/ydb/tests/tools/kqprun/runlib/kikimr_setup.h new file mode 100644 index 000000000000..fc02bcf3e2be --- /dev/null +++ b/ydb/tests/tools/kqprun/runlib/kikimr_setup.h @@ -0,0 +1,31 @@ +#pragma once + +#include "settings.h" + +#include + +#include + +namespace NKikimrRun { + +class TKikimrSetupBase { +public: + TKikimrSetupBase(const TServerSettings& settings); + + TAutoPtr CreateLogBackend() const; + + NKikimr::Tests::TServerSettings GetServerSettings(ui32 grpcPort, bool verbose); + +private: + void SetLoggerSettings(NKikimr::Tests::TServerSettings& serverSettings) const; + + void SetFunctionRegistry(NKikimr::Tests::TServerSettings& serverSettings) const; + +protected: + TPortManager PortManager; + +private: + const TServerSettings& Settings; +}; + +} // namespace NKikimrRun diff --git a/ydb/tests/tools/kqprun/runlib/settings.h b/ydb/tests/tools/kqprun/runlib/settings.h index dbb4d25ccd87..d2260b75deba 100644 --- a/ydb/tests/tools/kqprun/runlib/settings.h +++ b/ydb/tests/tools/kqprun/runlib/settings.h @@ -2,6 +2,13 @@ #include +#include + +#include +#include + +#include + namespace NKikimrRun { struct TAsyncQueriesSettings { @@ -15,6 +22,7 @@ struct TAsyncQueriesSettings { }; struct TServerSettings { + ui32 NodeCount = 1; TString DomainName = "Root"; bool MonitoringEnabled = false; @@ -24,6 +32,12 @@ struct TServerSettings { ui16 FirstGrpcPort = 0; TString LogOutputFile; + + TString YqlToken; + NKikimrConfig::TAppConfig AppConfig; + TIntrusivePtr FunctionRegistry; + NKikimr::NMiniKQL::TComputationNodeFactory ComputationFactory; + TIntrusivePtr YtGateway; }; enum class EResultOutputFormat { diff --git a/ydb/tests/tools/kqprun/runlib/ya.make b/ydb/tests/tools/kqprun/runlib/ya.make index cc92e6f90333..9abf6a8d384e 100644 --- a/ydb/tests/tools/kqprun/runlib/ya.make +++ b/ydb/tests/tools/kqprun/runlib/ya.make @@ -2,6 +2,7 @@ LIBRARY() SRCS( application.cpp + kikimr_setup.cpp utils.cpp ) @@ -9,21 +10,27 @@ PEERDIR( library/cpp/colorizer library/cpp/getopt library/cpp/json + library/cpp/logger library/cpp/threading/future ydb/core/base ydb/core/blob_depot ydb/core/fq/libs/compute/common ydb/core/protos + ydb/core/testlib ydb/library/actors/core ydb/library/actors/testlib ydb/library/services + ydb/library/yql/providers/s3/actors ydb/public/api/protos ydb/public/lib/json_value ydb/public/lib/ydb_cli/common yql/essentials/minikql + yql/essentials/minikql/computation yql/essentials/minikql/invoke_builtins yql/essentials/public/issue yql/essentials/public/udf + yt/yql/providers/yt/mkql_dq + yt/yql/providers/yt/provider ) YQL_LAST_ABI_VERSION() diff --git a/ydb/tests/tools/kqprun/src/common.h b/ydb/tests/tools/kqprun/src/common.h index 917e2f4f77c7..ae401303adf2 100644 --- a/ydb/tests/tools/kqprun/src/common.h +++ b/ydb/tests/tools/kqprun/src/common.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -10,11 +9,6 @@ #include -#include -#include - -#include - namespace NKqpRun { @@ -39,7 +33,6 @@ struct TYdbSetupSettings : public NKikimrRun::TServerSettings { Max }; - ui32 NodeCount = 1; std::map Tenants; TDuration HealthCheckTimeout = TDuration::Seconds(10); EHealthCheck HealthCheckLevel = EHealthCheck::NodesCount; @@ -52,12 +45,6 @@ struct TYdbSetupSettings : public NKikimrRun::TServerSettings { bool TraceOptEnabled = false; EVerbose VerboseLevel = EVerbose::Info; - - TString YqlToken; - TIntrusivePtr FunctionRegistry; - NKikimr::NMiniKQL::TComputationNodeFactory ComputationFactory; - TIntrusivePtr YtGateway; - NKikimrConfig::TAppConfig AppConfig; NKikimrRun::TAsyncQueriesSettings AsyncQueriesSettings; }; diff --git a/ydb/tests/tools/kqprun/src/ydb_setup.cpp b/ydb/tests/tools/kqprun/src/ydb_setup.cpp index 2d6e3aad58d4..46157889643f 100644 --- a/ydb/tests/tools/kqprun/src/ydb_setup.cpp +++ b/ydb/tests/tools/kqprun/src/ydb_setup.cpp @@ -8,67 +8,17 @@ #include #include -#include - +#include #include #include -#include - using namespace NKikimrRun; namespace NKqpRun { namespace { -class TStaticCredentialsProvider : public NYdb::ICredentialsProvider { -public: - TStaticCredentialsProvider(const TString& yqlToken) - : YqlToken_(yqlToken) - {} - - std::string GetAuthInfo() const override { - return YqlToken_; - } - - bool IsValid() const override { - return true; - } - -private: - std::string YqlToken_; -}; - -class TStaticCredentialsProviderFactory : public NYdb::ICredentialsProviderFactory { -public: - TStaticCredentialsProviderFactory(const TString& yqlToken) - : YqlToken_(yqlToken) - {} - - std::shared_ptr CreateProvider() const override { - return std::make_shared(YqlToken_); - } - -private: - TString YqlToken_; -}; - -class TStaticSecuredCredentialsFactory : public NYql::ISecuredServiceAccountCredentialsFactory { -public: - TStaticSecuredCredentialsFactory(const TString& yqlToken) - : YqlToken_(yqlToken) - {} - - std::shared_ptr Create(const TString&, const TString&) override { - return std::make_shared(YqlToken_); - } - -private: - TString YqlToken_; -}; - - class TSessionState { public: explicit TSessionState(NActors::TTestActorRuntime* runtime, ui32 targetNodeIndex, const TString& database, const TString& traceId, TYdbSetupSettings::EVerbose verboseLevel) @@ -136,7 +86,8 @@ void FillQueryMeta(TQueryMeta& meta, const NKikimrKqp::TQueryResponse& response) //// TYdbSetup::TImpl -class TYdbSetup::TImpl { +class TYdbSetup::TImpl : public TKikimrSetupBase { + using TBase = TKikimrSetupBase; using EVerbose = TYdbSetupSettings::EVerbose; using EHealthCheck = TYdbSetupSettings::EHealthCheck; @@ -160,35 +111,6 @@ class TYdbSetup::TImpl { }; private: - TAutoPtr CreateLogBackend() const { - if (Settings_.LogOutputFile) { - return NActors::CreateFileBackend(Settings_.LogOutputFile); - } else { - return NActors::CreateStderrBackend(); - } - } - - void SetLoggerSettings(NKikimr::Tests::TServerSettings& serverSettings) const { - auto loggerInitializer = [this](NActors::TTestActorRuntime& runtime) { - InitLogSettings(Settings_.AppConfig.GetLogConfig(), runtime); - runtime.SetLogBackendFactory([this]() { return CreateLogBackend(); }); - }; - - serverSettings.SetLoggerInitializer(loggerInitializer); - } - - void SetFunctionRegistry(NKikimr::Tests::TServerSettings& serverSettings) const { - if (!Settings_.FunctionRegistry) { - return; - } - - auto functionRegistryFactory = [this](const NKikimr::NScheme::TTypeRegistry&) { - return Settings_.FunctionRegistry.Get(); - }; - - serverSettings.SetFrFactory(functionRegistryFactory); - } - void SetStorageSettings(NKikimr::Tests::TServerSettings& serverSettings) { TFsPath diskPath; if (Settings_.PDisksPath && *Settings_.PDisksPath != "-") { @@ -255,43 +177,9 @@ class TYdbSetup::TImpl { } NKikimr::Tests::TServerSettings GetServerSettings(ui32 grpcPort) { - const ui32 msgBusPort = PortManager_.GetPort(); - - NKikimr::Tests::TServerSettings serverSettings(msgBusPort, Settings_.AppConfig.GetAuthConfig(), Settings_.AppConfig.GetPQConfig()); - serverSettings.SetNodeCount(Settings_.NodeCount); - - serverSettings.SetDomainName(TString(NKikimr::ExtractDomain(NKikimr::CanonizePath(Settings_.DomainName)))); - serverSettings.SetAppConfig(Settings_.AppConfig); - serverSettings.SetFeatureFlags(Settings_.AppConfig.GetFeatureFlags()); - serverSettings.SetControls(Settings_.AppConfig.GetImmediateControlsConfig()); - serverSettings.SetCompactionConfig(Settings_.AppConfig.GetCompactionConfig()); - serverSettings.PQClusterDiscoveryConfig = Settings_.AppConfig.GetPQClusterDiscoveryConfig(); - serverSettings.NetClassifierConfig = Settings_.AppConfig.GetNetClassifierConfig(); - - const auto& kqpSettings = Settings_.AppConfig.GetKQPConfig().GetSettings(); - serverSettings.SetKqpSettings({kqpSettings.begin(), kqpSettings.end()}); - - serverSettings.SetCredentialsFactory(std::make_shared(Settings_.YqlToken)); - serverSettings.SetComputationFactory(Settings_.ComputationFactory); - serverSettings.SetYtGateway(Settings_.YtGateway); - serverSettings.S3ActorsFactory = NYql::NDq::CreateS3ActorsFactory(); - serverSettings.SetDqTaskTransformFactory(NYql::CreateYtDqTaskTransformFactory(true)); - serverSettings.SetInitializeFederatedQuerySetupFactory(true); - serverSettings.SetVerbose(Settings_.VerboseLevel >= EVerbose::InitLogs); - - SetLoggerSettings(serverSettings); - SetFunctionRegistry(serverSettings); - SetStorageSettings(serverSettings); + auto serverSettings = TBase::GetServerSettings(grpcPort, Settings_.VerboseLevel >= EVerbose::InitLogs); - if (Settings_.MonitoringEnabled) { - serverSettings.InitKikimrRunConfig(); - serverSettings.SetMonitoringPortOffset(Settings_.FirstMonitoringPort, true); - serverSettings.SetNeedStatsCollectors(true); - } - - if (Settings_.GrpcEnabled) { - serverSettings.SetGrpcPort(grpcPort); - } + SetStorageSettings(serverSettings); for (const auto& [tenantPath, tenantInfo] : StorageMeta_.GetTenants()) { Settings_.Tenants.emplace(tenantPath, tenantInfo); @@ -408,7 +296,7 @@ class TYdbSetup::TImpl { } void InitializeServer() { - TPortGenerator grpcPortGen(PortManager_, Settings_.FirstGrpcPort); + TPortGenerator grpcPortGen(PortManager, Settings_.FirstGrpcPort); const ui32 domainGrpcPort = grpcPortGen.GetPort(); NKikimr::Tests::TServerSettings serverSettings = GetServerSettings(domainGrpcPort); @@ -476,7 +364,8 @@ class TYdbSetup::TImpl { public: explicit TImpl(const TYdbSetupSettings& settings) - : Settings_(settings) + : TBase(settings) + , Settings_(settings) , CoutColors_(NColorizer::AutoColors(Cout)) { InitializeYqlLogger(); @@ -736,7 +625,6 @@ class TYdbSetup::TImpl { NKikimr::Tests::TServer::TPtr Server_; THolder Client_; THolder Tenants_; - TPortManager PortManager_; std::unordered_map ServerlessToShared_; std::optional AsyncQueryRunnerActorId_; From c94b2ebe613bc396a23432873400286cfc7f7ef1 Mon Sep 17 00:00:00 2001 From: vvvv Date: Tue, 8 Apr 2025 21:39:24 +0300 Subject: [PATCH 065/454] YQL-19747 keywords freq commit_hash:7de75454f7dc424a5ac1883b88418eecdaa261fd --- .../data/language/rules_corr_basic.json | 2 +- .../language/yql/test/canondata/result.json | 5 ++ .../test.test_ExtractKeywords_/results.txt | 78 +++++++++++++++++++ .../yql/test/cases/ExtractKeywords.sql | 6 ++ yql/essentials/udfs/language/yql/ya.make | 1 + .../udfs/language/yql/yql_language_udf.cpp | 8 ++ 6 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 yql/essentials/udfs/language/yql/test/canondata/test.test_ExtractKeywords_/results.txt create mode 100644 yql/essentials/udfs/language/yql/test/cases/ExtractKeywords.sql diff --git a/yql/essentials/data/language/rules_corr_basic.json b/yql/essentials/data/language/rules_corr_basic.json index 5f7c7b05c8ae..783c4e6825da 100644 --- a/yql/essentials/data/language/rules_corr_basic.json +++ b/yql/essentials/data/language/rules_corr_basic.json @@ -1 +1 @@ -[{"parent":"FUNC","rule":"ABC","sum":1},{"parent":"FUNC","rule":"ABS","sum":3232134},{"parent":"FUNC","rule":"ADAPTIVE_WARD_HISTOGRAM","sum":1},{"parent":"FUNC","rule":"ADDTIMEZONE","sum":397},{"parent":"FUNC","rule":"AGGLIST","sum":1226},{"parent":"FUNC","rule":"AGGList","sum":1},{"parent":"FUNC","rule":"AGGREATE_LIST","sum":2},{"parent":"FUNC","rule":"AGGREGATELIST","sum":72},{"parent":"FUNC","rule":"AGGREGATE_BY","sum":1581740},{"parent":"FUNC","rule":"AGGREGATE_LIST","sum":19716719},{"parent":"FUNC","rule":"AGGREGATE_LIST_","sum":2},{"parent":"FUNC","rule":"AGGREGATE_LIST_DISTINCT","sum":12799822},{"parent":"FUNC","rule":"AGGREGATE_LIST_DISTINCt","sum":2},{"parent":"FUNC","rule":"AGGREGATE_LIST_DISTNCT","sum":1},{"parent":"FUNC","rule":"AGGREGATE_LIST_DiSTINCT","sum":4},{"parent":"FUNC","rule":"AGGREGATE_LIST_Distinct","sum":782},{"parent":"FUNC","rule":"AGGREGATE_LIST_distINCT","sum":4},{"parent":"FUNC","rule":"AGGREGATE_LIST_distinct","sum":18918},{"parent":"FUNC","rule":"AGGREGATE_LISt","sum":6},{"parent":"FUNC","rule":"AGGREGATE_LiST","sum":106},{"parent":"FUNC","rule":"AGGREGATE_List","sum":75},{"parent":"FUNC","rule":"AGGREGATE_lIST","sum":59},{"parent":"FUNC","rule":"AGGREGATE_lIST_DISTINCT","sum":6},{"parent":"FUNC","rule":"AGGREGATE_liST_DISTINCT","sum":9},{"parent":"FUNC","rule":"AGGREGATE_list","sum":317},{"parent":"FUNC","rule":"AGGREGATE_list_distinct","sum":1},{"parent":"FUNC","rule":"AGGREGATIONFACTORY","sum":57},{"parent":"FUNC","rule":"AGGREGATION_FACTORY","sum":66704},{"parent":"FUNC","rule":"AGGREGate_List","sum":2},{"parent":"FUNC","rule":"AGGR_LIST","sum":2979},{"parent":"FUNC","rule":"AGGR_LIST_DISTINCT","sum":44423},{"parent":"FUNC","rule":"AGGReGATE_LIST","sum":3},{"parent":"FUNC","rule":"AGGReGate_list","sum":1},{"parent":"FUNC","rule":"AGG_LIST","sum":5134479},{"parent":"FUNC","rule":"AGG_LIST_","sum":5},{"parent":"FUNC","rule":"AGG_LIST_DISTINCT","sum":2873803},{"parent":"FUNC","rule":"AGG_LIST_DISTINCt","sum":9},{"parent":"FUNC","rule":"AGG_LIST_DIStiNCT","sum":10},{"parent":"FUNC","rule":"AGG_LIST_DiSTINCT","sum":4},{"parent":"FUNC","rule":"AGG_LIST_Distinct","sum":47},{"parent":"FUNC","rule":"AGG_LIST_distinct","sum":647},{"parent":"FUNC","rule":"AGG_LISt","sum":2},{"parent":"FUNC","rule":"AGG_LIst","sum":11},{"parent":"FUNC","rule":"AGG_LiST","sum":4},{"parent":"FUNC","rule":"AGG_LiST_DIStiNCT","sum":2},{"parent":"FUNC","rule":"AGG_List","sum":6695},{"parent":"FUNC","rule":"AGG_List_DISTINCT","sum":39},{"parent":"FUNC","rule":"AGG_List_Distinct","sum":917},{"parent":"FUNC","rule":"AGG_List_distinct","sum":103},{"parent":"FUNC","rule":"AGG_lIST_DISTINCT","sum":5},{"parent":"FUNC","rule":"AGG_list","sum":17486},{"parent":"FUNC","rule":"AGG_list_DISTINCT","sum":3060},{"parent":"FUNC","rule":"AGG_list_distinct","sum":787},{"parent":"FUNC","rule":"AGGrEGATE_LIST","sum":2},{"parent":"FUNC","rule":"AGGreGATE_LIST_DISTINCT","sum":3},{"parent":"FUNC","rule":"AGGregateList","sum":19},{"parent":"FUNC","rule":"AGGregate_LIST","sum":3},{"parent":"FUNC","rule":"AGGregate_LIST_DISTINCT","sum":1},{"parent":"FUNC","rule":"AGGregate_List_Distinct","sum":4},{"parent":"FUNC","rule":"AGGregate_list","sum":6},{"parent":"FUNC","rule":"AGGregate_list_distinct","sum":65},{"parent":"FUNC","rule":"AND","sum":46},{"parent":"FUNC","rule":"ARRAY_AGG","sum":2},{"parent":"FUNC","rule":"ASDICT","sum":194},{"parent":"FUNC","rule":"ASDict","sum":625},{"parent":"FUNC","rule":"ASEnum","sum":84},{"parent":"FUNC","rule":"ASIN","sum":2},{"parent":"FUNC","rule":"ASLIST","sum":27649},{"parent":"FUNC","rule":"ASLIst","sum":4},{"parent":"FUNC","rule":"ASList","sum":23452},{"parent":"FUNC","rule":"ASListStrict","sum":3},{"parent":"FUNC","rule":"ASSET","sum":17},{"parent":"FUNC","rule":"ASSTRUCT","sum":2713},{"parent":"FUNC","rule":"ASSet","sum":5},{"parent":"FUNC","rule":"ASStruct","sum":2337},{"parent":"FUNC","rule":"ASTAGGED","sum":15},{"parent":"FUNC","rule":"ASTAgged","sum":3},{"parent":"FUNC","rule":"ASTUPLE","sum":1583},{"parent":"FUNC","rule":"ASTagged","sum":63},{"parent":"FUNC","rule":"ASTuple","sum":5821},{"parent":"FUNC","rule":"AS_DICT","sum":6},{"parent":"FUNC","rule":"AS_LIST","sum":130},{"parent":"FUNC","rule":"AS_STRUCT","sum":13398},{"parent":"FUNC","rule":"AS_TABLE","sum":33},{"parent":"FUNC","rule":"AS_TUPLE","sum":850},{"parent":"FUNC","rule":"ASdict","sum":4},{"parent":"FUNC","rule":"ASlist","sum":1025},{"parent":"FUNC","rule":"ASstruct","sum":41},{"parent":"FUNC","rule":"AStagged","sum":3},{"parent":"FUNC","rule":"AStuple","sum":406},{"parent":"FUNC","rule":"AVG","sum":9095867},{"parent":"FUNC","rule":"AVGIF","sum":15},{"parent":"FUNC","rule":"AVG_IF","sum":732975},{"parent":"FUNC","rule":"AVG_If","sum":8},{"parent":"FUNC","rule":"AVG_if","sum":14339},{"parent":"FUNC","rule":"AVg","sum":4},{"parent":"FUNC","rule":"Abs","sum":323222},{"parent":"FUNC","rule":"AdaptiveDistanceHistogramCDF","sum":1},{"parent":"FUNC","rule":"AdaptiveWardHistogram","sum":1},{"parent":"FUNC","rule":"AdaptiveWardHistogramCDF","sum":3},{"parent":"FUNC","rule":"AdaptiveWeightHistogram","sum":57407},{"parent":"FUNC","rule":"AddMember","sum":881712},{"parent":"FUNC","rule":"AddTimeZone","sum":515639},{"parent":"FUNC","rule":"AddTimezone","sum":12049138},{"parent":"FUNC","rule":"Addtimezone","sum":60},{"parent":"FUNC","rule":"AggLIst","sum":1},{"parent":"FUNC","rule":"AggList","sum":20182},{"parent":"FUNC","rule":"AggListDistinct","sum":77},{"parent":"FUNC","rule":"Agg_LIST","sum":60},{"parent":"FUNC","rule":"Agg_LIST_DISTINCT","sum":22},{"parent":"FUNC","rule":"Agg_LIST_Distinct","sum":1},{"parent":"FUNC","rule":"Agg_LIst","sum":2},{"parent":"FUNC","rule":"Agg_LiSt","sum":3},{"parent":"FUNC","rule":"Agg_List","sum":129430},{"parent":"FUNC","rule":"Agg_List_","sum":8},{"parent":"FUNC","rule":"Agg_List_DISTINCT","sum":732},{"parent":"FUNC","rule":"Agg_List_Distinct","sum":2498},{"parent":"FUNC","rule":"Agg_List_distinct","sum":4},{"parent":"FUNC","rule":"Agg_list","sum":35635},{"parent":"FUNC","rule":"Agg_list_distinct","sum":8131},{"parent":"FUNC","rule":"Aggergate_List","sum":1},{"parent":"FUNC","rule":"Agglist","sum":93},{"parent":"FUNC","rule":"AggrList","sum":13},{"parent":"FUNC","rule":"Aggr_List","sum":1},{"parent":"FUNC","rule":"AggreGate_List","sum":6},{"parent":"FUNC","rule":"AggregateBy","sum":42285},{"parent":"FUNC","rule":"AggregateFlatten","sum":52398},{"parent":"FUNC","rule":"AggregateList","sum":40590},{"parent":"FUNC","rule":"AggregateListDistinct","sum":7692},{"parent":"FUNC","rule":"AggregateTransformInput","sum":25485},{"parent":"FUNC","rule":"AggregateTransformOutput","sum":44900},{"parent":"FUNC","rule":"Aggregate_BY","sum":241},{"parent":"FUNC","rule":"Aggregate_By","sum":136915},{"parent":"FUNC","rule":"Aggregate_LIST","sum":852},{"parent":"FUNC","rule":"Aggregate_LIST_DISTINCT","sum":2},{"parent":"FUNC","rule":"Aggregate_LIst","sum":1},{"parent":"FUNC","rule":"Aggregate_List","sum":345267},{"parent":"FUNC","rule":"Aggregate_List_Distinct","sum":5221},{"parent":"FUNC","rule":"Aggregate_List_distinct","sum":1312},{"parent":"FUNC","rule":"Aggregate_by","sum":79},{"parent":"FUNC","rule":"Aggregate_list","sum":228827},{"parent":"FUNC","rule":"Aggregate_list_DISTINCT","sum":36},{"parent":"FUNC","rule":"Aggregate_list_Distinct","sum":11},{"parent":"FUNC","rule":"Aggregate_list_distinct","sum":201741},{"parent":"FUNC","rule":"AggregationFactory","sum":1511775},{"parent":"FUNC","rule":"Apply","sum":1},{"parent":"FUNC","rule":"AsAtom","sum":687771},{"parent":"FUNC","rule":"AsDict","sum":2926107},{"parent":"FUNC","rule":"AsDictStrict","sum":4464},{"parent":"FUNC","rule":"AsEnum","sum":50920},{"parent":"FUNC","rule":"AsLIST","sum":917},{"parent":"FUNC","rule":"AsLIst","sum":2758},{"parent":"FUNC","rule":"AsLisT","sum":1503},{"parent":"FUNC","rule":"AsList","sum":17319174},{"parent":"FUNC","rule":"AsListStrict","sum":86350},{"parent":"FUNC","rule":"AsListstrict","sum":1},{"parent":"FUNC","rule":"AsSTruct","sum":374},{"parent":"FUNC","rule":"AsSet","sum":1593946},{"parent":"FUNC","rule":"AsSetStrict","sum":11367},{"parent":"FUNC","rule":"AsStruct","sum":23521151},{"parent":"FUNC","rule":"AsTAgged","sum":271},{"parent":"FUNC","rule":"AsTUPLE","sum":448},{"parent":"FUNC","rule":"AsTUple","sum":270},{"parent":"FUNC","rule":"AsTable","sum":6},{"parent":"FUNC","rule":"AsTaggeD","sum":4},{"parent":"FUNC","rule":"AsTagged","sum":183477},{"parent":"FUNC","rule":"AsTuPle","sum":1},{"parent":"FUNC","rule":"AsTuple","sum":30262710},{"parent":"FUNC","rule":"AsTupleunwrap","sum":4},{"parent":"FUNC","rule":"AsVariant","sum":357237},{"parent":"FUNC","rule":"As_List","sum":6},{"parent":"FUNC","rule":"As_Struct","sum":6},{"parent":"FUNC","rule":"As_list","sum":20},{"parent":"FUNC","rule":"As_tuple","sum":805},{"parent":"FUNC","rule":"Asdict","sum":182},{"parent":"FUNC","rule":"AslIst","sum":14},{"parent":"FUNC","rule":"Aslist","sum":23613},{"parent":"FUNC","rule":"Asset","sum":49},{"parent":"FUNC","rule":"Asstruct","sum":413},{"parent":"FUNC","rule":"AssumeStrict","sum":2600},{"parent":"FUNC","rule":"Astagged","sum":166},{"parent":"FUNC","rule":"Astuple","sum":748},{"parent":"FUNC","rule":"AtomCode","sum":522566},{"parent":"FUNC","rule":"Avg","sum":139250},{"parent":"FUNC","rule":"Avg_IF","sum":162},{"parent":"FUNC","rule":"Avg_If","sum":126},{"parent":"FUNC","rule":"Avg_if","sum":223},{"parent":"FUNC","rule":"BIT_AND","sum":4},{"parent":"FUNC","rule":"BIT_OR","sum":38693},{"parent":"FUNC","rule":"BIT_XOR","sum":435623},{"parent":"FUNC","rule":"BOOL_AND","sum":266061},{"parent":"FUNC","rule":"BOOL_OR","sum":878969},{"parent":"FUNC","rule":"BOOL_XOR","sum":46},{"parent":"FUNC","rule":"BOOL_and","sum":2},{"parent":"FUNC","rule":"BOOl_OR","sum":380},{"parent":"FUNC","rule":"BOTTOM","sum":11612},{"parent":"FUNC","rule":"BOTTOM_BY","sum":47377},{"parent":"FUNC","rule":"BOTTOM_by","sum":2},{"parent":"FUNC","rule":"Bool","sum":1391},{"parent":"FUNC","rule":"Bool_And","sum":118},{"parent":"FUNC","rule":"Bool_Or","sum":585},{"parent":"FUNC","rule":"Bool_and","sum":85},{"parent":"FUNC","rule":"Bool_or","sum":820},{"parent":"FUNC","rule":"Bottom","sum":278},{"parent":"FUNC","rule":"Bottom_BY","sum":10},{"parent":"FUNC","rule":"Bottom_By","sum":101},{"parent":"FUNC","rule":"Bottom_by","sum":1648},{"parent":"FUNC","rule":"ByteAt","sum":14153},{"parent":"FUNC","rule":"Bytes","sum":5},{"parent":"FUNC","rule":"CHAR_LENGTH","sum":373},{"parent":"FUNC","rule":"COALECSE","sum":1},{"parent":"FUNC","rule":"COALESCE","sum":51725079},{"parent":"FUNC","rule":"COALESCe","sum":10},{"parent":"FUNC","rule":"COALESce","sum":8},{"parent":"FUNC","rule":"COALEsCE","sum":1},{"parent":"FUNC","rule":"COALEsce","sum":4},{"parent":"FUNC","rule":"COALeSCE","sum":1},{"parent":"FUNC","rule":"COALesce","sum":14},{"parent":"FUNC","rule":"COAlESCE","sum":2731},{"parent":"FUNC","rule":"COAlesce","sum":12},{"parent":"FUNC","rule":"CONCAT","sum":19},{"parent":"FUNC","rule":"COOUNT","sum":2},{"parent":"FUNC","rule":"CORR","sum":430},{"parent":"FUNC","rule":"CORRELATION","sum":20939},{"parent":"FUNC","rule":"COS","sum":4},{"parent":"FUNC","rule":"COUNT","sum":52772805},{"parent":"FUNC","rule":"COUNTD","sum":4},{"parent":"FUNC","rule":"COUNTDISTINCTESTIMATE","sum":609},{"parent":"FUNC","rule":"COUNTDistinctEstimate","sum":7},{"parent":"FUNC","rule":"COUNTIF","sum":15625},{"parent":"FUNC","rule":"COUNT_","sum":1},{"parent":"FUNC","rule":"COUNT_IF","sum":24112936},{"parent":"FUNC","rule":"COUNT_IF_","sum":24},{"parent":"FUNC","rule":"COUNT_If","sum":12952},{"parent":"FUNC","rule":"COUNT_iF","sum":44},{"parent":"FUNC","rule":"COUNT_if","sum":19513},{"parent":"FUNC","rule":"COUNt","sum":1261},{"parent":"FUNC","rule":"COUNt_IF","sum":24},{"parent":"FUNC","rule":"COUNt_If","sum":3},{"parent":"FUNC","rule":"COUNt_if","sum":11},{"parent":"FUNC","rule":"COUnT","sum":9},{"parent":"FUNC","rule":"COUnT_IF","sum":7},{"parent":"FUNC","rule":"COUnt","sum":40},{"parent":"FUNC","rule":"COVAR","sum":2852},{"parent":"FUNC","rule":"COVARIANCE","sum":1525},{"parent":"FUNC","rule":"COVARIANCE_POPULATION","sum":64},{"parent":"FUNC","rule":"COVARIANCE_SAMPLE","sum":4},{"parent":"FUNC","rule":"COVAR_POP","sum":4},{"parent":"FUNC","rule":"COalesce","sum":22},{"parent":"FUNC","rule":"COuNT","sum":64},{"parent":"FUNC","rule":"COuNT_If","sum":1},{"parent":"FUNC","rule":"COunt","sum":187},{"parent":"FUNC","rule":"COunt_IF","sum":57},{"parent":"FUNC","rule":"COunt_If","sum":2},{"parent":"FUNC","rule":"COunt_iF","sum":1},{"parent":"FUNC","rule":"COunt_if","sum":3},{"parent":"FUNC","rule":"CUME_DIST","sum":109},{"parent":"FUNC","rule":"CURRENTUTCDATE","sum":5408},{"parent":"FUNC","rule":"CURRENTUTCDATETIME","sum":6625},{"parent":"FUNC","rule":"CURRENTUTCDate","sum":89},{"parent":"FUNC","rule":"CURRENT_UTC_DATE","sum":8},{"parent":"FUNC","rule":"CUrrentUTCDate","sum":1},{"parent":"FUNC","rule":"CallableArgument","sum":10209},{"parent":"FUNC","rule":"CallableArgumentType","sum":19040},{"parent":"FUNC","rule":"CallableResultType","sum":117},{"parent":"FUNC","rule":"CallableType","sum":179745},{"parent":"FUNC","rule":"CallableTypeHandle","sum":5746},{"parent":"FUNC","rule":"Ceil","sum":3},{"parent":"FUNC","rule":"ChooseMembers","sum":2491929},{"parent":"FUNC","rule":"Choosemembers","sum":21065},{"parent":"FUNC","rule":"ChosenMembers","sum":8},{"parent":"FUNC","rule":"ClearBit","sum":30103},{"parent":"FUNC","rule":"CoALESCE","sum":1},{"parent":"FUNC","rule":"CoUNT","sum":35},{"parent":"FUNC","rule":"CoUNT_IF","sum":17},{"parent":"FUNC","rule":"CoUNt","sum":2},{"parent":"FUNC","rule":"CoUnt","sum":2},{"parent":"FUNC","rule":"Coalesce","sum":725779},{"parent":"FUNC","rule":"Collect","sum":1},{"parent":"FUNC","rule":"CollectList","sum":1},{"parent":"FUNC","rule":"CombineMembers","sum":506545},{"parent":"FUNC","rule":"Concat","sum":1},{"parent":"FUNC","rule":"Correlation","sum":180},{"parent":"FUNC","rule":"CouNT","sum":2},{"parent":"FUNC","rule":"CounT","sum":17},{"parent":"FUNC","rule":"Count","sum":395770},{"parent":"FUNC","rule":"CountDistinctEstimate","sum":157394},{"parent":"FUNC","rule":"CountIF","sum":81},{"parent":"FUNC","rule":"CountIf","sum":511},{"parent":"FUNC","rule":"Count_IF","sum":15818},{"parent":"FUNC","rule":"Count_If","sum":42501},{"parent":"FUNC","rule":"Count_if","sum":323427},{"parent":"FUNC","rule":"Countif","sum":12},{"parent":"FUNC","rule":"CurrentAuthenticatedUser","sum":90263},{"parent":"FUNC","rule":"CurrentDatetime","sum":1},{"parent":"FUNC","rule":"CurrentOperationId","sum":89788},{"parent":"FUNC","rule":"CurrentOperationSharedId","sum":5682},{"parent":"FUNC","rule":"CurrentTZDate","sum":598},{"parent":"FUNC","rule":"CurrentTZDateTime","sum":35},{"parent":"FUNC","rule":"CurrentTZDatetime","sum":525},{"parent":"FUNC","rule":"CurrentTZTimestamp","sum":245},{"parent":"FUNC","rule":"CurrentTZdatetime","sum":68},{"parent":"FUNC","rule":"CurrentTzDate","sum":1610877},{"parent":"FUNC","rule":"CurrentTzDateTime","sum":1466274},{"parent":"FUNC","rule":"CurrentTzDatetime","sum":1992182},{"parent":"FUNC","rule":"CurrentTzTimeStamp","sum":4338},{"parent":"FUNC","rule":"CurrentTzTimestamp","sum":1901822},{"parent":"FUNC","rule":"CurrentUTCDATE","sum":19},{"parent":"FUNC","rule":"CurrentUTCDAte","sum":38},{"parent":"FUNC","rule":"CurrentUTCDate","sum":919319},{"parent":"FUNC","rule":"CurrentUTCDateTime","sum":182570},{"parent":"FUNC","rule":"CurrentUTCDatetime","sum":131224},{"parent":"FUNC","rule":"CurrentUTCTimeStamp","sum":99},{"parent":"FUNC","rule":"CurrentUTCTimestamp","sum":452539},{"parent":"FUNC","rule":"CurrentUTCdate","sum":71296},{"parent":"FUNC","rule":"CurrentUTcDate","sum":68},{"parent":"FUNC","rule":"CurrentUtCDate","sum":5},{"parent":"FUNC","rule":"CurrentUtCDatetime","sum":3},{"parent":"FUNC","rule":"CurrentUtcDATE","sum":2},{"parent":"FUNC","rule":"CurrentUtcDAte","sum":3},{"parent":"FUNC","rule":"CurrentUtcDatE","sum":1},{"parent":"FUNC","rule":"CurrentUtcDate","sum":19616023},{"parent":"FUNC","rule":"CurrentUtcDateTIME","sum":1},{"parent":"FUNC","rule":"CurrentUtcDateTime","sum":3198884},{"parent":"FUNC","rule":"CurrentUtcDatetime","sum":13800051},{"parent":"FUNC","rule":"CurrentUtcDttm","sum":3},{"parent":"FUNC","rule":"CurrentUtcTimeStamp","sum":60207},{"parent":"FUNC","rule":"CurrentUtcTimestamp","sum":15289791},{"parent":"FUNC","rule":"CurrentUtcdate","sum":11626},{"parent":"FUNC","rule":"CurrenttzDate","sum":340},{"parent":"FUNC","rule":"CurrenttzDatetime","sum":1},{"parent":"FUNC","rule":"CurrentutcDate","sum":21001},{"parent":"FUNC","rule":"CurrentutcDateTime","sum":578},{"parent":"FUNC","rule":"CurrentutcTimestamp","sum":4},{"parent":"FUNC","rule":"Currentutcdate","sum":1508},{"parent":"FUNC","rule":"Currentutcdatetime","sum":22646},{"parent":"FUNC","rule":"D","sum":1},{"parent":"FUNC","rule":"DATE","sum":128519},{"parent":"FUNC","rule":"DATEADD","sum":3},{"parent":"FUNC","rule":"DATEDIFF","sum":9},{"parent":"FUNC","rule":"DATETIME","sum":830},{"parent":"FUNC","rule":"DATE_PART","sum":16},{"parent":"FUNC","rule":"DATE_TRUNC","sum":29},{"parent":"FUNC","rule":"DATe","sum":20},{"parent":"FUNC","rule":"DAte","sum":175},{"parent":"FUNC","rule":"DAtetime","sum":61},{"parent":"FUNC","rule":"DENSE_RANK","sum":274243},{"parent":"FUNC","rule":"DICTKEYS","sum":27},{"parent":"FUNC","rule":"DICTLENGTH","sum":4},{"parent":"FUNC","rule":"DICTLength","sum":2},{"parent":"FUNC","rule":"DICTPAYLOADS","sum":2},{"parent":"FUNC","rule":"DICT_CONTAINS","sum":5},{"parent":"FUNC","rule":"DIctHasItems","sum":1},{"parent":"FUNC","rule":"DIctItems","sum":1},{"parent":"FUNC","rule":"DIctKeys","sum":1},{"parent":"FUNC","rule":"DIctLength","sum":1},{"parent":"FUNC","rule":"DIctLookup","sum":16},{"parent":"FUNC","rule":"DOUBLE","sum":63},{"parent":"FUNC","rule":"DatE","sum":3},{"parent":"FUNC","rule":"DataType","sum":69092},{"parent":"FUNC","rule":"DataTypeComponents","sum":37173},{"parent":"FUNC","rule":"DataTypeHandle","sum":2},{"parent":"FUNC","rule":"Datatype","sum":2},{"parent":"FUNC","rule":"Date","sum":1771862},{"parent":"FUNC","rule":"Date32","sum":74},{"parent":"FUNC","rule":"DateTime","sum":435337},{"parent":"FUNC","rule":"DateTime64","sum":45},{"parent":"FUNC","rule":"Date_Diff","sum":1},{"parent":"FUNC","rule":"DatetimE","sum":8},{"parent":"FUNC","rule":"Datetime","sum":273226},{"parent":"FUNC","rule":"Datetime64","sum":6},{"parent":"FUNC","rule":"Decimal","sum":31325},{"parent":"FUNC","rule":"DenseRank","sum":27},{"parent":"FUNC","rule":"Dense_RANK","sum":1},{"parent":"FUNC","rule":"Dense_Rank","sum":55},{"parent":"FUNC","rule":"Dense_rank","sum":6},{"parent":"FUNC","rule":"DicTKeys","sum":2},{"parent":"FUNC","rule":"DictAggregate","sum":140548},{"parent":"FUNC","rule":"DictCOntains","sum":350},{"parent":"FUNC","rule":"DictContains","sum":2022972},{"parent":"FUNC","rule":"DictCreate","sum":69385},{"parent":"FUNC","rule":"DictHasItems","sum":614255},{"parent":"FUNC","rule":"DictHasitems","sum":261},{"parent":"FUNC","rule":"DictItems","sum":2553332},{"parent":"FUNC","rule":"DictKEYS","sum":12},{"parent":"FUNC","rule":"DictKEys","sum":1},{"parent":"FUNC","rule":"DictKeYS","sum":3},{"parent":"FUNC","rule":"DictKeyType","sum":941},{"parent":"FUNC","rule":"DictKeys","sum":2716126},{"parent":"FUNC","rule":"DictLOokup","sum":7},{"parent":"FUNC","rule":"DictLength","sum":1016614},{"parent":"FUNC","rule":"DictLookUP","sum":3},{"parent":"FUNC","rule":"DictLookUp","sum":59775},{"parent":"FUNC","rule":"DictLookup","sum":5979602},{"parent":"FUNC","rule":"DictPayLoads","sum":10372},{"parent":"FUNC","rule":"DictPayloadType","sum":210},{"parent":"FUNC","rule":"DictPayloads","sum":927148},{"parent":"FUNC","rule":"DictType","sum":540},{"parent":"FUNC","rule":"DictTypeComponents","sum":3},{"parent":"FUNC","rule":"DictTypeHandle","sum":1},{"parent":"FUNC","rule":"DictValues","sum":5},{"parent":"FUNC","rule":"Dict_Keys","sum":12},{"parent":"FUNC","rule":"Dictcontains","sum":7},{"parent":"FUNC","rule":"Dictitems","sum":19810},{"parent":"FUNC","rule":"Dictkeys","sum":1131},{"parent":"FUNC","rule":"Dictlength","sum":6},{"parent":"FUNC","rule":"Dictlookup","sum":76091},{"parent":"FUNC","rule":"Double","sum":34054},{"parent":"FUNC","rule":"DyNumber","sum":4},{"parent":"FUNC","rule":"EACH","sum":4},{"parent":"FUNC","rule":"ENDSWITH","sum":13704},{"parent":"FUNC","rule":"ENDsWith","sum":85},{"parent":"FUNC","rule":"ENSURE","sum":832413},{"parent":"FUNC","rule":"EOMONTH","sum":1},{"parent":"FUNC","rule":"EmptyDict","sum":433},{"parent":"FUNC","rule":"EmptyDictTypeHandle","sum":3},{"parent":"FUNC","rule":"EmptyList","sum":23826},{"parent":"FUNC","rule":"Emptydict","sum":6},{"parent":"FUNC","rule":"EndsWIth","sum":870},{"parent":"FUNC","rule":"EndsWith","sum":1567383},{"parent":"FUNC","rule":"Endswith","sum":19803},{"parent":"FUNC","rule":"Ensure","sum":1435372},{"parent":"FUNC","rule":"EnsureConvertibleTo","sum":2021},{"parent":"FUNC","rule":"EnsureType","sum":229224},{"parent":"FUNC","rule":"EvaluateAtom","sum":457},{"parent":"FUNC","rule":"EvaluateCode","sum":467121},{"parent":"FUNC","rule":"EvaluateExpr","sum":899979},{"parent":"FUNC","rule":"EvaluateType","sum":122201},{"parent":"FUNC","rule":"ExpandStruct","sum":265234},{"parent":"FUNC","rule":"ExtractUkropCtx","sum":1},{"parent":"FUNC","rule":"FIND","sum":5572833},{"parent":"FUNC","rule":"FIRST","sum":3},{"parent":"FUNC","rule":"FIRST_VALUE","sum":8906702},{"parent":"FUNC","rule":"FIRST_value","sum":815},{"parent":"FUNC","rule":"FIRsT_VALUE","sum":1},{"parent":"FUNC","rule":"FIleContent","sum":1},{"parent":"FUNC","rule":"FLATTEN","sum":9},{"parent":"FUNC","rule":"FLOAT","sum":5},{"parent":"FUNC","rule":"FLOOR","sum":1},{"parent":"FUNC","rule":"FORMATTYPE","sum":1},{"parent":"FUNC","rule":"FROMBYTES","sum":5},{"parent":"FUNC","rule":"FROmbytes","sum":4},{"parent":"FUNC","rule":"FileCOntent","sum":35},{"parent":"FUNC","rule":"FileContent","sum":2368603},{"parent":"FUNC","rule":"FilePath","sum":1452555},{"parent":"FUNC","rule":"Filecontent","sum":11773},{"parent":"FUNC","rule":"Filepath","sum":10},{"parent":"FUNC","rule":"FinD","sum":16},{"parent":"FUNC","rule":"Find","sum":321055},{"parent":"FUNC","rule":"FirsT_VALUE","sum":3},{"parent":"FUNC","rule":"FirstValue","sum":22},{"parent":"FUNC","rule":"First_VALUE","sum":12},{"parent":"FUNC","rule":"First_Value","sum":28},{"parent":"FUNC","rule":"First_value","sum":180},{"parent":"FUNC","rule":"FlattenMembers","sum":109273},{"parent":"FUNC","rule":"Float","sum":12377},{"parent":"FUNC","rule":"FoldMap","sum":13},{"parent":"FUNC","rule":"Folder","sum":13},{"parent":"FUNC","rule":"FolderPath","sum":9943},{"parent":"FUNC","rule":"ForceRemoveMember","sum":401887},{"parent":"FUNC","rule":"ForceRemoveMembers","sum":1082517},{"parent":"FUNC","rule":"ForceRenameMembers","sum":63996},{"parent":"FUNC","rule":"ForceSpreadMembers","sum":115431},{"parent":"FUNC","rule":"ForceSpreadmembers","sum":4},{"parent":"FUNC","rule":"Format","sum":1},{"parent":"FUNC","rule":"FormatCode","sum":675},{"parent":"FUNC","rule":"FormatType","sum":467449},{"parent":"FUNC","rule":"FormatTypeDiff","sum":813},{"parent":"FUNC","rule":"FormatTypeDiffPretty","sum":103},{"parent":"FUNC","rule":"Formattype","sum":101},{"parent":"FUNC","rule":"FromBytes","sum":99297},{"parent":"FUNC","rule":"FromPg","sum":4861},{"parent":"FUNC","rule":"FromYsonSimpleType","sum":1},{"parent":"FUNC","rule":"From_bytes","sum":1},{"parent":"FUNC","rule":"FromatType","sum":1},{"parent":"FUNC","rule":"Frombytes","sum":12},{"parent":"FUNC","rule":"FuncCode","sum":1239380},{"parent":"FUNC","rule":"GETDATE","sum":1},{"parent":"FUNC","rule":"GREATEST","sum":389805},{"parent":"FUNC","rule":"GROUPING","sum":71574},{"parent":"FUNC","rule":"GROUPINg","sum":4},{"parent":"FUNC","rule":"GROUP_CONCAT","sum":1},{"parent":"FUNC","rule":"GatherMembers","sum":1478901},{"parent":"FUNC","rule":"Gather_Members","sum":38},{"parent":"FUNC","rule":"Gathermembers","sum":8},{"parent":"FUNC","rule":"GetLength","sum":2},{"parent":"FUNC","rule":"GetWeekOfYear","sum":1},{"parent":"FUNC","rule":"Greatest","sum":6034},{"parent":"FUNC","rule":"Grouping","sum":243},{"parent":"FUNC","rule":"HISTOGRAM","sum":274200},{"parent":"FUNC","rule":"HISTOGRAMCDF","sum":421},{"parent":"FUNC","rule":"HISTOGRAMCdf","sum":47},{"parent":"FUNC","rule":"HISTOGRAM_CDF","sum":3},{"parent":"FUNC","rule":"HISTOGRAMcdf","sum":2},{"parent":"FUNC","rule":"HISTOGrAM","sum":48},{"parent":"FUNC","rule":"HISTOgram","sum":1},{"parent":"FUNC","rule":"HISToGRAM","sum":1},{"parent":"FUNC","rule":"HISTogram","sum":1},{"parent":"FUNC","rule":"HIStOGRAM","sum":1},{"parent":"FUNC","rule":"HIstogram","sum":34},{"parent":"FUNC","rule":"HLL","sum":12390},{"parent":"FUNC","rule":"HOP_END","sum":16},{"parent":"FUNC","rule":"HOP_START","sum":4},{"parent":"FUNC","rule":"Histogram","sum":34999},{"parent":"FUNC","rule":"HistogramCDF","sum":411},{"parent":"FUNC","rule":"HistogramCdf","sum":34},{"parent":"FUNC","rule":"Histogram_CDF","sum":57},{"parent":"FUNC","rule":"Histogramcdf","sum":1},{"parent":"FUNC","rule":"Hll","sum":1915},{"parent":"FUNC","rule":"HyperLogLog","sum":3996},{"parent":"FUNC","rule":"IF","sum":75354920},{"parent":"FUNC","rule":"IFNULL","sum":9},{"parent":"FUNC","rule":"IF_STRICT","sum":1},{"parent":"FUNC","rule":"IN","sum":2},{"parent":"FUNC","rule":"INT","sum":16},{"parent":"FUNC","rule":"INT32","sum":1},{"parent":"FUNC","rule":"INTERVAL","sum":889659},{"parent":"FUNC","rule":"INterval","sum":763},{"parent":"FUNC","rule":"If","sum":1086681},{"parent":"FUNC","rule":"IfNull","sum":6},{"parent":"FUNC","rule":"InstanceOf","sum":248429},{"parent":"FUNC","rule":"Int","sum":1},{"parent":"FUNC","rule":"Int16","sum":37},{"parent":"FUNC","rule":"Int32","sum":32595},{"parent":"FUNC","rule":"Int64","sum":3638},{"parent":"FUNC","rule":"Int8","sum":302},{"parent":"FUNC","rule":"InterVal","sum":4},{"parent":"FUNC","rule":"Interva","sum":1},{"parent":"FUNC","rule":"Interval","sum":16057580},{"parent":"FUNC","rule":"Interval64","sum":2},{"parent":"FUNC","rule":"IntervalFromDays","sum":8},{"parent":"FUNC","rule":"IsInt64","sum":1},{"parent":"FUNC","rule":"JSON","sum":68},{"parent":"FUNC","rule":"JUST","sum":128278},{"parent":"FUNC","rule":"Join","sum":1},{"parent":"FUNC","rule":"JoinTableRow","sum":1312193},{"parent":"FUNC","rule":"JoinTablerow","sum":721},{"parent":"FUNC","rule":"JointableRow","sum":1},{"parent":"FUNC","rule":"Json","sum":53211},{"parent":"FUNC","rule":"JsonDocument","sum":9},{"parent":"FUNC","rule":"Just","sum":6562961},{"parent":"FUNC","rule":"LAG","sum":4042269},{"parent":"FUNC","rule":"LAST","sum":1},{"parent":"FUNC","rule":"LAST_VALUE","sum":1339900},{"parent":"FUNC","rule":"LAST_value","sum":2},{"parent":"FUNC","rule":"LEAD","sum":1652252},{"parent":"FUNC","rule":"LEAST","sum":427318},{"parent":"FUNC","rule":"LEFT","sum":3},{"parent":"FUNC","rule":"LEFT_SHIFT","sum":1},{"parent":"FUNC","rule":"LEN","sum":1687004},{"parent":"FUNC","rule":"LENGTH","sum":3846912},{"parent":"FUNC","rule":"LENgth","sum":23},{"parent":"FUNC","rule":"LEngth","sum":12},{"parent":"FUNC","rule":"LIKELY","sum":140878},{"parent":"FUNC","rule":"LINEARHISTOGRAM","sum":374},{"parent":"FUNC","rule":"LINEARHISTOGRAMCDF","sum":1},{"parent":"FUNC","rule":"LINEARHistogram","sum":3},{"parent":"FUNC","rule":"LINEAR_HISTOGRAM","sum":13},{"parent":"FUNC","rule":"LISTALL","sum":2891},{"parent":"FUNC","rule":"LISTANY","sum":102},{"parent":"FUNC","rule":"LISTAVG","sum":25},{"parent":"FUNC","rule":"LISTAny","sum":10},{"parent":"FUNC","rule":"LISTCOLLECT","sum":1},{"parent":"FUNC","rule":"LISTCONCAT","sum":1517},{"parent":"FUNC","rule":"LISTENUMERATE","sum":3},{"parent":"FUNC","rule":"LISTEXTEND","sum":13},{"parent":"FUNC","rule":"LISTFILTER","sum":1629},{"parent":"FUNC","rule":"LISTFLATTEN","sum":4265},{"parent":"FUNC","rule":"LISTFROMRANGE","sum":1494},{"parent":"FUNC","rule":"LISTHAS","sum":30992},{"parent":"FUNC","rule":"LISTHASITEMS","sum":2099},{"parent":"FUNC","rule":"LISTHASItems","sum":1},{"parent":"FUNC","rule":"LISTHEAD","sum":18199},{"parent":"FUNC","rule":"LISTHas","sum":9},{"parent":"FUNC","rule":"LISTHead","sum":2},{"parent":"FUNC","rule":"LISTLAST","sum":1556},{"parent":"FUNC","rule":"LISTLENGTH","sum":48153},{"parent":"FUNC","rule":"LISTLENGth","sum":4},{"parent":"FUNC","rule":"LISTLenGTH","sum":7},{"parent":"FUNC","rule":"LISTLength","sum":2125},{"parent":"FUNC","rule":"LISTMAP","sum":14266},{"parent":"FUNC","rule":"LISTMAX","sum":6952},{"parent":"FUNC","rule":"LISTMIN","sum":187},{"parent":"FUNC","rule":"LISTMap","sum":365},{"parent":"FUNC","rule":"LISTNOTNULL","sum":8554},{"parent":"FUNC","rule":"LISTREVERSE","sum":2},{"parent":"FUNC","rule":"LISTSKIP","sum":15},{"parent":"FUNC","rule":"LISTSORT","sum":7614},{"parent":"FUNC","rule":"LISTSORTASC","sum":1665},{"parent":"FUNC","rule":"LISTSORTDESC","sum":109},{"parent":"FUNC","rule":"LISTSUM","sum":175},{"parent":"FUNC","rule":"LISTSort","sum":19},{"parent":"FUNC","rule":"LISTSum","sum":6},{"parent":"FUNC","rule":"LISTTAKE","sum":261},{"parent":"FUNC","rule":"LISTUNIQ","sum":596},{"parent":"FUNC","rule":"LISTUniq","sum":26},{"parent":"FUNC","rule":"LISTZIP","sum":261},{"parent":"FUNC","rule":"LISTZIPALL","sum":290},{"parent":"FUNC","rule":"LIST_AGGREGATE","sum":1},{"parent":"FUNC","rule":"LIST_ALL","sum":1},{"parent":"FUNC","rule":"LIST_ANY","sum":7},{"parent":"FUNC","rule":"LIST_CONCAT","sum":18},{"parent":"FUNC","rule":"LIST_EXTEND","sum":1},{"parent":"FUNC","rule":"LIST_EXTRACT","sum":73},{"parent":"FUNC","rule":"LIST_FOLD","sum":30},{"parent":"FUNC","rule":"LIST_FROM_RANGE","sum":352},{"parent":"FUNC","rule":"LIST_HAS","sum":2042},{"parent":"FUNC","rule":"LIST_HEAD","sum":100},{"parent":"FUNC","rule":"LIST_LAST","sum":54},{"parent":"FUNC","rule":"LIST_LENGTH","sum":2455},{"parent":"FUNC","rule":"LIST_Length","sum":1},{"parent":"FUNC","rule":"LIST_MAP","sum":9},{"parent":"FUNC","rule":"LIST_MAX","sum":285},{"parent":"FUNC","rule":"LIST_SORT","sum":624},{"parent":"FUNC","rule":"LIST_SORT_DESC","sum":14},{"parent":"FUNC","rule":"LIST_SUM","sum":2},{"parent":"FUNC","rule":"LIST_TAKE","sum":2},{"parent":"FUNC","rule":"LIST_UNIQ","sum":344},{"parent":"FUNC","rule":"LIST_length","sum":1},{"parent":"FUNC","rule":"LISTfilter","sum":7},{"parent":"FUNC","rule":"LISTfromRange","sum":1420},{"parent":"FUNC","rule":"LISTfromrange","sum":3},{"parent":"FUNC","rule":"LISThas","sum":2},{"parent":"FUNC","rule":"LISTnotNull","sum":2},{"parent":"FUNC","rule":"LIStExtend","sum":3},{"parent":"FUNC","rule":"LIStHas","sum":2},{"parent":"FUNC","rule":"LIStLENGth","sum":1},{"parent":"FUNC","rule":"LIStLength","sum":1},{"parent":"FUNC","rule":"LIStmap","sum":1},{"parent":"FUNC","rule":"LIstConcat","sum":303},{"parent":"FUNC","rule":"LIstExtend","sum":3},{"parent":"FUNC","rule":"LIstFilter","sum":71},{"parent":"FUNC","rule":"LIstFromRange","sum":8},{"parent":"FUNC","rule":"LIstFromrange","sum":1},{"parent":"FUNC","rule":"LIstHas","sum":14},{"parent":"FUNC","rule":"LIstHasItems","sum":13},{"parent":"FUNC","rule":"LIstHead","sum":3},{"parent":"FUNC","rule":"LIstLength","sum":345},{"parent":"FUNC","rule":"LIstMap","sum":1347},{"parent":"FUNC","rule":"LIstMax","sum":7},{"parent":"FUNC","rule":"LIstSkip","sum":2},{"parent":"FUNC","rule":"LIstSort","sum":1},{"parent":"FUNC","rule":"LIstSum","sum":1},{"parent":"FUNC","rule":"LIstfilter","sum":2},{"parent":"FUNC","rule":"LIstlength","sum":13},{"parent":"FUNC","rule":"LIstmap","sum":12},{"parent":"FUNC","rule":"LOG","sum":1},{"parent":"FUNC","rule":"LOG10","sum":6},{"parent":"FUNC","rule":"LOGHISTOGRAM","sum":1},{"parent":"FUNC","rule":"LOWER","sum":5},{"parent":"FUNC","rule":"Lag","sum":12300},{"parent":"FUNC","rule":"LambdaArgumentsCount","sum":32},{"parent":"FUNC","rule":"LambdaCode","sum":330699},{"parent":"FUNC","rule":"LastValue","sum":29},{"parent":"FUNC","rule":"Last_VALUE","sum":14},{"parent":"FUNC","rule":"Last_Value","sum":29},{"parent":"FUNC","rule":"Last_value","sum":101},{"parent":"FUNC","rule":"Lead","sum":11188},{"parent":"FUNC","rule":"Least","sum":2236},{"parent":"FUNC","rule":"Len","sum":93143},{"parent":"FUNC","rule":"LenGTH","sum":12},{"parent":"FUNC","rule":"Length","sum":1249246},{"parent":"FUNC","rule":"LiSTMAP","sum":2},{"parent":"FUNC","rule":"Likely","sum":20818},{"parent":"FUNC","rule":"LinearHISTOGRAM","sum":86},{"parent":"FUNC","rule":"LinearHistogram","sum":46217},{"parent":"FUNC","rule":"LinearHistogramCDF","sum":465},{"parent":"FUNC","rule":"LinearHistogramcdf","sum":10},{"parent":"FUNC","rule":"Linear_Histogram","sum":7},{"parent":"FUNC","rule":"Linearhistogram","sum":4},{"parent":"FUNC","rule":"Lis","sum":1},{"parent":"FUNC","rule":"LisMap","sum":2},{"parent":"FUNC","rule":"LisTHas","sum":8},{"parent":"FUNC","rule":"LisTLength","sum":2},{"parent":"FUNC","rule":"ListALL","sum":1550},{"parent":"FUNC","rule":"ListALl","sum":8},{"parent":"FUNC","rule":"ListANY","sum":1725},{"parent":"FUNC","rule":"ListAVG","sum":253},{"parent":"FUNC","rule":"ListAgg","sum":2},{"parent":"FUNC","rule":"ListAggregate","sum":424930},{"parent":"FUNC","rule":"ListAll","sum":265360},{"parent":"FUNC","rule":"ListAny","sum":1880564},{"parent":"FUNC","rule":"ListAppend","sum":1},{"parent":"FUNC","rule":"ListAvg","sum":542938},{"parent":"FUNC","rule":"ListCOncat","sum":2},{"parent":"FUNC","rule":"ListCode","sum":209616},{"parent":"FUNC","rule":"ListCollect","sum":903945},{"parent":"FUNC","rule":"ListConCat","sum":99},{"parent":"FUNC","rule":"ListConcat","sum":5476628},{"parent":"FUNC","rule":"ListCreate","sum":1959182},{"parent":"FUNC","rule":"ListDistinct","sum":1},{"parent":"FUNC","rule":"ListEnumerate","sum":1400780},{"parent":"FUNC","rule":"ListExtEnd","sum":1},{"parent":"FUNC","rule":"ListExtend","sum":4377341},{"parent":"FUNC","rule":"ListExtendStrict","sum":91852},{"parent":"FUNC","rule":"ListExtract","sum":3347283},{"parent":"FUNC","rule":"ListFILTER","sum":552},{"parent":"FUNC","rule":"ListFIlter","sum":346},{"parent":"FUNC","rule":"ListFLatMap","sum":262},{"parent":"FUNC","rule":"ListFLatten","sum":578},{"parent":"FUNC","rule":"ListFROMRange","sum":5076},{"parent":"FUNC","rule":"ListFilteR","sum":4},{"parent":"FUNC","rule":"ListFilter","sum":17818831},{"parent":"FUNC","rule":"ListFirst","sum":3},{"parent":"FUNC","rule":"ListFlatMap","sum":908104},{"parent":"FUNC","rule":"ListFlatmap","sum":29181},{"parent":"FUNC","rule":"ListFlatten","sum":2824559},{"parent":"FUNC","rule":"ListFold","sum":233104},{"parent":"FUNC","rule":"ListFold1","sum":35644},{"parent":"FUNC","rule":"ListFold1Map","sum":3433},{"parent":"FUNC","rule":"ListFoldMap","sum":41830},{"parent":"FUNC","rule":"ListFromPython","sum":2},{"parent":"FUNC","rule":"ListFromRANGE","sum":23},{"parent":"FUNC","rule":"ListFromRAnge","sum":45},{"parent":"FUNC","rule":"ListFromRange","sum":3094429},{"parent":"FUNC","rule":"ListFromTuple","sum":59325},{"parent":"FUNC","rule":"ListFromTyple","sum":2},{"parent":"FUNC","rule":"ListFromrange","sum":12},{"parent":"FUNC","rule":"ListHAS","sum":380},{"parent":"FUNC","rule":"ListHAs","sum":557},{"parent":"FUNC","rule":"ListHAsItems","sum":26},{"parent":"FUNC","rule":"ListHEAD","sum":2},{"parent":"FUNC","rule":"ListHEad","sum":69},{"parent":"FUNC","rule":"ListHaS","sum":1},{"parent":"FUNC","rule":"ListHas","sum":20700011},{"parent":"FUNC","rule":"ListHasITems","sum":9},{"parent":"FUNC","rule":"ListHasItemhs","sum":1},{"parent":"FUNC","rule":"ListHasItems","sum":5130581},{"parent":"FUNC","rule":"ListHasitems","sum":344},{"parent":"FUNC","rule":"ListHeaD","sum":94},{"parent":"FUNC","rule":"ListHead","sum":10740942},{"parent":"FUNC","rule":"ListINdexOf","sum":2},{"parent":"FUNC","rule":"ListIndex","sum":1},{"parent":"FUNC","rule":"ListIndexOF","sum":10},{"parent":"FUNC","rule":"ListIndexOf","sum":1233206},{"parent":"FUNC","rule":"ListIndexof","sum":19},{"parent":"FUNC","rule":"ListItemType","sum":208912},{"parent":"FUNC","rule":"ListJoin","sum":3},{"parent":"FUNC","rule":"ListJsonDocument","sum":1},{"parent":"FUNC","rule":"ListLAst","sum":10},{"parent":"FUNC","rule":"ListLENGTH","sum":2212},{"parent":"FUNC","rule":"ListLEngth","sum":19},{"parent":"FUNC","rule":"ListLasT","sum":12},{"parent":"FUNC","rule":"ListLast","sum":5989328},{"parent":"FUNC","rule":"ListLeNgth","sum":1},{"parent":"FUNC","rule":"ListLegth","sum":1},{"parent":"FUNC","rule":"ListLenght","sum":1},{"parent":"FUNC","rule":"ListLengtH","sum":2},{"parent":"FUNC","rule":"ListLength","sum":18519642},{"parent":"FUNC","rule":"ListMAP","sum":227},{"parent":"FUNC","rule":"ListMAX","sum":10301},{"parent":"FUNC","rule":"ListMAp","sum":4828},{"parent":"FUNC","rule":"ListMAx","sum":1},{"parent":"FUNC","rule":"ListMIN","sum":52},{"parent":"FUNC","rule":"ListMIn","sum":1},{"parent":"FUNC","rule":"ListMaP","sum":1164},{"parent":"FUNC","rule":"ListMap","sum":35473659},{"parent":"FUNC","rule":"ListMax","sum":1415731},{"parent":"FUNC","rule":"ListMin","sum":814456},{"parent":"FUNC","rule":"ListNOTNull","sum":715},{"parent":"FUNC","rule":"ListNoTNull","sum":17},{"parent":"FUNC","rule":"ListNoTnull","sum":963},{"parent":"FUNC","rule":"ListNonNull","sum":1},{"parent":"FUNC","rule":"ListNotNULL","sum":30598},{"parent":"FUNC","rule":"ListNotNUll","sum":7741},{"parent":"FUNC","rule":"ListNotNuLL","sum":5},{"parent":"FUNC","rule":"ListNotNul","sum":1},{"parent":"FUNC","rule":"ListNotNulL","sum":3},{"parent":"FUNC","rule":"ListNotNull","sum":9277210},{"parent":"FUNC","rule":"ListNotnull","sum":22},{"parent":"FUNC","rule":"ListREplicate","sum":2},{"parent":"FUNC","rule":"ListRange","sum":4},{"parent":"FUNC","rule":"ListRepeat","sum":1},{"parent":"FUNC","rule":"ListReplicate","sum":951876},{"parent":"FUNC","rule":"ListReverse","sum":1332692},{"parent":"FUNC","rule":"ListSORT","sum":1},{"parent":"FUNC","rule":"ListSORtAsc","sum":26},{"parent":"FUNC","rule":"ListSOrt","sum":3},{"parent":"FUNC","rule":"ListSUM","sum":782},{"parent":"FUNC","rule":"ListSUm","sum":12},{"parent":"FUNC","rule":"ListSample","sum":13},{"parent":"FUNC","rule":"ListSampleN","sum":715},{"parent":"FUNC","rule":"ListShuffle","sum":533},{"parent":"FUNC","rule":"ListShuffleN","sum":1},{"parent":"FUNC","rule":"ListSkip","sum":618121},{"parent":"FUNC","rule":"ListSkipWhile","sum":139342},{"parent":"FUNC","rule":"ListSkipWhileInclusive","sum":8763},{"parent":"FUNC","rule":"ListSort","sum":5013069},{"parent":"FUNC","rule":"ListSortASC","sum":18106},{"parent":"FUNC","rule":"ListSortAsc","sum":486196},{"parent":"FUNC","rule":"ListSortDESC","sum":56},{"parent":"FUNC","rule":"ListSortDEsc","sum":2},{"parent":"FUNC","rule":"ListSortDesc","sum":1137559},{"parent":"FUNC","rule":"ListSortasc","sum":9},{"parent":"FUNC","rule":"ListSortdesc","sum":633},{"parent":"FUNC","rule":"ListSum","sum":1751486},{"parent":"FUNC","rule":"ListTail","sum":1},{"parent":"FUNC","rule":"ListTake","sum":2155762},{"parent":"FUNC","rule":"ListTakeWhile","sum":89522},{"parent":"FUNC","rule":"ListTakeWhileInclusive","sum":2462},{"parent":"FUNC","rule":"ListToTuple","sum":6466},{"parent":"FUNC","rule":"ListTop","sum":2360},{"parent":"FUNC","rule":"ListTopAsc","sum":132},{"parent":"FUNC","rule":"ListTopDESC","sum":1},{"parent":"FUNC","rule":"ListTopDesc","sum":11009},{"parent":"FUNC","rule":"ListTopSort","sum":1056},{"parent":"FUNC","rule":"ListTopSortAsc","sum":40},{"parent":"FUNC","rule":"ListTopSortDesc","sum":60209},{"parent":"FUNC","rule":"ListTopdesc","sum":1},{"parent":"FUNC","rule":"ListType","sum":32269},{"parent":"FUNC","rule":"ListTypeHandle","sum":1},{"parent":"FUNC","rule":"ListUNiq","sum":30},{"parent":"FUNC","rule":"ListUnionALL","sum":128},{"parent":"FUNC","rule":"ListUnionAll","sum":56382},{"parent":"FUNC","rule":"ListUniq","sum":3980480},{"parent":"FUNC","rule":"ListUniqStable","sum":76021},{"parent":"FUNC","rule":"ListZIP","sum":8},{"parent":"FUNC","rule":"ListZIp","sum":1},{"parent":"FUNC","rule":"ListZip","sum":2533470},{"parent":"FUNC","rule":"ListZipALL","sum":290850},{"parent":"FUNC","rule":"ListZipAll","sum":275064},{"parent":"FUNC","rule":"List_FromRange","sum":11},{"parent":"FUNC","rule":"List_Has","sum":23},{"parent":"FUNC","rule":"List_Length","sum":15},{"parent":"FUNC","rule":"List_Sort","sum":10},{"parent":"FUNC","rule":"List_Uniq","sum":1},{"parent":"FUNC","rule":"List_concat","sum":3},{"parent":"FUNC","rule":"List_length","sum":2},{"parent":"FUNC","rule":"List_sort","sum":80},{"parent":"FUNC","rule":"Listall","sum":4450},{"parent":"FUNC","rule":"Listany","sum":38},{"parent":"FUNC","rule":"Listcollect","sum":5259},{"parent":"FUNC","rule":"Listconcat","sum":14851},{"parent":"FUNC","rule":"Listenumerate","sum":3},{"parent":"FUNC","rule":"Listextend","sum":5},{"parent":"FUNC","rule":"Listfilter","sum":263056},{"parent":"FUNC","rule":"Listflatmap","sum":297},{"parent":"FUNC","rule":"Listflatten","sum":33},{"parent":"FUNC","rule":"ListfromRange","sum":36},{"parent":"FUNC","rule":"Listfromrange","sum":113},{"parent":"FUNC","rule":"Listfromtuple","sum":1},{"parent":"FUNC","rule":"Listhas","sum":69729},{"parent":"FUNC","rule":"ListhasItems","sum":261},{"parent":"FUNC","rule":"Listhasitems","sum":488},{"parent":"FUNC","rule":"Listhead","sum":18575},{"parent":"FUNC","rule":"ListindexOf","sum":2172},{"parent":"FUNC","rule":"Listindexof","sum":4},{"parent":"FUNC","rule":"ListlENGTH","sum":1},{"parent":"FUNC","rule":"ListlEngth","sum":2},{"parent":"FUNC","rule":"Listlast","sum":4180},{"parent":"FUNC","rule":"Listlength","sum":10851},{"parent":"FUNC","rule":"Listmap","sum":11275},{"parent":"FUNC","rule":"Listmax","sum":498},{"parent":"FUNC","rule":"Listmin","sum":1627},{"parent":"FUNC","rule":"ListnotNull","sum":38},{"parent":"FUNC","rule":"Listnotnull","sum":8},{"parent":"FUNC","rule":"Listreverse","sum":17},{"parent":"FUNC","rule":"Listskip","sum":148},{"parent":"FUNC","rule":"ListskipWhile","sum":409},{"parent":"FUNC","rule":"Listsort","sum":1052},{"parent":"FUNC","rule":"Listsortasc","sum":1},{"parent":"FUNC","rule":"Listsortdesc","sum":1},{"parent":"FUNC","rule":"Listsum","sum":27},{"parent":"FUNC","rule":"Listtake","sum":20218},{"parent":"FUNC","rule":"ListtakeWhile","sum":2},{"parent":"FUNC","rule":"Listuniq","sum":327},{"parent":"FUNC","rule":"Listzip","sum":768},{"parent":"FUNC","rule":"Listzipall","sum":1},{"parent":"FUNC","rule":"LogHISTOGRAM","sum":7},{"parent":"FUNC","rule":"LogHistogram","sum":283},{"parent":"FUNC","rule":"LogHistogramCDF","sum":15},{"parent":"FUNC","rule":"LogarithmicHISTOGRAM","sum":1},{"parent":"FUNC","rule":"LogarithmicHistogram","sum":616},{"parent":"FUNC","rule":"Logarithmichistogram","sum":20},{"parent":"FUNC","rule":"Lookup","sum":1},{"parent":"FUNC","rule":"MAX","sum":34536576},{"parent":"FUNC","rule":"MAXBY","sum":123},{"parent":"FUNC","rule":"MAXOF","sum":3},{"parent":"FUNC","rule":"MAX_BY","sum":22832477},{"parent":"FUNC","rule":"MAX_By","sum":19},{"parent":"FUNC","rule":"MAX_IF","sum":2},{"parent":"FUNC","rule":"MAX_OF","sum":2198762},{"parent":"FUNC","rule":"MAX_Of","sum":2},{"parent":"FUNC","rule":"MAX_bY","sum":7},{"parent":"FUNC","rule":"MAX_by","sum":10621},{"parent":"FUNC","rule":"MAX_of","sum":589},{"parent":"FUNC","rule":"MAx","sum":285},{"parent":"FUNC","rule":"MEDIAN","sum":914242},{"parent":"FUNC","rule":"MEDiAN","sum":4},{"parent":"FUNC","rule":"MEdian","sum":14},{"parent":"FUNC","rule":"MIN","sum":14653631},{"parent":"FUNC","rule":"MINBY","sum":1907},{"parent":"FUNC","rule":"MIN_BY","sum":5293824},{"parent":"FUNC","rule":"MIN_IF","sum":8},{"parent":"FUNC","rule":"MIN_OF","sum":2265340},{"parent":"FUNC","rule":"MIN_by","sum":1293},{"parent":"FUNC","rule":"MIN_of","sum":3},{"parent":"FUNC","rule":"MIn","sum":199},{"parent":"FUNC","rule":"MIn_OF","sum":3},{"parent":"FUNC","rule":"MODE","sum":901832},{"parent":"FUNC","rule":"MODe","sum":1},{"parent":"FUNC","rule":"MONTH","sum":1},{"parent":"FUNC","rule":"MULTI_AGGREGATE_BY","sum":696416},{"parent":"FUNC","rule":"MaX","sum":7},{"parent":"FUNC","rule":"MakeDate","sum":1},{"parent":"FUNC","rule":"Map","sum":4},{"parent":"FUNC","rule":"Max","sum":380542},{"parent":"FUNC","rule":"MaxBy","sum":5394},{"parent":"FUNC","rule":"MaxOf","sum":207},{"parent":"FUNC","rule":"Max_BY","sum":3213},{"parent":"FUNC","rule":"Max_By","sum":70691},{"parent":"FUNC","rule":"Max_OF","sum":681},{"parent":"FUNC","rule":"Max_Of","sum":650},{"parent":"FUNC","rule":"Max_by","sum":141220},{"parent":"FUNC","rule":"Max_of","sum":3730},{"parent":"FUNC","rule":"Median","sum":19449},{"parent":"FUNC","rule":"MiN","sum":32},{"parent":"FUNC","rule":"Min","sum":193336},{"parent":"FUNC","rule":"MinBy","sum":1199},{"parent":"FUNC","rule":"MinOf","sum":892},{"parent":"FUNC","rule":"Min_BY","sum":433},{"parent":"FUNC","rule":"Min_By","sum":10707},{"parent":"FUNC","rule":"Min_OF","sum":1095},{"parent":"FUNC","rule":"Min_Of","sum":827},{"parent":"FUNC","rule":"Min_by","sum":9098},{"parent":"FUNC","rule":"Min_of","sum":1307},{"parent":"FUNC","rule":"MoDE","sum":1},{"parent":"FUNC","rule":"Mode","sum":14710},{"parent":"FUNC","rule":"Mul","sum":1},{"parent":"FUNC","rule":"MultiAggregateBy","sum":645},{"parent":"FUNC","rule":"Multi_Aggregate_BY","sum":4},{"parent":"FUNC","rule":"Multi_Aggregate_By","sum":1157},{"parent":"FUNC","rule":"Multi_Aggregate_by","sum":4},{"parent":"FUNC","rule":"Multi_aggregate_by","sum":413},{"parent":"FUNC","rule":"NANVL","sum":720089},{"parent":"FUNC","rule":"NOTHING","sum":3221},{"parent":"FUNC","rule":"NOW","sum":2},{"parent":"FUNC","rule":"NOW64","sum":2},{"parent":"FUNC","rule":"NOthing","sum":1},{"parent":"FUNC","rule":"NTH_VALUE","sum":3008},{"parent":"FUNC","rule":"NTILE","sum":1817},{"parent":"FUNC","rule":"NULLIF","sum":3},{"parent":"FUNC","rule":"NVL","sum":17680671},{"parent":"FUNC","rule":"NVl","sum":802},{"parent":"FUNC","rule":"NaNvl","sum":26},{"parent":"FUNC","rule":"NanVL","sum":1},{"parent":"FUNC","rule":"NanVl","sum":3},{"parent":"FUNC","rule":"Nanvl","sum":10769},{"parent":"FUNC","rule":"NothiNG","sum":2},{"parent":"FUNC","rule":"Nothing","sum":812266},{"parent":"FUNC","rule":"NullTypeHandle","sum":2314},{"parent":"FUNC","rule":"Nvl","sum":28483},{"parent":"FUNC","rule":"OR","sum":6},{"parent":"FUNC","rule":"OVER","sum":1},{"parent":"FUNC","rule":"OptionalItemType","sum":37180},{"parent":"FUNC","rule":"OptionalType","sum":136974},{"parent":"FUNC","rule":"OptionalTypeHandle","sum":44309},{"parent":"FUNC","rule":"PERCENTILE","sum":29934684},{"parent":"FUNC","rule":"PERCENTIlE","sum":4},{"parent":"FUNC","rule":"PERCENT_RANK","sum":6127},{"parent":"FUNC","rule":"PERCENtILE","sum":1957},{"parent":"FUNC","rule":"PERCEnTILE","sum":1},{"parent":"FUNC","rule":"PICKLE","sum":77},{"parent":"FUNC","rule":"PIckle","sum":7},{"parent":"FUNC","rule":"POPULATION_STDDEV","sum":364},{"parent":"FUNC","rule":"POPULATION_VARIANCE","sum":19},{"parent":"FUNC","rule":"POWER","sum":4},{"parent":"FUNC","rule":"ParseDuration","sum":2},{"parent":"FUNC","rule":"ParseFILE","sum":22},{"parent":"FUNC","rule":"ParseFIle","sum":8},{"parent":"FUNC","rule":"ParseFile","sum":952167},{"parent":"FUNC","rule":"ParseType","sum":464193},{"parent":"FUNC","rule":"ParseTypeHandle","sum":1193683},{"parent":"FUNC","rule":"Parsefile","sum":111},{"parent":"FUNC","rule":"Path","sum":4},{"parent":"FUNC","rule":"PeRCENTILE","sum":365},{"parent":"FUNC","rule":"Percentile","sum":73128},{"parent":"FUNC","rule":"PgArray","sum":17},{"parent":"FUNC","rule":"PgBool","sum":153},{"parent":"FUNC","rule":"PgCall","sum":554},{"parent":"FUNC","rule":"PgCast","sum":5593},{"parent":"FUNC","rule":"PgCircle","sum":5},{"parent":"FUNC","rule":"PgConst","sum":96},{"parent":"FUNC","rule":"PgDate","sum":110},{"parent":"FUNC","rule":"PgGeometry","sum":6},{"parent":"FUNC","rule":"PgInt4","sum":4},{"parent":"FUNC","rule":"PgInt8","sum":1},{"parent":"FUNC","rule":"PgInterval","sum":33},{"parent":"FUNC","rule":"PgOp","sum":1369},{"parent":"FUNC","rule":"PgPoint","sum":76},{"parent":"FUNC","rule":"PgPolygon","sum":517},{"parent":"FUNC","rule":"PgRangeCall","sum":7},{"parent":"FUNC","rule":"PgText","sum":24},{"parent":"FUNC","rule":"PgTimestamp","sum":42},{"parent":"FUNC","rule":"PgVarBit","sum":2},{"parent":"FUNC","rule":"Pickle","sum":118347},{"parent":"FUNC","rule":"QuoteCode","sum":722026},{"parent":"FUNC","rule":"RADIANS","sum":12},{"parent":"FUNC","rule":"RAND","sum":2},{"parent":"FUNC","rule":"RANDOM","sum":486698},{"parent":"FUNC","rule":"RANDOMNUMBER","sum":4009},{"parent":"FUNC","rule":"RANDOMNumber","sum":11},{"parent":"FUNC","rule":"RANDOMUUID","sum":5},{"parent":"FUNC","rule":"RANDOM_NUMBER","sum":83},{"parent":"FUNC","rule":"RANGE","sum":149},{"parent":"FUNC","rule":"RANK","sum":945395},{"parent":"FUNC","rule":"RAndom","sum":7},{"parent":"FUNC","rule":"REGEXP","sum":1},{"parent":"FUNC","rule":"REMOVEMEMBERS","sum":41},{"parent":"FUNC","rule":"REMOVE_mEMBER","sum":6},{"parent":"FUNC","rule":"REPLACE","sum":3},{"parent":"FUNC","rule":"RFIND","sum":3594199},{"parent":"FUNC","rule":"RFind","sum":251181},{"parent":"FUNC","rule":"RIGHT","sum":2},{"parent":"FUNC","rule":"ROUND","sum":10},{"parent":"FUNC","rule":"ROWNUMBER","sum":33},{"parent":"FUNC","rule":"ROW_NUMBER","sum":9408940},{"parent":"FUNC","rule":"ROW_NUMber","sum":11},{"parent":"FUNC","rule":"ROW_Number","sum":8},{"parent":"FUNC","rule":"ROW_nUMBER","sum":1},{"parent":"FUNC","rule":"ROW_nuMBER","sum":4},{"parent":"FUNC","rule":"ROW_number","sum":13473},{"parent":"FUNC","rule":"Rand","sum":1},{"parent":"FUNC","rule":"Random","sum":731618},{"parent":"FUNC","rule":"RandomNUmber","sum":172},{"parent":"FUNC","rule":"RandomNumber","sum":272780},{"parent":"FUNC","rule":"RandomUUID","sum":8049},{"parent":"FUNC","rule":"RandomUUid","sum":32889},{"parent":"FUNC","rule":"RandomUuid","sum":214210},{"parent":"FUNC","rule":"Randomnumber","sum":2},{"parent":"FUNC","rule":"Range","sum":2},{"parent":"FUNC","rule":"Rank","sum":3094},{"parent":"FUNC","rule":"RemoveMEmbers","sum":16},{"parent":"FUNC","rule":"RemoveMember","sum":431493},{"parent":"FUNC","rule":"RemoveMembers","sum":728191},{"parent":"FUNC","rule":"RemoveTimeZone","sum":13},{"parent":"FUNC","rule":"RemoveTimezone","sum":433746},{"parent":"FUNC","rule":"Removemember","sum":686},{"parent":"FUNC","rule":"Removemembers","sum":4},{"parent":"FUNC","rule":"RenameMembers","sum":506669},{"parent":"FUNC","rule":"ReplaceMember","sum":9370},{"parent":"FUNC","rule":"ReprCode","sum":195698},{"parent":"FUNC","rule":"ResourceType","sum":9},{"parent":"FUNC","rule":"Rfind","sum":871},{"parent":"FUNC","rule":"RootAttributes","sum":20},{"parent":"FUNC","rule":"RowNum","sum":1},{"parent":"FUNC","rule":"RowNumber","sum":20989},{"parent":"FUNC","rule":"Row_NUMBER","sum":33},{"parent":"FUNC","rule":"Row_NUmber","sum":16},{"parent":"FUNC","rule":"Row_Number","sum":60121},{"parent":"FUNC","rule":"Row_number","sum":4136},{"parent":"FUNC","rule":"SESSIONWINDOW","sum":131},{"parent":"FUNC","rule":"SETINTERSECTION","sum":20},{"parent":"FUNC","rule":"SIGN","sum":1},{"parent":"FUNC","rule":"SIN","sum":4},{"parent":"FUNC","rule":"SOME","sum":32975368},{"parent":"FUNC","rule":"SOMe","sum":17},{"parent":"FUNC","rule":"SON_VALUE","sum":1},{"parent":"FUNC","rule":"SOmE","sum":3},{"parent":"FUNC","rule":"SOme","sum":9},{"parent":"FUNC","rule":"SQL","sum":6},{"parent":"FUNC","rule":"SQRT","sum":2},{"parent":"FUNC","rule":"STARTSWITH","sum":25418},{"parent":"FUNC","rule":"STARTS_WITH","sum":46},{"parent":"FUNC","rule":"STARTsWITH","sum":17},{"parent":"FUNC","rule":"STATICMAP","sum":46},{"parent":"FUNC","rule":"STD","sum":6},{"parent":"FUNC","rule":"STDDEV","sum":400676},{"parent":"FUNC","rule":"STDDEVPOP","sum":2805},{"parent":"FUNC","rule":"STDDEVSAMP","sum":1098},{"parent":"FUNC","rule":"STDDEV_POP","sum":14},{"parent":"FUNC","rule":"STDDEV_POPULATION","sum":18603},{"parent":"FUNC","rule":"STDDEV_SAMP","sum":3359},{"parent":"FUNC","rule":"STDDEV_SAMPLE","sum":9936},{"parent":"FUNC","rule":"STDDev","sum":2},{"parent":"FUNC","rule":"STDdev","sum":4},{"parent":"FUNC","rule":"STRING_SPLIT","sum":1},{"parent":"FUNC","rule":"ST_AsText","sum":3},{"parent":"FUNC","rule":"ST_ClosestPoint","sum":3},{"parent":"FUNC","rule":"ST_DWithin","sum":4},{"parent":"FUNC","rule":"ST_Distance","sum":5},{"parent":"FUNC","rule":"ST_GeomFromGeoHash","sum":1},{"parent":"FUNC","rule":"ST_MakePoint","sum":4},{"parent":"FUNC","rule":"ST_Point","sum":10},{"parent":"FUNC","rule":"ST_PolygonFromText","sum":5},{"parent":"FUNC","rule":"ST_SetSRID","sum":10},{"parent":"FUNC","rule":"ST_Transform","sum":4},{"parent":"FUNC","rule":"STartsWith","sum":2},{"parent":"FUNC","rule":"STdDEV","sum":9},{"parent":"FUNC","rule":"SUBQUERYExtendFor","sum":6},{"parent":"FUNC","rule":"SUBSTIRNG","sum":4},{"parent":"FUNC","rule":"SUBSTRING","sum":29536028},{"parent":"FUNC","rule":"SUBSTRINg","sum":2},{"parent":"FUNC","rule":"SUBSTRInG","sum":4},{"parent":"FUNC","rule":"SUBSTRiNG","sum":2},{"parent":"FUNC","rule":"SUBSTRinG","sum":2},{"parent":"FUNC","rule":"SUBSTRing","sum":223},{"parent":"FUNC","rule":"SUBSTrING","sum":21},{"parent":"FUNC","rule":"SUBSTring","sum":14},{"parent":"FUNC","rule":"SUBStRING","sum":2},{"parent":"FUNC","rule":"SUBString","sum":20},{"parent":"FUNC","rule":"SUBstring","sum":3},{"parent":"FUNC","rule":"SUM","sum":42462858},{"parent":"FUNC","rule":"SUMIF","sum":3303},{"parent":"FUNC","rule":"SUM_","sum":317},{"parent":"FUNC","rule":"SUM_IF","sum":8452328},{"parent":"FUNC","rule":"SUM_If","sum":118},{"parent":"FUNC","rule":"SUM_iF","sum":19},{"parent":"FUNC","rule":"SUM_if","sum":267431},{"parent":"FUNC","rule":"SUN","sum":1},{"parent":"FUNC","rule":"SUbstring","sum":5},{"parent":"FUNC","rule":"SUm","sum":80},{"parent":"FUNC","rule":"SUm_IF","sum":30},{"parent":"FUNC","rule":"SWITCH","sum":2},{"parent":"FUNC","rule":"SecureParam","sum":900802},{"parent":"FUNC","rule":"SessionStart","sum":24230},{"parent":"FUNC","rule":"SessionState","sum":716},{"parent":"FUNC","rule":"SessionWindow","sum":102118},{"parent":"FUNC","rule":"SetBit","sum":44509},{"parent":"FUNC","rule":"SetContains","sum":1},{"parent":"FUNC","rule":"SetCreate","sum":45700},{"parent":"FUNC","rule":"SetDIfference","sum":11},{"parent":"FUNC","rule":"SetDifference","sum":486034},{"parent":"FUNC","rule":"SetINtersection","sum":1},{"parent":"FUNC","rule":"SetIncludes","sum":246595},{"parent":"FUNC","rule":"SetInterSection","sum":21},{"parent":"FUNC","rule":"SetIntersection","sum":1266793},{"parent":"FUNC","rule":"SetIsDisJOINt","sum":8081},{"parent":"FUNC","rule":"SetIsDisJoint","sum":1686},{"parent":"FUNC","rule":"SetIsDisjoint","sum":1241386},{"parent":"FUNC","rule":"SetSymmetricDifference","sum":8855},{"parent":"FUNC","rule":"SetUNION","sum":1},{"parent":"FUNC","rule":"SetUnion","sum":588902},{"parent":"FUNC","rule":"Setintersection","sum":4517},{"parent":"FUNC","rule":"SizeOf","sum":1},{"parent":"FUNC","rule":"Some","sum":2528977},{"parent":"FUNC","rule":"SplitToList","sum":6},{"parent":"FUNC","rule":"SpreadMembers","sum":344997},{"parent":"FUNC","rule":"StablePicke","sum":1},{"parent":"FUNC","rule":"StablePickle","sum":212966},{"parent":"FUNC","rule":"StartSwith","sum":105},{"parent":"FUNC","rule":"StartsWIth","sum":704},{"parent":"FUNC","rule":"StartsWith","sum":5765448},{"parent":"FUNC","rule":"Startswith","sum":19728},{"parent":"FUNC","rule":"StaticFold","sum":307},{"parent":"FUNC","rule":"StaticMap","sum":683032},{"parent":"FUNC","rule":"StaticZip","sum":14557},{"parent":"FUNC","rule":"Staticmap","sum":2},{"parent":"FUNC","rule":"StdDev","sum":33},{"parent":"FUNC","rule":"Stddev","sum":43},{"parent":"FUNC","rule":"StreamItemType","sum":5715},{"parent":"FUNC","rule":"StreamType","sum":78586},{"parent":"FUNC","rule":"StreamTypeHandle","sum":17},{"parent":"FUNC","rule":"String","sum":34348},{"parent":"FUNC","rule":"StringLength","sum":5},{"parent":"FUNC","rule":"StringSplitToList","sum":4},{"parent":"FUNC","rule":"StructDifference","sum":235},{"parent":"FUNC","rule":"StructIntersection","sum":816},{"parent":"FUNC","rule":"StructMemberType","sum":20166},{"parent":"FUNC","rule":"StructMembers","sum":970519},{"parent":"FUNC","rule":"StructSymmetricDifference","sum":172},{"parent":"FUNC","rule":"StructType","sum":17979},{"parent":"FUNC","rule":"StructTypeComponents","sum":99655},{"parent":"FUNC","rule":"StructTypeHandle","sum":88035},{"parent":"FUNC","rule":"StructUnion","sum":101879},{"parent":"FUNC","rule":"SuBSTRING","sum":1},{"parent":"FUNC","rule":"SuM","sum":9},{"parent":"FUNC","rule":"SuM_IF","sum":4},{"parent":"FUNC","rule":"SubQueryExtendFor","sum":3},{"parent":"FUNC","rule":"SubSTRING","sum":3},{"parent":"FUNC","rule":"SubString","sum":27456},{"parent":"FUNC","rule":"SubqueryAssumeOrderBy","sum":818},{"parent":"FUNC","rule":"SubqueryExtend","sum":37139},{"parent":"FUNC","rule":"SubqueryExtendFor","sum":769800},{"parent":"FUNC","rule":"SubqueryMerge","sum":19},{"parent":"FUNC","rule":"SubqueryMergeFor","sum":36400},{"parent":"FUNC","rule":"SubqueryOrderBy","sum":184291},{"parent":"FUNC","rule":"SubqueryUnionALLFor","sum":9},{"parent":"FUNC","rule":"SubqueryUnionALlFor","sum":82},{"parent":"FUNC","rule":"SubqueryUnionAll","sum":26089},{"parent":"FUNC","rule":"SubqueryUnionAllFor","sum":141391},{"parent":"FUNC","rule":"SubqueryUnionAllfor","sum":381},{"parent":"FUNC","rule":"SubqueryUnionMerge","sum":30584},{"parent":"FUNC","rule":"SubqueryUnionMergeFor","sum":73744},{"parent":"FUNC","rule":"SubsTRING","sum":3},{"parent":"FUNC","rule":"Substring","sum":2920490},{"parent":"FUNC","rule":"Sum","sum":453950},{"parent":"FUNC","rule":"SumIf","sum":1597},{"parent":"FUNC","rule":"Sum_IF","sum":85},{"parent":"FUNC","rule":"Sum_If","sum":13919},{"parent":"FUNC","rule":"Sum_if","sum":52945},{"parent":"FUNC","rule":"TABLENAME","sum":12025},{"parent":"FUNC","rule":"TABLEPATH","sum":280},{"parent":"FUNC","rule":"TABLERECORDINDEX","sum":45},{"parent":"FUNC","rule":"TABLEROW","sum":1249},{"parent":"FUNC","rule":"TABLE_NAME","sum":140},{"parent":"FUNC","rule":"TABLE_PATH","sum":53},{"parent":"FUNC","rule":"TABLE_ROW","sum":124},{"parent":"FUNC","rule":"TABLEname","sum":4},{"parent":"FUNC","rule":"TAbleName","sum":69},{"parent":"FUNC","rule":"TAblePath","sum":2},{"parent":"FUNC","rule":"TAbleRow","sum":25},{"parent":"FUNC","rule":"TAblename","sum":1},{"parent":"FUNC","rule":"TESTBIT","sum":3},{"parent":"FUNC","rule":"TEstBit","sum":1},{"parent":"FUNC","rule":"TIMESTAMP","sum":422},{"parent":"FUNC","rule":"TIMESTAMPDIFF","sum":2},{"parent":"FUNC","rule":"TIMESTAMP_SECONDS","sum":1},{"parent":"FUNC","rule":"TOBytes","sum":1},{"parent":"FUNC","rule":"TODICT","sum":21},{"parent":"FUNC","rule":"TODIct","sum":1},{"parent":"FUNC","rule":"TOP","sum":501438},{"parent":"FUNC","rule":"TOPBY","sum":1},{"parent":"FUNC","rule":"TOPFREQ","sum":510613},{"parent":"FUNC","rule":"TOPFreq","sum":3},{"parent":"FUNC","rule":"TOP_BY","sum":1772438},{"parent":"FUNC","rule":"TOP_FREQ","sum":46},{"parent":"FUNC","rule":"TOP_by","sum":26},{"parent":"FUNC","rule":"TOSET","sum":41},{"parent":"FUNC","rule":"TOSet","sum":776},{"parent":"FUNC","rule":"TO_NUMBER","sum":14},{"parent":"FUNC","rule":"TO_TIMESTAMP","sum":1},{"parent":"FUNC","rule":"TObytes","sum":3},{"parent":"FUNC","rule":"TRY_MEMBER","sum":37},{"parent":"FUNC","rule":"TYPEOF","sum":1},{"parent":"FUNC","rule":"TYPEof","sum":28},{"parent":"FUNC","rule":"TZDateTime","sum":136},{"parent":"FUNC","rule":"TZDatetime","sum":3},{"parent":"FUNC","rule":"TZTimestamp","sum":64},{"parent":"FUNC","rule":"TabLeName","sum":1},{"parent":"FUNC","rule":"TableNAME","sum":3},{"parent":"FUNC","rule":"TableNAme","sum":1655},{"parent":"FUNC","rule":"TableNamE","sum":2},{"parent":"FUNC","rule":"TableName","sum":15053163},{"parent":"FUNC","rule":"TablePATH","sum":1},{"parent":"FUNC","rule":"TablePAth","sum":5},{"parent":"FUNC","rule":"TablePath","sum":1502345},{"parent":"FUNC","rule":"TableROW","sum":4},{"parent":"FUNC","rule":"TableROw","sum":19},{"parent":"FUNC","rule":"TableRecordINdex","sum":4},{"parent":"FUNC","rule":"TableRecordIndex","sum":2316443},{"parent":"FUNC","rule":"TableRedordIndex","sum":1},{"parent":"FUNC","rule":"TableRow","sum":27030786},{"parent":"FUNC","rule":"TableRowIndex","sum":1},{"parent":"FUNC","rule":"TableRows","sum":1691348},{"parent":"FUNC","rule":"Table_Name","sum":55},{"parent":"FUNC","rule":"Table_Row","sum":5},{"parent":"FUNC","rule":"Table_name","sum":73},{"parent":"FUNC","rule":"Table_path","sum":3},{"parent":"FUNC","rule":"Tablename","sum":104331},{"parent":"FUNC","rule":"Tablepath","sum":204},{"parent":"FUNC","rule":"TablerRow","sum":1},{"parent":"FUNC","rule":"TablerecordIndex","sum":1},{"parent":"FUNC","rule":"Tablerecordindex","sum":3},{"parent":"FUNC","rule":"Tablerow","sum":26427},{"parent":"FUNC","rule":"TestBit","sum":253623},{"parent":"FUNC","rule":"Text","sum":20},{"parent":"FUNC","rule":"TimeStamp","sum":4383},{"parent":"FUNC","rule":"Timestamp","sum":1352583},{"parent":"FUNC","rule":"Timestamp64","sum":59},{"parent":"FUNC","rule":"ToBytes","sum":6657465},{"parent":"FUNC","rule":"ToDIct","sum":257},{"parent":"FUNC","rule":"ToDict","sum":6409425},{"parent":"FUNC","rule":"ToList","sum":3},{"parent":"FUNC","rule":"ToLower","sum":4},{"parent":"FUNC","rule":"ToMilliseconds","sum":2},{"parent":"FUNC","rule":"ToMultiDict","sum":339470},{"parent":"FUNC","rule":"ToPg","sum":3165},{"parent":"FUNC","rule":"ToSET","sum":80},{"parent":"FUNC","rule":"ToSet","sum":5476490},{"parent":"FUNC","rule":"ToSortedDict","sum":1116},{"parent":"FUNC","rule":"ToStartOfMonth","sum":4},{"parent":"FUNC","rule":"To_bytes","sum":3},{"parent":"FUNC","rule":"Todict","sum":232},{"parent":"FUNC","rule":"Top","sum":841},{"parent":"FUNC","rule":"TopBy","sum":77},{"parent":"FUNC","rule":"TopFreq","sum":13752},{"parent":"FUNC","rule":"Top_BY","sum":22},{"parent":"FUNC","rule":"Top_By","sum":110},{"parent":"FUNC","rule":"Top_by","sum":122},{"parent":"FUNC","rule":"Topfreq","sum":28},{"parent":"FUNC","rule":"Toset","sum":2338},{"parent":"FUNC","rule":"TryMember","sum":16756620},{"parent":"FUNC","rule":"Trymember","sum":36906},{"parent":"FUNC","rule":"TupleElementType","sum":7626},{"parent":"FUNC","rule":"TupleType","sum":2405},{"parent":"FUNC","rule":"TupleTypeComponents","sum":58},{"parent":"FUNC","rule":"TupleTypeHandle","sum":5579},{"parent":"FUNC","rule":"TypeHandle","sum":161538},{"parent":"FUNC","rule":"TypeKind","sum":54944},{"parent":"FUNC","rule":"TypeOF","sum":37},{"parent":"FUNC","rule":"TypeOf","sum":849905},{"parent":"FUNC","rule":"Typeof","sum":78},{"parent":"FUNC","rule":"TzDate","sum":671},{"parent":"FUNC","rule":"TzDate32","sum":7},{"parent":"FUNC","rule":"TzDateTime","sum":24905},{"parent":"FUNC","rule":"TzDateTime64","sum":7},{"parent":"FUNC","rule":"TzDatetime","sum":46356},{"parent":"FUNC","rule":"TzTimeStamp","sum":4},{"parent":"FUNC","rule":"TzTimestamp","sum":343153},{"parent":"FUNC","rule":"TzTimestamp64","sum":7},{"parent":"FUNC","rule":"UBSTRING","sum":1},{"parent":"FUNC","rule":"UDAF","sum":141596},{"parent":"FUNC","rule":"UDF","sum":1834},{"parent":"FUNC","rule":"UINT32","sum":4},{"parent":"FUNC","rule":"UINT64","sum":6},{"parent":"FUNC","rule":"UInt32","sum":110313},{"parent":"FUNC","rule":"UInt64","sum":829},{"parent":"FUNC","rule":"UInt8","sum":317},{"parent":"FUNC","rule":"UNIQ","sum":1},{"parent":"FUNC","rule":"UNPICKLE","sum":28},{"parent":"FUNC","rule":"UNTAG","sum":18},{"parent":"FUNC","rule":"UNWRAP","sum":14035490},{"parent":"FUNC","rule":"UNWRAp","sum":1},{"parent":"FUNC","rule":"UNWRaP","sum":1},{"parent":"FUNC","rule":"UNWRap","sum":10586},{"parent":"FUNC","rule":"UNWrAP","sum":18},{"parent":"FUNC","rule":"UNWraP","sum":8},{"parent":"FUNC","rule":"UNWrap","sum":4},{"parent":"FUNC","rule":"UNwRAP","sum":6},{"parent":"FUNC","rule":"UNwrap","sum":1368},{"parent":"FUNC","rule":"USING","sum":6},{"parent":"FUNC","rule":"UTF8","sum":336668},{"parent":"FUNC","rule":"UUID","sum":1},{"parent":"FUNC","rule":"Udf","sum":299948},{"parent":"FUNC","rule":"Uint16","sum":83},{"parent":"FUNC","rule":"Uint32","sum":332306},{"parent":"FUNC","rule":"Uint64","sum":11970},{"parent":"FUNC","rule":"Uint8","sum":2927},{"parent":"FUNC","rule":"UnTag","sum":55},{"parent":"FUNC","rule":"UnWRAP","sum":10},{"parent":"FUNC","rule":"UnWrAp","sum":1},{"parent":"FUNC","rule":"UnWrap","sum":1070983},{"parent":"FUNC","rule":"UnionAll","sum":3},{"parent":"FUNC","rule":"Unpickle","sum":180},{"parent":"FUNC","rule":"Untag","sum":15650},{"parent":"FUNC","rule":"Unwarp","sum":1},{"parent":"FUNC","rule":"Unwrap","sum":35784184},{"parent":"FUNC","rule":"UtcCurrentDatetime","sum":8},{"parent":"FUNC","rule":"Utf8","sum":41022},{"parent":"FUNC","rule":"Uuid","sum":451},{"parent":"FUNC","rule":"VALUES","sum":14},{"parent":"FUNC","rule":"VARIANCE","sum":31012},{"parent":"FUNC","rule":"VARIANCE_POPULATION","sum":3016},{"parent":"FUNC","rule":"VARIANCE_SAMPLE","sum":1236},{"parent":"FUNC","rule":"VARP","sum":146},{"parent":"FUNC","rule":"VARPOP","sum":15},{"parent":"FUNC","rule":"VAR_POP","sum":4},{"parent":"FUNC","rule":"VAR_SAMP","sum":44},{"parent":"FUNC","rule":"VERSION","sum":2},{"parent":"FUNC","rule":"Variance","sum":1145},{"parent":"FUNC","rule":"Variance_SAMPLE","sum":30},{"parent":"FUNC","rule":"Variance_Sample","sum":23},{"parent":"FUNC","rule":"Variance_sample","sum":24},{"parent":"FUNC","rule":"VariantType","sum":3161},{"parent":"FUNC","rule":"VariantTypeHandle","sum":8},{"parent":"FUNC","rule":"VariantUnderlyingType","sum":6517},{"parent":"FUNC","rule":"Version","sum":3},{"parent":"FUNC","rule":"Visit","sum":28},{"parent":"FUNC","rule":"Void","sum":92520},{"parent":"FUNC","rule":"WEAKFIELD","sum":833},{"parent":"FUNC","rule":"WEAK_FIELD","sum":372},{"parent":"FUNC","rule":"WEakField","sum":2},{"parent":"FUNC","rule":"Way","sum":9085},{"parent":"FUNC","rule":"WeakFIeld","sum":43},{"parent":"FUNC","rule":"WeakField","sum":21200118},{"parent":"FUNC","rule":"WeakFiled","sum":2},{"parent":"FUNC","rule":"Weakfield","sum":1925},{"parent":"FUNC","rule":"WorldCode","sum":378},{"parent":"FUNC","rule":"YPathDouble","sum":4},{"parent":"FUNC","rule":"YPathExtract","sum":4},{"parent":"FUNC","rule":"YPathInt64","sum":6},{"parent":"FUNC","rule":"YPathString","sum":4},{"parent":"FUNC","rule":"YSON","sum":756},{"parent":"FUNC","rule":"YSONExtractString","sum":6},{"parent":"FUNC","rule":"Yson","sum":609223},{"parent":"FUNC","rule":"aGGREGATE_LIST","sum":13},{"parent":"FUNC","rule":"aGGREGATE_LIST_DISTINCT","sum":4},{"parent":"FUNC","rule":"aGG_LIST","sum":2},{"parent":"FUNC","rule":"aGG_LIST_DISTINCT","sum":10},{"parent":"FUNC","rule":"aSSTRUCT","sum":1},{"parent":"FUNC","rule":"aSTuple","sum":3},{"parent":"FUNC","rule":"aVG","sum":2},{"parent":"FUNC","rule":"abs","sum":1551344},{"parent":"FUNC","rule":"addMember","sum":2594},{"parent":"FUNC","rule":"addTimezone","sum":782},{"parent":"FUNC","rule":"age","sum":2},{"parent":"FUNC","rule":"aggList","sum":265},{"parent":"FUNC","rule":"agg_LIST","sum":76},{"parent":"FUNC","rule":"agg_LIST_DISTINCT","sum":1},{"parent":"FUNC","rule":"agg_List","sum":546},{"parent":"FUNC","rule":"agg_List_distinct","sum":24},{"parent":"FUNC","rule":"agg_list","sum":1285275},{"parent":"FUNC","rule":"agg_list_DISTINCT","sum":2},{"parent":"FUNC","rule":"agg_list_Distinct","sum":1},{"parent":"FUNC","rule":"agg_list_distinct","sum":435217},{"parent":"FUNC","rule":"agg_set","sum":1},{"parent":"FUNC","rule":"agglist","sum":130},{"parent":"FUNC","rule":"agglistdistinct","sum":44},{"parent":"FUNC","rule":"aggr_list","sum":2662},{"parent":"FUNC","rule":"aggr_list_distinct","sum":18},{"parent":"FUNC","rule":"aggr_set","sum":2},{"parent":"FUNC","rule":"aggregATE_LIST","sum":16},{"parent":"FUNC","rule":"aggregateList","sum":368},{"parent":"FUNC","rule":"aggregateListDistinct","sum":38},{"parent":"FUNC","rule":"aggregate_List","sum":986},{"parent":"FUNC","rule":"aggregate_List_Distinct","sum":8},{"parent":"FUNC","rule":"aggregate_List_distinct","sum":10},{"parent":"FUNC","rule":"aggregate_by","sum":369299},{"parent":"FUNC","rule":"aggregate_list","sum":2505875},{"parent":"FUNC","rule":"aggregate_list_","sum":2},{"parent":"FUNC","rule":"aggregate_list_DISTINCT","sum":1795},{"parent":"FUNC","rule":"aggregate_list_Distinct","sum":27},{"parent":"FUNC","rule":"aggregate_list_distinct","sum":941616},{"parent":"FUNC","rule":"aggregatelist","sum":558},{"parent":"FUNC","rule":"aggregatetransforminput","sum":1},{"parent":"FUNC","rule":"aggregationFactory","sum":138},{"parent":"FUNC","rule":"aggregation_factory","sum":8960},{"parent":"FUNC","rule":"aggregationfactory","sum":77},{"parent":"FUNC","rule":"agregate_list_distinct","sum":1},{"parent":"FUNC","rule":"and","sum":5},{"parent":"FUNC","rule":"anyLast","sum":8},{"parent":"FUNC","rule":"argMax","sum":15},{"parent":"FUNC","rule":"argMin","sum":3},{"parent":"FUNC","rule":"arrayElement","sum":1},{"parent":"FUNC","rule":"arrayJoin","sum":10},{"parent":"FUNC","rule":"arrayMax","sum":4},{"parent":"FUNC","rule":"array_agg","sum":5},{"parent":"FUNC","rule":"array_to_string","sum":2},{"parent":"FUNC","rule":"asDict","sum":3796},{"parent":"FUNC","rule":"asLIST","sum":50},{"parent":"FUNC","rule":"asList","sum":175821},{"parent":"FUNC","rule":"asSet","sum":1970},{"parent":"FUNC","rule":"asStruct","sum":119870},{"parent":"FUNC","rule":"asTUPLE","sum":1},{"parent":"FUNC","rule":"asTagged","sum":2181},{"parent":"FUNC","rule":"asTuple","sum":83395},{"parent":"FUNC","rule":"asVariant","sum":10},{"parent":"FUNC","rule":"as_dict","sum":4},{"parent":"FUNC","rule":"as_list","sum":77},{"parent":"FUNC","rule":"as_struct","sum":122},{"parent":"FUNC","rule":"as_table","sum":30},{"parent":"FUNC","rule":"as_tagged","sum":1},{"parent":"FUNC","rule":"as_tuple","sum":368},{"parent":"FUNC","rule":"asdict","sum":3848},{"parent":"FUNC","rule":"asenum","sum":13},{"parent":"FUNC","rule":"aslist","sum":164811},{"parent":"FUNC","rule":"assessments_integralListReverse","sum":2},{"parent":"FUNC","rule":"asset","sum":1146},{"parent":"FUNC","rule":"asstruct","sum":13007},{"parent":"FUNC","rule":"assumeNotNull","sum":3},{"parent":"FUNC","rule":"astagged","sum":1372},{"parent":"FUNC","rule":"astuple","sum":30946},{"parent":"FUNC","rule":"asvariant","sum":3},{"parent":"FUNC","rule":"atan2","sum":4},{"parent":"FUNC","rule":"avG","sum":52},{"parent":"FUNC","rule":"avg","sum":6012613},{"parent":"FUNC","rule":"avgIf","sum":19424},{"parent":"FUNC","rule":"avg_","sum":1},{"parent":"FUNC","rule":"avg_IF","sum":155},{"parent":"FUNC","rule":"avg_If","sum":129},{"parent":"FUNC","rule":"avg_if","sum":497930},{"parent":"FUNC","rule":"ax","sum":13},{"parent":"FUNC","rule":"bit_or","sum":26580},{"parent":"FUNC","rule":"bool","sum":278},{"parent":"FUNC","rule":"bool_and","sum":67277},{"parent":"FUNC","rule":"bool_or","sum":236590},{"parent":"FUNC","rule":"bool_xor","sum":2},{"parent":"FUNC","rule":"bottom","sum":10501},{"parent":"FUNC","rule":"bottom_by","sum":332629},{"parent":"FUNC","rule":"business_id","sum":1},{"parent":"FUNC","rule":"bytes","sum":2},{"parent":"FUNC","rule":"cOALESCE","sum":36},{"parent":"FUNC","rule":"cOUNT","sum":64},{"parent":"FUNC","rule":"cOUNT_IF","sum":40},{"parent":"FUNC","rule":"cOunt","sum":2},{"parent":"FUNC","rule":"ceil","sum":1},{"parent":"FUNC","rule":"char_LENGTH","sum":2},{"parent":"FUNC","rule":"char_length","sum":18},{"parent":"FUNC","rule":"check_google_id","sum":1},{"parent":"FUNC","rule":"choosemembers","sum":5},{"parent":"FUNC","rule":"client_id","sum":1},{"parent":"FUNC","rule":"cnt","sum":2},{"parent":"FUNC","rule":"coALESCE","sum":14},{"parent":"FUNC","rule":"coUNT","sum":3},{"parent":"FUNC","rule":"coUNt","sum":3},{"parent":"FUNC","rule":"coalESCE","sum":40},{"parent":"FUNC","rule":"coalescE","sum":1},{"parent":"FUNC","rule":"coalesce","sum":25004966},{"parent":"FUNC","rule":"coalescue","sum":2},{"parent":"FUNC","rule":"coalsece","sum":1},{"parent":"FUNC","rule":"combinemembers","sum":5},{"parent":"FUNC","rule":"concat","sum":26},{"parent":"FUNC","rule":"conunt","sum":1},{"parent":"FUNC","rule":"convert_to_360","sum":2},{"parent":"FUNC","rule":"corr","sum":705},{"parent":"FUNC","rule":"correlation","sum":3843},{"parent":"FUNC","rule":"cos","sum":8},{"parent":"FUNC","rule":"couNT","sum":1},{"parent":"FUNC","rule":"couNT_IF","sum":7},{"parent":"FUNC","rule":"counT","sum":24},{"parent":"FUNC","rule":"count","sum":38648563},{"parent":"FUNC","rule":"countDistinct","sum":1},{"parent":"FUNC","rule":"countDistinctEstimate","sum":270896},{"parent":"FUNC","rule":"countIF","sum":8342},{"parent":"FUNC","rule":"countIf","sum":1389431},{"parent":"FUNC","rule":"count_","sum":553},{"parent":"FUNC","rule":"count_IF","sum":34210},{"parent":"FUNC","rule":"count_If","sum":26535},{"parent":"FUNC","rule":"count_distinct_estimate","sum":33},{"parent":"FUNC","rule":"count_if","sum":18935238},{"parent":"FUNC","rule":"countdistinctEstimate","sum":1777},{"parent":"FUNC","rule":"countdistinctestimate","sum":2856},{"parent":"FUNC","rule":"countif","sum":21044},{"parent":"FUNC","rule":"covar","sum":243},{"parent":"FUNC","rule":"covariance","sum":287},{"parent":"FUNC","rule":"covariance_sample","sum":165},{"parent":"FUNC","rule":"cpunt","sum":1},{"parent":"FUNC","rule":"cume_dist","sum":69},{"parent":"FUNC","rule":"currentTzDate","sum":3981},{"parent":"FUNC","rule":"currentTzTimestamp","sum":53},{"parent":"FUNC","rule":"currentUTCDATETIME","sum":7},{"parent":"FUNC","rule":"currentUTCDate","sum":661},{"parent":"FUNC","rule":"currentUTCDateTime","sum":310},{"parent":"FUNC","rule":"currentUTCdate","sum":365},{"parent":"FUNC","rule":"currentUTCdatetime","sum":20},{"parent":"FUNC","rule":"currentUTcdate","sum":1336},{"parent":"FUNC","rule":"currentUtcDate","sum":6329},{"parent":"FUNC","rule":"currentUtcDateTime","sum":14501},{"parent":"FUNC","rule":"currentUtcDatetime","sum":2383},{"parent":"FUNC","rule":"currentUtcTimestamp","sum":197},{"parent":"FUNC","rule":"current_utc_timestamp","sum":2},{"parent":"FUNC","rule":"currenttzdate","sum":418},{"parent":"FUNC","rule":"currenttzdatetime","sum":261},{"parent":"FUNC","rule":"currenttztimestamp","sum":47},{"parent":"FUNC","rule":"currentutcDateTime","sum":3},{"parent":"FUNC","rule":"currentutcdate","sum":118700},{"parent":"FUNC","rule":"currentutcdatetime","sum":58523},{"parent":"FUNC","rule":"currentutctimestamp","sum":48372},{"parent":"FUNC","rule":"d","sum":1},{"parent":"FUNC","rule":"dATE","sum":4},{"parent":"FUNC","rule":"date","sum":415702},{"parent":"FUNC","rule":"date32","sum":11},{"parent":"FUNC","rule":"dateDiff","sum":1},{"parent":"FUNC","rule":"dateNow","sum":2},{"parent":"FUNC","rule":"dateTIME","sum":2},{"parent":"FUNC","rule":"dateTime","sum":10},{"parent":"FUNC","rule":"date_add","sum":8},{"parent":"FUNC","rule":"date_format","sum":2},{"parent":"FUNC","rule":"date_sub","sum":2},{"parent":"FUNC","rule":"dateadd","sum":1},{"parent":"FUNC","rule":"datetime","sum":11759},{"parent":"FUNC","rule":"datetime64","sum":19},{"parent":"FUNC","rule":"decimal","sum":339},{"parent":"FUNC","rule":"dense_RANK","sum":42},{"parent":"FUNC","rule":"dense_rank","sum":46376},{"parent":"FUNC","rule":"dictAggregate","sum":59},{"parent":"FUNC","rule":"dictContains","sum":7},{"parent":"FUNC","rule":"dictGetString","sum":1},{"parent":"FUNC","rule":"dictItems","sum":8482},{"parent":"FUNC","rule":"dictKeys","sum":1199},{"parent":"FUNC","rule":"dictLength","sum":104},{"parent":"FUNC","rule":"dictLookUp","sum":9327},{"parent":"FUNC","rule":"dictLookup","sum":675},{"parent":"FUNC","rule":"dictPayloads","sum":90},{"parent":"FUNC","rule":"dict_keys","sum":8696},{"parent":"FUNC","rule":"dictcontains","sum":345},{"parent":"FUNC","rule":"dictcreate","sum":2},{"parent":"FUNC","rule":"dicthasitems","sum":24},{"parent":"FUNC","rule":"dictitems","sum":2512},{"parent":"FUNC","rule":"dictkeys","sum":897},{"parent":"FUNC","rule":"dictlength","sum":6530},{"parent":"FUNC","rule":"dictlookup","sum":1591},{"parent":"FUNC","rule":"dictpayloads","sum":113},{"parent":"FUNC","rule":"disctinct","sum":2},{"parent":"FUNC","rule":"dol_show1","sum":1},{"parent":"FUNC","rule":"double","sum":134},{"parent":"FUNC","rule":"dynumber","sum":12},{"parent":"FUNC","rule":"each","sum":1},{"parent":"FUNC","rule":"empty","sum":3},{"parent":"FUNC","rule":"emptylist","sum":1},{"parent":"FUNC","rule":"endsWith","sum":2149},{"parent":"FUNC","rule":"endswith","sum":31680},{"parent":"FUNC","rule":"ensure","sum":409136},{"parent":"FUNC","rule":"ensuretype","sum":708},{"parent":"FUNC","rule":"evaluateCode","sum":51},{"parent":"FUNC","rule":"evaluateExpr","sum":294},{"parent":"FUNC","rule":"expandstruct","sum":20},{"parent":"FUNC","rule":"f","sum":1},{"parent":"FUNC","rule":"file_content","sum":10},{"parent":"FUNC","rule":"file_path","sum":1},{"parent":"FUNC","rule":"filecontent","sum":603},{"parent":"FUNC","rule":"filepath","sum":973},{"parent":"FUNC","rule":"filter","sum":2},{"parent":"FUNC","rule":"find","sum":4070995},{"parent":"FUNC","rule":"first_VALUE","sum":19},{"parent":"FUNC","rule":"first_route_timestamp","sum":1},{"parent":"FUNC","rule":"first_value","sum":1147237},{"parent":"FUNC","rule":"flatten","sum":1},{"parent":"FUNC","rule":"float","sum":23058},{"parent":"FUNC","rule":"floor","sum":1},{"parent":"FUNC","rule":"forceremovemember","sum":373},{"parent":"FUNC","rule":"format","sum":1},{"parent":"FUNC","rule":"formatType","sum":8},{"parent":"FUNC","rule":"formattype","sum":146},{"parent":"FUNC","rule":"fromBytes","sum":13},{"parent":"FUNC","rule":"fromPg","sum":133},{"parent":"FUNC","rule":"fromUnixTimestamp64Micro","sum":1},{"parent":"FUNC","rule":"from_bytes","sum":2},{"parent":"FUNC","rule":"frombytes","sum":47},{"parent":"FUNC","rule":"frompg","sum":130},{"parent":"FUNC","rule":"gatherMembers","sum":67},{"parent":"FUNC","rule":"gathermembers","sum":7},{"parent":"FUNC","rule":"get_auto_label","sum":1},{"parent":"FUNC","rule":"get_html","sum":1},{"parent":"FUNC","rule":"get_is_in_collection_feature","sum":1},{"parent":"FUNC","rule":"get_metrika_bro","sum":1},{"parent":"FUNC","rule":"get_pay_processing","sum":2},{"parent":"FUNC","rule":"get_post_profiles","sum":1},{"parent":"FUNC","rule":"get_rewrite_prompt","sum":1},{"parent":"FUNC","rule":"get_support_line","sum":1},{"parent":"FUNC","rule":"get_test_id","sum":7},{"parent":"FUNC","rule":"getdate","sum":2},{"parent":"FUNC","rule":"greatest","sum":317805},{"parent":"FUNC","rule":"groupArray","sum":4},{"parent":"FUNC","rule":"groupUniqArray","sum":2},{"parent":"FUNC","rule":"grouping","sum":17631},{"parent":"FUNC","rule":"hISTOGRAM","sum":2},{"parent":"FUNC","rule":"has","sum":20},{"parent":"FUNC","rule":"histOGRAM","sum":4},{"parent":"FUNC","rule":"histograM","sum":359},{"parent":"FUNC","rule":"histogram","sum":52723},{"parent":"FUNC","rule":"histogramcdf","sum":84},{"parent":"FUNC","rule":"hll","sum":82176},{"parent":"FUNC","rule":"iF","sum":2691},{"parent":"FUNC","rule":"iNtErVaL","sum":1},{"parent":"FUNC","rule":"if","sum":43202776},{"parent":"FUNC","rule":"ifNull","sum":6},{"parent":"FUNC","rule":"in","sum":13},{"parent":"FUNC","rule":"indexOf","sum":14},{"parent":"FUNC","rule":"instanceof","sum":55},{"parent":"FUNC","rule":"instr","sum":1},{"parent":"FUNC","rule":"int","sum":32408},{"parent":"FUNC","rule":"int32","sum":2},{"parent":"FUNC","rule":"int64","sum":19},{"parent":"FUNC","rule":"int8","sum":2},{"parent":"FUNC","rule":"intervaL","sum":9421},{"parent":"FUNC","rule":"interval","sum":1800579},{"parent":"FUNC","rule":"interval64","sum":7},{"parent":"FUNC","rule":"isNull","sum":7},{"parent":"FUNC","rule":"is_allowed_in_kz","sum":2},{"parent":"FUNC","rule":"is_valid_intent","sum":4},{"parent":"FUNC","rule":"is_valid_organic","sum":4},{"parent":"FUNC","rule":"istLast","sum":1},{"parent":"FUNC","rule":"isum","sum":6},{"parent":"FUNC","rule":"joinTableRow","sum":5},{"parent":"FUNC","rule":"jointablerow","sum":215},{"parent":"FUNC","rule":"json","sum":5627},{"parent":"FUNC","rule":"json_extract","sum":3},{"parent":"FUNC","rule":"json_object_agg","sum":1},{"parent":"FUNC","rule":"jsondocument","sum":6},{"parent":"FUNC","rule":"just","sum":245256},{"parent":"FUNC","rule":"lAG","sum":2244},{"parent":"FUNC","rule":"lEAD","sum":6798},{"parent":"FUNC","rule":"lEN","sum":30},{"parent":"FUNC","rule":"lINEARHISTOGRAM","sum":115},{"parent":"FUNC","rule":"lISTlENGTH","sum":2},{"parent":"FUNC","rule":"lISTlength","sum":1},{"parent":"FUNC","rule":"lag","sum":1012991},{"parent":"FUNC","rule":"last_VALUE","sum":14},{"parent":"FUNC","rule":"last_value","sum":1082017},{"parent":"FUNC","rule":"lead","sum":928409},{"parent":"FUNC","rule":"least","sum":375371},{"parent":"FUNC","rule":"len","sum":712178},{"parent":"FUNC","rule":"lenGTH","sum":1},{"parent":"FUNC","rule":"lenght","sum":1},{"parent":"FUNC","rule":"lengtH","sum":2},{"parent":"FUNC","rule":"length","sum":2552436},{"parent":"FUNC","rule":"like","sum":4},{"parent":"FUNC","rule":"likely","sum":16470},{"parent":"FUNC","rule":"linearHISTOGRAM","sum":10},{"parent":"FUNC","rule":"linearHistogram","sum":14},{"parent":"FUNC","rule":"linearhistogram","sum":174},{"parent":"FUNC","rule":"linearhistogramcdf","sum":20},{"parent":"FUNC","rule":"listALL","sum":3},{"parent":"FUNC","rule":"listAVG","sum":894},{"parent":"FUNC","rule":"listAggregateUnique","sum":1},{"parent":"FUNC","rule":"listAll","sum":86},{"parent":"FUNC","rule":"listAny","sum":121},{"parent":"FUNC","rule":"listAvg","sum":105},{"parent":"FUNC","rule":"listCollect","sum":378},{"parent":"FUNC","rule":"listConcat","sum":11072},{"parent":"FUNC","rule":"listEnumerate","sum":132},{"parent":"FUNC","rule":"listExtend","sum":6711},{"parent":"FUNC","rule":"listExtract","sum":24},{"parent":"FUNC","rule":"listFilter","sum":39834},{"parent":"FUNC","rule":"listFlatten","sum":287},{"parent":"FUNC","rule":"listFold","sum":301},{"parent":"FUNC","rule":"listFromRange","sum":767},{"parent":"FUNC","rule":"listHAs","sum":52},{"parent":"FUNC","rule":"listHas","sum":41607},{"parent":"FUNC","rule":"listHasItems","sum":3253},{"parent":"FUNC","rule":"listHead","sum":2187},{"parent":"FUNC","rule":"listIndexOf","sum":39},{"parent":"FUNC","rule":"listLENGTH","sum":225},{"parent":"FUNC","rule":"listLENgth","sum":2},{"parent":"FUNC","rule":"listLast","sum":1020},{"parent":"FUNC","rule":"listLength","sum":29895},{"parent":"FUNC","rule":"listMAX","sum":1},{"parent":"FUNC","rule":"listMIN","sum":1},{"parent":"FUNC","rule":"listMap","sum":53689},{"parent":"FUNC","rule":"listMax","sum":812},{"parent":"FUNC","rule":"listMin","sum":170},{"parent":"FUNC","rule":"listNotNull","sum":279},{"parent":"FUNC","rule":"listReverse","sum":4483},{"parent":"FUNC","rule":"listSkip","sum":18},{"parent":"FUNC","rule":"listSort","sum":23734},{"parent":"FUNC","rule":"listSortAsc","sum":2},{"parent":"FUNC","rule":"listSortDesc","sum":200},{"parent":"FUNC","rule":"listSum","sum":1473},{"parent":"FUNC","rule":"listTake","sum":728},{"parent":"FUNC","rule":"listTopSort","sum":18},{"parent":"FUNC","rule":"listUniq","sum":10546},{"parent":"FUNC","rule":"listUniqStable","sum":1},{"parent":"FUNC","rule":"listZip","sum":1346},{"parent":"FUNC","rule":"listZipAll","sum":1389},{"parent":"FUNC","rule":"list_Length","sum":1},{"parent":"FUNC","rule":"list_MAX","sum":1},{"parent":"FUNC","rule":"list_agg","sum":2},{"parent":"FUNC","rule":"list_avg","sum":25},{"parent":"FUNC","rule":"list_concat","sum":264},{"parent":"FUNC","rule":"list_filter","sum":2},{"parent":"FUNC","rule":"list_flatten","sum":15},{"parent":"FUNC","rule":"list_has","sum":6267},{"parent":"FUNC","rule":"list_has_items","sum":2},{"parent":"FUNC","rule":"list_head","sum":16},{"parent":"FUNC","rule":"list_length","sum":865},{"parent":"FUNC","rule":"list_map","sum":3},{"parent":"FUNC","rule":"list_max","sum":3},{"parent":"FUNC","rule":"list_min","sum":3},{"parent":"FUNC","rule":"list_not_null","sum":1},{"parent":"FUNC","rule":"list_sort","sum":112},{"parent":"FUNC","rule":"list_uniq","sum":1},{"parent":"FUNC","rule":"list_zip","sum":30},{"parent":"FUNC","rule":"listaggregate","sum":95},{"parent":"FUNC","rule":"listall","sum":13316},{"parent":"FUNC","rule":"listany","sum":15235},{"parent":"FUNC","rule":"listavg","sum":11828},{"parent":"FUNC","rule":"listcollect","sum":505},{"parent":"FUNC","rule":"listconcat","sum":19350},{"parent":"FUNC","rule":"listcreate","sum":10},{"parent":"FUNC","rule":"listenumerate","sum":2077},{"parent":"FUNC","rule":"listextend","sum":3861},{"parent":"FUNC","rule":"listextendstrict","sum":61},{"parent":"FUNC","rule":"listextract","sum":1821},{"parent":"FUNC","rule":"listfilter","sum":102084},{"parent":"FUNC","rule":"listflatmap","sum":7255},{"parent":"FUNC","rule":"listflatten","sum":22749},{"parent":"FUNC","rule":"listfold","sum":16},{"parent":"FUNC","rule":"listfold1map","sum":60},{"parent":"FUNC","rule":"listfromRange","sum":16},{"parent":"FUNC","rule":"listfromrange","sum":14075},{"parent":"FUNC","rule":"listfromtuple","sum":58},{"parent":"FUNC","rule":"listhas","sum":171993},{"parent":"FUNC","rule":"listhasItems","sum":34},{"parent":"FUNC","rule":"listhasitems","sum":10552},{"parent":"FUNC","rule":"listhead","sum":18543},{"parent":"FUNC","rule":"listindexof","sum":1199},{"parent":"FUNC","rule":"listlast","sum":3102},{"parent":"FUNC","rule":"listlength","sum":343429},{"parent":"FUNC","rule":"listmap","sum":517183},{"parent":"FUNC","rule":"listmax","sum":3946},{"parent":"FUNC","rule":"listmin","sum":2671},{"parent":"FUNC","rule":"listnotNull","sum":1},{"parent":"FUNC","rule":"listnotnull","sum":12913},{"parent":"FUNC","rule":"listreplicate","sum":49},{"parent":"FUNC","rule":"listreverse","sum":2241},{"parent":"FUNC","rule":"listskip","sum":1176},{"parent":"FUNC","rule":"listsort","sum":56470},{"parent":"FUNC","rule":"listsortDesc","sum":1},{"parent":"FUNC","rule":"listsortasc","sum":383},{"parent":"FUNC","rule":"listsortdesc","sum":3964},{"parent":"FUNC","rule":"listsum","sum":3414},{"parent":"FUNC","rule":"listtake","sum":16117},{"parent":"FUNC","rule":"listtop","sum":68},{"parent":"FUNC","rule":"listunionall","sum":8},{"parent":"FUNC","rule":"listuniq","sum":25707},{"parent":"FUNC","rule":"listuniqstable","sum":94},{"parent":"FUNC","rule":"listzip","sum":16670},{"parent":"FUNC","rule":"listzipALL","sum":2},{"parent":"FUNC","rule":"listzipAll","sum":15},{"parent":"FUNC","rule":"listzipall","sum":99},{"parent":"FUNC","rule":"log","sum":2},{"parent":"FUNC","rule":"logarithmicHistogram","sum":1},{"parent":"FUNC","rule":"logarithmichistogram","sum":6},{"parent":"FUNC","rule":"loghistogram","sum":1},{"parent":"FUNC","rule":"lower","sum":3},{"parent":"FUNC","rule":"mAX","sum":17},{"parent":"FUNC","rule":"mAX_BY","sum":132},{"parent":"FUNC","rule":"mIN","sum":2},{"parent":"FUNC","rule":"mIN_by","sum":10},{"parent":"FUNC","rule":"maX","sum":6},{"parent":"FUNC","rule":"maX_BY","sum":1},{"parent":"FUNC","rule":"map","sum":2},{"parent":"FUNC","rule":"max","sum":25162892},{"parent":"FUNC","rule":"maxBy","sum":1},{"parent":"FUNC","rule":"maxOf","sum":3545},{"parent":"FUNC","rule":"max_","sum":1},{"parent":"FUNC","rule":"max_BY","sum":2358},{"parent":"FUNC","rule":"max_By","sum":4552},{"parent":"FUNC","rule":"max_OF","sum":8},{"parent":"FUNC","rule":"max_Of","sum":29},{"parent":"FUNC","rule":"max_by","sum":28974444},{"parent":"FUNC","rule":"max_if","sum":3},{"parent":"FUNC","rule":"max_of","sum":1281844},{"parent":"FUNC","rule":"maxby","sum":4088},{"parent":"FUNC","rule":"maxof","sum":853},{"parent":"FUNC","rule":"md5int","sum":1},{"parent":"FUNC","rule":"median","sum":382448},{"parent":"FUNC","rule":"metric_exp","sum":1},{"parent":"FUNC","rule":"min","sum":10266491},{"parent":"FUNC","rule":"minOf","sum":2},{"parent":"FUNC","rule":"min_BY","sum":8618},{"parent":"FUNC","rule":"min_By","sum":6},{"parent":"FUNC","rule":"min_OF","sum":9},{"parent":"FUNC","rule":"min_Of","sum":344},{"parent":"FUNC","rule":"min_by","sum":2330757},{"parent":"FUNC","rule":"min_if","sum":10},{"parent":"FUNC","rule":"min_of","sum":577383},{"parent":"FUNC","rule":"minby","sum":1},{"parent":"FUNC","rule":"minof","sum":98},{"parent":"FUNC","rule":"mode","sum":117625},{"parent":"FUNC","rule":"multiIf","sum":2},{"parent":"FUNC","rule":"multi_aggregate_by","sum":117848},{"parent":"FUNC","rule":"naNVL","sum":16},{"parent":"FUNC","rule":"nanvl","sum":129280},{"parent":"FUNC","rule":"notEmpty","sum":2},{"parent":"FUNC","rule":"nothing","sum":12897},{"parent":"FUNC","rule":"now","sum":16},{"parent":"FUNC","rule":"nth_value","sum":17},{"parent":"FUNC","rule":"ntile","sum":343},{"parent":"FUNC","rule":"nvL","sum":62},{"parent":"FUNC","rule":"nvl","sum":14035630},{"parent":"FUNC","rule":"on","sum":1},{"parent":"FUNC","rule":"optionaltype","sum":161},{"parent":"FUNC","rule":"or","sum":3},{"parent":"FUNC","rule":"order_nr","sum":1},{"parent":"FUNC","rule":"p25","sum":1},{"parent":"FUNC","rule":"p75","sum":1},{"parent":"FUNC","rule":"pERCENTILE","sum":11},{"parent":"FUNC","rule":"parseFile","sum":155},{"parent":"FUNC","rule":"parseForErrors","sum":32},{"parent":"FUNC","rule":"parse_dt_formatted","sum":1},{"parent":"FUNC","rule":"parsefile","sum":11186},{"parent":"FUNC","rule":"percent_rank","sum":2210},{"parent":"FUNC","rule":"percentile","sum":3351868},{"parent":"FUNC","rule":"pgInt2","sum":2},{"parent":"FUNC","rule":"pgarray","sum":2},{"parent":"FUNC","rule":"pgbpchar","sum":2},{"parent":"FUNC","rule":"pgbytea","sum":6},{"parent":"FUNC","rule":"pgcast","sum":39},{"parent":"FUNC","rule":"pgchar","sum":2},{"parent":"FUNC","rule":"pgdate","sum":94},{"parent":"FUNC","rule":"pgfloat4","sum":5},{"parent":"FUNC","rule":"pgfloat8","sum":3},{"parent":"FUNC","rule":"pgint2","sum":9},{"parent":"FUNC","rule":"pginterval","sum":176},{"parent":"FUNC","rule":"pgjson","sum":10},{"parent":"FUNC","rule":"pgname","sum":4},{"parent":"FUNC","rule":"pgnumeric","sum":4},{"parent":"FUNC","rule":"pgoidvector","sum":1},{"parent":"FUNC","rule":"pgtext","sum":9},{"parent":"FUNC","rule":"pgtimestamp","sum":7},{"parent":"FUNC","rule":"pgtimestamptz","sum":4},{"parent":"FUNC","rule":"pickle","sum":501},{"parent":"FUNC","rule":"pow","sum":8},{"parent":"FUNC","rule":"power","sum":3},{"parent":"FUNC","rule":"print","sum":1},{"parent":"FUNC","rule":"quantile","sum":1},{"parent":"FUNC","rule":"quantileExact","sum":1},{"parent":"FUNC","rule":"rFIND","sum":2},{"parent":"FUNC","rule":"rand","sum":5},{"parent":"FUNC","rule":"random","sum":260560},{"parent":"FUNC","rule":"randomNumber","sum":10},{"parent":"FUNC","rule":"randomUuid","sum":153},{"parent":"FUNC","rule":"random_number","sum":11},{"parent":"FUNC","rule":"randomnumber","sum":479},{"parent":"FUNC","rule":"randomuuid","sum":36},{"parent":"FUNC","rule":"range","sum":96},{"parent":"FUNC","rule":"rank","sum":222154},{"parent":"FUNC","rule":"regex_full_match","sum":1},{"parent":"FUNC","rule":"regex_replace_first","sum":1},{"parent":"FUNC","rule":"regionIn","sum":2},{"parent":"FUNC","rule":"removeMember","sum":160},{"parent":"FUNC","rule":"removemember","sum":18},{"parent":"FUNC","rule":"removemembers","sum":77},{"parent":"FUNC","rule":"removetimezone","sum":5},{"parent":"FUNC","rule":"renamemembers","sum":4},{"parent":"FUNC","rule":"replace","sum":1},{"parent":"FUNC","rule":"replaceRegexpAll","sum":2},{"parent":"FUNC","rule":"rfind","sum":127953},{"parent":"FUNC","rule":"round","sum":27},{"parent":"FUNC","rule":"row_NUMBER","sum":5},{"parent":"FUNC","rule":"row_Number","sum":3},{"parent":"FUNC","rule":"row_number","sum":2182073},{"parent":"FUNC","rule":"rownumber","sum":392},{"parent":"FUNC","rule":"sUBSTRING","sum":3},{"parent":"FUNC","rule":"sUM","sum":445},{"parent":"FUNC","rule":"sUM_IF","sum":20},{"parent":"FUNC","rule":"sUm","sum":8},{"parent":"FUNC","rule":"sessionWindow","sum":4},{"parent":"FUNC","rule":"session_start","sum":3},{"parent":"FUNC","rule":"sessionwindow","sum":172},{"parent":"FUNC","rule":"setDifference","sum":59},{"parent":"FUNC","rule":"setIntersection","sum":13},{"parent":"FUNC","rule":"setIsDisjoint","sum":1},{"parent":"FUNC","rule":"setUnion","sum":172},{"parent":"FUNC","rule":"setbit","sum":20},{"parent":"FUNC","rule":"setdifference","sum":171},{"parent":"FUNC","rule":"setincludes","sum":20},{"parent":"FUNC","rule":"setintersection","sum":122},{"parent":"FUNC","rule":"setisdisjoint","sum":1052},{"parent":"FUNC","rule":"setsymmetricdifference","sum":204},{"parent":"FUNC","rule":"setunion","sum":1790},{"parent":"FUNC","rule":"sign","sum":1},{"parent":"FUNC","rule":"sin","sum":16},{"parent":"FUNC","rule":"sipHash64","sum":2},{"parent":"FUNC","rule":"size","sum":1},{"parent":"FUNC","rule":"somE","sum":2},{"parent":"FUNC","rule":"some","sum":20357950},{"parent":"FUNC","rule":"somr","sum":1},{"parent":"FUNC","rule":"splitByChar","sum":1},{"parent":"FUNC","rule":"splitByString","sum":6},{"parent":"FUNC","rule":"spreadmembers","sum":3},{"parent":"FUNC","rule":"sqrt","sum":11},{"parent":"FUNC","rule":"ssubstring","sum":2},{"parent":"FUNC","rule":"stablepickle","sum":30},{"parent":"FUNC","rule":"startsWith","sum":200060},{"parent":"FUNC","rule":"starts_with","sum":14},{"parent":"FUNC","rule":"startswith","sum":20547},{"parent":"FUNC","rule":"staticmap","sum":22},{"parent":"FUNC","rule":"staticzip","sum":1},{"parent":"FUNC","rule":"status$$name","sum":3},{"parent":"FUNC","rule":"std_dev","sum":4},{"parent":"FUNC","rule":"stddev","sum":619791},{"parent":"FUNC","rule":"stddevPop","sum":13},{"parent":"FUNC","rule":"stddev_pop","sum":108},{"parent":"FUNC","rule":"stddev_population","sum":88},{"parent":"FUNC","rule":"stddev_samp","sum":27},{"parent":"FUNC","rule":"stddev_sample","sum":887},{"parent":"FUNC","rule":"stddevpop","sum":19},{"parent":"FUNC","rule":"stddevsamp","sum":5},{"parent":"FUNC","rule":"str","sum":15},{"parent":"FUNC","rule":"strfdate","sum":164},{"parent":"FUNC","rule":"string","sum":77},{"parent":"FUNC","rule":"string_agg","sum":1},{"parent":"FUNC","rule":"string_split","sum":1},{"parent":"FUNC","rule":"string_to_array","sum":3},{"parent":"FUNC","rule":"string_to_features","sum":1},{"parent":"FUNC","rule":"structMembers","sum":7},{"parent":"FUNC","rule":"structUnion","sum":41},{"parent":"FUNC","rule":"structdifference","sum":2},{"parent":"FUNC","rule":"structunion","sum":7},{"parent":"FUNC","rule":"suM","sum":185},{"parent":"FUNC","rule":"suM_if","sum":16},{"parent":"FUNC","rule":"subDate","sum":1},{"parent":"FUNC","rule":"subSTRING","sum":1},{"parent":"FUNC","rule":"subString","sum":581},{"parent":"FUNC","rule":"subqueryMergeFor","sum":21},{"parent":"FUNC","rule":"subqueryUnionMergeFor","sum":4390},{"parent":"FUNC","rule":"subquerymergefor","sum":1944},{"parent":"FUNC","rule":"subsTRING","sum":2},{"parent":"FUNC","rule":"subsrting","sum":3},{"parent":"FUNC","rule":"substing","sum":2},{"parent":"FUNC","rule":"substr","sum":173},{"parent":"FUNC","rule":"substring","sum":16541675},{"parent":"FUNC","rule":"substringUTF8","sum":1},{"parent":"FUNC","rule":"substring_index","sum":1},{"parent":"FUNC","rule":"sum","sum":45408099},{"parent":"FUNC","rule":"sumIF","sum":84},{"parent":"FUNC","rule":"sumIf","sum":94459},{"parent":"FUNC","rule":"sum_","sum":356},{"parent":"FUNC","rule":"sum_IF","sum":19531},{"parent":"FUNC","rule":"sum_If","sum":13050},{"parent":"FUNC","rule":"sum_if","sum":4234406},{"parent":"FUNC","rule":"sum_range2","sum":47},{"parent":"FUNC","rule":"sum_recursive_range","sum":1},{"parent":"FUNC","rule":"suma","sum":1},{"parent":"FUNC","rule":"sumif","sum":7488},{"parent":"FUNC","rule":"summ","sum":10},{"parent":"FUNC","rule":"sunstring","sum":2},{"parent":"FUNC","rule":"susbstring","sum":1},{"parent":"FUNC","rule":"tableName","sum":43283},{"parent":"FUNC","rule":"tablePath","sum":1488},{"parent":"FUNC","rule":"tableRecordIndex","sum":19},{"parent":"FUNC","rule":"tableRow","sum":22906},{"parent":"FUNC","rule":"table_name","sum":2893},{"parent":"FUNC","rule":"table_path","sum":46},{"parent":"FUNC","rule":"table_row","sum":377},{"parent":"FUNC","rule":"tablename","sum":165832},{"parent":"FUNC","rule":"tablepath","sum":32965},{"parent":"FUNC","rule":"tablerecordindex","sum":111},{"parent":"FUNC","rule":"tablerow","sum":42768},{"parent":"FUNC","rule":"tablerows","sum":5},{"parent":"FUNC","rule":"testBit","sum":34},{"parent":"FUNC","rule":"testbit","sum":39091},{"parent":"FUNC","rule":"testid","sum":2},{"parent":"FUNC","rule":"timestamp","sum":9976},{"parent":"FUNC","rule":"timestamp64","sum":7},{"parent":"FUNC","rule":"timezone","sum":2},{"parent":"FUNC","rule":"toBytes","sum":25779},{"parent":"FUNC","rule":"toDate","sum":57},{"parent":"FUNC","rule":"toDate32","sum":10},{"parent":"FUNC","rule":"toDateTime","sum":21},{"parent":"FUNC","rule":"toDateTimeOrNull","sum":3},{"parent":"FUNC","rule":"toDayOfWeek","sum":2},{"parent":"FUNC","rule":"toDict","sum":96413},{"parent":"FUNC","rule":"toFloat32","sum":4},{"parent":"FUNC","rule":"toInt128","sum":3},{"parent":"FUNC","rule":"toIntervalMonth","sum":2},{"parent":"FUNC","rule":"toLastDayOfMonth","sum":1},{"parent":"FUNC","rule":"toMonth","sum":1},{"parent":"FUNC","rule":"toMultiDict","sum":264},{"parent":"FUNC","rule":"toQuarter","sum":1},{"parent":"FUNC","rule":"toSet","sum":437979},{"parent":"FUNC","rule":"toStartOfMonth","sum":15},{"parent":"FUNC","rule":"toStartOfQuarter","sum":1},{"parent":"FUNC","rule":"toStartOfWeek","sum":9},{"parent":"FUNC","rule":"toString","sum":46},{"parent":"FUNC","rule":"toUInt64","sum":5},{"parent":"FUNC","rule":"toUnixTimestamp","sum":2},{"parent":"FUNC","rule":"toUnixTimestamp64Micro","sum":2},{"parent":"FUNC","rule":"toYear","sum":9},{"parent":"FUNC","rule":"to_bytes","sum":36},{"parent":"FUNC","rule":"to_char","sum":2},{"parent":"FUNC","rule":"to_date","sum":4},{"parent":"FUNC","rule":"to_dict","sum":65},{"parent":"FUNC","rule":"tobytes","sum":154},{"parent":"FUNC","rule":"today","sum":1},{"parent":"FUNC","rule":"todict","sum":100936},{"parent":"FUNC","rule":"tomultidict","sum":1164},{"parent":"FUNC","rule":"top","sum":54498},{"parent":"FUNC","rule":"topFreq","sum":95},{"parent":"FUNC","rule":"top_BY","sum":1},{"parent":"FUNC","rule":"top_by","sum":115758},{"parent":"FUNC","rule":"top_freq","sum":108},{"parent":"FUNC","rule":"topfreq","sum":23295},{"parent":"FUNC","rule":"topg","sum":2},{"parent":"FUNC","rule":"toset","sum":38801},{"parent":"FUNC","rule":"trunc","sum":13},{"parent":"FUNC","rule":"truncate","sum":2},{"parent":"FUNC","rule":"tryMember","sum":527},{"parent":"FUNC","rule":"trymember","sum":10140},{"parent":"FUNC","rule":"tupleElement","sum":2},{"parent":"FUNC","rule":"typeOf","sum":38},{"parent":"FUNC","rule":"typeof","sum":407},{"parent":"FUNC","rule":"tzdate","sum":8},{"parent":"FUNC","rule":"tzdate32","sum":7},{"parent":"FUNC","rule":"tzdatetime","sum":44},{"parent":"FUNC","rule":"tzdatetime64","sum":7},{"parent":"FUNC","rule":"tztimestamp","sum":35},{"parent":"FUNC","rule":"tztimestamp64","sum":7},{"parent":"FUNC","rule":"uNWRAP","sum":112},{"parent":"FUNC","rule":"udaf","sum":17583},{"parent":"FUNC","rule":"uint32","sum":13570},{"parent":"FUNC","rule":"uint64","sum":31},{"parent":"FUNC","rule":"uint8","sum":2},{"parent":"FUNC","rule":"unWRap","sum":3},{"parent":"FUNC","rule":"unWrap","sum":5},{"parent":"FUNC","rule":"uniq","sum":9},{"parent":"FUNC","rule":"uniqExact","sum":10},{"parent":"FUNC","rule":"unique","sum":1},{"parent":"FUNC","rule":"unique_pairs","sum":1},{"parent":"FUNC","rule":"unnest","sum":3},{"parent":"FUNC","rule":"untag","sum":1327},{"parent":"FUNC","rule":"unwrap","sum":27087950},{"parent":"FUNC","rule":"unwraped","sum":1},{"parent":"FUNC","rule":"upper","sum":2},{"parent":"FUNC","rule":"using","sum":12},{"parent":"FUNC","rule":"utc_action_created_dttm","sum":1},{"parent":"FUNC","rule":"utf8","sum":2038},{"parent":"FUNC","rule":"uuid","sum":25},{"parent":"FUNC","rule":"values","sum":6},{"parent":"FUNC","rule":"varPop","sum":77},{"parent":"FUNC","rule":"varSamp","sum":85},{"parent":"FUNC","rule":"var_samp","sum":43},{"parent":"FUNC","rule":"variance","sum":66655},{"parent":"FUNC","rule":"variance_population","sum":4},{"parent":"FUNC","rule":"variance_sample","sum":524},{"parent":"FUNC","rule":"varpop","sum":19},{"parent":"FUNC","rule":"version","sum":19},{"parent":"FUNC","rule":"vl","sum":2},{"parent":"FUNC","rule":"void","sum":1},{"parent":"FUNC","rule":"way","sum":42003},{"parent":"FUNC","rule":"weakField","sum":1077},{"parent":"FUNC","rule":"weakfield","sum":981176},{"parent":"FUNC","rule":"windowFunnel","sum":1},{"parent":"FUNC","rule":"worked_rules","sum":3},{"parent":"FUNC","rule":"wrap","sum":1},{"parent":"FUNC","rule":"yesterday","sum":4},{"parent":"FUNC","rule":"yson","sum":42},{"parent":"FUNC","rule":"ytListTables","sum":1},{"parent":"INSERT_HINT","rule":"COLUMN_GROUPS","sum":74},{"parent":"INSERT_HINT","rule":"COMPRESSION_CODEC","sum":855557},{"parent":"INSERT_HINT","rule":"ERASURE_CODEC","sum":67540},{"parent":"INSERT_HINT","rule":"EXPIRATION","sum":7127820},{"parent":"INSERT_HINT","rule":"Expiration","sum":175},{"parent":"INSERT_HINT","rule":"KEEPMETA","sum":10},{"parent":"INSERT_HINT","rule":"KEEP_META","sum":113218},{"parent":"INSERT_HINT","rule":"MODE","sum":2},{"parent":"INSERT_HINT","rule":"MONOTONIC_KEYS","sum":429636},{"parent":"INSERT_HINT","rule":"PRIMARY_MEDIUM","sum":88663},{"parent":"INSERT_HINT","rule":"REPLICATION_FACTOR","sum":7397},{"parent":"INSERT_HINT","rule":"SECURITY_TAGS","sum":4776},{"parent":"INSERT_HINT","rule":"TRUNCATE","sum":111356671},{"parent":"INSERT_HINT","rule":"TRUNCATe","sum":315},{"parent":"INSERT_HINT","rule":"TRUNCAtE","sum":3},{"parent":"INSERT_HINT","rule":"TRUNCAte","sum":11},{"parent":"INSERT_HINT","rule":"TRUNCaTE","sum":2},{"parent":"INSERT_HINT","rule":"TRUNCate","sum":10},{"parent":"INSERT_HINT","rule":"TRUNcATE","sum":6},{"parent":"INSERT_HINT","rule":"TRUnCATE","sum":1},{"parent":"INSERT_HINT","rule":"TRUncATE","sum":318},{"parent":"INSERT_HINT","rule":"TRUncate","sum":10},{"parent":"INSERT_HINT","rule":"TRuNCATE","sum":2},{"parent":"INSERT_HINT","rule":"TRuncaTE","sum":1},{"parent":"INSERT_HINT","rule":"TRuncate","sum":50},{"parent":"INSERT_HINT","rule":"TrUNCATE","sum":1},{"parent":"INSERT_HINT","rule":"Truncate","sum":4648},{"parent":"INSERT_HINT","rule":"USER_ATTRS","sum":2065234},{"parent":"INSERT_HINT","rule":"XLOCK","sum":1},{"parent":"INSERT_HINT","rule":"column_groups","sum":6440},{"parent":"INSERT_HINT","rule":"compression_codec","sum":2014},{"parent":"INSERT_HINT","rule":"erasure_codec","sum":3154},{"parent":"INSERT_HINT","rule":"expiration","sum":336077},{"parent":"INSERT_HINT","rule":"keep_meta","sum":134655},{"parent":"INSERT_HINT","rule":"monotonic_keys","sum":15},{"parent":"INSERT_HINT","rule":"primary_medium","sum":11528},{"parent":"INSERT_HINT","rule":"replication_factor","sum":1},{"parent":"INSERT_HINT","rule":"tRUNCATE","sum":1},{"parent":"INSERT_HINT","rule":"tRUNCAte","sum":1},{"parent":"INSERT_HINT","rule":"trUNCATE","sum":19},{"parent":"INSERT_HINT","rule":"truNCATE","sum":2},{"parent":"INSERT_HINT","rule":"trunCATE","sum":7},{"parent":"INSERT_HINT","rule":"truncate","sum":30986213},{"parent":"INSERT_HINT","rule":"user_attr","sum":1},{"parent":"INSERT_HINT","rule":"user_attrs","sum":66589},{"parent":"MODULE","rule":"Compress","sum":84351},{"parent":"MODULE","rule":"DATETIME","sum":1128},{"parent":"MODULE","rule":"DATEtime","sum":2},{"parent":"MODULE","rule":"DAteTime","sum":3233},{"parent":"MODULE","rule":"DAtetime","sum":7},{"parent":"MODULE","rule":"DIgest","sum":2},{"parent":"MODULE","rule":"DaTETIME","sum":334},{"parent":"MODULE","rule":"DaTeTime","sum":84},{"parent":"MODULE","rule":"DateTIME","sum":723},{"parent":"MODULE","rule":"DateTIme","sum":4369},{"parent":"MODULE","rule":"DateTime","sum":275534815},{"parent":"MODULE","rule":"DatetIme","sum":367},{"parent":"MODULE","rule":"Datetime","sum":7107067},{"parent":"MODULE","rule":"Decompress","sum":24698},{"parent":"MODULE","rule":"Digest","sum":7713118},{"parent":"MODULE","rule":"HyperScan","sum":2302},{"parent":"MODULE","rule":"Hyperscan","sum":389661},{"parent":"MODULE","rule":"Ip","sum":1348011},{"parent":"MODULE","rule":"JSON","sum":26908},{"parent":"MODULE","rule":"JSon","sum":2},{"parent":"MODULE","rule":"Json","sum":1012853},{"parent":"MODULE","rule":"MATH","sum":196},{"parent":"MODULE","rule":"Math","sum":44904674},{"parent":"MODULE","rule":"PG","sum":199},{"parent":"MODULE","rule":"PIRE","sum":29},{"parent":"MODULE","rule":"Pg","sum":4885},{"parent":"MODULE","rule":"PgAgg","sum":2},{"parent":"MODULE","rule":"PgProc","sum":2},{"parent":"MODULE","rule":"Pire","sum":1913457},{"parent":"MODULE","rule":"Protobuf","sum":270337},{"parent":"MODULE","rule":"RE2","sum":5148},{"parent":"MODULE","rule":"Re2","sum":12193295},{"parent":"MODULE","rule":"STRING","sum":6},{"parent":"MODULE","rule":"String","sum":95484074},{"parent":"MODULE","rule":"TryDecompress","sum":4761},{"parent":"MODULE","rule":"URL","sum":7},{"parent":"MODULE","rule":"Unicode","sum":4914960},{"parent":"MODULE","rule":"Url","sum":23538071},{"parent":"MODULE","rule":"YSON","sum":205},{"parent":"MODULE","rule":"YSon","sum":23},{"parent":"MODULE","rule":"Yson","sum":395534558},{"parent":"MODULE","rule":"dateTime","sum":471},{"parent":"MODULE","rule":"datetime","sum":14194},{"parent":"MODULE","rule":"digest","sum":15},{"parent":"MODULE","rule":"json","sum":8},{"parent":"MODULE","rule":"math","sum":68},{"parent":"MODULE","rule":"pg","sum":1796},{"parent":"MODULE","rule":"pire","sum":36},{"parent":"MODULE","rule":"re2","sum":3215},{"parent":"MODULE","rule":"string","sum":85},{"parent":"MODULE","rule":"url","sum":5},{"parent":"MODULE","rule":"ySoN","sum":1},{"parent":"MODULE","rule":"yson","sum":63},{"parent":"MODULE_FUNC","rule":"Compress::BZip2","sum":2},{"parent":"MODULE_FUNC","rule":"Compress::BlockCodec","sum":6},{"parent":"MODULE_FUNC","rule":"Compress::Brotli","sum":158},{"parent":"MODULE_FUNC","rule":"Compress::Gzip","sum":83368},{"parent":"MODULE_FUNC","rule":"Compress::Lz4","sum":623},{"parent":"MODULE_FUNC","rule":"Compress::Lzma","sum":7},{"parent":"MODULE_FUNC","rule":"Compress::Snappy","sum":7},{"parent":"MODULE_FUNC","rule":"Compress::Zlib","sum":32},{"parent":"MODULE_FUNC","rule":"Compress::Zstd","sum":148},{"parent":"MODULE_FUNC","rule":"DATETIME::Format","sum":10},{"parent":"MODULE_FUNC","rule":"DATETIME::FromMilliseconds","sum":49},{"parent":"MODULE_FUNC","rule":"DATETIME::FromSeconds","sum":1},{"parent":"MODULE_FUNC","rule":"DATETIME::GetYear","sum":18},{"parent":"MODULE_FUNC","rule":"DATETIME::MakeDate","sum":742},{"parent":"MODULE_FUNC","rule":"DATETIME::MakeDatetime","sum":285},{"parent":"MODULE_FUNC","rule":"DATETIME::Parse","sum":9},{"parent":"MODULE_FUNC","rule":"DATETIME::StartOfWeek","sum":14},{"parent":"MODULE_FUNC","rule":"DATEtime::GetMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DATEtime::GetYear","sum":1},{"parent":"MODULE_FUNC","rule":"DAteTime::FromSeconds","sum":1},{"parent":"MODULE_FUNC","rule":"DAteTime::GetDayOfMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DAteTime::MakeDate","sum":584},{"parent":"MODULE_FUNC","rule":"DAteTime::Parse","sum":150},{"parent":"MODULE_FUNC","rule":"DAteTime::StartOfMonth","sum":2488},{"parent":"MODULE_FUNC","rule":"DAteTime::StartOfWeek","sum":1},{"parent":"MODULE_FUNC","rule":"DAteTime::ToDays","sum":8},{"parent":"MODULE_FUNC","rule":"DAtetime::FromSeconds","sum":1},{"parent":"MODULE_FUNC","rule":"DAtetime::MakeDatetime","sum":2},{"parent":"MODULE_FUNC","rule":"DAtetime::ToStartOfWeek","sum":4},{"parent":"MODULE_FUNC","rule":"DIgest::SipHash","sum":2},{"parent":"MODULE_FUNC","rule":"DaTETIME::StartOfWeek","sum":334},{"parent":"MODULE_FUNC","rule":"DaTeTime::GetMonth","sum":4},{"parent":"MODULE_FUNC","rule":"DaTeTime::GetYear","sum":4},{"parent":"MODULE_FUNC","rule":"DaTeTime::IntervalFromDays","sum":1},{"parent":"MODULE_FUNC","rule":"DaTeTime::MakeDate","sum":32},{"parent":"MODULE_FUNC","rule":"DaTeTime::ShiftMonths","sum":42},{"parent":"MODULE_FUNC","rule":"DaTeTime::StartOfMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTIME::IntervalFromDays","sum":723},{"parent":"MODULE_FUNC","rule":"DateTIme::EndOfMonth","sum":3},{"parent":"MODULE_FUNC","rule":"DateTIme::Format","sum":11},{"parent":"MODULE_FUNC","rule":"DateTIme::FromMicroseconds","sum":11},{"parent":"MODULE_FUNC","rule":"DateTIme::FromSeconds","sum":64},{"parent":"MODULE_FUNC","rule":"DateTIme::GetDayOfWeek","sum":44},{"parent":"MODULE_FUNC","rule":"DateTIme::GetHour","sum":2},{"parent":"MODULE_FUNC","rule":"DateTIme::GetMinute","sum":38},{"parent":"MODULE_FUNC","rule":"DateTIme::GetYear","sum":71},{"parent":"MODULE_FUNC","rule":"DateTIme::IntervalFromDays","sum":46},{"parent":"MODULE_FUNC","rule":"DateTIme::MakeDate","sum":3622},{"parent":"MODULE_FUNC","rule":"DateTIme::MakeDatetime","sum":284},{"parent":"MODULE_FUNC","rule":"DateTIme::MakeTimestamp","sum":7},{"parent":"MODULE_FUNC","rule":"DateTIme::MakeTzTimestamp","sum":4},{"parent":"MODULE_FUNC","rule":"DateTIme::Parse","sum":2},{"parent":"MODULE_FUNC","rule":"DateTIme::ParseIso8601","sum":2},{"parent":"MODULE_FUNC","rule":"DateTIme::ShiftMonths","sum":6},{"parent":"MODULE_FUNC","rule":"DateTIme::StartOfMonth","sum":135},{"parent":"MODULE_FUNC","rule":"DateTIme::StartOfWeek","sum":1},{"parent":"MODULE_FUNC","rule":"DateTIme::ToDays","sum":13},{"parent":"MODULE_FUNC","rule":"DateTIme::ToHours","sum":1},{"parent":"MODULE_FUNC","rule":"DateTIme::ToMinutes","sum":1},{"parent":"MODULE_FUNC","rule":"DateTIme::ToSeconds","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::AddTimezone","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Convert","sum":4},{"parent":"MODULE_FUNC","rule":"DateTime::CurrentDate","sum":5},{"parent":"MODULE_FUNC","rule":"DateTime::CurrentDateTimeUTC","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::CurrentUtcDate","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Date","sum":4},{"parent":"MODULE_FUNC","rule":"DateTime::DateTime","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::DatetimeStartOfMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::DayOfWeek","sum":7},{"parent":"MODULE_FUNC","rule":"DateTime::Days","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::DiffMinutes","sum":8},{"parent":"MODULE_FUNC","rule":"DateTime::DiffMonths","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Difference","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::EndOf","sum":28},{"parent":"MODULE_FUNC","rule":"DateTime::EndOfDay","sum":418},{"parent":"MODULE_FUNC","rule":"DateTime::EndOfMonth","sum":39075},{"parent":"MODULE_FUNC","rule":"DateTime::EndOfQuarter","sum":306},{"parent":"MODULE_FUNC","rule":"DateTime::EndOfWeek","sum":615},{"parent":"MODULE_FUNC","rule":"DateTime::EndOfYear","sum":145},{"parent":"MODULE_FUNC","rule":"DateTime::EndofMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::EndtOfMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::ExtractHour","sum":4},{"parent":"MODULE_FUNC","rule":"DateTime::FROMMilliseconds","sum":14},{"parent":"MODULE_FUNC","rule":"DateTime::FROMSeconds","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::Format","sum":39855318},{"parent":"MODULE_FUNC","rule":"DateTime::FormatTime","sum":6},{"parent":"MODULE_FUNC","rule":"DateTime::FromDays","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::FromMicroSeconds","sum":240},{"parent":"MODULE_FUNC","rule":"DateTime::FromMicroseconds","sum":4686487},{"parent":"MODULE_FUNC","rule":"DateTime::FromMicroseconds64","sum":126},{"parent":"MODULE_FUNC","rule":"DateTime::FromMilliSeconds","sum":7},{"parent":"MODULE_FUNC","rule":"DateTime::FromMilliseconds","sum":9219972},{"parent":"MODULE_FUNC","rule":"DateTime::FromMilliseconds64","sum":997},{"parent":"MODULE_FUNC","rule":"DateTime::FromSecond","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::FromSeconds","sum":15195569},{"parent":"MODULE_FUNC","rule":"DateTime::FromSeconds64","sum":985},{"parent":"MODULE_FUNC","rule":"DateTime::FromString","sum":368},{"parent":"MODULE_FUNC","rule":"DateTime::FromTimeZone","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::Fromat","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::GetDay","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::GetDayOfMonth","sum":597594},{"parent":"MODULE_FUNC","rule":"DateTime::GetDayOfWeek","sum":637048},{"parent":"MODULE_FUNC","rule":"DateTime::GetDayOfWeekName","sum":126013},{"parent":"MODULE_FUNC","rule":"DateTime::GetDayOfYear","sum":44540},{"parent":"MODULE_FUNC","rule":"DateTime::GetHour","sum":1454427},{"parent":"MODULE_FUNC","rule":"DateTime::GetIntervalLength","sum":12},{"parent":"MODULE_FUNC","rule":"DateTime::GetLastDayOfMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::GetMicrosecondOfSecond","sum":1248},{"parent":"MODULE_FUNC","rule":"DateTime::GetMillisecondOfSecond","sum":31},{"parent":"MODULE_FUNC","rule":"DateTime::GetMinute","sum":288786},{"parent":"MODULE_FUNC","rule":"DateTime::GetMonth","sum":705134},{"parent":"MODULE_FUNC","rule":"DateTime::GetMonthName","sum":38934},{"parent":"MODULE_FUNC","rule":"DateTime::GetMonthOfYear","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::GetSecond","sum":85926},{"parent":"MODULE_FUNC","rule":"DateTime::GetTimezoneId","sum":104},{"parent":"MODULE_FUNC","rule":"DateTime::GetTimezoneName","sum":520},{"parent":"MODULE_FUNC","rule":"DateTime::GetWeek","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::GetWeekOfYear","sum":504483},{"parent":"MODULE_FUNC","rule":"DateTime::GetWeekOfYearIso8601","sum":34508},{"parent":"MODULE_FUNC","rule":"DateTime::GetYEAR","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::GetYear","sum":786911},{"parent":"MODULE_FUNC","rule":"DateTime::Getmonth","sum":16},{"parent":"MODULE_FUNC","rule":"DateTime::Interval","sum":33},{"parent":"MODULE_FUNC","rule":"DateTime::Interval64FromDays","sum":2220},{"parent":"MODULE_FUNC","rule":"DateTime::Interval64FromHours","sum":4358},{"parent":"MODULE_FUNC","rule":"DateTime::Interval64FromMicroseconds","sum":9},{"parent":"MODULE_FUNC","rule":"DateTime::Interval64FromMilliseconds","sum":8},{"parent":"MODULE_FUNC","rule":"DateTime::Interval64FromMinutes","sum":193},{"parent":"MODULE_FUNC","rule":"DateTime::Interval64FromSeconds","sum":133},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFROMDays","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFrom","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromDays","sum":15024513},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromHDays","sum":28},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromHours","sum":8962513},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromMicroseconds","sum":77727},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromMilliseconds","sum":516031},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromMinute","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromMinutes","sum":4276219},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromMonth","sum":9},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromMonths","sum":7},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromSeconds","sum":934655},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromYears","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalfromDays","sum":29},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalfromHours","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::LastDayOfMonth","sum":6},{"parent":"MODULE_FUNC","rule":"DateTime::MakeData","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::MakeDate","sum":23176904},{"parent":"MODULE_FUNC","rule":"DateTime::MakeDate32","sum":73},{"parent":"MODULE_FUNC","rule":"DateTime::MakeDateTime","sum":273},{"parent":"MODULE_FUNC","rule":"DateTime::MakeDatetime","sum":36661736},{"parent":"MODULE_FUNC","rule":"DateTime::MakeDatetime64","sum":114},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTimestamp","sum":7841906},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTimestamp64","sum":295},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTzDate","sum":262565},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTzDate32","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTzDateTime","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTzDatetime","sum":3126666},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTzDatetime64","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTzTimestamp","sum":153628},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTzTimestamp64","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::Makedate","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Makedatetime","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::MilliSeconds","sum":156},{"parent":"MODULE_FUNC","rule":"DateTime::NOW","sum":4},{"parent":"MODULE_FUNC","rule":"DateTime::Now","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::Parce","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Parse","sum":23548906},{"parent":"MODULE_FUNC","rule":"DateTime::Parse64","sum":13},{"parent":"MODULE_FUNC","rule":"DateTime::Parse8601","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::ParseDateTime","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::ParseDateTimeBestEffort","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::ParseFromString","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::ParseHttp","sum":26993},{"parent":"MODULE_FUNC","rule":"DateTime::ParseIso","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::ParseIso8601","sum":18557078},{"parent":"MODULE_FUNC","rule":"DateTime::ParseRfc822","sum":1861},{"parent":"MODULE_FUNC","rule":"DateTime::ParseX509","sum":245},{"parent":"MODULE_FUNC","rule":"DateTime::STartOfWeek","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Shift","sum":4},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftDay","sum":51},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftDays","sum":191},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftMinutes","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftMonth","sum":11},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftMonths","sum":3307661},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftQuarters","sum":389086},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftWeek","sum":7},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftWeeks","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftYears","sum":673368},{"parent":"MODULE_FUNC","rule":"DateTime::Split","sum":699782},{"parent":"MODULE_FUNC","rule":"DateTime::StartOf","sum":2340429},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfDay","sum":2654510},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfHour","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfMohth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfMonth","sum":4159745},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfQuarter","sum":555462},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfWeek","sum":2076212},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfYear","sum":943983},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfmonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfweek","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::TimeOfDay","sum":66946},{"parent":"MODULE_FUNC","rule":"DateTime::TimestampFromMicroSeconds","sum":364},{"parent":"MODULE_FUNC","rule":"DateTime::TimestampFromMilliSeconds","sum":2503},{"parent":"MODULE_FUNC","rule":"DateTime::TimestampFromMinutes","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::TimestampFromSeconds","sum":391},{"parent":"MODULE_FUNC","rule":"DateTime::TimestampFromString","sum":423},{"parent":"MODULE_FUNC","rule":"DateTime::TimestampStartOfMonth","sum":820},{"parent":"MODULE_FUNC","rule":"DateTime::TimestampStartOfWeek","sum":398},{"parent":"MODULE_FUNC","rule":"DateTime::To","sum":5},{"parent":"MODULE_FUNC","rule":"DateTime::ToDate","sum":1430},{"parent":"MODULE_FUNC","rule":"DateTime::ToDateTime","sum":6},{"parent":"MODULE_FUNC","rule":"DateTime::ToDays","sum":3470339},{"parent":"MODULE_FUNC","rule":"DateTime::ToHours","sum":1320622},{"parent":"MODULE_FUNC","rule":"DateTime::ToIsoFormat","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::ToMicroseconds","sum":2224035},{"parent":"MODULE_FUNC","rule":"DateTime::ToMilliseconds","sum":5310594},{"parent":"MODULE_FUNC","rule":"DateTime::ToMinutes","sum":861212},{"parent":"MODULE_FUNC","rule":"DateTime::ToMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::ToMonths","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::ToSeconds","sum":23418049},{"parent":"MODULE_FUNC","rule":"DateTime::ToSeconds64","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Today","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Toseconds","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Trunc","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Update","sum":3591013},{"parent":"MODULE_FUNC","rule":"DateTime::format","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::fromSeconds","sum":15},{"parent":"MODULE_FUNC","rule":"DateTime::parse","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::parseiso8601","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::toDate","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::toMinutes","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::toSeconds","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::toStartOfMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::todate","sum":1},{"parent":"MODULE_FUNC","rule":"DatetIme::IntervalFromDays","sum":367},{"parent":"MODULE_FUNC","rule":"Datetime::CurrentDate","sum":2},{"parent":"MODULE_FUNC","rule":"Datetime::CurrentUtcDatetime","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::DaysInMonth","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::EndOfMonth","sum":195},{"parent":"MODULE_FUNC","rule":"Datetime::EndOfWeek","sum":71},{"parent":"MODULE_FUNC","rule":"Datetime::Format","sum":366153},{"parent":"MODULE_FUNC","rule":"Datetime::FromMicroseconds","sum":36341},{"parent":"MODULE_FUNC","rule":"Datetime::FromMilliseconds","sum":789662},{"parent":"MODULE_FUNC","rule":"Datetime::FromSeconds","sum":567592},{"parent":"MODULE_FUNC","rule":"Datetime::FromSeconds64","sum":24},{"parent":"MODULE_FUNC","rule":"Datetime::GetDay","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::GetDayOfMonth","sum":709},{"parent":"MODULE_FUNC","rule":"Datetime::GetDayOfWeek","sum":12423},{"parent":"MODULE_FUNC","rule":"Datetime::GetDayOfWeekName","sum":838},{"parent":"MODULE_FUNC","rule":"Datetime::GetDayOfYear","sum":59},{"parent":"MODULE_FUNC","rule":"Datetime::GetHour","sum":14707},{"parent":"MODULE_FUNC","rule":"Datetime::GetMinute","sum":13778},{"parent":"MODULE_FUNC","rule":"Datetime::GetMonth","sum":1037},{"parent":"MODULE_FUNC","rule":"Datetime::GetMonthName","sum":345},{"parent":"MODULE_FUNC","rule":"Datetime::GetWeekOfYear","sum":2705},{"parent":"MODULE_FUNC","rule":"Datetime::GetWeekOfYearIso8601","sum":3},{"parent":"MODULE_FUNC","rule":"Datetime::GetYear","sum":2735},{"parent":"MODULE_FUNC","rule":"Datetime::Interval","sum":9},{"parent":"MODULE_FUNC","rule":"Datetime::IntervalFROMDays","sum":8},{"parent":"MODULE_FUNC","rule":"Datetime::IntervalFromDays","sum":372724},{"parent":"MODULE_FUNC","rule":"Datetime::IntervalFromHours","sum":266318},{"parent":"MODULE_FUNC","rule":"Datetime::IntervalFromMicroseconds","sum":194},{"parent":"MODULE_FUNC","rule":"Datetime::IntervalFromMilliseconds","sum":91},{"parent":"MODULE_FUNC","rule":"Datetime::IntervalFromMinutes","sum":50015},{"parent":"MODULE_FUNC","rule":"Datetime::IntervalFromSeconds","sum":9639},{"parent":"MODULE_FUNC","rule":"Datetime::MakeDate","sum":679780},{"parent":"MODULE_FUNC","rule":"Datetime::MakeDate32","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::MakeDateTime","sum":2},{"parent":"MODULE_FUNC","rule":"Datetime::MakeDatetime","sum":921448},{"parent":"MODULE_FUNC","rule":"Datetime::MakeDatetime64","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::MakeTimestamp","sum":416088},{"parent":"MODULE_FUNC","rule":"Datetime::MakeTzDate","sum":2312},{"parent":"MODULE_FUNC","rule":"Datetime::MakeTzDatetime","sum":24016},{"parent":"MODULE_FUNC","rule":"Datetime::MakeTzTimestamp","sum":33325},{"parent":"MODULE_FUNC","rule":"Datetime::Makedate","sum":37},{"parent":"MODULE_FUNC","rule":"Datetime::Parse","sum":138318},{"parent":"MODULE_FUNC","rule":"Datetime::ParseIso8601","sum":258024},{"parent":"MODULE_FUNC","rule":"Datetime::ShiftMonths","sum":25923},{"parent":"MODULE_FUNC","rule":"Datetime::ShiftQuarters","sum":554},{"parent":"MODULE_FUNC","rule":"Datetime::ShiftYears","sum":318},{"parent":"MODULE_FUNC","rule":"Datetime::Split","sum":207},{"parent":"MODULE_FUNC","rule":"Datetime::StarOfWeek","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::StartOf","sum":64225},{"parent":"MODULE_FUNC","rule":"Datetime::StartOfDay","sum":23114},{"parent":"MODULE_FUNC","rule":"Datetime::StartOfMonth","sum":74651},{"parent":"MODULE_FUNC","rule":"Datetime::StartOfQuarter","sum":4402},{"parent":"MODULE_FUNC","rule":"Datetime::StartOfWeek","sum":23006},{"parent":"MODULE_FUNC","rule":"Datetime::StartOfYear","sum":11664},{"parent":"MODULE_FUNC","rule":"Datetime::TimeOfDay","sum":125},{"parent":"MODULE_FUNC","rule":"Datetime::ToDatetime","sum":12},{"parent":"MODULE_FUNC","rule":"Datetime::ToDays","sum":141728},{"parent":"MODULE_FUNC","rule":"Datetime::ToHours","sum":22949},{"parent":"MODULE_FUNC","rule":"Datetime::ToMicroseconds","sum":585},{"parent":"MODULE_FUNC","rule":"Datetime::ToMilliseconds","sum":121727},{"parent":"MODULE_FUNC","rule":"Datetime::ToMinutes","sum":45248},{"parent":"MODULE_FUNC","rule":"Datetime::ToSeconds","sum":1535357},{"parent":"MODULE_FUNC","rule":"Datetime::Update","sum":29536},{"parent":"MODULE_FUNC","rule":"Datetime::split","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::startOfmonth","sum":2},{"parent":"MODULE_FUNC","rule":"Decompress::BZip2","sum":525},{"parent":"MODULE_FUNC","rule":"Decompress::Brotli","sum":7863},{"parent":"MODULE_FUNC","rule":"Decompress::Gzip","sum":3914},{"parent":"MODULE_FUNC","rule":"Decompress::Lz4","sum":902},{"parent":"MODULE_FUNC","rule":"Decompress::Snappy","sum":461},{"parent":"MODULE_FUNC","rule":"Decompress::Zlib","sum":11002},{"parent":"MODULE_FUNC","rule":"Decompress::Zstd","sum":31},{"parent":"MODULE_FUNC","rule":"Digest::Argon2","sum":48524},{"parent":"MODULE_FUNC","rule":"Digest::Blake2B","sum":4530},{"parent":"MODULE_FUNC","rule":"Digest::CityHash","sum":1226103},{"parent":"MODULE_FUNC","rule":"Digest::CityHash128","sum":18003},{"parent":"MODULE_FUNC","rule":"Digest::Crc32c","sum":77270},{"parent":"MODULE_FUNC","rule":"Digest::Crc64","sum":140659},{"parent":"MODULE_FUNC","rule":"Digest::FarmHashFingerprint","sum":70089},{"parent":"MODULE_FUNC","rule":"Digest::FarmHashFingerprint128","sum":26},{"parent":"MODULE_FUNC","rule":"Digest::FarmHashFingerprint2","sum":166688},{"parent":"MODULE_FUNC","rule":"Digest::FarmHashFingerprint32","sum":208},{"parent":"MODULE_FUNC","rule":"Digest::FarmHashFingerprint64","sum":1051883},{"parent":"MODULE_FUNC","rule":"Digest::Fnv32","sum":1747},{"parent":"MODULE_FUNC","rule":"Digest::Fnv64","sum":260976},{"parent":"MODULE_FUNC","rule":"Digest::IntHash64","sum":18246},{"parent":"MODULE_FUNC","rule":"Digest::MD5Hex","sum":6},{"parent":"MODULE_FUNC","rule":"Digest::Md5","sum":2},{"parent":"MODULE_FUNC","rule":"Digest::Md5HalfMix","sum":427858},{"parent":"MODULE_FUNC","rule":"Digest::Md5Hex","sum":568663},{"parent":"MODULE_FUNC","rule":"Digest::Md5Raw","sum":15705},{"parent":"MODULE_FUNC","rule":"Digest::MurMurHash","sum":2423211},{"parent":"MODULE_FUNC","rule":"Digest::MurMurHash2A","sum":2503},{"parent":"MODULE_FUNC","rule":"Digest::MurMurHash2A32","sum":837},{"parent":"MODULE_FUNC","rule":"Digest::MurMurHash32","sum":256178},{"parent":"MODULE_FUNC","rule":"Digest::MurMurhash","sum":2},{"parent":"MODULE_FUNC","rule":"Digest::NimericHash","sum":3},{"parent":"MODULE_FUNC","rule":"Digest::NumericHash","sum":275478},{"parent":"MODULE_FUNC","rule":"Digest::Sha1","sum":42539},{"parent":"MODULE_FUNC","rule":"Digest::Sha256","sum":399849},{"parent":"MODULE_FUNC","rule":"Digest::SipHash","sum":132502},{"parent":"MODULE_FUNC","rule":"Digest::SuperFastHash","sum":34987},{"parent":"MODULE_FUNC","rule":"Digest::XXH3","sum":47821},{"parent":"MODULE_FUNC","rule":"Digest::XXH3_128","sum":19},{"parent":"MODULE_FUNC","rule":"Digest::murmurhash","sum":3},{"parent":"MODULE_FUNC","rule":"HyperScan::BacktrackingGrep","sum":1},{"parent":"MODULE_FUNC","rule":"HyperScan::Grep","sum":2295},{"parent":"MODULE_FUNC","rule":"HyperScan::Match","sum":6},{"parent":"MODULE_FUNC","rule":"Hyperscan::BacktrackingGrep","sum":48625},{"parent":"MODULE_FUNC","rule":"Hyperscan::BacktrackingMatch","sum":128},{"parent":"MODULE_FUNC","rule":"Hyperscan::Capture","sum":5607},{"parent":"MODULE_FUNC","rule":"Hyperscan::Grep","sum":144904},{"parent":"MODULE_FUNC","rule":"Hyperscan::Match","sum":52758},{"parent":"MODULE_FUNC","rule":"Hyperscan::MultiGrep","sum":64},{"parent":"MODULE_FUNC","rule":"Hyperscan::MultiMatch","sum":40583},{"parent":"MODULE_FUNC","rule":"Hyperscan::Replace","sum":96992},{"parent":"MODULE_FUNC","rule":"Ip::ConvertToIPv6","sum":44980},{"parent":"MODULE_FUNC","rule":"Ip::FromString","sum":391561},{"parent":"MODULE_FUNC","rule":"Ip::GetSubnet","sum":135463},{"parent":"MODULE_FUNC","rule":"Ip::GetSubnetByMask","sum":4},{"parent":"MODULE_FUNC","rule":"Ip::IsEmbeddedIPv4","sum":6951},{"parent":"MODULE_FUNC","rule":"Ip::IsIPv4","sum":136021},{"parent":"MODULE_FUNC","rule":"Ip::IsIPv6","sum":118459},{"parent":"MODULE_FUNC","rule":"Ip::SubnetFromString","sum":549},{"parent":"MODULE_FUNC","rule":"Ip::SubnetMatch","sum":502},{"parent":"MODULE_FUNC","rule":"Ip::ToFixedIPv6String","sum":3818},{"parent":"MODULE_FUNC","rule":"Ip::ToString","sum":509703},{"parent":"MODULE_FUNC","rule":"JSON::ConvertToDouble","sum":19612},{"parent":"MODULE_FUNC","rule":"JSON::ConvertToInt64","sum":3261},{"parent":"MODULE_FUNC","rule":"JSON::ConvertToList","sum":15},{"parent":"MODULE_FUNC","rule":"JSON::ConvertToString","sum":133},{"parent":"MODULE_FUNC","rule":"JSON::ConvertToStringList","sum":4},{"parent":"MODULE_FUNC","rule":"JSON::From","sum":5},{"parent":"MODULE_FUNC","rule":"JSON::LookupBool","sum":5},{"parent":"MODULE_FUNC","rule":"JSON::LookupDouble","sum":10},{"parent":"MODULE_FUNC","rule":"JSON::LookupInt64","sum":8},{"parent":"MODULE_FUNC","rule":"JSON::LookupString","sum":255},{"parent":"MODULE_FUNC","rule":"JSON::PARSE","sum":2},{"parent":"MODULE_FUNC","rule":"JSON::Parse","sum":3598},{"parent":"MODULE_FUNC","rule":"JSon::From","sum":2},{"parent":"MODULE_FUNC","rule":"Json::Attributes","sum":2},{"parent":"MODULE_FUNC","rule":"Json::Contains","sum":1},{"parent":"MODULE_FUNC","rule":"Json::ConvertToBool","sum":5},{"parent":"MODULE_FUNC","rule":"Json::ConvertToDict","sum":114},{"parent":"MODULE_FUNC","rule":"Json::ConvertToDouble","sum":1},{"parent":"MODULE_FUNC","rule":"Json::ConvertToInt64","sum":1},{"parent":"MODULE_FUNC","rule":"Json::ConvertToList","sum":108},{"parent":"MODULE_FUNC","rule":"Json::ConvertToString","sum":161},{"parent":"MODULE_FUNC","rule":"Json::ConvertToStringDict","sum":5},{"parent":"MODULE_FUNC","rule":"Json::ConvertToStringList","sum":19},{"parent":"MODULE_FUNC","rule":"Json::From","sum":3925},{"parent":"MODULE_FUNC","rule":"Json::FromString","sum":16},{"parent":"MODULE_FUNC","rule":"Json::GetField","sum":21},{"parent":"MODULE_FUNC","rule":"Json::GetHash","sum":1},{"parent":"MODULE_FUNC","rule":"Json::GetLength","sum":19},{"parent":"MODULE_FUNC","rule":"Json::Lookup","sum":1},{"parent":"MODULE_FUNC","rule":"Json::LookupInt64","sum":821061},{"parent":"MODULE_FUNC","rule":"Json::LookupString","sum":53},{"parent":"MODULE_FUNC","rule":"Json::Options","sum":852},{"parent":"MODULE_FUNC","rule":"Json::Parse","sum":182633},{"parent":"MODULE_FUNC","rule":"Json::ParseJson","sum":213},{"parent":"MODULE_FUNC","rule":"Json::Serialize","sum":1557},{"parent":"MODULE_FUNC","rule":"Json::SerializeJson","sum":922},{"parent":"MODULE_FUNC","rule":"Json::SerializePretty","sum":1124},{"parent":"MODULE_FUNC","rule":"Json::SerializeText","sum":3},{"parent":"MODULE_FUNC","rule":"Json::YPath","sum":20},{"parent":"MODULE_FUNC","rule":"Json::YPathDict","sum":14},{"parent":"MODULE_FUNC","rule":"Json::YPathString","sum":1},{"parent":"MODULE_FUNC","rule":"MATH::ABS","sum":1},{"parent":"MODULE_FUNC","rule":"MATH::Cos","sum":5},{"parent":"MODULE_FUNC","rule":"MATH::EXP","sum":1},{"parent":"MODULE_FUNC","rule":"MATH::Log","sum":5},{"parent":"MODULE_FUNC","rule":"MATH::NearbyINT","sum":1},{"parent":"MODULE_FUNC","rule":"MATH::NearbyInt","sum":1},{"parent":"MODULE_FUNC","rule":"MATH::ROUND","sum":181},{"parent":"MODULE_FUNC","rule":"MATH::Round","sum":1},{"parent":"MODULE_FUNC","rule":"Math::Aabs","sum":1},{"parent":"MODULE_FUNC","rule":"Math::Abs","sum":477545},{"parent":"MODULE_FUNC","rule":"Math::Acos","sum":13419},{"parent":"MODULE_FUNC","rule":"Math::Asin","sum":11346},{"parent":"MODULE_FUNC","rule":"Math::Asinh","sum":4},{"parent":"MODULE_FUNC","rule":"Math::Atan","sum":7921},{"parent":"MODULE_FUNC","rule":"Math::Atan2","sum":13117},{"parent":"MODULE_FUNC","rule":"Math::Cbrt","sum":494},{"parent":"MODULE_FUNC","rule":"Math::Ceil","sum":1246311},{"parent":"MODULE_FUNC","rule":"Math::Cos","sum":97796},{"parent":"MODULE_FUNC","rule":"Math::Cosh","sum":5},{"parent":"MODULE_FUNC","rule":"Math::Crbt","sum":1},{"parent":"MODULE_FUNC","rule":"Math::E","sum":9612},{"parent":"MODULE_FUNC","rule":"Math::EXP","sum":1},{"parent":"MODULE_FUNC","rule":"Math::Eps","sum":179},{"parent":"MODULE_FUNC","rule":"Math::Erf","sum":2573},{"parent":"MODULE_FUNC","rule":"Math::ErfInv","sum":42},{"parent":"MODULE_FUNC","rule":"Math::ErfcInv","sum":6},{"parent":"MODULE_FUNC","rule":"Math::Exp","sum":557302},{"parent":"MODULE_FUNC","rule":"Math::Exp2","sum":1998},{"parent":"MODULE_FUNC","rule":"Math::Fabs","sum":144438},{"parent":"MODULE_FUNC","rule":"Math::Floor","sum":327974},{"parent":"MODULE_FUNC","rule":"Math::Flor","sum":1},{"parent":"MODULE_FUNC","rule":"Math::Fmod","sum":9},{"parent":"MODULE_FUNC","rule":"Math::FuzzyEquals","sum":19564},{"parent":"MODULE_FUNC","rule":"Math::Hypot","sum":18758},{"parent":"MODULE_FUNC","rule":"Math::IsFinite","sum":186970},{"parent":"MODULE_FUNC","rule":"Math::IsInf","sum":77157},{"parent":"MODULE_FUNC","rule":"Math::IsNaN","sum":250333},{"parent":"MODULE_FUNC","rule":"Math::IsNan","sum":6},{"parent":"MODULE_FUNC","rule":"Math::Ldexp","sum":47},{"parent":"MODULE_FUNC","rule":"Math::Lgamma","sum":4},{"parent":"MODULE_FUNC","rule":"Math::Log","sum":822848},{"parent":"MODULE_FUNC","rule":"Math::Log10","sum":153514},{"parent":"MODULE_FUNC","rule":"Math::Log2","sum":197742},{"parent":"MODULE_FUNC","rule":"Math::Max","sum":3},{"parent":"MODULE_FUNC","rule":"Math::Min","sum":1},{"parent":"MODULE_FUNC","rule":"Math::Mod","sum":66547},{"parent":"MODULE_FUNC","rule":"Math::NearbyInt","sum":429031},{"parent":"MODULE_FUNC","rule":"Math::Pi","sum":74683},{"parent":"MODULE_FUNC","rule":"Math::Pow","sum":1332305},{"parent":"MODULE_FUNC","rule":"Math::Power","sum":6},{"parent":"MODULE_FUNC","rule":"Math::ROUND","sum":5},{"parent":"MODULE_FUNC","rule":"Math::Rem","sum":2269},{"parent":"MODULE_FUNC","rule":"Math::Remainder","sum":163},{"parent":"MODULE_FUNC","rule":"Math::Rint","sum":20412},{"parent":"MODULE_FUNC","rule":"Math::Round","sum":36763997},{"parent":"MODULE_FUNC","rule":"Math::RoundDownward","sum":138580},{"parent":"MODULE_FUNC","rule":"Math::RoundToNearest","sum":76617},{"parent":"MODULE_FUNC","rule":"Math::RoundTowardZero","sum":894},{"parent":"MODULE_FUNC","rule":"Math::RoundUpward","sum":213012},{"parent":"MODULE_FUNC","rule":"Math::Sigmoid","sum":279208},{"parent":"MODULE_FUNC","rule":"Math::Sin","sum":82930},{"parent":"MODULE_FUNC","rule":"Math::Sinh","sum":6026},{"parent":"MODULE_FUNC","rule":"Math::Sqrt","sum":612692},{"parent":"MODULE_FUNC","rule":"Math::Tan","sum":4994},{"parent":"MODULE_FUNC","rule":"Math::Tanh","sum":4962},{"parent":"MODULE_FUNC","rule":"Math::Tgamma","sum":60},{"parent":"MODULE_FUNC","rule":"Math::Trunc","sum":156126},{"parent":"MODULE_FUNC","rule":"Math::abs","sum":2},{"parent":"MODULE_FUNC","rule":"Math::ceil","sum":8},{"parent":"MODULE_FUNC","rule":"Math::cos","sum":2},{"parent":"MODULE_FUNC","rule":"Math::exp","sum":6},{"parent":"MODULE_FUNC","rule":"Math::floor","sum":30},{"parent":"MODULE_FUNC","rule":"Math::isnan","sum":1},{"parent":"MODULE_FUNC","rule":"Math::round","sum":59},{"parent":"MODULE_FUNC","rule":"Math::sin","sum":2},{"parent":"MODULE_FUNC","rule":"Math::sqrt","sum":3},{"parent":"MODULE_FUNC","rule":"PG::ARRAY_AGG","sum":7},{"parent":"MODULE_FUNC","rule":"PG::STRING_AGG","sum":37},{"parent":"MODULE_FUNC","rule":"PG::generate_series","sum":7},{"parent":"MODULE_FUNC","rule":"PG::json_object_keys","sum":19},{"parent":"MODULE_FUNC","rule":"PG::jsonb_object_keys","sum":18},{"parent":"MODULE_FUNC","rule":"PG::string_agg","sum":102},{"parent":"MODULE_FUNC","rule":"PG::to_hex","sum":9},{"parent":"MODULE_FUNC","rule":"PIRE::Capture","sum":7},{"parent":"MODULE_FUNC","rule":"PIRE::Grep","sum":22},{"parent":"MODULE_FUNC","rule":"Pg::ARRAY_AGG","sum":11},{"parent":"MODULE_FUNC","rule":"Pg::Array_Agg","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::CONCAT","sum":12},{"parent":"MODULE_FUNC","rule":"Pg::Date","sum":3},{"parent":"MODULE_FUNC","rule":"Pg::GENERATE_SERIES","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::SPLIT_PART","sum":5},{"parent":"MODULE_FUNC","rule":"Pg::STRING_AGG","sum":50},{"parent":"MODULE_FUNC","rule":"Pg::ST_Area","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::ST_AsEWKB","sum":57},{"parent":"MODULE_FUNC","rule":"Pg::ST_AsEWKT","sum":15},{"parent":"MODULE_FUNC","rule":"Pg::ST_AsGeoJSON","sum":7},{"parent":"MODULE_FUNC","rule":"Pg::ST_AsSVG","sum":3},{"parent":"MODULE_FUNC","rule":"Pg::ST_AsText","sum":57},{"parent":"MODULE_FUNC","rule":"Pg::ST_Boundary","sum":43},{"parent":"MODULE_FUNC","rule":"Pg::ST_Centroid","sum":14},{"parent":"MODULE_FUNC","rule":"Pg::ST_ClosestPoint","sum":37},{"parent":"MODULE_FUNC","rule":"Pg::ST_Contains","sum":3},{"parent":"MODULE_FUNC","rule":"Pg::ST_Distance","sum":13},{"parent":"MODULE_FUNC","rule":"Pg::ST_GeoHash","sum":15},{"parent":"MODULE_FUNC","rule":"Pg::ST_GeomFromEWKB","sum":86},{"parent":"MODULE_FUNC","rule":"Pg::ST_GeomFromGeoHash","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::ST_GeomFromText","sum":65},{"parent":"MODULE_FUNC","rule":"Pg::ST_GeomFromWKB","sum":7},{"parent":"MODULE_FUNC","rule":"Pg::ST_Intersects","sum":13},{"parent":"MODULE_FUNC","rule":"Pg::ST_IsValid","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::ST_MakePoint","sum":7},{"parent":"MODULE_FUNC","rule":"Pg::ST_MakeValid","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::ST_Point","sum":6},{"parent":"MODULE_FUNC","rule":"Pg::ST_PointOnSurface","sum":17},{"parent":"MODULE_FUNC","rule":"Pg::ST_Scale","sum":3},{"parent":"MODULE_FUNC","rule":"Pg::ST_SetSRID","sum":6},{"parent":"MODULE_FUNC","rule":"Pg::ST_Transform","sum":183},{"parent":"MODULE_FUNC","rule":"Pg::ST_X","sum":72},{"parent":"MODULE_FUNC","rule":"Pg::ST_Y","sum":66},{"parent":"MODULE_FUNC","rule":"Pg::St_geomfromewkb","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::String_Agg","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::age","sum":8},{"parent":"MODULE_FUNC","rule":"Pg::array_agg","sum":6},{"parent":"MODULE_FUNC","rule":"Pg::array_length","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::bit_length","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::center","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::concat","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::date_generate_series","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::date_part","sum":8},{"parent":"MODULE_FUNC","rule":"Pg::date_trunc","sum":11},{"parent":"MODULE_FUNC","rule":"Pg::extract","sum":136},{"parent":"MODULE_FUNC","rule":"Pg::generate_series","sum":1514},{"parent":"MODULE_FUNC","rule":"Pg::json_object_agg","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::lower","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::max","sum":364},{"parent":"MODULE_FUNC","rule":"Pg::sind","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::split_part","sum":20},{"parent":"MODULE_FUNC","rule":"Pg::st_asgeojson","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::st_astext","sum":6},{"parent":"MODULE_FUNC","rule":"Pg::st_collect","sum":8},{"parent":"MODULE_FUNC","rule":"Pg::st_geomfromewkb","sum":22},{"parent":"MODULE_FUNC","rule":"Pg::st_intersects","sum":9},{"parent":"MODULE_FUNC","rule":"Pg::st_transform","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::st_union","sum":8},{"parent":"MODULE_FUNC","rule":"Pg::string_Agg","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::string_agg","sum":1765},{"parent":"MODULE_FUNC","rule":"Pg::to_char","sum":18},{"parent":"MODULE_FUNC","rule":"Pg::to_timestamp","sum":74},{"parent":"MODULE_FUNC","rule":"Pg::version","sum":3},{"parent":"MODULE_FUNC","rule":"PgAgg::string_agg","sum":2},{"parent":"MODULE_FUNC","rule":"PgProc::upper","sum":2},{"parent":"MODULE_FUNC","rule":"Pire::Capture","sum":528571},{"parent":"MODULE_FUNC","rule":"Pire::Grep","sum":144310},{"parent":"MODULE_FUNC","rule":"Pire::Match","sum":234577},{"parent":"MODULE_FUNC","rule":"Pire::MultiGrep","sum":686},{"parent":"MODULE_FUNC","rule":"Pire::MultiMatch","sum":152},{"parent":"MODULE_FUNC","rule":"Pire::Replace","sum":1005161},{"parent":"MODULE_FUNC","rule":"Protobuf::Parse","sum":21066},{"parent":"MODULE_FUNC","rule":"Protobuf::Serialize","sum":103753},{"parent":"MODULE_FUNC","rule":"Protobuf::TryParse","sum":145518},{"parent":"MODULE_FUNC","rule":"RE2::Capture","sum":4031},{"parent":"MODULE_FUNC","rule":"RE2::Count","sum":353},{"parent":"MODULE_FUNC","rule":"RE2::FindAndConsume","sum":31},{"parent":"MODULE_FUNC","rule":"RE2::Grep","sum":66},{"parent":"MODULE_FUNC","rule":"RE2::Match","sum":543},{"parent":"MODULE_FUNC","rule":"RE2::Replace","sum":124},{"parent":"MODULE_FUNC","rule":"Re2::Capture","sum":4405242},{"parent":"MODULE_FUNC","rule":"Re2::Catch","sum":1},{"parent":"MODULE_FUNC","rule":"Re2::Compile","sum":4},{"parent":"MODULE_FUNC","rule":"Re2::Count","sum":172465},{"parent":"MODULE_FUNC","rule":"Re2::FindAll","sum":2},{"parent":"MODULE_FUNC","rule":"Re2::FindAllSubmatch","sum":2},{"parent":"MODULE_FUNC","rule":"Re2::FindAndConsume","sum":389745},{"parent":"MODULE_FUNC","rule":"Re2::Grep","sum":653247},{"parent":"MODULE_FUNC","rule":"Re2::Match","sum":1686112},{"parent":"MODULE_FUNC","rule":"Re2::Options","sum":247912},{"parent":"MODULE_FUNC","rule":"Re2::Replace","sum":4638548},{"parent":"MODULE_FUNC","rule":"Re2::ReplaceAll","sum":15},{"parent":"MODULE_FUNC","rule":"STRING::AsciiToLower","sum":1},{"parent":"MODULE_FUNC","rule":"STRING::Contains","sum":2},{"parent":"MODULE_FUNC","rule":"STRING::RemoveAll","sum":1},{"parent":"MODULE_FUNC","rule":"STRING::SplitToList","sum":2},{"parent":"MODULE_FUNC","rule":"String::ASciiToLower","sum":2},{"parent":"MODULE_FUNC","rule":"String::AsciiToLower","sum":4122676},{"parent":"MODULE_FUNC","rule":"String::AsciiToTitle","sum":95633},{"parent":"MODULE_FUNC","rule":"String::AsciiToUpper","sum":548149},{"parent":"MODULE_FUNC","rule":"String::AsciiTolower","sum":5},{"parent":"MODULE_FUNC","rule":"String::Base32Decode","sum":275},{"parent":"MODULE_FUNC","rule":"String::Base32Encode","sum":194},{"parent":"MODULE_FUNC","rule":"String::Base32StrictDecode","sum":56},{"parent":"MODULE_FUNC","rule":"String::Base64Decode","sum":395027},{"parent":"MODULE_FUNC","rule":"String::Base64Encode","sum":112504},{"parent":"MODULE_FUNC","rule":"String::Base64EncodeUrl","sum":5737},{"parent":"MODULE_FUNC","rule":"String::Base64StrictDecode","sum":96549},{"parent":"MODULE_FUNC","rule":"String::Bin","sum":497},{"parent":"MODULE_FUNC","rule":"String::BinText","sum":121},{"parent":"MODULE_FUNC","rule":"String::CgiEscape","sum":72277},{"parent":"MODULE_FUNC","rule":"String::CgiUnescape","sum":24032},{"parent":"MODULE_FUNC","rule":"String::ColapseText","sum":4},{"parent":"MODULE_FUNC","rule":"String::Collapse","sum":198521},{"parent":"MODULE_FUNC","rule":"String::CollapseText","sum":200705},{"parent":"MODULE_FUNC","rule":"String::Contains","sum":6168048},{"parent":"MODULE_FUNC","rule":"String::DecodeHtml","sum":3040},{"parent":"MODULE_FUNC","rule":"String::EncodeHtml","sum":415},{"parent":"MODULE_FUNC","rule":"String::EndsWith","sum":539162},{"parent":"MODULE_FUNC","rule":"String::EndsWithIgnoreCase","sum":36087},{"parent":"MODULE_FUNC","rule":"String::EscapeC","sum":56112},{"parent":"MODULE_FUNC","rule":"String::Find","sum":654242},{"parent":"MODULE_FUNC","rule":"String::From","sum":2},{"parent":"MODULE_FUNC","rule":"String::FromByteList","sum":1046873},{"parent":"MODULE_FUNC","rule":"String::HasPrefix","sum":21339},{"parent":"MODULE_FUNC","rule":"String::HasPrefixIgnoreCase","sum":49},{"parent":"MODULE_FUNC","rule":"String::HasSuffix","sum":4922},{"parent":"MODULE_FUNC","rule":"String::HasSuffixIgnoreCase","sum":28702},{"parent":"MODULE_FUNC","rule":"String::Hex","sum":377608},{"parent":"MODULE_FUNC","rule":"String::HexDecode","sum":165852},{"parent":"MODULE_FUNC","rule":"String::HexEncode","sum":194850},{"parent":"MODULE_FUNC","rule":"String::HexText","sum":79183},{"parent":"MODULE_FUNC","rule":"String::HumanReadableBytes","sum":259},{"parent":"MODULE_FUNC","rule":"String::HumanReadableDuration","sum":1124415},{"parent":"MODULE_FUNC","rule":"String::HumanReadableQuantity","sum":342},{"parent":"MODULE_FUNC","rule":"String::IsAscii","sum":13988},{"parent":"MODULE_FUNC","rule":"String::IsAsciiAlnum","sum":1011},{"parent":"MODULE_FUNC","rule":"String::IsAsciiAlpha","sum":392},{"parent":"MODULE_FUNC","rule":"String::IsAsciiDigit","sum":8407},{"parent":"MODULE_FUNC","rule":"String::IsAsciiHex","sum":19424},{"parent":"MODULE_FUNC","rule":"String::IsAsciiLower","sum":22},{"parent":"MODULE_FUNC","rule":"String::IsAsciiSpace","sum":13},{"parent":"MODULE_FUNC","rule":"String::IsAsciiUpper","sum":357},{"parent":"MODULE_FUNC","rule":"String::Join","sum":2},{"parent":"MODULE_FUNC","rule":"String::JoinFROMList","sum":31824},{"parent":"MODULE_FUNC","rule":"String::JoinFromList","sum":14012536},{"parent":"MODULE_FUNC","rule":"String::LeftPad","sum":66086},{"parent":"MODULE_FUNC","rule":"String::Length","sum":2},{"parent":"MODULE_FUNC","rule":"String::LevenshteinDistance","sum":4},{"parent":"MODULE_FUNC","rule":"String::LevensteinDistance","sum":11760},{"parent":"MODULE_FUNC","rule":"String::Prec","sum":1847},{"parent":"MODULE_FUNC","rule":"String::RaplaceAll","sum":3},{"parent":"MODULE_FUNC","rule":"String::RemoveAll","sum":1248612},{"parent":"MODULE_FUNC","rule":"String::RemoveFirst","sum":641513},{"parent":"MODULE_FUNC","rule":"String::RemoveLast","sum":557607},{"parent":"MODULE_FUNC","rule":"String::Replace","sum":11},{"parent":"MODULE_FUNC","rule":"String::ReplaceALL","sum":3},{"parent":"MODULE_FUNC","rule":"String::ReplaceAll","sum":15670754},{"parent":"MODULE_FUNC","rule":"String::ReplaceFirst","sum":1365972},{"parent":"MODULE_FUNC","rule":"String::ReplaceFirstStartsWith","sum":1},{"parent":"MODULE_FUNC","rule":"String::ReplaceLast","sum":174029},{"parent":"MODULE_FUNC","rule":"String::ReplaceRegex","sum":1},{"parent":"MODULE_FUNC","rule":"String::Reverse","sum":119021},{"parent":"MODULE_FUNC","rule":"String::ReverseFind","sum":38830},{"parent":"MODULE_FUNC","rule":"String::RightPad","sum":374102},{"parent":"MODULE_FUNC","rule":"String::SBin","sum":7},{"parent":"MODULE_FUNC","rule":"String::SHex","sum":6279},{"parent":"MODULE_FUNC","rule":"String::Split","sum":10},{"parent":"MODULE_FUNC","rule":"String::SplitToList","sum":31836924},{"parent":"MODULE_FUNC","rule":"String::SplitToSet","sum":12},{"parent":"MODULE_FUNC","rule":"String::StartWith","sum":1},{"parent":"MODULE_FUNC","rule":"String::StartsWith","sum":3456482},{"parent":"MODULE_FUNC","rule":"String::StartsWithIgnoreCase","sum":56217},{"parent":"MODULE_FUNC","rule":"String::Strip","sum":3179583},{"parent":"MODULE_FUNC","rule":"String::Substring","sum":302682},{"parent":"MODULE_FUNC","rule":"String::ToByteList","sum":140412},{"parent":"MODULE_FUNC","rule":"String::ToLower","sum":5268432},{"parent":"MODULE_FUNC","rule":"String::ToLowerCase","sum":1},{"parent":"MODULE_FUNC","rule":"String::ToTitle","sum":34574},{"parent":"MODULE_FUNC","rule":"String::ToUpper","sum":140660},{"parent":"MODULE_FUNC","rule":"String::Trim","sum":3},{"parent":"MODULE_FUNC","rule":"String::UnescapeC","sum":329189},{"parent":"MODULE_FUNC","rule":"String::contains","sum":3},{"parent":"MODULE_FUNC","rule":"String::splittolist","sum":1},{"parent":"MODULE_FUNC","rule":"String::tolower","sum":2},{"parent":"MODULE_FUNC","rule":"TryDecompress::BZip2","sum":4},{"parent":"MODULE_FUNC","rule":"TryDecompress::BlockCodec","sum":1},{"parent":"MODULE_FUNC","rule":"TryDecompress::Brotli","sum":11},{"parent":"MODULE_FUNC","rule":"TryDecompress::Gzip","sum":1012},{"parent":"MODULE_FUNC","rule":"TryDecompress::Lz4","sum":145},{"parent":"MODULE_FUNC","rule":"TryDecompress::Lzma","sum":4},{"parent":"MODULE_FUNC","rule":"TryDecompress::Snappy","sum":10},{"parent":"MODULE_FUNC","rule":"TryDecompress::Xz","sum":4},{"parent":"MODULE_FUNC","rule":"TryDecompress::Zlib","sum":3552},{"parent":"MODULE_FUNC","rule":"TryDecompress::Zstd","sum":18},{"parent":"MODULE_FUNC","rule":"URL::Decode","sum":5},{"parent":"MODULE_FUNC","rule":"URL::GetHost","sum":2},{"parent":"MODULE_FUNC","rule":"Unicode::FInd","sum":4},{"parent":"MODULE_FUNC","rule":"Unicode::Find","sum":153636},{"parent":"MODULE_FUNC","rule":"Unicode::Fold","sum":29200},{"parent":"MODULE_FUNC","rule":"Unicode::FromCodePointList","sum":120346},{"parent":"MODULE_FUNC","rule":"Unicode::GetLength","sum":594925},{"parent":"MODULE_FUNC","rule":"Unicode::GetLengthn","sum":1},{"parent":"MODULE_FUNC","rule":"Unicode::IsAlnum","sum":551},{"parent":"MODULE_FUNC","rule":"Unicode::IsAlpha","sum":460},{"parent":"MODULE_FUNC","rule":"Unicode::IsAscii","sum":702},{"parent":"MODULE_FUNC","rule":"Unicode::IsDigit","sum":8983},{"parent":"MODULE_FUNC","rule":"Unicode::IsHex","sum":4},{"parent":"MODULE_FUNC","rule":"Unicode::IsLower","sum":96},{"parent":"MODULE_FUNC","rule":"Unicode::IsSpace","sum":18},{"parent":"MODULE_FUNC","rule":"Unicode::IsUnicodeSet","sum":441},{"parent":"MODULE_FUNC","rule":"Unicode::IsUpper","sum":1812},{"parent":"MODULE_FUNC","rule":"Unicode::IsUtf","sum":670858},{"parent":"MODULE_FUNC","rule":"Unicode::JoinFromList","sum":202977},{"parent":"MODULE_FUNC","rule":"Unicode::Length","sum":2},{"parent":"MODULE_FUNC","rule":"Unicode::LevensteinDistance","sum":39796},{"parent":"MODULE_FUNC","rule":"Unicode::Normalize","sum":110898},{"parent":"MODULE_FUNC","rule":"Unicode::NormalizeNFC","sum":526},{"parent":"MODULE_FUNC","rule":"Unicode::NormalizeNFD","sum":36},{"parent":"MODULE_FUNC","rule":"Unicode::NormalizeNFKC","sum":6978},{"parent":"MODULE_FUNC","rule":"Unicode::NormalizeNFKD","sum":1741},{"parent":"MODULE_FUNC","rule":"Unicode::RFind","sum":73307},{"parent":"MODULE_FUNC","rule":"Unicode::RemoveAll","sum":138890},{"parent":"MODULE_FUNC","rule":"Unicode::RemoveFirst","sum":7725},{"parent":"MODULE_FUNC","rule":"Unicode::RemoveLast","sum":7763},{"parent":"MODULE_FUNC","rule":"Unicode::ReplaceAll","sum":270824},{"parent":"MODULE_FUNC","rule":"Unicode::ReplaceFirst","sum":1748},{"parent":"MODULE_FUNC","rule":"Unicode::ReplaceLast","sum":318},{"parent":"MODULE_FUNC","rule":"Unicode::Reverse","sum":52754},{"parent":"MODULE_FUNC","rule":"Unicode::SUBSTRING","sum":2},{"parent":"MODULE_FUNC","rule":"Unicode::SplitToList","sum":181496},{"parent":"MODULE_FUNC","rule":"Unicode::Strip","sum":64880},{"parent":"MODULE_FUNC","rule":"Unicode::Substring","sum":602103},{"parent":"MODULE_FUNC","rule":"Unicode::ToCodePointList","sum":122836},{"parent":"MODULE_FUNC","rule":"Unicode::ToLower","sum":1191627},{"parent":"MODULE_FUNC","rule":"Unicode::ToTitle","sum":35832},{"parent":"MODULE_FUNC","rule":"Unicode::ToUint64","sum":389},{"parent":"MODULE_FUNC","rule":"Unicode::ToUpper","sum":111960},{"parent":"MODULE_FUNC","rule":"Unicode::Translit","sum":103574},{"parent":"MODULE_FUNC","rule":"Unicode::TryToUint64","sum":1941},{"parent":"MODULE_FUNC","rule":"Url::AsciiToLower","sum":1},{"parent":"MODULE_FUNC","rule":"Url::BuildQueryString","sum":25950},{"parent":"MODULE_FUNC","rule":"Url::CanBePunycodeHostName","sum":6526},{"parent":"MODULE_FUNC","rule":"Url::CutQueryStringAndFragment","sum":232682},{"parent":"MODULE_FUNC","rule":"Url::CutScheme","sum":1134149},{"parent":"MODULE_FUNC","rule":"Url::CutWWW","sum":860920},{"parent":"MODULE_FUNC","rule":"Url::CutWWW2","sum":741308},{"parent":"MODULE_FUNC","rule":"Url::Decode","sum":1693514},{"parent":"MODULE_FUNC","rule":"Url::Encode","sum":370961},{"parent":"MODULE_FUNC","rule":"Url::ForceHostNameToPunycode","sum":200975},{"parent":"MODULE_FUNC","rule":"Url::ForcePunycodeToHostName","sum":132393},{"parent":"MODULE_FUNC","rule":"Url::GEtPath","sum":5},{"parent":"MODULE_FUNC","rule":"Url::GetCGIParam","sum":1822738},{"parent":"MODULE_FUNC","rule":"Url::GetCgiParam","sum":7},{"parent":"MODULE_FUNC","rule":"Url::GetDomain","sum":1125269},{"parent":"MODULE_FUNC","rule":"Url::GetDomainLevel","sum":70746},{"parent":"MODULE_FUNC","rule":"Url::GetFragment","sum":496},{"parent":"MODULE_FUNC","rule":"Url::GetHost","sum":4053079},{"parent":"MODULE_FUNC","rule":"Url::GetHostPort","sum":196601},{"parent":"MODULE_FUNC","rule":"Url::GetOwner","sum":1403752},{"parent":"MODULE_FUNC","rule":"Url::GetPath","sum":1693317},{"parent":"MODULE_FUNC","rule":"Url::GetPort","sum":818213},{"parent":"MODULE_FUNC","rule":"Url::GetScheme","sum":2059696},{"parent":"MODULE_FUNC","rule":"Url::GetSchemeHost","sum":145904},{"parent":"MODULE_FUNC","rule":"Url::GetSchemeHostPort","sum":698264},{"parent":"MODULE_FUNC","rule":"Url::GetSignificantDomain","sum":462687},{"parent":"MODULE_FUNC","rule":"Url::GetTLD","sum":35522},{"parent":"MODULE_FUNC","rule":"Url::GetTail","sum":575463},{"parent":"MODULE_FUNC","rule":"Url::Getowner","sum":1},{"parent":"MODULE_FUNC","rule":"Url::HostNameToPunycode","sum":581089},{"parent":"MODULE_FUNC","rule":"Url::IsAllowedByRobotsTxt","sum":7},{"parent":"MODULE_FUNC","rule":"Url::IsKnownTLD","sum":20870},{"parent":"MODULE_FUNC","rule":"Url::IsWellKnownTLD","sum":4919},{"parent":"MODULE_FUNC","rule":"Url::Normalize","sum":1050668},{"parent":"MODULE_FUNC","rule":"Url::NormalizeWithDefaultHttpScheme","sum":623726},{"parent":"MODULE_FUNC","rule":"Url::Parse","sum":299304},{"parent":"MODULE_FUNC","rule":"Url::PunycodeToHostName","sum":202823},{"parent":"MODULE_FUNC","rule":"Url::QueryStringToDict","sum":154750},{"parent":"MODULE_FUNC","rule":"Url::QueryStringToList","sum":38768},{"parent":"MODULE_FUNC","rule":"Url::ReplaceAll","sum":8},{"parent":"MODULE_FUNC","rule":"YSON::Co","sum":1},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToBool","sum":12},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToDict","sum":6},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToDouble","sum":4},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToDoubleList","sum":10},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToInt64","sum":2},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToList","sum":12},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToString","sum":91},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToStringList","sum":27},{"parent":"MODULE_FUNC","rule":"YSON::From","sum":7},{"parent":"MODULE_FUNC","rule":"YSON::IsDict","sum":3},{"parent":"MODULE_FUNC","rule":"YSON::Lookup","sum":1},{"parent":"MODULE_FUNC","rule":"YSON::LookupDict","sum":1},{"parent":"MODULE_FUNC","rule":"YSON::LookupDouble","sum":6},{"parent":"MODULE_FUNC","rule":"YSON::LookupInt64","sum":1},{"parent":"MODULE_FUNC","rule":"YSON::LookupList","sum":4},{"parent":"MODULE_FUNC","rule":"YSON::LookupString","sum":3},{"parent":"MODULE_FUNC","rule":"YSON::Parse","sum":5},{"parent":"MODULE_FUNC","rule":"YSON::ToString","sum":1},{"parent":"MODULE_FUNC","rule":"YSON::convertToString","sum":7},{"parent":"MODULE_FUNC","rule":"YSON::from","sum":1},{"parent":"MODULE_FUNC","rule":"YSon::ConvertToDouble","sum":12},{"parent":"MODULE_FUNC","rule":"YSon::ConvertToList","sum":3},{"parent":"MODULE_FUNC","rule":"YSon::ConvertToString","sum":2},{"parent":"MODULE_FUNC","rule":"YSon::LookupString","sum":1},{"parent":"MODULE_FUNC","rule":"YSon::Parse","sum":5},{"parent":"MODULE_FUNC","rule":"Yson::AsList","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::Attributes","sum":1878},{"parent":"MODULE_FUNC","rule":"Yson::COntains","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::COnvertToDouble","sum":7},{"parent":"MODULE_FUNC","rule":"Yson::CastToStringList","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::Contains","sum":2964953},{"parent":"MODULE_FUNC","rule":"Yson::Conver","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::ConverTToInt64","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConverToDouble","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::ConverToInt64","sum":10},{"parent":"MODULE_FUNC","rule":"Yson::ConverToList","sum":9},{"parent":"MODULE_FUNC","rule":"Yson::ConverToString","sum":12},{"parent":"MODULE_FUNC","rule":"Yson::ConvertFromString","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertTOList","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertTo","sum":8893449},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToAttributes","sum":16},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToBool","sum":8777282},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToBoolDict","sum":105242},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToBoolList","sum":7419},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToBoolgDict","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToBytes","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDate","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDateTime","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDict","sum":8507382},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDictList","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDictOfDouble","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDictString","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDouble","sum":9538271},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDoubleDict","sum":280065},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDoubleList","sum":1195596},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToFloat","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToFloat64","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToINT64List","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToIn64","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToInt","sum":37},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToInt32","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToInt32List","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToInt64","sum":20437163},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToInt64Dict","sum":186877},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToInt64List","sum":2402436},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToIntList","sum":5},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToInteget","sum":169},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToJson","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToList","sum":18972909},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToListDouble","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToListString","sum":16},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToListg","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToSTring","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToSTringList","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToSetring","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToString","sum":96809421},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToStringDict","sum":1450323},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToStringInt64","sum":4},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToStringList","sum":24390484},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToStrint","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToStruct","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToText","sum":13},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUINT64List","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUInt64","sum":296},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUInt64List","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUint32","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUint64","sum":8496332},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUint64Dict","sum":36424},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUint64List","sum":2199229},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUnit64List","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToevent_value","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToint64","sum":13},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToint64List","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertTolIST","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertTolist","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertTostring","sum":4},{"parent":"MODULE_FUNC","rule":"Yson::ConverttoBool","sum":5},{"parent":"MODULE_FUNC","rule":"Yson::ConverttoList","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConverttoString","sum":13},{"parent":"MODULE_FUNC","rule":"Yson::Converttostring","sum":14},{"parent":"MODULE_FUNC","rule":"Yson::ConvvertToString","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::Dict","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::Equals","sum":797786},{"parent":"MODULE_FUNC","rule":"Yson::Extract","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FROM","sum":8},{"parent":"MODULE_FUNC","rule":"Yson::Find","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::From","sum":25156251},{"parent":"MODULE_FUNC","rule":"Yson::From64List","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromAGG_LIST","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromASDFDSKLDJF","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromAboba","sum":4},{"parent":"MODULE_FUNC","rule":"Yson::FromBinary","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromBytes","sum":17},{"parent":"MODULE_FUNC","rule":"Yson::FromDict","sum":3070},{"parent":"MODULE_FUNC","rule":"Yson::FromDouble","sum":2798},{"parent":"MODULE_FUNC","rule":"Yson::FromDouble64Dict","sum":3671},{"parent":"MODULE_FUNC","rule":"Yson::FromDoubleDict","sum":42633},{"parent":"MODULE_FUNC","rule":"Yson::FromDoubleList","sum":993},{"parent":"MODULE_FUNC","rule":"Yson::FromInt32","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromInt64","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::FromInt64Dict","sum":2136},{"parent":"MODULE_FUNC","rule":"Yson::FromInt64List","sum":7471},{"parent":"MODULE_FUNC","rule":"Yson::FromJson","sum":2171},{"parent":"MODULE_FUNC","rule":"Yson::FromKek","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::FromList","sum":4897},{"parent":"MODULE_FUNC","rule":"Yson::FromListTake","sum":9},{"parent":"MODULE_FUNC","rule":"Yson::FromMap","sum":356},{"parent":"MODULE_FUNC","rule":"Yson::FromMinutes","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromSHEEEEEEEEEEEEE","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::FromSHIIIIIIIIIII","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromSeconds","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::FromSring","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::FromSting","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromString","sum":56322},{"parent":"MODULE_FUNC","rule":"Yson::FromStringDict","sum":69362},{"parent":"MODULE_FUNC","rule":"Yson::FromStringList","sum":59205},{"parent":"MODULE_FUNC","rule":"Yson::FromStruct","sum":652706},{"parent":"MODULE_FUNC","rule":"Yson::FromUi64List","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromUin64List","sum":377},{"parent":"MODULE_FUNC","rule":"Yson::FromUint32Dict","sum":10254},{"parent":"MODULE_FUNC","rule":"Yson::FromUint64","sum":9},{"parent":"MODULE_FUNC","rule":"Yson::FromUint64Dict","sum":16013},{"parent":"MODULE_FUNC","rule":"Yson::FromUint64List","sum":25360},{"parent":"MODULE_FUNC","rule":"Yson::FromY2020MachoDachaTbIhaHouse","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::Fromt","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::Get","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::GetHash","sum":864646},{"parent":"MODULE_FUNC","rule":"Yson::GetLength","sum":2813177},{"parent":"MODULE_FUNC","rule":"Yson::ISDict","sum":6},{"parent":"MODULE_FUNC","rule":"Yson::ISList","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::IsBool","sum":33403},{"parent":"MODULE_FUNC","rule":"Yson::IsDict","sum":257269},{"parent":"MODULE_FUNC","rule":"Yson::IsDouble","sum":100319},{"parent":"MODULE_FUNC","rule":"Yson::IsEntity","sum":2675378},{"parent":"MODULE_FUNC","rule":"Yson::IsInt64","sum":288637},{"parent":"MODULE_FUNC","rule":"Yson::IsList","sum":287011},{"parent":"MODULE_FUNC","rule":"Yson::IsString","sum":1026312},{"parent":"MODULE_FUNC","rule":"Yson::IsUint64","sum":154118},{"parent":"MODULE_FUNC","rule":"Yson::ListMap","sum":12},{"parent":"MODULE_FUNC","rule":"Yson::Lo","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::Loo","sum":10},{"parent":"MODULE_FUNC","rule":"Yson::LookUp","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::LookUpDict","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::LookUpString","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::Lookup","sum":6572221},{"parent":"MODULE_FUNC","rule":"Yson::LookupBool","sum":2151225},{"parent":"MODULE_FUNC","rule":"Yson::LookupDict","sum":402733},{"parent":"MODULE_FUNC","rule":"Yson::LookupDouble","sum":3063595},{"parent":"MODULE_FUNC","rule":"Yson::LookupInt","sum":16},{"parent":"MODULE_FUNC","rule":"Yson::LookupInt32","sum":91},{"parent":"MODULE_FUNC","rule":"Yson::LookupInt64","sum":5506073},{"parent":"MODULE_FUNC","rule":"Yson::LookupInteger","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::LookupList","sum":1627012},{"parent":"MODULE_FUNC","rule":"Yson::LookupSTRING","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::LookupString","sum":41357204},{"parent":"MODULE_FUNC","rule":"Yson::LookupStringList","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::LookupStruct","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::LookupTimestamp","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::LookupUInt64","sum":6},{"parent":"MODULE_FUNC","rule":"Yson::LookupUint64","sum":3803411},{"parent":"MODULE_FUNC","rule":"Yson::LookupsTRING","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::LoopUpString","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::Options","sum":9255552},{"parent":"MODULE_FUNC","rule":"Yson::Parse","sum":8657637},{"parent":"MODULE_FUNC","rule":"Yson::ParseJSON","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::ParseJson","sum":12622715},{"parent":"MODULE_FUNC","rule":"Yson::ParseJsonDecodeUtf8","sum":133932},{"parent":"MODULE_FUNC","rule":"Yson::Parsejson","sum":9},{"parent":"MODULE_FUNC","rule":"Yson::Path","sum":9},{"parent":"MODULE_FUNC","rule":"Yson::Serialize","sum":3873323},{"parent":"MODULE_FUNC","rule":"Yson::SerializeJSON","sum":5},{"parent":"MODULE_FUNC","rule":"Yson::SerializeJson","sum":9860505},{"parent":"MODULE_FUNC","rule":"Yson::SerializeJsonEncodeUtf8","sum":202134},{"parent":"MODULE_FUNC","rule":"Yson::SerializePretty","sum":1187693},{"parent":"MODULE_FUNC","rule":"Yson::SerializeText","sum":612491},{"parent":"MODULE_FUNC","rule":"Yson::WithAttributes","sum":660},{"parent":"MODULE_FUNC","rule":"Yson::YPath","sum":12621396},{"parent":"MODULE_FUNC","rule":"Yson::YPathBool","sum":1178381},{"parent":"MODULE_FUNC","rule":"Yson::YPathBoolean","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::YPathDict","sum":25581},{"parent":"MODULE_FUNC","rule":"Yson::YPathDouble","sum":1365022},{"parent":"MODULE_FUNC","rule":"Yson::YPathInt16","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::YPathInt64","sum":2724117},{"parent":"MODULE_FUNC","rule":"Yson::YPathList","sum":1395373},{"parent":"MODULE_FUNC","rule":"Yson::YPathListString","sum":7},{"parent":"MODULE_FUNC","rule":"Yson::YPathString","sum":13557067},{"parent":"MODULE_FUNC","rule":"Yson::YPathUint64","sum":709161},{"parent":"MODULE_FUNC","rule":"Yson::YaPathString","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::Ypath","sum":51},{"parent":"MODULE_FUNC","rule":"Yson::YpathString","sum":10},{"parent":"MODULE_FUNC","rule":"Yson::Yson2","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::convertToDict","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::convertToInt64","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::convertToString","sum":7},{"parent":"MODULE_FUNC","rule":"Yson::convertToUint64","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::convertToUint64List","sum":5},{"parent":"MODULE_FUNC","rule":"Yson::from","sum":48},{"parent":"MODULE_FUNC","rule":"Yson::fromJson","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::lookupString","sum":1},{"parent":"MODULE_FUNC","rule":"dateTime::Format","sum":3},{"parent":"MODULE_FUNC","rule":"dateTime::GetMonth","sum":6},{"parent":"MODULE_FUNC","rule":"dateTime::IntervalFromDays","sum":365},{"parent":"MODULE_FUNC","rule":"dateTime::IntervalFromSeconds","sum":1},{"parent":"MODULE_FUNC","rule":"dateTime::MakeDate","sum":87},{"parent":"MODULE_FUNC","rule":"dateTime::MakeDatetime","sum":7},{"parent":"MODULE_FUNC","rule":"dateTime::StartOfMonth","sum":2},{"parent":"MODULE_FUNC","rule":"datetime::Format","sum":5},{"parent":"MODULE_FUNC","rule":"datetime::FromMilliseconds","sum":3},{"parent":"MODULE_FUNC","rule":"datetime::FromSeconds","sum":3736},{"parent":"MODULE_FUNC","rule":"datetime::GetDayOfWeek","sum":4},{"parent":"MODULE_FUNC","rule":"datetime::GetDayOfWeekName","sum":3},{"parent":"MODULE_FUNC","rule":"datetime::GetHour","sum":8},{"parent":"MODULE_FUNC","rule":"datetime::GetMonth","sum":14},{"parent":"MODULE_FUNC","rule":"datetime::GetWeekOfYear","sum":30},{"parent":"MODULE_FUNC","rule":"datetime::GetYear","sum":39},{"parent":"MODULE_FUNC","rule":"datetime::IntervalFromDays","sum":1341},{"parent":"MODULE_FUNC","rule":"datetime::IntervalFromHours","sum":37},{"parent":"MODULE_FUNC","rule":"datetime::IntervalFromMinutes","sum":6},{"parent":"MODULE_FUNC","rule":"datetime::MakeDate","sum":5399},{"parent":"MODULE_FUNC","rule":"datetime::MakeDatetime","sum":661},{"parent":"MODULE_FUNC","rule":"datetime::MakeTimestamp","sum":1},{"parent":"MODULE_FUNC","rule":"datetime::Parse","sum":397},{"parent":"MODULE_FUNC","rule":"datetime::ParseIso8601","sum":3},{"parent":"MODULE_FUNC","rule":"datetime::ShiftMonths","sum":310},{"parent":"MODULE_FUNC","rule":"datetime::StartOf","sum":1},{"parent":"MODULE_FUNC","rule":"datetime::StartOfDay","sum":2},{"parent":"MODULE_FUNC","rule":"datetime::StartOfMonth","sum":550},{"parent":"MODULE_FUNC","rule":"datetime::StartOfWeek","sum":530},{"parent":"MODULE_FUNC","rule":"datetime::ToDays","sum":375},{"parent":"MODULE_FUNC","rule":"datetime::ToSeconds","sum":735},{"parent":"MODULE_FUNC","rule":"datetime::fromseconds","sum":4},{"parent":"MODULE_FUNC","rule":"digest::Md5HalfMix","sum":14},{"parent":"MODULE_FUNC","rule":"digest::city_hash","sum":1},{"parent":"MODULE_FUNC","rule":"json::ConvertToString","sum":7},{"parent":"MODULE_FUNC","rule":"json::From","sum":1},{"parent":"MODULE_FUNC","rule":"math::Round","sum":2},{"parent":"MODULE_FUNC","rule":"math::floor","sum":2},{"parent":"MODULE_FUNC","rule":"math::log","sum":2},{"parent":"MODULE_FUNC","rule":"math::pow","sum":6},{"parent":"MODULE_FUNC","rule":"math::round","sum":56},{"parent":"MODULE_FUNC","rule":"pg::GENERATE_SERIES","sum":8},{"parent":"MODULE_FUNC","rule":"pg::SPLIT_PART","sum":2},{"parent":"MODULE_FUNC","rule":"pg::age","sum":737},{"parent":"MODULE_FUNC","rule":"pg::array_agg","sum":2},{"parent":"MODULE_FUNC","rule":"pg::date_part","sum":716},{"parent":"MODULE_FUNC","rule":"pg::extract","sum":285},{"parent":"MODULE_FUNC","rule":"pg::generate_series","sum":2},{"parent":"MODULE_FUNC","rule":"pg::st_asgeojson","sum":2},{"parent":"MODULE_FUNC","rule":"pg::st_astext","sum":4},{"parent":"MODULE_FUNC","rule":"pg::st_geomfromewkb","sum":14},{"parent":"MODULE_FUNC","rule":"pg::st_transform","sum":9},{"parent":"MODULE_FUNC","rule":"pg::string_agg","sum":15},{"parent":"MODULE_FUNC","rule":"pire::Capture","sum":7},{"parent":"MODULE_FUNC","rule":"pire::Match","sum":29},{"parent":"MODULE_FUNC","rule":"re2::Capture","sum":2753},{"parent":"MODULE_FUNC","rule":"re2::Grep","sum":1},{"parent":"MODULE_FUNC","rule":"re2::Match","sum":24},{"parent":"MODULE_FUNC","rule":"re2::Replace","sum":429},{"parent":"MODULE_FUNC","rule":"re2::capture","sum":8},{"parent":"MODULE_FUNC","rule":"string::AsciiToLower","sum":6},{"parent":"MODULE_FUNC","rule":"string::JoinFromList","sum":8},{"parent":"MODULE_FUNC","rule":"string::ReplaceFirst","sum":14},{"parent":"MODULE_FUNC","rule":"string::SplitToList","sum":6},{"parent":"MODULE_FUNC","rule":"string::StartsWith","sum":1},{"parent":"MODULE_FUNC","rule":"string::contains","sum":4},{"parent":"MODULE_FUNC","rule":"string::joinfromlist","sum":17},{"parent":"MODULE_FUNC","rule":"string::removeall","sum":4},{"parent":"MODULE_FUNC","rule":"string::replaceall","sum":11},{"parent":"MODULE_FUNC","rule":"string::splittolist","sum":12},{"parent":"MODULE_FUNC","rule":"string::strip","sum":2},{"parent":"MODULE_FUNC","rule":"url::Encode","sum":2},{"parent":"MODULE_FUNC","rule":"url::decode","sum":2},{"parent":"MODULE_FUNC","rule":"url::gethost","sum":1},{"parent":"MODULE_FUNC","rule":"ySoN::CoNveRtTo","sum":1},{"parent":"MODULE_FUNC","rule":"yson::ConvertToDict","sum":1},{"parent":"MODULE_FUNC","rule":"yson::ConvertToDouble","sum":1},{"parent":"MODULE_FUNC","rule":"yson::ConvertToInt64","sum":1},{"parent":"MODULE_FUNC","rule":"yson::ConvertToString","sum":3},{"parent":"MODULE_FUNC","rule":"yson::ConvertToStringList","sum":2},{"parent":"MODULE_FUNC","rule":"yson::From","sum":1},{"parent":"MODULE_FUNC","rule":"yson::LookupString","sum":1},{"parent":"MODULE_FUNC","rule":"yson::PARSE","sum":2},{"parent":"MODULE_FUNC","rule":"yson::SerializeJson","sum":1},{"parent":"MODULE_FUNC","rule":"yson::convertto","sum":2},{"parent":"MODULE_FUNC","rule":"yson::converttodoubledict","sum":8},{"parent":"MODULE_FUNC","rule":"yson::converttolist","sum":1},{"parent":"MODULE_FUNC","rule":"yson::converttostring","sum":5},{"parent":"MODULE_FUNC","rule":"yson::converttostringdict","sum":8},{"parent":"MODULE_FUNC","rule":"yson::from","sum":2},{"parent":"MODULE_FUNC","rule":"yson::options","sum":8},{"parent":"MODULE_FUNC","rule":"yson::parsejson","sum":16},{"parent":"PRAGMA","rule":"AllowDotInAlias","sum":258287},{"parent":"PRAGMA","rule":"AllowUnnamedColumns","sum":4},{"parent":"PRAGMA","rule":"AnsiCurrentRow","sum":957},{"parent":"PRAGMA","rule":"AnsiImplicitCrossJoin","sum":13070},{"parent":"PRAGMA","rule":"AnsiInFOREmptyORNullableItemsCollections","sum":52},{"parent":"PRAGMA","rule":"AnsiInForEmptyOrNULLableItemsCollectiONs","sum":169},{"parent":"PRAGMA","rule":"AnsiInForEmptyOrNULLableItemsCollections","sum":4074},{"parent":"PRAGMA","rule":"AnsiInForEmptyOrNullableItemsCollections","sum":39620670},{"parent":"PRAGMA","rule":"AnsiInForEmptyOrnullableItemsCollections","sum":263},{"parent":"PRAGMA","rule":"AnsiInForEmptyorNullableItemsCollections","sum":2141},{"parent":"PRAGMA","rule":"AnsiInForEmptyornullableItemsCollections","sum":1273},{"parent":"PRAGMA","rule":"AnsiInforEmptyOrNullableItemsCollections","sum":244},{"parent":"PRAGMA","rule":"AnsiOptionalAS","sum":4},{"parent":"PRAGMA","rule":"AnsiOptionalAs","sum":2152795},{"parent":"PRAGMA","rule":"AnsiOptionalas","sum":350},{"parent":"PRAGMA","rule":"AnsiOrderByLimitInUnionAll","sum":210333},{"parent":"PRAGMA","rule":"AnsiRankForNullableKeys","sum":223815},{"parent":"PRAGMA","rule":"AnsiinForEmptyOrNullableItemsCollections","sum":8517},{"parent":"PRAGMA","rule":"AnsiinForEmptyOrNullableitemsCollections","sum":16},{"parent":"PRAGMA","rule":"AutoCommit","sum":39168},{"parent":"PRAGMA","rule":"BlockEngine","sum":352454},{"parent":"PRAGMA","rule":"BogousStarInGroupByOverJoin","sum":2},{"parent":"PRAGMA","rule":"CLassicDivision","sum":9},{"parent":"PRAGMA","rule":"CheckedOps","sum":653},{"parent":"PRAGMA","rule":"ClASsicDivision","sum":639},{"parent":"PRAGMA","rule":"ClassicDIvision","sum":44},{"parent":"PRAGMA","rule":"ClassicDivisiON","sum":148},{"parent":"PRAGMA","rule":"ClassicDivision","sum":2557592},{"parent":"PRAGMA","rule":"Classicdivision","sum":6},{"parent":"PRAGMA","rule":"CoalesceJoinKeysOnQualifiedAll","sum":36},{"parent":"PRAGMA","rule":"CompactGroupBy","sum":26},{"parent":"PRAGMA","rule":"CompactNamedExprs","sum":2451},{"parent":"PRAGMA","rule":"CostBasedOptimizer","sum":14431},{"parent":"PRAGMA","rule":"DQ.ANALYZEQUERY","sum":1615},{"parent":"PRAGMA","rule":"DQEngine","sum":3},{"parent":"PRAGMA","rule":"DirectRead","sum":48},{"parent":"PRAGMA","rule":"DisableAnsiInForEmptyOrNullableItemsCollections","sum":233678},{"parent":"PRAGMA","rule":"DisableAnsiLike","sum":1},{"parent":"PRAGMA","rule":"DisableAnsiRankForNullableKeys","sum":38115},{"parent":"PRAGMA","rule":"DisableCoalesceJoinKeysOnQualifiedAll","sum":197713},{"parent":"PRAGMA","rule":"DisableCompactNamedExprs","sum":12},{"parent":"PRAGMA","rule":"DisableOrderedColumns","sum":536},{"parent":"PRAGMA","rule":"DisablePullUpFlatMapOverJoin","sum":2},{"parent":"PRAGMA","rule":"DisableSeqMode","sum":1},{"parent":"PRAGMA","rule":"DisableSimpleColumns","sum":398557},{"parent":"PRAGMA","rule":"DisableStrictJoinKeyTypes","sum":417},{"parent":"PRAGMA","rule":"DisableUnicodeLiterals","sum":34},{"parent":"PRAGMA","rule":"DisableUnordered","sum":867},{"parent":"PRAGMA","rule":"DistinctOverWindow","sum":7},{"parent":"PRAGMA","rule":"Dq.HashJoinMode","sum":6},{"parent":"PRAGMA","rule":"Dq.MaxTasksPerStage","sum":5},{"parent":"PRAGMA","rule":"Dq.SplitStageOnDqReplicate","sum":4},{"parent":"PRAGMA","rule":"Dq.UseBlockReader","sum":2},{"parent":"PRAGMA","rule":"DqEngine","sum":10793713},{"parent":"PRAGMA","rule":"Dqengine","sum":2},{"parent":"PRAGMA","rule":"EmitAggApply","sum":1},{"parent":"PRAGMA","rule":"EmitUnionMerge","sum":7},{"parent":"PRAGMA","rule":"EnableSystemColumns","sum":3},{"parent":"PRAGMA","rule":"FILE","sum":289896},{"parent":"PRAGMA","rule":"FeatureR010","sum":224},{"parent":"PRAGMA","rule":"File","sum":7406844},{"parent":"PRAGMA","rule":"FileOption","sum":15425},{"parent":"PRAGMA","rule":"FilterPushdownOverJoinOptionalSide","sum":6},{"parent":"PRAGMA","rule":"FlexibleTypes","sum":946},{"parent":"PRAGMA","rule":"Folder","sum":3771},{"parent":"PRAGMA","rule":"Greetings","sum":1453},{"parent":"PRAGMA","rule":"GroupByCubeLimit","sum":39642},{"parent":"PRAGMA","rule":"GroupByLimit","sum":151970},{"parent":"PRAGMA","rule":"JsonQueryReturnsJsonDocument","sum":300847},{"parent":"PRAGMA","rule":"LIBRARY","sum":247548},{"parent":"PRAGMA","rule":"LIbrary","sum":52},{"parent":"PRAGMA","rule":"Library","sum":15077641},{"parent":"PRAGMA","rule":"OrderedColumns","sum":5989922},{"parent":"PRAGMA","rule":"Orderedcolumns","sum":12},{"parent":"PRAGMA","rule":"OverrideLibrary","sum":182},{"parent":"PRAGMA","rule":"Package","sum":5},{"parent":"PRAGMA","rule":"PositionalUnionAll","sum":120124},{"parent":"PRAGMA","rule":"PqReadBy","sum":42},{"parent":"PRAGMA","rule":"REGEXUSERE2","sum":13439},{"parent":"PRAGMA","rule":"RefSelect","sum":435275},{"parent":"PRAGMA","rule":"RegExUseRe2","sum":32},{"parent":"PRAGMA","rule":"RegexUseRe2","sum":312065},{"parent":"PRAGMA","rule":"ResultRowsLimit","sum":3},{"parent":"PRAGMA","rule":"SampleSelect","sum":11},{"parent":"PRAGMA","rule":"SeqMode","sum":4},{"parent":"PRAGMA","rule":"SimpleColumns","sum":6946413},{"parent":"PRAGMA","rule":"Simplecolumns","sum":3},{"parent":"PRAGMA","rule":"StrictJoinKeyTypes","sum":76669},{"parent":"PRAGMA","rule":"TablePathPrefix","sum":5602522},{"parent":"PRAGMA","rule":"UDF","sum":2173643},{"parent":"PRAGMA","rule":"Udf","sum":1939655},{"parent":"PRAGMA","rule":"UnicodeLiterals","sum":98},{"parent":"PRAGMA","rule":"UnorderedSubqueries","sum":2},{"parent":"PRAGMA","rule":"UseBlocks","sum":57},{"parent":"PRAGMA","rule":"UseTablePrefixForEach","sum":52},{"parent":"PRAGMA","rule":"WARNING","sum":26},{"parent":"PRAGMA","rule":"WarnUnnamedColumns","sum":26243},{"parent":"PRAGMA","rule":"Warning","sum":2962238},{"parent":"PRAGMA","rule":"WarningMsg","sum":12699},{"parent":"PRAGMA","rule":"YSON.AutoConvert","sum":823},{"parent":"PRAGMA","rule":"YSON.DisableStrict","sum":44755},{"parent":"PRAGMA","rule":"YSON.Strict","sum":732},{"parent":"PRAGMA","rule":"YT.Auth","sum":68},{"parent":"PRAGMA","rule":"YT.DefaultOperationWeight","sum":252819},{"parent":"PRAGMA","rule":"YT.InferSchema","sum":17844},{"parent":"PRAGMA","rule":"YT.POOL","sum":275},{"parent":"PRAGMA","rule":"YT.Pool","sum":85880},{"parent":"PRAGMA","rule":"YT.StaticPool","sum":6},{"parent":"PRAGMA","rule":"YT.TableContentDeliveryMode","sum":1663},{"parent":"PRAGMA","rule":"YT.UseNativeYTTypes","sum":2},{"parent":"PRAGMA","rule":"YT.UseNativeYTtypes","sum":3},{"parent":"PRAGMA","rule":"YT.pOOL","sum":4},{"parent":"PRAGMA","rule":"YT.pool","sum":18812},{"parent":"PRAGMA","rule":"YsON.Disablestrict","sum":133},{"parent":"PRAGMA","rule":"Yson.AutoConvert","sum":41801},{"parent":"PRAGMA","rule":"Yson.DIsableStrict","sum":15251},{"parent":"PRAGMA","rule":"Yson.DisableStrict","sum":481261},{"parent":"PRAGMA","rule":"Yson.Strict","sum":6858},{"parent":"PRAGMA","rule":"Yson.disablestrict","sum":29},{"parent":"PRAGMA","rule":"Yt.Auth","sum":33},{"parent":"PRAGMA","rule":"Yt.Description","sum":4},{"parent":"PRAGMA","rule":"Yt.ExternalTx","sum":24798},{"parent":"PRAGMA","rule":"Yt.HybridDqExecution","sum":9},{"parent":"PRAGMA","rule":"Yt.InferSchema","sum":2744},{"parent":"PRAGMA","rule":"Yt.MaxRowWeight","sum":957},{"parent":"PRAGMA","rule":"Yt.ParallelOperationsLimit","sum":12},{"parent":"PRAGMA","rule":"Yt.Pool","sum":254713},{"parent":"PRAGMA","rule":"Yt.PoolTrees","sum":1},{"parent":"PRAGMA","rule":"Yt.StaticPool","sum":10080},{"parent":"PRAGMA","rule":"Yt.TmpFolder","sum":4},{"parent":"PRAGMA","rule":"Yt.UseNativeYtTypes","sum":2856},{"parent":"PRAGMA","rule":"Yt.pool","sum":82763},{"parent":"PRAGMA","rule":"ansiInForEmptyOrNullableItemsCollections","sum":118},{"parent":"PRAGMA","rule":"ansiimplicitcrossjoin","sum":2},{"parent":"PRAGMA","rule":"ansiinforemptyornullableitemscollections","sum":12},{"parent":"PRAGMA","rule":"ansioptionalas","sum":98},{"parent":"PRAGMA","rule":"autocommit","sum":133779},{"parent":"PRAGMA","rule":"classicDivision","sum":18},{"parent":"PRAGMA","rule":"classic_division","sum":11},{"parent":"PRAGMA","rule":"classicdivision","sum":77},{"parent":"PRAGMA","rule":"config.flags","sum":1289150},{"parent":"PRAGMA","rule":"direct_read","sum":2},{"parent":"PRAGMA","rule":"directread","sum":2},{"parent":"PRAGMA","rule":"disableSimpleColumns","sum":8},{"parent":"PRAGMA","rule":"disablesimplecolumns","sum":6},{"parent":"PRAGMA","rule":"dq.AnalyticsHopping","sum":4},{"parent":"PRAGMA","rule":"dq.AnalyzeQuery","sum":3086654},{"parent":"PRAGMA","rule":"dq.ENABLEDQREPLICATE","sum":1},{"parent":"PRAGMA","rule":"dq.EnableComputeActor","sum":1},{"parent":"PRAGMA","rule":"dq.EnableDqReplicate","sum":921734},{"parent":"PRAGMA","rule":"dq.EnableDqreplicate","sum":3},{"parent":"PRAGMA","rule":"dq.EnableFullResultWrite","sum":28699},{"parent":"PRAGMA","rule":"dq.EnableInsert","sum":86477},{"parent":"PRAGMA","rule":"dq.FallbackPolicy","sum":3},{"parent":"PRAGMA","rule":"dq.HashJoinMode","sum":6282},{"parent":"PRAGMA","rule":"dq.HashShuffleMaxTasks","sum":7},{"parent":"PRAGMA","rule":"dq.HashShuffleTasksRatio","sum":7},{"parent":"PRAGMA","rule":"dq.MaxDataSizePerJob","sum":11},{"parent":"PRAGMA","rule":"dq.MaxDataSizePerQuery","sum":2},{"parent":"PRAGMA","rule":"dq.MaxRetries","sum":1124},{"parent":"PRAGMA","rule":"dq.MaxTasksPerOperation","sum":23157},{"parent":"PRAGMA","rule":"dq.MaxTasksPerStage","sum":61204},{"parent":"PRAGMA","rule":"dq.MemoryLimit","sum":7977},{"parent":"PRAGMA","rule":"dq.OptLLVM","sum":11},{"parent":"PRAGMA","rule":"dq.SplitStageOnDqReplicate","sum":11034},{"parent":"PRAGMA","rule":"dq.UseBlockReader","sum":3993},{"parent":"PRAGMA","rule":"dq.UseFastPickleTransport","sum":3},{"parent":"PRAGMA","rule":"dq.UseFinalizeByKey","sum":10},{"parent":"PRAGMA","rule":"dq.UseOOBTransport","sum":9},{"parent":"PRAGMA","rule":"dq.UseWideBlockChannels","sum":2},{"parent":"PRAGMA","rule":"dq.UseWideChannels","sum":1},{"parent":"PRAGMA","rule":"dq.WorkerFilter","sum":104},{"parent":"PRAGMA","rule":"dq.enableDqReplicate","sum":348},{"parent":"PRAGMA","rule":"dq.enabledqreplicate","sum":24},{"parent":"PRAGMA","rule":"dqEngine","sum":91597},{"parent":"PRAGMA","rule":"dqengine","sum":21246},{"parent":"PRAGMA","rule":"equijoin","sum":4},{"parent":"PRAGMA","rule":"file","sum":1810746},{"parent":"PRAGMA","rule":"folder","sum":674},{"parent":"PRAGMA","rule":"greetings","sum":1},{"parent":"PRAGMA","rule":"library","sum":4878187},{"parent":"PRAGMA","rule":"orderedColumns","sum":7},{"parent":"PRAGMA","rule":"orderedcolumns","sum":15134},{"parent":"PRAGMA","rule":"override_library","sum":32},{"parent":"PRAGMA","rule":"package","sum":228921},{"parent":"PRAGMA","rule":"refselect","sum":32323},{"parent":"PRAGMA","rule":"rtmr.Account","sum":4},{"parent":"PRAGMA","rule":"rtmr.TaskName","sum":12},{"parent":"PRAGMA","rule":"rtmr.YfInstanceCount","sum":8},{"parent":"PRAGMA","rule":"rtmr.YfSlotCount","sum":8},{"parent":"PRAGMA","rule":"rtmr.yfPool","sum":1},{"parent":"PRAGMA","rule":"sampleselect","sum":177},{"parent":"PRAGMA","rule":"simpleColumns","sum":1446},{"parent":"PRAGMA","rule":"simplecolumns","sum":242914},{"parent":"PRAGMA","rule":"tablepathprefix","sum":2},{"parent":"PRAGMA","rule":"udf","sum":4336302},{"parent":"PRAGMA","rule":"warning","sum":66490},{"parent":"PRAGMA","rule":"yson.AutoConvert","sum":4731785},{"parent":"PRAGMA","rule":"yson.Auto_convert","sum":18},{"parent":"PRAGMA","rule":"yson.Autoconvert","sum":1158},{"parent":"PRAGMA","rule":"yson.DisableStrict","sum":20060072},{"parent":"PRAGMA","rule":"yson.Disablestrict","sum":46},{"parent":"PRAGMA","rule":"yson.Fast","sum":662},{"parent":"PRAGMA","rule":"yson.Strict","sum":3495746},{"parent":"PRAGMA","rule":"yson.autoConvert","sum":4},{"parent":"PRAGMA","rule":"yson.autoconvert","sum":3750},{"parent":"PRAGMA","rule":"yson.disableStrict","sum":2284},{"parent":"PRAGMA","rule":"yson.disable_strict","sum":3},{"parent":"PRAGMA","rule":"yson.disablestrict","sum":211473},{"parent":"PRAGMA","rule":"yson.strict","sum":709},{"parent":"PRAGMA","rule":"yt.AUth","sum":4},{"parent":"PRAGMA","rule":"yt.Annotations","sum":46551803},{"parent":"PRAGMA","rule":"yt.Auth","sum":1280645},{"parent":"PRAGMA","rule":"yt.AutoMerge","sum":4457191},{"parent":"PRAGMA","rule":"yt.Automerge","sum":2793},{"parent":"PRAGMA","rule":"yt.BatchListFolderConcurrency","sum":151},{"parent":"PRAGMA","rule":"yt.BinaryExpirationInterval","sum":6233208},{"parent":"PRAGMA","rule":"yt.BinaryTmpFolder","sum":6259531},{"parent":"PRAGMA","rule":"yt.BlockReaderSupportedDataTypes","sum":5},{"parent":"PRAGMA","rule":"yt.ColumnGroupMode","sum":445387},{"parent":"PRAGMA","rule":"yt.CombineCoreLimit","sum":76913},{"parent":"PRAGMA","rule":"yt.CommonJoinCoreLimit","sum":1854},{"parent":"PRAGMA","rule":"yt.CoreDumpPath","sum":2},{"parent":"PRAGMA","rule":"yt.DQRPCReaderInflight","sum":140},{"parent":"PRAGMA","rule":"yt.DQRPCReaderTimeout","sum":8},{"parent":"PRAGMA","rule":"yt.DatASizePerJob","sum":2150},{"parent":"PRAGMA","rule":"yt.DatASizePerPartition","sum":736},{"parent":"PRAGMA","rule":"yt.DataSizePerJob","sum":5238758},{"parent":"PRAGMA","rule":"yt.DataSizePerMapJob","sum":314915},{"parent":"PRAGMA","rule":"yt.DataSizePerPartition","sum":514836},{"parent":"PRAGMA","rule":"yt.DataSizePerSortJob","sum":200126},{"parent":"PRAGMA","rule":"yt.DatasizePerJob","sum":16},{"parent":"PRAGMA","rule":"yt.DatasizePerSortJob","sum":16},{"parent":"PRAGMA","rule":"yt.DefaultCalcMemoryLimit","sum":258857},{"parent":"PRAGMA","rule":"yt.DefaultCluster","sum":71816158},{"parent":"PRAGMA","rule":"yt.DefaultLocalityTimeout","sum":4075},{"parent":"PRAGMA","rule":"yt.DefaultMapSelectivityFactor","sum":53},{"parent":"PRAGMA","rule":"yt.DefaultMaxJobFails","sum":1549993},{"parent":"PRAGMA","rule":"yt.DefaultMemORyLimit","sum":7},{"parent":"PRAGMA","rule":"yt.DefaultMemoryLimit","sum":2061228},{"parent":"PRAGMA","rule":"yt.DefaultMemoryReserveFactor","sum":25421},{"parent":"PRAGMA","rule":"yt.DefaultOperationWeight","sum":9766568},{"parent":"PRAGMA","rule":"yt.Description","sum":236754},{"parent":"PRAGMA","rule":"yt.DisableFuseOperations","sum":2},{"parent":"PRAGMA","rule":"yt.DisableJobSplitting","sum":4770},{"parent":"PRAGMA","rule":"yt.DisableOptimizers","sum":30928},{"parent":"PRAGMA","rule":"yt.EnableDynamicStoreReadInDQ","sum":1},{"parent":"PRAGMA","rule":"yt.ErasureCodecCpu","sum":148399},{"parent":"PRAGMA","rule":"yt.EvaluationTableSizeLimit","sum":815543},{"parent":"PRAGMA","rule":"yt.ExpirationDeadline","sum":3432850},{"parent":"PRAGMA","rule":"yt.ExpirationInterval","sum":8121062},{"parent":"PRAGMA","rule":"yt.ExtendedStatsMaxChunkCount","sum":4},{"parent":"PRAGMA","rule":"yt.ExternalTx","sum":80697419},{"parent":"PRAGMA","rule":"yt.ExtraTmpfsSize","sum":95},{"parent":"PRAGMA","rule":"yt.FileCacheTtl","sum":8284523},{"parent":"PRAGMA","rule":"yt.FolderInlineDataLimit","sum":40},{"parent":"PRAGMA","rule":"yt.FolderInlineItemsLimit","sum":2},{"parent":"PRAGMA","rule":"yt.ForceInferSchema","sum":799593},{"parent":"PRAGMA","rule":"yt.ForceJobSizeAdjuster","sum":10239},{"parent":"PRAGMA","rule":"yt.GeobaseDownloadUrl","sum":62930},{"parent":"PRAGMA","rule":"yt.HybridDqDataSizeLimitForOrdered","sum":313623},{"parent":"PRAGMA","rule":"yt.HybridDqDataSizeLimitForUnordered","sum":316652},{"parent":"PRAGMA","rule":"yt.HybridDqExecution","sum":3706477},{"parent":"PRAGMA","rule":"yt.HybridDqExecutionFallback","sum":108},{"parent":"PRAGMA","rule":"yt.INFERSCHEMA","sum":1},{"parent":"PRAGMA","rule":"yt.INferSchema","sum":6},{"parent":"PRAGMA","rule":"yt.IgnoreTypeV3","sum":4588},{"parent":"PRAGMA","rule":"yt.IgnoreWeakSchema","sum":231291},{"parent":"PRAGMA","rule":"yt.IgnoreYamrDsv","sum":22558},{"parent":"PRAGMA","rule":"yt.InferSchemA","sum":11},{"parent":"PRAGMA","rule":"yt.InferSchema","sum":32288432},{"parent":"PRAGMA","rule":"yt.InferSchemaTableCountThreshold","sum":1},{"parent":"PRAGMA","rule":"yt.Inferschema","sum":85798},{"parent":"PRAGMA","rule":"yt.IntermediateAccount","sum":133151},{"parent":"PRAGMA","rule":"yt.IntermediateDataMedium","sum":296894},{"parent":"PRAGMA","rule":"yt.IntermediateReplicationFactor","sum":2809},{"parent":"PRAGMA","rule":"yt.JavascriptCpu","sum":42},{"parent":"PRAGMA","rule":"yt.JobBlockInput","sum":27},{"parent":"PRAGMA","rule":"yt.JobBlockOutput","sum":12},{"parent":"PRAGMA","rule":"yt.JobEnv","sum":14095},{"parent":"PRAGMA","rule":"yt.JoinAllowColumnRenames","sum":446},{"parent":"PRAGMA","rule":"yt.JoinCollectColumnarStatistics","sum":20346},{"parent":"PRAGMA","rule":"yt.JoinColumnarStatisticsFetcherMode","sum":593},{"parent":"PRAGMA","rule":"yt.JoinEnableStarJoin","sum":41751},{"parent":"PRAGMA","rule":"yt.JoinMergeForce","sum":53467},{"parent":"PRAGMA","rule":"yt.JoinMergeReduceJobMaxSize","sum":2741},{"parent":"PRAGMA","rule":"yt.JoinMergeTablesLimit","sum":3706},{"parent":"PRAGMA","rule":"yt.JoinMergeUnsortedFactor","sum":1663},{"parent":"PRAGMA","rule":"yt.JoinMergeUseSmallAsPrimary","sum":5978},{"parent":"PRAGMA","rule":"yt.JoinUseColumnarStatistics","sum":998},{"parent":"PRAGMA","rule":"yt.JoinWaitAllInputs","sum":16},{"parent":"PRAGMA","rule":"yt.KeepTempTables","sum":969},{"parent":"PRAGMA","rule":"yt.LayerPaths","sum":159199},{"parent":"PRAGMA","rule":"yt.LookupJoinLimit","sum":230793},{"parent":"PRAGMA","rule":"yt.LookupJoinMaxRows","sum":181147},{"parent":"PRAGMA","rule":"yt.MAXRowWeight","sum":58},{"parent":"PRAGMA","rule":"yt.MAxJobCount","sum":64},{"parent":"PRAGMA","rule":"yt.MAxRowWeight","sum":1},{"parent":"PRAGMA","rule":"yt.MapJOINLimit","sum":723},{"parent":"PRAGMA","rule":"yt.MapJoinLimit","sum":692785},{"parent":"PRAGMA","rule":"yt.MapJoinShardCount","sum":321708},{"parent":"PRAGMA","rule":"yt.MapJoinShardMinRows","sum":4},{"parent":"PRAGMA","rule":"yt.MapJoinUseFlow","sum":1},{"parent":"PRAGMA","rule":"yt.MapLocalityTimeout","sum":4},{"parent":"PRAGMA","rule":"yt.MaxChunksForDqRead","sum":120},{"parent":"PRAGMA","rule":"yt.MaxExtraJobMemoryToFuseOperations","sum":19950},{"parent":"PRAGMA","rule":"yt.MaxInputTables","sum":29603},{"parent":"PRAGMA","rule":"yt.MaxInputTablesForSortedMerge","sum":5914},{"parent":"PRAGMA","rule":"yt.MaxJobCount","sum":12548346},{"parent":"PRAGMA","rule":"yt.MaxJobcount","sum":1383},{"parent":"PRAGMA","rule":"yt.MaxKeyRangeCount","sum":9},{"parent":"PRAGMA","rule":"yt.MaxKeyWeight","sum":206800},{"parent":"PRAGMA","rule":"yt.MaxOutputTables","sum":54},{"parent":"PRAGMA","rule":"yt.MaxReplicationFactorToFuseOperations","sum":15},{"parent":"PRAGMA","rule":"yt.MaxRowWeight","sum":6104192},{"parent":"PRAGMA","rule":"yt.MaxSpeculativeJobCountPerTask","sum":2237},{"parent":"PRAGMA","rule":"yt.MinLocalityInputDataWeight","sum":8},{"parent":"PRAGMA","rule":"yt.MinPublishedAvgChunkSize","sum":3171409},{"parent":"PRAGMA","rule":"yt.MinTempAvgChunkSize","sum":178396},{"parent":"PRAGMA","rule":"yt.NativeYtTypeCompatibility","sum":15},{"parent":"PRAGMA","rule":"yt.NetworkProject","sum":609042},{"parent":"PRAGMA","rule":"yt.NightlyCompress","sum":146719},{"parent":"PRAGMA","rule":"yt.OWners","sum":21},{"parent":"PRAGMA","rule":"yt.OperationReaders","sum":12816428},{"parent":"PRAGMA","rule":"yt.OperationSpec","sum":8566187},{"parent":"PRAGMA","rule":"yt.OptimizeFor","sum":5784093},{"parent":"PRAGMA","rule":"yt.Owners","sum":65851849},{"parent":"PRAGMA","rule":"yt.POOL","sum":68},{"parent":"PRAGMA","rule":"yt.POol","sum":12},{"parent":"PRAGMA","rule":"yt.ParallelOperationsLimit","sum":1385400},{"parent":"PRAGMA","rule":"yt.PartitionByConstantKeysViaMap","sum":13},{"parent":"PRAGMA","rule":"yt.PooL","sum":1},{"parent":"PRAGMA","rule":"yt.Pool","sum":54672067},{"parent":"PRAGMA","rule":"yt.PoolTrees","sum":6601319},{"parent":"PRAGMA","rule":"yt.PrimaryMedium","sum":383871},{"parent":"PRAGMA","rule":"yt.PruneKeyFilterLambda","sum":562},{"parent":"PRAGMA","rule":"yt.PublishedAutoMerge","sum":3408556},{"parent":"PRAGMA","rule":"yt.PublishedCompressionCodec","sum":7408206},{"parent":"PRAGMA","rule":"yt.PublishedErasureCodec","sum":5395006},{"parent":"PRAGMA","rule":"yt.PublishedMedia","sum":4239},{"parent":"PRAGMA","rule":"yt.PublishedPrimaryMedium","sum":783428},{"parent":"PRAGMA","rule":"yt.PublishedReplicationFactor","sum":23632},{"parent":"PRAGMA","rule":"yt.PythonCpu","sum":82846},{"parent":"PRAGMA","rule":"yt.QueryCacheIgnoreTableRevision","sum":65393},{"parent":"PRAGMA","rule":"yt.QueryCacheMode","sum":24244197},{"parent":"PRAGMA","rule":"yt.QueryCacheSalt","sum":5},{"parent":"PRAGMA","rule":"yt.QueryCacheTtl","sum":8970969},{"parent":"PRAGMA","rule":"yt.QueryCacheUseForCalc","sum":8},{"parent":"PRAGMA","rule":"yt.QuerycacheMode","sum":2},{"parent":"PRAGMA","rule":"yt.ReleaseTempData","sum":2708518},{"parent":"PRAGMA","rule":"yt.STaticPool","sum":3},{"parent":"PRAGMA","rule":"yt.SamplingIoBlockSize","sum":3865},{"parent":"PRAGMA","rule":"yt.SchedulingTag","sum":39},{"parent":"PRAGMA","rule":"yt.SchedulingTagFilter","sum":2971},{"parent":"PRAGMA","rule":"yt.ScriptCpu","sum":4837},{"parent":"PRAGMA","rule":"yt.StartedBy","sum":264532},{"parent":"PRAGMA","rule":"yt.StaticPOol","sum":1},{"parent":"PRAGMA","rule":"yt.StaticPool","sum":113085962},{"parent":"PRAGMA","rule":"yt.Static_pool","sum":1},{"parent":"PRAGMA","rule":"yt.SuspendIfAccountLimitExceeded","sum":42782},{"parent":"PRAGMA","rule":"yt.TableContentDeliveryMode","sum":591},{"parent":"PRAGMA","rule":"yt.TableContentLocalExecution","sum":18},{"parent":"PRAGMA","rule":"yt.TableContentMaxChunksForNativeDelivery","sum":1},{"parent":"PRAGMA","rule":"yt.TableContentMaxInputTables","sum":6730},{"parent":"PRAGMA","rule":"yt.TableContentMinAvgChunkSize","sum":2629},{"parent":"PRAGMA","rule":"yt.TableContentTmpFolder","sum":28},{"parent":"PRAGMA","rule":"yt.TableContentUseSkiff","sum":11},{"parent":"PRAGMA","rule":"yt.TablesTmpFolder","sum":3437268},{"parent":"PRAGMA","rule":"yt.TempTablesTtl","sum":5386323},{"parent":"PRAGMA","rule":"yt.TemporaryAutoMerge","sum":8859300},{"parent":"PRAGMA","rule":"yt.TemporaryCompressionCodec","sum":5843040},{"parent":"PRAGMA","rule":"yt.TemporaryErasureCodec","sum":4764279},{"parent":"PRAGMA","rule":"yt.TemporaryPrimaryMedium","sum":496370},{"parent":"PRAGMA","rule":"yt.TemporaryReplicationFactor","sum":93},{"parent":"PRAGMA","rule":"yt.TentativePoolTrees","sum":1849032},{"parent":"PRAGMA","rule":"yt.TentativeTreeEligibilityMaxJobDurationRatio","sum":17551},{"parent":"PRAGMA","rule":"yt.TentativeTreeEligibilityMinJobDuration","sum":2179},{"parent":"PRAGMA","rule":"yt.TentativeTreeEligibilitySampleJobCount","sum":16205},{"parent":"PRAGMA","rule":"yt.TmpFolder","sum":31281903},{"parent":"PRAGMA","rule":"yt.TopSortMaxLimit","sum":59},{"parent":"PRAGMA","rule":"yt.TopSortSizePerJob","sum":1},{"parent":"PRAGMA","rule":"yt.USENATIVEYTTYPES","sum":25},{"parent":"PRAGMA","rule":"yt.USeNativeYtTypes","sum":12},{"parent":"PRAGMA","rule":"yt.UseColumnarStatistics","sum":166732},{"parent":"PRAGMA","rule":"yt.UseDefaultTentativePoolTrees","sum":252593},{"parent":"PRAGMA","rule":"yt.UseFlow","sum":3},{"parent":"PRAGMA","rule":"yt.UseIntermediateStreams","sum":6},{"parent":"PRAGMA","rule":"yt.UseNAtiveYtTypes","sum":1},{"parent":"PRAGMA","rule":"yt.UseNativeDescSort","sum":2032},{"parent":"PRAGMA","rule":"yt.UseNativeYtTYpes","sum":1485},{"parent":"PRAGMA","rule":"yt.UseNativeYtTypes","sum":24309630},{"parent":"PRAGMA","rule":"yt.UseNativeYttypes","sum":764},{"parent":"PRAGMA","rule":"yt.UseNativeytTypes","sum":516},{"parent":"PRAGMA","rule":"yt.UseNewPredicateExtraction","sum":182334},{"parent":"PRAGMA","rule":"yt.UseRPCReaderInDQ","sum":79},{"parent":"PRAGMA","rule":"yt.UseRPCReaderInDq","sum":12130},{"parent":"PRAGMA","rule":"yt.UseSkiff","sum":4025},{"parent":"PRAGMA","rule":"yt.UseSystemColumns","sum":2139},{"parent":"PRAGMA","rule":"yt.UseTmpfs","sum":34352},{"parent":"PRAGMA","rule":"yt.UseTypeV2","sum":4398},{"parent":"PRAGMA","rule":"yt.UseYqlRowSpecCompactForm","sum":3767},{"parent":"PRAGMA","rule":"yt.UserSlots","sum":2522195},{"parent":"PRAGMA","rule":"yt.ViewIsolation","sum":969},{"parent":"PRAGMA","rule":"yt.WideFlowLimit","sum":158125},{"parent":"PRAGMA","rule":"yt.auth","sum":47218},{"parent":"PRAGMA","rule":"yt.datasizeperjob","sum":2026},{"parent":"PRAGMA","rule":"yt.defaultoperationweight","sum":47},{"parent":"PRAGMA","rule":"yt.forceinferschema","sum":48},{"parent":"PRAGMA","rule":"yt.inferSchema","sum":54889},{"parent":"PRAGMA","rule":"yt.infer_schema","sum":10},{"parent":"PRAGMA","rule":"yt.inferschema","sum":2977},{"parent":"PRAGMA","rule":"yt.mapjoinlimit","sum":97781},{"parent":"PRAGMA","rule":"yt.maxRowWeight","sum":1},{"parent":"PRAGMA","rule":"yt.max_row_weight","sum":19},{"parent":"PRAGMA","rule":"yt.maxjobcount","sum":5},{"parent":"PRAGMA","rule":"yt.maxrowweight","sum":41890},{"parent":"PRAGMA","rule":"yt.minPublishedAvgChunksize","sum":11},{"parent":"PRAGMA","rule":"yt.network_project","sum":14499},{"parent":"PRAGMA","rule":"yt.pool","sum":6845320},{"parent":"PRAGMA","rule":"yt.pool_trees","sum":1},{"parent":"PRAGMA","rule":"yt.pooltrees","sum":53},{"parent":"PRAGMA","rule":"yt.publishedcompressioncodec","sum":403},{"parent":"PRAGMA","rule":"yt.staticPool","sum":1265865},{"parent":"PRAGMA","rule":"yt.static_pool","sum":20},{"parent":"PRAGMA","rule":"yt.staticpool","sum":10639},{"parent":"PRAGMA","rule":"yt.tmpFolder","sum":76657},{"parent":"PRAGMA","rule":"yt.tmpfolder","sum":65},{"parent":"PRAGMA","rule":"yt.useNativeYtTYpes","sum":1},{"parent":"PRAGMA","rule":"yt.useNativeYtTypes","sum":911},{"parent":"PRAGMA","rule":"yt.usenativeyttypes","sum":168},{"parent":"READ_HINT","rule":"COLUMNS","sum":823297},{"parent":"READ_HINT","rule":"CoLUMNS","sum":2},{"parent":"READ_HINT","rule":"Columns","sum":24},{"parent":"READ_HINT","rule":"DIRECT_READ","sum":98},{"parent":"READ_HINT","rule":"FORCE_INFER_SCHEMA","sum":18211},{"parent":"READ_HINT","rule":"ForceInferSchema","sum":350},{"parent":"READ_HINT","rule":"IGNORETYPEV3","sum":2},{"parent":"READ_HINT","rule":"IGNORE_TYPE_V3","sum":4},{"parent":"READ_HINT","rule":"INFER_SCHEMA","sum":105278},{"parent":"READ_HINT","rule":"INLINE","sum":87384},{"parent":"READ_HINT","rule":"InferSchema","sum":2282},{"parent":"READ_HINT","rule":"Infer_Schema","sum":3},{"parent":"READ_HINT","rule":"SCHEMA","sum":16885246},{"parent":"READ_HINT","rule":"SChema","sum":2},{"parent":"READ_HINT","rule":"Schema","sum":39235},{"parent":"READ_HINT","rule":"TRUNCATE","sum":5},{"parent":"READ_HINT","rule":"UNORDERED","sum":6558},{"parent":"READ_HINT","rule":"USER_ATTRS","sum":1},{"parent":"READ_HINT","rule":"Unordered","sum":365},{"parent":"READ_HINT","rule":"XLOCK","sum":144066},{"parent":"READ_HINT","rule":"columns","sum":423998},{"parent":"READ_HINT","rule":"direct_read","sum":1},{"parent":"READ_HINT","rule":"downsampling.aggregation","sum":2218},{"parent":"READ_HINT","rule":"downsampling.disabled","sum":2100},{"parent":"READ_HINT","rule":"downsampling.fill","sum":1723},{"parent":"READ_HINT","rule":"downsampling.grid_interval","sum":2470},{"parent":"READ_HINT","rule":"force_infer_schema","sum":2},{"parent":"READ_HINT","rule":"from","sum":22919},{"parent":"READ_HINT","rule":"infer_schema","sum":190},{"parent":"READ_HINT","rule":"infer_scheme","sum":17},{"parent":"READ_HINT","rule":"inferschema","sum":1},{"parent":"READ_HINT","rule":"inline","sum":75007},{"parent":"READ_HINT","rule":"labels","sum":20802},{"parent":"READ_HINT","rule":"program","sum":23171},{"parent":"READ_HINT","rule":"schema","sum":773737},{"parent":"READ_HINT","rule":"to","sum":22919},{"parent":"READ_HINT","rule":"unordered","sum":13598},{"parent":"READ_HINT","rule":"xlock","sum":260971},{"parent":"TRule_action_or_subquery_args","rule":"TRule_action_or_subquery_args.Block2","sum":4946777},{"parent":"TRule_action_or_subquery_args","rule":"TRule_action_or_subquery_args.Rule_opt_bind_parameter1","sum":13965321},{"parent":"TRule_action_or_subquery_args.TBlock2","rule":"TRule_action_or_subquery_args.TBlock2.Rule_opt_bind_parameter2","sum":7512439},{"parent":"TRule_action_or_subquery_args.TBlock2","rule":"TRule_action_or_subquery_args.TBlock2.Token1","sum":7512439},{"parent":"TRule_add_subexpr","rule":"TRule_add_subexpr.Block2","sum":136340311},{"parent":"TRule_add_subexpr","rule":"TRule_add_subexpr.Rule_mul_subexpr1","sum":15625099920},{"parent":"TRule_add_subexpr.TBlock2","rule":"TRule_add_subexpr.TBlock2.Rule_mul_subexpr2","sum":167934015},{"parent":"TRule_add_subexpr.TBlock2","rule":"TRule_add_subexpr.TBlock2.Token1","sum":167934015},{"parent":"TRule_an_id","rule":"TRule_an_id.Alt_an_id1","sum":2004199787},{"parent":"TRule_an_id.TAlt1","rule":"TRule_an_id.TAlt1.Rule_id1","sum":2004199787},{"parent":"TRule_an_id_as_compat","rule":"TRule_an_id_as_compat.Alt_an_id_as_compat1","sum":2995725},{"parent":"TRule_an_id_as_compat.TAlt1","rule":"TRule_an_id_as_compat.TAlt1.Rule_id_as_compat1","sum":2995725},{"parent":"TRule_an_id_expr","rule":"TRule_an_id_expr.Alt_an_id_expr1","sum":96313621},{"parent":"TRule_an_id_expr.TAlt1","rule":"TRule_an_id_expr.TAlt1.Rule_id_expr1","sum":96313621},{"parent":"TRule_an_id_hint","rule":"TRule_an_id_hint.Alt_an_id_hint1","sum":154481585},{"parent":"TRule_an_id_hint.TAlt1","rule":"TRule_an_id_hint.TAlt1.Rule_id_hint1","sum":154481585},{"parent":"TRule_an_id_or_type","rule":"TRule_an_id_or_type.Alt_an_id_or_type1","sum":9630859718},{"parent":"TRule_an_id_or_type","rule":"TRule_an_id_or_type.Alt_an_id_or_type2","sum":7},{"parent":"TRule_an_id_or_type.TAlt1","rule":"TRule_an_id_or_type.TAlt1.Rule_id_or_type1","sum":9630859718},{"parent":"TRule_an_id_or_type.TAlt2","rule":"TRule_an_id_or_type.TAlt2.Token1","sum":7},{"parent":"TRule_an_id_pure","rule":"TRule_an_id_pure.Alt_an_id_pure1","sum":677783605},{"parent":"TRule_an_id_pure.TAlt1","rule":"TRule_an_id_pure.TAlt1.Rule_identifier1","sum":677783605},{"parent":"TRule_an_id_schema","rule":"TRule_an_id_schema.Alt_an_id_schema1","sum":1181},{"parent":"TRule_an_id_schema.TAlt1","rule":"TRule_an_id_schema.TAlt1.Rule_id_schema1","sum":1181},{"parent":"TRule_an_id_table","rule":"TRule_an_id_table.Alt_an_id_table1","sum":330889868},{"parent":"TRule_an_id_table","rule":"TRule_an_id_table.Alt_an_id_table2","sum":1},{"parent":"TRule_an_id_table.TAlt1","rule":"TRule_an_id_table.TAlt1.Rule_id_table1","sum":330889868},{"parent":"TRule_an_id_table.TAlt2","rule":"TRule_an_id_table.TAlt2.Token1","sum":1},{"parent":"TRule_an_id_window","rule":"TRule_an_id_window.Alt_an_id_window1","sum":46670411},{"parent":"TRule_an_id_window.TAlt1","rule":"TRule_an_id_window.TAlt1.Rule_id_window1","sum":46670411},{"parent":"TRule_an_id_without","rule":"TRule_an_id_without.Alt_an_id_without1","sum":23304335},{"parent":"TRule_an_id_without.TAlt1","rule":"TRule_an_id_without.TAlt1.Rule_id_without1","sum":23304335},{"parent":"TRule_and_subexpr","rule":"TRule_and_subexpr.Block2","sum":29479},{"parent":"TRule_and_subexpr","rule":"TRule_and_subexpr.Rule_xor_subexpr1","sum":14287217648},{"parent":"TRule_and_subexpr.TBlock2","rule":"TRule_and_subexpr.TBlock2.Rule_xor_subexpr2","sum":29543},{"parent":"TRule_and_subexpr.TBlock2","rule":"TRule_and_subexpr.TBlock2.Token1","sum":29543},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr1","sum":5164970128},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr10","sum":36006226},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr11","sum":8514188},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr12","sum":14625860},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr2","sum":1772155576},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr3","sum":446923069},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr4","sum":398528656},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr5","sum":77117},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr6","sum":61757734},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr7","sum":928573299},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr8","sum":164072},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr9","sum":511417},{"parent":"TRule_atom_expr.TAlt1","rule":"TRule_atom_expr.TAlt1.Rule_literal_value1","sum":5164970128},{"parent":"TRule_atom_expr.TAlt10","rule":"TRule_atom_expr.TAlt10.Rule_list_literal1","sum":36006226},{"parent":"TRule_atom_expr.TAlt11","rule":"TRule_atom_expr.TAlt11.Rule_dict_literal1","sum":8514188},{"parent":"TRule_atom_expr.TAlt12","rule":"TRule_atom_expr.TAlt12.Rule_struct_literal1","sum":14625860},{"parent":"TRule_atom_expr.TAlt2","rule":"TRule_atom_expr.TAlt2.Rule_bind_parameter1","sum":1772155576},{"parent":"TRule_atom_expr.TAlt3","rule":"TRule_atom_expr.TAlt3.Rule_lambda1","sum":446923069},{"parent":"TRule_atom_expr.TAlt4","rule":"TRule_atom_expr.TAlt4.Rule_cast_expr1","sum":398528656},{"parent":"TRule_atom_expr.TAlt5","rule":"TRule_atom_expr.TAlt5.Rule_exists_expr1","sum":77117},{"parent":"TRule_atom_expr.TAlt6","rule":"TRule_atom_expr.TAlt6.Rule_case_expr1","sum":61757734},{"parent":"TRule_atom_expr.TAlt7","rule":"TRule_atom_expr.TAlt7.Block3","sum":928573299},{"parent":"TRule_atom_expr.TAlt7","rule":"TRule_atom_expr.TAlt7.Rule_an_id_or_type1","sum":928573299},{"parent":"TRule_atom_expr.TAlt7","rule":"TRule_atom_expr.TAlt7.Token2","sum":928573299},{"parent":"TRule_atom_expr.TAlt7.TBlock3","rule":"TRule_atom_expr.TAlt7.TBlock3.Alt1","sum":928572063},{"parent":"TRule_atom_expr.TAlt7.TBlock3","rule":"TRule_atom_expr.TAlt7.TBlock3.Alt2","sum":1236},{"parent":"TRule_atom_expr.TAlt7.TBlock3.TAlt1","rule":"TRule_atom_expr.TAlt7.TBlock3.TAlt1.Rule_id_or_type1","sum":928572063},{"parent":"TRule_atom_expr.TAlt7.TBlock3.TAlt2","rule":"TRule_atom_expr.TAlt7.TBlock3.TAlt2.Token1","sum":1236},{"parent":"TRule_atom_expr.TAlt8","rule":"TRule_atom_expr.TAlt8.Rule_value_constructor1","sum":164072},{"parent":"TRule_atom_expr.TAlt9","rule":"TRule_atom_expr.TAlt9.Rule_bitcast_expr1","sum":511417},{"parent":"TRule_bind_parameter","rule":"TRule_bind_parameter.Block2","sum":3704552329},{"parent":"TRule_bind_parameter","rule":"TRule_bind_parameter.Token1","sum":3704552329},{"parent":"TRule_bind_parameter.TBlock2","rule":"TRule_bind_parameter.TBlock2.Alt1","sum":3704540399},{"parent":"TRule_bind_parameter.TBlock2","rule":"TRule_bind_parameter.TBlock2.Alt2","sum":9450},{"parent":"TRule_bind_parameter.TBlock2","rule":"TRule_bind_parameter.TBlock2.Alt3","sum":2480},{"parent":"TRule_bind_parameter.TBlock2.TAlt1","rule":"TRule_bind_parameter.TBlock2.TAlt1.Rule_an_id_or_type1","sum":3704540399},{"parent":"TRule_bind_parameter.TBlock2.TAlt2","rule":"TRule_bind_parameter.TBlock2.TAlt2.Token1","sum":9450},{"parent":"TRule_bind_parameter.TBlock2.TAlt3","rule":"TRule_bind_parameter.TBlock2.TAlt3.Token1","sum":2480},{"parent":"TRule_bind_parameter_list","rule":"TRule_bind_parameter_list.Block2","sum":246364},{"parent":"TRule_bind_parameter_list","rule":"TRule_bind_parameter_list.Rule_bind_parameter1","sum":1007810457},{"parent":"TRule_bind_parameter_list.TBlock2","rule":"TRule_bind_parameter_list.TBlock2.Rule_bind_parameter2","sum":339375},{"parent":"TRule_bind_parameter_list.TBlock2","rule":"TRule_bind_parameter_list.TBlock2.Token1","sum":339375},{"parent":"TRule_bit_subexpr","rule":"TRule_bit_subexpr.Block2","sum":138818444},{"parent":"TRule_bit_subexpr","rule":"TRule_bit_subexpr.Rule_add_subexpr1","sum":15466701546},{"parent":"TRule_bit_subexpr.TBlock2","rule":"TRule_bit_subexpr.TBlock2.Rule_add_subexpr2","sum":158398374},{"parent":"TRule_bit_subexpr.TBlock2","rule":"TRule_bit_subexpr.TBlock2.Token1","sum":158398374},{"parent":"TRule_bitcast_expr","rule":"TRule_bitcast_expr.Rule_expr3","sum":511417},{"parent":"TRule_bitcast_expr","rule":"TRule_bitcast_expr.Rule_type_name_simple5","sum":511417},{"parent":"TRule_bitcast_expr","rule":"TRule_bitcast_expr.Token1","sum":511417},{"parent":"TRule_bitcast_expr","rule":"TRule_bitcast_expr.Token2","sum":511417},{"parent":"TRule_bitcast_expr","rule":"TRule_bitcast_expr.Token4","sum":511417},{"parent":"TRule_bitcast_expr","rule":"TRule_bitcast_expr.Token6","sum":511417},{"parent":"TRule_bool_value","rule":"TRule_bool_value.Token1","sum":104326396},{"parent":"TRule_call_action","rule":"TRule_call_action.Block1","sum":9449135},{"parent":"TRule_call_action","rule":"TRule_call_action.Block3","sum":7177188},{"parent":"TRule_call_action","rule":"TRule_call_action.Token2","sum":9449135},{"parent":"TRule_call_action","rule":"TRule_call_action.Token4","sum":9449135},{"parent":"TRule_call_action.TBlock1","rule":"TRule_call_action.TBlock1.Alt1","sum":9323053},{"parent":"TRule_call_action.TBlock1","rule":"TRule_call_action.TBlock1.Alt2","sum":126082},{"parent":"TRule_call_action.TBlock1.TAlt1","rule":"TRule_call_action.TBlock1.TAlt1.Rule_bind_parameter1","sum":9323053},{"parent":"TRule_call_action.TBlock1.TAlt2","rule":"TRule_call_action.TBlock1.TAlt2.Token1","sum":126082},{"parent":"TRule_call_action.TBlock3","rule":"TRule_call_action.TBlock3.Rule_expr_list1","sum":7177188},{"parent":"TRule_callable_arg","rule":"TRule_callable_arg.Block2","sum":1},{"parent":"TRule_callable_arg","rule":"TRule_callable_arg.Rule_variant_arg1","sum":17996377},{"parent":"TRule_callable_arg.TBlock2","rule":"TRule_callable_arg.TBlock2.Token1","sum":1},{"parent":"TRule_callable_arg.TBlock2","rule":"TRule_callable_arg.TBlock2.Token2","sum":1},{"parent":"TRule_callable_arg.TBlock2","rule":"TRule_callable_arg.TBlock2.Token3","sum":1},{"parent":"TRule_callable_arg_list","rule":"TRule_callable_arg_list.Block2","sum":4372330},{"parent":"TRule_callable_arg_list","rule":"TRule_callable_arg_list.Rule_callable_arg1","sum":9778163},{"parent":"TRule_callable_arg_list.TBlock2","rule":"TRule_callable_arg_list.TBlock2.Rule_callable_arg2","sum":8218214},{"parent":"TRule_callable_arg_list.TBlock2","rule":"TRule_callable_arg_list.TBlock2.Token1","sum":8218214},{"parent":"TRule_case_expr","rule":"TRule_case_expr.Block2","sum":4698567},{"parent":"TRule_case_expr","rule":"TRule_case_expr.Block3","sum":61757738},{"parent":"TRule_case_expr","rule":"TRule_case_expr.Block4","sum":61757738},{"parent":"TRule_case_expr","rule":"TRule_case_expr.Token1","sum":61757738},{"parent":"TRule_case_expr","rule":"TRule_case_expr.Token5","sum":61757738},{"parent":"TRule_case_expr.TBlock2","rule":"TRule_case_expr.TBlock2.Rule_expr1","sum":4698567},{"parent":"TRule_case_expr.TBlock3","rule":"TRule_case_expr.TBlock3.Rule_when_expr1","sum":158362267},{"parent":"TRule_case_expr.TBlock4","rule":"TRule_case_expr.TBlock4.Rule_expr2","sum":61757738},{"parent":"TRule_case_expr.TBlock4","rule":"TRule_case_expr.TBlock4.Token1","sum":61757738},{"parent":"TRule_cast_expr","rule":"TRule_cast_expr.Rule_expr3","sum":398573044},{"parent":"TRule_cast_expr","rule":"TRule_cast_expr.Rule_type_name_or_bind5","sum":398573044},{"parent":"TRule_cast_expr","rule":"TRule_cast_expr.Token1","sum":398573044},{"parent":"TRule_cast_expr","rule":"TRule_cast_expr.Token2","sum":398573044},{"parent":"TRule_cast_expr","rule":"TRule_cast_expr.Token4","sum":398573044},{"parent":"TRule_cast_expr","rule":"TRule_cast_expr.Token6","sum":398573044},{"parent":"TRule_cluster_expr","rule":"TRule_cluster_expr.Block1","sum":6780419},{"parent":"TRule_cluster_expr","rule":"TRule_cluster_expr.Block2","sum":374925174},{"parent":"TRule_cluster_expr.TBlock1","rule":"TRule_cluster_expr.TBlock1.Rule_an_id1","sum":6780419},{"parent":"TRule_cluster_expr.TBlock1","rule":"TRule_cluster_expr.TBlock1.Token2","sum":6780419},{"parent":"TRule_cluster_expr.TBlock2","rule":"TRule_cluster_expr.TBlock2.Alt1","sum":374925174},{"parent":"TRule_cluster_expr.TBlock2.TAlt1","rule":"TRule_cluster_expr.TBlock2.TAlt1.Rule_pure_column_or_named1","sum":374925174},{"parent":"TRule_column_list","rule":"TRule_column_list.Block2","sum":283315},{"parent":"TRule_column_list","rule":"TRule_column_list.Block3","sum":812},{"parent":"TRule_column_list","rule":"TRule_column_list.Rule_column_name1","sum":850906},{"parent":"TRule_column_list.TBlock2","rule":"TRule_column_list.TBlock2.Rule_column_name2","sum":1125538},{"parent":"TRule_column_list.TBlock2","rule":"TRule_column_list.TBlock2.Token1","sum":1125538},{"parent":"TRule_column_list.TBlock3","rule":"TRule_column_list.TBlock3.Token1","sum":812},{"parent":"TRule_column_name","rule":"TRule_column_name.Rule_an_id2","sum":23349011},{"parent":"TRule_column_name","rule":"TRule_column_name.Rule_opt_id_prefix1","sum":23349011},{"parent":"TRule_column_order_by_specification","rule":"TRule_column_order_by_specification.Rule_an_id1","sum":107},{"parent":"TRule_column_schema","rule":"TRule_column_schema.Rule_an_id_schema1","sum":1181},{"parent":"TRule_column_schema","rule":"TRule_column_schema.Rule_opt_column_constraints4","sum":1181},{"parent":"TRule_column_schema","rule":"TRule_column_schema.Rule_type_name_or_bind2","sum":1181},{"parent":"TRule_commit_stmt","rule":"TRule_commit_stmt.Token1","sum":13024992},{"parent":"TRule_con_subexpr","rule":"TRule_con_subexpr.Alt_con_subexpr1","sum":15934798710},{"parent":"TRule_con_subexpr","rule":"TRule_con_subexpr.Alt_con_subexpr2","sum":87770220},{"parent":"TRule_con_subexpr.TAlt1","rule":"TRule_con_subexpr.TAlt1.Rule_unary_subexpr1","sum":15934798710},{"parent":"TRule_con_subexpr.TAlt2","rule":"TRule_con_subexpr.TAlt2.Rule_unary_op1","sum":87770220},{"parent":"TRule_con_subexpr.TAlt2","rule":"TRule_con_subexpr.TAlt2.Rule_unary_subexpr2","sum":87770220},{"parent":"TRule_cond_expr","rule":"TRule_cond_expr.Alt_cond_expr1","sum":52236530},{"parent":"TRule_cond_expr","rule":"TRule_cond_expr.Alt_cond_expr2","sum":126151164},{"parent":"TRule_cond_expr","rule":"TRule_cond_expr.Alt_cond_expr3","sum":172789592},{"parent":"TRule_cond_expr","rule":"TRule_cond_expr.Alt_cond_expr4","sum":25002100},{"parent":"TRule_cond_expr","rule":"TRule_cond_expr.Alt_cond_expr5","sum":720021837},{"parent":"TRule_cond_expr.TAlt1","rule":"TRule_cond_expr.TAlt1.Block1","sum":9292433},{"parent":"TRule_cond_expr.TAlt1","rule":"TRule_cond_expr.TAlt1.Block4","sum":92834},{"parent":"TRule_cond_expr.TAlt1","rule":"TRule_cond_expr.TAlt1.Rule_eq_subexpr3","sum":52236530},{"parent":"TRule_cond_expr.TAlt1","rule":"TRule_cond_expr.TAlt1.Rule_match_op2","sum":52236530},{"parent":"TRule_cond_expr.TAlt1.TBlock1","rule":"TRule_cond_expr.TAlt1.TBlock1.Token1","sum":9292433},{"parent":"TRule_cond_expr.TAlt1.TBlock4","rule":"TRule_cond_expr.TAlt1.TBlock4.Rule_eq_subexpr2","sum":92834},{"parent":"TRule_cond_expr.TAlt1.TBlock4","rule":"TRule_cond_expr.TAlt1.TBlock4.Token1","sum":92834},{"parent":"TRule_cond_expr.TAlt2","rule":"TRule_cond_expr.TAlt2.Block1","sum":26188977},{"parent":"TRule_cond_expr.TAlt2","rule":"TRule_cond_expr.TAlt2.Block3","sum":3143455},{"parent":"TRule_cond_expr.TAlt2","rule":"TRule_cond_expr.TAlt2.Rule_in_expr4","sum":126151164},{"parent":"TRule_cond_expr.TAlt2","rule":"TRule_cond_expr.TAlt2.Token2","sum":126151164},{"parent":"TRule_cond_expr.TAlt2.TBlock1","rule":"TRule_cond_expr.TAlt2.TBlock1.Token1","sum":26188977},{"parent":"TRule_cond_expr.TAlt2.TBlock3","rule":"TRule_cond_expr.TAlt2.TBlock3.Token1","sum":3143455},{"parent":"TRule_cond_expr.TAlt3","rule":"TRule_cond_expr.TAlt3.Block1","sum":172789592},{"parent":"TRule_cond_expr.TAlt3.TBlock1","rule":"TRule_cond_expr.TAlt3.TBlock1.Alt1","sum":163},{"parent":"TRule_cond_expr.TAlt3.TBlock1","rule":"TRule_cond_expr.TAlt3.TBlock1.Alt2","sum":410},{"parent":"TRule_cond_expr.TAlt3.TBlock1","rule":"TRule_cond_expr.TAlt3.TBlock1.Alt3","sum":60725071},{"parent":"TRule_cond_expr.TAlt3.TBlock1","rule":"TRule_cond_expr.TAlt3.TBlock1.Alt4","sum":112063948},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt1","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt1.Token1","sum":163},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt2","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt2.Token1","sum":410},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt3","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt3.Token1","sum":60725071},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt3","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt3.Token2","sum":60725071},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt4","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt4.Block1","sum":112022484},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt4","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt4.Token2","sum":112063948},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt4","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt4.Token3","sum":112063948},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt4.TBlock1","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt4.TBlock1.Token1","sum":112022484},{"parent":"TRule_cond_expr.TAlt4","rule":"TRule_cond_expr.TAlt4.Block1","sum":403852},{"parent":"TRule_cond_expr.TAlt4","rule":"TRule_cond_expr.TAlt4.Block3","sum":25},{"parent":"TRule_cond_expr.TAlt4","rule":"TRule_cond_expr.TAlt4.Rule_eq_subexpr4","sum":25002100},{"parent":"TRule_cond_expr.TAlt4","rule":"TRule_cond_expr.TAlt4.Rule_eq_subexpr6","sum":25002100},{"parent":"TRule_cond_expr.TAlt4","rule":"TRule_cond_expr.TAlt4.Token2","sum":25002100},{"parent":"TRule_cond_expr.TAlt4","rule":"TRule_cond_expr.TAlt4.Token5","sum":25002100},{"parent":"TRule_cond_expr.TAlt4.TBlock1","rule":"TRule_cond_expr.TAlt4.TBlock1.Token1","sum":403852},{"parent":"TRule_cond_expr.TAlt4.TBlock3","rule":"TRule_cond_expr.TAlt4.TBlock3.Token1","sum":25},{"parent":"TRule_cond_expr.TAlt5","rule":"TRule_cond_expr.TAlt5.Block1","sum":720021837},{"parent":"TRule_cond_expr.TAlt5.TBlock1","rule":"TRule_cond_expr.TAlt5.TBlock1.Block1","sum":720023818},{"parent":"TRule_cond_expr.TAlt5.TBlock1","rule":"TRule_cond_expr.TAlt5.TBlock1.Rule_eq_subexpr2","sum":720023818},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.Alt1","sum":492538742},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.Alt2","sum":172429585},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.Alt3","sum":49596380},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.Alt4","sum":5060501},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.Alt5","sum":398610},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt1","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt1.Token1","sum":492538742},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt2","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt2.Token1","sum":172429585},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt3","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt3.Token1","sum":49596380},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt4","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt4.Token1","sum":5060501},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt5","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt5.Rule_distinct_from_op1","sum":398610},{"parent":"TRule_create_table_entry","rule":"TRule_create_table_entry.Alt_create_table_entry1","sum":1181},{"parent":"TRule_create_table_entry","rule":"TRule_create_table_entry.Alt_create_table_entry2","sum":233},{"parent":"TRule_create_table_entry.TAlt1","rule":"TRule_create_table_entry.TAlt1.Rule_column_schema1","sum":1181},{"parent":"TRule_create_table_entry.TAlt2","rule":"TRule_create_table_entry.TAlt2.Rule_table_constraint1","sum":233},{"parent":"TRule_create_table_stmt","rule":"TRule_create_table_stmt.Block3","sum":127},{"parent":"TRule_create_table_stmt","rule":"TRule_create_table_stmt.Block8","sum":127},{"parent":"TRule_create_table_stmt","rule":"TRule_create_table_stmt.Rule_create_table_entry7","sum":127},{"parent":"TRule_create_table_stmt","rule":"TRule_create_table_stmt.Rule_simple_table_ref5","sum":127},{"parent":"TRule_create_table_stmt","rule":"TRule_create_table_stmt.Token1","sum":127},{"parent":"TRule_create_table_stmt","rule":"TRule_create_table_stmt.Token10","sum":127},{"parent":"TRule_create_table_stmt","rule":"TRule_create_table_stmt.Token6","sum":127},{"parent":"TRule_create_table_stmt.TBlock3","rule":"TRule_create_table_stmt.TBlock3.Alt1","sum":127},{"parent":"TRule_create_table_stmt.TBlock3.TAlt1","rule":"TRule_create_table_stmt.TBlock3.TAlt1.Token1","sum":127},{"parent":"TRule_create_table_stmt.TBlock8","rule":"TRule_create_table_stmt.TBlock8.Rule_create_table_entry2","sum":1287},{"parent":"TRule_create_table_stmt.TBlock8","rule":"TRule_create_table_stmt.TBlock8.Token1","sum":1287},{"parent":"TRule_cube_list","rule":"TRule_cube_list.Rule_ordinary_grouping_set_list3","sum":276720},{"parent":"TRule_cube_list","rule":"TRule_cube_list.Token1","sum":276720},{"parent":"TRule_cube_list","rule":"TRule_cube_list.Token2","sum":276720},{"parent":"TRule_cube_list","rule":"TRule_cube_list.Token4","sum":276720},{"parent":"TRule_declare_stmt","rule":"TRule_declare_stmt.Rule_bind_parameter2","sum":156488693},{"parent":"TRule_declare_stmt","rule":"TRule_declare_stmt.Rule_type_name4","sum":156488693},{"parent":"TRule_declare_stmt","rule":"TRule_declare_stmt.Token1","sum":156488693},{"parent":"TRule_declare_stmt","rule":"TRule_declare_stmt.Token3","sum":156488693},{"parent":"TRule_define_action_or_subquery_body","rule":"TRule_define_action_or_subquery_body.Block1","sum":45603},{"parent":"TRule_define_action_or_subquery_body","rule":"TRule_define_action_or_subquery_body.Block2","sum":36158492},{"parent":"TRule_define_action_or_subquery_body.TBlock1","rule":"TRule_define_action_or_subquery_body.TBlock1.Token1","sum":45603},{"parent":"TRule_define_action_or_subquery_body.TBlock2","rule":"TRule_define_action_or_subquery_body.TBlock2.Block2","sum":16097297},{"parent":"TRule_define_action_or_subquery_body.TBlock2","rule":"TRule_define_action_or_subquery_body.TBlock2.Block3","sum":23550413},{"parent":"TRule_define_action_or_subquery_body.TBlock2","rule":"TRule_define_action_or_subquery_body.TBlock2.Rule_sql_stmt_core1","sum":36158492},{"parent":"TRule_define_action_or_subquery_body.TBlock2.TBlock2","rule":"TRule_define_action_or_subquery_body.TBlock2.TBlock2.Block1","sum":45947941},{"parent":"TRule_define_action_or_subquery_body.TBlock2.TBlock2","rule":"TRule_define_action_or_subquery_body.TBlock2.TBlock2.Rule_sql_stmt_core2","sum":45947941},{"parent":"TRule_define_action_or_subquery_body.TBlock2.TBlock2.TBlock1","rule":"TRule_define_action_or_subquery_body.TBlock2.TBlock2.TBlock1.Token1","sum":45961035},{"parent":"TRule_define_action_or_subquery_body.TBlock2.TBlock3","rule":"TRule_define_action_or_subquery_body.TBlock2.TBlock3.Token1","sum":23576206},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Block5","sum":13965321},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Rule_bind_parameter3","sum":22288095},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Rule_define_action_or_subquery_body8","sum":22288095},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Token1","sum":22288095},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Token10","sum":22288095},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Token2","sum":22288095},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Token4","sum":22288095},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Token6","sum":22288095},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Token7","sum":22288095},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Token9","sum":22288095},{"parent":"TRule_define_action_or_subquery_stmt.TBlock5","rule":"TRule_define_action_or_subquery_stmt.TBlock5.Rule_action_or_subquery_args1","sum":13965321},{"parent":"TRule_dict_literal","rule":"TRule_dict_literal.Block2","sum":8224534},{"parent":"TRule_dict_literal","rule":"TRule_dict_literal.Block3","sum":2250848},{"parent":"TRule_dict_literal","rule":"TRule_dict_literal.Token1","sum":8968921},{"parent":"TRule_dict_literal","rule":"TRule_dict_literal.Token4","sum":8968921},{"parent":"TRule_dict_literal.TBlock2","rule":"TRule_dict_literal.TBlock2.Rule_expr_dict_list1","sum":8224534},{"parent":"TRule_dict_literal.TBlock3","rule":"TRule_dict_literal.TBlock3.Token1","sum":2250848},{"parent":"TRule_distinct_from_op","rule":"TRule_distinct_from_op.Block2","sum":118905},{"parent":"TRule_distinct_from_op","rule":"TRule_distinct_from_op.Token1","sum":398610},{"parent":"TRule_distinct_from_op","rule":"TRule_distinct_from_op.Token3","sum":398610},{"parent":"TRule_distinct_from_op","rule":"TRule_distinct_from_op.Token4","sum":398610},{"parent":"TRule_distinct_from_op.TBlock2","rule":"TRule_distinct_from_op.TBlock2.Token1","sum":118905},{"parent":"TRule_do_stmt","rule":"TRule_do_stmt.Block2","sum":23326020},{"parent":"TRule_do_stmt","rule":"TRule_do_stmt.Token1","sum":23326020},{"parent":"TRule_do_stmt.TBlock2","rule":"TRule_do_stmt.TBlock2.Alt1","sum":9449135},{"parent":"TRule_do_stmt.TBlock2","rule":"TRule_do_stmt.TBlock2.Alt2","sum":13876885},{"parent":"TRule_do_stmt.TBlock2.TAlt1","rule":"TRule_do_stmt.TBlock2.TAlt1.Rule_call_action1","sum":9449135},{"parent":"TRule_do_stmt.TBlock2.TAlt2","rule":"TRule_do_stmt.TBlock2.TAlt2.Rule_inline_action1","sum":13876885},{"parent":"TRule_double_question","rule":"TRule_double_question.Token1","sum":108282209},{"parent":"TRule_double_question","rule":"TRule_double_question.Token2","sum":108282209},{"parent":"TRule_drop_table_stmt","rule":"TRule_drop_table_stmt.Block2","sum":2568070},{"parent":"TRule_drop_table_stmt","rule":"TRule_drop_table_stmt.Block3","sum":3},{"parent":"TRule_drop_table_stmt","rule":"TRule_drop_table_stmt.Rule_simple_table_ref4","sum":2568070},{"parent":"TRule_drop_table_stmt","rule":"TRule_drop_table_stmt.Token1","sum":2568070},{"parent":"TRule_drop_table_stmt.TBlock2","rule":"TRule_drop_table_stmt.TBlock2.Alt1","sum":2568070},{"parent":"TRule_drop_table_stmt.TBlock2.TAlt1","rule":"TRule_drop_table_stmt.TBlock2.TAlt1.Token1","sum":2568070},{"parent":"TRule_drop_table_stmt.TBlock3","rule":"TRule_drop_table_stmt.TBlock3.Token1","sum":3},{"parent":"TRule_drop_table_stmt.TBlock3","rule":"TRule_drop_table_stmt.TBlock3.Token2","sum":3},{"parent":"TRule_eq_subexpr","rule":"TRule_eq_subexpr.Block2","sum":239600395},{"parent":"TRule_eq_subexpr","rule":"TRule_eq_subexpr.Rule_neq_subexpr1","sum":15109604573},{"parent":"TRule_eq_subexpr.TBlock2","rule":"TRule_eq_subexpr.TBlock2.Rule_neq_subexpr2","sum":239600449},{"parent":"TRule_eq_subexpr.TBlock2","rule":"TRule_eq_subexpr.TBlock2.Token1","sum":239600449},{"parent":"TRule_exists_expr","rule":"TRule_exists_expr.Block3","sum":77117},{"parent":"TRule_exists_expr","rule":"TRule_exists_expr.Token1","sum":77117},{"parent":"TRule_exists_expr","rule":"TRule_exists_expr.Token2","sum":77117},{"parent":"TRule_exists_expr","rule":"TRule_exists_expr.Token4","sum":77117},{"parent":"TRule_exists_expr.TBlock3","rule":"TRule_exists_expr.TBlock3.Alt1","sum":77117},{"parent":"TRule_exists_expr.TBlock3.TAlt1","rule":"TRule_exists_expr.TBlock3.TAlt1.Rule_select_stmt1","sum":77117},{"parent":"TRule_expr","rule":"TRule_expr.Alt_expr1","sum":13700581585},{"parent":"TRule_expr","rule":"TRule_expr.Alt_expr2","sum":17389966},{"parent":"TRule_expr.TAlt1","rule":"TRule_expr.TAlt1.Block2","sum":68378152},{"parent":"TRule_expr.TAlt1","rule":"TRule_expr.TAlt1.Rule_or_subexpr1","sum":13700581585},{"parent":"TRule_expr.TAlt1.TBlock2","rule":"TRule_expr.TAlt1.TBlock2.Rule_or_subexpr2","sum":115236866},{"parent":"TRule_expr.TAlt1.TBlock2","rule":"TRule_expr.TAlt1.TBlock2.Token1","sum":115236866},{"parent":"TRule_expr.TAlt2","rule":"TRule_expr.TAlt2.Rule_type_name_composite1","sum":17389966},{"parent":"TRule_expr_dict_list","rule":"TRule_expr_dict_list.Block2","sum":7027260},{"parent":"TRule_expr_dict_list","rule":"TRule_expr_dict_list.Block3","sum":6637673},{"parent":"TRule_expr_dict_list","rule":"TRule_expr_dict_list.Rule_expr1","sum":8224534},{"parent":"TRule_expr_dict_list.TBlock2","rule":"TRule_expr_dict_list.TBlock2.Rule_expr2","sum":7027260},{"parent":"TRule_expr_dict_list.TBlock2","rule":"TRule_expr_dict_list.TBlock2.Token1","sum":7027260},{"parent":"TRule_expr_dict_list.TBlock3","rule":"TRule_expr_dict_list.TBlock3.Block3","sum":35232193},{"parent":"TRule_expr_dict_list.TBlock3","rule":"TRule_expr_dict_list.TBlock3.Rule_expr2","sum":42176709},{"parent":"TRule_expr_dict_list.TBlock3","rule":"TRule_expr_dict_list.TBlock3.Token1","sum":42176709},{"parent":"TRule_expr_dict_list.TBlock3.TBlock3","rule":"TRule_expr_dict_list.TBlock3.TBlock3.Rule_expr2","sum":35232193},{"parent":"TRule_expr_dict_list.TBlock3.TBlock3","rule":"TRule_expr_dict_list.TBlock3.TBlock3.Token1","sum":35232193},{"parent":"TRule_expr_list","rule":"TRule_expr_list.Block2","sum":41939238},{"parent":"TRule_expr_list","rule":"TRule_expr_list.Rule_expr1","sum":67533327},{"parent":"TRule_expr_list.TBlock2","rule":"TRule_expr_list.TBlock2.Rule_expr2","sum":206470243},{"parent":"TRule_expr_list.TBlock2","rule":"TRule_expr_list.TBlock2.Token1","sum":206470243},{"parent":"TRule_expr_struct_list","rule":"TRule_expr_struct_list.Block4","sum":12555297},{"parent":"TRule_expr_struct_list","rule":"TRule_expr_struct_list.Rule_expr1","sum":14494469},{"parent":"TRule_expr_struct_list","rule":"TRule_expr_struct_list.Rule_expr3","sum":14494469},{"parent":"TRule_expr_struct_list","rule":"TRule_expr_struct_list.Token2","sum":14494469},{"parent":"TRule_expr_struct_list.TBlock4","rule":"TRule_expr_struct_list.TBlock4.Rule_expr2","sum":31326759},{"parent":"TRule_expr_struct_list.TBlock4","rule":"TRule_expr_struct_list.TBlock4.Rule_expr4","sum":31326759},{"parent":"TRule_expr_struct_list.TBlock4","rule":"TRule_expr_struct_list.TBlock4.Token1","sum":31326759},{"parent":"TRule_expr_struct_list.TBlock4","rule":"TRule_expr_struct_list.TBlock4.Token3","sum":31326759},{"parent":"TRule_ext_order_by_clause","rule":"TRule_ext_order_by_clause.Block1","sum":2597625},{"parent":"TRule_ext_order_by_clause","rule":"TRule_ext_order_by_clause.Rule_order_by_clause2","sum":88715837},{"parent":"TRule_ext_order_by_clause.TBlock1","rule":"TRule_ext_order_by_clause.TBlock1.Token1","sum":2597625},{"parent":"TRule_flatten_by_arg","rule":"TRule_flatten_by_arg.Alt_flatten_by_arg1","sum":21372567},{"parent":"TRule_flatten_by_arg","rule":"TRule_flatten_by_arg.Alt_flatten_by_arg2","sum":4328246},{"parent":"TRule_flatten_by_arg.TAlt1","rule":"TRule_flatten_by_arg.TAlt1.Rule_named_column1","sum":21372567},{"parent":"TRule_flatten_by_arg.TAlt2","rule":"TRule_flatten_by_arg.TAlt2.Block3","sum":52259},{"parent":"TRule_flatten_by_arg.TAlt2","rule":"TRule_flatten_by_arg.TAlt2.Rule_named_expr_list2","sum":4328246},{"parent":"TRule_flatten_by_arg.TAlt2","rule":"TRule_flatten_by_arg.TAlt2.Token1","sum":4328246},{"parent":"TRule_flatten_by_arg.TAlt2","rule":"TRule_flatten_by_arg.TAlt2.Token4","sum":4328246},{"parent":"TRule_flatten_by_arg.TAlt2.TBlock3","rule":"TRule_flatten_by_arg.TAlt2.TBlock3.Token1","sum":52259},{"parent":"TRule_flatten_source","rule":"TRule_flatten_source.Block2","sum":33642409},{"parent":"TRule_flatten_source","rule":"TRule_flatten_source.Rule_named_single_source1","sum":1053231068},{"parent":"TRule_flatten_source.TBlock2","rule":"TRule_flatten_source.TBlock2.Block2","sum":33642409},{"parent":"TRule_flatten_source.TBlock2","rule":"TRule_flatten_source.TBlock2.Token1","sum":33642409},{"parent":"TRule_flatten_source.TBlock2.TBlock2","rule":"TRule_flatten_source.TBlock2.TBlock2.Alt1","sum":25700813},{"parent":"TRule_flatten_source.TBlock2.TBlock2","rule":"TRule_flatten_source.TBlock2.TBlock2.Alt2","sum":7941596},{"parent":"TRule_flatten_source.TBlock2.TBlock2.TAlt1","rule":"TRule_flatten_source.TBlock2.TBlock2.TAlt1.Block1","sum":19640624},{"parent":"TRule_flatten_source.TBlock2.TBlock2.TAlt1","rule":"TRule_flatten_source.TBlock2.TBlock2.TAlt1.Rule_flatten_by_arg3","sum":25700813},{"parent":"TRule_flatten_source.TBlock2.TBlock2.TAlt1","rule":"TRule_flatten_source.TBlock2.TBlock2.TAlt1.Token2","sum":25700813},{"parent":"TRule_flatten_source.TBlock2.TBlock2.TAlt1.TBlock1","rule":"TRule_flatten_source.TBlock2.TBlock2.TAlt1.TBlock1.Token1","sum":19640624},{"parent":"TRule_flatten_source.TBlock2.TBlock2.TAlt2","rule":"TRule_flatten_source.TBlock2.TBlock2.TAlt2.Token1","sum":7941596},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Block1","sum":7010814},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Block2","sum":8},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Block8","sum":64786},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Rule_bind_parameter4","sum":7010919},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Rule_do_stmt7","sum":7010919},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Rule_expr6","sum":7010919},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Token3","sum":7010919},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Token5","sum":7010919},{"parent":"TRule_for_stmt.TBlock1","rule":"TRule_for_stmt.TBlock1.Token1","sum":7010814},{"parent":"TRule_for_stmt.TBlock2","rule":"TRule_for_stmt.TBlock2.Token1","sum":8},{"parent":"TRule_for_stmt.TBlock8","rule":"TRule_for_stmt.TBlock8.Rule_do_stmt2","sum":64786},{"parent":"TRule_for_stmt.TBlock8","rule":"TRule_for_stmt.TBlock8.Token1","sum":64786},{"parent":"TRule_group_by_clause","rule":"TRule_group_by_clause.Block2","sum":1605609},{"parent":"TRule_group_by_clause","rule":"TRule_group_by_clause.Block6","sum":6},{"parent":"TRule_group_by_clause","rule":"TRule_group_by_clause.Rule_grouping_element_list5","sum":137899286},{"parent":"TRule_group_by_clause","rule":"TRule_group_by_clause.Rule_opt_set_quantifier4","sum":137899286},{"parent":"TRule_group_by_clause","rule":"TRule_group_by_clause.Token1","sum":137899286},{"parent":"TRule_group_by_clause","rule":"TRule_group_by_clause.Token3","sum":137899286},{"parent":"TRule_group_by_clause.TBlock2","rule":"TRule_group_by_clause.TBlock2.Token1","sum":1605609},{"parent":"TRule_group_by_clause.TBlock6","rule":"TRule_group_by_clause.TBlock6.Rule_an_id2","sum":6},{"parent":"TRule_group_by_clause.TBlock6","rule":"TRule_group_by_clause.TBlock6.Token1","sum":6},{"parent":"TRule_grouping_element","rule":"TRule_grouping_element.Alt_grouping_element1","sum":300615590},{"parent":"TRule_grouping_element","rule":"TRule_grouping_element.Alt_grouping_element2","sum":62641},{"parent":"TRule_grouping_element","rule":"TRule_grouping_element.Alt_grouping_element3","sum":276720},{"parent":"TRule_grouping_element","rule":"TRule_grouping_element.Alt_grouping_element4","sum":92425},{"parent":"TRule_grouping_element","rule":"TRule_grouping_element.Alt_grouping_element5","sum":23},{"parent":"TRule_grouping_element.TAlt1","rule":"TRule_grouping_element.TAlt1.Rule_ordinary_grouping_set1","sum":300615590},{"parent":"TRule_grouping_element.TAlt2","rule":"TRule_grouping_element.TAlt2.Rule_rollup_list1","sum":62641},{"parent":"TRule_grouping_element.TAlt3","rule":"TRule_grouping_element.TAlt3.Rule_cube_list1","sum":276720},{"parent":"TRule_grouping_element.TAlt4","rule":"TRule_grouping_element.TAlt4.Rule_grouping_sets_specification1","sum":92425},{"parent":"TRule_grouping_element.TAlt5","rule":"TRule_grouping_element.TAlt5.Rule_hopping_window_specification1","sum":23},{"parent":"TRule_grouping_element_list","rule":"TRule_grouping_element_list.Block2","sum":62764930},{"parent":"TRule_grouping_element_list","rule":"TRule_grouping_element_list.Rule_grouping_element1","sum":137991711},{"parent":"TRule_grouping_element_list.TBlock2","rule":"TRule_grouping_element_list.TBlock2.Rule_grouping_element2","sum":163055688},{"parent":"TRule_grouping_element_list.TBlock2","rule":"TRule_grouping_element_list.TBlock2.Token1","sum":163055688},{"parent":"TRule_grouping_sets_specification","rule":"TRule_grouping_sets_specification.Rule_grouping_element_list4","sum":92425},{"parent":"TRule_grouping_sets_specification","rule":"TRule_grouping_sets_specification.Token1","sum":92425},{"parent":"TRule_grouping_sets_specification","rule":"TRule_grouping_sets_specification.Token2","sum":92425},{"parent":"TRule_grouping_sets_specification","rule":"TRule_grouping_sets_specification.Token3","sum":92425},{"parent":"TRule_grouping_sets_specification","rule":"TRule_grouping_sets_specification.Token5","sum":92425},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Rule_expr3","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Rule_expr5","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Rule_expr7","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Rule_expr9","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Token1","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Token10","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Token2","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Token4","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Token6","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Token8","sum":23},{"parent":"TRule_id","rule":"TRule_id.Alt_id1","sum":12128005704},{"parent":"TRule_id","rule":"TRule_id.Alt_id2","sum":531926389},{"parent":"TRule_id.TAlt1","rule":"TRule_id.TAlt1.Rule_identifier1","sum":12128005704},{"parent":"TRule_id.TAlt2","rule":"TRule_id.TAlt2.Rule_keyword1","sum":531926389},{"parent":"TRule_id_as_compat","rule":"TRule_id_as_compat.Alt_id_as_compat1","sum":2993100},{"parent":"TRule_id_as_compat","rule":"TRule_id_as_compat.Alt_id_as_compat2","sum":2625},{"parent":"TRule_id_as_compat.TAlt1","rule":"TRule_id_as_compat.TAlt1.Rule_identifier1","sum":2993100},{"parent":"TRule_id_as_compat.TAlt2","rule":"TRule_id_as_compat.TAlt2.Rule_keyword_as_compat1","sum":2625},{"parent":"TRule_id_expr","rule":"TRule_id_expr.Alt_id_expr1","sum":6924072359},{"parent":"TRule_id_expr","rule":"TRule_id_expr.Alt_id_expr2","sum":319866905},{"parent":"TRule_id_expr","rule":"TRule_id_expr.Alt_id_expr3","sum":428215},{"parent":"TRule_id_expr","rule":"TRule_id_expr.Alt_id_expr5","sum":35200839},{"parent":"TRule_id_expr","rule":"TRule_id_expr.Alt_id_expr6","sum":181516},{"parent":"TRule_id_expr.TAlt1","rule":"TRule_id_expr.TAlt1.Rule_identifier1","sum":6924072359},{"parent":"TRule_id_expr.TAlt2","rule":"TRule_id_expr.TAlt2.Rule_keyword_compat1","sum":319866905},{"parent":"TRule_id_expr.TAlt3","rule":"TRule_id_expr.TAlt3.Rule_keyword_alter_uncompat1","sum":428215},{"parent":"TRule_id_expr.TAlt5","rule":"TRule_id_expr.TAlt5.Rule_keyword_window_uncompat1","sum":35200839},{"parent":"TRule_id_expr.TAlt6","rule":"TRule_id_expr.TAlt6.Rule_keyword_hint_uncompat1","sum":181516},{"parent":"TRule_id_expr_in","rule":"TRule_id_expr_in.Alt_id_expr_in1","sum":5638186},{"parent":"TRule_id_expr_in","rule":"TRule_id_expr_in.Alt_id_expr_in2","sum":74134},{"parent":"TRule_id_expr_in","rule":"TRule_id_expr_in.Alt_id_expr_in4","sum":213},{"parent":"TRule_id_expr_in","rule":"TRule_id_expr_in.Alt_id_expr_in5","sum":53},{"parent":"TRule_id_expr_in.TAlt1","rule":"TRule_id_expr_in.TAlt1.Rule_identifier1","sum":5638186},{"parent":"TRule_id_expr_in.TAlt2","rule":"TRule_id_expr_in.TAlt2.Rule_keyword_compat1","sum":74134},{"parent":"TRule_id_expr_in.TAlt4","rule":"TRule_id_expr_in.TAlt4.Rule_keyword_window_uncompat1","sum":213},{"parent":"TRule_id_expr_in.TAlt5","rule":"TRule_id_expr_in.TAlt5.Rule_keyword_hint_uncompat1","sum":53},{"parent":"TRule_id_hint","rule":"TRule_id_hint.Alt_id_hint1","sum":154435757},{"parent":"TRule_id_hint","rule":"TRule_id_hint.Alt_id_hint2","sum":22914},{"parent":"TRule_id_hint","rule":"TRule_id_hint.Alt_id_hint3","sum":22914},{"parent":"TRule_id_hint.TAlt1","rule":"TRule_id_hint.TAlt1.Rule_identifier1","sum":154435757},{"parent":"TRule_id_hint.TAlt2","rule":"TRule_id_hint.TAlt2.Rule_keyword_compat1","sum":22914},{"parent":"TRule_id_hint.TAlt3","rule":"TRule_id_hint.TAlt3.Rule_keyword_expr_uncompat1","sum":22914},{"parent":"TRule_id_or_at","rule":"TRule_id_or_at.Block1","sum":4766922},{"parent":"TRule_id_or_at","rule":"TRule_id_or_at.Rule_an_id_or_type2","sum":133786170},{"parent":"TRule_id_or_at.TBlock1","rule":"TRule_id_or_at.TBlock1.Token1","sum":4766922},{"parent":"TRule_id_or_type","rule":"TRule_id_or_type.Alt_id_or_type1","sum":10550728727},{"parent":"TRule_id_or_type","rule":"TRule_id_or_type.Alt_id_or_type2","sum":11671511},{"parent":"TRule_id_or_type.TAlt1","rule":"TRule_id_or_type.TAlt1.Rule_id1","sum":10550728727},{"parent":"TRule_id_or_type.TAlt2","rule":"TRule_id_or_type.TAlt2.Rule_type_id1","sum":11671511},{"parent":"TRule_id_schema","rule":"TRule_id_schema.Alt_id_schema1","sum":1169},{"parent":"TRule_id_schema","rule":"TRule_id_schema.Alt_id_schema2","sum":12},{"parent":"TRule_id_schema.TAlt1","rule":"TRule_id_schema.TAlt1.Rule_identifier1","sum":1169},{"parent":"TRule_id_schema.TAlt2","rule":"TRule_id_schema.TAlt2.Rule_keyword_compat1","sum":12},{"parent":"TRule_id_table","rule":"TRule_id_table.Alt_id_table1","sum":330226976},{"parent":"TRule_id_table","rule":"TRule_id_table.Alt_id_table2","sum":648184},{"parent":"TRule_id_table","rule":"TRule_id_table.Alt_id_table3","sum":369},{"parent":"TRule_id_table","rule":"TRule_id_table.Alt_id_table4","sum":12497},{"parent":"TRule_id_table","rule":"TRule_id_table.Alt_id_table5","sum":4},{"parent":"TRule_id_table","rule":"TRule_id_table.Alt_id_table6","sum":1828},{"parent":"TRule_id_table","rule":"TRule_id_table.Alt_id_table7","sum":10},{"parent":"TRule_id_table.TAlt1","rule":"TRule_id_table.TAlt1.Rule_identifier1","sum":330226976},{"parent":"TRule_id_table.TAlt2","rule":"TRule_id_table.TAlt2.Rule_keyword_compat1","sum":648184},{"parent":"TRule_id_table.TAlt3","rule":"TRule_id_table.TAlt3.Rule_keyword_expr_uncompat1","sum":369},{"parent":"TRule_id_table.TAlt4","rule":"TRule_id_table.TAlt4.Rule_keyword_select_uncompat1","sum":12497},{"parent":"TRule_id_table.TAlt5","rule":"TRule_id_table.TAlt5.Rule_keyword_in_uncompat1","sum":4},{"parent":"TRule_id_table.TAlt6","rule":"TRule_id_table.TAlt6.Rule_keyword_window_uncompat1","sum":1828},{"parent":"TRule_id_table.TAlt7","rule":"TRule_id_table.TAlt7.Rule_keyword_hint_uncompat1","sum":10},{"parent":"TRule_id_table_or_type","rule":"TRule_id_table_or_type.Alt_id_table_or_type1","sum":330889869},{"parent":"TRule_id_table_or_type","rule":"TRule_id_table_or_type.Alt_id_table_or_type2","sum":4256},{"parent":"TRule_id_table_or_type.TAlt1","rule":"TRule_id_table_or_type.TAlt1.Rule_an_id_table1","sum":330889869},{"parent":"TRule_id_table_or_type.TAlt2","rule":"TRule_id_table_or_type.TAlt2.Rule_type_id1","sum":4256},{"parent":"TRule_id_window","rule":"TRule_id_window.Alt_id_window1","sum":46399293},{"parent":"TRule_id_window","rule":"TRule_id_window.Alt_id_window2","sum":15712},{"parent":"TRule_id_window","rule":"TRule_id_window.Alt_id_window3","sum":247560},{"parent":"TRule_id_window","rule":"TRule_id_window.Alt_id_window5","sum":7846},{"parent":"TRule_id_window.TAlt1","rule":"TRule_id_window.TAlt1.Rule_identifier1","sum":46399293},{"parent":"TRule_id_window.TAlt2","rule":"TRule_id_window.TAlt2.Rule_keyword_compat1","sum":15712},{"parent":"TRule_id_window.TAlt3","rule":"TRule_id_window.TAlt3.Rule_keyword_expr_uncompat1","sum":247560},{"parent":"TRule_id_window.TAlt5","rule":"TRule_id_window.TAlt5.Rule_keyword_select_uncompat1","sum":7846},{"parent":"TRule_id_without","rule":"TRule_id_without.Alt_id_without1","sum":23026253},{"parent":"TRule_id_without","rule":"TRule_id_without.Alt_id_without2","sum":276407},{"parent":"TRule_id_without","rule":"TRule_id_without.Alt_id_without6","sum":1152},{"parent":"TRule_id_without","rule":"TRule_id_without.Alt_id_without7","sum":523},{"parent":"TRule_id_without.TAlt1","rule":"TRule_id_without.TAlt1.Rule_identifier1","sum":23026253},{"parent":"TRule_id_without.TAlt2","rule":"TRule_id_without.TAlt2.Rule_keyword_compat1","sum":276407},{"parent":"TRule_id_without.TAlt6","rule":"TRule_id_without.TAlt6.Rule_keyword_window_uncompat1","sum":1152},{"parent":"TRule_id_without.TAlt7","rule":"TRule_id_without.TAlt7.Rule_keyword_hint_uncompat1","sum":523},{"parent":"TRule_identifier","rule":"TRule_identifier.Token1","sum":20292582404},{"parent":"TRule_if_stmt","rule":"TRule_if_stmt.Block1","sum":8565563},{"parent":"TRule_if_stmt","rule":"TRule_if_stmt.Block5","sum":2975205},{"parent":"TRule_if_stmt","rule":"TRule_if_stmt.Rule_do_stmt4","sum":8565607},{"parent":"TRule_if_stmt","rule":"TRule_if_stmt.Rule_expr3","sum":8565607},{"parent":"TRule_if_stmt","rule":"TRule_if_stmt.Token2","sum":8565607},{"parent":"TRule_if_stmt.TBlock1","rule":"TRule_if_stmt.TBlock1.Token1","sum":8565563},{"parent":"TRule_if_stmt.TBlock5","rule":"TRule_if_stmt.TBlock5.Rule_do_stmt2","sum":2975205},{"parent":"TRule_if_stmt.TBlock5","rule":"TRule_if_stmt.TBlock5.Token1","sum":2975205},{"parent":"TRule_import_stmt","rule":"TRule_import_stmt.Rule_module_path2","sum":16595494},{"parent":"TRule_import_stmt","rule":"TRule_import_stmt.Rule_named_bind_parameter_list4","sum":16595494},{"parent":"TRule_import_stmt","rule":"TRule_import_stmt.Token1","sum":16595494},{"parent":"TRule_import_stmt","rule":"TRule_import_stmt.Token3","sum":16595494},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr1","sum":2232},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr10","sum":5119349},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr11","sum":454733},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr2","sum":36416170},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr3","sum":65683387},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr4","sum":44388},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr5","sum":4},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr6","sum":2968457},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr7","sum":9749806},{"parent":"TRule_in_atom_expr.TAlt1","rule":"TRule_in_atom_expr.TAlt1.Rule_literal_value1","sum":2232},{"parent":"TRule_in_atom_expr.TAlt10","rule":"TRule_in_atom_expr.TAlt10.Rule_list_literal1","sum":5119349},{"parent":"TRule_in_atom_expr.TAlt11","rule":"TRule_in_atom_expr.TAlt11.Rule_dict_literal1","sum":454733},{"parent":"TRule_in_atom_expr.TAlt2","rule":"TRule_in_atom_expr.TAlt2.Rule_bind_parameter1","sum":36416170},{"parent":"TRule_in_atom_expr.TAlt3","rule":"TRule_in_atom_expr.TAlt3.Rule_lambda1","sum":65683387},{"parent":"TRule_in_atom_expr.TAlt4","rule":"TRule_in_atom_expr.TAlt4.Rule_cast_expr1","sum":44388},{"parent":"TRule_in_atom_expr.TAlt5","rule":"TRule_in_atom_expr.TAlt5.Rule_case_expr1","sum":4},{"parent":"TRule_in_atom_expr.TAlt6","rule":"TRule_in_atom_expr.TAlt6.Block3","sum":2968457},{"parent":"TRule_in_atom_expr.TAlt6","rule":"TRule_in_atom_expr.TAlt6.Rule_an_id_or_type1","sum":2968457},{"parent":"TRule_in_atom_expr.TAlt6","rule":"TRule_in_atom_expr.TAlt6.Token2","sum":2968457},{"parent":"TRule_in_atom_expr.TAlt6.TBlock3","rule":"TRule_in_atom_expr.TAlt6.TBlock3.Alt1","sum":2968457},{"parent":"TRule_in_atom_expr.TAlt6.TBlock3.TAlt1","rule":"TRule_in_atom_expr.TAlt6.TBlock3.TAlt1.Rule_id_or_type1","sum":2968457},{"parent":"TRule_in_atom_expr.TAlt7","rule":"TRule_in_atom_expr.TAlt7.Rule_select_stmt2","sum":9749806},{"parent":"TRule_in_atom_expr.TAlt7","rule":"TRule_in_atom_expr.TAlt7.Token1","sum":9749806},{"parent":"TRule_in_atom_expr.TAlt7","rule":"TRule_in_atom_expr.TAlt7.Token3","sum":9749806},{"parent":"TRule_in_expr","rule":"TRule_in_expr.Rule_in_unary_subexpr1","sum":126151164},{"parent":"TRule_in_unary_casual_subexpr","rule":"TRule_in_unary_casual_subexpr.Block1","sum":126151112},{"parent":"TRule_in_unary_casual_subexpr","rule":"TRule_in_unary_casual_subexpr.Rule_unary_subexpr_suffix2","sum":126151112},{"parent":"TRule_in_unary_casual_subexpr.TBlock1","rule":"TRule_in_unary_casual_subexpr.TBlock1.Alt1","sum":5712586},{"parent":"TRule_in_unary_casual_subexpr.TBlock1","rule":"TRule_in_unary_casual_subexpr.TBlock1.Alt2","sum":120438526},{"parent":"TRule_in_unary_casual_subexpr.TBlock1.TAlt1","rule":"TRule_in_unary_casual_subexpr.TBlock1.TAlt1.Rule_id_expr_in1","sum":5712586},{"parent":"TRule_in_unary_casual_subexpr.TBlock1.TAlt2","rule":"TRule_in_unary_casual_subexpr.TBlock1.TAlt2.Rule_in_atom_expr1","sum":120438526},{"parent":"TRule_in_unary_subexpr","rule":"TRule_in_unary_subexpr.Alt_in_unary_subexpr1","sum":126151112},{"parent":"TRule_in_unary_subexpr","rule":"TRule_in_unary_subexpr.Alt_in_unary_subexpr2","sum":52},{"parent":"TRule_in_unary_subexpr.TAlt1","rule":"TRule_in_unary_subexpr.TAlt1.Rule_in_unary_casual_subexpr1","sum":126151112},{"parent":"TRule_in_unary_subexpr.TAlt2","rule":"TRule_in_unary_subexpr.TAlt2.Rule_json_api_expr1","sum":52},{"parent":"TRule_inline_action","rule":"TRule_inline_action.Rule_define_action_or_subquery_body2","sum":13876885},{"parent":"TRule_inline_action","rule":"TRule_inline_action.Token1","sum":13876885},{"parent":"TRule_inline_action","rule":"TRule_inline_action.Token3","sum":13876885},{"parent":"TRule_inline_action","rule":"TRule_inline_action.Token4","sum":13876885},{"parent":"TRule_integer","rule":"TRule_integer.Token1","sum":2804251466},{"parent":"TRule_integer_or_bind","rule":"TRule_integer_or_bind.Alt_integer_or_bind1","sum":55657901},{"parent":"TRule_integer_or_bind","rule":"TRule_integer_or_bind.Alt_integer_or_bind2","sum":48703},{"parent":"TRule_integer_or_bind.TAlt1","rule":"TRule_integer_or_bind.TAlt1.Rule_integer1","sum":55657901},{"parent":"TRule_integer_or_bind.TAlt2","rule":"TRule_integer_or_bind.TAlt2.Rule_bind_parameter1","sum":48703},{"parent":"TRule_into_simple_table_ref","rule":"TRule_into_simple_table_ref.Block2","sum":25371},{"parent":"TRule_into_simple_table_ref","rule":"TRule_into_simple_table_ref.Rule_simple_table_ref1","sum":209091152},{"parent":"TRule_into_simple_table_ref.TBlock2","rule":"TRule_into_simple_table_ref.TBlock2.Rule_pure_column_list3","sum":25371},{"parent":"TRule_into_simple_table_ref.TBlock2","rule":"TRule_into_simple_table_ref.TBlock2.Token1","sum":25371},{"parent":"TRule_into_simple_table_ref.TBlock2","rule":"TRule_into_simple_table_ref.TBlock2.Token2","sum":25371},{"parent":"TRule_into_table_stmt","rule":"TRule_into_table_stmt.Block1","sum":209091152},{"parent":"TRule_into_table_stmt","rule":"TRule_into_table_stmt.Rule_into_simple_table_ref3","sum":209091152},{"parent":"TRule_into_table_stmt","rule":"TRule_into_table_stmt.Rule_into_values_source4","sum":209091152},{"parent":"TRule_into_table_stmt","rule":"TRule_into_table_stmt.Token2","sum":209091152},{"parent":"TRule_into_table_stmt.TBlock1","rule":"TRule_into_table_stmt.TBlock1.Alt1","sum":208980387},{"parent":"TRule_into_table_stmt.TBlock1","rule":"TRule_into_table_stmt.TBlock1.Alt5","sum":110764},{"parent":"TRule_into_table_stmt.TBlock1","rule":"TRule_into_table_stmt.TBlock1.Alt6","sum":1},{"parent":"TRule_into_table_stmt.TBlock1.TAlt1","rule":"TRule_into_table_stmt.TBlock1.TAlt1.Token1","sum":208980387},{"parent":"TRule_into_table_stmt.TBlock1.TAlt5","rule":"TRule_into_table_stmt.TBlock1.TAlt5.Token1","sum":110764},{"parent":"TRule_into_table_stmt.TBlock1.TAlt6","rule":"TRule_into_table_stmt.TBlock1.TAlt6.Token1","sum":1},{"parent":"TRule_into_values_source","rule":"TRule_into_values_source.Alt_into_values_source1","sum":209091152},{"parent":"TRule_into_values_source.TAlt1","rule":"TRule_into_values_source.TAlt1.Block1","sum":4514874},{"parent":"TRule_into_values_source.TAlt1","rule":"TRule_into_values_source.TAlt1.Rule_values_source2","sum":209091152},{"parent":"TRule_into_values_source.TAlt1.TBlock1","rule":"TRule_into_values_source.TAlt1.TBlock1.Rule_pure_column_list1","sum":4514874},{"parent":"TRule_invoke_expr","rule":"TRule_invoke_expr.Block2","sum":2765415575},{"parent":"TRule_invoke_expr","rule":"TRule_invoke_expr.Rule_invoke_expr_tail4","sum":2879693756},{"parent":"TRule_invoke_expr","rule":"TRule_invoke_expr.Token1","sum":2879693756},{"parent":"TRule_invoke_expr","rule":"TRule_invoke_expr.Token3","sum":2879693756},{"parent":"TRule_invoke_expr.TBlock2","rule":"TRule_invoke_expr.TBlock2.Alt1","sum":2706379021},{"parent":"TRule_invoke_expr.TBlock2","rule":"TRule_invoke_expr.TBlock2.Alt2","sum":59036554},{"parent":"TRule_invoke_expr.TBlock2.TAlt1","rule":"TRule_invoke_expr.TBlock2.TAlt1.Block3","sum":9657583},{"parent":"TRule_invoke_expr.TBlock2.TAlt1","rule":"TRule_invoke_expr.TBlock2.TAlt1.Rule_named_expr_list2","sum":2706379021},{"parent":"TRule_invoke_expr.TBlock2.TAlt1","rule":"TRule_invoke_expr.TBlock2.TAlt1.Rule_opt_set_quantifier1","sum":2706379021},{"parent":"TRule_invoke_expr.TBlock2.TAlt1.TBlock3","rule":"TRule_invoke_expr.TBlock2.TAlt1.TBlock3.Token1","sum":9657583},{"parent":"TRule_invoke_expr.TBlock2.TAlt2","rule":"TRule_invoke_expr.TBlock2.TAlt2.Token1","sum":59036554},{"parent":"TRule_invoke_expr_tail","rule":"TRule_invoke_expr_tail.Block1","sum":7217779},{"parent":"TRule_invoke_expr_tail","rule":"TRule_invoke_expr_tail.Block2","sum":45342787},{"parent":"TRule_invoke_expr_tail.TBlock1","rule":"TRule_invoke_expr_tail.TBlock1.Alt1","sum":7217779},{"parent":"TRule_invoke_expr_tail.TBlock1.TAlt1","rule":"TRule_invoke_expr_tail.TBlock1.TAlt1.Rule_null_treatment1","sum":7217779},{"parent":"TRule_invoke_expr_tail.TBlock2","rule":"TRule_invoke_expr_tail.TBlock2.Rule_window_name_or_specification2","sum":45342787},{"parent":"TRule_invoke_expr_tail.TBlock2","rule":"TRule_invoke_expr_tail.TBlock2.Token1","sum":45342787},{"parent":"TRule_join_constraint","rule":"TRule_join_constraint.Alt_join_constraint1","sum":173168424},{"parent":"TRule_join_constraint","rule":"TRule_join_constraint.Alt_join_constraint2","sum":32475186},{"parent":"TRule_join_constraint.TAlt1","rule":"TRule_join_constraint.TAlt1.Rule_expr2","sum":173168424},{"parent":"TRule_join_constraint.TAlt1","rule":"TRule_join_constraint.TAlt1.Token1","sum":173168424},{"parent":"TRule_join_constraint.TAlt2","rule":"TRule_join_constraint.TAlt2.Rule_pure_column_or_named_list2","sum":32475186},{"parent":"TRule_join_constraint.TAlt2","rule":"TRule_join_constraint.TAlt2.Token1","sum":32475186},{"parent":"TRule_join_op","rule":"TRule_join_op.Alt_join_op1","sum":28099},{"parent":"TRule_join_op","rule":"TRule_join_op.Alt_join_op2","sum":208703034},{"parent":"TRule_join_op.TAlt1","rule":"TRule_join_op.TAlt1.Token1","sum":28099},{"parent":"TRule_join_op.TAlt2","rule":"TRule_join_op.TAlt2.Block2","sum":208703034},{"parent":"TRule_join_op.TAlt2","rule":"TRule_join_op.TAlt2.Token3","sum":208703034},{"parent":"TRule_join_op.TAlt2.TBlock2","rule":"TRule_join_op.TAlt2.TBlock2.Alt1","sum":174912521},{"parent":"TRule_join_op.TAlt2.TBlock2","rule":"TRule_join_op.TAlt2.TBlock2.Alt2","sum":30731089},{"parent":"TRule_join_op.TAlt2.TBlock2","rule":"TRule_join_op.TAlt2.TBlock2.Alt3","sum":3059424},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.Block1","sum":126817883},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.Block2","sum":295367},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.Alt1","sum":118904169},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.Alt2","sum":1698819},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.Alt3","sum":285680},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.Alt4","sum":5929215},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt1.Block2","sum":19688658},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt1.Token1","sum":118904169},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt1.TBlock2","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt1.TBlock2.Token1","sum":19688658},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt2","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt2.Block2","sum":519436},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt2","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt2.Token1","sum":1698819},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt2.TBlock2","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt2.TBlock2.Token1","sum":519436},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt3","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt3.Token1","sum":285680},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt4","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt4.Token1","sum":5929215},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock2","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock2.Token1","sum":295367},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt2","rule":"TRule_join_op.TAlt2.TBlock2.TAlt2.Token1","sum":30731089},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt3","rule":"TRule_join_op.TAlt2.TBlock2.TAlt3.Token1","sum":3059424},{"parent":"TRule_join_source","rule":"TRule_join_source.Block1","sum":616452},{"parent":"TRule_join_source","rule":"TRule_join_source.Block3","sum":145482737},{"parent":"TRule_join_source","rule":"TRule_join_source.Rule_flatten_source2","sum":844499935},{"parent":"TRule_join_source.TBlock1","rule":"TRule_join_source.TBlock1.Token1","sum":616452},{"parent":"TRule_join_source.TBlock3","rule":"TRule_join_source.TBlock3.Block2","sum":14042710},{"parent":"TRule_join_source.TBlock3","rule":"TRule_join_source.TBlock3.Block4","sum":205643610},{"parent":"TRule_join_source.TBlock3","rule":"TRule_join_source.TBlock3.Rule_flatten_source3","sum":208731133},{"parent":"TRule_join_source.TBlock3","rule":"TRule_join_source.TBlock3.Rule_join_op1","sum":208731133},{"parent":"TRule_join_source.TBlock3.TBlock2","rule":"TRule_join_source.TBlock3.TBlock2.Token1","sum":14042710},{"parent":"TRule_join_source.TBlock3.TBlock4","rule":"TRule_join_source.TBlock3.TBlock4.Rule_join_constraint1","sum":205643610},{"parent":"TRule_json_api_expr","rule":"TRule_json_api_expr.Alt_json_api_expr1","sum":5839155},{"parent":"TRule_json_api_expr","rule":"TRule_json_api_expr.Alt_json_api_expr2","sum":187482},{"parent":"TRule_json_api_expr","rule":"TRule_json_api_expr.Alt_json_api_expr3","sum":317059},{"parent":"TRule_json_api_expr.TAlt1","rule":"TRule_json_api_expr.TAlt1.Rule_json_value1","sum":5839155},{"parent":"TRule_json_api_expr.TAlt2","rule":"TRule_json_api_expr.TAlt2.Rule_json_exists1","sum":187482},{"parent":"TRule_json_api_expr.TAlt3","rule":"TRule_json_api_expr.TAlt3.Rule_json_query1","sum":317059},{"parent":"TRule_json_case_handler","rule":"TRule_json_case_handler.Alt_json_case_handler1","sum":6990},{"parent":"TRule_json_case_handler","rule":"TRule_json_case_handler.Alt_json_case_handler2","sum":14322},{"parent":"TRule_json_case_handler","rule":"TRule_json_case_handler.Alt_json_case_handler3","sum":200611},{"parent":"TRule_json_case_handler.TAlt1","rule":"TRule_json_case_handler.TAlt1.Token1","sum":6990},{"parent":"TRule_json_case_handler.TAlt2","rule":"TRule_json_case_handler.TAlt2.Token1","sum":14322},{"parent":"TRule_json_case_handler.TAlt3","rule":"TRule_json_case_handler.TAlt3.Rule_expr2","sum":200611},{"parent":"TRule_json_case_handler.TAlt3","rule":"TRule_json_case_handler.TAlt3.Token1","sum":200611},{"parent":"TRule_json_common_args","rule":"TRule_json_common_args.Block4","sum":20534},{"parent":"TRule_json_common_args","rule":"TRule_json_common_args.Rule_expr1","sum":6343696},{"parent":"TRule_json_common_args","rule":"TRule_json_common_args.Rule_jsonpath_spec3","sum":6343696},{"parent":"TRule_json_common_args","rule":"TRule_json_common_args.Token2","sum":6343696},{"parent":"TRule_json_common_args.TBlock4","rule":"TRule_json_common_args.TBlock4.Rule_json_variables2","sum":20534},{"parent":"TRule_json_common_args.TBlock4","rule":"TRule_json_common_args.TBlock4.Token1","sum":20534},{"parent":"TRule_json_exists","rule":"TRule_json_exists.Block4","sum":92},{"parent":"TRule_json_exists","rule":"TRule_json_exists.Rule_json_common_args3","sum":187482},{"parent":"TRule_json_exists","rule":"TRule_json_exists.Token1","sum":187482},{"parent":"TRule_json_exists","rule":"TRule_json_exists.Token2","sum":187482},{"parent":"TRule_json_exists","rule":"TRule_json_exists.Token5","sum":187482},{"parent":"TRule_json_exists.TBlock4","rule":"TRule_json_exists.TBlock4.Rule_json_exists_handler1","sum":92},{"parent":"TRule_json_exists_handler","rule":"TRule_json_exists_handler.Token1","sum":92},{"parent":"TRule_json_exists_handler","rule":"TRule_json_exists_handler.Token2","sum":92},{"parent":"TRule_json_exists_handler","rule":"TRule_json_exists_handler.Token3","sum":92},{"parent":"TRule_json_query","rule":"TRule_json_query.Block4","sum":190823},{"parent":"TRule_json_query","rule":"TRule_json_query.Block5","sum":86},{"parent":"TRule_json_query","rule":"TRule_json_query.Block6","sum":4124},{"parent":"TRule_json_query","rule":"TRule_json_query.Rule_json_common_args3","sum":317059},{"parent":"TRule_json_query","rule":"TRule_json_query.Token1","sum":317059},{"parent":"TRule_json_query","rule":"TRule_json_query.Token2","sum":317059},{"parent":"TRule_json_query","rule":"TRule_json_query.Token7","sum":317059},{"parent":"TRule_json_query.TBlock4","rule":"TRule_json_query.TBlock4.Rule_json_query_wrapper1","sum":190823},{"parent":"TRule_json_query.TBlock4","rule":"TRule_json_query.TBlock4.Token2","sum":190823},{"parent":"TRule_json_query.TBlock5","rule":"TRule_json_query.TBlock5.Rule_json_query_handler1","sum":86},{"parent":"TRule_json_query.TBlock5","rule":"TRule_json_query.TBlock5.Token2","sum":86},{"parent":"TRule_json_query.TBlock5","rule":"TRule_json_query.TBlock5.Token3","sum":86},{"parent":"TRule_json_query.TBlock6","rule":"TRule_json_query.TBlock6.Rule_json_query_handler1","sum":4124},{"parent":"TRule_json_query.TBlock6","rule":"TRule_json_query.TBlock6.Token2","sum":4124},{"parent":"TRule_json_query.TBlock6","rule":"TRule_json_query.TBlock6.Token3","sum":4124},{"parent":"TRule_json_query_handler","rule":"TRule_json_query_handler.Alt_json_query_handler1","sum":1675},{"parent":"TRule_json_query_handler","rule":"TRule_json_query_handler.Alt_json_query_handler2","sum":26},{"parent":"TRule_json_query_handler","rule":"TRule_json_query_handler.Alt_json_query_handler3","sum":2290},{"parent":"TRule_json_query_handler","rule":"TRule_json_query_handler.Alt_json_query_handler4","sum":219},{"parent":"TRule_json_query_handler.TAlt1","rule":"TRule_json_query_handler.TAlt1.Token1","sum":1675},{"parent":"TRule_json_query_handler.TAlt2","rule":"TRule_json_query_handler.TAlt2.Token1","sum":26},{"parent":"TRule_json_query_handler.TAlt3","rule":"TRule_json_query_handler.TAlt3.Token1","sum":2290},{"parent":"TRule_json_query_handler.TAlt3","rule":"TRule_json_query_handler.TAlt3.Token2","sum":2290},{"parent":"TRule_json_query_handler.TAlt4","rule":"TRule_json_query_handler.TAlt4.Token1","sum":219},{"parent":"TRule_json_query_handler.TAlt4","rule":"TRule_json_query_handler.TAlt4.Token2","sum":219},{"parent":"TRule_json_query_wrapper","rule":"TRule_json_query_wrapper.Alt_json_query_wrapper1","sum":45},{"parent":"TRule_json_query_wrapper","rule":"TRule_json_query_wrapper.Alt_json_query_wrapper2","sum":190778},{"parent":"TRule_json_query_wrapper.TAlt1","rule":"TRule_json_query_wrapper.TAlt1.Block2","sum":10},{"parent":"TRule_json_query_wrapper.TAlt1","rule":"TRule_json_query_wrapper.TAlt1.Token1","sum":45},{"parent":"TRule_json_query_wrapper.TAlt1.TBlock2","rule":"TRule_json_query_wrapper.TAlt1.TBlock2.Token1","sum":10},{"parent":"TRule_json_query_wrapper.TAlt2","rule":"TRule_json_query_wrapper.TAlt2.Block2","sum":166445},{"parent":"TRule_json_query_wrapper.TAlt2","rule":"TRule_json_query_wrapper.TAlt2.Block3","sum":32190},{"parent":"TRule_json_query_wrapper.TAlt2","rule":"TRule_json_query_wrapper.TAlt2.Token1","sum":190778},{"parent":"TRule_json_query_wrapper.TAlt2.TBlock2","rule":"TRule_json_query_wrapper.TAlt2.TBlock2.Token1","sum":166445},{"parent":"TRule_json_query_wrapper.TAlt2.TBlock3","rule":"TRule_json_query_wrapper.TAlt2.TBlock3.Token1","sum":32190},{"parent":"TRule_json_value","rule":"TRule_json_value.Block4","sum":1332342},{"parent":"TRule_json_value","rule":"TRule_json_value.Block5","sum":202460},{"parent":"TRule_json_value","rule":"TRule_json_value.Rule_json_common_args3","sum":5839155},{"parent":"TRule_json_value","rule":"TRule_json_value.Token1","sum":5839155},{"parent":"TRule_json_value","rule":"TRule_json_value.Token2","sum":5839155},{"parent":"TRule_json_value","rule":"TRule_json_value.Token6","sum":5839155},{"parent":"TRule_json_value.TBlock4","rule":"TRule_json_value.TBlock4.Rule_type_name_simple2","sum":1332342},{"parent":"TRule_json_value.TBlock4","rule":"TRule_json_value.TBlock4.Token1","sum":1332342},{"parent":"TRule_json_value.TBlock5","rule":"TRule_json_value.TBlock5.Rule_json_case_handler1","sum":221923},{"parent":"TRule_json_value.TBlock5","rule":"TRule_json_value.TBlock5.Token2","sum":221923},{"parent":"TRule_json_value.TBlock5","rule":"TRule_json_value.TBlock5.Token3","sum":221923},{"parent":"TRule_json_variable","rule":"TRule_json_variable.Rule_expr1","sum":20541},{"parent":"TRule_json_variable","rule":"TRule_json_variable.Rule_json_variable_name3","sum":20541},{"parent":"TRule_json_variable","rule":"TRule_json_variable.Token2","sum":20541},{"parent":"TRule_json_variable_name","rule":"TRule_json_variable_name.Alt_json_variable_name1","sum":18269},{"parent":"TRule_json_variable_name","rule":"TRule_json_variable_name.Alt_json_variable_name2","sum":2272},{"parent":"TRule_json_variable_name.TAlt1","rule":"TRule_json_variable_name.TAlt1.Rule_id_expr1","sum":18269},{"parent":"TRule_json_variable_name.TAlt2","rule":"TRule_json_variable_name.TAlt2.Token1","sum":2272},{"parent":"TRule_json_variables","rule":"TRule_json_variables.Block2","sum":7},{"parent":"TRule_json_variables","rule":"TRule_json_variables.Rule_json_variable1","sum":20534},{"parent":"TRule_json_variables.TBlock2","rule":"TRule_json_variables.TBlock2.Rule_json_variable2","sum":7},{"parent":"TRule_json_variables.TBlock2","rule":"TRule_json_variables.TBlock2.Token1","sum":7},{"parent":"TRule_jsonpath_spec","rule":"TRule_jsonpath_spec.Token1","sum":6343696},{"parent":"TRule_key_expr","rule":"TRule_key_expr.Rule_expr2","sum":173531558},{"parent":"TRule_key_expr","rule":"TRule_key_expr.Token1","sum":173531558},{"parent":"TRule_key_expr","rule":"TRule_key_expr.Token3","sum":173531558},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword1","sum":481505456},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword2","sum":33556549},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword3","sum":509133},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword4","sum":9140242},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword5","sum":777905},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword6","sum":23579},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword7","sum":3897493},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword8","sum":2516032},{"parent":"TRule_keyword.TAlt1","rule":"TRule_keyword.TAlt1.Rule_keyword_compat1","sum":481505456},{"parent":"TRule_keyword.TAlt2","rule":"TRule_keyword.TAlt2.Rule_keyword_expr_uncompat1","sum":33556549},{"parent":"TRule_keyword.TAlt3","rule":"TRule_keyword.TAlt3.Rule_keyword_table_uncompat1","sum":509133},{"parent":"TRule_keyword.TAlt4","rule":"TRule_keyword.TAlt4.Rule_keyword_select_uncompat1","sum":9140242},{"parent":"TRule_keyword.TAlt5","rule":"TRule_keyword.TAlt5.Rule_keyword_alter_uncompat1","sum":777905},{"parent":"TRule_keyword.TAlt6","rule":"TRule_keyword.TAlt6.Rule_keyword_in_uncompat1","sum":23579},{"parent":"TRule_keyword.TAlt7","rule":"TRule_keyword.TAlt7.Rule_keyword_window_uncompat1","sum":3897493},{"parent":"TRule_keyword.TAlt8","rule":"TRule_keyword.TAlt8.Rule_keyword_hint_uncompat1","sum":2516032},{"parent":"TRule_keyword_alter_uncompat","rule":"TRule_keyword_alter_uncompat.Token1","sum":1206120},{"parent":"TRule_keyword_as_compat","rule":"TRule_keyword_as_compat.Token1","sum":2625},{"parent":"TRule_keyword_compat","rule":"TRule_keyword_compat.Token1","sum":802409724},{"parent":"TRule_keyword_expr_uncompat","rule":"TRule_keyword_expr_uncompat.Token1","sum":33827392},{"parent":"TRule_keyword_hint_uncompat","rule":"TRule_keyword_hint_uncompat.Token1","sum":2698134},{"parent":"TRule_keyword_in_uncompat","rule":"TRule_keyword_in_uncompat.Token1","sum":23583},{"parent":"TRule_keyword_select_uncompat","rule":"TRule_keyword_select_uncompat.Token1","sum":9160585},{"parent":"TRule_keyword_table_uncompat","rule":"TRule_keyword_table_uncompat.Token1","sum":509133},{"parent":"TRule_keyword_window_uncompat","rule":"TRule_keyword_window_uncompat.Token1","sum":39101525},{"parent":"TRule_lambda","rule":"TRule_lambda.Block2","sum":208939219},{"parent":"TRule_lambda","rule":"TRule_lambda.Rule_smart_parenthesis1","sum":512606456},{"parent":"TRule_lambda.TBlock2","rule":"TRule_lambda.TBlock2.Block2","sum":208939219},{"parent":"TRule_lambda.TBlock2","rule":"TRule_lambda.TBlock2.Token1","sum":208939219},{"parent":"TRule_lambda.TBlock2.TBlock2","rule":"TRule_lambda.TBlock2.TBlock2.Alt1","sum":42650423},{"parent":"TRule_lambda.TBlock2.TBlock2","rule":"TRule_lambda.TBlock2.TBlock2.Alt2","sum":166288796},{"parent":"TRule_lambda.TBlock2.TBlock2.TAlt1","rule":"TRule_lambda.TBlock2.TBlock2.TAlt1.Rule_expr2","sum":42650423},{"parent":"TRule_lambda.TBlock2.TBlock2.TAlt1","rule":"TRule_lambda.TBlock2.TBlock2.TAlt1.Token1","sum":42650423},{"parent":"TRule_lambda.TBlock2.TBlock2.TAlt1","rule":"TRule_lambda.TBlock2.TBlock2.TAlt1.Token3","sum":42650423},{"parent":"TRule_lambda.TBlock2.TBlock2.TAlt2","rule":"TRule_lambda.TBlock2.TBlock2.TAlt2.Rule_lambda_body2","sum":166288796},{"parent":"TRule_lambda.TBlock2.TBlock2.TAlt2","rule":"TRule_lambda.TBlock2.TBlock2.TAlt2.Token1","sum":166288796},{"parent":"TRule_lambda.TBlock2.TBlock2.TAlt2","rule":"TRule_lambda.TBlock2.TBlock2.TAlt2.Token3","sum":166288796},{"parent":"TRule_lambda_body","rule":"TRule_lambda_body.Block1","sum":158},{"parent":"TRule_lambda_body","rule":"TRule_lambda_body.Block2","sum":34782650},{"parent":"TRule_lambda_body","rule":"TRule_lambda_body.Block5","sum":87670061},{"parent":"TRule_lambda_body","rule":"TRule_lambda_body.Rule_expr4","sum":166288796},{"parent":"TRule_lambda_body","rule":"TRule_lambda_body.Token3","sum":166288796},{"parent":"TRule_lambda_body.TBlock1","rule":"TRule_lambda_body.TBlock1.Token1","sum":158},{"parent":"TRule_lambda_body.TBlock2","rule":"TRule_lambda_body.TBlock2.Block2","sum":63758860},{"parent":"TRule_lambda_body.TBlock2","rule":"TRule_lambda_body.TBlock2.Rule_lambda_stmt1","sum":63758860},{"parent":"TRule_lambda_body.TBlock2.TBlock2","rule":"TRule_lambda_body.TBlock2.TBlock2.Token1","sum":63760050},{"parent":"TRule_lambda_body.TBlock5","rule":"TRule_lambda_body.TBlock5.Token1","sum":87678636},{"parent":"TRule_lambda_stmt","rule":"TRule_lambda_stmt.Alt_lambda_stmt1","sum":63756201},{"parent":"TRule_lambda_stmt","rule":"TRule_lambda_stmt.Alt_lambda_stmt2","sum":2659},{"parent":"TRule_lambda_stmt.TAlt1","rule":"TRule_lambda_stmt.TAlt1.Rule_named_nodes_stmt1","sum":63756201},{"parent":"TRule_lambda_stmt.TAlt2","rule":"TRule_lambda_stmt.TAlt2.Rule_import_stmt1","sum":2659},{"parent":"TRule_list_literal","rule":"TRule_list_literal.Block2","sum":35369157},{"parent":"TRule_list_literal","rule":"TRule_list_literal.Block3","sum":2299735},{"parent":"TRule_list_literal","rule":"TRule_list_literal.Token1","sum":41125575},{"parent":"TRule_list_literal","rule":"TRule_list_literal.Token4","sum":41125575},{"parent":"TRule_list_literal.TBlock2","rule":"TRule_list_literal.TBlock2.Rule_expr_list1","sum":35369157},{"parent":"TRule_list_literal.TBlock3","rule":"TRule_list_literal.TBlock3.Token1","sum":2299735},{"parent":"TRule_literal_value","rule":"TRule_literal_value.Alt_literal_value1","sum":2748593564},{"parent":"TRule_literal_value","rule":"TRule_literal_value.Alt_literal_value10","sum":2},{"parent":"TRule_literal_value","rule":"TRule_literal_value.Alt_literal_value2","sum":109140186},{"parent":"TRule_literal_value","rule":"TRule_literal_value.Alt_literal_value3","sum":2123403353},{"parent":"TRule_literal_value","rule":"TRule_literal_value.Alt_literal_value5","sum":79508859},{"parent":"TRule_literal_value","rule":"TRule_literal_value.Alt_literal_value9","sum":104326396},{"parent":"TRule_literal_value.TAlt1","rule":"TRule_literal_value.TAlt1.Rule_integer1","sum":2748593564},{"parent":"TRule_literal_value.TAlt10","rule":"TRule_literal_value.TAlt10.Token1","sum":2},{"parent":"TRule_literal_value.TAlt2","rule":"TRule_literal_value.TAlt2.Rule_real1","sum":109140186},{"parent":"TRule_literal_value.TAlt3","rule":"TRule_literal_value.TAlt3.Token1","sum":2123403353},{"parent":"TRule_literal_value.TAlt5","rule":"TRule_literal_value.TAlt5.Token1","sum":79508859},{"parent":"TRule_literal_value.TAlt9","rule":"TRule_literal_value.TAlt9.Rule_bool_value1","sum":104326396},{"parent":"TRule_match_op","rule":"TRule_match_op.Token1","sum":52236530},{"parent":"TRule_module_path","rule":"TRule_module_path.Block3","sum":362424},{"parent":"TRule_module_path","rule":"TRule_module_path.Rule_an_id2","sum":16595494},{"parent":"TRule_module_path.TBlock3","rule":"TRule_module_path.TBlock3.Rule_an_id2","sum":1080322},{"parent":"TRule_module_path.TBlock3","rule":"TRule_module_path.TBlock3.Token1","sum":1080322},{"parent":"TRule_mul_subexpr","rule":"TRule_mul_subexpr.Block2","sum":115281840},{"parent":"TRule_mul_subexpr","rule":"TRule_mul_subexpr.Rule_con_subexpr1","sum":15793033935},{"parent":"TRule_mul_subexpr.TBlock2","rule":"TRule_mul_subexpr.TBlock2.Rule_con_subexpr2","sum":229534995},{"parent":"TRule_mul_subexpr.TBlock2","rule":"TRule_mul_subexpr.TBlock2.Token1","sum":229534995},{"parent":"TRule_named_bind_parameter","rule":"TRule_named_bind_parameter.Block2","sum":137094},{"parent":"TRule_named_bind_parameter","rule":"TRule_named_bind_parameter.Rule_bind_parameter1","sum":37928631},{"parent":"TRule_named_bind_parameter.TBlock2","rule":"TRule_named_bind_parameter.TBlock2.Rule_bind_parameter2","sum":137094},{"parent":"TRule_named_bind_parameter.TBlock2","rule":"TRule_named_bind_parameter.TBlock2.Token1","sum":137094},{"parent":"TRule_named_bind_parameter_list","rule":"TRule_named_bind_parameter_list.Block2","sum":7067422},{"parent":"TRule_named_bind_parameter_list","rule":"TRule_named_bind_parameter_list.Rule_named_bind_parameter1","sum":16595494},{"parent":"TRule_named_bind_parameter_list.TBlock2","rule":"TRule_named_bind_parameter_list.TBlock2.Rule_named_bind_parameter2","sum":21333137},{"parent":"TRule_named_bind_parameter_list.TBlock2","rule":"TRule_named_bind_parameter_list.TBlock2.Token1","sum":21333137},{"parent":"TRule_named_column","rule":"TRule_named_column.Block2","sum":7179412},{"parent":"TRule_named_column","rule":"TRule_named_column.Rule_column_name1","sum":21372567},{"parent":"TRule_named_column.TBlock2","rule":"TRule_named_column.TBlock2.Rule_an_id2","sum":7179412},{"parent":"TRule_named_column.TBlock2","rule":"TRule_named_column.TBlock2.Token1","sum":7179412},{"parent":"TRule_named_expr","rule":"TRule_named_expr.Block2","sum":156378154},{"parent":"TRule_named_expr","rule":"TRule_named_expr.Rule_expr1","sum":7199519757},{"parent":"TRule_named_expr.TBlock2","rule":"TRule_named_expr.TBlock2.Rule_an_id_or_type2","sum":156378154},{"parent":"TRule_named_expr.TBlock2","rule":"TRule_named_expr.TBlock2.Token1","sum":156378154},{"parent":"TRule_named_expr_list","rule":"TRule_named_expr_list.Block2","sum":1184007000},{"parent":"TRule_named_expr_list","rule":"TRule_named_expr_list.Rule_named_expr1","sum":3241310082},{"parent":"TRule_named_expr_list.TBlock2","rule":"TRule_named_expr_list.TBlock2.Rule_named_expr2","sum":3464332706},{"parent":"TRule_named_expr_list.TBlock2","rule":"TRule_named_expr_list.TBlock2.Token1","sum":3464332706},{"parent":"TRule_named_nodes_stmt","rule":"TRule_named_nodes_stmt.Block3","sum":1007810457},{"parent":"TRule_named_nodes_stmt","rule":"TRule_named_nodes_stmt.Rule_bind_parameter_list1","sum":1007810457},{"parent":"TRule_named_nodes_stmt","rule":"TRule_named_nodes_stmt.Token2","sum":1007810457},{"parent":"TRule_named_nodes_stmt.TBlock3","rule":"TRule_named_nodes_stmt.TBlock3.Alt1","sum":677636582},{"parent":"TRule_named_nodes_stmt.TBlock3","rule":"TRule_named_nodes_stmt.TBlock3.Alt2","sum":330173875},{"parent":"TRule_named_nodes_stmt.TBlock3.TAlt1","rule":"TRule_named_nodes_stmt.TBlock3.TAlt1.Rule_expr1","sum":677636582},{"parent":"TRule_named_nodes_stmt.TBlock3.TAlt2","rule":"TRule_named_nodes_stmt.TBlock3.TAlt2.Rule_subselect_stmt1","sum":330173875},{"parent":"TRule_named_single_source","rule":"TRule_named_single_source.Block2","sum":1},{"parent":"TRule_named_single_source","rule":"TRule_named_single_source.Block3","sum":442845089},{"parent":"TRule_named_single_source","rule":"TRule_named_single_source.Block4","sum":404126},{"parent":"TRule_named_single_source","rule":"TRule_named_single_source.Rule_single_source1","sum":1058832771},{"parent":"TRule_named_single_source.TBlock2","rule":"TRule_named_single_source.TBlock2.Rule_row_pattern_recognition_clause1","sum":1},{"parent":"TRule_named_single_source.TBlock3","rule":"TRule_named_single_source.TBlock3.Block1","sum":442845089},{"parent":"TRule_named_single_source.TBlock3","rule":"TRule_named_single_source.TBlock3.Block2","sum":159943},{"parent":"TRule_named_single_source.TBlock3.TBlock1","rule":"TRule_named_single_source.TBlock3.TBlock1.Alt1","sum":440715497},{"parent":"TRule_named_single_source.TBlock3.TBlock1","rule":"TRule_named_single_source.TBlock3.TBlock1.Alt2","sum":2129592},{"parent":"TRule_named_single_source.TBlock3.TBlock1.TAlt1","rule":"TRule_named_single_source.TBlock3.TBlock1.TAlt1.Rule_an_id2","sum":440715497},{"parent":"TRule_named_single_source.TBlock3.TBlock1.TAlt1","rule":"TRule_named_single_source.TBlock3.TBlock1.TAlt1.Token1","sum":440715497},{"parent":"TRule_named_single_source.TBlock3.TBlock1.TAlt2","rule":"TRule_named_single_source.TBlock3.TBlock1.TAlt2.Rule_an_id_as_compat1","sum":2129592},{"parent":"TRule_named_single_source.TBlock3.TBlock2","rule":"TRule_named_single_source.TBlock3.TBlock2.Rule_pure_column_list1","sum":159943},{"parent":"TRule_named_single_source.TBlock4","rule":"TRule_named_single_source.TBlock4.Alt1","sum":75292},{"parent":"TRule_named_single_source.TBlock4","rule":"TRule_named_single_source.TBlock4.Alt2","sum":328834},{"parent":"TRule_named_single_source.TBlock4.TAlt1","rule":"TRule_named_single_source.TBlock4.TAlt1.Rule_sample_clause1","sum":75292},{"parent":"TRule_named_single_source.TBlock4.TAlt2","rule":"TRule_named_single_source.TBlock4.TAlt2.Rule_tablesample_clause1","sum":328834},{"parent":"TRule_neq_subexpr","rule":"TRule_neq_subexpr.Block2","sum":9145239},{"parent":"TRule_neq_subexpr","rule":"TRule_neq_subexpr.Block3","sum":112058899},{"parent":"TRule_neq_subexpr","rule":"TRule_neq_subexpr.Rule_bit_subexpr1","sum":15457487231},{"parent":"TRule_neq_subexpr.TBlock2","rule":"TRule_neq_subexpr.TBlock2.Block1","sum":9214315},{"parent":"TRule_neq_subexpr.TBlock2","rule":"TRule_neq_subexpr.TBlock2.Rule_bit_subexpr2","sum":9214315},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.Alt1","sum":8101859},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.Alt2","sum":53409},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.Alt3","sum":469},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.Alt4","sum":23},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.Alt5","sum":758109},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.Alt6","sum":134813},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.Alt7","sum":165633},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt1.Token1","sum":8101859},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt2","rule":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt2.Rule_shift_right1","sum":53409},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt3","rule":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt3.Token1","sum":469},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt4","rule":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt4.Rule_rot_right1","sum":23},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt5","rule":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt5.Token1","sum":758109},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt6","rule":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt6.Token1","sum":134813},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt7","rule":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt7.Token1","sum":165633},{"parent":"TRule_neq_subexpr.TBlock3","rule":"TRule_neq_subexpr.TBlock3.Alt1","sum":108282209},{"parent":"TRule_neq_subexpr.TBlock3","rule":"TRule_neq_subexpr.TBlock3.Alt2","sum":3776690},{"parent":"TRule_neq_subexpr.TBlock3.TAlt1","rule":"TRule_neq_subexpr.TBlock3.TAlt1.Rule_double_question1","sum":108282209},{"parent":"TRule_neq_subexpr.TBlock3.TAlt1","rule":"TRule_neq_subexpr.TBlock3.TAlt1.Rule_neq_subexpr2","sum":108282209},{"parent":"TRule_neq_subexpr.TBlock3.TAlt2","rule":"TRule_neq_subexpr.TBlock3.TAlt2.Block1","sum":3776690},{"parent":"TRule_neq_subexpr.TBlock3.TAlt2.TBlock1","rule":"TRule_neq_subexpr.TBlock3.TAlt2.TBlock1.Token1","sum":3788579},{"parent":"TRule_new_window_name","rule":"TRule_new_window_name.Rule_window_name1","sum":14168963},{"parent":"TRule_null_treatment","rule":"TRule_null_treatment.Alt_null_treatment1","sum":45},{"parent":"TRule_null_treatment","rule":"TRule_null_treatment.Alt_null_treatment2","sum":7217734},{"parent":"TRule_null_treatment.TAlt1","rule":"TRule_null_treatment.TAlt1.Token1","sum":45},{"parent":"TRule_null_treatment.TAlt1","rule":"TRule_null_treatment.TAlt1.Token2","sum":45},{"parent":"TRule_null_treatment.TAlt2","rule":"TRule_null_treatment.TAlt2.Token1","sum":7217734},{"parent":"TRule_null_treatment.TAlt2","rule":"TRule_null_treatment.TAlt2.Token2","sum":7217734},{"parent":"TRule_object_ref","rule":"TRule_object_ref.Block1","sum":5292495},{"parent":"TRule_object_ref","rule":"TRule_object_ref.Rule_id_or_at2","sum":133786170},{"parent":"TRule_object_ref.TBlock1","rule":"TRule_object_ref.TBlock1.Rule_cluster_expr1","sum":5292495},{"parent":"TRule_object_ref.TBlock1","rule":"TRule_object_ref.TBlock1.Token2","sum":5292495},{"parent":"TRule_opt_bind_parameter","rule":"TRule_opt_bind_parameter.Block2","sum":27133},{"parent":"TRule_opt_bind_parameter","rule":"TRule_opt_bind_parameter.Rule_bind_parameter1","sum":21477760},{"parent":"TRule_opt_bind_parameter.TBlock2","rule":"TRule_opt_bind_parameter.TBlock2.Token1","sum":27133},{"parent":"TRule_opt_id_prefix","rule":"TRule_opt_id_prefix.Block1","sum":83040753},{"parent":"TRule_opt_id_prefix.TBlock1","rule":"TRule_opt_id_prefix.TBlock1.Rule_an_id1","sum":83040753},{"parent":"TRule_opt_id_prefix.TBlock1","rule":"TRule_opt_id_prefix.TBlock1.Token2","sum":83040753},{"parent":"TRule_opt_id_prefix_or_type","rule":"TRule_opt_id_prefix_or_type.Block1","sum":777899391},{"parent":"TRule_opt_id_prefix_or_type.TBlock1","rule":"TRule_opt_id_prefix_or_type.TBlock1.Rule_an_id_or_type1","sum":777899391},{"parent":"TRule_opt_id_prefix_or_type.TBlock1","rule":"TRule_opt_id_prefix_or_type.TBlock1.Token2","sum":777899391},{"parent":"TRule_opt_set_quantifier","rule":"TRule_opt_set_quantifier.Block1","sum":70393678},{"parent":"TRule_opt_set_quantifier.TBlock1","rule":"TRule_opt_set_quantifier.TBlock1.Token1","sum":70393678},{"parent":"TRule_or_subexpr","rule":"TRule_or_subexpr.Block2","sum":277309968},{"parent":"TRule_or_subexpr","rule":"TRule_or_subexpr.Rule_and_subexpr1","sum":13815818451},{"parent":"TRule_or_subexpr.TBlock2","rule":"TRule_or_subexpr.TBlock2.Rule_and_subexpr2","sum":471399197},{"parent":"TRule_or_subexpr.TBlock2","rule":"TRule_or_subexpr.TBlock2.Token1","sum":471399197},{"parent":"TRule_order_by_clause","rule":"TRule_order_by_clause.Rule_sort_specification_list3","sum":107764368},{"parent":"TRule_order_by_clause","rule":"TRule_order_by_clause.Token1","sum":107764368},{"parent":"TRule_order_by_clause","rule":"TRule_order_by_clause.Token2","sum":107764368},{"parent":"TRule_ordinary_grouping_set","rule":"TRule_ordinary_grouping_set.Rule_named_expr1","sum":301387765},{"parent":"TRule_ordinary_grouping_set_list","rule":"TRule_ordinary_grouping_set_list.Block2","sum":199610},{"parent":"TRule_ordinary_grouping_set_list","rule":"TRule_ordinary_grouping_set_list.Rule_ordinary_grouping_set1","sum":339361},{"parent":"TRule_ordinary_grouping_set_list.TBlock2","rule":"TRule_ordinary_grouping_set_list.TBlock2.Rule_ordinary_grouping_set2","sum":432814},{"parent":"TRule_ordinary_grouping_set_list.TBlock2","rule":"TRule_ordinary_grouping_set_list.TBlock2.Token1","sum":432814},{"parent":"TRule_pragma_stmt","rule":"TRule_pragma_stmt.Block4","sum":792392746},{"parent":"TRule_pragma_stmt","rule":"TRule_pragma_stmt.Rule_an_id3","sum":897035838},{"parent":"TRule_pragma_stmt","rule":"TRule_pragma_stmt.Rule_opt_id_prefix_or_type2","sum":897035838},{"parent":"TRule_pragma_stmt","rule":"TRule_pragma_stmt.Token1","sum":897035838},{"parent":"TRule_pragma_stmt.TBlock4","rule":"TRule_pragma_stmt.TBlock4.Alt1","sum":744372125},{"parent":"TRule_pragma_stmt.TBlock4","rule":"TRule_pragma_stmt.TBlock4.Alt2","sum":48020621},{"parent":"TRule_pragma_stmt.TBlock4.TAlt1","rule":"TRule_pragma_stmt.TBlock4.TAlt1.Rule_pragma_value2","sum":744372125},{"parent":"TRule_pragma_stmt.TBlock4.TAlt1","rule":"TRule_pragma_stmt.TBlock4.TAlt1.Token1","sum":744372125},{"parent":"TRule_pragma_stmt.TBlock4.TAlt2","rule":"TRule_pragma_stmt.TBlock4.TAlt2.Block3","sum":17718783},{"parent":"TRule_pragma_stmt.TBlock4.TAlt2","rule":"TRule_pragma_stmt.TBlock4.TAlt2.Rule_pragma_value2","sum":48020621},{"parent":"TRule_pragma_stmt.TBlock4.TAlt2","rule":"TRule_pragma_stmt.TBlock4.TAlt2.Token1","sum":48020621},{"parent":"TRule_pragma_stmt.TBlock4.TAlt2","rule":"TRule_pragma_stmt.TBlock4.TAlt2.Token4","sum":48020621},{"parent":"TRule_pragma_stmt.TBlock4.TAlt2.TBlock3","rule":"TRule_pragma_stmt.TBlock4.TAlt2.TBlock3.Rule_pragma_value2","sum":18536615},{"parent":"TRule_pragma_stmt.TBlock4.TAlt2.TBlock3","rule":"TRule_pragma_stmt.TBlock4.TAlt2.TBlock3.Token1","sum":18536615},{"parent":"TRule_pragma_value","rule":"TRule_pragma_value.Alt_pragma_value2","sum":256154},{"parent":"TRule_pragma_value","rule":"TRule_pragma_value.Alt_pragma_value3","sum":798322117},{"parent":"TRule_pragma_value","rule":"TRule_pragma_value.Alt_pragma_value5","sum":12351090},{"parent":"TRule_pragma_value.TAlt2","rule":"TRule_pragma_value.TAlt2.Rule_id1","sum":256154},{"parent":"TRule_pragma_value.TAlt3","rule":"TRule_pragma_value.TAlt3.Token1","sum":798322117},{"parent":"TRule_pragma_value.TAlt5","rule":"TRule_pragma_value.TAlt5.Rule_bind_parameter1","sum":12351090},{"parent":"TRule_process_core","rule":"TRule_process_core.Block4","sum":1132},{"parent":"TRule_process_core","rule":"TRule_process_core.Block5","sum":1921069},{"parent":"TRule_process_core","rule":"TRule_process_core.Rule_named_single_source3","sum":4540825},{"parent":"TRule_process_core","rule":"TRule_process_core.Token1","sum":4540825},{"parent":"TRule_process_core.TBlock4","rule":"TRule_process_core.TBlock4.Rule_named_single_source2","sum":1133},{"parent":"TRule_process_core.TBlock4","rule":"TRule_process_core.TBlock4.Token1","sum":1133},{"parent":"TRule_process_core.TBlock5","rule":"TRule_process_core.TBlock5.Block3","sum":46},{"parent":"TRule_process_core.TBlock5","rule":"TRule_process_core.TBlock5.Block5","sum":4667},{"parent":"TRule_process_core.TBlock5","rule":"TRule_process_core.TBlock5.Block7","sum":34},{"parent":"TRule_process_core.TBlock5","rule":"TRule_process_core.TBlock5.Rule_using_call_expr2","sum":1921069},{"parent":"TRule_process_core.TBlock5","rule":"TRule_process_core.TBlock5.Token1","sum":1921069},{"parent":"TRule_process_core.TBlock5.TBlock3","rule":"TRule_process_core.TBlock5.TBlock3.Rule_an_id2","sum":46},{"parent":"TRule_process_core.TBlock5.TBlock3","rule":"TRule_process_core.TBlock5.TBlock3.Token1","sum":46},{"parent":"TRule_process_core.TBlock5.TBlock5","rule":"TRule_process_core.TBlock5.TBlock5.Rule_expr2","sum":4667},{"parent":"TRule_process_core.TBlock5.TBlock5","rule":"TRule_process_core.TBlock5.TBlock5.Token1","sum":4667},{"parent":"TRule_process_core.TBlock5.TBlock7","rule":"TRule_process_core.TBlock5.TBlock7.Rule_order_by_clause2","sum":34},{"parent":"TRule_process_core.TBlock5.TBlock7","rule":"TRule_process_core.TBlock5.TBlock7.Token1","sum":34},{"parent":"TRule_pure_column_list","rule":"TRule_pure_column_list.Block3","sum":3960275},{"parent":"TRule_pure_column_list","rule":"TRule_pure_column_list.Rule_an_id2","sum":4700188},{"parent":"TRule_pure_column_list","rule":"TRule_pure_column_list.Token1","sum":4700188},{"parent":"TRule_pure_column_list","rule":"TRule_pure_column_list.Token4","sum":4700188},{"parent":"TRule_pure_column_list.TBlock3","rule":"TRule_pure_column_list.TBlock3.Rule_an_id2","sum":35264390},{"parent":"TRule_pure_column_list.TBlock3","rule":"TRule_pure_column_list.TBlock3.Token1","sum":35264390},{"parent":"TRule_pure_column_or_named","rule":"TRule_pure_column_or_named.Alt_pure_column_or_named1","sum":6597834},{"parent":"TRule_pure_column_or_named","rule":"TRule_pure_column_or_named.Alt_pure_column_or_named2","sum":425423322},{"parent":"TRule_pure_column_or_named.TAlt1","rule":"TRule_pure_column_or_named.TAlt1.Rule_bind_parameter1","sum":6597834},{"parent":"TRule_pure_column_or_named.TAlt2","rule":"TRule_pure_column_or_named.TAlt2.Rule_an_id1","sum":425423322},{"parent":"TRule_pure_column_or_named_list","rule":"TRule_pure_column_or_named_list.Block3","sum":11686222},{"parent":"TRule_pure_column_or_named_list","rule":"TRule_pure_column_or_named_list.Rule_pure_column_or_named2","sum":32475186},{"parent":"TRule_pure_column_or_named_list","rule":"TRule_pure_column_or_named_list.Token1","sum":32475186},{"parent":"TRule_pure_column_or_named_list","rule":"TRule_pure_column_or_named_list.Token4","sum":32475186},{"parent":"TRule_pure_column_or_named_list.TBlock3","rule":"TRule_pure_column_or_named_list.TBlock3.Rule_pure_column_or_named2","sum":21737177},{"parent":"TRule_pure_column_or_named_list.TBlock3","rule":"TRule_pure_column_or_named_list.TBlock3.Token1","sum":21737177},{"parent":"TRule_real","rule":"TRule_real.Token1","sum":109140186},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Block11","sum":8903},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Block13","sum":26296},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Block3","sum":120701},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Block4","sum":303456},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Block8","sum":315166},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Rule_column_list6","sum":850906},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Rule_named_single_source2","sum":850906},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Rule_using_call_expr9","sum":850906},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Token1","sum":850906},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Token5","sum":850906},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Token7","sum":850906},{"parent":"TRule_reduce_core.TBlock11","rule":"TRule_reduce_core.TBlock11.Rule_expr2","sum":8903},{"parent":"TRule_reduce_core.TBlock11","rule":"TRule_reduce_core.TBlock11.Token1","sum":8903},{"parent":"TRule_reduce_core.TBlock13","rule":"TRule_reduce_core.TBlock13.Rule_order_by_clause2","sum":26296},{"parent":"TRule_reduce_core.TBlock13","rule":"TRule_reduce_core.TBlock13.Token1","sum":26296},{"parent":"TRule_reduce_core.TBlock3","rule":"TRule_reduce_core.TBlock3.Rule_named_single_source2","sum":208839},{"parent":"TRule_reduce_core.TBlock3","rule":"TRule_reduce_core.TBlock3.Token1","sum":208839},{"parent":"TRule_reduce_core.TBlock4","rule":"TRule_reduce_core.TBlock4.Rule_sort_specification_list2","sum":303456},{"parent":"TRule_reduce_core.TBlock4","rule":"TRule_reduce_core.TBlock4.Token1","sum":303456},{"parent":"TRule_reduce_core.TBlock8","rule":"TRule_reduce_core.TBlock8.Token1","sum":315166},{"parent":"TRule_repeatable_clause","rule":"TRule_repeatable_clause.Rule_expr3","sum":9298},{"parent":"TRule_repeatable_clause","rule":"TRule_repeatable_clause.Token1","sum":9298},{"parent":"TRule_repeatable_clause","rule":"TRule_repeatable_clause.Token2","sum":9298},{"parent":"TRule_repeatable_clause","rule":"TRule_repeatable_clause.Token4","sum":9298},{"parent":"TRule_result_column","rule":"TRule_result_column.Alt_result_column1","sum":250526986},{"parent":"TRule_result_column","rule":"TRule_result_column.Alt_result_column2","sum":3450415722},{"parent":"TRule_result_column.TAlt1","rule":"TRule_result_column.TAlt1.Rule_opt_id_prefix1","sum":250526986},{"parent":"TRule_result_column.TAlt1","rule":"TRule_result_column.TAlt1.Token2","sum":250526986},{"parent":"TRule_result_column.TAlt2","rule":"TRule_result_column.TAlt2.Block2","sum":1988884363},{"parent":"TRule_result_column.TAlt2","rule":"TRule_result_column.TAlt2.Rule_expr1","sum":3450415722},{"parent":"TRule_result_column.TAlt2.TBlock2","rule":"TRule_result_column.TAlt2.TBlock2.Alt1","sum":1988018230},{"parent":"TRule_result_column.TAlt2.TBlock2","rule":"TRule_result_column.TAlt2.TBlock2.Alt2","sum":866133},{"parent":"TRule_result_column.TAlt2.TBlock2.TAlt1","rule":"TRule_result_column.TAlt2.TBlock2.TAlt1.Rule_an_id_or_type2","sum":1988018230},{"parent":"TRule_result_column.TAlt2.TBlock2.TAlt1","rule":"TRule_result_column.TAlt2.TBlock2.TAlt1.Token1","sum":1988018230},{"parent":"TRule_result_column.TAlt2.TBlock2.TAlt2","rule":"TRule_result_column.TAlt2.TBlock2.TAlt2.Rule_an_id_as_compat1","sum":866133},{"parent":"TRule_rollup_list","rule":"TRule_rollup_list.Rule_ordinary_grouping_set_list3","sum":62641},{"parent":"TRule_rollup_list","rule":"TRule_rollup_list.Token1","sum":62641},{"parent":"TRule_rollup_list","rule":"TRule_rollup_list.Token2","sum":62641},{"parent":"TRule_rollup_list","rule":"TRule_rollup_list.Token4","sum":62641},{"parent":"TRule_rot_right","rule":"TRule_rot_right.Token1","sum":23},{"parent":"TRule_rot_right","rule":"TRule_rot_right.Token2","sum":23},{"parent":"TRule_rot_right","rule":"TRule_rot_right.Token3","sum":23},{"parent":"TRule_row_pattern","rule":"TRule_row_pattern.Rule_row_pattern_term1","sum":2},{"parent":"TRule_row_pattern_common_syntax","rule":"TRule_row_pattern_common_syntax.Rule_row_pattern5","sum":1},{"parent":"TRule_row_pattern_common_syntax","rule":"TRule_row_pattern_common_syntax.Rule_row_pattern_definition_list9","sum":1},{"parent":"TRule_row_pattern_common_syntax","rule":"TRule_row_pattern_common_syntax.Token3","sum":1},{"parent":"TRule_row_pattern_common_syntax","rule":"TRule_row_pattern_common_syntax.Token4","sum":1},{"parent":"TRule_row_pattern_common_syntax","rule":"TRule_row_pattern_common_syntax.Token6","sum":1},{"parent":"TRule_row_pattern_common_syntax","rule":"TRule_row_pattern_common_syntax.Token8","sum":1},{"parent":"TRule_row_pattern_definition","rule":"TRule_row_pattern_definition.Rule_row_pattern_definition_search_condition3","sum":1},{"parent":"TRule_row_pattern_definition","rule":"TRule_row_pattern_definition.Rule_row_pattern_definition_variable_name1","sum":1},{"parent":"TRule_row_pattern_definition","rule":"TRule_row_pattern_definition.Token2","sum":1},{"parent":"TRule_row_pattern_definition_list","rule":"TRule_row_pattern_definition_list.Rule_row_pattern_definition1","sum":1},{"parent":"TRule_row_pattern_definition_search_condition","rule":"TRule_row_pattern_definition_search_condition.Rule_search_condition1","sum":1},{"parent":"TRule_row_pattern_definition_variable_name","rule":"TRule_row_pattern_definition_variable_name.Rule_row_pattern_variable_name1","sum":1},{"parent":"TRule_row_pattern_factor","rule":"TRule_row_pattern_factor.Block2","sum":1},{"parent":"TRule_row_pattern_factor","rule":"TRule_row_pattern_factor.Rule_row_pattern_primary1","sum":2},{"parent":"TRule_row_pattern_factor.TBlock2","rule":"TRule_row_pattern_factor.TBlock2.Rule_row_pattern_quantifier1","sum":1},{"parent":"TRule_row_pattern_measure_definition","rule":"TRule_row_pattern_measure_definition.Rule_an_id3","sum":3},{"parent":"TRule_row_pattern_measure_definition","rule":"TRule_row_pattern_measure_definition.Rule_expr1","sum":3},{"parent":"TRule_row_pattern_measure_definition","rule":"TRule_row_pattern_measure_definition.Token2","sum":3},{"parent":"TRule_row_pattern_measure_list","rule":"TRule_row_pattern_measure_list.Block2","sum":1},{"parent":"TRule_row_pattern_measure_list","rule":"TRule_row_pattern_measure_list.Rule_row_pattern_measure_definition1","sum":1},{"parent":"TRule_row_pattern_measure_list.TBlock2","rule":"TRule_row_pattern_measure_list.TBlock2.Rule_row_pattern_measure_definition2","sum":2},{"parent":"TRule_row_pattern_measure_list.TBlock2","rule":"TRule_row_pattern_measure_list.TBlock2.Token1","sum":2},{"parent":"TRule_row_pattern_measures","rule":"TRule_row_pattern_measures.Rule_row_pattern_measure_list2","sum":1},{"parent":"TRule_row_pattern_measures","rule":"TRule_row_pattern_measures.Token1","sum":1},{"parent":"TRule_row_pattern_primary","rule":"TRule_row_pattern_primary.Alt_row_pattern_primary1","sum":1},{"parent":"TRule_row_pattern_primary","rule":"TRule_row_pattern_primary.Alt_row_pattern_primary4","sum":1},{"parent":"TRule_row_pattern_primary.TAlt1","rule":"TRule_row_pattern_primary.TAlt1.Rule_row_pattern_primary_variable_name1","sum":1},{"parent":"TRule_row_pattern_primary.TAlt4","rule":"TRule_row_pattern_primary.TAlt4.Block2","sum":1},{"parent":"TRule_row_pattern_primary.TAlt4","rule":"TRule_row_pattern_primary.TAlt4.Token1","sum":1},{"parent":"TRule_row_pattern_primary.TAlt4","rule":"TRule_row_pattern_primary.TAlt4.Token3","sum":1},{"parent":"TRule_row_pattern_primary.TAlt4.TBlock2","rule":"TRule_row_pattern_primary.TAlt4.TBlock2.Rule_row_pattern1","sum":1},{"parent":"TRule_row_pattern_primary_variable_name","rule":"TRule_row_pattern_primary_variable_name.Rule_row_pattern_variable_name1","sum":1},{"parent":"TRule_row_pattern_quantifier","rule":"TRule_row_pattern_quantifier.Alt_row_pattern_quantifier5","sum":1},{"parent":"TRule_row_pattern_quantifier.TAlt5","rule":"TRule_row_pattern_quantifier.TAlt5.Rule_integer2","sum":1},{"parent":"TRule_row_pattern_quantifier.TAlt5","rule":"TRule_row_pattern_quantifier.TAlt5.Token1","sum":1},{"parent":"TRule_row_pattern_quantifier.TAlt5","rule":"TRule_row_pattern_quantifier.TAlt5.Token3","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Block3","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Block4","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Block5","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Block6","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Rule_row_pattern_common_syntax7","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Token1","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Token2","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Token8","sum":1},{"parent":"TRule_row_pattern_recognition_clause.TBlock3","rule":"TRule_row_pattern_recognition_clause.TBlock3.Rule_window_partition_clause1","sum":1},{"parent":"TRule_row_pattern_recognition_clause.TBlock4","rule":"TRule_row_pattern_recognition_clause.TBlock4.Rule_order_by_clause1","sum":1},{"parent":"TRule_row_pattern_recognition_clause.TBlock5","rule":"TRule_row_pattern_recognition_clause.TBlock5.Rule_row_pattern_measures1","sum":1},{"parent":"TRule_row_pattern_recognition_clause.TBlock6","rule":"TRule_row_pattern_recognition_clause.TBlock6.Rule_row_pattern_rows_per_match1","sum":1},{"parent":"TRule_row_pattern_rows_per_match","rule":"TRule_row_pattern_rows_per_match.Alt_row_pattern_rows_per_match1","sum":1},{"parent":"TRule_row_pattern_rows_per_match.TAlt1","rule":"TRule_row_pattern_rows_per_match.TAlt1.Token1","sum":1},{"parent":"TRule_row_pattern_rows_per_match.TAlt1","rule":"TRule_row_pattern_rows_per_match.TAlt1.Token2","sum":1},{"parent":"TRule_row_pattern_rows_per_match.TAlt1","rule":"TRule_row_pattern_rows_per_match.TAlt1.Token3","sum":1},{"parent":"TRule_row_pattern_rows_per_match.TAlt1","rule":"TRule_row_pattern_rows_per_match.TAlt1.Token4","sum":1},{"parent":"TRule_row_pattern_term","rule":"TRule_row_pattern_term.Block1","sum":2},{"parent":"TRule_row_pattern_term.TBlock1","rule":"TRule_row_pattern_term.TBlock1.Rule_row_pattern_factor1","sum":2},{"parent":"TRule_row_pattern_variable_name","rule":"TRule_row_pattern_variable_name.Rule_identifier1","sum":2},{"parent":"TRule_sample_clause","rule":"TRule_sample_clause.Rule_expr2","sum":75292},{"parent":"TRule_sample_clause","rule":"TRule_sample_clause.Token1","sum":75292},{"parent":"TRule_sampling_mode","rule":"TRule_sampling_mode.Token1","sum":328834},{"parent":"TRule_search_condition","rule":"TRule_search_condition.Rule_expr1","sum":1},{"parent":"TRule_select_core","rule":"TRule_select_core.Block1","sum":10673659},{"parent":"TRule_select_core","rule":"TRule_select_core.Block10","sum":340990952},{"parent":"TRule_select_core","rule":"TRule_select_core.Block11","sum":137899286},{"parent":"TRule_select_core","rule":"TRule_select_core.Block12","sum":12067250},{"parent":"TRule_select_core","rule":"TRule_select_core.Block13","sum":13593427},{"parent":"TRule_select_core","rule":"TRule_select_core.Block14","sum":88715837},{"parent":"TRule_select_core","rule":"TRule_select_core.Block3","sum":117},{"parent":"TRule_select_core","rule":"TRule_select_core.Block6","sum":529926726},{"parent":"TRule_select_core","rule":"TRule_select_core.Block7","sum":93760052},{"parent":"TRule_select_core","rule":"TRule_select_core.Block8","sum":24912265},{"parent":"TRule_select_core","rule":"TRule_select_core.Block9","sum":833826276},{"parent":"TRule_select_core","rule":"TRule_select_core.Rule_opt_set_quantifier4","sum":905048656},{"parent":"TRule_select_core","rule":"TRule_select_core.Rule_result_column5","sum":905048656},{"parent":"TRule_select_core","rule":"TRule_select_core.Token2","sum":905048656},{"parent":"TRule_select_core.TBlock1","rule":"TRule_select_core.TBlock1.Rule_join_source2","sum":10673659},{"parent":"TRule_select_core.TBlock1","rule":"TRule_select_core.TBlock1.Token1","sum":10673659},{"parent":"TRule_select_core.TBlock10","rule":"TRule_select_core.TBlock10.Rule_expr2","sum":340990952},{"parent":"TRule_select_core.TBlock10","rule":"TRule_select_core.TBlock10.Token1","sum":340990952},{"parent":"TRule_select_core.TBlock11","rule":"TRule_select_core.TBlock11.Rule_group_by_clause1","sum":137899286},{"parent":"TRule_select_core.TBlock12","rule":"TRule_select_core.TBlock12.Rule_expr2","sum":12067250},{"parent":"TRule_select_core.TBlock12","rule":"TRule_select_core.TBlock12.Token1","sum":12067250},{"parent":"TRule_select_core.TBlock13","rule":"TRule_select_core.TBlock13.Rule_window_clause1","sum":13593427},{"parent":"TRule_select_core.TBlock14","rule":"TRule_select_core.TBlock14.Rule_ext_order_by_clause1","sum":88715837},{"parent":"TRule_select_core.TBlock3","rule":"TRule_select_core.TBlock3.Token1","sum":117},{"parent":"TRule_select_core.TBlock6","rule":"TRule_select_core.TBlock6.Rule_result_column2","sum":2795894052},{"parent":"TRule_select_core.TBlock6","rule":"TRule_select_core.TBlock6.Token1","sum":2795894052},{"parent":"TRule_select_core.TBlock7","rule":"TRule_select_core.TBlock7.Token1","sum":93760052},{"parent":"TRule_select_core.TBlock8","rule":"TRule_select_core.TBlock8.Block2","sum":50},{"parent":"TRule_select_core.TBlock8","rule":"TRule_select_core.TBlock8.Rule_without_column_list3","sum":24912265},{"parent":"TRule_select_core.TBlock8","rule":"TRule_select_core.TBlock8.Token1","sum":24912265},{"parent":"TRule_select_core.TBlock8.TBlock2","rule":"TRule_select_core.TBlock8.TBlock2.Token1","sum":50},{"parent":"TRule_select_core.TBlock8.TBlock2","rule":"TRule_select_core.TBlock8.TBlock2.Token2","sum":50},{"parent":"TRule_select_core.TBlock9","rule":"TRule_select_core.TBlock9.Rule_join_source2","sum":833826276},{"parent":"TRule_select_core.TBlock9","rule":"TRule_select_core.TBlock9.Token1","sum":833826276},{"parent":"TRule_select_kind","rule":"TRule_select_kind.Block1","sum":922928},{"parent":"TRule_select_kind","rule":"TRule_select_kind.Block2","sum":910440387},{"parent":"TRule_select_kind","rule":"TRule_select_kind.Block3","sum":2883619},{"parent":"TRule_select_kind.TBlock1","rule":"TRule_select_kind.TBlock1.Token1","sum":922928},{"parent":"TRule_select_kind.TBlock2","rule":"TRule_select_kind.TBlock2.Alt1","sum":4540825},{"parent":"TRule_select_kind.TBlock2","rule":"TRule_select_kind.TBlock2.Alt2","sum":850906},{"parent":"TRule_select_kind.TBlock2","rule":"TRule_select_kind.TBlock2.Alt3","sum":905048656},{"parent":"TRule_select_kind.TBlock2.TAlt1","rule":"TRule_select_kind.TBlock2.TAlt1.Rule_process_core1","sum":4540825},{"parent":"TRule_select_kind.TBlock2.TAlt2","rule":"TRule_select_kind.TBlock2.TAlt2.Rule_reduce_core1","sum":850906},{"parent":"TRule_select_kind.TBlock2.TAlt3","rule":"TRule_select_kind.TBlock2.TAlt3.Rule_select_core1","sum":905048656},{"parent":"TRule_select_kind.TBlock3","rule":"TRule_select_kind.TBlock3.Rule_pure_column_or_named3","sum":2883619},{"parent":"TRule_select_kind.TBlock3","rule":"TRule_select_kind.TBlock3.Token1","sum":2883619},{"parent":"TRule_select_kind.TBlock3","rule":"TRule_select_kind.TBlock3.Token2","sum":2883619},{"parent":"TRule_select_kind_parenthesis","rule":"TRule_select_kind_parenthesis.Alt_select_kind_parenthesis1","sum":779731897},{"parent":"TRule_select_kind_parenthesis","rule":"TRule_select_kind_parenthesis.Alt_select_kind_parenthesis2","sum":7982913},{"parent":"TRule_select_kind_parenthesis.TAlt1","rule":"TRule_select_kind_parenthesis.TAlt1.Rule_select_kind_partial1","sum":779731897},{"parent":"TRule_select_kind_parenthesis.TAlt2","rule":"TRule_select_kind_parenthesis.TAlt2.Rule_select_kind_partial2","sum":7982913},{"parent":"TRule_select_kind_parenthesis.TAlt2","rule":"TRule_select_kind_parenthesis.TAlt2.Token1","sum":7982913},{"parent":"TRule_select_kind_parenthesis.TAlt2","rule":"TRule_select_kind_parenthesis.TAlt2.Token3","sum":7982913},{"parent":"TRule_select_kind_partial","rule":"TRule_select_kind_partial.Block2","sum":30714415},{"parent":"TRule_select_kind_partial","rule":"TRule_select_kind_partial.Rule_select_kind1","sum":910440387},{"parent":"TRule_select_kind_partial.TBlock2","rule":"TRule_select_kind_partial.TBlock2.Block3","sum":4615623},{"parent":"TRule_select_kind_partial.TBlock2","rule":"TRule_select_kind_partial.TBlock2.Rule_expr2","sum":30714415},{"parent":"TRule_select_kind_partial.TBlock2","rule":"TRule_select_kind_partial.TBlock2.Token1","sum":30714415},{"parent":"TRule_select_kind_partial.TBlock2.TBlock3","rule":"TRule_select_kind_partial.TBlock2.TBlock3.Rule_expr2","sum":4615623},{"parent":"TRule_select_kind_partial.TBlock2.TBlock3","rule":"TRule_select_kind_partial.TBlock2.TBlock3.Token1","sum":4615623},{"parent":"TRule_select_op","rule":"TRule_select_op.Alt_select_op1","sum":63914805},{"parent":"TRule_select_op.TAlt1","rule":"TRule_select_op.TAlt1.Block2","sum":62999622},{"parent":"TRule_select_op.TAlt1","rule":"TRule_select_op.TAlt1.Token1","sum":63914805},{"parent":"TRule_select_op.TAlt1.TBlock2","rule":"TRule_select_op.TAlt1.TBlock2.Token1","sum":62999622},{"parent":"TRule_select_stmt","rule":"TRule_select_stmt.Block2","sum":33291159},{"parent":"TRule_select_stmt","rule":"TRule_select_stmt.Rule_select_kind_parenthesis1","sum":723800005},{"parent":"TRule_select_stmt.TBlock2","rule":"TRule_select_stmt.TBlock2.Rule_select_kind_parenthesis2","sum":56947670},{"parent":"TRule_select_stmt.TBlock2","rule":"TRule_select_stmt.TBlock2.Rule_select_op1","sum":56947670},{"parent":"TRule_select_unparenthesized_stmt","rule":"TRule_select_unparenthesized_stmt.Block2","sum":4301601},{"parent":"TRule_select_unparenthesized_stmt","rule":"TRule_select_unparenthesized_stmt.Rule_select_kind_partial1","sum":122725577},{"parent":"TRule_select_unparenthesized_stmt.TBlock2","rule":"TRule_select_unparenthesized_stmt.TBlock2.Rule_select_kind_parenthesis2","sum":6967135},{"parent":"TRule_select_unparenthesized_stmt.TBlock2","rule":"TRule_select_unparenthesized_stmt.TBlock2.Rule_select_op1","sum":6967135},{"parent":"TRule_shift_right","rule":"TRule_shift_right.Token1","sum":53409},{"parent":"TRule_shift_right","rule":"TRule_shift_right.Token2","sum":53409},{"parent":"TRule_simple_table_ref","rule":"TRule_simple_table_ref.Block2","sum":143100620},{"parent":"TRule_simple_table_ref","rule":"TRule_simple_table_ref.Rule_simple_table_ref_core1","sum":211659349},{"parent":"TRule_simple_table_ref.TBlock2","rule":"TRule_simple_table_ref.TBlock2.Rule_table_hints1","sum":143100620},{"parent":"TRule_simple_table_ref_core","rule":"TRule_simple_table_ref_core.Alt_simple_table_ref_core1","sum":133786170},{"parent":"TRule_simple_table_ref_core","rule":"TRule_simple_table_ref_core.Alt_simple_table_ref_core2","sum":77873179},{"parent":"TRule_simple_table_ref_core.TAlt1","rule":"TRule_simple_table_ref_core.TAlt1.Rule_object_ref1","sum":133786170},{"parent":"TRule_simple_table_ref_core.TAlt2","rule":"TRule_simple_table_ref_core.TAlt2.Block1","sum":71525},{"parent":"TRule_simple_table_ref_core.TAlt2","rule":"TRule_simple_table_ref_core.TAlt2.Rule_bind_parameter2","sum":77873179},{"parent":"TRule_simple_table_ref_core.TAlt2.TBlock1","rule":"TRule_simple_table_ref_core.TAlt2.TBlock1.Token1","sum":71525},{"parent":"TRule_single_source","rule":"TRule_single_source.Alt_single_source1","sum":953815950},{"parent":"TRule_single_source","rule":"TRule_single_source.Alt_single_source2","sum":104848265},{"parent":"TRule_single_source","rule":"TRule_single_source.Alt_single_source3","sum":168556},{"parent":"TRule_single_source.TAlt1","rule":"TRule_single_source.TAlt1.Rule_table_ref1","sum":953815950},{"parent":"TRule_single_source.TAlt2","rule":"TRule_single_source.TAlt2.Rule_select_stmt2","sum":104848265},{"parent":"TRule_single_source.TAlt2","rule":"TRule_single_source.TAlt2.Token1","sum":104848265},{"parent":"TRule_single_source.TAlt2","rule":"TRule_single_source.TAlt2.Token3","sum":104848265},{"parent":"TRule_single_source.TAlt3","rule":"TRule_single_source.TAlt3.Rule_values_stmt2","sum":168556},{"parent":"TRule_single_source.TAlt3","rule":"TRule_single_source.TAlt3.Token1","sum":168556},{"parent":"TRule_single_source.TAlt3","rule":"TRule_single_source.TAlt3.Token3","sum":168556},{"parent":"TRule_smart_parenthesis","rule":"TRule_smart_parenthesis.Block2","sum":508791006},{"parent":"TRule_smart_parenthesis","rule":"TRule_smart_parenthesis.Block3","sum":2645106},{"parent":"TRule_smart_parenthesis","rule":"TRule_smart_parenthesis.Token1","sum":512606456},{"parent":"TRule_smart_parenthesis","rule":"TRule_smart_parenthesis.Token4","sum":512606456},{"parent":"TRule_smart_parenthesis.TBlock2","rule":"TRule_smart_parenthesis.TBlock2.Rule_named_expr_list1","sum":508791006},{"parent":"TRule_smart_parenthesis.TBlock3","rule":"TRule_smart_parenthesis.TBlock3.Token1","sum":2645106},{"parent":"TRule_sort_specification","rule":"TRule_sort_specification.Block2","sum":33224244},{"parent":"TRule_sort_specification","rule":"TRule_sort_specification.Rule_expr1","sum":181756851},{"parent":"TRule_sort_specification.TBlock2","rule":"TRule_sort_specification.TBlock2.Token1","sum":33224244},{"parent":"TRule_sort_specification_list","rule":"TRule_sort_specification_list.Block2","sum":39892637},{"parent":"TRule_sort_specification_list","rule":"TRule_sort_specification_list.Rule_sort_specification1","sum":108067824},{"parent":"TRule_sort_specification_list.TBlock2","rule":"TRule_sort_specification_list.TBlock2.Rule_sort_specification2","sum":73689027},{"parent":"TRule_sort_specification_list.TBlock2","rule":"TRule_sort_specification_list.TBlock2.Token1","sum":73689027},{"parent":"TRule_sql_query","rule":"TRule_sql_query.Alt_sql_query1","sum":320376481},{"parent":"TRule_sql_query.TAlt1","rule":"TRule_sql_query.TAlt1.Rule_sql_stmt_list1","sum":320376481},{"parent":"TRule_sql_stmt","rule":"TRule_sql_stmt.Block1","sum":53},{"parent":"TRule_sql_stmt","rule":"TRule_sql_stmt.Rule_sql_stmt_core2","sum":2722668438},{"parent":"TRule_sql_stmt.TBlock1","rule":"TRule_sql_stmt.TBlock1.Token1","sum":53},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core1","sum":897035838},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core12","sum":156488693},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core13","sum":16592835},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core17","sum":4709503},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core18","sum":22288095},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core19","sum":8565607},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core2","sum":193671855},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core20","sum":7010919},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core21","sum":321},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core3","sum":944054256},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core4","sum":127},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core5","sum":2568070},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core6","sum":329672608},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core7","sum":209091152},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core8","sum":13024992},{"parent":"TRule_sql_stmt_core.TAlt1","rule":"TRule_sql_stmt_core.TAlt1.Rule_pragma_stmt1","sum":897035838},{"parent":"TRule_sql_stmt_core.TAlt12","rule":"TRule_sql_stmt_core.TAlt12.Rule_declare_stmt1","sum":156488693},{"parent":"TRule_sql_stmt_core.TAlt13","rule":"TRule_sql_stmt_core.TAlt13.Rule_import_stmt1","sum":16592835},{"parent":"TRule_sql_stmt_core.TAlt17","rule":"TRule_sql_stmt_core.TAlt17.Rule_do_stmt1","sum":4709503},{"parent":"TRule_sql_stmt_core.TAlt18","rule":"TRule_sql_stmt_core.TAlt18.Rule_define_action_or_subquery_stmt1","sum":22288095},{"parent":"TRule_sql_stmt_core.TAlt19","rule":"TRule_sql_stmt_core.TAlt19.Rule_if_stmt1","sum":8565607},{"parent":"TRule_sql_stmt_core.TAlt2","rule":"TRule_sql_stmt_core.TAlt2.Rule_select_stmt1","sum":193671855},{"parent":"TRule_sql_stmt_core.TAlt20","rule":"TRule_sql_stmt_core.TAlt20.Rule_for_stmt1","sum":7010919},{"parent":"TRule_sql_stmt_core.TAlt21","rule":"TRule_sql_stmt_core.TAlt21.Rule_values_stmt1","sum":321},{"parent":"TRule_sql_stmt_core.TAlt3","rule":"TRule_sql_stmt_core.TAlt3.Rule_named_nodes_stmt1","sum":944054256},{"parent":"TRule_sql_stmt_core.TAlt4","rule":"TRule_sql_stmt_core.TAlt4.Rule_create_table_stmt1","sum":127},{"parent":"TRule_sql_stmt_core.TAlt5","rule":"TRule_sql_stmt_core.TAlt5.Rule_drop_table_stmt1","sum":2568070},{"parent":"TRule_sql_stmt_core.TAlt6","rule":"TRule_sql_stmt_core.TAlt6.Rule_use_stmt1","sum":329672608},{"parent":"TRule_sql_stmt_core.TAlt7","rule":"TRule_sql_stmt_core.TAlt7.Rule_into_table_stmt1","sum":209091152},{"parent":"TRule_sql_stmt_core.TAlt8","rule":"TRule_sql_stmt_core.TAlt8.Rule_commit_stmt1","sum":13024992},{"parent":"TRule_sql_stmt_list","rule":"TRule_sql_stmt_list.Block1","sum":437},{"parent":"TRule_sql_stmt_list","rule":"TRule_sql_stmt_list.Block3","sum":314893323},{"parent":"TRule_sql_stmt_list","rule":"TRule_sql_stmt_list.Block4","sum":195235820},{"parent":"TRule_sql_stmt_list","rule":"TRule_sql_stmt_list.Rule_sql_stmt2","sum":320376481},{"parent":"TRule_sql_stmt_list","rule":"TRule_sql_stmt_list.Token5","sum":320376481},{"parent":"TRule_sql_stmt_list.TBlock1","rule":"TRule_sql_stmt_list.TBlock1.Token1","sum":460},{"parent":"TRule_sql_stmt_list.TBlock3","rule":"TRule_sql_stmt_list.TBlock3.Block1","sum":2402291957},{"parent":"TRule_sql_stmt_list.TBlock3","rule":"TRule_sql_stmt_list.TBlock3.Rule_sql_stmt2","sum":2402291957},{"parent":"TRule_sql_stmt_list.TBlock3.TBlock1","rule":"TRule_sql_stmt_list.TBlock3.TBlock1.Token1","sum":2411363014},{"parent":"TRule_sql_stmt_list.TBlock4","rule":"TRule_sql_stmt_list.TBlock4.Token1","sum":197926078},{"parent":"TRule_struct_arg","rule":"TRule_struct_arg.Rule_type_name_or_bind3","sum":114011524},{"parent":"TRule_struct_arg","rule":"TRule_struct_arg.Rule_type_name_tag1","sum":114011524},{"parent":"TRule_struct_arg","rule":"TRule_struct_arg.Token2","sum":114011524},{"parent":"TRule_struct_arg_positional","rule":"TRule_struct_arg_positional.Alt_struct_arg_positional1","sum":175},{"parent":"TRule_struct_arg_positional.TAlt1","rule":"TRule_struct_arg_positional.TAlt1.Block3","sum":146},{"parent":"TRule_struct_arg_positional.TAlt1","rule":"TRule_struct_arg_positional.TAlt1.Rule_type_name_or_bind2","sum":175},{"parent":"TRule_struct_arg_positional.TAlt1","rule":"TRule_struct_arg_positional.TAlt1.Rule_type_name_tag1","sum":175},{"parent":"TRule_struct_arg_positional.TAlt1.TBlock3","rule":"TRule_struct_arg_positional.TAlt1.TBlock3.Token2","sum":146},{"parent":"TRule_struct_literal","rule":"TRule_struct_literal.Block2","sum":14494469},{"parent":"TRule_struct_literal","rule":"TRule_struct_literal.Block3","sum":2539851},{"parent":"TRule_struct_literal","rule":"TRule_struct_literal.Token1","sum":14625860},{"parent":"TRule_struct_literal","rule":"TRule_struct_literal.Token4","sum":14625860},{"parent":"TRule_struct_literal.TBlock2","rule":"TRule_struct_literal.TBlock2.Rule_expr_struct_list1","sum":14494469},{"parent":"TRule_struct_literal.TBlock3","rule":"TRule_struct_literal.TBlock3.Token1","sum":2539851},{"parent":"TRule_subselect_stmt","rule":"TRule_subselect_stmt.Block1","sum":330173875},{"parent":"TRule_subselect_stmt.TBlock1","rule":"TRule_subselect_stmt.TBlock1.Alt1","sum":207448298},{"parent":"TRule_subselect_stmt.TBlock1","rule":"TRule_subselect_stmt.TBlock1.Alt2","sum":122725577},{"parent":"TRule_subselect_stmt.TBlock1.TAlt1","rule":"TRule_subselect_stmt.TBlock1.TAlt1.Rule_select_stmt2","sum":207448298},{"parent":"TRule_subselect_stmt.TBlock1.TAlt1","rule":"TRule_subselect_stmt.TBlock1.TAlt1.Token1","sum":207448298},{"parent":"TRule_subselect_stmt.TBlock1.TAlt1","rule":"TRule_subselect_stmt.TBlock1.TAlt1.Token3","sum":207448298},{"parent":"TRule_subselect_stmt.TBlock1.TAlt2","rule":"TRule_subselect_stmt.TBlock1.TAlt2.Rule_select_unparenthesized_stmt1","sum":122725577},{"parent":"TRule_table_arg","rule":"TRule_table_arg.Block1","sum":116480},{"parent":"TRule_table_arg","rule":"TRule_table_arg.Block3","sum":265957},{"parent":"TRule_table_arg","rule":"TRule_table_arg.Rule_named_expr2","sum":192489204},{"parent":"TRule_table_arg.TBlock1","rule":"TRule_table_arg.TBlock1.Token1","sum":116480},{"parent":"TRule_table_arg.TBlock3","rule":"TRule_table_arg.TBlock3.Rule_view_name2","sum":265957},{"parent":"TRule_table_arg.TBlock3","rule":"TRule_table_arg.TBlock3.Token1","sum":265957},{"parent":"TRule_table_constraint","rule":"TRule_table_constraint.Alt_table_constraint2","sum":126},{"parent":"TRule_table_constraint","rule":"TRule_table_constraint.Alt_table_constraint3","sum":107},{"parent":"TRule_table_constraint.TAlt2","rule":"TRule_table_constraint.TAlt2.Block5","sum":105},{"parent":"TRule_table_constraint.TAlt2","rule":"TRule_table_constraint.TAlt2.Rule_an_id4","sum":126},{"parent":"TRule_table_constraint.TAlt2","rule":"TRule_table_constraint.TAlt2.Token1","sum":126},{"parent":"TRule_table_constraint.TAlt2","rule":"TRule_table_constraint.TAlt2.Token2","sum":126},{"parent":"TRule_table_constraint.TAlt2","rule":"TRule_table_constraint.TAlt2.Token3","sum":126},{"parent":"TRule_table_constraint.TAlt2","rule":"TRule_table_constraint.TAlt2.Token6","sum":126},{"parent":"TRule_table_constraint.TAlt2.TBlock5","rule":"TRule_table_constraint.TAlt2.TBlock5.Rule_an_id2","sum":264},{"parent":"TRule_table_constraint.TAlt2.TBlock5","rule":"TRule_table_constraint.TAlt2.TBlock5.Token1","sum":264},{"parent":"TRule_table_constraint.TAlt3","rule":"TRule_table_constraint.TAlt3.Rule_column_order_by_specification4","sum":107},{"parent":"TRule_table_constraint.TAlt3","rule":"TRule_table_constraint.TAlt3.Token1","sum":107},{"parent":"TRule_table_constraint.TAlt3","rule":"TRule_table_constraint.TAlt3.Token2","sum":107},{"parent":"TRule_table_constraint.TAlt3","rule":"TRule_table_constraint.TAlt3.Token3","sum":107},{"parent":"TRule_table_constraint.TAlt3","rule":"TRule_table_constraint.TAlt3.Token6","sum":107},{"parent":"TRule_table_hint","rule":"TRule_table_hint.Alt_table_hint1","sum":154481585},{"parent":"TRule_table_hint","rule":"TRule_table_hint.Alt_table_hint2","sum":18945529},{"parent":"TRule_table_hint","rule":"TRule_table_hint.Alt_table_hint3","sum":12},{"parent":"TRule_table_hint.TAlt1","rule":"TRule_table_hint.TAlt1.Block2","sum":10750741},{"parent":"TRule_table_hint.TAlt1","rule":"TRule_table_hint.TAlt1.Rule_an_id_hint1","sum":154481585},{"parent":"TRule_table_hint.TAlt1.TBlock2","rule":"TRule_table_hint.TAlt1.TBlock2.Block2","sum":10750741},{"parent":"TRule_table_hint.TAlt1.TBlock2","rule":"TRule_table_hint.TAlt1.TBlock2.Token1","sum":10750741},{"parent":"TRule_table_hint.TAlt1.TBlock2.TBlock2","rule":"TRule_table_hint.TAlt1.TBlock2.TBlock2.Alt1","sum":10750741},{"parent":"TRule_table_hint.TAlt1.TBlock2.TBlock2.TAlt1","rule":"TRule_table_hint.TAlt1.TBlock2.TBlock2.TAlt1.Rule_type_name_tag1","sum":10750741},{"parent":"TRule_table_hint.TAlt2","rule":"TRule_table_hint.TAlt2.Block2","sum":1683},{"parent":"TRule_table_hint.TAlt2","rule":"TRule_table_hint.TAlt2.Rule_type_name_or_bind3","sum":18945529},{"parent":"TRule_table_hint.TAlt2","rule":"TRule_table_hint.TAlt2.Token1","sum":18945529},{"parent":"TRule_table_hint.TAlt2.TBlock2","rule":"TRule_table_hint.TAlt2.TBlock2.Token1","sum":1683},{"parent":"TRule_table_hint.TAlt3","rule":"TRule_table_hint.TAlt3.Block4","sum":12},{"parent":"TRule_table_hint.TAlt3","rule":"TRule_table_hint.TAlt3.Token1","sum":12},{"parent":"TRule_table_hint.TAlt3","rule":"TRule_table_hint.TAlt3.Token3","sum":12},{"parent":"TRule_table_hint.TAlt3","rule":"TRule_table_hint.TAlt3.Token6","sum":12},{"parent":"TRule_table_hint.TAlt3.TBlock4","rule":"TRule_table_hint.TAlt3.TBlock4.Block2","sum":7},{"parent":"TRule_table_hint.TAlt3.TBlock4","rule":"TRule_table_hint.TAlt3.TBlock4.Rule_struct_arg_positional1","sum":12},{"parent":"TRule_table_hint.TAlt3.TBlock4.TBlock2","rule":"TRule_table_hint.TAlt3.TBlock4.TBlock2.Rule_struct_arg_positional2","sum":163},{"parent":"TRule_table_hint.TAlt3.TBlock4.TBlock2","rule":"TRule_table_hint.TAlt3.TBlock4.TBlock2.Token1","sum":163},{"parent":"TRule_table_hints","rule":"TRule_table_hints.Block2","sum":162764877},{"parent":"TRule_table_hints","rule":"TRule_table_hints.Token1","sum":162764877},{"parent":"TRule_table_hints.TBlock2","rule":"TRule_table_hints.TBlock2.Alt1","sum":152231871},{"parent":"TRule_table_hints.TBlock2","rule":"TRule_table_hints.TBlock2.Alt2","sum":10533006},{"parent":"TRule_table_hints.TBlock2.TAlt1","rule":"TRule_table_hints.TBlock2.TAlt1.Rule_table_hint1","sum":152231871},{"parent":"TRule_table_hints.TBlock2.TAlt2","rule":"TRule_table_hints.TBlock2.TAlt2.Block3","sum":10261707},{"parent":"TRule_table_hints.TBlock2.TAlt2","rule":"TRule_table_hints.TBlock2.TAlt2.Rule_table_hint2","sum":10533006},{"parent":"TRule_table_hints.TBlock2.TAlt2","rule":"TRule_table_hints.TBlock2.TAlt2.Token1","sum":10533006},{"parent":"TRule_table_hints.TBlock2.TAlt2","rule":"TRule_table_hints.TBlock2.TAlt2.Token4","sum":10533006},{"parent":"TRule_table_hints.TBlock2.TAlt2.TBlock3","rule":"TRule_table_hints.TBlock2.TAlt2.TBlock3.Rule_table_hint2","sum":10662249},{"parent":"TRule_table_hints.TBlock2.TAlt2.TBlock3","rule":"TRule_table_hints.TBlock2.TAlt2.TBlock3.Token1","sum":10662249},{"parent":"TRule_table_key","rule":"TRule_table_key.Block2","sum":865837},{"parent":"TRule_table_key","rule":"TRule_table_key.Rule_id_table_or_type1","sum":330894125},{"parent":"TRule_table_key.TBlock2","rule":"TRule_table_key.TBlock2.Rule_view_name2","sum":865837},{"parent":"TRule_table_key.TBlock2","rule":"TRule_table_key.TBlock2.Token1","sum":865837},{"parent":"TRule_table_ref","rule":"TRule_table_ref.Block1","sum":39960071},{"parent":"TRule_table_ref","rule":"TRule_table_ref.Block2","sum":6035888},{"parent":"TRule_table_ref","rule":"TRule_table_ref.Block3","sum":953815950},{"parent":"TRule_table_ref","rule":"TRule_table_ref.Block4","sum":19664257},{"parent":"TRule_table_ref.TBlock1","rule":"TRule_table_ref.TBlock1.Rule_cluster_expr1","sum":39960071},{"parent":"TRule_table_ref.TBlock1","rule":"TRule_table_ref.TBlock1.Token2","sum":39960071},{"parent":"TRule_table_ref.TBlock2","rule":"TRule_table_ref.TBlock2.Token1","sum":6035888},{"parent":"TRule_table_ref.TBlock3","rule":"TRule_table_ref.TBlock3.Alt1","sum":330894125},{"parent":"TRule_table_ref.TBlock3","rule":"TRule_table_ref.TBlock3.Alt2","sum":96313621},{"parent":"TRule_table_ref.TBlock3","rule":"TRule_table_ref.TBlock3.Alt3","sum":526608204},{"parent":"TRule_table_ref.TBlock3.TAlt1","rule":"TRule_table_ref.TBlock3.TAlt1.Rule_table_key1","sum":330894125},{"parent":"TRule_table_ref.TBlock3.TAlt2","rule":"TRule_table_ref.TBlock3.TAlt2.Block3","sum":96313596},{"parent":"TRule_table_ref.TBlock3.TAlt2","rule":"TRule_table_ref.TBlock3.TAlt2.Rule_an_id_expr1","sum":96313621},{"parent":"TRule_table_ref.TBlock3.TAlt2","rule":"TRule_table_ref.TBlock3.TAlt2.Token2","sum":96313621},{"parent":"TRule_table_ref.TBlock3.TAlt2","rule":"TRule_table_ref.TBlock3.TAlt2.Token4","sum":96313621},{"parent":"TRule_table_ref.TBlock3.TAlt2.TBlock3","rule":"TRule_table_ref.TBlock3.TAlt2.TBlock3.Block2","sum":49697568},{"parent":"TRule_table_ref.TBlock3.TAlt2.TBlock3","rule":"TRule_table_ref.TBlock3.TAlt2.TBlock3.Block3","sum":356769},{"parent":"TRule_table_ref.TBlock3.TAlt2.TBlock3","rule":"TRule_table_ref.TBlock3.TAlt2.TBlock3.Rule_table_arg1","sum":96313596},{"parent":"TRule_table_ref.TBlock3.TAlt2.TBlock3.TBlock2","rule":"TRule_table_ref.TBlock3.TAlt2.TBlock3.TBlock2.Rule_table_arg2","sum":96175608},{"parent":"TRule_table_ref.TBlock3.TAlt2.TBlock3.TBlock2","rule":"TRule_table_ref.TBlock3.TAlt2.TBlock3.TBlock2.Token1","sum":96175608},{"parent":"TRule_table_ref.TBlock3.TAlt2.TBlock3.TBlock3","rule":"TRule_table_ref.TBlock3.TAlt2.TBlock3.TBlock3.Token1","sum":356769},{"parent":"TRule_table_ref.TBlock3.TAlt3","rule":"TRule_table_ref.TBlock3.TAlt3.Block2","sum":22294386},{"parent":"TRule_table_ref.TBlock3.TAlt3","rule":"TRule_table_ref.TBlock3.TAlt3.Block3","sum":177575},{"parent":"TRule_table_ref.TBlock3.TAlt3","rule":"TRule_table_ref.TBlock3.TAlt3.Rule_bind_parameter1","sum":526608204},{"parent":"TRule_table_ref.TBlock3.TAlt3.TBlock2","rule":"TRule_table_ref.TBlock3.TAlt3.TBlock2.Block2","sum":15925824},{"parent":"TRule_table_ref.TBlock3.TAlt3.TBlock2","rule":"TRule_table_ref.TBlock3.TAlt3.TBlock2.Token1","sum":22294386},{"parent":"TRule_table_ref.TBlock3.TAlt3.TBlock2","rule":"TRule_table_ref.TBlock3.TAlt3.TBlock2.Token3","sum":22294386},{"parent":"TRule_table_ref.TBlock3.TAlt3.TBlock2.TBlock2","rule":"TRule_table_ref.TBlock3.TAlt3.TBlock2.TBlock2.Rule_expr_list1","sum":15925824},{"parent":"TRule_table_ref.TBlock3.TAlt3.TBlock3","rule":"TRule_table_ref.TBlock3.TAlt3.TBlock3.Rule_view_name2","sum":177575},{"parent":"TRule_table_ref.TBlock3.TAlt3.TBlock3","rule":"TRule_table_ref.TBlock3.TAlt3.TBlock3.Token1","sum":177575},{"parent":"TRule_table_ref.TBlock4","rule":"TRule_table_ref.TBlock4.Rule_table_hints1","sum":19664257},{"parent":"TRule_tablesample_clause","rule":"TRule_tablesample_clause.Block6","sum":9298},{"parent":"TRule_tablesample_clause","rule":"TRule_tablesample_clause.Rule_expr4","sum":328834},{"parent":"TRule_tablesample_clause","rule":"TRule_tablesample_clause.Rule_sampling_mode2","sum":328834},{"parent":"TRule_tablesample_clause","rule":"TRule_tablesample_clause.Token1","sum":328834},{"parent":"TRule_tablesample_clause","rule":"TRule_tablesample_clause.Token3","sum":328834},{"parent":"TRule_tablesample_clause","rule":"TRule_tablesample_clause.Token5","sum":328834},{"parent":"TRule_tablesample_clause.TBlock6","rule":"TRule_tablesample_clause.TBlock6.Rule_repeatable_clause1","sum":9298},{"parent":"TRule_type_id","rule":"TRule_type_id.Token1","sum":11675767},{"parent":"TRule_type_name","rule":"TRule_type_name.Alt_type_name1","sum":89405041},{"parent":"TRule_type_name","rule":"TRule_type_name.Alt_type_name2","sum":703793148},{"parent":"TRule_type_name.TAlt1","rule":"TRule_type_name.TAlt1.Rule_type_name_composite1","sum":89405041},{"parent":"TRule_type_name.TAlt2","rule":"TRule_type_name.TAlt2.Block1","sum":703793148},{"parent":"TRule_type_name.TAlt2","rule":"TRule_type_name.TAlt2.Block2","sum":73563154},{"parent":"TRule_type_name.TAlt2.TBlock1","rule":"TRule_type_name.TAlt2.TBlock1.Alt1","sum":27853302},{"parent":"TRule_type_name.TAlt2.TBlock1","rule":"TRule_type_name.TAlt2.TBlock1.Alt2","sum":675939846},{"parent":"TRule_type_name.TAlt2.TBlock1.TAlt1","rule":"TRule_type_name.TAlt2.TBlock1.TAlt1.Rule_type_name_decimal1","sum":27853302},{"parent":"TRule_type_name.TAlt2.TBlock1.TAlt2","rule":"TRule_type_name.TAlt2.TBlock1.TAlt2.Rule_type_name_simple1","sum":675939846},{"parent":"TRule_type_name.TAlt2.TBlock2","rule":"TRule_type_name.TAlt2.TBlock2.Token1","sum":73564194},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Block4","sum":9767728},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Block5","sum":223950},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Block6","sum":10435},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Rule_type_name_or_bind9","sum":10094706},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Token1","sum":10094706},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Token10","sum":10094706},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Token2","sum":10094706},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Token3","sum":10094706},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Token7","sum":10094706},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Token8","sum":10094706},{"parent":"TRule_type_name_callable.TBlock4","rule":"TRule_type_name_callable.TBlock4.Rule_callable_arg_list1","sum":9767728},{"parent":"TRule_type_name_callable.TBlock5","rule":"TRule_type_name_callable.TBlock5.Token1","sum":223950},{"parent":"TRule_type_name_callable.TBlock6","rule":"TRule_type_name_callable.TBlock6.Rule_callable_arg_list2","sum":10435},{"parent":"TRule_type_name_callable.TBlock6","rule":"TRule_type_name_callable.TBlock6.Token1","sum":10435},{"parent":"TRule_type_name_callable.TBlock6","rule":"TRule_type_name_callable.TBlock6.Token3","sum":10435},{"parent":"TRule_type_name_composite","rule":"TRule_type_name_composite.Block1","sum":106795007},{"parent":"TRule_type_name_composite","rule":"TRule_type_name_composite.Block2","sum":4248366},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt1","sum":33266966},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt10","sum":20441},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt11","sum":456370},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt12","sum":7763},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt13","sum":10094706},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt2","sum":2160207},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt3","sum":26683306},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt4","sum":136902},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt5","sum":25785440},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt6","sum":1522146},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt8","sum":6647417},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt9","sum":13343},{"parent":"TRule_type_name_composite.TBlock1.TAlt1","rule":"TRule_type_name_composite.TBlock1.TAlt1.Rule_type_name_optional1","sum":33266966},{"parent":"TRule_type_name_composite.TBlock1.TAlt10","rule":"TRule_type_name_composite.TBlock1.TAlt10.Rule_type_name_enum1","sum":20441},{"parent":"TRule_type_name_composite.TBlock1.TAlt11","rule":"TRule_type_name_composite.TBlock1.TAlt11.Rule_type_name_resource1","sum":456370},{"parent":"TRule_type_name_composite.TBlock1.TAlt12","rule":"TRule_type_name_composite.TBlock1.TAlt12.Rule_type_name_tagged1","sum":7763},{"parent":"TRule_type_name_composite.TBlock1.TAlt13","rule":"TRule_type_name_composite.TBlock1.TAlt13.Rule_type_name_callable1","sum":10094706},{"parent":"TRule_type_name_composite.TBlock1.TAlt2","rule":"TRule_type_name_composite.TBlock1.TAlt2.Rule_type_name_tuple1","sum":2160207},{"parent":"TRule_type_name_composite.TBlock1.TAlt3","rule":"TRule_type_name_composite.TBlock1.TAlt3.Rule_type_name_struct1","sum":26683306},{"parent":"TRule_type_name_composite.TBlock1.TAlt4","rule":"TRule_type_name_composite.TBlock1.TAlt4.Rule_type_name_variant1","sum":136902},{"parent":"TRule_type_name_composite.TBlock1.TAlt5","rule":"TRule_type_name_composite.TBlock1.TAlt5.Rule_type_name_list1","sum":25785440},{"parent":"TRule_type_name_composite.TBlock1.TAlt6","rule":"TRule_type_name_composite.TBlock1.TAlt6.Rule_type_name_stream1","sum":1522146},{"parent":"TRule_type_name_composite.TBlock1.TAlt8","rule":"TRule_type_name_composite.TBlock1.TAlt8.Rule_type_name_dict1","sum":6647417},{"parent":"TRule_type_name_composite.TBlock1.TAlt9","rule":"TRule_type_name_composite.TBlock1.TAlt9.Rule_type_name_set1","sum":13343},{"parent":"TRule_type_name_composite.TBlock2","rule":"TRule_type_name_composite.TBlock2.Token1","sum":4248369},{"parent":"TRule_type_name_decimal","rule":"TRule_type_name_decimal.Rule_integer_or_bind3","sum":27853302},{"parent":"TRule_type_name_decimal","rule":"TRule_type_name_decimal.Rule_integer_or_bind5","sum":27853302},{"parent":"TRule_type_name_decimal","rule":"TRule_type_name_decimal.Token1","sum":27853302},{"parent":"TRule_type_name_decimal","rule":"TRule_type_name_decimal.Token2","sum":27853302},{"parent":"TRule_type_name_decimal","rule":"TRule_type_name_decimal.Token4","sum":27853302},{"parent":"TRule_type_name_decimal","rule":"TRule_type_name_decimal.Token6","sum":27853302},{"parent":"TRule_type_name_dict","rule":"TRule_type_name_dict.Rule_type_name_or_bind3","sum":6647417},{"parent":"TRule_type_name_dict","rule":"TRule_type_name_dict.Rule_type_name_or_bind5","sum":6647417},{"parent":"TRule_type_name_dict","rule":"TRule_type_name_dict.Token1","sum":6647417},{"parent":"TRule_type_name_dict","rule":"TRule_type_name_dict.Token2","sum":6647417},{"parent":"TRule_type_name_dict","rule":"TRule_type_name_dict.Token4","sum":6647417},{"parent":"TRule_type_name_dict","rule":"TRule_type_name_dict.Token6","sum":6647417},{"parent":"TRule_type_name_enum","rule":"TRule_type_name_enum.Block4","sum":20193},{"parent":"TRule_type_name_enum","rule":"TRule_type_name_enum.Block5","sum":377},{"parent":"TRule_type_name_enum","rule":"TRule_type_name_enum.Rule_type_name_tag3","sum":20441},{"parent":"TRule_type_name_enum","rule":"TRule_type_name_enum.Token1","sum":20441},{"parent":"TRule_type_name_enum","rule":"TRule_type_name_enum.Token2","sum":20441},{"parent":"TRule_type_name_enum","rule":"TRule_type_name_enum.Token6","sum":20441},{"parent":"TRule_type_name_enum.TBlock4","rule":"TRule_type_name_enum.TBlock4.Rule_type_name_tag2","sum":43975},{"parent":"TRule_type_name_enum.TBlock4","rule":"TRule_type_name_enum.TBlock4.Token1","sum":43975},{"parent":"TRule_type_name_enum.TBlock5","rule":"TRule_type_name_enum.TBlock5.Token1","sum":377},{"parent":"TRule_type_name_list","rule":"TRule_type_name_list.Rule_type_name_or_bind3","sum":25785440},{"parent":"TRule_type_name_list","rule":"TRule_type_name_list.Token1","sum":25785440},{"parent":"TRule_type_name_list","rule":"TRule_type_name_list.Token2","sum":25785440},{"parent":"TRule_type_name_list","rule":"TRule_type_name_list.Token4","sum":25785440},{"parent":"TRule_type_name_optional","rule":"TRule_type_name_optional.Rule_type_name_or_bind3","sum":33266966},{"parent":"TRule_type_name_optional","rule":"TRule_type_name_optional.Token1","sum":33266966},{"parent":"TRule_type_name_optional","rule":"TRule_type_name_optional.Token2","sum":33266966},{"parent":"TRule_type_name_optional","rule":"TRule_type_name_optional.Token4","sum":33266966},{"parent":"TRule_type_name_or_bind","rule":"TRule_type_name_or_bind.Alt_type_name_or_bind1","sum":636709496},{"parent":"TRule_type_name_or_bind","rule":"TRule_type_name_or_bind.Alt_type_name_or_bind2","sum":2676185},{"parent":"TRule_type_name_or_bind.TAlt1","rule":"TRule_type_name_or_bind.TAlt1.Rule_type_name1","sum":636709496},{"parent":"TRule_type_name_or_bind.TAlt2","rule":"TRule_type_name_or_bind.TAlt2.Rule_bind_parameter1","sum":2676185},{"parent":"TRule_type_name_resource","rule":"TRule_type_name_resource.Rule_type_name_tag3","sum":456370},{"parent":"TRule_type_name_resource","rule":"TRule_type_name_resource.Token1","sum":456370},{"parent":"TRule_type_name_resource","rule":"TRule_type_name_resource.Token2","sum":456370},{"parent":"TRule_type_name_resource","rule":"TRule_type_name_resource.Token4","sum":456370},{"parent":"TRule_type_name_set","rule":"TRule_type_name_set.Rule_type_name_or_bind3","sum":13343},{"parent":"TRule_type_name_set","rule":"TRule_type_name_set.Token1","sum":13343},{"parent":"TRule_type_name_set","rule":"TRule_type_name_set.Token2","sum":13343},{"parent":"TRule_type_name_set","rule":"TRule_type_name_set.Token4","sum":13343},{"parent":"TRule_type_name_simple","rule":"TRule_type_name_simple.Rule_an_id_pure1","sum":677783605},{"parent":"TRule_type_name_stream","rule":"TRule_type_name_stream.Rule_type_name_or_bind3","sum":1522146},{"parent":"TRule_type_name_stream","rule":"TRule_type_name_stream.Token1","sum":1522146},{"parent":"TRule_type_name_stream","rule":"TRule_type_name_stream.Token2","sum":1522146},{"parent":"TRule_type_name_stream","rule":"TRule_type_name_stream.Token4","sum":1522146},{"parent":"TRule_type_name_struct","rule":"TRule_type_name_struct.Block2","sum":26683306},{"parent":"TRule_type_name_struct","rule":"TRule_type_name_struct.Token1","sum":26683306},{"parent":"TRule_type_name_struct.TBlock2","rule":"TRule_type_name_struct.TBlock2.Alt1","sum":26680414},{"parent":"TRule_type_name_struct.TBlock2","rule":"TRule_type_name_struct.TBlock2.Alt2","sum":2892},{"parent":"TRule_type_name_struct.TBlock2.TAlt1","rule":"TRule_type_name_struct.TBlock2.TAlt1.Block2","sum":26680404},{"parent":"TRule_type_name_struct.TBlock2.TAlt1","rule":"TRule_type_name_struct.TBlock2.TAlt1.Token1","sum":26680414},{"parent":"TRule_type_name_struct.TBlock2.TAlt1","rule":"TRule_type_name_struct.TBlock2.TAlt1.Token3","sum":26680414},{"parent":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2","rule":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.Block2","sum":20364033},{"parent":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2","rule":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.Block3","sum":2056555},{"parent":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2","rule":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.Rule_struct_arg1","sum":26680404},{"parent":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.TBlock2","rule":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.TBlock2.Rule_struct_arg2","sum":87331120},{"parent":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.TBlock2","rule":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.TBlock2.Token1","sum":87331120},{"parent":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.TBlock3","rule":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.TBlock3.Token1","sum":2056555},{"parent":"TRule_type_name_struct.TBlock2.TAlt2","rule":"TRule_type_name_struct.TBlock2.TAlt2.Token1","sum":2892},{"parent":"TRule_type_name_tag","rule":"TRule_type_name_tag.Alt_type_name_tag1","sum":104747425},{"parent":"TRule_type_name_tag","rule":"TRule_type_name_tag.Alt_type_name_tag2","sum":18282215},{"parent":"TRule_type_name_tag","rule":"TRule_type_name_tag.Alt_type_name_tag3","sum":2617886},{"parent":"TRule_type_name_tag.TAlt1","rule":"TRule_type_name_tag.TAlt1.Rule_id1","sum":104747425},{"parent":"TRule_type_name_tag.TAlt2","rule":"TRule_type_name_tag.TAlt2.Token1","sum":18282215},{"parent":"TRule_type_name_tag.TAlt3","rule":"TRule_type_name_tag.TAlt3.Rule_bind_parameter1","sum":2617886},{"parent":"TRule_type_name_tagged","rule":"TRule_type_name_tagged.Rule_type_name_or_bind3","sum":7763},{"parent":"TRule_type_name_tagged","rule":"TRule_type_name_tagged.Rule_type_name_tag5","sum":7763},{"parent":"TRule_type_name_tagged","rule":"TRule_type_name_tagged.Token1","sum":7763},{"parent":"TRule_type_name_tagged","rule":"TRule_type_name_tagged.Token2","sum":7763},{"parent":"TRule_type_name_tagged","rule":"TRule_type_name_tagged.Token4","sum":7763},{"parent":"TRule_type_name_tagged","rule":"TRule_type_name_tagged.Token6","sum":7763},{"parent":"TRule_type_name_tuple","rule":"TRule_type_name_tuple.Block2","sum":2160207},{"parent":"TRule_type_name_tuple","rule":"TRule_type_name_tuple.Token1","sum":2160207},{"parent":"TRule_type_name_tuple.TBlock2","rule":"TRule_type_name_tuple.TBlock2.Alt1","sum":2160197},{"parent":"TRule_type_name_tuple.TBlock2","rule":"TRule_type_name_tuple.TBlock2.Alt2","sum":10},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1","rule":"TRule_type_name_tuple.TBlock2.TAlt1.Block2","sum":2160197},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1","rule":"TRule_type_name_tuple.TBlock2.TAlt1.Token1","sum":2160197},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1","rule":"TRule_type_name_tuple.TBlock2.TAlt1.Token3","sum":2160197},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2","rule":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.Block2","sum":2158663},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2","rule":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.Block3","sum":63559},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2","rule":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.Rule_type_name_or_bind1","sum":2160197},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.TBlock2","rule":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.TBlock2.Rule_type_name_or_bind2","sum":3341642},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.TBlock2","rule":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.TBlock2.Token1","sum":3341642},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.TBlock3","rule":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.TBlock3.Token1","sum":63559},{"parent":"TRule_type_name_tuple.TBlock2.TAlt2","rule":"TRule_type_name_tuple.TBlock2.TAlt2.Token1","sum":10},{"parent":"TRule_type_name_variant","rule":"TRule_type_name_variant.Block4","sum":122313},{"parent":"TRule_type_name_variant","rule":"TRule_type_name_variant.Block5","sum":104},{"parent":"TRule_type_name_variant","rule":"TRule_type_name_variant.Rule_variant_arg3","sum":136902},{"parent":"TRule_type_name_variant","rule":"TRule_type_name_variant.Token1","sum":136902},{"parent":"TRule_type_name_variant","rule":"TRule_type_name_variant.Token2","sum":136902},{"parent":"TRule_type_name_variant","rule":"TRule_type_name_variant.Token6","sum":136902},{"parent":"TRule_type_name_variant.TBlock4","rule":"TRule_type_name_variant.TBlock4.Rule_variant_arg2","sum":233912},{"parent":"TRule_type_name_variant.TBlock4","rule":"TRule_type_name_variant.TBlock4.Token1","sum":233912},{"parent":"TRule_type_name_variant.TBlock5","rule":"TRule_type_name_variant.TBlock5.Token1","sum":104},{"parent":"TRule_unary_casual_subexpr","rule":"TRule_unary_casual_subexpr.Block1","sum":16016225286},{"parent":"TRule_unary_casual_subexpr","rule":"TRule_unary_casual_subexpr.Rule_unary_subexpr_suffix2","sum":16016225286},{"parent":"TRule_unary_casual_subexpr.TBlock1","rule":"TRule_unary_casual_subexpr.TBlock1.Alt1","sum":7183417944},{"parent":"TRule_unary_casual_subexpr.TBlock1","rule":"TRule_unary_casual_subexpr.TBlock1.Alt2","sum":8832807342},{"parent":"TRule_unary_casual_subexpr.TBlock1.TAlt1","rule":"TRule_unary_casual_subexpr.TBlock1.TAlt1.Rule_id_expr1","sum":7183417944},{"parent":"TRule_unary_casual_subexpr.TBlock1.TAlt2","rule":"TRule_unary_casual_subexpr.TBlock1.TAlt2.Rule_atom_expr1","sum":8832807342},{"parent":"TRule_unary_op","rule":"TRule_unary_op.Token1","sum":87770220},{"parent":"TRule_unary_subexpr","rule":"TRule_unary_subexpr.Alt_unary_subexpr1","sum":16016225286},{"parent":"TRule_unary_subexpr","rule":"TRule_unary_subexpr.Alt_unary_subexpr2","sum":6343644},{"parent":"TRule_unary_subexpr.TAlt1","rule":"TRule_unary_subexpr.TAlt1.Rule_unary_casual_subexpr1","sum":16016225286},{"parent":"TRule_unary_subexpr.TAlt2","rule":"TRule_unary_subexpr.TAlt2.Rule_json_api_expr1","sum":6343644},{"parent":"TRule_unary_subexpr_suffix","rule":"TRule_unary_subexpr_suffix.Block1","sum":4775126942},{"parent":"TRule_unary_subexpr_suffix.TBlock1","rule":"TRule_unary_subexpr_suffix.TBlock1.Block1","sum":5029718261},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.Alt1","sum":173531558},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.Alt2","sum":2876921781},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.Alt3","sum":1979264922},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt1","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt1.Rule_key_expr1","sum":173531558},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt2","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt2.Rule_invoke_expr1","sum":2876921781},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.Block2","sum":1979264922},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.Token1","sum":1979264922},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.Alt1","sum":3153885},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.Alt2","sum":40460282},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.Alt3","sum":1935650755},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.TAlt1","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.TAlt1.Rule_bind_parameter1","sum":3153885},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.TAlt2","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.TAlt2.Token1","sum":40460282},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.TAlt3","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.TAlt3.Rule_an_id_or_type1","sum":1935650755},{"parent":"TRule_use_stmt","rule":"TRule_use_stmt.Rule_cluster_expr2","sum":329672608},{"parent":"TRule_use_stmt","rule":"TRule_use_stmt.Token1","sum":329672608},{"parent":"TRule_using_call_expr","rule":"TRule_using_call_expr.Block1","sum":2771975},{"parent":"TRule_using_call_expr","rule":"TRule_using_call_expr.Rule_invoke_expr2","sum":2771975},{"parent":"TRule_using_call_expr.TBlock1","rule":"TRule_using_call_expr.TBlock1.Alt1","sum":1522435},{"parent":"TRule_using_call_expr.TBlock1","rule":"TRule_using_call_expr.TBlock1.Alt3","sum":1249540},{"parent":"TRule_using_call_expr.TBlock1.TAlt1","rule":"TRule_using_call_expr.TBlock1.TAlt1.Rule_an_id_or_type1","sum":1522435},{"parent":"TRule_using_call_expr.TBlock1.TAlt1","rule":"TRule_using_call_expr.TBlock1.TAlt1.Rule_an_id_or_type3","sum":1522435},{"parent":"TRule_using_call_expr.TBlock1.TAlt1","rule":"TRule_using_call_expr.TBlock1.TAlt1.Token2","sum":1522435},{"parent":"TRule_using_call_expr.TBlock1.TAlt3","rule":"TRule_using_call_expr.TBlock1.TAlt3.Rule_bind_parameter1","sum":1249540},{"parent":"TRule_value_constructor","rule":"TRule_value_constructor.Alt_value_constructor1","sum":32087},{"parent":"TRule_value_constructor","rule":"TRule_value_constructor.Alt_value_constructor2","sum":51190},{"parent":"TRule_value_constructor","rule":"TRule_value_constructor.Alt_value_constructor3","sum":80795},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Rule_expr3","sum":32087},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Rule_expr5","sum":32087},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Rule_expr7","sum":32087},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Token1","sum":32087},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Token2","sum":32087},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Token4","sum":32087},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Token6","sum":32087},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Token8","sum":32087},{"parent":"TRule_value_constructor.TAlt2","rule":"TRule_value_constructor.TAlt2.Rule_expr3","sum":51190},{"parent":"TRule_value_constructor.TAlt2","rule":"TRule_value_constructor.TAlt2.Rule_expr5","sum":51190},{"parent":"TRule_value_constructor.TAlt2","rule":"TRule_value_constructor.TAlt2.Token1","sum":51190},{"parent":"TRule_value_constructor.TAlt2","rule":"TRule_value_constructor.TAlt2.Token2","sum":51190},{"parent":"TRule_value_constructor.TAlt2","rule":"TRule_value_constructor.TAlt2.Token4","sum":51190},{"parent":"TRule_value_constructor.TAlt2","rule":"TRule_value_constructor.TAlt2.Token6","sum":51190},{"parent":"TRule_value_constructor.TAlt3","rule":"TRule_value_constructor.TAlt3.Rule_expr3","sum":80795},{"parent":"TRule_value_constructor.TAlt3","rule":"TRule_value_constructor.TAlt3.Rule_expr5","sum":80795},{"parent":"TRule_value_constructor.TAlt3","rule":"TRule_value_constructor.TAlt3.Token1","sum":80795},{"parent":"TRule_value_constructor.TAlt3","rule":"TRule_value_constructor.TAlt3.Token2","sum":80795},{"parent":"TRule_value_constructor.TAlt3","rule":"TRule_value_constructor.TAlt3.Token4","sum":80795},{"parent":"TRule_value_constructor.TAlt3","rule":"TRule_value_constructor.TAlt3.Token6","sum":80795},{"parent":"TRule_values_source","rule":"TRule_values_source.Alt_values_source1","sum":1086488},{"parent":"TRule_values_source","rule":"TRule_values_source.Alt_values_source2","sum":208004664},{"parent":"TRule_values_source.TAlt1","rule":"TRule_values_source.TAlt1.Rule_values_stmt1","sum":1086488},{"parent":"TRule_values_source.TAlt2","rule":"TRule_values_source.TAlt2.Rule_select_stmt1","sum":208004664},{"parent":"TRule_values_source_row","rule":"TRule_values_source_row.Rule_expr_list2","sum":9061158},{"parent":"TRule_values_source_row","rule":"TRule_values_source_row.Token1","sum":9061158},{"parent":"TRule_values_source_row","rule":"TRule_values_source_row.Token3","sum":9061158},{"parent":"TRule_values_source_row_list","rule":"TRule_values_source_row_list.Block2","sum":486892},{"parent":"TRule_values_source_row_list","rule":"TRule_values_source_row_list.Rule_values_source_row1","sum":1255365},{"parent":"TRule_values_source_row_list.TBlock2","rule":"TRule_values_source_row_list.TBlock2.Rule_values_source_row2","sum":7805793},{"parent":"TRule_values_source_row_list.TBlock2","rule":"TRule_values_source_row_list.TBlock2.Token1","sum":7805793},{"parent":"TRule_values_stmt","rule":"TRule_values_stmt.Rule_values_source_row_list2","sum":1255365},{"parent":"TRule_values_stmt","rule":"TRule_values_stmt.Token1","sum":1255365},{"parent":"TRule_variant_arg","rule":"TRule_variant_arg.Block1","sum":356537},{"parent":"TRule_variant_arg","rule":"TRule_variant_arg.Rule_type_name_or_bind2","sum":18367191},{"parent":"TRule_variant_arg.TBlock1","rule":"TRule_variant_arg.TBlock1.Rule_type_name_tag1","sum":356537},{"parent":"TRule_variant_arg.TBlock1","rule":"TRule_variant_arg.TBlock1.Token2","sum":356537},{"parent":"TRule_view_name","rule":"TRule_view_name.Alt_view_name1","sum":1309369},{"parent":"TRule_view_name.TAlt1","rule":"TRule_view_name.TAlt1.Rule_an_id1","sum":1309369},{"parent":"TRule_when_expr","rule":"TRule_when_expr.Rule_expr2","sum":158362267},{"parent":"TRule_when_expr","rule":"TRule_when_expr.Rule_expr4","sum":158362267},{"parent":"TRule_when_expr","rule":"TRule_when_expr.Token1","sum":158362267},{"parent":"TRule_when_expr","rule":"TRule_when_expr.Token3","sum":158362267},{"parent":"TRule_window_clause","rule":"TRule_window_clause.Rule_window_definition_list2","sum":13593427},{"parent":"TRule_window_clause","rule":"TRule_window_clause.Token1","sum":13593427},{"parent":"TRule_window_definition","rule":"TRule_window_definition.Rule_new_window_name1","sum":14168963},{"parent":"TRule_window_definition","rule":"TRule_window_definition.Rule_window_specification3","sum":14168963},{"parent":"TRule_window_definition","rule":"TRule_window_definition.Token2","sum":14168963},{"parent":"TRule_window_definition_list","rule":"TRule_window_definition_list.Block2","sum":435449},{"parent":"TRule_window_definition_list","rule":"TRule_window_definition_list.Rule_window_definition1","sum":13593427},{"parent":"TRule_window_definition_list.TBlock2","rule":"TRule_window_definition_list.TBlock2.Rule_window_definition2","sum":575536},{"parent":"TRule_window_definition_list.TBlock2","rule":"TRule_window_definition_list.TBlock2.Token1","sum":575536},{"parent":"TRule_window_frame_between","rule":"TRule_window_frame_between.Rule_window_frame_bound2","sum":2317924},{"parent":"TRule_window_frame_between","rule":"TRule_window_frame_between.Rule_window_frame_bound4","sum":2317924},{"parent":"TRule_window_frame_between","rule":"TRule_window_frame_between.Token1","sum":2317924},{"parent":"TRule_window_frame_between","rule":"TRule_window_frame_between.Token3","sum":2317924},{"parent":"TRule_window_frame_bound","rule":"TRule_window_frame_bound.Alt_window_frame_bound1","sum":1326003},{"parent":"TRule_window_frame_bound","rule":"TRule_window_frame_bound.Alt_window_frame_bound2","sum":3367748},{"parent":"TRule_window_frame_bound.TAlt1","rule":"TRule_window_frame_bound.TAlt1.Token1","sum":1326003},{"parent":"TRule_window_frame_bound.TAlt1","rule":"TRule_window_frame_bound.TAlt1.Token2","sum":1326003},{"parent":"TRule_window_frame_bound.TAlt2","rule":"TRule_window_frame_bound.TAlt2.Block1","sum":3367748},{"parent":"TRule_window_frame_bound.TAlt2","rule":"TRule_window_frame_bound.TAlt2.Token2","sum":3367748},{"parent":"TRule_window_frame_bound.TAlt2.TBlock1","rule":"TRule_window_frame_bound.TAlt2.TBlock1.Alt1","sum":1114481},{"parent":"TRule_window_frame_bound.TAlt2.TBlock1","rule":"TRule_window_frame_bound.TAlt2.TBlock1.Alt2","sum":2253267},{"parent":"TRule_window_frame_bound.TAlt2.TBlock1.TAlt1","rule":"TRule_window_frame_bound.TAlt2.TBlock1.TAlt1.Rule_expr1","sum":1114481},{"parent":"TRule_window_frame_bound.TAlt2.TBlock1.TAlt2","rule":"TRule_window_frame_bound.TAlt2.TBlock1.TAlt2.Token1","sum":2253267},{"parent":"TRule_window_frame_clause","rule":"TRule_window_frame_clause.Rule_window_frame_extent2","sum":2375827},{"parent":"TRule_window_frame_clause","rule":"TRule_window_frame_clause.Rule_window_frame_units1","sum":2375827},{"parent":"TRule_window_frame_extent","rule":"TRule_window_frame_extent.Alt_window_frame_extent1","sum":57903},{"parent":"TRule_window_frame_extent","rule":"TRule_window_frame_extent.Alt_window_frame_extent2","sum":2317924},{"parent":"TRule_window_frame_extent.TAlt1","rule":"TRule_window_frame_extent.TAlt1.Rule_window_frame_bound1","sum":57903},{"parent":"TRule_window_frame_extent.TAlt2","rule":"TRule_window_frame_extent.TAlt2.Rule_window_frame_between1","sum":2317924},{"parent":"TRule_window_frame_units","rule":"TRule_window_frame_units.Token1","sum":2375827},{"parent":"TRule_window_name","rule":"TRule_window_name.Rule_an_id_window1","sum":46670411},{"parent":"TRule_window_name_or_specification","rule":"TRule_window_name_or_specification.Alt_window_name_or_specification1","sum":32501448},{"parent":"TRule_window_name_or_specification","rule":"TRule_window_name_or_specification.Alt_window_name_or_specification2","sum":12841339},{"parent":"TRule_window_name_or_specification.TAlt1","rule":"TRule_window_name_or_specification.TAlt1.Rule_window_name1","sum":32501448},{"parent":"TRule_window_name_or_specification.TAlt2","rule":"TRule_window_name_or_specification.TAlt2.Rule_window_specification1","sum":12841339},{"parent":"TRule_window_order_clause","rule":"TRule_window_order_clause.Rule_order_by_clause1","sum":19022200},{"parent":"TRule_window_partition_clause","rule":"TRule_window_partition_clause.Block2","sum":51775},{"parent":"TRule_window_partition_clause","rule":"TRule_window_partition_clause.Rule_named_expr_list4","sum":21811809},{"parent":"TRule_window_partition_clause","rule":"TRule_window_partition_clause.Token1","sum":21811809},{"parent":"TRule_window_partition_clause","rule":"TRule_window_partition_clause.Token3","sum":21811809},{"parent":"TRule_window_partition_clause.TBlock2","rule":"TRule_window_partition_clause.TBlock2.Token1","sum":51775},{"parent":"TRule_window_specification","rule":"TRule_window_specification.Rule_window_specification_details2","sum":27010302},{"parent":"TRule_window_specification","rule":"TRule_window_specification.Token1","sum":27010302},{"parent":"TRule_window_specification","rule":"TRule_window_specification.Token3","sum":27010302},{"parent":"TRule_window_specification_details","rule":"TRule_window_specification_details.Block2","sum":21811808},{"parent":"TRule_window_specification_details","rule":"TRule_window_specification_details.Block3","sum":19022200},{"parent":"TRule_window_specification_details","rule":"TRule_window_specification_details.Block4","sum":2375827},{"parent":"TRule_window_specification_details.TBlock2","rule":"TRule_window_specification_details.TBlock2.Rule_window_partition_clause1","sum":21811808},{"parent":"TRule_window_specification_details.TBlock3","rule":"TRule_window_specification_details.TBlock3.Rule_window_order_clause1","sum":19022200},{"parent":"TRule_window_specification_details.TBlock4","rule":"TRule_window_specification_details.TBlock4.Rule_window_frame_clause1","sum":2375827},{"parent":"TRule_without_column_list","rule":"TRule_without_column_list.Block2","sum":9212455},{"parent":"TRule_without_column_list","rule":"TRule_without_column_list.Block3","sum":1313805},{"parent":"TRule_without_column_list","rule":"TRule_without_column_list.Rule_without_column_name1","sum":24912265},{"parent":"TRule_without_column_list.TBlock2","rule":"TRule_without_column_list.TBlock2.Rule_without_column_name2","sum":29254680},{"parent":"TRule_without_column_list.TBlock2","rule":"TRule_without_column_list.TBlock2.Token1","sum":29254680},{"parent":"TRule_without_column_list.TBlock3","rule":"TRule_without_column_list.TBlock3.Token1","sum":1313805},{"parent":"TRule_without_column_name","rule":"TRule_without_column_name.Alt_without_column_name1","sum":30862610},{"parent":"TRule_without_column_name","rule":"TRule_without_column_name.Alt_without_column_name2","sum":23304335},{"parent":"TRule_without_column_name.TAlt1","rule":"TRule_without_column_name.TAlt1.Rule_an_id1","sum":30862610},{"parent":"TRule_without_column_name.TAlt1","rule":"TRule_without_column_name.TAlt1.Rule_an_id3","sum":30862610},{"parent":"TRule_without_column_name.TAlt1","rule":"TRule_without_column_name.TAlt1.Token2","sum":30862610},{"parent":"TRule_without_column_name.TAlt2","rule":"TRule_without_column_name.TAlt2.Rule_an_id_without1","sum":23304335},{"parent":"TRule_xor_subexpr","rule":"TRule_xor_subexpr.Block2","sum":1096201223},{"parent":"TRule_xor_subexpr","rule":"TRule_xor_subexpr.Rule_eq_subexpr1","sum":14287247191},{"parent":"TRule_xor_subexpr.TBlock2","rule":"TRule_xor_subexpr.TBlock2.Rule_cond_expr1","sum":1096201223},{"parent":"TSQLv1ParserAST","rule":"TSQLv1ParserAST.Rule_sql_query","sum":320376481},{"parent":"TYPE","rule":"BIGINT","sum":6966},{"parent":"TYPE","rule":"BOOL","sum":109222},{"parent":"TYPE","rule":"BYTEs","sum":1},{"parent":"TYPE","rule":"BigInt","sum":210},{"parent":"TYPE","rule":"Bool","sum":9307137},{"parent":"TYPE","rule":"Bytes","sum":422554},{"parent":"TYPE","rule":"DATE","sum":1255109},{"parent":"TYPE","rule":"DATETIME","sum":66830},{"parent":"TYPE","rule":"DATETime","sum":2},{"parent":"TYPE","rule":"DATEtIME","sum":1},{"parent":"TYPE","rule":"DATEtime","sum":34},{"parent":"TYPE","rule":"DAte","sum":9228},{"parent":"TYPE","rule":"DAteTime","sum":54},{"parent":"TYPE","rule":"DAtetime","sum":662},{"parent":"TYPE","rule":"DOUBLE","sum":1353329},{"parent":"TYPE","rule":"DOUBLe","sum":1},{"parent":"TYPE","rule":"DOUBle","sum":1},{"parent":"TYPE","rule":"DOUble","sum":3},{"parent":"TYPE","rule":"DOuble","sum":2152},{"parent":"TYPE","rule":"DaTeTime","sum":1},{"parent":"TYPE","rule":"Date","sum":20644045},{"parent":"TYPE","rule":"Date32","sum":64},{"parent":"TYPE","rule":"DateTIME","sum":19},{"parent":"TYPE","rule":"DateTIme","sum":112},{"parent":"TYPE","rule":"DateTime","sum":5002254},{"parent":"TYPE","rule":"DateTime64","sum":8},{"parent":"TYPE","rule":"DatetIME","sum":35},{"parent":"TYPE","rule":"Datetime","sum":3255820},{"parent":"TYPE","rule":"Datetime64","sum":37},{"parent":"TYPE","rule":"DoubLe","sum":13},{"parent":"TYPE","rule":"Double","sum":30117756},{"parent":"TYPE","rule":"EmptyDict","sum":28},{"parent":"TYPE","rule":"EmptyList","sum":28},{"parent":"TYPE","rule":"FLOAT","sum":191305},{"parent":"TYPE","rule":"FLoat","sum":3421},{"parent":"TYPE","rule":"FlOAT","sum":15},{"parent":"TYPE","rule":"FloaT","sum":326},{"parent":"TYPE","rule":"Float","sum":7088128},{"parent":"TYPE","rule":"Generic","sum":3},{"parent":"TYPE","rule":"INT","sum":418522},{"parent":"TYPE","rule":"INT16","sum":9450},{"parent":"TYPE","rule":"INT32","sum":140314},{"parent":"TYPE","rule":"INT64","sum":4150130},{"parent":"TYPE","rule":"INT8","sum":1830},{"parent":"TYPE","rule":"INTEGER","sum":73403},{"parent":"TYPE","rule":"INTERVAL","sum":10615},{"parent":"TYPE","rule":"INt16","sum":1},{"parent":"TYPE","rule":"INt32","sum":1179},{"parent":"TYPE","rule":"INt64","sum":38184},{"parent":"TYPE","rule":"InT32","sum":1},{"parent":"TYPE","rule":"Int","sum":523543},{"parent":"TYPE","rule":"Int16","sum":908526},{"parent":"TYPE","rule":"Int32","sum":13813761},{"parent":"TYPE","rule":"Int64","sum":47376804},{"parent":"TYPE","rule":"Int8","sum":1010275},{"parent":"TYPE","rule":"Integer","sum":468078},{"parent":"TYPE","rule":"Interval","sum":204821},{"parent":"TYPE","rule":"Interval64","sum":34},{"parent":"TYPE","rule":"JSON","sum":1738740},{"parent":"TYPE","rule":"JSONDocument","sum":257},{"parent":"TYPE","rule":"JSOn","sum":1},{"parent":"TYPE","rule":"JSon","sum":2},{"parent":"TYPE","rule":"Json","sum":5484795},{"parent":"TYPE","rule":"JsonDocument","sum":16958},{"parent":"TYPE","rule":"Jsondocument","sum":25},{"parent":"TYPE","rule":"PgBool","sum":20},{"parent":"TYPE","rule":"PgBox","sum":2},{"parent":"TYPE","rule":"PgByteA","sum":16},{"parent":"TYPE","rule":"PgCString","sum":19},{"parent":"TYPE","rule":"PgDate","sum":85},{"parent":"TYPE","rule":"PgFloat4","sum":31},{"parent":"TYPE","rule":"PgFloat8","sum":31},{"parent":"TYPE","rule":"PgInt","sum":1},{"parent":"TYPE","rule":"PgInt2","sum":97},{"parent":"TYPE","rule":"PgInt4","sum":37},{"parent":"TYPE","rule":"PgInt8","sum":32},{"parent":"TYPE","rule":"PgInterval","sum":238},{"parent":"TYPE","rule":"PgMoney","sum":2},{"parent":"TYPE","rule":"PgName","sum":2},{"parent":"TYPE","rule":"PgNumeric","sum":10},{"parent":"TYPE","rule":"PgPoint","sum":1279},{"parent":"TYPE","rule":"PgPolygon","sum":639},{"parent":"TYPE","rule":"PgText","sum":420},{"parent":"TYPE","rule":"PgTimestamp","sum":1885},{"parent":"TYPE","rule":"PgVarChar","sum":1},{"parent":"TYPE","rule":"PgVarchar","sum":231},{"parent":"TYPE","rule":"STRING","sum":2679012},{"parent":"TYPE","rule":"STRINg","sum":3},{"parent":"TYPE","rule":"STRing","sum":3},{"parent":"TYPE","rule":"STring","sum":1330},{"parent":"TYPE","rule":"StrINg","sum":45},{"parent":"TYPE","rule":"StrinG","sum":27},{"parent":"TYPE","rule":"String","sum":335343094},{"parent":"TYPE","rule":"TEXT","sum":20804},{"parent":"TYPE","rule":"TIMESTAMP","sum":316572},{"parent":"TYPE","rule":"TINYINT","sum":1},{"parent":"TYPE","rule":"TZDate","sum":30},{"parent":"TYPE","rule":"TZDateTime","sum":1},{"parent":"TYPE","rule":"TZDatetime","sum":25},{"parent":"TYPE","rule":"TZtimestamp","sum":1},{"parent":"TYPE","rule":"Text","sum":196975},{"parent":"TYPE","rule":"TimeStamp","sum":295674},{"parent":"TYPE","rule":"Timestamp","sum":5991764},{"parent":"TYPE","rule":"Timestamp64","sum":488},{"parent":"TYPE","rule":"TzDATE","sum":5},{"parent":"TYPE","rule":"TzDate","sum":48317},{"parent":"TYPE","rule":"TzDateTime","sum":43762},{"parent":"TYPE","rule":"TzDatetime","sum":672593},{"parent":"TYPE","rule":"TzTimeStamp","sum":6},{"parent":"TYPE","rule":"TzTimestamp","sum":8108},{"parent":"TYPE","rule":"TzTimestamp64","sum":1},{"parent":"TYPE","rule":"Tzdate","sum":5},{"parent":"TYPE","rule":"Tzdatetime","sum":4},{"parent":"TYPE","rule":"UINT16","sum":1236},{"parent":"TYPE","rule":"UINT32","sum":423872},{"parent":"TYPE","rule":"UINT64","sum":589596},{"parent":"TYPE","rule":"UINT8","sum":160},{"parent":"TYPE","rule":"UINt32","sum":44},{"parent":"TYPE","rule":"UINt64","sum":416},{"parent":"TYPE","rule":"UINt8","sum":24},{"parent":"TYPE","rule":"UInt16","sum":130050},{"parent":"TYPE","rule":"UInt32","sum":7336808},{"parent":"TYPE","rule":"UInt64","sum":9466348},{"parent":"TYPE","rule":"UInt8","sum":153035},{"parent":"TYPE","rule":"UNIT","sum":756},{"parent":"TYPE","rule":"UTF8","sum":268052},{"parent":"TYPE","rule":"UTf8","sum":144},{"parent":"TYPE","rule":"UUID","sum":1243345},{"parent":"TYPE","rule":"UiNt32","sum":4},{"parent":"TYPE","rule":"Uint16","sum":333960},{"parent":"TYPE","rule":"Uint32","sum":18494844},{"parent":"TYPE","rule":"Uint64","sum":32781958},{"parent":"TYPE","rule":"Uint8","sum":2330345},{"parent":"TYPE","rule":"Unit","sum":1145},{"parent":"TYPE","rule":"Utf8","sum":14377035},{"parent":"TYPE","rule":"Uuid","sum":43670},{"parent":"TYPE","rule":"VARCHAR","sum":517616},{"parent":"TYPE","rule":"Varchar","sum":2},{"parent":"TYPE","rule":"Void","sum":11091},{"parent":"TYPE","rule":"XML","sum":21},{"parent":"TYPE","rule":"YSON","sum":226731},{"parent":"TYPE","rule":"YSon","sum":341},{"parent":"TYPE","rule":"Yson","sum":17664858},{"parent":"TYPE","rule":"_PgMoney","sum":3},{"parent":"TYPE","rule":"bigint","sum":8828},{"parent":"TYPE","rule":"bool","sum":936190},{"parent":"TYPE","rule":"bytes","sum":35135},{"parent":"TYPE","rule":"dATE","sum":1},{"parent":"TYPE","rule":"daTE","sum":5},{"parent":"TYPE","rule":"date","sum":32420506},{"parent":"TYPE","rule":"date32","sum":41},{"parent":"TYPE","rule":"dateTIME","sum":8},{"parent":"TYPE","rule":"dateTime","sum":43592},{"parent":"TYPE","rule":"datetime","sum":7103828},{"parent":"TYPE","rule":"datetime64","sum":61},{"parent":"TYPE","rule":"double","sum":6941462},{"parent":"TYPE","rule":"emptyList","sum":1},{"parent":"TYPE","rule":"float","sum":4717598},{"parent":"TYPE","rule":"generic","sum":2},{"parent":"TYPE","rule":"iNT","sum":1},{"parent":"TYPE","rule":"iNT64","sum":27},{"parent":"TYPE","rule":"inT64","sum":260},{"parent":"TYPE","rule":"int","sum":1120407},{"parent":"TYPE","rule":"int16","sum":79087},{"parent":"TYPE","rule":"int32","sum":3210506},{"parent":"TYPE","rule":"int64","sum":8446097},{"parent":"TYPE","rule":"int8","sum":42063},{"parent":"TYPE","rule":"integer","sum":135781},{"parent":"TYPE","rule":"interval","sum":402198},{"parent":"TYPE","rule":"json","sum":1061189},{"parent":"TYPE","rule":"json_document","sum":1},{"parent":"TYPE","rule":"jsondocument","sum":1},{"parent":"TYPE","rule":"pgDate","sum":22},{"parent":"TYPE","rule":"pg_name","sum":2},{"parent":"TYPE","rule":"pgbigint","sum":1},{"parent":"TYPE","rule":"pgbool","sum":18},{"parent":"TYPE","rule":"pgdate","sum":14},{"parent":"TYPE","rule":"pgfloat8","sum":2},{"parent":"TYPE","rule":"pgint","sum":366},{"parent":"TYPE","rule":"pgint2","sum":6},{"parent":"TYPE","rule":"pgint4","sum":41},{"parent":"TYPE","rule":"pgint8","sum":1},{"parent":"TYPE","rule":"pginteger","sum":1},{"parent":"TYPE","rule":"pginterval","sum":371},{"parent":"TYPE","rule":"pgnumeric","sum":5},{"parent":"TYPE","rule":"pgoid","sum":1},{"parent":"TYPE","rule":"pgtext","sum":76},{"parent":"TYPE","rule":"pgtimestamp","sum":20},{"parent":"TYPE","rule":"sTRING","sum":16},{"parent":"TYPE","rule":"smallint","sum":1},{"parent":"TYPE","rule":"strINg","sum":14},{"parent":"TYPE","rule":"striNg","sum":1},{"parent":"TYPE","rule":"strinG","sum":73},{"parent":"TYPE","rule":"string","sum":45772323},{"parent":"TYPE","rule":"text","sum":4570081},{"parent":"TYPE","rule":"timeStamp","sum":82},{"parent":"TYPE","rule":"timestamp","sum":21902003},{"parent":"TYPE","rule":"timestamp64","sum":12},{"parent":"TYPE","rule":"tinyint","sum":3},{"parent":"TYPE","rule":"tzDate","sum":1},{"parent":"TYPE","rule":"tzDateTime","sum":3},{"parent":"TYPE","rule":"tzDatetime","sum":30},{"parent":"TYPE","rule":"tzTimestamp","sum":709},{"parent":"TYPE","rule":"tzdate","sum":19},{"parent":"TYPE","rule":"tzdatetime","sum":67},{"parent":"TYPE","rule":"tzdatetime64","sum":2},{"parent":"TYPE","rule":"tztimestamp","sum":32},{"parent":"TYPE","rule":"tztimestamp64","sum":3},{"parent":"TYPE","rule":"uINT32","sum":18},{"parent":"TYPE","rule":"uInt32","sum":12235},{"parent":"TYPE","rule":"uInt64","sum":2529},{"parent":"TYPE","rule":"uInt8","sum":52},{"parent":"TYPE","rule":"uint16","sum":27242},{"parent":"TYPE","rule":"uint32","sum":5311919},{"parent":"TYPE","rule":"uint64","sum":8655463},{"parent":"TYPE","rule":"uint8","sum":159908},{"parent":"TYPE","rule":"unit","sum":693697},{"parent":"TYPE","rule":"utf8","sum":4600990},{"parent":"TYPE","rule":"uuid","sum":2983539},{"parent":"TYPE","rule":"varchar","sum":58732},{"parent":"TYPE","rule":"void","sum":1},{"parent":"TYPE","rule":"xml","sum":32455},{"parent":"TYPE","rule":"yaml","sum":144},{"parent":"TYPE","rule":"yson","sum":1127366}] +[{"parent":"FUNC","rule":"ABC","sum":1},{"parent":"FUNC","rule":"ABS","sum":3117622},{"parent":"FUNC","rule":"ADAPTIVE_WARD_HISTOGRAM","sum":1},{"parent":"FUNC","rule":"ADDTIMEZONE","sum":405},{"parent":"FUNC","rule":"AGGLIST","sum":1245},{"parent":"FUNC","rule":"AGGList","sum":1},{"parent":"FUNC","rule":"AGGREATE_LIST","sum":2},{"parent":"FUNC","rule":"AGGREGATELIST","sum":71},{"parent":"FUNC","rule":"AGGREGATE_BY","sum":1601982},{"parent":"FUNC","rule":"AGGREGATE_LIST","sum":19737967},{"parent":"FUNC","rule":"AGGREGATE_LIST_","sum":2},{"parent":"FUNC","rule":"AGGREGATE_LIST_DISTINCT","sum":12914484},{"parent":"FUNC","rule":"AGGREGATE_LIST_DISTINCt","sum":2},{"parent":"FUNC","rule":"AGGREGATE_LIST_DISTNCT","sum":1},{"parent":"FUNC","rule":"AGGREGATE_LIST_DiSTINCT","sum":4},{"parent":"FUNC","rule":"AGGREGATE_LIST_Distinct","sum":774},{"parent":"FUNC","rule":"AGGREGATE_LIST_distINCT","sum":4},{"parent":"FUNC","rule":"AGGREGATE_LIST_distinct","sum":18948},{"parent":"FUNC","rule":"AGGREGATE_LISt","sum":6},{"parent":"FUNC","rule":"AGGREGATE_LiST","sum":106},{"parent":"FUNC","rule":"AGGREGATE_List","sum":75},{"parent":"FUNC","rule":"AGGREGATE_lIST","sum":59},{"parent":"FUNC","rule":"AGGREGATE_liST_DISTINCT","sum":9},{"parent":"FUNC","rule":"AGGREGATE_list","sum":321},{"parent":"FUNC","rule":"AGGREGATE_list_distinct","sum":1},{"parent":"FUNC","rule":"AGGREGATIONFACTORY","sum":57},{"parent":"FUNC","rule":"AGGREGATION_FACTORY","sum":66558},{"parent":"FUNC","rule":"AGGREGate_List","sum":2},{"parent":"FUNC","rule":"AGGR_LIST","sum":2994},{"parent":"FUNC","rule":"AGGR_LIST_DISTINCT","sum":44284},{"parent":"FUNC","rule":"AGGReGATE_LIST","sum":3},{"parent":"FUNC","rule":"AGGReGate_list","sum":1},{"parent":"FUNC","rule":"AGG_LIST","sum":5165435},{"parent":"FUNC","rule":"AGG_LIST_","sum":5},{"parent":"FUNC","rule":"AGG_LIST_DISTINCT","sum":2880462},{"parent":"FUNC","rule":"AGG_LIST_DISTINCt","sum":9},{"parent":"FUNC","rule":"AGG_LIST_DIStiNCT","sum":10},{"parent":"FUNC","rule":"AGG_LIST_DiSTINCT","sum":4},{"parent":"FUNC","rule":"AGG_LIST_Distinct","sum":47},{"parent":"FUNC","rule":"AGG_LIST_distinct","sum":647},{"parent":"FUNC","rule":"AGG_LISt","sum":2},{"parent":"FUNC","rule":"AGG_LIst","sum":11},{"parent":"FUNC","rule":"AGG_LiST","sum":4},{"parent":"FUNC","rule":"AGG_LiST_DIStiNCT","sum":2},{"parent":"FUNC","rule":"AGG_List","sum":6764},{"parent":"FUNC","rule":"AGG_List_DISTINCT","sum":39},{"parent":"FUNC","rule":"AGG_List_Distinct","sum":914},{"parent":"FUNC","rule":"AGG_List_distinct","sum":103},{"parent":"FUNC","rule":"AGG_lIST_DISTINCT","sum":5},{"parent":"FUNC","rule":"AGG_list","sum":17168},{"parent":"FUNC","rule":"AGG_list_DISTINCT","sum":3036},{"parent":"FUNC","rule":"AGG_list_distinct","sum":799},{"parent":"FUNC","rule":"AGGrEGATE_LIST","sum":2},{"parent":"FUNC","rule":"AGGreGATE_LIST_DISTINCT","sum":3},{"parent":"FUNC","rule":"AGGregateList","sum":19},{"parent":"FUNC","rule":"AGGregate_LIST","sum":3},{"parent":"FUNC","rule":"AGGregate_LIST_DISTINCT","sum":1},{"parent":"FUNC","rule":"AGGregate_list","sum":6},{"parent":"FUNC","rule":"AGGregate_list_distinct","sum":65},{"parent":"FUNC","rule":"AND","sum":46},{"parent":"FUNC","rule":"ARRAY_AGG","sum":2},{"parent":"FUNC","rule":"ASDICT","sum":198},{"parent":"FUNC","rule":"ASDict","sum":618},{"parent":"FUNC","rule":"ASEnum","sum":88},{"parent":"FUNC","rule":"ASIN","sum":2},{"parent":"FUNC","rule":"ASLIST","sum":27390},{"parent":"FUNC","rule":"ASLIst","sum":4},{"parent":"FUNC","rule":"ASList","sum":23161},{"parent":"FUNC","rule":"ASListStrict","sum":3},{"parent":"FUNC","rule":"ASSET","sum":17},{"parent":"FUNC","rule":"ASSTRUCT","sum":2732},{"parent":"FUNC","rule":"ASSet","sum":5},{"parent":"FUNC","rule":"ASStruct","sum":2498},{"parent":"FUNC","rule":"ASTAGGED","sum":15},{"parent":"FUNC","rule":"ASTAgged","sum":3},{"parent":"FUNC","rule":"ASTUPLE","sum":1574},{"parent":"FUNC","rule":"ASTagged","sum":63},{"parent":"FUNC","rule":"ASTuple","sum":5936},{"parent":"FUNC","rule":"AS_DICT","sum":6},{"parent":"FUNC","rule":"AS_LIST","sum":136},{"parent":"FUNC","rule":"AS_STRUCT","sum":13468},{"parent":"FUNC","rule":"AS_TABLE","sum":33},{"parent":"FUNC","rule":"AS_TUPLE","sum":853},{"parent":"FUNC","rule":"ASdict","sum":4},{"parent":"FUNC","rule":"ASlist","sum":1037},{"parent":"FUNC","rule":"ASstruct","sum":41},{"parent":"FUNC","rule":"AStagged","sum":3},{"parent":"FUNC","rule":"AStuple","sum":398},{"parent":"FUNC","rule":"AVG","sum":9148142},{"parent":"FUNC","rule":"AVGIF","sum":19},{"parent":"FUNC","rule":"AVG_IF","sum":734942},{"parent":"FUNC","rule":"AVG_If","sum":8},{"parent":"FUNC","rule":"AVG_if","sum":14181},{"parent":"FUNC","rule":"AVg","sum":4},{"parent":"FUNC","rule":"Abs","sum":323401},{"parent":"FUNC","rule":"AdaptiveDistanceHistogramCDF","sum":1},{"parent":"FUNC","rule":"AdaptiveWardHistogram","sum":1},{"parent":"FUNC","rule":"AdaptiveWardHistogramCDF","sum":3},{"parent":"FUNC","rule":"AdaptiveWeightHistogram","sum":57359},{"parent":"FUNC","rule":"AddMember","sum":885884},{"parent":"FUNC","rule":"AddTimeZone","sum":518426},{"parent":"FUNC","rule":"AddTimezone","sum":12027545},{"parent":"FUNC","rule":"Addtimezone","sum":60},{"parent":"FUNC","rule":"AggLIst","sum":1},{"parent":"FUNC","rule":"AggList","sum":20909},{"parent":"FUNC","rule":"AggListDistinct","sum":91},{"parent":"FUNC","rule":"Agg_LIST","sum":60},{"parent":"FUNC","rule":"Agg_LIST_DISTINCT","sum":30},{"parent":"FUNC","rule":"Agg_LIST_Distinct","sum":1},{"parent":"FUNC","rule":"Agg_LIst","sum":2},{"parent":"FUNC","rule":"Agg_LiSt","sum":3},{"parent":"FUNC","rule":"Agg_List","sum":129856},{"parent":"FUNC","rule":"Agg_List_","sum":8},{"parent":"FUNC","rule":"Agg_List_DISTINCT","sum":732},{"parent":"FUNC","rule":"Agg_List_Distinct","sum":2466},{"parent":"FUNC","rule":"Agg_List_distinct","sum":4},{"parent":"FUNC","rule":"Agg_list","sum":35750},{"parent":"FUNC","rule":"Agg_list_distinct","sum":8138},{"parent":"FUNC","rule":"Aggergate_List","sum":1},{"parent":"FUNC","rule":"Agglist","sum":93},{"parent":"FUNC","rule":"AggrList","sum":13},{"parent":"FUNC","rule":"Aggr_List","sum":1},{"parent":"FUNC","rule":"AggreGate_List","sum":6},{"parent":"FUNC","rule":"AggregateBy","sum":42482},{"parent":"FUNC","rule":"AggregateFlatten","sum":52498},{"parent":"FUNC","rule":"AggregateList","sum":40425},{"parent":"FUNC","rule":"AggregateListDistinct","sum":7681},{"parent":"FUNC","rule":"AggregateTransformInput","sum":25567},{"parent":"FUNC","rule":"AggregateTransformOutput","sum":44772},{"parent":"FUNC","rule":"Aggregate_BY","sum":237},{"parent":"FUNC","rule":"Aggregate_By","sum":136153},{"parent":"FUNC","rule":"Aggregate_LIST","sum":848},{"parent":"FUNC","rule":"Aggregate_LIST_DISTINCT","sum":2},{"parent":"FUNC","rule":"Aggregate_LIst","sum":1},{"parent":"FUNC","rule":"Aggregate_List","sum":346231},{"parent":"FUNC","rule":"Aggregate_List_Distinct","sum":5261},{"parent":"FUNC","rule":"Aggregate_List_distinct","sum":1372},{"parent":"FUNC","rule":"Aggregate_by","sum":79},{"parent":"FUNC","rule":"Aggregate_list","sum":230560},{"parent":"FUNC","rule":"Aggregate_list_DISTINCT","sum":36},{"parent":"FUNC","rule":"Aggregate_list_Distinct","sum":11},{"parent":"FUNC","rule":"Aggregate_list_distinct","sum":202995},{"parent":"FUNC","rule":"AggregationFactory","sum":1519387},{"parent":"FUNC","rule":"Apply","sum":1},{"parent":"FUNC","rule":"AsAtom","sum":688505},{"parent":"FUNC","rule":"AsDict","sum":2933238},{"parent":"FUNC","rule":"AsDictStrict","sum":4468},{"parent":"FUNC","rule":"AsEnum","sum":51781},{"parent":"FUNC","rule":"AsLIST","sum":917},{"parent":"FUNC","rule":"AsLIst","sum":2706},{"parent":"FUNC","rule":"AsLisT","sum":1511},{"parent":"FUNC","rule":"AsList","sum":17378189},{"parent":"FUNC","rule":"AsListStrict","sum":86759},{"parent":"FUNC","rule":"AsListstrict","sum":1},{"parent":"FUNC","rule":"AsSTruct","sum":374},{"parent":"FUNC","rule":"AsSet","sum":1600254},{"parent":"FUNC","rule":"AsSetStrict","sum":11394},{"parent":"FUNC","rule":"AsStruct","sum":23604103},{"parent":"FUNC","rule":"AsTAgged","sum":265},{"parent":"FUNC","rule":"AsTUPLE","sum":456},{"parent":"FUNC","rule":"AsTUple","sum":270},{"parent":"FUNC","rule":"AsTable","sum":6},{"parent":"FUNC","rule":"AsTaggeD","sum":1},{"parent":"FUNC","rule":"AsTagged","sum":183710},{"parent":"FUNC","rule":"AsTuPle","sum":1},{"parent":"FUNC","rule":"AsTuple","sum":30446583},{"parent":"FUNC","rule":"AsTupleunwrap","sum":4},{"parent":"FUNC","rule":"AsVariant","sum":357832},{"parent":"FUNC","rule":"As_List","sum":6},{"parent":"FUNC","rule":"As_Struct","sum":6},{"parent":"FUNC","rule":"As_list","sum":20},{"parent":"FUNC","rule":"As_tuple","sum":813},{"parent":"FUNC","rule":"Asdict","sum":186},{"parent":"FUNC","rule":"AslIst","sum":14},{"parent":"FUNC","rule":"Aslist","sum":23969},{"parent":"FUNC","rule":"Asset","sum":49},{"parent":"FUNC","rule":"Asstruct","sum":420},{"parent":"FUNC","rule":"AssumeStrict","sum":2912},{"parent":"FUNC","rule":"Astagged","sum":172},{"parent":"FUNC","rule":"Astuple","sum":783},{"parent":"FUNC","rule":"AtomCode","sum":526010},{"parent":"FUNC","rule":"Avg","sum":139829},{"parent":"FUNC","rule":"Avg_IF","sum":162},{"parent":"FUNC","rule":"Avg_If","sum":131},{"parent":"FUNC","rule":"Avg_if","sum":225},{"parent":"FUNC","rule":"BIT_AND","sum":4},{"parent":"FUNC","rule":"BIT_OR","sum":39261},{"parent":"FUNC","rule":"BIT_XOR","sum":447227},{"parent":"FUNC","rule":"BOOL_AND","sum":266337},{"parent":"FUNC","rule":"BOOL_OR","sum":880188},{"parent":"FUNC","rule":"BOOL_XOR","sum":52},{"parent":"FUNC","rule":"BOOL_and","sum":2},{"parent":"FUNC","rule":"BOOl_OR","sum":382},{"parent":"FUNC","rule":"BOTTOM","sum":11557},{"parent":"FUNC","rule":"BOTTOM_BY","sum":47958},{"parent":"FUNC","rule":"BOTTOM_by","sum":2},{"parent":"FUNC","rule":"Bool","sum":1369},{"parent":"FUNC","rule":"Bool_And","sum":118},{"parent":"FUNC","rule":"Bool_OR","sum":6},{"parent":"FUNC","rule":"Bool_Or","sum":597},{"parent":"FUNC","rule":"Bool_and","sum":85},{"parent":"FUNC","rule":"Bool_or","sum":820},{"parent":"FUNC","rule":"Bottom","sum":276},{"parent":"FUNC","rule":"Bottom_BY","sum":10},{"parent":"FUNC","rule":"Bottom_By","sum":121},{"parent":"FUNC","rule":"Bottom_by","sum":1684},{"parent":"FUNC","rule":"ByteAt","sum":17504},{"parent":"FUNC","rule":"Bytes","sum":5},{"parent":"FUNC","rule":"CHAR_LENGTH","sum":391},{"parent":"FUNC","rule":"COALECSE","sum":1},{"parent":"FUNC","rule":"COALESCE","sum":52024758},{"parent":"FUNC","rule":"COALESCe","sum":10},{"parent":"FUNC","rule":"COALESce","sum":8},{"parent":"FUNC","rule":"COALEsCE","sum":1},{"parent":"FUNC","rule":"COALEsce","sum":4},{"parent":"FUNC","rule":"COALeSCE","sum":1},{"parent":"FUNC","rule":"COALesce","sum":14},{"parent":"FUNC","rule":"COAlESCE","sum":2693},{"parent":"FUNC","rule":"COAlesce","sum":12},{"parent":"FUNC","rule":"CONCAT","sum":19},{"parent":"FUNC","rule":"COOUNT","sum":2},{"parent":"FUNC","rule":"CORR","sum":430},{"parent":"FUNC","rule":"CORRELATION","sum":21278},{"parent":"FUNC","rule":"COS","sum":4},{"parent":"FUNC","rule":"COUNT","sum":52979386},{"parent":"FUNC","rule":"COUNTD","sum":4},{"parent":"FUNC","rule":"COUNTDISTINCTESTIMATE","sum":609},{"parent":"FUNC","rule":"COUNTDistinctEstimate","sum":7},{"parent":"FUNC","rule":"COUNTIF","sum":14890},{"parent":"FUNC","rule":"COUNT_","sum":1},{"parent":"FUNC","rule":"COUNT_IF","sum":24159766},{"parent":"FUNC","rule":"COUNT_IF_","sum":24},{"parent":"FUNC","rule":"COUNT_If","sum":12957},{"parent":"FUNC","rule":"COUNT_iF","sum":44},{"parent":"FUNC","rule":"COUNT_if","sum":19390},{"parent":"FUNC","rule":"COUNt","sum":1261},{"parent":"FUNC","rule":"COUNt_IF","sum":24},{"parent":"FUNC","rule":"COUNt_If","sum":3},{"parent":"FUNC","rule":"COUNt_if","sum":11},{"parent":"FUNC","rule":"COUnT","sum":9},{"parent":"FUNC","rule":"COUnT_IF","sum":7},{"parent":"FUNC","rule":"COUnt","sum":40},{"parent":"FUNC","rule":"COVAR","sum":2870},{"parent":"FUNC","rule":"COVARIANCE","sum":1523},{"parent":"FUNC","rule":"COVARIANCE_POPULATION","sum":69},{"parent":"FUNC","rule":"COVARIANCE_SAMPLE","sum":4},{"parent":"FUNC","rule":"COVAR_POP","sum":4},{"parent":"FUNC","rule":"COalesce","sum":22},{"parent":"FUNC","rule":"COuNT","sum":64},{"parent":"FUNC","rule":"COuNT_If","sum":1},{"parent":"FUNC","rule":"COunt","sum":187},{"parent":"FUNC","rule":"COunt_IF","sum":57},{"parent":"FUNC","rule":"COunt_If","sum":2},{"parent":"FUNC","rule":"COunt_iF","sum":1},{"parent":"FUNC","rule":"COunt_if","sum":3},{"parent":"FUNC","rule":"CUME_DIST","sum":109},{"parent":"FUNC","rule":"CURRENTUTCDATE","sum":5408},{"parent":"FUNC","rule":"CURRENTUTCDATETIME","sum":6764},{"parent":"FUNC","rule":"CURRENTUTCDate","sum":109},{"parent":"FUNC","rule":"CURRENT_UTC_DATE","sum":8},{"parent":"FUNC","rule":"CUrrentUTCDate","sum":1},{"parent":"FUNC","rule":"CallableArgument","sum":10353},{"parent":"FUNC","rule":"CallableArgumentType","sum":18965},{"parent":"FUNC","rule":"CallableResultType","sum":114},{"parent":"FUNC","rule":"CallableType","sum":182912},{"parent":"FUNC","rule":"CallableTypeHandle","sum":5879},{"parent":"FUNC","rule":"Ceil","sum":3},{"parent":"FUNC","rule":"ChooseMember","sum":2},{"parent":"FUNC","rule":"ChooseMembers","sum":2490838},{"parent":"FUNC","rule":"Choosemembers","sum":21080},{"parent":"FUNC","rule":"ChosenMembers","sum":8},{"parent":"FUNC","rule":"ClearBit","sum":29489},{"parent":"FUNC","rule":"CoALESCE","sum":1},{"parent":"FUNC","rule":"CoUNT","sum":39},{"parent":"FUNC","rule":"CoUNT_IF","sum":17},{"parent":"FUNC","rule":"CoUNt","sum":2},{"parent":"FUNC","rule":"CoUnt","sum":2},{"parent":"FUNC","rule":"Coalesce","sum":728073},{"parent":"FUNC","rule":"Collect","sum":1},{"parent":"FUNC","rule":"CollectList","sum":1},{"parent":"FUNC","rule":"CombineMembers","sum":509813},{"parent":"FUNC","rule":"Concat","sum":1},{"parent":"FUNC","rule":"Correlation","sum":180},{"parent":"FUNC","rule":"CouNT","sum":2},{"parent":"FUNC","rule":"CounT","sum":17},{"parent":"FUNC","rule":"Count","sum":395738},{"parent":"FUNC","rule":"CountDistinctEstimate","sum":156846},{"parent":"FUNC","rule":"CountIF","sum":81},{"parent":"FUNC","rule":"CountIf","sum":505},{"parent":"FUNC","rule":"Count_IF","sum":15957},{"parent":"FUNC","rule":"Count_If","sum":42244},{"parent":"FUNC","rule":"Count_if","sum":323414},{"parent":"FUNC","rule":"Countif","sum":12},{"parent":"FUNC","rule":"CurrentAuthenticatedUser","sum":90845},{"parent":"FUNC","rule":"CurrentDatetime","sum":1},{"parent":"FUNC","rule":"CurrentOperationId","sum":89419},{"parent":"FUNC","rule":"CurrentOperationSharedId","sum":5755},{"parent":"FUNC","rule":"CurrentTZDate","sum":530},{"parent":"FUNC","rule":"CurrentTZDateTime","sum":35},{"parent":"FUNC","rule":"CurrentTZDatetime","sum":532},{"parent":"FUNC","rule":"CurrentTZTimestamp","sum":173},{"parent":"FUNC","rule":"CurrentTZdatetime","sum":68},{"parent":"FUNC","rule":"CurrentTzDate","sum":1612551},{"parent":"FUNC","rule":"CurrentTzDateTime","sum":1464812},{"parent":"FUNC","rule":"CurrentTzDatetime","sum":1999616},{"parent":"FUNC","rule":"CurrentTzTimeStamp","sum":4322},{"parent":"FUNC","rule":"CurrentTzTimestamp","sum":1908235},{"parent":"FUNC","rule":"CurrentUTCDATE","sum":20},{"parent":"FUNC","rule":"CurrentUTCDAte","sum":38},{"parent":"FUNC","rule":"CurrentUTCDate","sum":918777},{"parent":"FUNC","rule":"CurrentUTCDateTime","sum":182824},{"parent":"FUNC","rule":"CurrentUTCDatetime","sum":131694},{"parent":"FUNC","rule":"CurrentUTCTimeStamp","sum":99},{"parent":"FUNC","rule":"CurrentUTCTimestamp","sum":451698},{"parent":"FUNC","rule":"CurrentUTCdate","sum":71243},{"parent":"FUNC","rule":"CurrentUTcDate","sum":70},{"parent":"FUNC","rule":"CurrentUtCDate","sum":5},{"parent":"FUNC","rule":"CurrentUtCDatetime","sum":3},{"parent":"FUNC","rule":"CurrentUtcDATE","sum":2},{"parent":"FUNC","rule":"CurrentUtcDAte","sum":3},{"parent":"FUNC","rule":"CurrentUtcDatE","sum":1},{"parent":"FUNC","rule":"CurrentUtcDate","sum":19669061},{"parent":"FUNC","rule":"CurrentUtcDateTIME","sum":1},{"parent":"FUNC","rule":"CurrentUtcDateTime","sum":3211891},{"parent":"FUNC","rule":"CurrentUtcDatetime","sum":13829344},{"parent":"FUNC","rule":"CurrentUtcDttm","sum":3},{"parent":"FUNC","rule":"CurrentUtcTimeStamp","sum":59822},{"parent":"FUNC","rule":"CurrentUtcTimestamp","sum":15398914},{"parent":"FUNC","rule":"CurrentUtcdate","sum":11526},{"parent":"FUNC","rule":"CurrenttzDate","sum":352},{"parent":"FUNC","rule":"CurrenttzDatetime","sum":1},{"parent":"FUNC","rule":"CurrentutcDate","sum":21239},{"parent":"FUNC","rule":"CurrentutcDateTime","sum":625},{"parent":"FUNC","rule":"CurrentutcTimestamp","sum":4},{"parent":"FUNC","rule":"Currentutcdate","sum":1528},{"parent":"FUNC","rule":"Currentutcdatetime","sum":22633},{"parent":"FUNC","rule":"D","sum":1},{"parent":"FUNC","rule":"DATE","sum":128894},{"parent":"FUNC","rule":"DATEADD","sum":3},{"parent":"FUNC","rule":"DATEDIFF","sum":9},{"parent":"FUNC","rule":"DATETIME","sum":813},{"parent":"FUNC","rule":"DATE_PART","sum":16},{"parent":"FUNC","rule":"DATE_TRUNC","sum":29},{"parent":"FUNC","rule":"DATe","sum":20},{"parent":"FUNC","rule":"DAte","sum":179},{"parent":"FUNC","rule":"DAtetime","sum":61},{"parent":"FUNC","rule":"DENSE_RANK","sum":274578},{"parent":"FUNC","rule":"DICTKEYS","sum":27},{"parent":"FUNC","rule":"DICTLENGTH","sum":4},{"parent":"FUNC","rule":"DICTLength","sum":2},{"parent":"FUNC","rule":"DICTPAYLOADS","sum":2},{"parent":"FUNC","rule":"DICT_CONTAINS","sum":5},{"parent":"FUNC","rule":"DIctHasItems","sum":1},{"parent":"FUNC","rule":"DIctItems","sum":1},{"parent":"FUNC","rule":"DIctKeys","sum":1},{"parent":"FUNC","rule":"DIctLength","sum":1},{"parent":"FUNC","rule":"DIctLookup","sum":16},{"parent":"FUNC","rule":"DOUBLE","sum":63},{"parent":"FUNC","rule":"DatE","sum":3},{"parent":"FUNC","rule":"DataType","sum":69657},{"parent":"FUNC","rule":"DataTypeComponents","sum":37388},{"parent":"FUNC","rule":"DataTypeHandle","sum":2},{"parent":"FUNC","rule":"Datatype","sum":2},{"parent":"FUNC","rule":"Date","sum":1776018},{"parent":"FUNC","rule":"Date32","sum":74},{"parent":"FUNC","rule":"DateTime","sum":436381},{"parent":"FUNC","rule":"DateTime64","sum":45},{"parent":"FUNC","rule":"Date_Diff","sum":1},{"parent":"FUNC","rule":"DatetimE","sum":8},{"parent":"FUNC","rule":"Datetime","sum":288347},{"parent":"FUNC","rule":"Datetime64","sum":6},{"parent":"FUNC","rule":"Decimal","sum":31498},{"parent":"FUNC","rule":"DenseRank","sum":27},{"parent":"FUNC","rule":"Dense_RANK","sum":1},{"parent":"FUNC","rule":"Dense_Rank","sum":55},{"parent":"FUNC","rule":"Dense_rank","sum":6},{"parent":"FUNC","rule":"DicTKeys","sum":2},{"parent":"FUNC","rule":"DictAggregate","sum":140410},{"parent":"FUNC","rule":"DictCOntains","sum":350},{"parent":"FUNC","rule":"DictContains","sum":2023914},{"parent":"FUNC","rule":"DictCreate","sum":69740},{"parent":"FUNC","rule":"DictHasItems","sum":610877},{"parent":"FUNC","rule":"DictHasitems","sum":261},{"parent":"FUNC","rule":"DictItems","sum":2559168},{"parent":"FUNC","rule":"DictKEYS","sum":12},{"parent":"FUNC","rule":"DictKEys","sum":1},{"parent":"FUNC","rule":"DictKeYS","sum":3},{"parent":"FUNC","rule":"DictKeyType","sum":941},{"parent":"FUNC","rule":"DictKeys","sum":2717527},{"parent":"FUNC","rule":"DictLOokup","sum":7},{"parent":"FUNC","rule":"DictLength","sum":1020216},{"parent":"FUNC","rule":"DictLookUP","sum":3},{"parent":"FUNC","rule":"DictLookUp","sum":62348},{"parent":"FUNC","rule":"DictLookup","sum":5982095},{"parent":"FUNC","rule":"DictPayLoads","sum":10275},{"parent":"FUNC","rule":"DictPayloadType","sum":210},{"parent":"FUNC","rule":"DictPayloads","sum":928102},{"parent":"FUNC","rule":"DictType","sum":503},{"parent":"FUNC","rule":"DictTypeComponents","sum":3},{"parent":"FUNC","rule":"DictTypeHandle","sum":1},{"parent":"FUNC","rule":"DictValues","sum":5},{"parent":"FUNC","rule":"Dict_Keys","sum":12},{"parent":"FUNC","rule":"Dictcontains","sum":7},{"parent":"FUNC","rule":"Dictitems","sum":19780},{"parent":"FUNC","rule":"Dictkeys","sum":1159},{"parent":"FUNC","rule":"Dictlength","sum":6},{"parent":"FUNC","rule":"Dictlookup","sum":76634},{"parent":"FUNC","rule":"Double","sum":33704},{"parent":"FUNC","rule":"DyNumber","sum":4},{"parent":"FUNC","rule":"EACH","sum":4},{"parent":"FUNC","rule":"ENDSWITH","sum":13893},{"parent":"FUNC","rule":"ENDsWith","sum":85},{"parent":"FUNC","rule":"ENSURE","sum":833225},{"parent":"FUNC","rule":"EOMONTH","sum":1},{"parent":"FUNC","rule":"EmptyDict","sum":450},{"parent":"FUNC","rule":"EmptyDictTypeHandle","sum":3},{"parent":"FUNC","rule":"EmptyList","sum":23618},{"parent":"FUNC","rule":"Emptydict","sum":6},{"parent":"FUNC","rule":"EndsWIth","sum":870},{"parent":"FUNC","rule":"EndsWith","sum":1580550},{"parent":"FUNC","rule":"Endswith","sum":19806},{"parent":"FUNC","rule":"Ensure","sum":1438138},{"parent":"FUNC","rule":"EnsureConvertibleTo","sum":2062},{"parent":"FUNC","rule":"EnsureType","sum":229200},{"parent":"FUNC","rule":"EvaluateAtom","sum":429},{"parent":"FUNC","rule":"EvaluateCode","sum":465798},{"parent":"FUNC","rule":"EvaluateExpr","sum":902167},{"parent":"FUNC","rule":"EvaluateType","sum":122971},{"parent":"FUNC","rule":"ExpandStruct","sum":269664},{"parent":"FUNC","rule":"ExtractUkropCtx","sum":1},{"parent":"FUNC","rule":"FCatBoostUserActivityOnPage","sum":2},{"parent":"FUNC","rule":"FIND","sum":5651098},{"parent":"FUNC","rule":"FIRST","sum":3},{"parent":"FUNC","rule":"FIRST_VALUE","sum":8949141},{"parent":"FUNC","rule":"FIRST_value","sum":831},{"parent":"FUNC","rule":"FIRsT_VALUE","sum":1},{"parent":"FUNC","rule":"FIleContent","sum":1},{"parent":"FUNC","rule":"FLATTEN","sum":9},{"parent":"FUNC","rule":"FLOAT","sum":5},{"parent":"FUNC","rule":"FLOOR","sum":1},{"parent":"FUNC","rule":"FORMATTYPE","sum":1},{"parent":"FUNC","rule":"FROMBYTES","sum":5},{"parent":"FUNC","rule":"FROmbytes","sum":4},{"parent":"FUNC","rule":"FileCOntent","sum":55},{"parent":"FUNC","rule":"FileContent","sum":2391991},{"parent":"FUNC","rule":"FilePath","sum":1452670},{"parent":"FUNC","rule":"Filecontent","sum":11712},{"parent":"FUNC","rule":"Filepath","sum":10},{"parent":"FUNC","rule":"FinD","sum":16},{"parent":"FUNC","rule":"Find","sum":322130},{"parent":"FUNC","rule":"FirsT_VALUE","sum":3},{"parent":"FUNC","rule":"First_VALUE","sum":10},{"parent":"FUNC","rule":"First_Value","sum":28},{"parent":"FUNC","rule":"First_value","sum":180},{"parent":"FUNC","rule":"FlattenMembers","sum":109646},{"parent":"FUNC","rule":"Float","sum":12519},{"parent":"FUNC","rule":"FoldMap","sum":13},{"parent":"FUNC","rule":"FolderPath","sum":9918},{"parent":"FUNC","rule":"ForceRemoveMember","sum":403616},{"parent":"FUNC","rule":"ForceRemoveMembers","sum":1087165},{"parent":"FUNC","rule":"ForceRenameMembers","sum":64404},{"parent":"FUNC","rule":"ForceSpreadMembers","sum":116529},{"parent":"FUNC","rule":"ForceSpreadmembers","sum":4},{"parent":"FUNC","rule":"Format","sum":1},{"parent":"FUNC","rule":"FormatCode","sum":682},{"parent":"FUNC","rule":"FormatType","sum":455855},{"parent":"FUNC","rule":"FormatTypeDiff","sum":821},{"parent":"FUNC","rule":"FormatTypeDiffPretty","sum":103},{"parent":"FUNC","rule":"Formattype","sum":101},{"parent":"FUNC","rule":"FromBytes","sum":99585},{"parent":"FUNC","rule":"FromPg","sum":4898},{"parent":"FUNC","rule":"FromYsonSimpleType","sum":1},{"parent":"FUNC","rule":"From_bytes","sum":1},{"parent":"FUNC","rule":"FromatType","sum":1},{"parent":"FUNC","rule":"Frombytes","sum":12},{"parent":"FUNC","rule":"FuncCode","sum":1250611},{"parent":"FUNC","rule":"GETDATE","sum":1},{"parent":"FUNC","rule":"GREATEST","sum":390343},{"parent":"FUNC","rule":"GROUPING","sum":71960},{"parent":"FUNC","rule":"GROUPINg","sum":4},{"parent":"FUNC","rule":"GROUP_CONCAT","sum":1},{"parent":"FUNC","rule":"GatherMembers","sum":1479034},{"parent":"FUNC","rule":"Gather_Members","sum":38},{"parent":"FUNC","rule":"Gathermembers","sum":8},{"parent":"FUNC","rule":"GetLength","sum":2},{"parent":"FUNC","rule":"GetWeekOfYear","sum":1},{"parent":"FUNC","rule":"Greatest","sum":6047},{"parent":"FUNC","rule":"Grouping","sum":243},{"parent":"FUNC","rule":"HISTOGRAM","sum":276451},{"parent":"FUNC","rule":"HISTOGRAMCDF","sum":422},{"parent":"FUNC","rule":"HISTOGRAMCdf","sum":47},{"parent":"FUNC","rule":"HISTOGRAM_CDF","sum":3},{"parent":"FUNC","rule":"HISTOGRAMcdf","sum":2},{"parent":"FUNC","rule":"HISTOGrAM","sum":44},{"parent":"FUNC","rule":"HISTOgram","sum":1},{"parent":"FUNC","rule":"HISToGRAM","sum":1},{"parent":"FUNC","rule":"HISTogram","sum":1},{"parent":"FUNC","rule":"HIStOGRAM","sum":1},{"parent":"FUNC","rule":"HIstogram","sum":34},{"parent":"FUNC","rule":"HLL","sum":12389},{"parent":"FUNC","rule":"HOP_END","sum":16},{"parent":"FUNC","rule":"HOP_START","sum":4},{"parent":"FUNC","rule":"Histogram","sum":35328},{"parent":"FUNC","rule":"HistogramCDF","sum":507},{"parent":"FUNC","rule":"HistogramCdf","sum":34},{"parent":"FUNC","rule":"Histogram_CDF","sum":57},{"parent":"FUNC","rule":"Histogramcdf","sum":1},{"parent":"FUNC","rule":"Hll","sum":1903},{"parent":"FUNC","rule":"HyperLogLog","sum":3798},{"parent":"FUNC","rule":"IF","sum":75622624},{"parent":"FUNC","rule":"IFNULL","sum":9},{"parent":"FUNC","rule":"IF_STRICT","sum":1},{"parent":"FUNC","rule":"IN","sum":2},{"parent":"FUNC","rule":"INT","sum":16},{"parent":"FUNC","rule":"INT32","sum":1},{"parent":"FUNC","rule":"INTERVAL","sum":890810},{"parent":"FUNC","rule":"INterval","sum":763},{"parent":"FUNC","rule":"If","sum":1096955},{"parent":"FUNC","rule":"IfNull","sum":6},{"parent":"FUNC","rule":"InstanceOf","sum":248569},{"parent":"FUNC","rule":"Int","sum":1},{"parent":"FUNC","rule":"Int16","sum":37},{"parent":"FUNC","rule":"Int32","sum":32553},{"parent":"FUNC","rule":"Int64","sum":3648},{"parent":"FUNC","rule":"Int8","sum":302},{"parent":"FUNC","rule":"InterVal","sum":4},{"parent":"FUNC","rule":"Interva","sum":1},{"parent":"FUNC","rule":"Interval","sum":16089312},{"parent":"FUNC","rule":"Interval64","sum":2},{"parent":"FUNC","rule":"IntervalFromDays","sum":8},{"parent":"FUNC","rule":"IsInt64","sum":1},{"parent":"FUNC","rule":"JSON","sum":70},{"parent":"FUNC","rule":"JUST","sum":128739},{"parent":"FUNC","rule":"Join","sum":1},{"parent":"FUNC","rule":"JoinTableRow","sum":1323324},{"parent":"FUNC","rule":"JoinTablerow","sum":721},{"parent":"FUNC","rule":"JointableRow","sum":1},{"parent":"FUNC","rule":"Json","sum":54542},{"parent":"FUNC","rule":"JsonDocument","sum":7},{"parent":"FUNC","rule":"Just","sum":6603059},{"parent":"FUNC","rule":"LAG","sum":4063149},{"parent":"FUNC","rule":"LAST","sum":1},{"parent":"FUNC","rule":"LAST_VALUE","sum":1351241},{"parent":"FUNC","rule":"LAST_value","sum":2},{"parent":"FUNC","rule":"LEAD","sum":1661796},{"parent":"FUNC","rule":"LEAST","sum":428259},{"parent":"FUNC","rule":"LEFT","sum":3},{"parent":"FUNC","rule":"LEFT_SHIFT","sum":1},{"parent":"FUNC","rule":"LEN","sum":1687768},{"parent":"FUNC","rule":"LENGTH","sum":3859013},{"parent":"FUNC","rule":"LENgth","sum":23},{"parent":"FUNC","rule":"LEngth","sum":12},{"parent":"FUNC","rule":"LIKELY","sum":141121},{"parent":"FUNC","rule":"LINEARHISTOGRAM","sum":374},{"parent":"FUNC","rule":"LINEARHISTOGRAMCDF","sum":1},{"parent":"FUNC","rule":"LINEARHistogram","sum":3},{"parent":"FUNC","rule":"LINEAR_HISTOGRAM","sum":13},{"parent":"FUNC","rule":"LISTALL","sum":3038},{"parent":"FUNC","rule":"LISTANY","sum":103},{"parent":"FUNC","rule":"LISTAVG","sum":32},{"parent":"FUNC","rule":"LISTAny","sum":10},{"parent":"FUNC","rule":"LISTCOLLECT","sum":1},{"parent":"FUNC","rule":"LISTCONCAT","sum":1512},{"parent":"FUNC","rule":"LISTENUMERATE","sum":3},{"parent":"FUNC","rule":"LISTEXTEND","sum":16},{"parent":"FUNC","rule":"LISTFILTER","sum":1632},{"parent":"FUNC","rule":"LISTFLATTEN","sum":4280},{"parent":"FUNC","rule":"LISTFROMRANGE","sum":1489},{"parent":"FUNC","rule":"LISTHAS","sum":28962},{"parent":"FUNC","rule":"LISTHASITEMS","sum":2097},{"parent":"FUNC","rule":"LISTHASItems","sum":1},{"parent":"FUNC","rule":"LISTHEAD","sum":18146},{"parent":"FUNC","rule":"LISTHas","sum":9},{"parent":"FUNC","rule":"LISTHead","sum":2},{"parent":"FUNC","rule":"LISTLAST","sum":1569},{"parent":"FUNC","rule":"LISTLENGTH","sum":48412},{"parent":"FUNC","rule":"LISTLENGth","sum":5},{"parent":"FUNC","rule":"LISTLenGTH","sum":7},{"parent":"FUNC","rule":"LISTLength","sum":2149},{"parent":"FUNC","rule":"LISTMAP","sum":14343},{"parent":"FUNC","rule":"LISTMAX","sum":7817},{"parent":"FUNC","rule":"LISTMIN","sum":188},{"parent":"FUNC","rule":"LISTMap","sum":365},{"parent":"FUNC","rule":"LISTNOTNULL","sum":8600},{"parent":"FUNC","rule":"LISTREVERSE","sum":2},{"parent":"FUNC","rule":"LISTSKIP","sum":15},{"parent":"FUNC","rule":"LISTSORT","sum":7651},{"parent":"FUNC","rule":"LISTSORTASC","sum":1657},{"parent":"FUNC","rule":"LISTSORTDESC","sum":109},{"parent":"FUNC","rule":"LISTSUM","sum":172},{"parent":"FUNC","rule":"LISTSort","sum":19},{"parent":"FUNC","rule":"LISTSum","sum":6},{"parent":"FUNC","rule":"LISTTAKE","sum":261},{"parent":"FUNC","rule":"LISTUNIQ","sum":602},{"parent":"FUNC","rule":"LISTUniq","sum":26},{"parent":"FUNC","rule":"LISTZIP","sum":261},{"parent":"FUNC","rule":"LISTZIPALL","sum":305},{"parent":"FUNC","rule":"LIST_AGGREGATE","sum":1},{"parent":"FUNC","rule":"LIST_ALL","sum":1},{"parent":"FUNC","rule":"LIST_ANY","sum":7},{"parent":"FUNC","rule":"LIST_CONCAT","sum":18},{"parent":"FUNC","rule":"LIST_EXTEND","sum":1},{"parent":"FUNC","rule":"LIST_EXTRACT","sum":73},{"parent":"FUNC","rule":"LIST_FOLD","sum":30},{"parent":"FUNC","rule":"LIST_FROM_RANGE","sum":356},{"parent":"FUNC","rule":"LIST_HAS","sum":2084},{"parent":"FUNC","rule":"LIST_HEAD","sum":100},{"parent":"FUNC","rule":"LIST_LAST","sum":54},{"parent":"FUNC","rule":"LIST_LENGTH","sum":2453},{"parent":"FUNC","rule":"LIST_Length","sum":1},{"parent":"FUNC","rule":"LIST_MAP","sum":9},{"parent":"FUNC","rule":"LIST_MAX","sum":285},{"parent":"FUNC","rule":"LIST_SORT","sum":612},{"parent":"FUNC","rule":"LIST_SORT_DESC","sum":17},{"parent":"FUNC","rule":"LIST_SUM","sum":2},{"parent":"FUNC","rule":"LIST_TAKE","sum":2},{"parent":"FUNC","rule":"LIST_UNIQ","sum":349},{"parent":"FUNC","rule":"LIST_length","sum":1},{"parent":"FUNC","rule":"LISTfilter","sum":7},{"parent":"FUNC","rule":"LISTfromRange","sum":1424},{"parent":"FUNC","rule":"LISTfromrange","sum":3},{"parent":"FUNC","rule":"LISThas","sum":2},{"parent":"FUNC","rule":"LISTnotNull","sum":2},{"parent":"FUNC","rule":"LIStExtend","sum":3},{"parent":"FUNC","rule":"LIStHas","sum":2},{"parent":"FUNC","rule":"LIStLENGth","sum":1},{"parent":"FUNC","rule":"LIStLength","sum":1},{"parent":"FUNC","rule":"LIStmap","sum":1},{"parent":"FUNC","rule":"LIstConcat","sum":303},{"parent":"FUNC","rule":"LIstExtend","sum":3},{"parent":"FUNC","rule":"LIstFilter","sum":71},{"parent":"FUNC","rule":"LIstFromRange","sum":8},{"parent":"FUNC","rule":"LIstFromrange","sum":1},{"parent":"FUNC","rule":"LIstHas","sum":14},{"parent":"FUNC","rule":"LIstHasItems","sum":13},{"parent":"FUNC","rule":"LIstHead","sum":3},{"parent":"FUNC","rule":"LIstLength","sum":343},{"parent":"FUNC","rule":"LIstMap","sum":1363},{"parent":"FUNC","rule":"LIstMax","sum":7},{"parent":"FUNC","rule":"LIstSkip","sum":2},{"parent":"FUNC","rule":"LIstSort","sum":1},{"parent":"FUNC","rule":"LIstSum","sum":1},{"parent":"FUNC","rule":"LIstfilter","sum":2},{"parent":"FUNC","rule":"LIstlength","sum":13},{"parent":"FUNC","rule":"LIstmap","sum":12},{"parent":"FUNC","rule":"LOG","sum":1},{"parent":"FUNC","rule":"LOG10","sum":6},{"parent":"FUNC","rule":"LOGHISTOGRAM","sum":1},{"parent":"FUNC","rule":"LOWER","sum":5},{"parent":"FUNC","rule":"Lag","sum":12209},{"parent":"FUNC","rule":"LambdaArgumentsCount","sum":32},{"parent":"FUNC","rule":"LambdaCode","sum":332931},{"parent":"FUNC","rule":"LastValue","sum":5},{"parent":"FUNC","rule":"Last_VALUE","sum":14},{"parent":"FUNC","rule":"Last_Value","sum":29},{"parent":"FUNC","rule":"Last_value","sum":106},{"parent":"FUNC","rule":"Lead","sum":11214},{"parent":"FUNC","rule":"Least","sum":2256},{"parent":"FUNC","rule":"Len","sum":93638},{"parent":"FUNC","rule":"LenGTH","sum":12},{"parent":"FUNC","rule":"Length","sum":1252963},{"parent":"FUNC","rule":"LiSTMAP","sum":2},{"parent":"FUNC","rule":"Likely","sum":21239},{"parent":"FUNC","rule":"LinearHISTOGRAM","sum":86},{"parent":"FUNC","rule":"LinearHistogram","sum":46243},{"parent":"FUNC","rule":"LinearHistogramCDF","sum":347},{"parent":"FUNC","rule":"LinearHistogramcdf","sum":10},{"parent":"FUNC","rule":"Linear_Histogram","sum":7},{"parent":"FUNC","rule":"Linearhistogram","sum":4},{"parent":"FUNC","rule":"Lis","sum":1},{"parent":"FUNC","rule":"LisMap","sum":2},{"parent":"FUNC","rule":"LisTHas","sum":8},{"parent":"FUNC","rule":"LisTLength","sum":2},{"parent":"FUNC","rule":"ListALL","sum":1539},{"parent":"FUNC","rule":"ListALl","sum":8},{"parent":"FUNC","rule":"ListANY","sum":1765},{"parent":"FUNC","rule":"ListAVG","sum":267},{"parent":"FUNC","rule":"ListAgg","sum":1},{"parent":"FUNC","rule":"ListAggregate","sum":424700},{"parent":"FUNC","rule":"ListAll","sum":266378},{"parent":"FUNC","rule":"ListAny","sum":1881837},{"parent":"FUNC","rule":"ListAppend","sum":1},{"parent":"FUNC","rule":"ListAvg","sum":547883},{"parent":"FUNC","rule":"ListCOncat","sum":2},{"parent":"FUNC","rule":"ListCode","sum":211101},{"parent":"FUNC","rule":"ListCollect","sum":904831},{"parent":"FUNC","rule":"ListConCat","sum":99},{"parent":"FUNC","rule":"ListConcat","sum":5492226},{"parent":"FUNC","rule":"ListCount","sum":1},{"parent":"FUNC","rule":"ListCreate","sum":1959588},{"parent":"FUNC","rule":"ListDistinct","sum":1},{"parent":"FUNC","rule":"ListEnumerate","sum":1403741},{"parent":"FUNC","rule":"ListExtEnd","sum":1},{"parent":"FUNC","rule":"ListExtend","sum":4385295},{"parent":"FUNC","rule":"ListExtendStrict","sum":94001},{"parent":"FUNC","rule":"ListExtract","sum":3364774},{"parent":"FUNC","rule":"ListFILTER","sum":572},{"parent":"FUNC","rule":"ListFIlter","sum":350},{"parent":"FUNC","rule":"ListFLatMap","sum":258},{"parent":"FUNC","rule":"ListFLatten","sum":580},{"parent":"FUNC","rule":"ListFROMRange","sum":5100},{"parent":"FUNC","rule":"ListFilteR","sum":4},{"parent":"FUNC","rule":"ListFilter","sum":17869998},{"parent":"FUNC","rule":"ListFirst","sum":3},{"parent":"FUNC","rule":"ListFlatMap","sum":908417},{"parent":"FUNC","rule":"ListFlatmap","sum":29272},{"parent":"FUNC","rule":"ListFlatten","sum":2832777},{"parent":"FUNC","rule":"ListFold","sum":235244},{"parent":"FUNC","rule":"ListFold1","sum":35769},{"parent":"FUNC","rule":"ListFold1Map","sum":3456},{"parent":"FUNC","rule":"ListFoldMap","sum":43538},{"parent":"FUNC","rule":"ListFromPython","sum":2},{"parent":"FUNC","rule":"ListFromRANGE","sum":23},{"parent":"FUNC","rule":"ListFromRAnge","sum":45},{"parent":"FUNC","rule":"ListFromRange","sum":3104241},{"parent":"FUNC","rule":"ListFromTuple","sum":59596},{"parent":"FUNC","rule":"ListFromTyple","sum":2},{"parent":"FUNC","rule":"ListFromrange","sum":12},{"parent":"FUNC","rule":"ListHAS","sum":364},{"parent":"FUNC","rule":"ListHAs","sum":564},{"parent":"FUNC","rule":"ListHAsItems","sum":26},{"parent":"FUNC","rule":"ListHEAD","sum":2},{"parent":"FUNC","rule":"ListHEad","sum":76},{"parent":"FUNC","rule":"ListHaS","sum":1},{"parent":"FUNC","rule":"ListHas","sum":20698096},{"parent":"FUNC","rule":"ListHasITems","sum":9},{"parent":"FUNC","rule":"ListHasItemhs","sum":1},{"parent":"FUNC","rule":"ListHasItems","sum":5153780},{"parent":"FUNC","rule":"ListHasitems","sum":358},{"parent":"FUNC","rule":"ListHeaD","sum":89},{"parent":"FUNC","rule":"ListHead","sum":10851548},{"parent":"FUNC","rule":"ListINdexOf","sum":2},{"parent":"FUNC","rule":"ListIndex","sum":1},{"parent":"FUNC","rule":"ListIndexOF","sum":10},{"parent":"FUNC","rule":"ListIndexOf","sum":1237904},{"parent":"FUNC","rule":"ListIndexof","sum":19},{"parent":"FUNC","rule":"ListItemType","sum":211208},{"parent":"FUNC","rule":"ListJoin","sum":3},{"parent":"FUNC","rule":"ListJsonDocument","sum":1},{"parent":"FUNC","rule":"ListLAst","sum":10},{"parent":"FUNC","rule":"ListLENGTH","sum":2171},{"parent":"FUNC","rule":"ListLEngth","sum":19},{"parent":"FUNC","rule":"ListLasT","sum":12},{"parent":"FUNC","rule":"ListLast","sum":5994907},{"parent":"FUNC","rule":"ListLeNgth","sum":1},{"parent":"FUNC","rule":"ListLegth","sum":1},{"parent":"FUNC","rule":"ListLenght","sum":1},{"parent":"FUNC","rule":"ListLengtH","sum":2},{"parent":"FUNC","rule":"ListLength","sum":18603350},{"parent":"FUNC","rule":"ListMAP","sum":227},{"parent":"FUNC","rule":"ListMAX","sum":10586},{"parent":"FUNC","rule":"ListMAp","sum":4887},{"parent":"FUNC","rule":"ListMAx","sum":1},{"parent":"FUNC","rule":"ListMIN","sum":52},{"parent":"FUNC","rule":"ListMIn","sum":1},{"parent":"FUNC","rule":"ListMaP","sum":1152},{"parent":"FUNC","rule":"ListMap","sum":35552895},{"parent":"FUNC","rule":"ListMax","sum":1417613},{"parent":"FUNC","rule":"ListMin","sum":816878},{"parent":"FUNC","rule":"ListNOTNull","sum":719},{"parent":"FUNC","rule":"ListNoTNull","sum":17},{"parent":"FUNC","rule":"ListNoTnull","sum":1002},{"parent":"FUNC","rule":"ListNonNull","sum":1},{"parent":"FUNC","rule":"ListNotNULL","sum":30827},{"parent":"FUNC","rule":"ListNotNUll","sum":7688},{"parent":"FUNC","rule":"ListNotNuLL","sum":5},{"parent":"FUNC","rule":"ListNotNul","sum":1},{"parent":"FUNC","rule":"ListNotNulL","sum":3},{"parent":"FUNC","rule":"ListNotNull","sum":9371336},{"parent":"FUNC","rule":"ListNotnull","sum":22},{"parent":"FUNC","rule":"ListREplicate","sum":2},{"parent":"FUNC","rule":"ListRange","sum":4},{"parent":"FUNC","rule":"ListRepeat","sum":1},{"parent":"FUNC","rule":"ListReplicate","sum":953844},{"parent":"FUNC","rule":"ListReverse","sum":1330778},{"parent":"FUNC","rule":"ListSORT","sum":1},{"parent":"FUNC","rule":"ListSORtAsc","sum":26},{"parent":"FUNC","rule":"ListSOrt","sum":3},{"parent":"FUNC","rule":"ListSUM","sum":782},{"parent":"FUNC","rule":"ListSUm","sum":12},{"parent":"FUNC","rule":"ListSample","sum":13},{"parent":"FUNC","rule":"ListSampleN","sum":732},{"parent":"FUNC","rule":"ListShuffle","sum":560},{"parent":"FUNC","rule":"ListShuffleN","sum":1},{"parent":"FUNC","rule":"ListSkip","sum":617922},{"parent":"FUNC","rule":"ListSkipWhile","sum":139031},{"parent":"FUNC","rule":"ListSkipWhileInclusive","sum":8836},{"parent":"FUNC","rule":"ListSort","sum":5024768},{"parent":"FUNC","rule":"ListSortASC","sum":18351},{"parent":"FUNC","rule":"ListSortAsc","sum":488484},{"parent":"FUNC","rule":"ListSortDESC","sum":56},{"parent":"FUNC","rule":"ListSortDEsc","sum":2},{"parent":"FUNC","rule":"ListSortDesc","sum":1140951},{"parent":"FUNC","rule":"ListSortasc","sum":9},{"parent":"FUNC","rule":"ListSortdesc","sum":632},{"parent":"FUNC","rule":"ListSum","sum":1754680},{"parent":"FUNC","rule":"ListTail","sum":1},{"parent":"FUNC","rule":"ListTake","sum":2160879},{"parent":"FUNC","rule":"ListTakeWhile","sum":89576},{"parent":"FUNC","rule":"ListTakeWhileInclusive","sum":2411},{"parent":"FUNC","rule":"ListToTuple","sum":6582},{"parent":"FUNC","rule":"ListTop","sum":2410},{"parent":"FUNC","rule":"ListTopAsc","sum":132},{"parent":"FUNC","rule":"ListTopDESC","sum":1},{"parent":"FUNC","rule":"ListTopDesc","sum":11705},{"parent":"FUNC","rule":"ListTopSort","sum":1088},{"parent":"FUNC","rule":"ListTopSortAsc","sum":102},{"parent":"FUNC","rule":"ListTopSortDesc","sum":60334},{"parent":"FUNC","rule":"ListTopdesc","sum":1},{"parent":"FUNC","rule":"ListType","sum":32511},{"parent":"FUNC","rule":"ListTypeHandle","sum":1},{"parent":"FUNC","rule":"ListUNiq","sum":15},{"parent":"FUNC","rule":"ListUnionALL","sum":128},{"parent":"FUNC","rule":"ListUnionAll","sum":56616},{"parent":"FUNC","rule":"ListUniq","sum":3987721},{"parent":"FUNC","rule":"ListUniqStable","sum":76574},{"parent":"FUNC","rule":"ListZIP","sum":8},{"parent":"FUNC","rule":"ListZIp","sum":1},{"parent":"FUNC","rule":"ListZip","sum":2533519},{"parent":"FUNC","rule":"ListZipALL","sum":291501},{"parent":"FUNC","rule":"ListZipAll","sum":274990},{"parent":"FUNC","rule":"List_FromRange","sum":11},{"parent":"FUNC","rule":"List_Has","sum":23},{"parent":"FUNC","rule":"List_Length","sum":15},{"parent":"FUNC","rule":"List_Sort","sum":10},{"parent":"FUNC","rule":"List_Uniq","sum":1},{"parent":"FUNC","rule":"List_concat","sum":3},{"parent":"FUNC","rule":"List_length","sum":2},{"parent":"FUNC","rule":"List_sort","sum":80},{"parent":"FUNC","rule":"Listall","sum":4458},{"parent":"FUNC","rule":"Listany","sum":38},{"parent":"FUNC","rule":"Listcollect","sum":5312},{"parent":"FUNC","rule":"Listconcat","sum":14827},{"parent":"FUNC","rule":"Listenumerate","sum":3},{"parent":"FUNC","rule":"Listextend","sum":5},{"parent":"FUNC","rule":"Listfilter","sum":259840},{"parent":"FUNC","rule":"Listflatmap","sum":297},{"parent":"FUNC","rule":"Listflatten","sum":33},{"parent":"FUNC","rule":"ListfromRange","sum":31},{"parent":"FUNC","rule":"Listfromrange","sum":125},{"parent":"FUNC","rule":"Listfromtuple","sum":1},{"parent":"FUNC","rule":"Listhas","sum":69101},{"parent":"FUNC","rule":"ListhasItems","sum":259},{"parent":"FUNC","rule":"Listhasitems","sum":525},{"parent":"FUNC","rule":"Listhead","sum":18563},{"parent":"FUNC","rule":"ListindexOf","sum":2326},{"parent":"FUNC","rule":"Listindexof","sum":4},{"parent":"FUNC","rule":"ListlENGTH","sum":1},{"parent":"FUNC","rule":"ListlEngth","sum":2},{"parent":"FUNC","rule":"Listlast","sum":4458},{"parent":"FUNC","rule":"Listlength","sum":10842},{"parent":"FUNC","rule":"Listmap","sum":11243},{"parent":"FUNC","rule":"Listmax","sum":506},{"parent":"FUNC","rule":"Listmin","sum":1623},{"parent":"FUNC","rule":"ListnotNull","sum":38},{"parent":"FUNC","rule":"Listnotnull","sum":8},{"parent":"FUNC","rule":"Listreverse","sum":17},{"parent":"FUNC","rule":"Listskip","sum":148},{"parent":"FUNC","rule":"ListskipWhile","sum":409},{"parent":"FUNC","rule":"Listsort","sum":1096},{"parent":"FUNC","rule":"Listsortasc","sum":1},{"parent":"FUNC","rule":"Listsortdesc","sum":1},{"parent":"FUNC","rule":"Listsum","sum":27},{"parent":"FUNC","rule":"Listtake","sum":20214},{"parent":"FUNC","rule":"ListtakeWhile","sum":2},{"parent":"FUNC","rule":"Listuniq","sum":331},{"parent":"FUNC","rule":"Listzip","sum":789},{"parent":"FUNC","rule":"Listzipall","sum":1},{"parent":"FUNC","rule":"LogHISTOGRAM","sum":7},{"parent":"FUNC","rule":"LogHistogram","sum":284},{"parent":"FUNC","rule":"LogHistogramCDF","sum":6},{"parent":"FUNC","rule":"LogarithmicHISTOGRAM","sum":1},{"parent":"FUNC","rule":"LogarithmicHistogram","sum":614},{"parent":"FUNC","rule":"Logarithmichistogram","sum":20},{"parent":"FUNC","rule":"Lookup","sum":1},{"parent":"FUNC","rule":"MAX","sum":34609087},{"parent":"FUNC","rule":"MAXBY","sum":123},{"parent":"FUNC","rule":"MAXOF","sum":3},{"parent":"FUNC","rule":"MAX_BY","sum":22854976},{"parent":"FUNC","rule":"MAX_By","sum":19},{"parent":"FUNC","rule":"MAX_IF","sum":2},{"parent":"FUNC","rule":"MAX_OF","sum":2199737},{"parent":"FUNC","rule":"MAX_Of","sum":2},{"parent":"FUNC","rule":"MAX_bY","sum":7},{"parent":"FUNC","rule":"MAX_by","sum":10716},{"parent":"FUNC","rule":"MAX_of","sum":554},{"parent":"FUNC","rule":"MAx","sum":283},{"parent":"FUNC","rule":"MEDIAN","sum":920595},{"parent":"FUNC","rule":"MEDiAN","sum":4},{"parent":"FUNC","rule":"MEdian","sum":14},{"parent":"FUNC","rule":"MIN","sum":14670365},{"parent":"FUNC","rule":"MINBY","sum":1908},{"parent":"FUNC","rule":"MIN_BY","sum":5312374},{"parent":"FUNC","rule":"MIN_IF","sum":8},{"parent":"FUNC","rule":"MIN_OF","sum":2272013},{"parent":"FUNC","rule":"MIN_by","sum":1325},{"parent":"FUNC","rule":"MIN_of","sum":5},{"parent":"FUNC","rule":"MIn","sum":194},{"parent":"FUNC","rule":"MIn_OF","sum":3},{"parent":"FUNC","rule":"MODE","sum":901163},{"parent":"FUNC","rule":"MODe","sum":1},{"parent":"FUNC","rule":"MONTH","sum":1},{"parent":"FUNC","rule":"MULTI_AGGREGATE_BY","sum":702789},{"parent":"FUNC","rule":"MaX","sum":7},{"parent":"FUNC","rule":"MakeDate","sum":1},{"parent":"FUNC","rule":"Map","sum":4},{"parent":"FUNC","rule":"Max","sum":382457},{"parent":"FUNC","rule":"MaxBy","sum":5370},{"parent":"FUNC","rule":"MaxOf","sum":204},{"parent":"FUNC","rule":"Max_BY","sum":3200},{"parent":"FUNC","rule":"Max_By","sum":71883},{"parent":"FUNC","rule":"Max_OF","sum":689},{"parent":"FUNC","rule":"Max_Of","sum":657},{"parent":"FUNC","rule":"Max_by","sum":141471},{"parent":"FUNC","rule":"Max_of","sum":3901},{"parent":"FUNC","rule":"Median","sum":19475},{"parent":"FUNC","rule":"MiN","sum":32},{"parent":"FUNC","rule":"Min","sum":193742},{"parent":"FUNC","rule":"MinBy","sum":1221},{"parent":"FUNC","rule":"MinOf","sum":892},{"parent":"FUNC","rule":"Min_BY","sum":451},{"parent":"FUNC","rule":"Min_By","sum":10706},{"parent":"FUNC","rule":"Min_OF","sum":1095},{"parent":"FUNC","rule":"Min_Of","sum":855},{"parent":"FUNC","rule":"Min_by","sum":9075},{"parent":"FUNC","rule":"Min_of","sum":1293},{"parent":"FUNC","rule":"MoDE","sum":1},{"parent":"FUNC","rule":"Mode","sum":14889},{"parent":"FUNC","rule":"Mul","sum":1},{"parent":"FUNC","rule":"MultiAggregateBy","sum":653},{"parent":"FUNC","rule":"Multi_Aggregate_BY","sum":4},{"parent":"FUNC","rule":"Multi_Aggregate_By","sum":1157},{"parent":"FUNC","rule":"Multi_Aggregate_by","sum":4},{"parent":"FUNC","rule":"Multi_aggregate_by","sum":407},{"parent":"FUNC","rule":"NANVL","sum":720232},{"parent":"FUNC","rule":"NOTHING","sum":3334},{"parent":"FUNC","rule":"NOW","sum":2},{"parent":"FUNC","rule":"NOW64","sum":2},{"parent":"FUNC","rule":"NOthing","sum":1},{"parent":"FUNC","rule":"NTH_VALUE","sum":3048},{"parent":"FUNC","rule":"NTILE","sum":1844},{"parent":"FUNC","rule":"NULLIF","sum":3},{"parent":"FUNC","rule":"NVL","sum":17734420},{"parent":"FUNC","rule":"NVl","sum":756},{"parent":"FUNC","rule":"NaNvl","sum":26},{"parent":"FUNC","rule":"NanVL","sum":1},{"parent":"FUNC","rule":"NanVl","sum":3},{"parent":"FUNC","rule":"Nanvl","sum":10867},{"parent":"FUNC","rule":"NothiNG","sum":2},{"parent":"FUNC","rule":"Nothing","sum":814707},{"parent":"FUNC","rule":"NullTypeHandle","sum":2230},{"parent":"FUNC","rule":"Nvl","sum":28806},{"parent":"FUNC","rule":"ON","sum":1},{"parent":"FUNC","rule":"OR","sum":6},{"parent":"FUNC","rule":"OVER","sum":1},{"parent":"FUNC","rule":"OptionalItemType","sum":37237},{"parent":"FUNC","rule":"OptionalType","sum":135500},{"parent":"FUNC","rule":"OptionalTypeHandle","sum":44441},{"parent":"FUNC","rule":"PERCENTILE","sum":30169690},{"parent":"FUNC","rule":"PERCENTIlE","sum":4},{"parent":"FUNC","rule":"PERCENT_RANK","sum":6243},{"parent":"FUNC","rule":"PERCENtILE","sum":1994},{"parent":"FUNC","rule":"PERCEnTILE","sum":1},{"parent":"FUNC","rule":"PICKLE","sum":77},{"parent":"FUNC","rule":"PIckle","sum":7},{"parent":"FUNC","rule":"POPULATION_STDDEV","sum":360},{"parent":"FUNC","rule":"POPULATION_VARIANCE","sum":19},{"parent":"FUNC","rule":"POWER","sum":4},{"parent":"FUNC","rule":"ParseDuration","sum":2},{"parent":"FUNC","rule":"ParseFILE","sum":22},{"parent":"FUNC","rule":"ParseFIle","sum":8},{"parent":"FUNC","rule":"ParseFile","sum":950353},{"parent":"FUNC","rule":"ParseType","sum":467635},{"parent":"FUNC","rule":"ParseTypeHandle","sum":1210152},{"parent":"FUNC","rule":"Parsefile","sum":111},{"parent":"FUNC","rule":"Path","sum":4},{"parent":"FUNC","rule":"PeRCENTILE","sum":365},{"parent":"FUNC","rule":"Percentile","sum":72492},{"parent":"FUNC","rule":"PgArray","sum":17},{"parent":"FUNC","rule":"PgBool","sum":158},{"parent":"FUNC","rule":"PgCall","sum":562},{"parent":"FUNC","rule":"PgCast","sum":5679},{"parent":"FUNC","rule":"PgCircle","sum":5},{"parent":"FUNC","rule":"PgConst","sum":93},{"parent":"FUNC","rule":"PgDate","sum":104},{"parent":"FUNC","rule":"PgGeometry","sum":6},{"parent":"FUNC","rule":"PgInt4","sum":4},{"parent":"FUNC","rule":"PgInt8","sum":1},{"parent":"FUNC","rule":"PgInterval","sum":33},{"parent":"FUNC","rule":"PgOp","sum":1375},{"parent":"FUNC","rule":"PgPoint","sum":76},{"parent":"FUNC","rule":"PgPolygon","sum":517},{"parent":"FUNC","rule":"PgRangeCall","sum":7},{"parent":"FUNC","rule":"PgText","sum":24},{"parent":"FUNC","rule":"PgTimestamp","sum":42},{"parent":"FUNC","rule":"PgVarBit","sum":2},{"parent":"FUNC","rule":"Pickle","sum":118773},{"parent":"FUNC","rule":"QuoteCode","sum":715110},{"parent":"FUNC","rule":"RADIANS","sum":12},{"parent":"FUNC","rule":"RAND","sum":2},{"parent":"FUNC","rule":"RANDOM","sum":488032},{"parent":"FUNC","rule":"RANDOMNUMBER","sum":4004},{"parent":"FUNC","rule":"RANDOMNumber","sum":11},{"parent":"FUNC","rule":"RANDOMUUID","sum":5},{"parent":"FUNC","rule":"RANDOM_NUMBER","sum":83},{"parent":"FUNC","rule":"RANGE","sum":149},{"parent":"FUNC","rule":"RANK","sum":952478},{"parent":"FUNC","rule":"RAndom","sum":7},{"parent":"FUNC","rule":"REGEXP","sum":1},{"parent":"FUNC","rule":"REMOVEMEMBERS","sum":41},{"parent":"FUNC","rule":"REMOVE_mEMBER","sum":6},{"parent":"FUNC","rule":"REPLACE","sum":3},{"parent":"FUNC","rule":"RFIND","sum":3641157},{"parent":"FUNC","rule":"RFind","sum":247072},{"parent":"FUNC","rule":"RIGHT","sum":2},{"parent":"FUNC","rule":"ROUND","sum":10},{"parent":"FUNC","rule":"ROWNUMBER","sum":33},{"parent":"FUNC","rule":"ROW_NUMBER","sum":9443039},{"parent":"FUNC","rule":"ROW_NUMber","sum":11},{"parent":"FUNC","rule":"ROW_Number","sum":8},{"parent":"FUNC","rule":"ROW_nUMBER","sum":1},{"parent":"FUNC","rule":"ROW_nuMBER","sum":4},{"parent":"FUNC","rule":"ROW_number","sum":13426},{"parent":"FUNC","rule":"Rand","sum":1},{"parent":"FUNC","rule":"Random","sum":733297},{"parent":"FUNC","rule":"RandomNUmber","sum":167},{"parent":"FUNC","rule":"RandomNumber","sum":274828},{"parent":"FUNC","rule":"RandomUUID","sum":7899},{"parent":"FUNC","rule":"RandomUUid","sum":32479},{"parent":"FUNC","rule":"RandomUuid","sum":214069},{"parent":"FUNC","rule":"Randomnumber","sum":2},{"parent":"FUNC","rule":"Range","sum":2},{"parent":"FUNC","rule":"Rank","sum":3113},{"parent":"FUNC","rule":"RemoveMEmbers","sum":16},{"parent":"FUNC","rule":"RemoveMember","sum":432646},{"parent":"FUNC","rule":"RemoveMembers","sum":732652},{"parent":"FUNC","rule":"RemoveTimeZone","sum":13},{"parent":"FUNC","rule":"RemoveTimezone","sum":433750},{"parent":"FUNC","rule":"Removemember","sum":686},{"parent":"FUNC","rule":"Removemembers","sum":4},{"parent":"FUNC","rule":"RenameMembers","sum":519393},{"parent":"FUNC","rule":"ReplaceMember","sum":9364},{"parent":"FUNC","rule":"ReprCode","sum":196073},{"parent":"FUNC","rule":"ResourceType","sum":9},{"parent":"FUNC","rule":"Rfind","sum":869},{"parent":"FUNC","rule":"RootAttributes","sum":20},{"parent":"FUNC","rule":"RowNum","sum":1},{"parent":"FUNC","rule":"RowNumber","sum":20754},{"parent":"FUNC","rule":"Row_NUMBER","sum":33},{"parent":"FUNC","rule":"Row_NUmber","sum":16},{"parent":"FUNC","rule":"Row_Number","sum":59846},{"parent":"FUNC","rule":"Row_number","sum":4210},{"parent":"FUNC","rule":"SESSIONWINDOW","sum":131},{"parent":"FUNC","rule":"SETINTERSECTION","sum":20},{"parent":"FUNC","rule":"SIGN","sum":1},{"parent":"FUNC","rule":"SIN","sum":4},{"parent":"FUNC","rule":"SOME","sum":33042966},{"parent":"FUNC","rule":"SOMe","sum":17},{"parent":"FUNC","rule":"SON_VALUE","sum":1},{"parent":"FUNC","rule":"SOmE","sum":3},{"parent":"FUNC","rule":"SOme","sum":13},{"parent":"FUNC","rule":"SPLIT","sum":3},{"parent":"FUNC","rule":"SQL","sum":6},{"parent":"FUNC","rule":"SQRT","sum":2},{"parent":"FUNC","rule":"STARTSWITH","sum":25270},{"parent":"FUNC","rule":"STARTS_WITH","sum":54},{"parent":"FUNC","rule":"STARTsWITH","sum":17},{"parent":"FUNC","rule":"STATICMAP","sum":46},{"parent":"FUNC","rule":"STD","sum":6},{"parent":"FUNC","rule":"STDDEV","sum":400497},{"parent":"FUNC","rule":"STDDEVPOP","sum":2741},{"parent":"FUNC","rule":"STDDEVSAMP","sum":1106},{"parent":"FUNC","rule":"STDDEV_POP","sum":14},{"parent":"FUNC","rule":"STDDEV_POPULATION","sum":18667},{"parent":"FUNC","rule":"STDDEV_SAMP","sum":3263},{"parent":"FUNC","rule":"STDDEV_SAMPLE","sum":9958},{"parent":"FUNC","rule":"STDDev","sum":2},{"parent":"FUNC","rule":"STDdev","sum":4},{"parent":"FUNC","rule":"STRING_SPLIT","sum":1},{"parent":"FUNC","rule":"ST_AsText","sum":3},{"parent":"FUNC","rule":"ST_ClosestPoint","sum":3},{"parent":"FUNC","rule":"ST_DWithin","sum":4},{"parent":"FUNC","rule":"ST_Distance","sum":5},{"parent":"FUNC","rule":"ST_GeomFromGeoHash","sum":1},{"parent":"FUNC","rule":"ST_MakePoint","sum":4},{"parent":"FUNC","rule":"ST_Point","sum":10},{"parent":"FUNC","rule":"ST_PolygonFromText","sum":5},{"parent":"FUNC","rule":"ST_SetSRID","sum":10},{"parent":"FUNC","rule":"ST_Transform","sum":4},{"parent":"FUNC","rule":"STartsWith","sum":2},{"parent":"FUNC","rule":"STdDEV","sum":9},{"parent":"FUNC","rule":"SUBQUERYExtendFor","sum":6},{"parent":"FUNC","rule":"SUBSTIRNG","sum":4},{"parent":"FUNC","rule":"SUBSTRING","sum":29484013},{"parent":"FUNC","rule":"SUBSTRINg","sum":2},{"parent":"FUNC","rule":"SUBSTRInG","sum":4},{"parent":"FUNC","rule":"SUBSTRiNG","sum":2},{"parent":"FUNC","rule":"SUBSTRinG","sum":2},{"parent":"FUNC","rule":"SUBSTRing","sum":227},{"parent":"FUNC","rule":"SUBSTrING","sum":21},{"parent":"FUNC","rule":"SUBSTring","sum":14},{"parent":"FUNC","rule":"SUBStRING","sum":2},{"parent":"FUNC","rule":"SUBString","sum":20},{"parent":"FUNC","rule":"SUBstring","sum":3},{"parent":"FUNC","rule":"SUM","sum":42240466},{"parent":"FUNC","rule":"SUMIF","sum":3293},{"parent":"FUNC","rule":"SUM_","sum":318},{"parent":"FUNC","rule":"SUM_IF","sum":8459280},{"parent":"FUNC","rule":"SUM_If","sum":122},{"parent":"FUNC","rule":"SUM_iF","sum":19},{"parent":"FUNC","rule":"SUM_if","sum":269198},{"parent":"FUNC","rule":"SUbstring","sum":5},{"parent":"FUNC","rule":"SUm","sum":80},{"parent":"FUNC","rule":"SUm_IF","sum":30},{"parent":"FUNC","rule":"SWITCH","sum":2},{"parent":"FUNC","rule":"SecureParam","sum":907220},{"parent":"FUNC","rule":"SessionStart","sum":24180},{"parent":"FUNC","rule":"SessionState","sum":720},{"parent":"FUNC","rule":"SessionWindow","sum":102319},{"parent":"FUNC","rule":"SetBit","sum":43806},{"parent":"FUNC","rule":"SetContains","sum":1},{"parent":"FUNC","rule":"SetCreate","sum":45757},{"parent":"FUNC","rule":"SetDIfference","sum":11},{"parent":"FUNC","rule":"SetDifference","sum":487197},{"parent":"FUNC","rule":"SetINtersection","sum":1},{"parent":"FUNC","rule":"SetIncludes","sum":245705},{"parent":"FUNC","rule":"SetInterSection","sum":21},{"parent":"FUNC","rule":"SetIntersection","sum":1268919},{"parent":"FUNC","rule":"SetIsDisJOINt","sum":7985},{"parent":"FUNC","rule":"SetIsDisJoint","sum":1697},{"parent":"FUNC","rule":"SetIsDisjoint","sum":1251028},{"parent":"FUNC","rule":"SetSymmetricDifference","sum":8897},{"parent":"FUNC","rule":"SetUNION","sum":1},{"parent":"FUNC","rule":"SetUnion","sum":592702},{"parent":"FUNC","rule":"Setintersection","sum":4613},{"parent":"FUNC","rule":"SizeOf","sum":1},{"parent":"FUNC","rule":"Some","sum":2534820},{"parent":"FUNC","rule":"SplitToList","sum":6},{"parent":"FUNC","rule":"SpreadMembers","sum":345800},{"parent":"FUNC","rule":"StablePicke","sum":1},{"parent":"FUNC","rule":"StablePickle","sum":213884},{"parent":"FUNC","rule":"StartSwith","sum":105},{"parent":"FUNC","rule":"StartsWIth","sum":708},{"parent":"FUNC","rule":"StartsWith","sum":5782787},{"parent":"FUNC","rule":"Startswith","sum":20204},{"parent":"FUNC","rule":"StaticFold","sum":311},{"parent":"FUNC","rule":"StaticMap","sum":679859},{"parent":"FUNC","rule":"StaticZip","sum":15268},{"parent":"FUNC","rule":"Staticmap","sum":2},{"parent":"FUNC","rule":"StdDev","sum":33},{"parent":"FUNC","rule":"Stddev","sum":43},{"parent":"FUNC","rule":"StreamItemType","sum":5680},{"parent":"FUNC","rule":"StreamType","sum":79441},{"parent":"FUNC","rule":"StreamTypeHandle","sum":17},{"parent":"FUNC","rule":"String","sum":34247},{"parent":"FUNC","rule":"StringLength","sum":5},{"parent":"FUNC","rule":"StringSplitToList","sum":4},{"parent":"FUNC","rule":"StructDifference","sum":241},{"parent":"FUNC","rule":"StructIntersection","sum":859},{"parent":"FUNC","rule":"StructMemberType","sum":20787},{"parent":"FUNC","rule":"StructMembers","sum":974117},{"parent":"FUNC","rule":"StructSymmetricDifference","sum":172},{"parent":"FUNC","rule":"StructType","sum":17912},{"parent":"FUNC","rule":"StructTypeComponents","sum":100573},{"parent":"FUNC","rule":"StructTypeHandle","sum":88467},{"parent":"FUNC","rule":"StructUnion","sum":106490},{"parent":"FUNC","rule":"SuBSTRING","sum":1},{"parent":"FUNC","rule":"SuM","sum":9},{"parent":"FUNC","rule":"SuM_IF","sum":4},{"parent":"FUNC","rule":"SubQueryExtendFor","sum":3},{"parent":"FUNC","rule":"SubSTRING","sum":3},{"parent":"FUNC","rule":"SubString","sum":27710},{"parent":"FUNC","rule":"SubqueryAssumeOrderBy","sum":821},{"parent":"FUNC","rule":"SubqueryExtend","sum":37579},{"parent":"FUNC","rule":"SubqueryExtendFor","sum":769342},{"parent":"FUNC","rule":"SubqueryMerge","sum":19},{"parent":"FUNC","rule":"SubqueryMergeFor","sum":36687},{"parent":"FUNC","rule":"SubqueryOrderBy","sum":186437},{"parent":"FUNC","rule":"SubqueryUnionALLFor","sum":9},{"parent":"FUNC","rule":"SubqueryUnionALlFor","sum":82},{"parent":"FUNC","rule":"SubqueryUnionAll","sum":26085},{"parent":"FUNC","rule":"SubqueryUnionAllFor","sum":143430},{"parent":"FUNC","rule":"SubqueryUnionAllfor","sum":385},{"parent":"FUNC","rule":"SubqueryUnionMerge","sum":30557},{"parent":"FUNC","rule":"SubqueryUnionMergeFor","sum":73804},{"parent":"FUNC","rule":"SubsTRING","sum":3},{"parent":"FUNC","rule":"Substring","sum":2911730},{"parent":"FUNC","rule":"Sum","sum":454844},{"parent":"FUNC","rule":"SumIf","sum":1597},{"parent":"FUNC","rule":"Sum_IF","sum":85},{"parent":"FUNC","rule":"Sum_If","sum":13381},{"parent":"FUNC","rule":"Sum_if","sum":53747},{"parent":"FUNC","rule":"TABLENAME","sum":12256},{"parent":"FUNC","rule":"TABLEPATH","sum":264},{"parent":"FUNC","rule":"TABLERECORDINDEX","sum":45},{"parent":"FUNC","rule":"TABLEROW","sum":1251},{"parent":"FUNC","rule":"TABLE_NAME","sum":147},{"parent":"FUNC","rule":"TABLE_PATH","sum":53},{"parent":"FUNC","rule":"TABLE_ROW","sum":124},{"parent":"FUNC","rule":"TABLEname","sum":4},{"parent":"FUNC","rule":"TAbleName","sum":71},{"parent":"FUNC","rule":"TAblePath","sum":2},{"parent":"FUNC","rule":"TAbleRow","sum":25},{"parent":"FUNC","rule":"TAblename","sum":1},{"parent":"FUNC","rule":"TESTBIT","sum":3},{"parent":"FUNC","rule":"TEstBit","sum":1},{"parent":"FUNC","rule":"TIMESTAMP","sum":422},{"parent":"FUNC","rule":"TIMESTAMPDIFF","sum":2},{"parent":"FUNC","rule":"TIMESTAMP_SECONDS","sum":1},{"parent":"FUNC","rule":"TOBytes","sum":1},{"parent":"FUNC","rule":"TODICT","sum":21},{"parent":"FUNC","rule":"TODIct","sum":1},{"parent":"FUNC","rule":"TOP","sum":502571},{"parent":"FUNC","rule":"TOPBY","sum":1},{"parent":"FUNC","rule":"TOPFREQ","sum":509195},{"parent":"FUNC","rule":"TOPFreq","sum":3},{"parent":"FUNC","rule":"TOP_BY","sum":1779613},{"parent":"FUNC","rule":"TOP_FREQ","sum":46},{"parent":"FUNC","rule":"TOP_by","sum":26},{"parent":"FUNC","rule":"TOSET","sum":41},{"parent":"FUNC","rule":"TOSet","sum":787},{"parent":"FUNC","rule":"TO_NUMBER","sum":14},{"parent":"FUNC","rule":"TO_TIMESTAMP","sum":1},{"parent":"FUNC","rule":"TObytes","sum":3},{"parent":"FUNC","rule":"TRY_MEMBER","sum":37},{"parent":"FUNC","rule":"TYPEOF","sum":1},{"parent":"FUNC","rule":"TYPEof","sum":28},{"parent":"FUNC","rule":"TZDateTime","sum":139},{"parent":"FUNC","rule":"TZDatetime","sum":3},{"parent":"FUNC","rule":"TZTimestamp","sum":64},{"parent":"FUNC","rule":"TabLeName","sum":1},{"parent":"FUNC","rule":"TableNAME","sum":3},{"parent":"FUNC","rule":"TableNAme","sum":1751},{"parent":"FUNC","rule":"TableNamE","sum":2},{"parent":"FUNC","rule":"TableName","sum":15099355},{"parent":"FUNC","rule":"TablePATH","sum":1},{"parent":"FUNC","rule":"TablePAth","sum":5},{"parent":"FUNC","rule":"TablePath","sum":1504606},{"parent":"FUNC","rule":"TableROW","sum":4},{"parent":"FUNC","rule":"TableROw","sum":19},{"parent":"FUNC","rule":"TableRecordINdex","sum":4},{"parent":"FUNC","rule":"TableRecordIndex","sum":2312988},{"parent":"FUNC","rule":"TableRedordIndex","sum":1},{"parent":"FUNC","rule":"TableRow","sum":27122572},{"parent":"FUNC","rule":"TableRowIndex","sum":1},{"parent":"FUNC","rule":"TableRows","sum":1703144},{"parent":"FUNC","rule":"Table_Name","sum":55},{"parent":"FUNC","rule":"Table_Row","sum":5},{"parent":"FUNC","rule":"Table_name","sum":73},{"parent":"FUNC","rule":"Table_path","sum":3},{"parent":"FUNC","rule":"Tablename","sum":104553},{"parent":"FUNC","rule":"Tablepath","sum":193},{"parent":"FUNC","rule":"TablerRow","sum":1},{"parent":"FUNC","rule":"TablerecordIndex","sum":1},{"parent":"FUNC","rule":"Tablerecordindex","sum":3},{"parent":"FUNC","rule":"Tablerow","sum":26494},{"parent":"FUNC","rule":"TestBit","sum":255149},{"parent":"FUNC","rule":"Text","sum":20},{"parent":"FUNC","rule":"TimeStamp","sum":4378},{"parent":"FUNC","rule":"Timestamp","sum":1351497},{"parent":"FUNC","rule":"Timestamp64","sum":59},{"parent":"FUNC","rule":"ToBytes","sum":6690210},{"parent":"FUNC","rule":"ToDIct","sum":253},{"parent":"FUNC","rule":"ToDict","sum":6425145},{"parent":"FUNC","rule":"ToList","sum":3},{"parent":"FUNC","rule":"ToLower","sum":4},{"parent":"FUNC","rule":"ToMilliseconds","sum":2},{"parent":"FUNC","rule":"ToMultiDict","sum":338874},{"parent":"FUNC","rule":"ToPg","sum":3225},{"parent":"FUNC","rule":"ToSET","sum":80},{"parent":"FUNC","rule":"ToSet","sum":5487098},{"parent":"FUNC","rule":"ToSortedDict","sum":1116},{"parent":"FUNC","rule":"ToStartOfMonth","sum":4},{"parent":"FUNC","rule":"To_bytes","sum":3},{"parent":"FUNC","rule":"Todict","sum":250},{"parent":"FUNC","rule":"Top","sum":849},{"parent":"FUNC","rule":"TopBy","sum":77},{"parent":"FUNC","rule":"TopFreq","sum":13934},{"parent":"FUNC","rule":"Top_BY","sum":22},{"parent":"FUNC","rule":"Top_By","sum":114},{"parent":"FUNC","rule":"Top_by","sum":122},{"parent":"FUNC","rule":"Topfreq","sum":28},{"parent":"FUNC","rule":"Toset","sum":2324},{"parent":"FUNC","rule":"TryMember","sum":16823743},{"parent":"FUNC","rule":"Trymember","sum":36926},{"parent":"FUNC","rule":"TupleElementType","sum":7608},{"parent":"FUNC","rule":"TupleType","sum":2404},{"parent":"FUNC","rule":"TupleTypeComponents","sum":58},{"parent":"FUNC","rule":"TupleTypeHandle","sum":5566},{"parent":"FUNC","rule":"TypeHandle","sum":161528},{"parent":"FUNC","rule":"TypeKind","sum":55189},{"parent":"FUNC","rule":"TypeOF","sum":37},{"parent":"FUNC","rule":"TypeOf","sum":854631},{"parent":"FUNC","rule":"Typeof","sum":78},{"parent":"FUNC","rule":"TzDate","sum":670},{"parent":"FUNC","rule":"TzDate32","sum":7},{"parent":"FUNC","rule":"TzDateTime","sum":24903},{"parent":"FUNC","rule":"TzDateTime64","sum":7},{"parent":"FUNC","rule":"TzDatetime","sum":46413},{"parent":"FUNC","rule":"TzTimeStamp","sum":4},{"parent":"FUNC","rule":"TzTimestamp","sum":343344},{"parent":"FUNC","rule":"TzTimestamp64","sum":7},{"parent":"FUNC","rule":"UBSTRING","sum":1},{"parent":"FUNC","rule":"UDAF","sum":141570},{"parent":"FUNC","rule":"UDF","sum":1919},{"parent":"FUNC","rule":"UINT32","sum":4},{"parent":"FUNC","rule":"UINT64","sum":6},{"parent":"FUNC","rule":"UInt32","sum":111517},{"parent":"FUNC","rule":"UInt64","sum":829},{"parent":"FUNC","rule":"UInt8","sum":231},{"parent":"FUNC","rule":"UNIQ","sum":1},{"parent":"FUNC","rule":"UNPICKLE","sum":28},{"parent":"FUNC","rule":"UNTAG","sum":18},{"parent":"FUNC","rule":"UNWRAP","sum":14135041},{"parent":"FUNC","rule":"UNWRAp","sum":1},{"parent":"FUNC","rule":"UNWRaP","sum":2},{"parent":"FUNC","rule":"UNWRap","sum":10968},{"parent":"FUNC","rule":"UNWrAP","sum":18},{"parent":"FUNC","rule":"UNWraP","sum":8},{"parent":"FUNC","rule":"UNWrap","sum":4},{"parent":"FUNC","rule":"UNwRAP","sum":6},{"parent":"FUNC","rule":"UNwrap","sum":1417},{"parent":"FUNC","rule":"USING","sum":8},{"parent":"FUNC","rule":"UTF8","sum":333224},{"parent":"FUNC","rule":"UUID","sum":1},{"parent":"FUNC","rule":"Udf","sum":301959},{"parent":"FUNC","rule":"Uint16","sum":83},{"parent":"FUNC","rule":"Uint32","sum":333513},{"parent":"FUNC","rule":"Uint64","sum":11950},{"parent":"FUNC","rule":"Uint8","sum":2951},{"parent":"FUNC","rule":"UnTag","sum":55},{"parent":"FUNC","rule":"UnWRAP","sum":10},{"parent":"FUNC","rule":"UnWrAp","sum":1},{"parent":"FUNC","rule":"UnWrap","sum":1069425},{"parent":"FUNC","rule":"UnionAll","sum":3},{"parent":"FUNC","rule":"Unpickle","sum":178},{"parent":"FUNC","rule":"Untag","sum":16286},{"parent":"FUNC","rule":"Unwarp","sum":1},{"parent":"FUNC","rule":"Unwrap","sum":35848836},{"parent":"FUNC","rule":"UtcCurrentDatetime","sum":8},{"parent":"FUNC","rule":"Utf8","sum":40749},{"parent":"FUNC","rule":"Uuid","sum":450},{"parent":"FUNC","rule":"VALUES","sum":14},{"parent":"FUNC","rule":"VARIANCE","sum":31007},{"parent":"FUNC","rule":"VARIANCE_POPULATION","sum":3039},{"parent":"FUNC","rule":"VARIANCE_SAMPLE","sum":1223},{"parent":"FUNC","rule":"VARP","sum":146},{"parent":"FUNC","rule":"VARPOP","sum":15},{"parent":"FUNC","rule":"VAR_POP","sum":4},{"parent":"FUNC","rule":"VAR_SAMP","sum":44},{"parent":"FUNC","rule":"VERSION","sum":2},{"parent":"FUNC","rule":"Variance","sum":1145},{"parent":"FUNC","rule":"Variance_SAMPLE","sum":30},{"parent":"FUNC","rule":"Variance_Sample","sum":23},{"parent":"FUNC","rule":"Variance_sample","sum":24},{"parent":"FUNC","rule":"VariantType","sum":3129},{"parent":"FUNC","rule":"VariantTypeHandle","sum":8},{"parent":"FUNC","rule":"VariantUnderlyingType","sum":6499},{"parent":"FUNC","rule":"Version","sum":3},{"parent":"FUNC","rule":"Visit","sum":28},{"parent":"FUNC","rule":"Void","sum":91746},{"parent":"FUNC","rule":"WEAKFIELD","sum":837},{"parent":"FUNC","rule":"WEAK_FIELD","sum":364},{"parent":"FUNC","rule":"WEakField","sum":2},{"parent":"FUNC","rule":"Way","sum":9492},{"parent":"FUNC","rule":"WeakFIeld","sum":43},{"parent":"FUNC","rule":"WeakField","sum":21250353},{"parent":"FUNC","rule":"WeakFiled","sum":2},{"parent":"FUNC","rule":"Weakfield","sum":1953},{"parent":"FUNC","rule":"WorldCode","sum":396},{"parent":"FUNC","rule":"YPathDouble","sum":4},{"parent":"FUNC","rule":"YPathExtract","sum":4},{"parent":"FUNC","rule":"YPathInt64","sum":6},{"parent":"FUNC","rule":"YPathString","sum":4},{"parent":"FUNC","rule":"YSON","sum":752},{"parent":"FUNC","rule":"YSONExtractString","sum":6},{"parent":"FUNC","rule":"Yson","sum":613122},{"parent":"FUNC","rule":"aGGREGATE_LIST","sum":13},{"parent":"FUNC","rule":"aGGREGATE_LIST_DISTINCT","sum":4},{"parent":"FUNC","rule":"aGG_LIST","sum":2},{"parent":"FUNC","rule":"aGG_LIST_DISTINCT","sum":10},{"parent":"FUNC","rule":"aSSTRUCT","sum":1},{"parent":"FUNC","rule":"aSTuple","sum":3},{"parent":"FUNC","rule":"aVG","sum":2},{"parent":"FUNC","rule":"abs","sum":1555178},{"parent":"FUNC","rule":"addMember","sum":2634},{"parent":"FUNC","rule":"addTimezone","sum":780},{"parent":"FUNC","rule":"age","sum":2},{"parent":"FUNC","rule":"aggList","sum":265},{"parent":"FUNC","rule":"agg_LIST","sum":76},{"parent":"FUNC","rule":"agg_LIST_DISTINCT","sum":1},{"parent":"FUNC","rule":"agg_List","sum":546},{"parent":"FUNC","rule":"agg_List_distinct","sum":24},{"parent":"FUNC","rule":"agg_list","sum":1279120},{"parent":"FUNC","rule":"agg_list_DISTINCT","sum":2},{"parent":"FUNC","rule":"agg_list_Distinct","sum":1},{"parent":"FUNC","rule":"agg_list_distinct","sum":435905},{"parent":"FUNC","rule":"agg_set","sum":1},{"parent":"FUNC","rule":"agglist","sum":130},{"parent":"FUNC","rule":"agglistdistinct","sum":51},{"parent":"FUNC","rule":"aggr_list","sum":2599},{"parent":"FUNC","rule":"aggr_list_distinct","sum":18},{"parent":"FUNC","rule":"aggr_set","sum":2},{"parent":"FUNC","rule":"aggregATE_LIST","sum":16},{"parent":"FUNC","rule":"aggregateList","sum":392},{"parent":"FUNC","rule":"aggregateListDistinct","sum":38},{"parent":"FUNC","rule":"aggregate_List","sum":1000},{"parent":"FUNC","rule":"aggregate_List_Distinct","sum":8},{"parent":"FUNC","rule":"aggregate_List_distinct","sum":10},{"parent":"FUNC","rule":"aggregate_by","sum":369405},{"parent":"FUNC","rule":"aggregate_list","sum":2505307},{"parent":"FUNC","rule":"aggregate_list_","sum":2},{"parent":"FUNC","rule":"aggregate_list_DISTINCT","sum":1815},{"parent":"FUNC","rule":"aggregate_list_Distinct","sum":27},{"parent":"FUNC","rule":"aggregate_list_distinct","sum":947138},{"parent":"FUNC","rule":"aggregatelist","sum":569},{"parent":"FUNC","rule":"aggregatetransforminput","sum":1},{"parent":"FUNC","rule":"aggregationFactory","sum":154},{"parent":"FUNC","rule":"aggregation_factory","sum":8723},{"parent":"FUNC","rule":"aggregationfactory","sum":83},{"parent":"FUNC","rule":"agregate_list_distinct","sum":1},{"parent":"FUNC","rule":"and","sum":5},{"parent":"FUNC","rule":"anyLast","sum":8},{"parent":"FUNC","rule":"argMax","sum":15},{"parent":"FUNC","rule":"argMin","sum":3},{"parent":"FUNC","rule":"arrayElement","sum":1},{"parent":"FUNC","rule":"arrayJoin","sum":10},{"parent":"FUNC","rule":"arrayMax","sum":4},{"parent":"FUNC","rule":"array_agg","sum":5},{"parent":"FUNC","rule":"array_to_string","sum":2},{"parent":"FUNC","rule":"asDict","sum":3798},{"parent":"FUNC","rule":"asLIST","sum":50},{"parent":"FUNC","rule":"asList","sum":177274},{"parent":"FUNC","rule":"asSet","sum":1986},{"parent":"FUNC","rule":"asStruct","sum":125755},{"parent":"FUNC","rule":"asTUPLE","sum":1},{"parent":"FUNC","rule":"asTagged","sum":2255},{"parent":"FUNC","rule":"asTuple","sum":83172},{"parent":"FUNC","rule":"asVariant","sum":10},{"parent":"FUNC","rule":"as_dict","sum":4},{"parent":"FUNC","rule":"as_list","sum":77},{"parent":"FUNC","rule":"as_struct","sum":122},{"parent":"FUNC","rule":"as_table","sum":30},{"parent":"FUNC","rule":"as_tagged","sum":1},{"parent":"FUNC","rule":"as_tuple","sum":372},{"parent":"FUNC","rule":"asdict","sum":3802},{"parent":"FUNC","rule":"asenum","sum":13},{"parent":"FUNC","rule":"aslist","sum":164809},{"parent":"FUNC","rule":"assessments_integralListReverse","sum":2},{"parent":"FUNC","rule":"asset","sum":1126},{"parent":"FUNC","rule":"asstruct","sum":13075},{"parent":"FUNC","rule":"assumeNotNull","sum":3},{"parent":"FUNC","rule":"astagged","sum":1352},{"parent":"FUNC","rule":"astuple","sum":30810},{"parent":"FUNC","rule":"asvariant","sum":3},{"parent":"FUNC","rule":"atan2","sum":4},{"parent":"FUNC","rule":"avG","sum":52},{"parent":"FUNC","rule":"avg","sum":6034082},{"parent":"FUNC","rule":"avgIf","sum":19746},{"parent":"FUNC","rule":"avg_","sum":1},{"parent":"FUNC","rule":"avg_IF","sum":155},{"parent":"FUNC","rule":"avg_If","sum":153},{"parent":"FUNC","rule":"avg_if","sum":499296},{"parent":"FUNC","rule":"ax","sum":13},{"parent":"FUNC","rule":"bit_or","sum":26643},{"parent":"FUNC","rule":"bool","sum":274},{"parent":"FUNC","rule":"bool_and","sum":67987},{"parent":"FUNC","rule":"bool_or","sum":234728},{"parent":"FUNC","rule":"bool_xor","sum":2},{"parent":"FUNC","rule":"bottom","sum":10181},{"parent":"FUNC","rule":"bottom_by","sum":334498},{"parent":"FUNC","rule":"business_id","sum":1},{"parent":"FUNC","rule":"bytes","sum":2},{"parent":"FUNC","rule":"cOALESCE","sum":36},{"parent":"FUNC","rule":"cOUNT","sum":64},{"parent":"FUNC","rule":"cOUNT_IF","sum":40},{"parent":"FUNC","rule":"cOunt","sum":2},{"parent":"FUNC","rule":"ceil","sum":1},{"parent":"FUNC","rule":"char_LENGTH","sum":2},{"parent":"FUNC","rule":"char_length","sum":18},{"parent":"FUNC","rule":"check_google_id","sum":1},{"parent":"FUNC","rule":"choosemembers","sum":5},{"parent":"FUNC","rule":"client_id","sum":1},{"parent":"FUNC","rule":"cnt","sum":2},{"parent":"FUNC","rule":"coALESCE","sum":14},{"parent":"FUNC","rule":"coUNT","sum":3},{"parent":"FUNC","rule":"coUNt","sum":3},{"parent":"FUNC","rule":"coalESCE","sum":40},{"parent":"FUNC","rule":"coalescE","sum":1},{"parent":"FUNC","rule":"coalesce","sum":25106027},{"parent":"FUNC","rule":"coalescue","sum":2},{"parent":"FUNC","rule":"coalsece","sum":1},{"parent":"FUNC","rule":"combinemembers","sum":5},{"parent":"FUNC","rule":"concat","sum":26},{"parent":"FUNC","rule":"conunt","sum":1},{"parent":"FUNC","rule":"convert_to_360","sum":2},{"parent":"FUNC","rule":"corr","sum":716},{"parent":"FUNC","rule":"correlation","sum":3826},{"parent":"FUNC","rule":"cos","sum":8},{"parent":"FUNC","rule":"couNT","sum":1},{"parent":"FUNC","rule":"couNT_IF","sum":7},{"parent":"FUNC","rule":"counT","sum":24},{"parent":"FUNC","rule":"count","sum":38679935},{"parent":"FUNC","rule":"countDistinct","sum":1},{"parent":"FUNC","rule":"countDistinctEstimate","sum":263774},{"parent":"FUNC","rule":"countIF","sum":8273},{"parent":"FUNC","rule":"countIf","sum":1386283},{"parent":"FUNC","rule":"count_","sum":541},{"parent":"FUNC","rule":"count_IF","sum":34538},{"parent":"FUNC","rule":"count_If","sum":26678},{"parent":"FUNC","rule":"count_distinct_estimate","sum":33},{"parent":"FUNC","rule":"count_if","sum":18959232},{"parent":"FUNC","rule":"countdistinctEstimate","sum":1713},{"parent":"FUNC","rule":"countdistinctestimate","sum":2851},{"parent":"FUNC","rule":"countif","sum":20338},{"parent":"FUNC","rule":"covar","sum":247},{"parent":"FUNC","rule":"covariance","sum":292},{"parent":"FUNC","rule":"covariance_sample","sum":165},{"parent":"FUNC","rule":"cpunt","sum":1},{"parent":"FUNC","rule":"cume_dist","sum":69},{"parent":"FUNC","rule":"currentTzDate","sum":3922},{"parent":"FUNC","rule":"currentTzTimestamp","sum":53},{"parent":"FUNC","rule":"currentUTCDATETIME","sum":7},{"parent":"FUNC","rule":"currentUTCDate","sum":663},{"parent":"FUNC","rule":"currentUTCDateTime","sum":318},{"parent":"FUNC","rule":"currentUTCDatetime","sum":3},{"parent":"FUNC","rule":"currentUTCdate","sum":370},{"parent":"FUNC","rule":"currentUTCdatetime","sum":20},{"parent":"FUNC","rule":"currentUTcdate","sum":1343},{"parent":"FUNC","rule":"currentUtcDate","sum":6457},{"parent":"FUNC","rule":"currentUtcDateTime","sum":14876},{"parent":"FUNC","rule":"currentUtcDatetime","sum":2420},{"parent":"FUNC","rule":"currentUtcTimestamp","sum":197},{"parent":"FUNC","rule":"current_utc_timestamp","sum":2},{"parent":"FUNC","rule":"currenttzdate","sum":418},{"parent":"FUNC","rule":"currenttzdatetime","sum":257},{"parent":"FUNC","rule":"currenttztimestamp","sum":47},{"parent":"FUNC","rule":"currentutcDateTime","sum":3},{"parent":"FUNC","rule":"currentutcdate","sum":119245},{"parent":"FUNC","rule":"currentutcdatetime","sum":58922},{"parent":"FUNC","rule":"currentutctimestamp","sum":48538},{"parent":"FUNC","rule":"d","sum":1},{"parent":"FUNC","rule":"dATE","sum":4},{"parent":"FUNC","rule":"date","sum":416640},{"parent":"FUNC","rule":"date32","sum":11},{"parent":"FUNC","rule":"dateDiff","sum":1},{"parent":"FUNC","rule":"dateNow","sum":2},{"parent":"FUNC","rule":"dateTIME","sum":2},{"parent":"FUNC","rule":"dateTime","sum":10},{"parent":"FUNC","rule":"date_add","sum":8},{"parent":"FUNC","rule":"date_format","sum":2},{"parent":"FUNC","rule":"date_sub","sum":2},{"parent":"FUNC","rule":"dateadd","sum":1},{"parent":"FUNC","rule":"datediff","sum":4},{"parent":"FUNC","rule":"datetime","sum":11489},{"parent":"FUNC","rule":"datetime64","sum":19},{"parent":"FUNC","rule":"decimal","sum":342},{"parent":"FUNC","rule":"dense_RANK","sum":42},{"parent":"FUNC","rule":"dense_rank","sum":46459},{"parent":"FUNC","rule":"dictAggregate","sum":71},{"parent":"FUNC","rule":"dictContains","sum":7},{"parent":"FUNC","rule":"dictGetString","sum":1},{"parent":"FUNC","rule":"dictItems","sum":8586},{"parent":"FUNC","rule":"dictKeys","sum":1199},{"parent":"FUNC","rule":"dictLength","sum":104},{"parent":"FUNC","rule":"dictLookUp","sum":9267},{"parent":"FUNC","rule":"dictLookup","sum":678},{"parent":"FUNC","rule":"dictPayloads","sum":90},{"parent":"FUNC","rule":"dict_keys","sum":8695},{"parent":"FUNC","rule":"dictcontains","sum":346},{"parent":"FUNC","rule":"dictcreate","sum":2},{"parent":"FUNC","rule":"dicthasitems","sum":24},{"parent":"FUNC","rule":"dictitems","sum":2584},{"parent":"FUNC","rule":"dictkeys","sum":900},{"parent":"FUNC","rule":"dictlength","sum":6528},{"parent":"FUNC","rule":"dictlookup","sum":1613},{"parent":"FUNC","rule":"dictpayloads","sum":113},{"parent":"FUNC","rule":"disctinct","sum":2},{"parent":"FUNC","rule":"dol_show1","sum":1},{"parent":"FUNC","rule":"double","sum":134},{"parent":"FUNC","rule":"dynumber","sum":12},{"parent":"FUNC","rule":"each","sum":1},{"parent":"FUNC","rule":"empty","sum":3},{"parent":"FUNC","rule":"emptylist","sum":1},{"parent":"FUNC","rule":"endsWith","sum":2138},{"parent":"FUNC","rule":"endswith","sum":32167},{"parent":"FUNC","rule":"ensure","sum":411863},{"parent":"FUNC","rule":"ensuretype","sum":706},{"parent":"FUNC","rule":"evaluateCode","sum":47},{"parent":"FUNC","rule":"evaluateExpr","sum":304},{"parent":"FUNC","rule":"expandstruct","sum":20},{"parent":"FUNC","rule":"f","sum":1},{"parent":"FUNC","rule":"file_content","sum":10},{"parent":"FUNC","rule":"file_path","sum":1},{"parent":"FUNC","rule":"filecontent","sum":603},{"parent":"FUNC","rule":"filepath","sum":934},{"parent":"FUNC","rule":"filter","sum":2},{"parent":"FUNC","rule":"find","sum":4100173},{"parent":"FUNC","rule":"first_VALUE","sum":19},{"parent":"FUNC","rule":"first_route_timestamp","sum":1},{"parent":"FUNC","rule":"first_value","sum":1145796},{"parent":"FUNC","rule":"flatten","sum":1},{"parent":"FUNC","rule":"float","sum":23124},{"parent":"FUNC","rule":"floor","sum":1},{"parent":"FUNC","rule":"forceremovemember","sum":373},{"parent":"FUNC","rule":"format","sum":1},{"parent":"FUNC","rule":"formatType","sum":8},{"parent":"FUNC","rule":"formattype","sum":146},{"parent":"FUNC","rule":"fromBytes","sum":13},{"parent":"FUNC","rule":"fromPg","sum":141},{"parent":"FUNC","rule":"fromUnixTimestamp64Micro","sum":1},{"parent":"FUNC","rule":"from_bytes","sum":2},{"parent":"FUNC","rule":"frombytes","sum":47},{"parent":"FUNC","rule":"frompg","sum":134},{"parent":"FUNC","rule":"gatherMembers","sum":67},{"parent":"FUNC","rule":"gathermembers","sum":7},{"parent":"FUNC","rule":"get_auto_label","sum":1},{"parent":"FUNC","rule":"get_html","sum":1},{"parent":"FUNC","rule":"get_is_in_collection_feature","sum":1},{"parent":"FUNC","rule":"get_metrika_bro","sum":1},{"parent":"FUNC","rule":"get_pay_processing","sum":2},{"parent":"FUNC","rule":"get_post_profiles","sum":1},{"parent":"FUNC","rule":"get_rewrite_prompt","sum":1},{"parent":"FUNC","rule":"get_support_line","sum":1},{"parent":"FUNC","rule":"get_test_id","sum":7},{"parent":"FUNC","rule":"getdate","sum":2},{"parent":"FUNC","rule":"greatest","sum":317200},{"parent":"FUNC","rule":"groupArray","sum":4},{"parent":"FUNC","rule":"groupUniqArray","sum":2},{"parent":"FUNC","rule":"grouping","sum":17651},{"parent":"FUNC","rule":"hISTOGRAM","sum":2},{"parent":"FUNC","rule":"has","sum":20},{"parent":"FUNC","rule":"histOGRAM","sum":4},{"parent":"FUNC","rule":"histograM","sum":359},{"parent":"FUNC","rule":"histogram","sum":52870},{"parent":"FUNC","rule":"histogramcdf","sum":84},{"parent":"FUNC","rule":"hll","sum":82099},{"parent":"FUNC","rule":"iF","sum":2697},{"parent":"FUNC","rule":"iNtErVaL","sum":1},{"parent":"FUNC","rule":"if","sum":43313494},{"parent":"FUNC","rule":"ifNull","sum":6},{"parent":"FUNC","rule":"in","sum":10},{"parent":"FUNC","rule":"indexOf","sum":14},{"parent":"FUNC","rule":"instanceof","sum":55},{"parent":"FUNC","rule":"instr","sum":1},{"parent":"FUNC","rule":"int","sum":32691},{"parent":"FUNC","rule":"int32","sum":2},{"parent":"FUNC","rule":"int64","sum":19},{"parent":"FUNC","rule":"int8","sum":2},{"parent":"FUNC","rule":"intervaL","sum":9673},{"parent":"FUNC","rule":"interval","sum":1809588},{"parent":"FUNC","rule":"interval64","sum":7},{"parent":"FUNC","rule":"isNull","sum":7},{"parent":"FUNC","rule":"is_allowed_in_kz","sum":2},{"parent":"FUNC","rule":"is_valid_intent","sum":4},{"parent":"FUNC","rule":"is_valid_organic","sum":4},{"parent":"FUNC","rule":"istLast","sum":1},{"parent":"FUNC","rule":"isum","sum":6},{"parent":"FUNC","rule":"joinTableRow","sum":5},{"parent":"FUNC","rule":"jointablerow","sum":216},{"parent":"FUNC","rule":"json","sum":5659},{"parent":"FUNC","rule":"json_extract","sum":3},{"parent":"FUNC","rule":"json_object_agg","sum":1},{"parent":"FUNC","rule":"jsondocument","sum":6},{"parent":"FUNC","rule":"just","sum":248704},{"parent":"FUNC","rule":"lAG","sum":2220},{"parent":"FUNC","rule":"lEAD","sum":6802},{"parent":"FUNC","rule":"lEN","sum":30},{"parent":"FUNC","rule":"lINEARHISTOGRAM","sum":115},{"parent":"FUNC","rule":"lISTlENGTH","sum":2},{"parent":"FUNC","rule":"lISTlength","sum":1},{"parent":"FUNC","rule":"lag","sum":1013952},{"parent":"FUNC","rule":"last_VALUE","sum":14},{"parent":"FUNC","rule":"last_value","sum":1055540},{"parent":"FUNC","rule":"lead","sum":932701},{"parent":"FUNC","rule":"least","sum":378147},{"parent":"FUNC","rule":"len","sum":713279},{"parent":"FUNC","rule":"lenGTH","sum":1},{"parent":"FUNC","rule":"lenght","sum":1},{"parent":"FUNC","rule":"lengtH","sum":2},{"parent":"FUNC","rule":"length","sum":2575504},{"parent":"FUNC","rule":"like","sum":4},{"parent":"FUNC","rule":"likely","sum":16515},{"parent":"FUNC","rule":"linearHISTOGRAM","sum":10},{"parent":"FUNC","rule":"linearHistogram","sum":16},{"parent":"FUNC","rule":"linearhistogram","sum":174},{"parent":"FUNC","rule":"linearhistogramcdf","sum":20},{"parent":"FUNC","rule":"listALL","sum":3},{"parent":"FUNC","rule":"listAVG","sum":922},{"parent":"FUNC","rule":"listAggregateUnique","sum":1},{"parent":"FUNC","rule":"listAll","sum":86},{"parent":"FUNC","rule":"listAny","sum":128},{"parent":"FUNC","rule":"listAvg","sum":106},{"parent":"FUNC","rule":"listCollect","sum":378},{"parent":"FUNC","rule":"listConcat","sum":10966},{"parent":"FUNC","rule":"listEnumerate","sum":124},{"parent":"FUNC","rule":"listExtend","sum":6795},{"parent":"FUNC","rule":"listExtract","sum":24},{"parent":"FUNC","rule":"listFilter","sum":40338},{"parent":"FUNC","rule":"listFlatten","sum":292},{"parent":"FUNC","rule":"listFold","sum":305},{"parent":"FUNC","rule":"listFromRange","sum":752},{"parent":"FUNC","rule":"listHAs","sum":52},{"parent":"FUNC","rule":"listHas","sum":42008},{"parent":"FUNC","rule":"listHasItems","sum":3274},{"parent":"FUNC","rule":"listHead","sum":2187},{"parent":"FUNC","rule":"listIndexOf","sum":39},{"parent":"FUNC","rule":"listLENGTH","sum":223},{"parent":"FUNC","rule":"listLENgth","sum":2},{"parent":"FUNC","rule":"listLast","sum":1025},{"parent":"FUNC","rule":"listLength","sum":30279},{"parent":"FUNC","rule":"listMAX","sum":1},{"parent":"FUNC","rule":"listMIN","sum":1},{"parent":"FUNC","rule":"listMap","sum":54237},{"parent":"FUNC","rule":"listMax","sum":810},{"parent":"FUNC","rule":"listMin","sum":172},{"parent":"FUNC","rule":"listNotNull","sum":265},{"parent":"FUNC","rule":"listReverse","sum":4780},{"parent":"FUNC","rule":"listSkip","sum":18},{"parent":"FUNC","rule":"listSort","sum":24533},{"parent":"FUNC","rule":"listSortAsc","sum":2},{"parent":"FUNC","rule":"listSortDesc","sum":204},{"parent":"FUNC","rule":"listSum","sum":1460},{"parent":"FUNC","rule":"listTake","sum":720},{"parent":"FUNC","rule":"listTopSort","sum":18},{"parent":"FUNC","rule":"listUniq","sum":10594},{"parent":"FUNC","rule":"listUniqStable","sum":1},{"parent":"FUNC","rule":"listZip","sum":1365},{"parent":"FUNC","rule":"listZipAll","sum":1336},{"parent":"FUNC","rule":"list_Length","sum":1},{"parent":"FUNC","rule":"list_MAX","sum":1},{"parent":"FUNC","rule":"list_agg","sum":2},{"parent":"FUNC","rule":"list_avg","sum":25},{"parent":"FUNC","rule":"list_concat","sum":264},{"parent":"FUNC","rule":"list_filter","sum":2},{"parent":"FUNC","rule":"list_flatten","sum":15},{"parent":"FUNC","rule":"list_has","sum":6369},{"parent":"FUNC","rule":"list_has_items","sum":2},{"parent":"FUNC","rule":"list_head","sum":16},{"parent":"FUNC","rule":"list_length","sum":865},{"parent":"FUNC","rule":"list_map","sum":3},{"parent":"FUNC","rule":"list_min","sum":3},{"parent":"FUNC","rule":"list_not_null","sum":1},{"parent":"FUNC","rule":"list_sort","sum":102},{"parent":"FUNC","rule":"list_uniq","sum":1},{"parent":"FUNC","rule":"list_zip","sum":30},{"parent":"FUNC","rule":"listaggregate","sum":105},{"parent":"FUNC","rule":"listall","sum":13408},{"parent":"FUNC","rule":"listany","sum":15325},{"parent":"FUNC","rule":"listavg","sum":12124},{"parent":"FUNC","rule":"listcollect","sum":509},{"parent":"FUNC","rule":"listconcat","sum":19213},{"parent":"FUNC","rule":"listcreate","sum":10},{"parent":"FUNC","rule":"listenumerate","sum":2048},{"parent":"FUNC","rule":"listextend","sum":3932},{"parent":"FUNC","rule":"listextendstrict","sum":61},{"parent":"FUNC","rule":"listextract","sum":1813},{"parent":"FUNC","rule":"listfilter","sum":101149},{"parent":"FUNC","rule":"listflatmap","sum":7370},{"parent":"FUNC","rule":"listflatten","sum":23406},{"parent":"FUNC","rule":"listfold","sum":16},{"parent":"FUNC","rule":"listfold1map","sum":60},{"parent":"FUNC","rule":"listfromRange","sum":16},{"parent":"FUNC","rule":"listfromrange","sum":14106},{"parent":"FUNC","rule":"listfromtuple","sum":58},{"parent":"FUNC","rule":"listhas","sum":172035},{"parent":"FUNC","rule":"listhasItems","sum":34},{"parent":"FUNC","rule":"listhasitems","sum":10527},{"parent":"FUNC","rule":"listhead","sum":18583},{"parent":"FUNC","rule":"listindexof","sum":1201},{"parent":"FUNC","rule":"listlast","sum":3076},{"parent":"FUNC","rule":"listlength","sum":344746},{"parent":"FUNC","rule":"listmap","sum":513663},{"parent":"FUNC","rule":"listmax","sum":3930},{"parent":"FUNC","rule":"listmin","sum":2665},{"parent":"FUNC","rule":"listnotNull","sum":1},{"parent":"FUNC","rule":"listnotnull","sum":12967},{"parent":"FUNC","rule":"listreplicate","sum":49},{"parent":"FUNC","rule":"listreverse","sum":2249},{"parent":"FUNC","rule":"listskip","sum":1194},{"parent":"FUNC","rule":"listsort","sum":56744},{"parent":"FUNC","rule":"listsortDesc","sum":1},{"parent":"FUNC","rule":"listsortasc","sum":377},{"parent":"FUNC","rule":"listsortdesc","sum":3986},{"parent":"FUNC","rule":"listsum","sum":3392},{"parent":"FUNC","rule":"listtake","sum":16232},{"parent":"FUNC","rule":"listtop","sum":68},{"parent":"FUNC","rule":"listunionall","sum":8},{"parent":"FUNC","rule":"listuniq","sum":26219},{"parent":"FUNC","rule":"listuniqstable","sum":94},{"parent":"FUNC","rule":"listzip","sum":16893},{"parent":"FUNC","rule":"listzipALL","sum":2},{"parent":"FUNC","rule":"listzipAll","sum":15},{"parent":"FUNC","rule":"listzipall","sum":98},{"parent":"FUNC","rule":"log","sum":2},{"parent":"FUNC","rule":"logarithmicHistogram","sum":1},{"parent":"FUNC","rule":"logarithmichistogram","sum":6},{"parent":"FUNC","rule":"loghistogram","sum":1},{"parent":"FUNC","rule":"lower","sum":3},{"parent":"FUNC","rule":"mAX","sum":17},{"parent":"FUNC","rule":"mAX_BY","sum":132},{"parent":"FUNC","rule":"mIN","sum":2},{"parent":"FUNC","rule":"mIN_by","sum":10},{"parent":"FUNC","rule":"maX","sum":6},{"parent":"FUNC","rule":"maX_BY","sum":1},{"parent":"FUNC","rule":"map","sum":2},{"parent":"FUNC","rule":"max","sum":25228353},{"parent":"FUNC","rule":"maxBy","sum":1},{"parent":"FUNC","rule":"maxOf","sum":3595},{"parent":"FUNC","rule":"max_","sum":1},{"parent":"FUNC","rule":"max_BY","sum":2362},{"parent":"FUNC","rule":"max_By","sum":4552},{"parent":"FUNC","rule":"max_OF","sum":8},{"parent":"FUNC","rule":"max_Of","sum":29},{"parent":"FUNC","rule":"max_by","sum":29000324},{"parent":"FUNC","rule":"max_if","sum":3},{"parent":"FUNC","rule":"max_of","sum":1278387},{"parent":"FUNC","rule":"maxby","sum":3553},{"parent":"FUNC","rule":"maxof","sum":852},{"parent":"FUNC","rule":"md5int","sum":1},{"parent":"FUNC","rule":"median","sum":384656},{"parent":"FUNC","rule":"metric_exp","sum":1},{"parent":"FUNC","rule":"min","sum":10296946},{"parent":"FUNC","rule":"minOf","sum":2},{"parent":"FUNC","rule":"min_BY","sum":8619},{"parent":"FUNC","rule":"min_By","sum":6},{"parent":"FUNC","rule":"min_OF","sum":9},{"parent":"FUNC","rule":"min_Of","sum":348},{"parent":"FUNC","rule":"min_by","sum":2332840},{"parent":"FUNC","rule":"min_if","sum":1},{"parent":"FUNC","rule":"min_of","sum":577710},{"parent":"FUNC","rule":"minby","sum":1},{"parent":"FUNC","rule":"minof","sum":98},{"parent":"FUNC","rule":"mode","sum":117882},{"parent":"FUNC","rule":"multiIf","sum":2},{"parent":"FUNC","rule":"multi_aggregate_by","sum":118866},{"parent":"FUNC","rule":"naNVL","sum":16},{"parent":"FUNC","rule":"nanvl","sum":129219},{"parent":"FUNC","rule":"notEmpty","sum":2},{"parent":"FUNC","rule":"nothing","sum":13084},{"parent":"FUNC","rule":"now","sum":16},{"parent":"FUNC","rule":"nth_value","sum":17},{"parent":"FUNC","rule":"ntile","sum":343},{"parent":"FUNC","rule":"nvL","sum":63},{"parent":"FUNC","rule":"nvl","sum":14055156},{"parent":"FUNC","rule":"on","sum":1},{"parent":"FUNC","rule":"optionaltype","sum":161},{"parent":"FUNC","rule":"or","sum":3},{"parent":"FUNC","rule":"order_nr","sum":1},{"parent":"FUNC","rule":"p25","sum":1},{"parent":"FUNC","rule":"p75","sum":1},{"parent":"FUNC","rule":"pERCENTILE","sum":11},{"parent":"FUNC","rule":"parseFile","sum":155},{"parent":"FUNC","rule":"parseForErrors","sum":32},{"parent":"FUNC","rule":"parse_dt_formatted","sum":1},{"parent":"FUNC","rule":"parsefile","sum":10971},{"parent":"FUNC","rule":"percent_rank","sum":2230},{"parent":"FUNC","rule":"percentile","sum":3359965},{"parent":"FUNC","rule":"pgInt2","sum":2},{"parent":"FUNC","rule":"pgarray","sum":2},{"parent":"FUNC","rule":"pgbpchar","sum":2},{"parent":"FUNC","rule":"pgbytea","sum":6},{"parent":"FUNC","rule":"pgcast","sum":39},{"parent":"FUNC","rule":"pgchar","sum":2},{"parent":"FUNC","rule":"pgdate","sum":94},{"parent":"FUNC","rule":"pgfloat4","sum":5},{"parent":"FUNC","rule":"pgfloat8","sum":3},{"parent":"FUNC","rule":"pgint2","sum":9},{"parent":"FUNC","rule":"pginterval","sum":176},{"parent":"FUNC","rule":"pgjson","sum":10},{"parent":"FUNC","rule":"pgname","sum":4},{"parent":"FUNC","rule":"pgnumeric","sum":4},{"parent":"FUNC","rule":"pgoidvector","sum":1},{"parent":"FUNC","rule":"pgtext","sum":9},{"parent":"FUNC","rule":"pgtimestamp","sum":7},{"parent":"FUNC","rule":"pgtimestamptz","sum":4},{"parent":"FUNC","rule":"pickle","sum":925},{"parent":"FUNC","rule":"pow","sum":8},{"parent":"FUNC","rule":"power","sum":3},{"parent":"FUNC","rule":"print","sum":1},{"parent":"FUNC","rule":"quantile","sum":1},{"parent":"FUNC","rule":"quantileExact","sum":1},{"parent":"FUNC","rule":"rFIND","sum":2},{"parent":"FUNC","rule":"rand","sum":5},{"parent":"FUNC","rule":"random","sum":261110},{"parent":"FUNC","rule":"randomNumber","sum":10},{"parent":"FUNC","rule":"randomUuid","sum":157},{"parent":"FUNC","rule":"random_number","sum":11},{"parent":"FUNC","rule":"randomnumber","sum":478},{"parent":"FUNC","rule":"randomuuid","sum":34},{"parent":"FUNC","rule":"range","sum":96},{"parent":"FUNC","rule":"rank","sum":221725},{"parent":"FUNC","rule":"regex_full_match","sum":1},{"parent":"FUNC","rule":"regex_replace_first","sum":1},{"parent":"FUNC","rule":"regionIn","sum":2},{"parent":"FUNC","rule":"removeMember","sum":162},{"parent":"FUNC","rule":"removemember","sum":18},{"parent":"FUNC","rule":"removemembers","sum":77},{"parent":"FUNC","rule":"removetimezone","sum":5},{"parent":"FUNC","rule":"renamemembers","sum":4},{"parent":"FUNC","rule":"replace","sum":1},{"parent":"FUNC","rule":"replaceRegexpAll","sum":2},{"parent":"FUNC","rule":"rfind","sum":127572},{"parent":"FUNC","rule":"round","sum":27},{"parent":"FUNC","rule":"row_NUMBER","sum":5},{"parent":"FUNC","rule":"row_Number","sum":3},{"parent":"FUNC","rule":"row_number","sum":2193124},{"parent":"FUNC","rule":"rownumber","sum":399},{"parent":"FUNC","rule":"sUBSTRING","sum":3},{"parent":"FUNC","rule":"sUM","sum":449},{"parent":"FUNC","rule":"sUM_IF","sum":20},{"parent":"FUNC","rule":"sUm","sum":8},{"parent":"FUNC","rule":"sessionWindow","sum":4},{"parent":"FUNC","rule":"session_start","sum":3},{"parent":"FUNC","rule":"sessionwindow","sum":179},{"parent":"FUNC","rule":"setDifference","sum":59},{"parent":"FUNC","rule":"setIntersection","sum":13},{"parent":"FUNC","rule":"setIsDisjoint","sum":1},{"parent":"FUNC","rule":"setUnion","sum":172},{"parent":"FUNC","rule":"setbit","sum":20},{"parent":"FUNC","rule":"setdifference","sum":172},{"parent":"FUNC","rule":"setincludes","sum":20},{"parent":"FUNC","rule":"setintersection","sum":123},{"parent":"FUNC","rule":"setisdisjoint","sum":1032},{"parent":"FUNC","rule":"setsymmetricdifference","sum":204},{"parent":"FUNC","rule":"setunion","sum":1795},{"parent":"FUNC","rule":"sign","sum":1},{"parent":"FUNC","rule":"sin","sum":16},{"parent":"FUNC","rule":"sipHash64","sum":2},{"parent":"FUNC","rule":"size","sum":1},{"parent":"FUNC","rule":"somE","sum":2},{"parent":"FUNC","rule":"some","sum":20426723},{"parent":"FUNC","rule":"somr","sum":1},{"parent":"FUNC","rule":"splitByChar","sum":1},{"parent":"FUNC","rule":"splitByString","sum":6},{"parent":"FUNC","rule":"spreadmembers","sum":3},{"parent":"FUNC","rule":"sqrt","sum":11},{"parent":"FUNC","rule":"ssubstring","sum":2},{"parent":"FUNC","rule":"stablepickle","sum":30},{"parent":"FUNC","rule":"startsWith","sum":199037},{"parent":"FUNC","rule":"starts_with","sum":14},{"parent":"FUNC","rule":"startswith","sum":19928},{"parent":"FUNC","rule":"staticmap","sum":21},{"parent":"FUNC","rule":"staticzip","sum":1},{"parent":"FUNC","rule":"status$$name","sum":3},{"parent":"FUNC","rule":"std_dev","sum":4},{"parent":"FUNC","rule":"stddev","sum":624851},{"parent":"FUNC","rule":"stddevPop","sum":13},{"parent":"FUNC","rule":"stddev_pop","sum":108},{"parent":"FUNC","rule":"stddev_population","sum":88},{"parent":"FUNC","rule":"stddev_samp","sum":27},{"parent":"FUNC","rule":"stddev_sample","sum":884},{"parent":"FUNC","rule":"stddevpop","sum":19},{"parent":"FUNC","rule":"stddevsamp","sum":5},{"parent":"FUNC","rule":"str","sum":3},{"parent":"FUNC","rule":"strfdate","sum":164},{"parent":"FUNC","rule":"string","sum":77},{"parent":"FUNC","rule":"string_agg","sum":1},{"parent":"FUNC","rule":"string_split","sum":1},{"parent":"FUNC","rule":"string_to_array","sum":3},{"parent":"FUNC","rule":"string_to_features","sum":1},{"parent":"FUNC","rule":"structMembers","sum":7},{"parent":"FUNC","rule":"structUnion","sum":41},{"parent":"FUNC","rule":"structdifference","sum":2},{"parent":"FUNC","rule":"structunion","sum":7},{"parent":"FUNC","rule":"suM","sum":188},{"parent":"FUNC","rule":"suM_if","sum":16},{"parent":"FUNC","rule":"subDate","sum":1},{"parent":"FUNC","rule":"subSTRING","sum":1},{"parent":"FUNC","rule":"subString","sum":585},{"parent":"FUNC","rule":"subqueryMergeFor","sum":21},{"parent":"FUNC","rule":"subqueryUnionMergeFor","sum":4378},{"parent":"FUNC","rule":"subquerymergefor","sum":1984},{"parent":"FUNC","rule":"subsTRING","sum":2},{"parent":"FUNC","rule":"subsrting","sum":3},{"parent":"FUNC","rule":"substing","sum":2},{"parent":"FUNC","rule":"substr","sum":173},{"parent":"FUNC","rule":"substring","sum":16592865},{"parent":"FUNC","rule":"substringUTF8","sum":1},{"parent":"FUNC","rule":"substring_index","sum":1},{"parent":"FUNC","rule":"sum","sum":45292139},{"parent":"FUNC","rule":"sumIF","sum":84},{"parent":"FUNC","rule":"sumIf","sum":92909},{"parent":"FUNC","rule":"sum_","sum":356},{"parent":"FUNC","rule":"sum_IF","sum":19678},{"parent":"FUNC","rule":"sum_If","sum":13182},{"parent":"FUNC","rule":"sum_if","sum":4230704},{"parent":"FUNC","rule":"sum_range2","sum":47},{"parent":"FUNC","rule":"sum_recursive_range","sum":1},{"parent":"FUNC","rule":"suma","sum":1},{"parent":"FUNC","rule":"sumif","sum":7489},{"parent":"FUNC","rule":"summ","sum":10},{"parent":"FUNC","rule":"sunstring","sum":2},{"parent":"FUNC","rule":"susbstring","sum":1},{"parent":"FUNC","rule":"tableName","sum":43523},{"parent":"FUNC","rule":"tablePath","sum":1519},{"parent":"FUNC","rule":"tableRecordIndex","sum":19},{"parent":"FUNC","rule":"tableRow","sum":23218},{"parent":"FUNC","rule":"table_name","sum":2883},{"parent":"FUNC","rule":"table_path","sum":45},{"parent":"FUNC","rule":"table_row","sum":377},{"parent":"FUNC","rule":"tablename","sum":166587},{"parent":"FUNC","rule":"tablepath","sum":32910},{"parent":"FUNC","rule":"tablerecordindex","sum":111},{"parent":"FUNC","rule":"tablerow","sum":42998},{"parent":"FUNC","rule":"tablerows","sum":5},{"parent":"FUNC","rule":"testBit","sum":34},{"parent":"FUNC","rule":"testbit","sum":39563},{"parent":"FUNC","rule":"testid","sum":2},{"parent":"FUNC","rule":"timestamp","sum":10135},{"parent":"FUNC","rule":"timestamp64","sum":7},{"parent":"FUNC","rule":"timezone","sum":2},{"parent":"FUNC","rule":"toBytes","sum":26371},{"parent":"FUNC","rule":"toDate","sum":59},{"parent":"FUNC","rule":"toDate32","sum":10},{"parent":"FUNC","rule":"toDateTime","sum":21},{"parent":"FUNC","rule":"toDateTimeOrNull","sum":3},{"parent":"FUNC","rule":"toDayOfWeek","sum":2},{"parent":"FUNC","rule":"toDays","sum":1},{"parent":"FUNC","rule":"toDict","sum":97042},{"parent":"FUNC","rule":"toFloat32","sum":4},{"parent":"FUNC","rule":"toInt128","sum":3},{"parent":"FUNC","rule":"toIntervalMonth","sum":2},{"parent":"FUNC","rule":"toLastDayOfMonth","sum":1},{"parent":"FUNC","rule":"toMonth","sum":1},{"parent":"FUNC","rule":"toMultiDict","sum":264},{"parent":"FUNC","rule":"toQuarter","sum":1},{"parent":"FUNC","rule":"toSet","sum":448252},{"parent":"FUNC","rule":"toStartOfMonth","sum":15},{"parent":"FUNC","rule":"toStartOfQuarter","sum":1},{"parent":"FUNC","rule":"toStartOfWeek","sum":9},{"parent":"FUNC","rule":"toString","sum":46},{"parent":"FUNC","rule":"toUInt64","sum":5},{"parent":"FUNC","rule":"toUnixTimestamp","sum":2},{"parent":"FUNC","rule":"toUnixTimestamp64Micro","sum":2},{"parent":"FUNC","rule":"toYear","sum":9},{"parent":"FUNC","rule":"to_bytes","sum":36},{"parent":"FUNC","rule":"to_char","sum":2},{"parent":"FUNC","rule":"to_date","sum":4},{"parent":"FUNC","rule":"to_dict","sum":65},{"parent":"FUNC","rule":"tobytes","sum":155},{"parent":"FUNC","rule":"today","sum":1},{"parent":"FUNC","rule":"todict","sum":102846},{"parent":"FUNC","rule":"tomultidict","sum":1198},{"parent":"FUNC","rule":"top","sum":55371},{"parent":"FUNC","rule":"topFreq","sum":99},{"parent":"FUNC","rule":"top_BY","sum":1},{"parent":"FUNC","rule":"top_by","sum":115321},{"parent":"FUNC","rule":"top_freq","sum":107},{"parent":"FUNC","rule":"topfreq","sum":23300},{"parent":"FUNC","rule":"topg","sum":2},{"parent":"FUNC","rule":"toset","sum":39199},{"parent":"FUNC","rule":"trunc","sum":13},{"parent":"FUNC","rule":"truncate","sum":2},{"parent":"FUNC","rule":"tryMember","sum":527},{"parent":"FUNC","rule":"trymember","sum":10273},{"parent":"FUNC","rule":"tupleElement","sum":2},{"parent":"FUNC","rule":"typeOf","sum":38},{"parent":"FUNC","rule":"typeof","sum":397},{"parent":"FUNC","rule":"tzdate","sum":8},{"parent":"FUNC","rule":"tzdate32","sum":7},{"parent":"FUNC","rule":"tzdatetime","sum":44},{"parent":"FUNC","rule":"tzdatetime64","sum":7},{"parent":"FUNC","rule":"tztimestamp","sum":35},{"parent":"FUNC","rule":"tztimestamp64","sum":7},{"parent":"FUNC","rule":"uNWRAP","sum":118},{"parent":"FUNC","rule":"udaf","sum":17276},{"parent":"FUNC","rule":"uint32","sum":13705},{"parent":"FUNC","rule":"uint64","sum":35},{"parent":"FUNC","rule":"uint8","sum":2},{"parent":"FUNC","rule":"unWRap","sum":3},{"parent":"FUNC","rule":"unWrap","sum":5},{"parent":"FUNC","rule":"uniq","sum":9},{"parent":"FUNC","rule":"uniqExact","sum":10},{"parent":"FUNC","rule":"unique","sum":1},{"parent":"FUNC","rule":"unique_pairs","sum":1},{"parent":"FUNC","rule":"unnest","sum":3},{"parent":"FUNC","rule":"untag","sum":1180},{"parent":"FUNC","rule":"unwrap","sum":27136138},{"parent":"FUNC","rule":"unwraped","sum":1},{"parent":"FUNC","rule":"upper","sum":2},{"parent":"FUNC","rule":"using","sum":12},{"parent":"FUNC","rule":"utc_action_created_dttm","sum":1},{"parent":"FUNC","rule":"utf8","sum":2035},{"parent":"FUNC","rule":"uuid","sum":25},{"parent":"FUNC","rule":"values","sum":6},{"parent":"FUNC","rule":"varPop","sum":77},{"parent":"FUNC","rule":"varSamp","sum":85},{"parent":"FUNC","rule":"var_samp","sum":43},{"parent":"FUNC","rule":"variance","sum":66147},{"parent":"FUNC","rule":"variance_population","sum":4},{"parent":"FUNC","rule":"variance_sample","sum":524},{"parent":"FUNC","rule":"varpop","sum":19},{"parent":"FUNC","rule":"version","sum":19},{"parent":"FUNC","rule":"vl","sum":2},{"parent":"FUNC","rule":"void","sum":1},{"parent":"FUNC","rule":"way","sum":43731},{"parent":"FUNC","rule":"weakField","sum":1077},{"parent":"FUNC","rule":"weakfield","sum":988043},{"parent":"FUNC","rule":"windowFunnel","sum":1},{"parent":"FUNC","rule":"worked_rules","sum":3},{"parent":"FUNC","rule":"wrap","sum":1},{"parent":"FUNC","rule":"yesterday","sum":4},{"parent":"FUNC","rule":"yson","sum":42},{"parent":"FUNC","rule":"ytListTables","sum":1},{"parent":"INSERT_HINT","rule":"COLUMN_GROUPS","sum":225},{"parent":"INSERT_HINT","rule":"COMPRESSION_CODEC","sum":864489},{"parent":"INSERT_HINT","rule":"ERASURE_CODEC","sum":67995},{"parent":"INSERT_HINT","rule":"EXPIRATION","sum":7242661},{"parent":"INSERT_HINT","rule":"Expiration","sum":175},{"parent":"INSERT_HINT","rule":"KEEPMETA","sum":10},{"parent":"INSERT_HINT","rule":"KEEP_META","sum":115191},{"parent":"INSERT_HINT","rule":"MODE","sum":2},{"parent":"INSERT_HINT","rule":"MONOTONIC_KEYS","sum":429074},{"parent":"INSERT_HINT","rule":"PRIMARY_MEDIUM","sum":89502},{"parent":"INSERT_HINT","rule":"REPLICATION_FACTOR","sum":7389},{"parent":"INSERT_HINT","rule":"SECURITY_TAGS","sum":4831},{"parent":"INSERT_HINT","rule":"TRUNCATE","sum":111671227},{"parent":"INSERT_HINT","rule":"TRUNCATe","sum":321},{"parent":"INSERT_HINT","rule":"TRUNCAtE","sum":3},{"parent":"INSERT_HINT","rule":"TRUNCAte","sum":11},{"parent":"INSERT_HINT","rule":"TRUNCate","sum":10},{"parent":"INSERT_HINT","rule":"TRUNcATE","sum":6},{"parent":"INSERT_HINT","rule":"TRUnCATE","sum":1},{"parent":"INSERT_HINT","rule":"TRUncATE","sum":322},{"parent":"INSERT_HINT","rule":"TRUncate","sum":10},{"parent":"INSERT_HINT","rule":"TRuNCATE","sum":2},{"parent":"INSERT_HINT","rule":"TRuncaTE","sum":1},{"parent":"INSERT_HINT","rule":"TRuncate","sum":50},{"parent":"INSERT_HINT","rule":"TrUNCATE","sum":1},{"parent":"INSERT_HINT","rule":"Truncate","sum":4643},{"parent":"INSERT_HINT","rule":"USER_ATTRS","sum":2084355},{"parent":"INSERT_HINT","rule":"XLOCK","sum":1},{"parent":"INSERT_HINT","rule":"column_groups","sum":6541},{"parent":"INSERT_HINT","rule":"compression_codec","sum":2023},{"parent":"INSERT_HINT","rule":"erasure_codec","sum":3163},{"parent":"INSERT_HINT","rule":"expiration","sum":338636},{"parent":"INSERT_HINT","rule":"initial","sum":1},{"parent":"INSERT_HINT","rule":"keep_meta","sum":134738},{"parent":"INSERT_HINT","rule":"monotonic_keys","sum":15},{"parent":"INSERT_HINT","rule":"mutation_id","sum":3},{"parent":"INSERT_HINT","rule":"primary_medium","sum":11466},{"parent":"INSERT_HINT","rule":"replication_factor","sum":1},{"parent":"INSERT_HINT","rule":"tRUNCATE","sum":1},{"parent":"INSERT_HINT","rule":"tRUNCAte","sum":1},{"parent":"INSERT_HINT","rule":"trUNCATE","sum":19},{"parent":"INSERT_HINT","rule":"truNCATE","sum":2},{"parent":"INSERT_HINT","rule":"trunCATE","sum":7},{"parent":"INSERT_HINT","rule":"truncate","sum":31067516},{"parent":"INSERT_HINT","rule":"user_attr","sum":1},{"parent":"INSERT_HINT","rule":"user_attrs","sum":67268},{"parent":"KEYWORD","rule":"ABORT","sum":20},{"parent":"KEYWORD","rule":"ACTION","sum":15140547},{"parent":"KEYWORD","rule":"ADD","sum":1097680},{"parent":"KEYWORD","rule":"AFTER","sum":170643},{"parent":"KEYWORD","rule":"ALL","sum":68407457},{"parent":"KEYWORD","rule":"ALTER","sum":72},{"parent":"KEYWORD","rule":"ANALYZE","sum":5861},{"parent":"KEYWORD","rule":"AND","sum":499617854},{"parent":"KEYWORD","rule":"ANY","sum":14739224},{"parent":"KEYWORD","rule":"ARRAY","sum":47490},{"parent":"KEYWORD","rule":"AS","sum":3191320969},{"parent":"KEYWORD","rule":"ASC","sum":11404139},{"parent":"KEYWORD","rule":"ASSUME","sum":2653585},{"parent":"KEYWORD","rule":"ASYNC","sum":32420},{"parent":"KEYWORD","rule":"AT","sum":570055},{"parent":"KEYWORD","rule":"ATTACH","sum":30213},{"parent":"KEYWORD","rule":"ATTRIBUTES","sum":19192984},{"parent":"KEYWORD","rule":"AUTOMAP","sum":1},{"parent":"KEYWORD","rule":"BACKUP","sum":480150},{"parent":"KEYWORD","rule":"BATCH","sum":777254},{"parent":"KEYWORD","rule":"BEFORE","sum":115648},{"parent":"KEYWORD","rule":"BEGIN","sum":14996587},{"parent":"KEYWORD","rule":"BERNOULLI","sum":125782},{"parent":"KEYWORD","rule":"BETWEEN","sum":27434655},{"parent":"KEYWORD","rule":"BITCAST","sum":516962},{"parent":"KEYWORD","rule":"BY","sum":293888555},{"parent":"KEYWORD","rule":"CALLABLE","sum":11017342},{"parent":"KEYWORD","rule":"CASCADE","sum":6},{"parent":"KEYWORD","rule":"CASE","sum":62013190},{"parent":"KEYWORD","rule":"CAST","sum":399425614},{"parent":"KEYWORD","rule":"CHECK","sum":1306921},{"parent":"KEYWORD","rule":"CLASSIFIER","sum":32389},{"parent":"KEYWORD","rule":"COLLECTION","sum":233346},{"parent":"KEYWORD","rule":"COLUMN","sum":1199069},{"parent":"KEYWORD","rule":"COLUMNS","sum":9586995},{"parent":"KEYWORD","rule":"COMMIT","sum":13068360},{"parent":"KEYWORD","rule":"COMPACT","sum":4826758},{"parent":"KEYWORD","rule":"CONDITIONAL","sum":40362},{"parent":"KEYWORD","rule":"CONFLICT","sum":493},{"parent":"KEYWORD","rule":"CONNECT","sum":41497},{"parent":"KEYWORD","rule":"CONSTRAINT","sum":1235},{"parent":"KEYWORD","rule":"CONSUMER","sum":673115},{"parent":"KEYWORD","rule":"COVER","sum":42405},{"parent":"KEYWORD","rule":"CREATE","sum":449774},{"parent":"KEYWORD","rule":"CROSS","sum":3108046},{"parent":"KEYWORD","rule":"CUBE","sum":371916},{"parent":"KEYWORD","rule":"CURRENT","sum":3606127},{"parent":"KEYWORD","rule":"CURRENT_DATE","sum":2894412},{"parent":"KEYWORD","rule":"CURRENT_TIME","sum":583690},{"parent":"KEYWORD","rule":"CURRENT_TIMESTAMP","sum":589598},{"parent":"KEYWORD","rule":"DATA","sum":65702878},{"parent":"KEYWORD","rule":"DATABASE","sum":21193},{"parent":"KEYWORD","rule":"DECIMAL","sum":28187759},{"parent":"KEYWORD","rule":"DECLARE","sum":156792290},{"parent":"KEYWORD","rule":"DEFAULT","sum":1604032},{"parent":"KEYWORD","rule":"DEFERRED","sum":902},{"parent":"KEYWORD","rule":"DEFINE","sum":44751639},{"parent":"KEYWORD","rule":"DELETE","sum":19493},{"parent":"KEYWORD","rule":"DESC","sum":22095112},{"parent":"KEYWORD","rule":"DESCRIBE","sum":40},{"parent":"KEYWORD","rule":"DICT","sum":9923692},{"parent":"KEYWORD","rule":"DIRECTORY","sum":201912},{"parent":"KEYWORD","rule":"DISABLE","sum":313158},{"parent":"KEYWORD","rule":"DISCARD","sum":931019},{"parent":"KEYWORD","rule":"DISTINCT","sum":71048223},{"parent":"KEYWORD","rule":"DO","sum":37700462},{"parent":"KEYWORD","rule":"DROP","sum":2676674},{"parent":"KEYWORD","rule":"EACH","sum":18045183},{"parent":"KEYWORD","rule":"ELSE","sum":65051198},{"parent":"KEYWORD","rule":"EMPTY","sum":477937},{"parent":"KEYWORD","rule":"EMPTY_ACTION","sum":126380},{"parent":"KEYWORD","rule":"ENCRYPTED","sum":8973},{"parent":"KEYWORD","rule":"END","sum":108172892},{"parent":"KEYWORD","rule":"ENUM","sum":79387},{"parent":"KEYWORD","rule":"ERASE","sum":25532},{"parent":"KEYWORD","rule":"ERROR","sum":3492039},{"parent":"KEYWORD","rule":"ESCAPE","sum":1176049},{"parent":"KEYWORD","rule":"EVALUATE","sum":15637931},{"parent":"KEYWORD","rule":"EXCEPT","sum":562},{"parent":"KEYWORD","rule":"EXCLUDE","sum":240053},{"parent":"KEYWORD","rule":"EXCLUSION","sum":434271},{"parent":"KEYWORD","rule":"EXCLUSIVE","sum":2103},{"parent":"KEYWORD","rule":"EXISTS","sum":679423},{"parent":"KEYWORD","rule":"EXPLAIN","sum":77},{"parent":"KEYWORD","rule":"EXPORT","sum":505667},{"parent":"KEYWORD","rule":"EXTERNAL","sum":43331},{"parent":"KEYWORD","rule":"FAIL","sum":50133},{"parent":"KEYWORD","rule":"FALSE","sum":57888821},{"parent":"KEYWORD","rule":"FAMILY","sum":164621},{"parent":"KEYWORD","rule":"FILTER","sum":3873974},{"parent":"KEYWORD","rule":"FIRST","sum":784473},{"parent":"KEYWORD","rule":"FLATTEN","sum":34215436},{"parent":"KEYWORD","rule":"FLOW","sum":144090},{"parent":"KEYWORD","rule":"FOLLOWING","sum":979399},{"parent":"KEYWORD","rule":"FOR","sum":7050918},{"parent":"KEYWORD","rule":"FOREIGN","sum":21688},{"parent":"KEYWORD","rule":"FROM","sum":874058868},{"parent":"KEYWORD","rule":"FULL","sum":6177643},{"parent":"KEYWORD","rule":"FUNCTION","sum":81034},{"parent":"KEYWORD","rule":"GLOB","sum":5073},{"parent":"KEYWORD","rule":"GLOBAL","sum":293},{"parent":"KEYWORD","rule":"GRANT","sum":42987},{"parent":"KEYWORD","rule":"GROUP","sum":139923226},{"parent":"KEYWORD","rule":"GROUPING","sum":190047},{"parent":"KEYWORD","rule":"GROUPS","sum":1785345},{"parent":"KEYWORD","rule":"HASH","sum":6389784},{"parent":"KEYWORD","rule":"HAVING","sum":12007005},{"parent":"KEYWORD","rule":"HOP","sum":23},{"parent":"KEYWORD","rule":"IF","sum":128627611},{"parent":"KEYWORD","rule":"IGNORE","sum":8308713},{"parent":"KEYWORD","rule":"ILIKE","sum":10613820},{"parent":"KEYWORD","rule":"IMPORT","sum":16686234},{"parent":"KEYWORD","rule":"IN","sum":133742190},{"parent":"KEYWORD","rule":"INCREMENT","sum":558054},{"parent":"KEYWORD","rule":"INDEX","sum":2383417},{"parent":"KEYWORD","rule":"INDEXED","sum":184557},{"parent":"KEYWORD","rule":"INITIAL","sum":147066},{"parent":"KEYWORD","rule":"INNER","sum":30890968},{"parent":"KEYWORD","rule":"INSERT","sum":209792885},{"parent":"KEYWORD","rule":"INTERSECT","sum":49949},{"parent":"KEYWORD","rule":"INTO","sum":212610245},{"parent":"KEYWORD","rule":"IS","sum":173663787},{"parent":"KEYWORD","rule":"ISNULL","sum":5476},{"parent":"KEYWORD","rule":"JOIN","sum":210067566},{"parent":"KEYWORD","rule":"JSON_EXISTS","sum":184354},{"parent":"KEYWORD","rule":"JSON_QUERY","sum":316589},{"parent":"KEYWORD","rule":"JSON_VALUE","sum":6154167},{"parent":"KEYWORD","rule":"KEY","sum":39514934},{"parent":"KEYWORD","rule":"LAST","sum":976740},{"parent":"KEYWORD","rule":"LEFT","sum":120149213},{"parent":"KEYWORD","rule":"LEGACY","sum":18374},{"parent":"KEYWORD","rule":"LIKE","sum":41030922},{"parent":"KEYWORD","rule":"LIMIT","sum":33412717},{"parent":"KEYWORD","rule":"LIST","sum":50632334},{"parent":"KEYWORD","rule":"LOCAL","sum":4569},{"parent":"KEYWORD","rule":"LOGIN","sum":39271221},{"parent":"KEYWORD","rule":"MANAGE","sum":320160},{"parent":"KEYWORD","rule":"MATCH","sum":2546299},{"parent":"KEYWORD","rule":"MATCHES","sum":236320},{"parent":"KEYWORD","rule":"MATCH_RECOGNIZE","sum":1},{"parent":"KEYWORD","rule":"MEASURES","sum":35552},{"parent":"KEYWORD","rule":"MICROSECONDS","sum":6884},{"parent":"KEYWORD","rule":"MILLISECONDS","sum":4426235},{"parent":"KEYWORD","rule":"MODIFY","sum":4434},{"parent":"KEYWORD","rule":"NANOSECONDS","sum":488},{"parent":"KEYWORD","rule":"NEXT","sum":278533},{"parent":"KEYWORD","rule":"NO","sum":91482},{"parent":"KEYWORD","rule":"NOT","sum":186046250},{"parent":"KEYWORD","rule":"NOTNULL","sum":2174},{"parent":"KEYWORD","rule":"NULL","sum":253066440},{"parent":"KEYWORD","rule":"NULLS","sum":7298561},{"parent":"KEYWORD","rule":"OBJECT","sum":2234714},{"parent":"KEYWORD","rule":"OF","sum":1747513},{"parent":"KEYWORD","rule":"OFFSET","sum":6124731},{"parent":"KEYWORD","rule":"ON","sum":174603959},{"parent":"KEYWORD","rule":"ONE","sum":179399},{"parent":"KEYWORD","rule":"ONLY","sum":17310526},{"parent":"KEYWORD","rule":"OPTION","sum":365128},{"parent":"KEYWORD","rule":"OPTIONAL","sum":33347970},{"parent":"KEYWORD","rule":"OR","sum":115474847},{"parent":"KEYWORD","rule":"ORDER","sum":121503528},{"parent":"KEYWORD","rule":"OTHERS","sum":57263},{"parent":"KEYWORD","rule":"OUTER","sum":297175},{"parent":"KEYWORD","rule":"OVER","sum":45477559},{"parent":"KEYWORD","rule":"OWNER","sum":7128894},{"parent":"KEYWORD","rule":"PARALLEL","sum":1677},{"parent":"KEYWORD","rule":"PARTITION","sum":22815081},{"parent":"KEYWORD","rule":"PASSING","sum":20022},{"parent":"KEYWORD","rule":"PASSWORD","sum":35045},{"parent":"KEYWORD","rule":"PAST","sum":448562},{"parent":"KEYWORD","rule":"PATTERN","sum":471538},{"parent":"KEYWORD","rule":"PER","sum":51541},{"parent":"KEYWORD","rule":"PERMUTE","sum":60},{"parent":"KEYWORD","rule":"PLAN","sum":1507049},{"parent":"KEYWORD","rule":"POOL","sum":84747916},{"parent":"KEYWORD","rule":"PRAGMA","sum":900857162},{"parent":"KEYWORD","rule":"PRECEDING","sum":2395479},{"parent":"KEYWORD","rule":"PRESORT","sum":309613},{"parent":"KEYWORD","rule":"PRIMARY","sum":77532},{"parent":"KEYWORD","rule":"PROCESS","sum":5035742},{"parent":"KEYWORD","rule":"QUERY","sum":16700391},{"parent":"KEYWORD","rule":"QUEUE","sum":5028110},{"parent":"KEYWORD","rule":"RAISE","sum":80},{"parent":"KEYWORD","rule":"RANGE","sum":34178688},{"parent":"KEYWORD","rule":"REDUCE","sum":930444},{"parent":"KEYWORD","rule":"REFERENCES","sum":117434},{"parent":"KEYWORD","rule":"REGEXP","sum":4545892},{"parent":"KEYWORD","rule":"REINDEX","sum":16},{"parent":"KEYWORD","rule":"RELEASE","sum":31801},{"parent":"KEYWORD","rule":"REMOVE","sum":324614},{"parent":"KEYWORD","rule":"RENAME","sum":18041},{"parent":"KEYWORD","rule":"REPEATABLE","sum":9382},{"parent":"KEYWORD","rule":"REPLACE","sum":9224091},{"parent":"KEYWORD","rule":"REPLICATION","sum":80},{"parent":"KEYWORD","rule":"RESET","sum":66966},{"parent":"KEYWORD","rule":"RESOURCE","sum":692688},{"parent":"KEYWORD","rule":"RESPECT","sum":45},{"parent":"KEYWORD","rule":"RESTART","sum":89},{"parent":"KEYWORD","rule":"RESTORE","sum":150},{"parent":"KEYWORD","rule":"RESTRICT","sum":693},{"parent":"KEYWORD","rule":"RESULT","sum":35050793},{"parent":"KEYWORD","rule":"RETURN","sum":166802548},{"parent":"KEYWORD","rule":"RETURNING","sum":1331865},{"parent":"KEYWORD","rule":"REVERT","sum":45},{"parent":"KEYWORD","rule":"REVOKE","sum":10},{"parent":"KEYWORD","rule":"RIGHT","sum":2551125},{"parent":"KEYWORD","rule":"RLIKE","sum":545045},{"parent":"KEYWORD","rule":"ROLLBACK","sum":5476},{"parent":"KEYWORD","rule":"ROLLUP","sum":167291},{"parent":"KEYWORD","rule":"ROW","sum":17361901},{"parent":"KEYWORD","rule":"ROWS","sum":5567923},{"parent":"KEYWORD","rule":"SAMPLE","sum":1175534},{"parent":"KEYWORD","rule":"SCHEMA","sum":20038913},{"parent":"KEYWORD","rule":"SECONDS","sum":1124664},{"parent":"KEYWORD","rule":"SEEK","sum":31},{"parent":"KEYWORD","rule":"SELECT","sum":907217677},{"parent":"KEYWORD","rule":"SEMI","sum":2942603},{"parent":"KEYWORD","rule":"SEQUENCE","sum":124757},{"parent":"KEYWORD","rule":"SET","sum":63617},{"parent":"KEYWORD","rule":"SETS","sum":164950},{"parent":"KEYWORD","rule":"SHOW","sum":359109},{"parent":"KEYWORD","rule":"SOURCE","sum":25946400},{"parent":"KEYWORD","rule":"START","sum":14010422},{"parent":"KEYWORD","rule":"STREAM","sum":2017171},{"parent":"KEYWORD","rule":"STRUCT","sum":27615632},{"parent":"KEYWORD","rule":"SUBQUERY","sum":16023107},{"parent":"KEYWORD","rule":"SUBSET","sum":38704},{"parent":"KEYWORD","rule":"SYMBOLS","sum":16686411},{"parent":"KEYWORD","rule":"SYMMETRIC","sum":26},{"parent":"KEYWORD","rule":"SYNC","sum":61036},{"parent":"KEYWORD","rule":"SYSTEM","sum":556679},{"parent":"KEYWORD","rule":"TABLE","sum":44310526},{"parent":"KEYWORD","rule":"TABLES","sum":5309885},{"parent":"KEYWORD","rule":"TABLESAMPLE","sum":329247},{"parent":"KEYWORD","rule":"TAGGED","sum":82548},{"parent":"KEYWORD","rule":"TEMP","sum":6279100},{"parent":"KEYWORD","rule":"TEMPORARY","sum":15221},{"parent":"KEYWORD","rule":"THEN","sum":158730928},{"parent":"KEYWORD","rule":"TIES","sum":89},{"parent":"KEYWORD","rule":"TO","sum":1801515},{"parent":"KEYWORD","rule":"TOPIC","sum":12388311},{"parent":"KEYWORD","rule":"TRANSACTION","sum":515613},{"parent":"KEYWORD","rule":"TRANSFER","sum":160114},{"parent":"KEYWORD","rule":"TRIGGER","sum":233646},{"parent":"KEYWORD","rule":"TRUE","sum":46741617},{"parent":"KEYWORD","rule":"TUPLE","sum":3020519},{"parent":"KEYWORD","rule":"TYPE","sum":105264622},{"parent":"KEYWORD","rule":"UNBOUNDED","sum":2506338},{"parent":"KEYWORD","rule":"UNCONDITIONAL","sum":126246},{"parent":"KEYWORD","rule":"UNION","sum":65064443},{"parent":"KEYWORD","rule":"UNIQUE","sum":2276422},{"parent":"KEYWORD","rule":"UNKNOWN","sum":696408},{"parent":"KEYWORD","rule":"UNMATCHED","sum":21458},{"parent":"KEYWORD","rule":"UPDATE","sum":4900616},{"parent":"KEYWORD","rule":"UPSERT","sum":121636},{"parent":"KEYWORD","rule":"USE","sum":330556967},{"parent":"KEYWORD","rule":"USER","sum":7320829},{"parent":"KEYWORD","rule":"USING","sum":35330151},{"parent":"KEYWORD","rule":"VACUUM","sum":116},{"parent":"KEYWORD","rule":"VALUES","sum":3662842},{"parent":"KEYWORD","rule":"VARIANT","sum":461574},{"parent":"KEYWORD","rule":"VIEW","sum":2335873},{"parent":"KEYWORD","rule":"VIRTUAL","sum":49406},{"parent":"KEYWORD","rule":"WHEN","sum":158747397},{"parent":"KEYWORD","rule":"WHERE","sum":341529965},{"parent":"KEYWORD","rule":"WINDOW","sum":14012916},{"parent":"KEYWORD","rule":"WITH","sum":163350148},{"parent":"KEYWORD","rule":"WITHOUT","sum":25028587},{"parent":"KEYWORD","rule":"WRAPPER","sum":192773},{"parent":"KEYWORD","rule":"XOR","sum":29511},{"parent":"MODULE","rule":"Compress","sum":84557},{"parent":"MODULE","rule":"DATETIME","sum":1116},{"parent":"MODULE","rule":"DATEtime","sum":2},{"parent":"MODULE","rule":"DAteTime","sum":3197},{"parent":"MODULE","rule":"DAtetime","sum":7},{"parent":"MODULE","rule":"DIgest","sum":2},{"parent":"MODULE","rule":"DaTETIME","sum":330},{"parent":"MODULE","rule":"DaTeTime","sum":84},{"parent":"MODULE","rule":"DateTIME","sum":723},{"parent":"MODULE","rule":"DateTIme","sum":4377},{"parent":"MODULE","rule":"DateTime","sum":275922461},{"parent":"MODULE","rule":"DatetIme","sum":366},{"parent":"MODULE","rule":"Datetime","sum":7139738},{"parent":"MODULE","rule":"Decompress","sum":24958},{"parent":"MODULE","rule":"Digest","sum":7752078},{"parent":"MODULE","rule":"HyperScan","sum":2270},{"parent":"MODULE","rule":"Hyperscan","sum":391141},{"parent":"MODULE","rule":"Ip","sum":1332384},{"parent":"MODULE","rule":"JSON","sum":26868},{"parent":"MODULE","rule":"JSon","sum":2},{"parent":"MODULE","rule":"Json","sum":1000957},{"parent":"MODULE","rule":"MATH","sum":216},{"parent":"MODULE","rule":"MAth","sum":1},{"parent":"MODULE","rule":"Math","sum":45129415},{"parent":"MODULE","rule":"PG","sum":201},{"parent":"MODULE","rule":"PIRE","sum":29},{"parent":"MODULE","rule":"Pg","sum":4910},{"parent":"MODULE","rule":"PgAgg","sum":2},{"parent":"MODULE","rule":"PgProc","sum":2},{"parent":"MODULE","rule":"Pire","sum":1913717},{"parent":"MODULE","rule":"Protobuf","sum":272315},{"parent":"MODULE","rule":"RE2","sum":5210},{"parent":"MODULE","rule":"Re2","sum":12256127},{"parent":"MODULE","rule":"STRING","sum":31},{"parent":"MODULE","rule":"String","sum":95856698},{"parent":"MODULE","rule":"TryDecompress","sum":4825},{"parent":"MODULE","rule":"URL","sum":53},{"parent":"MODULE","rule":"Unicode","sum":4931335},{"parent":"MODULE","rule":"Url","sum":23599129},{"parent":"MODULE","rule":"YSON","sum":483},{"parent":"MODULE","rule":"YSon","sum":26},{"parent":"MODULE","rule":"Yson","sum":396694825},{"parent":"MODULE","rule":"dateTime","sum":483},{"parent":"MODULE","rule":"datetime","sum":14258},{"parent":"MODULE","rule":"digest","sum":15},{"parent":"MODULE","rule":"json","sum":8},{"parent":"MODULE","rule":"math","sum":178},{"parent":"MODULE","rule":"pg","sum":1844},{"parent":"MODULE","rule":"pire","sum":36},{"parent":"MODULE","rule":"re2","sum":3252},{"parent":"MODULE","rule":"string","sum":103},{"parent":"MODULE","rule":"url","sum":6},{"parent":"MODULE","rule":"ySoN","sum":1},{"parent":"MODULE","rule":"yson","sum":73},{"parent":"MODULE_FUNC","rule":"Compress::BZip2","sum":2},{"parent":"MODULE_FUNC","rule":"Compress::BlockCodec","sum":6},{"parent":"MODULE_FUNC","rule":"Compress::Brotli","sum":158},{"parent":"MODULE_FUNC","rule":"Compress::Gzip","sum":83567},{"parent":"MODULE_FUNC","rule":"Compress::Lz4","sum":630},{"parent":"MODULE_FUNC","rule":"Compress::Lzma","sum":7},{"parent":"MODULE_FUNC","rule":"Compress::Snappy","sum":7},{"parent":"MODULE_FUNC","rule":"Compress::Zlib","sum":32},{"parent":"MODULE_FUNC","rule":"Compress::Zstd","sum":148},{"parent":"MODULE_FUNC","rule":"DATETIME::Format","sum":10},{"parent":"MODULE_FUNC","rule":"DATETIME::FromMilliseconds","sum":49},{"parent":"MODULE_FUNC","rule":"DATETIME::FromSeconds","sum":1},{"parent":"MODULE_FUNC","rule":"DATETIME::GetYear","sum":18},{"parent":"MODULE_FUNC","rule":"DATETIME::MakeDate","sum":734},{"parent":"MODULE_FUNC","rule":"DATETIME::MakeDatetime","sum":281},{"parent":"MODULE_FUNC","rule":"DATETIME::Parse","sum":9},{"parent":"MODULE_FUNC","rule":"DATETIME::StartOfWeek","sum":14},{"parent":"MODULE_FUNC","rule":"DATEtime::GetMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DATEtime::GetYear","sum":1},{"parent":"MODULE_FUNC","rule":"DAteTime::FromSeconds","sum":1},{"parent":"MODULE_FUNC","rule":"DAteTime::GetDayOfMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DAteTime::MakeDate","sum":596},{"parent":"MODULE_FUNC","rule":"DAteTime::Parse","sum":150},{"parent":"MODULE_FUNC","rule":"DAteTime::StartOfMonth","sum":2440},{"parent":"MODULE_FUNC","rule":"DAteTime::StartOfWeek","sum":1},{"parent":"MODULE_FUNC","rule":"DAteTime::ToDays","sum":8},{"parent":"MODULE_FUNC","rule":"DAtetime::FromSeconds","sum":1},{"parent":"MODULE_FUNC","rule":"DAtetime::MakeDatetime","sum":2},{"parent":"MODULE_FUNC","rule":"DAtetime::ToStartOfWeek","sum":4},{"parent":"MODULE_FUNC","rule":"DIgest::SipHash","sum":2},{"parent":"MODULE_FUNC","rule":"DaTETIME::StartOfWeek","sum":330},{"parent":"MODULE_FUNC","rule":"DaTeTime::GetMonth","sum":4},{"parent":"MODULE_FUNC","rule":"DaTeTime::GetYear","sum":4},{"parent":"MODULE_FUNC","rule":"DaTeTime::IntervalFromDays","sum":1},{"parent":"MODULE_FUNC","rule":"DaTeTime::MakeDate","sum":32},{"parent":"MODULE_FUNC","rule":"DaTeTime::ShiftMonths","sum":42},{"parent":"MODULE_FUNC","rule":"DaTeTime::StartOfMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTIME::IntervalFromDays","sum":723},{"parent":"MODULE_FUNC","rule":"DateTIme::EndOfMonth","sum":3},{"parent":"MODULE_FUNC","rule":"DateTIme::Format","sum":11},{"parent":"MODULE_FUNC","rule":"DateTIme::FromMicroseconds","sum":11},{"parent":"MODULE_FUNC","rule":"DateTIme::FromSeconds","sum":64},{"parent":"MODULE_FUNC","rule":"DateTIme::GetDayOfWeek","sum":44},{"parent":"MODULE_FUNC","rule":"DateTIme::GetHour","sum":2},{"parent":"MODULE_FUNC","rule":"DateTIme::GetMinute","sum":38},{"parent":"MODULE_FUNC","rule":"DateTIme::GetYear","sum":75},{"parent":"MODULE_FUNC","rule":"DateTIme::IntervalFromDays","sum":46},{"parent":"MODULE_FUNC","rule":"DateTIme::MakeDate","sum":3624},{"parent":"MODULE_FUNC","rule":"DateTIme::MakeDatetime","sum":284},{"parent":"MODULE_FUNC","rule":"DateTIme::MakeTimestamp","sum":7},{"parent":"MODULE_FUNC","rule":"DateTIme::MakeTzTimestamp","sum":4},{"parent":"MODULE_FUNC","rule":"DateTIme::Parse","sum":2},{"parent":"MODULE_FUNC","rule":"DateTIme::ParseIso8601","sum":2},{"parent":"MODULE_FUNC","rule":"DateTIme::ShiftMonths","sum":6},{"parent":"MODULE_FUNC","rule":"DateTIme::StartOfMonth","sum":135},{"parent":"MODULE_FUNC","rule":"DateTIme::StartOfWeek","sum":1},{"parent":"MODULE_FUNC","rule":"DateTIme::ToDays","sum":15},{"parent":"MODULE_FUNC","rule":"DateTIme::ToHours","sum":1},{"parent":"MODULE_FUNC","rule":"DateTIme::ToMinutes","sum":1},{"parent":"MODULE_FUNC","rule":"DateTIme::ToSeconds","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::AddTimezone","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Convert","sum":4},{"parent":"MODULE_FUNC","rule":"DateTime::CurrentDate","sum":5},{"parent":"MODULE_FUNC","rule":"DateTime::CurrentDateTimeUTC","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::CurrentUtcDate","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Date","sum":4},{"parent":"MODULE_FUNC","rule":"DateTime::DateTime","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::DatetimeStartOfMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::DayOfWeek","sum":7},{"parent":"MODULE_FUNC","rule":"DateTime::Days","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::DiffMinutes","sum":8},{"parent":"MODULE_FUNC","rule":"DateTime::DiffMonths","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Difference","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::EndOf","sum":31},{"parent":"MODULE_FUNC","rule":"DateTime::EndOfDay","sum":457},{"parent":"MODULE_FUNC","rule":"DateTime::EndOfMonth","sum":39967},{"parent":"MODULE_FUNC","rule":"DateTime::EndOfQuarter","sum":434},{"parent":"MODULE_FUNC","rule":"DateTime::EndOfWeek","sum":700},{"parent":"MODULE_FUNC","rule":"DateTime::EndOfYear","sum":159},{"parent":"MODULE_FUNC","rule":"DateTime::EndofMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::EndtOfMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::ExtractHour","sum":4},{"parent":"MODULE_FUNC","rule":"DateTime::FROMMilliseconds","sum":14},{"parent":"MODULE_FUNC","rule":"DateTime::FROMSeconds","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::Format","sum":39883228},{"parent":"MODULE_FUNC","rule":"DateTime::FormatTime","sum":6},{"parent":"MODULE_FUNC","rule":"DateTime::FromDays","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::FromMicroSeconds","sum":347},{"parent":"MODULE_FUNC","rule":"DateTime::FromMicroseconds","sum":4727932},{"parent":"MODULE_FUNC","rule":"DateTime::FromMicroseconds64","sum":175},{"parent":"MODULE_FUNC","rule":"DateTime::FromMilliSeconds","sum":48},{"parent":"MODULE_FUNC","rule":"DateTime::FromMilliSeconds64","sum":13},{"parent":"MODULE_FUNC","rule":"DateTime::FromMilliseconds","sum":9251322},{"parent":"MODULE_FUNC","rule":"DateTime::FromMilliseconds64","sum":1137},{"parent":"MODULE_FUNC","rule":"DateTime::FromSecond","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::FromSeconds","sum":15178873},{"parent":"MODULE_FUNC","rule":"DateTime::FromSeconds64","sum":1201},{"parent":"MODULE_FUNC","rule":"DateTime::FromString","sum":368},{"parent":"MODULE_FUNC","rule":"DateTime::FromTimeZone","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::Fromat","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::GetDay","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::GetDayOfMonth","sum":604386},{"parent":"MODULE_FUNC","rule":"DateTime::GetDayOfWeek","sum":639764},{"parent":"MODULE_FUNC","rule":"DateTime::GetDayOfWeekName","sum":126690},{"parent":"MODULE_FUNC","rule":"DateTime::GetDayOfYear","sum":44849},{"parent":"MODULE_FUNC","rule":"DateTime::GetHour","sum":1456870},{"parent":"MODULE_FUNC","rule":"DateTime::GetIntervalLength","sum":12},{"parent":"MODULE_FUNC","rule":"DateTime::GetLastDayOfMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::GetMicrosecondOfSecond","sum":1228},{"parent":"MODULE_FUNC","rule":"DateTime::GetMillisecondOfSecond","sum":31},{"parent":"MODULE_FUNC","rule":"DateTime::GetMinute","sum":287562},{"parent":"MODULE_FUNC","rule":"DateTime::GetMonth","sum":707908},{"parent":"MODULE_FUNC","rule":"DateTime::GetMonthName","sum":39490},{"parent":"MODULE_FUNC","rule":"DateTime::GetMonthOfYear","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::GetSecond","sum":84581},{"parent":"MODULE_FUNC","rule":"DateTime::GetTimezoneId","sum":105},{"parent":"MODULE_FUNC","rule":"DateTime::GetTimezoneName","sum":512},{"parent":"MODULE_FUNC","rule":"DateTime::GetWeek","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::GetWeekOfYear","sum":507533},{"parent":"MODULE_FUNC","rule":"DateTime::GetWeekOfYearIso8601","sum":34952},{"parent":"MODULE_FUNC","rule":"DateTime::GetYEAR","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::GetYear","sum":795744},{"parent":"MODULE_FUNC","rule":"DateTime::Getmonth","sum":24},{"parent":"MODULE_FUNC","rule":"DateTime::Interval","sum":33},{"parent":"MODULE_FUNC","rule":"DateTime::Interval64FromDays","sum":2374},{"parent":"MODULE_FUNC","rule":"DateTime::Interval64FromHours","sum":4731},{"parent":"MODULE_FUNC","rule":"DateTime::Interval64FromMicroseconds","sum":10},{"parent":"MODULE_FUNC","rule":"DateTime::Interval64FromMilliseconds","sum":40},{"parent":"MODULE_FUNC","rule":"DateTime::Interval64FromMinutes","sum":226},{"parent":"MODULE_FUNC","rule":"DateTime::Interval64FromSeconds","sum":200},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFROMDays","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFrom","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromDays","sum":15040135},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromHDays","sum":28},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromHours","sum":8990692},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromMicroseconds","sum":78478},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromMilliseconds","sum":518252},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromMinute","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromMinutes","sum":4299944},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromMonth","sum":9},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromMonths","sum":7},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromSeconds","sum":930326},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalFromYears","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalfromDays","sum":32},{"parent":"MODULE_FUNC","rule":"DateTime::IntervalfromHours","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::LastDayOfMonth","sum":6},{"parent":"MODULE_FUNC","rule":"DateTime::MakeData","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::MakeDate","sum":23268806},{"parent":"MODULE_FUNC","rule":"DateTime::MakeDate32","sum":73},{"parent":"MODULE_FUNC","rule":"DateTime::MakeDateTime","sum":401},{"parent":"MODULE_FUNC","rule":"DateTime::MakeDatetime","sum":36578590},{"parent":"MODULE_FUNC","rule":"DateTime::MakeDatetime64","sum":131},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTimestamp","sum":7846791},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTimestamp64","sum":295},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTzDate","sum":263241},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTzDate32","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTzDateTime","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTzDatetime","sum":3125311},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTzDatetime64","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTzTimestamp","sum":154779},{"parent":"MODULE_FUNC","rule":"DateTime::MakeTzTimestamp64","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::Makedate","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Makedatetime","sum":8},{"parent":"MODULE_FUNC","rule":"DateTime::MilliSeconds","sum":156},{"parent":"MODULE_FUNC","rule":"DateTime::NOW","sum":4},{"parent":"MODULE_FUNC","rule":"DateTime::Now","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::Parce","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Parse","sum":23497626},{"parent":"MODULE_FUNC","rule":"DateTime::Parse64","sum":13},{"parent":"MODULE_FUNC","rule":"DateTime::Parse8601","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::ParseDateTime","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::ParseDateTimeBestEffort","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::ParseFromString","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::ParseHttp","sum":27026},{"parent":"MODULE_FUNC","rule":"DateTime::ParseIso","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::ParseIso8601","sum":18634887},{"parent":"MODULE_FUNC","rule":"DateTime::ParseRfc822","sum":1864},{"parent":"MODULE_FUNC","rule":"DateTime::ParseX509","sum":245},{"parent":"MODULE_FUNC","rule":"DateTime::STartOfWeek","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Shift","sum":4},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftDay","sum":51},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftDays","sum":187},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftMinutes","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftMonth","sum":11},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftMonths","sum":3325455},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftQuarters","sum":392141},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftWeek","sum":7},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftWeeks","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::ShiftYears","sum":676181},{"parent":"MODULE_FUNC","rule":"DateTime::Split","sum":697412},{"parent":"MODULE_FUNC","rule":"DateTime::StartOf","sum":2349112},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfDay","sum":2667465},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfHour","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfMohth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfMonth","sum":4176127},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfQuarter","sum":559698},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfWeek","sum":2078604},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfYear","sum":948432},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfmonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::StartOfweek","sum":3},{"parent":"MODULE_FUNC","rule":"DateTime::StartofMonth","sum":6},{"parent":"MODULE_FUNC","rule":"DateTime::TimeOfDay","sum":66823},{"parent":"MODULE_FUNC","rule":"DateTime::TimestampFromMicroSeconds","sum":364},{"parent":"MODULE_FUNC","rule":"DateTime::TimestampFromMilliSeconds","sum":2455},{"parent":"MODULE_FUNC","rule":"DateTime::TimestampFromMinutes","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::TimestampFromSeconds","sum":391},{"parent":"MODULE_FUNC","rule":"DateTime::TimestampFromString","sum":422},{"parent":"MODULE_FUNC","rule":"DateTime::TimestampStartOfMonth","sum":819},{"parent":"MODULE_FUNC","rule":"DateTime::TimestampStartOfWeek","sum":398},{"parent":"MODULE_FUNC","rule":"DateTime::To","sum":5},{"parent":"MODULE_FUNC","rule":"DateTime::ToDate","sum":1413},{"parent":"MODULE_FUNC","rule":"DateTime::ToDateTime","sum":6},{"parent":"MODULE_FUNC","rule":"DateTime::ToDays","sum":3480539},{"parent":"MODULE_FUNC","rule":"DateTime::ToHours","sum":1322837},{"parent":"MODULE_FUNC","rule":"DateTime::ToIsoFormat","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::ToMicroseconds","sum":2238948},{"parent":"MODULE_FUNC","rule":"DateTime::ToMilliseconds","sum":5351906},{"parent":"MODULE_FUNC","rule":"DateTime::ToMinutes","sum":868711},{"parent":"MODULE_FUNC","rule":"DateTime::ToMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::ToMonths","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::ToSeconds","sum":23463369},{"parent":"MODULE_FUNC","rule":"DateTime::ToSeconds64","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Today","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Toseconds","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Trunc","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::Update","sum":3567595},{"parent":"MODULE_FUNC","rule":"DateTime::format","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::fromSeconds","sum":15},{"parent":"MODULE_FUNC","rule":"DateTime::makeDate","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::parse","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::parseiso8601","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::toDate","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::toMinutes","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::toSeconds","sum":2},{"parent":"MODULE_FUNC","rule":"DateTime::toStartOfMonth","sum":1},{"parent":"MODULE_FUNC","rule":"DateTime::todate","sum":1},{"parent":"MODULE_FUNC","rule":"DatetIme::IntervalFromDays","sum":366},{"parent":"MODULE_FUNC","rule":"Datetime::CurrentDate","sum":2},{"parent":"MODULE_FUNC","rule":"Datetime::CurrentUtcDatetime","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::DaysInMonth","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::EndOfMonth","sum":215},{"parent":"MODULE_FUNC","rule":"Datetime::EndOfWeek","sum":104},{"parent":"MODULE_FUNC","rule":"Datetime::Format","sum":366401},{"parent":"MODULE_FUNC","rule":"Datetime::FromMicroseconds","sum":36237},{"parent":"MODULE_FUNC","rule":"Datetime::FromMicroseconds64","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::FromMilliseconds","sum":802725},{"parent":"MODULE_FUNC","rule":"Datetime::FromSeconds","sum":568395},{"parent":"MODULE_FUNC","rule":"Datetime::FromSeconds64","sum":29},{"parent":"MODULE_FUNC","rule":"Datetime::GetDay","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::GetDayOfMonth","sum":701},{"parent":"MODULE_FUNC","rule":"Datetime::GetDayOfWeek","sum":12377},{"parent":"MODULE_FUNC","rule":"Datetime::GetDayOfWeekName","sum":838},{"parent":"MODULE_FUNC","rule":"Datetime::GetDayOfYear","sum":59},{"parent":"MODULE_FUNC","rule":"Datetime::GetHour","sum":14926},{"parent":"MODULE_FUNC","rule":"Datetime::GetMinute","sum":13952},{"parent":"MODULE_FUNC","rule":"Datetime::GetMonth","sum":1041},{"parent":"MODULE_FUNC","rule":"Datetime::GetMonthName","sum":349},{"parent":"MODULE_FUNC","rule":"Datetime::GetWeekOfYear","sum":2697},{"parent":"MODULE_FUNC","rule":"Datetime::GetWeekOfYearIso8601","sum":3},{"parent":"MODULE_FUNC","rule":"Datetime::GetYear","sum":2764},{"parent":"MODULE_FUNC","rule":"Datetime::Interval","sum":9},{"parent":"MODULE_FUNC","rule":"Datetime::IntervalFROMDays","sum":10},{"parent":"MODULE_FUNC","rule":"Datetime::IntervalFromDays","sum":375392},{"parent":"MODULE_FUNC","rule":"Datetime::IntervalFromHours","sum":268217},{"parent":"MODULE_FUNC","rule":"Datetime::IntervalFromMicroseconds","sum":194},{"parent":"MODULE_FUNC","rule":"Datetime::IntervalFromMilliseconds","sum":91},{"parent":"MODULE_FUNC","rule":"Datetime::IntervalFromMinutes","sum":50476},{"parent":"MODULE_FUNC","rule":"Datetime::IntervalFromSeconds","sum":9682},{"parent":"MODULE_FUNC","rule":"Datetime::MakeDate","sum":682816},{"parent":"MODULE_FUNC","rule":"Datetime::MakeDate32","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::MakeDateTime","sum":2},{"parent":"MODULE_FUNC","rule":"Datetime::MakeDatetime","sum":923606},{"parent":"MODULE_FUNC","rule":"Datetime::MakeDatetime64","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::MakeTimestamp","sum":412332},{"parent":"MODULE_FUNC","rule":"Datetime::MakeTzDate","sum":2339},{"parent":"MODULE_FUNC","rule":"Datetime::MakeTzDatetime","sum":24493},{"parent":"MODULE_FUNC","rule":"Datetime::MakeTzTimestamp","sum":33462},{"parent":"MODULE_FUNC","rule":"Datetime::Makedate","sum":37},{"parent":"MODULE_FUNC","rule":"Datetime::Parse","sum":138374},{"parent":"MODULE_FUNC","rule":"Datetime::ParseIso8601","sum":259540},{"parent":"MODULE_FUNC","rule":"Datetime::ShiftMonths","sum":25893},{"parent":"MODULE_FUNC","rule":"Datetime::ShiftQuarters","sum":561},{"parent":"MODULE_FUNC","rule":"Datetime::ShiftYears","sum":333},{"parent":"MODULE_FUNC","rule":"Datetime::Split","sum":207},{"parent":"MODULE_FUNC","rule":"Datetime::StarOfWeek","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::StartOf","sum":64208},{"parent":"MODULE_FUNC","rule":"Datetime::StartOfDay","sum":24485},{"parent":"MODULE_FUNC","rule":"Datetime::StartOfMonth","sum":74980},{"parent":"MODULE_FUNC","rule":"Datetime::StartOfQuarter","sum":4440},{"parent":"MODULE_FUNC","rule":"Datetime::StartOfWeek","sum":23101},{"parent":"MODULE_FUNC","rule":"Datetime::StartOfYear","sum":11700},{"parent":"MODULE_FUNC","rule":"Datetime::TimeOfDay","sum":121},{"parent":"MODULE_FUNC","rule":"Datetime::ToDatetime","sum":12},{"parent":"MODULE_FUNC","rule":"Datetime::ToDays","sum":142671},{"parent":"MODULE_FUNC","rule":"Datetime::ToHours","sum":22974},{"parent":"MODULE_FUNC","rule":"Datetime::ToMicroseconds","sum":594},{"parent":"MODULE_FUNC","rule":"Datetime::ToMilliseconds","sum":121225},{"parent":"MODULE_FUNC","rule":"Datetime::ToMinutes","sum":45638},{"parent":"MODULE_FUNC","rule":"Datetime::ToSeconds","sum":1542105},{"parent":"MODULE_FUNC","rule":"Datetime::Update","sum":29592},{"parent":"MODULE_FUNC","rule":"Datetime::split","sum":1},{"parent":"MODULE_FUNC","rule":"Datetime::startOfmonth","sum":3},{"parent":"MODULE_FUNC","rule":"Decompress::BZip2","sum":525},{"parent":"MODULE_FUNC","rule":"Decompress::Brotli","sum":7877},{"parent":"MODULE_FUNC","rule":"Decompress::Gzip","sum":3875},{"parent":"MODULE_FUNC","rule":"Decompress::Lz4","sum":903},{"parent":"MODULE_FUNC","rule":"Decompress::Snappy","sum":458},{"parent":"MODULE_FUNC","rule":"Decompress::Zlib","sum":11289},{"parent":"MODULE_FUNC","rule":"Decompress::Zstd","sum":31},{"parent":"MODULE_FUNC","rule":"Digest::Argon2","sum":48395},{"parent":"MODULE_FUNC","rule":"Digest::Blake2B","sum":4505},{"parent":"MODULE_FUNC","rule":"Digest::CityHash","sum":1233478},{"parent":"MODULE_FUNC","rule":"Digest::CityHash128","sum":18331},{"parent":"MODULE_FUNC","rule":"Digest::Crc32c","sum":76791},{"parent":"MODULE_FUNC","rule":"Digest::Crc64","sum":141102},{"parent":"MODULE_FUNC","rule":"Digest::FarmHashFingerprint","sum":70611},{"parent":"MODULE_FUNC","rule":"Digest::FarmHashFingerprint128","sum":21},{"parent":"MODULE_FUNC","rule":"Digest::FarmHashFingerprint2","sum":168021},{"parent":"MODULE_FUNC","rule":"Digest::FarmHashFingerprint32","sum":196},{"parent":"MODULE_FUNC","rule":"Digest::FarmHashFingerprint64","sum":1054756},{"parent":"MODULE_FUNC","rule":"Digest::Fnv32","sum":1746},{"parent":"MODULE_FUNC","rule":"Digest::Fnv64","sum":261115},{"parent":"MODULE_FUNC","rule":"Digest::IntHash64","sum":18036},{"parent":"MODULE_FUNC","rule":"Digest::MD5Hex","sum":7},{"parent":"MODULE_FUNC","rule":"Digest::Md5","sum":2},{"parent":"MODULE_FUNC","rule":"Digest::Md5HalfMix","sum":429950},{"parent":"MODULE_FUNC","rule":"Digest::Md5Hex","sum":570452},{"parent":"MODULE_FUNC","rule":"Digest::Md5Raw","sum":15682},{"parent":"MODULE_FUNC","rule":"Digest::MurMurHash","sum":2438433},{"parent":"MODULE_FUNC","rule":"Digest::MurMurHash2A","sum":2526},{"parent":"MODULE_FUNC","rule":"Digest::MurMurHash2A32","sum":825},{"parent":"MODULE_FUNC","rule":"Digest::MurMurHash32","sum":255241},{"parent":"MODULE_FUNC","rule":"Digest::MurMurhash","sum":2},{"parent":"MODULE_FUNC","rule":"Digest::NimericHash","sum":3},{"parent":"MODULE_FUNC","rule":"Digest::NumericHash","sum":281580},{"parent":"MODULE_FUNC","rule":"Digest::Sha1","sum":42729},{"parent":"MODULE_FUNC","rule":"Digest::Sha256","sum":401820},{"parent":"MODULE_FUNC","rule":"Digest::SipHash","sum":133034},{"parent":"MODULE_FUNC","rule":"Digest::SuperFastHash","sum":35357},{"parent":"MODULE_FUNC","rule":"Digest::XXH3","sum":47306},{"parent":"MODULE_FUNC","rule":"Digest::XXH3_128","sum":22},{"parent":"MODULE_FUNC","rule":"Digest::murmurhash","sum":3},{"parent":"MODULE_FUNC","rule":"HyperScan::BacktrackingGrep","sum":1},{"parent":"MODULE_FUNC","rule":"HyperScan::Grep","sum":2263},{"parent":"MODULE_FUNC","rule":"HyperScan::Match","sum":6},{"parent":"MODULE_FUNC","rule":"Hyperscan::BacktrackingGrep","sum":50608},{"parent":"MODULE_FUNC","rule":"Hyperscan::BacktrackingMatch","sum":129},{"parent":"MODULE_FUNC","rule":"Hyperscan::Capture","sum":5532},{"parent":"MODULE_FUNC","rule":"Hyperscan::Grep","sum":144521},{"parent":"MODULE_FUNC","rule":"Hyperscan::Match","sum":52414},{"parent":"MODULE_FUNC","rule":"Hyperscan::MultiGrep","sum":64},{"parent":"MODULE_FUNC","rule":"Hyperscan::MultiMatch","sum":40524},{"parent":"MODULE_FUNC","rule":"Hyperscan::Replace","sum":97349},{"parent":"MODULE_FUNC","rule":"Ip::ConvertToIPv6","sum":45141},{"parent":"MODULE_FUNC","rule":"Ip::FromString","sum":392805},{"parent":"MODULE_FUNC","rule":"Ip::GetSubnet","sum":135330},{"parent":"MODULE_FUNC","rule":"Ip::GetSubnetByMask","sum":4},{"parent":"MODULE_FUNC","rule":"Ip::IsEmbeddedIPv4","sum":6947},{"parent":"MODULE_FUNC","rule":"Ip::IsIPv4","sum":135888},{"parent":"MODULE_FUNC","rule":"Ip::IsIPv6","sum":118294},{"parent":"MODULE_FUNC","rule":"Ip::SubnetFromString","sum":569},{"parent":"MODULE_FUNC","rule":"Ip::SubnetMatch","sum":516},{"parent":"MODULE_FUNC","rule":"Ip::ToFixedIPv6String","sum":3812},{"parent":"MODULE_FUNC","rule":"Ip::ToString","sum":493078},{"parent":"MODULE_FUNC","rule":"JSON::ConvertToDouble","sum":19612},{"parent":"MODULE_FUNC","rule":"JSON::ConvertToInt64","sum":3261},{"parent":"MODULE_FUNC","rule":"JSON::ConvertToList","sum":15},{"parent":"MODULE_FUNC","rule":"JSON::ConvertToString","sum":133},{"parent":"MODULE_FUNC","rule":"JSON::ConvertToStringList","sum":4},{"parent":"MODULE_FUNC","rule":"JSON::From","sum":5},{"parent":"MODULE_FUNC","rule":"JSON::LookupBool","sum":5},{"parent":"MODULE_FUNC","rule":"JSON::LookupDouble","sum":10},{"parent":"MODULE_FUNC","rule":"JSON::LookupInt64","sum":8},{"parent":"MODULE_FUNC","rule":"JSON::LookupString","sum":259},{"parent":"MODULE_FUNC","rule":"JSON::PARSE","sum":2},{"parent":"MODULE_FUNC","rule":"JSON::Parse","sum":3554},{"parent":"MODULE_FUNC","rule":"JSon::From","sum":2},{"parent":"MODULE_FUNC","rule":"Json::Attributes","sum":2},{"parent":"MODULE_FUNC","rule":"Json::Contains","sum":1},{"parent":"MODULE_FUNC","rule":"Json::ConvertToBool","sum":5},{"parent":"MODULE_FUNC","rule":"Json::ConvertToDict","sum":114},{"parent":"MODULE_FUNC","rule":"Json::ConvertToDouble","sum":1},{"parent":"MODULE_FUNC","rule":"Json::ConvertToInt64","sum":1},{"parent":"MODULE_FUNC","rule":"Json::ConvertToList","sum":117},{"parent":"MODULE_FUNC","rule":"Json::ConvertToString","sum":169},{"parent":"MODULE_FUNC","rule":"Json::ConvertToStringDict","sum":5},{"parent":"MODULE_FUNC","rule":"Json::ConvertToStringList","sum":19},{"parent":"MODULE_FUNC","rule":"Json::From","sum":4018},{"parent":"MODULE_FUNC","rule":"Json::FromString","sum":16},{"parent":"MODULE_FUNC","rule":"Json::GetField","sum":21},{"parent":"MODULE_FUNC","rule":"Json::GetHash","sum":1},{"parent":"MODULE_FUNC","rule":"Json::GetLength","sum":19},{"parent":"MODULE_FUNC","rule":"Json::Lookup","sum":1},{"parent":"MODULE_FUNC","rule":"Json::LookupInt64","sum":808376},{"parent":"MODULE_FUNC","rule":"Json::LookupString","sum":53},{"parent":"MODULE_FUNC","rule":"Json::Options","sum":852},{"parent":"MODULE_FUNC","rule":"Json::Parse","sum":183283},{"parent":"MODULE_FUNC","rule":"Json::ParseJson","sum":217},{"parent":"MODULE_FUNC","rule":"Json::Serialize","sum":1558},{"parent":"MODULE_FUNC","rule":"Json::SerializeJson","sum":934},{"parent":"MODULE_FUNC","rule":"Json::SerializePretty","sum":1136},{"parent":"MODULE_FUNC","rule":"Json::SerializeText","sum":3},{"parent":"MODULE_FUNC","rule":"Json::YPath","sum":20},{"parent":"MODULE_FUNC","rule":"Json::YPathDict","sum":14},{"parent":"MODULE_FUNC","rule":"Json::YPathString","sum":1},{"parent":"MODULE_FUNC","rule":"MATH::ABS","sum":7},{"parent":"MODULE_FUNC","rule":"MATH::Cos","sum":5},{"parent":"MODULE_FUNC","rule":"MATH::EXP","sum":1},{"parent":"MODULE_FUNC","rule":"MATH::Log","sum":5},{"parent":"MODULE_FUNC","rule":"MATH::NearbyINT","sum":1},{"parent":"MODULE_FUNC","rule":"MATH::NearbyInt","sum":1},{"parent":"MODULE_FUNC","rule":"MATH::ROUND","sum":194},{"parent":"MODULE_FUNC","rule":"MATH::Round","sum":1},{"parent":"MODULE_FUNC","rule":"MATH::Sigmoid","sum":1},{"parent":"MODULE_FUNC","rule":"MAth::Round","sum":1},{"parent":"MODULE_FUNC","rule":"Math::Abs","sum":477751},{"parent":"MODULE_FUNC","rule":"Math::Acos","sum":13940},{"parent":"MODULE_FUNC","rule":"Math::Asin","sum":11850},{"parent":"MODULE_FUNC","rule":"Math::Asinh","sum":4},{"parent":"MODULE_FUNC","rule":"Math::Atan","sum":8001},{"parent":"MODULE_FUNC","rule":"Math::Atan2","sum":13656},{"parent":"MODULE_FUNC","rule":"Math::Cbrt","sum":499},{"parent":"MODULE_FUNC","rule":"Math::Ceil","sum":1243601},{"parent":"MODULE_FUNC","rule":"Math::Cos","sum":102867},{"parent":"MODULE_FUNC","rule":"Math::Cosh","sum":5},{"parent":"MODULE_FUNC","rule":"Math::Crbt","sum":1},{"parent":"MODULE_FUNC","rule":"Math::E","sum":9592},{"parent":"MODULE_FUNC","rule":"Math::EXP","sum":1},{"parent":"MODULE_FUNC","rule":"Math::Eps","sum":179},{"parent":"MODULE_FUNC","rule":"Math::Erf","sum":2571},{"parent":"MODULE_FUNC","rule":"Math::ErfInv","sum":42},{"parent":"MODULE_FUNC","rule":"Math::ErfcInv","sum":6},{"parent":"MODULE_FUNC","rule":"Math::Exp","sum":557432},{"parent":"MODULE_FUNC","rule":"Math::Exp2","sum":1896},{"parent":"MODULE_FUNC","rule":"Math::Fabs","sum":144275},{"parent":"MODULE_FUNC","rule":"Math::Floor","sum":328631},{"parent":"MODULE_FUNC","rule":"Math::Flor","sum":1},{"parent":"MODULE_FUNC","rule":"Math::Fmod","sum":9},{"parent":"MODULE_FUNC","rule":"Math::FuzzyEquals","sum":20073},{"parent":"MODULE_FUNC","rule":"Math::Hypot","sum":18932},{"parent":"MODULE_FUNC","rule":"Math::IsFinite","sum":187126},{"parent":"MODULE_FUNC","rule":"Math::IsInf","sum":77827},{"parent":"MODULE_FUNC","rule":"Math::IsNaN","sum":250614},{"parent":"MODULE_FUNC","rule":"Math::IsNan","sum":6},{"parent":"MODULE_FUNC","rule":"Math::Ldexp","sum":47},{"parent":"MODULE_FUNC","rule":"Math::Lgamma","sum":4},{"parent":"MODULE_FUNC","rule":"Math::Log","sum":822425},{"parent":"MODULE_FUNC","rule":"Math::Log10","sum":155984},{"parent":"MODULE_FUNC","rule":"Math::Log2","sum":197686},{"parent":"MODULE_FUNC","rule":"Math::Max","sum":3},{"parent":"MODULE_FUNC","rule":"Math::Min","sum":1},{"parent":"MODULE_FUNC","rule":"Math::Mod","sum":66821},{"parent":"MODULE_FUNC","rule":"Math::NearbyInt","sum":437889},{"parent":"MODULE_FUNC","rule":"Math::Pi","sum":76334},{"parent":"MODULE_FUNC","rule":"Math::Pow","sum":1337716},{"parent":"MODULE_FUNC","rule":"Math::Power","sum":6},{"parent":"MODULE_FUNC","rule":"Math::ROUND","sum":7},{"parent":"MODULE_FUNC","rule":"Math::Rem","sum":2241},{"parent":"MODULE_FUNC","rule":"Math::Remainder","sum":163},{"parent":"MODULE_FUNC","rule":"Math::Rint","sum":20317},{"parent":"MODULE_FUNC","rule":"Math::Round","sum":36951846},{"parent":"MODULE_FUNC","rule":"Math::RoundDownward","sum":140193},{"parent":"MODULE_FUNC","rule":"Math::RoundToNearest","sum":77617},{"parent":"MODULE_FUNC","rule":"Math::RoundTowardZero","sum":887},{"parent":"MODULE_FUNC","rule":"Math::RoundUpward","sum":219263},{"parent":"MODULE_FUNC","rule":"Math::SQRT","sum":8},{"parent":"MODULE_FUNC","rule":"Math::Sigmoid","sum":278316},{"parent":"MODULE_FUNC","rule":"Math::Sin","sum":87071},{"parent":"MODULE_FUNC","rule":"Math::Sinh","sum":6023},{"parent":"MODULE_FUNC","rule":"Math::Sqrt","sum":612516},{"parent":"MODULE_FUNC","rule":"Math::Tan","sum":5112},{"parent":"MODULE_FUNC","rule":"Math::Tanh","sum":5032},{"parent":"MODULE_FUNC","rule":"Math::Tgamma","sum":60},{"parent":"MODULE_FUNC","rule":"Math::Trunc","sum":156248},{"parent":"MODULE_FUNC","rule":"Math::abs","sum":2},{"parent":"MODULE_FUNC","rule":"Math::ceil","sum":8},{"parent":"MODULE_FUNC","rule":"Math::cos","sum":2},{"parent":"MODULE_FUNC","rule":"Math::exp","sum":18},{"parent":"MODULE_FUNC","rule":"Math::floor","sum":55},{"parent":"MODULE_FUNC","rule":"Math::isnan","sum":1},{"parent":"MODULE_FUNC","rule":"Math::pow","sum":1},{"parent":"MODULE_FUNC","rule":"Math::round","sum":99},{"parent":"MODULE_FUNC","rule":"Math::sin","sum":2},{"parent":"MODULE_FUNC","rule":"Math::sqrt","sum":3},{"parent":"MODULE_FUNC","rule":"PG::ARRAY_AGG","sum":7},{"parent":"MODULE_FUNC","rule":"PG::STRING_AGG","sum":37},{"parent":"MODULE_FUNC","rule":"PG::generate_series","sum":7},{"parent":"MODULE_FUNC","rule":"PG::json_object_keys","sum":19},{"parent":"MODULE_FUNC","rule":"PG::jsonb_object_keys","sum":18},{"parent":"MODULE_FUNC","rule":"PG::string_agg","sum":104},{"parent":"MODULE_FUNC","rule":"PG::to_hex","sum":9},{"parent":"MODULE_FUNC","rule":"PIRE::Capture","sum":7},{"parent":"MODULE_FUNC","rule":"PIRE::Grep","sum":22},{"parent":"MODULE_FUNC","rule":"Pg::ARRAY_AGG","sum":11},{"parent":"MODULE_FUNC","rule":"Pg::Array_Agg","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::CONCAT","sum":12},{"parent":"MODULE_FUNC","rule":"Pg::Date","sum":3},{"parent":"MODULE_FUNC","rule":"Pg::GENERATE_SERIES","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::SPLIT_PART","sum":5},{"parent":"MODULE_FUNC","rule":"Pg::STRING_AGG","sum":52},{"parent":"MODULE_FUNC","rule":"Pg::ST_Area","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::ST_AsEWKB","sum":57},{"parent":"MODULE_FUNC","rule":"Pg::ST_AsEWKT","sum":15},{"parent":"MODULE_FUNC","rule":"Pg::ST_AsGeoJSON","sum":7},{"parent":"MODULE_FUNC","rule":"Pg::ST_AsSVG","sum":3},{"parent":"MODULE_FUNC","rule":"Pg::ST_AsText","sum":57},{"parent":"MODULE_FUNC","rule":"Pg::ST_Boundary","sum":43},{"parent":"MODULE_FUNC","rule":"Pg::ST_Centroid","sum":14},{"parent":"MODULE_FUNC","rule":"Pg::ST_ClosestPoint","sum":37},{"parent":"MODULE_FUNC","rule":"Pg::ST_Contains","sum":3},{"parent":"MODULE_FUNC","rule":"Pg::ST_Distance","sum":13},{"parent":"MODULE_FUNC","rule":"Pg::ST_GeoHash","sum":15},{"parent":"MODULE_FUNC","rule":"Pg::ST_GeomFromEWKB","sum":86},{"parent":"MODULE_FUNC","rule":"Pg::ST_GeomFromGeoHash","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::ST_GeomFromText","sum":65},{"parent":"MODULE_FUNC","rule":"Pg::ST_GeomFromWKB","sum":7},{"parent":"MODULE_FUNC","rule":"Pg::ST_Intersects","sum":13},{"parent":"MODULE_FUNC","rule":"Pg::ST_IsValid","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::ST_MakePoint","sum":7},{"parent":"MODULE_FUNC","rule":"Pg::ST_MakeValid","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::ST_Point","sum":6},{"parent":"MODULE_FUNC","rule":"Pg::ST_PointOnSurface","sum":17},{"parent":"MODULE_FUNC","rule":"Pg::ST_Scale","sum":3},{"parent":"MODULE_FUNC","rule":"Pg::ST_SetSRID","sum":6},{"parent":"MODULE_FUNC","rule":"Pg::ST_Transform","sum":183},{"parent":"MODULE_FUNC","rule":"Pg::ST_X","sum":72},{"parent":"MODULE_FUNC","rule":"Pg::ST_Y","sum":66},{"parent":"MODULE_FUNC","rule":"Pg::St_geomfromewkb","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::String_Agg","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::age","sum":8},{"parent":"MODULE_FUNC","rule":"Pg::array_agg","sum":9},{"parent":"MODULE_FUNC","rule":"Pg::array_length","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::bit_length","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::center","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::concat","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::date_generate_series","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::date_part","sum":8},{"parent":"MODULE_FUNC","rule":"Pg::date_trunc","sum":11},{"parent":"MODULE_FUNC","rule":"Pg::extract","sum":136},{"parent":"MODULE_FUNC","rule":"Pg::generate_series","sum":1523},{"parent":"MODULE_FUNC","rule":"Pg::json_object_agg","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::lower","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::max","sum":364},{"parent":"MODULE_FUNC","rule":"Pg::sind","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::split_part","sum":20},{"parent":"MODULE_FUNC","rule":"Pg::st_asgeojson","sum":1},{"parent":"MODULE_FUNC","rule":"Pg::st_astext","sum":6},{"parent":"MODULE_FUNC","rule":"Pg::st_collect","sum":8},{"parent":"MODULE_FUNC","rule":"Pg::st_geomfromewkb","sum":22},{"parent":"MODULE_FUNC","rule":"Pg::st_intersects","sum":9},{"parent":"MODULE_FUNC","rule":"Pg::st_transform","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::st_union","sum":8},{"parent":"MODULE_FUNC","rule":"Pg::string_Agg","sum":2},{"parent":"MODULE_FUNC","rule":"Pg::string_agg","sum":1771},{"parent":"MODULE_FUNC","rule":"Pg::to_char","sum":18},{"parent":"MODULE_FUNC","rule":"Pg::to_timestamp","sum":79},{"parent":"MODULE_FUNC","rule":"Pg::version","sum":3},{"parent":"MODULE_FUNC","rule":"PgAgg::string_agg","sum":2},{"parent":"MODULE_FUNC","rule":"PgProc::upper","sum":2},{"parent":"MODULE_FUNC","rule":"Pire::Capture","sum":525813},{"parent":"MODULE_FUNC","rule":"Pire::Grep","sum":144439},{"parent":"MODULE_FUNC","rule":"Pire::Match","sum":235092},{"parent":"MODULE_FUNC","rule":"Pire::MultiGrep","sum":684},{"parent":"MODULE_FUNC","rule":"Pire::MultiMatch","sum":152},{"parent":"MODULE_FUNC","rule":"Pire::Replace","sum":1007537},{"parent":"MODULE_FUNC","rule":"Protobuf::Parse","sum":21267},{"parent":"MODULE_FUNC","rule":"Protobuf::Serialize","sum":104073},{"parent":"MODULE_FUNC","rule":"Protobuf::TryParse","sum":146975},{"parent":"MODULE_FUNC","rule":"RE2::Capture","sum":4074},{"parent":"MODULE_FUNC","rule":"RE2::Count","sum":370},{"parent":"MODULE_FUNC","rule":"RE2::FindAndConsume","sum":31},{"parent":"MODULE_FUNC","rule":"RE2::Grep","sum":68},{"parent":"MODULE_FUNC","rule":"RE2::Match","sum":543},{"parent":"MODULE_FUNC","rule":"RE2::Replace","sum":124},{"parent":"MODULE_FUNC","rule":"Re2::Capture","sum":4426150},{"parent":"MODULE_FUNC","rule":"Re2::Catch","sum":1},{"parent":"MODULE_FUNC","rule":"Re2::Compile","sum":4},{"parent":"MODULE_FUNC","rule":"Re2::Count","sum":172459},{"parent":"MODULE_FUNC","rule":"Re2::FindAll","sum":2},{"parent":"MODULE_FUNC","rule":"Re2::FindAllSubmatch","sum":2},{"parent":"MODULE_FUNC","rule":"Re2::FindAndConsume","sum":389398},{"parent":"MODULE_FUNC","rule":"Re2::Grep","sum":657664},{"parent":"MODULE_FUNC","rule":"Re2::Match","sum":1681940},{"parent":"MODULE_FUNC","rule":"Re2::Options","sum":246586},{"parent":"MODULE_FUNC","rule":"Re2::Replace","sum":4681906},{"parent":"MODULE_FUNC","rule":"Re2::ReplaceAll","sum":15},{"parent":"MODULE_FUNC","rule":"STRING::AsciiToLower","sum":1},{"parent":"MODULE_FUNC","rule":"STRING::CONTAINS","sum":2},{"parent":"MODULE_FUNC","rule":"STRING::Contains","sum":2},{"parent":"MODULE_FUNC","rule":"STRING::RemoveAll","sum":1},{"parent":"MODULE_FUNC","rule":"STRING::ReplaceFirst","sum":20},{"parent":"MODULE_FUNC","rule":"STRING::SplitToList","sum":5},{"parent":"MODULE_FUNC","rule":"String::ASciiToLower","sum":2},{"parent":"MODULE_FUNC","rule":"String::AsciiToLower","sum":4129718},{"parent":"MODULE_FUNC","rule":"String::AsciiToTitle","sum":98428},{"parent":"MODULE_FUNC","rule":"String::AsciiToUpper","sum":546689},{"parent":"MODULE_FUNC","rule":"String::AsciiTolower","sum":5},{"parent":"MODULE_FUNC","rule":"String::Base32Decode","sum":276},{"parent":"MODULE_FUNC","rule":"String::Base32Encode","sum":196},{"parent":"MODULE_FUNC","rule":"String::Base32StrictDecode","sum":56},{"parent":"MODULE_FUNC","rule":"String::Base64Decode","sum":396077},{"parent":"MODULE_FUNC","rule":"String::Base64Encode","sum":112569},{"parent":"MODULE_FUNC","rule":"String::Base64EncodeUrl","sum":5853},{"parent":"MODULE_FUNC","rule":"String::Base64StrictDecode","sum":96311},{"parent":"MODULE_FUNC","rule":"String::Bin","sum":496},{"parent":"MODULE_FUNC","rule":"String::BinText","sum":121},{"parent":"MODULE_FUNC","rule":"String::CgiEscape","sum":74375},{"parent":"MODULE_FUNC","rule":"String::CgiUnescape","sum":24260},{"parent":"MODULE_FUNC","rule":"String::ColapseText","sum":4},{"parent":"MODULE_FUNC","rule":"String::Collapse","sum":201577},{"parent":"MODULE_FUNC","rule":"String::CollapseText","sum":202243},{"parent":"MODULE_FUNC","rule":"String::Contains","sum":6171324},{"parent":"MODULE_FUNC","rule":"String::DecodeHtml","sum":3052},{"parent":"MODULE_FUNC","rule":"String::EncodeHtml","sum":415},{"parent":"MODULE_FUNC","rule":"String::EndsWith","sum":538944},{"parent":"MODULE_FUNC","rule":"String::EndsWithIgnoreCase","sum":36066},{"parent":"MODULE_FUNC","rule":"String::EscapeC","sum":55954},{"parent":"MODULE_FUNC","rule":"String::Find","sum":653752},{"parent":"MODULE_FUNC","rule":"String::From","sum":2},{"parent":"MODULE_FUNC","rule":"String::FromByteList","sum":1039651},{"parent":"MODULE_FUNC","rule":"String::HasPrefix","sum":21399},{"parent":"MODULE_FUNC","rule":"String::HasPrefixIgnoreCase","sum":49},{"parent":"MODULE_FUNC","rule":"String::HasSuffix","sum":4898},{"parent":"MODULE_FUNC","rule":"String::HasSuffixIgnoreCase","sum":28654},{"parent":"MODULE_FUNC","rule":"String::Hex","sum":381613},{"parent":"MODULE_FUNC","rule":"String::HexDecode","sum":166472},{"parent":"MODULE_FUNC","rule":"String::HexEncode","sum":196478},{"parent":"MODULE_FUNC","rule":"String::HexText","sum":78340},{"parent":"MODULE_FUNC","rule":"String::HumanReadableBytes","sum":260},{"parent":"MODULE_FUNC","rule":"String::HumanReadableDuration","sum":1132817},{"parent":"MODULE_FUNC","rule":"String::HumanReadableQuantity","sum":344},{"parent":"MODULE_FUNC","rule":"String::IsAscii","sum":14113},{"parent":"MODULE_FUNC","rule":"String::IsAsciiAlnum","sum":1024},{"parent":"MODULE_FUNC","rule":"String::IsAsciiAlpha","sum":383},{"parent":"MODULE_FUNC","rule":"String::IsAsciiDigit","sum":8385},{"parent":"MODULE_FUNC","rule":"String::IsAsciiHex","sum":19397},{"parent":"MODULE_FUNC","rule":"String::IsAsciiLower","sum":22},{"parent":"MODULE_FUNC","rule":"String::IsAsciiSpace","sum":13},{"parent":"MODULE_FUNC","rule":"String::IsAsciiUpper","sum":361},{"parent":"MODULE_FUNC","rule":"String::Join","sum":2},{"parent":"MODULE_FUNC","rule":"String::JoinFROMList","sum":31064},{"parent":"MODULE_FUNC","rule":"String::JoinFromList","sum":14043281},{"parent":"MODULE_FUNC","rule":"String::LeftPad","sum":66755},{"parent":"MODULE_FUNC","rule":"String::Length","sum":2},{"parent":"MODULE_FUNC","rule":"String::LevenshteinDistance","sum":4},{"parent":"MODULE_FUNC","rule":"String::LevensteinDistance","sum":11867},{"parent":"MODULE_FUNC","rule":"String::Prec","sum":1845},{"parent":"MODULE_FUNC","rule":"String::RaplaceAll","sum":3},{"parent":"MODULE_FUNC","rule":"String::RemoveAll","sum":1249625},{"parent":"MODULE_FUNC","rule":"String::RemoveFirst","sum":643653},{"parent":"MODULE_FUNC","rule":"String::RemoveLast","sum":560035},{"parent":"MODULE_FUNC","rule":"String::Replace","sum":15},{"parent":"MODULE_FUNC","rule":"String::ReplaceALL","sum":3},{"parent":"MODULE_FUNC","rule":"String::ReplaceAll","sum":15745280},{"parent":"MODULE_FUNC","rule":"String::ReplaceFirst","sum":1371180},{"parent":"MODULE_FUNC","rule":"String::ReplaceFirstStartsWith","sum":1},{"parent":"MODULE_FUNC","rule":"String::ReplaceLast","sum":175893},{"parent":"MODULE_FUNC","rule":"String::ReplaceRegex","sum":1},{"parent":"MODULE_FUNC","rule":"String::Reverse","sum":119905},{"parent":"MODULE_FUNC","rule":"String::ReverseFind","sum":38777},{"parent":"MODULE_FUNC","rule":"String::RightPad","sum":378937},{"parent":"MODULE_FUNC","rule":"String::SBin","sum":7},{"parent":"MODULE_FUNC","rule":"String::SHex","sum":6272},{"parent":"MODULE_FUNC","rule":"String::Split","sum":10},{"parent":"MODULE_FUNC","rule":"String::SplitToList","sum":31992556},{"parent":"MODULE_FUNC","rule":"String::SplitToSet","sum":12},{"parent":"MODULE_FUNC","rule":"String::SplitTolist","sum":13},{"parent":"MODULE_FUNC","rule":"String::Splittolist","sum":2},{"parent":"MODULE_FUNC","rule":"String::StartWith","sum":1},{"parent":"MODULE_FUNC","rule":"String::StartsWith","sum":3453365},{"parent":"MODULE_FUNC","rule":"String::StartsWithIgnoreCase","sum":55738},{"parent":"MODULE_FUNC","rule":"String::Strip","sum":3186400},{"parent":"MODULE_FUNC","rule":"String::Substring","sum":304256},{"parent":"MODULE_FUNC","rule":"String::ToByteList","sum":140742},{"parent":"MODULE_FUNC","rule":"String::ToLower","sum":5306981},{"parent":"MODULE_FUNC","rule":"String::ToLowerCase","sum":1},{"parent":"MODULE_FUNC","rule":"String::ToTitle","sum":34745},{"parent":"MODULE_FUNC","rule":"String::ToUpper","sum":141158},{"parent":"MODULE_FUNC","rule":"String::Trim","sum":3},{"parent":"MODULE_FUNC","rule":"String::UnescapeC","sum":352860},{"parent":"MODULE_FUNC","rule":"String::contains","sum":3},{"parent":"MODULE_FUNC","rule":"String::splittolist","sum":1},{"parent":"MODULE_FUNC","rule":"String::strip","sum":4},{"parent":"MODULE_FUNC","rule":"String::tolower","sum":2},{"parent":"MODULE_FUNC","rule":"TryDecompress::BZip2","sum":4},{"parent":"MODULE_FUNC","rule":"TryDecompress::BlockCodec","sum":1},{"parent":"MODULE_FUNC","rule":"TryDecompress::Brotli","sum":11},{"parent":"MODULE_FUNC","rule":"TryDecompress::Gzip","sum":1012},{"parent":"MODULE_FUNC","rule":"TryDecompress::Lz4","sum":171},{"parent":"MODULE_FUNC","rule":"TryDecompress::Lzma","sum":4},{"parent":"MODULE_FUNC","rule":"TryDecompress::Snappy","sum":10},{"parent":"MODULE_FUNC","rule":"TryDecompress::Xz","sum":4},{"parent":"MODULE_FUNC","rule":"TryDecompress::Zlib","sum":3590},{"parent":"MODULE_FUNC","rule":"TryDecompress::Zstd","sum":18},{"parent":"MODULE_FUNC","rule":"URL::Decode","sum":5},{"parent":"MODULE_FUNC","rule":"URL::GetHost","sum":2},{"parent":"MODULE_FUNC","rule":"URL::GetOwner","sum":40},{"parent":"MODULE_FUNC","rule":"URL::Normalize","sum":6},{"parent":"MODULE_FUNC","rule":"Unicode::FInd","sum":4},{"parent":"MODULE_FUNC","rule":"Unicode::Find","sum":154963},{"parent":"MODULE_FUNC","rule":"Unicode::Fold","sum":29226},{"parent":"MODULE_FUNC","rule":"Unicode::FromCodePointList","sum":120339},{"parent":"MODULE_FUNC","rule":"Unicode::GetLength","sum":595220},{"parent":"MODULE_FUNC","rule":"Unicode::GetLengthn","sum":1},{"parent":"MODULE_FUNC","rule":"Unicode::IsAlnum","sum":545},{"parent":"MODULE_FUNC","rule":"Unicode::IsAlpha","sum":460},{"parent":"MODULE_FUNC","rule":"Unicode::IsAscii","sum":719},{"parent":"MODULE_FUNC","rule":"Unicode::IsDigit","sum":8978},{"parent":"MODULE_FUNC","rule":"Unicode::IsHex","sum":5},{"parent":"MODULE_FUNC","rule":"Unicode::IsLower","sum":96},{"parent":"MODULE_FUNC","rule":"Unicode::IsSpace","sum":18},{"parent":"MODULE_FUNC","rule":"Unicode::IsUnicodeSet","sum":448},{"parent":"MODULE_FUNC","rule":"Unicode::IsUpper","sum":1803},{"parent":"MODULE_FUNC","rule":"Unicode::IsUtf","sum":671535},{"parent":"MODULE_FUNC","rule":"Unicode::JoinFromList","sum":204153},{"parent":"MODULE_FUNC","rule":"Unicode::Length","sum":2},{"parent":"MODULE_FUNC","rule":"Unicode::LevensteinDistance","sum":40464},{"parent":"MODULE_FUNC","rule":"Unicode::Normalize","sum":111830},{"parent":"MODULE_FUNC","rule":"Unicode::NormalizeNFC","sum":517},{"parent":"MODULE_FUNC","rule":"Unicode::NormalizeNFD","sum":36},{"parent":"MODULE_FUNC","rule":"Unicode::NormalizeNFKC","sum":6970},{"parent":"MODULE_FUNC","rule":"Unicode::NormalizeNFKD","sum":1785},{"parent":"MODULE_FUNC","rule":"Unicode::RFind","sum":73416},{"parent":"MODULE_FUNC","rule":"Unicode::RemoveAll","sum":138640},{"parent":"MODULE_FUNC","rule":"Unicode::RemoveFirst","sum":7632},{"parent":"MODULE_FUNC","rule":"Unicode::RemoveLast","sum":7675},{"parent":"MODULE_FUNC","rule":"Unicode::ReplaceAll","sum":275447},{"parent":"MODULE_FUNC","rule":"Unicode::ReplaceFirst","sum":1715},{"parent":"MODULE_FUNC","rule":"Unicode::ReplaceLast","sum":318},{"parent":"MODULE_FUNC","rule":"Unicode::Reverse","sum":53941},{"parent":"MODULE_FUNC","rule":"Unicode::SUBSTRING","sum":2},{"parent":"MODULE_FUNC","rule":"Unicode::SplitToList","sum":183435},{"parent":"MODULE_FUNC","rule":"Unicode::Strip","sum":65408},{"parent":"MODULE_FUNC","rule":"Unicode::Substring","sum":604211},{"parent":"MODULE_FUNC","rule":"Unicode::ToCodePointList","sum":122752},{"parent":"MODULE_FUNC","rule":"Unicode::ToLower","sum":1193919},{"parent":"MODULE_FUNC","rule":"Unicode::ToTitle","sum":35194},{"parent":"MODULE_FUNC","rule":"Unicode::ToUint64","sum":447},{"parent":"MODULE_FUNC","rule":"Unicode::ToUpper","sum":111889},{"parent":"MODULE_FUNC","rule":"Unicode::Translit","sum":103239},{"parent":"MODULE_FUNC","rule":"Unicode::TryToUint64","sum":1938},{"parent":"MODULE_FUNC","rule":"Url::AsciiToLower","sum":1},{"parent":"MODULE_FUNC","rule":"Url::BuildQueryString","sum":26041},{"parent":"MODULE_FUNC","rule":"Url::CanBePunycodeHostName","sum":6519},{"parent":"MODULE_FUNC","rule":"Url::CutQueryStringAndFragment","sum":232483},{"parent":"MODULE_FUNC","rule":"Url::CutScheme","sum":1143458},{"parent":"MODULE_FUNC","rule":"Url::CutWWW","sum":867649},{"parent":"MODULE_FUNC","rule":"Url::CutWWW2","sum":740870},{"parent":"MODULE_FUNC","rule":"Url::Decode","sum":1694148},{"parent":"MODULE_FUNC","rule":"Url::Encode","sum":372537},{"parent":"MODULE_FUNC","rule":"Url::ForceHostNameToPunycode","sum":201392},{"parent":"MODULE_FUNC","rule":"Url::ForcePunycodeToHostName","sum":132566},{"parent":"MODULE_FUNC","rule":"Url::GEtPath","sum":5},{"parent":"MODULE_FUNC","rule":"Url::GetCGIParam","sum":1816638},{"parent":"MODULE_FUNC","rule":"Url::GetCgiParam","sum":7},{"parent":"MODULE_FUNC","rule":"Url::GetDomain","sum":1128500},{"parent":"MODULE_FUNC","rule":"Url::GetDomainLevel","sum":70869},{"parent":"MODULE_FUNC","rule":"Url::GetFragment","sum":491},{"parent":"MODULE_FUNC","rule":"Url::GetHost","sum":4064328},{"parent":"MODULE_FUNC","rule":"Url::GetHostPort","sum":197440},{"parent":"MODULE_FUNC","rule":"Url::GetOwner","sum":1402345},{"parent":"MODULE_FUNC","rule":"Url::GetPath","sum":1696043},{"parent":"MODULE_FUNC","rule":"Url::GetPort","sum":822090},{"parent":"MODULE_FUNC","rule":"Url::GetScheme","sum":2069232},{"parent":"MODULE_FUNC","rule":"Url::GetSchemeHost","sum":146095},{"parent":"MODULE_FUNC","rule":"Url::GetSchemeHostPort","sum":701539},{"parent":"MODULE_FUNC","rule":"Url::GetSignificantDomain","sum":459812},{"parent":"MODULE_FUNC","rule":"Url::GetTLD","sum":35530},{"parent":"MODULE_FUNC","rule":"Url::GetTail","sum":579230},{"parent":"MODULE_FUNC","rule":"Url::Getowner","sum":1},{"parent":"MODULE_FUNC","rule":"Url::HostNameToPunycode","sum":581560},{"parent":"MODULE_FUNC","rule":"Url::IsAllowedByRobotsTxt","sum":7},{"parent":"MODULE_FUNC","rule":"Url::IsKnownTLD","sum":21025},{"parent":"MODULE_FUNC","rule":"Url::IsWellKnownTLD","sum":4891},{"parent":"MODULE_FUNC","rule":"Url::Normalize","sum":1058335},{"parent":"MODULE_FUNC","rule":"Url::NormalizeWithDefaultHttpScheme","sum":627031},{"parent":"MODULE_FUNC","rule":"Url::Parse","sum":300344},{"parent":"MODULE_FUNC","rule":"Url::PunycodeToHostName","sum":203755},{"parent":"MODULE_FUNC","rule":"Url::QueryStringToDict","sum":155530},{"parent":"MODULE_FUNC","rule":"Url::QueryStringToList","sum":38784},{"parent":"MODULE_FUNC","rule":"Url::ReplaceAll","sum":8},{"parent":"MODULE_FUNC","rule":"YSON::Co","sum":1},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToBool","sum":12},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToDict","sum":13},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToDouble","sum":4},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToDoubleList","sum":10},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToInt64","sum":5},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToList","sum":37},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToString","sum":177},{"parent":"MODULE_FUNC","rule":"YSON::ConvertToStringList","sum":174},{"parent":"MODULE_FUNC","rule":"YSON::From","sum":13},{"parent":"MODULE_FUNC","rule":"YSON::IsDict","sum":3},{"parent":"MODULE_FUNC","rule":"YSON::Lookup","sum":1},{"parent":"MODULE_FUNC","rule":"YSON::LookupDict","sum":1},{"parent":"MODULE_FUNC","rule":"YSON::LookupDouble","sum":6},{"parent":"MODULE_FUNC","rule":"YSON::LookupInt64","sum":1},{"parent":"MODULE_FUNC","rule":"YSON::LookupList","sum":4},{"parent":"MODULE_FUNC","rule":"YSON::LookupString","sum":7},{"parent":"MODULE_FUNC","rule":"YSON::Parse","sum":5},{"parent":"MODULE_FUNC","rule":"YSON::ToString","sum":1},{"parent":"MODULE_FUNC","rule":"YSON::convertToString","sum":7},{"parent":"MODULE_FUNC","rule":"YSON::from","sum":1},{"parent":"MODULE_FUNC","rule":"YSon::ConvertToDouble","sum":12},{"parent":"MODULE_FUNC","rule":"YSon::ConvertToList","sum":3},{"parent":"MODULE_FUNC","rule":"YSon::ConvertToString","sum":2},{"parent":"MODULE_FUNC","rule":"YSon::LookupString","sum":4},{"parent":"MODULE_FUNC","rule":"YSon::Parse","sum":5},{"parent":"MODULE_FUNC","rule":"Yson::AsList","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::Attributes","sum":1871},{"parent":"MODULE_FUNC","rule":"Yson::COntains","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::COnvertToDouble","sum":7},{"parent":"MODULE_FUNC","rule":"Yson::COnvertToString","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::CastToStringList","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::Contains","sum":2963512},{"parent":"MODULE_FUNC","rule":"Yson::Conver","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::ConverTToInt64","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConverToDouble","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::ConverToInt64","sum":10},{"parent":"MODULE_FUNC","rule":"Yson::ConverToList","sum":9},{"parent":"MODULE_FUNC","rule":"Yson::ConverToString","sum":12},{"parent":"MODULE_FUNC","rule":"Yson::ConvertFromString","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertTOInt64","sum":10},{"parent":"MODULE_FUNC","rule":"Yson::ConvertTOList","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertTo","sum":8915300},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToAttributes","sum":16},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToBool","sum":8770158},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToBoolDict","sum":105066},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToBoolList","sum":7459},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToBoolgDict","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToBytes","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDate","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDateTime","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDict","sum":8518949},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDictList","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDictOfDouble","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDictString","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDouble","sum":9561196},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDoubleDict","sum":281239},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToDoubleList","sum":1207062},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToFloat","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToFloat64","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToINT64List","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToIn64","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToInt","sum":37},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToInt32","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToInt32List","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToInt64","sum":20470188},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToInt64Dict","sum":186638},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToInt64List","sum":2409532},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToIntList","sum":5},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToInteget","sum":180},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToJson","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToList","sum":19055025},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToListDouble","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToListString","sum":16},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToListg","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToSTring","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToSTringList","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToSetring","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToString","sum":97084981},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToStringDict","sum":1453032},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToStringInt64","sum":4},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToStringList","sum":24420655},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToStrint","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToStruct","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToText","sum":13},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUINT64List","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUInt64","sum":1066},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUInt64List","sum":4},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUint32","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUint64","sum":8522752},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUint64Dict","sum":36344},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUint64List","sum":2194314},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToUnit64List","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToevent_value","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertToint64","sum":13},{"parent":"MODULE_FUNC","rule":"Yson::ConvertTolIST","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertTolist","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::ConvertTostring","sum":4},{"parent":"MODULE_FUNC","rule":"Yson::ConverttoBool","sum":6},{"parent":"MODULE_FUNC","rule":"Yson::ConverttoInt64","sum":4},{"parent":"MODULE_FUNC","rule":"Yson::ConverttoList","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::ConverttoString","sum":13},{"parent":"MODULE_FUNC","rule":"Yson::Converttostring","sum":28},{"parent":"MODULE_FUNC","rule":"Yson::ConvvertToString","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::Dict","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::Equals","sum":799601},{"parent":"MODULE_FUNC","rule":"Yson::Extract","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FROM","sum":8},{"parent":"MODULE_FUNC","rule":"Yson::Find","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::From","sum":25307118},{"parent":"MODULE_FUNC","rule":"Yson::From64List","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromAGG_LIST","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromASDFDSKLDJF","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromAboba","sum":4},{"parent":"MODULE_FUNC","rule":"Yson::FromBinary","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromBytes","sum":17},{"parent":"MODULE_FUNC","rule":"Yson::FromDict","sum":3075},{"parent":"MODULE_FUNC","rule":"Yson::FromDouble","sum":2768},{"parent":"MODULE_FUNC","rule":"Yson::FromDouble64Dict","sum":3663},{"parent":"MODULE_FUNC","rule":"Yson::FromDoubleDict","sum":42557},{"parent":"MODULE_FUNC","rule":"Yson::FromDoubleList","sum":981},{"parent":"MODULE_FUNC","rule":"Yson::FromInt32","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromInt64","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::FromInt64Dict","sum":2134},{"parent":"MODULE_FUNC","rule":"Yson::FromInt64List","sum":7437},{"parent":"MODULE_FUNC","rule":"Yson::FromJson","sum":2196},{"parent":"MODULE_FUNC","rule":"Yson::FromKek","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::FromList","sum":4896},{"parent":"MODULE_FUNC","rule":"Yson::FromListTake","sum":9},{"parent":"MODULE_FUNC","rule":"Yson::FromMap","sum":356},{"parent":"MODULE_FUNC","rule":"Yson::FromMinutes","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromSHEEEEEEEEEEEEE","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::FromSHIIIIIIIIIII","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromSeconds","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::FromSring","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::FromSting","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromString","sum":56310},{"parent":"MODULE_FUNC","rule":"Yson::FromStringDict","sum":69847},{"parent":"MODULE_FUNC","rule":"Yson::FromStringList","sum":58827},{"parent":"MODULE_FUNC","rule":"Yson::FromStruct","sum":658126},{"parent":"MODULE_FUNC","rule":"Yson::FromUi64List","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::FromUin64List","sum":378},{"parent":"MODULE_FUNC","rule":"Yson::FromUint32Dict","sum":10236},{"parent":"MODULE_FUNC","rule":"Yson::FromUint64","sum":9},{"parent":"MODULE_FUNC","rule":"Yson::FromUint64Dict","sum":15964},{"parent":"MODULE_FUNC","rule":"Yson::FromUint64List","sum":25824},{"parent":"MODULE_FUNC","rule":"Yson::FromY2020MachoDachaTbIhaHouse","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::Fromt","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::Get","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::GetBool","sum":43},{"parent":"MODULE_FUNC","rule":"Yson::GetHash","sum":867376},{"parent":"MODULE_FUNC","rule":"Yson::GetLength","sum":2821320},{"parent":"MODULE_FUNC","rule":"Yson::ISDict","sum":6},{"parent":"MODULE_FUNC","rule":"Yson::ISList","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::IsBool","sum":33609},{"parent":"MODULE_FUNC","rule":"Yson::IsDict","sum":254643},{"parent":"MODULE_FUNC","rule":"Yson::IsDouble","sum":101289},{"parent":"MODULE_FUNC","rule":"Yson::IsEntity","sum":2672410},{"parent":"MODULE_FUNC","rule":"Yson::IsInt64","sum":288474},{"parent":"MODULE_FUNC","rule":"Yson::IsList","sum":287576},{"parent":"MODULE_FUNC","rule":"Yson::IsString","sum":1032724},{"parent":"MODULE_FUNC","rule":"Yson::IsUint64","sum":153100},{"parent":"MODULE_FUNC","rule":"Yson::ListMap","sum":12},{"parent":"MODULE_FUNC","rule":"Yson::Lo","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::Loo","sum":10},{"parent":"MODULE_FUNC","rule":"Yson::LookUp","sum":16},{"parent":"MODULE_FUNC","rule":"Yson::LookUpDict","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::LookUpInt64","sum":11},{"parent":"MODULE_FUNC","rule":"Yson::LookUpString","sum":8},{"parent":"MODULE_FUNC","rule":"Yson::Lookup","sum":6599827},{"parent":"MODULE_FUNC","rule":"Yson::LookupBool","sum":2154016},{"parent":"MODULE_FUNC","rule":"Yson::LookupDict","sum":403310},{"parent":"MODULE_FUNC","rule":"Yson::LookupDouble","sum":3064290},{"parent":"MODULE_FUNC","rule":"Yson::LookupInt","sum":16},{"parent":"MODULE_FUNC","rule":"Yson::LookupInt32","sum":91},{"parent":"MODULE_FUNC","rule":"Yson::LookupInt64","sum":5509623},{"parent":"MODULE_FUNC","rule":"Yson::LookupInteger","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::LookupList","sum":1625649},{"parent":"MODULE_FUNC","rule":"Yson::LookupSTRING","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::LookupString","sum":41534098},{"parent":"MODULE_FUNC","rule":"Yson::LookupStringList","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::LookupStruct","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::LookupTimestamp","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::LookupUInt64","sum":7},{"parent":"MODULE_FUNC","rule":"Yson::LookupUint64","sum":3806322},{"parent":"MODULE_FUNC","rule":"Yson::LookupsTRING","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::LoopUpString","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::Options","sum":9261343},{"parent":"MODULE_FUNC","rule":"Yson::Parse","sum":8676471},{"parent":"MODULE_FUNC","rule":"Yson::ParseJSON","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::ParseJson","sum":12624816},{"parent":"MODULE_FUNC","rule":"Yson::ParseJsonDecodeUtf8","sum":133168},{"parent":"MODULE_FUNC","rule":"Yson::Parsejson","sum":9},{"parent":"MODULE_FUNC","rule":"Yson::Path","sum":9},{"parent":"MODULE_FUNC","rule":"Yson::Serialize","sum":3883724},{"parent":"MODULE_FUNC","rule":"Yson::SerializeJSON","sum":5},{"parent":"MODULE_FUNC","rule":"Yson::SerializeJson","sum":9897316},{"parent":"MODULE_FUNC","rule":"Yson::SerializeJsonEncodeUtf8","sum":202661},{"parent":"MODULE_FUNC","rule":"Yson::SerializePretty","sum":1189975},{"parent":"MODULE_FUNC","rule":"Yson::SerializeText","sum":615049},{"parent":"MODULE_FUNC","rule":"Yson::TryGet","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::WithAttributes","sum":660},{"parent":"MODULE_FUNC","rule":"Yson::YPath","sum":12652442},{"parent":"MODULE_FUNC","rule":"Yson::YPathBool","sum":1182739},{"parent":"MODULE_FUNC","rule":"Yson::YPathBoolean","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::YPathDict","sum":25919},{"parent":"MODULE_FUNC","rule":"Yson::YPathDouble","sum":1360827},{"parent":"MODULE_FUNC","rule":"Yson::YPathInt16","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::YPathInt64","sum":2746595},{"parent":"MODULE_FUNC","rule":"Yson::YPathList","sum":1429308},{"parent":"MODULE_FUNC","rule":"Yson::YPathListString","sum":7},{"parent":"MODULE_FUNC","rule":"Yson::YPathString","sum":13653535},{"parent":"MODULE_FUNC","rule":"Yson::YPathUInt64","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::YPathUint64","sum":709028},{"parent":"MODULE_FUNC","rule":"Yson::YaPathString","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::Ypath","sum":53},{"parent":"MODULE_FUNC","rule":"Yson::YpathString","sum":15},{"parent":"MODULE_FUNC","rule":"Yson::Yson2","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::convertToDict","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::convertToInt64","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::convertToString","sum":7},{"parent":"MODULE_FUNC","rule":"Yson::convertToUint64","sum":2},{"parent":"MODULE_FUNC","rule":"Yson::convertToUint64List","sum":9},{"parent":"MODULE_FUNC","rule":"Yson::converttostring","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::from","sum":52},{"parent":"MODULE_FUNC","rule":"Yson::fromJson","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::lookupString","sum":1},{"parent":"MODULE_FUNC","rule":"Yson::parseJson","sum":3},{"parent":"MODULE_FUNC","rule":"Yson::ypathstring","sum":11},{"parent":"MODULE_FUNC","rule":"dateTime::Format","sum":3},{"parent":"MODULE_FUNC","rule":"dateTime::GetMonth","sum":6},{"parent":"MODULE_FUNC","rule":"dateTime::IntervalFromDays","sum":375},{"parent":"MODULE_FUNC","rule":"dateTime::IntervalFromSeconds","sum":1},{"parent":"MODULE_FUNC","rule":"dateTime::MakeDate","sum":89},{"parent":"MODULE_FUNC","rule":"dateTime::MakeDatetime","sum":7},{"parent":"MODULE_FUNC","rule":"dateTime::StartOfMonth","sum":2},{"parent":"MODULE_FUNC","rule":"datetime::Format","sum":5},{"parent":"MODULE_FUNC","rule":"datetime::FromMilliseconds","sum":3},{"parent":"MODULE_FUNC","rule":"datetime::FromSeconds","sum":3696},{"parent":"MODULE_FUNC","rule":"datetime::GetDayOfWeek","sum":4},{"parent":"MODULE_FUNC","rule":"datetime::GetDayOfWeekName","sum":3},{"parent":"MODULE_FUNC","rule":"datetime::GetHour","sum":8},{"parent":"MODULE_FUNC","rule":"datetime::GetMonth","sum":14},{"parent":"MODULE_FUNC","rule":"datetime::GetWeekOfYear","sum":106},{"parent":"MODULE_FUNC","rule":"datetime::GetYear","sum":115},{"parent":"MODULE_FUNC","rule":"datetime::IntervalFromDays","sum":1335},{"parent":"MODULE_FUNC","rule":"datetime::IntervalFromHours","sum":37},{"parent":"MODULE_FUNC","rule":"datetime::IntervalFromMinutes","sum":6},{"parent":"MODULE_FUNC","rule":"datetime::MakeDate","sum":5364},{"parent":"MODULE_FUNC","rule":"datetime::MakeDatetime","sum":664},{"parent":"MODULE_FUNC","rule":"datetime::MakeTimestamp","sum":1},{"parent":"MODULE_FUNC","rule":"datetime::Parse","sum":397},{"parent":"MODULE_FUNC","rule":"datetime::ParseIso8601","sum":3},{"parent":"MODULE_FUNC","rule":"datetime::ShiftMonths","sum":314},{"parent":"MODULE_FUNC","rule":"datetime::StartOf","sum":1},{"parent":"MODULE_FUNC","rule":"datetime::StartOfDay","sum":2},{"parent":"MODULE_FUNC","rule":"datetime::StartOfMonth","sum":529},{"parent":"MODULE_FUNC","rule":"datetime::StartOfWeek","sum":533},{"parent":"MODULE_FUNC","rule":"datetime::ToDays","sum":374},{"parent":"MODULE_FUNC","rule":"datetime::ToSeconds","sum":740},{"parent":"MODULE_FUNC","rule":"datetime::fromseconds","sum":4},{"parent":"MODULE_FUNC","rule":"digest::Md5HalfMix","sum":14},{"parent":"MODULE_FUNC","rule":"digest::city_hash","sum":1},{"parent":"MODULE_FUNC","rule":"json::ConvertToString","sum":7},{"parent":"MODULE_FUNC","rule":"json::From","sum":1},{"parent":"MODULE_FUNC","rule":"math::Floor","sum":1},{"parent":"MODULE_FUNC","rule":"math::Round","sum":4},{"parent":"MODULE_FUNC","rule":"math::floor","sum":2},{"parent":"MODULE_FUNC","rule":"math::log","sum":2},{"parent":"MODULE_FUNC","rule":"math::pow","sum":6},{"parent":"MODULE_FUNC","rule":"math::round","sum":163},{"parent":"MODULE_FUNC","rule":"pg::GENERATE_SERIES","sum":8},{"parent":"MODULE_FUNC","rule":"pg::SPLIT_PART","sum":2},{"parent":"MODULE_FUNC","rule":"pg::age","sum":761},{"parent":"MODULE_FUNC","rule":"pg::array_agg","sum":2},{"parent":"MODULE_FUNC","rule":"pg::date_part","sum":740},{"parent":"MODULE_FUNC","rule":"pg::extract","sum":285},{"parent":"MODULE_FUNC","rule":"pg::generate_series","sum":2},{"parent":"MODULE_FUNC","rule":"pg::st_asgeojson","sum":2},{"parent":"MODULE_FUNC","rule":"pg::st_astext","sum":4},{"parent":"MODULE_FUNC","rule":"pg::st_geomfromewkb","sum":14},{"parent":"MODULE_FUNC","rule":"pg::st_transform","sum":9},{"parent":"MODULE_FUNC","rule":"pg::string_agg","sum":15},{"parent":"MODULE_FUNC","rule":"pire::Capture","sum":7},{"parent":"MODULE_FUNC","rule":"pire::Match","sum":29},{"parent":"MODULE_FUNC","rule":"re2::Capture","sum":2789},{"parent":"MODULE_FUNC","rule":"re2::Grep","sum":1},{"parent":"MODULE_FUNC","rule":"re2::Match","sum":24},{"parent":"MODULE_FUNC","rule":"re2::Replace","sum":430},{"parent":"MODULE_FUNC","rule":"re2::capture","sum":8},{"parent":"MODULE_FUNC","rule":"string::AsciiToLower","sum":6},{"parent":"MODULE_FUNC","rule":"string::HexDecode","sum":2},{"parent":"MODULE_FUNC","rule":"string::HexEncode","sum":2},{"parent":"MODULE_FUNC","rule":"string::HexText","sum":1},{"parent":"MODULE_FUNC","rule":"string::JoinFromList","sum":8},{"parent":"MODULE_FUNC","rule":"string::ReplaceFirst","sum":14},{"parent":"MODULE_FUNC","rule":"string::Reverse","sum":4},{"parent":"MODULE_FUNC","rule":"string::SplitToList","sum":14},{"parent":"MODULE_FUNC","rule":"string::StartsWith","sum":1},{"parent":"MODULE_FUNC","rule":"string::contains","sum":4},{"parent":"MODULE_FUNC","rule":"string::joinfromlist","sum":17},{"parent":"MODULE_FUNC","rule":"string::removeall","sum":4},{"parent":"MODULE_FUNC","rule":"string::replaceall","sum":11},{"parent":"MODULE_FUNC","rule":"string::splittolist","sum":13},{"parent":"MODULE_FUNC","rule":"string::strip","sum":2},{"parent":"MODULE_FUNC","rule":"url::Decode","sum":1},{"parent":"MODULE_FUNC","rule":"url::Encode","sum":2},{"parent":"MODULE_FUNC","rule":"url::decode","sum":2},{"parent":"MODULE_FUNC","rule":"url::gethost","sum":1},{"parent":"MODULE_FUNC","rule":"ySoN::CoNveRtTo","sum":1},{"parent":"MODULE_FUNC","rule":"yson::ConvertToDict","sum":1},{"parent":"MODULE_FUNC","rule":"yson::ConvertToDouble","sum":1},{"parent":"MODULE_FUNC","rule":"yson::ConvertToInt64","sum":1},{"parent":"MODULE_FUNC","rule":"yson::ConvertToString","sum":7},{"parent":"MODULE_FUNC","rule":"yson::ConvertToStringList","sum":2},{"parent":"MODULE_FUNC","rule":"yson::From","sum":1},{"parent":"MODULE_FUNC","rule":"yson::LookupString","sum":1},{"parent":"MODULE_FUNC","rule":"yson::PARSE","sum":2},{"parent":"MODULE_FUNC","rule":"yson::SerializeJson","sum":1},{"parent":"MODULE_FUNC","rule":"yson::convertto","sum":2},{"parent":"MODULE_FUNC","rule":"yson::converttodoubledict","sum":8},{"parent":"MODULE_FUNC","rule":"yson::converttolist","sum":1},{"parent":"MODULE_FUNC","rule":"yson::converttostring","sum":7},{"parent":"MODULE_FUNC","rule":"yson::converttostringdict","sum":8},{"parent":"MODULE_FUNC","rule":"yson::from","sum":6},{"parent":"MODULE_FUNC","rule":"yson::options","sum":8},{"parent":"MODULE_FUNC","rule":"yson::parsejson","sum":16},{"parent":"PRAGMA","rule":"AllowDotInAlias","sum":259035},{"parent":"PRAGMA","rule":"AllowUnnamedColumns","sum":4},{"parent":"PRAGMA","rule":"AnsiCurrentRow","sum":985},{"parent":"PRAGMA","rule":"AnsiImplicitCrossJoin","sum":13350},{"parent":"PRAGMA","rule":"AnsiInFOREmptyORNullableItemsCollections","sum":53},{"parent":"PRAGMA","rule":"AnsiInForEmptyOrNULLableItemsCollectiONs","sum":176},{"parent":"PRAGMA","rule":"AnsiInForEmptyOrNULLableItemsCollections","sum":4097},{"parent":"PRAGMA","rule":"AnsiInForEmptyOrNullableItemsCollections","sum":39739891},{"parent":"PRAGMA","rule":"AnsiInForEmptyOrnullableItemsCollections","sum":248},{"parent":"PRAGMA","rule":"AnsiInForEmptyorNullableItemsCollections","sum":2125},{"parent":"PRAGMA","rule":"AnsiInForEmptyornullableItemsCollections","sum":1277},{"parent":"PRAGMA","rule":"AnsiInforEmptyOrNullableItemsCollections","sum":248},{"parent":"PRAGMA","rule":"AnsiOptionalAS","sum":4},{"parent":"PRAGMA","rule":"AnsiOptionalAs","sum":2180509},{"parent":"PRAGMA","rule":"AnsiOptionalas","sum":342},{"parent":"PRAGMA","rule":"AnsiOrderByLimitInUnionAll","sum":210567},{"parent":"PRAGMA","rule":"AnsiRankForNullableKeys","sum":224226},{"parent":"PRAGMA","rule":"AnsiinForEmptyOrNullableItemsCollections","sum":8649},{"parent":"PRAGMA","rule":"AnsiinForEmptyOrNullableitemsCollections","sum":16},{"parent":"PRAGMA","rule":"AutoCommit","sum":39271},{"parent":"PRAGMA","rule":"BlockEngine","sum":358233},{"parent":"PRAGMA","rule":"BogousStarInGroupByOverJoin","sum":2},{"parent":"PRAGMA","rule":"CLassicDivision","sum":9},{"parent":"PRAGMA","rule":"CheckedOps","sum":665},{"parent":"PRAGMA","rule":"ClASsicDivision","sum":670},{"parent":"PRAGMA","rule":"ClassicDIvision","sum":44},{"parent":"PRAGMA","rule":"ClassicDivisiON","sum":149},{"parent":"PRAGMA","rule":"ClassicDivision","sum":2573720},{"parent":"PRAGMA","rule":"Classicdivision","sum":6},{"parent":"PRAGMA","rule":"CoalesceJoinKeysOnQualifiedAll","sum":36},{"parent":"PRAGMA","rule":"CompactGroupBy","sum":19},{"parent":"PRAGMA","rule":"CompactNamedExprs","sum":2499},{"parent":"PRAGMA","rule":"CostBasedOptimizer","sum":14619},{"parent":"PRAGMA","rule":"DQ.ANALYZEQUERY","sum":1634},{"parent":"PRAGMA","rule":"DQEngine","sum":3},{"parent":"PRAGMA","rule":"DirectRead","sum":48},{"parent":"PRAGMA","rule":"DisableAnsiInForEmptyOrNullableItemsCollections","sum":234070},{"parent":"PRAGMA","rule":"DisableAnsiLike","sum":1},{"parent":"PRAGMA","rule":"DisableAnsiRankForNullableKeys","sum":38042},{"parent":"PRAGMA","rule":"DisableCoalesceJoinKeysOnQualifiedAll","sum":197985},{"parent":"PRAGMA","rule":"DisableCompactNamedExprs","sum":12},{"parent":"PRAGMA","rule":"DisableOrderedColumns","sum":540},{"parent":"PRAGMA","rule":"DisablePullUpFlatMapOverJoin","sum":2},{"parent":"PRAGMA","rule":"DisableSeqMode","sum":1},{"parent":"PRAGMA","rule":"DisableSimpleColumns","sum":401855},{"parent":"PRAGMA","rule":"DisableStrictJoinKeyTypes","sum":421},{"parent":"PRAGMA","rule":"DisableUnicodeLiterals","sum":34},{"parent":"PRAGMA","rule":"DisableUnordered","sum":856},{"parent":"PRAGMA","rule":"DistinctOverWindow","sum":10},{"parent":"PRAGMA","rule":"Dq.HashJoinMode","sum":6},{"parent":"PRAGMA","rule":"Dq.MaxTasksPerStage","sum":5},{"parent":"PRAGMA","rule":"Dq.SplitStageOnDqReplicate","sum":4},{"parent":"PRAGMA","rule":"Dq.UseBlockReader","sum":2},{"parent":"PRAGMA","rule":"DqEngine","sum":10773711},{"parent":"PRAGMA","rule":"Dqengine","sum":2},{"parent":"PRAGMA","rule":"EmitAggApply","sum":1},{"parent":"PRAGMA","rule":"EmitUnionMerge","sum":7},{"parent":"PRAGMA","rule":"EnableSystemColumns","sum":3},{"parent":"PRAGMA","rule":"FILE","sum":291436},{"parent":"PRAGMA","rule":"FeatureR010","sum":224},{"parent":"PRAGMA","rule":"File","sum":7432399},{"parent":"PRAGMA","rule":"FileOption","sum":15918},{"parent":"PRAGMA","rule":"FilterPushdownOverJoinOptionalSide","sum":6},{"parent":"PRAGMA","rule":"FlexibleTypes","sum":957},{"parent":"PRAGMA","rule":"Folder","sum":3764},{"parent":"PRAGMA","rule":"Greetings","sum":1497},{"parent":"PRAGMA","rule":"GroupByCubeLimit","sum":39630},{"parent":"PRAGMA","rule":"GroupByLimit","sum":151774},{"parent":"PRAGMA","rule":"JsonQueryReturnsJsonDocument","sum":301455},{"parent":"PRAGMA","rule":"LIBRARY","sum":252338},{"parent":"PRAGMA","rule":"LIbrary","sum":52},{"parent":"PRAGMA","rule":"Library","sum":15124200},{"parent":"PRAGMA","rule":"OrderedColumns","sum":6024265},{"parent":"PRAGMA","rule":"Orderedcolumns","sum":12},{"parent":"PRAGMA","rule":"OverrideLibrary","sum":182},{"parent":"PRAGMA","rule":"Package","sum":5},{"parent":"PRAGMA","rule":"PositionalUnionAll","sum":120676},{"parent":"PRAGMA","rule":"PqReadBy","sum":42},{"parent":"PRAGMA","rule":"REGEXUSERE2","sum":13432},{"parent":"PRAGMA","rule":"RefSelect","sum":441721},{"parent":"PRAGMA","rule":"RegExUseRe2","sum":26},{"parent":"PRAGMA","rule":"RegexUseRe2","sum":312053},{"parent":"PRAGMA","rule":"ResultRowsLimit","sum":3},{"parent":"PRAGMA","rule":"SampleSelect","sum":11},{"parent":"PRAGMA","rule":"SeqMode","sum":4},{"parent":"PRAGMA","rule":"SimpleColumns","sum":6957960},{"parent":"PRAGMA","rule":"Simplecolumns","sum":3},{"parent":"PRAGMA","rule":"StrictJoinKeyTypes","sum":77615},{"parent":"PRAGMA","rule":"TablePathPrefix","sum":5615617},{"parent":"PRAGMA","rule":"UDF","sum":2180491},{"parent":"PRAGMA","rule":"Udf","sum":1948075},{"parent":"PRAGMA","rule":"UnicodeLiterals","sum":98},{"parent":"PRAGMA","rule":"UnorderedSubqueries","sum":2},{"parent":"PRAGMA","rule":"UseBlocks","sum":57},{"parent":"PRAGMA","rule":"UseTablePrefixForEach","sum":52},{"parent":"PRAGMA","rule":"WARNING","sum":35},{"parent":"PRAGMA","rule":"WarnUnnamedColumns","sum":26263},{"parent":"PRAGMA","rule":"Warning","sum":2957753},{"parent":"PRAGMA","rule":"WarningMsg","sum":12965},{"parent":"PRAGMA","rule":"YSON.AutoConvert","sum":828},{"parent":"PRAGMA","rule":"YSON.DisableStrict","sum":44960},{"parent":"PRAGMA","rule":"YSON.Strict","sum":732},{"parent":"PRAGMA","rule":"YT.Auth","sum":68},{"parent":"PRAGMA","rule":"YT.DefaultOperationWeight","sum":248353},{"parent":"PRAGMA","rule":"YT.InferSchema","sum":17747},{"parent":"PRAGMA","rule":"YT.POOL","sum":275},{"parent":"PRAGMA","rule":"YT.Pool","sum":85113},{"parent":"PRAGMA","rule":"YT.StaticPool","sum":6},{"parent":"PRAGMA","rule":"YT.TableContentDeliveryMode","sum":1653},{"parent":"PRAGMA","rule":"YT.UseNativeYTTypes","sum":2},{"parent":"PRAGMA","rule":"YT.UseNativeYTtypes","sum":3},{"parent":"PRAGMA","rule":"YT.pOOL","sum":4},{"parent":"PRAGMA","rule":"YT.pool","sum":18756},{"parent":"PRAGMA","rule":"YsON.Disablestrict","sum":141},{"parent":"PRAGMA","rule":"Yson.AutoConvert","sum":41963},{"parent":"PRAGMA","rule":"Yson.DIsableStrict","sum":15459},{"parent":"PRAGMA","rule":"Yson.DisableStrict","sum":481506},{"parent":"PRAGMA","rule":"Yson.Strict","sum":6808},{"parent":"PRAGMA","rule":"Yson.disablestrict","sum":29},{"parent":"PRAGMA","rule":"Yt.Auth","sum":33},{"parent":"PRAGMA","rule":"Yt.Description","sum":4},{"parent":"PRAGMA","rule":"Yt.ExternalTx","sum":24791},{"parent":"PRAGMA","rule":"Yt.HybridDqExecution","sum":9},{"parent":"PRAGMA","rule":"Yt.InferSchema","sum":2770},{"parent":"PRAGMA","rule":"Yt.MaxRowWeight","sum":980},{"parent":"PRAGMA","rule":"Yt.ParallelOperationsLimit","sum":12},{"parent":"PRAGMA","rule":"Yt.Pool","sum":253071},{"parent":"PRAGMA","rule":"Yt.PoolTrees","sum":1},{"parent":"PRAGMA","rule":"Yt.StaticPool","sum":10319},{"parent":"PRAGMA","rule":"Yt.TmpFolder","sum":4},{"parent":"PRAGMA","rule":"Yt.UseNativeYtTypes","sum":2870},{"parent":"PRAGMA","rule":"Yt.pool","sum":83523},{"parent":"PRAGMA","rule":"ansiInForEmptyOrNullableItemsCollections","sum":118},{"parent":"PRAGMA","rule":"ansiimplicitcrossjoin","sum":2},{"parent":"PRAGMA","rule":"ansiinforemptyornullableitemscollections","sum":12},{"parent":"PRAGMA","rule":"ansioptionalas","sum":98},{"parent":"PRAGMA","rule":"autocommit","sum":134527},{"parent":"PRAGMA","rule":"classicDivision","sum":18},{"parent":"PRAGMA","rule":"classic_division","sum":11},{"parent":"PRAGMA","rule":"classicdivision","sum":82},{"parent":"PRAGMA","rule":"config.flags","sum":1294895},{"parent":"PRAGMA","rule":"direct_read","sum":2},{"parent":"PRAGMA","rule":"directread","sum":2},{"parent":"PRAGMA","rule":"disableSimpleColumns","sum":8},{"parent":"PRAGMA","rule":"disablesimplecolumns","sum":6},{"parent":"PRAGMA","rule":"dq.AnalyticsHopping","sum":4},{"parent":"PRAGMA","rule":"dq.AnalyzeQuery","sum":3055509},{"parent":"PRAGMA","rule":"dq.ENABLEDQREPLICATE","sum":1},{"parent":"PRAGMA","rule":"dq.EnableComputeActor","sum":1},{"parent":"PRAGMA","rule":"dq.EnableDqReplicate","sum":925662},{"parent":"PRAGMA","rule":"dq.EnableDqreplicate","sum":3},{"parent":"PRAGMA","rule":"dq.EnableFullResultWrite","sum":28633},{"parent":"PRAGMA","rule":"dq.EnableInsert","sum":88265},{"parent":"PRAGMA","rule":"dq.FallbackPolicy","sum":3},{"parent":"PRAGMA","rule":"dq.HashJoinMode","sum":6356},{"parent":"PRAGMA","rule":"dq.HashShuffleMaxTasks","sum":7},{"parent":"PRAGMA","rule":"dq.HashShuffleTasksRatio","sum":7},{"parent":"PRAGMA","rule":"dq.MaxDataSizePerJob","sum":11},{"parent":"PRAGMA","rule":"dq.MaxDataSizePerQuery","sum":2},{"parent":"PRAGMA","rule":"dq.MaxRetries","sum":1132},{"parent":"PRAGMA","rule":"dq.MaxTasksPerOperation","sum":22497},{"parent":"PRAGMA","rule":"dq.MaxTasksPerStage","sum":60716},{"parent":"PRAGMA","rule":"dq.MemoryLimit","sum":8204},{"parent":"PRAGMA","rule":"dq.OptLLVM","sum":11},{"parent":"PRAGMA","rule":"dq.SplitStageOnDqReplicate","sum":11038},{"parent":"PRAGMA","rule":"dq.UseBlockReader","sum":4185},{"parent":"PRAGMA","rule":"dq.UseFastPickleTransport","sum":3},{"parent":"PRAGMA","rule":"dq.UseFinalizeByKey","sum":10},{"parent":"PRAGMA","rule":"dq.UseOOBTransport","sum":9},{"parent":"PRAGMA","rule":"dq.UseWideBlockChannels","sum":2},{"parent":"PRAGMA","rule":"dq.UseWideChannels","sum":1},{"parent":"PRAGMA","rule":"dq.WorkerFilter","sum":107},{"parent":"PRAGMA","rule":"dq.enableDqReplicate","sum":348},{"parent":"PRAGMA","rule":"dq.enabledqreplicate","sum":40},{"parent":"PRAGMA","rule":"dqEngine","sum":91502},{"parent":"PRAGMA","rule":"dqengine","sum":21283},{"parent":"PRAGMA","rule":"file","sum":1817381},{"parent":"PRAGMA","rule":"folder","sum":674},{"parent":"PRAGMA","rule":"greetings","sum":1},{"parent":"PRAGMA","rule":"library","sum":4875262},{"parent":"PRAGMA","rule":"orderedColumns","sum":7},{"parent":"PRAGMA","rule":"orderedcolumns","sum":15135},{"parent":"PRAGMA","rule":"override_library","sum":32},{"parent":"PRAGMA","rule":"package","sum":231528},{"parent":"PRAGMA","rule":"refselect","sum":31760},{"parent":"PRAGMA","rule":"rtmr.Account","sum":4},{"parent":"PRAGMA","rule":"rtmr.TaskName","sum":12},{"parent":"PRAGMA","rule":"rtmr.YfInstanceCount","sum":8},{"parent":"PRAGMA","rule":"rtmr.YfSlotCount","sum":8},{"parent":"PRAGMA","rule":"rtmr.yfPool","sum":1},{"parent":"PRAGMA","rule":"sampleselect","sum":177},{"parent":"PRAGMA","rule":"simpleColumns","sum":1454},{"parent":"PRAGMA","rule":"simplecolumns","sum":241976},{"parent":"PRAGMA","rule":"tablepathprefix","sum":2},{"parent":"PRAGMA","rule":"udf","sum":4351587},{"parent":"PRAGMA","rule":"warning","sum":66266},{"parent":"PRAGMA","rule":"yson.AutoConvert","sum":4745561},{"parent":"PRAGMA","rule":"yson.Auto_convert","sum":18},{"parent":"PRAGMA","rule":"yson.Autoconvert","sum":1152},{"parent":"PRAGMA","rule":"yson.DisableStrict","sum":20131677},{"parent":"PRAGMA","rule":"yson.Disablestrict","sum":46},{"parent":"PRAGMA","rule":"yson.Fast","sum":654},{"parent":"PRAGMA","rule":"yson.Strict","sum":3508636},{"parent":"PRAGMA","rule":"yson.autoConvert","sum":4},{"parent":"PRAGMA","rule":"yson.autoconvert","sum":3813},{"parent":"PRAGMA","rule":"yson.disableStrict","sum":2237},{"parent":"PRAGMA","rule":"yson.disable_strict","sum":3},{"parent":"PRAGMA","rule":"yson.disablestrict","sum":210592},{"parent":"PRAGMA","rule":"yson.strict","sum":710},{"parent":"PRAGMA","rule":"yt.AUth","sum":4},{"parent":"PRAGMA","rule":"yt.Annotations","sum":47106441},{"parent":"PRAGMA","rule":"yt.Auth","sum":1292526},{"parent":"PRAGMA","rule":"yt.AutoMerge","sum":4457647},{"parent":"PRAGMA","rule":"yt.Automerge","sum":2765},{"parent":"PRAGMA","rule":"yt.BatchListFolderConcurrency","sum":147},{"parent":"PRAGMA","rule":"yt.BinaryExpirationInterval","sum":6313281},{"parent":"PRAGMA","rule":"yt.BinaryTmpFolder","sum":6340972},{"parent":"PRAGMA","rule":"yt.BlockMapJoin","sum":1},{"parent":"PRAGMA","rule":"yt.BlockReaderSupportedDataTypes","sum":6},{"parent":"PRAGMA","rule":"yt.BlockReaderSupportedTypes","sum":1},{"parent":"PRAGMA","rule":"yt.ColumnGroupMode","sum":452760},{"parent":"PRAGMA","rule":"yt.CombineCoreLimit","sum":77254},{"parent":"PRAGMA","rule":"yt.CommonJoinCoreLimit","sum":1892},{"parent":"PRAGMA","rule":"yt.CoreDumpPath","sum":2},{"parent":"PRAGMA","rule":"yt.DQRPCReaderInflight","sum":140},{"parent":"PRAGMA","rule":"yt.DQRPCReaderTimeout","sum":7},{"parent":"PRAGMA","rule":"yt.DatASizePerJob","sum":2166},{"parent":"PRAGMA","rule":"yt.DatASizePerPartition","sum":744},{"parent":"PRAGMA","rule":"yt.DataSizePerJob","sum":5235784},{"parent":"PRAGMA","rule":"yt.DataSizePerMapJob","sum":317581},{"parent":"PRAGMA","rule":"yt.DataSizePerPartition","sum":520584},{"parent":"PRAGMA","rule":"yt.DataSizePerSortJob","sum":201823},{"parent":"PRAGMA","rule":"yt.DatasizePerJob","sum":16},{"parent":"PRAGMA","rule":"yt.DatasizePerSortJob","sum":16},{"parent":"PRAGMA","rule":"yt.DefaultCalcMemoryLimit","sum":258964},{"parent":"PRAGMA","rule":"yt.DefaultCluster","sum":71882463},{"parent":"PRAGMA","rule":"yt.DefaultLocalityTimeout","sum":4123},{"parent":"PRAGMA","rule":"yt.DefaultMapSelectivityFactor","sum":3},{"parent":"PRAGMA","rule":"yt.DefaultMaxJobFails","sum":1544458},{"parent":"PRAGMA","rule":"yt.DefaultMemORyLimit","sum":7},{"parent":"PRAGMA","rule":"yt.DefaultMemoryLimit","sum":2068340},{"parent":"PRAGMA","rule":"yt.DefaultMemoryReserveFactor","sum":25257},{"parent":"PRAGMA","rule":"yt.DefaultOperationWeight","sum":9832401},{"parent":"PRAGMA","rule":"yt.Description","sum":238813},{"parent":"PRAGMA","rule":"yt.DisableFuseOperations","sum":2},{"parent":"PRAGMA","rule":"yt.DisableJobSplitting","sum":4886},{"parent":"PRAGMA","rule":"yt.DisableOptimizers","sum":30964},{"parent":"PRAGMA","rule":"yt.EnableDynamicStoreReadInDQ","sum":1},{"parent":"PRAGMA","rule":"yt.ErasureCodecCpu","sum":149921},{"parent":"PRAGMA","rule":"yt.EvaluationTableSizeLimit","sum":817366},{"parent":"PRAGMA","rule":"yt.ExpirationDeadline","sum":3467779},{"parent":"PRAGMA","rule":"yt.ExpirationInterval","sum":8245641},{"parent":"PRAGMA","rule":"yt.ExtendedStatsMaxChunkCount","sum":4},{"parent":"PRAGMA","rule":"yt.ExternalTx","sum":80798903},{"parent":"PRAGMA","rule":"yt.ExtraTmpfsSize","sum":95},{"parent":"PRAGMA","rule":"yt.FileCacheTtl","sum":8505324},{"parent":"PRAGMA","rule":"yt.FolderInlineDataLimit","sum":40},{"parent":"PRAGMA","rule":"yt.FolderInlineItemsLimit","sum":2},{"parent":"PRAGMA","rule":"yt.ForceInferSchema","sum":794278},{"parent":"PRAGMA","rule":"yt.ForceJobSizeAdjuster","sum":10247},{"parent":"PRAGMA","rule":"yt.GeobaseDownloadUrl","sum":62837},{"parent":"PRAGMA","rule":"yt.HybridDqDataSizeLimitForOrdered","sum":318548},{"parent":"PRAGMA","rule":"yt.HybridDqDataSizeLimitForUnordered","sum":321622},{"parent":"PRAGMA","rule":"yt.HybridDqExecution","sum":3739576},{"parent":"PRAGMA","rule":"yt.HybridDqExecutionFallback","sum":108},{"parent":"PRAGMA","rule":"yt.INFERSCHEMA","sum":1},{"parent":"PRAGMA","rule":"yt.INferSchema","sum":6},{"parent":"PRAGMA","rule":"yt.IgnoreTypeV3","sum":4579},{"parent":"PRAGMA","rule":"yt.IgnoreWeakSchema","sum":230394},{"parent":"PRAGMA","rule":"yt.IgnoreYamrDsv","sum":22561},{"parent":"PRAGMA","rule":"yt.InferSchemA","sum":11},{"parent":"PRAGMA","rule":"yt.InferSchema","sum":32267438},{"parent":"PRAGMA","rule":"yt.InferSchemaTableCountThreshold","sum":1},{"parent":"PRAGMA","rule":"yt.Inferschema","sum":86524},{"parent":"PRAGMA","rule":"yt.IntermediateAccount","sum":133764},{"parent":"PRAGMA","rule":"yt.IntermediateDataMedium","sum":305807},{"parent":"PRAGMA","rule":"yt.IntermediateReplicationFactor","sum":2986},{"parent":"PRAGMA","rule":"yt.JavascriptCpu","sum":42},{"parent":"PRAGMA","rule":"yt.JobBlockInput","sum":27},{"parent":"PRAGMA","rule":"yt.JobBlockOutput","sum":12},{"parent":"PRAGMA","rule":"yt.JobEnv","sum":13907},{"parent":"PRAGMA","rule":"yt.JoinAllowColumnRenames","sum":452},{"parent":"PRAGMA","rule":"yt.JoinCollectColumnarStatistics","sum":20280},{"parent":"PRAGMA","rule":"yt.JoinColumnarStatisticsFetcherMode","sum":594},{"parent":"PRAGMA","rule":"yt.JoinEnableStarJoin","sum":42050},{"parent":"PRAGMA","rule":"yt.JoinMergeForce","sum":52982},{"parent":"PRAGMA","rule":"yt.JoinMergeReduceJobMaxSize","sum":2703},{"parent":"PRAGMA","rule":"yt.JoinMergeTablesLimit","sum":3945},{"parent":"PRAGMA","rule":"yt.JoinMergeUnsortedFactor","sum":1625},{"parent":"PRAGMA","rule":"yt.JoinMergeUseSmallAsPrimary","sum":6020},{"parent":"PRAGMA","rule":"yt.JoinUseColumnarStatistics","sum":958},{"parent":"PRAGMA","rule":"yt.JoinWaitAllInputs","sum":16},{"parent":"PRAGMA","rule":"yt.KeepTempTables","sum":944},{"parent":"PRAGMA","rule":"yt.LayerPaths","sum":159569},{"parent":"PRAGMA","rule":"yt.LookupJoinLimit","sum":230902},{"parent":"PRAGMA","rule":"yt.LookupJoinMaxRows","sum":179815},{"parent":"PRAGMA","rule":"yt.MAXRowWeight","sum":66},{"parent":"PRAGMA","rule":"yt.MAxJobCount","sum":64},{"parent":"PRAGMA","rule":"yt.MAxRowWeight","sum":1},{"parent":"PRAGMA","rule":"yt.MapJOINLimit","sum":733},{"parent":"PRAGMA","rule":"yt.MapJoinLimit","sum":700922},{"parent":"PRAGMA","rule":"yt.MapJoinShardCount","sum":325591},{"parent":"PRAGMA","rule":"yt.MapJoinShardMinRows","sum":4},{"parent":"PRAGMA","rule":"yt.MapJoinUseFlow","sum":1},{"parent":"PRAGMA","rule":"yt.MapLocalityTimeout","sum":4},{"parent":"PRAGMA","rule":"yt.MaxChunksForDqRead","sum":120},{"parent":"PRAGMA","rule":"yt.MaxExtraJobMemoryToFuseOperations","sum":19625},{"parent":"PRAGMA","rule":"yt.MaxInputTables","sum":29548},{"parent":"PRAGMA","rule":"yt.MaxInputTablesForSortedMerge","sum":5885},{"parent":"PRAGMA","rule":"yt.MaxJobCount","sum":12604723},{"parent":"PRAGMA","rule":"yt.MaxJobcount","sum":1379},{"parent":"PRAGMA","rule":"yt.MaxKeyRangeCount","sum":9},{"parent":"PRAGMA","rule":"yt.MaxKeyWeight","sum":210503},{"parent":"PRAGMA","rule":"yt.MaxOutputTables","sum":53},{"parent":"PRAGMA","rule":"yt.MaxReplicationFactorToFuseOperations","sum":15},{"parent":"PRAGMA","rule":"yt.MaxRowWeight","sum":6129619},{"parent":"PRAGMA","rule":"yt.MaxSpeculativeJobCountPerTask","sum":2223},{"parent":"PRAGMA","rule":"yt.MinLocalityInputDataWeight","sum":8},{"parent":"PRAGMA","rule":"yt.MinPublishedAvgChunkSize","sum":3203547},{"parent":"PRAGMA","rule":"yt.MinTempAvgChunkSize","sum":179189},{"parent":"PRAGMA","rule":"yt.NativeYtTypeCompatibility","sum":15},{"parent":"PRAGMA","rule":"yt.NetworkProject","sum":609959},{"parent":"PRAGMA","rule":"yt.NightlyCompress","sum":146059},{"parent":"PRAGMA","rule":"yt.OWners","sum":21},{"parent":"PRAGMA","rule":"yt.OperationReaders","sum":12929391},{"parent":"PRAGMA","rule":"yt.OperationSpec","sum":8595182},{"parent":"PRAGMA","rule":"yt.OptimizeFor","sum":5854994},{"parent":"PRAGMA","rule":"yt.Owners","sum":65834227},{"parent":"PRAGMA","rule":"yt.POOL","sum":68},{"parent":"PRAGMA","rule":"yt.POol","sum":12},{"parent":"PRAGMA","rule":"yt.ParallelOperationsLimit","sum":1389738},{"parent":"PRAGMA","rule":"yt.PartitionByConstantKeysViaMap","sum":13},{"parent":"PRAGMA","rule":"yt.PooL","sum":1},{"parent":"PRAGMA","rule":"yt.Pool","sum":54578353},{"parent":"PRAGMA","rule":"yt.PoolTrees","sum":6604811},{"parent":"PRAGMA","rule":"yt.PrimaryMedium","sum":391200},{"parent":"PRAGMA","rule":"yt.PruneKeyFilterLambda","sum":570},{"parent":"PRAGMA","rule":"yt.PublishedAutoMerge","sum":3424208},{"parent":"PRAGMA","rule":"yt.PublishedCompressionCodec","sum":7477762},{"parent":"PRAGMA","rule":"yt.PublishedErasureCodec","sum":5461359},{"parent":"PRAGMA","rule":"yt.PublishedMedia","sum":4323},{"parent":"PRAGMA","rule":"yt.PublishedPrimaryMedium","sum":787756},{"parent":"PRAGMA","rule":"yt.PublishedReplicationFactor","sum":24049},{"parent":"PRAGMA","rule":"yt.PythonCpu","sum":87204},{"parent":"PRAGMA","rule":"yt.QueryCacheIgnoreTableRevision","sum":64613},{"parent":"PRAGMA","rule":"yt.QueryCacheMode","sum":24322168},{"parent":"PRAGMA","rule":"yt.QueryCacheSalt","sum":5},{"parent":"PRAGMA","rule":"yt.QueryCacheTtl","sum":9068170},{"parent":"PRAGMA","rule":"yt.QueryCacheUseForCalc","sum":8},{"parent":"PRAGMA","rule":"yt.QuerycacheMode","sum":2},{"parent":"PRAGMA","rule":"yt.ReleaseTempData","sum":2733894},{"parent":"PRAGMA","rule":"yt.STaticPool","sum":3},{"parent":"PRAGMA","rule":"yt.SamplingIoBlockSize","sum":3846},{"parent":"PRAGMA","rule":"yt.SchedulingTag","sum":61},{"parent":"PRAGMA","rule":"yt.SchedulingTagFilter","sum":2941},{"parent":"PRAGMA","rule":"yt.ScriptCpu","sum":4980},{"parent":"PRAGMA","rule":"yt.StartedBy","sum":266284},{"parent":"PRAGMA","rule":"yt.StaticPOol","sum":1},{"parent":"PRAGMA","rule":"yt.StaticPool","sum":113682792},{"parent":"PRAGMA","rule":"yt.Static_pool","sum":1},{"parent":"PRAGMA","rule":"yt.SuspendIfAccountLimitExceeded","sum":42957},{"parent":"PRAGMA","rule":"yt.TableContentDeliveryMode","sum":591},{"parent":"PRAGMA","rule":"yt.TableContentLocalExecution","sum":18},{"parent":"PRAGMA","rule":"yt.TableContentMaxChunksForNativeDelivery","sum":1},{"parent":"PRAGMA","rule":"yt.TableContentMaxInputTables","sum":6690},{"parent":"PRAGMA","rule":"yt.TableContentMinAvgChunkSize","sum":2589},{"parent":"PRAGMA","rule":"yt.TableContentTmpFolder","sum":28},{"parent":"PRAGMA","rule":"yt.TableContentUseSkiff","sum":11},{"parent":"PRAGMA","rule":"yt.TablesTmpFolder","sum":3476119},{"parent":"PRAGMA","rule":"yt.TempTablesTtl","sum":5550556},{"parent":"PRAGMA","rule":"yt.TemporaryAutoMerge","sum":8920140},{"parent":"PRAGMA","rule":"yt.TemporaryCompressionCodec","sum":5905781},{"parent":"PRAGMA","rule":"yt.TemporaryErasureCodec","sum":4825183},{"parent":"PRAGMA","rule":"yt.TemporaryPrimaryMedium","sum":505233},{"parent":"PRAGMA","rule":"yt.TemporaryReplicationFactor","sum":84},{"parent":"PRAGMA","rule":"yt.TentativePoolTrees","sum":1843714},{"parent":"PRAGMA","rule":"yt.TentativeTreeEligibilityMaxJobDurationRatio","sum":17598},{"parent":"PRAGMA","rule":"yt.TentativeTreeEligibilityMinJobDuration","sum":2168},{"parent":"PRAGMA","rule":"yt.TentativeTreeEligibilitySampleJobCount","sum":16259},{"parent":"PRAGMA","rule":"yt.TmpFolder","sum":31478968},{"parent":"PRAGMA","rule":"yt.TopSortMaxLimit","sum":59},{"parent":"PRAGMA","rule":"yt.TopSortSizePerJob","sum":1},{"parent":"PRAGMA","rule":"yt.USENATIVEYTTYPES","sum":29},{"parent":"PRAGMA","rule":"yt.USeNativeYtTypes","sum":12},{"parent":"PRAGMA","rule":"yt.UseColumnarStatistics","sum":168549},{"parent":"PRAGMA","rule":"yt.UseDefaultTentativePoolTrees","sum":253045},{"parent":"PRAGMA","rule":"yt.UseFlow","sum":3},{"parent":"PRAGMA","rule":"yt.UseIntermediateStreams","sum":6},{"parent":"PRAGMA","rule":"yt.UseNAtiveYtTypes","sum":1},{"parent":"PRAGMA","rule":"yt.UseNativeDescSort","sum":2102},{"parent":"PRAGMA","rule":"yt.UseNativeYtTYpes","sum":1485},{"parent":"PRAGMA","rule":"yt.UseNativeYtTypes","sum":24543429},{"parent":"PRAGMA","rule":"yt.UseNativeYttypes","sum":780},{"parent":"PRAGMA","rule":"yt.UseNativeytTypes","sum":524},{"parent":"PRAGMA","rule":"yt.UseNewPredicateExtraction","sum":182732},{"parent":"PRAGMA","rule":"yt.UseRPCReaderInDQ","sum":79},{"parent":"PRAGMA","rule":"yt.UseRPCReaderInDq","sum":12120},{"parent":"PRAGMA","rule":"yt.UseSkiff","sum":3926},{"parent":"PRAGMA","rule":"yt.UseSystemColumns","sum":2131},{"parent":"PRAGMA","rule":"yt.UseTmpfs","sum":34355},{"parent":"PRAGMA","rule":"yt.UseTypeV2","sum":4302},{"parent":"PRAGMA","rule":"yt.UseYqlRowSpecCompactForm","sum":3798},{"parent":"PRAGMA","rule":"yt.UserSlots","sum":2526588},{"parent":"PRAGMA","rule":"yt.ViewIsolation","sum":983},{"parent":"PRAGMA","rule":"yt.WideFlowLimit","sum":158676},{"parent":"PRAGMA","rule":"yt.auth","sum":46536},{"parent":"PRAGMA","rule":"yt.datasizeperjob","sum":2022},{"parent":"PRAGMA","rule":"yt.defaultoperationweight","sum":47},{"parent":"PRAGMA","rule":"yt.forceinferschema","sum":48},{"parent":"PRAGMA","rule":"yt.inferSchema","sum":56183},{"parent":"PRAGMA","rule":"yt.infer_schema","sum":10},{"parent":"PRAGMA","rule":"yt.inferschema","sum":2911},{"parent":"PRAGMA","rule":"yt.mapjoinlimit","sum":98499},{"parent":"PRAGMA","rule":"yt.maxRowWeight","sum":1},{"parent":"PRAGMA","rule":"yt.max_row_weight","sum":19},{"parent":"PRAGMA","rule":"yt.maxjobcount","sum":5},{"parent":"PRAGMA","rule":"yt.maxrowweight","sum":41949},{"parent":"PRAGMA","rule":"yt.minPublishedAvgChunksize","sum":11},{"parent":"PRAGMA","rule":"yt.network_project","sum":14594},{"parent":"PRAGMA","rule":"yt.pool","sum":6824278},{"parent":"PRAGMA","rule":"yt.pool_trees","sum":1},{"parent":"PRAGMA","rule":"yt.pooltrees","sum":53},{"parent":"PRAGMA","rule":"yt.publishedcompressioncodec","sum":403},{"parent":"PRAGMA","rule":"yt.staticPool","sum":1276802},{"parent":"PRAGMA","rule":"yt.static_pool","sum":20},{"parent":"PRAGMA","rule":"yt.staticpool","sum":10554},{"parent":"PRAGMA","rule":"yt.tmpFolder","sum":76757},{"parent":"PRAGMA","rule":"yt.tmpfolder","sum":65},{"parent":"PRAGMA","rule":"yt.useNativeYtTYpes","sum":1},{"parent":"PRAGMA","rule":"yt.useNativeYtTypes","sum":919},{"parent":"PRAGMA","rule":"yt.usenativeyttypes","sum":172},{"parent":"READ_HINT","rule":"COLUMNS","sum":826110},{"parent":"READ_HINT","rule":"CoLUMNS","sum":2},{"parent":"READ_HINT","rule":"Columns","sum":24},{"parent":"READ_HINT","rule":"DIRECT_READ","sum":98},{"parent":"READ_HINT","rule":"FORCE_INFER_SCHEMA","sum":18276},{"parent":"READ_HINT","rule":"ForceInferSchema","sum":364},{"parent":"READ_HINT","rule":"IGNORETYPEV3","sum":2},{"parent":"READ_HINT","rule":"IGNORE_TYPE_V3","sum":4},{"parent":"READ_HINT","rule":"INFER_SCHEMA","sum":105090},{"parent":"READ_HINT","rule":"INLINE","sum":88183},{"parent":"READ_HINT","rule":"InferSchema","sum":2275},{"parent":"READ_HINT","rule":"Infer_Schema","sum":3},{"parent":"READ_HINT","rule":"SCHEMA","sum":16862952},{"parent":"READ_HINT","rule":"SChema","sum":2},{"parent":"READ_HINT","rule":"Schema","sum":38545},{"parent":"READ_HINT","rule":"TRUNCATE","sum":5},{"parent":"READ_HINT","rule":"UNORDERED","sum":6456},{"parent":"READ_HINT","rule":"USER_ATTRS","sum":1},{"parent":"READ_HINT","rule":"Unordered","sum":365},{"parent":"READ_HINT","rule":"XLOCK","sum":140088},{"parent":"READ_HINT","rule":"columns","sum":428022},{"parent":"READ_HINT","rule":"direct_read","sum":1},{"parent":"READ_HINT","rule":"downsampling.aggregation","sum":2273},{"parent":"READ_HINT","rule":"downsampling.disabled","sum":2198},{"parent":"READ_HINT","rule":"downsampling.fill","sum":1773},{"parent":"READ_HINT","rule":"downsampling.grid_interval","sum":2574},{"parent":"READ_HINT","rule":"force_infer_schema","sum":2},{"parent":"READ_HINT","rule":"from","sum":24174},{"parent":"READ_HINT","rule":"infer_schema","sum":198},{"parent":"READ_HINT","rule":"infer_scheme","sum":17},{"parent":"READ_HINT","rule":"inferschema","sum":1},{"parent":"READ_HINT","rule":"inline","sum":75427},{"parent":"READ_HINT","rule":"labels","sum":22025},{"parent":"READ_HINT","rule":"program","sum":24426},{"parent":"READ_HINT","rule":"schema","sum":786926},{"parent":"READ_HINT","rule":"to","sum":24174},{"parent":"READ_HINT","rule":"unordered","sum":14252},{"parent":"READ_HINT","rule":"xlock","sum":261771},{"parent":"TRule_action_or_subquery_args","rule":"TRule_action_or_subquery_args.Block2","sum":4986143},{"parent":"TRule_action_or_subquery_args","rule":"TRule_action_or_subquery_args.Rule_opt_bind_parameter1","sum":14027239},{"parent":"TRule_action_or_subquery_args.TBlock2","rule":"TRule_action_or_subquery_args.TBlock2.Rule_opt_bind_parameter2","sum":7565014},{"parent":"TRule_action_or_subquery_args.TBlock2","rule":"TRule_action_or_subquery_args.TBlock2.Token1","sum":7565014},{"parent":"TRule_add_subexpr","rule":"TRule_add_subexpr.Block2","sum":136327164},{"parent":"TRule_add_subexpr","rule":"TRule_add_subexpr.Rule_mul_subexpr1","sum":15639753502},{"parent":"TRule_add_subexpr.TBlock2","rule":"TRule_add_subexpr.TBlock2.Rule_mul_subexpr2","sum":168035288},{"parent":"TRule_add_subexpr.TBlock2","rule":"TRule_add_subexpr.TBlock2.Token1","sum":168035288},{"parent":"TRule_an_id","rule":"TRule_an_id.Alt_an_id1","sum":2011167410},{"parent":"TRule_an_id.TAlt1","rule":"TRule_an_id.TAlt1.Rule_id1","sum":2011167410},{"parent":"TRule_an_id_as_compat","rule":"TRule_an_id_as_compat.Alt_an_id_as_compat1","sum":3037134},{"parent":"TRule_an_id_as_compat.TAlt1","rule":"TRule_an_id_as_compat.TAlt1.Rule_id_as_compat1","sum":3037134},{"parent":"TRule_an_id_expr","rule":"TRule_an_id_expr.Alt_an_id_expr1","sum":96457781},{"parent":"TRule_an_id_expr.TAlt1","rule":"TRule_an_id_expr.TAlt1.Rule_id_expr1","sum":96457781},{"parent":"TRule_an_id_hint","rule":"TRule_an_id_hint.Alt_an_id_hint1","sum":155030406},{"parent":"TRule_an_id_hint.TAlt1","rule":"TRule_an_id_hint.TAlt1.Rule_id_hint1","sum":155030406},{"parent":"TRule_an_id_or_type","rule":"TRule_an_id_or_type.Alt_an_id_or_type1","sum":9657689504},{"parent":"TRule_an_id_or_type","rule":"TRule_an_id_or_type.Alt_an_id_or_type2","sum":7},{"parent":"TRule_an_id_or_type.TAlt1","rule":"TRule_an_id_or_type.TAlt1.Rule_id_or_type1","sum":9657689504},{"parent":"TRule_an_id_or_type.TAlt2","rule":"TRule_an_id_or_type.TAlt2.Token1","sum":7},{"parent":"TRule_an_id_pure","rule":"TRule_an_id_pure.Alt_an_id_pure1","sum":678937497},{"parent":"TRule_an_id_pure.TAlt1","rule":"TRule_an_id_pure.TAlt1.Rule_identifier1","sum":678937497},{"parent":"TRule_an_id_schema","rule":"TRule_an_id_schema.Alt_an_id_schema1","sum":1160},{"parent":"TRule_an_id_schema.TAlt1","rule":"TRule_an_id_schema.TAlt1.Rule_id_schema1","sum":1160},{"parent":"TRule_an_id_table","rule":"TRule_an_id_table.Alt_an_id_table1","sum":331261943},{"parent":"TRule_an_id_table","rule":"TRule_an_id_table.Alt_an_id_table2","sum":1},{"parent":"TRule_an_id_table.TAlt1","rule":"TRule_an_id_table.TAlt1.Rule_id_table1","sum":331261943},{"parent":"TRule_an_id_table.TAlt2","rule":"TRule_an_id_table.TAlt2.Token1","sum":1},{"parent":"TRule_an_id_window","rule":"TRule_an_id_window.Alt_an_id_window1","sum":46794903},{"parent":"TRule_an_id_window.TAlt1","rule":"TRule_an_id_window.TAlt1.Rule_id_window1","sum":46794903},{"parent":"TRule_an_id_without","rule":"TRule_an_id_without.Alt_an_id_without1","sum":23422764},{"parent":"TRule_an_id_without.TAlt1","rule":"TRule_an_id_without.TAlt1.Rule_id_without1","sum":23422764},{"parent":"TRule_and_subexpr","rule":"TRule_and_subexpr.Block2","sum":29447},{"parent":"TRule_and_subexpr","rule":"TRule_and_subexpr.Rule_xor_subexpr1","sum":14301292117},{"parent":"TRule_and_subexpr.TBlock2","rule":"TRule_and_subexpr.TBlock2.Rule_xor_subexpr2","sum":29511},{"parent":"TRule_and_subexpr.TBlock2","rule":"TRule_and_subexpr.TBlock2.Token1","sum":29511},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr1","sum":5157361938},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr10","sum":36160238},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr11","sum":8542848},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr12","sum":14736673},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr2","sum":1777610750},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr3","sum":448136730},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr4","sum":399237067},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr5","sum":77242},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr6","sum":62000126},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr7","sum":931114620},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr8","sum":165732},{"parent":"TRule_atom_expr","rule":"TRule_atom_expr.Alt_atom_expr9","sum":516962},{"parent":"TRule_atom_expr.TAlt1","rule":"TRule_atom_expr.TAlt1.Rule_literal_value1","sum":5157361938},{"parent":"TRule_atom_expr.TAlt10","rule":"TRule_atom_expr.TAlt10.Rule_list_literal1","sum":36160238},{"parent":"TRule_atom_expr.TAlt11","rule":"TRule_atom_expr.TAlt11.Rule_dict_literal1","sum":8542848},{"parent":"TRule_atom_expr.TAlt12","rule":"TRule_atom_expr.TAlt12.Rule_struct_literal1","sum":14736673},{"parent":"TRule_atom_expr.TAlt2","rule":"TRule_atom_expr.TAlt2.Rule_bind_parameter1","sum":1777610750},{"parent":"TRule_atom_expr.TAlt3","rule":"TRule_atom_expr.TAlt3.Rule_lambda1","sum":448136730},{"parent":"TRule_atom_expr.TAlt4","rule":"TRule_atom_expr.TAlt4.Rule_cast_expr1","sum":399237067},{"parent":"TRule_atom_expr.TAlt5","rule":"TRule_atom_expr.TAlt5.Rule_exists_expr1","sum":77242},{"parent":"TRule_atom_expr.TAlt6","rule":"TRule_atom_expr.TAlt6.Rule_case_expr1","sum":62000126},{"parent":"TRule_atom_expr.TAlt7","rule":"TRule_atom_expr.TAlt7.Block3","sum":931114620},{"parent":"TRule_atom_expr.TAlt7","rule":"TRule_atom_expr.TAlt7.Rule_an_id_or_type1","sum":931114620},{"parent":"TRule_atom_expr.TAlt7","rule":"TRule_atom_expr.TAlt7.Token2","sum":931114620},{"parent":"TRule_atom_expr.TAlt7.TBlock3","rule":"TRule_atom_expr.TAlt7.TBlock3.Alt1","sum":931113385},{"parent":"TRule_atom_expr.TAlt7.TBlock3","rule":"TRule_atom_expr.TAlt7.TBlock3.Alt2","sum":1235},{"parent":"TRule_atom_expr.TAlt7.TBlock3.TAlt1","rule":"TRule_atom_expr.TAlt7.TBlock3.TAlt1.Rule_id_or_type1","sum":931113385},{"parent":"TRule_atom_expr.TAlt7.TBlock3.TAlt2","rule":"TRule_atom_expr.TAlt7.TBlock3.TAlt2.Token1","sum":1235},{"parent":"TRule_atom_expr.TAlt8","rule":"TRule_atom_expr.TAlt8.Rule_value_constructor1","sum":165732},{"parent":"TRule_atom_expr.TAlt9","rule":"TRule_atom_expr.TAlt9.Rule_bitcast_expr1","sum":516962},{"parent":"TRule_bind_parameter","rule":"TRule_bind_parameter.Block2","sum":3715856694},{"parent":"TRule_bind_parameter","rule":"TRule_bind_parameter.Token1","sum":3715856694},{"parent":"TRule_bind_parameter.TBlock2","rule":"TRule_bind_parameter.TBlock2.Alt1","sum":3715844742},{"parent":"TRule_bind_parameter.TBlock2","rule":"TRule_bind_parameter.TBlock2.Alt2","sum":9462},{"parent":"TRule_bind_parameter.TBlock2","rule":"TRule_bind_parameter.TBlock2.Alt3","sum":2490},{"parent":"TRule_bind_parameter.TBlock2.TAlt1","rule":"TRule_bind_parameter.TBlock2.TAlt1.Rule_an_id_or_type1","sum":3715844742},{"parent":"TRule_bind_parameter.TBlock2.TAlt2","rule":"TRule_bind_parameter.TBlock2.TAlt2.Token1","sum":9462},{"parent":"TRule_bind_parameter.TBlock2.TAlt3","rule":"TRule_bind_parameter.TBlock2.TAlt3.Token1","sum":2490},{"parent":"TRule_bind_parameter_list","rule":"TRule_bind_parameter_list.Block2","sum":251552},{"parent":"TRule_bind_parameter_list","rule":"TRule_bind_parameter_list.Rule_bind_parameter1","sum":1010795718},{"parent":"TRule_bind_parameter_list.TBlock2","rule":"TRule_bind_parameter_list.TBlock2.Rule_bind_parameter2","sum":348012},{"parent":"TRule_bind_parameter_list.TBlock2","rule":"TRule_bind_parameter_list.TBlock2.Token1","sum":348012},{"parent":"TRule_bit_subexpr","rule":"TRule_bit_subexpr.Block2","sum":138589425},{"parent":"TRule_bit_subexpr","rule":"TRule_bit_subexpr.Rule_add_subexpr1","sum":15482613119},{"parent":"TRule_bit_subexpr.TBlock2","rule":"TRule_bit_subexpr.TBlock2.Rule_add_subexpr2","sum":157140383},{"parent":"TRule_bit_subexpr.TBlock2","rule":"TRule_bit_subexpr.TBlock2.Token1","sum":157140383},{"parent":"TRule_bitcast_expr","rule":"TRule_bitcast_expr.Rule_expr3","sum":516962},{"parent":"TRule_bitcast_expr","rule":"TRule_bitcast_expr.Rule_type_name_simple5","sum":516962},{"parent":"TRule_bitcast_expr","rule":"TRule_bitcast_expr.Token1","sum":516962},{"parent":"TRule_bitcast_expr","rule":"TRule_bitcast_expr.Token2","sum":516962},{"parent":"TRule_bitcast_expr","rule":"TRule_bitcast_expr.Token4","sum":516962},{"parent":"TRule_bitcast_expr","rule":"TRule_bitcast_expr.Token6","sum":516962},{"parent":"TRule_bool_value","rule":"TRule_bool_value.Token1","sum":104618486},{"parent":"TRule_call_action","rule":"TRule_call_action.Block1","sum":9487200},{"parent":"TRule_call_action","rule":"TRule_call_action.Block3","sum":7206525},{"parent":"TRule_call_action","rule":"TRule_call_action.Token2","sum":9487200},{"parent":"TRule_call_action","rule":"TRule_call_action.Token4","sum":9487200},{"parent":"TRule_call_action.TBlock1","rule":"TRule_call_action.TBlock1.Alt1","sum":9360822},{"parent":"TRule_call_action.TBlock1","rule":"TRule_call_action.TBlock1.Alt2","sum":126378},{"parent":"TRule_call_action.TBlock1.TAlt1","rule":"TRule_call_action.TBlock1.TAlt1.Rule_bind_parameter1","sum":9360822},{"parent":"TRule_call_action.TBlock1.TAlt2","rule":"TRule_call_action.TBlock1.TAlt2.Token1","sum":126378},{"parent":"TRule_call_action.TBlock3","rule":"TRule_call_action.TBlock3.Rule_expr_list1","sum":7206525},{"parent":"TRule_callable_arg","rule":"TRule_callable_arg.Block2","sum":1},{"parent":"TRule_callable_arg","rule":"TRule_callable_arg.Rule_variant_arg1","sum":18037904},{"parent":"TRule_callable_arg.TBlock2","rule":"TRule_callable_arg.TBlock2.Token1","sum":1},{"parent":"TRule_callable_arg.TBlock2","rule":"TRule_callable_arg.TBlock2.Token2","sum":1},{"parent":"TRule_callable_arg.TBlock2","rule":"TRule_callable_arg.TBlock2.Token3","sum":1},{"parent":"TRule_callable_arg_list","rule":"TRule_callable_arg_list.Block2","sum":4390160},{"parent":"TRule_callable_arg_list","rule":"TRule_callable_arg_list.Rule_callable_arg1","sum":9799746},{"parent":"TRule_callable_arg_list.TBlock2","rule":"TRule_callable_arg_list.TBlock2.Rule_callable_arg2","sum":8238158},{"parent":"TRule_callable_arg_list.TBlock2","rule":"TRule_callable_arg_list.TBlock2.Token1","sum":8238158},{"parent":"TRule_case_expr","rule":"TRule_case_expr.Block2","sum":4677251},{"parent":"TRule_case_expr","rule":"TRule_case_expr.Block3","sum":62000130},{"parent":"TRule_case_expr","rule":"TRule_case_expr.Block4","sum":62000130},{"parent":"TRule_case_expr","rule":"TRule_case_expr.Token1","sum":62000130},{"parent":"TRule_case_expr","rule":"TRule_case_expr.Token5","sum":62000130},{"parent":"TRule_case_expr.TBlock2","rule":"TRule_case_expr.TBlock2.Rule_expr1","sum":4677251},{"parent":"TRule_case_expr.TBlock3","rule":"TRule_case_expr.TBlock3.Rule_when_expr1","sum":158729543},{"parent":"TRule_case_expr.TBlock4","rule":"TRule_case_expr.TBlock4.Rule_expr2","sum":62000130},{"parent":"TRule_case_expr.TBlock4","rule":"TRule_case_expr.TBlock4.Token1","sum":62000130},{"parent":"TRule_cast_expr","rule":"TRule_cast_expr.Rule_expr3","sum":399281360},{"parent":"TRule_cast_expr","rule":"TRule_cast_expr.Rule_type_name_or_bind5","sum":399281360},{"parent":"TRule_cast_expr","rule":"TRule_cast_expr.Token1","sum":399281360},{"parent":"TRule_cast_expr","rule":"TRule_cast_expr.Token2","sum":399281360},{"parent":"TRule_cast_expr","rule":"TRule_cast_expr.Token4","sum":399281360},{"parent":"TRule_cast_expr","rule":"TRule_cast_expr.Token6","sum":399281360},{"parent":"TRule_cluster_expr","rule":"TRule_cluster_expr.Block1","sum":6795363},{"parent":"TRule_cluster_expr","rule":"TRule_cluster_expr.Block2","sum":375904721},{"parent":"TRule_cluster_expr.TBlock1","rule":"TRule_cluster_expr.TBlock1.Rule_an_id1","sum":6795363},{"parent":"TRule_cluster_expr.TBlock1","rule":"TRule_cluster_expr.TBlock1.Token2","sum":6795363},{"parent":"TRule_cluster_expr.TBlock2","rule":"TRule_cluster_expr.TBlock2.Alt1","sum":375904721},{"parent":"TRule_cluster_expr.TBlock2.TAlt1","rule":"TRule_cluster_expr.TBlock2.TAlt1.Rule_pure_column_or_named1","sum":375904721},{"parent":"TRule_column_list","rule":"TRule_column_list.Block2","sum":286232},{"parent":"TRule_column_list","rule":"TRule_column_list.Block3","sum":890},{"parent":"TRule_column_list","rule":"TRule_column_list.Rule_column_name1","sum":858313},{"parent":"TRule_column_list.TBlock2","rule":"TRule_column_list.TBlock2.Rule_column_name2","sum":1129270},{"parent":"TRule_column_list.TBlock2","rule":"TRule_column_list.TBlock2.Token1","sum":1129270},{"parent":"TRule_column_list.TBlock3","rule":"TRule_column_list.TBlock3.Token1","sum":890},{"parent":"TRule_column_name","rule":"TRule_column_name.Rule_an_id2","sum":23439287},{"parent":"TRule_column_name","rule":"TRule_column_name.Rule_opt_id_prefix1","sum":23439287},{"parent":"TRule_column_order_by_specification","rule":"TRule_column_order_by_specification.Rule_an_id1","sum":105},{"parent":"TRule_column_schema","rule":"TRule_column_schema.Rule_an_id_schema1","sum":1160},{"parent":"TRule_column_schema","rule":"TRule_column_schema.Rule_opt_column_constraints4","sum":1160},{"parent":"TRule_column_schema","rule":"TRule_column_schema.Rule_type_name_or_bind2","sum":1160},{"parent":"TRule_commit_stmt","rule":"TRule_commit_stmt.Token1","sum":13057020},{"parent":"TRule_con_subexpr","rule":"TRule_con_subexpr.Alt_con_subexpr1","sum":15949808357},{"parent":"TRule_con_subexpr","rule":"TRule_con_subexpr.Alt_con_subexpr2","sum":87839446},{"parent":"TRule_con_subexpr.TAlt1","rule":"TRule_con_subexpr.TAlt1.Rule_unary_subexpr1","sum":15949808357},{"parent":"TRule_con_subexpr.TAlt2","rule":"TRule_con_subexpr.TAlt2.Rule_unary_op1","sum":87839446},{"parent":"TRule_con_subexpr.TAlt2","rule":"TRule_con_subexpr.TAlt2.Rule_unary_subexpr2","sum":87839446},{"parent":"TRule_cond_expr","rule":"TRule_cond_expr.Alt_cond_expr1","sum":52393370},{"parent":"TRule_cond_expr","rule":"TRule_cond_expr.Alt_cond_expr2","sum":126255554},{"parent":"TRule_cond_expr","rule":"TRule_cond_expr.Alt_cond_expr3","sum":173278806},{"parent":"TRule_cond_expr","rule":"TRule_cond_expr.Alt_cond_expr4","sum":25108695},{"parent":"TRule_cond_expr","rule":"TRule_cond_expr.Alt_cond_expr5","sum":721369232},{"parent":"TRule_cond_expr.TAlt1","rule":"TRule_cond_expr.TAlt1.Block1","sum":9336525},{"parent":"TRule_cond_expr.TAlt1","rule":"TRule_cond_expr.TAlt1.Block4","sum":92172},{"parent":"TRule_cond_expr.TAlt1","rule":"TRule_cond_expr.TAlt1.Rule_eq_subexpr3","sum":52393370},{"parent":"TRule_cond_expr.TAlt1","rule":"TRule_cond_expr.TAlt1.Rule_match_op2","sum":52393370},{"parent":"TRule_cond_expr.TAlt1.TBlock1","rule":"TRule_cond_expr.TAlt1.TBlock1.Token1","sum":9336525},{"parent":"TRule_cond_expr.TAlt1.TBlock4","rule":"TRule_cond_expr.TAlt1.TBlock4.Rule_eq_subexpr2","sum":92172},{"parent":"TRule_cond_expr.TAlt1.TBlock4","rule":"TRule_cond_expr.TAlt1.TBlock4.Token1","sum":92172},{"parent":"TRule_cond_expr.TAlt2","rule":"TRule_cond_expr.TAlt2.Block1","sum":26271760},{"parent":"TRule_cond_expr.TAlt2","rule":"TRule_cond_expr.TAlt2.Block3","sum":3141787},{"parent":"TRule_cond_expr.TAlt2","rule":"TRule_cond_expr.TAlt2.Rule_in_expr4","sum":126255554},{"parent":"TRule_cond_expr.TAlt2","rule":"TRule_cond_expr.TAlt2.Token2","sum":126255554},{"parent":"TRule_cond_expr.TAlt2.TBlock1","rule":"TRule_cond_expr.TAlt2.TBlock1.Token1","sum":26271760},{"parent":"TRule_cond_expr.TAlt2.TBlock3","rule":"TRule_cond_expr.TAlt2.TBlock3.Token1","sum":3141787},{"parent":"TRule_cond_expr.TAlt3","rule":"TRule_cond_expr.TAlt3.Block1","sum":173278806},{"parent":"TRule_cond_expr.TAlt3.TBlock1","rule":"TRule_cond_expr.TAlt3.TBlock1.Alt1","sum":162},{"parent":"TRule_cond_expr.TAlt3.TBlock1","rule":"TRule_cond_expr.TAlt3.TBlock1.Alt2","sum":390},{"parent":"TRule_cond_expr.TAlt3.TBlock1","rule":"TRule_cond_expr.TAlt3.TBlock1.Alt3","sum":60881961},{"parent":"TRule_cond_expr.TAlt3.TBlock1","rule":"TRule_cond_expr.TAlt3.TBlock1.Alt4","sum":112396293},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt1","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt1.Token1","sum":162},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt2","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt2.Token1","sum":390},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt3","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt3.Token1","sum":60881961},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt3","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt3.Token2","sum":60881961},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt4","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt4.Block1","sum":112354867},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt4","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt4.Token2","sum":112396293},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt4","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt4.Token3","sum":112396293},{"parent":"TRule_cond_expr.TAlt3.TBlock1.TAlt4.TBlock1","rule":"TRule_cond_expr.TAlt3.TBlock1.TAlt4.TBlock1.Token1","sum":112354867},{"parent":"TRule_cond_expr.TAlt4","rule":"TRule_cond_expr.TAlt4.Block1","sum":406296},{"parent":"TRule_cond_expr.TAlt4","rule":"TRule_cond_expr.TAlt4.Block3","sum":26},{"parent":"TRule_cond_expr.TAlt4","rule":"TRule_cond_expr.TAlt4.Rule_eq_subexpr4","sum":25108695},{"parent":"TRule_cond_expr.TAlt4","rule":"TRule_cond_expr.TAlt4.Rule_eq_subexpr6","sum":25108695},{"parent":"TRule_cond_expr.TAlt4","rule":"TRule_cond_expr.TAlt4.Token2","sum":25108695},{"parent":"TRule_cond_expr.TAlt4","rule":"TRule_cond_expr.TAlt4.Token5","sum":25108695},{"parent":"TRule_cond_expr.TAlt4.TBlock1","rule":"TRule_cond_expr.TAlt4.TBlock1.Token1","sum":406296},{"parent":"TRule_cond_expr.TAlt4.TBlock3","rule":"TRule_cond_expr.TAlt4.TBlock3.Token1","sum":26},{"parent":"TRule_cond_expr.TAlt5","rule":"TRule_cond_expr.TAlt5.Block1","sum":721369232},{"parent":"TRule_cond_expr.TAlt5.TBlock1","rule":"TRule_cond_expr.TAlt5.TBlock1.Block1","sum":721371197},{"parent":"TRule_cond_expr.TAlt5.TBlock1","rule":"TRule_cond_expr.TAlt5.TBlock1.Rule_eq_subexpr2","sum":721371197},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.Alt1","sum":493355233},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.Alt2","sum":172963026},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.Alt3","sum":49642288},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.Alt4","sum":5008709},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.Alt5","sum":401941},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt1","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt1.Token1","sum":493355233},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt2","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt2.Token1","sum":172963026},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt3","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt3.Token1","sum":49642288},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt4","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt4.Token1","sum":5008709},{"parent":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt5","rule":"TRule_cond_expr.TAlt5.TBlock1.TBlock1.TAlt5.Rule_distinct_from_op1","sum":401941},{"parent":"TRule_create_table_entry","rule":"TRule_create_table_entry.Alt_create_table_entry1","sum":1160},{"parent":"TRule_create_table_entry","rule":"TRule_create_table_entry.Alt_create_table_entry2","sum":229},{"parent":"TRule_create_table_entry.TAlt1","rule":"TRule_create_table_entry.TAlt1.Rule_column_schema1","sum":1160},{"parent":"TRule_create_table_entry.TAlt2","rule":"TRule_create_table_entry.TAlt2.Rule_table_constraint1","sum":229},{"parent":"TRule_create_table_stmt","rule":"TRule_create_table_stmt.Block3","sum":125},{"parent":"TRule_create_table_stmt","rule":"TRule_create_table_stmt.Block8","sum":125},{"parent":"TRule_create_table_stmt","rule":"TRule_create_table_stmt.Rule_create_table_entry7","sum":125},{"parent":"TRule_create_table_stmt","rule":"TRule_create_table_stmt.Rule_simple_table_ref5","sum":125},{"parent":"TRule_create_table_stmt","rule":"TRule_create_table_stmt.Token1","sum":125},{"parent":"TRule_create_table_stmt","rule":"TRule_create_table_stmt.Token10","sum":125},{"parent":"TRule_create_table_stmt","rule":"TRule_create_table_stmt.Token6","sum":125},{"parent":"TRule_create_table_stmt.TBlock3","rule":"TRule_create_table_stmt.TBlock3.Alt1","sum":125},{"parent":"TRule_create_table_stmt.TBlock3.TAlt1","rule":"TRule_create_table_stmt.TBlock3.TAlt1.Token1","sum":125},{"parent":"TRule_create_table_stmt.TBlock8","rule":"TRule_create_table_stmt.TBlock8.Rule_create_table_entry2","sum":1264},{"parent":"TRule_create_table_stmt.TBlock8","rule":"TRule_create_table_stmt.TBlock8.Token1","sum":1264},{"parent":"TRule_cube_list","rule":"TRule_cube_list.Rule_ordinary_grouping_set_list3","sum":276361},{"parent":"TRule_cube_list","rule":"TRule_cube_list.Token1","sum":276361},{"parent":"TRule_cube_list","rule":"TRule_cube_list.Token2","sum":276361},{"parent":"TRule_cube_list","rule":"TRule_cube_list.Token4","sum":276361},{"parent":"TRule_declare_stmt","rule":"TRule_declare_stmt.Rule_bind_parameter2","sum":156792290},{"parent":"TRule_declare_stmt","rule":"TRule_declare_stmt.Rule_type_name4","sum":156792290},{"parent":"TRule_declare_stmt","rule":"TRule_declare_stmt.Token1","sum":156792290},{"parent":"TRule_declare_stmt","rule":"TRule_declare_stmt.Token3","sum":156792290},{"parent":"TRule_define_action_or_subquery_body","rule":"TRule_define_action_or_subquery_body.Block1","sum":45718},{"parent":"TRule_define_action_or_subquery_body","rule":"TRule_define_action_or_subquery_body.Block2","sum":36285457},{"parent":"TRule_define_action_or_subquery_body.TBlock1","rule":"TRule_define_action_or_subquery_body.TBlock1.Token1","sum":45718},{"parent":"TRule_define_action_or_subquery_body.TBlock2","rule":"TRule_define_action_or_subquery_body.TBlock2.Block2","sum":16156594},{"parent":"TRule_define_action_or_subquery_body.TBlock2","rule":"TRule_define_action_or_subquery_body.TBlock2.Block3","sum":23643182},{"parent":"TRule_define_action_or_subquery_body.TBlock2","rule":"TRule_define_action_or_subquery_body.TBlock2.Rule_sql_stmt_core1","sum":36285457},{"parent":"TRule_define_action_or_subquery_body.TBlock2.TBlock2","rule":"TRule_define_action_or_subquery_body.TBlock2.TBlock2.Block1","sum":46112405},{"parent":"TRule_define_action_or_subquery_body.TBlock2.TBlock2","rule":"TRule_define_action_or_subquery_body.TBlock2.TBlock2.Rule_sql_stmt_core2","sum":46112405},{"parent":"TRule_define_action_or_subquery_body.TBlock2.TBlock2.TBlock1","rule":"TRule_define_action_or_subquery_body.TBlock2.TBlock2.TBlock1.Token1","sum":46125679},{"parent":"TRule_define_action_or_subquery_body.TBlock2.TBlock3","rule":"TRule_define_action_or_subquery_body.TBlock2.TBlock3.Token1","sum":23669314},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Block5","sum":14027239},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Rule_bind_parameter3","sum":22375819},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Rule_define_action_or_subquery_body8","sum":22375819},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Token1","sum":22375819},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Token10","sum":22375819},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Token2","sum":22375819},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Token4","sum":22375819},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Token6","sum":22375819},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Token7","sum":22375819},{"parent":"TRule_define_action_or_subquery_stmt","rule":"TRule_define_action_or_subquery_stmt.Token9","sum":22375819},{"parent":"TRule_define_action_or_subquery_stmt.TBlock5","rule":"TRule_define_action_or_subquery_stmt.TBlock5.Rule_action_or_subquery_args1","sum":14027239},{"parent":"TRule_dict_literal","rule":"TRule_dict_literal.Block2","sum":8248170},{"parent":"TRule_dict_literal","rule":"TRule_dict_literal.Block3","sum":2256610},{"parent":"TRule_dict_literal","rule":"TRule_dict_literal.Token1","sum":8997473},{"parent":"TRule_dict_literal","rule":"TRule_dict_literal.Token4","sum":8997473},{"parent":"TRule_dict_literal.TBlock2","rule":"TRule_dict_literal.TBlock2.Rule_expr_dict_list1","sum":8248170},{"parent":"TRule_dict_literal.TBlock3","rule":"TRule_dict_literal.TBlock3.Token1","sum":2256610},{"parent":"TRule_distinct_from_op","rule":"TRule_distinct_from_op.Block2","sum":118884},{"parent":"TRule_distinct_from_op","rule":"TRule_distinct_from_op.Token1","sum":401941},{"parent":"TRule_distinct_from_op","rule":"TRule_distinct_from_op.Token3","sum":401941},{"parent":"TRule_distinct_from_op","rule":"TRule_distinct_from_op.Token4","sum":401941},{"parent":"TRule_distinct_from_op.TBlock2","rule":"TRule_distinct_from_op.TBlock2.Token1","sum":118884},{"parent":"TRule_do_stmt","rule":"TRule_do_stmt.Block2","sum":23403292},{"parent":"TRule_do_stmt","rule":"TRule_do_stmt.Token1","sum":23403292},{"parent":"TRule_do_stmt.TBlock2","rule":"TRule_do_stmt.TBlock2.Alt1","sum":9487200},{"parent":"TRule_do_stmt.TBlock2","rule":"TRule_do_stmt.TBlock2.Alt2","sum":13916092},{"parent":"TRule_do_stmt.TBlock2.TAlt1","rule":"TRule_do_stmt.TBlock2.TAlt1.Rule_call_action1","sum":9487200},{"parent":"TRule_do_stmt.TBlock2.TAlt2","rule":"TRule_do_stmt.TBlock2.TAlt2.Rule_inline_action1","sum":13916092},{"parent":"TRule_double_question","rule":"TRule_double_question.Token1","sum":108073061},{"parent":"TRule_double_question","rule":"TRule_double_question.Token2","sum":108073061},{"parent":"TRule_drop_table_stmt","rule":"TRule_drop_table_stmt.Block2","sum":2572734},{"parent":"TRule_drop_table_stmt","rule":"TRule_drop_table_stmt.Block3","sum":3},{"parent":"TRule_drop_table_stmt","rule":"TRule_drop_table_stmt.Rule_simple_table_ref4","sum":2572734},{"parent":"TRule_drop_table_stmt","rule":"TRule_drop_table_stmt.Token1","sum":2572734},{"parent":"TRule_drop_table_stmt.TBlock2","rule":"TRule_drop_table_stmt.TBlock2.Alt1","sum":2572734},{"parent":"TRule_drop_table_stmt.TBlock2.TAlt1","rule":"TRule_drop_table_stmt.TBlock2.TAlt1.Token1","sum":2572734},{"parent":"TRule_drop_table_stmt.TBlock3","rule":"TRule_drop_table_stmt.TBlock3.Token1","sum":3},{"parent":"TRule_drop_table_stmt.TBlock3","rule":"TRule_drop_table_stmt.TBlock3.Token2","sum":3},{"parent":"TRule_eq_subexpr","rule":"TRule_eq_subexpr.Block2","sum":239920260},{"parent":"TRule_eq_subexpr","rule":"TRule_eq_subexpr.Rule_neq_subexpr1","sum":15125395757},{"parent":"TRule_eq_subexpr.TBlock2","rule":"TRule_eq_subexpr.TBlock2.Rule_neq_subexpr2","sum":239920314},{"parent":"TRule_eq_subexpr.TBlock2","rule":"TRule_eq_subexpr.TBlock2.Token1","sum":239920314},{"parent":"TRule_exists_expr","rule":"TRule_exists_expr.Block3","sum":77242},{"parent":"TRule_exists_expr","rule":"TRule_exists_expr.Token1","sum":77242},{"parent":"TRule_exists_expr","rule":"TRule_exists_expr.Token2","sum":77242},{"parent":"TRule_exists_expr","rule":"TRule_exists_expr.Token4","sum":77242},{"parent":"TRule_exists_expr.TBlock3","rule":"TRule_exists_expr.TBlock3.Alt1","sum":77242},{"parent":"TRule_exists_expr.TBlock3.TAlt1","rule":"TRule_exists_expr.TBlock3.TAlt1.Rule_select_stmt1","sum":77242},{"parent":"TRule_expr","rule":"TRule_expr.Alt_expr1","sum":13713697233},{"parent":"TRule_expr","rule":"TRule_expr.Alt_expr2","sum":17425556},{"parent":"TRule_expr.TAlt1","rule":"TRule_expr.TAlt1.Block2","sum":68508745},{"parent":"TRule_expr.TAlt1","rule":"TRule_expr.TAlt1.Rule_or_subexpr1","sum":13713697233},{"parent":"TRule_expr.TAlt1.TBlock2","rule":"TRule_expr.TAlt1.TBlock2.Rule_or_subexpr2","sum":115429705},{"parent":"TRule_expr.TAlt1.TBlock2","rule":"TRule_expr.TAlt1.TBlock2.Token1","sum":115429705},{"parent":"TRule_expr.TAlt2","rule":"TRule_expr.TAlt2.Rule_type_name_composite1","sum":17425556},{"parent":"TRule_expr_dict_list","rule":"TRule_expr_dict_list.Block2","sum":7050783},{"parent":"TRule_expr_dict_list","rule":"TRule_expr_dict_list.Block3","sum":6655688},{"parent":"TRule_expr_dict_list","rule":"TRule_expr_dict_list.Rule_expr1","sum":8248170},{"parent":"TRule_expr_dict_list.TBlock2","rule":"TRule_expr_dict_list.TBlock2.Rule_expr2","sum":7050783},{"parent":"TRule_expr_dict_list.TBlock2","rule":"TRule_expr_dict_list.TBlock2.Token1","sum":7050783},{"parent":"TRule_expr_dict_list.TBlock3","rule":"TRule_expr_dict_list.TBlock3.Block3","sum":35369774},{"parent":"TRule_expr_dict_list.TBlock3","rule":"TRule_expr_dict_list.TBlock3.Rule_expr2","sum":42335591},{"parent":"TRule_expr_dict_list.TBlock3","rule":"TRule_expr_dict_list.TBlock3.Token1","sum":42335591},{"parent":"TRule_expr_dict_list.TBlock3.TBlock3","rule":"TRule_expr_dict_list.TBlock3.TBlock3.Rule_expr2","sum":35369774},{"parent":"TRule_expr_dict_list.TBlock3.TBlock3","rule":"TRule_expr_dict_list.TBlock3.TBlock3.Token1","sum":35369774},{"parent":"TRule_expr_list","rule":"TRule_expr_list.Block2","sum":42099297},{"parent":"TRule_expr_list","rule":"TRule_expr_list.Rule_expr1","sum":67782951},{"parent":"TRule_expr_list.TBlock2","rule":"TRule_expr_list.TBlock2.Rule_expr2","sum":206854597},{"parent":"TRule_expr_list.TBlock2","rule":"TRule_expr_list.TBlock2.Token1","sum":206854597},{"parent":"TRule_expr_struct_list","rule":"TRule_expr_struct_list.Block4","sum":12650040},{"parent":"TRule_expr_struct_list","rule":"TRule_expr_struct_list.Rule_expr1","sum":14603829},{"parent":"TRule_expr_struct_list","rule":"TRule_expr_struct_list.Rule_expr3","sum":14603829},{"parent":"TRule_expr_struct_list","rule":"TRule_expr_struct_list.Token2","sum":14603829},{"parent":"TRule_expr_struct_list.TBlock4","rule":"TRule_expr_struct_list.TBlock4.Rule_expr2","sum":31557138},{"parent":"TRule_expr_struct_list.TBlock4","rule":"TRule_expr_struct_list.TBlock4.Rule_expr4","sum":31557138},{"parent":"TRule_expr_struct_list.TBlock4","rule":"TRule_expr_struct_list.TBlock4.Token1","sum":31557138},{"parent":"TRule_expr_struct_list.TBlock4","rule":"TRule_expr_struct_list.TBlock4.Token3","sum":31557138},{"parent":"TRule_ext_order_by_clause","rule":"TRule_ext_order_by_clause.Block1","sum":2627040},{"parent":"TRule_ext_order_by_clause","rule":"TRule_ext_order_by_clause.Rule_order_by_clause2","sum":89004653},{"parent":"TRule_ext_order_by_clause.TBlock1","rule":"TRule_ext_order_by_clause.TBlock1.Token1","sum":2627040},{"parent":"TRule_flatten_by_arg","rule":"TRule_flatten_by_arg.Alt_flatten_by_arg1","sum":21451704},{"parent":"TRule_flatten_by_arg","rule":"TRule_flatten_by_arg.Alt_flatten_by_arg2","sum":4343368},{"parent":"TRule_flatten_by_arg.TAlt1","rule":"TRule_flatten_by_arg.TAlt1.Rule_named_column1","sum":21451704},{"parent":"TRule_flatten_by_arg.TAlt2","rule":"TRule_flatten_by_arg.TAlt2.Block3","sum":53158},{"parent":"TRule_flatten_by_arg.TAlt2","rule":"TRule_flatten_by_arg.TAlt2.Rule_named_expr_list2","sum":4343368},{"parent":"TRule_flatten_by_arg.TAlt2","rule":"TRule_flatten_by_arg.TAlt2.Token1","sum":4343368},{"parent":"TRule_flatten_by_arg.TAlt2","rule":"TRule_flatten_by_arg.TAlt2.Token4","sum":4343368},{"parent":"TRule_flatten_by_arg.TAlt2.TBlock3","rule":"TRule_flatten_by_arg.TAlt2.TBlock3.Token1","sum":53158},{"parent":"TRule_flatten_source","rule":"TRule_flatten_source.Block2","sum":33768374},{"parent":"TRule_flatten_source","rule":"TRule_flatten_source.Rule_named_single_source1","sum":1055367403},{"parent":"TRule_flatten_source.TBlock2","rule":"TRule_flatten_source.TBlock2.Block2","sum":33768374},{"parent":"TRule_flatten_source.TBlock2","rule":"TRule_flatten_source.TBlock2.Token1","sum":33768374},{"parent":"TRule_flatten_source.TBlock2.TBlock2","rule":"TRule_flatten_source.TBlock2.TBlock2.Alt1","sum":25795072},{"parent":"TRule_flatten_source.TBlock2.TBlock2","rule":"TRule_flatten_source.TBlock2.TBlock2.Alt2","sum":7973302},{"parent":"TRule_flatten_source.TBlock2.TBlock2.TAlt1","rule":"TRule_flatten_source.TBlock2.TBlock2.TAlt1.Block1","sum":19723502},{"parent":"TRule_flatten_source.TBlock2.TBlock2.TAlt1","rule":"TRule_flatten_source.TBlock2.TBlock2.TAlt1.Rule_flatten_by_arg3","sum":25795072},{"parent":"TRule_flatten_source.TBlock2.TBlock2.TAlt1","rule":"TRule_flatten_source.TBlock2.TBlock2.TAlt1.Token2","sum":25795072},{"parent":"TRule_flatten_source.TBlock2.TBlock2.TAlt1.TBlock1","rule":"TRule_flatten_source.TBlock2.TBlock2.TAlt1.TBlock1.Token1","sum":19723502},{"parent":"TRule_flatten_source.TBlock2.TBlock2.TAlt2","rule":"TRule_flatten_source.TBlock2.TBlock2.TAlt2.Token1","sum":7973302},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Block1","sum":7048099},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Block2","sum":8},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Block8","sum":64969},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Rule_bind_parameter4","sum":7048194},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Rule_do_stmt7","sum":7048194},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Rule_expr6","sum":7048194},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Token3","sum":7048194},{"parent":"TRule_for_stmt","rule":"TRule_for_stmt.Token5","sum":7048194},{"parent":"TRule_for_stmt.TBlock1","rule":"TRule_for_stmt.TBlock1.Token1","sum":7048099},{"parent":"TRule_for_stmt.TBlock2","rule":"TRule_for_stmt.TBlock2.Token1","sum":8},{"parent":"TRule_for_stmt.TBlock8","rule":"TRule_for_stmt.TBlock8.Rule_do_stmt2","sum":64969},{"parent":"TRule_for_stmt.TBlock8","rule":"TRule_for_stmt.TBlock8.Token1","sum":64969},{"parent":"TRule_group_by_clause","rule":"TRule_group_by_clause.Block2","sum":1609399},{"parent":"TRule_group_by_clause","rule":"TRule_group_by_clause.Block6","sum":6},{"parent":"TRule_group_by_clause","rule":"TRule_group_by_clause.Rule_grouping_element_list5","sum":138061902},{"parent":"TRule_group_by_clause","rule":"TRule_group_by_clause.Rule_opt_set_quantifier4","sum":138061902},{"parent":"TRule_group_by_clause","rule":"TRule_group_by_clause.Token1","sum":138061902},{"parent":"TRule_group_by_clause","rule":"TRule_group_by_clause.Token3","sum":138061902},{"parent":"TRule_group_by_clause.TBlock2","rule":"TRule_group_by_clause.TBlock2.Token1","sum":1609399},{"parent":"TRule_group_by_clause.TBlock6","rule":"TRule_group_by_clause.TBlock6.Rule_an_id2","sum":6},{"parent":"TRule_group_by_clause.TBlock6","rule":"TRule_group_by_clause.TBlock6.Token1","sum":6},{"parent":"TRule_grouping_element","rule":"TRule_grouping_element.Alt_grouping_element1","sum":301105925},{"parent":"TRule_grouping_element","rule":"TRule_grouping_element.Alt_grouping_element2","sum":63017},{"parent":"TRule_grouping_element","rule":"TRule_grouping_element.Alt_grouping_element3","sum":276361},{"parent":"TRule_grouping_element","rule":"TRule_grouping_element.Alt_grouping_element4","sum":92394},{"parent":"TRule_grouping_element","rule":"TRule_grouping_element.Alt_grouping_element5","sum":23},{"parent":"TRule_grouping_element.TAlt1","rule":"TRule_grouping_element.TAlt1.Rule_ordinary_grouping_set1","sum":301105925},{"parent":"TRule_grouping_element.TAlt2","rule":"TRule_grouping_element.TAlt2.Rule_rollup_list1","sum":63017},{"parent":"TRule_grouping_element.TAlt3","rule":"TRule_grouping_element.TAlt3.Rule_cube_list1","sum":276361},{"parent":"TRule_grouping_element.TAlt4","rule":"TRule_grouping_element.TAlt4.Rule_grouping_sets_specification1","sum":92394},{"parent":"TRule_grouping_element.TAlt5","rule":"TRule_grouping_element.TAlt5.Rule_hopping_window_specification1","sum":23},{"parent":"TRule_grouping_element_list","rule":"TRule_grouping_element_list.Block2","sum":62884956},{"parent":"TRule_grouping_element_list","rule":"TRule_grouping_element_list.Rule_grouping_element1","sum":138154296},{"parent":"TRule_grouping_element_list.TBlock2","rule":"TRule_grouping_element_list.TBlock2.Rule_grouping_element2","sum":163383424},{"parent":"TRule_grouping_element_list.TBlock2","rule":"TRule_grouping_element_list.TBlock2.Token1","sum":163383424},{"parent":"TRule_grouping_sets_specification","rule":"TRule_grouping_sets_specification.Rule_grouping_element_list4","sum":92394},{"parent":"TRule_grouping_sets_specification","rule":"TRule_grouping_sets_specification.Token1","sum":92394},{"parent":"TRule_grouping_sets_specification","rule":"TRule_grouping_sets_specification.Token2","sum":92394},{"parent":"TRule_grouping_sets_specification","rule":"TRule_grouping_sets_specification.Token3","sum":92394},{"parent":"TRule_grouping_sets_specification","rule":"TRule_grouping_sets_specification.Token5","sum":92394},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Rule_expr3","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Rule_expr5","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Rule_expr7","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Rule_expr9","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Token1","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Token10","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Token2","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Token4","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Token6","sum":23},{"parent":"TRule_hopping_window_specification","rule":"TRule_hopping_window_specification.Token8","sum":23},{"parent":"TRule_id","rule":"TRule_id.Alt_id1","sum":12163133686},{"parent":"TRule_id","rule":"TRule_id.Alt_id2","sum":533050547},{"parent":"TRule_id.TAlt1","rule":"TRule_id.TAlt1.Rule_identifier1","sum":12163133686},{"parent":"TRule_id.TAlt2","rule":"TRule_id.TAlt2.Rule_keyword1","sum":533050547},{"parent":"TRule_id_as_compat","rule":"TRule_id_as_compat.Alt_id_as_compat1","sum":3034444},{"parent":"TRule_id_as_compat","rule":"TRule_id_as_compat.Alt_id_as_compat2","sum":2690},{"parent":"TRule_id_as_compat.TAlt1","rule":"TRule_id_as_compat.TAlt1.Rule_identifier1","sum":3034444},{"parent":"TRule_id_as_compat.TAlt2","rule":"TRule_id_as_compat.TAlt2.Rule_keyword_as_compat1","sum":2690},{"parent":"TRule_id_expr","rule":"TRule_id_expr.Alt_id_expr1","sum":6935456183},{"parent":"TRule_id_expr","rule":"TRule_id_expr.Alt_id_expr2","sum":320834100},{"parent":"TRule_id_expr","rule":"TRule_id_expr.Alt_id_expr3","sum":417538},{"parent":"TRule_id_expr","rule":"TRule_id_expr.Alt_id_expr5","sum":35238238},{"parent":"TRule_id_expr","rule":"TRule_id_expr.Alt_id_expr6","sum":181460},{"parent":"TRule_id_expr.TAlt1","rule":"TRule_id_expr.TAlt1.Rule_identifier1","sum":6935456183},{"parent":"TRule_id_expr.TAlt2","rule":"TRule_id_expr.TAlt2.Rule_keyword_compat1","sum":320834100},{"parent":"TRule_id_expr.TAlt3","rule":"TRule_id_expr.TAlt3.Rule_keyword_alter_uncompat1","sum":417538},{"parent":"TRule_id_expr.TAlt5","rule":"TRule_id_expr.TAlt5.Rule_keyword_window_uncompat1","sum":35238238},{"parent":"TRule_id_expr.TAlt6","rule":"TRule_id_expr.TAlt6.Rule_keyword_hint_uncompat1","sum":181460},{"parent":"TRule_id_expr_in","rule":"TRule_id_expr_in.Alt_id_expr_in1","sum":5652110},{"parent":"TRule_id_expr_in","rule":"TRule_id_expr_in.Alt_id_expr_in2","sum":75406},{"parent":"TRule_id_expr_in","rule":"TRule_id_expr_in.Alt_id_expr_in4","sum":217},{"parent":"TRule_id_expr_in","rule":"TRule_id_expr_in.Alt_id_expr_in5","sum":53},{"parent":"TRule_id_expr_in.TAlt1","rule":"TRule_id_expr_in.TAlt1.Rule_identifier1","sum":5652110},{"parent":"TRule_id_expr_in.TAlt2","rule":"TRule_id_expr_in.TAlt2.Rule_keyword_compat1","sum":75406},{"parent":"TRule_id_expr_in.TAlt4","rule":"TRule_id_expr_in.TAlt4.Rule_keyword_window_uncompat1","sum":217},{"parent":"TRule_id_expr_in.TAlt5","rule":"TRule_id_expr_in.TAlt5.Rule_keyword_hint_uncompat1","sum":53},{"parent":"TRule_id_hint","rule":"TRule_id_hint.Alt_id_hint1","sum":154982067},{"parent":"TRule_id_hint","rule":"TRule_id_hint.Alt_id_hint2","sum":24170},{"parent":"TRule_id_hint","rule":"TRule_id_hint.Alt_id_hint3","sum":24169},{"parent":"TRule_id_hint.TAlt1","rule":"TRule_id_hint.TAlt1.Rule_identifier1","sum":154982067},{"parent":"TRule_id_hint.TAlt2","rule":"TRule_id_hint.TAlt2.Rule_keyword_compat1","sum":24170},{"parent":"TRule_id_hint.TAlt3","rule":"TRule_id_hint.TAlt3.Rule_keyword_expr_uncompat1","sum":24169},{"parent":"TRule_id_or_at","rule":"TRule_id_or_at.Block1","sum":4799824},{"parent":"TRule_id_or_at","rule":"TRule_id_or_at.Rule_an_id_or_type2","sum":133959216},{"parent":"TRule_id_or_at.TBlock1","rule":"TRule_id_or_at.TBlock1.Token1","sum":4799824},{"parent":"TRule_id_or_type","rule":"TRule_id_or_type.Alt_id_or_type1","sum":10580056071},{"parent":"TRule_id_or_type","rule":"TRule_id_or_type.Alt_id_or_type2","sum":11723733},{"parent":"TRule_id_or_type.TAlt1","rule":"TRule_id_or_type.TAlt1.Rule_id1","sum":10580056071},{"parent":"TRule_id_or_type.TAlt2","rule":"TRule_id_or_type.TAlt2.Rule_type_id1","sum":11723733},{"parent":"TRule_id_schema","rule":"TRule_id_schema.Alt_id_schema1","sum":1148},{"parent":"TRule_id_schema","rule":"TRule_id_schema.Alt_id_schema2","sum":12},{"parent":"TRule_id_schema.TAlt1","rule":"TRule_id_schema.TAlt1.Rule_identifier1","sum":1148},{"parent":"TRule_id_schema.TAlt2","rule":"TRule_id_schema.TAlt2.Rule_keyword_compat1","sum":12},{"parent":"TRule_id_table","rule":"TRule_id_table.Alt_id_table1","sum":330592812},{"parent":"TRule_id_table","rule":"TRule_id_table.Alt_id_table2","sum":654441},{"parent":"TRule_id_table","rule":"TRule_id_table.Alt_id_table3","sum":365},{"parent":"TRule_id_table","rule":"TRule_id_table.Alt_id_table4","sum":12473},{"parent":"TRule_id_table","rule":"TRule_id_table.Alt_id_table5","sum":4},{"parent":"TRule_id_table","rule":"TRule_id_table.Alt_id_table6","sum":1838},{"parent":"TRule_id_table","rule":"TRule_id_table.Alt_id_table7","sum":10},{"parent":"TRule_id_table.TAlt1","rule":"TRule_id_table.TAlt1.Rule_identifier1","sum":330592812},{"parent":"TRule_id_table.TAlt2","rule":"TRule_id_table.TAlt2.Rule_keyword_compat1","sum":654441},{"parent":"TRule_id_table.TAlt3","rule":"TRule_id_table.TAlt3.Rule_keyword_expr_uncompat1","sum":365},{"parent":"TRule_id_table.TAlt4","rule":"TRule_id_table.TAlt4.Rule_keyword_select_uncompat1","sum":12473},{"parent":"TRule_id_table.TAlt5","rule":"TRule_id_table.TAlt5.Rule_keyword_in_uncompat1","sum":4},{"parent":"TRule_id_table.TAlt6","rule":"TRule_id_table.TAlt6.Rule_keyword_window_uncompat1","sum":1838},{"parent":"TRule_id_table.TAlt7","rule":"TRule_id_table.TAlt7.Rule_keyword_hint_uncompat1","sum":10},{"parent":"TRule_id_table_or_type","rule":"TRule_id_table_or_type.Alt_id_table_or_type1","sum":331261944},{"parent":"TRule_id_table_or_type","rule":"TRule_id_table_or_type.Alt_id_table_or_type2","sum":4190},{"parent":"TRule_id_table_or_type.TAlt1","rule":"TRule_id_table_or_type.TAlt1.Rule_an_id_table1","sum":331261944},{"parent":"TRule_id_table_or_type.TAlt2","rule":"TRule_id_table_or_type.TAlt2.Rule_type_id1","sum":4190},{"parent":"TRule_id_window","rule":"TRule_id_window.Alt_id_window1","sum":46523701},{"parent":"TRule_id_window","rule":"TRule_id_window.Alt_id_window2","sum":15783},{"parent":"TRule_id_window","rule":"TRule_id_window.Alt_id_window3","sum":247560},{"parent":"TRule_id_window","rule":"TRule_id_window.Alt_id_window5","sum":7859},{"parent":"TRule_id_window.TAlt1","rule":"TRule_id_window.TAlt1.Rule_identifier1","sum":46523701},{"parent":"TRule_id_window.TAlt2","rule":"TRule_id_window.TAlt2.Rule_keyword_compat1","sum":15783},{"parent":"TRule_id_window.TAlt3","rule":"TRule_id_window.TAlt3.Rule_keyword_expr_uncompat1","sum":247560},{"parent":"TRule_id_window.TAlt5","rule":"TRule_id_window.TAlt5.Rule_keyword_select_uncompat1","sum":7859},{"parent":"TRule_id_without","rule":"TRule_id_without.Alt_id_without1","sum":23143060},{"parent":"TRule_id_without","rule":"TRule_id_without.Alt_id_without2","sum":278042},{"parent":"TRule_id_without","rule":"TRule_id_without.Alt_id_without6","sum":1135},{"parent":"TRule_id_without","rule":"TRule_id_without.Alt_id_without7","sum":527},{"parent":"TRule_id_without.TAlt1","rule":"TRule_id_without.TAlt1.Rule_identifier1","sum":23143060},{"parent":"TRule_id_without.TAlt2","rule":"TRule_id_without.TAlt2.Rule_keyword_compat1","sum":278042},{"parent":"TRule_id_without.TAlt6","rule":"TRule_id_without.TAlt6.Rule_keyword_window_uncompat1","sum":1135},{"parent":"TRule_id_without.TAlt7","rule":"TRule_id_without.TAlt7.Rule_keyword_hint_uncompat1","sum":527},{"parent":"TRule_identifier","rule":"TRule_identifier.Token1","sum":20341456710},{"parent":"TRule_if_stmt","rule":"TRule_if_stmt.Block1","sum":8585409},{"parent":"TRule_if_stmt","rule":"TRule_if_stmt.Block5","sum":2984759},{"parent":"TRule_if_stmt","rule":"TRule_if_stmt.Rule_do_stmt4","sum":8585453},{"parent":"TRule_if_stmt","rule":"TRule_if_stmt.Rule_expr3","sum":8585453},{"parent":"TRule_if_stmt","rule":"TRule_if_stmt.Token2","sum":8585453},{"parent":"TRule_if_stmt.TBlock1","rule":"TRule_if_stmt.TBlock1.Token1","sum":8585409},{"parent":"TRule_if_stmt.TBlock5","rule":"TRule_if_stmt.TBlock5.Rule_do_stmt2","sum":2984759},{"parent":"TRule_if_stmt.TBlock5","rule":"TRule_if_stmt.TBlock5.Token1","sum":2984759},{"parent":"TRule_import_stmt","rule":"TRule_import_stmt.Rule_module_path2","sum":16683079},{"parent":"TRule_import_stmt","rule":"TRule_import_stmt.Rule_named_bind_parameter_list4","sum":16683079},{"parent":"TRule_import_stmt","rule":"TRule_import_stmt.Token1","sum":16683079},{"parent":"TRule_import_stmt","rule":"TRule_import_stmt.Token3","sum":16683079},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr1","sum":2234},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr10","sum":5136597},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr11","sum":454625},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr2","sum":36512023},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr3","sum":65607797},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr4","sum":44293},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr5","sum":4},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr6","sum":2976915},{"parent":"TRule_in_atom_expr","rule":"TRule_in_atom_expr.Alt_in_atom_expr7","sum":9793228},{"parent":"TRule_in_atom_expr.TAlt1","rule":"TRule_in_atom_expr.TAlt1.Rule_literal_value1","sum":2234},{"parent":"TRule_in_atom_expr.TAlt10","rule":"TRule_in_atom_expr.TAlt10.Rule_list_literal1","sum":5136597},{"parent":"TRule_in_atom_expr.TAlt11","rule":"TRule_in_atom_expr.TAlt11.Rule_dict_literal1","sum":454625},{"parent":"TRule_in_atom_expr.TAlt2","rule":"TRule_in_atom_expr.TAlt2.Rule_bind_parameter1","sum":36512023},{"parent":"TRule_in_atom_expr.TAlt3","rule":"TRule_in_atom_expr.TAlt3.Rule_lambda1","sum":65607797},{"parent":"TRule_in_atom_expr.TAlt4","rule":"TRule_in_atom_expr.TAlt4.Rule_cast_expr1","sum":44293},{"parent":"TRule_in_atom_expr.TAlt5","rule":"TRule_in_atom_expr.TAlt5.Rule_case_expr1","sum":4},{"parent":"TRule_in_atom_expr.TAlt6","rule":"TRule_in_atom_expr.TAlt6.Block3","sum":2976915},{"parent":"TRule_in_atom_expr.TAlt6","rule":"TRule_in_atom_expr.TAlt6.Rule_an_id_or_type1","sum":2976915},{"parent":"TRule_in_atom_expr.TAlt6","rule":"TRule_in_atom_expr.TAlt6.Token2","sum":2976915},{"parent":"TRule_in_atom_expr.TAlt6.TBlock3","rule":"TRule_in_atom_expr.TAlt6.TBlock3.Alt1","sum":2976915},{"parent":"TRule_in_atom_expr.TAlt6.TBlock3.TAlt1","rule":"TRule_in_atom_expr.TAlt6.TBlock3.TAlt1.Rule_id_or_type1","sum":2976915},{"parent":"TRule_in_atom_expr.TAlt7","rule":"TRule_in_atom_expr.TAlt7.Rule_select_stmt2","sum":9793228},{"parent":"TRule_in_atom_expr.TAlt7","rule":"TRule_in_atom_expr.TAlt7.Token1","sum":9793228},{"parent":"TRule_in_atom_expr.TAlt7","rule":"TRule_in_atom_expr.TAlt7.Token3","sum":9793228},{"parent":"TRule_in_expr","rule":"TRule_in_expr.Rule_in_unary_subexpr1","sum":126255554},{"parent":"TRule_in_unary_casual_subexpr","rule":"TRule_in_unary_casual_subexpr.Block1","sum":126255502},{"parent":"TRule_in_unary_casual_subexpr","rule":"TRule_in_unary_casual_subexpr.Rule_unary_subexpr_suffix2","sum":126255502},{"parent":"TRule_in_unary_casual_subexpr.TBlock1","rule":"TRule_in_unary_casual_subexpr.TBlock1.Alt1","sum":5727786},{"parent":"TRule_in_unary_casual_subexpr.TBlock1","rule":"TRule_in_unary_casual_subexpr.TBlock1.Alt2","sum":120527716},{"parent":"TRule_in_unary_casual_subexpr.TBlock1.TAlt1","rule":"TRule_in_unary_casual_subexpr.TBlock1.TAlt1.Rule_id_expr_in1","sum":5727786},{"parent":"TRule_in_unary_casual_subexpr.TBlock1.TAlt2","rule":"TRule_in_unary_casual_subexpr.TBlock1.TAlt2.Rule_in_atom_expr1","sum":120527716},{"parent":"TRule_in_unary_subexpr","rule":"TRule_in_unary_subexpr.Alt_in_unary_subexpr1","sum":126255502},{"parent":"TRule_in_unary_subexpr","rule":"TRule_in_unary_subexpr.Alt_in_unary_subexpr2","sum":52},{"parent":"TRule_in_unary_subexpr.TAlt1","rule":"TRule_in_unary_subexpr.TAlt1.Rule_in_unary_casual_subexpr1","sum":126255502},{"parent":"TRule_in_unary_subexpr.TAlt2","rule":"TRule_in_unary_subexpr.TAlt2.Rule_json_api_expr1","sum":52},{"parent":"TRule_inline_action","rule":"TRule_inline_action.Rule_define_action_or_subquery_body2","sum":13916092},{"parent":"TRule_inline_action","rule":"TRule_inline_action.Token1","sum":13916092},{"parent":"TRule_inline_action","rule":"TRule_inline_action.Token3","sum":13916092},{"parent":"TRule_inline_action","rule":"TRule_inline_action.Token4","sum":13916092},{"parent":"TRule_integer","rule":"TRule_integer.Token1","sum":2790874162},{"parent":"TRule_integer_or_bind","rule":"TRule_integer_or_bind.Alt_integer_or_bind1","sum":55447575},{"parent":"TRule_integer_or_bind","rule":"TRule_integer_or_bind.Alt_integer_or_bind2","sum":48703},{"parent":"TRule_integer_or_bind.TAlt1","rule":"TRule_integer_or_bind.TAlt1.Rule_integer1","sum":55447575},{"parent":"TRule_integer_or_bind.TAlt2","rule":"TRule_integer_or_bind.TAlt2.Rule_bind_parameter1","sum":48703},{"parent":"TRule_into_simple_table_ref","rule":"TRule_into_simple_table_ref.Block2","sum":25526},{"parent":"TRule_into_simple_table_ref","rule":"TRule_into_simple_table_ref.Rule_simple_table_ref1","sum":209729253},{"parent":"TRule_into_simple_table_ref.TBlock2","rule":"TRule_into_simple_table_ref.TBlock2.Rule_pure_column_list3","sum":25526},{"parent":"TRule_into_simple_table_ref.TBlock2","rule":"TRule_into_simple_table_ref.TBlock2.Token1","sum":25526},{"parent":"TRule_into_simple_table_ref.TBlock2","rule":"TRule_into_simple_table_ref.TBlock2.Token2","sum":25526},{"parent":"TRule_into_table_stmt","rule":"TRule_into_table_stmt.Block1","sum":209729253},{"parent":"TRule_into_table_stmt","rule":"TRule_into_table_stmt.Rule_into_simple_table_ref3","sum":209729253},{"parent":"TRule_into_table_stmt","rule":"TRule_into_table_stmt.Rule_into_values_source4","sum":209729253},{"parent":"TRule_into_table_stmt","rule":"TRule_into_table_stmt.Token2","sum":209729253},{"parent":"TRule_into_table_stmt.TBlock1","rule":"TRule_into_table_stmt.TBlock1.Alt1","sum":209619187},{"parent":"TRule_into_table_stmt.TBlock1","rule":"TRule_into_table_stmt.TBlock1.Alt5","sum":110065},{"parent":"TRule_into_table_stmt.TBlock1","rule":"TRule_into_table_stmt.TBlock1.Alt6","sum":1},{"parent":"TRule_into_table_stmt.TBlock1.TAlt1","rule":"TRule_into_table_stmt.TBlock1.TAlt1.Token1","sum":209619187},{"parent":"TRule_into_table_stmt.TBlock1.TAlt5","rule":"TRule_into_table_stmt.TBlock1.TAlt5.Token1","sum":110065},{"parent":"TRule_into_table_stmt.TBlock1.TAlt6","rule":"TRule_into_table_stmt.TBlock1.TAlt6.Token1","sum":1},{"parent":"TRule_into_values_source","rule":"TRule_into_values_source.Alt_into_values_source1","sum":209729253},{"parent":"TRule_into_values_source.TAlt1","rule":"TRule_into_values_source.TAlt1.Block1","sum":4547156},{"parent":"TRule_into_values_source.TAlt1","rule":"TRule_into_values_source.TAlt1.Rule_values_source2","sum":209729253},{"parent":"TRule_into_values_source.TAlt1.TBlock1","rule":"TRule_into_values_source.TAlt1.TBlock1.Rule_pure_column_list1","sum":4547156},{"parent":"TRule_invoke_expr","rule":"TRule_invoke_expr.Block2","sum":2772691048},{"parent":"TRule_invoke_expr","rule":"TRule_invoke_expr.Rule_invoke_expr_tail4","sum":2887374802},{"parent":"TRule_invoke_expr","rule":"TRule_invoke_expr.Token1","sum":2887374802},{"parent":"TRule_invoke_expr","rule":"TRule_invoke_expr.Token3","sum":2887374802},{"parent":"TRule_invoke_expr.TBlock2","rule":"TRule_invoke_expr.TBlock2.Alt1","sum":2713595432},{"parent":"TRule_invoke_expr.TBlock2","rule":"TRule_invoke_expr.TBlock2.Alt2","sum":59095616},{"parent":"TRule_invoke_expr.TBlock2.TAlt1","rule":"TRule_invoke_expr.TBlock2.TAlt1.Block3","sum":9708052},{"parent":"TRule_invoke_expr.TBlock2.TAlt1","rule":"TRule_invoke_expr.TBlock2.TAlt1.Rule_named_expr_list2","sum":2713595432},{"parent":"TRule_invoke_expr.TBlock2.TAlt1","rule":"TRule_invoke_expr.TBlock2.TAlt1.Rule_opt_set_quantifier1","sum":2713595432},{"parent":"TRule_invoke_expr.TBlock2.TAlt1.TBlock3","rule":"TRule_invoke_expr.TBlock2.TAlt1.TBlock3.Token1","sum":9708052},{"parent":"TRule_invoke_expr.TBlock2.TAlt2","rule":"TRule_invoke_expr.TBlock2.TAlt2.Token1","sum":59095616},{"parent":"TRule_invoke_expr_tail","rule":"TRule_invoke_expr_tail.Block1","sum":7293225},{"parent":"TRule_invoke_expr_tail","rule":"TRule_invoke_expr_tail.Block2","sum":45477385},{"parent":"TRule_invoke_expr_tail.TBlock1","rule":"TRule_invoke_expr_tail.TBlock1.Alt1","sum":7293225},{"parent":"TRule_invoke_expr_tail.TBlock1.TAlt1","rule":"TRule_invoke_expr_tail.TBlock1.TAlt1.Rule_null_treatment1","sum":7293225},{"parent":"TRule_invoke_expr_tail.TBlock2","rule":"TRule_invoke_expr_tail.TBlock2.Rule_window_name_or_specification2","sum":45477385},{"parent":"TRule_invoke_expr_tail.TBlock2","rule":"TRule_invoke_expr_tail.TBlock2.Token1","sum":45477385},{"parent":"TRule_join_constraint","rule":"TRule_join_constraint.Alt_join_constraint1","sum":173497169},{"parent":"TRule_join_constraint","rule":"TRule_join_constraint.Alt_join_constraint2","sum":32540623},{"parent":"TRule_join_constraint.TAlt1","rule":"TRule_join_constraint.TAlt1.Rule_expr2","sum":173497169},{"parent":"TRule_join_constraint.TAlt1","rule":"TRule_join_constraint.TAlt1.Token1","sum":173497169},{"parent":"TRule_join_constraint.TAlt2","rule":"TRule_join_constraint.TAlt2.Rule_pure_column_or_named_list2","sum":32540623},{"parent":"TRule_join_constraint.TAlt2","rule":"TRule_join_constraint.TAlt2.Token1","sum":32540623},{"parent":"TRule_join_op","rule":"TRule_join_op.Alt_join_op1","sum":28765},{"parent":"TRule_join_op","rule":"TRule_join_op.Alt_join_op2","sum":209109240},{"parent":"TRule_join_op.TAlt1","rule":"TRule_join_op.TAlt1.Token1","sum":28765},{"parent":"TRule_join_op.TAlt2","rule":"TRule_join_op.TAlt2.Block2","sum":209109240},{"parent":"TRule_join_op.TAlt2","rule":"TRule_join_op.TAlt2.Token3","sum":209109240},{"parent":"TRule_join_op.TAlt2.TBlock2","rule":"TRule_join_op.TAlt2.TBlock2.Alt1","sum":175229648},{"parent":"TRule_join_op.TAlt2.TBlock2","rule":"TRule_join_op.TAlt2.TBlock2.Alt2","sum":30808144},{"parent":"TRule_join_op.TAlt2.TBlock2","rule":"TRule_join_op.TAlt2.TBlock2.Alt3","sum":3071448},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.Block1","sum":127077276},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.Block2","sum":295958},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.Alt1","sum":119139880},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.Alt2","sum":1700064},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.Alt3","sum":285919},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.Alt4","sum":5951413},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt1.Block2","sum":19730652},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt1","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt1.Token1","sum":119139880},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt1.TBlock2","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt1.TBlock2.Token1","sum":19730652},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt2","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt2.Block2","sum":519930},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt2","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt2.Token1","sum":1700064},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt2.TBlock2","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt2.TBlock2.Token1","sum":519930},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt3","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt3.Token1","sum":285919},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt4","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock1.TAlt4.Token1","sum":5951413},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock2","rule":"TRule_join_op.TAlt2.TBlock2.TAlt1.TBlock2.Token1","sum":295958},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt2","rule":"TRule_join_op.TAlt2.TBlock2.TAlt2.Token1","sum":30808144},{"parent":"TRule_join_op.TAlt2.TBlock2.TAlt3","rule":"TRule_join_op.TAlt2.TBlock2.TAlt3.Token1","sum":3071448},{"parent":"TRule_join_source","rule":"TRule_join_source.Block1","sum":625518},{"parent":"TRule_join_source","rule":"TRule_join_source.Block3","sum":145768895},{"parent":"TRule_join_source","rule":"TRule_join_source.Rule_flatten_source2","sum":846229398},{"parent":"TRule_join_source.TBlock1","rule":"TRule_join_source.TBlock1.Token1","sum":625518},{"parent":"TRule_join_source.TBlock3","rule":"TRule_join_source.TBlock3.Block2","sum":14080518},{"parent":"TRule_join_source.TBlock3","rule":"TRule_join_source.TBlock3.Block4","sum":206037792},{"parent":"TRule_join_source.TBlock3","rule":"TRule_join_source.TBlock3.Rule_flatten_source3","sum":209138005},{"parent":"TRule_join_source.TBlock3","rule":"TRule_join_source.TBlock3.Rule_join_op1","sum":209138005},{"parent":"TRule_join_source.TBlock3.TBlock2","rule":"TRule_join_source.TBlock3.TBlock2.Token1","sum":14080518},{"parent":"TRule_join_source.TBlock3.TBlock4","rule":"TRule_join_source.TBlock3.TBlock4.Rule_join_constraint1","sum":206037792},{"parent":"TRule_json_api_expr","rule":"TRule_json_api_expr.Alt_json_api_expr1","sum":5833983},{"parent":"TRule_json_api_expr","rule":"TRule_json_api_expr.Alt_json_api_expr2","sum":184354},{"parent":"TRule_json_api_expr","rule":"TRule_json_api_expr.Alt_json_api_expr3","sum":316587},{"parent":"TRule_json_api_expr.TAlt1","rule":"TRule_json_api_expr.TAlt1.Rule_json_value1","sum":5833983},{"parent":"TRule_json_api_expr.TAlt2","rule":"TRule_json_api_expr.TAlt2.Rule_json_exists1","sum":184354},{"parent":"TRule_json_api_expr.TAlt3","rule":"TRule_json_api_expr.TAlt3.Rule_json_query1","sum":316587},{"parent":"TRule_json_case_handler","rule":"TRule_json_case_handler.Alt_json_case_handler1","sum":7134},{"parent":"TRule_json_case_handler","rule":"TRule_json_case_handler.Alt_json_case_handler2","sum":14319},{"parent":"TRule_json_case_handler","rule":"TRule_json_case_handler.Alt_json_case_handler3","sum":200472},{"parent":"TRule_json_case_handler.TAlt1","rule":"TRule_json_case_handler.TAlt1.Token1","sum":7134},{"parent":"TRule_json_case_handler.TAlt2","rule":"TRule_json_case_handler.TAlt2.Token1","sum":14319},{"parent":"TRule_json_case_handler.TAlt3","rule":"TRule_json_case_handler.TAlt3.Rule_expr2","sum":200472},{"parent":"TRule_json_case_handler.TAlt3","rule":"TRule_json_case_handler.TAlt3.Token1","sum":200472},{"parent":"TRule_json_common_args","rule":"TRule_json_common_args.Block4","sum":20022},{"parent":"TRule_json_common_args","rule":"TRule_json_common_args.Rule_expr1","sum":6334924},{"parent":"TRule_json_common_args","rule":"TRule_json_common_args.Rule_jsonpath_spec3","sum":6334924},{"parent":"TRule_json_common_args","rule":"TRule_json_common_args.Token2","sum":6334924},{"parent":"TRule_json_common_args.TBlock4","rule":"TRule_json_common_args.TBlock4.Rule_json_variables2","sum":20022},{"parent":"TRule_json_common_args.TBlock4","rule":"TRule_json_common_args.TBlock4.Token1","sum":20022},{"parent":"TRule_json_exists","rule":"TRule_json_exists.Block4","sum":116},{"parent":"TRule_json_exists","rule":"TRule_json_exists.Rule_json_common_args3","sum":184354},{"parent":"TRule_json_exists","rule":"TRule_json_exists.Token1","sum":184354},{"parent":"TRule_json_exists","rule":"TRule_json_exists.Token2","sum":184354},{"parent":"TRule_json_exists","rule":"TRule_json_exists.Token5","sum":184354},{"parent":"TRule_json_exists.TBlock4","rule":"TRule_json_exists.TBlock4.Rule_json_exists_handler1","sum":116},{"parent":"TRule_json_exists_handler","rule":"TRule_json_exists_handler.Token1","sum":116},{"parent":"TRule_json_exists_handler","rule":"TRule_json_exists_handler.Token2","sum":116},{"parent":"TRule_json_exists_handler","rule":"TRule_json_exists_handler.Token3","sum":116},{"parent":"TRule_json_query","rule":"TRule_json_query.Block4","sum":191123},{"parent":"TRule_json_query","rule":"TRule_json_query.Block5","sum":86},{"parent":"TRule_json_query","rule":"TRule_json_query.Block6","sum":4123},{"parent":"TRule_json_query","rule":"TRule_json_query.Rule_json_common_args3","sum":316587},{"parent":"TRule_json_query","rule":"TRule_json_query.Token1","sum":316587},{"parent":"TRule_json_query","rule":"TRule_json_query.Token2","sum":316587},{"parent":"TRule_json_query","rule":"TRule_json_query.Token7","sum":316587},{"parent":"TRule_json_query.TBlock4","rule":"TRule_json_query.TBlock4.Rule_json_query_wrapper1","sum":191123},{"parent":"TRule_json_query.TBlock4","rule":"TRule_json_query.TBlock4.Token2","sum":191123},{"parent":"TRule_json_query.TBlock5","rule":"TRule_json_query.TBlock5.Rule_json_query_handler1","sum":86},{"parent":"TRule_json_query.TBlock5","rule":"TRule_json_query.TBlock5.Token2","sum":86},{"parent":"TRule_json_query.TBlock5","rule":"TRule_json_query.TBlock5.Token3","sum":86},{"parent":"TRule_json_query.TBlock6","rule":"TRule_json_query.TBlock6.Rule_json_query_handler1","sum":4123},{"parent":"TRule_json_query.TBlock6","rule":"TRule_json_query.TBlock6.Token2","sum":4123},{"parent":"TRule_json_query.TBlock6","rule":"TRule_json_query.TBlock6.Token3","sum":4123},{"parent":"TRule_json_query_handler","rule":"TRule_json_query_handler.Alt_json_query_handler1","sum":1675},{"parent":"TRule_json_query_handler","rule":"TRule_json_query_handler.Alt_json_query_handler2","sum":26},{"parent":"TRule_json_query_handler","rule":"TRule_json_query_handler.Alt_json_query_handler3","sum":2289},{"parent":"TRule_json_query_handler","rule":"TRule_json_query_handler.Alt_json_query_handler4","sum":219},{"parent":"TRule_json_query_handler.TAlt1","rule":"TRule_json_query_handler.TAlt1.Token1","sum":1675},{"parent":"TRule_json_query_handler.TAlt2","rule":"TRule_json_query_handler.TAlt2.Token1","sum":26},{"parent":"TRule_json_query_handler.TAlt3","rule":"TRule_json_query_handler.TAlt3.Token1","sum":2289},{"parent":"TRule_json_query_handler.TAlt3","rule":"TRule_json_query_handler.TAlt3.Token2","sum":2289},{"parent":"TRule_json_query_handler.TAlt4","rule":"TRule_json_query_handler.TAlt4.Token1","sum":219},{"parent":"TRule_json_query_handler.TAlt4","rule":"TRule_json_query_handler.TAlt4.Token2","sum":219},{"parent":"TRule_json_query_wrapper","rule":"TRule_json_query_wrapper.Alt_json_query_wrapper1","sum":45},{"parent":"TRule_json_query_wrapper","rule":"TRule_json_query_wrapper.Alt_json_query_wrapper2","sum":191078},{"parent":"TRule_json_query_wrapper.TAlt1","rule":"TRule_json_query_wrapper.TAlt1.Block2","sum":10},{"parent":"TRule_json_query_wrapper.TAlt1","rule":"TRule_json_query_wrapper.TAlt1.Token1","sum":45},{"parent":"TRule_json_query_wrapper.TAlt1.TBlock2","rule":"TRule_json_query_wrapper.TAlt1.TBlock2.Token1","sum":10},{"parent":"TRule_json_query_wrapper.TAlt2","rule":"TRule_json_query_wrapper.TAlt2.Block2","sum":166591},{"parent":"TRule_json_query_wrapper.TAlt2","rule":"TRule_json_query_wrapper.TAlt2.Block3","sum":32430},{"parent":"TRule_json_query_wrapper.TAlt2","rule":"TRule_json_query_wrapper.TAlt2.Token1","sum":191078},{"parent":"TRule_json_query_wrapper.TAlt2.TBlock2","rule":"TRule_json_query_wrapper.TAlt2.TBlock2.Token1","sum":166591},{"parent":"TRule_json_query_wrapper.TAlt2.TBlock3","rule":"TRule_json_query_wrapper.TAlt2.TBlock3.Token1","sum":32430},{"parent":"TRule_json_value","rule":"TRule_json_value.Block4","sum":1331547},{"parent":"TRule_json_value","rule":"TRule_json_value.Block5","sum":202436},{"parent":"TRule_json_value","rule":"TRule_json_value.Rule_json_common_args3","sum":5833983},{"parent":"TRule_json_value","rule":"TRule_json_value.Token1","sum":5833983},{"parent":"TRule_json_value","rule":"TRule_json_value.Token2","sum":5833983},{"parent":"TRule_json_value","rule":"TRule_json_value.Token6","sum":5833983},{"parent":"TRule_json_value.TBlock4","rule":"TRule_json_value.TBlock4.Rule_type_name_simple2","sum":1331547},{"parent":"TRule_json_value.TBlock4","rule":"TRule_json_value.TBlock4.Token1","sum":1331547},{"parent":"TRule_json_value.TBlock5","rule":"TRule_json_value.TBlock5.Rule_json_case_handler1","sum":221925},{"parent":"TRule_json_value.TBlock5","rule":"TRule_json_value.TBlock5.Token2","sum":221925},{"parent":"TRule_json_value.TBlock5","rule":"TRule_json_value.TBlock5.Token3","sum":221925},{"parent":"TRule_json_variable","rule":"TRule_json_variable.Rule_expr1","sum":20029},{"parent":"TRule_json_variable","rule":"TRule_json_variable.Rule_json_variable_name3","sum":20029},{"parent":"TRule_json_variable","rule":"TRule_json_variable.Token2","sum":20029},{"parent":"TRule_json_variable_name","rule":"TRule_json_variable_name.Alt_json_variable_name1","sum":17733},{"parent":"TRule_json_variable_name","rule":"TRule_json_variable_name.Alt_json_variable_name2","sum":2296},{"parent":"TRule_json_variable_name.TAlt1","rule":"TRule_json_variable_name.TAlt1.Rule_id_expr1","sum":17733},{"parent":"TRule_json_variable_name.TAlt2","rule":"TRule_json_variable_name.TAlt2.Token1","sum":2296},{"parent":"TRule_json_variables","rule":"TRule_json_variables.Block2","sum":7},{"parent":"TRule_json_variables","rule":"TRule_json_variables.Rule_json_variable1","sum":20022},{"parent":"TRule_json_variables.TBlock2","rule":"TRule_json_variables.TBlock2.Rule_json_variable2","sum":7},{"parent":"TRule_json_variables.TBlock2","rule":"TRule_json_variables.TBlock2.Token1","sum":7},{"parent":"TRule_jsonpath_spec","rule":"TRule_jsonpath_spec.Token1","sum":6334924},{"parent":"TRule_key_expr","rule":"TRule_key_expr.Rule_expr2","sum":174308643},{"parent":"TRule_key_expr","rule":"TRule_key_expr.Token1","sum":174308643},{"parent":"TRule_key_expr","rule":"TRule_key_expr.Token3","sum":174308643},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword1","sum":482428535},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword2","sum":33736185},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword3","sum":520570},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword4","sum":9123289},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword5","sum":781531},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword6","sum":23587},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword7","sum":3908877},{"parent":"TRule_keyword","rule":"TRule_keyword.Alt_keyword8","sum":2527973},{"parent":"TRule_keyword.TAlt1","rule":"TRule_keyword.TAlt1.Rule_keyword_compat1","sum":482428535},{"parent":"TRule_keyword.TAlt2","rule":"TRule_keyword.TAlt2.Rule_keyword_expr_uncompat1","sum":33736185},{"parent":"TRule_keyword.TAlt3","rule":"TRule_keyword.TAlt3.Rule_keyword_table_uncompat1","sum":520570},{"parent":"TRule_keyword.TAlt4","rule":"TRule_keyword.TAlt4.Rule_keyword_select_uncompat1","sum":9123289},{"parent":"TRule_keyword.TAlt5","rule":"TRule_keyword.TAlt5.Rule_keyword_alter_uncompat1","sum":781531},{"parent":"TRule_keyword.TAlt6","rule":"TRule_keyword.TAlt6.Rule_keyword_in_uncompat1","sum":23587},{"parent":"TRule_keyword.TAlt7","rule":"TRule_keyword.TAlt7.Rule_keyword_window_uncompat1","sum":3908877},{"parent":"TRule_keyword.TAlt8","rule":"TRule_keyword.TAlt8.Rule_keyword_hint_uncompat1","sum":2527973},{"parent":"TRule_keyword_alter_uncompat","rule":"TRule_keyword_alter_uncompat.Token1","sum":1199069},{"parent":"TRule_keyword_as_compat","rule":"TRule_keyword_as_compat.Token1","sum":2690},{"parent":"TRule_keyword_compat","rule":"TRule_keyword_compat.Token1","sum":804310489},{"parent":"TRule_keyword_expr_uncompat","rule":"TRule_keyword_expr_uncompat.Token1","sum":34008279},{"parent":"TRule_keyword_hint_uncompat","rule":"TRule_keyword_hint_uncompat.Token1","sum":2710023},{"parent":"TRule_keyword_in_uncompat","rule":"TRule_keyword_in_uncompat.Token1","sum":23591},{"parent":"TRule_keyword_select_uncompat","rule":"TRule_keyword_select_uncompat.Token1","sum":9143621},{"parent":"TRule_keyword_table_uncompat","rule":"TRule_keyword_table_uncompat.Token1","sum":520570},{"parent":"TRule_keyword_window_uncompat","rule":"TRule_keyword_window_uncompat.Token1","sum":39150305},{"parent":"TRule_lambda","rule":"TRule_lambda.Block2","sum":209437719},{"parent":"TRule_lambda","rule":"TRule_lambda.Rule_smart_parenthesis1","sum":513744527},{"parent":"TRule_lambda.TBlock2","rule":"TRule_lambda.TBlock2.Block2","sum":209437719},{"parent":"TRule_lambda.TBlock2","rule":"TRule_lambda.TBlock2.Token1","sum":209437719},{"parent":"TRule_lambda.TBlock2.TBlock2","rule":"TRule_lambda.TBlock2.TBlock2.Alt1","sum":42716613},{"parent":"TRule_lambda.TBlock2.TBlock2","rule":"TRule_lambda.TBlock2.TBlock2.Alt2","sum":166721106},{"parent":"TRule_lambda.TBlock2.TBlock2.TAlt1","rule":"TRule_lambda.TBlock2.TBlock2.TAlt1.Rule_expr2","sum":42716613},{"parent":"TRule_lambda.TBlock2.TBlock2.TAlt1","rule":"TRule_lambda.TBlock2.TBlock2.TAlt1.Token1","sum":42716613},{"parent":"TRule_lambda.TBlock2.TBlock2.TAlt1","rule":"TRule_lambda.TBlock2.TBlock2.TAlt1.Token3","sum":42716613},{"parent":"TRule_lambda.TBlock2.TBlock2.TAlt2","rule":"TRule_lambda.TBlock2.TBlock2.TAlt2.Rule_lambda_body2","sum":166721106},{"parent":"TRule_lambda.TBlock2.TBlock2.TAlt2","rule":"TRule_lambda.TBlock2.TBlock2.TAlt2.Token1","sum":166721106},{"parent":"TRule_lambda.TBlock2.TBlock2.TAlt2","rule":"TRule_lambda.TBlock2.TBlock2.TAlt2.Token3","sum":166721106},{"parent":"TRule_lambda_body","rule":"TRule_lambda_body.Block1","sum":158},{"parent":"TRule_lambda_body","rule":"TRule_lambda_body.Block2","sum":34886821},{"parent":"TRule_lambda_body","rule":"TRule_lambda_body.Block5","sum":87884482},{"parent":"TRule_lambda_body","rule":"TRule_lambda_body.Rule_expr4","sum":166721106},{"parent":"TRule_lambda_body","rule":"TRule_lambda_body.Token3","sum":166721106},{"parent":"TRule_lambda_body.TBlock1","rule":"TRule_lambda_body.TBlock1.Token1","sum":158},{"parent":"TRule_lambda_body.TBlock2","rule":"TRule_lambda_body.TBlock2.Block2","sum":63980565},{"parent":"TRule_lambda_body.TBlock2","rule":"TRule_lambda_body.TBlock2.Rule_lambda_stmt1","sum":63980565},{"parent":"TRule_lambda_body.TBlock2.TBlock2","rule":"TRule_lambda_body.TBlock2.TBlock2.Token1","sum":63981788},{"parent":"TRule_lambda_body.TBlock5","rule":"TRule_lambda_body.TBlock5.Token1","sum":87892837},{"parent":"TRule_lambda_stmt","rule":"TRule_lambda_stmt.Alt_lambda_stmt1","sum":63977894},{"parent":"TRule_lambda_stmt","rule":"TRule_lambda_stmt.Alt_lambda_stmt2","sum":2671},{"parent":"TRule_lambda_stmt.TAlt1","rule":"TRule_lambda_stmt.TAlt1.Rule_named_nodes_stmt1","sum":63977894},{"parent":"TRule_lambda_stmt.TAlt2","rule":"TRule_lambda_stmt.TAlt2.Rule_import_stmt1","sum":2671},{"parent":"TRule_list_literal","rule":"TRule_list_literal.Block2","sum":35495407},{"parent":"TRule_list_literal","rule":"TRule_list_literal.Block3","sum":2318102},{"parent":"TRule_list_literal","rule":"TRule_list_literal.Token1","sum":41296835},{"parent":"TRule_list_literal","rule":"TRule_list_literal.Token4","sum":41296835},{"parent":"TRule_list_literal.TBlock2","rule":"TRule_list_literal.TBlock2.Rule_expr_list1","sum":35495407},{"parent":"TRule_list_literal.TBlock3","rule":"TRule_list_literal.TBlock3.Token1","sum":2318102},{"parent":"TRule_literal_value","rule":"TRule_literal_value.Alt_literal_value1","sum":2735426586},{"parent":"TRule_literal_value","rule":"TRule_literal_value.Alt_literal_value10","sum":2},{"parent":"TRule_literal_value","rule":"TRule_literal_value.Alt_literal_value2","sum":109366652},{"parent":"TRule_literal_value","rule":"TRule_literal_value.Alt_literal_value3","sum":2128186998},{"parent":"TRule_literal_value","rule":"TRule_literal_value.Alt_literal_value5","sum":79765448},{"parent":"TRule_literal_value","rule":"TRule_literal_value.Alt_literal_value9","sum":104618486},{"parent":"TRule_literal_value.TAlt1","rule":"TRule_literal_value.TAlt1.Rule_integer1","sum":2735426586},{"parent":"TRule_literal_value.TAlt10","rule":"TRule_literal_value.TAlt10.Token1","sum":2},{"parent":"TRule_literal_value.TAlt2","rule":"TRule_literal_value.TAlt2.Rule_real1","sum":109366652},{"parent":"TRule_literal_value.TAlt3","rule":"TRule_literal_value.TAlt3.Token1","sum":2128186998},{"parent":"TRule_literal_value.TAlt5","rule":"TRule_literal_value.TAlt5.Token1","sum":79765448},{"parent":"TRule_literal_value.TAlt9","rule":"TRule_literal_value.TAlt9.Rule_bool_value1","sum":104618486},{"parent":"TRule_match_op","rule":"TRule_match_op.Token1","sum":52393370},{"parent":"TRule_module_path","rule":"TRule_module_path.Block3","sum":366179},{"parent":"TRule_module_path","rule":"TRule_module_path.Rule_an_id2","sum":16683079},{"parent":"TRule_module_path.TBlock3","rule":"TRule_module_path.TBlock3.Rule_an_id2","sum":1091501},{"parent":"TRule_module_path.TBlock3","rule":"TRule_module_path.TBlock3.Token1","sum":1091501},{"parent":"TRule_mul_subexpr","rule":"TRule_mul_subexpr.Block2","sum":115511745},{"parent":"TRule_mul_subexpr","rule":"TRule_mul_subexpr.Rule_con_subexpr1","sum":15807788790},{"parent":"TRule_mul_subexpr.TBlock2","rule":"TRule_mul_subexpr.TBlock2.Rule_con_subexpr2","sum":229859013},{"parent":"TRule_mul_subexpr.TBlock2","rule":"TRule_mul_subexpr.TBlock2.Token1","sum":229859013},{"parent":"TRule_named_bind_parameter","rule":"TRule_named_bind_parameter.Block2","sum":146935},{"parent":"TRule_named_bind_parameter","rule":"TRule_named_bind_parameter.Rule_bind_parameter1","sum":38101725},{"parent":"TRule_named_bind_parameter.TBlock2","rule":"TRule_named_bind_parameter.TBlock2.Rule_bind_parameter2","sum":146935},{"parent":"TRule_named_bind_parameter.TBlock2","rule":"TRule_named_bind_parameter.TBlock2.Token1","sum":146935},{"parent":"TRule_named_bind_parameter_list","rule":"TRule_named_bind_parameter_list.Block2","sum":7116652},{"parent":"TRule_named_bind_parameter_list","rule":"TRule_named_bind_parameter_list.Rule_named_bind_parameter1","sum":16683079},{"parent":"TRule_named_bind_parameter_list.TBlock2","rule":"TRule_named_bind_parameter_list.TBlock2.Rule_named_bind_parameter2","sum":21418646},{"parent":"TRule_named_bind_parameter_list.TBlock2","rule":"TRule_named_bind_parameter_list.TBlock2.Token1","sum":21418646},{"parent":"TRule_named_column","rule":"TRule_named_column.Block2","sum":7211613},{"parent":"TRule_named_column","rule":"TRule_named_column.Rule_column_name1","sum":21451704},{"parent":"TRule_named_column.TBlock2","rule":"TRule_named_column.TBlock2.Rule_an_id2","sum":7211613},{"parent":"TRule_named_column.TBlock2","rule":"TRule_named_column.TBlock2.Token1","sum":7211613},{"parent":"TRule_named_expr","rule":"TRule_named_expr.Block2","sum":156898577},{"parent":"TRule_named_expr","rule":"TRule_named_expr.Rule_expr1","sum":7198460211},{"parent":"TRule_named_expr.TBlock2","rule":"TRule_named_expr.TBlock2.Rule_an_id_or_type2","sum":156898577},{"parent":"TRule_named_expr.TBlock2","rule":"TRule_named_expr.TBlock2.Token1","sum":156898577},{"parent":"TRule_named_expr_list","rule":"TRule_named_expr_list.Block2","sum":1187842181},{"parent":"TRule_named_expr_list","rule":"TRule_named_expr_list.Rule_named_expr1","sum":3249792168},{"parent":"TRule_named_expr_list.TBlock2","rule":"TRule_named_expr_list.TBlock2.Rule_named_expr2","sum":3454448866},{"parent":"TRule_named_expr_list.TBlock2","rule":"TRule_named_expr_list.TBlock2.Token1","sum":3454448866},{"parent":"TRule_named_nodes_stmt","rule":"TRule_named_nodes_stmt.Block3","sum":1010795718},{"parent":"TRule_named_nodes_stmt","rule":"TRule_named_nodes_stmt.Rule_bind_parameter_list1","sum":1010795718},{"parent":"TRule_named_nodes_stmt","rule":"TRule_named_nodes_stmt.Token2","sum":1010795718},{"parent":"TRule_named_nodes_stmt.TBlock3","rule":"TRule_named_nodes_stmt.TBlock3.Alt1","sum":679747353},{"parent":"TRule_named_nodes_stmt.TBlock3","rule":"TRule_named_nodes_stmt.TBlock3.Alt2","sum":331048365},{"parent":"TRule_named_nodes_stmt.TBlock3.TAlt1","rule":"TRule_named_nodes_stmt.TBlock3.TAlt1.Rule_expr1","sum":679747353},{"parent":"TRule_named_nodes_stmt.TBlock3.TAlt2","rule":"TRule_named_nodes_stmt.TBlock3.TAlt2.Rule_subselect_stmt1","sum":331048365},{"parent":"TRule_named_single_source","rule":"TRule_named_single_source.Block2","sum":1},{"parent":"TRule_named_single_source","rule":"TRule_named_single_source.Block3","sum":443834067},{"parent":"TRule_named_single_source","rule":"TRule_named_single_source.Block4","sum":404619},{"parent":"TRule_named_single_source","rule":"TRule_named_single_source.Rule_single_source1","sum":1061003000},{"parent":"TRule_named_single_source.TBlock2","rule":"TRule_named_single_source.TBlock2.Rule_row_pattern_recognition_clause1","sum":1},{"parent":"TRule_named_single_source.TBlock3","rule":"TRule_named_single_source.TBlock3.Block1","sum":443834067},{"parent":"TRule_named_single_source.TBlock3","rule":"TRule_named_single_source.TBlock3.Block2","sum":160877},{"parent":"TRule_named_single_source.TBlock3.TBlock1","rule":"TRule_named_single_source.TBlock3.TBlock1.Alt1","sum":441664725},{"parent":"TRule_named_single_source.TBlock3.TBlock1","rule":"TRule_named_single_source.TBlock3.TBlock1.Alt2","sum":2169342},{"parent":"TRule_named_single_source.TBlock3.TBlock1.TAlt1","rule":"TRule_named_single_source.TBlock3.TBlock1.TAlt1.Rule_an_id2","sum":441664725},{"parent":"TRule_named_single_source.TBlock3.TBlock1.TAlt1","rule":"TRule_named_single_source.TBlock3.TBlock1.TAlt1.Token1","sum":441664725},{"parent":"TRule_named_single_source.TBlock3.TBlock1.TAlt2","rule":"TRule_named_single_source.TBlock3.TBlock1.TAlt2.Rule_an_id_as_compat1","sum":2169342},{"parent":"TRule_named_single_source.TBlock3.TBlock2","rule":"TRule_named_single_source.TBlock3.TBlock2.Rule_pure_column_list1","sum":160877},{"parent":"TRule_named_single_source.TBlock4","rule":"TRule_named_single_source.TBlock4.Alt1","sum":75458},{"parent":"TRule_named_single_source.TBlock4","rule":"TRule_named_single_source.TBlock4.Alt2","sum":329161},{"parent":"TRule_named_single_source.TBlock4.TAlt1","rule":"TRule_named_single_source.TBlock4.TAlt1.Rule_sample_clause1","sum":75458},{"parent":"TRule_named_single_source.TBlock4.TAlt2","rule":"TRule_named_single_source.TBlock4.TAlt2.Rule_tablesample_clause1","sum":329161},{"parent":"TRule_neq_subexpr","rule":"TRule_neq_subexpr.Block2","sum":9155251},{"parent":"TRule_neq_subexpr","rule":"TRule_neq_subexpr.Block3","sum":111857165},{"parent":"TRule_neq_subexpr","rule":"TRule_neq_subexpr.Rule_bit_subexpr1","sum":15473389132},{"parent":"TRule_neq_subexpr.TBlock2","rule":"TRule_neq_subexpr.TBlock2.Block1","sum":9223987},{"parent":"TRule_neq_subexpr.TBlock2","rule":"TRule_neq_subexpr.TBlock2.Rule_bit_subexpr2","sum":9223987},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.Alt1","sum":8107015},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.Alt2","sum":53924},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.Alt3","sum":469},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.Alt4","sum":23},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.Alt5","sum":761022},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.Alt6","sum":134512},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.Alt7","sum":167022},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt1","rule":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt1.Token1","sum":8107015},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt2","rule":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt2.Rule_shift_right1","sum":53924},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt3","rule":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt3.Token1","sum":469},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt4","rule":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt4.Rule_rot_right1","sum":23},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt5","rule":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt5.Token1","sum":761022},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt6","rule":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt6.Token1","sum":134512},{"parent":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt7","rule":"TRule_neq_subexpr.TBlock2.TBlock1.TAlt7.Token1","sum":167022},{"parent":"TRule_neq_subexpr.TBlock3","rule":"TRule_neq_subexpr.TBlock3.Alt1","sum":108073061},{"parent":"TRule_neq_subexpr.TBlock3","rule":"TRule_neq_subexpr.TBlock3.Alt2","sum":3784104},{"parent":"TRule_neq_subexpr.TBlock3.TAlt1","rule":"TRule_neq_subexpr.TBlock3.TAlt1.Rule_double_question1","sum":108073061},{"parent":"TRule_neq_subexpr.TBlock3.TAlt1","rule":"TRule_neq_subexpr.TBlock3.TAlt1.Rule_neq_subexpr2","sum":108073061},{"parent":"TRule_neq_subexpr.TBlock3.TAlt2","rule":"TRule_neq_subexpr.TBlock3.TAlt2.Block1","sum":3784104},{"parent":"TRule_neq_subexpr.TBlock3.TAlt2.TBlock1","rule":"TRule_neq_subexpr.TBlock3.TAlt2.TBlock1.Token1","sum":3796088},{"parent":"TRule_new_window_name","rule":"TRule_new_window_name.Rule_window_name1","sum":14203555},{"parent":"TRule_null_treatment","rule":"TRule_null_treatment.Alt_null_treatment1","sum":45},{"parent":"TRule_null_treatment","rule":"TRule_null_treatment.Alt_null_treatment2","sum":7293180},{"parent":"TRule_null_treatment.TAlt1","rule":"TRule_null_treatment.TAlt1.Token1","sum":45},{"parent":"TRule_null_treatment.TAlt1","rule":"TRule_null_treatment.TAlt1.Token2","sum":45},{"parent":"TRule_null_treatment.TAlt2","rule":"TRule_null_treatment.TAlt2.Token1","sum":7293180},{"parent":"TRule_null_treatment.TAlt2","rule":"TRule_null_treatment.TAlt2.Token2","sum":7293180},{"parent":"TRule_object_ref","rule":"TRule_object_ref.Block1","sum":5299636},{"parent":"TRule_object_ref","rule":"TRule_object_ref.Rule_id_or_at2","sum":133959216},{"parent":"TRule_object_ref.TBlock1","rule":"TRule_object_ref.TBlock1.Rule_cluster_expr1","sum":5299636},{"parent":"TRule_object_ref.TBlock1","rule":"TRule_object_ref.TBlock1.Token2","sum":5299636},{"parent":"TRule_opt_bind_parameter","rule":"TRule_opt_bind_parameter.Block2","sum":27110},{"parent":"TRule_opt_bind_parameter","rule":"TRule_opt_bind_parameter.Rule_bind_parameter1","sum":21592253},{"parent":"TRule_opt_bind_parameter.TBlock2","rule":"TRule_opt_bind_parameter.TBlock2.Token1","sum":27110},{"parent":"TRule_opt_id_prefix","rule":"TRule_opt_id_prefix.Block1","sum":83358715},{"parent":"TRule_opt_id_prefix.TBlock1","rule":"TRule_opt_id_prefix.TBlock1.Rule_an_id1","sum":83358715},{"parent":"TRule_opt_id_prefix.TBlock1","rule":"TRule_opt_id_prefix.TBlock1.Token2","sum":83358715},{"parent":"TRule_opt_id_prefix_or_type","rule":"TRule_opt_id_prefix_or_type.Block1","sum":781387829},{"parent":"TRule_opt_id_prefix_or_type.TBlock1","rule":"TRule_opt_id_prefix_or_type.TBlock1.Rule_an_id_or_type1","sum":781387829},{"parent":"TRule_opt_id_prefix_or_type.TBlock1","rule":"TRule_opt_id_prefix_or_type.TBlock1.Token2","sum":781387829},{"parent":"TRule_opt_set_quantifier","rule":"TRule_opt_set_quantifier.Block1","sum":70623450},{"parent":"TRule_opt_set_quantifier.TBlock1","rule":"TRule_opt_set_quantifier.TBlock1.Token1","sum":70623450},{"parent":"TRule_or_subexpr","rule":"TRule_or_subexpr.Block2","sum":277843391},{"parent":"TRule_or_subexpr","rule":"TRule_or_subexpr.Rule_and_subexpr1","sum":13829126938},{"parent":"TRule_or_subexpr.TBlock2","rule":"TRule_or_subexpr.TBlock2.Rule_and_subexpr2","sum":472165179},{"parent":"TRule_or_subexpr.TBlock2","rule":"TRule_or_subexpr.TBlock2.Token1","sum":472165179},{"parent":"TRule_order_by_clause","rule":"TRule_order_by_clause.Rule_sort_specification_list3","sum":108121721},{"parent":"TRule_order_by_clause","rule":"TRule_order_by_clause.Token1","sum":108121721},{"parent":"TRule_order_by_clause","rule":"TRule_order_by_clause.Token2","sum":108121721},{"parent":"TRule_ordinary_grouping_set","rule":"TRule_ordinary_grouping_set.Rule_named_expr1","sum":301878091},{"parent":"TRule_ordinary_grouping_set_list","rule":"TRule_ordinary_grouping_set_list.Block2","sum":199601},{"parent":"TRule_ordinary_grouping_set_list","rule":"TRule_ordinary_grouping_set_list.Rule_ordinary_grouping_set1","sum":339378},{"parent":"TRule_ordinary_grouping_set_list.TBlock2","rule":"TRule_ordinary_grouping_set_list.TBlock2.Rule_ordinary_grouping_set2","sum":432788},{"parent":"TRule_ordinary_grouping_set_list.TBlock2","rule":"TRule_ordinary_grouping_set_list.TBlock2.Token1","sum":432788},{"parent":"TRule_pragma_stmt","rule":"TRule_pragma_stmt.Block4","sum":795793494},{"parent":"TRule_pragma_stmt","rule":"TRule_pragma_stmt.Rule_an_id3","sum":900857158},{"parent":"TRule_pragma_stmt","rule":"TRule_pragma_stmt.Rule_opt_id_prefix_or_type2","sum":900857158},{"parent":"TRule_pragma_stmt","rule":"TRule_pragma_stmt.Token1","sum":900857158},{"parent":"TRule_pragma_stmt.TBlock4","rule":"TRule_pragma_stmt.TBlock4.Alt1","sum":747636788},{"parent":"TRule_pragma_stmt.TBlock4","rule":"TRule_pragma_stmt.TBlock4.Alt2","sum":48156706},{"parent":"TRule_pragma_stmt.TBlock4.TAlt1","rule":"TRule_pragma_stmt.TBlock4.TAlt1.Rule_pragma_value2","sum":747636788},{"parent":"TRule_pragma_stmt.TBlock4.TAlt1","rule":"TRule_pragma_stmt.TBlock4.TAlt1.Token1","sum":747636788},{"parent":"TRule_pragma_stmt.TBlock4.TAlt2","rule":"TRule_pragma_stmt.TBlock4.TAlt2.Block3","sum":17774430},{"parent":"TRule_pragma_stmt.TBlock4.TAlt2","rule":"TRule_pragma_stmt.TBlock4.TAlt2.Rule_pragma_value2","sum":48156706},{"parent":"TRule_pragma_stmt.TBlock4.TAlt2","rule":"TRule_pragma_stmt.TBlock4.TAlt2.Token1","sum":48156706},{"parent":"TRule_pragma_stmt.TBlock4.TAlt2","rule":"TRule_pragma_stmt.TBlock4.TAlt2.Token4","sum":48156706},{"parent":"TRule_pragma_stmt.TBlock4.TAlt2.TBlock3","rule":"TRule_pragma_stmt.TBlock4.TAlt2.TBlock3.Rule_pragma_value2","sum":18600130},{"parent":"TRule_pragma_stmt.TBlock4.TAlt2.TBlock3","rule":"TRule_pragma_stmt.TBlock4.TAlt2.TBlock3.Token1","sum":18600130},{"parent":"TRule_pragma_value","rule":"TRule_pragma_value.Alt_pragma_value2","sum":256129},{"parent":"TRule_pragma_value","rule":"TRule_pragma_value.Alt_pragma_value3","sum":801902681},{"parent":"TRule_pragma_value","rule":"TRule_pragma_value.Alt_pragma_value5","sum":12234814},{"parent":"TRule_pragma_value.TAlt2","rule":"TRule_pragma_value.TAlt2.Rule_id1","sum":256129},{"parent":"TRule_pragma_value.TAlt3","rule":"TRule_pragma_value.TAlt3.Token1","sum":801902681},{"parent":"TRule_pragma_value.TAlt5","rule":"TRule_pragma_value.TAlt5.Rule_bind_parameter1","sum":12234814},{"parent":"TRule_process_core","rule":"TRule_process_core.Block4","sum":1132},{"parent":"TRule_process_core","rule":"TRule_process_core.Block5","sum":1930068},{"parent":"TRule_process_core","rule":"TRule_process_core.Rule_named_single_source3","sum":4560899},{"parent":"TRule_process_core","rule":"TRule_process_core.Token1","sum":4560899},{"parent":"TRule_process_core.TBlock4","rule":"TRule_process_core.TBlock4.Rule_named_single_source2","sum":1133},{"parent":"TRule_process_core.TBlock4","rule":"TRule_process_core.TBlock4.Token1","sum":1133},{"parent":"TRule_process_core.TBlock5","rule":"TRule_process_core.TBlock5.Block3","sum":46},{"parent":"TRule_process_core.TBlock5","rule":"TRule_process_core.TBlock5.Block5","sum":4746},{"parent":"TRule_process_core.TBlock5","rule":"TRule_process_core.TBlock5.Block7","sum":34},{"parent":"TRule_process_core.TBlock5","rule":"TRule_process_core.TBlock5.Rule_using_call_expr2","sum":1930068},{"parent":"TRule_process_core.TBlock5","rule":"TRule_process_core.TBlock5.Token1","sum":1930068},{"parent":"TRule_process_core.TBlock5.TBlock3","rule":"TRule_process_core.TBlock5.TBlock3.Rule_an_id2","sum":46},{"parent":"TRule_process_core.TBlock5.TBlock3","rule":"TRule_process_core.TBlock5.TBlock3.Token1","sum":46},{"parent":"TRule_process_core.TBlock5.TBlock5","rule":"TRule_process_core.TBlock5.TBlock5.Rule_expr2","sum":4746},{"parent":"TRule_process_core.TBlock5.TBlock5","rule":"TRule_process_core.TBlock5.TBlock5.Token1","sum":4746},{"parent":"TRule_process_core.TBlock5.TBlock7","rule":"TRule_process_core.TBlock5.TBlock7.Rule_order_by_clause2","sum":34},{"parent":"TRule_process_core.TBlock5.TBlock7","rule":"TRule_process_core.TBlock5.TBlock7.Token1","sum":34},{"parent":"TRule_pure_column_list","rule":"TRule_pure_column_list.Block3","sum":3992593},{"parent":"TRule_pure_column_list","rule":"TRule_pure_column_list.Rule_an_id2","sum":4733559},{"parent":"TRule_pure_column_list","rule":"TRule_pure_column_list.Token1","sum":4733559},{"parent":"TRule_pure_column_list","rule":"TRule_pure_column_list.Token4","sum":4733559},{"parent":"TRule_pure_column_list.TBlock3","rule":"TRule_pure_column_list.TBlock3.Rule_an_id2","sum":35642659},{"parent":"TRule_pure_column_list.TBlock3","rule":"TRule_pure_column_list.TBlock3.Token1","sum":35642659},{"parent":"TRule_pure_column_or_named","rule":"TRule_pure_column_or_named.Alt_pure_column_or_named1","sum":6613454},{"parent":"TRule_pure_column_or_named","rule":"TRule_pure_column_or_named.Alt_pure_column_or_named2","sum":426458416},{"parent":"TRule_pure_column_or_named.TAlt1","rule":"TRule_pure_column_or_named.TAlt1.Rule_bind_parameter1","sum":6613454},{"parent":"TRule_pure_column_or_named.TAlt2","rule":"TRule_pure_column_or_named.TAlt2.Rule_an_id1","sum":426458416},{"parent":"TRule_pure_column_or_named_list","rule":"TRule_pure_column_or_named_list.Block3","sum":11681930},{"parent":"TRule_pure_column_or_named_list","rule":"TRule_pure_column_or_named_list.Rule_pure_column_or_named2","sum":32540623},{"parent":"TRule_pure_column_or_named_list","rule":"TRule_pure_column_or_named_list.Token1","sum":32540623},{"parent":"TRule_pure_column_or_named_list","rule":"TRule_pure_column_or_named_list.Token4","sum":32540623},{"parent":"TRule_pure_column_or_named_list.TBlock3","rule":"TRule_pure_column_or_named_list.TBlock3.Rule_pure_column_or_named2","sum":21745838},{"parent":"TRule_pure_column_or_named_list.TBlock3","rule":"TRule_pure_column_or_named_list.TBlock3.Token1","sum":21745838},{"parent":"TRule_real","rule":"TRule_real.Token1","sum":109366652},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Block11","sum":8856},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Block13","sum":26511},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Block3","sum":124903},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Block4","sum":307402},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Block8","sum":320487},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Rule_column_list6","sum":858313},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Rule_named_single_source2","sum":858313},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Rule_using_call_expr9","sum":858313},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Token1","sum":858313},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Token5","sum":858313},{"parent":"TRule_reduce_core","rule":"TRule_reduce_core.Token7","sum":858313},{"parent":"TRule_reduce_core.TBlock11","rule":"TRule_reduce_core.TBlock11.Rule_expr2","sum":8856},{"parent":"TRule_reduce_core.TBlock11","rule":"TRule_reduce_core.TBlock11.Token1","sum":8856},{"parent":"TRule_reduce_core.TBlock13","rule":"TRule_reduce_core.TBlock13.Rule_order_by_clause2","sum":26511},{"parent":"TRule_reduce_core.TBlock13","rule":"TRule_reduce_core.TBlock13.Token1","sum":26511},{"parent":"TRule_reduce_core.TBlock3","rule":"TRule_reduce_core.TBlock3.Rule_named_single_source2","sum":215252},{"parent":"TRule_reduce_core.TBlock3","rule":"TRule_reduce_core.TBlock3.Token1","sum":215252},{"parent":"TRule_reduce_core.TBlock4","rule":"TRule_reduce_core.TBlock4.Rule_sort_specification_list2","sum":307402},{"parent":"TRule_reduce_core.TBlock4","rule":"TRule_reduce_core.TBlock4.Token1","sum":307402},{"parent":"TRule_reduce_core.TBlock8","rule":"TRule_reduce_core.TBlock8.Token1","sum":320487},{"parent":"TRule_repeatable_clause","rule":"TRule_repeatable_clause.Rule_expr3","sum":9382},{"parent":"TRule_repeatable_clause","rule":"TRule_repeatable_clause.Token1","sum":9382},{"parent":"TRule_repeatable_clause","rule":"TRule_repeatable_clause.Token2","sum":9382},{"parent":"TRule_repeatable_clause","rule":"TRule_repeatable_clause.Token4","sum":9382},{"parent":"TRule_result_column","rule":"TRule_result_column.Alt_result_column1","sum":251358239},{"parent":"TRule_result_column","rule":"TRule_result_column.Alt_result_column2","sum":3456316763},{"parent":"TRule_result_column.TAlt1","rule":"TRule_result_column.TAlt1.Rule_opt_id_prefix1","sum":251358239},{"parent":"TRule_result_column.TAlt1","rule":"TRule_result_column.TAlt1.Token2","sum":251358239},{"parent":"TRule_result_column.TAlt2","rule":"TRule_result_column.TAlt2.Block2","sum":1993067250},{"parent":"TRule_result_column.TAlt2","rule":"TRule_result_column.TAlt2.Rule_expr1","sum":3456316763},{"parent":"TRule_result_column.TAlt2.TBlock2","rule":"TRule_result_column.TAlt2.TBlock2.Alt1","sum":1992199458},{"parent":"TRule_result_column.TAlt2.TBlock2","rule":"TRule_result_column.TAlt2.TBlock2.Alt2","sum":867792},{"parent":"TRule_result_column.TAlt2.TBlock2.TAlt1","rule":"TRule_result_column.TAlt2.TBlock2.TAlt1.Rule_an_id_or_type2","sum":1992199458},{"parent":"TRule_result_column.TAlt2.TBlock2.TAlt1","rule":"TRule_result_column.TAlt2.TBlock2.TAlt1.Token1","sum":1992199458},{"parent":"TRule_result_column.TAlt2.TBlock2.TAlt2","rule":"TRule_result_column.TAlt2.TBlock2.TAlt2.Rule_an_id_as_compat1","sum":867792},{"parent":"TRule_rollup_list","rule":"TRule_rollup_list.Rule_ordinary_grouping_set_list3","sum":63017},{"parent":"TRule_rollup_list","rule":"TRule_rollup_list.Token1","sum":63017},{"parent":"TRule_rollup_list","rule":"TRule_rollup_list.Token2","sum":63017},{"parent":"TRule_rollup_list","rule":"TRule_rollup_list.Token4","sum":63017},{"parent":"TRule_rot_right","rule":"TRule_rot_right.Token1","sum":23},{"parent":"TRule_rot_right","rule":"TRule_rot_right.Token2","sum":23},{"parent":"TRule_rot_right","rule":"TRule_rot_right.Token3","sum":23},{"parent":"TRule_row_pattern","rule":"TRule_row_pattern.Rule_row_pattern_term1","sum":2},{"parent":"TRule_row_pattern_common_syntax","rule":"TRule_row_pattern_common_syntax.Rule_row_pattern5","sum":1},{"parent":"TRule_row_pattern_common_syntax","rule":"TRule_row_pattern_common_syntax.Rule_row_pattern_definition_list9","sum":1},{"parent":"TRule_row_pattern_common_syntax","rule":"TRule_row_pattern_common_syntax.Token3","sum":1},{"parent":"TRule_row_pattern_common_syntax","rule":"TRule_row_pattern_common_syntax.Token4","sum":1},{"parent":"TRule_row_pattern_common_syntax","rule":"TRule_row_pattern_common_syntax.Token6","sum":1},{"parent":"TRule_row_pattern_common_syntax","rule":"TRule_row_pattern_common_syntax.Token8","sum":1},{"parent":"TRule_row_pattern_definition","rule":"TRule_row_pattern_definition.Rule_row_pattern_definition_search_condition3","sum":1},{"parent":"TRule_row_pattern_definition","rule":"TRule_row_pattern_definition.Rule_row_pattern_definition_variable_name1","sum":1},{"parent":"TRule_row_pattern_definition","rule":"TRule_row_pattern_definition.Token2","sum":1},{"parent":"TRule_row_pattern_definition_list","rule":"TRule_row_pattern_definition_list.Rule_row_pattern_definition1","sum":1},{"parent":"TRule_row_pattern_definition_search_condition","rule":"TRule_row_pattern_definition_search_condition.Rule_search_condition1","sum":1},{"parent":"TRule_row_pattern_definition_variable_name","rule":"TRule_row_pattern_definition_variable_name.Rule_row_pattern_variable_name1","sum":1},{"parent":"TRule_row_pattern_factor","rule":"TRule_row_pattern_factor.Block2","sum":1},{"parent":"TRule_row_pattern_factor","rule":"TRule_row_pattern_factor.Rule_row_pattern_primary1","sum":2},{"parent":"TRule_row_pattern_factor.TBlock2","rule":"TRule_row_pattern_factor.TBlock2.Rule_row_pattern_quantifier1","sum":1},{"parent":"TRule_row_pattern_measure_definition","rule":"TRule_row_pattern_measure_definition.Rule_an_id3","sum":3},{"parent":"TRule_row_pattern_measure_definition","rule":"TRule_row_pattern_measure_definition.Rule_expr1","sum":3},{"parent":"TRule_row_pattern_measure_definition","rule":"TRule_row_pattern_measure_definition.Token2","sum":3},{"parent":"TRule_row_pattern_measure_list","rule":"TRule_row_pattern_measure_list.Block2","sum":1},{"parent":"TRule_row_pattern_measure_list","rule":"TRule_row_pattern_measure_list.Rule_row_pattern_measure_definition1","sum":1},{"parent":"TRule_row_pattern_measure_list.TBlock2","rule":"TRule_row_pattern_measure_list.TBlock2.Rule_row_pattern_measure_definition2","sum":2},{"parent":"TRule_row_pattern_measure_list.TBlock2","rule":"TRule_row_pattern_measure_list.TBlock2.Token1","sum":2},{"parent":"TRule_row_pattern_measures","rule":"TRule_row_pattern_measures.Rule_row_pattern_measure_list2","sum":1},{"parent":"TRule_row_pattern_measures","rule":"TRule_row_pattern_measures.Token1","sum":1},{"parent":"TRule_row_pattern_primary","rule":"TRule_row_pattern_primary.Alt_row_pattern_primary1","sum":1},{"parent":"TRule_row_pattern_primary","rule":"TRule_row_pattern_primary.Alt_row_pattern_primary4","sum":1},{"parent":"TRule_row_pattern_primary.TAlt1","rule":"TRule_row_pattern_primary.TAlt1.Rule_row_pattern_primary_variable_name1","sum":1},{"parent":"TRule_row_pattern_primary.TAlt4","rule":"TRule_row_pattern_primary.TAlt4.Block2","sum":1},{"parent":"TRule_row_pattern_primary.TAlt4","rule":"TRule_row_pattern_primary.TAlt4.Token1","sum":1},{"parent":"TRule_row_pattern_primary.TAlt4","rule":"TRule_row_pattern_primary.TAlt4.Token3","sum":1},{"parent":"TRule_row_pattern_primary.TAlt4.TBlock2","rule":"TRule_row_pattern_primary.TAlt4.TBlock2.Rule_row_pattern1","sum":1},{"parent":"TRule_row_pattern_primary_variable_name","rule":"TRule_row_pattern_primary_variable_name.Rule_row_pattern_variable_name1","sum":1},{"parent":"TRule_row_pattern_quantifier","rule":"TRule_row_pattern_quantifier.Alt_row_pattern_quantifier5","sum":1},{"parent":"TRule_row_pattern_quantifier.TAlt5","rule":"TRule_row_pattern_quantifier.TAlt5.Rule_integer2","sum":1},{"parent":"TRule_row_pattern_quantifier.TAlt5","rule":"TRule_row_pattern_quantifier.TAlt5.Token1","sum":1},{"parent":"TRule_row_pattern_quantifier.TAlt5","rule":"TRule_row_pattern_quantifier.TAlt5.Token3","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Block3","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Block4","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Block5","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Block6","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Rule_row_pattern_common_syntax7","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Token1","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Token2","sum":1},{"parent":"TRule_row_pattern_recognition_clause","rule":"TRule_row_pattern_recognition_clause.Token8","sum":1},{"parent":"TRule_row_pattern_recognition_clause.TBlock3","rule":"TRule_row_pattern_recognition_clause.TBlock3.Rule_window_partition_clause1","sum":1},{"parent":"TRule_row_pattern_recognition_clause.TBlock4","rule":"TRule_row_pattern_recognition_clause.TBlock4.Rule_order_by_clause1","sum":1},{"parent":"TRule_row_pattern_recognition_clause.TBlock5","rule":"TRule_row_pattern_recognition_clause.TBlock5.Rule_row_pattern_measures1","sum":1},{"parent":"TRule_row_pattern_recognition_clause.TBlock6","rule":"TRule_row_pattern_recognition_clause.TBlock6.Rule_row_pattern_rows_per_match1","sum":1},{"parent":"TRule_row_pattern_rows_per_match","rule":"TRule_row_pattern_rows_per_match.Alt_row_pattern_rows_per_match1","sum":1},{"parent":"TRule_row_pattern_rows_per_match.TAlt1","rule":"TRule_row_pattern_rows_per_match.TAlt1.Token1","sum":1},{"parent":"TRule_row_pattern_rows_per_match.TAlt1","rule":"TRule_row_pattern_rows_per_match.TAlt1.Token2","sum":1},{"parent":"TRule_row_pattern_rows_per_match.TAlt1","rule":"TRule_row_pattern_rows_per_match.TAlt1.Token3","sum":1},{"parent":"TRule_row_pattern_rows_per_match.TAlt1","rule":"TRule_row_pattern_rows_per_match.TAlt1.Token4","sum":1},{"parent":"TRule_row_pattern_term","rule":"TRule_row_pattern_term.Block1","sum":2},{"parent":"TRule_row_pattern_term.TBlock1","rule":"TRule_row_pattern_term.TBlock1.Rule_row_pattern_factor1","sum":2},{"parent":"TRule_row_pattern_variable_name","rule":"TRule_row_pattern_variable_name.Rule_identifier1","sum":2},{"parent":"TRule_sample_clause","rule":"TRule_sample_clause.Rule_expr2","sum":75458},{"parent":"TRule_sample_clause","rule":"TRule_sample_clause.Token1","sum":75458},{"parent":"TRule_sampling_mode","rule":"TRule_sampling_mode.Token1","sum":329161},{"parent":"TRule_search_condition","rule":"TRule_search_condition.Rule_expr1","sum":1},{"parent":"TRule_select_core","rule":"TRule_select_core.Block1","sum":10677032},{"parent":"TRule_select_core","rule":"TRule_select_core.Block10","sum":341490928},{"parent":"TRule_select_core","rule":"TRule_select_core.Block11","sum":138061902},{"parent":"TRule_select_core","rule":"TRule_select_core.Block12","sum":12007001},{"parent":"TRule_select_core","rule":"TRule_select_core.Block13","sum":13625726},{"parent":"TRule_select_core","rule":"TRule_select_core.Block14","sum":89004653},{"parent":"TRule_select_core","rule":"TRule_select_core.Block3","sum":117},{"parent":"TRule_select_core","rule":"TRule_select_core.Block6","sum":530771003},{"parent":"TRule_select_core","rule":"TRule_select_core.Block7","sum":94096389},{"parent":"TRule_select_core","rule":"TRule_select_core.Block8","sum":25026920},{"parent":"TRule_select_core","rule":"TRule_select_core.Block9","sum":835552366},{"parent":"TRule_select_core","rule":"TRule_select_core.Rule_opt_set_quantifier4","sum":907141337},{"parent":"TRule_select_core","rule":"TRule_select_core.Rule_result_column5","sum":907141337},{"parent":"TRule_select_core","rule":"TRule_select_core.Token2","sum":907141337},{"parent":"TRule_select_core.TBlock1","rule":"TRule_select_core.TBlock1.Rule_join_source2","sum":10677032},{"parent":"TRule_select_core.TBlock1","rule":"TRule_select_core.TBlock1.Token1","sum":10677032},{"parent":"TRule_select_core.TBlock10","rule":"TRule_select_core.TBlock10.Rule_expr2","sum":341490928},{"parent":"TRule_select_core.TBlock10","rule":"TRule_select_core.TBlock10.Token1","sum":341490928},{"parent":"TRule_select_core.TBlock11","rule":"TRule_select_core.TBlock11.Rule_group_by_clause1","sum":138061902},{"parent":"TRule_select_core.TBlock12","rule":"TRule_select_core.TBlock12.Rule_expr2","sum":12007001},{"parent":"TRule_select_core.TBlock12","rule":"TRule_select_core.TBlock12.Token1","sum":12007001},{"parent":"TRule_select_core.TBlock13","rule":"TRule_select_core.TBlock13.Rule_window_clause1","sum":13625726},{"parent":"TRule_select_core.TBlock14","rule":"TRule_select_core.TBlock14.Rule_ext_order_by_clause1","sum":89004653},{"parent":"TRule_select_core.TBlock3","rule":"TRule_select_core.TBlock3.Token1","sum":117},{"parent":"TRule_select_core.TBlock6","rule":"TRule_select_core.TBlock6.Rule_result_column2","sum":2800533665},{"parent":"TRule_select_core.TBlock6","rule":"TRule_select_core.TBlock6.Token1","sum":2800533665},{"parent":"TRule_select_core.TBlock7","rule":"TRule_select_core.TBlock7.Token1","sum":94096389},{"parent":"TRule_select_core.TBlock8","rule":"TRule_select_core.TBlock8.Block2","sum":63},{"parent":"TRule_select_core.TBlock8","rule":"TRule_select_core.TBlock8.Rule_without_column_list3","sum":25026920},{"parent":"TRule_select_core.TBlock8","rule":"TRule_select_core.TBlock8.Token1","sum":25026920},{"parent":"TRule_select_core.TBlock8.TBlock2","rule":"TRule_select_core.TBlock8.TBlock2.Token1","sum":63},{"parent":"TRule_select_core.TBlock8.TBlock2","rule":"TRule_select_core.TBlock8.TBlock2.Token2","sum":63},{"parent":"TRule_select_core.TBlock9","rule":"TRule_select_core.TBlock9.Rule_join_source2","sum":835552366},{"parent":"TRule_select_core.TBlock9","rule":"TRule_select_core.TBlock9.Token1","sum":835552366},{"parent":"TRule_select_kind","rule":"TRule_select_kind.Block1","sum":927614},{"parent":"TRule_select_kind","rule":"TRule_select_kind.Block2","sum":912560549},{"parent":"TRule_select_kind","rule":"TRule_select_kind.Block3","sum":2880688},{"parent":"TRule_select_kind.TBlock1","rule":"TRule_select_kind.TBlock1.Token1","sum":927614},{"parent":"TRule_select_kind.TBlock2","rule":"TRule_select_kind.TBlock2.Alt1","sum":4560899},{"parent":"TRule_select_kind.TBlock2","rule":"TRule_select_kind.TBlock2.Alt2","sum":858313},{"parent":"TRule_select_kind.TBlock2","rule":"TRule_select_kind.TBlock2.Alt3","sum":907141337},{"parent":"TRule_select_kind.TBlock2.TAlt1","rule":"TRule_select_kind.TBlock2.TAlt1.Rule_process_core1","sum":4560899},{"parent":"TRule_select_kind.TBlock2.TAlt2","rule":"TRule_select_kind.TBlock2.TAlt2.Rule_reduce_core1","sum":858313},{"parent":"TRule_select_kind.TBlock2.TAlt3","rule":"TRule_select_kind.TBlock2.TAlt3.Rule_select_core1","sum":907141337},{"parent":"TRule_select_kind.TBlock3","rule":"TRule_select_kind.TBlock3.Rule_pure_column_or_named3","sum":2880688},{"parent":"TRule_select_kind.TBlock3","rule":"TRule_select_kind.TBlock3.Token1","sum":2880688},{"parent":"TRule_select_kind.TBlock3","rule":"TRule_select_kind.TBlock3.Token2","sum":2880688},{"parent":"TRule_select_kind_parenthesis","rule":"TRule_select_kind_parenthesis.Alt_select_kind_parenthesis1","sum":781508132},{"parent":"TRule_select_kind_parenthesis","rule":"TRule_select_kind_parenthesis.Alt_select_kind_parenthesis2","sum":8012379},{"parent":"TRule_select_kind_parenthesis.TAlt1","rule":"TRule_select_kind_parenthesis.TAlt1.Rule_select_kind_partial1","sum":781508132},{"parent":"TRule_select_kind_parenthesis.TAlt2","rule":"TRule_select_kind_parenthesis.TAlt2.Rule_select_kind_partial2","sum":8012379},{"parent":"TRule_select_kind_parenthesis.TAlt2","rule":"TRule_select_kind_parenthesis.TAlt2.Token1","sum":8012379},{"parent":"TRule_select_kind_parenthesis.TAlt2","rule":"TRule_select_kind_parenthesis.TAlt2.Token3","sum":8012379},{"parent":"TRule_select_kind_partial","rule":"TRule_select_kind_partial.Block2","sum":30835525},{"parent":"TRule_select_kind_partial","rule":"TRule_select_kind_partial.Rule_select_kind1","sum":912560549},{"parent":"TRule_select_kind_partial.TBlock2","rule":"TRule_select_kind_partial.TBlock2.Block3","sum":4694367},{"parent":"TRule_select_kind_partial.TBlock2","rule":"TRule_select_kind_partial.TBlock2.Rule_expr2","sum":30835525},{"parent":"TRule_select_kind_partial.TBlock2","rule":"TRule_select_kind_partial.TBlock2.Token1","sum":30835525},{"parent":"TRule_select_kind_partial.TBlock2.TBlock3","rule":"TRule_select_kind_partial.TBlock2.TBlock3.Rule_expr2","sum":4694367},{"parent":"TRule_select_kind_partial.TBlock2.TBlock3","rule":"TRule_select_kind_partial.TBlock2.TBlock3.Token1","sum":4694367},{"parent":"TRule_select_op","rule":"TRule_select_op.Alt_select_op1","sum":63995060},{"parent":"TRule_select_op.TAlt1","rule":"TRule_select_op.TAlt1.Block2","sum":63061679},{"parent":"TRule_select_op.TAlt1","rule":"TRule_select_op.TAlt1.Token1","sum":63995060},{"parent":"TRule_select_op.TAlt1.TBlock2","rule":"TRule_select_op.TAlt1.TBlock2.Token1","sum":63061679},{"parent":"TRule_select_stmt","rule":"TRule_select_stmt.Block2","sum":33347504},{"parent":"TRule_select_stmt","rule":"TRule_select_stmt.Rule_select_kind_parenthesis1","sum":725525451},{"parent":"TRule_select_stmt.TBlock2","rule":"TRule_select_stmt.TBlock2.Rule_select_kind_parenthesis2","sum":56999230},{"parent":"TRule_select_stmt.TBlock2","rule":"TRule_select_stmt.TBlock2.Rule_select_op1","sum":56999230},{"parent":"TRule_select_unparenthesized_stmt","rule":"TRule_select_unparenthesized_stmt.Block2","sum":4320245},{"parent":"TRule_select_unparenthesized_stmt","rule":"TRule_select_unparenthesized_stmt.Rule_select_kind_partial1","sum":123040038},{"parent":"TRule_select_unparenthesized_stmt.TBlock2","rule":"TRule_select_unparenthesized_stmt.TBlock2.Rule_select_kind_parenthesis2","sum":6995830},{"parent":"TRule_select_unparenthesized_stmt.TBlock2","rule":"TRule_select_unparenthesized_stmt.TBlock2.Rule_select_op1","sum":6995830},{"parent":"TRule_shift_right","rule":"TRule_shift_right.Token1","sum":53924},{"parent":"TRule_shift_right","rule":"TRule_shift_right.Token2","sum":53924},{"parent":"TRule_simple_table_ref","rule":"TRule_simple_table_ref.Block2","sum":143496843},{"parent":"TRule_simple_table_ref","rule":"TRule_simple_table_ref.Rule_simple_table_ref_core1","sum":212302112},{"parent":"TRule_simple_table_ref.TBlock2","rule":"TRule_simple_table_ref.TBlock2.Rule_table_hints1","sum":143496843},{"parent":"TRule_simple_table_ref_core","rule":"TRule_simple_table_ref_core.Alt_simple_table_ref_core1","sum":133959216},{"parent":"TRule_simple_table_ref_core","rule":"TRule_simple_table_ref_core.Alt_simple_table_ref_core2","sum":78342896},{"parent":"TRule_simple_table_ref_core.TAlt1","rule":"TRule_simple_table_ref_core.TAlt1.Rule_object_ref1","sum":133959216},{"parent":"TRule_simple_table_ref_core.TAlt2","rule":"TRule_simple_table_ref_core.TAlt2.Block1","sum":71527},{"parent":"TRule_simple_table_ref_core.TAlt2","rule":"TRule_simple_table_ref_core.TAlt2.Rule_bind_parameter2","sum":78342896},{"parent":"TRule_simple_table_ref_core.TAlt2.TBlock1","rule":"TRule_simple_table_ref_core.TAlt2.TBlock1.Token1","sum":71527},{"parent":"TRule_single_source","rule":"TRule_single_source.Alt_single_source1","sum":955906317},{"parent":"TRule_single_source","rule":"TRule_single_source.Alt_single_source2","sum":104927242},{"parent":"TRule_single_source","rule":"TRule_single_source.Alt_single_source3","sum":169441},{"parent":"TRule_single_source.TAlt1","rule":"TRule_single_source.TAlt1.Rule_table_ref1","sum":955906317},{"parent":"TRule_single_source.TAlt2","rule":"TRule_single_source.TAlt2.Rule_select_stmt2","sum":104927242},{"parent":"TRule_single_source.TAlt2","rule":"TRule_single_source.TAlt2.Token1","sum":104927242},{"parent":"TRule_single_source.TAlt2","rule":"TRule_single_source.TAlt2.Token3","sum":104927242},{"parent":"TRule_single_source.TAlt3","rule":"TRule_single_source.TAlt3.Rule_values_stmt2","sum":169441},{"parent":"TRule_single_source.TAlt3","rule":"TRule_single_source.TAlt3.Token1","sum":169441},{"parent":"TRule_single_source.TAlt3","rule":"TRule_single_source.TAlt3.Token3","sum":169441},{"parent":"TRule_smart_parenthesis","rule":"TRule_smart_parenthesis.Block2","sum":509972815},{"parent":"TRule_smart_parenthesis","rule":"TRule_smart_parenthesis.Block3","sum":2668059},{"parent":"TRule_smart_parenthesis","rule":"TRule_smart_parenthesis.Token1","sum":513744527},{"parent":"TRule_smart_parenthesis","rule":"TRule_smart_parenthesis.Token4","sum":513744527},{"parent":"TRule_smart_parenthesis.TBlock2","rule":"TRule_smart_parenthesis.TBlock2.Rule_named_expr_list1","sum":509972815},{"parent":"TRule_smart_parenthesis.TBlock3","rule":"TRule_smart_parenthesis.TBlock3.Token1","sum":2668059},{"parent":"TRule_sort_specification","rule":"TRule_sort_specification.Block2","sum":33272816},{"parent":"TRule_sort_specification","rule":"TRule_sort_specification.Rule_expr1","sum":182332141},{"parent":"TRule_sort_specification.TBlock2","rule":"TRule_sort_specification.TBlock2.Token1","sum":33272816},{"parent":"TRule_sort_specification_list","rule":"TRule_sort_specification_list.Block2","sum":40028678},{"parent":"TRule_sort_specification_list","rule":"TRule_sort_specification_list.Rule_sort_specification1","sum":108429123},{"parent":"TRule_sort_specification_list.TBlock2","rule":"TRule_sort_specification_list.TBlock2.Rule_sort_specification2","sum":73903018},{"parent":"TRule_sort_specification_list.TBlock2","rule":"TRule_sort_specification_list.TBlock2.Token1","sum":73903018},{"parent":"TRule_sql_query","rule":"TRule_sql_query.Alt_sql_query1","sum":321178940},{"parent":"TRule_sql_query.TAlt1","rule":"TRule_sql_query.TAlt1.Rule_sql_stmt_list1","sum":321178940},{"parent":"TRule_sql_stmt","rule":"TRule_sql_stmt.Block1","sum":53},{"parent":"TRule_sql_stmt","rule":"TRule_sql_stmt.Rule_sql_stmt_core2","sum":2731471309},{"parent":"TRule_sql_stmt.TBlock1","rule":"TRule_sql_stmt.TBlock1.Token1","sum":53},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core1","sum":900857158},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core12","sum":156792290},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core13","sum":16680408},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core17","sum":4719917},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core18","sum":22375819},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core19","sum":8585453},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core2","sum":194079479},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core20","sum":7048194},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core21","sum":322},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core3","sum":946817824},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core4","sum":125},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core5","sum":2572734},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core6","sum":330553175},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core7","sum":209729253},{"parent":"TRule_sql_stmt_core","rule":"TRule_sql_stmt_core.Alt_sql_stmt_core8","sum":13057020},{"parent":"TRule_sql_stmt_core.TAlt1","rule":"TRule_sql_stmt_core.TAlt1.Rule_pragma_stmt1","sum":900857158},{"parent":"TRule_sql_stmt_core.TAlt12","rule":"TRule_sql_stmt_core.TAlt12.Rule_declare_stmt1","sum":156792290},{"parent":"TRule_sql_stmt_core.TAlt13","rule":"TRule_sql_stmt_core.TAlt13.Rule_import_stmt1","sum":16680408},{"parent":"TRule_sql_stmt_core.TAlt17","rule":"TRule_sql_stmt_core.TAlt17.Rule_do_stmt1","sum":4719917},{"parent":"TRule_sql_stmt_core.TAlt18","rule":"TRule_sql_stmt_core.TAlt18.Rule_define_action_or_subquery_stmt1","sum":22375819},{"parent":"TRule_sql_stmt_core.TAlt19","rule":"TRule_sql_stmt_core.TAlt19.Rule_if_stmt1","sum":8585453},{"parent":"TRule_sql_stmt_core.TAlt2","rule":"TRule_sql_stmt_core.TAlt2.Rule_select_stmt1","sum":194079479},{"parent":"TRule_sql_stmt_core.TAlt20","rule":"TRule_sql_stmt_core.TAlt20.Rule_for_stmt1","sum":7048194},{"parent":"TRule_sql_stmt_core.TAlt21","rule":"TRule_sql_stmt_core.TAlt21.Rule_values_stmt1","sum":322},{"parent":"TRule_sql_stmt_core.TAlt3","rule":"TRule_sql_stmt_core.TAlt3.Rule_named_nodes_stmt1","sum":946817824},{"parent":"TRule_sql_stmt_core.TAlt4","rule":"TRule_sql_stmt_core.TAlt4.Rule_create_table_stmt1","sum":125},{"parent":"TRule_sql_stmt_core.TAlt5","rule":"TRule_sql_stmt_core.TAlt5.Rule_drop_table_stmt1","sum":2572734},{"parent":"TRule_sql_stmt_core.TAlt6","rule":"TRule_sql_stmt_core.TAlt6.Rule_use_stmt1","sum":330553175},{"parent":"TRule_sql_stmt_core.TAlt7","rule":"TRule_sql_stmt_core.TAlt7.Rule_into_table_stmt1","sum":209729253},{"parent":"TRule_sql_stmt_core.TAlt8","rule":"TRule_sql_stmt_core.TAlt8.Rule_commit_stmt1","sum":13057020},{"parent":"TRule_sql_stmt_list","rule":"TRule_sql_stmt_list.Block1","sum":435},{"parent":"TRule_sql_stmt_list","rule":"TRule_sql_stmt_list.Block3","sum":315770059},{"parent":"TRule_sql_stmt_list","rule":"TRule_sql_stmt_list.Block4","sum":195437753},{"parent":"TRule_sql_stmt_list","rule":"TRule_sql_stmt_list.Rule_sql_stmt2","sum":321178940},{"parent":"TRule_sql_stmt_list","rule":"TRule_sql_stmt_list.Token5","sum":321178940},{"parent":"TRule_sql_stmt_list.TBlock1","rule":"TRule_sql_stmt_list.TBlock1.Token1","sum":458},{"parent":"TRule_sql_stmt_list.TBlock3","rule":"TRule_sql_stmt_list.TBlock3.Block1","sum":2410292369},{"parent":"TRule_sql_stmt_list.TBlock3","rule":"TRule_sql_stmt_list.TBlock3.Rule_sql_stmt2","sum":2410292369},{"parent":"TRule_sql_stmt_list.TBlock3.TBlock1","rule":"TRule_sql_stmt_list.TBlock3.TBlock1.Token1","sum":2419377654},{"parent":"TRule_sql_stmt_list.TBlock4","rule":"TRule_sql_stmt_list.TBlock4.Token1","sum":198139030},{"parent":"TRule_struct_arg","rule":"TRule_struct_arg.Rule_type_name_or_bind3","sum":113973263},{"parent":"TRule_struct_arg","rule":"TRule_struct_arg.Rule_type_name_tag1","sum":113973263},{"parent":"TRule_struct_arg","rule":"TRule_struct_arg.Token2","sum":113973263},{"parent":"TRule_struct_arg_positional","rule":"TRule_struct_arg_positional.Alt_struct_arg_positional1","sum":195},{"parent":"TRule_struct_arg_positional.TAlt1","rule":"TRule_struct_arg_positional.TAlt1.Block3","sum":166},{"parent":"TRule_struct_arg_positional.TAlt1","rule":"TRule_struct_arg_positional.TAlt1.Rule_type_name_or_bind2","sum":195},{"parent":"TRule_struct_arg_positional.TAlt1","rule":"TRule_struct_arg_positional.TAlt1.Rule_type_name_tag1","sum":195},{"parent":"TRule_struct_arg_positional.TAlt1.TBlock3","rule":"TRule_struct_arg_positional.TAlt1.TBlock3.Token2","sum":166},{"parent":"TRule_struct_literal","rule":"TRule_struct_literal.Block2","sum":14603829},{"parent":"TRule_struct_literal","rule":"TRule_struct_literal.Block3","sum":2563557},{"parent":"TRule_struct_literal","rule":"TRule_struct_literal.Token1","sum":14736673},{"parent":"TRule_struct_literal","rule":"TRule_struct_literal.Token4","sum":14736673},{"parent":"TRule_struct_literal.TBlock2","rule":"TRule_struct_literal.TBlock2.Rule_expr_struct_list1","sum":14603829},{"parent":"TRule_struct_literal.TBlock3","rule":"TRule_struct_literal.TBlock3.Token1","sum":2563557},{"parent":"TRule_subselect_stmt","rule":"TRule_subselect_stmt.Block1","sum":331048365},{"parent":"TRule_subselect_stmt.TBlock1","rule":"TRule_subselect_stmt.TBlock1.Alt1","sum":208008327},{"parent":"TRule_subselect_stmt.TBlock1","rule":"TRule_subselect_stmt.TBlock1.Alt2","sum":123040038},{"parent":"TRule_subselect_stmt.TBlock1.TAlt1","rule":"TRule_subselect_stmt.TBlock1.TAlt1.Rule_select_stmt2","sum":208008327},{"parent":"TRule_subselect_stmt.TBlock1.TAlt1","rule":"TRule_subselect_stmt.TBlock1.TAlt1.Token1","sum":208008327},{"parent":"TRule_subselect_stmt.TBlock1.TAlt1","rule":"TRule_subselect_stmt.TBlock1.TAlt1.Token3","sum":208008327},{"parent":"TRule_subselect_stmt.TBlock1.TAlt2","rule":"TRule_subselect_stmt.TBlock1.TAlt2.Rule_select_unparenthesized_stmt1","sum":123040038},{"parent":"TRule_table_arg","rule":"TRule_table_arg.Block1","sum":117005},{"parent":"TRule_table_arg","rule":"TRule_table_arg.Block3","sum":271664},{"parent":"TRule_table_arg","rule":"TRule_table_arg.Rule_named_expr2","sum":192341086},{"parent":"TRule_table_arg.TBlock1","rule":"TRule_table_arg.TBlock1.Token1","sum":117005},{"parent":"TRule_table_arg.TBlock3","rule":"TRule_table_arg.TBlock3.Rule_view_name2","sum":271664},{"parent":"TRule_table_arg.TBlock3","rule":"TRule_table_arg.TBlock3.Token1","sum":271664},{"parent":"TRule_table_constraint","rule":"TRule_table_constraint.Alt_table_constraint2","sum":124},{"parent":"TRule_table_constraint","rule":"TRule_table_constraint.Alt_table_constraint3","sum":105},{"parent":"TRule_table_constraint.TAlt2","rule":"TRule_table_constraint.TAlt2.Block5","sum":103},{"parent":"TRule_table_constraint.TAlt2","rule":"TRule_table_constraint.TAlt2.Rule_an_id4","sum":124},{"parent":"TRule_table_constraint.TAlt2","rule":"TRule_table_constraint.TAlt2.Token1","sum":124},{"parent":"TRule_table_constraint.TAlt2","rule":"TRule_table_constraint.TAlt2.Token2","sum":124},{"parent":"TRule_table_constraint.TAlt2","rule":"TRule_table_constraint.TAlt2.Token3","sum":124},{"parent":"TRule_table_constraint.TAlt2","rule":"TRule_table_constraint.TAlt2.Token6","sum":124},{"parent":"TRule_table_constraint.TAlt2.TBlock5","rule":"TRule_table_constraint.TAlt2.TBlock5.Rule_an_id2","sum":259},{"parent":"TRule_table_constraint.TAlt2.TBlock5","rule":"TRule_table_constraint.TAlt2.TBlock5.Token1","sum":259},{"parent":"TRule_table_constraint.TAlt3","rule":"TRule_table_constraint.TAlt3.Rule_column_order_by_specification4","sum":105},{"parent":"TRule_table_constraint.TAlt3","rule":"TRule_table_constraint.TAlt3.Token1","sum":105},{"parent":"TRule_table_constraint.TAlt3","rule":"TRule_table_constraint.TAlt3.Token2","sum":105},{"parent":"TRule_table_constraint.TAlt3","rule":"TRule_table_constraint.TAlt3.Token3","sum":105},{"parent":"TRule_table_constraint.TAlt3","rule":"TRule_table_constraint.TAlt3.Token6","sum":105},{"parent":"TRule_table_hint","rule":"TRule_table_hint.Alt_table_hint1","sum":155030406},{"parent":"TRule_table_hint","rule":"TRule_table_hint.Alt_table_hint2","sum":18942561},{"parent":"TRule_table_hint","rule":"TRule_table_hint.Alt_table_hint3","sum":22},{"parent":"TRule_table_hint.TAlt1","rule":"TRule_table_hint.TAlt1.Block2","sum":10903829},{"parent":"TRule_table_hint.TAlt1","rule":"TRule_table_hint.TAlt1.Rule_an_id_hint1","sum":155030406},{"parent":"TRule_table_hint.TAlt1.TBlock2","rule":"TRule_table_hint.TAlt1.TBlock2.Block2","sum":10903829},{"parent":"TRule_table_hint.TAlt1.TBlock2","rule":"TRule_table_hint.TAlt1.TBlock2.Token1","sum":10903829},{"parent":"TRule_table_hint.TAlt1.TBlock2.TBlock2","rule":"TRule_table_hint.TAlt1.TBlock2.TBlock2.Alt1","sum":10903829},{"parent":"TRule_table_hint.TAlt1.TBlock2.TBlock2.TAlt1","rule":"TRule_table_hint.TAlt1.TBlock2.TBlock2.TAlt1.Rule_type_name_tag1","sum":10903829},{"parent":"TRule_table_hint.TAlt2","rule":"TRule_table_hint.TAlt2.Block2","sum":1745},{"parent":"TRule_table_hint.TAlt2","rule":"TRule_table_hint.TAlt2.Rule_type_name_or_bind3","sum":18942561},{"parent":"TRule_table_hint.TAlt2","rule":"TRule_table_hint.TAlt2.Token1","sum":18942561},{"parent":"TRule_table_hint.TAlt2.TBlock2","rule":"TRule_table_hint.TAlt2.TBlock2.Token1","sum":1745},{"parent":"TRule_table_hint.TAlt3","rule":"TRule_table_hint.TAlt3.Block4","sum":22},{"parent":"TRule_table_hint.TAlt3","rule":"TRule_table_hint.TAlt3.Block5","sum":10},{"parent":"TRule_table_hint.TAlt3","rule":"TRule_table_hint.TAlt3.Token1","sum":22},{"parent":"TRule_table_hint.TAlt3","rule":"TRule_table_hint.TAlt3.Token3","sum":22},{"parent":"TRule_table_hint.TAlt3","rule":"TRule_table_hint.TAlt3.Token6","sum":22},{"parent":"TRule_table_hint.TAlt3.TBlock4","rule":"TRule_table_hint.TAlt3.TBlock4.Block2","sum":17},{"parent":"TRule_table_hint.TAlt3.TBlock4","rule":"TRule_table_hint.TAlt3.TBlock4.Rule_struct_arg_positional1","sum":22},{"parent":"TRule_table_hint.TAlt3.TBlock4.TBlock2","rule":"TRule_table_hint.TAlt3.TBlock4.TBlock2.Rule_struct_arg_positional2","sum":173},{"parent":"TRule_table_hint.TAlt3.TBlock4.TBlock2","rule":"TRule_table_hint.TAlt3.TBlock4.TBlock2.Token1","sum":173},{"parent":"TRule_table_hint.TAlt3.TBlock5","rule":"TRule_table_hint.TAlt3.TBlock5.Token1","sum":10},{"parent":"TRule_table_hints","rule":"TRule_table_hints.Block2","sum":163157673},{"parent":"TRule_table_hints","rule":"TRule_table_hints.Token1","sum":163157673},{"parent":"TRule_table_hints.TBlock2","rule":"TRule_table_hints.TBlock2.Alt1","sum":152472662},{"parent":"TRule_table_hints.TBlock2","rule":"TRule_table_hints.TBlock2.Alt2","sum":10685011},{"parent":"TRule_table_hints.TBlock2.TAlt1","rule":"TRule_table_hints.TBlock2.TAlt1.Rule_table_hint1","sum":152472662},{"parent":"TRule_table_hints.TBlock2.TAlt2","rule":"TRule_table_hints.TBlock2.TAlt2.Block3","sum":10409927},{"parent":"TRule_table_hints.TBlock2.TAlt2","rule":"TRule_table_hints.TBlock2.TAlt2.Rule_table_hint2","sum":10685011},{"parent":"TRule_table_hints.TBlock2.TAlt2","rule":"TRule_table_hints.TBlock2.TAlt2.Token1","sum":10685011},{"parent":"TRule_table_hints.TBlock2.TAlt2","rule":"TRule_table_hints.TBlock2.TAlt2.Token4","sum":10685011},{"parent":"TRule_table_hints.TBlock2.TAlt2.TBlock3","rule":"TRule_table_hints.TBlock2.TAlt2.TBlock3.Rule_table_hint2","sum":10815316},{"parent":"TRule_table_hints.TBlock2.TAlt2.TBlock3","rule":"TRule_table_hints.TBlock2.TAlt2.TBlock3.Token1","sum":10815316},{"parent":"TRule_table_key","rule":"TRule_table_key.Block2","sum":869375},{"parent":"TRule_table_key","rule":"TRule_table_key.Rule_id_table_or_type1","sum":331266134},{"parent":"TRule_table_key.TBlock2","rule":"TRule_table_key.TBlock2.Rule_view_name2","sum":869375},{"parent":"TRule_table_key.TBlock2","rule":"TRule_table_key.TBlock2.Token1","sum":869375},{"parent":"TRule_table_ref","rule":"TRule_table_ref.Block1","sum":40051910},{"parent":"TRule_table_ref","rule":"TRule_table_ref.Block2","sum":6068166},{"parent":"TRule_table_ref","rule":"TRule_table_ref.Block3","sum":955906317},{"parent":"TRule_table_ref","rule":"TRule_table_ref.Block4","sum":19660830},{"parent":"TRule_table_ref.TBlock1","rule":"TRule_table_ref.TBlock1.Rule_cluster_expr1","sum":40051910},{"parent":"TRule_table_ref.TBlock1","rule":"TRule_table_ref.TBlock1.Token2","sum":40051910},{"parent":"TRule_table_ref.TBlock2","rule":"TRule_table_ref.TBlock2.Token1","sum":6068166},{"parent":"TRule_table_ref.TBlock3","rule":"TRule_table_ref.TBlock3.Alt1","sum":331266134},{"parent":"TRule_table_ref.TBlock3","rule":"TRule_table_ref.TBlock3.Alt2","sum":96457781},{"parent":"TRule_table_ref.TBlock3","rule":"TRule_table_ref.TBlock3.Alt3","sum":528182402},{"parent":"TRule_table_ref.TBlock3.TAlt1","rule":"TRule_table_ref.TBlock3.TAlt1.Rule_table_key1","sum":331266134},{"parent":"TRule_table_ref.TBlock3.TAlt2","rule":"TRule_table_ref.TBlock3.TAlt2.Block3","sum":96457757},{"parent":"TRule_table_ref.TBlock3.TAlt2","rule":"TRule_table_ref.TBlock3.TAlt2.Rule_an_id_expr1","sum":96457781},{"parent":"TRule_table_ref.TBlock3.TAlt2","rule":"TRule_table_ref.TBlock3.TAlt2.Token2","sum":96457781},{"parent":"TRule_table_ref.TBlock3.TAlt2","rule":"TRule_table_ref.TBlock3.TAlt2.Token4","sum":96457781},{"parent":"TRule_table_ref.TBlock3.TAlt2.TBlock3","rule":"TRule_table_ref.TBlock3.TAlt2.TBlock3.Block2","sum":49681294},{"parent":"TRule_table_ref.TBlock3.TAlt2.TBlock3","rule":"TRule_table_ref.TBlock3.TAlt2.TBlock3.Block3","sum":358512},{"parent":"TRule_table_ref.TBlock3.TAlt2.TBlock3","rule":"TRule_table_ref.TBlock3.TAlt2.TBlock3.Rule_table_arg1","sum":96457757},{"parent":"TRule_table_ref.TBlock3.TAlt2.TBlock3.TBlock2","rule":"TRule_table_ref.TBlock3.TAlt2.TBlock3.TBlock2.Rule_table_arg2","sum":95883329},{"parent":"TRule_table_ref.TBlock3.TAlt2.TBlock3.TBlock2","rule":"TRule_table_ref.TBlock3.TAlt2.TBlock3.TBlock2.Token1","sum":95883329},{"parent":"TRule_table_ref.TBlock3.TAlt2.TBlock3.TBlock3","rule":"TRule_table_ref.TBlock3.TAlt2.TBlock3.TBlock3.Token1","sum":358512},{"parent":"TRule_table_ref.TBlock3.TAlt3","rule":"TRule_table_ref.TBlock3.TAlt3.Block2","sum":22391157},{"parent":"TRule_table_ref.TBlock3.TAlt3","rule":"TRule_table_ref.TBlock3.TAlt3.Block3","sum":179571},{"parent":"TRule_table_ref.TBlock3.TAlt3","rule":"TRule_table_ref.TBlock3.TAlt3.Rule_bind_parameter1","sum":528182402},{"parent":"TRule_table_ref.TBlock3.TAlt3.TBlock2","rule":"TRule_table_ref.TBlock3.TAlt3.TBlock2.Block2","sum":16009153},{"parent":"TRule_table_ref.TBlock3.TAlt3.TBlock2","rule":"TRule_table_ref.TBlock3.TAlt3.TBlock2.Token1","sum":22391157},{"parent":"TRule_table_ref.TBlock3.TAlt3.TBlock2","rule":"TRule_table_ref.TBlock3.TAlt3.TBlock2.Token3","sum":22391157},{"parent":"TRule_table_ref.TBlock3.TAlt3.TBlock2.TBlock2","rule":"TRule_table_ref.TBlock3.TAlt3.TBlock2.TBlock2.Rule_expr_list1","sum":16009153},{"parent":"TRule_table_ref.TBlock3.TAlt3.TBlock3","rule":"TRule_table_ref.TBlock3.TAlt3.TBlock3.Rule_view_name2","sum":179571},{"parent":"TRule_table_ref.TBlock3.TAlt3.TBlock3","rule":"TRule_table_ref.TBlock3.TAlt3.TBlock3.Token1","sum":179571},{"parent":"TRule_table_ref.TBlock4","rule":"TRule_table_ref.TBlock4.Rule_table_hints1","sum":19660830},{"parent":"TRule_tablesample_clause","rule":"TRule_tablesample_clause.Block6","sum":9382},{"parent":"TRule_tablesample_clause","rule":"TRule_tablesample_clause.Rule_expr4","sum":329161},{"parent":"TRule_tablesample_clause","rule":"TRule_tablesample_clause.Rule_sampling_mode2","sum":329161},{"parent":"TRule_tablesample_clause","rule":"TRule_tablesample_clause.Token1","sum":329161},{"parent":"TRule_tablesample_clause","rule":"TRule_tablesample_clause.Token3","sum":329161},{"parent":"TRule_tablesample_clause","rule":"TRule_tablesample_clause.Token5","sum":329161},{"parent":"TRule_tablesample_clause.TBlock6","rule":"TRule_tablesample_clause.TBlock6.Rule_repeatable_clause1","sum":9382},{"parent":"TRule_type_id","rule":"TRule_type_id.Token1","sum":11727923},{"parent":"TRule_type_name","rule":"TRule_type_name.Alt_type_name1","sum":89568358},{"parent":"TRule_type_name","rule":"TRule_type_name.Alt_type_name2","sum":704837127},{"parent":"TRule_type_name.TAlt1","rule":"TRule_type_name.TAlt1.Rule_type_name_composite1","sum":89568358},{"parent":"TRule_type_name.TAlt2","rule":"TRule_type_name.TAlt2.Block1","sum":704837127},{"parent":"TRule_type_name.TAlt2","rule":"TRule_type_name.TAlt2.Block2","sum":73447647},{"parent":"TRule_type_name.TAlt2.TBlock1","rule":"TRule_type_name.TAlt2.TBlock1.Alt1","sum":27748139},{"parent":"TRule_type_name.TAlt2.TBlock1","rule":"TRule_type_name.TAlt2.TBlock1.Alt2","sum":677088988},{"parent":"TRule_type_name.TAlt2.TBlock1.TAlt1","rule":"TRule_type_name.TAlt2.TBlock1.TAlt1.Rule_type_name_decimal1","sum":27748139},{"parent":"TRule_type_name.TAlt2.TBlock1.TAlt2","rule":"TRule_type_name.TAlt2.TBlock1.TAlt2.Rule_type_name_simple1","sum":677088988},{"parent":"TRule_type_name.TAlt2.TBlock2","rule":"TRule_type_name.TAlt2.TBlock2.Token1","sum":73448705},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Block4","sum":9789399},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Block5","sum":227874},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Block6","sum":10347},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Rule_type_name_or_bind9","sum":10116228},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Token1","sum":10116228},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Token10","sum":10116228},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Token2","sum":10116228},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Token3","sum":10116228},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Token7","sum":10116228},{"parent":"TRule_type_name_callable","rule":"TRule_type_name_callable.Token8","sum":10116228},{"parent":"TRule_type_name_callable.TBlock4","rule":"TRule_type_name_callable.TBlock4.Rule_callable_arg_list1","sum":9789399},{"parent":"TRule_type_name_callable.TBlock5","rule":"TRule_type_name_callable.TBlock5.Token1","sum":227874},{"parent":"TRule_type_name_callable.TBlock6","rule":"TRule_type_name_callable.TBlock6.Rule_callable_arg_list2","sum":10347},{"parent":"TRule_type_name_callable.TBlock6","rule":"TRule_type_name_callable.TBlock6.Token1","sum":10347},{"parent":"TRule_type_name_callable.TBlock6","rule":"TRule_type_name_callable.TBlock6.Token3","sum":10347},{"parent":"TRule_type_name_composite","rule":"TRule_type_name_composite.Block1","sum":106993914},{"parent":"TRule_type_name_composite","rule":"TRule_type_name_composite.Block2","sum":4261399},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt1","sum":33300382},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt10","sum":20856},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt11","sum":451633},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt12","sum":7569},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt13","sum":10116228},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt2","sum":2167125},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt3","sum":26707667},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt4","sum":138745},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt5","sum":25872035},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt6","sum":1529678},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt8","sum":6668423},{"parent":"TRule_type_name_composite.TBlock1","rule":"TRule_type_name_composite.TBlock1.Alt9","sum":13573},{"parent":"TRule_type_name_composite.TBlock1.TAlt1","rule":"TRule_type_name_composite.TBlock1.TAlt1.Rule_type_name_optional1","sum":33300382},{"parent":"TRule_type_name_composite.TBlock1.TAlt10","rule":"TRule_type_name_composite.TBlock1.TAlt10.Rule_type_name_enum1","sum":20856},{"parent":"TRule_type_name_composite.TBlock1.TAlt11","rule":"TRule_type_name_composite.TBlock1.TAlt11.Rule_type_name_resource1","sum":451633},{"parent":"TRule_type_name_composite.TBlock1.TAlt12","rule":"TRule_type_name_composite.TBlock1.TAlt12.Rule_type_name_tagged1","sum":7569},{"parent":"TRule_type_name_composite.TBlock1.TAlt13","rule":"TRule_type_name_composite.TBlock1.TAlt13.Rule_type_name_callable1","sum":10116228},{"parent":"TRule_type_name_composite.TBlock1.TAlt2","rule":"TRule_type_name_composite.TBlock1.TAlt2.Rule_type_name_tuple1","sum":2167125},{"parent":"TRule_type_name_composite.TBlock1.TAlt3","rule":"TRule_type_name_composite.TBlock1.TAlt3.Rule_type_name_struct1","sum":26707667},{"parent":"TRule_type_name_composite.TBlock1.TAlt4","rule":"TRule_type_name_composite.TBlock1.TAlt4.Rule_type_name_variant1","sum":138745},{"parent":"TRule_type_name_composite.TBlock1.TAlt5","rule":"TRule_type_name_composite.TBlock1.TAlt5.Rule_type_name_list1","sum":25872035},{"parent":"TRule_type_name_composite.TBlock1.TAlt6","rule":"TRule_type_name_composite.TBlock1.TAlt6.Rule_type_name_stream1","sum":1529678},{"parent":"TRule_type_name_composite.TBlock1.TAlt8","rule":"TRule_type_name_composite.TBlock1.TAlt8.Rule_type_name_dict1","sum":6668423},{"parent":"TRule_type_name_composite.TBlock1.TAlt9","rule":"TRule_type_name_composite.TBlock1.TAlt9.Rule_type_name_set1","sum":13573},{"parent":"TRule_type_name_composite.TBlock2","rule":"TRule_type_name_composite.TBlock2.Token1","sum":4261402},{"parent":"TRule_type_name_decimal","rule":"TRule_type_name_decimal.Rule_integer_or_bind3","sum":27748139},{"parent":"TRule_type_name_decimal","rule":"TRule_type_name_decimal.Rule_integer_or_bind5","sum":27748139},{"parent":"TRule_type_name_decimal","rule":"TRule_type_name_decimal.Token1","sum":27748139},{"parent":"TRule_type_name_decimal","rule":"TRule_type_name_decimal.Token2","sum":27748139},{"parent":"TRule_type_name_decimal","rule":"TRule_type_name_decimal.Token4","sum":27748139},{"parent":"TRule_type_name_decimal","rule":"TRule_type_name_decimal.Token6","sum":27748139},{"parent":"TRule_type_name_dict","rule":"TRule_type_name_dict.Rule_type_name_or_bind3","sum":6668423},{"parent":"TRule_type_name_dict","rule":"TRule_type_name_dict.Rule_type_name_or_bind5","sum":6668423},{"parent":"TRule_type_name_dict","rule":"TRule_type_name_dict.Token1","sum":6668423},{"parent":"TRule_type_name_dict","rule":"TRule_type_name_dict.Token2","sum":6668423},{"parent":"TRule_type_name_dict","rule":"TRule_type_name_dict.Token4","sum":6668423},{"parent":"TRule_type_name_dict","rule":"TRule_type_name_dict.Token6","sum":6668423},{"parent":"TRule_type_name_enum","rule":"TRule_type_name_enum.Block4","sum":20608},{"parent":"TRule_type_name_enum","rule":"TRule_type_name_enum.Block5","sum":352},{"parent":"TRule_type_name_enum","rule":"TRule_type_name_enum.Rule_type_name_tag3","sum":20856},{"parent":"TRule_type_name_enum","rule":"TRule_type_name_enum.Token1","sum":20856},{"parent":"TRule_type_name_enum","rule":"TRule_type_name_enum.Token2","sum":20856},{"parent":"TRule_type_name_enum","rule":"TRule_type_name_enum.Token6","sum":20856},{"parent":"TRule_type_name_enum.TBlock4","rule":"TRule_type_name_enum.TBlock4.Rule_type_name_tag2","sum":44864},{"parent":"TRule_type_name_enum.TBlock4","rule":"TRule_type_name_enum.TBlock4.Token1","sum":44864},{"parent":"TRule_type_name_enum.TBlock5","rule":"TRule_type_name_enum.TBlock5.Token1","sum":352},{"parent":"TRule_type_name_list","rule":"TRule_type_name_list.Rule_type_name_or_bind3","sum":25872035},{"parent":"TRule_type_name_list","rule":"TRule_type_name_list.Token1","sum":25872035},{"parent":"TRule_type_name_list","rule":"TRule_type_name_list.Token2","sum":25872035},{"parent":"TRule_type_name_list","rule":"TRule_type_name_list.Token4","sum":25872035},{"parent":"TRule_type_name_optional","rule":"TRule_type_name_optional.Rule_type_name_or_bind3","sum":33300382},{"parent":"TRule_type_name_optional","rule":"TRule_type_name_optional.Token1","sum":33300382},{"parent":"TRule_type_name_optional","rule":"TRule_type_name_optional.Token2","sum":33300382},{"parent":"TRule_type_name_optional","rule":"TRule_type_name_optional.Token4","sum":33300382},{"parent":"TRule_type_name_or_bind","rule":"TRule_type_name_or_bind.Alt_type_name_or_bind1","sum":637613195},{"parent":"TRule_type_name_or_bind","rule":"TRule_type_name_or_bind.Alt_type_name_or_bind2","sum":2692737},{"parent":"TRule_type_name_or_bind.TAlt1","rule":"TRule_type_name_or_bind.TAlt1.Rule_type_name1","sum":637613195},{"parent":"TRule_type_name_or_bind.TAlt2","rule":"TRule_type_name_or_bind.TAlt2.Rule_bind_parameter1","sum":2692737},{"parent":"TRule_type_name_resource","rule":"TRule_type_name_resource.Rule_type_name_tag3","sum":451633},{"parent":"TRule_type_name_resource","rule":"TRule_type_name_resource.Token1","sum":451633},{"parent":"TRule_type_name_resource","rule":"TRule_type_name_resource.Token2","sum":451633},{"parent":"TRule_type_name_resource","rule":"TRule_type_name_resource.Token4","sum":451633},{"parent":"TRule_type_name_set","rule":"TRule_type_name_set.Rule_type_name_or_bind3","sum":13573},{"parent":"TRule_type_name_set","rule":"TRule_type_name_set.Token1","sum":13573},{"parent":"TRule_type_name_set","rule":"TRule_type_name_set.Token2","sum":13573},{"parent":"TRule_type_name_set","rule":"TRule_type_name_set.Token4","sum":13573},{"parent":"TRule_type_name_simple","rule":"TRule_type_name_simple.Rule_an_id_pure1","sum":678937497},{"parent":"TRule_type_name_stream","rule":"TRule_type_name_stream.Rule_type_name_or_bind3","sum":1529678},{"parent":"TRule_type_name_stream","rule":"TRule_type_name_stream.Token1","sum":1529678},{"parent":"TRule_type_name_stream","rule":"TRule_type_name_stream.Token2","sum":1529678},{"parent":"TRule_type_name_stream","rule":"TRule_type_name_stream.Token4","sum":1529678},{"parent":"TRule_type_name_struct","rule":"TRule_type_name_struct.Block2","sum":26707667},{"parent":"TRule_type_name_struct","rule":"TRule_type_name_struct.Token1","sum":26707667},{"parent":"TRule_type_name_struct.TBlock2","rule":"TRule_type_name_struct.TBlock2.Alt1","sum":26704759},{"parent":"TRule_type_name_struct.TBlock2","rule":"TRule_type_name_struct.TBlock2.Alt2","sum":2908},{"parent":"TRule_type_name_struct.TBlock2.TAlt1","rule":"TRule_type_name_struct.TBlock2.TAlt1.Block2","sum":26704749},{"parent":"TRule_type_name_struct.TBlock2.TAlt1","rule":"TRule_type_name_struct.TBlock2.TAlt1.Token1","sum":26704759},{"parent":"TRule_type_name_struct.TBlock2.TAlt1","rule":"TRule_type_name_struct.TBlock2.TAlt1.Token3","sum":26704759},{"parent":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2","rule":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.Block2","sum":20382974},{"parent":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2","rule":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.Block3","sum":2062225},{"parent":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2","rule":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.Rule_struct_arg1","sum":26704749},{"parent":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.TBlock2","rule":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.TBlock2.Rule_struct_arg2","sum":87268514},{"parent":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.TBlock2","rule":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.TBlock2.Token1","sum":87268514},{"parent":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.TBlock3","rule":"TRule_type_name_struct.TBlock2.TAlt1.TBlock2.TBlock3.Token1","sum":2062225},{"parent":"TRule_type_name_struct.TBlock2.TAlt2","rule":"TRule_type_name_struct.TBlock2.TAlt2.Token1","sum":2908},{"parent":"TRule_type_name_tag","rule":"TRule_type_name_tag.Alt_type_name_tag1","sum":104704623},{"parent":"TRule_type_name_tag","rule":"TRule_type_name_tag.Alt_type_name_tag2","sum":18411822},{"parent":"TRule_type_name_tag","rule":"TRule_type_name_tag.Alt_type_name_tag3","sum":2640961},{"parent":"TRule_type_name_tag.TAlt1","rule":"TRule_type_name_tag.TAlt1.Rule_id1","sum":104704623},{"parent":"TRule_type_name_tag.TAlt2","rule":"TRule_type_name_tag.TAlt2.Token1","sum":18411822},{"parent":"TRule_type_name_tag.TAlt3","rule":"TRule_type_name_tag.TAlt3.Rule_bind_parameter1","sum":2640961},{"parent":"TRule_type_name_tagged","rule":"TRule_type_name_tagged.Rule_type_name_or_bind3","sum":7569},{"parent":"TRule_type_name_tagged","rule":"TRule_type_name_tagged.Rule_type_name_tag5","sum":7569},{"parent":"TRule_type_name_tagged","rule":"TRule_type_name_tagged.Token1","sum":7569},{"parent":"TRule_type_name_tagged","rule":"TRule_type_name_tagged.Token2","sum":7569},{"parent":"TRule_type_name_tagged","rule":"TRule_type_name_tagged.Token4","sum":7569},{"parent":"TRule_type_name_tagged","rule":"TRule_type_name_tagged.Token6","sum":7569},{"parent":"TRule_type_name_tuple","rule":"TRule_type_name_tuple.Block2","sum":2167125},{"parent":"TRule_type_name_tuple","rule":"TRule_type_name_tuple.Token1","sum":2167125},{"parent":"TRule_type_name_tuple.TBlock2","rule":"TRule_type_name_tuple.TBlock2.Alt1","sum":2167115},{"parent":"TRule_type_name_tuple.TBlock2","rule":"TRule_type_name_tuple.TBlock2.Alt2","sum":10},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1","rule":"TRule_type_name_tuple.TBlock2.TAlt1.Block2","sum":2167115},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1","rule":"TRule_type_name_tuple.TBlock2.TAlt1.Token1","sum":2167115},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1","rule":"TRule_type_name_tuple.TBlock2.TAlt1.Token3","sum":2167115},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2","rule":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.Block2","sum":2165561},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2","rule":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.Block3","sum":63364},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2","rule":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.Rule_type_name_or_bind1","sum":2167115},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.TBlock2","rule":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.TBlock2.Rule_type_name_or_bind2","sum":3348110},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.TBlock2","rule":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.TBlock2.Token1","sum":3348110},{"parent":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.TBlock3","rule":"TRule_type_name_tuple.TBlock2.TAlt1.TBlock2.TBlock3.Token1","sum":63364},{"parent":"TRule_type_name_tuple.TBlock2.TAlt2","rule":"TRule_type_name_tuple.TBlock2.TAlt2.Token1","sum":10},{"parent":"TRule_type_name_variant","rule":"TRule_type_name_variant.Block4","sum":124427},{"parent":"TRule_type_name_variant","rule":"TRule_type_name_variant.Block5","sum":106},{"parent":"TRule_type_name_variant","rule":"TRule_type_name_variant.Rule_variant_arg3","sum":138745},{"parent":"TRule_type_name_variant","rule":"TRule_type_name_variant.Token1","sum":138745},{"parent":"TRule_type_name_variant","rule":"TRule_type_name_variant.Token2","sum":138745},{"parent":"TRule_type_name_variant","rule":"TRule_type_name_variant.Token6","sum":138745},{"parent":"TRule_type_name_variant.TBlock4","rule":"TRule_type_name_variant.TBlock4.Rule_variant_arg2","sum":239208},{"parent":"TRule_type_name_variant.TBlock4","rule":"TRule_type_name_variant.TBlock4.Token1","sum":239208},{"parent":"TRule_type_name_variant.TBlock5","rule":"TRule_type_name_variant.TBlock5.Token1","sum":106},{"parent":"TRule_unary_casual_subexpr","rule":"TRule_unary_casual_subexpr.Block1","sum":16031312931},{"parent":"TRule_unary_casual_subexpr","rule":"TRule_unary_casual_subexpr.Rule_unary_subexpr_suffix2","sum":16031312931},{"parent":"TRule_unary_casual_subexpr.TBlock1","rule":"TRule_unary_casual_subexpr.TBlock1.Alt1","sum":7195652005},{"parent":"TRule_unary_casual_subexpr.TBlock1","rule":"TRule_unary_casual_subexpr.TBlock1.Alt2","sum":8835660926},{"parent":"TRule_unary_casual_subexpr.TBlock1.TAlt1","rule":"TRule_unary_casual_subexpr.TBlock1.TAlt1.Rule_id_expr1","sum":7195652005},{"parent":"TRule_unary_casual_subexpr.TBlock1.TAlt2","rule":"TRule_unary_casual_subexpr.TBlock1.TAlt2.Rule_atom_expr1","sum":8835660926},{"parent":"TRule_unary_op","rule":"TRule_unary_op.Token1","sum":87839446},{"parent":"TRule_unary_subexpr","rule":"TRule_unary_subexpr.Alt_unary_subexpr1","sum":16031312931},{"parent":"TRule_unary_subexpr","rule":"TRule_unary_subexpr.Alt_unary_subexpr2","sum":6334872},{"parent":"TRule_unary_subexpr.TAlt1","rule":"TRule_unary_subexpr.TAlt1.Rule_unary_casual_subexpr1","sum":16031312931},{"parent":"TRule_unary_subexpr.TAlt2","rule":"TRule_unary_subexpr.TAlt2.Rule_json_api_expr1","sum":6334872},{"parent":"TRule_unary_subexpr_suffix","rule":"TRule_unary_subexpr_suffix.Block1","sum":4787377355},{"parent":"TRule_unary_subexpr_suffix.TBlock1","rule":"TRule_unary_subexpr_suffix.TBlock1.Block1","sum":5042894322},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.Alt1","sum":174308643},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.Alt2","sum":2884586421},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.Alt3","sum":1983999258},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt1","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt1.Rule_key_expr1","sum":174308643},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt2","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt2.Rule_invoke_expr1","sum":2884586421},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.Block2","sum":1983999258},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.Token1","sum":1983999258},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.Alt1","sum":3156035},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.Alt2","sum":40591529},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.Alt3","sum":1940251694},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.TAlt1","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.TAlt1.Rule_bind_parameter1","sum":3156035},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.TAlt2","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.TAlt2.Token1","sum":40591529},{"parent":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.TAlt3","rule":"TRule_unary_subexpr_suffix.TBlock1.TBlock1.TAlt3.TBlock2.TAlt3.Rule_an_id_or_type1","sum":1940251694},{"parent":"TRule_use_stmt","rule":"TRule_use_stmt.Rule_cluster_expr2","sum":330553175},{"parent":"TRule_use_stmt","rule":"TRule_use_stmt.Token1","sum":330553175},{"parent":"TRule_using_call_expr","rule":"TRule_using_call_expr.Block1","sum":2788381},{"parent":"TRule_using_call_expr","rule":"TRule_using_call_expr.Rule_invoke_expr2","sum":2788381},{"parent":"TRule_using_call_expr.TBlock1","rule":"TRule_using_call_expr.TBlock1.Alt1","sum":1528230},{"parent":"TRule_using_call_expr.TBlock1","rule":"TRule_using_call_expr.TBlock1.Alt3","sum":1260151},{"parent":"TRule_using_call_expr.TBlock1.TAlt1","rule":"TRule_using_call_expr.TBlock1.TAlt1.Rule_an_id_or_type1","sum":1528230},{"parent":"TRule_using_call_expr.TBlock1.TAlt1","rule":"TRule_using_call_expr.TBlock1.TAlt1.Rule_an_id_or_type3","sum":1528230},{"parent":"TRule_using_call_expr.TBlock1.TAlt1","rule":"TRule_using_call_expr.TBlock1.TAlt1.Token2","sum":1528230},{"parent":"TRule_using_call_expr.TBlock1.TAlt3","rule":"TRule_using_call_expr.TBlock1.TAlt3.Rule_bind_parameter1","sum":1260151},{"parent":"TRule_value_constructor","rule":"TRule_value_constructor.Alt_value_constructor1","sum":32197},{"parent":"TRule_value_constructor","rule":"TRule_value_constructor.Alt_value_constructor2","sum":52564},{"parent":"TRule_value_constructor","rule":"TRule_value_constructor.Alt_value_constructor3","sum":80971},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Rule_expr3","sum":32197},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Rule_expr5","sum":32197},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Rule_expr7","sum":32197},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Token1","sum":32197},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Token2","sum":32197},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Token4","sum":32197},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Token6","sum":32197},{"parent":"TRule_value_constructor.TAlt1","rule":"TRule_value_constructor.TAlt1.Token8","sum":32197},{"parent":"TRule_value_constructor.TAlt2","rule":"TRule_value_constructor.TAlt2.Rule_expr3","sum":52564},{"parent":"TRule_value_constructor.TAlt2","rule":"TRule_value_constructor.TAlt2.Rule_expr5","sum":52564},{"parent":"TRule_value_constructor.TAlt2","rule":"TRule_value_constructor.TAlt2.Token1","sum":52564},{"parent":"TRule_value_constructor.TAlt2","rule":"TRule_value_constructor.TAlt2.Token2","sum":52564},{"parent":"TRule_value_constructor.TAlt2","rule":"TRule_value_constructor.TAlt2.Token4","sum":52564},{"parent":"TRule_value_constructor.TAlt2","rule":"TRule_value_constructor.TAlt2.Token6","sum":52564},{"parent":"TRule_value_constructor.TAlt3","rule":"TRule_value_constructor.TAlt3.Rule_expr3","sum":80971},{"parent":"TRule_value_constructor.TAlt3","rule":"TRule_value_constructor.TAlt3.Rule_expr5","sum":80971},{"parent":"TRule_value_constructor.TAlt3","rule":"TRule_value_constructor.TAlt3.Token1","sum":80971},{"parent":"TRule_value_constructor.TAlt3","rule":"TRule_value_constructor.TAlt3.Token2","sum":80971},{"parent":"TRule_value_constructor.TAlt3","rule":"TRule_value_constructor.TAlt3.Token4","sum":80971},{"parent":"TRule_value_constructor.TAlt3","rule":"TRule_value_constructor.TAlt3.Token6","sum":80971},{"parent":"TRule_values_source","rule":"TRule_values_source.Alt_values_source1","sum":1089320},{"parent":"TRule_values_source","rule":"TRule_values_source.Alt_values_source2","sum":208639933},{"parent":"TRule_values_source.TAlt1","rule":"TRule_values_source.TAlt1.Rule_values_stmt1","sum":1089320},{"parent":"TRule_values_source.TAlt2","rule":"TRule_values_source.TAlt2.Rule_select_stmt1","sum":208639933},{"parent":"TRule_values_source_row","rule":"TRule_values_source_row.Rule_expr_list2","sum":9071866},{"parent":"TRule_values_source_row","rule":"TRule_values_source_row.Token1","sum":9071866},{"parent":"TRule_values_source_row","rule":"TRule_values_source_row.Token3","sum":9071866},{"parent":"TRule_values_source_row_list","rule":"TRule_values_source_row_list.Block2","sum":486688},{"parent":"TRule_values_source_row_list","rule":"TRule_values_source_row_list.Rule_values_source_row1","sum":1259083},{"parent":"TRule_values_source_row_list.TBlock2","rule":"TRule_values_source_row_list.TBlock2.Rule_values_source_row2","sum":7812783},{"parent":"TRule_values_source_row_list.TBlock2","rule":"TRule_values_source_row_list.TBlock2.Token1","sum":7812783},{"parent":"TRule_values_stmt","rule":"TRule_values_stmt.Rule_values_source_row_list2","sum":1259083},{"parent":"TRule_values_stmt","rule":"TRule_values_stmt.Token1","sum":1259083},{"parent":"TRule_variant_arg","rule":"TRule_variant_arg.Block1","sum":355197},{"parent":"TRule_variant_arg","rule":"TRule_variant_arg.Rule_type_name_or_bind2","sum":18415857},{"parent":"TRule_variant_arg.TBlock1","rule":"TRule_variant_arg.TBlock1.Rule_type_name_tag1","sum":355197},{"parent":"TRule_variant_arg.TBlock1","rule":"TRule_variant_arg.TBlock1.Token2","sum":355197},{"parent":"TRule_view_name","rule":"TRule_view_name.Alt_view_name1","sum":1320610},{"parent":"TRule_view_name.TAlt1","rule":"TRule_view_name.TAlt1.Rule_an_id1","sum":1320610},{"parent":"TRule_when_expr","rule":"TRule_when_expr.Rule_expr2","sum":158729543},{"parent":"TRule_when_expr","rule":"TRule_when_expr.Rule_expr4","sum":158729543},{"parent":"TRule_when_expr","rule":"TRule_when_expr.Token1","sum":158729543},{"parent":"TRule_when_expr","rule":"TRule_when_expr.Token3","sum":158729543},{"parent":"TRule_window_clause","rule":"TRule_window_clause.Rule_window_definition_list2","sum":13625726},{"parent":"TRule_window_clause","rule":"TRule_window_clause.Token1","sum":13625726},{"parent":"TRule_window_definition","rule":"TRule_window_definition.Rule_new_window_name1","sum":14203555},{"parent":"TRule_window_definition","rule":"TRule_window_definition.Rule_window_specification3","sum":14203555},{"parent":"TRule_window_definition","rule":"TRule_window_definition.Token2","sum":14203555},{"parent":"TRule_window_definition_list","rule":"TRule_window_definition_list.Block2","sum":437513},{"parent":"TRule_window_definition_list","rule":"TRule_window_definition_list.Rule_window_definition1","sum":13625726},{"parent":"TRule_window_definition_list.TBlock2","rule":"TRule_window_definition_list.TBlock2.Rule_window_definition2","sum":577829},{"parent":"TRule_window_definition_list.TBlock2","rule":"TRule_window_definition_list.TBlock2.Token1","sum":577829},{"parent":"TRule_window_frame_between","rule":"TRule_window_frame_between.Rule_window_frame_bound2","sum":2323616},{"parent":"TRule_window_frame_between","rule":"TRule_window_frame_between.Rule_window_frame_bound4","sum":2323616},{"parent":"TRule_window_frame_between","rule":"TRule_window_frame_between.Token1","sum":2323616},{"parent":"TRule_window_frame_between","rule":"TRule_window_frame_between.Token3","sum":2323616},{"parent":"TRule_window_frame_bound","rule":"TRule_window_frame_bound.Alt_window_frame_bound1","sum":1330552},{"parent":"TRule_window_frame_bound","rule":"TRule_window_frame_bound.Alt_window_frame_bound2","sum":3374715},{"parent":"TRule_window_frame_bound.TAlt1","rule":"TRule_window_frame_bound.TAlt1.Token1","sum":1330552},{"parent":"TRule_window_frame_bound.TAlt1","rule":"TRule_window_frame_bound.TAlt1.Token2","sum":1330552},{"parent":"TRule_window_frame_bound.TAlt2","rule":"TRule_window_frame_bound.TAlt2.Block1","sum":3374715},{"parent":"TRule_window_frame_bound.TAlt2","rule":"TRule_window_frame_bound.TAlt2.Token2","sum":3374715},{"parent":"TRule_window_frame_bound.TAlt2.TBlock1","rule":"TRule_window_frame_bound.TAlt2.TBlock1.Alt1","sum":1115948},{"parent":"TRule_window_frame_bound.TAlt2.TBlock1","rule":"TRule_window_frame_bound.TAlt2.TBlock1.Alt2","sum":2258767},{"parent":"TRule_window_frame_bound.TAlt2.TBlock1.TAlt1","rule":"TRule_window_frame_bound.TAlt2.TBlock1.TAlt1.Rule_expr1","sum":1115948},{"parent":"TRule_window_frame_bound.TAlt2.TBlock1.TAlt2","rule":"TRule_window_frame_bound.TAlt2.TBlock1.TAlt2.Token1","sum":2258767},{"parent":"TRule_window_frame_clause","rule":"TRule_window_frame_clause.Rule_window_frame_extent2","sum":2381651},{"parent":"TRule_window_frame_clause","rule":"TRule_window_frame_clause.Rule_window_frame_units1","sum":2381651},{"parent":"TRule_window_frame_extent","rule":"TRule_window_frame_extent.Alt_window_frame_extent1","sum":58035},{"parent":"TRule_window_frame_extent","rule":"TRule_window_frame_extent.Alt_window_frame_extent2","sum":2323616},{"parent":"TRule_window_frame_extent.TAlt1","rule":"TRule_window_frame_extent.TAlt1.Rule_window_frame_bound1","sum":58035},{"parent":"TRule_window_frame_extent.TAlt2","rule":"TRule_window_frame_extent.TAlt2.Rule_window_frame_between1","sum":2323616},{"parent":"TRule_window_frame_units","rule":"TRule_window_frame_units.Token1","sum":2381651},{"parent":"TRule_window_name","rule":"TRule_window_name.Rule_an_id_window1","sum":46794903},{"parent":"TRule_window_name_or_specification","rule":"TRule_window_name_or_specification.Alt_window_name_or_specification1","sum":32591348},{"parent":"TRule_window_name_or_specification","rule":"TRule_window_name_or_specification.Alt_window_name_or_specification2","sum":12886037},{"parent":"TRule_window_name_or_specification.TAlt1","rule":"TRule_window_name_or_specification.TAlt1.Rule_window_name1","sum":32591348},{"parent":"TRule_window_name_or_specification.TAlt2","rule":"TRule_window_name_or_specification.TAlt2.Rule_window_specification1","sum":12886037},{"parent":"TRule_window_order_clause","rule":"TRule_window_order_clause.Rule_order_by_clause1","sum":19090522},{"parent":"TRule_window_partition_clause","rule":"TRule_window_partition_clause.Block2","sum":51981},{"parent":"TRule_window_partition_clause","rule":"TRule_window_partition_clause.Rule_named_expr_list4","sum":21880553},{"parent":"TRule_window_partition_clause","rule":"TRule_window_partition_clause.Token1","sum":21880553},{"parent":"TRule_window_partition_clause","rule":"TRule_window_partition_clause.Token3","sum":21880553},{"parent":"TRule_window_partition_clause.TBlock2","rule":"TRule_window_partition_clause.TBlock2.Token1","sum":51981},{"parent":"TRule_window_specification","rule":"TRule_window_specification.Rule_window_specification_details2","sum":27089592},{"parent":"TRule_window_specification","rule":"TRule_window_specification.Token1","sum":27089592},{"parent":"TRule_window_specification","rule":"TRule_window_specification.Token3","sum":27089592},{"parent":"TRule_window_specification_details","rule":"TRule_window_specification_details.Block2","sum":21880552},{"parent":"TRule_window_specification_details","rule":"TRule_window_specification_details.Block3","sum":19090522},{"parent":"TRule_window_specification_details","rule":"TRule_window_specification_details.Block4","sum":2381651},{"parent":"TRule_window_specification_details.TBlock2","rule":"TRule_window_specification_details.TBlock2.Rule_window_partition_clause1","sum":21880552},{"parent":"TRule_window_specification_details.TBlock3","rule":"TRule_window_specification_details.TBlock3.Rule_window_order_clause1","sum":19090522},{"parent":"TRule_window_specification_details.TBlock4","rule":"TRule_window_specification_details.TBlock4.Rule_window_frame_clause1","sum":2381651},{"parent":"TRule_without_column_list","rule":"TRule_without_column_list.Block2","sum":9254793},{"parent":"TRule_without_column_list","rule":"TRule_without_column_list.Block3","sum":1324200},{"parent":"TRule_without_column_list","rule":"TRule_without_column_list.Rule_without_column_name1","sum":25026920},{"parent":"TRule_without_column_list.TBlock2","rule":"TRule_without_column_list.TBlock2.Rule_without_column_name2","sum":29350935},{"parent":"TRule_without_column_list.TBlock2","rule":"TRule_without_column_list.TBlock2.Token1","sum":29350935},{"parent":"TRule_without_column_list.TBlock3","rule":"TRule_without_column_list.TBlock3.Token1","sum":1324200},{"parent":"TRule_without_column_name","rule":"TRule_without_column_name.Alt_without_column_name1","sum":30955091},{"parent":"TRule_without_column_name","rule":"TRule_without_column_name.Alt_without_column_name2","sum":23422764},{"parent":"TRule_without_column_name.TAlt1","rule":"TRule_without_column_name.TAlt1.Rule_an_id1","sum":30955091},{"parent":"TRule_without_column_name.TAlt1","rule":"TRule_without_column_name.TAlt1.Rule_an_id3","sum":30955091},{"parent":"TRule_without_column_name.TAlt1","rule":"TRule_without_column_name.TAlt1.Token2","sum":30955091},{"parent":"TRule_without_column_name.TAlt2","rule":"TRule_without_column_name.TAlt2.Rule_an_id_without1","sum":23422764},{"parent":"TRule_xor_subexpr","rule":"TRule_xor_subexpr.Block2","sum":1098405657},{"parent":"TRule_xor_subexpr","rule":"TRule_xor_subexpr.Rule_eq_subexpr1","sum":14301321628},{"parent":"TRule_xor_subexpr.TBlock2","rule":"TRule_xor_subexpr.TBlock2.Rule_cond_expr1","sum":1098405657},{"parent":"TSQLv1ParserAST","rule":"TSQLv1ParserAST.Rule_sql_query","sum":321178940},{"parent":"TYPE","rule":"BIGINT","sum":6932},{"parent":"TYPE","rule":"BOOL","sum":109593},{"parent":"TYPE","rule":"BYTEs","sum":1},{"parent":"TYPE","rule":"BigInt","sum":210},{"parent":"TYPE","rule":"Bool","sum":9328918},{"parent":"TYPE","rule":"Bytes","sum":428005},{"parent":"TYPE","rule":"DATE","sum":1262181},{"parent":"TYPE","rule":"DATETIME","sum":66984},{"parent":"TYPE","rule":"DATETime","sum":2},{"parent":"TYPE","rule":"DATEtIME","sum":1},{"parent":"TYPE","rule":"DATEtime","sum":34},{"parent":"TYPE","rule":"DAte","sum":9072},{"parent":"TYPE","rule":"DAteTime","sum":54},{"parent":"TYPE","rule":"DAtetime","sum":650},{"parent":"TYPE","rule":"DOUBLE","sum":1363060},{"parent":"TYPE","rule":"DOUBLe","sum":1},{"parent":"TYPE","rule":"DOUBle","sum":1},{"parent":"TYPE","rule":"DOUble","sum":3},{"parent":"TYPE","rule":"DOuble","sum":2183},{"parent":"TYPE","rule":"DaTeTime","sum":1},{"parent":"TYPE","rule":"Date","sum":20697406},{"parent":"TYPE","rule":"Date32","sum":65},{"parent":"TYPE","rule":"DateTIME","sum":21},{"parent":"TYPE","rule":"DateTIme","sum":112},{"parent":"TYPE","rule":"DateTime","sum":5026810},{"parent":"TYPE","rule":"DateTime64","sum":8},{"parent":"TYPE","rule":"DatetIME","sum":35},{"parent":"TYPE","rule":"Datetime","sum":3265600},{"parent":"TYPE","rule":"Datetime64","sum":38},{"parent":"TYPE","rule":"DoubLe","sum":13},{"parent":"TYPE","rule":"Double","sum":30150647},{"parent":"TYPE","rule":"EmptyDict","sum":28},{"parent":"TYPE","rule":"EmptyList","sum":28},{"parent":"TYPE","rule":"FLOAT","sum":188567},{"parent":"TYPE","rule":"FLoat","sum":3386},{"parent":"TYPE","rule":"FlOAT","sum":15},{"parent":"TYPE","rule":"FloaT","sum":338},{"parent":"TYPE","rule":"Float","sum":7111544},{"parent":"TYPE","rule":"Generic","sum":3},{"parent":"TYPE","rule":"INT","sum":410042},{"parent":"TYPE","rule":"INT16","sum":9417},{"parent":"TYPE","rule":"INT32","sum":140859},{"parent":"TYPE","rule":"INT64","sum":4166541},{"parent":"TYPE","rule":"INT8","sum":1862},{"parent":"TYPE","rule":"INTEGER","sum":73375},{"parent":"TYPE","rule":"INTERVAL","sum":10426},{"parent":"TYPE","rule":"INt16","sum":1},{"parent":"TYPE","rule":"INt32","sum":1191},{"parent":"TYPE","rule":"INt64","sum":37874},{"parent":"TYPE","rule":"InT32","sum":1},{"parent":"TYPE","rule":"Int","sum":524499},{"parent":"TYPE","rule":"Int16","sum":914040},{"parent":"TYPE","rule":"Int32","sum":13884136},{"parent":"TYPE","rule":"Int64","sum":47272161},{"parent":"TYPE","rule":"Int8","sum":1029823},{"parent":"TYPE","rule":"Integer","sum":467686},{"parent":"TYPE","rule":"Interval","sum":205400},{"parent":"TYPE","rule":"Interval64","sum":34},{"parent":"TYPE","rule":"JSON","sum":1757583},{"parent":"TYPE","rule":"JSONDocument","sum":265},{"parent":"TYPE","rule":"JSOn","sum":1},{"parent":"TYPE","rule":"JSon","sum":2},{"parent":"TYPE","rule":"Json","sum":5507192},{"parent":"TYPE","rule":"JsonDocument","sum":16890},{"parent":"TYPE","rule":"Jsondocument","sum":25},{"parent":"TYPE","rule":"PgBool","sum":20},{"parent":"TYPE","rule":"PgBox","sum":2},{"parent":"TYPE","rule":"PgByteA","sum":16},{"parent":"TYPE","rule":"PgCString","sum":19},{"parent":"TYPE","rule":"PgDate","sum":85},{"parent":"TYPE","rule":"PgFloat4","sum":31},{"parent":"TYPE","rule":"PgFloat8","sum":31},{"parent":"TYPE","rule":"PgInt","sum":1},{"parent":"TYPE","rule":"PgInt2","sum":97},{"parent":"TYPE","rule":"PgInt4","sum":37},{"parent":"TYPE","rule":"PgInt8","sum":32},{"parent":"TYPE","rule":"PgInterval","sum":238},{"parent":"TYPE","rule":"PgMoney","sum":2},{"parent":"TYPE","rule":"PgName","sum":2},{"parent":"TYPE","rule":"PgNumeric","sum":10},{"parent":"TYPE","rule":"PgPoint","sum":1296},{"parent":"TYPE","rule":"PgPolygon","sum":651},{"parent":"TYPE","rule":"PgText","sum":429},{"parent":"TYPE","rule":"PgTimestamp","sum":1933},{"parent":"TYPE","rule":"PgVarChar","sum":1},{"parent":"TYPE","rule":"PgVarchar","sum":231},{"parent":"TYPE","rule":"STRING","sum":2680222},{"parent":"TYPE","rule":"STRINg","sum":3},{"parent":"TYPE","rule":"STRing","sum":3},{"parent":"TYPE","rule":"STring","sum":1330},{"parent":"TYPE","rule":"StrINg","sum":45},{"parent":"TYPE","rule":"StrinG","sum":27},{"parent":"TYPE","rule":"String","sum":335692096},{"parent":"TYPE","rule":"TEXT","sum":21570},{"parent":"TYPE","rule":"TIMESTAMP","sum":319390},{"parent":"TYPE","rule":"TINYINT","sum":1},{"parent":"TYPE","rule":"TZDate","sum":30},{"parent":"TYPE","rule":"TZDateTime","sum":1},{"parent":"TYPE","rule":"TZDatetime","sum":25},{"parent":"TYPE","rule":"TZtimestamp","sum":1},{"parent":"TYPE","rule":"Text","sum":204450},{"parent":"TYPE","rule":"TimeStamp","sum":294978},{"parent":"TYPE","rule":"Timestamp","sum":6007260},{"parent":"TYPE","rule":"Timestamp64","sum":488},{"parent":"TYPE","rule":"TzDATE","sum":5},{"parent":"TYPE","rule":"TzDate","sum":48936},{"parent":"TYPE","rule":"TzDateTime","sum":43711},{"parent":"TYPE","rule":"TzDatetime","sum":670798},{"parent":"TYPE","rule":"TzTimeStamp","sum":6},{"parent":"TYPE","rule":"TzTimestamp","sum":8231},{"parent":"TYPE","rule":"TzTimestamp64","sum":1},{"parent":"TYPE","rule":"Tzdate","sum":5},{"parent":"TYPE","rule":"Tzdatetime","sum":4},{"parent":"TYPE","rule":"UINT16","sum":1256},{"parent":"TYPE","rule":"UINT32","sum":423512},{"parent":"TYPE","rule":"UINT64","sum":586047},{"parent":"TYPE","rule":"UINT8","sum":160},{"parent":"TYPE","rule":"UINt32","sum":44},{"parent":"TYPE","rule":"UINt64","sum":416},{"parent":"TYPE","rule":"UINt8","sum":24},{"parent":"TYPE","rule":"UInt16","sum":130653},{"parent":"TYPE","rule":"UInt32","sum":7368130},{"parent":"TYPE","rule":"UInt64","sum":9491372},{"parent":"TYPE","rule":"UInt8","sum":153048},{"parent":"TYPE","rule":"UNIT","sum":756},{"parent":"TYPE","rule":"UTF8","sum":269828},{"parent":"TYPE","rule":"UTf8","sum":142},{"parent":"TYPE","rule":"UUID","sum":1247896},{"parent":"TYPE","rule":"UiNt32","sum":4},{"parent":"TYPE","rule":"Uint16","sum":332190},{"parent":"TYPE","rule":"Uint32","sum":18462946},{"parent":"TYPE","rule":"Uint64","sum":32896918},{"parent":"TYPE","rule":"Uint8","sum":2325435},{"parent":"TYPE","rule":"Unit","sum":1123},{"parent":"TYPE","rule":"Utf8","sum":14459445},{"parent":"TYPE","rule":"Uuid","sum":44029},{"parent":"TYPE","rule":"VARCHAR","sum":518834},{"parent":"TYPE","rule":"Varchar","sum":2},{"parent":"TYPE","rule":"Void","sum":10821},{"parent":"TYPE","rule":"XML","sum":21},{"parent":"TYPE","rule":"YSON","sum":226297},{"parent":"TYPE","rule":"YSon","sum":277},{"parent":"TYPE","rule":"Yson","sum":17709535},{"parent":"TYPE","rule":"_PgMoney","sum":3},{"parent":"TYPE","rule":"bigint","sum":8977},{"parent":"TYPE","rule":"bool","sum":933913},{"parent":"TYPE","rule":"bytes","sum":34732},{"parent":"TYPE","rule":"dATE","sum":1},{"parent":"TYPE","rule":"daTE","sum":5},{"parent":"TYPE","rule":"date","sum":32529879},{"parent":"TYPE","rule":"date32","sum":41},{"parent":"TYPE","rule":"dateTIME","sum":8},{"parent":"TYPE","rule":"dateTime","sum":44165},{"parent":"TYPE","rule":"datetime","sum":7090167},{"parent":"TYPE","rule":"datetime64","sum":61},{"parent":"TYPE","rule":"double","sum":6955432},{"parent":"TYPE","rule":"emptyList","sum":1},{"parent":"TYPE","rule":"float","sum":4706820},{"parent":"TYPE","rule":"generic","sum":2},{"parent":"TYPE","rule":"iNT","sum":1},{"parent":"TYPE","rule":"iNT64","sum":25},{"parent":"TYPE","rule":"inT64","sum":260},{"parent":"TYPE","rule":"int","sum":1125005},{"parent":"TYPE","rule":"int16","sum":78359},{"parent":"TYPE","rule":"int32","sum":3222384},{"parent":"TYPE","rule":"int64","sum":8453909},{"parent":"TYPE","rule":"int8","sum":41932},{"parent":"TYPE","rule":"integer","sum":136328},{"parent":"TYPE","rule":"interval","sum":408838},{"parent":"TYPE","rule":"json","sum":1060285},{"parent":"TYPE","rule":"json_document","sum":1},{"parent":"TYPE","rule":"jsondocument","sum":1},{"parent":"TYPE","rule":"pgDate","sum":22},{"parent":"TYPE","rule":"pg_name","sum":2},{"parent":"TYPE","rule":"pgbigint","sum":1},{"parent":"TYPE","rule":"pgbool","sum":18},{"parent":"TYPE","rule":"pgdate","sum":14},{"parent":"TYPE","rule":"pgfloat8","sum":2},{"parent":"TYPE","rule":"pgint","sum":366},{"parent":"TYPE","rule":"pgint2","sum":6},{"parent":"TYPE","rule":"pgint4","sum":41},{"parent":"TYPE","rule":"pgint8","sum":1},{"parent":"TYPE","rule":"pginteger","sum":1},{"parent":"TYPE","rule":"pginterval","sum":368},{"parent":"TYPE","rule":"pgnumeric","sum":5},{"parent":"TYPE","rule":"pgoid","sum":1},{"parent":"TYPE","rule":"pgtext","sum":76},{"parent":"TYPE","rule":"pgtimestamp","sum":20},{"parent":"TYPE","rule":"sTRING","sum":16},{"parent":"TYPE","rule":"smallint","sum":1},{"parent":"TYPE","rule":"strINg","sum":14},{"parent":"TYPE","rule":"striNg","sum":1},{"parent":"TYPE","rule":"strinG","sum":73},{"parent":"TYPE","rule":"string","sum":45963463},{"parent":"TYPE","rule":"text","sum":4589439},{"parent":"TYPE","rule":"timeStamp","sum":80},{"parent":"TYPE","rule":"timestamp","sum":21925377},{"parent":"TYPE","rule":"timestamp64","sum":12},{"parent":"TYPE","rule":"tinyint","sum":3},{"parent":"TYPE","rule":"tzDate","sum":1},{"parent":"TYPE","rule":"tzDateTime","sum":3},{"parent":"TYPE","rule":"tzDatetime","sum":30},{"parent":"TYPE","rule":"tzTimestamp","sum":709},{"parent":"TYPE","rule":"tzdate","sum":19},{"parent":"TYPE","rule":"tzdatetime","sum":67},{"parent":"TYPE","rule":"tzdatetime64","sum":2},{"parent":"TYPE","rule":"tztimestamp","sum":32},{"parent":"TYPE","rule":"tztimestamp64","sum":3},{"parent":"TYPE","rule":"uINT32","sum":21},{"parent":"TYPE","rule":"uInt32","sum":12046},{"parent":"TYPE","rule":"uInt64","sum":2534},{"parent":"TYPE","rule":"uInt8","sum":52},{"parent":"TYPE","rule":"uint16","sum":27461},{"parent":"TYPE","rule":"uint32","sum":5327264},{"parent":"TYPE","rule":"uint64","sum":8708288},{"parent":"TYPE","rule":"uint8","sum":160798},{"parent":"TYPE","rule":"unit","sum":694461},{"parent":"TYPE","rule":"utf8","sum":4655490},{"parent":"TYPE","rule":"uuid","sum":2992838},{"parent":"TYPE","rule":"varchar","sum":58394},{"parent":"TYPE","rule":"void","sum":1},{"parent":"TYPE","rule":"xml","sum":32763},{"parent":"TYPE","rule":"yaml","sum":145},{"parent":"TYPE","rule":"yson","sum":1126517}] diff --git a/yql/essentials/udfs/language/yql/test/canondata/result.json b/yql/essentials/udfs/language/yql/test/canondata/result.json index 38975dcc8d3a..2a589612bf06 100644 --- a/yql/essentials/udfs/language/yql/test/canondata/result.json +++ b/yql/essentials/udfs/language/yql/test/canondata/result.json @@ -19,6 +19,11 @@ "uri": "file://test.test_ExtractInsertHints_/results.txt" } ], + "test.test[ExtractKeywords]": [ + { + "uri": "file://test.test_ExtractKeywords_/results.txt" + } + ], "test.test[ExtractPragmas]": [ { "uri": "file://test.test_ExtractPragmas_/results.txt" diff --git a/yql/essentials/udfs/language/yql/test/canondata/test.test_ExtractKeywords_/results.txt b/yql/essentials/udfs/language/yql/test/canondata/test.test_ExtractKeywords_/results.txt new file mode 100644 index 000000000000..d638a52c1392 --- /dev/null +++ b/yql/essentials/udfs/language/yql/test/canondata/test.test_ExtractKeywords_/results.txt @@ -0,0 +1,78 @@ +[ + { + "Write" = [ + { + "Type" = [ + "ListType"; + [ + "StructType"; + [ + [ + "q"; + [ + "DataType"; + "String" + ] + ]; + [ + "column1"; + [ + "OptionalType"; + [ + "ListType"; + [ + "TupleType"; + [ + [ + "DataType"; + "String" + ]; + [ + "DataType"; + "String" + ]; + [ + "DataType"; + "Uint64" + ] + ] + ] + ] + ] + ] + ] + ] + ]; + "Data" = [ + [ + "select 1 as x union all select 2 as x"; + [ + [ + [ + "KEYWORD"; + "ALL"; + "1" + ]; + [ + "KEYWORD"; + "AS"; + "2" + ]; + [ + "KEYWORD"; + "SELECT"; + "2" + ]; + [ + "KEYWORD"; + "UNION"; + "1" + ] + ] + ] + ] + ] + } + ] + } +] \ No newline at end of file diff --git a/yql/essentials/udfs/language/yql/test/cases/ExtractKeywords.sql b/yql/essentials/udfs/language/yql/test/cases/ExtractKeywords.sql new file mode 100644 index 000000000000..c3346ae3c276 --- /dev/null +++ b/yql/essentials/udfs/language/yql/test/cases/ExtractKeywords.sql @@ -0,0 +1,6 @@ +SELECT + q,ListSort(ListFilter(YqlLang::RuleFreq(q),($x)->($x.0 in ("KEYWORD")))) +FROM (VALUES + ("select 1 as x union all select 2 as x") +) AS a(q) +order by q diff --git a/yql/essentials/udfs/language/yql/ya.make b/yql/essentials/udfs/language/yql/ya.make index 5c951c1cc16e..e0c16d6f5daf 100644 --- a/yql/essentials/udfs/language/yql/ya.make +++ b/yql/essentials/udfs/language/yql/ya.make @@ -23,6 +23,7 @@ PEERDIR( yql/essentials/sql/v1/proto_parser/antlr4_ansi yql/essentials/sql/pg_dummy yql/essentials/sql/v1/format + yql/essentials/sql/v1/reflect library/cpp/protobuf/util ) diff --git a/yql/essentials/udfs/language/yql/yql_language_udf.cpp b/yql/essentials/udfs/language/yql/yql_language_udf.cpp index 6460031a6abe..23bc092099c0 100644 --- a/yql/essentials/udfs/language/yql/yql_language_udf.cpp +++ b/yql/essentials/udfs/language/yql/yql_language_udf.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -31,11 +32,17 @@ class TRuleFreqVisitor { TRuleFreqVisitor(TContext& ctx) : Translation(ctx) { + KeywordNames = NSQLReflect::LoadLexerGrammar().KeywordNames; } void Visit(const NProtoBuf::Message& msg) { const NProtoBuf::Descriptor* descr = msg.GetDescriptor(); if (descr == TToken::GetDescriptor()) { + const auto& token = dynamic_cast(msg); + auto upper = to_upper(token.GetValue()); + if (KeywordNames.contains(upper)) { + Freqs[std::make_pair("KEYWORD", upper)] += 1; + } return; } else if (descr == TRule_use_stmt::GetDescriptor()) { VisitUseStmt(dynamic_cast(msg)); @@ -285,6 +292,7 @@ class TRuleFreqVisitor { THashMap, ui64> Freqs; TRuleFreqTranslation Translation; + THashSet KeywordNames; }; SIMPLE_UDF(TObfuscate, TOptional(TAutoMap)) { From 974186e89fb713c12bed34c21a8fccd099be7fe9 Mon Sep 17 00:00:00 2001 From: zverevgeny Date: Tue, 8 Apr 2025 22:35:09 +0300 Subject: [PATCH 066/454] helper for combinatorial tests (#16954) --- .../columnshard/test_helper/test_combinator.h | 80 +++++++++++++++++++ .../ut_schema/ut_columnshard_schema.cpp | 19 +---- 2 files changed, 81 insertions(+), 18 deletions(-) create mode 100644 ydb/core/tx/columnshard/test_helper/test_combinator.h diff --git a/ydb/core/tx/columnshard/test_helper/test_combinator.h b/ydb/core/tx/columnshard/test_helper/test_combinator.h new file mode 100644 index 000000000000..d98519465e44 --- /dev/null +++ b/ydb/core/tx/columnshard/test_helper/test_combinator.h @@ -0,0 +1,80 @@ +#pragma once + + +#define Y_UNIT_TEST_COMBINATOR_1(BaseName, Flag1) \ + template void BaseName(NUnitTest::TTestContext&); \ + struct TTestRegistration##BaseName { \ + TTestRegistration##BaseName() { \ + TCurrentTest::AddTest(#BaseName "-" #Flag1, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1, static_cast(&BaseName), false); \ + } \ + }; \ + static TTestRegistration##BaseName testRegistration##BaseName; \ + template \ + void BaseName(NUnitTest::TTestContext&) + +#define Y_UNIT_TEST_COMBINATOR_2(BaseName, Flag1, Flag2) \ + template void BaseName(NUnitTest::TTestContext&); \ + struct TTestRegistration##BaseName { \ + TTestRegistration##BaseName() { \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2, static_cast(&BaseName), false); \ + } \ + }; \ + static TTestRegistration##BaseName testRegistration##BaseName; \ + template \ + void BaseName(NUnitTest::TTestContext&) + + +#define Y_UNIT_TEST_COMBINATOR_3(BaseName, Flag1, Flag2, Flag3) \ + template void BaseName(NUnitTest::TTestContext&); \ + struct TTestRegistration##BaseName { \ + TTestRegistration##BaseName() { \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ + } \ + }; \ + static TTestRegistration##BaseName testRegistration##BaseName; \ + template \ + void BaseName(NUnitTest::TTestContext&) + +#define Y_UNIT_TEST_COMBINATOR_4(BaseName, Flag1, Flag2, Flag3, Flag4) \ + template void BaseName(NUnitTest::TTestContext&); \ + struct TTestRegistration##BaseName { \ + TTestRegistration##BaseName() { \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "-" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "-" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "-" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "-" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "+" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "+" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "+" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "+" #Flag3 "-" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "-" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "-" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "-" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "-" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "+" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "+" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "+" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "+" #Flag3 "+" #Flag4, static_cast(&BaseName), false); \ + } \ + }; \ + static TTestRegistration##BaseName testRegistration##BaseName; \ + template \ + void BaseName(NUnitTest::TTestContext&) + + +#define Y_UNIT_TEST_DUO Y_UNIT_TEST_COMBINATOR_1 +#define Y_UNIT_TEST_QUATRO Y_UNIT_TEST_COMBINATOR_2 +#define Y_UNIT_TEST_OCTO Y_UNIT_TEST_COMBINATOR_3 +#define Y_UNIT_TEST_SEDECIM Y_UNIT_TEST_COMBINATOR_4 + diff --git a/ydb/core/tx/columnshard/ut_schema/ut_columnshard_schema.cpp b/ydb/core/tx/columnshard/ut_schema/ut_columnshard_schema.cpp index 731fe98cc86a..99c6634511dc 100644 --- a/ydb/core/tx/columnshard/ut_schema/ut_columnshard_schema.cpp +++ b/ydb/core/tx/columnshard/ut_schema/ut_columnshard_schema.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -20,24 +21,6 @@ #include #include -#define Y_UNIT_TEST_OCTO(BaseName, Flag1, Flag2, Flag3) \ - template void BaseName(NUnitTest::TTestContext&); \ - struct TTestRegistration##BaseName { \ - TTestRegistration##BaseName() { \ - TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ - TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ - TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ - TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "-" #Flag3, static_cast(&BaseName), false); \ - TCurrentTest::AddTest(#BaseName "-" #Flag1 "-" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ - TCurrentTest::AddTest(#BaseName "+" #Flag1 "-" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ - TCurrentTest::AddTest(#BaseName "-" #Flag1 "+" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ - TCurrentTest::AddTest(#BaseName "+" #Flag1 "+" #Flag2 "+" #Flag3, static_cast(&BaseName), false); \ - } \ - }; \ - static TTestRegistration##BaseName testRegistration##BaseName; \ - template \ - void BaseName(NUnitTest::TTestContext&) - namespace NKikimr { From 27b0bd14698f3db17c8a2c3fd040daeab91c3075 Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Tue, 8 Apr 2025 23:11:49 +0300 Subject: [PATCH 067/454] Intermediate changes commit_hash:bf469eb9f85927cfef8fb4151f740c34dd092add --- .../driver/distributed_table_commands.cpp | 53 +++++++++++++------ .../driver/distributed_table_commands.h | 10 +--- yt/yt/client/driver/driver.cpp | 9 ++-- 3 files changed, 44 insertions(+), 28 deletions(-) diff --git a/yt/yt/client/driver/distributed_table_commands.cpp b/yt/yt/client/driver/distributed_table_commands.cpp index 0f26f86cbf06..c40869201ede 100644 --- a/yt/yt/client/driver/distributed_table_commands.cpp +++ b/yt/yt/client/driver/distributed_table_commands.cpp @@ -12,6 +12,10 @@ #include #include +#include +#include +#include + #include #include @@ -25,6 +29,7 @@ namespace NYT::NDriver { using namespace NApi; using namespace NConcurrency; using namespace NFormats; +using namespace NTableClient; using namespace NTracing; using namespace NYTree; using namespace NYson; @@ -35,6 +40,12 @@ using namespace NYPath; void TStartDistributedWriteSessionCommand::Register(TRegistrar registrar) { registrar.Parameter("path", &TThis::Path); + registrar.ParameterWithUniversalAccessor( + "cookie_count", + [] (TThis* command) -> auto& { + return command->Options.CookieCount; + }) + .Default(); } // -> DistributedWriteSession @@ -91,23 +102,18 @@ void TFinishDistributedWriteSessionCommand::DoExecute(ICommandContextPtr context WaitFor(context->GetClient()->FinishDistributedWriteSession(sessionWithResults, Options)) .ThrowOnError(); - - ProduceEmptyOutput(context); } //////////////////////////////////////////////////////////////////////////////// -void TWriteTableFragmentCommand::Execute(ICommandContextPtr context) -{ - TTypedCommand::Execute(std::move(context)); -} - void TWriteTableFragmentCommand::Register(TRegistrar registrar) { registrar.Parameter("cookie", &TThis::Cookie); + registrar.Parameter("max_row_buffer_size", &TThis::MaxRowBufferSize) + .Default(1_MB); } -NApi::ITableWriterPtr TWriteTableFragmentCommand::CreateTableWriter( +ITableFragmentWriterPtr TWriteTableFragmentCommand::CreateTableWriter( const ICommandContextPtr& context) { PutMethodInfoInTraceContext("write_table_fragment"); @@ -125,14 +131,12 @@ NApi::ITableWriterPtr TWriteTableFragmentCommand::CreateTableWriter( << TErrorAttribute("cookie_id", concreteCookie.CookieId); } - auto tableWriter = WaitFor(context + return WaitFor(context ->GetClient() ->CreateTableFragmentWriter( signedCookie, TTypedCommand::Options)) .ValueOrThrow(); - TableWriter = tableWriter; - return tableWriter; } // -> Cookie @@ -140,12 +144,31 @@ void TWriteTableFragmentCommand::DoExecute(ICommandContextPtr context) { auto cookie = ConvertTo(Cookie); - DoExecuteImpl(context); + auto tableWriter = CreateTableWriter(context); + + // NB(pavook): we shouldn't ping transaction here, as this method is executed in parallel + // and pinging the transaction could cause substantial master load. + + auto schemalessWriter = CreateSchemalessFromApiWriterAdapter(static_cast(tableWriter)); - // Sadly, we are plagued by virtual bases :/. - auto writer = DynamicPointerCast(TableWriter); + TWritingValueConsumer valueConsumer( + schemalessWriter, + ConvertTo(context->GetInputFormat().Attributes()), + MaxRowBufferSize); + + TTableOutput output(CreateParserForFormat( + context->GetInputFormat(), + &valueConsumer)); + + PipeInputToOutput(context->Request().InputStream, &output); + + WaitFor(valueConsumer.Flush()) + .ThrowOnError(); + + WaitFor(schemalessWriter->Close()) + .ThrowOnError(); - auto signedWriteResult = writer->GetWriteFragmentResult(); + auto signedWriteResult = tableWriter->GetWriteFragmentResult(); context->GetDriver()->GetSignatureGenerator()->Resign(signedWriteResult.Underlying()); ProduceOutput(context, [result = std::move(signedWriteResult)] (IYsonConsumer* consumer) { diff --git a/yt/yt/client/driver/distributed_table_commands.h b/yt/yt/client/driver/distributed_table_commands.h index 57fcfd7c6df6..36bd404e6ac6 100644 --- a/yt/yt/client/driver/distributed_table_commands.h +++ b/yt/yt/client/driver/distributed_table_commands.h @@ -48,13 +48,8 @@ class TFinishDistributedWriteSessionCommand // -> Cookie class TWriteTableFragmentCommand : public TTypedCommand - , private TWriteTableCommand { public: - // Shadow normal execute in order to fix - // ambiguity in dispatch. - void Execute(ICommandContextPtr context) override; - REGISTER_YSON_STRUCT_LITE(TWriteTableFragmentCommand); static void Register(TRegistrar registrar); @@ -63,10 +58,9 @@ class TWriteTableFragmentCommand using TBase = TWriteTableCommand; NYTree::INodePtr Cookie; - TRefCountedPtr TableWriter; + i64 MaxRowBufferSize; - NApi::ITableWriterPtr CreateTableWriter( - const ICommandContextPtr& context) override; + NApi::ITableFragmentWriterPtr CreateTableWriter(const ICommandContextPtr& context); void DoExecute(ICommandContextPtr context) override; }; diff --git a/yt/yt/client/driver/driver.cpp b/yt/yt/client/driver/driver.cpp index 0fa6393238e5..b21748f94391 100644 --- a/yt/yt/client/driver/driver.cpp +++ b/yt/yt/client/driver/driver.cpp @@ -398,6 +398,10 @@ class TDriver REGISTER (TReadShuffleDataCommand, "read_shuffle_data", Null, Tabular, false, true, ApiVersion4); REGISTER (TWriteShuffleDataCommand, "write_shuffle_data", Tabular, Structured, false, true, ApiVersion4); + REGISTER (TStartDistributedWriteSessionCommand, "start_distributed_write_session", Null, Structured, true, false, ApiVersion4); + REGISTER (TFinishDistributedWriteSessionCommand, "finish_distributed_write_session", Null, Null, true, false, ApiVersion4); + REGISTER (TWriteTableFragmentCommand, "write_table_fragment", Tabular, Structured, true, true, ApiVersion4); + if (Config_->EnableInternalCommands) { REGISTER_ALL(TReadHunksCommand, "read_hunks", Null, Structured, false, true ); REGISTER_ALL(TWriteHunksCommand, "write_hunks", Null, Structured, true, true ); @@ -408,11 +412,6 @@ class TDriver REGISTER_ALL(TRevokeLeaseCommand, "revoke_lease", Null, Structured, true, false); REGISTER_ALL(TReferenceLeaseCommand, "reference_lease", Null, Structured, true, false); REGISTER_ALL(TUnreferenceLeaseCommand, "unreference_lease", Null, Structured, true, false); - - // TODO(arkady-e1ppa): flags past command name might be complete rubbish -- think them through later. - REGISTER_ALL(TStartDistributedWriteSessionCommand, "start_distributed_write_session", Null, Structured, true, false); - REGISTER_ALL(TFinishDistributedWriteSessionCommand, "finish_distributed_write_session", Null, Null, true, false); - REGISTER_ALL(TWriteTableFragmentCommand, "distributed_write_table_partition", Tabular, Structured, true, true ); REGISTER_ALL(TForsakeChaosCoordinator, "forsake_chaos_coordinator", Null, Null, true, true); } From 7b0bf837ead80544ba76406eaa29e2e9122d3ad6 Mon Sep 17 00:00:00 2001 From: snermolaev Date: Wed, 9 Apr 2025 05:55:33 +0300 Subject: [PATCH 068/454] Switch CI_GROUP to new commands commit_hash:510cec0d50dda1dfe3fb8d59e9183dba3faee604 --- build/ymake.core.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/ymake.core.conf b/build/ymake.core.conf index de39d57ed284..7e0ddcf6dffe 100644 --- a/build/ymake.core.conf +++ b/build/ymake.core.conf @@ -2375,10 +2375,11 @@ TOUCH_GROUP=$FAKE_PACKAGE_CMD $VCS_INFO_DISABLE_CACHE__NO_UID__ ${hide:PEERS} ${ ### ### Is only used together with the macro PEERDIR() and FILES(). Don't use SRCS inside CI_GROUP(). module CI_GROUP: _BARE_UNIT { - .CMD=TOUCH_GROUP + .CMD=$TOUCH_GROUP .PEERDIR_POLICY=as_build_from .FINAL_TARGET=yes .RESTRICTED=SRCS + .STRUCT_CMD=yes .USE_PEERS_LATE_OUTS=yes MODULE_SUFFIX=.ci.pkg.fake PEERDIR_TAGS=CPP_PROTO CPP_PROTO_FROM_SCHEMA PY3 PY3_NATIVE PY3_BIN PY3TEST_PROGRAM YQL_UDF_SHARED __EMPTY__ RESOURCE_LIB DOCSBOOK JAR_RUNNABLE DLL PACKAGE_FINAL From bd6b1ba8dece602adbd2b57008bbeabca60d6f60 Mon Sep 17 00:00:00 2001 From: snermolaev Date: Wed, 9 Apr 2025 05:55:47 +0300 Subject: [PATCH 069/454] Swicth DEV_DLL_PROXY to new commands commit_hash:998d57c1793410a93fc535bf960eead64a81d66d --- build/ymake.core.conf | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build/ymake.core.conf b/build/ymake.core.conf index 7e0ddcf6dffe..87436486e9a6 100644 --- a/build/ymake.core.conf +++ b/build/ymake.core.conf @@ -2194,9 +2194,10 @@ DLL_PROXY_CMD_MF=$GENERATE_MF && $COPY_CMD $AUTO_INPUT $TARGET ### The use of this module is strictly prohibited!!! ### This is a temporary and project-specific solution. module DEV_DLL_PROXY: _BARE_UNIT { - .NODE_TYPE=Library + .CMD=$DLL_PROXY_CMD_MF .EXTS=.so .dll .dylib .mf - .CMD=DLL_PROXY_CMD_MF + .NODE_TYPE=Library + .STRUCT_CMD=yes DYNAMIC_LINK=yes when ($OS_WINDOWS == "yes") { From bad3f25104b317e4a8e569979658c6ed34711b4b Mon Sep 17 00:00:00 2001 From: snermolaev Date: Wed, 9 Apr 2025 05:55:55 +0300 Subject: [PATCH 070/454] Switch IOS_INTERFACE and DEFAULT_IOS_INTERFACE to new commands commit_hash:e6121a6932075416d37d6a6b7da6bd0e956701ed --- build/ymake.core.conf | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/build/ymake.core.conf b/build/ymake.core.conf index 87436486e9a6..d6fc5e9e8d4a 100644 --- a/build/ymake.core.conf +++ b/build/ymake.core.conf @@ -5591,10 +5591,11 @@ PACK_IOS_ARCHIVE=$GENERATE_MF && $YMAKE_PYTHON ${input:"build/scripts/ios_wrappe ### @usage: IOS_INTERFACE() ### iOS GUI module definition module IOS_INTERFACE: _BARE_UNIT { - .CMD=PACK_IOS_ARCHIVE + .CMD=$PACK_IOS_ARCHIVE .EXTS=.compiled_storyboard_tar .partial_plist .plist .xcent .nib .resource_tar .signed_resource_tar .strings_tar .plist_json - .NODE_TYPE=Library .FINAL_TARGET=no + .NODE_TYPE=Library + .STRUCT_CMD=yes SET(MODULE_SUFFIX .ios.interface) PEERDIR+=build/platform/xcode/tools From 69788d332aa360e125ebdddf28ec62e0248ab73d Mon Sep 17 00:00:00 2001 From: snermolaev Date: Wed, 9 Apr 2025 05:56:13 +0300 Subject: [PATCH 071/454] Switch JSRC_LIBRARY and its successors to new commands commit_hash:fb9373414e0a94f9fe4895b6c21e329e63f19565 --- build/conf/java.conf | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/build/conf/java.conf b/build/conf/java.conf index c05362ec5c44..0952bd6b1826 100644 --- a/build/conf/java.conf +++ b/build/conf/java.conf @@ -2131,7 +2131,7 @@ macro JAR_EXCLUDE(Filters...) { } # tag:java-specific -_COMPILE_JSRC=${cwd:ARCADIA_BUILD_ROOT} $YMAKE_PYTHON ${input:"build/scripts/compile_jsrc.py"} --input $AUTO_INPUT --output $TARGET --prefix $BINDIR ${hide;kv:"p JC"} ${hide;kv:"pc light-blue"} ${hide;kv:"show_out"} +_COMPILE_JSRC=${cwd:ARCADIA_BUILD_ROOT} $YMAKE_PYTHON3 ${input:"build/scripts/compile_jsrc.py"} --input $AUTO_INPUT --output $TARGET --prefix $BINDIR ${hide;kv:"p JC"} ${hide;kv:"pc light-blue"} ${hide;kv:"show_out"} # tag:java-specific COMPILE_JSRC_MF=$_COMPILE_JSRC && $GENERATE_MF @@ -2139,11 +2139,12 @@ COMPILE_JSRC_MF=$_COMPILE_JSRC && $GENERATE_MF # tag:java-specific tag:internal ### @usage: JSRC_LIBRARY() # internal module JSRC_LIBRARY: _BARE_UNIT { - .CMD=COMPILE_JSRC_MF + .ALIASES=SRCS=FILES + .CMD=$COMPILE_JSRC_MF .EXTS=.java - .PEERDIR_POLICY=as_include .FINAL_TARGET=no - .ALIASES=SRCS=FILES + .PEERDIR_POLICY=as_include + .STRUCT_CMD=yes PEERDIR_TAGS=JAVA JAVA_PROTO JAVA_PROTO_FROM_SCHEMA JAVA_FBS JAVA_IDL MODULE_TYPE=LIBRARY SET(MODULE_SUFFIX .jsrc) From 7ee6130d3c522b8f012d2e2e4366bb423c5c7574 Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Wed, 9 Apr 2025 07:40:48 +0300 Subject: [PATCH 072/454] Intermediate changes commit_hash:09b286f52f83fbff697b82af94ef317af646e3f6 --- .../python/pyparsing/py3/.dist-info/METADATA | 2 +- .../pyparsing/py3/pyparsing/__init__.py | 4 +-- .../python/pyparsing/py3/pyparsing/helpers.py | 27 +++++++++++++------ contrib/python/pyparsing/py3/ya.make | 2 +- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/contrib/python/pyparsing/py3/.dist-info/METADATA b/contrib/python/pyparsing/py3/.dist-info/METADATA index ed52278486a0..d03671b61301 100644 --- a/contrib/python/pyparsing/py3/.dist-info/METADATA +++ b/contrib/python/pyparsing/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pyparsing -Version: 3.2.2 +Version: 3.2.3 Summary: pyparsing module - Classes and methods to define and execute parsing grammars Author-email: Paul McGuire Requires-Python: >=3.9 diff --git a/contrib/python/pyparsing/py3/pyparsing/__init__.py b/contrib/python/pyparsing/py3/pyparsing/__init__.py index fa1f2abe67e5..d839fd253756 100644 --- a/contrib/python/pyparsing/py3/pyparsing/__init__.py +++ b/contrib/python/pyparsing/py3/pyparsing/__init__.py @@ -120,8 +120,8 @@ def __repr__(self): return f"{__name__}.{type(self).__name__}({', '.join('{}={!r}'.format(*nv) for nv in zip(self._fields, self))})" -__version_info__ = version_info(3, 2, 2, "final", 1) -__version_time__ = "22 Mar 2025 22:09 UTC" +__version_info__ = version_info(3, 2, 3, "final", 1) +__version_time__ = "25 Mar 2025 01:38 UTC" __version__ = __version_info__.__version__ __versionTime__ = __version_time__ __author__ = "Paul McGuire " diff --git a/contrib/python/pyparsing/py3/pyparsing/helpers.py b/contrib/python/pyparsing/py3/pyparsing/helpers.py index 7f62df863747..2badd68d64f6 100644 --- a/contrib/python/pyparsing/py3/pyparsing/helpers.py +++ b/contrib/python/pyparsing/py3/pyparsing/helpers.py @@ -418,6 +418,8 @@ def locatedExpr(expr: ParserElement) -> ParserElement: ) +# define special default value to permit None as a significant value for +# ignore_expr _NO_IGNORE_EXPR_GIVEN = NoMatch() @@ -498,11 +500,13 @@ def nested_expr( """ if ignoreExpr != ignore_expr: ignoreExpr = ignore_expr if ignoreExpr is _NO_IGNORE_EXPR_GIVEN else ignoreExpr + if ignoreExpr is _NO_IGNORE_EXPR_GIVEN: ignoreExpr = quoted_string() if opener == closer: raise ValueError("opening and closing strings cannot be the same") + if content is None: if isinstance(opener, str_type) and isinstance(closer, str_type): opener = typing.cast(str, opener) @@ -519,8 +523,11 @@ def nested_expr( ) ) else: - content = empty.copy() + CharsNotIn( - opener + closer + ParserElement.DEFAULT_WHITE_CHARS + content = Combine( + Empty() + + CharsNotIn( + opener + closer + ParserElement.DEFAULT_WHITE_CHARS + ) ) else: if ignoreExpr is not None: @@ -544,10 +551,12 @@ def nested_expr( raise ValueError( "opening and closing arguments must be strings if no content expression is given" ) - if ParserElement.DEFAULT_WHITE_CHARS: - content.set_parse_action( - lambda t: t[0].strip(ParserElement.DEFAULT_WHITE_CHARS) - ) + + # for these internally-created context expressions, simulate whitespace-skipping + if ParserElement.DEFAULT_WHITE_CHARS: + content.set_parse_action( + lambda t: t[0].strip(ParserElement.DEFAULT_WHITE_CHARS) + ) ret = Forward() if ignoreExpr is not None: @@ -556,7 +565,9 @@ def nested_expr( ) else: ret <<= Group(Suppress(opener) + ZeroOrMore(ret | content) + Suppress(closer)) + ret.set_name(f"nested {opener}{closer} expression") + # don't override error message from content expressions ret.errmsg = None return ret @@ -621,7 +632,7 @@ def _makeTags(tagStr, xml, suppress_LT=Suppress("<"), suppress_GT=Suppress(">")) def make_html_tags( - tag_str: Union[str, ParserElement] + tag_str: Union[str, ParserElement], ) -> tuple[ParserElement, ParserElement]: """Helper to construct opening and closing tag expressions for HTML, given a tag name. Matches tags in either upper or lower case, @@ -648,7 +659,7 @@ def make_html_tags( def make_xml_tags( - tag_str: Union[str, ParserElement] + tag_str: Union[str, ParserElement], ) -> tuple[ParserElement, ParserElement]: """Helper to construct opening and closing tag expressions for XML, given a tag name. Matches tags only in the given upper/lower case. diff --git a/contrib/python/pyparsing/py3/ya.make b/contrib/python/pyparsing/py3/ya.make index a53ebf37ecf0..13dd585e164a 100644 --- a/contrib/python/pyparsing/py3/ya.make +++ b/contrib/python/pyparsing/py3/ya.make @@ -4,7 +4,7 @@ PY3_LIBRARY() PROVIDES(pyparsing) -VERSION(3.2.2) +VERSION(3.2.3) LICENSE(MIT) From e30884e7c80f5fe50760de64246f8f4d36713f61 Mon Sep 17 00:00:00 2001 From: Dmitry Kardymon Date: Wed, 9 Apr 2025 08:32:57 +0300 Subject: [PATCH 073/454] Check ActorLibCollectUsageStats to reduce utils metric count (#15992) --- ydb/library/actors/core/mailbox_lockfree.cpp | 2 +- ydb/library/actors/helpers/collector_counters.cpp | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/ydb/library/actors/core/mailbox_lockfree.cpp b/ydb/library/actors/core/mailbox_lockfree.cpp index f1f4a6b9d9d4..872367021c9a 100644 --- a/ydb/library/actors/core/mailbox_lockfree.cpp +++ b/ydb/library/actors/core/mailbox_lockfree.cpp @@ -361,7 +361,7 @@ namespace NActors { Y_DEBUG_ABORT_UNLESS(GetNextPtr(tail) == nullptr); #ifdef ACTORSLIB_COLLECT_EXEC_STATS // Mark events as enqueued when usage stats are enabled - if (ActorLibCollectUsageStats) { + if constexpr (ActorLibCollectUsageStats) { for (IEventHandle* ev = head; ev; ev = GetNextPtr(ev)) { if (IActor* actor = FindActor(ev->GetRecipientRewrite().LocalId())) { actor->OnEnqueueEvent(ev->SendTime); diff --git a/ydb/library/actors/helpers/collector_counters.cpp b/ydb/library/actors/helpers/collector_counters.cpp index 9dc8d471ef70..a5ff0e9fc2d0 100644 --- a/ydb/library/actors/helpers/collector_counters.cpp +++ b/ydb/library/actors/helpers/collector_counters.cpp @@ -70,8 +70,10 @@ void TActivityStats::Set(const TExecutorThreadStats& stats) { *ScheduledEventsByActivityBuckets[i] = scheduled; *StuckActorsByActivityBuckets[i] = stuck; - for (ui32 j = 0; j < 10; ++j) { - *UsageByActivityBuckets[i][j] = stats.UsageByActivity[i][j]; + if constexpr (ActorLibCollectUsageStats) { + for (ui32 j = 0; j < 10; ++j) { + *UsageByActivityBuckets[i][j] = stats.UsageByActivity[i][j]; + } } } @@ -117,8 +119,10 @@ void TActivityStats::InitCountersForActivity(ui32 activityType) { StuckActorsByActivityBuckets[activityType] = Group->GetSubgroup("sensor", "StuckActorsByActivity")->GetNamedCounter("activity", bucketName, false); - for (ui32 i = 0; i < 10; ++i) { - UsageByActivityBuckets[activityType][i] = Group->GetSubgroup("sensor", "UsageByActivity")->GetSubgroup("bin", ToString(i))->GetNamedCounter("activity", bucketName, false); + if constexpr (ActorLibCollectUsageStats) { + for (ui32 i = 0; i < 10; ++i) { + UsageByActivityBuckets[activityType][i] = Group->GetSubgroup("sensor", "UsageByActivity")->GetSubgroup("bin", ToString(i))->GetNamedCounter("activity", bucketName, false); + } } } From 27c5c03858333546c5926482d4f0b2d2af05844c Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Wed, 9 Apr 2025 08:30:55 +0300 Subject: [PATCH 074/454] Intermediate changes commit_hash:beff4bb8465ac16cbba2bd47f1a49bc8ae8565ca --- contrib/python/pytz/py2/.dist-info/METADATA | 2 +- contrib/python/pytz/py2/pytz/__init__.py | 6 ++++-- .../python/pytz/py2/pytz/tests/test_tzinfo.py | 4 ++-- .../pytz/py2/pytz/zoneinfo/America/Coyhaique | Bin 0 -> 2126 bytes .../python/pytz/py2/pytz/zoneinfo/Asia/Tehran | Bin 1248 -> 1248 bytes contrib/python/pytz/py2/pytz/zoneinfo/Iran | Bin 1248 -> 1248 bytes .../python/pytz/py2/pytz/zoneinfo/tzdata.zi | 16 +++++++++++++++- .../python/pytz/py2/pytz/zoneinfo/zone.tab | 3 ++- .../pytz/py2/pytz/zoneinfo/zone1970.tab | 3 ++- .../python/pytz/py2/pytz/zoneinfo/zonenow.tab | 2 +- contrib/python/pytz/py2/ya.make | 3 ++- 11 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 contrib/python/pytz/py2/pytz/zoneinfo/America/Coyhaique diff --git a/contrib/python/pytz/py2/.dist-info/METADATA b/contrib/python/pytz/py2/.dist-info/METADATA index 879a28cf7a1c..6ecc5a3e468a 100644 --- a/contrib/python/pytz/py2/.dist-info/METADATA +++ b/contrib/python/pytz/py2/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pytz -Version: 2025.1 +Version: 2025.2 Summary: World timezone definitions, modern and historical Home-page: http://pythonhosted.org/pytz Download-URL: https://pypi.org/project/pytz/ diff --git a/contrib/python/pytz/py2/pytz/__init__.py b/contrib/python/pytz/py2/pytz/__init__.py index 1f0194634ca1..c7ee5efd2f08 100644 --- a/contrib/python/pytz/py2/pytz/__init__.py +++ b/contrib/python/pytz/py2/pytz/__init__.py @@ -22,8 +22,8 @@ # The IANA (nee Olson) database is updated several times a year. -OLSON_VERSION = '2025a' -VERSION = '2025.1' # pip compatible version number. +OLSON_VERSION = '2025b' +VERSION = '2025.2' # pip compatible version number. __version__ = VERSION OLSEN_VERSION = OLSON_VERSION # Old releases had this misspelling @@ -617,6 +617,7 @@ def _test(): 'America/Coral_Harbour', 'America/Cordoba', 'America/Costa_Rica', + 'America/Coyhaique', 'America/Creston', 'America/Cuiaba', 'America/Curacao', @@ -1210,6 +1211,7 @@ def _test(): 'America/Chihuahua', 'America/Ciudad_Juarez', 'America/Costa_Rica', + 'America/Coyhaique', 'America/Creston', 'America/Cuiaba', 'America/Curacao', diff --git a/contrib/python/pytz/py2/pytz/tests/test_tzinfo.py b/contrib/python/pytz/py2/pytz/tests/test_tzinfo.py index 3195a1fde36a..6d1cadaf2dbe 100644 --- a/contrib/python/pytz/py2/pytz/tests/test_tzinfo.py +++ b/contrib/python/pytz/py2/pytz/tests/test_tzinfo.py @@ -27,8 +27,8 @@ # I test for expected version to ensure the correct version of pytz is # actually being tested. -EXPECTED_VERSION = '2025.1' -EXPECTED_OLSON_VERSION = '2025a' +EXPECTED_VERSION = '2025.2' +EXPECTED_OLSON_VERSION = '2025b' fmt = '%Y-%m-%d %H:%M:%S %Z%z' diff --git a/contrib/python/pytz/py2/pytz/zoneinfo/America/Coyhaique b/contrib/python/pytz/py2/pytz/zoneinfo/America/Coyhaique new file mode 100644 index 0000000000000000000000000000000000000000..e0c6832bb36bde2468038a1e8fa25f89835a4e5f GIT binary patch literal 2126 zcmdtiOKenC9LMoH58B#xq@~ECf)o_2j_9FNq{TiCh1ynLqaEbov?7p}5@RdDvapFr z1gZ%;#KmJwpK*!k=2c1WaG;Tl9v%OsRE^-pb z*0h;7XB9`^Dt%SI9cWJU<&T)Y^ZTRym*ZyOWI=Rz+9P`S;ja^)Pd=wpkyR$u-mNbu z%k-7*-^CsN#5h~ei0`qe@#{JXtSU0Wg0PIMSgF&Tkfdh~>hv$iB;!h+zUFvRGDm;b zS%W z1~Vmjzf8SQY4UqY`QcY{^QnWX@X~wcmUoBb){)mt_>}{4TVJP{yYor8ecu*y$A*ofcI?sf zs;Z@EeT$BikEmk3RL{>^qV5d!>jh~kDRIW@l8-Y~={I4s@bI_lt`9?|?3rOzerU{8 zY&oJTJCjD&e7_z!&sieFFYK&>t9=_MblKt~=P~IIcVNjuUj<0dX>1_oQ*MdHd`;mGI?U z{U()ga+WQRIra9=RrBpFwl`w`+V=Q-e;fN3!*K0s*)zlbhU+pAWF*K?kg*_xK}LfN z2N@4CAY??ykdQHX+Cd?sLWYHm%hL`F85uG(PdhebaOjPW4-AiE#|I1$86h%6WQ@ol zkx?SU^t9td28xUn87eYXWU$C+k>MiaMFxzF7#T7$W@OOFsF7iN+HoTT_p~ENhK`IK z89Xw2WcbMVkpLhOKth1T00{yT1tbifHV#N2kVqh*Kw^Oe1BnI_4kR8(K#+(aAwgn- z1OsV%%*@RX^GXDa79D+9h literal 0 HcmV?d00001 diff --git a/contrib/python/pytz/py2/pytz/zoneinfo/Asia/Tehran b/contrib/python/pytz/py2/pytz/zoneinfo/Asia/Tehran index cc2a2c219b0c893cfa8187e962028eb19ea3425d..78f28cc402027bd337cf67b937bf8c31a75ee8b3 100644 GIT binary patch delta 23 dcmaFB`G9kREAz^~2R3?qVFb~e?U@!b0RV|73jY8A delta 23 ccmaFB`G9kREAv|`hm9Uz7(w)Ad!~g<0CdF(0RR91 diff --git a/contrib/python/pytz/py2/pytz/zoneinfo/Iran b/contrib/python/pytz/py2/pytz/zoneinfo/Iran index cc2a2c219b0c893cfa8187e962028eb19ea3425d..78f28cc402027bd337cf67b937bf8c31a75ee8b3 100644 GIT binary patch delta 23 dcmaFB`G9kREAz^~2R3?qVFb~e?U@!b0RV|73jY8A delta 23 ccmaFB`G9kREAv|`hm9Uz7(w)Ad!~g<0CdF(0RR91 diff --git a/contrib/python/pytz/py2/pytz/zoneinfo/tzdata.zi b/contrib/python/pytz/py2/pytz/zoneinfo/tzdata.zi index a2fcd5449632..0bcae52e5efa 100644 --- a/contrib/python/pytz/py2/pytz/zoneinfo/tzdata.zi +++ b/contrib/python/pytz/py2/pytz/zoneinfo/tzdata.zi @@ -2432,6 +2432,20 @@ Z America/Ciudad_Juarez -7:5:56 - LMT 1922 Ja 1 7u Z America/Costa_Rica -5:36:13 - LMT 1890 -5:36:13 - SJMT 1921 Ja 15 -6 CR C%sT +Z America/Coyhaique -4:48:16 - LMT 1890 +-4:42:45 - SMT 1910 Ja 10 +-5 - %z 1916 Jul +-4:42:45 - SMT 1918 S 10 +-4 - %z 1919 Jul +-4:42:45 - SMT 1927 S +-5 x %z 1932 S +-4 - %z 1942 Jun +-5 - %z 1942 Au +-4 - %z 1946 Au 28 24 +-5 1 %z 1947 Mar 31 24 +-5 - %z 1947 May 21 23 +-4 x %z 2025 Mar 20 +-3 - %z Z America/Cuiaba -3:44:20 - LMT 1914 -4 B %z 2003 S 24 -4 - %z 2004 O @@ -3420,7 +3434,7 @@ Z Asia/Tbilisi 2:59:11 - LMT 1880 Z Asia/Tehran 3:25:44 - LMT 1916 3:25:44 - TMT 1935 Jun 13 3:30 i %z 1977 O 20 24 -4 i %z 1979 +4 i %z 1978 N 10 24 3:30 i %z Z Asia/Thimphu 5:58:36 - LMT 1947 Au 15 5:30 - %z 1987 O diff --git a/contrib/python/pytz/py2/pytz/zoneinfo/zone.tab b/contrib/python/pytz/py2/pytz/zoneinfo/zone.tab index d2be66359f3b..2626b0550341 100644 --- a/contrib/python/pytz/py2/pytz/zoneinfo/zone.tab +++ b/contrib/python/pytz/py2/pytz/zoneinfo/zone.tab @@ -139,7 +139,8 @@ CH +4723+00832 Europe/Zurich CI +0519-00402 Africa/Abidjan CK -2114-15946 Pacific/Rarotonga CL -3327-07040 America/Santiago most of Chile -CL -5309-07055 America/Punta_Arenas Region of Magallanes +CL -4534-07204 America/Coyhaique Aysen Region +CL -5309-07055 America/Punta_Arenas Magallanes Region CL -2709-10926 Pacific/Easter Easter Island CM +0403+00942 Africa/Douala CN +3114+12128 Asia/Shanghai Beijing Time diff --git a/contrib/python/pytz/py2/pytz/zoneinfo/zone1970.tab b/contrib/python/pytz/py2/pytz/zoneinfo/zone1970.tab index 5ded0565ebf3..36535bdf5cfb 100644 --- a/contrib/python/pytz/py2/pytz/zoneinfo/zone1970.tab +++ b/contrib/python/pytz/py2/pytz/zoneinfo/zone1970.tab @@ -124,7 +124,8 @@ CH,DE,LI +4723+00832 Europe/Zurich Büsingen CI,BF,GH,GM,GN,IS,ML,MR,SH,SL,SN,TG +0519-00402 Africa/Abidjan CK -2114-15946 Pacific/Rarotonga CL -3327-07040 America/Santiago most of Chile -CL -5309-07055 America/Punta_Arenas Region of Magallanes +CL -4534-07204 America/Coyhaique Aysén Region +CL -5309-07055 America/Punta_Arenas Magallanes Region CL -2709-10926 Pacific/Easter Easter Island CN +3114+12128 Asia/Shanghai Beijing Time CN +4348+08735 Asia/Urumqi Xinjiang Time diff --git a/contrib/python/pytz/py2/pytz/zoneinfo/zonenow.tab b/contrib/python/pytz/py2/pytz/zoneinfo/zonenow.tab index d2c1e48584f8..093f0a0cb749 100644 --- a/contrib/python/pytz/py2/pytz/zoneinfo/zonenow.tab +++ b/contrib/python/pytz/py2/pytz/zoneinfo/zonenow.tab @@ -104,7 +104,7 @@ XX +4439-06336 America/Halifax Atlantic ("AST/ADT") - Canada; Bermuda XX +4734-05243 America/St_Johns Newfoundland ("NST/NDT") # # -03 -XX -2332-04637 America/Sao_Paulo eastern South America +XX -2332-04637 America/Sao_Paulo eastern and southern South America # # -03/-02 (North America DST) XX +4703-05620 America/Miquelon St Pierre & Miquelon diff --git a/contrib/python/pytz/py2/ya.make b/contrib/python/pytz/py2/ya.make index ea9dc82c568e..b893dc7f05d3 100644 --- a/contrib/python/pytz/py2/ya.make +++ b/contrib/python/pytz/py2/ya.make @@ -2,7 +2,7 @@ PY2_LIBRARY() -VERSION(2025.1) +VERSION(2025.2) LICENSE(MIT) @@ -125,6 +125,7 @@ RESOURCE_FILES( pytz/zoneinfo/America/Coral_Harbour pytz/zoneinfo/America/Cordoba pytz/zoneinfo/America/Costa_Rica + pytz/zoneinfo/America/Coyhaique pytz/zoneinfo/America/Creston pytz/zoneinfo/America/Cuiaba pytz/zoneinfo/America/Curacao From 56d21546eaa29f332c0ac39e83742ed4614c9309 Mon Sep 17 00:00:00 2001 From: azevaykin <145343289+azevaykin@users.noreply.github.com> Date: Wed, 9 Apr 2025 08:50:09 +0300 Subject: [PATCH 075/454] Lower log verbosity for schemeshard (#16806) --- .../schemeshard__operation_side_effects.cpp | 2 +- .../tx/schemeshard/schemeshard__pq_stats.cpp | 2 +- .../tx/schemeshard/schemeshard__table_stats.cpp | 16 ++++++---------- ydb/core/tx/schemeshard/schemeshard_impl.cpp | 2 +- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/ydb/core/tx/schemeshard/schemeshard__operation_side_effects.cpp b/ydb/core/tx/schemeshard/schemeshard__operation_side_effects.cpp index c0dbe726583b..e03cf0debbd0 100644 --- a/ydb/core/tx/schemeshard/schemeshard__operation_side_effects.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__operation_side_effects.cpp @@ -555,7 +555,7 @@ void TSideEffects::DoUpdateTenant(TSchemeShard* ss, NTabletFlatExecutor::TTransa } if (!hasChanges) { - LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "DoUpdateTenant no hasChanges" << ", pathId: " << pathId << ", tenantLink: " << tenantLink diff --git a/ydb/core/tx/schemeshard/schemeshard__pq_stats.cpp b/ydb/core/tx/schemeshard/schemeshard__pq_stats.cpp index 29bb1a15aff7..caecef552515 100644 --- a/ydb/core/tx/schemeshard/schemeshard__pq_stats.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__pq_stats.cpp @@ -115,7 +115,7 @@ void TSchemeShard::Handle(TEvPersQueue::TEvPeriodicTopicStats::TPtr& ev, const T } void TSchemeShard::Handle(TEvPrivate::TEvPersistTopicStats::TPtr&, const TActorContext& ctx) { - LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "Started TEvPersistStats at tablet " << TabletID() << ", queue size# " << TopicStatsQueue.Size()); TopicStatsBatchScheduled = false; diff --git a/ydb/core/tx/schemeshard/schemeshard__table_stats.cpp b/ydb/core/tx/schemeshard/schemeshard__table_stats.cpp index 71d616f75bfa..c8013bc57d31 100644 --- a/ydb/core/tx/schemeshard/schemeshard__table_stats.cpp +++ b/ydb/core/tx/schemeshard/schemeshard__table_stats.cpp @@ -279,19 +279,15 @@ bool TTxStoreTableStats::PersistSingleStats(const TPathId& pathId, shardInfo->BindedChannels); const auto pathElement = Self->PathsById[pathId]; + const TPartitionStats newStats = PrepareStats(ctx, rec, channelsMapping); + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "TTxStoreTableStats.PersistSingleStats: main stats from" << " datashardId(TabletID)=" << datashardId << " maps to shardIdx: " << shardIdx << " followerId=" << followerId << ", pathId: " << pathId << ", pathId map=" << pathElement->Name - << ", is column=" << isColumnTable << ", is olap=" << isOlapStore); - - const TPartitionStats newStats = PrepareStats(ctx, rec, channelsMapping); - - LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, - "Add stats from shard with datashardId(TabletID)=" << datashardId << " followerId=" << followerId - << ", pathId " << pathId.LocalPathId - << ": RowCount " << newStats.RowCount + << ", is column=" << isColumnTable << ", is olap=" << isOlapStore + << ", RowCount " << newStats.RowCount << ", DataSize " << newStats.DataSize << (newStats.HasBorrowedData ? ", with borrowed parts" : "")); @@ -543,7 +539,7 @@ void TSchemeShard::Handle(TEvDataShard::TEvPeriodicTableStats::TPtr& ev, const T ? TPathId(TOwnerId(rec.GetTableOwnerId()), TLocalPathId(rec.GetTableLocalId())) : MakeLocalId(TLocalPathId(rec.GetTableLocalId())); - LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "Got periodic table stats at tablet " << TabletID() << " from shard " << datashardId << " followerId " << followerId @@ -577,7 +573,7 @@ void TSchemeShard::Handle(TEvDataShard::TEvPeriodicTableStats::TPtr& ev, const T } void TSchemeShard::Handle(TEvPrivate::TEvPersistTableStats::TPtr&, const TActorContext& ctx) { - LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "Started TEvPersistStats at tablet " << TabletID() << ", queue size# " << TableStatsQueue.Size()); TableStatsBatchScheduled = false; diff --git a/ydb/core/tx/schemeshard/schemeshard_impl.cpp b/ydb/core/tx/schemeshard/schemeshard_impl.cpp index 4a2756a256ef..1bbf3d96b404 100644 --- a/ydb/core/tx/schemeshard/schemeshard_impl.cpp +++ b/ydb/core/tx/schemeshard/schemeshard_impl.cpp @@ -5755,7 +5755,7 @@ void TSchemeShard::Handle(TEvTabletPipe::TEvServerDisconnected::TPtr &, const TA void TSchemeShard::Handle(TEvSchemeShard::TEvSyncTenantSchemeShard::TPtr& ev, const TActorContext& ctx) { const auto& record = ev->Get()->Record; - LOG_INFO_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, + LOG_DEBUG_S(ctx, NKikimrServices::FLAT_TX_SCHEMESHARD, "Handle TEvSyncTenantSchemeShard" << ", at schemeshard: " << TabletID() << ", msg: " << record.DebugString()); From 34a1855aaa5fb3d26817b2bbedbebc08a57f6a11 Mon Sep 17 00:00:00 2001 From: Oleg Doronin Date: Wed, 9 Apr 2025 09:30:04 +0300 Subject: [PATCH 076/454] DDR scheduler (#16950) --- ydb/library/analytics/all.h | 10 + ydb/library/analytics/analytics.cpp | 5 + ydb/library/analytics/asciiart_output.h | 256 +++ ydb/library/analytics/csv_output.h | 52 + ydb/library/analytics/data.h | 76 + ydb/library/analytics/html_output.h | 86 + ydb/library/analytics/json_output.h | 98 ++ ydb/library/analytics/protobuf.h | 49 + ydb/library/analytics/protos/data.proto | 21 + ydb/library/analytics/protos/ya.make | 11 + ydb/library/analytics/transform.h | 192 ++ ydb/library/analytics/util.h | 122 ++ ydb/library/analytics/ya.make | 15 + ydb/library/drr/drr.cpp | 5 + ydb/library/drr/drr.h | 363 ++++ ydb/library/drr/probes.cpp | 3 + ydb/library/drr/probes.h | 22 + ydb/library/drr/ut/drr_ut.cpp | 581 +++++++ ydb/library/drr/ut/ya.make | 12 + ydb/library/drr/ya.make | 17 + ydb/library/planner/base/defs.h | 60 + ydb/library/planner/base/visitor.h | 55 + ydb/library/planner/share/account.cpp | 5 + ydb/library/planner/share/account.h | 24 + ydb/library/planner/share/analytics.h | 99 ++ ydb/library/planner/share/apply.h | 104 ++ ydb/library/planner/share/billing.h | 78 + ydb/library/planner/share/group.cpp | 100 ++ ydb/library/planner/share/group.h | 63 + ydb/library/planner/share/history.cpp | 4 + ydb/library/planner/share/history.h | 114 ++ ydb/library/planner/share/models/density.h | 385 +++++ ydb/library/planner/share/models/max.h | 35 + ydb/library/planner/share/models/model.h | 47 + ydb/library/planner/share/models/recursive.h | 80 + ydb/library/planner/share/models/static.h | 35 + ydb/library/planner/share/monitoring.h | 542 ++++++ ydb/library/planner/share/node.cpp | 114 ++ ydb/library/planner/share/node.h | 136 ++ ydb/library/planner/share/node_visitor.h | 42 + ydb/library/planner/share/probes.cpp | 3 + ydb/library/planner/share/probes.h | 123 ++ .../planner/share/protos/shareplanner.proto | 38 + .../share/protos/shareplanner_history.proto | 22 + .../share/protos/shareplanner_sensors.proto | 88 + ydb/library/planner/share/protos/ya.make | 15 + ydb/library/planner/share/pull.h | 208 +++ ydb/library/planner/share/shareplanner.cpp | 186 ++ ydb/library/planner/share/shareplanner.h | 332 ++++ ydb/library/planner/share/stats.h | 48 + ydb/library/planner/share/step.h | 23 + ydb/library/planner/share/ut/all.lwt | 14 + .../planner/share/ut/shareplanner_ut.cpp | 541 ++++++ ydb/library/planner/share/ut/ya.make | 12 + ydb/library/planner/share/utilization.cpp | 71 + ydb/library/planner/share/utilization.h | 33 + ydb/library/planner/share/ya.make | 25 + ydb/library/planner/ya.make | 3 + ydb/library/shop/counters.h | 107 ++ ydb/library/shop/estimator.h | 192 ++ ydb/library/shop/flowctl.cpp | 680 ++++++++ ydb/library/shop/flowctl.h | 213 +++ ydb/library/shop/lazy_scheduler.h | 788 +++++++++ ydb/library/shop/probes.cpp | 3 + ydb/library/shop/probes.h | 157 ++ .../protos/library-shop-protos-sources.jar | 1 + .../shop/protos/library-shop-protos.jar | 1 + .../shop/protos/library-shop-protos.protosrc | 1 + ydb/library/shop/protos/shop.proto | 47 + ydb/library/shop/protos/ya.make | 9 + ydb/library/shop/resource.h | 98 ++ ydb/library/shop/schedulable.h | 17 + ydb/library/shop/scheduler.h | 732 ++++++++ ydb/library/shop/shop.cpp | 363 ++++ ydb/library/shop/shop.h | 195 +++ ydb/library/shop/shop_state.h | 122 ++ ydb/library/shop/sim_estimator/estimator.css | 32 + ydb/library/shop/sim_estimator/estimator.html | 131 ++ ydb/library/shop/sim_estimator/estimator.js | 124 ++ ydb/library/shop/sim_flowctl/flowctlmain.cpp | 588 +++++++ ydb/library/shop/sim_flowctl/one.pb.txt | 18 + ydb/library/shop/sim_flowctl/ya.make | 16 + ydb/library/shop/sim_shop/config.proto | 114 ++ ydb/library/shop/sim_shop/myshop.cpp | 807 +++++++++ ydb/library/shop/sim_shop/myshop.h | 286 +++ ydb/library/shop/sim_shop/myshopmain.cpp | 319 ++++ ydb/library/shop/sim_shop/one.pb.txt | 18 + ydb/library/shop/sim_shop/two.pb.txt | 26 + ydb/library/shop/sim_shop/ya.make | 25 + ydb/library/shop/ut/estimator_ut.cpp | 58 + ydb/library/shop/ut/flowctl_ut.cpp | 523 ++++++ ydb/library/shop/ut/lazy_scheduler_ut.cpp | 1537 +++++++++++++++++ ydb/library/shop/ut/scheduler_ut.cpp | 1403 +++++++++++++++ ydb/library/shop/ut/tr.lwt | 4 + ydb/library/shop/ut/ya.make | 15 + ydb/library/shop/valve.h | 51 + ydb/library/shop/ya.make | 23 + ydb/library/ya.make | 4 + 98 files changed, 15751 insertions(+) create mode 100644 ydb/library/analytics/all.h create mode 100644 ydb/library/analytics/analytics.cpp create mode 100644 ydb/library/analytics/asciiart_output.h create mode 100644 ydb/library/analytics/csv_output.h create mode 100644 ydb/library/analytics/data.h create mode 100644 ydb/library/analytics/html_output.h create mode 100644 ydb/library/analytics/json_output.h create mode 100644 ydb/library/analytics/protobuf.h create mode 100644 ydb/library/analytics/protos/data.proto create mode 100644 ydb/library/analytics/protos/ya.make create mode 100644 ydb/library/analytics/transform.h create mode 100644 ydb/library/analytics/util.h create mode 100644 ydb/library/analytics/ya.make create mode 100644 ydb/library/drr/drr.cpp create mode 100644 ydb/library/drr/drr.h create mode 100644 ydb/library/drr/probes.cpp create mode 100644 ydb/library/drr/probes.h create mode 100644 ydb/library/drr/ut/drr_ut.cpp create mode 100644 ydb/library/drr/ut/ya.make create mode 100644 ydb/library/drr/ya.make create mode 100644 ydb/library/planner/base/defs.h create mode 100644 ydb/library/planner/base/visitor.h create mode 100644 ydb/library/planner/share/account.cpp create mode 100644 ydb/library/planner/share/account.h create mode 100644 ydb/library/planner/share/analytics.h create mode 100644 ydb/library/planner/share/apply.h create mode 100644 ydb/library/planner/share/billing.h create mode 100644 ydb/library/planner/share/group.cpp create mode 100644 ydb/library/planner/share/group.h create mode 100644 ydb/library/planner/share/history.cpp create mode 100644 ydb/library/planner/share/history.h create mode 100644 ydb/library/planner/share/models/density.h create mode 100644 ydb/library/planner/share/models/max.h create mode 100644 ydb/library/planner/share/models/model.h create mode 100644 ydb/library/planner/share/models/recursive.h create mode 100644 ydb/library/planner/share/models/static.h create mode 100644 ydb/library/planner/share/monitoring.h create mode 100644 ydb/library/planner/share/node.cpp create mode 100644 ydb/library/planner/share/node.h create mode 100644 ydb/library/planner/share/node_visitor.h create mode 100644 ydb/library/planner/share/probes.cpp create mode 100644 ydb/library/planner/share/probes.h create mode 100644 ydb/library/planner/share/protos/shareplanner.proto create mode 100644 ydb/library/planner/share/protos/shareplanner_history.proto create mode 100644 ydb/library/planner/share/protos/shareplanner_sensors.proto create mode 100644 ydb/library/planner/share/protos/ya.make create mode 100644 ydb/library/planner/share/pull.h create mode 100644 ydb/library/planner/share/shareplanner.cpp create mode 100644 ydb/library/planner/share/shareplanner.h create mode 100644 ydb/library/planner/share/stats.h create mode 100644 ydb/library/planner/share/step.h create mode 100644 ydb/library/planner/share/ut/all.lwt create mode 100644 ydb/library/planner/share/ut/shareplanner_ut.cpp create mode 100644 ydb/library/planner/share/ut/ya.make create mode 100644 ydb/library/planner/share/utilization.cpp create mode 100644 ydb/library/planner/share/utilization.h create mode 100644 ydb/library/planner/share/ya.make create mode 100644 ydb/library/planner/ya.make create mode 100644 ydb/library/shop/counters.h create mode 100644 ydb/library/shop/estimator.h create mode 100644 ydb/library/shop/flowctl.cpp create mode 100644 ydb/library/shop/flowctl.h create mode 100644 ydb/library/shop/lazy_scheduler.h create mode 100644 ydb/library/shop/probes.cpp create mode 100644 ydb/library/shop/probes.h create mode 120000 ydb/library/shop/protos/library-shop-protos-sources.jar create mode 120000 ydb/library/shop/protos/library-shop-protos.jar create mode 120000 ydb/library/shop/protos/library-shop-protos.protosrc create mode 100644 ydb/library/shop/protos/shop.proto create mode 100644 ydb/library/shop/protos/ya.make create mode 100644 ydb/library/shop/resource.h create mode 100644 ydb/library/shop/schedulable.h create mode 100644 ydb/library/shop/scheduler.h create mode 100644 ydb/library/shop/shop.cpp create mode 100644 ydb/library/shop/shop.h create mode 100644 ydb/library/shop/shop_state.h create mode 100644 ydb/library/shop/sim_estimator/estimator.css create mode 100644 ydb/library/shop/sim_estimator/estimator.html create mode 100644 ydb/library/shop/sim_estimator/estimator.js create mode 100644 ydb/library/shop/sim_flowctl/flowctlmain.cpp create mode 100644 ydb/library/shop/sim_flowctl/one.pb.txt create mode 100644 ydb/library/shop/sim_flowctl/ya.make create mode 100644 ydb/library/shop/sim_shop/config.proto create mode 100644 ydb/library/shop/sim_shop/myshop.cpp create mode 100644 ydb/library/shop/sim_shop/myshop.h create mode 100644 ydb/library/shop/sim_shop/myshopmain.cpp create mode 100644 ydb/library/shop/sim_shop/one.pb.txt create mode 100644 ydb/library/shop/sim_shop/two.pb.txt create mode 100644 ydb/library/shop/sim_shop/ya.make create mode 100644 ydb/library/shop/ut/estimator_ut.cpp create mode 100644 ydb/library/shop/ut/flowctl_ut.cpp create mode 100644 ydb/library/shop/ut/lazy_scheduler_ut.cpp create mode 100644 ydb/library/shop/ut/scheduler_ut.cpp create mode 100644 ydb/library/shop/ut/tr.lwt create mode 100644 ydb/library/shop/ut/ya.make create mode 100644 ydb/library/shop/valve.h create mode 100644 ydb/library/shop/ya.make diff --git a/ydb/library/analytics/all.h b/ydb/library/analytics/all.h new file mode 100644 index 000000000000..c3defbba4be6 --- /dev/null +++ b/ydb/library/analytics/all.h @@ -0,0 +1,10 @@ +#pragma once + +#include "asciiart_output.h" +#include "csv_output.h" +#include "data.h" +#include "html_output.h" +#include "json_output.h" +#include "protobuf.h" +#include "transform.h" +#include "util.h" diff --git a/ydb/library/analytics/analytics.cpp b/ydb/library/analytics/analytics.cpp new file mode 100644 index 000000000000..1b25263386bd --- /dev/null +++ b/ydb/library/analytics/analytics.cpp @@ -0,0 +1,5 @@ +#include "all.h" + +namespace NAnalytics { + +} diff --git a/ydb/library/analytics/asciiart_output.h b/ydb/library/analytics/asciiart_output.h new file mode 100644 index 000000000000..5b7398700ad8 --- /dev/null +++ b/ydb/library/analytics/asciiart_output.h @@ -0,0 +1,256 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "data.h" +#include "util.h" + +namespace NAnalytics { + +struct TAxis { + TString Name; + double From; + double To; + char Symbol; + bool Ticks; + + TAxis(const TString& name, double from, double to, char symbol = '+', bool ticks = true) + : Name(name) + , From(from) + , To(to) + , Symbol(symbol) + , Ticks(ticks) + {} + + double Place(double value) const + { + return (value - From) / (To - From); + } + + bool Get(const TRow& row, double& value) const + { + return row.Get(Name, value); + } +}; + +struct TChart { + int Width; + int Height; + bool Frame; + + TChart(int width, int height, bool frame = true) + : Width(width) + , Height(height) + , Frame(frame) + { + if (Width < 2) + Width = 2; + if (Height < 2) + Height = 2; + } +}; + +struct TPoint { + int X; + int Y; + char* Pixel; +}; + +class TScreen { +public: + TChart Chart; + TAxis Ox; + TAxis Oy; + TVector Screen; +public: + TScreen(const TChart& chart, const TAxis& ox, const TAxis& oy) + : Chart(chart) + , Ox(ox) + , Oy(oy) + , Screen(Chart.Width * Chart.Height, ' ') + {} + + int X(double x) const + { + return llrint(Ox.Place(x) * (Chart.Width - 1)); + } + + int Y(double y) const + { + return Chart.Height - 1 - llrint(Oy.Place(y) * (Chart.Height - 1)); + } + + TPoint At(double x, double y) + { + TPoint pt{X(x), Y(y), nullptr}; + if (Fits(pt)) { + pt.Pixel = &Screen[pt.Y * Chart.Width + pt.X]; + } + return pt; + } + + bool Fits(TPoint pt) const + { + return pt.X >= 0 && pt.X < Chart.Width + && pt.Y >= 0 && pt.Y < Chart.Height; + } + + TString Str() const + { + TStringStream ss; + size_t i = 0; + TString lmargin; + TString x1label; + TString x2label; + TString xtick = "-"; + TString y1label; + TString y2label; + TString ytick = "|"; + if (Ox.Ticks) { + x1label = Sprintf("%-7.2le", Ox.From); + x2label = Sprintf("%-7.2le", Ox.To); + xtick = "+"; + } + if (Oy.Ticks) { + y1label = Sprintf("%-7.2le ", Oy.From); + y2label = Sprintf("%-7.2le ", Oy.To); + int sz = Max(y1label.size(), y2label.size()); + y1label = TString(sz - y1label.size(), ' ') + y1label; + y2label = TString(sz - y2label.size(), ' ') + y2label; + lmargin = TString(sz, ' '); + ytick = "+"; + } + if (Chart.Frame) { + ss << lmargin << "." << TString(Chart.Width, '-') << ".\n"; + } + for (int iy = 0; iy < Chart.Height; iy++) { + if (iy == 0) { + ss << y2label; + if (Chart.Frame) + ss << ytick; + } else if (iy == Chart.Height - 1) { + ss << y1label; + if (Chart.Frame) + ss << ytick; + } else { + ss << lmargin; + if (Chart.Frame) + ss << "|"; + } + for (int ix = 0; ix < Chart.Width; ix++) + ss << Screen[i++]; + if (Chart.Frame) + ss << "|"; + ss << "\n"; + } + if (Chart.Frame) { + ss << lmargin << "'" << xtick + << TString(Chart.Width - 2, '-') + << xtick << "'\n"; + } + if (Ox.Ticks) { + ss << lmargin << " " << x1label + << TString(Max(Chart.Width - int(x1label.size()) - int(x2label.size()), 1), ' ') + << x2label << "\n"; + } + return ss.Str(); + } +}; + +class TLegend { +public: + TMap Symbols; + char DefSymbol = '+'; +public: + void Register(const TString& name) + { + if (name) + Symbols[name] = DefSymbol; + } + + void Build() + { + char c = 'A'; + for (auto& kv : Symbols) { + if (!kv.first) + continue; + kv.second = c; + if (c == '9') + c = 'a'; + else if (c == 'z') + c = 'A'; + else if (c == 'Z') + c = '1'; + else + c++; + } + } + + char Get(const TString& name) const + { + auto iter = Symbols.find(name); + return iter != Symbols.end()? iter->second: DefSymbol; + } + + TString Str(size_t columns) const + { + if (columns == 0) + columns = 1; + size_t height = (Symbols.size() + columns - 1) / columns; + TVector all; + TVector widths; + size_t width = 0; + size_t count = 0; + for (auto kv : Symbols) { + TString s = Sprintf("(%ld) %c = %s", count + 1, kv.second, kv.first.data()); + width = Max(width, s.size()); + all.push_back(s); + if (++count % height == 0) { + widths.push_back(width); + width = 0; + } + } + widths.push_back(width); + + TStringStream ss; + for (size_t row = 0; row < height; ++row) { + bool first = true; + for (size_t col = 0; col < widths.size(); col++) { + size_t idx = col * height + row; + if (idx < all.size()) { + ss << (first? "": " ") << Sprintf("%-*s", (int)widths[col], all[idx].data()); + first = false; + } + } + ss << Endl; + } + return ss.Str(); + } +}; + +inline TString PlotAsAsciiArt(const TTable& in, const TChart& chart, const TAxis& ox, const TAxis& oy, bool showLegend = true, size_t columns = 4) +{ + TLegend legend; + legend.DefSymbol = oy.Symbol; + for (const TRow& row : in) { + legend.Register(row.Name); + } + legend.Build(); + + TScreen screen(chart, ox, oy); + for (const TRow& row : in) { + double x, y; + if (ox.Get(row, x) && oy.Get(row, y)) { + TPoint pt = screen.At(Finitize(x), Finitize(y)); + if (pt.Pixel) { + *pt.Pixel = legend.Get(row.Name); + } + } + } + return screen.Str() + (showLegend? TString("\n") + legend.Str(columns): TString()); +} + +} diff --git a/ydb/library/analytics/csv_output.h b/ydb/library/analytics/csv_output.h new file mode 100644 index 000000000000..3b767b454c5a --- /dev/null +++ b/ydb/library/analytics/csv_output.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include +#include "data.h" + +namespace NAnalytics { + +inline TString ToCsv(const TTable& in, TString sep = TString("\t"), bool head = true) +{ + TSet cols; + bool hasName = false; + for (const TRow& row : in) { + hasName = hasName || !row.Name.empty(); + for (const auto& kv : row) { + cols.insert(kv.first); + } + } + + TStringStream ss; + if (head) { + bool first = true; + if (hasName) { + ss << (first? TString(): sep) << "Name"; + first = false; + } + for (const TString& c : cols) { + ss << (first? TString(): sep) << c; + first = false; + } + ss << Endl; + } + + for (const TRow& row : in) { + bool first = true; + if (hasName) { + ss << (first? TString(): sep) << row.Name; + first = false; + } + for (const TString& c : cols) { + ss << (first? TString(): sep); + first = false; + double value; + ss << (row.Get(c, value)? Sprintf("%le", value) : TString("-")); + } + ss << Endl; + } + return ss.Str(); +} + +} diff --git a/ydb/library/analytics/data.h b/ydb/library/analytics/data.h new file mode 100644 index 000000000000..fe544c72734c --- /dev/null +++ b/ydb/library/analytics/data.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include +#include + +namespace NAnalytics { + +struct TRow : public THashMap { + TString Name; + + bool Get(const TString& name, double& value) const + { + if (name == "_count") { // Special values + value = 1.0; + return true; + } + auto iter = find(name); + if (iter != end()) { + value = iter->second; + return true; + } else { + return false; + } + } +}; + +using TAttributes = THashMap; + +struct TTable : public TVector { + TAttributes Attributes; +}; + +struct TMatrix : public TVector { + size_t Rows; + size_t Cols; + + explicit TMatrix(size_t rows = 0, size_t cols = 0) + : TVector(rows * cols) + , Rows(rows) + , Cols(cols) + {} + + void Reset(size_t rows, size_t cols) + { + Rows = rows; + Cols = cols; + clear(); + resize(rows * cols); + } + + double& Cell(size_t row, size_t col) + { + Y_ABORT_UNLESS(row < Rows); + Y_ABORT_UNLESS(col < Cols); + return operator[](row * Cols + col); + } + + double Cell(size_t row, size_t col) const + { + Y_ABORT_UNLESS(row < Rows); + Y_ABORT_UNLESS(col < Cols); + return operator[](row * Cols + col); + } + + double CellSum() const + { + double sum = 0.0; + for (double x : *this) { + sum += x; + } + return sum; + } +}; + +} diff --git a/ydb/library/analytics/html_output.h b/ydb/library/analytics/html_output.h new file mode 100644 index 000000000000..bdc6213a3149 --- /dev/null +++ b/ydb/library/analytics/html_output.h @@ -0,0 +1,86 @@ +#pragma once + +#include +#include +#include +#include "data.h" + +namespace NAnalytics { + +inline TString ToHtml(const TTable& in) +{ + TSet cols; + bool hasName = false; + for (const TRow& row : in) { + hasName = hasName || !row.Name.empty(); + for (const auto& kv : row) { + cols.insert(kv.first); + } + } + + TStringStream ss; + ss << "
"; + ss << ""; + if (hasName) { + ss << ""; + } + for (const TString& c : cols) { + ss << ""; + } + ss << ""; + + for (const TRow& row : in) { + ss << ""; + if (hasName) { + ss << ""; + } + for (const TString& c : cols) { + double value; + ss << ""; + } + ss << ""; + } + ss << "
Name" << c << "
" << row.Name << "" << (row.Get(c, value)? Sprintf("%lf", value) : TString("-")) << "
"; + + return ss.Str(); +} + +inline TString ToTransposedHtml(const TTable& in) +{ + TSet cols; + bool hasName = false; + for (const TRow& row : in) { + hasName = hasName || !row.Name.empty(); + for (const auto& kv : row) { + cols.insert(kv.first); + } + } + + TStringStream ss; + ss << ""; + if (hasName) { + ss << ""; + ss << ""; + for (const TRow& row : in) { + ss << ""; + } + ss << ""; + } + + ss << ""; + + for (const TString& c : cols) { + ss << ""; + ss << ""; + for (const TRow& row : in) { + double value; + ss << ""; + } + ss << ""; + } + ss << "
Name" << row.Name << "
" << c << "" << (row.Get(c, value)? Sprintf("%lf", value) : TString("-")) << "
"; + + return ss.Str(); +} + +} diff --git a/ydb/library/analytics/json_output.h b/ydb/library/analytics/json_output.h new file mode 100644 index 000000000000..189f9802d3ca --- /dev/null +++ b/ydb/library/analytics/json_output.h @@ -0,0 +1,98 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "data.h" +#include "util.h" + +namespace NAnalytics { + +inline TString ToJsonFlot(const TTable& in, const TString& xno, const TVector& ynos, const TString& opts = TString()) +{ + TStringStream ss; + ss << "[ "; + bool first = true; + + TString xn; + THashSet xopts; + ParseNameAndOpts(xno, xn, xopts); + bool xstack = xopts.contains("stack"); + + for (const TString& yno : ynos) { + TString yn; + THashSet yopts; + ParseNameAndOpts(yno, yn, yopts); + bool ystackOpt = yopts.contains("stack"); + + ss << (first? "": ",\n ") << "{ " << opts << (opts? ", ": "") << "\"label\": \"" << yn << "\", \"data\": [ "; + bool first2 = true; + using TPt = std::tuple; + std::vector pts; + for (const TRow& row : in) { + double x, y; + if (row.Get(xn, x) && row.Get(yn, y)) { + pts.emplace_back(x, y, row.Name); + } + } + + if (xstack) { + std::sort(pts.begin(), pts.end(), [] (const TPt& a, const TPt& b) { + // At first sort by Name, then by x, then by y + return std::make_tuple(std::get<2>(a), std::get<0>(a), std::get<1>(a)) < + std::make_tuple(std::get<2>(b), std::get<0>(b), std::get<1>(b)); + }); + } else { + std::sort(pts.begin(), pts.end()); + } + + double x = 0.0, xsum = 0.0; + double y = 0.0, ysum = 0.0; + for (auto& pt : pts) { + if (xstack) { + x = xsum; + xsum += std::get<0>(pt); + } else { + x = std::get<0>(pt); + } + + if (ystackOpt) { + y = ysum; + ysum += std::get<1>(pt); + } else { + y = std::get<1>(pt); + } + + ss << (first2? "": ", ") << "[" + << Sprintf("%.6lf", Finitize(x)) << ", " // x coordinate + << Sprintf("%.6lf", Finitize(y)) << ", " // y coordinate + << "\"" << std::get<2>(pt) << "\", " // label + << Sprintf("%.6lf", std::get<0>(pt)) << ", " // x label (real value) + << Sprintf("%.6lf", std::get<1>(pt)) // y label (real value) + << "]"; + first2 = false; + } + // Add final point + if (!first2 && (xstack || ystackOpt)) { + if (xstack) + x = xsum; + if (ystackOpt) + y = ysum; + ss << (first2? "": ", ") << "[" + << Sprintf("%.6lf", Finitize(x)) << ", " // x coordinate + << Sprintf("%.6lf", Finitize(y)) << ", " // y coordinate + << "\"\", " + << Sprintf("%.6lf", x) << ", " // x label (real value) + << Sprintf("%.6lf", y) // y label (real value) + << "]"; + } + ss << " ] }"; + first = false; + } + ss << "\n]"; + return ss.Str(); +} + +} diff --git a/ydb/library/analytics/protobuf.h b/ydb/library/analytics/protobuf.h new file mode 100644 index 000000000000..202bd54c7175 --- /dev/null +++ b/ydb/library/analytics/protobuf.h @@ -0,0 +1,49 @@ +#pragma once + +#include "data.h" +#include + +namespace NAnalytics { + +inline void ToProtoBuf(const TTable& in, TTableData* tableData) +{ + for (const TRow& row : in) { + TRowData* rowData = tableData->AddRows(); + if (row.Name) { + rowData->SetName(row.Name); + } + for (const auto& kv : row) { + TFieldData* fieldData = rowData->AddFields(); + fieldData->SetKey(kv.first); + fieldData->SetValue(kv.second); + } + } + for (const auto& av : in.Attributes) { + TAttributeData* attrData = tableData->AddAttributes(); + attrData->SetAttribute(av.first); + attrData->SetValue(av.second); + } +} + +inline TTable FromProtoBuf(const TTableData& tableData) +{ + TTable table; + for (int i = 0; i < tableData.GetAttributes().size(); i++) { + const TAttributeData& attrData = tableData.GetAttributes(i); + table.Attributes[attrData.GetAttribute()] = attrData.GetValue(); + } + + for (int i = 0; i < tableData.GetRows().size(); i++) { + const TRowData& rowData = tableData.GetRows(i); + table.push_back(TRow()); + TRow& row = table.back(); + row.Name = rowData.GetName(); + for (int j = 0; j < rowData.GetFields().size(); j++) { + const TFieldData& fieldData = rowData.GetFields(j); + row[fieldData.GetKey()] = fieldData.GetValue(); + } + } + return table; +} + +} diff --git a/ydb/library/analytics/protos/data.proto b/ydb/library/analytics/protos/data.proto new file mode 100644 index 000000000000..9e500c9b0262 --- /dev/null +++ b/ydb/library/analytics/protos/data.proto @@ -0,0 +1,21 @@ +package NAnalytics; + +message TFieldData { + optional string Key = 1; + optional double Value = 2; +} + +message TRowData { + optional string Name = 1; + repeated TFieldData Fields = 2; +} + +message TAttributeData { + optional string Attribute = 1; + optional string Value = 2; +} + +message TTableData { + repeated TRowData Rows = 1; + repeated TAttributeData Attributes = 2; +} diff --git a/ydb/library/analytics/protos/ya.make b/ydb/library/analytics/protos/ya.make new file mode 100644 index 000000000000..588646b21b51 --- /dev/null +++ b/ydb/library/analytics/protos/ya.make @@ -0,0 +1,11 @@ +PROTO_LIBRARY() + +SUBSCRIBER(g:kikimr) + +SRCS( + data.proto +) + +EXCLUDE_TAGS(GO_PROTO) + +END() diff --git a/ydb/library/analytics/transform.h b/ydb/library/analytics/transform.h new file mode 100644 index 000000000000..29dfba7b7449 --- /dev/null +++ b/ydb/library/analytics/transform.h @@ -0,0 +1,192 @@ +#pragma once + +#include "data.h" + +namespace NAnalytics { + +template +inline TTable Histogram(const TTable& in, TSkip skip, + const TString& xn_out, TX x_in, + const TString& yn_out, TY y_in, + double x1, double x2, double dx) +{ + long buckets = (x2 - x1) / dx; + TTable out; + TString yn_sum = yn_out + "_sum"; + TString yn_share = yn_out + "_share"; + double ysum = 0.0; + out.resize(buckets); + for (size_t i = 0; i < out.size(); i++) { + double lb = x1 + dx*i; + double ub = lb + dx; + out[i].Name = "[" + ToString(lb) + ";" + ToString(ub) + (ub==x2? "]": ")"); + out[i][xn_out] = (lb + ub) / 2; + out[i][yn_sum] = 0.0; + } + for (const auto& row : in) { + if (skip(row)) { + continue; + } + double x = x_in(row); + long i = (x - x1) / dx; + if (x == x2) { // Special hack to include right edge + i--; + } + double y = y_in(row); + ysum += y; + if (i >= 0 && i < buckets) { + out[i][yn_sum] += y; + } + } + for (TRow& row : out) { + if (ysum != 0.0) { + row[yn_share] = row[yn_sum] / ysum; + } + } + return out; +} + +inline TTable HistogramAll(const TTable& in, const TString& xn, double x1, double x2, double dx) +{ + long buckets = (dx == 0.0? 1: (x2 - x1) / dx); + TTable out; + THashMap colSum; + out.resize(buckets); + + TSet cols; + for (auto& row : in) { + for (auto& kv : row) { + cols.insert(kv.first); + } + } + cols.insert("_count"); + cols.erase(xn); + + for (const TString& col : cols) { + colSum[col] = 0.0; + } + + for (size_t i = 0; i < out.size(); i++) { + double lb = x1 + dx*i; + double ub = lb + dx; + TRow& row = out[i]; + row.Name = "[" + ToString(lb) + ";" + ToString(ub) + (ub==x2? "]": ")"); + row[xn] = (lb + ub) / 2; + for (const TString& col : cols) { + row[col + "_sum"] = 0.0; + } + } + for (const TRow& row_in : in) { + double x; + if (!row_in.Get(xn, x)) { + continue; + } + long i = (dx == 0.0? 0: (x - x1) / dx); + if (x == x2 && dx > 0.0) { // Special hack to include right edge + i--; + } + for (const auto& kv : row_in) { + const TString& yn = kv.first; + if (yn == xn) { + continue; + } + double y = kv.second; + colSum[yn] += y; + if (i >= 0 && i < buckets) { + out[i][yn + "_cnt"]++; + out[i][yn + "_sum"] += y; + if (out[i].contains(yn + "_min")) { + out[i][yn + "_min"] = Min(y, out[i][yn + "_min"]); + } else { + out[i][yn + "_min"] = y; + } + if (out[i].contains(yn + "_max")) { + out[i][yn + "_max"] = Max(y, out[i][yn + "_max"]); + } else { + out[i][yn + "_max"] = y; + } + } + } + colSum["_count"]++; + if (i >= 0 && i < buckets) { + out[i]["_count_sum"]++; + } + } + for (TRow& row : out) { + for (const TString& col : cols) { + double ysum = colSum[col]; + if (col != "_count") { + if (row[col + "_cnt"] != 0.0) { + row[col + "_avg"] = row[col + "_sum"] / row[col + "_cnt"]; + } + } + if (ysum != 0.0) { + row[col + "_share"] = row[col + "_sum"] / ysum; + } + } + } + return out; +} + +inline TMatrix CovarianceMatrix(const TTable& in) +{ + TSet cols; + for (auto& row : in) { + for (auto& kv : row) { + cols.insert(kv.first); + } + } + + struct TAggregate { + size_t Idx = 0; + double Sum = 0; + size_t Count = 0; + double Mean = 0; + }; + + THashMap colAggr; + + size_t colCount = 0; + for (const TString& col : cols) { + TAggregate& aggr = colAggr[col]; + aggr.Idx = colCount++; + } + + for (const TRow& row : in) { + for (const auto& kv : row) { + const TString& xn = kv.first; + double x = kv.second; + TAggregate& aggr = colAggr[xn]; + aggr.Sum += x; + aggr.Count++; + } + } + + for (auto& kv : colAggr) { + TAggregate& aggr = kv.second; + aggr.Mean = aggr.Sum / aggr.Count; + } + + TMatrix covCount(cols.size(), cols.size()); + TMatrix cov(cols.size(), cols.size()); + for (const TRow& row : in) { + for (const auto& kv1 : row) { + double x = kv1.second; + TAggregate& xaggr = colAggr[kv1.first]; + for (const auto& kv2 : row) { + double y = kv2.second; + TAggregate& yaggr = colAggr[kv2.first]; + covCount.Cell(xaggr.Idx, yaggr.Idx)++; + cov.Cell(xaggr.Idx, yaggr.Idx) += (x - xaggr.Mean) * (y - yaggr.Mean); + } + } + } + + for (size_t idx = 0; idx < cov.size(); idx++) { + cov[idx] /= covCount[idx]; + } + + return cov; +} + +} diff --git a/ydb/library/analytics/util.h b/ydb/library/analytics/util.h new file mode 100644 index 000000000000..e07d06cc43f9 --- /dev/null +++ b/ydb/library/analytics/util.h @@ -0,0 +1,122 @@ +#pragma once + +#include "data.h" +#include +#include +#include + +namespace NAnalytics { + +// Get rid of NaNs and INFs +inline double Finitize(double x, double notFiniteValue = 0.0) +{ + return isfinite(x)? x: notFiniteValue; +} + +inline void ParseNameAndOpts(const TString& nameAndOpts, TString& name, THashSet& opts) +{ + name.clear(); + opts.clear(); + bool first = true; + auto vs = SplitString(nameAndOpts, "-"); + for (const auto& s : vs) { + if (first) { + name = s; + first = false; + } else { + opts.insert(s); + } + } +} + +inline TString ParseName(const TString& nameAndOpts) +{ + auto vs = SplitString(nameAndOpts, "-"); + if (vs.empty()) { + return TString(); + } else { + return vs[0]; + } +} + +template +inline R AccumulateIfExist(const TString& name, const TTable& table, R r, T t) +{ + ForEach(table.begin(), table.end(), [=,&r] (const TRow& row) { + double value; + if (row.Get(name, value)) { + r = t(r, value); + } + }); + return r; +} + +inline double MinValue(const TString& nameAndOpts, const TTable& table) +{ + TString name; + THashSet opts; + ParseNameAndOpts(nameAndOpts, name, opts); + bool stack = opts.contains("stack"); + if (stack) { + return 0.0; + } else { + auto zero = 0.0; + + return AccumulateIfExist(name, table, 1.0 / zero /*+inf*/, [] (double x, double y) { + return Min(x, y); + }); + } +} + +inline double MaxValue(const TString& nameAndOpts, const TTable& table) +{ + TString name; + THashSet opts; + ParseNameAndOpts(nameAndOpts, name, opts); + bool stack = opts.contains("stack"); + if (stack) { + return AccumulateIfExist(name, table, 0.0, [] (double x, double y) { + return x + y; + }); + } else { + auto zero = 0.0; + + return AccumulateIfExist(name, table, -1.0 / zero /*-inf*/, [] (double x, double y) { + return Max(x, y); + }); + } +} + +template +inline void Map(TTable& table, const TString& rname, T t) +{ + ForEach(table.begin(), table.end(), [=] (TRow& row) { + row[rname] = t(row); + }); +} + +inline std::function HasNoValueFor(TString name) +{ + return [=] (const TRow& row) -> bool { + double value; + return !row.Get(name, value); + }; +} + + +inline std::function GetValueFor(TString name, double defVal = 0.0) +{ + return [=] (const TRow& row) -> double { + double value; + return row.Get(name, value)? value: defVal; + }; +} + +inline std::function Const(double defVal = 0.0) +{ + return [=] (const TRow&) { + return defVal; + }; +} + +} diff --git a/ydb/library/analytics/ya.make b/ydb/library/analytics/ya.make new file mode 100644 index 000000000000..5c20a3f42c24 --- /dev/null +++ b/ydb/library/analytics/ya.make @@ -0,0 +1,15 @@ +LIBRARY() + +PEERDIR( + ydb/library/analytics/protos +) + +SRCS( + analytics.cpp +) + +END() + +RECURSE( + protos +) diff --git a/ydb/library/drr/drr.cpp b/ydb/library/drr/drr.cpp new file mode 100644 index 000000000000..7f948daba888 --- /dev/null +++ b/ydb/library/drr/drr.cpp @@ -0,0 +1,5 @@ +#include "drr.h" + +namespace NScheduling { + +} diff --git a/ydb/library/drr/drr.h b/ydb/library/drr/drr.h new file mode 100644 index 000000000000..601eda29ae82 --- /dev/null +++ b/ydb/library/drr/drr.h @@ -0,0 +1,363 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "probes.h" + +namespace NScheduling { + +class TDRRSchedulerBase; +template class TDRRScheduler; + +class TDRRQueue { +private: + TDRRSchedulerBase* Scheduler = nullptr; + TWeight Weight; + TUCost DeficitCounter; + TUCost QuantumFraction = 0; + TUCost MaxBurst; + // Active list (cyclic double-linked list of active queues for round-robin to cycle through) + TDRRQueue* ActNext = nullptr; + TDRRQueue* ActPrev = nullptr; + TString Name; +public: + TDRRQueue(TWeight w = 1, TUCost maxBurst = 0, const TString& name = TString()) + : Weight(w) + , DeficitCounter(maxBurst) + , MaxBurst(maxBurst) + , Name(name) + {} + + TDRRSchedulerBase* GetScheduler() { return Scheduler; } + TWeight GetWeight() const { return Weight; } + TUCost GetDeficitCounter() const { return DeficitCounter; } + TUCost GetQuantumFraction() const { return QuantumFraction; } + const TString& GetName() const { return Name; } + bool IsActive() const { return ActNext != nullptr; } +protected: + void OnSchedulerAttach() {} // To be overriden in derived class + void OnSchedulerDetach() {} // To be overriden in derived class +private: // For TDRRScheduler + friend class TDRRSchedulerBase; + template friend class TDRRScheduler; + + void SetScheduler(TDRRSchedulerBase* scheduler) { Scheduler = scheduler; } + void SetWeight(TWeight w) { Y_ABORT_UNLESS(w != 0, "zero weight in queue '%s'", Name.data()); Weight = w; } + void SetDeficitCounter(TUCost c) { DeficitCounter = c; } + void SetQuantumFraction(TUCost c) { QuantumFraction = c; } + + TDRRQueue* GetActNext() { return ActNext; } + void SetActNext(TDRRQueue* v) { ActNext = v; } + TDRRQueue* GetActPrev() { return ActPrev; } + void SetActPrev(TDRRQueue* v) { ActPrev = v; } + + void AddCredit(TUCost c) + { + DeficitCounter += c; + } + + void UseCredit(TUCost c) + { + if (DeficitCounter > c) { + DeficitCounter -= c; + } else { + DeficitCounter = 0; + } + } + + bool CreditOverflow() const + { + return DeficitCounter >= MaxBurst; + } + + void FixCreditOverflow() + { + DeficitCounter = Min(MaxBurst, DeficitCounter); + } +}; + +class TDRRSchedulerBase: public TDRRQueue { +protected: + TUCost Quantum; + TWeight AllWeight = 0; + TWeight ActWeight = 0; + TDRRQueue* CurQueue = nullptr; + TDRRQueue* LastQueue = nullptr; + void* Peek = nullptr; +public: + TDRRSchedulerBase(TUCost quantum, TWeight w = 1, TUCost maxBurst = 0, const TString& name = TString()) + : TDRRQueue(w, maxBurst, name) + , Quantum(quantum) + {} + + // Must be called when queue becomes backlogged + void ActivateQueue(TDRRQueue* queue) + { + if (queue->IsActive()) { + return; + } + DRR_PROBE(ActivateQueue, GetName(), queue->GetName()); + ActWeight += queue->GetWeight(); + if (CurQueue == nullptr) { + // First active queue + queue->SetActNext(queue); + queue->SetActPrev(queue); + CurQueue = queue; + if (GetScheduler()) { + GetScheduler()->ActivateQueue(this); + } + } else { + // Add queue to the tail of active list to avoid unfairness due to + // otherwise possible multiple reorderings in a single round + TDRRQueue* after = CurQueue->GetActPrev(); + queue->SetActNext(CurQueue); + queue->SetActPrev(after); + CurQueue->SetActPrev(queue); + after->SetActNext(queue); + } + } + + // Must be called after each push to queue front + void DropCache(TDRRQueue* queue) + { + DRR_PROBE(DropCache, GetName(), queue->GetName()); + if (CurQueue == queue && Peek) { + DRR_PROBE(CacheDropped, GetName(), queue->GetName()); + Peek = nullptr; + if (GetScheduler()) { + GetScheduler()->DropCache(this); + } + } + } +}; + +// Deficit Weighted Round Robin scheduling algorithm +// http://en.wikipedia.org/wiki/Deficit_round_robin +// TODO(serxa): add TSharingPolicy (as template parameter that is inherited) to control Quantum splitting +// TODO(serxa): add support for non-zero DeficitCounter while idle +template +class TDRRScheduler: public TDRRSchedulerBase { + static_assert(std::is_base_of::value, "TQueueType must inherit TDRRQueue"); +private: + typedef std::shared_ptr TQueuePtr; + typedef THashMap TAllQueues; + TAllQueues AllQueues; +public: + typedef typename TQueueType::TTask TTask; + explicit TDRRScheduler(TUCost quantum, TWeight w = 1, TUCost maxBurst = 0, const TString& name = TString()) + : TDRRSchedulerBase(quantum, w, maxBurst, name) + {} + + template + void ForEachQueue(Func func) const { + for (auto kv : AllQueues) { + func(kv.first, kv.second.Get()); + } + } + + // Add an empty queue + // NOTE: if queue is not empty ActivateQueue() must be called after Add() + bool AddQueue(typename TTypeTraits::TFuncParam id, TQueuePtr queue) + { + if (AllQueues.contains(id)) { + return false; + } + queue->SetScheduler(this); + AllQueues.insert(std::make_pair(id, queue)); + AllWeight += queue->GetWeight(); + UpdateQuantums(); + queue->OnSchedulerAttach(); + return true; + } + + // Delete queue by Id + void DeleteQueue(typename TTypeTraits::TFuncParam id) + { + typename TAllQueues::iterator i = AllQueues.find(id); + if (i != AllQueues.end()) { + TQueueType* queue = i->second.get(); + queue->OnSchedulerDetach(); + if (queue->IsActive()) { + DeactivateQueue(queue); + } + queue->SetScheduler(nullptr); + AllWeight -= queue->GetWeight(); + AllQueues.erase(id); + } + } + + // Get queue by Id + TQueuePtr GetQueue(typename TTypeTraits::TFuncParam id) + { + typename TAllQueues::iterator i = AllQueues.find(id); + if (i != AllQueues.end()) { + return i->second; + } else { + return TQueuePtr(); + } + } + + // Get queue by Id + TQueueType* GetQueuePtr(typename TTypeTraits::TFuncParam id) + { + typename TAllQueues::iterator i = AllQueues.find(id); + if (i != AllQueues.end()) { + return i->second.Get(); + } else { + return nullptr; + } + } + + // Update queue weight + void UpdateQueueWeight(TQueueType* queue, TWeight w) + { + if (w) { + AllWeight -= queue->GetWeight(); + if (queue->IsActive()) { + ActWeight -= queue->GetWeight(); + } + queue->SetWeight(w); + if (queue->IsActive()) { + ActWeight += w; + } + AllWeight += w; + UpdateQuantums(); + } + } + + TQueueType* GetCurQueue() + { + return static_cast(CurQueue); + } + + TTask* GetPeek() + { + return static_cast(Peek); + } + + // Runs scheduling algorithm and returns task to be served next or nullptr if empty + TTask* PeekTask() + { + if (!Peek) { + if (!CurQueue) { + LastQueue = nullptr; + return nullptr; + } + + if (!LastQueue) { + GiveCredit(); // For first round at start of backlogged period + } + while (GetCurQueue()->Empty() || GetCurQueue()->PeekTask()->GetCost() > CurQueue->GetDeficitCounter()) { + if (!NextNonEmptyQueue()) { + // If all queue was deactivated due to credit overflow + LastQueue = nullptr; + return nullptr; + } + } + Peek = GetCurQueue()->PeekTask(); + } + return GetPeek(); + } + + // Pops peek task from queue + void PopTask() + { + if (!PeekTask()) { + return; // No more tasks + } + + // Pop peek task from current queue and use credit + CurQueue->UseCredit(GetPeek()->GetCost()); + Peek = nullptr; +// Cerr << "pop\t" << (ui64)CurQueue << "\tDC:" << CurQueue->DeficitCounter << Endl; + GetCurQueue()->PopTask(); + + LastQueue = CurQueue; + } + + bool Empty() + { + PeekTask(); + return !CurQueue; + } + +private: + void GiveCredit() + { + // Maintain given Quantum to be split to exactly one round of active queues + CurQueue->AddCredit(CurQueue->GetQuantumFraction()*AllWeight/ActWeight); +// Cerr << "credit\t" << (ui64)CurQueue << "\tplus:" << CurQueue->GetQuantumFraction()*AllWeight/ActWeight +// << "\tDC:" << CurQueue->DeficitCounter << Endl; + } + + bool NextNonEmptyQueue(TDRRQueue* next = nullptr) + { + while (true) { + CurQueue = next? next: CurQueue->GetActNext(); + next = nullptr; + GiveCredit(); + if (GetCurQueue()->Empty()) { + if (CurQueue->CreditOverflow()) { + next = DeactivateQueueImpl(CurQueue); + if (!CurQueue) { + return false; // Last empty queue was deactivated due to credit overflow + } + } + continue; + } + break; + } + return true; + } + + void DeactivateQueue(TDRRQueue* queue) + { + if (TDRRQueue* next = DeactivateQueueImpl(queue)) { + NextNonEmptyQueue(next); + } + } + + TDRRQueue* DeactivateQueueImpl(TDRRQueue* queue) + { +// Cerr << "deactivate\t" << (ui64)queue << Endl; + TDRRQueue* ret = nullptr; + ActWeight -= queue->GetWeight(); + Y_ASSERT(queue->IsActive()); + TDRRQueue* before = queue->GetActPrev(); + TDRRQueue* after = queue->GetActNext(); + bool lastActive = (before == queue); + if (lastActive) { + CurQueue = nullptr; + } else { + if (queue == CurQueue) { + ret = CurQueue->GetActNext(); + } + before->SetActNext(after); + after->SetActPrev(before); + } + queue->SetActNext(nullptr); + queue->SetActPrev(nullptr); + + // Keep deficit counter of non-backlogged queues limited by MaxBurst + // to exclude accumulation of resource while being idle + queue->FixCreditOverflow(); + return ret; + } + + void UpdateQuantums() + { + TUCost qsum = Quantum; + TWeight wsum = AllWeight; + for (typename TAllQueues::iterator i = AllQueues.begin(), e = AllQueues.end(); i != e; ++i) { + TQueueType* qi = i->second.get(); + qi->SetQuantumFraction(WCut(qi->GetWeight(), wsum, qsum)); + } + } +}; + +} diff --git a/ydb/library/drr/probes.cpp b/ydb/library/drr/probes.cpp new file mode 100644 index 000000000000..4433d18d0d24 --- /dev/null +++ b/ydb/library/drr/probes.cpp @@ -0,0 +1,3 @@ +#include "probes.h" + +LWTRACE_DEFINE_PROVIDER(SCHEDULING_DRR_PROVIDER) diff --git a/ydb/library/drr/probes.h b/ydb/library/drr/probes.h new file mode 100644 index 000000000000..29861e8ecb26 --- /dev/null +++ b/ydb/library/drr/probes.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#define DRR_PROBE(name, ...) GLOBAL_LWPROBE(SCHEDULING_DRR_PROVIDER, name, ## __VA_ARGS__) + +#define SCHEDULING_DRR_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ + PROBE(ActivateQueue, GROUPS("Scheduling", "Drr"), \ + TYPES(TString,TString), \ + NAMES("parent","queue")) \ + PROBE(DropCache, GROUPS("Scheduling", "Drr"), \ + TYPES(TString,TString), \ + NAMES("parent","queue")) \ + PROBE(CacheDropped, GROUPS("Scheduling", "Drr"), \ + TYPES(TString,TString), \ + NAMES("parent","queue")) \ + PROBE(Info, GROUPS("Scheduling", "DrrDetails"), \ + TYPES(TString,TString), \ + NAMES("drr","info")) \ + /**/ + +LWTRACE_DECLARE_PROVIDER(SCHEDULING_DRR_PROVIDER) diff --git a/ydb/library/drr/ut/drr_ut.cpp b/ydb/library/drr/ut/drr_ut.cpp new file mode 100644 index 000000000000..ae8324539b0e --- /dev/null +++ b/ydb/library/drr/ut/drr_ut.cpp @@ -0,0 +1,581 @@ +#include +#include + +#include +#include +#include +#include + +Y_UNIT_TEST_SUITE(SchedulingDRR) { + using namespace NScheduling; + + class TMyQueue; + + class TMyTask { + public: + TUCost Cost; + TMyQueue* Queue; // Needed only for test + public: + TMyTask(TUCost cost) + : Cost(cost) + , Queue(nullptr) + {} + + TUCost GetCost() const + { + return Cost; + } + }; + + class TMyQueue: public TDRRQueue { + public: + typedef TMyTask TTask; + public: + typedef TList TTasks; + TString Name; + TTasks Tasks; + public: // Interface for clients + TMyQueue(const TString& name, TWeight w = 1, TUCost maxBurst = 0) + : TDRRQueue(w, maxBurst) + , Name(name) + {} + + ~TMyQueue() + { + for (TTasks::iterator i = Tasks.begin(), e = Tasks.end(); i != e; ++i) { + delete *i; + } + } + + void PushTask(TMyTask* task) + { + task->Queue = this; + if (Tasks.empty()) { + // Scheduler must be notified on first task in queue + if (GetScheduler()) { + GetScheduler()->ActivateQueue(this); + } + } + Tasks.push_back(task); + } + + void PushTaskFront(TMyTask* task) + { + task->Queue = this; + if (Tasks.empty()) { + // Scheduler must be notified on first task in queue + if (GetScheduler()) { + GetScheduler()->ActivateQueue(this); + } + } + Tasks.push_front(task); + if (GetScheduler()) { + GetScheduler()->DropCache(this); + } + } + public: // Interface for scheduler + void OnSchedulerAttach() + { + Y_ASSERT(GetScheduler() != nullptr); + if (!Tasks.empty()) { + GetScheduler()->ActivateQueue(this); + } + } + + TTask* PeekTask() + { + UNIT_ASSERT(!Tasks.empty()); + return Tasks.front(); + } + + void PopTask() + { + UNIT_ASSERT(!Tasks.empty()); + Tasks.pop_front(); + } + + bool Empty() const + { + return Tasks.empty(); + } + }; + + void Generate(TMyQueue* queue, const TString& tasks) + { + TVector v = SplitString(tasks, " "); + for (size_t i = 0; i < v.size(); i++) { + queue->PushTask(new TMyTask(FromString(v[i]))); + } + } + + void GenerateFront(TMyQueue* queue, const TString& tasks) + { + TVector v = SplitString(tasks, " "); + for (size_t i = 0; i < v.size(); i++) { + queue->PushTaskFront(new TMyTask(FromString(v[i]))); + } + } + + template + TString Schedule(TDRR& drr, size_t count = size_t(-1), bool printcost = false) { + TStringStream ss; + while (count--) { + TMyTask* task = drr.PeekTask(); + if (!task) + break; + drr.PopTask(); + ss << task->Queue->Name; + if (printcost) { + ss << task->Cost; + } + delete task; + } + if (count != size_t(-1)) { + UNIT_ASSERT(drr.PeekTask() == nullptr); + } + return ss.Str(); + } + + typedef std::shared_ptr TQueuePtr; + + Y_UNIT_TEST(SimpleDRR) { + TDRRScheduler drr(100); + + TMyQueue* A; + TMyQueue* B; + drr.AddQueue("A", TQueuePtr(A = new TMyQueue("A"))); + drr.AddQueue("B", TQueuePtr(B = new TMyQueue("B"))); + + Generate(A, "100 100 100"); // 50 + Generate(B, "100 100 100"); // 50 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "ABABAB"); + + Generate(A, "50 50 50 50 50"); // 50 + Generate(B, "50 50 50 50 50"); // 50 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "ABABABABAB"); + + Generate(A, "20 20 20 20 20 20 20"); // 50 + Generate(B, "20 20 20 20 20 20 20"); // 50 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "AABBAAABBBAABB"); + + Generate(A, "20 20 20 20 20 20 20"); // 50 + Generate(B, "50 50 50" ); // 50 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "AABAAABAAB"); + + Generate(A, " 100 100"); // 50 + Generate(B, "20 20 20 20 20 20 20 "); // 50 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "BBABBBBBA"); + + TMyQueue* C; + drr.AddQueue("C", TQueuePtr(C = new TMyQueue("C", 2))); + + Generate(A, "20 20 20 20 20 20"); // 25 + Generate(B, "20 20 20 20 20 20"); // 25 + Generate(C, "20 20 20 20 20 20 20 20 20 20 20"); // 50 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "ABCCABCCCABCCAABBCCCABC"); + + drr.GetQueue("B"); // just to instantiate GetQueue() function from template + + drr.DeleteQueue("A"); + // DRR.DeleteQueue("B"); // scheduler must delete queue be itself + } + + Y_UNIT_TEST(SimpleDRRLag) { + TDRRScheduler drr(100); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + TMyQueue* E; + drr.AddQueue("A", TQueuePtr(A = new TMyQueue("A"))); + drr.AddQueue("B", TQueuePtr(B = new TMyQueue("B"))); + drr.AddQueue("C", TQueuePtr(C = new TMyQueue("C"))); + drr.AddQueue("D", TQueuePtr(D = new TMyQueue("D"))); + drr.AddQueue("E", TQueuePtr(E = new TMyQueue("E"))); + + Generate(A, "500 500 500"); // 25 + Generate(B, "500 500 500"); // 25 + Generate(C, "500 500 500"); // 25 + Generate(D, "500 500 500"); // 25 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, 8), "ABCDABCD"); + Generate(E, "500"); // 100 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "ABCED"); + } + + Y_UNIT_TEST(SimpleDRRWithOneBursty) { + TDRRScheduler drr(100); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + TMyQueue* E; + drr.AddQueue("A", TQueuePtr(A = new TMyQueue("A"))); + drr.AddQueue("B", TQueuePtr(B = new TMyQueue("B"))); + drr.AddQueue("C", TQueuePtr(C = new TMyQueue("C"))); + drr.AddQueue("D", TQueuePtr(D = new TMyQueue("D"))); + drr.AddQueue("E", TQueuePtr(E = new TMyQueue("E", 1, 500))); + + Generate(A, "500 500 500"); // 25 + Generate(B, "500 500 500"); // 25 + Generate(C, "500 500 500"); // 25 + Generate(D, "500 500 500"); // 25 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, 8), "ABCDABCD"); + Generate(E, "500"); // 100 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "EABCD"); + + // The same test to avoid effect of first message after add + Generate(A, "500 500 500"); // 25 + Generate(B, "500 500 500"); // 25 + Generate(C, "500 500 500"); // 25 + Generate(D, "500 500 500"); // 25 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, 8), "ABCDABCD"); + Generate(E, "500"); // 20 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "EABCD"); + } + + Y_UNIT_TEST(SimpleDRRWithAllBursty) { + TDRRScheduler drr(100); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + TMyQueue* E; + drr.AddQueue("A", TQueuePtr(A = new TMyQueue("A", 1, 500))); + drr.AddQueue("B", TQueuePtr(B = new TMyQueue("B", 1, 500))); + drr.AddQueue("C", TQueuePtr(C = new TMyQueue("C", 1, 500))); + drr.AddQueue("D", TQueuePtr(D = new TMyQueue("D", 1, 500))); + drr.AddQueue("E", TQueuePtr(E = new TMyQueue("E", 1, 500))); + + Generate(A, "500 500 500"); // 25 + Generate(B, "500 500 500"); // 25 + Generate(C, "500 500 500"); // 25 + Generate(D, "500 500 500"); // 25 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, 8), "ABCDABCD"); + Generate(E, "500"); // 20 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "EABCD"); + } + + Y_UNIT_TEST(DoubleDRR) { + typedef TDRRScheduler TInnerDRR; + typedef std::shared_ptr TInnerDRRPtr; + typedef TDRRScheduler TOuterDRR; + TOuterDRR drr(200); + + TInnerDRR* G; + drr.AddQueue("G", TInnerDRRPtr(G = new TInnerDRR(200))); + TInnerDRR* H; + drr.AddQueue("H", TInnerDRRPtr(H = new TInnerDRR(200))); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + TMyQueue* E; + TMyQueue* X; + G->AddQueue("A", TQueuePtr(A = new TMyQueue("A"))); + G->AddQueue("B", TQueuePtr(B = new TMyQueue("B"))); + G->AddQueue("C", TQueuePtr(C = new TMyQueue("C"))); + G->AddQueue("D", TQueuePtr(D = new TMyQueue("D"))); + G->AddQueue("E", TQueuePtr(E = new TMyQueue("E"))); + H->AddQueue("X", TQueuePtr(X = new TMyQueue("X"))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "ABABAB"); + + Generate(A, "100 100 100"); + Generate(X, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "AXAXAX"); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + Generate(E, "100 100 100"); + Generate(X, "100 100 100 100 100 100 100 100 100 100 100 100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "AXBXCXDXEXAXBXCXDXEXAXBXCXDXEX"); + } + + Y_UNIT_TEST(DoubleDRRWithWeights) { + typedef TDRRScheduler TInnerDRR; + typedef std::shared_ptr TInnerDRRPtr; + typedef TDRRScheduler TOuterDRR; + TOuterDRR drr(200); + + TInnerDRR* G; + drr.AddQueue("G", TInnerDRRPtr(G = new TInnerDRR(200, 1))); + TInnerDRR* H; + drr.AddQueue("H", TInnerDRRPtr(H = new TInnerDRR(200, 3))); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + G->AddQueue("A", TQueuePtr(A = new TMyQueue("A"))); + G->AddQueue("B", TQueuePtr(B = new TMyQueue("B"))); + H->AddQueue("C", TQueuePtr(C = new TMyQueue("C"))); + H->AddQueue("D", TQueuePtr(D = new TMyQueue("D"))); + + Generate(A, "100 100 100"); // 100 + Generate(B, "100 100 100"); // 100 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "ABABAB"); + + Generate(C, "100 100 100"); // 100 + Generate(D, "100 100 100"); // 100 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "CDCDCD"); + + Generate(A, "100 100 100 100 100 100 100 100"); // 50 + Generate(C, "100 100 100 100 100 100 100 100"); // 150 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "CACCCACCCACAAAAA"); + + Generate(B, "100 100 100 100 100 100 100 100"); // 50 + Generate(D, "100 100 100 100 100 100 100 100"); // 150 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "DBDDDBDDDBDBBBBB"); + + Generate(A, "200 200 200 200 200 200 200 200 200 200 200"); // 25 + Generate(B, "200 200 200 200 200 200 200 200 200 200 200"); // 25 + Generate(C, "200 200 200 200 200 200 200 200 200 200 200"); // 75 + Generate(D, "200 200 200 200 200 200 200 200 200 200 200"); // 75 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "CDACDCBDCDACDCBDCDACDCBDCDACDBABABABABABABAB"); + + Generate(A, "100 100 100 100 100 100 100 100 100 100 100"); // 25 + Generate(B, "100 100 100 100 100 100 100 100 100 100 100"); // 25 + Generate(C, "100 100 100 100 100 100 100 100 100 100 100"); // 75 + Generate(D, "100 100 100 100 100 100 100 100 100 100 100"); // 75 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "CADCDBCDCADCDBCDCADCDBCDCADCDBABABABABABABAB"); + + Generate(A, "50 50 50 50 50 50 50 50 50 50 50"); // 25 + Generate(B, "50 50 50 50 50 50 50 50 50 50 50"); // 25 + Generate(C, "50 50 50 50 50 50 50 50 50 50 50"); // 75 + Generate(D, "50 50 50 50 50 50 50 50 50 50 50"); // 75 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "ACCDADCCBDDCBCDDACCDADCCBDDCBDAABBAABBAABBAB"); + + Generate(A, "25 25 25 25 25 25 25 25 25 25 25"); // 25 + Generate(B, "25 25 25 25 25 25 25 25 25 25 25"); // 25 + Generate(C, "25 25 25 25 25 25 25 25 25 25 25"); // 75 + Generate(D, "25 25 25 25 25 25 25 25 25 25 25"); // 75 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr), "AACCCCDDAADDCCCCBBDDDDCCBBCDDDAAAABBBBAAABBB"); + } + + Y_UNIT_TEST(OneQueueDRRFrontPush) { + TDRRScheduler drr(100); + + TMyQueue* A; + drr.AddQueue("A", TQueuePtr(A = new TMyQueue("A"))); + + Generate(A, "10 20 30"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, 1, true), "A10"); + + GenerateFront(A, "40"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, size_t(-1), true), "A40A20A30"); + } + + Y_UNIT_TEST(SimpleDRRFrontPush) { + TDRRScheduler drr(10); + + TMyQueue* A; + TMyQueue* B; + drr.AddQueue("A", TQueuePtr(A = new TMyQueue("A"))); + drr.AddQueue("B", TQueuePtr(B = new TMyQueue("B"))); + + Generate(A, "10 30 40"); + Generate(B, "10 20 30"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, 2, true), "A10B10"); + + GenerateFront(A, "20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, size_t(-1), true), "A20B20A30B30A40"); + } + + Y_UNIT_TEST(SimpleDRRFrontPushAll) { + TDRRScheduler drr(10); + + TMyQueue* A; + TMyQueue* B; + drr.AddQueue("A", TQueuePtr(A = new TMyQueue("A"))); + drr.AddQueue("B", TQueuePtr(B = new TMyQueue("B"))); + + Generate(A, "10 30"); + Generate(B, "10 30"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, 2, true), "A10B10"); + + GenerateFront(A, "20"); + GenerateFront(B, "20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, size_t(-1), true), "A20B20A30B30"); + } + + Y_UNIT_TEST(DoubleDRRFrontPush) { + typedef TDRRScheduler TInnerDRR; + typedef std::shared_ptr TInnerDRRPtr; + typedef TDRRScheduler TOuterDRR; + TOuterDRR drr(10); + + TInnerDRR* G; + drr.AddQueue("G", TInnerDRRPtr(G = new TInnerDRR(10))); + TInnerDRR* H; + drr.AddQueue("H", TInnerDRRPtr(H = new TInnerDRR(10))); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + G->AddQueue("A", TQueuePtr(A = new TMyQueue("A"))); + G->AddQueue("B", TQueuePtr(B = new TMyQueue("B"))); + H->AddQueue("C", TQueuePtr(C = new TMyQueue("C"))); + H->AddQueue("D", TQueuePtr(D = new TMyQueue("D"))); + + Generate(A, "10 20"); + Generate(B, "10 30"); + Generate(C, "10 20"); + Generate(D, "10 20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, 4, true), "A10C10B10D10"); + + GenerateFront(B, "20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, size_t(-1), true), "A20C20B20D20B30"); + } + + Y_UNIT_TEST(DoubleDRRFrontPushAll) { + typedef TDRRScheduler TInnerDRR; + typedef std::shared_ptr TInnerDRRPtr; + typedef TDRRScheduler TOuterDRR; + TOuterDRR drr(10); + + TInnerDRR* G; + drr.AddQueue("G", TInnerDRRPtr(G = new TInnerDRR(10))); + TInnerDRR* H; + drr.AddQueue("H", TInnerDRRPtr(H = new TInnerDRR(10))); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + G->AddQueue("A", TQueuePtr(A = new TMyQueue("A"))); + G->AddQueue("B", TQueuePtr(B = new TMyQueue("B"))); + H->AddQueue("C", TQueuePtr(C = new TMyQueue("C"))); + H->AddQueue("D", TQueuePtr(D = new TMyQueue("D"))); + + Generate(A, "10 30"); + Generate(B, "10 30"); + Generate(C, "10 30"); + Generate(D, "10 30"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, 4, true), "A10C10B10D10"); + + GenerateFront(A, "20"); + GenerateFront(B, "20"); + GenerateFront(C, "20"); + GenerateFront(D, "20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, size_t(-1), true), "A20C20B20D20A30C30B30D30"); + } + + Y_UNIT_TEST(DoubleDRRMultiplePush) { + typedef TDRRScheduler TInnerDRR; + typedef std::shared_ptr TInnerDRRPtr; + typedef TDRRScheduler TOuterDRR; + TOuterDRR drr(40); + + TInnerDRR* G; + drr.AddQueue("G", TInnerDRRPtr(G = new TInnerDRR(20))); + TInnerDRR* H; + drr.AddQueue("H", TInnerDRRPtr(H = new TInnerDRR(20))); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + G->AddQueue("A", TQueuePtr(A = new TMyQueue("A"))); + G->AddQueue("B", TQueuePtr(B = new TMyQueue("B"))); + H->AddQueue("C", TQueuePtr(C = new TMyQueue("C"))); + H->AddQueue("D", TQueuePtr(D = new TMyQueue("D"))); + + Generate(A, "5 5 5 5 5"); + Generate(B, "10 10"); + Generate(C, "10 10"); + Generate(D, "10 10"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, size_t(-1), true), "A5A5B10C10D10A5A5B10C10D10A5"); + } + + Y_UNIT_TEST(DoubleDRRFrontMultiplePush) { + typedef TDRRScheduler TInnerDRR; + typedef std::shared_ptr TInnerDRRPtr; + typedef TDRRScheduler TOuterDRR; + TOuterDRR drr(40); + + TInnerDRR* G; + drr.AddQueue("G", TInnerDRRPtr(G = new TInnerDRR(20))); + TInnerDRR* H; + drr.AddQueue("H", TInnerDRRPtr(H = new TInnerDRR(20))); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + G->AddQueue("A", TQueuePtr(A = new TMyQueue("A"))); + G->AddQueue("B", TQueuePtr(B = new TMyQueue("B"))); + H->AddQueue("C", TQueuePtr(C = new TMyQueue("C"))); + H->AddQueue("D", TQueuePtr(D = new TMyQueue("D"))); +// Cerr << "A\t" << (ui64)A << Endl; +// Cerr << "B\t" << (ui64)B << Endl; +// Cerr << "C\t" << (ui64)C << Endl; +// Cerr << "D\t" << (ui64)D << Endl; +// Cerr << "G\t" << (ui64)G << Endl; +// Cerr << "H\t" << (ui64)H << Endl; + + + Generate(A, "5"); + Generate(B, "10 10"); + Generate(C, "10 10"); + Generate(D, "10 10"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, 1, true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, 1, true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, 4, true), "B10C10D10A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, 1, true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, size_t(-1), true), "B10C10D10A5"); + } + + Y_UNIT_TEST(DoubleDRRCheckEmpty) { + typedef TDRRScheduler TInnerDRR; + typedef std::shared_ptr TInnerDRRPtr; + typedef TDRRScheduler TOuterDRR; + TOuterDRR drr(40); + + TInnerDRR* G; + drr.AddQueue("G", TInnerDRRPtr(G = new TInnerDRR(20))); + TInnerDRR* H; + drr.AddQueue("H", TInnerDRRPtr(H = new TInnerDRR(20))); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + G->AddQueue("A", TQueuePtr(A = new TMyQueue("A"))); + G->AddQueue("B", TQueuePtr(B = new TMyQueue("B"))); + H->AddQueue("C", TQueuePtr(C = new TMyQueue("C"))); + H->AddQueue("D", TQueuePtr(D = new TMyQueue("D"))); + + Generate(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, size_t(1), true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, size_t(1), true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, size_t(1), true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, size_t(1), true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(drr, size_t(-1), true), "A5"); + } + // TODO(serxa): add test for weight update +} diff --git a/ydb/library/drr/ut/ya.make b/ydb/library/drr/ut/ya.make new file mode 100644 index 000000000000..3ee62e9ec6dc --- /dev/null +++ b/ydb/library/drr/ut/ya.make @@ -0,0 +1,12 @@ +UNITTEST() + +PEERDIR( + library/cpp/threading/future + ydb/library/drr +) + +SRCS( + drr_ut.cpp +) + +END() diff --git a/ydb/library/drr/ya.make b/ydb/library/drr/ya.make new file mode 100644 index 000000000000..9051bc10c691 --- /dev/null +++ b/ydb/library/drr/ya.make @@ -0,0 +1,17 @@ +LIBRARY() + +PEERDIR( + library/cpp/lwtrace + library/cpp/monlib/encode/legacy_protobuf/protos +) + +SRCS( + drr.cpp + probes.cpp +) + +END() + +RECURSE( + ut +) diff --git a/ydb/library/planner/base/defs.h b/ydb/library/planner/base/defs.h new file mode 100644 index 000000000000..fb669fa638c4 --- /dev/null +++ b/ydb/library/planner/base/defs.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include + +#define SHAREPLANNER_CHECK_EACH_ACTION + +namespace NScheduling { + +typedef ui64 TUCost; // [res*sec] + +// Different parrots for resource counting +typedef double TLength; // [metre] +typedef double TForce; // [newton] +typedef double TEnergy; // [joule] +typedef double TDimless; // [1] + +typedef ui64 TWeight; +typedef double FWeight; + +static const TForce gs = 1; + +template +X WCut(W w, W& wsum, X& xsum) +{ + Y_ASSERT(w > 0); + Y_ASSERT(wsum > 0); + Y_ASSERT(xsum > 0); + X x = Max(0, xsum * w / wsum); + Y_ASSERT(x >= 0); + wsum -= w; + if (wsum < 0) + wsum = 0; + xsum -= x; + if (xsum < 0) + xsum = 0; + return x; +} + +template +X WMaxCut(W w, X xmax, W& wsum, X& xsum) +{ + Y_ASSERT(w > 0); + Y_ASSERT(wsum > 0); + Y_ASSERT(xsum > 0); + X x = Max(0, Min(xmax, xsum * w / wsum)); + Y_ASSERT(x >= 0); + wsum -= w; + if (wsum < 0) + wsum = 0; + xsum -= x; + if (xsum < 0) + xsum = 0; + Y_ASSERT(wsum >= 0); + Y_ASSERT(xsum >= 0); + return x; +} + +} diff --git a/ydb/library/planner/base/visitor.h b/ydb/library/planner/base/visitor.h new file mode 100644 index 000000000000..981aa47a497c --- /dev/null +++ b/ydb/library/planner/base/visitor.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include + +namespace NScheduling { + +class IVisitable; + +class IVisitorBase { +public: + virtual ~IVisitorBase() {} + virtual void VisitUnkown(IVisitable* o) { VisitFailed(o); } + virtual void VisitUnkown(const IVisitable* o) { VisitFailed(o); } +private: + inline void VisitFailed(const IVisitable* o); +}; + +template +class IVisitor { +public: + virtual void Visit(T* node) = 0; +}; + +class IVisitable { +public: + virtual ~IVisitable() {} + virtual void Accept(IVisitorBase* v) { v->VisitUnkown(this); } + virtual void Accept(IVisitorBase* v) const { v->VisitUnkown(this); } +protected: + template + static bool AcceptImpl(TDerived* d, IVisitorBase* v) + { + if (auto* p = dynamic_cast*>(v)) { + p->Visit(d); + return true; + } else { + return false; + } + } +private: +}; + +#define SCHEDULING_DEFINE_VISITABLE(TBase) \ + void Accept(::NScheduling::IVisitorBase* v) override { if (!AcceptImpl(this, v)) { TBase::Accept(v); } } \ + void Accept(::NScheduling::IVisitorBase* v) const override { if (!AcceptImpl(this, v)) { TBase::Accept(v); } } \ + /**/ + + +void IVisitorBase::VisitFailed(const IVisitable* o) +{ + Y_ABORT("visitor of type '%s' cannot visit class of type '%s'", TypeName(*this).c_str(), TypeName(*o).c_str()); +} + +} diff --git a/ydb/library/planner/share/account.cpp b/ydb/library/planner/share/account.cpp new file mode 100644 index 000000000000..1481943fe527 --- /dev/null +++ b/ydb/library/planner/share/account.cpp @@ -0,0 +1,5 @@ +#include "account.h" + +namespace NScheduling { + +} diff --git a/ydb/library/planner/share/account.h b/ydb/library/planner/share/account.h new file mode 100644 index 000000000000..e2754bfe6860 --- /dev/null +++ b/ydb/library/planner/share/account.h @@ -0,0 +1,24 @@ +#pragma once + +#include "node.h" + +namespace NScheduling { + +class TShareAccount: public TShareNode { +public: + SCHEDULING_DEFINE_VISITABLE(TShareNode); +public: // Configuration + TShareAccount(TAutoPtr cfg) + : TShareNode(cfg.Release()) + {} + TShareAccount(const TString& name, FWeight w, FWeight wmax, TEnergy v) + : TShareAccount(new TConfig(v, wmax, w, name)) + {} + void Configure(const TString& name, FWeight w, FWeight wmax, TEnergy v) + { + SetConfig(new TConfig(v, wmax, w, name)); + } + const TConfig& Cfg() const { return *static_cast(Config.Get()); } +}; + +} diff --git a/ydb/library/planner/share/analytics.h b/ydb/library/planner/share/analytics.h new file mode 100644 index 000000000000..6d75a08e416d --- /dev/null +++ b/ydb/library/planner/share/analytics.h @@ -0,0 +1,99 @@ +#pragma once + +#include +#include "apply.h" +#include + +#define FOREACH_NODE_ACCESSOR(XX, YY) \ + XX(s0) \ + XX(w0) \ + XX(wmax) \ + XX(w) \ + XX(h) \ + XX(D) \ + XX(S) \ + XX(dD) \ + XX(dS) \ + XX(pdD) \ + XX(pdS) \ + XX(E) \ + XX(V) \ + YY(L) \ + YY(O) \ + YY(A) \ + YY(P) \ + XX(dd) \ + XX(ds) \ + XX(pdd) \ + XX(pds) \ + XX(e) \ + XX(v) \ + YY(l) \ + YY(o) \ + YY(a) \ + YY(p) \ + /**/ + +#define FILL_ROW(n) row[#n] = c->n +#define FILL_ROW_N(n, v) row[n] = c->v + +namespace NScheduling { namespace NAnalytics { + +using namespace ::NAnalytics; + +inline void AddFromCtx(TRow& row, const IContext* ctx) +{ + if (const TDeContext* c = dynamic_cast(ctx)) { + FILL_ROW(x); + FILL_ROW(ix); + FILL_ROW(s); + FILL_ROW(u); + FILL_ROW(iu); + FILL_ROW(wl); + FILL_ROW(iwl); + FILL_ROW_N("pa", p); // pa = point of attachment + FILL_ROW(pr); + FILL_ROW(pl); + FILL_ROW(pf); + FILL_ROW(lambda); + FILL_ROW_N("hf", h); // h-function + FILL_ROW(sigma); + FILL_ROW(isigma); + FILL_ROW(p0); + FILL_ROW(ip0); + FILL_ROW_N("stretch", Pull.stretch); + FILL_ROW_N("retardness", Pull.retardness); + FILL_ROW_N("s0R", Pull.s0R); + } +} + +inline TRow FromNode(const TShareNode* node, TEnergy Eg) +{ + TRow row; + row.Name = node->GetName(); +#define XX_MACRO(n) row[#n] = node->n(); +#define YY_MACRO(n) row[#n] = node->n(Eg); + FOREACH_NODE_ACCESSOR(XX_MACRO, YY_MACRO); +#undef XX_MACRO +#undef YY_MACRO + AddFromCtx(row, node->Ctx()); + return row; +} + +inline TTable FromGroup(const TShareGroup* group) +{ + TTable out; + TEnergy Eg = 0; + ApplyTo(group, [&Eg] (const TShareNode* node) { + Eg += node->E(); + }); + ApplyTo(group, [&out, Eg] (const TShareNode* node) { + out.push_back(FromNode(node, Eg)); + }); + return out; +} + +}} + +#undef FILL_ROW +#undef FOREACH_NODE_FIELD diff --git a/ydb/library/planner/share/apply.h b/ydb/library/planner/share/apply.h new file mode 100644 index 000000000000..b692d2cada62 --- /dev/null +++ b/ydb/library/planner/share/apply.h @@ -0,0 +1,104 @@ +#pragma once + +#include "node_visitor.h" +#include "group.h" +#include + +namespace NScheduling { + +template +class TApplyVisitor + : public IVisitorBase + , public IVisitor + , public IVisitor +{ +private: + std::function AccFunc; + std::function GrpFunc; +public: + template + TApplyVisitor(AF af, GF gf) + : AccFunc(af) + , GrpFunc(gf) + {} + + void Visit(TAcc* node) override + { + AccFunc(node); + } + + void Visit(TGrp* node) override + { + GrpFunc(node); + } +}; + +template +class TApplySimpleVisitor + : public IVisitorBase + , public IVisitor +{ +private: + std::function NodeFunc; +public: + template + TApplySimpleVisitor(NF nf) + : NodeFunc(nf) + {} + + void Visit(TNode* node) override + { + NodeFunc(node); + } +}; + +template +class TRecursiveApplyVisitor + : public IVisitorBase + , public IVisitor + , public IVisitor +{ +private: + std::function AccFunc; + std::function GrpFunc; +public: + template + TRecursiveApplyVisitor(AF af, GF gf) + : AccFunc(af) + , GrpFunc(gf) + {} + + void Visit(TAcc* node) override + { + AccFunc(node); + } + + void Visit(TGrp* node) override + { + GrpFunc(node); + node->AcceptInChildren(this); + } +}; + +template +void ApplyTo(T* group, AF af, GF gf) +{ + TApplyVisitor v(af, gf); + group->AcceptInChildren(&v); +} + +template +void ApplyTo(T* group, NF nf) +{ + TApplySimpleVisitor v(nf); + group->AcceptInChildren(&v); +} + +template +void RecursiveApplyTo(T* group, AF af, GF gf) +{ + TRecursiveApplyVisitor v(af, gf); + group->Accept(&v); +} + +} diff --git a/ydb/library/planner/share/billing.h b/ydb/library/planner/share/billing.h new file mode 100644 index 000000000000..affcd8fc5ca4 --- /dev/null +++ b/ydb/library/planner/share/billing.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include "apply.h" +#include "node_visitor.h" +#include "shareplanner.h" +#include + +namespace NScheduling { + +// Just apply static tariff +class TStaticBilling : public INodeVisitor +{ +private: + TDimless Tariff; +public: + TStaticBilling(TDimless tariff = 1.0) + : Tariff(tariff) + {} + + void Visit(TShareAccount* node) override + { + Handle(node); + } + + void Visit(TShareGroup* node) override + { + node->AcceptInChildren(this); + Handle(node); + } +protected: + void Handle(TShareNode* node) + { + node->SetTariff(Tariff); + } +}; + +// It sets current tariff, which in turn is just sigma value +// for parent group. Sigma represents how many nodes of a group is present at the moment +// each multiplied by it's static share +// For example: +// 1) if every user is working, then sigma equals one +// 2) if there is the only working user with static weight s0, then sigma equals s0 +// Note that 0 < sigma <= 1 +class TPresentShareBilling : public INodeVisitor +{ +private: + bool Memoryless = false; +public: + TPresentShareBilling(bool memoryless) + : Memoryless(memoryless) + {} + + void Visit(TShareAccount* node) override + { + Handle(node); + } + + void Visit(TShareGroup* node) override + { + node->AcceptInChildren(this); + Handle(node); + } +protected: + void Handle(TShareNode* node) + { + if (TShareGroup* group = node->GetParent()) { + if (TDeContext* pctx = group->CtxAs()) { + TDimless tariff = Memoryless? pctx->isigma: pctx->sigma; + if (tariff == 0) // There is nobody working on cluster + tariff = 1.0; // Just to avoid stalling (otherwise, every dDi will be zero always) + node->SetTariff(tariff); + } + } + } +}; + +} diff --git a/ydb/library/planner/share/group.cpp b/ydb/library/planner/share/group.cpp new file mode 100644 index 000000000000..df1245c4b7fd --- /dev/null +++ b/ydb/library/planner/share/group.cpp @@ -0,0 +1,100 @@ +#include "group.h" +#include "apply.h" + +namespace NScheduling { + +TShareNode* TShareGroup::FindByName(const TString& name) +{ + auto i = Children.find(name); + if (i == Children.end()) { + return nullptr; + } else { + return i->second; + } +} + +void TShareGroup::ResetShare() +{ + TForce s0 = gs; + FWeight wsum = TotalWeight; + for (auto ch : Children) { + TShareNode* node = ch.second; + node->SetShare(WCut(node->w0(), wsum, s0)); + } +} + +void TShareGroup::Add(TShareNode* node) +{ + Y_ABORT_UNLESS(!Children.contains(node->GetName()), "duplicate child name '%s' in group '%s'", node->GetName().data(), GetName().data()); + Children[node->GetName()] = node; + TotalWeight += node->w0(); + TotalVolume += node->V(); + ResetShare(); +} + +void TShareGroup::Remove(TShareNode* node) +{ + Y_ABORT_UNLESS(Children.contains(node->GetName()), "trying to delete unknown child name '%s' in group '%s'", node->GetName().data(), GetName().data()); + Children.erase(node->GetName()); + TotalWeight -= node->w0(); + TotalVolume -= node->V(); + ResetShare(); +} + +void TShareGroup::Clear() +{ + ApplyTo(this, [] (TShareAccount* acc) { + acc->DetachNoRemove(); + }, [] (TShareGroup* grp) { + grp->Clear(); + grp->DetachNoRemove(); + }); + Children.clear(); + TotalWeight = 0; + TotalVolume = 0; +} + +TEnergy TShareGroup::ComputeEc() const +{ + TEnergy Ec = 0; + ApplyTo(this, [&Ec] (const TShareNode* node) { + Ec += node->E(); + }); + return Ec; +} + +TEnergy TShareGroup::GetTotalCredit() const +{ + TEnergy Eg = 0; + for (auto ch : Children) { + TShareNode* node = ch.second; + Eg += node->E(); + } + TEnergy credit = 0; + for (auto ch : Children) { + TShareNode* node = ch.second; + TEnergy P = node->P(Eg); + if (P > 0) { + credit += P; + } + } + return credit; +} + +void TShareGroup::AcceptInChildren(IVisitorBase* v) +{ + for (auto ch : Children) { + TShareNode* node = ch.second; + node->Accept(v); + } +} + +void TShareGroup::AcceptInChildren(IVisitorBase* v) const +{ + for (auto ch : Children) { + const TShareNode* node = ch.second; + node->Accept(v); + } +} + +} diff --git a/ydb/library/planner/share/group.h b/ydb/library/planner/share/group.h new file mode 100644 index 000000000000..305a8519c8b7 --- /dev/null +++ b/ydb/library/planner/share/group.h @@ -0,0 +1,63 @@ +#pragma once + +#include +#include +#include "account.h" + +namespace NScheduling { + +class TShareGroup: public TShareNode { +public: + SCHEDULING_DEFINE_VISITABLE(TShareNode); +protected: + TMap Children; + FWeight TotalWeight = 0; // Total weight of children + TEnergy TotalVolume = 0; // Total volume of children +public: // Configuration + TShareGroup(TAutoPtr cfg) + : TShareNode(cfg.Release()) + {} + TShareGroup(const TString& name, FWeight w, FWeight wmax, TEnergy v) + : TShareGroup(new TConfig(v, wmax, w, name)) + {} + void Configure(const TString& name, FWeight w, FWeight wmax, TEnergy v) + { + SetConfig(new TConfig(v, wmax, w, name)); + } + const TConfig& Cfg() const { return *static_cast(Config.Get()); } +public: + bool Empty() const { return Children.empty(); } + void AcceptInChildren(IVisitorBase* v); + void AcceptInChildren(IVisitorBase* v) const; +public: + TShareNode* FindByName(const TString& name); + inline FWeight GetTotalWeight() const { return TotalWeight; } + inline TEnergy GetTotalVolume() const { return TotalVolume; } + void Add(TShareNode* node); + void Remove(TShareNode* node); + void Clear(); + TEnergy ComputeEc() const; +public: // Monitoring + TEnergy GetTotalCredit() const; +protected: + void Insert(TShareAccount* node); + void Insert(TShareGroup* node); + void Erase(TShareAccount* node); + void Erase(TShareGroup* node); + void ResetShare(); +}; + +#define CUSTOMSHAREPLANNER_FOR(acctype, grptype, node, expr) \ + do { \ + for (auto _ch_ : Children) { \ + auto* _node_ = _ch_.second; \ + if (auto* node = dynamic_cast(_node_)) { expr; } \ + else if (auto* node = dynamic_cast(_node_)) { expr; } \ + else { Y_ABORT("node is niether " #acctype " nor " #grptype ", it is %s", TypeName(*node).c_str()); } \ + } \ + } while (false) \ + /**/ + +#define SHAREPLANNER_FOR(node, expr) CUSTOMSHAREPLANNER_FOR(TShareAccount, TShareGroup, node, expr) + +} diff --git a/ydb/library/planner/share/history.cpp b/ydb/library/planner/share/history.cpp new file mode 100644 index 000000000000..41aeb0151373 --- /dev/null +++ b/ydb/library/planner/share/history.cpp @@ -0,0 +1,4 @@ +#include "history.h" + +namespace NScheduling { +} diff --git a/ydb/library/planner/share/history.h b/ydb/library/planner/share/history.h new file mode 100644 index 000000000000..7e64b4ab2f61 --- /dev/null +++ b/ydb/library/planner/share/history.h @@ -0,0 +1,114 @@ +#pragma once + +#include "shareplanner.h" +#include +#include "node_visitor.h" +#include "apply.h" +#include "probes.h" + +namespace NScheduling { + +class THistorySaver : public IConstNodeVisitor +{ +protected: + TSharePlannerHistory History; + TEnergy Eg = 0; +public: + static void Save(const TSharePlanner* planner, IOutputStream& os) + { + PLANNER_PROBE(SerializeHistory, planner->GetName()); + THistorySaver v; + planner->GetRoot()->Accept(&v); + v.History.SerializeToArcadiaStream(&os); + } +protected: + void Visit(const TShareAccount* account) override + { + SaveNode(account); + } + + void Visit(const TShareGroup* group) override + { + SaveNode(group); + // Recurse into children + TEnergy Eg_stack = Eg; + Eg = 0; + ApplyTo(group, [=] (const TShareNode* node) { + Eg += node->E(); + }); + group->AcceptInChildren(this); + Eg = Eg_stack; + } + + void SaveNode(const TShareNode* node) + { + TShareNodeHistory* nh = History.AddNodes(); + nh->SetName(node->GetName()); + nh->SetProficit(node->P(Eg)); + } +}; + +class THistoryLoader: public INodeVisitor +{ +protected: + THashMap NHMap; + TSharePlannerHistory History; + TSharePlanner* Planner; +public: + static bool Load(TSharePlanner* planner, IInputStream& is) + { + THistoryLoader v(planner); + return v.LoadFrom(is); + } +protected: + explicit THistoryLoader(TSharePlanner* planner) + : Planner(planner) + {} + + bool LoadFrom(IInputStream& is) + { + PLANNER_PROBE(DeserializeHistoryBegin, Planner->GetName()); + bool success = false; + if (History.ParseFromArcadiaStream(&is)) { + for (size_t i = 0; i < History.NodesSize(); i++) { + const TShareNodeHistory& nh = History.GetNodes(i); + NHMap[nh.GetName()] = &nh; + } + + if (OnHistoryDeserialized()) { + //UtilMeter->Load(History.GetUtilization()); // Load utilization history + Planner->GetRoot()->Accept(this); + success = true; + } + } + PLANNER_PROBE(DeserializeHistoryEnd, Planner->GetName(), success); + return success; + } + + void Visit(TShareAccount* account) override + { + LoadNode(account); + } + + void Visit(TShareGroup* group) override + { + LoadNode(group); + group->AcceptInChildren(this); + } + + void LoadNode(TShareNode* node) + { + auto i = NHMap.find(node->GetName()); + TEnergy Dnew = 0; + if (i != NHMap.end()) { + const TShareNodeHistory& nh = *i->second; + Dnew = nh.GetProficit(); + } + node->SetS(0); + node->SetD(Dnew); + } + + virtual bool OnHistoryDeserialized() { return true; } +}; + +} diff --git a/ydb/library/planner/share/models/density.h b/ydb/library/planner/share/models/density.h new file mode 100644 index 000000000000..bada470ee38d --- /dev/null +++ b/ydb/library/planner/share/models/density.h @@ -0,0 +1,385 @@ +#pragma once + +#include +#include +#include "recursive.h" + +namespace NScheduling { + +enum class TDepType { Left = 0, Top, AtNode, Bottom, Right, Other }; + +template +struct TDePoint { + TCtx* Ctx; + double p; + TDepType Type; + + void Move(double& h, double& lambda, const TDePoint* prev) const + { + if (prev) { + h += lambda * (prev->p - p); // Integrate density + } + switch (Type) { + case TDepType::Right: lambda += Ctx->lambda; break; + case TDepType::Left: lambda -= Ctx->lambda; break; + case TDepType::Bottom: break; + case TDepType::Top: h += Ctx->x; break; + default: break; // other types must be processed separately + } + } + + bool operator<(const TDePoint& o) const + { + if (p == o.p) { + return Type > o.Type; + } else { + return p > o.p; + } + } +}; + +class TDeContext : public IContext { +public: + SCHEDULING_DEFINE_VISITABLE(IContext); + + ui64 ModelCycle = 0; // Number of times that Run() passed with this context + + // Context for child role + TShareNode* Node; + FWeight w; // weight + TDimless ix = 0; // instant utilization + TDimless x = 0; // average utilization + TDimless u = 0; // usage + TDimless iu = 0; // instant usage + TDimless wl = 0; // x/w (water-level) + TDimless iwl = 0; // ix/w (instant water-level) + TLength p = 0; // normalized proficit + TLength pr = 0; // dense interval rightmost point + TLength pl = 0; // dense interval leftmost point + TLength pf = 0; // normalized proficit relative to floating origin + double lambda = 0; // density [1/metre] + TDimless h = 0; // h-function value + TForce s = 0; // dynamic share + + // Context for parent role + TEnergy Ec = 0; // sum of E() of children + TEnergy dDc = 0; // sum of dD() of children + TForce sigma = 0; // used fraction of band (0; 1] + TForce isigma = 0; // instant used fraction of band (0; 1] + TLength p0 = 0; // floating origin + TLength ip0 = 0; // instant floating origin + + // Context for insensitive puller + struct { + ui64 Cycle = ui64(-1); + TEnergy Dlast = 0; // D was on last pull + TDimless stretch = 0; + TDimless retardness = 0; + TForce s0R = 0; + } Pull; + + explicit TDeContext(IModel* model, TShareNode* node) + : IContext(model) + , Node(node) + , w(node? node->w0(): 1.0) + {} + + void Update(TDeContext gctx, double avgLength) + { + // Update utilization + ix = Node->dD() / gctx.dDc; + if (avgLength > 0) { + TLength ddg = gctx.dDc / gs; + double alpha = std::pow(2.0, -ddg / avgLength); + x = alpha * x + (1-alpha) * ix; + } else { + x = ix; + } + + // Update normalized proficit + p = Node->p(gctx.Ec); + } + + void Normalize(double Xsum, double iXsum) + { + if (Xsum > 0) { + // Moving averaging formulas should always give Xsum == 1.0 exactly + // Reasons for normalize are: + // 1) fix floating-point arithmetic errors + // 2) on new group start actual sum of x of all children is zero + // and this should be fixed somehow + // 3) when account leaves group Xsum would be not equal to 1.0 + x /= Xsum; + wl = x / w; + } + if (iXsum > 0) { + ix /= iXsum; + iwl = ix / w; + } + } + + void ComputeUsage(double& xsum, double& wsum, double& ucur, double& wlcur, bool instant) + { + // EXPLANATION FOR FORMULA + // If we assume: + // (1) all "vectors" below are sorted by water-level wl[k] = x[k] / w[k] + // (2) u[k] >= u[k-1] -- u should monotonically increase with k + // (3) u[k] must be bounded by 1 (when xp[k] == 0) + // (4) u[k] must be a linear function of wl[k] + // + // One can proove that: + // wl[k] - wl[k-1] + // u[k] = u[k-1] + ----------------- (1 - u[k-1]) + // WL[k] - wl[k-1] + // + // , where WL[k] = sum(i=k..n, x[i]) / sum(i=k..n, w[i]) + // WL[k] is max possible value for wl[k] (due to sort by wl[k]) + // + // Or equivalently (adapted and used below for computation): + // xm[k] + // (*) u[k] = u[k-1] + --------------- (1 - u[k-1]) + // xp[k] + xm[k] + // + // , where xp[k] = x[k] - wl[k-1] * w[k] -- water in k-th bucket lacking to become max possible WL[k] + // xm[k] = WL[k] * w[k] - x[k] -- water in k-th bucket above min possible wl[k-1] + // + + Y_ABORT_UNLESS(wsum > 0); + double xx = (instant? ix: x); + double xn = xx - wlcur * w; + double xp = w * (xsum/wsum) - xx; + if (xn + xp > 0) { + ucur += xn / (xn+xp) * (1-ucur); + } + wlcur = (instant? iwl: wl); + xsum -= xx; + wsum -= w; + (instant? iu: u) = ucur; + } + + template + static void PushPointsImpl(TCtx* t, TVector>& points) + { + if (t->pr > t->pl) { + points.push_back(TDePoint{t, t->pr, TDepType::Right}); + points.push_back(TDePoint{t, t->p, TDepType::AtNode}); + points.push_back(TDePoint{t, t->pl, TDepType::Left}); + } else { + points.push_back(TDePoint{t, t->p, TDepType::Bottom}); + points.push_back(TDePoint{t, t->p, TDepType::AtNode}); + points.push_back(TDePoint{t, t->p, TDepType::Top}); + } + } + + void PushPoints(TVector>& points) + { + PushPointsImpl(this, points); + } + + void PushPoints(TVector>& points) const + { + PushPointsImpl(this, points); + } + + FWeight GetWeight() const override + { + return w; + } + + double CalcGlobalRealShare() const + { + if (TShareGroup* group = Node->GetParent()) + if (TDeContext* pctx = group->CtxAs()) + return ix * pctx->CalcGlobalRealShare(); + return 1.0; + } + + double CalcGlobalAvgRealShare() const + { + if (TShareGroup* group = Node->GetParent()) + if (TDeContext* pctx = group->CtxAs()) + return x * pctx->CalcGlobalAvgRealShare(); + return 1.0; + } + + double CalcGlobalDynamicShare() const + { + if (TShareGroup* group = Node->GetParent()) + if (TDeContext* pctx = group->CtxAs()) + return s * pctx->CalcGlobalDynamicShare(); + return 1.0; + } + + void FillSensors(TShareNodeSensors& sensors) const override + { + sensors.SetFloatingLag(pf); + sensors.SetRealShare(CalcGlobalRealShare()); + sensors.SetAvgRealShare(CalcGlobalAvgRealShare()); + sensors.SetDynamicShare(CalcGlobalDynamicShare()); + sensors.SetGrpRealShare(ix); + sensors.SetGrpAvgRealShare(x); + sensors.SetGrpDynamicShare(s); + sensors.SetUsage(u); + sensors.SetInstantUsage(iu); + sensors.SetTariff(sigma); + sensors.SetInstantTariff(isigma); + sensors.SetFloatingOrigin(p0); + sensors.SetInstantOrigin(ip0); + sensors.SetBoost(h); + sensors.SetPullStretch(Pull.stretch); + sensors.SetRetardness(Pull.retardness); + sensors.SetRetardShare(Pull.s0R); + } +}; + +class TDensityModel : public TRecursiveModel { +private: + TLength DenseLength; + TLength AveragingLength; + TVector Ctxs; + TVector> Points; + double Xsum = 0; + double iXsum = 0; + double Wsum = 0; + double Wsum_new = 0; +public: + explicit TDensityModel(TSharePlanner* planner) + : TRecursiveModel(planner) + , DenseLength(planner->Cfg().GetDenseLength()) + , AveragingLength(planner->Cfg().GetAveragingLength()) + {} + void OnAttach(TShareNode*) override {} + void OnDetach(TShareNode*) override {} + void OnAccount(TShareAccount* account, TCtx& ctx, TCtx& pctx) override + { + pctx.Ec += account->E(); + pctx.dDc += account->dD(); + ctx.ModelCycle++; + } + void OnDescend(TShareGroup* group, TCtx& gctx, TCtx& pctx) override + { + pctx.Ec += group->E(); + pctx.dDc += group->dD(); + gctx.Ec = gctx.dDc = 0; + gctx.ModelCycle++; + } + void OnAscend(TShareGroup* group, TCtx& gctx, TCtx&) override + { + if (ProcessNodes(group, gctx)) { + ProcessUtilization(); + ProcessUsage(gctx); + ProcessLag(gctx); + ProcessWeight(); + ProcessSensors(gctx); + } + } +private: + bool ProcessNodes(TShareGroup* group, TCtx& gctx) + { + if (gctx.dDc == 0) + // There was no work done since last model run, so dynamic weights + // must remain the same + return false; + Ctxs.clear(); + Xsum = 0; + iXsum = 0; + Wsum = 0; + ApplyTo(group, [=] (TShareNode* node) { + TCtx& ctx = node->Ctx(); + ctx.Update(gctx, AveragingLength); + Xsum += ctx.x; + iXsum += ctx.ix; + Wsum += ctx.w; + Ctxs.push_back(&ctx); + }); + return Xsum > 0 && iXsum > 0; + } + + void ProcessUtilization() + { + // Renormalize utilization + double xsum = 0; + double ixsum = 0; + for (TDeContext* ctx : Ctxs) { + ctx->Normalize(Xsum, iXsum); + xsum += ctx->x; + ixsum += ctx->ix; + } + Xsum = xsum; + iXsum = ixsum; + } + + void ProcessUsageImpl(TForce& sigma, TLength& p0, bool instant) + { + // Ctx are assumed to be sorted by water-level (instant or average) + double ucur = 0; + double wlcur = 0; + double xsum = (instant? iXsum: Xsum); + double wsum = Wsum; + sigma = 0; + TEnergy p0sigma = 0; + for (TDeContext* ctx : Ctxs) { + ctx->ComputeUsage(xsum, wsum, ucur, wlcur, instant); + TForce sigma_i = ucur * ctx->Node->s0(); + sigma += sigma_i; + p0sigma += sigma_i * ctx->p; + } + p0 = p0sigma / sigma; + } + + void ProcessUsage(TDeContext& gctx) + { + Sort(Ctxs, [] (const TDeContext* x, const TDeContext* y) { return x->iwl < y->iwl; }); + ProcessUsageImpl(gctx.isigma, gctx.ip0, true); + Sort(Ctxs, [] (const TDeContext* x, const TDeContext* y) { return x->wl < y->wl; }); + ProcessUsageImpl(gctx.sigma, gctx.p0, false); + } + + void ProcessLag(TDeContext& gctx) + { + Points.clear(); + // We should not multiply by sigma iff sigma is used as tariff, but let's not comlicate and + // not multiply by sigma any ways, so you'd better use tarification by sigma, otherwise + // density model is NOT insensitive to absent users + //double dp = DenseLength * gs / gctx.sigma; // TODO[serxa]: also multiply by efficiency + double dp = DenseLength; + for (TDeContext* ctx : Ctxs) { + ctx->pr = ctx->p + Max(0.0, Min(dp, gctx.p0 - ctx->p)); + ctx->pl = ctx->pr - dp; + ctx->lambda = dp > 0.0? ctx->x / dp: 0.0; + ctx->PushPoints(Points); + } + Sort(Points); + double h = 0.0; + double lambda = 0.0; + TDePoint* prev = nullptr; + for (TDePoint& cur : Points) { + cur.Move(h, lambda, prev); + if (cur.Type == TDepType::AtNode) { + cur.Ctx->h = h; + } + prev = &cur; + } + } + + void ProcessWeight() + { + Wsum_new = 0.0; + for (TDeContext* ctx : Ctxs) { + TShareNode& node = *ctx->Node; + double w = node.w0() + (node.wmax() - node.w0()) * ctx->h; + ctx->w = Max(node.w0(), Min(node.wmax(), w)); + Wsum_new +=ctx->w; + } + } + + void ProcessSensors(TDeContext& gctx) + { + for (TDeContext* ctx : Ctxs) { + ctx->s = ctx->w / Wsum_new; + ctx->pf = ctx->p - gctx.p0; + } + } +}; + +} diff --git a/ydb/library/planner/share/models/max.h b/ydb/library/planner/share/models/max.h new file mode 100644 index 000000000000..bd8f596e1014 --- /dev/null +++ b/ydb/library/planner/share/models/max.h @@ -0,0 +1,35 @@ +#pragma once + +#include "recursive.h" + +namespace NScheduling { + +class TMaxContext : public IContext { +private: + TShareNode* Node; +public: + TMaxContext(IModel* model, TShareNode* node) + : IContext(model) + , Node(node) + {} + + FWeight GetWeight() const override + { + return Node->wmax(); + } +}; + +class TMaxModel : public TRecursiveModel { +public: + explicit TMaxModel(TSharePlanner* planner) + : TRecursiveModel(planner) + {} + + void OnAccount(TShareAccount*, TCtx&, TCtx&) override {} + void OnDescend(TShareGroup*, TCtx&, TCtx&) override {} + void OnAscend(TShareGroup*, TCtx&, TCtx&) override {} + void OnAttach(TShareNode*) override {} + void OnDetach(TShareNode*) override {} +}; + +} diff --git a/ydb/library/planner/share/models/model.h b/ydb/library/planner/share/models/model.h new file mode 100644 index 000000000000..ca424328a985 --- /dev/null +++ b/ydb/library/planner/share/models/model.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +namespace NScheduling { + +class IContext; +class IModel; +class TShareNode; +class TSharePlanner; + +class IContext: public IVisitable { +public: + SCHEDULING_DEFINE_VISITABLE(IVisitable); +protected: + IModel* Model; +public: + explicit IContext(IModel* model) + : Model(model) + {} + + virtual ~IContext() {} + virtual FWeight GetWeight() const = 0; + virtual void FillSensors(TShareNodeSensors&) const { } + IModel* GetModel() { return Model; } + const IModel* GetModel() const { return Model; } +}; + +class IModel: public INodeVisitor +{ +protected: + TSharePlanner* Planner; +public: + explicit IModel(TSharePlanner* planner) + : Planner(planner) + {} + + virtual void Run(TShareGroup* root) + { + Visit(root); + } + virtual void OnAttach(TShareNode* node) = 0; + virtual void OnDetach(TShareNode* node) = 0; +}; + +} diff --git a/ydb/library/planner/share/models/recursive.h b/ydb/library/planner/share/models/recursive.h new file mode 100644 index 000000000000..9acd6e4656c4 --- /dev/null +++ b/ydb/library/planner/share/models/recursive.h @@ -0,0 +1,80 @@ +#pragma once + +#include "model.h" +#include +#include + +namespace NScheduling { + +template +class TRecursiveModel : public IModel +{ +public: + typedef Context TCtx; +private: + THolder GlobalCtx; // Special parent context for root +public: + explicit TRecursiveModel(TSharePlanner* planner) + : IModel(planner) + {} + + void Visit(TShareAccount* node) final + { + TCtx& ctx = GetContext(node); + TCtx& pctx = GetParentContext(node); + OnAccount(node, ctx, pctx); + } + + void Visit(TShareGroup* node) final + { + TCtx& ctx = GetContext(node); + TCtx& pctx = GetParentContext(node); + OnDescend(node, ctx, pctx); + node->AcceptInChildren(this); + OnAscend(node, ctx, pctx); + } + + virtual TCtx* CreateContext(TShareNode* node = nullptr) + { + return new TCtx(this, node); + } +protected: + virtual void OnAccount(TShareAccount* account, TCtx& ctx, TCtx& pctx) { Y_UNUSED(account); Y_UNUSED(ctx); Y_UNUSED(pctx); } + virtual void OnDescend(TShareGroup* group, TCtx& ctx, TCtx& pctx) { Y_UNUSED(group); Y_UNUSED(ctx); Y_UNUSED(pctx); } + virtual void OnAscend(TShareGroup* group, TCtx& ctx, TCtx& pctx) { Y_UNUSED(group); Y_UNUSED(ctx); Y_UNUSED(pctx); } +protected: + TCtx& GetGlobalCtx() + { + Y_ASSERT(GlobalCtx); + return *GlobalCtx; + } + + TCtx& GetContext(TShareNode* node) + { + if (!node->Ctx() || node->Ctx()->GetModel() != this) { + node->ResetCtx(CreateContext(node)); + } + return node->Ctx(); + } + + TCtx& GetParentContext(TShareNode* node) + { + TShareNode* parent = node->GetParent(); + if (parent) { + Y_ASSERT(parent->Ctx()->GetModel() == this); + return parent->Ctx(); + } else { + if (!GlobalCtx) { + GlobalCtx.Reset(CreateContext()); + } + return *GlobalCtx; + } + } + + void DestroyGlobalContext() + { + GlobalCtx.Destroy(); + } +}; + +} diff --git a/ydb/library/planner/share/models/static.h b/ydb/library/planner/share/models/static.h new file mode 100644 index 000000000000..bcafe76b7c55 --- /dev/null +++ b/ydb/library/planner/share/models/static.h @@ -0,0 +1,35 @@ +#pragma once + +#include "recursive.h" + +namespace NScheduling { + +class TStaticContext : public IContext { +private: + TShareNode* Node; +public: + TStaticContext(IModel* model, TShareNode* node) + : IContext(model) + , Node(node) + {} + + FWeight GetWeight() const override + { + return Node->w0(); + } +}; + +class TStaticModel : public TRecursiveModel { +public: + explicit TStaticModel(TSharePlanner* planner) + : TRecursiveModel(planner) + {} + + void OnAccount(TShareAccount*, TCtx&, TCtx&) override {} + void OnDescend(TShareGroup*, TCtx&, TCtx&) override {} + void OnAscend(TShareGroup*, TCtx&, TCtx&) override {} + void OnAttach(TShareNode*) override {} + void OnDetach(TShareNode*) override {} +}; + +} diff --git a/ydb/library/planner/share/monitoring.h b/ydb/library/planner/share/monitoring.h new file mode 100644 index 000000000000..ba63e7949c7f --- /dev/null +++ b/ydb/library/planner/share/monitoring.h @@ -0,0 +1,542 @@ +#pragma once + +#include +#include +#include "shareplanner.h" +#include +#include + +namespace NScheduling { + +class TNameWidthEvaluator : public IConstNodeVisitor { +private: + size_t Ident; + size_t TreeWidth; + size_t Depth = 0; + + explicit TNameWidthEvaluator(size_t ident, size_t minWidth) + : Ident(ident) + , TreeWidth(minWidth) + {} + + void Visit(const TShareAccount* node) override + { + Update(node->GetName().size()); + } + + void Visit(const TShareGroup* node) override + { + Update(node->GetName().size()); + Depth++; + node->AcceptInChildren(this); + Depth--; + } + + void Update(size_t width) + { + TreeWidth = Max(TreeWidth, Depth * Ident + width); + } +public: + static size_t Get(const TShareGroup* root, size_t ident = 1, size_t minWidth = 4 /* = len("Name")*/) + { + TNameWidthEvaluator v(ident, minWidth); + v.Visit(root); + return v.TreeWidth; + } +}; + +#define SP_NAME(x) Sprintf("%-*s ", (int)treeWidth, ((depth>0? TString(depth - 1, '|') + "+": "") + ToString(x)).data()) << +#define SP_FOREACH_STATUS(XX) \ + XX("V", Node->V()) \ + XX("w0", Node->w0()) \ + XX("wmax", Node->wmax()) \ + XX("s0", Node->s0()) \ + XX("v", Node->v()) \ + XX("w", Node->w()) \ + XX("D", Node->D()) \ + XX("S", Node->S()) \ + XX("l", Node->l(Eg())) \ + XX("e", Node->e()) \ + XX("a", Node->a(Eg())) \ + XX("Ec", Dc + Sc) \ + /**/ +#define SP_HEAD(h, e) Sprintf(" %11s", h) << +#define SP_ELEM(h, e) Sprintf(" %11.2le", double(e)) << +#define SP_STR(s) SP_HEAD(s, not_used) +#define SP_CTX(n) SP_STR(Sprintf("%s:%.2le", #n, ctx->n).data()) + +class TCtxStatusPrinter + : public IVisitorBase + , public IVisitor + , public IVisitor +{ +private: + TStringStream Ss; +public: + void Visit(const IContext*) override + { + Ss << SP_STR("unknown") ""; + } + + void Visit(const TDeContext* ctx) override + { + Ss << SP_STR("density") + SP_CTX(x) + SP_CTX(s) + SP_CTX(u) + SP_CTX(wl) + SP_CTX(p) + SP_CTX(pr) + SP_CTX(pl) + SP_CTX(pf) + SP_CTX(lambda) + SP_CTX(h) + SP_CTX(sigma) + SP_CTX(p0) + SP_CTX(isigma) + SP_CTX(ip0) + ""; + } + + TString Str() const + { + return Ss.Str(); + } + + static TString Get(const TShareNode* node) + { + TCtxStatusPrinter v; + if (const IContext* ctx = node->Ctx()) { + ctx->Accept(&v); + } else { + v.Ss << SP_STR("-") ""; + } + return v.Str(); + } +}; + +class TStatusPrinter : public IConstNodeVisitor { +private: + class TSums : public IConstSimpleNodeVisitor { + public: + const TShareNode* Node; + TSums* PSums; + TEnergy Dc = 0, Sc = 0; // Sums over alll children + + TSums(const TShareAccount* node, TSums* psums) + : Node(node) + , PSums(psums) + {} + + + TSums(const TShareGroup* node, TSums* psums) + : Node(node) + , PSums(psums) + { + node->AcceptInChildren(this); + } + + void Visit(const TShareNode* node) override + { + Dc += node->D(); Sc += node->S(); + } + + void Print(IOutputStream& os, size_t depth, size_t treeWidth) const + { + os << SP_NAME(Node->GetName()) SP_FOREACH_STATUS(SP_ELEM) TCtxStatusPrinter::Get(Node) << "\n"; + } + + TEnergy Eg() const + { + return PSums? PSums->Dc + PSums->Sc: 0; + } + }; + + TStringStream Ss; + size_t TreeWidth; + size_t Depth = 0; + TSums* PSums = nullptr; + + explicit TStatusPrinter(size_t treeWidth) + : TreeWidth(treeWidth) + {} + + void Visit(const TShareAccount* node) override + { + TSums sums(node, PSums); + sums.Print(Ss, Depth, TreeWidth); + } + + void Visit(const TShareGroup* node) override + { + // Stack + TSums* StackedSums = PSums; + + // Recurse + TSums sums(node, PSums); + PSums = &sums; + Depth++; + node->AcceptInChildren(this); + Depth--; + PSums = StackedSums; + + // Print + sums.Print(Ss, Depth, TreeWidth); + } + + TString Str() const + { + return Ss.Str(); + } + +public: + static TString Print(const TSharePlanner* planner) + { + TStringStream ss; + size_t treeWidth = TNameWidthEvaluator::Get(planner->GetRoot()); + size_t depth = 0; // just for macro to work + ss << SP_NAME("Name") SP_FOREACH_STATUS(SP_HEAD) SP_STR("model") "\n"; + TStatusPrinter v(treeWidth); + v.Visit(planner->GetRoot()); + ss << v.Str() << "\n"; + return ss.Str(); + } +}; + +struct TAsciiArt { + size_t TreeWidth; + size_t Depth; + const TShareGroup* Group; + TArtParams Art; + + int Height = 32; + int Width = 36; + int Length = 4 * Width; + double ScaleFactor = 1.0; + double Sigma = 1.0; + + TAsciiArt(size_t treeWidth, size_t depth, const TShareGroup* parent, const TArtParams& art) + : TreeWidth(treeWidth) + , Depth(depth) + , Group(parent) + , Art(art) + { + if (const TDeContext* gctx = dynamic_cast(Group->Ctx())) { + Sigma = gctx->sigma; + } + ScaleFactor = (Art.SigmaStretch? Sigma: 1.0) / Art.Scale; + } + + TLength Xinv(int x) const + { + return double(x) / ScaleFactor / Width * gs * Group->GetTotalVolume(); + } + + int Xcut(TLength x) const + { + return Max(0, Min(Length, X(x))); + } + + int X(TLength x) const + { + return llrint(x * ScaleFactor * Width * gs / Group->GetTotalVolume()); + } + + TForce Yinv(int y) const + { + return double(y) / Height * gs; + } + + int Ycut(TForce s) const + { + return Max(0, Min(Height, Y(s))); + } + + int Y(TForce s) const + { + return llrint(s * Height / gs); + } +}; + +class TBandPrinter : public IConstSimpleNodeVisitor, public TAsciiArt { +private: + TStringStream Ss; + TString Prefix; + TVector Nodes; + TEnergy Eg = 0; + FWeight wg = 0; +public: + TBandPrinter(size_t treeWidth, size_t depth, const TShareGroup* group, const TArtParams& art) + : TAsciiArt(treeWidth, depth, group, art) + , Prefix(TString(2 * Depth, ' ') + "|" + TString(TreeWidth + 1, ' ')) + { + Height = 0; // Manual height + } + + void Visit(const TShareNode* node) override + { + Nodes.push_back(node); + Eg += node->E(); + wg += node->w(); + Height += 5; + } + + TString Str() + { + TForce x_offset = (Eg - 2 * Group->GetTotalVolume()) / gs; + for (const TShareNode* node : Nodes) { + TString status = node->GetStatus(); + Ss << Sprintf("%-*s ", (int)TreeWidth, (TString(2 * Depth, ' ') + "+-" + ToString(node->GetName())).data()) + << TString(9, '*') + << Sprintf(" Ac:%-9ld De:%-9ld Re:%-9ld Ot:%-9ld *** Done:%-9ld w0:%-7.2le w:%-7.2le ", + node->GetStats().Activations, node->GetStats().Deactivations, + node->GetStats().Retardations, node->GetStats().Overtakes, + node->GetStats().NDone, node->w0(), node->w()) + << TString(Length - 109 - status.size(), '*') + << Sprintf(" %s ***", status.data()) + << Endl; + // Ensure li <= oi <= ei to be able to draw even corrupted or transitional state + int li = Xcut(node->l(Eg) - x_offset); + int oi = Max(li, Xcut(node->o(Eg) - x_offset)); + int e = Max(oi, Xcut(Eg/gs - x_offset)); + int ei = Xcut(node->e() - x_offset); + // ei + // | (4 possible cases) + // .-----------+-----+-----+-----------. + // | | | | + // ei_l li ei_lo oi ei_oe e ei_e + // -----+-----+-----+-----+-----+-----+-----+------ + // ..... ===== ::::: >>>>> OOOOO ----- XXXXX + // ..... ===== ::::: >>>>> OOOOO ----- XXXXX + // -----+-----+-----+-----+-----+-----+-----+-----> x + // + int ei_l = Min(ei, li); + int ei_lo = Max(li, Min(ei, oi)); + int ei_oe = Max(oi, Min(ei, e)); + int ei_e = Max(ei, e); + int h = Max(1, Ycut(node->s0())); + for (int i = 0; i < h; i++) { + Ss << Prefix + << TString(ei_l , '.') + << TString(li - ei_l , '=') + << TString(ei_lo - li , ':') + << TString(oi - ei_lo, '>') + << TString(ei_oe - oi , 'O') + << TString(e - ei_oe, '-') + << TString(ei_e - e , 'X') + << Endl; + } + } + Ss << Sprintf("%-*s ", (int)TreeWidth, (TString(2 * Depth, ' ') + ToString(Group->GetName())).data()) + << TString(61, '*') + << Sprintf(" gw0:%-7.2le gw:%-7.2le ", Group->GetTotalWeight(), wg) + << TString(Length - 87, '*') + << Endl; + return Ss.Str(); + } + + static TString Print(size_t treeWidth, size_t depth, const TShareGroup* group, const TArtParams& art) + { + TBandPrinter v(treeWidth, depth, group, art); + group->AcceptInChildren(&v); + return v.Str(); + } +}; + +class TDensityPlotter + : public IConstSimpleNodeVisitor + , public IVisitor + , public IVisitor + , public TAsciiArt { +private: + TStringStream Ss; + TStringStream Err; + TString Prefix; + TVector> Points; + TVector Pixels; + TLength Xoffset = 0; +public: + TDensityPlotter(size_t treeWidth, size_t depth, const TShareGroup* group, const TArtParams& art) + : TAsciiArt(treeWidth, depth, group, art) + , Prefix(TString(2 * Depth + TreeWidth + 1, ' ')) + {} + + void Visit(const IContext* ctx) override + { + Err << "unknown context type: " << TypeName(*ctx) << "\n"; + } + + void Visit(const TDeContext* ctx) override + { + ctx->PushPoints(Points); + } + + void Visit(const TShareNode* node) override + { + if (const IContext* ctx = node->Ctx()) { + ctx->Accept(this); + } + } + + TString Str() + { + if (Points.empty()) + Err << "no points"; + if (!Err.Empty()) + return "TDensityPlotter: error: " + Err.Str() + "\n"; + Xoffset = (- 2 * Group->GetTotalVolume()) / gs; + AddLine(); + MakePlot(); + PrintPlot(); + return Ss.Str(); + } + + void AddLine() + { + for (int x = 0; x <= Length; x++) { + double p = Xinv(x) + Xoffset; + Points.push_back(TDePoint{nullptr, p, TDepType::Other}); + } + } + + void MakePlot() + { + static const char Signs[] = "+^1.+-"; + Pixels.resize((Length+1) * (Height+1), ' '); + double h = 0.0; + double lambda = 0.0; + TDePoint* prev = nullptr; + Sort(Points); + for (TDePoint& cur : Points) { + cur.Move(h, lambda, prev); + prev = &cur; + int x = X(cur.p - Xoffset); + int y = Y((1-h) * gs); + char pc = GetPixel(x, y); + char c = Signs[int(cur.Type)]; + if (pc == ' ' || pc == '-' || c == '1') { + if (c == '1') { + if (pc >= '1' && pc <= '8') { + c = pc + 1; + } + if (pc == '9' || pc == '*') { + c = '*'; + } + } + SetPixel(x, y, c); + } + } + TLength p0 = 0; + if (const TDeContext* gctx = dynamic_cast(Group->Ctx())) { + p0 = gctx->p0; + } + int xp0 = X(p0 - Xoffset); + for (int y = 0; y <= Height; y++) { + char pc = GetPixel(xp0, y); + if (pc == ' ') { + SetPixel(xp0, y, ':'); + } + } + } + + char SigmaPixel(int y) + { + return (1.0 - Yinv(y)) > Sigma? ' ': 'X'; + } + + void PrintPlot() + { + for (int y = 0; y <= Height; y++) { + Ss << Prefix + << SigmaPixel(y) + << TString(Pixels.begin() + y*(Length+1), Pixels.begin() + (y+1)*(Length+1)) << Endl; + } + Ss << Sprintf("%-*s ", (int)TreeWidth, (TString(2 * Depth, ' ') + ToString(Group->GetName())).data()) + << 's' << TString(Length + 1, '*') << Endl; + } + + void SetPixel(int x, int y, char c) + { + if (x >= 0 && y >= 0 && x <= Length && y <= Height) { + Pixels[y * (Length+1) + x] = c; + } + } + + char GetPixel(int x, int y) + { + if (x >= 0 && y >= 0 && x <= Length && y <= Height) { + return Pixels[y * (Length+1) + x]; + } else { + return 0; + } + } + + static TString Print(size_t treeWidth, size_t depth, const TShareGroup* group, const TArtParams& art) + { + TDensityPlotter v(treeWidth, depth, group, art); + group->AcceptInChildren(&v); + return v.Str(); + } +}; + +class TTreePrinter : public IConstNodeVisitor { +private: + const TSharePlanner* Planner; + TStringStream Ss; + size_t TreeWidth; + size_t Depth = 0; + bool Band; + bool Model; + TArtParams Art; + + explicit TTreePrinter(const TSharePlanner* planner, size_t treeWidth, bool band, bool model, const TArtParams& art) + : Planner(planner) + , TreeWidth(treeWidth) + , Band(band) + , Model(model) + , Art(art) + {} + + void Visit(const TShareAccount*) override + { + // Do nothing for accounts + } + + void Visit(const TShareGroup* node) override + { + Depth++; + node->AcceptInChildren(this); + Depth--; + if (Band) { + Ss << TBandPrinter::Print(TreeWidth, Depth, node, Art); + } + if (Model) { + switch (Planner->Cfg().GetModel()) { + case PM_STATIC: + break; + case PM_MAX: + break; + case PM_DENSITY: + Ss << TDensityPlotter::Print(TreeWidth, Depth, node, Art); + break; + default: break; + } + } + Ss << Endl; + } + + TString Str() const + { + return Ss.Str(); + } + +public: + static TString Print(const TSharePlanner* planner, bool band, bool model, const TArtParams& art) + { + TTreePrinter v(planner, TNameWidthEvaluator::Get(planner->GetRoot(), 2), band, model, art); + v.Visit(planner->GetRoot()); + return v.Str(); + } +}; + +} diff --git a/ydb/library/planner/share/node.cpp b/ydb/library/planner/share/node.cpp new file mode 100644 index 000000000000..4cee89d9e366 --- /dev/null +++ b/ydb/library/planner/share/node.cpp @@ -0,0 +1,114 @@ +#include "node.h" +#include "group.h" +#include "apply.h" + +namespace NScheduling { + +void TShareNode::SetConfig(TAutoPtr cfg) +{ + Y_ABORT_UNLESS(!Planner, "configure of attached share planner nodes is not allowed"); + Config.Reset(cfg.Release()); +} + +TEnergy TShareNode::ComputeEg() const +{ + if (Parent) { + return Parent->ComputeEc(); + } else { + return E(); + } +} + +TForce TShareNode::CalcGlobalShare() const +{ + return Share * (Parent? Parent->CalcGlobalShare(): 1.0); +} + +void TShareNode::Attach(TSharePlanner* planner, TShareGroup* parent) +{ + Planner = planner; + Parent = parent; + if (Parent) { + Parent->Add(this); + } else { + Share = gs; + } +} + +void TShareNode::Detach() +{ + if (Parent) { + Parent->Remove(this); + } + DetachNoRemove(); +} + +void TShareNode::DetachNoRemove() +{ + Planner = nullptr; + Parent = nullptr; +} + +void TShareNode::Done(TEnergy cost) +{ + Y_ABORT_UNLESS(cost >= 0, "negative work in node '%s' dD=%lf", GetName().data(), cost); + + // Apply current tariff + TEnergy bill = cost * Tariff; + D_ += bill; + dD_ += bill; + Stats.Done(cost); + Stats.Pay(bill); + + if (Parent) { + Parent->Done(cost); // Work is transmitted to parent + } +} + +void TShareNode::Spoil(TEnergy cost) +{ + Y_ABORT_UNLESS(cost >= 0, "negative spoil in node '%s' dS=%lf", GetName().data(), cost); + S_ += cost; + dS_ += cost; + Stats.Spoil(cost); + // Spoil is NOT transmitted to parent +} + +void TShareNode::SetTariff(TDimless tariff) +{ + Tariff = tariff; +} + +void TShareNode::Step() +{ + bool wasActive = IsActive(); + bool wasRetarded = IsRetard(); + pdS_ = dS_; + pdD_ = dD_; + dS_ = 0; + dD_ = 0; + if (!wasActive && IsActive()) + Stats.Activations++; + if (wasActive && !IsActive()) + Stats.Deactivations++; + if (!wasRetarded && IsRetard()) + Stats.Retardations++; + if (wasRetarded && !IsRetard()) + Stats.Overtakes++; +} + +TString TShareNode::GetStatus() const +{ + TString status; + if (pdD() > 0) { + status += "ACTIVE"; + } else { + status += "IDLE"; + } + if (pdS() > 0) { + status += " RETARD"; + } + return status; +} + +} diff --git a/ydb/library/planner/share/node.h b/ydb/library/planner/share/node.h new file mode 100644 index 000000000000..e81973116331 --- /dev/null +++ b/ydb/library/planner/share/node.h @@ -0,0 +1,136 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "stats.h" + +namespace NScheduling { + +class IContext; +class IModel; +class TShareAccount; +class TShareGroup; +class TSharePlanner; + +class TShareNode : public IVisitable { +public: + SCHEDULING_DEFINE_VISITABLE(IVisitable); +public: + struct TConfig { + virtual ~TConfig() {} + TString Name; + FWeight Weight; // Weight in parent group + FWeight MaxWeight; + TEnergy Volume; + + TConfig(TEnergy v, FWeight wmax, FWeight w, const TString& name) + : Name(name) + , Weight(w) + , MaxWeight(wmax) + , Volume(v) + { + Y_ABORT_UNLESS(Weight > 0, "non-positive (%lf) weight in planner node '%s'", + Weight, Name.data()); + Y_ABORT_UNLESS(Weight <= MaxWeight, "max weight (%lf) must be greater or equal to normal weight (%lf) in planner node '%s'", + MaxWeight, Weight, Name.data()); + Y_ABORT_UNLESS(Volume >= 0, "negative (%lf) volume in planner node '%s'", + Volume, Name.data()); + } + }; +protected: + THolder Context; + THolder Config; + TSharePlanner* Planner = nullptr; + TShareGroup* Parent = nullptr; + TForce Share = 0; // s0[i] = w0[i] / sum(w0[i] for i in parent group) -- default share in parent group + TEnergy D_ = 0; // Work done + TEnergy S_ = 0; // Spoiled energy + TEnergy dD_ = 0; + TEnergy dS_ = 0; + TEnergy pdD_ = 0; + TEnergy pdS_ = 0; + TDimless Tariff = 1.0; + TNodeStats Stats; +public: + explicit TShareNode(TAutoPtr cfg) + : Config(cfg.Release()) + {} + virtual ~TShareNode() {} + const TConfig& Cfg() const { return *Config.Get(); } + void SetConfig(TAutoPtr cfg); +public: // Accessors + const TString& GetName() const { return Cfg().Name; } + TShareGroup* GetParent() { return Parent; } + const TShareGroup* GetParent() const { return Parent; } + TSharePlanner* GetPlanner() { return Planner; } + const TSharePlanner* GetPlanner() const { return Planner; } + TForce GetShare() const { return Share; } + void SetShare(TForce value) { Share = value; } +public: // Computations + TLength Normalize(TEnergy cost) const { return cost / s0(); } + TEnergy ComputeEg() const; + TForce CalcGlobalShare() const; +public: // Short accessors for formulas + TForce s0() const { return Share; } + FWeight w0() const { return Cfg().Weight; } + FWeight wmax() const { return Cfg().MaxWeight; } + FWeight w() const { return Context? Ctx()->GetWeight(): w0(); } + TDimless h() const { return (w() - w0()) / (wmax() - w0()); } + TEnergy D() const { return D_; } + TEnergy S() const { return S_; } + TEnergy dD() const { return dD_; } + TEnergy dS() const { return dS_; } + TEnergy pdD() const { return pdD_; } + TEnergy pdS() const { return pdS_; } + TEnergy E() const { return D_ + S_; } + TEnergy V() const { return Cfg().Volume; } + TEnergy L(TEnergy Eg) const { return Eg*Share/gs - V(); } + TEnergy O(TEnergy Eg) const { return L(Eg); } + TEnergy A(TEnergy Eg) const { return E() - L(Eg); } + TEnergy P(TEnergy Eg) const { return E() - Eg*Share/gs; } + TLength dd() const { return dD() / Share; } + TLength ds() const { return dS() / Share; } + TLength pdd() const { return pdD() / Share; } + TLength pds() const { return pdS() / Share; } + TLength e() const { return E() / Share; } + TLength v() const { return V() / Share; } + TLength l(TEnergy Eg) const { return L(Eg) / Share; } + TLength o(TEnergy Eg) const { return O(Eg) / Share; } + TLength a(TEnergy Eg) const { return A(Eg) / Share; } + TLength p(TEnergy Eg) const { return e() - Eg/gs; } +public: + void SetS(TEnergy value) { S_ = value; } + void SetD(TEnergy value) { D_ = value; } +public: // Context for models + IContext* Ctx() { return Context.Get(); } + const IContext* Ctx() const { return Context.Get(); } + void ResetCtx(IContext* ctx) { Context.Reset(ctx); } + template + TCtx& Ctx() { return *static_cast(Context.Get()); } + template + TCtx* CtxAs() { return dynamic_cast(Context.Get()); } +public: // Tree modifications + void Attach(TSharePlanner* planner, TShareGroup* parent); + void Detach(); + void DetachNoRemove(); +public: // Evolution + void Done(TEnergy cost); + void Spoil(TEnergy cost); + void SetTariff(TDimless tariff); + void Step(); +public: // Monitoring + bool IsActive() const { return pdD() > 0; } + bool IsRetard() const { return pdS() > 0; } + const TNodeStats& GetStats() const { return Stats; } + virtual TString GetStatus() const; +}; + +} diff --git a/ydb/library/planner/share/node_visitor.h b/ydb/library/planner/share/node_visitor.h new file mode 100644 index 000000000000..3f7d6e1a2995 --- /dev/null +++ b/ydb/library/planner/share/node_visitor.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +namespace NScheduling { + +class TShareNode; +class TShareAccount; +class TShareGroup; + +class INodeVisitor + : public IVisitorBase + , public IVisitor + , public IVisitor +{ +public: + using IVisitor::Visit; + using IVisitor::Visit; +}; + +class IConstNodeVisitor + : public IVisitorBase + , public IVisitor + , public IVisitor +{ +public: + using IVisitor::Visit; + using IVisitor::Visit; +}; + +class ISimpleNodeVisitor + : public IVisitorBase + , public IVisitor +{}; + +class IConstSimpleNodeVisitor + : public IVisitorBase + , public IVisitor +{}; + +} diff --git a/ydb/library/planner/share/probes.cpp b/ydb/library/planner/share/probes.cpp new file mode 100644 index 000000000000..478de8a4b135 --- /dev/null +++ b/ydb/library/planner/share/probes.cpp @@ -0,0 +1,3 @@ +#include "probes.h" + +LWTRACE_DEFINE_PROVIDER(SCHEDULING_SHAREPLANNER_PROVIDER) diff --git a/ydb/library/planner/share/probes.h b/ydb/library/planner/share/probes.h new file mode 100644 index 000000000000..2b39253ec213 --- /dev/null +++ b/ydb/library/planner/share/probes.h @@ -0,0 +1,123 @@ +#pragma once + +#include +#include +#include + +namespace NScheduling { + +// Helper class for printing cost in percents of total planner capacity +struct TModelField { + typedef int TStoreType; + static void ToString(int value, TString* out) { + *out = Sprintf("%d(%s)", value, EPlanningModel_Name((EPlanningModel)value).c_str()); + } +}; + +} + +#define PLANNER_PROBE(name, ...) GLOBAL_LWPROBE(SCHEDULING_SHAREPLANNER_PROVIDER, name, ## __VA_ARGS__) + +#define SCHEDULING_SHAREPLANNER_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ + PROBE(Done, GROUPS("Scheduling", "SharePlannerInterface", "SharePlannerAccount"), \ + TYPES(TString,TString,double,double), \ + NAMES("planner","account","cost","time")) \ + PROBE(Waste, GROUPS("Scheduling", "SharePlannerInterface"), \ + TYPES(TString,double), \ + NAMES("planner","cost")) \ + PROBE(Run, GROUPS("Scheduling", "SharePlannerInterface"), \ + TYPES(TString), \ + NAMES("planner")) \ + PROBE(Configure, GROUPS("Scheduling", "SharePlannerInterface"), \ + TYPES(TString, TString), \ + NAMES("planner", "cfg")) \ + PROBE(SerializeHistory, GROUPS("Scheduling", "SharePlannerInterface"), \ + TYPES(TString), \ + NAMES("planner")) \ + PROBE(DeserializeHistoryBegin, GROUPS("Scheduling", "SharePlannerInterface"), \ + TYPES(TString), \ + NAMES("planner")) \ + PROBE(DeserializeHistoryEnd, GROUPS("Scheduling", "SharePlannerInterface"), \ + TYPES(TString, bool), \ + NAMES("planner", "success")) \ + PROBE(Add, GROUPS("Scheduling", "SharePlannerInterface"), \ + TYPES(TString,TString,NScheduling::TWeight,TString), \ + NAMES("planner","parent","weight","node")) \ + PROBE(Delete, GROUPS("Scheduling", "SharePlannerInterface"), \ + TYPES(TString,TString), \ + NAMES("planner","node")) \ + \ + PROBE(FirstActivation, GROUPS("Scheduling", "SharePlannerDetails"), \ + TYPES(TString), \ + NAMES("planner")) \ + PROBE(LastDeactivation, GROUPS("Scheduling", "SharePlannerDetails"), \ + TYPES(TString), \ + NAMES("planner")) \ + PROBE(CommitInfo, GROUPS("Scheduling", "SharePlannerDetails"), \ + TYPES(TString, bool,bool,TString), \ + NAMES("planner","model","run","info")) \ + PROBE(Advance, GROUPS("Scheduling", "SharePlannerDetails"), \ + TYPES(TString,double,double), \ + NAMES("planner","cost","wcost")) \ + PROBE(TryDeactivate, GROUPS("Scheduling", "SharePlannerDetails"), \ + TYPES(TString), \ + NAMES("planner")) \ + PROBE(Spoil, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerAccount"), \ + TYPES(TString,TString,double), \ + NAMES("planner","account","cost")) \ + PROBE(SetRate, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerAccount"), \ + TYPES(TString,TString,double,double), \ + NAMES("planner","account","oldrate","newrate")) \ + PROBE(SetAssuredRate, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerAccount"), \ + TYPES(TString,TString,double,double), \ + NAMES("planner","account","oldrate","newrate")) \ + PROBE(ResetRate, GROUPS("Scheduling", "SharePlannerDetails"), \ + TYPES(TString,TString,double), \ + NAMES("planner","group","rate")) \ + PROBE(ResetAssuredRate, GROUPS("Scheduling", "SharePlannerDetails"), \ + TYPES(TString,TString,double), \ + NAMES("planner","group","rate")) \ + PROBE(SetTL, GROUPS("Scheduling", "SharePlannerDetails"), \ + TYPES(TString,double,double), \ + NAMES("planner","old","new")) \ + PROBE(CalcFixedHyperbolicWeight, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerAccount", "SharePlannerWeight"), \ + TYPES(TString,TString,double,double,double,double,double), \ + NAMES("planner","account","l","x","X","Xxi","result")) \ + PROBE(CalcFixedHyperbolicWeight_I, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerAccount", "SharePlannerWeight"), \ + TYPES(TString,TString,double,double,double,double,double), \ + NAMES("planner","account","D_R","W","WMax","xi_min","RepaymentPeriod")) \ + PROBE(FloatingLinearModel, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerAccount", "SharePlannerWeight"), \ + TYPES(TString,TString,double,double,double,double,double, double, double), \ + NAMES("planner","account","w_prev","rho","h","u","dD","xsum","wsum")) \ + PROBE(FloatingLinearModel_I, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerAccount", "SharePlannerWeight"), \ + TYPES(TString,TString,double,double,double,double,double,double,double,double), \ + NAMES("planner","account","w0","wm","RepaymentPeriod","a0","amin","a","w","result")) \ + \ + PROBE(ActivePoolPush, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerHeaps", "SharePlannerAccount"), \ + TYPES(TString,TString,double,size_t), \ + NAMES("planner","account","until","newsize")) \ + PROBE(ActivePoolPop, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerHeaps", "SharePlannerAccount"), \ + TYPES(TString,TString,size_t), \ + NAMES("planner","account","newsize")) \ + PROBE(ActivePoolPeek, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerHeaps", "SharePlannerAccount"), \ + TYPES(TString,TString,double,size_t), \ + NAMES("planner","account","until","size")) \ + PROBE(ActivePoolRebuild, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerHeaps"), \ + TYPES(TString,size_t,size_t), \ + NAMES("planner","badnonidle","size")) \ + PROBE(ActivePoolIncBad, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerHeaps", "SharePlannerAccount"), \ + TYPES(TString,TString,size_t), \ + NAMES("planner","account","new")) \ + PROBE(ActivePoolDecBad, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerHeaps", "SharePlannerAccount"), \ + TYPES(TString,TString,size_t), \ + NAMES("planner","account","new")) \ + \ + PROBE(Deactivate, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerAccountTransitions", "SharePlannerAccount"), \ + TYPES(TString,TString), \ + NAMES("planner","account")) \ + PROBE(Activate, GROUPS("Scheduling", "SharePlannerDetails", "SharePlannerAccountTransitions", "SharePlannerAccount"), \ + TYPES(TString,TString), \ + NAMES("planner","account")) \ + /**/ + +LWTRACE_DECLARE_PROVIDER(SCHEDULING_SHAREPLANNER_PROVIDER) diff --git a/ydb/library/planner/share/protos/shareplanner.proto b/ydb/library/planner/share/protos/shareplanner.proto new file mode 100644 index 000000000000..8b746b1f5b04 --- /dev/null +++ b/ydb/library/planner/share/protos/shareplanner.proto @@ -0,0 +1,38 @@ +package NScheduling; + +option java_package = "ru.yandex.scheduling.proto"; + +enum EPlanningModel { + PM_STATIC = 0; + PM_MAX = 1; + PM_DENSITY = 2; +} + +enum EPullType { + PT_STRICT = 0; + PT_INSENSITIVE = 1; + PT_NONE = 2; +} + +enum EBillingType { + BT_STATIC = 0; + BT_PRESENT_SHARE = 1; +} + +message TSharePlannerConfig { + optional string Name = 1 [ default = "shareplanner" ]; + + // Puller params + optional EPullType Pull = 2 [ default = PT_STRICT ]; + optional double PullLength = 8 [ default = 100 ]; + + // Model params + optional EPlanningModel Model = 3 [ default = PM_DENSITY ]; + optional double DenseLength = 4 [ default = 1.0 ]; + optional double AveragingLength = 5 [ default = 0.1 ]; + + // Billing params + optional EBillingType Billing = 6 [ default = BT_STATIC ]; + optional double StaticTariff = 7 [ default = 1.0 ]; // Used only if Billing=BT_STATIC + optional bool BillingIsMemoryless = 9; // Used only if Billing=BT_PRESENT_SHARE +} diff --git a/ydb/library/planner/share/protos/shareplanner_history.proto b/ydb/library/planner/share/protos/shareplanner_history.proto new file mode 100644 index 000000000000..cb9fe0e4aca3 --- /dev/null +++ b/ydb/library/planner/share/protos/shareplanner_history.proto @@ -0,0 +1,22 @@ +package NScheduling; + +option java_package = "ru.yandex.scheduling.proto"; + +message TShareNodeHistory { + optional string Name = 1; + optional double Proficit = 2; +} + +// +//message TUtilizationHistory { +// repeated int64 DoneInSlot = 1; +// optional int64 SlotVolume = 2; +// optional uint64 CurrentSlot = 3; +//} +// + +message TSharePlannerHistory { + repeated TShareNodeHistory Nodes = 1; +// optional TUtilizationHistory Utilization = 3; +} + diff --git a/ydb/library/planner/share/protos/shareplanner_sensors.proto b/ydb/library/planner/share/protos/shareplanner_sensors.proto new file mode 100644 index 000000000000..a7a00b660076 --- /dev/null +++ b/ydb/library/planner/share/protos/shareplanner_sensors.proto @@ -0,0 +1,88 @@ +import "library/cpp/monlib/encode/legacy_protobuf/protos/metric_meta.proto"; + +package NScheduling; + +option java_package = "ru.yandex.scheduling.proto"; + +message TShareNodeSensors { + optional string Name = 1; + optional string ParentName = 2; + + // Planner outcome stats for requests + optional uint64 NDone = 11 [ (NMonProto.Metric).Type = RATE ]; + optional uint64 NSpoiled = 12 [ (NMonProto.Metric).Type = RATE ]; + + // Resource usage [cluster-power * sec] + optional double ResDone = 13 [ (NMonProto.Metric).Type = RATE ]; + optional double ResSpoiled = 14 [ (NMonProto.Metric).Type = RATE ]; + optional double MoneySpent = 29 [ (NMonProto.Metric).Type = RATE ]; + optional double Proficit = 15 [ (NMonProto.Metric).Type = GAUGE ]; + //optional uint64 ResDone = 16 [ (NMonProto.Metric).Type = RATE ]; DEPRECATED + //optional int64 Deficit = 17 [ (NMonProto.Metric).Type = GAUGE ]; DEPRECATED + + // Lag is proficit normalized for account's parent group + optional double Lag = 18 [ (NMonProto.Metric).Type = GAUGE ]; + optional double FloatingLag = 19 [ (NMonProto.Metric).Type = GAUGE ]; + + // Consumer status count (0 - is not current state; 1 - is current state) + optional uint64 Idle = 20 [ (NMonProto.Metric).Type = GAUGE ]; + optional uint64 Active = 21 [ (NMonProto.Metric).Type = GAUGE ]; + optional uint64 IdleRetard = 22 [ (NMonProto.Metric).Type = GAUGE ]; + optional uint64 ActiveRetard = 23 [ (NMonProto.Metric).Type = GAUGE ]; + + // Consumer event stats + optional uint64 Activations = 30 [ (NMonProto.Metric).Type = RATE ]; + optional uint64 Deactivations = 31 [ (NMonProto.Metric).Type = RATE ]; + optional uint64 Retardations = 32 [ (NMonProto.Metric).Type = RATE ]; + optional uint64 Overtakes = 33 [ (NMonProto.Metric).Type = RATE ]; + + // Global shares [between 0 and 1] + optional double DefShare = 40 [ (NMonProto.Metric).Type = GAUGE ]; + optional double RealShare = 41 [ (NMonProto.Metric).Type = GAUGE ]; + optional double AvgRealShare = 42 [ (NMonProto.Metric).Type = GAUGE ]; + optional double DynamicShare = 43 [ (NMonProto.Metric).Type = GAUGE ]; + + // Group shares [between 0 and 1] + optional double GrpDefShare = 60 [ (NMonProto.Metric).Type = GAUGE ]; + optional double GrpRealShare = 61 [ (NMonProto.Metric).Type = GAUGE ]; + optional double GrpAvgRealShare = 62 [ (NMonProto.Metric).Type = GAUGE ]; + optional double GrpDynamicShare = 63 [ (NMonProto.Metric).Type = GAUGE ]; + + // Weights information + optional double DefWeight = 51 [ (NMonProto.Metric).Type = GAUGE ]; + optional double MaxWeight = 52 [ (NMonProto.Metric).Type = GAUGE ]; + optional double MinWeight = 53 [ (NMonProto.Metric).Type = GAUGE ]; + optional double DynamicWeight = 54 [ (NMonProto.Metric).Type = GAUGE ]; + + // Density model specific + optional double Usage = 70 [ (NMonProto.Metric).Type = GAUGE ]; + optional double InstantUsage = 74 [ (NMonProto.Metric).Type = GAUGE ]; + optional double Tariff = 71 [ (NMonProto.Metric).Type = GAUGE ]; + optional double InstantTariff = 76 [ (NMonProto.Metric).Type = GAUGE ]; + optional double Boost = 72 [ (NMonProto.Metric).Type = GAUGE ]; + optional double FloatingOrigin = 73 [ (NMonProto.Metric).Type = GAUGE ]; + optional double InstantOrigin = 75 [ (NMonProto.Metric).Type = GAUGE ]; + optional double PullStretch = 77 [ (NMonProto.Metric).Type = GAUGE ]; + optional double Retardness = 78 [ (NMonProto.Metric).Type = GAUGE ]; + optional double RetardShare = 79 [ (NMonProto.Metric).Type = GAUGE ]; + + // Parent-specific sensors (set only for groups) + optional double TotalCredit = 100 [ (NMonProto.Metric).Type = GAUGE ]; +} + +message TSharePlannerSensors { + repeated TShareNodeSensors Accounts = 1 [ (NMonProto.Metric).Path = false, (NMonProto.Metric).Keys = "account:Name" ]; + repeated TShareNodeSensors Groups = 2 [ (NMonProto.Metric).Path = false, (NMonProto.Metric).Keys = "group:Name" ]; + repeated TShareNodeSensors Nodes = 4 [ (NMonProto.Metric).Path = false, (NMonProto.Metric).Keys = "node:Name parent:ParentName" ]; + optional TShareNodeSensors Total = 3 [ (NMonProto.Metric).Path = true ]; // All accounts w/o groups + + // Resource totals + optional double ResUsed = 10 [ (NMonProto.Metric).Type = RATE ]; + optional double ResWasted = 11 [ (NMonProto.Metric).Type = RATE ]; + + // Utilization measuments + optional double ResUsedInWindow = 20 [ (NMonProto.Metric).Type = GAUGE ]; + optional double ResWastedInWindow = 21 [ (NMonProto.Metric).Type = GAUGE ]; + optional double Utilization = 22 [ (NMonProto.Metric).Type = GAUGE ]; +} + diff --git a/ydb/library/planner/share/protos/ya.make b/ydb/library/planner/share/protos/ya.make new file mode 100644 index 000000000000..cdccb9b0be7e --- /dev/null +++ b/ydb/library/planner/share/protos/ya.make @@ -0,0 +1,15 @@ +PROTO_LIBRARY() + +PEERDIR( + library/cpp/monlib/encode/legacy_protobuf/protos +) + +SRCS( + shareplanner_sensors.proto + shareplanner.proto + shareplanner_history.proto +) + +EXCLUDE_TAGS(GO_PROTO) + +END() diff --git a/ydb/library/planner/share/pull.h b/ydb/library/planner/share/pull.h new file mode 100644 index 000000000000..a335a6bf4d9e --- /dev/null +++ b/ydb/library/planner/share/pull.h @@ -0,0 +1,208 @@ +#pragma once + +#include +#include "apply.h" +#include "node_visitor.h" +#include "shareplanner.h" +#include + +namespace NScheduling { + +// It pulls retarded users in group up to their left edge immediately +class TStrictPuller : public ISimpleNodeVisitor { +private: + struct TNodeInfo { + TShareNode* Node; + TLength Key; + + explicit TNodeInfo(TShareNode& n) + : Node(&n) + , Key(double(n.D() + n.S() + n.V()) / n.s0()) // e[i] + v[i] + {} + + bool operator<(const TNodeInfo& o) const + { + return Key > o.Key; // Greater is used to build min-heap + } + }; + + TShareGroup* Group = nullptr; + TVector Infos; + TForce s0R = 0; // sum(s0[i] for i in retarded nodes) + TEnergy E_ = 0; // sum(E[i] for i in Group) + TEnergy dS = 0; +public: + void Pull(TShareGroup* group) + { + StartGroup(group); + group->AcceptInChildren(this); + FinishGroup(); + } +private: + void StartGroup(TShareGroup* group) + { + Group = group; + Infos.clear(); + s0R = 0; + E_ = 0; + dS = 0; + } + + void Visit(TShareNode* node) override + { + Infos.push_back(TNodeInfo(*node)); + E_ += node->E(); + } + + TEnergy E() const { return E_ + dS; } + TLength e() const { return E() / gs; } + + void FinishGroup() + { + if (Infos.size() <= 1) { + return; // If there is less than 2 nodes, then pull is not needed + } + // Iterate over all nodes in Group sorted by e[i] + v[i] + MakeHeap(Infos.begin(), Infos.end()); + auto last = Infos.end(); + auto second = Infos.begin() + 1; // avoid pulling first node which otherwise lead to dS=inf (s0R - gs == 0.0) + for (; last != second; ) { + TLength de = e() - Infos.front().Key; + if (de <= 0) { + break; // Stop if no more retarded nodes + } + + PopHeap(Infos.begin(), last); + TNodeInfo& ni = *--last; + TShareNode& n = *ni.Node; + s0R += n.s0(); + dS += de * gs * n.s0() / (gs - s0R); + } + + // Iterate backwards over retarded nodes in Group + for (; last != Infos.end(); ++last) { + TNodeInfo& ni = *last; + TShareNode& n = *ni.Node; + TEnergy dSi = e() * n.s0() - n.V() - n.E(); + if (dSi > 0) { // Negative value may appear only due to floating-point arithmetic inaccuracy + n.Spoil(dSi); + } + } + } +}; + +// It pulls all retarded users in group for the same amount of normalized proficit +// It also calculates left edge relative to the floating origin (which in turn is +// insensitive to absent users) +class TInsensitivePuller { +private: + TLength Length; +public: + TInsensitivePuller(TLength length) + : Length(length) + {} + + void Pull(TShareGroup* group) + { + // This puller is assumed to be used only with density model + TDeContext* gctx = group->CtxAs(); + if (!gctx) + return; // Most probably new group + + // (1) Compute p0 based on u computed in last model run + // (Note that gctx->p0 is updated only on model runs, so we cannot use it directly + // And it is assumed that iu is not changing very fast, so ctx->iu is good enough) + // (2) And also compute dD since last pull in the same traverse + TEnergy dD = 0; + TForce sigma = 0; + TEnergy p0sigma = 0; + TEnergy Ec = group->ComputeEc(); + ApplyTo(group, [=, &dD, &sigma, &p0sigma] (TShareNode* node) { + if (TDeContext* ctx = node->CtxAs()) { + // Avoid pulling with big dD just after turning ON + if (ctx->Pull.Cycle == ctx->ModelCycle || ctx->Pull.Cycle == ctx->ModelCycle + 1) { + TEnergy dDi = node->D() - ctx->Pull.Dlast; + dD += dDi; + } + ctx->Pull.Cycle = ctx->ModelCycle + 1; + ctx->Pull.Dlast = node->D(); + + TForce sigma_i = ctx->iu * node->s0(); + sigma += sigma_i; + p0sigma += sigma_i * node->p(Ec); + } + }); + TLength p0 = p0sigma / sigma; + + // Take movement into account + p0 -= dD / gs; + TForce s0R_prev = gctx->Pull.s0R; // We do not want solve system of equations, so just use previous value of s0R + if (s0R_prev > 0.0 && s0R_prev < 1.0) { + TEnergy dS_estimate = s0R_prev / (1 - s0R_prev) * dD; // See formula explanation below + p0 -= dS_estimate / gs; + } + + // Find retards and compute their total share + TForce s0R = 0; + ApplyTo(group, [=, &s0R] (TShareNode* node) { + if (TDeContext* ctx = node->CtxAs()) { + ctx->Pull.stretch = Min(2.0, Max(0.0, p0 - node->p(Ec) - node->v() + Length) / Length); + ctx->Pull.retardness = Min(1.0, ctx->Pull.stretch); // To avoid s0R jumps + if (ctx->Pull.retardness > 0.0) { // Retard found + s0R += node->s0() * ctx->Pull.retardness; + } + } + }); + gctx->Pull.s0R = s0R; // Just for analytics + + if (s0R > 0.0 && s0R < 1.0) { + // EXPLANATION FOR FORMULA + // If we assume: + // (1) dsi = dd # we pull accounts for the same distance [metre] as non-retarded accounts + // (2) dSi = s0i/s0R * dS # we pull each retarded account for the same distance + // We can conclude that: + // (1) => dSi / s0i = dD / (1 - s0R) + // (2) => dS / s0R = dD / (1 - s0R) + // Therefore: dS = s0R / (1 - s0R) * dD + TEnergy dS = s0R / (1 - s0R) * dD; + + // Pull retards + ApplyTo(group, [=] (TShareNode* node) { + if (TDeContext* ctx = node->CtxAs()) { + if (ctx->Pull.retardness > 0.0) { + TEnergy dSi = node->s0() * ctx->Pull.stretch / s0R * dS; + if (dSi > 0) { // Just to avoid floating-point arithmetic errors + node->Spoil(dSi); + } + } + } + }); + } + } +}; + +// It recursively runs given visitor in each group in tree +template +class TRecursivePuller : public INodeVisitor +{ +private: + TPuller Puller; +public: + template + explicit TRecursivePuller(TArgs... args) + : Puller(args...) + {} + + void Visit(TShareAccount*) override + { + // Do nothing for accounts + } + + void Visit(TShareGroup* node) override + { + node->AcceptInChildren(this); + Puller.Pull(node); + } +}; + +} diff --git a/ydb/library/planner/share/shareplanner.cpp b/ydb/library/planner/share/shareplanner.cpp new file mode 100644 index 000000000000..736b096328d5 --- /dev/null +++ b/ydb/library/planner/share/shareplanner.cpp @@ -0,0 +1,186 @@ +#include "shareplanner.h" +#include +#include +#include +#include +#include +#include "pull.h" +#include "billing.h" +#include "step.h" +#include +#include +#include +#include "history.h" +#include "monitoring.h" + +namespace NScheduling { + +TSharePlanner::TSharePlanner(const TSharePlannerConfig& cfg) + : Root(nullptr) + //, UtilMeter(new TUtilizationMeter()) + , Stepper(new TStepper()) +{ + Configure(cfg); +} + +void TSharePlanner::Configure(const TSharePlannerConfig& cfg) +{ + PLANNER_PROBE(Configure, GetName(), cfg.DebugString()); + Config = cfg; + EPullType pullType = Config.GetPull(); + EBillingType billingType = Config.GetBilling(); + if (pullType == PT_INSENSITIVE && Config.GetModel() != PM_DENSITY) { + // Insensitive puller can be used only with density model + // because it uses some data (p0) from its context. + // Otherwise fallback to strict puller + pullType = PT_STRICT; + } + + TDimless staticTariff = Config.GetStaticTariff(); + if ((billingType == BT_PRESENT_SHARE) + && Config.GetModel() != PM_DENSITY) { + // Present share billing can be used only with density model + // because they use some data (sigma/isigma) from its context. + // Otherwise do not use billing at all + billingType = BT_STATIC; + staticTariff = 1.0; + } + switch (pullType) { + default: // for forward compatibility + case PT_STRICT: Puller.Reset(new TRecursivePuller()); break; + case PT_INSENSITIVE: Puller.Reset(new TRecursivePuller(Config.GetPullLength())); break; + case PT_NONE: Puller.Destroy(); break; + } + switch (Config.GetModel()) { + case PM_STATIC: Model.Reset(new TStaticModel(this)); break; + case PM_MAX: Model.Reset(new TMaxModel(this)); break; + default: // for forward compatibility + case PM_DENSITY: Model.Reset(new TDensityModel(this)); break; + } + switch (billingType) { + default: // for forward compatibility + case BT_STATIC: Billing.Reset(new TStaticBilling(staticTariff)); break; + case BT_PRESENT_SHARE: Billing.Reset(new TPresentShareBilling(Config.GetBillingIsMemoryless())); break; + } +} + +void TSharePlanner::Advance(TEnergy cost, bool wasted) +{ + PLANNER_PROBE(Advance, GetName(), cost, wasted); + Y_ASSERT(cost >= 0); + + // Adjust totals + if (!wasted) { + D_ += cost; + dD_ += cost; + Stats.ResUsed += cost; + } else { + W_ += cost; + dW_ += cost; + Stats.ResWasted += cost; + } + + //UtilMeter->Add(cost, wasted); // Adjust utilization history +} + +void TSharePlanner::Done(TShareAccount* acc, TEnergy cost) +{ + Y_ASSERT(cost >= 0); + acc->Done(cost); + PLANNER_PROBE(Done, GetName(), acc->GetName(), cost, acc->Normalize(cost)); + Advance(cost, false); +} + +void TSharePlanner::Waste(TEnergy cost) +{ + PLANNER_PROBE(Waste, GetName(), cost); + Advance(cost, true); +} + +void TSharePlanner::Commit(bool model) +{ + if (!Puller && !Model && !Billing) { + return; // We are not configured yet + } + if (Puller) { + Root->Accept(Puller.Get()); + } + bool run = false; + if (model && (dD_ > 0 || dW_ > 0)) { + PLANNER_PROBE(Run, GetName()); + if (Model) { + Model->Run(Root); + if (Billing) { + Root->Accept(Billing.Get()); + } + } + Root->Accept(Stepper.Get()); + pdD_ = dD_; + pdW_ = dW_; + dD_ = dW_ = 0; + run = true; + } + PLANNER_PROBE(CommitInfo, GetName(), model, run, PrintInfo()); +} + +void TSharePlanner::OnDetach(TShareNode* node) +{ + if (Model) { + Model->OnDetach(node); + } + node->Detach(); +} + +void TSharePlanner::OnAttach(TShareNode* node, TShareGroup* parent) +{ + node->Attach(this, parent); + if (Model) { + Model->OnAttach(node); + } +} + +TString TSharePlanner::PrintStatus() const +{ + return TStatusPrinter::Print(this); +} + +TString TSharePlanner::PrintTree(bool band, bool model, const TArtParams& art) const +{ + return TTreePrinter::Print(this, band, model, art); +} + +TString TSharePlanner::PrintStats() const +{ + TStringStream ss; + ss << " === PLANNER ===\n" + << " D:" << D_ << "\n" + << " W:" << W_ << "\n" + << " dD:" << dD_ << "\n" + << " dW:" << dW_ << "\n" +// << " Used:" << UtilMeter->Used() << "\n" +// << " Wasted:" << UtilMeter->Wasted() << "\n" +// << " Utilization:" << UtilMeter->Utilization() << "\n" + << "\n" + ; + return ss.Str(); +} + +TString TSharePlanner::PrintInfo(bool status, bool band, bool model, bool stats, const TArtParams& art) const +{ + TStringStream ss; + ss << Endl; + if (status) + ss << PrintStatus(); + if (band || model) + ss << PrintTree(band, model, art); + if (stats) + ss << PrintStats(); + return ss.Str(); +} + +void TSharePlanner::GetStats(TSharePlannerStats& stats) const +{ + stats = Stats; +} + +} diff --git a/ydb/library/planner/share/shareplanner.h b/ydb/library/planner/share/shareplanner.h new file mode 100644 index 000000000000..71b8f8bd1c8c --- /dev/null +++ b/ydb/library/planner/share/shareplanner.h @@ -0,0 +1,332 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "probes.h" +#include "node.h" +#include "account.h" +#include "group.h" +//#include + +namespace NScheduling { + +struct TArtParams { + bool SigmaStretch; + double Scale; + + TArtParams(bool sigmaStretch = true, double scale = 1.0) + : SigmaStretch(sigmaStretch) + , Scale(scale) + {} +}; + +struct TSharePlannerStats { + double ResUsed = 0; + double ResWasted = 0; +}; + +class TSharePlanner { +protected: + // Configuration + TSharePlannerConfig Config; + + TShareGroup* Root = nullptr; // Root must be set by derived class (e.g. TCustomSharePlanner) + TEnergy D_ = 0; // Total work done in system + TEnergy W_ = 0; // Total work wasted in system + TEnergy dD_ = 0; + TEnergy dW_ = 0; + TEnergy pdD_ = 0; + TEnergy pdW_ = 0; + //THolder UtilMeter; + THolder Billing; + THolder Model; + THolder Puller; + THolder Stepper; + + // Statistics and monitoring + TSharePlannerStats Stats; +public: // Configuration + explicit TSharePlanner(const TSharePlannerConfig& cfg = TSharePlannerConfig()); + virtual ~TSharePlanner() {} + const TSharePlannerConfig& Cfg() const { return Config; } + void Configure(const TSharePlannerConfig& cfg); +public: // Accessors + TString GetName() const { return Config.GetName(); } + TShareGroup* GetRoot() { return Root; } + const TShareGroup* GetRoot() const { return Root; } + TEnergy D() const { return D_; } + TEnergy W() const { return W_; } + TEnergy dD() const { return dD_; } + TEnergy dW() const { return dW_; } + TEnergy pdD() const { return dD_; } + TEnergy pdW() const { return dW_; } + //double Utilization() const { return UtilMeter->Utilization(); } +public: // Evolution + void Done(TShareAccount* acc, TEnergy cost); + void Waste(TEnergy cost); + void Commit(bool model = true); +public: // Monitoring + virtual TString PrintStatus() const; + virtual TString PrintTree(bool band, bool model, const TArtParams& art) const; + virtual TString PrintStats() const; + TString PrintInfo(bool status = true, bool band = true, bool model = true, bool stats = true, const TArtParams& art = TArtParams()) const; + void GetStats(TSharePlannerStats& stats) const; +protected: // Implementation + void Advance(TEnergy cost, bool wasted); + virtual void OnDetach(TShareNode* node); + virtual void OnAttach(TShareNode* node, TShareGroup* parent); +}; + +///////////////////////////////// +/// /// +/// Custom planner /// +/// /// +///////////////////////////////// + +// Helpers +template struct TNodeTraits {}; // See specialization below +template +struct TNodeTraits { typedef TAccPtr TPtr; }; +template +struct TNodeTraits { typedef TGrpPtr TPtr; }; + +template , class TGrpPtr = std::shared_ptr> +class TCustomSharePlanner: public TSharePlanner { +public: + typedef THashMap TAccs; + typedef THashMap TGrps; + static_assert(std::is_base_of::value, "TGrp must inherit TShareGroup"); + static_assert(std::is_base_of::value, "TAcc must inherit TShareAccount"); + template using TTraits = TNodeTraits; +protected: + TAccs Accs; // All accounts storage + TGrps Grps; // All groups storage +protected: // To support shared pointers on base class of TAcc/TGrp (not directly of TAcc/TGrp) + static TAcc* Cast(const TAccPtr& node) { return static_cast(&*node); } + static TGrp* Cast(const TGrpPtr& node) { return static_cast(&*node); } + static const TAcc* ConstCast(const TAccPtr& node) { return static_cast(&*node); } + static const TGrp* ConstCast(const TGrpPtr& node) { return static_cast(&*node); } + static TShareAccount* BaseCast(const TAccPtr& node) { return (TShareAccount*)Cast(node); } + static TShareGroup* BaseCast(const TGrpPtr& node) { return (TShareGroup*)Cast(node); } + static TShareAccount* Base(TAcc* node) { return (TShareAccount*)node; } + static TShareGroup* Base(TGrp* node) { return (TShareGroup*)node; } +public: // Configuration + explicit TCustomSharePlanner(const TSharePlannerConfig& cfg = TSharePlannerConfig()) + : TSharePlanner(cfg) + { + Root = Cast(Add(nullptr, "/", 1, 1, 1)); + } + + TGrp* GetRoot() + { + return static_cast(Root); + } + + const TGrp* GetRoot() const + { + return static_cast(Root); + } + + template + typename TTraits::TPtr Add(TGrp* parent, const Args&... args) + { + typename TTraits::TPtr node(new TNode(args...)); + Add(node, parent); + return node; + } + + template + void Add(typename TTraits::TPtr node, TGrp* parent) + { + PLANNER_PROBE(Add, GetName(), parent? parent->GetName(): "NULL", Cast(node)->w0(), Cast(node)->GetName()); + AddImpl(node); + OnAttach(Cast(node), parent); + } + + template + void Delete(TNode* node) + { + PLANNER_PROBE(Delete, GetName(), node->GetName()); + OnDetach(node); + DeleteImpl(node); + } + + void Clear() + { + Root->Clear(); + Accs.clear(); + // Clear Grps, but save Root + for (auto i = Grps.begin(), e = Grps.end(); i != e;) { + if (Cast(i->second) != Root) { + Grps.erase(i++); + } else { + ++i; + } + } + } + + TAccPtr FindAccountByName(const TString& name) + { + auto i = Accs.find(name); + if (i == Accs.end()) { + return TAccPtr(); + } + return i->second; + } + + TGrpPtr FindGroupByName(const TString& name) + { + auto i = Grps.find(name); + if (i == Grps.end()) { + return TGrpPtr(); + } + return i->second; + } + + size_t AccountsCount() const + { + return Accs.size(); + } + + size_t GroupsCount() const + { + return Grps.size(); + } + + const TAccs& Accounts() const + { + return Accs; + } + + const TGrps& Groups() const + { + return Grps; + } + + void GetSensors(TSharePlannerSensors& sensors, bool total, bool accounts, bool groups) const + { + if (accounts) { + for (typename TAccs::const_iterator i = Accs.begin(), e = Accs.end(); i != e; ++i) { + const TShareAccount& node = *Cast(i->second); + TShareNodeSensors* pb = sensors.AddAccounts(); + pb->SetName(node.GetName()); + pb->SetParentName(node.GetParent()? node.GetParent()->GetName(): ""); + node.GetStats().FillSensorsPb(pb); + FillNodeSensors(pb, node); + } + } + if (groups) { + for (typename TGrps::const_iterator i = Grps.begin(), e = Grps.end(); i != e; ++i) { + const TShareGroup& node = *Cast(i->second); + TShareNodeSensors* pb = sensors.AddGroups(); + pb->SetName(node.GetName()); + pb->SetParentName(node.GetParent()? node.GetParent()->GetName(): ""); + FillNodeSensors(pb, node); + } + } + if (accounts && groups) { + sensors.MutableNodes()->MergeFrom(sensors.GetAccounts()); + sensors.MutableNodes()->MergeFrom(sensors.GetGroups()); + } + if (total) { + TShareNodeSensors* pb = sensors.MutableTotal(); + Root->GetStats().FillSensorsPb(pb); + + size_t idleCount = 0; + size_t activeCount = 0; + size_t idleRetardCount = 0; + size_t activeRetardCount = 0; + size_t ac = 0, de = 0, re = 0, ot = 0; + for (typename TAccs::const_iterator i = Accs.begin(), e = Accs.end(); i != e; ++i) { + const TShareAccount& node = *Cast(i->second); + bool active = node.IsActive(); + bool retard = node.IsRetard(); + idleCount += !active && !retard; + activeCount += active && !retard; + idleRetardCount += !active && retard; + activeRetardCount += active && retard; + ac += node.GetStats().Activations; + de += node.GetStats().Deactivations; + re += node.GetStats().Retardations; + ot += node.GetStats().Overtakes; + } + pb->SetIdle(idleCount); + pb->SetActive(activeCount); + pb->SetIdleRetard(idleRetardCount); + pb->SetActiveRetard(activeRetardCount); + pb->SetActivations(ac); + pb->SetDeactivations(de); + pb->SetRetardations(re); + pb->SetOvertakes(ot); + sensors.SetResUsed(Stats.ResUsed); + sensors.SetResWasted(Stats.ResWasted); + //UtilMeter->GetSensors(sensors); + } + } +private: + void AddImpl(TAccPtr node) + { + bool inserted = Accs.insert(typename TAccs::value_type(Cast(node)->GetName(), node)).second; + Y_ABORT_UNLESS(inserted, "duplicate account name '%s'", Cast(node)->GetName().data()); + } + + void AddImpl(TGrpPtr node) + { + bool inserted = Grps.insert(typename TGrps::value_type(Cast(node)->GetName(), node)).second; + Y_ABORT_UNLESS(inserted, "duplicate group name '%s'", Cast(node)->GetName().data()); + } + + void DeleteImpl(TAcc* node) + { + typename TAccs::iterator i = Accs.find(node->GetName()); + Y_ASSERT(i != Accs.end() && "trying to delete unknown/detached account"); + Accs.erase(i); + } + + void DeleteImpl(TGrp* node) + { + typename TGrps::iterator i = Grps.find(node->GetName()); + Y_ASSERT(i != Grps.end() && "trying to delete unknown/detached group"); + Grps.erase(i); + } + + template + void FillNodeSensors(TShareNodeSensors* pb, const T& node) const + { + bool active = node.IsActive(); + bool retard = node.IsRetard(); + pb->SetIdle(!active && !retard); + pb->SetActive(active && !retard); + pb->SetIdleRetard(!active && retard); + pb->SetActiveRetard(active && retard); + pb->SetActivations(node.GetStats().Activations); + pb->SetDeactivations(node.GetStats().Deactivations); + pb->SetRetardations(node.GetStats().Retardations); + pb->SetOvertakes(node.GetStats().Overtakes); + TEnergy Eg = node.ComputeEg(); + pb->SetProficit(node.P(Eg)); + pb->SetLag(node.p(Eg)); + pb->SetDefShare(node.CalcGlobalShare()); + pb->SetGrpDefShare(node.s0()); + pb->SetDefWeight(node.w0()); + pb->SetMaxWeight(node.wmax()); + pb->SetDynamicWeight(node.w()); + if (const IContext* ctx = node.Ctx()) { + ctx->FillSensors(*pb); + } + if (const TShareGroup* grp = dynamic_cast(&node)) { + pb->SetTotalCredit(grp->GetTotalCredit()); + } + } +}; + +} diff --git a/ydb/library/planner/share/stats.h b/ydb/library/planner/share/stats.h new file mode 100644 index 000000000000..cef1878979c0 --- /dev/null +++ b/ydb/library/planner/share/stats.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +namespace NScheduling { + +struct TNodeStats { + ui64 NDone = 0; + ui64 NSpoiled = 0; + TEnergy ResDone = 0; + TEnergy ResSpoiled = 0; + TEnergy MoneySpent = 0; + ui64 Activations = 0; + ui64 Deactivations = 0; + ui64 Retardations = 0; + ui64 Overtakes = 0; + + void Done(TEnergy cost, size_t queries = 1) + { + NDone += queries; + ResDone += cost; + } + + void Spoil(TEnergy cost, size_t queries = 1) + { + NSpoiled += queries; + ResSpoiled += cost; + } + + void Pay(TEnergy bill) + { + MoneySpent += bill; + } + + void FillSensorsPb(TShareNodeSensors* sensors) const + { + sensors->SetNDone(NDone); + sensors->SetNSpoiled(NSpoiled); + sensors->SetResDone(ResDone); + sensors->SetResSpoiled(ResSpoiled); + sensors->SetMoneySpent(MoneySpent); + sensors->SetActivations(Activations); + sensors->SetDeactivations(Deactivations); + } +}; + +} diff --git a/ydb/library/planner/share/step.h b/ydb/library/planner/share/step.h new file mode 100644 index 000000000000..629c0ff7400c --- /dev/null +++ b/ydb/library/planner/share/step.h @@ -0,0 +1,23 @@ +#pragma once + +#include "node_visitor.h" +#include "shareplanner.h" + +namespace NScheduling { + +class TStepper : public INodeVisitor +{ +public: + void Visit(TShareAccount* node) override + { + node->Step(); + } + + void Visit(TShareGroup* node) override + { + node->AcceptInChildren(this); + node->Step(); + } +}; + +} diff --git a/ydb/library/planner/share/ut/all.lwt b/ydb/library/planner/share/ut/all.lwt new file mode 100644 index 000000000000..1f63dd634531 --- /dev/null +++ b/ydb/library/planner/share/ut/all.lwt @@ -0,0 +1,14 @@ +Blocks { + ProbeDesc { Group: "SCHEDULING_SHAREPLANNER_PROVIDER" } + Action { + LogAction { LogTimestamp: true } + PrintToStderrAction {} + } +} +Blocks { + ProbeDesc { Group: "SHAREPLANNER_UT_PROVIDER" } + Action { + LogAction { LogTimestamp: true } + PrintToStderrAction {} + } +} diff --git a/ydb/library/planner/share/ut/shareplanner_ut.cpp b/ydb/library/planner/share/ut/shareplanner_ut.cpp new file mode 100644 index 000000000000..6d918c0bf58b --- /dev/null +++ b/ydb/library/planner/share/ut/shareplanner_ut.cpp @@ -0,0 +1,541 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include +#define SHAREPLANNER_UT_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ + PROBE(TracePrint, GROUPS(), \ + TYPES(TString), \ + NAMES("message")) \ + /**/ + +LWTRACE_DECLARE_PROVIDER(SHAREPLANNER_UT_PROVIDER) +LWTRACE_DEFINE_PROVIDER(SHAREPLANNER_UT_PROVIDER) +LWTRACE_USING(SHAREPLANNER_UT_PROVIDER) + +Y_UNIT_TEST_SUITE(SchedulingSharePlanner) { + using namespace NScheduling; + + class TMyAccount; + class TMyGroup; + class TMyPlanner; + + //////////////////////////// + /// /// + /// Planner for test /// + /// /// + //////////////////////////// + + class TMyAccount: public TShareAccount { + private: + double DemandShare = 1.0; // Max share that account can consume (1.0 - is whole cluster) + public: + TMyAccount(const TString& name, FWeight w, FWeight wmax, TEnergy v = 1) + : TShareAccount(name, w, wmax, v) + {} + TMyPlanner* GetPlanner(); + TMyGroup* GetParent(); + const TMyGroup* GetParent() const; + void Distribute(TEnergy cost); + double GatherDemands(); + double P(); + double C(); + double GetDemandShare() const { return DemandShare; } + void SetDemandShare(double value) { DemandShare = value; } + }; + + class TMyGroup: public TShareGroup { + private: + double DemandShare = 1.0; // Max share that account can consume (1.0 - is whole cluster) + public: + TMyGroup(const TString& name, FWeight w, FWeight wmax, TEnergy v = 1) + : TShareGroup(name, w, wmax, v) + {} + TMyPlanner* GetPlanner(); + TMyGroup* GetParent(); + const TMyGroup* GetParent() const; + void Distribute(TEnergy cost); + double GatherDemands(); + double GetDemandShare() const { return DemandShare; } + void SetDemandShare(double value) { DemandShare = value; } + TEnergy Esum() const + { + TEnergy result = 0; + CUSTOMSHAREPLANNER_FOR(TMyAccount, TMyGroup, node, + result += node->E(); + ); + return result; + } + }; + + class TMyPlanner: public TCustomSharePlanner { + public: + double GetRepaymentRate() const; + double GetMaxRepaymentSpeed() const; + void CheckRepayment(double debt1, double debt2, double dx, double maxErr, const TString& desc = TString()) const; + double GetX() const; + friend class TMyGroup; + friend class TMyAccount; + }; + + /////////////////////////////// + /// /// + /// Accessors /// + /// /// + /////////////////////////////// + + TMyPlanner* TMyAccount::GetPlanner() { return static_cast(Planner); } + TMyGroup* TMyAccount::GetParent() { return static_cast(Parent); } + const TMyGroup* TMyAccount::GetParent() const { return static_cast(Parent); } + + TMyPlanner* TMyGroup::GetPlanner() { return static_cast(Planner); } + TMyGroup* TMyGroup::GetParent() { return static_cast(Parent); } + const TMyGroup* TMyGroup::GetParent() const { return static_cast(Parent); } + + //////////////////////////////// + /// /// + /// Main class for tests /// + /// /// + //////////////////////////////// + + struct TTester { + TMyPlanner Planner; + void Evolve(TEnergy cost, size_t steps); + }; + + /////////////////////////////// + /// /// + /// Scheduler emulation /// + /// /// + /////////////////////////////// + + void TMyAccount::Distribute(TEnergy cost) + { + Planner->Done(this, cost); + } + + struct TDistrItem { + TMyAccount* Account = nullptr; + TMyGroup* Group = nullptr; + double Nordem; // Demands normalized by weight + + TDistrItem(TMyAccount* node) + : Account(node) + , Nordem(node->GetDemandShare() / node->Ctx()->GetWeight()) + {} + + TDistrItem(TMyGroup* node) + : Group(node) + , Nordem(node->GetDemandShare() / node->Ctx()->GetWeight()) + {} + + bool operator<(const TDistrItem& o) const + { + return Nordem < o.Nordem; + } + }; + +#define CUSTOMSHAREPLANNER_FOR_DST(items, node, expr) \ + do { \ + for (auto& item : (items)) { \ + if (auto* node = item.Account) { expr; } \ + else if (auto* node = item.Group) { expr; } \ + } \ + } while (false) \ + /**/ + + void TMyGroup::Distribute(TEnergy cost) + { + TEnergy slot = cost; + FWeight wsum = 0; + TVector Items; + CUSTOMSHAREPLANNER_FOR(TMyAccount, TMyGroup, node, + Items.push_back(TDistrItem(node)); + wsum += node->Ctx()->GetWeight()); + + Sort(Items); + CUSTOMSHAREPLANNER_FOR_DST(Items, node, + node->Distribute(WMaxCut(node->Ctx()->GetWeight(), TEnergy(node->GetDemandShare() * slot), wsum, cost))); + GetPlanner()->Waste(cost); + } + + double TMyAccount::GatherDemands() + { + return DemandShare; + } + + double TMyGroup::GatherDemands() + { + DemandShare = 0.0; + CUSTOMSHAREPLANNER_FOR(TMyAccount, TMyGroup, node, + DemandShare += node->GatherDemands()); + return DemandShare; + } + + void TTester::Evolve(TEnergy cost, size_t steps = 1) + { + Planner.GetRoot()->GatherDemands(); + for (; steps > 0; steps--) { + TEnergy c = cost / steps; + cost -= c; + Planner.GetRoot()->Distribute(c); + Planner.Commit(); + } + } + + /////////////////////////////// + /// /// + /// Measurements /// + /// /// + /////////////////////////////// + + double TMyAccount::P() + { + return E() - double(GetParent()->Esum()) / gs * s0(); + } + + double TMyAccount::C() + { + return fabs(P()); + } + + double TMyPlanner::GetRepaymentRate() const + { + return Config.GetDenseLength() > 0.0 ? 1.0 / Config.GetDenseLength() : 0.0; + } + + double TMyPlanner::GetMaxRepaymentSpeed() const + { + double gR = 128*81*125*7*11*13; // WTF? + return gR / 2; + } + + void TMyPlanner::CheckRepayment(double debt1, double debt2, double dx, double maxErr, const TString& desc) const + { + UNIT_ASSERT(debt1 >= 0 && debt2 >= 0); + double minDebt = 10000; + double debt2_hi_threshold = debt1 * exp(-(GetRepaymentRate()/maxErr) * dx); + double debt2_lo_threshold = debt1 * exp(-(GetRepaymentRate()*maxErr) * dx); + double debt2_target = debt1 * exp(-GetRepaymentRate() * dx); + Y_UNUSED(debt2_target); + bool tooLoDebts = debt2 < minDebt && debt2 < minDebt; + double repaySpeed = debt1 * GetRepaymentRate(); + bool tooHiSpeed = repaySpeed > 0.3 * GetMaxRepaymentSpeed(); + auto tracegen = [=]() { + return Sprintf("CheckRepayment: %s DenseLength=%g speed=%g maxspeed=%g debt1=%g debt2=%g dx=%g -%s%s-> %g < %g < %g", + desc.data(), Config.GetDenseLength(), repaySpeed, GetMaxRepaymentSpeed(), + debt1, debt2, dx, tooLoDebts? "L": "-", tooHiSpeed? "H": "-", + debt2_lo_threshold / debt2_target, debt2 / debt2_target, + debt2_hi_threshold / debt2_target); + }; + if (!tooLoDebts && !tooHiSpeed) { + UNIT_ASSERT_C(debt2 < debt2_hi_threshold && debt2_lo_threshold < debt2, + tracegen()); + } + LWPROBE(TracePrint, tracegen()); + } + + double TMyPlanner::GetX() const + { + return GetRoot()->Esum()/gs; + } + + //////////////////////////// + /// /// + /// Unit tests /// + /// /// + //////////////////////////// + + Y_UNIT_TEST(StartLwtrace) { + NLWTrace::StartLwtraceFromEnv(); + } + + Y_UNIT_TEST(Smoke) { + TTester t; + + TMyAccount* A = t.Planner.Add(t.Planner.GetRoot(), "A", 1000, 2000).get(); + TMyAccount* B = t.Planner.Add(t.Planner.GetRoot(), "B", 1000, 2000).get(); + float N = 100; + TEnergy c = 1.0 / N; + for (int i = 0; i<50; i++) { + t.Planner.Done(A, c); + } + t.Planner.Done(B, 50*c); + t.Planner.Commit(); + } + + Y_UNIT_TEST(Pull) { + TTester t; + + TMyAccount* A = t.Planner.Add(t.Planner.GetRoot(), "A", 2000, 100000, 3).get(); + TMyAccount* B = t.Planner.Add(t.Planner.GetRoot(), "B", 1000, 100000, 2).get(); + TMyAccount* C = t.Planner.Add(t.Planner.GetRoot(), "C", 1000, 100000, 1).get(); + float N = 100; + TEnergy c = 6.0 / N; + t.Planner.Done(A, 10*c); + t.Planner.Done(B, 20*c); + t.Planner.Done(C, 30*c); + t.Planner.Commit(); + for (int i = 0; i<10; i++) { + t.Planner.Done(C, 10*c); + t.Planner.Commit(); + } + for (int i = 0; i<20; i++) { + t.Planner.Done(B, 10*c); + t.Planner.Commit(); + } + for (int i = 0; i<50; i++) { + t.Planner.Done(A, 10*c); + t.Planner.Commit(); + } + } + + Y_UNIT_TEST(RelativeHistorySmoke) { + TStringStream ss; + TTester t; + + TMyAccount* A = t.Planner.Add(t.Planner.GetRoot(), "A", 1000, 100000).get(); + TMyAccount* B = t.Planner.Add(t.Planner.GetRoot(), "B", 2000, 200000).get(); + TMyAccount* C = t.Planner.Add(t.Planner.GetRoot(), "C", 3000, 300000).get(); + + // Create some history + float N = 100; + TEnergy c = 3.0 / N; + t.Planner.Done(A, 10*c); + t.Planner.Done(B, 20*c); + t.Planner.Done(C, 30*c); + t.Planner.Commit(); + THistorySaver::Save(&t.Planner, ss); + + // Change state + t.Planner.Done(A, 30*c); + t.Planner.Done(B, 20*c); + t.Planner.Done(C, 10*c); + t.Planner.Commit(); + + // Load and check history + bool ok = THistoryLoader::Load(&t.Planner, ss); + UNIT_ASSERT(ok); + t.Planner.Commit(); + UNIT_ASSERT(fabs(A->e() - B->e()) < 1e-5); + UNIT_ASSERT(fabs(B->e() - C->e()) < 1e-5); + + // Create another history + t.Planner.Done(A, 25*c); + t.Planner.Done(B, 36*c); + t.Planner.Done(C, 49*c); + t.Planner.Commit(); + ss.Clear(); + THistorySaver::Save(&t.Planner, ss); + double eAB = A->e() - B->e(); + double eBC = B->e() - C->e(); + + // Change state + t.Planner.Done(A, 44*c); + t.Planner.Done(B, 33*c); + t.Planner.Done(C, 22*c); + t.Planner.Commit(); + + // Load and check history + ok = THistoryLoader::Load(&t.Planner, ss); + UNIT_ASSERT(ok); + t.Planner.Commit(); + UNIT_ASSERT(fabs(eAB - (A->e() - B->e())) < 1e-5); + UNIT_ASSERT(fabs(eBC - (B->e() - C->e())) < 1e-5); + } + + Y_UNIT_TEST(RelativeHistoryWithDelete) { + TStringStream ss; + TTester t; + + TMyAccount* A = t.Planner.Add(t.Planner.GetRoot(), "A", 1000, 100000).get(); + TMyAccount* B = t.Planner.Add(t.Planner.GetRoot(), "B", 2000, 200000).get(); + TMyAccount* C = t.Planner.Add(t.Planner.GetRoot(), "C", 3000, 300000).get(); + + // Create some history + float N = 100; + TEnergy c = 3.0 / N; + t.Planner.Done(A, 10*c); + t.Planner.Done(B, 20*c); + t.Planner.Done(C, 30*c); + t.Planner.Commit(); + THistorySaver::Save(&t.Planner, ss); + + // Change state + t.Planner.Done(A, 30*c); + t.Planner.Done(B, 20*c); + t.Planner.Commit(); + + // Delete one account + t.Planner.Delete(C); + t.Planner.Commit(); + + // Load and check history + bool ok = THistoryLoader::Load(&t.Planner, ss); + UNIT_ASSERT(ok); + t.Planner.Commit(); + UNIT_ASSERT(fabs(A->e() - B->e()) < 1e-5); + } + + double denseLengths[] = {1.0, 0.2, 0.4, 0.5, 0.6, 0.9, 0.99, 1.01, 1.1, 1.5, 2.0, 4.0, 8.0, 10.0, 0.0}; + int checks[] = {1, 5, 10, 20, 40, 50, 80}; + int steps = 1000; + + Y_UNIT_TEST(RepaymentConvergence) { + for (const auto& denseLength : denseLengths) { + TTester t; + + TMyAccount* A = t.Planner.Add(t.Planner.GetRoot(), "A", 1000, 100000).get(); + TMyAccount* B = t.Planner.Add(t.Planner.GetRoot(), "B", 1000, 100000).get(); + + TSharePlannerConfig cfg; + cfg.SetDenseLength(denseLength); + t.Planner.Configure(cfg); + LWPROBE(TracePrint, Sprintf("SetDenseLength: %g", denseLength)); + + // Create some history + float N = 100; + TEnergy c = 2.0 / N; + t.Planner.Done(A, 40*c); + t.Planner.Done(B, 10*c); + t.Planner.Commit(); + + // Emulate dynamics + TVector> state; // pairs + for (int i = 0; i < steps; ++i) { + double debt = (A->C() + B->C()) / 2; + double x = t.Planner.GetX(); + state.push_back(std::make_pair(debt, x)); + LWPROBE(TracePrint, Sprintf("i=%d x=%g debt=%g", i, x, debt)); + t.Evolve(c); + } + + // Check convergence + for (const auto& check : checks) { + for (int i = check; i < steps; ++i) { + const auto& s1 = state[i - check]; + const auto& s2 = state[i]; + t.Planner.CheckRepayment(s1.first, s2.first, s2.second - s1.second, 2.0, Sprintf("i1=%d i2=%d", i-check, i)); + } + } + } + } + + Y_UNIT_TEST(RepaymentConvergence4Users) { + for (const auto& denseLength : denseLengths) { + TTester t; + + TMyAccount* A = t.Planner.Add(t.Planner.GetRoot(), "A", 1000, 100000).get(); + TMyAccount* B = t.Planner.Add(t.Planner.GetRoot(), "B", 2000, 200000).get(); + TMyAccount* C = t.Planner.Add(t.Planner.GetRoot(), "C", 3000, 300000).get(); + TMyAccount* D = t.Planner.Add(t.Planner.GetRoot(), "D", 4000, 400000).get(); + + TSharePlannerConfig cfg; + cfg.SetDenseLength(denseLength); + t.Planner.Configure(cfg); + LWPROBE(TracePrint, Sprintf("SetDenseLength: %g", denseLength)); + + // Create some history + float N = 100; + TEnergy c = 4.0 / N; + t.Planner.Done(A, 20*c); + t.Planner.Done(B, 10*c); + t.Planner.Done(C, 40*c); + t.Planner.Done(D, 30*c); + t.Planner.Commit(); + + // Emulate dynamics + TVector> state; // pairs + for (int i = 0; i < steps; ++i) { + double debt = (A->C() + B->C() + C->C() + D->C()) / 2; + double x = t.Planner.GetX(); + state.push_back(std::make_pair(debt, x)); + LWPROBE(TracePrint, Sprintf("i=%d x=%g debt=%g", i, x, debt)); + t.Evolve(c); + } + + // Check convergence + for (const auto& check : checks) { + for (int i = check; i < steps; ++i) { + const auto& s1 = state[i - check]; + const auto& s2 = state[i]; + t.Planner.CheckRepayment(s1.first, s2.first, s2.second - s1.second, 2.0, Sprintf("i1=%d i2=%d", i-check, i)); + } + } + + /* + TMyAccount* accounts[] = {A, B, C, D}; + // Emulate dynamics + typedef THashMap TAccs; + TAccs prev; + double prevx; + for (int i = 0; i < steps; ++i) { + // Check + double x = t.Planner.GetX(); + if (!prev.empty()) { + for (auto acc : accounts) { + //t.Planner.CheckRepayment(prev[acc], acc->P(), x - prevx, 2.0e10, Sprintf("i=%d", i)); + Y_UNUSED(acc); Y_UNUSED(prevx); + } + } + + // Save prev state + for (auto acc : accounts) { + prev[acc] = acc->P(); + } + prevx = x; + + // Emulate + t.Evolve(c); + } + */ + } + } + + Y_UNIT_TEST(OuterGroupInsensitivity) { + for (const auto& denseLength : denseLengths) { + if (denseLength == 0.0) + continue; // This test should not work for discontinuous h-function + TTester t; + + TMyAccount* A = t.Planner.Add(t.Planner.GetRoot(), "A", 1000, 2000).get(); + TMyGroup* G = t.Planner.Add(t.Planner.GetRoot(), "G", 1000, 2000).get(); + TMyAccount* B = t.Planner.Add(G, "B", 1000, 100000).get(); + TMyAccount* C = t.Planner.Add(G, "C", 1000, 100000).get(); + + B->SetDemandShare(0.0); + + TSharePlannerConfig cfg; + cfg.SetDenseLength(denseLength); + t.Planner.Configure(cfg); + LWPROBE(TracePrint, Sprintf("SetDenseLength: %g", denseLength)); + + // Create some history + float N = 100; + TEnergy c = 3.0 / N; + t.Planner.Done(A, 50*c); + t.Planner.Done(B, 25*c); + t.Planner.Done(C, 25*c); + t.Planner.Commit(); + + // Emulate dynamics + int idleSteps = 100; + for (int i = 0; i < steps; ++i) { + UNIT_ASSERT(fabs(A->w() - 1000.0) < 50.0); + UNIT_ASSERT(fabs(G->w() - 1000.0) < 50.0); + LWPROBE(TracePrint, Sprintf("wA=%g wG=%g", A->w(), G->w())); + t.Evolve(c); + if (B->pdS() > 0) { + if (--idleSteps == 0) { + B->SetDemandShare(1.0); + } + } + } + } + } +} diff --git a/ydb/library/planner/share/ut/ya.make b/ydb/library/planner/share/ut/ya.make new file mode 100644 index 000000000000..d3fca68ec026 --- /dev/null +++ b/ydb/library/planner/share/ut/ya.make @@ -0,0 +1,12 @@ +UNITTEST() + +PEERDIR( + library/cpp/threading/future + ydb/library/planner/share +) + +SRCS( + shareplanner_ut.cpp +) + +END() diff --git a/ydb/library/planner/share/utilization.cpp b/ydb/library/planner/share/utilization.cpp new file mode 100644 index 000000000000..9762a5ab65a4 --- /dev/null +++ b/ydb/library/planner/share/utilization.cpp @@ -0,0 +1,71 @@ +#include "utilization.h" + +namespace NScheduling { + +TUtilizationMeter::TUtilizationMeter() +{ + for (unsigned i = 0; i < Slots; i++) { + DoneInSlot[i] = 0; + } + DoneInWindow = 0; + SlotVolume = 0; + CurrentSlot = 0; +} + +void TUtilizationMeter::AddToSlot(TEnergy cost, bool wasted) +{ + SlotVolume += cost; + Y_ASSERT(SlotVolume <= SlotCapacity && "slot overflow"); + if (!wasted) { + DoneInSlot[CurrentSlot] += cost; + DoneInWindow += cost; + } +} + +void TUtilizationMeter::NextSlot() +{ + Y_ASSERT(SlotVolume == SlotCapacity && "previous slot must be filled before moving to the next slot"); + CurrentSlot = (CurrentSlot + 1)%Slots; + DoneInWindow -= DoneInSlot[CurrentSlot]; + DoneInSlot[CurrentSlot] = 0; + SlotVolume = 0; +} + +void TUtilizationMeter::Add(TEnergy cost, bool wasted) +{ + while (SlotVolume + cost > SlotCapacity) { + TEnergy added = SlotCapacity - SlotVolume; + AddToSlot(added, wasted); + cost -= added; + NextSlot(); + } + AddToSlot(cost, wasted); +} + +void TUtilizationMeter::Save(TUtilizationHistory* history) const +{ + for (unsigned i = 0; i < Slots; i++) { + history->AddDoneInSlot(DoneInSlot[i]); + } + history->SetSlotVolume(SlotVolume); + history->SetCurrentSlot(CurrentSlot); +} + +void TUtilizationMeter::Load(const TUtilizationHistory& history) +{ + DoneInWindow = 0; + for (unsigned i = 0; i < Slots; i++) { + DoneInWindow += (DoneInSlot[i] = history.GetDoneInSlot(i)); + } + SlotVolume = history.GetSlotVolume(); + CurrentSlot = history.GetCurrentSlot(); +} + +void TUtilizationMeter::GetSensors(TSharePlannerSensors& sensors) const +{ + sensors.SetResUsedInWindow(double(Used())*1000/gV); + sensors.SetResWastedInWindow(double(Wasted())*1000/gV); + sensors.SetUtilization(Utilization()); +} + +} diff --git a/ydb/library/planner/share/utilization.h b/ydb/library/planner/share/utilization.h new file mode 100644 index 000000000000..3326a5e34a7a --- /dev/null +++ b/ydb/library/planner/share/utilization.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include + +namespace NScheduling { + +class TUtilizationMeter { +private: + static const unsigned Slots = 2*gX; // Number of slots in averaging window + static const TEnergy SlotCapacity = gV/Slots; // Size of a slot in res*sec + TEnergy DoneInSlot[Slots]; + TEnergy DoneInWindow; // Sum of values DoneInSlot[i] for all i + TEnergy SlotVolume; // Done in slot plus wasted in slot + unsigned CurrentSlot; +public: + TUtilizationMeter(); + void Add(TEnergy cost, bool wasted); + void Save(TUtilizationHistory* history) const; + void Load(const TUtilizationHistory& history); +public: // Accessors + inline double Utilization() const { return double(DoneInWindow)/(gV-SlotCapacity+SlotVolume); } + inline TEnergy Used() const { return DoneInWindow; } + inline TEnergy Wasted() const { return (gV-SlotCapacity+SlotVolume) - DoneInWindow; } +public: // Monitoring and sensors + void GetSensors(TSharePlannerSensors& sensors) const; +private: + void AddToSlot(TEnergy cost, bool wasted); + void NextSlot(); +}; + +} diff --git a/ydb/library/planner/share/ya.make b/ydb/library/planner/share/ya.make new file mode 100644 index 000000000000..ea6a5b3c9c60 --- /dev/null +++ b/ydb/library/planner/share/ya.make @@ -0,0 +1,25 @@ +LIBRARY() + +PEERDIR( + ydb/library/planner/share/protos + ydb/library/analytics + library/cpp/lwtrace + library/cpp/monlib/encode/legacy_protobuf/protos +) + +SRCS( + account.cpp + group.cpp + history.cpp + node.cpp + probes.cpp + shareplanner.cpp + # utilization.cpp +) + +END() + +RECURSE( + protos + ut +) diff --git a/ydb/library/planner/ya.make b/ydb/library/planner/ya.make new file mode 100644 index 000000000000..5d9f91986515 --- /dev/null +++ b/ydb/library/planner/ya.make @@ -0,0 +1,3 @@ +RECURSE( + share +) diff --git a/ydb/library/shop/counters.h b/ydb/library/shop/counters.h new file mode 100644 index 000000000000..07e26234eeea --- /dev/null +++ b/ydb/library/shop/counters.h @@ -0,0 +1,107 @@ +#pragma once + +#include "resource.h" + +#include +#include + +namespace NShop { + +/////////////////////////////////////////////////////////////////////////////// + +struct TConsumerCounters { + TAtomic Consumed = 0; // in TCost units (deriv) + TAtomic Borrowed = 0; // in TCost units (deriv) + TAtomic Donated = 0; // in TCost units (deriv) + TAtomic Usage = 0; // in promiles (as_is) +}; + +/////////////////////////////////////////////////////////////////////////////// + +template +class TCountersAggregator { +private: + struct TData { + TConsumerCounters* Counters; + TWeight Weight; + TTag Consumed; + + explicit TData(TCons* consumer) + : Counters(consumer->GetCounters()) + , Weight(consumer->GetWeight()) + , Consumed(consumer->ResetConsumed()) + {} + }; + + TVector Consumers; + TTag ConsumedRest = TTag(); + TTag UsedTotal = TTag(); + TWeight WeightTotal = 0; + +public: + void Add(TCons* consumer) + { + Consumers.emplace_back(consumer); + TData& d = Consumers.back(); + ConsumedRest += d.Consumed; + UsedTotal += d.Consumed * d.Weight; + WeightTotal += d.Weight; + } + + void Apply() + { + if (WeightTotal == 0) { + return; + } + + Sort(Consumers, [] (const TData& lhs, const TData& rhs) { + return lhs.Consumed < rhs.Consumed; + }); + + TTag usagePrev = TTag(); + TTag consumedPrev = TTag(); + size_t consumersRest = Consumers.size(); + TTag fairShare = UsedTotal / TTag(WeightTotal); + for (TData& d : Consumers) { + TTag borrowed = (d.Consumed - fairShare) * d.Weight; + AtomicAdd(d.Counters->Consumed, TAtomicBase(d.Consumed * d.Weight)); + if (borrowed > 0) { + AtomicAdd(d.Counters->Borrowed, TAtomicBase(borrowed)); + } else { + AtomicAdd(d.Counters->Donated, TAtomicBase(-borrowed)); + } + + // EXPLANATION FOR USAGE FORMULA + // If we assume: + // (1) all "vectors" below are sorted by consumption c[k] + // (2) u[k] >= u[k-1] -- u should monotonically increase with k + // (3) u[k] must be bounded by 1 + // (4) the last u[n] must be equal to 1 + // (5) u[k] must be a continuous function of every c[k] + // + // One can proove that the following formula satisfies these requirements: + // c[k] - c[k-1] + // u[k] = u[k-1] + ----------------- (1 - u[k-1]) + // L[k] - c[k-1] + // + // , where L[k] = sum(i=k..n, c[i]) / (n - k + 1) + // L[k] is max possible value for c[k] (due to sort by c[k]) + + if (ConsumedRest > 1e-6) { + TTag avgConsumed = ConsumedRest / consumersRest; + if (avgConsumed > d.Consumed) { + usagePrev += (d.Consumed - consumedPrev) / (avgConsumed - d.Consumed) * (1.0 - usagePrev); + } + } + if (usagePrev > 1.0) { + usagePrev = 1.0; // just to account for fp-errors + } + consumedPrev = d.Consumed; + ConsumedRest -= d.Consumed; + consumersRest--; + AtomicSet(d.Counters->Usage, TAtomicBase(usagePrev * 1000.0)); + } + } +}; + +} diff --git a/ydb/library/shop/estimator.h b/ydb/library/shop/estimator.h new file mode 100644 index 000000000000..3490e2693de1 --- /dev/null +++ b/ydb/library/shop/estimator.h @@ -0,0 +1,192 @@ +#pragma once + +#include "probes.h" +#include + +namespace NShop { + +template +class TMovingAverageEstimator { + static constexpr double NewFactor = double(ReactionNom) / double(ReactionDenom); + static constexpr double OldFactor = 1 - NewFactor; +protected: + double GoalMean; +public: + explicit TMovingAverageEstimator(double average) + : GoalMean(average) + {} + + double GetAverage() const + { + return GoalMean; + } + + void Update(double goal) + { + GoalMean = OldFactor * GoalMean + NewFactor * goal; + } + + TString ToString() const + { + return TStringBuilder() << "{ GoalMean:" << GoalMean << "}"; + } +}; + +template +class TMovingSlrEstimator : public TMovingAverageEstimator { +protected: + static constexpr double NewFactor = double(ReactionNom) / double(ReactionDenom); + static constexpr double OldFactor = 1 - NewFactor; + double FeatureMean; + double FeatureSqMean; + double GoalFeatureMean; +public: + TMovingSlrEstimator(double goal1, double feature1, double goal2, double feature2) + : TMovingAverageEstimator(0.5 * (goal1 + goal2)) + , FeatureMean(0.5 * (feature1 + feature2)) + , FeatureSqMean(0.5 * (feature1 * feature1 + feature2 * feature2)) + , GoalFeatureMean(0.5 * (goal1 * feature1 + goal2 * feature2)) + {} + + double GetEstimation(double feature) const + { + return this->GoalMean + GetSlope() * (feature - FeatureMean); + } + + double GetEstimationAndSlope(double feature, double& slope) const + { + slope = GetSlope(); + return this->GoalMean + slope * (feature - FeatureMean); + } + + double GetSlope() const + { + double disp = FeatureSqMean - FeatureMean * FeatureMean; + if (disp > 1e-10) { + return (GoalFeatureMean - this->GoalMean * FeatureMean) / disp; + } else { + return this->GetAverage(); + } + } + + using TMovingAverageEstimator::Update; + + void Update(double goal, double feature) + { + Update(goal); + FeatureMean = OldFactor * FeatureMean + NewFactor * feature; + FeatureSqMean = OldFactor * FeatureSqMean + NewFactor * feature * feature; + GoalFeatureMean = OldFactor * GoalFeatureMean + NewFactor * goal * feature; + } + + TString ToString() const + { + return TStringBuilder() + << "{ GoalMean:" << this->GoalMean + << ", FeatureMean:" << FeatureMean + << ", FeatureSqMean:" << FeatureSqMean + << ", GoalFeatureMean:" << GoalFeatureMean + << " }"; + } +}; + +struct TAnomalyFilter { + // New value is classified as anomaly if it is `MaxRelativeError' times larger or smaller + float MinRelativeError; + float MaxRelativeError; + + // Token bucket for anomaly filter (1 token = 1 anomaly allowed) + float MaxAnomaliesBurst; // Total bucket capacity + float MaxAnomaliesRate; // Bucket fill rate (number of tokens generated per one Update() calls) + + void Disable() + { + MaxAnomaliesBurst = 0.0f; + } + + TAnomalyFilter(float minRelativeError, float maxRelativeError, float maxAnomaliesBurst, float maxAnomaliesRate) + : MinRelativeError(minRelativeError) + , MaxRelativeError(maxRelativeError) + , MaxAnomaliesBurst(maxAnomaliesBurst) + , MaxAnomaliesRate(maxAnomaliesRate) + {} +}; + +template +class TFilteredMovingSlrEstimator { +protected: + TMovingSlrEstimator Estimator; + float AnomaliesAllowed; // Current token count +public: + TFilteredMovingSlrEstimator(double goal1, double feature1, double goal2, double feature2, ui64 anomaliesAllowed = 0) + : Estimator(goal1, feature1, goal2, feature2) + , AnomaliesAllowed(anomaliesAllowed) + {} + + double GetAverage() const + { + return Estimator.GetAverage(); + } + + double GetEstimation(double feature) const + { + return Estimator.GetEstimation(feature); + } + + double GetEstimationAndSlope(double feature, double& slope) const + { + return Estimator.GetEstimationAndSlope(feature, slope); + } + + double GetSlope() const + { + return Estimator.GetSlope(); + } + + void Update(double goal, double estimation, const TAnomalyFilter& filter) + { + if (Filter(goal, estimation, filter)) { + Estimator.Update(goal); + } + } + + void Update(double goal, double estimation, double feature, const TAnomalyFilter& filter) + { + if (Filter(goal, estimation, filter)) { + Estimator.Update(goal, feature); + } + } + + TString ToString() const + { + return TStringBuilder() + << "{ Estimator:" << Estimator.ToString() + << ", AnomaliesAllowed:" << AnomaliesAllowed + << " }"; + } +private: + bool Filter(double goal, double estimation, const TAnomalyFilter& filter) + { + // Shortcut for turned off mode + if (filter.MaxAnomaliesBurst <= 0.0f || estimation < 1e-3) { + return true; + } + + // Fill bucket + AnomaliesAllowed += filter.MaxAnomaliesRate; + if (AnomaliesAllowed > filter.MaxAnomaliesBurst) { + AnomaliesAllowed = filter.MaxAnomaliesBurst; + } + + // Apply filter + float error = goal / estimation; + if ((error < filter.MinRelativeError || filter.MaxRelativeError < error) && AnomaliesAllowed >= 1.0f) { + AnomaliesAllowed--; // Use 1 token on anomaly that we ignore + return false; + } else { + return true; + } + } +}; + +} diff --git a/ydb/library/shop/flowctl.cpp b/ydb/library/shop/flowctl.cpp new file mode 100644 index 000000000000..e015b9952fb0 --- /dev/null +++ b/ydb/library/shop/flowctl.cpp @@ -0,0 +1,680 @@ +#include "flowctl.h" +#include "probes.h" + +#include +#include + +#include + +namespace NShop { + +LWTRACE_USING(SHOP_PROVIDER); + +TFlowCtlCounters TFlowCtl::FakeCounters; // instantiate static object + +TFlowCtl::TFlowCtl(ui64 initialWindow) + : Window(initialWindow) + , State(Window) + , Counters(&FakeCounters) +{ + UpdateThreshold(); +} + +TFlowCtl::TFlowCtl(const TFlowCtlConfig& cfg, double now, ui64 initialWindow) + : TFlowCtl(initialWindow) +{ + Configure(cfg, now); +} + +void TFlowCtl::Validate(const TFlowCtlConfig& cfg) +{ +#define TLFC_VERIFY(cond, ...) \ + do { \ + if (!(cond)) ythrow yexception() << Sprintf(__VA_ARGS__); \ + } while (false) \ + /**/ + + TLFC_VERIFY(cfg.GetPeriodDuration() > 0, + "PeriodDuration must be positive, got %lf", + (double)cfg.GetPeriodDuration()); + TLFC_VERIFY(cfg.GetMeasurementError() > 0 && cfg.GetMeasurementError() < 1, + "MeasurementError must be in (0, 1) range, got %lf", + (double)cfg.GetMeasurementError()); + TLFC_VERIFY(cfg.GetSteadyLimit() > 0 && cfg.GetSteadyLimit() < 1, + "SteadyLimit must be in (0, 1) range, got %lf", + (double)cfg.GetSteadyLimit()); + TLFC_VERIFY(cfg.GetHistorySize() > 1, + "HistorySize must be at least 2, got %ld", + (long)cfg.GetHistorySize()); + TLFC_VERIFY(cfg.GetMinCountInFly() > 0, + "MinCountInFly must be at least 1, got %ld", + (long)cfg.GetMinCountInFly()); + TLFC_VERIFY(cfg.GetMinCostInFly() > 0, + "MinCostInFly must be at least 1, got %ld", + (long)cfg.GetMinCostInFly()); + TLFC_VERIFY(cfg.GetMultiplierLimit() > 0 && cfg.GetMultiplierLimit() < 1, + "MultiplierLimit must be in (0, 1) range, got %lf", + (double)cfg.GetMultiplierLimit()); + +#undef TLFC_VERIFY +} + +void TFlowCtl::Configure(const TFlowCtlConfig& cfg, double now) +{ + if (cfg.GetFixedWindow()) { + Window = cfg.GetFixedWindow(); + } + Window = Max(Window, cfg.GetMinCostInFly()); + State = Max(State, (double)cfg.GetMinCostInFly()); + UpdateThreshold(); + if (Period.empty()) { // if brand new TFlowCtl + Cfg = cfg; + Period.resize(Cfg.GetHistorySize()); + ConfigureTime = now; + SlowStart = Cfg.GetSlowStartLimit(); + AdvanceTime(now, false); + } else { // if reconfiguration + AdvanceTime(now, false); + + // Pretend that current period was started with new config + Cfg = cfg; + TPeriod* cp = CurPeriod(); + cp->PeriodDuration = Cfg.GetPeriodDuration(); + ConfigureTime = cp->StartTime; + ConfigurePeriodId = CurPeriodId; + + // Create new history + TVector oldPeriod; + oldPeriod.swap(Period); + Period.resize(Cfg.GetHistorySize()); + + // Rearrange old history into new one using new modulo + // and fill old periods with zeros if history was enlarged + ui64 id = CurPeriodId; + for (ui64 j = Min(Period.size(), oldPeriod.size()); j > 0 && id != ui64(-1); j--, id--) { + *GetPeriod(id) = oldPeriod[id % oldPeriod.size()]; + } + for (ui64 j = oldPeriod.size(); j < Period.size() && id != ui64(-1); j++, id--) { + InitPeriod(id, 0); + } + } + SetWindow(Window); // update CostCap + LWPROBE(Configure, GetName(), Now, cfg.ShortDebugString()); +} + +bool TFlowCtl::IsOpen() const +{ + return Cfg.GetDisabled() || CountInFly < Cfg.GetMinCountInFly() || CostInFly < Window; +} + +bool TFlowCtl::IsOpenForMonitoring() const +{ + return Cfg.GetDisabled() || CostInFly < WindowCloseThreshold; +} + +enum class EMode { + Zero = 0, + Restart = 1, + Unused = 2, + SlowStart = 3, + Optimum = 4, + Unsteady = 5, + Undispersive = 6, + WindowInc = 7, + WindowDec = 8, + Overshoot = 9, + CatchUp = 10, + FixedWindow = 11, + FixedLatency = 12 +}; + +void TFlowCtl::Arrive(TFcOp& op, ui64 estcost, double now) +{ + TPeriod* p = AdvanceTime(now, true); + p->AccumulateClosedTime(now, IsOpen()); + + op.EstCost = estcost; + op.UsedCost = Min(estcost, CostCap); + op.ArriveTime = Now; + op.PeriodId = CurPeriodId; + op.OpId = ++LastOpId; + + p->CountInFly++; + p->CostInFly += op.EstCost; + + LWPROBE(Arrive, GetName(), op.OpId, op.PeriodId, Now, + op.EstCost, op.UsedCost, CountInFly, CostInFly, Window); + + CountInFly++; + CostInFly += op.UsedCost; + if (KleinrockControlEnabled() && CountInFly <= Cfg.GetMinCountInFly() && State < CostInFly) { + ui64 minCost = RealCostMA * Cfg.GetMinCountInFly(); + if (State < minCost) { + SetWindow(minCost); + State = Window; + UpdateThreshold(); + } + } + + AtomicIncrement(Counters->CountArrived); + AtomicAdd(Counters->CostArrived, op.EstCost); +} + +void TFlowCtl::Depart(TFcOp& op, ui64 realcost, double now) +{ + Y_ABORT_UNLESS(Now >= op.ArriveTime); + Y_ABORT_UNLESS(CurPeriodId >= op.PeriodId); + + TPeriod* p = AdvanceTime(now, true); + p->AccumulateClosedTime(now, IsOpen()); + + CountInFly--; + CostInFly -= op.UsedCost; + + // Weight is coef of significance of given op in period performance metrics + // we use 1, 1/2, 1/3... weight if ops was execute during 1, 2, 3... periods + double weight = 1.0 / (1 + CurPeriodId - op.PeriodId); + + double latency = Now - op.ArriveTime; + LatencyMA = latency * Cfg.GetLatencyMACoef() + + LatencyMA * (1 - Cfg.GetLatencyMACoef()); + RealCostMA = realcost * Cfg.GetRealCostMACoef() + + RealCostMA * (1 - Cfg.GetRealCostMACoef()); + + LWPROBE(Depart, GetName(), op.OpId, op.PeriodId, Now, + op.EstCost, op.UsedCost, CountInFly, CostInFly, realcost, + LatencyMA * 1000, weight, Window); + + LWPROBE(DepartLatency, GetName(), op.OpId, op.PeriodId, Now, + latency * 1000, LatencyMA * 1000, RealCostMA, op.ArriveTime); + + // Iterate over all periods that intersect execution of operation + if (op.PeriodId + Cfg.GetHistorySize() > CurPeriodId) { + p = GetPeriod(op.PeriodId); + p->CountInFly--; + p->CostInFly -= op.EstCost; + } else { + p = LastPeriod(); + AtomicIncrement(Counters->CountDepartedLate); + AtomicAdd(Counters->CostDepartedLate, realcost); + } + TPeriod* curPeriod = CurPeriod(); + while (true) { + p->WeightSum += weight; + p->RealCostSum += weight * realcost; + p->EstCostSum += weight * op.EstCost; + p->LatencySum += weight * LatencyMA; + p->LatencySqSum += weight * LatencyMA * LatencyMA; + if (p == curPeriod) { + break; + } + p = NextPeriod(p); + } + + AtomicIncrement(Counters->CountDeparted); + AtomicAdd(Counters->CostDeparted, realcost); +} + +void TFlowCtl::Abort(TFcOp& op) +{ + CountInFly--; + CostInFly -= op.UsedCost; + + // Abort op in period it arrived (if it is not forgotten yet) + if (op.PeriodId + Cfg.GetHistorySize() > CurPeriodId) { + TPeriod* p = GetPeriod(op.PeriodId); + p->CountInFly--; + p->CostInFly -= op.EstCost; + } + + AtomicIncrement(Counters->CountAborted); + AtomicAdd(Counters->CostAborted, op.EstCost); + + LWPROBE(Abort, GetName(), op.OpId, op.PeriodId, Now, + op.EstCost, op.UsedCost, CountInFly, CostInFly); +} + +TFlowCtl::EStateTransition TFlowCtl::ConfigureST(const TFlowCtlConfig& cfg, double now) +{ + bool wasOpen = IsOpen(); + Configure(cfg, now); + return CreateST(wasOpen, IsOpen()); +} + +TFlowCtl::EStateTransition TFlowCtl::ArriveST(TFcOp& op, ui64 estcost, double now) +{ + bool wasOpen = IsOpen(); + Arrive(op, estcost, now); + return CreateST(wasOpen, IsOpen()); +} + +TFlowCtl::EStateTransition TFlowCtl::DepartST(TFcOp& op, ui64 realcost, double now) +{ + bool wasOpen = IsOpen(); + Depart(op, realcost, now); + return CreateST(wasOpen, IsOpen()); +} + +TFlowCtl::EStateTransition TFlowCtl::AbortST(TFcOp& op) +{ + bool wasOpen = IsOpen(); + Abort(op); + return CreateST(wasOpen, IsOpen()); +} + +void TFlowCtl::UpdateCounters() +{ + AdvanceMonitoring(); + AtomicSet(Counters->CostInFly, CostInFly); + AtomicSet(Counters->CountInFly, CountInFly); + AtomicSet(Counters->Window, Window); +} + +void TFlowCtl::SetWindow(ui64 window) +{ + Window = window; + CostCap = Max(Cfg.GetMinCostInFly(), ui64(ceil(double(window) * Cfg.GetCostCapToWindow()))); +} + +TFlowCtl::EStateTransition TFlowCtl::CreateST(bool wasOpen, bool isOpen) +{ + if (wasOpen) { + if (!isOpen) { + LWPROBE(TransitionClosed, GetName(), Now); + return Closed; + } + } else { + if (isOpen) { + LWPROBE(TransitionOpened, GetName(), Now); + return Opened; + } + } + return None; +} + +TFlowCtl::TPeriod* TFlowCtl::AdvanceTime(double now, bool control) +{ + AdvanceMonitoring(); + + LWPROBE(AdvanceTime, GetName(), Now, now); + + if (Now == 0) { // Initialization on first call + Now = now; + InitPeriod(); + } + + if (Now < now) { + Now = now; + } + + TPeriod* cp = CurPeriod(); + double end = cp->StartTime + cp->PeriodDuration; + if (end < Now) { + // Take into account zero periods (skipped; no arrival/departure) + // TODO: You should test this!! look in debugger!! better write UT + size_t skipPeriods = (Now - end) / Cfg.GetPeriodDuration(); + size_t addPeriods = Min(skipPeriods, Period.size()); + CurPeriodId += skipPeriods - addPeriods; + while (addPeriods-- > 0) { + CurPeriodId++; + cp = InitPeriod(); + } + + // Adjust window before starting new period, because we want have as + // much historic information as possible, including oldest period + if (control) { + Control(); + } + + // Start period with new value of Window + CurPeriodId++; + cp = InitPeriod(); + } + + return cp; +} + +TFlowCtl::TPeriod* TFlowCtl::GetPeriod(ui64 periodId) +{ + Y_ABORT_UNLESS(!Period.empty(), "TFlowCtl must be configured"); + return &Period[periodId % Cfg.GetHistorySize()]; +} + +TFlowCtl::TPeriod* TFlowCtl::CurPeriod() +{ + return GetPeriod(CurPeriodId); +} + +TFlowCtl::TPeriod* TFlowCtl::LastPeriod() +{ + if (CurPeriodId < Cfg.GetHistorySize()) { + return &Period[0]; + } else { + return GetPeriod(CurPeriodId + 1); + } +} + +TFlowCtl::TPeriod* TFlowCtl::NextPeriod(TFlowCtl::TPeriod* p) +{ + p++; + if (p == &Period[0] + Cfg.GetHistorySize()) { + p = &Period[0]; + } + return p; +} + +TFlowCtl::TPeriod* TFlowCtl::InitPeriod(ui64 periodId, ui64 window) +{ + TPeriod* cp = GetPeriod(periodId); + *cp = TPeriod(); + cp->PeriodId = periodId; + cp->StartTime = ConfigureTime + + (periodId - ConfigurePeriodId) * Cfg.GetPeriodDuration(); + cp->PeriodDuration = Cfg.GetPeriodDuration(); + cp->Window = window; + return cp; +} + +TFlowCtl::TPeriod* TFlowCtl::InitPeriod() +{ + TPeriod* cp = InitPeriod(CurPeriodId, Window); + LWPROBE(InitPeriod, GetName(), CurPeriodId, Now, Window); + return cp; +} + +bool TFlowCtl::KleinrockControlEnabled() +{ + return !Cfg.GetFixedWindow() && Cfg.GetFixedLatencyMs() <= 0.0; +} + +void TFlowCtl::Control() +{ + // Iterate over completed periods + TPeriod* p = LastPeriod(); + TPeriod* curPeriod = CurPeriod(); + double costSumError = 0; + double weightSumError = 0; + double latencySumError = 0; + double latencySqSumError = 0; + ui64 goodPeriods = 0; + ui64 badPeriods = 0; + ui64 zeroPeriods = 0; + double rthroughputSum = 0; + double ethroughputSum = 0; + double latencyAvgSum = 0; + double rthroughputSqSum = 0; + double ethroughputSqSum = 0; + double latencyAvgSqSum = 0; + double rthroughputMin = -1.0; + double rthroughputMax = -1.0; + double ethroughputMin = -1.0; + double ethroughputMax = -1.0; + double latencyAvgMin = -1.0; + double latencyAvgMax = -1.0; + // Note that curPeriod is not included, because it can have or not have + // higher error, and could lead to `goodPeriods' blinking + for (; p != curPeriod; p = NextPeriod(p)) { + // It is a good approximation to think that op will continue it's + // execution for as long as it already executes, so it's weight will be + // about twice less than if op will complete in current period + ui64 periodsToComplete = 2*(CurPeriodId - p->PeriodId); + double weightEst = 1.0 / periodsToComplete; + double latencyEst = p->PeriodDuration * periodsToComplete; + + // Error accumulates over uncompleted ops of periods before `p' + costSumError += p->CostInFly * weightEst; + weightSumError += p->CountInFly * weightEst; + latencySumError += p->CountInFly * weightEst * latencyEst; + latencySqSumError += p->CountInFly * weightEst * latencyEst * latencyEst; + + // Take in-fly operations into account to increase accuracy + double rcostSum = p->RealCostSum + costSumError; + double ecostSum = p->EstCostSum + costSumError; + double weightSum = p->WeightSum + weightSumError; + double latencySum = p->LatencySum + latencySumError; + double latencySqSum = p->LatencySqSum + latencySqSumError; + + LWPROBE(PeriodStats, GetName(), CurPeriodId, Now, p->PeriodId, + rcostSum, costSumError, + weightSum, weightSumError, + latencySum, latencySumError); + if (rcostSum == 0 || weightSum == 0) { + zeroPeriods++; + } else if (costSumError / rcostSum < Cfg.GetMeasurementError() && // cost + weightSumError / weightSum < Cfg.GetMeasurementError() // count + ) { + // Period performace metrics at best we can estimate for now + double latencyAvg = latencySum / weightSum; + double latencyErr = sqrt(latencySqSum / weightSum - latencyAvg * latencyAvg); + double rthroughput = rcostSum / p->PeriodDuration; + double ethroughput = ecostSum / p->PeriodDuration; + + LWPROBE(PeriodGood, GetName(), CurPeriodId, Now, p->PeriodId, + goodPeriods, rthroughput, ethroughput, latencyAvg, latencyErr); + + // Aggregate performance metrics over all "good" periods + goodPeriods++; + latencyAvgSum += latencyAvg; + rthroughputSum += rthroughput; + ethroughputSum += ethroughput; + latencyAvgSqSum += latencyAvg * latencyAvg; + rthroughputSqSum += rthroughput * rthroughput; + ethroughputSqSum += ethroughput * ethroughput; + if (rthroughputMax < 0) { // For first pass + rthroughputMin = rthroughputMax = rthroughput; + ethroughputMin = ethroughputMax = ethroughput; + latencyAvgMin = latencyAvgMax = latencyAvg; + } else { + rthroughputMin = Min(rthroughput, rthroughputMin); + rthroughputMax = Max(rthroughput, rthroughputMax); + ethroughputMin = Min(ethroughput, ethroughputMin); + ethroughputMax = Max(ethroughput, ethroughputMax); + latencyAvgMin = Min(latencyAvg, latencyAvgMin); + latencyAvgMax = Max(latencyAvg, latencyAvgMax); + } + } else { // Not enough measurement accuracy + badPeriods++; + } + } + + AtomicAdd(Counters->BadPeriods, badPeriods); + AtomicAdd(Counters->GoodPeriods, goodPeriods); + AtomicAdd(Counters->ZeroPeriods, zeroPeriods); + LWPROBE(Measurement, GetName(), CurPeriodId, Now, + badPeriods, goodPeriods, zeroPeriods); + + EMode mode = EMode::Zero; // Just for monitoring + if (KleinrockControlEnabled() && goodPeriods == 0) { + if (zeroPeriods == 0) { + mode = EMode::Restart; // Probably we have huge window, restart + SetWindow(Cfg.GetMinCostInFly()); + State = Window; + SlowStart = Cfg.GetSlowStartLimit(); + // NOTE: PeriodDuration maybe lower than latency. + // NOTE: If this is the case try to manually choose PeriodDuration + // NOTE: to be much higher (x20) than average latency + } else { + mode = EMode::Unused; // Looks like utilization is zero mainly, wait + } + } else { + double L = latencyAvgSum / goodPeriods; + double T = rthroughputSum / goodPeriods; + double ET = ethroughputSum / goodPeriods; + double dT = sqrt(rthroughputSqSum / goodPeriods - T*T); + double dET = sqrt(ethroughputSqSum / goodPeriods - ET*ET); + double dL = sqrt(latencyAvgSqSum / goodPeriods - L*L); + + LWPROBE(Throughput, GetName(), CurPeriodId, Now, + T, rthroughputMin, rthroughputMax, T-dT, T+dT, dT/T); + LWPROBE(EstThroughput, GetName(), CurPeriodId, Now, + ET, ethroughputMin, ethroughputMax, ET-dET, ET+dET, dET/ET); + LWPROBE(Latency, GetName(), CurPeriodId, Now, + L*1000.0, latencyAvgMin*1000.0, latencyAvgMax*1000.0, (L-dL)*1000.0, (L+dL)*1000.0, dL/L); + + // Process variable = abs latency error over abs throughput error + double pv; + if (dT/T < 1e-6) { + pv = 1e6; + } else { + pv = (dL/L) / (dT/T); // We want pv -> 1 + } + + // Error. Maps pv=0 -> e=1, pv=1 -> e=0 and pv=+inf -> e=-1 + // Intention is to make throughput and latency symetric for controller + double err = (pv < 1.0? 1.0 - pv: 1.0/pv - 1.0); // We want e -> 0 + + if (!Cfg.GetFixedWindow() && Cfg.GetFixedLatencyMs() <= 0.0 && SlowStart) { + mode = EMode::SlowStart; // In SlowStart mode we always multiply window by max allowed coef + State *= 1.0 + Cfg.GetMultiplierLimit(); + SetWindow(State); + SlowStart--; + } else { + // Exclude NaNs and zeros + if (dL >= 0 && L > 0 && dT >= 0 && T > 0 && pv >= 0) { + AtomicSet(Counters->Throughput, T * 1e6); + AtomicSet(Counters->Latency, L * 1e6); + AtomicSet(Counters->ThroughputDispAbs, dT/T * 1e6); + AtomicSet(Counters->LatencyDispAbs, dL/L * 1e6); + LWPROBE(Slowdown, GetName(), CurPeriodId, Now, Slowdown); + if (Slowdown) { + mode = EMode::Optimum; // Just wait if slowdown enabled + Slowdown--; + } else { + if (dL/L > Cfg.GetSteadyLimit() || + dT/T > Cfg.GetSteadyLimit()) + { + mode = EMode::Unsteady; // Too unsteady, wait + } else { + if (dL/L < Cfg.GetMeasurementError() && + dT/T < Cfg.GetMeasurementError()) + { // Dispersions are lower than measurement accuracy + mode = EMode::Undispersive; + } else { + // Slowdown if we are close to setpoint (optimum) + if (Cfg.GetSlowdownLimit() && + 0.5 / Cfg.GetSlowdownLimit() < fabs(err) && + fabs(err) < 0.5) + { + Slowdown = Min( + Cfg.GetSlowdownLimit(), + ui64(1.0/fabs(err))); + } + + // Make controlling decision + // e-values closer to 0 lead to finer control + // due to e-square term + double ratio = 1.0 + Cfg.GetMultiplierLimit() * + err * err * (pv < 1? 1.0: -1.0); + double target = T * L * ratio; + + // System reaction has lag. Real position is T*L. + // In steady state with full window, Little's law: + // T*L = Window + // So we have two exceptions: + // - not full window due to underutilization + // - not steady state due to reaction lag + if (target > 0.5 * State) { + mode = ratio > 1.0? EMode::WindowInc: EMode::WindowDec; + State *= ratio; + } else if (target > Cfg.GetMinCostInFly() + && ratio < 1.0) + { + mode = EMode::Overshoot; // Too large window + State *= 1.0 - Cfg.GetMultiplierLimit(); + } else { + mode = EMode::CatchUp; // Catching up, wait + } + + // Apply boundary conditions + if (State < Cfg.GetMinCostInFly()) { + State = Cfg.GetMinCostInFly(); + } + + LWPROBE(Control, GetName(), CurPeriodId, Now, + pv, err, ratio, target); + } + } + } + } + // Set window to osscilate near current state + double disp = Cfg.GetMeasurementError() * 2.0; + double mult = 1.0 - disp + + ((CurPeriodId * 2 / Cfg.GetHistorySize() / 3) % 2) * disp; + SetWindow(mult * State); + if (Window < Cfg.GetMinCostInFly()) { + SetWindow(Cfg.GetMinCostInFly()); + } + if (Cfg.GetFixedWindow()) { + mode = EMode::FixedWindow; // Fixed window mode + SetWindow(Cfg.GetFixedWindow()); + State = Window; + } else if (Cfg.GetFixedLatencyMs() > 0.0) { + mode = EMode::FixedLatency; // Fixed latency mode + SetWindow(Max( + Cfg.GetMinCostInFly(), + Cfg.GetFixedLatencyMs() * ethroughputMax / 1000.0)); + State = Window; + } + LWPROBE(Window, GetName(), CurPeriodId, Now, Window); + } + UpdateThreshold(); + } + + switch (mode) { +#define TLFC_MODE(name) \ + case EMode::name: AtomicIncrement(Counters->Mode ## name); break + TLFC_MODE(Zero); + TLFC_MODE(Restart); + TLFC_MODE(Unused); + TLFC_MODE(SlowStart); + TLFC_MODE(Optimum); + TLFC_MODE(Unsteady); + TLFC_MODE(Undispersive); + TLFC_MODE(WindowInc); + TLFC_MODE(WindowDec); + TLFC_MODE(Overshoot); + TLFC_MODE(CatchUp); + TLFC_MODE(FixedWindow); + TLFC_MODE(FixedLatency); + } +#undef TLFC_MODE + LWPROBE(State, GetName(), CurPeriodId, Now, (ui64)mode, State); +} + +void TFlowCtl::AdvanceMonitoring() +{ + if (LastEvent == 0) { + LastEvent = GetCycleCount(); + } + ui64 now = GetCycleCount(); + ui64 elapsed = 0; + if (LastEvent < now) { + elapsed = now - LastEvent; + LastEvent = now; + } + ui64 elapsedUs = CyclesToDuration(elapsed).MicroSeconds(); + bool isIdle = CountInFly == 0; + bool isOpen = IsOpenForMonitoring(); + if (!LastIdle && isIdle) { + AtomicIncrement(Counters->IdleCount); + } + if (LastOpen && !isOpen) { + AtomicIncrement(Counters->CloseCount); + } + if (isIdle) { + AtomicAdd(Counters->IdleUs, elapsedUs); + } else if (isOpen) { + AtomicAdd(Counters->OpenUs, elapsedUs); + } else { + AtomicAdd(Counters->ClosedUs, elapsedUs); + } + LastIdle = isIdle; + LastOpen = isOpen; +} + +void TFlowCtl::UpdateThreshold() +{ + WindowCloseThreshold = Window * UtilizationThreshold / 100; +} + +} diff --git a/ydb/library/shop/flowctl.h b/ydb/library/shop/flowctl.h new file mode 100644 index 000000000000..76c1888e77d7 --- /dev/null +++ b/ydb/library/shop/flowctl.h @@ -0,0 +1,213 @@ +#pragma once + +#include + +#include + +#include +#include +#include + +namespace NShop { + +struct TFlowCtlCounters { + TAtomic CostArrived = 0; // Total estimated cost arrived + TAtomic CountArrived = 0; // Total ops arrived + TAtomic CostDeparted = 0; // Total real cost departed + TAtomic CountDeparted = 0; // Total ops departed + TAtomic CostDepartedLate = 0; // Total real cost departed after history forget it + TAtomic CountDepartedLate = 0; // Total ops departed after history forget it + TAtomic CostAborted = 0; // Total estimated cost aborted + TAtomic CountAborted = 0; // Total ops aborted + TAtomic CostInFly = 0; // Currently estimated cost in flight + TAtomic CountInFly = 0; // Currently ops in flight + + TAtomic Window = 0; // Current window size in estimated cost units + TAtomic IdleCount = 0; // Total switches to idle state (zero in-flight) + TAtomic CloseCount = 0; // Total switches to closed state (ecost in-flight >= 80% Window) + TAtomic IdleUs = 0; // Total microseconds in idle state + TAtomic OpenUs = 0; // Total microseconds in open state + TAtomic ClosedUs = 0; // Total microseconds in closed state + + // On every period boundary we analyze history up to `Cfg.HistorySize' periods into past + // and based on amount and cost of still-in-fly requests we can estimate error + // of throughtput and latency measurements, and than control it based on `Cfg.MeasurementError' + // NOTE: one period is counted multiple times (Cfg.HistorySize) and can be classified differently + TAtomic BadPeriods = 0; // Total periods with too high measurement error + TAtomic GoodPeriods = 0; // Total periods with acceptable measurment error + TAtomic ZeroPeriods = 0; // Total periods w/o requests (not crossed by any request) + + // Performance metrics + // Measured based on good period (up to `Cfg.HistorySize') + TAtomic Throughput = 0; // Measured throughput (micro-realcost per second) + TAtomic Latency = 0; // Measured latency (microseconds) + TAtomic ThroughputDispAbs = 0; // Measured throughput variability (ppm) + TAtomic LatencyDispAbs = 0; // Measured latency variability (ppm) + + // On every period flow control operates in one on the following mode: + TAtomic ModeZero = 0; // Undefined + TAtomic ModeRestart = 0; // Restart with minimal window due to every period being bad + TAtomic ModeUnused = 0; // Only zero and/or bad periods (just wait, probably idle) + TAtomic ModeSlowStart = 0; // Window exponential growth after Restart + TAtomic ModeOptimum = 0; // Optimal operating point (Kleinrock point) + TAtomic ModeUnsteady = 0; // Too high variability of latency and/or throughput + TAtomic ModeUndispersive = 0; // Too low variability of latency and throughput + TAtomic ModeWindowInc = 0; // Increase window + TAtomic ModeWindowDec = 0; // Decrease window + TAtomic ModeOvershoot = 0; // Too large window, decrease as fast as allowed + TAtomic ModeCatchUp = 0; // Catching up, wait + + // Do not apply smart flowctl, use `Cfg.FixedWindow' + TAtomic ModeFixedWindow = 0; + + // Use max measured estimated cost throughput ETmax (estcost per second) + // to compute `Window = ETmax * Cfg.FixedLatencyMs' + TAtomic ModeFixedLatency = 0; +}; + + +struct TFcOp { + ui64 EstCost = 0; // Estimation of cost; should be known on arrive + ui64 UsedCost = 0; // Min(EstCost, Window * Cfg.CostCapToWindow) + double ArriveTime = 0; + ui64 PeriodId = 0; + ui64 OpId = 0; + + bool HasArrived() const + { + return OpId != 0; + } + + void Reset() + { + OpId = 0; + } +}; + +class TFlowCtl : public TAtomicRefCount { +public: + enum EStateTransition { + None = 0, + Closed = 1, + Opened = 2 + }; +private: + TFlowCtlConfig Cfg; + TString Name; + + // Flow state + ui64 Window; + ui64 CostCap; + ui64 CostInFly = 0; + ui64 CountInFly = 0; + ui64 CurPeriodId = 0; + ui64 LastOpId = 0; + + // Performance measurements + struct TPeriod { + // Constants during period + ui64 PeriodId = 0; + double StartTime = 0; + double PeriodDuration = 0; + ui64 Window = 0; // Window used for period + + // Intermediate and accumulated values + ui64 CountInFly = 0; // Number of in fly ops arrived during period + ui64 CostInFly = 0; // In-fly-cost of arrived during period operations + double WeightSum = 0; // Total weight of executed operations + double RealCostSum = 0; // Weighted sum of executed operations' real cost + double EstCostSum = 0; // Weighted sum of executed operations' estimated cost + double LatencySum = 0; // Weighted sum of executed operations' latencies + double LatencySqSum = 0; // Weighted sum of executed operations' latency squares + + // Window utilization + double LastEventTime = 0; + double TotalClosedTime = 0; + void AccumulateClosedTime(double now, bool wasOpen) { + if (!LastEventTime) { + LastEventTime = StartTime; + } + double end = StartTime + PeriodDuration; + if (now > end) { + now = end; + } + if (!wasOpen) { + TotalClosedTime += now - LastEventTime; + } + LastEventTime = now; + } + }; + TVector Period; // Cyclic buffer for last periods + double Now = 0; + double ConfigureTime = 0; + double ConfigurePeriodId = 0; + double LatencyMA = 0; + double RealCostMA = 0; + + // Controller + double State; + ui64 Slowdown = 0; + ui64 SlowStart = 0; + + // Monitoring + TFlowCtlCounters* Counters; + static TFlowCtlCounters FakeCounters; + ui64 LastEvent = 0; + bool LastOpen = true; + bool LastIdle = true; + + // If `UtilizationThreshold' share of Window is used (in-fly) than + // for monitoring we count window as closed. This is done to provide meaningful + // `ClosedUs' counter. Note that if we count really !IsOpen() time + // we'd get metric that depend on reaction time (just opened -> closed again) + static const ui64 UtilizationThreshold = 80; // percent + ui64 WindowCloseThreshold; + +public: + // Configuration + explicit TFlowCtl(ui64 initialWindow = 1); + TFlowCtl(const TFlowCtlConfig& cfg, double now, ui64 initialWindow = 1); + // You'd better validate config before Configure() to avoid troubles + static void Validate(const TFlowCtlConfig& cfg); + void Configure(const TFlowCtlConfig& cfg, double now); + + // Processing + bool IsOpen() const; + bool IsOpenForMonitoring() const; + void Arrive(TFcOp& op, ui64 estcost, double now); + void Depart(TFcOp& op, ui64 realcost, double now); + void Abort(TFcOp& op); + + // Adapters with state transitions (just sugar) + EStateTransition ConfigureST(const TFlowCtlConfig& cfg, double now); + EStateTransition ArriveST(TFcOp& op, ui64 estcost, double now); + EStateTransition DepartST(TFcOp& op, ui64 realcost, double now); + EStateTransition AbortST(TFcOp& op); + + // Acessors + const TFlowCtlConfig& GetConfig() { return Cfg; } + const TString& GetName() const { return Name; } + void SetName(const TString& name) { Name = name; } + + // Monitoring + void UpdateCounters(); + void SetCounters(TFlowCtlCounters* counters) { Counters = counters; } +private: + void SetWindow(ui64 window); + EStateTransition CreateST(bool wasOpen, bool isOpen); + TPeriod* AdvanceTime(double now, bool control); + TPeriod* GetPeriod(ui64 periodId); + TPeriod* CurPeriod(); // Returns current period + TPeriod* LastPeriod(); // Returns last remembered period + TPeriod* NextPeriod(TPeriod* p); // Iterate periods + TPeriod* InitPeriod(ui64 periodId, ui64 window); + TPeriod* InitPeriod(); + bool KleinrockControlEnabled(); + void Control(); + void AdvanceMonitoring(); + void UpdateThreshold(); +}; + +using TFlowCtlPtr = TIntrusivePtr; + +} diff --git a/ydb/library/shop/lazy_scheduler.h b/ydb/library/shop/lazy_scheduler.h new file mode 100644 index 000000000000..dc2357a01401 --- /dev/null +++ b/ydb/library/shop/lazy_scheduler.h @@ -0,0 +1,788 @@ +#pragma once + +#include "counters.h" +#include "probes.h" +#include "resource.h" +#include "schedulable.h" +#include "shop_state.h" + +#include +#include +#include +#include + +/// +/// Lazy scheduler is SFQ-scheduler with almost zero freezing cost (in term of CPU cycles). +/// Note that it is true even for hierarchical scheduling. Laziness means that hierarchy, +/// schedulers and consumers are not modified to freeze/unfreeze a machine. There is a global +/// shop state that reflects current state of machines, and every consumer has set of machines +/// from which at least one must be warm (not frozen) for consumer to be scheduled. +/// +/// In terms of resulting schedule (and fairness) there is no difference between shop/scheduler.h +/// and lazy scheduler, but there are the following issues: +/// - lazy scheduler has no layer of TFreezable objects between scheduler and consumers, but +/// freeze control is done through global (shared between schedulers) shop state; +/// - lazy scheduler has no heap to find consumer with minimal tag, but it just uses vector and +/// scans it on every scheduling event (it's okay if there are few consumers per node); +/// - it is more compute-intensive but less memory-intensive, because frozen key are pulled +/// on every scheduling event, but data required for it is dense; +/// - lazy scheduler uses small stack-vectors to remove one memory hop. +/// +/// Note that there is no thread-safety precautions (except for atomic monitoring counters). +/// + +namespace NShop { +namespace NLazy { + +template class TConsumer; +template class TScheduler; +template class TRootScheduler; + +using TConsumerIdx = ui16; + +constexpr TMachineIdx DoNotActivate = TMachineIdx(-1); +constexpr TMachineIdx DoNotDeactivate = TMachineIdx(-1); + +/////////////////////////////////////////////////////////////////////////////// + +constexpr size_t ResOptCount = 2; // optimal resource count (for stack vec) +constexpr size_t ConOptCount = 6; // optimal consumers count (for stack vec) + +/////////////////////////////////////////////////////////////////////////////// + +struct TCtx { + // Warm machines on current subtree (include overrides on local states) + TMachineMask Warm; + + // Create root context using shop state + explicit TCtx(const TShopState& shopState) + : Warm(shopState.Warm) + {} + + // Create subcontext on subtree with override and localstate + // NOTE: overrides bit marked in `override` using values from `state` + explicit TCtx(const TCtx& ctx, TMachineMask override, TMachineMask state) + : Warm((ctx.Warm & ~override) | (state & override)) + {} + + bool IsRunnable(TMachineMask active, TMachineMask allowed) const + { + return Warm & active & allowed; + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +template +class TConsumer: public virtual TThrRefBase { +private: + using TCost = typename TRes::TCost; + using TTag = typename TRes::TTag; + using TSch = TScheduler; + +private: + // Configuration + TString Name; + TWeight Weight = 1; + TSch* Scheduler = nullptr; + + // Scheduling state + TCost Underestimation = TCost(); // sum over all errors (realCost - estCost) to be fixed + TConsumerIdx Idx = TConsumerIdx(-1); // Index of consumer in parent scheduler + ui64 BusyPeriod = ui64(-1); + + // Monitoring + TTag Consumed = TTag(); + static TConsumerCounters FakeCounters; + TConsumerCounters* Counters = &FakeCounters; + +public: + virtual ~TConsumer() + { + Detach(); + } + + void SetName(const TString& name) { Name = name; } + const TString& GetName() const { return Name; } + + void SetWeight(TWeight weight) { Y_ABORT_UNLESS(weight > 0); Weight = weight; } + TWeight GetWeight() const { return Weight; } + + TSch* GetScheduler() const { return Scheduler; } + + void SetCounters(TConsumerCounters* counters) { Counters = counters; } + TConsumerCounters* GetCounters() { return Counters; } + + // Returns the next thing to schedule or nullptr (denial) + // WARNING: in case of denial, this scheduler will NOT be called with the + // same set (or its subset) of warm machines, till either + // - Allow(mi) is called on this or CHILD scheduler with machine from the set + // - DropDenials() is called on any PARENT scheduler (including root one) + virtual TSchedulable* PopSchedulable(const TCtx& ctx) = 0; + + // Recursive counters update (nothing to do on leafs) + virtual void UpdateCounters() {} + + // Activates consumer to compete for resources on given machine + void Activate(TMachineIdx mi); + + // Removes consumer from competition for resources on given machine + // NOTE: Scheduler keeps track of resource consumption + // NOTE: till busy period is over (in case deactivated consumer will return) + void Deactivate(TMachineIdx mi); + + // Notify about unfreeze + virtual void Allow(TMachineIdx mi); + + // Clear every cached denial + virtual void DropDenials() {} + + // Removes consumer from competition for resources on every machine + virtual void DeactivateAll() = 0; + + // Unlinks scheduler and consumer + void Detach(); + + // Adds estimation error (real - est) cost to be fixed on this consumer + void AddUnderestimation(TCost cost) { + Underestimation += cost; + } + + // Monitoring + TTag ResetConsumed(); + virtual void DebugPrint(IOutputStream& out, const TString& indent = {}) const; + TString DebugString() const; + + friend class TScheduler; +}; + +template +TConsumerCounters TConsumer::FakeCounters; + +template +class TScheduler: public TConsumer { +protected: + using TCost = typename TRes::TCost; + using TTag = typename TRes::TTag; + using TKey = typename TRes::TKey; + using TCon = TConsumer; + +protected: + // Configuration + TShopState* ShopState = nullptr; + TMachineMask* Override = nullptr; + TMachineMask* LocalState = nullptr; + TConsumerIdx Active = 0; // Total number of consumers currently active on at least on machine + ui64 BusyPeriod = 0; + TTag VirtualTime = TTag(); + + // Scheduling state + TStackVec Consumers; // consumerIdx -> consumer-object + TStackVec Masks; // consumerIdx -> machineIdx -> (1=active | 0=empty) + TStackVec Allowed; // consumerIdx -> machineIdx -> (1=allowed | 0=frozen) + TStackVec Keys; // consumerIdx -> TKey (e.g. amount of consumed resource so far) + TStackVec FrozenTmp; // temporary array for consumers we have to pull + TStackVec ActivePerMachine; // machineIdx -> number of active consumers +public: + // NOTE: Shop state should be set before scheduling begins + // NOTE: Shop state can be shared by multiple schedulers + void SetShopState(TShopState* value); + TShopState* GetShopState() const { return ShopState; } + + // Do not use `ShopState` bits marked by `override` mask, instead use corresponding bits from `local` mask + void OverrideState(TMachineMask* override, TMachineMask* local) { Override = override; LocalState = local; } + TMachineMask* GetOverride() const { return Override; } + TMachineMask* GetLocalState() const { return LocalState; } + + // Attaches new consumer to scheduler + void Attach(TCon* consumer); + + // Returns the next thing to schedule or nullptr (if empty and/or frozen) + TSchedulable* PopSchedulable(); + TSchedulable* PopSchedulable(const TCtx& ctx) override; + + // Return true iff there is no active consumers for warm machines + bool Empty() const; // DEPRECATED: use TRootScheduler::IsRunnable() + + // Activates every consumer for which `machineIdx(consumer)' + // call returns idx different from `DoNotActivate'. + // Returns number of activatied consumers + template + size_t ActivateConsumers(TFunc&& machineIdx); + + // Deactivates every consumer for which `machineIdx(consumer)' + // call returns idx different from `DoNotActivate'. + // Returns number of activatied consumers + template + size_t DeactivateConsumers(TFunc&& machineIdx); + + // Recursively DeactivateAll() every active consumer + void DeactivateAll() override; + + // Clears every cached denial + void DropDenials() override; + + // Detaches all consumers + void Clear(); + + // Monitoring + void UpdateCounters() override; + void DebugPrint(IOutputStream& out, const TString& indent = {}) const override; +private: + TSchedulable* PopSchedulableImpl(const TCtx& ctx); + bool IsNotFrozen(TConsumerIdx ci) const; + void Swap(TConsumerIdx ci1, TConsumerIdx ci2); + void Activate(TConsumerIdx ci, TMachineIdx mi); + TConsumerIdx Deactivate(TConsumerIdx ci, TMachineIdx mi); + void Deny(TConsumerIdx ci, TMachineMask machines); + void AllowChild(TConsumerIdx ci, TMachineIdx mi); + void Detach(TConsumerIdx ci); + + friend class TConsumer; +}; + +/////////////////////////////////////////////////////////////////////////////// + +template +class TRootScheduler: public TScheduler { +protected: + TMachineMask RootAllowed; +public: + bool IsRunnable() const; + TSchedulable* PopSchedulable(const TCtx& ctx) override; + void Allow(TMachineIdx mi) override; +}; + +/////////////////////////////////////////////////////////////////////////////// + +template +inline +void TConsumer::Activate(TMachineIdx mi) +{ + Scheduler->Activate(Idx, mi); +} + +template +inline +void TConsumer::Deactivate(TMachineIdx mi) +{ + Scheduler->Deactivate(Idx, mi); +} + +template +void TConsumer::Allow(TMachineIdx mi) +{ + if (Scheduler) { + Scheduler->AllowChild(Idx, mi); + } +} + +template +inline +void TConsumer::Detach() +{ + if (Scheduler) { + Scheduler->Detach(Idx); + } +} + +template +inline +typename TRes::TTag TConsumer::ResetConsumed() +{ + TTag result = Consumed; + Consumed = 0; + return result; +} + +template +inline +void TConsumer::DebugPrint(IOutputStream& out, const TString& indent) const +{ + out << indent << "Name: " << Name << Endl + << indent << "Weight: " << Weight << Endl + << indent << "BusyPeriod: " << BusyPeriod << Endl + << indent << "Borrowed: " << Counters->Borrowed << Endl + << indent << "Donated: " << Counters->Donated << Endl + << indent << "Usage: " << Counters->Usage << Endl + << indent << "Idx: " << Idx << Endl; +} + +template +inline +TString TConsumer::DebugString() const +{ + TStringStream ss; + DebugPrint(ss); + return ss.Str(); +} + +/////////////////////////////////////////////////////////////////////////////// + +template +inline +void TScheduler::SetShopState(TShopState* value) +{ + ShopState = value; + // NOTE: machines can be added and removed on flight, but cannot change its machineIds + ActivePerMachine.resize(ShopState->MachineCount, 0); +} + +template +inline +TSchedulable* TScheduler::PopSchedulable() +{ + return PopSchedulable(TCtx(*ShopState)); +} + + +template +inline +TSchedulable* TScheduler::PopSchedulable(const TCtx& ctx) +{ + if (Override) { + Y_ASSERT(LocalState); + return PopSchedulableImpl(TCtx(ctx, *Override, *LocalState)); + } else { + return PopSchedulableImpl(ctx); + } +} + +template +inline +TSchedulable* TScheduler::PopSchedulableImpl(const TCtx& ctx) +{ + while (true) { + // Select next warm consumer to be scheduled in a fair way + // And collect frozen consumer keys (to pull later) + TKey minKey = TRes::MaxKey(); + TConsumerIdx ci = TConsumerIdx(-1); + FrozenTmp.clear(); + for (TConsumerIdx cj = 0; cj < Active; cj++) { + if (ctx.IsRunnable(Masks[cj], Allowed[cj])) { + // If consumer is active on at least one warm machine -- it can be scheduled + TKey& key = Keys[cj]; + if (key < minKey) { + minKey = key; + ci = cj; + } + } else { + // Cannot be scheduled, but is active on at least one frozen machine + FrozenTmp.emplace_back(cj); + } + } + + if (ci == TConsumerIdx(-1)) { // If all warm and active consumers turned to be inactive + GLOBAL_LWPROBE(SHOP_PROVIDER, LazyIdlePeriod, + this->Name, VirtualTime, BusyPeriod); + + // Start new idle period (and new busy period that will follow it) + BusyPeriod++; + for (TConsumerIdx cj : FrozenTmp) { // Frozen consumers should NOT have idle periods + Consumers[cj]->BusyPeriod = BusyPeriod; + TKey& frozenKey = Keys[cj]; + frozenKey = TRes::OffsetKey(frozenKey, -VirtualTime); + } + VirtualTime = TTag(); + + if (!this->GetScheduler()) { + GLOBAL_LWPROBE(SHOP_PROVIDER, LazyWasted, + this->Name, VirtualTime, BusyPeriod, + this->DebugString()); + } + + return nullptr; + } + + // Schedule consumer + TCon* consumer = Consumers[ci]; + ui64 busyPeriod = BusyPeriod; + + if (TSchedulable* schedulable = consumer->PopSchedulable(ctx)) { + // Update idx in case consumer was deactivated in PopSchedulable() + // NOTE: FrozenKeys cannot invalidate even if consumer was deactivated + ci = consumer->Idx; + + // Propagate virtual time (if idle period has not been started) + if (busyPeriod == BusyPeriod) { + TTag vtime0 = VirtualTime; + VirtualTime = TRes::GetTag(minKey); + TTag vtimeDelta = VirtualTime - vtime0; + + // Pull all frozen consumers + for (TConsumerIdx cj : FrozenTmp) { + TKey& frozenKey = Keys[cj]; + frozenKey = TRes::OffsetKey(frozenKey, vtimeDelta); + } + } + + // Try to immediatly fix any discrepancy between real and estimated costs + // (as long as it doesn't lead to negative cost) + TCost cost = schedulable->Cost + consumer->Underestimation; + if (cost >= 0) { + consumer->Underestimation = 0; + } else { + // Lower consumer overestimation by schedulable cost, and allow "free" usage + consumer->Underestimation = cost; + cost = 0; + } + + // Update consumer key + TTag duration = cost / consumer->Weight; + TKey& key = Keys[ci]; + key = TRes::OffsetKey(key, duration); + consumer->Consumed += duration; + + GLOBAL_LWPROBE(SHOP_PROVIDER, LazyPopSchedulable, + this->Name, consumer->Name, + VirtualTime, BusyPeriod, + TRes::GetTag(key), schedulable->Cost, + cost - schedulable->Cost, consumer->Weight, duration); + + return schedulable; + } else { + // Consumer refused to return schedulable + // Deny entrance into it with currently warm machines to avoid hang up + Deny(ci, ctx.Warm); + } + } +} + +template +inline +bool TScheduler::Empty() const +{ + for (TConsumerIdx cj = 0; cj < Active; cj++) { + if (IsNotFrozen(cj)) { + return false; // There is an active consumer on at least one warm machine + } + } + return true; // There is no active consumers for warm machines +} + +template +inline +void TScheduler::Clear() +{ + auto consumers = Consumers; + for (TCon* c : consumers) { + c->Detach(); + } + Y_ASSERT(Masks.empty()); + Y_ASSERT(Allowed.empty()); + Y_ASSERT(Keys.empty()); + Y_ASSERT(Consumers.empty()); +} + +template +inline +void TScheduler::UpdateCounters() +{ + TCountersAggregator aggr; + for (TCon* consumer : Consumers) { + aggr.Add(consumer); + consumer->UpdateCounters(); // Recurse into children + } + aggr.Apply(); +} + +template +inline +void TScheduler::DebugPrint(IOutputStream& out, const TString& indent) const +{ + out << indent << "VirtualTime: " << VirtualTime << Endl + << indent << "BusyPeriod: " << BusyPeriod << Endl; + if (this->GetScheduler()) { + // Print consumer-related part of scheduler, if it is not root scheudler + TCon::DebugPrint(out, indent); + } + for (size_t ci = 0; ci < Consumers.size(); ci++) { + const TCon& c = *Consumers[ci]; + TString indent2 = indent + " "; + out << indent << "Consumer {" << Endl + << indent2 << (ci < Active? "[A]": "[I]") << "Mask: " << Masks[ci].ToString(ShopState->MachineCount) << Endl + << indent2 << "Allowed: " << Allowed[ci].ToString(ShopState->MachineCount) << Endl + << indent2 << "Key: " << Keys[ci] << Endl; + c.DebugPrint(out, indent2); + out << indent << "}" << Endl; + } +} + +template +inline +void TScheduler::Attach(TCon* consumer) +{ + // Reset state in case consumer was used in another scheduler + consumer->BusyPeriod = size_t(-1); + consumer->Underestimation = TCost(); + consumer->Idx = Consumers.size(); + consumer->Scheduler = this; + + // Attach consumer + Consumers.emplace_back(consumer); + Masks.emplace_back(0); + Allowed.emplace_back(0); + Keys.emplace_back(TRes::ZeroKey(consumer)); + + Y_ABORT_UNLESS(Consumers.size() < (1ull << (8 * sizeof(TConsumerIdx))), "too many consumers"); +} + +template +inline +bool TScheduler::IsNotFrozen(TConsumerIdx ci) const +{ + if (Override && LocalState) { + TMachineMask override = *Override; + TMachineMask state = *LocalState; + // Override bit marked in `Override` using values from `LocalState` + // and then check if there is at least one warm and active machine + return ((ShopState->Warm & ~override) + | (state & override)) & Masks[ci]; + } else { + // Just check if there is at least one warm and active machine + return ShopState->Warm & Masks[ci]; + } +} + +template +inline +void TScheduler::Swap(TConsumerIdx ci1, TConsumerIdx ci2) +{ + DoSwap(Consumers[ci1], Consumers[ci2]); + DoSwap(Masks[ci1], Masks[ci2]); + DoSwap(Allowed[ci1], Allowed[ci2]); + DoSwap(Keys[ci1], Keys[ci2]); + Consumers[ci1]->Idx = ci1; + Consumers[ci2]->Idx = ci2; +} + +template +inline +void TScheduler::Activate(TConsumerIdx ci, TMachineIdx mi) +{ + AllowChild(ci, mi); // Activation is worthless without allowment + + TMachineMask& mask = Masks[ci]; + if (mask.Get(mi)) { + return; // Avoid double activation + } + + // Recursively activate machine in parent schedulers (if required) + if (this->GetScheduler() && ActivePerMachine[mi] == 0) { + TCon::Activate(mi); + } + + // Activate machine for consumer + mask.Set(mi); + ActivePerMachine[mi]++; + + // Update consumer's key + TCon* consumer = Consumers[ci]; + TKey& key = Keys[ci]; + if (consumer->BusyPeriod != BusyPeriod) { + consumer->BusyPeriod = BusyPeriod; + // Memoryless property: consumption history must be reset on new busy period + key = TRes::ZeroKey(consumer); + // Estimation errors of pervious busy period does not matter any more + consumer->Underestimation = TCost(); + } + TRes::ActivateKey(key, VirtualTime); // Do not reclaim unused resource from past + + GLOBAL_LWPROBE(SHOP_PROVIDER, LazyActivate, + this->Name, consumer->Name, + VirtualTime, BusyPeriod, + TRes::GetTag(Keys[ci]), mask.ToString(ShopState->MachineCount), + mi, ActivePerMachine[mi]); + + // Rearrange consumers to have completely deactivated (on every machine) in separate range + if (ci >= Active) { + if (ci != Active) { + Swap(ci, Active); + } + Active++; + } +} + +template +template +inline +size_t TScheduler::ActivateConsumers(TFunc&& machineIdx) +{ + size_t prevActiveCount = Active; + auto i = Consumers.begin() + Active; + auto e = Consumers.end(); + for (TConsumerIdx ci = Active; i != e; ++i, ci++) { + TCon* consumer = *i; + TMachineIdx mi = machineIdx(consumer); + if (mi != DoNotActivate) { + Activate(ci, mi); + } + } + return Active - prevActiveCount; +} + +template +template +inline +size_t TScheduler::DeactivateConsumers(TFunc&& machineIdx) +{ + size_t prevActiveCount = Active; + auto i = Consumers.rend() - Active; + auto e = Consumers.rend(); + for (TConsumerIdx ci = Active - 1; i != e; ++i, ci--) { + TCon* consumer = *i; + TMachineIdx mi = machineIdx(consumer); + if (mi != DoNotDeactivate) { + Deactivate(ci, mi); + } + } + return prevActiveCount - Active; +} + +template +inline +void TScheduler::DeactivateAll() +{ + while (Active > 0) { + TCon* consumer = Consumers[Active - 1]; + consumer->DeactivateAll(); + Y_ABORT_UNLESS(Masks[consumer->Idx].IsZero(), + "unable to deactivate consumer '%s' of scheduler '%s'", + consumer->GetName().c_str(), this->GetName().c_str()); + } +} + +template +void TScheduler::DropDenials() +{ + // every active consumed is allowed recursively + for (TConsumerIdx ci = 0; ci < Active; ci++) { + Allowed[ci] = Masks[ci]; + Consumers[ci]->DropDenials(); + } +} + +template +inline +TConsumerIdx TScheduler::Deactivate(TConsumerIdx ci, TMachineIdx mi) +{ + TMachineMask& mask = Masks[ci]; + if (!mask.Get(mi)) { + return ci; // Avoid double deactivation + } + + // Deactivate machine for consumer + mask.Reset(mi); + // NOTE: Deny is not required, because only (Allowed & Masks) matters and mask is reset + ActivePerMachine[mi]--; + + GLOBAL_LWPROBE(SHOP_PROVIDER, LazyDeactivate, + this->Name, Consumers[ci]->Name, + VirtualTime, BusyPeriod, + TRes::GetTag(Keys[ci]), mask.ToString(ShopState->MachineCount), + mi, ActivePerMachine[mi]); + + // Recursively deactivate machine in parent schedulers (if required) + if (this->GetScheduler() && ActivePerMachine[mi] == 0) { + TCon::Deactivate(mi); + } + + // Rearrange consumers to have completely deactivated (on every machine) in separate range + // (to be able to quickly iterate through them) + if (ci < Active && mask.IsZero()) { + Active--; + Swap(ci, Active); + ci = Active; + } + + return ci; +} + +template +void TScheduler::AllowChild(TConsumerIdx ci, TMachineIdx mi) +{ + TMachineMask& allowed = Allowed[ci]; + if (allowed.Get(mi)) { + return; // Avoid double allow + } + + // Recursively allow machine in parent schedulers + this->Allow(mi); + + GLOBAL_LWPROBE(SHOP_PROVIDER, LazyAllow, + this->GetName(), Consumers[ci]->GetName(), + VirtualTime, BusyPeriod, + mi); + + allowed.Set(mi); +} + +template +void TScheduler::Deny(TConsumerIdx ci, TMachineMask machines) +{ + GLOBAL_LWPROBE(SHOP_PROVIDER, LazyDeny, + this->GetName(), Consumers[ci]->GetName(), + VirtualTime, BusyPeriod, + machines.ToString(ShopState->MachineCount)); + + Allowed[ci].ResetAll(machines); +} + +template +inline +void TScheduler::Detach(TConsumerIdx ci) +{ + // Completely deactivate consumer on every machine + for (TMachineIdx mi = 0; mi < ShopState->MachineCount; mi++) { + ci = Deactivate(ci, mi); + } + Y_ASSERT(ci >= Active); + + // Unlink consumer and scheduler + if (ci != Consumers.size() - 1) { // Consumer should be the last one to be detached + Swap(ci, Consumers.size() - 1); + } + Consumers.back()->Scheduler = nullptr; + Consumers.pop_back(); + Masks.pop_back(); + Allowed.pop_back(); + Keys.pop_back(); +} + + +/////////////////////////////////////////////////////////////////////////////// + +template +bool TRootScheduler::IsRunnable() const +{ + return RootAllowed & this->GetShopState()->Warm; +} + +template +TSchedulable* TRootScheduler::PopSchedulable(const TCtx& ctx) +{ + if (TSchedulable* schedulable = TScheduler::PopSchedulable(ctx)) { + return schedulable; + } else { // Deny + GLOBAL_LWPROBE(SHOP_PROVIDER, LazyRootDeny, + this->GetName(), ctx.Warm.ToString(this->ShopState->MachineCount)); + RootAllowed.ResetAll(ctx.Warm); + return nullptr; + } +} + +template +void TRootScheduler::Allow(TMachineIdx mi) +{ + if (RootAllowed.Get(mi)) { + return; // Avoid double allow + } + + GLOBAL_LWPROBE(SHOP_PROVIDER, LazyRootAllow, + this->GetName(), mi); + + RootAllowed.Set(mi); +} + +} +} diff --git a/ydb/library/shop/probes.cpp b/ydb/library/shop/probes.cpp new file mode 100644 index 000000000000..86fc2d5bd3e5 --- /dev/null +++ b/ydb/library/shop/probes.cpp @@ -0,0 +1,3 @@ +#include "probes.h" + +LWTRACE_DEFINE_PROVIDER(SHOP_PROVIDER) diff --git a/ydb/library/shop/probes.h b/ydb/library/shop/probes.h new file mode 100644 index 000000000000..3c6a1c31119b --- /dev/null +++ b/ydb/library/shop/probes.h @@ -0,0 +1,157 @@ +#pragma once + +#include +#include + +inline ui64 Duration(ui64 ts1, ui64 ts2) +{ + return ts2 > ts1? ts2 - ts1: 0; +} + +inline double CyclesToMs(ui64 cycles) +{ + return double(cycles) * 1e3 / NHPTimer::GetCyclesPerSecond(); +} + +#define SHOP_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ + PROBE(Arrive, GROUPS("ShopFlowCtlOp"), \ + TYPES(TString, ui64, ui64, double, ui64, ui64, ui64, ui64, ui64), \ + NAMES("flowctl", "opId", "periodId", "now", "estCost", "usedCost", "countInFly", "costInFly", "window")) \ + PROBE(Depart, GROUPS("ShopFlowCtlOp", "ShopFlowCtlOpDepart"), \ + TYPES(TString, ui64, ui64, double, ui64, ui64, ui64, ui64, ui64, double, double, ui64), \ + NAMES("flowctl", "opId", "periodId", "now", "estCost", "usedCost", "countInFly", "costInFly", "realCost", "latencyMs", "weight", "window")) \ + PROBE(DepartLatency, GROUPS("ShopFlowCtlOpDepart"), \ + TYPES(TString, ui64, ui64, double, double, double, ui64, double), \ + NAMES("flowctl", "opId", "periodId", "now", "realLatencyMs", "latencyMAMs", "realCostMA", "arriveTime")) \ + PROBE(AdvanceTime, GROUPS(), \ + TYPES(TString, double, double), \ + NAMES("flowctl", "oldNow", "now")) \ + PROBE(Abort, GROUPS("ShopFlowCtlOp"), \ + TYPES(TString, ui64, ui64, double, ui64, ui64, ui64, ui64), \ + NAMES("flowctl", "opId", "periodId", "now", "estCost", "usedCost", "countInFly", "costInFly")) \ + PROBE(InitPeriod, GROUPS("ShopFlowCtlPeriod"), \ + TYPES(TString, ui64, double, ui64), \ + NAMES("flowctl", "periodId", "now", "window")) \ + PROBE(PeriodStats, GROUPS(), \ + TYPES(TString, ui64, double, ui64, double, double, double, double, double, double), \ + NAMES("flowctl", "periodId", "now", "statsPeriodId", "costSum", "costSumError", "weightSum", "weightSumError", "latencySum", "latencySumError")) \ + PROBE(PeriodGood, GROUPS(), \ + TYPES(TString, ui64, double, ui64, ui64, double, double, double, double), \ + NAMES("flowctl", "periodId", "now", "statsPeriodId", "goodPeriodIdx", "periodThroughput", "periodEThroughput", "periodLatencyAvgMs", "periodLatencyErrMs")) \ + PROBE(Measurement, GROUPS("ShopFlowCtlPeriod"), \ + TYPES(TString, ui64, double, ui64, ui64, ui64), \ + NAMES("flowctl", "periodId", "now", "badPeriods", "goodPeriods", "zeroPeriods")) \ + PROBE(Throughput, GROUPS("ShopFlowCtlPeriod"), \ + TYPES(TString, ui64, double, double, double, double, double, double, double), \ + NAMES("flowctl", "periodId", "now", "throughput", "throughputMin", "throughputMax", "throughputLo", "throughputHi", "dT_T")) \ + PROBE(EstThroughput, GROUPS("ShopFlowCtlPeriod"), \ + TYPES(TString, ui64, double, double, double, double, double, double, double), \ + NAMES("flowctl", "periodId", "now", "ethroughput", "ethroughputMin", "ethroughputMax", "ethroughputLo", "ethroughputHi", "dET_ET")) \ + PROBE(Latency, GROUPS("ShopFlowCtlPeriod"), \ + TYPES(TString, ui64, double, double, double, double, double, double, double), \ + NAMES("flowctl", "periodId", "now", "latencyAvgMs", "latencyAvgMinMs", "latencyAvgMaxMs", "latencyAvgLoMs", "latencyAvgHiMs", "dL_L")) \ + PROBE(Slowdown, GROUPS("ShopFlowCtlPeriod"), \ + TYPES(TString, ui64, double, ui64), \ + NAMES("flowctl", "periodId", "now", "waitSteady")) \ + PROBE(Control, GROUPS("ShopFlowCtlPeriod"), \ + TYPES(TString, ui64, double, double, double, double, double), \ + NAMES("flowctl", "periodId", "now", "pv", "error", "ratio", "target")) \ + PROBE(Window, GROUPS("ShopFlowCtlPeriod"), \ + TYPES(TString, ui64, double, ui64), \ + NAMES("flowctl", "periodId", "now", "window")) \ + PROBE(State, GROUPS("ShopFlowCtlPeriod"), \ + TYPES(TString, ui64, double, ui64, double), \ + NAMES("flowctl", "periodId", "now", "mode", "state")) \ + PROBE(TransitionClosed, GROUPS("FlowCtlTransition"), \ + TYPES(TString, double), \ + NAMES("flowctl", "now")) \ + PROBE(TransitionOpened, GROUPS("FlowCtlTransition"), \ + TYPES(TString, double), \ + NAMES("flowctl", "now")) \ + PROBE(Configure, GROUPS(), \ + TYPES(TString, double, TString), \ + NAMES("flowctl", "now", "config")) \ + \ + \ + \ + PROBE(StartJob, GROUPS("ShopJob"), \ + TYPES(TString, TString, ui64), \ + NAMES("shop", "flow", "job")) \ + PROBE(CancelJob, GROUPS("ShopJob"), \ + TYPES(TString, TString, ui64), \ + NAMES("shop", "flow", "job")) \ + PROBE(JobFinished, GROUPS("ShopJob"), \ + TYPES(TString, TString, ui64, double), \ + NAMES("shop", "flow", "job", "jobTimeMs")) \ + PROBE(StartOperation, GROUPS("ShopJob", "ShopOp"), \ + TYPES(TString, TString, ui64, ui64, ui64, ui64), \ + NAMES("shop", "flow", "job", "sid", "machineid", "estcost")) \ + PROBE(SkipOperation, GROUPS("ShopJob", "ShopOp"), \ + TYPES(TString, TString, ui64, ui64, ui64), \ + NAMES("shop", "flow", "job", "sid", "machineid")) \ + PROBE(OperationFinished, GROUPS("ShopJob", "ShopOp"), \ + TYPES(TString, TString, ui64, ui64, ui64, ui64, bool, double), \ + NAMES("shop", "flow", "job", "sid", "machineid", "realcost", "success", "procTimeMs")) \ + PROBE(NoMachine, GROUPS("ShopJob", "ShopOp"), \ + TYPES(TString, TString, ui64, ui64, ui64), \ + NAMES("shop", "flow", "job", "sid", "machineid")) \ + \ + \ + \ + PROBE(GlobalBusyPeriod, GROUPS("ShopScheduler"), \ + TYPES(TString, double, ui64, ui64, ui64, double, double, double), \ + NAMES("scheduler", "vtime", "busyPeriod", "busyPeriodPops", "busyPeriodCost", "idlePeriodDurationMs", "busyPeriodDurationMs", "utilization")) \ + PROBE(LocalBusyPeriod, GROUPS("ShopScheduler"), \ + TYPES(TString, double, ui64, ui64, ui64, double, double, double), \ + NAMES("scheduler", "vtime", "busyPeriod", "busyPeriodPops", "busyPeriodCost", "idlePeriodDurationMs", "busyPeriodDurationMs", "utilization")) \ + PROBE(PopSchedulable, GROUPS("ShopScheduler", "ShopFreezable", "ShopConsumer"), \ + TYPES(TString, TString, TString, double, ui64, double, ui64, i64, double, double), \ + NAMES("scheduler", "freezable", "consumer", "vtime", "busyPeriod", "finish", "cost", "underestimation", "weight", "vduration")) \ + PROBE(Activate, GROUPS("ShopScheduler", "ShopFreezable", "ShopConsumer"), \ + TYPES(TString, TString, TString, double, ui64, double, bool), \ + NAMES("scheduler", "freezable", "consumer", "vtime", "busyPeriod", "start", "frozen")) \ + PROBE(Deactivate, GROUPS("ShopScheduler", "ShopFreezable", "ShopConsumer"), \ + TYPES(TString, TString, TString, double, ui64, double, bool), \ + NAMES("scheduler", "freezable", "consumer", "vtime", "busyPeriod", "start", "frozen")) \ + PROBE(DeactivateImplicit, GROUPS("ShopScheduler", "ShopFreezable", "ShopConsumer"), \ + TYPES(TString, TString, TString, double, ui64, double, bool), \ + NAMES("scheduler", "freezable", "consumer", "vtime", "busyPeriod", "start", "frozen")) \ + PROBE(Freeze, GROUPS("ShopScheduler", "ShopFreezable"), \ + TYPES(TString, TString, double, ui64, ui64, ui64, double), \ + NAMES("scheduler", "freezable", "vtime", "busyPeriod", "freezableBusyPeriod", "frozenCount", "offset")) \ + PROBE(Unfreeze, GROUPS("ShopScheduler", "ShopFreezable"), \ + TYPES(TString, TString, double, ui64, ui64, ui64, double), \ + NAMES("scheduler", "freezable", "vtime", "busyPeriod", "freezableBusyPeriod", "frozenCount", "offset")) \ + \ + \ + \ + PROBE(LazyIdlePeriod, GROUPS("ShopLazyScheduler"), \ + TYPES(TString, double, ui64), \ + NAMES("scheduler", "vtime", "busyPeriod")) \ + PROBE(LazyWasted, GROUPS("ShopLazyScheduler"), \ + TYPES(TString, double, ui64, TString), \ + NAMES("scheduler", "vtime", "busyPeriod", "debugString")) \ + PROBE(LazyPopSchedulable, GROUPS("ShopLazyScheduler", "ShopLazyConsumer"), \ + TYPES(TString, TString, double, ui64, double, ui64, i64, double, double), \ + NAMES("scheduler", "consumer", "vtime", "busyPeriod", "finish", "cost", "underestimation", "weight", "vduration")) \ + PROBE(LazyActivate, GROUPS("ShopLazyScheduler", "ShopLazyConsumer"), \ + TYPES(TString, TString, double, ui64, double, TString, ui64, ui64), \ + NAMES("scheduler", "consumer", "vtime", "busyPeriod", "start", "mask", "machineIdx", "activePerMachine")) \ + PROBE(LazyDeactivate, GROUPS("ShopLazyScheduler", "ShopLazyConsumer"), \ + TYPES(TString, TString, double, ui64, double, TString, ui64, ui64), \ + NAMES("scheduler", "consumer", "vtime", "busyPeriod", "start", "mask", "machineIdx", "activePerMachine")) \ + PROBE(LazyDeny, GROUPS("ShopLazyScheduler", "ShopLazyConsumer"), \ + TYPES(TString, TString, double, ui64, TString), \ + NAMES("scheduler", "consumer", "vtime", "busyPeriod", "machines")) \ + PROBE(LazyAllow, GROUPS("ShopLazyScheduler", "ShopLazyConsumer"), \ + TYPES(TString, TString, double, ui64, ui64), \ + NAMES("scheduler", "consumer", "vtime", "busyPeriod", "machineIdx")) \ + PROBE(LazyRootDeny, GROUPS("ShopLazyScheduler"), \ + TYPES(TString, TString), \ + NAMES("scheduler", "machines")) \ + PROBE(LazyRootAllow, GROUPS("ShopLazyScheduler"), \ + TYPES(TString, ui64), \ + NAMES("scheduler", "machineIdx")) \ +/**/ + +LWTRACE_DECLARE_PROVIDER(SHOP_PROVIDER) diff --git a/ydb/library/shop/protos/library-shop-protos-sources.jar b/ydb/library/shop/protos/library-shop-protos-sources.jar new file mode 120000 index 000000000000..8263a11083f1 --- /dev/null +++ b/ydb/library/shop/protos/library-shop-protos-sources.jar @@ -0,0 +1 @@ +/home/hcpp/.ya/build/symres/5714ce2c5d23ea3b02c8b92a30c7a99c/library-shop-protos-sources.jar \ No newline at end of file diff --git a/ydb/library/shop/protos/library-shop-protos.jar b/ydb/library/shop/protos/library-shop-protos.jar new file mode 120000 index 000000000000..1ce433596d40 --- /dev/null +++ b/ydb/library/shop/protos/library-shop-protos.jar @@ -0,0 +1 @@ +/home/hcpp/.ya/build/symres/129ac0f5aaf3e03e818dafe3713a8744/library-shop-protos.jar \ No newline at end of file diff --git a/ydb/library/shop/protos/library-shop-protos.protosrc b/ydb/library/shop/protos/library-shop-protos.protosrc new file mode 120000 index 000000000000..2c1acf2d1f02 --- /dev/null +++ b/ydb/library/shop/protos/library-shop-protos.protosrc @@ -0,0 +1 @@ +/home/hcpp/.ya/build/symres/40a3e923e38f7d8fad119a1d90c0a787/library-shop-protos.protosrc \ No newline at end of file diff --git a/ydb/library/shop/protos/shop.proto b/ydb/library/shop/protos/shop.proto new file mode 100644 index 000000000000..de26c548d648 --- /dev/null +++ b/ydb/library/shop/protos/shop.proto @@ -0,0 +1,47 @@ +package NShop; + +option java_package = "ru.yandex.shop.proto"; + +message TFlowCtlConfig { + // Time-related stuff + optional double PeriodDuration = 100 [default = 1.0]; // in seconds + optional uint64 HistorySize = 101 [default = 9]; // in periods + + // Measurements + optional double MeasurementError = 200 [default = 0.01]; // ratio (not percents) + optional double SteadyLimit = 201 [default = 0.5]; // ratio + optional double LatencyMACoef = 202 [default = 0.01]; // moving average coef (less=smooth) + optional double RealCostMACoef = 203 [default = 0.01]; // moving average coef (less=smooth) + + // Controller + optional bool Disabled = 299 [default = false]; // Has always open window if disabled + optional uint64 FixedWindow = 300 [default = 0]; // Just use const window iff>0 + optional double FixedLatencyMs = 301 [default = 0]; // Adjust window to contain queue of given length in milliseconds iff>0 + optional uint64 MinCountInFly = 302 [default = 10]; + optional uint64 MinCostInFly = 303 [default = 1]; + optional double MultiplierLimit = 304 [default = 0.05]; // Max window multiplier per period + optional uint64 SlowdownLimit = 305 [default = 5]; // Max periods in slowest controlling mode + optional uint64 SlowStartLimit = 306 [default = 30]; // Max periods in SlowStart controlling mode + optional double CostCapToWindow = 307 [default = 0.5]; // Cap for request cost devided by window +} + +message TProcCounters { + // Op or job result count + optional uint64 Done = 5; + optional uint64 Failed = 6; + optional uint64 Aborted = 7; // Op skip or job cancel + + // Op or job processing time + optional uint64 Time1ms = 20; + optional uint64 Time3ms = 21; + optional uint64 Time10ms = 22; + optional uint64 Time30ms = 23; + optional uint64 Time100ms = 24; + optional uint64 Time300ms = 25; + optional uint64 Time1000ms = 26; + optional uint64 Time3000ms = 27; + optional uint64 Time10000ms = 28; + optional uint64 Time30000ms = 29; + optional uint64 Time100000ms = 30; + optional uint64 TimeGt100000ms = 31; +} diff --git a/ydb/library/shop/protos/ya.make b/ydb/library/shop/protos/ya.make new file mode 100644 index 000000000000..ec7290c78144 --- /dev/null +++ b/ydb/library/shop/protos/ya.make @@ -0,0 +1,9 @@ +PROTO_LIBRARY() + +SRCS( + shop.proto +) + +EXCLUDE_TAGS(GO_PROTO) + +END() diff --git a/ydb/library/shop/resource.h b/ydb/library/shop/resource.h new file mode 100644 index 000000000000..199d2261f0a6 --- /dev/null +++ b/ydb/library/shop/resource.h @@ -0,0 +1,98 @@ +#pragma once + +#include +#include + +#include +#include + +namespace NShop { + +using TWeight = double; + +// Single resource max-min fairness allocation policy +template +struct TSingleResourceTempl { + using TCost = i64; + using TTag = TFloat; + using TKey = TFloat; + + inline static TKey OffsetKey(TKey key, TTag offset) + { + return key + offset; + } + + template + inline static void SetKey(TKey& key, ConsumerT* consumer) + { + key = consumer->GetTag(); + } + + inline static TTag GetTag(const TKey& key) + { + return key; + } + + inline static TKey MaxKey() + { + return std::numeric_limits::max(); + } + + template + inline static TKey ZeroKey(ConsumerT* consumer) + { + Y_UNUSED(consumer); + return 0; + } + + inline static void ActivateKey(TKey& key, TTag vtime) + { + key = Max(key, vtime); + } +}; + +using TSingleResource = TSingleResourceTempl; +using TSingleResourceDense = TSingleResourceTempl; // for lazy scheduler + +// Dominant resource fairness queueing (DRFQ) allocation policy +// with two resources and perfect dovetailing +struct TPairDrf { + using TCost = std::pair; + using TTag = std::pair; + using TKey = double; // dominant resource + + inline static TKey OffsetKey(TKey key, TTag offset) + { + return key + Dominant(offset); + } + + template + inline static void SetKey(TKey& key, ConsumerT* consumer) + { + key = Dominant(consumer->GetTag()); + } + + inline static TKey Dominant(TTag tag) + { + return Max(tag.first, tag.second); + } + + inline static TKey MaxKey() + { + return std::numeric_limits::max(); + } + + template + inline static TKey ZeroKey(ConsumerT* consumer) + { + Y_UNUSED(consumer); + return 0; + } + + inline static void ActivateKey(TKey& key, TTag vtime) + { + key = Max(key, Dominant(vtime)); + } +}; + +} diff --git a/ydb/library/shop/schedulable.h b/ydb/library/shop/schedulable.h new file mode 100644 index 000000000000..b09058a4819a --- /dev/null +++ b/ydb/library/shop/schedulable.h @@ -0,0 +1,17 @@ +#pragma once + +#include "resource.h" + +#include + +namespace NShop { + +/////////////////////////////////////////////////////////////////////////////// + +template +struct TSchedulable: public virtual TThrRefBase { +public: + TCost Cost; +}; + +} diff --git a/ydb/library/shop/scheduler.h b/ydb/library/shop/scheduler.h new file mode 100644 index 000000000000..3ba0052b98d1 --- /dev/null +++ b/ydb/library/shop/scheduler.h @@ -0,0 +1,732 @@ +#pragma once + +#include "counters.h" +#include "probes.h" +#include "resource.h" +#include "schedulable.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace NShop { + +static constexpr i64 IsActive = -1; +static constexpr i64 IsDetached = -2; + +struct TConsumerCounters; +template class TConsumer; +template class TFreezable; +template class TScheduler; + +/////////////////////////////////////////////////////////////////////////////// + +template +class TConsumer { +private: + using TCost = typename TRes::TCost; + using TTag = typename TRes::TTag; + using FreezableT = TFreezable; + using SchedulerT = TScheduler; + + // Configuration + TString Name; + TWeight Weight = 1; + SchedulerT* Scheduler = nullptr; + FreezableT* Freezable = nullptr; + + // Scheduling state + TTag HolTag = TTag(); // Tag (aka virtual time) of head-of-line schedulable + ui64 GlobalBusyPeriod = 0; + i64 DeactIdx = IsDetached; // Index of deactivated consumer in parent freezable (or special values) + TCost Underestimation = TCost(); // sum over all errors (realCost - estCost) to be fixed + + // Monitoring + TTag Consumed = TTag(); + static TConsumerCounters FakeCounters; + TConsumerCounters* Counters = &FakeCounters; + +public: + virtual ~TConsumer() + { + Detach(); + } + + void SetName(const TString& name) { Name = name; } + const TString& GetName() const { return Name; } + + void SetWeight(TWeight weight) { Y_ABORT_UNLESS(weight > 0); Weight = weight; } + TWeight GetWeight() const { return Weight; } + + void SetScheduler(SchedulerT* scheduler) { Scheduler = scheduler; } + SchedulerT* GetScheduler() const { return Scheduler; } + + void SetFreezable(FreezableT* freezable) { Freezable = freezable; } + FreezableT* GetFreezable() const { return Freezable; } + + void SetCounters(TConsumerCounters* counters) { Counters = counters; } + TConsumerCounters* GetCounters() { return Counters; } + + TTag GetTag() const { return HolTag; } + + virtual TSchedulable* PopSchedulable() = 0; + virtual bool Empty() const = 0; + virtual void UpdateCounters() {} + + void Activate(); // NOTE: it also attaches consumer if it hasn't been done yet + void Deactivate(); + void Detach(); + void AddUnderestimation(TCost cost) { + Underestimation += cost; + } + + TTag ResetConsumed(); + void Print(IOutputStream& out) const; + + friend class TFreezable; + friend class TScheduler; +}; + +template +TConsumerCounters TConsumer::FakeCounters; + +template +class TFreezable { +private: + using TCost = typename TRes::TCost; + using TTag = typename TRes::TTag; + using SchedulerT = TScheduler; + using ConsumerT = TConsumer; + +private: + struct THeapItem { + typename TRes::TKey Key; + ConsumerT* Consumer; + + explicit THeapItem(ConsumerT* consumer) + : Consumer(consumer) + { + UpdateKey(); + } + + void UpdateKey() + { + TRes::SetKey(Key, Consumer); + } + + bool operator<(const THeapItem& rhs) const + { + return rhs.Key < Key; // swapped for min-heap + } + }; + +private: + // Configuration + TString Name; + SchedulerT* Scheduler = nullptr; + + // Scheduling state + TVector Heap; + i64 HeapEndIdx = 0; + bool Frozen = false; + TTag LastFreeze = TTag(); + TTag Offset = TTag(); + ui64 GlobalBusyPeriod = 0; +public: + void SetName(const TString& name) { Name = name; } + TString GetName() { return Name; } + + TSchedulable* PopSchedulable(); + bool Empty() const; + + void SetScheduler(SchedulerT* scheduler) { Scheduler = scheduler; } + SchedulerT* GetScheduler() { return Scheduler; } + + // Activates consumers for which `predicate' holds true + template + size_t ActivateConsumers(TPredicate&& predicate); + + // Should be called before delete or just for detaching freezable + void Deactivate(); + + bool IsFrozen() const { return Frozen; } + void Freeze(); + void Unfreeze(); + + // Defines scheduling order of freezables + bool operator<(const TFreezable& o) const + { + Y_ASSERT(HeapEndIdx > 0); + Y_ASSERT(o.HeapEndIdx > 0); + Y_ASSERT(!Heap.empty()); + Y_ASSERT(!o.Heap.empty()); + return TRes::OffsetKey(Heap.front().Key, Offset) + < TRes::OffsetKey(o.Heap.front().Key, o.Offset); + } +private: + void Activate(ConsumerT* consumer); + void Insert(ConsumerT* consumer); + void Deactivate(ConsumerT* consumer); + void Detach(ConsumerT* consumer); + + friend class TScheduler; + friend class TConsumer; +}; + +template +class TScheduler: public TConsumer { +private: + using TCost = typename TRes::TCost; + using TTag = typename TRes::TTag; + using FreezableT = TFreezable; + using ConsumerT = TConsumer; + +private: + struct TCmp { + bool operator()(FreezableT* lhs, FreezableT* rhs) const + { + return *lhs < *rhs; + } + }; + TVector Freezables; + ui64 FrozenCount = 0; + TTag VirtualTime = TTag(); + TTag LatestFinish = TTag(); + ui64 GlobalBusyPeriod = 0; + TCost GlobalBusyPeriodCost = TCost(); + ui64 GlobalBusyPeriodPops = 0; + ui64 GlobalPeriodTs = 0; // Idle or busy period start time (in cycles) + ui64 GlobalIdlePeriodDuration = ui64(-1); + ui64 LocalBusyPeriod = 0; + TCost LocalBusyPeriodCost = TCost(); + ui64 LocalBusyPeriodPops = 0; + ui64 LocalPeriodTs = 0; // Idle or busy period start time (in cycles) + ui64 LocalIdlePeriodDuration = ui64(-1); +public: + TSchedulable* PopSchedulable() override; + bool Empty() const override; + void Clear(); + void UpdateCounters() override; + void Print(IOutputStream& out) const; + void DebugPrint(IOutputStream& out) const; +private: + void Activate(FreezableT* freezable); + void Deactivate(FreezableT* freezable); + void StartGlobalBusyPeriod(); + void StartGlobalIdlePeriod(); + void StartLocalBusyPeriod(); + void StartLocalIdlePeriod(); + + friend class TFreezable; + friend class TConsumer; +}; + +/////////////////////////////////////////////////////////////////////////////// + +template +inline +void TConsumer::Activate() +{ + if (DeactIdx != IsActive) { // Avoid double activation + Freezable->Activate(this); + } +} + +template +inline +void TConsumer::Deactivate() +{ + if (DeactIdx == IsActive) { + Freezable->Deactivate(this); + } +} + +template +void TConsumer::Detach() +{ + if (DeactIdx == IsActive) { + Freezable->Deactivate(this); + Freezable->Detach(this); + } else if (DeactIdx != IsDetached) { + Freezable->Detach(this); + } + DeactIdx = IsDetached; +} + +template +inline +typename TRes::TTag TConsumer::ResetConsumed() +{ + TTag result = Consumed; + Consumed = 0; + return result; +} + +template +inline +void TConsumer::Print(IOutputStream& out) const +{ + out << "Weight = " << Weight << Endl + << "HolTag = " << HolTag << Endl + << "GlobalBusyPeriod = " << GlobalBusyPeriod << Endl + << "Borrowed = " << Counters->Borrowed << Endl + << "Donated = " << Counters->Donated << Endl + << "Usage = " << Counters->Usage << Endl + << "DeactIdx = " << DeactIdx << Endl; +} + +template +inline +TSchedulable* TFreezable::PopSchedulable() +{ + if (!Empty() && !Frozen) { + PopHeap(Heap.begin(), Heap.begin() + HeapEndIdx); + HeapEndIdx--; + THeapItem& item = Heap[HeapEndIdx]; + ConsumerT* consumer = item.Consumer; + + if (TSchedulable* schedulable = consumer->PopSchedulable()) { + Scheduler->VirtualTime = consumer->HolTag + Offset; + + // Try to immediatly fix any discrepancy between real and estimated costs + // (as long as it doesn't lead to negative cost) + TCost cost = schedulable->Cost + consumer->Underestimation; + if (cost >= 0) { + consumer->Underestimation = 0; + } else { + // lower consumer overestimation by schedulable cost, and allow "free" usage + consumer->Underestimation = cost; + cost = 0; + } + TTag duration = cost / consumer->Weight; + consumer->HolTag += duration; + consumer->Consumed += duration; + Scheduler->LatestFinish = Max(Scheduler->LatestFinish, consumer->HolTag); + + if (consumer->Empty()) { + consumer->DeactIdx = HeapEndIdx; + } else { + item.UpdateKey(); + HeapEndIdx++; + PushHeap(Heap.begin(), Heap.begin() + HeapEndIdx); + } + + GLOBAL_LWPROBE(SHOP_PROVIDER, PopSchedulable, + Scheduler->GetName(), Name, consumer->Name, + Scheduler->VirtualTime, Scheduler->GlobalBusyPeriod, + consumer->HolTag + Offset, schedulable->Cost, + cost - schedulable->Cost, consumer->Weight, duration); + + return schedulable; + } else { + // Consumer turns to be inactive -- just deactivate it and repeat + GLOBAL_LWPROBE(SHOP_PROVIDER, DeactivateImplicit, + Scheduler->GetName(), Name, consumer->Name, + Scheduler->VirtualTime, Scheduler->GlobalBusyPeriod, + consumer->HolTag, Frozen); + consumer->DeactIdx = HeapEndIdx; + return nullptr; + } + } else { + return nullptr; + } +} + +template +inline +bool TFreezable::Empty() const +{ + return HeapEndIdx == 0; +} + +template +template +inline +size_t TFreezable::ActivateConsumers(TPredicate&& predicate) +{ + size_t prevHeapEndIdx = HeapEndIdx; + for (auto i = Heap.begin() + HeapEndIdx, e = Heap.end(); i != e; ++i) { + ConsumerT* consumer = i->Consumer; + if (predicate(consumer)) { // Consumer should be activated + Y_ASSERT(consumer->DeactIdx >= 0); + Insert(consumer); + } + } + size_t inserted = HeapEndIdx - prevHeapEndIdx; + if (prevHeapEndIdx == 0 && inserted > 0 && !Frozen) { + Scheduler->Activate(this); + } + return inserted; +} + +template +inline +void TFreezable::Deactivate() +{ + if (Frozen) { + Unfreeze(); + } + if (!Empty()) { + Scheduler->Deactivate(this); + } +} + +template +inline +void TFreezable::Freeze() +{ + Y_ASSERT(!Frozen); + Scheduler->FrozenCount++; + if (!Empty()) { + Scheduler->Deactivate(this); + } + Frozen = true; + LastFreeze = Scheduler->VirtualTime; + GLOBAL_LWPROBE(SHOP_PROVIDER, Freeze, + Scheduler->GetName(), Name, + Scheduler->VirtualTime, Scheduler->GlobalBusyPeriod, GlobalBusyPeriod, + Scheduler->FrozenCount, Offset); +} + +template +inline +void TFreezable::Unfreeze() +{ + Y_ASSERT(Frozen); + Frozen = false; + Offset = Offset + Scheduler->VirtualTime - LastFreeze; + GLOBAL_LWPROBE(SHOP_PROVIDER, Unfreeze, + Scheduler->GetName(), Name, + Scheduler->VirtualTime, Scheduler->GlobalBusyPeriod, GlobalBusyPeriod, + Scheduler->FrozenCount, Offset); + if (!Empty()) { + Scheduler->Activate(this); + Scheduler->FrozenCount--; + } else { + Scheduler->FrozenCount--; + if (Scheduler->Empty()) { + Scheduler->StartGlobalIdlePeriod(); + } + } +} + +template +inline +void TFreezable::Activate(ConsumerT* consumer) +{ + bool wasEmpty = Empty(); + Insert(consumer); + if (!Frozen && wasEmpty) { + Scheduler->Activate(this); + } +} + +template +inline +void TFreezable::Insert(ConsumerT* consumer) +{ + // Update consumer's tag + if (consumer->GlobalBusyPeriod != Scheduler->GlobalBusyPeriod) { + consumer->GlobalBusyPeriod = Scheduler->GlobalBusyPeriod; + consumer->HolTag = TTag(); + // Estimation errors of pervious busy period does not matter any more + consumer->Underestimation = TCost(); + if (GlobalBusyPeriod != Scheduler->GlobalBusyPeriod) { + GlobalBusyPeriod = Scheduler->GlobalBusyPeriod; + Offset = TTag(); + } + } + TTag vtime = (Frozen? LastFreeze: Scheduler->VirtualTime); + TTag selfvtime = vtime - Offset; + consumer->HolTag = Max(consumer->HolTag, selfvtime); + + // Insert consumer into attached vector (if detached) + Y_ASSERT(consumer->DeactIdx != IsActive); + if (consumer->DeactIdx == IsDetached) { + consumer->DeactIdx = Heap.size(); + Heap.emplace_back(consumer); + } + + // Swap consumer in place to push into heap + i64 deactIdx = consumer->DeactIdx; + THeapItem& place = Heap[HeapEndIdx]; + if (deactIdx != HeapEndIdx) { + THeapItem& oldItem = Heap[deactIdx]; + DoSwap(place, oldItem); + oldItem.Consumer->DeactIdx = deactIdx; + } + place.UpdateKey(); + + // Push into active consumers heap + HeapEndIdx++; + PushHeap(Heap.begin(), Heap.begin() + HeapEndIdx); + consumer->DeactIdx = IsActive; + GLOBAL_LWPROBE(SHOP_PROVIDER, Activate, + Scheduler->GetName(), Name, consumer->Name, + Scheduler->VirtualTime, Scheduler->GlobalBusyPeriod, + consumer->HolTag, Frozen); +} + +template +inline +void TFreezable::Deactivate(ConsumerT* consumer) +{ + GLOBAL_LWPROBE(SHOP_PROVIDER, Deactivate, + Scheduler->GetName(), Name, consumer->Name, + Scheduler->VirtualTime, Scheduler->GlobalBusyPeriod, + consumer->HolTag, Frozen); + + Y_ASSERT(consumer->DeactIdx == IsActive); + for (auto i = Heap.begin(), e = Heap.begin() + HeapEndIdx; i != e; ++i) { + if (i->Consumer == consumer) { + HeapEndIdx--; + i64 idx = i - Heap.begin(); + if (HeapEndIdx != idx) { + DoSwap(Heap[HeapEndIdx], Heap[idx]); + } + consumer->DeactIdx = HeapEndIdx; + if (!Empty()) { + MakeHeap(Heap.begin(), Heap.begin() + HeapEndIdx); + } else { + Scheduler->Deactivate(this); + } + return; + } + } + Y_ABORT_UNLESS("trying to deactivate unknown consumer"); +} + +template +inline +void TFreezable::Detach(ConsumerT* consumer) +{ + Y_ASSERT(consumer->DeactIdx >= 0); + i64 oldIdx = consumer->DeactIdx; + i64 newIdx = Heap.size() - 1; + if (oldIdx != newIdx) { + DoSwap(Heap[oldIdx], Heap[newIdx]); + Heap[oldIdx].Consumer->DeactIdx = oldIdx; + } + Heap.pop_back(); +} + +template +inline +TSchedulable* TScheduler::PopSchedulable() +{ + while (!Empty()) { + auto iter = std::min_element(Freezables.begin(), Freezables.end(), TCmp()); + + FreezableT* freezable = *iter; + + TSchedulable* schedulable = freezable->PopSchedulable(); + if (schedulable) { + GlobalBusyPeriodCost = GlobalBusyPeriodCost + schedulable->Cost; + GlobalBusyPeriodPops++; + LocalBusyPeriodCost = LocalBusyPeriodCost + schedulable->Cost; + LocalBusyPeriodPops++; + } + + if (freezable->Empty()) { + if (Freezables.size() > 1) { + DoSwap(*iter, Freezables.back()); + Freezables.pop_back(); + } else { + Freezables.pop_back(); + StartGlobalIdlePeriod(); + StartLocalIdlePeriod(); + if (this->GetFreezable()) { // Deactivate parent if it is not root scheduler + TConsumer::Deactivate(); + } + } + } + + if (schedulable) { + return schedulable; + } + } + return nullptr; +} + +template +inline +bool TScheduler::Empty() const +{ + return Freezables.empty(); +} + +template +inline +void TScheduler::Clear() +{ + TVector consumers; + for (FreezableT* freezable : Freezables) { + for (auto item : freezable->Heap) { + // Delay modification of Freezables (we are iterating over it) + consumers.push_back(item.Consumer); + } + } + for (ConsumerT* consumer : consumers) { + consumer->Detach(); + } + Y_ASSERT(Freezables.empty()); +} + +template +inline +void TScheduler::UpdateCounters() +{ + TCountersAggregator, TTag> aggr; + for (FreezableT* freezable : Freezables) { + for (auto item : freezable->Heap) { + aggr.Add(item.Consumer); + item.Consumer->UpdateCounters(); // Recurse into children + } + } + aggr.Apply(); +} + +template +inline +void TScheduler::Print(IOutputStream& out) const +{ + out << "FrozenCount = " << FrozenCount << Endl + << "VirtualTime = " << VirtualTime << Endl + << "LatestFinish = " << LatestFinish << Endl + << "GlobalBusyPeriod = " << GlobalBusyPeriod << Endl + << "GlobalBusyPeriodCost = " << GlobalBusyPeriodCost << Endl + << "GlobalBusyPeriodPops = " << GlobalBusyPeriodPops << Endl + << "GlobalPeriodTs = " << GlobalPeriodTs << Endl + << "GlobalIdlePeriodDuration = " << GlobalIdlePeriodDuration << Endl + << "LocalBusyPeriod = " << LocalBusyPeriod << Endl + << "LocalBusyPeriodCost = " << LocalBusyPeriodCost << Endl + << "LocalBusyPeriodPops = " << LocalBusyPeriodPops << Endl + << "LocalPeriodTs = " << LocalPeriodTs << Endl + << "LocalIdlePeriodDuration = " << LocalIdlePeriodDuration << Endl; + if (this->GetFreezable()) { + TConsumer::Print(out); + } +} + +template +void TScheduler::DebugPrint(IOutputStream& out) const +{ + for (const auto& freezable : Freezables) { + i64 idx = 0; + for (const auto& item: freezable->Heap) { + out << (idx < freezable->HeapEndIdx? "* ": " ") + << "key:" << item.Key + << " tag:" << item.Consumer->HolTag + << " didx:" << item.Consumer->DeactIdx << Endl; + idx++; + } + } + out << Endl; +} + +template +inline +void TScheduler::Activate(FreezableT* freezable) +{ + Y_ASSERT(!freezable->Frozen); + bool wasEmpty = Empty(); + Freezables.push_back(freezable); + if (wasEmpty) { + StartGlobalBusyPeriod(); + StartLocalBusyPeriod(); + if (this->GetFreezable()) { // Activate parent if it is not root scheduler + TConsumer::Activate(); + } + } +} + +template +inline +void TScheduler::Deactivate(FreezableT* freezable) +{ + Y_ASSERT(!freezable->Frozen); + Freezables.erase(std::remove(Freezables.begin(), Freezables.end(), freezable), Freezables.end()); + if (Empty()) { + StartGlobalIdlePeriod(); + StartLocalIdlePeriod(); + if (this->GetFreezable()) { // Deactivate parent if it is not root scheduler + TConsumer::Deactivate(); + } + } +} + +template +inline +void TScheduler::StartGlobalBusyPeriod() +{ + if (FrozenCount == 0) { + Y_ASSERT(GlobalIdlePeriodDuration == ui64(-1)); + ui64 now = GetCycleCount(); + GlobalIdlePeriodDuration = GlobalPeriodTs? Duration(GlobalPeriodTs, now): 0; + GlobalPeriodTs = now; + } +} + +template +inline +void TScheduler::StartGlobalIdlePeriod() +{ + if (FrozenCount == 0 && GlobalIdlePeriodDuration != ui64(-1)) { + ui64 now = GetCycleCount(); + ui64 busyPeriodDuration = Duration(GlobalPeriodTs, now); + GlobalPeriodTs = now; + GLOBAL_LWPROBE(SHOP_PROVIDER, GlobalBusyPeriod, this->GetName(), + VirtualTime, GlobalBusyPeriod, + GlobalBusyPeriodPops, GlobalBusyPeriodCost, + CyclesToMs(GlobalIdlePeriodDuration), CyclesToMs(busyPeriodDuration), + double(busyPeriodDuration) / (GlobalIdlePeriodDuration + busyPeriodDuration)); + GlobalBusyPeriod++; + GlobalBusyPeriodCost = TCost(); + GlobalBusyPeriodPops = 0; + GlobalIdlePeriodDuration = ui64(-1); + + VirtualTime = TTag(); + LatestFinish = TTag(); + } +} + +template +inline +void TScheduler::StartLocalBusyPeriod() +{ + Y_ASSERT(LocalIdlePeriodDuration == ui64(-1)); + ui64 now = GetCycleCount(); + LocalIdlePeriodDuration = LocalPeriodTs? Duration(LocalPeriodTs, now): 0; + LocalPeriodTs = now; +} + +template +inline +void TScheduler::StartLocalIdlePeriod() +{ + Y_ASSERT(LocalIdlePeriodDuration != ui64(-1)); + ui64 now = GetCycleCount(); + ui64 busyPeriodDuration = Duration(LocalPeriodTs, now); + LocalPeriodTs = now; + GLOBAL_LWPROBE(SHOP_PROVIDER, LocalBusyPeriod, this->GetName(), + VirtualTime, LocalBusyPeriod, + LocalBusyPeriodPops, LocalBusyPeriodCost, + CyclesToMs(LocalIdlePeriodDuration), CyclesToMs(busyPeriodDuration), + double(busyPeriodDuration) / (LocalIdlePeriodDuration + busyPeriodDuration)); + LocalBusyPeriod++; + LocalBusyPeriodCost = TCost(); + LocalBusyPeriodPops = 0; + LocalIdlePeriodDuration = ui64(-1); + + VirtualTime = LatestFinish; +} + +} diff --git a/ydb/library/shop/shop.cpp b/ydb/library/shop/shop.cpp new file mode 100644 index 000000000000..528e713ad1d2 --- /dev/null +++ b/ydb/library/shop/shop.cpp @@ -0,0 +1,363 @@ +#include "shop.h" +#include "probes.h" + +#include +#include + +namespace NShop { + +LWTRACE_USING(SHOP_PROVIDER); + +TOp::TOp(const TStage* stage) + : DepsLeft(stage->Depends.size()) +{} + +const char* TOp::StateName() const +{ + switch (State) { + case EState::Wait: return "Wait"; + case EState::Proc: return "Proc"; + case EState::Done: return "Done"; + case EState::Fail: return "Fail"; + case EState::Skip: return "Skip"; + } + Y_ABORT("Unexpected"); +} + +size_t TFlow::AddStage(std::initializer_list depends) +{ + Stage.emplace_back(); + size_t sid = Stage.size() - 1; + TStage& desc = Stage.back(); + desc.MachineId = sid; + desc.Depends.reserve(depends.size()); + for (size_t idx : depends) { + desc.Depends.push_back(idx); + Y_ABORT_UNLESS(idx < Stage.size()); + Stage[idx].Blocks.push_back(sid); + } + return sid; +} + +size_t TFlow::AddStage(ui64 machineId, std::initializer_list depends) +{ + ui64 sid = AddStage(depends); + Stage[sid].MachineId = machineId; + return sid; +} + +TString TFlow::DebugDump() const +{ + TStringStream ss; + ss << "=== TFlow ===" << Endl; + ss << "Name:" << Name << Endl; + size_t sid = 0; + for (const TStage& stage : Stage) { + ss << sid++ << ") Name:" << stage.Name + << " MachineId:" << stage.MachineId + << " Blocks:["; + for (auto x : stage.Blocks) { + ss << " " << x; + } + ss << " ] Depends:["; + for (auto x : stage.Depends) { + ss << " " << x; + } + ss << " ]" << Endl; + } + return ss.Str(); +} + +void TJob::AddOp(ui64 estcost) +{ + Y_ABORT_UNLESS(Op.size() < Flow->StageCount()); + Op.emplace_back(Flow->GetStage(Op.size())); + TOp& op = Op.back(); + op.EstCost = estcost; +} + +TString TJob::DebugDump() const +{ + TStringStream ss; + if (Flow) { + ss << Flow->DebugDump() << Endl; + } else { + ss << "Flow:nullptr" << Endl; + } + ss << "=== TJob ===" << Endl; + ss << "JobId:" << JobId << Endl; + ss << "OpsLeft:" << OpsLeft << Endl; + ss << "OpsInFly:" << OpsInFly << Endl; + ss << "Failed:" << Failed << Endl; + ss << "StartTs:" << StartTs << Endl; + size_t sid = 0; + for (const TOp& op : Op) { + ss << sid++ << ")" + << " DepsLeft:" << op.DepsLeft + << " StartTs:" << op.StartTs + << " State:" << op.StateName() + << Endl; + } + return ss.Str(); +} + +void TShop::StartJob(TJob* job, double now) +{ + Y_ABORT_UNLESS(job->Flow); + Y_ABORT_UNLESS(job->Op.size() == job->Flow->StageCount(), "opSize:%lu != flowSize:%lu", + job->Op.size(), job->Flow->StageCount()); + + job->JobId = ++LastJobId; + job->OpsLeft = job->Op.size(); + job->StartTs = GetCycleCount(); + LWPROBE(StartJob, Name, job->Flow->Name, job->JobId); + + RunOperation(job, 0, now); +} + +void TShop::CancelJob(TJob* job) +{ + job->Failed = true; + job->Canceled = true; + LWPROBE(CancelJob, Name, job->Flow->Name, job->JobId); +} + +void TShop::JobFinished(TJob* job) +{ + job->FinishTs = GetCycleCount(); + job->Duration = Duration(job->StartTs, job->FinishTs); + LWPROBE(JobFinished, Name, job->Flow->Name, job->JobId, CyclesToMs(job->Duration)); +} + +void TShop::SkipOperation(TJob* job, size_t sid) +{ + // Mark operation to be skipped + job->GetOp(sid)->State = TOp::EState::Skip; + LWPROBE(SkipOperation, Name, job->Flow->Name, job->JobId, sid, + job->Flow->GetStage(sid)->MachineId); + OnOperationAbort(job, sid); +} + +// Returns true if job has been finished +bool TShop::OperationFinished(TJob* job, size_t sid, ui64 realcost, bool success, double now) +{ + // Monitoring + TOp* op = job->GetOp(sid); + op->FinishTs = GetCycleCount(); + op->Duration = Duration(op->StartTs, op->FinishTs); + + // Change state + job->OpsInFly--; + job->OpsLeft--; + LWPROBE(OperationFinished, Name, job->Flow->Name, job->JobId, sid, + job->Flow->GetStage(sid)->MachineId, + realcost, success, CyclesToMs(op->Duration)); + if (op->State != TOp::EState::Skip) { + Y_ABORT_UNLESS(op->State == TOp::EState::Proc); + op->State = success? TOp::EState::Done : TOp::EState::Fail; + op->Machine->Count(op); + if (!success) { + job->Failed = true; + } + OnOperationFinished(job, sid, realcost, now); + } else { + op->Machine->Count(op); + } + + if (!job->Failed) { + if (job->OpsLeft == 0) { + JobFinished(job); + return true; + } else { + // Run dependent operations + for (size_t i : job->Flow->GetStage(sid)->Blocks) { + if (--job->GetOp(i)->DepsLeft == 0) { + if (RunOperation(job, i, now)) { + return true; + } + } + } + } + } else { + // Finish failed/canceled job immediately if all in fly ops are finished + // and don't start any other operations for this job + if (job->OpsInFly == 0) { + for (size_t op2Idx = 0; op2Idx < job->Op.size(); op2Idx++) { + if (job->GetOp(op2Idx)->State == TOp::EState::Wait) { + OnOperationAbort(job, op2Idx); + } + } + JobFinished(job); + return true; + } else { + return false; // In fly ops remain -- wait for them to finish + } + } + Y_ABORT_UNLESS(job->OpsInFly > 0, "no more ops in flight\n%s", job->DebugDump().data()); + return false; +} + +// Returns true if job has been finished (3 reasons: skip/cancel/done) +bool TShop::RunOperation(TJob* job, size_t sid, double now) +{ + job->OpsInFly++; + + Y_ABORT_UNLESS(job->Flow); + TOp::EState state = job->GetOp(sid)->State; + if (state != TOp::EState::Skip) { + Y_ABORT_UNLESS(job->GetOp(sid)->State == TOp::EState::Wait); + job->GetOp(sid)->State = TOp::EState::Proc; + if (TMachine* machine = GetMachine(job, sid)) { + return machine->StartOperation(job, sid); + } else { + // Required machine is not available; job failed + LWPROBE(NoMachine, Name, job->Flow->Name, job->JobId, sid, + job->Flow->GetStage(sid)->MachineId); + return OperationFinished(job, sid, 0, false, now); + } + } else { + return OperationFinished(job, sid, 0, true, now); + } +} + +TMachine::TMachine(TShop* shop) + : Shop(shop) +{} + +bool TMachine::StartOperation(TJob* job, size_t sid) +{ + LWPROBE(StartOperation, Shop->GetName(), job->Flow->GetName(), job->JobId, sid, + job->Flow->GetStage(sid)->MachineId, + job->GetOp(sid)->EstCost); + TOp* op = job->GetOp(sid); + op->StartTs = GetCycleCount(); + op->Machine = this; + return false; +} + +void TMachine::Count(const TOp* op) +{ + if (Counters) { + Counters->Count(op); + } +} + +void TProcMonCounters::Count(const TOp* op) +{ +#define INC_COUNTER(name) Counters.Set##name(Counters.Get##name() + 1) + if (op->State == TOp::EState::Done) { + INC_COUNTER(Done); + } else if (op->State == TOp::EState::Fail) { + INC_COUNTER(Failed); + } else if (op->State == TOp::EState::Skip) { + INC_COUNTER(Aborted); + } + double timeMs = CyclesToMs(op->Duration); + if (timeMs <= 30.0) { + if (timeMs <= 3.0) { + if (timeMs <= 1.0) { + INC_COUNTER(Time1ms); + } else { + INC_COUNTER(Time3ms); + } + } else { + if (timeMs <= 10.0) { + INC_COUNTER(Time10ms); + } else { + INC_COUNTER(Time30ms); + } + } + } else if (timeMs <= 3000.0) { + if (timeMs <= 300.0) { + if (timeMs <= 100.0) { + INC_COUNTER(Time100ms); + } else { + INC_COUNTER(Time300ms); + } + } else { + if (timeMs <= 1000.0) { + INC_COUNTER(Time1000ms); + } else { + INC_COUNTER(Time3000ms); + } + } + } else { + if (timeMs <= 30000.0) { + if (timeMs <= 10000.0) { + INC_COUNTER(Time10000ms); + } else { + INC_COUNTER(Time30000ms); + } + } else { + if (timeMs <= 100000.0) { + INC_COUNTER(Time100000ms); + } else { + INC_COUNTER(TimeGt100000ms); + } + } + } +#undef INC_COUNTER +} + +void TMachineCtl::Transition(TFlowCtl::EStateTransition st) +{ + switch (st) { + case TFlowCtl::None: break; + case TFlowCtl::Closed: Freeze(); break; + case TFlowCtl::Opened: Unfreeze(); break; + } +} + +void TShopCtl::Configure(TMachineCtl* ctl, const TFlowCtlConfig& cfg, double now) +{ + ctl->Transition(ctl->GetFlowCtl()->ConfigureST(cfg, now)); +} + +void TShopCtl::ArriveJob(TJob* job, double now) +{ + // Flow control arrive for all operations + for (size_t sid = 0; sid < job->Op.size(); sid++) { + ArriveJobStage(job, sid, now); + } +} + +void TShopCtl::ArriveJobStage(TJob* job, size_t sid, double now) +{ + TOp* op = job->GetOp(sid); + if (TMachineCtl* ctl = GetMachineCtl(job, sid)) { + ctl->Transition(ctl->GetFlowCtl()->ArriveST(*op, op->EstCost, now)); + } else { + // OpId == 0 is marker for disabled flow control + Y_ABORT_UNLESS(op->OpId == 0, "operation not marked with OpId=0"); + } +} + +void TShopCtl::DepartJobStage(TJob* job, size_t sid, ui64 realcost, double now) +{ + if (TMachineCtl* ctl = GetMachineCtl(job, sid)) { + Depart(ctl, job->GetOp(sid), realcost, now); + } +} + +void TShopCtl::Depart(TMachineCtl* ctl, TFcOp* op, ui64 realcost, double now) +{ + if (op->HasArrived()) { + ctl->Transition(ctl->GetFlowCtl()->DepartST(*op, realcost, now)); + } +} + +void TShopCtl::AbortJobStage(TJob* job, size_t sid) +{ + if (TMachineCtl* ctl = GetMachineCtl(job, sid)) { + Abort(ctl, job->GetOp(sid)); + } +} + +void TShopCtl::Abort(TMachineCtl* ctl, TFcOp* op) +{ + if (op->HasArrived()) { + ctl->Transition(ctl->GetFlowCtl()->AbortST(*op)); + } +} + +} diff --git a/ydb/library/shop/shop.h b/ydb/library/shop/shop.h new file mode 100644 index 000000000000..151e7b863f44 --- /dev/null +++ b/ydb/library/shop/shop.h @@ -0,0 +1,195 @@ +#pragma once + +#include "flowctl.h" + +#include +#include +#include +#include + +#include + +namespace NShop { + +struct TStage; +class TFlow; +struct TOp; +struct TJob; +class TMachine; +class TShop; + +struct TStage { + ui64 MachineId; + TString Name; + TStackVec Depends; // Idx of stages it depends on + TStackVec Blocks; // Idx of stages dependent on it +}; + +class TFlow { +private: + TStackVec Stage; // Topologicaly sorted DAG of stages + TString Name; +public: + virtual ~TFlow() {} + + size_t AddStage(std::initializer_list depends); + size_t AddStage(ui64 machineId, std::initializer_list depends); + + // Accessors + void SetName(const TString& name) { Name = name; } + TString GetName() const { return Name; } + const TStage* GetStage(size_t idx) const { return &Stage[idx]; } + size_t StageCount() const { return Stage.size(); } + + TString DebugDump() const; + + friend class TShop; +}; + +struct TOp: public TFcOp { + enum class EState : ui8 { + Wait = 0, // Awaits it's dependencies to be done + Proc = 1, // Is processing on machine + Done = 2, // Already processed + Fail = 3, // Already processed, but unsuccessfully + Skip = 4, // Not going to be processed + }; + + TMachine* Machine = nullptr; // Machine assigned for processing + + EState State = EState::Wait; + ui64 DepsLeft = 0; // Count of blocker operation left to be done + + ui64 StartTs = 0; // in cycles + ui64 FinishTs = 0; // in cycles + ui64 Duration = 0; // in cycles + + TOp() {} + explicit TOp(const TStage* stage); + + const char* StateName() const; +}; + +struct TJob { + TFlow* Flow = nullptr; + TStackVec Op; + ui64 JobId = 0; + ui64 OpsLeft = 0; + ui64 OpsInFly = 0; + bool Failed = false; + bool Canceled = false; + + ui64 StartTs = 0; // in cycles + ui64 FinishTs = 0; // in cycles + ui64 Duration = 0; // in cycles + + void AddOp(ui64 estcost); + TOp* GetOp(size_t idx) { return &Op[idx]; } + const TOp* GetOp(size_t idx) const { return &Op[idx]; } + + TString DebugDump() const; +}; + +class IMonCounters { +public: + virtual ~IMonCounters() {} + virtual void Count(const TOp* op) = 0; +}; + +class TProcMonCounters : public IMonCounters { +private: + TProcCounters Counters; +public: + void Count(const TOp* op) override; + const TProcCounters& GetCounters() const { return Counters; } +}; + +class TMachine { +private: + TShop* Shop; + TString Name; + THolder Counters; +public: + explicit TMachine(TShop* shop); + virtual ~TMachine() {} + + TShop* GetShop() { return Shop; } + void SetName(const TString& name) { Name = name; } + TString GetName() const { return Name; } + void SetCounters(IMonCounters* counters) { Counters.Reset(counters); } + + // Execute sync or start async operation processing. + // TShop::OperationFinished() must be called on finish + // Returns: + // - result of sync-called OperationFinished() + // - false in case of async operation + virtual bool StartOperation(TJob* job, size_t sid); + + // Monitoring + void Count(const TOp* op); +}; + +class TShop { +private: + ui64 LastJobId = 0; + TString Name; +public: + virtual ~TShop() {} + + void SetName(const TString& name) { Name = name; } + TString GetName() const { return Name; } + + // Machines + virtual TMachine* GetMachine(const TJob* job, size_t sid) = 0; + + // Jobs + void StartJob(TJob* job, double now); + void CancelJob(TJob* job); + virtual void JobFinished(TJob* job); + + // Operations + void SkipOperation(TJob* job, size_t sid); + bool OperationFinished(TJob* job, size_t sid, ui64 realcost, bool success, double now); + +protected: + virtual void OnOperationFinished(TJob* job, size_t sid, ui64 realcost, double now) = 0; + virtual void OnOperationAbort(TJob* job, size_t sid) = 0; + +private: + bool RunOperation(TJob* job, size_t sid, double now); +}; + +class TMachineCtl { +private: + TFlowCtlPtr FlowCtl; +public: + explicit TMachineCtl(TFlowCtl* flowCtl) + : FlowCtl(flowCtl) + {} + + TFlowCtl* GetFlowCtl() { return FlowCtl.Get(); } + + void Transition(TFlowCtl::EStateTransition st); + + // Flow control callbacks (e.g. stop/start incoming job flows in scheduler) + virtual void Freeze() = 0; + virtual void Unfreeze() = 0; +}; + +class TShopCtl { +public: + void Configure(TMachineCtl* ctl, const TFlowCtlConfig& cfg, double now); + + virtual TMachineCtl* GetMachineCtl(const TJob* job, size_t sid) = 0; + + void ArriveJob(TJob* job, double now); + void DepartJobStage(TJob* job, size_t sid, ui64 realcost, double now); + void Depart(TMachineCtl* ctl, TFcOp* op, ui64 realcost, double now); + void AbortJobStage(TJob* job, size_t sid); + void Abort(TMachineCtl* ctl, TFcOp* op); + +private: + void ArriveJobStage(TJob* job, size_t sid, double now); +}; + +} diff --git a/ydb/library/shop/shop_state.h b/ydb/library/shop/shop_state.h new file mode 100644 index 000000000000..66807a173a17 --- /dev/null +++ b/ydb/library/shop/shop_state.h @@ -0,0 +1,122 @@ +#pragma once + +#include +#include + +namespace NShop { + +using TMachineIdx = ui8; + +/////////////////////////////////////////////////////////////////////////////// + +struct TMachineMask { + using TIdx = TMachineIdx; + using TMask = ui64; + constexpr static TMask One = TMask(1); + + TMask Mask; + + TMachineMask(TMask mask = 0) + : Mask(mask) + {} + + operator TMask() const + { + return Mask; + } + + void Set(TIdx idx) + { + Mask = Mask | (One << idx); + } + + void SetAll(TMask mask) + { + Mask = Mask | mask; + } + + void Reset(TIdx idx) + { + Mask = Mask & ~(One << idx) ; + } + + void ResetAll(TMask mask) + { + Mask = Mask & ~mask; + } + + bool Get(TIdx idx) const + { + return Mask & (One << idx); + } + + bool IsZero() const + { + return Mask == 0; + } + + TString ToString(TIdx size) const + { + TStringStream ss; + for (TIdx idx = 0; idx < size; idx++) { + if (idx % 8 == 0 && idx) { + ss << '-'; // bytes separator + } + ss << (Get(idx)? '1': '0'); + } + return ss.Str(); + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +struct TShopState { + TMachineMask Warm; // machineIdx -> (1=warm | 0=frozen) + TMachineIdx MachineCount; + static constexpr TMachineIdx MaxMachines = 64; // we have only 64 bits, it must be enough for now + + TShopState(TMachineIdx machineCount = 1) + : Warm((TMachineMask::One << machineCount) - 1) // all machines are warm + , MachineCount(machineCount) + {} + + void Freeze(TMachineIdx idx) + { + Y_ASSERT(idx < MachineCount); + Warm.Reset(idx); + } + + void Unfreeze(TMachineIdx idx) + { + Y_ASSERT(idx < MachineCount); + Warm.Set(idx); + } + + void AddMachine() + { + Warm.Set(MachineCount); // New machine is warm at start + MachineCount++; + } + + bool AllFrozen() const + { + return Warm.Mask == 0; + } + + bool HasFrozen() const + { + if (Y_LIKELY(MachineCount < 8*sizeof(TMachineMask::TMask))) { + return Warm.Mask != ((TMachineMask::One << MachineCount) - 1); + } else { + return Warm.Mask != TMachineMask::TMask(-1); + } + } + + void Print(IOutputStream& out) const + { + out << "MachineCount = " << int(MachineCount) << Endl + << "Warm = [" << Warm.ToString(MachineCount) << "]" << Endl; + } +}; + +} diff --git a/ydb/library/shop/sim_estimator/estimator.css b/ydb/library/shop/sim_estimator/estimator.css new file mode 100644 index 000000000000..fa1d99f535c9 --- /dev/null +++ b/ydb/library/shop/sim_estimator/estimator.css @@ -0,0 +1,32 @@ +html,body,#wrapper { + width: 100%; + height: 100%; + margin: 0px; +} + +body { + font: 14px Helvetica Neue; + text-rendering: optimizeLegibility; + margin-top: 1em; + overflow-y: scroll; +} + +.data-table { + border: 2px; + border-color: black; +} + +.data-table-head { + +} + +.chart { + font-family: Arial, sans-serif; + font-size: 12px; +} + +.axis path,.axis line { + fill: none; + stroke: #000; + shape-rendering: crispEdges; +} diff --git a/ydb/library/shop/sim_estimator/estimator.html b/ydb/library/shop/sim_estimator/estimator.html new file mode 100644 index 000000000000..ce3d405b0b30 --- /dev/null +++ b/ydb/library/shop/sim_estimator/estimator.html @@ -0,0 +1,131 @@ + + + + + + + Estimators + + + + + + + + + +
+

Moving Simple Linear Regression

+

This page allow you to enter any data and check how it is interpreted by online moving simple linear regression (MSLR). + MSLR is algorithm that trains regression model online using incoming data and tries to minimize exponentially + weighted sum of squared errors, i.e. more recent points get more weight based on reaction factor (0 to 1) +

+

Data

+
+
+
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+

Initial State

+
+
+
+ +
+
Goal
+ +
Y
+
+
+
+
+
+
+
+ +
+
Feature
+ +
X
+
+
+
+
+
+
+
+ +
+
Feature Square
+ +
X*X
+
+
+
+
+
+
+
+ +
+
Product
+ +
X*Y
+
+
+
+
+

Model

+
+
+
+
+
+
+ + + + + + + + diff --git a/ydb/library/shop/sim_estimator/estimator.js b/ydb/library/shop/sim_estimator/estimator.js new file mode 100644 index 000000000000..29ca1854752c --- /dev/null +++ b/ydb/library/shop/sim_estimator/estimator.js @@ -0,0 +1,124 @@ +d3.estimator = function (tableData) { + function estimator() { } + + function createAll() { + // create empty table + table.append("table") + .attr("class", "table data-table") + ; + + table.append("thead").append("tr").attr("class", "data-table-head") + .selectAll("td") + .data(attributes) + .enter().append("th") + .text(function (d) { return d.name; }) + ; + + table.append("tbody"); + + // initialize initial state editor + //d3.select("input#throughput").on('keypress', onKeyPress); + } + + function createTableData(tableData) { + var data = []; + for (var i = 0; i < tableData.length; i++) { + var row = []; + for (var a = 0; a < attributes.length; a++) { + if (attributes[a].type) { + row.push(tableData[i][attributes[a].name]); + } else { + row.push(i); // save row index for remove operation + } + } + data.push(row); + } + + var tr = table.select("tbody").selectAll("tr.data-table-row") + .data(data) + ; + tr.exit().remove(); + var trEnterUpd = tr.enter().append("tr") + .attr("class", "data-table-row") + .merge(tr) // enter + update + ; + + var td = trEnterUpd.selectAll("td") + .data(function (d) { return d; }) + ; + + td.enter().append("td") + .merge(td) // enter + update + .attr("contenteditable", function (d, i) { return attributes[i].type ? "true" : null; }) + .text(function (d, i) { return attributes[i].type ? d : null; }) + //.on('keypress', onKeyPress) + .attr("class", function (d, i) { + return "data-cell data-cell-" + + (attributes[i].type ? attributes[i].type : attributes[i].class) + ; + }) + ; + } + + estimator.GetAverage = function () { + return GoalMean; + } + + estimator.GetEstimation = function (feature) { + return GoalMean + GetSlope() * (feature - FeatureMean); + } + + estimator.GetSlope = function () { + var disp = FeatureSqMean - FeatureMean * FeatureMean; + if (disp > 1e-10) { + return (GoalFeatureMean - GoalMean * FeatureMean) / disp; + } else { + return GetAverage(); + } + } + + estimator.Update = function (goal, feature) { + GoalMean = OldFactor * GoalMean + NewFactor * goal; + FeatureMean = OldFactor * FeatureMean + NewFactor * feature; + FeatureSqMean = OldFactor * FeatureSqMean + NewFactor * feature * feature; + GoalFeatureMean = OldFactor * GoalFeatureMean + NewFactor * goal * feature; + } + + var GoalMean = 1, + FeatureMean = 1, + FeatureSqMean = 1, + GoalFeatureMean = 1, + NewFactor = 0.3, + OldFactor = 1 - NewFactor + ; + + var attributes = [ + { name: "feature", type: "integer" }, + { name: "goal", type: "integer" }, + //{ name: "estimate", type: "integer" }, + //{ name: "error", type: "integer" }, + + // Remove button + { name: "", class: "btn-remove" } + ]; + + var margin = { + top: 20, + right: 40, + bottom: 20, + left: 80, + footer: 100, + }; + + var emptyRow = { + goal: 1, + feature: 1 + }; + + var table = d3.select("#data-table"); + + createAll(); + createTableData(tableData); + + return estimator; +} \ No newline at end of file diff --git a/ydb/library/shop/sim_flowctl/flowctlmain.cpp b/ydb/library/shop/sim_flowctl/flowctlmain.cpp new file mode 100644 index 000000000000..19b2a5ef1b18 --- /dev/null +++ b/ydb/library/shop/sim_flowctl/flowctlmain.cpp @@ -0,0 +1,588 @@ +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#define SIMFC_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ + PROBE(IncomingRequest, GROUPS("FcSimEvents"), \ + TYPES(ui64, TString, double, double), \ + NAMES("requestId","type","costSec","startTime")) \ + PROBE(ScheduleRequest, GROUPS("FcSimEvents"), \ + TYPES(ui64, TString, double), \ + NAMES("requestId","type","schedulerTimeSec")) \ + PROBE(DequeueRequest, GROUPS("FcSimEvents"), \ + TYPES(ui64, TString, double), \ + NAMES("requestId","type","queueTimeSec")) \ + PROBE(ExecuteRequest, GROUPS("FcSimEvents"), \ + TYPES(ui64, TString, double), \ + NAMES("requestId","type","execTimeSec")) \ + PROBE(WorkerStats, GROUPS("FcSimWorker"), \ + TYPES(double, double, double), \ + NAMES("idleTimeSec", "activeTimeSec", "totalTimeSec")) \ + PROBE(SystemStats, GROUPS("FcSimSystem"), \ + TYPES(double), \ + NAMES("utilization")) \ + PROBE(CompleteRequest, GROUPS("FcSimEvents"), \ + TYPES(ui64, TString, double, double, double, double), \ + NAMES("requestId", "type", "waitTimeSec", "totalTimeSec", "procTimeSec", "costSec")) \ +/**/ + +LWTRACE_DECLARE_PROVIDER(SIMFC_PROVIDER) +LWTRACE_DEFINE_PROVIDER(SIMFC_PROVIDER); + +namespace NFcSim { + +inline double Now() +{ + return CyclesToDuration(GetCycleCount()).SecondsFloat(); +} + +LWTRACE_USING(SIMFC_PROVIDER); + +using namespace NScheduling; +class TMyTask; +class TMyQueue; + +struct TRMeta { + double m; + double d; + double p; +}; + +// Config +int g_MonPort = 8080; +double g_AvgPeriodSec = 0.002; +double g_MaxPeriodSec = 0.001; +///TRMeta g_CostSec[] = {{0.5, 0.05, 0.05}, {0.02, 0.01, 1.0}}; // double peek +TRMeta g_CostSec[] = {{0.02, 0.01, 1.0}}; // small reqs +///TRMeta g_CostSec[] = {{0.02, 0.0, 1.0}}; // fixed cost +///TRMeta g_CostSec[] = {{0.2, 0.1, 1.0}}; // large reqs +TRMeta g_WaitSec[] = {{0.05, 0.005, 1.0}}; // 50ms wait +///TRMeta g_WaitSec[] = {{0.05, 0.000, 1.0}}; // fixed 50ms wait +///TRMeta g_WaitSec[] = {{0.005, 0.0005, 1.0}}; // 5ms wait +TDuration g_CompletePeriod = TDuration::MicroSeconds(100); +ui64 g_QuantumNs = 100 * 1000ull; +NShop::TFlowCtlConfig g_FcCfg; + +// Returns exponentially distributed random number (cuts if upperLimit exceeded) +double ExpRandom(double lambda, double upperLimit) +{ + return Min(upperLimit, -(1.0/lambda) * log(1 - RandomNumber())); +} + +// Returns ranged Gaussian distribution +double GaussRandom(double m, double d) +{ + while (true) { + double x = NormalRandom(m, d); + if (x >= m/3 && x <= m*3) { + return x; + } + } +} + +// Returns random value distributed according to sum of gaussian distributions +double GaussSumRandom(TRMeta* meta, size_t size) +{ + double p = RandomNumber(); + for (size_t i = 0; i < size - 1; i++) { + if (p < meta[i].p) { + return GaussRandom(meta[i].m, meta[i].d); + } + } + return GaussRandom(meta[size - 1].m, meta[size - 1].d); +} + +class TMyTask { +public: + TUCost Cost; // in microseconds + TUCost RealCost; // in microseconds + size_t Type; + TMyQueue* Queue = nullptr; + ui64 Id; + NHPTimer::STime Timer; + double SchedTime = 0.0; + double TotalTime = 0.0; + NShop::TFcOp FcOp; + TInstant CompleteDeadline; +public: + TMyTask(TUCost cost, TUCost realcost, size_t type, ui64 id) + : Cost(cost) + , RealCost(realcost) + , Type(type) + , Id(id) + { + NHPTimer::GetTime(&Timer); + } + + TUCost GetCost() const + { + return Cost; + } +}; + +class TMyQueue: public TDRRQueue { +public: + typedef TMyTask TTask; +public: + typedef TList TTasks; + TString Name; + TTasks Tasks; +public: // Interface for clients + TMyQueue(const TString& name, TWeight w = 1, TUCost maxBurst = 0) + : TDRRQueue(w, maxBurst) + , Name(name) + {} + + ~TMyQueue() + { + for (TTasks::iterator i = Tasks.begin(), e = Tasks.end(); i != e; ++i) { + delete *i; + } + } + + void PushTask(TMyTask* task) + { + task->Queue = this; + if (Tasks.empty()) { + // Scheduler must be notified on first task in queue + if (GetScheduler()) { + GetScheduler()->ActivateQueue(this); + } + } + Tasks.push_back(task); + LWPROBE(IncomingRequest, task->Id, task->Queue->Name, + double(task->Cost) / 1000000.0, + NHPTimer::GetSeconds(task->Timer)); + } +public: // Interface for scheduler + void OnSchedulerAttach() + { + Y_ABORT_UNLESS(GetScheduler() != nullptr); + if (!Tasks.empty()) { + GetScheduler()->ActivateQueue(this); + } + } + + TTask* PeekTask() + { + Y_ABORT_UNLESS(!Tasks.empty()); + return Tasks.front(); + } + + void PopTask() + { + Y_ABORT_UNLESS(!Tasks.empty()); + Tasks.pop_front(); + } + + bool Empty() const + { + return Tasks.empty(); + } +}; + +typedef std::shared_ptr TQueuePtr; + +// State +NLWTrace::TProbeRegistry* g_Probes; +NLWTrace::TManager* g_TraceMngr; +volatile bool g_Running = true; +ui64 g_LastRequestId = 0; + +TMutex g_CompleteLock; +TCondVar g_CompleteCondVar; +TVector g_Complete; + +TMutex g_ScheduledLock; +TCondVar g_ScheduledCondVar; +TDeque g_Scheduled; + +TMutex g_Lock; +TCondVar g_CondVar; +TDeque g_Incoming; +TVector g_SchedulerQs; +THolder g_Fc; +THolder> g_Drr; + +TAtomic g_IdleTime = 0; // in microsec +TAtomic g_ActiveTime = 0; // in microsec + +void Arrive(TMyTask* task) +{ + TGuard g(g_Lock); + bool wasOpen = g_Fc->IsOpen(); + g_Fc->Arrive(task->FcOp, task->Cost, Now()); + if (!wasOpen && g_Fc->IsOpen()) { + g_CondVar.BroadCast(); + } +} + +void Depart(TMyTask* task) +{ + TGuard g(g_Lock); + bool wasOpen = g_Fc->IsOpen(); + g_Fc->Depart(task->FcOp, task->RealCost, Now()); + if (!wasOpen && g_Fc->IsOpen()) { + g_CondVar.BroadCast(); + } +} + +void Enqueue(TMyTask* task) +{ + TGuard g(g_ScheduledLock); + g_ScheduledCondVar.Signal(); + g_Scheduled.push_back(task); +} + +TMyTask* Dequeue() +{ + TGuard g(g_ScheduledLock); + while (g_Scheduled.empty()) { + if (!g_ScheduledCondVar.WaitT(g_ScheduledLock, TDuration::Seconds(1))) { + if (!g_Running) { + return nullptr; + } + } + } + TMyTask* task = g_Scheduled.front(); + g_Scheduled.pop_front(); + return task; +} + +struct TCompleteCmp { + bool operator()(const TMyTask* lhs, const TMyTask* rhs) { + return lhs->CompleteDeadline > rhs->CompleteDeadline; + } +}; + +void PushToWaitHeap(TMyTask* task) +{ + TGuard g(g_CompleteLock); + if (g_Complete.empty()) { + g_CompleteCondVar.BroadCast(); + } + g_Complete.push_back(task); + PushHeap(g_Complete.begin(), g_Complete.end(), TCompleteCmp()); +} + +TMyTask* PopFromWaitHeap() +{ + TInstant deadline = TInstant::Zero(); + while (g_Running) { + if (deadline != TInstant::Zero()) { + TDuration waitTime = TInstant::Now() - deadline; + Sleep(Min(waitTime, g_CompletePeriod)); + } + + TGuard g(g_CompleteLock); + while (g_Complete.empty()) { + if (!g_CompleteCondVar.WaitT(g_CompleteLock, TDuration::Seconds(1))) { + if (!g_Running) { + return nullptr; + } + } + } + + TMyTask* peek = g_Complete.front(); + TInstant now = TInstant::Now(); + if (peek->CompleteDeadline < now) { + PopHeap(g_Complete.begin(), g_Complete.end(), TCompleteCmp()); + TMyTask* task = g_Complete.back(); + g_Complete.pop_back(); + return task; + } else { + deadline = peek->CompleteDeadline; + } + } + return nullptr; +} + +void Execute(TMyTask* task) +{ + // Emulate execution for real cost nanosaconds + NHPTimer::STime timer; + NHPTimer::GetTime(&timer); + if (task->RealCost >= 2) { + Sleep(TDuration::MicroSeconds((task->RealCost - 1))); + } + double passed = 0.0; + while (passed * 1000000ull < task->RealCost) { + passed += NHPTimer::GetTimePassed(&timer); + } + + // Time measurements + double execTime = NHPTimer::GetTimePassed(&task->Timer); + task->TotalTime += execTime; + LWPROBE(ExecuteRequest, task->Id, task->Queue->Name, execTime); + + // Complete request + double wait = GaussSumRandom(g_WaitSec, Y_ARRAY_SIZE(g_WaitSec)); + task->CompleteDeadline = TInstant::Now() + + TDuration::MicroSeconds(ui64(wait * 1000000.0)); + PushToWaitHeap(task); +} + +void* CompleteThread(void*) +{ + double lastMonSec = Now(); + ui64 lastIdleTime = 0; + ui64 lastActiveTime = 0; + while (TMyTask* task = PopFromWaitHeap()) { + double waitTime = NHPTimer::GetTimePassed(&task->Timer); + task->TotalTime += waitTime; + LWPROBE(CompleteRequest, task->Id, task->Queue->Name, waitTime, + task->TotalTime, task->TotalTime - task->SchedTime, + double(task->Cost)/1000000.0); + Depart(task); + delete task; + + // Utilization monitoring + double now = Now(); + if (lastMonSec + 1.0 < now) { + ui64 idleTime = AtomicGet(g_IdleTime); + ui64 activeTime = AtomicGet(g_ActiveTime); + ui64 idleDelta = idleTime - lastIdleTime; + ui64 activeDelta = activeTime - lastActiveTime; + ui64 elapsed = idleDelta + activeDelta; + double utilization = (elapsed == 0? 0: double(activeDelta) / elapsed); + lastIdleTime = idleTime; + lastActiveTime = activeTime; + LWPROBE(SystemStats, utilization); + lastMonSec = now; + } + } + return nullptr; +} + +void* WorkerThread(void*) +{ + NHPTimer::STime workerTimer; + NHPTimer::GetTime(&workerTimer); + while (TMyTask* task = Dequeue()) { + double workerIdleTime = NHPTimer::GetTimePassed(&workerTimer); + double queueTime = NHPTimer::GetTimePassed(&task->Timer); + task->TotalTime += queueTime; + LWPROBE(DequeueRequest, task->Id, task->Queue->Name, queueTime); + Execute(task); + double workerActiveTime = NHPTimer::GetTimePassed(&workerTimer); + LWPROBE(WorkerStats, workerIdleTime, workerActiveTime, + workerIdleTime + workerActiveTime); + AtomicAdd(g_IdleTime, workerIdleTime * 1000000); + AtomicAdd(g_ActiveTime, workerActiveTime * 1000000); + } + return nullptr; +} + +void* SchedulerThread(void*) +{ + while (g_Running) { + TMyTask* task = g_Drr->PeekTask(); + if (task) { + g_Drr->PopTask(); + task->SchedTime = NHPTimer::GetTimePassed(&task->Timer); + task->TotalTime += task->SchedTime; + LWPROBE(ScheduleRequest, task->Id, task->Queue->Name, + task->SchedTime); + Arrive(task); + Enqueue(task); + } + + TGuard g(g_Lock); + while (!g_Fc->IsOpen() || (!g_Drr->PeekTask() && g_Incoming.empty())) { + g_CondVar.WaitI(g_Lock); + } + + for (TMyTask* task : g_Incoming) { + TMyQueue* q = g_SchedulerQs[task->Type].get(); + q->PushTask(task); + } + g_Incoming.clear(); + } + return nullptr; +} + +void* GenerateThread(void*) +{ + while (g_Running) { + // Wait some random time + Sleep(TDuration::Seconds( + ExpRandom(1.0/g_AvgPeriodSec, g_MaxPeriodSec))); + + // Generate some random task + size_t type = RandomNumber(g_SchedulerQs.size()); + TUCost cost = 1000000ull * GaussSumRandom(g_CostSec, Y_ARRAY_SIZE(g_CostSec)); + TUCost realcost = cost * (0.5 + 1.5 * RandomNumber()); // cost; + TMyTask* task = new TMyTask(cost, realcost, type, ++g_LastRequestId); + + // Push task into incoming queue + TGuard g(g_Lock); + if (g_Incoming.empty()) { + g_CondVar.BroadCast(); + } + g_Incoming.push_back(task); + } + return nullptr; +} + +} // namespace NFcSim + +class TMachineMonPage : public NMonitoring::IMonPage { +public: + TMachineMonPage() + : IMonPage("dashboard", "Dashboard") + {} + virtual void Output(NMonitoring::IMonHttpRequest& request) { + const char* urls[] = { + "/trace?fullscreen=y&aggr=hist&autoscale=y&refresh=3000&bn=queueTimeSec&id=.SIMFC_PROVIDER.DequeueRequest.d1s&linesfill=y&mode=analytics&out=flot&pointsshow=n&xn=queueTimeSec&y1=0&x1=0&yns=_count_share", + "/trace?fullscreen=y&aggr=hist&autoscale=y&refresh=3000&bn=execTimeSec&id=.SIMFC_PROVIDER.ExecuteRequest.d1s&linesfill=y&mode=analytics&out=flot&pointsshow=n&xn=execTimeSec&y1=0&x1=0&yns=_count_share", + "/trace?fullscreen=y&aggr=hist&autoscale=y&refresh=3000&bn=waitTimeSec&id=.SIMFC_PROVIDER.CompleteRequest.d1s&linesfill=y&mode=analytics&out=flot&pointsshow=n&xn=waitTimeSec&y1=0&x1=0&yns=_count_share", + + "/trace?fullscreen=y&id=.SHOP_PROVIDER.Arrive.d200ms&mode=analytics&out=flot&xn=_thrRTime&y1=0&yns=costInFly", + "/trace?fullscreen=y&aggr=hist&autoscale=y&refresh=3000&bn=procTimeSec&id=.SIMFC_PROVIDER.CompleteRequest.d1s&linesfill=y&mode=analytics&out=flot&pointsshow=n&xn=procTimeSec&y1=0&x1=0&yns=_count_share", + "/trace?fullscreen=y&aggr=hist&autoscale=y&refresh=3000&bn=schedulerTimeSec&id=.SIMFC_PROVIDER.ScheduleRequest.d1s&linesfill=y&mode=analytics&out=flot&pointsshow=n&xn=schedulerTimeSec&y1=0&x1=0&yns=_count_share", + + "/trace?fullscreen=y&id=.SHOP_PROVIDER.Arrive.d200ms&mode=analytics&out=flot&xn=_thrRTime&y1=0&yns=countInFly", + "/trace?fullscreen=y&id=.SIMFC_PROVIDER.DequeueRequest.d200ms&mode=analytics&out=flot&xn=_thrRTime&yns=queueTimeSec&y0=0&pointsshow=n&cutts=y", + "/trace?fullscreen=y&id=.Group.ShopFlowCtlPeriod.d10m&mode=analytics&out=flot&pointsshow=n&xn=periodId&yns=badPeriods:goodPeriods:zeroPeriods", + + "/trace?fullscreen=y&g=periodId&id=.Group.ShopFlowCtlPeriod.d10m&mode=analytics&out=flot&pointsshow=n&xn=periodId&y1=0&yns=dT_T:dL_L", + "/trace?fullscreen=y&g=periodId&id=.Group.ShopFlowCtlPeriod.d10m&mode=analytics&out=flot&pointsshow=n&xn=periodId&y1=0&yns=pv", + "/trace?fullscreen=y&g=periodId&id=.Group.ShopFlowCtlPeriod.d10m&linesfill=y&mode=analytics&out=flot&xn=periodId&y1=0&yns=state:window&pointsshow=n", + + "/trace?fullscreen=y&g=periodId&id=.Group.ShopFlowCtlPeriod.d10m&mode=analytics&out=flot&xn=periodId&y1=-1&y2=1&yns=error", + "/trace?fullscreen=y&g=periodId&id=.Group.ShopFlowCtlPeriod.d10m&linesshow=n&mode=analytics&out=flot&x1=0&xn=window&y1=0&yns=throughput&cutts=y", + "/trace?fullscreen=y&g=periodId&id=.Group.ShopFlowCtlPeriod.d10m&mode=analytics&out=flot&xn=periodId&y1=0&yns=throughput:throughputMin:throughputMax:throughputLo:throughputHi&pointsshow=n&legendshow=n", + + "/trace?fullscreen=y&g=periodId&id=.Group.ShopFlowCtlPeriod.d10m&mode=analytics&out=flot&xn=periodId&yns=mode", + "/trace?fullscreen=y&g=periodId&id=.Group.ShopFlowCtlPeriod.d10m&linesshow=n&mode=analytics&out=flot&x1=0&xn=window&y1=0&yns=latencyAvgMs&cutts=y", + "/trace?fullscreen=y&g=periodId&id=.Group.ShopFlowCtlPeriod.d10m&mode=analytics&out=flot&pointsshow=n&xn=periodId&y1=0&yns=latencyAvgMs:latencyAvgMinMs:latencyAvgMaxMs:latencyAvgLoMs:latencyAvgHiMs&legendshow=n", + + "/trace?fullscreen=y&id=.SIMFC_PROVIDER.SystemStats.d10m&mode=analytics&out=flot&xn=_thrRTime&yns=utilization&linesfill=y&y1=0&y2=1&pointsshow=n", + "/trace?fullscreen=y&autoscale=y&id=.SIMFC_PROVIDER.WorkerStats.d1s&mode=analytics&out=flot&xn=_thrRTime&yns=activeTimeSec-stack:totalTimeSec-stack&pointsshow=n&linesfill=y&cutts=y&legendshow=n", + "/trace?fullscreen=y&id=.SHOP_PROVIDER.Depart.d1s&mode=analytics&out=flot&xn=realCost&yns=estCost&linesshow=n" + }; + + TStringStream out; + out << NMonitoring::HTTPOKHTML; + HTML(out) { + out << "" << Endl; + HTML_TAG() { + //HEAD() + BODY() { + out << ""; + for (size_t i = 0; i < Y_ARRAY_SIZE(urls); i++) { + if (i > 0 && i % 3 == 0) { + out << ""; + } + out << ""; + } + out << "
"; + } + } + } + request.Output() << out.Str(); + } +}; + +int main(int argc, char** argv) +{ + using namespace NFcSim; + try { + NLWTrace::StartLwtraceFromEnv(); +#ifdef _unix_ + signal(SIGPIPE, SIG_IGN); +#endif + +#ifdef _win32_ + WSADATA dummy; + WSAStartup(MAKEWORD(2,2), &dummy); +#endif + + // Configure + using TMonSrvc = NMonitoring::TMonService2; + THolder MonSrvc; + NLastGetopt::TOpts opts = NLastGetopt::TOpts::Default(); + opts.AddLongOption(0, "mon-port", "port of monitoring service") + .RequiredArgument("port") + .StoreResult(&g_MonPort, g_MonPort); + NLastGetopt::TOptsParseResult res(&opts, argc, argv); + + // Init monservice + MonSrvc.Reset(new TMonSrvc(g_MonPort)); + MonSrvc->Register(new TMachineMonPage()); + NLwTraceMonPage::RegisterPages(MonSrvc->GetRoot()); + NLwTraceMonPage::ProbeRegistry().AddProbesList( + LWTRACE_GET_PROBES(SIMFC_PROVIDER)); + NLwTraceMonPage::ProbeRegistry().AddProbesList( + LWTRACE_GET_PROBES(SHOP_PROVIDER)); + g_Probes = &NLwTraceMonPage::ProbeRegistry(); + g_TraceMngr = &NLwTraceMonPage::TraceManager(); + + // Start monservice + MonSrvc->Start(); + + // Initialization + g_SchedulerQs.push_back(TQueuePtr(new TMyQueue("A:rdc"))); + g_SchedulerQs.push_back(TQueuePtr(new TMyQueue("B:map"))); + g_Fc.Reset(new NShop::TFlowCtl(g_FcCfg, NFcSim::Now())); + g_Drr.Reset(new TDRRScheduler(g_QuantumNs)); + for (TQueuePtr q : g_SchedulerQs) { + g_Drr->AddQueue(q->Name, q); + } + + + // Start all threads + TThread completeThread(&CompleteThread, nullptr); + TThread generateThread(&GenerateThread, nullptr); + TThread workerThread1(&WorkerThread, nullptr); + TThread workerThread2(&WorkerThread, nullptr); + TThread workerThread3(&WorkerThread, nullptr); + TThread workerThread4(&WorkerThread, nullptr); + TThread workerThread5(&WorkerThread, nullptr); + TThread workerThread6(&WorkerThread, nullptr); + TThread workerThread7(&WorkerThread, nullptr); + TThread workerThread8(&WorkerThread, nullptr); + TThread workerThread9(&WorkerThread, nullptr); + TThread workerThread0(&WorkerThread, nullptr); + completeThread.Start(); + generateThread.Start(); + workerThread1.Start(); + workerThread2.Start(); + workerThread3.Start(); + workerThread4.Start(); + workerThread5.Start(); + workerThread6.Start(); + workerThread7.Start(); + workerThread8.Start(); + workerThread9.Start(); + workerThread0.Start(); + SchedulerThread(nullptr); + + // Finish + g_Running = false; + Cout << "bye" << Endl; + return 0; + } catch (...) { + Cerr << "failure: " << CurrentExceptionMessage() << Endl; + return 1; + } +} diff --git a/ydb/library/shop/sim_flowctl/one.pb.txt b/ydb/library/shop/sim_flowctl/one.pb.txt new file mode 100644 index 000000000000..5a32986f89dc --- /dev/null +++ b/ydb/library/shop/sim_flowctl/one.pb.txt @@ -0,0 +1,18 @@ +Machine { + Name: "srv" + Scheduler { FIFO { Name: "fifo" } } + WorkerCount: 10 + Wait { Distr { Name: "wait" Gauss { Mean: 0.05 Disp: 0.005 } MinRelValue: 0.1 MaxRelValue: 10 } } + FlowCtl { Name: "srv" } +} + +Source { + Name: "src" + InterArrival { Distr { Name: "ia" Exp { Period: 0.0002 } MaxRelValue: 10 } } + Operation { + Name: "exec" + Machine: "srv" + EstCost { Distr { Gauss { Mean: 0.02 Disp: 0.01 } MinRelValue: 0.1 MaxRelValue: 10 } } + EstCostOverRealCost { Distr { Const: 1.0 } } + } +} diff --git a/ydb/library/shop/sim_flowctl/ya.make b/ydb/library/shop/sim_flowctl/ya.make new file mode 100644 index 000000000000..fa5a8e34b5c5 --- /dev/null +++ b/ydb/library/shop/sim_flowctl/ya.make @@ -0,0 +1,16 @@ +PROGRAM() + +SRCS( + flowctlmain.cpp +) + +PEERDIR( + ydb/library/drr + library/cpp/lwtrace/mon + ydb/library/shop + library/cpp/getopt + library/cpp/lwtrace + library/cpp/monlib/dynamic_counters +) + +END() diff --git a/ydb/library/shop/sim_shop/config.proto b/ydb/library/shop/sim_shop/config.proto new file mode 100644 index 000000000000..30bee490c5a1 --- /dev/null +++ b/ydb/library/shop/sim_shop/config.proto @@ -0,0 +1,114 @@ +import "ydb/library/shop/protos/shop.proto"; + +package NShopSim; + +option java_package = "ru.yandex.shopsim.proto"; + +message TGaussDistrPb { + optional double Mean = 1; + optional double Disp = 2; +} + +message TExpDistrPb { + // Either only should be used + optional double Lambda = 1; + optional double Period = 2; // 1/Lambda +} + +message TUniformDistrPb { + optional double From = 11; + optional double To = 12; +} + +message TDistrPb { + optional string Name = 1; + optional double Weight = 2 [default = 1.0]; + + // The only one of types should be set + optional TGaussDistrPb Gauss = 11; + optional TExpDistrPb Exp = 12; + optional TUniformDistrPb Uniform = 13; + optional double Const = 14; // not random, just constant value + + optional double MinAbsValue = 101; + optional double MaxAbsValue = 102; + optional double MinRelValue = 103; // relative to Mean + optional double MaxRelValue = 104; // relative to Mean +} + +message TRandomPb { + repeated TDistrPb Distr = 2; +} + +message TOperationPb { + optional string Name = 1; + optional string Queue = 2; // for machine schedulers (overrides TSourcePb.Queue) + optional string Machine = 3; + + // cost estimation (any pair have to be set) + optional TRandomPb EstCost = 11; + optional TRandomPb RealCost = 12; + optional TRandomPb EstCostOverRealCost = 13; + optional TRandomPb EstCostMinusRealCost = 14; +} + +message TSourcePb { + optional string Name = 1; + optional string Queue = 2; // for main scheduler + optional TRandomPb InterArrival = 3; + repeated TOperationPb Operation = 4; + // TODO: make it possible to correlate costs in different ops +} + +// TODO: for common worker pool at different machines (aka common resource) +//message TWorkersPb { +// optional string Name = 1; +// optional uint64 Count = 2; +// optional double Speed = 3; +// // TODO: worker scheduling procedure? +//} + +message TFIFOPb { + optional string Name = 1; +} + +message TDRRQueuePb { + optional string Name = 1; + optional uint64 Weight = 2; + optional uint64 MaxBurst = 3; +} + +message TDRRPb { + optional string Name = 1; + optional uint64 Quantum = 2; + + repeated TDRRQueuePb Queue = 3; +}; + +message TSchedulerPb { + // Only one qdisc should be set + optional TFIFOPb FIFO = 1; + optional TDRRPb DRR = 2; +} + +message TMachinePb { + optional string Name = 1; + + // At first all incoming jobs are pushed to queueing discipline + optional TSchedulerPb Scheduler = 101; + + // After job scheduling, operation of a job is processed by worker + optional uint64 WorkerCount = 201 [default = 1]; + optional double Speed = 202 [default = 1.0]; + + // After operation processing job waits for random time + optional TRandomPb Wait = 301; + + // Machine operates under flow controller + optional NShop.TFlowCtlConfig FlowCtl = 401; +} + +message TConfigPb { + repeated TMachinePb Machine = 1; + repeated TSourcePb Source = 2; +} diff --git a/ydb/library/shop/sim_shop/myshop.cpp b/ydb/library/shop/sim_shop/myshop.cpp new file mode 100644 index 000000000000..8892dcc7a545 --- /dev/null +++ b/ydb/library/shop/sim_shop/myshop.cpp @@ -0,0 +1,807 @@ +#include "myshop.h" + +#include + +#include +#include + +#include + +LWTRACE_DEFINE_PROVIDER(SIMSHOP_PROVIDER); + +namespace NShopSim { + +LWTRACE_USING(SIMSHOP_PROVIDER); + +// Return random value according to distribution described by protobuf +double Random(const TDistrPb& pb) +{ + double x; + double mean; + if (pb.HasConst()) { + mean = x = pb.GetConst(); + } else if (pb.HasGauss()) { + mean = pb.GetGauss().GetMean(); + x = NormalRandom(mean, pb.GetGauss().GetDisp()); + } else if (pb.HasExp()) { + mean = pb.GetExp().HasLambda()? + pb.GetExp().GetLambda() : 1.0 / pb.GetExp().GetPeriod(); + x = -(1.0 / mean) * log(1 - RandomNumber()); + } else if (pb.HasUniform()) { + double from = pb.GetUniform().GetFrom(); + double to = pb.GetUniform().GetTo(); + mean = (from + to) / 2.0; + x = from + (to - from) * RandomNumber(); + } + if (pb.HasMinAbsValue()) { + x = Max(x, pb.GetMinAbsValue()); + } + if (pb.HasMaxAbsValue()) { + x = Min(x, pb.GetMaxAbsValue()); + } + if (pb.HasMinRelValue()) { + x = Max(x, mean * pb.GetMinRelValue()); + } + if (pb.HasMaxAbsValue()) { + x = Min(x, mean * pb.GetMaxRelValue()); + } + return x; +} + +// Return random value according to distribution described by protobuf +double Random(const TRandomPb& pb) +{ + double totalWeight = 0; + for (int i = 0; i < pb.GetDistr().size(); i++) { + double weight = pb.GetDistr(i).GetWeight(); + Y_ABORT_UNLESS(weight >= 0); + totalWeight += weight; + } + + double weightSum = 0; + double p = RandomNumber(); + for (int i = 0; i < pb.GetDistr().size(); i++) { + TDistrPb distr = pb.GetDistr(i); + double weight = distr.GetWeight(); + weightSum += weight; + if (p < weightSum/totalWeight) { + return Random(distr); + } + } + Y_ABORT("bad weights configuration"); +} + +TMyShop::TMyShop() + : SourceThread(&SourceThreadFunc, this) + , SchedulerThread(&SchedulerThreadFunc, this) +{ + SourceThread.Start(); + SchedulerThread.Start(); +} + +TMyShop::~TMyShop() +{ + AtomicSet(Running, 0); + // Explicit join to avoid troubles + SourceThread.Join(); + SchedulerThread.Join(); +} + +void TMyShop::Configure(const TConfigPb& newCfg) +{ + TGuard g(Mutex); + Cfg = newCfg; + + // Create map of current machines by name + THashMap machines; + for (const auto& kv : Machines) { + TMyMachine* machine = kv.second.Machine.Get(); + machines[machine->GetName()] = machine; + } + + // Create/update machines + THashSet names; + for (int i = 0; i < Cfg.GetMachine().size(); i++) { + const TMachinePb& pb = Cfg.GetMachine(i); + bool inserted = names.insert(pb.GetName()).second; + Y_ABORT_UNLESS(inserted, "duplicate machine name '%s'", pb.GetName().data()); + + TMachineItem* item; + auto mIter = machines.find(pb.GetName()); + if (mIter != machines.end()) { + item = &Machines.find(mIter->second->GetId())->second; + } else { + // Create new machine + ui64 id = ++LastMachineId; + item = &Machines[id]; + item->Machine.Reset(new TMyMachine(this, id)); + machines[pb.GetName()] = item->Machine.Get(); + } + + // Machine's flows must be cleared to destroy old flows + item->Machine->ClearFlows(); + + // Configure/reconfigure machine and it's flow control + item->Machine->Configure(pb); + auto st = item->Machine->GetFlowCtl()->ConfigureST(pb.GetFlowCtl(), Now()); + switch (st) { + case TFlowCtl::None: break; + case TFlowCtl::Closed: item->Machine->Freeze(); break; + case TFlowCtl::Opened: item->Machine->Unfreeze(); break; + } + } + + // Remove machines that are no longer in config + TVector toDelete; // to avoid deadlocks + for (const auto& kv : machines) { + if (names.find(kv.first) == names.end()) { + TMyMachine* machine = kv.second; + auto mIter = Machines.find(machine->GetId()); + Y_ABORT_UNLESS(mIter != Machines.end()); + TMachineItem* item = &mIter->second; + toDelete.push_back(item->Machine.Release()); + Machines.erase(mIter); + } + } + + // Create map of current flows by name + THashMap flows; + for (const THeapItem& item : SourceHeap) { + const TMyFlowPtr& flow = item.Flow; + flows[flow->Source.GetName()] = flow; + } + + // All flows will be actually deleted when all their jobs are done + SourceHeap.clear(); + Sched.Clear(); + + // Create/update flows + double now = Now(); + for (int i = 0; i < newCfg.GetSource().size(); i++) { + TMyFlowPtr flow; + const TSourcePb& source = newCfg.GetSource(i); + double ia = Random(source.GetInterArrival()); + auto fIter = flows.find(source.GetName()); + if (fIter != flows.end() && NProtoBuf::IsEqual(source, fIter->second->Source)) { + // Use already existing flow + flow = fIter->second; + } else { + // Create new flow + flow.Reset(new TMyFlow(source, &Sched)); + + // Create ops with simplest linear dependencies graph + // (i.e. sequential processing) + size_t prevsid; + for (int i = 0; i < source.GetOperation().size(); i++) { + const TOperationPb& pb = source.GetOperation(i); + auto mIter = machines.find(pb.GetMachine()); + if (mIter != machines.end()) { + TMyMachine* machine = mIter->second; + ui64 machineId = machine->GetId(); + if (i == 0) { + prevsid = flow->AddStage(machineId, {}); + } else { + prevsid = flow->AddStage(machineId, {prevsid}); + } + + // Freeze control + machine->AddFlow(flow); + if (machine->IsFrozen()) { + flow->IncFrozenMachine(); + } + } else { + Y_ABORT("unknown machine %s", pb.GetMachine().data()); + } + } + } + PushSource(now + ia, flow); + if (!flow->Empty()) { + flow->Activate(); + } + } + + // Delete machines after lock release to avoid deadlock w/ wait-thread + g.Release(); + for (TMyMachine* machine : toDelete) { + delete machine; // this will join thread that can lock `Mutex' + } +} + +void TMyShop::OperationFinished(TMyJob* job, size_t sid, ui64 realcost, bool success) +{ + TGuard g(Mutex); + TShop::OperationFinished(job, sid, realcost, success, Now()); +} + +TMyMachine* TMyShop::GetMachine(ui64 machineId) +{ + TGuard g(Mutex); + auto iter = Machines.find(machineId); + if (iter != Machines.end()) { + return iter->second.Machine.Get(); + } else { + return nullptr; + } +} + +TMachine* TMyShop::GetMachine(const TJob* job, size_t sid) +{ + return GetMachine(job->Flow->GetStage(sid)->MachineId); +} + +TMachineCtl* TMyShop::GetMachineCtl(const TJob* job, size_t sid) +{ + return GetMachine(job->Flow->GetStage(sid)->MachineId); +} + +void TMyShop::StartJob(TMyJob* job) +{ + TGuard g(Mutex); + double now = Now(); + TShopCtl::ArriveJob(job, now); + TShop::StartJob(job, now); +} + +void TMyShop::JobFinished(TJob* job) +{ + TGuard g(Mutex); // for TMyFlow dtor to work under lock + TShop::JobFinished(job); + delete static_cast(job); +} + +void TMyShop::OnOperationFinished(TJob* job, size_t sid, ui64 realcost, double now) +{ + DepartJobStage(job, sid, realcost, now); +} + +void TMyShop::OnOperationAbort(TJob* job, size_t sid) +{ + AbortJobStage(job, sid); +} + +void* TMyShop::SourceThreadFunc(void* this_) +{ + ::NShopSim::SetCurrentThreadName("source"); + reinterpret_cast(this_)->Source(); + return nullptr; +} + +void* TMyShop::SchedulerThreadFunc(void* this_) +{ + ::NShopSim::SetCurrentThreadName("sched"); + reinterpret_cast(this_)->Scheduler(); + return nullptr; +} + +inline ui64 IntegerCost(double cost) +{ + return Max(1, ceilf(cost * 1e6)); +} + +void TMyShop::Generate(double time, const TMyFlowPtr& flow) +{ + TMyJob* job = new TMyJob(); + job->MyFlow = flow; + job->GenerateTime = time; + job->Flow = flow.Get(); + job->Cost = 0; + for (int i = 0; i < flow->Source.GetOperation().size(); i++) { + const TOperationPb& op = flow->Source.GetOperation(i); + double estcost = NAN; + double realcost = NAN; + if (op.HasEstCost()) { + estcost = Random(op.GetEstCost()); + if (op.HasRealCost()) { + realcost = Random(op.GetRealCost()); + } else if (op.HasEstCostMinusRealCost()) { + double diff = Random(op.GetEstCostMinusRealCost()); + realcost = estcost - diff; + } else if (op.HasEstCostOverRealCost()) { + double ratio = Random(op.GetEstCostOverRealCost()); + realcost = estcost / ratio; + } else { + Y_ABORT("wrong flow config"); + } + } else if (op.HasRealCost()) { + realcost = Random(op.GetRealCost()); + if (op.HasEstCostMinusRealCost()) { + double diff = Random(op.GetEstCostMinusRealCost()); + estcost = realcost + diff; + } else if (op.HasEstCostOverRealCost()) { + double ratio = Random(op.GetEstCostOverRealCost()); + estcost = realcost * ratio; + } else { + Y_ABORT("wrong flow config"); + } + } else { + Y_ABORT("wrong flow config"); + } + ui64 intrealcost = IntegerCost(realcost); + job->Cost += intrealcost; + job->RealCost.push_back(intrealcost); + job->AddOp(IntegerCost(estcost)); + } + Enqueue(job); +} + +void TMyShop::PushSource(double time, const TMyFlowPtr& flow) +{ + SourceHeap.emplace_back(time, flow); + PushHeap(SourceHeap.begin(), SourceHeap.end()); +} + +void TMyShop::PopSource() +{ + PopHeap(SourceHeap.begin(), SourceHeap.end()); + SourceHeap.pop_back(); +} + +void TMyShop::Source() +{ + double deadline = 0.0; + while (AtomicGet(Running)) { + if (deadline != 0.0) { + double waitTime = Now() - deadline; + if (waitTime > 0.0) { + NanoSleep(Min(waitTime, 1.0) * 1e9); + } + } + + while (AtomicGet(Running)) { + TGuard g(Mutex); + double now = Now(); + if (SourceHeap.empty()) { + deadline = now + 1.0; // Wait for config with sources + break; + } + + THeapItem peek = SourceHeap.front(); + if (peek.Time < now) { + PopSource(); + Generate(peek.Time, peek.Flow); + double ia = Random(peek.Flow->Source.GetInterArrival()); + PushSource(peek.Time + ia, peek.Flow); + } else { + deadline = peek.Time; + break; + } + } + } +} + +bool TMyShop::IsFlowFrozen(TMyFlow* flow) +{ + for (size_t sid = 0; sid < flow->StageCount(); sid++) { + if (TMachine* machine = GetMachine(flow->GetStage(sid)->MachineId)) { + if (static_cast(machine)->IsFrozen()) { + return true; + } + } else { + // Flow is considered to be frozen if any of machines is unavailable + return true; + } + } + // Flow is not frozen only if every machine is not frozen + return false; +} + +void TMyShop::Enqueue(TMyJob* job) +{ + TGuard g(Mutex); + CondVar.Signal(); + job->MyFlow->Enqueue(job); +} + +TMyJob* TMyShop::Dequeue(TInstant deadline) +{ + TGuard g(Mutex); + // Wait for jobs + while (Sched.Empty()) { + if (!CondVar.WaitD(Mutex, deadline)) { + return nullptr; + } + } + return static_cast(Sched.PopSchedulable()); +} + +void TMyShop::Scheduler() +{ + while (AtomicGet(Running)) { + if (TMyJob* job = Dequeue(TInstant::Now() + TDuration::Seconds(1))) { + StartJob(job); + } + } +} + +class TFifo : public IScheduler { +private: + TString Name; + TMutex Mutex; + TCondVar CondVar; + struct TItem { + TMyJob* Job; + size_t Sid; + ui64 Ts; + TItem() {} + TItem(TMyJob* job, size_t sid) : Job(job), Sid(sid), Ts(GetCycleCount()) {} + }; + TDeque Queue; + ui64 EstCostInQueue = 0; + TMyShop* Shop; +public: + explicit TFifo(TMyShop* shop) + : Shop(shop) + {} + + void SetName(const TString& name) { Name = name; } + + ~TFifo() { + Y_ABORT_UNLESS(Queue.empty(), "queue must be empty on destruction"); + } + + void Enqueue(TMyJob* job, size_t sid) override { + TGuard g(Mutex); + LWPROBE(FifoEnqueue, Shop->GetName(), job->Flow->GetName(), job->JobId, sid, + job->Flow->GetStage(sid)->MachineId, + job->GetOp(sid)->EstCost, Queue.size(), EstCostInQueue); + CondVar.Signal(); + Queue.emplace_back(job, sid); + EstCostInQueue += job->GetOp(sid)->EstCost; + } + + TMyJob* Dequeue(size_t* sid) override { + TGuard g(Mutex); + if (!Queue.empty()) { + TItem item = Queue.front(); + Queue.pop_front(); + EstCostInQueue -= item.Job->GetOp(item.Sid)->EstCost; + if (sid) { + *sid = item.Sid; + } + LWPROBE(FifoDequeue, Shop->GetName(), item.Job->Flow->GetName(), item.Job->JobId, item.Sid, + item.Job->Flow->GetStage(item.Sid)->MachineId, + item.Job->GetOp(item.Sid)->EstCost, Queue.size(), EstCostInQueue, + CyclesToMs(Duration(item.Ts, GetCycleCount()))); + return item.Job; + } + return nullptr; + } + + TMyJob* DequeueWait(size_t* sid, TInstant deadline) override { + TGuard g(Mutex); + while (Queue.empty()) { + if (!CondVar.WaitD(Mutex, deadline)) { + return nullptr; + } + } + return TFifo::Dequeue(sid); + } +}; + +void* TMyMachine::TWorkerThread::ThreadProc() +{ + ::NShopSim::SetCurrentThreadName(ToString(WorkerIdx) + Machine->GetName()); + Machine->Worker(WorkerIdx); + return nullptr; +} + +TMyMachine::TMyMachine(TMyShop* shop, ui64 machineId) + : TMachine(shop) + , TMachineCtl(new TFlowCtl()) + , MyShop(shop) + , MachineId(machineId) + , WaitThread(&WaitThreadFunc, this) +{ + WaitThread.Start(); +} + +void TMyMachine::FailAllJobs() +{ + TReadSpinLockGuard g(ConfigureLock); + size_t sid; + while (TMyJob* job = Scheduler->Dequeue(&sid)) { + MyShop->OperationFinished(job, sid, 0, false); + } +} + +TMyMachine::~TMyMachine() +{ + AtomicSet(Running, 0); + + // Fail all enqueued jobs + FailAllJobs(); + + // Join all threads (complete and workers) explicitly + // to avoid joining on half-destructed TMachine object + WorkerThread.clear(); + WaitThread.Join(); +} + +void TMyMachine::Configure(const TMachinePb& cfg) +{ + TWriteSpinLockGuard g(ConfigureLock); + TSchedulerPb oldSchedulerCfg = GetSchedulerCfg(); + SetConfig(cfg); + SetName(cfg.GetName()); + + // Update scheduler + if (!NProtoBuf::IsEqual(oldSchedulerCfg, cfg.GetScheduler())) { + THolder oldScheduler(Scheduler.Release()); + if (cfg.GetScheduler().HasFIFO()) { + TFifo* fifo = new TFifo(MyShop); + fifo->SetName(cfg.GetScheduler().GetFIFO().GetName()); + Scheduler.Reset(fifo); + } else { + Y_ABORT_UNLESS("only FIFO queueing disciplice is supported for now"); + } + + if (oldScheduler) { + // Requeue jobs into new scheduler + size_t sid; + while (TMyJob* job = oldScheduler->Dequeue(&sid)) { + Scheduler->Enqueue(job, sid); + } + oldScheduler.Destroy(); // Just to be explicit + } + } + + // Adjust workers count + while (WorkerThread.size() < cfg.GetWorkerCount()) { + auto worker = new TWorkerThread(this, WorkerThread.size()); + WorkerThread.emplace_back(worker); + worker->Start(); + } + WorkerThread.resize(cfg.GetWorkerCount()); // Shrink only, join threads +} + +bool TMyMachine::StartOperation(TJob* job, size_t sid) +{ + TReadSpinLockGuard g(ConfigureLock); + TMachine::StartOperation(job, sid); + Scheduler->Enqueue(static_cast(job), sid); + return false; +} + +void TMyMachine::Freeze() +{ + Frozen = true; + for (const TMyFlowPtr& p : Flows) { + p->IncFrozenMachine(); + } +} + +void TMyMachine::Unfreeze() +{ + Frozen = false; + for (const TMyFlowPtr& p : Flows) { + p->DecFrozenMachine(); + } +} + +void TMyMachine::ClearFlows() +{ + if (Frozen) { + for (const TMyFlowPtr& flow : Flows) { + flow->DecFrozenMachine(); + } + } + Flows.clear(); +} + +void TMyMachine::AddFlow(const TMyFlowPtr& flow) +{ + Flows.push_back(flow); +} + +void TMyMachine::SetConfig(const TMachinePb& cfg) +{ + TGuard g(CfgLock); + Cfg = cfg; +} + +TSchedulerPb TMyMachine::GetSchedulerCfg() +{ + TGuard g(CfgLock); + return Cfg.GetScheduler(); +} + +double TMyMachine::RandomWaitTime() +{ + TGuard g(CfgLock); + return Random(Cfg.GetWait()); +} + +ui64 TMyMachine::GetWorkerCount() +{ + TGuard g(CfgLock); + return Cfg.GetWorkerCount(); +} + +double TMyMachine::GetSpeed() +{ + TGuard g(CfgLock); + return Cfg.GetSpeed(); +} + +TMyJob* TMyMachine::DequeueJob(size_t* sid) +{ + TReadSpinLockGuard g(ConfigureLock); + return Scheduler->DequeueWait(sid, TInstant::Now() + TDuration::Seconds(1)); +} + +void TMyMachine::Worker(size_t workerIdx) +{ + NHPTimer::STime workerTimer; + NHPTimer::GetTime(&workerTimer); + + while (AtomicGet(Running) && workerIdx < GetWorkerCount()) { + size_t jobLimitPerCycle = 10; + size_t sid; + while (TMyJob* job = DequeueJob(&sid)) { + double workerIdleTime = NHPTimer::GetTimePassed(&workerTimer) * 1000; + Execute(job, sid); + double workerActiveTime = NHPTimer::GetTimePassed(&workerTimer) * 1000; + LWPROBE(MachineWorkerStats, MyShop->GetName(), MachineId, + workerIdleTime, workerActiveTime, workerIdleTime + workerActiveTime); + AtomicAdd(IdleTime, workerIdleTime * 1000); + AtomicAdd(ActiveTime, workerActiveTime * 1000); + if (!--jobLimitPerCycle) { + break; + } + } + } +} + +void TMyMachine::Execute(TMyJob* job, size_t sid) +{ + // Emulate execution for real cost nanosaconds + ui64 ts = GetCycleCount(); + double speed = GetSpeed(); + ui64 realcost = job->RealCost[sid] / speed; + if (realcost >= 2) { + Sleep(TDuration::MicroSeconds((realcost - 1))); + } + while (CyclesToMs(Duration(ts, GetCycleCount())) * 1000.0 < realcost) ; + + // Time measurements + ui64 execTs = GetCycleCount(); + double execTimeMs = CyclesToMs(Duration(ts, execTs)); + LWPROBE(MachineExecute, MyShop->GetName(), job->Flow->GetName(), job->JobId, sid, + MachineId, + job->GetOp(sid)->EstCost, job->RealCost[sid], speed, execTimeMs); + + double wait = RandomWaitTime(); + TInstant deadline = TInstant::Now() + TDuration::MicroSeconds(ui64(wait * 1000000.0)); + PushToWaitHeap(deadline, job, sid, execTs); +} + +void TMyMachine::PushToWaitHeap(TInstant deadline, TMyJob* job, size_t sid, ui64 execTs) +{ + TGuard g(WaitMutex); + WaitCondVar.Signal(); + WaitHeap.emplace_back(deadline, job, sid, execTs); + PushHeap(WaitHeap.begin(), WaitHeap.end(), TWaitCmp()); +} + +TMyJob* TMyMachine::PopFromWaitHeap(size_t* sid) +{ + while (AtomicGet(Running)) { + TGuard g(WaitMutex); + while (WaitHeap.empty()) { + if (!WaitCondVar.WaitT(WaitMutex, TDuration::Seconds(1))) { + if (!AtomicGet(Running)) { + return nullptr; + } + } + } + + TWaitItem peek = WaitHeap.front(); + TInstant now = TInstant::Now(); + if (peek.Deadline < now) { + PopHeap(WaitHeap.begin(), WaitHeap.end(), TWaitCmp()); + WaitHeap.pop_back(); + if (sid) { + *sid = peek.Sid; + } + LWPROBE(MachineWait, MyShop->GetName(), peek.Job->Flow->GetName(), peek.Job->JobId, peek.Sid, + MachineId, + CyclesToMs(Duration(peek.Ts, GetCycleCount()))); + return peek.Job; + } else { + TInstant deadline = peek.Deadline; + WaitCondVar.WaitD(WaitMutex, Min(deadline, now + TDuration::Seconds(1))); + } + } + return nullptr; +} + +void* TMyMachine::WaitThreadFunc(void* this_) +{ + reinterpret_cast(this_)->Wait(); + return nullptr; +} + +void TMyMachine::Wait() +{ + ::NShopSim::SetCurrentThreadName(GetName()); + + double lastMonSec = Now(); + ui64 lastIdleTime = 0; + ui64 lastActiveTime = 0; + size_t sid; + while (TMyJob* job = PopFromWaitHeap(&sid)) { + ui64 realcost = job->RealCost[sid]; + MyShop->OperationFinished(job, sid, realcost, true); + + // Utilization monitoring + double now = Now(); + if (lastMonSec + 1.0 < now) { + ui64 idleTime = AtomicGet(IdleTime); + ui64 activeTime = AtomicGet(ActiveTime); + ui64 idleDelta = idleTime - lastIdleTime; + ui64 activeDelta = activeTime - lastActiveTime; + ui64 elapsed = idleDelta + activeDelta; + double utilization = (elapsed == 0? 0: double(activeDelta) / elapsed); + lastIdleTime = idleTime; + lastActiveTime = activeTime; + LWPROBE(MachineStats, MyShop->GetName(), MachineId, utilization); + lastMonSec = now; + } + } +} + +TMyFlow::TMyFlow(const TSourcePb& source, TScheduler* sched) + : Source(source) +{ + TFlow::SetName(source.GetName()); + Freezable.SetName(source.GetName()); + Freezable.SetScheduler(sched); + TConsumer::SetName(source.GetName()); + SetScheduler(sched); + SetFreezable(&Freezable); +} + +TMyFlow::~TMyFlow() +{ + Deactivate(); +} + +void TMyFlow::Enqueue(TMyJob* job) +{ + if (Queue.empty()) { + Activate(); + } + Queue.push_back(job); +} + +TSchedulable* TMyFlow::PopSchedulable() +{ + Y_ABORT_UNLESS(!Queue.empty()); + TMyJob* job = Queue.front(); + Queue.pop_front(); + return job; +} + +bool TMyFlow::Empty() const +{ + return Queue.empty(); +} + +void TMyFlow::IncFrozenMachine() +{ + if (FrozenMachines == 0) { + Freezable.Freeze(); + } + FrozenMachines++; +} + +void TMyFlow::DecFrozenMachine() +{ + Y_ASSERT(FrozenMachines > 0); + FrozenMachines--; + if (FrozenMachines == 0) { + Freezable.Unfreeze(); + } +} + +} diff --git a/ydb/library/shop/sim_shop/myshop.h b/ydb/library/shop/sim_shop/myshop.h new file mode 100644 index 000000000000..7bac571c892d --- /dev/null +++ b/ydb/library/shop/sim_shop/myshop.h @@ -0,0 +1,286 @@ +#pragma once + +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include +#include + +#define SIMSHOP_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ + PROBE(FifoEnqueue, GROUPS("SimShopJob", "SimShopOp"), \ + TYPES(TString, TString, ui64, ui64, ui64, ui64, ui64, ui64), \ + NAMES("shop", "flow", "job", "sid", "machineid", "estcost", "queueLength", "queueCost")) \ + PROBE(FifoDequeue, GROUPS("SimShopJob", "SimShopOp"), \ + TYPES(TString, TString, ui64, ui64, ui64, ui64, ui64, ui64, double), \ + NAMES("shop", "flow", "job", "sid", "machineid", "estcost", "queueLength", "queueCost", "queueTimeMs")) \ + PROBE(MachineExecute, GROUPS("SimShopJob", "SimShopOp"), \ + TYPES(TString, TString, ui64, ui64, ui64, ui64, ui64, double, double), \ + NAMES("shop", "flow", "job", "sid", "machineid", "estcost", "realcost", "speed", "execTimeMs")) \ + PROBE(MachineWait, GROUPS("SimShopJob", "SimShopOp"), \ + TYPES(TString, TString, ui64, ui64, ui64, double), \ + NAMES("shop", "flow", "job", "sid", "machineid", "waitTimeMs")) \ + PROBE(MachineWorkerStats, GROUPS("SimShopMachine"), \ + TYPES(TString, ui64, double, double, double), \ + NAMES("shop", "machineid", "idleTimeMs", "activeTimeMs", "totalTimeMs")) \ + PROBE(MachineStats, GROUPS("SimShopMachine"), \ + TYPES(TString, ui64, double), \ + NAMES("shop", "machineid", "utilization")) \ +/**/ + +LWTRACE_DECLARE_PROVIDER(SIMSHOP_PROVIDER) + +namespace NShopSim { + +inline void SetCurrentThreadName(const TString& name, + const ui32 maxCharsFromProcessName = 8) +{ +#if defined(_linux_) + // linux limits threadname by 15 + \0 + + TStringBuf procName(GetExecPath()); + procName = procName.RNextTok('/'); + procName = procName.SubStr(0, maxCharsFromProcessName); + + TStringStream linuxName; + linuxName << procName << "." << name; + TThread::SetCurrentThreadName(linuxName.Str().data()); +#else + Y_UNUSED(maxCharsFromProcessName); + TThread::SetCurrentThreadName(name.c_str()); +#endif +} + +inline double Now() +{ + return CyclesToDuration(GetCycleCount()).SecondsFloat(); +} + +using namespace NShop; + +class TMyQueue; +class TMyFlow; +struct TMyJob; +class TMyShop; +class TMyMachine; + +class TMyFlow + : public TFlow + , public TConsumer + , public TAtomicRefCount +{ +public: + const TSourcePb Source; + + // Should be accessed under Shop::Mutex lock + TDeque Queue; + TFreezable Freezable; + ui64 FrozenMachines = 0; + + TMyFlow(const TSourcePb& source, TScheduler* sched); + ~TMyFlow(); + void Enqueue(TMyJob* job); + TSchedulable* PopSchedulable() override; + bool Empty() const override; + void IncFrozenMachine(); + void DecFrozenMachine(); +}; + +using TMyFlowPtr = TIntrusivePtr; + +struct TMyJob + : public TJob + , public TSchedulable +{ + TVector RealCost; // us + double GenerateTime = 0.0; + TMyFlowPtr MyFlow; +}; + +class IScheduler { +public: + virtual ~IScheduler() {} + virtual void Enqueue(TMyJob* job, size_t sid) = 0; + virtual TMyJob* Dequeue(size_t* sid) = 0; + virtual TMyJob* DequeueWait(size_t* sid, TInstant deadline) = 0; +}; + +class TMyMachine : public TMachine, public TMachineCtl { +private: + class TWorkerThread + : public ISimpleThread + , public TSimpleRefCount + { + private: + TMyMachine* Machine; + size_t WorkerIdx; + public: + TWorkerThread(TMyMachine* machine, size_t workerIdx) + : Machine(machine) + , WorkerIdx(workerIdx) + {} + void* ThreadProc() override; + }; + using TWorkerThreadPtr = TIntrusivePtr; + +private: + TAtomic Running = 1; + TMyShop* MyShop; + const ui64 MachineId; + + bool Frozen = false; + TVector Flows; + + TSpinLock CfgLock; + TMachinePb Cfg; + + TRWSpinLock ConfigureLock; + TFlowCtl MyFlowCtl; + THolder Scheduler; + TList WorkerThread; + + TMutex WaitMutex; + TCondVar WaitCondVar; + struct TWaitItem { + TInstant Deadline; + TMyJob* Job; + size_t Sid; + ui64 Ts; + TWaitItem(TInstant d, TMyJob* j, size_t s, ui64 t) + : Deadline(d), Job(j), Sid(s), Ts(t) + {} + }; + struct TWaitCmp { + bool operator()(const TWaitItem& lhs, const TWaitItem& rhs) const { + return lhs.Deadline > rhs.Deadline; + } + }; + TVector WaitHeap; + TThread WaitThread; + + // Monitoring + TAtomic IdleTime; + TAtomic ActiveTime; + +public: + TMyMachine(TMyShop* shop, ui64 machineId); + ~TMyMachine(); + + ui64 GetId() const { return MachineId; } + + void Configure(const TMachinePb& cfg); + bool StartOperation(TJob* job, size_t sid) override; + void Freeze() override; + void Unfreeze() override; + bool IsFrozen() { return Frozen; } + + void ClearFlows(); + void AddFlow(const TMyFlowPtr& flow); + + +private: + void SetConfig(const TMachinePb& cfg); + TSchedulerPb GetSchedulerCfg(); + double RandomWaitTime(); + ui64 GetWorkerCount(); + double GetSpeed(); + TMyJob* DequeueJob(size_t* sid); + void Worker(size_t workerIdx); + void Execute(TMyJob* job, size_t sid); + void PushToWaitHeap(TInstant deadline, TMyJob* job, size_t sid, ui64 execTs); + TMyJob* PopFromWaitHeap(size_t* sid); + static void* WaitThreadFunc(void* this_); + void Wait(); + void FailAllJobs(); + friend class TWorkerThread; +}; + +class TMyShop : public TShop, public TShopCtl { +private: + TAtomic Running = 1; + + TMutex Mutex; + TCondVar CondVar; + TConfigPb Cfg; + + // Flows and sources + TThread SourceThread; + struct THeapItem { + double Time; + TMyFlowPtr Flow; + THeapItem(double time, const TMyFlowPtr flow) + : Time(time) + , Flow(flow) + {} + bool operator<(const THeapItem& rhs) const { + return Time > rhs.Time; + } + }; + TVector SourceHeap; + + // Scheduling and congestion control + TThread SchedulerThread; + TScheduler Sched; + + // Machines + struct TMachineItem { + THolder Machine; + }; + THashMap Machines; // machineId -> machine/flowctl + ui64 LastMachineId = 0; +public: + TMyShop(); + ~TMyShop(); + + void Configure(const TConfigPb& newCfg); + void OperationFinished(TMyJob* job, size_t sid, ui64 realcost, bool success); + + TMyMachine* GetMachine(ui64 machineId); + TMachine* GetMachine(const TJob* job, size_t sid) override; + TMachineCtl* GetMachineCtl(const TJob* job, size_t sid) override; + + void StartJob(TMyJob* job); + void JobFinished(TJob* job) override; + + template + void ForEachMachine(TFunc func) + { + TGuard g(Mutex); + for (const auto& kv : Machines) { + ui64 machineId = kv.first; + TMyMachine* machine = kv.second.Machine.Get(); + func(machineId, machine, machine->GetFlowCtl()); + } + } + + TConfigPb GetConfig() const { TGuard g(Mutex); return Cfg; } + +protected: + void OnOperationFinished(TJob* job, size_t sid, ui64 realcost, double now) override; + void OnOperationAbort(TJob* job, size_t sid) override; + +private: + static void* SourceThreadFunc(void* this_); + static void* SchedulerThreadFunc(void* this_); + void Generate(double time, const TMyFlowPtr& flow); + void PushSource(double time, const TMyFlowPtr& flow); + void PopSource(); + void Source(); + + bool IsFlowFrozen(TMyFlow* flow); + void Enqueue(TMyJob* job); + TMyJob* Dequeue(TInstant deadline); + void Scheduler(); +}; + +} diff --git a/ydb/library/shop/sim_shop/myshopmain.cpp b/ydb/library/shop/sim_shop/myshopmain.cpp new file mode 100644 index 000000000000..c78a7c64d43d --- /dev/null +++ b/ydb/library/shop/sim_shop/myshopmain.cpp @@ -0,0 +1,319 @@ +#include "myshop.h" + +#include + +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +using namespace NShopSim; + +#define WWW_CHECK(cond, ...) \ + do { \ + if (!(cond)) { \ + ythrow yexception() << Sprintf(__VA_ARGS__); \ + } \ + } while (false) \ + /**/ + +#define WWW_HTML_INNER(out, body) HTML(out) { \ + out << "" << Endl; \ + HTML_TAG() { \ + HEAD() { OutputCommonHeader(out); } \ + BODY() { \ + body; \ + } \ + } \ +} +#define WWW_HTML(out, body) out << NMonitoring::HTTPOKHTML; \ + WWW_HTML_INNER(out, body) + +void OutputCommonHeader(IOutputStream& out) +{ + out << ""; + out << ""; + out << ""; +} + +class TMachineMonPage : public NMonitoring::IMonPage { +public: + TMachineMonPage() + : IMonPage("machine") + {} + + virtual void Output(NMonitoring::IMonHttpRequest& request) { + + const char* urls[] = { + "/trace?fullscreen=y&id=.SIMSHOP_PROVIDER.FifoDequeue.pmachineid={{machineid}}.d1s&aggr=hist&autoscale=y&refresh=3000&bn=queueTimeMs&linesfill=y&mode=analytics&out=flot&pointsshow=n&xn=queueTimeMs&y1=0&x1=0&yns=_count_share", + "/trace?fullscreen=y&id=.SIMSHOP_PROVIDER.MachineExecute.pmachineid={{machineid}}.d1s&aggr=hist&autoscale=y&refresh=3000&bn=execTimeMs&linesfill=y&mode=analytics&out=flot&pointsshow=n&xn=execTimeMs&y1=0&x1=0&yns=_count_share", + "/trace?fullscreen=y&id=.SIMSHOP_PROVIDER.MachineWait.pmachineid={{machineid}}.d1s&aggr=hist&autoscale=y&refresh=3000&bn=waitTimeMs&linesfill=y&mode=analytics&out=flot&pointsshow=n&xn=waitTimeMs&y1=0&x1=0&yns=_count_share", + + "/trace?fullscreen=y&id=.SHOP_PROVIDER.Arrive.pflowctl={{flowctl}}.d200ms:.SHOP_PROVIDER.Depart.pflowctl={{flowctl}}.d200ms:.SIMSHOP_PROVIDER.FifoEnqueue.pmachineid={{machineid}}.d200ms:.SIMSHOP_PROVIDER.FifoDequeue.pmachineid={{machineid}}.d200ms&mode=analytics&out=flot&xn=_thrRTime&y1=0&yns=costInFly:queueCost&cutts=y", + "/trace?fullscreen=y&id=.SIMSHOP_PROVIDER.FifoEnqueue.pmachineid={{machineid}}.d1s&aggr=hist&autoscale=y&refresh=3000&bn=queueCost&linesfill=y&mode=analytics&out=flot&pointsshow=n&xn=queueCost&y1=0&x1=0&yns=_count_share-stack", + "/trace?fullscreen=y&id=.SIMSHOP_PROVIDER.FifoEnqueue.pmachineid={{machineid}}.d1s&aggr=hist&autoscale=y&refresh=3000&bn=queueCost&linesfill=y&mode=analytics&out=flot&pointsshow=n&xn=queueCost&y1=0&x1=0&yns=_count_share", + + "/trace?fullscreen=y&id=.SHOP_PROVIDER.Arrive.pflowctl={{flowctl}}.d200ms:.SHOP_PROVIDER.Depart.pflowctl={{flowctl}}.d200ms:.SIMSHOP_PROVIDER.FifoEnqueue.pmachineid={{machineid}}.d200ms:.SIMSHOP_PROVIDER.FifoDequeue.pmachineid={{machineid}}.d200ms&mode=analytics&out=flot&xn=_thrRTime&y1=0&yns=countInFly:queueLength&cutts=y", + "/trace?fullscreen=y&id=.SIMSHOP_PROVIDER.FifoDequeue.pmachineid={{machineid}}.d200ms&mode=analytics&out=flot&xn=_thrRTime&yns=queueTimeMs&y0=0&pointsshow=n&cutts=y", + "/trace?fullscreen=y&id=.Group.ShopFlowCtlPeriod.pflowctl={{flowctl}}.d10m&mode=analytics&out=flot&pointsshow=n&xn=periodId&yns=badPeriods:goodPeriods:zeroPeriods", + + "/trace?fullscreen=y&id=.Group.ShopFlowCtlPeriod.pflowctl={{flowctl}}.d10m&g=periodId&mode=analytics&out=flot&pointsshow=n&xn=periodId&y1=0&yns=dT_T:dL_L", + "/trace?fullscreen=y&id=.Group.ShopFlowCtlPeriod.pflowctl={{flowctl}}.d10m&g=periodId&mode=analytics&out=flot&pointsshow=n&xn=periodId&y1=0&yns=pv", + "/trace?fullscreen=y&id=.Group.ShopFlowCtlPeriod.pflowctl={{flowctl}}.d10m&g=periodId&linesfill=y&mode=analytics&out=flot&xn=periodId&y1=0&yns=state:window&pointsshow=n", + + "/trace?fullscreen=y&id=.Group.ShopFlowCtlPeriod.pflowctl={{flowctl}}.d10m&g=periodId&mode=analytics&out=flot&xn=periodId&y1=-1&y2=1&yns=error", + "/trace?fullscreen=y&id=.Group.ShopFlowCtlPeriod.pflowctl={{flowctl}}.d10m&g=periodId&linesshow=n&mode=analytics&out=flot&x1=0&xn=window&y1=0&yns=throughput&cutts=y", + "/trace?fullscreen=y&id=.Group.ShopFlowCtlPeriod.pflowctl={{flowctl}}.d10m&g=periodId&mode=analytics&out=flot&xn=periodId&y1=0&yns=throughput:throughputMin:throughputMax:throughputLo:throughputHi&pointsshow=n&legendshow=n", + + "/trace?fullscreen=y&id=.Group.ShopFlowCtlPeriod.pflowctl={{flowctl}}.d10m&g=periodId&mode=analytics&out=flot&xn=periodId&yns=mode", + "/trace?fullscreen=y&id=.Group.ShopFlowCtlPeriod.pflowctl={{flowctl}}.d10m&g=periodId&linesshow=n&mode=analytics&out=flot&x1=0&xn=window&y1=0&yns=latencyAvgMs&cutts=y", + "/trace?fullscreen=y&id=.Group.ShopFlowCtlPeriod.pflowctl={{flowctl}}.d10m&g=periodId&mode=analytics&out=flot&pointsshow=n&xn=periodId&y1=0&yns=latencyAvgMs:latencyAvgMinMs:latencyAvgMaxMs:latencyAvgLoMs:latencyAvgHiMs&legendshow=n", + + "/trace?fullscreen=y&id=.SIMSHOP_PROVIDER.MachineStats.pmachineid={{machineid}}.d10m&mode=analytics&out=flot&xn=_thrRTime&yns=utilization&linesfill=y&y1=0&y2=1&pointsshow=n", + "/trace?fullscreen=y&id=.SIMSHOP_PROVIDER.MachineWorkerStats.pmachineid={{machineid}}.d1s&autoscale=y&mode=analytics&out=flot&xn=_thrRTime&yns=activeTimeMs-stack:totalTimeMs-stack&pointsshow=n&linesfill=y&cutts=y&legendshow=n", + "/trace?fullscreen=y&id=.SHOP_PROVIDER.Depart.pflowctl={{flowctl}}.d1s&mode=analytics&out=flot&xn=realCost&yns=estCost&linesshow=n" + }; + + THashMap dict; + for (const auto& kv : request.GetParams()) { + dict[kv.first] = kv.second; + } + + TStringStream out; + out << NMonitoring::HTTPOKHTML; + HTML(out) { + out << "" << Endl; + HTML_TAG() { + BODY() { + out << ""; + for (size_t i = 0; i < Y_ARRAY_SIZE(urls); i++) { + if (i > 0 && i % 3 == 0) { + out << ""; + } + out << ""; + } + out << "
"; + } + } + } + request.Output() << out.Str(); + } +private: + template + TString Subst(const TString& str, const TDict& dict) + { + TString res = str; + for (const auto& kv: dict) { + SubstGlobal(res, "{{" + kv.first + "}}", kv.second); + } + return res; + } +}; + +class TShopMonPage : public NMonitoring::IMonPage { +private: + TMyShop* Shop; + TVector Templates; +public: + explicit TShopMonPage(TMyShop* shop) + : IMonPage("shop", "Shop") + , Shop(shop) + , Templates({"one", "two"}) + {} + + virtual void Output(NMonitoring::IMonHttpRequest& request) { + + TStringStream out; + try { + if (request.GetParams().Get("mode") == "") { + OutputMain(request, out); + } else if (request.GetParams().Get("mode") == "configure") { + PostConfigure(request, out); + } else { + ythrow yexception() << "Bad request"; + } + } catch (...) { + out.Clear(); + WWW_HTML(out, + out << "

Error

"
+                    << CurrentExceptionMessage()
+                    << Endl;
+            )
+        }
+
+        request.Output() << out.Str();
+    }
+
+    void OutputMain(const NMonitoring::IMonHttpRequest& request, IOutputStream& out)
+    {
+        out << NMonitoring::HTTPOKHTML;
+        HTML(out) {
+            out << "" << Endl;
+            HTML_TAG() {
+                OutputHead(out);
+                BODY() {
+                    out << "

Machines

"; + Shop->ForEachMachine([&out] (ui64 machineId, TMyMachine* machine, TFlowCtl* flowctl) { + out << " "; + out << "" << (machine->GetName()? machine->GetName(): ToString(machineId)) << "
"; + }); + out << "

Configure

"; + OutputConfigure(request, out); + } + } + } + } + + void PostConfigure(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) + { + TConfigPb shopCfg; + bool ok = NProtoBuf::TextFormat::ParseFromString( + request.GetPostParams().Get("config"), + &shopCfg + ); + WWW_CHECK(ok, "config parse failed"); + Shop->Configure(shopCfg); + WWW_HTML(out, + out << + "
" + "

Configured successfully

" + "
" + "\n"; + ) + } +private: + void OutputHead(IOutputStream& out) + { + out << "\n"; + out << "" << Title << "\n"; + OutputCommonHeader(out); + out << ""; + out << "\n"; + } + + void OutputConfigure(const NMonitoring::IMonHttpRequest& request, IOutputStream& out) + { + Y_UNUSED(request); + HTML(out) { + out << "
"; + DIV_CLASS("form-group") { + LABEL_CLASS_FOR("col-sm-1 control-label", "textareaQuery") { out << "Templates"; } + DIV_CLASS("col-sm-11") { + for (auto name : Templates) { + out << " "; + } + } + } + DIV_CLASS("form-group") { + LABEL_CLASS_FOR("col-sm-1 control-label", "textareaQuery") { out << "Config"; } + DIV_CLASS("col-sm-11") { + out << ""; + } + } + DIV_CLASS("form-group") { + DIV_CLASS("col-sm-offset-1 col-sm-11") { + out << ""; + } + } + out << "
"; + } + } +}; + +int main(int argc, char** argv) +{ + try { + NLWTrace::StartLwtraceFromEnv(); +#ifdef _unix_ + signal(SIGPIPE, SIG_IGN); +#endif + +#ifdef _win32_ + WSADATA dummy; + WSAStartup(MAKEWORD(2,2), &dummy); +#endif + + // Configure + int monPort = 8080; + using TMonSrvc = NMonitoring::TMonService2; + THolder MonSrvc; + NLastGetopt::TOpts opts = NLastGetopt::TOpts::Default(); + opts.AddLongOption(0, "mon-port", "port of monitoring service") + .RequiredArgument("port") + .StoreResult(&monPort, monPort); + NLastGetopt::TOptsParseResult res(&opts, argc, argv); + + // Init monservice + MonSrvc.Reset(new TMonSrvc(monPort)); + MonSrvc->Register(new TMachineMonPage()); + NLwTraceMonPage::RegisterPages(MonSrvc->GetRoot()); + NLwTraceMonPage::ProbeRegistry().AddProbesList( + LWTRACE_GET_PROBES(SHOP_PROVIDER)); + NLwTraceMonPage::ProbeRegistry().AddProbesList( + LWTRACE_GET_PROBES(SIMSHOP_PROVIDER)); + + // Start monservice + MonSrvc->Start(); + + // Initial shop config + TConfigPb shopCfg; + bool ok = NProtoBuf::TextFormat::ParseFromString( + NResource::Find("one"), + &shopCfg + ); + Y_ABORT_UNLESS(ok, "config parse failed"); + + // Start shop + TMyShop shop; + MonSrvc->Register(new TShopMonPage(&shop)); + shop.Configure(shopCfg); + + while (true) { + Sleep(TDuration::Seconds(1)); + } + + // Finish + Cout << "bye" << Endl; + return 0; + } catch (...) { + Cerr << "failure: " << CurrentExceptionMessage() << Endl; + return 1; + } +} diff --git a/ydb/library/shop/sim_shop/one.pb.txt b/ydb/library/shop/sim_shop/one.pb.txt new file mode 100644 index 000000000000..5a32986f89dc --- /dev/null +++ b/ydb/library/shop/sim_shop/one.pb.txt @@ -0,0 +1,18 @@ +Machine { + Name: "srv" + Scheduler { FIFO { Name: "fifo" } } + WorkerCount: 10 + Wait { Distr { Name: "wait" Gauss { Mean: 0.05 Disp: 0.005 } MinRelValue: 0.1 MaxRelValue: 10 } } + FlowCtl { Name: "srv" } +} + +Source { + Name: "src" + InterArrival { Distr { Name: "ia" Exp { Period: 0.0002 } MaxRelValue: 10 } } + Operation { + Name: "exec" + Machine: "srv" + EstCost { Distr { Gauss { Mean: 0.02 Disp: 0.01 } MinRelValue: 0.1 MaxRelValue: 10 } } + EstCostOverRealCost { Distr { Const: 1.0 } } + } +} diff --git a/ydb/library/shop/sim_shop/two.pb.txt b/ydb/library/shop/sim_shop/two.pb.txt new file mode 100644 index 000000000000..cccf13a8557d --- /dev/null +++ b/ydb/library/shop/sim_shop/two.pb.txt @@ -0,0 +1,26 @@ +Machine { + Name: "srv1" + Scheduler { FIFO { Name: "fifo1" } } + WorkerCount: 10 + Wait { Distr { Name: "wait1" Gauss { Mean: 0.05 Disp: 0.005 } MinRelValue: 0.1 MaxRelValue: 10 } } + FlowCtl { Name: "srv1" } +} + +Machine { + Name: "srv2" + Scheduler { FIFO { Name: "fifo2" } } + WorkerCount: 10 + Wait { Distr { Name: "wait2" Gauss { Mean: 0.05 Disp: 0.005 } MinRelValue: 0.1 MaxRelValue: 10 } } + FlowCtl { Name: "srv2" } +} + +Source { + Name: "src" + InterArrival { Distr { Name: "ia" Exp { Period: 0.0002 } MaxRelValue: 10 } } + Operation { + Name: "exec" + Machine: "srv" + EstCost { Distr { Gauss { Mean: 0.02 Disp: 0.01 } MinRelValue: 0.1 MaxRelValue: 10 } } + EstCostOverRealCost { Distr { Const: 1.0 } } + } +} diff --git a/ydb/library/shop/sim_shop/ya.make b/ydb/library/shop/sim_shop/ya.make new file mode 100644 index 000000000000..68e3add530ed --- /dev/null +++ b/ydb/library/shop/sim_shop/ya.make @@ -0,0 +1,25 @@ +PROGRAM() + +RESOURCE( + one.pb.txt one + two.pb.txt two +) + +SRCS( + myshopmain.cpp + myshop.cpp + config.proto +) + +PEERDIR( + ydb/library/drr + library/cpp/lwtrace/mon + ydb/library/shop + library/cpp/getopt + library/cpp/lwtrace + library/cpp/monlib/dynamic_counters + library/cpp/resource + library/cpp/protobuf/util +) + +END() diff --git a/ydb/library/shop/ut/estimator_ut.cpp b/ydb/library/shop/ut/estimator_ut.cpp new file mode 100644 index 000000000000..6aa74e9e5591 --- /dev/null +++ b/ydb/library/shop/ut/estimator_ut.cpp @@ -0,0 +1,58 @@ +#include + +#include + +using namespace NShop; + +Y_UNIT_TEST_SUITE(ShopEstimator) { + Y_UNIT_TEST(StartLwtrace) { + NLWTrace::StartLwtraceFromEnv(); + } + + Y_UNIT_TEST(MovingAverage) { + TMovingAverageEstimator<1, 2> est(1.0); + UNIT_ASSERT_EQUAL(est.GetAverage(), 1.0); + est.Update(2.0); + UNIT_ASSERT(fabs(est.GetAverage() - 1.5) < 1e-5); + for (int i = 1; i < 100; i++) { + est.Update(2.0); + } + UNIT_ASSERT(fabs(est.GetAverage() - 2.0) < 1e-5); + } + + Y_UNIT_TEST(MovingSlr) { + TMovingSlrEstimator<1, 2> est(1.0, 1.0, 2.0, 2.0); + + // check that initial 2-point guess is a straight line + UNIT_ASSERT(fabs(est.GetEstimation(3.0) - 3.0) < 1e-5); + UNIT_ASSERT(fabs(est.GetEstimation(4.0) - 4.0) < 1e-5); + UNIT_ASSERT(fabs(est.GetEstimation(0.0) - 0.0) < 1e-5); + + // check that update has right 1/2 weight + est.Update(2.5, 2.5); + UNIT_ASSERT(fabs(est.GetEstimation(3.0) - 3.0) < 1e-5); + UNIT_ASSERT(fabs(est.GetEstimation(4.0) - 4.0) < 1e-5); + UNIT_ASSERT(fabs(est.GetEstimation(0.0) - 0.0) < 1e-5); + UNIT_ASSERT(fabs(est.GetAverage() - 2.0) < 1e-5); + + // check history wipe out + for (int i = 1; i < 100; i++) { + est.Update(10.0, 1.0); + est.Update(11.0, 5.0); + } + UNIT_ASSERT(fabs(est.GetEstimation(1.0) - 10.0) < 1e-5); + UNIT_ASSERT(fabs(est.GetEstimation(5.0) - 11.0) < 1e-5); + UNIT_ASSERT(fabs(est.GetEstimation(9.0) - 12.0) < 1e-5); + UNIT_ASSERT(fabs(est.GetEstimation(3.0) - 10.5) < 1e-5); + + // another check history wipe out + for (int i = 1; i < 100; i++) { + est.Update(10.0, 5.0); + est.Update(11.0, 1.0); + } + UNIT_ASSERT(fabs(est.GetEstimation(5.0) - 10.0) < 1e-5); + UNIT_ASSERT(fabs(est.GetEstimation(1.0) - 11.0) < 1e-5); + UNIT_ASSERT(fabs(est.GetEstimation(9.0) - 9.0) < 1e-5); + UNIT_ASSERT(fabs(est.GetEstimation(3.0) - 10.5) < 1e-5); + } +} diff --git a/ydb/library/shop/ut/flowctl_ut.cpp b/ydb/library/shop/ut/flowctl_ut.cpp new file mode 100644 index 000000000000..89d9264442e6 --- /dev/null +++ b/ydb/library/shop/ut/flowctl_ut.cpp @@ -0,0 +1,523 @@ +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +namespace NFcTest { + +//////////////////////////////////////////////////////////////////////////////// +/// Event-driven simulator core +/// +using namespace NShop; + +class INode; +class TSimulator; + +struct TMyEvent { + double Time = 0; // Time at which event should be executed + bool Quit = false; + INode* Sender = nullptr; + INode* Receiver = nullptr; + + virtual ~TMyEvent() {} + + virtual void Print(IOutputStream& os); +}; + +class INode { +protected: + TSimulator* Sim; + TString Name; +public: + INode(TSimulator* sim) + : Sim(sim) + {} + virtual ~INode() {} + virtual void Receive(TMyEvent* ev) = 0; + void SetName(const TString& name) { Name = name; } + const TString& GetName() const { return Name; } +protected: + void Send(TMyEvent* ev, INode* receiver); + void SendAt(TMyEvent* ev, INode* receiver, double time); + void SendAfter(TMyEvent* ev, INode* receiver, double delay); +}; + +class TSimulator { +public: + double CurrentTime = 0; + struct TEventsCmp { + bool operator()(const TMyEvent* l, const TMyEvent* r) const { + return l->Time > r->Time; + } + }; + TVector Events; + bool SimLog; +public: + TSimulator() + { + TString path = GetEnv("SIMLOG"); + SimLog = path && TString(path) == "y"; + } + + ~TSimulator() + { + for (TMyEvent* ev : Events) { + delete ev; + } + } + + void Schedule(TMyEvent* ev, INode* sender, INode* receiver, double time) + { + if (receiver == nullptr && !ev->Quit) { + delete ev; + } else { + ev->Time = time; + ev->Sender = sender; + ev->Receiver = receiver; + Events.push_back(ev); + PushHeap(Events.begin(), Events.end(), TEventsCmp()); + } + } + + void Run() + { + while (!Events.empty()) { + PopHeap(Events.begin(), Events.end(), TEventsCmp()); + TMyEvent* ev = Events.back(); + Events.pop_back(); + CurrentTime = ev->Time; + if (SimLog) { + ev->Print(Cerr); + Cerr << Endl; + } + if (ev->Quit) { + delete ev; + return; + } else { + ev->Receiver->Receive(ev); + } + } + } + + + void QuitAt(double time) + { + TMyEvent* ev = new TMyEvent(); + ev->Quit = true; + Schedule(ev, nullptr, nullptr, time); + } + + double Now() const { return CurrentTime; } +}; + +void INode::Send(TMyEvent* ev, INode* receiver) +{ + Sim->Schedule(ev, this, receiver, Sim->Now()); +} + +void INode::SendAt(TMyEvent* ev, INode* receiver, double time) +{ + Sim->Schedule(ev, this, receiver, time); +} + +void INode::SendAfter(TMyEvent* ev, INode* receiver, double delay) +{ + Sim->Schedule(ev, this, receiver, Sim->Now() + delay); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Flow control related stuff +/// + +struct TMyRequest : public TMyEvent { + bool Arrived = false; + double ArriveTime = 0; + double DepartTime = 0; + ui64 Cost = 0; + TFcOp FcOp; + + explicit TMyRequest(ui64 cost = 0) + : Cost(cost) + {} + + double ResponseTime() const { return DepartTime - ArriveTime; } + + virtual void Print(IOutputStream& os); +}; + +struct TMyTransition : public TMyEvent { + TFlowCtl::EStateTransition Transition; + bool IsOpen; + bool Arrive; // true = arrive, false = depart + + TMyTransition(TFlowCtl::EStateTransition transition, bool isOpen, bool arrive) + : Transition(transition) + , IsOpen(isOpen) + , Arrive(arrive) + {} + + virtual void Print(IOutputStream& os); +}; + +class TFcSystem : public INode { +protected: + TFlowCtl Fc; + INode* Source = nullptr; +public: + TFcSystem(TSimulator* sim) + : INode(sim) + {} + + void Configure(const TFlowCtlConfig& cfg) + { + Fc.Configure(cfg, Sim->Now()); + } + + void Receive(TMyEvent* ev) override + { + TMyRequest* req = CheckedCast(ev); + if (!req->Arrived) { + req->ArriveTime = Sim->Now(); + req->Arrived = true; + TFlowCtl::EStateTransition st = Fc.ArriveST(req->FcOp, req->Cost, req->ArriveTime); + if (Source) { + Send(new TMyTransition(st, Fc.IsOpen(), true), Source); + } + Enter(req); + } else { + req->DepartTime = Sim->Now(); + TFlowCtl::EStateTransition st = Fc.DepartST(req->FcOp, req->Cost, req->DepartTime); + if (Source) { + Send(new TMyTransition(st, Fc.IsOpen(), false), Source); + } + Exit(req); + } + } + + bool IsOpen() const { return Fc.IsOpen(); } + + void SetSource(INode* source) { Source = source; } +protected: + virtual void Enter(TMyRequest* req) = 0; + virtual void Exit(TMyRequest* req) = 0; +}; + +TFlowCtlConfig DefaultFlowCtlConfig() +{ + TFlowCtlConfig cfg; + return cfg; +} + +class TOneServerWithFifo : public TFcSystem { +public: + double Throughput; // cost/sec + TDeque Queue; + INode* Target = nullptr; + bool Busy = false; + + TOneServerWithFifo(TSimulator* sim, double throughput) + : TFcSystem(sim) + , Throughput(throughput) + { + Y_ABORT_UNLESS(Throughput > 0); + } + + ~TOneServerWithFifo() + { + for (TMyRequest* req : Queue) { + delete req; + } + } + + void Enter(TMyRequest* req) override + { + if (!Busy) { + Execute(req); + Busy = true; + } else { + Queue.push_back(req); + } + } + + void Exit(TMyRequest* req) override + { + Send(req, Target); + if (Queue.empty()) { + Busy = false; + } else { + TMyRequest* nextReq = Queue.back(); + Queue.pop_back(); + Execute(nextReq); + } + } + + void SetTarget(INode* target) { Target = target; } +private: + void Execute(TMyRequest* req) + { + SendAfter(req, this, req->Cost / Throughput); + } +}; + +class TParallelServersWithFifo : public TFcSystem { +public: + double Throughput; // cost/sec per server + ui64 ServersCount; + TDeque Queue; + INode* Target = nullptr; + ui64 BusyCount = 0; + + TParallelServersWithFifo(TSimulator* sim, double throughput, ui64 serversCount) + : TFcSystem(sim) + , Throughput(throughput) + , ServersCount(serversCount) + { + Y_ABORT_UNLESS(Throughput > 0); + } + + ~TParallelServersWithFifo() + { + for (TMyRequest* req : Queue) { + delete req; + } + } + + void Enter(TMyRequest* req) override + { + if (BusyCount < ServersCount) { + Execute(req); + BusyCount++; + } else { + Queue.push_back(req); + } + } + + void Exit(TMyRequest* req) override + { + Send(req, Target); + if (Queue.empty()) { + BusyCount--; + } else { + TMyRequest* nextReq = Queue.back(); + Queue.pop_back(); + Execute(nextReq); + } + } + + void SetTarget(INode* target) { Target = target; } +private: + void Execute(TMyRequest* req) + { + SendAfter(req, this, req->Cost / Throughput); + } +}; + +class TUnlimSource : public INode { +private: + TFcSystem* Target = nullptr; + ui64 Cost; + bool InFly = false; +public: + TUnlimSource(TSimulator* sim, ui64 cost) + : INode(sim) + , Cost(cost) + {} + + void Receive(TMyEvent* ev) override + { + TMyTransition* tr = CheckedCast(ev); + if (tr->Arrive) { + InFly = false; + } + if (tr->IsOpen && !InFly) { + Generate(); + } + delete tr; + } + + void Generate() + { + Y_ABORT_UNLESS(!InFly); + Send(new TMyRequest(Cost), Target); + InFly = true; + } + + void SetTarget(TFcSystem* target) + { + Y_ABORT_UNLESS(!Target); + Target = target; + Generate(); + } +}; + +class TChecker : public INode { +private: + using TCheckFunc = std::function; + TCheckFunc CheckFunc; + INode* Target = nullptr; +public: + TChecker(TSimulator* sim, TCheckFunc f) + : INode(sim) + , CheckFunc(f) + {} + + void Receive(TMyEvent* ev) override + { + TMyRequest* req = CheckedCast(ev); + CheckFunc(req); + Send(req, Target); + } + + void SetTarget(INode* target) { Target = target; } +}; + + +//////////////////////////////////////////////////////////////////////////////// +/// Auxilary stuff +/// + +struct TAuxEvent : public TMyEvent { + std::function Func; + + explicit TAuxEvent(std::function&& f) + : Func(std::move(f)) + {} +}; + +class TAuxNode : public INode { +public: + explicit TAuxNode(TSimulator* sim) + : INode(sim) + {} + + void ExecuteAt(double time, std::function&& f) + { + SendAt(new TAuxEvent(std::move(f)), this, time); + } + + void Receive(TMyEvent* ev) override + { + TAuxEvent* aux = CheckedCast(ev); + aux->Func(); + delete aux; + } +}; + +void TMyEvent::Print(IOutputStream& os) +{ + if (Quit) { + os << Sprintf("[%010.3lf] QUIT", Time); + } else { + os << Sprintf("[%010.3lf] %s->%s", + Time, + Sender? Sender->GetName().data(): "nullptr", + Receiver? Receiver->GetName().data(): "nullptr" + ); + } +} + +void TMyRequest::Print(IOutputStream& os) +{ + TMyEvent::Print(os); + os << " Arrived=" << Arrived + << " Cost=" << Cost + << " ArriveTime=" << ArriveTime + << " DepartTime=" << DepartTime + ; +} + +void TMyTransition::Print(IOutputStream& os) +{ + TMyEvent::Print(os); + os << " Transition=" << int(Transition) + << " IsOpen=" << IsOpen + << " Arrive=" << Arrive + ; +} + +} // namespace NFcTest + +Y_UNIT_TEST_SUITE(ShopFlowCtl) { + + using namespace NFcTest; + using namespace NShop; + + Y_UNIT_TEST(StartLwtrace) { + NLWTrace::StartLwtraceFromEnv(); + } + + Y_UNIT_TEST(OneOp) { + { + TSimulator sim; + TOneServerWithFifo srv(&sim, 1.0); + srv.Configure(DefaultFlowCtlConfig()); + sim.Schedule(new TMyRequest(3), nullptr, &srv, 5.0); + sim.QuitAt(10.0); + sim.Run(); + UNIT_ASSERT(sim.Now() == 10.0); + } + + { + TSimulator sim; + TOneServerWithFifo srv(&sim, 1.0); + srv.Configure(DefaultFlowCtlConfig()); + sim.Schedule(new TMyRequest(3), nullptr, &srv, 5.0); + sim.Run(); + UNIT_ASSERT(sim.Now() == 8.0); + } + } + + Y_UNIT_TEST(Unlim_D_1_FIFO) { + TSimulator sim; + TUnlimSource src(&sim, 1); + TOneServerWithFifo srv(&sim, 100.0); + srv.Configure(DefaultFlowCtlConfig()); + TChecker chk(&sim, [&sim] (TMyRequest* req) { + if (sim.Now() > 500.0) { + UNIT_ASSERT(req->ResponseTime() < 5.0); + } + }); + + src.SetTarget(&srv); + srv.SetSource(&src); + srv.SetTarget(&chk); + + src.SetName("src"); + srv.SetName("srv"); + chk.SetName("chk"); + + sim.QuitAt(2000.0); + sim.Run(); + } + + Y_UNIT_TEST(Unlim_D_k_FIFO) { + TSimulator sim; + TUnlimSource src(&sim, 1); + TParallelServersWithFifo srv(&sim, 10.0, 10); + srv.Configure(DefaultFlowCtlConfig()); + TChecker chk(&sim, [&sim] (TMyRequest* req) { + if (sim.Now() > 500.0) { + UNIT_ASSERT(req->ResponseTime() < 5.0); + } + }); + + src.SetTarget(&srv); + srv.SetSource(&src); + srv.SetTarget(&chk); + + src.SetName("src"); + srv.SetName("srv"); + chk.SetName("chk"); + + sim.QuitAt(2000.0); + sim.Run(); + } +} diff --git a/ydb/library/shop/ut/lazy_scheduler_ut.cpp b/ydb/library/shop/ut/lazy_scheduler_ut.cpp new file mode 100644 index 000000000000..0027e5c10b5c --- /dev/null +++ b/ydb/library/shop/ut/lazy_scheduler_ut.cpp @@ -0,0 +1,1537 @@ +#include + +#include +#include +#include +#include +#include + +#define SHOP_LAZY_SCHEDULER_UT_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES) \ + PROBE(LazyUtScheduleState, GROUPS(), \ + TYPES(TString), \ + NAMES("state")) \ + PROBE(LazyUtScheduleTask, GROUPS(), \ + TYPES(TString, ui64), \ + NAMES("queue", "cost")) \ + /**/ + +LWTRACE_DECLARE_PROVIDER(SHOP_LAZY_SCHEDULER_UT_PROVIDER) +LWTRACE_DEFINE_PROVIDER(SHOP_LAZY_SCHEDULER_UT_PROVIDER) + +Y_UNIT_TEST_SUITE(ShopLazyScheduler) { + LWTRACE_USING(SHOP_LAZY_SCHEDULER_UT_PROVIDER); + using namespace NShop; + + template + struct TTest { + // We need Priority in tests to break ties in deterministic fashion + struct TMyRes { + using TCost = typename TRes::TCost; + using TTag = typename TRes::TTag; + + struct TKey { + typename TRes::TKey Key; + int Priority; + + bool operator<(const TKey& rhs) const + { + if (Key < rhs.Key) { + return true; + } else if (Key > rhs.Key) { + return false; + } else { + return Priority < rhs.Priority; + } + } + }; + + inline static TKey OffsetKey(TKey key, typename TRes::TTag offset); + template + inline static void SetKey(TKey& key, ConsumerT* consumer); + inline static TTag GetTag(const TKey& key); + inline static TKey MaxKey(); + template + inline static TKey ZeroKey(ConsumerT* consumer); + inline static void ActivateKey(TKey& key, TTag vtime); + }; + + class TMyQueue; + using TMySchedulable = TSchedulable; + using TMyConsumer = NLazy::TConsumer; + using TCtx = NLazy::TCtx; + + class TMyTask : public TMySchedulable { + public: + TMyQueue* Queue = nullptr; + public: + explicit TMyTask(typename TMyRes::TCost cost) + { + this->Cost = cost; + } + }; + + class TMyQueue: public TMyConsumer { + public: + TDeque Tasks; + int Priority; + TMachineIdx MachineIdx = 0; + public: // Interface for clients + TMyQueue(TWeight w = 1, int priority = 0) + : Priority(priority) + { + this->SetWeight(w); + } + + ~TMyQueue() + { + for (auto i = Tasks.begin(), e = Tasks.end(); i != e; ++i) { + delete *i; + } + } + + void SetMachineIdx(TMachineIdx midx) + { + MachineIdx = midx; + } + + void PushTask(TMyTask* task) + { + if (Empty()) { // Scheduler must be notified on first task in queue + this->Activate(MachineIdx); + } + task->Queue = this; + Tasks.push_back(task); + } + + void PushTaskFront(TMyTask* task) + { + if (Empty()) { // Scheduler must be notified on first task in queue + this->Activate(MachineIdx); + } + task->Queue = this; + Tasks.push_front(task); + } + + using TMyConsumer::Activate; + using TMyConsumer::Deactivate; + + void Activate() + { + this->Activate(MachineIdx); + } + + void Deactivate() + { + this->Deactivate(MachineIdx); + } + + bool Empty() const + { + return Tasks.empty(); + } + + public: // Interface for scheduler + TMySchedulable* PopSchedulable(const TCtx&) override + { + if (Tasks.empty()) { + return nullptr; // denial + } + UNIT_ASSERT(!Tasks.empty()); + TMyTask* task = Tasks.front(); + Tasks.pop_front(); + if (Tasks.empty()) { + this->Deactivate(MachineIdx); + } + return task; + } + + void DeactivateAll() override + { + Deactivate(); + } + }; + + + /////////////////////////////////////////////////////////////////////////////// + + class TMyScheduler; + + struct TMyShopState : public TShopState { + explicit TMyShopState(size_t size = 1) + : TShopState(size) + {} + + void Freeze(TMachineIdx idx); + void Unfreeze(TMachineIdx idx); + void AddScheduler(TMyScheduler* scheduler); + }; + + /////////////////////////////////////////////////////////////////////////////// + + using TQueuePtr = std::shared_ptr; + + class TMyScheduler: public NLazy::TScheduler { + public: + THashMap Queues; + int Priority; + public: + explicit TMyScheduler(TMyShopState& ss, TWeight w = 1, int priority = 0) + : Priority(priority) + { + ss.AddScheduler(this); + this->SetWeight(w); + } + + ~TMyScheduler() + { + this->UpdateCounters(); + } + + void AddQueue(const TString& name, TMachineIdx midx, const TQueuePtr& queue) + { + queue->SetName(name); + queue->SetMachineIdx(midx); + Queues.emplace(name, queue); + this->Attach(queue.get()); + } + + void AddSubScheduler(const TString& name, TMyScheduler* scheduler) + { + scheduler->SetName(name); + this->Attach(scheduler); + } + + void DeleteQueue(const TString& name) + { + auto iter = Queues.find(name); + if (iter != Queues.end()) { + TMyConsumer* consumer = iter->second.get(); + consumer->Detach(); + Queues.erase(iter); + } + } + + void DeleteSubScheduler(TMyScheduler* scheduler) + { + scheduler->Detach(); + } + }; + + /////////////////////////////////////////////////////////////////////////////// + + template + static void SetPriority(int& priority, ConsumerT const* consumer) + { + if (auto queue = dynamic_cast(consumer)) { + priority = queue->Priority; + } else if (auto sched = dynamic_cast(consumer)) { + priority = sched->Priority; + } else { + UNIT_FAIL("unable get priority of object of type: " << TypeName(consumer)); + } + } + + static void Generate(TMyQueue* queue, const TString& tasks) + { + TVector v = SplitString(tasks, " "); + for (size_t i = 0; i < v.size(); i++) { + queue->PushTask(new TMyTask(FromString(v[i]))); + } + } + + static void GenerateFront(TMyQueue* queue, const TString& tasks) + { + TVector v = SplitString(tasks, " "); + for (size_t i = 0; i < v.size(); i++) { + queue->PushTaskFront(new TMyTask(FromString(v[i]))); + } + } + + static TString Schedule(TMyScheduler& sched, size_t count = size_t(-1), bool printcost = false) + { + TStringStream ss; + while (count--) { + LWPROBE(LazyUtScheduleState, sched.DebugString()); + TMyTask* task = static_cast(sched.PopSchedulable()); + if (!task) { + break; + } + LWPROBE(LazyUtScheduleTask, task->Queue->GetName(), task->Cost); + ss << task->Queue->GetName(); + if (printcost) { + ss << task->Cost; + } + delete task; + } + return ss.Str(); + } + }; + + /////////////////////////////////////////////////////////////////////////////// + + template + void TTest::TMyShopState::Freeze(TMachineIdx idx) + { + TShopState::Freeze(idx); + } + + template + void TTest::TMyShopState::Unfreeze(TMachineIdx idx) + { + TShopState::Unfreeze(idx); + } + + template + void TTest::TMyShopState::AddScheduler(TMyScheduler* scheduler) + { + scheduler->SetShopState(this); + } + + /////////////////////////////////////////////////////////////////////////////// + + template + template + inline void TTest::TMyRes::SetKey( + typename TTest::TMyRes::TKey& key, + ConsumerT* consumer) + { + TRes::SetKey(key.Key, consumer); + TTest::SetPriority(key.Priority, consumer); + } + + template + inline typename TRes::TTag TTest::TMyRes::GetTag( + const typename TTest::TMyRes::TKey& key) + { + return TRes::GetTag(key.Key); + } + + template + inline typename TTest::TMyRes::TKey TTest::TMyRes::OffsetKey( + typename TTest::TMyRes::TKey key, + typename TRes::TTag offset) + { + return { TRes::OffsetKey(key.Key, offset), key.Priority }; + } + + template + inline typename TTest::TMyRes::TKey TTest::TMyRes::MaxKey() + { + return { TRes::MaxKey(), std::numeric_limits::max() }; + } + + template + template + inline typename TTest::TMyRes::TKey TTest::TMyRes::ZeroKey( + ConsumerT* consumer) + { + TKey key; + key.Key = TRes::ZeroKey(consumer); + TTest::SetPriority(key.Priority, consumer); + return key; + } + + template + inline void TTest::TMyRes::ActivateKey( + typename TTest::TMyRes::TKey& key, + typename TRes::TTag vtime) + { + TRes::ActivateKey(key.Key, vtime); + // Keep key.Priority unchanged + } + + namespace NSingleResource { + using TRes = NShop::TSingleResource; + using TMyConsumer = TTest::TMyConsumer; + using TMyShopState = TTest::TMyShopState; + using TMyScheduler = TTest::TMyScheduler; + using TMyQueue = TTest::TMyQueue; + using TQueuePtr = TTest::TQueuePtr; + + template + void Generate(TArgs&&... args) + { + TTest::Generate(args...); + } + + template + void GenerateFront(TArgs&&... args) + { + TTest::GenerateFront(args...); + } + + template + auto Schedule(TArgs&&... args) + { + return TTest::Schedule(args...); + } + } + + Y_UNIT_TEST(StartLwtrace) { + NLWTrace::StartLwtraceFromEnv(); + } + + Y_UNIT_TEST(Simple) { + using namespace NSingleResource; + + TMyShopState state; + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABABAB"); + + Generate(A, "50 50 50 50 50"); + Generate(B, "50 50 50 50 50"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABABABABAB"); + + Generate(A, "20 20 20 20 20 20 20"); + Generate(B, "20 20 20 20 20 20 20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABABABABABABAB"); + + Generate(A, "20 20 20 20 20 20 20"); + Generate(B, "50 50 50" ); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABAABAAABA"); + + Generate(A, " 100 100"); + Generate(B, "20 20 20 20 20 20 20 "); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABBBBBABB"); + + TMyQueue* C; + sched.AddQueue("C", 0, TQueuePtr(C = new TMyQueue(2, 2))); + + Generate(A, "20 20 20 20 20 20"); + Generate(B, "20 20 20 20 20 20"); + Generate(C, "20 20 20 20 20 20 20 20 20 20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCCABCCABCCABCCABCCAB"); + + sched.DeleteQueue("A"); + // sched.DeleteQueue("B"); // scheduler must delete queue be itself + } + + Y_UNIT_TEST(DoubleActivation) { + using namespace NSingleResource; + + TMyShopState state; + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "AB"); + + A->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "AB"); + + A->Activate(); + B->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AB"); + } + + Y_UNIT_TEST(SimpleLag) { + using namespace NSingleResource; + + TMyShopState state; + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + TMyQueue* E; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 0, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", 0, TQueuePtr(D = new TMyQueue(1, 3))); + sched.AddQueue("E", 0, TQueuePtr(E = new TMyQueue(1, 4))); + + Generate(A, "500 500 500"); // 25 + Generate(B, "500 500 500"); // 25 + Generate(C, "500 500 500"); // 25 + Generate(D, "500 500 500"); // 25 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 8), "ABCDABCD"); + Generate(E, "500"); // 100 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "EABCD"); + } + + Y_UNIT_TEST(Complex) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + TMyQueue* E; + TMyQueue* X; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 0, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", 0, TQueuePtr(D = new TMyQueue(1, 3))); + sched.AddQueue("E", 0, TQueuePtr(E = new TMyQueue(1, 4))); + sched.AddQueue("X", 1, TQueuePtr(X = new TMyQueue(1, 5))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABABAB"); + + Generate(A, "100 100 100"); + Generate(X, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AXAXAX"); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + Generate(E, "100 100 100"); + Generate(X, "100 100 100 100 100 100 100 100 100 100 100 100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDEXABCDEXABCDEXXXXXXXXXXXXX"); + } + + Y_UNIT_TEST(ComplexWithWeights) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 1, TQueuePtr(C = new TMyQueue(3, 2))); + sched.AddQueue("D", 1, TQueuePtr(D = new TMyQueue(3, 3))); + + Generate(A, "100 100 100"); // 100 + Generate(B, "100 100 100"); // 100 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABABAB"); + + Generate(C, "100 100 100"); // 100 + Generate(D, "100 100 100"); // 100 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDCDCD"); + + Generate(A, "100 100 100 100 100 100 100 100"); + Generate(C, "100 100 100 100 100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ACCCACCCACCAAAAA"); + + Generate(B, "100 100 100 100 100 100 100 100"); + Generate(D, "100 100 100 100 100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "BDDDBDDDBDDBBBBB"); + + Generate(A, "200 200 200 200 200 200 200 200 200 200 200"); + Generate(B, "200 200 200 200 200 200 200 200 200 200 200"); + Generate(C, "200 200 200 200 200 200 200 200 200 200 200"); + Generate(D, "200 200 200 200 200 200 200 200 200 200 200"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDCDCDABCDCDCDABCDCDCDABCDCDABABABABABABAB"); + + Generate(A, "100 100 100 100 100 100 100 100 100 100 100"); + Generate(B, "100 100 100 100 100 100 100 100 100 100 100"); + Generate(C, "100 100 100 100 100 100 100 100 100 100 100"); + Generate(D, "100 100 100 100 100 100 100 100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDCDCDABCDCDCDABCDCDCDABCDCDABABABABABABAB"); + + Generate(A, "50 50 50 50 50 50 50 50 50 50 50"); + Generate(B, "50 50 50 50 50 50 50 50 50 50 50"); + Generate(C, "50 50 50 50 50 50 50 50 50 50 50"); + Generate(D, "50 50 50 50 50 50 50 50 50 50 50"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDCDCDABCDCDCDABCDCDCDABCDCDABABABABABABAB"); + } + + Y_UNIT_TEST(OneQueueFrontPush) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue())); + + Generate(A, "10 20 30"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1, true), "A10"); + GenerateFront(A, "40"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(-1), true), "A40A20A30"); + } + + Y_UNIT_TEST(SimpleFrontPush) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "10 30 40"); + Generate(B, "10 20 30"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2, true), "A10B10"); + GenerateFront(A, "20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(-1), true), "A20B20A30B30A40"); + } + + Y_UNIT_TEST(SimpleFrontPushAll) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "10 30 40"); + Generate(B, " 5 30 40"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2, true), "A10B5"); + GenerateFront(A, "20"); + GenerateFront(B, "20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4, true), "B20A20B30A30"); + GenerateFront(A, "10 10"); + GenerateFront(B, "10 8"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(-1), true), "B8A10B10A10B40A40"); + } + + Y_UNIT_TEST(ComplexFrontPush) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 1, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", 1, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "10 20"); + Generate(B, "10 30"); + Generate(C, "10 20"); + Generate(D, "10 20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4, true), "A10B10C10D10"); + GenerateFront(B, "20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(-1), true), "A20B20C20D20B30"); + } + + Y_UNIT_TEST(ComplexFrontPushAll) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 1, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", 1, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "10 36"); + Generate(B, "10 34"); + Generate(C, "10 32"); + Generate(D, "10 30"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4, true), "A10B10C10D10"); + GenerateFront(A, "20"); + GenerateFront(B, "21"); + GenerateFront(C, "22"); + GenerateFront(D, "23"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(-1), true), "A20B21C22D23A36B34C32D30"); + } + + Y_UNIT_TEST(ComplexMultiplePush) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 1, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", 1, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "5 5 5 5 5"); + Generate(B, "10 10"); + Generate(C, "10 10"); + Generate(D, "10 10"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDAABCDAA"); + } + + Y_UNIT_TEST(ComplexFrontMultiplePush) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 1, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", 1, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "5"); + Generate(B, "10 10"); + Generate(C, "10 10"); + Generate(D, "10 10"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1, true), "A5"); + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1, true), "B10"); + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4, true), "C10D10A5A5"); + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1, true), "B10"); + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(-1), true), "C10D10A5A5"); + } + + Y_UNIT_TEST(ComplexCheckEmpty) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 1, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", 1, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(1), true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(1), true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(1), true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(1), true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(-1), true), "A5"); + } + + Y_UNIT_TEST(SimpleFreeze) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100 100"); + Generate(B, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + state.Unfreeze(0); + + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABAB"); + + Generate(A, "100 100 100 100"); + Generate(B, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "A"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "B"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "A"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "B"); + } + + Y_UNIT_TEST(FreezeSaveTagDiff) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 1, TQueuePtr(C = new TMyQueue(1, 2))); + + Generate(A, "100 100 100 100"); + Generate(B, "50 25 25 100 100 100"); + Generate(C, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 3), "ABC"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "CC"); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "BBABCABAB"); + } + + Y_UNIT_TEST(FreezeSaveTagDiffOnIdlePeriod) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 1, TQueuePtr(C = new TMyQueue(1, 2))); + + Generate(A, "100 100 100 100"); + Generate(B, "50 25 25 100 100 100"); + Generate(C, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 3), "ABC"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CC"); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "BBABABAB"); + } + + Y_UNIT_TEST(FreezeSaveTagDiffOnSeveralIdlePeriods) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 1, TQueuePtr(C = new TMyQueue(1, 2))); + + Generate(A, "100 100 100 100"); + Generate(B, "50 25 25 100 100 100"); + Generate(C, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 3), "ABC"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CC"); + Generate(C, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CCC"); + Generate(C, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CCC"); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "BBABABAB"); + } + + Y_UNIT_TEST(ComplexFreeze) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 1, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", 1, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "100 100 100 100"); + Generate(B, "100 100 100 100"); + Generate(C, "100 100 100 100"); + Generate(D, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "CDCD"); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDABAB"); + + Generate(A, "100 100 100 100"); + Generate(B, "100 100 100 100"); + Generate(C, "100 100 100 100"); + Generate(D, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "CD"); + state.Freeze(1); + state.Unfreeze(1); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "CD"); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDABAB"); + + Generate(A, "100 100 100 100"); + Generate(B, "100 100 100 100"); + Generate(C, "100 100 100 100"); + Generate(D, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "CD"); + state.Freeze(1); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + state.Unfreeze(1); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "CD"); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDABAB"); + + Generate(A, "100 100 100 100"); + Generate(B, "100 100 100 100"); + Generate(C, "100 100 100 100"); + Generate(D, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + state.Freeze(0); + state.Freeze(1); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + state.Unfreeze(0); + state.Unfreeze(1); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "CDCD"); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDABAB"); + + Generate(A, "100 100 100 100"); + Generate(B, "100 100 100 100"); + Generate(C, "100 100 100 100"); + Generate(D, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + state.Freeze(0); + state.Freeze(1); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + state.Unfreeze(1); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "C"); + state.Freeze(1); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + state.Unfreeze(1); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "D"); + state.Freeze(1); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + state.Unfreeze(1); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "C"); + state.Freeze(1); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + state.Unfreeze(1); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "D"); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDABAB"); + } + + Y_UNIT_TEST(ComplexLocalBusyPeriods) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 1, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", 1, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "100 100"); + Generate(B, "100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "CDCD"); + for (int i = 0; i < 10; i++) { + Generate(C, "50 50 50 40"); + Generate(D, "100 100 "); + UNIT_ASSERT_STRINGS_EQUAL_C(Schedule(sched), "CDCCDC", i); + } + state.Unfreeze(0); + Generate(C, "50 50 50"); + Generate(D, "50 50 50"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDCDABCD"); + } + + Y_UNIT_TEST(ComplexGlobalBusyPeriods) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 1, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", 1, TQueuePtr(D = new TMyQueue(1, 3))); + + for (int j = 0; j < 5; j++) { + Generate(A, "100 100"); + Generate(B, "100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "CDCD"); + for (int i = 0; i < 5; i++) { + Generate(C, "50 50 50 40"); + Generate(D, "100 100 "); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDCCDC"); + } + state.Unfreeze(0); + Generate(C, "50 50 25"); + Generate(D, "50 50 50"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDCDABCD"); + } + } + + Y_UNIT_TEST(VeryComplexFreeze) { + using namespace NSingleResource; + + TMyShopState state(3); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + TMyQueue* E; + TMyQueue* F; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 1, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", 1, TQueuePtr(D = new TMyQueue(1, 3))); + sched.AddQueue("E", 2, TQueuePtr(E = new TMyQueue(1, 4))); + sched.AddQueue("F", 2, TQueuePtr(F = new TMyQueue(1, 5))); + + for (int j = 0; j < 5; j++) { + Generate(A, "100 100"); + Generate(B, "100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "CDCD"); + for (int i = 0; i < 5; i++) { + Generate(C, "50 50 50 40"); + Generate(D, "100 100 "); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDCCDC"); + Generate(E, "50 50 50 40"); + Generate(F, "100 100 "); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "EFEEFE"); + } + for (int i = 0; i < 5; i++) { + Generate(C, "50 50 50 50"); + Generate(D, "100 100 "); + Generate(E, "50 50 50 50 50 50"); + Generate(F, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 6), "CDEFCE"); + state.Freeze(1); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 3), "EFE"); + state.Unfreeze(1); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDEFCE"); + } + state.Unfreeze(0); + Generate(C, "50 50 55"); + Generate(D, "50 50 40"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDCDABCD"); + } + } + + Y_UNIT_TEST(SimplestClear) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + + Generate(A, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AAA"); + + Generate(A, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AAA"); + + sched.Clear(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + } + + Y_UNIT_TEST(SimpleClear) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + sched.Clear(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + sched.Attach(A); + A->Activate(); + sched.Attach(B); + B->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AB"); + } + + Y_UNIT_TEST(ComplexClear) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 1, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + sched.Clear(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + sched.Attach(A); + A->Activate(); + sched.Attach(B); + B->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AB"); + } + + Y_UNIT_TEST(SimpleFreezeClear) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + + Generate(A, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "A"); + + state.Freeze(0); + sched.Clear(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + sched.Attach(A); + A->Activate(); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AA"); + } + + Y_UNIT_TEST(EmptyFreezeClear) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + + Generate(A, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AAA"); + + state.Freeze(0); + sched.Clear(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + } + + Y_UNIT_TEST(ComplexFreezeClear) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 1, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + state.Freeze(0); + sched.Clear(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + sched.Attach(A); + sched.Attach(B); + A->Activate(); // double activation should be ignored gracefully + B->Activate(); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AB"); + } + + Y_UNIT_TEST(DeleteQueue) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100 100 100"); + Generate(B, "100 100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "AB"); + + TMyQueue* C; + sched.AddQueue("C", 0, TQueuePtr(C = new TMyQueue(1, 2))); + Generate(C, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "CABC"); + + sched.DeleteQueue("C"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + sched.AddQueue("C", 0, TQueuePtr(C = new TMyQueue(1, 2))); + Generate(C, "100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CABC"); + } + + Y_UNIT_TEST(SimpleActDeact) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + A->Deactivate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "B"); + + A->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "A"); + } + + Y_UNIT_TEST(TotalActDeact) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + A->Deactivate(); + B->Deactivate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + B->Activate(); + A->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AB"); + } + + Y_UNIT_TEST(TotalActDeactReordered) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + B->Deactivate(); + A->Deactivate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + A->Activate(); + B->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AB"); + } + + Y_UNIT_TEST(ComplexActDeact) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + B->Deactivate(); + A->Deactivate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + sched.ActivateConsumers([=] (TMyConsumer* c) { return c == A? 0: NLazy::DoNotActivate; }); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "A"); + + sched.ActivateConsumers([=] (TMyConsumer* c) { return c == B? 0: NLazy::DoNotActivate; }); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "B"); + } + + Y_UNIT_TEST(ComplexDeactDoubleAct) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 0, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", 0, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 6), "ABCDAB"); + + A->Deactivate(); + B->Deactivate(); + C->Deactivate(); + D->Deactivate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + sched.ActivateConsumers([=] (TMyConsumer* c) { return c == A || c == D? 0: NLazy::DoNotActivate; }); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ADD"); + + sched.ActivateConsumers([=] (TMyConsumer* c) { return c == B || c == C? 0: NLazy::DoNotActivate; }); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "BCC"); + } + + + Y_UNIT_TEST(AttachIntoFreezableAfterDeact) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler sched(state); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", 0, TQueuePtr(C = new TMyQueue(1, 2))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + Generate(C, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 6), "ABCABC"); + + C->Deactivate(); + + sched.AddQueue("D", 0, TQueuePtr(D = new TMyQueue(1, 3))); + Generate(D, "100"); + + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "DAB"); + + C->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "C"); + } + + Y_UNIT_TEST(Random) { + using namespace NSingleResource; + + for (int cycle = 0; cycle < 50; cycle++) { + TMyShopState state(1); + TMyScheduler sched(state); + + TVector queues; + for (int i = 0; i < 50; i++) { + TQueuePtr queue(new TMyQueue(1, 0)); + queues.push_back(queue); + sched.AddQueue(Sprintf("Q%03d", i), 0, queue); + } + + for (int i = 0; i < 10000; i++) { + if (RandomNumber(10)) { + size_t i = RandomNumber(queues.size()); + TMyQueue* queue = queues[i].get(); + switch (RandomNumber(3)) { + case 0: + Generate(queue, "100"); + queue->Activate(); + break; + case 2: + queue->Deactivate(); + break; + } + } else { + Schedule(sched, 3); + } + } + } + } + + Y_UNIT_TEST(SimpleHierarchy) { + using namespace NSingleResource; + + TMyShopState state(1); + TMyScheduler schedR(state); + + TMyScheduler schedG(state, 1, 0); + TMyQueue* A; + TMyQueue* B; + schedG.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + schedG.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + + TMyScheduler schedH(state, 1, 0); + TMyQueue* C; + TMyQueue* D; + schedH.AddQueue("C", 0, TQueuePtr(C = new TMyQueue(1, 0))); + schedH.AddQueue("D", 0, TQueuePtr(D = new TMyQueue(1, 1))); + + schedR.AddSubScheduler("G", &schedG); + schedR.AddSubScheduler("H", &schedH); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(schedR), "ACBDACBDACBD"); + } + + Y_UNIT_TEST(SimpleHierarchyFreezeSubTree) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler schedR(state); + + TMyScheduler schedG(state, 1, 0); + TMyQueue* A; + TMyQueue* B; + schedG.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + schedG.AddQueue("B", 0, TQueuePtr(B = new TMyQueue(1, 1))); + + TMyScheduler schedH(state, 1, 0); + TMyQueue* C; + TMyQueue* D; + schedH.AddQueue("C", 1, TQueuePtr(C = new TMyQueue(1, 0))); + schedH.AddQueue("D", 1, TQueuePtr(D = new TMyQueue(1, 1))); + + schedR.AddSubScheduler("G", &schedG); + schedR.AddSubScheduler("H", &schedH); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(schedR, 4), "ACBD"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(schedR), "CDCD"); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(schedR), "ABAB"); + } + + Y_UNIT_TEST(SimpleHierarchyFreezeLeafsOnly) { + using namespace NSingleResource; + + TMyShopState state(2); + TMyScheduler schedR(state); + + TMyScheduler schedG(state, 1, 0); + TMyQueue* A; + TMyQueue* B; + schedG.AddQueue("A", 0, TQueuePtr(A = new TMyQueue(1, 0))); + schedG.AddQueue("B", 1, TQueuePtr(B = new TMyQueue(1, 1))); + + TMyScheduler schedH(state, 1, 0); + TMyQueue* C; + TMyQueue* D; + schedH.AddQueue("C", 0, TQueuePtr(C = new TMyQueue(1, 0))); + schedH.AddQueue("D", 1, TQueuePtr(D = new TMyQueue(1, 1))); + + schedR.AddSubScheduler("G", &schedG); + schedR.AddSubScheduler("H", &schedH); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(schedR, 4), "ACBD"); + state.Freeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(schedR), "BDBD"); + state.Unfreeze(0); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(schedR), "ACAC"); + } +} + +template<> +void Out::TMyRes::TKey>( + IOutputStream& out, + const NTestSuiteShopLazyScheduler::TTest::TMyRes::TKey& key) +{ + out << "<" << key.Key << "|" << key.Priority << ">"; +} + +template<> +void Out::TMyRes::TKey>( + IOutputStream& out, + const NTestSuiteShopLazyScheduler::TTest::TMyRes::TKey& key) +{ + out << "<" << key.Key << "|" << key.Priority << ">"; +} diff --git a/ydb/library/shop/ut/scheduler_ut.cpp b/ydb/library/shop/ut/scheduler_ut.cpp new file mode 100644 index 000000000000..619fde5b31f3 --- /dev/null +++ b/ydb/library/shop/ut/scheduler_ut.cpp @@ -0,0 +1,1403 @@ +#include + +#include +#include +#include +#include + +Y_UNIT_TEST_SUITE(ShopScheduler) { + using namespace NShop; + + template + struct TTest { + // We need Priority in tests to break ties in deterministic fashion + struct TMyRes { + using TCost = typename TRes::TCost; + using TTag = typename TRes::TTag; + + struct TKey { + typename TRes::TKey Key; + int Priority; + + bool operator<(const TKey& rhs) const + { + if (Key < rhs.Key) { + return true; + } else if (Key > rhs.Key) { + return false; + } else { + return Priority < rhs.Priority; + } + } + }; + + inline static TKey OffsetKey(TKey key, typename TRes::TTag offset); + template + inline static void SetKey(TKey& key, ConsumerT* consumer); + }; + + class TMyQueue; + using TMySchedulable = TSchedulable; + using TMyConsumer = TConsumer; + using TMyFreezable = TFreezable; + + class TMyTask : public TMySchedulable { + public: + TMyQueue* Queue = nullptr; + public: + explicit TMyTask(typename TMyRes::TCost cost) + { + this->Cost = cost; + } + }; + + class TMyQueue: public TMyConsumer { + public: + TDeque Tasks; + int Priority; + bool AllowEmpty = false; + public: // Interface for clients + TMyQueue(TWeight w = 1, int priority = 0) + : Priority(priority) + { + this->SetWeight(w); + } + + ~TMyQueue() + { + for (auto i = Tasks.begin(), e = Tasks.end(); i != e; ++i) { + delete *i; + } + } + + void PushTask(TMyTask* task) + { + if (Empty()) { // Scheduler must be notified on first task in queue + this->Activate(); + } + task->Queue = this; + Tasks.push_back(task); + } + + void PushTaskFront(TMyTask* task) + { + if (Empty()) { // Scheduler must be notified on first task in queue + this->Activate(); + } + task->Queue = this; + Tasks.push_front(task); + } + public: // Interface for scheduler + TMySchedulable* PopSchedulable() override + { + if (AllowEmpty && Tasks.empty()) { + return nullptr; + } + UNIT_ASSERT(!Tasks.empty()); + TMyTask* task = Tasks.front(); + Tasks.pop_front(); + return task; + } + + bool Empty() const override + { + return Tasks.empty(); + } + }; + + /////////////////////////////////////////////////////////////////////////////// + + using TQueuePtr = std::shared_ptr; + using TFreezablePtr = std::shared_ptr; + + class TMyScheduler: public TScheduler { + public: + THashMap Freezables; + THashMap Queues; + bool AllowEmpty; + int Priority; + public: + explicit TMyScheduler(bool allowEmpty, TWeight w = 1, int priority = 0) + : AllowEmpty(allowEmpty) + , Priority(priority) + { + this->SetWeight(w); + } + + explicit TMyScheduler(TWeight w = 1, int priority = 0) + : TMyScheduler(false, w, priority) + {} + + ~TMyScheduler() + { + this->UpdateCounters(); + } + + void AddFreezable(const TString& name, const TFreezablePtr& freezable) + { + freezable->SetName(name); + freezable->SetScheduler(this); + Freezables.emplace(name, freezable); + } + + void DeleteFreezable(const TString& name) + { + auto iter = Freezables.find(name); + if (iter != Freezables.end()) { + TMyFreezable* freezable = iter->second.Get(); + freezable->Deactivate(); + Freezables.erase(iter); + } + } + + void AddQueue(const TString& name, TMyFreezable* freezable, const TQueuePtr& queue) + { + queue->SetName(name); + queue->SetScheduler(this); + queue->SetFreezable(freezable); + queue->AllowEmpty = AllowEmpty; + Queues.emplace(name, queue); + } + + void AddSubScheduler(const TString& name, TMyFreezable* freezable, TMyScheduler* scheduler) + { + scheduler->SetName(name); + scheduler->SetScheduler(this); + scheduler->SetFreezable(freezable); + scheduler->AllowEmpty = AllowEmpty; + } + + void DeleteQueue(const TString& name) + { + auto iter = Queues.find(name); + if (iter != Queues.end()) { + TMyConsumer* consumer = iter->second.get(); + consumer->Detach(); + Queues.erase(iter); + } + } + + void DeleteSubScheduler(TMyScheduler* scheduler) + { + scheduler->Detach(); + } + }; + + /////////////////////////////////////////////////////////////////////////////// + + static void Generate(TMyQueue* queue, const TString& tasks) + { + TVector v = SplitString(tasks, " "); + for (size_t i = 0; i < v.size(); i++) { + queue->PushTask(new TMyTask(FromString(v[i]))); + } + } + + static void GenerateFront(TMyQueue* queue, const TString& tasks) + { + TVector v = SplitString(tasks, " "); + for (size_t i = 0; i < v.size(); i++) { + queue->PushTaskFront(new TMyTask(FromString(v[i]))); + } + } + + static TString Schedule(TMyScheduler& sched, size_t count = size_t(-1), bool printcost = false) + { + TStringStream ss; + while (count-- && !sched.Empty()) { + TMyTask* task = static_cast(sched.PopSchedulable()); + if (sched.AllowEmpty && !task) { + break; + } + ss << task->Queue->GetName(); + if (printcost) { + ss << task->Cost; + } + delete task; + } + if (count != size_t(-1)) { + UNIT_ASSERT(sched.Empty()); + } + return ss.Str(); + } + }; + + /////////////////////////////////////////////////////////////////////////////// + + template + template + inline void TTest::TMyRes::SetKey( + typename TTest::TMyRes::TKey& key, + ConsumerT* consumer) + { + TRes::SetKey(key.Key, consumer); + if (auto queue = dynamic_cast::TMyQueue*>(consumer)) { + key.Priority = queue->Priority; + } else if (auto sched = dynamic_cast::TMyScheduler*>(consumer)) { + key.Priority = sched->Priority; + } + } + + template + inline typename TTest::TMyRes::TKey TTest::TMyRes::OffsetKey( + typename TTest::TMyRes::TKey key, + typename TRes::TTag offset) + { + return { TRes::OffsetKey(key.Key, offset), key.Priority }; + } + + namespace NSingleResource { + using TRes = NShop::TSingleResource; + using TMyConsumer = TTest::TMyConsumer; + using TMyFreezable = TTest::TMyFreezable; + using TMyScheduler = TTest::TMyScheduler; + using TMyQueue = TTest::TMyQueue; + using TQueuePtr = TTest::TQueuePtr; + using TFreezablePtr = TTest::TFreezablePtr; + + template + void Generate(TArgs&&... args) + { + TTest::Generate(args...); + } + + template + void GenerateFront(TArgs&&... args) + { + TTest::GenerateFront(args...); + } + + template + auto Schedule(TArgs&&... args) + { + return TTest::Schedule(args...); + } + } + + namespace NPairDrf { + using TRes = NShop::TPairDrf; + using TMyConsumer = TTest::TMyConsumer; + using TMyFreezable = TTest::TMyFreezable; + using TMyScheduler = TTest::TMyScheduler; + using TMyQueue = TTest::TMyQueue; + using TQueuePtr = TTest::TQueuePtr; + using TFreezablePtr = TTest::TFreezablePtr; + + template + void Generate(TArgs&&... args) + { + TTest::Generate(args...); + } + + template + void GenerateFront(TArgs&&... args) + { + TTest::GenerateFront(args...); + } + + template + auto Schedule(TArgs&&... args) + { + return TTest::Schedule(args...); + } + } + + Y_UNIT_TEST(StartLwtrace) { + NLWTrace::StartLwtraceFromEnv(); + } + + Y_UNIT_TEST(Simple) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABABAB"); + + Generate(A, "50 50 50 50 50"); + Generate(B, "50 50 50 50 50"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABABABABAB"); + + Generate(A, "20 20 20 20 20 20 20"); + Generate(B, "20 20 20 20 20 20 20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABABABABABABAB"); + + Generate(A, "20 20 20 20 20 20 20"); + Generate(B, "50 50 50" ); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABAABAAABA"); + + Generate(A, " 100 100"); + Generate(B, "20 20 20 20 20 20 20 "); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABBBBBABB"); + + TMyQueue* C; + sched.AddQueue("C", G, TQueuePtr(C = new TMyQueue(2, 2))); + + Generate(A, "20 20 20 20 20 20"); + Generate(B, "20 20 20 20 20 20"); + Generate(C, "20 20 20 20 20 20 20 20 20 20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCCABCCABCCABCCABCCAB"); + + sched.DeleteQueue("A"); + // sched.DeleteQueue("B"); // scheduler must delete queue be itself + } + +// Y_UNIT_TEST(CompileDrf) { +// using namespace NPairDrf; + +// TMyScheduler sched; +// TMyFreezable* G; +// sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); +// TMyQueue* A; +// TMyQueue* B; +// sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); +// sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); +// } + + Y_UNIT_TEST(DoubleActivation) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "AB"); + + A->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "AB"); + + A->Activate(); + B->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AB"); + } + + Y_UNIT_TEST(SimpleLag) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + TMyQueue* E; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", G, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", G, TQueuePtr(D = new TMyQueue(1, 3))); + sched.AddQueue("E", G, TQueuePtr(E = new TMyQueue(1, 4))); + + Generate(A, "500 500 500"); // 25 + Generate(B, "500 500 500"); // 25 + Generate(C, "500 500 500"); // 25 + Generate(D, "500 500 500"); // 25 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 8), "ABCDABCD"); + Generate(E, "500"); // 100 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "EABCD"); + } + + Y_UNIT_TEST(Complex) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + TMyFreezable* H; + sched.AddFreezable("H", TFreezablePtr(H = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + TMyQueue* E; + TMyQueue* X; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", G, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", G, TQueuePtr(D = new TMyQueue(1, 3))); + sched.AddQueue("E", G, TQueuePtr(E = new TMyQueue(1, 4))); + sched.AddQueue("X", H, TQueuePtr(X = new TMyQueue(1, 5))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABABAB"); + + Generate(A, "100 100 100"); + Generate(X, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AXAXAX"); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + Generate(E, "100 100 100"); + Generate(X, "100 100 100 100 100 100 100 100 100 100 100 100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDEXABCDEXABCDEXXXXXXXXXXXXX"); + } + + Y_UNIT_TEST(ComplexWithWeights) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + TMyFreezable* H; + sched.AddFreezable("H", TFreezablePtr(H = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", H, TQueuePtr(C = new TMyQueue(3, 2))); + sched.AddQueue("D", H, TQueuePtr(D = new TMyQueue(3, 3))); + + Generate(A, "100 100 100"); // 100 + Generate(B, "100 100 100"); // 100 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABABAB"); + + Generate(C, "100 100 100"); // 100 + Generate(D, "100 100 100"); // 100 + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDCDCD"); + + Generate(A, "100 100 100 100 100 100 100 100"); + Generate(C, "100 100 100 100 100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ACCCACCCACCAAAAA"); + + Generate(B, "100 100 100 100 100 100 100 100"); + Generate(D, "100 100 100 100 100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "BDDDBDDDBDDBBBBB"); + + Generate(A, "200 200 200 200 200 200 200 200 200 200 200"); + Generate(B, "200 200 200 200 200 200 200 200 200 200 200"); + Generate(C, "200 200 200 200 200 200 200 200 200 200 200"); + Generate(D, "200 200 200 200 200 200 200 200 200 200 200"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDCDCDABCDCDCDABCDCDCDABCDCDABABABABABABAB"); + + Generate(A, "100 100 100 100 100 100 100 100 100 100 100"); + Generate(B, "100 100 100 100 100 100 100 100 100 100 100"); + Generate(C, "100 100 100 100 100 100 100 100 100 100 100"); + Generate(D, "100 100 100 100 100 100 100 100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDCDCDABCDCDCDABCDCDCDABCDCDABABABABABABAB"); + + Generate(A, "50 50 50 50 50 50 50 50 50 50 50"); + Generate(B, "50 50 50 50 50 50 50 50 50 50 50"); + Generate(C, "50 50 50 50 50 50 50 50 50 50 50"); + Generate(D, "50 50 50 50 50 50 50 50 50 50 50"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDCDCDABCDCDCDABCDCDCDABCDCDABABABABABABAB"); + } + + Y_UNIT_TEST(OneQueueFrontPush) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue())); + + Generate(A, "10 20 30"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1, true), "A10"); + GenerateFront(A, "40"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(-1), true), "A40A20A30"); + } + + Y_UNIT_TEST(SimpleFrontPush) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "10 30 40"); + Generate(B, "10 20 30"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2, true), "A10B10"); + GenerateFront(A, "20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(-1), true), "A20B20A30B30A40"); + } + + Y_UNIT_TEST(SimpleFrontPushAll) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "10 30 40"); + Generate(B, " 5 30 40"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2, true), "A10B5"); + GenerateFront(A, "20"); + GenerateFront(B, "20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4, true), "B20A20B30A30"); + GenerateFront(A, "10 10"); + GenerateFront(B, "10 8"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(-1), true), "B8A10B10A10B40A40"); + } + + Y_UNIT_TEST(ComplexFrontPush) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + TMyFreezable* H; + sched.AddFreezable("H", TFreezablePtr(H = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", H, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", H, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "10 20"); + Generate(B, "10 30"); + Generate(C, "10 20"); + Generate(D, "10 20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4, true), "A10B10C10D10"); + GenerateFront(B, "20"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(-1), true), "A20B20C20D20B30"); + } + + Y_UNIT_TEST(ComplexFrontPushAll) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + TMyFreezable* H; + sched.AddFreezable("H", TFreezablePtr(H = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", H, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", H, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "10 36"); + Generate(B, "10 34"); + Generate(C, "10 32"); + Generate(D, "10 30"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4, true), "A10B10C10D10"); + GenerateFront(A, "20"); + GenerateFront(B, "21"); + GenerateFront(C, "22"); + GenerateFront(D, "23"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(-1), true), "A20B21C22D23A36B34C32D30"); + } + + Y_UNIT_TEST(ComplexMultiplePush) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + TMyFreezable* H; + sched.AddFreezable("H", TFreezablePtr(H = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", H, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", H, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "5 5 5 5 5"); + Generate(B, "10 10"); + Generate(C, "10 10"); + Generate(D, "10 10"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDAABCDAA"); + } + + Y_UNIT_TEST(ComplexFrontMultiplePush) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + TMyFreezable* H; + sched.AddFreezable("H", TFreezablePtr(H = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", H, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", H, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "5"); + Generate(B, "10 10"); + Generate(C, "10 10"); + Generate(D, "10 10"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1, true), "A5"); + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1, true), "B10"); + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4, true), "C10D10A5A5"); + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1, true), "B10"); + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(-1), true), "C10D10A5A5"); + } + + Y_UNIT_TEST(ComplexCheckEmpty) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + TMyFreezable* H; + sched.AddFreezable("H", TFreezablePtr(H = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", H, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", H, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(1), true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(1), true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(1), true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(1), true), "A5"); + + GenerateFront(A, "5"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, size_t(-1), true), "A5"); + } + + Y_UNIT_TEST(SimpleFreeze) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100 100"); + Generate(B, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + G->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + G->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABAB"); + + Generate(A, "100 100 100 100"); + Generate(B, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + G->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + G->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "A"); + G->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + G->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "B"); + G->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + G->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "A"); + G->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + G->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "B"); + } + + Y_UNIT_TEST(ComplexFreeze) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + TMyFreezable* H; + sched.AddFreezable("H", TFreezablePtr(H = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", H, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", H, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "100 100 100 100"); + Generate(B, "100 100 100 100"); + Generate(C, "100 100 100 100"); + Generate(D, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + G->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "CDCD"); + G->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDABAB"); + + Generate(A, "100 100 100 100"); + Generate(B, "100 100 100 100"); + Generate(C, "100 100 100 100"); + Generate(D, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + G->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "CD"); + H->Freeze(); + H->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "CD"); + G->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDABAB"); + + Generate(A, "100 100 100 100"); + Generate(B, "100 100 100 100"); + Generate(C, "100 100 100 100"); + Generate(D, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + G->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "CD"); + H->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + H->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "CD"); + G->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDABAB"); + + Generate(A, "100 100 100 100"); + Generate(B, "100 100 100 100"); + Generate(C, "100 100 100 100"); + Generate(D, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + G->Freeze(); + H->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + G->Unfreeze(); + H->Unfreeze(); + G->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "CDCD"); + G->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDABAB"); + + Generate(A, "100 100 100 100"); + Generate(B, "100 100 100 100"); + Generate(C, "100 100 100 100"); + Generate(D, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + G->Freeze(); + H->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + H->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "C"); + H->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + H->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "D"); + H->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + H->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "C"); + H->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + H->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "D"); + G->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ABCDABAB"); + } + + Y_UNIT_TEST(ComplexLocalBusyPeriods) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + TMyFreezable* H; + sched.AddFreezable("H", TFreezablePtr(H = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", H, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", H, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "100 100"); + Generate(B, "100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + G->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "CDCD"); + for (int i = 0; i < 10; i++) { + Generate(C, "50 50 50 40"); + Generate(D, "100 100 "); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDCCDC"); + } + G->Unfreeze(); + Generate(C, "50 50 50"); + Generate(D, "50 50 50"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDCDABCD"); + } + + Y_UNIT_TEST(ComplexGlobalBusyPeriods) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + TMyFreezable* H; + sched.AddFreezable("H", TFreezablePtr(H = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", H, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", H, TQueuePtr(D = new TMyQueue(1, 3))); + + for (int j = 0; j < 5; j++) { + Generate(A, "100 100"); + Generate(B, "100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + G->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "CDCD"); + for (int i = 0; i < 5; i++) { + Generate(C, "50 50 50 40"); + Generate(D, "100 100 "); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDCCDC"); + } + G->Unfreeze(); + Generate(C, "50 50 25"); + Generate(D, "50 50 50"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDCDABCD"); + } + } + + Y_UNIT_TEST(VeryComplexFreeze) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + TMyFreezable* H; + sched.AddFreezable("H", TFreezablePtr(H = new TMyFreezable())); + TMyFreezable* K; + sched.AddFreezable("K", TFreezablePtr(K = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + TMyQueue* E; + TMyQueue* F; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", H, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", H, TQueuePtr(D = new TMyQueue(1, 3))); + sched.AddQueue("E", K, TQueuePtr(E = new TMyQueue(1, 4))); + sched.AddQueue("F", K, TQueuePtr(F = new TMyQueue(1, 5))); + + for (int j = 0; j < 5; j++) { + Generate(A, "100 100"); + Generate(B, "100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABCD"); + G->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "CDCD"); + for (int i = 0; i < 5; i++) { + Generate(C, "50 50 50 40"); + Generate(D, "100 100 "); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDCCDC"); + Generate(E, "50 50 50 40"); + Generate(F, "100 100 "); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "EFEEFE"); + } + for (int i = 0; i < 5; i++) { + Generate(C, "50 50 50 50"); + Generate(D, "100 100 "); + Generate(E, "50 50 50 50 50 50"); + Generate(F, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 6), "CDEFCE"); + H->Freeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 3), "EFE"); + H->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDEFCE"); + } + G->Unfreeze(); + Generate(C, "50 50 55"); + Generate(D, "50 50 40"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CDCDABCD"); + } + } + + Y_UNIT_TEST(SimplestClear) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + + Generate(A, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AAA"); + + Generate(A, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AAA"); + + sched.Clear(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + } + + Y_UNIT_TEST(SimpleClear) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + sched.Clear(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + A->Activate(); + B->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AB"); + } + + Y_UNIT_TEST(ComplexClear) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + TMyFreezable* H; + sched.AddFreezable("H", TFreezablePtr(H = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", H, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + sched.Clear(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + A->Activate(); + B->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AB"); + } + + Y_UNIT_TEST(SimpleFreezeClear) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + + Generate(A, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 1), "A"); + + G->Freeze(); + sched.Clear(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + G->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AA"); + } + + Y_UNIT_TEST(EmptyFreezeClear) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + + Generate(A, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AAA"); + + G->Freeze(); + sched.Clear(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + G->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + } + + Y_UNIT_TEST(ComplexFreezeClear) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + TMyFreezable* H; + sched.AddFreezable("H", TFreezablePtr(H = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", H, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + G->Freeze(); + sched.Clear(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + A->Activate(); // double activation should be ignored gracefully + B->Activate(); + G->Unfreeze(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "BA"); + } + + Y_UNIT_TEST(DeleteQueue) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100 100 100"); + Generate(B, "100 100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 2), "AB"); + + TMyQueue* C; + sched.AddQueue("C", G, TQueuePtr(C = new TMyQueue(1, 2))); + Generate(C, "100 100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "CABC"); + + sched.DeleteQueue("C"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + sched.AddQueue("C", G, TQueuePtr(C = new TMyQueue(1, 2))); + Generate(C, "100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "CABC"); + } + + Y_UNIT_TEST(SimpleActDeact) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + A->Deactivate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "B"); + + A->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "A"); + } + + Y_UNIT_TEST(TotalActDeact) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + A->Deactivate(); + B->Deactivate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + B->Activate(); + A->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AB"); + } + + Y_UNIT_TEST(TotalActDeactReordered) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + B->Deactivate(); + A->Deactivate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + A->Activate(); + B->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "AB"); + } + + Y_UNIT_TEST(ComplexActDeact) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 4), "ABAB"); + + B->Deactivate(); + A->Deactivate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + G->ActivateConsumers([=] (TMyConsumer* c) { return c == A; }); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "A"); + + G->ActivateConsumers([=] (TMyConsumer* c) { return c == B; }); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "B"); + } + + Y_UNIT_TEST(ComplexDeactDoubleAct) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", G, TQueuePtr(C = new TMyQueue(1, 2))); + sched.AddQueue("D", G, TQueuePtr(D = new TMyQueue(1, 3))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 6), "ABCDAB"); + + A->Deactivate(); + B->Deactivate(); + C->Deactivate(); + D->Deactivate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), ""); + + G->ActivateConsumers([=] (TMyConsumer* c) { return c == A || c == D; }); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "ADD"); + + G->ActivateConsumers([=] (TMyConsumer* c) { return c == B || c == C; }); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "BCC"); + } + + + Y_UNIT_TEST(AttachIntoFreezableAfterDeact) { + using namespace NSingleResource; + + TMyScheduler sched; + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TMyQueue* A; + TMyQueue* B; + TMyQueue* C; + TMyQueue* D; + sched.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + sched.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + sched.AddQueue("C", G, TQueuePtr(C = new TMyQueue(1, 2))); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + Generate(C, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched, 6), "ABCABC"); + + C->Deactivate(); + + sched.AddQueue("D", G, TQueuePtr(D = new TMyQueue(1, 3))); + Generate(D, "100"); + + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "DAB"); + + C->Activate(); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(sched), "C"); + } + + Y_UNIT_TEST(Random) { + using namespace NSingleResource; + + for (int cycle = 0; cycle < 50; cycle++) { + TMyScheduler sched(true); + TMyFreezable* G; + sched.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + + TVector queues; + for (int i = 0; i < 50; i++) { + TQueuePtr queue(new TMyQueue(1, 0)); + queues.push_back(queue); + sched.AddQueue(Sprintf("Q%03d", i), G, queue); + } + + for (int i = 0; i < 10000; i++) { + if (RandomNumber(10)) { + size_t i = RandomNumber(queues.size()); + TMyQueue* queue = queues[i].get(); + switch (RandomNumber(3)) { + case 0: + Generate(queue, "100"); + queue->Activate(); + break; + case 2: + queue->Deactivate(); + break; + } + } else { + Schedule(sched, 3); + } + } + } + } + + Y_UNIT_TEST(SimpleHierarchy) { + using namespace NSingleResource; + + TMyScheduler schedR; // must be destructed last + + TMyScheduler schedG(1, 0); + TMyFreezable* G; + schedG.AddFreezable("G", TFreezablePtr(G = new TMyFreezable())); + TMyQueue* A; + TMyQueue* B; + schedG.AddQueue("A", G, TQueuePtr(A = new TMyQueue(1, 0))); + schedG.AddQueue("B", G, TQueuePtr(B = new TMyQueue(1, 1))); + + TMyScheduler schedH(1, 0); + TMyFreezable* H; + schedH.AddFreezable("H", TFreezablePtr(H = new TMyFreezable())); + TMyQueue* C; + TMyQueue* D; + schedH.AddQueue("C", H, TQueuePtr(C = new TMyQueue(1, 0))); + schedH.AddQueue("D", H, TQueuePtr(D = new TMyQueue(1, 1))); + + TMyFreezable* R; + schedR.AddFreezable("R", TFreezablePtr(R = new TMyFreezable())); + schedR.AddSubScheduler("G", R, &schedG); + schedR.AddSubScheduler("H", R, &schedH); + + Generate(A, "100 100 100"); + Generate(B, "100 100 100"); + Generate(C, "100 100 100"); + Generate(D, "100 100 100"); + UNIT_ASSERT_STRINGS_EQUAL(Schedule(schedR), "ACBDACBDACBD"); + } +} + +template<> +void Out::TMyRes::TKey>( + IOutputStream& out, + const NTestSuiteShopScheduler::TTest::TMyRes::TKey& key) +{ + out << "<" << key.Key << "|" << key.Priority << ">"; +} + +template<> +void Out::TMyRes::TKey>( + IOutputStream& out, + const NTestSuiteShopScheduler::TTest::TMyRes::TKey& key) +{ + out << "<" << key.Key << "|" << key.Priority << ">"; +} diff --git a/ydb/library/shop/ut/tr.lwt b/ydb/library/shop/ut/tr.lwt new file mode 100644 index 000000000000..3c9c55a310a8 --- /dev/null +++ b/ydb/library/shop/ut/tr.lwt @@ -0,0 +1,4 @@ +Blocks { + ProbeDesc { Group: "SHOP_PROVIDER" } + Action { PrintToStderrAction {} } +} diff --git a/ydb/library/shop/ut/ya.make b/ydb/library/shop/ut/ya.make new file mode 100644 index 000000000000..81ffb3398fd2 --- /dev/null +++ b/ydb/library/shop/ut/ya.make @@ -0,0 +1,15 @@ +UNITTEST() + +PEERDIR( + library/cpp/threading/future + ydb/library/shop +) + +SRCS( + estimator_ut.cpp + flowctl_ut.cpp + scheduler_ut.cpp + lazy_scheduler_ut.cpp +) + +END() diff --git a/ydb/library/shop/valve.h b/ydb/library/shop/valve.h new file mode 100644 index 000000000000..40eec6b30501 --- /dev/null +++ b/ydb/library/shop/valve.h @@ -0,0 +1,51 @@ +#pragma once + +#include "resource.h" +#include + +namespace NShop { + +class TValve { +public: + using TCost = i64; + +private: + TSpinLock Lock; + + TCost Consumed = 0; + TCost Supply = 0; + TCost Demand = 0; + +public: + bool CanConsume() const + { + auto guard = Guard(Lock); + return Consumed <= Supply; + } + + bool CanSupply() const + { + auto guard = Guard(Lock); + return Supply < Demand; + } + + void AddConsumed(TCost cost) + { + auto guard = Guard(Lock); + Consumed += cost; + } + + void AddSupply(TCost cost) + { + auto guard = Guard(Lock); + Supply += cost; + } + + void AddDemand(TCost cost) + { + auto guard = Guard(Lock); + Demand += cost; + } +}; + +} diff --git a/ydb/library/shop/ya.make b/ydb/library/shop/ya.make new file mode 100644 index 000000000000..81b5922b16a4 --- /dev/null +++ b/ydb/library/shop/ya.make @@ -0,0 +1,23 @@ +LIBRARY() + +SRCS( + probes.cpp + shop.cpp + flowctl.cpp +) + +PEERDIR( + library/cpp/containers/stack_vector + library/cpp/lwtrace + ydb/library/shop/protos + library/cpp/deprecated/atomic +) + +END() + +RECURSE( + protos + sim_flowctl + sim_shop + ut +) diff --git a/ydb/library/ya.make b/ydb/library/ya.make index 4e35a1d1fcdd..72d27498af0f 100644 --- a/ydb/library/ya.make +++ b/ydb/library/ya.make @@ -2,6 +2,7 @@ RECURSE( accessor aclib actors + analytics arrow_clickhouse arrow_kernels arrow_parquet @@ -9,6 +10,7 @@ RECURSE( benchmarks breakpad chunks_limiter + drr folder_service formats fyamlcpp @@ -23,11 +25,13 @@ RECURSE( ncloud pdisk_io persqueue + planner pretty_types_print protobuf_printer query_actor schlab security + shop signal_backtrace table_creator testlib From d42149aab9a13a57ed779d9ed2aed8d1e34ec7ea Mon Sep 17 00:00:00 2001 From: zverevgeny Date: Wed, 9 Apr 2025 09:44:25 +0300 Subject: [PATCH 077/454] test overload with WritePortionsOnInsert (#16963) --- .../ut_rw/ut_columnshard_read_write.cpp | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/ydb/core/tx/columnshard/ut_rw/ut_columnshard_read_write.cpp b/ydb/core/tx/columnshard/ut_rw/ut_columnshard_read_write.cpp index 394868ac5716..2e5078be89ae 100644 --- a/ydb/core/tx/columnshard/ut_rw/ut_columnshard_read_write.cpp +++ b/ydb/core/tx/columnshard/ut_rw/ut_columnshard_read_write.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -434,11 +435,12 @@ void TestWrite(const TestTableDescription& table) { UNIT_ASSERT(ok); } -void TestWriteOverload(const TestTableDescription& table) { +void TestWriteOverload(const TestTableDescription& table, bool WritePortionsOnInsert) { TTestBasicRuntime runtime; TTester::Setup(runtime); + runtime.GetAppData().FeatureFlags.SetEnableWritePortionsOnInsert(WritePortionsOnInsert); auto csDefaultControllerGuard = NKikimr::NYDBTest::TControllers::RegisterCSControllerGuard(); - + csDefaultControllerGuard->SetOverrideBlobSplitSettings(std::nullopt); TActorId sender = runtime.AllocateEdgeActor(); CreateTestBootstrapper(runtime, CreateTestTabletInfo(TTestTxConfig::TxTablet0, TTabletTypes::ColumnShard), &CreateColumnShard); @@ -462,26 +464,31 @@ void TestWriteOverload(const TestTableDescription& table) { TDeque> capturedWrites; auto captureEvents = [&](TTestActorRuntimeBase&, TAutoPtr& ev) { - if (auto* msg = TryGetPrivateEvent(ev)) { - Cerr << "CATCH TEvWrite, status " << msg->GetPutResult().GetPutStatus() << Endl; - if (toCatch && msg->GetPutResult().GetPutStatus() != NKikimrProto::UNKNOWN) { - capturedWrites.push_back(ev.Release()); + if (toCatch) { + TAutoPtr eventToCapture; + if (WritePortionsOnInsert) { + if (auto* msg = TryGetPrivateEvent(ev)) { + Cerr << "CATCH TEvWritePortionResult, status " << msg->GetWriteStatus() << Endl; + if (msg->GetWriteStatus() != NKikimrProto::EReplyStatus::UNKNOWN) { + eventToCapture = ev.Release(); + } + } + } else { + if (auto* msg = TryGetPrivateEvent(ev)) { + Cerr << "CATCH TEvWrite, status " << msg->GetPutResult().GetPutStatus() << Endl; + if (msg->GetPutResult().GetPutStatus() != NKikimrProto::UNKNOWN) { + eventToCapture = ev.Release(); + } + } + } + if (eventToCapture) { --toCatch; + capturedWrites.push_back(std::move(eventToCapture)); return true; - } else { - return false; } } return false; }; - - auto resendOneCaptured = [&]() { - UNIT_ASSERT(capturedWrites.size()); - Cerr << "RESEND TEvWrite" << Endl; - runtime.Send(capturedWrites.front().Release()); - capturedWrites.pop_front(); - }; - runtime.SetEventFilter(captureEvents); const ui32 toSend = toCatch + 1; @@ -492,7 +499,8 @@ void TestWriteOverload(const TestTableDescription& table) { UNIT_ASSERT_VALUES_EQUAL(WaitWriteResult(runtime, TTestTxConfig::TxTablet0), (ui32)NKikimrDataEvents::TEvWriteResult::STATUS_OVERLOADED); while (capturedWrites.size()) { - resendOneCaptured(); + runtime.Send(capturedWrites.front().Release()); + capturedWrites.pop_front(); UNIT_ASSERT_VALUES_EQUAL(WaitWriteResult(runtime, TTestTxConfig::TxTablet0), (ui32)NKikimrDataEvents::TEvWriteResult::STATUS_COMPLETED); } @@ -1665,15 +1673,10 @@ Y_UNIT_TEST_SUITE(TColumnShardTestReadWrite) { TestWrite(table); } - Y_UNIT_TEST(WriteOverload) { + Y_UNIT_TEST_QUATRO(WriteOverload, InStore, WithWritePortionsOnInsert) { TestTableDescription table; - TestWriteOverload(table); - } - - Y_UNIT_TEST(WriteStandaloneOverload) { - TestTableDescription table; - table.InStore = false; - TestWriteOverload(table); + table.InStore = InStore; + TestWriteOverload(table, WithWritePortionsOnInsert); } Y_UNIT_TEST(WriteReadDuplicate) { From e2854c158bd1fb5f22380680ef99d721a41b82a7 Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Wed, 9 Apr 2025 09:51:14 +0300 Subject: [PATCH 078/454] Intermediate changes commit_hash:82cfb3bb916af616b6a16161253ed74b1be02c4e --- contrib/python/pytz/py3/.dist-info/METADATA | 2 +- contrib/python/pytz/py3/pytz/__init__.py | 6 ++++-- .../python/pytz/py3/pytz/tests/test_tzinfo.py | 4 ++-- .../pytz/py3/pytz/zoneinfo/America/Coyhaique | Bin 0 -> 2126 bytes .../python/pytz/py3/pytz/zoneinfo/Asia/Tehran | Bin 1248 -> 1248 bytes contrib/python/pytz/py3/pytz/zoneinfo/Iran | Bin 1248 -> 1248 bytes .../python/pytz/py3/pytz/zoneinfo/tzdata.zi | 16 +++++++++++++++- .../python/pytz/py3/pytz/zoneinfo/zone.tab | 3 ++- .../pytz/py3/pytz/zoneinfo/zone1970.tab | 3 ++- .../python/pytz/py3/pytz/zoneinfo/zonenow.tab | 2 +- contrib/python/pytz/py3/ya.make | 3 ++- .../misc/unittests/consistent_hashing_ut.cpp | 5 +++-- 12 files changed, 32 insertions(+), 12 deletions(-) create mode 100644 contrib/python/pytz/py3/pytz/zoneinfo/America/Coyhaique diff --git a/contrib/python/pytz/py3/.dist-info/METADATA b/contrib/python/pytz/py3/.dist-info/METADATA index 879a28cf7a1c..6ecc5a3e468a 100644 --- a/contrib/python/pytz/py3/.dist-info/METADATA +++ b/contrib/python/pytz/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pytz -Version: 2025.1 +Version: 2025.2 Summary: World timezone definitions, modern and historical Home-page: http://pythonhosted.org/pytz Download-URL: https://pypi.org/project/pytz/ diff --git a/contrib/python/pytz/py3/pytz/__init__.py b/contrib/python/pytz/py3/pytz/__init__.py index 1f0194634ca1..c7ee5efd2f08 100644 --- a/contrib/python/pytz/py3/pytz/__init__.py +++ b/contrib/python/pytz/py3/pytz/__init__.py @@ -22,8 +22,8 @@ # The IANA (nee Olson) database is updated several times a year. -OLSON_VERSION = '2025a' -VERSION = '2025.1' # pip compatible version number. +OLSON_VERSION = '2025b' +VERSION = '2025.2' # pip compatible version number. __version__ = VERSION OLSEN_VERSION = OLSON_VERSION # Old releases had this misspelling @@ -617,6 +617,7 @@ def _test(): 'America/Coral_Harbour', 'America/Cordoba', 'America/Costa_Rica', + 'America/Coyhaique', 'America/Creston', 'America/Cuiaba', 'America/Curacao', @@ -1210,6 +1211,7 @@ def _test(): 'America/Chihuahua', 'America/Ciudad_Juarez', 'America/Costa_Rica', + 'America/Coyhaique', 'America/Creston', 'America/Cuiaba', 'America/Curacao', diff --git a/contrib/python/pytz/py3/pytz/tests/test_tzinfo.py b/contrib/python/pytz/py3/pytz/tests/test_tzinfo.py index 3195a1fde36a..6d1cadaf2dbe 100644 --- a/contrib/python/pytz/py3/pytz/tests/test_tzinfo.py +++ b/contrib/python/pytz/py3/pytz/tests/test_tzinfo.py @@ -27,8 +27,8 @@ # I test for expected version to ensure the correct version of pytz is # actually being tested. -EXPECTED_VERSION = '2025.1' -EXPECTED_OLSON_VERSION = '2025a' +EXPECTED_VERSION = '2025.2' +EXPECTED_OLSON_VERSION = '2025b' fmt = '%Y-%m-%d %H:%M:%S %Z%z' diff --git a/contrib/python/pytz/py3/pytz/zoneinfo/America/Coyhaique b/contrib/python/pytz/py3/pytz/zoneinfo/America/Coyhaique new file mode 100644 index 0000000000000000000000000000000000000000..e0c6832bb36bde2468038a1e8fa25f89835a4e5f GIT binary patch literal 2126 zcmdtiOKenC9LMoH58B#xq@~ECf)o_2j_9FNq{TiCh1ynLqaEbov?7p}5@RdDvapFr z1gZ%;#KmJwpK*!k=2c1WaG;Tl9v%OsRE^-pb z*0h;7XB9`^Dt%SI9cWJU<&T)Y^ZTRym*ZyOWI=Rz+9P`S;ja^)Pd=wpkyR$u-mNbu z%k-7*-^CsN#5h~ei0`qe@#{JXtSU0Wg0PIMSgF&Tkfdh~>hv$iB;!h+zUFvRGDm;b zS%W z1~Vmjzf8SQY4UqY`QcY{^QnWX@X~wcmUoBb){)mt_>}{4TVJP{yYor8ecu*y$A*ofcI?sf zs;Z@EeT$BikEmk3RL{>^qV5d!>jh~kDRIW@l8-Y~={I4s@bI_lt`9?|?3rOzerU{8 zY&oJTJCjD&e7_z!&sieFFYK&>t9=_MblKt~=P~IIcVNjuUj<0dX>1_oQ*MdHd`;mGI?U z{U()ga+WQRIra9=RrBpFwl`w`+V=Q-e;fN3!*K0s*)zlbhU+pAWF*K?kg*_xK}LfN z2N@4CAY??ykdQHX+Cd?sLWYHm%hL`F85uG(PdhebaOjPW4-AiE#|I1$86h%6WQ@ol zkx?SU^t9td28xUn87eYXWU$C+k>MiaMFxzF7#T7$W@OOFsF7iN+HoTT_p~ENhK`IK z89Xw2WcbMVkpLhOKth1T00{yT1tbifHV#N2kVqh*Kw^Oe1BnI_4kR8(K#+(aAwgn- z1OsV%%*@RX^GXDa79D+9h literal 0 HcmV?d00001 diff --git a/contrib/python/pytz/py3/pytz/zoneinfo/Asia/Tehran b/contrib/python/pytz/py3/pytz/zoneinfo/Asia/Tehran index cc2a2c219b0c893cfa8187e962028eb19ea3425d..78f28cc402027bd337cf67b937bf8c31a75ee8b3 100644 GIT binary patch delta 23 dcmaFB`G9kREAz^~2R3?qVFb~e?U@!b0RV|73jY8A delta 23 ccmaFB`G9kREAv|`hm9Uz7(w)Ad!~g<0CdF(0RR91 diff --git a/contrib/python/pytz/py3/pytz/zoneinfo/Iran b/contrib/python/pytz/py3/pytz/zoneinfo/Iran index cc2a2c219b0c893cfa8187e962028eb19ea3425d..78f28cc402027bd337cf67b937bf8c31a75ee8b3 100644 GIT binary patch delta 23 dcmaFB`G9kREAz^~2R3?qVFb~e?U@!b0RV|73jY8A delta 23 ccmaFB`G9kREAv|`hm9Uz7(w)Ad!~g<0CdF(0RR91 diff --git a/contrib/python/pytz/py3/pytz/zoneinfo/tzdata.zi b/contrib/python/pytz/py3/pytz/zoneinfo/tzdata.zi index a2fcd5449632..0bcae52e5efa 100644 --- a/contrib/python/pytz/py3/pytz/zoneinfo/tzdata.zi +++ b/contrib/python/pytz/py3/pytz/zoneinfo/tzdata.zi @@ -2432,6 +2432,20 @@ Z America/Ciudad_Juarez -7:5:56 - LMT 1922 Ja 1 7u Z America/Costa_Rica -5:36:13 - LMT 1890 -5:36:13 - SJMT 1921 Ja 15 -6 CR C%sT +Z America/Coyhaique -4:48:16 - LMT 1890 +-4:42:45 - SMT 1910 Ja 10 +-5 - %z 1916 Jul +-4:42:45 - SMT 1918 S 10 +-4 - %z 1919 Jul +-4:42:45 - SMT 1927 S +-5 x %z 1932 S +-4 - %z 1942 Jun +-5 - %z 1942 Au +-4 - %z 1946 Au 28 24 +-5 1 %z 1947 Mar 31 24 +-5 - %z 1947 May 21 23 +-4 x %z 2025 Mar 20 +-3 - %z Z America/Cuiaba -3:44:20 - LMT 1914 -4 B %z 2003 S 24 -4 - %z 2004 O @@ -3420,7 +3434,7 @@ Z Asia/Tbilisi 2:59:11 - LMT 1880 Z Asia/Tehran 3:25:44 - LMT 1916 3:25:44 - TMT 1935 Jun 13 3:30 i %z 1977 O 20 24 -4 i %z 1979 +4 i %z 1978 N 10 24 3:30 i %z Z Asia/Thimphu 5:58:36 - LMT 1947 Au 15 5:30 - %z 1987 O diff --git a/contrib/python/pytz/py3/pytz/zoneinfo/zone.tab b/contrib/python/pytz/py3/pytz/zoneinfo/zone.tab index d2be66359f3b..2626b0550341 100644 --- a/contrib/python/pytz/py3/pytz/zoneinfo/zone.tab +++ b/contrib/python/pytz/py3/pytz/zoneinfo/zone.tab @@ -139,7 +139,8 @@ CH +4723+00832 Europe/Zurich CI +0519-00402 Africa/Abidjan CK -2114-15946 Pacific/Rarotonga CL -3327-07040 America/Santiago most of Chile -CL -5309-07055 America/Punta_Arenas Region of Magallanes +CL -4534-07204 America/Coyhaique Aysen Region +CL -5309-07055 America/Punta_Arenas Magallanes Region CL -2709-10926 Pacific/Easter Easter Island CM +0403+00942 Africa/Douala CN +3114+12128 Asia/Shanghai Beijing Time diff --git a/contrib/python/pytz/py3/pytz/zoneinfo/zone1970.tab b/contrib/python/pytz/py3/pytz/zoneinfo/zone1970.tab index 5ded0565ebf3..36535bdf5cfb 100644 --- a/contrib/python/pytz/py3/pytz/zoneinfo/zone1970.tab +++ b/contrib/python/pytz/py3/pytz/zoneinfo/zone1970.tab @@ -124,7 +124,8 @@ CH,DE,LI +4723+00832 Europe/Zurich Büsingen CI,BF,GH,GM,GN,IS,ML,MR,SH,SL,SN,TG +0519-00402 Africa/Abidjan CK -2114-15946 Pacific/Rarotonga CL -3327-07040 America/Santiago most of Chile -CL -5309-07055 America/Punta_Arenas Region of Magallanes +CL -4534-07204 America/Coyhaique Aysén Region +CL -5309-07055 America/Punta_Arenas Magallanes Region CL -2709-10926 Pacific/Easter Easter Island CN +3114+12128 Asia/Shanghai Beijing Time CN +4348+08735 Asia/Urumqi Xinjiang Time diff --git a/contrib/python/pytz/py3/pytz/zoneinfo/zonenow.tab b/contrib/python/pytz/py3/pytz/zoneinfo/zonenow.tab index d2c1e48584f8..093f0a0cb749 100644 --- a/contrib/python/pytz/py3/pytz/zoneinfo/zonenow.tab +++ b/contrib/python/pytz/py3/pytz/zoneinfo/zonenow.tab @@ -104,7 +104,7 @@ XX +4439-06336 America/Halifax Atlantic ("AST/ADT") - Canada; Bermuda XX +4734-05243 America/St_Johns Newfoundland ("NST/NDT") # # -03 -XX -2332-04637 America/Sao_Paulo eastern South America +XX -2332-04637 America/Sao_Paulo eastern and southern South America # # -03/-02 (North America DST) XX +4703-05620 America/Miquelon St Pierre & Miquelon diff --git a/contrib/python/pytz/py3/ya.make b/contrib/python/pytz/py3/ya.make index 7686a5866163..60909b6a6b88 100644 --- a/contrib/python/pytz/py3/ya.make +++ b/contrib/python/pytz/py3/ya.make @@ -2,7 +2,7 @@ PY3_LIBRARY() -VERSION(2025.1) +VERSION(2025.2) LICENSE(MIT) @@ -125,6 +125,7 @@ RESOURCE_FILES( pytz/zoneinfo/America/Coral_Harbour pytz/zoneinfo/America/Cordoba pytz/zoneinfo/America/Costa_Rica + pytz/zoneinfo/America/Coyhaique pytz/zoneinfo/America/Creston pytz/zoneinfo/America/Cuiaba pytz/zoneinfo/America/Curacao diff --git a/yt/yt/core/misc/unittests/consistent_hashing_ut.cpp b/yt/yt/core/misc/unittests/consistent_hashing_ut.cpp index 2f96372a61c7..dfe692f419a8 100644 --- a/yt/yt/core/misc/unittests/consistent_hashing_ut.cpp +++ b/yt/yt/core/misc/unittests/consistent_hashing_ut.cpp @@ -6,6 +6,8 @@ #include +#include + #include #include #include @@ -27,8 +29,7 @@ struct TStringHasher { ui64 operator()(const TString& node, ui64 index) const { - auto hashNode = ::THash()(node); - return (hashNode ^ (index << 3)) + hashNode << (index & 7); + return MultiHash(node, index); } }; From 8aaf2a74f96af4031b1dd50661e0514977129470 Mon Sep 17 00:00:00 2001 From: pogorelov Date: Wed, 9 Apr 2025 09:51:18 +0300 Subject: [PATCH 079/454] Make TLogger respect rvalues commit_hash:dc29e989d9edbb7f171ba47632de428289393058 --- library/cpp/yt/logging/logger-inl.h | 18 +++++++++++++-- library/cpp/yt/logging/logger.cpp | 34 +++++++++++++++++++++++++---- library/cpp/yt/logging/logger.h | 22 ++++++++++++++----- 3 files changed, 62 insertions(+), 12 deletions(-) diff --git a/library/cpp/yt/logging/logger-inl.h b/library/cpp/yt/logging/logger-inl.h index 958ede8cda05..c9a98cb3b449 100644 --- a/library/cpp/yt/logging/logger-inl.h +++ b/library/cpp/yt/logging/logger-inl.h @@ -35,21 +35,35 @@ void TLogger::AddStructuredTag(TStringBuf key, TType value) } template -TLogger TLogger::WithTag(const char* format, TArgs&&... args) const +TLogger TLogger::WithTag(const char* format, TArgs&&... args) const & { auto result = *this; result.AddTag(format, std::forward(args)...); return result; } +template +TLogger TLogger::WithTag(const char* format, TArgs&&... args) && +{ + AddTag(format, std::forward(args)...); + return std::move(*this); +} + template -TLogger TLogger::WithStructuredTag(TStringBuf key, TType value) const +TLogger TLogger::WithStructuredTag(TStringBuf key, TType value) const & { auto result = *this; result.AddStructuredTag(key, value); return result; } +template +TLogger TLogger::WithStructuredTag(TStringBuf key, TType value) && +{ + AddStructuredTag(key, value); + return std::move(*this); +} + Y_FORCE_INLINE ELogLevel TLogger::GetEffectiveLoggingLevel(ELogLevel level, const TLoggingAnchor& anchor) { // Check if anchor is suppressed. diff --git a/library/cpp/yt/logging/logger.cpp b/library/cpp/yt/logging/logger.cpp index 682231d48958..38fd5b6e1349 100644 --- a/library/cpp/yt/logging/logger.cpp +++ b/library/cpp/yt/logging/logger.cpp @@ -226,34 +226,52 @@ void TLogger::AddRawTag(const std::string& tag) state->Tag += tag; } -TLogger TLogger::WithRawTag(const std::string& tag) const +TLogger TLogger::WithRawTag(const std::string& tag) const & { auto result = *this; result.AddRawTag(tag); return result; } -TLogger TLogger::WithEssential(bool essential) const +TLogger TLogger::WithRawTag(const std::string& tag) && +{ + AddRawTag(tag); + return std::move(*this); +} + +TLogger TLogger::WithEssential(bool essential) const & { auto result = *this; result.Essential_ = essential; return result; } +TLogger TLogger::WithEssential(bool essential) && +{ + Essential_ = essential; + return std::move(*this); +} + void TLogger::AddStructuredValidator(TStructuredValidator validator) { auto* state = GetMutableCoWState(); state->StructuredValidators.push_back(std::move(validator)); } -TLogger TLogger::WithStructuredValidator(TStructuredValidator validator) const +TLogger TLogger::WithStructuredValidator(TStructuredValidator validator) const & { auto result = *this; result.AddStructuredValidator(std::move(validator)); return result; } -TLogger TLogger::WithMinLevel(ELogLevel minLevel) const +TLogger TLogger::WithStructuredValidator(TStructuredValidator validator) && +{ + AddStructuredValidator(std::move(validator)); + return std::move(*this); +} + +TLogger TLogger::WithMinLevel(ELogLevel minLevel) const & { auto result = *this; if (result) { @@ -262,6 +280,14 @@ TLogger TLogger::WithMinLevel(ELogLevel minLevel) const return result; } +TLogger TLogger::WithMinLevel(ELogLevel minLevel) && +{ + if (*this) { + MinLevel_ = minLevel; + } + return std::move(*this); +} + const std::string& TLogger::GetTag() const { static const std::string emptyResult; diff --git a/library/cpp/yt/logging/logger.h b/library/cpp/yt/logging/logger.h index 53bb13e70545..dfa1b79bac8f 100644 --- a/library/cpp/yt/logging/logger.h +++ b/library/cpp/yt/logging/logger.h @@ -181,7 +181,9 @@ class TLogger TLogger() = default; TLogger(const TLogger& other) = default; + TLogger(TLogger&& other) = default; TLogger& operator=(const TLogger& other) = default; + TLogger& operator=(TLogger&& other) = default; TLogger(ILogManager* logManager, TStringBuf categoryName); explicit TLogger(TStringBuf categoryName); @@ -224,18 +226,26 @@ class TLogger void AddStructuredValidator(TStructuredValidator validator); - TLogger WithRawTag(const std::string& tag) const; + TLogger WithRawTag(const std::string& tag) const &; + TLogger WithRawTag(const std::string& tag) &&; template - TLogger WithTag(const char* format, TArgs&&... args) const; + TLogger WithTag(const char* format, TArgs&&... args) const &; + template + TLogger WithTag(const char* format, TArgs&&... args) &&; template - TLogger WithStructuredTag(TStringBuf key, TType value) const; + TLogger WithStructuredTag(TStringBuf key, TType value) const &; + template + TLogger WithStructuredTag(TStringBuf key, TType value) &&; - TLogger WithStructuredValidator(TStructuredValidator validator) const; + TLogger WithStructuredValidator(TStructuredValidator validator) const &; + TLogger WithStructuredValidator(TStructuredValidator validator) &&; - TLogger WithMinLevel(ELogLevel minLevel) const; + TLogger WithMinLevel(ELogLevel minLevel) const &; + TLogger WithMinLevel(ELogLevel minLevel) &&; - TLogger WithEssential(bool essential = true) const; + TLogger WithEssential(bool essential = true) const &; + TLogger WithEssential(bool essential = true) &&; const std::string& GetTag() const; const TStructuredTags& GetStructuredTags() const; From 54fc0013c84757f06a83d1ce931b031d61b68aa4 Mon Sep 17 00:00:00 2001 From: egovol Date: Wed, 9 Apr 2025 11:20:48 +0300 Subject: [PATCH 080/454] use consistent BreakConstructorInitializers and BreakInheritanceList options in `.clang-format` commit_hash:1d25146f5a76da6ee2b6fadbf9e9650782f6704b --- build/config/tests/cpp_style/.clang-format | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/config/tests/cpp_style/.clang-format b/build/config/tests/cpp_style/.clang-format index b2d89e2e756e..1f107ebb99a1 100644 --- a/build/config/tests/cpp_style/.clang-format +++ b/build/config/tests/cpp_style/.clang-format @@ -15,7 +15,7 @@ AlwaysBreakTemplateDeclarations: true AlwaysBreakBeforeMultilineStrings: false BreakBeforeBinaryOperators: false BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: true +BreakConstructorInitializers: BeforeComma BinPackParameters: true ColumnLimit: 0 ConstructorInitializerAllOnOneLineOrOnePerLine: false From 477ebee98a56c83d74793a0c41e29bbb211ed829 Mon Sep 17 00:00:00 2001 From: nechda Date: Wed, 9 Apr 2025 11:27:16 +0300 Subject: [PATCH 081/454] Change default TensorRT version in AUTOCHECK from 5 to 10 commit_hash:b82d5a6815e917785ddb64ad020632e814fe0308 --- build/ymake.core.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/ymake.core.conf b/build/ymake.core.conf index d6fc5e9e8d4a..bbcc3d87a8fb 100644 --- a/build/ymake.core.conf +++ b/build/ymake.core.conf @@ -5669,7 +5669,7 @@ when ($CUDA11) { when ($CUDA12) { CUDA_VERSION=12.6 CUDNN_VERSION=8.6.0 - TENSORRT_VERSION=8 + TENSORRT_VERSION=10 CUDA_ARCHITECTURES= NVCC_STD_VER=20 } @@ -5679,7 +5679,7 @@ when ($TENSORFLOW_WITH_CUDA) { } when (!$TENSORRT_VERSION) { - TENSORRT_VERSION=5 + TENSORRT_VERSION=10 } ANDROID_APK_TEST_ACTIVITY_VALUE=com.yandex.test.unittests/.RunTestsActivity From 2195df62d781b7d0522e80b4cea455eba9e273a2 Mon Sep 17 00:00:00 2001 From: babenko Date: Wed, 9 Apr 2025 11:31:41 +0300 Subject: [PATCH 082/454] Fix (irreproduciable) bug in ParseAndValidateYamlInteger commit_hash:520a331780a798315911b90e4f4d932d9b809bc9 --- yt/yt/library/formats/yaml_helpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yt/yt/library/formats/yaml_helpers.cpp b/yt/yt/library/formats/yaml_helpers.cpp index 1797514767d3..33efe3fe22b3 100644 --- a/yt/yt/library/formats/yaml_helpers.cpp +++ b/yt/yt/library/formats/yaml_helpers.cpp @@ -120,7 +120,7 @@ std::pair ParseAndValidateYamlInteger(const std::st return TryIntFromString<10>(adjustedValue, result); } else if (base == 16) { return TryIntFromString<16>(adjustedValue, result); - } else if (base = 8) { + } else if (base == 8) { return TryIntFromString<8>(adjustedValue, result); } else { YT_ABORT(); From eece934e80fc0daedd6174e6fbc0e507e59690f6 Mon Sep 17 00:00:00 2001 From: Pisarenko Grigoriy Date: Wed, 9 Apr 2025 12:18:05 +0300 Subject: [PATCH 083/454] YQ kqprun, fixed settings passing (#16974) --- ydb/tests/tools/fqrun/fqrun.cpp | 4 ++ ydb/tests/tools/fqrun/src/fq_setup.cpp | 9 +-- .../tools/kqprun/runlib/kikimr_setup.cpp | 64 +++++++++---------- ydb/tests/tools/kqprun/runlib/kikimr_setup.h | 13 ++-- ydb/tests/tools/kqprun/src/ydb_setup.cpp | 7 +- 5 files changed, 47 insertions(+), 50 deletions(-) diff --git a/ydb/tests/tools/fqrun/fqrun.cpp b/ydb/tests/tools/fqrun/fqrun.cpp index ec68a177a9ab..7e2cc0613a6a 100644 --- a/ydb/tests/tools/fqrun/fqrun.cpp +++ b/ydb/tests/tools/fqrun/fqrun.cpp @@ -551,6 +551,10 @@ class TMain : public TMainBase { void SetupLogsConfig() { auto& logConfig = *RunnerOptions.FqSettings.AppConfig.MutableLogConfig(); + if (DefaultLogPriority) { + logConfig.SetDefaultLevel(*DefaultLogPriority); + } + if (FqLogPriority) { std::unordered_map fqLogPriorities; std::unordered_set prefixes = { diff --git a/ydb/tests/tools/fqrun/src/fq_setup.cpp b/ydb/tests/tools/fqrun/src/fq_setup.cpp index 647ef74ebf17..066d6d01dbfe 100644 --- a/ydb/tests/tools/fqrun/src/fq_setup.cpp +++ b/ydb/tests/tools/fqrun/src/fq_setup.cpp @@ -33,7 +33,9 @@ class TFqSetup::TImpl : public TKikimrSetupBase { private: NKikimr::Tests::TServerSettings GetServerSettings(ui32 grpcPort) { - auto serverSettings = TBase::GetServerSettings(grpcPort, Settings.VerboseLevel >= EVerbose::InitLogs); + auto serverSettings = TBase::GetServerSettings(Settings, grpcPort, Settings.VerboseLevel >= EVerbose::InitLogs); + + serverSettings.SetEnableYqGrpc(true); return serverSettings; } @@ -178,8 +180,7 @@ class TFqSetup::TImpl : public TKikimrSetupBase { public: explicit TImpl(const TFqSetupSettings& settings) - : TBase(settings) - , Settings(settings) + : Settings(settings) { const ui32 grpcPort = Settings.FirstGrpcPort ? Settings.FirstGrpcPort : PortManager.GetPort(); if (Settings.GrpcEnabled && Settings.VerboseLevel >= EVerbose::Info) { @@ -270,7 +271,7 @@ class TFqSetup::TImpl : public TKikimrSetupBase { ythrow yexception() << "Trace opt was disabled"; } - NYql::NLog::YqlLogger().ResetBackend(CreateLogBackend()); + NYql::NLog::YqlLogger().ResetBackend(CreateLogBackend(Settings)); } static void StopTraceOpt() { diff --git a/ydb/tests/tools/kqprun/runlib/kikimr_setup.cpp b/ydb/tests/tools/kqprun/runlib/kikimr_setup.cpp index db98a5b05abf..4d241becf2b9 100644 --- a/ydb/tests/tools/kqprun/runlib/kikimr_setup.cpp +++ b/ydb/tests/tools/kqprun/runlib/kikimr_setup.cpp @@ -58,75 +58,71 @@ class TStaticSecuredCredentialsFactory : public NYql::ISecuredServiceAccountCred } // anonymous namespace -TKikimrSetupBase::TKikimrSetupBase(const TServerSettings& settings) - : Settings(settings) -{} - -TAutoPtr TKikimrSetupBase::CreateLogBackend() const { - if (Settings.LogOutputFile) { - return NActors::CreateFileBackend(Settings.LogOutputFile); +TAutoPtr TKikimrSetupBase::CreateLogBackend(const TServerSettings& settings) const { + if (settings.LogOutputFile) { + return NActors::CreateFileBackend(settings.LogOutputFile); } else { return NActors::CreateStderrBackend(); } } -NKikimr::Tests::TServerSettings TKikimrSetupBase::GetServerSettings(ui32 grpcPort, bool verbose) { +NKikimr::Tests::TServerSettings TKikimrSetupBase::GetServerSettings(const TServerSettings& settings, ui32 grpcPort, bool verbose) { const ui32 msgBusPort = PortManager.GetPort(); - NKikimr::Tests::TServerSettings serverSettings(msgBusPort, Settings.AppConfig.GetAuthConfig(), Settings.AppConfig.GetPQConfig()); - serverSettings.SetNodeCount(Settings.NodeCount); + NKikimr::Tests::TServerSettings serverSettings(msgBusPort, settings.AppConfig.GetAuthConfig(), settings.AppConfig.GetPQConfig()); + serverSettings.SetNodeCount(settings.NodeCount); - serverSettings.SetDomainName(TString(NKikimr::ExtractDomain(NKikimr::CanonizePath(Settings.DomainName)))); - serverSettings.SetAppConfig(Settings.AppConfig); - serverSettings.SetFeatureFlags(Settings.AppConfig.GetFeatureFlags()); - serverSettings.SetControls(Settings.AppConfig.GetImmediateControlsConfig()); - serverSettings.SetCompactionConfig(Settings.AppConfig.GetCompactionConfig()); - serverSettings.PQClusterDiscoveryConfig = Settings.AppConfig.GetPQClusterDiscoveryConfig(); - serverSettings.NetClassifierConfig = Settings.AppConfig.GetNetClassifierConfig(); + serverSettings.SetDomainName(TString(NKikimr::ExtractDomain(NKikimr::CanonizePath(settings.DomainName)))); + serverSettings.SetAppConfig(settings.AppConfig); + serverSettings.SetFeatureFlags(settings.AppConfig.GetFeatureFlags()); + serverSettings.SetControls(settings.AppConfig.GetImmediateControlsConfig()); + serverSettings.SetCompactionConfig(settings.AppConfig.GetCompactionConfig()); + serverSettings.PQClusterDiscoveryConfig = settings.AppConfig.GetPQClusterDiscoveryConfig(); + serverSettings.NetClassifierConfig = settings.AppConfig.GetNetClassifierConfig(); - const auto& kqpSettings = Settings.AppConfig.GetKQPConfig().GetSettings(); + const auto& kqpSettings = settings.AppConfig.GetKQPConfig().GetSettings(); serverSettings.SetKqpSettings({kqpSettings.begin(), kqpSettings.end()}); - serverSettings.SetCredentialsFactory(std::make_shared(Settings.YqlToken)); - serverSettings.SetComputationFactory(Settings.ComputationFactory); - serverSettings.SetYtGateway(Settings.YtGateway); + serverSettings.SetCredentialsFactory(std::make_shared(settings.YqlToken)); + serverSettings.SetComputationFactory(settings.ComputationFactory); + serverSettings.SetYtGateway(settings.YtGateway); serverSettings.S3ActorsFactory = NYql::NDq::CreateS3ActorsFactory(); serverSettings.SetDqTaskTransformFactory(NYql::CreateYtDqTaskTransformFactory(true)); serverSettings.SetInitializeFederatedQuerySetupFactory(true); serverSettings.SetVerbose(verbose); serverSettings.SetNeedStatsCollectors(true); - SetLoggerSettings(serverSettings); - SetFunctionRegistry(serverSettings); + SetLoggerSettings(settings, serverSettings); + SetFunctionRegistry(settings, serverSettings); - if (Settings.MonitoringEnabled) { + if (settings.MonitoringEnabled) { serverSettings.InitKikimrRunConfig(); - serverSettings.SetMonitoringPortOffset(Settings.FirstMonitoringPort, true); + serverSettings.SetMonitoringPortOffset(settings.FirstMonitoringPort, true); } - if (Settings.GrpcEnabled) { + if (settings.GrpcEnabled) { serverSettings.SetGrpcPort(grpcPort); } return serverSettings; } -void TKikimrSetupBase::SetLoggerSettings(NKikimr::Tests::TServerSettings& serverSettings) const { - auto loggerInitializer = [this](NActors::TTestActorRuntime& runtime) { - InitLogSettings(Settings.AppConfig.GetLogConfig(), runtime); - runtime.SetLogBackendFactory([this]() { return CreateLogBackend(); }); +void TKikimrSetupBase::SetLoggerSettings(const TServerSettings& settings, NKikimr::Tests::TServerSettings& serverSettings) const { + auto loggerInitializer = [this, settings](NActors::TTestActorRuntime& runtime) { + InitLogSettings(settings.AppConfig.GetLogConfig(), runtime); + runtime.SetLogBackendFactory([this, settings]() { return CreateLogBackend(settings); }); }; serverSettings.SetLoggerInitializer(loggerInitializer); } -void TKikimrSetupBase::SetFunctionRegistry(NKikimr::Tests::TServerSettings& serverSettings) const { - if (!Settings.FunctionRegistry) { +void TKikimrSetupBase::SetFunctionRegistry(const TServerSettings& settings, NKikimr::Tests::TServerSettings& serverSettings) const { + if (!settings.FunctionRegistry) { return; } - auto functionRegistryFactory = [this](const NKikimr::NScheme::TTypeRegistry&) { - return Settings.FunctionRegistry.Get(); + auto functionRegistryFactory = [settings](const NKikimr::NScheme::TTypeRegistry&) { + return settings.FunctionRegistry.Get(); }; serverSettings.SetFrFactory(functionRegistryFactory); diff --git a/ydb/tests/tools/kqprun/runlib/kikimr_setup.h b/ydb/tests/tools/kqprun/runlib/kikimr_setup.h index fc02bcf3e2be..3c0b7fa27d56 100644 --- a/ydb/tests/tools/kqprun/runlib/kikimr_setup.h +++ b/ydb/tests/tools/kqprun/runlib/kikimr_setup.h @@ -10,22 +10,19 @@ namespace NKikimrRun { class TKikimrSetupBase { public: - TKikimrSetupBase(const TServerSettings& settings); + TKikimrSetupBase() = default; - TAutoPtr CreateLogBackend() const; + TAutoPtr CreateLogBackend(const TServerSettings& settings) const; - NKikimr::Tests::TServerSettings GetServerSettings(ui32 grpcPort, bool verbose); + NKikimr::Tests::TServerSettings GetServerSettings(const TServerSettings& settings, ui32 grpcPort, bool verbose); private: - void SetLoggerSettings(NKikimr::Tests::TServerSettings& serverSettings) const; + void SetLoggerSettings(const TServerSettings& settings, NKikimr::Tests::TServerSettings& serverSettings) const; - void SetFunctionRegistry(NKikimr::Tests::TServerSettings& serverSettings) const; + void SetFunctionRegistry(const TServerSettings& settings, NKikimr::Tests::TServerSettings& serverSettings) const; protected: TPortManager PortManager; - -private: - const TServerSettings& Settings; }; } // namespace NKikimrRun diff --git a/ydb/tests/tools/kqprun/src/ydb_setup.cpp b/ydb/tests/tools/kqprun/src/ydb_setup.cpp index 46157889643f..83e2c0923dd0 100644 --- a/ydb/tests/tools/kqprun/src/ydb_setup.cpp +++ b/ydb/tests/tools/kqprun/src/ydb_setup.cpp @@ -177,7 +177,7 @@ class TYdbSetup::TImpl : public TKikimrSetupBase { } NKikimr::Tests::TServerSettings GetServerSettings(ui32 grpcPort) { - auto serverSettings = TBase::GetServerSettings(grpcPort, Settings_.VerboseLevel >= EVerbose::InitLogs); + auto serverSettings = TBase::GetServerSettings(Settings_, grpcPort, Settings_.VerboseLevel >= EVerbose::InitLogs); SetStorageSettings(serverSettings); @@ -364,8 +364,7 @@ class TYdbSetup::TImpl : public TKikimrSetupBase { public: explicit TImpl(const TYdbSetupSettings& settings) - : TBase(settings) - , Settings_(settings) + : Settings_(settings) , CoutColors_(NColorizer::AutoColors(Cout)) { InitializeYqlLogger(); @@ -501,7 +500,7 @@ class TYdbSetup::TImpl : public TKikimrSetupBase { ythrow yexception() << "Trace opt was disabled"; } - NYql::NLog::YqlLogger().ResetBackend(CreateLogBackend()); + NYql::NLog::YqlLogger().ResetBackend(CreateLogBackend(Settings_)); } static void StopTraceOpt() { From 4089bad606c857a668fa63bbb3a426274b0d3fb5 Mon Sep 17 00:00:00 2001 From: Ilia Shakhov Date: Wed, 9 Apr 2025 12:54:21 +0300 Subject: [PATCH 084/454] Fix `-d /Root` in `ydb admin cluster dump` (#16943) --- ydb/apps/ydb/CHANGELOG.md | 1 + ydb/library/backup/backup.cpp | 6 +++++- ydb/tests/functional/ydb_cli/test_ydb_backup.py | 10 +++++++++- ydb/tests/library/harness/kikimr_config.py | 6 ++++++ 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ydb/apps/ydb/CHANGELOG.md b/ydb/apps/ydb/CHANGELOG.md index d017326187a0..823efa412a7c 100644 --- a/ydb/apps/ydb/CHANGELOG.md +++ b/ydb/apps/ydb/CHANGELOG.md @@ -5,6 +5,7 @@ * YDB CLI help message improvements. Different display for detailed help and brief help. * Support coordination nodes in `ydb scheme rmdir --recursive`. * Fixed return code of command `ydb workload * run --check-canonical` for the case when benchmark query results differ from canonical ones. +* Fixed scheme error in `ydb admin cluster dump` when specifying a domain database. ## 2.20.0 ## diff --git a/ydb/library/backup/backup.cpp b/ydb/library/backup/backup.cpp index 6e6ec69a572b..b2baf248a224 100644 --- a/ydb/library/backup/backup.cpp +++ b/ydb/library/backup/backup.cpp @@ -1474,8 +1474,12 @@ void BackupCluster(const TDriver& driver, TFsPath folderPath) { BackupClusterRoot(driver, folderPath); auto databases = ListDatabases(driver); + TDriverConfig dbDriverCfg = driver.GetConfig(); for (const auto& database : databases.GetPaths()) { - BackupDatabaseImpl(driver, TString(database), folderPath.Child("." + database), { + dbDriverCfg.SetDatabase(database); + TDriver dbDriver(dbDriverCfg); + + BackupDatabaseImpl(dbDriver, TString(database), folderPath.Child("." + database), { .WithRegularUsers = false, .WithContent = false, }); diff --git a/ydb/tests/functional/ydb_cli/test_ydb_backup.py b/ydb/tests/functional/ydb_cli/test_ydb_backup.py index be9147ea9ed8..4561f78b7557 100644 --- a/ydb/tests/functional/ydb_cli/test_ydb_backup.py +++ b/ydb/tests/functional/ydb_cli/test_ydb_backup.py @@ -1299,7 +1299,14 @@ def test_restore_no_data(self): class BaseTestClusterBackupInFiles(object): @classmethod def setup_class(cls): - cls.cluster = KiKiMR(KikimrConfigGenerator(extra_feature_flags=["enable_resource_pools"])) + cls.cluster = KiKiMR(KikimrConfigGenerator( + extra_feature_flags=[ + "enable_strict_acl_check", + "enable_strict_user_management", + "enable_database_admin" + ], + domain_login_only=False, + )) cls.cluster.start() cls.root_dir = "/Root" @@ -1366,6 +1373,7 @@ def create_backup(cls, command, expected_files, additional_args=[]): def create_cluster_backup(cls, expected_files, additional_args=[]): cls.create_backup( [ + "--database", cls.root_dir, "admin", "cluster", "dump", ], expected_files, diff --git a/ydb/tests/library/harness/kikimr_config.py b/ydb/tests/library/harness/kikimr_config.py index a2c0d5b37f1e..86bbd1fba3ca 100644 --- a/ydb/tests/library/harness/kikimr_config.py +++ b/ydb/tests/library/harness/kikimr_config.py @@ -165,6 +165,7 @@ def __init__( enable_resource_pools=None, grouped_memory_limiter_config=None, query_service_config=None, + domain_login_only=None, ): if extra_feature_flags is None: extra_feature_flags = [] @@ -349,6 +350,11 @@ def __init__( if auth_config_path: self.yaml_config["auth_config"] = _load_yaml_config(auth_config_path) + if domain_login_only is not None: + if "auth_config" not in self.yaml_config: + self.yaml_config["auth_config"] = dict() + self.yaml_config["auth_config"]["domain_login_only"] = domain_login_only + if fq_config_path: self.yaml_config["federated_query_config"] = _load_yaml_config(fq_config_path) From 3109c7a26f89a904f6a52d24f48072afd8c7ba19 Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Wed, 9 Apr 2025 12:45:09 +0300 Subject: [PATCH 085/454] Intermediate changes commit_hash:b05d89eb8dfeb6b3f2fe069a57d8f2297b8e3638 --- .../cfg/tests/gateways-experimental.conf | 31 ++++++++++++++++++- .../minirun/part0/canondata/result.json | 14 +++++++++ .../minirun/part8/canondata/result.json | 14 +++++++++ .../Blocks/WideFromBlocks-WideToBlocks.yqls | 24 ++++++++++++++ .../Blocks/WideToBlocks-WideFromBlocks.yqls | 25 +++++++++++++++ 5 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 yql/essentials/tests/s-expressions/suites/Blocks/WideFromBlocks-WideToBlocks.yqls create mode 100644 yql/essentials/tests/s-expressions/suites/Blocks/WideToBlocks-WideFromBlocks.yqls diff --git a/yql/essentials/cfg/tests/gateways-experimental.conf b/yql/essentials/cfg/tests/gateways-experimental.conf index a68414581b75..0c3dfaea61c2 100644 --- a/yql/essentials/cfg/tests/gateways-experimental.conf +++ b/yql/essentials/cfg/tests/gateways-experimental.conf @@ -39,9 +39,19 @@ Yt { Value: "true" } + DefaultSettings { + Name: "JobBlockInput" + Value: "true" + } + DefaultSettings { Name: "JobBlockInputSupportedTypes" - Value: "tuple" + Value: "tuple,pg" + } + + DefaultSettings { + Name: "BlockReaderSupportedTypes" + Value: "tuple,pg" } DefaultSettings { @@ -49,13 +59,32 @@ Yt { Value: "Int8,Uint8,Int16,Uint16,Int32,Uint32,Int64,Uint64,Bool,Double,String,Utf8,Yson,Float" } + DefaultSettings { + Name: "BlockReaderSupportedDataTypes" + Value: "Int8,Uint8,Int16,Uint16,Int32,Uint32,Int64,Uint64,Bool,Double,String,Utf8,Yson,Float" + } + DefaultSettings { Name: "ReportEquiJoinStats" Value: "true" } + + DefaultSettings { + Name: "UseRPCReaderInDq" + Value: "true" + } + + DefaultSettings { + Name: "DQRPCReaderTimeout" + Value: "600s" + } } Dq { + DefaultSettings { + Name: "UseBlockReader" + Value: "true" + } } YqlCore { diff --git a/yql/essentials/tests/s-expressions/minirun/part0/canondata/result.json b/yql/essentials/tests/s-expressions/minirun/part0/canondata/result.json index 0a80f2cd10c9..5902893a5aca 100644 --- a/yql/essentials/tests/s-expressions/minirun/part0/canondata/result.json +++ b/yql/essentials/tests/s-expressions/minirun/part0/canondata/result.json @@ -13,6 +13,20 @@ "uri": "https://{canondata_backend}/1942671/fe442fb9178873beea37ece387e67a5d541a25b2/resource.tar.gz#test.test_Aggregation-AggrCount-default.txt-Results_/results.txt" } ], + "test.test[Blocks-WideToBlocks-WideFromBlocks-default.txt-Debug]": [ + { + "checksum": "7838538438ce14638ded18f1defb2380", + "size": 627, + "uri": "https://{canondata_backend}/1925842/3d4a337c6b21036cefb828b5de69295a7ec717f6/resource.tar.gz#test.test_Blocks-WideToBlocks-WideFromBlocks-default.txt-Debug_/opt.yql" + } + ], + "test.test[Blocks-WideToBlocks-WideFromBlocks-default.txt-Results]": [ + { + "checksum": "f98666abfa816dc9b28ac6c28c9b5e7c", + "size": 1257, + "uri": "https://{canondata_backend}/1925842/3d4a337c6b21036cefb828b5de69295a7ec717f6/resource.tar.gz#test.test_Blocks-WideToBlocks-WideFromBlocks-default.txt-Results_/results.txt" + } + ], "test.test[Builtins-ByteString-default.txt-Debug]": [ { "checksum": "056b689b9c8cf44642288e79f8cd0185", diff --git a/yql/essentials/tests/s-expressions/minirun/part8/canondata/result.json b/yql/essentials/tests/s-expressions/minirun/part8/canondata/result.json index 2e7391094852..3d8ae83f3b51 100644 --- a/yql/essentials/tests/s-expressions/minirun/part8/canondata/result.json +++ b/yql/essentials/tests/s-expressions/minirun/part8/canondata/result.json @@ -55,6 +55,20 @@ "uri": "https://{canondata_backend}/1937429/6dc717bd36879ce84e2fa1eb85b97eefce0733e9/resource.tar.gz#test.test_Blocks-ListFromBlocks-default.txt-Results_/results.txt" } ], + "test.test[Blocks-WideFromBlocks-WideToBlocks-default.txt-Debug]": [ + { + "checksum": "d6c0024db8898aef8f8b31b1025667cc", + "size": 483, + "uri": "https://{canondata_backend}/1925842/70c39ce7d6aa898d26d58abf8d512eebac34de7f/resource.tar.gz#test.test_Blocks-WideFromBlocks-WideToBlocks-default.txt-Debug_/opt.yql" + } + ], + "test.test[Blocks-WideFromBlocks-WideToBlocks-default.txt-Results]": [ + { + "checksum": "3326d454244059e96a0b61b3fdf53480", + "size": 878, + "uri": "https://{canondata_backend}/1925842/70c39ce7d6aa898d26d58abf8d512eebac34de7f/resource.tar.gz#test.test_Blocks-WideFromBlocks-WideToBlocks-default.txt-Results_/results.txt" + } + ], "test.test[Builtins-ToIntegral-default.txt-Debug]": [ { "checksum": "33f569baf5940bbd79fbf635f47cc363", diff --git a/yql/essentials/tests/s-expressions/suites/Blocks/WideFromBlocks-WideToBlocks.yqls b/yql/essentials/tests/s-expressions/suites/Blocks/WideFromBlocks-WideToBlocks.yqls new file mode 100644 index 000000000000..cd1a5d60d23c --- /dev/null +++ b/yql/essentials/tests/s-expressions/suites/Blocks/WideFromBlocks-WideToBlocks.yqls @@ -0,0 +1,24 @@ +( +# XXX: Explicitly enable PeepHoleBlock and PeepHoleFinalBlock steps. +(let world (Configure! world (DataSource 'config) 'BlockEngine 'force)) +(let wconf (DataSink 'result)) + +(let x1 (AsStruct '('"x" (Int32 '"1")))) +(let x2 (AsStruct '('"x" (Int32 '"2")))) +(let x3 (AsStruct '('"x" (Int32 '"3")))) +(let x4 (AsStruct '('"x" (Int32 '"4")))) + +(let list (AsList x1 x2 x3 x4)) + +(let expandLambda (lambda '(item) (Member item '"x"))) +(let wideStream (FromFlow (ExpandMap (ToFlow list) expandLambda))) + +(let nopFromBlocksToBlocks (WideFromBlocks (WideToBlocks wideStream))) + +(let narrowLambda (lambda '(x) (AsStruct '('"x" x)))) +(let scalarList (ForwardList (NarrowMap (ToFlow nopFromBlocksToBlocks) narrowLambda))) + +(let world (Write! world wconf (Key) scalarList '('('type)))) +(let world (Commit! world wconf)) +(return world) +) diff --git a/yql/essentials/tests/s-expressions/suites/Blocks/WideToBlocks-WideFromBlocks.yqls b/yql/essentials/tests/s-expressions/suites/Blocks/WideToBlocks-WideFromBlocks.yqls new file mode 100644 index 000000000000..cafd0f45a815 --- /dev/null +++ b/yql/essentials/tests/s-expressions/suites/Blocks/WideToBlocks-WideFromBlocks.yqls @@ -0,0 +1,25 @@ +( +# XXX: Explicitly enable PeepHoleBlock and PeepHoleFinalBlock steps. +(let world (Configure! world (DataSource 'config) 'BlockEngine 'force)) +(let wconf (DataSink 'result)) + +(let x1 (AsStruct '('"x" (Int32 '"1")))) +(let x2 (AsStruct '('"x" (Int32 '"2")))) +(let x3 (AsStruct '('"x" (Int32 '"3")))) +(let x4 (AsStruct '('"x" (Int32 '"4")))) +(let scalar0 (AsScalar (Int32 '"0"))) + +(let blockList (ListToBlocks (AsList x1 x2 x3 x4))) + +(let expandLambda (lambda '(item) (Member item '"x") scalar0 (Member item '"_yql_block_length"))) +(let wideBlocksStream (FromFlow (ExpandMap (ToFlow blockList) expandLambda))) + +(let nopToBlocksFromBlocks (WideToBlocks (WideFromBlocks wideBlocksStream))) + +(let narrowLambda (lambda '(x scalar blockLength) (AsStruct '('"x" x) '('"scalar" scalar) '('"_yql_block_length" blockLength)))) +(let scalarList (ListFromBlocks (ForwardList (NarrowMap (ToFlow nopToBlocksFromBlocks) narrowLambda)))) + +(let world (Write! world wconf (Key) scalarList '('('type)))) +(let world (Commit! world wconf)) +(return world) +) From b4a15ad406e0bd7ff34461ef71216f0155a81a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9E=D0=BB=D0=B5=D0=B3?= <150132506+iddqdex@users.noreply.github.com> Date: Wed, 9 Apr 2025 13:26:15 +0300 Subject: [PATCH 086/454] Tpcds q73 order by ss ticket number (#16977) --- ydb/library/benchmarks/queries/tpcds/pg/q73.sql | 2 +- ydb/library/benchmarks/queries/tpcds/yql/q73.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ydb/library/benchmarks/queries/tpcds/pg/q73.sql b/ydb/library/benchmarks/queries/tpcds/pg/q73.sql index 7c5223c6a3ea..edfd6c029c35 100644 --- a/ydb/library/benchmarks/queries/tpcds/pg/q73.sql +++ b/ydb/library/benchmarks/queries/tpcds/pg/q73.sql @@ -24,6 +24,6 @@ select c_last_name group by ss_ticket_number,ss_customer_sk) dj,{{customer}} where ss_customer_sk = c_customer_sk and cnt between 1::int8 and 5::int8 - order by cnt desc, c_last_name asc; + order by cnt desc, c_last_name asc, ss_ticket_number asc; -- end query 1 in stream 0 using template ../query_templates/query73.tpl diff --git a/ydb/library/benchmarks/queries/tpcds/yql/q73.sql b/ydb/library/benchmarks/queries/tpcds/yql/q73.sql index 38ec16b2413b..bd9a142449be 100644 --- a/ydb/library/benchmarks/queries/tpcds/yql/q73.sql +++ b/ydb/library/benchmarks/queries/tpcds/yql/q73.sql @@ -28,6 +28,6 @@ select c_last_name group by store_sales.ss_ticket_number,store_sales.ss_customer_sk) dj cross join {{customer}} as customer where ss_customer_sk = c_customer_sk and cnt between 1 and 5 - order by cnt desc, c_last_name asc; + order by cnt desc, c_last_name asc, ss_ticket_number asc; -- end query 1 in stream 0 using template query73.tpl From 7499298f48733a18426a9a3cb0d62efb08eb3164 Mon Sep 17 00:00:00 2001 From: Alexander Avdonkin Date: Wed, 9 Apr 2025 13:39:21 +0300 Subject: [PATCH 087/454] =?UTF-8?q?Added=20parameter=20which=20sets=20fixe?= =?UTF-8?q?d=20number=20of=20seconds=20to=20subtract=20from=20c=E2=80=A6?= =?UTF-8?q?=20(#15351)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ydb/library/workload/log/log.cpp | 4 +++- ydb/library/workload/log/log.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ydb/library/workload/log/log.cpp b/ydb/library/workload/log/log.cpp index 5bfe4fa5c34f..7339adce9acd 100644 --- a/ydb/library/workload/log/log.cpp +++ b/ydb/library/workload/log/log.cpp @@ -253,7 +253,7 @@ class TRandomLogGenerator { } TInstant RandomInstant() const { - auto result = TInstant::Now(); + auto result = TInstant::Now() - TDuration::Seconds(Params.TimestampSubtract); i64 millisecondsDiff = 60 * 1000 * NormalRandom(0., Params.TimestampStandardDeviationMinutes); if (millisecondsDiff >= 0) { // TDuration::MilliSeconds can't be negative for some reason... result += TDuration::MilliSeconds(millisecondsDiff); @@ -420,6 +420,8 @@ void TLogWorkloadParams::ConfigureOpts(NLastGetopt::TOpts& opts, const ECommandT .DefaultValue(RowsCnt).StoreResult(&RowsCnt); opts.AddLongOption("timestamp_deviation", "Standard deviation. For each timestamp, a random variable with a specified standard deviation in minutes is added.") .DefaultValue(TimestampStandardDeviationMinutes).StoreResult(&TimestampStandardDeviationMinutes); + opts.AddLongOption("timestamp_subtract", "Value in seconds to subtract from timestamp. For each timestamp, this value in seconds is subtracted") + .DefaultValue(0).StoreResult(&TimestampSubtract); opts.AddLongOption("null-percent", "Percent of nulls in generated data") .DefaultValue(NullPercent).StoreResult(&NullPercent); break; diff --git a/ydb/library/workload/log/log.h b/ydb/library/workload/log/log.h index e7f903b32794..7145a0e04791 100644 --- a/ydb/library/workload/log/log.h +++ b/ydb/library/workload/log/log.h @@ -25,6 +25,7 @@ class TLogWorkloadParams : public TWorkloadParams { ui64 KeyColumnsCnt = 0; ui64 TimestampStandardDeviationMinutes = 0; ui64 TimestampTtlMinutes = 0; + ui64 TimestampSubtract = 0; ui64 RowsCnt = 1; ui32 NullPercent = 10; bool PartitionsByLoad = true; From 2da977708b0f780fd122dd337aedefbad66ad289 Mon Sep 17 00:00:00 2001 From: gryzlov-ad Date: Wed, 9 Apr 2025 13:24:00 +0300 Subject: [PATCH 088/454] YT-23505: Introduce chaos lease commit_hash:4c47b7b75ace18f0f57347b25b062bf0d414e7d9 --- yt/yt/client/chaos_client/helpers.cpp | 9 +++++++++ yt/yt/client/chaos_client/public.h | 5 ++++- yt/yt/client/object_client/helpers.cpp | 10 ++++++++++ yt/yt/client/object_client/helpers.h | 6 ++++++ yt/yt/client/object_client/public.h | 1 + .../yt/client/chaos_client/proto/chaos_lease.proto | 10 ++++++++++ yt/yt_proto/yt/client/ya.make | 1 + 7 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 yt/yt_proto/yt/client/chaos_client/proto/chaos_lease.proto diff --git a/yt/yt/client/chaos_client/helpers.cpp b/yt/yt/client/chaos_client/helpers.cpp index 8f7a289c3486..7ec2f3284d7f 100644 --- a/yt/yt/client/chaos_client/helpers.cpp +++ b/yt/yt/client/chaos_client/helpers.cpp @@ -21,6 +21,15 @@ TReplicationCardId MakeReplicationCardId(TObjectId randomId) EntropyFromId(randomId) & 0xffff0000); } +TReplicationCardId MakeChaosLeaseId(TObjectId randomId) +{ + return MakeId( + EObjectType::ChaosLease, + CellTagFromId(randomId), + CounterFromId(randomId), + EntropyFromId(randomId) & 0xffff0000); +} + TReplicaId MakeReplicaId(TReplicationCardId replicationCardId, TReplicaIdIndex index) { return MakeId( diff --git a/yt/yt/client/chaos_client/public.h b/yt/yt/client/chaos_client/public.h index 4f1eb1c50ae1..5c50d3a806e2 100644 --- a/yt/yt/client/chaos_client/public.h +++ b/yt/yt/client/chaos_client/public.h @@ -11,7 +11,10 @@ namespace NYT::NChaosClient { //////////////////////////////////////////////////////////////////////////////// using TReplicationCardId = NObjectClient::TObjectId; -using TReplicationCardCollocationId = NObjectClient::TObjectId; +using TChaosObjectId = NObjectClient::TObjectId; +// using TReplicationCardId = TChaosObjectId; +using TReplicationCardCollocationId = TChaosObjectId; +using TChaosLeaseId = TChaosObjectId; using TReplicaId = NObjectClient::TObjectId; using TReplicationEra = ui64; using TReplicaIdIndex = ui16; diff --git a/yt/yt/client/object_client/helpers.cpp b/yt/yt/client/object_client/helpers.cpp index e7ba1b93ce19..db59fe02b081 100644 --- a/yt/yt/client/object_client/helpers.cpp +++ b/yt/yt/client/object_client/helpers.cpp @@ -256,6 +256,16 @@ bool IsChaosTableReplicaType(EObjectType type) return type == EObjectType::ChaosTableReplica; } +bool IsReplicationCardType(EObjectType type) +{ + return type == EObjectType::ReplicationCard; +} + +bool IsChaosLeaseType(EObjectType type) +{ + return type == EObjectType::ChaosLease; +} + bool IsCollocationType(EObjectType type) { return diff --git a/yt/yt/client/object_client/helpers.h b/yt/yt/client/object_client/helpers.h index ac2f24714c1a..64fd9b2445c0 100644 --- a/yt/yt/client/object_client/helpers.h +++ b/yt/yt/client/object_client/helpers.h @@ -67,6 +67,12 @@ bool IsTableReplicaType(EObjectType type); //! Checks if the given type is a chaos replica. bool IsChaosTableReplicaType(EObjectType type); +//! Checks if the given type is a replication card. +bool IsReplicationCardType(EObjectType type); + +//! Checks if the given type is a chaos lease. +bool IsChaosLeaseType(EObjectType type); + //! Checks if the given type is a collocation. bool IsCollocationType(EObjectType type); diff --git a/yt/yt/client/object_client/public.h b/yt/yt/client/object_client/public.h index 37a83b1b2075..e037ce3f74ae 100644 --- a/yt/yt/client/object_client/public.h +++ b/yt/yt/client/object_client/public.h @@ -342,6 +342,7 @@ DEFINE_ENUM(EObjectType, ((ChaosReplicatedTable) (1206)) ((ReplicationCardCollocation) (1207)) ((VirtualChaosCellMap) (1208)) + ((ChaosLease) (1209)) // Other cluster components stuff ((ClusterProxyNode) (1500)) diff --git a/yt/yt_proto/yt/client/chaos_client/proto/chaos_lease.proto b/yt/yt_proto/yt/client/chaos_client/proto/chaos_lease.proto new file mode 100644 index 000000000000..970c8e7447ba --- /dev/null +++ b/yt/yt_proto/yt/client/chaos_client/proto/chaos_lease.proto @@ -0,0 +1,10 @@ +package NYT.NChaosClient.NProto; + +import "yt_proto/yt/core/misc/proto/guid.proto"; + +//////////////////////////////////////////////////////////////////////////////// + +message TChaosLease +{ } + +//////////////////////////////////////////////////////////////////////////////// diff --git a/yt/yt_proto/yt/client/ya.make b/yt/yt_proto/yt/client/ya.make index dbf44fcbc892..e799449115f7 100644 --- a/yt/yt_proto/yt/client/ya.make +++ b/yt/yt_proto/yt/client/ya.make @@ -19,6 +19,7 @@ SRCS( cell_master/proto/cell_directory.proto chaos_client/proto/replication_card.proto + chaos_client/proto/chaos_lease.proto chunk_client/proto/data_statistics.proto chunk_client/proto/chunk_meta.proto From 3a93a5327c56de1d9b5df1457120d5d788068123 Mon Sep 17 00:00:00 2001 From: gryzlov-ad Date: Wed, 9 Apr 2025 13:28:31 +0300 Subject: [PATCH 089/454] YT-23505: Add IPrerequisite to client/api commit_hash:7dcae50ae63844645ae306627ebeec7cc090430d --- yt/yt/client/api/client.h | 14 +++-- yt/yt/client/api/delegating_client.cpp | 2 +- yt/yt/client/api/delegating_client.h | 5 ++ yt/yt/client/api/delegating_transaction.cpp | 2 +- yt/yt/client/api/delegating_transaction.h | 6 +- yt/yt/client/api/prerequisite-inl.h | 41 ++++++++++++ yt/yt/client/api/prerequisite.h | 62 +++++++++++++++++++ yt/yt/client/api/prerequisite_client.h | 30 +++++++++ yt/yt/client/api/public.h | 3 + yt/yt/client/api/rpc_proxy/client_impl.cpp | 11 ++++ yt/yt/client/api/rpc_proxy/client_impl.h | 4 ++ .../client/api/rpc_proxy/transaction_impl.cpp | 4 +- yt/yt/client/api/rpc_proxy/transaction_impl.h | 4 +- yt/yt/client/api/transaction-inl.h | 42 ------------- yt/yt/client/api/transaction.cpp | 10 +++ yt/yt/client/api/transaction.h | 52 ++++------------ yt/yt/client/api/transaction_client.h | 7 +-- yt/yt/client/federated/client.cpp | 24 ++++++- yt/yt/client/hedging/hedging.cpp | 1 + yt/yt/client/prerequisite_client/public.h | 13 ++++ yt/yt/client/unittests/mock/client.h | 5 ++ yt/yt/client/unittests/mock/transaction.h | 2 +- 22 files changed, 238 insertions(+), 106 deletions(-) create mode 100644 yt/yt/client/api/prerequisite-inl.h create mode 100644 yt/yt/client/api/prerequisite.h create mode 100644 yt/yt/client/api/prerequisite_client.h delete mode 100644 yt/yt/client/api/transaction-inl.h create mode 100644 yt/yt/client/prerequisite_client/public.h diff --git a/yt/yt/client/api/client.h b/yt/yt/client/api/client.h index 823e37ad3962..713c524a1d00 100644 --- a/yt/yt/client/api/client.h +++ b/yt/yt/client/api/client.h @@ -1,21 +1,22 @@ #pragma once -#include "connection.h" #include "accounting_client.h" #include "admin_client.h" +#include "connection.h" #include "cypress_client.h" #include "distributed_table_client.h" #include "etc_client.h" #include "file_client.h" +#include "flow_client.h" #include "journal_client.h" #include "operation_client.h" -#include "security_client.h" -#include "transaction_client.h" -#include "table_client.h" -#include "queue_client.h" +#include "prerequisite_client.h" #include "query_tracker_client.h" -#include "flow_client.h" +#include "queue_client.h" +#include "security_client.h" #include "shuffle_client.h" +#include "table_client.h" +#include "transaction_client.h" #include @@ -60,6 +61,7 @@ DEFINE_REFCOUNTED_TYPE(IClientBase) */ struct IClient : public virtual IClientBase + , public IPrerequisiteClient , public ITransactionClient , public ITableClient , public IQueueClient diff --git a/yt/yt/client/api/delegating_client.cpp b/yt/yt/client/api/delegating_client.cpp index d71befc40205..5e4b6f6afce2 100644 --- a/yt/yt/client/api/delegating_client.cpp +++ b/yt/yt/client/api/delegating_client.cpp @@ -11,7 +11,7 @@ TDelegatingClient::TDelegatingClient(IClientPtr underlying) //////////////////////////////////////////////////////////////////////////////// // Ensure that delegating client contains implementations for all -// methods of IClient. Tthis reduces the number of PR iterations you need to +// methods of IClient. This reduces the number of PR iterations you need to // find that some out-of-yt/yt implementation of IClient does not compile. void InstantiateDelegatingClient() { diff --git a/yt/yt/client/api/delegating_client.h b/yt/yt/client/api/delegating_client.h index f04c2108426d..81ddbc5f5b76 100644 --- a/yt/yt/client/api/delegating_client.h +++ b/yt/yt/client/api/delegating_client.h @@ -256,6 +256,11 @@ class TDelegatingClient const TTransactionAttachOptions& options), (transactionId, options)) + DELEGATE_METHOD(IPrerequisitePtr, AttachPrerequisite, ( + NPrerequisiteClient::TPrerequisiteId prerequisiteId, + const TPrerequisiteAttachOptions& options), + (prerequisiteId, options)) + // Tables DELEGATE_METHOD(TFuture, MountTable, ( const NYPath::TYPath& path, diff --git a/yt/yt/client/api/delegating_transaction.cpp b/yt/yt/client/api/delegating_transaction.cpp index 437c991875ce..a5bed74db993 100644 --- a/yt/yt/client/api/delegating_transaction.cpp +++ b/yt/yt/client/api/delegating_transaction.cpp @@ -189,7 +189,7 @@ DELEGATE_METHOD(NTransactionClient::EDurability, GetDurability, () const, ()) DELEGATE_METHOD(TDuration, GetTimeout, () const, ()) DELEGATE_METHOD(TFuture, Ping, ( - const NApi::TTransactionPingOptions& options), + const NApi::TPrerequisitePingOptions& options), (options)) DELEGATE_METHOD(TFuture, Commit, ( diff --git a/yt/yt/client/api/delegating_transaction.h b/yt/yt/client/api/delegating_transaction.h index 1bf742fe7bc1..90591dd91d68 100644 --- a/yt/yt/client/api/delegating_transaction.h +++ b/yt/yt/client/api/delegating_transaction.h @@ -163,13 +163,13 @@ class TDelegatingTransaction TDuration GetTimeout() const override; TFuture Ping( - const NApi::TTransactionPingOptions& options) override; + const NApi::TPrerequisitePingOptions& options) override; TFuture Commit( - const TTransactionCommitOptions& options = TTransactionCommitOptions()) override; + const TTransactionCommitOptions& options = {}) override; TFuture Abort( - const TTransactionAbortOptions& options = TTransactionAbortOptions()) override; + const TTransactionAbortOptions& options) override; void Detach() override; TFuture Flush() override; diff --git a/yt/yt/client/api/prerequisite-inl.h b/yt/yt/client/api/prerequisite-inl.h new file mode 100644 index 000000000000..26fee62b733a --- /dev/null +++ b/yt/yt/client/api/prerequisite-inl.h @@ -0,0 +1,41 @@ +#ifndef PREREQUISITE_INL_H_ +#error "Direct inclusion of this file is not allowed, include transaction.h" +// For the sake of sane code completion. +#include "prerequisite.h" +#endif + +namespace NYT::NApi { + +//////////////////////////////////////////////////////////////////////////////// + +template +TDerived* IPrerequisite::As() +{ + auto* derived = dynamic_cast(this); + YT_VERIFY(derived); + return derived; +} + +template +TDerived* IPrerequisite::TryAs() +{ + return dynamic_cast(this); +} + +template +const TDerived* IPrerequisite::As() const +{ + const auto* derived = dynamic_cast(this); + YT_VERIFY(derived); + return derived; +} + +template +const TDerived* IPrerequisite::TryAs() const +{ + return dynamic_cast(this); +} + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NApi diff --git a/yt/yt/client/api/prerequisite.h b/yt/yt/client/api/prerequisite.h new file mode 100644 index 000000000000..229cca00f82b --- /dev/null +++ b/yt/yt/client/api/prerequisite.h @@ -0,0 +1,62 @@ +#pragma once + +#include "client_common.h" +#include "public.h" + +#include + +namespace NYT::NApi { + +//////////////////////////////////////////////////////////////////////////////// + +struct TPrerequisitePingOptions +{ + bool EnableRetries = false; +}; + +struct TPrerequisiteAbortOptions + : public TMutatingOptions +{ + bool Force = false; +}; + +//////////////////////////////////////////////////////////////////////////////// + +struct IPrerequisite + : public virtual TRefCounted +{ + using TAbortedHandlerSignature = void(const TError& error); + using TAbortedHandler = TCallback; + DECLARE_INTERFACE_SIGNAL(TAbortedHandlerSignature, Aborted); + + virtual IClientPtr GetClient() const = 0; + virtual TDuration GetTimeout() const = 0; + + virtual TFuture Ping(const TPrerequisitePingOptions& options = {}) = 0; + virtual TFuture Abort(const TPrerequisiteAbortOptions& options = {}) = 0; + + virtual void Detach() = 0; + + virtual NPrerequisiteClient::TPrerequisiteId GetId() const = 0; + + //! Verified dynamic casts to a more specific interface. + template + TDerived* As(); + template + TDerived* TryAs(); + + template + const TDerived* As() const; + template + const TDerived* TryAs() const; +}; + +DEFINE_REFCOUNTED_TYPE(IPrerequisite) + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NApi + +#define PREREQUISITE_INL_H_ +#include "prerequisite-inl.h" +#undef PREREQUISITE_INL_H_ diff --git a/yt/yt/client/api/prerequisite_client.h b/yt/yt/client/api/prerequisite_client.h new file mode 100644 index 000000000000..dfe5be31e4c8 --- /dev/null +++ b/yt/yt/client/api/prerequisite_client.h @@ -0,0 +1,30 @@ +#pragma once + +#include "public.h" + +namespace NYT::NApi { + +//////////////////////////////////////////////////////////////////////////////// + +struct TPrerequisiteAttachOptions +{ + bool AutoAbort = false; + std::optional PingPeriod; + bool Ping = true; + bool PingAncestors = false; +}; + +//////////////////////////////////////////////////////////////////////////////// + +struct IPrerequisiteClient +{ + virtual ~IPrerequisiteClient() = default; + + virtual IPrerequisitePtr AttachPrerequisite( + NPrerequisiteClient::TPrerequisiteId preqreuisiteId, + const TPrerequisiteAttachOptions& options = {}) = 0; +}; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NApi diff --git a/yt/yt/client/api/public.h b/yt/yt/client/api/public.h index 7322d6083020..7902bae0d123 100644 --- a/yt/yt/client/api/public.h +++ b/yt/yt/client/api/public.h @@ -6,6 +6,8 @@ #include +#include + #include #include @@ -138,6 +140,7 @@ DECLARE_REFCOUNTED_STRUCT(IClientBase) DECLARE_REFCOUNTED_STRUCT(IClient) DECLARE_REFCOUNTED_STRUCT(IInternalClient) DECLARE_REFCOUNTED_STRUCT(ITransaction) +DECLARE_REFCOUNTED_STRUCT(IPrerequisite) DECLARE_REFCOUNTED_STRUCT(IStickyTransactionPool) DECLARE_REFCOUNTED_STRUCT(IRowBatchReader) diff --git a/yt/yt/client/api/rpc_proxy/client_impl.cpp b/yt/yt/client/api/rpc_proxy/client_impl.cpp index 9274e82811a5..a4b77dd18328 100644 --- a/yt/yt/client/api/rpc_proxy/client_impl.cpp +++ b/yt/yt/client/api/rpc_proxy/client_impl.cpp @@ -12,6 +12,7 @@ #include #include +#include #include @@ -225,6 +226,16 @@ ITransactionPtr TClient::AttachTransaction( "Transaction attached"); } +IPrerequisitePtr TClient::AttachPrerequisite( + NPrerequisiteClient::TPrerequisiteId prerequisiteId, + const TPrerequisiteAttachOptions& options) +{ + TTransactionAttachOptions attachOptions = {}; + static_cast(attachOptions) = options; + + return AttachTransaction(prerequisiteId, attachOptions); +} + TFuture TClient::MountTable( const TYPath& path, const TMountTableOptions& options) diff --git a/yt/yt/client/api/rpc_proxy/client_impl.h b/yt/yt/client/api/rpc_proxy/client_impl.h index 151a2398621f..41c9b79c1247 100644 --- a/yt/yt/client/api/rpc_proxy/client_impl.h +++ b/yt/yt/client/api/rpc_proxy/client_impl.h @@ -32,6 +32,10 @@ class TClient NTransactionClient::TTransactionId transactionId, const NApi::TTransactionAttachOptions& options) override; + NApi::IPrerequisitePtr AttachPrerequisite( + NPrerequisiteClient::TPrerequisiteId prerequisiteId, + const NApi::TPrerequisiteAttachOptions& options) override; + // Tables. TFuture MountTable( const NYPath::TYPath& path, diff --git a/yt/yt/client/api/rpc_proxy/transaction_impl.cpp b/yt/yt/client/api/rpc_proxy/transaction_impl.cpp index cf732951ba73..164c52340493 100644 --- a/yt/yt/client/api/rpc_proxy/transaction_impl.cpp +++ b/yt/yt/client/api/rpc_proxy/transaction_impl.cpp @@ -165,7 +165,7 @@ void TTransaction::RegisterAlienTransaction(const ITransactionPtr& transaction) transaction->GetConnection()->GetLoggingTag()); } -TFuture TTransaction::Ping(const NApi::TTransactionPingOptions& /*options*/) +TFuture TTransaction::Ping(const NApi::TPrerequisitePingOptions& /*options*/) { return SendPing(); } @@ -489,7 +489,7 @@ void TTransaction::ModifyRows( .Subscribe(BIND([=, this, this_ = MakeStrong(this)] (const TError& error) { if (!error.IsOK()) { YT_LOG_DEBUG(error, "Error sending row modifications"); - YT_UNUSED_FUTURE(Abort()); + YT_UNUSED_FUTURE(ITransaction::Abort()); } })); diff --git a/yt/yt/client/api/rpc_proxy/transaction_impl.h b/yt/yt/client/api/rpc_proxy/transaction_impl.h index 300f3a9bd9b1..968e36eabe7a 100644 --- a/yt/yt/client/api/rpc_proxy/transaction_impl.h +++ b/yt/yt/client/api/rpc_proxy/transaction_impl.h @@ -61,10 +61,10 @@ class TTransaction NTransactionClient::EDurability GetDurability() const override; TDuration GetTimeout() const override; - TFuture Ping(const NApi::TTransactionPingOptions& options = {}) override; + TFuture Ping(const NApi::TPrerequisitePingOptions& options = {}) override; TFuture Flush() override; TFuture Commit(const NApi::TTransactionCommitOptions&) override; - TFuture Abort(const NApi::TTransactionAbortOptions& options = {}) override; + TFuture Abort(const NApi::TTransactionAbortOptions& options) override; void Detach() override; void RegisterAlienTransaction(const ITransactionPtr& transaction) override; diff --git a/yt/yt/client/api/transaction-inl.h b/yt/yt/client/api/transaction-inl.h deleted file mode 100644 index c2ceb5f38851..000000000000 --- a/yt/yt/client/api/transaction-inl.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef TRANSACTION_INL_H_ -#error "Direct inclusion of this file is not allowed, include transaction.h" -// For the sake of sane code completion. -#include "transaction.h" -#endif - -namespace NYT::NApi { - -//////////////////////////////////////////////////////////////////////////////// - -template -TDerivedTransaction* ITransaction::As() -{ - auto* derived = dynamic_cast(this); - YT_VERIFY(derived); - return derived; -} - -template -TDerivedTransaction* ITransaction::TryAs() -{ - return dynamic_cast(this); -} - -template -const TDerivedTransaction* ITransaction::As() const -{ - const auto* derived = dynamic_cast(this); - YT_VERIFY(derived); - return derived; -} - -template -const TDerivedTransaction* ITransaction::TryAs() const -{ - return dynamic_cast(this); -} - -//////////////////////////////////////////////////////////////////////////////// - -} // namespace NYT::NApi - diff --git a/yt/yt/client/api/transaction.cpp b/yt/yt/client/api/transaction.cpp index 6287cd793c30..214317bf7605 100644 --- a/yt/yt/client/api/transaction.cpp +++ b/yt/yt/client/api/transaction.cpp @@ -4,6 +4,16 @@ namespace NYT::NApi { //////////////////////////////////////////////////////////////////////////////// +TFuture ITransaction::Abort(const TPrerequisiteAbortOptions& options) +{ + TTransactionAbortOptions abortOptions = {}; + static_cast(abortOptions) = options; + + return Abort(abortOptions); +} + +//////////////////////////////////////////////////////////////////////////////// + TFuture StartAlienTransaction( const ITransactionPtr& localTransaction, const IClientPtr& alienClient, diff --git a/yt/yt/client/api/transaction.h b/yt/yt/client/api/transaction.h index dac7f87be89b..5a20f09c2401 100644 --- a/yt/yt/client/api/transaction.h +++ b/yt/yt/client/api/transaction.h @@ -3,6 +3,7 @@ #include "client.h" #include "dynamic_table_transaction.h" #include "queue_transaction.h" +#include "prerequisite.h" #include #include @@ -70,11 +71,6 @@ struct TTransactionCommitOptions bool StronglyOrdered = false; }; -struct TTransactionPingOptions -{ - bool EnableRetries = false; -}; - struct TTransactionCommitResult { //! NullTimestamp for all cases when CommitTimestamps are empty. @@ -87,12 +83,9 @@ struct TTransactionCommitResult }; struct TTransactionAbortOptions - : public TMutatingOptions - , public TPrerequisiteOptions + : public TPrerequisiteAbortOptions , public TTransactionalOptions -{ - bool Force = false; -}; +{ }; struct TTransactionFlushResult { @@ -113,43 +106,26 @@ struct TTransactionFlushResult */ struct ITransaction : public virtual IClientBase + , public virtual IPrerequisite , public virtual IDynamicTableTransaction , public virtual IQueueTransaction { - virtual IClientPtr GetClient() const = 0; + using TCommittedHandlerSignature = void(); + using TCommittedHandler = TCallback; + DECLARE_INTERFACE_SIGNAL(TCommittedHandlerSignature, Committed); + virtual NTransactionClient::ETransactionType GetType() const = 0; - virtual NTransactionClient::TTransactionId GetId() const = 0; virtual NTransactionClient::TTimestamp GetStartTimestamp() const = 0; virtual NTransactionClient::EAtomicity GetAtomicity() const = 0; virtual NTransactionClient::EDurability GetDurability() const = 0; - virtual TDuration GetTimeout() const = 0; - virtual TFuture Ping(const NApi::TTransactionPingOptions& options = {}) = 0; virtual TFuture Commit(const TTransactionCommitOptions& options = {}) = 0; - virtual TFuture Abort(const TTransactionAbortOptions& options = {}) = 0; - virtual void Detach() = 0; - virtual TFuture Flush() = 0; - virtual void RegisterAlienTransaction(const ITransactionPtr& transaction) = 0; - - using TCommittedHandlerSignature = void(); - using TCommittedHandler = TCallback; - DECLARE_INTERFACE_SIGNAL(TCommittedHandlerSignature, Committed); - using TAbortedHandlerSignature = void(const TError& error); - using TAbortedHandler = TCallback; - DECLARE_INTERFACE_SIGNAL(TAbortedHandlerSignature, Aborted); + virtual TFuture Abort(const TPrerequisiteAbortOptions& options = {}) override; + virtual TFuture Abort(const TTransactionAbortOptions& options) = 0; - // Verified dynamic casts to a more specific interface. - - template - TDerivedTransaction* As(); - template - TDerivedTransaction* TryAs(); - - template - const TDerivedTransaction* As() const; - template - const TDerivedTransaction* TryAs() const; + virtual TFuture Flush() = 0; + virtual void RegisterAlienTransaction(const ITransactionPtr& transaction) = 0; }; DEFINE_REFCOUNTED_TYPE(ITransaction) @@ -182,7 +158,3 @@ TFuture StartAlienTransaction( //////////////////////////////////////////////////////////////////////////////// } // namespace NYT::NApi - -#define TRANSACTION_INL_H_ -#include "transaction-inl.h" -#undef TRANSACTION_INL_H_ diff --git a/yt/yt/client/api/transaction_client.h b/yt/yt/client/api/transaction_client.h index 626d4eae38ab..b1954e79242d 100644 --- a/yt/yt/client/api/transaction_client.h +++ b/yt/yt/client/api/transaction_client.h @@ -1,6 +1,7 @@ #pragma once #include "client_common.h" +#include "prerequisite_client.h" #include @@ -63,12 +64,8 @@ struct TTransactionStartOptions }; struct TTransactionAttachOptions + : public TPrerequisiteAttachOptions { - bool AutoAbort = false; - std::optional PingPeriod; - bool Ping = true; - bool PingAncestors = false; - //! If non-empty, assumes that the transaction is sticky and specifies address of the transaction manager. //! Throws if the transaction is not sticky actually. //! Only supported by RPC proxy client for now. Ignored by other clients. diff --git a/yt/yt/client/federated/client.cpp b/yt/yt/client/federated/client.cpp index 2a07474aaad0..1037d2ee96be 100644 --- a/yt/yt/client/federated/client.cpp +++ b/yt/yt/client/federated/client.cpp @@ -116,11 +116,11 @@ class TTransaction TFuture Flush() override; - TFuture Ping(const NApi::TTransactionPingOptions& options = {}) override; + TFuture Ping(const TPrerequisitePingOptions& options = {}) override; TFuture Commit(const TTransactionCommitOptions& options = TTransactionCommitOptions()) override; - TFuture Abort(const TTransactionAbortOptions& options = TTransactionAbortOptions()) override; + TFuture Abort(const TTransactionAbortOptions& options = {}) override; TFuture VersionedLookupRows( const NYPath::TYPath&, NTableClient::TNameTablePtr, @@ -238,6 +238,7 @@ class TTransaction UNIMPLEMENTED_METHOD(IJournalWriterPtr, CreateJournalWriter, (const NYPath::TYPath&, const TJournalWriterOptions&)); UNIMPLEMENTED_METHOD(TFuture, StartDistributedWriteSession, (const NYPath::TRichYPath&, const TDistributedWriteSessionStartOptions&)); UNIMPLEMENTED_METHOD(TFuture, FinishDistributedWriteSession, (const TDistributedWriteSessionWithResults&, const TDistributedWriteSessionFinishOptions&)); + UNIMPLEMENTED_METHOD(TFuture, Abort, (const TPrerequisiteAbortOptions&)); private: const TClientPtr Client_; @@ -336,6 +337,8 @@ class TClient ITransactionPtr AttachTransaction(NTransactionClient::TTransactionId, const TTransactionAttachOptions&) override; + IPrerequisitePtr AttachPrerequisite(NPrerequisiteClient::TPrerequisiteId, const TPrerequisiteAttachOptions&) override; + IConnectionPtr GetConnection() override { auto [client, _] = GetActiveClient(); @@ -552,7 +555,7 @@ TFuture TTransaction::MethodName(Y_METHOD_USED_ARGS_DECLARATION(Args TRANSACTION_METHOD_IMPL(TUnversionedLookupRowsResult, LookupRows, (const NYPath::TYPath&, NTableClient::TNameTablePtr, const TSharedRange&, const TLookupRowsOptions&)); TRANSACTION_METHOD_IMPL(TSelectRowsResult, SelectRows, (const std::string&, const TSelectRowsOptions&)); -TRANSACTION_METHOD_IMPL(void, Ping, (const NApi::TTransactionPingOptions&)); +TRANSACTION_METHOD_IMPL(void, Ping, (const NApi::TPrerequisitePingOptions&)); TRANSACTION_METHOD_IMPL(TTransactionCommitResult, Commit, (const TTransactionCommitOptions&)); TRANSACTION_METHOD_IMPL(void, Abort, (const TTransactionAbortOptions&)); TRANSACTION_METHOD_IMPL(TVersionedLookupRowsResult, VersionedLookupRows, (const NYPath::TYPath&, NTableClient::TNameTablePtr, const TSharedRange&, const TVersionedLookupRowsOptions&)); @@ -762,6 +765,21 @@ ITransactionPtr TClient::AttachTransaction( THROW_ERROR_EXCEPTION("No client is known for transaction %v", transactionId); } +IPrerequisitePtr TClient::AttachPrerequisite( + NPrerequisiteClient::TPrerequisiteId prerequisiteId, + const TPrerequisiteAttachOptions& options) +{ + TTransactionAttachOptions attachOptions = {}; + attachOptions.AutoAbort = options.AutoAbort; + attachOptions.PingPeriod = options.PingPeriod; + attachOptions.Ping = options.Ping; + attachOptions.PingAncestors = options.PingAncestors; + + static_assert(std::is_convertible_v); + + return AttachTransaction(prerequisiteId, attachOptions); +} + void TClient::HandleError(const TErrorOr& error, int clientIndex) { if (!NRpc::IsChannelFailureError(error) && !Config_->RetryAnyError) { diff --git a/yt/yt/client/hedging/hedging.cpp b/yt/yt/client/hedging/hedging.cpp index 5ea0675af6d4..13e9c5471d93 100644 --- a/yt/yt/client/hedging/hedging.cpp +++ b/yt/yt/client/hedging/hedging.cpp @@ -120,6 +120,7 @@ class THedgingClient UNSUPPORTED_METHOD(const NChaosClient::IReplicationCardCachePtr&, GetReplicationCardCache, ()); UNSUPPORTED_METHOD(const NTransactionClient::ITimestampProviderPtr&, GetTimestampProvider, ()); UNSUPPORTED_METHOD(ITransactionPtr, AttachTransaction, (NTransactionClient::TTransactionId, const TTransactionAttachOptions&)); + UNSUPPORTED_METHOD(IPrerequisitePtr, AttachPrerequisite, (NPrerequisiteClient::TPrerequisiteId, const TPrerequisiteAttachOptions&)); UNSUPPORTED_METHOD(TFuture, MountTable, (const TYPath&, const TMountTableOptions&)); UNSUPPORTED_METHOD(TFuture, UnmountTable, (const TYPath&, const TUnmountTableOptions&)); UNSUPPORTED_METHOD(TFuture, RemountTable, (const TYPath&, const TRemountTableOptions&)); diff --git a/yt/yt/client/prerequisite_client/public.h b/yt/yt/client/prerequisite_client/public.h new file mode 100644 index 000000000000..f3b5afadf9d5 --- /dev/null +++ b/yt/yt/client/prerequisite_client/public.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace NYT::NPrerequisiteClient { + +//////////////////////////////////////////////////////////////////////////////// + +using TPrerequisiteId = NObjectClient::TObjectId; + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NPrerequisiteClient diff --git a/yt/yt/client/unittests/mock/client.h b/yt/yt/client/unittests/mock/client.h index 8a5f8b7bdf72..feac7010ccfa 100644 --- a/yt/yt/client/unittests/mock/client.h +++ b/yt/yt/client/unittests/mock/client.h @@ -378,6 +378,11 @@ class TMockClient const TTransactionAttachOptions& options), (override)); + MOCK_METHOD(IPrerequisitePtr, AttachPrerequisite, ( + NPrerequisiteClient::TPrerequisiteId prerequisiteId, + const TPrerequisiteAttachOptions& options), + (override)); + MOCK_METHOD(TFuture, MountTable, ( const NYPath::TYPath& path, const TMountTableOptions& options), diff --git a/yt/yt/client/unittests/mock/transaction.h b/yt/yt/client/unittests/mock/transaction.h index 25c6dd6cd9ef..440d0ea4d0f5 100644 --- a/yt/yt/client/unittests/mock/transaction.h +++ b/yt/yt/client/unittests/mock/transaction.h @@ -197,7 +197,7 @@ class TMockTransaction return Timeout; } - MOCK_METHOD(TFuture, Ping, (const NApi::TTransactionPingOptions& options), (override)); + MOCK_METHOD(TFuture, Ping, (const NApi::TPrerequisitePingOptions& options), (override)); MOCK_METHOD(TFuture, Commit, (const TTransactionCommitOptions& options), (override)); MOCK_METHOD(TFuture, Abort, (const TTransactionAbortOptions& options), (override)); MOCK_METHOD(void, Detach, (), (override)); From 13546a439546eb51e2f77320b8a9321c2186912a Mon Sep 17 00:00:00 2001 From: YDBot Date: Wed, 9 Apr 2025 13:21:06 +0200 Subject: [PATCH 090/454] Update muted_ya.txt in main (#16979) --- .github/config/muted_ya.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/config/muted_ya.txt b/.github/config/muted_ya.txt index 37b34790c5be..cfcfb579ad55 100644 --- a/.github/config/muted_ya.txt +++ b/.github/config/muted_ya.txt @@ -49,6 +49,7 @@ ydb/core/kqp/ut/tx KqpSnapshotIsolation.TSimpleOltp ydb/core/kqp/ut/tx KqpSnapshotIsolation.TSimpleOltpNoSink ydb/core/kqp/ut/yql KqpScripting.StreamExecuteYqlScriptScanOperationTmeoutBruteForce ydb/core/mind/hive/ut TStorageBalanceTest.TestScenario2 +ydb/core/persqueue/ut/ut_with_sdk TopicAutoscaling.PartitionSplit_DistributedTxCommit_CheckOffsetCommitForDifferentCases_SplitedTopic ydb/core/quoter/ut QuoterWithKesusTest.PrefetchCoefficient ydb/core/statistics/aggregator/ut AnalyzeColumnshard.AnalyzeRebootColumnShard ydb/core/tablet_flat/ut DataCleanup.CleanupDataWithFollowers From 6e708895d0a23ad0bcbf7ba11f69e7e32fa765c0 Mon Sep 17 00:00:00 2001 From: Vitalii Gridnev Date: Wed, 9 Apr 2025 14:21:59 +0300 Subject: [PATCH 091/454] recanonize tests (for suite tests) (#16978) --- .github/config/muted_ya.txt | 7 ------- .../query_10.plan | 12 ++++++------ .../query_12.plan | 12 ++++++------ .../query_5.plan | 1 + .../query_6.plan | 1 + .../query_1.plan | 1 + .../query_15.plan | 1 + .../query_16.plan | 1 + .../query_8.plan | 1 + .../query_10.plan | 1 + .../query_120.plan | 1 + .../query_106.plan | 1 + .../query_64.plan | 1 + .../query_103.plan | 1 + .../query_104.plan | 1 + ydb/tests/functional/suite_tests/ya.make | 4 +--- 16 files changed, 25 insertions(+), 22 deletions(-) diff --git a/.github/config/muted_ya.txt b/.github/config/muted_ya.txt index cfcfb579ad55..507d74738cf4 100644 --- a/.github/config/muted_ya.txt +++ b/.github/config/muted_ya.txt @@ -99,13 +99,6 @@ ydb/tests/functional/serverless test_serverless.py.test_database_with_disk_quota ydb/tests/functional/serverless test_serverless.py.test_database_with_disk_quotas[enable_alter_database_create_hive_first--true] ydb/tests/functional/suite_tests [test_sql_logic.py */*] chunk chunk ydb/tests/functional/suite_tests test_postgres.py.TestPGSQL.test_sql_suite[plan-jointest/join2.test] -ydb/tests/functional/suite_tests test_postgres.py.TestPGSQL.test_sql_suite[plan-select.test] -ydb/tests/functional/suite_tests test_sql_logic.py.TestSQLLogic.test_sql_suite[plan-select1-1.test] -ydb/tests/functional/suite_tests test_sql_logic.py.TestSQLLogic.test_sql_suite[plan-select2-1.test] -ydb/tests/functional/suite_tests test_sql_logic.py.TestSQLLogic.test_sql_suite[plan-select2-3.test] -ydb/tests/functional/suite_tests test_sql_logic.py.TestSQLLogic.test_sql_suite[plan-select2-4.test] -ydb/tests/functional/suite_tests test_sql_logic.py.TestSQLLogic.test_sql_suite[plan-select3-9.test] -ydb/tests/functional/suite_tests test_sql_logic.py.TestSQLLogic.test_sql_suite[results-select3-13.test] ydb/tests/functional/tenants test_dynamic_tenants.py.test_create_and_drop_the_same_tenant2[enable_alter_database_create_hive_first--false] ydb/tests/functional/tenants test_dynamic_tenants.py.test_create_and_drop_the_same_tenant2[enable_alter_database_create_hive_first--true] ydb/tests/functional/tenants test_tenants.py.TestTenants.test_create_drop_create_table3[enable_alter_database_create_hive_first--false] diff --git a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_10.plan b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_10.plan index 73f5a6645109..be35e47069e5 100644 --- a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_10.plan +++ b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_10.plan @@ -89,7 +89,7 @@ "PlanNodeType": "Connection", "Plans": [ { - "CTE Name": "precompute_0_1", + "CTE Name": "precompute_0_0", "Node Type": "LeftJoin (MapJoin)-ConstantExpr", "Operators": [ { @@ -107,7 +107,7 @@ { "Inputs": [], "Name": "ToFlow", - "ToFlow": "precompute_0_1" + "ToFlow": "precompute_0_0" } ], "PlanNodeId": 18, @@ -158,7 +158,7 @@ "PlanNodeType": "Connection", "Plans": [ { - "CTE Name": "precompute_0_1", + "CTE Name": "precompute_0_0", "Node Type": "ConstantExpr-Aggregate", "Operators": [ { @@ -171,7 +171,7 @@ "Name": "Iterator" }, { - "Input": "precompute_0_1", + "Input": "precompute_0_0", "Inputs": [], "Name": "PartitionByKey" } @@ -199,13 +199,13 @@ "PlanNodeType": "Connection", "Plans": [ { - "CTE Name": "precompute_0_0", + "CTE Name": "precompute_0_1", "Node Type": "ConstantExpr", "Operators": [ { "Inputs": [], "Name": "ToFlow", - "ToFlow": "precompute_0_0" + "ToFlow": "precompute_0_1" } ], "PlanNodeId": 10 diff --git a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_12.plan b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_12.plan index 24a2184a37cd..91b1dcee38b1 100644 --- a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_12.plan +++ b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_12.plan @@ -98,7 +98,7 @@ "PlanNodeType": "Connection", "Plans": [ { - "CTE Name": "precompute_0_0", + "CTE Name": "precompute_0_1", "Node Type": "LeftJoin (MapJoin)-ConstantExpr", "Operators": [ { @@ -116,7 +116,7 @@ { "Inputs": [], "Name": "ToFlow", - "ToFlow": "precompute_0_0" + "ToFlow": "precompute_0_1" } ], "PlanNodeId": 18, @@ -167,7 +167,7 @@ "PlanNodeType": "Connection", "Plans": [ { - "CTE Name": "precompute_0_0", + "CTE Name": "precompute_0_1", "Node Type": "ConstantExpr-Aggregate", "Operators": [ { @@ -180,7 +180,7 @@ "Name": "Iterator" }, { - "Input": "precompute_0_0", + "Input": "precompute_0_1", "Inputs": [], "Name": "PartitionByKey" } @@ -208,13 +208,13 @@ "PlanNodeType": "Connection", "Plans": [ { - "CTE Name": "precompute_0_1", + "CTE Name": "precompute_0_0", "Node Type": "ConstantExpr", "Operators": [ { "Inputs": [], "Name": "ToFlow", - "ToFlow": "precompute_0_1" + "ToFlow": "precompute_0_0" } ], "PlanNodeId": 10 diff --git a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_5.plan b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_5.plan index 197b3fa727c1..29ff88720dd3 100644 --- a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_5.plan +++ b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_5.plan @@ -60,6 +60,7 @@ "x2 (-\u221e, +\u221e)" ], "ReadRangesPointPrefixLen": "0", + "Reverse": false, "Scan": "Sequential", "Table": "postgres_jointest/join2.test_plan/x" } diff --git a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_6.plan b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_6.plan index 60531a052ae9..76a9522811cf 100644 --- a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_6.plan +++ b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-jointest_join2.test_/query_6.plan @@ -60,6 +60,7 @@ "y2 (-\u221e, +\u221e)" ], "ReadRangesPointPrefixLen": "0", + "Reverse": false, "Scan": "Sequential", "Table": "postgres_jointest/join2.test_plan/y" } diff --git a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_1.plan b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_1.plan index c5260d831fa6..1a37c1967e32 100644 --- a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_1.plan +++ b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_1.plan @@ -73,6 +73,7 @@ "unique1 (null, 10)", "unique2 (-\u221e, +\u221e)" ], + "Reverse": false, "Scan": "Sequential", "Table": "postgres_select.test_plan/onek" } diff --git a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_15.plan b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_15.plan index f04c6856dfd8..a07652e370a9 100644 --- a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_15.plan +++ b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_15.plan @@ -58,6 +58,7 @@ "f1 (-\u221e, +\u221e)" ], "ReadRangesPointPrefixLen": "0", + "Reverse": false, "Scan": "Sequential", "Table": "postgres_select.test_plan/foo" } diff --git a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_16.plan b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_16.plan index f04c6856dfd8..a07652e370a9 100644 --- a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_16.plan +++ b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_16.plan @@ -58,6 +58,7 @@ "f1 (-\u221e, +\u221e)" ], "ReadRangesPointPrefixLen": "0", + "Reverse": false, "Scan": "Sequential", "Table": "postgres_select.test_plan/foo" } diff --git a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_8.plan b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_8.plan index 58620b238902..9d9b73e6a82c 100644 --- a/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_8.plan +++ b/ydb/tests/functional/suite_tests/canondata/test_postgres.TestPGSQL.test_sql_suite_plan-select.test_/query_8.plan @@ -74,6 +74,7 @@ "unique2 (-\u221e, +\u221e)" ], "ReadRangesPointPrefixLen": "0", + "Reverse": false, "Scan": "Sequential", "Table": "postgres_select.test_plan/onek2" } diff --git a/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select1-1.test_/query_10.plan b/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select1-1.test_/query_10.plan index 3e868ee90fc1..586f9216d9ef 100644 --- a/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select1-1.test_/query_10.plan +++ b/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select1-1.test_/query_10.plan @@ -63,6 +63,7 @@ "e (-\u221e, +\u221e)" ], "ReadRangesPointPrefixLen": "0", + "Reverse": false, "Scan": "Sequential", "Table": "sqllogictest_select1-1.test_plan/t1" } diff --git a/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select2-1.test_/query_120.plan b/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select2-1.test_/query_120.plan index b534e9760521..1639f0e3e681 100644 --- a/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select2-1.test_/query_120.plan +++ b/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select2-1.test_/query_120.plan @@ -62,6 +62,7 @@ "e (-\u221e, +\u221e)" ], "ReadRangesPointPrefixLen": "0", + "Reverse": false, "Scan": "Sequential", "Table": "sqllogictest_select2-1.test_plan/t1" } diff --git a/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select2-3.test_/query_106.plan b/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select2-3.test_/query_106.plan index 74424bc2b5dd..8f132b381434 100644 --- a/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select2-3.test_/query_106.plan +++ b/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select2-3.test_/query_106.plan @@ -62,6 +62,7 @@ "e (-\u221e, +\u221e)" ], "ReadRangesPointPrefixLen": "0", + "Reverse": false, "Scan": "Sequential", "Table": "sqllogictest_select2-3.test_plan/t1" } diff --git a/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select2-4.test_/query_64.plan b/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select2-4.test_/query_64.plan index 49df9c2abb1f..04a8e6c32a41 100644 --- a/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select2-4.test_/query_64.plan +++ b/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select2-4.test_/query_64.plan @@ -62,6 +62,7 @@ "e (-\u221e, +\u221e)" ], "ReadRangesPointPrefixLen": "0", + "Reverse": false, "Scan": "Sequential", "Table": "sqllogictest_select2-4.test_plan/t1" } diff --git a/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select3-9.test_/query_103.plan b/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select3-9.test_/query_103.plan index 4d74869c3354..f0c4952f5486 100644 --- a/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select3-9.test_/query_103.plan +++ b/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select3-9.test_/query_103.plan @@ -62,6 +62,7 @@ "e (-\u221e, +\u221e)" ], "ReadRangesPointPrefixLen": "0", + "Reverse": false, "Scan": "Sequential", "Table": "sqllogictest_select3-9.test_plan/t1" } diff --git a/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select3-9.test_/query_104.plan b/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select3-9.test_/query_104.plan index 4d74869c3354..f0c4952f5486 100644 --- a/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select3-9.test_/query_104.plan +++ b/ydb/tests/functional/suite_tests/canondata/test_sql_logic.TestSQLLogic.test_sql_suite_plan-select3-9.test_/query_104.plan @@ -62,6 +62,7 @@ "e (-\u221e, +\u221e)" ], "ReadRangesPointPrefixLen": "0", + "Reverse": false, "Scan": "Sequential", "Table": "sqllogictest_select3-9.test_plan/t1" } diff --git a/ydb/tests/functional/suite_tests/ya.make b/ydb/tests/functional/suite_tests/ya.make index 7e84f03aa0ef..f08e64caad04 100644 --- a/ydb/tests/functional/suite_tests/ya.make +++ b/ydb/tests/functional/suite_tests/ya.make @@ -10,9 +10,7 @@ IF (NOT SANITIZER_TYPE AND NOT WITH_VALGRIND) test_stream_query.py ) - SIZE(LARGE) - TAG(ya:fat) - + SIZE(MEDIUM) DEPENDS( ydb/apps/ydbd From 4b9da76fa4a866eaf2285e14c9d8136edfad9604 Mon Sep 17 00:00:00 2001 From: Ilia Shakhov Date: Wed, 9 Apr 2025 14:32:53 +0300 Subject: [PATCH 092/454] Fix database restore failure when there are two database admins (#16958) --- ydb/apps/ydb/CHANGELOG.md | 1 + ydb/public/lib/ydb_cli/dump/restore_impl.cpp | 5 +- .../functional/ydb_cli/test_ydb_backup.py | 216 ++++++++++++++++-- 3 files changed, 208 insertions(+), 14 deletions(-) diff --git a/ydb/apps/ydb/CHANGELOG.md b/ydb/apps/ydb/CHANGELOG.md index 823efa412a7c..637e78e4e2b5 100644 --- a/ydb/apps/ydb/CHANGELOG.md +++ b/ydb/apps/ydb/CHANGELOG.md @@ -6,6 +6,7 @@ * Support coordination nodes in `ydb scheme rmdir --recursive`. * Fixed return code of command `ydb workload * run --check-canonical` for the case when benchmark query results differ from canonical ones. * Fixed scheme error in `ydb admin cluster dump` when specifying a domain database. +* Fixed unauthorized error in `ydb admin database restore` when multiple database admins are in dump. ## 2.20.0 ## diff --git a/ydb/public/lib/ydb_cli/dump/restore_impl.cpp b/ydb/public/lib/ydb_cli/dump/restore_impl.cpp index 1f0bf2e66a33..8cff8f934e19 100644 --- a/ydb/public/lib/ydb_cli/dump/restore_impl.cpp +++ b/ydb/public/lib/ydb_cli/dump/restore_impl.cpp @@ -635,7 +635,10 @@ TRestoreResult TRestoreClient::RestoreUsers(TTableClient& client, const TFsPath& auto alterStatementResult = client.RetryOperationSync([&](TSession session) { return session.ExecuteSchemeQuery(alterStatement).ExtractValueSync(); }); - if (!alterStatementResult.IsSuccess()) { + if (alterStatementResult.GetStatus() == EStatus::UNAUTHORIZED) { + LOG_W("Not enough rights to restore user from statement " << alterStatement.Quote() << ", skipping"); + continue; + } else if (!alterStatementResult.IsSuccess()) { LOG_E("Failed to execute statement for restoring user: " << alterStatement.Quote() << ", error: " << alterStatementResult.GetIssues().ToOneLineString()); diff --git a/ydb/tests/functional/ydb_cli/test_ydb_backup.py b/ydb/tests/functional/ydb_cli/test_ydb_backup.py index 4561f78b7557..704f6aedfc19 100644 --- a/ydb/tests/functional/ydb_cli/test_ydb_backup.py +++ b/ydb/tests/functional/ydb_cli/test_ydb_backup.py @@ -1306,6 +1306,8 @@ def setup_class(cls): "enable_database_admin" ], domain_login_only=False, + enforce_user_token_requirement=True, + default_clusteradmin="root@builtin", )) cls.cluster.start() @@ -1317,15 +1319,17 @@ def setup_class(cls): storage_pool_units_count={ 'hdd': 1 }, - timeout_seconds=100 + timeout_seconds=100, + token=cls.cluster.config.default_clusteradmin ) cls.database_nodes = cls.cluster.register_and_start_slots(cls.database, count=3) - cls.cluster.wait_tenant_up(cls.database) + cls.cluster.wait_tenant_up(cls.database, cls.cluster.config.default_clusteradmin) driver_config = ydb.DriverConfig( database=cls.database, - endpoint="%s:%s" % (cls.cluster.nodes[1].host, cls.cluster.nodes[1].port)) + endpoint="%s:%s" % (cls.cluster.nodes[1].host, cls.cluster.nodes[1].port), + credentials=ydb.AuthTokenCredentials(cls.cluster.config.default_clusteradmin)) cls.driver = ydb.Driver(driver_config) cls.driver.wait(timeout=4) @@ -1340,8 +1344,8 @@ def set_test_name(cls, request): cls.test_name = request.node.name @classmethod - def create_backup(cls, command, expected_files, additional_args=[]): - backup_files_dir = output_path(cls.test_name, "backup_files_dir") + def create_backup(cls, command, expected_files, output, additional_args=[], token=""): + backup_files_dir = output_path(cls.test_name, output) execution = yatest.common.execute( [ backup_bin(), @@ -1350,7 +1354,8 @@ def create_backup(cls, command, expected_files, additional_args=[]): ] + command + ["--output", backup_files_dir] - + additional_args + + additional_args, + env={"YDB_TOKEN": token} ) list_result = fs_recursive_list(backup_files_dir, ListMode.FILES) @@ -1370,32 +1375,59 @@ def create_backup(cls, command, expected_files, additional_args=[]): ) @classmethod - def create_cluster_backup(cls, expected_files, additional_args=[]): + def create_cluster_backup(cls, expected_files, output="backup_files_dir", additional_args=[]): cls.create_backup( [ "--database", cls.root_dir, "admin", "cluster", "dump", ], expected_files, - additional_args + output, + additional_args, + token=cls.cluster.config.default_clusteradmin, ) @classmethod - def create_database_backup(cls, expected_files, additional_args=[]): + def create_database_backup(cls, expected_files, output="backup_files_dir", additional_args=[]): cls.create_backup( [ "--database", cls.database, + "--user", "dbadmin1", "--no-password", "admin", "database", "dump", ], expected_files, + output, additional_args ) + @classmethod + def setup_sample_data(cls): + pool = ydb.SessionPool(cls.driver) + with pool.checkout() as session: + session.execute_scheme("CREATE GROUP people") + session.execute_scheme("CREATE USER alice PASSWORD '1234'") + session.execute_scheme("CREATE USER bob PASSWORD '1234'") + session.execute_scheme("ALTER GROUP people ADD USER alice") + session.execute_scheme("ALTER GROUP people ADD USER bob") + + session.execute_scheme("CREATE GROUP dbadmins") + session.execute_scheme("CREATE USER dbadmin1") + session.execute_scheme("CREATE USER dbadmin2 PASSWORD '1234'") + session.execute_scheme("ALTER GROUP dbadmins ADD USER dbadmin1") + session.execute_scheme("ALTER GROUP dbadmins ADD USER dbadmin2") + session.execute_scheme(f'GRANT "ydb.generic.use" on `{cls.database}` TO dbadmins') + + cls.driver.scheme_client.modify_permissions( + cls.database, + ydb.ModifyPermissionsSettings().change_owner("dbadmins") + ) + + create_table_with_data(cls.driver.table_client.session().create(), "db1/table") + class TestClusterBackup(BaseTestClusterBackupInFiles): def test_cluster_backup(self): - session = self.driver.table_client.session().create() - create_table_with_data(session, "db1/table") + self.setup_sample_data() self.create_cluster_backup(expected_files=[ # cluster metadata @@ -1415,8 +1447,7 @@ def test_cluster_backup(self): class TestDatabaseBackup(BaseTestClusterBackupInFiles): def test_database_backup(self): - session = self.driver.table_client.session().create() - create_table_with_data(session, "db1/table") + self.setup_sample_data() self.create_database_backup(expected_files=[ # database metadata @@ -1431,3 +1462,162 @@ def test_database_backup(self): "table/permissions.pb", "table/data_00.csv", ]) + + +class BaseTestMultipleClusterBackupInFiles(BaseTestClusterBackupInFiles): + @classmethod + def setup_class(cls): + super().setup_class() + + cfg = KikimrConfigGenerator( + extra_feature_flags=[ + "enable_strict_acl_check", + "enable_strict_user_management", + "enable_database_admin" + ], + domain_name="Root2", + domain_login_only=False, + enforce_user_token_requirement=True, + default_clusteradmin="root@builtin", + ) + + cls.restore_cluster = KiKiMR( + cfg, + cluster_name="restore_cluster" + ) + + cls.restore_cluster.start() + + cls.restore_root_dir = "/Root2" + cls.restore_database = os.path.join(cls.restore_root_dir, "db1") + cls.restore_database_nodes = cls.restore_cluster.register_and_start_slots( + cls.restore_database, + count=1 + ) + + restore_driver_config = ydb.DriverConfig( + database=cls.restore_database, + endpoint="%s:%s" % ( + cls.restore_cluster.nodes[1].host, + cls.restore_cluster.nodes[1].port + ), + credentials=ydb.AuthTokenCredentials(cls.cluster.config.default_clusteradmin), + ) + cls.restore_driver = ydb.Driver(restore_driver_config) + + @classmethod + def teardown_class(cls): + cls.restore_cluster.unregister_and_stop_slots(cls.restore_database_nodes) + cls.restore_cluster.stop() + super().teardown_class() + + @classmethod + def restore(cls, command, input, additional_args=[], token=""): + backup_files_dir = os.path.join( + yatest.common.output_path(), + cls.test_name, + input + ) + + yatest.common.execute( + [ + backup_bin(), + "--verbose", + "--assume-yes", + "--endpoint", f"grpc://localhost:{cls.restore_cluster.nodes[1].grpc_port}", + ] + + command + + ["--input", backup_files_dir, "-w", "60s"] + + additional_args, + env={"YDB_TOKEN": token} + ) + + @classmethod + def restore_cluster_backup(cls, input="backup_files_dir", additional_args=[]): + cls.restore( + [ + "--database", cls.restore_root_dir, + "admin", "cluster", "restore" + ], + input, + additional_args, + token=cls.restore_cluster.config.default_clusteradmin, + ) + + @classmethod + def restore_database_backup(cls, input="backup_files_dir", additional_args=[]): + cls.restore( + [ + "--database", cls.restore_database, + "--user", "dbadmin1", "--no-password", + "admin", "database", "restore" + ], + input, + additional_args + ) + + +class TestClusterBackupRestore(BaseTestMultipleClusterBackupInFiles): + def test_cluster_backup_restore(self): + self.setup_sample_data() + + self.create_cluster_backup(expected_files=[ + # cluster metadata + "permissions.pb", + "create_user.sql", + "create_group.sql", + "alter_group.sql", + + # database metadata + "Root/db1/database.pb", + "Root/db1/permissions.pb", + "Root/db1/create_user.sql", + "Root/db1/create_group.sql", + "Root/db1/alter_group.sql", + ]) + + self.restore_cluster_backup() + + self.restore_cluster.wait_tenant_up(self.restore_database, self.cluster.config.default_clusteradmin) + self.restore_driver.wait(timeout=10) + + +class TestDatabaseBackupRestore(BaseTestMultipleClusterBackupInFiles): + def test_database_backup_restore(self): + self.setup_sample_data() + + self.create_cluster_backup(output="cluster_backup", expected_files=[ + # cluster metadata + "permissions.pb", + "create_user.sql", + "create_group.sql", + "alter_group.sql", + + # database metadata + "Root/db1/database.pb", + "Root/db1/permissions.pb", + "Root/db1/create_user.sql", + "Root/db1/create_group.sql", + "Root/db1/alter_group.sql", + ]) + + self.create_database_backup(output="database_backup", expected_files=[ + # database metadata + "database.pb", + "permissions.pb", + "create_user.sql", + "create_group.sql", + "alter_group.sql", + + # database table + "table/scheme.pb", + "table/permissions.pb", + "table/data_00.csv", + ]) + + self.restore_cluster_backup(input="cluster_backup") + + self.restore_cluster.wait_tenant_up(self.restore_database, self.cluster.config.default_clusteradmin) + self.restore_driver.wait(timeout=10) + + self.restore_database_backup(input="database_backup") From 13ca27d3cd2639beb3fd541fe64b07c9dd8193b7 Mon Sep 17 00:00:00 2001 From: Bulat Date: Wed, 9 Apr 2025 14:42:36 +0300 Subject: [PATCH 093/454] Retuned Value and Params tests to ydb-cpp-sdk CI (#16960) --- ydb/public/sdk/cpp/src/library/retry/retry.h | 4 +- .../base64/base64_decode_uneven_ut.cpp | 2 +- .../library/string_utils/base64/base64_ut.cpp | 6 +- .../tests/unit/client/params/params_ut.cpp | 405 ++- .../sdk/cpp/tests/unit/client/params/ya.make | 3 +- .../cpp/tests/unit/client/value/value_ut.cpp | 2328 +++++++++-------- .../sdk/cpp/tests/unit/client/value/ya.make | 4 +- 7 files changed, 1419 insertions(+), 1333 deletions(-) diff --git a/ydb/public/sdk/cpp/src/library/retry/retry.h b/ydb/public/sdk/cpp/src/library/retry/retry.h index a4fe97c70c51..24b0440a1d1a 100644 --- a/ydb/public/sdk/cpp/src/library/retry/retry.h +++ b/ydb/public/sdk/cpp/src/library/retry/retry.h @@ -1,9 +1,9 @@ #pragma once -#include +#include #include "utils.h" -#include +#include #include #include diff --git a/ydb/public/sdk/cpp/src/library/string_utils/base64/base64_decode_uneven_ut.cpp b/ydb/public/sdk/cpp/src/library/string_utils/base64/base64_decode_uneven_ut.cpp index 9e1585738ae3..0c9e453008f9 100644 --- a/ydb/public/sdk/cpp/src/library/string_utils/base64/base64_decode_uneven_ut.cpp +++ b/ydb/public/sdk/cpp/src/library/string_utils/base64/base64_decode_uneven_ut.cpp @@ -1,6 +1,6 @@ #include -#include +#include Y_UNIT_TEST_SUITE(TBase64DecodeUneven) { Y_UNIT_TEST(Base64DecodeUneven) { diff --git a/ydb/public/sdk/cpp/src/library/string_utils/base64/base64_ut.cpp b/ydb/public/sdk/cpp/src/library/string_utils/base64/base64_ut.cpp index e3d5961f62c1..811066918a82 100644 --- a/ydb/public/sdk/cpp/src/library/string_utils/base64/base64_ut.cpp +++ b/ydb/public/sdk/cpp/src/library/string_utils/base64/base64_ut.cpp @@ -10,9 +10,9 @@ #include -#include -#include -#include +#include +#include +#include #include diff --git a/ydb/public/sdk/cpp/tests/unit/client/params/params_ut.cpp b/ydb/public/sdk/cpp/tests/unit/client/params/params_ut.cpp index 4e48dda53243..aaf54275285a 100644 --- a/ydb/public/sdk/cpp/tests/unit/client/params/params_ut.cpp +++ b/ydb/public/sdk/cpp/tests/unit/client/params/params_ut.cpp @@ -1,244 +1,241 @@ +#include #include - -#include - -#include -#include +#include +#include using namespace NYdb; using TExpectedErrorException = yexception; -Y_UNIT_TEST_SUITE(ParamsBuilder) { - Y_UNIT_TEST(Build) { - auto params = TParamsBuilder() - .AddParam("$param1") - .BeginList() - .AddListItem() - .BeginOptional() - .Uint64(10) - .EndOptional() - .AddListItem() - .EmptyOptional() - .EndList() - .Build() - .AddParam("$param2") - .String("test") - .Build() - .Build(); - - UNIT_ASSERT_NO_DIFF(FormatType(params.GetValue("$param1")->GetType()), - R"(List)"); - UNIT_ASSERT_NO_DIFF(FormatValueYson(*params.GetValue("$param1")), - R"([[10u];#])"); - - UNIT_ASSERT_NO_DIFF(FormatType(params.GetValue("$param2")->GetType()), - R"(String)"); - UNIT_ASSERT_NO_DIFF(FormatValueYson(*params.GetValue("$param2")), - R"("test")"); - } +void CheckProtoValue(const Ydb::Value& value, const TString& expected) { + TStringType protoStr; + google::protobuf::TextFormat::PrintToString(value, &protoStr); + ASSERT_EQ(protoStr, expected); +} - Y_UNIT_TEST(BuildFromValue) { - auto value2 = TValueBuilder() +TEST(ParamsBuilder, Build) { + auto params = TParamsBuilder() + .AddParam("$param1") .BeginList() .AddListItem() .BeginOptional() - .BeginTuple() - .AddElement() - .Int32(-11) - .AddElement() - .String("test2") - .EndTuple() + .Uint64(10) .EndOptional() .AddListItem() .EmptyOptional() .EndList() - .Build(); - - auto params = TParamsBuilder() - .AddParam("$param1") - .Utf8("test1") - .Build() - .AddParam("$param2", value2) - .Build(); - - UNIT_ASSERT_NO_DIFF(FormatType(params.GetValue("$param1")->GetType()), - R"(Utf8)"); - UNIT_ASSERT_NO_DIFF(FormatValueYson(*params.GetValue("$param1")), - R"("test1")"); - - UNIT_ASSERT_NO_DIFF(FormatType(params.GetValue("$param2")->GetType()), - R"(List?>)"); - UNIT_ASSERT_NO_DIFF(FormatValueYson(*params.GetValue("$param2")), - R"([[[-11;"test2"]];#])"); - } - - Y_UNIT_TEST(BuildWithTypeInfo) { - auto param1Type = TTypeBuilder() - .BeginList() - .Primitive(EPrimitiveType::String) - .EndList() - .Build(); + .Build() + .AddParam("$param2") + .String("test") + .Build() + .Build(); + + ASSERT_EQ(FormatType(params.GetValue("$param1")->GetType()), "List"); + + CheckProtoValue(params.GetValue("$param1")->GetProto(), + "items {\n" + " uint64_value: 10\n" + "}\n" + "items {\n" + " null_flag_value: NULL_VALUE\n" + "}\n"); + + ASSERT_EQ(FormatType(params.GetValue("$param2")->GetType()), "String"); + CheckProtoValue(params.GetValue("$param2")->GetProto(), "bytes_value: \"test\"\n"); +} - auto param2Type = TTypeBuilder() +TEST(ParamsBuilder, BuildFromValue) { + auto value2 = TValueBuilder() + .BeginList() + .AddListItem() .BeginOptional() - .Primitive(EPrimitiveType::Uint32) + .BeginTuple() + .AddElement() + .Int32(-11) + .AddElement() + .String("test2") + .EndTuple() .EndOptional() - .Build(); + .AddListItem() + .EmptyOptional() + .EndList() + .Build(); + + auto params = TParamsBuilder() + .AddParam("$param1") + .Utf8("test1") + .Build() + .AddParam("$param2", value2) + .Build(); + + ASSERT_EQ(FormatType(params.GetValue("$param1")->GetType()), "Utf8"); + + CheckProtoValue(params.GetValue("$param1")->GetProto(), "text_value: \"test1\"\n"); + + ASSERT_EQ(FormatType(params.GetValue("$param2")->GetType()), "List?>"); + CheckProtoValue(params.GetValue("$param2")->GetProto(), + "items {\n" + " items {\n" + " int32_value: -11\n" + " }\n" + " items {\n" + " bytes_value: \"test2\"\n" + " }\n" + "}\n" + "items {\n" + " null_flag_value: NULL_VALUE\n" + "}\n"); +} - std::map paramsMap; - paramsMap.emplace("$param1", param1Type); - paramsMap.emplace("$param2", param2Type); +TEST(ParamsBuilder, BuildWithTypeInfo) { + auto param1Type = TTypeBuilder() + .BeginList() + .Primitive(EPrimitiveType::String) + .EndList() + .Build(); + + auto param2Type = TTypeBuilder() + .BeginOptional() + .Primitive(EPrimitiveType::Uint32) + .EndOptional() + .Build(); + + std::map paramsMap; + paramsMap.emplace("$param1", param1Type); + paramsMap.emplace("$param2", param2Type); + + auto value1 = TValueBuilder() + .BeginList() + .AddListItem() + .String("str1") + .AddListItem() + .String("str2") + .EndList() + .Build(); + + auto params = TParamsBuilder(paramsMap) + .AddParam("$param1", value1) + .AddParam("$param2") + .EmptyOptional() + .Build() + .Build(); + + ASSERT_EQ(FormatType(params.GetValue("$param1")->GetType()), "List"); + CheckProtoValue(params.GetValue("$param1")->GetProto(), + "items {\n" + " bytes_value: \"str1\"\n" + "}\n" + "items {\n" + " bytes_value: \"str2\"\n" + "}\n"); + + ASSERT_EQ(FormatType(params.GetValue("$param2")->GetType()), "Uint32?"); + CheckProtoValue(params.GetValue("$param2")->GetProto(), "null_flag_value: NULL_VALUE\n"); +} - auto value1 = TValueBuilder() - .BeginList() - .AddListItem() - .String("str1") - .AddListItem() - .String("str2") - .EndList() - .Build(); +TEST(ParamsBuilder, MissingParam) { + auto param1Type = TTypeBuilder() + .BeginList() + .Primitive(EPrimitiveType::String) + .EndList() + .Build(); + auto param2Type = TTypeBuilder() + .BeginOptional() + .Primitive(EPrimitiveType::Uint32) + .EndOptional() + .Build(); + + std::map paramsMap; + paramsMap.emplace("$param1", param1Type); + paramsMap.emplace("$param2", param2Type); + + ASSERT_THROW({ auto params = TParamsBuilder(paramsMap) - .AddParam("$param1", value1) - .AddParam("$param2") + .AddParam("$param3") .EmptyOptional() .Build() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatType(params.GetValue("$param1")->GetType()), - R"(List)"); - UNIT_ASSERT_NO_DIFF(FormatValueYson(*params.GetValue("$param1")), - R"(["str1";"str2"])"); +TEST(ParamsBuilder, IncompleteParam) { + auto paramsBuilder = TParamsBuilder(); - UNIT_ASSERT_NO_DIFF(FormatType(params.GetValue("$param2")->GetType()), - R"(Uint32?)"); - UNIT_ASSERT_NO_DIFF(FormatValueYson(*params.GetValue("$param2")), - R"(#)"); - } + auto& param1Builder = paramsBuilder.AddParam("$param1"); + auto& param2Builder = paramsBuilder.AddParam("$param2"); - Y_UNIT_TEST(MissingParam) { - auto param1Type = TTypeBuilder() - .BeginList() - .Primitive(EPrimitiveType::String) - .EndList() - .Build(); - - auto param2Type = TTypeBuilder() + param1Builder + .BeginList() + .AddListItem() .BeginOptional() - .Primitive(EPrimitiveType::Uint32) + .Uint64(10) .EndOptional() - .Build(); + .AddListItem() + .EmptyOptional() + .EndList() + .Build(); - std::map paramsMap; - paramsMap.emplace("$param1", param1Type); - paramsMap.emplace("$param2", param2Type); + param2Builder.String("test"); - try { - auto params = TParamsBuilder(paramsMap) - .AddParam("$param3") - .EmptyOptional() - .Build() - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } + ASSERT_THROW(paramsBuilder.Build(), TExpectedErrorException); +} - UNIT_ASSERT(false); - } +TEST(ParamsBuilder, TypeMismatch) { + auto param1Type = TTypeBuilder() + .BeginList() + .Primitive(EPrimitiveType::String) + .EndList() + .Build(); - Y_UNIT_TEST(IncompleteParam) { - auto paramsBuilder = TParamsBuilder(); + auto param2Type = TTypeBuilder() + .BeginOptional() + .Primitive(EPrimitiveType::Uint32) + .EndOptional() + .Build(); - auto& param1Builder = paramsBuilder.AddParam("$param1"); - auto& param2Builder = paramsBuilder.AddParam("$param2"); + std::map paramsMap; + paramsMap.emplace("$param1", param1Type); + paramsMap.emplace("$param2", param2Type); - param1Builder - .BeginList() - .AddListItem() - .BeginOptional() - .Uint64(10) - .EndOptional() - .AddListItem() + ASSERT_THROW({ + auto params = TParamsBuilder(paramsMap) + .AddParam("$param1") .EmptyOptional() - .EndList() - .Build(); - - param2Builder.String("test"); - - try { - paramsBuilder.Build(); - } catch (const TExpectedErrorException& e) { - return; - } - - UNIT_ASSERT(false); - } - - Y_UNIT_TEST(TypeMismatch) { - auto param1Type = TTypeBuilder() - .BeginList() - .Primitive(EPrimitiveType::String) - .EndList() - .Build(); - - auto param2Type = TTypeBuilder() - .BeginOptional() - .Primitive(EPrimitiveType::Uint32) - .EndOptional() - .Build(); - - std::map paramsMap; - paramsMap.emplace("$param1", param1Type); - paramsMap.emplace("$param2", param2Type); - - try { - auto params = TParamsBuilder(paramsMap) - .AddParam("$param1") - .EmptyOptional() - .Build() - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } - - UNIT_ASSERT(false); - } - - Y_UNIT_TEST(TypeMismatchFromValue) { - auto param1Type = TTypeBuilder() - .BeginList() - .Primitive(EPrimitiveType::String) - .EndList() - .Build(); - - auto param2Type = TTypeBuilder() - .BeginOptional() - .Primitive(EPrimitiveType::Uint32) - .EndOptional() + .Build() .Build(); + }, TExpectedErrorException); +} - std::map paramsMap; - paramsMap.emplace("$param1", param1Type); - paramsMap.emplace("$param2", param2Type); - - auto value1 = TValueBuilder() - .BeginList() - .AddListItem() - .String("str1") - .AddListItem() - .String("str2") - .EndList() +TEST(ParamsBuilder, TypeMismatchFromValue) { + auto param1Type = TTypeBuilder() + .BeginList() + .Primitive(EPrimitiveType::String) + .EndList() + .Build(); + + auto param2Type = TTypeBuilder() + .BeginOptional() + .Primitive(EPrimitiveType::Uint32) + .EndOptional() + .Build(); + + std::map paramsMap; + paramsMap.emplace("$param1", param1Type); + paramsMap.emplace("$param2", param2Type); + + auto value1 = TValueBuilder() + .BeginList() + .AddListItem() + .String("str1") + .AddListItem() + .String("str2") + .EndList() + .Build(); + + ASSERT_THROW({ + auto params = TParamsBuilder(paramsMap) + .AddParam("$param2", value1) .Build(); - - try { - auto params = TParamsBuilder(paramsMap) - .AddParam("$param2", value1) - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } - - UNIT_ASSERT(false); - } + }, TExpectedErrorException); } diff --git a/ydb/public/sdk/cpp/tests/unit/client/params/ya.make b/ydb/public/sdk/cpp/tests/unit/client/params/ya.make index fdb02c2e95c1..d115bb5eb377 100644 --- a/ydb/public/sdk/cpp/tests/unit/client/params/ya.make +++ b/ydb/public/sdk/cpp/tests/unit/client/params/ya.make @@ -1,4 +1,4 @@ -UNITTEST() +GTEST() IF (SANITIZER_TYPE == "thread") SIZE(LARGE) @@ -11,7 +11,6 @@ FORK_SUBTESTS() PEERDIR( ydb/public/sdk/cpp/src/client/params - ydb/public/lib/yson_value ) SRCS( diff --git a/ydb/public/sdk/cpp/tests/unit/client/value/value_ut.cpp b/ydb/public/sdk/cpp/tests/unit/client/value/value_ut.cpp index f69252da67ba..edc9a1de9d3d 100644 --- a/ydb/public/sdk/cpp/tests/unit/client/value/value_ut.cpp +++ b/ydb/public/sdk/cpp/tests/unit/client/value/value_ut.cpp @@ -1,700 +1,575 @@ +#include #include #include - #include #include -#include -#include - -#include -#include - #include namespace NYdb { using TExpectedErrorException = yexception; -Y_UNIT_TEST_SUITE(YdbValue) { - Y_UNIT_TEST(ParseType1) { - auto protoTypeStr = R"( - struct_type { - members { - name: "Member1" - type { - type_id: UINT32 - } +void CheckProtoValue(const Ydb::Value& value, const TString& expected) { + TStringType protoStr; + google::protobuf::TextFormat::PrintToString(value, &protoStr); + ASSERT_EQ(protoStr, expected); +} + +TEST(YdbValue, ParseType1) { + auto protoTypeStr = R"( + struct_type { + members { + name: "Member1" + type { + type_id: UINT32 } - members { - name: "Member2" - type { - list_type { - item { - type_id: STRING - } + } + members { + name: "Member2" + type { + list_type { + item { + type_id: STRING } } } - members { - name: "Member3" - type { - tuple_type { - elements { - optional_type { - item { - type_id: UTF8 - } - } - } - elements { - decimal_type { - precision: 8 - scale: 13 + } + members { + name: "Member3" + type { + tuple_type { + elements { + optional_type { + item { + type_id: UTF8 } } - elements { - void_type: NULL_VALUE + } + elements { + decimal_type { + precision: 8 + scale: 13 } } + elements { + void_type: NULL_VALUE + } } } } - )"; + } + )"; - Ydb::Type protoType; - google::protobuf::TextFormat::ParseFromString(protoTypeStr, &protoType); + Ydb::Type protoType; + google::protobuf::TextFormat::ParseFromString(protoTypeStr, &protoType); - UNIT_ASSERT_NO_DIFF(FormatType(protoType), - R"(Struct<'Member1':Uint32,'Member2':List,'Member3':Tuple>)"); - } + ASSERT_EQ(FormatType(protoType), + R"(Struct<'Member1':Uint32,'Member2':List,'Member3':Tuple>)"); +} - Y_UNIT_TEST(ParseType2) { - auto protoTypeStr = R"( - dict_type { - key { - type_id: UINT32 - } - payload { - struct_type { - members { - name: "Member1" - type { - type_id: DATE - } +TEST(YdbValue, ParseType2) { + auto protoTypeStr = R"( + dict_type { + key { + type_id: UINT32 + } + payload { + struct_type { + members { + name: "Member1" + type { + type_id: DATE } } } } - )"; + } + )"; - Ydb::Type protoType; - google::protobuf::TextFormat::ParseFromString(protoTypeStr, &protoType); + Ydb::Type protoType; + google::protobuf::TextFormat::ParseFromString(protoTypeStr, &protoType); - UNIT_ASSERT_NO_DIFF(FormatType(protoType), - R"(Dict>)"); - } + ASSERT_EQ(FormatType(protoType), + R"(Dict>)"); +} - Y_UNIT_TEST(ParseTaggedType) { - auto protoTypeStr = R"( - tagged_type { - tag: "my_tag" - type { - type_id: STRING - } +TEST(YdbValue, ParseTaggedType) { + auto protoTypeStr = R"( + tagged_type { + tag: "my_tag" + type { + type_id: STRING } - )"; + } + )"; - Ydb::Type protoType; - google::protobuf::TextFormat::ParseFromString(protoTypeStr, &protoType); + Ydb::Type protoType; + google::protobuf::TextFormat::ParseFromString(protoTypeStr, &protoType); - UNIT_ASSERT_NO_DIFF(FormatType(protoType), - R"(Tagged)"); - } + ASSERT_EQ(FormatType(protoType), + R"(Tagged)"); +} - Y_UNIT_TEST(BuildTaggedType) { - auto type = TTypeBuilder() - .BeginTagged("my_tag") - .BeginList() - .BeginOptional() - .Primitive(EPrimitiveType::Uint32) - .EndOptional() - .EndList() - .EndTagged() - .Build(); +TEST(YdbValue, BuildTaggedType) { + auto type = TTypeBuilder() + .BeginTagged("my_tag") + .BeginList() + .BeginOptional() + .Primitive(EPrimitiveType::Uint32) + .EndOptional() + .EndList() + .EndTagged() + .Build(); - UNIT_ASSERT_NO_DIFF(FormatType(type), - R"(Tagged,'my_tag'>)"); - } + ASSERT_EQ(FormatType(type), + R"(Tagged,'my_tag'>)"); +} - Y_UNIT_TEST(BuildType) { - auto type = TTypeBuilder() - .BeginStruct() - .AddMember("Member1") - .BeginList() +TEST(YdbValue, BuildType) { + auto type = TTypeBuilder() + .BeginStruct() + .AddMember("Member1") + .BeginList() + .BeginOptional() + .Primitive(EPrimitiveType::Uint32) + .EndOptional() + .EndList() + .AddMember("Member2") + .BeginDict() + .DictKey().Primitive(EPrimitiveType::Int64) + .DictPayload() + .BeginTuple() + .AddElement() + .Decimal(TDecimalType(8, 13)) + .AddElement() + .Pg(TPgType("pgint2")) + .AddElement() .BeginOptional() - .Primitive(EPrimitiveType::Uint32) + .Primitive(EPrimitiveType::Utf8) .EndOptional() - .EndList() - .AddMember("Member2") - .BeginDict() - .DictKey().Primitive(EPrimitiveType::Int64) - .DictPayload() - .BeginTuple() - .AddElement() - .Decimal(TDecimalType(8, 13)) - .AddElement() - .Pg(TPgType("pgint2")) - .AddElement() - .BeginOptional() - .Primitive(EPrimitiveType::Utf8) - .EndOptional() - .EndTuple() - .EndDict() - .EndStruct() - .Build(); - - UNIT_ASSERT_NO_DIFF(FormatType(type), - R"(Struct<'Member1':List,'Member2':Dict>>)"); - } - - Y_UNIT_TEST(BuildTypeReuse) { - auto intType = TTypeBuilder() - .Primitive(EPrimitiveType::Int32) - .Build(); - - UNIT_ASSERT_NO_DIFF(FormatType(intType), - R"(Int32)"); - - auto optIntType = TTypeBuilder() - .Optional(intType) - .Build(); - - UNIT_ASSERT_NO_DIFF(FormatType(optIntType), - R"(Int32?)"); + .EndTuple() + .EndDict() + .EndStruct() + .Build(); - auto structType = TTypeBuilder() - .BeginStruct() - .AddMember("Member1", intType) - .AddMember("Member2") - .List(optIntType) - .EndStruct() - .Build(); + ASSERT_EQ(FormatType(type), + R"(Struct<'Member1':List,'Member2':Dict>>)"); +} - UNIT_ASSERT_NO_DIFF(FormatType(structType), - R"(Struct<'Member1':Int32,'Member2':List>)"); +TEST(YdbValue, BuildTypeReuse) { + auto intType = TTypeBuilder() + .Primitive(EPrimitiveType::Int32) + .Build(); + + ASSERT_EQ(FormatType(intType), + R"(Int32)"); + + auto optIntType = TTypeBuilder() + .Optional(intType) + .Build(); + + ASSERT_EQ(FormatType(optIntType), + R"(Int32?)"); + + auto structType = TTypeBuilder() + .BeginStruct() + .AddMember("Member1", intType) + .AddMember("Member2") + .List(optIntType) + .EndStruct() + .Build(); + + ASSERT_EQ(FormatType(structType), + R"(Struct<'Member1':Int32,'Member2':List>)"); + + auto tupleType = TTypeBuilder() + .BeginTuple() + .AddElement(optIntType) + .AddElement() + .Primitive(EPrimitiveType::String) + .EndTuple() + .Build(); + + ASSERT_EQ(FormatType(tupleType), + R"(Tuple)"); + + auto type = TTypeBuilder() + .BeginDict() + .DictKey(tupleType) + .DictPayload(structType) + .EndDict() + .Build(); + + ASSERT_EQ(FormatType(type), + R"(Dict,Struct<'Member1':Int32,'Member2':List>>)"); +} - auto tupleType = TTypeBuilder() +TEST(YdbValue, BuildTypeIncomplete) { + ASSERT_THROW({ + auto value = TTypeBuilder() .BeginTuple() - .AddElement(optIntType) + .AddElement() + .Primitive(EPrimitiveType::Uint32) .AddElement() .Primitive(EPrimitiveType::String) - .EndTuple() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatType(tupleType), - R"(Tuple)"); - - auto type = TTypeBuilder() - .BeginDict() - .DictKey(tupleType) - .DictPayload(structType) - .EndDict() - .Build(); - - UNIT_ASSERT_NO_DIFF(FormatType(type), - R"(Dict,Struct<'Member1':Int32,'Member2':List>>)"); - } - - Y_UNIT_TEST(BuildTypeIncomplete) { - try { - auto value = TTypeBuilder() - .BeginTuple() - .AddElement() - .Primitive(EPrimitiveType::Uint32) - .AddElement() - .Primitive(EPrimitiveType::String) - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } - - UNIT_ASSERT(false); - } - - Y_UNIT_TEST(ParseValue1) { - auto protoTypeStr = R"( - struct_type { - members { - name: "Member1" - type { - type_id: UINT32 - } +TEST(YdbValue, ParseValue1) { + auto protoTypeStr = R"( + struct_type { + members { + name: "Member1" + type { + type_id: UINT32 } - members { - name: "Member2" - type { - list_type { - item { - type_id: STRING - } + } + members { + name: "Member2" + type { + list_type { + item { + type_id: STRING } } } - members { - name: "Member3" - type { - tuple_type { - elements { - optional_type { - item { - type_id: UTF8 - } + } + members { + name: "Member3" + type { + tuple_type { + elements { + optional_type { + item { + type_id: UTF8 } } - elements { - type_id: UTF8 - } - elements { - void_type: NULL_VALUE - } + } + elements { + type_id: UTF8 + } + elements { + void_type: NULL_VALUE } } } } - )"; + } + )"; + + auto protoValueStr = + "items {\n" + " uint32_value: 137\n" + "}\n" + "items {\n" + " items {\n" + " bytes_value: \"String1\"\n" + " }\n" + " items {\n" + " bytes_value: \"String2\"\n" + " }\n" + "}\n" + "items {\n" + " items {\n" + " null_flag_value: NULL_VALUE\n" + " }\n" + " items {\n" + " text_value: \"UtfString\"\n" + " }\n" + " items {\n" + " }\n" + "}\n"; + + Ydb::Type protoType; + google::protobuf::TextFormat::ParseFromString(protoTypeStr, &protoType); + + Ydb::Value protoValue; + google::protobuf::TextFormat::ParseFromString(protoValueStr, &protoValue); + + TValue value(TType(protoType), protoValue); + + CheckProtoValue(value.GetProto(), protoValueStr); +} - auto protoValueStr = R"( - items { - uint32_value: 137 +TEST(YdbValue, ParseValue2) { + auto protoTypeStr = R"( + dict_type { + key { + type_id: UINT32 } - items { - items { - bytes_value: "String1" - } - items { - bytes_value: "String2" - } - } - items { - items { - null_flag_value: NULL_VALUE - } - items { - text_value: "UtfString" - } - items { - } - } - )"; - - Ydb::Type protoType; - google::protobuf::TextFormat::ParseFromString(protoTypeStr, &protoType); - - Ydb::Value protoValue; - google::protobuf::TextFormat::ParseFromString(protoValueStr, &protoValue); - - TValue value(TType(protoType), protoValue); - - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([137u;["String1";"String2"];[#;"UtfString";"Void"]])"); - } - - Y_UNIT_TEST(ParseValue2) { - auto protoTypeStr = R"( - dict_type { - key { - type_id: UINT32 - } - payload { - struct_type { - members { - name: "Member1" - type { - type_id: DATE - } + payload { + struct_type { + members { + name: "Member1" + type { + type_id: DATE } } } } - )"; + } + )"; + + auto protoValueStr = + "pairs {\n" + " key {\n" + " uint32_value: 10\n" + " }\n" + " payload {\n" + " items {\n" + " uint32_value: 1000\n" + " }\n" + " }\n" + "}\n" + "pairs {\n" + " key {\n" + " uint32_value: 20\n" + " }\n" + " payload {\n" + " items {\n" + " uint32_value: 2000\n" + " }\n" + " }\n" + "}\n"; + + Ydb::Type protoType; + google::protobuf::TextFormat::ParseFromString(protoTypeStr, &protoType); + + Ydb::Value protoValue; + google::protobuf::TextFormat::ParseFromString(protoValueStr, &protoValue); + + TValue value(TType(protoType), protoValue); + + CheckProtoValue(value.GetProto(), protoValueStr); +} - auto protoValueStr = R"( - pairs { - key { - uint32_value: 10 - } - payload { - items { - uint32_value: 1000 +TEST(YdbValue, ParseValuePg) { + auto protoTypeStr = R"( + struct_type { + members { + name: "A" + type { + pg_type { + oid: 123 + typlen: 345 + typmod: -321 } } } - pairs { - key { - uint32_value: 20 - } - payload { - items { - uint32_value: 2000 + members { + name: "B" + type { + pg_type { + oid: 123 + typlen: -345 + typmod: 321 } } } - )"; - - Ydb::Type protoType; - google::protobuf::TextFormat::ParseFromString(protoTypeStr, &protoType); - - Ydb::Value protoValue; - google::protobuf::TextFormat::ParseFromString(protoValueStr, &protoValue); - - TValue value(TType(protoType), protoValue); - - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([[10u;[1000u]];[20u;[2000u]]])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([[10,{"Member1":"1972-09-27"}],[20,{"Member1":"1975-06-24"}]])"); - } - - Y_UNIT_TEST(ParseValuePg) { - auto protoTypeStr = R"( - struct_type { - members { - name: "A" - type { - pg_type { - oid: 123 - typlen: 345 - typmod: -321 - } - } - } - members { - name: "B" - type { - pg_type { - oid: 123 - typlen: -345 - typmod: 321 - } - } - } - members { - name: "C" - type { - pg_type { - oid: 123 - typlen: -345 - typmod: -321 - } + members { + name: "C" + type { + pg_type { + oid: 123 + typlen: -345 + typmod: -321 } } - members { - name: "D" - type { - pg_type { - oid: 123 - typlen: -1 - typmod: -1 - } + } + members { + name: "D" + type { + pg_type { + oid: 123 + typlen: -1 + typmod: -1 } } - members { - name: "E" - type { - pg_type { - oid: 123 - typlen: -1 - typmod: -1 - } + } + members { + name: "E" + type { + pg_type { + oid: 123 + typlen: -1 + typmod: -1 } } } - )"; - - auto protoValueStr = R"( - items { - text_value: "my_text_value" - } - items { - bytes_value: "my_binary_value" - } - items { - text_value: "" - } - items { - bytes_value: "" - } - items { - } + } )"; - Ydb::Type protoType; - google::protobuf::TextFormat::ParseFromString(protoTypeStr, &protoType); - - Ydb::Value protoValue; - google::protobuf::TextFormat::ParseFromString(protoValueStr, &protoValue); - - TValue value(TType(protoType), protoValue); - - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"(["my_text_value";["my_binary_value"];"";[""];#])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"({"A":"my_text_value","B":["my_binary_value"],"C":"","D":[""],"E":null})"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Base64), - R"({"A":"my_text_value","B":["bXlfYmluYXJ5X3ZhbHVl"],"C":"","D":[""],"E":null})"); - } + auto protoValueStr = + "items {\n" + " text_value: \"my_text_value\"\n" + "}\n" + "items {\n" + " bytes_value: \"my_binary_value\"\n" + "}\n" + "items {\n" + " text_value: \"\"\n" + "}\n" + "items {\n" + " bytes_value: \"\"\n" + "}\n"; + + Ydb::Type protoType; + google::protobuf::TextFormat::ParseFromString(protoTypeStr, &protoType); + + Ydb::Value protoValue; + google::protobuf::TextFormat::ParseFromString(protoValueStr, &protoValue); + + TValue value(TType(protoType), protoValue); + + CheckProtoValue(value.GetProto(), protoValueStr); +} - Y_UNIT_TEST(ParseValueMaybe) { - auto protoTypeStr = R"( - tuple_type { - elements { - optional_type { - item { - type_id: UTF8 - } +TEST(YdbValue, ParseValueMaybe) { + auto protoTypeStr = R"( + tuple_type { + elements { + optional_type { + item { + type_id: UTF8 } } - elements { - optional_type { - item { - type_id: INT8 - } - } - } - elements { - optional_type { - item { - type_id: DOUBLE - } - } - } - elements { - optional_type { - item { - type_id: UINT64 - } + } + elements { + optional_type { + item { + type_id: INT8 } } - elements { - optional_type { - item { - type_id: DYNUMBER - } + } + elements { + optional_type { + item { + type_id: DOUBLE } } } - )"; - - auto protoValueStr = R"( - items { - text_value: "SomeUtf" - } - items { - int32_value: -5 - } - items { - null_flag_value: NULL_VALUE - } - items { - nested_value { - uint64_value: 7 + elements { + optional_type { + item { + type_id: UINT64 + } } } - items { - nested_value { - text_value: "12.345" + elements { + optional_type { + item { + type_id: DYNUMBER + } } } - )"; - - Ydb::Type protoType; - google::protobuf::TextFormat::ParseFromString(protoTypeStr, &protoType); - - Ydb::Value protoValue; - google::protobuf::TextFormat::ParseFromString(protoValueStr, &protoValue); - - TValue value(TType(protoType), protoValue); - TValueParser parser(value); - - parser.OpenTuple(); - UNIT_ASSERT(parser.TryNextElement()); - UNIT_ASSERT(parser.GetOptionalUtf8() == "SomeUtf"); - UNIT_ASSERT(parser.TryNextElement()); - UNIT_ASSERT(parser.GetOptionalInt8() == -5); - UNIT_ASSERT(parser.TryNextElement()); - UNIT_ASSERT(parser.GetOptionalDouble() == std::optional()); - UNIT_ASSERT(parser.TryNextElement()); - UNIT_ASSERT(parser.GetOptionalUint64() == (ui64)7); - UNIT_ASSERT(parser.TryNextElement()); - UNIT_ASSERT(parser.GetOptionalDyNumber() == "12.345"); - parser.CloseTuple(); - } - - Y_UNIT_TEST(BuildValueIncomplete) { - try { - auto value = TValueBuilder() - .BeginTuple() - .AddElement() - .Uint32(10) - .AddElement() - .String("test") - .Build(); - } catch (const TExpectedErrorException& e) { - return; } + )"; - UNIT_ASSERT(false); - } - - Y_UNIT_TEST(BuildValueListItemMismatch1) { - try { - auto value = TValueBuilder() - .BeginList() - .AddListItem() - .Int32(17) - .AddListItem() - .Uint32(19) - .EndList() - .Build(); - } catch (const TExpectedErrorException& e) { - return; + auto protoValueStr = R"( + items { + text_value: "SomeUtf" } - - UNIT_ASSERT(false); - } - - Y_UNIT_TEST(BuildValueListItemMismatch2) { - auto itemValue = TValueBuilder() - .String("Test") - .Build(); - - try { - auto value = TValueBuilder() - .BeginList() - .AddListItem(itemValue) - .AddListItem() - .Int32(17) - .EndList() - .Build(); - } catch (const TExpectedErrorException& e) { - return; + items { + int32_value: -5 } - - UNIT_ASSERT(false); - } - - Y_UNIT_TEST(BuildValueListItemMismatch3) { - auto itemValue = TValueBuilder() - .String("Test") - .Build(); - - try { - auto value = TValueBuilder() - .BeginList() - .AddListItem() - .Int32(17) - .AddListItem(itemValue) - .EndList() - .Build(); - } catch (const TExpectedErrorException& e) { - return; + items { + null_flag_value: NULL_VALUE } - - UNIT_ASSERT(false); - } - - Y_UNIT_TEST(BuildValueListItemMismatch4) { - try { - auto value = TValueBuilder() - .BeginList() - .AddListItem() - .BeginList() - .AddListItem() - .Uint32(10) - .EndList() - .AddListItem() - .EmptyList(TTypeBuilder().Primitive(EPrimitiveType::Uint64).Build()) - .EndList() - .Build(); - } catch (const TExpectedErrorException& e) { - return; + items { + nested_value { + uint64_value: 7 + } } - - UNIT_ASSERT(false); - } - - - Y_UNIT_TEST(BuildValueEmptyListUnknown) { - try { - auto value = TValueBuilder() - .EmptyList() - .Build(); - } catch (const TExpectedErrorException& e) { - return; + items { + nested_value { + text_value: "12.345" + } } + )"; + + Ydb::Type protoType; + google::protobuf::TextFormat::ParseFromString(protoTypeStr, &protoType); + + Ydb::Value protoValue; + google::protobuf::TextFormat::ParseFromString(protoValueStr, &protoValue); + + TValue value(TType(protoType), protoValue); + TValueParser parser(value); + + parser.OpenTuple(); + ASSERT_TRUE(parser.TryNextElement()); + ASSERT_EQ(parser.GetOptionalUtf8(), "SomeUtf"); + ASSERT_TRUE(parser.TryNextElement()); + ASSERT_EQ(parser.GetOptionalInt8(), -5); + ASSERT_TRUE(parser.TryNextElement()); + ASSERT_EQ(parser.GetOptionalDouble(), std::optional()); + ASSERT_TRUE(parser.TryNextElement()); + ASSERT_EQ(parser.GetOptionalUint64(), (ui64)7); + ASSERT_TRUE(parser.TryNextElement()); + ASSERT_EQ(parser.GetOptionalDyNumber(), "12.345"); + parser.CloseTuple(); +} - UNIT_ASSERT(false); - } - - Y_UNIT_TEST(BuildDyNumberValue) { +TEST(YdbValue, BuildValueIncomplete) { + ASSERT_THROW({ auto value = TValueBuilder() - .DyNumber("12.345") + .BeginTuple() + .AddElement() + .Uint32(10) + .AddElement() + .String("test") .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"("12.345")"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"("12.345")"); - } - - Y_UNIT_TEST(BuildTaggedValue) { +TEST(YdbValue, BuildValueListItemMismatch1) { + ASSERT_THROW({ auto value = TValueBuilder() - .BeginTagged("my_tag") - .DyNumber("12.345") - .EndTagged() + .BeginList() + .AddListItem() + .Int32(17) + .AddListItem() + .Uint32(19) + .EndList() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"("12.345")"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"("12.345")"); - } - - Y_UNIT_TEST(BuildValueList) { - auto intValue = TValueBuilder() - .Int32(21) - .Build(); +TEST(YdbValue, BuildValueListItemMismatch2) { + auto itemValue = TValueBuilder() + .String("Test") + .Build(); + ASSERT_THROW({ auto value = TValueBuilder() .BeginList() + .AddListItem(itemValue) .AddListItem() .Int32(17) - .AddListItem() - .Int32(19) - .AddListItem(intValue) .EndList() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([17;19;21])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([17,19,21])"); - } +TEST(YdbValue, BuildValueListItemMismatch3) { + auto itemValue = TValueBuilder() + .String("Test") + .Build(); - Y_UNIT_TEST(BuildValueListEmpty) { + ASSERT_THROW({ auto value = TValueBuilder() - .EmptyList(TTypeBuilder().Primitive(EPrimitiveType::Uint32).Build()) + .BeginList() + .AddListItem() + .Int32(17) + .AddListItem(itemValue) + .EndList() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatType(value.GetType()), - R"(List)"); - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([])"); - } - - Y_UNIT_TEST(BuildValueListEmpty2) { +TEST(YdbValue, BuildValueListItemMismatch4) { + ASSERT_THROW({ auto value = TValueBuilder() .BeginList() .AddListItem() @@ -703,195 +578,318 @@ Y_UNIT_TEST_SUITE(YdbValue) { .Uint32(10) .EndList() .AddListItem() - .EmptyList() + .EmptyList(TTypeBuilder().Primitive(EPrimitiveType::Uint64).Build()) + .EndList() + .Build(); + }, TExpectedErrorException); +} + +TEST(YdbValue, BuildValueEmptyListUnknown) { + ASSERT_THROW({ + auto value = TValueBuilder() + .EmptyList() + .Build(); + }, TExpectedErrorException); +} + +TEST(YdbValue, BuildDyNumberValue) { + auto value = TValueBuilder() + .DyNumber("12.345") + .Build(); + + CheckProtoValue(value.GetProto(), "text_value: \"12.345\"\n"); +} + +TEST(YdbValue, BuildTaggedValue) { + auto value = TValueBuilder() + .BeginTagged("my_tag") + .DyNumber("12.345") + .EndTagged() + .Build(); + + CheckProtoValue(value.GetProto(), "text_value: \"12.345\"\n"); +} + +TEST(YdbValue, BuildValueList) { + auto intValue = TValueBuilder() + .Int32(21) + .Build(); + + auto value = TValueBuilder() + .BeginList() + .AddListItem() + .Int32(17) + .AddListItem() + .Int32(19) + .AddListItem(intValue) + .EndList() + .Build(); + + CheckProtoValue(value.GetProto(), + "items {\n" + " int32_value: 17\n" + "}\n" + "items {\n" + " int32_value: 19\n" + "}\n" + "items {\n" + " int32_value: 21\n" + "}\n"); +} + +TEST(YdbValue, BuildValueListEmpty) { + auto value = TValueBuilder() + .EmptyList(TTypeBuilder().Primitive(EPrimitiveType::Uint32).Build()) + .Build(); + + ASSERT_EQ(FormatType(value.GetType()), + R"(List)"); + CheckProtoValue(value.GetProto(), ""); +} + +TEST(YdbValue, BuildValueListEmpty2) { + auto value = TValueBuilder() + .BeginList() + .AddListItem() + .BeginList() + .AddListItem() + .Uint32(10) + .EndList() + .AddListItem() + .EmptyList() + .EndList() + .Build(); + + CheckProtoValue(value.GetProto(), + "items {\n" + " items {\n" + " uint32_value: 10\n" + " }\n" + "}\n" + "items {\n" + "}\n"); +} + +TEST(YdbValue, BuildValueListEmpty3) { + auto value = TValueBuilder() + .BeginList() + .AddListItem() + .EmptyList(TTypeBuilder().Primitive(EPrimitiveType::Uint32).Build()) + .AddListItem() + .BeginList() + .AddListItem() + .Uint32(10) .EndList() - .Build(); - - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([[10u];[]])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([[10],[]])"); - } + .EndList() + .Build(); + + CheckProtoValue(value.GetProto(), + "items {\n" + "}\n" + "items {\n" + " items {\n" + " uint32_value: 10\n" + " }\n" + "}\n"); +} - Y_UNIT_TEST(BuildValueListEmpty3) { +TEST(YdbValue, BuildValueBadCall) { + ASSERT_THROW({ auto value = TValueBuilder() - .BeginList() - .AddListItem() - .EmptyList(TTypeBuilder().Primitive(EPrimitiveType::Uint32).Build()) .AddListItem() - .BeginList() - .AddListItem() - .Uint32(10) - .EndList() .EndList() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([[];[10u]])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([[],[10]])"); - } - - Y_UNIT_TEST(BuildValueBadCall) { - try { - auto value = TValueBuilder() - .AddListItem() - .EndList() - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } +TEST(YdbValue, BuildValueOptional) { + auto value = TValueBuilder() + .BeginList() + .AddListItem() + .OptionalInt32(1) + .AddListItem() + .EmptyOptional() + .AddListItem() + .BeginOptional() + .Int32(57) + .EndOptional() + .AddListItem() + .EmptyOptional(TTypeBuilder().Primitive(EPrimitiveType::Int32).Build()) + .EndList() + .Build(); + + ASSERT_EQ(FormatType(value.GetType()), + R"(List)"); + + auto expectedProtoValueStr = + "items {\n" + " int32_value: 1\n" + "}\n" + "items {\n" + " null_flag_value: NULL_VALUE\n" + "}\n" + "items {\n" + " int32_value: 57\n" + "}\n" + "items {\n" + " null_flag_value: NULL_VALUE\n" + "}\n"; + + CheckProtoValue(value.GetProto(), expectedProtoValueStr); +} - UNIT_ASSERT(false); - } +TEST(YdbValue, BuildValueNestedOptional) { + auto value = TValueBuilder() + .BeginTuple() + .AddElement() + .BeginOptional() + .BeginOptional() + .Int32(10) + .EndOptional() + .EndOptional() + .AddElement() + .BeginOptional() + .BeginOptional() + .BeginOptional() + .Int64(-1) + .EndOptional() + .EndOptional() + .EndOptional() + .AddElement() + .BeginOptional() + .EmptyOptional(TTypeBuilder().Primitive(EPrimitiveType::String).Build()) + .EndOptional() + .AddElement() + .BeginOptional() + .BeginOptional() + .EmptyOptional(EPrimitiveType::Utf8) + .EndOptional() + .EndOptional() + .EndTuple() + .Build(); + + ASSERT_EQ(FormatType(value.GetType()), + R"(Tuple)"); + + auto expectedProtoValueStr = + "items {\n" + " int32_value: 10\n" + "}\n" + "items {\n" + " int64_value: -1\n" + "}\n" + "items {\n" + " nested_value {\n" + " null_flag_value: NULL_VALUE\n" + " }\n" + "}\n" + "items {\n" + " nested_value {\n" + " nested_value {\n" + " null_flag_value: NULL_VALUE\n" + " }\n" + " }\n" + "}\n"; + + CheckProtoValue(value.GetProto(), expectedProtoValueStr); +} - Y_UNIT_TEST(BuildValueOptional) { +TEST(YdbValue, BuildValueOptionalMismatch1) { + ASSERT_THROW({ auto value = TValueBuilder() .BeginList() - .AddListItem() - .OptionalInt32(1) - .AddListItem() - .EmptyOptional() .AddListItem() .BeginOptional() - .Int32(57) + .Uint32(10) .EndOptional() .AddListItem() - .EmptyOptional(TTypeBuilder().Primitive(EPrimitiveType::Int32).Build()) + .BeginOptional() + .Int32(20) + .EndOptional() .EndList() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatType(value.GetType()), - R"(List)"); - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([[1];#;[57];#])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([1,null,57,null])"); - - auto expectedProtoValueStr = - "items {\n" - " int32_value: 1\n" - "}\n" - "items {\n" - " null_flag_value: NULL_VALUE\n" - "}\n" - "items {\n" - " int32_value: 57\n" - "}\n" - "items {\n" - " null_flag_value: NULL_VALUE\n" - "}\n"; - - TStringType protoValueStr; - google::protobuf::TextFormat::PrintToString(value.GetProto(), &protoValueStr); - UNIT_ASSERT_NO_DIFF(protoValueStr, expectedProtoValueStr); - } - - Y_UNIT_TEST(BuildValueNestedOptional) { +TEST(YdbValue, BuildValueOptionalMismatch2) { + ASSERT_THROW({ auto value = TValueBuilder() - .BeginTuple() - .AddElement() - .BeginOptional() - .BeginOptional() - .Int32(10) - .EndOptional() - .EndOptional() - .AddElement() - .BeginOptional() - .BeginOptional() - .BeginOptional() - .Int64(-1) - .EndOptional() - .EndOptional() - .EndOptional() - .AddElement() + .BeginList() + .AddListItem() .BeginOptional() - .EmptyOptional(TTypeBuilder().Primitive(EPrimitiveType::String).Build()) + .Uint32(10) .EndOptional() - .AddElement() + .AddListItem() .BeginOptional() - .BeginOptional() - .EmptyOptional(EPrimitiveType::Utf8) - .EndOptional() + .Int32(57) .EndOptional() - .EndTuple() + .EndList() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatType(value.GetType()), - R"(Tuple)"); - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([[[10]];[[[-1]]];[#];[[#]]])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([10,-1,null,null])"); - - auto expectedProtoValueStr = - "items {\n" - " int32_value: 10\n" - "}\n" - "items {\n" - " int64_value: -1\n" - "}\n" - "items {\n" - " nested_value {\n" - " null_flag_value: NULL_VALUE\n" - " }\n" - "}\n" - "items {\n" - " nested_value {\n" - " nested_value {\n" - " null_flag_value: NULL_VALUE\n" - " }\n" - " }\n" - "}\n"; - - TStringType protoValueStr; - google::protobuf::TextFormat::PrintToString(value.GetProto(), &protoValueStr); - UNIT_ASSERT_NO_DIFF(protoValueStr, expectedProtoValueStr); - } - - Y_UNIT_TEST(BuildValueOptionalMismatch1) { - try { - auto value = TValueBuilder() - .BeginList() - .AddListItem() - .BeginOptional() - .Uint32(10) - .EndOptional() - .AddListItem() - .BeginOptional() - .Int32(20) - .EndOptional() - .EndList() - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } - - UNIT_ASSERT(false); - } - - Y_UNIT_TEST(BuildValueOptionalMismatch2) { - try { - auto value = TValueBuilder() - .BeginList() - .AddListItem() - .BeginOptional() - .Uint32(10) - .EndOptional() - .AddListItem() - .BeginOptional() - .Int32(57) - .EndOptional() - .EndList() - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } - - UNIT_ASSERT(false); - } +TEST(YdbValue, BuildValueStruct) { + auto value = TValueBuilder() + .BeginList() + .AddListItem() + .BeginStruct() + .AddMember("Id") + .Uint32(1) + .AddMember("Name") + .String("Anna") + .AddMember("Value") + .Int32(-100) + .AddMember("Description") + .EmptyOptional(EPrimitiveType::Utf8) + .EndStruct() + .AddListItem() + .BeginStruct() + .AddMember("Name") + .String("Paul") + .AddMember("Value", TValueBuilder().Int32(-200).Build()) + .AddMember("Id") + .Uint32(2) + .AddMember("Description") + .OptionalUtf8("Some details") + .EndStruct() + .EndList() + .Build(); + + auto expectedProtoValueStr = + "items {\n" + " items {\n" + " uint32_value: 1\n" + " }\n" + " items {\n" + " bytes_value: \"Anna\"\n" + " }\n" + " items {\n" + " int32_value: -100\n" + " }\n" + " items {\n" + " null_flag_value: NULL_VALUE\n" + " }\n" + "}\n" + "items {\n" + " items {\n" + " uint32_value: 2\n" + " }\n" + " items {\n" + " bytes_value: \"Paul\"\n" + " }\n" + " items {\n" + " int32_value: -200\n" + " }\n" + " items {\n" + " text_value: \"Some details\"\n" + " }\n" + "}\n"; + + CheckProtoValue(value.GetProto(), expectedProtoValueStr); +} - Y_UNIT_TEST(BuildValueStruct) { +TEST(YdbValue, BuildValueStructMissingMember) { + ASSERT_THROW({ auto value = TValueBuilder() .BeginList() .AddListItem() @@ -902,100 +900,223 @@ Y_UNIT_TEST_SUITE(YdbValue) { .String("Anna") .AddMember("Value") .Int32(-100) - .AddMember("Description") - .EmptyOptional(EPrimitiveType::Utf8) .EndStruct() .AddListItem() .BeginStruct() - .AddMember("Name") - .String("Paul") - .AddMember("Value", TValueBuilder().Int32(-200).Build()) + .AddMember("Value") + .Int32(-200) .AddMember("Id") .Uint32(2) - .AddMember("Description") - .OptionalUtf8("Some details") .EndStruct() .EndList() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([[1u;"Anna";-100;#];[2u;"Paul";-200;["Some details"]]])"); - UNIT_ASSERT_NO_DIFF( - FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([{"Id":1,"Name":"Anna","Value":-100,"Description":null},)" - R"({"Id":2,"Name":"Paul","Value":-200,"Description":"Some details"}])" - ); - } - - Y_UNIT_TEST(BuildValueStructMissingMember) { - try { - auto value = TValueBuilder() - .BeginList() - .AddListItem() - .BeginStruct() - .AddMember("Id") - .Uint32(1) - .AddMember("Name") - .String("Anna") - .AddMember("Value") - .Int32(-100) - .EndStruct() - .AddListItem() - .BeginStruct() - .AddMember("Value") - .Int32(-200) - .AddMember("Id") - .Uint32(2) - .EndStruct() - .EndList() - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } +TEST(YdbValue, BuildValueTuplePrimitives) { + auto value = TValueBuilder() + .BeginTuple() + .AddElement().Bool(true) + .AddElement().Int8(-1) + .AddElement().Uint8(1) + .AddElement().Int16(-2) + .AddElement().Uint16(2) + .AddElement().Int32(-3) + .AddElement().Uint32(3) + .AddElement().Int64(-4) + .AddElement().Uint64(4) + .AddElement().Float(-5.5) + .AddElement().Double(6.6) + .AddElement().Date(TInstant::Days(7)) + .AddElement().Datetime(TInstant::Seconds(8)) + .AddElement().Timestamp(TInstant::MicroSeconds(9)) + .AddElement().Interval(-10) + .AddElement().TzDate("2018-02-02,Europe/Moscow") + .AddElement().TzDatetime("2018-02-03T15:00:00,Europe/Moscow") + .AddElement().TzTimestamp("2018-02-07T15:00:00,Europe/Moscow") + .AddElement().String("TestString") + .AddElement().Utf8("TestUtf8") + .AddElement().Yson("[]") + .AddElement().Json("{}") + .EndTuple() + .Build(); + + ASSERT_EQ(FormatType(value.GetType()), + R"(Tuple)"); + + auto expectedProtoValueStr = + "items {\n" + " bool_value: true\n" + "}\n" + "items {\n" + " int32_value: -1\n" + "}\n" + "items {\n" + " uint32_value: 1\n" + "}\n" + "items {\n" + " int32_value: -2\n" + "}\n" + "items {\n" + " uint32_value: 2\n" + "}\n" + "items {\n" + " int32_value: -3\n" + "}\n" + "items {\n" + " uint32_value: 3\n" + "}\n" + "items {\n" + " int64_value: -4\n" + "}\n" + "items {\n" + " uint64_value: 4\n" + "}\n" + "items {\n" + " float_value: -5.5\n" + "}\n" + "items {\n" + " double_value: 6.6\n" + "}\n" + "items {\n" + " uint32_value: 7\n" + "}\n" + "items {\n" + " uint32_value: 8\n" + "}\n" + "items {\n" + " uint64_value: 9\n" + "}\n" + "items {\n" + " int64_value: -10\n" + "}\n" + "items {\n" + " text_value: \"2018-02-02,Europe/Moscow\"\n" + "}\n" + "items {\n" + " text_value: \"2018-02-03T15:00:00,Europe/Moscow\"\n" + "}\n" + "items {\n" + " text_value: \"2018-02-07T15:00:00,Europe/Moscow\"\n" + "}\n" + "items {\n" + " bytes_value: \"TestString\"\n" + "}\n" + "items {\n" + " text_value: \"TestUtf8\"\n" + "}\n" + "items {\n" + " bytes_value: \"[]\"\n" + "}\n" + "items {\n" + " text_value: \"{}\"\n" + "}\n"; + + CheckProtoValue(value.GetProto(), expectedProtoValueStr); +} - UNIT_ASSERT(false); - } +TEST(YdbValue, BuildValueTuple1) { + auto value = TValueBuilder() + .BeginList() + .AddListItem() + .BeginTuple() + .AddElement() + .Int32(10) + .AddElement() + .String("Str1") + .EndTuple() + .AddListItem() + .BeginTuple() + .AddElement(TValueBuilder().Int32(20).Build()) + .AddElement() + .String("Str2") + .EndTuple() + .EndList() + .Build(); + + auto expectedProtoValueStr = + "items {\n" + " items {\n" + " int32_value: 10\n" + " }\n" + " items {\n" + " bytes_value: \"Str1\"\n" + " }\n" + "}\n" + "items {\n" + " items {\n" + " int32_value: 20\n" + " }\n" + " items {\n" + " bytes_value: \"Str2\"\n" + " }\n" + "}\n"; + + CheckProtoValue(value.GetProto(), expectedProtoValueStr); +} - Y_UNIT_TEST(BuildValueTuplePrimitives) { - auto value = TValueBuilder() +TEST(YdbValue, BuildValueTuple2) { + auto value = TValueBuilder() + .BeginList() + .AddListItem() + .BeginTuple() + .AddElement(TValueBuilder().Int32(-10).Build()) + .AddElement(TValueBuilder().Utf8("Utf1").Build()) + .EndTuple() + .AddListItem() .BeginTuple() - .AddElement().Bool(true) - .AddElement().Int8(-1) - .AddElement().Uint8(1) - .AddElement().Int16(-2) - .AddElement().Uint16(2) - .AddElement().Int32(-3) - .AddElement().Uint32(3) - .AddElement().Int64(-4) - .AddElement().Uint64(4) - .AddElement().Float(-5.5) - .AddElement().Double(6.6) - .AddElement().Date(TInstant::Days(7)) - .AddElement().Datetime(TInstant::Seconds(8)) - .AddElement().Timestamp(TInstant::MicroSeconds(9)) - .AddElement().Interval(-10) - .AddElement().TzDate("2018-02-02,Europe/Moscow") - .AddElement().TzDatetime("2018-02-03T15:00:00,Europe/Moscow") - .AddElement().TzTimestamp("2018-02-07T15:00:00,Europe/Moscow") - .AddElement().String("TestString") - .AddElement().Utf8("TestUtf8") - .AddElement().Yson("[]") - .AddElement().Json("{}") + .AddElement() + .Int32(-20) + .AddElement() + .Utf8("Utf2") .EndTuple() + .EndList() + .Build(); + + auto expectedProtoValueStr = + "items {\n" + " items {\n" + " int32_value: -10\n" + " }\n" + " items {\n" + " text_value: \"Utf1\"\n" + " }\n" + "}\n" + "items {\n" + " items {\n" + " int32_value: -20\n" + " }\n" + " items {\n" + " text_value: \"Utf2\"\n" + " }\n" + "}\n"; + + CheckProtoValue(value.GetProto(), expectedProtoValueStr); +} + +TEST(YdbValue, BuildValueTupleElementsMismatch1) { + ASSERT_THROW({ + auto value = TValueBuilder() + .BeginList() + .AddListItem() + .BeginTuple() + .AddElement() + .Int32(10) + .AddElement() + .String("Str1") + .EndTuple() + .AddListItem() + .BeginTuple() + .AddElement() + .Int32(-20) + .EndTuple() + .EndList() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatType(value.GetType()), - R"(Tuple)"); - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([%true;-1;1u;-2;2u;-3;3u;-4;4u;-5.5;6.6;7u;8u;9u;-10;"2018-02-02,Europe/Moscow";"2018-02-03T15:00:00,Europe/Moscow";"2018-02-07T15:00:00,Europe/Moscow";"TestString";"TestUtf8";"[]";"{}"])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([true,-1,1,-2,2,-3,3,-4,4,-5.5,6.6,"1970-01-08","1970-01-01T00:00:08Z",)" - R"("1970-01-01T00:00:00.000009Z",-10,"2018-02-02,Europe/Moscow",)" - R"("2018-02-03T15:00:00,Europe/Moscow","2018-02-07T15:00:00,Europe/Moscow",)" - R"("TestString","TestUtf8","[]","{}"])"); - } - - Y_UNIT_TEST(BuildValueTuple1) { +TEST(YdbValue, BuildValueTupleElementsMismatch2) { + ASSERT_THROW({ auto value = TValueBuilder() .BeginList() .AddListItem() @@ -1007,125 +1128,113 @@ Y_UNIT_TEST_SUITE(YdbValue) { .EndTuple() .AddListItem() .BeginTuple() - .AddElement(TValueBuilder().Int32(20).Build()) + .AddElement() + .Int32(20) .AddElement() .String("Str2") + .AddElement() + .Uint64(1) .EndTuple() .EndList() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([[10;"Str1"];[20;"Str2"]])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([[10,"Str1"],[20,"Str2"]])"); - } - - Y_UNIT_TEST(BuildValueTuple2) { +TEST(YdbValue, BuildValueTupleTypeMismatch) { + ASSERT_THROW({ auto value = TValueBuilder() .BeginList() .AddListItem() .BeginTuple() - .AddElement(TValueBuilder().Int32(-10).Build()) - .AddElement(TValueBuilder().Utf8("Utf1").Build()) + .AddElement() + .Int32(10) + .AddElement() + .String("Str1") .EndTuple() .AddListItem() .BeginTuple() .AddElement() - .Int32(-20) + .Int32(20) .AddElement() .Utf8("Utf2") .EndTuple() .EndList() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([[-10;"Utf1"];[-20;"Utf2"]])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([[-10,"Utf1"],[-20,"Utf2"]])"); - } - - Y_UNIT_TEST(BuildValueTupleElementsMismatch1) { - try { - auto value = TValueBuilder() - .BeginList() - .AddListItem() - .BeginTuple() - .AddElement() - .Int32(10) - .AddElement() - .String("Str1") - .EndTuple() - .AddListItem() - .BeginTuple() - .AddElement() - .Int32(-20) - .EndTuple() - .EndList() - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } - - UNIT_ASSERT(false); - } - - Y_UNIT_TEST(BuildValueTupleElementsMismatch2) { - try { - auto value = TValueBuilder() - .BeginList() - .AddListItem() - .BeginTuple() - .AddElement() - .Int32(10) - .AddElement() - .String("Str1") - .EndTuple() - .AddListItem() - .BeginTuple() - .AddElement() - .Int32(20) - .AddElement() - .String("Str2") - .AddElement() - .Uint64(1) - .EndTuple() - .EndList() - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } - - UNIT_ASSERT(false); - } - - Y_UNIT_TEST(BuildValueTupleTypeMismatch) { - try { - auto value = TValueBuilder() - .BeginList() - .AddListItem() - .BeginTuple() - .AddElement() - .Int32(10) - .AddElement() - .String("Str1") - .EndTuple() - .AddListItem() - .BeginTuple() - .AddElement() - .Int32(20) - .AddElement() - .Utf8("Utf2") - .EndTuple() - .EndList() - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } +TEST(YdbValue, BuildValueDict1) { + auto value = TValueBuilder() + .BeginDict() + .AddDictItem() + .DictKey(TValueBuilder().Int32(1).Build()) + .DictPayload(TValueBuilder().String("Str1").Build()) + .AddDictItem() + .DictKey() + .Int32(2) + .DictPayload() + .String("Str2") + .EndDict() + .Build(); + + auto expectedProtoValueStr = + "pairs {\n" + " key {\n" + " int32_value: 1\n" + " }\n" + " payload {\n" + " bytes_value: \"Str1\"\n" + " }\n" + "}\n" + "pairs {\n" + " key {\n" + " int32_value: 2\n" + " }\n" + " payload {\n" + " bytes_value: \"Str2\"\n" + " }\n" + "}\n"; + + CheckProtoValue(value.GetProto(), expectedProtoValueStr); +} - UNIT_ASSERT(false); - } +TEST(YdbValue, BuildValueDict2) { + auto value = TValueBuilder() + .BeginDict() + .AddDictItem() + .DictKey() + .Int32(1) + .DictPayload() + .String("Str1") + .AddDictItem() + .DictKey(TValueBuilder().Int32(2).Build()) + .DictPayload(TValueBuilder().String("Str2").Build()) + .EndDict() + .Build(); + + auto expectedProtoValueStr = + "pairs {\n" + " key {\n" + " int32_value: 1\n" + " }\n" + " payload {\n" + " bytes_value: \"Str1\"\n" + " }\n" + "}\n" + "pairs {\n" + " key {\n" + " int32_value: 2\n" + " }\n" + " payload {\n" + " bytes_value: \"Str2\"\n" + " }\n" + "}\n"; + + CheckProtoValue(value.GetProto(), expectedProtoValueStr); +} - Y_UNIT_TEST(BuildValueDict1) { +TEST(YdbValue, BuildValueDictTypeMismatch1) { + ASSERT_THROW({ auto value = TValueBuilder() .BeginDict() .AddDictItem() @@ -1135,17 +1244,14 @@ Y_UNIT_TEST_SUITE(YdbValue) { .DictKey() .Int32(2) .DictPayload() - .String("Str2") + .Utf8("Utf2") .EndDict() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([[1;"Str1"];[2;"Str2"]])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([[1,"Str1"],[2,"Str2"]])"); - } - - Y_UNIT_TEST(BuildValueDict2) { +TEST(YdbValue, BuildValueDictTypeMismatch2) { + ASSERT_THROW({ auto value = TValueBuilder() .BeginDict() .AddDictItem() @@ -1154,224 +1260,210 @@ Y_UNIT_TEST_SUITE(YdbValue) { .DictPayload() .String("Str1") .AddDictItem() - .DictKey(TValueBuilder().Int32(2).Build()) + .DictKey(TValueBuilder().Uint32(2).Build()) .DictPayload(TValueBuilder().String("Str2").Build()) .EndDict() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([[1;"Str1"];[2;"Str2"]])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([[1,"Str1"],[2,"Str2"]])"); - } - - Y_UNIT_TEST(BuildValueDictTypeMismatch1) { - try { - auto value = TValueBuilder() - .BeginDict() - .AddDictItem() - .DictKey(TValueBuilder().Int32(1).Build()) - .DictPayload(TValueBuilder().String("Str1").Build()) - .AddDictItem() - .DictKey() - .Int32(2) - .DictPayload() - .Utf8("Utf2") - .EndDict() - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } +TEST(YdbValue, BuildValueDictEmpty1) { + auto value = TValueBuilder() + .EmptyDict( + TTypeBuilder().Primitive(EPrimitiveType::Uint32).Build(), + TTypeBuilder().Primitive(EPrimitiveType::String).Build()) + .Build(); - UNIT_ASSERT(false); - } - - Y_UNIT_TEST(BuildValueDictTypeMismatch2) { - try { - auto value = TValueBuilder() - .BeginDict() - .AddDictItem() - .DictKey() - .Int32(1) - .DictPayload() - .String("Str1") - .AddDictItem() - .DictKey(TValueBuilder().Uint32(2).Build()) - .DictPayload(TValueBuilder().String("Str2").Build()) - .EndDict() - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } + ASSERT_EQ(FormatType(value.GetType()), + R"(Dict)"); - UNIT_ASSERT(false); - } + auto expectedProtoValueStr = ""; + CheckProtoValue(value.GetProto(), expectedProtoValueStr); +} - Y_UNIT_TEST(BuildValueDictEmpty1) { - auto value = TValueBuilder() +TEST(YdbValue, BuildValueDictEmpty2) { + auto value = TValueBuilder() + .BeginList() + .AddListItem() + .BeginDict() + .AddDictItem() + .DictKey() + .Int32(1) + .DictPayload() + .String("Str1") + .EndDict() + .AddListItem() + .EmptyDict() + .AddListItem() .EmptyDict( - TTypeBuilder().Primitive(EPrimitiveType::Uint32).Build(), + TTypeBuilder().Primitive(EPrimitiveType::Int32).Build(), TTypeBuilder().Primitive(EPrimitiveType::String).Build()) - .Build(); - - UNIT_ASSERT_NO_DIFF(FormatType(value.GetType()), - R"(Dict)"); - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([])"); - } + .EndList() + .Build(); + + ASSERT_EQ(FormatType(value.GetType()), + R"(List>)"); + + auto expectedProtoValueStr = + "items {\n" + " pairs {\n" + " key {\n" + " int32_value: 1\n" + " }\n" + " payload {\n" + " bytes_value: \"Str1\"\n" + " }\n" + " }\n" + "}\n" + "items {\n" + "}\n" + "items {\n" + "}\n"; + + CheckProtoValue(value.GetProto(), expectedProtoValueStr); +} - Y_UNIT_TEST(BuildValueDictEmpty2) { +TEST(YdbValue, BuildValueDictEmptyNoType) { + ASSERT_THROW({ auto value = TValueBuilder() .BeginList() - .AddListItem() - .BeginDict() - .AddDictItem() - .DictKey() - .Int32(1) - .DictPayload() - .String("Str1") - .EndDict() .AddListItem() .EmptyDict() + .EndList() + .Build(); + }, TExpectedErrorException); +} + +TEST(YdbValue, BuildValueDictEmptyTypeMismatch) { + ASSERT_THROW({ + auto value = TValueBuilder() + .BeginList() .AddListItem() .EmptyDict( TTypeBuilder().Primitive(EPrimitiveType::Int32).Build(), TTypeBuilder().Primitive(EPrimitiveType::String).Build()) + .AddListItem() + .EmptyDict( + TTypeBuilder().Primitive(EPrimitiveType::Int32).Build(), + TTypeBuilder().Primitive(EPrimitiveType::Utf8).Build()) .EndList() .Build(); + }, TExpectedErrorException); +} - UNIT_ASSERT_NO_DIFF(FormatType(value.GetType()), - R"(List>)"); - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([[[1;"Str1"]];[];[]])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([[[1,"Str1"]],[],[]])"); - } - - Y_UNIT_TEST(BuildValueDictEmptyNoType) { - try { - auto value = TValueBuilder() - .BeginList() - .AddListItem() - .EmptyDict() - .EndList() - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } - - UNIT_ASSERT(false); - } - - Y_UNIT_TEST(BuildValueDictEmptyTypeMismatch) { - try { - auto value = TValueBuilder() - .BeginList() - .AddListItem() - .EmptyDict( - TTypeBuilder().Primitive(EPrimitiveType::Int32).Build(), - TTypeBuilder().Primitive(EPrimitiveType::String).Build()) - .AddListItem() - .EmptyDict( - TTypeBuilder().Primitive(EPrimitiveType::Int32).Build(), - TTypeBuilder().Primitive(EPrimitiveType::Utf8).Build()) - .EndList() - .Build(); - } catch (const TExpectedErrorException& e) { - return; - } - - UNIT_ASSERT(false); - } - - Y_UNIT_TEST(BuildValueWithType) { - auto type = TTypeBuilder() - .BeginTuple() - .AddElement() - .BeginStruct() - .AddMember("Name") - .Primitive(EPrimitiveType::String) - .AddMember("Value") - .Primitive(EPrimitiveType::Uint64) - .EndStruct() - .AddElement() +TEST(YdbValue, BuildValueWithType) { + auto type = TTypeBuilder() + .BeginTuple() + .AddElement() + .BeginStruct() + .AddMember("Name") + .Primitive(EPrimitiveType::String) + .AddMember("Value") + .Primitive(EPrimitiveType::Uint64) + .EndStruct() + .AddElement() + .BeginOptional() + .Primitive(EPrimitiveType::Utf8) + .EndOptional() + .AddElement() + .BeginList() + .Primitive(EPrimitiveType::Bool) + .EndList() + .AddElement() + .BeginDict() + .DictKey() + .Primitive(EPrimitiveType::Int32) + .DictPayload() .BeginOptional() - .Primitive(EPrimitiveType::Utf8) + .Primitive(EPrimitiveType::Uint8) .EndOptional() - .AddElement() - .BeginList() - .Primitive(EPrimitiveType::Bool) - .EndList() - .AddElement() - .BeginDict() + .EndDict() + .AddElement() + .BeginOptional() + .Primitive(EPrimitiveType::DyNumber) + .EndOptional() + .EndTuple() + .Build(); + + auto value = TValueBuilder(type) + .BeginTuple() + .AddElement() + .BeginStruct() + .AddMember("Value") + .Uint64(1) + .AddMember("Name") + .String("Sergey") + .EndStruct() + .AddElement() + .EmptyOptional() + .AddElement() + .BeginList() + .AddListItem() + .Bool(true) + .EndList() + .AddElement() + .BeginDict() + .AddDictItem() .DictKey() - .Primitive(EPrimitiveType::Int32) + .Int32(10) .DictPayload() - .BeginOptional() - .Primitive(EPrimitiveType::Uint8) - .EndOptional() - .EndDict() - .AddElement() - .BeginOptional() - .Primitive(EPrimitiveType::DyNumber) - .EndOptional() - .EndTuple() - .Build(); - - auto value = TValueBuilder(type) - .BeginTuple() - .AddElement() - .BeginStruct() - .AddMember("Value") - .Uint64(1) - .AddMember("Name") - .String("Sergey") - .EndStruct() - .AddElement() - .EmptyOptional() - .AddElement() - .BeginList() - .AddListItem() - .Bool(true) - .EndList() - .AddElement() - .BeginDict() - .AddDictItem() - .DictKey() - .Int32(10) - .DictPayload() - .EmptyOptional() - .EndDict() - .AddElement() - .BeginOptional() - .DyNumber("12.345") - .EndOptional() - .EndTuple() - .Build(); + .EmptyOptional() + .EndDict() + .AddElement() + .BeginOptional() + .DyNumber("12.345") + .EndOptional() + .EndTuple() + .Build(); + + ASSERT_EQ(FormatType(value.GetType()), + R"(Tuple,Utf8?,List,Dict,DyNumber?>)"); + + auto expectedProtoValueStr = + "items {\n" + " items {\n" + " bytes_value: \"Sergey\"\n" + " }\n" + " items {\n" + " uint64_value: 1\n" + " }\n" + "}\n" + "items {\n" + " null_flag_value: NULL_VALUE\n" + "}\n" + "items {\n" + " items {\n" + " bool_value: true\n" + " }\n" + "}\n" + "items {\n" + " pairs {\n" + " key {\n" + " int32_value: 10\n" + " }\n" + " payload {\n" + " null_flag_value: NULL_VALUE\n" + " }\n" + " }\n" + "}\n" + "items {\n" + " text_value: \"12.345\"\n" + "}\n"; + + CheckProtoValue(value.GetProto(), expectedProtoValueStr); +} - UNIT_ASSERT_NO_DIFF(FormatType(value.GetType()), - R"(Tuple,Utf8?,List,Dict,DyNumber?>)"); - UNIT_ASSERT_NO_DIFF(FormatValueYson(value), - R"([["Sergey";1u];#;[%true];[[10;#]];["12.345"]])"); - UNIT_ASSERT_NO_DIFF(FormatValueJson(value, EBinaryStringEncoding::Unicode), - R"([{"Name":"Sergey","Value":1},null,[true],[[10,null]],"12.345"])"); - } - - Y_UNIT_TEST(CorrectUuid) { - std::string uuidStr = "5ca32c22-841b-11e8-adc0-fa7ae01bbebc"; - TUuidValue uuid(uuidStr); - UNIT_ASSERT_VALUES_EQUAL(uuidStr, uuid.ToString()); - } - - Y_UNIT_TEST(IncorrectUuid) { - UNIT_ASSERT_EXCEPTION(TUuidValue(""), TContractViolation); - UNIT_ASSERT_EXCEPTION(TUuidValue("0123456789abcdef0123456789abcdef0123456789abcdef"), TContractViolation); - UNIT_ASSERT_EXCEPTION(TUuidValue("5ca32c22+841b-11e8-adc0-fa7ae01bbebc"), TContractViolation); - UNIT_ASSERT_EXCEPTION(TUuidValue("5ca32-c22841b-11e8-adc0-fa7ae01bbebc"), TContractViolation); - } +TEST(YdbValue, CorrectUuid) { + std::string uuidStr = "5ca32c22-841b-11e8-adc0-fa7ae01bbebc"; + TUuidValue uuid(uuidStr); + ASSERT_EQ(uuidStr, uuid.ToString()); +} +TEST(YdbValue, IncorrectUuid) { + ASSERT_THROW(TUuidValue(""), TContractViolation); + ASSERT_THROW(TUuidValue("0123456789abcdef0123456789abcdef0123456789abcdef"), TContractViolation); + ASSERT_THROW(TUuidValue("5ca32c22+841b-11e8-adc0-fa7ae01bbebc"), TContractViolation); + ASSERT_THROW(TUuidValue("5ca32-c22841b-11e8-adc0-fa7ae01bbebc"), TContractViolation); } } // namespace NYdb diff --git a/ydb/public/sdk/cpp/tests/unit/client/value/ya.make b/ydb/public/sdk/cpp/tests/unit/client/value/ya.make index 9a6c85257a59..aafd694cb84a 100644 --- a/ydb/public/sdk/cpp/tests/unit/client/value/ya.make +++ b/ydb/public/sdk/cpp/tests/unit/client/value/ya.make @@ -1,4 +1,4 @@ -UNITTEST() +GTEST() IF (SANITIZER_TYPE == "thread") SIZE(LARGE) @@ -10,8 +10,6 @@ ENDIF() FORK_SUBTESTS() PEERDIR( - ydb/public/lib/json_value - ydb/public/lib/yson_value ydb/public/sdk/cpp/src/client/value ydb/public/sdk/cpp/src/client/params ) From 651a677f8d638814bb2013fc87df737a92b279c9 Mon Sep 17 00:00:00 2001 From: Nikolay Shestakov Date: Wed, 9 Apr 2025 16:44:42 +0500 Subject: [PATCH 094/454] Added max_committed_time_lag for DescribeConsumer (#16857) --- ydb/core/persqueue/partition.cpp | 150 +++++++++------- ydb/core/persqueue/partition.h | 2 + ydb/core/persqueue/partition_monitoring.cpp | 27 +-- ydb/core/persqueue/partition_read.cpp | 12 +- ydb/core/persqueue/user_info.h | 59 ++++--- .../persqueue/ut/ut_with_sdk/topic_ut.cpp | 165 ++++++++++++++++++ ydb/core/persqueue/ut/ut_with_sdk/ya.make | 1 + ydb/core/protos/pqconfig.proto | 2 + ydb/public/api/protos/ydb_topic.proto | 4 + .../ydb-cpp-sdk/client/topic/control_plane.h | 2 + .../sdk/cpp/src/client/topic/impl/topic.cpp | 5 + .../ut/ut_utils/topic_sdk_test_setup.cpp | 21 +++ .../topic/ut/ut_utils/topic_sdk_test_setup.h | 3 + .../persqueue_v1/actors/schema_actors.cpp | 5 + 14 files changed, 352 insertions(+), 106 deletions(-) create mode 100644 ydb/core/persqueue/ut/ut_with_sdk/topic_ut.cpp diff --git a/ydb/core/persqueue/partition.cpp b/ydb/core/persqueue/partition.cpp index 40796d3dffc6..4d12b2167ab8 100644 --- a/ydb/core/persqueue/partition.cpp +++ b/ydb/core/persqueue/partition.cpp @@ -650,6 +650,54 @@ void TPartition::Handle(TEvPQ::TEvPipeDisconnected::TPtr& ev, const TActorContex } +TConsumerSnapshot TPartition::CreateSnapshot(TUserInfo& userInfo) const { + auto now = TAppData::TimeProvider->Now(); + + userInfo.UpdateReadingTimeAndState(EndOffset, now); + + TConsumerSnapshot result; + result.Now = now; + + if (userInfo.Offset >= static_cast(EndOffset)) { + result.LastCommittedMessage.CreateTimestamp = now; + result.LastCommittedMessage.WriteTimestamp = now; + } else if (userInfo.ActualTimestamps) { + result.LastCommittedMessage.CreateTimestamp = userInfo.CreateTimestamp; + result.LastCommittedMessage.WriteTimestamp = userInfo.WriteTimestamp; + } else { + auto timestamp = GetWriteTimeEstimate(userInfo.Offset); + result.LastCommittedMessage.CreateTimestamp = timestamp; + result.LastCommittedMessage.WriteTimestamp = timestamp; + } + + auto readOffset = userInfo.GetReadOffset(); + + result.ReadOffset = readOffset; + result.LastReadTimestamp = userInfo.ReadTimestamp; + + if (readOffset >= static_cast(EndOffset)) { + result.LastReadMessage.CreateTimestamp = now; + result.LastReadMessage.WriteTimestamp = now; + } else if (userInfo.ReadOffset == -1) { + result.LastReadMessage = result.LastCommittedMessage; + } else if (userInfo.ReadWriteTimestamp) { + result.LastReadMessage.CreateTimestamp = userInfo.ReadCreateTimestamp; + result.LastReadMessage.WriteTimestamp = userInfo.ReadWriteTimestamp; + } else { + auto timestamp = GetWriteTimeEstimate(readOffset); + result.LastCommittedMessage.CreateTimestamp = timestamp; + result.LastCommittedMessage.WriteTimestamp = timestamp; + } + + if (readOffset < (i64)EndOffset) { + result.ReadLag = result.LastReadTimestamp - result.LastReadMessage.WriteTimestamp; + } + result.CommitedLag = result.LastCommittedMessage.WriteTimestamp - now; + result.TotalLag = TDuration::MilliSeconds(userInfo.GetWriteLagMs()) + result.ReadLag + (now - result.LastReadTimestamp); + + return result; +} + void TPartition::Handle(TEvPQ::TEvPartitionStatus::TPtr& ev, const TActorContext& ctx) { const auto now = ctx.Now(); @@ -696,7 +744,7 @@ void TPartition::Handle(TEvPQ::TEvPartitionStatus::TPtr& ev, const TActorContext bool filterConsumers = !ev->Get()->Consumers.empty(); TSet requiredConsumers(ev->Get()->Consumers.begin(), ev->Get()->Consumers.end()); for (auto& userInfoPair : UsersInfoStorage->GetAll()) { - const auto& userInfo = userInfoPair.second; + auto& userInfo = userInfoPair.second; auto& clientId = ev->Get()->ClientId; bool consumerShouldBeProcessed = filterConsumers ? requiredConsumers.contains(userInfo.User) @@ -719,46 +767,32 @@ void TPartition::Handle(TEvPQ::TEvPartitionStatus::TPtr& ev, const TActorContext continue; } - auto estimateWriteTimestamp = [&]() { - auto timestamp = userInfo.GetWriteTimestamp(EndOffset); - if (!timestamp) { - timestamp = GetWriteTimeEstimate(userInfo.Offset); - } - return timestamp; - }; - - auto estimateReadWriteTimestamp = [&]() { - auto timestamp = userInfo.GetReadWriteTimestamp(EndOffset); - if (!timestamp) { - timestamp = GetWriteTimeEstimate(userInfo.GetReadOffset()); - }; - return timestamp; - }; - if (clientId == userInfo.User) { //fill lags NKikimrPQ::TClientInfo* clientInfo = result.MutableLagsInfo(); clientInfo->SetClientId(userInfo.User); + auto snapshot = CreateSnapshot(userInfo); + auto write = clientInfo->MutableWritePosition(); write->SetOffset(userInfo.Offset); - write->SetWriteTimestamp(estimateWriteTimestamp().MilliSeconds()); - write->SetCreateTimestamp(userInfo.GetCreateTimestamp(EndOffset).MilliSeconds()); + write->SetWriteTimestamp(snapshot.LastCommittedMessage.WriteTimestamp.MilliSeconds()); + write->SetCreateTimestamp(snapshot.LastCommittedMessage.CreateTimestamp.MilliSeconds()); write->SetSize(GetSizeLag(userInfo.Offset)); - auto read = clientInfo->MutableReadPosition(); - read->SetOffset(userInfo.GetReadOffset()); - read->SetWriteTimestamp(estimateReadWriteTimestamp().MilliSeconds()); - read->SetCreateTimestamp(userInfo.GetReadCreateTimestamp(EndOffset).MilliSeconds()); - read->SetSize(GetSizeLag(userInfo.GetReadOffset())); + auto readOffset = userInfo.GetReadOffset(); - clientInfo->SetLastReadTimestampMs(userInfo.GetReadTimestamp().MilliSeconds()); - if (IsActive() || userInfo.GetReadOffset() < (i64)EndOffset) { - clientInfo->SetReadLagMs(userInfo.GetReadOffset() < (i64)EndOffset - ? (userInfo.GetReadTimestamp() - TInstant::MilliSeconds(read->GetWriteTimestamp())).MilliSeconds() - : 0); + auto read = clientInfo->MutableReadPosition(); + read->SetOffset(readOffset); + read->SetWriteTimestamp(snapshot.LastReadMessage.WriteTimestamp.MilliSeconds()); + read->SetCreateTimestamp(snapshot.LastReadMessage.CreateTimestamp.MilliSeconds()); + read->SetSize(GetSizeLag(readOffset)); + + clientInfo->SetLastReadTimestampMs(snapshot.LastReadTimestamp.MilliSeconds()); + clientInfo->SetCommitedLagMs(snapshot.CommitedLag.MilliSeconds()); + if (IsActive() || readOffset < (i64)EndOffset) { + clientInfo->SetReadLagMs(snapshot.ReadLag.MilliSeconds()); clientInfo->SetWriteLagMs(userInfo.GetWriteLagMs()); - ui64 totalLag = clientInfo->GetReadLagMs() + userInfo.GetWriteLagMs() + (now - userInfo.GetReadTimestamp()).MilliSeconds(); - clientInfo->SetTotalLagMs(totalLag); + clientInfo->SetTotalLagMs(snapshot.TotalLag.MilliSeconds()); } else { clientInfo->SetReadLagMs(0); clientInfo->SetWriteLagMs(0); @@ -767,14 +801,16 @@ void TPartition::Handle(TEvPQ::TEvPartitionStatus::TPtr& ev, const TActorContext } if (ev->Get()->GetStatForAllConsumers) { //fill lags + auto snapshot = CreateSnapshot(userInfo); + auto* clientInfo = result.AddConsumerResult(); clientInfo->SetConsumer(userInfo.User); clientInfo->SetLastReadTimestampMs(userInfo.GetReadTimestamp().MilliSeconds()); + clientInfo->SetCommitedLagMs(snapshot.CommitedLag.MilliSeconds()); - if (IsActive() || userInfo.GetReadOffset() < (i64)EndOffset) { - clientInfo->SetReadLagMs(userInfo.GetReadOffset() < (i64)EndOffset - ? (userInfo.GetReadTimestamp() - estimateReadWriteTimestamp()).MilliSeconds() - : 0); + auto readOffset = userInfo.GetReadOffset(); + if (IsActive() || readOffset < (i64)EndOffset) { + clientInfo->SetReadLagMs(snapshot.ReadLag.MilliSeconds()); clientInfo->SetWriteLagMs(userInfo.GetWriteLagMs()); } else { clientInfo->SetReadLagMs(0); @@ -862,20 +898,22 @@ void TPartition::Handle(TEvPQ::TEvGetPartitionClientInfo::TPtr& ev, const TActor result.SetEndOffset(EndOffset); result.SetResponseTimestamp(ctx.Now().MilliSeconds()); for (auto& pr : UsersInfoStorage->GetAll()) { + auto snapshot = CreateSnapshot(pr.second); + TUserInfo& userInfo(pr.second); NKikimrPQ::TClientInfo& clientInfo = *result.AddClientInfo(); clientInfo.SetClientId(pr.first); auto& write = *clientInfo.MutableWritePosition(); write.SetOffset(userInfo.Offset); - write.SetWriteTimestamp((userInfo.GetWriteTimestamp(EndOffset) ? userInfo.GetWriteTimestamp(EndOffset) : GetWriteTimeEstimate(userInfo.Offset)).MilliSeconds()); - write.SetCreateTimestamp(userInfo.GetCreateTimestamp(EndOffset).MilliSeconds()); + write.SetWriteTimestamp(snapshot.LastCommittedMessage.WriteTimestamp.MilliSeconds()); + write.SetCreateTimestamp(snapshot.LastCommittedMessage.CreateTimestamp.MilliSeconds()); write.SetSize(GetSizeLag(userInfo.Offset)); auto& read = *clientInfo.MutableReadPosition(); read.SetOffset(userInfo.GetReadOffset()); - read.SetWriteTimestamp((userInfo.GetReadWriteTimestamp(EndOffset) ? userInfo.GetReadWriteTimestamp(EndOffset) : GetWriteTimeEstimate(userInfo.GetReadOffset())).MilliSeconds()); - read.SetCreateTimestamp(userInfo.GetReadCreateTimestamp(EndOffset).MilliSeconds()); + read.SetWriteTimestamp(snapshot.LastReadMessage.WriteTimestamp.MilliSeconds()); + read.SetCreateTimestamp(snapshot.LastReadMessage.CreateTimestamp.MilliSeconds()); read.SetSize(GetSizeLag(userInfo.GetReadOffset())); } ctx.Send(ev->Get()->Sender, response.Release(), 0, ev->Cookie); @@ -1528,37 +1566,31 @@ bool TPartition::UpdateCounters(const TActorContext& ctx, bool force) { if (userInfoPair.first != CLIENTID_WITHOUT_CONSUMER && !userInfo.HasReadRule && !userInfo.Important) continue; bool haveChanges = false; - userInfo.UpdateReadingTimeAndState(EndOffset, now); - ui64 ts = userInfo.GetWriteTimestamp(EndOffset).MilliSeconds(); + auto snapshot = CreateSnapshot(userInfo); + auto ts = snapshot.LastCommittedMessage.WriteTimestamp.MilliSeconds(); if (ts < MIN_TIMESTAMP_MS) ts = Max(); if (userInfo.LabeledCounters->GetCounters()[METRIC_COMMIT_WRITE_TIME].Get() != ts) { haveChanges = true; userInfo.LabeledCounters->GetCounters()[METRIC_COMMIT_WRITE_TIME].Set(ts); } - ts = userInfo.GetCreateTimestamp(EndOffset).MilliSeconds(); + ts = snapshot.LastCommittedMessage.CreateTimestamp.MilliSeconds(); if (ts < MIN_TIMESTAMP_MS) ts = Max(); if (userInfo.LabeledCounters->GetCounters()[METRIC_COMMIT_CREATE_TIME].Get() != ts) { haveChanges = true; userInfo.LabeledCounters->GetCounters()[METRIC_COMMIT_CREATE_TIME].Set(ts); } - ts = userInfo.GetReadWriteTimestamp(EndOffset).MilliSeconds(); - if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_WRITE_TIME].Get() != ts) { + auto readWriteTimestamp = snapshot.LastReadMessage.WriteTimestamp; + if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_WRITE_TIME].Get() != readWriteTimestamp.MilliSeconds()) { haveChanges = true; - userInfo.LabeledCounters->GetCounters()[METRIC_READ_WRITE_TIME].Set(ts); + userInfo.LabeledCounters->GetCounters()[METRIC_READ_WRITE_TIME].Set(readWriteTimestamp.MilliSeconds()); } - i64 off = userInfo.GetReadOffset(); //we want to track first not-readed offset - TInstant wts = userInfo.GetReadWriteTimestamp(EndOffset) ? userInfo.GetReadWriteTimestamp(EndOffset) : GetWriteTimeEstimate(userInfo.GetReadOffset()); - TInstant readTimestamp = userInfo.GetReadTimestamp(); - ui64 readTimeLag = off >= (i64)EndOffset ? 0 : (readTimestamp - wts).MilliSeconds(); - ui64 totalLag = userInfo.GetWriteLagMs() + readTimeLag + (now - readTimestamp).MilliSeconds(); - - if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_TOTAL_TIME].Get() != totalLag) { + if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_TOTAL_TIME].Get() != snapshot.TotalLag.MilliSeconds()) { haveChanges = true; - userInfo.LabeledCounters->GetCounters()[METRIC_READ_TOTAL_TIME].Set(totalLag); + userInfo.LabeledCounters->GetCounters()[METRIC_READ_TOTAL_TIME].Set(snapshot.TotalLag.MilliSeconds()); } - ts = readTimestamp.MilliSeconds(); + ts = snapshot.LastReadTimestamp.MilliSeconds(); if (userInfo.LabeledCounters->GetCounters()[METRIC_LAST_READ_TIME].Get() != ts) { haveChanges = true; userInfo.LabeledCounters->GetCounters()[METRIC_LAST_READ_TIME].Set(ts); @@ -1570,9 +1602,9 @@ bool TPartition::UpdateCounters(const TActorContext& ctx, bool force) { userInfo.LabeledCounters->GetCounters()[METRIC_WRITE_TIME_LAG].Set(timeLag); } - if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_TIME_LAG].Get() != readTimeLag) { + if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_TIME_LAG].Get() != snapshot.ReadLag.MilliSeconds()) { haveChanges = true; - userInfo.LabeledCounters->GetCounters()[METRIC_READ_TIME_LAG].Set(readTimeLag); + userInfo.LabeledCounters->GetCounters()[METRIC_READ_TIME_LAG].Set(snapshot.ReadLag.MilliSeconds()); } if (userInfo.LabeledCounters->GetCounters()[METRIC_COMMIT_MESSAGE_LAG].Get() != EndOffset - userInfo.Offset) { @@ -1580,10 +1612,10 @@ bool TPartition::UpdateCounters(const TActorContext& ctx, bool force) { userInfo.LabeledCounters->GetCounters()[METRIC_COMMIT_MESSAGE_LAG].Set(EndOffset - userInfo.Offset); } - if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_MESSAGE_LAG].Get() != EndOffset - off) { + if (userInfo.LabeledCounters->GetCounters()[METRIC_READ_MESSAGE_LAG].Get() != EndOffset - snapshot.ReadOffset) { haveChanges = true; - userInfo.LabeledCounters->GetCounters()[METRIC_READ_MESSAGE_LAG].Set(EndOffset - off); - userInfo.LabeledCounters->GetCounters()[METRIC_READ_TOTAL_MESSAGE_LAG].Set(EndOffset - off); + userInfo.LabeledCounters->GetCounters()[METRIC_READ_MESSAGE_LAG].Set(EndOffset - snapshot.ReadOffset); + userInfo.LabeledCounters->GetCounters()[METRIC_READ_TOTAL_MESSAGE_LAG].Set(EndOffset - snapshot.ReadOffset); } ui64 sizeLag = GetSizeLag(userInfo.Offset); diff --git a/ydb/core/persqueue/partition.h b/ydb/core/persqueue/partition.h index b801c87ab2ca..0752dcde37c5 100644 --- a/ydb/core/persqueue/partition.h +++ b/ydb/core/persqueue/partition.h @@ -456,6 +456,8 @@ class TPartition : public TActorBootstrapped { ui64 GetReadOffset(ui64 offset, TMaybe readTimestamp) const; + TConsumerSnapshot CreateSnapshot(TUserInfo& userInfo) const; + public: static constexpr NKikimrServices::TActivity::EType ActorActivityType() { return NKikimrServices::TActivity::PERSQUEUE_PARTITION_ACTOR; diff --git a/ydb/core/persqueue/partition_monitoring.cpp b/ydb/core/persqueue/partition_monitoring.cpp index 582afdb234b2..b4d8b61769e4 100644 --- a/ydb/core/persqueue/partition_monitoring.cpp +++ b/ydb/core/persqueue/partition_monitoring.cpp @@ -232,20 +232,21 @@ void TPartition::HandleMonitoring(TEvPQ::TEvMonRequest::TPtr& ev, const TActorCo } } TABLEBODY() { - for (auto& d: UsersInfoStorage->GetAll()) { + for (auto& [user, userInfo]: UsersInfoStorage->GetAll()) { + auto snapshot = CreateSnapshot(userInfo); TABLER() { - TABLED() {out << EncodeHtmlPcdata(d.first);} - TABLED() {out << d.second.Offset;} - TABLED() {out << (EndOffset - d.second.Offset);} - TABLED() {out << ToStringLocalTimeUpToSeconds(d.second.ReadFromTimestamp);} - TABLED() {out << ToStringLocalTimeUpToSeconds(d.second.WriteTimestamp);} - TABLED() {out << ToStringLocalTimeUpToSeconds(d.second.CreateTimestamp);} - TABLED() {out << (d.second.GetReadOffset());} - TABLED() {out << ToStringLocalTimeUpToSeconds(d.second.GetReadWriteTimestamp(EndOffset));} - TABLED() {out << ToStringLocalTimeUpToSeconds(d.second.GetReadCreateTimestamp(EndOffset));} - TABLED() {out << (d.second.ReadOffsetRewindSum);} - TABLED() {out << d.second.ActiveReads;} - TABLED() {out << d.second.Subscriptions;} + TABLED() {out << EncodeHtmlPcdata(user);} + TABLED() {out << userInfo.Offset;} + TABLED() {out << (EndOffset - userInfo.Offset);} + TABLED() {out << ToStringLocalTimeUpToSeconds(userInfo.ReadFromTimestamp);} + TABLED() {out << ToStringLocalTimeUpToSeconds(snapshot.LastCommittedMessage.WriteTimestamp);} + TABLED() {out << ToStringLocalTimeUpToSeconds(snapshot.LastCommittedMessage.WriteTimestamp);} + TABLED() {out << (userInfo.GetReadOffset());} + TABLED() {out << ToStringLocalTimeUpToSeconds(snapshot.LastReadMessage.WriteTimestamp);} + TABLED() {out << ToStringLocalTimeUpToSeconds(snapshot.LastReadMessage.CreateTimestamp);} + TABLED() {out << (userInfo.ReadOffsetRewindSum);} + TABLED() {out << userInfo.ActiveReads;} + TABLED() {out << userInfo.Subscriptions;} } } } diff --git a/ydb/core/persqueue/partition_read.cpp b/ydb/core/persqueue/partition_read.cpp index ba9355f62c4f..f7af353f3e8c 100644 --- a/ydb/core/persqueue/partition_read.cpp +++ b/ydb/core/persqueue/partition_read.cpp @@ -281,15 +281,13 @@ void TPartition::Handle(TEvPQ::TEvPartitionOffsets::TPtr& ev, const TActorContex if (!ev->Get()->ClientId.empty()) { TUserInfo* userInfo = UsersInfoStorage->GetIfExists(ev->Get()->ClientId); if (userInfo) { - i64 offset = Max(userInfo->Offset, 0); + auto snapshot = CreateSnapshot(*userInfo); result.SetClientOffset(userInfo->Offset); - TInstant tmp = userInfo->GetWriteTimestamp(EndOffset) ? userInfo->GetWriteTimestamp(EndOffset) : GetWriteTimeEstimate(offset); - result.SetWriteTimestampMS(tmp.MilliSeconds()); - result.SetCreateTimestampMS(userInfo->GetCreateTimestamp(EndOffset).MilliSeconds()); + result.SetWriteTimestampMS(snapshot.LastCommittedMessage.WriteTimestamp.MilliSeconds()); + result.SetCreateTimestampMS(snapshot.LastCommittedMessage.CreateTimestamp.MilliSeconds()); result.SetClientReadOffset(userInfo->GetReadOffset()); - tmp = userInfo->GetReadWriteTimestamp(EndOffset) ? userInfo->GetReadWriteTimestamp(EndOffset) : GetWriteTimeEstimate(userInfo->GetReadOffset()); - result.SetReadWriteTimestampMS(tmp.MilliSeconds()); - result.SetReadCreateTimestampMS(userInfo->GetReadCreateTimestamp(EndOffset).MilliSeconds()); + result.SetReadWriteTimestampMS(snapshot.LastReadMessage.WriteTimestamp.MilliSeconds()); + result.SetReadCreateTimestampMS(snapshot.LastReadMessage.CreateTimestamp.MilliSeconds()); } } ctx.Send(ev->Get()->Sender, new TEvPQ::TEvPartitionOffsetsResponse(result, Partition)); diff --git a/ydb/core/persqueue/user_info.h b/ydb/core/persqueue/user_info.h index 5aaad167d9f0..86559394bd00 100644 --- a/ydb/core/persqueue/user_info.h +++ b/ydb/core/persqueue/user_info.h @@ -37,6 +37,25 @@ static const TString CLIENTID_WITHOUT_CONSUMER = "$without_consumer"; typedef TProtobufTabletLabeledCounters TUserLabeledCounters; +struct TMessageInfo { + TInstant CreateTimestamp; + TInstant WriteTimestamp; +}; + +struct TConsumerSnapshot { + TInstant Now; + + TMessageInfo LastCommittedMessage; + + i64 ReadOffset; + TInstant LastReadTimestamp; + TMessageInfo LastReadMessage; + + TDuration ReadLag; + TDuration CommitedLag; + TDuration TotalLag; +}; + struct TUserInfoBase { TString User; ui64 ReadRuleGeneration = 0; @@ -55,13 +74,20 @@ struct TUserInfoBase { }; struct TUserInfo: public TUserInfoBase { + bool ActualTimestamps = false; + // WriteTimestamp of the last committed message TInstant WriteTimestamp; + // CreateTimestamp of the last committed message TInstant CreateTimestamp; + + // Timstamp of the last read TInstant ReadTimestamp; - bool ActualTimestamps = false; i64 ReadOffset = -1; + + // WriteTimestamp of the last read message TInstant ReadWriteTimestamp; + // CreateTimestamp of the last read message TInstant ReadCreateTimestamp; ui64 ReadOffsetRewindSum = 0; @@ -175,13 +201,13 @@ struct TUserInfo: public TUserInfoBase { ) : TUserInfoBase{user, readRuleGeneration, session, gen, step, offset, anyCommits, important, readFromTimestamp, partitionSession, pipeClient} - , WriteTimestamp(TAppData::TimeProvider->Now()) - , CreateTimestamp(TAppData::TimeProvider->Now()) - , ReadTimestamp(TAppData::TimeProvider->Now()) , ActualTimestamps(false) + , WriteTimestamp(TInstant::Zero()) + , CreateTimestamp(TInstant::Zero()) + , ReadTimestamp(TAppData::TimeProvider->Now()) , ReadOffset(-1) - , ReadWriteTimestamp(TAppData::TimeProvider->Now()) - , ReadCreateTimestamp(TAppData::TimeProvider->Now()) + , ReadWriteTimestamp(TInstant::Zero()) + , ReadCreateTimestamp(TInstant::Zero()) , ReadOffsetRewindSum(readOffsetRewindSum) , ReadScheduled(false) , HasReadRule(false) @@ -334,30 +360,9 @@ struct TUserInfo: public TUserInfoBase { return ReadTimestamp; } - TInstant GetWriteTimestamp(i64 endOffset) const { - return Offset == endOffset ? TAppData::TimeProvider->Now() : WriteTimestamp; - } - - TInstant GetCreateTimestamp(i64 endOffset) const { - return Offset == endOffset ? TAppData::TimeProvider->Now() : CreateTimestamp; - } - - TInstant GetReadWriteTimestamp(i64 endOffset) const { - TInstant ts = ReadOffset == -1 ? WriteTimestamp : ReadWriteTimestamp; - ts = GetReadOffset() >= endOffset ? TAppData::TimeProvider->Now() : ts; - return ts; - } - ui64 GetWriteLagMs() const { return WriteLagMs.GetValue(); } - - TInstant GetReadCreateTimestamp(i64 endOffset) const { - TInstant ts = ReadOffset == -1 ? CreateTimestamp : ReadCreateTimestamp; - ts = GetReadOffset() >= endOffset ? TAppData::TimeProvider->Now() : ts; - return ts; - } - }; class TUsersInfoStorage { diff --git a/ydb/core/persqueue/ut/ut_with_sdk/topic_ut.cpp b/ydb/core/persqueue/ut/ut_with_sdk/topic_ut.cpp new file mode 100644 index 000000000000..da5d349a71f3 --- /dev/null +++ b/ydb/core/persqueue/ut/ut_with_sdk/topic_ut.cpp @@ -0,0 +1,165 @@ +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace NKikimr { + +using namespace NYdb::NTopic; +using namespace NYdb::NTopic::NTests; +using namespace NSchemeShardUT_Private; +using namespace NKikimr::NPQ::NTest; + +#define UNIT_ASSERT_TIME_EQUAL(A, B, D) \ + do { \ + if (!(((A - B) >= TDuration::Zero()) && ((A - B) <= D)) \ + && !(((B - A) >= TDuration::Zero()) && ((B - A) <= D))) { \ + auto&& failMsg = Sprintf("%s and %s diferent more then %s", (::TStringBuilder() << A).data(), \ + (::TStringBuilder() << B).data(), (::TStringBuilder() << D).data()); \ + UNIT_FAIL_IMPL("assertion failure", failMsg); \ + } \ + } while (false) + + +Y_UNIT_TEST_SUITE(WithSDK) { + + Y_UNIT_TEST(DescribeConsumer) { + TTopicSdkTestSetup setup = CreateSetup(); + setup.CreateTopic(std::string{TEST_TOPIC}, std::string{TEST_CONSUMER}, 1); + + auto describe = [&]() { + return setup.DescribeConsumer(TString{TEST_TOPIC}, TString{TEST_CONSUMER}); + }; + + auto write = [&](size_t seqNo) { + TTopicClient client(setup.MakeDriver()); + + TWriteSessionSettings settings; + settings.Path(TEST_TOPIC); + settings.PartitionId(0); + settings.DeduplicationEnabled(false); + auto session = client.CreateSimpleBlockingWriteSession(settings); + + TWriteMessage msg(TStringBuilder() << "message_" << seqNo); + msg.CreateTimestamp(TInstant::Now() - TDuration::Seconds(10 - seqNo)); + UNIT_ASSERT(session->Write(std::move(msg))); + + session->Close(TDuration::Seconds(5)); + }; + + // Check describe for empty topic + { + auto d = describe(); + UNIT_ASSERT_STRINGS_EQUAL(TEST_CONSUMER, d.GetConsumer().GetConsumerName()); + UNIT_ASSERT_VALUES_EQUAL(1, d.GetPartitions().size()); + auto& p = d.GetPartitions()[0]; + UNIT_ASSERT_VALUES_EQUAL(0, p.GetPartitionId()); + UNIT_ASSERT_VALUES_EQUAL(true, p.GetActive()); + UNIT_ASSERT_VALUES_EQUAL(0, p.GetPartitionStats()->GetEndOffset()); + auto& c = p.GetPartitionConsumerStats(); + UNIT_ASSERT_VALUES_EQUAL(true, c.has_value()); + UNIT_ASSERT_VALUES_EQUAL(0, c->GetCommittedOffset()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxWriteTimeLag()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxReadTimeLag()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxCommittedTimeLag()); + UNIT_ASSERT_TIME_EQUAL(TInstant::Now(), c->GetLastReadTime(), TDuration::Seconds(3)); // why not zero? + UNIT_ASSERT_VALUES_EQUAL(0, c->GetLastReadOffset()); + } + + write(3); + write(7); + + // Check describe for topic which contains messages, but consumer hasn`t read + { + auto d = describe(); + UNIT_ASSERT_STRINGS_EQUAL(TEST_CONSUMER, d.GetConsumer().GetConsumerName()); + UNIT_ASSERT_VALUES_EQUAL(1, d.GetPartitions().size()); + auto& p = d.GetPartitions()[0]; + UNIT_ASSERT_VALUES_EQUAL(0, p.GetPartitionId()); + UNIT_ASSERT_VALUES_EQUAL(true, p.GetActive()); + UNIT_ASSERT_VALUES_EQUAL(2, p.GetPartitionStats()->GetEndOffset()); + auto& c = p.GetPartitionConsumerStats(); + UNIT_ASSERT_VALUES_EQUAL(true, c.has_value()); + UNIT_ASSERT_VALUES_EQUAL(0, c->GetCommittedOffset()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(7), c->GetMaxWriteTimeLag()); // + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxReadTimeLag()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxCommittedTimeLag()); + UNIT_ASSERT_TIME_EQUAL(TInstant::Now(), c->GetLastReadTime(), TDuration::Seconds(3)); // why not zero? + UNIT_ASSERT_VALUES_EQUAL(1, c->GetLastReadOffset()); + } + + UNIT_ASSERT(setup.Commit(TString{TEST_TOPIC}, TEST_CONSUMER, 0, 1).IsSuccess()); + + // Check describe for topic whis contains messages, has commited offset but hasn`t read (restart tablet for example) + { + auto d = describe(); + UNIT_ASSERT_STRINGS_EQUAL(TEST_CONSUMER, d.GetConsumer().GetConsumerName()); + UNIT_ASSERT_VALUES_EQUAL(1, d.GetPartitions().size()); + auto& p = d.GetPartitions()[0]; + UNIT_ASSERT_VALUES_EQUAL(0, p.GetPartitionId()); + UNIT_ASSERT_VALUES_EQUAL(true, p.GetActive()); + UNIT_ASSERT_VALUES_EQUAL(2, p.GetPartitionStats()->GetEndOffset()); + auto& c = p.GetPartitionConsumerStats(); + UNIT_ASSERT_VALUES_EQUAL(true, c.has_value()); + UNIT_ASSERT_VALUES_EQUAL(1, c->GetCommittedOffset()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(7), c->GetMaxWriteTimeLag()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxReadTimeLag()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxCommittedTimeLag()); + UNIT_ASSERT_TIME_EQUAL(TInstant::Now(), c->GetLastReadTime(), TDuration::Seconds(3)); // why not zero? + UNIT_ASSERT_VALUES_EQUAL(1, c->GetLastReadOffset()); + } + + { + TTopicClient client(setup.MakeDriver()); + TReadSessionSettings settings; + settings.ConsumerName(TEST_CONSUMER); + settings.AppendTopics(TTopicReadSettings().Path(TEST_TOPIC)); + + auto session = client.CreateReadSession(settings); + + TInstant endTime = TInstant::Now() + TDuration::Seconds(5); + while (true) { + auto e = session->GetEvent(); + if (e) { + Cerr << ">>>>> Event = " << e->index() << Endl << Flush; + } + if (e && std::holds_alternative(e.value())) { + // we must recive only one date event with second message + break; + } else if (e && std::holds_alternative(e.value())) { + std::get(e.value()).Confirm(); + } + UNIT_ASSERT_C(endTime > TInstant::Now(), "Unable wait"); + } + } + + // Check describe for topic wich contains messages, has commited offset of first message and read second message + { + auto d = describe(); + UNIT_ASSERT_STRINGS_EQUAL(TEST_CONSUMER, d.GetConsumer().GetConsumerName()); + UNIT_ASSERT_VALUES_EQUAL(1, d.GetPartitions().size()); + auto& p = d.GetPartitions()[0]; + UNIT_ASSERT_VALUES_EQUAL(0, p.GetPartitionId()); + UNIT_ASSERT_VALUES_EQUAL(true, p.GetActive()); + UNIT_ASSERT_VALUES_EQUAL(2, p.GetPartitionStats()->GetEndOffset()); + auto& c = p.GetPartitionConsumerStats(); + UNIT_ASSERT_VALUES_EQUAL(true, c.has_value()); + UNIT_ASSERT_VALUES_EQUAL(1, c->GetCommittedOffset()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(7), c->GetMaxWriteTimeLag()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxReadTimeLag()); + UNIT_ASSERT_VALUES_EQUAL(TDuration::Seconds(0), c->GetMaxCommittedTimeLag()); + UNIT_ASSERT_TIME_EQUAL(TInstant::Now(), c->GetLastReadTime(), TDuration::Seconds(3)); + UNIT_ASSERT_VALUES_EQUAL(2, c->GetLastReadOffset()); + } + + } +} + +} // namespace NKikimr diff --git a/ydb/core/persqueue/ut/ut_with_sdk/ya.make b/ydb/core/persqueue/ut/ut_with_sdk/ya.make index fdb6c2ff4054..eb370dff0244 100644 --- a/ydb/core/persqueue/ut/ut_with_sdk/ya.make +++ b/ydb/core/persqueue/ut/ut_with_sdk/ya.make @@ -32,6 +32,7 @@ SRCS( autoscaling_ut.cpp balancing_ut.cpp mirrorer_ut.cpp + topic_ut.cpp ) END() diff --git a/ydb/core/protos/pqconfig.proto b/ydb/core/protos/pqconfig.proto index 2f27923c359e..b2c682c588fb 100644 --- a/ydb/core/protos/pqconfig.proto +++ b/ydb/core/protos/pqconfig.proto @@ -751,6 +751,7 @@ message TClientInfo { optional uint64 ReadLagMs = 5; optional uint64 LastReadTimestampMs = 8; optional uint64 TotalLagMs = 9; + optional uint64 CommitedLagMs = 10; } @@ -851,6 +852,7 @@ message TStatusResponse { optional uint64 CommitedOffset = 9; optional bool ReadingFinished = 10; + optional uint64 CommitedLagMs = 11; } diff --git a/ydb/public/api/protos/ydb_topic.proto b/ydb/public/api/protos/ydb_topic.proto index a45a8c673140..5ac93836d158 100644 --- a/ydb/public/api/protos/ydb_topic.proto +++ b/ydb/public/api/protos/ydb_topic.proto @@ -810,6 +810,8 @@ message Consumer { google.protobuf.Duration max_read_time_lag = 2; // Maximum of differences between write timestamp and create timestamp for all messages, read during last minute. google.protobuf.Duration max_write_time_lag = 3; + // The difference between the write timestamp of the last commited message and the current time. + google.protobuf.Duration max_committed_time_lag = 5; // Bytes read statistics. MultipleWindowsStat bytes_read = 4; } @@ -1214,6 +1216,8 @@ message DescribeConsumerResult { google.protobuf.Duration max_read_time_lag = 6; // Maximum of differences between write timestamp and create timestamp for all messages, read during last minute. google.protobuf.Duration max_write_time_lag = 7; + // The difference between the write timestamp of the last commited message and the current time. + google.protobuf.Duration max_committed_time_lag = 13; // How much bytes were read during several windows statistics from this partition. MultipleWindowsStat bytes_read = 8; diff --git a/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/topic/control_plane.h b/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/topic/control_plane.h index c776e3f5b45a..09611b1e07c3 100644 --- a/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/topic/control_plane.h +++ b/ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/topic/control_plane.h @@ -111,6 +111,7 @@ class TPartitionConsumerStats { const TInstant& GetLastReadTime() const; const TDuration& GetMaxReadTimeLag() const; const TDuration& GetMaxWriteTimeLag() const; + const TDuration& GetMaxCommittedTimeLag() const; private: uint64_t CommittedOffset_; @@ -120,6 +121,7 @@ class TPartitionConsumerStats { TInstant LastReadTime_; TDuration MaxReadTimeLag_; TDuration MaxWriteTimeLag_; + TDuration MaxCommittedTimeLag_; }; // Topic partition location diff --git a/ydb/public/sdk/cpp/src/client/topic/impl/topic.cpp b/ydb/public/sdk/cpp/src/client/topic/impl/topic.cpp index 280cd800b599..1717f29cd7eb 100644 --- a/ydb/public/sdk/cpp/src/client/topic/impl/topic.cpp +++ b/ydb/public/sdk/cpp/src/client/topic/impl/topic.cpp @@ -376,6 +376,7 @@ TPartitionConsumerStats::TPartitionConsumerStats(const Ydb::Topic::DescribeConsu , LastReadTime_(TInstant::Seconds(partitionStats.last_read_time().seconds())) , MaxReadTimeLag_(TDuration::Seconds(partitionStats.max_read_time_lag().seconds())) , MaxWriteTimeLag_(TDuration::Seconds(partitionStats.max_write_time_lag().seconds())) + , MaxCommittedTimeLag_(TDuration::Seconds(partitionStats.max_committed_time_lag().seconds())) {} uint64_t TPartitionConsumerStats::GetCommittedOffset() const { @@ -406,6 +407,10 @@ const TDuration& TPartitionConsumerStats::GetMaxWriteTimeLag() const { return MaxWriteTimeLag_; } +const TDuration& TPartitionConsumerStats::GetMaxCommittedTimeLag() const { + return MaxCommittedTimeLag_; +} + TPartitionLocation::TPartitionLocation(const Ydb::Topic::PartitionLocation& partitionLocation) : NodeId_(partitionLocation.node_id()) , Generation_(partitionLocation.generation()) diff --git a/ydb/public/sdk/cpp/src/client/topic/ut/ut_utils/topic_sdk_test_setup.cpp b/ydb/public/sdk/cpp/src/client/topic/ut/ut_utils/topic_sdk_test_setup.cpp index c3253d1ea766..b61ec85322e8 100644 --- a/ydb/public/sdk/cpp/src/client/topic/ut/ut_utils/topic_sdk_test_setup.cpp +++ b/ydb/public/sdk/cpp/src/client/topic/ut/ut_utils/topic_sdk_test_setup.cpp @@ -66,6 +66,27 @@ TTopicDescription TTopicSdkTestSetup::DescribeTopic(const TString& path) return status.GetTopicDescription(); } +TConsumerDescription TTopicSdkTestSetup::DescribeConsumer(const TString& path, const TString& consumer) +{ + TTopicClient client(MakeDriver()); + + TDescribeConsumerSettings settings; + settings.IncludeStats(true); + settings.IncludeLocation(true); + + auto status = client.DescribeConsumer(path, consumer, settings).GetValueSync(); + UNIT_ASSERT(status.IsSuccess()); + + return status.GetConsumerDescription(); +} + +TStatus TTopicSdkTestSetup::Commit(const TString& path, const TString& consumerName, size_t partitionId, size_t offset) { + TTopicClient client(MakeDriver()); + + return client.CommitOffset(path, partitionId, consumerName, offset).GetValueSync(); +} + + TString TTopicSdkTestSetup::GetEndpoint() const { return "localhost:" + ToString(Server.GrpcPort); } diff --git a/ydb/public/sdk/cpp/src/client/topic/ut/ut_utils/topic_sdk_test_setup.h b/ydb/public/sdk/cpp/src/client/topic/ut/ut_utils/topic_sdk_test_setup.h index 3473b883b7ce..4b6ee30e2968 100644 --- a/ydb/public/sdk/cpp/src/client/topic/ut/ut_utils/topic_sdk_test_setup.h +++ b/ydb/public/sdk/cpp/src/client/topic/ut/ut_utils/topic_sdk_test_setup.h @@ -22,6 +22,9 @@ class TTopicSdkTestSetup { size_t maxPartitionCount = 100); TTopicDescription DescribeTopic(const TString& path = TString{TEST_TOPIC}); + TConsumerDescription DescribeConsumer(const TString& path = TString{TEST_TOPIC}, const TString& consumer = TString{TEST_CONSUMER}); + + TStatus Commit(const TString& path, const TString& consumerName, size_t partitionId, size_t offset); TString GetEndpoint() const; TString GetTopicPath(const TString& name = TString{TEST_TOPIC}) const; diff --git a/ydb/services/persqueue_v1/actors/schema_actors.cpp b/ydb/services/persqueue_v1/actors/schema_actors.cpp index bfd6519c95ae..fd1ac8a47a35 100644 --- a/ydb/services/persqueue_v1/actors/schema_actors.cpp +++ b/ydb/services/persqueue_v1/actors/schema_actors.cpp @@ -874,12 +874,14 @@ void TDescribeTopicActor::ApplyResponse(TTabletInfo& tabletInfo, NKikimr::TEvPer SetProtoTime(stats->mutable_min_partitions_last_read_time(), cons.GetLastReadTimestampMs()); SetProtoTime(stats->mutable_max_read_time_lag(), cons.GetReadLagMs()); SetProtoTime(stats->mutable_max_write_time_lag(), cons.GetWriteLagMs()); + SetProtoTime(stats->mutable_max_committed_time_lag(), cons.GetCommitedLagMs()); } else { auto* stats = it->second->mutable_consumer_stats(); UpdateProtoTime(stats->mutable_min_partitions_last_read_time(), cons.GetLastReadTimestampMs(), true); UpdateProtoTime(stats->mutable_max_read_time_lag(), cons.GetReadLagMs(), false); UpdateProtoTime(stats->mutable_max_write_time_lag(), cons.GetWriteLagMs(), false); + UpdateProtoTime(stats->mutable_max_committed_time_lag(), cons.GetCommitedLagMs(), false); } AddWindowsStat(it->second->mutable_consumer_stats()->mutable_bytes_read(), cons.GetAvgReadSpeedPerMin(), cons.GetAvgReadSpeedPerHour(), cons.GetAvgReadSpeedPerDay()); @@ -988,6 +990,7 @@ void TDescribeConsumerActor::ApplyResponse(TTabletInfo& tabletInfo, NKikimr::TEv SetProtoTime(consStats->mutable_last_read_time(), partResult.GetLagsInfo().GetLastReadTimestampMs()); SetProtoTime(consStats->mutable_max_read_time_lag(), partResult.GetLagsInfo().GetReadLagMs()); SetProtoTime(consStats->mutable_max_write_time_lag(), partResult.GetLagsInfo().GetWriteLagMs()); + SetProtoTime(consStats->mutable_max_committed_time_lag(), partResult.GetLagsInfo().GetCommitedLagMs()); AddWindowsStat(consStats->mutable_bytes_read(), partResult.GetAvgReadSpeedPerMin(), partResult.GetAvgReadSpeedPerHour(), partResult.GetAvgReadSpeedPerDay()); @@ -997,12 +1000,14 @@ void TDescribeConsumerActor::ApplyResponse(TTabletInfo& tabletInfo, NKikimr::TEv SetProtoTime(stats->mutable_min_partitions_last_read_time(), partResult.GetLagsInfo().GetLastReadTimestampMs()); SetProtoTime(stats->mutable_max_read_time_lag(), partResult.GetLagsInfo().GetReadLagMs()); SetProtoTime(stats->mutable_max_write_time_lag(), partResult.GetLagsInfo().GetWriteLagMs()); + SetProtoTime(stats->mutable_max_committed_time_lag(), partResult.GetLagsInfo().GetCommitedLagMs()); } else { auto* stats = Result.mutable_consumer()->mutable_consumer_stats(); UpdateProtoTime(stats->mutable_min_partitions_last_read_time(), partResult.GetLagsInfo().GetLastReadTimestampMs(), true); UpdateProtoTime(stats->mutable_max_read_time_lag(), partResult.GetLagsInfo().GetReadLagMs(), false); UpdateProtoTime(stats->mutable_max_write_time_lag(), partResult.GetLagsInfo().GetWriteLagMs(), false); + UpdateProtoTime(stats->mutable_max_committed_time_lag(), partResult.GetLagsInfo().GetCommitedLagMs(), false); } } } From 0f2ed8db38e568f577b0c046c331519e6caf30b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9E=D0=BB=D0=B5=D0=B3?= <150132506+iddqdex@users.noreply.github.com> Date: Wed, 9 Apr 2025 15:37:30 +0300 Subject: [PATCH 095/454] Fix tpch canonization (#16983) --- ydb/library/benchmarks/queries/tpch/pg/q18.sql | 3 ++- ydb/library/benchmarks/queries/tpch/pg/q3.sql | 3 ++- ydb/library/benchmarks/queries/tpch/yql/q18.sql | 3 ++- ydb/library/benchmarks/queries/tpch/yql/q3.sql | 5 +++-- ydb/library/workload/tpch/s10000_canonical/q1.result | 2 +- ydb/library/workload/tpch/s10000_canonical/q10.result | 2 +- ydb/library/workload/tpch/s10000_canonical/q17.result | 2 ++ ydb/library/workload/tpch/s10000_canonical/q18.result | 3 +++ ydb/library/workload/tpch/s10000_canonical/q20.result | 3 +++ ydb/library/workload/tpch/s10000_canonical/q21.result | 3 +++ ydb/library/workload/tpch/s10000_canonical/q3.result | 2 +- ydb/library/workload/tpch/s10000_canonical/q9.result | 3 +++ ydb/tests/olap/load/lib/tpch.py | 2 +- 13 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 ydb/library/workload/tpch/s10000_canonical/q17.result create mode 100644 ydb/library/workload/tpch/s10000_canonical/q18.result create mode 100644 ydb/library/workload/tpch/s10000_canonical/q20.result create mode 100644 ydb/library/workload/tpch/s10000_canonical/q21.result create mode 100644 ydb/library/workload/tpch/s10000_canonical/q9.result diff --git a/ydb/library/benchmarks/queries/tpch/pg/q18.sql b/ydb/library/benchmarks/queries/tpch/pg/q18.sql index 7f9a26c90f80..fa0dc534fd5d 100644 --- a/ydb/library/benchmarks/queries/tpch/pg/q18.sql +++ b/ydb/library/benchmarks/queries/tpch/pg/q18.sql @@ -35,7 +35,8 @@ group by o_totalprice order by o_totalprice desc, - o_orderdate + o_orderdate, + o_orderkey limit 100; diff --git a/ydb/library/benchmarks/queries/tpch/pg/q3.sql b/ydb/library/benchmarks/queries/tpch/pg/q3.sql index d30016631b23..fad89e76a02a 100644 --- a/ydb/library/benchmarks/queries/tpch/pg/q3.sql +++ b/ydb/library/benchmarks/queries/tpch/pg/q3.sql @@ -26,6 +26,7 @@ group by o_shippriority order by revenue desc, - o_orderdate + o_orderdate, + l_orderkey limit 10; diff --git a/ydb/library/benchmarks/queries/tpch/yql/q18.sql b/ydb/library/benchmarks/queries/tpch/yql/q18.sql index 1917d35d81d0..839d7c8cf00e 100644 --- a/ydb/library/benchmarks/queries/tpch/yql/q18.sql +++ b/ydb/library/benchmarks/queries/tpch/yql/q18.sql @@ -50,5 +50,6 @@ group by j.o_totalprice order by o_totalprice desc, - o_orderdate + o_orderdate, + o_orderkey limit 100; diff --git a/ydb/library/benchmarks/queries/tpch/yql/q3.sql b/ydb/library/benchmarks/queries/tpch/yql/q3.sql index 6f3d0b905828..a815e7c306f6 100644 --- a/ydb/library/benchmarks/queries/tpch/yql/q3.sql +++ b/ydb/library/benchmarks/queries/tpch/yql/q3.sql @@ -47,7 +47,7 @@ where select l_orderkey, - sum(l_extendedprice * ($z1_12 - l_discount)) as revenue, + $round(sum(l_extendedprice * ($z1_12 - l_discount)), -2) as revenue, o_orderdate, o_shippriority from @@ -58,5 +58,6 @@ group by o_shippriority order by revenue desc, - o_orderdate + o_orderdate, + l_orderkey limit 10; diff --git a/ydb/library/workload/tpch/s10000_canonical/q1.result b/ydb/library/workload/tpch/s10000_canonical/q1.result index 5d67d2029a36..2a1559b221e5 100644 --- a/ydb/library/workload/tpch/s10000_canonical/q1.result +++ b/ydb/library/workload/tpch/s10000_canonical/q1.result @@ -1,3 +1,3 @@ l_returnflag,l_linestatus,sum_qty,sum_base_price,sum_disc_price,sum_charge,avg_qty,avg_price,avg_disc,count_order -A,F,3.775711377e+11,5.66171807e+14,5.378625747e+14,5.59376974e+14,25.5+-0.01,38237.28+-0.01,0.05+-0.01,14802885380 +A,F,3.775711377e+11,5.66171807e+14,5.378625747e+14,5.59376974e+14,25.5+-0.01,38237.28+-0.01,0.05+-0.01,14806799886 ... \ No newline at end of file diff --git a/ydb/library/workload/tpch/s10000_canonical/q10.result b/ydb/library/workload/tpch/s10000_canonical/q10.result index c96c8c2c4ca4..f5301ddcc98f 100644 --- a/ydb/library/workload/tpch/s10000_canonical/q10.result +++ b/ydb/library/workload/tpch/s10000_canonical/q10.result @@ -1,3 +1,3 @@ c_custkey,c_name,revenue,c_acctbal,n_name,c_address,c_phone,c_comment -883656898,Customer#883656898,4676163.4255,2487.44,MOROCCO,"6Temru GsGPkOQ",25-465-335-3565,"ites across the blithely regular pinto beans cajole quickly carefully ironic pinto beans. furiousdep" +883656898,Customer#883656898,4676163.4255,2487.44,MOROCCO,"6Temru GsGPkOQ",25-465-335-3565,"ites across the blithely regular pinto beans cajole quickly carefully ironic pinto beans. furious dep" ... \ No newline at end of file diff --git a/ydb/library/workload/tpch/s10000_canonical/q17.result b/ydb/library/workload/tpch/s10000_canonical/q17.result new file mode 100644 index 000000000000..c078421250c4 --- /dev/null +++ b/ydb/library/workload/tpch/s10000_canonical/q17.result @@ -0,0 +1,2 @@ +avg_yearly +140373742.0 \ No newline at end of file diff --git a/ydb/library/workload/tpch/s10000_canonical/q18.result b/ydb/library/workload/tpch/s10000_canonical/q18.result new file mode 100644 index 000000000000..c4d22d77f28d --- /dev/null +++ b/ydb/library/workload/tpch/s10000_canonical/q18.result @@ -0,0 +1,3 @@ +c_name,c_custkey,o_orderkey,o_orderdate,o_totalprice,sum_l_quantity +Customer#468790567,468790567,1851977413,1993-10-12,618092.3,335 +... \ No newline at end of file diff --git a/ydb/library/workload/tpch/s10000_canonical/q20.result b/ydb/library/workload/tpch/s10000_canonical/q20.result new file mode 100644 index 000000000000..56895f79ca01 --- /dev/null +++ b/ydb/library/workload/tpch/s10000_canonical/q20.result @@ -0,0 +1,3 @@ +s_name,s_address +Supplier#000000020,"iybAE,RmTymrZVYaFZva2SH,j" +... \ No newline at end of file diff --git a/ydb/library/workload/tpch/s10000_canonical/q21.result b/ydb/library/workload/tpch/s10000_canonical/q21.result new file mode 100644 index 000000000000..ea9d6972a222 --- /dev/null +++ b/ydb/library/workload/tpch/s10000_canonical/q21.result @@ -0,0 +1,3 @@ +s_name,numwait +Supplier#044953064,133 +... \ No newline at end of file diff --git a/ydb/library/workload/tpch/s10000_canonical/q3.result b/ydb/library/workload/tpch/s10000_canonical/q3.result index 79d1b6212181..96f1892ea56c 100644 --- a/ydb/library/workload/tpch/s10000_canonical/q3.result +++ b/ydb/library/workload/tpch/s10000_canonical/q3.result @@ -1,3 +1,3 @@ l_orderkey,revenue,o_orderdate,o_shippriority -35314204736 ,510414.04,1995-02-13,0 +954466400,510414.04,1995-02-13,0 ... \ No newline at end of file diff --git a/ydb/library/workload/tpch/s10000_canonical/q9.result b/ydb/library/workload/tpch/s10000_canonical/q9.result new file mode 100644 index 000000000000..d0bd5b8988fd --- /dev/null +++ b/ydb/library/workload/tpch/s10000_canonical/q9.result @@ -0,0 +1,3 @@ +nation,o_year,sum_profit +ALGERIA,1998,273173498787.0 +... \ No newline at end of file diff --git a/ydb/tests/olap/load/lib/tpch.py b/ydb/tests/olap/load/lib/tpch.py index 8b64960dc571..cef7adf4fe7f 100644 --- a/ydb/tests/olap/load/lib/tpch.py +++ b/ydb/tests/olap/load/lib/tpch.py @@ -78,7 +78,7 @@ class TestTpch1000(TpchSuiteBase): 'lineitem': 5999989709, } scale: int = 1000 - check_canonical: bool = CheckCanonicalPolicy.WARNING + check_canonical: bool = CheckCanonicalPolicy.ERROR timeout = max(TpchSuiteBase.timeout, 3600.) From 78dd44a66dabf814956a243b4a50c0c1ea6c0abb Mon Sep 17 00:00:00 2001 From: Roman Udovichenko Date: Wed, 9 Apr 2025 15:44:45 +0300 Subject: [PATCH 096/454] Reduce dq logs size (#16968) --- ydb/library/yql/providers/dq/planner/execution_planner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ydb/library/yql/providers/dq/planner/execution_planner.cpp b/ydb/library/yql/providers/dq/planner/execution_planner.cpp index 90bd08f2a91e..c96b807efdf7 100644 --- a/ydb/library/yql/providers/dq/planner/execution_planner.cpp +++ b/ydb/library/yql/providers/dq/planner/execution_planner.cpp @@ -149,7 +149,7 @@ namespace NYql::NDqs { auto value = expr.Maybe(); const auto maxTasksPerOperation = Settings->MaxTasksPerOperation.Get().GetOrElse(TDqSettings::TDefault::MaxTasksPerOperation); - YQL_CLOG(DEBUG, ProviderDq) << "Execution Plan " << NCommon::ExprToPrettyString(ExprContext, *DqExprRoot); + YQL_CLOG(TRACE, ProviderDq) << "Execution Plan " << NCommon::ExprToPrettyString(ExprContext, *DqExprRoot); auto stages = GetStages(DqExprRoot); YQL_ENSURE(!stages.empty()); From 8c02be7c9a260edf13714760e07bf560c803761a Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Wed, 9 Apr 2025 15:55:06 +0300 Subject: [PATCH 097/454] Intermediate changes commit_hash:82c13e8369702b168088dc96f7c8c9025d7abbb6 --- .../core/type_ann/type-ann-coverage.sh | 63 +++++++++---------- yql/essentials/scripts/collect-coverage.sh | 54 ++++++++++++++++ 2 files changed, 83 insertions(+), 34 deletions(-) create mode 100755 yql/essentials/scripts/collect-coverage.sh diff --git a/yql/essentials/core/type_ann/type-ann-coverage.sh b/yql/essentials/core/type_ann/type-ann-coverage.sh index 09a28963e570..e5336f6aac79 100755 --- a/yql/essentials/core/type_ann/type-ann-coverage.sh +++ b/yql/essentials/core/type_ann/type-ann-coverage.sh @@ -1,22 +1,38 @@ #!/bin/bash # # Script to collect the type annotation callbacks, being uncovered -# by minirun test suite. Pass the filename as the first argument +# by minirun test suite. Pass the coverage report root directory +# as the first argument, and the filename as the second argument # to store the collected list to the particular file. set -eu -ARC_ROOT=$(arc rev-parse --show-toplevel) -REPORT_ROOT=$(mktemp --tmpdir -d yql-essentials-core-type_ann-coverage-XXXXXXX) +REPORT_ROOT=$1 +# Check whether the desired prefix (i.e. yql/essentials/core/type_ann) +# is collected (see collect-coverage.sh for the contract). +COLLECTED_PREFIX=yql/essentials/core/type_ann +COLLECTED_ANCHOR=${REPORT_ROOT}/collect-coverage.sh/${COLLECTED_PREFIX}/collected +if [ ! -f ${COLLECTED_ANCHOR} ]; then + cat < Date: Wed, 9 Apr 2025 16:12:15 +0300 Subject: [PATCH 098/454] Added deviation param for test_log_scenario (#16991) --- ydb/tests/olap/test_log_scenario.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/ydb/tests/olap/test_log_scenario.py b/ydb/tests/olap/test_log_scenario.py index 9921b14ffeba..4c7e1c6ffe98 100644 --- a/ydb/tests/olap/test_log_scenario.py +++ b/ydb/tests/olap/test_log_scenario.py @@ -1,5 +1,7 @@ import datetime import os +import pytest + import random import logging @@ -19,11 +21,12 @@ class YdbWorkloadLog: - def __init__(self, endpoint: str, database: str, table_name: str): + def __init__(self, endpoint: str, database: str, table_name: str, timestamp_deviation: int): self.path: str = yatest.common.binary_path(os.environ["YDB_CLI_BINARY"]) self.endpoint: str = endpoint self.database: str = database self.begin_command: list[str] = [self.path, "-e", self.endpoint, "-d", self.database, "workload", "log", "--path", table_name] + self.timestamp_deviation = timestamp_deviation def _call(self, command: list[str], wait=False): logging.info(f'YdbWorkloadLog execute {' '.join(command)} with wait = {wait}') @@ -46,7 +49,7 @@ def _insert_rows(self, operation_name: str, seconds: int, threads: int, rows: in "--rows", str(rows), "--timestamp_deviation", - "180" + str(self.timestamp_deviation) ] self._call(command=command, wait=wait) @@ -122,13 +125,14 @@ def check_insert(self, duration: int): logging.info(f'check insert: {current_count} {prev_count}') assert current_count != prev_count - def test(self): - """As per https://github.com/ydb-platform/ydb/issues/13530""" + @pytest.mark.parametrize('timestamp_deviation', [3 * 60, 365 * 24 * 60 * 2]) # [3 hours, 2 years] + def test(self, timestamp_deviation: int): + """As per https://github.com/ydb-platform/ydb/issues/13531""" wait_time: int = int(get_external_param("wait_seconds", "30")) self.table_name: str = "log" - ydb_workload: YdbWorkloadLog = YdbWorkloadLog(endpoint=self.ydb_client.endpoint, database=self.ydb_client.database, table_name=self.table_name) + ydb_workload: YdbWorkloadLog = YdbWorkloadLog(endpoint=self.ydb_client.endpoint, database=self.ydb_client.database, table_name=self.table_name, timestamp_deviation=timestamp_deviation) ydb_workload.create_table(self.table_name) ydb_workload.bulk_upsert(seconds=10, threads=10, rows=500, wait=True) logging.info(f"Count rows after insert {self.get_row_count()} before wait") From fae3411f1a74876186ead0c72fd580259d540697 Mon Sep 17 00:00:00 2001 From: Vitalii Gridnev Date: Wed, 9 Apr 2025 16:21:04 +0300 Subject: [PATCH 099/454] fix replay with query parameter types (#16995) --- ydb/tools/query_replay_yt/main.cpp | 2 ++ ydb/tools/query_replay_yt/query_compiler.cpp | 13 +++++++++++-- ydb/tools/query_replay_yt/query_replay.h | 1 + 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/ydb/tools/query_replay_yt/main.cpp b/ydb/tools/query_replay_yt/main.cpp index 8fb058cae2ce..782eec346c62 100644 --- a/ydb/tools/query_replay_yt/main.cpp +++ b/ydb/tools/query_replay_yt/main.cpp @@ -86,6 +86,8 @@ class TQueryReplayMapper return "uncategorized_plan_mismatch"; case TQueryReplayEvents::MissingTableMetadata: return "missing_table_metadata"; + case TQueryReplayEvents::UncategorizedFailure: + return "uncategorized_failure"; default: return "unspecified"; } diff --git a/ydb/tools/query_replay_yt/query_compiler.cpp b/ydb/tools/query_replay_yt/query_compiler.cpp index 1168e0138291..d50160ccbf88 100644 --- a/ydb/tools/query_replay_yt/query_compiler.cpp +++ b/ydb/tools/query_replay_yt/query_compiler.cpp @@ -548,7 +548,9 @@ class TReplayCompileActor: public TActorBootstrapped { Y_UNUSED(queryPlan); if (status != Ydb::StatusIds::SUCCESS) { ev->Success = false; - if (MetadataLoader->HasMissingTableMetadata()) { + if (!MetadataLoader) { + ev->Status = TQueryReplayEvents::UncategorizedFailure; + } else if (MetadataLoader->HasMissingTableMetadata()) { ev->Status = TQueryReplayEvents::MissingTableMetadata; } else if (status == Ydb::StatusIds::TIMEOUT) { ev->Status = TQueryReplayEvents::CompileTimeout; @@ -578,7 +580,14 @@ class TReplayCompileActor: public TActorBootstrapped { std::map queryParameterTypes; if (ReplayDetails.Has("query_parameter_types")) { - for (const auto& [paramName, paramType] : ReplayDetails["query_parameter_types"].GetMapSafe()) { + NJson::TJsonValue qpt; + Y_ENSURE(ReplayDetails["query_parameter_types"].IsString()); + static NJson::TJsonReaderConfig readConfig; + TStringInput in(ReplayDetails["query_parameter_types"].GetStringSafe()); + NJson::ReadJsonTree(&in, &readConfig, &qpt, false); + + Y_ENSURE(qpt.IsMap()); + for (const auto& [paramName, paramType] : qpt.GetMapSafe()) { if (!queryParameterTypes[paramName].ParseFromString(Base64Decode(paramType.GetStringSafe()))) { queryParameterTypes.erase(paramName); } diff --git a/ydb/tools/query_replay_yt/query_replay.h b/ydb/tools/query_replay_yt/query_replay.h index 91164b2c47c7..36f9a4d4c643 100644 --- a/ydb/tools/query_replay_yt/query_replay.h +++ b/ydb/tools/query_replay_yt/query_replay.h @@ -55,6 +55,7 @@ struct TQueryReplayEvents { WriteColumnsMismatch, UncategorizedPlanMismatch, MissingTableMetadata, + UncategorizedFailure, Unspecified, }; From 51016b5bd58ceae9cd9e56aaa4b52a0a12174221 Mon Sep 17 00:00:00 2001 From: vityaman Date: Wed, 9 Apr 2025 15:56:28 +0300 Subject: [PATCH 100/454] YQL-19616 Fix regex lexer Fixed regex lexer issues: - `TSKIP` token recognition - `HEXGIGITS` number recognition - `EOF` token content --- - Related to https://github.com/ydb-platform/ydb/issues/15129 - Related to https://github.com/vityaman/ydb/issues/11 --- Pull Request resolved: https://github.com/ytsaurus/ytsaurus/pull/1190 commit_hash:497c39efcbbe4e387da523b5e2c8abaa6485d93b --- yql/essentials/sql/v1/lexer/lexer_ut.cpp | 12 +++++++++--- yql/essentials/sql/v1/lexer/regex/lexer.cpp | 9 ++++++--- yql/essentials/sql/v1/lexer/regex/lexer_ut.cpp | 2 +- yql/essentials/sql/v1/lexer/regex/regex_ut.cpp | 2 +- yql/essentials/sql/v1/reflect/sql_reflect.cpp | 9 ++++++++- yql/essentials/sql/v1/reflect/sql_reflect.h | 2 ++ 6 files changed, 27 insertions(+), 9 deletions(-) diff --git a/yql/essentials/sql/v1/lexer/lexer_ut.cpp b/yql/essentials/sql/v1/lexer/lexer_ut.cpp index 549dc9d8fa96..8f5b6d69e9b3 100644 --- a/yql/essentials/sql/v1/lexer/lexer_ut.cpp +++ b/yql/essentials/sql/v1/lexer/lexer_ut.cpp @@ -28,7 +28,7 @@ using namespace NSQLTranslationV1; TLexers Lexers = { .Antlr3 = MakeAntlr3LexerFactory(), - .Antlr3Ansi = MakeAntlr4AnsiLexerFactory(), + .Antlr3Ansi = MakeAntlr3AnsiLexerFactory(), .Antlr4 = MakeAntlr4LexerFactory(), .Antlr4Ansi = MakeAntlr4AnsiLexerFactory(), .Antlr4Pure = MakeAntlr4PureLexerFactory(), @@ -307,6 +307,11 @@ Y_UNIT_TEST_SUITE(SQLv1Lexer) { UNIT_ASSERT_TOKENIZED(lexer, "INSERT", "INSERT EOF"); UNIT_ASSERT_TOKENIZED(lexer, "FROM", "FROM EOF"); UNIT_ASSERT_TOKENIZED(lexer, "from", "FROM(from) EOF"); + if (ANTLR4 || FLAVOR == ELexerFlavor::Regex) { + UNIT_ASSERT_TOKENIZED(lexer, "sKip", "TSKIP(sKip) EOF"); + } else { + UNIT_ASSERT_TOKENIZED(lexer, "sKip", "SKIP(sKip) EOF"); + } } Y_UNIT_TEST_ON_EACH_LEXER(Punctuation) { @@ -337,6 +342,7 @@ Y_UNIT_TEST_SUITE(SQLv1Lexer) { UNIT_ASSERT_TOKENIZED(lexer, "123", "DIGITS(123) EOF"); UNIT_ASSERT_TOKENIZED(lexer, "123u", "INTEGER_VALUE(123u) EOF"); UNIT_ASSERT_TOKENIZED(lexer, "123ui", "INTEGER_VALUE(123ui) EOF"); + UNIT_ASSERT_TOKENIZED(lexer, "0xDEADbeef", "DIGITS(0xDEADbeef) EOF"); UNIT_ASSERT_TOKENIZED(lexer, "123.45", "REAL(123.45) EOF"); UNIT_ASSERT_TOKENIZED(lexer, "123.45E10", "REAL(123.45E10) EOF"); UNIT_ASSERT_TOKENIZED(lexer, "123.45E+10", "REAL(123.45E+10) EOF"); @@ -353,7 +359,7 @@ Y_UNIT_TEST_SUITE(SQLv1Lexer) { if (!ANSI) { UNIT_ASSERT_TOKENIZED(lexer, "\"\\\"\"", "STRING_VALUE(\"\\\"\") EOF"); UNIT_ASSERT_TOKENIZED(lexer, "\"\"\"\"", "STRING_VALUE(\"\") STRING_VALUE(\"\") EOF"); - } else { + } else if (ANTLR4 || FLAVOR == ELexerFlavor::Regex) { UNIT_ASSERT_TOKENIZED(lexer, "\"\\\"\"", "[INVALID] STRING_VALUE(\"\\\") EOF"); UNIT_ASSERT_TOKENIZED(lexer, "\"\"\"\"", "STRING_VALUE(\"\"\"\") EOF"); } @@ -387,7 +393,7 @@ Y_UNIT_TEST_SUITE(SQLv1Lexer) { if (!ANSI) { UNIT_ASSERT_TOKENIZED(lexer, "/* /* yql */", "COMMENT(/* /* yql */) EOF"); UNIT_ASSERT_TOKENIZED(lexer, "/* /* yql */ */", "COMMENT(/* /* yql */) WS( ) ASTERISK(*) SLASH(/) EOF"); - } else { + } else if (ANTLR4 || FLAVOR == ELexerFlavor::Regex) { UNIT_ASSERT_TOKENIZED(lexer, "/* /* yql */", "COMMENT(/* /* yql */) EOF"); UNIT_ASSERT_TOKENIZED(lexer, "/* yql */ */", "COMMENT(/* yql */) WS( ) ASTERISK(*) SLASH(/) EOF"); UNIT_ASSERT_TOKENIZED(lexer, "/* /* /* yql */ */", "COMMENT(/* /* /* yql */ */) EOF"); diff --git a/yql/essentials/sql/v1/lexer/regex/lexer.cpp b/yql/essentials/sql/v1/lexer/regex/lexer.cpp index b8ca033b0c6a..9f96e444ac77 100644 --- a/yql/essentials/sql/v1/lexer/regex/lexer.cpp +++ b/yql/essentials/sql/v1/lexer/regex/lexer.cpp @@ -28,11 +28,14 @@ namespace NSQLTranslationV1 { : Grammar_(std::move(grammar)) , Ansi_(ansi) { + RE2::Options custom; + custom.set_longest_match(true); + for (const auto& [token, regex] : RegexByOtherName) { if (token == CommentTokenName) { CommentRegex_.Reset(new RE2(regex)); } else { - OtherRegexes_.emplace_back(token, new RE2(regex)); + OtherRegexes_.emplace_back(token, new RE2(regex, custom)); } } } @@ -62,7 +65,7 @@ namespace NSQLTranslationV1 { onNextToken(std::move(matched)); } - onNextToken(TParsedToken{.Name = "EOF"}); + onNextToken(TParsedToken{.Name = "EOF", .Content = ""}); return errors == 0; } @@ -110,7 +113,7 @@ namespace NSQLTranslationV1 { size_t count = 0; for (const auto& keyword : Grammar_.KeywordNames) { const TStringBuf content = prefix.substr(0, keyword.length()); - if (AsciiEqualsIgnoreCase(content, keyword)) { + if (AsciiEqualsIgnoreCase(content, NSQLReflect::TLexerGrammar::KeywordBlock(keyword))) { matches.emplace_back(keyword, TString(content)); count += 1; } diff --git a/yql/essentials/sql/v1/lexer/regex/lexer_ut.cpp b/yql/essentials/sql/v1/lexer/regex/lexer_ut.cpp index 03c84bcffe3d..6ac25008b340 100644 --- a/yql/essentials/sql/v1/lexer/regex/lexer_ut.cpp +++ b/yql/essentials/sql/v1/lexer/regex/lexer_ut.cpp @@ -216,4 +216,4 @@ Y_UNIT_TEST_SUITE(RegexLexerTests) { Check("\" SELECT", "[INVALID] WS( ) SELECT EOF"); } -} // Y_UNIT_TEST_SUITE(RegexLexerTests) \ No newline at end of file +} // Y_UNIT_TEST_SUITE(RegexLexerTests) diff --git a/yql/essentials/sql/v1/lexer/regex/regex_ut.cpp b/yql/essentials/sql/v1/lexer/regex/regex_ut.cpp index dad0b2ebd2d1..8f22bda58868 100644 --- a/yql/essentials/sql/v1/lexer/regex/regex_ut.cpp +++ b/yql/essentials/sql/v1/lexer/regex/regex_ut.cpp @@ -93,4 +93,4 @@ Y_UNIT_TEST_SUITE(SqlRegexTests) { Get(defaultRegexes, "COMMENT")); } -} // Y_UNIT_TEST_SUITE(SqlRegexTests) \ No newline at end of file +} // Y_UNIT_TEST_SUITE(SqlRegexTests) diff --git a/yql/essentials/sql/v1/reflect/sql_reflect.cpp b/yql/essentials/sql/v1/reflect/sql_reflect.cpp index c0af06e0b464..22fda0a33cd2 100644 --- a/yql/essentials/sql/v1/reflect/sql_reflect.cpp +++ b/yql/essentials/sql/v1/reflect/sql_reflect.cpp @@ -15,6 +15,13 @@ namespace NSQLReflect { const TStringBuf SectionOther = "//! section:other"; const TStringBuf FragmentPrefix = "fragment "; + const TStringBuf TLexerGrammar::KeywordBlock(const TStringBuf name) { + if (name == "TSKIP") { + return "SKIP"; + } + return name; + } + TVector GetResourceLines(const TStringBuf key) { TString text; Y_ENSURE(NResource::FindExact(key, &text)); @@ -126,7 +133,7 @@ namespace NSQLReflect { SubstGlobal(block, "'", ""); SubstGlobal(block, " ", ""); - Y_ENSURE(name == block || (name == "TSKIP" && block == "SKIP")); + Y_ENSURE(name == block || (name == "TSKIP" && block == TLexerGrammar::KeywordBlock("SKIP"))); grammar.KeywordNames.emplace(std::move(name)); } diff --git a/yql/essentials/sql/v1/reflect/sql_reflect.h b/yql/essentials/sql/v1/reflect/sql_reflect.h index ca3987068733..1f67a2f93a3d 100644 --- a/yql/essentials/sql/v1/reflect/sql_reflect.h +++ b/yql/essentials/sql/v1/reflect/sql_reflect.h @@ -12,6 +12,8 @@ namespace NSQLReflect { THashSet PunctuationNames; TVector OtherNames; THashMap BlockByName; + + static const TStringBuf KeywordBlock(const TStringBuf name); }; TLexerGrammar LoadLexerGrammar(); From 1488933736b20bc05fb1b3382aa7939ec75dd489 Mon Sep 17 00:00:00 2001 From: gryzlov-ad Date: Wed, 9 Apr 2025 16:10:12 +0300 Subject: [PATCH 101/454] Revert commit rXXXXXX, YT-23505: Introduce chaos lease commit_hash:acd02a6aad00818fd0494fe506378c03f1f581cd --- yt/yt/client/chaos_client/helpers.cpp | 9 --------- yt/yt/client/chaos_client/public.h | 5 +---- yt/yt/client/object_client/helpers.cpp | 10 ---------- yt/yt/client/object_client/helpers.h | 6 ------ yt/yt/client/object_client/public.h | 1 - .../yt/client/chaos_client/proto/chaos_lease.proto | 10 ---------- yt/yt_proto/yt/client/ya.make | 1 - 7 files changed, 1 insertion(+), 41 deletions(-) delete mode 100644 yt/yt_proto/yt/client/chaos_client/proto/chaos_lease.proto diff --git a/yt/yt/client/chaos_client/helpers.cpp b/yt/yt/client/chaos_client/helpers.cpp index 7ec2f3284d7f..8f7a289c3486 100644 --- a/yt/yt/client/chaos_client/helpers.cpp +++ b/yt/yt/client/chaos_client/helpers.cpp @@ -21,15 +21,6 @@ TReplicationCardId MakeReplicationCardId(TObjectId randomId) EntropyFromId(randomId) & 0xffff0000); } -TReplicationCardId MakeChaosLeaseId(TObjectId randomId) -{ - return MakeId( - EObjectType::ChaosLease, - CellTagFromId(randomId), - CounterFromId(randomId), - EntropyFromId(randomId) & 0xffff0000); -} - TReplicaId MakeReplicaId(TReplicationCardId replicationCardId, TReplicaIdIndex index) { return MakeId( diff --git a/yt/yt/client/chaos_client/public.h b/yt/yt/client/chaos_client/public.h index 5c50d3a806e2..4f1eb1c50ae1 100644 --- a/yt/yt/client/chaos_client/public.h +++ b/yt/yt/client/chaos_client/public.h @@ -11,10 +11,7 @@ namespace NYT::NChaosClient { //////////////////////////////////////////////////////////////////////////////// using TReplicationCardId = NObjectClient::TObjectId; -using TChaosObjectId = NObjectClient::TObjectId; -// using TReplicationCardId = TChaosObjectId; -using TReplicationCardCollocationId = TChaosObjectId; -using TChaosLeaseId = TChaosObjectId; +using TReplicationCardCollocationId = NObjectClient::TObjectId; using TReplicaId = NObjectClient::TObjectId; using TReplicationEra = ui64; using TReplicaIdIndex = ui16; diff --git a/yt/yt/client/object_client/helpers.cpp b/yt/yt/client/object_client/helpers.cpp index db59fe02b081..e7ba1b93ce19 100644 --- a/yt/yt/client/object_client/helpers.cpp +++ b/yt/yt/client/object_client/helpers.cpp @@ -256,16 +256,6 @@ bool IsChaosTableReplicaType(EObjectType type) return type == EObjectType::ChaosTableReplica; } -bool IsReplicationCardType(EObjectType type) -{ - return type == EObjectType::ReplicationCard; -} - -bool IsChaosLeaseType(EObjectType type) -{ - return type == EObjectType::ChaosLease; -} - bool IsCollocationType(EObjectType type) { return diff --git a/yt/yt/client/object_client/helpers.h b/yt/yt/client/object_client/helpers.h index 64fd9b2445c0..ac2f24714c1a 100644 --- a/yt/yt/client/object_client/helpers.h +++ b/yt/yt/client/object_client/helpers.h @@ -67,12 +67,6 @@ bool IsTableReplicaType(EObjectType type); //! Checks if the given type is a chaos replica. bool IsChaosTableReplicaType(EObjectType type); -//! Checks if the given type is a replication card. -bool IsReplicationCardType(EObjectType type); - -//! Checks if the given type is a chaos lease. -bool IsChaosLeaseType(EObjectType type); - //! Checks if the given type is a collocation. bool IsCollocationType(EObjectType type); diff --git a/yt/yt/client/object_client/public.h b/yt/yt/client/object_client/public.h index e037ce3f74ae..37a83b1b2075 100644 --- a/yt/yt/client/object_client/public.h +++ b/yt/yt/client/object_client/public.h @@ -342,7 +342,6 @@ DEFINE_ENUM(EObjectType, ((ChaosReplicatedTable) (1206)) ((ReplicationCardCollocation) (1207)) ((VirtualChaosCellMap) (1208)) - ((ChaosLease) (1209)) // Other cluster components stuff ((ClusterProxyNode) (1500)) diff --git a/yt/yt_proto/yt/client/chaos_client/proto/chaos_lease.proto b/yt/yt_proto/yt/client/chaos_client/proto/chaos_lease.proto deleted file mode 100644 index 970c8e7447ba..000000000000 --- a/yt/yt_proto/yt/client/chaos_client/proto/chaos_lease.proto +++ /dev/null @@ -1,10 +0,0 @@ -package NYT.NChaosClient.NProto; - -import "yt_proto/yt/core/misc/proto/guid.proto"; - -//////////////////////////////////////////////////////////////////////////////// - -message TChaosLease -{ } - -//////////////////////////////////////////////////////////////////////////////// diff --git a/yt/yt_proto/yt/client/ya.make b/yt/yt_proto/yt/client/ya.make index e799449115f7..dbf44fcbc892 100644 --- a/yt/yt_proto/yt/client/ya.make +++ b/yt/yt_proto/yt/client/ya.make @@ -19,7 +19,6 @@ SRCS( cell_master/proto/cell_directory.proto chaos_client/proto/replication_card.proto - chaos_client/proto/chaos_lease.proto chunk_client/proto/data_statistics.proto chunk_client/proto/chunk_meta.proto From 9e501b41a83f11a19c3ee6317f0f24721771f095 Mon Sep 17 00:00:00 2001 From: Cthulhu Date: Wed, 9 Apr 2025 16:45:36 +0300 Subject: [PATCH 102/454] Fix stale metadata with disabled encryption (#16887) (#16888) --- .../blobstorage/pdisk/blobstorage_pdisk_data.h | 18 ++++++++++++++++-- .../blobstorage/pdisk/blobstorage_pdisk_impl.h | 2 +- .../pdisk/blobstorage_pdisk_impl_metadata.cpp | 14 +++++++------- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_data.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_data.h index 508784e48ba2..2f6ce6ffe033 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_data.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_data.h @@ -428,14 +428,28 @@ struct TMetadataHeader { *this = header; } - bool CheckHash() const { + bool CheckHash(ui64 *magic) const { TPDiskHashCalculator hasher; +#ifdef DISABLE_PDISK_ENCRYPTION + if (magic) { + hasher.Hash(magic, sizeof(ui64)); + } +#else + Y_UNUSED(magic); +#endif hasher.Hash(this, sizeof(TMetadataHeader) - sizeof(THash)); return hasher.GetHashResult() == HeaderHash; } - void SetHash() { + void SetHash(const ui64 *magic) { TPDiskHashCalculator hasher; +#ifdef DISABLE_PDISK_ENCRYPTION + if (magic) { + hasher.Hash(magic, sizeof(ui64)); + } +#else + Y_UNUSED(magic); +#endif hasher.Hash(this, sizeof(TMetadataHeader) - sizeof(THash)); HeaderHash = hasher.GetHashResult(); } diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h index 553923f87596..7c2a10b2d3bc 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.h @@ -425,7 +425,7 @@ class TPDisk : public IPDisk { void DropAllMetadataRequests(); TRcBuf CreateMetadataPayload(TRcBuf& metadata, size_t offset, size_t payloadSize, ui32 sectorSize, bool encryption, - const TKey& key, ui64 sequenceNumber, ui32 recordIndex, ui32 totalRecords); + const TKey& key, ui64 sequenceNumber, ui32 recordIndex, ui32 totalRecords, const ui64 *magic); bool WriteMetadataSync(TRcBuf&& metadata, const TDiskFormat& format); static std::optional CheckMetadataFormatSector(const ui8 *data, size_t len, diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_metadata.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_metadata.cpp index f10e61dfdbf5..189fada436a5 100644 --- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_metadata.cpp +++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_metadata.cpp @@ -41,7 +41,7 @@ namespace NKikimr::NPDisk { // obtain the header and decrypt its encrypted part, then validate the hash TMetadataHeader *header = reinterpret_cast(GetBuffer()); header->Encrypt(cypher); - if (header->CheckHash()) { + if (header->CheckHash((ui64*)(void*)&PDisk->Format.ChunkKey)) { // check we have read it all const ui32 total = sizeof(TMetadataHeader) + header->Length; if (total <= Buffer.size()) { @@ -167,7 +167,7 @@ namespace NKikimr::NPDisk { auto *header = reinterpret_cast(Buffer.GetDataMut()); header->Encrypt(cypher); - if (!header->CheckHash()) { + if (!header->CheckHash((ui64*)(void*)&Format.DataKey)) { req->ErrorReason = "header has is not valid"; } else if (header->TotalRecords != 1 || header->RecordIndex != 0 || header->SequenceNumber != 0) { req->ErrorReason = "header fields are filled incorrectly"; @@ -593,7 +593,7 @@ namespace NKikimr::NPDisk { const size_t payloadSize = Min(slotSize, metadataSize - offset); TRcBuf payload = CreateMetadataPayload(write.Metadata, offset, payloadSize, Format.SectorSize, - Cfg->EnableSectorEncryption, Format.ChunkKey, Meta.NextSequenceNumber, i, numSlotsRequired); + Cfg->EnableSectorEncryption, Format.ChunkKey, Meta.NextSequenceNumber, i, numSlotsRequired, (ui64*)(void*)&Format.ChunkKey); completion->AddQuery(key, std::move(payload)); completion->CostNs += DriveModel.TimeForSizeNs(payload.size(), key.ChunkIdx, TDriveModel::OP_TYPE_WRITE); @@ -617,7 +617,7 @@ namespace NKikimr::NPDisk { } TRcBuf payload = CreateMetadataPayload(write.Metadata, 0, write.Metadata.size(), DefaultSectorSize, - true, fmt.DataKey, 0, 0, 1); + true, fmt.DataKey, 0, 0, 1, (ui64*)(void*)&fmt.DataKey); const size_t bytesToWrite = payload.size(); ui64 rawDeviceSize = 0; @@ -718,7 +718,7 @@ namespace NKikimr::NPDisk { } TRcBuf TPDisk::CreateMetadataPayload(TRcBuf& metadata, size_t offset, size_t payloadSize, ui32 sectorSize, - bool encryption, const TKey& key, ui64 sequenceNumber, ui32 recordIndex, ui32 totalRecords) { + bool encryption, const TKey& key, ui64 sequenceNumber, ui32 recordIndex, ui32 totalRecords, const ui64 *magic) { Y_VERIFY_S(offset + payloadSize <= metadata.size(), PCtx->PDiskLogPrefix); Y_VERIFY_DEBUG_S(IsPowerOf2(sectorSize), PCtx->PDiskLogPrefix); @@ -749,7 +749,7 @@ namespace NKikimr::NPDisk { .DataHash = dataHasher.GetHashResult(), }; - header->SetHash(); + header->SetHash(magic); header->EncryptData(cypher); header->Encrypt(cypher); @@ -791,7 +791,7 @@ namespace NKikimr::NPDisk { const NMeta::TSlotKey key = freeSlotKeys[i]; const size_t payloadSize = Min(slotSize, metadataSize - offset); TRcBuf payload = CreateMetadataPayload(metadata, offset, payloadSize, format.SectorSize, - Cfg->EnableSectorEncryption, format.ChunkKey, 1, i, numSlotsRequired); + Cfg->EnableSectorEncryption, format.ChunkKey, 1, i, numSlotsRequired, (ui64*)(void*)&format.ChunkKey); BlockDevice->PwriteSync(payload.data(), payload.size(), format.Offset(key.ChunkIdx, key.OffsetInSectors), {}, nullptr); } From 122c8d60dbd031e265d172e3b4f6d1346abab1f5 Mon Sep 17 00:00:00 2001 From: Victor Smirnov <53015676+vityaman@users.noreply.github.com> Date: Wed, 9 Apr 2025 17:02:29 +0300 Subject: [PATCH 103/454] YQL-19747 Improve YDB CLI completion (#16820) Signed-off-by: vityaman --- .../commands/interactive/complete/ya.make | 2 +- .../interactive/complete/yql_completer.cpp | 50 ++++++++++++++++--- .../interactive/complete/yql_completer.h | 4 +- .../interactive/highlight/color/schema.cpp | 43 ++++++++++++++++ .../interactive/highlight/color/schema.h | 29 +++++++++++ .../interactive/highlight/color/ya.make | 11 ++++ .../commands/interactive/highlight/ya.make | 5 ++ .../interactive/highlight/yql_highlighter.cpp | 38 -------------- .../interactive/highlight/yql_highlighter.h | 22 +------- .../commands/interactive/line_reader.cpp | 9 +++- .../lib/ydb_cli/commands/interactive/ya.make | 4 ++ 11 files changed, 150 insertions(+), 67 deletions(-) create mode 100644 ydb/public/lib/ydb_cli/commands/interactive/highlight/color/schema.cpp create mode 100644 ydb/public/lib/ydb_cli/commands/interactive/highlight/color/schema.h create mode 100644 ydb/public/lib/ydb_cli/commands/interactive/highlight/color/ya.make diff --git a/ydb/public/lib/ydb_cli/commands/interactive/complete/ya.make b/ydb/public/lib/ydb_cli/commands/interactive/complete/ya.make index ec285886bdc4..4f272c7d8a47 100644 --- a/ydb/public/lib/ydb_cli/commands/interactive/complete/ya.make +++ b/ydb/public/lib/ydb_cli/commands/interactive/complete/ya.make @@ -9,7 +9,7 @@ PEERDIR( yql/essentials/sql/v1/complete yql/essentials/sql/v1/lexer/antlr4_pure yql/essentials/sql/v1/lexer/antlr4_pure_ansi + ydb/public/lib/ydb_cli/commands/interactive/highlight/color ) END() - diff --git a/ydb/public/lib/ydb_cli/commands/interactive/complete/yql_completer.cpp b/ydb/public/lib/ydb_cli/commands/interactive/complete/yql_completer.cpp index 5b37a9241359..956206928fc0 100644 --- a/ydb/public/lib/ydb_cli/commands/interactive/complete/yql_completer.cpp +++ b/ydb/public/lib/ydb_cli/commands/interactive/complete/yql_completer.cpp @@ -1,5 +1,7 @@ #include "yql_completer.h" +#include + #include #include #include @@ -11,8 +13,9 @@ namespace NYdb::NConsoleClient { public: using TPtr = THolder; - explicit TYQLCompleter(NSQLComplete::ISqlCompletionEngine::TPtr engine) + explicit TYQLCompleter(NSQLComplete::ISqlCompletionEngine::TPtr engine, TColorSchema color) : Engine(std::move(engine)) + , Color(std::move(color)) { } @@ -24,7 +27,11 @@ namespace NYdb::NConsoleClient { replxx::Replxx::completions_t entries; for (auto& candidate : completion.Candidates) { - candidate.Content += ' '; + const auto back = candidate.Content.back(); + if (!IsLeftPunct(back) && back != '<' || IsQuotation(back)) { + candidate.Content += ' '; + } + entries.emplace_back( std::move(candidate.Content), ReplxxColorOf(candidate.Kind)); @@ -33,16 +40,47 @@ namespace NYdb::NConsoleClient { } private: - static replxx::Replxx::Color ReplxxColorOf(NSQLComplete::ECandidateKind /* kind */) { - return replxx::Replxx::Color::DEFAULT; + replxx::Replxx::Color ReplxxColorOf(NSQLComplete::ECandidateKind kind) { + switch (kind) { + case NSQLComplete::ECandidateKind::Keyword: + return Color.keyword; + case NSQLComplete::ECandidateKind::TypeName: + return Color.identifier.type; + case NSQLComplete::ECandidateKind::FunctionName: + return Color.identifier.function; + default: + return replxx::Replxx::Color::DEFAULT; + } } NSQLComplete::ISqlCompletionEngine::TPtr Engine; + TColorSchema Color; }; - IYQLCompleter::TPtr MakeYQLCompleter() { + NSQLComplete::TLexerSupplier MakePureLexerSupplier() { + NSQLTranslationV1::TLexers lexers; + lexers.Antlr4Pure = NSQLTranslationV1::MakeAntlr4PureLexerFactory(); + lexers.Antlr4PureAnsi = NSQLTranslationV1::MakeAntlr4PureAnsiLexerFactory(); + return [lexers = std::move(lexers)](bool ansi) { + return NSQLTranslationV1::MakeLexer( + lexers, ansi, /* antlr4 = */ true, + NSQLTranslationV1::ELexerFlavor::Pure); + }; + } + + IYQLCompleter::TPtr MakeYQLCompleter(TColorSchema color) { + NSQLComplete::TLexerSupplier lexer = MakePureLexerSupplier(); + + NSQLComplete::NameSet names = NSQLComplete::MakeDefaultNameSet(); + + NSQLComplete::IRanking::TPtr ranking = NSQLComplete::MakeDefaultRanking(); + + NSQLComplete::INameService::TPtr service = + MakeStaticNameService(std::move(names), std::move(ranking)); + return IYQLCompleter::TPtr(new TYQLCompleter( - NSQLComplete::MakeSqlCompletionEngine())); + NSQLComplete::MakeSqlCompletionEngine(std::move(lexer), std::move(service)), + std::move(color))); } } // namespace NYdb::NConsoleClient diff --git a/ydb/public/lib/ydb_cli/commands/interactive/complete/yql_completer.h b/ydb/public/lib/ydb_cli/commands/interactive/complete/yql_completer.h index 083a248b0ff8..bf97d6049769 100644 --- a/ydb/public/lib/ydb_cli/commands/interactive/complete/yql_completer.h +++ b/ydb/public/lib/ydb_cli/commands/interactive/complete/yql_completer.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -16,6 +18,6 @@ namespace NYdb::NConsoleClient { virtual ~IYQLCompleter() = default; }; - IYQLCompleter::TPtr MakeYQLCompleter(); + IYQLCompleter::TPtr MakeYQLCompleter(TColorSchema color); } // namespace NYdb::NConsoleClient diff --git a/ydb/public/lib/ydb_cli/commands/interactive/highlight/color/schema.cpp b/ydb/public/lib/ydb_cli/commands/interactive/highlight/color/schema.cpp new file mode 100644 index 000000000000..9607d0eaf797 --- /dev/null +++ b/ydb/public/lib/ydb_cli/commands/interactive/highlight/color/schema.cpp @@ -0,0 +1,43 @@ +#include "schema.h" + +namespace NYdb::NConsoleClient { + + TColorSchema TColorSchema::Monaco() { + using replxx::color::rgb666; + + return { + .keyword = TColor::BLUE, + .operation = rgb666(3, 3, 3), + .identifier = { + .function = rgb666(4, 1, 5), + .type = rgb666(2, 3, 2), + .variable = TColor::DEFAULT, + .quoted = rgb666(1, 3, 3), + }, + .string = rgb666(3, 0, 0), + .number = TColor::BRIGHTGREEN, + .comment = rgb666(2, 2, 2), + .unknown = TColor::DEFAULT, + }; + } + + TColorSchema TColorSchema::Debug() { + using replxx::color::rgb666; + + return { + .keyword = TColor::BLUE, + .operation = TColor::GRAY, + .identifier = { + .function = TColor::MAGENTA, + .type = TColor::YELLOW, + .variable = TColor::RED, + .quoted = TColor::CYAN, + }, + .string = TColor::GREEN, + .number = TColor::BRIGHTGREEN, + .comment = rgb666(2, 2, 2), + .unknown = TColor::DEFAULT, + }; + } + +} // namespace NYdb::NConsoleClient diff --git a/ydb/public/lib/ydb_cli/commands/interactive/highlight/color/schema.h b/ydb/public/lib/ydb_cli/commands/interactive/highlight/color/schema.h new file mode 100644 index 000000000000..b16b73a1cfbc --- /dev/null +++ b/ydb/public/lib/ydb_cli/commands/interactive/highlight/color/schema.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include + +namespace NYdb::NConsoleClient { + + using TColor = replxx::Replxx::Color; + + struct TColorSchema { + TColor keyword; + TColor operation; + struct { + TColor function; + TColor type; + TColor variable; + TColor quoted; + } identifier; + TColor string; + TColor number; + TColor comment; + TColor unknown; + + static TColorSchema Monaco(); + static TColorSchema Debug(); + }; + +} // namespace NYdb::NConsoleClient diff --git a/ydb/public/lib/ydb_cli/commands/interactive/highlight/color/ya.make b/ydb/public/lib/ydb_cli/commands/interactive/highlight/color/ya.make new file mode 100644 index 000000000000..513157a3567a --- /dev/null +++ b/ydb/public/lib/ydb_cli/commands/interactive/highlight/color/ya.make @@ -0,0 +1,11 @@ +LIBRARY() + +SRCS( + schema.cpp +) + +PEERDIR( + contrib/restricted/patched/replxx +) + +END() diff --git a/ydb/public/lib/ydb_cli/commands/interactive/highlight/ya.make b/ydb/public/lib/ydb_cli/commands/interactive/highlight/ya.make index 26a7b0e16156..b6a4045ef8d0 100644 --- a/ydb/public/lib/ydb_cli/commands/interactive/highlight/ya.make +++ b/ydb/public/lib/ydb_cli/commands/interactive/highlight/ya.make @@ -11,10 +11,15 @@ PEERDIR( yql/essentials/sql/v1/lexer/antlr4 yql/essentials/sql/v1/lexer/antlr4_ansi yql/essentials/sql/settings + ydb/public/lib/ydb_cli/commands/interactive/highlight/color ) END() +RECURSE( + color +) + RECURSE_FOR_TESTS( ut ) diff --git a/ydb/public/lib/ydb_cli/commands/interactive/highlight/yql_highlighter.cpp b/ydb/public/lib/ydb_cli/commands/interactive/highlight/yql_highlighter.cpp index ddb08f6974db..d219629b3d71 100644 --- a/ydb/public/lib/ydb_cli/commands/interactive/highlight/yql_highlighter.cpp +++ b/ydb/public/lib/ydb_cli/commands/interactive/highlight/yql_highlighter.cpp @@ -98,44 +98,6 @@ namespace NYdb::NConsoleClient { return settings.AnsiLexer; } - TColorSchema TColorSchema::Monaco() { - using replxx::color::rgb666; - - return { - .keyword = TColor::BLUE, - .operation = rgb666(3, 3, 3), - .identifier = { - .function = rgb666(4, 1, 5), - .type = rgb666(2, 3, 2), - .variable = TColor::DEFAULT, - .quoted = rgb666(1, 3, 3), - }, - .string = rgb666(3, 0, 0), - .number = TColor::BRIGHTGREEN, - .comment = rgb666(2, 2, 2), - .unknown = TColor::DEFAULT, - }; - } - - TColorSchema TColorSchema::Debug() { - using replxx::color::rgb666; - - return { - .keyword = TColor::BLUE, - .operation = TColor::GRAY, - .identifier = { - .function = TColor::MAGENTA, - .type = TColor::YELLOW, - .variable = TColor::RED, - .quoted = TColor::CYAN, - }, - .string = TColor::GREEN, - .number = TColor::BRIGHTGREEN, - .comment = rgb666(2, 2, 2), - .unknown = TColor::DEFAULT, - }; - } - class TYQLHighlighter: public IYQLHighlighter { public: explicit TYQLHighlighter(TColorSchema color) diff --git a/ydb/public/lib/ydb_cli/commands/interactive/highlight/yql_highlighter.h b/ydb/public/lib/ydb_cli/commands/interactive/highlight/yql_highlighter.h index 700bc5b18bf2..4d39208605fa 100644 --- a/ydb/public/lib/ydb_cli/commands/interactive/highlight/yql_highlighter.h +++ b/ydb/public/lib/ydb_cli/commands/interactive/highlight/yql_highlighter.h @@ -2,33 +2,15 @@ #include +#include + #include namespace NYdb::NConsoleClient { - using TColor = replxx::Replxx::Color; - // Colors are provided as for a UTF32 string using TColors = replxx::Replxx::colors_t; - struct TColorSchema { - TColor keyword; - TColor operation; - struct { - TColor function; - TColor type; - TColor variable; - TColor quoted; - } identifier; - TColor string; - TColor number; - TColor comment; - TColor unknown; - - static TColorSchema Monaco(); - static TColorSchema Debug(); - }; - class IYQLHighlighter { public: using TPtr = THolder; diff --git a/ydb/public/lib/ydb_cli/commands/interactive/line_reader.cpp b/ydb/public/lib/ydb_cli/commands/interactive/line_reader.cpp index 722ab03f7d66..080131b44908 100644 --- a/ydb/public/lib/ydb_cli/commands/interactive/line_reader.cpp +++ b/ydb/public/lib/ydb_cli/commands/interactive/line_reader.cpp @@ -59,7 +59,7 @@ TLineReader::TLineReader(std::string prompt, std::string historyFilePath) : Prompt(std::move(prompt)) , HistoryFilePath(std::move(historyFilePath)) , HistoryFileHandle(HistoryFilePath.c_str(), EOpenModeFlag::OpenAlways | EOpenModeFlag::RdWr | EOpenModeFlag::AW | EOpenModeFlag::ARUser | EOpenModeFlag::ARGroup) - , YQLCompleter(MakeYQLCompleter()) + , YQLCompleter(MakeYQLCompleter(TColorSchema::Monaco())) , YQLHighlighter(MakeYQLHighlighter(TColorSchema::Monaco())) { Rx.install_window_change_handler(); @@ -67,6 +67,13 @@ TLineReader::TLineReader(std::string prompt, std::string historyFilePath) Rx.set_completion_callback([this](const std::string& prefix, int& contextLen) { return YQLCompleter->Apply(prefix, contextLen); }); + Rx.set_hint_callback([this](const std::string& prefix, int& contextLen, TColor&) { + replxx::Replxx::hints_t hints; + for (auto& candidate : YQLCompleter->Apply(prefix, contextLen)) { + hints.emplace_back(std::move(candidate.text())); + } + return hints; + }); Rx.set_highlighter_callback([this](const auto& text, auto& colors) { YQLHighlighter->Apply(text, colors); }); diff --git a/ydb/public/lib/ydb_cli/commands/interactive/ya.make b/ydb/public/lib/ydb_cli/commands/interactive/ya.make index 81b513ae1de3..6a0d6f1ddc75 100644 --- a/ydb/public/lib/ydb_cli/commands/interactive/ya.make +++ b/ydb/public/lib/ydb_cli/commands/interactive/ya.make @@ -14,3 +14,7 @@ PEERDIR( END() +RECURSE( + complete + highlight +) From 439db1cfe398621d7fa0ef4f2fa59ff4421eda0c Mon Sep 17 00:00:00 2001 From: bystrovserg Date: Wed, 9 Apr 2025 16:52:06 +0300 Subject: [PATCH 104/454] YT-6812, YT-24298: Introducing attributes and events to list_jobs commit_hash:9395b2e879d30ba83d17dcc8c94af4618a13d2a7 --- .../rpc_parameters_serialization.cpp | 22 ++++----- yt/cpp/mapreduce/interface/operation.h | 47 +++++++++++++++++++ yt/yt/client/api/operation_client.h | 7 ++- yt/yt/client/api/rpc_proxy/client_impl.cpp | 3 ++ yt/yt/client/api/rpc_proxy/helpers.cpp | 20 ++++++-- yt/yt/client/driver/scheduler_commands.cpp | 7 +++ .../api/rpc_proxy/proto/api_service.proto | 4 ++ 7 files changed, 93 insertions(+), 17 deletions(-) diff --git a/yt/cpp/mapreduce/http_client/rpc_parameters_serialization.cpp b/yt/cpp/mapreduce/http_client/rpc_parameters_serialization.cpp index 8487a1de8f2e..14ab0e1db85f 100644 --- a/yt/cpp/mapreduce/http_client/rpc_parameters_serialization.cpp +++ b/yt/cpp/mapreduce/http_client/rpc_parameters_serialization.cpp @@ -49,18 +49,10 @@ static void SetPathParam(TNode* node, const TString& pathPrefix, const TYPath& p (*node)["path"] = std::move(updatedPath); } -static TNode SerializeAttributeFilter(const TAttributeFilter& attributeFilter) +template +static TNode SerializeAttributeFilter(const TFilter& attributeFilter) { - TNode result = TNode::CreateList(); - for (const auto& attribute : attributeFilter.Attributes_) { - result.Add(attribute); - } - return result; -} - -static TNode SerializeAttributeFilter(const TOperationAttributeFilter& attributeFilter) -{ - TNode result = TNode::CreateList(); + auto result = TNode::CreateList(); for (const auto& attribute : attributeFilter.Attributes_) { result.Add(ToString(attribute)); } @@ -513,11 +505,14 @@ TNode SerializeParamsForUpdateOperationParameters( TNode SerializeParamsForGetJob( const TOperationId& operationId, const TJobId& jobId, - const TGetJobOptions& /* options */) + const TGetJobOptions& options) { TNode result; SetOperationIdParam(&result, operationId); result["job_id"] = GetGuidAsString(jobId); + if (options.AttributeFilter_) { + result["attributes"] = SerializeAttributeFilter(*options.AttributeFilter_); + } return result; } @@ -597,6 +592,9 @@ TNode SerializeParamsForListJobs( if (options.IncludeControllerAgent_) { result["include_controller_agent"] = *options.IncludeControllerAgent_; } + if (options.AttributeFilter_) { + result["attributes"] = SerializeAttributeFilter(*options.AttributeFilter_); + } return result; } diff --git a/yt/cpp/mapreduce/interface/operation.h b/yt/cpp/mapreduce/interface/operation.h index 1f327b4b5d64..ee3e3b1fa111 100644 --- a/yt/cpp/mapreduce/interface/operation.h +++ b/yt/cpp/mapreduce/interface/operation.h @@ -2857,6 +2857,45 @@ enum class EJobSortDirection : int Descending /* "descending" */, }; +/// +/// @brief Attributes to request for a job. +enum class EJobAttribute : int +{ + Id /* "id" */, + Type /* "type" */, + State /* "state" */, + Address /* "address" */, + TaskName /* "task_name" */, + StartTime /* "start_time" */, + FinishTime /* "finish_time" */, + Progress /* "progress" */, + StderrSize /* "stderr_size" */, + Error /* "error" */, + Result /* "result" */, + BriefStatistics /* "brief_statistics" */, + InputPaths /* "input_paths" */, + CoreInfos /* "core_infos" */, +}; + +/// +/// @brief A class that specifies which attributes to request when using @ref NYT::IClient::GetJob or @ref NYT::IClient::ListJobs. +struct TJobAttributeFilter +{ + /// @cond Doxygen_Suppress + using TSelf = TJobAttributeFilter; + /// @endcond + + THashSet Attributes_; + + /// + /// @brief Add attribute to the filter. Calls are supposed to be chained. + TSelf& Add(EJobAttribute attribute) + { + Attributes_.insert(attribute); + return *this; + } +}; + /// /// @brief Options for @ref NYT::IClient::ListJobs. /// @@ -2921,6 +2960,10 @@ struct TListJobsOptions /// @brief Search for jobs with filters encoded in token. FLUENT_FIELD_OPTION(TString, ContinuationToken); + /// + /// @brief Return only requested job attributes. + FLUENT_FIELD_OPTION(TJobAttributeFilter, AttributeFilter); + /// @} /// @@ -3065,6 +3108,10 @@ struct TGetJobOptions /// @cond Doxygen_Suppress using TSelf = TGetJobOptions; /// @endcond + + /// + /// @brief Return only requested job attributes. + FLUENT_FIELD_OPTION(TJobAttributeFilter, AttributeFilter); }; /// diff --git a/yt/yt/client/api/operation_client.h b/yt/yt/client/api/operation_client.h index 8e672c80e5fe..7b67508c4816 100644 --- a/yt/yt/client/api/operation_client.h +++ b/yt/yt/client/api/operation_client.h @@ -217,6 +217,8 @@ struct TListJobsOptions std::optional FromTime; std::optional ToTime; + std::optional> Attributes; + std::optional ContinuationToken; TDuration RunningJobsLookbehindPeriod = TDuration::Max(); @@ -394,9 +396,12 @@ struct TJob NYson::TYsonString ArchiveFeatures; std::optional OperationIncarnation; std::optional AllocationId; - std::optional IsStale; + // Service flags which are used to compute "is_stale" attribute in "list_jobs". + bool PresentInArchive = false; + bool PresentInControllerAgent = false; + std::optional GetState() const; }; diff --git a/yt/yt/client/api/rpc_proxy/client_impl.cpp b/yt/yt/client/api/rpc_proxy/client_impl.cpp index a4b77dd18328..fdb29f948b29 100644 --- a/yt/yt/client/api/rpc_proxy/client_impl.cpp +++ b/yt/yt/client/api/rpc_proxy/client_impl.cpp @@ -1482,6 +1482,9 @@ TFuture TClient::ListJobs( if (options.ContinuationToken) { req->set_continuation_token(*options.ContinuationToken); } + if (options.Attributes) { + ToProto(req->mutable_attributes()->mutable_keys(), *options.Attributes); + } req->set_sort_field(static_cast(options.SortField)); req->set_sort_order(static_cast(options.SortOrder)); diff --git a/yt/yt/client/api/rpc_proxy/helpers.cpp b/yt/yt/client/api/rpc_proxy/helpers.cpp index 8e1fdd366ec5..ba36a57d88a9 100644 --- a/yt/yt/client/api/rpc_proxy/helpers.cpp +++ b/yt/yt/client/api/rpc_proxy/helpers.cpp @@ -886,6 +886,12 @@ void ToProto(NProto::TJob* protoJob, const NApi::TJob& job) YT_OPTIONAL_TO_PROTO(protoJob, monitoring_descriptor, job.MonitoringDescriptor); YT_OPTIONAL_SET_PROTO(protoJob, operation_incarnation, job.OperationIncarnation); YT_OPTIONAL_TO_PROTO(protoJob, allocation_id, job.AllocationId); + if (job.Events) { + protoJob->set_events(job.Events.ToString()); + } + if (job.Statistics) { + protoJob->set_statistics(job.Statistics.ToString()); + } } void FromProto(NApi::TJob* job, const NProto::TJob& protoJob) @@ -916,8 +922,6 @@ void FromProto(NApi::TJob* job, const NProto::TJob& protoJob) job->FailContextSize = YT_OPTIONAL_FROM_PROTO(protoJob, fail_context_size); if (protoJob.has_has_spec()) { job->HasSpec = protoJob.has_spec(); - } else { - job->HasSpec = false; } if (protoJob.has_error()) { job->Error = TYsonString(protoJob.error()); @@ -956,8 +960,6 @@ void FromProto(NApi::TJob* job, const NProto::TJob& protoJob) } if (protoJob.has_has_competitors()) { job->HasCompetitors = protoJob.has_competitors(); - } else { - job->HasCompetitors = false; } job->HasProbingCompetitors = YT_OPTIONAL_FROM_PROTO(protoJob, has_probing_competitors); job->IsStale = YT_OPTIONAL_FROM_PROTO(protoJob, is_stale); @@ -966,6 +968,11 @@ void FromProto(NApi::TJob* job, const NProto::TJob& protoJob) } else { job->ExecAttributes = TYsonString(); } + if (protoJob.has_events()) { + job->Events = TYsonString(protoJob.events()); + } else { + job->Events = TYsonString(); + } job->TaskName = YT_OPTIONAL_FROM_PROTO(protoJob, task_name); job->PoolTree = YT_OPTIONAL_FROM_PROTO(protoJob, pool_tree); job->Pool = YT_OPTIONAL_FROM_PROTO(protoJob, pool); @@ -982,6 +989,11 @@ void FromProto(NApi::TJob* job, const NProto::TJob& protoJob) } else { job->AllocationId = {}; } + if (protoJob.has_statistics()) { + job->Statistics = TYsonString(protoJob.statistics()); + } else { + job->Statistics = TYsonString(); + } } void ToProto( diff --git a/yt/yt/client/driver/scheduler_commands.cpp b/yt/yt/client/driver/scheduler_commands.cpp index 6710ee43e284..8169d7aea30d 100644 --- a/yt/yt/client/driver/scheduler_commands.cpp +++ b/yt/yt/client/driver/scheduler_commands.cpp @@ -585,6 +585,13 @@ void TListJobsCommand::Register(TRegistrar registrar) return command->Options.RunningJobsLookbehindPeriod; }) .Optional(/*init*/ false); + + registrar.ParameterWithUniversalAccessor>>( + "attributes", + [] (TThis* command) -> auto& { + return command->Options.Attributes; + }) + .Optional(/*init*/ false); } void TListJobsCommand::DoExecute(ICommandContextPtr context) diff --git a/yt/yt_proto/yt/client/api/rpc_proxy/proto/api_service.proto b/yt/yt_proto/yt/client/api/rpc_proxy/proto/api_service.proto index c1f922829e3a..25551ed96328 100644 --- a/yt/yt_proto/yt/client/api/rpc_proxy/proto/api_service.proto +++ b/yt/yt_proto/yt/client/api/rpc_proxy/proto/api_service.proto @@ -2479,6 +2479,8 @@ message TReqListJobs optional bool with_interruption_info = 26; + optional NYT.NYTree.NProto.TAttributeFilter attributes = 27; + optional TMasterReadOptions master_read_options = 102; } @@ -3216,6 +3218,8 @@ message TJob optional string operation_incarnation = 31; optional NYT.NProto.TGuid allocation_id = 32; optional NNodeTrackerClient.NProto.TAddressMap addresses = 33; + optional bytes events = 34; // YSON + optional bytes statistics = 35; // YSON } message TListJobsStatistics From 751c197f1a8cf88c09b44fee5e4afe528d0a970f Mon Sep 17 00:00:00 2001 From: Filitov Mikhail Date: Wed, 9 Apr 2025 16:22:07 +0200 Subject: [PATCH 105/454] Change exception to error in spilling queue (#16922) --- .../yql/dq/actors/spilling/spilling_file.cpp | 67 +++++++++++++------ .../dq/actors/spilling/spilling_file_ut.cpp | 32 ++++++++- 2 files changed, 77 insertions(+), 22 deletions(-) diff --git a/ydb/library/yql/dq/actors/spilling/spilling_file.cpp b/ydb/library/yql/dq/actors/spilling/spilling_file.cpp index fa1c11ace453..083b9746315d 100644 --- a/ydb/library/yql/dq/actors/spilling/spilling_file.cpp +++ b/ydb/library/yql/dq/actors/spilling/spilling_file.cpp @@ -353,7 +353,9 @@ class TDqLocalFileSpillingService : public TActorBootstrappedFileNames.emplace_back(std::move(fp.FileName)); } - RunOp("CloseFile", std::move(closeOp), fd); + if (!RunOp("CloseFile", std::move(closeOp), fd)) { + LOG_E("[CloseFile] Can not run operation"); + } } else { MoveFileToClosed(it); } @@ -469,7 +471,12 @@ class TDqLocalFileSpillingService : public TActorBootstrappedBlobId = msg.BlobId; writeOp->Blob = std::move(msg.Blob); - RunOp("Write", std::move(writeOp), fd); + if (!RunOp("Write", std::move(writeOp), fd)) { + TString error = "[Write] Can not run operation"; + LOG_E(error); + + Send(ev->Sender, new TEvDqSpilling::TEvError(error)); + } } void HandleWork(TEvPrivate::TEvWriteFileResponse::TPtr& ev) { @@ -526,8 +533,15 @@ class TDqLocalFileSpillingService : public TActorBootstrappedSpillingWriteBlobs->Inc(); - Send(msg.Client, new TEvDqSpilling::TEvWriteResult(msg.BlobId)); - RunNextOp(fd); + if (RunNextOp(fd)) { + Send(msg.Client, new TEvDqSpilling::TEvWriteResult(msg.BlobId)); + } else { + TString error = "[WriteFileResponse] Can not run operation"; + LOG_E(error); + + Send(ev->Sender, new TEvDqSpilling::TEvError(error)); + return; + } } void HandleWork(TEvDqSpilling::TEvRead::TPtr& ev) { @@ -602,7 +616,12 @@ class TDqLocalFileSpillingService : public TActorBootstrappedRemoveFile = std::move(fp->FileHandle); } - RunOp("Read", std::move(readOp), fd); + if (!RunOp("Read", std::move(readOp), fd)) { + TString error = "[Read] Can not run operation"; + LOG_E(error); + + Send(ev->Sender, new TEvDqSpilling::TEvError(error)); + } } void HandleWork(TEvPrivate::TEvReadFileResponse::TPtr& ev) { @@ -660,8 +679,15 @@ class TDqLocalFileSpillingService : public TActorBootstrappedSpillingReadBlobs->Inc(); - Send(msg.Client, new TEvDqSpilling::TEvReadResult(msg.BlobId, std::move(msg.Blob))); - RunNextOp(fd); + if (RunNextOp(fd)) { + Send(msg.Client, new TEvDqSpilling::TEvReadResult(msg.BlobId, std::move(msg.Blob))); + } else { + TString error = "[ReadFileResponse] Can not run operation"; + LOG_E(error); + + Send(ev->Sender, new TEvDqSpilling::TEvError(error)); + return; + } } void HandleWork(NMon::TEvHttpInfo::TPtr& ev) { @@ -789,25 +815,28 @@ class TDqLocalFileSpillingService : public TActorBootstrapped op, TFileDesc& fd) { + + bool RunOp(TStringBuf opName, THolder op, TFileDesc& fd) { if (fd.HasActiveOp) { fd.Ops.emplace_back(opName, std::move(op)); - } else { - fd.HasActiveOp = true; - // TODO: retry if fails - IoThreadPool_->SafeAddAndOwn(std::move(op)); + return true; } + + fd.HasActiveOp = true; + + return IoThreadPool_->AddAndOwn(std::move(op)); } - void RunNextOp(TFileDesc& fd) { + bool RunNextOp(TFileDesc& fd) { fd.HasActiveOp = false; - if (!fd.Ops.empty()) { - auto op = std::move(fd.Ops.front().second); - auto opName = fd.Ops.front().first; - fd.Ops.pop_front(); - - RunOp(opName, std::move(op), fd); + if (fd.Ops.empty()) { + return true; } + auto op = std::move(fd.Ops.front().second); + auto opName = fd.Ops.front().first; + fd.Ops.pop_front(); + + return RunOp(opName, std::move(op), fd); } void MoveFileToClosed(TFilesIt it) { diff --git a/ydb/library/yql/dq/actors/spilling/spilling_file_ut.cpp b/ydb/library/yql/dq/actors/spilling/spilling_file_ut.cpp index 04f4a6ecc3c0..18d583c8e364 100644 --- a/ydb/library/yql/dq/actors/spilling/spilling_file_ut.cpp +++ b/ydb/library/yql/dq/actors/spilling/spilling_file_ut.cpp @@ -53,7 +53,7 @@ class TTestActorRuntime: public TTestActorRuntimeBase { } TActorId StartSpillingService(ui64 maxTotalSize = 1000, ui64 maxFileSize = 500, - ui64 maxFilePartSize = 100, const TFsPath& root = TFsPath::Cwd() / GetSpillingPrefix()) + ui64 maxFilePartSize = 100, ui32 ioThreadPoolQueueSize = 1000, const TFsPath& root = TFsPath::Cwd() / GetSpillingPrefix()) { SpillingRoot_ = root; SpillingSessionId_ = CreateGuidAsString(); @@ -63,7 +63,8 @@ class TTestActorRuntime: public TTestActorRuntimeBase { .SpillingSessionId = SpillingSessionId_, .MaxTotalSize = maxTotalSize, .MaxFileSize = maxFileSize, - .MaxFilePartSize = maxFilePartSize + .MaxFilePartSize = maxFilePartSize, + .IoThreadPoolQueueSize = ioThreadPoolQueueSize }; auto counters = Counters(); @@ -497,11 +498,36 @@ Y_UNIT_TEST_SUITE(DqSpillingFileTests) { } } + Y_UNIT_TEST(ThreadPoolQueueOverflow) { + TTestActorRuntime runtime; + runtime.Initialize(); + + runtime.StartSpillingService(1000, 500, 10, 1); + ui32 iters = 100; + std::vector testers; + std::vector spillingActors; + for (ui32 i = 0; i < iters; ++i) { + testers.emplace_back(runtime.AllocateEdgeActor()); + spillingActors.emplace_back(runtime.StartSpillingActor(testers.back())); + } + + runtime.WaitBootstrap(); + + for (ui32 i = 0; i < iters; ++i) { + auto ev = new TEvDqSpilling::TEvWrite(i, CreateRope(10, 'a')); + runtime.Send(new IEventHandle(spillingActors[i], testers[i], ev)); + } + + auto resp = runtime.GrabEdgeEvent(TDuration::Seconds(1)); + Cerr << resp->Message << Endl; + UNIT_ASSERT_EQUAL("[Write] Can not run operation", resp->Message); + } + Y_UNIT_TEST(StartError) { TTestActorRuntime runtime; runtime.Initialize(); - auto spillingService = runtime.StartSpillingService(100, 500, 100, TFsPath("/nonexistent") / runtime.GetSpillingPrefix()); + auto spillingService = runtime.StartSpillingService(100, 500, 100, 1000, TFsPath("/nonexistent") / runtime.GetSpillingPrefix()); auto tester = runtime.AllocateEdgeActor(); auto spillingActor = runtime.StartSpillingActor(tester); From a55bf5d901ba7fd4cd4cbf3c998b31f28ecece4c Mon Sep 17 00:00:00 2001 From: Alexander Avdonkin Date: Wed, 9 Apr 2025 17:26:37 +0300 Subject: [PATCH 106/454] Mixed stress test (#14163) --- ydb/library/workload/mixed/mixed.cpp | 367 ++++++++++++++++++ ydb/library/workload/mixed/mixed.h | 109 ++++++ ydb/library/workload/mixed/registrar.cpp | 12 + ydb/library/workload/mixed/ya.make | 14 + ydb/library/workload/ya.make | 2 + .../lib/ydb_cli/commands/ydb_workload.cpp | 4 +- ydb/tests/stress/mixedpy/test_mixed.py | 108 ++++++ ydb/tests/stress/mixedpy/ya.make | 31 ++ ydb/tests/stress/ya.make | 1 + 9 files changed, 646 insertions(+), 2 deletions(-) create mode 100644 ydb/library/workload/mixed/mixed.cpp create mode 100644 ydb/library/workload/mixed/mixed.h create mode 100644 ydb/library/workload/mixed/registrar.cpp create mode 100644 ydb/library/workload/mixed/ya.make create mode 100644 ydb/tests/stress/mixedpy/test_mixed.py create mode 100644 ydb/tests/stress/mixedpy/ya.make diff --git a/ydb/library/workload/mixed/mixed.cpp b/ydb/library/workload/mixed/mixed.cpp new file mode 100644 index 000000000000..28902ac46194 --- /dev/null +++ b/ydb/library/workload/mixed/mixed.cpp @@ -0,0 +1,367 @@ +#include "mixed.h" +#include +#include +#include +#include + +namespace NYdbWorkload { + +namespace NMixed { + +using TRow = TLogGenerator::TRow; + + +TLogGenerator::TLogGenerator(const TMixedWorkloadParams* params) + : TBase(params) + , TotalColumnsCnt(1 + Params.IntColumnsCnt + Params.StrColumnsCnt) +{ + Y_ABORT_UNLESS(TotalColumnsCnt >= Params.KeyColumnsCnt); +} + +std::string TLogGenerator::GetDDLQueries() const { + std::stringstream ss; + + ss << "--!syntax_v1\n"; + ss << "CREATE TABLE `" << Params.DbPath << "/" << Params.TableName << "`("; + + for (size_t i = 0; i < TotalColumnsCnt; ++i) { + if (i == 0) { + ss << "ts Timestamp"; + } else if (i < Params.IntColumnsCnt + 1) { + ss << "c" << i << " Uint64"; + } else { + ss << "c" << i << " String"; + } + + if (i < Params.KeyColumnsCnt && Params.GetStoreType() == TMixedWorkloadParams::EStoreType::Column) { + ss << " NOT NULL"; + } + ss << ", "; + } + + ss << "PRIMARY KEY("; + ss << "ts"; + for (size_t i = 1; i < Params.KeyColumnsCnt; ++i) { + ss << ", c" << i; + } + ss << ")) WITH ("; + + ss << "TTL = Interval(\"PT" << Params.TimestampTtlMinutes << "M\") ON ts, "; + + switch (Params.GetStoreType()) { + case TMixedWorkloadParams::EStoreType::Row: + ss << "STORE = ROW, "; + break; + case TMixedWorkloadParams::EStoreType::Column: + ss << "STORE = COLUMN, "; + break; + default: + throw yexception() << "Unsupported store type: " << Params.GetStoreType(); + } + if (Params.PartitionsByLoad) { + ss << "AUTO_PARTITIONING_BY_LOAD = ENABLED, "; + } + ss << "AUTO_PARTITIONING_MAX_PARTITIONS_COUNT = " << Max(Params.MinPartitions, Params.MaxPartitions) << ", "; + ss << "AUTO_PARTITIONING_PARTITION_SIZE_MB = " << Params.PartitionSizeMb << ", "; + ss << "AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = " << Params.MinPartitions << ")"; + return ss.str(); +} + +TQueryInfoList TLogGenerator::GetWorkload(int type) { + switch (static_cast(type)) { + case EType::Insert: + return Insert(GenerateRandomRows()); + case EType::Upsert: + return Upsert(GenerateRandomRows()); + case EType::BulkUpsert: + return BulkUpsert(GenerateRandomRows()); + case EType::Select: + return Select(GenerateRandomRows()); + default: + return TQueryInfoList(); + } +} + + +TVector TLogGenerator::GetSupportedWorkloadTypes() const { + TVector result; + result.emplace_back(static_cast(EType::Insert), "insert", "Insert random rows into table near current ts"); + result.emplace_back(static_cast(EType::Upsert), "upsert", "Upsert random rows into table near current ts"); + result.emplace_back(static_cast(EType::BulkUpsert), "bulk_upsert", "Bulk upsert random rows into table near current ts"); + result.emplace_back(static_cast(EType::Select), "select", "Select random rows from table"); + return result; +} + +TQueryInfoList TLogGenerator::WriteRows(TString operation, TVector&& rows) { + std::stringstream ss; + + NYdb::TParamsBuilder paramsBuilder; + + ss << "--!syntax_v1\n"; + + for (size_t row = 0; row < Params.RowsCnt; ++row) { + for (size_t col = 0; col < TotalColumnsCnt; ++col) { + TString cname = "$c" + std::to_string(row) + "_" + std::to_string(col); + if (col == 0) { + ss << "DECLARE " << cname << " AS Timestamp;\n"; + paramsBuilder.AddParam(cname).Timestamp(rows[row].Ts).Build(); + } else if (col < Params.IntColumnsCnt + 1) { + ss << "DECLARE " << cname << " AS Uint64;\n"; + paramsBuilder.AddParam(cname).Uint64(rows[row].Ints[col - 1]).Build(); + } else { + ss << "DECLARE " << cname << " AS String;\n"; + paramsBuilder.AddParam(cname).String(rows[row].Strings[col - Params.IntColumnsCnt - 1]).Build(); + } + } + } + + ss << operation << " INTO `" << Params.TableName << "` ("; + + for (size_t col = 0; col < TotalColumnsCnt; ++col) { + if (col != 0) { + ss << "c" << col; + } else { + ss << "ts"; + } + + if (col + 1 < TotalColumnsCnt) { + ss << ", "; + } + } + + ss << ") VALUES "; + + for (size_t row = 0; row < Params.RowsCnt; ++row) { + ss << "("; + + for (size_t col = 0; col < TotalColumnsCnt; ++col) { + ss << "$c" << row << "_" << col; + if (col + 1 < TotalColumnsCnt) { + ss << ", "; + } + } + + ss << ")"; + + if (row + 1 < Params.RowsCnt) { + ss << ", "; + } + } + auto params = paramsBuilder.Build(); + return TQueryInfoList(1, TQueryInfo(ss.str(), std::move(params))); +} + +TQueryInfoList TLogGenerator::Insert(TVector&& rows) { + return WriteRows("INSERT", std::move(rows)); +} + +TQueryInfoList TLogGenerator::Upsert(TVector&& rows) { + return WriteRows("UPSERT", std::move(rows)); +} + +TQueryInfoList TLogGenerator::Select(TVector&& rows) { + std::stringstream ss; + + NYdb::TParamsBuilder paramsBuilder; + + ss << "--!syntax_v1\n"; + + for (size_t row = 0; row < Params.RowsCnt; ++row) { + for (size_t col = 0; col < Params.KeyColumnsCnt; ++col) { + TString paramName = "$r" + std::to_string(row) + "_" + std::to_string(col); + if (col == 0) { + ss << "DECLARE " << paramName << " AS Timestamp;\n"; + paramsBuilder.AddParam(paramName).Timestamp(rows[row].Ts).Build(); + } else if (col < Params.IntColumnsCnt) { + ss << "DECLARE " << paramName << " AS Uint64;\n"; + paramsBuilder.AddParam(paramName).Uint64(rows[row].Ints[col]).Build(); + } else { + ss << "DECLARE " << paramName << " AS String;\n"; + paramsBuilder.AddParam(paramName).String(rows[row].Strings[col - Params.IntColumnsCnt]).Build(); + } + } + } + + ss << "SELECT "; + for (size_t col = 1; col <= TotalColumnsCnt; ++col) { + ss << "c" << col; + if (col + 1 < TotalColumnsCnt) { + ss << ","; + } + ss << " "; + } + + ss << "FROM `" << Params.TableName << "` WHERE "; + for (size_t row = 0; row < Params.RowsCnt; ++row) { + for (size_t col = 0; col < Params.KeyColumnsCnt; ++col) { + TString paramName = "$r" + std::to_string(row) + "_" + std::to_string(col); + if (col == 0) { + ss << "ts = " << paramName; + } else { + ss << "c" << col << " = " << paramName; + } + if (col + 1 < Params.KeyColumnsCnt) { + ss << " AND "; + } + } + if (row + 1 < Params.RowsCnt) { + ss << " OR "; + } + } + + auto params = paramsBuilder.Build(); + TQueryInfo info(ss.str(), std::move(params)); + return TQueryInfoList(1, std::move(info)); +} + +TQueryInfoList TLogGenerator::BulkUpsert(TVector&& rows) { + NYdb::TValueBuilder valueBuilder; + valueBuilder.BeginList(); + for (const TRow& row : rows) { + auto &listItem = valueBuilder.AddListItem(); + listItem.BeginStruct(); + for (size_t col = 0; col < TotalColumnsCnt; ++col) { + if (col == 0) { + listItem.AddMember("ts").Timestamp(row.Ts); + } else if (col < Params.IntColumnsCnt + 1) { + listItem.AddMember(std::format("c{}", col)).Uint64(row.Ints[col-1]); + } else { + listItem.AddMember(std::format("c{}", col)).String(row.Strings[col - Params.IntColumnsCnt - 1]); + } + } + listItem.EndStruct(); + } + valueBuilder.EndList(); + TString table_path = Params.DbPath + "/" + Params.TableName; + NYdb::TValue rowsValue = valueBuilder.Build(); + auto bulkUpsertOperation = [table_path, rowsValue](NYdb::NTable::TTableClient& tableClient) { + auto r = rowsValue; + auto status = tableClient.BulkUpsert(table_path, std::move(r)); + return status.GetValueSync(); + }; + TQueryInfo queryInfo; + queryInfo.TableOperation = bulkUpsertOperation; + return TQueryInfoList(1, std::move(queryInfo)); +} + + +TQueryInfoList TLogGenerator::GetInitialData() { + TQueryInfoList res; + return res; +} + +TVector TLogGenerator::GetCleanPaths() const { + return { Params.TableName }; +} + +TVector TLogGenerator::GenerateRandomRows() { + TVector result(Params.RowsCnt); + + for (size_t row = 0; row < Params.RowsCnt; ++row) { + result[row].Ts = TInstant::Now(); + i64 millisecondsDiff = 60 * 1000 * NormalRandom(0., static_cast(Params.TimestampStandardDeviationMinutes)); + if (millisecondsDiff >= 0) { // TDuration::MilliSeconds can't be negative for some reason... + result[row].Ts = result[row].Ts + TDuration::MilliSeconds(millisecondsDiff); + } else { + result[row].Ts = result[row].Ts - TDuration::MilliSeconds(-millisecondsDiff); + } + + result[row].Ints.resize(Params.IntColumnsCnt); + result[row].Strings.resize(Params.StrColumnsCnt); + + for (size_t col = 0; col < Params.IntColumnsCnt; ++col) { + ui64 val = RandomNumber(); + result[row].Ints[col] = val; + } + + for (size_t col = 0; col < Params.StrColumnsCnt; ++col) { + TString val; + val = TString(Params.StringLen, '_'); + for (size_t i = 0; i < Params.StringLen; i++) { + val[i] = (char)('a' + RandomNumber(26)); + } + result[row].Strings[col] = val; + } + } + + return result; +} + +void TMixedWorkloadParams::ConfigureOpts(NLastGetopt::TOpts& opts, const ECommandType commandType, int workloadType) { + opts.AddLongOption('p', "path", "Path where benchmark tables are located") + .Optional() + .DefaultValue(TableName) + .Handler1T([this](TStringBuf arg) { + while(arg.SkipPrefix("/")); + while(arg.ChopSuffix("/")); + TableName = arg; + }); + switch (commandType) { + case TWorkloadParams::ECommandType::Init: + opts.AddLongOption("min-partitions", "Minimum partitions for tables.") + .DefaultValue((ui64)LogWorkloadConstants::MIN_PARTITIONS).StoreResult(&MinPartitions); + opts.AddLongOption("max-partitions", "Maximum partitions for tables.") + .DefaultValue((ui64)LogWorkloadConstants::MAX_PARTITIONS).StoreResult(&MaxPartitions); + opts.AddLongOption("partition-size", "Maximum partition size in megabytes (AUTO_PARTITIONING_PARTITION_SIZE_MB).") + .DefaultValue((ui64)LogWorkloadConstants::PARTITION_SIZE_MB).StoreResult(&PartitionSizeMb); + opts.AddLongOption("auto-partition", "Enable auto partitioning by load.") + .DefaultValue((ui64)LogWorkloadConstants::PARTITIONS_BY_LOAD).StoreResult(&PartitionsByLoad); + opts.AddLongOption("len", "String len") + .DefaultValue((ui64)LogWorkloadConstants::STRING_LEN).StoreResult(&StringLen); + opts.AddLongOption("int-cols", "Number of int columns") + .DefaultValue((ui64)LogWorkloadConstants::INT_COLUMNS_CNT).StoreResult(&IntColumnsCnt); + opts.AddLongOption("str-cols", "Number of string columns") + .DefaultValue((ui64)LogWorkloadConstants::STR_COLUMNS_CNT).StoreResult(&StrColumnsCnt); + opts.AddLongOption("key-cols", "Number of key columns") + .DefaultValue((ui64)LogWorkloadConstants::KEY_COLUMNS_CNT).StoreResult(&KeyColumnsCnt); + opts.AddLongOption("ttl", "TTL for timestamp column in minutes") + .DefaultValue((ui64)LogWorkloadConstants::TIMESTAMP_TTL_MIN).StoreResult(&TimestampTtlMinutes); + opts.AddLongOption("store", "Storage type." + " Options: row, column\n" + " row - use row-based storage engine;\n" + " column - use column-based storage engine.") + .DefaultValue(StoreType) + .Handler1T([this](TStringBuf arg) { + const auto l = to_lower(TString(arg)); + if (!TryFromString(arg, StoreType)) { + throw yexception() << "Ivalid store type: " << arg; + } + }); + break; + case TWorkloadParams::ECommandType::Run: + opts.AddLongOption("int-cols", "Number of int columns") + .DefaultValue((ui64)LogWorkloadConstants::INT_COLUMNS_CNT).StoreResult(&IntColumnsCnt); + opts.AddLongOption("str-cols", "Number of string columns") + .DefaultValue((ui64)LogWorkloadConstants::STR_COLUMNS_CNT).StoreResult(&StrColumnsCnt); + opts.AddLongOption("key-cols", "Number of key columns") + .DefaultValue((ui64)LogWorkloadConstants::KEY_COLUMNS_CNT).StoreResult(&KeyColumnsCnt); + switch (static_cast(workloadType)) { + case TLogGenerator::EType::Select: + case TLogGenerator::EType::Insert: + case TLogGenerator::EType::Upsert: + case TLogGenerator::EType::BulkUpsert: + opts.AddLongOption("len", "String len") + .DefaultValue((ui64)LogWorkloadConstants::STRING_LEN).StoreResult(&StringLen); + opts.AddLongOption("rows", "Number of rows to upsert") + .DefaultValue((ui64)LogWorkloadConstants::ROWS_CNT).StoreResult(&RowsCnt); + opts.AddLongOption("timestamp_deviation", "Standard deviation. For each timestamp, a random variable with a specified standard deviation in minutes is added.") + .DefaultValue((ui64)LogWorkloadConstants::TIMESTAMP_STANDARD_DEVIATION_MINUTES).StoreResult(&TimestampStandardDeviationMinutes); + break; + } + break; + default: + break; + } +} + +THolder TMixedWorkloadParams::CreateGenerator() const { + return MakeHolder(this); +} + +TString TMixedWorkloadParams::GetWorkloadName() const { + return "Log"; +} + +} // namespace NMixed + +} // namespace NYdbWorkload diff --git a/ydb/library/workload/mixed/mixed.h b/ydb/library/workload/mixed/mixed.h new file mode 100644 index 000000000000..08e27ca93f55 --- /dev/null +++ b/ydb/library/workload/mixed/mixed.h @@ -0,0 +1,109 @@ +#pragma once + +#include + +#include + +namespace NYdbWorkload { + +namespace NMixed { + +enum LogWorkloadConstants : ui64 { + MIN_PARTITIONS = 40, + MAX_PARTITIONS = 1000, + PARTITION_SIZE_MB = 2000, + STRING_LEN = 8, + STR_COLUMNS_CNT = 1, + INT_COLUMNS_CNT = 1, + KEY_COLUMNS_CNT = 1, + ROWS_CNT = 1, + PARTITIONS_BY_LOAD = true, + + TIMESTAMP_STANDARD_DEVIATION_MINUTES = 0, + TIMESTAMP_TTL_MIN = 60, +}; + +class TMixedWorkloadParams : public TWorkloadParams { +public: + enum class EStoreType { + Row /* "row" */, + Column /* "column" */, + }; + + void ConfigureOpts(NLastGetopt::TOpts& opts, const ECommandType commandType, int workloadType) override; + THolder CreateGenerator() const override; + TString GetWorkloadName() const override; + ui64 MinPartitions = LogWorkloadConstants::MIN_PARTITIONS; + ui64 MaxPartitions = LogWorkloadConstants::MAX_PARTITIONS; + ui64 PartitionSizeMb = LogWorkloadConstants::PARTITION_SIZE_MB; + ui64 StringLen = LogWorkloadConstants::STRING_LEN; + ui64 StrColumnsCnt = LogWorkloadConstants::STR_COLUMNS_CNT; + ui64 IntColumnsCnt = LogWorkloadConstants::INT_COLUMNS_CNT; + ui64 KeyColumnsCnt = LogWorkloadConstants::KEY_COLUMNS_CNT; + ui64 TimestampStandardDeviationMinutes = LogWorkloadConstants::TIMESTAMP_STANDARD_DEVIATION_MINUTES; + ui64 TimestampTtlMinutes = LogWorkloadConstants::TIMESTAMP_STANDARD_DEVIATION_MINUTES; + ui64 RowsCnt = LogWorkloadConstants::ROWS_CNT; + bool PartitionsByLoad = LogWorkloadConstants::PARTITIONS_BY_LOAD; + + std::string TableName = "log_writer_test"; + + YDB_READONLY(EStoreType, StoreType, EStoreType::Row); +}; + +class TLogGenerator final: public TWorkloadQueryGeneratorBase { +public: + using TBase = TWorkloadQueryGeneratorBase; + struct TRow { + TInstant Ts; + TVector Ints; + TVector Strings; + + TString ToString() const { + std::stringstream ss; + ss << "( "; + for (auto i : Ints) { + ss << i << " "; + } + for (auto s : Strings) { + ss << s << " "; + } + ss << ")"; + return ss.str(); + } + + bool operator == (const TRow &other) const { + return Ts == other.Ts && Ints == other.Ints && Strings == other.Strings; + } + }; + TLogGenerator(const TMixedWorkloadParams* params); + + std::string GetDDLQueries() const override; + + TQueryInfoList GetInitialData() override; + + TVector GetCleanPaths() const override; + + TQueryInfoList GetWorkload(int type) override; + TVector GetSupportedWorkloadTypes() const override; + + enum class EType { + Insert, + Upsert, + BulkUpsert, + Select + }; + +private: + TQueryInfoList WriteRows(TString operation, TVector&& rows); + TQueryInfoList Select(TVector&& rows); + TQueryInfoList Insert(TVector&& rows); + TQueryInfoList Upsert(TVector&& rows); + TQueryInfoList BulkUpsert(TVector&& rows); + TVector GenerateRandomRows(); + + const ui64 TotalColumnsCnt; +}; + +} // namespace NMixed + +} // namespace NYdbWorkload diff --git a/ydb/library/workload/mixed/registrar.cpp b/ydb/library/workload/mixed/registrar.cpp new file mode 100644 index 000000000000..8a8042cf343f --- /dev/null +++ b/ydb/library/workload/mixed/registrar.cpp @@ -0,0 +1,12 @@ +#include "mixed.h" +#include + +namespace NYdbWorkload { + +namespace NMixed { + +TWorkloadFactory::TRegistrator Registrar("mixed"); + +} // namespace NMixed + +} // namespace NYdbWorkload diff --git a/ydb/library/workload/mixed/ya.make b/ydb/library/workload/mixed/ya.make new file mode 100644 index 000000000000..6cdd7dc405de --- /dev/null +++ b/ydb/library/workload/mixed/ya.make @@ -0,0 +1,14 @@ +LIBRARY() + +SRCS( + GLOBAL registrar.cpp + mixed.cpp +) + +PEERDIR( + ydb/library/workload/abstract +) + +GENERATE_ENUM_SERIALIZATION_WITH_HEADER(mixed.h) + +END() diff --git a/ydb/library/workload/ya.make b/ydb/library/workload/ya.make index 7819c15847a4..b269c9422a5e 100644 --- a/ydb/library/workload/ya.make +++ b/ydb/library/workload/ya.make @@ -5,6 +5,7 @@ PEERDIR( ydb/library/workload/clickbench ydb/library/workload/kv ydb/library/workload/log + ydb/library/workload/mixed ydb/library/workload/stock ydb/library/workload/tpcds ydb/library/workload/tpch @@ -18,6 +19,7 @@ RECURSE( clickbench kv log + mixed stock tpc_base tpcds diff --git a/ydb/public/lib/ydb_cli/commands/ydb_workload.cpp b/ydb/public/lib/ydb_cli/commands/ydb_workload.cpp index 10e3423996da..a5ce8a927349 100644 --- a/ydb/public/lib/ydb_cli/commands/ydb_workload.cpp +++ b/ydb/public/lib/ydb_cli/commands/ydb_workload.cpp @@ -268,7 +268,7 @@ void TWorkloadCommand::WorkerFn(int taskId, NYdbWorkload::IWorkloadQueryGenerato int TWorkloadCommand::RunWorkload(NYdbWorkload::IWorkloadQueryGenerator& workloadGen, const int type) { if (!Quiet) { - std::cout << "Window\tTxs/Sec\tRetries\tErrors\tp50(ms)\tp95(ms)\tp99(ms)\tpMax(ms)"; + std::cout << "Window\tTxs\tTxs/Sec\tRetries\tErrors\tp50(ms)\tp95(ms)\tp99(ms)\tpMax(ms)"; if (PrintTimestamp) { std::cout << "\tTimestamp"; } @@ -320,7 +320,7 @@ void TWorkloadCommand::PrintWindowStats(int windowIt) { WindowHist.Reset(); } if (!Quiet) { - std::cout << windowIt << "\t" << std::setw(7) << stats.OpsCount / WindowSec << "\t" << retries << "\t" + std::cout << windowIt << "\t" << std::setw(7) << stats.OpsCount << "\t" << stats.OpsCount / WindowSec << "\t" << retries << "\t" << errors << "\t" << stats.Percentile50 << "\t" << stats.Percentile95 << "\t" << stats.Percentile99 << "\t" << stats.Percentile100; if (PrintTimestamp) { diff --git a/ydb/tests/stress/mixedpy/test_mixed.py b/ydb/tests/stress/mixedpy/test_mixed.py new file mode 100644 index 000000000000..50f1ef0e23e7 --- /dev/null +++ b/ydb/tests/stress/mixedpy/test_mixed.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- +import os +import sys + +import pytest + +import yatest + +from ydb.tests.library.harness.kikimr_runner import KiKiMR +from ydb.tests.library.harness.kikimr_config import KikimrConfigGenerator +from ydb.tests.olap.lib.utils import get_external_param + + +class TestYdbMixedWorkload(object): + @classmethod + def setup_class(cls): + cls.cluster = KiKiMR(KikimrConfigGenerator()) + cls.cluster.start() + + def get_command_prefix(self, subcmds: list[str]) -> list[str]: + return [ + yatest.common.binary_path(os.getenv('YDB_CLI_BINARY')), + '--verbose', + '--endpoint', self.endpoint, + '--database={}'.format(self.database), + 'workload', 'mixed' + ] + subcmds + + @classmethod + def teardown_class(cls): + cls.cluster.stop() + + @classmethod + def get_cols_count_command_params(cls) -> list[str]: + return [ + '--int-cols', '5', + '--str-cols', '5', + ] + + def get_bulk_upsert_cmd(self, duration: str): + return self.get_command_prefix(subcmds=['run', 'bulk_upsert'] + self.get_cols_count_command_params()) + [ + '-s', duration, + '-t', '40', + '--rows', '1000', + '--window', '20', + '--len', '1000', + ] + + def get_select_cmd(self, duration: str): + return self.get_command_prefix(subcmds=['run', 'select']) + [ + '-s', duration, + '-t', '5', + '--rows', '100', + ] + + def get_update_cmd(self, duration: str): + return self.get_command_prefix(subcmds=['run', 'upsert'] + self.get_cols_count_command_params()) + [ + '-s', duration, + '-t', '5', + '--rows', '100', + '--len', '1000', + ] + + @classmethod + def print_txs(cls, step: str, filename: str): + found = False + with open(filename, 'r') as f: + for line in f.readlines(): + if found: + print('{} txs/sec: {}'.format(step, line.split()[1])) + break + else: + words = line.split() + if len(words) > 0 and words[0] == 'Txs': + found = True + + @pytest.mark.parametrize('store_type', ['row', 'column']) + def test(self, store_type): + duration = get_external_param('duration', '120') + self.endpoint = get_external_param('endpoint', 'grpc://localhost:%d' % self.cluster.nodes[1].grpc_port) + self.database = get_external_param('database', '/Root') + yatest.common.execute( + self.get_command_prefix(subcmds=['clean'])) + + yatest.common.execute( + self.get_command_prefix(subcmds=['init'] + self.get_cols_count_command_params()) + [ + '--store', store_type, + ]) + + with open('upsert_out', 'w+') as out: + yatest.common.execute(self.get_bulk_upsert_cmd(duration), stdout=out, stderr=sys.stderr) + + with open('upsert1_out', 'w+') as out: + bulk_upsert = yatest.common.execute(self.get_bulk_upsert_cmd(duration), wait=False, stdout=out, stderr=sys.stderr) + select = yatest.common.execute(self.get_select_cmd(duration), wait=False) + bulk_upsert.wait() + select.wait() + + with open('upsert2_out', 'w+') as out: + bulk_upsert = yatest.common.execute(self.get_bulk_upsert_cmd(duration), wait=False, stdout=out, stderr=sys.stderr) + select = yatest.common.execute(self.get_select_cmd(duration), wait=False) + update = yatest.common.execute(self.get_update_cmd(duration), wait=False) + bulk_upsert.wait() + select.wait() + update.wait() + self.print_txs('Upsert', 'upsert_out') + self.print_txs('Select', 'upsert1_out') + self.print_txs('Update', 'upsert2_out') diff --git a/ydb/tests/stress/mixedpy/ya.make b/ydb/tests/stress/mixedpy/ya.make new file mode 100644 index 000000000000..244460f7c924 --- /dev/null +++ b/ydb/tests/stress/mixedpy/ya.make @@ -0,0 +1,31 @@ +PY3TEST() +ENV(YDB_DRIVER_BINARY="ydb/apps/ydbd/ydbd") +ENV(YDB_CLI_BINARY="ydb/apps/ydb/ydb") + + +TEST_SRCS( + test_mixed.py +) + +IF (SANITIZER_TYPE) + REQUIREMENTS(ram:32) +ELSE() + REQUIREMENTS(ram:16) +ENDIF() + +TIMEOUT(1200) +SIZE(LARGE) +TAG(ya:fat) + +DEPENDS( + ydb/apps/ydbd + ydb/apps/ydb +) + +PEERDIR( + ydb/tests/library + ydb/tests/olap/lib +) + + +END() diff --git a/ydb/tests/stress/ya.make b/ydb/tests/stress/ya.make index a688f425b899..95ed1f67463e 100644 --- a/ydb/tests/stress/ya.make +++ b/ydb/tests/stress/ya.make @@ -1,6 +1,7 @@ RECURSE( kv log + mixedpy olap_workload oltp_workload simple_queue From 0fd1b879589ea8263582a184ccbeac61fd38b596 Mon Sep 17 00:00:00 2001 From: kirilltatunov Date: Wed, 9 Apr 2025 17:42:42 +0300 Subject: [PATCH 107/454] Fix graphics backend initialization in skia MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Использовалась заглушка, которая ничего не делает. По какой-то причине эти файлы нужно использовать разные на разных платформах в отличие от всех остальных файлов, где платформенно-специфичное поведение достигается через `#ifdef` в самих файлах. commit_hash:3368ad5fbc484df3b185bb1b69ae7a5f13afe522 --- build/sysincl/android.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/sysincl/android.yml b/build/sysincl/android.yml index d3bfbef9635b..30053ec76352 100644 --- a/build/sysincl/android.yml +++ b/build/sysincl/android.yml @@ -15,6 +15,8 @@ - jni.h - EGL/egl.h - EGL/eglext.h + - GLES/gl.h + - GLES/glext.h - GLES2/gl2.h - GLES2/gl2ext.h - GLES3/gl31.h From 394fee4aa8d48e58cf82c72bcb9dda0a5dd50190 Mon Sep 17 00:00:00 2001 From: vityaman Date: Wed, 9 Apr 2025 17:57:35 +0300 Subject: [PATCH 108/454] YQL-19747 Complete select and insert hints - Related to https://github.com/ydb-platform/ydb/issues/9056 - Related to https://github.com/vityaman/ydb/issues/19 --- Pull Request resolved: https://github.com/ytsaurus/ytsaurus/pull/1189 commit_hash:7f1cb1dcf0617aa2c94c3f2188fc9bd481380252 --- .../sql/v1/complete/core/statement.h | 10 ++++ yql/essentials/sql/v1/complete/core/ya.make | 3 + .../sql/v1/complete/name/name_service.h | 15 ++++- .../sql/v1/complete/name/static/frequency.cpp | 13 +++- .../sql/v1/complete/name/static/frequency.h | 1 + .../v1/complete/name/static/frequency_ut.cpp | 6 ++ .../v1/complete/name/static/json_name_set.cpp | 33 +++++++++- .../v1/complete/name/static/name_service.cpp | 10 ++++ .../v1/complete/name/static/name_service.h | 1 + .../sql/v1/complete/name/static/ranking.cpp | 6 ++ .../sql/v1/complete/name/static/ya.make | 1 + yql/essentials/sql/v1/complete/name/ya.make | 4 ++ .../sql/v1/complete/sql_complete.cpp | 12 ++++ yql/essentials/sql/v1/complete/sql_complete.h | 1 + .../sql/v1/complete/sql_complete_ut.cpp | 60 +++++++++++++++---- .../sql/v1/complete/syntax/local.cpp | 39 ++++++++---- yql/essentials/sql/v1/complete/syntax/local.h | 5 ++ .../v1/complete/syntax/parser_call_stack.cpp | 22 +++++++ .../v1/complete/syntax/parser_call_stack.h | 5 ++ yql/essentials/sql/v1/complete/ya.make | 1 + 20 files changed, 220 insertions(+), 28 deletions(-) create mode 100644 yql/essentials/sql/v1/complete/core/statement.h create mode 100644 yql/essentials/sql/v1/complete/core/ya.make diff --git a/yql/essentials/sql/v1/complete/core/statement.h b/yql/essentials/sql/v1/complete/core/statement.h new file mode 100644 index 000000000000..d4c095a0e1fd --- /dev/null +++ b/yql/essentials/sql/v1/complete/core/statement.h @@ -0,0 +1,10 @@ +#pragma once + +namespace NSQLComplete { + + enum class EStatementKind { + Select, + Insert, + }; + +} // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/core/ya.make b/yql/essentials/sql/v1/complete/core/ya.make new file mode 100644 index 000000000000..9865d255c8f1 --- /dev/null +++ b/yql/essentials/sql/v1/complete/core/ya.make @@ -0,0 +1,3 @@ +LIBRARY() + +END() diff --git a/yql/essentials/sql/v1/complete/name/name_service.h b/yql/essentials/sql/v1/complete/name/name_service.h index 6a7e38dfc208..34a109d00137 100644 --- a/yql/essentials/sql/v1/complete/name/name_service.h +++ b/yql/essentials/sql/v1/complete/name/name_service.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -29,16 +31,24 @@ namespace NSQLComplete { struct TConstraints: TNamespaced {}; }; + struct THintName: TIndentifier { + struct TConstraints { + EStatementKind Statement; + }; + }; + using TGenericName = std::variant< TPragmaName, TTypeName, - TFunctionName>; + TFunctionName, + THintName>; struct TNameRequest { struct { std::optional Pragma; std::optional Type; std::optional Function; + std::optional Hint; } Constraints; TString Prefix = ""; size_t Limit = 128; @@ -46,7 +56,8 @@ namespace NSQLComplete { bool IsEmpty() const { return !Constraints.Pragma && !Constraints.Type && - !Constraints.Function; + !Constraints.Function && + !Constraints.Hint; } }; diff --git a/yql/essentials/sql/v1/complete/name/static/frequency.cpp b/yql/essentials/sql/v1/complete/name/static/frequency.cpp index 2de082e287ec..b3707533e693 100644 --- a/yql/essentials/sql/v1/complete/name/static/frequency.cpp +++ b/yql/essentials/sql/v1/complete/name/static/frequency.cpp @@ -19,6 +19,8 @@ namespace NSQLComplete { const char* Func = "FUNC"; const char* Module = "MODULE"; const char* ModuleFunc = "MODULE_FUNC"; + const char* ReadHint = "READ_HINT"; + const char* InsertHint = "INSERT_HINT"; } Parent; } Json; @@ -58,7 +60,9 @@ namespace NSQLComplete { item.Parent == Json.Parent.Type || item.Parent == Json.Parent.Func || item.Parent == Json.Parent.ModuleFunc || - item.Parent == Json.Parent.Module) { + item.Parent == Json.Parent.Module || + item.Parent == Json.Parent.ReadHint || + item.Parent == Json.Parent.InsertHint) { item.Rule = ToLowerUTF8(item.Rule); } @@ -66,11 +70,14 @@ namespace NSQLComplete { data.Pragmas[item.Rule] += item.Sum; } else if (item.Parent == Json.Parent.Type) { data.Types[item.Rule] += item.Sum; + } else if (item.Parent == Json.Parent.Module) { + // Ignore, unsupported: Modules } else if (item.Parent == Json.Parent.Func || item.Parent == Json.Parent.ModuleFunc) { data.Functions[item.Rule] += item.Sum; - } else if (item.Parent == Json.Parent.Module) { - // Ignore, unsupported: Modules + } else if (item.Parent == Json.Parent.ReadHint || + item.Parent == Json.Parent.InsertHint) { + data.Hints[item.Rule] += item.Sum; } else { // Ignore, unsupported: Parser Call Stacks } diff --git a/yql/essentials/sql/v1/complete/name/static/frequency.h b/yql/essentials/sql/v1/complete/name/static/frequency.h index 067453bc4044..024d93cefcb1 100644 --- a/yql/essentials/sql/v1/complete/name/static/frequency.h +++ b/yql/essentials/sql/v1/complete/name/static/frequency.h @@ -9,6 +9,7 @@ namespace NSQLComplete { THashMap Pragmas; THashMap Types; THashMap Functions; + THashMap Hints; }; TFrequencyData ParseJsonFrequencyData(const TStringBuf text); diff --git a/yql/essentials/sql/v1/complete/name/static/frequency_ut.cpp b/yql/essentials/sql/v1/complete/name/static/frequency_ut.cpp index dd6ee2cfbb29..a5fd8fad00ac 100644 --- a/yql/essentials/sql/v1/complete/name/static/frequency_ut.cpp +++ b/yql/essentials/sql/v1/complete/name/static/frequency_ut.cpp @@ -12,6 +12,8 @@ Y_UNIT_TEST_SUITE(FrequencyTests) { {"parent":"TYPE","rule":"BIGINT","sum":7101}, {"parent":"MODULE_FUNC","rule":"Compress::BZip2","sum":2}, {"parent":"MODULE","rule":"re2","sum":3094}, + {"parent":"READ_HINT","rule":"COLUMNS","sum":826110}, + {"parent":"INSERT_HINT","rule":"COLUMN_GROUPS","sum":225}, {"parent":"TRule_action_or_subquery_args","rule":"TRule_action_or_subquery_args.Block2","sum":4874480} ])"); @@ -23,6 +25,10 @@ Y_UNIT_TEST_SUITE(FrequencyTests) { {"abc", 1}, {"compress::bzip2", 2}, }, + .Hints = { + {"columns", 826110}, + {"column_groups", 225}, + }, }; UNIT_ASSERT_VALUES_EQUAL(actual.Types, expected.Types); diff --git a/yql/essentials/sql/v1/complete/name/static/json_name_set.cpp b/yql/essentials/sql/v1/complete/name/static/json_name_set.cpp index 9fdf314fee61..bc522fd674c8 100644 --- a/yql/essentials/sql/v1/complete/name/static/json_name_set.cpp +++ b/yql/essentials/sql/v1/complete/name/static/json_name_set.cpp @@ -3,6 +3,8 @@ #include #include +#include + namespace NSQLComplete { NJson::TJsonValue LoadJsonResource(const TStringBuf filename) { @@ -38,7 +40,7 @@ namespace NSQLComplete { return ParseNames(json.GetArraySafe()); } - TVector ParseUfs(NJson::TJsonValue json) { + TVector ParseUdfs(NJson::TJsonValue json) { TVector names; for (auto& [module, v] : json.GetMapSafe()) { auto functions = ParseNames(v.GetArraySafe()); @@ -50,13 +52,40 @@ namespace NSQLComplete { return names; } + // TODO(YQL-19747): support multiple systems, name service/set hierarchy - common & special + THashMap> ParseHints(NJson::TJsonValue json) { + THashMap> hints; + + THashMap StatementNames = { + {EStatementKind::Select, "read"}, + {EStatementKind::Insert, "insert"}, + }; + + for (const auto& [k, kname] : StatementNames) { + for (auto& [_, values] : json.GetMapSafe().at(kname).GetMapSafe()) { + for (auto& name : ParseNames(values.GetMapSafe().at("hints").GetArraySafe())) { + hints[k].emplace_back(std::move(name)); + } + } + } + + for (auto& [_, hints] : hints) { + for (auto& hint : hints) { + hint = ToUpperUTF8(hint); + } + } + + return hints; + } + NameSet MakeDefaultNameSet() { return { .Pragmas = ParsePragmas(LoadJsonResource("pragmas_opensource.json")), .Types = ParseTypes(LoadJsonResource("types.json")), .Functions = Merge( ParseFunctions(LoadJsonResource("sql_functions.json")), - ParseUfs(LoadJsonResource("udfs_basic.json"))), + ParseUdfs(LoadJsonResource("udfs_basic.json"))), + .Hints = ParseHints(LoadJsonResource("statements_opensource.json")), }; } diff --git a/yql/essentials/sql/v1/complete/name/static/name_service.cpp b/yql/essentials/sql/v1/complete/name/static/name_service.cpp index 427691985793..37f5a06785bc 100644 --- a/yql/essentials/sql/v1/complete/name/static/name_service.cpp +++ b/yql/essentials/sql/v1/complete/name/static/name_service.cpp @@ -74,6 +74,9 @@ namespace NSQLComplete { Sort(NameSet_.Pragmas, NoCaseCompare); Sort(NameSet_.Types, NoCaseCompare); Sort(NameSet_.Functions, NoCaseCompare); + for (auto& [_, hints] : NameSet_.Hints) { + Sort(hints, NoCaseCompare); + } } TFuture Lookup(TNameRequest request) override { @@ -97,6 +100,13 @@ namespace NSQLComplete { AppendAs(response.RankedNames, names); } + if (request.Constraints.Hint) { + const auto stmt = request.Constraints.Hint->Statement; + AppendAs( + response.RankedNames, + FilteredByPrefix(request.Prefix, NameSet_.Hints[stmt])); + } + Ranking_->CropToSortedPrefix(response.RankedNames, request.Limit); for (auto& name : response.RankedNames) { diff --git a/yql/essentials/sql/v1/complete/name/static/name_service.h b/yql/essentials/sql/v1/complete/name/static/name_service.h index 348d6ece454b..d5459faa1d76 100644 --- a/yql/essentials/sql/v1/complete/name/static/name_service.h +++ b/yql/essentials/sql/v1/complete/name/static/name_service.h @@ -10,6 +10,7 @@ namespace NSQLComplete { TVector Pragmas; TVector Types; TVector Functions; + THashMap> Hints; }; NameSet MakeDefaultNameSet(); diff --git a/yql/essentials/sql/v1/complete/name/static/ranking.cpp b/yql/essentials/sql/v1/complete/name/static/ranking.cpp index b3d5c3c8c31a..79ebbc98003d 100644 --- a/yql/essentials/sql/v1/complete/name/static/ranking.cpp +++ b/yql/essentials/sql/v1/complete/name/static/ranking.cpp @@ -77,6 +77,12 @@ namespace NSQLComplete { } } + if constexpr (std::is_same_v) { + if (auto weight = Frequency_.Hints.FindPtr(identifier)) { + return *weight; + } + } + return 0; }, name); } diff --git a/yql/essentials/sql/v1/complete/name/static/ya.make b/yql/essentials/sql/v1/complete/name/static/ya.make index 3c6547f3b526..155c0926399d 100644 --- a/yql/essentials/sql/v1/complete/name/static/ya.make +++ b/yql/essentials/sql/v1/complete/name/static/ya.make @@ -17,6 +17,7 @@ RESOURCE( yql/essentials/data/language/types.json types.json yql/essentials/data/language/sql_functions.json sql_functions.json yql/essentials/data/language/udfs_basic.json udfs_basic.json + yql/essentials/data/language/statements_opensource.json statements_opensource.json yql/essentials/data/language/rules_corr_basic.json rules_corr_basic.json ) diff --git a/yql/essentials/sql/v1/complete/name/ya.make b/yql/essentials/sql/v1/complete/name/ya.make index c8af42acfb08..43f7dc2c1b30 100644 --- a/yql/essentials/sql/v1/complete/name/ya.make +++ b/yql/essentials/sql/v1/complete/name/ya.make @@ -1,5 +1,9 @@ LIBRARY() +PEERDIR( + yql/essentials/sql/v1/complete/core +) + END() RECURSE( diff --git a/yql/essentials/sql/v1/complete/sql_complete.cpp b/yql/essentials/sql/v1/complete/sql_complete.cpp index 85fcf87afd17..c3581bfc9ea2 100644 --- a/yql/essentials/sql/v1/complete/sql_complete.cpp +++ b/yql/essentials/sql/v1/complete/sql_complete.cpp @@ -101,6 +101,12 @@ namespace NSQLComplete { request.Constraints.Function = std::move(constraints); } + if (context.Hint) { + THintName::TConstraints constraints; + constraints.Statement = context.Hint->StatementKind; + request.Constraints.Hint = std::move(constraints); + } + if (request.IsEmpty()) { return; } @@ -125,6 +131,9 @@ namespace NSQLComplete { name.Indentifier += "("; return {ECandidateKind::FunctionName, std::move(name.Indentifier)}; } + if constexpr (std::is_base_of_v) { + return {ECandidateKind::HintName, std::move(name.Indentifier)}; + } }, std::move(name))); } } @@ -182,6 +191,9 @@ void Out(IOutputStream& out, NSQLComplete::ECandid case NSQLComplete::ECandidateKind::FunctionName: out << "FunctionName"; break; + case NSQLComplete::ECandidateKind::HintName: + out << "HintName"; + break; } } diff --git a/yql/essentials/sql/v1/complete/sql_complete.h b/yql/essentials/sql/v1/complete/sql_complete.h index 5d0271b4dca7..de7a597d517a 100644 --- a/yql/essentials/sql/v1/complete/sql_complete.h +++ b/yql/essentials/sql/v1/complete/sql_complete.h @@ -23,6 +23,7 @@ namespace NSQLComplete { PragmaName, TypeName, FunctionName, + HintName, }; struct TCandidate { diff --git a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp index 7d595842afb8..4e3b84be6176 100644 --- a/yql/essentials/sql/v1/complete/sql_complete_ut.cpp +++ b/yql/essentials/sql/v1/complete/sql_complete_ut.cpp @@ -38,6 +38,7 @@ class TSilentNameService: public INameService { Y_UNIT_TEST_SUITE(SqlCompleteTests) { using ECandidateKind::FunctionName; + using ECandidateKind::HintName; using ECandidateKind::Keyword; using ECandidateKind::PragmaName; using ECandidateKind::TypeName; @@ -59,6 +60,10 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { .Pragmas = {"yson.CastToString"}, .Types = {"Uint64"}, .Functions = {"StartsWith", "DateTime::Split"}, + .Hints = { + {EStatementKind::Select, {"XLOCK"}}, + {EStatementKind::Insert, {"EXPIRATION"}}, + }, }; auto ranking = MakeDefaultRanking({}); INameService::TPtr service = MakeStaticNameService(std::move(names), std::move(ranking)); @@ -69,6 +74,12 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { return engine->Complete(input).Candidates; } + TVector CompleteTop(size_t limit, ISqlCompletionEngine::TPtr& engine, TCompletionInput input) { + auto candidates = Complete(engine, input); + candidates.crop(limit); + return candidates; + } + Y_UNIT_TEST(Beginning) { TVector expected = { {Keyword, "ALTER"}, @@ -465,6 +476,28 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { } } + Y_UNIT_TEST(SelectTableHintName) { + TVector expected = { + {Keyword, "COLUMNS"}, + {Keyword, "SCHEMA"}, + {HintName, "XLOCK"}, + }; + + auto engine = MakeSqlCompletionEngineUT(); + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT key FROM my_table WITH "}), expected); + } + + Y_UNIT_TEST(InsertTableHintName) { + TVector expected = { + {Keyword, "COLUMNS"}, + {Keyword, "SCHEMA"}, + {HintName, "EXPIRATION"}, + }; + + auto engine = MakeSqlCompletionEngineUT(); + UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"INSERT INTO my_table WITH "}), expected); + } + Y_UNIT_TEST(UTF8Wide) { auto engine = MakeSqlCompletionEngineUT(); UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"\xF0\x9F\x98\x8A"}).size(), 0); @@ -606,17 +639,19 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { {"minby", 32}, {"maxby", 32}, }, + .Hints = { + {"xlock", 4}, + {"unordered", 2}, + }, }; auto service = MakeStaticNameService(MakeDefaultNameSet(), MakeDefaultRanking(frequency)); auto engine = MakeSqlCompletionEngine(MakePureLexerSupplier(), std::move(service)); { - TVector expectedPrefix = { + TVector expected = { {PragmaName, "DefaultMemoryLimit"}, {PragmaName, "Annotations"}, }; - auto actualPrefix = Complete(engine, {"PRAGMA yt."}); - actualPrefix.crop(expectedPrefix.size()); - UNIT_ASSERT_VALUES_EQUAL(actualPrefix, expectedPrefix); + UNIT_ASSERT_VALUES_EQUAL(CompleteTop(expected.size(), engine, {"PRAGMA yt."}), expected); } { TVector expected = { @@ -630,7 +665,7 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { UNIT_ASSERT_VALUES_EQUAL(Complete(engine, {"SELECT OPTIONAL expectedPrefix = { + TVector expected = { {FunctionName, "Min("}, {FunctionName, "Max("}, {FunctionName, "MaxOf("}, @@ -640,11 +675,16 @@ Y_UNIT_TEST_SUITE(SqlCompleteTests) { {FunctionName, "Math::Acos("}, {FunctionName, "Math::Asin("}, }; - - auto actualPrefix = Complete(engine, {"SELECT m"}); - actualPrefix.crop(expectedPrefix.size()); - - UNIT_ASSERT_VALUES_EQUAL(actualPrefix, expectedPrefix); + UNIT_ASSERT_VALUES_EQUAL(CompleteTop(expected.size(), engine, {"SELECT m"}), expected); + } + { + TVector expected = { + {Keyword, "COLUMNS"}, + {Keyword, "SCHEMA"}, + {HintName, "XLOCK"}, + {HintName, "UNORDERED"}, + }; + UNIT_ASSERT_VALUES_EQUAL(CompleteTop(expected.size(), engine, {"SELECT * FROM a WITH "}), expected); } } diff --git a/yql/essentials/sql/v1/complete/syntax/local.cpp b/yql/essentials/sql/v1/complete/syntax/local.cpp index 28ace474f8e4..e6a7430ca27b 100644 --- a/yql/essentials/sql/v1/complete/syntax/local.cpp +++ b/yql/essentials/sql/v1/complete/syntax/local.cpp @@ -22,6 +22,13 @@ namespace NSQLComplete { + template StackPredicate> + std::regular_invocable auto RuleAdapted(StackPredicate predicate) { + return [=](const TMatchedRule& rule) { + return predicate(rule.ParserCallStack); + }; + } + template class TSpecializedLocalSyntaxAnalysis: public ILocalSyntaxAnalysis { private: @@ -61,6 +68,7 @@ namespace NSQLComplete { .Pragma = PragmaMatch(tokens, candidates), .IsTypeName = IsTypeNameMatched(candidates), .Function = FunctionMatch(tokens, candidates), + .Hint = HintMatch(candidates), }; } @@ -137,10 +145,7 @@ namespace NSQLComplete { std::optional PragmaMatch( const NSQLTranslation::TParsedTokenList& tokens, const TC3Candidates& candidates) { - bool isMatched = AnyOf(candidates.Rules, [&](const TMatchedRule& rule) { - return IsLikelyPragmaStack(rule.ParserCallStack); - }); - if (!isMatched) { + if (!AnyOf(candidates.Rules, RuleAdapted(IsLikelyPragmaStack))) { return std::nullopt; } @@ -154,17 +159,12 @@ namespace NSQLComplete { } bool IsTypeNameMatched(const TC3Candidates& candidates) { - return AnyOf(candidates.Rules, [&](const TMatchedRule& rule) { - return IsLikelyTypeStack(rule.ParserCallStack); - }); + return AnyOf(candidates.Rules, RuleAdapted(IsLikelyTypeStack)); } std::optional FunctionMatch( const NSQLTranslation::TParsedTokenList& tokens, const TC3Candidates& candidates) { - bool isMatched = AnyOf(candidates.Rules, [&](const TMatchedRule& rule) { - return IsLikelyFunctionStack(rule.ParserCallStack); - }); - if (!isMatched) { + if (!AnyOf(candidates.Rules, RuleAdapted(IsLikelyFunctionStack))) { return std::nullopt; } @@ -177,6 +177,23 @@ namespace NSQLComplete { return function; } + std::optional HintMatch(const TC3Candidates& candidates) { + // TODO(YQL-19747): detect local contexts with a single iteration through the candidates.Rules + auto rule = FindIf(candidates.Rules, RuleAdapted(IsLikelyHintStack)); + if (rule == std::end(candidates.Rules)) { + return std::nullopt; + } + + auto stmt = StatementKindOf(rule->ParserCallStack); + if (stmt == std::nullopt) { + return std::nullopt; + } + + return TLocalSyntaxContext::THint{ + .StatementKind = *stmt, + }; + } + NSQLTranslation::TParsedTokenList Tokenized(const TStringBuf text) { NSQLTranslation::TParsedTokenList tokens; NYql::TIssues issues; diff --git a/yql/essentials/sql/v1/complete/syntax/local.h b/yql/essentials/sql/v1/complete/syntax/local.h index 24e78108e10e..8d51c54df577 100644 --- a/yql/essentials/sql/v1/complete/syntax/local.h +++ b/yql/essentials/sql/v1/complete/syntax/local.h @@ -18,10 +18,15 @@ namespace NSQLComplete { TString Namespace; }; + struct THint { + EStatementKind StatementKind; + }; + TVector Keywords; std::optional Pragma; bool IsTypeName; std::optional Function; + std::optional Hint; }; class ILocalSyntaxAnalysis { diff --git a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp index 1bfcac47266f..bbe0b3d371c1 100644 --- a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp +++ b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.cpp @@ -6,6 +6,8 @@ #include #include +#include + #define DEBUG_SYMBOLIZE_STACK(stack) \ auto debug_symbolized_##stack = Symbolized(stack) @@ -40,6 +42,10 @@ namespace NSQLComplete { RULE(Id_or_type), }; + const TVector HintNameRules = { + RULE(Id_hint), + }; + TVector Symbolized(const TParserCallStack& stack) { const ISqlGrammar& grammar = GetSqlGrammar(); @@ -89,6 +95,22 @@ namespace NSQLComplete { EndsWith({RULE(Atom_expr), RULE(Id_or_type)}, stack); } + bool IsLikelyHintStack(const TParserCallStack& stack) { + return ContainsRule(RULE(Id_hint), stack); + } + + std::optional StatementKindOf(const TParserCallStack& stack) { + for (TRuleId rule : std::ranges::views::reverse(stack)) { + if (rule == RULE(Select_core)) { + return EStatementKind::Select; + } + if (rule == RULE(Into_table_stmt)) { + return EStatementKind::Insert; + } + } + return std::nullopt; + } + std::unordered_set GetC3PreferredRules() { std::unordered_set preferredRules; preferredRules.insert(std::begin(KeywordRules), std::end(KeywordRules)); diff --git a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h index 94533bddaaeb..987387282311 100644 --- a/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h +++ b/yql/essentials/sql/v1/complete/syntax/parser_call_stack.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace NSQLComplete { @@ -10,6 +11,10 @@ namespace NSQLComplete { bool IsLikelyFunctionStack(const TParserCallStack& stack); + bool IsLikelyHintStack(const TParserCallStack& stack); + + std::optional StatementKindOf(const TParserCallStack& stack); + std::unordered_set GetC3PreferredRules(); } // namespace NSQLComplete diff --git a/yql/essentials/sql/v1/complete/ya.make b/yql/essentials/sql/v1/complete/ya.make index 4db8f92d5aad..57e3ba3bf63e 100644 --- a/yql/essentials/sql/v1/complete/ya.make +++ b/yql/essentials/sql/v1/complete/ya.make @@ -22,6 +22,7 @@ END() RECURSE( antlr4 + core name syntax text From 6853d241e761b0ce1402c2aef65bd102c1c2f822 Mon Sep 17 00:00:00 2001 From: Aleksandr Dmitriev Date: Wed, 9 Apr 2025 18:16:29 +0300 Subject: [PATCH 109/454] optimized SST index for blobs (index and iterator part) (#16992) --- .../hulldb/generic/blobstorage_hullwritesst.h | 2 + .../vdisk/hulldb/generic/hullds_sst.cpp | 4 +- .../vdisk/hulldb/generic/hullds_sst.h | 259 ++++++++++++++---- .../vdisk/hulldb/generic/hullds_sst_it.h | 182 ++++++++++-- .../vdisk/hulldb/generic/hullds_sstvec_it.h | 8 - .../vdisk/hullop/blobstorage_buildslice.h | 8 +- .../vdisk/hullop/blobstorage_hullload.h | 2 +- .../blobstorage/vdisk/query/query_statalgo.h | 10 +- .../vdisk/skeleton/skeleton_shred.cpp | 2 +- .../blobstorage_synclogkeeper_state.cpp | 4 +- 10 files changed, 389 insertions(+), 92 deletions(-) diff --git a/ydb/core/blobstorage/vdisk/hulldb/generic/blobstorage_hullwritesst.h b/ydb/core/blobstorage/vdisk/hulldb/generic/blobstorage_hullwritesst.h index b0f9608fb33f..65e546c4d26d 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/generic/blobstorage_hullwritesst.h +++ b/ydb/core/blobstorage/vdisk/hulldb/generic/blobstorage_hullwritesst.h @@ -412,6 +412,8 @@ namespace NKikimr { static_assert((SuffixSize >> 2 << 2) == SuffixSize, "expect (SuffixSize >> 2 << 2) == SuffixSize"); static_assert(sizeof(TIdxDiskLinker) <= sizeof(TIdxDiskPlaceHolder), "expect sizeof(TIdxDiskLinker) <= sizeof(TIdxDiskPlaceHolder)"); + typedef TRecIndex::TRec TRec; + public: TIndexBuilder(TVDiskContextPtr vctx, EWriterDataType type, ui8 owner, ui64 ownerRound, ui32 chunkSize, ui32 appendBlockSize, ui32 writeBlockSize, ui64 sstId, bool createdByRepl, diff --git a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.cpp b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.cpp index 85583f55488e..470fc79090c2 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.cpp +++ b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.cpp @@ -8,7 +8,7 @@ namespace NKikimr { template void TLevelSegment::OutputHtml(ui32 &index, ui32 level, IOutputStream &str, TIdxDiskPlaceHolder::TInfo &sum) const { HTML(str) { - if (IsLoaded()) { + if (this->IsLoaded()) { TABLER() { TABLED() {SMALL() {str << index;}} TABLED() {SMALL() {str << level;}} @@ -31,7 +31,7 @@ namespace NKikimr { template void TLevelSegment::OutputProto(ui32 level, google::protobuf::RepeatedPtrField *rows) const { - if (IsLoaded()) { + if (this->IsLoaded()) { NKikimrVDisk::LevelStat *row = rows->Add(); row->set_level(level); row->set_first_lsn(Info.FirstLsn); diff --git a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.h b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.h index 6b9717a849d4..baa9153d8fb9 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.h +++ b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst.h @@ -11,11 +11,211 @@ namespace NKikimr { + template + struct TRecIndex : public TThrRefBase { +#pragma pack(push, 4) + struct TRec { + TKey Key; + TMemRec MemRec; + + TRec() = default; + + TRec(const TKey &key) + : Key(key) + , MemRec() + {} + + TRec(const TKey &key, const TMemRec &memRec) + : Key(key) + , MemRec(memRec) + {} + + struct TLess { + bool operator ()(const TRec &x, const TKey &key) const { + return x.Key < key; + } + }; + }; +#pragma pack(pop) + + TTrackableVector LoadedIndex; + + TRecIndex(TVDiskContextPtr vctx) + : LoadedIndex(TMemoryConsumer(vctx->SstIndex)) + {} + + bool IsLoaded() const { + return !LoadedIndex.empty(); + } + + ui64 Elements() const { + Y_DEBUG_ABORT_UNLESS(IsLoaded()); + return LoadedIndex.size(); + } + }; + + template <> + struct TRecIndex : public TThrRefBase { + + // TODO: remove +#pragma pack(push, 4) + struct TRec { + TKeyLogoBlob Key; + TMemRecLogoBlob MemRec; + + TRec() = default; + + TRec(const TKeyLogoBlob &key) + : Key(key) + , MemRec() + {} + + TRec(const TKeyLogoBlob &key, const TMemRecLogoBlob &memRec) + : Key(key) + , MemRec(memRec) + {} + + struct TLess { + bool operator ()(const TRec &x, const TKeyLogoBlob &key) const { + return x.Key < key; + } + }; + }; +#pragma pack(pop) + +#pragma pack(push, 4) + struct TLogoBlobIdHigh { + union { + struct { + ui64 TabletId; // 8 bytes + ui64 StepR1 : 24; // 8 bytes + ui64 Generation : 32; + ui64 Channel : 8; + } N; + + ui64 X[2]; + } Raw; + + explicit TLogoBlobIdHigh(const TLogoBlobID& id) { + Raw.X[0] = id.GetRaw()[0]; + Raw.X[1] = id.GetRaw()[1]; + } + + TLogoBlobIdHigh(ui64 tabletId, ui32 generation, ui32 step, ui8 channel) { + Raw.N.TabletId = tabletId; + Raw.N.Channel = channel; + Raw.N.Generation = generation; + Raw.N.StepR1 = (step & 0xFFFFFF00ull) >> 8; + } + + bool operator == (const TLogoBlobIdHigh& r) const { + return Raw.X[0] == r.Raw.X[0] && Raw.X[1] == r.Raw.X[1]; + } + + bool operator != (const TLogoBlobIdHigh& r) const { + return !(operator == (r)); + } + + bool operator < (const TLogoBlobIdHigh& r) const { + return Raw.X[0] != r.Raw.X[0] ? Raw.X[0] < r.Raw.X[0] : Raw.X[1] < r.Raw.X[1]; + } + }; + + static_assert(sizeof(TLogoBlobIdHigh) == 16, "expect sizeof(TLogoBlobIdHigh) == 16"); + + struct TLogoBlobIdLow { + union { + struct { + ui64 PartId : 4; // 8 bytes + ui64 BlobSize : 26; + ui64 CrcMode : 2; + ui64 Cookie : 24; + ui64 StepR2 : 8; + } N; + + ui64 X; + } Raw; + + explicit TLogoBlobIdLow(const TLogoBlobID& id) { + Raw.X = id.GetRaw()[2]; + } + + TLogoBlobIdLow(ui32 step, ui32 cookie, ui32 crcMode, ui32 blobSize, ui32 partId) { + Raw.N.StepR2 = step & 0x000000FFull; + Raw.N.Cookie = cookie; + Raw.N.CrcMode = crcMode; + Raw.N.BlobSize = blobSize; + Raw.N.PartId = partId; + } + + bool operator == (const TLogoBlobIdLow& r) const { + return Raw.X == r.Raw.X; + } + + bool operator != (const TLogoBlobIdLow& r) const { + return !(operator == (r)); + } + + bool operator < (const TLogoBlobIdLow& r) const { + return Raw.X < r.Raw.X; + } + }; + + static_assert(sizeof(TLogoBlobIdLow) == 8, "expect sizeof(TLogoBlobIdLow) == 8"); + + struct TRecHigh { + TLogoBlobIdHigh Key; + ui32 LowRangeEndIndex; + + struct TLess { + bool operator ()(const TRecHigh& l, const TLogoBlobIdHigh& r) const { + return l.Key < r; + } + }; + }; + + static_assert(sizeof(TRecHigh) == 20, "expect sizeof(TRecHigh) == 20"); + + struct TRecLow { + TLogoBlobIdLow Key; + TMemRecLogoBlob MemRec; + + struct TLess { + bool operator ()(const TRecLow& l, const TLogoBlobIdLow& r) const { + return l.Key < r; + } + }; + }; + + static_assert(sizeof(TRecLow) == 28, "expect sizeof(TRecLow) == 28"); +#pragma pack(pop) + + TTrackableVector IndexHigh; + TTrackableVector IndexLow; + + TTrackableVector LoadedIndex; // TODO: remove + + TRecIndex(TVDiskContextPtr vctx) + : IndexHigh(TMemoryConsumer(vctx->SstIndex)) + , IndexLow(TMemoryConsumer(vctx->SstIndex)) + , LoadedIndex(TMemoryConsumer(vctx->SstIndex)) + {} + + bool IsLoaded() const { + return !LoadedIndex.empty(); + } + + ui64 Elements() const { + Y_DEBUG_ABORT_UNLESS(IsLoaded()); + return LoadedIndex.size(); + } + }; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TLevelSegment //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template - struct TLevelSegment : public TThrRefBase { + struct TLevelSegment : public TRecIndex { typedef TLevelSegment TThis; using TKeyType = TKey; using TMemRecType = TMemRec; @@ -56,34 +256,7 @@ namespace NKikimr { } }; - // records stored in the index -#pragma pack(push, 4) - struct TRec { - TKey Key; - TMemRec MemRec; - - TRec() = default; - - TRec(const TKey &key) - : Key(key) - , MemRec() - {} - - TRec(const TKey &key, const TMemRec &memRec) - : Key(key) - , MemRec(memRec) - {} - - struct TLess { - bool operator () (const TRec &x, const TKey &key) const { - return x.Key < key; - } - }; - }; -#pragma pack(pop) - TDiskPart LastPartAddr; // tail of reverted list of parts (on disk) - TTrackableVector LoadedIndex; // the whole index loaded into memory TTrackableVector LoadedOutbound; TIdxDiskPlaceHolder::TInfo Info; TVector AllChunks; // all chunk ids that store index and data for this segment @@ -95,8 +268,8 @@ namespace NKikimr { ui64 VolatileOrderId = 0; TLevelSegment(TVDiskContextPtr vctx) - : LastPartAddr() - , LoadedIndex(TMemoryConsumer(vctx->SstIndex)) + : TRecIndex(vctx) + , LastPartAddr() , LoadedOutbound(TMemoryConsumer(vctx->SstIndex)) , Info() , AllChunks() @@ -104,8 +277,8 @@ namespace NKikimr { {} TLevelSegment(TVDiskContextPtr vctx, const TDiskPart &addr) - : LastPartAddr(addr) - , LoadedIndex(TMemoryConsumer(vctx->SstIndex)) + : TRecIndex(vctx) + , LastPartAddr(addr) , LoadedOutbound(TMemoryConsumer(vctx->SstIndex)) , Info() , AllChunks() @@ -115,8 +288,8 @@ namespace NKikimr { } TLevelSegment(TVDiskContextPtr vctx, const NKikimrVDiskData::TDiskPart &pb) - : LastPartAddr(pb) - , LoadedIndex(TMemoryConsumer(vctx->SstIndex)) + : TRecIndex(vctx) + , LastPartAddr(pb) , LoadedOutbound(TMemoryConsumer(vctx->SstIndex)) , Info() , AllChunks() @@ -127,10 +300,6 @@ namespace NKikimr { return LastPartAddr; } - bool IsLoaded() const { - return !LoadedIndex.empty(); - } - void SetAddr(const TDiskPart &addr) { LastPartAddr = addr; } @@ -163,7 +332,7 @@ namespace NKikimr { TMemIterator it(this); it.SeekToFirst(); while (it.Valid()) { - const TMemRec& memRec = it->MemRec; + const TMemRec& memRec = it.GetMemRec(); switch (memRec.GetType()) { case TBlobType::HugeBlob: case TBlobType::ManyHugeBlobs: @@ -189,13 +358,9 @@ namespace NKikimr { ui64 GetFirstLsn() const { return Info.FirstLsn; } ui64 GetLastLsn() const { return Info.LastLsn; } - const TKey &FirstKey() const; - const TKey &LastKey() const; - // number of elements in the sst - ui64 Elements() const { - Y_DEBUG_ABORT_UNLESS(IsLoaded()); - return LoadedIndex.size(); - } + TKey FirstKey() const; + TKey LastKey() const; + // append cur seg chunk ids (index and data) to the vector void FillInChunkIds(TVector &vec) const { // copy chunks ids @@ -218,9 +383,7 @@ namespace NKikimr { class TWriter; }; - extern template struct TLevelSegment; extern template struct TLevelSegment; extern template struct TLevelSegment; } // NKikimr - diff --git a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it.h b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it.h index 3f44caf5937b..e251fb5f21a5 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it.h +++ b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sst_it.h @@ -13,18 +13,9 @@ namespace NKikimr { typedef ::NKikimr::TLevelSegment TLevelSegment; typedef typename TLevelSegment::TRec TRec; - typedef ptrdiff_t difference_type; - typedef TRec value_type; - typedef const TRec * pointer; - typedef const TRec & reference; - - typedef std::bidirectional_iterator_tag iterator_category; - - const TLevelSegment *Segment; const TRec *Ptr; - const TRec *Begin() const { return Segment->LoadedIndex.data(); } @@ -82,6 +73,11 @@ namespace NKikimr { return Ptr->Key; } + const TMemRec& GetMemRec() const { + Y_DEBUG_ABORT_UNLESS(Valid()); + return Ptr->MemRec; + } + void SeekToFirst() { Ptr = Begin(); } @@ -96,14 +92,6 @@ namespace NKikimr { Ptr = ::LowerBound(Begin(), End(), key, typename TRec::TLess()); } - const TRec &operator*() const { - return *Ptr; - } - - const TRec *operator->() const { - return Ptr; - } - template void PutToMerger(TRecordMerger *merger) { merger->AddFromSegment(Ptr->MemRec, Segment->GetOutbound(), GetCurKey(), Segment->Info.LastLsn, Segment); @@ -136,21 +124,173 @@ namespace NKikimr { } }; +// TODO: use this iterator +// template <> +// class TLevelSegment::TMemIterator { + namespace NTemp { + + class TMemIterator { + protected: + typedef ::NKikimr::TLevelSegment TLevelSegment; + + const TLevelSegment* Segment = nullptr; + + const TLevelSegment::TRecHigh* High = nullptr; + const TLevelSegment::TRecLow* Low = nullptr; + const TLevelSegment::TRecLow* LowRangeBegin = nullptr; + + public: + TMemIterator(const TLevelSegment* segment) + : Segment(segment) + {} + + TMemIterator() = default; + + TMemIterator(const TMemIterator& i) { + Segment = i.Segment; + High = i.High; + Low = i.Low; + LowRangeBegin = i.LowRangeBegin; + } + + TMemIterator& operator=(const TMemIterator& i) { + Segment = i.Segment; + High = i.High; + Low = i.Low; + LowRangeBegin = i.LowRangeBegin; + return *this; + } + + bool Valid() const { + return Segment && Low && Low >= Segment->IndexLow.begin() && Low < Segment->IndexLow.end(); + } + + void Next() { + Y_DEBUG_ABORT_UNLESS(Valid()); + ++Low; + if (Low == Segment->IndexLow.begin() + High->LowRangeEndIndex) { + ++High; + LowRangeBegin = Low; + } + } + + void Prev() { + Y_DEBUG_ABORT_UNLESS(Segment && Low + && Low > Segment->IndexLow.begin() && Low <= Segment->IndexLow.end()); + + if (Low == LowRangeBegin) { + Y_DEBUG_ABORT_UNLESS(High > Segment->IndexHigh.begin()); + --High; + LowRangeBegin = Segment->IndexLow.begin() + + (High == Segment->IndexHigh.begin() ? 0 : (High - 1)->LowRangeEndIndex); + } + --Low; + } + + TKeyLogoBlob GetCurKey() const { + Y_DEBUG_ABORT_UNLESS(Valid()); + const auto& high = High->Key; + const auto& low = Low->Key; + return TKeyLogoBlob(TLogoBlobID(high.Raw.X[0], high.Raw.X[1], low.Raw.X)); + } + + const TMemRecLogoBlob& GetMemRec() const { + Y_DEBUG_ABORT_UNLESS(Valid()); + return Low->MemRec; + } + + void SeekToFirst() { + High = Segment->IndexHigh.begin(); + Low = LowRangeBegin = Segment->IndexLow.begin(); + } + + void SeekToLast() { + High = Segment->IndexHigh.end(); + Low = LowRangeBegin = Segment->IndexLow.end(); + Prev(); + } + + void Seek(const TKeyLogoBlob& key) { + TLevelSegment::TLogoBlobIdHigh keyHigh(key.LogoBlobID()); + TLevelSegment::TLogoBlobIdLow keyLow(key.LogoBlobID()); + + High = std::lower_bound(Segment->IndexHigh.begin(), Segment->IndexHigh.end(), + keyHigh, TLevelSegment::TRecHigh::TLess()); + + if (High == Segment->IndexHigh.end()) { + Low = LowRangeBegin = Segment->IndexLow.end(); + return; + } + + auto rangeBegin = Segment->IndexLow.begin() + + (High == Segment->IndexHigh.begin() ? 0 : (High - 1)->LowRangeEndIndex); + + if (High->Key != keyHigh) { + Low = LowRangeBegin = rangeBegin; + return; + } + + auto rangeEnd = Segment->IndexLow.begin() + High->LowRangeEndIndex; + + Low = std::lower_bound(rangeBegin, rangeEnd, keyLow, TLevelSegment::TRecLow::TLess()); + + if (Low == rangeEnd) { + LowRangeBegin = rangeEnd; + ++High; + } else { + LowRangeBegin = rangeBegin; + } + } + + template + void PutToMerger(TRecordMerger* merger) { + merger->AddFromSegment(GetMemRec(), Segment->GetOutbound(), GetCurKey(), Segment->Info.LastLsn, Segment); + } + + template + void PutToHeap(Heap& heap) { + heap.Add(this); + } + + bool operator == (const TMemIterator& it) const { + Y_ABORT_UNLESS(Segment == it.Segment); + return High == it.High && Low == it.Low; + } + + bool operator != (const TMemIterator& it) const { + return !(operator == (it)); + } + + TDiskDataExtractor* GetDiskData(TDiskDataExtractor* extr) const { + return GetMemRec().GetDiskData(extr, Segment->GetOutbound()); + } + + const TLevelSegment* GetSstPtr() const { + return Segment; + } + + const TDiskPart* GetOutbound() const { + return Segment->GetOutbound(); + } + }; + + } // namespace NTemp + //////////////////////////////////////////////////////////////////////////// // TLevelSegment methods //////////////////////////////////////////////////////////////////////////// template - const TKey &TLevelSegment::FirstKey() const { + TKey TLevelSegment::FirstKey() const { TMemIterator it(this); it.SeekToFirst(); - return it->Key; + return it.GetCurKey(); } template - const TKey &TLevelSegment::LastKey() const { + TKey TLevelSegment::LastKey() const { TMemIterator it(this); it.SeekToLast(); - return it->Key; + return it.GetCurKey(); } } // NKikimr diff --git a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sstvec_it.h b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sstvec_it.h index cedeb449bb9c..cd251558019d 100644 --- a/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sstvec_it.h +++ b/ydb/core/blobstorage/vdisk/hulldb/generic/hullds_sstvec_it.h @@ -127,14 +127,6 @@ namespace NKikimr { return CurSegIt.GetSstPtr(); } - const TRec &operator*() const { - return CurSegIt.operator*(); - } - - const TRec *operator->() const { - return CurSegIt.operator->(); - } - bool operator ==(const TReadIterator &it) const { return CrossSegIt == it.CrossSegIt && CurSegIt == it.CurSegIt; } diff --git a/ydb/core/blobstorage/vdisk/hullop/blobstorage_buildslice.h b/ydb/core/blobstorage/vdisk/hullop/blobstorage_buildslice.h index 64538923a514..f1fbc9bdb86c 100644 --- a/ydb/core/blobstorage/vdisk/hullop/blobstorage_buildslice.h +++ b/ydb/core/blobstorage/vdisk/hullop/blobstorage_buildslice.h @@ -276,10 +276,10 @@ namespace NKikimr { TMemIterator c(p.SstPtr.Get()); c.SeekToFirst(); while (c.Valid()) { - TBlobType::EType type = c->MemRec.GetType(); + TBlobType::EType type = c.GetMemRec().GetType(); if (type == TBlobType::HugeBlob || type == TBlobType::ManyHugeBlobs) { TDiskDataExtractor extr; - c->MemRec.GetDiskData(&extr, p.SstPtr->GetOutbound()); + c.GetMemRec().GetDiskData(&extr, p.SstPtr->GetOutbound()); for (const TDiskPart *hb = extr.Begin; hb != extr.End; ++hb) { func(*hb); } @@ -338,10 +338,10 @@ namespace NKikimr { TMemIterator c(seg.Get()); c.SeekToFirst(); while (c.Valid()) { - TBlobType::EType type = c->MemRec.GetType(); + TBlobType::EType type = c.GetMemRec().GetType(); if (type == TBlobType::HugeBlob || type == TBlobType::ManyHugeBlobs) { TDiskDataExtractor extr; - c->MemRec.GetDiskData(&extr, seg->GetOutbound()); + c.GetMemRec().GetDiskData(&extr, seg->GetOutbound()); for (const TDiskPart *hb = extr.Begin; hb != extr.End; ++hb) { func(*hb); } diff --git a/ydb/core/blobstorage/vdisk/hullop/blobstorage_hullload.h b/ydb/core/blobstorage/vdisk/hullop/blobstorage_hullload.h index 998806c7ae80..fa0481e7111c 100644 --- a/ydb/core/blobstorage/vdisk/hullop/blobstorage_hullload.h +++ b/ydb/core/blobstorage/vdisk/hullop/blobstorage_hullload.h @@ -21,7 +21,7 @@ namespace NKikimr { struct TSmallBlobChunkIdxExtractor { template TMaybe ExtractChunkIdx(TIterator& it) { - if (it->MemRec.GetType() == TBlobType::DiskBlob) { + if (it.GetMemRec().GetType() == TBlobType::DiskBlob) { TDiskDataExtractor extr; it.GetDiskData(&extr); const TDiskPart& part = extr.SwearOne(); diff --git a/ydb/core/blobstorage/vdisk/query/query_statalgo.h b/ydb/core/blobstorage/vdisk/query/query_statalgo.h index a08b5fa1b06f..861080a02a95 100644 --- a/ydb/core/blobstorage/vdisk/query/query_statalgo.h +++ b/ydb/core/blobstorage/vdisk/query/query_statalgo.h @@ -50,7 +50,7 @@ namespace NKikimr { TMemIterator c(p.SstPtr.Get()); c.SeekToFirst(); while (c.Valid()) { - aggr->UpdateLevel(p, c->Key, c->MemRec); + aggr->UpdateLevel(p, c.GetCurKey(), c.GetMemRec()); c.Next(); } it.Next(); @@ -204,14 +204,14 @@ namespace NKikimr { return; } const auto& c = *MemIt; - if (!Constraint || Constraint->Check(c->Key)) { - auto mr = c->MemRec.ToString(HullCtx->IngressCache.Get(), c.GetSstPtr()->GetOutbound()); + if (!Constraint || Constraint->Check(c.GetCurKey())) { + auto mr = c.GetMemRec().ToString(HullCtx->IngressCache.Get(), c.GetSstPtr()->GetOutbound()); auto ing = IngressToString(HullCtx->VCtx->Top.get(), HullCtx->VCtx->ShortSelfVDisk, - c->Key, c->MemRec); + c.GetCurKey(), c.GetMemRec()); str << Prefix << "L: " << p.Level << " ID: " << p.SstPtr->AssignedSstId - << " Key: " << c->Key.ToString() + << " Key: " << c.GetCurKey().ToString() << " Ingress: " << ing << " MemRec: " << mr << "\n"; diff --git a/ydb/core/blobstorage/vdisk/skeleton/skeleton_shred.cpp b/ydb/core/blobstorage/vdisk/skeleton/skeleton_shred.cpp index b31e603799c9..62b94ba3df99 100644 --- a/ydb/core/blobstorage/vdisk/skeleton/skeleton_shred.cpp +++ b/ydb/core/blobstorage/vdisk/skeleton/skeleton_shred.cpp @@ -166,7 +166,7 @@ namespace NKikimr { const TDiskPart *outbound = seg.GetOutbound(); typename TLevelSegment::TMemIterator memIt(&seg); for (memIt.SeekToFirst(); memIt.Valid(); memIt.Next()) { - scanHuge(memIt->MemRec, outbound); + scanHuge(memIt.GetMemRec(), outbound); } } } diff --git a/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogkeeper_state.cpp b/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogkeeper_state.cpp index b4892f8355e9..df1c7ea8bbc4 100644 --- a/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogkeeper_state.cpp +++ b/ydb/core/blobstorage/vdisk/synclog/blobstorage_synclogkeeper_state.cpp @@ -87,8 +87,8 @@ namespace NKikimr { ui32 len = TSerializeRoutines::SetLogoBlob(VCtx->Top->GType, buffer, lsn, - it->Key.LogoBlobID(), - it->MemRec.GetIngress()); + it.GetCurKey().LogoBlobID(), + it.GetMemRec().GetIngress()); Y_DEBUG_ABORT_UNLESS(len <= sizeof(buffer)); SyncLogPtr->PutOne(reinterpret_cast(buffer), len); it.Next(); From 96b68b2a6ae5da120654548529011b368d711fa8 Mon Sep 17 00:00:00 2001 From: robot-piglet Date: Wed, 9 Apr 2025 18:57:10 +0300 Subject: [PATCH 110/454] Intermediate changes commit_hash:f430adf87d23165dab8f8ee82ab299ced5de4b59 --- .../protobuf/test/canondata/result.json | 20 +- .../test.test_YQL-19040_/results.txt | 325 ++++++++++++++++++ .../test.test_recursion_ignore_/results.txt | 119 +++++++ .../test.test_yt_mode_no_ser_/results.txt | 95 +++++ .../test.test_yt_mode_plain_/results.txt | 210 +++++++++++ .../test.test_yt_mode_ser_pb_/results.txt | 95 +++++ .../test.test_yt_mode_ser_yt_/results.txt | 105 ++++++ .../common/protobuf/test/cases/YQL-19040.sql | 2 +- .../protobuf/test/cases/recursion_ignore.sql | 2 +- .../protobuf/test/cases/yt_mode_no_ser.sql | 2 +- .../protobuf/test/cases/yt_mode_plain.sql | 6 + .../protobuf/test/cases/yt_mode_ser_pb.sql | 2 +- .../protobuf/test/cases/yt_mode_ser_yt.sql | 2 +- 13 files changed, 965 insertions(+), 20 deletions(-) create mode 100644 yql/essentials/udfs/common/protobuf/test/canondata/test.test_recursion_ignore_/results.txt create mode 100644 yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_no_ser_/results.txt create mode 100644 yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_plain_/results.txt create mode 100644 yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_ser_pb_/results.txt create mode 100644 yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_ser_yt_/results.txt diff --git a/yql/essentials/udfs/common/protobuf/test/canondata/result.json b/yql/essentials/udfs/common/protobuf/test/canondata/result.json index be8251f2ae00..84b3ed5d76a6 100644 --- a/yql/essentials/udfs/common/protobuf/test/canondata/result.json +++ b/yql/essentials/udfs/common/protobuf/test/canondata/result.json @@ -53,9 +53,7 @@ ], "test.test[recursion_ignore]": [ { - "checksum": "eeb1ca24bdc09529bd0a320965b3123d", - "size": 1241, - "uri": "https://storage.yandex-team.ru/get-devtools/1937492/9579ab43fa70f08e465aa7673b27a5da5460a75e/resource.tar.gz#test.test_recursion_ignore_/results.txt" + "uri": "file://test.test_recursion_ignore_/results.txt" } ], "test.test[syntax_aware_empty_nested_message]": [ @@ -95,30 +93,22 @@ ], "test.test[yt_mode_no_ser]": [ { - "checksum": "eeb1ca24bdc09529bd0a320965b3123d", - "size": 1241, - "uri": "https://storage.yandex-team.ru/get-devtools/1937492/9579ab43fa70f08e465aa7673b27a5da5460a75e/resource.tar.gz#test.test_yt_mode_no_ser_/results.txt" + "uri": "file://test.test_yt_mode_no_ser_/results.txt" } ], "test.test[yt_mode_plain]": [ { - "checksum": "7321635f17c1f8fdb75d96bb2a3ce4d1", - "size": 1796, - "uri": "https://storage.yandex-team.ru/get-devtools/1937492/9579ab43fa70f08e465aa7673b27a5da5460a75e/resource.tar.gz#test.test_yt_mode_plain_/results.txt" + "uri": "file://test.test_yt_mode_plain_/results.txt" } ], "test.test[yt_mode_ser_pb]": [ { - "checksum": "eeb1ca24bdc09529bd0a320965b3123d", - "size": 1241, - "uri": "https://storage.yandex-team.ru/get-devtools/1937492/9579ab43fa70f08e465aa7673b27a5da5460a75e/resource.tar.gz#test.test_yt_mode_ser_pb_/results.txt" + "uri": "file://test.test_yt_mode_ser_pb_/results.txt" } ], "test.test[yt_mode_ser_yt]": [ { - "checksum": "eeb1ca24bdc09529bd0a320965b3123d", - "size": 1241, - "uri": "https://storage.yandex-team.ru/get-devtools/1937492/9579ab43fa70f08e465aa7673b27a5da5460a75e/resource.tar.gz#test.test_yt_mode_ser_yt_/results.txt" + "uri": "file://test.test_yt_mode_ser_yt_/results.txt" } ], "test.test[yt_mode_variant]": [ diff --git a/yql/essentials/udfs/common/protobuf/test/canondata/test.test_YQL-19040_/results.txt b/yql/essentials/udfs/common/protobuf/test/canondata/test.test_YQL-19040_/results.txt index 67f6ba046e3f..b42aff88de35 100644 --- a/yql/essentials/udfs/common/protobuf/test/canondata/test.test_YQL-19040_/results.txt +++ b/yql/essentials/udfs/common/protobuf/test/canondata/test.test_YQL-19040_/results.txt @@ -9,6 +9,240 @@ [ [ "column0"; + [ + "StructType"; + [ + [ + "dict1"; + [ + "DictType"; + [ + "DataType"; + "String" + ]; + [ + "StructType"; + [ + [ + "a"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ] + ] + ]; + [ + "dict2"; + [ + "OptionalType"; + [ + "DictType"; + [ + "DataType"; + "String" + ]; + [ + "StructType"; + [ + [ + "a"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ] + ] + ] + ]; + [ + "dict3"; + [ + "ListType"; + [ + "StructType"; + [ + [ + "key"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "value"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ] + ] + ]; + [ + "dict4"; + [ + "ListType"; + [ + "StructType"; + [ + [ + "key"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "value"; + [ + "OptionalType"; + [ + "StructType"; + [ + [ + "a"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ]; + [ + "dict5"; + [ + "DictType"; + [ + "DataType"; + "String" + ]; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "dict6"; + [ + "OptionalType"; + [ + "DictType"; + [ + "DataType"; + "String" + ]; + [ + "DataType"; + "String" + ] + ] + ] + ]; + [ + "dict7"; + [ + "ListType"; + [ + "StructType"; + [ + [ + "key"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "value"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ] + ] + ]; + [ + "dict8"; + [ + "ListType"; + [ + "StructType"; + [ + [ + "key"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "value"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ] + ] + ] + ] + ] + ]; + [ + "column1"; + [ + "DataType"; + "String" + ] + ]; + [ + "column2"; [ "DataType"; "String" @@ -19,6 +253,97 @@ ]; "Data" = [ [ + [ + [ + [ + "k2"; + [ + [ + "0" + ] + ] + ]; + [ + "k1"; + [ + [ + "1" + ] + ] + ] + ]; + [ + [ + [ + "k2"; + [ + [ + "2" + ] + ] + ] + ] + ]; + [ + [ + [ + "k3" + ]; + [ + "\n\0013" + ] + ] + ]; + [ + [ + [ + "k4" + ]; + [ + [ + [ + "4" + ] + ] + ] + ] + ]; + [ + [ + "k5"; + "v5" + ] + ]; + [ + [ + [ + "k6"; + "v6" + ] + ] + ]; + [ + [ + [ + "k7" + ]; + [ + "v7" + ] + ] + ]; + [ + [ + [ + "k8" + ]; + [ + "v8" + ] + ] + ] + ]; + "\n\t\n\2k1\x12\3\n\0011\n\t\n\2k2\x12\3\n\0010\x12\t\n\2k2\x12\3\n\0012\x1A\t\n\2k3\x12\3\n\0013\"\t\n\2k4\x12\3\n\0014*\x08\n\2k5\x12\2v52\x08\n\2k6\x12\2v6:\x08\n\2k7\x12\2v7B\x08\n\2k8\x12\2v8"; "Success" ] ] diff --git a/yql/essentials/udfs/common/protobuf/test/canondata/test.test_recursion_ignore_/results.txt b/yql/essentials/udfs/common/protobuf/test/canondata/test.test_recursion_ignore_/results.txt new file mode 100644 index 000000000000..a1805b102315 --- /dev/null +++ b/yql/essentials/udfs/common/protobuf/test/canondata/test.test_recursion_ignore_/results.txt @@ -0,0 +1,119 @@ +[ + { + "Write" = [ + { + "Type" = [ + "ListType"; + [ + "StructType"; + [ + [ + "TestField"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "column1"; + [ + "OptionalType"; + [ + "StructType"; + [ + [ + "inner"; + [ + "OptionalType"; + [ + "StructType"; + [ + [ + "i"; + [ + "OptionalType"; + [ + "StructType"; + [ + [ + "a"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ]; + [ + "test"; + [ + "VoidType" + ] + ] + ] + ] + ] + ]; + [ + "column2"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "column3"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ]; + "Data" = [ + [ + [ + "{\"inner\":{\"i\":{\"a\":\"hello\"}},\"test\":{\"inner\":{\"i\":{\"a\":\"bye\"}}}}" + ]; + [ + [ + [ + [ + [ + [ + [ + "hello" + ] + ] + ] + ] + ]; + "Void" + ] + ]; + [ + "{\n \"inner\":\n {\n \"i\":\n {\n \"a\":\"hello\"\n }\n }\n}" + ]; + "Success" + ] + ] + } + ] + } +] \ No newline at end of file diff --git a/yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_no_ser_/results.txt b/yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_no_ser_/results.txt new file mode 100644 index 000000000000..9f4e9169eb3b --- /dev/null +++ b/yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_no_ser_/results.txt @@ -0,0 +1,95 @@ +[ + { + "Write" = [ + { + "Type" = [ + "ListType"; + [ + "StructType"; + [ + [ + "TestField"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "column1"; + [ + "OptionalType"; + [ + "StructType"; + [ + [ + "inner"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "test"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ] + ] + ]; + [ + "column2"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "column3"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ]; + "Data" = [ + [ + [ + "{\"inner\":{\"i\":{\"a\":\"hello\"}},\"test\":{\"inner\":{\"i\":{\"a\":\"bye\"}}}}" + ]; + [ + [ + [ + "\n\7\n\5hello" + ]; + [ + "\n\7\n\5\n\3bye" + ] + ] + ]; + [ + "{\n \"test\":\n {\n \"inner\":\n {\n \"i\":\n {\n \"a\":\"bye\"\n }\n }\n },\n \"inner\":\n {\n \"i\":\n {\n \"a\":\"hello\"\n }\n }\n}" + ]; + "Success" + ] + ] + } + ] + } +] \ No newline at end of file diff --git a/yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_plain_/results.txt b/yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_plain_/results.txt new file mode 100644 index 000000000000..626c7404b75c --- /dev/null +++ b/yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_plain_/results.txt @@ -0,0 +1,210 @@ +[ + { + "Write" = [ + { + "Type" = [ + "ListType"; + [ + "StructType"; + [ + [ + "TestField"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "column1"; + [ + "OptionalType"; + [ + "StructType"; + [ + [ + "inner"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ] + ] + ]; + [ + "column2"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "column3"; + [ + "OptionalType"; + [ + "StructType"; + [ + [ + "inner"; + [ + "OptionalType"; + [ + "StructType"; + [ + [ + "i"; + [ + "OptionalType"; + [ + "StructType"; + [ + [ + "a"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ] + ]; + [ + "column4"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "column5"; + [ + "OptionalType"; + [ + "StructType"; + [ + [ + "inner"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ] + ] + ]; + [ + "column6"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "column7"; + [ + "DataType"; + "String" + ] + ]; + [ + "column8"; + [ + "DataType"; + "String" + ] + ]; + [ + "column9"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ]; + "Data" = [ + [ + [ + "{\"inner\":{\"i\":{\"a\":\"hello\"}}}" + ]; + [ + [ + [ + "\n\7\n\5hello" + ] + ] + ]; + [ + "{\n \"inner\":\n {\n \"i\":\n {\n \"a\":\"hello\"\n }\n }\n}" + ]; + [ + [ + [ + [ + [ + [ + [ + "hello" + ] + ] + ] + ] + ] + ] + ]; + [ + "{\n \"inner\":\n {\n \"i\":\n {\n \"a\":\"hello\"\n }\n }\n}" + ]; + [ + [ + [ + "\n\7\n\5hello" + ] + ] + ]; + [ + "{\n \"inner\":\n {\n \"i\":\n {\n \"a\":\"hello\"\n }\n }\n}" + ]; + "Success"; + "Success"; + "Success" + ] + ] + } + ] + } +] \ No newline at end of file diff --git a/yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_ser_pb_/results.txt b/yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_ser_pb_/results.txt new file mode 100644 index 000000000000..9f4e9169eb3b --- /dev/null +++ b/yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_ser_pb_/results.txt @@ -0,0 +1,95 @@ +[ + { + "Write" = [ + { + "Type" = [ + "ListType"; + [ + "StructType"; + [ + [ + "TestField"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "column1"; + [ + "OptionalType"; + [ + "StructType"; + [ + [ + "inner"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "test"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ] + ] + ]; + [ + "column2"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "column3"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ]; + "Data" = [ + [ + [ + "{\"inner\":{\"i\":{\"a\":\"hello\"}},\"test\":{\"inner\":{\"i\":{\"a\":\"bye\"}}}}" + ]; + [ + [ + [ + "\n\7\n\5hello" + ]; + [ + "\n\7\n\5\n\3bye" + ] + ] + ]; + [ + "{\n \"test\":\n {\n \"inner\":\n {\n \"i\":\n {\n \"a\":\"bye\"\n }\n }\n },\n \"inner\":\n {\n \"i\":\n {\n \"a\":\"hello\"\n }\n }\n}" + ]; + "Success" + ] + ] + } + ] + } +] \ No newline at end of file diff --git a/yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_ser_yt_/results.txt b/yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_ser_yt_/results.txt new file mode 100644 index 000000000000..3e5c425b434c --- /dev/null +++ b/yql/essentials/udfs/common/protobuf/test/canondata/test.test_yt_mode_ser_yt_/results.txt @@ -0,0 +1,105 @@ +[ + { + "Write" = [ + { + "Type" = [ + "ListType"; + [ + "StructType"; + [ + [ + "TestField"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "column1"; + [ + "OptionalType"; + [ + "StructType"; + [ + [ + "inner"; + [ + "OptionalType"; + [ + "StructType"; + [ + [ + "i"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ] + ] + ]; + [ + "test"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ] + ]; + [ + "column2"; + [ + "OptionalType"; + [ + "DataType"; + "String" + ] + ] + ]; + [ + "column3"; + [ + "DataType"; + "String" + ] + ] + ] + ] + ]; + "Data" = [ + [ + [ + "{\"inner\":{\"i\":{\"a\":\"hello\"}},\"test\":{\"inner\":{\"i\":{\"a\":\"bye\"}}}}" + ]; + [ + [ + [ + [ + [ + "\n\5hello" + ] + ] + ]; + "\n\7\n\5\n\3bye" + ] + ]; + [ + "{\n \"test\":\n {\n \"inner\":\n {\n \"i\":\n {\n \"a\":\"bye\"\n }\n }\n },\n \"inner\":\n {\n \"i\":\n {\n \"a\":\"hello\"\n }\n }\n}" + ]; + "Success" + ] + ] + } + ] + } +] \ No newline at end of file diff --git a/yql/essentials/udfs/common/protobuf/test/cases/YQL-19040.sql b/yql/essentials/udfs/common/protobuf/test/cases/YQL-19040.sql index 895929c06c98..1b51ce590fab 100644 --- a/yql/essentials/udfs/common/protobuf/test/cases/YQL-19040.sql +++ b/yql/essentials/udfs/common/protobuf/test/cases/YQL-19040.sql @@ -59,4 +59,4 @@ $udfParseJson = Udf(Protobuf::Parse, $config_json as TypeConfig); $udfParseBin = Udf(Protobuf::Parse, $config_bin as TypeConfig); $udfSerializeBin = Udf(Protobuf::Serialize, $config_bin as TypeConfig); -SELECT Ensure("Success", $udfParseJson($dat) == $udfParseBin($udfSerializeBin($udfParseJson($dat))), "Fail"); \ No newline at end of file +SELECT $udfParseJson($dat), $udfSerializeBin($udfParseJson($dat)), Ensure("Success", $udfParseJson($dat) == $udfParseBin($udfSerializeBin($udfParseJson($dat))), "Fail"); \ No newline at end of file diff --git a/yql/essentials/udfs/common/protobuf/test/cases/recursion_ignore.sql b/yql/essentials/udfs/common/protobuf/test/cases/recursion_ignore.sql index 2f57eb18d190..6849518bb004 100644 --- a/yql/essentials/udfs/common/protobuf/test/cases/recursion_ignore.sql +++ b/yql/essentials/udfs/common/protobuf/test/cases/recursion_ignore.sql @@ -30,6 +30,6 @@ $config = @@{ $udfPar = Udf(Protobuf::Parse, $config as TypeConfig); $udfSer = Udf(Protobuf::Serialize, $config as TypeConfig); -SELECT TestField, Ensure("Success", $udfPar(TestField) == $udfPar($udfSer($udfPar(TestField))), "Fail") +SELECT TestField, $udfPar(TestField), $udfSer($udfPar(TestField)), Ensure("Success", $udfPar(TestField) == $udfPar($udfSer($udfPar(TestField))), "Fail") FROM plato.Input; diff --git a/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_no_ser.sql b/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_no_ser.sql index d75aa4af2fe2..c582ddd2f717 100644 --- a/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_no_ser.sql +++ b/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_no_ser.sql @@ -31,6 +31,6 @@ $config = @@{ $udfPar = Udf(Protobuf::Parse, $config as TypeConfig); $udfSer = Udf(Protobuf::Serialize, $config as TypeConfig); -SELECT TestField, Ensure("Success", $udfPar(TestField) == $udfPar($udfSer($udfPar(TestField))), "Fail") +SELECT TestField, $udfPar(TestField), $udfSer($udfPar(TestField)), Ensure("Success", $udfPar(TestField) == $udfPar($udfSer($udfPar(TestField))), "Fail") FROM plato.Input; diff --git a/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_plain.sql b/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_plain.sql index 87e9fc6bd26c..9f0aeaf2c0ff 100644 --- a/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_plain.sql +++ b/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_plain.sql @@ -106,6 +106,12 @@ $udfParPB = Udf(Protobuf::Parse, $configPB as TypeConfig); $udfSerPB = Udf(Protobuf::Serialize, $configPB as TypeConfig); SELECT TestField, + $udfParNO(TestField), + $udfSerNO($udfParNO(TestField)), + $udfParYT(TestField), + $udfSerYT($udfParYT(TestField)), + $udfParPB(TestField), + $udfSerPB($udfParPB(TestField)), Ensure("Success", $udfParNO(TestField) == $udfParNO($udfSerNO($udfParNO(TestField))), "Fail"), Ensure("Success", $udfParYT(TestField) == $udfParYT($udfSerYT($udfParYT(TestField))), "Fail"), Ensure("Success", $udfParPB(TestField) == $udfParPB($udfSerPB($udfParPB(TestField))), "Fail") diff --git a/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_ser_pb.sql b/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_ser_pb.sql index 35945ffe7a23..d8f903d74a53 100644 --- a/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_ser_pb.sql +++ b/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_ser_pb.sql @@ -35,6 +35,6 @@ $config = @@{ $udfPar = Udf(Protobuf::Parse, $config as TypeConfig); $udfSer = Udf(Protobuf::Serialize, $config as TypeConfig); -SELECT TestField, Ensure("Success", $udfPar(TestField) == $udfPar($udfSer($udfPar(TestField))), "Fail") +SELECT TestField, $udfPar(TestField), $udfSer($udfPar(TestField)), Ensure("Success", $udfPar(TestField) == $udfPar($udfSer($udfPar(TestField))), "Fail") FROM plato.Input; diff --git a/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_ser_yt.sql b/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_ser_yt.sql index 42312716e688..17e97cb9a182 100644 --- a/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_ser_yt.sql +++ b/yql/essentials/udfs/common/protobuf/test/cases/yt_mode_ser_yt.sql @@ -34,6 +34,6 @@ $config = @@{ $udfPar = Udf(Protobuf::Parse, $config as TypeConfig); $udfSer = Udf(Protobuf::Serialize, $config as TypeConfig); -SELECT TestField, Ensure("Success", $udfPar(TestField) == $udfPar($udfSer($udfPar(TestField))), "Fail") +SELECT TestField, $udfPar(TestField), $udfSer($udfPar(TestField)), Ensure("Success", $udfPar(TestField) == $udfPar($udfSer($udfPar(TestField))), "Fail") FROM plato.Input; From 8c5eda29f2998c4e228438bb64211132a1e72550 Mon Sep 17 00:00:00 2001 From: robot-infraui-ci Date: Wed, 9 Apr 2025 18:57:16 +0300 Subject: [PATCH 111/454] Update docs cli to "4.57.11" version commit_hash:76ec541017934c2859c39816e1272c945ef7b115 --- build/platform/yfm/resources.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/platform/yfm/resources.json b/build/platform/yfm/resources.json index f68293f7a728..c15491ce634a 100644 --- a/build/platform/yfm/resources.json +++ b/build/platform/yfm/resources.json @@ -1,16 +1,16 @@ { "by_platform": { "win32-x86_64": { - "uri": "sbr:8437304145" + "uri": "sbr:8476056065" }, "darwin-x86_64": { - "uri": "sbr:8437300792" + "uri": "sbr:8476054671" }, "linux-x86_64": { - "uri": "sbr:8437297413" + "uri": "sbr:8476053254" }, "darwin-arm64": { - "uri": "sbr:8437300792" + "uri": "sbr:8476054671" } } } From 559f37669e6f400b117d624852cd36ddefb1f733 Mon Sep 17 00:00:00 2001 From: Alexander Alexeev Date: Wed, 9 Apr 2025 19:37:39 +0200 Subject: [PATCH 112/454] Add SharedMetadata actor to test_client --- ydb/core/testlib/basics/feature_flags.h | 1 + ydb/core/testlib/test_client.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/ydb/core/testlib/basics/feature_flags.h b/ydb/core/testlib/basics/feature_flags.h index 9992dde56355..22f1f11b4f24 100644 --- a/ydb/core/testlib/basics/feature_flags.h +++ b/ydb/core/testlib/basics/feature_flags.h @@ -77,6 +77,7 @@ class TTestFeatureFlagsHolder { FEATURE_FLAG_SETTER(EnableDatabaseAdmin) FEATURE_FLAG_SETTER(EnablePermissionsExport) FEATURE_FLAG_SETTER(EnableShowCreate) + FEATURE_FLAG_SETTER(EnableSharedMetadataCache) #undef FEATURE_FLAG_SETTER }; diff --git a/ydb/core/testlib/test_client.cpp b/ydb/core/testlib/test_client.cpp index 610c8a52ebb5..a27dfed49565 100644 --- a/ydb/core/testlib/test_client.cpp +++ b/ydb/core/testlib/test_client.cpp @@ -77,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -1149,6 +1150,16 @@ namespace Tests { const auto aid = Runtime->Register(actor, nodeIdx, appData.UserPoolId, TMailboxType::Revolving, 0); Runtime->RegisterService(NConveyor::TInsertServiceOperator::MakeServiceId(Runtime->GetNodeId(nodeIdx)), aid, nodeIdx); } + { + if (Settings.FeatureFlags.GetEnableSharedMetadataCache()) { + auto* actor = NKikimr::NOlap::NDataAccessorControl::TNodeActor::CreateActor(); + + const auto aid = Runtime->Register(actor, nodeIdx, appData.UserPoolId, TMailboxType::HTSwap, 0); + const auto serviceId = NKikimr::NOlap::NDataAccessorControl::TNodeActor::MakeActorId(Runtime->GetNodeId(nodeIdx)); + Runtime->RegisterService(serviceId, aid, nodeIdx); + } + } + Runtime->Register(CreateLabelsMaintainer({}), nodeIdx, appData.SystemPoolId, TMailboxType::Revolving, 0); auto sysViewService = NSysView::CreateSysViewServiceForTests(); From 63fc2dfd9168ad64deaadc38503deb931bae77f5 Mon Sep 17 00:00:00 2001 From: imunkin Date: Wed, 9 Apr 2025 20:04:58 +0300 Subject: [PATCH 113/454] Drop the flag to control type annotation for ReplicateScalars commit_hash:6237b71d18123f35a02503d115b90075efc76121 --- yql/essentials/core/yql_expr_type_annotation.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/yql/essentials/core/yql_expr_type_annotation.h b/yql/essentials/core/yql_expr_type_annotation.h index d23ce163e3cf..9bad092f76c6 100644 --- a/yql/essentials/core/yql_expr_type_annotation.h +++ b/yql/essentials/core/yql_expr_type_annotation.h @@ -355,8 +355,4 @@ TStringBuf NormalizeCallableName(TStringBuf name); void CheckExpectedTypeAndColumnOrder(const TExprNode& node, TExprContext& ctx, TTypeAnnotationContext& typesCtx); -namespace NBlockStreamIO { - constexpr bool ReplicateScalars = true; -} // namespace NBlockStreamIO - } From 8ea2310750aafd8bed4ba64021e25b089304d4ed Mon Sep 17 00:00:00 2001 From: mikailbag Date: Wed, 9 Apr 2025 20:23:00 +0300 Subject: [PATCH 114/454] Update TCMalloc commit_hash:87d74347445d4b849db4248cfd5b83ff3a0a54b9 --- contrib/libs/tcmalloc/.yandex_meta/build.ym | 62 + .../.yandex_meta/devtools.copyrights.report | 382 +- .../.yandex_meta/devtools.licenses.report | 393 +- .../tcmalloc/.yandex_meta/licenses.list.txt | 241 +- contrib/libs/tcmalloc/README.md | 35 +- contrib/libs/tcmalloc/common.inc | 28 +- contrib/libs/tcmalloc/default/ya.make | 6 +- contrib/libs/tcmalloc/no_percpu_cache/ya.make | 5 +- contrib/libs/tcmalloc/numa_256k/ya.make | 2 +- .../libs/tcmalloc/numa_large_pages/ya.make | 2 +- contrib/libs/tcmalloc/patches/010-fork.patch | 400 ++ .../libs/tcmalloc/patches/020-user-data.patch | 269 + ...ler.patch => 030-soft-limit-handler.patch} | 30 +- .../040-remove-conflicting-noexcept.patch | 13 + .../tcmalloc/patches/050-avoid-cycle.patch | 13 + .../tcmalloc/patches/060-system-headers.sh | 5 + .../900-undeprecate-rate-interval.patch | 24 + contrib/libs/tcmalloc/patches/fork.patch | 310 - contrib/libs/tcmalloc/patches/userdata.patch | 220 - contrib/libs/tcmalloc/patches/yandex.patch | 91 - contrib/libs/tcmalloc/small_but_slow/ya.make | 1 + .../libs/tcmalloc/tcmalloc/.github/CODEOWNERS | 5 + .../tcmalloc/.github/workflows/ci.yml | 63 + contrib/libs/tcmalloc/tcmalloc/BUILD | 1401 ++-- .../tcmalloc/tcmalloc/allocation_sample.cc | 59 + .../tcmalloc/tcmalloc/allocation_sample.h | 93 + .../tcmalloc/allocation_sample_test.cc | 132 + .../tcmalloc/tcmalloc/allocation_sampling.cc | 270 + .../tcmalloc/tcmalloc/allocation_sampling.h | 259 + contrib/libs/tcmalloc/tcmalloc/arena.cc | 65 +- contrib/libs/tcmalloc/tcmalloc/arena.h | 88 +- contrib/libs/tcmalloc/tcmalloc/arena_test.cc | 100 +- contrib/libs/tcmalloc/tcmalloc/background.cc | 259 +- .../tcmalloc/tcmalloc/central_freelist.cc | 306 +- .../libs/tcmalloc/tcmalloc/central_freelist.h | 647 +- .../tcmalloc/central_freelist_benchmark.cc | 38 +- .../tcmalloc/central_freelist_fuzz.cc | 161 + .../tcmalloc/central_freelist_test.cc | 887 ++- contrib/libs/tcmalloc/tcmalloc/common.cc | 182 +- contrib/libs/tcmalloc/tcmalloc/common.h | 386 +- contrib/libs/tcmalloc/tcmalloc/copts.bzl | 49 + contrib/libs/tcmalloc/tcmalloc/cpu_cache.cc | 1088 +--- contrib/libs/tcmalloc/tcmalloc/cpu_cache.h | 2764 +++++++- .../tcmalloc/cpu_cache_activate_test.cc | 87 + .../libs/tcmalloc/tcmalloc/cpu_cache_test.cc | 1728 ++++- .../tcmalloc/deallocation_profiler.cc | 760 +++ .../tcmalloc/tcmalloc/deallocation_profiler.h | 69 + contrib/libs/tcmalloc/tcmalloc/experiment.cc | 180 +- contrib/libs/tcmalloc/tcmalloc/experiment.h | 23 +- .../tcmalloc/tcmalloc/experiment_config.h | 25 +- .../libs/tcmalloc/tcmalloc/experiment_fuzz.cc | 29 +- .../tcmalloc/experimental_56_size_class.cc | 706 -- .../experimental_pow2_below64_size_class.cc | 679 -- .../tcmalloc/experimental_pow2_size_class.cc | 412 +- .../libs/tcmalloc/tcmalloc/global_stats.cc | 1029 +++ contrib/libs/tcmalloc/tcmalloc/global_stats.h | 87 + .../tcmalloc/tcmalloc/guarded_allocations.h | 62 + .../tcmalloc/guarded_page_allocator.cc | 663 +- .../tcmalloc/guarded_page_allocator.h | 246 +- .../guarded_page_allocator_benchmark.cc | 148 +- .../guarded_page_allocator_profile_test.cc | 371 ++ .../tcmalloc/guarded_page_allocator_test.cc | 227 +- .../tcmalloc/tcmalloc/heap_profiling_test.cc | 122 - .../tcmalloc/tcmalloc/hinted_tracker_lists.h | 131 + .../tcmalloc/tcmalloc/huge_address_map.cc | 139 +- .../libs/tcmalloc/tcmalloc/huge_address_map.h | 63 +- .../tcmalloc/huge_address_map_test.cc | 20 +- .../libs/tcmalloc/tcmalloc/huge_allocator.cc | 61 +- .../libs/tcmalloc/tcmalloc/huge_allocator.h | 39 +- .../tcmalloc/tcmalloc/huge_allocator_test.cc | 142 +- contrib/libs/tcmalloc/tcmalloc/huge_cache.cc | 309 +- contrib/libs/tcmalloc/tcmalloc/huge_cache.h | 159 +- .../libs/tcmalloc/tcmalloc/huge_cache_test.cc | 800 ++- .../tcmalloc/huge_page_aware_allocator.cc | 655 +- .../tcmalloc/huge_page_aware_allocator.h | 1106 +++- .../huge_page_aware_allocator_fuzz.cc | 550 ++ .../huge_page_aware_allocator_test.cc | 1607 ++++- .../libs/tcmalloc/tcmalloc/huge_page_filler.h | 2394 ++++--- .../tcmalloc/huge_page_filler_fuzz.cc | 450 ++ .../tcmalloc/huge_page_filler_test.cc | 5651 +++++++++-------- .../tcmalloc/tcmalloc/huge_page_subrelease.h | 731 +++ .../tcmalloc/huge_page_subrelease_test.cc | 351 + contrib/libs/tcmalloc/tcmalloc/huge_pages.h | 114 +- contrib/libs/tcmalloc/tcmalloc/huge_region.h | 588 +- .../tcmalloc/tcmalloc/huge_region_fuzz.cc | 262 + .../tcmalloc/tcmalloc/huge_region_test.cc | 774 ++- contrib/libs/tcmalloc/tcmalloc/internal/BUILD | 1122 ++++ .../tcmalloc/tcmalloc/internal/affinity.cc | 99 + .../tcmalloc/tcmalloc/internal/affinity.h | 71 + .../tcmalloc/internal/affinity_test.cc | 102 + .../tcmalloc/internal/allocation_guard.cc | 24 + .../tcmalloc/internal/allocation_guard.h | 57 + .../internal/allocation_guard_test.cc | 40 + .../tcmalloc/internal/atomic_danger.h | 2 + .../tcmalloc/internal/atomic_stats_counter.h | 3 +- .../libs/tcmalloc/tcmalloc/internal/bits.h | 82 - .../tcmalloc/tcmalloc/internal/bits_test.cc | 104 - .../tcmalloc/internal/cache_topology.cc | 92 +- .../tcmalloc/internal/cache_topology.h | 38 +- .../tcmalloc/internal/cache_topology_test.cc | 33 +- .../libs/tcmalloc/tcmalloc/internal/clock.h | 1 + .../libs/tcmalloc/tcmalloc/internal/config.h | 82 +- .../tcmalloc/tcmalloc/internal/config_test.cc | 101 + .../tcmalloc/tcmalloc/internal/cpu_utils.h | 85 + .../tcmalloc/tcmalloc/internal/declarations.h | 22 +- .../tcmalloc/tcmalloc/internal/environment.cc | 2 + .../tcmalloc/tcmalloc/internal/environment.h | 1 + .../internal/explicitly_constructed.h | 63 + .../tcmalloc/internal/exponential_biased.h | 78 + .../internal/exponential_biased_test.cc | 125 + .../tcmalloc/tcmalloc/internal/fake_profile.h | 66 + .../tcmalloc/internal/lifetime_predictions.h | 252 - .../internal/lifetime_predictions_test.cc | 156 - .../tcmalloc/internal/lifetime_tracker.h | 172 - .../internal/lifetime_tracker_test.cc | 129 - .../tcmalloc/tcmalloc/internal/linked_list.h | 39 +- .../internal/linked_list_benchmark.cc | 5 +- .../tcmalloc/internal/linked_list_test.cc | 16 +- .../tcmalloc/internal/linux_syscall_support.h | 19 +- .../tcmalloc/tcmalloc/internal/logging.cc | 302 +- .../libs/tcmalloc/tcmalloc/internal/logging.h | 390 +- .../tcmalloc/internal/logging_test.cc | 243 +- .../tcmalloc/internal/memory_stats.cc | 15 +- .../tcmalloc/tcmalloc/internal/memory_stats.h | 1 + .../tcmalloc/internal/memory_stats_test.cc | 3 +- .../tcmalloc/tcmalloc/internal/memory_tag.cc | 44 + .../tcmalloc/tcmalloc/internal/memory_tag.h | 90 + .../tcmalloc/tcmalloc/internal/mincore.cc | 9 +- .../libs/tcmalloc/tcmalloc/internal/mincore.h | 1 + .../tcmalloc/internal/mincore_benchmark.cc | 12 +- .../tcmalloc/internal/mincore_test.cc | 32 +- .../internal/mismatched_delete_state.h | 122 + .../tcmalloc/tcmalloc/internal/mock_span.h | 1 + .../libs/tcmalloc/tcmalloc/internal/numa.cc | 107 +- .../libs/tcmalloc/tcmalloc/internal/numa.h | 100 +- .../tcmalloc/tcmalloc/internal/numa_test.cc | 116 +- .../tcmalloc/tcmalloc/internal/optimization.h | 28 +- .../overflow.h} | 28 +- .../tcmalloc/tcmalloc/internal/page_size.cc | 45 + .../page_size.h} | 16 +- .../tcmalloc/tcmalloc/internal/pageflags.cc | 368 ++ .../tcmalloc/tcmalloc/internal/pageflags.h | 154 + .../tcmalloc/internal/pageflags_test.cc | 571 ++ .../tcmalloc/internal/parameter_accessors.h | 85 +- .../libs/tcmalloc/tcmalloc/internal/percpu.cc | 292 +- .../libs/tcmalloc/tcmalloc/internal/percpu.h | 379 +- .../tcmalloc/internal/percpu_early_test.cc | 39 + .../tcmalloc/internal/percpu_rseq_aarch64.S | 344 +- .../tcmalloc/internal/percpu_rseq_asm.S | 43 +- .../tcmalloc/internal/percpu_rseq_ppc.S | 606 -- .../internal/percpu_rseq_unsupported.cc | 45 +- .../tcmalloc/internal/percpu_rseq_x86_64.S | 311 +- .../tcmalloc/internal/percpu_tcmalloc.h | 2136 ++++--- .../tcmalloc/internal/percpu_tcmalloc_test.cc | 1385 ++-- .../tcmalloc/tcmalloc/internal/percpu_test.cc | 74 + .../tcmalloc/tcmalloc/internal/prefetch.h | 116 + .../tcmalloc/internal/prefetch_test.cc | 72 + .../tcmalloc/tcmalloc/internal/proc_maps.cc | 19 +- .../tcmalloc/tcmalloc/internal/proc_maps.h | 14 +- .../tcmalloc/tcmalloc/internal/profile.proto | 233 + .../tcmalloc/internal/profile_builder.cc | 927 +++ .../tcmalloc/internal/profile_builder.h | 102 + .../tcmalloc/internal/profile_builder_fuzz.cc | 54 + .../profile_builder_no_tcmalloc_test.cc | 46 + .../tcmalloc/internal/profile_builder_test.cc | 1031 +++ .../tcmalloc/internal/range_tracker.h | 95 +- .../internal/range_tracker_benchmark.cc | 14 +- .../tcmalloc/internal/range_tracker_test.cc | 33 +- .../tcmalloc/tcmalloc/internal/residency.cc | 230 + .../tcmalloc/tcmalloc/internal/residency.h | 120 + .../tcmalloc/internal/residency_test.cc | 373 ++ .../tcmalloc/internal/sampled_allocation.h | 64 + .../internal/sampled_allocation_recorder.h | 262 + .../sampled_allocation_recorder_test.cc | 278 + .../internal/sampled_allocation_test.cc | 70 + .../tcmalloc/internal/stacktrace_filter.h | 161 + .../internal/stacktrace_filter_test.cc | 262 + .../tcmalloc/tcmalloc/internal/sysinfo.cc | 147 + .../libs/tcmalloc/tcmalloc/internal/sysinfo.h | 80 + .../tcmalloc/internal/sysinfo_fuzz.cc | 48 + .../tcmalloc/internal/sysinfo_test.cc | 181 + ...ized-profile_builder_fuzz-5534221534363648 | Bin 0 -> 16 bytes ...ized-profile_builder_fuzz-5647243657216000 | Bin 0 -> 16 bytes ...ized-profile_builder_fuzz-5915530833559552 | Bin 0 -> 12 bytes ...profile_builder_fuzz-6685031907328000.fuzz | Bin 0 -> 84 bytes ...h-adc83b19e793491b1c6ea0fd8b46cd9f32e592fc | 1 + .../tcmalloc/internal/timeseries_tracker.h | 31 +- .../internal/timeseries_tracker_test.cc | 35 +- .../libs/tcmalloc/tcmalloc/internal/util.cc | 77 +- .../libs/tcmalloc/tcmalloc/internal/util.h | 86 +- .../libs/tcmalloc/tcmalloc/internal/ya.make | 21 + .../tcmalloc/internal_malloc_extension.h | 62 +- .../internal_malloc_tracing_extension.h | 36 + .../tcmalloc/tcmalloc/legacy_size_classes.cc | 1356 ++-- .../libs/tcmalloc/tcmalloc/libc_override.h | 185 +- .../tcmalloc/libc_override_gcc_and_weak.h | 114 - .../tcmalloc/tcmalloc/libc_override_glibc.h | 120 - .../tcmalloc/libc_override_redefine.h | 100 - .../tcmalloc/tcmalloc/malloc_extension.cc | 536 +- .../libs/tcmalloc/tcmalloc/malloc_extension.h | 422 +- .../tcmalloc/malloc_extension_fuzz.cc | 26 +- .../tcmalloc/malloc_extension_test.cc | 67 - .../tcmalloc/malloc_tracing_extension.cc | 41 + .../tcmalloc/malloc_tracing_extension.h | 55 + .../tcmalloc/tcmalloc/metadata_allocator.h | 41 + .../tcmalloc/metadata_object_allocator.h | 142 + .../tcmalloc/mock_central_freelist.cc | 39 +- .../tcmalloc/tcmalloc/mock_central_freelist.h | 28 +- .../mock_huge_page_static_forwarder.cc | 13 + .../mock_huge_page_static_forwarder.h | 243 + .../tcmalloc/mock_metadata_allocator.h | 47 + .../tcmalloc/tcmalloc/mock_static_forwarder.h | 242 + .../tcmalloc/tcmalloc/mock_transfer_cache.cc | 10 +- .../tcmalloc/tcmalloc/mock_transfer_cache.h | 329 +- .../tcmalloc/mock_virtual_allocator.h | 70 + .../libs/tcmalloc/tcmalloc/new_extension.h | 24 + .../tcmalloc/tcmalloc/new_extension_test.cc | 485 ++ .../libs/tcmalloc/tcmalloc/page_allocator.cc | 231 +- .../libs/tcmalloc/tcmalloc/page_allocator.h | 250 +- .../tcmalloc/page_allocator_interface.cc | 58 +- .../tcmalloc/page_allocator_interface.h | 51 +- .../tcmalloc/tcmalloc/page_allocator_test.cc | 165 +- .../tcmalloc/page_allocator_test_util.h | 35 +- contrib/libs/tcmalloc/tcmalloc/page_heap.cc | 528 -- contrib/libs/tcmalloc/tcmalloc/page_heap.h | 161 - .../tcmalloc/tcmalloc/page_heap_allocator.h | 93 - .../libs/tcmalloc/tcmalloc/page_heap_test.cc | 109 - contrib/libs/tcmalloc/tcmalloc/pagemap.cc | 19 +- contrib/libs/tcmalloc/tcmalloc/pagemap.h | 190 +- .../libs/tcmalloc/tcmalloc/pagemap_test.cc | 6 +- contrib/libs/tcmalloc/tcmalloc/pages.h | 80 +- contrib/libs/tcmalloc/tcmalloc/pages_test.cc | 34 + contrib/libs/tcmalloc/tcmalloc/parameters.cc | 528 +- contrib/libs/tcmalloc/tcmalloc/parameters.h | 192 +- .../tcmalloc/tcmalloc/peak_heap_tracker.cc | 71 +- .../tcmalloc/tcmalloc/peak_heap_tracker.h | 62 +- .../tcmalloc/tcmalloc/profile_marshaler.cc | 46 + .../tcmalloc/tcmalloc/profile_marshaler.h | 33 + .../tcmalloc/profile_marshaler_test.cc | 86 + .../libs/tcmalloc/tcmalloc/profile_test.cc | 137 +- .../tcmalloc/tcmalloc/reuse_size_classes.cc | 514 ++ .../tcmalloc/tcmalloc/runtime_size_classes.cc | 81 - .../tcmalloc/tcmalloc/runtime_size_classes.h | 49 - .../tcmalloc/runtime_size_classes_test.cc | 114 - contrib/libs/tcmalloc/tcmalloc/sampler.cc | 144 +- contrib/libs/tcmalloc/tcmalloc/sampler.h | 211 +- .../libs/tcmalloc/tcmalloc/segv_handler.cc | 261 + .../{want_no_hpaa.cc => segv_handler.h} | 17 +- .../tcmalloc/tcmalloc/segv_handler_test.cc | 108 + contrib/libs/tcmalloc/tcmalloc/selsan/BUILD | 63 + .../libs/tcmalloc/tcmalloc/selsan/README.md | 25 + .../tcmalloc/tcmalloc/selsan/report_test.cc | 82 + .../libs/tcmalloc/tcmalloc/selsan/selsan.cc | 300 + .../libs/tcmalloc/tcmalloc/selsan/selsan.h | 209 + .../tcmalloc/tcmalloc/selsan/shadow_test.cc | 139 + .../libs/tcmalloc/tcmalloc/size_class_info.h | 62 +- .../libs/tcmalloc/tcmalloc/size_classes.cc | 1336 ++-- .../tcmalloc/tcmalloc/size_classes_test.cc | 298 +- ..._classes_with_runtime_size_classes_test.cc | 127 - contrib/libs/tcmalloc/tcmalloc/sizemap.cc | 289 + contrib/libs/tcmalloc/tcmalloc/sizemap.h | 322 + .../libs/tcmalloc/tcmalloc/sizemap_fuzz.cc | 65 + .../libs/tcmalloc/tcmalloc/sizemap_test.cc | 142 + contrib/libs/tcmalloc/tcmalloc/span.cc | 331 +- contrib/libs/tcmalloc/tcmalloc/span.h | 672 +- .../libs/tcmalloc/tcmalloc/span_benchmark.cc | 141 +- contrib/libs/tcmalloc/tcmalloc/span_fuzz.cc | 129 + contrib/libs/tcmalloc/tcmalloc/span_stats.h | 3 +- contrib/libs/tcmalloc/tcmalloc/span_test.cc | 186 +- .../tcmalloc/tcmalloc/stack_trace_table.cc | 182 +- .../tcmalloc/tcmalloc/stack_trace_table.h | 65 +- .../tcmalloc/stack_trace_table_test.cc | 264 +- contrib/libs/tcmalloc/tcmalloc/static_vars.cc | 198 +- contrib/libs/tcmalloc/tcmalloc/static_vars.h | 258 +- contrib/libs/tcmalloc/tcmalloc/stats.cc | 432 +- contrib/libs/tcmalloc/tcmalloc/stats.h | 185 +- contrib/libs/tcmalloc/tcmalloc/stats_test.cc | 135 +- .../libs/tcmalloc/tcmalloc/system-alloc.cc | 614 +- contrib/libs/tcmalloc/tcmalloc/system-alloc.h | 831 ++- contrib/libs/tcmalloc/tcmalloc/tcmalloc.cc | 2602 +++----- contrib/libs/tcmalloc/tcmalloc/tcmalloc.h | 135 +- .../libs/tcmalloc/tcmalloc/tcmalloc_policy.h | 251 +- ...ase-central_freelist_fuzz-6338860943802368 | Bin 0 -> 74490 bytes ...zed-central_freelist_fuzz-5328515345809408 | Bin 0 -> 52550 bytes ...page_aware_allocator_fuzz-4796454007799808 | Bin 0 -> 824 bytes ...page_aware_allocator_fuzz-4650158169391104 | Bin 0 -> 171 bytes ...page_aware_allocator_fuzz-5216394376773632 | 5 + ...page_aware_allocator_fuzz-5397442449178624 | 1 + ...page_aware_allocator_fuzz-5580915038093312 | Bin 0 -> 53344 bytes ...page_aware_allocator_fuzz-6140744194457600 | 1 + ...page_aware_allocator_fuzz-6302517124005888 | Bin 0 -> 1454 bytes .../testcase-4507694249082880 | Bin 0 -> 4614 bytes .../testcase-4582514590875648 | 0 .../testcase-5091122805276672 | Bin 0 -> 3663 bytes .../testcase-5185382849773568 | Bin 0 -> 2749 bytes .../testcase-5781242586923008 | Bin 0 -> 22 bytes .../testcase-6591694528970752 | Bin 0 -> 22 bytes ...ase-huge_page_filler_fuzz-5476984341004288 | Bin 0 -> 48109 bytes ...uge_page_filler_fuzz-5161409228701696.test | Bin 0 -> 587 bytes ...uge_page_filler_fuzz-5516474505363456.test | Bin 0 -> 42 bytes ...uge_page_filler_fuzz-6053674183688192.test | Bin 0 -> 450 bytes ...zed-huge_page_filler_fuzz-6159120802381824 | Bin 0 -> 32 bytes ...uge_page_filler_fuzz-6512022070886400.test | Bin 0 -> 32 bytes ...zed-huge_page_filler_fuzz-6622985612820480 | Bin 0 -> 1615 bytes ...h-869dbc1cdf6a1f79b386adf046c7df32257ef684 | Bin 0 -> 24 bytes ...h-e9f3aa3ad83e808a5588ec529c6cdf00d5d397fc | Bin 0 -> 73 bytes .../testcase-6686265543557120 | 4 + .../testcase-5235702354214912 | Bin 0 -> 131 bytes .../testcase-5618130730156032 | Bin 0 -> 71 bytes ...h-4338e5c59e1bda5104fb5f0aa5553aeb1d3d6465 | 1 + ...h-c20bfc5c10e885f8e5498c2907cfab82da7c0cff | 1 + ...se-minimized-sizemap_fuzz-5240920228626432 | Bin 0 -> 24 bytes ...tcase-minimized-span_fuzz-6271015625031680 | Bin 0 -> 24 bytes ...-minimized-span_fuzz-6321706670620672.fuzz | Bin 0 -> 24 bytes ...h-01d72a40d5815461b92d3f7c0f6377fd441b0034 | Bin 0 -> 24 bytes ...h-32697afd59029eb8356fee8ba568e7f6b58d728f | Bin 0 -> 24 bytes ...h-42b80edf9551d1095aebb6724c070ee43d490125 | Bin 0 -> 24 bytes ...h-500955af6568b0ed234bd40d6a01af496ba15eb2 | Bin 0 -> 24 bytes ...h-6ef2b6ae2246d1bda0190983b1007df2699e7738 | Bin 0 -> 24 bytes ...h-746940d0368bfe3e4a94b60659eeb6cb87106618 | Bin 0 -> 24 bytes .../span_fuzz/testcase-5877384059617280 | Bin 0 -> 77 bytes ...k-0b593173f17376c77a3a74a6644af58f77d7a366 | 1 + contrib/libs/tcmalloc/tcmalloc/testing/BUILD | 977 +++ .../tcmalloc/testing/aligned_new_test.cc | 184 + .../tcmalloc/testing/background_test.cc | 73 + .../tcmalloc/testing/benchmark_main.cc | 21 + .../testing/current_allocated_bytes_test.cc | 64 + .../testing/deallocation_profiler_test.cc | 772 +++ .../testing/default_parameters_test.cc | 135 + .../tcmalloc/testing/disable_numa_test.cc | 26 + .../testing/fast_path.insecure.golden | 16 + .../tcmalloc/testing/fast_path.opt.golden | 16 + .../testing/fast_path.release+insecure.golden | 16 + .../tcmalloc/testing/fast_path.release.golden | 16 + .../testing/fast_path.unstable.release.golden | 16 + .../tcmalloc/tcmalloc/testing/frag_test.cc | 69 + .../tcmalloc/testing/get_stats_test.cc | 415 ++ .../tcmalloc/testing/heap_profiling_test.cc | 267 + .../tcmalloc/tcmalloc/testing/hello_main.cc | 62 + .../tcmalloc/testing/large_alloc_size_test.cc | 56 + .../tcmalloc/testing/largesmall_frag_test.cc | 109 + .../tcmalloc/tcmalloc/testing/limit_test.cc | 476 ++ .../malloc_extension_system_malloc_test.cc | 7 +- .../tcmalloc/testing/malloc_extension_test.cc | 192 + .../testing/malloc_tracing_extension_test.cc | 111 + .../tcmalloc/testing/markidle_test.cc | 95 + .../tcmalloc/testing/memalign_test.cc | 297 + .../tcmalloc/testing/memory_errors_test.cc | 665 ++ .../tcmalloc/tcmalloc/testing/no_deps_test.cc | 145 + .../tcmalloc/testing/numa_locality_test.cc | 244 + .../tcmalloc/testing/outofmemory_test.cc | 90 + .../tcmalloc/testing/parallel_test.cc | 90 + .../testing/peak_heap_profiling_test.cc | 156 + .../testing/profile_drop_frames_test.cc | 382 ++ .../tcmalloc/tcmalloc/testing/profile_test.cc | 229 + .../testing/realized_fragmentation_test.cc | 217 + .../tcmalloc/{ => testing}/realloc_test.cc | 4 - .../tcmalloc/tcmalloc/testing/reclaim_test.cc | 191 + .../tcmalloc/testing/releasing_test.cc | 145 + .../testing/sample_size_class_test.cc | 103 + .../tcmalloc/tcmalloc/testing/sampler_test.cc | 275 + .../testing/sampling_memusage_test.cc | 187 + .../tcmalloc/testing/sampling_test.cc | 286 + .../tcmalloc/testing/startup_size_test.cc | 75 + .../{ => testing}/system-alloc_test.cc | 129 +- .../tcmalloc/testing/tcmalloc_benchmark.cc | 503 ++ .../{ => testing}/tcmalloc_large_test.cc | 32 +- .../tcmalloc/testing/tcmalloc_test.cc | 1670 +++++ .../tcmalloc/testing/test_allocator_harness.h | 225 + .../tcmalloc/tcmalloc/testing/testutil.cc | 178 + .../libs/tcmalloc/tcmalloc/testing/testutil.h | 295 + .../tcmalloc/testing/thread_ctor_test.cc | 22 + .../tcmalloc/testing/thread_ctor_test_lib.cc | 64 + .../tcmalloc/testing/thread_manager.h | 64 + .../tcmalloc/testing/threadcachesize_test.cc | 107 + .../tcmalloc/testing/variants_test.cc | 65 + ...ble_huge_region_more_often_test_helper.cc} | 24 +- ...t_disable_tcmalloc_big_span_test_helper.cc | 32 + .../tcmalloc/testing/want_hpaa_test_helper.cc | 60 + .../want_pow2below64_size_classes_helper.cc | 39 + .../libs/tcmalloc/tcmalloc/thread_cache.cc | 196 +- contrib/libs/tcmalloc/tcmalloc/thread_cache.h | 179 +- .../tcmalloc/tcmalloc/thread_cache_test.cc | 34 +- contrib/libs/tcmalloc/tcmalloc/tracking.h | 109 - .../libs/tcmalloc/tcmalloc/transfer_cache.cc | 134 +- .../libs/tcmalloc/tcmalloc/transfer_cache.h | 613 +- .../tcmalloc/transfer_cache_benchmark.cc | 128 +- .../tcmalloc/tcmalloc/transfer_cache_fuzz.cc | 70 +- .../tcmalloc/transfer_cache_internals.h | 881 +-- .../tcmalloc/tcmalloc/transfer_cache_stats.h | 8 +- .../tcmalloc/tcmalloc/transfer_cache_test.cc | 763 ++- contrib/libs/tcmalloc/tcmalloc/variants.bzl | 397 ++ ...spans.cc => want_disable_dynamic_slabs.cc} | 10 +- .../want_disable_huge_region_more_often.cc | 28 + .../want_disable_tcmalloc_big_span.cc | 26 + contrib/libs/tcmalloc/tcmalloc/want_hpaa.cc | 4 +- .../tcmalloc/want_legacy_size_classes.cc | 25 + .../tcmalloc/want_legacy_size_classes_test.cc | 46 + contrib/libs/tcmalloc/ya.make | 10 +- .../yatest_common/yatest/common/process.py | 4 +- yt/yt/library/ytprof/profile.cpp | 2 +- 401 files changed, 63094 insertions(+), 26324 deletions(-) create mode 100644 contrib/libs/tcmalloc/.yandex_meta/build.ym create mode 100644 contrib/libs/tcmalloc/patches/010-fork.patch create mode 100644 contrib/libs/tcmalloc/patches/020-user-data.patch rename contrib/libs/tcmalloc/patches/{handler.patch => 030-soft-limit-handler.patch} (58%) create mode 100644 contrib/libs/tcmalloc/patches/040-remove-conflicting-noexcept.patch create mode 100644 contrib/libs/tcmalloc/patches/050-avoid-cycle.patch create mode 100644 contrib/libs/tcmalloc/patches/060-system-headers.sh create mode 100644 contrib/libs/tcmalloc/patches/900-undeprecate-rate-interval.patch delete mode 100644 contrib/libs/tcmalloc/patches/fork.patch delete mode 100644 contrib/libs/tcmalloc/patches/userdata.patch delete mode 100644 contrib/libs/tcmalloc/patches/yandex.patch create mode 100644 contrib/libs/tcmalloc/tcmalloc/.github/CODEOWNERS create mode 100644 contrib/libs/tcmalloc/tcmalloc/.github/workflows/ci.yml create mode 100644 contrib/libs/tcmalloc/tcmalloc/allocation_sample.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/allocation_sample.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/allocation_sample_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/allocation_sampling.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/allocation_sampling.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/central_freelist_fuzz.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/copts.bzl create mode 100644 contrib/libs/tcmalloc/tcmalloc/cpu_cache_activate_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/deallocation_profiler.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/deallocation_profiler.h delete mode 100644 contrib/libs/tcmalloc/tcmalloc/experimental_56_size_class.cc delete mode 100755 contrib/libs/tcmalloc/tcmalloc/experimental_pow2_below64_size_class.cc mode change 100755 => 100644 contrib/libs/tcmalloc/tcmalloc/experimental_pow2_size_class.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/global_stats.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/global_stats.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/guarded_allocations.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator_profile_test.cc delete mode 100644 contrib/libs/tcmalloc/tcmalloc/heap_profiling_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/hinted_tracker_lists.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator_fuzz.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/huge_page_filler_fuzz.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/huge_page_subrelease.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/huge_page_subrelease_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/huge_region_fuzz.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/BUILD create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/affinity.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/affinity.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/affinity_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/allocation_guard.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/allocation_guard.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/allocation_guard_test.cc delete mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/bits.h delete mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/bits_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/config_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/cpu_utils.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/explicitly_constructed.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/exponential_biased.h create mode 100755 contrib/libs/tcmalloc/tcmalloc/internal/exponential_biased_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/fake_profile.h delete mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/lifetime_predictions.h delete mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/lifetime_predictions_test.cc delete mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/lifetime_tracker.h delete mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/lifetime_tracker_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/memory_tag.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/memory_tag.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/mismatched_delete_state.h rename contrib/libs/tcmalloc/tcmalloc/{noruntime_size_classes.cc => internal/overflow.h} (58%) create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/page_size.cc rename contrib/libs/tcmalloc/tcmalloc/{want_hpaa_subrelease.cc => internal/page_size.h} (75%) create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/pageflags.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/pageflags.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/pageflags_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/percpu_early_test.cc delete mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_ppc.S create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/percpu_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/prefetch.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/prefetch_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/profile.proto create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/profile_builder.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/profile_builder.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/profile_builder_fuzz.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/profile_builder_no_tcmalloc_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/profile_builder_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/residency.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/residency.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/residency_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation_recorder.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation_recorder_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/stacktrace_filter.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/stacktrace_filter_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/sysinfo.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/sysinfo.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/sysinfo_fuzz.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/sysinfo_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/testdata/profile_builder_fuzz/clusterfuzz-testcase-minimized-profile_builder_fuzz-5534221534363648 create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/testdata/profile_builder_fuzz/clusterfuzz-testcase-minimized-profile_builder_fuzz-5647243657216000 create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/testdata/profile_builder_fuzz/clusterfuzz-testcase-minimized-profile_builder_fuzz-5915530833559552 create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/testdata/profile_builder_fuzz/clusterfuzz-testcase-minimized-profile_builder_fuzz-6685031907328000.fuzz create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/testdata/profile_builder_fuzz/crash-adc83b19e793491b1c6ea0fd8b46cd9f32e592fc create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal/ya.make create mode 100644 contrib/libs/tcmalloc/tcmalloc/internal_malloc_tracing_extension.h delete mode 100644 contrib/libs/tcmalloc/tcmalloc/libc_override_gcc_and_weak.h delete mode 100644 contrib/libs/tcmalloc/tcmalloc/libc_override_glibc.h delete mode 100644 contrib/libs/tcmalloc/tcmalloc/libc_override_redefine.h delete mode 100644 contrib/libs/tcmalloc/tcmalloc/malloc_extension_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/malloc_tracing_extension.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/malloc_tracing_extension.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/metadata_allocator.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/metadata_object_allocator.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/mock_huge_page_static_forwarder.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/mock_huge_page_static_forwarder.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/mock_metadata_allocator.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/mock_static_forwarder.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/mock_virtual_allocator.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/new_extension.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/new_extension_test.cc delete mode 100644 contrib/libs/tcmalloc/tcmalloc/page_heap.cc delete mode 100644 contrib/libs/tcmalloc/tcmalloc/page_heap.h delete mode 100644 contrib/libs/tcmalloc/tcmalloc/page_heap_allocator.h delete mode 100644 contrib/libs/tcmalloc/tcmalloc/page_heap_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/pages_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/profile_marshaler.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/profile_marshaler.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/profile_marshaler_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/reuse_size_classes.cc delete mode 100644 contrib/libs/tcmalloc/tcmalloc/runtime_size_classes.cc delete mode 100644 contrib/libs/tcmalloc/tcmalloc/runtime_size_classes.h delete mode 100644 contrib/libs/tcmalloc/tcmalloc/runtime_size_classes_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/segv_handler.cc rename contrib/libs/tcmalloc/tcmalloc/{want_no_hpaa.cc => segv_handler.h} (68%) create mode 100644 contrib/libs/tcmalloc/tcmalloc/segv_handler_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/selsan/BUILD create mode 100644 contrib/libs/tcmalloc/tcmalloc/selsan/README.md create mode 100644 contrib/libs/tcmalloc/tcmalloc/selsan/report_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/selsan/selsan.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/selsan/selsan.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/selsan/shadow_test.cc delete mode 100644 contrib/libs/tcmalloc/tcmalloc/size_classes_with_runtime_size_classes_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/sizemap.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/sizemap.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/sizemap_fuzz.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/sizemap_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/span_fuzz.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/central_freelist_fuzz/clusterfuzz-testcase-central_freelist_fuzz-6338860943802368 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/central_freelist_fuzz/clusterfuzz-testcase-minimized-central_freelist_fuzz-5328515345809408 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/clusterfuzz-testcase-minimized-huge_page_aware_allocator_fuzz-4796454007799808 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_aware_allocator_fuzz/clusterfuzz-testcase-minimized-huge_page_aware_allocator_fuzz-4650158169391104 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_aware_allocator_fuzz/clusterfuzz-testcase-minimized-huge_page_aware_allocator_fuzz-5216394376773632 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_aware_allocator_fuzz/clusterfuzz-testcase-minimized-huge_page_aware_allocator_fuzz-5397442449178624 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_aware_allocator_fuzz/clusterfuzz-testcase-minimized-huge_page_aware_allocator_fuzz-5580915038093312 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_aware_allocator_fuzz/clusterfuzz-testcase-minimized-huge_page_aware_allocator_fuzz-6140744194457600 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_aware_allocator_fuzz/clusterfuzz-testcase-minimized-huge_page_aware_allocator_fuzz-6302517124005888 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_aware_allocator_fuzz/testcase-4507694249082880 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_aware_allocator_fuzz/testcase-4582514590875648 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_aware_allocator_fuzz/testcase-5091122805276672 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_aware_allocator_fuzz/testcase-5185382849773568 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_aware_allocator_fuzz/testcase-5781242586923008 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_aware_allocator_fuzz/testcase-6591694528970752 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_filler_fuzz/clusterfuzz-testcase-huge_page_filler_fuzz-5476984341004288 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_filler_fuzz/clusterfuzz-testcase-minimized-huge_page_filler_fuzz-5161409228701696.test create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_filler_fuzz/clusterfuzz-testcase-minimized-huge_page_filler_fuzz-5516474505363456.test create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_filler_fuzz/clusterfuzz-testcase-minimized-huge_page_filler_fuzz-6053674183688192.test create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_filler_fuzz/clusterfuzz-testcase-minimized-huge_page_filler_fuzz-6159120802381824 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_filler_fuzz/clusterfuzz-testcase-minimized-huge_page_filler_fuzz-6512022070886400.test create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_filler_fuzz/clusterfuzz-testcase-minimized-huge_page_filler_fuzz-6622985612820480 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_filler_fuzz/crash-869dbc1cdf6a1f79b386adf046c7df32257ef684 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_filler_fuzz/crash-e9f3aa3ad83e808a5588ec529c6cdf00d5d397fc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_page_filler_fuzz/testcase-6686265543557120 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_region_fuzz/testcase-5235702354214912 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/huge_region_fuzz/testcase-5618130730156032 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/malloc_extension_fuzz/crash-4338e5c59e1bda5104fb5f0aa5553aeb1d3d6465 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/malloc_extension_fuzz/crash-c20bfc5c10e885f8e5498c2907cfab82da7c0cff create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/sizemap_fuzz/clusterfuzz-testcase-minimized-sizemap_fuzz-5240920228626432 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/span_fuzz/clusterfuzz-testcase-minimized-span_fuzz-6271015625031680 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/span_fuzz/clusterfuzz-testcase-minimized-span_fuzz-6321706670620672.fuzz create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/span_fuzz/crash-01d72a40d5815461b92d3f7c0f6377fd441b0034 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/span_fuzz/crash-32697afd59029eb8356fee8ba568e7f6b58d728f create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/span_fuzz/crash-42b80edf9551d1095aebb6724c070ee43d490125 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/span_fuzz/crash-500955af6568b0ed234bd40d6a01af496ba15eb2 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/span_fuzz/crash-6ef2b6ae2246d1bda0190983b1007df2699e7738 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/span_fuzz/crash-746940d0368bfe3e4a94b60659eeb6cb87106618 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/span_fuzz/testcase-5877384059617280 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testdata/transfer_cache_fuzz/leak-0b593173f17376c77a3a74a6644af58f77d7a366 create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/BUILD create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/aligned_new_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/background_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/benchmark_main.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/current_allocated_bytes_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/deallocation_profiler_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/default_parameters_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/disable_numa_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/fast_path.insecure.golden create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/fast_path.opt.golden create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/fast_path.release+insecure.golden create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/fast_path.release.golden create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/fast_path.unstable.release.golden create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/frag_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/get_stats_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/heap_profiling_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/hello_main.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/large_alloc_size_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/largesmall_frag_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/limit_test.cc rename contrib/libs/tcmalloc/tcmalloc/{ => testing}/malloc_extension_system_malloc_test.cc (95%) create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/malloc_extension_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/malloc_tracing_extension_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/markidle_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/memalign_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/memory_errors_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/no_deps_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/numa_locality_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/outofmemory_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/parallel_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/peak_heap_profiling_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/profile_drop_frames_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/profile_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/realized_fragmentation_test.cc rename contrib/libs/tcmalloc/tcmalloc/{ => testing}/realloc_test.cc (96%) create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/reclaim_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/releasing_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/sample_size_class_test.cc create mode 100755 contrib/libs/tcmalloc/tcmalloc/testing/sampler_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/sampling_memusage_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/sampling_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/startup_size_test.cc rename contrib/libs/tcmalloc/tcmalloc/{ => testing}/system-alloc_test.cc (53%) create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/tcmalloc_benchmark.cc rename contrib/libs/tcmalloc/tcmalloc/{ => testing}/tcmalloc_large_test.cc (85%) create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/tcmalloc_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/test_allocator_harness.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/testutil.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/testutil.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/thread_ctor_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/thread_ctor_test_lib.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/thread_manager.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/threadcachesize_test.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/variants_test.cc rename contrib/libs/tcmalloc/tcmalloc/{runtime_size_classes_fuzz.cc => testing/want_disable_huge_region_more_often_test_helper.cc} (53%) create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/want_disable_tcmalloc_big_span_test_helper.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/want_hpaa_test_helper.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/testing/want_pow2below64_size_classes_helper.cc delete mode 100644 contrib/libs/tcmalloc/tcmalloc/tracking.h create mode 100644 contrib/libs/tcmalloc/tcmalloc/variants.bzl rename contrib/libs/tcmalloc/tcmalloc/{want_legacy_spans.cc => want_disable_dynamic_slabs.cc} (71%) create mode 100644 contrib/libs/tcmalloc/tcmalloc/want_disable_huge_region_more_often.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/want_disable_tcmalloc_big_span.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/want_legacy_size_classes.cc create mode 100644 contrib/libs/tcmalloc/tcmalloc/want_legacy_size_classes_test.cc diff --git a/contrib/libs/tcmalloc/.yandex_meta/build.ym b/contrib/libs/tcmalloc/.yandex_meta/build.ym new file mode 100644 index 000000000000..b6bf9d0f75ac --- /dev/null +++ b/contrib/libs/tcmalloc/.yandex_meta/build.ym @@ -0,0 +1,62 @@ +{% extends '//builtin/bag.ym' %} + +{% block current_version %}c8dfee3e4c489c5ae0d30c484c92db102a69ec51{% endblock %} + +{% block current_url %} +https://github.com/google/tcmalloc/archive/{{self.version().strip()}}.tar.gz +{% endblock %} + +{% block current_date %}2025-01-30{% endblock %} + +{% block keep_sources %} +common.inc +default/ya.make +dynamic/ya.make +malloc_extension/ya.make +no_percpu_cache/ya.make +no_percpu_cache/aligned_alloc.c +numa_256k/ya.make +numa_large_pages/ya.make +small_but_slow/ya.make +tcmalloc/internal/ya.make +{% endblock %} + +{% block ya_make %} +SUBSCRIBER( + g:cpp-contrib + ayles + mikailbag +) + +SRCS( + # Options + tcmalloc/want_hpaa.cc +) + +INCLUDE(common.inc) + +CFLAGS( + -DTCMALLOC_256K_PAGES +) +{% endblock %} + +{% block ya_make_suffix %} +IF (NOT DLL_FOR) + RECURSE( + default + dynamic + malloc_extension + no_percpu_cache + numa_256k + numa_large_pages + small_but_slow + tcmalloc/internal + ) +ENDIF() +{% endblock %} + +{% block move_to_output %} +{{super()}} +cp -R tcmalloc common.inc ${OUTPUT} +cp no_percpu_cache/aligned_alloc.c ${OUTPUT}/no_percpu_cache/ +{% endblock %} diff --git a/contrib/libs/tcmalloc/.yandex_meta/devtools.copyrights.report b/contrib/libs/tcmalloc/.yandex_meta/devtools.copyrights.report index 7acc7e09c852..33350ad4e7c7 100644 --- a/contrib/libs/tcmalloc/.yandex_meta/devtools.copyrights.report +++ b/contrib/libs/tcmalloc/.yandex_meta/devtools.copyrights.report @@ -29,6 +29,20 @@ # FILE_INCLUDE - include all file data into licenses text file # ======================= +KEEP COPYRIGHT_SERVICE_LABEL 05bdd09fb9fdb384a61f2eb54df462d6 +BELONGS ya.make + License text: + // Copyright 2016 Google Inc. All Rights Reserved. + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + tcmalloc/internal/profile.proto [1:1] + Belongs difference: + + ya.make + - tcmalloc/internal/ya.make + KEEP COPYRIGHT_SERVICE_LABEL 279545394b5ad4b6b26c0686ac5f9921 BELONGS ya.make License text: @@ -40,161 +54,195 @@ BELONGS ya.make Files with this license: tcmalloc/BUILD [1:1] tcmalloc/arena.cc [1:1] - tcmalloc/arena.h [1:1] + tcmalloc/arena.h [2:2] tcmalloc/background.cc [1:1] tcmalloc/central_freelist.cc [1:1] - tcmalloc/central_freelist.h [1:1] + tcmalloc/central_freelist.h [2:2] tcmalloc/central_freelist_test.cc [1:1] tcmalloc/common.cc [1:1] - tcmalloc/common.h [1:1] + tcmalloc/common.h [2:2] + tcmalloc/copts.bzl [1:1] tcmalloc/cpu_cache.cc [1:1] - tcmalloc/cpu_cache.h [1:1] + tcmalloc/cpu_cache.h [2:2] tcmalloc/cpu_cache_test.cc [1:1] tcmalloc/experiment.cc [1:1] - tcmalloc/experiment.h [1:1] - tcmalloc/experiment_config.h [1:1] + tcmalloc/experiment.h [2:2] + tcmalloc/experiment_config.h [2:2] tcmalloc/experiment_config_test.cc [1:1] tcmalloc/experiment_fuzz.cc [1:1] - tcmalloc/experimental_56_size_class.cc [1:1] - tcmalloc/experimental_pow2_below64_size_class.cc [1:1] tcmalloc/experimental_pow2_size_class.cc [1:1] + tcmalloc/global_stats.cc [1:1] + tcmalloc/global_stats.h [2:2] tcmalloc/guarded_page_allocator.cc [1:1] - tcmalloc/guarded_page_allocator.h [1:1] + tcmalloc/guarded_page_allocator.h [2:2] tcmalloc/guarded_page_allocator_benchmark.cc [1:1] + tcmalloc/guarded_page_allocator_profile_test.cc [1:1] tcmalloc/guarded_page_allocator_test.cc [1:1] - tcmalloc/heap_profiling_test.cc [1:1] tcmalloc/huge_address_map.cc [1:1] - tcmalloc/huge_address_map.h [1:1] + tcmalloc/huge_address_map.h [2:2] tcmalloc/huge_address_map_test.cc [1:1] tcmalloc/huge_allocator.cc [1:1] - tcmalloc/huge_allocator.h [1:1] + tcmalloc/huge_allocator.h [2:2] tcmalloc/huge_allocator_test.cc [1:1] tcmalloc/huge_cache.cc [1:1] - tcmalloc/huge_cache.h [1:1] + tcmalloc/huge_cache.h [2:2] tcmalloc/huge_cache_test.cc [1:1] tcmalloc/huge_page_aware_allocator.cc [1:1] - tcmalloc/huge_page_aware_allocator.h [1:1] + tcmalloc/huge_page_aware_allocator.h [2:2] tcmalloc/huge_page_aware_allocator_test.cc [1:1] - tcmalloc/huge_page_filler.h [1:1] + tcmalloc/huge_page_filler.h [2:2] tcmalloc/huge_page_filler_test.cc [1:1] - tcmalloc/huge_pages.h [1:1] - tcmalloc/huge_region.h [1:1] + tcmalloc/huge_page_subrelease.h [2:2] + tcmalloc/huge_page_subrelease_test.cc [1:1] + tcmalloc/huge_pages.h [2:2] + tcmalloc/huge_region.h [2:2] tcmalloc/huge_region_test.cc [1:1] - tcmalloc/internal/atomic_danger.h [1:1] - tcmalloc/internal/atomic_stats_counter.h [1:1] - tcmalloc/internal/bits.h [1:1] - tcmalloc/internal/bits_test.cc [1:1] - tcmalloc/internal/config.h [1:1] - tcmalloc/internal/declarations.h [1:1] + tcmalloc/internal/BUILD [1:1] + tcmalloc/internal/affinity.cc [1:1] + tcmalloc/internal/affinity.h [2:2] + tcmalloc/internal/atomic_danger.h [2:2] + tcmalloc/internal/atomic_stats_counter.h [2:2] + tcmalloc/internal/config.h [2:2] + tcmalloc/internal/declarations.h [2:2] tcmalloc/internal/environment.cc [1:1] - tcmalloc/internal/environment.h [1:1] + tcmalloc/internal/environment.h [2:2] tcmalloc/internal/environment_test.cc [1:1] - tcmalloc/internal/lifetime_predictions_test.cc [1:1] - tcmalloc/internal/lifetime_tracker_test.cc [1:1] - tcmalloc/internal/linked_list.h [1:1] + tcmalloc/internal/explicitly_constructed.h [2:2] + tcmalloc/internal/exponential_biased.h [2:2] + tcmalloc/internal/exponential_biased_test.cc [1:1] + tcmalloc/internal/linked_list.h [2:2] tcmalloc/internal/linked_list_benchmark.cc [1:1] tcmalloc/internal/linked_list_test.cc [1:1] - tcmalloc/internal/linux_syscall_support.h [1:1] + tcmalloc/internal/linux_syscall_support.h [2:2] tcmalloc/internal/logging.cc [1:1] - tcmalloc/internal/logging.h [1:1] + tcmalloc/internal/logging.h [2:2] tcmalloc/internal/logging_test.cc [1:1] tcmalloc/internal/memory_stats.cc [1:1] - tcmalloc/internal/memory_stats.h [1:1] + tcmalloc/internal/memory_stats.h [2:2] tcmalloc/internal/memory_stats_test.cc [1:1] tcmalloc/internal/mincore.cc [1:1] - tcmalloc/internal/mincore.h [1:1] + tcmalloc/internal/mincore.h [2:2] tcmalloc/internal/mincore_benchmark.cc [1:1] tcmalloc/internal/mincore_test.cc [1:1] - tcmalloc/internal/mock_span.h [1:1] - tcmalloc/internal/parameter_accessors.h [1:1] + tcmalloc/internal/mock_span.h [2:2] + tcmalloc/internal/parameter_accessors.h [2:2] tcmalloc/internal/percpu.cc [1:1] - tcmalloc/internal/percpu.h [1:1] + tcmalloc/internal/percpu.h [2:2] tcmalloc/internal/percpu_rseq_asm.S [1:1] - tcmalloc/internal/percpu_rseq_ppc.S [2:2] tcmalloc/internal/percpu_rseq_unsupported.cc [1:1] tcmalloc/internal/percpu_rseq_x86_64.S [2:2] - tcmalloc/internal/percpu_tcmalloc.h [1:1] + tcmalloc/internal/percpu_tcmalloc.h [2:2] tcmalloc/internal/percpu_tcmalloc_test.cc [1:1] tcmalloc/internal/proc_maps.cc [1:1] - tcmalloc/internal/proc_maps.h [1:1] - tcmalloc/internal/range_tracker.h [1:1] + tcmalloc/internal/proc_maps.h [2:2] + tcmalloc/internal/range_tracker.h [2:2] tcmalloc/internal/range_tracker_benchmark.cc [1:1] tcmalloc/internal/range_tracker_test.cc [1:1] - tcmalloc/internal/timeseries_tracker.h [1:1] + tcmalloc/internal/residency.cc [1:1] + tcmalloc/internal/residency.h [2:2] + tcmalloc/internal/residency_test.cc [1:1] + tcmalloc/internal/timeseries_tracker.h [2:2] tcmalloc/internal/timeseries_tracker_test.cc [1:1] tcmalloc/internal/util.cc [1:1] - tcmalloc/internal/util.h [1:1] - tcmalloc/internal_malloc_extension.h [1:1] + tcmalloc/internal/util.h [2:2] + tcmalloc/internal_malloc_extension.h [2:2] tcmalloc/legacy_size_classes.cc [1:1] - tcmalloc/libc_override.h [1:1] - tcmalloc/libc_override_gcc_and_weak.h [1:1] - tcmalloc/libc_override_glibc.h [1:1] - tcmalloc/libc_override_redefine.h [1:1] + tcmalloc/libc_override.h [2:2] tcmalloc/malloc_extension.cc [1:1] - tcmalloc/malloc_extension.h [1:1] + tcmalloc/malloc_extension.h [2:2] tcmalloc/malloc_extension_fuzz.cc [1:1] - tcmalloc/malloc_extension_system_malloc_test.cc [1:1] - tcmalloc/malloc_extension_test.cc [1:1] - tcmalloc/noruntime_size_classes.cc [1:1] + tcmalloc/metadata_object_allocator.h [2:2] tcmalloc/page_allocator.cc [1:1] - tcmalloc/page_allocator.h [1:1] + tcmalloc/page_allocator.h [2:2] tcmalloc/page_allocator_interface.cc [1:1] - tcmalloc/page_allocator_interface.h [1:1] + tcmalloc/page_allocator_interface.h [2:2] tcmalloc/page_allocator_test.cc [1:1] - tcmalloc/page_allocator_test_util.h [1:1] - tcmalloc/page_heap.cc [1:1] - tcmalloc/page_heap.h [1:1] - tcmalloc/page_heap_allocator.h [1:1] - tcmalloc/page_heap_test.cc [1:1] + tcmalloc/page_allocator_test_util.h [2:2] tcmalloc/pagemap.cc [1:1] - tcmalloc/pagemap.h [1:1] + tcmalloc/pagemap.h [3:3] tcmalloc/pagemap_test.cc [1:1] - tcmalloc/pages.h [1:1] + tcmalloc/pages.h [2:2] tcmalloc/parameters.cc [1:1] - tcmalloc/parameters.h [1:1] + tcmalloc/parameters.h [2:2] tcmalloc/peak_heap_tracker.cc [1:1] - tcmalloc/peak_heap_tracker.h [1:1] + tcmalloc/peak_heap_tracker.h [2:2] tcmalloc/profile_test.cc [1:1] - tcmalloc/realloc_test.cc [1:1] - tcmalloc/runtime_size_classes.cc [1:1] - tcmalloc/runtime_size_classes.h [1:1] - tcmalloc/runtime_size_classes_fuzz.cc [1:1] - tcmalloc/runtime_size_classes_test.cc [1:1] + tcmalloc/reuse_size_classes.cc [1:1] tcmalloc/sampler.cc [1:1] - tcmalloc/sampler.h [1:1] - tcmalloc/size_class_info.h [1:1] + tcmalloc/sampler.h [2:2] + tcmalloc/segv_handler.cc [1:1] + tcmalloc/segv_handler.h [2:2] + tcmalloc/segv_handler_test.cc [1:1] + tcmalloc/size_class_info.h [2:2] tcmalloc/size_classes.cc [1:1] tcmalloc/size_classes_test.cc [1:1] - tcmalloc/size_classes_with_runtime_size_classes_test.cc [1:1] + tcmalloc/sizemap_test.cc [1:1] tcmalloc/span.cc [1:1] - tcmalloc/span.h [1:1] + tcmalloc/span.h [2:2] tcmalloc/span_benchmark.cc [1:1] - tcmalloc/span_stats.h [1:1] + tcmalloc/span_stats.h [2:2] tcmalloc/span_test.cc [1:1] tcmalloc/stack_trace_table.cc [1:1] - tcmalloc/stack_trace_table.h [1:1] + tcmalloc/stack_trace_table.h [2:2] tcmalloc/stack_trace_table_test.cc [1:1] tcmalloc/static_vars.cc [1:1] - tcmalloc/static_vars.h [1:1] + tcmalloc/static_vars.h [2:2] tcmalloc/stats.cc [1:1] - tcmalloc/stats.h [1:1] + tcmalloc/stats.h [2:2] tcmalloc/stats_test.cc [1:1] tcmalloc/system-alloc.cc [1:1] - tcmalloc/system-alloc.h [1:1] - tcmalloc/system-alloc_test.cc [1:1] + tcmalloc/system-alloc.h [2:2] tcmalloc/tcmalloc.cc [1:1] - tcmalloc/tcmalloc.h [1:1] - tcmalloc/tcmalloc_large_test.cc [1:1] - tcmalloc/tcmalloc_policy.h [1:1] + tcmalloc/tcmalloc.h [2:2] + tcmalloc/tcmalloc_policy.h [2:2] + tcmalloc/testing/BUILD [1:1] + tcmalloc/testing/aligned_new_test.cc [1:1] + tcmalloc/testing/current_allocated_bytes_test.cc [1:1] + tcmalloc/testing/default_parameters_test.cc [1:1] + tcmalloc/testing/frag_test.cc [1:1] + tcmalloc/testing/get_stats_test.cc [1:1] + tcmalloc/testing/heap_profiling_test.cc [1:1] + tcmalloc/testing/hello_main.cc [1:1] + tcmalloc/testing/large_alloc_size_test.cc [1:1] + tcmalloc/testing/largesmall_frag_test.cc [1:1] + tcmalloc/testing/limit_test.cc [1:1] + tcmalloc/testing/malloc_extension_system_malloc_test.cc [1:1] + tcmalloc/testing/malloc_extension_test.cc [1:1] + tcmalloc/testing/markidle_test.cc [1:1] + tcmalloc/testing/memalign_test.cc [1:1] + tcmalloc/testing/memory_errors_test.cc [1:1] + tcmalloc/testing/no_deps_test.cc [1:1] + tcmalloc/testing/outofmemory_test.cc [1:1] + tcmalloc/testing/peak_heap_profiling_test.cc [1:1] + tcmalloc/testing/realloc_test.cc [1:1] + tcmalloc/testing/releasing_test.cc [1:1] + tcmalloc/testing/sample_size_class_test.cc [1:1] + tcmalloc/testing/sampler_test.cc [1:1] + tcmalloc/testing/sampling_memusage_test.cc [1:1] + tcmalloc/testing/sampling_test.cc [1:1] + tcmalloc/testing/startup_size_test.cc [1:1] + tcmalloc/testing/system-alloc_test.cc [1:1] + tcmalloc/testing/tcmalloc_benchmark.cc [1:1] + tcmalloc/testing/tcmalloc_large_test.cc [1:1] + tcmalloc/testing/tcmalloc_test.cc [1:1] + tcmalloc/testing/testutil.cc [1:1] + tcmalloc/testing/testutil.h [2:2] + tcmalloc/testing/thread_ctor_test.cc [1:1] + tcmalloc/testing/thread_ctor_test_lib.cc [1:1] + tcmalloc/testing/threadcachesize_test.cc [1:1] + tcmalloc/testing/want_disable_huge_region_more_often_test_helper.cc [1:1] + tcmalloc/testing/want_disable_tcmalloc_big_span_test_helper.cc [1:1] + tcmalloc/testing/want_hpaa_test_helper.cc [1:1] + tcmalloc/testing/want_pow2below64_size_classes_helper.cc [1:1] tcmalloc/thread_cache.cc [1:1] - tcmalloc/thread_cache.h [1:1] + tcmalloc/thread_cache.h [2:2] tcmalloc/thread_cache_test.cc [1:1] - tcmalloc/tracking.h [1:1] tcmalloc/transfer_cache.cc [1:1] - tcmalloc/transfer_cache.h [1:1] + tcmalloc/transfer_cache.h [2:2] + tcmalloc/variants.bzl [1:1] tcmalloc/want_hpaa.cc [1:1] - tcmalloc/want_hpaa_subrelease.cc [1:1] - tcmalloc/want_no_hpaa.cc [1:1] + Belongs difference: + - tcmalloc/internal/ya.make KEEP COPYRIGHT_SERVICE_LABEL 2f85f99f6e6cdec04f6948d273430658 BELONGS ya.make @@ -207,15 +255,47 @@ BELONGS ya.make Files with this license: tcmalloc/arena_test.cc [1:1] tcmalloc/central_freelist_benchmark.cc [1:1] + tcmalloc/cpu_cache_activate_test.cc [1:1] tcmalloc/internal/cache_topology.cc [1:1] - tcmalloc/internal/cache_topology.h [1:1] + tcmalloc/internal/cache_topology.h [2:2] tcmalloc/internal/cache_topology_test.cc [1:1] - tcmalloc/internal/clock.h [1:1] + tcmalloc/internal/clock.h [2:2] + tcmalloc/internal/fake_profile.h [2:2] tcmalloc/internal/logging_test_helper.cc [1:1] tcmalloc/internal/numa.cc [1:1] - tcmalloc/internal/numa.h [1:1] + tcmalloc/internal/numa.h [2:2] tcmalloc/internal/numa_test.cc [1:1] + tcmalloc/internal/profile_builder.cc [1:1] + tcmalloc/internal/profile_builder.h [2:2] + tcmalloc/internal/profile_builder_test.cc [1:1] + tcmalloc/internal/sampled_allocation.h [2:2] + tcmalloc/internal/sampled_allocation_test.cc [1:1] + tcmalloc/mock_static_forwarder.h [2:2] + tcmalloc/profile_marshaler.cc [1:1] + tcmalloc/profile_marshaler.h [2:2] + tcmalloc/profile_marshaler_test.cc [1:1] + tcmalloc/testing/numa_locality_test.cc [1:1] + tcmalloc/testing/profile_test.cc [1:1] + tcmalloc/testing/reclaim_test.cc [1:1] + tcmalloc/testing/test_allocator_harness.h [2:2] tcmalloc/want_numa_aware.cc [1:1] + Belongs difference: + - tcmalloc/internal/ya.make + +KEEP COPYRIGHT_SERVICE_LABEL 3fb410b721d46624abdaeb2473ffa5d6 +BELONGS ya.make + License text: + // Copyright 2018 The Abseil Authors. + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + tcmalloc/internal/sampled_allocation_recorder.h [2:2] + tcmalloc/internal/sampled_allocation_recorder_test.cc [1:1] + Belongs difference: + + ya.make + - tcmalloc/internal/ya.make KEEP COPYRIGHT_SERVICE_LABEL 62f2df7d02ddf07de59d1a4e25e663aa BELONGS ya.make @@ -226,20 +306,107 @@ BELONGS ya.make Score : 100.00 Match type : COPYRIGHT Files with this license: - tcmalloc/internal/lifetime_predictions.h [1:1] - tcmalloc/internal/lifetime_tracker.h [1:1] - tcmalloc/internal/optimization.h [1:1] + tcmalloc/central_freelist_fuzz.cc [1:1] + tcmalloc/internal/config_test.cc [1:1] + tcmalloc/internal/optimization.h [2:2] tcmalloc/internal/percpu_rseq_aarch64.S [2:2] tcmalloc/mock_central_freelist.cc [1:1] - tcmalloc/mock_central_freelist.h [1:1] + tcmalloc/mock_central_freelist.h [2:2] tcmalloc/mock_transfer_cache.cc [1:1] - tcmalloc/mock_transfer_cache.h [1:1] + tcmalloc/mock_transfer_cache.h [2:2] + tcmalloc/new_extension.h [2:2] + tcmalloc/new_extension_test.cc [1:1] + tcmalloc/testing/benchmark_main.cc [1:1] + tcmalloc/testing/thread_manager.h [2:2] tcmalloc/transfer_cache_benchmark.cc [1:1] tcmalloc/transfer_cache_fuzz.cc [1:1] - tcmalloc/transfer_cache_internals.h [1:1] - tcmalloc/transfer_cache_stats.h [1:1] + tcmalloc/transfer_cache_internals.h [2:2] + tcmalloc/transfer_cache_stats.h [2:2] tcmalloc/transfer_cache_test.cc [1:1] - tcmalloc/want_legacy_spans.cc [1:1] + Belongs difference: + - tcmalloc/internal/ya.make + +KEEP COPYRIGHT_SERVICE_LABEL 6ce13c4573adc84fa643b80888b20c2f +BELONGS ya.make + License text: + // Copyright 2023 The TCMalloc Authors + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + tcmalloc/guarded_allocations.h [2:2] + tcmalloc/internal/allocation_guard.cc [1:1] + tcmalloc/internal/allocation_guard.h [2:2] + tcmalloc/internal/allocation_guard_test.cc [1:1] + tcmalloc/internal/cpu_utils.h [2:2] + tcmalloc/internal/pageflags.cc [1:1] + tcmalloc/internal/pageflags.h [2:2] + tcmalloc/internal/pageflags_test.cc [1:1] + tcmalloc/internal/sysinfo.cc [1:1] + tcmalloc/internal/sysinfo.h [2:2] + tcmalloc/internal/sysinfo_test.cc [1:1] + tcmalloc/metadata_allocator.h [2:2] + tcmalloc/mock_huge_page_static_forwarder.cc [1:1] + tcmalloc/mock_huge_page_static_forwarder.h [2:2] + tcmalloc/mock_metadata_allocator.h [2:2] + tcmalloc/mock_virtual_allocator.h [2:2] + tcmalloc/pages_test.cc [1:1] + tcmalloc/testing/background_test.cc [1:1] + tcmalloc/testing/parallel_test.cc [1:1] + tcmalloc/testing/profile_drop_frames_test.cc [1:1] + tcmalloc/testing/variants_test.cc [1:1] + Belongs difference: + - tcmalloc/internal/ya.make + +KEEP COPYRIGHT_SERVICE_LABEL 8f32d6982020583277a589c31d7b9283 +BELONGS ya.make + License text: + // Copyright 2022 The TCMalloc Authors + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + tcmalloc/.github/workflows/ci.yml [1:1] + tcmalloc/allocation_sample.cc [1:1] + tcmalloc/allocation_sample.h [2:2] + tcmalloc/allocation_sample_test.cc [1:1] + tcmalloc/allocation_sampling.cc [1:1] + tcmalloc/allocation_sampling.h [2:2] + tcmalloc/deallocation_profiler.cc [1:1] + tcmalloc/deallocation_profiler.h [2:2] + tcmalloc/hinted_tracker_lists.h [2:2] + tcmalloc/huge_page_aware_allocator_fuzz.cc [1:1] + tcmalloc/huge_page_filler_fuzz.cc [1:1] + tcmalloc/huge_region_fuzz.cc [1:1] + tcmalloc/internal/affinity_test.cc [1:1] + tcmalloc/internal/overflow.h [2:2] + tcmalloc/internal/page_size.cc [1:1] + tcmalloc/internal/page_size.h [2:2] + tcmalloc/internal/prefetch.h [2:2] + tcmalloc/internal/prefetch_test.cc [1:1] + tcmalloc/internal/profile_builder_fuzz.cc [1:1] + tcmalloc/internal/stacktrace_filter.h [2:2] + tcmalloc/internal/stacktrace_filter_test.cc [1:1] + tcmalloc/internal/sysinfo_fuzz.cc [1:1] + tcmalloc/internal_malloc_tracing_extension.h [2:2] + tcmalloc/malloc_tracing_extension.cc [1:1] + tcmalloc/malloc_tracing_extension.h [2:2] + tcmalloc/sizemap.cc [1:1] + tcmalloc/sizemap.h [2:2] + tcmalloc/sizemap_fuzz.cc [1:1] + tcmalloc/span_fuzz.cc [1:1] + tcmalloc/testing/deallocation_profiler_test.cc [1:1] + tcmalloc/testing/malloc_tracing_extension_test.cc [1:1] + tcmalloc/testing/realized_fragmentation_test.cc [1:1] + tcmalloc/want_disable_dynamic_slabs.cc [1:1] + tcmalloc/want_disable_huge_region_more_often.cc [1:1] + tcmalloc/want_disable_tcmalloc_big_span.cc [1:1] + tcmalloc/want_legacy_size_classes.cc [1:1] + tcmalloc/want_legacy_size_classes_test.cc [1:1] + Belongs difference: + - tcmalloc/internal/ya.make SKIP COPYRIGHT_SERVICE_LABEL b7c6499c855f04bbe7161fc4de3a41d6 BELONGS ya.make @@ -252,4 +419,29 @@ BELONGS ya.make Score : 100.00 Match type : COPYRIGHT Files with this license: - tcmalloc/huge_region_test.cc [433:435] + tcmalloc/huge_region_test.cc [582:584] + tcmalloc/huge_region_test.cc [614:616] + +KEEP COPYRIGHT_SERVICE_LABEL d4c3b5c5d59dc3fc89f75c05560b08bd +BELONGS ya.make + License text: + // Copyright 2024 The TCMalloc Authors + Scancode info: + Original SPDX id: COPYRIGHT_SERVICE_LABEL + Score : 100.00 + Match type : COPYRIGHT + Files with this license: + tcmalloc/internal/memory_tag.cc [1:1] + tcmalloc/internal/memory_tag.h [2:2] + tcmalloc/internal/mismatched_delete_state.h [2:2] + tcmalloc/internal/percpu_early_test.cc [1:1] + tcmalloc/internal/percpu_test.cc [1:1] + tcmalloc/internal/profile_builder_no_tcmalloc_test.cc [1:1] + tcmalloc/selsan/BUILD [1:1] + tcmalloc/selsan/report_test.cc [1:1] + tcmalloc/selsan/selsan.cc [1:1] + tcmalloc/selsan/selsan.h [2:2] + tcmalloc/selsan/shadow_test.cc [1:1] + tcmalloc/testing/disable_numa_test.cc [1:1] + Belongs difference: + - tcmalloc/internal/ya.make diff --git a/contrib/libs/tcmalloc/.yandex_meta/devtools.licenses.report b/contrib/libs/tcmalloc/.yandex_meta/devtools.licenses.report index 29c5c149ce10..2e8f17be06de 100644 --- a/contrib/libs/tcmalloc/.yandex_meta/devtools.licenses.report +++ b/contrib/libs/tcmalloc/.yandex_meta/devtools.licenses.report @@ -38,184 +38,301 @@ BELONGS ya.make Match type : NOTICE Links : http://www.apache.org/licenses/, http://www.apache.org/licenses/LICENSE-2.0, https://spdx.org/licenses/Apache-2.0 Files with this license: + tcmalloc/allocation_sample.cc [3:13] + tcmalloc/allocation_sample.h [4:14] + tcmalloc/allocation_sample_test.cc [3:13] + tcmalloc/allocation_sampling.cc [3:13] + tcmalloc/allocation_sampling.h [4:14] tcmalloc/arena.cc [3:13] - tcmalloc/arena.h [3:13] + tcmalloc/arena.h [4:14] tcmalloc/arena_test.cc [3:13] tcmalloc/background.cc [3:13] tcmalloc/central_freelist.cc [3:13] - tcmalloc/central_freelist.h [3:13] + tcmalloc/central_freelist.h [4:14] tcmalloc/central_freelist_benchmark.cc [3:13] + tcmalloc/central_freelist_fuzz.cc [3:13] tcmalloc/central_freelist_test.cc [3:13] tcmalloc/common.cc [3:13] - tcmalloc/common.h [3:13] + tcmalloc/common.h [4:14] tcmalloc/cpu_cache.cc [3:13] - tcmalloc/cpu_cache.h [3:13] + tcmalloc/cpu_cache.h [4:14] + tcmalloc/cpu_cache_activate_test.cc [3:13] tcmalloc/cpu_cache_test.cc [3:13] + tcmalloc/deallocation_profiler.cc [3:13] + tcmalloc/deallocation_profiler.h [4:14] tcmalloc/experiment.cc [3:13] - tcmalloc/experiment.h [3:13] - tcmalloc/experiment_config.h [3:13] + tcmalloc/experiment.h [4:14] + tcmalloc/experiment_config.h [4:14] tcmalloc/experiment_config_test.cc [3:13] tcmalloc/experiment_fuzz.cc [3:13] - tcmalloc/experimental_56_size_class.cc [3:13] - tcmalloc/experimental_pow2_below64_size_class.cc [3:13] tcmalloc/experimental_pow2_size_class.cc [3:13] + tcmalloc/global_stats.cc [3:13] + tcmalloc/global_stats.h [4:14] + tcmalloc/guarded_allocations.h [4:14] tcmalloc/guarded_page_allocator.cc [3:13] - tcmalloc/guarded_page_allocator.h [3:13] + tcmalloc/guarded_page_allocator.h [4:14] tcmalloc/guarded_page_allocator_benchmark.cc [3:13] + tcmalloc/guarded_page_allocator_profile_test.cc [3:13] tcmalloc/guarded_page_allocator_test.cc [3:13] - tcmalloc/heap_profiling_test.cc [3:13] + tcmalloc/hinted_tracker_lists.h [4:14] tcmalloc/huge_address_map.cc [3:13] - tcmalloc/huge_address_map.h [3:13] + tcmalloc/huge_address_map.h [4:14] tcmalloc/huge_address_map_test.cc [3:13] tcmalloc/huge_allocator.cc [3:13] - tcmalloc/huge_allocator.h [3:13] + tcmalloc/huge_allocator.h [4:14] tcmalloc/huge_allocator_test.cc [3:13] tcmalloc/huge_cache.cc [3:13] - tcmalloc/huge_cache.h [3:13] + tcmalloc/huge_cache.h [4:14] tcmalloc/huge_cache_test.cc [3:13] tcmalloc/huge_page_aware_allocator.cc [3:13] - tcmalloc/huge_page_aware_allocator.h [3:13] + tcmalloc/huge_page_aware_allocator.h [4:14] + tcmalloc/huge_page_aware_allocator_fuzz.cc [3:13] tcmalloc/huge_page_aware_allocator_test.cc [3:13] - tcmalloc/huge_page_filler.h [3:13] + tcmalloc/huge_page_filler.h [4:14] + tcmalloc/huge_page_filler_fuzz.cc [3:13] tcmalloc/huge_page_filler_test.cc [3:13] - tcmalloc/huge_pages.h [3:13] - tcmalloc/huge_region.h [3:13] + tcmalloc/huge_page_subrelease.h [4:14] + tcmalloc/huge_page_subrelease_test.cc [3:13] + tcmalloc/huge_pages.h [4:14] + tcmalloc/huge_region.h [4:14] + tcmalloc/huge_region_fuzz.cc [3:13] tcmalloc/huge_region_test.cc [3:13] - tcmalloc/internal/atomic_danger.h [3:13] - tcmalloc/internal/atomic_stats_counter.h [3:13] - tcmalloc/internal/bits.h [3:13] - tcmalloc/internal/bits_test.cc [3:13] + tcmalloc/internal/affinity.cc [3:13] + tcmalloc/internal/affinity.h [4:14] + tcmalloc/internal/affinity_test.cc [3:13] + tcmalloc/internal/allocation_guard.cc [3:13] + tcmalloc/internal/allocation_guard.h [4:14] + tcmalloc/internal/allocation_guard_test.cc [3:13] + tcmalloc/internal/atomic_danger.h [4:14] + tcmalloc/internal/atomic_stats_counter.h [4:14] tcmalloc/internal/cache_topology.cc [3:13] - tcmalloc/internal/cache_topology.h [3:13] + tcmalloc/internal/cache_topology.h [4:14] tcmalloc/internal/cache_topology_test.cc [3:13] - tcmalloc/internal/clock.h [3:13] - tcmalloc/internal/config.h [3:13] - tcmalloc/internal/declarations.h [3:13] + tcmalloc/internal/clock.h [4:14] + tcmalloc/internal/config.h [4:14] + tcmalloc/internal/config_test.cc [3:13] + tcmalloc/internal/cpu_utils.h [4:14] + tcmalloc/internal/declarations.h [4:14] tcmalloc/internal/environment.cc [3:13] - tcmalloc/internal/environment.h [3:13] + tcmalloc/internal/environment.h [4:14] tcmalloc/internal/environment_test.cc [3:13] - tcmalloc/internal/lifetime_predictions.h [3:13] - tcmalloc/internal/lifetime_predictions_test.cc [3:13] - tcmalloc/internal/lifetime_tracker.h [3:13] - tcmalloc/internal/lifetime_tracker_test.cc [3:13] - tcmalloc/internal/linked_list.h [3:13] + tcmalloc/internal/explicitly_constructed.h [4:14] + tcmalloc/internal/exponential_biased.h [4:14] + tcmalloc/internal/exponential_biased_test.cc [3:13] + tcmalloc/internal/fake_profile.h [4:14] + tcmalloc/internal/linked_list.h [4:14] tcmalloc/internal/linked_list_benchmark.cc [3:13] tcmalloc/internal/linked_list_test.cc [3:13] - tcmalloc/internal/linux_syscall_support.h [3:13] + tcmalloc/internal/linux_syscall_support.h [4:14] tcmalloc/internal/logging.cc [3:13] - tcmalloc/internal/logging.h [3:13] + tcmalloc/internal/logging.h [4:14] tcmalloc/internal/logging_test.cc [3:13] tcmalloc/internal/logging_test_helper.cc [3:13] tcmalloc/internal/memory_stats.cc [3:13] - tcmalloc/internal/memory_stats.h [3:13] + tcmalloc/internal/memory_stats.h [4:14] tcmalloc/internal/memory_stats_test.cc [3:13] + tcmalloc/internal/memory_tag.cc [3:13] + tcmalloc/internal/memory_tag.h [4:14] tcmalloc/internal/mincore.cc [3:13] - tcmalloc/internal/mincore.h [3:13] + tcmalloc/internal/mincore.h [4:14] tcmalloc/internal/mincore_benchmark.cc [3:13] tcmalloc/internal/mincore_test.cc [3:13] - tcmalloc/internal/mock_span.h [3:13] + tcmalloc/internal/mismatched_delete_state.h [4:14] + tcmalloc/internal/mock_span.h [4:14] tcmalloc/internal/numa.cc [3:13] - tcmalloc/internal/numa.h [3:13] + tcmalloc/internal/numa.h [4:14] tcmalloc/internal/numa_test.cc [3:13] - tcmalloc/internal/optimization.h [3:13] - tcmalloc/internal/parameter_accessors.h [3:13] + tcmalloc/internal/optimization.h [4:14] + tcmalloc/internal/overflow.h [4:14] + tcmalloc/internal/page_size.cc [3:13] + tcmalloc/internal/page_size.h [4:14] + tcmalloc/internal/pageflags.cc [3:13] + tcmalloc/internal/pageflags.h [4:14] + tcmalloc/internal/pageflags_test.cc [3:13] + tcmalloc/internal/parameter_accessors.h [4:14] tcmalloc/internal/percpu.cc [3:13] - tcmalloc/internal/percpu.h [3:13] + tcmalloc/internal/percpu.h [4:14] + tcmalloc/internal/percpu_early_test.cc [3:13] tcmalloc/internal/percpu_rseq_asm.S [3:13] tcmalloc/internal/percpu_rseq_unsupported.cc [3:13] - tcmalloc/internal/percpu_tcmalloc.h [3:13] + tcmalloc/internal/percpu_tcmalloc.h [4:14] tcmalloc/internal/percpu_tcmalloc_test.cc [3:13] + tcmalloc/internal/percpu_test.cc [3:13] + tcmalloc/internal/prefetch.h [4:14] + tcmalloc/internal/prefetch_test.cc [3:13] tcmalloc/internal/proc_maps.cc [3:13] - tcmalloc/internal/proc_maps.h [3:13] - tcmalloc/internal/range_tracker.h [3:13] + tcmalloc/internal/proc_maps.h [4:14] + tcmalloc/internal/profile_builder.cc [3:13] + tcmalloc/internal/profile_builder.h [4:14] + tcmalloc/internal/profile_builder_fuzz.cc [3:13] + tcmalloc/internal/profile_builder_no_tcmalloc_test.cc [3:13] + tcmalloc/internal/profile_builder_test.cc [3:13] + tcmalloc/internal/range_tracker.h [4:14] tcmalloc/internal/range_tracker_benchmark.cc [3:13] tcmalloc/internal/range_tracker_test.cc [3:13] - tcmalloc/internal/timeseries_tracker.h [3:13] + tcmalloc/internal/residency.cc [3:13] + tcmalloc/internal/residency.h [4:14] + tcmalloc/internal/residency_test.cc [3:13] + tcmalloc/internal/sampled_allocation.h [4:14] + tcmalloc/internal/sampled_allocation_test.cc [3:13] + tcmalloc/internal/stacktrace_filter.h [4:14] + tcmalloc/internal/stacktrace_filter_test.cc [3:13] + tcmalloc/internal/sysinfo.cc [3:13] + tcmalloc/internal/sysinfo.h [4:14] + tcmalloc/internal/sysinfo_fuzz.cc [3:13] + tcmalloc/internal/sysinfo_test.cc [3:13] + tcmalloc/internal/timeseries_tracker.h [4:14] tcmalloc/internal/timeseries_tracker_test.cc [3:13] tcmalloc/internal/util.cc [3:13] - tcmalloc/internal/util.h [3:13] - tcmalloc/internal_malloc_extension.h [3:13] + tcmalloc/internal/util.h [4:14] + tcmalloc/internal_malloc_extension.h [4:14] + tcmalloc/internal_malloc_tracing_extension.h [4:14] tcmalloc/legacy_size_classes.cc [3:13] - tcmalloc/libc_override.h [3:13] - tcmalloc/libc_override_gcc_and_weak.h [3:13] - tcmalloc/libc_override_glibc.h [3:13] - tcmalloc/libc_override_redefine.h [3:13] + tcmalloc/libc_override.h [4:14] tcmalloc/malloc_extension.cc [3:13] - tcmalloc/malloc_extension.h [3:13] + tcmalloc/malloc_extension.h [4:14] tcmalloc/malloc_extension_fuzz.cc [3:13] - tcmalloc/malloc_extension_system_malloc_test.cc [3:13] - tcmalloc/malloc_extension_test.cc [3:13] + tcmalloc/malloc_tracing_extension.cc [3:13] + tcmalloc/malloc_tracing_extension.h [4:14] + tcmalloc/metadata_allocator.h [4:14] + tcmalloc/metadata_object_allocator.h [4:14] tcmalloc/mock_central_freelist.cc [3:13] - tcmalloc/mock_central_freelist.h [3:13] + tcmalloc/mock_central_freelist.h [4:14] + tcmalloc/mock_huge_page_static_forwarder.cc [3:13] + tcmalloc/mock_huge_page_static_forwarder.h [4:14] + tcmalloc/mock_metadata_allocator.h [4:14] + tcmalloc/mock_static_forwarder.h [4:14] tcmalloc/mock_transfer_cache.cc [3:13] - tcmalloc/mock_transfer_cache.h [3:13] - tcmalloc/noruntime_size_classes.cc [3:13] + tcmalloc/mock_transfer_cache.h [4:14] + tcmalloc/mock_virtual_allocator.h [4:14] + tcmalloc/new_extension.h [4:14] + tcmalloc/new_extension_test.cc [3:13] tcmalloc/page_allocator.cc [3:13] - tcmalloc/page_allocator.h [3:13] + tcmalloc/page_allocator.h [4:14] tcmalloc/page_allocator_interface.cc [3:13] - tcmalloc/page_allocator_interface.h [3:13] + tcmalloc/page_allocator_interface.h [4:14] tcmalloc/page_allocator_test.cc [3:13] - tcmalloc/page_allocator_test_util.h [3:13] - tcmalloc/page_heap.cc [3:13] - tcmalloc/page_heap.h [3:13] - tcmalloc/page_heap_allocator.h [3:13] - tcmalloc/page_heap_test.cc [3:13] + tcmalloc/page_allocator_test_util.h [4:14] tcmalloc/pagemap.cc [3:13] - tcmalloc/pagemap.h [3:13] + tcmalloc/pagemap.h [5:15] tcmalloc/pagemap_test.cc [3:13] - tcmalloc/pages.h [3:13] + tcmalloc/pages.h [4:14] + tcmalloc/pages_test.cc [3:13] tcmalloc/parameters.cc [3:13] - tcmalloc/parameters.h [3:13] + tcmalloc/parameters.h [4:14] tcmalloc/peak_heap_tracker.cc [3:13] - tcmalloc/peak_heap_tracker.h [3:13] + tcmalloc/peak_heap_tracker.h [4:14] + tcmalloc/profile_marshaler.cc [3:13] + tcmalloc/profile_marshaler.h [4:14] + tcmalloc/profile_marshaler_test.cc [3:13] tcmalloc/profile_test.cc [3:13] - tcmalloc/realloc_test.cc [3:13] - tcmalloc/runtime_size_classes.cc [3:13] - tcmalloc/runtime_size_classes.h [3:13] - tcmalloc/runtime_size_classes_fuzz.cc [3:13] - tcmalloc/runtime_size_classes_test.cc [3:13] + tcmalloc/reuse_size_classes.cc [3:13] tcmalloc/sampler.cc [3:13] - tcmalloc/sampler.h [3:13] - tcmalloc/size_class_info.h [3:13] + tcmalloc/sampler.h [4:14] + tcmalloc/segv_handler.cc [3:13] + tcmalloc/segv_handler.h [4:14] + tcmalloc/segv_handler_test.cc [3:13] + tcmalloc/selsan/report_test.cc [3:13] + tcmalloc/selsan/selsan.cc [3:13] + tcmalloc/selsan/selsan.h [4:14] + tcmalloc/selsan/shadow_test.cc [3:13] + tcmalloc/size_class_info.h [4:14] tcmalloc/size_classes.cc [3:13] tcmalloc/size_classes_test.cc [3:13] - tcmalloc/size_classes_with_runtime_size_classes_test.cc [3:13] + tcmalloc/sizemap.cc [3:13] + tcmalloc/sizemap.h [4:14] + tcmalloc/sizemap_fuzz.cc [3:13] + tcmalloc/sizemap_test.cc [3:13] tcmalloc/span.cc [3:13] - tcmalloc/span.h [3:13] + tcmalloc/span.h [4:14] tcmalloc/span_benchmark.cc [3:13] - tcmalloc/span_stats.h [3:13] + tcmalloc/span_fuzz.cc [3:13] + tcmalloc/span_stats.h [4:14] tcmalloc/span_test.cc [3:13] tcmalloc/stack_trace_table.cc [3:13] - tcmalloc/stack_trace_table.h [3:13] + tcmalloc/stack_trace_table.h [4:14] tcmalloc/stack_trace_table_test.cc [3:13] tcmalloc/static_vars.cc [3:13] - tcmalloc/static_vars.h [3:13] + tcmalloc/static_vars.h [4:14] tcmalloc/stats.cc [3:13] - tcmalloc/stats.h [3:13] + tcmalloc/stats.h [4:14] tcmalloc/stats_test.cc [3:13] tcmalloc/system-alloc.cc [3:13] - tcmalloc/system-alloc.h [3:13] - tcmalloc/system-alloc_test.cc [3:13] + tcmalloc/system-alloc.h [4:14] tcmalloc/tcmalloc.cc [3:13] - tcmalloc/tcmalloc.h [3:13] - tcmalloc/tcmalloc_large_test.cc [3:13] - tcmalloc/tcmalloc_policy.h [3:13] + tcmalloc/tcmalloc.h [4:14] + tcmalloc/tcmalloc_policy.h [4:14] + tcmalloc/testing/aligned_new_test.cc [3:13] + tcmalloc/testing/background_test.cc [3:13] + tcmalloc/testing/benchmark_main.cc [3:13] + tcmalloc/testing/current_allocated_bytes_test.cc [3:13] + tcmalloc/testing/deallocation_profiler_test.cc [3:13] + tcmalloc/testing/default_parameters_test.cc [3:13] + tcmalloc/testing/disable_numa_test.cc [3:13] + tcmalloc/testing/frag_test.cc [3:13] + tcmalloc/testing/get_stats_test.cc [3:13] + tcmalloc/testing/heap_profiling_test.cc [3:13] + tcmalloc/testing/hello_main.cc [3:13] + tcmalloc/testing/large_alloc_size_test.cc [3:13] + tcmalloc/testing/largesmall_frag_test.cc [3:13] + tcmalloc/testing/limit_test.cc [3:13] + tcmalloc/testing/malloc_extension_system_malloc_test.cc [3:13] + tcmalloc/testing/malloc_extension_test.cc [3:13] + tcmalloc/testing/malloc_tracing_extension_test.cc [3:13] + tcmalloc/testing/markidle_test.cc [3:13] + tcmalloc/testing/memalign_test.cc [3:13] + tcmalloc/testing/memory_errors_test.cc [3:13] + tcmalloc/testing/no_deps_test.cc [3:13] + tcmalloc/testing/numa_locality_test.cc [3:13] + tcmalloc/testing/outofmemory_test.cc [3:13] + tcmalloc/testing/parallel_test.cc [3:13] + tcmalloc/testing/peak_heap_profiling_test.cc [3:13] + tcmalloc/testing/profile_drop_frames_test.cc [3:13] + tcmalloc/testing/profile_test.cc [3:13] + tcmalloc/testing/realized_fragmentation_test.cc [3:13] + tcmalloc/testing/realloc_test.cc [3:13] + tcmalloc/testing/reclaim_test.cc [3:13] + tcmalloc/testing/releasing_test.cc [3:13] + tcmalloc/testing/sample_size_class_test.cc [3:13] + tcmalloc/testing/sampler_test.cc [3:13] + tcmalloc/testing/sampling_memusage_test.cc [3:13] + tcmalloc/testing/sampling_test.cc [3:13] + tcmalloc/testing/startup_size_test.cc [3:13] + tcmalloc/testing/system-alloc_test.cc [3:13] + tcmalloc/testing/tcmalloc_benchmark.cc [3:13] + tcmalloc/testing/tcmalloc_large_test.cc [3:13] + tcmalloc/testing/tcmalloc_test.cc [3:13] + tcmalloc/testing/test_allocator_harness.h [4:14] + tcmalloc/testing/testutil.cc [3:13] + tcmalloc/testing/testutil.h [4:14] + tcmalloc/testing/thread_ctor_test.cc [3:13] + tcmalloc/testing/thread_ctor_test_lib.cc [3:13] + tcmalloc/testing/thread_manager.h [4:14] + tcmalloc/testing/threadcachesize_test.cc [3:13] + tcmalloc/testing/variants_test.cc [3:13] + tcmalloc/testing/want_disable_huge_region_more_often_test_helper.cc [3:13] + tcmalloc/testing/want_disable_tcmalloc_big_span_test_helper.cc [3:13] + tcmalloc/testing/want_hpaa_test_helper.cc [3:13] + tcmalloc/testing/want_pow2below64_size_classes_helper.cc [3:13] tcmalloc/thread_cache.cc [3:13] - tcmalloc/thread_cache.h [3:13] + tcmalloc/thread_cache.h [4:14] tcmalloc/thread_cache_test.cc [3:13] - tcmalloc/tracking.h [3:13] tcmalloc/transfer_cache.cc [3:13] - tcmalloc/transfer_cache.h [3:13] + tcmalloc/transfer_cache.h [4:14] tcmalloc/transfer_cache_benchmark.cc [3:13] tcmalloc/transfer_cache_fuzz.cc [3:13] - tcmalloc/transfer_cache_internals.h [3:13] - tcmalloc/transfer_cache_stats.h [3:13] + tcmalloc/transfer_cache_internals.h [4:14] + tcmalloc/transfer_cache_stats.h [4:14] tcmalloc/transfer_cache_test.cc [3:13] + tcmalloc/want_disable_dynamic_slabs.cc [3:13] + tcmalloc/want_disable_huge_region_more_often.cc [3:13] + tcmalloc/want_disable_tcmalloc_big_span.cc [3:13] tcmalloc/want_hpaa.cc [3:13] - tcmalloc/want_hpaa_subrelease.cc [3:13] - tcmalloc/want_legacy_spans.cc [3:13] - tcmalloc/want_no_hpaa.cc [3:13] + tcmalloc/want_legacy_size_classes.cc [3:13] + tcmalloc/want_legacy_size_classes_test.cc [3:13] tcmalloc/want_numa_aware.cc [3:13] + Belongs difference: + - tcmalloc/internal/ya.make KEEP Apache-2.0 24be4e5673a9c71cdba851c53ed9677b BELONGS ya.make @@ -227,6 +344,37 @@ BELONGS ya.make Links : http://www.apache.org/licenses/, http://www.apache.org/licenses/LICENSE-2.0, https://spdx.org/licenses/Apache-2.0 Files with this license: tcmalloc/internal/percpu_rseq_aarch64.S [4:14] + Belongs difference: + + ya.make + - tcmalloc/internal/ya.make + +KEEP Apache-2.0 2695f523f6550abd8506fe00ecd5fd73 +BELONGS ya.make + Note: matched license text is too long. Read it in the source files. + Scancode info: + Original SPDX id: Apache-2.0 + Score : 100.00 + Match type : NOTICE + Links : http://www.apache.org/licenses/, http://www.apache.org/licenses/LICENSE-2.0, https://spdx.org/licenses/Apache-2.0 + Files with this license: + tcmalloc/internal/profile.proto [3:13] + Belongs difference: + + ya.make + - tcmalloc/internal/ya.make + +SKIP LicenseRef-scancode-unknown-license-reference 2b7ce4d6f90a7e895f2cf83f68079656 +BELONGS ya.make +FILE_INCLUDE LICENSE found in files: README.md at line 43 + License text: + The TCMalloc library is licensed under the terms of the Apache license. See + LICENSE for more information. + Scancode info: + Original SPDX id: LicenseRef-scancode-unknown-license-reference + Score : 100.00 + Match type : REFERENCE + Links : https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/unknown-license-reference.LICENSE + Files with this license: + README.md [42:43] KEEP Apache-2.0 34ef0c6d1296bad9c0b8ea4447611e19 BELONGS ya.make @@ -237,21 +385,42 @@ BELONGS ya.make Match type : NOTICE Links : http://www.apache.org/licenses/, http://www.apache.org/licenses/LICENSE-2.0, https://spdx.org/licenses/Apache-2.0 Files with this license: + tcmalloc/.github/workflows/ci.yml [3:13] tcmalloc/BUILD [3:13] + tcmalloc/copts.bzl [3:13] + tcmalloc/internal/BUILD [3:13] + tcmalloc/selsan/BUILD [3:13] + tcmalloc/testing/BUILD [3:13] + tcmalloc/variants.bzl [3:13] + Belongs difference: + - tcmalloc/internal/ya.make + +KEEP Apache-2.0 3ea5060c4f08f5769674fbf0c0fb3992 +BELONGS ya.make + Note: matched license text is too long. Read it in the source files. + Scancode info: + Original SPDX id: Apache-2.0 + Score : 100.00 + Match type : NOTICE + Links : http://www.apache.org/licenses/, http://www.apache.org/licenses/LICENSE-2.0, https://spdx.org/licenses/Apache-2.0 + Files with this license: + tcmalloc/internal/sampled_allocation_recorder.h [4:14] + tcmalloc/internal/sampled_allocation_recorder_test.cc [3:13] + Belongs difference: + + ya.make + - tcmalloc/internal/ya.make -KEEP Apache-2.0 566444825cbcc83578050639168bd08f +KEEP Apache-2.0 546d5c2ec03ff489fdf645b478946134 BELONGS ya.make -FILE_INCLUDE LICENSE found in files: README.md at line 42 License text: - The TCMalloc library is licensed under the terms of the Apache - license. See LICENSE for more information. + The TCMalloc library is licensed under the terms of the Apache license. See Scancode info: Original SPDX id: Apache-2.0 Score : 90.00 Match type : NOTICE Links : http://www.apache.org/licenses/, http://www.apache.org/licenses/LICENSE-2.0, https://spdx.org/licenses/Apache-2.0 Files with this license: - README.md [41:42] + README.md [42:42] SKIP LicenseRef-scancode-generic-cla 5d780ffa423067f23c6a123ae33e7c18 BELONGS ya.make @@ -274,8 +443,10 @@ BELONGS ya.make Match type : NOTICE Links : http://www.apache.org/licenses/, http://www.apache.org/licenses/LICENSE-2.0, https://spdx.org/licenses/Apache-2.0 Files with this license: - tcmalloc/internal/percpu_rseq_ppc.S [4:14] tcmalloc/internal/percpu_rseq_x86_64.S [4:14] + Belongs difference: + + ya.make + - tcmalloc/internal/ya.make SKIP LicenseRef-scancode-generic-cla 979d7de2e3ff119ee2c22c7efbec766d BELONGS ya.make @@ -301,31 +472,17 @@ BELONGS ya.make Files with this license: LICENSE [2:202] -SKIP LicenseRef-scancode-other-permissive cd348406a46a4c91e9edaa5be5e9c074 -BELONGS ya.make -FILE_INCLUDE LICENSE found in files: README.md at line 42 - # File LICENSES allready included - License text: - license. See LICENSE for more information. - Scancode info: - Original SPDX id: LicenseRef-scancode-unknown-license-reference - Score : 100.00 - Match type : REFERENCE - Links : https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/unknown-license-reference.LICENSE - Files with this license: - README.md [42:42] - -KEEP Apache-2.0 e0f9a998414a9ae203fd34f4452d4dbc +SKIP MIT f360ff14698610d13d4c35791f051cde BELONGS ya.make -FILE_INCLUDE LICENSE found in files: README.md at line 42 +FILE_INCLUDE LICENSE found in files: README.md at line 43 License text: \## License - The TCMalloc library is licensed under the terms of the Apache - license. See LICENSE for more information. + The TCMalloc library is licensed under the terms of the Apache license. See + LICENSE for more information. Scancode info: Original SPDX id: MIT Score : 52.63 Match type : NOTICE Links : http://opensource.org/licenses/mit-license.php, https://spdx.org/licenses/MIT Files with this license: - README.md [39:42] + README.md [40:43] diff --git a/contrib/libs/tcmalloc/.yandex_meta/licenses.list.txt b/contrib/libs/tcmalloc/.yandex_meta/licenses.list.txt index 7eb94bee02d9..9a38173d348c 100644 --- a/contrib/libs/tcmalloc/.yandex_meta/licenses.list.txt +++ b/contrib/libs/tcmalloc/.yandex_meta/licenses.list.txt @@ -244,10 +244,31 @@ ====================Apache-2.0==================== -## License +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. -The TCMalloc library is licensed under the terms of the Apache -license. See LICENSE for more information. + +====================Apache-2.0==================== +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. ====================Apache-2.0==================== @@ -265,222 +286,36 @@ license. See LICENSE for more information. ====================Apache-2.0==================== -The TCMalloc library is licensed under the terms of the Apache -license. See LICENSE for more information. +The TCMalloc library is licensed under the terms of the Apache license. See ====================COPYRIGHT==================== -// Copyright 2019 The TCMalloc Authors +// Copyright 2016 Google Inc. All Rights Reserved. ====================COPYRIGHT==================== -// Copyright 2020 The TCMalloc Authors +// Copyright 2018 The Abseil Authors. ====================COPYRIGHT==================== -// Copyright 2021 The TCMalloc Authors - - -====================File: LICENSE==================== - - Apache License - Version 2.0, January 2004 - https://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. +// Copyright 2019 The TCMalloc Authors - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. +====================COPYRIGHT==================== +// Copyright 2020 The TCMalloc Authors - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - END OF TERMS AND CONDITIONS +====================COPYRIGHT==================== +// Copyright 2021 The TCMalloc Authors - APPENDIX: How to apply the Apache License to your work. - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. +====================COPYRIGHT==================== +// Copyright 2022 The TCMalloc Authors - Copyright [yyyy] [name of copyright owner] - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at +====================COPYRIGHT==================== +// Copyright 2023 The TCMalloc Authors - https://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +====================COPYRIGHT==================== +// Copyright 2024 The TCMalloc Authors diff --git a/contrib/libs/tcmalloc/README.md b/contrib/libs/tcmalloc/README.md index c848b4838d3f..46fc49c1fb9c 100644 --- a/contrib/libs/tcmalloc/README.md +++ b/contrib/libs/tcmalloc/README.md @@ -17,28 +17,29 @@ platform support for TCMalloc. All users of TCMalloc should consult the following documentation resources: -* The [TCMalloc Quickstart](docs/quickstart.md) covers downloading, installing, - building, and testing TCMalloc, including incorporating within your codebase. -* The [TCMalloc Overview](docs/overview.md) covers the basic architecture of - TCMalloc, and how that may affect configuration choices. -* The [TCMalloc Reference](docs/reference.md) covers the C and C++ TCMalloc API - endpoints. +* The [TCMalloc Quickstart](docs/quickstart.md) covers downloading, + installing, building, and testing TCMalloc, including incorporating within + your codebase. +* The [TCMalloc Overview](docs/overview.md) covers the basic architecture of + TCMalloc, and how that may affect configuration choices. +* The [TCMalloc Reference](docs/reference.md) covers the C and C++ TCMalloc + API endpoints. More advanced usages of TCMalloc may find the following documentation useful: -* The [TCMalloc Tuning Guide](docs/tuning.md) covers the configuration choices - in more depth, and also illustrates other ways to customize TCMalloc. This - also covers important operating system-level properties for improving TCMalloc - performance. -* The [TCMalloc Design Doc](docs/design.md) covers how TCMalloc works - underneath the hood, and why certain design choices were made. Most developers - will not need this level of implementation detail. -* The [TCMalloc Compatibility Guide](docs/compatibility.md) which documents our - expectations for how our APIs are used. +* The [TCMalloc Tuning Guide](docs/tuning.md) covers the configuration + choices in more depth, and also illustrates other ways to customize + TCMalloc. This also covers important operating system-level properties for + improving TCMalloc performance. +* The [TCMalloc Design Doc](docs/design.md) covers how TCMalloc works + underneath the hood, and why certain design choices were made. Most + developers will not need this level of implementation detail. +* The [TCMalloc Compatibility Guide](docs/compatibility.md) which documents + our expectations for how our APIs are used. ## License -The TCMalloc library is licensed under the terms of the Apache -license. See LICENSE for more information. +The TCMalloc library is licensed under the terms of the Apache license. See +LICENSE for more information. Disclaimer: This is not an officially supported Google product. diff --git a/contrib/libs/tcmalloc/common.inc b/contrib/libs/tcmalloc/common.inc index 077942c3871f..5acb463797d7 100644 --- a/contrib/libs/tcmalloc/common.inc +++ b/contrib/libs/tcmalloc/common.inc @@ -3,27 +3,33 @@ GLOBAL_SRCS( tcmalloc/tcmalloc.cc # Common Sources + tcmalloc/allocation_sample.cc + tcmalloc/allocation_sampling.cc tcmalloc/arena.cc tcmalloc/background.cc tcmalloc/central_freelist.cc tcmalloc/common.cc tcmalloc/cpu_cache.cc - tcmalloc/experimental_pow2_below64_size_class.cc + tcmalloc/deallocation_profiler.cc tcmalloc/experimental_pow2_size_class.cc - tcmalloc/legacy_size_classes.cc + tcmalloc/global_stats.cc tcmalloc/guarded_page_allocator.cc tcmalloc/huge_address_map.cc tcmalloc/huge_allocator.cc tcmalloc/huge_cache.cc tcmalloc/huge_page_aware_allocator.cc + tcmalloc/legacy_size_classes.cc tcmalloc/page_allocator.cc tcmalloc/page_allocator_interface.cc - tcmalloc/page_heap.cc tcmalloc/pagemap.cc tcmalloc/parameters.cc tcmalloc/peak_heap_tracker.cc + # tcmalloc/profile_marshaler.cc + tcmalloc/reuse_size_classes.cc tcmalloc/sampler.cc + tcmalloc/segv_handler.cc tcmalloc/size_classes.cc + tcmalloc/sizemap.cc tcmalloc/span.cc tcmalloc/stack_trace_table.cc tcmalloc/static_vars.cc @@ -34,21 +40,33 @@ GLOBAL_SRCS( # Common deps tcmalloc/experiment.cc - tcmalloc/noruntime_size_classes.cc # Internal libraries + tcmalloc/internal/affinity.cc + tcmalloc/internal/allocation_guard.cc tcmalloc/internal/cache_topology.cc tcmalloc/internal/environment.cc tcmalloc/internal/logging.cc tcmalloc/internal/memory_stats.cc + tcmalloc/internal/memory_tag.cc tcmalloc/internal/mincore.cc tcmalloc/internal/numa.cc + tcmalloc/internal/page_size.cc + tcmalloc/internal/pageflags.cc tcmalloc/internal/percpu.cc - tcmalloc/internal/percpu_rseq_asm.S tcmalloc/internal/percpu_rseq_unsupported.cc + tcmalloc/internal/percpu_rseq_asm.S + tcmalloc/internal/proc_maps.cc + # tcmalloc/internal/profile_builder.cc + tcmalloc/internal/residency.cc + tcmalloc/internal/sysinfo.cc tcmalloc/internal/util.cc ) +ADDINCL( + GLOBAL contrib/libs/tcmalloc +) + PEERDIR( contrib/restricted/abseil-cpp contrib/libs/tcmalloc/malloc_extension diff --git a/contrib/libs/tcmalloc/default/ya.make b/contrib/libs/tcmalloc/default/ya.make index 25a88b4bdeb2..1bc6ab6dacc1 100644 --- a/contrib/libs/tcmalloc/default/ya.make +++ b/contrib/libs/tcmalloc/default/ya.make @@ -5,15 +5,11 @@ WITHOUT_LICENSE_TEXTS() VERSION(2021-10-04-45c59ccbc062ac96d83710205033c656e490d376) LICENSE(Apache-2.0) + ALLOCATOR_IMPL() SRCDIR(contrib/libs/tcmalloc) INCLUDE(../common.inc) -GLOBAL_SRCS( - # Options - tcmalloc/want_hpaa_subrelease.cc -) - END() diff --git a/contrib/libs/tcmalloc/no_percpu_cache/ya.make b/contrib/libs/tcmalloc/no_percpu_cache/ya.make index a6b3ce700c4b..928d9092cf88 100644 --- a/contrib/libs/tcmalloc/no_percpu_cache/ya.make +++ b/contrib/libs/tcmalloc/no_percpu_cache/ya.make @@ -5,6 +5,7 @@ WITHOUT_LICENSE_TEXTS() VERSION(2021-10-04-45c59ccbc062ac96d83710205033c656e490d376) LICENSE(Apache-2.0) + ALLOCATOR_IMPL() SRCDIR(contrib/libs/tcmalloc) @@ -16,7 +17,9 @@ GLOBAL_SRCS( INCLUDE(../common.inc) -SRCS(aligned_alloc.c) +SRCS( + aligned_alloc.c +) CFLAGS( -DTCMALLOC_256K_PAGES diff --git a/contrib/libs/tcmalloc/numa_256k/ya.make b/contrib/libs/tcmalloc/numa_256k/ya.make index d6b3bb2df31e..5b43065230a0 100644 --- a/contrib/libs/tcmalloc/numa_256k/ya.make +++ b/contrib/libs/tcmalloc/numa_256k/ya.make @@ -5,6 +5,7 @@ WITHOUT_LICENSE_TEXTS() VERSION(2021-10-04-45c59ccbc062ac96d83710205033c656e490d376) LICENSE(Apache-2.0) + ALLOCATOR_IMPL() SRCDIR(contrib/libs/tcmalloc) @@ -13,7 +14,6 @@ INCLUDE(../common.inc) GLOBAL_SRCS( # Options - tcmalloc/want_hpaa_subrelease.cc tcmalloc/want_numa_aware.cc ) diff --git a/contrib/libs/tcmalloc/numa_large_pages/ya.make b/contrib/libs/tcmalloc/numa_large_pages/ya.make index 8cb48bd42319..0a94465472dd 100644 --- a/contrib/libs/tcmalloc/numa_large_pages/ya.make +++ b/contrib/libs/tcmalloc/numa_large_pages/ya.make @@ -5,6 +5,7 @@ WITHOUT_LICENSE_TEXTS() VERSION(2021-10-04-45c59ccbc062ac96d83710205033c656e490d376) LICENSE(Apache-2.0) + ALLOCATOR_IMPL() SRCDIR(contrib/libs/tcmalloc) @@ -13,7 +14,6 @@ INCLUDE(../common.inc) GLOBAL_SRCS( # Options - tcmalloc/want_hpaa_subrelease.cc tcmalloc/want_numa_aware.cc ) diff --git a/contrib/libs/tcmalloc/patches/010-fork.patch b/contrib/libs/tcmalloc/patches/010-fork.patch new file mode 100644 index 000000000000..d23b4de3d2b7 --- /dev/null +++ b/contrib/libs/tcmalloc/patches/010-fork.patch @@ -0,0 +1,400 @@ +diff --git a/tcmalloc/central_freelist.h b/tcmalloc/central_freelist.h +index 9fdcd83..90181e5 100644 +--- a/tcmalloc/central_freelist.h ++++ b/tcmalloc/central_freelist.h +@@ -131,6 +131,14 @@ class CentralFreeList { + size_t NumSpansInList(int n) ABSL_LOCKS_EXCLUDED(lock_); + SpanStats GetSpanStats() const; + ++ void AcquireInternalLocks() { ++ lock_.Lock(); ++ } ++ ++ void ReleaseInternalLocks() { ++ lock_.Unlock(); ++ } ++ + // Reports span utilization and lifetime histogram stats. + void PrintSpanUtilStats(Printer& out); + void PrintSpanLifetimeStats(Printer& out); +diff --git a/tcmalloc/cpu_cache.h b/tcmalloc/cpu_cache.h +index 164e06f..b9a6bd6 100644 +--- a/tcmalloc/cpu_cache.h ++++ b/tcmalloc/cpu_cache.h +@@ -487,6 +487,9 @@ class CpuCache { + void Print(Printer& out) const; + void PrintInPbtxt(PbtxtRegion& region) const; + ++ void AcquireInternalLocks(); ++ void ReleaseInternalLocks(); ++ + const Forwarder& forwarder() const { return forwarder_; } + + Forwarder& forwarder() { return forwarder_; } +@@ -2635,6 +2638,22 @@ inline void CpuCache::PrintInPbtxt(PbtxtRegion& region) const { + dynamic_slab_info_.madvise_failed_bytes.load(std::memory_order_relaxed)); + } + ++template ++inline void CpuCache::AcquireInternalLocks() { ++ int ncpus = absl::base_internal::NumCPUs(); ++ for (int cpu = 0; cpu < ncpus; ++cpu) { ++ resize_[cpu].lock.Lock(); ++ } ++} ++ ++template ++inline void CpuCache::ReleaseInternalLocks() { ++ int ncpus = absl::base_internal::NumCPUs(); ++ for (int cpu = 0; cpu < ncpus; ++cpu) { ++ resize_[cpu].lock.Unlock(); ++ } ++} ++ + template + inline void CpuCache::PerClassResizeInfo::Init() { + state_.store(0, std::memory_order_relaxed); +diff --git a/tcmalloc/guarded_page_allocator.cc b/tcmalloc/guarded_page_allocator.cc +index 8acfdc4..9e2a54a 100644 +--- a/tcmalloc/guarded_page_allocator.cc ++++ b/tcmalloc/guarded_page_allocator.cc +@@ -92,6 +92,14 @@ void GuardedPageAllocator::Reset() { + stacktrace_filter_.DecayAll(); + } + ++void GuardedPageAllocator::AcquireInternalLocks() { ++ guarded_page_lock_.Lock(); ++} ++ ++void GuardedPageAllocator::ReleaseInternalLocks() { ++ guarded_page_lock_.Unlock(); ++} ++ + GuardedAllocWithStatus GuardedPageAllocator::TrySample( + size_t size, size_t alignment, Length num_pages, + const StackTrace& stack_trace) { +diff --git a/tcmalloc/guarded_page_allocator.h b/tcmalloc/guarded_page_allocator.h +index 4330ab7..8bd5c9a 100644 +--- a/tcmalloc/guarded_page_allocator.h ++++ b/tcmalloc/guarded_page_allocator.h +@@ -114,6 +114,10 @@ class GuardedPageAllocator { + // and avoiding use-after-destruction issues for static/global instances. + void Destroy(); + ++ void AcquireInternalLocks() ABSL_LOCKS_EXCLUDED(guarded_page_lock_); ++ void ReleaseInternalLocks() ABSL_LOCKS_EXCLUDED(guarded_page_lock_); ++ ++ + // If this allocation can be guarded, and if it's time to do a guarded sample, + // returns an instance of GuardedAllocWithStatus, that includes guarded + // allocation Span and guarded status. Otherwise, returns nullptr and the +diff --git a/tcmalloc/internal/sampled_allocation_recorder.h b/tcmalloc/internal/sampled_allocation_recorder.h +index a3ef3cc..8e1ec85 100644 +--- a/tcmalloc/internal/sampled_allocation_recorder.h ++++ b/tcmalloc/internal/sampled_allocation_recorder.h +@@ -92,6 +92,9 @@ class SampleRecorder { + // Iterates over all the registered samples. + void Iterate(const absl::FunctionRef& f); + ++ void AcquireInternalLocks(); ++ void ReleaseInternalLocks(); ++ + private: + void PushNew(T* sample); + void PushDead(T* sample); +@@ -240,7 +243,17 @@ void SampleRecorder::Iterate( + } + } + +-} // namespace tcmalloc_internal ++template ++void SampleRecorder::AcquireInternalLocks() { ++ graveyard_.lock.Lock(); ++} ++ ++template ++void SampleRecorder::ReleaseInternalLocks() { ++ graveyard_.lock.Unlock(); ++} ++ ++} // namespace tcmalloc_internal + } // namespace tcmalloc + GOOGLE_MALLOC_SECTION_END + +diff --git a/tcmalloc/internal_malloc_extension.h b/tcmalloc/internal_malloc_extension.h +index 2f8b329..190d742 100644 +--- a/tcmalloc/internal_malloc_extension.h ++++ b/tcmalloc/internal_malloc_extension.h +@@ -154,6 +154,9 @@ ABSL_ATTRIBUTE_WEAK int64_t + MallocExtension_Internal_GetMaxTotalThreadCacheBytes(); + ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_SetMaxTotalThreadCacheBytes( + int64_t value); ++ ++ABSL_ATTRIBUTE_WEAK void ++MallocExtension_EnableForkSupport(); + } + + #endif +diff --git a/tcmalloc/malloc_extension.cc b/tcmalloc/malloc_extension.cc +index 1475faa..cee8ba3 100644 +--- a/tcmalloc/malloc_extension.cc ++++ b/tcmalloc/malloc_extension.cc +@@ -796,6 +796,14 @@ void MallocExtension::SetBackgroundReleaseRate(BytesPerSecond rate) { + #endif + } + ++void MallocExtension::EnableForkSupport() { ++#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS ++ if (&MallocExtension_EnableForkSupport != nullptr) { ++ MallocExtension_EnableForkSupport(); ++ } ++#endif ++} ++ + } // namespace tcmalloc + + // Default implementation just returns size. The expectation is that +diff --git a/tcmalloc/malloc_extension.h b/tcmalloc/malloc_extension.h +index 403520e..36fd433 100644 +--- a/tcmalloc/malloc_extension.h ++++ b/tcmalloc/malloc_extension.h +@@ -660,6 +660,10 @@ class MallocExtension final { + // Specifies the release rate from the page heap. ProcessBackgroundActions + // must be called for this to be operative. + static void SetBackgroundReleaseRate(BytesPerSecond rate); ++ ++ // Enables fork support. ++ // Allocator will continue to function correctly in the child, after calling fork(). ++ static void EnableForkSupport(); + }; + + } // namespace tcmalloc +diff --git a/tcmalloc/static_vars.cc b/tcmalloc/static_vars.cc +index aaacbbb..464b49a 100644 +--- a/tcmalloc/static_vars.cc ++++ b/tcmalloc/static_vars.cc +@@ -123,6 +123,7 @@ ABSL_CONST_INIT MetadataObjectAllocator + Static::linked_sample_allocator_{arena_}; + ABSL_CONST_INIT std::atomic Static::inited_{false}; + ABSL_CONST_INIT std::atomic Static::cpu_cache_active_{false}; ++ABSL_CONST_INIT bool Static::fork_support_enabled_ = false; + ABSL_CONST_INIT Static::PageAllocatorStorage Static::page_allocator_; + ABSL_CONST_INIT PageMap Static::pagemap_; + ABSL_CONST_INIT GuardedPageAllocator Static::guardedpage_allocator_; +@@ -235,6 +236,14 @@ ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void Static::SlowInitIfNecessary() { + guardedpage_allocator_.Init(/*max_allocated_pages=*/64, + /*total_pages=*/128); + inited_.store(true, std::memory_order_release); ++ ++ // TODO: this is called with inited_ = true, so it looks like a race condition ++ pageheap_lock.Unlock(); ++ pthread_atfork( ++ TCMallocPreFork, ++ TCMallocPostFork, ++ TCMallocPostFork); ++ pageheap_lock.Lock(); + } + } + +diff --git a/tcmalloc/static_vars.h b/tcmalloc/static_vars.h +index af1c14b..58f706c 100644 +--- a/tcmalloc/static_vars.h ++++ b/tcmalloc/static_vars.h +@@ -72,6 +72,9 @@ enum class SizeClassConfiguration { + + bool tcmalloc_big_span(); + ++void TCMallocPreFork(); ++void TCMallocPostFork(); ++ + class Static final { + public: + constexpr Static() = default; +@@ -172,6 +175,13 @@ class Static final { + cpu_cache_active_.store(true, std::memory_order_release); + } + ++ static bool ForkSupportEnabled() { ++ return fork_support_enabled_; ++ } ++ static void EnableForkSupport() { ++ fork_support_enabled_ = true; ++ } ++ + static bool ABSL_ATTRIBUTE_ALWAYS_INLINE HaveHooks() { + return false; + } +@@ -215,6 +225,7 @@ class Static final { + linked_sample_allocator_; + ABSL_CONST_INIT static std::atomic inited_; + ABSL_CONST_INIT static std::atomic cpu_cache_active_; ++ ABSL_CONST_INIT static bool fork_support_enabled_; + ABSL_CONST_INIT static PeakHeapTracker peak_heap_tracker_; + ABSL_CONST_INIT static NumaTopology + numa_topology_; +diff --git a/tcmalloc/system-alloc.h b/tcmalloc/system-alloc.h +index 84280cf..06392e2 100644 +--- a/tcmalloc/system-alloc.h ++++ b/tcmalloc/system-alloc.h +@@ -142,6 +142,13 @@ class SystemAllocator { + [[nodiscard]] void* MmapAligned(size_t size, size_t alignment, MemoryTag tag) + ABSL_LOCKS_EXCLUDED(spinlock_); + ++ void AcquireInternalLocks() { ++ spinlock_.Lock(); ++ } ++ void ReleaseInternalLocks() { ++ spinlock_.Unlock(); ++ } ++ + private: + const Topology& topology_; + +diff --git a/tcmalloc/tcmalloc.cc b/tcmalloc/tcmalloc.cc +index 062d257..846ab86 100644 +--- a/tcmalloc/tcmalloc.cc ++++ b/tcmalloc/tcmalloc.cc +@@ -117,6 +117,7 @@ + #include "tcmalloc/tcmalloc_policy.h" + #include "tcmalloc/thread_cache.h" + #include "tcmalloc/transfer_cache.h" ++#include "thread_cache.h" + + #if defined(TCMALLOC_HAVE_STRUCT_MALLINFO) || \ + defined(TCMALLOC_HAVE_STRUCT_MALLINFO2) +@@ -338,6 +339,44 @@ extern "C" size_t MallocExtension_Internal_ReleaseMemoryToSystem( + /*reason=*/PageReleaseReason::kReleaseMemoryToSystem); + } + ++extern "C" void MallocExtension_EnableForkSupport() { ++ Static::EnableForkSupport(); ++} ++ ++void TCMallocPreFork() { ++ if (!Static::ForkSupportEnabled()) { ++ return; ++ } ++ ++ if (Static::CpuCacheActive()) { ++ Static::cpu_cache().AcquireInternalLocks(); ++ } ++ Static::transfer_cache().AcquireInternalLocks(); ++ Static::guardedpage_allocator().AcquireInternalLocks(); ++ release_lock.Lock(); ++ pageheap_lock.Lock(); ++ Static::system_allocator().AcquireInternalLocks(); ++ ThreadCache::AcquireInternalLocks(); ++ Static::sampled_allocation_recorder().AcquireInternalLocks(); ++} ++ ++void TCMallocPostFork() { ++ if (!Static::ForkSupportEnabled()) { ++ return; ++ } ++ Static::system_allocator().ReleaseInternalLocks(); ++ pageheap_lock.Unlock(); ++ Static::guardedpage_allocator().ReleaseInternalLocks(); ++ release_lock.Unlock(); ++ Static::transfer_cache().ReleaseInternalLocks(); ++ if (Static::CpuCacheActive()) { ++ Static::cpu_cache().ReleaseInternalLocks(); ++ } ++ ThreadCache::ReleaseInternalLocks(); ++ Static::sampled_allocation_recorder().ReleaseInternalLocks(); ++} ++ ++ + // nallocx slow path. + // Moved to a separate function because size_class_with_alignment is not inlined + // which would cause nallocx to become non-leaf function with stack frame and +diff --git a/tcmalloc/tcmalloc.h b/tcmalloc/tcmalloc.h +index b908aff..c877168 100644 +--- a/tcmalloc/tcmalloc.h ++++ b/tcmalloc/tcmalloc.h +@@ -158,6 +158,9 @@ ABSL_ATTRIBUTE_UNUSED void TCMallocInternalDeleteArrayAlignedNothrow( + ABSL_ATTRIBUTE_SECTION(google_malloc); + #endif + ++void TCMallocInternalAcquireLocks(); ++void TCMallocInternalReleaseLocks(); ++ + } // extern "C" + + #endif // TCMALLOC_TCMALLOC_H_ +diff --git a/tcmalloc/thread_cache.cc b/tcmalloc/thread_cache.cc +index 0a6f038..ff50665 100644 +--- a/tcmalloc/thread_cache.cc ++++ b/tcmalloc/thread_cache.cc +@@ -424,6 +424,14 @@ void ThreadCache::set_overall_thread_cache_size(size_t new_size) { + RecomputePerThreadCacheSize(); + } + ++void ThreadCache::AcquireInternalLocks() { ++ threadcache_lock_.Lock(); ++} ++ ++void ThreadCache::ReleaseInternalLocks() { ++ threadcache_lock_.Unlock(); ++} ++ + } // namespace tcmalloc_internal + } // namespace tcmalloc + GOOGLE_MALLOC_SECTION_END +diff --git a/tcmalloc/thread_cache.h b/tcmalloc/thread_cache.h +index 2b94ac7..8ae5e76 100644 +--- a/tcmalloc/thread_cache.h ++++ b/tcmalloc/thread_cache.h +@@ -70,6 +70,9 @@ class ABSL_CACHELINE_ALIGNED ThreadCache { + return overall_thread_cache_size_.load(std::memory_order_relaxed); + } + ++ static void AcquireInternalLocks(); ++ static void ReleaseInternalLocks(); ++ + private: + // We inherit rather than include the list as a data structure to reduce + // compiler padding. Without inheritance, the compiler pads the list +diff --git a/tcmalloc/transfer_cache.h b/tcmalloc/transfer_cache.h +index b2b29d5..5af6dc8 100644 +--- a/tcmalloc/transfer_cache.h ++++ b/tcmalloc/transfer_cache.h +@@ -415,6 +415,18 @@ class TransferCacheManager : public StaticForwarder { + + void Init() { InitCaches(); } + ++ void AcquireInternalLocks() { ++ for (int i = 0; i < kNumClasses; ++i) { ++ cache_[i].tc.AcquireInternalLocks(); ++ } ++ } ++ ++ void ReleaseInternalLocks() { ++ for (int i = 0; i < kNumClasses; ++i) { ++ cache_[i].tc.ReleaseInternalLocks(); ++ } ++ } ++ + void InsertRange(int size_class, absl::Span batch) { + cache_[size_class].tc.InsertRange(size_class, batch); + } +diff --git a/tcmalloc/transfer_cache_internals.h b/tcmalloc/transfer_cache_internals.h +index 2a3bd4c..d8f1031 100644 +--- a/tcmalloc/transfer_cache_internals.h ++++ b/tcmalloc/transfer_cache_internals.h +@@ -205,6 +205,16 @@ class TransferCache { + return freelist().RemoveRange(batch); + } + ++ void AcquireInternalLocks() { ++ lock_.Lock(); ++ freelist().AcquireInternalLocks(); ++ } ++ ++ void ReleaseInternalLocks() { ++ lock_.Unlock(); ++ freelist().ReleaseInternalLocks(); ++ } ++ + // We record the lowest value of info.used in a low water mark since the last + // call to TryPlunder. We plunder all those objects to the freelist, as the + // objects not used within a full cycle are unlikely to be used again. diff --git a/contrib/libs/tcmalloc/patches/020-user-data.patch b/contrib/libs/tcmalloc/patches/020-user-data.patch new file mode 100644 index 000000000000..811d4cacd2ab --- /dev/null +++ b/contrib/libs/tcmalloc/patches/020-user-data.patch @@ -0,0 +1,269 @@ +diff --git a/tcmalloc/allocation_sampling.h b/tcmalloc/allocation_sampling.h +index 2af67c8..023263a 100644 +--- a/tcmalloc/allocation_sampling.h ++++ b/tcmalloc/allocation_sampling.h +@@ -193,6 +193,7 @@ SampleifyAllocation(Static& state, Policy policy, size_t requested_size, + stack_trace.allocation_time = absl::Now(); + stack_trace.guarded_status = alloc_with_status.status; + stack_trace.allocation_type = policy.allocation_type(); ++ stack_trace.user_data = SampleUserDataSupport::UserData::Make(); + + // How many allocations does this sample represent, given the sampling + // frequency (weight) and its size. +diff --git a/tcmalloc/internal/logging.cc b/tcmalloc/internal/logging.cc +index 1cd8d18..a53c26a 100644 +--- a/tcmalloc/internal/logging.cc ++++ b/tcmalloc/internal/logging.cc +@@ -43,6 +43,10 @@ GOOGLE_MALLOC_SECTION_BEGIN + namespace tcmalloc { + namespace tcmalloc_internal { + ++ABSL_CONST_INIT SampleUserDataSupport::CreateSampleUserDataCallback* SampleUserDataSupport::create_sample_user_data_callback_ = nullptr; ++ABSL_CONST_INIT SampleUserDataSupport::CopySampleUserDataCallback* SampleUserDataSupport::copy_sample_user_data_callback_ = nullptr; ++ABSL_CONST_INIT SampleUserDataSupport::DestroySampleUserDataCallback* SampleUserDataSupport::destroy_sample_user_data_callback_ = nullptr; ++ + // Variables for storing crash output. Allocated statically since we + // may not be able to heap-allocate while crashing. + ABSL_CONST_INIT static absl::base_internal::SpinLock crash_lock( +diff --git a/tcmalloc/internal/logging.h b/tcmalloc/internal/logging.h +index 2a5c761..f2ecc1d 100644 +--- a/tcmalloc/internal/logging.h ++++ b/tcmalloc/internal/logging.h +@@ -51,6 +51,87 @@ GOOGLE_MALLOC_SECTION_BEGIN + namespace tcmalloc { + namespace tcmalloc_internal { + ++class SampleUserDataSupport { ++public: ++ using CreateSampleUserDataCallback = void*(); ++ using CopySampleUserDataCallback = void*(void*); ++ using DestroySampleUserDataCallback = void(void*); ++ ++ class UserData { ++ public: ++ static UserData Make() { ++ return UserData{CreateSampleUserData()}; ++ } ++ ++ constexpr UserData() noexcept : ptr_(nullptr) {} ++ ++ UserData(const UserData& that) noexcept : ptr_(CopySampleUserData(that.ptr_)) {} ++ UserData& operator=(const UserData& that) noexcept { ++ DestroySampleUserData(ptr_); ++ ptr_ = CopySampleUserData(that.ptr_); ++ return *this; ++ } ++ ++ UserData(UserData&& that) noexcept : ptr_(that.ptr_) { ++ that.ptr_ = nullptr; ++ } ++ UserData& operator=(UserData&& that) noexcept { ++ if (this == &that) { ++ return *this; ++ } ++ DestroySampleUserData(ptr_); ++ ptr_ = that.ptr_; ++ that.ptr_ = nullptr; ++ return *this; ++ } ++ void Reset() { ++ DestroySampleUserData(ptr_); ++ ptr_ = nullptr; ++ } ++ ++ ~UserData() { ++ DestroySampleUserData(ptr_); ++ } ++ ++ void* Get() const { return ptr_; } ++ private: ++ UserData(void* ptr) noexcept : ptr_(ptr) {} ++ private: ++ void* ptr_; ++ }; ++ ++ static void Enable(CreateSampleUserDataCallback create, ++ CopySampleUserDataCallback copy, ++ DestroySampleUserDataCallback destroy) { ++ create_sample_user_data_callback_ = create; ++ copy_sample_user_data_callback_ = copy; ++ destroy_sample_user_data_callback_ = destroy; ++ } ++private: ++ static void* CreateSampleUserData() { ++ if (create_sample_user_data_callback_ != nullptr) { ++ return create_sample_user_data_callback_(); ++ } ++ return nullptr; ++ } ++ ++ static void* CopySampleUserData(void* ptr) noexcept { ++ if (copy_sample_user_data_callback_ != nullptr) { ++ return copy_sample_user_data_callback_(ptr); ++ } ++ return nullptr; ++ } ++ ++ static void DestroySampleUserData(void* ptr) noexcept { ++ if (destroy_sample_user_data_callback_ != nullptr) { ++ destroy_sample_user_data_callback_(ptr); ++ } ++ } ++ ABSL_CONST_INIT static CreateSampleUserDataCallback* create_sample_user_data_callback_; ++ ABSL_CONST_INIT static CopySampleUserDataCallback* copy_sample_user_data_callback_; ++ ABSL_CONST_INIT static DestroySampleUserDataCallback* destroy_sample_user_data_callback_; ++}; ++ + static constexpr int kMaxStackDepth = 64; + + // An opaque handle type used to identify allocations. +@@ -84,6 +165,8 @@ struct StackTrace { + // between the previous sample and this one + size_t weight; + ++ SampleUserDataSupport::UserData user_data; ++ + // Timestamp of allocation. + absl::Time allocation_time; + +diff --git a/tcmalloc/internal/sampled_allocation_recorder.h b/tcmalloc/internal/sampled_allocation_recorder.h +index 8e1ec85..7f9818f 100644 +--- a/tcmalloc/internal/sampled_allocation_recorder.h ++++ b/tcmalloc/internal/sampled_allocation_recorder.h +@@ -169,6 +169,7 @@ void SampleRecorder::PushDead(T* sample) { + if (auto* dispose = dispose_.load(std::memory_order_relaxed)) { + dispose(*sample); + } ++ sample->sampled_stack.user_data.Reset(); + + AllocationGuardSpinLockHolder graveyard_lock(&graveyard_.lock); + AllocationGuardSpinLockHolder sample_lock(&sample->lock); +diff --git a/tcmalloc/internal_malloc_extension.h b/tcmalloc/internal_malloc_extension.h +index 190d742..dc0c0e0 100644 +--- a/tcmalloc/internal_malloc_extension.h ++++ b/tcmalloc/internal_malloc_extension.h +@@ -157,6 +157,12 @@ ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_SetMaxTotalThreadCacheBytes( + + ABSL_ATTRIBUTE_WEAK void + MallocExtension_EnableForkSupport(); ++ ++ABSL_ATTRIBUTE_WEAK void ++MallocExtension_SetSampleUserDataCallbacks( ++ tcmalloc::MallocExtension::CreateSampleUserDataCallback create, ++ tcmalloc::MallocExtension::CopySampleUserDataCallback copy, ++ tcmalloc::MallocExtension::DestroySampleUserDataCallback destroy); + } + + #endif +diff --git a/tcmalloc/malloc_extension.cc b/tcmalloc/malloc_extension.cc +index cee8ba3..b7ca15a 100644 +--- a/tcmalloc/malloc_extension.cc ++++ b/tcmalloc/malloc_extension.cc +@@ -804,6 +804,21 @@ void MallocExtension::EnableForkSupport() { + #endif + } + ++void MallocExtension::SetSampleUserDataCallbacks( ++ CreateSampleUserDataCallback create, ++ CopySampleUserDataCallback copy, ++ DestroySampleUserDataCallback destroy) { ++#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS ++ if (&MallocExtension_SetSampleUserDataCallbacks != nullptr) { ++ MallocExtension_SetSampleUserDataCallbacks(create, copy, destroy); ++ } ++#else ++ (void)create; ++ (void)copy; ++ (void)destroy; ++#endif ++} ++ + } // namespace tcmalloc + + // Default implementation just returns size. The expectation is that +diff --git a/tcmalloc/malloc_extension.h b/tcmalloc/malloc_extension.h +index 36fd433..702baa8 100644 +--- a/tcmalloc/malloc_extension.h ++++ b/tcmalloc/malloc_extension.h +@@ -214,6 +214,8 @@ class Profile final { + int depth; + void* stack[kMaxStackDepth]; + ++ void* user_data; ++ + // The following vars are used by the lifetime (deallocation) profiler. + uint64_t profile_id; + +@@ -664,6 +666,16 @@ class MallocExtension final { + // Enables fork support. + // Allocator will continue to function correctly in the child, after calling fork(). + static void EnableForkSupport(); ++ ++ using CreateSampleUserDataCallback = void*(); ++ using CopySampleUserDataCallback = void*(void*); ++ using DestroySampleUserDataCallback = void(void*); ++ ++ // Sets callbacks for lifetime control of custom user data attached to allocation samples ++ static void SetSampleUserDataCallbacks( ++ CreateSampleUserDataCallback create, ++ CopySampleUserDataCallback copy, ++ DestroySampleUserDataCallback destroy); + }; + + } // namespace tcmalloc +diff --git a/tcmalloc/stack_trace_table.cc b/tcmalloc/stack_trace_table.cc +index cf57148..2de1a25 100644 +--- a/tcmalloc/stack_trace_table.cc ++++ b/tcmalloc/stack_trace_table.cc +@@ -88,6 +88,7 @@ void StackTraceTable::AddTrace(double sample_weight, const StackTrace& t) { + s->sample.span_start_address = t.span_start_address; + s->sample.guarded_status = t.guarded_status; + s->sample.type = t.allocation_type; ++ s->sample.user_data = t.user_data.Get(); + + static_assert(kMaxStackDepth <= Profile::Sample::kMaxStackDepth, + "Profile stack size smaller than internal stack sizes"); +diff --git a/tcmalloc/static_vars.h b/tcmalloc/static_vars.h +index 58f706c..010ceed 100644 +--- a/tcmalloc/static_vars.h ++++ b/tcmalloc/static_vars.h +@@ -26,6 +26,7 @@ + #include "absl/base/attributes.h" + #include "absl/base/optimization.h" + #include "absl/base/thread_annotations.h" ++#include "internal/logging.h" + #include "tcmalloc/allocation_sample.h" + #include "tcmalloc/arena.h" + #include "tcmalloc/central_freelist.h" +@@ -182,6 +183,14 @@ class Static final { + fork_support_enabled_ = true; + } + ++ ++ static void SetSampleUserDataCallbacks( ++ SampleUserDataSupport::CreateSampleUserDataCallback create, ++ SampleUserDataSupport::CopySampleUserDataCallback copy, ++ SampleUserDataSupport::DestroySampleUserDataCallback destroy) { ++ SampleUserDataSupport::Enable(create, copy, destroy); ++ } ++ + static bool ABSL_ATTRIBUTE_ALWAYS_INLINE HaveHooks() { + return false; + } +diff --git a/tcmalloc/tcmalloc.cc b/tcmalloc/tcmalloc.cc +index 846ab86..d4d4169 100644 +--- a/tcmalloc/tcmalloc.cc ++++ b/tcmalloc/tcmalloc.cc +@@ -376,6 +376,12 @@ void TCMallocPostFork() { + Static::sampled_allocation_recorder().ReleaseInternalLocks(); + } + ++extern "C" void MallocExtension_SetSampleUserDataCallbacks( ++ MallocExtension::CreateSampleUserDataCallback create, ++ MallocExtension::CopySampleUserDataCallback copy, ++ MallocExtension::DestroySampleUserDataCallback destroy) { ++ Static::SetSampleUserDataCallbacks(create, copy, destroy); ++} + + // nallocx slow path. + // Moved to a separate function because size_class_with_alignment is not inlined diff --git a/contrib/libs/tcmalloc/patches/handler.patch b/contrib/libs/tcmalloc/patches/030-soft-limit-handler.patch similarity index 58% rename from contrib/libs/tcmalloc/patches/handler.patch rename to contrib/libs/tcmalloc/patches/030-soft-limit-handler.patch index ce30d7e1c2f8..77c54cbff8a3 100644 --- a/contrib/libs/tcmalloc/patches/handler.patch +++ b/contrib/libs/tcmalloc/patches/030-soft-limit-handler.patch @@ -1,6 +1,8 @@ ---- contrib/libs/tcmalloc/tcmalloc/malloc_extension.cc (index) -+++ contrib/libs/tcmalloc/tcmalloc/malloc_extension.cc (working tree) -@@ -468,6 +468,20 @@ void MallocExtension::EnableForkSupport() { +diff --git a/tcmalloc/malloc_extension.cc b/tcmalloc/malloc_extension.cc +index b7ca15a..dc4aeb5 100644 +--- a/tcmalloc/malloc_extension.cc ++++ b/tcmalloc/malloc_extension.cc +@@ -804,6 +804,20 @@ void MallocExtension::EnableForkSupport() { #endif } @@ -21,9 +23,11 @@ void MallocExtension::SetSampleUserDataCallbacks( CreateSampleUserDataCallback create, CopySampleUserDataCallback copy, ---- contrib/libs/tcmalloc/tcmalloc/malloc_extension.h (index) -+++ contrib/libs/tcmalloc/tcmalloc/malloc_extension.h (working tree) -@@ -475,6 +475,10 @@ class MallocExtension final { +diff --git a/tcmalloc/malloc_extension.h b/tcmalloc/malloc_extension.h +index 702baa8..0505971 100644 +--- a/tcmalloc/malloc_extension.h ++++ b/tcmalloc/malloc_extension.h +@@ -667,6 +667,10 @@ class MallocExtension final { // Allocator will continue to function correctly in the child, after calling fork(). static void EnableForkSupport(); @@ -34,16 +38,18 @@ using CreateSampleUserDataCallback = void*(); using CopySampleUserDataCallback = void*(void*); using DestroySampleUserDataCallback = void(void*); ---- contrib/libs/tcmalloc/tcmalloc/page_allocator.cc (index) -+++ contrib/libs/tcmalloc/tcmalloc/page_allocator.cc (working tree) -@@ -151,6 +151,10 @@ void PageAllocator::ShrinkToUsageLimit() { +diff --git a/tcmalloc/page_allocator.cc b/tcmalloc/page_allocator.cc +index 2f450d8..f723297 100644 +--- a/tcmalloc/page_allocator.cc ++++ b/tcmalloc/page_allocator.cc +@@ -138,6 +138,10 @@ void PageAllocator::ShrinkToUsageLimit(Length n) { warned = true; - Log(kLogWithStack, __FILE__, __LINE__, "Couldn't respect usage limit of ", - limit_, "and OOM is likely to follow."); + TC_LOG("Couldn't respect usage limit of %v and OOM is likely to follow.", + limits_[kSoft]); + + if (auto* handler = MallocExtension::GetSoftMemoryLimitHandler()) { + (*handler)(); + } } - bool PageAllocator::ShrinkHardBy(Length pages) { + bool PageAllocator::ShrinkHardBy(Length pages, LimitKind limit_kind) { diff --git a/contrib/libs/tcmalloc/patches/040-remove-conflicting-noexcept.patch b/contrib/libs/tcmalloc/patches/040-remove-conflicting-noexcept.patch new file mode 100644 index 000000000000..bd80a5d6bee6 --- /dev/null +++ b/contrib/libs/tcmalloc/patches/040-remove-conflicting-noexcept.patch @@ -0,0 +1,13 @@ +diff --git a/tcmalloc/libc_override.h b/tcmalloc/libc_override.h +index 424e6ee..9674e9b 100644 +--- a/tcmalloc/libc_override.h ++++ b/tcmalloc/libc_override.h +@@ -174,7 +174,7 @@ void sdallocx(void* ptr, size_t size, int flags) noexcept + TCMALLOC_ALIAS(TCMallocInternalSdallocx); + void* realloc(void* ptr, size_t size) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalRealloc); +-void* reallocarray(void* ptr, size_t n, size_t size) TCMALLOC_NOTHROW ++void* reallocarray(void* ptr, size_t n, size_t size) + TCMALLOC_ALIAS(TCMallocInternalReallocArray); + void* calloc(size_t n, size_t size) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalCalloc); diff --git a/contrib/libs/tcmalloc/patches/050-avoid-cycle.patch b/contrib/libs/tcmalloc/patches/050-avoid-cycle.patch new file mode 100644 index 000000000000..aa7d649be6ab --- /dev/null +++ b/contrib/libs/tcmalloc/patches/050-avoid-cycle.patch @@ -0,0 +1,13 @@ +diff --git a/tcmalloc/internal/profile_builder.h b/tcmalloc/internal/profile_builder.h +index 06f2abe..d50992e 100644 +--- a/tcmalloc/internal/profile_builder.h ++++ b/tcmalloc/internal/profile_builder.h +@@ -24,7 +24,7 @@ + #include + #include + +-#include "tcmalloc/internal/profile.pb.h" ++// #include "tcmalloc/internal/profile.pb.h" + #include "absl/container/btree_map.h" + #include "absl/container/flat_hash_map.h" + #include "absl/status/status.h" diff --git a/contrib/libs/tcmalloc/patches/060-system-headers.sh b/contrib/libs/tcmalloc/patches/060-system-headers.sh new file mode 100644 index 000000000000..7f5b4b26deaa --- /dev/null +++ b/contrib/libs/tcmalloc/patches/060-system-headers.sh @@ -0,0 +1,5 @@ +set -eux +# DTCC-1856 +find . -type f -name '*.h' | while read l; do + sed -i '1s/^/#pragma clang system_header\n/' ${l} +done \ No newline at end of file diff --git a/contrib/libs/tcmalloc/patches/900-undeprecate-rate-interval.patch b/contrib/libs/tcmalloc/patches/900-undeprecate-rate-interval.patch new file mode 100644 index 000000000000..cdb0e19dae1a --- /dev/null +++ b/contrib/libs/tcmalloc/patches/900-undeprecate-rate-interval.patch @@ -0,0 +1,24 @@ +diff --git a/tcmalloc/malloc_extension.h b/tcmalloc/malloc_extension.h +index 0505971..26e15b4 100644 +--- a/tcmalloc/malloc_extension.h ++++ b/tcmalloc/malloc_extension.h +@@ -476,11 +476,9 @@ class MallocExtension final { + + // The old names to get and set profile sampling intervals used "rate" to + // refer to intervals. Use of the below is deprecated to avoid confusion. +- ABSL_DEPRECATE_AND_INLINE() + static int64_t GetProfileSamplingRate() { + return GetProfileSamplingInterval(); + } +- ABSL_DEPRECATE_AND_INLINE() + static void SetProfileSamplingRate(int64_t rate) { + SetProfileSamplingInterval(rate); + } +@@ -488,7 +486,6 @@ class MallocExtension final { + static int64_t GetGuardedSamplingRate() { + return GetGuardedSamplingInterval(); + } +- ABSL_DEPRECATE_AND_INLINE() + static void SetGuardedSamplingRate(int64_t rate) { + SetGuardedSamplingInterval(rate); + } diff --git a/contrib/libs/tcmalloc/patches/fork.patch b/contrib/libs/tcmalloc/patches/fork.patch deleted file mode 100644 index 250339443190..000000000000 --- a/contrib/libs/tcmalloc/patches/fork.patch +++ /dev/null @@ -1,310 +0,0 @@ ---- contrib/libs/tcmalloc/tcmalloc/central_freelist.h (index) -+++ contrib/libs/tcmalloc/tcmalloc/central_freelist.h (working tree) -@@ -70,6 +70,14 @@ class CentralFreeList { - - SpanStats GetSpanStats() const; - -+ void AcquireInternalLocks() { -+ lock_.Lock(); -+ } -+ -+ void ReleaseInternalLocks() { -+ lock_.Unlock(); -+ } -+ - private: - // Release an object to spans. - // Returns object's span if it become completely free. ---- contrib/libs/tcmalloc/tcmalloc/cpu_cache.cc (index) -+++ contrib/libs/tcmalloc/tcmalloc/cpu_cache.cc (working tree) -@@ -1031,6 +1031,20 @@ void CPUCache::PrintInPbtxt(PbtxtRegion *region) const { - } - } - -+void CPUCache::AcquireInternalLocks() { -+ for (int cpu = 0, num_cpus = absl::base_internal::NumCPUs(); cpu < num_cpus; -+ ++cpu) { -+ resize_[cpu].lock.Lock(); -+ } -+} -+ -+void CPUCache::ReleaseInternalLocks() { -+ for (int cpu = 0, num_cpus = absl::base_internal::NumCPUs(); cpu < num_cpus; -+ ++cpu) { -+ resize_[cpu].lock.Unlock(); -+ } -+} -+ - void CPUCache::PerClassResizeInfo::Init() { - state_.store(0, std::memory_order_relaxed); - } ---- contrib/libs/tcmalloc/tcmalloc/cpu_cache.h (index) -+++ contrib/libs/tcmalloc/tcmalloc/cpu_cache.h (working tree) -@@ -164,6 +164,9 @@ class CPUCache { - void Print(Printer* out) const; - void PrintInPbtxt(PbtxtRegion* region) const; - -+ void AcquireInternalLocks(); -+ void ReleaseInternalLocks(); -+ - private: - // Per-size-class freelist resizing info. - class PerClassResizeInfo { ---- contrib/libs/tcmalloc/tcmalloc/internal_malloc_extension.h (index) -+++ contrib/libs/tcmalloc/tcmalloc/internal_malloc_extension.h (working tree) -@@ -116,6 +116,10 @@ ABSL_ATTRIBUTE_WEAK int64_t - MallocExtension_Internal_GetMaxTotalThreadCacheBytes(); - ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_SetMaxTotalThreadCacheBytes( - int64_t value); -+ -+ABSL_ATTRIBUTE_WEAK void -+MallocExtension_EnableForkSupport(); -+ - } - - #endif ---- contrib/libs/tcmalloc/tcmalloc/malloc_extension.cc (index) -+++ contrib/libs/tcmalloc/tcmalloc/malloc_extension.cc (working tree) -@@ -460,6 +460,14 @@ void MallocExtension::SetBackgroundReleaseRate(BytesPerSecond rate) { - #endif - } - -+void MallocExtension::EnableForkSupport() { -+#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS -+ if (&MallocExtension_EnableForkSupport != nullptr) { -+ MallocExtension_EnableForkSupport(); -+ } -+#endif -+} -+ - } // namespace tcmalloc - - // Default implementation just returns size. The expectation is that ---- contrib/libs/tcmalloc/tcmalloc/malloc_extension.h (index) -+++ contrib/libs/tcmalloc/tcmalloc/malloc_extension.h (working tree) -@@ -468,6 +468,10 @@ class MallocExtension final { - // Specifies the release rate from the page heap. ProcessBackgroundActions - // must be called for this to be operative. - static void SetBackgroundReleaseRate(BytesPerSecond rate); -+ -+ // Enables fork support. -+ // Allocator will continue to function correctly in the child, after calling fork(). -+ static void EnableForkSupport(); - }; - - } // namespace tcmalloc ---- contrib/libs/tcmalloc/tcmalloc/static_vars.cc (index) -+++ contrib/libs/tcmalloc/tcmalloc/static_vars.cc (working tree) -@@ -59,6 +59,7 @@ ABSL_CONST_INIT PageHeapAllocator - Static::bucket_allocator_; - ABSL_CONST_INIT std::atomic Static::inited_{false}; - ABSL_CONST_INIT bool Static::cpu_cache_active_ = false; -+ABSL_CONST_INIT bool Static::fork_support_enabled_ = false; - ABSL_CONST_INIT Static::PageAllocatorStorage Static::page_allocator_; - ABSL_CONST_INIT PageMap Static::pagemap_; - ABSL_CONST_INIT absl::base_internal::SpinLock guarded_page_lock( -@@ -116,6 +117,13 @@ ABSL_ATTRIBUTE_COLD ABSL_ATTRIBUTE_NOINLINE void Static::SlowInitIfNecessary() { - pagemap_.MapRootWithSmallPages(); - guardedpage_allocator_.Init(/*max_alloced_pages=*/64, /*total_pages=*/128); - inited_.store(true, std::memory_order_release); -+ -+ pageheap_lock.Unlock(); -+ pthread_atfork( -+ TCMallocPreFork, -+ TCMallocPostFork, -+ TCMallocPostFork); -+ pageheap_lock.Lock(); - } - } - ---- contrib/libs/tcmalloc/tcmalloc/static_vars.h (index) -+++ contrib/libs/tcmalloc/tcmalloc/static_vars.h (working tree) -@@ -50,6 +50,9 @@ class CPUCache; - class PageMap; - class ThreadCache; - -+void TCMallocPreFork(); -+void TCMallocPostFork(); -+ - class Static { - public: - // True if InitIfNecessary() has run to completion. -@@ -124,6 +127,9 @@ class Static { - static void ActivateCPUCache() { cpu_cache_active_ = true; } - static void DeactivateCPUCache() { cpu_cache_active_ = false; } - -+ static bool ForkSupportEnabled() { return fork_support_enabled_; } -+ static void EnableForkSupport() { fork_support_enabled_ = true; } -+ - static bool ABSL_ATTRIBUTE_ALWAYS_INLINE IsOnFastPath() { - return - #ifndef TCMALLOC_DEPRECATED_PERTHREAD -@@ -169,6 +175,7 @@ class Static { - static PageHeapAllocator bucket_allocator_; - ABSL_CONST_INIT static std::atomic inited_; - static bool cpu_cache_active_; -+ static bool fork_support_enabled_; - ABSL_CONST_INIT static PeakHeapTracker peak_heap_tracker_; - ABSL_CONST_INIT static NumaTopology - numa_topology_; ---- contrib/libs/tcmalloc/tcmalloc/system-alloc.cc (index) -+++ contrib/libs/tcmalloc/tcmalloc/system-alloc.cc (working tree) -@@ -354,6 +354,14 @@ ABSL_CONST_INIT std::atomic system_release_errors = ATOMIC_VAR_INIT(0); - - } // namespace - -+void AcquireSystemAllocLock() { -+ spinlock.Lock(); -+} -+ -+void ReleaseSystemAllocLock() { -+ spinlock.Unlock(); -+} -+ - void* SystemAlloc(size_t bytes, size_t* actual_bytes, size_t alignment, - const MemoryTag tag) { - // If default alignment is set request the minimum alignment provided by ---- contrib/libs/tcmalloc/tcmalloc/system-alloc.h (index) -+++ contrib/libs/tcmalloc/tcmalloc/system-alloc.h (working tree) -@@ -50,6 +50,9 @@ void *SystemAlloc(size_t bytes, size_t *actual_bytes, size_t alignment, - // call to SystemRelease. - int SystemReleaseErrors(); - -+void AcquireSystemAllocLock(); -+void ReleaseSystemAllocLock(); -+ - // This call is a hint to the operating system that the pages - // contained in the specified range of memory will not be used for a - // while, and can be released for use by other processes or the OS. ---- contrib/libs/tcmalloc/tcmalloc/tcmalloc.cc (index) -+++ contrib/libs/tcmalloc/tcmalloc/tcmalloc.cc (working tree) -@@ -1117,6 +1117,40 @@ extern "C" void MallocExtension_Internal_ReleaseMemoryToSystem( - } - } - -+extern "C" void MallocExtension_EnableForkSupport() { -+ Static::EnableForkSupport(); -+} -+ -+void TCMallocPreFork() { -+ if (!Static::ForkSupportEnabled()) { -+ return; -+ } -+ -+ if (Static::CPUCacheActive()) { -+ Static::cpu_cache().AcquireInternalLocks(); -+ } -+ Static::transfer_cache().AcquireInternalLocks(); -+ guarded_page_lock.Lock(); -+ release_lock.Lock(); -+ pageheap_lock.Lock(); -+ AcquireSystemAllocLock(); -+} -+ -+void TCMallocPostFork() { -+ if (!Static::ForkSupportEnabled()) { -+ return; -+ } -+ -+ ReleaseSystemAllocLock(); -+ pageheap_lock.Unlock(); -+ guarded_page_lock.Unlock(); -+ release_lock.Unlock(); -+ Static::transfer_cache().ReleaseInternalLocks(); -+ if (Static::CPUCacheActive()) { -+ Static::cpu_cache().ReleaseInternalLocks(); -+ } -+} -+ - // nallocx slow path. - // Moved to a separate function because size_class_with_alignment is not inlined - // which would cause nallocx to become non-leaf function with stack frame and ---- contrib/libs/tcmalloc/tcmalloc/tcmalloc.h (index) -+++ contrib/libs/tcmalloc/tcmalloc/tcmalloc.h (working tree) -@@ -120,4 +120,7 @@ void TCMallocInternalDeleteArrayNothrow(void* p, const std::nothrow_t&) __THROW - } - #endif - -+void TCMallocInternalAcquireLocks(); -+void TCMallocInternalReleaseLocks(); -+ - #endif // TCMALLOC_TCMALLOC_H_ ---- contrib/libs/tcmalloc/tcmalloc/transfer_cache.h (index) -+++ contrib/libs/tcmalloc/tcmalloc/transfer_cache.h (working tree) -@@ -176,6 +176,26 @@ class TransferCacheManager : public StaticForwarder { - } - } - -+ void AcquireInternalLocks() { -+ for (int i = 0; i < kNumClasses; ++i) { -+ if (implementation_ == TransferCacheImplementation::Ring) { -+ cache_[i].rbtc.AcquireInternalLocks(); -+ } else { -+ cache_[i].tc.AcquireInternalLocks(); -+ } -+ } -+ } -+ -+ void ReleaseInternalLocks() { -+ for (int i = 0; i < kNumClasses; ++i) { -+ if (implementation_ == TransferCacheImplementation::Ring) { -+ cache_[i].rbtc.ReleaseInternalLocks(); -+ } else { -+ cache_[i].tc.ReleaseInternalLocks(); -+ } -+ } -+ } -+ - void InsertRange(int size_class, absl::Span batch) { - if (implementation_ == TransferCacheImplementation::Ring) { - cache_[size_class].rbtc.InsertRange(size_class, batch); -@@ -295,6 +315,9 @@ class TransferCacheManager { - return TransferCacheImplementation::None; - } - -+ void AcquireInternalLocks() {} -+ void ReleaseInternalLocks() {} -+ - private: - CentralFreeList freelist_[kNumClasses]; - } ABSL_CACHELINE_ALIGNED; ---- contrib/libs/tcmalloc/tcmalloc/transfer_cache_internals.h (index) -+++ contrib/libs/tcmalloc/tcmalloc/transfer_cache_internals.h (working tree) -@@ -366,6 +366,18 @@ class TransferCache { - return freelist_do_not_access_directly_; - } - -+ void AcquireInternalLocks() -+ { -+ freelist().AcquireInternalLocks(); -+ lock_.Lock(); -+ } -+ -+ void ReleaseInternalLocks() -+ { -+ lock_.Unlock(); -+ freelist().ReleaseInternalLocks(); -+ } -+ - private: - // Returns first object of the i-th slot. - void **GetSlot(size_t i) ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock_) { -@@ -468,6 +480,18 @@ class RingBufferTransferCache { - - // These methods all do internal locking. - -+ void AcquireInternalLocks() -+ { -+ freelist().AcquireInternalLocks(); -+ lock_.Lock(); -+ } -+ -+ void ReleaseInternalLocks() -+ { -+ lock_.Unlock(); -+ freelist().ReleaseInternalLocks(); -+ } -+ - // Insert the specified batch into the transfer cache. N is the number of - // elements in the range. RemoveRange() is the opposite operation. - void InsertRange(int size_class, absl::Span batch) diff --git a/contrib/libs/tcmalloc/patches/userdata.patch b/contrib/libs/tcmalloc/patches/userdata.patch deleted file mode 100644 index 83373cebfe0a..000000000000 --- a/contrib/libs/tcmalloc/patches/userdata.patch +++ /dev/null @@ -1,220 +0,0 @@ ---- contrib/libs/tcmalloc/tcmalloc/internal/logging.h (index) -+++ contrib/libs/tcmalloc/tcmalloc/internal/logging.h (working tree) -@@ -67,6 +67,8 @@ struct StackTrace { - // between the previous sample and this one - size_t weight; - -+ void* user_data; -+ - template - friend H AbslHashValue(H h, const StackTrace& t) { - // As we use StackTrace as a key-value node in StackTraceTable, we only ---- contrib/libs/tcmalloc/tcmalloc/internal_malloc_extension.h (index) -+++ contrib/libs/tcmalloc/tcmalloc/internal_malloc_extension.h (working tree) -@@ -120,6 +120,12 @@ ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_SetMaxTotalThreadCacheBytes( - ABSL_ATTRIBUTE_WEAK void - MallocExtension_EnableForkSupport(); - -+ABSL_ATTRIBUTE_WEAK void -+MallocExtension_SetSampleUserDataCallbacks( -+ tcmalloc::MallocExtension::CreateSampleUserDataCallback create, -+ tcmalloc::MallocExtension::CopySampleUserDataCallback copy, -+ tcmalloc::MallocExtension::DestroySampleUserDataCallback destroy); -+ - } - - #endif ---- contrib/libs/tcmalloc/tcmalloc/malloc_extension.cc (index) -+++ contrib/libs/tcmalloc/tcmalloc/malloc_extension.cc (working tree) -@@ -468,6 +468,21 @@ void MallocExtension::EnableForkSupport() { - #endif - } - -+void MallocExtension::SetSampleUserDataCallbacks( -+ CreateSampleUserDataCallback create, -+ CopySampleUserDataCallback copy, -+ DestroySampleUserDataCallback destroy) { -+#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS -+ if (&MallocExtension_SetSampleUserDataCallbacks != nullptr) { -+ MallocExtension_SetSampleUserDataCallbacks(create, copy, destroy); -+ } -+#else -+ (void)create; -+ (void)copy; -+ (void)destroy; -+#endif -+} -+ - } // namespace tcmalloc - - // Default implementation just returns size. The expectation is that ---- contrib/libs/tcmalloc/tcmalloc/malloc_extension.h (index) -+++ contrib/libs/tcmalloc/tcmalloc/malloc_extension.h (working tree) -@@ -94,6 +94,8 @@ class Profile final { - - int depth; - void* stack[kMaxStackDepth]; -+ -+ void* user_data; - }; - - void Iterate(absl::FunctionRef f) const; -@@ -472,6 +474,16 @@ class MallocExtension final { - // Enables fork support. - // Allocator will continue to function correctly in the child, after calling fork(). - static void EnableForkSupport(); -+ -+ using CreateSampleUserDataCallback = void*(); -+ using CopySampleUserDataCallback = void*(void*); -+ using DestroySampleUserDataCallback = void(void*); -+ -+ // Sets callbacks for lifetime control of custom user data attached to allocation samples -+ static void SetSampleUserDataCallbacks( -+ CreateSampleUserDataCallback create, -+ CopySampleUserDataCallback copy, -+ DestroySampleUserDataCallback destroy); - }; - - } // namespace tcmalloc ---- contrib/libs/tcmalloc/tcmalloc/peak_heap_tracker.cc (index) -+++ contrib/libs/tcmalloc/tcmalloc/peak_heap_tracker.cc (working tree) -@@ -55,6 +55,7 @@ void PeakHeapTracker::MaybeSaveSample() { - StackTrace *t = peak_sampled_span_stacks_, *next = nullptr; - while (t != nullptr) { - next = reinterpret_cast(t->stack[kMaxStackDepth - 1]); -+ Static::DestroySampleUserData(t->user_data); - Static::stacktrace_allocator().Delete(t); - t = next; - } -@@ -63,7 +64,9 @@ void PeakHeapTracker::MaybeSaveSample() { - for (Span* s : Static::sampled_objects_) { - t = Static::stacktrace_allocator().New(); - -- *t = *s->sampled_stack(); -+ StackTrace* sampled_stack = s->sampled_stack(); -+ *t = *sampled_stack; -+ t->user_data = Static::CopySampleUserData(sampled_stack->user_data); - if (t->depth == kMaxStackDepth) { - t->depth = kMaxStackDepth - 1; - } ---- contrib/libs/tcmalloc/tcmalloc/stack_trace_table.cc (index) -+++ contrib/libs/tcmalloc/tcmalloc/stack_trace_table.cc (working tree) -@@ -73,6 +73,7 @@ StackTraceTable::~StackTraceTable() { - Bucket* b = table_[i]; - while (b != nullptr) { - Bucket* next = b->next; -+ Static::DestroySampleUserData(b->trace.user_data); - Static::bucket_allocator().Delete(b); - b = next; - } -@@ -104,6 +105,7 @@ void StackTraceTable::AddTrace(double count, const StackTrace& t) { - b = Static::bucket_allocator().New(); - b->hash = h; - b->trace = t; -+ b->trace.user_data = Static::CopySampleUserData(t.user_data); - b->count = count; - b->total_weight = t.weight * count; - b->next = table_[idx]; -@@ -135,6 +137,8 @@ void StackTraceTable::Iterate( - e.requested_alignment = b->trace.requested_alignment; - e.allocated_size = allocated_size; - -+ e.user_data = b->trace.user_data; -+ - e.depth = b->trace.depth; - static_assert(kMaxStackDepth <= Profile::Sample::kMaxStackDepth, - "Profile stack size smaller than internal stack sizes"); ---- contrib/libs/tcmalloc/tcmalloc/static_vars.cc (index) -+++ contrib/libs/tcmalloc/tcmalloc/static_vars.cc (working tree) -@@ -60,6 +60,12 @@ ABSL_CONST_INIT PageHeapAllocator - ABSL_CONST_INIT std::atomic Static::inited_{false}; - ABSL_CONST_INIT bool Static::cpu_cache_active_ = false; - ABSL_CONST_INIT bool Static::fork_support_enabled_ = false; -+ABSL_CONST_INIT Static::CreateSampleUserDataCallback* -+ Static::create_sample_user_data_callback_ = nullptr; -+ABSL_CONST_INIT Static::CopySampleUserDataCallback* -+ Static::copy_sample_user_data_callback_ = nullptr; -+ABSL_CONST_INIT Static::DestroySampleUserDataCallback* -+ Static::destroy_sample_user_data_callback_ = nullptr; - ABSL_CONST_INIT Static::PageAllocatorStorage Static::page_allocator_; - ABSL_CONST_INIT PageMap Static::pagemap_; - ABSL_CONST_INIT absl::base_internal::SpinLock guarded_page_lock( ---- contrib/libs/tcmalloc/tcmalloc/static_vars.h (index) -+++ contrib/libs/tcmalloc/tcmalloc/static_vars.h (working tree) -@@ -130,6 +130,34 @@ class Static { - static bool ForkSupportEnabled() { return fork_support_enabled_; } - static void EnableForkSupport() { fork_support_enabled_ = true; } - -+ using CreateSampleUserDataCallback = void*(); -+ using CopySampleUserDataCallback = void*(void*); -+ using DestroySampleUserDataCallback = void(void*); -+ -+ static void SetSampleUserDataCallbacks( -+ CreateSampleUserDataCallback create, -+ CopySampleUserDataCallback copy, -+ DestroySampleUserDataCallback destroy) { -+ create_sample_user_data_callback_ = create; -+ copy_sample_user_data_callback_ = copy; -+ destroy_sample_user_data_callback_ = destroy; -+ } -+ -+ static void* CreateSampleUserData() { -+ if (create_sample_user_data_callback_) -+ return create_sample_user_data_callback_(); -+ return nullptr; -+ } -+ static void* CopySampleUserData(void* user_data) { -+ if (copy_sample_user_data_callback_) -+ return copy_sample_user_data_callback_(user_data); -+ return nullptr; -+ } -+ static void DestroySampleUserData(void* user_data) { -+ if (destroy_sample_user_data_callback_) -+ destroy_sample_user_data_callback_(user_data); -+ } -+ - static bool ABSL_ATTRIBUTE_ALWAYS_INLINE IsOnFastPath() { - return - #ifndef TCMALLOC_DEPRECATED_PERTHREAD -@@ -176,6 +204,9 @@ class Static { - ABSL_CONST_INIT static std::atomic inited_; - static bool cpu_cache_active_; - static bool fork_support_enabled_; -+ static CreateSampleUserDataCallback* create_sample_user_data_callback_; -+ static CopySampleUserDataCallback* copy_sample_user_data_callback_; -+ static DestroySampleUserDataCallback* destroy_sample_user_data_callback_; - ABSL_CONST_INIT static PeakHeapTracker peak_heap_tracker_; - ABSL_CONST_INIT static NumaTopology - numa_topology_; ---- contrib/libs/tcmalloc/tcmalloc/tcmalloc.cc (index) -+++ contrib/libs/tcmalloc/tcmalloc/tcmalloc.cc (working tree) -@@ -1151,6 +1151,13 @@ void TCMallocPostFork() { - } - } - -+extern "C" void MallocExtension_SetSampleUserDataCallbacks( -+ MallocExtension::CreateSampleUserDataCallback create, -+ MallocExtension::CopySampleUserDataCallback copy, -+ MallocExtension::DestroySampleUserDataCallback destroy) { -+ Static::SetSampleUserDataCallbacks(create, copy, destroy); -+} -+ - // nallocx slow path. - // Moved to a separate function because size_class_with_alignment is not inlined - // which would cause nallocx to become non-leaf function with stack frame and -@@ -1500,6 +1507,7 @@ static void* SampleifyAllocation(size_t requested_size, size_t weight, - tmp.requested_alignment = requested_alignment; - tmp.allocated_size = allocated_size; - tmp.weight = weight; -+ tmp.user_data = Static::CreateSampleUserData(); - - { - absl::base_internal::SpinLockHolder h(&pageheap_lock); -@@ -1629,6 +1637,7 @@ static void do_free_pages(void* ptr, const PageId p) { - 1); - } - notify_sampled_alloc = true; -+ Static::DestroySampleUserData(st->user_data); - Static::stacktrace_allocator().Delete(st); - } - if (IsSampledMemory(ptr)) { diff --git a/contrib/libs/tcmalloc/patches/yandex.patch b/contrib/libs/tcmalloc/patches/yandex.patch deleted file mode 100644 index 12d11f2dadf6..000000000000 --- a/contrib/libs/tcmalloc/patches/yandex.patch +++ /dev/null @@ -1,91 +0,0 @@ -commit ab4069ebdd376db4d32c29e1a2414565ec849249 -author: prime -date: 2021-10-07T14:52:42+03:00 - - Apply yandex patches - ---- contrib/libs/tcmalloc/tcmalloc/cpu_cache.cc (5096009d22199137186c9a972bc88409d8ebd513) -+++ contrib/libs/tcmalloc/tcmalloc/cpu_cache.cc (ab4069ebdd376db4d32c29e1a2414565ec849249) -@@ -1112,6 +1112,11 @@ extern "C" bool MallocExtension_Internal_GetPerCpuCachesActive() { - return tcmalloc::tcmalloc_internal::Static::CPUCacheActive(); - } - -+extern "C" void MallocExtension_Internal_DeactivatePerCpuCaches() { -+ tcmalloc::tcmalloc_internal::Parameters::set_per_cpu_caches(false); -+ tcmalloc::tcmalloc_internal::Static::DeactivateCPUCache(); -+} -+ - extern "C" int32_t MallocExtension_Internal_GetMaxPerCpuCacheSize() { - return tcmalloc::tcmalloc_internal::Parameters::max_per_cpu_cache_size(); - } ---- contrib/libs/tcmalloc/tcmalloc/internal_malloc_extension.h (5096009d22199137186c9a972bc88409d8ebd513) -+++ contrib/libs/tcmalloc/tcmalloc/internal_malloc_extension.h (ab4069ebdd376db4d32c29e1a2414565ec849249) -@@ -75,6 +75,7 @@ ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_GetMemoryLimit( - ABSL_ATTRIBUTE_WEAK bool MallocExtension_Internal_GetNumericProperty( - const char* name_data, size_t name_size, size_t* value); - ABSL_ATTRIBUTE_WEAK bool MallocExtension_Internal_GetPerCpuCachesActive(); -+ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_DeactivatePerCpuCaches(); - ABSL_ATTRIBUTE_WEAK int32_t MallocExtension_Internal_GetMaxPerCpuCacheSize(); - ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_GetSkipSubreleaseInterval( - absl::Duration* ret); ---- contrib/libs/tcmalloc/tcmalloc/malloc_extension.cc (5096009d22199137186c9a972bc88409d8ebd513) -+++ contrib/libs/tcmalloc/tcmalloc/malloc_extension.cc (ab4069ebdd376db4d32c29e1a2414565ec849249) -@@ -287,6 +287,16 @@ bool MallocExtension::PerCpuCachesActive() { - #endif - } - -+void MallocExtension::DeactivatePerCpuCaches() { -+#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS -+ if (MallocExtension_Internal_DeactivatePerCpuCaches == nullptr) { -+ return; -+ } -+ -+ MallocExtension_Internal_DeactivatePerCpuCaches(); -+#endif -+} -+ - int32_t MallocExtension::GetMaxPerCpuCacheSize() { - #if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS - if (MallocExtension_Internal_GetMaxPerCpuCacheSize == nullptr) { ---- contrib/libs/tcmalloc/tcmalloc/malloc_extension.h (5096009d22199137186c9a972bc88409d8ebd513) -+++ contrib/libs/tcmalloc/tcmalloc/malloc_extension.h (ab4069ebdd376db4d32c29e1a2414565ec849249) -@@ -329,6 +329,11 @@ class MallocExtension final { - // Gets whether TCMalloc is using per-CPU caches. - static bool PerCpuCachesActive(); - -+ // Extension for unified agent. -+ // -+ // Should be removed in the future https://st.yandex-team.ru/UNIFIEDAGENT-321 -+ static void DeactivatePerCpuCaches(); -+ - // Gets the current maximum cache size per CPU cache. - static int32_t GetMaxPerCpuCacheSize(); - // Sets the maximum cache size per CPU cache. This is a per-core limit. ---- contrib/libs/tcmalloc/tcmalloc/static_vars.h (5096009d22199137186c9a972bc88409d8ebd513) -+++ contrib/libs/tcmalloc/tcmalloc/static_vars.h (ab4069ebdd376db4d32c29e1a2414565ec849249) -@@ -122,6 +122,7 @@ class Static { - return cpu_cache_active_; - } - static void ActivateCPUCache() { cpu_cache_active_ = true; } -+ static void DeactivateCPUCache() { cpu_cache_active_ = false; } - - static bool ABSL_ATTRIBUTE_ALWAYS_INLINE IsOnFastPath() { - return ---- contrib/libs/tcmalloc/tcmalloc/tcmalloc.cc (5096009d22199137186c9a972bc88409d8ebd513) -+++ contrib/libs/tcmalloc/tcmalloc/tcmalloc.cc (ab4069ebdd376db4d32c29e1a2414565ec849249) -@@ -2210,14 +2210,7 @@ extern "C" void* TCMallocInternalNewArray(size_t size) - TCMALLOC_ALIAS(TCMallocInternalNew); - #else - { -- void* p = fast_alloc(CppPolicy().WithoutHooks(), size); -- // We keep this next instruction out of fast_alloc for a reason: when -- // it's in, and new just calls fast_alloc, the optimizer may fold the -- // new call into fast_alloc, which messes up our whole section-based -- // stacktracing (see ABSL_ATTRIBUTE_SECTION, above). This ensures fast_alloc -- // isn't the last thing this fn calls, and prevents the folding. -- MallocHook::InvokeNewHook(p, size); -- return p; -+ return fast_alloc(CppPolicy().WithoutHooks(), size); - } - #endif // TCMALLOC_ALIAS - diff --git a/contrib/libs/tcmalloc/small_but_slow/ya.make b/contrib/libs/tcmalloc/small_but_slow/ya.make index 6a21988172f3..b0259ab095d9 100644 --- a/contrib/libs/tcmalloc/small_but_slow/ya.make +++ b/contrib/libs/tcmalloc/small_but_slow/ya.make @@ -5,6 +5,7 @@ WITHOUT_LICENSE_TEXTS() VERSION(2021-10-04-45c59ccbc062ac96d83710205033c656e490d376) LICENSE(Apache-2.0) + ALLOCATOR_IMPL() SRCDIR(contrib/libs/tcmalloc) diff --git a/contrib/libs/tcmalloc/tcmalloc/.github/CODEOWNERS b/contrib/libs/tcmalloc/tcmalloc/.github/CODEOWNERS new file mode 100644 index 000000000000..df21f0476bfb --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/.github/CODEOWNERS @@ -0,0 +1,5 @@ +# Default owners +* @ckennelly + +# Documentation +docs/* @manshreck diff --git a/contrib/libs/tcmalloc/tcmalloc/.github/workflows/ci.yml b/contrib/libs/tcmalloc/tcmalloc/.github/workflows/ci.yml new file mode 100644 index 000000000000..e4a93a4077fd --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/.github/workflows/ci.yml @@ -0,0 +1,63 @@ +# Copyright 2022 The TCMalloc Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +name: ci + +on: + push: + branches: + - master + + pull_request: + +jobs: + Linux: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + compiler: + - g++ + - clang++ + + name: "Build/Test ${{matrix.compiler}}" + steps: + - name: Cancel previous + uses: styfle/cancel-workflow-action@0.8.0 + with: + access_token: ${{ github.token }} + + - name: Prepare + run: | + sudo apt-get update -qq + sudo apt install -y g++ clang + + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Create Cache Timestamp + id: cache_timestamp + uses: nanzm/get-time-action@v1.1 + with: + format: 'YYYY-MM-DD-HH-mm-ss' + + - name: Mount bazel cache + uses: actions/cache@v2 + with: + path: "/home/runner/.cache/bazel" + key: bazelcache_${{matrix.compiler}}_${{ steps.cache_timestamp.outputs.time }} + restore-keys: bazelcache_${{matrix.compiler}}_ + + - name: Tests + run: CXX=${{matrix.compiler}} bazel test --test_output=errors //... diff --git a/contrib/libs/tcmalloc/tcmalloc/BUILD b/contrib/libs/tcmalloc/tcmalloc/BUILD index e618b85eec2a..feaf22b3c01b 100644 --- a/contrib/libs/tcmalloc/tcmalloc/BUILD +++ b/contrib/libs/tcmalloc/tcmalloc/BUILD @@ -18,9 +18,8 @@ # https://github.com/google/tcmalloc/tree/master/docs/design.md for a high-level description of # how this malloc works. -load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test") load("//tcmalloc:copts.bzl", "TCMALLOC_DEFAULT_COPTS") -load("//tcmalloc:variants.bzl", "create_tcmalloc_benchmark", "create_tcmalloc_testsuite") +load("//tcmalloc:variants.bzl", "create_tcmalloc_benchmark", "create_tcmalloc_libraries", "create_tcmalloc_testsuite") package(default_visibility = ["//visibility:private"]) @@ -33,10 +32,7 @@ config_setting( flag_values = { "@bazel_tools//tools/cpp:compiler": "clang", }, - visibility = [ - "//tcmalloc/internal:__subpackages__", - "//tcmalloc/testing:__subpackages__", - ], + visibility = ["//tcmalloc:__subpackages__"], ) cc_library( @@ -47,11 +43,18 @@ cc_library( "experiment_config.h", ], copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc/testing:__pkg__", + ], deps = [ ":malloc_extension", + "//tcmalloc/internal:config", "//tcmalloc/internal:environment", "//tcmalloc/internal:logging", + "@com_google_absl//absl/base", "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/functional:function_ref", + "@com_google_absl//absl/hash", "@com_google_absl//absl/strings", "@com_google_absl//absl/types:optional", ], @@ -62,23 +65,28 @@ cc_library( tcmalloc_deps = [ ":experiment", ":malloc_extension", + ":malloc_tracing_extension", "@com_google_absl//absl/base", "@com_google_absl//absl/base:config", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/base:dynamic_annotations", - "@com_google_absl//absl/debugging:leak_check", "@com_google_absl//absl/debugging:stacktrace", "@com_google_absl//absl/debugging:symbolize", + "//tcmalloc/selsan", "@com_google_absl//absl/memory", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", "@com_google_absl//absl/numeric:bits", "//tcmalloc/internal:config", "//tcmalloc/internal:declarations", "//tcmalloc/internal:linked_list", "//tcmalloc/internal:logging", - "//tcmalloc/internal:memory_stats", + "//tcmalloc/internal:memory_tag", "//tcmalloc/internal:optimization", "//tcmalloc/internal:percpu", + "//tcmalloc/internal:sampled_allocation", ] # This library provides tcmalloc always @@ -86,66 +94,65 @@ cc_library( name = "tcmalloc", srcs = [ "libc_override.h", - "libc_override_gcc_and_weak.h", - "libc_override_glibc.h", - "libc_override_redefine.h", "tcmalloc.cc", "tcmalloc.h", ], - copts = TCMALLOC_DEFAULT_COPTS, + copts = ["-DTCMALLOC_INTERNAL_8K_PAGES"] + TCMALLOC_DEFAULT_COPTS, linkstatic = 1, visibility = ["//visibility:public"], deps = tcmalloc_deps + [ - ":common", + ":common_8k_pages", + "//tcmalloc/internal:allocation_guard", + "//tcmalloc/internal:overflow", + "//tcmalloc/internal:page_size", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", ], alwayslink = 1, ) -# Provides tcmalloc always; use per-thread mode. cc_library( - name = "tcmalloc_deprecated_perthread", + name = "tcmalloc_internal_methods_only", srcs = [ - "libc_override.h", - "libc_override_gcc_and_weak.h", - "libc_override_glibc.h", - "libc_override_redefine.h", "tcmalloc.cc", "tcmalloc.h", ], - copts = ["-DTCMALLOC_DEPRECATED_PERTHREAD"] + TCMALLOC_DEFAULT_COPTS, - linkstatic = 1, - visibility = [ - "//tcmalloc/internal:__pkg__", - "//tcmalloc/testing:__pkg__", + copts = TCMALLOC_DEFAULT_COPTS + [ + "-DTCMALLOC_INTERNAL_METHODS_ONLY", ], + linkstatic = 1, + visibility = ["//tcmalloc:__subpackages__"], deps = tcmalloc_deps + [ - ":common_deprecated_perthread", + ":common_8k_pages", + "//tcmalloc/internal:allocation_guard", + "//tcmalloc/internal:overflow", + "//tcmalloc/internal:page_size", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", ], alwayslink = 1, ) -# An opt tcmalloc build with ASSERTs forced on (by turning off -# NDEBUG). Useful for tracking down crashes in production binaries. -# To use add malloc = "//tcmalloc:opt_with_assertions" in your -# target's build rule. +# Provides tcmalloc always; use per-thread mode. cc_library( - name = "opt_with_assertions", + name = "tcmalloc_deprecated_perthread", srcs = [ "libc_override.h", - "libc_override_gcc_and_weak.h", - "libc_override_glibc.h", - "libc_override_redefine.h", "tcmalloc.cc", "tcmalloc.h", ], - copts = [ - "-O2", - "-UNDEBUG", - ] + TCMALLOC_DEFAULT_COPTS, + copts = ["-DTCMALLOC_DEPRECATED_PERTHREAD"] + TCMALLOC_DEFAULT_COPTS, linkstatic = 1, - visibility = ["//visibility:public"], + visibility = [ + ":tcmalloc_tests", + ], deps = tcmalloc_deps + [ - ":common", + ":common_deprecated_perthread", + "//tcmalloc/internal:allocation_guard", + "//tcmalloc/internal:overflow", + "//tcmalloc/internal:page_size", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", ], alwayslink = 1, ) @@ -155,188 +162,185 @@ cc_library( hdrs = ["size_class_info.h"], copts = TCMALLOC_DEFAULT_COPTS, deps = [ - "//tcmalloc/internal:logging", + "//tcmalloc/internal:config", + "@com_google_absl//absl/types:span", ], ) -# List of common source files used by the various tcmalloc libraries. -common_srcs = [ - "arena.cc", - "arena.h", - "background.cc", - "central_freelist.cc", - "central_freelist.h", - "common.cc", - "common.h", - "cpu_cache.cc", - "cpu_cache.h", - "experimental_pow2_below64_size_class.cc", - "experimental_pow2_size_class.cc", - "legacy_size_classes.cc", - "guarded_page_allocator.h", - "guarded_page_allocator.cc", - "huge_address_map.cc", - "huge_allocator.cc", - "huge_allocator.h", - "huge_cache.cc", - "huge_cache.h", - "huge_region.h", - "huge_page_aware_allocator.cc", - "huge_page_aware_allocator.h", - "huge_page_filler.h", - "huge_pages.h", - "page_allocator.cc", - "page_allocator.h", - "page_allocator_interface.cc", - "page_allocator_interface.h", - "page_heap.cc", - "page_heap.h", - "page_heap_allocator.h", - "pagemap.cc", - "pagemap.h", - "parameters.cc", - "peak_heap_tracker.cc", - "sampler.cc", - "sampler.h", - "size_classes.cc", - "span.cc", - "span.h", - "span_stats.h", - "stack_trace_table.cc", - "stack_trace_table.h", - "static_vars.cc", - "static_vars.h", - "stats.cc", - "system-alloc.cc", - "system-alloc.h", - "thread_cache.cc", - "thread_cache.h", - "tracking.h", - "transfer_cache_stats.h", - "transfer_cache.cc", - "transfer_cache.h", - "transfer_cache_internals.h", -] - -common_hdrs = [ - "arena.h", - "central_freelist.h", - "common.h", - "cpu_cache.h", - "guarded_page_allocator.h", - "huge_address_map.h", - "huge_allocator.h", - "tcmalloc_policy.h", - "huge_cache.h", - "huge_page_filler.h", - "huge_pages.h", - "huge_region.h", - "huge_page_aware_allocator.h", - "page_allocator.h", - "page_allocator_interface.h", - "page_heap.h", - "page_heap_allocator.h", - "pages.h", - "pagemap.h", - "parameters.h", - "peak_heap_tracker.h", - "sampler.h", - "span.h", - "span_stats.h", - "stack_trace_table.h", - "stats.h", - "static_vars.h", - "system-alloc.h", - "thread_cache.h", - "tracking.h", - "transfer_cache_stats.h", - "transfer_cache.h", - "transfer_cache_internals.h", -] - -common_deps = [ - ":experiment", - ":malloc_extension", - ":noruntime_size_classes", - ":size_class_info", - "@com_google_absl//absl/algorithm:container", - "@com_google_absl//absl/base", - "@com_google_absl//absl/base:config", - "@com_google_absl//absl/base:core_headers", - "@com_google_absl//absl/base:dynamic_annotations", - "@com_google_absl//absl/container:fixed_array", - "@com_google_absl//absl/debugging:debugging_internal", - "@com_google_absl//absl/debugging:stacktrace", - "@com_google_absl//absl/debugging:symbolize", - "@com_google_absl//absl/synchronization", - "@com_google_absl//absl/hash:hash", - "@com_google_absl//absl/memory", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/strings:str_format", - "@com_google_absl//absl/time", - "@com_google_absl//absl/types:optional", - "@com_google_absl//absl/types:span", - "//tcmalloc/internal:atomic_stats_counter", - "@com_google_absl//absl/numeric:bits", - "//tcmalloc/internal:config", - "//tcmalloc/internal:declarations", - "//tcmalloc/internal:environment", - "//tcmalloc/internal:linked_list", - "//tcmalloc/internal:logging", - "//tcmalloc/internal:mincore", - "//tcmalloc/internal:numa", - "//tcmalloc/internal:cache_topology", - "//tcmalloc/internal:optimization", - "//tcmalloc/internal:parameter_accessors", - "//tcmalloc/internal:percpu", - "//tcmalloc/internal:percpu_tcmalloc", - "//tcmalloc/internal:range_tracker", - "//tcmalloc/internal:timeseries_tracker", - "//tcmalloc/internal:util", -] - -cc_library( +create_tcmalloc_libraries( name = "common", - srcs = common_srcs, - hdrs = common_hdrs, + srcs = [ + "allocation_sample.cc", + "allocation_sampling.cc", + "arena.cc", + "arena.h", + "background.cc", + "central_freelist.cc", + "central_freelist.h", + "common.cc", + "common.h", + "cpu_cache.cc", + "cpu_cache.h", + "deallocation_profiler.cc", + "experimental_pow2_size_class.cc", + "global_stats.cc", + "guarded_allocations.h", + "guarded_page_allocator.cc", + "guarded_page_allocator.h", + "hinted_tracker_lists.h", + "huge_address_map.cc", + "huge_allocator.cc", + "huge_allocator.h", + "huge_cache.cc", + "huge_cache.h", + "huge_page_aware_allocator.cc", + "huge_page_aware_allocator.h", + "huge_page_filler.h", + "huge_page_subrelease.h", + "huge_pages.h", + "huge_region.h", + "legacy_size_classes.cc", + "metadata_object_allocator.h", + "page_allocator.cc", + "page_allocator.h", + "page_allocator_interface.cc", + "page_allocator_interface.h", + "pagemap.cc", + "pagemap.h", + "parameters.cc", + "peak_heap_tracker.cc", + "reuse_size_classes.cc", + "sampler.cc", + "sampler.h", + "segv_handler.cc", + "segv_handler.h", + "size_classes.cc", + "sizemap.cc", + "span.cc", + "span.h", + "span_stats.h", + "stack_trace_table.cc", + "stack_trace_table.h", + "static_vars.cc", + "static_vars.h", + "stats.cc", + "system-alloc.cc", + "system-alloc.h", + "thread_cache.cc", + "thread_cache.h", + "transfer_cache.cc", + "transfer_cache.h", + "transfer_cache_internals.h", + "transfer_cache_stats.h", + ], + hdrs = [ + "allocation_sample.h", + "allocation_sampling.h", + "arena.h", + "central_freelist.h", + "common.h", + "cpu_cache.h", + "deallocation_profiler.h", + "global_stats.h", + "guarded_allocations.h", + "guarded_page_allocator.h", + "hinted_tracker_lists.h", + "huge_address_map.h", + "huge_allocator.h", + "huge_cache.h", + "huge_page_aware_allocator.h", + "huge_page_filler.h", + "huge_page_subrelease.h", + "huge_pages.h", + "huge_region.h", + "metadata_object_allocator.h", + "page_allocator.h", + "page_allocator_interface.h", + "pagemap.h", + "pages.h", + "parameters.h", + "peak_heap_tracker.h", + "sampler.h", + "segv_handler.h", + "sizemap.h", + "span.h", + "span_stats.h", + "stack_trace_table.h", + "static_vars.h", + "stats.h", + "system-alloc.h", + "tcmalloc_policy.h", + "thread_cache.h", + "transfer_cache.h", + "transfer_cache_internals.h", + "transfer_cache_stats.h", + ], copts = TCMALLOC_DEFAULT_COPTS, linkstatic = 1, - visibility = ["//tcmalloc:tcmalloc_tests"], - deps = common_deps, - alwayslink = 1, -) - -cc_library( - name = "common_deprecated_perthread", - srcs = common_srcs, - hdrs = common_hdrs, - copts = ["-DTCMALLOC_DEPRECATED_PERTHREAD"] + TCMALLOC_DEFAULT_COPTS, - linkstatic = 1, - deps = common_deps, - alwayslink = 1, -) - -# TEMPORARY. WILL BE REMOVED. -# Add a dep to this if you want your binary to use hugepage-aware -# allocator. -cc_library( - name = "want_hpaa", - srcs = ["want_hpaa.cc"], - copts = ["-g0"] + TCMALLOC_DEFAULT_COPTS, - visibility = ["//visibility:public"], + visibility = [":tcmalloc_tests"], deps = [ + ":experiment", + ":malloc_extension", + ":malloc_tracing_extension", + ":metadata_allocator", + ":size_class_info", + "//tcmalloc/internal:allocation_guard", + "//tcmalloc/internal:atomic_stats_counter", + "//tcmalloc/internal:cache_topology", + "//tcmalloc/internal:clock", "//tcmalloc/internal:config", + "//tcmalloc/internal:cpu_utils", + "//tcmalloc/internal:environment", + "//tcmalloc/internal:explicitly_constructed", + "//tcmalloc/internal:exponential_biased", + "//tcmalloc/internal:linked_list", + "//tcmalloc/internal:logging", + "//tcmalloc/internal:memory_stats", + "//tcmalloc/internal:memory_tag", + "//tcmalloc/internal:mincore", + "//tcmalloc/internal:mismatched_delete_state", + "//tcmalloc/internal:numa", + "//tcmalloc/internal:optimization", + "//tcmalloc/internal:page_size", + "//tcmalloc/internal:pageflags", + "//tcmalloc/internal:parameter_accessors", + "//tcmalloc/internal:percpu", + "//tcmalloc/internal:percpu_tcmalloc", + "//tcmalloc/internal:prefetch", + "//tcmalloc/internal:range_tracker", + "//tcmalloc/internal:sampled_allocation", + "//tcmalloc/internal:sampled_allocation_recorder", + "//tcmalloc/internal:stacktrace_filter", + "//tcmalloc/internal:sysinfo", + "//tcmalloc/internal:timeseries_tracker", + "//tcmalloc/internal:util", + "//tcmalloc/selsan", + "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/base", "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/base:dynamic_annotations", + "@com_google_absl//absl/container:fixed_array", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/debugging:stacktrace", + "@com_google_absl//absl/functional:function_ref", + "@com_google_absl//absl/hash", + "@com_google_absl//absl/memory", + "@com_google_absl//absl/numeric:bits", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:optional", + "@com_google_absl//absl/types:span", ], alwayslink = 1, ) # TEMPORARY. WILL BE REMOVED. # Add a dep to this if you want your binary to use hugepage-aware -# allocator with hpaa_subrelease=true. +# allocator. cc_library( - name = "want_hpaa_subrelease", - srcs = ["want_hpaa_subrelease.cc"], + name = "want_hpaa", + srcs = ["want_hpaa.cc"], copts = ["-g0"] + TCMALLOC_DEFAULT_COPTS, visibility = ["//visibility:public"], deps = [ @@ -346,32 +350,25 @@ cc_library( alwayslink = 1, ) -# TEMPORARY. WILL BE REMOVED. -# Add a dep to this if you want your binary to not use hugepage-aware -# allocator. cc_library( - name = "want_no_hpaa", - srcs = ["want_no_hpaa.cc"], + # TODO(b/304135905): Remove this opt-out. + name = "want_disable_tcmalloc_big_span", + srcs = ["want_disable_tcmalloc_big_span.cc"], copts = ["-g0"] + TCMALLOC_DEFAULT_COPTS, - visibility = ["//tcmalloc/testing:__pkg__"], - deps = [ - "//tcmalloc/internal:config", - "@com_google_absl//absl/base:core_headers", - ], + visibility = ["//visibility:public"], + deps = ["@com_google_absl//absl/base:core_headers"], alwayslink = 1, ) -# TEMPORARY. WILL BE REMOVED. -# Add a dep to this if you want your binary to use old span sizes. cc_library( - name = "want_legacy_spans", - srcs = ["want_legacy_spans.cc"], + # TODO(b/199203282, b/296281171): Remove this opt-out. + name = "want_disable_huge_region_more_often", + srcs = ["want_disable_huge_region_more_often.cc"], copts = ["-g0"] + TCMALLOC_DEFAULT_COPTS, - visibility = ["//tcmalloc/testing:__pkg__"], - deps = [ - "//tcmalloc/internal:config", - "@com_google_absl//absl/base:core_headers", + visibility = [ + "//tcmalloc/testing:__pkg__", ], + deps = ["@com_google_absl//absl/base:core_headers"], alwayslink = 1, ) @@ -393,135 +390,78 @@ cc_library( alwayslink = 1, ) -cc_library( - name = "runtime_size_classes", - srcs = ["runtime_size_classes.cc"], - hdrs = ["runtime_size_classes.h"], - copts = TCMALLOC_DEFAULT_COPTS, - visibility = ["//visibility:private"], - deps = [ - ":size_class_info", - "//tcmalloc/internal:environment", - "//tcmalloc/internal:logging", - "@com_google_absl//absl/base:core_headers", - "@com_google_absl//absl/strings", - ], - alwayslink = 1, -) - -cc_library( - name = "noruntime_size_classes", - srcs = ["noruntime_size_classes.cc"], - hdrs = ["runtime_size_classes.h"], - copts = TCMALLOC_DEFAULT_COPTS, - deps = [ - ":size_class_info", - "@com_google_absl//absl/base:core_headers", - "@com_google_absl//absl/strings", - ], - alwayslink = 1, -) - # TCMalloc with large pages is usually faster but fragmentation is higher. See # https://github.com/google/tcmalloc/tree/master/docs/tuning.md for more details. cc_library( name = "tcmalloc_large_pages", srcs = [ "libc_override.h", - "libc_override_gcc_and_weak.h", - "libc_override_glibc.h", - "libc_override_redefine.h", "tcmalloc.cc", "tcmalloc.h", ], - copts = ["-DTCMALLOC_LARGE_PAGES"] + TCMALLOC_DEFAULT_COPTS, + copts = ["-DTCMALLOC_INTERNAL_32K_PAGES"] + TCMALLOC_DEFAULT_COPTS, linkstatic = 1, visibility = ["//visibility:public"], deps = tcmalloc_deps + [ ":common_large_pages", + "//tcmalloc/internal:allocation_guard", + "//tcmalloc/internal:overflow", + "//tcmalloc/internal:page_size", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", ], alwayslink = 1, ) -cc_library( - name = "common_large_pages", - srcs = common_srcs, - hdrs = common_hdrs, - copts = ["-DTCMALLOC_LARGE_PAGES"] + TCMALLOC_DEFAULT_COPTS, - linkstatic = 1, - visibility = ["//tcmalloc:tcmalloc_tests"], - deps = common_deps, - alwayslink = 1, -) - # TCMalloc with 256k pages is usually faster but fragmentation is higher. See # https://github.com/google/tcmalloc/tree/master/docs/tuning.md for more details. cc_library( name = "tcmalloc_256k_pages", srcs = [ "libc_override.h", - "libc_override_gcc_and_weak.h", - "libc_override_glibc.h", - "libc_override_redefine.h", "tcmalloc.cc", "tcmalloc.h", ], - copts = ["-DTCMALLOC_256K_PAGES"] + TCMALLOC_DEFAULT_COPTS, + copts = ["-DTCMALLOC_INTERNAL_256K_PAGES"] + TCMALLOC_DEFAULT_COPTS, linkstatic = 1, visibility = ["//visibility:public"], deps = tcmalloc_deps + [ ":common_256k_pages", + "//tcmalloc/internal:allocation_guard", + "//tcmalloc/internal:overflow", + "//tcmalloc/internal:page_size", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", ], alwayslink = 1, ) cc_library( - name = "common_256k_pages", - srcs = common_srcs, - hdrs = common_hdrs, - copts = ["-DTCMALLOC_256K_PAGES"] + TCMALLOC_DEFAULT_COPTS, - linkstatic = 1, - visibility = ["//tcmalloc:tcmalloc_tests"], - deps = common_deps, - alwayslink = 1, -) - -cc_library( - name = "tcmalloc_256k_pages_and_numa", + name = "tcmalloc_256k_pages_numa_aware", srcs = [ "libc_override.h", - "libc_override_gcc_and_weak.h", - "libc_override_glibc.h", - "libc_override_redefine.h", "tcmalloc.cc", "tcmalloc.h", ], copts = [ - "-DTCMALLOC_256K_PAGES", - "-DTCMALLOC_NUMA_AWARE", + "-DTCMALLOC_INTERNAL_256K_PAGES", + "-DTCMALLOC_INTERNAL_NUMA_AWARE", ] + TCMALLOC_DEFAULT_COPTS, linkstatic = 1, - visibility = ["//tcmalloc/testing:__pkg__"], + visibility = [ + ":tcmalloc_tests", + ], deps = tcmalloc_deps + [ - ":common_256k_pages_and_numa", + ":common_256k_pages_numa_aware", + "//tcmalloc/internal:allocation_guard", + "//tcmalloc/internal:overflow", + "//tcmalloc/internal:page_size", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", ], alwayslink = 1, ) -cc_library( - name = "common_256k_pages_and_numa", - srcs = common_srcs, - hdrs = common_hdrs, - copts = [ - "-DTCMALLOC_256K_PAGES", - "-DTCMALLOC_NUMA_AWARE", - ] + TCMALLOC_DEFAULT_COPTS, - linkstatic = 1, - visibility = ["//tcmalloc:tcmalloc_tests"], - deps = common_deps, - alwayslink = 1, -) - # TCMalloc small-but-slow is a a version of TCMalloc that chooses to minimize # fragmentation at a *severe* cost to performance. It should be used by # applications that have significant memory constraints, but don't need to @@ -532,32 +472,23 @@ cc_library( name = "tcmalloc_small_but_slow", srcs = [ "libc_override.h", - "libc_override_gcc_and_weak.h", - "libc_override_glibc.h", - "libc_override_redefine.h", "tcmalloc.cc", "tcmalloc.h", ], - copts = ["-DTCMALLOC_SMALL_BUT_SLOW"] + TCMALLOC_DEFAULT_COPTS, + copts = ["-DTCMALLOC_INTERNAL_SMALL_BUT_SLOW"] + TCMALLOC_DEFAULT_COPTS, linkstatic = 1, - visibility = ["//visibility:public"], + visibility = ["//tcmalloc:__subpackages__"], deps = tcmalloc_deps + [ ":common_small_but_slow", + "//tcmalloc/internal:allocation_guard", + "//tcmalloc/internal:overflow", + "//tcmalloc/internal:page_size", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", ], alwayslink = 1, ) -cc_library( - name = "common_small_but_slow", - srcs = common_srcs, - hdrs = common_hdrs, - copts = ["-DTCMALLOC_SMALL_BUT_SLOW"] + TCMALLOC_DEFAULT_COPTS, - linkstatic = 1, - visibility = ["//tcmalloc:tcmalloc_tests"], - deps = common_deps, - alwayslink = 1, -) - # TCMalloc with NUMA awareness compiled in. Note that by default NUMA awareness # will still be disabled at runtime - this default can be changed by adding a # dependency upon want_numa_aware, or overridden by setting the @@ -566,29 +497,44 @@ cc_library( name = "tcmalloc_numa_aware", srcs = [ "libc_override.h", - "libc_override_gcc_and_weak.h", - "libc_override_glibc.h", - "libc_override_redefine.h", "tcmalloc.cc", "tcmalloc.h", ], - copts = ["-DTCMALLOC_NUMA_AWARE"] + TCMALLOC_DEFAULT_COPTS, + copts = ["-DTCMALLOC_INTERNAL_NUMA_AWARE"] + TCMALLOC_DEFAULT_COPTS, linkstatic = 1, visibility = ["//tcmalloc/testing:__pkg__"], deps = tcmalloc_deps + [ ":common_numa_aware", + "//tcmalloc/internal:allocation_guard", + "//tcmalloc/internal:overflow", + "//tcmalloc/internal:page_size", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", ], alwayslink = 1, ) cc_library( - name = "common_numa_aware", - srcs = common_srcs, - hdrs = common_hdrs, - copts = ["-DTCMALLOC_NUMA_AWARE"] + TCMALLOC_DEFAULT_COPTS, + name = "tcmalloc_legacy_locking", + srcs = [ + "libc_override.h", + "tcmalloc.cc", + "tcmalloc.h", + ], + copts = [ + "-DTCMALLOC_INTERNAL_8K_PAGES", + "-DTCMALLOC_INTERNAL_LEGACY_LOCKING", + ] + TCMALLOC_DEFAULT_COPTS, linkstatic = 1, - visibility = ["//tcmalloc:tcmalloc_tests"], - deps = common_deps, + visibility = [":tcmalloc_tests"], + deps = tcmalloc_deps + [ + ":common_legacy_locking", + "//tcmalloc/internal:allocation_guard", + "//tcmalloc/internal:overflow", + "//tcmalloc/internal:page_size", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", + ], alwayslink = 1, ) @@ -600,48 +546,6 @@ package_group( ], ) -cc_library( - name = "headers_for_tests", - srcs = [ - "arena.h", - "central_freelist.h", - "guarded_page_allocator.h", - "huge_address_map.h", - "huge_allocator.h", - "huge_cache.h", - "huge_page_aware_allocator.h", - "huge_page_filler.h", - "huge_pages.h", - "huge_region.h", - "page_allocator.h", - "page_allocator_interface.h", - "page_heap.h", - "page_heap_allocator.h", - "pagemap.h", - "parameters.h", - "peak_heap_tracker.h", - "span_stats.h", - "stack_trace_table.h", - "tracking.h", - "transfer_cache.h", - "transfer_cache_internals.h", - "transfer_cache_stats.h", - ], - hdrs = [ - "common.h", - "pages.h", - "sampler.h", - "size_class_info.h", - "span.h", - "static_vars.h", - "stats.h", - "system-alloc.h", - ], - copts = TCMALLOC_DEFAULT_COPTS, - visibility = ["//tcmalloc:tcmalloc_tests"], - deps = common_deps, -) - cc_library( name = "mock_central_freelist", testonly = 1, @@ -649,7 +553,7 @@ cc_library( hdrs = ["mock_central_freelist.h"], copts = TCMALLOC_DEFAULT_COPTS, deps = [ - ":common", + ":common_8k_pages", "//tcmalloc/internal:logging", "@com_google_absl//absl/base", "@com_google_absl//absl/types:span", @@ -658,30 +562,46 @@ cc_library( ) cc_library( - name = "page_allocator_test_util", + name = "mock_static_forwarder", testonly = 1, - srcs = [ - "page_allocator_test_util.h", + hdrs = ["mock_static_forwarder.h"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":common_8k_pages", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", + "@com_google_googletest//:gtest", ], - hdrs = ["page_allocator_test_util.h"], +) + +cc_library( + name = "mock_virtual_allocator", + testonly = 1, + hdrs = ["mock_virtual_allocator.h"], copts = TCMALLOC_DEFAULT_COPTS, - visibility = ["//tcmalloc:tcmalloc_tests"], deps = [ - ":common", - ":malloc_extension", + ":common_8k_pages", + "//tcmalloc/internal:config", + "//tcmalloc/internal:logging", + "@com_google_absl//absl/base:core_headers", ], ) -cc_test( - name = "page_heap_test", - srcs = ["page_heap_test.cc"], +cc_library( + name = "page_allocator_test_util", + testonly = 1, + srcs = [ + "page_allocator_test_util.h", + ], + hdrs = ["page_allocator_test_util.h"], copts = TCMALLOC_DEFAULT_COPTS, deps = [ - ":common", - "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/base", - "@com_google_absl//absl/memory", - "@com_google_googletest//:gtest_main", + ":common_8k_pages", + ":malloc_extension", + "//tcmalloc/internal:config", + "//tcmalloc/internal:logging", + "@com_google_absl//absl/types:span", ], ) @@ -692,7 +612,7 @@ cc_library( hdrs = ["mock_transfer_cache.h"], copts = TCMALLOC_DEFAULT_COPTS, deps = [ - ":common", + ":common_8k_pages", ":mock_central_freelist", "@com_google_absl//absl/random", "@com_google_absl//absl/random:distributions", @@ -700,31 +620,156 @@ cc_library( ], ) -cc_fuzz_test( - name = "transfer_cache_fuzz", +cc_library( + name = "mock_huge_page_static_forwarder", testonly = 1, - srcs = ["transfer_cache_fuzz.cc"], + srcs = ["mock_huge_page_static_forwarder.cc"], + hdrs = ["mock_huge_page_static_forwarder.h"], + deps = [ + ":common_8k_pages", + "//tcmalloc/internal:config", + "//tcmalloc/internal:logging", + "@com_google_absl//absl/base", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/base:malloc_internal", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/hash", + "@com_google_absl//absl/numeric:bits", + "@com_google_absl//absl/time", + ], +) + +cc_test( + name = "huge_page_aware_allocator_fuzz", + srcs = ["huge_page_aware_allocator_fuzz.cc"], copts = TCMALLOC_DEFAULT_COPTS, - tags = [ - "noasan", - "nomsan", - "notsan", + data = glob(["testdata/huge_page_aware_allocator_fuzz/*"]), + deps = [ + ":common_8k_pages", + ":mock_huge_page_static_forwarder", + "//tcmalloc/internal:logging", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/time", + "@com_google_fuzztest//fuzztest", + "@com_google_fuzztest//fuzztest:fuzztest_gtest_main", + "@com_google_googletest//:gtest", + ], +) + +cc_test( + name = "huge_region_fuzz", + srcs = ["huge_region_fuzz.cc"], + args = ["--fuzztest_stack_limit_kb=2048"], + copts = TCMALLOC_DEFAULT_COPTS, + data = glob(["testdata/huge_region_fuzz/*"]), + deps = [ + ":common_8k_pages", + "//tcmalloc/internal:logging", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/log:check", + "@com_google_fuzztest//fuzztest", + "@com_google_fuzztest//fuzztest:fuzztest_gtest_main", + "@com_google_googletest//:gtest", + ], +) + +cc_test( + name = "huge_page_filler_fuzz", + srcs = ["huge_page_filler_fuzz.cc"], + args = ["--fuzztest_stack_limit_kb=2048"], + copts = TCMALLOC_DEFAULT_COPTS, + data = glob(["testdata/huge_page_filler_fuzz/*"]), + deps = [ + ":common_8k_pages", + "//tcmalloc/internal:allocation_guard", + "//tcmalloc/internal:clock", + "//tcmalloc/internal:logging", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/time", + "@com_google_fuzztest//fuzztest", + "@com_google_fuzztest//fuzztest:fuzztest_gtest_main", + "@com_google_googletest//:gtest", + ], +) + +cc_test( + name = "span_fuzz", + srcs = ["span_fuzz.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + data = glob(["testdata/span_fuzz/*"]), + deps = [ + ":common_8k_pages", + "//tcmalloc/internal:logging", + "@com_google_absl//absl/types:span", + "@com_google_fuzztest//fuzztest", + "@com_google_fuzztest//fuzztest:fuzztest_gtest_main", + "@com_google_googletest//:gtest", + ], +) + +cc_test( + name = "sizemap_fuzz", + srcs = ["sizemap_fuzz.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + data = glob(["testdata/sizemap_fuzz/*"]), + deps = [ + ":common_8k_pages", + ":size_class_info", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/types:span", + "@com_google_fuzztest//fuzztest", + "@com_google_fuzztest//fuzztest:fuzztest_gtest_main", + "@com_google_googletest//:gtest", + ], +) + +cc_test( + name = "central_freelist_fuzz", + srcs = ["central_freelist_fuzz.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + data = glob(["testdata/central_freelist_fuzz/*"]), + deps = [ + ":common_8k_pages", + ":mock_static_forwarder", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/types:span", + "@com_google_fuzztest//fuzztest", + "@com_google_fuzztest//fuzztest:fuzztest_gtest_main", + "@com_google_googletest//:gtest", ], +) + +cc_test( + name = "transfer_cache_fuzz", + srcs = ["transfer_cache_fuzz.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + data = glob(["testdata/transfer_cache_fuzz/*"]), deps = [ - ":common", + ":common_8k_pages", ":mock_central_freelist", ":mock_transfer_cache", + "//tcmalloc/internal:config", + "@com_google_absl//absl/log:check", + "@com_google_fuzztest//fuzztest", + "@com_google_fuzztest//fuzztest:fuzztest_gtest_main", + "@com_google_googletest//:gtest", ], ) -cc_test( +create_tcmalloc_testsuite( name = "arena_test", timeout = "moderate", srcs = ["arena_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, + tags = [ + ], deps = [ - ":common", - "@com_github_google_benchmark//:benchmark", + "@com_google_absl//absl/base", "@com_google_googletest//:gtest_main", ], ) @@ -734,16 +779,15 @@ cc_test( timeout = "moderate", srcs = ["transfer_cache_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, + malloc = "//tcmalloc", shard_count = 3, deps = [ - ":common", + ":common_8k_pages", ":mock_central_freelist", ":mock_transfer_cache", + "//tcmalloc/internal:logging", + "//tcmalloc/internal:percpu", "//tcmalloc/testing:thread_manager", - "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/base", - "@com_google_absl//absl/random", - "@com_google_absl//absl/random:distributions", "@com_google_absl//absl/time", "@com_google_absl//absl/types:span", "@com_google_googletest//:gtest_main", @@ -756,10 +800,13 @@ create_tcmalloc_benchmark( copts = TCMALLOC_DEFAULT_COPTS, malloc = "//tcmalloc", deps = [ - ":common", + ":common_8k_pages", ":mock_central_freelist", ":mock_transfer_cache", + "//tcmalloc/internal:config", "@com_github_google_benchmark//:benchmark", + "@com_google_absl//absl/random", + "@com_google_absl//absl/random:distributions", "@com_google_absl//absl/types:optional", ], ) @@ -769,10 +816,12 @@ cc_test( srcs = ["huge_cache_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, deps = [ - ":common", + ":common_8k_pages", + ":mock_metadata_allocator", + ":mock_virtual_allocator", + "//tcmalloc/internal:clock", + "//tcmalloc/internal:config", "//tcmalloc/internal:logging", - "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/base", "@com_google_absl//absl/memory", "@com_google_absl//absl/random", "@com_google_absl//absl/strings", @@ -786,12 +835,36 @@ cc_test( srcs = ["huge_allocator_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, deps = [ - ":common", + ":common_8k_pages", + ":mock_metadata_allocator", + ":mock_virtual_allocator", + "//tcmalloc/internal:config", "//tcmalloc/internal:logging", - "@com_github_google_benchmark//:benchmark", + "@com_google_absl//absl/base", + "@com_google_absl//absl/random", + "@com_google_absl//absl/time", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "huge_page_subrelease_test", + srcs = ["huge_page_subrelease_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":common_8k_pages", + "//tcmalloc/internal:clock", + "//tcmalloc/internal:config", + "//tcmalloc/internal:logging", + "@com_google_absl//absl/algorithm:container", "@com_google_absl//absl/base", "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/memory", "@com_google_absl//absl/random", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/synchronization", "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", ], @@ -799,23 +872,24 @@ cc_test( cc_test( name = "huge_page_filler_test", - timeout = "long", + timeout = "eternal", srcs = ["huge_page_filler_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, linkstatic = 1, + shard_count = 3, deps = [ - ":common", + ":common_8k_pages", + "//tcmalloc/internal:clock", + "//tcmalloc/internal:config", "//tcmalloc/internal:logging", "@com_github_google_benchmark//:benchmark", "@com_google_absl//absl/algorithm:container", "@com_google_absl//absl/base", "@com_google_absl//absl/base:core_headers", - "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/flags:flag", "@com_google_absl//absl/memory", "@com_google_absl//absl/random", - "@com_google_absl//absl/random:distributions", "@com_google_absl//absl/strings", "@com_google_absl//absl/synchronization", "@com_google_absl//absl/time", @@ -829,20 +903,24 @@ cc_test( copts = TCMALLOC_DEFAULT_COPTS, linkstatic = 1, malloc = "//tcmalloc", - tags = [ - ], deps = [ - ":common", + ":common_8k_pages", ":malloc_extension", + ":mock_huge_page_static_forwarder", ":page_allocator_test_util", + "//tcmalloc/internal:config", "//tcmalloc/internal:logging", + "//tcmalloc/internal:page_size", "//tcmalloc/testing:thread_manager", "@com_github_google_benchmark//:benchmark", "@com_google_absl//absl/base", "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/base:nullability", "@com_google_absl//absl/container:flat_hash_map", - "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/meta:type_traits", "@com_google_absl//absl/random", + "@com_google_absl//absl/random:bit_gen_ref", + "@com_google_absl//absl/random:distributions", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", "@com_google_absl//absl/synchronization", @@ -856,12 +934,17 @@ cc_test( srcs = ["huge_region_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, deps = [ - ":common", + ":common_8k_pages", + "//tcmalloc/internal:clock", "//tcmalloc/internal:logging", - "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/base", + "//tcmalloc/testing:thread_manager", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/container:fixed_array", + "@com_google_absl//absl/memory", "@com_google_absl//absl/random", + "@com_google_absl//absl/synchronization", "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", "@com_google_googletest//:gtest_main", ], ) @@ -872,10 +955,12 @@ create_tcmalloc_benchmark( copts = TCMALLOC_DEFAULT_COPTS, malloc = "//tcmalloc", deps = [ - ":common", + ":common_8k_pages", + ":malloc_extension", + "//tcmalloc/internal:config", "//tcmalloc/internal:logging", + "//tcmalloc/internal:page_size", "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/base", ], ) @@ -885,55 +970,58 @@ cc_test( copts = TCMALLOC_DEFAULT_COPTS, malloc = "//tcmalloc", deps = [ - ":common", + ":common_8k_pages", + ":malloc_extension", "//tcmalloc/internal:logging", - "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/base", + "//tcmalloc/internal:page_size", + "//tcmalloc/internal:sysinfo", + "//tcmalloc/testing:testutil", + "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/container:flat_hash_set", - "@com_google_absl//absl/memory", - "@com_google_absl//absl/numeric:bits", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", ], ) cc_test( - name = "pagemap_test", - srcs = ["pagemap_test.cc"], + name = "guarded_page_allocator_profile_test", + srcs = ["guarded_page_allocator_profile_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, + malloc = "//tcmalloc", + tags = [ + "noasan", + "nomsan", + "notsan", + ], deps = [ - ":common", - "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/random", + ":common_8k_pages", + ":malloc_extension", + "//tcmalloc/testing:testutil", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/functional:function_ref", + "@com_google_absl//absl/log:check", "@com_google_googletest//:gtest_main", ], ) -cc_test( - name = "realloc_test", - srcs = ["realloc_test.cc"], +create_tcmalloc_testsuite( + name = "pagemap_test", + srcs = ["pagemap_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, - malloc = "//tcmalloc", deps = [ - "@com_github_google_benchmark//:benchmark", + "//tcmalloc/internal:config", "@com_google_absl//absl/random", - "@com_google_absl//absl/random:distributions", "@com_google_googletest//:gtest_main", ], ) -cc_test( +create_tcmalloc_testsuite( name = "stack_trace_table_test", srcs = ["stack_trace_table_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, deps = [ - ":common", + ":malloc_extension", "//tcmalloc/internal:logging", - "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/base", "@com_google_absl//absl/base:core_headers", - "@com_google_absl//absl/debugging:stacktrace", "@com_google_absl//absl/strings", "@com_google_absl//absl/strings:str_format", "@com_google_googletest//:gtest_main", @@ -941,88 +1029,36 @@ cc_test( ) cc_test( - name = "system-alloc_test", - srcs = ["system-alloc_test.cc"], + name = "malloc_extension_fuzz", + srcs = ["malloc_extension_fuzz.cc"], copts = TCMALLOC_DEFAULT_COPTS, - malloc = "//tcmalloc", - tags = ["nosan"], + data = glob(["testdata/malloc_extension_fuzz/*"]), deps = [ - ":common", ":malloc_extension", - "//tcmalloc/internal:logging", - "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/strings:str_format", - "@com_google_googletest//:gtest_main", + "@com_google_absl//absl/types:optional", + "@com_google_fuzztest//fuzztest", + "@com_google_fuzztest//fuzztest:fuzztest_gtest_main", + "@com_google_googletest//:gtest", ], ) -# This test has been named "large" since before tests were s/m/l. -# The "large" refers to large allocation sizes. -cc_test( - name = "tcmalloc_large_test", - size = "small", - timeout = "moderate", - srcs = ["tcmalloc_large_test.cc"], +cc_library( + name = "metadata_allocator", + hdrs = ["metadata_allocator.h"], copts = TCMALLOC_DEFAULT_COPTS, - malloc = "//tcmalloc", - tags = [ - "noasan", - "noubsan", - ], deps = [ - ":common", - ":malloc_extension", - "//tcmalloc/internal:logging", - "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/container:flat_hash_set", - "@com_google_absl//absl/container:node_hash_set", - "@com_google_googletest//:gtest_main", + "@com_google_absl//absl/base:core_headers", ], ) -cc_test( - name = "malloc_extension_system_malloc_test", - srcs = ["malloc_extension_system_malloc_test.cc"], - copts = TCMALLOC_DEFAULT_COPTS, - malloc = "//tcmalloc/internal:system_malloc", - deps = [ - ":malloc_extension", - "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/random", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "malloc_extension_test", - srcs = ["malloc_extension_test.cc"], - copts = TCMALLOC_DEFAULT_COPTS, - malloc = "//tcmalloc", - tags = [ - "nosan", - ], - deps = [ - ":malloc_extension", - "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/time", - "@com_google_googletest//:gtest_main", - ], -) - -cc_fuzz_test( - name = "malloc_extension_fuzz", +cc_library( + name = "mock_metadata_allocator", testonly = 1, - srcs = ["malloc_extension_fuzz.cc"], + hdrs = ["mock_metadata_allocator.h"], copts = TCMALLOC_DEFAULT_COPTS, - tags = [ - "noasan", - "nomsan", - "notsan", - ], deps = [ - ":malloc_extension", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/types:optional", + ":metadata_allocator", + "@com_google_absl//absl/base:core_headers", ], ) @@ -1032,16 +1068,12 @@ cc_test( copts = TCMALLOC_DEFAULT_COPTS, linkstatic = 1, deps = [ - ":common", + ":common_8k_pages", ":malloc_extension", ":page_allocator_test_util", + "//tcmalloc/internal:config", "//tcmalloc/internal:logging", - "@com_github_google_benchmark//:benchmark", "@com_google_absl//absl/base", - "@com_google_absl//absl/base:core_headers", - "@com_google_absl//absl/memory", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", ], ) @@ -1052,7 +1084,6 @@ cc_test( timeout = "long", srcs = ["profile_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, - flaky = 1, # TODO(b/134690164) linkstatic = 1, malloc = "//tcmalloc", shard_count = 2, @@ -1066,9 +1097,24 @@ cc_test( "//tcmalloc/internal:declarations", "//tcmalloc/internal:linked_list", "//tcmalloc/testing:testutil", - "@com_github_google_benchmark//:benchmark", + "@com_google_absl//absl/container:btree", "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:optional", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "segv_handler_test", + srcs = ["segv_handler_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + malloc = "//tcmalloc", + deps = [ + ":common_8k_pages", + ":malloc_extension", + "//tcmalloc/internal:logging", "@com_google_googletest//:gtest_main", ], ) @@ -1081,7 +1127,10 @@ cc_test( linkstatic = 1, malloc = "//tcmalloc:tcmalloc_deprecated_perthread", tags = [ - "nosan", + "noasan", + "nomsan", + "notsan", + "noubsan", ], deps = [ ":malloc_extension", @@ -1089,8 +1138,8 @@ cc_test( "//tcmalloc/internal:memory_stats", "//tcmalloc/internal:parameter_accessors", "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/strings", + "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", ], ) @@ -1101,70 +1150,28 @@ create_tcmalloc_testsuite( copts = TCMALLOC_DEFAULT_COPTS, deps = [ ":size_class_info", - "@com_github_google_benchmark//:benchmark", + "//tcmalloc/internal:config", + "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/random", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "size_classes_test_with_runtime_size_classes", - srcs = ["size_classes_with_runtime_size_classes_test.cc"], - copts = TCMALLOC_DEFAULT_COPTS, - linkstatic = 1, - malloc = "//tcmalloc", - deps = [ - ":common", - ":runtime_size_classes", - ":size_class_info", - "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/strings", - "@com_google_absl//absl/strings:str_format", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "heap_profiling_test", - srcs = ["heap_profiling_test.cc"], - copts = TCMALLOC_DEFAULT_COPTS, - malloc = "//tcmalloc", - tags = [ - "nosan", - ], - deps = [ - ":common", - ":malloc_extension", - "//tcmalloc/internal:logging", - "//tcmalloc/internal:parameter_accessors", - "@com_github_google_benchmark//:benchmark", - "@com_google_googletest//:gtest_main", - ], -) - -cc_test( - name = "runtime_size_classes_test", - srcs = ["runtime_size_classes_test.cc"], - copts = TCMALLOC_DEFAULT_COPTS, - linkstatic = 1, - malloc = "//tcmalloc", - deps = [ - ":runtime_size_classes", - "@com_github_google_benchmark//:benchmark", + "@com_google_absl//absl/types:span", "@com_google_googletest//:gtest_main", ], ) create_tcmalloc_testsuite( name = "span_test", + timeout = "long", srcs = ["span_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, deps = [ + ":experiment", "//tcmalloc/internal:logging", - "@com_github_google_benchmark//:benchmark", "@com_google_absl//absl/base", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/random", + "@com_google_absl//absl/types:span", "@com_google_googletest//:gtest_main", ], ) @@ -1175,11 +1182,13 @@ create_tcmalloc_benchmark( copts = TCMALLOC_DEFAULT_COPTS, malloc = ":tcmalloc", deps = [ - ":common", + ":common_8k_pages", + "//tcmalloc/internal:allocation_guard", + "//tcmalloc/internal:config", "//tcmalloc/internal:logging", "@com_github_google_benchmark//:benchmark", - "@com_google_absl//absl/base", "@com_google_absl//absl/random", + "@com_google_absl//absl/types:span", ], ) @@ -1189,8 +1198,8 @@ cc_test( copts = TCMALLOC_DEFAULT_COPTS, malloc = "//tcmalloc", deps = [ - ":common", - "@com_github_google_benchmark//:benchmark", + ":common_8k_pages", + "//tcmalloc/internal:logging", "@com_google_absl//absl/base", "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", @@ -1202,8 +1211,8 @@ cc_test( srcs = ["huge_address_map_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, deps = [ - ":common", - "@com_github_google_benchmark//:benchmark", + ":common_8k_pages", + ":mock_metadata_allocator", "@com_google_googletest//:gtest_main", ], ) @@ -1220,12 +1229,10 @@ cc_library( "//visibility:public", ], deps = [ - "//tcmalloc/internal:parameter_accessors", - "@com_google_absl//absl/base:config", + "@com_google_absl//absl/base", "@com_google_absl//absl/base:core_headers", "@com_google_absl//absl/base:malloc_internal", "@com_google_absl//absl/functional:function_ref", - "@com_google_absl//absl/memory", "@com_google_absl//absl/strings", "@com_google_absl//absl/time", "@com_google_absl//absl/types:optional", @@ -1233,70 +1240,152 @@ cc_library( ], ) +cc_library( + name = "malloc_tracing_extension", + srcs = ["malloc_tracing_extension.cc"], + hdrs = [ + "internal_malloc_tracing_extension.h", + "malloc_tracing_extension.h", + ], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + ":__subpackages__", + ], + deps = [ + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + ], +) + +cc_library( + name = "new_extension", + hdrs = ["new_extension.h"], + copts = TCMALLOC_DEFAULT_COPTS, + deprecation = "Use :malloc_extension directly", + visibility = [":__subpackages__"], + deps = [ + ":malloc_extension", + "@com_google_absl//absl/base:core_headers", + ], +) + +create_tcmalloc_testsuite( + name = "new_extension_test", + srcs = ["new_extension_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":malloc_extension", + "//tcmalloc/internal:page_size", + "//tcmalloc/testing:testutil", + "@com_github_google_benchmark//:benchmark", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/numeric:bits", + "@com_google_absl//absl/random", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "experiment_config_test", srcs = ["experiment_config_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, deps = [ ":experiment", - "@com_github_google_benchmark//:benchmark", "@com_google_googletest//:gtest_main", ], ) -cc_fuzz_test( +cc_test( name = "experiment_fuzz", - testonly = 1, srcs = ["experiment_fuzz.cc"], copts = TCMALLOC_DEFAULT_COPTS, deps = [ ":experiment", "@com_google_absl//absl/strings", + "@com_google_fuzztest//fuzztest", + "@com_google_fuzztest//fuzztest:fuzztest_gtest_main", + "@com_google_googletest//:gtest", ], ) -cc_fuzz_test( - name = "runtime_size_classes_fuzz", - testonly = 1, - srcs = ["runtime_size_classes_fuzz.cc"], +cc_test( + name = "cpu_cache_test", + timeout = "long", + srcs = ["cpu_cache_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, + # Some experiments change expected size class capacities. + env = {"BORG_EXPERIMENTS": ""}, + # There can be only one CpuCache due to slab offset caching in rseq. + malloc = "//tcmalloc/internal:system_malloc", + shard_count = 3, + tags = ["noubsan"], deps = [ - ":common", - ":runtime_size_classes", + ":common_8k_pages", + ":mock_transfer_cache", ":size_class_info", - "@com_google_absl//absl/strings", + "//tcmalloc/internal:affinity", + "//tcmalloc/internal:logging", + "//tcmalloc/internal:optimization", + "//tcmalloc/internal:percpu", + "//tcmalloc/internal:percpu_tcmalloc", + "//tcmalloc/internal:sysinfo", + "//tcmalloc/testing:testutil", + "//tcmalloc/testing:thread_manager", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/random", + "@com_google_absl//absl/random:bit_gen_ref", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", + "@com_google_googletest//:gtest_main", ], ) cc_test( - name = "cpu_cache_test", - srcs = ["cpu_cache_test.cc"], + name = "cpu_cache_activate_test", + srcs = ["cpu_cache_activate_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, malloc = ":tcmalloc_deprecated_perthread", - tags = [ - # TODO(b/193887621): Add TSan annotations to CPUCache and/or add - # atomics to PageMap - "notsan", - ], + tags = ["noubsan"], deps = [ ":common_deprecated_perthread", - "//tcmalloc/internal:optimization", - "//tcmalloc/internal:util", - "//tcmalloc/testing:testutil", + ":malloc_extension", + "//tcmalloc/internal:percpu", + "//tcmalloc/internal:sysinfo", "@com_github_google_benchmark//:benchmark", + "@com_google_absl//absl/base", "@com_google_absl//absl/random", - "@com_google_absl//absl/random:seed_sequences", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", "@com_google_googletest//:gtest_main", ], ) -create_tcmalloc_testsuite( +cc_test( name = "central_freelist_test", srcs = ["central_freelist_test.cc"], copts = TCMALLOC_DEFAULT_COPTS, + tags = [ + ], deps = [ + ":common_8k_pages", + ":mock_static_forwarder", + ":size_class_info", + "//tcmalloc/internal:logging", + "//tcmalloc/testing:thread_manager", "@com_github_google_benchmark//:benchmark", + "@com_google_absl//absl/algorithm:container", + "@com_google_absl//absl/base", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/container:fixed_array", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/memory", + "@com_google_absl//absl/numeric:bits", "@com_google_absl//absl/random", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", "@com_google_googletest//:gtest_main", ], ) @@ -1307,10 +1396,106 @@ create_tcmalloc_benchmark( copts = TCMALLOC_DEFAULT_COPTS, malloc = "//tcmalloc", deps = [ - ":common", + ":common_8k_pages", "@com_github_google_benchmark//:benchmark", "@com_google_absl//absl/algorithm:container", "@com_google_absl//absl/random", - "@com_google_absl//absl/types:optional", + "@com_google_absl//absl/types:span", + ], +) + +cc_library( + name = "profile_marshaler", + srcs = ["profile_marshaler.cc"], + hdrs = ["profile_marshaler.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = ["//visibility:public"], + deps = [ + ":malloc_extension", + "//tcmalloc/internal:profile_builder", + "@com_google_absl//absl/status:statusor", + "@com_google_protobuf//:protobuf", + ], +) + +cc_test( + name = "profile_marshaler_test", + srcs = ["profile_marshaler_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":malloc_extension", + ":profile_marshaler", + "//tcmalloc/internal:fake_profile", + "//tcmalloc/internal:profile_cc_proto", + "@com_google_absl//absl/memory", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/time", + "@com_google_googletest//:gtest_main", + "@com_google_protobuf//:protobuf", + ], +) + +# TEMPORARY. WILL BE REMOVED. +# Add a dep to this if you want your binary to use old size classes. +# +# TODO(b/242710633): Remove this. +cc_library( + name = "want_legacy_size_classes", + srcs = ["want_legacy_size_classes.cc"], + copts = ["-g0"] + TCMALLOC_DEFAULT_COPTS, + visibility = ["//visibility:public"], + deps = [ + "@com_google_absl//absl/base:core_headers", + ], + alwayslink = 1, +) + +cc_test( + name = "want_legacy_size_classes_test", + srcs = ["want_legacy_size_classes_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + env = {"BORG_DISABLE_EXPERIMENTS": "all"}, + malloc = "//tcmalloc", + deps = [ + ":common_8k_pages", + ":want_legacy_size_classes", + "@com_google_absl//absl/types:span", + "@com_google_googletest//:gtest_main", + ], +) + +create_tcmalloc_testsuite( + name = "allocation_sample_test", + srcs = ["allocation_sample_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + "//tcmalloc/internal:logging", + "//tcmalloc/testing:thread_manager", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/random", + "@com_google_absl//absl/random:bit_gen_ref", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", + "@com_google_googletest//:gtest_main", + ], +) + +create_tcmalloc_testsuite( + name = "pages_test", + srcs = ["pages_test.cc"], + deps = [ + "@com_github_google_benchmark//:benchmark", + "@com_google_googletest//:gtest_main", + ], +) + +create_tcmalloc_testsuite( + name = "sizemap_test", + srcs = ["sizemap_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":size_class_info", + "@com_google_googletest//:gtest_main", ], ) diff --git a/contrib/libs/tcmalloc/tcmalloc/allocation_sample.cc b/contrib/libs/tcmalloc/tcmalloc/allocation_sample.cc new file mode 100644 index 000000000000..219eba32b5a8 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/allocation_sample.cc @@ -0,0 +1,59 @@ +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/allocation_sample.h" + +#include +#include + +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal_malloc_extension.h" +#include "tcmalloc/malloc_extension.h" +#include "tcmalloc/stack_trace_table.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc::tcmalloc_internal { + +AllocationSample::AllocationSample(AllocationSampleList* list, absl::Time start) + : list_(list), start_(start) { + mallocs_ = std::make_unique(ProfileType::kAllocations); + mallocs_->SetStartTime(start_); + list->Add(this); +} + +AllocationSample::~AllocationSample() { + if (mallocs_ == nullptr) { + return; + } + + // deleted before ending profile, do it for them + list_->Remove(this); +} + +Profile AllocationSample::Stop() && { + // We need to remove ourselves from list_ before we mutate mallocs_; + // + // A concurrent call to AllocationSampleList::ReportMalloc can access mallocs_ + // until we remove it from list_. + if (mallocs_) { + list_->Remove(this); + mallocs_->SetDuration(absl::Now() - start_); + } + return ProfileAccessor::MakeProfile(std::move(mallocs_)); +} + +} // namespace tcmalloc::tcmalloc_internal +GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/allocation_sample.h b/contrib/libs/tcmalloc/tcmalloc/allocation_sample.h new file mode 100644 index 000000000000..69f15e13a5cc --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/allocation_sample.h @@ -0,0 +1,93 @@ +#pragma clang system_header +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_ALLOCATION_SAMPLE_H_ +#define TCMALLOC_ALLOCATION_SAMPLE_H_ + +#include + +#include "absl/base/const_init.h" +#include "absl/base/internal/spinlock.h" +#include "absl/base/thread_annotations.h" +#include "absl/time/time.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/malloc_extension.h" +#include "tcmalloc/stack_trace_table.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc::tcmalloc_internal { + +class AllocationSampleList; + +class AllocationSample final : public AllocationProfilingTokenBase { + public: + AllocationSample(AllocationSampleList* list, absl::Time start); + ~AllocationSample() override; + + Profile Stop() && override; + + private: + AllocationSampleList* list_; + std::unique_ptr mallocs_; + absl::Time start_; + AllocationSample* next_ = nullptr; + friend class AllocationSampleList; +}; + +class AllocationSampleList { + public: + constexpr AllocationSampleList() = default; + + void Add(AllocationSample* as) { + AllocationGuardSpinLockHolder h(&lock_); + as->next_ = first_; + first_ = as; + } + + // This list is very short and we're nowhere near a hot path, just walk + void Remove(AllocationSample* as) { + AllocationGuardSpinLockHolder h(&lock_); + AllocationSample** link = &first_; + AllocationSample* cur = first_; + while (cur != as) { + TC_CHECK_NE(cur, nullptr); + link = &cur->next_; + cur = cur->next_; + } + *link = as->next_; + } + + void ReportMalloc(const struct StackTrace& sample) { + AllocationGuardSpinLockHolder h(&lock_); + AllocationSample* cur = first_; + while (cur != nullptr) { + cur->mallocs_->AddTrace(1.0, sample); + cur = cur->next_; + } + } + + private: + // Guard against any concurrent modifications on the list of allocation + // samples. Invoking `new` while holding this lock can lead to deadlock. + absl::base_internal::SpinLock lock_{ + absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY}; + AllocationSample* first_ ABSL_GUARDED_BY(lock_) = nullptr; +}; + +} // namespace tcmalloc::tcmalloc_internal +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_ALLOCATION_SAMPLE_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/allocation_sample_test.cc b/contrib/libs/tcmalloc/tcmalloc/allocation_sample_test.cc new file mode 100644 index 000000000000..7290154478ac --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/allocation_sample_test.cc @@ -0,0 +1,132 @@ +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/allocation_sample.h" + +#include + +#include +#include +#include + +#include "gtest/gtest.h" +#include "absl/base/thread_annotations.h" +#include "absl/random/bit_gen_ref.h" +#include "absl/random/random.h" +#include "absl/synchronization/mutex.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/static_vars.h" +#include "tcmalloc/testing/thread_manager.h" + +namespace tcmalloc::tcmalloc_internal { +namespace { + +TEST(AllocationSample, Threaded) { + // StackTraceTable uses a global allocator. It must be initialized. + tc_globals.InitIfNecessary(); + + // This test exercises b/143623146 by ensuring that the state of the sample is + // not modified before it is removed from the linked list. + AllocationSampleList list; + + const int kThreads = 5; + const int kMaxSamplers = 3; + const int kMaxAllocations = 100; + ThreadManager m; + std::vector thread_states(kThreads); + + struct GlobalState { + absl::Mutex mu; + std::vector> samplers ABSL_GUARDED_BY(mu); + } global; + + auto PopSample = [&](absl::BitGenRef rng) { + std::unique_ptr ret; + + // Do our test bookkeeping separately, so we don't synchronize list + // externally. + absl::MutexLock l(&global.mu); + if (global.samplers.empty()) { + return ret; + } + size_t index = absl::Uniform(rng, 0, global.samplers.size() - 1u); + std::swap(global.samplers[index], global.samplers.back()); + ret = std::move(global.samplers.back()); + global.samplers.pop_back(); + + TC_CHECK_NE(ret.get(), nullptr); + return ret; + }; + + m.Start(kThreads, [&](int thread) { + auto& state = thread_states[thread]; + const double coin = absl::Uniform(state, 0., 1.0); + + if (coin < 0.1) { + // Add a sampler. This occurs implicitly in the AllocationSample + // constructor. + auto sampler = std::make_unique(&list, absl::Now()); + + // Do our test bookkeeping separately, so we don't synchronize list + // externally. + { + absl::MutexLock l(&global.mu); + if (global.samplers.size() < kMaxSamplers) { + // Add to the list. + global.samplers.push_back(std::move(sampler)); + } + } + + // If we didn't push it, we will unregister in ~AllocationSample. + } else if (coin < 0.2) { + std::unique_ptr sampler = PopSample(state); + + // Remove a sample and allow its destructor to handle unregistering. + sampler.reset(); + } else if (coin < 0.25) { + // Call Stop occasionally. + std::unique_ptr sampler = PopSample(state); + + if (sampler) { + std::move(*sampler).Stop(); + } + } else { + int allocations; + { + // StackTraceTable uses a global allocator, rather than one that is + // injected. Consult the global state to see how many allocations are + // active. + PageHeapSpinLockHolder l; + allocations = tc_globals.linked_sample_allocator().stats().in_use; + } + if (allocations >= kMaxAllocations) { + return; + } + + StackTrace s{}; + s.requested_size = 16; + s.allocated_size = 32; + list.ReportMalloc(s); + } + }); + + absl::SleepFor(absl::Milliseconds(1)); + + m.Stop(); +} + +} // namespace +} // namespace tcmalloc::tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/allocation_sampling.cc b/contrib/libs/tcmalloc/tcmalloc/allocation_sampling.cc new file mode 100644 index 000000000000..d0b60347e2d4 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/allocation_sampling.cc @@ -0,0 +1,270 @@ +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/allocation_sampling.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "absl/base/attributes.h" +#include "absl/base/optimization.h" +#include "absl/debugging/stacktrace.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "absl/types/span.h" +#include "tcmalloc/common.h" +#include "tcmalloc/cpu_cache.h" +#include "tcmalloc/guarded_allocations.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/exponential_biased.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/sampled_allocation.h" +#include "tcmalloc/malloc_extension.h" +#include "tcmalloc/pagemap.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/parameters.h" +#include "tcmalloc/span.h" +#include "tcmalloc/stack_trace_table.h" +#include "tcmalloc/static_vars.h" +#include "tcmalloc/tcmalloc_policy.h" +#include "tcmalloc/thread_cache.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc::tcmalloc_internal { + +std::unique_ptr DumpFragmentationProfile(Static& state) { + auto profile = std::make_unique(ProfileType::kFragmentation); + state.sampled_allocation_recorder().Iterate( + [&state, &profile](const SampledAllocation& sampled_allocation) { + // Compute fragmentation to charge to this sample: + const StackTrace& t = sampled_allocation.sampled_stack; + if (t.proxy == nullptr) { + // There is just one object per-span, and neighboring spans + // can be released back to the system, so we charge no + // fragmentation to this sampled object. + return; + } + + // Fetch the span on which the proxy lives so we can examine its + // co-residents. + const PageId p = PageIdContaining(t.proxy); + Span* span = state.pagemap().GetDescriptor(p); + if (span == nullptr) { + // Avoid crashes in production mode code, but report in tests. + TC_ASSERT_NE(span, nullptr); + return; + } + + const double frag = span->Fragmentation(t.allocated_size); + if (frag > 0) { + // Associate the memory warmth with the actual object, not the proxy. + // The residency information (t.span_start_address) is likely not very + // useful, but we might as well pass it along. + profile->AddTrace(frag, t); + } + }); + return profile; +} + +std::unique_ptr DumpHeapProfile(Static& state) { + auto profile = std::make_unique(ProfileType::kHeap); + profile->SetStartTime(absl::Now()); + state.sampled_allocation_recorder().Iterate( + [&](const SampledAllocation& sampled_allocation) { + profile->AddTrace(1.0, sampled_allocation.sampled_stack); + }); + return profile; +} + +ABSL_ATTRIBUTE_NOINLINE void FreeProxyObject(Static& state, void* ptr, + size_t size_class) { + if (ABSL_PREDICT_TRUE(UsePerCpuCache(state))) { + state.cpu_cache().Deallocate(ptr, size_class); + } else if (ThreadCache* cache = ThreadCache::GetCacheIfPresent(); + ABSL_PREDICT_TRUE(cache)) { + cache->Deallocate(ptr, size_class); + } else { + // This thread doesn't have thread-cache yet or already. Delete directly + // into transfer cache. + state.transfer_cache().InsertRange(size_class, absl::Span(&ptr, 1)); + } +} + +ABSL_ATTRIBUTE_NOINLINE +static void ReportMismatchedDelete(Static& state, + const SampledAllocation& alloc, size_t size, + size_t requested_size, + std::optional allocated_size) { + TC_LOG("*** GWP-ASan (https://google.github.io/tcmalloc/gwp-asan.html) has detected a memory error ***"); + TC_LOG("Error originates from memory allocated at:"); + PrintStackTrace(alloc.sampled_stack.stack, alloc.sampled_stack.depth); + + size_t maximum_size; + if (allocated_size.value_or(requested_size) != requested_size) { + TC_LOG( + "Mismatched-size-delete " + "(https://github.com/google/tcmalloc/tree/master/docs/mismatched-sized-delete.md) " + "of %v bytes (expected %v - %v bytes) at:", + size, requested_size, *allocated_size); + + maximum_size = *allocated_size; + } else { + TC_LOG( + "Mismatched-size-delete " + "(https://github.com/google/tcmalloc/tree/master/docs/mismatched-sized-delete.md) " + "of %v bytes (expected %v bytes) at:", + size, requested_size); + + maximum_size = requested_size; + } + static void* stack[kMaxStackDepth]; + const size_t depth = absl::GetStackTrace(stack, kMaxStackDepth, 1); + PrintStackTrace(stack, depth); + + RecordCrash("GWP-ASan", "mismatched-size-delete"); + state.mismatched_delete_state().Record( + size, size, requested_size, maximum_size, + absl::MakeSpan(alloc.sampled_stack.stack, alloc.sampled_stack.depth), + absl::MakeSpan(stack, depth)); + abort(); +} + +ABSL_ATTRIBUTE_NOINLINE +static void ReportMismatchedDelete(Static& state, void* ptr, size_t size, + size_t minimum_size, size_t maximum_size) { + // Try to refine the maximum possible size. + const PageId p = PageIdContainingTagged(ptr); + size_t size_class = state.pagemap().sizeclass(p); + if (size_class != 0) { + maximum_size = state.sizemap().class_to_size(size_class); + if (maximum_size < minimum_size) { + // Our size class refinement may have made the bounds inconsistent. + // Consult the size map to find the correct bounds. + minimum_size = state.sizemap().class_to_size_range(size_class).first; + } + } + + TC_LOG("*** GWP-ASan (https://google.github.io/tcmalloc/gwp-asan.html) has detected a memory error ***"); + + TC_LOG( + "Mismatched-size-delete " + "(https://github.com/google/tcmalloc/tree/master/docs/mismatched-sized-delete.md) " + "of %v bytes (expected between [%v, %v] bytes) for %p at:", + size, minimum_size, maximum_size, ptr); + + static void* stack[kMaxStackDepth]; + const size_t depth = absl::GetStackTrace(stack, kMaxStackDepth, 1); + PrintStackTrace(stack, depth); + + RecordCrash("GWP-ASan", "mismatched-size-delete"); + state.mismatched_delete_state().Record(/*provided_min=*/size, + /*provided_max=*/size, minimum_size, + maximum_size, std::nullopt, + absl::MakeSpan(stack, depth)); + abort(); +} + +void MaybeUnsampleAllocation(Static& state, void* ptr, + std::optional size, Span& span) { + // No pageheap_lock required. The sampled span should be unmarked and have its + // state cleared only once. External synchronization when freeing is required; + // otherwise, concurrent writes here would likely report a double-free. + SampledAllocation* sampled_allocation = span.Unsample(); + if (sampled_allocation == nullptr) { + if (ABSL_PREDICT_TRUE(size.has_value())) { + const size_t maximum_size = span.bytes_in_span(); + const size_t minimum_size = maximum_size - (kPageSize - 1u); + + if (ABSL_PREDICT_FALSE(*size < minimum_size || *size > maximum_size)) { + // While we don't have precise allocation-time information because this + // span was not sampled, the deallocated object's purported size exceeds + // the span it is on. This is impossible and indicates corruption. + ReportMismatchedDelete(state, ptr, *size, minimum_size, maximum_size); + } + } + + return; + } + + TC_ASSERT_EQ(state.pagemap().sizeclass(PageIdContainingTagged(ptr)), 0); + + void* const proxy = sampled_allocation->sampled_stack.proxy; + const size_t weight = sampled_allocation->sampled_stack.weight; + const size_t requested_size = + sampled_allocation->sampled_stack.requested_size; + const size_t allocated_size = + sampled_allocation->sampled_stack.allocated_size; + if (size.has_value()) { + if (sampled_allocation->sampled_stack.requested_size_returning) { + if (ABSL_PREDICT_FALSE( + !(requested_size <= *size && *size <= allocated_size))) { + ReportMismatchedDelete(state, *sampled_allocation, *size, + requested_size, allocated_size); + } + } else if (ABSL_PREDICT_FALSE(size != requested_size)) { + ReportMismatchedDelete(state, *sampled_allocation, *size, requested_size, + std::nullopt); + } + } + // SampleifyAllocation turns alignment 1 into 0, turn it back for + // SizeMap::SizeClass. + const size_t alignment = + sampled_allocation->sampled_stack.requested_alignment != 0 + ? sampled_allocation->sampled_stack.requested_alignment + : 1; + // How many allocations does this sample represent, given the sampling + // frequency (weight) and its size. + const double allocation_estimate = + static_cast(weight) / (requested_size + 1); + AllocHandle sampled_alloc_handle = + sampled_allocation->sampled_stack.sampled_alloc_handle; + state.sampled_allocation_recorder().Unregister(sampled_allocation); + + // Adjust our estimate of internal fragmentation. + TC_ASSERT_LE(requested_size, allocated_size); + if (requested_size < allocated_size) { + const size_t sampled_fragmentation = + allocation_estimate * (allocated_size - requested_size); + + // Check against wraparound + TC_ASSERT_GE(state.sampled_internal_fragmentation_.value(), + sampled_fragmentation); + state.sampled_internal_fragmentation_.Add(-sampled_fragmentation); + } + + state.deallocation_samples.ReportFree(sampled_alloc_handle); + + if (proxy) { + const auto policy = CppPolicy().InSameNumaPartitionAs(proxy); + size_t size_class; + if (AccessFromPointer(proxy) == AllocationAccess::kCold) { + size_class = state.sizemap().SizeClass( + policy.AccessAsCold().AlignAs(alignment), allocated_size); + } else { + size_class = state.sizemap().SizeClass( + policy.AccessAsHot().AlignAs(alignment), allocated_size); + } + TC_ASSERT_EQ(size_class, + state.pagemap().sizeclass(PageIdContainingTagged(proxy))); + FreeProxyObject(state, proxy, size_class); + } +} + +} // namespace tcmalloc::tcmalloc_internal +GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/allocation_sampling.h b/contrib/libs/tcmalloc/tcmalloc/allocation_sampling.h new file mode 100644 index 000000000000..552150db46a5 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/allocation_sampling.h @@ -0,0 +1,259 @@ +#pragma clang system_header +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_ALLOCATION_SAMPLING_H_ +#define TCMALLOC_ALLOCATION_SAMPLING_H_ + +#include +#include +#include + +#include "absl/base/attributes.h" +#include "absl/debugging/stacktrace.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/percpu.h" +#include "tcmalloc/malloc_extension.h" +#include "tcmalloc/pagemap.h" +#include "tcmalloc/sampler.h" +#include "tcmalloc/span.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc::tcmalloc_internal { + +class Static; + +// This function computes a profile that maps a live stack trace to +// the number of bytes of central-cache memory pinned by an allocation +// at that stack trace. +// In the case when span is hosting >= 1 number of small objects (t.proxy != +// nullptr), we call span::Fragmentation() and read `span->allocated_`. It is +// safe to do so since we hold the per-sample lock while iterating over sampled +// allocations. It prevents the sampled allocation that has the proxy object to +// complete deallocation, thus `proxy` can not be returned to the span yet. It +// thus prevents the central free list to return the span to the page heap. +std::unique_ptr DumpFragmentationProfile(Static& state); + +std::unique_ptr DumpHeapProfile(Static& state); + +extern "C" ABSL_CONST_INIT thread_local Sampler tcmalloc_sampler + ABSL_ATTRIBUTE_INITIAL_EXEC; + +// Compiler needs to see definition of this variable to generate more +// efficient code for -fPIE/PIC. If the compiler does not see the definition +// it considers it may come from another dynamic library. So even for +// initial-exec model, it need to emit an access via GOT (GOTTPOFF). +// When it sees the definition, it can emit direct %fs:TPOFF access. +// So we provide a weak definition here, but the actual definition is in +// percpu_rseq_asm.S. +ABSL_CONST_INIT ABSL_ATTRIBUTE_WEAK thread_local Sampler tcmalloc_sampler + ABSL_ATTRIBUTE_INITIAL_EXEC; + +inline Sampler* GetThreadSampler() { + static_assert(sizeof(Sampler) == TCMALLOC_SAMPLER_SIZE, + "update TCMALLOC_SAMPLER_SIZE"); + static_assert(alignof(Sampler) == TCMALLOC_SAMPLER_ALIGN, + "update TCMALLOC_SAMPLER_ALIGN"); + static_assert(Sampler::HotDataOffset() == TCMALLOC_SAMPLER_HOT_OFFSET, + "update TCMALLOC_SAMPLER_HOT_OFFSET"); + return &tcmalloc_sampler; +} + +void FreeProxyObject(Static& state, void* ptr, size_t size_class); + +// Performs sampling for already occurred allocation of object. +// +// For very small object sizes, object is used as 'proxy' and full +// page with sampled marked is allocated instead. +// +// For medium-sized objects that have single instance per span, +// they're simply freed and fresh page span is allocated to represent +// sampling. +// +// For large objects (i.e. allocated with do_malloc_pages) they are +// also fully reused and their span is marked as sampled. +// +// Note that do_free_with_size assumes sampled objects have +// page-aligned addresses. Please change both functions if need to +// invalidate the assumption. +// +// Note that size_class might not match requested_size in case of +// memalign. I.e. when larger than requested allocation is done to +// satisfy alignment constraint. +// +// In case of out-of-memory condition when allocating span or +// stacktrace struct, this function simply cheats and returns original +// object. As if no sampling was requested. +template +ABSL_ATTRIBUTE_NOINLINE sized_ptr_t +SampleifyAllocation(Static& state, Policy policy, size_t requested_size, + size_t weight, size_t size_class, void* obj, Span* span) { + TC_CHECK((size_class != 0 && obj != nullptr && span == nullptr) || + (size_class == 0 && obj == nullptr && span != nullptr)); + + StackTrace stack_trace; + stack_trace.proxy = nullptr; + stack_trace.requested_size = requested_size; + // Grab the stack trace outside the heap lock. + stack_trace.depth = absl::GetStackTrace(stack_trace.stack, kMaxStackDepth, 0); + + // requested_alignment = 1 means 'small size table alignment was used' + // Historically this is reported as requested_alignment = 0 + stack_trace.requested_alignment = policy.align(); + if (stack_trace.requested_alignment == 1) { + stack_trace.requested_alignment = 0; + } + + stack_trace.requested_size_returning = policy.size_returning(); + stack_trace.access_hint = static_cast(policy.access()); + stack_trace.weight = weight; + + GuardedAllocWithStatus alloc_with_status{ + nullptr, Profile::Sample::GuardedStatus::NotAttempted}; + + size_t capacity = 0; + if (size_class != 0) { + TC_ASSERT_EQ(size_class, + state.pagemap().sizeclass(PageIdContainingTagged(obj))); + + stack_trace.allocated_size = state.sizemap().class_to_size(size_class); + stack_trace.cold_allocated = IsExpandedSizeClass(size_class); + + Length num_pages = BytesToLengthCeil(stack_trace.allocated_size); + alloc_with_status = state.guardedpage_allocator().TrySample( + requested_size, stack_trace.requested_alignment, num_pages, + stack_trace); + if (alloc_with_status.status == Profile::Sample::GuardedStatus::Guarded) { + TC_ASSERT(!IsNormalMemory(alloc_with_status.alloc)); + const PageId p = PageIdContaining(alloc_with_status.alloc); +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + PageHeapSpinLockHolder l; +#endif // TCMALLOC_INTERNAL_LEGACY_LOCKING + span = Span::New(Range(p, num_pages)); + state.pagemap().Set(p, span); + // If we report capacity back from a size returning allocation, we can not + // report the stack_trace.allocated_size, as we guard the size to + // 'requested_size', and we maintain the invariant that GetAllocatedSize() + // must match the returned size from size returning allocations. So in + // that case, we report the requested size for both capacity and + // GetAllocatedSize(). + if (policy.size_returning()) { + stack_trace.allocated_size = requested_size; + } + capacity = requested_size; + } else if ((span = state.page_allocator().New( + num_pages, {1, AccessDensityPrediction::kSparse}, + MemoryTag::kSampled)) == nullptr) { + capacity = stack_trace.allocated_size; + return {obj, capacity}; + } else { + capacity = stack_trace.allocated_size; + } + + size_t span_size = + Length(state.sizemap().class_to_pages(size_class)).in_bytes(); + size_t objects_per_span = span_size / stack_trace.allocated_size; + + if (objects_per_span != 1) { + TC_ASSERT_GT(objects_per_span, 1); + stack_trace.proxy = obj; + obj = nullptr; + } + } else { + // Set stack_trace.allocated_size to the exact size for a page allocation. + // NOTE: if we introduce gwp-asan sampling / guarded allocations + // for page allocations, then we need to revisit do_malloc_pages as + // the current assumption is that only class sized allocs are sampled + // for gwp-asan. + stack_trace.allocated_size = span->bytes_in_span(); + stack_trace.cold_allocated = + GetMemoryTag(span->start_address()) == MemoryTag::kCold; + capacity = stack_trace.allocated_size; + } + + // A span must be provided or created by this point. + TC_ASSERT_NE(span, nullptr); + + stack_trace.sampled_alloc_handle = + state.sampled_alloc_handle_generator.fetch_add( + 1, std::memory_order_relaxed) + + 1; + stack_trace.span_start_address = span->start_address(); + stack_trace.allocation_time = absl::Now(); + stack_trace.guarded_status = alloc_with_status.status; + stack_trace.allocation_type = policy.allocation_type(); + stack_trace.user_data = SampleUserDataSupport::UserData::Make(); + + // How many allocations does this sample represent, given the sampling + // frequency (weight) and its size. + const double allocation_estimate = + static_cast(weight) / (requested_size + 1); + + // Adjust our estimate of internal fragmentation. + TC_ASSERT_LE(requested_size, stack_trace.allocated_size); + if (requested_size < stack_trace.allocated_size) { + state.sampled_internal_fragmentation_.Add( + allocation_estimate * (stack_trace.allocated_size - requested_size)); + } + + state.allocation_samples.ReportMalloc(stack_trace); + + state.deallocation_samples.ReportMalloc(stack_trace); + + // The SampledAllocation object is visible to readers after this. Readers only + // care about its various metadata (e.g. stack trace, weight) to generate the + // heap profile, and won't need any information from Span::Sample() next. + SampledAllocation* sampled_allocation = + state.sampled_allocation_recorder().Register(std::move(stack_trace)); + // No pageheap_lock required. The span is freshly allocated and no one else + // can access it. It is visible after we return from this allocation path. + span->Sample(sampled_allocation); + + state.peak_heap_tracker().MaybeSaveSample(); + + if (obj != nullptr) { + // We are not maintaining precise statistics on malloc hit/miss rates at our + // cache tiers. We can deallocate into our ordinary cache. + TC_ASSERT_NE(size_class, 0); + FreeProxyObject(state, obj, size_class); + } + TC_ASSERT_EQ(state.pagemap().sizeclass(span->first_page()), 0); + return {(alloc_with_status.alloc != nullptr) ? alloc_with_status.alloc + : span->start_address(), + capacity}; +} + +void MaybeUnsampleAllocation(Static& state, void* ptr, + std::optional size, Span& span); + +template +static sized_ptr_t SampleLargeAllocation(Static& state, Policy policy, + size_t requested_size, size_t weight, + Span* span) { + return SampleifyAllocation(state, policy, requested_size, weight, 0, nullptr, + span); +} + +template +static sized_ptr_t SampleSmallAllocation(Static& state, Policy policy, + size_t requested_size, size_t weight, + size_t size_class, sized_ptr_t res) { + return SampleifyAllocation(state, policy, requested_size, weight, size_class, + res.p, nullptr); +} +} // namespace tcmalloc::tcmalloc_internal +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_ALLOCATION_SAMPLING_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/arena.cc b/contrib/libs/tcmalloc/tcmalloc/arena.cc index 5ba1a65bf374..05d505805460 100644 --- a/contrib/libs/tcmalloc/tcmalloc/arena.cc +++ b/contrib/libs/tcmalloc/tcmalloc/arena.cc @@ -14,7 +14,16 @@ #include "tcmalloc/arena.h" +#include +#include +#include + +#include "absl/base/optimization.h" +#include "tcmalloc/common.h" +#include "tcmalloc/internal/allocation_guard.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/memory_tag.h" #include "tcmalloc/static_vars.h" #include "tcmalloc/system-alloc.h" @@ -22,50 +31,44 @@ GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { -void* Arena::Alloc(size_t bytes, int alignment) { - ASSERT(alignment > 0); +void* Arena::Alloc(size_t bytes, std::align_val_t alignment) { + size_t align = static_cast(alignment); + TC_ASSERT_GT(align, 0); + + AllocationGuardSpinLockHolder l(&arena_lock_); + { // First we need to move up to the correct alignment. - const int misalignment = - reinterpret_cast(free_area_) % alignment; - const int alignment_bytes = - misalignment != 0 ? alignment - misalignment : 0; + const int misalignment = reinterpret_cast(free_area_) % align; + const int alignment_bytes = misalignment != 0 ? align - misalignment : 0; free_area_ += alignment_bytes; free_avail_ -= alignment_bytes; bytes_allocated_ += alignment_bytes; } char* result; + auto& system_allocator = tc_globals.system_allocator(); if (free_avail_ < bytes) { size_t ask = bytes > kAllocIncrement ? bytes : kAllocIncrement; - size_t actual_size; - // TODO(b/171081864): Arena allocations should be made relatively - // infrequently. Consider tagging this memory with sampled objects which - // are also infrequently allocated. - // - // In the meantime it is important that we use the current NUMA partition - // rather than always using a particular one because it's possible that any - // single partition we choose might only contain nodes that the process is - // unable to allocate from due to cgroup restrictions. - MemoryTag tag; - const auto& numa_topology = Static::numa_topology(); - if (numa_topology.numa_aware()) { - tag = NumaNormalTag(numa_topology.GetCurrentPartition()); - } else { - tag = MemoryTag::kNormal; - } - free_area_ = - reinterpret_cast(SystemAlloc(ask, &actual_size, kPageSize, tag)); + auto [ptr, actual_size] = + system_allocator.Allocate(ask, kPageSize, MemoryTag::kMetadata); + free_area_ = reinterpret_cast(ptr); if (ABSL_PREDICT_FALSE(free_area_ == nullptr)) { - Crash(kCrash, __FILE__, __LINE__, - "FATAL ERROR: Out of memory trying to allocate internal tcmalloc " - "data (bytes, object-size); is something preventing mmap from " - "succeeding (sandbox, VSS limitations)?", - kAllocIncrement, bytes); + TC_BUG( + "FATAL ERROR: Out of memory trying to allocate internal tcmalloc " + "data (bytes=%v, object-size=%v); is something preventing mmap from " + "succeeding (sandbox, VSS limitations)?", + kAllocIncrement, bytes); } - SystemBack(free_area_, actual_size); + system_allocator.Back(free_area_, actual_size); + + // We've discarded the previous free_area_, so any bytes that were + // unallocated are effectively inaccessible to future allocations. + bytes_unavailable_ += free_avail_; + blocks_++; + free_avail_ = actual_size; } - ASSERT(reinterpret_cast(free_area_) % alignment == 0); + TC_ASSERT_EQ(reinterpret_cast(free_area_) % align, 0); result = free_area_; free_area_ += bytes; free_avail_ -= bytes; diff --git a/contrib/libs/tcmalloc/tcmalloc/arena.h b/contrib/libs/tcmalloc/tcmalloc/arena.h index 06552535405a..b70fefff213e 100644 --- a/contrib/libs/tcmalloc/tcmalloc/arena.h +++ b/contrib/libs/tcmalloc/tcmalloc/arena.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,49 +19,100 @@ #include #include +#include + #include "absl/base/attributes.h" +#include "absl/base/optimization.h" #include "absl/base/thread_annotations.h" #include "tcmalloc/common.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { +struct ArenaStats { + // The number of bytes allocated and in-use by calls to Alloc(). + size_t bytes_allocated; + // The number of bytes currently reserved for future calls to Alloc(). + size_t bytes_unallocated; + // The number of bytes lost and unavailable to calls to Alloc() due to + // inefficiencies in Arena. + size_t bytes_unavailable; + // The number of allocated bytes that have subsequently become non-resident, + // e.g. due to the slab being resized. Note that these bytes are disjoint from + // the ones counted in `bytes_allocated`. + size_t bytes_nonresident; + + // The number of blocks allocated by the Arena. + size_t blocks; +}; + // Arena allocation; designed for use by tcmalloc internal data structures like // spans, profiles, etc. Always expands. -class Arena { +// +// Thread-safe. +class ABSL_CACHELINE_ALIGNED Arena { public: - constexpr Arena() - : free_area_(nullptr), free_avail_(0), bytes_allocated_(0) {} - - // Return a properly aligned byte array of length "bytes". Crashes if - // allocation fails. Requires pageheap_lock is held. - ABSL_ATTRIBUTE_RETURNS_NONNULL void* Alloc(size_t bytes, - int alignment = kAlignment) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); - - // Returns the total number of bytes allocated from this arena. Requires - // pageheap_lock is held. - uint64_t bytes_allocated() const - ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { - return bytes_allocated_; + constexpr Arena() = default; + + // Returns a properly aligned byte array of length "bytes". Crashes if + // allocation fails. + ABSL_ATTRIBUTE_RETURNS_NONNULL void* Alloc( + size_t bytes, std::align_val_t alignment = kAlignment); + + // Updates the stats for allocated and non-resident bytes. + void UpdateAllocatedAndNonresident(int64_t allocated, int64_t nonresident) { + AllocationGuardSpinLockHolder l(&arena_lock_); + TC_ASSERT_GE(static_cast(bytes_allocated_) + allocated, 0); + bytes_allocated_ += allocated; + TC_ASSERT_GE(static_cast(bytes_nonresident_) + nonresident, 0); + bytes_nonresident_ += nonresident; + } + + // Returns statistics about memory allocated and managed by this Arena. + ArenaStats stats() const { + AllocationGuardSpinLockHolder l(&arena_lock_); + + ArenaStats s; + s.bytes_allocated = bytes_allocated_; + s.bytes_unallocated = free_avail_; + s.bytes_unavailable = bytes_unavailable_; + s.bytes_nonresident = bytes_nonresident_; + s.blocks = blocks_; + return s; } private: // How much to allocate from system at a time static constexpr int kAllocIncrement = 128 << 10; + mutable absl::base_internal::SpinLock arena_lock_{ + absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY}; + // Free area from which to carve new objects - char* free_area_ ABSL_GUARDED_BY(pageheap_lock); - size_t free_avail_ ABSL_GUARDED_BY(pageheap_lock); + char* free_area_ ABSL_GUARDED_BY(arena_lock_) = nullptr; + size_t free_avail_ ABSL_GUARDED_BY(arena_lock_) = 0; // Total number of bytes allocated from this arena - uint64_t bytes_allocated_ ABSL_GUARDED_BY(pageheap_lock); + size_t bytes_allocated_ ABSL_GUARDED_BY(arena_lock_) = 0; + // The number of bytes that are unused and unavailable for future allocations + // because they are at the end of a discarded arena block. + size_t bytes_unavailable_ ABSL_GUARDED_BY(arena_lock_) = 0; + // The number of bytes on the arena that have been MADV_DONTNEEDed away. Note + // that these bytes are disjoint from the ones counted in `bytes_allocated`. + size_t bytes_nonresident_ ABSL_GUARDED_BY(arena_lock_) = 0; + // Total number of blocks/free areas managed by this Arena. + size_t blocks_ ABSL_GUARDED_BY(arena_lock_) = 0; Arena(const Arena&) = delete; Arena& operator=(const Arena&) = delete; }; +static_assert(sizeof(Arena) <= ABSL_CACHELINE_SIZE, + "Arena is unexpectedly large"); + } // namespace tcmalloc_internal } // namespace tcmalloc GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/arena_test.cc b/contrib/libs/tcmalloc/tcmalloc/arena_test.cc index 2fb728cac9c9..43bfec995912 100644 --- a/contrib/libs/tcmalloc/tcmalloc/arena_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/arena_test.cc @@ -14,25 +14,113 @@ #include "tcmalloc/arena.h" -#include "gmock/gmock.h" +#include + +#include + #include "gtest/gtest.h" +#include "absl/base/internal/spinlock.h" +#include "tcmalloc/common.h" namespace tcmalloc { namespace tcmalloc_internal { namespace { +std::align_val_t Align(int align) { + return static_cast(align); +} + TEST(Arena, AlignedAlloc) { Arena arena; - absl::base_internal::SpinLockHolder h(&pageheap_lock); - EXPECT_EQ(reinterpret_cast(arena.Alloc(64, 64)) % 64, 0); + EXPECT_EQ(reinterpret_cast(arena.Alloc(64, Align(64))) % 64, 0); EXPECT_EQ(reinterpret_cast(arena.Alloc(7)) % 8, 0); - EXPECT_EQ(reinterpret_cast(arena.Alloc(128, 64)) % 64, 0); + EXPECT_EQ(reinterpret_cast(arena.Alloc(128, Align(64))) % 64, 0); for (int alignment = 1; alignment < 100; ++alignment) { - EXPECT_EQ( - reinterpret_cast(arena.Alloc(7, alignment)) % alignment, 0); + EXPECT_EQ(reinterpret_cast(arena.Alloc(7, Align(alignment))) % + alignment, + 0); } } +TEST(Arena, Stats) { + Arena arena; + + ArenaStats stats = arena.stats(); + EXPECT_EQ(stats.bytes_allocated, 0); + EXPECT_EQ(stats.bytes_unallocated, 0); + EXPECT_EQ(stats.bytes_unavailable, 0); + EXPECT_EQ(stats.bytes_nonresident, 0); + EXPECT_EQ(stats.blocks, 0); + + // Trigger an allocation and grab new stats. + void* ptr = arena.Alloc(1, Align(1)); + ArenaStats stats_after_alloc = arena.stats(); + + EXPECT_NE(ptr, nullptr); + + EXPECT_EQ(stats_after_alloc.bytes_allocated, 1); + EXPECT_GE(stats_after_alloc.bytes_unallocated, 0); + EXPECT_EQ(stats_after_alloc.bytes_unavailable, 0); + EXPECT_EQ(stats_after_alloc.bytes_nonresident, 0); + EXPECT_EQ(stats_after_alloc.blocks, 1); + + // Trigger an allocation that is larger than the remaining free bytes. + // + // TODO(b/201694482): Optimize this. + ptr = arena.Alloc(stats_after_alloc.bytes_unallocated + 1, Align(1)); + ArenaStats stats_after_alloc2 = arena.stats(); + EXPECT_NE(ptr, nullptr); + + EXPECT_EQ(stats_after_alloc2.bytes_allocated, + stats_after_alloc.bytes_unallocated + 2); + EXPECT_GE(stats_after_alloc2.bytes_unallocated, 0); + EXPECT_EQ(stats_after_alloc2.bytes_unavailable, + stats_after_alloc.bytes_unallocated); + EXPECT_EQ(stats_after_alloc.bytes_nonresident, 0); + EXPECT_EQ(stats_after_alloc2.blocks, 2); +} + +TEST(Arena, ReportUnmapped) { + Arena arena; + void* ptr = arena.Alloc(10, Align(1)); + ArenaStats stats_after_alloc = arena.stats(); + EXPECT_NE(ptr, nullptr); + + EXPECT_EQ(stats_after_alloc.bytes_allocated, 10); + EXPECT_EQ(stats_after_alloc.bytes_nonresident, 0); + + arena.UpdateAllocatedAndNonresident(-5, 5); + stats_after_alloc = arena.stats(); + + EXPECT_EQ(stats_after_alloc.bytes_allocated, 5); + EXPECT_EQ(stats_after_alloc.bytes_nonresident, 5); + + arena.UpdateAllocatedAndNonresident(3, -3); + stats_after_alloc = arena.stats(); + + EXPECT_EQ(stats_after_alloc.bytes_allocated, 8); + EXPECT_EQ(stats_after_alloc.bytes_nonresident, 2); +} + +TEST(Arena, BytesImpending) { + Arena arena; + + ArenaStats stats = arena.stats(); + EXPECT_EQ(stats.bytes_allocated, 0); + + arena.UpdateAllocatedAndNonresident(100, 0); + stats = arena.stats(); + + EXPECT_EQ(stats.bytes_allocated, 100); + + arena.UpdateAllocatedAndNonresident(-100, 0); + void* ptr = arena.Alloc(100, Align(1)); + stats = arena.stats(); + + EXPECT_NE(ptr, nullptr); + EXPECT_EQ(stats.bytes_allocated, 100); +} + } // namespace } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/background.cc b/contrib/libs/tcmalloc/tcmalloc/background.cc index ec57c039016e..762214cedd8f 100644 --- a/contrib/libs/tcmalloc/tcmalloc/background.cc +++ b/contrib/libs/tcmalloc/tcmalloc/background.cc @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#include +#include -#include "absl/base/internal/sysinfo.h" #include "absl/time/clock.h" #include "absl/time/time.h" #include "tcmalloc/cpu_cache.h" @@ -24,159 +24,146 @@ #include "tcmalloc/malloc_extension.h" #include "tcmalloc/parameters.h" #include "tcmalloc/static_vars.h" +#include "tcmalloc/stats.h" -GOOGLE_MALLOC_SECTION_BEGIN -namespace tcmalloc { -namespace tcmalloc_internal { -namespace { - -// Called by MallocExtension_Internal_ProcessBackgroundActions. -// -// We use a simple heuristic here: -// We keep track of the set of CPUs that we are allowed to run on. Whenever a -// CPU is removed from this list, the next call to this routine will detect the -// disappearance and call ReleaseCpuMemory on it. -// -// Note that this heuristic _explicitly_ does not reclaim from isolated cores -// that this process may have set up specific affinities for -- as this thread -// will never have been allowed to run there. -cpu_set_t prev_allowed_cpus; -void ReleasePerCpuMemoryToOS() { - cpu_set_t allowed_cpus; - - // Only attempt reclaim when per-CPU caches are in use. While - // ReleaseCpuMemory() itself is usually a no-op otherwise, we are experiencing - // failures in non-permissive sandboxes due to calls made to - // sched_getaffinity() below. It is expected that a runtime environment - // supporting per-CPU allocations supports sched_getaffinity(). - // See b/27247854. - if (!MallocExtension::PerCpuCachesActive()) { - return; - } - - if (subtle::percpu::UsingFlatVirtualCpus()) { - // Our (real) CPU mask does not provide useful information about the state - // of our virtual CPU set. - return; - } - - // This can only fail due to a sandbox or similar intercepting the syscall. - if (sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus)) { - // We log periodically as start-up errors are frequently ignored and this is - // something we do want clients to fix if they are experiencing it. - Log(kLog, __FILE__, __LINE__, - "Unexpected sched_getaffinity() failure; errno ", errno); - return; - } +// Release memory to the system at a constant rate. +void MallocExtension_Internal_ProcessBackgroundActions() { + using ::tcmalloc::tcmalloc_internal::Parameters; + using ::tcmalloc::tcmalloc_internal::tc_globals; - // Note: This is technically not correct in the presence of hotplug (it is - // not guaranteed that NumCPUs() is an upper bound on CPU-number). It is - // currently safe for Google systems. - const int num_cpus = absl::base_internal::NumCPUs(); - for (int cpu = 0; cpu < num_cpus; cpu++) { - if (CPU_ISSET(cpu, &prev_allowed_cpus) && !CPU_ISSET(cpu, &allowed_cpus)) { - // This is a CPU present in the old mask, but not the new. Reclaim. - MallocExtension::ReleaseCpuMemory(cpu); - } - } + tcmalloc::MallocExtension::MarkThreadIdle(); - // Update cached runnable CPUs for next iteration. - memcpy(&prev_allowed_cpus, &allowed_cpus, sizeof(cpu_set_t)); -} + absl::Time prev_time = absl::Now(); + absl::Time last_reclaim = prev_time; + absl::Time last_shuffle = prev_time; + absl::Time last_size_class_resize = prev_time; + absl::Time last_size_class_max_capacity_resize = prev_time; + absl::Time last_slab_resize_check = prev_time; + +#ifndef TCMALLOC_INTERNAL_SMALL_BUT_SLOW + absl::Time last_transfer_cache_plunder_check = prev_time; + absl::Time last_transfer_cache_resize_check = prev_time; +#endif + + // We use a separate release rate smoother from the one used by + // ReleaseMemoryToSystem because a) we want to maintain a constant background + // release rate, regardless of whether the user is releasing memory; and b) we + // want to separately account for pages released by ProcessBackgroundActions. + tcmalloc::tcmalloc_internal::ConstantRatePageAllocatorReleaser releaser; + + while (tcmalloc::MallocExtension::GetBackgroundProcessActionsEnabled()) { + const absl::Duration sleep_time = + tcmalloc::MallocExtension::GetBackgroundProcessSleepInterval(); + + // Reclaim inactive per-cpu caches once per cpu_cache_shuffle_period. + // + // We use a longer 30 sleep cycle reclaim period to make sure that caches + // are indeed idle. Reclaim drains entire cache, as opposed to cache shuffle + // for instance that only shrinks a cache by a few objects at a time. So, we + // might have larger performance degradation if we use a shorter reclaim + // interval and drain caches that weren't supposed to. + const absl::Duration cpu_cache_reclaim_period = 30 * sleep_time; + + // Shuffle per-cpu caches once per cpu_cache_shuffle_period. + const absl::Duration cpu_cache_shuffle_period = 5 * sleep_time; + + const absl::Duration size_class_resize_period = 2 * sleep_time; + const absl::Duration size_class_max_capacity_resize_period = + 29 * sleep_time; + + // See if we should resize the slab once per cpu_cache_slab_resize_period. + // This period is coprime to cpu_cache_shuffle_period and + // cpu_cache_shuffle_period. + const absl::Duration cpu_cache_slab_resize_period = 29 * sleep_time; + +#ifndef TCMALLOC_INTERNAL_SMALL_BUT_SLOW + // We reclaim unused objects from the transfer caches once per + // transfer_cache_plunder_period. + const absl::Duration transfer_cache_plunder_period = 5 * sleep_time; + // Resize transfer caches once per transfer_cache_resize_period. + const absl::Duration transfer_cache_resize_period = 2 * sleep_time; +#endif -void ShuffleCpuCaches() { - if (!MallocExtension::PerCpuCachesActive()) { - return; - } + absl::Time now = absl::Now(); - // Shuffle per-cpu caches - Static::cpu_cache().ShuffleCpuCaches(); -} + // We follow the cache hierarchy in TCMalloc from outermost (per-CPU) to + // innermost (the page heap). Freeing up objects at one layer can help aid + // memory coalescing for inner caches. -// Reclaims per-cpu caches. The CPU mask used in ReleasePerCpuMemoryToOS does -// not provide useful information about virtual CPU state and hence, does not -// reclaim memory when virtual CPUs are enabled. -// -// Here, we use heuristics that are based on cache usage and misses, to -// determine if the caches have been recently inactive and if they may be -// reclaimed. -void ReclaimIdleCpuCaches() { - // Attempts reclaim only when per-CPU caches are in use. - if (!MallocExtension::PerCpuCachesActive()) { - return; - } + if (tcmalloc::MallocExtension::PerCpuCachesActive()) { + // Accelerate fences as part of this operation by registering this thread + // with rseq. While this is not strictly required to succeed, we do not + // expect an inconsistent state for rseq (some threads registered and some + // threads unable to). + TC_CHECK(tcmalloc::tcmalloc_internal::subtle::percpu::IsFast()); - Static::cpu_cache().TryReclaimingCaches(); -} + // Try to reclaim per-cpu caches once every cpu_cache_reclaim_period + // when enabled. + if (now - last_reclaim >= cpu_cache_reclaim_period) { + tc_globals.cpu_cache().TryReclaimingCaches(); + last_reclaim = now; + } -} // namespace -} // namespace tcmalloc_internal -} // namespace tcmalloc -GOOGLE_MALLOC_SECTION_END + if (now - last_shuffle >= cpu_cache_shuffle_period) { + tc_globals.cpu_cache().ShuffleCpuCaches(); + last_shuffle = now; + } -// Release memory to the system at a constant rate. -void MallocExtension_Internal_ProcessBackgroundActions() { - tcmalloc::MallocExtension::MarkThreadIdle(); + if (now - last_size_class_resize >= size_class_resize_period) { + tc_globals.cpu_cache().ResizeSizeClasses(); + last_size_class_resize = now; + } - // Initialize storage for ReleasePerCpuMemoryToOS(). - CPU_ZERO(&tcmalloc::tcmalloc_internal::prev_allowed_cpus); + if (Parameters::resize_size_class_max_capacity() && + now - last_size_class_max_capacity_resize >= + size_class_max_capacity_resize_period) { + tc_globals.cpu_cache().ResizeSizeClassMaxCapacities(); + last_size_class_max_capacity_resize = now; + } - absl::Time prev_time = absl::Now(); - constexpr absl::Duration kSleepTime = absl::Seconds(1); - - // Reclaim inactive per-cpu caches once per kCpuCacheReclaimPeriod. - // - // We use a longer 30 sec reclaim period to make sure that caches are indeed - // idle. Reclaim drains entire cache, as opposed to cache shuffle for instance - // that only shrinks a cache by a few objects at a time. So, we might have - // larger performance degradation if we use a shorter reclaim interval and - // drain caches that weren't supposed to. - constexpr absl::Duration kCpuCacheReclaimPeriod = absl::Seconds(30); - absl::Time last_reclaim = absl::Now(); - - // Shuffle per-cpu caches once per kCpuCacheShufflePeriod secs. - constexpr absl::Duration kCpuCacheShufflePeriod = absl::Seconds(5); - absl::Time last_shuffle = absl::Now(); - - while (true) { - absl::Time now = absl::Now(); - const ssize_t bytes_to_release = - static_cast(tcmalloc::tcmalloc_internal::Parameters:: - background_release_rate()) * - absl::ToDoubleSeconds(now - prev_time); - if (bytes_to_release > 0) { // may be negative if time goes backwards - tcmalloc::MallocExtension::ReleaseMemoryToSystem(bytes_to_release); + // See if we need to grow the slab once every kCpuCacheSlabResizePeriod + // when enabled. + if (Parameters::per_cpu_caches_dynamic_slab_enabled() && + now - last_slab_resize_check >= cpu_cache_slab_resize_period) { + tc_globals.cpu_cache().ResizeSlabIfNeeded(); + last_slab_resize_check = now; + } } - const bool reclaim_idle_per_cpu_caches = - tcmalloc::tcmalloc_internal::Parameters::reclaim_idle_per_cpu_caches(); + tc_globals.sharded_transfer_cache().Plunder(); - // If enabled, we use heuristics to determine if the per-cpu caches are - // inactive. If disabled, we use a more conservative approach, that uses - // allowed cpu masks, to reclaim cpu caches. - if (reclaim_idle_per_cpu_caches) { - // Try to reclaim per-cpu caches once every kCpuCacheReclaimPeriod - // when enabled. - if (now - last_reclaim >= kCpuCacheReclaimPeriod) { - tcmalloc::tcmalloc_internal::ReclaimIdleCpuCaches(); - last_reclaim = now; - } - } else { - tcmalloc::tcmalloc_internal::ReleasePerCpuMemoryToOS(); +#ifndef TCMALLOC_INTERNAL_SMALL_BUT_SLOW + // Try to plunder and reclaim unused objects from transfer caches. + if (now - last_transfer_cache_plunder_check >= + transfer_cache_plunder_period) { + tc_globals.transfer_cache().TryPlunder(); + last_transfer_cache_plunder_check = now; } - const bool shuffle_per_cpu_caches = - tcmalloc::tcmalloc_internal::Parameters::shuffle_per_cpu_caches(); + if (now - last_transfer_cache_resize_check >= + transfer_cache_resize_period) { + tc_globals.transfer_cache().TryResizingCaches(); + last_transfer_cache_resize_check = now; + } +#endif - if (shuffle_per_cpu_caches) { - if (now - last_shuffle >= kCpuCacheShufflePeriod) { - tcmalloc::tcmalloc_internal::ShuffleCpuCaches(); - last_shuffle = now; - } + // If time goes backwards, we would like to cap the release rate at 0. + ssize_t bytes_to_release = + static_cast(Parameters::background_release_rate()) * + absl::ToDoubleSeconds(now - prev_time); + bytes_to_release = std::max(bytes_to_release, 0); + + // If release rate is set to 0, do not release memory to system. However, if + // we want to release free and backed hugepages from HugeRegion, + // ReleaseMemoryToSystem should be able to release those pages to the + // system even with bytes_to_release = 0. + if (bytes_to_release > 0 || Parameters::release_pages_from_huge_region()) { + releaser.Release(bytes_to_release, + /*reason=*/tcmalloc::tcmalloc_internal:: + PageReleaseReason::kProcessBackgroundActions); } - tcmalloc::tcmalloc_internal::Static().sharded_transfer_cache().Plunder(); prev_time = now; - absl::SleepFor(kSleepTime); + absl::SleepFor(sleep_time); } } diff --git a/contrib/libs/tcmalloc/tcmalloc/central_freelist.cc b/contrib/libs/tcmalloc/tcmalloc/central_freelist.cc index 8620e228a133..cfcf1353e799 100644 --- a/contrib/libs/tcmalloc/tcmalloc/central_freelist.cc +++ b/contrib/libs/tcmalloc/tcmalloc/central_freelist.cc @@ -14,205 +14,193 @@ #include "tcmalloc/central_freelist.h" -#include - -#include "tcmalloc/internal/linked_list.h" +#include +#include +#include + +#include "absl/base/attributes.h" +#include "absl/base/optimization.h" +#include "absl/base/thread_annotations.h" +#include "absl/types/span.h" +#include "tcmalloc/common.h" +#include "tcmalloc/internal/allocation_guard.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" -#include "tcmalloc/internal/optimization.h" -#include "tcmalloc/page_heap.h" +#include "tcmalloc/internal/prefetch.h" +#include "tcmalloc/page_allocator_interface.h" #include "tcmalloc/pagemap.h" #include "tcmalloc/pages.h" +#include "tcmalloc/selsan/selsan.h" +#include "tcmalloc/span.h" #include "tcmalloc/static_vars.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { +namespace central_freelist_internal { -static MemoryTag MemoryTagFromSizeClass(size_t cl) { - if (!Static::numa_topology().numa_aware()) { +static MemoryTag MemoryTagFromSizeClass(size_t size_class) { + if (IsExpandedSizeClass(size_class)) { + return MemoryTag::kCold; + } + if (selsan::IsEnabled()) { + return MemoryTag::kSelSan; + } + if (!tc_globals.numa_topology().numa_aware()) { return MemoryTag::kNormal; } - return NumaNormalTag(cl / kNumBaseClasses); + return NumaNormalTag(size_class / kNumBaseClasses); } -// Like a constructor and hence we disable thread safety analysis. -void CentralFreeList::Init(size_t cl) ABSL_NO_THREAD_SAFETY_ANALYSIS { - size_class_ = cl; - object_size_ = Static::sizemap().class_to_size(cl); - pages_per_span_ = Length(Static::sizemap().class_to_pages(cl)); - objects_per_span_ = - pages_per_span_.in_bytes() / (object_size_ ? object_size_ : 1); +static AccessDensityPrediction AccessDensity(int objects_per_span) { + // Use number of objects per span as a proxy for estimating access density of + // the span. If number of objects per span is higher than + // kFewObjectsAllocMaxLimit threshold, we assume that the span would be + // long-lived. + return objects_per_span > kFewObjectsAllocMaxLimit + ? AccessDensityPrediction::kDense + : AccessDensityPrediction::kSparse; } -static Span* MapObjectToSpan(void* object) { - const PageId p = PageIdContaining(object); - Span* span = Static::pagemap().GetExistingDescriptor(p); - return span; +size_t StaticForwarder::class_to_size(int size_class) { + return tc_globals.sizemap().class_to_size(size_class); } -Span* CentralFreeList::ReleaseToSpans(void* object, Span* span, - size_t object_size) { - if (ABSL_PREDICT_FALSE(span->FreelistEmpty(object_size))) { - nonempty_.prepend(span); - } - - if (ABSL_PREDICT_TRUE(span->FreelistPush(object, object_size))) { - return nullptr; - } - span->RemoveFromList(); // from nonempty_ - return span; +Length StaticForwarder::class_to_pages(int size_class) { + return Length(tc_globals.sizemap().class_to_pages(size_class)); } -void CentralFreeList::InsertRange(absl::Span batch) { - CHECK_CONDITION(!batch.empty() && batch.size() <= kMaxObjectsToMove); - Span* spans[kMaxObjectsToMove]; - // Safe to store free spans into freed up space in span array. - Span** free_spans = spans; - int free_count = 0; +ABSL_ATTRIBUTE_NOINLINE +static void ReportMismatchedSizeClass(void* object, int page_size_class, + int object_size_class) { + auto [object_min_size, object_max_size] = + tc_globals.sizemap().class_to_size_range(object_size_class); + auto [page_min_size, page_max_size] = + tc_globals.sizemap().class_to_size_range(page_size_class); + + TC_LOG("*** GWP-ASan (https://google.github.io/tcmalloc/gwp-asan.html) has detected a memory error ***"); + TC_LOG( + "Mismatched-size-class " + "(https://github.com/google/tcmalloc/tree/master/docs/mismatched-sized-delete.md) " + "discovered for pointer %p: this pointer was recently freed " + "with a size argument in the range [%v, %v], but the " + "associated span of allocated memory is for allocations with sizes " + "[%v, %v]. This is not a bug in tcmalloc, but rather is indicative " + "of an application bug such as buffer overrun/underrun, use-after-free " + "or double-free.", + object, object_min_size, object_max_size, page_min_size, page_max_size); + TC_LOG( + "NOTE: The blamed stack trace that is about to crash is not likely the " + "root cause of the issue. We are detecting the invalid deletion at a " + "later point in time and different code location."); + RecordCrash("GWP-ASan", "mismatched-size-class"); + + tc_globals.mismatched_delete_state().Record(object_min_size, object_max_size, + page_min_size, page_max_size, + std::nullopt, std::nullopt); + abort(); +} +void StaticForwarder::MapObjectsToSpans(absl::Span batch, Span** spans, + int expected_size_class) { // Prefetch Span objects to reduce cache misses. for (int i = 0; i < batch.size(); ++i) { - Span* span = MapObjectToSpan(batch[i]); - ASSERT(span != nullptr); + const PageId p = PageIdContaining(batch[i]); + auto [span, page_size_class] = + tc_globals.pagemap().GetExistingDescriptorAndSizeClass(p); + TC_ASSERT_NE(span, nullptr); + if (ABSL_PREDICT_FALSE(page_size_class != expected_size_class)) { + ReportMismatchedSizeClass(span, page_size_class, expected_size_class); + } span->Prefetch(); spans[i] = span; } +} - // First, release all individual objects into spans under our mutex - // and collect spans that become completely free. - { - // Use local copy of variable to ensure that it is not reloaded. - size_t object_size = object_size_; - absl::base_internal::SpinLockHolder h(&lock_); - for (int i = 0; i < batch.size(); ++i) { - Span* span = ReleaseToSpans(batch[i], spans[i], object_size); - if (ABSL_PREDICT_FALSE(span)) { - free_spans[free_count] = span; - free_count++; - } - } - - RecordMultiSpansDeallocated(free_count); - UpdateObjectCounts(batch.size()); +Span* StaticForwarder::AllocateSpan(int size_class, size_t objects_per_span, + Length pages_per_span) { + const MemoryTag tag = MemoryTagFromSizeClass(size_class); + const AccessDensityPrediction density = AccessDensity(objects_per_span); + + SpanAllocInfo span_alloc_info = {.objects_per_span = objects_per_span, + .density = density}; + TC_ASSERT(density == AccessDensityPrediction::kSparse || + (density == AccessDensityPrediction::kDense && + pages_per_span == Length(1))); + Span* span = + tc_globals.page_allocator().New(pages_per_span, span_alloc_info, tag); + if (ABSL_PREDICT_FALSE(span == nullptr)) { + return nullptr; } + TC_ASSERT_EQ(tag, GetMemoryTag(span->start_address())); + TC_ASSERT_EQ(span->num_pages(), pages_per_span); - // Then, release all free spans into page heap under its mutex. - if (ABSL_PREDICT_FALSE(free_count)) { - // Unregister size class doesn't require holding any locks. - for (int i = 0; i < free_count; ++i) { - Span* const free_span = free_spans[i]; - ASSERT(IsNormalMemory(free_span->start_address()) - ); - Static::pagemap().UnregisterSizeClass(free_span); - - // Before taking pageheap_lock, prefetch the PageTrackers these spans are - // on. - // - // Small-but-slow does not use the HugePageAwareAllocator (by default), so - // do not prefetch on this config. -#ifndef TCMALLOC_SMALL_BUT_SLOW - const PageId p = free_span->first_page(); - - // In huge_page_filler.h, we static_assert that PageTracker's key elements - // for deallocation are within the first two cachelines. - void* pt = Static::pagemap().GetHugepage(p); - // Prefetch for writing, as we will issue stores to the PageTracker - // instance. - __builtin_prefetch(pt, 1, 3); - __builtin_prefetch( - reinterpret_cast(reinterpret_cast(pt) + - ABSL_CACHELINE_SIZE), - 1, 3); -#endif // TCMALLOC_SMALL_BUT_SLOW - } - - const MemoryTag tag = MemoryTagFromSizeClass(size_class_); - absl::base_internal::SpinLockHolder h(&pageheap_lock); - for (int i = 0; i < free_count; ++i) { - Span* const free_span = free_spans[i]; - ASSERT(tag == GetMemoryTag(free_span->start_address())); - Static::page_allocator().Delete(free_span, tag); - } - } + tc_globals.pagemap().RegisterSizeClass(span, size_class); + return span; } -int CentralFreeList::RemoveRange(void** batch, int N) { - ASSUME(N > 0); - // Use local copy of variable to ensure that it is not reloaded. - size_t object_size = object_size_; - int result = 0; - absl::base_internal::SpinLockHolder h(&lock_); - if (ABSL_PREDICT_FALSE(nonempty_.empty())) { - result = Populate(batch, N); - } else { - do { - Span* span = nonempty_.first(); - int here = - span->FreelistPopBatch(batch + result, N - result, object_size); - ASSERT(here > 0); - if (span->FreelistEmpty(object_size)) { - span->RemoveFromList(); // from nonempty_ - } - result += here; - } while (result < N && !nonempty_.empty()); +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING +static void ReturnSpansToPageHeap(MemoryTag tag, absl::Span free_spans, + size_t objects_per_span) + ABSL_LOCKS_EXCLUDED(pageheap_lock) { + PageHeapSpinLockHolder l; + for (Span* const free_span : free_spans) { + TC_ASSERT_EQ(tag, GetMemoryTag(free_span->start_address())); + tc_globals.page_allocator().Delete(free_span, tag); } - UpdateObjectCounts(-result); - return result; } - -// Fetch memory from the system and add to the central cache freelist. -int CentralFreeList::Populate(void** batch, - int N) ABSL_NO_THREAD_SAFETY_ANALYSIS { - // Release central list lock while operating on pageheap - // Note, this could result in multiple calls to populate each allocating - // a new span and the pushing those partially full spans onto nonempty. - lock_.Unlock(); - - const MemoryTag tag = MemoryTagFromSizeClass(size_class_); - Span* span = Static::page_allocator().New(pages_per_span_, tag); - if (ABSL_PREDICT_FALSE(span == nullptr)) { - Log(kLog, __FILE__, __LINE__, "tcmalloc: allocation failed", - pages_per_span_.in_bytes()); - lock_.Lock(); - return 0; - } - ASSERT(tag == GetMemoryTag(span->start_address())); - ASSERT(span->num_pages() == pages_per_span_); - - Static::pagemap().RegisterSizeClass(span, size_class_); - size_t objects_per_span = objects_per_span_; - int result = span->BuildFreelist(object_size_, objects_per_span, batch, N); - ASSERT(result > 0); - // This is a cheaper check than using FreelistEmpty(). - bool span_empty = result == objects_per_span; - - lock_.Lock(); - if (!span_empty) { - nonempty_.prepend(span); +#endif // TCMALLOC_INTERNAL_LEGACY_LOCKING + +static void ReturnAllocsToPageHeap( + MemoryTag tag, + absl::Span free_allocs) + ABSL_LOCKS_EXCLUDED(pageheap_lock) { + PageHeapSpinLockHolder l; + for (const auto& alloc : free_allocs) { + tc_globals.page_allocator().Delete(alloc, tag); } - RecordSpanAllocated(); - return result; } -size_t CentralFreeList::OverheadBytes() const { - if (ABSL_PREDICT_FALSE(object_size_ == 0)) { - return 0; +void StaticForwarder::DeallocateSpans(size_t objects_per_span, + absl::Span free_spans) { + TC_ASSERT_NE(free_spans.size(), 0); + const MemoryTag tag = GetMemoryTag(free_spans[0]->start_address()); + // Unregister size class doesn't require holding any locks. + for (Span* const free_span : free_spans) { + TC_ASSERT_EQ(GetMemoryTag(free_span->start_address()), tag); + TC_ASSERT_NE(GetMemoryTag(free_span->start_address()), MemoryTag::kSampled); + tc_globals.pagemap().UnregisterSizeClass(free_span); + + // Before taking pageheap_lock, prefetch the PageTrackers these spans are + // on. + const PageId p = free_span->first_page(); + + // In huge_page_filler.h, we static_assert that PageTracker's key elements + // for deallocation are within the first two cachelines. + void* pt = tc_globals.pagemap().GetHugepage(p); + // Prefetch for writing, as we will issue stores to the PageTracker + // instance. + PrefetchW(pt); + PrefetchW(reinterpret_cast(reinterpret_cast(pt) + + ABSL_CACHELINE_SIZE)); } - const size_t overhead_per_span = pages_per_span_.in_bytes() % object_size_; - return num_spans() * overhead_per_span; -} -SpanStats CentralFreeList::GetSpanStats() const { - SpanStats stats; - if (ABSL_PREDICT_FALSE(objects_per_span_ == 0)) { - return stats; +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + ReturnSpansToPageHeap(tag, free_spans, objects_per_span); +#else + PageAllocatorInterface::AllocationState allocs[kMaxObjectsToMove]; + for (int i = 0, n = free_spans.size(); i < n; ++i) { + Span* s = free_spans[i]; + TC_ASSERT_EQ(tag, GetMemoryTag(s->start_address())); + allocs[i].r = Range(s->first_page(), s->num_pages()); + allocs[i].donated = s->donated(); + Span::Delete(s); } - stats.num_spans_requested = static_cast(num_spans_requested_.value()); - stats.num_spans_returned = static_cast(num_spans_returned_.value()); - stats.obj_capacity = stats.num_live_spans() * objects_per_span_; - return stats; + ReturnAllocsToPageHeap(tag, absl::MakeSpan(allocs, free_spans.size())); +#endif } +} // namespace central_freelist_internal } // namespace tcmalloc_internal } // namespace tcmalloc GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/central_freelist.h b/contrib/libs/tcmalloc/tcmalloc/central_freelist.h index 266f184d6b37..0cd456f8a2f9 100644 --- a/contrib/libs/tcmalloc/tcmalloc/central_freelist.h +++ b/contrib/libs/tcmalloc/tcmalloc/central_freelist.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,14 +18,27 @@ #include +#include #include +#include #include "absl/base/attributes.h" #include "absl/base/const_init.h" +#include "absl/base/internal/cycleclock.h" #include "absl/base/internal/spinlock.h" -#include "absl/base/macros.h" +#include "absl/base/optimization.h" #include "absl/base/thread_annotations.h" +#include "absl/numeric/bits.h" +#include "absl/types/span.h" +#include "tcmalloc/common.h" +#include "tcmalloc/hinted_tracker_lists.h" #include "tcmalloc/internal/atomic_stats_counter.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/optimization.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/parameters.h" +#include "tcmalloc/selsan/selsan.h" #include "tcmalloc/span.h" #include "tcmalloc/span_stats.h" @@ -32,21 +46,66 @@ GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { +namespace central_freelist_internal { + +// StaticForwarder provides access to the PageMap and page heap. +// +// This is a class, rather than namespaced globals, so that it can be mocked for +// testing. +class StaticForwarder { + public: + static uint32_t max_span_cache_size() { + return Parameters::max_span_cache_size(); + } + static uint32_t max_span_cache_array_size() { + return Parameters::max_span_cache_array_size(); + } + static uint64_t clock_now() { return absl::base_internal::CycleClock::Now(); } + static double clock_frequency() { + return absl::base_internal::CycleClock::Frequency(); + } + + static size_t class_to_size(int size_class); + static Length class_to_pages(int size_class); + static void MapObjectsToSpans(absl::Span batch, Span** spans, + int expected_size_class); + [[nodiscard]] static Span* AllocateSpan(int size_class, + size_t objects_per_span, + Length pages_per_span) + ABSL_LOCKS_EXCLUDED(pageheap_lock); + static void DeallocateSpans(size_t objects_per_span, + absl::Span free_spans) + ABSL_LOCKS_EXCLUDED(pageheap_lock); +}; + +// Specifies number of nonempty_ lists that keep track of non-empty spans. +static constexpr size_t kNumLists = 8; + +// Specifies the threshold for number of objects per span. The threshold is +// used to consider a span sparsely- vs. densely-accessed. +static constexpr size_t kFewObjectsAllocMaxLimit = 16; + // Data kept per size-class in central cache. +template class CentralFreeList { public: + using Forwarder = ForwarderT; + constexpr CentralFreeList() : lock_(absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY), size_class_(0), object_size_(0), objects_per_span_(0), + first_nonempty_index_(0), pages_per_span_(0), - nonempty_() {} + nonempty_(), + use_all_buckets_for_few_object_spans_(false), + lifetime_bucket_bounds_() {} CentralFreeList(const CentralFreeList&) = delete; CentralFreeList& operator=(const CentralFreeList&) = delete; - void Init(size_t cl) ABSL_LOCKS_EXCLUDED(lock_); + void Init(size_t size_class) ABSL_LOCKS_EXCLUDED(lock_); // These methods all do internal locking. @@ -56,7 +115,7 @@ class CentralFreeList { // Fill a prefix of batch[0..N-1] with up to N elements removed from central // freelist. Return the number of elements removed. - ABSL_MUST_USE_RESULT int RemoveRange(void** batch, int N) + [[nodiscard]] int RemoveRange(absl::Span batch) ABSL_LOCKS_EXCLUDED(lock_); // Returns the number of free objects in cache. @@ -68,6 +127,9 @@ class CentralFreeList { // page full of 5-byte objects would have 2 bytes memory overhead). size_t OverheadBytes() const; + // Returns number of live spans currently in the nonempty_[n] list. + // REQUIRES: n >= 0 && n < kNumLists. + size_t NumSpansInList(int n) ABSL_LOCKS_EXCLUDED(lock_); SpanStats GetSpanStats() const; void AcquireInternalLocks() { @@ -78,17 +140,69 @@ class CentralFreeList { lock_.Unlock(); } + // Reports span utilization and lifetime histogram stats. + void PrintSpanUtilStats(Printer& out); + void PrintSpanLifetimeStats(Printer& out); + void PrintSpanUtilStatsInPbtxt(PbtxtRegion& region); + void PrintSpanLifetimeStatsInPbtxt(PbtxtRegion& region); + + // Get number of spans in the histogram bucket. We record spans in the + // histogram indexed by absl::bit_width(allocated). So, instead of using the + // absolute number of allocated objects, it uses absl::bit_width(allocated), + // passed as , to index and return the number of spans in the + // histogram. + size_t NumSpansWith(uint16_t bitwidth) const; + + Forwarder& forwarder() { return forwarder_; } + private: // Release an object to spans. // Returns object's span if it become completely free. - Span* ReleaseToSpans(void* object, Span* span, size_t object_size) + Span* ReleaseToSpans(void* object, Span* span, size_t object_size, + uint32_t size_reciprocal, uint32_t max_span_cache_size) ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock_); // Populate cache by fetching from the page heap. // May temporarily release lock_. // Fill a prefix of batch[0..N-1] with up to N elements removed from central // freelist. Returns the number of elements removed. - int Populate(void** batch, int N) ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock_); + int Populate(absl::Span batch) ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock_); + + // Allocate a span from the forwarder. + Span* AllocateSpan(); + + // Deallocate spans to the forwarder. + void DeallocateSpans(absl::Span spans); + + // Parses nonempty_ lists and returns span from the list with the lowest + // possible index. + // Returns the span if one exists in the nonempty_ lists. Else, returns + // nullptr. + Span* FirstNonEmptySpan() ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock_); + + // Returns first index to the nonempty_ lists that may record spans. + uint8_t GetFirstNonEmptyIndex() const; + + // Returns index into nonempty_ based on the number of allocated objects for + // the span. Depending on the number of objects per span, either the absolute + // number of allocated objects or the absl::bit_width(allocated), passed as + // bitwidth, is used to to calculate the list index. + uint8_t IndexFor(uint16_t allocated, uint8_t bitwidth); + + // Records span utilization in objects_to_span_ map. Instead of using the + // absolute number of allocated objects, it uses absl::bit_width(allocated), + // passed as , to index this map. + // + // If increase is set to true, includes the span by incrementing the count + // in the map. Otherwise, removes the span by decrementing the count in + // the map. + void RecordSpanUtil(uint8_t bitwidth, bool increase) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock_) { + ASSUME(bitwidth > 0); + // Updates to objects_to_span_ are guarded by lock_, so writes may be + // performed using LossyAdd. + objects_to_spans_[bitwidth - 1].LossyAdd(increase ? 1 : -1); + } // This lock protects all the mutable data members. absl::base_internal::SpinLock lock_; @@ -96,6 +210,13 @@ class CentralFreeList { size_t size_class_; // My size class (immutable after Init()) size_t object_size_; size_t objects_per_span_; + // Size reciprocal is used to replace division with multiplication when + // computing object indices in the Span bitmap. + uint32_t size_reciprocal_ = 0; + // Hint used for parsing through the nonempty_ lists. This prevents us from + // parsing the lists with an index starting zero, if the lowest possible index + // is higher than that. + size_t first_nonempty_index_; Length pages_per_span_; size_t num_spans() const { @@ -120,6 +241,18 @@ class CentralFreeList { counter_.LossyAdd(num); } + static constexpr size_t kLifetimeBuckets = 8; + using LifetimeHistogram = size_t[kLifetimeBuckets]; + + int LifetimeBucketNum(absl::Duration duration) { + int64_t duration_ms = absl::ToInt64Milliseconds(duration); + auto it = std::upper_bound(lifetime_bucket_bounds_, + lifetime_bucket_bounds_ + kLifetimeBuckets, + duration_ms); + TC_CHECK_NE(it, lifetime_bucket_bounds_); + return it - lifetime_bucket_bounds_ - 1; + } + // The followings are kept as a StatsCounter so that they can read without // acquiring a lock. Updates to these variables are guarded by lock_ // so writes are performed using LossyAdd for speed, the lock still @@ -131,10 +264,508 @@ class CentralFreeList { StatsCounter num_spans_requested_; StatsCounter num_spans_returned_; - // Dummy header for non-empty spans - SpanList nonempty_ ABSL_GUARDED_BY(lock_); + // Records histogram of span utilization. + // + // Each bucket in the histogram records number of live spans with + // corresponding number of allocated objects. Instead of using the absolute + // value of number of allocated objects, we use absl::bit_width(allocated) to + // index this map. A bucket in the histogram corresponds to power-of-two + // number of objects. That is, bucket N tracks number of spans with allocated + // objects < 2^(N+1). For instance, objects_to_spans_ map tracks number of + // spans with allocated objects in the range [a,b), indexed as: [1,2) in + // objects_to_spans_[0], [2,4) in objects_to_spans_[1], [4, 8) in + // objects_to_spans_[2] and so on. We can query the objects_to_spans_ map + // using NumSpansWith(bitwidth) to obtain the number of spans associated + // with the corresponding bucket in the histogram. + // + // As the actual value of objects_per_span_ is not known at compile time, we + // use maximum value that it can be to initialize this hashmap, and + // kSpanUtilBucketCapacity determines this value. We also check during Init + // that absl::bit_width(objects_per_span_) is indeed less than or equal to + // kSpanUtilBucketCapacity. + // + // We disable collection of histogram stats for TCMalloc small-but-slow due to + // performance issues. See b/227362263. + static constexpr size_t kSpanUtilBucketCapacity = 16; + StatsCounter objects_to_spans_[kSpanUtilBucketCapacity]; + + // Non-empty lists that distinguish spans based on the number of objects + // allocated from them. As we prioritize spans, spans may be added to any of + // the kNumLists nonempty_ lists based on their allocated objects. If span + // prioritization is disabled, we add spans to the nonempty_[kNumlists-1] + // list, leaving other lists unused. + HintedTrackerLists nonempty_ ABSL_GUARDED_BY(lock_); + bool use_all_buckets_for_few_object_spans_; + + size_t lifetime_bucket_bounds_[kLifetimeBuckets]; + + ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS Forwarder forwarder_; }; +// Like a constructor and hence we disable thread safety analysis. +template +inline void CentralFreeList::Init(size_t size_class) + ABSL_NO_THREAD_SAFETY_ANALYSIS { + size_class_ = size_class; + object_size_ = forwarder_.class_to_size(size_class); + if (object_size_ == 0) { + return; + } + if (selsan::IsEnabled()) { + object_size_ = selsan::RoundUpObjectSize(object_size_); + } + pages_per_span_ = forwarder_.class_to_pages(size_class); + objects_per_span_ = + pages_per_span_.in_bytes() / (object_size_ ? object_size_ : 1); + size_reciprocal_ = Span::CalcReciprocal(object_size_); + use_all_buckets_for_few_object_spans_ = objects_per_span_ <= 2 * kNumLists; + + // Records nonempty_ list index associated with the span with + // objects_per_span_ number of allocated objects. Refer to the comment in + // IndexFor(...) below for a detailed description. + first_nonempty_index_ = + use_all_buckets_for_few_object_spans_ + ? (kNumLists + 1 >= objects_per_span_ + ? kNumLists + 1 - objects_per_span_ + : 0) + : kNumLists - + std::min(absl::bit_width(objects_per_span_), kNumLists); + + TC_ASSERT(absl::bit_width(objects_per_span_) <= kSpanUtilBucketCapacity); + + lifetime_bucket_bounds_[0] = 0; + lifetime_bucket_bounds_[1] = 1; + for (int i = 2; i < kLifetimeBuckets; ++i) { + lifetime_bucket_bounds_[i] = lifetime_bucket_bounds_[i - 1] * 10; + } +} + +template +inline Span* CentralFreeList::ReleaseToSpans( + void* object, Span* span, size_t object_size, uint32_t size_reciprocal, + uint32_t max_span_cache_size) { + if (ABSL_PREDICT_FALSE(span->FreelistEmpty(object_size))) { + const uint8_t index = GetFirstNonEmptyIndex(); + nonempty_.Add(span, index); + span->set_nonempty_index(index); + } + + const uint8_t prev_index = span->nonempty_index(); + const uint16_t prev_allocated = span->Allocated(); + const uint8_t prev_bitwidth = absl::bit_width(prev_allocated); + if (ABSL_PREDICT_FALSE(!span->FreelistPush( + object, object_size, size_reciprocal, max_span_cache_size))) { + // Update the histogram as the span is full and will be removed from the + // nonempty_ list. + RecordSpanUtil(prev_bitwidth, /*increase=*/false); + nonempty_.Remove(span, prev_index); + return span; + } + // As the objects are being added to the span, its utilization might change. + // We remove the stale utilization from the histogram and add the new + // utilization to the histogram after we release objects to the span. + uint16_t cur_allocated = prev_allocated - 1; + TC_ASSERT_EQ(cur_allocated, span->Allocated()); + const uint8_t cur_bitwidth = absl::bit_width(cur_allocated); + if (cur_bitwidth != prev_bitwidth) { + RecordSpanUtil(prev_bitwidth, /*increase=*/false); + RecordSpanUtil(cur_bitwidth, /*increase=*/true); + } + // If span allocation changes so that it moved to a different nonempty_ list, + // we remove it from the previous list and add it to the desired list indexed + // by cur_index. + const uint8_t cur_index = IndexFor(cur_allocated, cur_bitwidth); + if (cur_index != prev_index) { + nonempty_.Remove(span, prev_index); + nonempty_.Add(span, cur_index); + span->set_nonempty_index(cur_index); + } + return nullptr; +} + +template +inline Span* CentralFreeList::FirstNonEmptySpan() { + // Scan nonempty_ lists in the range [first_nonempty_index_, kNumLists) and + // return the span from a non-empty list if one exists. If all the lists are + // empty, return nullptr. + return nonempty_.PeekLeast(GetFirstNonEmptyIndex()); +} + +template +inline uint8_t CentralFreeList::GetFirstNonEmptyIndex() const { + return first_nonempty_index_; +} + +template +inline uint8_t CentralFreeList::IndexFor(uint16_t allocated, + uint8_t bitwidth) { + // We would like to index into the nonempty_ list based on the number of + // allocated objects from the span. Given a span with fewer allocated objects + // (i.e. when it is more likely to be freed), we would like to map it to a + // higher index in the nonempty_ list. + // + // The number of objects per span is less than or equal to 2 * kNumlists. + // We index such spans by just the number of allocated objects. When the + // allocated objects are in the range [1, 8], then we map the spans to buckets + // 7, 6, ... 0 respectively. When the allocated objects are more than + // kNumlists, then we map the span to bucket 0. + ASSUME(allocated > 0); + if (use_all_buckets_for_few_object_spans_) { + if (allocated <= kNumLists) { + return kNumLists - allocated; + } + return 0; + } + // Depending on the number of kNumLists and the number of objects per span, we + // may have to clamp multiple buckets in index 0. It should be ok to do that + // because it is less beneficial to differentiate between spans that have 128 + // vs 256 allocated objects, compared to those that have 16 vs 32 allocated + // objects. + // + // Consider objects_per_span = 1024 and kNumLists = 8. The following examples + // show spans with allocated objects in the range [a, b) indexed to the + // nonempty_[idx] list using a notation [a, b) -> idx. + // [1, 2) -> 7, [2, 4) -> 6, [4, 8) -> 5, [8, 16) -> 4, [16, 32) -> 3, [32, + // 64) -> 2, [64, 128) -> 1, [128, 1024) -> 0. + ASSUME(bitwidth > 0); + const uint8_t offset = std::min(bitwidth, kNumLists); + const uint8_t index = kNumLists - offset; + ASSUME(index < kNumLists); + return index; +} + +template +inline size_t CentralFreeList::NumSpansInList(int n) { + ASSUME(n >= 0); + ASSUME(n < kNumLists); + AllocationGuardSpinLockHolder h(&lock_); + return nonempty_.SizeOfList(n); +} + +template +inline void CentralFreeList::InsertRange(absl::Span batch) { + TC_CHECK(!batch.empty()); + TC_CHECK_LE(batch.size(), kMaxObjectsToMove); + + if (selsan::IsEnabled()) { + for (auto& ptr : batch) { + ptr = selsan::ResetTag(ptr, object_size_); + } + } + + Span* spans[kMaxObjectsToMove]; + // First, map objects to spans and prefetch spans outside of our mutex + // (to reduce critical section size and cache misses). + forwarder_.MapObjectsToSpans(batch, spans, size_class_); + + if (objects_per_span_ == 1) { + // If there is only 1 object per span, skip CentralFreeList entirely. + DeallocateSpans({spans, batch.size()}); + return; + } + + // Safe to store free spans into freed up space in span array. + const uint32_t max_span_cache_size = forwarder_.max_span_cache_size(); + Span** free_spans = spans; + int free_count = 0; + + // Then, release all individual objects into spans under our mutex + // and collect spans that become completely free. + { + // Use local copy of variables to ensure that they are not reloaded. + size_t object_size = object_size_; + uint32_t size_reciprocal = size_reciprocal_; + absl::base_internal::SpinLockHolder h(&lock_); + for (int i = 0; i < batch.size(); ++i) { + Span* span = ReleaseToSpans(batch[i], spans[i], object_size, + size_reciprocal, max_span_cache_size); + if (ABSL_PREDICT_FALSE(span)) { + free_spans[free_count] = span; + free_count++; + } + } + + RecordMultiSpansDeallocated(free_count); + UpdateObjectCounts(batch.size()); + } + + // Then, release all free spans into page heap under its mutex. + if (ABSL_PREDICT_FALSE(free_count)) { + DeallocateSpans(absl::MakeSpan(free_spans, free_count)); + } +} + +template +void CentralFreeList::DeallocateSpans(absl::Span spans) { + if (ABSL_PREDICT_TRUE(!selsan::IsEnabled())) { + return forwarder_.DeallocateSpans(objects_per_span_, spans); + } + Span* selsan_spans[kMaxObjectsToMove]; + size_t selsan_count = 0; + size_t normal_count = 0; + for (Span* span : spans) { + if (IsSelSanMemory(span->start_address())) { + selsan_spans[selsan_count++] = span; + } else { + spans[normal_count++] = span; + } + } + + if (normal_count) { + forwarder_.DeallocateSpans(objects_per_span_, {spans.data(), normal_count}); + } + if (selsan_count) { + forwarder_.DeallocateSpans(objects_per_span_, {selsan_spans, selsan_count}); + } +} + +template +inline int CentralFreeList::RemoveRange(absl::Span batch) { + TC_ASSERT(!batch.empty()); + + if (objects_per_span_ == 1) { + // If there is only 1 object per span, skip CentralFreeList entirely. + Span* span = AllocateSpan(); + if (ABSL_PREDICT_FALSE(span == nullptr)) { + return 0; + } + batch[0] = span->start_address(); + return 1; + } + + // Use local copy of variable to ensure that it is not reloaded. + size_t object_size = object_size_; + int result = 0; + absl::base_internal::SpinLockHolder h(&lock_); + + do { + Span* span = FirstNonEmptySpan(); + if (ABSL_PREDICT_FALSE(!span)) { + result += Populate(batch.subspan(result)); + break; + } + + const uint16_t prev_allocated = span->Allocated(); + const uint8_t prev_bitwidth = absl::bit_width(prev_allocated); + const uint8_t prev_index = span->nonempty_index(); + int here = span->FreelistPopBatch(batch.subspan(result), object_size); + TC_ASSERT_GT(here, 0); + // As the objects are being popped from the span, its utilization might + // change. So, we remove the stale utilization from the histogram here and + // add it again once we pop the objects. + const uint16_t cur_allocated = prev_allocated + here; + TC_ASSERT_EQ(cur_allocated, span->Allocated()); + const uint8_t cur_bitwidth = absl::bit_width(cur_allocated); + if (cur_bitwidth != prev_bitwidth) { + RecordSpanUtil(prev_bitwidth, /*increase=*/false); + RecordSpanUtil(cur_bitwidth, /*increase=*/true); + } + if (span->FreelistEmpty(object_size)) { + nonempty_.Remove(span, prev_index); + } else { + // If span allocation changes so that it must be moved to a different + // nonempty_ list, we remove it from the previous list and add it to the + // desired list indexed by cur_index. + const uint8_t cur_index = IndexFor(cur_allocated, cur_bitwidth); + if (cur_index != prev_index) { + nonempty_.Remove(span, prev_index); + nonempty_.Add(span, cur_index); + span->set_nonempty_index(cur_index); + } + } + result += here; + } while (result < batch.size()); + UpdateObjectCounts(-result); + return result; +} + +// Fetch memory from the system and add to the central cache freelist. +template +inline int CentralFreeList::Populate(absl::Span batch) + ABSL_NO_THREAD_SAFETY_ANALYSIS { + // Release central list lock while operating on pageheap + // Note, this could result in multiple calls to populate each allocating + // a new span and the pushing those partially full spans onto nonempty. + lock_.Unlock(); + + Span* span = AllocateSpan(); + if (ABSL_PREDICT_FALSE(span == nullptr)) { + return 0; + } + + const uint64_t alloc_time = forwarder_.clock_now(); + int result = + span->BuildFreelist(object_size_, objects_per_span_, batch, + forwarder_.max_span_cache_size(), alloc_time); + TC_ASSERT_GT(result, 0); + // This is a cheaper check than using FreelistEmpty(). + bool span_empty = result == objects_per_span_; + + lock_.Lock(); + + // Update the histogram once we populate the span. + const uint16_t allocated = result; + TC_ASSERT_EQ(allocated, span->Allocated()); + const uint8_t bitwidth = absl::bit_width(allocated); + RecordSpanUtil(bitwidth, /*increase=*/true); + if (!span_empty) { + const uint8_t index = IndexFor(allocated, bitwidth); + nonempty_.Add(span, index); + span->set_nonempty_index(index); + } + RecordSpanAllocated(); + return result; +} + +template +Span* CentralFreeList::AllocateSpan() { + Span* span = + forwarder_.AllocateSpan(size_class_, objects_per_span_, pages_per_span_); + if (ABSL_PREDICT_FALSE(span == nullptr)) { + TC_LOG("tcmalloc: allocation failed %v", pages_per_span_); + } + return span; +} + +template +inline size_t CentralFreeList::OverheadBytes() const { + if (ABSL_PREDICT_FALSE(object_size_ == 0)) { + return 0; + } + const size_t overhead_per_span = pages_per_span_.in_bytes() % object_size_; + return num_spans() * overhead_per_span; +} + +template +inline SpanStats CentralFreeList::GetSpanStats() const { + SpanStats stats; + if (ABSL_PREDICT_FALSE(objects_per_span_ == 0)) { + return stats; + } + stats.num_spans_requested = static_cast(num_spans_requested_.value()); + stats.num_spans_returned = static_cast(num_spans_returned_.value()); + stats.obj_capacity = stats.num_live_spans() * objects_per_span_; + return stats; +} + +template +inline size_t CentralFreeList::NumSpansWith( + uint16_t bitwidth) const { + TC_ASSERT_GT(bitwidth, 0); + const int bucket = bitwidth - 1; + return objects_to_spans_[bucket].value(); +} + +template +inline void CentralFreeList::PrintSpanUtilStats(Printer& out) { + out.printf("class %3d [ %8zu bytes ] : ", size_class_, object_size_); + for (size_t i = 1; i <= kSpanUtilBucketCapacity; ++i) { + out.printf("%6zu < %zu", NumSpansWith(i), 1 << i); + if (i < kSpanUtilBucketCapacity) { + out.printf(","); + } + } + out.printf("\n"); + out.printf("class %3d [ %8zu bytes ] : ", size_class_, object_size_); + for (size_t i = 0; i < kNumLists; ++i) { + out.printf("%6zu: %zu", i, NumSpansInList(i)); + if (i < kNumLists - 1) { + out.printf(","); + } + } + out.printf("\n"); +} + +template +inline void CentralFreeList::PrintSpanLifetimeStats(Printer& out) { + // We do not log allocation time when bitmap is used for spans. + if (Span::UseBitmapForSize(object_size_)) return; + + uint64_t now = forwarder_.clock_now(); + double frequency = forwarder_.clock_frequency(); + LifetimeHistogram lifetime_histo{}; + + { + AllocationGuardSpinLockHolder h(&lock_); + nonempty_.Iter( + [&](const Span& s) GOOGLE_MALLOC_SECTION { + const double elapsed = std::max( + now - s.AllocTime(size_class_, forwarder_.max_span_cache_size()), + 0); + const absl::Duration lifetime = + absl::Milliseconds(elapsed * 1000 / frequency); + ++lifetime_histo[LifetimeBucketNum(lifetime)]; + }, + 0); + } + + out.printf("class %3d [ %8zu bytes ] : ", size_class_, object_size_); + for (size_t i = 0; i < kLifetimeBuckets; ++i) { + out.printf("%3zu ms < %6zu", lifetime_bucket_bounds_[i], lifetime_histo[i]); + if (i < kLifetimeBuckets - 1) { + out.printf(","); + } + } + out.printf("\n"); +} + +template +inline void CentralFreeList::PrintSpanUtilStatsInPbtxt( + PbtxtRegion& region) { + for (size_t i = 1; i <= kSpanUtilBucketCapacity; ++i) { + PbtxtRegion histogram = region.CreateSubRegion("span_util_histogram"); + histogram.PrintI64("lower_bound", 1 << (i - 1)); + histogram.PrintI64("upper_bound", 1 << i); + histogram.PrintI64("value", NumSpansWith(i)); + } + + for (size_t i = 0; i < kNumLists; ++i) { + PbtxtRegion occupancy = + region.CreateSubRegion("prioritization_list_occupancy"); + occupancy.PrintI64("list_index", i); + occupancy.PrintI64("value", NumSpansInList(i)); + } +} + +template +inline void CentralFreeList::PrintSpanLifetimeStatsInPbtxt( + PbtxtRegion& region) { + // We do not log allocation time when bitmap is used for spans. + if (Span::UseBitmapForSize(object_size_)) return; + + uint64_t now = forwarder_.clock_now(); + double frequency = forwarder_.clock_frequency(); + LifetimeHistogram lifetime_histo{}; + + { + AllocationGuardSpinLockHolder h(&lock_); + nonempty_.Iter( + [&](const Span& s) GOOGLE_MALLOC_SECTION { + const double elapsed = std::max( + now - s.AllocTime(size_class_, forwarder_.max_span_cache_size()), + 0); + const absl::Duration lifetime = + absl::Milliseconds(elapsed * 1000 / frequency); + ++lifetime_histo[LifetimeBucketNum(lifetime)]; + }, + 0); + } + + for (size_t i = 0; i < kLifetimeBuckets; ++i) { + PbtxtRegion histogram = region.CreateSubRegion("span_lifetime_histogram"); + histogram.PrintI64("lower_bound", lifetime_bucket_bounds_[i]); + histogram.PrintI64("upper_bound", (i == kLifetimeBuckets - 1 + ? lifetime_bucket_bounds_[i] + : lifetime_bucket_bounds_[i + 1])); + histogram.PrintI64("value", lifetime_histo[i]); + } +} + +} // namespace central_freelist_internal + +using CentralFreeList = central_freelist_internal::CentralFreeList< + central_freelist_internal::StaticForwarder>; + } // namespace tcmalloc_internal } // namespace tcmalloc GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/central_freelist_benchmark.cc b/contrib/libs/tcmalloc/tcmalloc/central_freelist_benchmark.cc index a80d5807539e..56de549ebda1 100644 --- a/contrib/libs/tcmalloc/tcmalloc/central_freelist_benchmark.cc +++ b/contrib/libs/tcmalloc/tcmalloc/central_freelist_benchmark.cc @@ -19,9 +19,9 @@ #include "absl/algorithm/container.h" #include "absl/random/random.h" +#include "absl/types/span.h" #include "benchmark/benchmark.h" #include "tcmalloc/central_freelist.h" -#include "tcmalloc/common.h" #include "tcmalloc/static_vars.h" #include "tcmalloc/tcmalloc_policy.h" @@ -34,25 +34,26 @@ namespace { // to minimize the time it takes to free them. void BM_Populate(benchmark::State& state) { size_t object_size = state.range(0); - size_t cl = Static::sizemap().SizeClass(CppPolicy(), object_size); - int batch_size = Static::sizemap().num_objects_to_move(cl); + size_t size_class = tc_globals.sizemap().SizeClass(CppPolicy(), object_size); + int batch_size = tc_globals.sizemap().num_objects_to_move(size_class); int num_objects = 64 * 1024 * 1024 / object_size; + const int num_batches = num_objects / batch_size; CentralFreeList cfl; // Initialize the span to contain the appropriate size of object. - cfl.Init(cl); + cfl.Init(size_class); // Allocate an array large enough to hold 64 MiB of objects. std::vector buffer(num_objects); int64_t items_processed = 0; absl::BitGen rnd; - for (auto s : state) { + while (state.KeepRunningBatch(num_batches)) { int index = 0; // The cost of fetching objects will include the cost of fetching and // populating the span. while (index < num_objects) { int count = std::min(batch_size, num_objects - index); - int got = cfl.RemoveRange(&buffer[index], count); + int got = cfl.RemoveRange(absl::MakeSpan(buffer).subspan(index, count)); index += got; } @@ -83,23 +84,24 @@ BENCHMARK(BM_Populate) // them is usually done spread over many active spans. void BM_MixAndReturn(benchmark::State& state) { size_t object_size = state.range(0); - size_t cl = Static::sizemap().SizeClass(CppPolicy(), object_size); - int batch_size = Static::sizemap().num_objects_to_move(cl); + size_t size_class = tc_globals.sizemap().SizeClass(CppPolicy(), object_size); + int batch_size = tc_globals.sizemap().num_objects_to_move(size_class); int num_objects = 64 * 1024 * 1024 / object_size; + const int num_batches = num_objects / batch_size; CentralFreeList cfl; // Initialize the span to contain the appropriate size of object. - cfl.Init(cl); + cfl.Init(size_class); // Allocate an array large enough to hold 64 MiB of objects. std::vector buffer(num_objects); int64_t items_processed = 0; absl::BitGen rnd; - for (auto s : state) { + while (state.KeepRunningBatch(num_batches)) { int index = 0; while (index < num_objects) { int count = std::min(batch_size, num_objects - index); - int got = cfl.RemoveRange(&buffer[index], count); + int got = cfl.RemoveRange(absl::MakeSpan(buffer).subspan(index, count)); index += got; } @@ -131,19 +133,21 @@ BENCHMARK(BM_MixAndReturn) // code, and avoids timing the pageheap code. void BM_SpanReuse(benchmark::State& state) { size_t object_size = state.range(0); - size_t cl = Static::sizemap().SizeClass(CppPolicy(), object_size); - int batch_size = Static::sizemap().num_objects_to_move(cl); + size_t size_class = tc_globals.sizemap().SizeClass(CppPolicy(), object_size); + int batch_size = tc_globals.sizemap().num_objects_to_move(size_class); int num_objects = 64 * 1024 * 1024 / object_size; + const int num_batches = num_objects / batch_size; CentralFreeList cfl; // Initialize the span to contain the appropriate size of object. - cfl.Init(cl); + cfl.Init(size_class); // Array used to hold onto half of the objects std::vector held_objects(2 * num_objects); // Request twice the objects we need for (int index = 0; index < 2 * num_objects;) { int count = std::min(batch_size, 2 * num_objects - index); - int got = cfl.RemoveRange(&held_objects[index], count); + int got = + cfl.RemoveRange(absl::MakeSpan(held_objects).subspan(index, count)); index += got; } @@ -158,11 +162,11 @@ void BM_SpanReuse(benchmark::State& state) { int64_t items_processed = 0; absl::BitGen rnd; - for (auto s : state) { + while (state.KeepRunningBatch(num_batches)) { int index = 0; while (index < num_objects) { int count = std::min(batch_size, num_objects - index); - int got = cfl.RemoveRange(&buffer[index], count); + int got = cfl.RemoveRange(absl::MakeSpan(buffer).subspan(index, count)); index += got; } diff --git a/contrib/libs/tcmalloc/tcmalloc/central_freelist_fuzz.cc b/contrib/libs/tcmalloc/tcmalloc/central_freelist_fuzz.cc new file mode 100644 index 000000000000..6c2a42aac3b3 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/central_freelist_fuzz.cc @@ -0,0 +1,161 @@ +// Copyright 2020 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include + +#include "fuzztest/fuzztest.h" +#include "absl/log/check.h" +#include "absl/types/span.h" +#include "tcmalloc/central_freelist.h" +#include "tcmalloc/common.h" +#include "tcmalloc/mock_static_forwarder.h" +#include "tcmalloc/sizemap.h" +#include "tcmalloc/span_stats.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc::tcmalloc_internal { +namespace { + +using CentralFreeList = central_freelist_internal::CentralFreeList< + tcmalloc_internal::MockStaticForwarder>; +using CentralFreelistEnv = FakeCentralFreeListEnvironment; + +void FuzzCFL(const std::string& s) { + const char* data = s.data(); + size_t size = s.size(); + + if (size < 11 || size > 100000) { + // size < 11 for bare minimum fuzz test for a single operation. + // Avoid overly large inputs as we perform some shuffling and checking. + return; + } + // object_size can be at most kMaxSize. The current maximum value of kMaxSize + // is 2^18. So we use the first 24 bits to set object_size. + // + // TODO(b/271282540): Convert these to strongly typed fuzztest parameters. + const size_t object_size = data[0] | (data[1] << 8) | (data[2] << 16); + const size_t num_pages = data[3]; + const size_t num_objects_to_move = data[4]; + // data[5] & 0x1: reserved + const bool use_large_spans = data[5] & 0x2; + data += 6; + size -= 6; + if (!SizeMap::IsValidSizeClass(object_size, num_pages, num_objects_to_move)) { + return; + } + CentralFreelistEnv env(object_size, num_pages, num_objects_to_move, + use_large_spans); + std::vector objects; + + for (int i = 0; i + 5 < size; i += 5) { + // data[N] : choose the operation. + const uint8_t op = data[i]; + // We only use data[N+1] right now. data[N+4:N+2] are currently reserved. + // TODO(271282540): Add support for multiple size classes for fuzzing. + uint32_t value; + memcpy(&value, &data[i + 1], sizeof(value)); + + switch (op & 0x7) { + case 0: { + // Allocate objects. + // value[7:0] : number of objects to allocate. + const uint8_t num_objects = value & 0x00FF; + void* batch[kMaxObjectsToMove]; + const size_t n = num_objects % kMaxObjectsToMove + 1; + int allocated = + env.central_freelist().RemoveRange(absl::MakeSpan(batch, n)); + objects.insert(objects.end(), batch, batch + allocated); + break; + } + case 1: { + // Deallocate objects if number of previously allocated objects is + // non-empty. value[7:0] : number of objects to deallocate. + if (objects.empty()) break; + + const uint8_t num_objects = value & 0x00FF; + const size_t n = std::min(num_objects % kMaxObjectsToMove + 1, + objects.size()); + env.central_freelist().InsertRange({&objects[objects.size() - n], n}); + objects.resize(objects.size() - n); + break; + } + case 2: { + // Shuffle allocated objects such that we don't return them in the + // same order we allocated them. + const int seed = value & 0x00FF; + std::mt19937 rng(seed); + // Limit number of elements to shuffle so that we don't spend a lot of + // time in shuffling a large number of objects. + constexpr int kMaxToShuffle = 10 * kMaxObjectsToMove; + if (objects.size() <= kMaxToShuffle) { + std::shuffle(objects.begin(), objects.end(), rng); + } else { + std::shuffle(objects.end() - kMaxToShuffle, objects.end(), rng); + } + break; + } + case 3: { + // Check stats. + tcmalloc_internal::SpanStats stats = + env.central_freelist().GetSpanStats(); + // Spans with objects_per_span = 1 skip most of the logic in the + // central freelist including stats updates. So skip the check for + // objects_per_span = 1. + if (env.objects_per_span() != 1) { + CHECK_EQ(env.central_freelist().length() + objects.size(), + stats.obj_capacity); + if (objects.empty()) { + CHECK_EQ(stats.num_live_spans(), 0); + } else { + CHECK_GT(stats.num_live_spans(), 0); + } + } + break; + } + case 4: { + std::string s; + s.resize(1 << 20); + Printer p(&s[0], s.size()); + env.central_freelist().PrintSpanUtilStats(p); + env.central_freelist().PrintSpanLifetimeStats(p); + + PbtxtRegion region(p, kTop); + env.central_freelist().PrintSpanUtilStatsInPbtxt(region); + env.central_freelist().PrintSpanLifetimeStatsInPbtxt(region); + break; + } + } + } + + // Clean up. + const size_t allocated = objects.size(); + size_t returned = 0; + while (returned < allocated) { + const size_t to_return = std::min(allocated - returned, kMaxObjectsToMove); + env.central_freelist().InsertRange({&objects[returned], to_return}); + returned += to_return; + } +} + +FUZZ_TEST(CentralFreeListTest, FuzzCFL) + ; + +} // namespace +} // namespace tcmalloc::tcmalloc_internal +GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/central_freelist_test.cc b/contrib/libs/tcmalloc/tcmalloc/central_freelist_test.cc index de5960120d72..1cec1ec27a00 100644 --- a/contrib/libs/tcmalloc/tcmalloc/central_freelist_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/central_freelist_test.cc @@ -14,75 +14,810 @@ #include "tcmalloc/central_freelist.h" +#include +#include +#include + #include +#include +#include +#include +#include +#include +#include +#include "benchmark/benchmark.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/algorithm/container.h" +#include "absl/base/internal/spinlock.h" +#include "absl/base/thread_annotations.h" +#include "absl/container/fixed_array.h" +#include "absl/container/flat_hash_map.h" +#include "absl/memory/memory.h" +#include "absl/numeric/bits.h" #include "absl/random/random.h" +#include "absl/synchronization/mutex.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "absl/types/span.h" #include "tcmalloc/common.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/mock_static_forwarder.h" +#include "tcmalloc/pagemap.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/size_class_info.h" +#include "tcmalloc/sizemap.h" +#include "tcmalloc/span.h" +#include "tcmalloc/span_stats.h" #include "tcmalloc/static_vars.h" +#include "tcmalloc/stats.h" +#include "tcmalloc/testing/thread_manager.h" namespace tcmalloc { namespace tcmalloc_internal { -namespace { -// TODO(b/162552708) Mock out the page heap to interact with CFL instead -class CFLTest : public testing::TestWithParam { +namespace central_freelist_internal { + +class StaticForwarderTest : public testing::TestWithParam { protected: - size_t cl_; + size_t size_class_; + size_t object_size_; + Length pages_per_span_; size_t batch_size_; size_t objects_per_span_; - CentralFreeList cfl_; + uint32_t size_reciprocal_; private: void SetUp() override { - cl_ = GetParam(); - size_t object_size = Static::sizemap().class_to_size(cl_); - if (object_size == 0) { + size_class_ = GetParam(); + if (IsExpandedSizeClass(size_class_)) { +#if ABSL_HAVE_THREAD_SANITIZER + GTEST_SKIP() << "Skipping test under sanitizers that conflict with " + "address placement"; +#endif + + if (!ColdFeatureActive()) { + // If !ColdFeatureActive(), we will use the normal page heap, which will + // keep us from seeing memory get the expected tags. + GTEST_SKIP() + << "Skipping expanded size classes without cold experiment"; + } + } + object_size_ = tc_globals.sizemap().class_to_size(size_class_); + if (object_size_ == 0) { GTEST_SKIP() << "Skipping empty size class."; } - auto pages_per_span = Length(Static::sizemap().class_to_pages(cl_)); - batch_size_ = Static::sizemap().num_objects_to_move(cl_); - objects_per_span_ = pages_per_span.in_bytes() / object_size; - cfl_.Init(cl_); + pages_per_span_ = Length(tc_globals.sizemap().class_to_pages(size_class_)); + batch_size_ = tc_globals.sizemap().num_objects_to_move(size_class_); + objects_per_span_ = pages_per_span_.in_bytes() / object_size_; + size_reciprocal_ = Span::CalcReciprocal(object_size_); + } +}; + +TEST_P(StaticForwarderTest, Simple) { + Span* span = StaticForwarder::AllocateSpan(size_class_, objects_per_span_, + pages_per_span_); + ASSERT_NE(span, nullptr); + + absl::FixedArray batch(objects_per_span_); + const uint32_t max_span_cache_size = StaticForwarder::max_span_cache_size(); + const uint64_t alloc_time = StaticForwarder::clock_now(); + size_t allocated = span->BuildFreelist(object_size_, objects_per_span_, + absl::MakeSpan(batch), + max_span_cache_size, alloc_time); + ASSERT_EQ(allocated, objects_per_span_); + + EXPECT_EQ(size_class_, tc_globals.pagemap().sizeclass(span->first_page())); + EXPECT_EQ(size_class_, tc_globals.pagemap().sizeclass(span->last_page())); + + // span_test.cc provides test coverage for Span, but we need to obtain several + // objects to confirm we can map back to the Span pointer from the PageMap. + for (void* ptr : batch) { + Span* got; + StaticForwarder::MapObjectsToSpans({&ptr, 1}, &got, size_class_); + EXPECT_EQ(span, got); + } + + for (void* ptr : batch) { + EXPECT_EQ(span->FreelistPush(ptr, object_size_, size_reciprocal_, + max_span_cache_size), + ptr != batch.back()); + } + + StaticForwarder::DeallocateSpans(objects_per_span_, absl::MakeSpan(&span, 1)); +} + +class StaticForwarderEnvironment { + struct SpanData { + Span* span; + void* batch[kMaxObjectsToMove]; + }; + + public: + StaticForwarderEnvironment(int size_class, size_t object_size, + size_t objects_per_span, Length pages_per_span, + int batch_size) + : size_class_(size_class), + object_size_(object_size), + objects_per_span_(objects_per_span), + pages_per_span_(pages_per_span), + batch_size_(batch_size) {} + + ~StaticForwarderEnvironment() { Drain(); } + + void RandomlyPoke() { + absl::BitGen rng; + double coin = absl::Uniform(rng, 0.0, 1.0); + + if (coin < 0.5) { + Grow(); + } else if (coin < 0.9) { + // Deallocate Spans. We may deallocate more than 1 span, so we bias + // towards allocating Spans more often than we deallocate. + Shrink(); + } else { + Shuffle(rng); + } + } + + void Drain() { + std::vector> spans; + + { + absl::MutexLock l(&mu_); + if (data_.empty()) { + return; + } + + spans = std::move(data_); + data_.clear(); + } + + // Check mappings. + std::vector free_spans; + for (const auto& data : spans) { + EXPECT_EQ(size_class_, + tc_globals.pagemap().sizeclass(data->span->first_page())); + EXPECT_EQ(size_class_, + tc_globals.pagemap().sizeclass(data->span->last_page())); + // Confirm we can map at least one object back. + Span* got; + StaticForwarder::MapObjectsToSpans({&data->batch[0], 1}, &got, + size_class_); + EXPECT_EQ(data->span, got); + + free_spans.push_back(data->span); + } + + StaticForwarder::DeallocateSpans(objects_per_span_, + absl::MakeSpan(free_spans)); + } + + void Grow() { + // Allocate a Span + Span* span = StaticForwarder::AllocateSpan(size_class_, objects_per_span_, + pages_per_span_); + ASSERT_NE(span, nullptr); + + auto d = std::make_unique(); + d->span = span; + + size_t allocated = span->BuildFreelist( + object_size_, objects_per_span_, absl::MakeSpan(d->batch, batch_size_), + StaticForwarder::max_span_cache_size(), StaticForwarder::clock_now()); + EXPECT_LE(allocated, objects_per_span_); + + EXPECT_EQ(size_class_, tc_globals.pagemap().sizeclass(span->first_page())); + EXPECT_EQ(size_class_, tc_globals.pagemap().sizeclass(span->last_page())); + // Confirm we can map at least one object back. + Span* got; + StaticForwarder::MapObjectsToSpans({&d->batch[0], 1}, &got, size_class_); + EXPECT_EQ(span, got); + + absl::MutexLock l(&mu_); + spans_allocated_++; + data_.push_back(std::move(d)); + } + + void Shrink() { + absl::BitGen rng; + std::vector> spans; + + { + absl::MutexLock l(&mu_); + if (data_.empty()) { + return; + } + + size_t count = absl::LogUniform(rng, 1, data_.size()); + spans.reserve(count); + + for (int i = 0; i < count; i++) { + spans.push_back(std::move(data_.back())); + data_.pop_back(); + } + } + + // Check mappings. + std::vector free_spans; + for (auto& data : spans) { + EXPECT_EQ(size_class_, + tc_globals.pagemap().sizeclass(data->span->first_page())); + EXPECT_EQ(size_class_, + tc_globals.pagemap().sizeclass(data->span->last_page())); + // Confirm we can map at least one object back. + Span* got; + StaticForwarder::MapObjectsToSpans({&data->batch[0], 1}, &got, + size_class_); + EXPECT_EQ(data->span, got); + + free_spans.push_back(data->span); + } + + StaticForwarder::DeallocateSpans(objects_per_span_, + absl::MakeSpan(free_spans)); + } + + void Shuffle(absl::BitGen& rng) { + // Shuffle the shared vector. + absl::MutexLock l(&mu_); + absl::c_shuffle(data_, rng); + } + + int64_t BytesAllocated() { + absl::MutexLock l(&mu_); + return pages_per_span_.in_bytes() * spans_allocated_; } - void TearDown() override { EXPECT_EQ(cfl_.length(), 0); } + private: + int size_class_; + size_t object_size_; + size_t objects_per_span_; + Length pages_per_span_; + int batch_size_; + + absl::Mutex mu_; + int64_t spans_allocated_ ABSL_GUARDED_BY(mu_) = 0; + std::vector> data_ ABSL_GUARDED_BY(mu_); }; -TEST_P(CFLTest, SingleBatch) { +static BackingStats PageHeapStats() { + PageHeapSpinLockHolder l; + return tc_globals.page_allocator().stats(); +} + +TEST_P(StaticForwarderTest, Fuzz) { +#if ABSL_HAVE_THREAD_SANITIZER + // TODO(b/193887621): Enable this test under TSan after addressing benign + // true positives. + GTEST_SKIP() << "Skipping test under Thread Sanitizer."; +#endif // ABSL_HAVE_THREAD_SANITIZER + + const auto page_heap_before = PageHeapStats(); + + StaticForwarderEnvironment env(size_class_, object_size_, objects_per_span_, + pages_per_span_, batch_size_); + ThreadManager threads; + threads.Start(10, [&](int) { env.RandomlyPoke(); }); + + absl::SleepFor(absl::Seconds(0.2)); + + threads.Stop(); + + const auto page_heap_after = PageHeapStats(); + // Confirm we did not leak Spans by ensuring the page heap did not grow nearly + // 1:1 by the total number of Spans we ever allocated. + // + // Since we expect to allocate a significant number of spans, we apply a + // factor of 1/2 (which is unlikely to be flaky) to avoid false negatives + // if/when a background thread triggers a deallocation. + const int64_t bytes_allocated = env.BytesAllocated(); + EXPECT_GT(bytes_allocated, 0); + EXPECT_LE(static_cast(page_heap_after.system_bytes) - + static_cast(page_heap_before.system_bytes), + bytes_allocated / 2); +} + +INSTANTIATE_TEST_SUITE_P(All, StaticForwarderTest, + testing::Range(size_t(1), kNumClasses)); + +} // namespace central_freelist_internal + +namespace { + +using central_freelist_internal::kNumLists; +using TypeParam = FakeCentralFreeListEnvironment< + central_freelist_internal::CentralFreeList>; +using CentralFreeListTest = + ::testing::TestWithParam>; + +TEST_P(CentralFreeListTest, IsolatedSmoke) { + TypeParam e(std::get<0>(GetParam()).size, std::get<0>(GetParam()).pages, + std::get<0>(GetParam()).num_to_move, std::get<1>(GetParam())); + EXPECT_CALL(e.forwarder(), AllocateSpan).Times(1); + + absl::FixedArray batch(e.batch_size()); + int allocated = e.central_freelist().RemoveRange( + absl::MakeSpan(&batch[0], e.batch_size())); + ASSERT_GT(allocated, 0); + EXPECT_LE(allocated, e.batch_size()); + + // We should observe span's utilization captured in the histogram. The number + // of spans in rest of the buckets should be zero. + const int bitwidth = absl::bit_width(static_cast(allocated)); + for (int i = 1; i <= absl::bit_width(e.objects_per_span()); ++i) { + // Skip the check for objects_per_span = 1 since such spans skip most of the + // central freelist's logic. + if (i == bitwidth && e.objects_per_span() != 1) { + EXPECT_EQ(e.central_freelist().NumSpansWith(i), 1); + } else { + EXPECT_EQ(e.central_freelist().NumSpansWith(i), 0); + } + } + + EXPECT_CALL(e.forwarder(), MapObjectsToSpans).Times(1); + EXPECT_CALL(e.forwarder(), DeallocateSpans).Times(1); + + // Skip the check for objects_per_span = 1 since such spans skip most of the + // central freelist's logic. + SpanStats stats = e.central_freelist().GetSpanStats(); + if (e.objects_per_span() != 1) { + EXPECT_EQ(stats.num_spans_requested, 1); + EXPECT_EQ(stats.num_spans_returned, 0); + EXPECT_EQ(stats.obj_capacity, e.objects_per_span()); + } + + e.central_freelist().InsertRange(absl::MakeSpan(&batch[0], allocated)); + // Skip the check for objects_per_span = 1 since such spans skip most of the + // central freelist's logic. + if (e.objects_per_span() != 1) { + SpanStats stats = e.central_freelist().GetSpanStats(); + EXPECT_EQ(stats.num_spans_requested, 1); + EXPECT_EQ(stats.num_spans_returned, 1); + EXPECT_EQ(stats.obj_capacity, 0); + } + + // Span captured in the histogram with the earlier utilization should have + // been removed. + for (int i = 1; i <= absl::bit_width(e.objects_per_span()); ++i) { + EXPECT_EQ(e.central_freelist().NumSpansWith(i), 0); + } +} + +TEST_P(CentralFreeListTest, SpanUtilizationHistogram) { + TypeParam e(std::get<0>(GetParam()).size, std::get<0>(GetParam()).pages, + std::get<0>(GetParam()).num_to_move, std::get<1>(GetParam())); + constexpr size_t kNumSpans = 10; + + // Request kNumSpans spans. void* batch[kMaxObjectsToMove]; - uint64_t got = cfl_.RemoveRange(batch, batch_size_); - ASSERT_GT(got, 0); - cfl_.InsertRange({batch, got}); - SpanStats stats = cfl_.GetSpanStats(); - EXPECT_EQ(stats.num_spans_requested, 1); - EXPECT_EQ(stats.num_spans_returned, 1); - EXPECT_EQ(stats.obj_capacity, 0); + const int num_objects_to_fetch = kNumSpans * e.objects_per_span(); + int total_fetched = 0; + // Tracks object and corresponding span from which it was allocated. + std::vector> object_to_span; + // Tracks number of objects allocated per span. + absl::flat_hash_map allocated_per_span; + int span_idx = 0; + + while (total_fetched < num_objects_to_fetch) { + size_t n = num_objects_to_fetch - total_fetched; + int got = e.central_freelist().RemoveRange( + absl::MakeSpan(batch, std::min(n, e.batch_size()))); + total_fetched += got; + + // Increment span_idx if current objects have been fetched from the new + // span. + if (total_fetched > (span_idx + 1) * e.objects_per_span()) { + ++span_idx; + } + // Record fetched object and the associated span. + for (int i = 0; i < got; ++i) { + Span* s = e.forwarder().MapObjectToSpan(batch[i]); + object_to_span.emplace_back(batch[i], s); + allocated_per_span[s] += 1; + } + TC_ASSERT_LT(span_idx, kNumSpans); + } + + // Make sure that we have fetched exactly from kNumSpans spans. + EXPECT_EQ(span_idx + 1, kNumSpans); + + // We should have kNumSpans spans in the histogram with number of allocated + // objects equal to e.objects_per_span() (i.e. in the last bucket). + // Rest of the buckets should be empty. + const int expected_bitwidth = absl::bit_width(e.objects_per_span()); + // Skip the check when objects_per_span = 1 as those spans skip most of the + // central freelist's logic. + if (e.objects_per_span() != 1) { + EXPECT_EQ(e.central_freelist().NumSpansWith(expected_bitwidth), kNumSpans); + } + for (int i = 1; i < expected_bitwidth; ++i) { + EXPECT_EQ(e.central_freelist().NumSpansWith(i), 0); + } + + // Shuffle. + absl::BitGen rng; + std::shuffle(object_to_span.begin(), object_to_span.end(), rng); + + // Return objects, a fraction at a time, each time checking that histogram is + // correct. + int total_returned = 0; + const int last_bucket = absl::bit_width(e.objects_per_span()) - 1; + while (total_returned < num_objects_to_fetch) { + uint64_t size_to_pop = + std::min(object_to_span.size() - total_returned, e.batch_size()); + + for (int i = 0; i < size_to_pop; ++i) { + const auto [ptr, span] = object_to_span[i + total_returned]; + batch[i] = ptr; + --allocated_per_span[span]; + } + total_returned += size_to_pop; + e.central_freelist().InsertRange({batch, size_to_pop}); + + // Calculate expected histogram. + std::vector expected(absl::bit_width(e.objects_per_span()), 0); + for (const auto& span_and_count : allocated_per_span) { + // If span has non-zero allocated objects, include it in the histogram. + if (span_and_count.second > 0) { + const size_t bucket = absl::bit_width(span_and_count.second) - 1; + TC_ASSERT_LE(bucket, last_bucket); + ++expected[bucket]; + } + } + + // Fetch number of spans logged in the histogram and compare it with the + // expected histogram that we calculated using the tracked allocated + // objects per span. + for (int i = 1; i <= last_bucket; ++i) { + EXPECT_EQ(e.central_freelist().NumSpansWith(i), expected[i - 1]); + } + } + + // Since no span is live here, histogram must be empty. + for (int i = 1; i <= last_bucket; ++i) { + EXPECT_EQ(e.central_freelist().NumSpansWith(i), 0); + } +} + +// Confirms that a call to RemoveRange returns at most kObjectsPerSpan objects +// in cases when there are no non-empty spans in the central freelist. This +// makes sure that we populate, and subsequently allocate from a single span. +// This avoids memory regression due to multiple Populate calls observed in +// b/225880278. +TEST_P(CentralFreeListTest, SinglePopulate) { + // Make sure that we allocate up to kObjectsPerSpan objects in both the span + // prioritization states. + TypeParam e(std::get<0>(GetParam()).size, std::get<0>(GetParam()).pages, + std::get<0>(GetParam()).num_to_move, std::get<1>(GetParam())); + // Try to fetch sufficiently large number of objects at startup. + const int num_objects_to_fetch = 10 * e.objects_per_span(); + std::vector objects(num_objects_to_fetch, nullptr); + const size_t got = e.central_freelist().RemoveRange( + absl::MakeSpan(objects.data(), num_objects_to_fetch)); + // Confirm we allocated at most kObjectsPerSpan number of objects. + EXPECT_GT(got, 0); + EXPECT_LE(got, e.objects_per_span()); + size_t returned = 0; + while (returned < got) { + const size_t to_return = std::min(got - returned, e.batch_size()); + e.central_freelist().InsertRange({&objects[returned], to_return}); + returned += to_return; + } +} + +// Tests whether the index generated by the input indexing function matches the +// index of the span on which allocations and deallocation operations are +// carried out. The test first allocates objects and deallocates them. After +// each operation, the actual index is matched against the expected one. +template +void TestIndexing(TypeParam& e, IndexingFunc f) { + TC_ASSERT_GT(kNumLists, 0); + const int num_objects_to_fetch = e.objects_per_span(); + std::vector objects(num_objects_to_fetch); + size_t fetched = 0; + int expected_idx = kNumLists - 1; + + // Fetch one object at a time from a span and confirm that the span is moved + // through the nonempty_ lists as we allocate more objects from it. + while (fetched < num_objects_to_fetch) { + // Try to fetch one object from the span. + int got = + e.central_freelist().RemoveRange(absl::MakeSpan(&objects[fetched], 1)); + fetched += got; + TC_ASSERT(fetched); + if (fetched % num_objects_to_fetch == 0) { + // Span should have been removed from nonempty_ lists because we have + // allocated all the objects from it. + EXPECT_EQ(e.central_freelist().NumSpansInList(expected_idx), 0); + } else { + expected_idx = f(fetched); + TC_ASSERT_GE(expected_idx, 0); + TC_ASSERT_LT(expected_idx, kNumLists); + // Check that the span exists in the corresponding nonempty_ list. + EXPECT_EQ(e.central_freelist().NumSpansInList(expected_idx), 1); + } + } + + // Similar to our previous test, we now make sure that the span is moved + // through the nonempty_ lists when we deallocate objects back to it. + size_t remaining = fetched; + while (--remaining > 0) { + // Return objects back to the span one at a time. + e.central_freelist().InsertRange({&objects[remaining], 1}); + TC_ASSERT(remaining); + // When allocated objects are more than the threshold, the span is indexed + // to nonempty_ list 0. + expected_idx = f(remaining); + EXPECT_LT(expected_idx, kNumLists); + EXPECT_EQ(e.central_freelist().NumSpansInList(expected_idx), 1); + } + + // When the last object is returned, we release the span to the page heap. So, + // nonempty_[0] should also be empty. + e.central_freelist().InsertRange({&objects[remaining], 1}); + EXPECT_EQ(e.central_freelist().NumSpansInList(0), 0); +} + +TEST_P(CentralFreeListTest, BitwidthIndexedNonEmptyLists) { + TypeParam e(std::get<0>(GetParam()).size, std::get<0>(GetParam()).pages, + std::get<0>(GetParam()).num_to_move, std::get<1>(GetParam())); + if (e.objects_per_span() <= 2 * kNumLists) { + GTEST_SKIP() + << "Skipping test as one hot encoding used for few object spans."; + } + auto bitwidth_indexing = [](size_t allocated) { + size_t bitwidth = absl::bit_width(allocated); + return kNumLists - std::min(bitwidth, kNumLists); + }; + TestIndexing(e, bitwidth_indexing); +} + +TEST_P(CentralFreeListTest, DirectIndexedEncodedNonEmptyLists) { + TypeParam e(std::get<0>(GetParam()).size, std::get<0>(GetParam()).pages, + std::get<0>(GetParam()).num_to_move, std::get<1>(GetParam())); + if (e.objects_per_span() > 2 * kNumLists) { + GTEST_SKIP() << "Skipping test as one hot encoding not required."; + } + auto direct_indexing = [](int allocated) { + if (allocated <= kNumLists) return kNumLists - allocated; + return 0UL; + }; + TestIndexing(e, direct_indexing); +} + +// Checks if we are indexing a span in the nonempty_ lists as expected. We also +// check if the spans are correctly being prioritized. That is, we create a +// scenario where we have two live spans, and one span has more allocated +// objects than the other span. On subsequent allocations, we confirm that the +// objects are allocated from the span with a higher number of allocated objects +// as enforced by our prioritization scheme. +TEST_P(CentralFreeListTest, SpanPriority) { + TypeParam e(std::get<0>(GetParam()).size, std::get<0>(GetParam()).pages, + std::get<0>(GetParam()).num_to_move, std::get<1>(GetParam())); + + // If the number of objects per span is less than 2, we do not use more than + // one nonempty_ lists. So, we can not prioritize the spans based on how many + // objects were allocated from them. + const int objects_per_span = e.objects_per_span(); + if (objects_per_span < 3 || kNumLists < 2) return; + + constexpr int kNumSpans = 2; + // Track objects allocated per span. + absl::FixedArray> objects(kNumSpans); + void* batch[kMaxObjectsToMove]; + + const size_t to_fetch = objects_per_span; + // Allocate all objects from kNumSpans. + for (int span = 0; span < kNumSpans; ++span) { + size_t fetched = 0; + while (fetched < to_fetch) { + const size_t n = to_fetch - fetched; + int got = e.central_freelist().RemoveRange( + absl::MakeSpan(batch, std::min(n, e.batch_size()))); + for (int i = 0; i < got; ++i) { + objects[span].push_back(batch[i]); + } + fetched += got; + } + } + + // Perform deallocations so that each span contains only two objects. + size_t to_release = to_fetch - 2; + for (int span = 0; span < kNumSpans; ++span) { + size_t released = 0; + while (released < to_release) { + uint64_t n = std::min(to_release - released, e.batch_size()); + for (int i = 0; i < n; ++i) { + batch[i] = objects[span][i + released]; + } + released += n; + e.central_freelist().InsertRange({batch, n}); + } + objects[span].erase(objects[span].begin(), + objects[span].begin() + released); + } + + // Make sure we have kNumSpans in the expected second-last nonempty_ list. + EXPECT_EQ(e.central_freelist().NumSpansInList(kNumLists - 2), kNumSpans); + + // Release an additional object from all but one spans so that they are + // deprioritized for subsequent allocations. + to_release = 1; + for (int span = 1; span < kNumSpans; ++span) { + size_t released = 0; + while (released < to_release) { + uint64_t n = std::min(to_release - released, e.batch_size()); + for (int i = 0; i < n; ++i) { + batch[i] = objects[span][i + released]; + } + released += n; + e.central_freelist().InsertRange({batch, n}); + } + objects[span].erase(objects[span].begin(), + objects[span].begin() + released); + } + + // Make sure we have kNumSpans-1 spans in the last nonempty_ list and just one + // span in the second-last list. + EXPECT_EQ(e.central_freelist().NumSpansInList(kNumLists - 1), kNumSpans - 1); + EXPECT_EQ(e.central_freelist().NumSpansInList(kNumLists - 2), 1); + + // Allocate one object to ensure that it is being allocated from the span with + // the highest number of allocated objects. + int got = e.central_freelist().RemoveRange(absl::MakeSpan(batch, 1)); + EXPECT_EQ(got, 1); + // Number of spans in the last nonempty_ list should be unchanged (i.e. + // kNumSpans-1). + EXPECT_EQ(e.central_freelist().NumSpansInList(kNumLists - 1), kNumSpans - 1); + if (e.objects_per_span() == 3) { + // Since we allocated another object from the span that had two objects + // allocated from it, so the span would no longer be there in the span list. + for (int i = kNumLists - 2; i >= 0; --i) { + EXPECT_EQ(e.central_freelist().NumSpansInList(i), 0); + } + } else if (e.objects_per_span() <= 2 * kNumLists) { + // We should have only one span in the third-last nonempty_ list; this is + // the span from which we should have allocated the last object. + EXPECT_EQ(e.central_freelist().NumSpansInList(kNumLists - 3), 1); + } else { + // We should have only one span in the second-last nonempty_ list; this is + // the span from which we should have allocated the last object. + EXPECT_EQ(e.central_freelist().NumSpansInList(kNumLists - 2), 1); + } + // Return previously allocated object. + e.central_freelist().InsertRange({batch, 1}); + + // Return rest of the objects. + for (int span = 0; span < kNumSpans; ++span) { + for (int i = 0; i < objects[span].size(); ++i) { + e.central_freelist().InsertRange({&objects[span][i], 1}); + } + } } -TEST_P(CFLTest, MultipleSpans) { +TEST_P(CentralFreeListTest, SpanLifetime) { + TypeParam e(std::get<0>(GetParam()).size, std::get<0>(GetParam()).pages, + std::get<0>(GetParam()).num_to_move, std::get<1>(GetParam())); + + const uint32_t max_span_cache_size = e.forwarder().max_span_cache_size(); + if (max_span_cache_size != Span::kLargeCacheSize) { + GTEST_SKIP() << "Skipping test when cache size is small. We do not " + "record lifetime telemetry."; + } + const size_t object_size = + e.central_freelist().forwarder().class_to_size(TypeParam::kSizeClass); + if (Span::UseBitmapForSize(object_size)) { + GTEST_SKIP() << "Bitmap is used for size class. We do not " + "record lifetime telemetry."; + } std::vector all_objects; - const size_t num_spans = 10; + // Request kNumSpans spans. + void* batch[kMaxObjectsToMove]; + ASSERT_GT(e.objects_per_span(), 0); + int got = e.central_freelist().RemoveRange(absl::MakeSpan(batch, 1)); + ASSERT_EQ(got, 1); + + e.forwarder().AdvanceClock(absl::Seconds(1)); + + { + std::string buffer(1024 * 1024, '\0'); + Printer printer(&*buffer.begin(), buffer.size()); + e.central_freelist().PrintSpanLifetimeStats(printer); + buffer.resize(strlen(buffer.c_str())); + + EXPECT_THAT( + buffer, + testing::HasSubstr( + R"(0 ms < 0, 1 ms < 0, 10 ms < 0,100 ms < 0,1000 ms < 1,10000 ms < 0,100000 ms < 0,1000000 ms < 0)")); + } + + e.forwarder().AdvanceClock(absl::Seconds(10)); + { + std::string buffer(1024 * 1024, '\0'); + Printer printer(&*buffer.begin(), buffer.size()); + e.central_freelist().PrintSpanLifetimeStats(printer); + buffer.resize(strlen(buffer.c_str())); + + EXPECT_THAT( + buffer, + testing::HasSubstr( + R"(0 ms < 0, 1 ms < 0, 10 ms < 0,100 ms < 0,1000 ms < 0,10000 ms < 1,100000 ms < 0,1000000 ms < 0)")); + } + + e.forwarder().AdvanceClock(absl::Seconds(100)); + { + std::string buffer(1024 * 1024, '\0'); + Printer printer(&*buffer.begin(), buffer.size()); + e.central_freelist().PrintSpanLifetimeStats(printer); + buffer.resize(strlen(buffer.c_str())); + + EXPECT_THAT( + buffer, + testing::HasSubstr( + R"(0 ms < 0, 1 ms < 0, 10 ms < 0,100 ms < 0,1000 ms < 0,10000 ms < 0,100000 ms < 1,1000000 ms < 0)")); + } + + e.forwarder().AdvanceClock(absl::Seconds(1000)); + { + std::string buffer(1024 * 1024, '\0'); + Printer printer(&*buffer.begin(), buffer.size()); + e.central_freelist().PrintSpanLifetimeStats(printer); + buffer.resize(strlen(buffer.c_str())); - // Request num_spans spans + EXPECT_THAT( + buffer, + testing::HasSubstr( + R"(0 ms < 0, 1 ms < 0, 10 ms < 0,100 ms < 0,1000 ms < 0,10000 ms < 0,100000 ms < 0,1000000 ms < 1)")); + } + + e.central_freelist().InsertRange({batch, 1}); +} + +TEST_P(CentralFreeListTest, MultipleSpans) { + TypeParam e(std::get<0>(GetParam()).size, std::get<0>(GetParam()).pages, + std::get<0>(GetParam()).num_to_move, std::get<1>(GetParam())); + std::vector all_objects; + constexpr size_t kNumSpans = 10; + + // Request kNumSpans spans. void* batch[kMaxObjectsToMove]; - const int num_objects_to_fetch = num_spans * objects_per_span_; + ASSERT_GT(e.objects_per_span(), 0); + const int num_objects_to_fetch = kNumSpans * e.objects_per_span(); int total_fetched = 0; while (total_fetched < num_objects_to_fetch) { size_t n = num_objects_to_fetch - total_fetched; - int got = cfl_.RemoveRange(batch, std::min(n, batch_size_)); + int got = e.central_freelist().RemoveRange( + absl::MakeSpan(batch, std::min(n, e.batch_size()))); for (int i = 0; i < got; ++i) { all_objects.push_back(batch[i]); } total_fetched += got; } - SpanStats stats = cfl_.GetSpanStats(); - EXPECT_EQ(stats.num_spans_requested, num_spans); - EXPECT_EQ(stats.num_spans_returned, 0); + // We should have kNumSpans spans in the histogram with number of + // allocated objects equal to e.objects_per_span() (i.e. in the last + // bucket). Rest of the buckets should be empty. + const int expected_bitwidth = absl::bit_width(e.objects_per_span()); + // Skip the check for objects_per_span = 1 since such spans skip most of the + // central freelist's logic. + if (e.objects_per_span() != 1) { + EXPECT_EQ(e.central_freelist().NumSpansWith(expected_bitwidth), kNumSpans); + } + for (int i = 1; i < expected_bitwidth; ++i) { + EXPECT_EQ(e.central_freelist().NumSpansWith(i), 0); + } + + // Skip the check for objects_per_span = 1 since such spans skip most of the + // central freelist's logic. + if (e.objects_per_span() != 1) { + SpanStats stats = e.central_freelist().GetSpanStats(); + EXPECT_EQ(stats.num_spans_requested, kNumSpans); + EXPECT_EQ(stats.num_spans_returned, 0); + } EXPECT_EQ(all_objects.size(), num_objects_to_fetch); @@ -92,30 +827,108 @@ TEST_P(CFLTest, MultipleSpans) { // Return all int total_returned = 0; - bool checked_half = false; while (total_returned < num_objects_to_fetch) { uint64_t size_to_pop = - std::min(all_objects.size() - total_returned, batch_size_); + std::min(all_objects.size() - total_returned, e.batch_size()); for (int i = 0; i < size_to_pop; ++i) { batch[i] = all_objects[i + total_returned]; } total_returned += size_to_pop; - cfl_.InsertRange({batch, size_to_pop}); + e.central_freelist().InsertRange({batch, size_to_pop}); // sanity check - if (!checked_half && total_returned >= (num_objects_to_fetch / 2)) { - stats = cfl_.GetSpanStats(); + if (e.objects_per_span() != 1 && total_returned < num_objects_to_fetch) { + SpanStats stats = e.central_freelist().GetSpanStats(); EXPECT_GT(stats.num_spans_requested, stats.num_spans_returned); EXPECT_NE(stats.obj_capacity, 0); - checked_half = true; + // Total spans recorded in the histogram must be equal to the number of + // live spans. + size_t spans_in_histogram = 0; + for (int i = 1; i <= absl::bit_width(e.objects_per_span()); ++i) { + spans_in_histogram += e.central_freelist().NumSpansWith(i); + } + EXPECT_EQ(spans_in_histogram, stats.num_live_spans()); } } - stats = cfl_.GetSpanStats(); + SpanStats stats = e.central_freelist().GetSpanStats(); EXPECT_EQ(stats.num_spans_requested, stats.num_spans_returned); + // Since no span is live, histogram must be empty. + for (int i = 1; i <= absl::bit_width(e.objects_per_span()); ++i) { + EXPECT_EQ(e.central_freelist().NumSpansWith(i), 0); + } EXPECT_EQ(stats.obj_capacity, 0); } -INSTANTIATE_TEST_SUITE_P(All, CFLTest, testing::Range(size_t(1), kNumClasses)); +TEST_P(CentralFreeListTest, PassSpanDensityToPageheap) { + TypeParam e(std::get<0>(GetParam()).size, std::get<0>(GetParam()).pages, + std::get<0>(GetParam()).num_to_move, std::get<1>(GetParam())); + ASSERT_GE(e.objects_per_span(), 1); + auto test_function = [&](size_t num_objects, + AccessDensityPrediction density) { + std::vector objects(e.objects_per_span()); + EXPECT_CALL(e.forwarder(), AllocateSpan(testing::_, testing::_, testing::_)) + .Times(1); + const size_t to_fetch = std::min(e.objects_per_span(), e.batch_size()); + const size_t fetched = + e.central_freelist().RemoveRange(absl::MakeSpan(&objects[0], to_fetch)); + size_t returned = 0; + while (returned < fetched) { + EXPECT_CALL(e.forwarder(), DeallocateSpans(testing::_, testing::_)) + .Times(1); + const size_t to_return = std::min(fetched - returned, e.batch_size()); + e.central_freelist().InsertRange({&objects[returned], to_return}); + returned += to_return; + } + }; + test_function(1, AccessDensityPrediction::kDense); + test_function(e.objects_per_span(), AccessDensityPrediction::kDense); +} + +TEST_P(CentralFreeListTest, SpanFragmentation) { + // This test is primarily exercising Span itself to model how tcmalloc.cc uses + // it, but this gives us a self-contained (and sanitizable) implementation of + // the CentralFreeList. + TypeParam e(std::get<0>(GetParam()).size, std::get<0>(GetParam()).pages, + std::get<0>(GetParam()).num_to_move, std::get<1>(GetParam())); + // Allocate one object from the CFL to allocate a span. + void* initial; + int got = e.central_freelist().RemoveRange(absl::MakeSpan(&initial, 1)); + ASSERT_EQ(got, 1); + + Span* const span = e.central_freelist().forwarder().MapObjectToSpan(initial); + const size_t object_size = + e.central_freelist().forwarder().class_to_size(TypeParam::kSizeClass); + + ThreadManager fragmentation; + fragmentation.Start(1, [&](int) { + if (e.objects_per_span() != 1) { + benchmark::DoNotOptimize(span->Fragmentation(object_size)); + } + }); + + ThreadManager cfl; + cfl.Start(1, [&](int) { + void* next; + int got = e.central_freelist().RemoveRange(absl::MakeSpan(&next, 1)); + e.central_freelist().InsertRange(absl::MakeSpan(&next, got)); + }); + + absl::SleepFor(absl::Seconds(0.1)); + + fragmentation.Stop(); + cfl.Stop(); + + e.central_freelist().InsertRange(absl::MakeSpan(&initial, 1)); +} + +INSTANTIATE_TEST_SUITE_P( + CentralFreeList, CentralFreeListTest, + testing::Combine( + // We skip the first size class since it is set to 0. + testing::ValuesIn(kSizeClasses.classes.begin() + 1, + kSizeClasses.classes.end()), + /*use_large_spans=*/testing::Values(false, true))); + } // namespace } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/common.cc b/contrib/libs/tcmalloc/tcmalloc/common.cc index 38443040cad2..155893724841 100644 --- a/contrib/libs/tcmalloc/tcmalloc/common.cc +++ b/contrib/libs/tcmalloc/tcmalloc/common.cc @@ -14,189 +14,17 @@ #include "tcmalloc/common.h" -#include "tcmalloc/experiment.h" -#include "tcmalloc/internal/environment.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/optimization.h" -#include "tcmalloc/pages.h" -#include "tcmalloc/runtime_size_classes.h" -#include "tcmalloc/sampler.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { -absl::string_view MemoryTagToLabel(MemoryTag tag) { - switch (tag) { - case MemoryTag::kNormal: - return "NORMAL"; - case MemoryTag::kNormalP1: - return "NORMAL_P1"; - case MemoryTag::kSampled: - return "SAMPLED"; - default: - ASSUME(false); - } -} - -// Load sizes classes from environment variable if present -// and valid, then returns True. If not found or valid, returns -// False. -bool SizeMap::MaybeRunTimeSizeClasses() { - SizeClassInfo parsed[kNumClasses]; - int num_classes = MaybeSizeClassesFromEnv(kMaxSize, kNumClasses, parsed); - if (!ValidSizeClasses(num_classes, parsed)) { - return false; - } - - if (num_classes != kSizeClassesCount) { - // TODO(b/122839049) - Add tests for num_classes < kSizeClassesCount before - // allowing that case. - Log(kLog, __FILE__, __LINE__, "Can't change the number of size classes", - num_classes, kSizeClassesCount); - return false; - } - - SetSizeClasses(num_classes, parsed); - Log(kLog, __FILE__, __LINE__, "Loaded valid Runtime Size classes"); - return true; -} - -void SizeMap::SetSizeClasses(int num_classes, const SizeClassInfo* parsed) { - class_to_size_[0] = 0; - class_to_pages_[0] = 0; - num_objects_to_move_[0] = 0; - - for (int c = 1; c < num_classes; c++) { - class_to_size_[c] = parsed[c].size; - class_to_pages_[c] = parsed[c].pages; - num_objects_to_move_[c] = parsed[c].num_to_move; - } - - // Fill any unspecified size classes with 0. - for (int x = num_classes; x < kNumBaseClasses; x++) { - class_to_size_[x] = 0; - class_to_pages_[x] = 0; - num_objects_to_move_[x] = 0; - } - - // Copy selected size classes into the upper registers. - for (int i = 1; i < (kNumClasses / kNumBaseClasses); i++) { - std::copy(&class_to_size_[0], &class_to_size_[kNumBaseClasses], - &class_to_size_[kNumBaseClasses * i]); - std::copy(&class_to_pages_[0], &class_to_pages_[kNumBaseClasses], - &class_to_pages_[kNumBaseClasses * i]); - std::copy(&num_objects_to_move_[0], &num_objects_to_move_[kNumBaseClasses], - &num_objects_to_move_[kNumBaseClasses * i]); - } -} - -// Return true if all size classes meet the requirements for alignment -// ordering and min and max values. -bool SizeMap::ValidSizeClasses(int num_classes, const SizeClassInfo* parsed) { - if (num_classes <= 0) { - return false; - } - if (kHasExpandedClasses && num_classes > kNumBaseClasses) { - num_classes = kNumBaseClasses; - } - - for (int c = 1; c < num_classes; c++) { - size_t class_size = parsed[c].size; - size_t pages = parsed[c].pages; - size_t num_objects_to_move = parsed[c].num_to_move; - // Each size class must be larger than the previous size class. - if (class_size <= parsed[c - 1].size) { - Log(kLog, __FILE__, __LINE__, "Non-increasing size class", c, - parsed[c - 1].size, class_size); - return false; - } - if (class_size > kMaxSize) { - Log(kLog, __FILE__, __LINE__, "size class too big", c, class_size, - kMaxSize); - return false; - } - // Check required alignment - size_t alignment = 128; - if (class_size <= kMultiPageSize) { - alignment = kAlignment; - } else if (class_size <= SizeMap::kMaxSmallSize) { - alignment = kMultiPageAlignment; - } - if ((class_size & (alignment - 1)) != 0) { - Log(kLog, __FILE__, __LINE__, "Not aligned properly", c, class_size, - alignment); - return false; - } - if (class_size <= kMultiPageSize && pages != 1) { - Log(kLog, __FILE__, __LINE__, "Multiple pages not allowed", class_size, - pages, kMultiPageSize); - return false; - } - if (pages >= 256) { - Log(kLog, __FILE__, __LINE__, "pages limited to 255", pages); - return false; - } - if (num_objects_to_move > kMaxObjectsToMove) { - Log(kLog, __FILE__, __LINE__, "num objects to move too large", - num_objects_to_move, kMaxObjectsToMove); - return false; - } - } - // Last size class must be able to hold kMaxSize. - if (parsed[num_classes - 1].size < kMaxSize) { - Log(kLog, __FILE__, __LINE__, "last class doesn't cover kMaxSize", - num_classes - 1, parsed[num_classes - 1].size, kMaxSize); - return false; - } - return true; -} - -int ABSL_ATTRIBUTE_WEAK default_want_legacy_spans(); - -// Initialize the mapping arrays -void SizeMap::Init() { - // Do some sanity checking on add_amount[]/shift_amount[]/class_array[] - if (ClassIndex(0) != 0) { - Crash(kCrash, __FILE__, __LINE__, "Invalid class index for size 0", - ClassIndex(0)); - } - if (ClassIndex(kMaxSize) >= sizeof(class_array_)) { - Crash(kCrash, __FILE__, __LINE__, "Invalid class index for kMaxSize", - ClassIndex(kMaxSize)); - } - - static_assert(kAlignment <= 16, "kAlignment is too large"); - - if (IsExperimentActive(Experiment::TEST_ONLY_TCMALLOC_POW2_SIZECLASS)) { - SetSizeClasses(kExperimentalPow2SizeClassesCount, - kExperimentalPow2SizeClasses); - } else if (IsExperimentActive( - Experiment::TEST_ONLY_TCMALLOC_POW2_BELOW64_SIZECLASS)) { - SetSizeClasses(kExperimentalPow2Below64SizeClassesCount, - kExperimentalPow2Below64SizeClasses); - } else { - if (default_want_legacy_spans != nullptr && - default_want_legacy_spans() > 0 - ) { - SetSizeClasses(kLegacySizeClassesCount, kLegacySizeClasses); - } else { - SetSizeClasses(kSizeClassesCount, kSizeClasses); - } - } - MaybeRunTimeSizeClasses(); - - int next_size = 0; - for (int c = 1; c < kNumClasses; c++) { - const int max_size_in_class = class_to_size_[c]; - - for (int s = next_size; s <= max_size_in_class; s += kAlignment) { - class_array_[ClassIndex(s)] = c; - } - next_size = max_size_in_class + kAlignment; - if (next_size > kMaxSize) { - break; - } - } +// This only provides correct answer for TCMalloc-allocated memory, +// and may give a false positive for non-allocated block. +extern "C" bool TCMalloc_Internal_PossiblyCold(const void* ptr) { + return GetMemoryTag(ptr) == MemoryTag::kCold; } } // namespace tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/common.h b/contrib/libs/tcmalloc/tcmalloc/common.h index d44811c72662..c9de12a5bb89 100644 --- a/contrib/libs/tcmalloc/tcmalloc/common.h +++ b/contrib/libs/tcmalloc/tcmalloc/common.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,27 +21,28 @@ #include #include +#include +#include #include +#include #include -#include "absl/base/attributes.h" -#include "absl/base/dynamic_annotations.h" #include "absl/base/internal/spinlock.h" -#include "absl/base/macros.h" #include "absl/base/optimization.h" #include "absl/numeric/bits.h" #include "absl/strings/string_view.h" -#include "absl/types/span.h" -#include "tcmalloc/experiment.h" #include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/memory_tag.h" #include "tcmalloc/internal/optimization.h" -#include "tcmalloc/size_class_info.h" +#include "tcmalloc/malloc_extension.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { +static_assert(sizeof(void*) == 8); + //------------------------------------------------------------------- // Configuration //------------------------------------------------------------------- @@ -52,12 +54,12 @@ namespace tcmalloc_internal { // The default configuration strives for good performance while trying to // minimize fragmentation. It uses a smaller page size to reduce // fragmentation, but allocates per-thread and per-cpu capacities similar to -// TCMALLOC_LARGE_PAGES / TCMALLOC_256K_PAGES. +// TCMALLOC_INTERNAL_32K_PAGES / TCMALLOC_INTERNAL_256K_PAGES. // -// TCMALLOC_LARGE_PAGES: -// Larger page sizes increase the bookkeeping granularity used by TCMalloc for -// its allocations. This can reduce PageMap size and traffic to the -// innermost cache (the page heap), but can increase memory footprints. As +// TCMALLOC_INTERNAL_32K_PAGES: +// Larger page sizes (32KB) increase the bookkeeping granularity used by +// TCMalloc for its allocations. This can reduce PageMap size and traffic to +// the innermost cache (the page heap), but can increase memory footprints. As // TCMalloc will not reuse a page for a different allocation size until the // entire page is deallocated, this can be a source of increased memory // fragmentation. @@ -68,11 +70,11 @@ namespace tcmalloc_internal { // (https://isocpp.org/files/papers/n3778.html), this optimization is less // significant. // -// TCMALLOC_256K_PAGES +// TCMALLOC_INTERNAL_256K_PAGES // This configuration uses an even larger page size (256KB) as the unit of // accounting granularity. // -// TCMALLOC_SMALL_BUT_SLOW: +// TCMALLOC_INTERNAL_SMALL_BUT_SLOW: // Used for situations where minimizing the memory footprint is the most // desirable attribute, even at the cost of performance. // @@ -88,17 +90,18 @@ namespace tcmalloc_internal { // kStealAmount - The number of bytes one ThreadCache will steal from another // when the first ThreadCache is forced to Scavenge(), delaying the next // call to Scavenge for this thread. +// kDefaultProfileSamplingInterval - Bytes between sampled allocations. // Older configurations had their own customized macros. Convert them into // a page-shift parameter that is checked below. #ifndef TCMALLOC_PAGE_SHIFT -#ifdef TCMALLOC_SMALL_BUT_SLOW +#ifdef TCMALLOC_INTERNAL_SMALL_BUT_SLOW #define TCMALLOC_PAGE_SHIFT 12 #define TCMALLOC_USE_PAGEMAP3 -#elif defined(TCMALLOC_256K_PAGES) +#elif defined(TCMALLOC_INTERNAL_256K_PAGES) #define TCMALLOC_PAGE_SHIFT 18 -#elif defined(TCMALLOC_LARGE_PAGES) +#elif defined(TCMALLOC_INTERNAL_32K_PAGES) #define TCMALLOC_PAGE_SHIFT 15 #else #define TCMALLOC_PAGE_SHIFT 13 @@ -107,6 +110,14 @@ namespace tcmalloc_internal { #error "TCMALLOC_PAGE_SHIFT is an internal macro!" #endif +#if defined(TCMALLOC_INTERNAL_SMALL_BUT_SLOW) + \ + defined(TCMALLOC_INTERNAL_8K_PAGES) + \ + defined(TCMALLOC_INTERNAL_256K_PAGES) + \ + defined(TCMALLOC_INTERNAL_32K_PAGES) > \ + 1 +#error "At most 1 variant configuration must be used." +#endif + #if TCMALLOC_PAGE_SHIFT == 12 inline constexpr size_t kPageShift = 12; inline constexpr size_t kNumBaseClasses = 46; @@ -114,11 +125,10 @@ inline constexpr bool kHasExpandedClasses = false; inline constexpr size_t kMaxSize = 8 << 10; inline constexpr size_t kMinThreadCacheSize = 4 * 1024; inline constexpr size_t kMaxThreadCacheSize = 64 * 1024; -inline constexpr size_t kMaxCpuCacheSize = 20 * 1024; +inline constexpr size_t kMaxCpuCacheSize = 10 * 1024; inline constexpr size_t kDefaultOverallThreadCacheSize = kMaxThreadCacheSize; inline constexpr size_t kStealAmount = kMinThreadCacheSize; -inline constexpr size_t kDefaultProfileSamplingRate = 1 << 19; -inline constexpr size_t kMinPages = 2; +inline constexpr size_t kDefaultProfileSamplingInterval = 1 << 19; #elif TCMALLOC_PAGE_SHIFT == 15 inline constexpr size_t kPageShift = 15; inline constexpr size_t kNumBaseClasses = 78; @@ -126,12 +136,11 @@ inline constexpr bool kHasExpandedClasses = true; inline constexpr size_t kMaxSize = 256 * 1024; inline constexpr size_t kMinThreadCacheSize = kMaxSize * 2; inline constexpr size_t kMaxThreadCacheSize = 4 << 20; -inline constexpr size_t kMaxCpuCacheSize = 3 * 1024 * 1024; +inline constexpr size_t kMaxCpuCacheSize = 1.5 * 1024 * 1024; inline constexpr size_t kDefaultOverallThreadCacheSize = 8u * kMaxThreadCacheSize; inline constexpr size_t kStealAmount = 1 << 16; -inline constexpr size_t kDefaultProfileSamplingRate = 1 << 21; -inline constexpr size_t kMinPages = 8; +inline constexpr size_t kDefaultProfileSamplingInterval = 1 << 21; #elif TCMALLOC_PAGE_SHIFT == 18 inline constexpr size_t kPageShift = 18; inline constexpr size_t kNumBaseClasses = 89; @@ -139,12 +148,11 @@ inline constexpr bool kHasExpandedClasses = true; inline constexpr size_t kMaxSize = 256 * 1024; inline constexpr size_t kMinThreadCacheSize = kMaxSize * 2; inline constexpr size_t kMaxThreadCacheSize = 4 << 20; -inline constexpr size_t kMaxCpuCacheSize = 3 * 1024 * 1024; +inline constexpr size_t kMaxCpuCacheSize = 1.5 * 1024 * 1024; inline constexpr size_t kDefaultOverallThreadCacheSize = 8u * kMaxThreadCacheSize; inline constexpr size_t kStealAmount = 1 << 16; -inline constexpr size_t kDefaultProfileSamplingRate = 1 << 21; -inline constexpr size_t kMinPages = 8; +inline constexpr size_t kDefaultProfileSamplingInterval = 1 << 21; #elif TCMALLOC_PAGE_SHIFT == 13 inline constexpr size_t kPageShift = 13; inline constexpr size_t kNumBaseClasses = 86; @@ -152,22 +160,18 @@ inline constexpr bool kHasExpandedClasses = true; inline constexpr size_t kMaxSize = 256 * 1024; inline constexpr size_t kMinThreadCacheSize = kMaxSize * 2; inline constexpr size_t kMaxThreadCacheSize = 4 << 20; -inline constexpr size_t kMaxCpuCacheSize = 3 * 1024 * 1024; +inline constexpr size_t kMaxCpuCacheSize = 1.5 * 1024 * 1024; inline constexpr size_t kDefaultOverallThreadCacheSize = 8u * kMaxThreadCacheSize; inline constexpr size_t kStealAmount = 1 << 16; -inline constexpr size_t kDefaultProfileSamplingRate = 1 << 21; -inline constexpr size_t kMinPages = 8; +inline constexpr size_t kDefaultProfileSamplingInterval = 1 << 21; #else #error "Unsupported TCMALLOC_PAGE_SHIFT value!" #endif -// Sanitizers constrain the memory layout which causes problems with the -// enlarged tags required to represent NUMA partitions. Disable NUMA awareness -// to avoid failing to mmap memory. -#if defined(TCMALLOC_NUMA_AWARE) && !defined(MEMORY_SANITIZER) && \ - !defined(THREAD_SANITIZER) -inline constexpr size_t kNumaPartitions = 2; +// Disable NUMA awareness under Sanitizers to avoid failing to mmap memory. +#if defined(TCMALLOC_INTERNAL_NUMA_AWARE) +inline constexpr size_t kNumaPartitions = kSanitizerAddressSpace ? 1 : 2; #else inline constexpr size_t kNumaPartitions = 1; #endif @@ -199,97 +203,56 @@ inline constexpr size_t kMinObjectsToMove = 2; inline constexpr size_t kMaxObjectsToMove = 128; inline constexpr size_t kPageSize = 1 << kPageShift; -// Verify that the page size used is at least 8x smaller than the maximum -// element size in the thread cache. This guarantees at most 12.5% internal -// fragmentation (1/8). When page size is 256k (kPageShift == 18), the benefit -// of increasing kMaxSize to be multiple of kPageSize is unclear. Object size -// profile data indicates that the number of simultaneously live objects (of -// size >= 256k) tends to be very small. Keeping those objects as 'large' -// objects won't cause too much memory waste, while heap memory reuse can be -// improved. Increasing kMaxSize to be too large has another bad side effect -- -// the thread cache pressure is increased, which will in turn increase traffic -// between central cache and thread cache, leading to performance degradation. -static_assert((kMaxSize / kPageSize) >= kMinPages || kPageShift >= 18, - "Ratio of kMaxSize / kPageSize is too small"); - -inline constexpr size_t kAlignment = 8; + +inline constexpr std::align_val_t kAlignment{8}; // log2 (kAlignment) -inline constexpr size_t kAlignmentShift = absl::bit_width(kAlignment - 1u); +inline constexpr size_t kAlignmentShift = + absl::bit_width(static_cast(kAlignment) - 1u); // The number of times that a deallocation can cause a freelist to // go over its max_length() before shrinking max_length(). inline constexpr int kMaxOverages = 3; // Maximum length we allow a per-thread free-list to have before we -// move objects from it into the corresponding central free-list. We -// want this big to avoid locking the central free-list too often. It +// move objects from it into the corresponding transfer cache. We +// want this big to avoid locking the transfer cache too often. It // should not hurt to make this list somewhat big because the // scavenging code will shrink it down when its contents are not in use. -inline constexpr int kMaxDynamicFreeListLength = 8192; - -enum class MemoryTag : uint8_t { - // Sampled, infrequently allocated - kSampled = 0x0, - // Not sampled, NUMA partition 0 - kNormalP0 = 0x1, - // Not sampled, NUMA partition 1 - kNormalP1 = (kNumaPartitions > 1) ? 0x2 : 0xff, - // Not sampled - kNormal = kNormalP0, -}; +inline constexpr size_t kMaxDynamicFreeListLength = 8192; -inline constexpr uintptr_t kTagShift = std::min(kAddressBits - 4, 42); -inline constexpr uintptr_t kTagMask = uintptr_t{0x3} << kTagShift; +inline constexpr bool ColdFeatureActive() { return kHasExpandedClasses; } -// Returns true if ptr is tagged. -ABSL_DEPRECATED("Replace with specific tests") -inline bool IsTaggedMemory(const void* ptr) { - return (reinterpret_cast(ptr) & kTagMask) == 0; +inline constexpr bool IsExpandedSizeClass(unsigned size_class) { + return kHasExpandedClasses && (size_class >= kExpandedClassesStart); } -inline bool IsSampledMemory(const void* ptr) { - constexpr uintptr_t kSampledNormalMask = kNumaPartitions > 1 ? 0x3 : 0x1; - - static_assert(static_cast(MemoryTag::kNormalP0) & - kSampledNormalMask); - static_assert(static_cast(MemoryTag::kNormalP1) & - kSampledNormalMask); - - const uintptr_t tag = - (reinterpret_cast(ptr) & kTagMask) >> kTagShift; - return (tag & kSampledNormalMask) == - static_cast(MemoryTag::kSampled); -} - -inline bool IsNormalMemory(const void* ptr) { return !IsSampledMemory(ptr); } - -inline MemoryTag GetMemoryTag(const void* ptr) { - return static_cast((reinterpret_cast(ptr) & kTagMask) >> - kTagShift); -} - -absl::string_view MemoryTagToLabel(MemoryTag tag); - -inline constexpr bool IsExpandedSizeClass(unsigned cl) { - return kHasExpandedClasses && (cl >= kExpandedClassesStart); -} - -#if !defined(TCMALLOC_SMALL_BUT_SLOW) && __SIZEOF_POINTER__ != 4 -// Always allocate at least a huge page -inline constexpr size_t kMinSystemAlloc = kHugePageSize; +#if !defined(TCMALLOC_INTERNAL_SMALL_BUT_SLOW) inline constexpr size_t kMinMmapAlloc = 1 << 30; // mmap() in 1GiB ranges. #else -// Allocate in units of 2MiB. This is the size of a huge page for x86, but -// not for Power. -inline constexpr size_t kMinSystemAlloc = 2 << 20; // mmap() in units of 32MiB. This is a multiple of huge page size for // both x86 (2MiB) and Power (16MiB) inline constexpr size_t kMinMmapAlloc = 32 << 20; #endif -static_assert(kMinMmapAlloc % kMinSystemAlloc == 0, - "Minimum mmap allocation size is not a multiple of" - " minimum system allocation size"); +static_assert( + kMinMmapAlloc % kHugePageSize == 0, + "Minimum mmap allocation size is not a multiple of the huge page size"); + +enum class AllocationAccess { + kHot, + kCold, +}; + +inline AllocationAccess AccessFromPointer(void* ptr) { + if (!kHasExpandedClasses) { + TC_ASSERT_NE(GetMemoryTag(ptr), MemoryTag::kCold); + return AllocationAccess::kHot; + } + + return ABSL_PREDICT_FALSE(GetMemoryTag(ptr) == MemoryTag::kCold) + ? AllocationAccess::kCold + : AllocationAccess::kHot; +} inline MemoryTag NumaNormalTag(size_t numa_partition) { switch (numa_partition) { @@ -316,206 +279,29 @@ inline size_t NumaPartitionFromPointer(void* ptr) { } } -// Size-class information + mapping -class SizeMap { - public: - // All size classes <= 512 in all configs always have 1 page spans. - static constexpr size_t kMultiPageSize = 512; - // Min alignment for all size classes > kMultiPageSize in all configs. - static constexpr size_t kMultiPageAlignment = 64; - // log2 (kMultiPageAlignment) - static constexpr size_t kMultiPageAlignmentShift = - absl::bit_width(kMultiPageAlignment - 1u); - - private: - //------------------------------------------------------------------- - // Mapping from size to size_class and vice versa - //------------------------------------------------------------------- - - // Sizes <= 1024 have an alignment >= 8. So for such sizes we have an - // array indexed by ceil(size/8). Sizes > 1024 have an alignment >= 128. - // So for these larger sizes we have an array indexed by ceil(size/128). - // - // We flatten both logical arrays into one physical array and use - // arithmetic to compute an appropriate index. The constants used by - // ClassIndex() were selected to make the flattening work. - // - // Examples: - // Size Expression Index - // ------------------------------------------------------- - // 0 (0 + 7) / 8 0 - // 1 (1 + 7) / 8 1 - // ... - // 1024 (1024 + 7) / 8 128 - // 1025 (1025 + 127 + (120<<7)) / 128 129 - // ... - // 32768 (32768 + 127 + (120<<7)) / 128 376 - static constexpr int kMaxSmallSize = 1024; - static constexpr size_t kClassArraySize = - ((kMaxSize + 127 + (120 << 7)) >> 7) + 1; - - // Batch size is the number of objects to move at once. - typedef unsigned char BatchSize; - - // class_array_ is accessed on every malloc, so is very hot. We make it the - // first member so that it inherits the overall alignment of a SizeMap - // instance. In particular, if we create a SizeMap instance that's cache-line - // aligned, this member is also aligned to the width of a cache line. - CompactSizeClass - class_array_[kClassArraySize * (kHasExpandedClasses ? 2 : 1)] = {0}; - - // Number of objects to move between a per-thread list and a central - // list in one shot. We want this to be not too small so we can - // amortize the lock overhead for accessing the central list. Making - // it too big may temporarily cause unnecessary memory wastage in the - // per-thread free list until the scavenger cleans up the list. - BatchSize num_objects_to_move_[kNumClasses] = {0}; - - // If size is no more than kMaxSize, compute index of the - // class_array[] entry for it, putting the class index in output - // parameter idx and returning true. Otherwise return false. - static inline bool ABSL_ATTRIBUTE_ALWAYS_INLINE - ClassIndexMaybe(size_t s, uint32_t* idx) { - if (ABSL_PREDICT_TRUE(s <= kMaxSmallSize)) { - *idx = (static_cast(s) + 7) >> 3; - return true; - } else if (s <= kMaxSize) { - *idx = (static_cast(s) + 127 + (120 << 7)) >> 7; - return true; - } - return false; - } - - static inline size_t ClassIndex(size_t s) { - uint32_t ret; - CHECK_CONDITION(ClassIndexMaybe(s, &ret)); - return ret; - } - - // Mapping from size class to number of pages to allocate at a time - unsigned char class_to_pages_[kNumClasses] = {0}; - - // Mapping from size class to max size storable in that class - uint32_t class_to_size_[kNumClasses] = {0}; - - // If environment variable defined, use it to override sizes classes. - // Returns true if all classes defined correctly. - bool MaybeRunTimeSizeClasses(); - - protected: - // Set the give size classes to be used by TCMalloc. - void SetSizeClasses(int num_classes, const SizeClassInfo* parsed); - - // Check that the size classes meet all requirements. - bool ValidSizeClasses(int num_classes, const SizeClassInfo* parsed); - - // Definition of size class that is set in size_classes.cc - static const SizeClassInfo kSizeClasses[]; - static const int kSizeClassesCount; - - static const SizeClassInfo kExperimentalPow2Below64SizeClasses[]; - static const int kExperimentalPow2Below64SizeClassesCount; - // kExperimentalPowBelow64SizeClassesCount - static const SizeClassInfo kExperimentalPow2SizeClasses[]; - static const int kExperimentalPow2SizeClassesCount; - - // Definition of size class that is set in size_classes.cc - static const SizeClassInfo kLegacySizeClasses[]; - static const int kLegacySizeClassesCount; +// Linker initialized, so this lock can be accessed at any time. +// Note: `CpuCache::ResizeInfo::lock` must be taken before the `pageheap_lock` +// if both are going to be held simultaneously. +extern absl::base_internal::SpinLock pageheap_lock; +class ABSL_SCOPED_LOCKABLE PageHeapSpinLockHolder { public: - // constexpr constructor to guarantee zero-initialization at compile-time. We - // rely on Init() to populate things. - constexpr SizeMap() = default; - - // Initialize the mapping arrays - void Init(); - - // Returns the size class for size `size` respecting the alignment - // requirements of `policy`. - // - // Returns true on success. Returns false if either: - // - the size exceeds the maximum size class size. - // - the align size is greater or equal to the default page size - // - no matching properly aligned size class is available - // - // Requires that policy.align() returns a non-zero power of 2. - // - // When policy.align() = 1 the default alignment of the size table will be - // used. If policy.align() is constexpr 1 (e.g. when using - // DefaultAlignPolicy) then alignment-related code will optimize away. - // - // TODO(b/171978365): Replace the output parameter with returning - // absl::optional. - template - inline bool ABSL_ATTRIBUTE_ALWAYS_INLINE GetSizeClass(Policy policy, - size_t size, - uint32_t* cl) { - const size_t align = policy.align(); - ASSERT(absl::has_single_bit(align)); - - if (ABSL_PREDICT_FALSE(align >= kPageSize)) { - // TODO(b/172060547): Consider changing this to align > kPageSize. - ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(cl, sizeof(*cl)); - return false; - } - - uint32_t idx; - if (ABSL_PREDICT_FALSE(!ClassIndexMaybe(size, &idx))) { - ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(cl, sizeof(*cl)); - return false; - } - *cl = class_array_[idx] + policy.scaled_numa_partition(); - - // Predict that size aligned allocs most often directly map to a proper - // size class, i.e., multiples of 32, 64, etc, matching our class sizes. - const size_t mask = (align - 1); - do { - if (ABSL_PREDICT_TRUE((class_to_size(*cl) & mask) == 0)) { - return true; - } - } while ((++*cl % kNumBaseClasses) != 0); - - ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(cl, sizeof(*cl)); - return false; - } + PageHeapSpinLockHolder() + ABSL_EXCLUSIVE_LOCK_FUNCTION(pageheap_lock) = default; + ~PageHeapSpinLockHolder() ABSL_UNLOCK_FUNCTION() = default; - // Returns size class for given size, or 0 if this instance has not been - // initialized yet. REQUIRES: size <= kMaxSize. - template - inline size_t ABSL_ATTRIBUTE_ALWAYS_INLINE SizeClass(Policy policy, - size_t size) { - ASSERT(size <= kMaxSize); - uint32_t ret = 0; - GetSizeClass(policy, size, &ret); - return ret; - } - - // Get the byte-size for a specified class. REQUIRES: cl <= kNumClasses. - inline size_t ABSL_ATTRIBUTE_ALWAYS_INLINE class_to_size(size_t cl) { - ASSERT(cl < kNumClasses); - return class_to_size_[cl]; - } - - // Mapping from size class to number of pages to allocate at a time - inline size_t class_to_pages(size_t cl) { - ASSERT(cl < kNumClasses); - return class_to_pages_[cl]; - } - - // Number of objects to move between a per-thread list and a central - // list in one shot. We want this to be not too small so we can - // amortize the lock overhead for accessing the central list. Making - // it too big may temporarily cause unnecessary memory wastage in the - // per-thread free list until the scavenger cleans up the list. - inline SizeMap::BatchSize num_objects_to_move(size_t cl) { - ASSERT(cl < kNumClasses); - return num_objects_to_move_[cl]; - } + private: + AllocationGuardSpinLockHolder lock_{&pageheap_lock}; }; -// Linker initialized, so this lock can be accessed at any time. -extern absl::base_internal::SpinLock pageheap_lock; +// Evaluates a/b, avoiding division by zero. +inline double safe_div(double a, double b) { + if (b == 0) { + return 0.; + } else { + return a / b; + } +} } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/copts.bzl b/contrib/libs/tcmalloc/tcmalloc/copts.bzl new file mode 100644 index 000000000000..81cfe8fa3367 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/copts.bzl @@ -0,0 +1,49 @@ +# Copyright 2019 The TCMalloc Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This package provides default compiler warning flags for the OSS release""" + +TCMALLOC_LLVM_FLAGS = [ + # Ensure TCMalloc itself builds without errors, even if its dependencies + # aren't necessarily -Werror clean. + "-Werror", + "-Wno-deprecated-declarations", + "-Wno-deprecated-volatile", + "-Wno-implicit-int-float-conversion", + "-Wno-sign-compare", + "-Wno-uninitialized", + "-Wno-unused-function", + "-Wno-unused-variable", +] + +TCMALLOC_GCC_FLAGS = [ + # Ensure TCMalloc itself builds without errors, even if its dependencies + # aren't necessarily -Werror clean. + "-Werror", + "-Wno-array-bounds", + "-Wno-attribute-alias", + "-Wno-deprecated-declarations", + "-Wno-sign-compare", + "-Wno-stringop-overflow", + "-Wno-uninitialized", + "-Wno-unused-function", + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 + "-Wno-unused-result", + "-Wno-unused-variable", +] + +TCMALLOC_DEFAULT_COPTS = select({ + "//tcmalloc:llvm": TCMALLOC_LLVM_FLAGS, + "//conditions:default": TCMALLOC_GCC_FLAGS, +}) diff --git a/contrib/libs/tcmalloc/tcmalloc/cpu_cache.cc b/contrib/libs/tcmalloc/tcmalloc/cpu_cache.cc index 8ae02b38e9ce..15c7e65f3daf 100644 --- a/contrib/libs/tcmalloc/tcmalloc/cpu_cache.cc +++ b/contrib/libs/tcmalloc/tcmalloc/cpu_cache.cc @@ -15,1090 +15,31 @@ #include "tcmalloc/cpu_cache.h" #include -#include -#include -#include +#include +#include -#include "absl/base/dynamic_annotations.h" -#include "absl/base/internal/spinlock.h" -#include "absl/base/internal/sysinfo.h" -#include "absl/base/macros.h" -#include "absl/base/thread_annotations.h" -#include "absl/container/fixed_array.h" -#include "tcmalloc/arena.h" -#include "tcmalloc/common.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/percpu.h" #include "tcmalloc/internal_malloc_extension.h" #include "tcmalloc/parameters.h" #include "tcmalloc/static_vars.h" -#include "tcmalloc/transfer_cache.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { -static cpu_set_t FillActiveCpuMask() { - cpu_set_t allowed_cpus; - if (sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus) != 0) { - CPU_ZERO(&allowed_cpus); - } - -#ifdef PERCPU_USE_RSEQ - const bool real_cpus = !subtle::percpu::UsingFlatVirtualCpus(); -#else - const bool real_cpus = true; -#endif - - if (real_cpus) { - return allowed_cpus; - } - - const int virtual_cpu_count = CPU_COUNT(&allowed_cpus); - CPU_ZERO(&allowed_cpus); - for (int cpu = 0; cpu < virtual_cpu_count; ++cpu) { - CPU_SET(cpu, &allowed_cpus); - } - return allowed_cpus; -} - -// MaxCapacity() determines how we distribute memory in the per-cpu cache -// to the various class sizes. -static size_t MaxCapacity(size_t cl) { - // The number of size classes that are commonly used and thus should be - // allocated more slots in the per-cpu cache. - static constexpr size_t kNumSmall = 10; - - // The memory used for each per-CPU slab is the sum of: - // sizeof(std::atomic) * kNumClasses - // sizeof(void*) * (kSmallObjectDepth + 1) * kNumSmall - // sizeof(void*) * (kLargeObjectDepth + 1) * kNumLarge - // - // Class size 0 has MaxCapacity() == 0, which is the reason for using - // kNumClasses - 1 above instead of kNumClasses. - // - // Each Size class region in the slab is preceded by one padding pointer that - // points to itself, because prefetch instructions of invalid pointers are - // slow. That is accounted for by the +1 for object depths. -#if defined(TCMALLOC_SMALL_BUT_SLOW) - // With SMALL_BUT_SLOW we have 4KiB of per-cpu slab and 46 class sizes we - // allocate: - // == 8 * 46 + 8 * ((16 + 1) * 10 + (6 + 1) * 35) = 4038 bytes of 4096 - static const uint16_t kSmallObjectDepth = 16; - static const uint16_t kLargeObjectDepth = 6; -#else - // We allocate 256KiB per-cpu for pointers to cached per-cpu memory. - // Each 256KiB is a subtle::percpu::TcmallocSlab::Slabs - // Max(kNumClasses) is 89, so the maximum footprint per CPU is: - // 89 * 8 + 8 * ((2048 + 1) * 10 + (152 + 1) * 78 + 88) = 254 KiB - static const uint16_t kSmallObjectDepth = 2048; - static const uint16_t kLargeObjectDepth = 152; -#endif - if (cl == 0 || cl >= kNumClasses) return 0; - - if (Static::sharded_transfer_cache().should_use(cl)) { - return 0; - } - - if (Static::sizemap().class_to_size(cl) == 0) { - return 0; - } - - if (!IsExpandedSizeClass(cl) && (cl % kNumBaseClasses) <= kNumSmall) { - // Small object sizes are very heavily used and need very deep caches for - // good performance (well over 90% of malloc calls are for cl <= 10.) - return kSmallObjectDepth; - } - - if (IsExpandedSizeClass(cl)) { - return 0; - } - - return kLargeObjectDepth; -} - -static void *SlabAlloc(size_t size) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { - return Static::arena().Alloc(size); -} - -void CPUCache::Activate(ActivationMode mode) { - ASSERT(Static::IsInited()); - int num_cpus = absl::base_internal::NumCPUs(); - - size_t per_cpu_shift = kPerCpuShift; - const auto &topology = Static::numa_topology(); - if (topology.numa_aware()) { - per_cpu_shift += absl::bit_ceil(topology.active_partitions() - 1); - } - - const size_t kBytesAvailable = (1 << per_cpu_shift); - size_t bytes_required = sizeof(std::atomic) * kNumClasses; - - // Deal with size classes that correspond only to NUMA partitions that are in - // use. If NUMA awareness is disabled then we may have a smaller shift than - // would suffice for all of the unused size classes. - for (int cl = 0; - cl < Static::numa_topology().active_partitions() * kNumBaseClasses; - ++cl) { - const uint16_t mc = MaxCapacity(cl); - max_capacity_[cl] = mc; - bytes_required += sizeof(void *) * mc; - } - - // Deal with expanded size classes. - for (int cl = kExpandedClassesStart; cl < kNumClasses; ++cl) { - const uint16_t mc = MaxCapacity(cl); - max_capacity_[cl] = mc; - bytes_required += sizeof(void *) * mc; - } - - // As we may make certain size classes no-ops by selecting "0" at runtime, - // using a compile-time calculation overestimates the worst-case memory usage. - if (ABSL_PREDICT_FALSE(bytes_required > kBytesAvailable)) { - Crash(kCrash, __FILE__, __LINE__, "per-CPU memory exceeded, have ", - kBytesAvailable, " need ", bytes_required); - } - - absl::base_internal::SpinLockHolder h(&pageheap_lock); - - resize_ = reinterpret_cast( - Static::arena().Alloc(sizeof(ResizeInfo) * num_cpus)); - lazy_slabs_ = Parameters::lazy_per_cpu_caches(); - - auto max_cache_size = Parameters::max_per_cpu_cache_size(); - - for (int cpu = 0; cpu < num_cpus; ++cpu) { - for (int cl = 1; cl < kNumClasses; ++cl) { - resize_[cpu].per_class[cl].Init(); - } - resize_[cpu].available.store(max_cache_size, std::memory_order_relaxed); - resize_[cpu].capacity.store(max_cache_size, std::memory_order_relaxed); - resize_[cpu].last_steal.store(1, std::memory_order_relaxed); - } - - freelist_.Init(SlabAlloc, MaxCapacityHelper, lazy_slabs_, per_cpu_shift); - if (mode == ActivationMode::FastPathOn) { - Static::ActivateCPUCache(); - } -} - -// Fetch more items from the central cache, refill our local cache, -// and try to grow it if necessary. -// -// This is complicated by the fact that we can only tweak the cache on -// our current CPU and we might get migrated whenever (in fact, we -// might already have been migrated since failing to get memory...) -// -// So make sure only to make changes to one CPU's cache; at all times, -// it must be safe to find ourselves migrated (at which point we atomically -// return memory to the correct CPU.) -void *CPUCache::Refill(int cpu, size_t cl) { - const size_t batch_length = Static::sizemap().num_objects_to_move(cl); - - // UpdateCapacity can evict objects from other size classes as it tries to - // increase capacity of this size class. The objects are returned in - // to_return, we insert them into transfer cache at the end of function - // (to increase possibility that we stay on the current CPU as we are - // refilling the list). - ObjectsToReturn to_return; - const size_t target = - UpdateCapacity(cpu, cl, batch_length, false, &to_return); - - // Refill target objects in batch_length batches. - size_t total = 0; - size_t got; - size_t i; - void *result = nullptr; - void *batch[kMaxObjectsToMove]; - do { - const size_t want = std::min(batch_length, target - total); - got = Static::transfer_cache().RemoveRange(cl, batch, want); - if (got == 0) { - break; - } - total += got; - i = got; - if (result == nullptr) { - i--; - result = batch[i]; - } - if (i) { - i -= freelist_.PushBatch(cl, batch, i); - if (i != 0) { - static_assert(ABSL_ARRAYSIZE(batch) >= kMaxObjectsToMove, - "not enough space in batch"); - Static::transfer_cache().InsertRange(cl, absl::Span(batch, i)); - } - } - } while (got == batch_length && i == 0 && total < target && - cpu == freelist_.GetCurrentVirtualCpuUnsafe()); - - for (int i = to_return.count; i < kMaxToReturn; ++i) { - Static::transfer_cache().InsertRange( - to_return.cl[i], absl::Span(&(to_return.obj[i]), 1)); - } - - return result; -} - -size_t CPUCache::UpdateCapacity(int cpu, size_t cl, size_t batch_length, - bool overflow, ObjectsToReturn *to_return) { - // Freelist size balancing strategy: - // - We grow a size class only on overflow/underflow. - // - We shrink size classes in Steal as it scans all size classes. - // - If overflows/underflows happen on a size class, we want to grow its - // capacity to at least 2 * batch_length. It enables usage of the - // transfer cache and leaves the list half-full after we insert/remove - // a batch from the transfer cache. - // - We increase capacity beyond 2 * batch_length only when an overflow is - // followed by an underflow. That's the only case when we could benefit - // from larger capacity -- the overflow and the underflow would collapse. - // - // Note: we can't understand when we have a perfectly-sized list, because for - // a perfectly-sized list we don't hit any slow paths which looks the same as - // inactive list. Eventually we will shrink a perfectly-sized list a bit and - // then it will grow back. This won't happen very frequently for the most - // important small sizes, because we will need several ticks before we shrink - // it again. Also we will shrink it by 1, but grow by a batch. So we should - // have lots of time until we need to grow it again. - - const size_t max_capacity = max_capacity_[cl]; - size_t capacity = freelist_.Capacity(cpu, cl); - // We assert that the return value, target, is non-zero, so starting from an - // initial capacity of zero means we may be populating this core for the - // first time. - absl::base_internal::LowLevelCallOnce( - &resize_[cpu].initialized, - [](CPUCache *cache, int cpu) { - if (cache->lazy_slabs_) { - absl::base_internal::SpinLockHolder h(&cache->resize_[cpu].lock); - cache->freelist_.InitCPU(cpu, MaxCapacityHelper); - } - - // While we could unconditionally store, a lazy slab population - // implementation will require evaluating a branch. - cache->resize_[cpu].populated.store(true, std::memory_order_relaxed); - }, - this, cpu); - const bool grow_by_one = capacity < 2 * batch_length; - uint32_t successive = 0; - bool grow_by_batch = - resize_[cpu].per_class[cl].Update(overflow, grow_by_one, &successive); - if ((grow_by_one || grow_by_batch) && capacity != max_capacity) { - size_t increase = 1; - if (grow_by_batch) { - increase = std::min(batch_length, max_capacity - capacity); - } else if (!overflow && capacity < batch_length) { - // On underflow we want to grow to at least batch size, because that's - // what we want to request from transfer cache. - increase = batch_length - capacity; - } - Grow(cpu, cl, increase, to_return); - capacity = freelist_.Capacity(cpu, cl); - } - // Calculate number of objects to return/request from transfer cache. - // Generally we prefer to transfer a single batch, because transfer cache - // handles it efficiently. Except for 2 special cases: - size_t target = batch_length; - // "capacity + 1" because on overflow we already have one object from caller, - // so we can return a whole batch even if capacity is one less. Similarly, - // on underflow we need to return one object to caller, so we can request - // a whole batch even if capacity is one less. - if ((capacity + 1) < batch_length) { - // If we don't have a full batch, return/request just half. We are missing - // transfer cache anyway, and cost of insertion into central freelist is - // ~O(number of objects). - target = std::max(1, (capacity + 1) / 2); - } else if (successive > 0 && capacity >= 3 * batch_length) { - // If the freelist is large and we are hitting series of overflows or - // underflows, return/request several batches at once. On the first overflow - // we return 1 batch, on the second -- 2, on the third -- 4 and so on up to - // half of the batches we have. We do this to save on the cost of hitting - // malloc/free slow path, reduce instruction cache pollution, avoid cache - // misses when accessing transfer/central caches, etc. - size_t num_batches = - std::min(1 << std::min(successive, 10), - ((capacity / batch_length) + 1) / 2); - target = num_batches * batch_length; - } - ASSERT(target != 0); - return target; -} - -void CPUCache::Grow(int cpu, size_t cl, size_t desired_increase, - ObjectsToReturn *to_return) { - const size_t size = Static::sizemap().class_to_size(cl); - const size_t desired_bytes = desired_increase * size; - size_t acquired_bytes; - - // First, there might be unreserved slack. Take what we can. - size_t before, after; - do { - before = resize_[cpu].available.load(std::memory_order_relaxed); - acquired_bytes = std::min(before, desired_bytes); - after = before - acquired_bytes; - } while (!resize_[cpu].available.compare_exchange_strong( - before, after, std::memory_order_relaxed, std::memory_order_relaxed)); - - if (acquired_bytes < desired_bytes) { - acquired_bytes += Steal(cpu, cl, desired_bytes - acquired_bytes, to_return); - } - - // We have all the memory we could reserve. Time to actually do the growth. - - // We might have gotten more than we wanted (stealing from larger sizeclasses) - // so don't grow _too_ much. - size_t actual_increase = acquired_bytes / size; - actual_increase = std::min(actual_increase, desired_increase); - // Remember, Grow may not give us all we ask for. - size_t increase = freelist_.Grow(cpu, cl, actual_increase, max_capacity_[cl]); - size_t increased_bytes = increase * size; - if (increased_bytes < acquired_bytes) { - // return whatever we didn't use to the slack. - size_t unused = acquired_bytes - increased_bytes; - resize_[cpu].available.fetch_add(unused, std::memory_order_relaxed); - } -} - -void CPUCache::TryReclaimingCaches() { - const int num_cpus = absl::base_internal::NumCPUs(); - - for (int cpu = 0; cpu < num_cpus; ++cpu) { - // Nothing to reclaim if the cpu is not populated. - if (!HasPopulated(cpu)) { - continue; - } - - uint64_t used_bytes = UsedBytes(cpu); - uint64_t prev_used_bytes = - resize_[cpu].reclaim_used_bytes.load(std::memory_order_relaxed); - - // Get reclaim miss and used bytes stats that were captured at the end of - // the previous interval. - const CpuCacheMissStats miss_stats = GetReclaimCacheMissStats(cpu); - uint64_t misses = - uint64_t{miss_stats.underflows} + uint64_t{miss_stats.overflows}; - - // Reclaim the cache if the number of used bytes and total number of misses - // stayed constant since the last interval. - if (used_bytes != 0 && used_bytes == prev_used_bytes && misses == 0) { - Reclaim(cpu); - } - - // Takes a snapshot of used bytes in the cache at the end of this interval - // so that we can calculate if cache usage changed in the next interval. - // - // Reclaim occurs on a single thread. So, the relaxed store to used_bytes - // is safe. - resize_[cpu].reclaim_used_bytes.store(used_bytes, - std::memory_order_relaxed); - } -} - -void CPUCache::ShuffleCpuCaches() { - // Knobs that we can potentially tune depending on the workloads. - constexpr double kBytesToStealPercent = 5.0; - constexpr int kMaxNumStealCpus = 5; - - const int num_cpus = absl::base_internal::NumCPUs(); - absl::FixedArray> misses(num_cpus); - - // Record the cumulative misses for the caches so that we can select the - // caches with the highest misses as the candidates to steal the cache for. - int max_populated_cpu = -1; - int num_populated_cpus = 0; - for (int cpu = 0; cpu < num_cpus; ++cpu) { - if (!HasPopulated(cpu)) { - continue; - } - const CpuCacheMissStats miss_stats = GetIntervalCacheMissStats(cpu); - misses[num_populated_cpus] = { - cpu, uint64_t{miss_stats.underflows} + uint64_t{miss_stats.overflows}}; - max_populated_cpu = cpu; - ++num_populated_cpus; - } - if (max_populated_cpu == -1) { - return; - } - - // Sorts misses to identify cpus with highest misses. - // - // TODO(vgogte): We can potentially sort the entire misses array and use that - // in StealFromOtherCache to determine cpus to steal from. That is, [0, - // num_dest_cpus) may be the destination cpus and [num_dest_cpus, num_cpus) - // may be cpus we may steal from. We can iterate through the array in a - // descending order to steal from them. The upside of this mechanism is that - // we would be able to do a more fair stealing, starting with cpus with lowest - // misses. The downside of this mechanism is that we would have to sort the - // entire misses array. This might be compute intensive on servers with high - // number of cpus (eg. Rome, Milan). We need to investigate the compute - // required to implement this. - const int num_dest_cpus = std::min(num_populated_cpus, kMaxNumStealCpus); - std::partial_sort(misses.begin(), misses.begin() + num_dest_cpus, - misses.end(), - [](std::pair a, std::pair b) { - if (a.second == b.second) { - return a.first < b.first; - } - return a.second > b.second; - }); - - // Try to steal kBytesToStealPercent percentage of max_per_cpu_cache_size for - // each destination cpu cache. - size_t to_steal = - kBytesToStealPercent / 100.0 * Parameters::max_per_cpu_cache_size(); - for (int i = 0; i < num_dest_cpus; ++i) { - StealFromOtherCache(misses[i].first, max_populated_cpu, to_steal); - } - - // Takes a snapshot of underflows and overflows at the end of this interval - // so that we can calculate the misses that occurred in the next interval. - for (int cpu = 0; cpu < num_cpus; ++cpu) { - size_t underflows = - resize_[cpu].total_underflows.load(std::memory_order_relaxed); - size_t overflows = - resize_[cpu].total_overflows.load(std::memory_order_relaxed); - - // Shuffle occurs on a single thread. So, the relaxed stores to - // prev_underflow and pre_overflow counters are safe. - resize_[cpu].shuffle_underflows.store(underflows, - std::memory_order_relaxed); - resize_[cpu].shuffle_overflows.store(overflows, std::memory_order_relaxed); - } -} - -static void ShrinkHandler(void *arg, size_t cl, void **batch, size_t count) { - const size_t batch_length = Static::sizemap().num_objects_to_move(cl); - for (size_t i = 0; i < count; i += batch_length) { - size_t n = std::min(batch_length, count - i); - Static::transfer_cache().InsertRange(cl, absl::Span(batch + i, n)); - } -} - -void CPUCache::StealFromOtherCache(int cpu, int max_populated_cpu, - size_t bytes) { - constexpr double kCacheMissThreshold = 0.80; - - const CpuCacheMissStats dest_misses = GetIntervalCacheMissStats(cpu); - - // If both underflows and overflows are 0, we should not need to steal. - if (dest_misses.underflows == 0 && dest_misses.overflows == 0) return; - - size_t acquired = 0; - - // We use last_cpu_cache_steal_ as a hint to start our search for cpu ids to - // steal from so that we can iterate through the cpus in a nice round-robin - // fashion. - int src_cpu = std::min(last_cpu_cache_steal_.load(std::memory_order_relaxed), - max_populated_cpu); - - // We iterate through max_populate_cpus number of cpus to steal from. - // max_populate_cpus records the max cpu id that has been populated. Note - // that, any intermediate changes since the max_populated_cpus was measured - // may have populated higher cpu ids, but we do not include those in the - // search. The approximation prevents us from doing another pass through the - // cpus to just find the latest populated cpu id. - // - // We break from the loop once we iterate through all the cpus once, or if the - // total number of acquired bytes is higher than or equal to the desired bytes - // we want to steal. - for (int cpu_offset = 1; cpu_offset <= max_populated_cpu && acquired < bytes; - ++cpu_offset) { - if (--src_cpu < 0) { - src_cpu = max_populated_cpu; - } - ASSERT(0 <= src_cpu); - ASSERT(src_cpu <= max_populated_cpu); - - // We do not steal from the same CPU. Maybe we can explore combining this - // with stealing from the same CPU later. - if (src_cpu == cpu) continue; - - // We do not steal from the cache that hasn't been populated yet. - if (!HasPopulated(src_cpu)) continue; - - // We do not steal from cache that has capacity less than our lower - // capacity threshold. - if (Capacity(src_cpu) < - kCacheCapacityThreshold * Parameters::max_per_cpu_cache_size()) - continue; - - const CpuCacheMissStats src_misses = GetIntervalCacheMissStats(src_cpu); - - // If underflows and overflows from the source cpu are higher, we do not - // steal from that cache. We consider the cache as a candidate to steal from - // only when its misses are lower than 0.8x that of the dest cache. - if (src_misses.underflows > kCacheMissThreshold * dest_misses.underflows || - src_misses.overflows > kCacheMissThreshold * dest_misses.overflows) - continue; - - size_t start_cl = - resize_[src_cpu].last_steal.load(std::memory_order_relaxed); - - ASSERT(start_cl < kNumClasses); - ASSERT(0 < start_cl); - size_t source_cl = start_cl; - for (size_t offset = 1; offset < kNumClasses; ++offset) { - source_cl = start_cl + offset; - if (source_cl >= kNumClasses) { - source_cl -= kNumClasses - 1; - } - ASSERT(0 < source_cl); - ASSERT(source_cl < kNumClasses); - - const size_t capacity = freelist_.Capacity(src_cpu, source_cl); - if (capacity == 0) { - // Nothing to steal. - continue; - } - const size_t length = freelist_.Length(src_cpu, source_cl); - - // TODO(vgogte): Currently, scoring is similar to stealing from the - // same cpu in CpuCache::Steal(). Revisit this later to tune the - // knobs. - const size_t batch_length = - Static::sizemap().num_objects_to_move(source_cl); - size_t size = Static::sizemap().class_to_size(source_cl); - - // Clock-like algorithm to prioritize size classes for shrinking. - // - // Each size class has quiescent ticks counter which is incremented as we - // pass it, the counter is reset to 0 in UpdateCapacity on grow. - // If the counter value is 0, then we've just tried to grow the size - // class, so it makes little sense to shrink it back. The higher counter - // value the longer ago we grew the list and the more probable it is that - // the full capacity is unused. - // - // Then, we calculate "shrinking score", the higher the score the less we - // we want to shrink this size class. The score is considerably skewed - // towards larger size classes: smaller classes are usually used more - // actively and we also benefit less from shrinking smaller classes (steal - // less capacity). Then, we also avoid shrinking full freelists as we will - // need to evict an object and then go to the central freelist to return - // it. Then, we also avoid shrinking freelists that are just above batch - // size, because shrinking them will disable transfer cache. - // - // Finally, we shrink if the ticks counter is >= the score. - uint32_t qticks = resize_[src_cpu].per_class[source_cl].Tick(); - uint32_t score = 0; - // Note: the following numbers are based solely on intuition, common sense - // and benchmarking results. - if (size <= 144) { - score = 2 + (length >= capacity) + - (length >= batch_length && length < 2 * batch_length); - } else if (size <= 1024) { - score = 1 + (length >= capacity) + - (length >= batch_length && length < 2 * batch_length); - } else if (size <= (64 << 10)) { - score = (length >= capacity); - } - if (score > qticks) { - continue; - } - - // Finally, try to shrink (can fail if we were migrated). - // We always shrink by 1 object. The idea is that inactive lists will be - // shrunk to zero eventually anyway (or they just would not grow in the - // first place), but for active lists it does not make sense to - // aggressively shuffle capacity all the time. - // - // If the list is full, ShrinkOtherCache first tries to pop enough items - // to make space and then shrinks the capacity. - // TODO(vgogte): Maybe we can steal more from a single list to avoid - // frequent locking overhead. - { - absl::base_internal::SpinLockHolder h(&resize_[src_cpu].lock); - if (freelist_.ShrinkOtherCache(src_cpu, source_cl, 1, nullptr, - ShrinkHandler) == 1) { - acquired += size; - resize_[src_cpu].capacity.fetch_sub(size, std::memory_order_relaxed); - } - } - - if (acquired >= bytes) { - break; - } - } - resize_[cpu].last_steal.store(source_cl, std::memory_order_relaxed); - } - // Record the last cpu id we stole from, which would provide a hint to the - // next time we iterate through the cpus for stealing. - last_cpu_cache_steal_.store(src_cpu, std::memory_order_relaxed); - - // Increment the capacity of the destination cpu cache by the amount of bytes - // acquired from source caches. - if (acquired) { - size_t before = resize_[cpu].available.load(std::memory_order_relaxed); - size_t bytes_with_stolen; - do { - bytes_with_stolen = before + acquired; - } while (!resize_[cpu].available.compare_exchange_weak( - before, bytes_with_stolen, std::memory_order_relaxed, - std::memory_order_relaxed)); - resize_[cpu].capacity.fetch_add(acquired, std::memory_order_relaxed); - } -} - -// There are rather a lot of policy knobs we could tweak here. -size_t CPUCache::Steal(int cpu, size_t dest_cl, size_t bytes, - ObjectsToReturn *to_return) { - // Steal from other sizeclasses. Try to go in a nice circle. - // Complicated by sizeclasses actually being 1-indexed. - size_t acquired = 0; - size_t start = resize_[cpu].last_steal.load(std::memory_order_relaxed); - ASSERT(start < kNumClasses); - ASSERT(0 < start); - size_t source_cl = start; - for (size_t offset = 1; offset < kNumClasses; ++offset) { - source_cl = start + offset; - if (source_cl >= kNumClasses) { - source_cl -= kNumClasses - 1; - } - ASSERT(0 < source_cl); - ASSERT(source_cl < kNumClasses); - // Decide if we want to steal source_cl. - if (source_cl == dest_cl) { - // First, no sense in picking your own pocket. - continue; - } - const size_t capacity = freelist_.Capacity(cpu, source_cl); - if (capacity == 0) { - // Nothing to steal. - continue; - } - const size_t length = freelist_.Length(cpu, source_cl); - const size_t batch_length = - Static::sizemap().num_objects_to_move(source_cl); - size_t size = Static::sizemap().class_to_size(source_cl); - - // Clock-like algorithm to prioritize size classes for shrinking. - // - // Each size class has quiescent ticks counter which is incremented as we - // pass it, the counter is reset to 0 in UpdateCapacity on grow. - // If the counter value is 0, then we've just tried to grow the size class, - // so it makes little sense to shrink it back. The higher counter value - // the longer ago we grew the list and the more probable it is that - // the full capacity is unused. - // - // Then, we calculate "shrinking score", the higher the score the less we - // we want to shrink this size class. The score is considerably skewed - // towards larger size classes: smaller classes are usually used more - // actively and we also benefit less from shrinking smaller classes (steal - // less capacity). Then, we also avoid shrinking full freelists as we will - // need to evict an object and then go to the central freelist to return it. - // Then, we also avoid shrinking freelists that are just above batch size, - // because shrinking them will disable transfer cache. - // - // Finally, we shrink if the ticks counter is >= the score. - uint32_t qticks = resize_[cpu].per_class[source_cl].Tick(); - uint32_t score = 0; - // Note: the following numbers are based solely on intuition, common sense - // and benchmarking results. - if (size <= 144) { - score = 2 + (length >= capacity) + - (length >= batch_length && length < 2 * batch_length); - } else if (size <= 1024) { - score = 1 + (length >= capacity) + - (length >= batch_length && length < 2 * batch_length); - } else if (size <= (64 << 10)) { - score = (length >= capacity); - } - if (score > qticks) { - continue; - } - - if (length >= capacity) { - // The list is full, need to evict an object to shrink it. - if (to_return == nullptr) { - continue; - } - if (to_return->count == 0) { - // Can't steal any more because the to_return set is full. - break; - } - void *obj = freelist_.Pop(source_cl, NoopUnderflow); - if (obj) { - --to_return->count; - to_return->cl[to_return->count] = source_cl; - to_return->obj[to_return->count] = obj; - } - } - - // Finally, try to shrink (can fail if we were migrated). - // We always shrink by 1 object. The idea is that inactive lists will be - // shrunk to zero eventually anyway (or they just would not grow in the - // first place), but for active lists it does not make sense to aggressively - // shuffle capacity all the time. - if (freelist_.Shrink(cpu, source_cl, 1) == 1) { - acquired += size; - } - - if (cpu != freelist_.GetCurrentVirtualCpuUnsafe() || acquired >= bytes) { - // can't steal any more or don't need to - break; - } - } - // update the hint - resize_[cpu].last_steal.store(source_cl, std::memory_order_relaxed); - return acquired; -} - -int CPUCache::Overflow(void *ptr, size_t cl, int cpu) { - const size_t batch_length = Static::sizemap().num_objects_to_move(cl); - const size_t target = UpdateCapacity(cpu, cl, batch_length, true, nullptr); - // Return target objects in batch_length batches. - size_t total = 0; - size_t count = 1; - void *batch[kMaxObjectsToMove]; - batch[0] = ptr; - do { - size_t want = std::min(batch_length, target - total); - if (count < want) { - count += freelist_.PopBatch(cl, batch + count, want - count); - } - if (!count) break; - - total += count; - static_assert(ABSL_ARRAYSIZE(batch) >= kMaxObjectsToMove, - "not enough space in batch"); - Static::transfer_cache().InsertRange(cl, absl::Span(batch, count)); - if (count != batch_length) break; - count = 0; - } while (total < target && cpu == freelist_.GetCurrentVirtualCpuUnsafe()); - tracking::Report(kFreeTruncations, cl, 1); - return 1; -} - -uint64_t CPUCache::Allocated(int target_cpu) const { - ASSERT(target_cpu >= 0); - if (!HasPopulated(target_cpu)) { - return 0; - } - - uint64_t total = 0; - for (int cl = 1; cl < kNumClasses; cl++) { - int size = Static::sizemap().class_to_size(cl); - total += size * freelist_.Capacity(target_cpu, cl); - } - return total; -} - -uint64_t CPUCache::UsedBytes(int target_cpu) const { - ASSERT(target_cpu >= 0); - if (!HasPopulated(target_cpu)) { - return 0; - } - - uint64_t total = 0; - for (int cl = 1; cl < kNumClasses; cl++) { - int size = Static::sizemap().class_to_size(cl); - total += size * freelist_.Length(target_cpu, cl); - } - return total; -} - -bool CPUCache::HasPopulated(int target_cpu) const { - ASSERT(target_cpu >= 0); - return resize_[target_cpu].populated.load(std::memory_order_relaxed); -} - -PerCPUMetadataState CPUCache::MetadataMemoryUsage() const { - return freelist_.MetadataMemoryUsage(); -} - -uint64_t CPUCache::TotalUsedBytes() const { - uint64_t total = 0; - for (int cpu = 0, num_cpus = absl::base_internal::NumCPUs(); cpu < num_cpus; - ++cpu) { - total += UsedBytes(cpu); - } - return total; -} - -uint64_t CPUCache::TotalObjectsOfClass(size_t cl) const { - ASSERT(cl < kNumClasses); - uint64_t total_objects = 0; - if (cl > 0) { - for (int cpu = 0, n = absl::base_internal::NumCPUs(); cpu < n; cpu++) { - if (!HasPopulated(cpu)) { - continue; - } - total_objects += freelist_.Length(cpu, cl); - } - } - return total_objects; -} - -uint64_t CPUCache::Unallocated(int cpu) const { - return resize_[cpu].available.load(std::memory_order_relaxed); -} - -uint64_t CPUCache::Capacity(int cpu) const { - return resize_[cpu].capacity.load(std::memory_order_relaxed); -} - -uint64_t CPUCache::CacheLimit() const { - return Parameters::max_per_cpu_cache_size(); -} - -struct DrainContext { - std::atomic *available; - uint64_t bytes; -}; - -static void DrainHandler(void *arg, size_t cl, void **batch, size_t count, - size_t cap) { - DrainContext *ctx = static_cast(arg); - const size_t size = Static::sizemap().class_to_size(cl); - const size_t batch_length = Static::sizemap().num_objects_to_move(cl); - ctx->bytes += count * size; - // Drain resets capacity to 0, so return the allocated capacity to that - // CPU's slack. - ctx->available->fetch_add(cap * size, std::memory_order_relaxed); - for (size_t i = 0; i < count; i += batch_length) { - size_t n = std::min(batch_length, count - i); - Static::transfer_cache().InsertRange(cl, absl::Span(batch + i, n)); - } -} - -uint64_t CPUCache::Reclaim(int cpu) { - absl::base_internal::SpinLockHolder h(&resize_[cpu].lock); - - // If we haven't populated this core, freelist_.Drain() will touch the memory - // (for writing) as part of its locking process. Avoid faulting new pages as - // part of a release process. - if (!resize_[cpu].populated.load(std::memory_order_relaxed)) { - return 0; - } - - DrainContext ctx{&resize_[cpu].available, 0}; - freelist_.Drain(cpu, &ctx, DrainHandler); - - // Record that the reclaim occurred for this CPU. - resize_[cpu].num_reclaims.store( - resize_[cpu].num_reclaims.load(std::memory_order_relaxed) + 1, - std::memory_order_relaxed); - return ctx.bytes; -} - -uint64_t CPUCache::GetNumReclaims(int cpu) const { - return resize_[cpu].num_reclaims.load(std::memory_order_relaxed); -} - -void CPUCache::RecordCacheMissStat(const int cpu, const bool is_malloc) { - CPUCache &cpu_cache = Static::cpu_cache(); - if (is_malloc) { - cpu_cache.resize_[cpu].total_underflows.fetch_add( - 1, std::memory_order_relaxed); - } else { - cpu_cache.resize_[cpu].total_overflows.fetch_add(1, - std::memory_order_relaxed); - } -} - -CPUCache::CpuCacheMissStats CPUCache::GetReclaimCacheMissStats(int cpu) const { - CpuCacheMissStats stats; - size_t total_underflows = - resize_[cpu].total_underflows.load(std::memory_order_relaxed); - size_t prev_reclaim_underflows = - resize_[cpu].reclaim_underflows.load(std::memory_order_relaxed); - // Takes a snapshot of underflows at the end of this interval so that we can - // calculate the misses that occurred in the next interval. - // - // Reclaim occurs on a single thread. So, a relaxed store to the reclaim - // underflow stat is safe. - resize_[cpu].reclaim_underflows.store(total_underflows, - std::memory_order_relaxed); - - // In case of a size_t overflow, we wrap around to 0. - stats.underflows = total_underflows > prev_reclaim_underflows - ? total_underflows - prev_reclaim_underflows - : 0; - - size_t total_overflows = - resize_[cpu].total_overflows.load(std::memory_order_relaxed); - size_t prev_reclaim_overflows = - resize_[cpu].reclaim_overflows.load(std::memory_order_relaxed); - // Takes a snapshot of overflows at the end of this interval so that we can - // calculate the misses that occurred in the next interval. - // - // Reclaim occurs on a single thread. So, a relaxed store to the reclaim - // overflow stat is safe. - resize_[cpu].reclaim_overflows.store(total_overflows, - std::memory_order_relaxed); - - // In case of a size_t overflow, we wrap around to 0. - stats.overflows = total_overflows > prev_reclaim_overflows - ? total_overflows - prev_reclaim_overflows - : 0; - - return stats; -} - -CPUCache::CpuCacheMissStats CPUCache::GetIntervalCacheMissStats(int cpu) const { - CpuCacheMissStats stats; - size_t total_underflows = - resize_[cpu].total_underflows.load(std::memory_order_relaxed); - size_t shuffle_underflows = - resize_[cpu].shuffle_underflows.load(std::memory_order_relaxed); - // In case of a size_t overflow, we wrap around to 0. - stats.underflows = total_underflows > shuffle_underflows - ? total_underflows - shuffle_underflows - : 0; - - size_t total_overflows = - resize_[cpu].total_overflows.load(std::memory_order_relaxed); - size_t shuffle_overflows = - resize_[cpu].shuffle_overflows.load(std::memory_order_relaxed); - // In case of a size_t overflow, we wrap around to 0. - stats.overflows = total_overflows > shuffle_overflows - ? total_overflows - shuffle_overflows - : 0; - - return stats; -} - -CPUCache::CpuCacheMissStats CPUCache::GetTotalCacheMissStats(int cpu) const { - CpuCacheMissStats stats; - stats.underflows = - resize_[cpu].total_underflows.load(std::memory_order_relaxed); - stats.overflows = - resize_[cpu].total_overflows.load(std::memory_order_relaxed); - return stats; -} - -void CPUCache::Print(Printer *out) const { - out->printf("------------------------------------------------\n"); - out->printf("Bytes in per-CPU caches (per cpu limit: %" PRIu64 " bytes)\n", - Static::cpu_cache().CacheLimit()); - out->printf("------------------------------------------------\n"); - - const cpu_set_t allowed_cpus = FillActiveCpuMask(); - - for (int cpu = 0, num_cpus = absl::base_internal::NumCPUs(); cpu < num_cpus; - ++cpu) { - static constexpr double MiB = 1048576.0; - - uint64_t rbytes = UsedBytes(cpu); - bool populated = HasPopulated(cpu); - uint64_t unallocated = Unallocated(cpu); - out->printf("cpu %3d: %12" PRIu64 - " bytes (%7.1f MiB) with" - "%12" PRIu64 " bytes unallocated %s%s\n", - cpu, rbytes, rbytes / MiB, unallocated, - CPU_ISSET(cpu, &allowed_cpus) ? " active" : "", - populated ? " populated" : ""); - } - - out->printf("------------------------------------------------\n"); - out->printf("Number of per-CPU cache underflows, overflows and reclaims\n"); - out->printf("------------------------------------------------\n"); - for (int cpu = 0, num_cpus = absl::base_internal::NumCPUs(); cpu < num_cpus; - ++cpu) { - CpuCacheMissStats miss_stats = GetTotalCacheMissStats(cpu); - uint64_t reclaims = GetNumReclaims(cpu); - out->printf( - "cpu %3d:" - "%12" PRIu64 - " underflows," - "%12" PRIu64 - " overflows," - "%12" PRIu64 " reclaims\n", - cpu, miss_stats.underflows, miss_stats.overflows, reclaims); - } -} - -void CPUCache::PrintInPbtxt(PbtxtRegion *region) const { - const cpu_set_t allowed_cpus = FillActiveCpuMask(); - - for (int cpu = 0, num_cpus = absl::base_internal::NumCPUs(); cpu < num_cpus; - ++cpu) { - PbtxtRegion entry = region->CreateSubRegion("cpu_cache"); - uint64_t rbytes = UsedBytes(cpu); - bool populated = HasPopulated(cpu); - uint64_t unallocated = Unallocated(cpu); - CpuCacheMissStats miss_stats = GetTotalCacheMissStats(cpu); - uint64_t reclaims = GetNumReclaims(cpu); - entry.PrintI64("cpu", uint64_t(cpu)); - entry.PrintI64("used", rbytes); - entry.PrintI64("unused", unallocated); - entry.PrintBool("active", CPU_ISSET(cpu, &allowed_cpus)); - entry.PrintBool("populated", populated); - entry.PrintI64("underflows", miss_stats.underflows); - entry.PrintI64("overflows", miss_stats.overflows); - entry.PrintI64("reclaims", reclaims); - } -} - -void CPUCache::AcquireInternalLocks() { - for (int cpu = 0, num_cpus = absl::base_internal::NumCPUs(); cpu < num_cpus; - ++cpu) { - resize_[cpu].lock.Lock(); - } -} - -void CPUCache::ReleaseInternalLocks() { - for (int cpu = 0, num_cpus = absl::base_internal::NumCPUs(); cpu < num_cpus; - ++cpu) { - resize_[cpu].lock.Unlock(); - } -} - -void CPUCache::PerClassResizeInfo::Init() { - state_.store(0, std::memory_order_relaxed); -} - -bool CPUCache::PerClassResizeInfo::Update(bool overflow, bool grow, - uint32_t *successive) { - int32_t raw = state_.load(std::memory_order_relaxed); - State state; - memcpy(&state, &raw, sizeof(state)); - const bool overflow_then_underflow = !overflow && state.overflow; - grow |= overflow_then_underflow; - // Reset quiescent ticks for Steal clock algorithm if we are going to grow. - State new_state; - new_state.overflow = overflow; - new_state.quiescent_ticks = grow ? 0 : state.quiescent_ticks; - new_state.successive = overflow == state.overflow ? state.successive + 1 : 0; - memcpy(&raw, &new_state, sizeof(raw)); - state_.store(raw, std::memory_order_relaxed); - *successive = new_state.successive; - return overflow_then_underflow; -} - -uint32_t CPUCache::PerClassResizeInfo::Tick() { - int32_t raw = state_.load(std::memory_order_relaxed); - State state; - memcpy(&state, &raw, sizeof(state)); - state.quiescent_ticks++; - memcpy(&raw, &state, sizeof(raw)); - state_.store(raw, std::memory_order_relaxed); - return state.quiescent_ticks - 1; -} - -#ifdef ABSL_HAVE_THREAD_SANITIZER -extern "C" int RunningOnValgrind(); -#endif - -static void ActivatePerCPUCaches() { - if (tcmalloc::tcmalloc_internal::Static::CPUCacheActive()) { +static void ActivatePerCpuCaches() { + if (tcmalloc::tcmalloc_internal::tc_globals.CpuCacheActive()) { // Already active. return; } -#ifdef ABSL_HAVE_THREAD_SANITIZER - // RunningOnValgrind is a proxy for "is something intercepting malloc." - // - // If Valgrind, et. al., are in use, TCMalloc isn't in use and we shouldn't - // activate our per-CPU caches. - if (RunningOnValgrind()) { - return; - } -#endif if (Parameters::per_cpu_caches() && subtle::percpu::IsFast()) { - Static::InitIfNecessary(); - Static::cpu_cache().Activate(CPUCache::ActivationMode::FastPathOn); + tc_globals.InitIfNecessary(); + tc_globals.cpu_cache().Activate(); + tc_globals.ActivateCpuCache(); // no need for this thread cache anymore, I guess. ThreadCache::BecomeIdle(); // If there's a problem with this code, let's notice it right away: @@ -1109,7 +50,7 @@ static void ActivatePerCPUCaches() { class PerCPUInitializer { public: PerCPUInitializer() { - ActivatePerCPUCaches(); + ActivatePerCpuCaches(); } }; static PerCPUInitializer module_enter_exit; @@ -1119,16 +60,11 @@ static PerCPUInitializer module_enter_exit; GOOGLE_MALLOC_SECTION_END extern "C" void TCMalloc_Internal_ForceCpuCacheActivation() { - tcmalloc::tcmalloc_internal::ActivatePerCPUCaches(); + tcmalloc::tcmalloc_internal::ActivatePerCpuCaches(); } extern "C" bool MallocExtension_Internal_GetPerCpuCachesActive() { - return tcmalloc::tcmalloc_internal::Static::CPUCacheActive(); -} - -extern "C" void MallocExtension_Internal_DeactivatePerCpuCaches() { - tcmalloc::tcmalloc_internal::Parameters::set_per_cpu_caches(false); - tcmalloc::tcmalloc_internal::Static::DeactivateCPUCache(); + return tcmalloc::tcmalloc_internal::tc_globals.CpuCacheActive(); } extern "C" int32_t MallocExtension_Internal_GetMaxPerCpuCacheSize() { diff --git a/contrib/libs/tcmalloc/tcmalloc/cpu_cache.h b/contrib/libs/tcmalloc/tcmalloc/cpu_cache.h index dab7d1891018..26732291cf7e 100644 --- a/contrib/libs/tcmalloc/tcmalloc/cpu_cache.h +++ b/contrib/libs/tcmalloc/tcmalloc/cpu_cache.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,52 +18,324 @@ #include #include +#include +#include #include +#include +#include +#include +#include +#include "absl/algorithm/container.h" #include "absl/base/attributes.h" #include "absl/base/call_once.h" +#include "absl/base/dynamic_annotations.h" +#include "absl/base/internal/cycleclock.h" #include "absl/base/internal/spinlock.h" #include "absl/base/optimization.h" +#include "absl/base/thread_annotations.h" +#include "absl/container/fixed_array.h" +#include "absl/functional/function_ref.h" +#include "absl/time/time.h" +#include "absl/types/span.h" #include "tcmalloc/common.h" +#include "tcmalloc/experiment.h" +#include "tcmalloc/experiment_config.h" +#include "tcmalloc/internal/allocation_guard.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/cpu_utils.h" +#include "tcmalloc/internal/environment.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/numa.h" +#include "tcmalloc/internal/optimization.h" #include "tcmalloc/internal/percpu.h" #include "tcmalloc/internal/percpu_tcmalloc.h" +#include "tcmalloc/internal/sysinfo.h" +#include "tcmalloc/internal/util.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/parameters.h" #include "tcmalloc/static_vars.h" #include "tcmalloc/thread_cache.h" -#include "tcmalloc/tracking.h" +#include "tcmalloc/transfer_cache.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { +class CpuCachePeer; -class CPUCache { +namespace cpu_cache_internal { +template +struct DrainHandler; + +// Determine number of bits we should use for allocating per-cpu cache. +// The amount of per-cpu cache is 2 ^ per-cpu-shift. +// When dynamic slab size is enabled, we start with kInitialPerCpuShift and +// grow as needed up to kMaxPerCpuShift. When dynamic slab size is disabled, +// we always use kMaxPerCpuShift. +#if defined(TCMALLOC_INTERNAL_SMALL_BUT_SLOW) +constexpr inline uint8_t kInitialBasePerCpuShift = 12; +constexpr inline uint8_t kMaxBasePerCpuShift = 12; +#else +constexpr inline uint8_t kInitialBasePerCpuShift = 14; +constexpr inline uint8_t kMaxBasePerCpuShift = 18; +#endif +constexpr inline uint8_t kNumPossiblePerCpuShifts = + kMaxBasePerCpuShift - kInitialBasePerCpuShift + 1; + +constexpr inline uint8_t kResizeSlabCopies = 2; +constexpr inline uint8_t kTotalPossibleSlabs = + kNumPossiblePerCpuShifts * kResizeSlabCopies; +// StaticForwarder provides access to the SizeMap and transfer caches. +// +// This is a class, rather than namespaced globals, so that it can be mocked for +// testing. +class StaticForwarder { + public: + [[nodiscard]] static void* Alloc(size_t size, std::align_val_t alignment) + ABSL_LOCKS_EXCLUDED(pageheap_lock) { + TC_ASSERT(tc_globals.IsInited()); + // TODO(b/373944374): Arena is thread-safe, but we take the pageheap_lock to + // present a consistent view of memory usage. + PageHeapSpinLockHolder l; + return tc_globals.arena().Alloc(size, alignment); + } + [[nodiscard]] static void* AllocReportedImpending(size_t size, + std::align_val_t alignment) + ABSL_LOCKS_EXCLUDED(pageheap_lock) { + TC_ASSERT(tc_globals.IsInited()); + // TODO(b/373944374): Arena is thread-safe, but we take the pageheap_lock to + // present a consistent view of memory usage. + PageHeapSpinLockHolder l; + // Negate previous update to allocated that accounted for this allocation. + tc_globals.arena().UpdateAllocatedAndNonresident( + -static_cast(size), 0); + return tc_globals.arena().Alloc(size, alignment); + } + + static void Dealloc(void* ptr, size_t size, std::align_val_t alignment) { + TC_ASSERT(false); + } + + static void ArenaUpdateAllocatedAndNonresident(int64_t allocated, + int64_t nonresident) + ABSL_LOCKS_EXCLUDED(pageheap_lock) { + TC_ASSERT(tc_globals.IsInited()); + // TODO(b/373944374): Arena is thread-safe, but we take the pageheap_lock to + // present a consistent view of memory usage. + PageHeapSpinLockHolder l; + if (allocated > 0) { + tc_globals.page_allocator().ShrinkToUsageLimit(Length(allocated)); + } + tc_globals.arena().UpdateAllocatedAndNonresident(allocated, nonresident); + } + + static bool per_cpu_caches_dynamic_slab_enabled() { + return Parameters::per_cpu_caches_dynamic_slab_enabled(); + } + + static double per_cpu_caches_dynamic_slab_grow_threshold() { + return Parameters::per_cpu_caches_dynamic_slab_grow_threshold(); + } + + static double per_cpu_caches_dynamic_slab_shrink_threshold() { + return Parameters::per_cpu_caches_dynamic_slab_shrink_threshold(); + } + + static bool reuse_size_classes() { + return tc_globals.size_class_configuration() == + SizeClassConfiguration::kReuse; + } + + static size_t class_to_size(int size_class) { + return tc_globals.sizemap().class_to_size(size_class); + } + + static absl::Span cold_size_classes() { + return tc_globals.sizemap().ColdSizeClasses(); + } + + static size_t num_objects_to_move(int size_class) { + return tc_globals.sizemap().num_objects_to_move(size_class); + } + + static const NumaTopology& numa_topology() { + return tc_globals.numa_topology(); + } + + static ShardedTransferCacheManager& sharded_transfer_cache() { + return tc_globals.sharded_transfer_cache(); + } + + static TransferCacheManager& transfer_cache() { + return tc_globals.transfer_cache(); + } + + static bool UseGenericShardedCache() { + return tc_globals.sharded_transfer_cache().UseGenericCache(); + } + + static bool UseShardedCacheForLargeClassesOnly() { + return tc_globals.sharded_transfer_cache().UseCacheForLargeClassesOnly(); + } + + static bool HaveHooks() { return tc_globals.HaveHooks(); } +}; + +template +uint8_t NumaShift(const NumaTopology& topology) { + return topology.numa_aware() + ? absl::bit_ceil(topology.active_partitions() - 1) + : 0; +} + +// Translates from a shift value to the offset of that shift in arrays of +// possible shift values. +inline uint8_t ShiftOffset(uint8_t shift, uint8_t initial_shift) { + TC_ASSERT_GE(shift, initial_shift); + return shift - initial_shift; +} + +// Tracks the range of allowed slab shifts. +struct SlabShiftBounds { + uint8_t initial_shift; + uint8_t max_shift; +}; + +struct GetShiftMaxCapacity { + size_t operator()(size_t size_class) const { + TC_ASSERT_GE(shift_bounds.max_shift, shift); + const uint8_t relative_shift = shift_bounds.max_shift - shift; + if (relative_shift == 0) + return max_capacities[size_class].load(std::memory_order_relaxed); + int mc = max_capacities[size_class].load(std::memory_order_relaxed) >> + relative_shift; + // We decrement by 3 because of (1) cost of per-size-class header, (2) cost + // of per-size-class padding pointer, (3) there are a lot of empty size + // classes that have headers and whose max capacities can't be decremented. + // TODO(b/272085443): try using size_class_to_header_idx array to allow for + // not having headers for empty size classes. + // TODO(b/219565872): try not doing prefetching for large size classes to + // allow for not having padding pointers for large size classes. + mc = std::max(mc - 3, 0); + return mc; + } + + const std::atomic* max_capacities; + uint8_t shift; + SlabShiftBounds shift_bounds; +}; + +template +class CpuCache { public: - constexpr CPUCache() = default; + struct CpuCacheMissStats { + size_t underflows = 0; + size_t overflows = 0; + + CpuCacheMissStats& operator+=(const CpuCacheMissStats rhs) { + underflows += rhs.underflows; + overflows += rhs.overflows; + return *this; + } + }; + + enum class DynamicSlabResize { + kNoop = 0, + kShrink, + kGrow, + }; + + enum class PerClassMissType { + // Tracks total number of capacity misses. + kCapacityTotal = 0, + // Tracks number of misses recorded as of the end of the last per-class + // resize interval. + kCapacityResize, + // Tracks total number of misses due to insufficient max_capacity. + kMaxCapacityTotal, + // Tracks number of misses recorded as of the end of the last per-class + // max capacity resize interval. + kMaxCapacityResize, + kNumTypes, + }; + + // We track the number of overflows/underflows for each of these cases. + enum class MissCount { + // Tracks total number of misses. + kTotal = 0, + // Tracks number of misses recorded as of the end of the last shuffle + // interval. + kShuffle, + // Tracks number of misses recorded as of the end of the last resize + // interval. + kReclaim, + // Tracks number of misses recorded as of the end of the last slab resize + // interval. + kSlabResize, + kNumCounts, + }; + + struct SizeClassCapacityStats { + size_t min_capacity = 0; + double avg_capacity = 0; + size_t max_capacity = 0; + size_t max_capacity_misses = 0; + absl::Duration min_last_underflow = absl::InfiniteDuration(); + absl::Duration max_last_underflow; + absl::Duration min_last_overflow = absl::InfiniteDuration(); + absl::Duration max_last_overflow; + int min_last_underflow_cpu_id = -1; + int max_last_underflow_cpu_id = -1; + int min_last_overflow_cpu_id = -1; + int max_last_overflow_cpu_id = -1; + }; - enum class ActivationMode { - FastPathOn, - FastPathOffTestOnly, + struct DynamicSlabInfo { + std::atomic grow_count[kNumPossiblePerCpuShifts]; + std::atomic shrink_count[kNumPossiblePerCpuShifts]; + std::atomic madvise_failed_bytes; }; + // Sets the lower limit on the capacity that can be stolen from the cpu cache. + static constexpr double kCacheCapacityThreshold = 0.20; + + constexpr CpuCache() = default; + // tcmalloc explicitly initializes its global state (to be safe for // use in global constructors) so our constructor must be trivial; // do all initialization here instead. - void Activate(ActivationMode mode); - - // Allocate an object of the given size class. When allocation fails - // (from this cache and after running Refill), OOMHandler(size) is - // called and its return value is returned from - // Allocate. OOMHandler is used to parameterize out-of-memory - // handling (raising exception, returning nullptr, calling - // new_handler or anything else). "Passing" OOMHandler in this way - // allows Allocate to be used in tail-call position in fast-path, - // making Allocate use jump (tail-call) to slow path code. - template - void* Allocate(size_t cl); + void Activate(); + + // For testing + void Deactivate(); + + // Allocate an object of the given size class. + // Returns nullptr when allocation fails. + [[nodiscard]] void* Allocate(size_t size_class); + // Separate allocation fast/slow paths. + // The fast path succeeds iff the thread has already cached the slab pointer + // (done by AllocateSlow) and there is an available object in the slab. + [[nodiscard]] void* AllocateFast(size_t size_class); + [[nodiscard]] void* AllocateSlow(size_t size_class); + // A slightly faster version of AllocateSlow that may be called only + // when it's known that no hooks are installed. + [[nodiscard]] void* AllocateSlowNoHooks(size_t size_class); // Free an object of the given class. - void Deallocate(void* ptr, size_t cl); + void Deallocate(void* ptr, size_t size_class); + // Separate deallocation fast/slow paths. + // The fast path succeeds iff the thread has already cached the slab pointer + // (done by DeallocateSlow) and there is free space in the slab. + bool DeallocateFast(void* ptr, size_t size_class); + void DeallocateSlow(void* ptr, size_t size_class); + // A slightly faster version of DeallocateSlow that may be called only + // when it's known that no hooks are installed. + void DeallocateSlowNoHooks(void* ptr, size_t size_class); + + // Force all Allocate/DeallocateFast to fail in the current thread + // if malloc hooks are installed. + void MaybeForceSlowPath(); // Give the number of bytes in 's cache uint64_t UsedBytes(int cpu) const; @@ -79,7 +352,7 @@ class CPUCache { uint64_t TotalUsedBytes() const; // Give the number of objects of a given class in all cpu caches. - uint64_t TotalObjectsOfClass(size_t cl) const; + uint64_t TotalObjectsOfClass(size_t size_class) const; // Give the number of bytes unallocated to any sizeclass in 's cache. uint64_t Unallocated(int cpu) const; @@ -92,6 +365,7 @@ class CPUCache { // Give the per-cpu limit of cache size. uint64_t CacheLimit() const; + void SetCacheLimit(uint64_t v); // Shuffles per-cpu caches using the number of underflows and overflows that // occurred in the prior interval. It selects the top per-cpu caches @@ -103,29 +377,50 @@ class CPUCache { // ShuffleCpuCaches. void ShuffleCpuCaches(); - // Sets the lower limit on the capacity that can be stolen from the cpu cache. - static constexpr double kCacheCapacityThreshold = 0.20; - - // Tries to steal for the destination . It iterates through the - // the set of populated cpu caches and steals the bytes from them. A cpu is - // considered a good candidate to steal from if: - // (1) the cache is populated - // (2) the numbers of underflows and overflows are both less than 0.8x those - // of the destination per-cpu cache - // (3) source cpu is not the same as the destination cpu - // (4) capacity of the source cpu/cl is non-zero - // - // For a given source cpu, we iterate through the size classes to steal from - // them. Currently, we use a similar clock-like algorithm from Steal() to - // identify the cl to steal from. - void StealFromOtherCache(int cpu, int max_populated_cpu, size_t bytes); - // Tries to reclaim inactive per-CPU caches. It iterates through the set of // populated cpu caches and reclaims the caches that: // (1) had same number of used bytes since the last interval, // (2) had no change in the number of misses since the last interval. void TryReclaimingCaches(); + // Resize size classes for up to kNumCpuCachesToResize cpu caches per + // interval. + static constexpr int kNumCpuCachesToResize = 10; + // Resizes size classes within up to kNumCpuCachesToResize per-cpu caches per + // iteration in a round-robin fashion. Per cpu cache, it iterates through the + // size classes and attempts to grow up to kMaxSizeClassesToResize number of + // classes by stealing capacity from rest of them. Per iteration, it resizes + // size classes for up to kNumCpuCachesToResize number of per-cpu caches. + void ResizeSizeClasses(); + + // Gets the max capacity for the size class using the current per-cpu shift. + uint16_t GetMaxCapacity(int size_class, uint8_t shift) const; + + // Gets the current capacity for the in a cache. + size_t GetCapacityOfSizeClass(int cpu, int size_class) const; + + // Computes maximum capacities that we want to update the size classes to. It + // fetches number of capacity misses obvserved for the size classes, and + // computes increases to the maximum capacities for the size classes with the + // highest misses. It computes maximum capacities for kNumBaseClasses number + // of size classes, starting with . It records the resized + // size classes and capacities in starting from index + // . + // Returns total number of valid size classes recorded in + // array. + int GetUpdatedMaxCapacities(int start_size_class, + PerSizeClassMaxCapacity* max_capacity, + int valid_entries); + + // Resizes maximum capacities for the size classes. First, it computes + // candidates to resize using GetUpdatedMaxCapacities(...), and then updates + // maximum capacities for size classes for all per-cpu caches. Resizing is a + // global operation. It stops all per-cpu caches, drains them, updates maximum + // capacities and begin, current and end indices for the slabs and then + // restarts the per-cpu caches. Because it's a global operation that involves + // stopping all per-cpu caches, this mechanism should be used sparingly. + void ResizeSizeClassMaxCapacities(); + // Empty out the cache on ; move all objects to the central // cache. (If other threads run concurrently on that cpu, we can't // guarantee it will be fully empty on return, but if the cpu is @@ -133,41 +428,88 @@ class CPUCache { // of bytes we sent back. This function is thread safe. uint64_t Reclaim(int cpu); + // Reports number of times the size classes were resized for . + uint64_t GetNumResizes(int cpu) const; + + // Reports total number of times size classes were resized. + uint64_t GetNumResizes() const; + // Reports number of times the has been reclaimed. uint64_t GetNumReclaims(int cpu) const; - // Determine number of bits we should use for allocating per-cpu cache - // The amount of per-cpu cache is 2 ^ kPerCpuShift -#if defined(TCMALLOC_SMALL_BUT_SLOW) - static const size_t kPerCpuShift = 12; -#else - static constexpr size_t kPerCpuShift = 18; -#endif + // Reports total number of times any CPU has been reclaimed. + uint64_t GetNumReclaims() const; - struct CpuCacheMissStats { - size_t underflows; - size_t overflows; - }; + // When dynamic slab size is enabled, checks if there is a need to resize + // the slab based on miss-counts and resizes if so. + void ResizeSlabIfNeeded(); // Reports total cache underflows and overflows for . CpuCacheMissStats GetTotalCacheMissStats(int cpu) const; - // Reports the cache underflows and overflows for that were recorded at - // the end of the previous interval. It also records current underflows and - // overflows in the reclaim underflow and overflow stats. - CpuCacheMissStats GetReclaimCacheMissStats(int cpu) const; + // Reports total cache underflows and overflows for all CPUs. + CpuCacheMissStats GetTotalCacheMissStats() const; - // Reports cache underflows and overflows for this interval. - CpuCacheMissStats GetIntervalCacheMissStats(int cpu) const; + // Reports the cache underflows and overflows for that were recorded + // during the previous interval for . + CpuCacheMissStats GetIntervalCacheMissStats(int cpu, + MissCount miss_count) const; + + // Records current underflows and overflows in the underflow and + // overflow stats. + void UpdateIntervalCacheMissStats(int cpu, MissCount miss_count); + + // Reports the cache underflows and overflows for that were recorded + // during the previous interval for . Records current underflows + // and overflows in the underflow and overflow stats. + CpuCacheMissStats GetAndUpdateIntervalCacheMissStats(int cpu, + MissCount miss_count); + + // Scans through populated per-CPU caches, and reports minimum, average and + // maximum capacity for size class . + SizeClassCapacityStats GetSizeClassCapacityStats(size_t size_class) const; + + // Reports the number of misses encountered by a that were + // recorded during the previous interval between and + // kinds of misses. + size_t GetIntervalSizeClassMisses(int cpu, size_t size_class, + PerClassMissType total_type, + PerClassMissType interval_type); + + // Reports if we should use a wider 512KiB slab. + bool UseWiderSlabs() const; + + // Reports allowed slab shift initial and maximum bounds. + SlabShiftBounds GetPerCpuSlabShiftBounds() const; + + size_t GetDynamicSlabFailedBytes() const; // Report statistics - void Print(Printer* out) const; - void PrintInPbtxt(PbtxtRegion* region) const; + void Print(Printer& out) const; + void PrintInPbtxt(PbtxtRegion& region) const; void AcquireInternalLocks(); void ReleaseInternalLocks(); + const Forwarder& forwarder() const { return forwarder_; } + + Forwarder& forwarder() { return forwarder_; } + private: + friend struct DrainHandler; + friend class ::tcmalloc::tcmalloc_internal::CpuCachePeer; + + using Freelist = subtle::percpu::TcmallocSlab; + + struct PerClassMissCounts { + std::atomic + misses[static_cast(PerClassMissType::kNumTypes)]; + + std::atomic& operator[](PerClassMissType type) { + return misses[static_cast(type)]; + } + }; + // Per-size-class freelist resizing info. class PerClassResizeInfo { public: @@ -180,6 +522,28 @@ class CPUCache { bool Update(bool overflow, bool grow, uint32_t* successive); uint32_t Tick(); + // Records a miss for a provided . A miss occurs when size class + // attempts to grow it's capacity on underflow/overflow, but we are already + // at the maximum configured per-cpu cache capacity limit. + void RecordMiss(PerClassMissType type); + + // Reports total number of misses recorded for this size class. + size_t GetTotalMisses(PerClassMissType type); + + size_t GetAndUpdateIntervalMisses(PerClassMissType total_type, + PerClassMissType interval_type); + + // Reports the number of misses encountered by this size class that + // were recorded during the previous interval between misses + // and . + size_t GetIntervalMisses(PerClassMissType total_type, + PerClassMissType interval_type); + + // Copies total misses of type encountered by the size class to + // the type . + void UpdateIntervalMisses(PerClassMissType total_type, + PerClassMissType interval_type); + private: std::atomic state_; // state_ layout: @@ -191,173 +555,2209 @@ class CPUCache { // number of successive overflows/underflows uint32_t successive : 16; }; + PerClassMissCounts misses_; static_assert(sizeof(State) == sizeof(std::atomic), "size mismatch"); }; - subtle::percpu::TcmallocSlab freelist_; + // Helper type so we don't need to sprinkle `static_cast`s everywhere. + struct MissCounts { + std::atomic misses[static_cast(MissCount::kNumCounts)]; - struct ResizeInfoUnpadded { + std::atomic& operator[](MissCount miss_count) { + return misses[static_cast(miss_count)]; + } + }; + + struct ABSL_CACHELINE_ALIGNED ResizeInfo { // cache space on this CPU we're not using. Modify atomically; // we don't want to lose space. std::atomic available; - // this is just a hint - std::atomic last_steal; - // Track whether we have initialized this CPU. - absl::once_flag initialized; + // Size class to steal from for the clock-wise algorithm. + size_t next_steal = 1; // Track whether we have ever populated this CPU. std::atomic populated; - // For cross-cpu operations. - absl::base_internal::SpinLock lock; + // For cross-cpu operations. We can't allocate while holding one of these so + // please use AllocationGuardSpinLockHolder to hold it. + absl::base_internal::SpinLock lock ABSL_ACQUIRED_BEFORE(pageheap_lock){ + absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY}; PerClassResizeInfo per_class[kNumClasses]; - // tracks number of underflows on allocate. - std::atomic total_underflows; - // tracks number of overflows on deallocate. - std::atomic total_overflows; - // tracks number of underflows recorded as of the end of the last shuffle - // interval. - std::atomic shuffle_underflows; - // tracks number of overflows recorded as of the end of the last shuffle - // interval. - std::atomic shuffle_overflows; + std::atomic num_size_class_resizes; + // Tracks number of underflows on allocate. + MissCounts underflows; + // Tracks number of overflows on deallocate. + MissCounts overflows; + std::atomic last_miss_cycles[2][kNumClasses]; // total cache space available on this CPU. This tracks the total // allocated and unallocated bytes on this CPU cache. std::atomic capacity; - // Number of underflows as of the end of the last resize interval. - std::atomic reclaim_underflows; - // Number of overflows as of the end of the last resize interval. - std::atomic reclaim_overflows; // Used bytes in the cache as of the end of the last resize interval. std::atomic reclaim_used_bytes; // Tracks number of times this CPU has been reclaimed. std::atomic num_reclaims; + // Tracks last time this CPU was reclaimed. If last underflow/overflow data + // appears before this point in time, we ignore the CPU. + std::atomic last_reclaim; + }; + + // Determines how we distribute memory in the per-cpu cache to the various + // class sizes. + size_t MaxCapacity(size_t size_class) const; + + // Updates maximum capacity for the to . + void UpdateMaxCapacity(int size_class, uint16_t cap); + + GetShiftMaxCapacity GetMaxCapacityFunctor(uint8_t shift) const; + + // Fetches objects from backing transfer cache. + [[nodiscard]] int FetchFromBackingCache(size_t size_class, + absl::Span batch); + + // Releases free batch of objects to the backing transfer cache. + void ReleaseToBackingCache(size_t size_class, absl::Span batch); + + [[nodiscard]] void* Refill(int cpu, size_t size_class); + std::pair CacheCpuSlab(); + void Populate(int cpu); + + // Returns true if we bypass cpu cache for a . We may bypass + // per-cpu cache when we enable certain configurations of sharded transfer + // cache. + bool BypassCpuCache(size_t size_class) const; + + // Returns true if we use sharded transfer cache as a backing cache for + // per-cpu caches. If a sharded transfer cache is used, we fetch/release + // from/to a sharded transfer cache. Else, we use a legacy transfer cache. + bool UseBackingShardedTransferCache(size_t size_class) const; + + // Called on freelist on to record overflow/underflow + // Returns number of objects to return/request from transfer cache. + size_t UpdateCapacity(int cpu, size_t size_class, bool overflow); + + // Tries to grow freelist on the current by up to + // objects if there is available capacity. + void Grow(int cpu, size_t size_class, size_t desired_increase); + + // Depending on the number of misses that cpu caches encountered in the + // previous resize interval, returns if slabs should be grown, shrunk or + // remain the same. + DynamicSlabResize ShouldResizeSlab(); + + // Determine if the is a good candidate to be shrunk. We use + // clock-like algorithm to prioritize size classes for shrinking. + bool IsGoodCandidateForShrinking(int cpu, size_t size_class); + + struct SizeClassMissStat { + size_t size_class; + size_t misses; }; - struct ResizeInfo : ResizeInfoUnpadded { - char pad[ABSL_CACHELINE_SIZE - - sizeof(ResizeInfoUnpadded) % ABSL_CACHELINE_SIZE]; + struct CpuMissStat { + int cpu; + size_t misses; }; + + // Tries to steal for on from other size classes on + // that CPU. Returns acquired bytes. + size_t StealCapacityForSizeClassWithinCpu( + int cpu, absl::Span dest_size_classes, size_t bytes); + + // Records a cache underflow or overflow on , increments underflow or + // overflow by 1. + // determines whether the associated count corresponds to an + // underflow or overflow. + void RecordCacheMissStat(int cpu, bool is_alloc); + + // Tries to steal for the destination . It iterates through the + // the set of populated cpu caches and steals the bytes from them. A cpu is + // considered a good candidate to steal from if: + // (1) the cache is populated + // (2) the numbers of underflows and overflows are both less than 0.8x those + // of the destination per-cpu cache + // (3) source cpu is not the same as the destination cpu + // (4) capacity of the source cpu/size_class is non-zero + // + // For a given source cpu, we iterate through the size classes to steal from + // them. Currently, we use a clock-like algorithm to identify the size_class + // to steal from. + void StealFromOtherCache(int cpu, int max_populated_cpu, + absl::Span skip_cpus, size_t bytes); + + // Try to steal one object from cpu/size_class. Return bytes stolen. + size_t ShrinkOtherCache(int cpu, size_t size_class); + + // Resizes capacities of up to kMaxSizeClassesToResize size classes for a + // single . + void ResizeCpuSizeClasses(int cpu); + + // is the offset of the shift in slabs_by_shift_. Note that we + // can't calculate this from `shift` directly due to numa shift. + // Returns the allocated slabs and the number of reused bytes. + [[nodiscard]] std::pair AllocOrReuseSlabs( + absl::FunctionRef alloc, + subtle::percpu::Shift shift, int num_cpus, uint8_t shift_offset, + uint8_t resize_offset); + + // madvise-away slab memory, pointed to by of size . + void MadviseAwaySlabs(void* slab_addr, size_t slab_size); + + Freelist freelist_; + // Tracking data for each CPU's cache resizing efforts. ResizeInfo* resize_ = nullptr; - // Track whether we are lazily initializing slabs. We cannot use the latest - // value in Parameters, as it can change after initialization. - bool lazy_slabs_ = false; + // Tracks initial and maximum slab shift bounds. + SlabShiftBounds shift_bounds_{}; + // The maximum capacity of each size class within the slab. - uint16_t max_capacity_[kNumClasses] = {0}; + std::atomic max_capacity_[kNumClasses] = {0}; // Provides a hint to StealFromOtherCache() so that we can steal from the // caches in a round-robin fashion. - std::atomic last_cpu_cache_steal_ = 0; - - // Return a set of objects to be returned to the Transfer Cache. - static constexpr int kMaxToReturn = 16; - struct ObjectsToReturn { - // The number of slots available for storing objects. - int count = kMaxToReturn; - // The size class of the returned object. kNumClasses is the - // largest value that needs to be stored in cl. - CompactSizeClass cl[kMaxToReturn]; - void* obj[kMaxToReturn]; - }; + int next_cpu_cache_steal_ = 0; + + // Provides a hint to ResizeSizeClasses() that records the last CPU for which + // we resized size classes. We use this to resize size classes for CPUs in a + // round-robin fashion. + std::atomic last_cpu_size_class_resize_ = 0; + + // Records the slab copy currently in use. We maintain kResizeSlabCopies + // sets of kNumPossiblePerCpuShifts slabs. While resizing maximum size class + // capacity, we choose a new slab from one of the copies. resize_slab_offset_ + // is an index into the copy currently in use. + std::atomic resize_slab_offset_ = 0; - static size_t MaxCapacityHelper(size_t cl) { - CPUCache& cpu_cache = Static::cpu_cache(); - // Heuristic that the CPUCache has been activated. - ASSERT(cpu_cache.resize_ != nullptr); - return cpu_cache.max_capacity_[cl]; + // Per-core cache limit in bytes. + std::atomic max_per_cpu_cache_size_{kMaxCpuCacheSize}; + + ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS Forwarder forwarder_; + + DynamicSlabInfo dynamic_slab_info_{}; + + // Pointers to allocations for slabs of each shift value for use in + // ResizeSlabs. This memory is allocated on the arena, and it is nonresident + // while not in use. + void* slabs_by_shift_[kTotalPossibleSlabs] = {nullptr}; +}; + +template +void* CpuCache::Allocate(size_t size_class) { + void* ret = AllocateFast(size_class); + if (ABSL_PREDICT_TRUE(ret != nullptr)) { + return ret; } + TCMALLOC_MUSTTAIL return AllocateSlow(size_class); +} - void* Refill(int cpu, size_t cl); +template +inline ABSL_ATTRIBUTE_ALWAYS_INLINE void* CpuCache::AllocateFast( + size_t size_class) { + TC_ASSERT_GT(size_class, 0); + return freelist_.Pop(size_class); +} - // This is called after finding a full freelist when attempting to push - // on the freelist for sizeclass . The last arg should indicate which - // CPU's list was full. Returns 1. - int Overflow(void* ptr, size_t cl, int cpu); +template +void CpuCache::Deallocate(void* ptr, size_t size_class) { + if (ABSL_PREDICT_FALSE(!DeallocateFast(ptr, size_class))) { + TCMALLOC_MUSTTAIL return DeallocateSlow(ptr, size_class); + } +} - // Called on freelist overflow/underflow on to balance cache - // capacity between size classes. Returns number of objects to return/request - // from transfer cache. will contain objects that need to be - // freed. - size_t UpdateCapacity(int cpu, size_t cl, size_t batch_length, bool overflow, - ObjectsToReturn* to_return); +template +inline ABSL_ATTRIBUTE_ALWAYS_INLINE bool CpuCache::DeallocateFast( + void* ptr, size_t size_class) { + TC_ASSERT_GT(size_class, 0); + return freelist_.Push(size_class, ptr); +} - // Tries to obtain up to bytes of freelist space on - // for from other . will contain objects that need to be - // freed. - void Grow(int cpu, size_t cl, size_t desired_increase, - ObjectsToReturn* to_return); +template +void CpuCache::MaybeForceSlowPath() { + if (ABSL_PREDICT_FALSE(forwarder_.HaveHooks())) { + freelist_.UncacheCpuSlab(); + } +} - // Tries to steal for on from other size classes on that - // CPU. Returns acquired bytes. will contain objects that need to - // be freed. - size_t Steal(int cpu, size_t cl, size_t bytes, ObjectsToReturn* to_return); +static CpuSet FillActiveCpuMask() { + CpuSet allowed_cpus; + if (!allowed_cpus.GetAffinity(0)) { + allowed_cpus.Zero(); + } - // Records a cache underflow or overflow on , increments underflow or - // overflow by 1. - // determines whether the associated count corresponds to an - // underflow or overflow. - void RecordCacheMissStat(const int cpu, const bool is_malloc); +#ifdef PERCPU_USE_RSEQ + const bool real_cpus = !subtle::percpu::UsingVirtualCpus(); +#else + const bool real_cpus = true; +#endif - static void* NoopUnderflow(int cpu, size_t cl) { return nullptr; } - static int NoopOverflow(int cpu, size_t cl, void* item) { return -1; } -}; + if (real_cpus) { + return allowed_cpus; + } -template -inline void* ABSL_ATTRIBUTE_ALWAYS_INLINE CPUCache::Allocate(size_t cl) { - ASSERT(cl > 0); - - tracking::Report(kMallocHit, cl, 1); - struct Helper { - static void* ABSL_ATTRIBUTE_NOINLINE Underflow(int cpu, size_t cl) { - // we've optimistically reported hit in Allocate, lets undo it and - // report miss instead. - tracking::Report(kMallocHit, cl, -1); - void* ret = nullptr; - if (Static::sharded_transfer_cache().should_use(cl)) { - ret = Static::sharded_transfer_cache().Pop(cl); - } else { - tracking::Report(kMallocMiss, cl, 1); - CPUCache& cache = Static::cpu_cache(); - cache.RecordCacheMissStat(cpu, true); - ret = cache.Refill(cpu, cl); - } - if (ABSL_PREDICT_FALSE(ret == nullptr)) { - size_t size = Static::sizemap().class_to_size(cl); - return OOMHandler(size); - } - return ret; + const int virtual_cpu_count = allowed_cpus.Count(); + allowed_cpus.Zero(); + for (int cpu = 0; cpu < virtual_cpu_count; ++cpu) { + allowed_cpus.Set(cpu); + } + return allowed_cpus; +} + +template +inline size_t CpuCache::MaxCapacity(size_t size_class) const { + // The number of size classes that are commonly used and thus should be + // allocated more slots in the per-cpu cache. + static constexpr size_t kNumSmall = 10; + + // When we use wider slabs, we also want to double the maximum capacities for + // size classes to use that slab. + const size_t kWiderSlabMultiplier = UseWiderSlabs() ? 2 : 1; + + // The memory used for each per-CPU slab is the sum of: + // sizeof(std::atomic) * kNumClasses + // sizeof(void*) * (kSmallObjectDepth + 1) * kNumSmall + // sizeof(void*) * (kLargeObjectDepth + 1) * kNumLarge + // + // Class size 0 has MaxCapacity() == 0, which is the reason for using + // kNumClasses - 1 above instead of kNumClasses. + // + // Each Size class region in the slab is preceded by one padding pointer that + // points to itself, because prefetch instructions of invalid pointers are + // slow. That is accounted for by the +1 for object depths. +#if defined(TCMALLOC_INTERNAL_SMALL_BUT_SLOW) + // With SMALL_BUT_SLOW we have 4KiB of per-cpu slab and 46 class sizes we + // allocate: + // == 8 * 46 + 8 * ((16 + 1) * 10 + (6 + 1) * 35) = 4038 bytes of 4096 + static const uint16_t kSmallObjectDepth = 16; + static const uint16_t kLargeObjectDepth = 6; +#else + // We allocate 256KiB per-cpu for pointers to cached per-cpu memory. + // Max(kNumClasses) is 89, so the maximum footprint per CPU for a 256KiB + // slab is: + // 89 * 8 + 8 * ((2048 + 1) * 10 + (152 + 1) * 78) = 254 KiB + // For 512KiB slab, with a multiplier of 2, maximum footprint is: + // 89 * 8 + 8 * ((4096 + 1) * 10 + (304 + 1) * 78) = 506 KiB + const uint16_t kSmallObjectDepth = 2048 * kWiderSlabMultiplier; + const uint16_t kLargeObjectDepth = 152 * kWiderSlabMultiplier; +#endif + if (size_class == 0 || size_class >= kNumClasses) { + return 0; + } + + if (BypassCpuCache(size_class)) { + return 0; + } + + if (forwarder_.class_to_size(size_class) == 0) { + return 0; + } + + if (!IsExpandedSizeClass(size_class) && + (size_class % kNumBaseClasses) <= kNumSmall) { + // Small object sizes are very heavily used and need very deep caches for + // good performance (well over 90% of malloc calls are for size_class + // <= 10.) + return kSmallObjectDepth; + } + + if (ColdFeatureActive()) { + // We reduce the number of cached objects for some sizes to fit into the + // slab. + // + // We use fewer number of size classes when using reuse size classes. So, + // we may use larger capacity for some sizes. + const uint16_t kLargeUninterestingObjectDepth = + forwarder_.reuse_size_classes() ? 246 * kWiderSlabMultiplier + : 133 * kWiderSlabMultiplier; + const uint16_t kLargeInterestingObjectDepth = + forwarder_.reuse_size_classes() ? 46 * kWiderSlabMultiplier + : 28 * kWiderSlabMultiplier; + + absl::Span cold = forwarder_.cold_size_classes(); + if (absl::c_binary_search(cold, size_class)) { + return kLargeInterestingObjectDepth; + } else if (!IsExpandedSizeClass(size_class)) { + return kLargeUninterestingObjectDepth; + } else { + return 0; } - }; - return freelist_.Pop(cl, &Helper::Underflow); -} - -inline void ABSL_ATTRIBUTE_ALWAYS_INLINE CPUCache::Deallocate(void* ptr, - size_t cl) { - ASSERT(cl > 0); - tracking::Report(kFreeHit, cl, 1); // Be optimistic; correct later if needed. - - struct Helper { - static int ABSL_ATTRIBUTE_NOINLINE Overflow(int cpu, size_t cl, void* ptr) { - // When we reach here we've already optimistically bumped FreeHits. - // Fix that. - tracking::Report(kFreeHit, cl, -1); - if (Static::sharded_transfer_cache().should_use(cl)) { - Static::sharded_transfer_cache().Push(cl, ptr); - return 1; - } - tracking::Report(kFreeMiss, cl, 1); - CPUCache& cache = Static::cpu_cache(); - cache.RecordCacheMissStat(cpu, false); - return cache.Overflow(ptr, cl, cpu); + } + + if (IsExpandedSizeClass(size_class)) { + return 0; + } + + return kLargeObjectDepth; +} + +// Returns estimated bytes required and the bytes available. +inline std::pair EstimateSlabBytes( + GetShiftMaxCapacity get_shift_capacity) { + size_t bytes_required = sizeof(std::atomic) * kNumClasses; + + for (int size_class = 0; size_class < kNumClasses; ++size_class) { + // Each non-empty size class region in the slab is preceded by one padding + // pointer that points to itself. (We do this because prefetches of invalid + // pointers are slow.) + size_t num_pointers = get_shift_capacity(size_class); + if (num_pointers > 0) ++num_pointers; + bytes_required += sizeof(void*) * num_pointers; + } + + const size_t bytes_available = 1 << get_shift_capacity.shift; + return {bytes_required, bytes_available}; +} + +template +inline uint16_t CpuCache::GetMaxCapacity(int size_class, + uint8_t shift) const { + return GetMaxCapacityFunctor(shift)(size_class); +} + +template +inline size_t CpuCache::GetCapacityOfSizeClass( + int cpu, int size_class) const { + return freelist_.Capacity(cpu, size_class); +} + +template +inline GetShiftMaxCapacity CpuCache::GetMaxCapacityFunctor( + uint8_t shift) const { + return {max_capacity_, shift, shift_bounds_}; +} + +template +inline void CpuCache::UpdateMaxCapacity(int size_class, + uint16_t cap) { + max_capacity_[size_class].store(cap, std::memory_order_relaxed); +} + +template +inline bool CpuCache::UseWiderSlabs() const { + // We use wider 512KiB slab only when NUMA partitioning is not enabled. NUMA + // increases shift by 1 by itself, so we can not increase it further. + return !forwarder_.numa_topology().numa_aware(); +} + +template +inline SlabShiftBounds CpuCache::GetPerCpuSlabShiftBounds() const { + return shift_bounds_; +} + +template +inline size_t CpuCache::GetDynamicSlabFailedBytes() const { + return dynamic_slab_info_.madvise_failed_bytes.load( + std::memory_order_relaxed); +} + +template +inline void CpuCache::Activate() { + int num_cpus = NumCPUs(); + + shift_bounds_.initial_shift = kInitialBasePerCpuShift; + shift_bounds_.max_shift = kMaxBasePerCpuShift; + uint8_t per_cpu_shift = forwarder_.per_cpu_caches_dynamic_slab_enabled() + ? kInitialBasePerCpuShift + : kMaxBasePerCpuShift; + + const auto& topology = forwarder_.numa_topology(); + const uint8_t numa_shift = NumaShift(topology); + const uint8_t wider_slab_shift = UseWiderSlabs() ? 1 : 0; + + shift_bounds_.initial_shift += numa_shift + wider_slab_shift; + shift_bounds_.max_shift += numa_shift + wider_slab_shift; + per_cpu_shift += numa_shift + wider_slab_shift; + + TC_CHECK_LE(shift_bounds_.initial_shift, shift_bounds_.max_shift); + TC_CHECK_GE(per_cpu_shift, shift_bounds_.initial_shift); + TC_CHECK_LE(per_cpu_shift, shift_bounds_.max_shift); + TC_CHECK_EQ(shift_bounds_.max_shift - shift_bounds_.initial_shift + 1, + kNumPossiblePerCpuShifts); + + // Deal with size classes that correspond only to NUMA partitions that are in + // use. If NUMA awareness is disabled then we may have a smaller shift than + // would suffice for all of the unused size classes. + for (int size_class = 0; + size_class < topology.active_partitions() * kNumBaseClasses; + ++size_class) { + max_capacity_[size_class].store(MaxCapacity(size_class), + std::memory_order_relaxed); + } + + // Deal with expanded size classes. + for (int size_class = kExpandedClassesStart; size_class < kNumClasses; + ++size_class) { + max_capacity_[size_class].store(MaxCapacity(size_class), + std::memory_order_relaxed); + } + + // Verify that all the possible shifts will have valid max capacities. + for (uint8_t shift = shift_bounds_.initial_shift; + shift <= shift_bounds_.max_shift; ++shift) { + const auto [bytes_required, bytes_available] = + EstimateSlabBytes({max_capacity_, shift, shift_bounds_}); + // We may make certain size classes no-ops by selecting "0" at runtime, so + // using a compile-time calculation overestimates worst-case memory usage. + if (ABSL_PREDICT_FALSE(bytes_required > bytes_available)) { + TC_BUG("per-CPU memory exceeded, have %v, need %v", bytes_available, + bytes_required); } - }; - freelist_.Push(cl, ptr, Helper::Overflow); + } + + resize_ = reinterpret_cast(forwarder_.Alloc( + sizeof(ResizeInfo) * num_cpus, std::align_val_t{alignof(ResizeInfo)})); + + auto max_cache_size = CacheLimit(); + + for (int cpu = 0; cpu < num_cpus; ++cpu) { + new (&resize_[cpu]) ResizeInfo(); + + for (int size_class = 1; size_class < kNumClasses; ++size_class) { + resize_[cpu].per_class[size_class].Init(); + } + resize_[cpu].available.store(max_cache_size, std::memory_order_relaxed); + resize_[cpu].capacity.store(max_cache_size, std::memory_order_relaxed); + } + + void* slabs = + AllocOrReuseSlabs(&forwarder_.Alloc, + subtle::percpu::ToShiftType(per_cpu_shift), num_cpus, + ShiftOffset(per_cpu_shift, shift_bounds_.initial_shift), + /*resize_offset=*/0) + .first; + freelist_.Init( + &forwarder_.Alloc, slabs, + GetShiftMaxCapacity{max_capacity_, per_cpu_shift, shift_bounds_}, + subtle::percpu::ToShiftType(per_cpu_shift)); +} + +template +inline void CpuCache::Deactivate() { + int num_cpus = NumCPUs(); + for (int i = 0; i < num_cpus; i++) { + Reclaim(i); + } + + freelist_.Destroy(&forwarder_.Dealloc); + static_assert(std::is_trivially_destructible::value, + "ResizeInfo is expected to be trivially destructible"); + forwarder_.Dealloc(resize_, sizeof(*resize_) * num_cpus, + std::align_val_t{alignof(decltype(*resize_))}); +} + +template +inline int CpuCache::FetchFromBackingCache(size_t size_class, + absl::Span batch) { + if (UseBackingShardedTransferCache(size_class)) { + return forwarder_.sharded_transfer_cache().RemoveRange(size_class, batch); + } + return forwarder_.transfer_cache().RemoveRange(size_class, batch); } -inline bool UsePerCpuCache() { +template +inline void CpuCache::ReleaseToBackingCache( + size_t size_class, absl::Span batch) { + if (UseBackingShardedTransferCache(size_class)) { + forwarder_.sharded_transfer_cache().InsertRange(size_class, batch); + return; + } + + forwarder_.transfer_cache().InsertRange(size_class, batch); +} + +template +void* CpuCache::AllocateSlow(size_t size_class) { + void* ret = AllocateSlowNoHooks(size_class); + MaybeForceSlowPath(); + return ret; +} + +template +void* CpuCache::AllocateSlowNoHooks(size_t size_class) { + if (BypassCpuCache(size_class)) { + return forwarder_.sharded_transfer_cache().Pop(size_class); + } + auto [cpu, cached] = CacheCpuSlab(); + if (ABSL_PREDICT_FALSE(cached)) { + if (ABSL_PREDICT_FALSE(cpu < 0)) { + // The cpu is stopped. + void* ptr = nullptr; + int r = FetchFromBackingCache(size_class, absl::MakeSpan(&ptr, 1)); +#ifndef NDEBUG + TC_ASSERT(r == 1 || ptr == nullptr); +#else + (void)r; +#endif + return ptr; + } + if (void* ret = AllocateFast(size_class)) { + return ret; + } + } + RecordCacheMissStat(cpu, true); + return Refill(cpu, size_class); +} + +// Fetch more items from the central cache, refill our local cache, +// and try to grow it if necessary. +// +// This is complicated by the fact that we can only tweak the cache on +// our current CPU and we might get migrated whenever (in fact, we +// might already have been migrated since failing to get memory...) +// +// So make sure only to make changes to one CPU's cache; at all times, +// it must be safe to find ourselves migrated (at which point we atomically +// return memory to the correct CPU.) +template +inline void* CpuCache::Refill(int cpu, size_t size_class) { + const size_t target = UpdateCapacity(cpu, size_class, false); + + // Refill target objects in batch_length batches. + size_t total = 0; + size_t got; + size_t i; + void* result = nullptr; + void* batch[kMaxObjectsToMove]; + + do { + const size_t want = std::min(kMaxObjectsToMove, target - total); + got = FetchFromBackingCache(size_class, absl::MakeSpan(batch, want)); + if (got == 0) { + break; + } + total += got; + i = got; + if (result == nullptr) { + i--; + result = batch[i]; + } + if (i) { + i -= freelist_.PushBatch(size_class, batch, i); + if (i != 0) { + ReleaseToBackingCache(size_class, {batch, i}); + } + } + } while (got == kMaxObjectsToMove && i == 0 && total < target); + return result; +} + +template +inline bool CpuCache::BypassCpuCache(size_t size_class) const { + // We bypass per-cpu cache when sharded transfer cache is enabled for large + // size classes (i.e. when we use the traditional configuration of the sharded + // transfer cache). + return forwarder_.sharded_transfer_cache().should_use(size_class) && + forwarder_.UseShardedCacheForLargeClassesOnly(); +} + +template +inline bool CpuCache::UseBackingShardedTransferCache( + size_t size_class) const { + // Make sure that the thread is registered with rseq. + TC_ASSERT(subtle::percpu::IsFastNoInit()); + // We enable sharded cache as a backing cache for all size classes when + // generic configuration is enabled. + return forwarder_.sharded_transfer_cache().should_use(size_class) && + forwarder_.UseGenericShardedCache(); +} + +// Calculate number of objects to return/request from transfer cache. +inline size_t TargetOverflowRefillCount(size_t capacity, size_t batch_length, + size_t successive) { + // If the freelist is large and we are hitting a series of overflows or + // underflows, return/request several batches at once. On the first overflow + // we return 1 batch, on the second -- 2, on the third -- 4 and so on up to + // half of the batches we have. We do this to save on the cost of hitting + // malloc/free slow path, reduce instruction cache pollution, avoid cache + // misses when accessing transfer/central caches, etc. + const size_t max = (1 << std::min(successive, 10)) * batch_length; + // Aim at returning/refilling roughly half of objects. + // Round up odd sizes, e.g. if the capacity is 3, we want to refill 2 objects. + // Also always add 1 to the result to account for the additional object + // we need to return to the caller on refill, or return on overflow. + size_t target = std::min((capacity + 1) / 2 + 1, max); + if (capacity == 1 && successive < 3) { + // If the capacity is 1, it's generally impossible to avoid bad behavior. + // Consider refills (but the same stands for overflows): if we fetch an + // additional object and put it into the cache, and the caller is doing + // malloc/free in a loop, then we both fetched an unnecessary object and + // we will immediately hit an overflow on the free. On the other hand + // if we don't fetch an additional object, and the caller is allocating + // in a loop, then we also hit underflow again on the next malloc. + // Currently we fetch/return an additional objects only if we are hitting + // successive underflows/overflows. + // But note that this behavior is also easy to compromise: if the caller is + // allocating 3 objects and then freeing 3 objects in a loop, then we always + // do the wrong thing. + target = 1; + } + TC_ASSERT_LE(target, capacity + 1); + TC_ASSERT_NE(target, 0); + return target; +} + +template +inline size_t CpuCache::UpdateCapacity(int cpu, size_t size_class, + bool overflow) { + // Freelist size balancing strategy: + // - We grow a size class only on overflow/underflow. + // - We shrink size classes in Steal as it scans all size classes. + // - If overflows/underflows happen on a size class, we want to grow its + // capacity to at least 2 * batch_length. It enables usage of the + // transfer cache and leaves the list half-full after we insert/remove + // a batch from the transfer cache. + // - We increase capacity beyond 2 * batch_length only when an overflow is + // followed by an underflow. That's the only case when we could benefit + // from larger capacity -- the overflow and the underflow would collapse. + // + // Note: we can't understand when we have a perfectly-sized list, because for + // a perfectly-sized list we don't hit any slow paths which looks the same as + // inactive list. Eventually we will shrink a perfectly-sized list a bit and + // then it will grow back. This won't happen very frequently for the most + // important small sizes, because we will need several ticks before we shrink + // it again. Also we will shrink it by 1, but grow by a batch. So we should + // have lots of time until we need to grow it again. + + // We assert that the return value, target, is non-zero, so starting from an + // initial capacity of zero means we may be populating this core for the + // first time. + size_t batch_length = forwarder_.num_objects_to_move(size_class); + const size_t max_capacity = GetMaxCapacity(size_class, freelist_.GetShift()); + size_t capacity = freelist_.Capacity(cpu, size_class); + const bool grow_by_one = capacity < 2 * batch_length; + uint32_t successive = 0; + ResizeInfo& resize = resize_[cpu]; + const int64_t now = absl::base_internal::CycleClock::Now(); + // TODO(ckennelly): Use a strongly typed enum. + resize.last_miss_cycles[overflow][size_class].store( + now, std::memory_order_relaxed); + bool grow_by_batch = + resize.per_class[size_class].Update(overflow, grow_by_one, &successive); + if ((grow_by_one || grow_by_batch) && capacity != max_capacity) { + size_t increase = 1; + if (grow_by_batch) { + increase = std::min(batch_length, max_capacity - capacity); + } else if (!overflow && capacity < batch_length) { + // On underflow we want to grow to at least batch size, because that's + // what we want to request from transfer cache. + increase = batch_length - capacity; + } + Grow(cpu, size_class, increase); + capacity = freelist_.Capacity(cpu, size_class); + } + // We hit the maximum capacity limit when the size class capacity is equal to + // its maximum allowed capacity. Record a miss due to that so that we can + // potentially grow the max capacity for this size class later. + if (capacity == max_capacity) { + resize_[cpu].per_class[size_class].RecordMiss( + PerClassMissType::kMaxCapacityTotal); + } + return TargetOverflowRefillCount(capacity, batch_length, successive); +} + +template +std::pair CpuCache::CacheCpuSlab() { + auto [cpu, cached] = freelist_.CacheCpuSlab(); + if (ABSL_PREDICT_FALSE(cached) && ABSL_PREDICT_TRUE(cpu >= 0) && + ABSL_PREDICT_FALSE( + !resize_[cpu].populated.load(std::memory_order_acquire))) { + Populate(cpu); + } + return {cpu, cached}; +} + +template +ABSL_ATTRIBUTE_NOINLINE void CpuCache::Populate(int cpu) { + AllocationGuardSpinLockHolder h(&resize_[cpu].lock); + if (resize_[cpu].populated.load(std::memory_order_relaxed)) { + return; + } + freelist_.InitCpu(cpu, GetMaxCapacityFunctor(freelist_.GetShift())); + resize_[cpu].populated.store(true, std::memory_order_release); +} + +inline size_t subtract_at_least(std::atomic* a, size_t min, + size_t max) { + size_t cmp = a->load(std::memory_order_relaxed); + for (;;) { + if (cmp < min) { + return 0; + } + size_t got = std::min(cmp, max); + if (a->compare_exchange_weak(cmp, cmp - got, std::memory_order_relaxed)) { + return got; + } + } +} + +template +inline void CpuCache::Grow(int cpu, size_t size_class, + size_t desired_increase) { + const size_t size = forwarder_.class_to_size(size_class); + const size_t desired_bytes = desired_increase * size; + size_t acquired_bytes = + subtract_at_least(&resize_[cpu].available, size, desired_bytes); + if (acquired_bytes < desired_bytes) { + resize_[cpu].per_class[size_class].RecordMiss( + PerClassMissType::kCapacityTotal); + } + if (acquired_bytes == 0) { + return; + } + size_t actual_increase = acquired_bytes / size; + TC_ASSERT_GT(actual_increase, 0); + TC_ASSERT_LE(actual_increase, desired_increase); + // Remember, Grow may not give us all we ask for. + size_t increase = freelist_.Grow( + cpu, size_class, actual_increase, + [&](uint8_t shift) { return GetMaxCapacity(size_class, shift); }); + if (size_t unused = acquired_bytes - increase * size) { + // return whatever we didn't use to the slack. + resize_[cpu].available.fetch_add(unused, std::memory_order_relaxed); + } +} + +template +inline void CpuCache::TryReclaimingCaches() { + const int num_cpus = NumCPUs(); + + for (int cpu = 0; cpu < num_cpus; ++cpu) { + // Nothing to reclaim if the cpu is not populated. + if (!HasPopulated(cpu)) { + continue; + } + + uint64_t used_bytes = UsedBytes(cpu); + uint64_t prev_used_bytes = + resize_[cpu].reclaim_used_bytes.load(std::memory_order_relaxed); + + // Get reclaim miss and used bytes stats that were captured at the end of + // the previous interval. + const CpuCacheMissStats miss_stats = + GetAndUpdateIntervalCacheMissStats(cpu, MissCount::kReclaim); + uint64_t misses = + uint64_t{miss_stats.underflows} + uint64_t{miss_stats.overflows}; + + // Reclaim the cache if the number of used bytes and total number of misses + // stayed constant since the last interval. + if (used_bytes != 0 && used_bytes == prev_used_bytes && misses == 0) { + Reclaim(cpu); + } + + // Takes a snapshot of used bytes in the cache at the end of this interval + // so that we can calculate if cache usage changed in the next interval. + // + // Reclaim occurs on a single thread. So, the relaxed store to used_bytes + // is safe. + resize_[cpu].reclaim_used_bytes.store(used_bytes, + std::memory_order_relaxed); + } +} + +template +int CpuCache::GetUpdatedMaxCapacities( + int start_size_class, PerSizeClassMaxCapacity* max_capacity, + int valid_entries) { + TC_ASSERT_LT(valid_entries, kNumClasses); + // Collect miss stats incurred during the current resize interval for all the + // size classes. + const int num_cpus = NumCPUs(); + absl::FixedArray total_misses(kNumBaseClasses, 0); + int index = 0; + for (int cpu = 0; cpu < num_cpus; ++cpu) { + index = 0; + if (!HasPopulated(cpu)) continue; + for (size_t size_class = start_size_class; + size_class < start_size_class + kNumBaseClasses; ++size_class) { + total_misses[index] += + resize_[cpu].per_class[size_class].GetAndUpdateIntervalMisses( + PerClassMissType::kMaxCapacityTotal, + PerClassMissType::kMaxCapacityResize); + + ++index; + } + } + + absl::FixedArray miss_stats(kNumBaseClasses); + index = 0; + for (size_t size_class = start_size_class; + size_class < start_size_class + kNumBaseClasses; ++size_class) { + miss_stats[index] = SizeClassMissStat{.size_class = size_class, + .misses = total_misses[index]}; + ++index; + } + + // Sort the collected stats to record size classes with largest number of + // misses in the last interval. + std::sort(miss_stats.begin(), miss_stats.end(), + [](SizeClassMissStat a, SizeClassMissStat b) { + // In case of a conflict, prefer growing smaller size classes. + if (a.misses == b.misses) { + return a.size_class < b.size_class; + } + return a.misses > b.misses; + }); + + // Computing number of size classes to resize is a light-weight operation, but + // resizing size classes involves stopping all per-cpu caches, and hence is a + // heavy-weight operation. So, we try to be aggressive in the number of size + // classes we would like to resize when we can, but perform resizing operation + // sparingly. + constexpr int kMaxCapacitiesToGrow = kNumBaseClasses / 2; + + int grown = 0; + int max_capacity_index = valid_entries; + + // We try to grow size class max capacities by batch_size times the growth + // factor. The growth factor starts with 5 times the batch size for the size + // class that suffers the highest misses, and then gradually shrinks to 1 for + // the size class with fifth-highest misses and onwards. There is nothing + // interesting about this factor; it may be tuned in the future to increase or + // decrease the aggresiveness of the growth. + int growth_factor = 5; + // Indices in miss_stats corresponding to the size classes we aim to grow + // and shrink. + int shrink_index = kNumBaseClasses - 1; + for (int grow_index = 0; grow_index < kNumBaseClasses; ++grow_index) { + // If a size class with largest misses is zero, break. Other size classes + // should also have suffered zero misses as well. + if (miss_stats[grow_index].misses == 0) break; + + // We grow a size class by its batch_size, while trying to shrink max + // capacities of other size classes by the same amount. We shrink each + // size classes' max capacity by its batch size too. + const size_t size_class_to_grow = miss_stats[grow_index].size_class; + const int to_grow = forwarder_.num_objects_to_move(size_class_to_grow); + + // max_capacity_index keeps track of number of entries in max_capacity + // that are valid. If we do not find enough size classes to shrink, we + // give up and return early. So, we only `commit` index in max_capacity + // once we find enough size classes to shrink max capacities equal to the + // target. next_capacity_index records a temporary index in max_capacity. + int next_capacity_index = max_capacity_index; + int target = to_grow * growth_factor; + int shrunk = 0; + + // Loop until we found enough capacity from other size classes, or if we run + // out of size classes to shrink. + while (shrink_index > grow_index && target > 0) { + size_t size_class_to_shrink = miss_stats[shrink_index].size_class; + int batch_size = forwarder_.num_objects_to_move(size_class_to_shrink); + size_t cap = + max_capacity_[size_class_to_shrink].load(std::memory_order_relaxed); + --shrink_index; + + // We retain at least batch_size amount of max capacity for a size + // class. + if (cap <= batch_size) continue; + + int to_shrink = std::min(target, batch_size); + // Do not shrink such that max capacity falls below batch_size. + to_shrink = std::min(to_shrink, cap - batch_size); + if (to_shrink == 0) continue; + + max_capacity[next_capacity_index] = PerSizeClassMaxCapacity{ + .size_class = size_class_to_shrink, .max_capacity = cap - to_shrink}; + ++next_capacity_index; + target -= to_shrink; + shrunk += to_shrink; + } + + // We didn't find any size classes that may be shrunk. Break. + if (shrunk == 0) break; + + // Update maximum capacity for the size class we intend to grow by the + // amount we shrunk from other size classes. + size_t cap = + max_capacity_[size_class_to_grow].load(std::memory_order_relaxed); + max_capacity[next_capacity_index] = PerSizeClassMaxCapacity{ + .size_class = size_class_to_grow, .max_capacity = cap + shrunk}; + ++next_capacity_index; + max_capacity_index = next_capacity_index; + + ++grown; + growth_factor = std::max(growth_factor - 1, 1); + // We have enough candidates to grow. Break. + if (grown == kMaxCapacitiesToGrow) break; + } + + return max_capacity_index; +} + +template +void CpuCache::MadviseAwaySlabs(void* slab_addr, size_t slab_size) { + // It is important that we do not MADV_REMOVE the memory, since file-backed + // pages may SIGSEGV/SIGBUS if another thread sees the previous slab after + // this point and reads it. + // + // TODO(b/214241843): we should be able to remove MADV_NOHUGEPAGE once the + // kernel enables huge zero pages. + // Note: we use bitwise OR to avoid short-circuiting. + ErrnoRestorer errno_restorer; + bool madvise_failed = false; + do { + madvise_failed = madvise(slab_addr, slab_size, MADV_NOHUGEPAGE) | + madvise(slab_addr, slab_size, MADV_DONTNEED); + } while (madvise_failed && errno == EAGAIN); + + int ret = 0; + if (madvise_failed) { + // Try to unlock if madvise fails the first time. + do { + ret = munlock(slab_addr, slab_size); + } while (ret == -1 && errno == EAGAIN); + + do { + madvise_failed = madvise(slab_addr, slab_size, MADV_NOHUGEPAGE) | + madvise(slab_addr, slab_size, MADV_DONTNEED); + } while (madvise_failed && errno == EAGAIN); + } + + if (ret != 0 || madvise_failed) { + dynamic_slab_info_.madvise_failed_bytes.fetch_add( + slab_size, std::memory_order_relaxed); + } +} + +template +void CpuCache::ResizeSizeClassMaxCapacities() + ABSL_NO_THREAD_SAFETY_ANALYSIS { + const int num_cpus = NumCPUs(); + const auto& topology = forwarder_.numa_topology(); + + PerSizeClassMaxCapacity new_max_capacities[kNumClasses]; + size_t start_size_class = 0; + int to_update = 0; + + // Obtain candidates to resize for size classes within each NUMA domain. We do + // not resize across NUMA domains. + for (int i = 0; i < topology.active_partitions(); ++i) { + to_update = GetUpdatedMaxCapacities(start_size_class, new_max_capacities, + to_update); + start_size_class += kNumBaseClasses; + } + + // Obtain candidates to resize within expanded size classes. + if (kHasExpandedClasses) { + to_update = GetUpdatedMaxCapacities(start_size_class, new_max_capacities, + to_update); + } + + // Nothing to update. + if (to_update == 0) return; + + uint8_t per_cpu_shift = freelist_.GetShift(); + const auto shift = subtle::percpu::ToShiftType(per_cpu_shift); + const int64_t new_slabs_size = + subtle::percpu::GetSlabsAllocSize(shift, num_cpus); + // Account for impending allocation/reusing of new slab so that we can avoid + // going over memory limit. + forwarder_.ArenaUpdateAllocatedAndNonresident(new_slabs_size, 0); + + int64_t reused_bytes; + ResizeSlabsInfo info; + for (int cpu = 0; cpu < num_cpus; ++cpu) resize_[cpu].lock.Lock(); + uint8_t new_resize_slab_offset = + resize_slab_offset_.load(std::memory_order_relaxed) + 1; + if (new_resize_slab_offset >= kResizeSlabCopies) { + new_resize_slab_offset = 0; + } + resize_slab_offset_.store(new_resize_slab_offset, std::memory_order_relaxed); + + { + // We can't allocate while holding the per-cpu spinlocks. + AllocationGuard enforce_no_alloc; + void* new_slabs; + std::tie(new_slabs, reused_bytes) = AllocOrReuseSlabs( + [&](size_t size, std::align_val_t align) { + return forwarder_.AllocReportedImpending(size, align); + }, + shift, num_cpus, + ShiftOffset(per_cpu_shift, shift_bounds_.initial_shift), + new_resize_slab_offset); + + info = freelist_.UpdateMaxCapacities( + new_slabs, + GetShiftMaxCapacity{max_capacity_, per_cpu_shift, shift_bounds_}, + [this](int size_class, uint16_t cap) { + UpdateMaxCapacity(size_class, cap); + }, + [this](int cpu) { return HasPopulated(cpu); }, + DrainHandler{*this, nullptr}, new_max_capacities, to_update); + } + for (int cpu = 0; cpu < num_cpus; ++cpu) resize_[cpu].lock.Unlock(); + + MadviseAwaySlabs(info.old_slabs, info.old_slabs_size); + const int64_t old_slabs_size = info.old_slabs_size; + forwarder_.ArenaUpdateAllocatedAndNonresident(-old_slabs_size, + old_slabs_size - reused_bytes); +} + +template +inline void CpuCache::ResizeSizeClasses() { + const int num_cpus = NumCPUs(); + // Start resizing from where we left off the last time, and resize size class + // capacities for up to kNumCpuCachesToResize per-cpu caches. + int cpu = last_cpu_size_class_resize_.load(std::memory_order_relaxed); + int num_cpus_resized = 0; + + // Record the cumulative misses for the caches so that we can select the + // size classes with the highest misses as the candidates to resize. + for (int cpu_offset = 0; cpu_offset < num_cpus; ++cpu_offset) { + if (++cpu >= num_cpus) { + cpu = 0; + } + TC_ASSERT_GE(cpu, 0); + TC_ASSERT_LT(cpu, num_cpus); + + // Nothing to resize if the cache is not populated. + if (!HasPopulated(cpu)) { + continue; + } + + ResizeCpuSizeClasses(cpu); + + // Record full stats in previous full stat counters so that we can collect + // stats per interval. + for (size_t size_class = 1; size_class < kNumClasses; ++size_class) { + resize_[cpu].per_class[size_class].UpdateIntervalMisses( + PerClassMissType::kCapacityTotal, PerClassMissType::kCapacityResize); + } + + if (++num_cpus_resized >= kNumCpuCachesToResize) break; + } + // Record the cpu hint for which the size classes were resized so that we + // can start from the subsequent cpu in the next interval. + last_cpu_size_class_resize_.store(cpu, std::memory_order_relaxed); +} + +template +void CpuCache::ResizeCpuSizeClasses(int cpu) { + if (resize_[cpu].available.load(std::memory_order_relaxed) >= + kMaxCpuCacheSize) { + // We still have enough available capacity, so all size classes can just + // grow as they see fit. + return; + } + + absl::FixedArray miss_stats(kNumClasses - 1); + for (size_t size_class = 1; size_class < kNumClasses; ++size_class) { + miss_stats[size_class - 1] = SizeClassMissStat{ + .size_class = size_class, + .misses = resize_[cpu].per_class[size_class].GetIntervalMisses( + PerClassMissType::kCapacityTotal, + PerClassMissType::kCapacityResize)}; + } + + // Sort the collected stats to record size classes with largest number of + // misses in the last interval. + std::sort(miss_stats.begin(), miss_stats.end(), + [](SizeClassMissStat a, SizeClassMissStat b) { + // In case of a conflict, prefer growing smaller size classes. + if (a.misses == b.misses) { + return a.size_class < b.size_class; + } + return a.misses > b.misses; + }); + + size_t available = + resize_[cpu].available.exchange(0, std::memory_order_relaxed); + size_t num_resizes = 0; + { + AllocationGuardSpinLockHolder h(&resize_[cpu].lock); + subtle::percpu::ScopedSlabCpuStop cpu_stop(freelist_, cpu); + const auto max_capacity = GetMaxCapacityFunctor(freelist_.GetShift()); + size_t size_classes_to_resize = 5; + TC_ASSERT_LT(size_classes_to_resize, kNumClasses); + for (size_t i = 0; i < size_classes_to_resize; ++i) { + // If a size class with largest misses is zero, break. Other size classes + // should also have suffered zero misses as well. + if (miss_stats[i].misses == 0) break; + const size_t size_class_to_grow = miss_stats[i].size_class; + + // If we are already at a maximum capacity, nothing to grow. + const ssize_t can_grow = max_capacity(size_class_to_grow) - + freelist_.Capacity(cpu, size_class_to_grow); + // can_grow can be negative only if slabs were resized, + // but since we hold resize_[cpu].lock it must not happen. + TC_ASSERT_GE(can_grow, 0); + if (can_grow <= 0) { + // If one of the highest miss classes is already at the max capacity, + // we need to try to grow more classes. Otherwise, if first 5 are at + // max capacity, resizing will stop working. + if (size_classes_to_resize < kNumClasses) { + size_classes_to_resize++; + } + continue; + } + + num_resizes++; + + size_t size = forwarder_.class_to_size(size_class_to_grow); + // Get total bytes to steal from other size classes. We would like to grow + // the capacity of the size class by a batch size. + const size_t need_bytes = + std::min(can_grow, + forwarder_.num_objects_to_move(size_class_to_grow)) * + size; + const ssize_t to_steal_bytes = need_bytes - available; + if (to_steal_bytes > 0) { + available += StealCapacityForSizeClassWithinCpu( + cpu, {miss_stats.begin(), size_classes_to_resize}, to_steal_bytes); + } + size_t capacity_acquired = std::min(can_grow, available / size); + if (capacity_acquired != 0) { + size_t got = freelist_.GrowOtherCache( + cpu, size_class_to_grow, capacity_acquired, [&](uint8_t shift) { + return GetMaxCapacity(size_class_to_grow, shift); + }); + available -= got * size; + } + } + } + resize_[cpu].available.fetch_add(available, std::memory_order_relaxed); + resize_[cpu].num_size_class_resizes.fetch_add(num_resizes, + std::memory_order_relaxed); +} + +template +inline void CpuCache::ShuffleCpuCaches() { + // Knobs that we can potentially tune depending on the workloads. + constexpr double kBytesToStealPercent = 5.0; + constexpr int kMaxNumStealCpus = 5; + + const int num_cpus = NumCPUs(); + absl::FixedArray misses(num_cpus); + + // Record the cumulative misses for the caches so that we can select the + // caches with the highest misses as the candidates to steal the cache for. + int max_populated_cpu = -1; + int num_populated_cpus = 0; + for (int cpu = 0; cpu < num_cpus; ++cpu) { + if (!HasPopulated(cpu)) { + continue; + } + const CpuCacheMissStats miss_stats = + GetIntervalCacheMissStats(cpu, MissCount::kShuffle); + misses[num_populated_cpus] = {cpu, + miss_stats.underflows + miss_stats.overflows}; + max_populated_cpu = cpu; + ++num_populated_cpus; + } + if (max_populated_cpu == -1) { + return; + } + + // Sorts misses to identify cpus with highest misses. + // + // TODO(vgogte): We can potentially sort the entire misses array and use that + // in StealFromOtherCache to determine cpus to steal from. That is, [0, + // num_dest_cpus) may be the destination cpus and [num_dest_cpus, num_cpus) + // may be cpus we may steal from. We can iterate through the array in a + // descending order to steal from them. The upside of this mechanism is that + // we would be able to do a more fair stealing, starting with cpus with lowest + // misses. The downside of this mechanism is that we would have to sort the + // entire misses array. This might be compute intensive on servers with high + // number of cpus (eg. Rome, Milan). We need to investigate the compute + // required to implement this. + const int num_dest_cpus = std::min(num_populated_cpus, kMaxNumStealCpus); + std::partial_sort(misses.begin(), misses.begin() + num_dest_cpus, + misses.begin() + num_populated_cpus, + [](CpuMissStat a, CpuMissStat b) { + if (a.misses == b.misses) { + return a.cpu < b.cpu; + } + return a.misses > b.misses; + }); + + // Try to steal kBytesToStealPercent percentage of max_per_cpu_cache_size for + // each destination cpu cache. + size_t to_steal = kBytesToStealPercent / 100.0 * CacheLimit(); + for (int i = 0; i < num_dest_cpus; ++i) { + if (misses[i].misses == 0) { + break; + } + absl::Span skip = {misses.begin(), static_cast(i + 1)}; + StealFromOtherCache(misses[i].cpu, max_populated_cpu, skip, to_steal); + } + + // Takes a snapshot of underflows and overflows at the end of this interval + // so that we can calculate the misses that occurred in the next interval. + for (int cpu = 0; cpu < num_cpus; ++cpu) { + UpdateIntervalCacheMissStats(cpu, MissCount::kShuffle); + } +} + +template +inline void CpuCache::StealFromOtherCache( + int cpu, int max_populated_cpu, absl::Span skip_cpus, + size_t bytes) { + constexpr double kCacheMissThreshold = 0.80; + + const CpuCacheMissStats dest_misses = + GetIntervalCacheMissStats(cpu, MissCount::kShuffle); + + if (resize_[cpu].available.load(std::memory_order_relaxed) >= kMaxSize) { + // We still have enough available capacity, so all size classes can just + // grow as they see fit. + return; + } + + size_t acquired = 0; + + // We use next_cpu_cache_steal_ as a hint to start our search for cpu ids to + // steal from so that we can iterate through the cpus in a nice round-robin + // fashion. + int src_cpu = next_cpu_cache_steal_; + + // We iterate through max_populate_cpus number of cpus to steal from. + // max_populate_cpus records the max cpu id that has been populated. Note + // that, any intermediate changes since the max_populated_cpus was measured + // may have populated higher cpu ids, but we do not include those in the + // search. The approximation prevents us from doing another pass through the + // cpus to just find the latest populated cpu id. + // + // We break from the loop once we iterate through all the cpus once, or if the + // total number of acquired bytes is higher than or equal to the desired bytes + // we want to steal. + for (int i = 0; i <= max_populated_cpu && acquired < bytes; ++i, ++src_cpu) { + if (src_cpu > max_populated_cpu) { + src_cpu = 0; + } + TC_ASSERT_LE(0, src_cpu); + TC_ASSERT_LE(src_cpu, max_populated_cpu); + + // We do not steal from the CPUs we want to grow. Maybe we can explore + // combining this with stealing from the same CPU later. + bool skip = false; + for (auto dest : skip_cpus) { + if (src_cpu == dest.cpu) { + skip = true; + break; + } + } + if (skip) continue; + + // We do not steal from the cache that hasn't been populated yet. + if (!HasPopulated(src_cpu)) continue; + + // We do not steal from cache that has capacity less than our lower + // capacity threshold. + if (Capacity(src_cpu) < kCacheCapacityThreshold * CacheLimit()) continue; + + const CpuCacheMissStats src_misses = + GetIntervalCacheMissStats(src_cpu, MissCount::kShuffle); + + // If underflows and overflows from the source cpu are higher, we do not + // steal from that cache. We consider the cache as a candidate to steal from + // only when its misses are lower than 0.8x that of the dest cache. + if (src_misses.underflows > kCacheMissThreshold * dest_misses.underflows || + src_misses.overflows > kCacheMissThreshold * dest_misses.overflows) + continue; + + // Try to steal available capacity from the target cpu, if any. + // This is cheaper than remote slab operations. + size_t stolen = + subtract_at_least(&resize_[src_cpu].available, 0, bytes - acquired); + if (stolen != 0) { + resize_[src_cpu].capacity.fetch_sub(stolen, std::memory_order_relaxed); + acquired += stolen; + if (acquired >= bytes) { + continue; + } + } + + AllocationGuardSpinLockHolder h(&resize_[src_cpu].lock); + subtle::percpu::ScopedSlabCpuStop cpu_stop(freelist_, src_cpu); + size_t source_size_class = resize_[src_cpu].next_steal; + for (size_t i = 1; i < kNumClasses; ++i, ++source_size_class) { + if (source_size_class >= kNumClasses) { + source_size_class = 1; + } + if (size_t stolen = ShrinkOtherCache(src_cpu, source_size_class)) { + resize_[src_cpu].capacity.fetch_sub(stolen, std::memory_order_relaxed); + acquired += stolen; + if (acquired >= bytes) { + break; + } + } + } + resize_[src_cpu].next_steal = source_size_class; + } + // Record the last cpu id we stole from, which would provide a hint to the + // next time we iterate through the cpus for stealing. + next_cpu_cache_steal_ = src_cpu; + + // Increment the capacity of the destination cpu cache by the amount of bytes + // acquired from source caches. + if (acquired) { + resize_[cpu].available.fetch_add(acquired, std::memory_order_relaxed); + resize_[cpu].capacity.fetch_add(acquired, std::memory_order_relaxed); + } +} + +template +size_t CpuCache::ShrinkOtherCache(int cpu, size_t size_class) { + TC_ASSERT(cpu >= 0 && cpu < NumCPUs(), "cpu=%d", cpu); + TC_ASSERT(size_class >= 1 && size_class < kNumClasses); + TC_ASSERT(resize_[cpu].lock.IsHeld()); + const size_t capacity = freelist_.Capacity(cpu, size_class); + if (capacity == 0) { + return 0; // Nothing to steal. + } + + const size_t length = freelist_.Length(cpu, size_class); + const size_t batch_length = forwarder_.num_objects_to_move(size_class); + size_t size = forwarder_.class_to_size(size_class); + + // Clock-like algorithm to prioritize size classes for shrinking. + // + // Each size class has quiescent ticks counter which is incremented as we + // pass it, the counter is reset to 0 in UpdateCapacity on grow. + // If the counter value is 0, then we've just tried to grow the size class, + // so it makes little sense to shrink it back. The higher counter value + // the longer ago we grew the list and the more probable it is that + // the full capacity is unused. + // + // Then, we calculate "shrinking score", the higher the score the less we + // we want to shrink this size class. The score is considerably skewed + // towards larger size classes: smaller classes are usually used more + // actively and we also benefit less from shrinking smaller classes (steal + // less capacity). Then, we also avoid shrinking full freelists as we will + // need to evict an object and then go to the central freelist to return it. + // Then, we also avoid shrinking freelists that are just above batch size, + // because shrinking them will disable transfer cache. + // + // Finally, we shrink if the ticks counter is >= the score. + uint32_t score = 0; + // Note: the following numbers are based solely on intuition, common sense + // and benchmarking results. + if (size <= 144) { + score = 2 + (length >= capacity) + + (length >= batch_length && length < 2 * batch_length); + } else if (size <= 1024) { + score = 1 + (length >= capacity) + + (length >= batch_length && length < 2 * batch_length); + } else if (size <= (64 << 10)) { + score = (length >= capacity); + } + if (resize_[cpu].per_class[size_class].Tick() < score) { + return 0; + } + + // Finally, try to shrink. + if (!freelist_.ShrinkOtherCache( + cpu, size_class, /*len=*/1, + [this](size_t size_class, void** batch, size_t count) { + TC_ASSERT_EQ(count, 1); + ReleaseToBackingCache(size_class, {batch, count}); + })) { + return 0; + } + return size; +} + +template +inline size_t CpuCache::StealCapacityForSizeClassWithinCpu( + int cpu, absl::Span dest_size_classes, size_t bytes) { + // Steal from other sizeclasses. Try to go in a nice circle. + // Complicated by sizeclasses actually being 1-indexed. + size_t acquired = 0; + size_t source_size_class = resize_[cpu].next_steal; + for (size_t i = 1; i < kNumClasses; ++i, ++source_size_class) { + if (source_size_class >= kNumClasses) { + source_size_class = 1; + } + // Decide if we want to steal source_size_class. + // Don't shrink classes we want to grow. + bool skip = false; + for (auto dest : dest_size_classes) { + if (source_size_class == dest.size_class && dest.misses != 0) { + skip = true; + break; + } + } + if (skip) { + continue; + } + acquired += ShrinkOtherCache(cpu, source_size_class); + if (acquired >= bytes) { + // can't steal any more or don't need to + break; + } + } + // update the hint + resize_[cpu].next_steal = source_size_class; + return acquired; +} + +template +void CpuCache::DeallocateSlow(void* ptr, size_t size_class) { + DeallocateSlowNoHooks(ptr, size_class); + MaybeForceSlowPath(); +} + +template +void CpuCache::DeallocateSlowNoHooks(void* ptr, size_t size_class) { + if (BypassCpuCache(size_class)) { + return forwarder_.sharded_transfer_cache().Push(size_class, ptr); + } + auto [cpu, cached] = CacheCpuSlab(); + if (ABSL_PREDICT_FALSE(cached)) { + if (ABSL_PREDICT_FALSE(cpu < 0)) { + // The cpu is stopped. + return ReleaseToBackingCache(size_class, {&ptr, 1}); + } + if (DeallocateFast(ptr, size_class)) { + return; + } + } + RecordCacheMissStat(cpu, false); + const size_t target = UpdateCapacity(cpu, size_class, true); + size_t total = 0; + size_t count = 1; + void* batch[kMaxObjectsToMove]; + batch[0] = ptr; + do { + size_t want = std::min(kMaxObjectsToMove, target - total); + if (count < want) { + count += freelist_.PopBatch(size_class, batch + count, want - count); + } + if (!count) break; + + total += count; + ReleaseToBackingCache(size_class, absl::Span(batch, count)); + if (count != kMaxObjectsToMove) break; + count = 0; + } while (total < target); +} + +template +inline uint64_t CpuCache::Allocated(int target_cpu) const { + TC_ASSERT_GE(target_cpu, 0); + if (!HasPopulated(target_cpu)) { + return 0; + } + + uint64_t total = 0; + for (int size_class = 1; size_class < kNumClasses; size_class++) { + int size = forwarder_.class_to_size(size_class); + total += size * freelist_.Capacity(target_cpu, size_class); + } + return total; +} + +template +inline uint64_t CpuCache::UsedBytes(int target_cpu) const { + TC_ASSERT_GE(target_cpu, 0); + if (!HasPopulated(target_cpu)) { + return 0; + } + + uint64_t total = 0; + for (int size_class = 1; size_class < kNumClasses; size_class++) { + int size = forwarder_.class_to_size(size_class); + total += size * freelist_.Length(target_cpu, size_class); + } + return total; +} + +template +inline bool CpuCache::HasPopulated(int target_cpu) const { + TC_ASSERT_GE(target_cpu, 0); + return resize_[target_cpu].populated.load(std::memory_order_relaxed); +} + +template +inline PerCPUMetadataState CpuCache::MetadataMemoryUsage() const { + return freelist_.MetadataMemoryUsage(); +} + +template +inline uint64_t CpuCache::TotalUsedBytes() const { + uint64_t total = 0; + for (int cpu = 0, num_cpus = NumCPUs(); cpu < num_cpus; ++cpu) { + total += UsedBytes(cpu); + } + return total; +} + +template +inline uint64_t CpuCache::TotalObjectsOfClass( + size_t size_class) const { + TC_ASSERT_LT(size_class, kNumClasses); + uint64_t total_objects = 0; + if (size_class > 0) { + for (int cpu = 0, n = NumCPUs(); cpu < n; cpu++) { + if (!HasPopulated(cpu)) { + continue; + } + total_objects += freelist_.Length(cpu, size_class); + } + } + return total_objects; +} + +template +inline uint64_t CpuCache::Unallocated(int cpu) const { + return resize_[cpu].available.load(std::memory_order_relaxed); +} + +template +inline uint64_t CpuCache::Capacity(int cpu) const { + return resize_[cpu].capacity.load(std::memory_order_relaxed); +} + +template +inline uint64_t CpuCache::CacheLimit() const { + return max_per_cpu_cache_size_.load(std::memory_order_relaxed); +} + +template +inline void CpuCache::SetCacheLimit(uint64_t v) { + // TODO(b/179516472): Drain cores as required. + max_per_cpu_cache_size_.store(v, std::memory_order_relaxed); +} + +template +struct DrainHandler { + void operator()(int cpu, size_t size_class, void** batch, size_t count, + size_t cap) const { + const size_t size = cache.forwarder_.class_to_size(size_class); + const size_t batch_length = + cache.forwarder_.num_objects_to_move(size_class); + if (bytes != nullptr) *bytes += count * size; + // Drain resets capacity to 0, so return the allocated capacity to that + // CPU's slack. + cache.resize_[cpu].available.fetch_add(cap * size, + std::memory_order_relaxed); + for (size_t i = 0; i < count; i += batch_length) { + size_t n = std::min(batch_length, count - i); + cache.ReleaseToBackingCache(size_class, absl::Span(batch + i, n)); + } + } + + CpuCache& cache; + uint64_t* bytes; +}; + +template +inline uint64_t CpuCache::Reclaim(int cpu) { + AllocationGuardSpinLockHolder h(&resize_[cpu].lock); + + // If we haven't populated this core, freelist_.Drain() will touch the memory + // (for writing) as part of its locking process. Avoid faulting new pages as + // part of a release process. + if (!HasPopulated(cpu)) { + return 0; + } + + uint64_t bytes = 0; + freelist_.Drain(cpu, DrainHandler{*this, &bytes}); + + // Record that the reclaim occurred for this CPU. + resize_[cpu].num_reclaims.store( + resize_[cpu].num_reclaims.load(std::memory_order_relaxed) + 1, + std::memory_order_relaxed); + resize_[cpu].last_reclaim.store(absl::base_internal::CycleClock::Now(), + std::memory_order_relaxed); + + return bytes; +} +template +inline uint64_t CpuCache::GetNumResizes(int cpu) const { + return resize_[cpu].num_size_class_resizes.load(std::memory_order_relaxed); +} + +template +inline uint64_t CpuCache::GetNumResizes() const { + uint64_t resizes = 0; + const int num_cpus = NumCPUs(); + for (int cpu = 0; cpu < num_cpus; ++cpu) + resizes += + resize_[cpu].num_size_class_resizes.load(std::memory_order_relaxed); + return resizes; +} + +template +inline uint64_t CpuCache::GetNumReclaims(int cpu) const { + return resize_[cpu].num_reclaims.load(std::memory_order_relaxed); +} + +template +inline uint64_t CpuCache::GetNumReclaims() const { + uint64_t reclaims = 0; + const int num_cpus = NumCPUs(); + for (int cpu = 0; cpu < num_cpus; ++cpu) + reclaims += resize_[cpu].num_reclaims.load(std::memory_order_relaxed); + return reclaims; +} + +template +inline std::pair CpuCache::AllocOrReuseSlabs( + absl::FunctionRef alloc, + subtle::percpu::Shift shift, int num_cpus, uint8_t shift_offset, + uint8_t resize_offset) { + TC_ASSERT_LT(resize_offset, kResizeSlabCopies); + TC_ASSERT_LT(shift_offset, kNumPossiblePerCpuShifts); + int slab_offset = kNumPossiblePerCpuShifts * resize_offset + shift_offset; + TC_ASSERT_LT(slab_offset, kTotalPossibleSlabs); + void*& reused_slabs = slabs_by_shift_[slab_offset]; + const size_t size = GetSlabsAllocSize(shift, num_cpus); + const bool can_reuse = reused_slabs != nullptr; + if (can_reuse) { + // Enable huge pages for reused slabs. + // TODO(b/214241843): we should be able to remove this once the kernel + // enables huge zero pages. + ErrnoRestorer errno_restorer; + madvise(reused_slabs, size, MADV_HUGEPAGE); + } else { + reused_slabs = alloc(size, subtle::percpu::kPhysicalPageAlign); + // MSan does not see writes in assembly. + ANNOTATE_MEMORY_IS_INITIALIZED(reused_slabs, size); + } + return {reused_slabs, can_reuse ? size : 0}; +} + +template +inline typename CpuCache::DynamicSlabResize +CpuCache::ShouldResizeSlab() { + const int num_cpus = NumCPUs(); + CpuCacheMissStats total_misses{}; + DynamicSlabResize resize = DynamicSlabResize::kNoop; + const bool wider_slabs_enabled = UseWiderSlabs(); + for (int cpu = 0; cpu < num_cpus; ++cpu) { + CpuCacheMissStats misses = + GetAndUpdateIntervalCacheMissStats(cpu, MissCount::kSlabResize); + total_misses += misses; + + // If overflows to underflows ratio exceeds the threshold, grow the slab. + // Increase counts by 1 during comparison so that we can still compare the + // ratio to the threshold when underflows is zero. + if (misses.overflows + 1 > + (misses.underflows + 1) * + forwarder_.per_cpu_caches_dynamic_slab_grow_threshold()) { + resize = DynamicSlabResize::kGrow; + } + } + + // When wider slabs featuee is enabled, we try to grow slabs when the + // condition for at least one cpu cache is met. Else, we use total misses to + // figure out whether to grow the slab, shrink it, or do nothing. + if (wider_slabs_enabled && resize == DynamicSlabResize::kGrow) { + return resize; + } + + // As a simple heuristic, we decide to grow if the total number of overflows + // is large compared to total number of underflows during the growth period. + // If the slab size was infinite, we would expect 0 overflows. If the slab + // size was 0, we would expect approximately equal numbers of underflows and + // overflows. + if (total_misses.overflows + 1 > + (total_misses.underflows + 1) * + forwarder_.per_cpu_caches_dynamic_slab_grow_threshold()) { + return DynamicSlabResize::kGrow; + } else if (total_misses.overflows < + total_misses.underflows * + forwarder_.per_cpu_caches_dynamic_slab_shrink_threshold()) { + return DynamicSlabResize::kShrink; + } + + return DynamicSlabResize::kNoop; +} + +template +void CpuCache::ResizeSlabIfNeeded() ABSL_NO_THREAD_SAFETY_ANALYSIS { + uint8_t per_cpu_shift = freelist_.GetShift(); + + const int num_cpus = NumCPUs(); + const DynamicSlabResize resize = ShouldResizeSlab(); + + if (resize == DynamicSlabResize::kGrow) { + if (per_cpu_shift == shift_bounds_.max_shift) return; + ++per_cpu_shift; + dynamic_slab_info_ + .grow_count[ShiftOffset(per_cpu_shift, shift_bounds_.initial_shift)] + .fetch_add(1, std::memory_order_relaxed); + } else if (resize == DynamicSlabResize::kShrink) { + if (per_cpu_shift == shift_bounds_.initial_shift) return; + --per_cpu_shift; + dynamic_slab_info_ + .shrink_count[ShiftOffset(per_cpu_shift, shift_bounds_.initial_shift)] + .fetch_add(1, std::memory_order_relaxed); + } else { + return; + } + + const auto new_shift = subtle::percpu::ToShiftType(per_cpu_shift); + const int64_t new_slabs_size = + subtle::percpu::GetSlabsAllocSize(new_shift, num_cpus); + // Account for impending allocation/reusing of new slab so that we can avoid + // going over memory limit. + forwarder_.ArenaUpdateAllocatedAndNonresident(new_slabs_size, 0); + + for (int cpu = 0; cpu < num_cpus; ++cpu) resize_[cpu].lock.Lock(); + ResizeSlabsInfo info; + const uint8_t resize_offset = + resize_slab_offset_.load(std::memory_order_relaxed); + int64_t reused_bytes; + { + // We can't allocate while holding the per-cpu spinlocks. + AllocationGuard enforce_no_alloc; + + void* new_slabs; + std::tie(new_slabs, reused_bytes) = AllocOrReuseSlabs( + [&](size_t size, std::align_val_t align) { + return forwarder_.AllocReportedImpending(size, align); + }, + new_shift, num_cpus, + ShiftOffset(per_cpu_shift, shift_bounds_.initial_shift), resize_offset); + info = freelist_.ResizeSlabs( + new_shift, new_slabs, + GetShiftMaxCapacity{max_capacity_, per_cpu_shift, shift_bounds_}, + [this](int cpu) { return HasPopulated(cpu); }, + DrainHandler{*this, nullptr}); + } + for (int cpu = 0; cpu < num_cpus; ++cpu) resize_[cpu].lock.Unlock(); + + MadviseAwaySlabs(info.old_slabs, info.old_slabs_size); + const int64_t old_slabs_size = info.old_slabs_size; + forwarder_.ArenaUpdateAllocatedAndNonresident(-old_slabs_size, + old_slabs_size - reused_bytes); +} + +template +inline void CpuCache::RecordCacheMissStat(const int cpu, + const bool is_alloc) { + MissCounts& misses = + is_alloc ? resize_[cpu].underflows : resize_[cpu].overflows; + auto& c = misses[MissCount::kTotal]; + c.store(c.load(std::memory_order_relaxed) + 1, std::memory_order_relaxed); +} + +template +inline typename CpuCache::CpuCacheMissStats +CpuCache::GetTotalCacheMissStats(int cpu) const { + CpuCacheMissStats stats; + stats.underflows = resize_[cpu].underflows[MissCount::kTotal].load( + std::memory_order_relaxed); + stats.overflows = + resize_[cpu].overflows[MissCount::kTotal].load(std::memory_order_relaxed); + return stats; +} + +template +inline typename CpuCache::CpuCacheMissStats +CpuCache::GetTotalCacheMissStats() const { + CpuCacheMissStats stats; + const int num_cpus = NumCPUs(); + for (int cpu = 0; cpu < num_cpus; ++cpu) stats += GetTotalCacheMissStats(cpu); + return stats; +} + +template +inline typename CpuCache::CpuCacheMissStats +CpuCache::GetIntervalCacheMissStats(int cpu, + MissCount miss_count) const { + TC_ASSERT_NE(miss_count, MissCount::kTotal); + TC_ASSERT_LT(miss_count, MissCount::kNumCounts); + const auto get_safe_miss_diff = [miss_count](MissCounts& misses) { + const size_t total_misses = + misses[MissCount::kTotal].load(std::memory_order_relaxed); + const size_t interval_misses = + misses[miss_count].load(std::memory_order_relaxed); + // In case of a size_t overflow, we wrap around to 0. + return total_misses > interval_misses ? total_misses - interval_misses : 0; + }; + return {get_safe_miss_diff(resize_[cpu].underflows), + get_safe_miss_diff(resize_[cpu].overflows)}; +} + +template +void CpuCache::UpdateIntervalCacheMissStats(int cpu, + MissCount miss_count) { + CpuCacheMissStats total_stats = GetTotalCacheMissStats(cpu); + // Takes a snapshot of misses at the end of this interval so that we can + // calculate the misses that occurred in the next interval. + // + // Interval updates occur on a single thread so relaxed stores to interval + // miss stats are safe. + resize_[cpu].underflows[miss_count].store(total_stats.underflows, + std::memory_order_relaxed); + resize_[cpu].overflows[miss_count].store(total_stats.overflows, + std::memory_order_relaxed); +} + +template +inline typename CpuCache::CpuCacheMissStats +CpuCache::GetAndUpdateIntervalCacheMissStats(int cpu, + MissCount miss_count) { + // Note: it's possible for cache misses to occur between these two calls, but + // there's likely to be few of them so we don't handle them specially. + CpuCacheMissStats interval_stats = GetIntervalCacheMissStats(cpu, miss_count); + UpdateIntervalCacheMissStats(cpu, miss_count); + return interval_stats; +} + +template +size_t CpuCache::GetIntervalSizeClassMisses( + int cpu, size_t size_class, PerClassMissType total_type, + PerClassMissType interval_type) { + return resize_[cpu].per_class[size_class].GetIntervalMisses(total_type, + interval_type); +} + +template +inline typename CpuCache::SizeClassCapacityStats +CpuCache::GetSizeClassCapacityStats(size_t size_class) const { + SizeClassCapacityStats stats; + int num_populated = 0; + // We use a local variable here, instead of directly updating min_capacity in + // SizeClassCapacityStats struct to make sure we do not end up with SIZE_MAX + // in stats.min_capacity when num_populated is equal to zero. + size_t min_capacity = SIZE_MAX; + const double now = absl::base_internal::CycleClock::Now(); + const double frequency = absl::base_internal::CycleClock::Frequency(); + + // Scan through all per-CPU caches and calculate minimum, average and maximum + // capacities for the size class across all the populated caches. + for (int cpu = 0, num_cpus = NumCPUs(); cpu < num_cpus; ++cpu) { + // We do not include stats for non-populated cpus in our average. + if (!HasPopulated(cpu)) { + continue; + } + + ++num_populated; + + const auto last_reclaim = + resize_[cpu].last_reclaim.load(std::memory_order_relaxed); + + const auto last_underflow_cycles = + resize_[cpu].last_miss_cycles[0][size_class].load( + std::memory_order_relaxed); + const auto last_overflow_cycles = + resize_[cpu].last_miss_cycles[1][size_class].load( + std::memory_order_relaxed); + + size_t cap = freelist_.Capacity(cpu, size_class); + stats.max_capacity = std::max(stats.max_capacity, cap); + min_capacity = std::min(min_capacity, cap); + stats.avg_capacity += cap; + + if (last_reclaim >= last_underflow_cycles || + last_reclaim >= last_overflow_cycles) { + // Don't consider the underflow/overflow time on this CPU if we have + // recently reclaimed. + continue; + } + + if (cap == 0) { + // Or if the capacity is empty. We may simply not be allocating this size + // class. + continue; + } + + const absl::Duration last_underflow = + absl::Seconds((now - last_underflow_cycles) / frequency); + const absl::Duration last_overflow = + absl::Seconds((now - last_overflow_cycles) / frequency); + + if (last_overflow < stats.min_last_overflow) { + stats.min_last_overflow = last_overflow; + stats.min_last_overflow_cpu_id = cpu; + } + if (last_overflow > stats.max_last_overflow) { + stats.max_last_overflow = last_overflow; + stats.max_last_overflow_cpu_id = cpu; + } + if (last_underflow < stats.min_last_underflow) { + stats.min_last_underflow = last_underflow; + stats.min_last_underflow_cpu_id = cpu; + } + if (last_underflow > stats.max_last_underflow) { + stats.max_last_underflow = last_underflow; + stats.max_last_underflow_cpu_id = cpu; + } + stats.max_capacity_misses += + resize_[cpu].per_class[size_class].GetIntervalMisses( + PerClassMissType::kMaxCapacityTotal, + PerClassMissType::kMaxCapacityResize); + } + if (num_populated > 0) { + stats.avg_capacity /= num_populated; + stats.min_capacity = min_capacity; + } + return stats; +} + +template +inline void CpuCache::Print(Printer& out) const { + out.printf("------------------------------------------------\n"); + out.printf("Bytes in per-CPU caches (per cpu limit: %u bytes)\n", + CacheLimit()); + out.printf("------------------------------------------------\n"); + + const CpuSet allowed_cpus = FillActiveCpuMask(); + const int num_cpus = NumCPUs(); + + for (int cpu = 0; cpu < num_cpus; ++cpu) { + static constexpr double MiB = 1048576.0; + + uint64_t rbytes = UsedBytes(cpu); + bool populated = HasPopulated(cpu); + uint64_t unallocated = Unallocated(cpu); + out.printf( + "cpu %3d: %12u" + " bytes (%7.1f MiB) with" + "%12u bytes unallocated %s%s\n", + cpu, rbytes, rbytes / MiB, unallocated, + allowed_cpus.IsSet(cpu) ? " active" : "", + populated ? " populated" : ""); + } + + out.printf("------------------------------------------------\n"); + out.printf("Size class capacity statistics in per-cpu caches\n"); + out.printf("------------------------------------------------\n"); + + for (int size_class = 1; size_class < kNumClasses; ++size_class) { + SizeClassCapacityStats stats = GetSizeClassCapacityStats(size_class); + out.printf( + "class %3d [ %8zu bytes ] : " + "%6zu (minimum), %7.1f (average), %6zu (maximum), %6zu maximum " + "allowed capacity, " + "maximum capacity misses %8zu, " + "(underflow: [%d us CPU %d, %d us CPU %d]; " + "overflow [%d us CPU %d, %d us CPU %d]\n", + size_class, forwarder_.class_to_size(size_class), stats.min_capacity, + stats.avg_capacity, stats.max_capacity, + GetMaxCapacity(size_class, freelist_.GetShift()), + stats.max_capacity_misses, + absl::ToInt64Microseconds(stats.min_last_underflow), + stats.min_last_underflow_cpu_id, + absl::ToInt64Microseconds(stats.max_last_underflow), + stats.max_last_underflow_cpu_id, + absl::ToInt64Microseconds(stats.min_last_overflow), + stats.min_last_overflow_cpu_id, + absl::ToInt64Microseconds(stats.max_last_overflow), + stats.max_last_overflow_cpu_id); + } + + out.printf("------------------------------------------------\n"); + out.printf("Number of per-CPU cache underflows, overflows, and reclaims\n"); + out.printf("------------------------------------------------\n"); + const auto print_miss_stats = [&out](CpuCacheMissStats miss_stats, + uint64_t reclaims, uint64_t resizes) { + out.printf( + "%12u underflows," + "%12u overflows, overflows / underflows: %5.2f, " + "%12u reclaims," + "%12u resizes\n", + miss_stats.underflows, miss_stats.overflows, + safe_div(miss_stats.overflows, miss_stats.underflows), reclaims, + resizes); + }; + out.printf("Total :"); + print_miss_stats(GetTotalCacheMissStats(), GetNumReclaims(), GetNumResizes()); + for (int cpu = 0; cpu < num_cpus; ++cpu) { + out.printf("cpu %3d:", cpu); + print_miss_stats(GetTotalCacheMissStats(cpu), GetNumReclaims(cpu), + GetNumResizes(cpu)); + } + + out.printf("------------------------------------------------\n"); + out.printf("Per-CPU cache slab resizing info:\n"); + out.printf("------------------------------------------------\n"); + uint8_t current_shift = freelist_.GetShift(); + out.printf("Current shift: %3d (slab size: %4d KiB)\n", current_shift, + (1 << current_shift) / 1024); + for (int shift = 0; shift < kNumPossiblePerCpuShifts; ++shift) { + out.printf("shift %3d:", shift + shift_bounds_.initial_shift); + out.printf( + "%12u growths, %12u shrinkages\n", + dynamic_slab_info_.grow_count[shift].load(std::memory_order_relaxed), + dynamic_slab_info_.shrink_count[shift].load(std::memory_order_relaxed)); + } + out.printf( + "%12u bytes for which MADVISE_DONTNEED failed\n", + dynamic_slab_info_.madvise_failed_bytes.load(std::memory_order_relaxed)); +} + +template +inline void CpuCache::PrintInPbtxt(PbtxtRegion& region) const { + const CpuSet allowed_cpus = FillActiveCpuMask(); + + for (int cpu = 0, num_cpus = NumCPUs(); cpu < num_cpus; ++cpu) { + PbtxtRegion entry = region.CreateSubRegion("cpu_cache"); + uint64_t rbytes = UsedBytes(cpu); + bool populated = HasPopulated(cpu); + uint64_t unallocated = Unallocated(cpu); + CpuCacheMissStats miss_stats = GetTotalCacheMissStats(cpu); + uint64_t reclaims = GetNumReclaims(cpu); + uint64_t resizes = GetNumResizes(cpu); + entry.PrintI64("cpu", cpu); + entry.PrintI64("used", rbytes); + entry.PrintI64("unused", unallocated); + entry.PrintBool("active", allowed_cpus.IsSet(cpu)); + entry.PrintBool("populated", populated); + entry.PrintI64("underflows", miss_stats.underflows); + entry.PrintI64("overflows", miss_stats.overflows); + entry.PrintI64("reclaims", reclaims); + entry.PrintI64("size_class_resizes", resizes); + } + + // Record size class capacity statistics. + for (int size_class = 1; size_class < kNumClasses; ++size_class) { + SizeClassCapacityStats stats = GetSizeClassCapacityStats(size_class); + PbtxtRegion entry = region.CreateSubRegion("size_class_capacity"); + entry.PrintI64("sizeclass", forwarder_.class_to_size(size_class)); + entry.PrintI64("min_capacity", stats.min_capacity); + entry.PrintDouble("avg_capacity", stats.avg_capacity); + entry.PrintI64("max_capacity", stats.max_capacity); + entry.PrintI64("max_allowed_capacity", + GetMaxCapacity(size_class, freelist_.GetShift())); + + entry.PrintI64("min_last_underflow_ns", + absl::ToInt64Nanoseconds(stats.min_last_underflow)); + entry.PrintI64("max_last_underflow_ns", + absl::ToInt64Nanoseconds(stats.max_last_underflow)); + entry.PrintI64("min_last_overflow_ns", + absl::ToInt64Nanoseconds(stats.min_last_overflow)); + entry.PrintI64("max_last_overflow_ns", + absl::ToInt64Nanoseconds(stats.max_last_overflow)); + entry.PrintI64("max_capacity_misses", stats.max_capacity_misses); + } + + // Record dynamic slab statistics. + region.PrintI64("dynamic_per_cpu_slab_size", 1 << freelist_.GetShift()); + for (int shift = 0; shift < kNumPossiblePerCpuShifts; ++shift) { + PbtxtRegion entry = region.CreateSubRegion("dynamic_slab"); + entry.PrintI64("shift", shift + shift_bounds_.initial_shift); + entry.PrintI64("grow_count", dynamic_slab_info_.grow_count[shift].load( + std::memory_order_relaxed)); + entry.PrintI64("shrink_count", dynamic_slab_info_.shrink_count[shift].load( + std::memory_order_relaxed)); + } + region.PrintI64( + "dynamic_slab_madvise_failed_bytes", + dynamic_slab_info_.madvise_failed_bytes.load(std::memory_order_relaxed)); +} + +template +inline void CpuCache::AcquireInternalLocks() { + int ncpus = absl::base_internal::NumCPUs(); + for (int cpu = 0; cpu < ncpus; ++cpu) { + resize_[cpu].lock.Lock(); + } +} + +template +inline void CpuCache::ReleaseInternalLocks() { + int ncpus = absl::base_internal::NumCPUs(); + for (int cpu = 0; cpu < ncpus; ++cpu) { + resize_[cpu].lock.Unlock(); + } +} + +template +inline void CpuCache::PerClassResizeInfo::Init() { + state_.store(0, std::memory_order_relaxed); +} + +template +inline bool CpuCache::PerClassResizeInfo::Update( + bool overflow, bool grow, uint32_t* successive) { + int32_t raw = state_.load(std::memory_order_relaxed); + State state; + memcpy(&state, &raw, sizeof(state)); + const bool overflow_then_underflow = !overflow && state.overflow; + grow |= overflow_then_underflow; + // Reset quiescent ticks for Steal clock algorithm if we are going to grow. + State new_state; + new_state.overflow = overflow; + new_state.quiescent_ticks = grow ? 0 : state.quiescent_ticks; + new_state.successive = overflow == state.overflow ? state.successive + 1 : 0; + memcpy(&raw, &new_state, sizeof(raw)); + state_.store(raw, std::memory_order_relaxed); + *successive = new_state.successive; + return overflow_then_underflow; +} + +template +inline uint32_t CpuCache::PerClassResizeInfo::Tick() { + int32_t raw = state_.load(std::memory_order_relaxed); + State state; + memcpy(&state, &raw, sizeof(state)); + state.quiescent_ticks++; + memcpy(&raw, &state, sizeof(raw)); + state_.store(raw, std::memory_order_relaxed); + return state.quiescent_ticks - 1; +} + +template +inline void CpuCache::PerClassResizeInfo::RecordMiss( + PerClassMissType type) { + auto& c = misses_[type]; + c.store(c.load(std::memory_order_relaxed) + 1, std::memory_order_relaxed); +} + +template +inline size_t CpuCache::PerClassResizeInfo::GetTotalMisses( + PerClassMissType type) { + return misses_[type].load(std::memory_order_relaxed); +} + +template +inline size_t +CpuCache::PerClassResizeInfo::GetAndUpdateIntervalMisses( + PerClassMissType total_type, PerClassMissType interval_type) { + TC_ASSERT_LT(total_type, PerClassMissType::kNumTypes); + TC_ASSERT_LT(interval_type, PerClassMissType::kNumTypes); + + const size_t total_misses = + misses_[total_type].load(std::memory_order_relaxed); + const size_t interval_misses = + misses_[interval_type].load(std::memory_order_relaxed); + misses_[interval_type].store(total_misses, std::memory_order_relaxed); + // In case of a size_t overflow, we wrap around to 0. + return total_misses > interval_misses ? total_misses - interval_misses : 0; +} + +template +inline size_t CpuCache::PerClassResizeInfo::GetIntervalMisses( + PerClassMissType total_type, PerClassMissType interval_type) { + TC_ASSERT_LT(total_type, PerClassMissType::kNumTypes); + TC_ASSERT_LT(interval_type, PerClassMissType::kNumTypes); + + const size_t total_misses = + misses_[total_type].load(std::memory_order_relaxed); + const size_t interval_misses = + misses_[interval_type].load(std::memory_order_relaxed); + // In case of a size_t overflow, we wrap around to 0. + return total_misses > interval_misses ? total_misses - interval_misses : 0; +} + +template +void CpuCache::PerClassResizeInfo::UpdateIntervalMisses( + PerClassMissType total_type, PerClassMissType interval_type) { + const size_t total_misses = GetTotalMisses(total_type); + // Takes a snapshot of misses at the end of this interval so that we can + // calculate the misses that occurred in the next interval. + // + // Interval updates occur on a single thread so relaxed stores to interval + // miss stats are safe. + misses_[interval_type].store(total_misses, std::memory_order_relaxed); +} + +} // namespace cpu_cache_internal + +// Static forward declares CpuCache to avoid a cycle in headers. Make +// "CpuCache" be non-templated to avoid breaking that forward declaration. +class CpuCache final + : public cpu_cache_internal::CpuCache { +}; + +template +inline bool UsePerCpuCache(State& state) { // We expect a fast path of per-CPU caches being active and the thread being // registered with rseq. - if (ABSL_PREDICT_FALSE(!Static::CPUCacheActive())) { + if (ABSL_PREDICT_FALSE(!state.CpuCacheActive())) { return false; } @@ -374,8 +2774,8 @@ inline bool UsePerCpuCache() { // into tcmalloc. // // If the per-CPU cache for a thread is not initialized, we push ourselves - // onto the slow path (if !defined(TCMALLOC_DEPRECATED_PERTHREAD)) until this - // occurs. See fast_alloc's use of TryRecordAllocationFast. + // onto the slow path until this occurs. See fast_alloc's use of + // TryRecordAllocationFast. if (ABSL_PREDICT_TRUE(subtle::percpu::IsFast())) { ThreadCache::BecomeIdle(); return true; diff --git a/contrib/libs/tcmalloc/tcmalloc/cpu_cache_activate_test.cc b/contrib/libs/tcmalloc/tcmalloc/cpu_cache_activate_test.cc new file mode 100644 index 000000000000..960e79428618 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/cpu_cache_activate_test.cc @@ -0,0 +1,87 @@ +// Copyright 2021 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +#include // NOLINT(build/c++11) + +#include "benchmark/benchmark.h" +#include "gtest/gtest.h" +#include "absl/base/internal/sysinfo.h" +#include "absl/random/random.h" +#include "absl/synchronization/notification.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "tcmalloc/cpu_cache.h" +#include "tcmalloc/internal/percpu.h" +#include "tcmalloc/internal/sysinfo.h" +#include "tcmalloc/internal_malloc_extension.h" +#include "tcmalloc/static_vars.h" + +namespace tcmalloc { +namespace tcmalloc_internal { +namespace { + +// This test mutates global state, including triggering the activation of the +// per-CPU caches. It should not be run along side other tests in the same +// process that may rely on an isolated global instance. +TEST(CpuCacheActivateTest, GlobalInstance) { + if (!subtle::percpu::IsFast()) { + return; + } + + CpuCache& cache = tc_globals.cpu_cache(); + + absl::Notification done; + + std::thread t([&]() { + const int num_cpus = NumCPUs(); + absl::BitGen rng; + + while (!done.HasBeenNotified()) { + const double coin = absl::Uniform(rng, 0., 1.); + const bool ready = tc_globals.CpuCacheActive(); + + if (ready && coin < 0.25) { + const int cpu = absl::Uniform(rng, 0, num_cpus); + benchmark::DoNotOptimize(cache.UsedBytes(cpu)); + } else if (ready && coin < 0.5) { + const int cpu = absl::Uniform(rng, 0, num_cpus); + benchmark::DoNotOptimize(cache.Capacity(cpu)); + } else if (ready && coin < 0.75) { + benchmark::DoNotOptimize(cache.TotalUsedBytes()); + } else { + benchmark::DoNotOptimize(cache.CacheLimit()); + } + } + }); + + // Trigger initialization of the CpuCache, confirming it was not initialized + // at the start of the test and is afterwards. + EXPECT_FALSE(tc_globals.CpuCacheActive()); + ASSERT_NE(&TCMalloc_Internal_ForceCpuCacheActivation, nullptr); + Parameters::set_per_cpu_caches(true); + TCMalloc_Internal_ForceCpuCacheActivation(); + EXPECT_TRUE(tc_globals.CpuCacheActive()); + + absl::SleepFor(absl::Seconds(0.2)); + + done.Notify(); + t.join(); +} + +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/cpu_cache_test.cc b/contrib/libs/tcmalloc/tcmalloc/cpu_cache_test.cc index fd4282b9c3c1..68eb45b67f91 100644 --- a/contrib/libs/tcmalloc/tcmalloc/cpu_cache_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/cpu_cache_test.cc @@ -14,121 +14,494 @@ #include "tcmalloc/cpu_cache.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include #include // NOLINT(build/c++11) +#include +#include #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/base/optimization.h" +#include "absl/random/bit_gen_ref.h" #include "absl/random/random.h" -#include "absl/random/seed_sequences.h" +#include "absl/synchronization/mutex.h" +#include "absl/time/time.h" +#include "absl/types/span.h" #include "tcmalloc/common.h" +#include "tcmalloc/internal/affinity.h" +#include "tcmalloc/internal/logging.h" #include "tcmalloc/internal/optimization.h" -#include "tcmalloc/internal/util.h" +#include "tcmalloc/internal/percpu.h" +#include "tcmalloc/internal/percpu_tcmalloc.h" +#include "tcmalloc/internal/sysinfo.h" +#include "tcmalloc/mock_transfer_cache.h" #include "tcmalloc/parameters.h" +#include "tcmalloc/size_class_info.h" +#include "tcmalloc/sizemap.h" #include "tcmalloc/static_vars.h" +#include "tcmalloc/tcmalloc_policy.h" #include "tcmalloc/testing/testutil.h" +#include "tcmalloc/testing/thread_manager.h" +#include "tcmalloc/transfer_cache.h" namespace tcmalloc { namespace tcmalloc_internal { +namespace subtle::percpu { +class TcmallocTest { + public: + static int VirtualCpuSynchronize() { return VirtualCpu::Synchronize(); } +}; +} // namespace subtle::percpu + +class CpuCachePeer { + public: + template + static uint8_t GetSlabShift(const CpuCache& cpu_cache) { + return cpu_cache.freelist_.GetShift(); + } + + template + static void IncrementCacheMisses(CpuCache& cpu_cache) { + cpu_cache.RecordCacheMissStat(/*cpu=*/0, /*is_alloc=*/true); + cpu_cache.RecordCacheMissStat(/*cpu=*/0, /*is_alloc=*/false); + } + + // Validate that we're using >90% of the available slab bytes. + template + static void ValidateSlabBytes(const CpuCache& cpu_cache) { + cpu_cache_internal::SlabShiftBounds bounds = + cpu_cache.GetPerCpuSlabShiftBounds(); + for (uint8_t shift = bounds.initial_shift; + shift <= bounds.max_shift && + shift > cpu_cache_internal::kInitialBasePerCpuShift; + ++shift) { + const auto [bytes_required, bytes_available] = + EstimateSlabBytes(cpu_cache.GetMaxCapacityFunctor(shift)); + EXPECT_GT(bytes_required * 10, bytes_available * 9) + << bytes_required << " " << bytes_available << " " << kNumaPartitions + << " " << kNumBaseClasses << " " << kNumClasses; + EXPECT_LE(bytes_required, bytes_available); + } + } + + template + static size_t ResizeInfoSize() { + return sizeof(typename CpuCache::ResizeInfo); + } +}; + namespace { -constexpr size_t kStressSlabs = 4; -void* OOMHandler(size_t) { return nullptr; } +enum class DynamicSlab { kGrow, kShrink, kNoop }; -TEST(CpuCacheTest, Metadata) { - if (!subtle::percpu::IsFast()) { - return; +class TestStaticForwarder { + public: + TestStaticForwarder() : sharded_manager_(&owner_, &cpu_layout_) { + numa_topology_.Init(); + } + + void InitializeShardedManager(int num_shards) { + cpu_layout_.Init(num_shards); + sharded_manager_.Init(); } - const int num_cpus = absl::base_internal::NumCPUs(); + static void* Alloc(size_t size, std::align_val_t alignment) { + return mmap(nullptr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } - CPUCache& cache = Static::cpu_cache(); - // Since this test allocates memory, avoid activating the real fast path to - // minimize allocations against the per-CPU cache. - cache.Activate(CPUCache::ActivationMode::FastPathOffTestOnly); + void* AllocReportedImpending(size_t size, std::align_val_t alignment) { + arena_reported_impending_bytes_ -= static_cast(size); + return mmap(nullptr, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } - PerCPUMetadataState r = cache.MetadataMemoryUsage(); - EXPECT_EQ(r.virtual_size, num_cpus << CPUCache::kPerCpuShift); - if (Parameters::lazy_per_cpu_caches()) { - EXPECT_EQ(r.resident_size, 0); - } else { - EXPECT_EQ(r.resident_size, r.virtual_size); + static void Dealloc(void* ptr, size_t size, std::align_val_t /*alignment*/) { + munmap(ptr, size); } - auto count_cores = [&]() { - int populated_cores = 0; - for (int i = 0; i < num_cpus; i++) { - if (cache.HasPopulated(i)) { - populated_cores++; - } + void ArenaUpdateAllocatedAndNonresident(int64_t allocated, + int64_t nonresident) { + if (allocated > 0) { + EXPECT_EQ(arena_reported_impending_bytes_, 0); + ++shrink_to_usage_limit_calls_; } - return populated_cores; - }; - EXPECT_EQ(0, count_cores()); + if (nonresident == 0) { + arena_reported_impending_bytes_ += allocated; + } else { + arena_reported_impending_bytes_ = 0; + } + arena_reported_nonresident_bytes_ += nonresident; + } - int allowed_cpu_id; - const size_t kSizeClass = 3; - const size_t num_to_move = Static::sizemap().num_objects_to_move(kSizeClass); - const size_t virtual_cpu_id_offset = subtle::percpu::UsingFlatVirtualCpus() - ? offsetof(kernel_rseq, vcpu_id) - : offsetof(kernel_rseq, cpu_id); - void* ptr; - { - // Restrict this thread to a single core while allocating and processing the - // slow path. - // - // TODO(b/151313823): Without this restriction, we may access--for reading - // only--other slabs if we end up being migrated. These may cause huge - // pages to be faulted for those cores, leading to test flakiness. - tcmalloc_internal::ScopedAffinityMask mask( - tcmalloc_internal::AllowedCpus()[0]); - allowed_cpu_id = - subtle::percpu::GetCurrentVirtualCpuUnsafe(virtual_cpu_id_offset); + bool per_cpu_caches_dynamic_slab_enabled() { return dynamic_slab_enabled_; } - ptr = cache.Allocate(kSizeClass); + double per_cpu_caches_dynamic_slab_grow_threshold() { + if (dynamic_slab_grow_threshold_ >= 0) return dynamic_slab_grow_threshold_; + return dynamic_slab_ == DynamicSlab::kGrow + ? -1.0 + : std::numeric_limits::max(); + } - if (mask.Tampered() || - allowed_cpu_id != - subtle::percpu::GetCurrentVirtualCpuUnsafe(virtual_cpu_id_offset)) { - return; + double per_cpu_caches_dynamic_slab_shrink_threshold() { + if (dynamic_slab_shrink_threshold_ >= 0) + return dynamic_slab_shrink_threshold_; + return dynamic_slab_ == DynamicSlab::kShrink + ? std::numeric_limits::max() + : -1.0; + } + + bool reuse_size_classes() const { return true; } + + size_t class_to_size(int size_class) const { + if (size_map_.has_value()) { + return size_map_->class_to_size(size_class); + } else { + return transfer_cache_.class_to_size(size_class); + } + } + + absl::Span cold_size_classes() const { + if (size_map_.has_value()) { + return size_map_->ColdSizeClasses(); + } else { + return {}; + } + } + + size_t num_objects_to_move(int size_class) const { + if (size_map_.has_value()) { + return size_map_->num_objects_to_move(size_class); + } else { + return transfer_cache_.num_objects_to_move(size_class); } } - EXPECT_NE(ptr, nullptr); - EXPECT_EQ(1, count_cores()); - r = cache.MetadataMemoryUsage(); - EXPECT_EQ(r.virtual_size, num_cpus << CPUCache::kPerCpuShift); - if (Parameters::lazy_per_cpu_caches()) { + const NumaTopology& numa_topology() const { + return numa_topology_; + } + + using ShardedManager = + ShardedTransferCacheManagerBase; + + ShardedManager& sharded_transfer_cache() { return sharded_manager_; } + + const ShardedManager& sharded_transfer_cache() const { + return sharded_manager_; + } + + TwoSizeClassManager& + transfer_cache() { + return transfer_cache_; + } + + bool UseGenericShardedCache() const { return owner_.UseGenericCache(); } + void SetGenericShardedCache(bool value) { owner_.SetGenericCache(value); } + bool UseShardedCacheForLargeClassesOnly() const { + return owner_.EnableCacheForLargeClassesOnly(); + } + void SetShardedCacheForLargeClassesOnly(bool value) { + owner_.SetCacheForLargeClassesOnly(value); + } + + bool HaveHooks() const { + // TODO(b/242550501): Test other states. + return false; + } + + size_t arena_reported_nonresident_bytes_ = 0; + int64_t arena_reported_impending_bytes_ = 0; + size_t shrink_to_usage_limit_calls_ = 0; + bool dynamic_slab_enabled_ = false; + double dynamic_slab_grow_threshold_ = -1; + double dynamic_slab_shrink_threshold_ = -1; + DynamicSlab dynamic_slab_ = DynamicSlab::kNoop; + std::optional size_map_; + + private: + NumaTopology numa_topology_; + FakeShardedTransferCacheManager owner_; + FakeCpuLayout cpu_layout_; + ShardedManager sharded_manager_; + TwoSizeClassManager + transfer_cache_; +}; + +using CpuCache = cpu_cache_internal::CpuCache; +using MissCount = CpuCache::MissCount; +using PerClassMissType = CpuCache::PerClassMissType; + +TEST(CpuCacheTest, MinimumShardsForGenericCache) { + if (!subtle::percpu::IsFast()) { + return; + } + CpuCache cache; + cache.Activate(); + + using ShardedManager = TestStaticForwarder::ShardedManager; + TestStaticForwarder& forwarder = cache.forwarder(); + forwarder.SetShardedCacheForLargeClassesOnly(false); + forwarder.SetGenericShardedCache(true); + + ShardedManager& sharded_transfer_cache = forwarder.sharded_transfer_cache(); + constexpr int kNumShards = ShardedManager::kMinShardsAllowed - 1; + TC_ASSERT_GT(kNumShards, 0); + forwarder.InitializeShardedManager(kNumShards); + + constexpr int kCpuId = 0; + ScopedFakeCpuId fake_cpu_id(kCpuId); + EXPECT_FALSE(sharded_transfer_cache.shard_initialized(0)); + EXPECT_EQ(sharded_transfer_cache.NumActiveShards(), 0); + EXPECT_EQ(forwarder.transfer_cache().tc_length(kSizeClass), 0); + + constexpr size_t kSizeClass = 1; + const size_t num_to_move = cache.forwarder().num_objects_to_move(kSizeClass); + + // Allocate an object. As we are using less than kMinShardsAllowed number of + // shards, we should bypass sharded transfer cache entirely. + void* ptr = cache.Allocate(kSizeClass); + for (int size_class = 1; size_class < kNumClasses; ++size_class) { + EXPECT_FALSE(sharded_transfer_cache.should_use(size_class)); + EXPECT_EQ(sharded_transfer_cache.GetStats(size_class).capacity, 0); + EXPECT_EQ(sharded_transfer_cache.GetStats(size_class).max_capacity, 0); + } + // No requests are sent to sharded transfer cache. So, it should stay + // uninitialized. + EXPECT_EQ(sharded_transfer_cache.tc_length(kCpuId, kSizeClass), 0); + EXPECT_FALSE(sharded_transfer_cache.shard_initialized(0)); + EXPECT_EQ(sharded_transfer_cache.NumActiveShards(), 0); + EXPECT_EQ(forwarder.transfer_cache().tc_length(kSizeClass), 0); + + cache.Deallocate(ptr, kSizeClass); + cache.Reclaim(0); + EXPECT_EQ(sharded_transfer_cache.tc_length(kCpuId, kSizeClass), 0); + EXPECT_FALSE(sharded_transfer_cache.shard_initialized(0)); + EXPECT_EQ(sharded_transfer_cache.NumActiveShards(), 0); + // We should deallocate directly to the LIFO transfer cache. + EXPECT_EQ(forwarder.transfer_cache().tc_length(kSizeClass), + num_to_move / 2 + 1); +} + +TEST(CpuCacheTest, UsesShardedAsBackingCache) { + if (!subtle::percpu::IsFast()) { + return; + } + CpuCache cache; + cache.Activate(); + + using ShardedManager = TestStaticForwarder::ShardedManager; + TestStaticForwarder& forwarder = cache.forwarder(); + forwarder.SetShardedCacheForLargeClassesOnly(false); + forwarder.SetGenericShardedCache(true); + + ShardedManager& sharded_transfer_cache = forwarder.sharded_transfer_cache(); + constexpr int kNumShards = ShardedManager::kMinShardsAllowed; + TC_ASSERT_GT(kNumShards, 0); + forwarder.InitializeShardedManager(kNumShards); + + ScopedFakeCpuId fake_cpu_id(0); + EXPECT_FALSE(sharded_transfer_cache.shard_initialized(0)); + EXPECT_EQ(sharded_transfer_cache.NumActiveShards(), 0); + + constexpr size_t kSizeClass = 1; + TransferCacheStats sharded_stats = + sharded_transfer_cache.GetStats(kSizeClass); + EXPECT_EQ(sharded_stats.remove_hits, 0); + EXPECT_EQ(sharded_stats.remove_misses, 0); + EXPECT_EQ(sharded_stats.insert_hits, 0); + EXPECT_EQ(sharded_stats.insert_misses, 0); + + // Allocate an object and make sure that we allocate from the sharded transfer + // cache and that the sharded cache has been initialized. + void* ptr = cache.Allocate(kSizeClass); + sharded_stats = sharded_transfer_cache.GetStats(kSizeClass); + EXPECT_EQ(sharded_stats.remove_hits, 0); + EXPECT_EQ(sharded_stats.remove_misses, 1); + EXPECT_EQ(sharded_stats.insert_hits, 0); + EXPECT_EQ(sharded_stats.insert_misses, 0); + EXPECT_TRUE(sharded_transfer_cache.shard_initialized(0)); + EXPECT_EQ(sharded_transfer_cache.NumActiveShards(), 1); + + // Free objects to confirm that they are indeed released back to the sharded + // transfer cache. + cache.Deallocate(ptr, kSizeClass); + cache.Reclaim(0); + sharded_stats = sharded_transfer_cache.GetStats(kSizeClass); + EXPECT_EQ(sharded_stats.insert_hits, 1); + EXPECT_EQ(sharded_stats.insert_misses, 0); + + // Ensure that we never use legacy transfer cache by checking that hits and + // misses are zero. + TransferCacheStats tc_stats = forwarder.transfer_cache().GetStats(kSizeClass); + EXPECT_EQ(tc_stats.remove_hits, 0); + EXPECT_EQ(tc_stats.remove_misses, 0); + EXPECT_EQ(tc_stats.insert_hits, 0); + EXPECT_EQ(tc_stats.insert_misses, 0); + forwarder.SetGenericShardedCache(false); + cache.Deactivate(); +} + +TEST(CpuCacheTest, ResizeInfoNoFalseSharing) { + const size_t resize_info_size = CpuCachePeer::ResizeInfoSize(); + EXPECT_EQ(resize_info_size % ABSL_CACHELINE_SIZE, 0) << resize_info_size; +} + +TEST(CpuCacheTest, Metadata) { + if (!subtle::percpu::IsFast()) { + return; + } + + const int num_cpus = NumCPUs(); + + const int kAttempts = 3; + for (int attempt = 1; attempt <= kAttempts; attempt++) { + SCOPED_TRACE(absl::StrCat("attempt=", attempt)); + + CpuCache cache; + cache.Activate(); + + cpu_cache_internal::SlabShiftBounds shift_bounds = + cache.GetPerCpuSlabShiftBounds(); + + PerCPUMetadataState r = cache.MetadataMemoryUsage(); + size_t slabs_size = subtle::percpu::GetSlabsAllocSize( + subtle::percpu::ToShiftType(shift_bounds.max_shift), num_cpus); + size_t resize_size = num_cpus * sizeof(bool); + size_t begins_size = kNumClasses * sizeof(std::atomic); + EXPECT_EQ(r.virtual_size, slabs_size + resize_size + begins_size); + EXPECT_EQ(r.resident_size, 0); + + auto count_cores = [&]() { + int populated_cores = 0; + for (int i = 0; i < num_cpus; i++) { + if (cache.HasPopulated(i)) { + populated_cores++; + } + } + return populated_cores; + }; + + EXPECT_EQ(0, count_cores()); + + int allowed_cpu_id; + const size_t kSizeClass = 2; + const size_t num_to_move = + cache.forwarder().num_objects_to_move(kSizeClass); + + TransferCacheStats tc_stats = + cache.forwarder().transfer_cache().GetStats(kSizeClass); + EXPECT_EQ(tc_stats.remove_hits, 0); + EXPECT_EQ(tc_stats.remove_misses, 0); + EXPECT_EQ(tc_stats.remove_object_misses, 0); + EXPECT_EQ(tc_stats.insert_hits, 0); + EXPECT_EQ(tc_stats.insert_misses, 0); + EXPECT_EQ(tc_stats.insert_object_misses, 0); + + void* ptr; + { + // Restrict this thread to a single core while allocating and processing + // the slow path. + // + // TODO(b/151313823): Without this restriction, we may access--for + // reading only--other slabs if we end up being migrated. These may cause + // huge pages to be faulted for those cores, leading to test flakiness. + tcmalloc_internal::ScopedAffinityMask mask( + tcmalloc_internal::AllowedCpus()[0]); + allowed_cpu_id = subtle::percpu::TcmallocTest::VirtualCpuSynchronize(); + + ptr = cache.Allocate(kSizeClass); + + if (mask.Tampered() || + allowed_cpu_id != + subtle::percpu::TcmallocTest::VirtualCpuSynchronize()) { + return; + } + } + EXPECT_NE(ptr, nullptr); + EXPECT_EQ(1, count_cores()); + + // We don't care if the transfer cache hit or missed, but the CPU cache + // should have done the operation. + tc_stats = cache.forwarder().transfer_cache().GetStats(kSizeClass); + if ((tc_stats.remove_object_misses != num_to_move || + tc_stats.insert_hits + tc_stats.insert_misses != 0) && + attempt < kAttempts) { + // The operation didn't occur as expected, likely because we were + // preempted but returned to the same core (otherwise Tampered would have + // fired). + // + // The MSB of tcmalloc_slabs should be cleared to indicate we were + // preempted. As of December 2024, Refill and its callees do not invoke + // CacheCpuSlab. This check can spuriously pass if we're preempted + // between the end of Allocate and now, rather than within Allocate, but + // it ensures we do not silently break. +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + EXPECT_EQ(subtle::percpu::tcmalloc_slabs & TCMALLOC_CACHED_SLABS_MASK, 0); +#endif // TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + + cache.Deallocate(ptr, kSizeClass); + cache.Deactivate(); + + continue; + } + + EXPECT_EQ(tc_stats.remove_hits + tc_stats.remove_misses, 1); + EXPECT_EQ(tc_stats.remove_object_misses, num_to_move); + EXPECT_EQ(tc_stats.insert_hits, 0); + EXPECT_EQ(tc_stats.insert_misses, 0); + EXPECT_EQ(tc_stats.insert_object_misses, 0); + + r = cache.MetadataMemoryUsage(); + EXPECT_EQ( + r.virtual_size, + resize_size + begins_size + + subtle::percpu::GetSlabsAllocSize( + subtle::percpu::ToShiftType(shift_bounds.max_shift), num_cpus)); + // We expect to fault in a single core, but we may end up faulting an - // entire hugepage worth of memory + // entire hugepage worth of memory when we touch that core and another when + // touching the header. const size_t core_slab_size = r.virtual_size / num_cpus; const size_t upper_bound = - ((core_slab_size + kHugePageSize - 1) & ~(kHugePageSize - 1)); + ((core_slab_size + kHugePageSize - 1) & ~(kHugePageSize - 1)) + + kHugePageSize; // A single core may be less than the full slab (core_slab_size), since we // do not touch every page within the slab. EXPECT_GT(r.resident_size, 0); - EXPECT_LE(r.resident_size, upper_bound) << count_cores(); + EXPECT_LE(r.resident_size, upper_bound) + << count_cores() << " " << core_slab_size << " " << kHugePageSize; // This test is much more sensitive to implementation details of the per-CPU // cache. It may need to be updated from time to time. These numbers were // calculated by MADV_NOHUGEPAGE'ing the memory used for the slab and // measuring the resident size. - // - // TODO(ckennelly): Allow CPUCache::Activate to accept a specific arena - // allocator, so we can MADV_NOHUGEPAGE the backing store in testing for - // more precise measurements. - switch (CPUCache::kPerCpuShift) { - case 12: + switch (shift_bounds.max_shift) { + case 13: EXPECT_GE(r.resident_size, 4096); break; - case 18: - EXPECT_GE(r.resident_size, 110592); + case 19: + EXPECT_GE(r.resident_size, 8192); break; default: ASSUME(false); break; - }; + } // Read stats from the CPU caches. This should not impact resident_size. const size_t max_cpu_cache_size = Parameters::max_per_cpu_cache_size(); @@ -151,12 +524,12 @@ TEST(CpuCacheTest, Metadata) { cache.Capacity(cpu)); } - for (int cl = 0; cl < kNumClasses; ++cl) { - // This is sensitive to the current growth policies of CPUCache. It may + for (int size_class = 1; size_class < kNumClasses; ++size_class) { + // This is sensitive to the current growth policies of CpuCache. It may // require updating from time-to-time. - EXPECT_EQ(cache.TotalObjectsOfClass(cl), - (cl == kSizeClass ? num_to_move - 1 : 0)) - << cl; + EXPECT_EQ(cache.TotalObjectsOfClass(size_class), + (size_class == kSizeClass ? num_to_move - 1 : 0)) + << size_class; } EXPECT_EQ(cache.TotalUsedBytes(), total_used_bytes); @@ -166,17 +539,11 @@ TEST(CpuCacheTest, Metadata) { EXPECT_LE(post_stats.resident_size, upper_bound) << count_cores(); // Confirm stats are unchanged. EXPECT_EQ(r.resident_size, post_stats.resident_size); - } else { - EXPECT_EQ(r.resident_size, r.virtual_size); - } - - // Tear down. - // - // TODO(ckennelly): We're interacting with the real TransferCache. - cache.Deallocate(ptr, kSizeClass); - for (int i = 0; i < num_cpus; i++) { - cache.Reclaim(i); + // Tear down. + cache.Deallocate(ptr, kSizeClass); + cache.Deactivate(); + break; } } @@ -185,30 +552,25 @@ TEST(CpuCacheTest, CacheMissStats) { return; } - const int num_cpus = absl::base_internal::NumCPUs(); + const int num_cpus = NumCPUs(); - CPUCache& cache = Static::cpu_cache(); - // Since this test allocates memory, avoid activating the real fast path to - // minimize allocations against the per-CPU cache. - cache.Activate(CPUCache::ActivationMode::FastPathOffTestOnly); + CpuCache cache; + cache.Activate(); // The number of underflows and overflows must be zero for all the caches. for (int cpu = 0; cpu < num_cpus; ++cpu) { - CPUCache::CpuCacheMissStats total_misses = + CpuCache::CpuCacheMissStats total_misses = cache.GetTotalCacheMissStats(cpu); - CPUCache::CpuCacheMissStats interval_misses = - cache.GetIntervalCacheMissStats(cpu); + CpuCache::CpuCacheMissStats shuffle_misses = + cache.GetIntervalCacheMissStats(cpu, MissCount::kShuffle); EXPECT_EQ(total_misses.underflows, 0); EXPECT_EQ(total_misses.overflows, 0); - EXPECT_EQ(interval_misses.underflows, 0); - EXPECT_EQ(interval_misses.overflows, 0); + EXPECT_EQ(shuffle_misses.underflows, 0); + EXPECT_EQ(shuffle_misses.overflows, 0); } int allowed_cpu_id; - const size_t kSizeClass = 3; - const size_t virtual_cpu_id_offset = subtle::percpu::UsingFlatVirtualCpus() - ? offsetof(kernel_rseq, vcpu_id) - : offsetof(kernel_rseq, cpu_id); + const size_t kSizeClass = 2; void* ptr; { // Restrict this thread to a single core while allocating and processing the @@ -219,73 +581,79 @@ TEST(CpuCacheTest, CacheMissStats) { // pages to be faulted for those cores, leading to test flakiness. tcmalloc_internal::ScopedAffinityMask mask( tcmalloc_internal::AllowedCpus()[0]); - allowed_cpu_id = - subtle::percpu::GetCurrentVirtualCpuUnsafe(virtual_cpu_id_offset); + allowed_cpu_id = subtle::percpu::TcmallocTest::VirtualCpuSynchronize(); - ptr = cache.Allocate(kSizeClass); + ptr = cache.Allocate(kSizeClass); if (mask.Tampered() || allowed_cpu_id != - subtle::percpu::GetCurrentVirtualCpuUnsafe(virtual_cpu_id_offset)) { + subtle::percpu::TcmallocTest::VirtualCpuSynchronize()) { return; } } for (int cpu = 0; cpu < num_cpus; ++cpu) { - CPUCache::CpuCacheMissStats total_misses = + CpuCache::CpuCacheMissStats total_misses = cache.GetTotalCacheMissStats(cpu); - CPUCache::CpuCacheMissStats interval_misses = - cache.GetIntervalCacheMissStats(cpu); + CpuCache::CpuCacheMissStats shuffle_misses = + cache.GetIntervalCacheMissStats(cpu, MissCount::kShuffle); if (cpu == allowed_cpu_id) { EXPECT_EQ(total_misses.underflows, 1); - EXPECT_EQ(interval_misses.underflows, 1); + EXPECT_EQ(shuffle_misses.underflows, 1); } else { EXPECT_EQ(total_misses.underflows, 0); - EXPECT_EQ(interval_misses.underflows, 0); + EXPECT_EQ(shuffle_misses.underflows, 0); } EXPECT_EQ(total_misses.overflows, 0); - EXPECT_EQ(interval_misses.overflows, 0); + EXPECT_EQ(shuffle_misses.overflows, 0); } // Tear down. - // - // TODO(ckennelly): We're interacting with the real TransferCache. cache.Deallocate(ptr, kSizeClass); + cache.Deactivate(); +} - for (int i = 0; i < num_cpus; i++) { - cache.Reclaim(i); +static void ResizeSizeClasses(CpuCache& cache, const std::atomic& stop) { + if (!subtle::percpu::IsFast()) { + return; + } + + // Wake up every 10ms to resize size classes. Let miss stats acummulate over + // those 10ms. + while (!stop.load(std::memory_order_acquire)) { + cache.ResizeSizeClasses(); + absl::SleepFor(absl::Milliseconds(10)); } } -static void ShuffleThread(const std::atomic& stop) { +static void ShuffleThread(CpuCache& cache, const std::atomic& stop) { if (!subtle::percpu::IsFast()) { return; } - CPUCache& cache = Static::cpu_cache(); // Wake up every 10ms to shuffle the caches so that we can allow misses to // accumulate during that interval - while (!stop) { + while (!stop.load(std::memory_order_acquire)) { cache.ShuffleCpuCaches(); absl::SleepFor(absl::Milliseconds(10)); } } -static void StressThread(size_t thread_id, const std::atomic& stop) { +static void StressThread(CpuCache& cache, size_t thread_id, + const std::atomic& stop) { if (!subtle::percpu::IsFast()) { return; } - CPUCache& cache = Static::cpu_cache(); std::vector> blocks; - absl::BitGen rnd; - while (!stop) { + absl::InsecureBitGen rnd; + while (!stop.load(std::memory_order_acquire)) { const int what = absl::Uniform(rnd, 0, 2); if (what) { // Allocate an object for a class - size_t cl = absl::Uniform(rnd, 1, kStressSlabs + 1); - void* ptr = cache.Allocate(cl); - blocks.emplace_back(std::make_pair(cl, ptr)); + size_t size_class = absl::Uniform(rnd, 1, 3); + void* ptr = cache.Allocate(size_class); + blocks.emplace_back(std::make_pair(size_class, ptr)); } else { // Deallocate an object for a class if (!blocks.empty()) { @@ -301,25 +669,247 @@ static void StressThread(size_t thread_id, const std::atomic& stop) { } } +void AllocateThenDeallocate(CpuCache& cache, int cpu, size_t size_class, + int ops) { + std::vector objects; + ScopedFakeCpuId fake_cpu_id(cpu); + for (int i = 0; i < ops; ++i) { + void* ptr = cache.Allocate(size_class); + objects.push_back(ptr); + } + for (auto* ptr : objects) { + cache.Deallocate(ptr, size_class); + } + objects.clear(); +} + +// In this test, we check if we can resize size classes based on the number of +// misses they encounter. First, we exhaust cache capacity by filling up +// larger size class as much as possible. Then, we try to allocate objects for +// the smaller size class. This should result in misses as we do not resize its +// capacity in the foreground when the feature is enabled. We confirm that it +// indeed encounters a capacity miss. We then resize size classes and allocate +// small size class objects again. We should be able to utilize an increased +// capacity for the size class to allocate and deallocate these objects. We also +// confirm that we do not lose the overall cpu cache capacity when we resize +// size class capacities. +TEST(CpuCacheTest, ResizeMaxCapacityTest) { + if (!subtle::percpu::IsFast()) { + return; + } + + CpuCache cache; + // Increase cache capacity so that we can exhaust max capacity for the size + // class before hitting the maximum cache limit. + const size_t max_cpu_cache_size = 128 << 10 << 10; + cache.SetCacheLimit(max_cpu_cache_size); + cache.Activate(); + + // Temporarily fake being on the given CPU. + constexpr int kCpuId = 0; + constexpr int kCpuId1 = 1; + + constexpr int kLargeClass = 2; + constexpr int kGrowthFactor = 5; + const int base_max_capacity = + cache.GetMaxCapacity(kLargeClass, CpuCachePeer::GetSlabShift(cache)); + + const size_t large_class_size = cache.forwarder().class_to_size(kLargeClass); + ASSERT_LT(large_class_size * base_max_capacity, cache.CacheLimit()); + + const size_t batch_size_large = + cache.forwarder().num_objects_to_move(kLargeClass); + + size_t ops = 0; + while (true) { + // We allocate and deallocate additional batch_size number of objects each + // time so that cpu cache suffers successive underflow and overflow, and it + // can grow. + ops += batch_size_large; + AllocateThenDeallocate(cache, kCpuId, kLargeClass, ops); + if (cache.GetCapacityOfSizeClass(kCpuId, kLargeClass) == + base_max_capacity) { + break; + } + } + + size_t interval_misses = cache.GetIntervalSizeClassMisses( + kCpuId, kLargeClass, PerClassMissType::kMaxCapacityTotal, + PerClassMissType::kMaxCapacityResize); + EXPECT_GT(interval_misses, 0); + EXPECT_EQ(cache.GetCapacityOfSizeClass(kCpuId, kLargeClass), + base_max_capacity); + + AllocateThenDeallocate(cache, kCpuId, kLargeClass, ops); + EXPECT_GT(cache.GetIntervalSizeClassMisses( + kCpuId, kLargeClass, PerClassMissType::kMaxCapacityTotal, + PerClassMissType::kMaxCapacityResize), + 0); + + { + ScopedFakeCpuId fake_cpu_id_1(kCpuId1); + cache.ResizeSizeClassMaxCapacities(); + } + + const int resized_max_capacity = + cache.GetMaxCapacity(kLargeClass, CpuCachePeer::GetSlabShift(cache)); + EXPECT_EQ(resized_max_capacity, + base_max_capacity + kGrowthFactor * batch_size_large); + + interval_misses = cache.GetIntervalSizeClassMisses( + kCpuId, kLargeClass, PerClassMissType::kMaxCapacityTotal, + PerClassMissType::kMaxCapacityResize); + EXPECT_EQ(interval_misses, 0); + + ops = 0; + while (true) { + // We allocate and deallocate additional batch_size number of objects each + // time so that cpu cache suffers successive underflow and overflow, and it + // can grow. + ops += batch_size_large; + AllocateThenDeallocate(cache, kCpuId, kLargeClass, ops); + if (cache.GetCapacityOfSizeClass(kCpuId, kLargeClass) == + base_max_capacity) { + break; + } + } + for (int i = 0; i < kGrowthFactor; ++i) { + ops += batch_size_large; + AllocateThenDeallocate(cache, kCpuId, kLargeClass, ops); + } + EXPECT_EQ(cache.GetCapacityOfSizeClass(kCpuId, kLargeClass), + resized_max_capacity); + + // Reclaim caches. + cache.Deactivate(); +} + +static void ResizeMaxCapacities(CpuCache& cache, + const std::atomic& stop) { + if (!subtle::percpu::IsFast()) { + return; + } + + // Wake up every 10ms to resize size classes. Let miss stats acummulate over + // those 10ms. + while (!stop.load(std::memory_order_acquire)) { + cache.ResizeSizeClassMaxCapacities(); + absl::SleepFor(absl::Milliseconds(10)); + } +} + +TEST(CpuCacheTest, StressMaxCapacityResize) { + if (!subtle::percpu::IsFast()) { + return; + } + + CpuCache cache; + cache.Activate(); + + std::vector threads; + std::thread resize_thread; + const int n_threads = NumCPUs(); + std::atomic stop(false); + + size_t old_max_capacity = 0; + size_t new_max_capacity = 0; + for (int size_class = 0; size_class < kNumClasses; ++size_class) { + old_max_capacity += + cache.GetMaxCapacity(size_class, CpuCachePeer::GetSlabShift(cache)); + } + + for (size_t t = 0; t < n_threads; ++t) { + threads.push_back( + std::thread(StressThread, std::ref(cache), t, std::ref(stop))); + } + resize_thread = + std::thread(ResizeMaxCapacities, std::ref(cache), std::ref(stop)); + + absl::SleepFor(absl::Seconds(10)); + stop = true; + for (auto& t : threads) { + t.join(); + } + resize_thread.join(); + + // Check that the total capacity is preserved after the stress test. + size_t capacity = 0; + const int num_cpus = NumCPUs(); + const size_t kTotalCapacity = num_cpus * Parameters::max_per_cpu_cache_size(); + for (int cpu = 0; cpu < num_cpus; ++cpu) { + EXPECT_EQ(cache.Allocated(cpu) + cache.Unallocated(cpu), + cache.Capacity(cpu)); + capacity += cache.Capacity(cpu); + } + for (int size_class = 0; size_class < kNumClasses; ++size_class) { + new_max_capacity += + cache.GetMaxCapacity(size_class, CpuCachePeer::GetSlabShift(cache)); + } + EXPECT_EQ(new_max_capacity, old_max_capacity); + + EXPECT_EQ(capacity, kTotalCapacity); + cache.Deactivate(); +} + +TEST(CpuCacheTest, StressSizeClassResize) { + if (!subtle::percpu::IsFast()) { + return; + } + + CpuCache cache; + cache.Activate(); + + std::vector threads; + std::thread resize_thread; + const int n_threads = NumCPUs(); + std::atomic stop(false); + + for (size_t t = 0; t < n_threads; ++t) { + threads.push_back( + std::thread(StressThread, std::ref(cache), t, std::ref(stop))); + } + resize_thread = + std::thread(ResizeSizeClasses, std::ref(cache), std::ref(stop)); + + absl::SleepFor(absl::Seconds(5)); + stop = true; + for (auto& t : threads) { + t.join(); + } + resize_thread.join(); + + // Check that the total capacity is preserved after the stress test. + size_t capacity = 0; + const int num_cpus = NumCPUs(); + const size_t kTotalCapacity = num_cpus * Parameters::max_per_cpu_cache_size(); + for (int cpu = 0; cpu < num_cpus; ++cpu) { + EXPECT_EQ(cache.Allocated(cpu) + cache.Unallocated(cpu), + cache.Capacity(cpu)); + capacity += cache.Capacity(cpu); + } + EXPECT_EQ(capacity, kTotalCapacity); + + cache.Deactivate(); +} + TEST(CpuCacheTest, StealCpuCache) { if (!subtle::percpu::IsFast()) { return; } - CPUCache& cache = Static::cpu_cache(); - // Since this test allocates memory, avoid activating the real fast path to - // minimize allocations against the per-CPU cache. - cache.Activate(CPUCache::ActivationMode::FastPathOffTestOnly); + CpuCache cache; + cache.Activate(); std::vector threads; std::thread shuffle_thread; - const int n_threads = absl::base_internal::NumCPUs(); + const int n_threads = NumCPUs(); std::atomic stop(false); for (size_t t = 0; t < n_threads; ++t) { - threads.push_back(std::thread(StressThread, t, std::ref(stop))); + threads.push_back( + std::thread(StressThread, std::ref(cache), t, std::ref(stop))); } - shuffle_thread = std::thread(ShuffleThread, std::ref(stop)); + shuffle_thread = std::thread(ShuffleThread, std::ref(cache), std::ref(stop)); absl::SleepFor(absl::Seconds(5)); stop = true; @@ -330,7 +920,7 @@ TEST(CpuCacheTest, StealCpuCache) { // Check that the total capacity is preserved after the shuffle. size_t capacity = 0; - const int num_cpus = absl::base_internal::NumCPUs(); + const int num_cpus = NumCPUs(); const size_t kTotalCapacity = num_cpus * Parameters::max_per_cpu_cache_size(); for (int cpu = 0; cpu < num_cpus; ++cpu) { EXPECT_EQ(cache.Allocated(cpu) + cache.Unallocated(cpu), @@ -339,50 +929,225 @@ TEST(CpuCacheTest, StealCpuCache) { } EXPECT_EQ(capacity, kTotalCapacity); - for (int cpu = 0; cpu < num_cpus; ++cpu) { - cache.Reclaim(cpu); + cache.Deactivate(); +} + +// Test that when dynamic slab is enabled, nothing goes horribly wrong and that +// arena non-resident bytes increases as expected. +TEST(CpuCacheTest, DynamicSlab) { + if (!subtle::percpu::IsFast()) { + return; + } + CpuCache cache; + TestStaticForwarder& forwarder = cache.forwarder(); + + size_t prev_reported_nonresident_bytes = + forwarder.arena_reported_nonresident_bytes_; + EXPECT_EQ(forwarder.arena_reported_impending_bytes_, 0); + size_t prev_shrink_to_usage_limit_calls = + forwarder.shrink_to_usage_limit_calls_; + forwarder.dynamic_slab_enabled_ = true; + forwarder.dynamic_slab_ = DynamicSlab::kNoop; + + cache.Activate(); + + std::vector threads; + const int n_threads = NumCPUs(); + std::atomic stop(false); + + for (size_t t = 0; t < n_threads; ++t) { + threads.push_back( + std::thread(StressThread, std::ref(cache), t, std::ref(stop))); + } + + cpu_cache_internal::SlabShiftBounds shift_bounds = + cache.GetPerCpuSlabShiftBounds(); + int shift = shift_bounds.initial_shift; + + const auto repeat_dynamic_slab_ops = [&](DynamicSlab op, int shift_update, + int end_shift) { + const DynamicSlab ops[2] = {DynamicSlab::kNoop, op}; + int iters = end_shift > shift ? end_shift - shift : shift - end_shift; + iters += 2; // Test that we don't resize past end_shift. + for (int i = 0; i < iters; ++i) { + for (DynamicSlab dynamic_slab : ops) { + EXPECT_EQ(shift, CpuCachePeer::GetSlabShift(cache)); + absl::SleepFor(absl::Milliseconds(100)); + forwarder.dynamic_slab_ = dynamic_slab; + // If there were no misses in the current resize interval, then we may + // not resize so we ensure non-zero misses. + CpuCachePeer::IncrementCacheMisses(cache); + cache.ResizeSlabIfNeeded(); + if (dynamic_slab != DynamicSlab::kNoop && shift != end_shift) { + EXPECT_LT(prev_reported_nonresident_bytes, + forwarder.arena_reported_nonresident_bytes_); + EXPECT_EQ(forwarder.shrink_to_usage_limit_calls_, + 1 + prev_shrink_to_usage_limit_calls); + shift += shift_update; + } else { + EXPECT_EQ(prev_reported_nonresident_bytes, + forwarder.arena_reported_nonresident_bytes_); + } + prev_reported_nonresident_bytes = + forwarder.arena_reported_nonresident_bytes_; + + EXPECT_EQ(forwarder.arena_reported_impending_bytes_, 0); + prev_shrink_to_usage_limit_calls = + forwarder.shrink_to_usage_limit_calls_; + } + } + }; + + // First grow the slab to max size, then shrink it to min size. + repeat_dynamic_slab_ops(DynamicSlab::kGrow, /*shift_update=*/1, + shift_bounds.max_shift); + repeat_dynamic_slab_ops(DynamicSlab::kShrink, /*shift_update=*/-1, + shift_bounds.initial_shift); + + stop = true; + for (auto& t : threads) { + t.join(); + } + + cache.Deactivate(); +} + +// In this test, we check if we can resize size classes based on the number of +// misses they encounter. First, we exhaust cache capacity by filling up +// larger size class as much as possible. Then, we try to allocate objects for +// the smaller size class. This should result in misses as we do not resize its +// capacity in the foreground when the feature is enabled. We confirm that it +// indeed encounters a capacity miss. When then resize size classes and allocate +// small size class objects again. We should be able to utilize an increased +// capacity for the size class to allocate and deallocate these objects. We also +// confirm that we do not lose the overall cpu cache capacity when we resize +// size class capacities. +TEST(CpuCacheTest, ResizeSizeClassesTest) { + if (!subtle::percpu::IsFast()) { + return; + } + + CpuCache cache; + // Reduce cache capacity so that it will see need in stealing and rebalancing. + const size_t max_cpu_cache_size = 128 << 10; + cache.SetCacheLimit(max_cpu_cache_size); + cache.Activate(); + + // Temporarily fake being on the given CPU. + constexpr int kCpuId = 0; + constexpr int kCpuId1 = 1; + + constexpr int kSmallClass = 1; + constexpr int kLargeClass = 2; + constexpr int kMaxCapacity = 2048; + + const size_t large_class_size = cache.forwarder().class_to_size(kLargeClass); + ASSERT_GT(large_class_size * kMaxCapacity, max_cpu_cache_size); + + const size_t batch_size_small = + cache.forwarder().num_objects_to_move(kSmallClass); + const size_t batch_size_large = + cache.forwarder().num_objects_to_move(kLargeClass); + + size_t ops = 0; + while (true) { + // We allocate and deallocate additional batch_size number of objects each + // time so that cpu cache suffers successive underflow and overflow, and it + // can grow. + ops += batch_size_large; + if (ops > kMaxCapacity || cache.Allocated(kCpuId) == max_cpu_cache_size) + break; + + AllocateThenDeallocate(cache, kCpuId, kLargeClass, ops); + } + + EXPECT_EQ(cache.Unallocated(kCpuId), 0); + EXPECT_EQ(cache.Allocated(kCpuId), max_cpu_cache_size); + EXPECT_EQ(cache.TotalObjectsOfClass(kSmallClass), 0); + + size_t interval_misses = cache.GetIntervalSizeClassMisses( + kCpuId, kSmallClass, PerClassMissType::kCapacityTotal, + PerClassMissType::kCapacityResize); + EXPECT_EQ(interval_misses, 0); + + AllocateThenDeallocate(cache, kCpuId, kSmallClass, batch_size_small); + + interval_misses = cache.GetIntervalSizeClassMisses( + kCpuId, kSmallClass, PerClassMissType::kCapacityTotal, + PerClassMissType::kCapacityResize); + EXPECT_EQ(interval_misses, 2 * batch_size_small); + + EXPECT_EQ(cache.Unallocated(kCpuId), 0); + EXPECT_EQ(cache.Allocated(kCpuId), max_cpu_cache_size); + EXPECT_EQ(cache.TotalObjectsOfClass(kSmallClass), 0); + + const int num_resizes = NumCPUs() / CpuCache::kNumCpuCachesToResize; + { + ScopedFakeCpuId fake_cpu_id_1(kCpuId1); + for (int i = 0; i < num_resizes; ++i) { + cache.ResizeSizeClasses(); + } } + + // Since we just resized size classes, we started a new interval. So, miss + // this interval should be zero. + interval_misses = cache.GetIntervalSizeClassMisses( + kCpuId, kSmallClass, PerClassMissType::kCapacityTotal, + PerClassMissType::kCapacityResize); + EXPECT_EQ(interval_misses, 0); + + EXPECT_EQ(cache.Unallocated(kCpuId), 0); + EXPECT_EQ(cache.Allocated(kCpuId), max_cpu_cache_size); + + AllocateThenDeallocate(cache, kCpuId, kSmallClass, batch_size_small); + interval_misses = cache.GetIntervalSizeClassMisses( + kCpuId, kSmallClass, PerClassMissType::kCapacityTotal, + PerClassMissType::kCapacityResize); + // Given all objects are allocated, cpu cache will still try to grow the + // capacity on an underflow and record one miss. + EXPECT_EQ(interval_misses, 1); + + EXPECT_EQ(cache.Unallocated(kCpuId), 0); + EXPECT_EQ(cache.Allocated(kCpuId), max_cpu_cache_size); + EXPECT_EQ(cache.TotalObjectsOfClass(kSmallClass), batch_size_small); + + // Reclaim caches. + cache.Deactivate(); } // Runs a single allocate and deallocate operation to warm up the cache. Once a // few objects are allocated in the cold cache, we can shuffle cpu caches to // steal that capacity from the cold cache to the hot cache. -static void ColdCacheOperations(int cpu_id, size_t size_class) { +static void ColdCacheOperations(CpuCache& cache, int cpu_id, + size_t size_class) { // Temporarily fake being on the given CPU. ScopedFakeCpuId fake_cpu_id(cpu_id); - - CPUCache& cache = Static::cpu_cache(); -#if TCMALLOC_PERCPU_USE_RSEQ - if (subtle::percpu::UsingFlatVirtualCpus()) { - subtle::percpu::__rseq_abi.vcpu_id = cpu_id; - } -#endif - - void* ptr = cache.Allocate(size_class); + void* ptr = cache.Allocate(size_class); cache.Deallocate(ptr, size_class); } // Runs multiple allocate and deallocate operation on the cpu cache to collect // misses. Once we collect enough misses on this cache, we can shuffle cpu // caches to steal capacity from colder caches to the hot cache. -static void HotCacheOperations(int cpu_id) { +static void HotCacheOperations(CpuCache& cache, int cpu_id) { + constexpr size_t kPtrs = 4096; + std::vector ptrs; + ptrs.resize(kPtrs); + // Temporarily fake being on the given CPU. ScopedFakeCpuId fake_cpu_id(cpu_id); - CPUCache& cache = Static::cpu_cache(); -#if TCMALLOC_PERCPU_USE_RSEQ - if (subtle::percpu::UsingFlatVirtualCpus()) { - subtle::percpu::__rseq_abi.vcpu_id = cpu_id; - } -#endif - // Allocate and deallocate objects to make sure we have enough misses on the // cache. This will make sure we have sufficient disparity in misses between // the hotter and colder cache, and that we may be able to steal bytes from // the colder cache. - for (size_t cl = 1; cl <= kStressSlabs; ++cl) { - void* ptr = cache.Allocate(cl); - cache.Deallocate(ptr, cl); + for (size_t size_class = 1; size_class <= 2; ++size_class) { + for (auto& ptr : ptrs) { + ptr = cache.Allocate(size_class); + } + for (void* ptr : ptrs) { + cache.Deallocate(ptr, size_class); + } } // We reclaim the cache to reset it so that we record underflows/overflows the @@ -391,39 +1156,251 @@ static void HotCacheOperations(int cpu_id) { cache.Reclaim(cpu_id); } +// Test that we are complying with the threshold when we grow the slab. +// When wider slab is enabled, we check if overflow/underflow ratio is above the +// threshold for individual cpu caches. +TEST(CpuCacheTest, DynamicSlabThreshold) { + if (!subtle::percpu::IsFast()) { + return; + } + + constexpr double kDynamicSlabGrowThreshold = 0.9; + CpuCache cache; + TestStaticForwarder& forwarder = cache.forwarder(); + forwarder.dynamic_slab_enabled_ = true; + forwarder.dynamic_slab_grow_threshold_ = kDynamicSlabGrowThreshold; + SizeMap size_map; + size_map.Init(size_map.CurrentClasses().classes); + forwarder.size_map_ = size_map; + + cache.Activate(); + + constexpr int kCpuId0 = 0; + constexpr int kCpuId1 = 1; + + // Accumulate overflows and underflows for kCpuId0. + HotCacheOperations(cache, kCpuId0); + CpuCache::CpuCacheMissStats interval_misses = + cache.GetIntervalCacheMissStats(kCpuId0, MissCount::kSlabResize); + // Make sure that overflows/underflows ratio is greater than the threshold + // for kCpuId0 cache. + ASSERT_GT(interval_misses.overflows, + interval_misses.underflows * kDynamicSlabGrowThreshold); + + // Perform allocations on kCpuId1 so that we accumulate only underflows. + // Reclaim after each allocation such that we have no objects in the cache + // for the next allocation. + for (int i = 0; i < 1024; ++i) { + ColdCacheOperations(cache, kCpuId1, /*size_class=*/1); + cache.Reclaim(kCpuId1); + } + + // Total overflows/underflows ratio must be less than grow threshold now. + CpuCache::CpuCacheMissStats total_misses = + cache.GetIntervalCacheMissStats(kCpuId0, MissCount::kSlabResize); + total_misses += + cache.GetIntervalCacheMissStats(kCpuId1, MissCount::kSlabResize); + ASSERT_LT(total_misses.overflows, + total_misses.underflows * kDynamicSlabGrowThreshold); + + cpu_cache_internal::SlabShiftBounds shift_bounds = + cache.GetPerCpuSlabShiftBounds(); + const int shift = shift_bounds.initial_shift; + EXPECT_EQ(CpuCachePeer::GetSlabShift(cache), shift); + cache.ResizeSlabIfNeeded(); + + EXPECT_EQ(CpuCachePeer::GetSlabShift(cache), shift + 1); +} + +// Test that when dynamic slab parameters change, things still work. +TEST(CpuCacheTest, DynamicSlabParamsChange) { + if (!subtle::percpu::IsFast()) { + return; + } + int n_threads = NumCPUs(); +#ifdef UNDEFINED_BEHAVIOR_SANITIZER + // Prevent timeout issues by using fewer stress threads with UBSan. + n_threads = std::min(n_threads, 2); +#endif + + SizeMap size_map; + size_map.Init(size_map.CurrentClasses().classes); + for (bool initially_enabled : {false, true}) { + for (DynamicSlab initial_dynamic_slab : + {DynamicSlab::kGrow, DynamicSlab::kShrink, DynamicSlab::kNoop}) { + CpuCache cache; + TestStaticForwarder& forwarder = cache.forwarder(); + forwarder.dynamic_slab_enabled_ = initially_enabled; + forwarder.dynamic_slab_ = initial_dynamic_slab; + forwarder.size_map_ = size_map; + + cache.Activate(); + + std::vector threads; + std::atomic stop(false); + + for (size_t t = 0; t < n_threads; ++t) { + threads.push_back( + std::thread(StressThread, std::ref(cache), t, std::ref(stop))); + } + + for (bool enabled : {false, true}) { + for (DynamicSlab dynamic_slab : + {DynamicSlab::kGrow, DynamicSlab::kShrink, DynamicSlab::kNoop}) { + absl::SleepFor(absl::Milliseconds(100)); + forwarder.dynamic_slab_enabled_ = enabled; + forwarder.dynamic_slab_ = dynamic_slab; + cache.ResizeSlabIfNeeded(); + } + } + stop = true; + for (auto& t : threads) { + t.join(); + } + + cache.Deactivate(); + } + } +} + +// Test that old slabs are madvised-away during max capacity resize even when +// memory is mlocked. +TEST(CpuCacheTest, MaxCapacityResizeFailedBytesMlocked) { + if (!subtle::percpu::IsFast()) { + return; + } + int n_threads = NumCPUs(); +#ifdef UNDEFINED_BEHAVIOR_SANITIZER + // Prevent timeout issues by using fewer stress threads with UBSan. + n_threads = std::min(n_threads, 2); +#endif + + int ret = mlockall(MCL_CURRENT | MCL_FUTURE); + ASSERT_EQ(ret, 0); + + CpuCache cache; + TestStaticForwarder& forwarder = cache.forwarder(); + forwarder.dynamic_slab_enabled_ = true; + cache.Activate(); + + SizeMap size_map; + size_map.Init(size_map.CurrentClasses().classes); + forwarder.size_map_ = size_map; + + std::vector threads; + std::atomic stop(false); + + for (size_t t = 0; t < n_threads; ++t) { + threads.push_back( + std::thread(StressThread, std::ref(cache), t, std::ref(stop))); + } + + for (int i = 0; i < 10; ++i) { + absl::SleepFor(absl::Milliseconds(100)); + cache.ResizeSizeClassMaxCapacities(); + } + stop = true; + for (auto& t : threads) { + t.join(); + } + int failed_bytes = cache.GetDynamicSlabFailedBytes(); + EXPECT_EQ(failed_bytes, 0); + + ret = munlockall(); + ASSERT_EQ(ret, 0); + + cache.Deactivate(); +} + +// Test that old slabs are madvised-away during slab resize even when memory is +// mlocked. +TEST(CpuCacheTest, SlabResizeFailedBytesMlocked) { + if (!subtle::percpu::IsFast()) { + return; + } + int n_threads = NumCPUs(); +#ifdef UNDEFINED_BEHAVIOR_SANITIZER + // Prevent timeout issues by using fewer stress threads with UBSan. + n_threads = std::min(n_threads, 2); +#endif + + int ret = mlockall(MCL_CURRENT | MCL_FUTURE); + ASSERT_EQ(ret, 0); + + CpuCache cache; + TestStaticForwarder& forwarder = cache.forwarder(); + forwarder.dynamic_slab_enabled_ = true; + cache.Activate(); + + SizeMap size_map; + size_map.Init(size_map.CurrentClasses().classes); + forwarder.size_map_ = size_map; + + std::vector threads; + std::atomic stop(false); + + for (size_t t = 0; t < n_threads; ++t) { + threads.push_back( + std::thread(StressThread, std::ref(cache), t, std::ref(stop))); + } + + for (DynamicSlab dynamic_slab : + {DynamicSlab::kGrow, DynamicSlab::kShrink, DynamicSlab::kNoop}) { + absl::SleepFor(absl::Milliseconds(100)); + forwarder.dynamic_slab_ = dynamic_slab; + cache.ResizeSlabIfNeeded(); + } + stop = true; + for (auto& t : threads) { + t.join(); + } + int failed_bytes = cache.GetDynamicSlabFailedBytes(); + EXPECT_EQ(failed_bytes, 0); + + ret = munlockall(); + ASSERT_EQ(ret, 0); + + cache.Deactivate(); +} + +TEST(CpuCacheTest, SlabUsage) { + // Note: we can't do ValidateSlabBytes on the test-cpu-cache because in that + // case, the slab only uses size classes 1 and 2. + CpuCachePeer::ValidateSlabBytes(tc_globals.cpu_cache()); +} + TEST(CpuCacheTest, ColdHotCacheShuffleTest) { if (!subtle::percpu::IsFast()) { return; } - CPUCache& cache = Static::cpu_cache(); - // Since this test allocates memory, avoid activating the real fast path to - // minimize allocations against the per-CPU cache. - cache.Activate(CPUCache::ActivationMode::FastPathOffTestOnly); + CpuCache cache; + // Reduce cache capacity so that it will see need in stealing and rebalancing. + const size_t max_cpu_cache_size = 1 << 10; + cache.SetCacheLimit(max_cpu_cache_size); + cache.Activate(); constexpr int hot_cpu_id = 0; constexpr int cold_cpu_id = 1; - const size_t max_cpu_cache_size = Parameters::max_per_cpu_cache_size(); - // Empirical tests suggest that we should be able to steal all the steal-able // capacity from colder cache in < 100 tries. Keeping enough buffer here to // make sure we steal from colder cache, while at the same time avoid timeouts // if something goes bad. constexpr int kMaxStealTries = 1000; - // We allocate and deallocate a single highest cl object. + // We allocate and deallocate a single highest size_class object. // This makes sure that we have a single large object in the cache that faster // cache can steal. - const size_t size_class = kNumClasses - 1; + const size_t size_class = 2; for (int num_tries = 0; num_tries < kMaxStealTries && cache.Capacity(cold_cpu_id) > - CPUCache::kCacheCapacityThreshold * max_cpu_cache_size; + CpuCache::kCacheCapacityThreshold * max_cpu_cache_size; ++num_tries) { - ColdCacheOperations(cold_cpu_id, size_class); - HotCacheOperations(hot_cpu_id); + ColdCacheOperations(cache, cold_cpu_id, size_class); + HotCacheOperations(cache, hot_cpu_id); cache.ShuffleCpuCaches(); // Check that the capacity is preserved. @@ -439,9 +1416,10 @@ TEST(CpuCacheTest, ColdHotCacheShuffleTest) { // Check that we drained cold cache to the lower capacity limit. // We also keep some tolerance, up to the largest class size, below the lower // capacity threshold that we can drain cold cache to. + EXPECT_LT(cold_cache_capacity, max_cpu_cache_size); EXPECT_GT(cold_cache_capacity, - CPUCache::kCacheCapacityThreshold * max_cpu_cache_size - - Static::sizemap().class_to_size(kNumClasses - 1)); + CpuCache::kCacheCapacityThreshold * max_cpu_cache_size - + cache.forwarder().class_to_size(size_class)); // Check that we have at least stolen some capacity. EXPECT_GT(hot_cache_capacity, max_cpu_cache_size); @@ -450,8 +1428,8 @@ TEST(CpuCacheTest, ColdHotCacheShuffleTest) { // has been reached for the cold cache. A few more shuffles should not // change the capacity of either of the caches. for (int i = 0; i < 100; ++i) { - ColdCacheOperations(cold_cpu_id, size_class); - HotCacheOperations(hot_cpu_id); + ColdCacheOperations(cache, cold_cpu_id, size_class); + HotCacheOperations(cache, hot_cpu_id); cache.ShuffleCpuCaches(); // Check that the capacity is preserved. @@ -462,7 +1440,8 @@ TEST(CpuCacheTest, ColdHotCacheShuffleTest) { } // Check that the capacity of cold and hot caches is same as before. - EXPECT_EQ(cache.Capacity(cold_cpu_id), cold_cache_capacity); + EXPECT_EQ(cache.Capacity(cold_cpu_id), cold_cache_capacity) + << CpuCache::kCacheCapacityThreshold * max_cpu_cache_size; EXPECT_EQ(cache.Capacity(hot_cpu_id), hot_cache_capacity); // Make sure that the total capacity is preserved. @@ -470,10 +1449,7 @@ TEST(CpuCacheTest, ColdHotCacheShuffleTest) { 2 * max_cpu_cache_size); // Reclaim caches. - const int num_cpus = absl::base_internal::NumCPUs(); - for (int cpu = 0; cpu < num_cpus; ++cpu) { - cache.Reclaim(cpu); - } + cache.Deactivate(); } TEST(CpuCacheTest, ReclaimCpuCache) { @@ -481,18 +1457,16 @@ TEST(CpuCacheTest, ReclaimCpuCache) { return; } - CPUCache& cache = Static::cpu_cache(); - // Since this test allocates memory, avoid activating the real fast path to - // minimize allocations against the per-CPU cache. - cache.Activate(CPUCache::ActivationMode::FastPathOffTestOnly); + CpuCache cache; + cache.Activate(); // The number of underflows and overflows must be zero for all the caches. - const int num_cpus = absl::base_internal::NumCPUs(); + const int num_cpus = NumCPUs(); for (int cpu = 0; cpu < num_cpus; ++cpu) { SCOPED_TRACE(absl::StrFormat("Failed CPU: %d", cpu)); // Check that reclaim miss metrics are reset. - CPUCache::CpuCacheMissStats reclaim_misses = - cache.GetReclaimCacheMissStats(cpu); + CpuCache::CpuCacheMissStats reclaim_misses = + cache.GetAndUpdateIntervalCacheMissStats(cpu, MissCount::kReclaim); EXPECT_EQ(reclaim_misses.underflows, 0); EXPECT_EQ(reclaim_misses.overflows, 0); @@ -504,25 +1478,26 @@ TEST(CpuCacheTest, ReclaimCpuCache) { EXPECT_EQ(used_bytes, 0); } - const size_t kSizeClass = 3; + const size_t kSizeClass = 2; // We chose a different size class here so that we can populate different size // class slots and change the number of bytes used by the busy cache later in // our test. - const size_t kBusySizeClass = 4; + const size_t kBusySizeClass = 1; + ASSERT_NE(kSizeClass, kBusySizeClass); // Perform some operations to warm up caches and make sure they are populated. for (int cpu = 0; cpu < num_cpus; ++cpu) { SCOPED_TRACE(absl::StrFormat("Failed CPU: %d", cpu)); - ColdCacheOperations(cpu, kSizeClass); + ColdCacheOperations(cache, cpu, kSizeClass); EXPECT_TRUE(cache.HasPopulated(cpu)); } for (int cpu = 0; cpu < num_cpus; ++cpu) { SCOPED_TRACE(absl::StrFormat("Failed CPU: %d", cpu)); - CPUCache::CpuCacheMissStats misses_last_interval = - cache.GetReclaimCacheMissStats(cpu); - CPUCache::CpuCacheMissStats total_misses = + CpuCache::CpuCacheMissStats misses_last_interval = + cache.GetAndUpdateIntervalCacheMissStats(cpu, MissCount::kReclaim); + CpuCache::CpuCacheMissStats total_misses = cache.GetTotalCacheMissStats(cpu); // Misses since the last reclaim (i.e. since we initialized the caches) @@ -543,8 +1518,8 @@ TEST(CpuCacheTest, ReclaimCpuCache) { // As no cache operations were performed since the last reclaim // operation, the reclaim misses captured during the last interval (i.e. // since the last reclaim) should be zero. - CPUCache::CpuCacheMissStats reclaim_misses = - cache.GetReclaimCacheMissStats(cpu); + CpuCache::CpuCacheMissStats reclaim_misses = + cache.GetAndUpdateIntervalCacheMissStats(cpu, MissCount::kReclaim); EXPECT_EQ(reclaim_misses.underflows, 0); EXPECT_EQ(reclaim_misses.overflows, 0); @@ -557,10 +1532,9 @@ TEST(CpuCacheTest, ReclaimCpuCache) { } absl::BitGen rnd; - const int busy_cpu = - absl::Uniform(rnd, 0, absl::base_internal::NumCPUs()); + const int busy_cpu = absl::Uniform(rnd, 0, NumCPUs()); const size_t prev_used = cache.UsedBytes(busy_cpu); - ColdCacheOperations(busy_cpu, kBusySizeClass); + ColdCacheOperations(cache, busy_cpu, kBusySizeClass); EXPECT_GT(cache.UsedBytes(busy_cpu), prev_used); // Try reclaiming caches again. @@ -592,6 +1566,382 @@ TEST(CpuCacheTest, ReclaimCpuCache) { EXPECT_EQ(cache.UsedBytes(cpu), 0); EXPECT_EQ(cache.GetNumReclaims(cpu), 1); } + + cache.Deactivate(); +} + +TEST(CpuCacheTest, SizeClassCapacityTest) { + if (!subtle::percpu::IsFast()) { + return; + } + + CpuCache cache; + cache.Activate(); + + const int num_cpus = NumCPUs(); + constexpr size_t kSizeClass = 2; + const size_t batch_size = cache.forwarder().num_objects_to_move(kSizeClass); + + // Perform some operations to warm up caches and make sure they are populated. + for (int cpu = 0; cpu < num_cpus; ++cpu) { + SCOPED_TRACE(absl::StrFormat("Failed CPU: %d", cpu)); + ColdCacheOperations(cache, cpu, kSizeClass); + EXPECT_TRUE(cache.HasPopulated(cpu)); + } + + for (int size_class = 1; size_class < kNumClasses; ++size_class) { + SCOPED_TRACE(absl::StrFormat("Failed size_class: %d", size_class)); + CpuCache::SizeClassCapacityStats capacity_stats = + cache.GetSizeClassCapacityStats(size_class); + if (size_class == kSizeClass) { + // As all the caches are populated and each cache stores batch_size number + // of kSizeClass objects, all the stats below should be equal to + // batch_size. + EXPECT_EQ(capacity_stats.min_capacity, batch_size); + EXPECT_DOUBLE_EQ(capacity_stats.avg_capacity, batch_size); + EXPECT_EQ(capacity_stats.max_capacity, batch_size); + } else { + // Capacity stats for other size classes should be zero. + EXPECT_EQ(capacity_stats.min_capacity, 0); + EXPECT_DOUBLE_EQ(capacity_stats.avg_capacity, 0); + EXPECT_EQ(capacity_stats.max_capacity, 0); + } + } + + // Next, we reclaim per-cpu caches, one at a time, to drain all the kSizeClass + // objects cached by them. As we progressively reclaim per-cpu caches, the + // capacity for kSizeClass averaged over all CPUs should also drop linearly. + // We reclaim all but one per-cpu caches (we reclaim last per-cpu cache + // outside the loop so that we can check for max_capacity=0 separately). + for (int cpu = 0; cpu < num_cpus - 1; ++cpu) { + SCOPED_TRACE(absl::StrFormat("Failed CPU: %d", cpu)); + cache.Reclaim(cpu); + + CpuCache::SizeClassCapacityStats capacity_stats = + cache.GetSizeClassCapacityStats(kSizeClass); + // Reclaiming even one per-cpu cache should set min_capacity to zero. + EXPECT_EQ(capacity_stats.min_capacity, 0); + + // (cpu+1) number of caches have been reclaimed. So, (num_cpus-cpu-1) number + // of caches are currently populated, with each cache storing batch_size + // number of kSizeClass objects. + double expected_avg = + static_cast(batch_size * (num_cpus - cpu - 1)) / num_cpus; + EXPECT_DOUBLE_EQ(capacity_stats.avg_capacity, expected_avg); + + // At least one per-cpu cache exists that caches batch_size number of + // kSizeClass objects. + EXPECT_EQ(capacity_stats.max_capacity, batch_size); + } + + // We finally reclaim last per-cpu cache. All the reported capacity stats + // should drop to zero as none of the caches hold any objects. + cache.Reclaim(num_cpus - 1); + CpuCache::SizeClassCapacityStats capacity_stats = + cache.GetSizeClassCapacityStats(kSizeClass); + EXPECT_EQ(capacity_stats.min_capacity, 0); + EXPECT_DOUBLE_EQ(capacity_stats.avg_capacity, 0); + EXPECT_EQ(capacity_stats.max_capacity, 0); + + cache.Deactivate(); +} + +class CpuCacheEnvironment { + public: + CpuCacheEnvironment() : num_cpus_(NumCPUs()) {} + ~CpuCacheEnvironment() { cache_.Deactivate(); } + + void Activate() { + cache_.Activate(); + ready_.store(true, std::memory_order_release); + } + + void RandomlyPoke(absl::BitGenRef rng) { + // We run a random operation based on our random number generated. + const int coin = absl::Uniform(rng, 0, 18); + const bool ready = ready_.load(std::memory_order_acquire); + + // Pick a random CPU and size class. We will likely need one or both. + const int cpu = absl::Uniform(rng, 0, num_cpus_); + const int size_class = absl::Uniform(rng, 1, 3); + + if (!ready || coin < 1) { + benchmark::DoNotOptimize(cache_.CacheLimit()); + return; + } + + // Methods beyond this point require the CpuCache to be activated. + + switch (coin) { + case 1: { + // Allocate, Deallocate + void* ptr = cache_.Allocate(size_class); + EXPECT_NE(ptr, nullptr); + // Touch *ptr to allow sanitizers to see an access (and a potential + // race, if synchronization is insufficient). + *static_cast(ptr) = 1; + benchmark::DoNotOptimize(*static_cast(ptr)); + + cache_.Deallocate(ptr, size_class); + break; + } + case 2: + benchmark::DoNotOptimize(cache_.TotalUsedBytes()); + break; + case 3: + benchmark::DoNotOptimize(cache_.UsedBytes(cpu)); + break; + case 4: + benchmark::DoNotOptimize(cache_.Allocated(cpu)); + break; + case 5: + benchmark::DoNotOptimize(cache_.HasPopulated(cpu)); + break; + case 6: { + auto metadata = cache_.MetadataMemoryUsage(); + EXPECT_GE(metadata.virtual_size, metadata.resident_size); + EXPECT_GT(metadata.virtual_size, 0); + break; + } + case 7: + benchmark::DoNotOptimize(cache_.TotalObjectsOfClass(size_class)); + break; + case 8: + benchmark::DoNotOptimize(cache_.Unallocated(cpu)); + break; + case 9: + benchmark::DoNotOptimize(cache_.Capacity(cpu)); + break; + case 10: { + absl::MutexLock lock(&background_mutex_); + cache_.ShuffleCpuCaches(); + break; + } + case 11: { + absl::MutexLock lock(&background_mutex_); + cache_.TryReclaimingCaches(); + break; + } + case 12: { + absl::MutexLock lock(&background_mutex_); + cache_.Reclaim(cpu); + break; + } + case 13: + benchmark::DoNotOptimize(cache_.GetNumReclaims(cpu)); + break; + case 14: { + const auto total_misses = cache_.GetTotalCacheMissStats(cpu); + const auto reclaim_misses = + cache_.GetAndUpdateIntervalCacheMissStats(cpu, MissCount::kReclaim); + const auto shuffle_misses = + cache_.GetIntervalCacheMissStats(cpu, MissCount::kShuffle); + + benchmark::DoNotOptimize(total_misses); + benchmark::DoNotOptimize(reclaim_misses); + benchmark::DoNotOptimize(shuffle_misses); + break; + } + case 15: { + const auto stats = cache_.GetSizeClassCapacityStats(size_class); + EXPECT_GE(stats.max_capacity, stats.avg_capacity); + EXPECT_GE(stats.avg_capacity, stats.min_capacity); + break; + } + case 16: { + std::string out; + out.resize(128 << 10); + ANNOTATE_MEMORY_IS_UNINITIALIZED(out.data(), out.size()); + Printer p(out.data(), out.size()); + PbtxtRegion r(p, kTop); + + cache_.PrintInPbtxt(r); + + benchmark::DoNotOptimize(out.data()); + break; + } + case 17: { + std::string out; + out.resize(128 << 10); + ANNOTATE_MEMORY_IS_UNINITIALIZED(out.data(), out.size()); + Printer p(out.data(), out.size()); + + cache_.Print(p); + + benchmark::DoNotOptimize(out.data()); + break; + } + default: + GTEST_FAIL() << "Unexpected value " << coin; + break; + } + } + + CpuCache& cache() { return cache_; } + + int num_cpus() const { return num_cpus_; } + + private: + const int num_cpus_; + CpuCache cache_; + // Protects operations executed on the background thread in real life. + absl::Mutex background_mutex_; + std::atomic ready_{false}; +}; + +TEST(CpuCacheTest, Fuzz) { + if (!subtle::percpu::IsFast()) { + return; + } + + const int kThreads = 10; + struct ABSL_CACHELINE_ALIGNED ThreadState { + absl::BitGen rng; + }; + std::vector thread_state(kThreads); + + CpuCacheEnvironment env; + ThreadManager threads; + threads.Start(10, [&](int thread_id) { + // Ensure this thread has registered itself with the kernel to use + // restartable sequences. + ASSERT_TRUE(subtle::percpu::IsFast()); + env.RandomlyPoke(thread_state[thread_id].rng); + }); + + absl::SleepFor(absl::Seconds(0.1)); + env.Activate(); + absl::SleepFor(absl::Seconds(0.3)); + + threads.Stop(); + + // Inspect the CpuCache and validate invariants. + + // The number of caches * per-core limit should be equivalent to the bytes + // managed by the cache. + size_t capacity = 0; + size_t allocated = 0; + size_t unallocated = 0; + for (int i = 0, n = env.num_cpus(); i < n; i++) { + capacity += env.cache().Capacity(i); + allocated += env.cache().Allocated(i); + unallocated += env.cache().Unallocated(i); + } + + EXPECT_EQ(allocated + unallocated, capacity); + EXPECT_EQ(env.num_cpus() * env.cache().CacheLimit(), capacity); + + // Log mallocz content for manual inspection. + std::string mallocz; + mallocz.resize(128 << 10); + Printer p(mallocz.data(), mallocz.size()); + env.cache().Print(p); + std::cout << mallocz; +} + +// TODO(b/179516472): Enable this test. +TEST(CpuCacheTest, DISABLED_ChangingSizes) { + if (!subtle::percpu::IsFast()) { + return; + } + + constexpr int kThreads = 10; + struct ABSL_CACHELINE_ALIGNED ThreadState { + absl::BitGen rng; + }; + std::vector thread_state(kThreads); + + CpuCacheEnvironment env; + ThreadManager threads; + const size_t initial_size = env.cache().CacheLimit(); + ASSERT_GT(initial_size, 0); + bool rseq_active_for_size_changing_thread = false; + int index = 0; + size_t last_cache_size = initial_size; + + env.Activate(); + + threads.Start(kThreads, [&](int thread_id) { + // Ensure this thread has registered itself with the kernel to use + // restartable sequences. + if (thread_id > 0) { + ASSERT_TRUE(subtle::percpu::IsFast()); + env.RandomlyPoke(thread_state[thread_id].rng); + return; + } + + // Alternative between having the thread register for rseq and not, to + // ensure that we can call SetCacheLimit with either precondition. + std::optional rseq; + if (rseq_active_for_size_changing_thread) { + ASSERT_TRUE(subtle::percpu::IsFast()); + } else { + rseq.emplace(); + } + rseq_active_for_size_changing_thread = + !rseq_active_for_size_changing_thread; + + // Vary the cache size up and down. Exclude 1. from the list so that we + // will always expect to see a nontrivial change after the threads stop + // work. + constexpr double kConversions[] = {0.25, 0.5, 0.75, 1.25, 1.5}; + size_t new_cache_size = initial_size * kConversions[index]; + index = (index + 1) % 5; + + env.cache().SetCacheLimit(new_cache_size); + last_cache_size = new_cache_size; + }); + + absl::SleepFor(absl::Seconds(0.5)); + + threads.Stop(); + + // Inspect the CpuCache and validate invariants. + + // The number of caches * per-core limit should be equivalent to the bytes + // managed by the cache. + size_t capacity = 0; + size_t allocated = 0; + size_t unallocated = 0; + for (int i = 0, n = env.num_cpus(); i < n; i++) { + capacity += env.cache().Capacity(i); + allocated += env.cache().Allocated(i); + unallocated += env.cache().Unallocated(i); + } + + EXPECT_EQ(allocated + unallocated, capacity); + EXPECT_EQ(env.num_cpus() * last_cache_size, capacity); +} + +TEST(CpuCacheTest, TargetOverflowRefillCount) { + auto F = cpu_cache_internal::TargetOverflowRefillCount; + // Args are: capacity, batch_length, successive. + EXPECT_EQ(F(0, 8, 0), 1); + EXPECT_EQ(F(0, 8, 10), 1); + EXPECT_EQ(F(1, 8, 0), 1); + EXPECT_EQ(F(1, 8, 1), 1); + EXPECT_EQ(F(1, 8, 2), 1); + EXPECT_EQ(F(1, 8, 3), 2); + EXPECT_EQ(F(1, 8, 4), 2); + EXPECT_EQ(F(2, 8, 0), 2); + EXPECT_EQ(F(3, 8, 0), 3); + EXPECT_EQ(F(4, 8, 0), 3); + EXPECT_EQ(F(5, 8, 0), 4); + EXPECT_EQ(F(6, 8, 0), 4); + EXPECT_EQ(F(7, 8, 0), 5); + EXPECT_EQ(F(8, 8, 0), 5); + EXPECT_EQ(F(9, 8, 0), 6); + EXPECT_EQ(F(100, 8, 0), 8); + EXPECT_EQ(F(23, 8, 1), 13); + EXPECT_EQ(F(24, 8, 1), 13); + EXPECT_EQ(F(100, 8, 1), 16); + EXPECT_EQ(F(24, 8, 2), 13); + EXPECT_EQ(F(32, 8, 2), 17); + EXPECT_EQ(F(40, 8, 2), 21); + EXPECT_EQ(F(100, 8, 2), 32); + EXPECT_EQ(F(48, 8, 3), 25); + EXPECT_EQ(F(56, 8, 3), 29); + EXPECT_EQ(F(100, 8, 3), 51); } } // namespace diff --git a/contrib/libs/tcmalloc/tcmalloc/deallocation_profiler.cc b/contrib/libs/tcmalloc/tcmalloc/deallocation_profiler.cc new file mode 100644 index 000000000000..60539c4713f0 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/deallocation_profiler.cc @@ -0,0 +1,760 @@ +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/deallocation_profiler.h" + +#include +#include // for std::lround +#include +#include // for uintptr_t +#include +#include +#include +#include +#include +#include +#include + +#include "absl/base/attributes.h" +#include "absl/base/const_init.h" +#include "absl/base/internal/low_level_alloc.h" +#include "absl/base/internal/spinlock.h" +#include "absl/base/internal/sysinfo.h" +#include "absl/base/macros.h" +#include "absl/container/flat_hash_map.h" +#include "absl/debugging/stacktrace.h" // for GetStackTrace +#include "absl/functional/function_ref.h" +#include "absl/hash/hash.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "tcmalloc/internal/allocation_guard.h" +#include "tcmalloc/internal/cache_topology.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/percpu.h" +#include "tcmalloc/internal/sampled_allocation.h" +#include "tcmalloc/internal_malloc_extension.h" +#include "tcmalloc/malloc_extension.h" +#include "tcmalloc/static_vars.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace deallocationz { +namespace { +using ::absl::base_internal::SpinLock; +using tcmalloc_internal::AllocationGuardSpinLockHolder; + +// STL adaptor for an arena based allocator which provides the following: +// static void* Alloc::Allocate(size_t size); +// static void Alloc::Free(void* ptr, size_t size); +template +class AllocAdaptor final { + public: + using value_type = T; + + AllocAdaptor() {} + AllocAdaptor(const AllocAdaptor&) {} + + template + using rebind = AllocAdaptor; + + template + explicit AllocAdaptor(const AllocAdaptor&) {} + + T* allocate(size_t n) { + // Check if n is too big to allocate. + TC_ASSERT_EQ((n * sizeof(T)) / sizeof(T), n); + return static_cast(Alloc::Allocate(n * sizeof(T))); + } + void deallocate(T* p, size_t n) { Alloc::Free(p, n * sizeof(T)); } +}; + +const int64_t kMaxStackDepth = 64; + +// Stores stack traces and metadata for any allocation or deallocation +// encountered by the profiler. +struct DeallocationSampleRecord { + double weight = 0.0; + size_t requested_size = 0; + size_t requested_alignment = 0; + size_t allocated_size = 0; // size after sizeclass/page rounding + + int depth = 0; // Number of PC values stored in array below + void* stack[kMaxStackDepth]; + + // creation_time is used to capture the life_time of sampled allocations + absl::Time creation_time; + int cpu_id = -1; + int vcpu_id = -1; + int l3_id = -1; + int numa_id = -1; + pid_t thread_id = 0; + + template + friend H AbslHashValue(H h, const DeallocationSampleRecord& c) { + return H::combine(H::combine_contiguous(std::move(h), c.stack, c.depth), + c.depth, c.requested_size, c.requested_alignment, + c.allocated_size); + } + + bool operator==(const DeallocationSampleRecord& other) const { + if (depth != other.depth || requested_size != other.requested_size || + requested_alignment != other.requested_alignment || + allocated_size != other.allocated_size) { + return false; + } + return std::equal(stack, stack + depth, other.stack); + } +}; + +// Tracks whether an object was allocated/deallocated by the same CPU/thread. +struct CpuThreadMatchingStatus { + constexpr CpuThreadMatchingStatus(bool physical_cpu_matched, + bool virtual_cpu_matched, bool l3_matched, + bool numa_matched, bool thread_matched) + : physical_cpu_matched(physical_cpu_matched), + virtual_cpu_matched(virtual_cpu_matched), + l3_matched(l3_matched), + numa_matched(numa_matched), + thread_matched(thread_matched), + value((static_cast(physical_cpu_matched) << 4) | + (static_cast(virtual_cpu_matched) << 3) | + (static_cast(l3_matched) << 2) | + (static_cast(numa_matched) << 1) | + static_cast(thread_matched)) {} + bool physical_cpu_matched; + bool virtual_cpu_matched; + bool l3_matched; + bool numa_matched; + bool thread_matched; + int value; +}; + +struct RpcMatchingStatus { + static constexpr int ComputeValue(uint64_t alloc, uint64_t dealloc) { + if (alloc != 0 && dealloc != 0) { + return static_cast(alloc == dealloc); + } else { + return 2; + } + } + + constexpr RpcMatchingStatus(uint64_t alloc, uint64_t dealloc) + : value(ComputeValue(alloc, dealloc)) {} + + int value; +}; + +int ComputeIndex(CpuThreadMatchingStatus status, RpcMatchingStatus rpc_status) { + return status.value * 3 + rpc_status.value; +} + +int GetL3Id(int cpu_id) { + return cpu_id >= 0 + ? tcmalloc_internal::CacheTopology::Instance().GetL3FromCpuId( + cpu_id) + : -1; +} + +int GetNumaId(int cpu_id) { + return cpu_id >= 0 + ? tcmalloc_internal::tc_globals.numa_topology().GetCpuPartition( + cpu_id) + : -1; +} + +constexpr std::pair kAllCases[] = { + // clang-format off + {CpuThreadMatchingStatus(false, false, false, false, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(false, false, false, false, true), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(false, false, false, true, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(false, false, false, true, true), RpcMatchingStatus(0, 0)}, + + {CpuThreadMatchingStatus(false, false, false, false, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(false, false, false, false, true), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(false, false, false, true, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(false, false, false, true, true), RpcMatchingStatus(1, 2)}, + + {CpuThreadMatchingStatus(false, false, false, false, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(false, false, false, false, true), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(false, false, false, true, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(false, false, false, true, true), RpcMatchingStatus(1, 1)}, + + {CpuThreadMatchingStatus(false, false, true, false, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(false, false, true, false, true), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(false, false, true, true, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(false, false, true, true, true), RpcMatchingStatus(0, 0)}, + + {CpuThreadMatchingStatus(false, false, true, false, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(false, false, true, false, true), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(false, false, true, true, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(false, false, true, true, true), RpcMatchingStatus(1, 2)}, + + {CpuThreadMatchingStatus(false, false, true, false, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(false, false, true, false, true), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(false, false, true, true, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(false, false, true, true, true), RpcMatchingStatus(1, 1)}, + + {CpuThreadMatchingStatus(false, true, false, false, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(false, true, false, false, true), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(false, true, false, true, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(false, true, false, true, true), RpcMatchingStatus(0, 0)}, + + {CpuThreadMatchingStatus(false, true, false, false, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(false, true, false, false, true), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(false, true, false, true, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(false, true, false, true, true), RpcMatchingStatus(1, 2)}, + + {CpuThreadMatchingStatus(false, true, false, false, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(false, true, false, false, true), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(false, true, false, true, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(false, true, false, true, true), RpcMatchingStatus(1, 1)}, + + {CpuThreadMatchingStatus(false, true, true, false, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(false, true, true, false, true), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(false, true, true, true, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(false, true, true, true, true), RpcMatchingStatus(0, 0)}, + + {CpuThreadMatchingStatus(false, true, true, false, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(false, true, true, false, true), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(false, true, true, true, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(false, true, true, true, true), RpcMatchingStatus(1, 2)}, + + {CpuThreadMatchingStatus(false, true, true, false, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(false, true, true, false, true), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(false, true, true, true, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(false, true, true, true, true), RpcMatchingStatus(1, 1)}, + + {CpuThreadMatchingStatus(true, false, false, false, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(true, false, false, false, true), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(true, false, false, true, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(true, false, false, true, true), RpcMatchingStatus(0, 0)}, + + {CpuThreadMatchingStatus(true, false, false, false, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(true, false, false, false, true), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(true, false, false, true, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(true, false, false, true, true), RpcMatchingStatus(1, 2)}, + + {CpuThreadMatchingStatus(true, false, false, false, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(true, false, false, false, true), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(true, false, false, true, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(true, false, false, true, true), RpcMatchingStatus(1, 1)}, + + {CpuThreadMatchingStatus(true, false, true, false, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(true, false, true, false, true), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(true, false, true, true, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(true, false, true, true, true), RpcMatchingStatus(0, 0)}, + + {CpuThreadMatchingStatus(true, false, true, false, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(true, false, true, false, true), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(true, false, true, true, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(true, false, true, true, true), RpcMatchingStatus(1, 2)}, + + {CpuThreadMatchingStatus(true, false, true, false, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(true, false, true, false, true), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(true, false, true, true, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(true, false, true, true, true), RpcMatchingStatus(1, 1)}, + + {CpuThreadMatchingStatus(true, true, false, false, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(true, true, false, false, true), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(true, true, false, true, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(true, true, false, true, true), RpcMatchingStatus(0, 0)}, + + {CpuThreadMatchingStatus(true, true, false, false, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(true, true, false, false, true), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(true, true, false, true, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(true, true, false, true, true), RpcMatchingStatus(1, 2)}, + + {CpuThreadMatchingStatus(true, true, false, false, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(true, true, false, false, true), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(true, true, false, true, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(true, true, false, true, true), RpcMatchingStatus(1, 1)}, + + {CpuThreadMatchingStatus(true, true, true, false, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(true, true, true, false, true), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(true, true, true, true, false), RpcMatchingStatus(0, 0)}, + {CpuThreadMatchingStatus(true, true, true, true, true), RpcMatchingStatus(0, 0)}, + + {CpuThreadMatchingStatus(true, true, true, false, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(true, true, true, false, true), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(true, true, true, true, false), RpcMatchingStatus(1, 2)}, + {CpuThreadMatchingStatus(true, true, true, true, true), RpcMatchingStatus(1, 2)}, + + {CpuThreadMatchingStatus(true, true, true, false, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(true, true, true, false, true), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(true, true, true, true, false), RpcMatchingStatus(1, 1)}, + {CpuThreadMatchingStatus(true, true, true, true, true), RpcMatchingStatus(1, 1)}, + // clang-format on +}; +} // namespace + +class DeallocationProfiler { + private: + // Arena and allocator used to back STL objects used by DeallocationProfiler + // Shared between all instances of DeallocationProfiler + // TODO(b/248332543): Use TCMalloc's own arena allocator instead of defining a + // new one here. The need for refcount management could be the reason for + // using a custom allocator in the first place. + class MyAllocator { + public: + static void* Allocate(size_t n) { + return absl::base_internal::LowLevelAlloc::AllocWithArena(n, arena_); + } + static void Free(const void* p, size_t /* n */) { + absl::base_internal::LowLevelAlloc::Free(const_cast(p)); + } + + // The lifetime of the arena is managed using a reference count and + // determined by how long at least one emitted Profile remains alive. + struct LowLevelArenaReference { + LowLevelArenaReference() { + AllocationGuardSpinLockHolder h(&arena_lock_); + if ((refcount_++) == 0) { + TC_CHECK_EQ(arena_, nullptr); + arena_ = absl::base_internal::LowLevelAlloc::NewArena(0); + } + } + + ~LowLevelArenaReference() { + AllocationGuardSpinLockHolder h(&arena_lock_); + if ((--refcount_) == 0) { + TC_CHECK(absl::base_internal::LowLevelAlloc::DeleteArena(arena_)); + arena_ = nullptr; + } + } + }; + + private: + // We need to protect the arena with a mutex and ensure that every thread + // acquires that mutex before it uses the arena for the first time. Once + // it has acquired the mutex, it is guaranteed that arena won't change + // between that point in time and when the thread stops accessing it (as + // enforced by LowLevelArenaReference below). + ABSL_CONST_INIT static SpinLock arena_lock_; + static absl::base_internal::LowLevelAlloc::Arena* arena_; + + // We assume that launching a new deallocation profiler takes too long + // to cause this to overflow within the sampling period. The reason this + // is not using std::shared_ptr is that we do not only need to protect the + // value of the reference count but also the pointer itself (and therefore + // need a separate mutex either way). + static uint32_t refcount_; + }; + + // This must be the first member of the class to be initialized. The + // underlying arena must stay alive as long as the profiler. + MyAllocator::LowLevelArenaReference arena_ref_; + + // All active profilers are stored in a list. + DeallocationProfiler* next_; + DeallocationProfilerList* list_ = nullptr; + friend class DeallocationProfilerList; + + using AllocsTable = absl::flat_hash_map< + tcmalloc_internal::AllocHandle, DeallocationSampleRecord, + absl::Hash, + std::equal_to, + AllocAdaptor, + MyAllocator>>; + + class DeallocationStackTraceTable final + : public tcmalloc_internal::ProfileBase { + public: + // We define the dtor to ensure it is placed in the desired text section. + ~DeallocationStackTraceTable() override = default; + void AddTrace(const DeallocationSampleRecord& alloc_trace, + const DeallocationSampleRecord& dealloc_trace); + + void Iterate( + absl::FunctionRef func) const override; + + ProfileType Type() const override { + return tcmalloc::ProfileType::kLifetimes; + } + + std::optional StartTime() const override { return start_time_; } + + absl::Duration Duration() const override { + return stop_time_ - start_time_; + } + + void StopAndRecord(const AllocsTable& allocs); + + private: + // This must be the first member of the class to be initialized. The + // underlying arena must stay alive as long as the profile. + MyAllocator::LowLevelArenaReference arena_ref_; + + static constexpr int kNumCases = ABSL_ARRAYSIZE(kAllCases); + + struct Key { + DeallocationSampleRecord alloc; + DeallocationSampleRecord dealloc; + + Key(const DeallocationSampleRecord& alloc, + const DeallocationSampleRecord& dealloc) + : alloc(alloc), dealloc(dealloc) {} + + template + friend H AbslHashValue(H h, const Key& c) { + return H::combine(std::move(h), c.alloc, c.dealloc); + } + + bool operator==(const Key& other) const { + return (alloc == other.alloc) && (dealloc == other.dealloc); + } + }; + + struct Value { + // for each possible cases, we collect repetition count and avg lifetime + // we also collect the minimum and maximum lifetimes, as well as the sum + // of squares (to calculate the standard deviation). + double counts[kNumCases] = {0.0}; + double mean_life_times_ns[kNumCases] = {0.0}; + double variance_life_times_ns[kNumCases] = {0.0}; + double min_life_times_ns[kNumCases] = {0.0}; + double max_life_times_ns[kNumCases] = {0.0}; + + Value() { + std::fill_n(min_life_times_ns, kNumCases, + std::numeric_limits::max()); + } + }; + + absl::flat_hash_map, std::equal_to, + AllocAdaptor, MyAllocator>> + table_; + + absl::Time start_time_ = absl::Now(); + absl::Time stop_time_; + }; + + // Keep track of allocations that are in flight + AllocsTable allocs_; + + // Table to store lifetime information collected by this profiler + std::unique_ptr reports_ = nullptr; + + public: + explicit DeallocationProfiler(DeallocationProfilerList* list) : list_(list) { + reports_ = std::make_unique(); + list_->Add(this); + } + + ~DeallocationProfiler() { + if (reports_ != nullptr) { + Stop(); + } + } + + const tcmalloc::Profile Stop() { + if (reports_ != nullptr) { + // We first remove the profiler from the list to avoid racing with + // potential allocations which may modify the allocs_ table. + list_->Remove(this); + reports_->StopAndRecord(allocs_); + return tcmalloc_internal::ProfileAccessor::MakeProfile( + std::move(reports_)); + } + return tcmalloc::Profile(); + } + + void ReportMalloc(const tcmalloc_internal::StackTrace& stack_trace) { + // store sampled alloc in the hashmap + DeallocationSampleRecord& allocation = + allocs_[stack_trace.sampled_alloc_handle]; + + allocation.allocated_size = stack_trace.allocated_size; + allocation.requested_size = stack_trace.requested_size; + allocation.requested_alignment = stack_trace.requested_alignment; + allocation.depth = stack_trace.depth; + memcpy(allocation.stack, stack_trace.stack, + sizeof(void*) * std::min(static_cast(stack_trace.depth), + kMaxStackDepth)); + // TODO(mmaas): Do we need to worry about b/65384231 anymore? + allocation.creation_time = stack_trace.allocation_time; + allocation.cpu_id = tcmalloc_internal::subtle::percpu::GetRealCpu(); + allocation.vcpu_id = tcmalloc_internal::subtle::percpu::VirtualCpu::get(); + allocation.l3_id = GetL3Id(allocation.cpu_id); + allocation.numa_id = GetNumaId(allocation.cpu_id); + allocation.thread_id = absl::base_internal::GetTID(); + // We divide by the requested size to obtain the number of allocations. + // TODO(b/248332543): Consider using AllocatedBytes from sampler.h. + allocation.weight = static_cast(stack_trace.weight) / + (stack_trace.requested_size + 1); + } + + void ReportFree(tcmalloc_internal::AllocHandle handle) { + auto it = allocs_.find(handle); + + // Handle the case that we observed the deallocation but not the allocation + if (it == allocs_.end()) { + return; + } + + DeallocationSampleRecord sample = it->second; + allocs_.erase(it); + + DeallocationSampleRecord deallocation; + deallocation.allocated_size = sample.allocated_size; + deallocation.requested_alignment = sample.requested_alignment; + deallocation.requested_size = sample.requested_size; + deallocation.creation_time = absl::Now(); + deallocation.cpu_id = tcmalloc_internal::subtle::percpu::GetRealCpu(); + deallocation.vcpu_id = tcmalloc_internal::subtle::percpu::VirtualCpu::get(); + deallocation.l3_id = GetL3Id(deallocation.cpu_id); + deallocation.numa_id = GetNumaId(deallocation.cpu_id); + deallocation.thread_id = absl::base_internal::GetTID(); + deallocation.depth = + absl::GetStackTrace(deallocation.stack, kMaxStackDepth, 1); + + reports_->AddTrace(sample, deallocation); + } +}; + +void DeallocationProfilerList::Add(DeallocationProfiler* profiler) { + AllocationGuardSpinLockHolder h(&profilers_lock_); + profiler->next_ = first_; + first_ = profiler; + + // Whenever a new profiler is created, we seed it with live allocations. + tcmalloc_internal::tc_globals.sampled_allocation_recorder().Iterate( + [profiler]( + const tcmalloc_internal::SampledAllocation& sampled_allocation) { + profiler->ReportMalloc(sampled_allocation.sampled_stack); + }); +} + +// This list is very short and we're nowhere near a hot path, just walk +void DeallocationProfilerList::Remove(DeallocationProfiler* profiler) { + AllocationGuardSpinLockHolder h(&profilers_lock_); + DeallocationProfiler** link = &first_; + DeallocationProfiler* cur = first_; + while (cur != profiler) { + TC_CHECK_NE(cur, nullptr); + link = &cur->next_; + cur = cur->next_; + } + *link = profiler->next_; +} + +void DeallocationProfilerList::ReportMalloc( + const tcmalloc_internal::StackTrace& stack_trace) { + AllocationGuardSpinLockHolder h(&profilers_lock_); + DeallocationProfiler* cur = first_; + while (cur != nullptr) { + cur->ReportMalloc(stack_trace); + cur = cur->next_; + } +} + +void DeallocationProfilerList::ReportFree( + tcmalloc_internal::AllocHandle handle) { + AllocationGuardSpinLockHolder h(&profilers_lock_); + DeallocationProfiler* cur = first_; + while (cur != nullptr) { + cur->ReportFree(handle); + cur = cur->next_; + } +} + +// Initialize static variables +absl::base_internal::LowLevelAlloc::Arena* + DeallocationProfiler::MyAllocator::arena_ = nullptr; +uint32_t DeallocationProfiler::MyAllocator::refcount_ = 0; +ABSL_CONST_INIT SpinLock DeallocationProfiler::MyAllocator::arena_lock_( + absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY); + +void DeallocationProfiler::DeallocationStackTraceTable::StopAndRecord( + const AllocsTable& allocs) { + stop_time_ = absl::Now(); + + // Insert a dummy DeallocationSampleRecord since the table stores pairs. This + // allows us to make minimal changes to the rest of the sample processing + // steps reducing special casing for censored samples. This also allows us to + // aggregate censored samples just like regular deallocation samples. + const DeallocationSampleRecord censored{ + .creation_time = stop_time_, + }; + for (const auto& [unused, alloc] : allocs) { + AddTrace(alloc, censored); + } +} + +void DeallocationProfiler::DeallocationStackTraceTable::AddTrace( + const DeallocationSampleRecord& alloc_trace, + const DeallocationSampleRecord& dealloc_trace) { + CpuThreadMatchingStatus status = + CpuThreadMatchingStatus(alloc_trace.cpu_id == dealloc_trace.cpu_id, + alloc_trace.vcpu_id == dealloc_trace.vcpu_id, + alloc_trace.l3_id == dealloc_trace.l3_id, + alloc_trace.numa_id == dealloc_trace.numa_id, + alloc_trace.thread_id == dealloc_trace.thread_id); + + // Initialize a default rpc matched status. + RpcMatchingStatus rpc_status(/*alloc=*/0, /*dealloc=*/0); + + const int index = ComputeIndex(status, rpc_status); + + DeallocationStackTraceTable::Value& v = + table_[DeallocationStackTraceTable::Key(alloc_trace, dealloc_trace)]; + + const absl::Duration life_time = + dealloc_trace.creation_time - alloc_trace.creation_time; + double life_time_ns = absl::ToDoubleNanoseconds(life_time); + + // Update mean and variance using Welford’s online algorithm. + TC_ASSERT_LT(index, ABSL_ARRAYSIZE(v.counts)); + + double old_mean_ns = v.mean_life_times_ns[index]; + v.mean_life_times_ns[index] += + (life_time_ns - old_mean_ns) / static_cast(v.counts[index] + 1); + v.variance_life_times_ns[index] += + (life_time_ns - v.mean_life_times_ns[index]) * + (v.mean_life_times_ns[index] - old_mean_ns); + + v.min_life_times_ns[index] = + std::min(v.min_life_times_ns[index], life_time_ns); + v.max_life_times_ns[index] = + std::max(v.max_life_times_ns[index], life_time_ns); + v.counts[index]++; +} + +void DeallocationProfiler::DeallocationStackTraceTable::Iterate( + absl::FunctionRef func) const { + uint64_t pair_id = 1; + + for (auto& it : table_) { + const Key& k = it.first; + const Value& v = it.second; + + // Report total bytes that are a multiple of the object size. + size_t allocated_size = k.alloc.allocated_size; + + for (const auto& matching_case : kAllCases) { + const int index = ComputeIndex(matching_case.first, matching_case.second); + if (v.counts[index] == 0) { + continue; + } + + uintptr_t bytes = + std::lround(v.counts[index] * k.alloc.weight * allocated_size); + int64_t count = (bytes + allocated_size - 1) / allocated_size; + int64_t sum = count * allocated_size; + + // The variance should be >= 0, but it's not impossible that it drops + // below 0 for numerical reasons. We don't want to crash in this case, + // so we ensure to return 0 if this happens. + double stddev_life_time_ns = + sqrt(std::max(0.0, v.variance_life_times_ns[index] / + static_cast((v.counts[index])))); + + const auto bucketize = internal::LifetimeNsToBucketedDuration; + Profile::Sample sample; + sample.sum = sum, sample.requested_size = k.alloc.requested_size, + sample.requested_alignment = k.alloc.requested_alignment, + sample.allocated_size = allocated_size, sample.profile_id = pair_id++, + // Set the is_censored flag so that when we create a proto + // sample later we can treat the *_lifetime accordingly. + sample.is_censored = (k.dealloc.depth == 0), + sample.avg_lifetime = bucketize(v.mean_life_times_ns[index]), + sample.stddev_lifetime = bucketize(stddev_life_time_ns), + sample.min_lifetime = bucketize(v.min_life_times_ns[index]), + sample.max_lifetime = bucketize(v.max_life_times_ns[index]); + // Only set the cpu and thread matched flags if the sample is not + // censored. + if (!sample.is_censored) { + sample.allocator_deallocator_physical_cpu_matched = + matching_case.first.physical_cpu_matched; + sample.allocator_deallocator_virtual_cpu_matched = + matching_case.first.virtual_cpu_matched; + sample.allocator_deallocator_l3_matched = + matching_case.first.l3_matched; + sample.allocator_deallocator_numa_matched = + matching_case.first.numa_matched; + sample.allocator_deallocator_thread_matched = + matching_case.first.thread_matched; + } + + // first for allocation + sample.count = count; + sample.depth = k.alloc.depth; + std::copy(k.alloc.stack, k.alloc.stack + k.alloc.depth, sample.stack); + func(sample); + + // If this is a right-censored allocation (i.e. we did not observe the + // deallocation) then do not emit a deallocation sample pair. + if (sample.is_censored) { + continue; + } + + // second for deallocation + static_assert( + std::is_signed::value, + "Deallocation samples are tagged with negative count values."); + sample.count = -1 * count; + sample.depth = k.dealloc.depth; + std::copy(k.dealloc.stack, k.dealloc.stack + k.dealloc.depth, + sample.stack); + func(sample); + } + } +} + +DeallocationSample::DeallocationSample(DeallocationProfilerList* list) { + profiler_ = std::make_unique(list); +} + +tcmalloc::Profile DeallocationSample::Stop() && { + if (profiler_ != nullptr) { + tcmalloc::Profile profile = profiler_->Stop(); + profiler_.reset(); + return profile; + } + return tcmalloc::Profile(); +} + +namespace internal { + +// Lifetimes below 1ns are truncated to 1ns. Lifetimes between 1ns and 1ms +// are rounded to the next smaller power of 10. Lifetimes above 1ms are rounded +// down to the nearest millisecond. +absl::Duration LifetimeNsToBucketedDuration(double lifetime_ns) { + if (lifetime_ns < 1000000.0) { + if (lifetime_ns <= 1) { + // Avoid negatives. We can't allocate in a negative amount of time or + // even as quickly as a nanosecond (microbenchmarks of + // allocation/deallocation in a tight loop are several nanoseconds), so + // results this small indicate probable clock skew or other confounding + // factors in the data. + return absl::Nanoseconds(1); + } + + for (uint64_t cutoff_ns = 10; cutoff_ns <= 1000000; cutoff_ns *= 10) { + if (lifetime_ns < cutoff_ns) { + return absl::Nanoseconds(cutoff_ns / 10); + } + } + } + + // Round down to nearest millisecond. + return absl::Nanoseconds(static_cast(lifetime_ns / 1000000.0) * + 1000000L); +} + +} // namespace internal +} // namespace deallocationz +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/deallocation_profiler.h b/contrib/libs/tcmalloc/tcmalloc/deallocation_profiler.h new file mode 100644 index 000000000000..0f0d47120d46 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/deallocation_profiler.h @@ -0,0 +1,69 @@ +#pragma clang system_header +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_DEALLOCATION_PROFILER_H_ +#define TCMALLOC_DEALLOCATION_PROFILER_H_ + +#include + +#include "absl/base/const_init.h" +#include "absl/base/internal/spinlock.h" +#include "absl/time/time.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/malloc_extension.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace deallocationz { + +class DeallocationProfiler; + +class DeallocationProfilerList { + public: + constexpr DeallocationProfilerList() = default; + + void ReportMalloc(const tcmalloc_internal::StackTrace& stack_trace); + void ReportFree(tcmalloc_internal::AllocHandle handle); + void Add(DeallocationProfiler* profiler); + void Remove(DeallocationProfiler* profiler); + + private: + DeallocationProfiler* first_ = nullptr; + absl::base_internal::SpinLock profilers_lock_{ + absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY}; +}; + +class DeallocationSample final + : public tcmalloc_internal::AllocationProfilingTokenBase { + public: + explicit DeallocationSample(DeallocationProfilerList* list); + // We define the dtor to ensure it is placed in the desired text section. + ~DeallocationSample() override = default; + + tcmalloc::Profile Stop() && override; + + private: + std::unique_ptr profiler_; +}; + +namespace internal { +absl::Duration LifetimeNsToBucketedDuration(double lifetime_ns); +} // namespace internal +} // namespace deallocationz +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_DEALLOCATION_PROFILER_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/experiment.cc b/contrib/libs/tcmalloc/tcmalloc/experiment.cc index 1c425fbf9ed1..bd131db4f7a1 100644 --- a/contrib/libs/tcmalloc/tcmalloc/experiment.cc +++ b/contrib/libs/tcmalloc/tcmalloc/experiment.cc @@ -16,11 +16,28 @@ #include -#include "absl/base/macros.h" +#include +#include +#include +#include +#include +#include +#include + +#include "absl/base/attributes.h" +#include "absl/base/call_once.h" +#include "absl/base/internal/cycleclock.h" +#include "absl/functional/function_ref.h" +#include "absl/hash/hash.h" +#include "absl/strings/match.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "tcmalloc/experiment_config.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/environment.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/malloc_extension.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { @@ -33,6 +50,28 @@ const char kDisableExperiments[] = "BORG_DISABLE_EXPERIMENTS"; constexpr absl::string_view kEnableAll = "enable-all-known-experiments"; constexpr absl::string_view kDisableAll = "all"; +// Experiments that have known issues with brittle tests, are not enabled +// involuntarily in tests, and shouldn't be enabled widely. +bool HasBrittleTestFailures(Experiment exp) { + if (exp == Experiment::TEST_ONLY_TCMALLOC_POW2_SIZECLASS) { + return true; + } + + if (exp == Experiment::TEST_ONLY_TCMALLOC_SHARDED_TRANSFER_CACHE) { + return true; + } + + return false; +} + +bool IsCompilerExperiment(Experiment exp) { +#ifdef NPX_COMPILER_ENABLED_EXPERIMENT + return exp == Experiment::NPX_COMPILER_EXPERIMENT; +#else + return false; +#endif +} + bool LookupExperimentID(absl::string_view label, Experiment* exp) { for (auto config : experiments) { if (config.name == label) { @@ -45,16 +84,20 @@ bool LookupExperimentID(absl::string_view label, Experiment* exp) { } const bool* GetSelectedExperiments() { - static bool by_id[kNumExperiments]; + ABSL_CONST_INIT static bool by_id[kNumExperiments]; + ABSL_CONST_INIT static absl::once_flag flag; - static const bool* status = [&]() { + absl::base_internal::LowLevelCallOnce(&flag, [&]() { + const char* test_target = thread_safe_getenv("TEST_TARGET"); const char* active_experiments = thread_safe_getenv(kExperiments); const char* disabled_experiments = thread_safe_getenv(kDisableExperiments); - return SelectExperiments(by_id, - active_experiments ? active_experiments : "", - disabled_experiments ? disabled_experiments : ""); - }(); - return status; + SelectExperiments( + by_id, test_target ? test_target : "", + active_experiments ? active_experiments : "", + disabled_experiments ? disabled_experiments : "", + active_experiments == nullptr && disabled_experiments == nullptr); + }); + return by_id; } template @@ -77,8 +120,9 @@ void ParseExperiments(absl::string_view labels, F f) { } // namespace -const bool* SelectExperiments(bool* buffer, absl::string_view active, - absl::string_view disabled) { +const bool* SelectExperiments(bool* buffer, absl::string_view test_target, + absl::string_view active, + absl::string_view disabled, bool unset) { memset(buffer, 0, sizeof(*buffer) * kNumExperiments); if (active == kEnableAll) { @@ -92,70 +136,114 @@ const bool* SelectExperiments(bool* buffer, absl::string_view active, } }); + // The compiler experiments should be env variable independent. +#ifdef NPX_COMPILER_ENABLED_EXPERIMENT + if (!absl::StrContains(active, NPX_COMPILER_ENABLED_EXPERIMENT)) { + Experiment id; + if (LookupExperimentID(NPX_COMPILER_ENABLED_EXPERIMENT, &id)) { + buffer[static_cast(id)] = true; + } + } +#endif + if (disabled == kDisableAll) { - memset(buffer, 0, sizeof(*buffer) * kNumExperiments); + for (auto config : experiments) { + // Exclude compile-time experiments + if (!IsCompilerExperiment(config.id)) { + buffer[static_cast(config.id)] = false; + } + } } + // disable non-compiler experiments ParseExperiments(disabled, [buffer](absl::string_view token) { Experiment id; - if (LookupExperimentID(token, &id)) { + if (LookupExperimentID(token, &id) && !IsCompilerExperiment(id)) { buffer[static_cast(id)] = false; } }); - return buffer; -} - -void PrintExperiments(Printer* printer) { - // Index experiments by their positions in the experiments array, rather than - // by experiment ID. - static bool active[ABSL_ARRAYSIZE(experiments)]; - static const bool* status = []() { - memset(active, 0, sizeof(active)); - const bool* by_id = GetSelectedExperiments(); - - for (int i = 0; i < ABSL_ARRAYSIZE(experiments); i++) { - const auto& config = experiments[i]; - active[i] = by_id[static_cast(config.id)]; + // Enable some random combination of experiments for tests that don't + // explicitly set any of the experiment env vars. This allows to get better + // test coverage of experiments before production. + // Tests can opt out by exporting BORG_EXPERIMENTS="". + // Enabled experiments are selected based on the stable test target name hash, + // this allows get a wide range of experiment permutations on a large test + // base, but at the same time avoids flaky test failures (if a particular + // test fails only with a particular experiment combination). + // It would be nice to print what experiments we enable, but printing even + // to stderr breaks some tests that capture subprocess output. + if (unset && !test_target.empty()) { + TC_CHECK(active.empty() && disabled.empty()); + uint64_t seed = + static_cast(absl::base_internal::CycleClock::Now()); + const size_t target_hash = absl::HashOf(test_target, seed); + constexpr size_t kVanillaOneOf = 11; + constexpr size_t kEnableOneOf = 3; + if ((target_hash % kVanillaOneOf) == 0) { + return buffer; } - return active; - }(); - - printer->printf("MALLOC EXPERIMENTS:"); - for (int i = 0; i < ABSL_ARRAYSIZE(experiments); i++) { - const char* value = status[i] ? "1" : "0"; - printer->printf(" %s=%s", experiments[i].name, value); + int num_enabled_experiments = 0; + Experiment experiment_id = Experiment::kMaxExperimentID; + for (auto config : experiments) { + if (IsCompilerExperiment(config.id) || + HasBrittleTestFailures(config.id)) { + continue; + } + TC_CHECK(!buffer[static_cast(config.id)]); + experiment_id = config.id; + + // Enabling is specifically based on the experiment name so that it's + // stable when experiments are added/removed. + bool enabled = + ((target_hash ^ absl::HashOf(config.name)) % kEnableOneOf) == 0; + buffer[static_cast(config.id)] = enabled; + num_enabled_experiments += enabled; + } + // In case the hash-based selection above did not work out, select the last + // experiment. + if (num_enabled_experiments == 0 && + experiment_id != Experiment::kMaxExperimentID) { + TC_CHECK(!buffer[static_cast(experiment_id)]); + buffer[static_cast(experiment_id)] = true; + } } - printer->printf("\n"); -} - -void FillExperimentProperties( - std::map* result) { - for (const auto& config : experiments) { - (*result)[absl::StrCat("tcmalloc.experiment.", config.name)].value = - IsExperimentActive(config.id) ? 1 : 0; - } + return buffer; } } // namespace tcmalloc_internal bool IsExperimentActive(Experiment exp) { - ASSERT(static_cast(exp) >= 0); - ASSERT(exp < Experiment::kMaxExperimentID); + TC_ASSERT_GE(static_cast(exp), 0); + TC_ASSERT_LT(exp, Experiment::kMaxExperimentID); return tcmalloc_internal::GetSelectedExperiments()[static_cast(exp)]; } -absl::optional FindExperimentByName(absl::string_view name) { +std::optional FindExperimentByName(absl::string_view name) { for (const auto& config : experiments) { if (name == config.name) { return config.id; } } - return absl::nullopt; + return std::nullopt; +} + +void WalkExperiments( + absl::FunctionRef callback) { + for (const auto& config : experiments) { + callback(config.name, IsExperimentActive(config.id)); + } +} + +extern "C" void MallocExtension_Internal_GetExperiments( + std::map* result) { + WalkExperiments([&](absl::string_view name, bool active) { + (*result)[absl::StrCat("tcmalloc.experiment.", name)].value = active; + }); } } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/experiment.h b/contrib/libs/tcmalloc/tcmalloc/experiment.h index 90b3049df117..75ee9d64f2ce 100644 --- a/contrib/libs/tcmalloc/tcmalloc/experiment.h +++ b/contrib/libs/tcmalloc/tcmalloc/experiment.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,14 +18,13 @@ #include -#include -#include +#include +#include "absl/functional/function_ref.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "tcmalloc/experiment_config.h" -#include "tcmalloc/internal/logging.h" -#include "tcmalloc/malloc_extension.h" +#include "tcmalloc/internal/config.h" // TCMalloc Experiment Controller // @@ -51,19 +51,18 @@ constexpr size_t kNumExperiments = // buffer must be sized for kMaxExperimentID entries. // // This is exposed for testing purposes only. -const bool* SelectExperiments(bool* buffer, absl::string_view active, - absl::string_view disabled); - -void FillExperimentProperties( - std::map* result); - -void PrintExperiments(Printer* printer); +const bool* SelectExperiments(bool* buffer, absl::string_view test_target, + absl::string_view active, + absl::string_view disabled, bool unset); } // namespace tcmalloc_internal bool IsExperimentActive(Experiment exp); -absl::optional FindExperimentByName(absl::string_view name); +std::optional FindExperimentByName(absl::string_view name); + +void WalkExperiments( + absl::FunctionRef callback); } // namespace tcmalloc GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/experiment_config.h b/contrib/libs/tcmalloc/tcmalloc/experiment_config.h index 294c0374e415..382b3388061a 100644 --- a/contrib/libs/tcmalloc/tcmalloc/experiment_config.h +++ b/contrib/libs/tcmalloc/tcmalloc/experiment_config.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,13 +22,18 @@ namespace tcmalloc { enum class Experiment : int { - TCMALLOC_TEMERAIRE, - TCMALLOC_SANS_56_SIZECLASS, + // clang-format off + // go/keep-sorted start + TCMALLOC_L3_AWARE_VCPUS, // TODO(b/239977380): Complete experiment. + TCMALLOC_MIN_HOT_ACCESS_HINT_ABLATION, // TODO(b/376902157): Complete experiment. + TEST_ONLY_L3_AWARE, // TODO(b/239977380): Complete experiment. + TEST_ONLY_TCMALLOC_DENSE_TRACKERS_SORTED_ON_SPANS_ALLOCATED, // TODO(b/348043731): Complete experiment. + TEST_ONLY_TCMALLOC_HUGE_CACHE_RELEASE_30S, // TODO(b/319872040): Complete experiment. TEST_ONLY_TCMALLOC_POW2_SIZECLASS, - TEST_ONLY_TCMALLOC_POW2_BELOW64_SIZECLASS, - TEST_ONLY_TCMALLOC_RING_BUFFER_TRANSFER_CACHE, TEST_ONLY_TCMALLOC_SHARDED_TRANSFER_CACHE, + // go/keep-sorted end kMaxExperimentID, + // clang-format on }; struct ExperimentConfig { @@ -37,12 +43,15 @@ struct ExperimentConfig { // clang-format off inline constexpr ExperimentConfig experiments[] = { - {Experiment::TCMALLOC_TEMERAIRE, "TCMALLOC_TEMERAIRE"}, - {Experiment::TCMALLOC_SANS_56_SIZECLASS, "TCMALLOC_SANS_56_SIZECLASS"}, + // go/keep-sorted start + {Experiment::TCMALLOC_L3_AWARE_VCPUS, "TCMALLOC_L3_AWARE_VCPUS"}, + {Experiment::TCMALLOC_MIN_HOT_ACCESS_HINT_ABLATION, "TCMALLOC_MIN_HOT_ACCESS_HINT_ABLATION"}, + {Experiment::TEST_ONLY_L3_AWARE, "TEST_ONLY_L3_AWARE"}, + {Experiment::TEST_ONLY_TCMALLOC_DENSE_TRACKERS_SORTED_ON_SPANS_ALLOCATED, "TEST_ONLY_TCMALLOC_DENSE_TRACKERS_SORTED_ON_SPANS_ALLOCATED"}, + {Experiment::TEST_ONLY_TCMALLOC_HUGE_CACHE_RELEASE_30S, "TEST_ONLY_TCMALLOC_HUGE_CACHE_RELEASE_30S"}, {Experiment::TEST_ONLY_TCMALLOC_POW2_SIZECLASS, "TEST_ONLY_TCMALLOC_POW2_SIZECLASS"}, - {Experiment::TEST_ONLY_TCMALLOC_POW2_BELOW64_SIZECLASS, "TEST_ONLY_TCMALLOC_POW2_BELOW64_SIZECLASS"}, - {Experiment::TEST_ONLY_TCMALLOC_RING_BUFFER_TRANSFER_CACHE, "TEST_ONLY_TCMALLOC_RING_BUFFER_TRANSFER_CACHE"}, {Experiment::TEST_ONLY_TCMALLOC_SHARDED_TRANSFER_CACHE, "TEST_ONLY_TCMALLOC_SHARDED_TRANSFER_CACHE"}, + // go/keep-sorted end }; // clang-format on diff --git a/contrib/libs/tcmalloc/tcmalloc/experiment_fuzz.cc b/contrib/libs/tcmalloc/tcmalloc/experiment_fuzz.cc index 2a7afe9b85a9..87fa5c26a07a 100644 --- a/contrib/libs/tcmalloc/tcmalloc/experiment_fuzz.cc +++ b/contrib/libs/tcmalloc/tcmalloc/experiment_fuzz.cc @@ -16,23 +16,26 @@ #include #include +#include "fuzztest/fuzztest.h" #include "absl/strings/string_view.h" #include "tcmalloc/experiment.h" -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* d, size_t size) { - const char* data = reinterpret_cast(d); +namespace tcmalloc::tcmalloc_internal { +namespace { - bool buffer[tcmalloc::tcmalloc_internal::kNumExperiments]; - absl::string_view active, disabled; - - const char* split = static_cast(memchr(data, ';', size)); - if (split == nullptr) { - active = absl::string_view(data, size); - } else { - active = absl::string_view(data, split - data); - disabled = absl::string_view(split + 1, size - (split - data + 1)); +void FuzzSelectExperiments(absl::string_view test_target, + absl::string_view active, absl::string_view disabled, + bool unset) { + if (unset && !test_target.empty() && (!active.empty() || !disabled.empty())) { + return; } - tcmalloc::tcmalloc_internal::SelectExperiments(buffer, active, disabled); - return 0; + bool buffer[tcmalloc::tcmalloc_internal::kNumExperiments]; + + SelectExperiments(buffer, test_target, active, disabled, unset); } + +FUZZ_TEST(ExperimentTest, FuzzSelectExperiments); + +} // namespace +} // namespace tcmalloc::tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/experimental_56_size_class.cc b/contrib/libs/tcmalloc/tcmalloc/experimental_56_size_class.cc deleted file mode 100644 index c582cdb9baf5..000000000000 --- a/contrib/libs/tcmalloc/tcmalloc/experimental_56_size_class.cc +++ /dev/null @@ -1,706 +0,0 @@ -// Copyright 2019 The TCMalloc Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "tcmalloc/common.h" - -namespace tcmalloc { - -// is fixed per-size-class overhead due to end-of-span fragmentation -// and other factors. For instance, if we have a 96 byte size class, and use a -// single 8KiB page, then we will hold 85 objects per span, and have 32 bytes -// left over. There is also a fixed component of 48 bytes of TCMalloc metadata -// per span. Together, the fixed overhead would be wasted/allocated = -// (32 + 48) / (8192 - 32) ~= 0.98%. -// There is also a dynamic component to overhead based on mismatches between the -// number of bytes requested and the number of bytes provided by the size class. -// Together they sum to the total overhead; for instance if you asked for a -// 50-byte allocation that rounds up to a 64-byte size class, the dynamic -// overhead would be 28%, and if were 22% it would mean (on average) -// 25 bytes of overhead for allocations of that size. - -// clang-format off -#if defined(__cpp_aligned_new) && __STDCPP_DEFAULT_NEW_ALIGNMENT__ <= 8 -#if TCMALLOC_PAGE_SHIFT == 13 -static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 86; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalSizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalSizeClasses[SizeMap::kExperimentalSizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.59% - { 16, 1, 32}, // 0.59% - { 24, 1, 32}, // 0.68% - { 32, 1, 32}, // 0.59% - { 40, 1, 32}, // 0.98% - { 48, 1, 32}, // 0.98% - { 64, 1, 32}, // 0.59% - { 72, 1, 32}, // 1.28% - { 80, 1, 32}, // 0.98% - { 88, 1, 32}, // 0.68% - { 96, 1, 32}, // 0.98% - { 104, 1, 32}, // 1.58% - { 112, 1, 32}, // 0.78% - { 120, 1, 32}, // 0.98% - { 128, 1, 32}, // 0.59% - { 136, 1, 32}, // 0.98% - { 144, 1, 32}, // 2.18% - { 160, 1, 32}, // 0.98% - { 176, 1, 32}, // 1.78% - { 184, 1, 32}, // 1.78% - { 192, 1, 32}, // 2.18% - { 208, 1, 32}, // 1.58% - { 224, 1, 32}, // 2.18% - { 240, 1, 32}, // 0.98% - { 256, 1, 32}, // 0.59% - { 272, 1, 32}, // 0.98% - { 288, 1, 32}, // 2.18% - { 312, 1, 32}, // 1.58% - { 336, 1, 32}, // 2.18% - { 352, 1, 32}, // 1.78% - { 384, 1, 32}, // 2.18% - { 408, 1, 32}, // 0.98% - { 424, 1, 32}, // 2.28% - { 448, 1, 32}, // 2.18% - { 480, 1, 32}, // 0.98% - { 512, 1, 32}, // 0.59% - { 576, 1, 32}, // 2.18% - { 640, 1, 32}, // 7.29% - { 704, 1, 32}, // 6.40% - { 768, 1, 32}, // 7.29% - { 896, 1, 32}, // 2.18% - { 1024, 1, 32}, // 0.59% - { 1152, 2, 32}, // 1.88% - { 1280, 2, 32}, // 6.98% - { 1408, 2, 32}, // 6.10% - { 1536, 2, 32}, // 6.98% - { 1792, 2, 32}, // 1.88% - { 2048, 2, 32}, // 0.29% - { 2304, 2, 28}, // 1.88% - { 2688, 2, 24}, // 1.88% - { 2816, 3, 23}, // 9.30% - { 3200, 2, 20}, // 2.70% - { 3456, 3, 18}, // 1.79% - { 3584, 4, 18}, // 1.74% - { 4096, 2, 16}, // 0.29% - { 4736, 3, 13}, // 3.99% - { 5376, 2, 12}, // 1.88% - { 6144, 3, 10}, // 0.20% - { 6528, 4, 10}, // 0.54% - { 7168, 7, 9}, // 0.08% - { 8192, 2, 8}, // 0.29% - { 9472, 5, 6}, // 8.23% - { 10240, 4, 6}, // 6.82% - { 12288, 3, 5}, // 0.20% - { 14336, 7, 4}, // 0.08% - { 16384, 2, 4}, // 0.29% - { 20480, 5, 3}, // 0.12% - { 24576, 3, 2}, // 0.20% - { 28672, 7, 2}, // 0.08% - { 32768, 4, 2}, // 0.15% - { 40960, 5, 2}, // 0.12% - { 49152, 6, 2}, // 0.10% - { 57344, 7, 2}, // 0.08% - { 65536, 8, 2}, // 0.07% - { 73728, 9, 2}, // 0.07% - { 81920, 10, 2}, // 0.06% - { 98304, 12, 2}, // 0.05% - { 106496, 13, 2}, // 0.05% - { 131072, 16, 2}, // 0.04% - { 147456, 18, 2}, // 0.03% - { 163840, 20, 2}, // 0.03% - { 180224, 22, 2}, // 0.03% - { 204800, 25, 2}, // 0.02% - { 229376, 28, 2}, // 0.02% - { 262144, 32, 2}, // 0.02% -}; -#elif TCMALLOC_PAGE_SHIFT == 15 -static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 78; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalSizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalSizeClasses[SizeMap::kExperimentalSizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.15% - { 16, 1, 32}, // 0.15% - { 24, 1, 32}, // 0.17% - { 32, 1, 32}, // 0.15% - { 40, 1, 32}, // 0.17% - { 48, 1, 32}, // 0.24% - { 64, 1, 32}, // 0.15% - { 72, 1, 32}, // 0.17% - { 80, 1, 32}, // 0.29% - { 88, 1, 32}, // 0.24% - { 96, 1, 32}, // 0.24% - { 104, 1, 32}, // 0.17% - { 112, 1, 32}, // 0.34% - { 120, 1, 32}, // 0.17% - { 128, 1, 32}, // 0.15% - { 144, 1, 32}, // 0.39% - { 160, 1, 32}, // 0.54% - { 176, 1, 32}, // 0.24% - { 192, 1, 32}, // 0.54% - { 208, 1, 32}, // 0.49% - { 224, 1, 32}, // 0.34% - { 240, 1, 32}, // 0.54% - { 256, 1, 32}, // 0.15% - { 280, 1, 32}, // 0.17% - { 304, 1, 32}, // 0.89% - { 336, 1, 32}, // 0.69% - { 368, 1, 32}, // 0.20% - { 416, 1, 32}, // 1.13% - { 456, 1, 32}, // 1.36% - { 488, 1, 32}, // 0.37% - { 512, 1, 32}, // 0.15% - { 576, 1, 32}, // 1.74% - { 640, 1, 32}, // 0.54% - { 704, 1, 32}, // 1.33% - { 768, 1, 32}, // 1.74% - { 832, 1, 32}, // 1.13% - { 896, 1, 32}, // 1.74% - { 1024, 1, 32}, // 0.15% - { 1152, 1, 32}, // 1.74% - { 1280, 1, 32}, // 2.55% - { 1408, 1, 32}, // 1.33% - { 1664, 1, 32}, // 3.80% - { 2048, 1, 32}, // 0.15% - { 2176, 1, 30}, // 0.54% - { 2304, 1, 28}, // 1.74% - { 2432, 1, 26}, // 3.80% - { 2688, 1, 24}, // 1.74% - { 2944, 1, 22}, // 1.33% - { 3200, 1, 20}, // 2.55% - { 3584, 1, 18}, // 1.74% - { 4096, 1, 16}, // 0.15% - { 4608, 1, 14}, // 1.74% - { 5376, 1, 12}, // 1.74% - { 6528, 1, 10}, // 0.54% - { 8192, 1, 8}, // 0.15% - { 9344, 2, 7}, // 0.27% - { 10880, 1, 6}, // 0.54% - { 13056, 2, 5}, // 0.47% - { 13952, 3, 4}, // 0.70% - { 16384, 1, 4}, // 0.15% - { 19072, 3, 3}, // 3.14% - { 21760, 2, 3}, // 0.47% - { 24576, 3, 2}, // 0.05% - { 28032, 6, 2}, // 0.22% - { 32768, 1, 2}, // 0.15% - { 40960, 4, 2}, // 6.71% - { 49152, 3, 2}, // 0.05% - { 57344, 7, 2}, // 0.02% - { 65536, 2, 2}, // 0.07% - { 81920, 5, 2}, // 0.03% - { 98304, 3, 2}, // 0.05% - { 114688, 7, 2}, // 0.02% - { 131072, 4, 2}, // 0.04% - { 163840, 5, 2}, // 0.03% - { 196608, 6, 2}, // 0.02% - { 229376, 7, 2}, // 0.02% - { 262144, 8, 2}, // 0.02% -}; -#elif TCMALLOC_PAGE_SHIFT == 18 -static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 89; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalSizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalSizeClasses[SizeMap::kExperimentalSizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.02% - { 16, 1, 32}, // 0.02% - { 24, 1, 32}, // 0.02% - { 32, 1, 32}, // 0.02% - { 40, 1, 32}, // 0.03% - { 48, 1, 32}, // 0.02% - { 64, 1, 32}, // 0.02% - { 72, 1, 32}, // 0.04% - { 80, 1, 32}, // 0.04% - { 88, 1, 32}, // 0.05% - { 96, 1, 32}, // 0.04% - { 112, 1, 32}, // 0.04% - { 128, 1, 32}, // 0.02% - { 144, 1, 32}, // 0.04% - { 160, 1, 32}, // 0.04% - { 176, 1, 32}, // 0.05% - { 192, 1, 32}, // 0.04% - { 216, 1, 32}, // 0.07% - { 240, 1, 32}, // 0.04% - { 256, 1, 32}, // 0.02% - { 288, 1, 32}, // 0.04% - { 312, 1, 32}, // 0.04% - { 344, 1, 32}, // 0.02% - { 360, 1, 32}, // 0.04% - { 416, 1, 32}, // 0.04% - { 464, 1, 32}, // 0.19% - { 512, 1, 32}, // 0.02% - { 576, 1, 32}, // 0.04% - { 640, 1, 32}, // 0.17% - { 704, 1, 32}, // 0.12% - { 832, 1, 32}, // 0.04% - { 1024, 1, 32}, // 0.02% - { 1152, 1, 32}, // 0.26% - { 1280, 1, 32}, // 0.41% - { 1408, 1, 32}, // 0.12% - { 1664, 1, 32}, // 0.36% - { 1792, 1, 32}, // 0.21% - { 1920, 1, 32}, // 0.41% - { 2048, 1, 32}, // 0.02% - { 2176, 1, 30}, // 0.41% - { 2304, 1, 28}, // 0.71% - { 2432, 1, 26}, // 0.76% - { 2688, 1, 24}, // 0.56% - { 2944, 1, 22}, // 0.07% - { 3072, 1, 21}, // 0.41% - { 3328, 1, 19}, // 1.00% - { 3584, 1, 18}, // 0.21% - { 3840, 1, 17}, // 0.41% - { 4096, 1, 16}, // 0.02% - { 4608, 1, 14}, // 1.61% - { 5120, 1, 12}, // 0.41% - { 5504, 1, 11}, // 1.35% - { 5760, 1, 11}, // 1.15% - { 6144, 1, 10}, // 1.61% - { 6656, 1, 9}, // 1.00% - { 7168, 1, 9}, // 1.61% - { 7680, 1, 8}, // 0.41% - { 8192, 1, 8}, // 0.02% - { 9344, 1, 7}, // 0.21% - { 9984, 1, 6}, // 1.00% - { 10880, 1, 6}, // 0.41% - { 11904, 1, 5}, // 0.12% - { 13056, 1, 5}, // 0.41% - { 14464, 1, 4}, // 0.71% - { 16384, 1, 4}, // 0.02% - { 17408, 1, 3}, // 0.41% - { 20096, 1, 3}, // 0.36% - { 21760, 1, 3}, // 0.41% - { 23808, 1, 2}, // 0.12% - { 26112, 1, 2}, // 0.41% - { 29056, 1, 2}, // 0.26% - { 32768, 1, 2}, // 0.02% - { 37376, 1, 2}, // 0.21% - { 43648, 1, 2}, // 0.12% - { 45568, 2, 2}, // 4.61% - { 52352, 1, 2}, // 0.17% - { 56064, 2, 2}, // 3.92% - { 65536, 1, 2}, // 0.02% - { 74880, 2, 2}, // 0.03% - { 87296, 1, 2}, // 0.12% - { 104832, 2, 2}, // 0.03% - { 112256, 3, 2}, // 0.09% - { 131072, 1, 2}, // 0.02% - { 149760, 3, 2}, // 5.03% - { 174720, 2, 2}, // 0.03% - { 196608, 3, 2}, // 0.01% - { 209664, 4, 2}, // 0.03% - { 262144, 1, 2}, // 0.02% -}; -#elif TCMALLOC_PAGE_SHIFT == 12 -static_assert(kMaxSize == 8192, "kMaxSize mismatch"); -static const int kCount = 46; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalSizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalSizeClasses[SizeMap::kExperimentalSizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 1.17% - { 16, 1, 32}, // 1.17% - { 24, 1, 32}, // 1.57% - { 32, 1, 32}, // 1.17% - { 40, 1, 32}, // 1.57% - { 48, 1, 32}, // 1.57% - { 64, 1, 32}, // 1.17% - { 72, 1, 32}, // 2.78% - { 80, 1, 32}, // 1.57% - { 88, 1, 32}, // 2.37% - { 96, 1, 32}, // 2.78% - { 104, 1, 32}, // 2.17% - { 112, 1, 32}, // 2.78% - { 128, 1, 32}, // 1.17% - { 144, 1, 32}, // 2.78% - { 160, 1, 32}, // 3.60% - { 176, 1, 32}, // 2.37% - { 192, 1, 32}, // 2.78% - { 208, 1, 32}, // 4.86% - { 240, 1, 32}, // 1.57% - { 256, 1, 32}, // 1.17% - { 272, 1, 32}, // 1.57% - { 312, 1, 32}, // 2.17% - { 336, 1, 32}, // 2.78% - { 368, 1, 32}, // 2.37% - { 408, 1, 32}, // 1.57% - { 448, 1, 32}, // 2.78% - { 512, 1, 32}, // 1.17% - { 576, 2, 32}, // 2.18% - { 640, 2, 32}, // 7.29% - { 768, 2, 32}, // 7.29% - { 896, 2, 32}, // 2.18% - { 1024, 2, 32}, // 0.59% - { 1152, 3, 32}, // 7.08% - { 1280, 3, 32}, // 7.08% - { 1536, 3, 32}, // 0.39% - { 2048, 4, 32}, // 0.29% - { 2304, 4, 28}, // 1.88% - { 2688, 4, 24}, // 1.88% - { 3200, 4, 20}, // 2.70% - { 4096, 4, 16}, // 0.29% - { 4736, 5, 13}, // 8.36% - { 6144, 3, 10}, // 0.39% - { 7168, 7, 9}, // 0.17% - { 8192, 4, 8}, // 0.29% -}; -#else -#error "Unsupported TCMALLOC_PAGE_SHIFT value!" -#endif -#else -#if TCMALLOC_PAGE_SHIFT == 13 -static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 86; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalSizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalSizeClasses[SizeMap::kExperimentalSizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.59% - { 16, 1, 32}, // 0.59% - { 32, 1, 32}, // 0.59% - { 48, 1, 32}, // 0.98% - { 64, 1, 32}, // 0.59% - { 80, 1, 32}, // 0.98% - { 96, 1, 32}, // 0.98% - { 112, 1, 32}, // 0.78% - { 128, 1, 32}, // 0.59% - { 144, 1, 32}, // 2.18% - { 160, 1, 32}, // 0.98% - { 176, 1, 32}, // 1.78% - { 192, 1, 32}, // 2.18% - { 208, 1, 32}, // 1.58% - { 224, 1, 32}, // 2.18% - { 240, 1, 32}, // 0.98% - { 256, 1, 32}, // 0.59% - { 272, 1, 32}, // 0.98% - { 288, 1, 32}, // 2.18% - { 304, 1, 32}, // 4.25% - { 320, 1, 32}, // 3.00% - { 336, 1, 32}, // 2.18% - { 352, 1, 32}, // 1.78% - { 368, 1, 32}, // 1.78% - { 384, 1, 32}, // 2.18% - { 400, 1, 32}, // 3.00% - { 416, 1, 32}, // 4.25% - { 448, 1, 32}, // 2.18% - { 480, 1, 32}, // 0.98% - { 512, 1, 32}, // 0.59% - { 576, 1, 32}, // 2.18% - { 640, 1, 32}, // 7.29% - { 704, 1, 32}, // 6.40% - { 768, 1, 32}, // 7.29% - { 896, 1, 32}, // 2.18% - { 1024, 1, 32}, // 0.59% - { 1152, 2, 32}, // 1.88% - { 1280, 2, 32}, // 6.98% - { 1408, 2, 32}, // 6.10% - { 1536, 2, 32}, // 6.98% - { 1792, 2, 32}, // 1.88% - { 2048, 2, 32}, // 0.29% - { 2304, 2, 28}, // 1.88% - { 2688, 2, 24}, // 1.88% - { 2816, 3, 23}, // 9.30% - { 3200, 2, 20}, // 2.70% - { 3456, 3, 18}, // 1.79% - { 3584, 4, 18}, // 1.74% - { 4096, 2, 16}, // 0.29% - { 4736, 3, 13}, // 3.99% - { 5376, 2, 12}, // 1.88% - { 6144, 3, 10}, // 0.20% - { 6528, 4, 10}, // 0.54% - { 6784, 5, 9}, // 0.75% - { 7168, 7, 9}, // 0.08% - { 8192, 2, 8}, // 0.29% - { 9472, 5, 6}, // 8.23% - { 10240, 4, 6}, // 6.82% - { 12288, 3, 5}, // 0.20% - { 13568, 5, 4}, // 0.75% - { 14336, 7, 4}, // 0.08% - { 16384, 2, 4}, // 0.29% - { 20480, 5, 3}, // 0.12% - { 24576, 3, 2}, // 0.20% - { 28672, 7, 2}, // 0.08% - { 32768, 4, 2}, // 0.15% - { 40960, 5, 2}, // 0.12% - { 49152, 6, 2}, // 0.10% - { 57344, 7, 2}, // 0.08% - { 65536, 8, 2}, // 0.07% - { 73728, 9, 2}, // 0.07% - { 81920, 10, 2}, // 0.06% - { 90112, 11, 2}, // 0.05% - { 98304, 12, 2}, // 0.05% - { 106496, 13, 2}, // 0.05% - { 122880, 15, 2}, // 0.04% - { 131072, 16, 2}, // 0.04% - { 139264, 17, 2}, // 0.03% - { 155648, 19, 2}, // 0.03% - { 163840, 20, 2}, // 0.03% - { 180224, 22, 2}, // 0.03% - { 204800, 25, 2}, // 0.02% - { 221184, 27, 2}, // 0.02% - { 237568, 29, 2}, // 0.02% - { 262144, 32, 2}, // 0.02% -}; -#elif TCMALLOC_PAGE_SHIFT == 15 -static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 78; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalSizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalSizeClasses[SizeMap::kExperimentalSizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.15% - { 16, 1, 32}, // 0.15% - { 32, 1, 32}, // 0.15% - { 48, 1, 32}, // 0.24% - { 64, 1, 32}, // 0.15% - { 80, 1, 32}, // 0.29% - { 96, 1, 32}, // 0.24% - { 112, 1, 32}, // 0.34% - { 128, 1, 32}, // 0.15% - { 144, 1, 32}, // 0.39% - { 160, 1, 32}, // 0.54% - { 176, 1, 32}, // 0.24% - { 192, 1, 32}, // 0.54% - { 208, 1, 32}, // 0.49% - { 224, 1, 32}, // 0.34% - { 240, 1, 32}, // 0.54% - { 256, 1, 32}, // 0.15% - { 272, 1, 32}, // 0.54% - { 288, 1, 32}, // 0.84% - { 304, 1, 32}, // 0.89% - { 336, 1, 32}, // 0.69% - { 368, 1, 32}, // 0.20% - { 416, 1, 32}, // 1.13% - { 448, 1, 32}, // 0.34% - { 480, 1, 32}, // 0.54% - { 512, 1, 32}, // 0.15% - { 576, 1, 32}, // 1.74% - { 640, 1, 32}, // 0.54% - { 704, 1, 32}, // 1.33% - { 768, 1, 32}, // 1.74% - { 832, 1, 32}, // 1.13% - { 896, 1, 32}, // 1.74% - { 1024, 1, 32}, // 0.15% - { 1152, 1, 32}, // 1.74% - { 1280, 1, 32}, // 2.55% - { 1408, 1, 32}, // 1.33% - { 1536, 1, 32}, // 1.74% - { 1664, 1, 32}, // 3.80% - { 1920, 1, 32}, // 0.54% - { 2048, 1, 32}, // 0.15% - { 2176, 1, 30}, // 0.54% - { 2304, 1, 28}, // 1.74% - { 2432, 1, 26}, // 3.80% - { 2688, 1, 24}, // 1.74% - { 2944, 1, 22}, // 1.33% - { 3200, 1, 20}, // 2.55% - { 3584, 1, 18}, // 1.74% - { 4096, 1, 16}, // 0.15% - { 4608, 1, 14}, // 1.74% - { 5376, 1, 12}, // 1.74% - { 5632, 2, 11}, // 5.86% - { 6528, 1, 10}, // 0.54% - { 7168, 2, 9}, // 1.66% - { 8192, 1, 8}, // 0.15% - { 9344, 2, 7}, // 0.27% - { 10880, 1, 6}, // 0.54% - { 13056, 2, 5}, // 0.47% - { 13952, 3, 4}, // 0.70% - { 16384, 1, 4}, // 0.15% - { 19072, 3, 3}, // 3.14% - { 21760, 2, 3}, // 0.47% - { 24576, 3, 2}, // 0.05% - { 28032, 6, 2}, // 0.22% - { 32768, 1, 2}, // 0.15% - { 38144, 5, 2}, // 7.41% - { 40960, 4, 2}, // 6.71% - { 49152, 3, 2}, // 0.05% - { 57344, 7, 2}, // 0.02% - { 65536, 2, 2}, // 0.07% - { 81920, 5, 2}, // 0.03% - { 98304, 3, 2}, // 0.05% - { 114688, 7, 2}, // 0.02% - { 131072, 4, 2}, // 0.04% - { 163840, 5, 2}, // 0.03% - { 196608, 6, 2}, // 0.02% - { 229376, 7, 2}, // 0.02% - { 262144, 8, 2}, // 0.02% -}; -#elif TCMALLOC_PAGE_SHIFT == 18 -static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 89; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalSizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalSizeClasses[SizeMap::kExperimentalSizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.02% - { 16, 1, 32}, // 0.02% - { 32, 1, 32}, // 0.02% - { 48, 1, 32}, // 0.02% - { 64, 1, 32}, // 0.02% - { 80, 1, 32}, // 0.04% - { 96, 1, 32}, // 0.04% - { 112, 1, 32}, // 0.04% - { 128, 1, 32}, // 0.02% - { 144, 1, 32}, // 0.04% - { 160, 1, 32}, // 0.04% - { 176, 1, 32}, // 0.05% - { 192, 1, 32}, // 0.04% - { 224, 1, 32}, // 0.04% - { 240, 1, 32}, // 0.04% - { 256, 1, 32}, // 0.02% - { 288, 1, 32}, // 0.04% - { 320, 1, 32}, // 0.04% - { 352, 1, 32}, // 0.12% - { 368, 1, 32}, // 0.07% - { 416, 1, 32}, // 0.04% - { 464, 1, 32}, // 0.19% - { 512, 1, 32}, // 0.02% - { 576, 1, 32}, // 0.04% - { 640, 1, 32}, // 0.17% - { 704, 1, 32}, // 0.12% - { 832, 1, 32}, // 0.04% - { 896, 1, 32}, // 0.21% - { 1024, 1, 32}, // 0.02% - { 1152, 1, 32}, // 0.26% - { 1280, 1, 32}, // 0.41% - { 1408, 1, 32}, // 0.12% - { 1536, 1, 32}, // 0.41% - { 1664, 1, 32}, // 0.36% - { 1792, 1, 32}, // 0.21% - { 1920, 1, 32}, // 0.41% - { 2048, 1, 32}, // 0.02% - { 2176, 1, 30}, // 0.41% - { 2304, 1, 28}, // 0.71% - { 2432, 1, 26}, // 0.76% - { 2688, 1, 24}, // 0.56% - { 2944, 1, 22}, // 0.07% - { 3072, 1, 21}, // 0.41% - { 3328, 1, 19}, // 1.00% - { 3584, 1, 18}, // 0.21% - { 3840, 1, 17}, // 0.41% - { 4096, 1, 16}, // 0.02% - { 4608, 1, 14}, // 1.61% - { 5120, 1, 12}, // 0.41% - { 5504, 1, 11}, // 1.35% - { 5760, 1, 11}, // 1.15% - { 6144, 1, 10}, // 1.61% - { 6528, 1, 10}, // 0.41% - { 7040, 1, 9}, // 0.66% - { 7168, 1, 9}, // 1.61% - { 7680, 1, 8}, // 0.41% - { 8192, 1, 8}, // 0.02% - { 8704, 1, 7}, // 0.41% - { 9344, 1, 7}, // 0.21% - { 9984, 1, 6}, // 1.00% - { 10880, 1, 6}, // 0.41% - { 11904, 1, 5}, // 0.12% - { 13056, 1, 5}, // 0.41% - { 14464, 1, 4}, // 0.71% - { 16384, 1, 4}, // 0.02% - { 17408, 1, 3}, // 0.41% - { 20096, 1, 3}, // 0.36% - { 21760, 1, 3}, // 0.41% - { 23808, 1, 2}, // 0.12% - { 26112, 1, 2}, // 0.41% - { 29056, 1, 2}, // 0.26% - { 32768, 1, 2}, // 0.02% - { 37376, 1, 2}, // 0.21% - { 43648, 1, 2}, // 0.12% - { 45568, 2, 2}, // 4.61% - { 52352, 1, 2}, // 0.17% - { 56064, 2, 2}, // 3.92% - { 65536, 1, 2}, // 0.02% - { 74880, 2, 2}, // 0.03% - { 87296, 1, 2}, // 0.12% - { 104832, 2, 2}, // 0.03% - { 112256, 3, 2}, // 0.09% - { 131072, 1, 2}, // 0.02% - { 149760, 3, 2}, // 5.03% - { 174720, 2, 2}, // 0.03% - { 196608, 3, 2}, // 0.01% - { 209664, 4, 2}, // 0.03% - { 262144, 1, 2}, // 0.02% -}; -#elif TCMALLOC_PAGE_SHIFT == 12 -static_assert(kMaxSize == 8192, "kMaxSize mismatch"); -static const int kCount = 46; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalSizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalSizeClasses[SizeMap::kExperimentalSizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 1.17% - { 16, 1, 32}, // 1.17% - { 32, 1, 32}, // 1.17% - { 48, 1, 32}, // 1.57% - { 64, 1, 32}, // 1.17% - { 80, 1, 32}, // 1.57% - { 96, 1, 32}, // 2.78% - { 112, 1, 32}, // 2.78% - { 128, 1, 32}, // 1.17% - { 144, 1, 32}, // 2.78% - { 160, 1, 32}, // 3.60% - { 176, 1, 32}, // 2.37% - { 192, 1, 32}, // 2.78% - { 208, 1, 32}, // 4.86% - { 224, 1, 32}, // 2.78% - { 240, 1, 32}, // 1.57% - { 256, 1, 32}, // 1.17% - { 272, 1, 32}, // 1.57% - { 288, 1, 32}, // 2.78% - { 304, 1, 32}, // 4.86% - { 336, 1, 32}, // 2.78% - { 368, 1, 32}, // 2.37% - { 400, 1, 32}, // 3.60% - { 448, 1, 32}, // 2.78% - { 512, 1, 32}, // 1.17% - { 576, 2, 32}, // 2.18% - { 640, 2, 32}, // 7.29% - { 704, 2, 32}, // 6.40% - { 768, 2, 32}, // 7.29% - { 896, 2, 32}, // 2.18% - { 1024, 2, 32}, // 0.59% - { 1152, 3, 32}, // 7.08% - { 1280, 3, 32}, // 7.08% - { 1536, 3, 32}, // 0.39% - { 1792, 4, 32}, // 1.88% - { 2048, 4, 32}, // 0.29% - { 2304, 4, 28}, // 1.88% - { 2688, 4, 24}, // 1.88% - { 3200, 4, 20}, // 2.70% - { 3584, 7, 18}, // 0.17% - { 4096, 4, 16}, // 0.29% - { 4736, 5, 13}, // 8.36% - { 6144, 3, 10}, // 0.39% - { 7168, 7, 9}, // 0.17% - { 8192, 4, 8}, // 0.29% -}; -#else -#error "Unsupported TCMALLOC_PAGE_SHIFT value!" -#endif -#endif -// clang-format on - -} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/experimental_pow2_below64_size_class.cc b/contrib/libs/tcmalloc/tcmalloc/experimental_pow2_below64_size_class.cc deleted file mode 100755 index c6769f450ed9..000000000000 --- a/contrib/libs/tcmalloc/tcmalloc/experimental_pow2_below64_size_class.cc +++ /dev/null @@ -1,679 +0,0 @@ -// Copyright 2019 The TCMalloc Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "tcmalloc/common.h" - -GOOGLE_MALLOC_SECTION_BEGIN -namespace tcmalloc { - -namespace tcmalloc_internal { - -// is fixed per-size-class overhead due to end-of-span fragmentation -// and other factors. For instance, if we have a 96 byte size class, and use a -// single 8KiB page, then we will hold 85 objects per span, and have 32 bytes -// left over. There is also a fixed component of 48 bytes of TCMalloc metadata -// per span. Together, the fixed overhead would be wasted/allocated = -// (32 + 48) / (8192 - 32) ~= 0.98%. -// There is also a dynamic component to overhead based on mismatches between the -// number of bytes requested and the number of bytes provided by the size class. -// Together they sum to the total overhead; for instance if you asked for a -// 50-byte allocation that rounds up to a 64-byte size class, the dynamic -// overhead would be 28%, and if were 22% it would mean (on average) -// 25 bytes of overhead for allocations of that size. - -// clang-format off -#if defined(__cpp_aligned_new) && __STDCPP_DEFAULT_NEW_ALIGNMENT__ <= 8 -#if TCMALLOC_PAGE_SHIFT == 13 -static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 82; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2Below64SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2Below64SizeClasses[SizeMap::kExperimentalPow2Below64SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.59% - { 16, 1, 32}, // 0.59% - { 32, 1, 32}, // 0.59% - { 64, 1, 32}, // 0.59% - { 72, 1, 32}, // 1.28% - { 80, 1, 32}, // 0.98% - { 88, 1, 32}, // 0.68% - { 96, 1, 32}, // 0.98% - { 104, 1, 32}, // 1.58% - { 112, 1, 32}, // 0.78% - { 120, 1, 32}, // 0.98% - { 128, 1, 32}, // 0.59% - { 136, 1, 32}, // 0.98% - { 144, 1, 32}, // 2.18% - { 160, 1, 32}, // 0.98% - { 176, 1, 32}, // 1.78% - { 192, 1, 32}, // 2.18% - { 208, 1, 32}, // 1.58% - { 224, 1, 32}, // 2.18% - { 240, 1, 32}, // 0.98% - { 256, 1, 32}, // 0.59% - { 272, 1, 32}, // 0.98% - { 296, 1, 32}, // 3.10% - { 312, 1, 32}, // 1.58% - { 336, 1, 32}, // 2.18% - { 352, 1, 32}, // 1.78% - { 368, 1, 32}, // 1.78% - { 408, 1, 32}, // 0.98% - { 448, 1, 32}, // 2.18% - { 480, 1, 32}, // 0.98% - { 512, 1, 32}, // 0.59% - { 576, 1, 32}, // 2.18% - { 640, 1, 32}, // 7.29% - { 704, 1, 32}, // 6.40% - { 768, 1, 32}, // 7.29% - { 896, 1, 32}, // 2.18% - { 1024, 1, 32}, // 0.59% - { 1152, 2, 32}, // 1.88% - { 1280, 2, 32}, // 6.98% - { 1408, 2, 32}, // 6.10% - { 1536, 2, 32}, // 6.98% - { 1792, 2, 32}, // 1.88% - { 2048, 2, 32}, // 0.29% - { 2304, 2, 28}, // 1.88% - { 2688, 2, 24}, // 1.88% - { 2816, 3, 23}, // 9.30% - { 3200, 2, 20}, // 2.70% - { 3456, 3, 18}, // 1.79% - { 3584, 4, 18}, // 1.74% - { 4096, 1, 16}, // 0.29% - { 4736, 3, 13}, // 3.99% - { 5376, 2, 12}, // 1.88% - { 6144, 3, 10}, // 0.20% - { 6528, 4, 10}, // 0.54% - { 7168, 7, 9}, // 0.08% - { 8192, 1, 8}, // 0.29% - { 9472, 5, 6}, // 8.23% - { 10240, 4, 6}, // 6.82% - { 12288, 3, 5}, // 0.20% - { 13568, 5, 4}, // 0.75% - { 14336, 7, 4}, // 0.08% - { 16384, 2, 4}, // 0.29% - { 20480, 5, 3}, // 0.12% - { 24576, 3, 2}, // 0.20% - { 28672, 7, 2}, // 0.08% - { 32768, 4, 2}, // 0.15% - { 40960, 5, 2}, // 0.12% - { 49152, 6, 2}, // 0.10% - { 57344, 7, 2}, // 0.08% - { 65536, 8, 2}, // 0.07% - { 73728, 9, 2}, // 0.07% - { 81920, 10, 2}, // 0.06% - { 98304, 12, 2}, // 0.05% - { 114688, 14, 2}, // 0.04% - { 131072, 16, 2}, // 0.04% - { 147456, 18, 2}, // 0.03% - { 163840, 20, 2}, // 0.03% - { 180224, 22, 2}, // 0.03% - { 204800, 25, 2}, // 0.02% - { 237568, 29, 2}, // 0.02% - { 262144, 32, 2}, // 0.02% -}; -#elif TCMALLOC_PAGE_SHIFT == 15 -static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 74; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2Below64SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2Below64SizeClasses[SizeMap::kExperimentalPow2Below64SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.15% - { 16, 1, 32}, // 0.15% - { 32, 1, 32}, // 0.15% - { 64, 1, 32}, // 0.15% - { 72, 1, 32}, // 0.17% - { 80, 1, 32}, // 0.29% - { 88, 1, 32}, // 0.24% - { 96, 1, 32}, // 0.24% - { 104, 1, 32}, // 0.17% - { 112, 1, 32}, // 0.34% - { 128, 1, 32}, // 0.15% - { 144, 1, 32}, // 0.39% - { 160, 1, 32}, // 0.54% - { 176, 1, 32}, // 0.24% - { 192, 1, 32}, // 0.54% - { 208, 1, 32}, // 0.49% - { 224, 1, 32}, // 0.34% - { 240, 1, 32}, // 0.54% - { 256, 1, 32}, // 0.15% - { 280, 1, 32}, // 0.17% - { 304, 1, 32}, // 0.89% - { 328, 1, 32}, // 1.06% - { 352, 1, 32}, // 0.24% - { 384, 1, 32}, // 0.54% - { 416, 1, 32}, // 1.13% - { 448, 1, 32}, // 0.34% - { 488, 1, 32}, // 0.37% - { 512, 1, 32}, // 0.15% - { 576, 1, 32}, // 1.74% - { 640, 1, 32}, // 0.54% - { 704, 1, 32}, // 1.33% - { 832, 1, 32}, // 1.13% - { 896, 1, 32}, // 1.74% - { 1024, 1, 32}, // 0.15% - { 1152, 1, 32}, // 1.74% - { 1280, 1, 32}, // 2.55% - { 1536, 1, 32}, // 1.74% - { 1792, 1, 32}, // 1.74% - { 2048, 1, 32}, // 0.15% - { 2176, 1, 30}, // 0.54% - { 2304, 1, 28}, // 1.74% - { 2688, 1, 24}, // 1.74% - { 2944, 1, 22}, // 1.33% - { 3200, 1, 20}, // 2.55% - { 3584, 1, 18}, // 1.74% - { 4096, 1, 16}, // 0.15% - { 4608, 1, 14}, // 1.74% - { 5376, 1, 12}, // 1.74% - { 6528, 1, 10}, // 0.54% - { 7168, 2, 9}, // 1.66% - { 8192, 1, 8}, // 0.15% - { 9344, 2, 7}, // 0.27% - { 10880, 1, 6}, // 0.54% - { 13952, 3, 4}, // 0.70% - { 16384, 1, 4}, // 0.15% - { 19072, 3, 3}, // 3.14% - { 21760, 2, 3}, // 0.47% - { 24576, 3, 2}, // 0.05% - { 28032, 6, 2}, // 0.22% - { 32768, 1, 2}, // 0.15% - { 38144, 5, 2}, // 7.41% - { 40960, 4, 2}, // 6.71% - { 49152, 3, 2}, // 0.05% - { 57344, 7, 2}, // 0.02% - { 65536, 2, 2}, // 0.07% - { 81920, 5, 2}, // 0.03% - { 98304, 3, 2}, // 0.05% - { 114688, 7, 2}, // 0.02% - { 131072, 4, 2}, // 0.04% - { 163840, 5, 2}, // 0.03% - { 196608, 6, 2}, // 0.02% - { 229376, 7, 2}, // 0.02% - { 262144, 8, 2}, // 0.02% -}; -#elif TCMALLOC_PAGE_SHIFT == 18 -static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 85; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2Below64SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2Below64SizeClasses[SizeMap::kExperimentalPow2Below64SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.02% - { 16, 1, 32}, // 0.02% - { 32, 1, 32}, // 0.02% - { 64, 1, 32}, // 0.02% - { 72, 1, 32}, // 0.04% - { 80, 1, 32}, // 0.04% - { 88, 1, 32}, // 0.05% - { 96, 1, 32}, // 0.04% - { 104, 1, 32}, // 0.04% - { 112, 1, 32}, // 0.04% - { 128, 1, 32}, // 0.02% - { 144, 1, 32}, // 0.04% - { 160, 1, 32}, // 0.04% - { 176, 1, 32}, // 0.05% - { 192, 1, 32}, // 0.04% - { 208, 1, 32}, // 0.04% - { 240, 1, 32}, // 0.04% - { 256, 1, 32}, // 0.02% - { 304, 1, 32}, // 0.05% - { 336, 1, 32}, // 0.04% - { 360, 1, 32}, // 0.04% - { 408, 1, 32}, // 0.10% - { 456, 1, 32}, // 0.17% - { 512, 1, 32}, // 0.02% - { 576, 1, 32}, // 0.04% - { 640, 1, 32}, // 0.17% - { 704, 1, 32}, // 0.12% - { 768, 1, 32}, // 0.12% - { 832, 1, 32}, // 0.04% - { 896, 1, 32}, // 0.21% - { 1024, 1, 32}, // 0.02% - { 1152, 1, 32}, // 0.26% - { 1280, 1, 32}, // 0.41% - { 1536, 1, 32}, // 0.41% - { 1664, 1, 32}, // 0.36% - { 1792, 1, 32}, // 0.21% - { 1920, 1, 32}, // 0.41% - { 2048, 1, 32}, // 0.02% - { 2176, 1, 30}, // 0.41% - { 2304, 1, 28}, // 0.71% - { 2432, 1, 26}, // 0.76% - { 2560, 1, 25}, // 0.41% - { 2688, 1, 24}, // 0.56% - { 2816, 1, 23}, // 0.12% - { 2944, 1, 22}, // 0.07% - { 3072, 1, 21}, // 0.41% - { 3328, 1, 19}, // 1.00% - { 3584, 1, 18}, // 0.21% - { 3840, 1, 17}, // 0.41% - { 4096, 1, 16}, // 0.02% - { 4736, 1, 13}, // 0.66% - { 5504, 1, 11}, // 1.35% - { 6144, 1, 10}, // 1.61% - { 6528, 1, 10}, // 0.41% - { 6784, 1, 9}, // 1.71% - { 7168, 1, 9}, // 1.61% - { 7680, 1, 8}, // 0.41% - { 8192, 1, 8}, // 0.02% - { 8704, 1, 7}, // 0.41% - { 9344, 1, 7}, // 0.21% - { 10880, 1, 6}, // 0.41% - { 11904, 1, 5}, // 0.12% - { 13056, 1, 5}, // 0.41% - { 14464, 1, 4}, // 0.71% - { 16384, 1, 4}, // 0.02% - { 18688, 1, 3}, // 0.21% - { 21760, 1, 3}, // 0.41% - { 26112, 1, 2}, // 0.41% - { 29056, 1, 2}, // 0.26% - { 32768, 1, 2}, // 0.02% - { 37376, 1, 2}, // 0.21% - { 43648, 1, 2}, // 0.12% - { 52352, 1, 2}, // 0.17% - { 56064, 2, 2}, // 3.92% - { 65536, 1, 2}, // 0.02% - { 74880, 2, 2}, // 0.03% - { 87296, 1, 2}, // 0.12% - { 104832, 2, 2}, // 0.03% - { 112256, 3, 2}, // 0.09% - { 131072, 1, 2}, // 0.02% - { 149760, 3, 2}, // 5.03% - { 174720, 2, 2}, // 0.03% - { 209664, 4, 2}, // 0.03% - { 262144, 1, 2}, // 0.02% -}; -#elif TCMALLOC_PAGE_SHIFT == 12 -static_assert(kMaxSize == 8192, "kMaxSize mismatch"); -static const int kCount = 42; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2Below64SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2Below64SizeClasses[SizeMap::kExperimentalPow2Below64SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 1.17% - { 16, 1, 32}, // 1.17% - { 32, 1, 32}, // 1.17% - { 64, 1, 32}, // 1.17% - { 72, 1, 32}, // 2.78% - { 80, 1, 32}, // 1.57% - { 88, 1, 32}, // 2.37% - { 96, 1, 32}, // 2.78% - { 104, 1, 32}, // 2.17% - { 120, 1, 32}, // 1.57% - { 128, 1, 32}, // 1.17% - { 144, 1, 32}, // 2.78% - { 160, 1, 32}, // 3.60% - { 184, 1, 32}, // 2.37% - { 208, 1, 32}, // 4.86% - { 240, 1, 32}, // 1.57% - { 256, 1, 32}, // 1.17% - { 272, 1, 32}, // 1.57% - { 312, 1, 32}, // 2.17% - { 336, 1, 32}, // 2.78% - { 368, 1, 32}, // 2.37% - { 408, 1, 32}, // 1.57% - { 512, 1, 32}, // 1.17% - { 576, 2, 32}, // 2.18% - { 704, 2, 32}, // 6.40% - { 768, 2, 32}, // 7.29% - { 896, 2, 32}, // 2.18% - { 1024, 2, 32}, // 0.59% - { 1152, 3, 32}, // 7.08% - { 1280, 3, 32}, // 7.08% - { 1536, 3, 32}, // 0.39% - { 1792, 4, 32}, // 1.88% - { 2048, 4, 32}, // 0.29% - { 2304, 4, 28}, // 1.88% - { 2688, 4, 24}, // 1.88% - { 3456, 6, 18}, // 1.79% - { 4096, 4, 16}, // 0.29% - { 5376, 4, 12}, // 1.88% - { 6144, 3, 10}, // 0.39% - { 7168, 7, 9}, // 0.17% - { 8192, 4, 8}, // 0.29% -}; -#else -#error "Unsupported TCMALLOC_PAGE_SHIFT value!" -#endif -#else -#if TCMALLOC_PAGE_SHIFT == 13 -static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 82; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2Below64SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2Below64SizeClasses[SizeMap::kExperimentalPow2Below64SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.59% - { 16, 1, 32}, // 0.59% - { 32, 1, 32}, // 0.59% - { 64, 1, 32}, // 0.59% - { 80, 1, 32}, // 0.98% - { 96, 1, 32}, // 0.98% - { 112, 1, 32}, // 0.78% - { 128, 1, 32}, // 0.59% - { 144, 1, 32}, // 2.18% - { 160, 1, 32}, // 0.98% - { 176, 1, 32}, // 1.78% - { 192, 1, 32}, // 2.18% - { 208, 1, 32}, // 1.58% - { 224, 1, 32}, // 2.18% - { 240, 1, 32}, // 0.98% - { 256, 1, 32}, // 0.59% - { 272, 1, 32}, // 0.98% - { 288, 1, 32}, // 2.18% - { 304, 1, 32}, // 4.25% - { 320, 1, 32}, // 3.00% - { 336, 1, 32}, // 2.18% - { 352, 1, 32}, // 1.78% - { 368, 1, 32}, // 1.78% - { 384, 1, 32}, // 2.18% - { 400, 1, 32}, // 3.00% - { 416, 1, 32}, // 4.25% - { 448, 1, 32}, // 2.18% - { 480, 1, 32}, // 0.98% - { 512, 1, 32}, // 0.59% - { 576, 1, 32}, // 2.18% - { 640, 1, 32}, // 7.29% - { 704, 1, 32}, // 6.40% - { 768, 1, 32}, // 7.29% - { 896, 1, 32}, // 2.18% - { 1024, 1, 32}, // 0.59% - { 1152, 2, 32}, // 1.88% - { 1280, 2, 32}, // 6.98% - { 1408, 2, 32}, // 6.10% - { 1536, 2, 32}, // 6.98% - { 1792, 2, 32}, // 1.88% - { 2048, 2, 32}, // 0.29% - { 2304, 2, 28}, // 1.88% - { 2688, 2, 24}, // 1.88% - { 2816, 3, 23}, // 9.30% - { 3200, 2, 20}, // 2.70% - { 3456, 3, 18}, // 1.79% - { 3584, 4, 18}, // 1.74% - { 4096, 1, 16}, // 0.29% - { 4736, 3, 13}, // 3.99% - { 5376, 2, 12}, // 1.88% - { 6144, 3, 10}, // 0.20% - { 6528, 4, 10}, // 0.54% - { 7168, 7, 9}, // 0.08% - { 8192, 1, 8}, // 0.29% - { 9472, 5, 6}, // 8.23% - { 10240, 4, 6}, // 6.82% - { 12288, 3, 5}, // 0.20% - { 13568, 5, 4}, // 0.75% - { 14336, 7, 4}, // 0.08% - { 16384, 2, 4}, // 0.29% - { 20480, 5, 3}, // 0.12% - { 24576, 3, 2}, // 0.20% - { 28672, 7, 2}, // 0.08% - { 32768, 4, 2}, // 0.15% - { 40960, 5, 2}, // 0.12% - { 49152, 6, 2}, // 0.10% - { 57344, 7, 2}, // 0.08% - { 65536, 8, 2}, // 0.07% - { 73728, 9, 2}, // 0.07% - { 81920, 10, 2}, // 0.06% - { 90112, 11, 2}, // 0.05% - { 98304, 12, 2}, // 0.05% - { 106496, 13, 2}, // 0.05% - { 114688, 14, 2}, // 0.04% - { 131072, 16, 2}, // 0.04% - { 147456, 18, 2}, // 0.03% - { 163840, 20, 2}, // 0.03% - { 180224, 22, 2}, // 0.03% - { 204800, 25, 2}, // 0.02% - { 237568, 29, 2}, // 0.02% - { 262144, 32, 2}, // 0.02% -}; -#elif TCMALLOC_PAGE_SHIFT == 15 -static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 74; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2Below64SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2Below64SizeClasses[SizeMap::kExperimentalPow2Below64SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.15% - { 16, 1, 32}, // 0.15% - { 32, 1, 32}, // 0.15% - { 64, 1, 32}, // 0.15% - { 80, 1, 32}, // 0.29% - { 96, 1, 32}, // 0.24% - { 112, 1, 32}, // 0.34% - { 128, 1, 32}, // 0.15% - { 144, 1, 32}, // 0.39% - { 160, 1, 32}, // 0.54% - { 176, 1, 32}, // 0.24% - { 192, 1, 32}, // 0.54% - { 208, 1, 32}, // 0.49% - { 224, 1, 32}, // 0.34% - { 240, 1, 32}, // 0.54% - { 256, 1, 32}, // 0.15% - { 272, 1, 32}, // 0.54% - { 288, 1, 32}, // 0.84% - { 304, 1, 32}, // 0.89% - { 320, 1, 32}, // 0.54% - { 352, 1, 32}, // 0.24% - { 384, 1, 32}, // 0.54% - { 416, 1, 32}, // 1.13% - { 448, 1, 32}, // 0.34% - { 480, 1, 32}, // 0.54% - { 512, 1, 32}, // 0.15% - { 576, 1, 32}, // 1.74% - { 640, 1, 32}, // 0.54% - { 704, 1, 32}, // 1.33% - { 768, 1, 32}, // 1.74% - { 832, 1, 32}, // 1.13% - { 896, 1, 32}, // 1.74% - { 1024, 1, 32}, // 0.15% - { 1152, 1, 32}, // 1.74% - { 1280, 1, 32}, // 2.55% - { 1408, 1, 32}, // 1.33% - { 1536, 1, 32}, // 1.74% - { 1792, 1, 32}, // 1.74% - { 2048, 1, 32}, // 0.15% - { 2176, 1, 30}, // 0.54% - { 2304, 1, 28}, // 1.74% - { 2688, 1, 24}, // 1.74% - { 2944, 1, 22}, // 1.33% - { 3200, 1, 20}, // 2.55% - { 3584, 1, 18}, // 1.74% - { 4096, 1, 16}, // 0.15% - { 4608, 1, 14}, // 1.74% - { 5376, 1, 12}, // 1.74% - { 6528, 1, 10}, // 0.54% - { 7168, 2, 9}, // 1.66% - { 8192, 1, 8}, // 0.15% - { 9344, 2, 7}, // 0.27% - { 10880, 1, 6}, // 0.54% - { 13952, 3, 4}, // 0.70% - { 16384, 1, 4}, // 0.15% - { 19072, 3, 3}, // 3.14% - { 21760, 2, 3}, // 0.47% - { 24576, 3, 2}, // 0.05% - { 28032, 6, 2}, // 0.22% - { 32768, 1, 2}, // 0.15% - { 38144, 5, 2}, // 7.41% - { 40960, 4, 2}, // 6.71% - { 49152, 3, 2}, // 0.05% - { 57344, 7, 2}, // 0.02% - { 65536, 2, 2}, // 0.07% - { 81920, 5, 2}, // 0.03% - { 98304, 3, 2}, // 0.05% - { 114688, 7, 2}, // 0.02% - { 131072, 4, 2}, // 0.04% - { 163840, 5, 2}, // 0.03% - { 196608, 6, 2}, // 0.02% - { 229376, 7, 2}, // 0.02% - { 262144, 8, 2}, // 0.02% -}; -#elif TCMALLOC_PAGE_SHIFT == 18 -static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 85; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2Below64SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2Below64SizeClasses[SizeMap::kExperimentalPow2Below64SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.02% - { 16, 1, 32}, // 0.02% - { 32, 1, 32}, // 0.02% - { 64, 1, 32}, // 0.02% - { 80, 1, 32}, // 0.04% - { 96, 1, 32}, // 0.04% - { 112, 1, 32}, // 0.04% - { 128, 1, 32}, // 0.02% - { 144, 1, 32}, // 0.04% - { 160, 1, 32}, // 0.04% - { 176, 1, 32}, // 0.05% - { 192, 1, 32}, // 0.04% - { 208, 1, 32}, // 0.04% - { 240, 1, 32}, // 0.04% - { 256, 1, 32}, // 0.02% - { 304, 1, 32}, // 0.05% - { 336, 1, 32}, // 0.04% - { 368, 1, 32}, // 0.07% - { 416, 1, 32}, // 0.04% - { 464, 1, 32}, // 0.19% - { 512, 1, 32}, // 0.02% - { 576, 1, 32}, // 0.04% - { 640, 1, 32}, // 0.17% - { 704, 1, 32}, // 0.12% - { 768, 1, 32}, // 0.12% - { 832, 1, 32}, // 0.04% - { 896, 1, 32}, // 0.21% - { 1024, 1, 32}, // 0.02% - { 1152, 1, 32}, // 0.26% - { 1280, 1, 32}, // 0.41% - { 1408, 1, 32}, // 0.12% - { 1536, 1, 32}, // 0.41% - { 1664, 1, 32}, // 0.36% - { 1792, 1, 32}, // 0.21% - { 1920, 1, 32}, // 0.41% - { 2048, 1, 32}, // 0.02% - { 2176, 1, 30}, // 0.41% - { 2304, 1, 28}, // 0.71% - { 2432, 1, 26}, // 0.76% - { 2560, 1, 25}, // 0.41% - { 2688, 1, 24}, // 0.56% - { 2816, 1, 23}, // 0.12% - { 2944, 1, 22}, // 0.07% - { 3072, 1, 21}, // 0.41% - { 3200, 1, 20}, // 1.15% - { 3328, 1, 19}, // 1.00% - { 3584, 1, 18}, // 0.21% - { 3840, 1, 17}, // 0.41% - { 4096, 1, 16}, // 0.02% - { 4736, 1, 13}, // 0.66% - { 5504, 1, 11}, // 1.35% - { 6144, 1, 10}, // 1.61% - { 6528, 1, 10}, // 0.41% - { 6784, 1, 9}, // 1.71% - { 7168, 1, 9}, // 1.61% - { 7680, 1, 8}, // 0.41% - { 8192, 1, 8}, // 0.02% - { 8704, 1, 7}, // 0.41% - { 9344, 1, 7}, // 0.21% - { 10368, 1, 6}, // 1.15% - { 11392, 1, 5}, // 0.07% - { 12416, 1, 5}, // 0.56% - { 13696, 1, 4}, // 0.76% - { 14464, 1, 4}, // 0.71% - { 16384, 1, 4}, // 0.02% - { 18688, 1, 3}, // 0.21% - { 21760, 1, 3}, // 0.41% - { 26112, 1, 2}, // 0.41% - { 29056, 1, 2}, // 0.26% - { 32768, 1, 2}, // 0.02% - { 37376, 1, 2}, // 0.21% - { 43648, 1, 2}, // 0.12% - { 52352, 1, 2}, // 0.17% - { 56064, 2, 2}, // 3.92% - { 65536, 1, 2}, // 0.02% - { 74880, 2, 2}, // 0.03% - { 87296, 1, 2}, // 0.12% - { 104832, 2, 2}, // 0.03% - { 112256, 3, 2}, // 0.09% - { 131072, 1, 2}, // 0.02% - { 149760, 3, 2}, // 5.03% - { 174720, 2, 2}, // 0.03% - { 209664, 4, 2}, // 0.03% - { 262144, 1, 2}, // 0.02% -}; -#elif TCMALLOC_PAGE_SHIFT == 12 -static_assert(kMaxSize == 8192, "kMaxSize mismatch"); -static const int kCount = 42; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2Below64SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2Below64SizeClasses[SizeMap::kExperimentalPow2Below64SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 1.17% - { 16, 1, 32}, // 1.17% - { 32, 1, 32}, // 1.17% - { 64, 1, 32}, // 1.17% - { 80, 1, 32}, // 1.57% - { 96, 1, 32}, // 2.78% - { 112, 1, 32}, // 2.78% - { 128, 1, 32}, // 1.17% - { 144, 1, 32}, // 2.78% - { 160, 1, 32}, // 3.60% - { 176, 1, 32}, // 2.37% - { 192, 1, 32}, // 2.78% - { 208, 1, 32}, // 4.86% - { 240, 1, 32}, // 1.57% - { 256, 1, 32}, // 1.17% - { 272, 1, 32}, // 1.57% - { 304, 1, 32}, // 4.86% - { 336, 1, 32}, // 2.78% - { 368, 1, 32}, // 2.37% - { 400, 1, 32}, // 3.60% - { 448, 1, 32}, // 2.78% - { 512, 1, 32}, // 1.17% - { 576, 2, 32}, // 2.18% - { 640, 2, 32}, // 7.29% - { 704, 2, 32}, // 6.40% - { 768, 2, 32}, // 7.29% - { 896, 2, 32}, // 2.18% - { 1024, 2, 32}, // 0.59% - { 1152, 3, 32}, // 7.08% - { 1280, 3, 32}, // 7.08% - { 1536, 3, 32}, // 0.39% - { 1792, 4, 32}, // 1.88% - { 2048, 4, 32}, // 0.29% - { 2304, 4, 28}, // 1.88% - { 2688, 4, 24}, // 1.88% - { 3456, 6, 18}, // 1.79% - { 4096, 4, 16}, // 0.29% - { 5376, 4, 12}, // 1.88% - { 6144, 3, 10}, // 0.39% - { 7168, 7, 9}, // 0.17% - { 8192, 4, 8}, // 0.29% -}; -#else -#error "Unsupported TCMALLOC_PAGE_SHIFT value!" -#endif -#endif -// clang-format on - -} // namespace tcmalloc_internal -} // namespace tcmalloc -GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/experimental_pow2_size_class.cc b/contrib/libs/tcmalloc/tcmalloc/experimental_pow2_size_class.cc old mode 100755 new mode 100644 index 1e6da051cae2..a24e95d9aeb2 --- a/contrib/libs/tcmalloc/tcmalloc/experimental_pow2_size_class.cc +++ b/contrib/libs/tcmalloc/tcmalloc/experimental_pow2_size_class.cc @@ -12,122 +12,153 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "absl/types/span.h" #include "tcmalloc/common.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/size_class_info.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { - namespace tcmalloc_internal { -// is fixed per-size-class overhead due to end-of-span fragmentation -// and other factors. For instance, if we have a 96 byte size class, and use a -// single 8KiB page, then we will hold 85 objects per span, and have 32 bytes -// left over. There is also a fixed component of 48 bytes of TCMalloc metadata -// per span. Together, the fixed overhead would be wasted/allocated = -// (32 + 48) / (8192 - 32) ~= 0.98%. -// There is also a dynamic component to overhead based on mismatches between the -// number of bytes requested and the number of bytes provided by the size class. -// Together they sum to the total overhead; for instance if you asked for a -// 50-byte allocation that rounds up to a 64-byte size class, the dynamic -// overhead would be 28%, and if were 22% it would mean (on average) -// 25 bytes of overhead for allocations of that size. +// Columns in the following tables: +// - bytes: size of the size class +// - pages: number of pages per span +// - batch: preferred number of objects for transfers between caches +// - class: size class number +// - objs: number of objects per span +// - waste/fixed: fixed per-size-class overhead due to end-of-span fragmentation +// and other factors. For instance, if we have a 96 byte size class, and use +// a single 8KiB page, then we will hold 85 objects per span, and have 32 +// bytes left over. There is also a fixed component of 48 bytes of TCMalloc +// metadata per span. Together, the fixed overhead would be wasted/allocated +// = (32 + 48) / (8192 - 32) ~= 0.98%. +// - waste/sampling: overhead due to heap sampling +// (rounding to page size, proxy object, metadata). +// - inc: increment from the previous size class. This caps the dynamic +// overhead component based on mismatches between the number of bytes +// requested and the number of bytes provided by the size class. Together +// they sum to the total overhead; for instance if you asked for a 50-byte +// allocation that rounds up to a 64-byte size class, the dynamic overhead +// would be 28%, and if waste were 22% it would mean (on average) 25 bytes +// of overhead for allocations of that size. // clang-format off #if defined(__cpp_aligned_new) && __STDCPP_DEFAULT_NEW_ALIGNMENT__ <= 8 #if TCMALLOC_PAGE_SHIFT == 13 static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 17; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2SizeClasses[SizeMap::kExperimentalPow2SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.59% - { 16, 1, 32}, // 0.59% - { 32, 1, 32}, // 0.59% - { 64, 1, 32}, // 0.59% - { 128, 1, 32}, // 0.59% - { 256, 1, 32}, // 0.59% - { 512, 1, 32}, // 0.59% - { 1024, 1, 32}, // 0.59% - { 2048, 2, 32}, // 0.29% - { 4096, 1, 16}, // 0.29% - { 8192, 1, 8}, // 0.29% - { 16384, 2, 4}, // 0.29% - { 32768, 4, 2}, // 0.15% - { 65536, 8, 2}, // 0.07% - { 131072, 16, 2}, // 0.04% - { 262144, 32, 2}, // 0.02% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = true, + .span_size = 48, + .sampling_interval = 2097152, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 1024 0.58% 0.42% 0.00% + { 16, 1, 32}, // 1 512 0.58% 0.42% 100.00% + { 32, 1, 32}, // 2 256 0.58% 0.42% 100.00% + { 64, 1, 32}, // 3 128 0.58% 0.42% 100.00% + { 128, 1, 32}, // 4 64 0.58% 0.42% 100.00% + { 256, 1, 32}, // 5 32 0.58% 0.42% 100.00% + { 512, 1, 32}, // 6 16 0.58% 0.42% 100.00% + { 1024, 1, 32}, // 7 8 0.58% 0.42% 100.00% + { 2048, 2, 32}, // 8 8 0.29% 0.42% 100.00% + { 4096, 1, 16}, // 9 2 0.58% 0.43% 100.00% + { 8192, 1, 8}, // 10 1 0.58% 0.03% 100.00% + { 16384, 2, 4}, // 11 1 0.29% 0.03% 100.00% + { 32768, 4, 2}, // 12 1 0.15% 0.03% 100.00% + { 65536, 8, 2}, // 13 1 0.07% 0.03% 100.00% + {131072, 16, 2}, // 14 1 0.04% 0.03% 100.00% + {262144, 32, 2}, // 15 1 0.02% 0.03% 100.00% }; #elif TCMALLOC_PAGE_SHIFT == 15 static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 17; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2SizeClasses[SizeMap::kExperimentalPow2SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.15% - { 16, 1, 32}, // 0.15% - { 32, 1, 32}, // 0.15% - { 64, 1, 32}, // 0.15% - { 128, 1, 32}, // 0.15% - { 256, 1, 32}, // 0.15% - { 512, 1, 32}, // 0.15% - { 1024, 1, 32}, // 0.15% - { 2048, 1, 32}, // 0.15% - { 4096, 1, 16}, // 0.15% - { 8192, 1, 8}, // 0.15% - { 16384, 1, 4}, // 0.15% - { 32768, 1, 2}, // 0.15% - { 65536, 2, 2}, // 0.07% - { 131072, 4, 2}, // 0.04% - { 262144, 8, 2}, // 0.02% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = true, + .span_size = 48, + .sampling_interval = 2097152, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 4096 0.15% 1.60% 0.00% + { 16, 1, 32}, // 1 2048 0.15% 1.60% 100.00% + { 32, 1, 32}, // 2 1024 0.15% 1.60% 100.00% + { 64, 1, 32}, // 3 512 0.15% 1.60% 100.00% + { 128, 1, 32}, // 4 256 0.15% 1.60% 100.00% + { 256, 1, 32}, // 5 128 0.15% 1.60% 100.00% + { 512, 1, 32}, // 6 64 0.15% 1.60% 100.00% + { 1024, 1, 32}, // 7 32 0.15% 1.60% 100.00% + { 2048, 1, 32}, // 8 16 0.15% 1.60% 100.00% + { 4096, 1, 16}, // 9 8 0.15% 1.60% 100.00% + { 8192, 1, 8}, // 10 4 0.15% 1.60% 100.00% + { 16384, 1, 4}, // 11 2 0.15% 1.60% 100.00% + { 32768, 1, 2}, // 12 1 0.15% 0.03% 100.00% + { 65536, 2, 2}, // 13 1 0.07% 0.03% 100.00% + {131072, 4, 2}, // 14 1 0.04% 0.03% 100.00% + {262144, 8, 2}, // 15 1 0.02% 0.03% 100.00% }; #elif TCMALLOC_PAGE_SHIFT == 18 static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 17; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2SizeClasses[SizeMap::kExperimentalPow2SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.02% - { 16, 1, 32}, // 0.02% - { 32, 1, 32}, // 0.02% - { 64, 1, 32}, // 0.02% - { 128, 1, 32}, // 0.02% - { 256, 1, 32}, // 0.02% - { 512, 1, 32}, // 0.02% - { 1024, 1, 32}, // 0.02% - { 2048, 1, 32}, // 0.02% - { 4096, 1, 16}, // 0.02% - { 8192, 1, 8}, // 0.02% - { 16384, 1, 4}, // 0.02% - { 32768, 1, 2}, // 0.02% - { 65536, 1, 2}, // 0.02% - { 131072, 1, 2}, // 0.02% - { 262144, 1, 2}, // 0.02% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = true, + .span_size = 48, + .sampling_interval = 2097152, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 32768 0.02% 12.53% 0.00% + { 16, 1, 32}, // 1 16384 0.02% 12.53% 100.00% + { 32, 1, 32}, // 2 8192 0.02% 12.53% 100.00% + { 64, 1, 32}, // 3 4096 0.02% 12.53% 100.00% + { 128, 1, 32}, // 4 2048 0.02% 12.53% 100.00% + { 256, 1, 32}, // 5 1024 0.02% 12.53% 100.00% + { 512, 1, 32}, // 6 512 0.02% 12.53% 100.00% + { 1024, 1, 32}, // 7 256 0.02% 12.53% 100.00% + { 2048, 1, 32}, // 8 128 0.02% 12.53% 100.00% + { 4096, 1, 16}, // 9 64 0.02% 12.53% 100.00% + { 8192, 1, 8}, // 10 32 0.02% 12.53% 100.00% + { 16384, 1, 4}, // 11 16 0.02% 12.53% 100.00% + { 32768, 1, 2}, // 12 8 0.02% 12.53% 100.00% + { 65536, 1, 2}, // 13 4 0.02% 12.53% 100.00% + {131072, 1, 2}, // 14 2 0.02% 12.53% 100.00% + {262144, 1, 2}, // 15 1 0.02% 0.03% 100.00% }; #elif TCMALLOC_PAGE_SHIFT == 12 static_assert(kMaxSize == 8192, "kMaxSize mismatch"); -static const int kCount = 12; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2SizeClasses[SizeMap::kExperimentalPow2SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 1.17% - { 16, 1, 32}, // 1.17% - { 32, 1, 32}, // 1.17% - { 64, 1, 32}, // 1.17% - { 128, 1, 32}, // 1.17% - { 256, 1, 32}, // 1.17% - { 512, 1, 32}, // 1.17% - { 1024, 2, 32}, // 0.59% - { 2048, 4, 32}, // 0.29% - { 4096, 4, 16}, // 0.29% - { 8192, 4, 8}, // 0.29% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = false, + .span_size = 48, + .sampling_interval = 524288, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 512 1.16% 0.92% 0.00% + { 16, 1, 32}, // 1 256 1.16% 0.92% 100.00% + { 32, 1, 32}, // 2 128 1.16% 0.92% 100.00% + { 64, 1, 32}, // 3 64 1.16% 0.92% 100.00% + { 128, 1, 32}, // 4 32 1.16% 0.92% 100.00% + { 256, 1, 32}, // 5 16 1.16% 0.92% 100.00% + { 512, 1, 32}, // 6 8 1.16% 0.92% 100.00% + { 1024, 2, 32}, // 7 8 0.58% 0.92% 100.00% + { 2048, 4, 32}, // 8 8 0.29% 0.92% 100.00% + { 4096, 4, 16}, // 9 4 0.29% 0.92% 100.00% + { 8192, 4, 8}, // 10 2 0.29% 1.70% 100.00% }; #else #error "Unsupported TCMALLOC_PAGE_SHIFT value!" @@ -135,98 +166,118 @@ const SizeClassInfo SizeMap::kExperimentalPow2SizeClasses[SizeMap::kExperimental #else #if TCMALLOC_PAGE_SHIFT == 13 static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 17; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2SizeClasses[SizeMap::kExperimentalPow2SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.59% - { 16, 1, 32}, // 0.59% - { 32, 1, 32}, // 0.59% - { 64, 1, 32}, // 0.59% - { 128, 1, 32}, // 0.59% - { 256, 1, 32}, // 0.59% - { 512, 1, 32}, // 0.59% - { 1024, 1, 32}, // 0.59% - { 2048, 2, 32}, // 0.29% - { 4096, 1, 16}, // 0.29% - { 8192, 1, 8}, // 0.29% - { 16384, 2, 4}, // 0.29% - { 32768, 4, 2}, // 0.15% - { 65536, 8, 2}, // 0.07% - { 131072, 16, 2}, // 0.04% - { 262144, 32, 2}, // 0.02% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = true, + .span_size = 48, + .sampling_interval = 2097152, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 1024 0.58% 0.42% 0.00% + { 16, 1, 32}, // 1 512 0.58% 0.42% 100.00% + { 32, 1, 32}, // 2 256 0.58% 0.42% 100.00% + { 64, 1, 32}, // 3 128 0.58% 0.42% 100.00% + { 128, 1, 32}, // 4 64 0.58% 0.42% 100.00% + { 256, 1, 32}, // 5 32 0.58% 0.42% 100.00% + { 512, 1, 32}, // 6 16 0.58% 0.42% 100.00% + { 1024, 1, 32}, // 7 8 0.58% 0.42% 100.00% + { 2048, 2, 32}, // 8 8 0.29% 0.42% 100.00% + { 4096, 1, 16}, // 9 2 0.58% 0.43% 100.00% + { 8192, 1, 8}, // 10 1 0.58% 0.03% 100.00% + { 16384, 2, 4}, // 11 1 0.29% 0.03% 100.00% + { 32768, 4, 2}, // 12 1 0.15% 0.03% 100.00% + { 65536, 8, 2}, // 13 1 0.07% 0.03% 100.00% + {131072, 16, 2}, // 14 1 0.04% 0.03% 100.00% + {262144, 32, 2}, // 15 1 0.02% 0.03% 100.00% }; #elif TCMALLOC_PAGE_SHIFT == 15 static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 17; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2SizeClasses[SizeMap::kExperimentalPow2SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.15% - { 16, 1, 32}, // 0.15% - { 32, 1, 32}, // 0.15% - { 64, 1, 32}, // 0.15% - { 128, 1, 32}, // 0.15% - { 256, 1, 32}, // 0.15% - { 512, 1, 32}, // 0.15% - { 1024, 1, 32}, // 0.15% - { 2048, 1, 32}, // 0.15% - { 4096, 1, 16}, // 0.15% - { 8192, 1, 8}, // 0.15% - { 16384, 1, 4}, // 0.15% - { 32768, 1, 2}, // 0.15% - { 65536, 2, 2}, // 0.07% - { 131072, 4, 2}, // 0.04% - { 262144, 8, 2}, // 0.02% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = true, + .span_size = 48, + .sampling_interval = 2097152, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 4096 0.15% 1.60% 0.00% + { 16, 1, 32}, // 1 2048 0.15% 1.60% 100.00% + { 32, 1, 32}, // 2 1024 0.15% 1.60% 100.00% + { 64, 1, 32}, // 3 512 0.15% 1.60% 100.00% + { 128, 1, 32}, // 4 256 0.15% 1.60% 100.00% + { 256, 1, 32}, // 5 128 0.15% 1.60% 100.00% + { 512, 1, 32}, // 6 64 0.15% 1.60% 100.00% + { 1024, 1, 32}, // 7 32 0.15% 1.60% 100.00% + { 2048, 1, 32}, // 8 16 0.15% 1.60% 100.00% + { 4096, 1, 16}, // 9 8 0.15% 1.60% 100.00% + { 8192, 1, 8}, // 10 4 0.15% 1.60% 100.00% + { 16384, 1, 4}, // 11 2 0.15% 1.60% 100.00% + { 32768, 1, 2}, // 12 1 0.15% 0.03% 100.00% + { 65536, 2, 2}, // 13 1 0.07% 0.03% 100.00% + {131072, 4, 2}, // 14 1 0.04% 0.03% 100.00% + {262144, 8, 2}, // 15 1 0.02% 0.03% 100.00% }; #elif TCMALLOC_PAGE_SHIFT == 18 static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 17; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2SizeClasses[SizeMap::kExperimentalPow2SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.02% - { 16, 1, 32}, // 0.02% - { 32, 1, 32}, // 0.02% - { 64, 1, 32}, // 0.02% - { 128, 1, 32}, // 0.02% - { 256, 1, 32}, // 0.02% - { 512, 1, 32}, // 0.02% - { 1024, 1, 32}, // 0.02% - { 2048, 1, 32}, // 0.02% - { 4096, 1, 16}, // 0.02% - { 8192, 1, 8}, // 0.02% - { 16384, 1, 4}, // 0.02% - { 32768, 1, 2}, // 0.02% - { 65536, 1, 2}, // 0.02% - { 131072, 1, 2}, // 0.02% - { 262144, 1, 2}, // 0.02% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = true, + .span_size = 48, + .sampling_interval = 2097152, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 32768 0.02% 12.53% 0.00% + { 16, 1, 32}, // 1 16384 0.02% 12.53% 100.00% + { 32, 1, 32}, // 2 8192 0.02% 12.53% 100.00% + { 64, 1, 32}, // 3 4096 0.02% 12.53% 100.00% + { 128, 1, 32}, // 4 2048 0.02% 12.53% 100.00% + { 256, 1, 32}, // 5 1024 0.02% 12.53% 100.00% + { 512, 1, 32}, // 6 512 0.02% 12.53% 100.00% + { 1024, 1, 32}, // 7 256 0.02% 12.53% 100.00% + { 2048, 1, 32}, // 8 128 0.02% 12.53% 100.00% + { 4096, 1, 16}, // 9 64 0.02% 12.53% 100.00% + { 8192, 1, 8}, // 10 32 0.02% 12.53% 100.00% + { 16384, 1, 4}, // 11 16 0.02% 12.53% 100.00% + { 32768, 1, 2}, // 12 8 0.02% 12.53% 100.00% + { 65536, 1, 2}, // 13 4 0.02% 12.53% 100.00% + {131072, 1, 2}, // 14 2 0.02% 12.53% 100.00% + {262144, 1, 2}, // 15 1 0.02% 0.03% 100.00% }; #elif TCMALLOC_PAGE_SHIFT == 12 static_assert(kMaxSize == 8192, "kMaxSize mismatch"); -static const int kCount = 12; -static_assert(kCount <= kNumClasses); -const int SizeMap::kExperimentalPow2SizeClassesCount = kCount; -const SizeClassInfo SizeMap::kExperimentalPow2SizeClasses[SizeMap::kExperimentalPow2SizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 1.17% - { 16, 1, 32}, // 1.17% - { 32, 1, 32}, // 1.17% - { 64, 1, 32}, // 1.17% - { 128, 1, 32}, // 1.17% - { 256, 1, 32}, // 1.17% - { 512, 1, 32}, // 1.17% - { 1024, 2, 32}, // 0.59% - { 2048, 4, 32}, // 0.29% - { 4096, 4, 16}, // 0.29% - { 8192, 4, 8}, // 0.29% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = false, + .span_size = 48, + .sampling_interval = 524288, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 512 1.16% 0.92% 0.00% + { 16, 1, 32}, // 1 256 1.16% 0.92% 100.00% + { 32, 1, 32}, // 2 128 1.16% 0.92% 100.00% + { 64, 1, 32}, // 3 64 1.16% 0.92% 100.00% + { 128, 1, 32}, // 4 32 1.16% 0.92% 100.00% + { 256, 1, 32}, // 5 16 1.16% 0.92% 100.00% + { 512, 1, 32}, // 6 8 1.16% 0.92% 100.00% + { 1024, 2, 32}, // 7 8 0.58% 0.92% 100.00% + { 2048, 4, 32}, // 8 8 0.29% 0.92% 100.00% + { 4096, 4, 16}, // 9 4 0.29% 0.92% 100.00% + { 8192, 4, 8}, // 10 2 0.29% 1.70% 100.00% }; #else #error "Unsupported TCMALLOC_PAGE_SHIFT value!" @@ -234,6 +285,9 @@ const SizeClassInfo SizeMap::kExperimentalPow2SizeClasses[SizeMap::kExperimental #endif // clang-format on +static_assert(sizeof(List) / sizeof(List[0]) <= kNumBaseClasses); +extern constexpr SizeClasses kExperimentalPow2SizeClasses{List, Assumptions}; + } // namespace tcmalloc_internal } // namespace tcmalloc GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/global_stats.cc b/contrib/libs/tcmalloc/tcmalloc/global_stats.cc new file mode 100644 index 000000000000..0d5244429b7f --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/global_stats.cc @@ -0,0 +1,1029 @@ +// Copyright 2019 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/global_stats.h" + +#include +#include +#include +#include +#include + +#include "absl/strings/match.h" +#include "absl/strings/string_view.h" +#include "absl/strings/strip.h" +#include "absl/time/time.h" +#include "absl/types/optional.h" +#include "tcmalloc/central_freelist.h" +#include "tcmalloc/common.h" +#include "tcmalloc/cpu_cache.h" +#include "tcmalloc/experiment.h" +#include "tcmalloc/experiment_config.h" +#include "tcmalloc/guarded_page_allocator.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/cpu_utils.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/memory_stats.h" +#include "tcmalloc/internal/optimization.h" +#include "tcmalloc/internal/percpu.h" +#include "tcmalloc/metadata_object_allocator.h" +#include "tcmalloc/page_allocator.h" +#include "tcmalloc/pagemap.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/parameters.h" +#include "tcmalloc/selsan/selsan.h" +#include "tcmalloc/span.h" +#include "tcmalloc/span_stats.h" +#include "tcmalloc/stack_trace_table.h" +#include "tcmalloc/static_vars.h" +#include "tcmalloc/stats.h" +#include "tcmalloc/system-alloc.h" +#include "tcmalloc/thread_cache.h" +#include "tcmalloc/transfer_cache.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +using subtle::percpu::RseqVcpuMode; + +static absl::string_view MadviseString() { + MadvisePreference pref = tc_globals.system_allocator().madvise_preference(); + + switch (pref) { + case MadvisePreference::kNever: + return "MADVISE_NEVER"; + case MadvisePreference::kDontNeed: + return "MADVISE_DONTNEED"; + case MadvisePreference::kFreeOnly: + return "MADVISE_FREE_ONLY"; + case MadvisePreference::kFreeAndDontNeed: + return "MADVISE_FREE_AND_DONTNEED"; + } + + ABSL_UNREACHABLE(); +} + +// Get stats into "r". Also, if class_count != NULL, class_count[k] +// will be set to the total number of objects of size class k in the +// central cache, transfer cache, and per-thread and per-CPU caches. +// If small_spans is non-NULL, it is filled. Same for large_spans. +// The boolean report_residence determines whether residence information +// should be captured or not. Residence info requires a potentially +// costly OS call, and is not necessary in all situations. +void ExtractStats(TCMallocStats* r, uint64_t* class_count, + SpanStats* span_stats, SmallSpanStats* small_spans, + LargeSpanStats* large_spans, bool report_residence) { + r->central_bytes = 0; + r->transfer_bytes = 0; + for (int size_class = 0; size_class < kNumClasses; ++size_class) { + const size_t length = tc_globals.central_freelist(size_class).length(); + const size_t tc_length = tc_globals.transfer_cache().tc_length(size_class); + const size_t sharded_tc_length = + tc_globals.sharded_transfer_cache().TotalObjectsOfClass(size_class); + const size_t cache_overhead = + tc_globals.central_freelist(size_class).OverheadBytes(); + const size_t size = tc_globals.sizemap().class_to_size(size_class); + r->central_bytes += (size * length) + cache_overhead; + r->transfer_bytes += (size * tc_length); + if (class_count) { + // Sum the lengths of all per-class freelists, except the per-thread + // freelists, which get counted when we call GetThreadStats(), below. + class_count[size_class] = length + tc_length + sharded_tc_length; + if (UsePerCpuCache(tc_globals)) { + class_count[size_class] += + tc_globals.cpu_cache().TotalObjectsOfClass(size_class); + } + } + if (span_stats) { + span_stats[size_class] = + tc_globals.central_freelist(size_class).GetSpanStats(); + } + } + + // Add stats from per-thread heaps + r->thread_bytes = 0; + + r->span_stats = tc_globals.span_allocator().stats(); + r->stack_stats = tc_globals.sampledallocation_allocator().stats(); + r->linked_sample_stats = tc_globals.linked_sample_allocator().stats(); + r->tc_stats = ThreadCache::GetStats(&r->thread_bytes, class_count); + + { // scope + PageHeapSpinLockHolder l; + r->metadata_bytes = tc_globals.metadata_bytes(); + r->pagemap_bytes = tc_globals.pagemap().bytes(); + r->pageheap = tc_globals.page_allocator().stats(); + r->peak_stats = tc_globals.page_allocator().peak_stats(); + if (small_spans != nullptr) { + tc_globals.page_allocator().GetSmallSpanStats(small_spans); + } + if (large_spans != nullptr) { + tc_globals.page_allocator().GetLargeSpanStats(large_spans); + } + + // TODO(b/207622377): Arena is thread-safe, but we take the pageheap_lock + // to present a consistent view of memory usage. + r->arena = tc_globals.arena().stats(); + if (!report_residence) { + r->metadata_bytes += r->arena.bytes_nonresident; + } + + const PageReleaseStats release_stats = + tc_globals.page_allocator().GetReleaseStats(); + + r->num_released_total = release_stats.total; + r->num_released_release_memory_to_system = + release_stats.release_memory_to_system; + r->num_released_process_background_actions = + release_stats.process_background_actions; + r->num_released_soft_limit_exceeded = release_stats.soft_limit_exceeded; + r->num_released_hard_limit_exceeded = release_stats.hard_limit_exceeded; + + r->per_cpu_bytes = 0; + r->sharded_transfer_bytes = 0; + r->percpu_metadata_bytes_res = 0; + r->percpu_metadata_bytes = 0; + if (UsePerCpuCache(tc_globals)) { + r->per_cpu_bytes = tc_globals.cpu_cache().TotalUsedBytes(); + r->sharded_transfer_bytes = + tc_globals.sharded_transfer_cache().TotalBytes(); + + if (report_residence) { + auto percpu_metadata = tc_globals.cpu_cache().MetadataMemoryUsage(); + r->percpu_metadata_bytes_res = percpu_metadata.resident_size; + r->percpu_metadata_bytes = percpu_metadata.virtual_size; + + TC_ASSERT_GE(r->metadata_bytes, r->percpu_metadata_bytes); + r->metadata_bytes = r->metadata_bytes - r->percpu_metadata_bytes + + r->percpu_metadata_bytes_res; + } + } + } + // We can access the pagemap without holding the pageheap_lock since it + // is static data, and we are only taking address and size which are + // constants. + if (report_residence) { + auto resident_bytes = tc_globals.pagemap_residence(); + r->pagemap_root_bytes_res = resident_bytes; + TC_ASSERT_GE(r->metadata_bytes, r->pagemap_bytes); + r->metadata_bytes = r->metadata_bytes - r->pagemap_bytes + resident_bytes; + } else { + r->pagemap_root_bytes_res = 0; + } +} + +void ExtractTCMallocStats(TCMallocStats* r, bool report_residence) { + ExtractStats(r, nullptr, nullptr, nullptr, nullptr, report_residence); +} + +// Because different fields of stats are computed from state protected +// by different locks, they may be inconsistent. Prevent underflow +// when subtracting to avoid gigantic results. +static uint64_t StatSub(uint64_t a, uint64_t b) { + return (a >= b) ? (a - b) : 0; +} + +// Return approximate number of bytes in use by app. +uint64_t InUseByApp(const TCMallocStats& stats) { + return StatSub(stats.pageheap.system_bytes, + stats.thread_bytes + stats.central_bytes + + stats.transfer_bytes + stats.per_cpu_bytes + + stats.sharded_transfer_bytes + stats.pageheap.free_bytes + + stats.pageheap.unmapped_bytes); +} + +uint64_t VirtualMemoryUsed(const TCMallocStats& stats) { + return stats.pageheap.system_bytes + stats.metadata_bytes + + stats.arena.bytes_unallocated + stats.arena.bytes_unavailable + + stats.arena.bytes_nonresident; +} + +uint64_t UnmappedBytes(const TCMallocStats& stats) { + return stats.pageheap.unmapped_bytes + stats.arena.bytes_nonresident; +} + +uint64_t PhysicalMemoryUsed(const TCMallocStats& stats) { + return StatSub(VirtualMemoryUsed(stats), UnmappedBytes(stats)); +} + +// The number of bytes either in use by the app or fragmented so that +// it cannot be (arbitrarily) reused. +uint64_t RequiredBytes(const TCMallocStats& stats) { + return StatSub(PhysicalMemoryUsed(stats), stats.pageheap.free_bytes); +} + +size_t ExternalBytes(const TCMallocStats& stats) { + return stats.pageheap.free_bytes + stats.central_bytes + stats.per_cpu_bytes + + stats.sharded_transfer_bytes + stats.transfer_bytes + + stats.thread_bytes + stats.metadata_bytes + + stats.arena.bytes_unavailable + stats.arena.bytes_unallocated; +} + +size_t HeapSizeBytes(const BackingStats& stats) { + return StatSub(stats.system_bytes, stats.unmapped_bytes); +} + +size_t LocalBytes(const TCMallocStats& stats) { + return stats.thread_bytes + stats.per_cpu_bytes + + stats.sharded_transfer_bytes; +} + +size_t SlackBytes(const BackingStats& stats) { + return stats.free_bytes + stats.unmapped_bytes; +} + +static int CountAllowedCpus() { + CpuSet allowed_cpus; + if (!allowed_cpus.GetAffinity(0)) { + return 0; + } + + return allowed_cpus.Count(); +} + +static absl::string_view SizeClassConfigurationString( + SizeClassConfiguration config) { + switch (config) { + case SizeClassConfiguration::kPow2Below64: + return "SIZE_CLASS_POW2_BELOW_64"; + case SizeClassConfiguration::kPow2Only: + return "SIZE_CLASS_POW2_ONLY"; + case SizeClassConfiguration::kLegacy: + // TODO(b/242710633): remove this opt out. + return "SIZE_CLASS_LEGACY"; + case SizeClassConfiguration::kReuse: + return "SIZE_CLASS_REUSE"; + } + + ASSUME(false); + return "SIZE_CLASS_UNKNOWN"; +} + +static absl::string_view PerCpuTypeString(RseqVcpuMode mode) { + switch (mode) { + case RseqVcpuMode::kNone: + return "NONE"; + } + + ASSUME(false); + return "NONE"; +} + +void DumpStats(Printer& out, int level) { + TCMallocStats stats; + uint64_t class_count[kNumClasses]; + SpanStats span_stats[kNumClasses]; + if (level >= 2) { + ExtractStats(&stats, class_count, span_stats, nullptr, nullptr, true); + } else { + ExtractTCMallocStats(&stats, true); + } + + static const double MiB = 1048576.0; + + out.printf( + "See https://github.com/google/tcmalloc/tree/master/docs/stats.md for an explanation of " + "this page\n"); + + const uint64_t virtual_memory_used = VirtualMemoryUsed(stats); + const uint64_t physical_memory_used = PhysicalMemoryUsed(stats); + const uint64_t unmapped_bytes = UnmappedBytes(stats); + const uint64_t bytes_in_use_by_app = InUseByApp(stats); + +#ifdef TCMALLOC_INTERNAL_SMALL_BUT_SLOW + out.printf("NOTE: SMALL MEMORY MODEL IS IN USE, PERFORMANCE MAY SUFFER.\n"); +#endif + // clang-format off + // Avoid clang-format complaining about the way that this text is laid out. + out.printf( + "------------------------------------------------\n" + "MALLOC: %12u (%7.1f MiB) Bytes in use by application\n" + "MALLOC: + %12u (%7.1f MiB) Bytes in page heap freelist\n" + "MALLOC: + %12u (%7.1f MiB) Bytes in central cache freelist\n" + "MALLOC: + %12u (%7.1f MiB) Bytes in per-CPU cache freelist\n" + "MALLOC: + %12u (%7.1f MiB) Bytes in Sharded cache freelist\n" + "MALLOC: + %12u (%7.1f MiB) Bytes in transfer cache freelist\n" + "MALLOC: + %12u (%7.1f MiB) Bytes in thread cache freelists\n" + "MALLOC: + %12u (%7.1f MiB) Bytes in malloc metadata\n" + "MALLOC: + %12u (%7.1f MiB) Bytes in malloc metadata Arena unallocated\n" + "MALLOC: + %12u (%7.1f MiB) Bytes in malloc metadata Arena unavailable\n" + + "MALLOC: ------------\n" + "MALLOC: = %12u (%7.1f MiB) Actual memory used (physical + swap)\n" + "MALLOC: + %12u (%7.1f MiB) Bytes released to OS (aka unmapped)\n" + "MALLOC: ------------\n" + "MALLOC: = %12u (%7.1f MiB) Virtual address space used\n" + "MALLOC:\n" + "MALLOC: %12u Spans in use\n" + "MALLOC: %12u (%7.1f MiB) Spans created\n" + "MALLOC: %12u Thread heaps in use\n" + "MALLOC: %12u (%7.1f MiB) Thread heaps created\n" + "MALLOC: %12u Stack traces in use\n" + "MALLOC: %12u (%7.1f MiB) Stack traces created\n" + "MALLOC: %12u Table buckets in use\n" + "MALLOC: %12u (%7.1f MiB) Table buckets created\n" + "MALLOC: %12u (%7.1f MiB) Pagemap bytes used\n" + "MALLOC: %12u (%7.1f MiB) Pagemap root resident bytes\n" + "MALLOC: %12u (%7.1f MiB) per-CPU slab bytes used\n" + "MALLOC: %12u (%7.1f MiB) per-CPU slab resident bytes\n" + "MALLOC: %12u (%7.1f MiB) malloc metadata Arena non-resident bytes\n" + "MALLOC: %12u (%7.1f MiB) Actual memory used at peak\n" + "MALLOC: %12u (%7.1f MiB) Estimated in-use at peak\n" + "MALLOC: %12.4f Realized fragmentation (%%)\n" + "MALLOC: %12u Tcmalloc page size\n" + "MALLOC: %12u Tcmalloc hugepage size\n" + "MALLOC: %12u CPUs Allowed in Mask\n" + "MALLOC: %12u Arena blocks\n", + bytes_in_use_by_app, bytes_in_use_by_app / MiB, + stats.pageheap.free_bytes, stats.pageheap.free_bytes / MiB, + stats.central_bytes, stats.central_bytes / MiB, + stats.per_cpu_bytes, stats.per_cpu_bytes / MiB, + stats.sharded_transfer_bytes, stats.sharded_transfer_bytes / MiB, + stats.transfer_bytes, stats.transfer_bytes / MiB, + stats.thread_bytes, stats.thread_bytes / MiB, + stats.metadata_bytes, stats.metadata_bytes / MiB, + stats.arena.bytes_unallocated, stats.arena.bytes_unallocated / MiB, + stats.arena.bytes_unavailable, stats.arena.bytes_unavailable / MiB, + physical_memory_used, physical_memory_used / MiB, + unmapped_bytes, unmapped_bytes / MiB, + virtual_memory_used, virtual_memory_used / MiB, + uint64_t(stats.span_stats.in_use), + uint64_t(stats.span_stats.total), + (stats.span_stats.total * Span::CalcSizeOf(Parameters::max_span_cache_array_size())) / MiB, + uint64_t(stats.tc_stats.in_use), + uint64_t(stats.tc_stats.total), + (stats.tc_stats.total * sizeof(ThreadCache)) / MiB, + uint64_t(stats.stack_stats.in_use), + uint64_t(stats.stack_stats.total), + (stats.stack_stats.total * sizeof(StackTrace)) / MiB, + uint64_t(stats.linked_sample_stats.in_use), + uint64_t(stats.linked_sample_stats.total), + (stats.linked_sample_stats.total * sizeof(StackTraceTable::LinkedSample)) / MiB, + uint64_t(stats.pagemap_bytes), + stats.pagemap_bytes / MiB, + stats.pagemap_root_bytes_res, stats.pagemap_root_bytes_res / MiB, + uint64_t(stats.percpu_metadata_bytes), + stats.percpu_metadata_bytes / MiB, + stats.percpu_metadata_bytes_res, stats.percpu_metadata_bytes_res / MiB, + stats.arena.bytes_nonresident, stats.arena.bytes_nonresident / MiB, + uint64_t(stats.peak_stats.backed_bytes), + stats.peak_stats.backed_bytes / MiB, + uint64_t(stats.peak_stats.sampled_application_bytes), + stats.peak_stats.sampled_application_bytes / MiB, + 100. * safe_div(stats.peak_stats.backed_bytes - stats.peak_stats.sampled_application_bytes, stats.peak_stats.sampled_application_bytes), + uint64_t(kPageSize), + uint64_t(kHugePageSize), + CountAllowedCpus(), + stats.arena.blocks + ); + // clang-format on + + out.printf("MALLOC EXPERIMENTS:"); + WalkExperiments([&](absl::string_view name, bool active) { + const char* value = active ? "1" : "0"; + out.printf(" %s=%s", name, value); + }); + out.printf("\n"); + + out.printf( + "MALLOC SAMPLED PROFILES: %zu bytes (current), %zu bytes (internal " + "fragmentation), %zu bytes (peak), %zu count (total)\n", + static_cast(tc_globals.sampled_objects_size_.value()), + tc_globals.sampled_internal_fragmentation_.value(), + tc_globals.peak_heap_tracker().CurrentPeakSize(), + tc_globals.total_sampled_count_.value()); + + MemoryStats memstats; + if (GetMemoryStats(&memstats)) { + uint64_t rss = memstats.rss; + uint64_t vss = memstats.vss; + // clang-format off + out.printf( + "\n" + "Total process stats (inclusive of non-malloc sources):\n" + "TOTAL: %12u (%7.1f MiB) Bytes resident (physical memory used)\n" + "TOTAL: %12u (%7.1f MiB) Bytes mapped (virtual memory used)\n", + rss, rss / MiB, vss, vss / MiB); + // clang-format on + } + + out.printf( + "------------------------------------------------\n" + "Call ReleaseMemoryToSystem() to release freelist memory to the OS" + " (via madvise()).\n" + "Bytes released to the OS take up virtual address space" + " but no physical memory.\n"); + if (level >= 2) { + out.printf("------------------------------------------------\n"); + out.printf("Total size of freelists for per-thread and per-CPU caches,\n"); + out.printf("transfer cache, and central cache, as well as number of\n"); + out.printf("live pages, returned/requested spans by size class\n"); + out.printf("------------------------------------------------\n"); + + uint64_t cumulative = 0; + for (int size_class = 1; size_class < kNumClasses; ++size_class) { + uint64_t class_bytes = class_count[size_class] * + tc_globals.sizemap().class_to_size(size_class); + + cumulative += class_bytes; + out.printf( + // clang-format off + "class %3d [ %8zu bytes ] : %8u objs; %5.1f MiB; %6.1f cum MiB; " + "%8u live pages; spans: %10zu ret / %10zu req = %5.4f;\n", + // clang-format on + size_class, tc_globals.sizemap().class_to_size(size_class), + class_count[size_class], class_bytes / MiB, cumulative / MiB, + span_stats[size_class].num_live_spans() * + tc_globals.sizemap().class_to_pages(size_class), + span_stats[size_class].num_spans_returned, + span_stats[size_class].num_spans_requested, + span_stats[size_class].prob_returned()); + } + +#ifndef TCMALLOC_INTERNAL_SMALL_BUT_SLOW + out.printf("------------------------------------------------\n"); + out.printf("Central cache freelist: Span utilization histogram\n"); + out.printf("Non-cumulative number of spans with allocated objects < N\n"); + out.printf("------------------------------------------------\n"); + for (int size_class = 1; size_class < kNumClasses; ++size_class) { + tc_globals.central_freelist(size_class).PrintSpanUtilStats(out); + } + + out.printf("\n"); + out.printf("------------------------------------------------\n"); + out.printf("Central cache freelist: Span lifetime histogram\n"); + out.printf("Non-cumulative number of spans lifetime a < N\n"); + out.printf("------------------------------------------------\n"); + for (int size_class = 1; size_class < kNumClasses; ++size_class) { + tc_globals.central_freelist(size_class).PrintSpanLifetimeStats(out); + } +#endif + + tc_globals.transfer_cache().Print(out); + tc_globals.sharded_transfer_cache().Print(out); + + if (UsePerCpuCache(tc_globals)) { + tc_globals.cpu_cache().Print(out); + } + + tc_globals.page_allocator().Print(out, MemoryTag::kNormal); + if (tc_globals.numa_topology().active_partitions() > 1) { + tc_globals.page_allocator().Print(out, MemoryTag::kNormalP1); + } + tc_globals.page_allocator().Print(out, MemoryTag::kSampled); + tc_globals.page_allocator().Print(out, MemoryTag::kCold); + if (selsan::IsEnabled()) { + tc_globals.page_allocator().Print(out, MemoryTag::kSelSan); + } + tc_globals.guardedpage_allocator().Print(out); + selsan::PrintTextStats(out); + + out.printf("------------------------------------------------\n"); + out.printf("Configured limits and related statistics\n"); + out.printf("------------------------------------------------\n"); + uint64_t soft_limit_bytes = + tc_globals.page_allocator().limit(PageAllocator::kSoft); + uint64_t hard_limit_bytes = + tc_globals.page_allocator().limit(PageAllocator::kHard); + + out.printf("PARAMETER desired_usage_limit_bytes %u\n", soft_limit_bytes); + out.printf("PARAMETER hard_usage_limit_bytes %u\n", hard_limit_bytes); + out.printf("Number of times soft limit was hit: %lld\n", + tc_globals.page_allocator().limit_hits(PageAllocator::kSoft)); + out.printf("Number of times hard limit was hit: %lld\n", + tc_globals.page_allocator().limit_hits(PageAllocator::kHard)); + out.printf("Number of times memory shrank below soft limit: %lld\n", + tc_globals.page_allocator().successful_shrinks_after_limit_hit( + PageAllocator::kSoft)); + out.printf("Number of times memory shrank below hard limit: %lld\n", + tc_globals.page_allocator().successful_shrinks_after_limit_hit( + PageAllocator::kHard)); + + out.printf("Total number of pages released: %llu (%7.1f MiB)\n", + stats.num_released_total.in_pages().raw_num(), + stats.num_released_total.in_mib()); + out.printf( + "Number of pages released by ReleaseMemoryToSystem: %llu (%7.1f " + "MiB)\n", + stats.num_released_release_memory_to_system.in_pages().raw_num(), + stats.num_released_release_memory_to_system.in_mib()); + out.printf( + "Number of pages released by ProcessBackgroundActions: %llu " + "(%7.1f MiB)\n", + stats.num_released_process_background_actions.in_pages().raw_num(), + stats.num_released_process_background_actions.in_mib()); + out.printf( + "Number of pages released after soft limit hits: %llu (%7.1f " + "MiB)\n", + stats.num_released_soft_limit_exceeded.in_pages().raw_num(), + stats.num_released_soft_limit_exceeded.in_mib()); + out.printf( + "Number of pages released after hard limit hits: %llu (%7.1f " + "MiB)\n", + stats.num_released_hard_limit_exceeded.in_pages().raw_num(), + stats.num_released_hard_limit_exceeded.in_mib()); + + out.printf("------------------------------------------------\n"); + out.printf("Parameters\n"); + out.printf("------------------------------------------------\n"); + out.printf("PARAMETER tcmalloc_per_cpu_caches %d\n", + Parameters::per_cpu_caches() ? 1 : 0); + out.printf("PARAMETER tcmalloc_max_per_cpu_cache_size %d\n", + Parameters::max_per_cpu_cache_size()); + out.printf("PARAMETER tcmalloc_max_total_thread_cache_bytes %lld\n", + Parameters::max_total_thread_cache_bytes()); + out.printf("PARAMETER malloc_release_bytes_per_sec %llu\n", + Parameters::background_release_rate()); + out.printf("PARAMETER tcmalloc_skip_subrelease_short_interval %s\n", + absl::FormatDuration( + Parameters::filler_skip_subrelease_short_interval())); + out.printf("PARAMETER tcmalloc_skip_subrelease_long_interval %s\n", + absl::FormatDuration( + Parameters::filler_skip_subrelease_long_interval())); + out.printf("PARAMETER tcmalloc_cache_demand_release_short_interval %s\n", + absl::FormatDuration( + Parameters::cache_demand_release_short_interval())); + out.printf( + "PARAMETER tcmalloc_cache_demand_release_long_interval %s\n", + absl::FormatDuration(Parameters::cache_demand_release_long_interval())); + out.printf("PARAMETER tcmalloc_release_partial_alloc_pages %d\n", + Parameters::release_partial_alloc_pages() ? 1 : 0); + out.printf("PARAMETER tcmalloc_huge_cache_demand_based_release %d\n", + Parameters::huge_cache_demand_based_release() ? 1 : 0); + out.printf("PARAMETER tcmalloc_huge_region_demand_based_release %d\n", + Parameters::huge_region_demand_based_release() ? 1 : 0); + out.printf("PARAMETER tcmalloc_release_pages_from_huge_region %d\n", + Parameters::release_pages_from_huge_region() ? 1 : 0); + out.printf("PARAMETER tcmalloc_use_wider_slabs %d\n", + tc_globals.cpu_cache().UseWiderSlabs() ? 1 : 0); + + out.printf( + "PARAMETER size_class_config %s\n", + SizeClassConfigurationString(tc_globals.size_class_configuration())); + out.printf("PARAMETER percpu_vcpu_type %s\n", + PerCpuTypeString(subtle::percpu::GetRseqVcpuMode())); + out.printf("PARAMETER max_span_cache_size %d\n", + Parameters::max_span_cache_size()); + out.printf("PARAMETER max_span_cache_array_size %d\n", + Parameters::max_span_cache_array_size()); + out.printf("PARAMETER madvise %s\n", MadviseString()); + out.printf("PARAMETER tcmalloc_resize_size_class_max_capacity %d\n", + Parameters::resize_size_class_max_capacity() ? 1 : 0); + out.printf( + "PARAMETER tcmalloc_dense_trackers_sorted_on_spans_allocated %d\n", + Parameters::dense_trackers_sorted_on_spans_allocated() ? 1 : 0); + out.printf("PARAMETER min_hot_access_hint %d\n", + static_cast(Parameters::min_hot_access_hint())); + } +} + +void DumpStatsInPbtxt(Printer& out, int level) { + TCMallocStats stats; + uint64_t class_count[kNumClasses]; + SpanStats span_stats[kNumClasses]; + if (level >= 2) { + ExtractStats(&stats, class_count, span_stats, nullptr, nullptr, true); + } else { + ExtractTCMallocStats(&stats, true); + } + + const uint64_t bytes_in_use_by_app = InUseByApp(stats); + const uint64_t virtual_memory_used = VirtualMemoryUsed(stats); + const uint64_t physical_memory_used = PhysicalMemoryUsed(stats); + const uint64_t unmapped_bytes = UnmappedBytes(stats); + + PbtxtRegion region(out, kTop); + region.PrintI64("in_use_by_app", bytes_in_use_by_app); + region.PrintI64("page_heap_freelist", stats.pageheap.free_bytes); + region.PrintI64("central_cache_freelist", stats.central_bytes); + region.PrintI64("per_cpu_cache_freelist", stats.per_cpu_bytes); + region.PrintI64("sharded_transfer_cache_freelist", + stats.sharded_transfer_bytes); + region.PrintI64("transfer_cache_freelist", stats.transfer_bytes); + region.PrintI64("thread_cache_freelists", stats.thread_bytes); + region.PrintI64("malloc_metadata", stats.metadata_bytes); + region.PrintI64("malloc_metadata_arena_unavailable", + stats.arena.bytes_unavailable); + region.PrintI64("malloc_metadata_arena_unallocated", + stats.arena.bytes_unallocated); + region.PrintI64("actual_mem_used", physical_memory_used); + region.PrintI64("unmapped", unmapped_bytes); + region.PrintI64("virtual_address_space_used", virtual_memory_used); + region.PrintI64("num_spans", uint64_t(stats.span_stats.in_use)); + region.PrintI64("num_spans_created", uint64_t(stats.span_stats.total)); + region.PrintI64("num_thread_heaps", uint64_t(stats.tc_stats.in_use)); + region.PrintI64("num_thread_heaps_created", uint64_t(stats.tc_stats.total)); + region.PrintI64("num_stack_traces", uint64_t(stats.stack_stats.in_use)); + region.PrintI64("num_stack_traces_created", + uint64_t(stats.stack_stats.total)); + region.PrintI64("num_table_buckets", + uint64_t(stats.linked_sample_stats.in_use)); + region.PrintI64("num_table_buckets_created", + uint64_t(stats.linked_sample_stats.total)); + region.PrintI64("pagemap_size", uint64_t(stats.pagemap_bytes)); + region.PrintI64("pagemap_root_residence", stats.pagemap_root_bytes_res); + region.PrintI64("percpu_slab_size", stats.percpu_metadata_bytes); + region.PrintI64("percpu_slab_residence", stats.percpu_metadata_bytes_res); + region.PrintI64("peak_backed", stats.peak_stats.backed_bytes); + region.PrintI64("peak_application_demand", + stats.peak_stats.sampled_application_bytes); + region.PrintI64("tcmalloc_page_size", uint64_t(kPageSize)); + region.PrintI64("tcmalloc_huge_page_size", uint64_t(kHugePageSize)); + region.PrintI64("cpus_allowed", CountAllowedCpus()); + region.PrintI64("arena_blocks", stats.arena.blocks); + + { + auto sampled_profiles = region.CreateSubRegion("sampled_profiles"); + sampled_profiles.PrintI64("current_bytes", + tc_globals.sampled_objects_size_.value()); + sampled_profiles.PrintI64( + "current_fragmentation_bytes", + tc_globals.sampled_internal_fragmentation_.value()); + sampled_profiles.PrintI64("peak_bytes", + tc_globals.peak_heap_tracker().CurrentPeakSize()); + } + + // Print total process stats (inclusive of non-malloc sources). + MemoryStats memstats; + if (GetMemoryStats(&memstats)) { + region.PrintI64("total_resident", uint64_t(memstats.rss)); + region.PrintI64("total_mapped", uint64_t(memstats.vss)); + } + + region.PrintI64("total_sampled_count", + tc_globals.total_sampled_count_.value()); + + if (level >= 2) { + { +#ifndef TCMALLOC_INTERNAL_SMALL_BUT_SLOW + for (int size_class = 1; size_class < kNumClasses; ++size_class) { + uint64_t class_bytes = class_count[size_class] * + tc_globals.sizemap().class_to_size(size_class); + PbtxtRegion entry = region.CreateSubRegion("freelist"); + entry.PrintI64("sizeclass", + tc_globals.sizemap().class_to_size(size_class)); + entry.PrintI64("bytes", class_bytes); + entry.PrintI64("num_spans_requested", + span_stats[size_class].num_spans_requested); + entry.PrintI64("num_spans_returned", + span_stats[size_class].num_spans_returned); + entry.PrintI64("obj_capacity", span_stats[size_class].obj_capacity); + tc_globals.central_freelist(size_class) + .PrintSpanUtilStatsInPbtxt(entry); + tc_globals.central_freelist(size_class) + .PrintSpanLifetimeStatsInPbtxt(entry); + } +#endif + } + + tc_globals.transfer_cache().PrintInPbtxt(region); + tc_globals.sharded_transfer_cache().PrintInPbtxt(region); + + if (UsePerCpuCache(tc_globals)) { + tc_globals.cpu_cache().PrintInPbtxt(region); + } + } + tc_globals.page_allocator().PrintInPbtxt(region, MemoryTag::kNormal); + if (tc_globals.numa_topology().active_partitions() > 1) { + tc_globals.page_allocator().PrintInPbtxt(region, MemoryTag::kNormalP1); + } + tc_globals.page_allocator().PrintInPbtxt(region, MemoryTag::kSampled); + tc_globals.page_allocator().PrintInPbtxt(region, MemoryTag::kCold); + if (selsan::IsEnabled()) { + tc_globals.page_allocator().PrintInPbtxt(region, MemoryTag::kSelSan); + } + // We do not collect tracking information in pbtxt. + + size_t soft_limit_bytes = + tc_globals.page_allocator().limit(PageAllocator::kSoft); + size_t hard_limit_bytes = + tc_globals.page_allocator().limit(PageAllocator::kHard); + + region.PrintI64("desired_usage_limit_bytes", soft_limit_bytes); + region.PrintI64("hard_usage_limit_bytes", hard_limit_bytes); + region.PrintI64("soft_limit_hits", + tc_globals.page_allocator().limit_hits(PageAllocator::kSoft)); + region.PrintI64("hard_limit_hits", + tc_globals.page_allocator().limit_hits(PageAllocator::kHard)); + region.PrintI64( + "successful_shrinks_after_soft_limit_hit", + tc_globals.page_allocator().successful_shrinks_after_limit_hit( + PageAllocator::kSoft)); + region.PrintI64( + "successful_shrinks_after_hard_limit_hit", + tc_globals.page_allocator().successful_shrinks_after_limit_hit( + PageAllocator::kHard)); + + region.PrintI64("num_released_total_pages", + stats.num_released_total.in_pages().raw_num()); + region.PrintI64( + "num_released_release_memory_to_system_pages", + stats.num_released_release_memory_to_system.in_pages().raw_num()); + region.PrintI64( + "num_released_process_background_actions_pages", + stats.num_released_process_background_actions.in_pages().raw_num()); + region.PrintI64("num_released_soft_limit_exceeded_pages", + stats.num_released_soft_limit_exceeded.in_pages().raw_num()); + region.PrintI64("num_released_hard_limit_exceeded_pages", + stats.num_released_hard_limit_exceeded.in_pages().raw_num()); + + { + auto gwp_asan = region.CreateSubRegion("gwp_asan"); + tc_globals.guardedpage_allocator().PrintInPbtxt(gwp_asan); + } + selsan::PrintPbtxtStats(region); + + region.PrintI64("memory_release_failures", + tc_globals.system_allocator().release_errors()); + + region.PrintBool("tcmalloc_per_cpu_caches", Parameters::per_cpu_caches()); + region.PrintI64("tcmalloc_max_per_cpu_cache_size", + Parameters::max_per_cpu_cache_size()); + region.PrintI64("tcmalloc_max_total_thread_cache_bytes", + Parameters::max_total_thread_cache_bytes()); + region.PrintI64("malloc_release_bytes_per_sec", + static_cast(Parameters::background_release_rate())); + region.PrintI64("tcmalloc_skip_subrelease_short_interval_ns", + absl::ToInt64Nanoseconds( + Parameters::filler_skip_subrelease_short_interval())); + region.PrintI64("tcmalloc_skip_subrelease_long_interval_ns", + absl::ToInt64Nanoseconds( + Parameters::filler_skip_subrelease_long_interval())); + region.PrintI64("tcmalloc_cache_demand_release_short_interval_ns", + absl::ToInt64Nanoseconds( + Parameters::cache_demand_release_short_interval())); + region.PrintI64("tcmalloc_cache_demand_release_long_interval_ns", + absl::ToInt64Nanoseconds( + Parameters::cache_demand_release_long_interval())); + region.PrintBool("tcmalloc_release_partial_alloc_pages", + Parameters::release_partial_alloc_pages()); + region.PrintBool("tcmalloc_huge_cache_demand_based_release", + Parameters::huge_cache_demand_based_release()); + region.PrintBool("tcmalloc_huge_region_demand_based_release", + Parameters::huge_region_demand_based_release()); + region.PrintBool("tcmalloc_release_pages_from_huge_region", + Parameters::release_pages_from_huge_region()); + region.PrintI64("profile_sampling_interval", + Parameters::profile_sampling_interval()); + region.PrintRaw("percpu_vcpu_type", + PerCpuTypeString(subtle::percpu::GetRseqVcpuMode())); + region.PrintBool("tcmalloc_use_wider_slabs", + tc_globals.cpu_cache().UseWiderSlabs()); + region.PrintI64("span_max_cache_size", Parameters::max_span_cache_size()); + region.PrintI64("span_max_cache_array_size", + Parameters::max_span_cache_array_size()); + region.PrintBool("tcmalloc_dense_trackers_sorted_on_spans_allocated", + Parameters::dense_trackers_sorted_on_spans_allocated()); + region.PrintI64("min_hot_access_hint", + static_cast(Parameters::min_hot_access_hint())); + + region.PrintRaw( + "size_class_config", + SizeClassConfigurationString(tc_globals.size_class_configuration())); + region.PrintRaw("madvise", MadviseString()); + region.PrintBool("tcmalloc_resize_size_class_max_capacity", + Parameters::resize_size_class_max_capacity()); +} + +bool GetNumericProperty(const char* name_data, size_t name_size, + size_t* value) { + // LINT.IfChange + TC_ASSERT_NE(name_data, nullptr); + TC_ASSERT_NE(value, nullptr); + const absl::string_view name(name_data, name_size); + + // This is near the top since ReleasePerCpuMemoryToOS() calls it frequently. + if (name == "tcmalloc.per_cpu_caches_active") { + *value = tc_globals.CpuCacheActive(); + return true; + } + + if (name == "generic.virtual_memory_used") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, false); + *value = VirtualMemoryUsed(stats); + return true; + } + + if (name == "generic.physical_memory_used") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, false); + *value = PhysicalMemoryUsed(stats); + return true; + } + + if (name == "generic.current_allocated_bytes" || + name == "generic.bytes_in_use_by_app") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, false); + *value = InUseByApp(stats); + return true; + } + + if (name == "generic.peak_memory_usage") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, false); + *value = static_cast(stats.peak_stats.sampled_application_bytes); + return true; + } + + if (name == "generic.realized_fragmentation") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, false); + *value = static_cast( + 100. * safe_div(stats.peak_stats.backed_bytes - + stats.peak_stats.sampled_application_bytes, + stats.peak_stats.sampled_application_bytes)); + + return true; + } + + if (name == "generic.heap_size") { + PageHeapSpinLockHolder l; + BackingStats stats = tc_globals.page_allocator().stats(); + *value = HeapSizeBytes(stats); + return true; + } + + if (name == "tcmalloc.central_cache_free") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, false); + *value = stats.central_bytes; + return true; + } + + if (name == "tcmalloc.cpu_free") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, false); + *value = stats.per_cpu_bytes; + return true; + } + + if (name == "tcmalloc.sharded_transfer_cache_free") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, false); + *value = stats.sharded_transfer_bytes; + return true; + } + + if (name == "tcmalloc.slack_bytes") { + // Kept for backwards compatibility. Now defined externally as: + // pageheap_free_bytes + pageheap_unmapped_bytes. + PageHeapSpinLockHolder l; + BackingStats stats = tc_globals.page_allocator().stats(); + *value = SlackBytes(stats); + return true; + } + + if (name == "tcmalloc.pageheap_free_bytes" || + name == "tcmalloc.page_heap_free") { + PageHeapSpinLockHolder l; + *value = tc_globals.page_allocator().stats().free_bytes; + return true; + } + + if (name == "tcmalloc.pageheap_unmapped_bytes" || + name == "tcmalloc.page_heap_unmapped") { + PageHeapSpinLockHolder l; + // Arena non-resident bytes aren't on the page heap, but they are unmapped. + *value = tc_globals.page_allocator().stats().unmapped_bytes + + tc_globals.arena().stats().bytes_nonresident; + return true; + } + + if (name == "tcmalloc.sampled_internal_fragmentation") { + *value = tc_globals.sampled_internal_fragmentation_.value(); + return true; + } + + if (name == "tcmalloc.max_total_thread_cache_bytes") { + *value = ThreadCache::overall_thread_cache_size(); + return true; + } + + if (name == "tcmalloc.current_total_thread_cache_bytes" || + name == "tcmalloc.thread_cache_free") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, false); + *value = stats.thread_bytes; + return true; + } + + if (name == "tcmalloc.thread_cache_count") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, false); + *value = stats.tc_stats.in_use; + return true; + } + + if (name == "tcmalloc.local_bytes") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, false); + *value = LocalBytes(stats); + return true; + } + + if (name == "tcmalloc.external_fragmentation_bytes") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, false); + *value = ExternalBytes(stats); + return true; + } + + if (name == "tcmalloc.metadata_bytes") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, true); + *value = stats.metadata_bytes; + return true; + } + + if (name == "tcmalloc.transfer_cache_free") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, false); + *value = stats.transfer_bytes; + return true; + } + + auto limit_kind = (name == "tcmalloc.hard_usage_limit_bytes") + ? PageAllocator::kHard + : PageAllocator::kSoft; + if (limit_kind == PageAllocator::kHard || + name == "tcmalloc.desired_usage_limit_bytes") { + *value = tc_globals.page_allocator().limit(limit_kind); + return true; + } + if (name == "tcmalloc.soft_limit_hits") { + *value = tc_globals.page_allocator().limit_hits(PageAllocator::kSoft); + return true; + } + if (name == "tcmalloc.hard_limit_hits") { + *value = tc_globals.page_allocator().limit_hits(PageAllocator::kHard); + return true; + } + if (name == "tcmalloc.successful_shrinks_after_soft_limit_hit") { + *value = tc_globals.page_allocator().successful_shrinks_after_limit_hit( + PageAllocator::kSoft); + return true; + } + if (name == "tcmalloc.successful_shrinks_after_hard_limit_hit") { + *value = tc_globals.page_allocator().successful_shrinks_after_limit_hit( + PageAllocator::kHard); + return true; + } + + for (const auto& [property_name, field] : + std::initializer_list>{ + {"tcmalloc.num_released_total_bytes", &PageReleaseStats::total}, + {"tcmalloc.num_released_release_memory_to_system_bytes", + &PageReleaseStats::release_memory_to_system}, + {"tcmalloc.num_released_process_background_actions_bytes", + &PageReleaseStats::process_background_actions}, + {"tcmalloc.num_released_soft_limit_exceeded_bytes", + &PageReleaseStats::soft_limit_exceeded}, + {"tcmalloc.num_released_hard_limit_exceeded_bytes", + &PageReleaseStats::hard_limit_exceeded}}) { + if (name == property_name) { + const PageHeapSpinLockHolder l; + *value = + (tc_globals.page_allocator().GetReleaseStats().*field).in_bytes(); + return true; + } + } + + if (name == "tcmalloc.required_bytes") { + TCMallocStats stats; + ExtractTCMallocStats(&stats, false); + *value = RequiredBytes(stats); + return true; + } + + const absl::string_view kExperimentPrefix = "tcmalloc.experiment."; + if (absl::StartsWith(name, kExperimentPrefix)) { + std::optional exp = + FindExperimentByName(absl::StripPrefix(name, kExperimentPrefix)); + if (exp.has_value()) { + *value = IsExperimentActive(*exp) ? 1 : 0; + return true; + } + } + + // LINT.ThenChange(//depot/google3/tcmalloc/testing/malloc_extension_test.cc) + return false; +} + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/global_stats.h b/contrib/libs/tcmalloc/tcmalloc/global_stats.h new file mode 100644 index 000000000000..80d3c81e2152 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/global_stats.h @@ -0,0 +1,87 @@ +#pragma clang system_header +// Copyright 2019 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_GLOBAL_STATS_H_ +#define TCMALLOC_GLOBAL_STATS_H_ + +#include +#include + +#include "tcmalloc/arena.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/metadata_object_allocator.h" +#include "tcmalloc/page_allocator.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/stats.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +// Extract interesting stats +struct TCMallocStats { + uint64_t thread_bytes; // Bytes in thread caches + uint64_t central_bytes; // Bytes in central cache + uint64_t transfer_bytes; // Bytes in central transfer cache + uint64_t metadata_bytes; // Bytes alloced for metadata + uint64_t sharded_transfer_bytes; // Bytes in per-CCX cache + uint64_t per_cpu_bytes; // Bytes in per-CPU cache + uint64_t pagemap_root_bytes_res; // Resident bytes of pagemap root node + uint64_t percpu_metadata_bytes_res; // Resident bytes of the per-CPU metadata + AllocatorStats tc_stats; // ThreadCache objects + AllocatorStats span_stats; // Span objects + AllocatorStats stack_stats; // StackTrace objects + AllocatorStats linked_sample_stats; // StackTraceTable::LinkedSample objects + size_t pagemap_bytes; // included in metadata bytes + size_t percpu_metadata_bytes; // included in metadata bytes + BackingStats pageheap; // Stats from page heap + PageAllocator::PeakStats peak_stats; + + Length num_released_total; + Length num_released_release_memory_to_system; + Length num_released_process_background_actions; + Length num_released_soft_limit_exceeded; + Length num_released_hard_limit_exceeded; + + ArenaStats arena; // Stats from the metadata Arena + + // Explicitly declare the ctor to put it in the google_malloc section. + TCMallocStats() = default; +}; + +void ExtractTCMallocStats(TCMallocStats* r, bool report_residence); + +uint64_t InUseByApp(const TCMallocStats& stats); +uint64_t VirtualMemoryUsed(const TCMallocStats& stats); +uint64_t UnmappedBytes(const TCMallocStats& stats); +uint64_t PhysicalMemoryUsed(const TCMallocStats& stats); +uint64_t RequiredBytes(const TCMallocStats& stats); +size_t ExternalBytes(const TCMallocStats& stats); +size_t HeapSizeBytes(const BackingStats& stats); +size_t LocalBytes(const TCMallocStats& stats); +size_t SlackBytes(const BackingStats& stats); + +// WRITE stats to "out" +void DumpStats(Printer& out, int level); +void DumpStatsInPbtxt(Printer& out, int level); + +bool GetNumericProperty(const char* name_data, size_t name_size, size_t* value); + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_GLOBAL_STATS_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/guarded_allocations.h b/contrib/libs/tcmalloc/tcmalloc/guarded_allocations.h new file mode 100644 index 000000000000..ecf10d87cc36 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/guarded_allocations.h @@ -0,0 +1,62 @@ +#pragma clang system_header +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_GUARDED_ALLOCATIONS_H_ +#define TCMALLOC_GUARDED_ALLOCATIONS_H_ + +#include + +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/malloc_extension.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +struct GuardedAllocationsStackTrace { + void* stack[kMaxStackDepth]; + size_t depth = 0; + pid_t thread_id = 0; +}; + +enum class WriteFlag : int { Unknown, Read, Write }; + +enum class GuardedAllocationsErrorType { + kUseAfterFree, + kUseAfterFreeRead, + kUseAfterFreeWrite, + kBufferUnderflow, + kBufferUnderflowRead, + kBufferUnderflowWrite, + kBufferOverflow, + kBufferOverflowRead, + kBufferOverflowWrite, + kDoubleFree, + kBufferOverflowOnDealloc, + kUnknown, +}; + +struct GuardedAllocWithStatus { + void* alloc = nullptr; + Profile::Sample::GuardedStatus status = + Profile::Sample::GuardedStatus::Unknown; +}; + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_GUARDED_ALLOCATIONS_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator.cc b/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator.cc index cc02ed7a05df..9e2a54a45d92 100644 --- a/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator.cc +++ b/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator.cc @@ -14,30 +14,34 @@ #include "tcmalloc/guarded_page_allocator.h" -#include -#include #include -#include #include -#include +#include #include -#include -#include +#include +#include +#include #include -#include "absl/base/call_once.h" +#include "absl/base/attributes.h" +#include "absl/base/internal/cycleclock.h" #include "absl/base/internal/spinlock.h" #include "absl/base/internal/sysinfo.h" +#include "absl/base/optimization.h" #include "absl/debugging/stacktrace.h" #include "absl/numeric/bits.h" -#include "absl/strings/string_view.h" #include "tcmalloc/common.h" -#include "tcmalloc/internal/environment.h" +#include "tcmalloc/guarded_allocations.h" +#include "tcmalloc/internal/allocation_guard.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" -#include "tcmalloc/internal/util.h" +#include "tcmalloc/internal/memory_tag.h" +#include "tcmalloc/internal/page_size.h" +#include "tcmalloc/malloc_extension.h" #include "tcmalloc/pagemap.h" -#include "tcmalloc/sampler.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/parameters.h" #include "tcmalloc/static_vars.h" #include "tcmalloc/system-alloc.h" @@ -45,191 +49,346 @@ GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { -const size_t GuardedPageAllocator::kMagicSize; // NOLINT - -void GuardedPageAllocator::Init(size_t max_alloced_pages, size_t total_pages) { - CHECK_CONDITION(max_alloced_pages > 0); - CHECK_CONDITION(max_alloced_pages <= total_pages); - CHECK_CONDITION(total_pages <= kGpaMaxPages); - max_alloced_pages_ = max_alloced_pages; +void GuardedPageAllocator::Init(size_t max_allocated_pages, + size_t total_pages) { + TC_CHECK_GT(max_allocated_pages, 0); + TC_CHECK_LE(max_allocated_pages, total_pages); + TC_CHECK_LE(total_pages, kGpaMaxPages); + max_allocated_pages_ = max_allocated_pages; total_pages_ = total_pages; // If the system page size is larger than kPageSize, we need to use the // system page size for this allocator since mprotect operates on full pages // only. This case happens on PPC. - page_size_ = std::max(kPageSize, static_cast(getpagesize())); - ASSERT(page_size_ % kPageSize == 0); + page_size_ = std::max(kPageSize, static_cast(GetPageSize())); + TC_ASSERT_EQ(page_size_ % kPageSize, 0); - rand_ = reinterpret_cast(this); // Initialize RNG seed. + rand_.Reset(static_cast(absl::base_internal::CycleClock::Now()) + + reinterpret_cast(this)); MapPages(); } void GuardedPageAllocator::Destroy() { - absl::base_internal::SpinLockHolder h(&guarded_page_lock); + AllocationGuardSpinLockHolder h(&guarded_page_lock_); if (initialized_) { size_t len = pages_end_addr_ - pages_base_addr_; - int err = munmap(reinterpret_cast(pages_base_addr_), len); - ASSERT(err != -1); + int err = munmap(reinterpret_cast(pages_base_addr_), len); + TC_ASSERT_NE(err, -1); (void)err; initialized_ = false; } } -void *GuardedPageAllocator::Allocate(size_t size, size_t alignment) { - if (size == 0) return nullptr; - ssize_t free_slot = ReserveFreeSlot(); - if (free_slot == -1) return nullptr; // All slots are reserved. +// Reset is used by tests to ensure that subsequent allocations will be sampled. +void GuardedPageAllocator::Reset() { + // Reset sampled/guarded counters so that that we don't skip guarded sampling + // for a prolonged time due to accumulated stats. + tc_globals.total_sampled_count_.Add(-tc_globals.total_sampled_count_.value()); + successful_allocations_.Add(-successful_allocations_.value()); + // Allow allocations that are not currently covered by an existing allocation. + // Fully resetting the stack trace filter is a bad idea, because the pool may + // not be empty: a later deallocation would try to remove a non-existent entry + // from the filter. + stacktrace_filter_.DecayAll(); +} + +void GuardedPageAllocator::AcquireInternalLocks() { + guarded_page_lock_.Lock(); +} + +void GuardedPageAllocator::ReleaseInternalLocks() { + guarded_page_lock_.Unlock(); +} + +GuardedAllocWithStatus GuardedPageAllocator::TrySample( + size_t size, size_t alignment, Length num_pages, + const StackTrace& stack_trace) { + if (num_pages != Length(1)) { + skipped_allocations_toolarge_.Add(1); + return {nullptr, Profile::Sample::GuardedStatus::LargerThanOnePage}; + } + + const int64_t guarded_sampling_interval = + tcmalloc::tcmalloc_internal::Parameters::guarded_sampling_interval(); + // Guarded sampling is disabled if guarded_sampling_interval is negative. + if (guarded_sampling_interval < 0) { + return {nullptr, Profile::Sample::GuardedStatus::Disabled}; + } + // Never filter if guarded_sampling_interval == 0, or no samples yet. + const size_t num_guarded = successful_allocations(); + if (guarded_sampling_interval > 0 && num_guarded > 0) { + // The guarded page allocator should not exceed the desired sampling rate. + // To do so, we need to filter allocations while this condition holds: + // + // num_guarded * guarded_interval > num_sampled * profile_interval + // + // I.e. if the next guarded allocation should occur at total bytes allocated + // later than the next sampled allocation. Recall that sampled allocations + // are a superset of guarded sampled allocations, and num_sampled is always + // incremented _after_ num_guarded. + // + // Assuming that the number of total samples (num_sampled) must always be + // larger or equal to the guarded samples (num_guarded), and allow for a + // target num_sampled:num_guarded ratio with up to 1 decimal place, the + // above can be rewritten as: + // + // guarded_interval * 10 > + // ((num_sampled * 10) / num_guarded) * profile_interval + // + // This avoids possible overflow if num_sampled or num_guarded grows larger, + // when individually multiplied by the intervals. We can avoid floating + // point math as well. + const int64_t profile_sampling_interval = + tcmalloc::tcmalloc_internal::Parameters::profile_sampling_interval(); + const int64_t num_sampled = tc_globals.total_sampled_count_.value(); + const int64_t ratio = (num_sampled * 10) / num_guarded; + if (guarded_sampling_interval * 10 > ratio * profile_sampling_interval) { + return {nullptr, Profile::Sample::GuardedStatus::RateLimited}; + } + + if (stacktrace_filter_.Contains({stack_trace.stack, stack_trace.depth})) { + // The probability that we skip a currently covered allocation scales + // proportional to pool utilization, with pool utilization of 50% or more + // resulting in always filtering currently covered allocations. + const size_t usage_pct = (allocated_pages() * 100) / max_allocated_pages_; + if (rand_.Next() % 50 <= usage_pct) { + // Decay even if the current allocation is filtered, so that we keep + // sampling even if we only see the same allocations over and over. + stacktrace_filter_.Decay(); + skipped_allocations_filtered_.Add(1); + return {nullptr, Profile::Sample::GuardedStatus::Filtered}; + } + } + } + // The num_pages == 1 constraint ensures that size <= kPageSize. And + // since alignments above kPageSize cause size_class == 0, we're also + // guaranteed alignment <= kPageSize + // + // In all cases kPageSize <= GPA::page_size_, so Allocate's preconditions + // are met. + return Allocate(size, alignment, stack_trace); +} + +GuardedAllocWithStatus GuardedPageAllocator::Allocate( + size_t size, size_t alignment, const StackTrace& stack_trace) { + if (size == 0) { + return {nullptr, Profile::Sample::GuardedStatus::TooSmall}; + } + const ssize_t free_slot = ReserveFreeSlot(); + if (free_slot == -1) { + // All slots are reserved. + return {nullptr, Profile::Sample::GuardedStatus::NoAvailableSlots}; + } - ASSERT(size <= page_size_); - ASSERT(alignment <= page_size_); - ASSERT(alignment == 0 || absl::has_single_bit(alignment)); - void *result = reinterpret_cast(SlotToAddr(free_slot)); + TC_ASSERT_LE(size, page_size_); + TC_ASSERT_LE(alignment, page_size_); + TC_ASSERT(alignment == 0 || absl::has_single_bit(alignment)); + void* result = reinterpret_cast(SlotToAddr(free_slot)); if (mprotect(result, page_size_, PROT_READ | PROT_WRITE) == -1) { - ASSERT(false && "mprotect failed"); - absl::base_internal::SpinLockHolder h(&guarded_page_lock); - num_failed_allocations_++; + TC_ASSERT(false, "mprotect(.., PROT_READ|PROT_WRITE) failed"); + AllocationGuardSpinLockHolder h(&guarded_page_lock_); + failed_allocations_.LossyAdd(1); + successful_allocations_.LossyAdd(-1); FreeSlot(free_slot); - return nullptr; + return {nullptr, Profile::Sample::GuardedStatus::MProtectFailed}; } // Place some allocations at end of page for better overflow detection. MaybeRightAlign(free_slot, size, alignment, &result); // Record stack trace. - SlotMetadata &d = data_[free_slot]; + SlotMetadata& d = data_[free_slot]; + // Count the number of pages that have been used at least once. + if (ABSL_PREDICT_FALSE(d.allocation_start == 0)) { + pages_touched_.Add(1); + } + + static_assert(sizeof(d.alloc_trace.stack) == sizeof(stack_trace.stack)); + memcpy(d.alloc_trace.stack, stack_trace.stack, + stack_trace.depth * sizeof(stack_trace.stack[0])); + d.alloc_trace.depth = stack_trace.depth; + d.alloc_trace.thread_id = absl::base_internal::GetTID(); d.dealloc_trace.depth = 0; - d.alloc_trace.depth = absl::GetStackTrace(d.alloc_trace.stack, kMaxStackDepth, - /*skip_count=*/3); - d.alloc_trace.tid = absl::base_internal::GetTID(); d.requested_size = size; d.allocation_start = reinterpret_cast(result); + d.dealloc_count.store(0, std::memory_order_relaxed); + TC_ASSERT(!d.write_overflow_detected); + TC_ASSERT(!alignment || d.allocation_start % alignment == 0); - ASSERT(!alignment || d.allocation_start % alignment == 0); - return result; + stacktrace_filter_.Add({stack_trace.stack, stack_trace.depth}, 1); + return {result, Profile::Sample::GuardedStatus::Guarded}; } -void GuardedPageAllocator::Deallocate(void *ptr) { - ASSERT(PointerIsMine(ptr)); +// To trigger SEGV handler. +static ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NORETURN void ForceTouchPage( + void* ptr) { + // Spin, in case this thread is waiting for concurrent mprotect() to finish. + for (;;) { + *reinterpret_cast(ptr) = 'X'; + } +} + +void GuardedPageAllocator::Deallocate(void* ptr) { + TC_ASSERT(PointerIsMine(ptr)); const uintptr_t page_addr = GetPageAddr(reinterpret_cast(ptr)); - size_t slot = AddrToSlot(page_addr); + const size_t slot = AddrToSlot(page_addr); + SlotMetadata& d = data_[slot]; - absl::base_internal::SpinLockHolder h(&guarded_page_lock); - if (IsFreed(slot)) { - double_free_detected_ = true; - } else if (WriteOverflowOccurred(slot)) { - write_overflow_detected_ = true; + // On double-free, do not overwrite the original deallocation metadata, so + // that the report produced shows the original deallocation stack trace. + if (d.dealloc_count.fetch_add(1, std::memory_order_relaxed) != 0) { + ForceTouchPage(ptr); } - CHECK_CONDITION(mprotect(reinterpret_cast(page_addr), page_size_, - PROT_NONE) != -1); + // Record stack trace. Unwinding the stack is expensive, and holding the + // guarded_page_lock_ should be avoided here. + d.dealloc_trace.depth = + absl::GetStackTrace(d.dealloc_trace.stack, kMaxStackDepth, + /*skip_count=*/2); + d.dealloc_trace.thread_id = absl::base_internal::GetTID(); - if (write_overflow_detected_ || double_free_detected_) { - *reinterpret_cast(ptr) = 'X'; // Trigger SEGV handler. - CHECK_CONDITION(false); // Unreachable. + // Remove allocation (based on allocation stack trace) from filter. + stacktrace_filter_.Add({d.alloc_trace.stack, d.alloc_trace.depth}, -1); + + // Needs to be done before mprotect() because it accesses the object page to + // check canary bytes. + if (WriteOverflowOccurred(slot)) { + d.write_overflow_detected = true; } - // Record stack trace. - GpaStackTrace &trace = data_[slot].dealloc_trace; - trace.depth = absl::GetStackTrace(trace.stack, kMaxStackDepth, - /*skip_count=*/2); - trace.tid = absl::base_internal::GetTID(); + // Calling mprotect() should also be done outside the guarded_page_lock_ + // critical section, since mprotect() can have relatively large latency. + TC_CHECK_EQ( + 0, mprotect(reinterpret_cast(page_addr), page_size_, PROT_NONE)); + if (d.write_overflow_detected) { + ForceTouchPage(ptr); + } + + AllocationGuardSpinLockHolder h(&guarded_page_lock_); FreeSlot(slot); } -size_t GuardedPageAllocator::GetRequestedSize(const void *ptr) const { - ASSERT(PointerIsMine(ptr)); +size_t GuardedPageAllocator::GetRequestedSize(const void* ptr) const { + TC_ASSERT(PointerIsMine(ptr)); size_t slot = AddrToSlot(GetPageAddr(reinterpret_cast(ptr))); return data_[slot].requested_size; } std::pair GuardedPageAllocator::GetAllocationOffsetAndSize( - const void *ptr) const { - ASSERT(PointerIsMine(ptr)); + const void* ptr) const { + TC_ASSERT(PointerIsMine(ptr)); const uintptr_t addr = reinterpret_cast(ptr); const size_t slot = GetNearestSlot(addr); return {addr - data_[slot].allocation_start, data_[slot].requested_size}; } -GuardedPageAllocator::ErrorType GuardedPageAllocator::GetStackTraces( - const void *ptr, GpaStackTrace *alloc_trace, - GpaStackTrace *dealloc_trace) const { - ASSERT(PointerIsMine(ptr)); +GuardedAllocationsErrorType GuardedPageAllocator::GetStackTraces( + const void* ptr, GuardedAllocationsStackTrace** alloc_trace, + GuardedAllocationsStackTrace** dealloc_trace) const { + TC_ASSERT(PointerIsMine(ptr)); const uintptr_t addr = reinterpret_cast(ptr); size_t slot = GetNearestSlot(addr); - *alloc_trace = data_[slot].alloc_trace; - *dealloc_trace = data_[slot].dealloc_trace; + *alloc_trace = &data_[slot].alloc_trace; + *dealloc_trace = &data_[slot].dealloc_trace; return GetErrorType(addr, data_[slot]); } // We take guarded samples during periodic profiling samples. Computes the // mean number of profiled samples made for every guarded sample. -static int GetChainedRate() { - auto guarded_rate = Parameters::guarded_sampling_rate(); - auto sample_rate = Parameters::profile_sampling_rate(); - if (guarded_rate < 0 || sample_rate <= 0) { - return guarded_rate; +static int GetChainedInterval() { + auto guarded_interval = Parameters::guarded_sampling_interval(); + auto sample_interval = Parameters::profile_sampling_interval(); + if (guarded_interval < 0 || sample_interval <= 0) { + return guarded_interval; } else { - return std::ceil(static_cast(guarded_rate) / - static_cast(sample_rate)); + return std::ceil(static_cast(guarded_interval) / + static_cast(sample_interval)); } } -void GuardedPageAllocator::Print(Printer *out) { - absl::base_internal::SpinLockHolder h(&guarded_page_lock); - out->printf( +void GuardedPageAllocator::Print(Printer& out) { + out.printf( "\n" "------------------------------------------------\n" "GWP-ASan Status\n" "------------------------------------------------\n" "Successful Allocations: %zu\n" "Failed Allocations: %zu\n" - "Slots Currently Allocated: %zu\n" - "Slots Currently Quarantined: %zu\n" - "Maximum Slots Allocated: %zu / %zu\n" + "Skipped Allocations (No Slots): %zu\n" + "Skipped Allocations (Filtered): %zu\n" + "Skipped Allocations (Too Large): %zu\n" + "Currently Allocated: %zu / %zu\n" + "Allocated High-Watermark: %zu / %zu\n" + "Object Pages Touched: %zu / %zu\n" + "Currently Quarantined: %zu\n" "PARAMETER tcmalloc_guarded_sample_parameter %d\n", - num_allocation_requests_ - num_failed_allocations_, - num_failed_allocations_, num_alloced_pages_, - total_pages_ - num_alloced_pages_, num_alloced_pages_max_, - max_alloced_pages_, GetChainedRate()); -} - -void GuardedPageAllocator::PrintInPbtxt(PbtxtRegion *gwp_asan) const { - absl::base_internal::SpinLockHolder h(&guarded_page_lock); - gwp_asan->PrintI64("successful_allocations", - num_allocation_requests_ - num_failed_allocations_); - gwp_asan->PrintI64("failed_allocations", num_failed_allocations_); - gwp_asan->PrintI64("current_slots_allocated", num_alloced_pages_); - gwp_asan->PrintI64("current_slots_quarantined", - total_pages_ - num_alloced_pages_); - gwp_asan->PrintI64("max_slots_allocated", num_alloced_pages_max_); - gwp_asan->PrintI64("allocated_slot_limit", max_alloced_pages_); - gwp_asan->PrintI64("tcmalloc_guarded_sample_parameter", GetChainedRate()); + // Successful Allocations + successful_allocations_.value(), + // Failed Allocations + failed_allocations_.value(), + // Skipped Allocations (No Slots) + skipped_allocations_noslots_.value(), + // Skipped Allocations (Filtered) + skipped_allocations_filtered_.value(), + // Skipped Allocations (Too Large) + skipped_allocations_toolarge_.value(), + // Currently Allocated + allocated_pages(), max_allocated_pages_, + // Allocated High-Watermark + high_allocated_pages_.load(std::memory_order_relaxed), + max_allocated_pages_, + // Object Pages Touched + pages_touched_.value(), total_pages_, + // Currently Quarantined + total_pages_ - allocated_pages(), + // PARAMETER + GetChainedInterval()); +} + +void GuardedPageAllocator::PrintInPbtxt(PbtxtRegion& gwp_asan) { + gwp_asan.PrintI64("successful_allocations", successful_allocations_.value()); + gwp_asan.PrintI64("failed_allocations", failed_allocations_.value()); + gwp_asan.PrintI64("skipped_allocations_noslots", + skipped_allocations_noslots_.value()); + gwp_asan.PrintI64("skipped_allocations_filtered", + skipped_allocations_filtered_.value()); + gwp_asan.PrintI64("skipped_allocations_toolarge", + skipped_allocations_toolarge_.value()); + gwp_asan.PrintI64("allocated_pages", allocated_pages()); + gwp_asan.PrintI64("quarantine_pages", total_pages_ - allocated_pages()); + gwp_asan.PrintI64("high_allocated_pages", + high_allocated_pages_.load(std::memory_order_relaxed)); + gwp_asan.PrintI64("max_allocated_pages", max_allocated_pages_); + gwp_asan.PrintI64("pages_touched", pages_touched_.value()); + gwp_asan.PrintI64("total_pages", total_pages_); + gwp_asan.PrintI64("tcmalloc_guarded_sample_parameter", GetChainedInterval()); } // Maps 2 * total_pages_ + 1 pages so that there are total_pages_ unique pages // we can return from Allocate with guard pages before and after them. void GuardedPageAllocator::MapPages() { - absl::base_internal::SpinLockHolder h(&guarded_page_lock); - ASSERT(!first_page_addr_); - ASSERT(page_size_ % getpagesize() == 0); + AllocationGuardSpinLockHolder h(&guarded_page_lock_); + TC_ASSERT(!first_page_addr_); + TC_ASSERT_EQ(page_size_ % GetPageSize(), 0); size_t len = (2 * total_pages_ + 1) * page_size_; - auto base_addr = reinterpret_cast( - MmapAligned(len, page_size_, MemoryTag::kSampled)); - ASSERT(base_addr); + auto base_addr = + reinterpret_cast(tc_globals.system_allocator().MmapAligned( + len, page_size_, MemoryTag::kSampled)); + TC_ASSERT(base_addr); if (!base_addr) return; // Tell TCMalloc's PageMap about the memory we own. - const PageId page = PageIdContaining(reinterpret_cast(base_addr)); + const PageId page = PageIdContaining(reinterpret_cast(base_addr)); const Length page_len = BytesToLengthFloor(len); - if (!Static::pagemap().Ensure(page, page_len)) { - ASSERT(false && "Failed to notify page map of page-guarded memory."); + if (!tc_globals.pagemap().Ensure(Range(page, page_len))) { + TC_ASSERT(false, "Failed to notify page map of page-guarded memory."); return; } // Allocate memory for slot metadata. - data_ = reinterpret_cast( - Static::arena().Alloc(sizeof(*data_) * total_pages_)); + data_ = reinterpret_cast( + tc_globals.arena().Alloc(sizeof(*data_) * total_pages_)); for (size_t i = 0; i < total_pages_; ++i) { new (&data_[i]) SlotMetadata; } @@ -240,45 +399,53 @@ void GuardedPageAllocator::MapPages() { // Align first page to page_size_. first_page_addr_ = GetPageAddr(pages_base_addr_ + page_size_); - std::fill_n(free_pages_, total_pages_, true); initialized_ = true; } -// Selects a random slot in O(total_pages_) time. +// Selects a random slot in O(1) time. ssize_t GuardedPageAllocator::ReserveFreeSlot() { - absl::base_internal::SpinLockHolder h(&guarded_page_lock); + AllocationGuardSpinLockHolder h(&guarded_page_lock_); if (!initialized_ || !allow_allocations_) return -1; - num_allocation_requests_++; - if (num_alloced_pages_ == max_alloced_pages_) { - num_failed_allocations_++; + if (GetNumAvailablePages() == 0) { + skipped_allocations_noslots_.Add(1); return -1; } - - rand_ = Sampler::NextRandom(rand_); - size_t num_free_pages = total_pages_ - num_alloced_pages_; - size_t slot = GetIthFreeSlot(rand_ % num_free_pages); - ASSERT(free_pages_[slot]); - free_pages_[slot] = false; - num_alloced_pages_++; - num_alloced_pages_max_ = std::max(num_alloced_pages_, num_alloced_pages_max_); + successful_allocations_.LossyAdd(1); + + const size_t slot = GetFreeSlot(); + TC_ASSERT(!used_pages_.GetBit(slot)); + used_pages_.SetBit(slot); + + // Both writes to allocated_pages_ happen under the guarded_page_lock_, so + // we do not have to use an atomic fetch_add(), which is more expensive due to + // typically imposing a full memory barrier when lowered on e.g. x86. Recent + // compiler optimizations will also turn the store(load(relaxed) + N, relaxed) + // into a simple add instruction. + const size_t nalloced = allocated_pages_.load(std::memory_order_relaxed) + 1; + allocated_pages_.store(nalloced, std::memory_order_relaxed); + if (nalloced > high_allocated_pages_.load(std::memory_order_relaxed)) { + high_allocated_pages_.store(nalloced, std::memory_order_relaxed); + } return slot; } -size_t GuardedPageAllocator::GetIthFreeSlot(size_t ith_free_slot) { - ASSERT(ith_free_slot < total_pages_ - num_alloced_pages_); - for (size_t free_slot_count = 0, j = 0;; j++) { - if (free_pages_[j]) { - if (free_slot_count == ith_free_slot) return j; - free_slot_count++; - } - } +size_t GuardedPageAllocator::GetFreeSlot() { + const size_t idx = rand_.Next() % total_pages_; + // Find the closest adjacent free slot to the random index. + ssize_t slot = used_pages_.FindClearBackwards(idx); + if (slot >= 0) return slot; + slot = used_pages_.FindClear(idx); + TC_ASSERT_LT(slot, total_pages_); + return slot; } void GuardedPageAllocator::FreeSlot(size_t slot) { - ASSERT(slot < total_pages_); - ASSERT(!free_pages_[slot]); - free_pages_[slot] = true; - num_alloced_pages_--; + TC_ASSERT_LT(slot, total_pages_); + TC_ASSERT(used_pages_.GetBit(slot)); + used_pages_.ClearBit(slot); + // Cheaper decrement - see above. + allocated_pages_.store(allocated_pages_.load(std::memory_order_relaxed) - 1, + std::memory_order_relaxed); } uintptr_t GuardedPageAllocator::GetPageAddr(uintptr_t addr) const { @@ -308,10 +475,6 @@ size_t GuardedPageAllocator::GetNearestSlot(uintptr_t addr) const { return AddrToSlot(GetPageAddr(GetNearestValidPage(addr))); } -bool GuardedPageAllocator::IsFreed(size_t slot) const { - return free_pages_[slot]; -} - bool GuardedPageAllocator::WriteOverflowOccurred(size_t slot) const { if (!ShouldRightAlign(slot)) return false; uint8_t magic = GetWriteOverflowMagic(slot); @@ -320,40 +483,46 @@ bool GuardedPageAllocator::WriteOverflowOccurred(size_t slot) const { uintptr_t page_end = SlotToAddr(slot) + page_size_; uintptr_t magic_end = std::min(page_end, alloc_end + kMagicSize); for (uintptr_t p = alloc_end; p < magic_end; ++p) { - if (*reinterpret_cast(p) != magic) return true; + if (*reinterpret_cast(p) != magic) return true; } return false; } -GuardedPageAllocator::ErrorType GuardedPageAllocator::GetErrorType( - uintptr_t addr, const SlotMetadata &d) const { - if (!d.allocation_start) return ErrorType::kUnknown; - if (double_free_detected_) return ErrorType::kDoubleFree; - if (write_overflow_detected_) return ErrorType::kBufferOverflowOnDealloc; - if (d.dealloc_trace.depth) return ErrorType::kUseAfterFree; - if (addr < d.allocation_start) return ErrorType::kBufferUnderflow; +GuardedAllocationsErrorType GuardedPageAllocator::GetErrorType( + uintptr_t addr, const SlotMetadata& d) const { + if (!d.allocation_start) return GuardedAllocationsErrorType::kUnknown; + if (d.dealloc_count.load(std::memory_order_relaxed) >= 2) + return GuardedAllocationsErrorType::kDoubleFree; + if (d.write_overflow_detected) + return GuardedAllocationsErrorType::kBufferOverflowOnDealloc; + if (d.dealloc_trace.depth > 0) { + return GuardedAllocationsErrorType::kUseAfterFree; + } + if (addr < d.allocation_start) { + return GuardedAllocationsErrorType::kBufferUnderflow; + } if (addr >= d.allocation_start + d.requested_size) { - return ErrorType::kBufferOverflow; + return GuardedAllocationsErrorType::kBufferOverflow; } - return ErrorType::kUnknown; + return GuardedAllocationsErrorType::kUnknown; } uintptr_t GuardedPageAllocator::SlotToAddr(size_t slot) const { - ASSERT(slot < total_pages_); + TC_ASSERT_LT(slot, total_pages_); return first_page_addr_ + 2 * slot * page_size_; } size_t GuardedPageAllocator::AddrToSlot(uintptr_t addr) const { uintptr_t offset = addr - first_page_addr_; - ASSERT(offset % page_size_ == 0); - ASSERT((offset / page_size_) % 2 == 0); + TC_ASSERT_EQ(offset % page_size_, 0); + TC_ASSERT_EQ((offset / page_size_) % 2, 0); int slot = offset / page_size_ / 2; - ASSERT(slot >= 0 && slot < total_pages_); + TC_ASSERT(slot >= 0 && slot < total_pages_); return slot; } void GuardedPageAllocator::MaybeRightAlign(size_t slot, size_t size, - size_t alignment, void **ptr) { + size_t alignment, void** ptr) { if (!ShouldRightAlign(slot)) return; uintptr_t adjusted_ptr = reinterpret_cast(*ptr) + page_size_ - size; @@ -366,7 +535,7 @@ void GuardedPageAllocator::MaybeRightAlign(size_t slot, size_t size, // __STDCPP_DEFAULT_NEW_ALIGNMENT__, we're safe aligning to that value. size_t default_alignment = std::min(absl::bit_ceil(size), - std::max(kAlignment, + std::max(static_cast(kAlignment), static_cast(__STDCPP_DEFAULT_NEW_ALIGNMENT__))); // Ensure valid alignment. @@ -376,185 +545,9 @@ void GuardedPageAllocator::MaybeRightAlign(size_t slot, size_t size, // Write magic bytes in alignment padding to detect small overflow writes. size_t magic_size = std::min(alignment_padding, kMagicSize); - memset(reinterpret_cast(adjusted_ptr + size), + memset(reinterpret_cast(adjusted_ptr + size), GetWriteOverflowMagic(slot), magic_size); - *ptr = reinterpret_cast(adjusted_ptr); -} - -// If this failure occurs during "bazel test", writes a warning for Bazel to -// display. -static void RecordBazelWarning(absl::string_view error) { - const char *warning_file = thread_safe_getenv("TEST_WARNINGS_OUTPUT_FILE"); - if (!warning_file) return; // Not a bazel test. - - constexpr char warning[] = "GWP-ASan error detected: "; - int fd = open(warning_file, O_CREAT | O_WRONLY | O_APPEND, 0644); - if (fd == -1) return; - (void)write(fd, warning, sizeof(warning) - 1); - (void)write(fd, error.data(), error.size()); - (void)write(fd, "\n", 1); - close(fd); -} - -// If this failure occurs during a gUnit test, writes an XML file describing the -// error type. Note that we cannot use ::testing::Test::RecordProperty() -// because it doesn't write the XML file if a test crashes (which we're about to -// do here). So we write directly to the XML file instead. -// -static void RecordTestFailure(absl::string_view error) { - const char *xml_file = thread_safe_getenv("XML_OUTPUT_FILE"); - if (!xml_file) return; // Not a gUnit test. - - // Record test failure for Sponge. - constexpr char xml_text_header[] = - "" - "" - " " - " " - " " - " " - " GWP-ASan detected a memory error. See the test log for full report." - " " - ""; - - int fd = open(xml_file, O_CREAT | O_WRONLY | O_TRUNC, 0644); - if (fd == -1) return; - (void)write(fd, xml_text_header, sizeof(xml_text_header) - 1); - (void)write(fd, error.data(), error.size()); - (void)write(fd, xml_text_footer, sizeof(xml_text_footer) - 1); - close(fd); -} -// -// If this crash occurs in a test, records test failure summaries. -// -// error contains the type of error to record. -static void RecordCrash(absl::string_view error) { - - RecordBazelWarning(error); - RecordTestFailure(error); -} - -static void PrintStackTrace(void **stack_frames, size_t depth) { - for (size_t i = 0; i < depth; ++i) { - Log(kLog, __FILE__, __LINE__, " @ ", stack_frames[i]); - } -} - -static void PrintStackTraceFromSignalHandler(void *context) { - void *stack_frames[kMaxStackDepth]; - size_t depth = absl::GetStackTraceWithContext(stack_frames, kMaxStackDepth, 1, - context, nullptr); - PrintStackTrace(stack_frames, depth); -} - -// A SEGV handler that prints stack traces for the allocation and deallocation -// of relevant memory as well as the location of the memory error. -static void SegvHandler(int signo, siginfo_t *info, void *context) { - if (signo != SIGSEGV) return; - void *fault = info->si_addr; - if (!Static::guardedpage_allocator().PointerIsMine(fault)) return; - GuardedPageAllocator::GpaStackTrace alloc_trace, dealloc_trace; - GuardedPageAllocator::ErrorType error = - Static::guardedpage_allocator().GetStackTraces(fault, &alloc_trace, - &dealloc_trace); - if (error == GuardedPageAllocator::ErrorType::kUnknown) return; - pid_t current_thread = absl::base_internal::GetTID(); - off_t offset; - size_t size; - std::tie(offset, size) = - Static::guardedpage_allocator().GetAllocationOffsetAndSize(fault); - - Log(kLog, __FILE__, __LINE__, - "*** GWP-ASan " - "(https://google.github.io/tcmalloc/gwp-asan.html) " - "has detected a memory error ***"); - Log(kLog, __FILE__, __LINE__, ">>> Access at offset", offset, - "into buffer of length", size); - Log(kLog, __FILE__, __LINE__, - "Error originates from memory allocated in thread", alloc_trace.tid, - "at:"); - PrintStackTrace(alloc_trace.stack, alloc_trace.depth); - - switch (error) { - case GuardedPageAllocator::ErrorType::kUseAfterFree: - Log(kLog, __FILE__, __LINE__, "The memory was freed in thread", - dealloc_trace.tid, "at:"); - PrintStackTrace(dealloc_trace.stack, dealloc_trace.depth); - Log(kLog, __FILE__, __LINE__, "Use-after-free occurs in thread", - current_thread, "at:"); - RecordCrash("use-after-free"); - break; - case GuardedPageAllocator::ErrorType::kBufferUnderflow: - Log(kLog, __FILE__, __LINE__, "Buffer underflow occurs in thread", - current_thread, "at:"); - RecordCrash("buffer-underflow"); - break; - case GuardedPageAllocator::ErrorType::kBufferOverflow: - Log(kLog, __FILE__, __LINE__, "Buffer overflow occurs in thread", - current_thread, "at:"); - RecordCrash("buffer-overflow"); - break; - case GuardedPageAllocator::ErrorType::kDoubleFree: - Log(kLog, __FILE__, __LINE__, "The memory was freed in thread", - dealloc_trace.tid, "at:"); - PrintStackTrace(dealloc_trace.stack, dealloc_trace.depth); - Log(kLog, __FILE__, __LINE__, "Double free occurs in thread", - current_thread, "at:"); - RecordCrash("double-free"); - break; - case GuardedPageAllocator::ErrorType::kBufferOverflowOnDealloc: - Log(kLog, __FILE__, __LINE__, - "Buffer overflow (write) detected in thread", current_thread, - "at free:"); - RecordCrash("buffer-overflow-detected-at-free"); - break; - case GuardedPageAllocator::ErrorType::kUnknown: - Crash(kCrash, __FILE__, __LINE__, "Unexpected ErrorType::kUnknown"); - } - PrintStackTraceFromSignalHandler(context); - if (error == GuardedPageAllocator::ErrorType::kBufferOverflowOnDealloc) { - Log(kLog, __FILE__, __LINE__, - "*** Try rerunning with --config=asan to get stack trace of overflow " - "***"); - } -} - -static struct sigaction old_sa; - -static void ForwardSignal(int signo, siginfo_t *info, void *context) { - if (old_sa.sa_flags & SA_SIGINFO) { - old_sa.sa_sigaction(signo, info, context); - } else if (old_sa.sa_handler == SIG_DFL) { - // No previous handler registered. Re-raise signal for core dump. - int err = sigaction(signo, &old_sa, nullptr); - if (err == -1) { - Log(kLog, __FILE__, __LINE__, "Couldn't restore previous sigaction!"); - } - raise(signo); - } else if (old_sa.sa_handler == SIG_IGN) { - return; // Previous sigaction ignored signal, so do the same. - } else { - old_sa.sa_handler(signo); - } -} - -static void HandleSegvAndForward(int signo, siginfo_t *info, void *context) { - SegvHandler(signo, info, context); - ForwardSignal(signo, info, context); -} - -extern "C" void MallocExtension_Internal_ActivateGuardedSampling() { - static absl::once_flag flag; - absl::call_once(flag, []() { - struct sigaction action = {}; - action.sa_sigaction = HandleSegvAndForward; - sigemptyset(&action.sa_mask); - action.sa_flags = SA_SIGINFO; - sigaction(SIGSEGV, &action, &old_sa); - Static::guardedpage_allocator().AllowAllocations(); - }); + *ptr = reinterpret_cast(adjusted_ptr); } } // namespace tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator.h b/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator.h index e5a6118c081c..295a9d756f4d 100644 --- a/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator.h +++ b/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,24 +16,29 @@ #ifndef TCMALLOC_GUARDED_PAGE_ALLOCATOR_H_ #define TCMALLOC_GUARDED_PAGE_ALLOCATOR_H_ -#include -#include -#include - +#include +#include +#include #include #include "absl/base/attributes.h" +#include "absl/base/const_init.h" #include "absl/base/internal/spinlock.h" #include "absl/base/thread_annotations.h" #include "tcmalloc/common.h" +#include "tcmalloc/guarded_allocations.h" +#include "tcmalloc/internal/atomic_stats_counter.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/exponential_biased.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/range_tracker.h" +#include "tcmalloc/internal/stacktrace_filter.h" +#include "tcmalloc/pages.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { -ABSL_CONST_INIT extern absl::base_internal::SpinLock guarded_page_lock; - // An allocator that gives each allocation a new region, with guard pages on // either side of the allocated region. If a buffer is overflowed to the next // guard page or underflowed to the previous guard page, a segfault occurs. @@ -44,16 +50,7 @@ ABSL_CONST_INIT extern absl::base_internal::SpinLock guarded_page_lock; // exception of calls to Init() and Destroy() (see corresponding function // comments). // -// SYNCHRONIZATION -// Requires the SpinLock guarded_page_lock to be defined externally. This is -// required so that this class may be instantiated with static storage -// duration. The lock is held by this class during initialization and when -// accessing the internal free page map. -// // Example: -// ABSL_CONST_INIT absl::base_internal::SpinLock -// guarded_page_lock(absl::kConstInit, -// absl::base_internal::SCHEDULE_KERNEL_ONLY); // ABSL_CONST_INIT GuardedPageAllocator gpa; // // void foo() { @@ -75,57 +72,39 @@ ABSL_CONST_INIT extern absl::base_internal::SpinLock guarded_page_lock; // } class GuardedPageAllocator { public: - struct GpaStackTrace { - void *stack[kMaxStackDepth]; - size_t depth = 0; - pid_t tid = 0; - }; - // Maximum number of pages this class can allocate. static constexpr size_t kGpaMaxPages = 512; - enum class ErrorType { - kUseAfterFree, - kBufferUnderflow, - kBufferOverflow, - kDoubleFree, - kBufferOverflowOnDealloc, - kUnknown, - }; - constexpr GuardedPageAllocator() - : free_pages_{}, - num_alloced_pages_(0), - num_alloced_pages_max_(0), - num_allocation_requests_(0), - num_failed_allocations_(0), + : guarded_page_lock_(absl::kConstInit, + absl::base_internal::SCHEDULE_KERNEL_ONLY), + allocated_pages_(0), + high_allocated_pages_(0), data_(nullptr), pages_base_addr_(0), pages_end_addr_(0), first_page_addr_(0), - max_alloced_pages_(0), + max_allocated_pages_(0), total_pages_(0), page_size_(0), rand_(0), initialized_(false), - allow_allocations_(false), - double_free_detected_(false), - write_overflow_detected_(false) {} + allow_allocations_(false) {} - GuardedPageAllocator(const GuardedPageAllocator &) = delete; - GuardedPageAllocator &operator=(const GuardedPageAllocator &) = delete; + GuardedPageAllocator(const GuardedPageAllocator&) = delete; + GuardedPageAllocator& operator=(const GuardedPageAllocator&) = delete; ~GuardedPageAllocator() = default; - // Configures this allocator to allocate up to max_alloced_pages pages at a + // Configures this allocator to allocate up to max_allocated_pages pages at a // time from a pool of total_pages pages, where: - // 1 <= max_alloced_pages <= total_pages <= kGpaMaxPages + // 1 <= max_allocated_pages <= total_pages <= kGpaMaxPages // // This method should be called non-concurrently and only once to complete // initialization. Dynamic initialization is deliberately done here and not // in the constructor, thereby allowing the constructor to be constexpr and // avoiding static initialization order issues. - void Init(size_t max_alloced_pages, size_t total_pages) + void Init(size_t max_allocated_pages, size_t total_pages) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); // Unmaps memory allocated by this class. @@ -136,27 +115,45 @@ class GuardedPageAllocator { // and avoiding use-after-destruction issues for static/global instances. void Destroy(); - // On success, returns a pointer to size bytes of page-guarded memory, aligned - // to alignment. On failure, returns nullptr. The returned pointer is - // guaranteed to be tagged. Failure can occur if memory could not be mapped - // or protected, if all guarded pages are already allocated, or if size is 0. + void AcquireInternalLocks() ABSL_LOCKS_EXCLUDED(guarded_page_lock_); + void ReleaseInternalLocks() ABSL_LOCKS_EXCLUDED(guarded_page_lock_); + + + // If this allocation can be guarded, and if it's time to do a guarded sample, + // returns an instance of GuardedAllocWithStatus, that includes guarded + // allocation Span and guarded status. Otherwise, returns nullptr and the + // status indicating why the allocation may not be guarded. + GuardedAllocWithStatus TrySample(size_t size, size_t alignment, + Length num_pages, + const StackTrace& stack_trace); + + // On success, returns an instance of GuardedAllocWithStatus which includes a + // pointer to size bytes of page-guarded memory, aligned to alignment. The + // member 'alloc' is a pointer that is guaranteed to be tagged. The 'status' + // member is set to GuardedStatus::Guarded. On failure, returns an instance + // of GuardedAllocWithStatus (the 'alloc' member is set to 'nullptr'). + // Failure can occur if memory could not be mapped or protected, if all + // guarded pages are already allocated, or if size is 0. These conditions are + // reflected in the 'status' member of the GuardedAllocWithStatus return + // value. // // Precondition: size and alignment <= page_size_ // Precondition: alignment is 0 or a power of 2 - void *Allocate(size_t size, size_t alignment) - ABSL_LOCKS_EXCLUDED(guarded_page_lock); + GuardedAllocWithStatus Allocate(size_t size, size_t alignment, + const StackTrace& stack_trace) + ABSL_LOCKS_EXCLUDED(guarded_page_lock_); // Deallocates memory pointed to by ptr. ptr must have been previously // returned by a call to Allocate. - void Deallocate(void *ptr) ABSL_LOCKS_EXCLUDED(guarded_page_lock); + void Deallocate(void* ptr) ABSL_LOCKS_EXCLUDED(guarded_page_lock_); // Returns the size requested when ptr was allocated. ptr must have been // previously returned by a call to Allocate. - size_t GetRequestedSize(const void *ptr) const; + size_t GetRequestedSize(const void* ptr) const; // Returns ptr's offset from the beginning of its allocation along with the // allocation's size. - std::pair GetAllocationOffsetAndSize(const void *ptr) const; + std::pair GetAllocationOffsetAndSize(const void* ptr) const; // Records stack traces in alloc_trace and dealloc_trace for the page nearest // to ptr. alloc_trace is the trace at the time the page was allocated. If @@ -167,56 +164,71 @@ class GuardedPageAllocator { // Returns the likely error type for an access at ptr. // // Requires that ptr points to memory mapped by this class. - ErrorType GetStackTraces(const void *ptr, GpaStackTrace *alloc_trace, - GpaStackTrace *dealloc_trace) const; + GuardedAllocationsErrorType GetStackTraces( + const void* ptr, GuardedAllocationsStackTrace** alloc_trace, + GuardedAllocationsStackTrace** dealloc_trace) const; // Writes a human-readable summary of GuardedPageAllocator's internal state to // *out. - void Print(Printer *out) ABSL_LOCKS_EXCLUDED(guarded_page_lock); - void PrintInPbtxt(PbtxtRegion *gwp_asan) const - ABSL_LOCKS_EXCLUDED(guarded_page_lock); + void Print(Printer& out) ABSL_LOCKS_EXCLUDED(guarded_page_lock_); + void PrintInPbtxt(PbtxtRegion& gwp_asan) + ABSL_LOCKS_EXCLUDED(guarded_page_lock_); // Returns true if ptr points to memory managed by this class. inline bool ABSL_ATTRIBUTE_ALWAYS_INLINE - PointerIsMine(const void *ptr) const { + PointerIsMine(const void* ptr) const { uintptr_t addr = reinterpret_cast(ptr); return pages_base_addr_ <= addr && addr < pages_end_addr_; } // Allows Allocate() to start returning allocations. - void AllowAllocations() ABSL_LOCKS_EXCLUDED(guarded_page_lock) { - absl::base_internal::SpinLockHolder h(&guarded_page_lock); + void AllowAllocations() ABSL_LOCKS_EXCLUDED(guarded_page_lock_) { + AllocationGuardSpinLockHolder h(&guarded_page_lock_); allow_allocations_ = true; } + // Returns the number of pages available for allocation, based on how many are + // currently in use. (Should only be used in testing.) + size_t GetNumAvailablePages() const { + return max_allocated_pages_ - allocated_pages(); + } + + // Resets sampling state. + void Reset(); + + size_t page_size() const { return page_size_; } + size_t successful_allocations() const { + return successful_allocations_.value(); + } + private: // Structure for storing data about a slot. struct SlotMetadata { - GpaStackTrace alloc_trace; - GpaStackTrace dealloc_trace; - size_t requested_size = 0; - uintptr_t allocation_start = 0; + GuardedAllocationsStackTrace alloc_trace; + GuardedAllocationsStackTrace dealloc_trace; + size_t requested_size = 0; // requested allocaton size + uintptr_t allocation_start = 0; // allocation start address + std::atomic dealloc_count = 0; // deallocation counter + bool write_overflow_detected = false; // write overflow detected }; // Max number of magic bytes we use to detect write-overflows at deallocation. static constexpr size_t kMagicSize = 32; // Maps pages into memory. - void MapPages() ABSL_LOCKS_EXCLUDED(guarded_page_lock) + void MapPages() ABSL_LOCKS_EXCLUDED(guarded_page_lock_) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); // Reserves and returns a slot randomly selected from the free slots in - // free_pages_. Returns -1 if no slots available, or if AllowAllocations() + // used_pages_. Returns -1 if no slots available, or if AllowAllocations() // hasn't been called yet. - ssize_t ReserveFreeSlot() ABSL_LOCKS_EXCLUDED(guarded_page_lock); + ssize_t ReserveFreeSlot() ABSL_LOCKS_EXCLUDED(guarded_page_lock_); - // Returns the i-th free slot of free_pages_. i must be in the range [0, - // total_pages_ - num_alloced_pages_). - size_t GetIthFreeSlot(size_t i) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(guarded_page_lock); + // Returns a random free slot in used_pages_. + size_t GetFreeSlot() ABSL_EXCLUSIVE_LOCKS_REQUIRED(guarded_page_lock_); // Marks the specified slot as unreserved. - void FreeSlot(size_t slot) ABSL_EXCLUSIVE_LOCKS_REQUIRED(guarded_page_lock); + void FreeSlot(size_t slot) ABSL_EXCLUSIVE_LOCKS_REQUIRED(guarded_page_lock_); // Returns the address of the page that addr resides on. uintptr_t GetPageAddr(uintptr_t addr) const; @@ -227,16 +239,13 @@ class GuardedPageAllocator { // Returns the slot number for the page nearest to addr. size_t GetNearestSlot(uintptr_t addr) const; - // Returns true if the specified slot has already been freed. - bool IsFreed(size_t slot) const - ABSL_EXCLUSIVE_LOCKS_REQUIRED(guarded_page_lock); - // Returns true if magic bytes for slot were overwritten. bool WriteOverflowOccurred(size_t slot) const; // Returns the likely error type for the given access address and metadata // associated with the nearest slot. - ErrorType GetErrorType(uintptr_t addr, const SlotMetadata &d) const; + GuardedAllocationsErrorType GetErrorType(uintptr_t addr, + const SlotMetadata& d) const; // Magic constant used for detecting write-overflows at deallocation time. static uint8_t GetWriteOverflowMagic(size_t slot) { @@ -250,58 +259,67 @@ class GuardedPageAllocator { // If slot is marked for right alignment, moves the allocation in *ptr to the // right end of the slot, maintaining the specified size and alignment. Magic // bytes are written in any alignment padding. - void MaybeRightAlign(size_t slot, size_t size, size_t alignment, void **ptr); + void MaybeRightAlign(size_t slot, size_t size, size_t alignment, void** ptr); uintptr_t SlotToAddr(size_t slot) const; size_t AddrToSlot(uintptr_t addr) const; - // Maps each bool to one page. - // true: Free. false: Reserved. - bool free_pages_[kGpaMaxPages] ABSL_GUARDED_BY(guarded_page_lock); - - // Number of currently-allocated pages. - size_t num_alloced_pages_ ABSL_GUARDED_BY(guarded_page_lock); + size_t allocated_pages() const { + return allocated_pages_.load(std::memory_order_relaxed); + } - // The high-water mark for num_alloced_pages_. - size_t num_alloced_pages_max_ ABSL_GUARDED_BY(guarded_page_lock); + // DecayingStackTraceFilter instance to limit allocations already covered by a + // current or recent allocation. + // + // With the chosen configuration, assuming 90% unique allocations in a fully + // utilized pool (in the worst case), the CBF will have a false positive + // probability of 20%. In more moderate scenarios with unique allocations of + // 80% or below, the probability of false positives will be below 10%. + DecayingStackTraceFilter stacktrace_filter_; - // Number of calls to Allocate. - size_t num_allocation_requests_ ABSL_GUARDED_BY(guarded_page_lock); + absl::base_internal::SpinLock guarded_page_lock_; - // Number of times Allocate has failed. - size_t num_failed_allocations_ ABSL_GUARDED_BY(guarded_page_lock); + // Maps each bool to one page. + // true: reserved. false: freed. + Bitmap used_pages_ ABSL_GUARDED_BY(guarded_page_lock_); + + // Number of currently allocated pages. Atomic so it may be accessed outside + // the guarded_page_lock_ to calculate heuristics based on pool utilization. + std::atomic allocated_pages_; + // The high-water mark for allocated_pages_. + std::atomic high_allocated_pages_; + + // Number of successful allocations. + tcmalloc_internal::StatsCounter successful_allocations_; + // Number of times an allocation failed due to an internal error. + tcmalloc_internal::StatsCounter failed_allocations_; + // Number of times an allocation was skipped (no available slots). + tcmalloc_internal::StatsCounter skipped_allocations_noslots_; + // Number of times an allocation was skipped (filtered). + tcmalloc_internal::StatsCounter skipped_allocations_filtered_; + // Number of times an allocation was skipped (too large). + tcmalloc_internal::StatsCounter skipped_allocations_toolarge_; + // Number of pages allocated at least once from page pool. + tcmalloc_internal::StatsCounter pages_touched_; // A dynamically-allocated array of stack trace data captured when each page // is allocated/deallocated. Printed by the SEGV handler when a memory error // is detected. - SlotMetadata *data_; + SlotMetadata* data_; - uintptr_t pages_base_addr_; // Points to start of mapped region. - uintptr_t pages_end_addr_; // Points to the end of mapped region. - uintptr_t first_page_addr_; // Points to first page returnable by Allocate. - size_t max_alloced_pages_; // Max number of pages to allocate at once. - size_t total_pages_; // Size of the page pool to allocate from. - size_t page_size_; // Size of pages we allocate. - uint64_t rand_; // RNG seed. + uintptr_t pages_base_addr_; // Points to start of mapped region. + uintptr_t pages_end_addr_; // Points to the end of mapped region. + uintptr_t first_page_addr_; // Points to first page returnable by Allocate. + size_t max_allocated_pages_; // Max number of pages to allocate at once. + size_t total_pages_; // Size of the page pool to allocate from. + size_t page_size_; // Size of pages we allocate. + Random rand_; // True if this object has been fully initialized. - bool initialized_ ABSL_GUARDED_BY(guarded_page_lock); + bool initialized_ ABSL_GUARDED_BY(guarded_page_lock_); // Flag to control whether we can return allocations or not. - bool allow_allocations_ ABSL_GUARDED_BY(guarded_page_lock); - - // Set to true if a double free has occurred. - bool double_free_detected_; - - // Set to true if a write overflow was detected on deallocation. - bool write_overflow_detected_; - - friend struct ConstexprCheck; -}; - -struct ConstexprCheck { - static_assert(GuardedPageAllocator().rand_ || true, - "GuardedPageAllocator must have a constexpr constructor"); + bool allow_allocations_ ABSL_GUARDED_BY(guarded_page_lock_); }; } // namespace tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator_benchmark.cc b/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator_benchmark.cc index fb6d0ea265d5..b19a00bb41ba 100644 --- a/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator_benchmark.cc +++ b/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator_benchmark.cc @@ -12,48 +12,170 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include +#include +#include +#include +#include +#include +#include -#include "absl/base/internal/spinlock.h" #include "benchmark/benchmark.h" +#include "tcmalloc/common.h" #include "tcmalloc/guarded_page_allocator.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/page_size.h" +#include "tcmalloc/malloc_extension.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/static_vars.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { namespace { +using GuardedStatus = Profile::Sample::GuardedStatus; -static constexpr size_t kMaxGpaPages = GuardedPageAllocator::kGpaMaxPages; +constexpr size_t kMaxGpaPages = GuardedPageAllocator::kGpaMaxPages; -// Size of pages used by GuardedPageAllocator. -static size_t PageSize() { +// Size of pages used by GuardedPageAllocator. See GuardedPageAllocator::Init(). +size_t GetGpaPageSize() { static const size_t page_size = - std::max(kPageSize, static_cast(getpagesize())); + std::max(kPageSize, static_cast(GetPageSize())); return page_size; } -void BM_AllocDealloc(benchmark::State& state) { - static GuardedPageAllocator* gpa = []() { +inline auto& GetStackTrace(size_t first_frame) { + thread_local StackTrace* s = new StackTrace; + s->stack[0] = reinterpret_cast(first_frame + 42); + s->depth = 1; + return *s; +} + +std::unique_ptr +GetGuardedPageAllocator() { + static GuardedPageAllocator* gpa = [] { auto gpa = new GuardedPageAllocator; - absl::base_internal::SpinLockHolder h(&pageheap_lock); + PageHeapSpinLockHolder l; gpa->Init(kMaxGpaPages, kMaxGpaPages); gpa->AllowAllocations(); + // Benchmark should always sample. + MallocExtension::SetProfileSamplingInterval(1); + MallocExtension::SetGuardedSamplingInterval(1); return gpa; }(); - size_t alloc_size = state.range(0); + return {gpa, +[](GuardedPageAllocator* gpa) { + // We can't reset GuardedPageAllocator before the benchmark in + // multi-threaded mode as it might race with pre-initialization and + // concurrent Reset() from all other benchmark threads. Instead, + // just reset after each benchmark. + gpa->Reset(); + }}; +} + +// Benchmark for guarded page allocation overhead only, to focus on free slot +// selection, mprotect() overhead, and allocation metadata storage. +void BM_AllocDealloc(benchmark::State& state) { + const size_t alloc_size = state.range(0); + auto gpa = GetGuardedPageAllocator(); for (auto _ : state) { - char* ptr = reinterpret_cast(gpa->Allocate(alloc_size, 0)); - CHECK_CONDITION(ptr != nullptr); + char* ptr = reinterpret_cast( + gpa->Allocate(alloc_size, 0, GetStackTrace(0)).alloc); + TC_CHECK_NE(ptr, nullptr); ptr[0] = 'X'; // Page fault first page. ptr[alloc_size - 1] = 'X'; // Page fault last page. gpa->Deallocate(ptr); } } -BENCHMARK(BM_AllocDealloc)->Range(1, PageSize()); +BENCHMARK(BM_AllocDealloc)->Range(1, GetGpaPageSize()); BENCHMARK(BM_AllocDealloc)->Arg(1)->ThreadRange(1, kMaxGpaPages); +auto& GetReserved() { + static auto* ret = + new std::vector>>; + return *ret; +} + +// Exhaust the pool first so we do not profile allocation overhead. +void ReservePool(const benchmark::State&) { + TC_CHECK(GetReserved().empty()); + auto* gpa = GetGuardedPageAllocator().release(); // do not Reset() + auto deleter = [gpa](void* p) { gpa->Deallocate(p); }; + + for (size_t stack_idx = 0;;) { + auto alloc = gpa->TrySample(1, 0, Length(1), GetStackTrace(stack_idx)); + switch (alloc.status) { + case GuardedStatus::NoAvailableSlots: + TC_CHECK(!GetReserved().empty()); + return; + case GuardedStatus::RateLimited: + // Emulate that non-guarded sampling happened. + tc_globals.total_sampled_count_.Add(1); + break; + case GuardedStatus::Filtered: + // The filter is rejecting the stack trace, give it one more unique + // stack trace. + stack_idx++; + break; + default: + if (alloc.alloc) GetReserved().emplace_back(alloc.alloc, deleter); + break; + } + } +} + +void ReleasePool(const benchmark::State&) { + TC_CHECK(!GetReserved().empty()); + GetReserved().clear(); +} + +// Benchmark that includes sampling-decision overhead. +void BM_TrySample(benchmark::State& state) { + TC_CHECK(!GetReserved().empty()); + // Shared between benchmark threads. We don't care if one of the threads + // doesn't see one of the statuses. + static std::atomic seen_filtered; + seen_filtered = false; + + const size_t alloc_size = state.range(0); + auto gpa = GetGuardedPageAllocator(); + size_t stack_idx = 0; + + for (auto _ : state) { + StackTrace& stack_trace = GetStackTrace(stack_idx++ % GetReserved().size()); + auto alloc = gpa->TrySample(alloc_size, 0, Length(1), stack_trace); + + switch (alloc.status) { + case GuardedStatus::RateLimited: + tc_globals.total_sampled_count_.Add(1); + break; + case GuardedStatus::Filtered: + seen_filtered.store(true, std::memory_order_relaxed); + break; + default: + TC_CHECK_NE(alloc.status, GuardedStatus::Guarded); + TC_CHECK_NE(alloc.status, GuardedStatus::LargerThanOnePage); + TC_CHECK_NE(alloc.status, GuardedStatus::Disabled); + TC_CHECK_NE(alloc.status, GuardedStatus::MProtectFailed); + TC_CHECK_NE(alloc.status, GuardedStatus::TooSmall); + break; + } + TC_CHECK_EQ(alloc.alloc, nullptr); + } + + if (state.iterations() > 1000) TC_CHECK(seen_filtered); +} + +BENCHMARK(BM_TrySample) + ->Range(1, GetGpaPageSize()) + ->Setup(ReservePool) + ->Teardown(ReleasePool); +BENCHMARK(BM_TrySample) + ->Arg(1) + ->ThreadRange(1, kMaxGpaPages) + ->Setup(ReservePool) + ->Teardown(ReleasePool); + } // namespace } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator_profile_test.cc b/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator_profile_test.cc new file mode 100644 index 000000000000..961bf77b652f --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator_profile_test.cc @@ -0,0 +1,371 @@ +// Copyright 2019 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include "benchmark/benchmark.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/container/flat_hash_set.h" +#include "absl/functional/function_ref.h" +#include "absl/log/check.h" +#include "tcmalloc/common.h" +#include "tcmalloc/malloc_extension.h" +#include "tcmalloc/parameters.h" +#include "tcmalloc/static_vars.h" +#include "tcmalloc/testing/testutil.h" + +namespace tcmalloc { +namespace tcmalloc_internal { + +class GuardedPageAllocatorProfileTest : public testing::Test { + public: + struct NextSteps { + bool stop = true; // stop allocating + bool free = true; // free allocation + }; + + void SetUp() override { MallocExtension::ActivateGuardedSampling(); } + + // Return the number of allocations + int AllocateUntil(size_t size, + absl::FunctionRef evaluate_alloc) { + // The test harness may allocate, so move Reset() close to where we do the + // allocations we want to test. + tc_globals.guardedpage_allocator().Reset(); + + int alloc_count = 0; + while (true) { + void* alloc = ::operator new(size); + ++alloc_count; + benchmark::DoNotOptimize(alloc); + auto result = evaluate_alloc(alloc); + // evaluate_alloc takes responsibility for delete/free if result.free is + // set to false. + if (result.free) { + ::operator delete(alloc); + } + if (result.stop) { + break; + } + } + return alloc_count; + } + + int AllocateGuardableUntil( + size_t size, absl::FunctionRef evaluate_alloc) { + CHECK_LE(size, tc_globals.guardedpage_allocator().page_size()); + return AllocateUntil(size, evaluate_alloc); + } + + // Allocate until sample is guarded + // Called to reduce the internal counter to -1, which will trigger resetting + // the counter to the configured rate. + void AllocateUntilGuarded() { + AllocateGuardableUntil(968, [&](void* alloc) -> NextSteps { + return {!IsNormalMemory(alloc) && + tc_globals.guardedpage_allocator().PointerIsMine(alloc), + true}; + }); + } + + void ExamineSamples( + Profile& profile, Profile::Sample::GuardedStatus sought_status, + absl::FunctionRef verify = + [](const Profile::Sample& s) { /* do nothing */ }) { + absl::flat_hash_set found_statuses; + int samples = 0; + profile.Iterate([&](const Profile::Sample& s) { + ++samples; + found_statuses.insert(s.guarded_status); + verify(s); + }); + EXPECT_THAT(found_statuses, ::testing::Contains(sought_status)); + } +}; + +namespace { + +TEST_F(GuardedPageAllocatorProfileTest, Guarded) { + ScopedAlwaysSample always_sample; + AllocateUntilGuarded(); + auto token = MallocExtension::StartAllocationProfiling(); + + AllocateGuardableUntil( + 1051, [&](void* alloc) -> NextSteps { return {true, true}; }); + + auto profile = std::move(token).Stop(); + ExamineSamples(profile, Profile::Sample::GuardedStatus::Guarded); +} + +TEST_F(GuardedPageAllocatorProfileTest, NotAttempted) { + ScopedProfileSamplingInterval profile_sampling_interval(4096); + auto token = MallocExtension::StartAllocationProfiling(); + + constexpr size_t alloc_size = 2 * 1024 * 1024; + AllocateUntil(alloc_size, + [&](void* alloc) -> NextSteps { return {true, true}; }); + + auto profile = std::move(token).Stop(); + ExamineSamples(profile, Profile::Sample::GuardedStatus::NotAttempted, + [&](const Profile::Sample& s) { + switch (s.guarded_status) { + case Profile::Sample::GuardedStatus::Guarded: + EXPECT_NE(alloc_size, s.requested_size); + break; + default: + break; + } + }); +} + +TEST_F(GuardedPageAllocatorProfileTest, LargerThanOnePage) { + ScopedAlwaysSample always_sample; + AllocateUntilGuarded(); + auto token = MallocExtension::StartAllocationProfiling(); + + constexpr size_t alloc_size = kPageSize + 1; + AllocateUntil(alloc_size, + [&](void* alloc) -> NextSteps { return {true, true}; }); + + auto profile = std::move(token).Stop(); + ExamineSamples(profile, Profile::Sample::GuardedStatus::LargerThanOnePage, + [&](const Profile::Sample& s) { + switch (s.guarded_status) { + case Profile::Sample::GuardedStatus::Guarded: + EXPECT_NE(alloc_size, s.requested_size); + break; + default: + break; + } + }); +} + +TEST_F(GuardedPageAllocatorProfileTest, Disabled) { + ScopedGuardedSamplingInterval guarded_sampling_interval(-1); + ScopedProfileSamplingInterval profile_sampling_interval(1); + auto token = MallocExtension::StartAllocationProfiling(); + + AllocateGuardableUntil( + 1024, [&](void* alloc) -> NextSteps { return {true, true}; }); + + auto profile = std::move(token).Stop(); + ExamineSamples(profile, Profile::Sample::GuardedStatus::Disabled); +} + +TEST_F(GuardedPageAllocatorProfileTest, RateLimited) { + // For every 2 sampled allocations, have just 1 guarded allocation. + ScopedProfileSamplingInterval profile_sampling_interval(1); + ScopedGuardedSamplingInterval guarded_sampling_interval(2); + auto token = MallocExtension::StartAllocationProfiling(); + + // Keep allocating until something is sampled + constexpr size_t kAllocSize = 1033; + size_t num_guarded = 0; + size_t num_sampled = 0; + AllocateGuardableUntil(kAllocSize, [&](void* alloc) -> NextSteps { + if (!IsNormalMemory(alloc)) { + num_sampled++; + if (tc_globals.guardedpage_allocator().PointerIsMine(alloc)) { + num_guarded++; + } + // The expectation is that as soon as there are more sampled allocations + // than guarded, at least once the rate limiter kicked in. + return {num_guarded > 0 && num_sampled > num_guarded, true}; + } + return {false, true}; + }); + + // Ensure Guarded and RateLimited both occur for the alloc_size + bool success_found = false; + bool ratelimited_found = false; + auto profile = std::move(token).Stop(); + ExamineSamples(profile, Profile::Sample::GuardedStatus::RateLimited, + [&](const Profile::Sample& s) { + if (s.requested_size != kAllocSize) return; + switch (s.guarded_status) { + case Profile::Sample::GuardedStatus::Guarded: + success_found = true; + break; + case Profile::Sample::GuardedStatus::RateLimited: + ratelimited_found = true; + break; + default: + break; + } + }); + EXPECT_TRUE(success_found); + EXPECT_TRUE(ratelimited_found); +} + +TEST_F(GuardedPageAllocatorProfileTest, NeverRateLimited) { + ScopedProfileSamplingInterval profile_sampling_interval(42); + ScopedGuardedSamplingInterval guarded_sampling_interval(42); + ASSERT_EQ(MallocExtension::GetGuardedSamplingInterval(), + MallocExtension::GetProfileSamplingInterval()); + auto token = MallocExtension::StartAllocationProfiling(); + + constexpr size_t kAllocSize = 1033; + size_t num_guarded = 0; + AllocateGuardableUntil(kAllocSize, [&](void* alloc) -> NextSteps { + if (!IsNormalMemory(alloc)) { + // Stack trace filter may still filter. + if (tc_globals.guardedpage_allocator().PointerIsMine(alloc)) + num_guarded++; + return {num_guarded > 100, true}; + } + return {false, true}; + }); + auto profile = std::move(token).Stop(); + ExamineSamples(profile, Profile::Sample::GuardedStatus::Guarded, + [&](const Profile::Sample& s) { + if (s.requested_size != kAllocSize) return; + EXPECT_NE(s.guarded_status, + Profile::Sample::GuardedStatus::RateLimited); + }); +} + +TEST_F(GuardedPageAllocatorProfileTest, TooSmall) { + ScopedAlwaysSample always_sample; + AllocateUntilGuarded(); + auto token = MallocExtension::StartAllocationProfiling(); + + // Next sampled allocation should be too small + constexpr size_t alloc_size = 0; + AllocateGuardableUntil( + alloc_size, [&](void* alloc) -> NextSteps { return {true, true}; }); + + auto profile = std::move(token).Stop(); + ExamineSamples(profile, Profile::Sample::GuardedStatus::TooSmall, + [&](const Profile::Sample& s) { + switch (s.guarded_status) { + case Profile::Sample::GuardedStatus::Guarded: + EXPECT_NE(alloc_size, s.requested_size); + break; + case Profile::Sample::GuardedStatus::TooSmall: + EXPECT_EQ(alloc_size, s.requested_size); + break; + default: + break; + } + }); +} + +TEST_F(GuardedPageAllocatorProfileTest, NoAvailableSlots) { + ScopedAlwaysSample always_sample; + AllocateUntilGuarded(); + + std::vector> allocs; + // Guard until there are no slots available. + AllocateGuardableUntil(1039, [&](void* alloc) -> NextSteps { + if (tc_globals.guardedpage_allocator().PointerIsMine(alloc)) { + allocs.emplace_back(alloc, + static_cast(::operator delete)); + return {tc_globals.guardedpage_allocator().GetNumAvailablePages() == 0, + false}; + } + return {false, true}; + }); + + auto token = MallocExtension::StartAllocationProfiling(); + // This should fail for lack of slots + AllocateGuardableUntil(1055, [&](void* alloc) -> NextSteps { + return {!tc_globals.guardedpage_allocator().PointerIsMine(alloc), true}; + }); + + auto profile = std::move(token).Stop(); + ExamineSamples(profile, Profile::Sample::GuardedStatus::NoAvailableSlots); +} + +TEST_F(GuardedPageAllocatorProfileTest, NeverSample) { + ScopedProfileSamplingInterval profile_sampling_interval(0); + auto token = MallocExtension::StartAllocationProfiling(); + + // This will not succeed in guarding anything. + int alloc_count = AllocateGuardableUntil( + 1025, [&](void* alloc) -> NextSteps { return {true, true}; }); + ASSERT_EQ(alloc_count, 1); + + auto profile = std::move(token).Stop(); + int samples = 0; + profile.Iterate([&](const Profile::Sample& s) { ++samples; }); + EXPECT_EQ(samples, 0); +} + +TEST_F(GuardedPageAllocatorProfileTest, Filtered) { + auto token = MallocExtension::StartAllocationProfiling(); + int guarded_count = 0; + AllocateGuardableUntil(1058, [&](void* alloc) -> NextSteps { + guarded_count += tc_globals.guardedpage_allocator().PointerIsMine(alloc); + return {guarded_count == 1000, true}; + }); + + auto profile = std::move(token).Stop(); + ExamineSamples(profile, Profile::Sample::GuardedStatus::Filtered); +} + +TEST_F(GuardedPageAllocatorProfileTest, FilteredWithRateLimiting) { + // Have to have a rate that is less than every single one. + ScopedGuardedSamplingInterval scoped_guarded_sampling_interval( + 2 * tcmalloc::tcmalloc_internal::Parameters::profile_sampling_interval()); + AllocateUntilGuarded(); + + auto token = MallocExtension::StartAllocationProfiling(); + // Obtain a few sample guarding candidates, which will eventually yield at + // least one that is filtered. + int guarded_count = 0; + int sampled_count = 0; + AllocateGuardableUntil(1062, [&](void* alloc) -> NextSteps { + if (!IsNormalMemory(alloc)) { + if (tc_globals.guardedpage_allocator().PointerIsMine(alloc)) { + ++guarded_count; + } + ++sampled_count; + } + return {guarded_count == 1000, true}; + }); + + EXPECT_GT(sampled_count, guarded_count); + + auto profile = std::move(token).Stop(); + ExamineSamples(profile, Profile::Sample::GuardedStatus::Filtered); +} + +TEST_F(GuardedPageAllocatorProfileTest, DynamicParamChange) { + ScopedGuardedSamplingInterval scoped_guarded_sampling_interval( + 2 * tcmalloc::tcmalloc_internal::Parameters::profile_sampling_interval()); + for (int loop_count = 0; loop_count < 10; ++loop_count) { + AllocateUntilGuarded(); + + // Accumulate at least 2 guarded allocations. + auto token = MallocExtension::StartAllocationProfiling(); + int guarded_count = 0; + AllocateGuardableUntil(1063, [&](void* alloc) -> NextSteps { + if (tc_globals.guardedpage_allocator().PointerIsMine(alloc)) { + ++guarded_count; + } + return {guarded_count > 1, true}; + }); + + auto profile = std::move(token).Stop(); + ExamineSamples(profile, Profile::Sample::GuardedStatus::Guarded); + } +} + +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator_test.cc b/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator_test.cc index 0d603de6901b..29e389576ce2 100644 --- a/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/guarded_page_allocator_test.cc @@ -14,31 +14,26 @@ #include "tcmalloc/guarded_page_allocator.h" -#include -#include -#include - #include +#include +#include +#include #include -#include -#include +#include #include // NOLINT(build/c++11) #include #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/casts.h" -#include "absl/base/internal/spinlock.h" -#include "absl/base/internal/sysinfo.h" +#include "absl/base/attributes.h" #include "absl/container/flat_hash_set.h" -#include "absl/memory/memory.h" -#include "absl/numeric/bits.h" -#include "absl/strings/str_cat.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" #include "tcmalloc/common.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/page_size.h" +#include "tcmalloc/internal/sysinfo.h" +#include "tcmalloc/malloc_extension.h" #include "tcmalloc/static_vars.h" +#include "tcmalloc/testing/testutil.h" namespace tcmalloc { namespace tcmalloc_internal { @@ -49,20 +44,28 @@ static constexpr size_t kMaxGpaPages = GuardedPageAllocator::kGpaMaxPages; // Size of pages used by GuardedPageAllocator. static size_t PageSize() { static const size_t page_size = - std::max(kPageSize, static_cast(getpagesize())); + std::max(kPageSize, static_cast(GetPageSize())); return page_size; } +inline auto GetStackTrace() { +self: + StackTrace s; + s.stack[0] = reinterpret_cast(&&self); + s.depth = 1; + return s; +} + class GuardedPageAllocatorTest : public testing::Test { protected: GuardedPageAllocatorTest() { - absl::base_internal::SpinLockHolder h(&pageheap_lock); + PageHeapSpinLockHolder l; gpa_.Init(kMaxGpaPages, kMaxGpaPages); gpa_.AllowAllocations(); } explicit GuardedPageAllocatorTest(size_t num_pages) { - absl::base_internal::SpinLockHolder h(&pageheap_lock); + PageHeapSpinLockHolder l; gpa_.Init(num_pages, kMaxGpaPages); gpa_.AllowAllocations(); } @@ -80,7 +83,10 @@ class GuardedPageAllocatorParamTest }; TEST_F(GuardedPageAllocatorTest, SingleAllocDealloc) { - char *buf = reinterpret_cast(gpa_.Allocate(PageSize(), 0)); + auto alloc_with_status = gpa_.Allocate(PageSize(), 0, GetStackTrace()); + EXPECT_EQ(alloc_with_status.status, Profile::Sample::GuardedStatus::Guarded); + EXPECT_EQ(gpa_.successful_allocations(), 1); + char* buf = static_cast(alloc_with_status.alloc); EXPECT_NE(buf, nullptr); EXPECT_TRUE(gpa_.PointerIsMine(buf)); memset(buf, 'A', PageSize()); @@ -93,58 +99,78 @@ TEST_F(GuardedPageAllocatorTest, SingleAllocDealloc) { } TEST_F(GuardedPageAllocatorTest, NoAlignmentProvided) { - constexpr size_t kLargeObjectAlignment = std::max( - kAlignment, static_cast(__STDCPP_DEFAULT_NEW_ALIGNMENT__)); + constexpr size_t kLargeObjectAlignment = + std::max(static_cast(kAlignment), + static_cast(__STDCPP_DEFAULT_NEW_ALIGNMENT__)); + int allocation_count = 0; for (size_t base_size = 1; base_size <= 64; base_size <<= 1) { for (size_t size : {base_size, base_size + 1}) { SCOPED_TRACE(size); constexpr int kElements = 10; - std::array ptrs; + std::array ptrs; // Make several allocation attempts to encounter left/right-alignment in // the guarded region. for (int i = 0; i < kElements; i++) { - ptrs[i] = gpa_.Allocate(size, 0); + auto alloc_with_status = gpa_.Allocate(size, 0, GetStackTrace()); + EXPECT_EQ(alloc_with_status.status, + Profile::Sample::GuardedStatus::Guarded); + ptrs[i] = alloc_with_status.alloc; EXPECT_NE(ptrs[i], nullptr); EXPECT_TRUE(gpa_.PointerIsMine(ptrs[i])); + ++allocation_count; size_t observed_alignment = 1 << absl::countr_zero(absl::bit_cast(ptrs[i])); EXPECT_GE(observed_alignment, std::min(size, kLargeObjectAlignment)); } - for (void *ptr : ptrs) { + for (void* ptr : ptrs) { gpa_.Deallocate(ptr); } } } + EXPECT_EQ(gpa_.successful_allocations(), allocation_count); } TEST_F(GuardedPageAllocatorTest, AllocDeallocAligned) { for (size_t align = 1; align <= PageSize(); align <<= 1) { constexpr size_t alloc_size = 1; - void *p = gpa_.Allocate(alloc_size, align); - EXPECT_NE(p, nullptr); - EXPECT_TRUE(gpa_.PointerIsMine(p)); - EXPECT_EQ(reinterpret_cast(p) % align, 0); + auto alloc_with_status = gpa_.Allocate(alloc_size, align, GetStackTrace()); + EXPECT_EQ(alloc_with_status.status, + Profile::Sample::GuardedStatus::Guarded); + EXPECT_NE(alloc_with_status.alloc, nullptr); + EXPECT_TRUE(gpa_.PointerIsMine(alloc_with_status.alloc)); + EXPECT_EQ(reinterpret_cast(alloc_with_status.alloc) % align, 0); } + EXPECT_EQ(gpa_.successful_allocations(), (32 - __builtin_clz(PageSize()))); } TEST_P(GuardedPageAllocatorParamTest, AllocDeallocAllPages) { size_t num_pages = GetParam(); - char *bufs[kMaxGpaPages]; + char* bufs[kMaxGpaPages]; for (size_t i = 0; i < num_pages; i++) { - bufs[i] = reinterpret_cast(gpa_.Allocate(1, 0)); + auto alloc_with_status = gpa_.Allocate(1, 0, GetStackTrace()); + EXPECT_EQ(alloc_with_status.status, + Profile::Sample::GuardedStatus::Guarded); + bufs[i] = reinterpret_cast(alloc_with_status.alloc); EXPECT_NE(bufs[i], nullptr); EXPECT_TRUE(gpa_.PointerIsMine(bufs[i])); } - EXPECT_EQ(gpa_.Allocate(1, 0), nullptr); + EXPECT_EQ(gpa_.successful_allocations(), num_pages); + auto alloc_with_status = gpa_.Allocate(1, 0, GetStackTrace()); + EXPECT_EQ(alloc_with_status.status, + Profile::Sample::GuardedStatus::NoAvailableSlots); + EXPECT_EQ(alloc_with_status.alloc, nullptr); gpa_.Deallocate(bufs[0]); - bufs[0] = reinterpret_cast(gpa_.Allocate(1, 0)); + alloc_with_status = gpa_.Allocate(1, 0, GetStackTrace()); + EXPECT_EQ(alloc_with_status.status, Profile::Sample::GuardedStatus::Guarded); + bufs[0] = reinterpret_cast(alloc_with_status.alloc); EXPECT_NE(bufs[0], nullptr); EXPECT_TRUE(gpa_.PointerIsMine(bufs[0])); + EXPECT_EQ(gpa_.successful_allocations(), num_pages + 1); for (size_t i = 0; i < num_pages; i++) { bufs[i][0] = 'A'; gpa_.Deallocate(bufs[i]); @@ -154,9 +180,12 @@ INSTANTIATE_TEST_SUITE_P(VaryNumPages, GuardedPageAllocatorParamTest, testing::Values(1, kMaxGpaPages / 2, kMaxGpaPages)); TEST_F(GuardedPageAllocatorTest, PointerIsMine) { - void *buf = gpa_.Allocate(1, 0); + auto alloc_with_status = gpa_.Allocate(1, 0, GetStackTrace()); + EXPECT_EQ(alloc_with_status.status, Profile::Sample::GuardedStatus::Guarded); + EXPECT_EQ(gpa_.successful_allocations(), 1); + void* buf = alloc_with_status.alloc; int stack_var; - auto malloc_ptr = absl::make_unique(); + auto malloc_ptr = std::make_unique(); EXPECT_TRUE(gpa_.PointerIsMine(buf)); EXPECT_FALSE(gpa_.PointerIsMine(&stack_var)); EXPECT_FALSE(gpa_.PointerIsMine(malloc_ptr.get())); @@ -165,7 +194,7 @@ TEST_F(GuardedPageAllocatorTest, PointerIsMine) { TEST_F(GuardedPageAllocatorTest, Print) { char buf[1024] = {}; Printer out(buf, sizeof(buf)); - gpa_.Print(&out); + gpa_.Print(out); EXPECT_THAT(buf, testing::ContainsRegex("GWP-ASan Status")); } @@ -173,23 +202,23 @@ TEST_F(GuardedPageAllocatorTest, Print) { // extra pages are allocated when there's concurrent calls to Allocate(). TEST_F(GuardedPageAllocatorTest, ThreadedAllocCount) { constexpr size_t kNumThreads = 2; - void *allocations[kNumThreads][kMaxGpaPages]; + void* allocations[kNumThreads][kMaxGpaPages]; { std::vector threads; threads.reserve(kNumThreads); for (size_t i = 0; i < kNumThreads; i++) { threads.push_back(std::thread([this, &allocations, i]() { for (size_t j = 0; j < kMaxGpaPages; j++) { - allocations[i][j] = gpa_.Allocate(1, 0); + allocations[i][j] = gpa_.Allocate(1, 0, GetStackTrace()).alloc; } })); } - for (auto &t : threads) { + for (auto& t : threads) { t.join(); } } - absl::flat_hash_set allocations_set; + absl::flat_hash_set allocations_set; for (size_t i = 0; i < kNumThreads; i++) { for (size_t j = 0; j < kMaxGpaPages; j++) { allocations_set.insert(allocations[i][j]); @@ -197,20 +226,27 @@ TEST_F(GuardedPageAllocatorTest, ThreadedAllocCount) { } allocations_set.erase(nullptr); EXPECT_EQ(allocations_set.size(), kMaxGpaPages); + EXPECT_EQ(gpa_.successful_allocations(), kMaxGpaPages); } // Test that allocator remains in consistent state under high contention and // doesn't double-allocate pages or fail to deallocate pages. TEST_F(GuardedPageAllocatorTest, ThreadedHighContention) { - const size_t kNumThreads = 4 * absl::base_internal::NumCPUs(); + const size_t kNumThreads = 4 * NumCPUs(); { std::vector threads; threads.reserve(kNumThreads); for (size_t i = 0; i < kNumThreads; i++) { threads.push_back(std::thread([this]() { - char *buf; - while ((buf = reinterpret_cast(gpa_.Allocate(1, 0))) == - nullptr) { + char* buf; + while (true) { + auto alloc_with_status = gpa_.Allocate(1, 0, GetStackTrace()); + if (alloc_with_status.status == + Profile::Sample::GuardedStatus::Guarded) { + buf = reinterpret_cast(alloc_with_status.alloc); + EXPECT_NE(buf, nullptr); + break; + } absl::SleepFor(absl::Nanoseconds(5000)); } @@ -228,16 +264,119 @@ TEST_F(GuardedPageAllocatorTest, ThreadedHighContention) { })); } - for (auto &t : threads) { + for (auto& t : threads) { t.join(); } } // Verify all pages have been deallocated now that all threads are done. for (size_t i = 0; i < kMaxGpaPages; i++) { - EXPECT_NE(gpa_.Allocate(1, 0), nullptr); + auto alloc_with_status = gpa_.Allocate(1, 0, GetStackTrace()); + EXPECT_EQ(alloc_with_status.status, + Profile::Sample::GuardedStatus::Guarded); + EXPECT_NE(alloc_with_status.alloc, nullptr); + } +} + +class SampledAllocationWithFilterTest + : public GuardedPageAllocatorTest, + public testing::WithParamInterface> { + protected: + void SetUp() override { +#ifndef __cpp_sized_deallocation + GTEST_SKIP() << "requires sized delete support"; +#endif + // Sanitizers override malloc/free with their own. +#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ + defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER) + GTEST_SKIP() << "skipping tests on sanitizers"; +#endif } +}; + +TEST_P(SampledAllocationWithFilterTest, MismatchedSizeDelete) { + constexpr int kIter = 1000000; + const auto& filter = GetParam(); + + for (int i = 0; i < kIter; ++i) { + auto deleter = [](void* ptr) { ::operator delete(ptr); }; + std::unique_ptr ptr(::operator new(1000), deleter); + if (!filter(ptr.get())) continue; + ASSERT_TRUE(!IsNormalMemory(ptr.get())); + + EXPECT_DEATH(sized_delete(ptr.get(), 2000), + "Mismatched-size-delete.*mismatched-sized-delete.md.*of 2000 " + "bytes \\(expected 1000 bytes\\) at"); + + return; + } + + GTEST_SKIP() << "can't get a sampled allocation, giving up"; } +TEST_P(SampledAllocationWithFilterTest, MismatchedSizeDeleteZero) { + constexpr int kIter = 1000000; + const auto& filter = GetParam(); + + for (int i = 0; i < kIter; ++i) { + auto deleter = [](void* ptr) { ::operator delete(ptr); }; + std::unique_ptr ptr(::operator new(1000), deleter); + if (!filter(ptr.get())) continue; + ASSERT_TRUE(!IsNormalMemory(ptr.get())); + + EXPECT_DEATH(sized_delete(ptr.get(), 0), + "Mismatched-size-delete.*mismatched-sized-delete.md.*of 0 " + "bytes \\(expected 1000 bytes\\) at"); + + return; + } + + GTEST_SKIP() << "can't get a sampled allocation, giving up"; +} + +TEST_P(SampledAllocationWithFilterTest, SizedNewMismatchedSizeDelete) { + constexpr int kIter = 1000000; + const auto& filter = GetParam(); + + for (int i = 0; i < kIter; ++i) { + auto sized_ptr = tcmalloc_size_returning_operator_new(1000); + auto deleter = [](void* ptr) { ::operator delete(ptr); }; + std::unique_ptr ptr(sized_ptr.p, deleter); + if (!filter(ptr.get())) continue; + ASSERT_TRUE(!IsNormalMemory(ptr.get())); + + if (tc_globals.guardedpage_allocator().PointerIsMine(ptr.get())) + EXPECT_DEATH( // Guarded page allocation will return exactly as requested + sized_delete(ptr.get(), 2000), + "Mismatched-size-delete.*mismatched-sized-delete.md.*of 2000 bytes " + "\\(expected 1000 bytes\\) at"); + else + EXPECT_DEATH(sized_delete(ptr.get(), 2000), + "Mismatched-size-delete.*mismatched-sized-delete.md.*of " + "2000 bytes \\(expected 1000 - " + "1024 bytes\\) at"); + + return; + } + + GTEST_SKIP() << "can't get a sampled allocation, giving up"; +} + +INSTANTIATE_TEST_SUITE_P( + VaryingSampleCases, SampledAllocationWithFilterTest, + testing::Values( + [](void* ptr) { + // Sampled page-guarded memory + return tc_globals.guardedpage_allocator().PointerIsMine(ptr); + }, + [](void* ptr) { + // Sampled memory only + return !IsNormalMemory(ptr) && + !tc_globals.guardedpage_allocator().PointerIsMine(ptr); + })); + +ABSL_CONST_INIT ABSL_ATTRIBUTE_UNUSED GuardedPageAllocator + gpa_is_constant_initializable; + } // namespace } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/heap_profiling_test.cc b/contrib/libs/tcmalloc/tcmalloc/heap_profiling_test.cc deleted file mode 100644 index 5c2473ffedca..000000000000 --- a/contrib/libs/tcmalloc/tcmalloc/heap_profiling_test.cc +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2019 The TCMalloc Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include -#include - -#include -#include - -#include "gtest/gtest.h" -#include "benchmark/benchmark.h" -#include "tcmalloc/internal/logging.h" -#include "tcmalloc/internal/parameter_accessors.h" -#include "tcmalloc/malloc_extension.h" -#include "tcmalloc/static_vars.h" - -namespace tcmalloc { -namespace { - -int64_t ProfileSize(ProfileType type) { - int64_t total = 0; - - MallocExtension::SnapshotCurrent(type).Iterate( - [&](const Profile::Sample &e) { total += e.sum; }); - return total; -} - -class ScopedPeakGrowthFraction { - public: - explicit ScopedPeakGrowthFraction(double temporary_value) - : previous_(TCMalloc_Internal_GetPeakSamplingHeapGrowthFraction()) { - TCMalloc_Internal_SetPeakSamplingHeapGrowthFraction(temporary_value); - } - - ~ScopedPeakGrowthFraction() { - TCMalloc_Internal_SetPeakSamplingHeapGrowthFraction(previous_); - } - - private: - double previous_; -}; - -TEST(HeapProfilingTest, PeakHeapTracking) { - // Adjust high watermark threshold for our scenario, to be independent of - // changes to the default. As we use a random value for choosing our next - // sampling point, we may overweight some allocations above their true size. - ScopedPeakGrowthFraction s(1.25); - - int64_t start_peak_sz = ProfileSize(ProfileType::kPeakHeap); - - // make a large allocation to force a new peak heap sample - // (total live: 50MiB) - void *first = ::operator new(50 << 20); - // TODO(b/183453911): Remove workaround for GCC 10.x deleting operator new, - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94295. - benchmark::DoNotOptimize(first); - int64_t peak_after_first = ProfileSize(ProfileType::kPeakHeap); - EXPECT_NEAR(peak_after_first, start_peak_sz + (50 << 20), 10 << 20); - - // a small allocation shouldn't increase the peak - // (total live: 54MiB) - void *second = ::operator new(4 << 20); - benchmark::DoNotOptimize(second); - int64_t peak_after_second = ProfileSize(ProfileType::kPeakHeap); - EXPECT_EQ(peak_after_second, peak_after_first); - - // but a large one should - // (total live: 254MiB) - void *third = ::operator new(200 << 20); - benchmark::DoNotOptimize(third); - int64_t peak_after_third = ProfileSize(ProfileType::kPeakHeap); - EXPECT_NEAR(peak_after_third, peak_after_second + (200 << 20), 10 << 20); - - // freeing everything shouldn't affect the peak - // (total live: 0MiB) - ::operator delete(first); - EXPECT_EQ(ProfileSize(ProfileType::kPeakHeap), peak_after_third); - - ::operator delete(second); - EXPECT_EQ(ProfileSize(ProfileType::kPeakHeap), peak_after_third); - - ::operator delete(third); - EXPECT_EQ(ProfileSize(ProfileType::kPeakHeap), peak_after_third); - - // going back up less than previous peak shouldn't affect the peak - // (total live: 200MiB) - void *fourth = ::operator new(100 << 20); - benchmark::DoNotOptimize(fourth); - void *fifth = ::operator new(100 << 20); - benchmark::DoNotOptimize(fifth); - EXPECT_EQ(ProfileSize(ProfileType::kPeakHeap), peak_after_third); - - // passing the old peak significantly, even with many small allocations, - // should generate a new one - // (total live: 200MiB + 256MiB = 456MiB, 80% over the 254MiB peak) - void *bitsy[1 << 10]; - for (int i = 0; i < 1 << 10; i++) { - bitsy[i] = ::operator new(1 << 18); - benchmark::DoNotOptimize(bitsy[i]); - } - EXPECT_GT(ProfileSize(ProfileType::kPeakHeap), peak_after_third); - - ::operator delete(fourth); - ::operator delete(fifth); - for (int i = 0; i < 1 << 10; i++) { - ::operator delete(bitsy[i]); - } -} - -} // namespace -} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/hinted_tracker_lists.h b/contrib/libs/tcmalloc/tcmalloc/hinted_tracker_lists.h new file mode 100644 index 000000000000..9df21ec83712 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/hinted_tracker_lists.h @@ -0,0 +1,131 @@ +#pragma clang system_header +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_HINTED_TRACKER_LISTS_H_ +#define TCMALLOC_HINTED_TRACKER_LISTS_H_ + +#include + +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/linked_list.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/range_tracker.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +// This class wraps an array of N TrackerLists and a Bitmap storing which +// elements are non-empty. +template +class HintedTrackerLists { + public: + using TrackerList = TList; + + constexpr HintedTrackerLists() : size_{} {} + + // Removes a TrackerType from the first non-empty freelist with index at + // least n and returns it. Returns nullptr if there is none. + TrackerType* GetLeast(const size_t n) { + TC_ASSERT_LT(n, N); + size_t i = nonempty_.FindSet(n); + if (i == N) { + return nullptr; + } + TC_ASSERT(!lists_[i].empty()); + TrackerType* pt = lists_[i].first(); + if (lists_[i].remove(pt)) { + nonempty_.ClearBit(i); + } + --size_; + return pt; + } + + // Returns a pointer to the TrackerType from the first non-empty freelist with + // index at least n and returns it. Returns nullptr if there is none. + // + // Unlike GetLeast, this does not remove the pointer from the list when it is + // found. + TrackerType* PeekLeast(const size_t n) { + TC_ASSERT_LT(n, N); + size_t i = nonempty_.FindSet(n); + if (i == N) { + return nullptr; + } + TC_ASSERT(!lists_[i].empty()); + return lists_[i].first(); + } + + // Adds pointer to the nonempty_[i] list. + // REQUIRES: i < N && pt != nullptr. + void Add(TrackerType* pt, const size_t i) { + TC_ASSERT_LT(i, N); + TC_ASSERT_NE(pt, nullptr); + lists_[i].prepend(pt); + ++size_; + nonempty_.SetBit(i); + } + + // Removes pointer from the nonempty_[i] list. + // REQUIRES: i < N && pt != nullptr. + void Remove(TrackerType* pt, const size_t i) { + TC_ASSERT_LT(i, N); + TC_ASSERT_NE(pt, nullptr); + if (lists_[i].remove(pt)) { + nonempty_.ClearBit(i); + } + --size_; + } + const TrackerList& operator[](const size_t n) const { + TC_ASSERT_LT(n, N); + return lists_[n]; + } + size_t size() const { return size_; } + bool empty() const { return size_ == 0; } + + // Returns length of the list at an index . + // REQUIRES: n < N. + size_t SizeOfList(const size_t n) const { + TC_ASSERT_LT(n, N); + return lists_[n].length(); + } + // Runs a functor on all pointers in the TrackerLists. + // This method is const but the Functor gets passed a non-const pointer. + // This quirk is inherited from TrackerList. + template + void Iter(const Functor& func, size_t start) const { + size_t i = nonempty_.FindSet(start); + while (i < N) { + auto& list = lists_[i]; + TC_ASSERT(!list.empty()); + for (TrackerType* pt : list) { + func(*pt); + } + i++; + if (i < N) i = nonempty_.FindSet(i); + } + } + + private: + TrackerList lists_[N]; + size_t size_; + Bitmap nonempty_; +}; + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_HINTED_TRACKER_LISTS_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_address_map.cc b/contrib/libs/tcmalloc/tcmalloc/huge_address_map.cc index 898c6d934a83..a979e2f9387c 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_address_map.cc +++ b/contrib/libs/tcmalloc/tcmalloc/huge_address_map.cc @@ -14,27 +14,29 @@ #include "tcmalloc/huge_address_map.h" -#include - #include -#include +#include +#include #include "absl/base/internal/cycleclock.h" +#include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/exponential_biased.h" #include "tcmalloc/internal/logging.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { -const HugeAddressMap::Node *HugeAddressMap::Node::next() const { - const Node *n = right_; +const HugeAddressMap::Node* HugeAddressMap::Node::next() const { + const Node* n = right_; if (n) { while (n->left_) n = n->left_; return n; } n = parent_; - const Node *last = this; + const Node* last = this; while (n) { if (n->left_ == last) return n; last = n; @@ -44,49 +46,49 @@ const HugeAddressMap::Node *HugeAddressMap::Node::next() const { return nullptr; } -HugeAddressMap::Node *HugeAddressMap::Node::next() { - const Node *n = static_cast(this)->next(); - return const_cast(n); +HugeAddressMap::Node* HugeAddressMap::Node::next() { + const Node* n = static_cast(this)->next(); + return const_cast(n); } -void HugeAddressMap::Node::Check(size_t *num_nodes, HugeLength *size) const { +void HugeAddressMap::Node::Check(size_t* num_nodes, HugeLength* size) const { HugeLength longest = range_.len(); *num_nodes += 1; *size += range_.len(); if (left_) { // tree - CHECK_CONDITION(left_->range_.start() < range_.start()); + TC_CHECK_LT(left_->range_.start(), range_.start()); // disjoint - CHECK_CONDITION(left_->range_.end_addr() < range_.start_addr()); + TC_CHECK_LT(left_->range_.end_addr(), range_.start_addr()); // well-formed - CHECK_CONDITION(left_->parent_ == this); + TC_CHECK_EQ(left_->parent_, this); // heap - CHECK_CONDITION(left_->prio_ <= prio_); + TC_CHECK_LE(left_->prio_, prio_); left_->Check(num_nodes, size); if (left_->longest_ > longest) longest = left_->longest_; } if (right_) { // tree - CHECK_CONDITION(right_->range_.start() > range_.start()); + TC_CHECK_GT(right_->range_.start(), range_.start()); // disjoint - CHECK_CONDITION(right_->range_.start_addr() > range_.end_addr()); + TC_CHECK_GT(right_->range_.start_addr(), range_.end_addr()); // well-formed - CHECK_CONDITION(right_->parent_ == this); + TC_CHECK_EQ(right_->parent_, this); // heap - CHECK_CONDITION(right_->prio_ <= prio_); + TC_CHECK_LE(right_->prio_, prio_); right_->Check(num_nodes, size); if (right_->longest_ > longest) longest = right_->longest_; } - CHECK_CONDITION(longest_ == longest); + TC_CHECK_EQ(longest_, longest); } -const HugeAddressMap::Node *HugeAddressMap::first() const { - const Node *n = root(); +const HugeAddressMap::Node* HugeAddressMap::first() const { + const Node* n = root(); if (!n) return nullptr; - const Node *left = n->left_; + const Node* left = n->left_; while (left) { n = left; left = n->left_; @@ -95,44 +97,44 @@ const HugeAddressMap::Node *HugeAddressMap::first() const { return n; } -HugeAddressMap::Node *HugeAddressMap::first() { - const Node *f = static_cast(this)->first(); - return const_cast(f); +HugeAddressMap::Node* HugeAddressMap::first() { + const Node* f = static_cast(this)->first(); + return const_cast(f); } void HugeAddressMap::Check() { size_t nodes = 0; HugeLength size = NHugePages(0); if (root_) { - CHECK_CONDITION(root_->parent_ == nullptr); + TC_CHECK_EQ(root_->parent_, nullptr); root_->Check(&nodes, &size); } - CHECK_CONDITION(nodes == nranges()); - CHECK_CONDITION(size == total_mapped()); - CHECK_CONDITION(total_nodes_ == used_nodes_ + freelist_size_); + TC_CHECK_EQ(nodes, nranges()); + TC_CHECK_EQ(size, total_mapped()); + TC_CHECK_EQ(total_nodes_, used_nodes_ + freelist_size_); } size_t HugeAddressMap::nranges() const { return used_nodes_; } HugeLength HugeAddressMap::total_mapped() const { return total_size_; } -void HugeAddressMap::Print(Printer *out) const { - out->printf("HugeAddressMap: treap %zu / %zu nodes used / created\n", - used_nodes_, total_nodes_); +void HugeAddressMap::Print(Printer& out) const { + out.printf("HugeAddressMap: treap %zu / %zu nodes used / created\n", + used_nodes_, total_nodes_); const size_t longest = root_ ? root_->longest_.raw_num() : 0; - out->printf("HugeAddressMap: %zu contiguous hugepages available\n", longest); + out.printf("HugeAddressMap: %zu contiguous hugepages available\n", longest); } -void HugeAddressMap::PrintInPbtxt(PbtxtRegion *hpaa) const { - hpaa->PrintI64("num_huge_address_map_treap_nodes_used", used_nodes_); - hpaa->PrintI64("num_huge_address_map_treap_nodes_created", total_nodes_); +void HugeAddressMap::PrintInPbtxt(PbtxtRegion& hpaa) const { + hpaa.PrintI64("num_huge_address_map_treap_nodes_used", used_nodes_); + hpaa.PrintI64("num_huge_address_map_treap_nodes_created", total_nodes_); const size_t longest = root_ ? root_->longest_.in_bytes() : 0; - hpaa->PrintI64("contiguous_free_bytes", longest); + hpaa.PrintI64("contiguous_free_bytes", longest); } -HugeAddressMap::Node *HugeAddressMap::Predecessor(HugePage p) { - Node *n = root(); - Node *best = nullptr; +HugeAddressMap::Node* HugeAddressMap::Predecessor(HugePage p) { + Node* n = root(); + Node* best = nullptr; while (n) { HugeRange here = n->range_; if (here.contains(p)) return n; @@ -151,7 +153,7 @@ HugeAddressMap::Node *HugeAddressMap::Predecessor(HugePage p) { return best; } -void HugeAddressMap::Merge(Node *b, HugeRange r, Node *a) { +void HugeAddressMap::Merge(Node* b, HugeRange r, Node* a) { auto merge_when = [](HugeRange x, int64_t x_when, HugeRange y, int64_t y_when) { // avoid overflow with floating-point @@ -195,10 +197,10 @@ void HugeAddressMap::Insert(HugeRange r) { total_size_ += r.len(); // First, try to merge if necessary. Note there are three possibilities: // we might need to merge before with r, r with after, or all three together. - Node *before = Predecessor(r.start()); - CHECK_CONDITION(!before || !before->range_.intersects(r)); - Node *after = before ? before->next() : first(); - CHECK_CONDITION(!after || !after->range_.intersects(r)); + Node* before = Predecessor(r.start()); + TC_CHECK(!before || !before->range_.intersects(r)); + Node* after = before ? before->next() : first(); + TC_CHECK(!after || !after->range_.intersects(r)); if (before && before->range_.precedes(r)) { if (after && r.precedes(after->range_)) { Merge(before, r, after); @@ -210,13 +212,13 @@ void HugeAddressMap::Insert(HugeRange r) { Merge(nullptr, r, after); return; } - CHECK_CONDITION(!before || !before->range_.precedes(r)); - CHECK_CONDITION(!after || !r.precedes(after->range_)); + TC_CHECK(!before || !before->range_.precedes(r)); + TC_CHECK(!after || !r.precedes(after->range_)); // No merging possible; just add a new node. - Node *n = Get(r); - Node *curr = root(); - Node *parent = nullptr; - Node **link = &root_; + Node* n = Get(r); + Node* curr = root(); + Node* parent = nullptr; + Node** link = &root_; // Walk down the tree to our correct location while (curr != nullptr && curr->prio_ >= n->prio_) { curr->longest_ = std::max(curr->longest_, r.len()); @@ -238,10 +240,10 @@ void HugeAddressMap::Insert(HugeRange r) { // We need to split the treap at curr into n's children. // This will be two treaps: one less than p, one greater, and has // a nice recursive structure. - Node **less = &n->left_; - Node *lp = n; - Node **more = &n->right_; - Node *mp = n; + Node** less = &n->left_; + Node* lp = n; + Node** more = &n->right_; + Node* mp = n; while (curr) { if (curr->range_.start() < p) { *less = curr; @@ -272,21 +274,21 @@ void HugeAddressMap::Node::FixLongest() { longest_ = new_longest; } -void HugeAddressMap::FixLongest(HugeAddressMap::Node *n) { +void HugeAddressMap::FixLongest(HugeAddressMap::Node* n) { while (n) { n->FixLongest(); n = n->parent_; } } -void HugeAddressMap::Remove(HugeAddressMap::Node *n) { +void HugeAddressMap::Remove(HugeAddressMap::Node* n) { total_size_ -= n->range_.len(); // We need to merge the left and right children of n into one // treap, then glue it into place wherever n was. - Node **link; - Node *parent = n->parent_; - Node *top = n->left_; - Node *bottom = n->right_; + Node** link; + Node* parent = n->parent_; + Node* top = n->left_; + Node* bottom = n->right_; const HugeLength child_longest = std::max(top ? top->longest_ : NHugePages(0), @@ -308,7 +310,7 @@ void HugeAddressMap::Remove(HugeAddressMap::Node *n) { // A routine op we'll need a lot: given two (possibly null) // children, put the root-ier one into top. - auto reorder_maybe = [](Node **top, Node **bottom) { + auto reorder_maybe = [](Node** top, Node** bottom) { Node *b = *bottom, *t = *top; if (b && (!t || t->prio_ < b->prio_)) { *bottom = t; @@ -343,25 +345,26 @@ void HugeAddressMap::Remove(HugeAddressMap::Node *n) { Put(n); } -void HugeAddressMap::Put(Node *n) { +void HugeAddressMap::Put(Node* n) { freelist_size_++; used_nodes_--; n->left_ = freelist_; freelist_ = n; } -HugeAddressMap::Node *HugeAddressMap::Get(HugeRange r) { - CHECK_CONDITION((freelist_ == nullptr) == (freelist_size_ == 0)); +HugeAddressMap::Node* HugeAddressMap::Get(HugeRange r) { + TC_CHECK_EQ(freelist_ == nullptr, freelist_size_ == 0); used_nodes_++; - int prio = rand_r(&seed_); + seed_ = ExponentialBiased::NextRandom(seed_); + int prio = ExponentialBiased::GetRandom(seed_); if (freelist_size_ == 0) { total_nodes_++; - Node *ret = reinterpret_cast(meta_(sizeof(Node))); + Node* ret = reinterpret_cast(meta_(sizeof(Node))); return new (ret) Node(r, prio); } freelist_size_--; - Node *ret = freelist_; + Node* ret = freelist_; freelist_ = ret->left_; return new (ret) Node(r, prio); } diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_address_map.h b/contrib/libs/tcmalloc/tcmalloc/huge_address_map.h index 3c71f19a3fcc..7e449f63064c 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_address_map.h +++ b/contrib/libs/tcmalloc/tcmalloc/huge_address_map.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,8 +18,11 @@ #include #include +#include "absl/base/attributes.h" #include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/metadata_allocator.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { @@ -31,11 +35,10 @@ namespace tcmalloc_internal { // // This class scales well and is *reasonably* performant, but it is not intended // for use on extremely hot paths. -// TODO(b/134688982): extend to support other range-like types? class HugeAddressMap { public: - typedef void *(*MetadataAllocFunction)(size_t bytes); - explicit constexpr HugeAddressMap(MetadataAllocFunction meta); + explicit constexpr HugeAddressMap( + MetadataAllocator& meta ABSL_ATTRIBUTE_LIFETIME_BOUND); // IMPORTANT: DESTROYING A HUGE ADDRESS MAP DOES NOT MAKE ANY ATTEMPT // AT FREEING ALLOCATED METADATA. @@ -46,11 +49,11 @@ class HugeAddressMap { // the range stored at this point HugeRange range() const; // Tree structure - Node *left(); - Node *right(); + Node* left(); + Node* right(); // Iterate to the next node in address order - const Node *next() const; - Node *next(); + const Node* next() const; + Node* next(); // when were this node's content added (in // absl::base_internal::CycleClock::Now units)? int64_t when() const; @@ -64,28 +67,28 @@ class HugeAddressMap { HugeRange range_; int prio_; // chosen randomly Node *left_, *right_; - Node *parent_; + Node* parent_; HugeLength longest_; int64_t when_; // Expensive, recursive consistency check. // Accumulates node count and range sizes into passed arguments. - void Check(size_t *num_nodes, HugeLength *size) const; + void Check(size_t* num_nodes, HugeLength* size) const; // We've broken longest invariants somehow; fix them here. void FixLongest(); }; // Get root of the tree. - Node *root(); - const Node *root() const; + Node* root(); + const Node* root() const; // Get lowest-addressed node - const Node *first() const; - Node *first(); + const Node* first() const; + Node* first(); // Returns the highest-addressed range that does not lie completely // after p (if any). - Node *Predecessor(HugePage p); + Node* Predecessor(HugePage p); // Expensive consistency check. void Check(); @@ -93,51 +96,51 @@ class HugeAddressMap { // Statistics size_t nranges() const; HugeLength total_mapped() const; - void Print(Printer *out) const; - void PrintInPbtxt(PbtxtRegion *hpaa) const; + void Print(Printer& out) const; + void PrintInPbtxt(PbtxtRegion& hpaa) const; // Add to the map, merging with adjacent ranges as needed. void Insert(HugeRange r); // Delete n from the map. - void Remove(Node *n); + void Remove(Node* n); private: // our tree - Node *root_{nullptr}; + Node* root_{nullptr}; size_t used_nodes_{0}; HugeLength total_size_{NHugePages(0)}; // cache of unused nodes - Node *freelist_{nullptr}; + Node* freelist_{nullptr}; size_t freelist_size_{0}; // How we get more - MetadataAllocFunction meta_; - Node *Get(HugeRange r); - void Put(Node *n); + MetadataAllocator& meta_; + Node* Get(HugeRange r); + void Put(Node* n); size_t total_nodes_{0}; - void Merge(Node *b, HugeRange r, Node *a); - void FixLongest(Node *n); + void Merge(Node* b, HugeRange r, Node* a); + void FixLongest(Node* n); // Note that we always use the same seed, currently; this isn't very random. // In practice we're not worried about adversarial input and this works well // enough. - unsigned int seed_{0}; + uint64_t seed_{0}; }; -inline constexpr HugeAddressMap::HugeAddressMap(MetadataAllocFunction meta) +inline constexpr HugeAddressMap::HugeAddressMap(MetadataAllocator& meta) : meta_(meta) {} inline HugeRange HugeAddressMap::Node::range() const { return range_; } -inline HugeAddressMap::Node *HugeAddressMap::Node::left() { return left_; } -inline HugeAddressMap::Node *HugeAddressMap::Node::right() { return right_; } +inline HugeAddressMap::Node* HugeAddressMap::Node::left() { return left_; } +inline HugeAddressMap::Node* HugeAddressMap::Node::right() { return right_; } inline int64_t HugeAddressMap::Node::when() const { return when_; } inline HugeLength HugeAddressMap::Node::longest() const { return longest_; } -inline HugeAddressMap::Node *HugeAddressMap::root() { return root_; } -inline const HugeAddressMap::Node *HugeAddressMap::root() const { +inline HugeAddressMap::Node* HugeAddressMap::root() { return root_; } +inline const HugeAddressMap::Node* HugeAddressMap::root() const { return root_; } diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_address_map_test.cc b/contrib/libs/tcmalloc/tcmalloc/huge_address_map_test.cc index 455cd6380964..c4ec9f810e51 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_address_map_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/huge_address_map_test.cc @@ -14,12 +14,14 @@ #include "tcmalloc/huge_address_map.h" +#include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "tcmalloc/mock_metadata_allocator.h" namespace tcmalloc { namespace tcmalloc_internal { @@ -27,13 +29,7 @@ namespace { class HugeAddressMapTest : public ::testing::Test { protected: - HugeAddressMapTest() : map_(MallocMetadata) { metadata_allocs_.clear(); } - - ~HugeAddressMapTest() override { - for (void* p : metadata_allocs_) { - free(p); - } - } + HugeAddressMapTest() : map_(malloc_metadata_) {} std::vector Contents() { std::vector ret; @@ -52,17 +48,9 @@ class HugeAddressMapTest : public ::testing::Test { HugeAddressMap map_; private: - static void* MallocMetadata(size_t size) { - void* ptr = malloc(size); - metadata_allocs_.push_back(ptr); - return ptr; - } - - static std::vector metadata_allocs_; + FakeMetadataAllocator malloc_metadata_; }; -std::vector HugeAddressMapTest::metadata_allocs_; - // This test verifies that HugeAddressMap merges properly. TEST_F(HugeAddressMapTest, Merging) { const HugeRange r1 = HugeRange::Make(hp(0), hl(1)); diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_allocator.cc b/contrib/libs/tcmalloc/tcmalloc/huge_allocator.cc index c77f4522ad54..d7d090c281bc 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_allocator.cc +++ b/contrib/libs/tcmalloc/tcmalloc/huge_allocator.cc @@ -17,34 +17,36 @@ #include #include "tcmalloc/huge_address_map.h" +#include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/stats.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { -void HugeAllocator::Print(Printer *out) { - out->printf("HugeAllocator: contiguous, unbacked hugepage(s)\n"); +void HugeAllocator::Print(Printer& out) { + out.printf("HugeAllocator: contiguous, unbacked hugepage(s)\n"); free_.Print(out); - out->printf( - "HugeAllocator: %zu requested - %zu in use = %zu hugepages free\n", - from_system_.raw_num(), in_use_.raw_num(), - (from_system_ - in_use_).raw_num()); + out.printf("HugeAllocator: %zu requested - %zu in use = %zu hugepages free\n", + from_system_.raw_num(), in_use_.raw_num(), + (from_system_ - in_use_).raw_num()); } -void HugeAllocator::PrintInPbtxt(PbtxtRegion *hpaa) const { +void HugeAllocator::PrintInPbtxt(PbtxtRegion& hpaa) const { free_.PrintInPbtxt(hpaa); - hpaa->PrintI64("num_total_requested_huge_pages", from_system_.raw_num()); - hpaa->PrintI64("num_in_use_huge_pages", in_use_.raw_num()); + hpaa.PrintI64("num_total_requested_huge_pages", from_system_.raw_num()); + hpaa.PrintI64("num_in_use_huge_pages", in_use_.raw_num()); } -HugeAddressMap::Node *HugeAllocator::Find(HugeLength n) { - HugeAddressMap::Node *curr = free_.root(); +HugeAddressMap::Node* HugeAllocator::Find(HugeLength n) { + HugeAddressMap::Node* curr = free_.root(); // invariant: curr != nullptr && curr->longest >= n // we favor smaller gaps and lower nodes and lower addresses, in that // order. The net effect is that we are neither a best-fit nor a // lowest-address allocator but vaguely close to both. - HugeAddressMap::Node *best = nullptr; + HugeAddressMap::Node* best = nullptr; while (curr && curr->longest() >= n) { if (curr->range().len() >= n) { if (!best || best->range().len() > curr->range().len()) { @@ -90,34 +92,33 @@ void HugeAllocator::CheckFreelist() { size_t num_nodes = free_.nranges(); HugeLength n = free_.total_mapped(); free_.Check(); - CHECK_CONDITION(n == from_system_ - in_use_); + TC_CHECK_EQ(n, from_system_ - in_use_); LargeSpanStats large; - AddSpanStats(nullptr, &large, nullptr); - CHECK_CONDITION(num_nodes == large.spans); - CHECK_CONDITION(n.in_pages() == large.returned_pages); + AddSpanStats(nullptr, &large); + TC_CHECK_EQ(num_nodes, large.spans); + TC_CHECK_EQ(n.in_pages(), large.returned_pages); } HugeRange HugeAllocator::AllocateRange(HugeLength n) { if (n.overflows()) return HugeRange::Nil(); - size_t actual; size_t bytes = n.in_bytes(); size_t align = kHugePageSize; - void *ptr = allocate_(bytes, &actual, align); + auto [ptr, actual] = allocate_(bytes, align); if (ptr == nullptr) { // OOM... return HugeRange::Nil(); } - CHECK_CONDITION(ptr != nullptr); + TC_CHECK_NE(ptr, nullptr); // It's possible for a request to return extra hugepages. - CHECK_CONDITION(actual % kHugePageSize == 0); + TC_CHECK_EQ(actual % kHugePageSize, 0); n = HLFromBytes(actual); from_system_ += n; return HugeRange::Make(HugePageContaining(ptr), n); } HugeRange HugeAllocator::Get(HugeLength n) { - CHECK_CONDITION(n > NHugePages(0)); - auto *node = Find(n); + TC_CHECK_GT(n, NHugePages(0)); + auto* node = Find(n); if (!node) { // Get more memory, then "delete" it HugeRange r = AllocateRange(n); @@ -125,7 +126,7 @@ HugeRange HugeAllocator::Get(HugeLength n) { in_use_ += r.len(); Release(r); node = Find(n); - CHECK_CONDITION(node != nullptr); + TC_CHECK_NE(node, nullptr); } in_use_ += n; @@ -135,8 +136,8 @@ HugeRange HugeAllocator::Get(HugeLength n) { HugeLength before = r.len(); HugeRange extra = HugeRange::Make(r.start() + n, before - n); r = HugeRange::Make(r.start(), n); - ASSERT(r.precedes(extra)); - ASSERT(r.len() + extra.len() == before); + TC_ASSERT(r.precedes(extra)); + TC_ASSERT_EQ(r.len() + extra.len(), before); in_use_ += extra.len(); Release(extra); } else { @@ -154,19 +155,15 @@ void HugeAllocator::Release(HugeRange r) { DebugCheckFreelist(); } -void HugeAllocator::AddSpanStats(SmallSpanStats *small, LargeSpanStats *large, - PageAgeHistograms *ages) const { - for (const HugeAddressMap::Node *node = free_.first(); node != nullptr; +void HugeAllocator::AddSpanStats(SmallSpanStats* small, + LargeSpanStats* large) const { + for (const HugeAddressMap::Node* node = free_.first(); node != nullptr; node = node->next()) { HugeLength n = node->range().len(); if (large != nullptr) { large->spans++; large->returned_pages += n.in_pages(); } - - if (ages != nullptr) { - ages->RecordRange(n.in_pages(), true, node->when()); - } } } diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_allocator.h b/contrib/libs/tcmalloc/tcmalloc/huge_allocator.h index 6242805c49ac..baa4499d2b8c 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_allocator.h +++ b/contrib/libs/tcmalloc/tcmalloc/huge_allocator.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,27 +20,42 @@ #include -#include "tcmalloc/common.h" +#include "absl/base/attributes.h" #include "tcmalloc/huge_address_map.h" #include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/metadata_allocator.h" #include "tcmalloc/stats.h" +#include "tcmalloc/system-alloc.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { // these typedefs allow replacement of tcmalloc::System* for tests. -typedef void *(*MemoryAllocFunction)(size_t bytes, size_t *actual, - size_t align); -typedef void *(*MetadataAllocFunction)(size_t bytes); +class VirtualAllocator { + public: + VirtualAllocator() = default; + virtual ~VirtualAllocator() = default; + + VirtualAllocator(const VirtualAllocator&) = delete; + VirtualAllocator(VirtualAllocator&&) = delete; + VirtualAllocator& operator=(const VirtualAllocator&) = delete; + VirtualAllocator& operator=(VirtualAllocator&&) = delete; + + // Allocates bytes of virtual address space with align alignment. + [[nodiscard]] virtual AddressRange operator()(size_t bytes, size_t align) = 0; +}; // This tracks available ranges of hugepages and fulfills requests for // usable memory, allocating more from the system as needed. All // hugepages are treated as (and assumed to be) unbacked. class HugeAllocator { public: - constexpr HugeAllocator(MemoryAllocFunction allocate, - MetadataAllocFunction meta_allocate) + constexpr HugeAllocator( + VirtualAllocator& allocate ABSL_ATTRIBUTE_LIFETIME_BOUND, + MetadataAllocator& meta_allocate ABSL_ATTRIBUTE_LIFETIME_BOUND) : free_(meta_allocate), allocate_(allocate) {} // Obtain a range of n unbacked hugepages, distinct from all other @@ -57,8 +73,7 @@ class HugeAllocator { // Unused memory in the allocator. HugeLength size() const { return from_system_ - in_use_; } - void AddSpanStats(SmallSpanStats *small, LargeSpanStats *large, - PageAgeHistograms *ages) const; + void AddSpanStats(SmallSpanStats* small, LargeSpanStats* large) const; BackingStats stats() const { BackingStats s; @@ -68,8 +83,8 @@ class HugeAllocator { return s; } - void Print(Printer *out); - void PrintInPbtxt(PbtxtRegion *hpaa) const; + void Print(Printer& out); + void PrintInPbtxt(PbtxtRegion& hpaa) const; private: // We're constrained in several ways by existing code. Hard requirements: @@ -85,7 +100,7 @@ class HugeAllocator { // don't matter, and most of the simple ideas can't hit all of the above // requirements. HugeAddressMap free_; - HugeAddressMap::Node *Find(HugeLength n); + HugeAddressMap::Node* Find(HugeLength n); void CheckFreelist(); void DebugCheckFreelist() { @@ -97,7 +112,7 @@ class HugeAllocator { HugeLength from_system_{NHugePages(0)}; HugeLength in_use_{NHugePages(0)}; - MemoryAllocFunction allocate_; + VirtualAllocator& allocate_; HugeRange AllocateRange(HugeLength n); }; diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_allocator_test.cc b/contrib/libs/tcmalloc/tcmalloc/huge_allocator_test.cc index 150075b88e32..a26c4b50e85f 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_allocator_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/huge_allocator_test.cc @@ -14,12 +14,12 @@ #include "tcmalloc/huge_allocator.h" +#include #include #include -#include #include -#include +#include #include #include @@ -29,54 +29,34 @@ #include "absl/time/clock.h" #include "absl/time/time.h" #include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/mock_metadata_allocator.h" +#include "tcmalloc/mock_virtual_allocator.h" namespace tcmalloc { namespace tcmalloc_internal { namespace { class HugeAllocatorTest : public testing::TestWithParam { - private: - // Use a tiny fraction of actual size so we can test aggressively. - static void *AllocateFake(size_t bytes, size_t *actual, size_t align); - - static constexpr size_t kMaxBacking = 1024 * 1024; - // This isn't super good form but we'll never have more than one HAT - // extant at once. - static std::vector backing_; - - // We use actual malloc for metadata allocations, but we track them so they - // can be deleted. - static void *MallocMetadata(size_t size); - static std::vector metadata_allocs_; - static size_t metadata_bytes_; - static bool should_overallocate_; - static HugeLength huge_pages_requested_; - static HugeLength huge_pages_received_; - protected: - HugeLength HugePagesRequested() { return huge_pages_requested_; } - HugeLength HugePagesReceived() { return huge_pages_received_; } + HugeLength HugePagesRequested() { + return vm_allocator_.huge_pages_requested_; + } + HugeLength HugePagesReceived() { return vm_allocator_.huge_pages_received_; } HugeAllocatorTest() { - should_overallocate_ = GetParam(); - huge_pages_requested_ = NHugePages(0); - huge_pages_received_ = NHugePages(0); + vm_allocator_.should_overallocate_ = GetParam(); + vm_allocator_.huge_pages_requested_ = NHugePages(0); + vm_allocator_.huge_pages_received_ = NHugePages(0); // We don't use the first few bytes, because things might get weird // given zero pointers. - backing_.resize(1024); - metadata_bytes_ = 0; + vm_allocator_.backing_.resize(1024); } - ~HugeAllocatorTest() override { - for (void *p : metadata_allocs_) { - free(p); - } - metadata_allocs_.clear(); - backing_.clear(); - } + ~HugeAllocatorTest() override { vm_allocator_.backing_.clear(); } - size_t *GetActual(HugePage p) { return &backing_[p.index()]; } + size_t* GetActual(HugePage p) { return &vm_allocator_.backing_[p.index()]; } // We're dealing with a lot of memory, so we don't want to do full memset // and then check every byte for corruption. So set the first and last @@ -100,49 +80,11 @@ class HugeAllocatorTest : public testing::TestWithParam { EXPECT_EQ(used, expected_use); } - HugeAllocator allocator_{AllocateFake, MallocMetadata}; + FakeVirtualAllocator vm_allocator_; + FakeMetadataAllocator metadata_allocator_; + HugeAllocator allocator_{vm_allocator_, metadata_allocator_}; }; -// Use a tiny fraction of actual size so we can test aggressively. -void *HugeAllocatorTest::AllocateFake(size_t bytes, size_t *actual, - size_t align) { - CHECK_CONDITION(bytes % kHugePageSize == 0); - CHECK_CONDITION(align % kHugePageSize == 0); - HugeLength req = HLFromBytes(bytes); - huge_pages_requested_ += req; - // Test the case where our sys allocator provides too much. - if (should_overallocate_) ++req; - huge_pages_received_ += req; - *actual = req.in_bytes(); - // we'll actually provide hidden backing, one word per hugepage. - bytes = req / NHugePages(1); - align /= kHugePageSize; - size_t index = backing_.size(); - if (index % align != 0) { - index += (align - (index & align)); - } - if (index + bytes > kMaxBacking) return nullptr; - backing_.resize(index + bytes); - void *ptr = reinterpret_cast(index * kHugePageSize); - return ptr; -} - -// We use actual malloc for metadata allocations, but we track them so they -// can be deleted. -void *HugeAllocatorTest::MallocMetadata(size_t size) { - metadata_bytes_ += size; - void *ptr = malloc(size); - metadata_allocs_.push_back(ptr); - return ptr; -} - -std::vector HugeAllocatorTest::backing_; -std::vector HugeAllocatorTest::metadata_allocs_; -size_t HugeAllocatorTest::metadata_bytes_; -bool HugeAllocatorTest::should_overallocate_; -HugeLength HugeAllocatorTest::huge_pages_requested_; -HugeLength HugeAllocatorTest::huge_pages_received_; - TEST_P(HugeAllocatorTest, Basic) { std::vector> allocs; absl::BitGen rng; @@ -340,12 +282,11 @@ TEST_P(HugeAllocatorTest, Frugal) { TEST_P(HugeAllocatorTest, Stats) { struct Helper { - static void Stats(const HugeAllocator *huge, size_t *num_spans, - Length *pages, absl::Duration *avg_age) { + static void Stats(const HugeAllocator* huge, size_t* num_spans, + Length* pages) { SmallSpanStats small; LargeSpanStats large; - PageAgeHistograms ages(absl::base_internal::CycleClock::Now()); - huge->AddSpanStats(&small, &large, &ages); + huge->AddSpanStats(&small, &large); for (auto i = Length(0); i < kMaxPages; ++i) { EXPECT_EQ(0, small.normal_length[i.raw_num()]); EXPECT_EQ(0, small.returned_length[i.raw_num()]); @@ -353,8 +294,6 @@ TEST_P(HugeAllocatorTest, Stats) { *num_spans = large.spans; EXPECT_EQ(Length(0), large.normal_pages); *pages = large.returned_pages; - const PageAgeHistograms::Histogram *hist = ages.GetTotalHistogram(true); - *avg_age = absl::Seconds(hist->avg_age()); } }; @@ -375,58 +314,31 @@ TEST_P(HugeAllocatorTest, Stats) { size_t num_spans; Length pages; - absl::Duration avg_age; - Helper::Stats(&allocator_, &num_spans, &pages, &avg_age); + Helper::Stats(&allocator_, &num_spans, &pages); EXPECT_EQ(0, num_spans); EXPECT_EQ(Length(0), pages); - EXPECT_EQ(absl::ZeroDuration(), avg_age); allocator_.Release(r1); - constexpr absl::Duration kDelay = absl::Milliseconds(500); - absl::SleepFor(kDelay); - Helper::Stats(&allocator_, &num_spans, &pages, &avg_age); + Helper::Stats(&allocator_, &num_spans, &pages); EXPECT_EQ(1, num_spans); EXPECT_EQ(NHugePages(1).in_pages(), pages); - // We can only do >= testing, because we might be arbitrarily delayed. - // Since avg_age is computed in floating point, we may have round-off from - // TCMalloc's internal use of absl::base_internal::CycleClock down through - // computing the average age of the spans. kEpsilon allows for a tiny amount - // of slop. - constexpr absl::Duration kEpsilon = absl::Microseconds(200); - EXPECT_LE(kDelay - kEpsilon, avg_age); allocator_.Release(r2); - absl::SleepFor(absl::Milliseconds(250)); - Helper::Stats(&allocator_, &num_spans, &pages, &avg_age); + Helper::Stats(&allocator_, &num_spans, &pages); EXPECT_EQ(2, num_spans); EXPECT_EQ(NHugePages(3).in_pages(), pages); - EXPECT_LE( - (absl::Seconds(0.75) * 1 + absl::Seconds(0.25) * 2) / (1 + 2) - kEpsilon, - avg_age); allocator_.Release(r3); - absl::SleepFor(absl::Milliseconds(125)); - Helper::Stats(&allocator_, &num_spans, &pages, &avg_age); + Helper::Stats(&allocator_, &num_spans, &pages); EXPECT_EQ(3, num_spans); EXPECT_EQ(NHugePages(6).in_pages(), pages); - EXPECT_LE((absl::Seconds(0.875) * 1 + absl::Seconds(0.375) * 2 + - absl::Seconds(0.125) * 3) / - (1 + 2 + 3) - - kEpsilon, - avg_age); allocator_.Release(b1); allocator_.Release(b2); - absl::SleepFor(absl::Milliseconds(100)); - Helper::Stats(&allocator_, &num_spans, &pages, &avg_age); + Helper::Stats(&allocator_, &num_spans, &pages); EXPECT_EQ(1, num_spans); EXPECT_EQ(NHugePages(8).in_pages(), pages); - EXPECT_LE((absl::Seconds(0.975) * 1 + absl::Seconds(0.475) * 2 + - absl::Seconds(0.225) * 3 + absl::Seconds(0.1) * 2) / - (1 + 2 + 3 + 2) - - kEpsilon, - avg_age); } // Make sure we're well-behaved in the presence of OOM (and that we do @@ -440,7 +352,7 @@ TEST_P(HugeAllocatorTest, OOM) { INSTANTIATE_TEST_SUITE_P( NormalOverAlloc, HugeAllocatorTest, testing::Values(false, true), - +[](const testing::TestParamInfo &info) { + +[](const testing::TestParamInfo& info) { return info.param ? "overallocates" : "normal"; }); diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_cache.cc b/contrib/libs/tcmalloc/tcmalloc/huge_cache.cc index 0d25da2983fc..5f1d9d56c519 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_cache.cc +++ b/contrib/libs/tcmalloc/tcmalloc/huge_cache.cc @@ -14,13 +14,20 @@ #include "tcmalloc/huge_cache.h" +#include +#include +#include +#include #include +#include "absl/base/optimization.h" #include "absl/time/time.h" -#include "tcmalloc/common.h" #include "tcmalloc/huge_address_map.h" +#include "tcmalloc/huge_page_subrelease.h" #include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/pages.h" #include "tcmalloc/stats.h" GOOGLE_MALLOC_SECTION_BEGIN @@ -36,9 +43,9 @@ template HugeLength MinMaxTracker::MaxOverTime(absl::Duration t) const { HugeLength m = NHugePages(0); size_t num_epochs = ceil(absl::FDivDuration(t, kEpochLength)); - timeseries_.IterBackwards([&](size_t offset, int64_t ts, - const Extrema &e) { m = std::max(m, e.max); }, - num_epochs); + timeseries_.IterBackwards( + [&](size_t offset, const Extrema& e) { m = std::max(m, e.max); }, + num_epochs); return m; } @@ -46,39 +53,40 @@ template HugeLength MinMaxTracker::MinOverTime(absl::Duration t) const { HugeLength m = kMaxVal; size_t num_epochs = ceil(absl::FDivDuration(t, kEpochLength)); - timeseries_.IterBackwards([&](size_t offset, int64_t ts, - const Extrema &e) { m = std::min(m, e.min); }, - num_epochs); + timeseries_.IterBackwards( + [&](size_t offset, const Extrema& e) { m = std::min(m, e.min); }, + num_epochs); return m; } template -void MinMaxTracker::Print(Printer *out) const { +void MinMaxTracker::Print(Printer& out) const { // Prints timestamp:min_pages:max_pages for each window with records. // Timestamp == kEpochs - 1 is the most recent measurement. const int64_t millis = absl::ToInt64Milliseconds(kEpochLength); - out->printf("\nHugeCache: window %lldms * %zu", millis, kEpochs); + out.printf("\nHugeCache: window %lldms * %zu", millis, kEpochs); int written = 0; timeseries_.Iter( - [&](size_t offset, int64_t ts, const Extrema &e) { - if ((written++) % 100 == 0) - out->printf("\nHugeCache: Usage timeseries "); - out->printf("%zu:%zu:%zd,", offset, e.min.raw_num(), e.max.raw_num()); + [&](size_t offset, const Extrema& e) { + if ((written++) % 100 == 0) { + out.printf("\nHugeCache: Usage timeseries "); + } + out.printf("%zu:%zu:%zd,", offset, e.min.raw_num(), e.max.raw_num()); }, timeseries_.kSkipEmptyEntries); - out->printf("\n"); + out.printf("\n"); } template -void MinMaxTracker::PrintInPbtxt(PbtxtRegion *hpaa) const { +void MinMaxTracker::PrintInPbtxt(PbtxtRegion& hpaa) const { // Prints content of each non-empty epoch, from oldest to most recent data - auto huge_cache_history = hpaa->CreateSubRegion("huge_cache_history"); + auto huge_cache_history = hpaa.CreateSubRegion("huge_cache_history"); huge_cache_history.PrintI64("window_ms", absl::ToInt64Milliseconds(kEpochLength)); huge_cache_history.PrintI64("epochs", kEpochs); timeseries_.Iter( - [&](size_t offset, int64_t ts, const Extrema &e) { + [&](size_t offset, const Extrema& e) { auto m = huge_cache_history.CreateSubRegion("measurements"); m.PrintI64("epoch", offset); m.PrintI64("min_bytes", e.min.in_bytes()); @@ -88,7 +96,7 @@ void MinMaxTracker::PrintInPbtxt(PbtxtRegion *hpaa) const { } template -bool MinMaxTracker::Extrema::operator==(const Extrema &other) const { +bool MinMaxTracker::Extrema::operator==(const Extrema& other) const { return (other.max == max) && (other.min == min); } @@ -98,8 +106,8 @@ template class MinMaxTracker<600>; // The logic for actually allocating from the cache or backing, and keeping // the hit rates specified. -HugeRange HugeCache::DoGet(HugeLength n, bool *from_released) { - auto *node = Find(n); +HugeRange HugeCache::DoGet(HugeLength n, bool* from_released) { + auto* node = Find(n); if (!node) { misses_++; weighted_misses_ += n.raw_num(); @@ -131,19 +139,19 @@ void HugeCache::MaybeGrowCacheLimit(HugeLength missed) { // A "dip" being a case where usage shrinks, then increases back up // to previous levels (at least partially). // - // "brief" is "returns to normal usage in < kCacheTime." (In + // "brief" is "returns to normal usage in < cache_time_." (In // other words, we ideally want to be willing to cache memory for - // kCacheTime before expecting it to be used again--we are loose + // cache_time_ before expecting it to be used again--we are loose // on the timing..) // // The interesting part is finding those dips. // This is the downward slope: we lost some usage. (This in theory could - // be as much as 2 * kCacheTime old, which is fine.) - const HugeLength shrink = off_peak_tracker_.MaxOverTime(kCacheTime); + // be as much as 2 * cache_time_ old, which is fine.) + const HugeLength shrink = off_peak_tracker_.MaxOverTime(cache_time_); // This is the upward slope: we are coming back up. - const HugeLength grow = usage_ - usage_tracker_.MinOverTime(kCacheTime); + const HugeLength grow = usage_ - usage_tracker_.MinOverTime(cache_time_); // Ideally we now know that we dipped down by some amount, then came // up. Sadly our stats aren't quite good enough to guarantee things @@ -176,35 +184,26 @@ void HugeCache::IncUsage(HugeLength n) { usage_tracker_.Report(usage_); detailed_tracker_.Report(usage_); off_peak_tracker_.Report(NHugePages(0)); - if (size() + usage() > max_rss_) max_rss_ = size() + usage(); } void HugeCache::DecUsage(HugeLength n) { usage_ -= n; usage_tracker_.Report(usage_); detailed_tracker_.Report(usage_); - const HugeLength max = usage_tracker_.MaxOverTime(kCacheTime); - ASSERT(max >= usage_); + const HugeLength max = usage_tracker_.MaxOverTime(cache_time_); + TC_ASSERT_GE(max, usage_); const HugeLength off_peak = max - usage_; off_peak_tracker_.Report(off_peak); - if (size() + usage() > max_rss_) max_rss_ = size() + usage(); } -void HugeCache::UpdateSize(HugeLength size) { - size_tracker_.Report(size); - if (size > max_size_) max_size_ = size; - if (size + usage() > max_rss_) max_rss_ = size + usage(); - - // TODO(b/134691947): moving this inside the MinMaxTracker would save one call - // to clock_.now() but all MinMaxTrackers would track regret instead. - int64_t now = clock_.now(); - if (now > last_regret_update_) { - regret_ += size.raw_num() * (now - last_regret_update_); - last_regret_update_ = now; - } +void HugeCache::UpdateSize(HugeLength size) { size_tracker_.Report(size); } + +void HugeCache::UpdateStatsTracker() { + cachestats_tracker_.Report(GetSubreleaseStats()); + hugepage_release_stats_.reset(); } -HugeRange HugeCache::Get(HugeLength n, bool *from_released) { +HugeRange HugeCache::Get(HugeLength n, bool* from_released) { HugeRange r = DoGet(n, from_released); // failure to get a range should "never" "never" happen (VSS limits // or wildly incorrect allocation sizes only...) Don't deal with @@ -213,10 +212,11 @@ HugeRange HugeCache::Get(HugeLength n, bool *from_released) { const bool miss = r.valid() && *from_released; if (miss) MaybeGrowCacheLimit(n); + UpdateStatsTracker(); return r; } -void HugeCache::Release(HugeRange r) { +void HugeCache::Release(HugeRange r, bool demand_based_unback) { DecUsage(r.len()); cache_.Insert(r); @@ -226,28 +226,31 @@ void HugeCache::Release(HugeRange r) { } else { overflows_++; } - - // Shrink the limit, if we're going to do it, before we shrink to - // the max size. (This could reduce the number of regions we break - // in half to avoid overshrinking.) - if ((clock_.now() - last_limit_change_) > (cache_time_ticks_ * 2)) { - total_fast_unbacked_ += MaybeShrinkCacheLimit(); + // Performs a (quick) unback if the demand-based release is disabled. + if (!demand_based_unback) { + // Shrink the limit, if we're going to do it, before we shrink to + // the max size. (This could reduce the number of regions we break + // in half to avoid overshrinking.) + if ((clock_.now() - last_limit_change_) > (cache_time_ticks_ * 2)) { + total_fast_unbacked_ += MaybeShrinkCacheLimit(); + } + total_fast_unbacked_ += ShrinkCache(limit()); } - total_fast_unbacked_ += ShrinkCache(limit()); - UpdateSize(size()); + UpdateStatsTracker(); } void HugeCache::ReleaseUnbacked(HugeRange r) { DecUsage(r.len()); // No point in trying to cache it, just hand it back. allocator_->Release(r); + UpdateStatsTracker(); } HugeLength HugeCache::MaybeShrinkCacheLimit() { last_limit_change_ = clock_.now(); - const HugeLength min = size_tracker_.MinOverTime(kCacheTime * 2); + const HugeLength min = size_tracker_.MinOverTime(cache_time_ * 2); // If cache size has gotten down to at most 20% of max, we assume // we're close enough to the optimal size--we don't want to fiddle // too much/too often unless we have large gaps in usage. @@ -264,8 +267,8 @@ HugeLength HugeCache::ShrinkCache(HugeLength target) { HugeLength removed = NHugePages(0); while (size_ > target) { // Remove smallest-ish nodes, to avoid fragmentation where possible. - auto *node = Find(NHugePages(1)); - CHECK_CONDITION(node); + auto* node = Find(NHugePages(1)); + TC_CHECK_NE(node, nullptr); HugeRange r = node->range(); cache_.Remove(node); // Suppose we're 10 MiB over target but the smallest available node @@ -277,7 +280,7 @@ HugeLength HugeCache::ShrinkCache(HugeLength target) { if (r.len() > delta) { HugeRange to_remove, leftover; std::tie(to_remove, leftover) = Split(r, delta); - ASSERT(leftover.valid()); + TC_ASSERT(leftover.valid()); cache_.Insert(leftover); r = to_remove; } @@ -285,7 +288,13 @@ HugeLength HugeCache::ShrinkCache(HugeLength target) { size_ -= r.len(); // Note, actual unback implementation is temporarily dropping and // re-acquiring the page heap lock here. - unback_(r.start_addr(), r.byte_len()); + if (ABSL_PREDICT_FALSE(!unback_(r))) { + // We failed to release r. Retain it in the cache instead of returning it + // to the HugeAllocator. + size_ += r.len(); + cache_.Insert(r); + break; + } allocator_->Release(r); removed += r.len(); } @@ -302,36 +311,104 @@ HugeLength HugeCache::ReleaseCachedPages(HugeLength n) { const HugeLength target = n > size() ? NHugePages(0) : size() - n; released += ShrinkCache(target); } + UpdateSize(size()); + UpdateStatsTracker(); + total_periodic_unbacked_ += released; + return released; +} +HugeLength HugeCache::GetDesiredReleaseablePages( + HugeLength desired, SkipSubreleaseIntervals intervals) { + TC_CHECK(intervals.SkipSubreleaseEnabled()); + UpdateStatsTracker(); + HugeLength required_by_demand; + required_by_demand = HLFromPages(cachestats_tracker_.GetRecentDemand( + intervals.short_interval, intervals.long_interval, CapDemandInterval())); + + HugeLength current = usage() + size(); + if (required_by_demand != NHugePages(0)) { + HugeLength new_desired; + // We can only release if the current capacity is larger than the demand. + if (required_by_demand < current) { + new_desired = current - required_by_demand; + } + if (new_desired >= desired) { + return desired; + } + // Reports the amount of free hugepages that we didn't release due to this + // mechanism. As the initial release target is capped by the cache size, + // here we simply report the reduced amount. Note, only free pages in the + // smaller of the two (current and required_by_demand) are skipped, so we + // use that as the reporting peak. + HugeLength skipped = desired - new_desired; + cachestats_tracker_.ReportSkippedSubreleasePages( + skipped.in_pages(), + std::min(current.in_pages(), required_by_demand.in_pages())); + return new_desired; + } + return desired; +} + +HugeLength HugeCache::ReleaseCachedPagesByDemand( + HugeLength n, SkipSubreleaseIntervals intervals, bool hit_limit) { + // We get here when one of the three happened: A) hit limit, B) background + // release, or C) ReleaseMemoryToSystem(). + HugeLength release_target = std::min(n, size()); + + // For all those three reasons, we want to release as much as possible to be + // efficient. However, we do not want to release a large number of hugepages + // at once because that may impact applications' performance. So we release a + // fraction of the cache. + if (size() > MinCacheLimit()) { + HugeLength increased_release_target = + std::min(HugeLength(kFractionToReleaseFromCache * size().raw_num()), + size() - MinCacheLimit()); + release_target = std::max(release_target, increased_release_target); + } + + if (release_target == NHugePages(0)) { + return NHugePages(0); + } + if (intervals.SkipSubreleaseEnabled() && !hit_limit) { + // This will reduce the target if the calculated (future) demand is higher + // than the current. In other words, we need to reserve some of the free + // hugepages to meet the future demand. It also makes sure we release the + // realized fragmentation. + release_target = GetDesiredReleaseablePages(release_target, intervals); + } + HugeLength released = ShrinkCache(size() - release_target); + hugepage_release_stats_.num_pages_subreleased += released.in_pages(); + hugepage_release_stats_.set_limit_hit(hit_limit); + if (hugepage_release_stats_.limit_hit()) { + hugepage_release_stats_.total_pages_subreleased_due_to_limit += + released.in_pages(); + } UpdateSize(size()); + UpdateStatsTracker(); total_periodic_unbacked_ += released; return released; } -void HugeCache::AddSpanStats(SmallSpanStats *small, LargeSpanStats *large, - PageAgeHistograms *ages) const { +void HugeCache::AddSpanStats(SmallSpanStats* small, + LargeSpanStats* large) const { static_assert(kPagesPerHugePage >= kMaxPages); - for (const HugeAddressMap::Node *node = cache_.first(); node != nullptr; + for (const HugeAddressMap::Node* node = cache_.first(); node != nullptr; node = node->next()) { HugeLength n = node->range().len(); if (large != nullptr) { large->spans++; large->normal_pages += n.in_pages(); } - - if (ages != nullptr) { - ages->RecordRange(n.in_pages(), false, node->when()); - } } } -HugeAddressMap::Node *HugeCache::Find(HugeLength n) { - HugeAddressMap::Node *curr = cache_.root(); +HugeAddressMap::Node* HugeCache::Find(HugeLength n) { + HugeAddressMap::Node* curr = cache_.root(); // invariant: curr != nullptr && curr->longest >= n // we favor smaller gaps and lower nodes and lower addresses, in that // order. The net effect is that we are neither a best-fit nor a // lowest-address allocator but vaguely close to both. - HugeAddressMap::Node *best = nullptr; + HugeAddressMap::Node* best = nullptr; while (curr && curr->longest() >= n) { if (curr->range().len() >= n) { if (!best || best->range().len() > curr->range().len()) { @@ -372,11 +449,11 @@ HugeAddressMap::Node *HugeCache::Find(HugeLength n) { return best; } -void HugeCache::Print(Printer *out) { - const int64_t millis = absl::ToInt64Milliseconds(kCacheTime); - out->printf( +void HugeCache::Print(Printer& out) { + const int64_t millis = absl::ToInt64Milliseconds(cache_time_); + out.printf( "HugeCache: contains unused, backed hugepage(s) " - "(kCacheTime = %lldms)\n", + "(cache_time = %lldms)\n", millis); // a / (a + b), avoiding division by zero auto safe_ratio = [](double a, double b) { @@ -388,45 +465,53 @@ void HugeCache::Print(Printer *out) { const double hit_rate = safe_ratio(hits_, misses_); const double overflow_rate = safe_ratio(overflows_, fills_); - out->printf( + out.printf( "HugeCache: %zu / %zu hugepages cached / cache limit " "(%.3f hit rate, %.3f overflow rate)\n", size_.raw_num(), limit().raw_num(), hit_rate, overflow_rate); - out->printf("HugeCache: %zu MiB fast unbacked, %zu MiB periodic\n", - total_fast_unbacked_.in_bytes() / 1024 / 1024, - total_periodic_unbacked_.in_bytes() / 1024 / 1024); + out.printf("HugeCache: %zu MiB fast unbacked, %zu MiB periodic\n", + total_fast_unbacked_.in_bytes() / 1024 / 1024, + total_periodic_unbacked_.in_bytes() / 1024 / 1024); UpdateSize(size()); - out->printf( - "HugeCache: %zu MiB*s cached since startup\n", - NHugePages(regret_).in_mib() / static_cast(clock_.freq())); usage_tracker_.Report(usage_); - const HugeLength usage_min = usage_tracker_.MinOverTime(kCacheTime); - const HugeLength usage_max = usage_tracker_.MaxOverTime(kCacheTime); - out->printf( + const HugeLength usage_min = usage_tracker_.MinOverTime(cache_time_); + const HugeLength usage_max = usage_tracker_.MaxOverTime(cache_time_); + out.printf( "HugeCache: recent usage range: %zu min - %zu curr - %zu max MiB\n", usage_min.in_mib(), usage_.in_mib(), usage_max.in_mib()); const HugeLength off_peak = usage_max - usage_; off_peak_tracker_.Report(off_peak); - const HugeLength off_peak_min = off_peak_tracker_.MinOverTime(kCacheTime); - const HugeLength off_peak_max = off_peak_tracker_.MaxOverTime(kCacheTime); - out->printf( + const HugeLength off_peak_min = off_peak_tracker_.MinOverTime(cache_time_); + const HugeLength off_peak_max = off_peak_tracker_.MaxOverTime(cache_time_); + out.printf( "HugeCache: recent offpeak range: %zu min - %zu curr - %zu max MiB\n", off_peak_min.in_mib(), off_peak.in_mib(), off_peak_max.in_mib()); - const HugeLength cache_min = size_tracker_.MinOverTime(kCacheTime); - const HugeLength cache_max = size_tracker_.MaxOverTime(kCacheTime); - out->printf( + const HugeLength cache_min = size_tracker_.MinOverTime(cache_time_); + const HugeLength cache_max = size_tracker_.MaxOverTime(cache_time_); + out.printf( "HugeCache: recent cache range: %zu min - %zu curr - %zu max MiB\n", cache_min.in_mib(), size_.in_mib(), cache_max.in_mib()); detailed_tracker_.Print(out); + + // Release stats tracked by the demand-based release mechanism. + out.printf("\n"); + out.printf( + "HugeCache: Since startup, %zu hugepages released, " + "(%zu hugepages due to reaching tcmalloc limit)\n", + HLFromPages(hugepage_release_stats_.total_pages_subreleased).raw_num(), + HLFromPages(hugepage_release_stats_.total_pages_subreleased_due_to_limit) + .raw_num()); + + cachestats_tracker_.Print(out, "HugeCache"); } -void HugeCache::PrintInPbtxt(PbtxtRegion *hpaa) { - hpaa->PrintI64("huge_cache_time_const", - absl::ToInt64Milliseconds(kCacheTime)); +void HugeCache::PrintInPbtxt(PbtxtRegion& hpaa) { + hpaa.PrintI64("huge_cache_time_const", + absl::ToInt64Milliseconds(cache_time_)); // a / (a + b), avoiding division by zero auto safe_ratio = [](double a, double b) { @@ -439,28 +524,24 @@ void HugeCache::PrintInPbtxt(PbtxtRegion *hpaa) { const double overflow_rate = safe_ratio(overflows_, fills_); // number of bytes in HugeCache - hpaa->PrintI64("cached_huge_page_bytes", size_.in_bytes()); + hpaa.PrintI64("cached_huge_page_bytes", size_.in_bytes()); // max allowed bytes in HugeCache - hpaa->PrintI64("max_cached_huge_page_bytes", limit().in_bytes()); + hpaa.PrintI64("max_cached_huge_page_bytes", limit().in_bytes()); // lifetime cache hit rate - hpaa->PrintDouble("huge_cache_hit_rate", hit_rate); + hpaa.PrintDouble("huge_cache_hit_rate", hit_rate); // lifetime cache overflow rate - hpaa->PrintDouble("huge_cache_overflow_rate", overflow_rate); + hpaa.PrintDouble("huge_cache_overflow_rate", overflow_rate); // bytes eagerly unbacked by HugeCache - hpaa->PrintI64("fast_unbacked_bytes", total_fast_unbacked_.in_bytes()); + hpaa.PrintI64("fast_unbacked_bytes", total_fast_unbacked_.in_bytes()); // bytes unbacked by periodic releaser thread - hpaa->PrintI64("periodic_unbacked_bytes", - total_periodic_unbacked_.in_bytes()); + hpaa.PrintI64("periodic_unbacked_bytes", total_periodic_unbacked_.in_bytes()); UpdateSize(size()); - // memory cached since startup (in MiB*s) - hpaa->PrintI64("huge_cache_regret", NHugePages(regret_).in_mib() / - static_cast(clock_.freq())); usage_tracker_.Report(usage_); - const HugeLength usage_min = usage_tracker_.MinOverTime(kCacheTime); - const HugeLength usage_max = usage_tracker_.MaxOverTime(kCacheTime); + const HugeLength usage_min = usage_tracker_.MinOverTime(cache_time_); + const HugeLength usage_max = usage_tracker_.MaxOverTime(cache_time_); { - auto usage_stats = hpaa->CreateSubRegion("huge_cache_usage_stats"); + auto usage_stats = hpaa.CreateSubRegion("huge_cache_usage_stats"); usage_stats.PrintI64("min_bytes", usage_min.in_bytes()); usage_stats.PrintI64("current_bytes", usage_.in_bytes()); usage_stats.PrintI64("max_bytes", usage_max.in_bytes()); @@ -468,25 +549,35 @@ void HugeCache::PrintInPbtxt(PbtxtRegion *hpaa) { const HugeLength off_peak = usage_max - usage_; off_peak_tracker_.Report(off_peak); - const HugeLength off_peak_min = off_peak_tracker_.MinOverTime(kCacheTime); - const HugeLength off_peak_max = off_peak_tracker_.MaxOverTime(kCacheTime); + const HugeLength off_peak_min = off_peak_tracker_.MinOverTime(cache_time_); + const HugeLength off_peak_max = off_peak_tracker_.MaxOverTime(cache_time_); { - auto usage_stats = hpaa->CreateSubRegion("huge_cache_offpeak_stats"); + auto usage_stats = hpaa.CreateSubRegion("huge_cache_offpeak_stats"); usage_stats.PrintI64("min_bytes", off_peak_min.in_bytes()); usage_stats.PrintI64("current_bytes", off_peak.in_bytes()); usage_stats.PrintI64("max_bytes", off_peak_max.in_bytes()); } - const HugeLength cache_min = size_tracker_.MinOverTime(kCacheTime); - const HugeLength cache_max = size_tracker_.MaxOverTime(kCacheTime); + const HugeLength cache_min = size_tracker_.MinOverTime(cache_time_); + const HugeLength cache_max = size_tracker_.MaxOverTime(cache_time_); { - auto usage_stats = hpaa->CreateSubRegion("huge_cache_cache_stats"); + auto usage_stats = hpaa.CreateSubRegion("huge_cache_cache_stats"); usage_stats.PrintI64("min_bytes", cache_min.in_bytes()); usage_stats.PrintI64("current_bytes", size_.in_bytes()); usage_stats.PrintI64("max_bytes", cache_max.in_bytes()); } - + hpaa.PrintI64( + "cache_num_hugepages_released", + HLFromPages(hugepage_release_stats_.total_pages_subreleased).raw_num()); + hpaa.PrintI64( + "cache_num_hugepages_released_due_to_limit", + HLFromPages(hugepage_release_stats_.total_pages_subreleased_due_to_limit) + .raw_num()); detailed_tracker_.PrintInPbtxt(hpaa); + cachestats_tracker_.PrintTimeseriesStatsInPbtxt(hpaa, + "cache_stats_timeseries"); + cachestats_tracker_.PrintSubreleaseStatsInPbtxt(hpaa, + "cache_skipped_subrelease"); } } // namespace tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_cache.h b/contrib/libs/tcmalloc/tcmalloc/huge_cache.h index 2ffda26cb227..e795d9df12ed 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_cache.h +++ b/contrib/libs/tcmalloc/tcmalloc/huge_cache.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,22 +23,33 @@ #include #include +#include "absl/base/attributes.h" +#include "absl/base/internal/cycleclock.h" #include "absl/time/time.h" -#include "tcmalloc/common.h" -#include "tcmalloc/experiment.h" -#include "tcmalloc/experiment_config.h" +#include "tcmalloc/huge_address_map.h" #include "tcmalloc/huge_allocator.h" +#include "tcmalloc/huge_page_subrelease.h" #include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/clock.h" #include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" #include "tcmalloc/internal/timeseries_tracker.h" +#include "tcmalloc/metadata_allocator.h" #include "tcmalloc/stats.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { -typedef void (*MemoryModifyFunction)(void *start, size_t len); +class MemoryModifyFunction { + public: + virtual ~MemoryModifyFunction() = default; + + [[nodiscard]] virtual bool operator()(Range r) = 0; + [[nodiscard]] bool operator()(HugeRange r) { + return (*this)(Range{r.start().first_page(), r.len().in_pages()}); + } +}; // Track the extreme values of a HugeLength value over the past // kWindow (time ranges approximate.) @@ -48,8 +60,8 @@ class MinMaxTracker { : kEpochLength(w / kEpochs), timeseries_(clock, w) {} void Report(HugeLength val); - void Print(Printer *out) const; - void PrintInPbtxt(PbtxtRegion *hpaa) const; + void Print(Printer& out) const; + void PrintInPbtxt(PbtxtRegion& hpaa) const; // If t < kEpochLength, these functions return statistics for last epoch. The // granularity is kEpochLength (rounded up). @@ -78,7 +90,7 @@ class MinMaxTracker { bool empty() const { return (*this == Nil()); } - bool operator==(const Extrema &other) const; + bool operator==(const Extrema& other) const; }; TimeSeriesTracker timeseries_; @@ -88,60 +100,100 @@ class MinMaxTracker { extern template class MinMaxTracker<>; extern template class MinMaxTracker<600>; -template -constexpr HugeLength MinMaxTracker::kMaxVal; - class HugeCache { public: // For use in production - HugeCache(HugeAllocator *allocator, MetadataAllocFunction meta_allocate, - MemoryModifyFunction unback) - : HugeCache(allocator, meta_allocate, unback, + HugeCache(HugeAllocator* allocator, + MetadataAllocator& meta_allocate ABSL_ATTRIBUTE_LIFETIME_BOUND, + MemoryModifyFunction& unback ABSL_ATTRIBUTE_LIFETIME_BOUND, + absl::Duration cache_time) + : HugeCache(allocator, meta_allocate, unback, cache_time, Clock{.now = absl::base_internal::CycleClock::Now, .freq = absl::base_internal::CycleClock::Frequency}) {} - // For testing with mock clock - HugeCache(HugeAllocator *allocator, MetadataAllocFunction meta_allocate, - MemoryModifyFunction unback, Clock clock) + // For testing with mock clock. + // + // cache_time * 2 (default cache_time = 1s) looks like an arbitrary window; it + // mostly is. + // + // Suffice to say that the below code (see MaybeGrowCacheLimit) + // tries to make sure the cache is sized to protect a working set + // that ebbs for 1 second, as a reasonable heuristic. This means it + // needs 1s of historical data to examine. + // + // Why 2s duration, then? Two reasons: + // + // - (minor) granularity of epoch boundaries make me want to err towards + // keeping a bit too much data over a bit too little. + // + // - (major) hysteresis: in ReleaseCachedPages we try to detect + // mistaken cache expansion and reverse it. I hope that using a + // longer timescale than our expansion will increase stability + // here: I will take some caches staying a bit too big over caches + // oscillating back and forth between two size estimates, so we + // require stronger evidence (longer time) to reverse an expansion + // than to make it. + // + // We also tried other algorithms, but this one is simple and suffices to + // capture the empirical dynamics we've seen. See "Beyond Malloc + // Efficiency..." (https://research.google/pubs/pub50370/) for more + // information. + HugeCache(HugeAllocator* allocator, + MetadataAllocator& meta_allocate ABSL_ATTRIBUTE_LIFETIME_BOUND, + MemoryModifyFunction& unback ABSL_ATTRIBUTE_LIFETIME_BOUND, + absl::Duration cache_time, Clock clock) : allocator_(allocator), cache_(meta_allocate), clock_(clock), - cache_time_ticks_(clock_.freq() * absl::ToDoubleSeconds(kCacheTime)), + cache_time_ticks_(clock_.freq() * absl::ToDoubleSeconds(cache_time)), nanoseconds_per_tick_(absl::ToInt64Nanoseconds(absl::Seconds(1)) / clock_.freq()), last_limit_change_(clock.now()), - last_regret_update_(clock.now()), detailed_tracker_(clock, absl::Minutes(10)), - usage_tracker_(clock, kCacheTime * 2), - off_peak_tracker_(clock, kCacheTime * 2), - size_tracker_(clock, kCacheTime * 2), - unback_(unback) {} + usage_tracker_(clock, cache_time * 2), + off_peak_tracker_(clock, cache_time * 2), + size_tracker_(clock, cache_time * 2), + unback_(unback), + cache_time_(cache_time), + cachestats_tracker_(clock, absl::Minutes(10), absl::Minutes(5)) {} // Allocate a usable set of contiguous hugepages. Try to give out // memory that's currently backed from the kernel if we have it available. // *from_released is set to false if the return range is already backed; // otherwise, it is set to true (and the caller should back it.) - HugeRange Get(HugeLength n, bool *from_released); + HugeRange Get(HugeLength n, bool* from_released); // Deallocate (assumed to be backed by the kernel.) - void Release(HugeRange r); + // If demand_based_unback is set, HugeCache will not try to shrink the cache + // here but unback in ReleaseCachedPagesByDemand() instead. The flag is + // designed to separate the normal (quick) unbacking from the demand-based + // unbacking. + void Release(HugeRange r, bool demand_based_unback); + // As Release, but the range is assumed to _not_ be backed. void ReleaseUnbacked(HugeRange r); // Release to the system up to hugepages of cache contents; returns - // the number of hugepages released. + // the number of hugepages released. It also triggers cache shrinking if + // the cache becomes too big. HugeLength ReleaseCachedPages(HugeLength n); + // Release to the system up to hugepages of cache contents if recent + // demand allows; returns the number of hugepages released. The demand history + // is captured using the provided intervals, and the feature is disabled if + // either hit_limit is true or the intervals are not set. It also triggers + // cache shrinking if it has more than what demand needs. + HugeLength ReleaseCachedPagesByDemand(HugeLength n, + SkipSubreleaseIntervals intervals, + bool hit_limit); + // Backed memory available. HugeLength size() const { return size_; } - // Total memory cached (in HugeLength * nanoseconds) - uint64_t regret() const { return regret_ * nanoseconds_per_tick_; } // Current limit for how much backed memory we'll cache. HugeLength limit() const { return limit_; } // Sum total of unreleased requests. HugeLength usage() const { return usage_; } - void AddSpanStats(SmallSpanStats *small, LargeSpanStats *large, - PageAgeHistograms *ages) const; + void AddSpanStats(SmallSpanStats* small, LargeSpanStats* large) const; BackingStats stats() const { BackingStats s; @@ -151,11 +203,11 @@ class HugeCache { return s; } - void Print(Printer *out); - void PrintInPbtxt(PbtxtRegion *hpaa); + void Print(Printer& out); + void PrintInPbtxt(PbtxtRegion& hpaa); private: - HugeAllocator *allocator_; + HugeAllocator* allocator_; // We just cache-missed a request for pages; // should we grow? @@ -168,15 +220,20 @@ class HugeCache { // returning the number removed. HugeLength ShrinkCache(HugeLength target); - HugeRange DoGet(HugeLength n, bool *from_released); + // Calculates the desired releasing target according to the recent demand + // history, returns the updated (reduced) target if releasing the desired + // amount will cause possible future misses. + HugeLength GetDesiredReleaseablePages(HugeLength desired, + SkipSubreleaseIntervals intervals); - HugeAddressMap::Node *Find(HugeLength n); + HugeRange DoGet(HugeLength n, bool* from_released); + + HugeAddressMap::Node* Find(HugeLength n); HugeAddressMap cache_; HugeLength size_{NHugePages(0)}; HugeLength limit_{NHugePages(10)}; - const absl::Duration kCacheTime = absl::Seconds(1); size_t hits_{0}; size_t misses_{0}; @@ -203,8 +260,6 @@ class HugeCache { // However, we can go below it if we haven't used that much for 30 seconds. HugeLength MinCacheLimit() const { return NHugePages(10); } - uint64_t regret_{0}; // overflows if we cache 585 hugepages for 1 year - int64_t last_regret_update_; void UpdateSize(HugeLength size); MinMaxTracker<600> detailed_tracker_; @@ -212,13 +267,37 @@ class HugeCache { MinMaxTracker<> usage_tracker_; MinMaxTracker<> off_peak_tracker_; MinMaxTracker<> size_tracker_; - HugeLength max_size_{NHugePages(0)}; - HugeLength max_rss_{NHugePages(0)}; HugeLength total_fast_unbacked_{NHugePages(0)}; HugeLength total_periodic_unbacked_{NHugePages(0)}; - MemoryModifyFunction unback_; + MemoryModifyFunction& unback_; + absl::Duration cache_time_; + + // Interval used for capping demand calculated for demand-based release: + // making sure that it is not more than the maximum demand recorded in that + // period. When the cap applies, we also release the minimum amount of free + // hugepages that we have been consistently holding at anytime for 5 minutes + // (realized fragmentation). + absl::Duration CapDemandInterval() const { return absl::Minutes(5); } + + // The fraction of the cache that we are happy to return at a time. We use + // this to efficiently reduce the fragmenation. + static constexpr double kFractionToReleaseFromCache = 0.2; + + using StatsTrackerType = SubreleaseStatsTracker<600>; + StatsTrackerType::SubreleaseStats GetSubreleaseStats() const { + StatsTrackerType::SubreleaseStats stats; + stats.num_pages = usage().in_pages(); + stats.free_pages = size().in_pages(); + stats.huge_pages[StatsTrackerType::kRegular] = usage() + size(); + stats.num_pages_subreleased = hugepage_release_stats_.num_pages_subreleased; + return stats; + } + // Tracks recent demand history and demand-based release stats. + void UpdateStatsTracker(); + StatsTrackerType cachestats_tracker_; + SubreleaseStats hugepage_release_stats_; }; } // namespace tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_cache_test.cc b/contrib/libs/tcmalloc/tcmalloc/huge_cache_test.cc index 2699b44303f3..b07451f3e8c5 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_cache_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/huge_cache_test.cc @@ -14,142 +14,99 @@ #include "tcmalloc/huge_cache.h" +#include +#include #include -#include +#include +#include #include #include +#include #include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/cycleclock.h" #include "absl/memory/memory.h" #include "absl/random/random.h" #include "absl/strings/str_cat.h" -#include "absl/time/clock.h" #include "absl/time/time.h" +#include "tcmalloc/huge_page_subrelease.h" #include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/clock.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/mock_metadata_allocator.h" +#include "tcmalloc/mock_virtual_allocator.h" +#include "tcmalloc/pages.h" #include "tcmalloc/stats.h" namespace tcmalloc { namespace tcmalloc_internal { namespace { -class HugeCacheTest : public testing::Test { +using testing::Return; + +class HugeCacheTest + : public testing::TestWithParam> { private: // Allow tests to modify the clock used by the cache. - static int64_t clock_offset_; - static double GetClockFrequency() { - return absl::base_internal::CycleClock::Frequency(); - } - static int64_t GetClock() { - return absl::base_internal::CycleClock::Now() + - clock_offset_ * GetClockFrequency() / - absl::ToDoubleNanoseconds(absl::Seconds(1)); + static int64_t clock_; + + static int64_t FakeClock() { return clock_; } + + static double GetFakeClockFrequency() { + return absl::ToDoubleNanoseconds(absl::Seconds(2)); } - // Use a tiny fraction of actual size so we can test aggressively. - static void* AllocateFake(size_t bytes, size_t* actual, size_t align) { - if (bytes % kHugePageSize != 0) { - Crash(kCrash, __FILE__, __LINE__, "not aligned", bytes, kHugePageSize); - } - if (align % kHugePageSize != 0) { - Crash(kCrash, __FILE__, __LINE__, "not aligned", align, kHugePageSize); - } - *actual = bytes; - // we'll actually provide hidden backing, one word per hugepage. - bytes /= kHugePageSize; - align /= kHugePageSize; - size_t index = backing.size(); - if (index % align != 0) { - index += (align - (index & align)); - } - backing.resize(index + bytes); - void* ptr = reinterpret_cast(index * kHugePageSize); - return ptr; - } - // This isn't super good form but we'll never have more than one HAT - // extant at once. - static std::vector backing; - - // We use actual malloc for metadata allocations, but we track them so they - // can be deleted. (TODO make this an arena if we care, which I doubt) - static void* MallocMetadata(size_t size) { - metadata_bytes += size; - void* ptr = calloc(size, 1); - metadata_allocs.push_back(ptr); - return ptr; - } - static std::vector metadata_allocs; - static size_t metadata_bytes; - - // This is wordy, but necessary for mocking: - class BackingInterface { - public: - virtual void Unback(void* p, size_t len) = 0; - virtual ~BackingInterface() {} - }; + static void ResetClock() { clock_ = 1234; } - class MockBackingInterface : public BackingInterface { + class MockBackingInterface : public MemoryModifyFunction { public: - MOCK_METHOD2(Unback, void(void* p, size_t len)); - }; + MOCK_METHOD(bool, Unback, (PageId p, Length len), ()); - static void MockUnback(void* p, size_t len) { mock_->Unback(p, len); } + bool operator()(Range r) override { return Unback(r.p, r.n); } + }; protected: - static std::unique_ptr> mock_; + testing::NiceMock mock_unback_; HugeCacheTest() { // We don't use the first few bytes, because things might get weird // given zero pointers. - backing.resize(1024); - metadata_bytes = 0; - mock_ = absl::make_unique>(); + vm_allocator_.backing_.resize(1024); + ResetClock(); } - ~HugeCacheTest() override { - for (void* p : metadata_allocs) { - free(p); - } - metadata_allocs.clear(); - backing.clear(); - mock_.reset(nullptr); - - clock_offset_ = 0; + static void Advance(absl::Duration d) { + clock_ += absl::ToDoubleSeconds(d) * GetFakeClockFrequency(); } - void Advance(absl::Duration d) { - clock_offset_ += absl::ToInt64Nanoseconds(d); - } + absl::Duration GetCacheTime() { return std::get<0>(GetParam()); } + bool GetDemandBasedRelease() { return std::get<1>(GetParam()); } + void Release(HugeRange r) { cache_.Release(r, GetDemandBasedRelease()); } - HugeAllocator alloc_{AllocateFake, MallocMetadata}; - HugeCache cache_{&alloc_, MallocMetadata, MockUnback, - Clock{.now = GetClock, .freq = GetClockFrequency}}; + FakeVirtualAllocator vm_allocator_; + FakeMetadataAllocator metadata_allocator_; + HugeAllocator alloc_{vm_allocator_, metadata_allocator_}; + HugeCache cache_{&alloc_, metadata_allocator_, mock_unback_, GetCacheTime(), + Clock{.now = FakeClock, .freq = GetFakeClockFrequency}}; }; -std::vector HugeCacheTest::backing; -std::vector HugeCacheTest::metadata_allocs; -size_t HugeCacheTest::metadata_bytes; -std::unique_ptr> - HugeCacheTest::mock_; +int64_t HugeCacheTest::clock_{1234}; -int64_t HugeCacheTest::clock_offset_ = 0; - -TEST_F(HugeCacheTest, Basic) { +TEST_P(HugeCacheTest, Basic) { bool from; for (int i = 0; i < 100 * 1000; ++i) { - cache_.Release(cache_.Get(NHugePages(1), &from)); + Release(cache_.Get(NHugePages(1), &from)); } } -TEST_F(HugeCacheTest, Backing) { +TEST_P(HugeCacheTest, Backing) { bool from; - cache_.Release(cache_.Get(NHugePages(4), &from)); + Release(cache_.Get(NHugePages(4), &from)); EXPECT_TRUE(from); // We should be able to split up a large range... HugeRange r1 = cache_.Get(NHugePages(3), &from); @@ -158,28 +115,28 @@ TEST_F(HugeCacheTest, Backing) { EXPECT_FALSE(from); // and then merge it back. - cache_.Release(r1); - cache_.Release(r2); + Release(r1); + Release(r2); HugeRange r = cache_.Get(NHugePages(4), &from); EXPECT_FALSE(from); - cache_.Release(r); + Release(r); } -TEST_F(HugeCacheTest, Release) { +TEST_P(HugeCacheTest, Release) { bool from; const HugeLength one = NHugePages(1); - cache_.Release(cache_.Get(NHugePages(5), &from)); + Release(cache_.Get(NHugePages(5), &from)); HugeRange r1, r2, r3, r4, r5; r1 = cache_.Get(one, &from); r2 = cache_.Get(one, &from); r3 = cache_.Get(one, &from); r4 = cache_.Get(one, &from); r5 = cache_.Get(one, &from); - cache_.Release(r1); - cache_.Release(r2); - cache_.Release(r3); - cache_.Release(r4); - cache_.Release(r5); + Release(r1); + Release(r2); + Release(r3); + Release(r4); + Release(r5); r1 = cache_.Get(one, &from); ASSERT_EQ(false, from); @@ -191,38 +148,68 @@ TEST_F(HugeCacheTest, Release) { ASSERT_EQ(false, from); r5 = cache_.Get(one, &from); ASSERT_EQ(false, from); - cache_.Release(r1); - cache_.Release(r2); - cache_.Release(r5); + Release(r1); + Release(r2); + Release(r5); ASSERT_EQ(NHugePages(3), cache_.size()); - EXPECT_CALL(*mock_, Unback(r5.start_addr(), kHugePageSize * 1)).Times(1); + EXPECT_CALL(mock_unback_, Unback(r5.start().first_page(), kPagesPerHugePage)) + .WillOnce(Return(true)); EXPECT_EQ(NHugePages(1), cache_.ReleaseCachedPages(NHugePages(1))); - cache_.Release(r3); - cache_.Release(r4); + Release(r3); + Release(r4); - EXPECT_CALL(*mock_, Unback(r1.start_addr(), 4 * kHugePageSize)).Times(1); + EXPECT_CALL(mock_unback_, + Unback(r1.start().first_page(), 4 * kPagesPerHugePage)) + .WillOnce(Return(true)); EXPECT_EQ(NHugePages(4), cache_.ReleaseCachedPages(NHugePages(200))); } -TEST_F(HugeCacheTest, Regret) { +TEST_P(HugeCacheTest, ReleaseFailure) { bool from; - HugeRange r = cache_.Get(NHugePages(20), &from); - cache_.Release(r); - HugeLength cached = cache_.size(); - absl::Duration d = absl::Seconds(20); - Advance(d); - char buf[512]; - Printer out(buf, 512); - cache_.Print(&out); // To update the regret - uint64_t expected_regret = absl::ToInt64Nanoseconds(d) * cached.raw_num(); - // Not exactly accurate since the mock clock advances with real time, and - // when we measure regret will be updated. - EXPECT_NEAR(cache_.regret(), expected_regret, expected_regret / 1000); - EXPECT_GE(cache_.regret(), expected_regret); + const HugeLength one = NHugePages(1); + Release(cache_.Get(NHugePages(5), &from)); + HugeRange r1, r2, r3, r4, r5; + r1 = cache_.Get(one, &from); + r2 = cache_.Get(one, &from); + r3 = cache_.Get(one, &from); + r4 = cache_.Get(one, &from); + r5 = cache_.Get(one, &from); + Release(r1); + Release(r2); + Release(r3); + Release(r4); + Release(r5); + + r1 = cache_.Get(one, &from); + ASSERT_EQ(false, from); + r2 = cache_.Get(one, &from); + ASSERT_EQ(false, from); + r3 = cache_.Get(one, &from); + ASSERT_EQ(false, from); + r4 = cache_.Get(one, &from); + ASSERT_EQ(false, from); + r5 = cache_.Get(one, &from); + ASSERT_EQ(false, from); + Release(r1); + Release(r2); + Release(r5); + + ASSERT_EQ(NHugePages(3), cache_.size()); + EXPECT_CALL(mock_unback_, + Unback(r5.start().first_page(), 1 * kPagesPerHugePage)) + .WillOnce(Return(false)); + EXPECT_EQ(NHugePages(0), cache_.ReleaseCachedPages(NHugePages(1))); + Release(r3); + Release(r4); + + EXPECT_CALL(mock_unback_, + Unback(r1.start().first_page(), 5 * kPagesPerHugePage)) + .WillOnce(Return(false)); + EXPECT_EQ(NHugePages(0), cache_.ReleaseCachedPages(NHugePages(200))); } -TEST_F(HugeCacheTest, Stats) { +TEST_P(HugeCacheTest, Stats) { bool from; HugeRange r = cache_.Get(NHugePages(1 + 1 + 2 + 1 + 3), &from); HugeRange r1, r2, r3, spacer1, spacer2; @@ -230,9 +217,9 @@ TEST_F(HugeCacheTest, Stats) { std::tie(spacer1, r2) = Split(spacer1, NHugePages(1)); std::tie(r2, spacer2) = Split(r2, NHugePages(2)); std::tie(spacer2, r3) = Split(spacer2, NHugePages(1)); - cache_.Release(r1); - cache_.Release(r2); - cache_.Release(r3); + Release(r1); + Release(r2); + Release(r3); ASSERT_EQ(NHugePages(6), cache_.size()); r1 = cache_.Get(NHugePages(1), &from); @@ -244,55 +231,51 @@ TEST_F(HugeCacheTest, Stats) { struct Helper { static void Stat(const HugeCache& cache, size_t* spans, - Length* pages_backed, Length* pages_unbacked, - double* avg_age) { - PageAgeHistograms ages(absl::base_internal::CycleClock::Now()); + Length* pages_backed, Length* pages_unbacked) { LargeSpanStats large; - cache.AddSpanStats(nullptr, &large, &ages); + cache.AddSpanStats(nullptr, &large); - const PageAgeHistograms::Histogram* hist = ages.GetTotalHistogram(false); *spans = large.spans; *pages_backed = large.normal_pages; *pages_unbacked = large.returned_pages; - *avg_age = hist->avg_age(); } }; - double avg_age; size_t spans; Length pages_backed; Length pages_unbacked; - cache_.Release(r1); - absl::SleepFor(absl::Microseconds(5000)); - Helper::Stat(cache_, &spans, &pages_backed, &pages_unbacked, &avg_age); + Release(r1); + Helper::Stat(cache_, &spans, &pages_backed, &pages_unbacked); EXPECT_EQ(Length(0), pages_unbacked); EXPECT_EQ(1, spans); EXPECT_EQ(NHugePages(1).in_pages(), pages_backed); - EXPECT_LE(0.005, avg_age); - cache_.Release(r2); - absl::SleepFor(absl::Microseconds(2500)); - Helper::Stat(cache_, &spans, &pages_backed, &pages_unbacked, &avg_age); + Release(r2); + Helper::Stat(cache_, &spans, &pages_backed, &pages_unbacked); EXPECT_EQ(Length(0), pages_unbacked); EXPECT_EQ(2, spans); EXPECT_EQ(NHugePages(3).in_pages(), pages_backed); - EXPECT_LE((0.0075 * 1 + 0.0025 * 2) / (1 + 2), avg_age); - cache_.Release(r3); - absl::SleepFor(absl::Microseconds(1250)); - Helper::Stat(cache_, &spans, &pages_backed, &pages_unbacked, &avg_age); + Release(r3); + Helper::Stat(cache_, &spans, &pages_backed, &pages_unbacked); EXPECT_EQ(Length(0), pages_unbacked); EXPECT_EQ(3, spans); EXPECT_EQ(NHugePages(6).in_pages(), pages_backed); - EXPECT_LE((0.00875 * 1 + 0.00375 * 2 + 0.00125 * 3) / (1 + 2 + 3), avg_age); } static double Frac(HugeLength num, HugeLength denom) { return static_cast(num.raw_num()) / denom.raw_num(); } -TEST_F(HugeCacheTest, Growth) { +// Tests that the cache can grow to fit a working set. The two cache shrinking +// mechanisms, demand-based release and limit-based release, use two different +// paths to shrink the cache (ReleaseCachedPagesByDemand vs. Release). We +// test both paths here. +TEST_P(HugeCacheTest, Growth) { + EXPECT_CALL(mock_unback_, Unback(testing::_, testing::_)) + .WillRepeatedly(Return(true)); + bool released; absl::BitGen rng; // fragmentation is a bit of a challenge @@ -306,13 +289,20 @@ TEST_F(HugeCacheTest, Growth) { } for (auto r : drop) { - cache_.Release(r); + Release(r); } // See the TODO in HugeCache::MaybeGrowCache; without this delay, // the above fragmentation plays merry havoc with our instrumentation. Advance(absl::Seconds(30)); - + // Requests a best-effort demand-based release to shrink the cache. + if (GetDemandBasedRelease()) { + cache_.ReleaseCachedPagesByDemand( + cache_.size(), + SkipSubreleaseIntervals{.short_interval = absl::Seconds(10), + .long_interval = absl::Seconds(10)}, + /*hit_limit=*/false); + } // Test that our cache can grow to fit a working set. HugeLength hot_set_sizes[] = {NHugePages(5), NHugePages(10), NHugePages(100), NHugePages(10000)}; @@ -334,7 +324,17 @@ TEST_F(HugeCacheTest, Growth) { if (released) needed_backing += l; } for (auto r : items) { - cache_.Release(r); + Release(r); + } + // Requests a demand-based release. The target will increase to + // kFractionToReleaseFromCache of the cache, and that is enough to trim + // the fragmentation. + if (GetDemandBasedRelease()) { + cache_.ReleaseCachedPagesByDemand( + NHugePages(0), + SkipSubreleaseIntervals{.short_interval = absl::Seconds(1), + .long_interval = absl::Seconds(1)}, + /*hit_limit=*/false); } return {needed_backing, got}; }; @@ -363,26 +363,35 @@ TEST_F(HugeCacheTest, Growth) { // approximately, given the randomized sizing... const double ratio = Frac(needed_backing, total); - EXPECT_LE(ratio, 0.2); + EXPECT_LE(ratio, 0.3); } } // If we repeatedly grow and shrink, but do so very slowly, we should *not* // cache the large variation. -TEST_F(HugeCacheTest, SlowGrowthUncached) { +TEST_P(HugeCacheTest, SlowGrowthUncached) { + // This test expects the cache to stay small when using unbacking with + // Release(). Hence we skip it when demand-based release is enabled. + if (GetDemandBasedRelease()) { + GTEST_SKIP(); + } + EXPECT_CALL(mock_unback_, Unback(testing::_, testing::_)) + .WillRepeatedly(Return(true)); + absl::Duration cache_time = GetCacheTime(); + absl::BitGen rng; std::uniform_int_distribution sizes(1, 10); for (int i = 0; i < 20; ++i) { std::vector rs; for (int j = 0; j < 20; ++j) { - Advance(absl::Milliseconds(600)); + Advance(cache_time); bool released; rs.push_back(cache_.Get(NHugePages(sizes(rng)), &released)); } HugeLength max_cached = NHugePages(0); for (auto r : rs) { - Advance(absl::Milliseconds(600)); - cache_.Release(r); + Advance(cache_time); + Release(r); max_cached = std::max(max_cached, cache_.size()); } EXPECT_GE(NHugePages(10), max_cached); @@ -390,7 +399,15 @@ TEST_F(HugeCacheTest, SlowGrowthUncached) { } // If very rarely we have a huge increase in usage, it shouldn't be cached. -TEST_F(HugeCacheTest, SpikesUncached) { +TEST_P(HugeCacheTest, SpikesUncached) { + // This test expects the cache to stay small when using unbacking with + // Release(). Hence we skip it when demand-based release is enabled. + if (GetDemandBasedRelease()) { + GTEST_SKIP(); + } + EXPECT_CALL(mock_unback_, Unback(testing::_, testing::_)) + .WillRepeatedly(Return(true)); + absl::Duration cache_time = GetCacheTime(); absl::BitGen rng; std::uniform_int_distribution sizes(1, 10); for (int i = 0; i < 20; ++i) { @@ -401,18 +418,50 @@ TEST_F(HugeCacheTest, SpikesUncached) { } HugeLength max_cached = NHugePages(0); for (auto r : rs) { - cache_.Release(r); + Release(r); max_cached = std::max(max_cached, cache_.size()); } EXPECT_GE(NHugePages(10), max_cached); - Advance(absl::Seconds(30)); + Advance(10 * cache_time); + } +} + +// If we allocate a spike occasionally but having demand-based release enabled, +// all freed hugepages will be cached even though the cache limit is low. This +// is because the cache shrinking mechanism in Release() is bypassed when +// demand-based release is enabled. +TEST_P(HugeCacheTest, SpikesCachedNoUnback) { + // This test expects no cache shirking in Release(). Hence we skip it when + // demand-based release is disabled. + if (!GetDemandBasedRelease()) { + GTEST_SKIP(); + } + absl::Duration cache_time = GetCacheTime(); + for (int i = 0; i < 20; ++i) { + std::vector rs; + for (int j = 0; j < 200; ++j) { + bool released; + rs.push_back(cache_.Get(NHugePages(5), &released)); + } + HugeLength max_cached = NHugePages(0); + for (auto r : rs) { + Release(r); + max_cached = std::max(max_cached, cache_.size()); + } + EXPECT_EQ(max_cached, NHugePages(1000)); + // The limit never changed as the growth mechanism sees no value in + // preparing for occasional peaks (i.e., shrink and grow in cache_time + // are not balanced). + EXPECT_EQ(cache_.limit(), NHugePages(10)); + Advance(10 * cache_time); } } // If very rarely we have a huge *decrease* in usage, it *should* be cached. -TEST_F(HugeCacheTest, DipsCached) { +TEST_P(HugeCacheTest, DipsCached) { absl::BitGen rng; std::uniform_int_distribution sizes(1, 10); + absl::Duration cache_time = GetCacheTime(); for (int i = 0; i < 20; ++i) { std::vector rs; HugeLength got = NHugePages(0); @@ -425,24 +474,32 @@ TEST_F(HugeCacheTest, DipsCached) { if (released) uncached += n; } // Most of our time is at high usage... - Advance(absl::Seconds(30)); + Advance(10 * cache_time); // Now immediately release and reallocate. for (auto r : rs) { - cache_.Release(r); + Release(r); } // warmup if (i >= 2) { - EXPECT_GE(0.06, Frac(uncached, got)); + EXPECT_GE(0.07, Frac(uncached, got)); } } } // Suppose in a previous era of behavior we needed a giant cache, // but now we don't. Do we figure this out promptly? -TEST_F(HugeCacheTest, Shrink) { +TEST_P(HugeCacheTest, Shrink) { + // This test expects the cache to shrink in Release() after the working set + // size is reduced. Hence we skip it when demand-based release is enabled. + if (GetDemandBasedRelease()) { + GTEST_SKIP(); + } + EXPECT_CALL(mock_unback_, Unback(testing::_, testing::_)) + .WillRepeatedly(Return(true)); absl::BitGen rng; std::uniform_int_distribution sizes(1, 10); + absl::Duration cache_time = GetCacheTime(); for (int i = 0; i < 20; ++i) { std::vector rs; for (int j = 0; j < 2000; ++j) { @@ -451,30 +508,431 @@ TEST_F(HugeCacheTest, Shrink) { rs.push_back(cache_.Get(n, &released)); } for (auto r : rs) { - cache_.Release(r); + Release(r); } } ASSERT_LE(NHugePages(10000), cache_.size()); for (int i = 0; i < 30; ++i) { - // New working set <= 20 pages. - Advance(absl::Seconds(1)); + // New working set <= 20 pages, arranging the allocation rounds happen in + // different cache limit updating windows (> cache_time * 2) so we can + // shrink the cache gradually in each round. + Advance(cache_time * 3); // And do some work. for (int j = 0; j < 100; ++j) { bool released; HugeRange r1 = cache_.Get(NHugePages(sizes(rng)), &released); HugeRange r2 = cache_.Get(NHugePages(sizes(rng)), &released); - cache_.Release(r1); - cache_.Release(r2); + Release(r1); + Release(r2); } } - + // The cache should have shrunk to the working set size. + ASSERT_GE(NHugePages(25), cache_.size()); ASSERT_GE(NHugePages(25), cache_.limit()); } -TEST_F(HugeCacheTest, Usage) { +// In demand-based release, we want to release as much as possible when the +// hit_limit is set. +TEST_P(HugeCacheTest, ReleaseByDemandHardRelease) { + // This test is sensitive to the number of pages per hugepage, as we are + // printing raw stats. + if (!GetDemandBasedRelease() || (kPagesPerHugePage != Length(256))) { + GTEST_SKIP(); + } + EXPECT_CALL(mock_unback_, Unback(testing::_, testing::_)) + .WillRepeatedly(Return(true)); + bool released; + HugeRange r = cache_.Get(NHugePages(1000), &released); + Release(r); + ASSERT_EQ(cache_.size(), NHugePages(1000)); + // Releases half of the cache with hit_limit set. + HugeLength unbacked_1 = cache_.ReleaseCachedPagesByDemand( + NHugePages(500), SkipSubreleaseIntervals{}, /*hit_limit=*/true); + EXPECT_EQ(unbacked_1, NHugePages(500)); + // Releases the remaining using invalid intervals. + HugeLength unbacked_2 = cache_.ReleaseCachedPagesByDemand( + NHugePages(1000), SkipSubreleaseIntervals{}, /*hit_limit=*/false); + EXPECT_EQ(unbacked_2, NHugePages(500)); + std::string buffer(1024 * 1024, '\0'); + { + Printer printer(&*buffer.begin(), buffer.size()); + cache_.Print(printer); + } + buffer.resize(strlen(buffer.c_str())); + + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugeCache: 0 MiB fast unbacked, 2000 MiB periodic +)")); + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugeCache: Since startup, 1000 hugepages released, (500 hugepages due to reaching tcmalloc limit) +)")); + // The skip-subrelease mechanism is bypassed for both requests. + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugeCache: Since the start of the execution, 0 subreleases (0 pages) were skipped due to the sum of short-term (0s) fluctuations and long-term (0s) trends. +HugeCache: 0.0000% of decisions confirmed correct, 0 pending (0.0000% of pages, 0 pending). +HugeCache: Subrelease stats last 10 min: total 256000 pages subreleased (0 pages from partial allocs), 0 hugepages broken +)")); +} + +// Tests that we can increase the release target to a fraction +// (kFractionToReleaseFromCache) of HugeCache. This can happen regardless of the +// initial value of the target. +TEST_P(HugeCacheTest, ReleaseByDemandIncreaseTarget) { + if (!GetDemandBasedRelease()) { + GTEST_SKIP(); + } + EXPECT_CALL(mock_unback_, Unback(testing::_, testing::_)) + .WillRepeatedly(Return(true)); + bool released; + // (Current - 3 min) Max: 60 hps, Min: 50 hps. + HugeRange peak_1a = cache_.Get(NHugePages(50), &released); + HugeRange peak_1b = cache_.Get(NHugePages(10), &released); + Advance(absl::Minutes(1)); + + // (Current - 2 min) Max: 170 hps, Min: 70 hps. + HugeRange peak_2a = cache_.Get(NHugePages(100), &released); + HugeRange peak_2b = cache_.Get(NHugePages(10), &released); + Release(peak_2a); + Advance(absl::Minutes(1)); + + // (Current - 1 minute) Max: 20 hps, Min: 10 hps. + Release(peak_1a); + Release(peak_2b); + Advance(absl::Minutes(1)); + + // (Current) Max: 0 hps, Min: 0 hps. + Release(peak_1b); + EXPECT_EQ(cache_.size(), NHugePages(170)); + EXPECT_EQ(cache_.usage(), NHugePages(0)); + + // The past demand is 80 hps (short 10 hps + long 70 hps), and we can unback + // 34 hps (170 hps * kFractionToReleaseFromCache), more than the release + // target (0 hps). + HugeLength unbacked_1 = cache_.ReleaseCachedPagesByDemand( + NHugePages(0), + SkipSubreleaseIntervals{.short_interval = absl::Seconds(120), + .long_interval = absl::Seconds(180)}, + /*hit_limit=*/false); + EXPECT_EQ(unbacked_1, NHugePages(34)); + // Repeats the test using a non-zero target. + EXPECT_EQ(cache_.size(), NHugePages(136)); + HugeLength unbacked_2 = cache_.ReleaseCachedPagesByDemand( + NHugePages(10), + SkipSubreleaseIntervals{.short_interval = absl::Seconds(120), + .long_interval = absl::Seconds(180)}, + /*hit_limit=*/false); + EXPECT_EQ(unbacked_2, NHugePages(28)); + + // Tests that we always manage to protect the cache limit (10 hps) while + // increasing the target. First, force the cache close to the limit using a + // crafted target. + HugeLength unbacked_3 = cache_.ReleaseCachedPagesByDemand( + NHugePages(97), SkipSubreleaseIntervals{}, /*hit_limit=*/true); + EXPECT_EQ(unbacked_3, NHugePages(97)); + EXPECT_EQ(cache_.size(), NHugePages(11)); + // Then, ask for release using target zero. + HugeLength unbacked_4 = cache_.ReleaseCachedPagesByDemand( + NHugePages(0), SkipSubreleaseIntervals{}, /*hit_limit=*/true); + EXPECT_EQ(unbacked_4, NHugePages(1)); + EXPECT_EQ(cache_.size(), NHugePages(10)); + // Now the cache is at the limit. Checks if that can be protected. + HugeLength unbacked_5 = cache_.ReleaseCachedPagesByDemand( + NHugePages(0), SkipSubreleaseIntervals{}, /*hit_limit=*/true); + EXPECT_EQ(unbacked_5, NHugePages(0)); + + // Finally, show that we can release the limit if requested. There has been no + // demand in the past 10s so we can release the rest of the cache. + HugeLength unbacked_6 = cache_.ReleaseCachedPagesByDemand( + NHugePages(100), + SkipSubreleaseIntervals{.short_interval = absl::Seconds(10), + .long_interval = absl::Seconds(10)}, + /*hit_limit=*/false); + EXPECT_EQ(unbacked_6, NHugePages(10)); +} + +// Tests releasing zero pages when the cache size and demand are both zero. +TEST_P(HugeCacheTest, ReleaseByDemandReleaseZero) { + if (!GetDemandBasedRelease()) { + GTEST_SKIP(); + } + EXPECT_EQ(cache_.ReleaseCachedPagesByDemand( + NHugePages(0), + SkipSubreleaseIntervals{.short_interval = absl::Seconds(1), + .long_interval = absl::Seconds(1)}, + /*hit_limit=*/false), + NHugePages(0)); +} + +// Tests that releasing target is not affected if the demand history is empty. +TEST_P(HugeCacheTest, ReleaseByDemandNoHistory) { + if (!GetDemandBasedRelease()) { + GTEST_SKIP(); + } + EXPECT_CALL(mock_unback_, Unback(testing::_, testing::_)) + .WillRepeatedly(Return(true)); + // First we make sure that the cache is not empty. + bool released; + Release(cache_.Get(NHugePages(10), &released)); + EXPECT_EQ(cache_.size(), NHugePages(10)); + // Then we advance the time to make sure that the demand history is empty. + Advance(absl::Minutes(30)); + EXPECT_EQ(cache_.ReleaseCachedPagesByDemand( + NHugePages(10), + SkipSubreleaseIntervals{.short_interval = absl::Seconds(1), + .long_interval = absl::Seconds(1)}, + /*hit_limit=*/false), + NHugePages(10)); +} + +// Tests that the demand is capped by peak within the default interval (5 mins). +TEST_P(HugeCacheTest, ReleaseByDemandCappedByDemandPeak) { + if (!GetDemandBasedRelease()) { + GTEST_SKIP(); + } + EXPECT_CALL(mock_unback_, Unback(testing::_, testing::_)) + .WillRepeatedly(Return(true)); + // Generates a demand pattern that can cause the sum-of-peak issue. + bool released; + // The diff peak: 20 hps - 1 hps = 19 hps. + HugeRange diff_a = cache_.Get(NHugePages(1), &released); + HugeRange diff_b = cache_.Get(NHugePages(20), &released); + Release(diff_a); + Release(diff_b); + Advance(absl::Minutes(5)); + // The long-term demand peak: 15 hps. + HugeRange peak = cache_.Get(NHugePages(15), &released); + Advance(absl::Minutes(1)); + Release(peak); + EXPECT_EQ(cache_.size(), NHugePages(21)); + // Releases partial of the cache as the demand is capped by the 5-mins' peak + // (15 hps). + EXPECT_EQ(cache_.ReleaseCachedPagesByDemand( + NHugePages(100), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(10), + .long_interval = absl::Minutes(10)}, + /*hit_limit=*/false), + NHugePages(6)); + // Releases the rest of the cache. + EXPECT_EQ(cache_.ReleaseCachedPagesByDemand(NHugePages(100), + SkipSubreleaseIntervals{}, + /*hit_limit=*/false), + NHugePages(15)); +} + +// Tests demand-based skip release. The test is a modified version of the +// FillerTest.SkipSubrelease test by removing parts designed particularly for +// subrelease. +TEST_P(HugeCacheTest, ReleaseByDemandSkipRelease) { + // This test is sensitive to the number of pages per hugepage, as we are + // printing raw stats. + if (!GetDemandBasedRelease() || (kPagesPerHugePage != Length(256))) { + GTEST_SKIP(); + } + + EXPECT_CALL(mock_unback_, Unback(testing::_, testing::_)) + .WillRepeatedly(Return(true)); + // First it generates a peak (the long-term demand peak) and waits for + // time_interval(a). Then, it generates a higher peak that contains the + // short-term fluctuation peak, and waits for time_interval(b). It then + // generates a trough in demand and asks to release. Finally, it waits for + // time_interval(c) to generate the highest peak which is used for evaluating + // release correctness. + const auto demand_pattern = + [&](absl::Duration a, absl::Duration b, absl::Duration c, + SkipSubreleaseIntervals intervals, bool expected_release) { + bool released; + // First peak: min_demand 10 hps , max_demand 15 hps, diff 10 hps. + HugeRange peak_1a = cache_.Get(NHugePages(10), &released); + HugeRange peak_1b = cache_.Get(NHugePages(5), &released); + Advance(a); + // Second peak: min_demand 0 hps, max_demand 20 hps, diff 20 hps. + Release(peak_1a); + Release(peak_1b); + HugeRange peak_2a = cache_.Get(NHugePages(15), &released); + HugeRange peak_2b = cache_.Get(NHugePages(5), &released); + EXPECT_EQ(cache_.usage(), NHugePages(20)); + EXPECT_EQ(cache_.size(), NHugePages(0)); + Advance(b); + // Trough: min_demand 5 hps, max_demand 5 hps, diff 0 hps. + Release(peak_2a); + EXPECT_EQ(cache_.usage(), NHugePages(5)); + EXPECT_EQ(cache_.size(), NHugePages(15)); + // Release is capped by the cache size. + EXPECT_EQ(cache_.ReleaseCachedPagesByDemand(NHugePages(100), intervals, + /*hit_limit=*/false), + expected_release ? NHugePages(15) : NHugePages(0)); + Advance(c); + // Third peak: min_demand 25 hps, max_demand 30 hps, diff 5 hps. + // Note, skip-subrelease evaluates the correctness of skipped releases + // using the first demand update recorded in an epoch (25 hps for this + // case). + HugeRange peak_3a = cache_.Get(NHugePages(20), &released); + HugeRange peak_3b = cache_.Get(NHugePages(5), &released); + EXPECT_EQ(cache_.usage(), NHugePages(30)); + Release(peak_2b); + Release(peak_3a); + Release(peak_3b); + // If the previous release is skipped, the cache size is larger due to + // fragmentation. + EXPECT_EQ(cache_.ReleaseCachedPagesByDemand(NHugePages(100), + SkipSubreleaseIntervals{}, + /*hit_limit=*/false), + expected_release ? NHugePages(30) : NHugePages(40)); + Advance(absl::Minutes(30)); + }; + { + // Skip release feature is disabled if all intervals are zero. + SCOPED_TRACE("demand_pattern 1"); + demand_pattern(absl::Minutes(1), absl::Minutes(1), absl::Minutes(4), + SkipSubreleaseIntervals{}, /*expected_release=*/true); + } + { + // Uses short-term and long-term intervals (combined demand is 30 hps but + // capped by maximum demand in 10 mins, 20 hps), incorrectly skipped 15 hps. + SCOPED_TRACE("demand_pattern 2"); + demand_pattern(absl::Minutes(3), absl::Minutes(2), absl::Minutes(7), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(3), + .long_interval = absl::Minutes(6)}, + /*expected_release=*/false); + } + { + // Uses short-term and long-term intervals (combined demand 5 hps), released + // all free hps. + SCOPED_TRACE("demand_pattern 3"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(1), + .long_interval = absl::Minutes(2)}, + /*expected_release=*/true); + } + { + // Uses only short-term interval (demand 20 hps), correctly skipped 15 hps. + SCOPED_TRACE("demand_pattern 4"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(3)}, + /*expected_release=*/false); + } + { + // Uses only long-term interval (demand 5 hps), released all free pages. + SCOPED_TRACE("demand_pattern 5"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.long_interval = absl::Minutes(2)}, + /*expected_release=*/true); + } + // This captures a corner case: If we hit another peak immediately after a + // release decision (recorded in the same epoch), do not count this as + // a correct release decision. + { + SCOPED_TRACE("demand_pattern 6"); + demand_pattern(absl::Milliseconds(10), absl::Milliseconds(10), + absl::Milliseconds(10), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(1), + .long_interval = absl::Minutes(2)}, + /*expected_release=*/false); + } + // Ensure that the tracker is updated. + bool released; + HugeRange tiny = cache_.Get(NHugePages(1), &released); + Release(tiny); + std::string buffer(1024 * 1024, '\0'); + { + Printer printer(&*buffer.begin(), buffer.size()); + cache_.Print(printer); + } + buffer.resize(strlen(buffer.c_str())); + + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugeCache: Since the start of the execution, 3 subreleases (11520 pages) were skipped due to the sum of short-term (60s) fluctuations and long-term (120s) trends. +HugeCache: 33.3333% of decisions confirmed correct, 0 pending (33.3333% of pages, 0 pending). +HugeCache: Subrelease stats last 10 min: total 0 pages subreleased (0 pages from partial allocs), 0 hugepages broken +)")); +} + +// Tests the skipping decisions are reported correctly, particularly for the +// demand peaks used in correctness evaluation. +TEST_P(HugeCacheTest, ReleaseByDemandSkipReleaseReport) { + // This test is sensitive to the number of pages per hugepage, as we are + // printing raw stats. + if (!GetDemandBasedRelease() || (kPagesPerHugePage != Length(256))) { + GTEST_SKIP(); + } + EXPECT_CALL(mock_unback_, Unback(testing::_, testing::_)) + .WillRepeatedly(Return(true)); + + // Reports skip release using the recent demand peak (23 hps): it is + // smaller than the current capacity (33 hps) when 8 hps are skipped. + // The skipping is correct as the future demand is 25 hps. + bool released; + HugeRange peak_1a = cache_.Get(NHugePages(10), &released); + HugeRange peak_1b = cache_.Get(NHugePages(8), &released); + Advance(absl::Minutes(2)); + Release(peak_1a); + HugeRange peak_2a = cache_.Get(NHugePages(15), &released); + Release(peak_1b); + EXPECT_EQ(cache_.usage(), NHugePages(15)); + EXPECT_EQ(cache_.size(), NHugePages(18)); + EXPECT_EQ(cache_.ReleaseCachedPagesByDemand( + NHugePages(30), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(3), + .long_interval = absl::Minutes(3)}, + /*hit_limit=*/false), + NHugePages(10)); + Advance(absl::Minutes(3)); + HugeRange peak_3a = cache_.Get(NHugePages(10), &released); + Release(peak_2a); + Release(peak_3a); + EXPECT_EQ(cache_.ReleaseCachedPagesByDemand(NHugePages(100), + SkipSubreleaseIntervals{}, + /*hit_limit=*/false), + NHugePages(33)); + Advance(absl::Minutes(30)); + + // Reports skip release using the current capacity (15 hps): it + // is smaller than the recent peak (20 hps) when 10 hps are skipped. They are + // correctly skipped as the future demand is 18 hps. + HugeRange peak_4a = cache_.Get(NHugePages(10), &released); + HugeRange peak_4b = cache_.Get(NHugePages(10), &released); + Release(peak_4a); + EXPECT_EQ(cache_.ReleaseCachedPagesByDemand(NHugePages(10), + SkipSubreleaseIntervals{}, false), + NHugePages(10)); + Advance(absl::Minutes(2)); + HugeRange peak_5a = cache_.Get(NHugePages(5), &released); + Release(peak_4b); + EXPECT_EQ(cache_.ReleaseCachedPagesByDemand( + NHugePages(10), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(3), + .long_interval = absl::Minutes(3)}, + /*hit_limit=*/false), + NHugePages(0)); + Advance(absl::Minutes(3)); + HugeRange peak_6a = cache_.Get(NHugePages(10), &released); + HugeRange peak_6b = cache_.Get(NHugePages(3), &released); + Release(peak_5a); + Release(peak_6a); + Release(peak_6b); + EXPECT_EQ(cache_.ReleaseCachedPagesByDemand(NHugePages(100), + SkipSubreleaseIntervals{}, + /*hit_limit=*/false), + NHugePages(18)); + Advance(absl::Minutes(30)); + + std::string buffer(1024 * 1024, '\0'); + { + Printer printer(&*buffer.begin(), buffer.size()); + cache_.Print(printer); + } + buffer.resize(strlen(buffer.c_str())); + + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugeCache: Since the start of the execution, 2 subreleases (4608 pages) were skipped due to the sum of short-term (180s) fluctuations and long-term (180s) trends. +HugeCache: 100.0000% of decisions confirmed correct, 0 pending (100.0000% of pages, 0 pending). +)")); +} + +TEST_P(HugeCacheTest, Usage) { bool released; auto r1 = cache_.Get(NHugePages(10), &released); @@ -483,7 +941,7 @@ TEST_F(HugeCacheTest, Usage) { auto r2 = cache_.Get(NHugePages(100), &released); EXPECT_EQ(NHugePages(110), cache_.usage()); - cache_.Release(r1); + Release(r1); EXPECT_EQ(NHugePages(100), cache_.usage()); // Pretend we unbacked this. @@ -558,6 +1016,16 @@ TEST_F(MinMaxTrackerTest, Works) { EXPECT_EQ(NHugePages(1), tracker.MinOverTime(kDuration)); } +INSTANTIATE_TEST_SUITE_P( + All, HugeCacheTest, + testing::Combine(testing::Values(absl::Seconds(1), absl::Seconds(30)), + testing::Bool()), + [](const testing::TestParamInfo info) { + return "Cachetime_" + absl::FormatDuration(std::get<0>(info.param)) + + "DemandBasedRelease_" + + (std::get<1>(info.param) ? "Enabled" : "Disabled"); + }); + } // namespace } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator.cc b/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator.cc index e662456df6bb..57b45a425351 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator.cc +++ b/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator.cc @@ -14,69 +14,44 @@ #include "tcmalloc/huge_page_aware_allocator.h" -#include -#include +#include -#include - -#include "absl/base/internal/cycleclock.h" -#include "absl/base/internal/spinlock.h" -#include "absl/time/time.h" -#include "tcmalloc/common.h" -#include "tcmalloc/experiment.h" -#include "tcmalloc/experiment_config.h" -#include "tcmalloc/huge_allocator.h" +#include "absl/base/attributes.h" +#include "tcmalloc/arena.h" #include "tcmalloc/huge_pages.h" +#include "tcmalloc/huge_region.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/environment.h" #include "tcmalloc/internal/logging.h" -#include "tcmalloc/internal/optimization.h" +#include "tcmalloc/internal/memory_tag.h" #include "tcmalloc/pagemap.h" -#include "tcmalloc/parameters.h" +#include "tcmalloc/pages.h" #include "tcmalloc/span.h" #include "tcmalloc/static_vars.h" -#include "tcmalloc/stats.h" +#include "tcmalloc/system-alloc.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { -bool decide_want_hpaa(); -ABSL_ATTRIBUTE_WEAK int default_want_hpaa(); ABSL_ATTRIBUTE_WEAK int default_subrelease(); -bool decide_subrelease() { - if (!decide_want_hpaa()) { - // Subrelease is off if HPAA is off. - return false; - } +namespace huge_page_allocator_internal { - const char *e = thread_safe_getenv("TCMALLOC_HPAA_CONTROL"); +bool decide_subrelease() { + const char* e = thread_safe_getenv("TCMALLOC_HPAA_CONTROL"); if (e) { switch (e[0]) { case '0': - if (kPageShift <= 12) { - return false; - } - - if (default_want_hpaa != nullptr) { - int default_hpaa = default_want_hpaa(); - if (default_hpaa < 0) { - return false; - } - } - - Log(kLog, __FILE__, __LINE__, - "Runtime opt-out from HPAA requires building with " - "//tcmalloc:want_no_hpaa." - ); + // If we're forcing HPAA on, we want to converge towards our default + // of subrelease on, rather than off (where it is moot without HPAA). break; case '1': return false; case '2': return true; default: - Crash(kCrash, __FILE__, __LINE__, "bad env var", e); - return false; + TC_BUG("bad env var '%s'", e); } } @@ -87,589 +62,91 @@ bool decide_subrelease() { } } - if (tcmalloc::IsExperimentActive(tcmalloc::Experiment::TCMALLOC_TEMERAIRE)) { - return false; - } - return true; } -FillerPartialRerelease decide_partial_rerelease() { - const char *e = thread_safe_getenv("TCMALLOC_PARTIAL_RELEASE_CONTROL"); - if (e) { - if (e[0] == '0') { - return FillerPartialRerelease::Return; - } - if (e[0] == '1') { - return FillerPartialRerelease::Retain; - } - Crash(kCrash, __FILE__, __LINE__, "bad env var", e); - } - - return FillerPartialRerelease::Retain; -} - -// Some notes: locking discipline here is a bit funny, because -// we want to *not* hold the pageheap lock while backing memory. - -// We have here a collection of slightly different allocators each -// optimized for slightly different purposes. This file has two main purposes: -// - pick the right one for a given allocation -// - provide enough data to figure out what we picked last time! - -HugePageAwareAllocator::HugePageAwareAllocator(MemoryTag tag) - : PageAllocatorInterface("HugePageAware", tag), - filler_(decide_partial_rerelease()), - alloc_( - [](MemoryTag tag) { - // TODO(ckennelly): Remove the template parameter. - switch (tag) { - case MemoryTag::kNormal: - return AllocAndReport; - case MemoryTag::kNormalP1: - return AllocAndReport; - case MemoryTag::kSampled: - return AllocAndReport; - default: - ASSUME(false); - __builtin_unreachable(); - } - }(tag), - MetaDataAlloc), - cache_(HugeCache{&alloc_, MetaDataAlloc, UnbackWithoutLock}) { - tracker_allocator_.Init(&Static::arena()); - region_allocator_.Init(&Static::arena()); -} - -HugePageAwareAllocator::FillerType::Tracker *HugePageAwareAllocator::GetTracker( - HugePage p) { - void *v = Static::pagemap().GetHugepage(p.first_page()); - FillerType::Tracker *pt = reinterpret_cast(v); - ASSERT(pt == nullptr || pt->location() == p); - return pt; -} - -void HugePageAwareAllocator::SetTracker( - HugePage p, HugePageAwareAllocator::FillerType::Tracker *pt) { - Static::pagemap().SetHugepage(p.first_page(), pt); -} - -PageId HugePageAwareAllocator::AllocAndContribute(HugePage p, Length n, - bool donated) { - CHECK_CONDITION(p.start_addr() != nullptr); - FillerType::Tracker *pt = tracker_allocator_.New(); - new (pt) FillerType::Tracker(p, absl::base_internal::CycleClock::Now()); - ASSERT(pt->longest_free_range() >= n); - PageId page = pt->Get(n).page; - ASSERT(page == p.first_page()); - SetTracker(p, pt); - filler_.Contribute(pt, donated); - return page; -} - -PageId HugePageAwareAllocator::RefillFiller(Length n, bool *from_released) { - HugeRange r = cache_.Get(NHugePages(1), from_released); - if (!r.valid()) return PageId{0}; - // This is duplicate to Finalize, but if we need to break up - // hugepages to get to our usage limit it would be very bad to break - // up what's left of r after we allocate from there--while r is - // mostly empty, clearly what's left in the filler is too fragmented - // to be very useful, and we would rather release those - // pages. Otherwise, we're nearly guaranteed to release r (if n - // isn't very large), and the next allocation will just repeat this - // process. - Static::page_allocator().ShrinkToUsageLimit(); - return AllocAndContribute(r.start(), n, /*donated=*/false); -} - -Span *HugePageAwareAllocator::Finalize(Length n, PageId page) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { - ASSERT(page != PageId{0}); - Span *ret = Span::New(page, n); - Static::pagemap().Set(page, ret); - ASSERT(!ret->sampled()); - info_.RecordAlloc(page, n); - Static::page_allocator().ShrinkToUsageLimit(); - return ret; -} - -// For anything <= half a huge page, we will unconditionally use the filler -// to pack it into a single page. If we need another page, that's fine. -Span *HugePageAwareAllocator::AllocSmall(Length n, bool *from_released) { - auto [pt, page] = filler_.TryGet(n); - if (ABSL_PREDICT_TRUE(pt != nullptr)) { - *from_released = false; - return Finalize(n, page); - } - - page = RefillFiller(n, from_released); - if (ABSL_PREDICT_FALSE(page == PageId{0})) { - return nullptr; - } - return Finalize(n, page); -} +extern "C" ABSL_ATTRIBUTE_WEAK bool +default_want_disable_huge_region_more_often(); -Span *HugePageAwareAllocator::AllocLarge(Length n, bool *from_released) { - // If it's an exact page multiple, just pull it from pages directly. - HugeLength hl = HLFromPages(n); - if (hl.in_pages() == n) { - return AllocRawHugepages(n, from_released); +bool use_huge_region_more_often() { + // Disable huge regions more often feature if built against an opt-out. + if (default_want_disable_huge_region_more_often != nullptr) { + return false; } - PageId page; - // If we fit in a single hugepage, try the Filler first. - if (n < kPagesPerHugePage) { - auto [pt, page] = filler_.TryGet(n); - if (ABSL_PREDICT_TRUE(pt != nullptr)) { - *from_released = false; - return Finalize(n, page); + // TODO(b/296281171): Remove this opt-out. + const char* e = + thread_safe_getenv("TCMALLOC_USE_HUGE_REGION_MORE_OFTEN_DISABLE"); + if (e) { + switch (e[0]) { + case '0': + return true; + case '1': + return false; + default: + TC_BUG("bad env var '%s'", e); } } - // If we're using regions in this binary (see below comment), is - // there currently available space there? - if (regions_.MaybeGet(n, &page, from_released)) { - return Finalize(n, page); - } - - // We have two choices here: allocate a new region or go to - // hugepages directly (hoping that slack will be filled by small - // allocation.) The second strategy is preferrable, as it's - // typically faster and usually more space efficient, but it's sometimes - // catastrophic. - // - // See https://github.com/google/tcmalloc/tree/master/docs/regions-are-not-optional.md - // - // So test directly if we're in the bad case--almost no binaries are. - // If not, just fall back to direct allocation (and hope we do hit that case!) - const Length slack = info_.slack(); - // Don't bother at all until the binary is reasonably sized - if (slack < HLFromBytes(64 * 1024 * 1024).in_pages()) { - return AllocRawHugepages(n, from_released); - } - - // In the vast majority of binaries, we have many small allocations which - // will nicely fill slack. (Fleetwide, the average ratio is 15:1; only - // a handful of binaries fall below 1:1.) - const Length small = info_.small(); - if (slack < small) { - return AllocRawHugepages(n, from_released); - } - - // We couldn't allocate a new region. They're oversized, so maybe we'd get - // lucky with a smaller request? - if (!AddRegion()) { - return AllocRawHugepages(n, from_released); - } - - CHECK_CONDITION(regions_.MaybeGet(n, &page, from_released)); - return Finalize(n, page); -} - -Span *HugePageAwareAllocator::AllocEnormous(Length n, bool *from_released) { - return AllocRawHugepages(n, from_released); -} - -Span *HugePageAwareAllocator::AllocRawHugepages(Length n, bool *from_released) { - HugeLength hl = HLFromPages(n); - - HugeRange r = cache_.Get(hl, from_released); - if (!r.valid()) return nullptr; - - // We now have a huge page range that covers our request. There - // might be some slack in it if n isn't a multiple of - // kPagesPerHugePage. Add the hugepage with slack to the filler, - // pretending the non-slack portion is a smaller allocation. - Length total = hl.in_pages(); - Length slack = total - n; - HugePage first = r.start(); - SetTracker(first, nullptr); - HugePage last = first + r.len() - NHugePages(1); - if (slack == Length(0)) { - SetTracker(last, nullptr); - return Finalize(total, r.start().first_page()); - } - - ++donated_huge_pages_; - - Length here = kPagesPerHugePage - slack; - ASSERT(here > Length(0)); - AllocAndContribute(last, here, /*donated=*/true); - return Finalize(n, r.start().first_page()); -} - -static void BackSpan(Span *span) { - SystemBack(span->start_address(), span->bytes_in_span()); -} - -// public -Span *HugePageAwareAllocator::New(Length n) { - CHECK_CONDITION(n > Length(0)); - bool from_released; - Span *s = LockAndAlloc(n, &from_released); - if (s) { - // Prefetch for writing, as we anticipate using the memory soon. - __builtin_prefetch(s->start_address(), 1, 3); - if (from_released) BackSpan(s); - } - ASSERT(!s || GetMemoryTag(s->start_address()) == tag_); - return s; -} - -Span *HugePageAwareAllocator::LockAndAlloc(Length n, bool *from_released) { - absl::base_internal::SpinLockHolder h(&pageheap_lock); - // Our policy depends on size. For small things, we will pack them - // into single hugepages. - if (n <= kPagesPerHugePage / 2) { - return AllocSmall(n, from_released); - } - - // For anything too big for the filler, we use either a direct hugepage - // allocation, or possibly the regions if we are worried about slack. - if (n <= HugeRegion::size().in_pages()) { - return AllocLarge(n, from_released); - } - - // In the worst case, we just fall back to directly allocating a run - // of hugepages. - return AllocEnormous(n, from_released); -} - -// public -Span *HugePageAwareAllocator::NewAligned(Length n, Length align) { - if (align <= Length(1)) { - return New(n); - } - - // we can do better than this, but... - // TODO(b/134690769): support higher align. - CHECK_CONDITION(align <= kPagesPerHugePage); - bool from_released; - Span *s; - { - absl::base_internal::SpinLockHolder h(&pageheap_lock); - s = AllocRawHugepages(n, &from_released); - } - if (s && from_released) BackSpan(s); - ASSERT(!s || GetMemoryTag(s->start_address()) == tag_); - return s; -} - -void HugePageAwareAllocator::DeleteFromHugepage(FillerType::Tracker *pt, - PageId p, Length n) { - if (ABSL_PREDICT_TRUE(filler_.Put(pt, p, n) == nullptr)) return; - if (pt->donated()) { - --donated_huge_pages_; - } - ReleaseHugepage(pt); -} - -bool HugePageAwareAllocator::AddRegion() { - HugeRange r = alloc_.Get(HugeRegion::size()); - if (!r.valid()) return false; - HugeRegion *region = region_allocator_.New(); - new (region) HugeRegion(r, SystemRelease); - regions_.Contribute(region); return true; } -void HugePageAwareAllocator::Delete(Span *span) { - ASSERT(!span || GetMemoryTag(span->start_address()) == tag_); - PageId p = span->first_page(); - HugePage hp = HugePageContaining(p); - Length n = span->num_pages(); - info_.RecordFree(p, n); - - Span::Delete(span); - - // The tricky part, as with so many allocators: where did we come from? - // There are several possibilities. - FillerType::Tracker *pt = GetTracker(hp); - // a) We got packed by the filler onto a single hugepage - return our - // allocation to that hugepage in the filler. - if (ABSL_PREDICT_TRUE(pt != nullptr)) { - ASSERT(hp == HugePageContaining(p + n - Length(1))); - DeleteFromHugepage(pt, p, n); - return; - } - - // b) We got put into a region, possibly crossing hugepages - - // return our allocation to the region. - if (regions_.MaybePut(p, n)) return; - - // c) we came straight from the HugeCache - return straight there. (We - // might have had slack put into the filler - if so, return that virtual - // allocation to the filler too!) - ASSERT(n >= kPagesPerHugePage); - HugeLength hl = HLFromPages(n); - HugePage last = hp + hl - NHugePages(1); - Length slack = hl.in_pages() - n; - if (slack == Length(0)) { - ASSERT(GetTracker(last) == nullptr); - } else { - pt = GetTracker(last); - CHECK_CONDITION(pt != nullptr); - // We put the slack into the filler (see AllocEnormous.) - // Handle this page separately as a virtual allocation - // onto the last hugepage. - PageId virt = last.first_page(); - Length virt_len = kPagesPerHugePage - slack; - pt = filler_.Put(pt, virt, virt_len); - // We may have used the slack, which would prevent us from returning - // the entire range now. If filler returned a Tracker, we are fully empty. - if (pt == nullptr) { - // Last page isn't empty -- pretend the range was shorter. - --hl; - } else { - // Last page was empty - but if we sub-released it, we still - // have to split it off and release it independently.) - if (pt->released()) { - --hl; - ReleaseHugepage(pt); - } else { - // Get rid of the tracker *object*, but not the *hugepage* - // (which is still part of our range.) We were able to reclaim the - // contributed slack. - --donated_huge_pages_; - SetTracker(pt->location(), nullptr); - tracker_allocator_.Delete(pt); - } - } - } - cache_.Release({hp, hl}); -} - -void HugePageAwareAllocator::ReleaseHugepage(FillerType::Tracker *pt) { - ASSERT(pt->used_pages() == Length(0)); - HugeRange r = {pt->location(), NHugePages(1)}; - SetTracker(pt->location(), nullptr); - - if (pt->released()) { - cache_.ReleaseUnbacked(r); - } else { - cache_.Release(r); - } - - tracker_allocator_.Delete(pt); -} - -// public -BackingStats HugePageAwareAllocator::stats() const { - BackingStats stats = alloc_.stats(); - const auto actual_system = stats.system_bytes; - stats += cache_.stats(); - stats += filler_.stats(); - stats += regions_.stats(); - // the "system" (total managed) byte count is wildly double counted, - // since it all comes from HugeAllocator but is then managed by - // cache/regions/filler. Adjust for that. - stats.system_bytes = actual_system; - return stats; -} - -// public -void HugePageAwareAllocator::GetSmallSpanStats(SmallSpanStats *result) { - GetSpanStats(result, nullptr, nullptr); -} - -// public -void HugePageAwareAllocator::GetLargeSpanStats(LargeSpanStats *result) { - GetSpanStats(nullptr, result, nullptr); +HugeRegionUsageOption huge_region_option() { + // By default, we use slack to determine when to use HugeRegion. When slack is + // greater than 64MB (to ignore small binaries), and greater than the number + // of small allocations, we allocate large allocations from HugeRegion. + // + // When huge-region-more-often feature is enabled, we use number of abandoned + // pages in addition to slack to make a decision. If the size of abandoned + // pages plus slack exceeds 64MB (to ignore small binaries), we use HugeRegion + // for large allocations. This results in using HugeRegions for all the large + // allocations once the size exceeds 64MB. + return use_huge_region_more_often() + ? HugeRegionUsageOption::kUseForAllLargeAllocs + : HugeRegionUsageOption::kDefault; } -void HugePageAwareAllocator::GetSpanStats(SmallSpanStats *small, - LargeSpanStats *large, - PageAgeHistograms *ages) { - if (small != nullptr) { - *small = SmallSpanStats(); - } - if (large != nullptr) { - *large = LargeSpanStats(); - } +Arena& StaticForwarder::arena() { return tc_globals.arena(); } - alloc_.AddSpanStats(small, large, ages); - filler_.AddSpanStats(small, large, ages); - regions_.AddSpanStats(small, large, ages); - cache_.AddSpanStats(small, large, ages); +void* StaticForwarder::GetHugepage(HugePage p) { + return tc_globals.pagemap().GetHugepage(p.first_page()); } -// public -Length HugePageAwareAllocator::ReleaseAtLeastNPages(Length num_pages) { - Length released; - released += cache_.ReleaseCachedPages(HLFromPages(num_pages)).in_pages(); - - // This is our long term plan but in current state will lead to insufficent - // THP coverage. It is however very useful to have the ability to turn this on - // for testing. - // TODO(b/134690769): make this work, remove the flag guard. - if (Parameters::hpaa_subrelease()) { - if (released < num_pages) { - released += filler_.ReleasePages( - num_pages - released, Parameters::filler_skip_subrelease_interval(), - /*hit_limit*/ false); - } - } - - // TODO(b/134690769): - // - perhaps release region? - // - refuse to release if we're too close to zero? - info_.RecordRelease(num_pages, released); - return released; -} +bool StaticForwarder::Ensure(Range r) { return tc_globals.pagemap().Ensure(r); } -static double BytesToMiB(size_t bytes) { - const double MiB = 1048576.0; - return bytes / MiB; +void StaticForwarder::Set(PageId page, Span* span) { + tc_globals.pagemap().Set(page, span); } -static void BreakdownStats(Printer *out, const BackingStats &s, - const char *label) { - out->printf("%s %6.1f MiB used, %6.1f MiB free, %6.1f MiB unmapped\n", label, - BytesToMiB(s.system_bytes - s.free_bytes - s.unmapped_bytes), - BytesToMiB(s.free_bytes), BytesToMiB(s.unmapped_bytes)); +void StaticForwarder::SetHugepage(HugePage p, void* pt) { + tc_globals.pagemap().SetHugepage(p.first_page(), pt); } -static void BreakdownStatsInPbtxt(PbtxtRegion *hpaa, const BackingStats &s, - const char *key) { - auto usage = hpaa->CreateSubRegion(key); - usage.PrintI64("used", s.system_bytes - s.free_bytes - s.unmapped_bytes); - usage.PrintI64("free", s.free_bytes); - usage.PrintI64("unmapped", s.unmapped_bytes); +void StaticForwarder::ShrinkToUsageLimit(Length n) { + tc_globals.page_allocator().ShrinkToUsageLimit(n); } -// public -void HugePageAwareAllocator::Print(Printer *out) { Print(out, true); } - -void HugePageAwareAllocator::Print(Printer *out, bool everything) { - SmallSpanStats small; - LargeSpanStats large; - BackingStats bstats; - PageAgeHistograms ages(absl::base_internal::CycleClock::Now()); - absl::base_internal::SpinLockHolder h(&pageheap_lock); - bstats = stats(); - GetSpanStats(&small, &large, &ages); - PrintStats("HugePageAware", out, bstats, small, large, everything); - out->printf( - "\nHuge page aware allocator components:\n" - "------------------------------------------------\n"); - out->printf("HugePageAware: breakdown of used / free / unmapped space:\n"); - - auto fstats = filler_.stats(); - BreakdownStats(out, fstats, "HugePageAware: filler"); - - auto rstats = regions_.stats(); - BreakdownStats(out, rstats, "HugePageAware: region"); - - auto cstats = cache_.stats(); - // Everything in the filler came from the cache - - // adjust the totals so we see the amount used by the mutator. - cstats.system_bytes -= fstats.system_bytes; - BreakdownStats(out, cstats, "HugePageAware: cache "); - - auto astats = alloc_.stats(); - // Everything in *all* components came from here - - // so again adjust the totals. - astats.system_bytes -= (fstats + rstats + cstats).system_bytes; - BreakdownStats(out, astats, "HugePageAware: alloc "); - out->printf("\n"); - - out->printf("HugePageAware: filler donations %zu\n", - donated_huge_pages_.raw_num()); - - // Component debug output - // Filler is by far the most important; print (some) of it - // unconditionally. - filler_.Print(out, everything); - out->printf("\n"); - if (everything) { - regions_.Print(out); - out->printf("\n"); - cache_.Print(out); - out->printf("\n"); - alloc_.Print(out); - out->printf("\n"); - - // Use statistics - info_.Print(out); - - // and age tracking. - ages.Print("HugePageAware", out); - } - - out->printf("PARAMETER hpaa_subrelease %d\n", - Parameters::hpaa_subrelease() ? 1 : 0); +Span* StaticForwarder::NewSpan(Range r) { + // TODO(b/134687001): Delete this when span_allocator moves. + return Span::New(r); } -void HugePageAwareAllocator::PrintInPbtxt(PbtxtRegion *region) { - SmallSpanStats small; - LargeSpanStats large; - PageAgeHistograms ages(absl::base_internal::CycleClock::Now()); - absl::base_internal::SpinLockHolder h(&pageheap_lock); - GetSpanStats(&small, &large, &ages); - PrintStatsInPbtxt(region, small, large, ages); - { - auto hpaa = region->CreateSubRegion("huge_page_allocator"); - hpaa.PrintBool("using_hpaa", true); - hpaa.PrintBool("using_hpaa_subrelease", Parameters::hpaa_subrelease()); - - // Fill HPAA Usage - auto fstats = filler_.stats(); - BreakdownStatsInPbtxt(&hpaa, fstats, "filler_usage"); - - auto rstats = regions_.stats(); - BreakdownStatsInPbtxt(&hpaa, rstats, "region_usage"); +void StaticForwarder::DeleteSpan(Span* span) { Span::Delete(span); } - auto cstats = cache_.stats(); - // Everything in the filler came from the cache - - // adjust the totals so we see the amount used by the mutator. - cstats.system_bytes -= fstats.system_bytes; - BreakdownStatsInPbtxt(&hpaa, cstats, "cache_usage"); - - auto astats = alloc_.stats(); - // Everything in *all* components came from here - - // so again adjust the totals. - astats.system_bytes -= (fstats + rstats + cstats).system_bytes; - BreakdownStatsInPbtxt(&hpaa, astats, "alloc_usage"); - - filler_.PrintInPbtxt(&hpaa); - regions_.PrintInPbtxt(&hpaa); - cache_.PrintInPbtxt(&hpaa); - alloc_.PrintInPbtxt(&hpaa); - - // Use statistics - info_.PrintInPbtxt(&hpaa, "hpaa_stat"); - - hpaa.PrintI64("filler_donated_huge_pages", donated_huge_pages_.raw_num()); - } -} - -template -void *HugePageAwareAllocator::AllocAndReport(size_t bytes, size_t *actual, - size_t align) { - void *p = SystemAlloc(bytes, actual, align, tag); - if (p == nullptr) return p; - const PageId page = PageIdContaining(p); - const Length page_len = BytesToLengthFloor(*actual); - Static::pagemap().Ensure(page, page_len); - return p; +AddressRange StaticForwarder::AllocatePages(size_t bytes, size_t align, + MemoryTag tag) { + return tc_globals.system_allocator().Allocate(bytes, align, tag); } -void *HugePageAwareAllocator::MetaDataAlloc(size_t bytes) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { - return Static::arena().Alloc(bytes); +void StaticForwarder::Back(Range r) { + tc_globals.system_allocator().Back(r.start_addr(), r.in_bytes()); } -Length HugePageAwareAllocator::ReleaseAtLeastNPagesBreakingHugepages(Length n) { - // We desparately need to release memory, and are willing to - // compromise on hugepage usage. That means releasing from the filler. - return filler_.ReleasePages(n, absl::ZeroDuration(), /*hit_limit*/ true); +bool StaticForwarder::ReleasePages(Range r) { + return tc_globals.system_allocator().Release(r.start_addr(), r.in_bytes()); } -void HugePageAwareAllocator::UnbackWithoutLock(void *start, size_t length) { - pageheap_lock.Unlock(); - SystemRelease(start, length); - pageheap_lock.Lock(); -} +} // namespace huge_page_allocator_internal } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator.h b/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator.h index c36a1e515e15..ea2bb02d9dcf 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator.h +++ b/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,18 +18,29 @@ #include +#include "absl/base/attributes.h" +#include "absl/base/internal/cycleclock.h" +#include "absl/base/optimization.h" #include "absl/base/thread_annotations.h" +#include "absl/time/time.h" #include "tcmalloc/arena.h" +#include "tcmalloc/central_freelist.h" #include "tcmalloc/common.h" #include "tcmalloc/huge_allocator.h" #include "tcmalloc/huge_cache.h" #include "tcmalloc/huge_page_filler.h" +#include "tcmalloc/huge_page_subrelease.h" #include "tcmalloc/huge_pages.h" #include "tcmalloc/huge_region.h" +#include "tcmalloc/internal/allocation_guard.h" #include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/prefetch.h" +#include "tcmalloc/metadata_allocator.h" +#include "tcmalloc/metadata_object_allocator.h" #include "tcmalloc/page_allocator_interface.h" -#include "tcmalloc/page_heap_allocator.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/parameters.h" #include "tcmalloc/span.h" #include "tcmalloc/stats.h" #include "tcmalloc/system-alloc.h" @@ -36,31 +48,130 @@ GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { +namespace huge_page_allocator_internal { bool decide_subrelease(); -// An implementation of the PageAllocator interface that is hugepage-efficent. +HugeRegionUsageOption huge_region_option(); +bool use_huge_region_more_often(); + +class StaticForwarder { + public: + // Runtime parameters. This can change between calls. + static absl::Duration filler_skip_subrelease_short_interval() { + return Parameters::filler_skip_subrelease_short_interval(); + } + static absl::Duration filler_skip_subrelease_long_interval() { + return Parameters::filler_skip_subrelease_long_interval(); + } + static absl::Duration cache_demand_release_short_interval() { + return Parameters::cache_demand_release_short_interval(); + } + static absl::Duration cache_demand_release_long_interval() { + return Parameters::cache_demand_release_long_interval(); + } + + static bool release_partial_alloc_pages() { + return Parameters::release_partial_alloc_pages(); + } + + static bool huge_region_demand_based_release() { + return Parameters::huge_region_demand_based_release(); + } + + static bool huge_cache_demand_based_release() { + return Parameters::huge_cache_demand_based_release(); + } + + static bool hpaa_subrelease() { return Parameters::hpaa_subrelease(); } + + // Arena state. + static Arena& arena(); + + // PageAllocator state. + + // Check page heap memory limit. `n` indicates the size of the allocation + // currently being made, which will not be included in the sampled memory heap + // for realized fragmentation estimation. + static void ShrinkToUsageLimit(Length n) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); + + // PageMap state. + static void* GetHugepage(HugePage p); + [[nodiscard]] static bool Ensure(Range r) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); + static void Set(PageId page, Span* span); + static void SetHugepage(HugePage p, void* pt); + + // SpanAllocator state. + static Span* NewSpan(Range r) +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) +#else + ABSL_LOCKS_EXCLUDED(pageheap_lock) +#endif // TCMALLOC_INTERNAL_LEGACY_LOCKING + ABSL_ATTRIBUTE_RETURNS_NONNULL; + static void DeleteSpan(Span* span) +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) +#endif // TCMALLOC_INTERNAL_LEGACY_LOCKING + ABSL_ATTRIBUTE_NONNULL(); + + // SystemAlloc state. + [[nodiscard]] static AddressRange AllocatePages(size_t bytes, size_t align, + MemoryTag tag); + static void Back(Range r); + [[nodiscard]] static bool ReleasePages(Range r); +}; + +struct HugePageAwareAllocatorOptions { + MemoryTag tag; + HugeRegionUsageOption use_huge_region_more_often = huge_region_option(); + HugePageFillerDenseTrackerType dense_tracker_type = + Parameters::dense_trackers_sorted_on_spans_allocated() + ? HugePageFillerDenseTrackerType::kSpansAllocated + : HugePageFillerDenseTrackerType::kLongestFreeRangeAndChunks; + absl::Duration huge_cache_time = Parameters::huge_cache_release_time(); +}; + +// An implementation of the PageAllocator interface that is hugepage-efficient. // Attempts to pack allocations into full hugepages wherever possible, // and aggressively returns empty ones to the system. +// +// Some notes: locking discipline here is a bit funny, because +// we want to *not* hold the pageheap lock while backing memory. +// +// We have here a collection of slightly different allocators each +// optimized for slightly different purposes. This file has two main purposes: +// - pick the right one for a given allocation +// - provide enough data to figure out what we picked last time! + +template class HugePageAwareAllocator final : public PageAllocatorInterface { public: - explicit HugePageAwareAllocator(MemoryTag tag); + explicit HugePageAwareAllocator(const HugePageAwareAllocatorOptions& options); ~HugePageAwareAllocator() override = default; // Allocate a run of "n" pages. Returns zero if out of memory. // Caller should not pass "n == 0" -- instead, n should have // been rounded up already. - Span* New(Length n) ABSL_LOCKS_EXCLUDED(pageheap_lock) override; + Span* New(Length n, SpanAllocInfo span_alloc_info) + ABSL_LOCKS_EXCLUDED(pageheap_lock) override; // As New, but the returned span is aligned to a -page boundary. // must be a power of two. - Span* NewAligned(Length n, Length align) + Span* NewAligned(Length n, Length align, SpanAllocInfo span_alloc_info) ABSL_LOCKS_EXCLUDED(pageheap_lock) override; // Delete the span "[p, p+n-1]". // REQUIRES: span was returned by earlier call to New() and // has not yet been deleted. +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING void Delete(Span* span) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) override; +#endif // TCMALLOC_INTERNAL_LEGACY_LOCKING + + void Delete(AllocationState s) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) override; BackingStats stats() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) override; @@ -77,52 +188,164 @@ class HugePageAwareAllocator final : public PageAllocatorInterface { // may also be larger than num_pages since page_heap might decide to // release one large range instead of fragmenting it into two // smaller released and unreleased ranges. - Length ReleaseAtLeastNPages(Length num_pages) + Length ReleaseAtLeastNPages(Length num_pages, PageReleaseReason reason) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) override; - Length ReleaseAtLeastNPagesBreakingHugepages(Length n) + Length ReleaseAtLeastNPagesBreakingHugepages(Length n, + PageReleaseReason reason) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); + PageReleaseStats GetReleaseStats() const + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) override; + // Prints stats about the page heap to *out. - void Print(Printer* out) ABSL_LOCKS_EXCLUDED(pageheap_lock) override; + void Print(Printer& out) ABSL_LOCKS_EXCLUDED(pageheap_lock) override; // Print stats to *out, excluding long/likely uninteresting things // unless is true. - void Print(Printer* out, bool everything) ABSL_LOCKS_EXCLUDED(pageheap_lock); + void Print(Printer& out, bool everything) ABSL_LOCKS_EXCLUDED(pageheap_lock); - void PrintInPbtxt(PbtxtRegion* region) + void PrintInPbtxt(PbtxtRegion& region) ABSL_LOCKS_EXCLUDED(pageheap_lock) override; + BackingStats FillerStats() const + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { + return filler_.stats(); + } + + BackingStats RegionsStats() const + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { + return regions_.stats(); + } + + BackingStats CacheStats() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { + return cache_.stats(); + } + HugeLength DonatedHugePages() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { return donated_huge_pages_; } + HugeLength RegionsFreeBacked() const + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { + return regions_.free_backed(); + } + + // Number of pages that have been retained on huge pages by donations that did + // not reassemble by the time the larger allocation was deallocated. + Length AbandonedPages() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { + return abandoned_pages_; + } + const HugeCache* cache() const { return &cache_; } + const HugeRegionSet& region() const + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { + return regions_; + }; + + // IsValidSizeClass verifies size class parameters from the HPAA perspective. + static bool IsValidSizeClass(size_t size, size_t pages); + + Forwarder& forwarder() { return forwarder_; } + private: - typedef HugePageFiller> FillerType; - FillerType filler_; + static constexpr Length kSmallAllocPages = kPagesPerHugePage / 2; - // Calls SystemRelease, but with dropping of pageheap_lock around the call. - static void UnbackWithoutLock(void* start, size_t length) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); + class Unback final : public MemoryModifyFunction { + public: + explicit Unback(HugePageAwareAllocator& hpaa ABSL_ATTRIBUTE_LIFETIME_BOUND) + : hpaa_(hpaa) {} + + [[nodiscard]] bool operator()(Range r) override + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { +#ifndef NDEBUG + pageheap_lock.AssertHeld(); +#endif // NDEBUG + return hpaa_.forwarder_.ReleasePages(r); + } + + public: + HugePageAwareAllocator& hpaa_; + }; + + class UnbackWithoutLock final : public MemoryModifyFunction { + public: + explicit UnbackWithoutLock( + HugePageAwareAllocator& hpaa ABSL_ATTRIBUTE_LIFETIME_BOUND) + : hpaa_(hpaa) {} + + [[nodiscard]] bool operator()(Range r) override + ABSL_NO_THREAD_SAFETY_ANALYSIS { +#ifndef NDEBUG + pageheap_lock.AssertHeld(); +#endif // NDEBUG + pageheap_lock.Unlock(); + bool ret = hpaa_.forwarder_.ReleasePages(r); + pageheap_lock.Lock(); + return ret; + } + + public: + HugePageAwareAllocator& hpaa_; + }; + + ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS Forwarder forwarder_; + + Unback unback_ ABSL_GUARDED_BY(pageheap_lock); + UnbackWithoutLock unback_without_lock_ ABSL_GUARDED_BY(pageheap_lock); + + typedef HugePageFiller FillerType; + FillerType filler_ ABSL_GUARDED_BY(pageheap_lock); + + class VirtualMemoryAllocator final : public VirtualAllocator { + public: + explicit VirtualMemoryAllocator( + HugePageAwareAllocator& hpaa ABSL_ATTRIBUTE_LIFETIME_BOUND) + : hpaa_(hpaa) {} + + [[nodiscard]] AddressRange operator()(size_t bytes, size_t align) override + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { + return hpaa_.AllocAndReport(bytes, align); + } + + private: + HugePageAwareAllocator& hpaa_; + }; - HugeRegionSet regions_; + class ArenaMetadataAllocator final : public MetadataAllocator { + public: + explicit ArenaMetadataAllocator( + HugePageAwareAllocator& hpaa ABSL_ATTRIBUTE_LIFETIME_BOUND) + : hpaa_(hpaa) {} - PageHeapAllocator tracker_allocator_; - PageHeapAllocator region_allocator_; + [[nodiscard]] void* operator()(size_t bytes) override { + return hpaa_.forwarder_.arena().Alloc(bytes); + } + + public: + HugePageAwareAllocator& hpaa_; + }; + + HugeRegionSet regions_ ABSL_GUARDED_BY(pageheap_lock); + + MetadataObjectAllocator tracker_allocator_ + ABSL_GUARDED_BY(pageheap_lock); + MetadataObjectAllocator region_allocator_ + ABSL_GUARDED_BY(pageheap_lock); FillerType::Tracker* GetTracker(HugePage p); void SetTracker(HugePage p, FillerType::Tracker* pt); - template - static void* AllocAndReport(size_t bytes, size_t* actual, size_t align) + AddressRange AllocAndReport(size_t bytes, size_t align) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); - static void* MetaDataAlloc(size_t bytes); - HugeAllocator alloc_; - HugeCache cache_; + + VirtualMemoryAllocator vm_allocator_ ABSL_GUARDED_BY(pageheap_lock); + ArenaMetadataAllocator metadata_allocator_ ABSL_GUARDED_BY(pageheap_lock); + HugeAllocator alloc_ ABSL_GUARDED_BY(pageheap_lock); + HugeCache cache_ ABSL_GUARDED_BY(pageheap_lock); // donated_huge_pages_ measures the number of huge pages contributed to the // filler from left overs of large huge page allocations. When the large @@ -130,30 +353,50 @@ class HugePageAwareAllocator final : public PageAllocatorInterface { // fully reassemble the address range (that is, the partial hugepage did not // get stuck in the filler). HugeLength donated_huge_pages_ ABSL_GUARDED_BY(pageheap_lock); + // abandoned_pages_ tracks the number of pages contributed to the filler after + // a donating allocation is deallocated but the entire huge page has not been + // reassembled. + Length abandoned_pages_ ABSL_GUARDED_BY(pageheap_lock); - void GetSpanStats(SmallSpanStats* small, LargeSpanStats* large, - PageAgeHistograms* ages); + void GetSpanStats(SmallSpanStats* small, LargeSpanStats* large) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); - PageId RefillFiller(Length n, bool* from_released) + PageId RefillFiller(Length n, SpanAllocInfo span_alloc_info, + bool* from_released) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); // Allocate the first from p, and contribute the rest to the filler. If // "donated" is true, the contribution will be marked as coming from the // tail of a multi-hugepage alloc. Returns the allocated section. - PageId AllocAndContribute(HugePage p, Length n, bool donated) + PageId AllocAndContribute(HugePage p, Length n, SpanAllocInfo span_alloc_info, + bool donated) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); // Helpers for New(). - Span* LockAndAlloc(Length n, bool* from_released); +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + using FinalizeType = Span*; +#else // !TCMALLOC_INTERNAL_LEGACY_LOCKING + struct FinalizeType { + Range r; + bool donated = false; + }; +#endif // !TCMALLOC_INTERNAL_LEGACY_LOCKING + + FinalizeType LockAndAlloc(Length n, SpanAllocInfo span_alloc_info, + bool* from_released); - Span* AllocSmall(Length n, bool* from_released) + FinalizeType AllocSmall(Length n, SpanAllocInfo span_alloc_info, + bool* from_released) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); - Span* AllocLarge(Length n, bool* from_released) + FinalizeType AllocLarge(Length n, SpanAllocInfo span_alloc_info, + bool* from_released) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); - Span* AllocEnormous(Length n, bool* from_released) + FinalizeType AllocEnormous(Length n, SpanAllocInfo span_alloc_info, + bool* from_released) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); - Span* AllocRawHugepages(Length n, bool* from_released) + FinalizeType AllocRawHugepages(Length n, SpanAllocInfo span_alloc_info, + bool* from_released) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); bool AddRegion() ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); @@ -161,13 +404,808 @@ class HugePageAwareAllocator final : public PageAllocatorInterface { void ReleaseHugepage(FillerType::Tracker* pt) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); // Return an allocation from a single hugepage. - void DeleteFromHugepage(FillerType::Tracker* pt, PageId p, Length n) + void DeleteFromHugepage(FillerType::Tracker* pt, Range r, bool might_abandon) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); // Finish an allocation request - give it a span and mark it in the pagemap. - Span* Finalize(Length n, PageId page); + FinalizeType Finalize(Range r); + + Span* Spanify(FinalizeType f); + + // Whether this HPAA should use subrelease. This delegates to the appropriate + // parameter depending whether this is for the cold heap or another heap. + bool hpaa_subrelease() const; }; +template +inline HugePageAwareAllocator::HugePageAwareAllocator( + const HugePageAwareAllocatorOptions& options) + : PageAllocatorInterface("HugePageAware", options.tag), + unback_(*this), + unback_without_lock_(*this), + filler_(options.dense_tracker_type, unback_, unback_without_lock_), + regions_(options.use_huge_region_more_often), + tracker_allocator_(forwarder_.arena()), + region_allocator_(forwarder_.arena()), + vm_allocator_(*this), + metadata_allocator_(*this), + alloc_(vm_allocator_, metadata_allocator_), + cache_(HugeCache{&alloc_, metadata_allocator_, unback_without_lock_, + options.huge_cache_time}) {} + +template +inline HugePageAwareAllocator::FillerType::Tracker* +HugePageAwareAllocator::GetTracker(HugePage p) { + void* v = forwarder_.GetHugepage(p); + FillerType::Tracker* pt = reinterpret_cast(v); + TC_ASSERT(pt == nullptr || pt->location() == p); + return pt; +} + +template +inline void HugePageAwareAllocator::SetTracker( + HugePage p, HugePageAwareAllocator::FillerType::Tracker* pt) { + forwarder_.SetHugepage(p, pt); +} + +template +inline PageId HugePageAwareAllocator::AllocAndContribute( + HugePage p, Length n, SpanAllocInfo span_alloc_info, bool donated) { + TC_CHECK_NE(p.start_addr(), nullptr); + FillerType::Tracker* pt = tracker_allocator_.New( + p, donated, absl::base_internal::CycleClock::Now()); + TC_ASSERT_GE(pt->longest_free_range(), n); + TC_ASSERT_EQ(pt->was_donated(), donated); + // if the page was donated, we track its size so that we can potentially + // measure it in abandoned_count_ once this large allocation gets deallocated. + if (pt->was_donated()) { + pt->set_abandoned_count(n); + } + PageId page = pt->Get(n).page; + TC_ASSERT_EQ(page, p.first_page()); + SetTracker(p, pt); + filler_.Contribute(pt, donated, span_alloc_info); + TC_ASSERT_EQ(pt->was_donated(), donated); + return page; +} + +template +inline PageId HugePageAwareAllocator::RefillFiller( + Length n, SpanAllocInfo span_alloc_info, bool* from_released) { + HugeRange r = cache_.Get(NHugePages(1), from_released); + if (!r.valid()) return PageId{0}; + // This is duplicate to Finalize, but if we need to break up + // hugepages to get to our usage limit it would be very bad to break + // up what's left of r after we allocate from there--while r is + // mostly empty, clearly what's left in the filler is too fragmented + // to be very useful, and we would rather release those + // pages. Otherwise, we're nearly guaranteed to release r (if n + // isn't very large), and the next allocation will just repeat this + // process. + forwarder_.ShrinkToUsageLimit(n); + return AllocAndContribute(r.start(), n, span_alloc_info, /*donated=*/false); +} + +template +inline typename HugePageAwareAllocator::FinalizeType +HugePageAwareAllocator::Finalize(Range r) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { + TC_ASSERT_NE(r.p, PageId{0}); + info_.RecordAlloc(r); + forwarder_.ShrinkToUsageLimit(r.n); +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + // TODO(b/175334169): Lift Span creation out of LockAndAlloc. + Span* ret = forwarder_.NewSpan(r); + forwarder_.Set(r.p, ret); + TC_ASSERT(!ret->sampled()); + return ret; +#else + return {r, false}; +#endif +} + +// For anything <= half a huge page, we will unconditionally use the filler +// to pack it into a single page. If we need another page, that's fine. +template +inline typename HugePageAwareAllocator::FinalizeType +HugePageAwareAllocator::AllocSmall(Length n, + SpanAllocInfo span_alloc_info, + bool* from_released) { + auto [pt, page, released] = filler_.TryGet(n, span_alloc_info); + *from_released = released; + if (ABSL_PREDICT_TRUE(pt != nullptr)) { + return Finalize(Range(page, n)); + } + + page = RefillFiller(n, span_alloc_info, from_released); + if (ABSL_PREDICT_FALSE(page == PageId{0})) { + return {}; + } + return Finalize(Range(page, n)); +} + +template +inline typename HugePageAwareAllocator::FinalizeType +HugePageAwareAllocator::AllocLarge(Length n, + SpanAllocInfo span_alloc_info, + bool* from_released) { + // If it's an exact page multiple, just pull it from pages directly. + HugeLength hl = HLFromPages(n); + if (hl.in_pages() == n) { + return AllocRawHugepages(n, span_alloc_info, from_released); + } + + PageId page; + // If we fit in a single hugepage, try the Filler.p. + if (n < kPagesPerHugePage) { + auto [pt, page, released] = filler_.TryGet(n, span_alloc_info); + *from_released = released; + if (ABSL_PREDICT_TRUE(pt != nullptr)) { + return Finalize(Range(page, n)); + } + } + + // If we're using regions in this binary (see below comment), is + // there currently available space there? + if (regions_.MaybeGet(n, &page, from_released)) { + return Finalize(Range(page, n)); + } + + // We have two choices here: allocate a new region or go to + // hugepages directly (hoping that slack will be filled by small + // allocation.) The second strategy is preferable, as it's + // typically faster and usually more space efficient, but it's sometimes + // catastrophic. + // + // See https://github.com/google/tcmalloc/tree/master/docs/regions-are-not-optional.md + // + // So test directly if we're in the bad case--almost no binaries are. + // If not, just fall back to direct allocation (and hope we do hit that case!) + const Length slack = info_.slack(); + const Length donated = + regions_.UseHugeRegionMoreOften() ? abandoned_pages_ + slack : slack; + // Don't bother at all until the binary is reasonably sized. + if (donated < HLFromBytes(64 * 1024 * 1024).in_pages()) { + return AllocRawHugepages(n, span_alloc_info, from_released); + } + + // In the vast majority of binaries, we have many small allocations which + // will nicely fill slack. (Fleetwide, the average ratio is 15:1; only + // a handful of binaries fall below 1:1.) + // + // If we enable an experiment that tries to use huge regions more frequently, + // we skip the check. + const Length small = info_.small(); + if (slack < small && !regions_.UseHugeRegionMoreOften()) { + return AllocRawHugepages(n, span_alloc_info, from_released); + } + + // We couldn't allocate a new region. They're oversized, so maybe we'd get + // lucky with a smaller request? + if (!AddRegion()) { + return AllocRawHugepages(n, span_alloc_info, from_released); + } + + TC_CHECK(regions_.MaybeGet(n, &page, from_released)); + return Finalize(Range(page, n)); +} + +template +inline typename HugePageAwareAllocator::FinalizeType +HugePageAwareAllocator::AllocEnormous(Length n, + SpanAllocInfo span_alloc_info, + bool* from_released) { + return AllocRawHugepages(n, span_alloc_info, from_released); +} + +template +inline typename HugePageAwareAllocator::FinalizeType +HugePageAwareAllocator::AllocRawHugepages( + Length n, SpanAllocInfo span_alloc_info, bool* from_released) { + HugeLength hl = HLFromPages(n); + + HugeRange r = cache_.Get(hl, from_released); + if (!r.valid()) return {}; + + // We now have a huge page range that covers our request. There + // might be some slack in it if n isn't a multiple of + // kPagesPerHugePage. Add the hugepage with slack to the filler, + // pretending the non-slack portion is a smaller allocation. + Length total = hl.in_pages(); + Length slack = total - n; + HugePage first = r.start(); + SetTracker(first, nullptr); + HugePage last = first + r.len() - NHugePages(1); + if (slack == Length(0)) { + SetTracker(last, nullptr); + return Finalize(Range(r.start().first_page(), total)); + } + + ++donated_huge_pages_; + + Length here = kPagesPerHugePage - slack; + TC_ASSERT_GT(here, Length(0)); + AllocAndContribute(last, here, span_alloc_info, /*donated=*/true); + auto span = Finalize(Range(r.start().first_page(), n)); +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + span->set_donated(/*value=*/true); + return span; +#else + span.donated = true; + return span; +#endif +} + +// public +template +inline Span* HugePageAwareAllocator::New( + Length n, SpanAllocInfo span_alloc_info) { + TC_CHECK_GT(n, Length(0)); + bool from_released; + Span* s = Spanify(LockAndAlloc(n, span_alloc_info, &from_released)); + if (s) { + // Prefetch for writing, as we anticipate using the memory soon. + PrefetchW(s->start_address()); + if (from_released) { + forwarder_.Back(Range(s->first_page(), s->num_pages())); + } + } + TC_ASSERT(!s || GetMemoryTag(s->start_address()) == tag_); + return s; +} + +template +inline typename HugePageAwareAllocator::FinalizeType +HugePageAwareAllocator::LockAndAlloc(Length n, + SpanAllocInfo span_alloc_info, + bool* from_released) { + PageHeapSpinLockHolder l; + // Our policy depends on size. For small things, we will pack them + // into single hugepages. + if (n <= kSmallAllocPages) { + return AllocSmall(n, span_alloc_info, from_released); + } + + // For anything too big for the filler, we use either a direct hugepage + // allocation, or possibly the regions if we are worried about slack. + if (n <= HugeRegion::size().in_pages()) { + return AllocLarge(n, span_alloc_info, from_released); + } + + // In the worst case, we just fall back to directly allocating a run + // of hugepages. + return AllocEnormous(n, span_alloc_info, from_released); +} + +// public +template +inline Span* HugePageAwareAllocator::NewAligned( + Length n, Length align, SpanAllocInfo span_alloc_info) { + if (align <= Length(1)) { + return New(n, span_alloc_info); + } + + // we can do better than this, but... + // TODO(b/134690769): support higher align. + TC_CHECK_LE(align, kPagesPerHugePage); + bool from_released; + FinalizeType f; + { + PageHeapSpinLockHolder l; + f = AllocRawHugepages(n, span_alloc_info, &from_released); + } + Span* s = Spanify(f); + if (s && from_released) { + forwarder_.Back(Range(s->first_page(), s->num_pages())); + } + + TC_ASSERT(!s || GetMemoryTag(s->start_address()) == tag_); + return s; +} + +template +inline Span* HugePageAwareAllocator::Spanify(FinalizeType f) { +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + return f; +#else + if (ABSL_PREDICT_FALSE(f.r.p == PageId{0})) { + return nullptr; + } + + Span* s = forwarder_.NewSpan(f.r); + forwarder_.Set(f.r.p, s); + TC_ASSERT(!s->sampled()); + s->set_donated(f.donated); + return s; +#endif +} + +template +inline void HugePageAwareAllocator::DeleteFromHugepage( + FillerType::Tracker* pt, Range r, bool might_abandon) { + if (ABSL_PREDICT_TRUE(filler_.Put(pt, r) == nullptr)) { + // If this allocation had resulted in a donation to the filler, we record + // these pages as abandoned. + if (ABSL_PREDICT_FALSE(might_abandon)) { + TC_ASSERT(pt->was_donated()); + abandoned_pages_ += pt->abandoned_count(); + pt->set_abandoned(true); + } + return; + } + if (pt->was_donated()) { + --donated_huge_pages_; + if (pt->abandoned()) { + abandoned_pages_ -= pt->abandoned_count(); + pt->set_abandoned(false); + } + } else { + TC_ASSERT_EQ(pt->abandoned_count(), Length(0)); + } + ReleaseHugepage(pt); +} + +template +inline bool HugePageAwareAllocator::AddRegion() { + HugeRange r = alloc_.Get(HugeRegion::size()); + if (!r.valid()) return false; + HugeRegion* region = region_allocator_.New(r, unback_); + regions_.Contribute(region); + return true; +} + +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING +template +inline void HugePageAwareAllocator::Delete(Span* span) { + TC_ASSERT(!span || GetMemoryTag(span->start_address()) == tag_); + PageId p = span->first_page(); + Length n = span->num_pages(); + + bool donated = span->donated(); + forwarder_.DeleteSpan(span); + + Delete(AllocationState{Range{p, n}, donated}); +} +#endif // TCMALLOC_INTERNAL_LEGACY_LOCKING + +template +inline void HugePageAwareAllocator::Delete(AllocationState s) { + const PageId p = s.r.p; + const HugePage hp = HugePageContaining(p); + const Length n = s.r.n; + info_.RecordFree(Range(p, n)); + + // Clear the descriptor of the page so a second pass through the same page + // could trigger the check on `span != nullptr` in do_free_pages. + forwarder_.Set(p, nullptr); + + const bool might_abandon = s.donated; + + // The tricky part, as with so many allocators: where did we come from? + // There are several possibilities. + FillerType::Tracker* pt = GetTracker(hp); + // a) We got packed by the filler onto a single hugepage - return our + // allocation to that hugepage in the filler. + if (ABSL_PREDICT_TRUE(pt != nullptr)) { + TC_ASSERT_EQ(hp, HugePageContaining(p + n - Length(1))); + DeleteFromHugepage(pt, Range(p, n), might_abandon); + return; + } + + // b) We got put into a region, possibly crossing hugepages - + // return our allocation to the region. + if (regions_.MaybePut(Range(p, n))) return; + + // c) we came straight from the HugeCache - return straight there. (We + // might have had slack put into the filler - if so, return that virtual + // allocation to the filler too!) + TC_ASSERT_GE(n, kPagesPerHugePage); + HugeLength hl = HLFromPages(n); + HugePage last = hp + hl - NHugePages(1); + Length slack = hl.in_pages() - n; + if (slack == Length(0)) { + TC_ASSERT_EQ(GetTracker(last), nullptr); + } else { + pt = GetTracker(last); + TC_CHECK_NE(pt, nullptr); + TC_ASSERT(pt->was_donated()); + // We put the slack into the filler (see AllocEnormous.) + // Handle this page separately as a virtual allocation + // onto the last hugepage. + PageId virt = last.first_page(); + Length virt_len = kPagesPerHugePage - slack; + // We may have used the slack, which would prevent us from returning + // the entire range now. If filler returned a Tracker, we are fully empty. + if (filler_.Put(pt, Range(virt, virt_len)) == nullptr) { + // Last page isn't empty -- pretend the range was shorter. + --hl; + + // Note that we abandoned virt_len pages with pt. These can be reused for + // other allocations, but this can contribute to excessive slack in the + // filler. + abandoned_pages_ += pt->abandoned_count(); + pt->set_abandoned(true); + } else { + // Last page was empty - but if we sub-released it, we still + // have to split it off and release it independently.) + // + // We were able to reclaim the donated slack. + --donated_huge_pages_; + TC_ASSERT(!pt->abandoned()); + + if (pt->released()) { + --hl; + ReleaseHugepage(pt); + } else { + // Get rid of the tracker *object*, but not the *hugepage* (which is + // still part of our range.) + SetTracker(pt->location(), nullptr); + tracker_allocator_.Delete(pt); + } + } + } + // We release in the background task instead (i.e., ReleaseAtLeastNPages()) if + // the demand-based release is enabled. + cache_.Release( + {hp, hl}, + /*demand_based_unback=*/forwarder_.huge_cache_demand_based_release()); +} + +template +inline void HugePageAwareAllocator::ReleaseHugepage( + FillerType::Tracker* pt) { + TC_ASSERT_EQ(pt->used_pages(), Length(0)); + HugeRange r = {pt->location(), NHugePages(1)}; + SetTracker(pt->location(), nullptr); + + if (pt->released()) { + cache_.ReleaseUnbacked(r); + } else { + // We release in the background task instead (i.e., ReleaseAtLeastNPages()) + // if the demand-based release is enabled. + cache_.Release( + r, + /*demand_based_unback=*/forwarder_.huge_cache_demand_based_release()); + } + + tracker_allocator_.Delete(pt); +} + +// public +template +inline BackingStats HugePageAwareAllocator::stats() const { + BackingStats stats = alloc_.stats(); + const auto actual_system = stats.system_bytes; + stats += cache_.stats(); + stats += filler_.stats(); + stats += regions_.stats(); + // the "system" (total managed) byte count is wildly double counted, + // since it all comes from HugeAllocator but is then managed by + // cache/regions/filler. Adjust for that. + stats.system_bytes = actual_system; + return stats; +} + +// public +template +inline void HugePageAwareAllocator::GetSmallSpanStats( + SmallSpanStats* result) { + GetSpanStats(result, nullptr); +} + +// public +template +inline void HugePageAwareAllocator::GetLargeSpanStats( + LargeSpanStats* result) { + GetSpanStats(nullptr, result); +} + +template +inline void HugePageAwareAllocator::GetSpanStats( + SmallSpanStats* small, LargeSpanStats* large) { + if (small != nullptr) { + *small = SmallSpanStats(); + } + if (large != nullptr) { + *large = LargeSpanStats(); + } + + alloc_.AddSpanStats(small, large); + filler_.AddSpanStats(small, large); + regions_.AddSpanStats(small, large); + cache_.AddSpanStats(small, large); +} + +// public +template +inline Length HugePageAwareAllocator::ReleaseAtLeastNPages( + Length num_pages, PageReleaseReason reason) { + // We use demand-based release for the background release but not for the + // other cases (e.g., limit hit). We achieve this by configuring the intervals + // and hit_limit accordingly. + SkipSubreleaseIntervals cache_release_intervals; + if (reason == PageReleaseReason::kProcessBackgroundActions) { + cache_release_intervals.short_interval = + forwarder_.cache_demand_release_short_interval(); + cache_release_intervals.long_interval = + forwarder_.cache_demand_release_long_interval(); + } + bool hit_limit = (reason == PageReleaseReason::kSoftLimitExceeded || + reason == PageReleaseReason::kHardLimitExceeded); + Length released; + if (forwarder_.huge_cache_demand_based_release()) { + released += + cache_ + .ReleaseCachedPagesByDemand(HLFromPages(num_pages), + cache_release_intervals, hit_limit) + .in_pages(); + } else { + released += cache_.ReleaseCachedPages(HLFromPages(num_pages)).in_pages(); + } + + // Release all backed-but-free hugepages from HugeRegion. + // TODO(b/199203282): We release all the free hugepages from HugeRegions when + // the experiment is enabled. We can also explore releasing only a desired + // number of pages. + if (regions_.UseHugeRegionMoreOften()) { + if (forwarder_.huge_region_demand_based_release()) { + Length desired = released > num_pages ? Length(0) : num_pages - released; + released += regions_.ReleasePagesByPeakDemand( + desired, + SkipSubreleaseIntervals{ + .short_interval = + forwarder_.filler_skip_subrelease_short_interval(), + .long_interval = + forwarder_.filler_skip_subrelease_long_interval()}, + /*hit_limit*/ false); + } else { + released += regions_.ReleasePages(kFractionToReleaseFromRegion); + } + } + + // This is our long term plan but in current state will lead to insufficient + // THP coverage. It is however very useful to have the ability to turn this on + // for testing. + // TODO(b/134690769): make this work, remove the flag guard. + if (hpaa_subrelease()) { + if (released < num_pages) { + released += filler_.ReleasePages( + num_pages - released, + SkipSubreleaseIntervals{ + .short_interval = + forwarder_.filler_skip_subrelease_short_interval(), + .long_interval = + forwarder_.filler_skip_subrelease_long_interval()}, + forwarder_.release_partial_alloc_pages(), + /*hit_limit*/ false); + } + } + + info_.RecordRelease(num_pages, released, reason); + return released; +} + +inline static double BytesToMiB(size_t bytes) { + const double MiB = 1048576.0; + return bytes / MiB; +} + +inline static void BreakdownStats(Printer& out, const BackingStats& s, + const char* label) { + out.printf("%s %6.1f MiB used, %6.1f MiB free, %6.1f MiB unmapped\n", label, + BytesToMiB(s.system_bytes - s.free_bytes - s.unmapped_bytes), + BytesToMiB(s.free_bytes), BytesToMiB(s.unmapped_bytes)); +} + +inline static void BreakdownStatsInPbtxt(PbtxtRegion& hpaa, + const BackingStats& s, + const char* key) { + auto usage = hpaa.CreateSubRegion(key); + usage.PrintI64("used", s.system_bytes - s.free_bytes - s.unmapped_bytes); + usage.PrintI64("free", s.free_bytes); + usage.PrintI64("unmapped", s.unmapped_bytes); +} + +// public +template +inline void HugePageAwareAllocator::Print(Printer& out) { + Print(out, true); +} + +template +inline void HugePageAwareAllocator::Print(Printer& out, + bool everything) { + SmallSpanStats small; + LargeSpanStats large; + BackingStats bstats; + PageHeapSpinLockHolder l; + bstats = stats(); + GetSpanStats(&small, &large); + PrintStats("HugePageAware", out, bstats, small, large, everything); + out.printf( + "\nHuge page aware allocator components:\n" + "------------------------------------------------\n"); + out.printf("HugePageAware: breakdown of used / free / unmapped space:\n"); + + auto fstats = filler_.stats(); + BreakdownStats(out, fstats, "HugePageAware: filler "); + + auto rstats = regions_.stats(); + BreakdownStats(out, rstats, "HugePageAware: region "); + + auto cstats = cache_.stats(); + // Everything in the filler came from the cache - + // adjust the totals so we see the amount used by the mutator. + cstats.system_bytes -= fstats.system_bytes; + BreakdownStats(out, cstats, "HugePageAware: cache "); + + auto astats = alloc_.stats(); + // Everything in *all* components came from here - + // so again adjust the totals. + astats.system_bytes -= (fstats + rstats + cstats).system_bytes; + BreakdownStats(out, astats, "HugePageAware: alloc "); + out.printf("\n"); + + out.printf( + "HugePageAware: filler donations %zu (%zu pages from abandoned " + "donations)\n", + donated_huge_pages_.raw_num(), abandoned_pages_.raw_num()); + + // Component debug output + // Filler is by far the most important; print (some) of it + // unconditionally. + filler_.Print(out, everything); + out.printf("\n"); + if (everything) { + regions_.Print(out); + out.printf("\n"); + cache_.Print(out); + alloc_.Print(out); + out.printf("\n"); + + // Use statistics + info_.Print(out); + } + + out.printf("PARAMETER use_huge_region_more_often %d\n", + regions_.UseHugeRegionMoreOften() ? 1 : 0); + out.printf("PARAMETER hpaa_subrelease %d\n", hpaa_subrelease() ? 1 : 0); +} + +template +inline void HugePageAwareAllocator::PrintInPbtxt( + PbtxtRegion& region) { + SmallSpanStats small; + LargeSpanStats large; + PageHeapSpinLockHolder l; + GetSpanStats(&small, &large); + PrintStatsInPbtxt(region, small, large); + { + auto hpaa = region.CreateSubRegion("huge_page_allocator"); + hpaa.PrintBool("using_hpaa", true); + hpaa.PrintBool("using_hpaa_subrelease", hpaa_subrelease()); + hpaa.PrintBool("use_huge_region_more_often", + regions_.UseHugeRegionMoreOften()); + + // Fill HPAA Usage + auto fstats = filler_.stats(); + BreakdownStatsInPbtxt(hpaa, fstats, "filler_usage"); + + auto rstats = regions_.stats(); + BreakdownStatsInPbtxt(hpaa, rstats, "region_usage"); + + auto cstats = cache_.stats(); + // Everything in the filler came from the cache - + // adjust the totals so we see the amount used by the mutator. + cstats.system_bytes -= fstats.system_bytes; + BreakdownStatsInPbtxt(hpaa, cstats, "cache_usage"); + + auto astats = alloc_.stats(); + // Everything in *all* components came from here - + // so again adjust the totals. + astats.system_bytes -= (fstats + rstats + cstats).system_bytes; + + BreakdownStatsInPbtxt(hpaa, astats, "alloc_usage"); + + filler_.PrintInPbtxt(hpaa); + regions_.PrintInPbtxt(hpaa); + cache_.PrintInPbtxt(hpaa); + alloc_.PrintInPbtxt(hpaa); + + // Use statistics + info_.PrintInPbtxt(hpaa, "hpaa_stat"); + + hpaa.PrintI64("filler_donated_huge_pages", donated_huge_pages_.raw_num()); + hpaa.PrintI64("filler_abandoned_pages", abandoned_pages_.raw_num()); + } +} + +template +inline AddressRange HugePageAwareAllocator::AllocAndReport( + size_t bytes, size_t align) { + auto ret = forwarder_.AllocatePages(bytes, align, tag_); + if (ret.ptr == nullptr) return ret; + const PageId page = PageIdContaining(ret.ptr); + const Length page_len = BytesToLengthFloor(ret.bytes); + TC_CHECK(forwarder_.Ensure(Range(page, page_len)), + "Is something limiting virtual address space?"); + return ret; +} + +template +inline Length +HugePageAwareAllocator::ReleaseAtLeastNPagesBreakingHugepages( + Length n, PageReleaseReason reason) { + // We desperately need to release memory, and are willing to + // compromise on hugepage usage. That means releasing from the region and + // filler. + + Length released; + + if (forwarder_.huge_cache_demand_based_release()) { + released += cache_ + .ReleaseCachedPagesByDemand(HLFromPages(n), + SkipSubreleaseIntervals{}, + /*hit_limit=*/true) + .in_pages(); + } else { + released += cache_.ReleaseCachedPages(HLFromPages(n)).in_pages(); + } + + // We try to release as many free hugepages from HugeRegion as possible. + if (forwarder_.huge_region_demand_based_release()) { + released += regions_.ReleasePagesByPeakDemand( + n - released, SkipSubreleaseIntervals{}, /*hit_limit=*/true); + } else { + released += regions_.ReleasePages(/*release_fraction=*/1.0); + } + + if (released >= n) { + info_.RecordRelease(n, released, reason); + return released; + } + + released += filler_.ReleasePages(n - released, SkipSubreleaseIntervals{}, + /*release_partial_alloc_pages=*/false, + /*hit_limit=*/true); + + info_.RecordRelease(n, released, reason); + return released; +} + +template +inline PageReleaseStats HugePageAwareAllocator::GetReleaseStats() + const { + return info_.GetRecordedReleases(); +} + +template +bool HugePageAwareAllocator::IsValidSizeClass(size_t size, + size_t pages) { + // We assume that dense spans won't be donated. + size_t objects = Length(pages).in_bytes() / size; + if (objects > central_freelist_internal::kFewObjectsAllocMaxLimit && + Length(pages) > kSmallAllocPages) { + return false; + } + return true; +} + +template +inline bool HugePageAwareAllocator::hpaa_subrelease() const { + if (tag_ == MemoryTag::kCold) { + return true; + } else { + return forwarder_.hpaa_subrelease(); + } +} + +} // namespace huge_page_allocator_internal + +using HugePageAwareAllocator = + huge_page_allocator_internal::HugePageAwareAllocator< + huge_page_allocator_internal::StaticForwarder>; + } // namespace tcmalloc_internal } // namespace tcmalloc GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator_fuzz.cc b/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator_fuzz.cc new file mode 100644 index 000000000000..60158b0ca67a --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator_fuzz.cc @@ -0,0 +1,550 @@ +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "fuzztest/fuzztest.h" +#include "absl/base/attributes.h" +#include "absl/log/check.h" +#include "absl/time/time.h" +#include "tcmalloc/common.h" +#include "tcmalloc/huge_page_aware_allocator.h" +#include "tcmalloc/huge_page_filler.h" +#include "tcmalloc/huge_pages.h" +#include "tcmalloc/huge_region.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/mock_huge_page_static_forwarder.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/sizemap.h" +#include "tcmalloc/span.h" +#include "tcmalloc/stats.h" + +namespace tcmalloc::tcmalloc_internal { +namespace { +using huge_page_allocator_internal::FakeStaticForwarder; +using huge_page_allocator_internal::HugePageAwareAllocator; +using huge_page_allocator_internal::HugePageAwareAllocatorOptions; + +class FakeStaticForwarderWithUnback : public FakeStaticForwarder { + public: + bool ReleasePages(Range r) { + pending_release_ += r.n; + release_callback_(); + pending_release_ -= r.n; + + return FakeStaticForwarder::ReleasePages(r); + } + + Length pending_release_; + std::function release_callback_; +}; + +void FuzzHPAA(const std::string& s) { + const char* data = s.data(); + size_t size = s.size(); + + if (size < 13 || size > 100000) { + // size < 13 for needing some entropy to initialize huge page aware + // allocator. + // + // size > 100000 for avoiding overly large inputs given we do extra + // checking. + return; + } + +#if ABSL_HAVE_ADDRESS_SANITIZER + // Since asan introduces runtime overhead, limit size of fuzz targets further. + if (size > 10000) { + return; + } +#endif + + // We interpret data as a small DSL for exploring the state space of + // HugePageAwareAllocator. + // + // [0] - Memory tag. + // [1] - HugeRegionsMode. + // [2] - HugeCache release time + // [3:4] - Reserved. + // [5] - Dense tracker type + // [6:12] - Reserved. + // + // TODO(b/271282540): Convert these to strongly typed fuzztest parameters. + // + // Afterwards, we read 9 bytes at a time until the buffer is exhausted. + // [i + 0] - Specifies an operation to perform on the allocator + // [i + 1, i + 8] - Specifies an integer. We use this as a source of + // deterministic entropy to allow inputs to be replayed. + // For example, this input can provide a Length to + // allocate, or the index of the previous allocation to + // deallocate. + + constexpr MemoryTag kTagOptions[] = { + MemoryTag::kSampled, MemoryTag::kNormalP0, MemoryTag::kNormalP1, + MemoryTag::kNormal, MemoryTag::kCold}; + constexpr int kTagSize = sizeof(kTagOptions) / sizeof(MemoryTag); + static_assert(kTagSize > 0); + MemoryTag tag = kTagOptions[static_cast(data[0]) % kTagSize]; + // Use kNormalP1 memory tag only if we have more than one NUMA partitions. + tag = (kNumaPartitions == 1 && tag == MemoryTag::kNormalP1) + ? MemoryTag::kNormalP0 + : tag; + + const HugeRegionUsageOption huge_region_option = + static_cast(data[1]) >= 128 + ? HugeRegionUsageOption::kDefault + : HugeRegionUsageOption::kUseForAllLargeAllocs; + + const HugePageFillerDenseTrackerType dense_tracker_type = + static_cast(data[5]) >= 128 + ? HugePageFillerDenseTrackerType::kLongestFreeRangeAndChunks + : HugePageFillerDenseTrackerType::kSpansAllocated; + + const int32_t huge_cache_release_s = std::max(data[2], 1); + + // data[6:12] - Reserve additional bytes for any features we might want to add + // in the future. + data += 13; + size -= 13; + + // HugePageAwareAllocator can't be destroyed cleanly, so we store a pointer + // to one and construct in place. + void* p = + malloc(sizeof(HugePageAwareAllocator)); + HugePageAwareAllocatorOptions options; + options.tag = tag; + options.use_huge_region_more_often = huge_region_option; + options.huge_cache_time = absl::Seconds(huge_cache_release_s); + options.dense_tracker_type = dense_tracker_type; + HugePageAwareAllocator* allocator; + allocator = + new (p) HugePageAwareAllocator(options); + auto& forwarder = allocator->forwarder(); + + struct SpanInfo { + Span* span; + size_t objects_per_span; + }; + std::vector allocs; + Length allocated; + PageReleaseStats expected_stats; + + std::vector> reentrant; + std::string output; + output.resize(1 << 20); + + auto run_dsl = [&](const char* data, size_t size) { + for (size_t i = 0; i + 9 <= size; i += 9) { + const uint16_t op = data[i]; + uint64_t value; + memcpy(&value, &data[i + 1], sizeof(value)); + + switch (op & 0x7) { + case 0: { + // Aligned allocate. We divide up our random value by: + // + // value[0:15] - We choose a Length to allocate. + // value[16:31] - We select num_to_objects, i.e. the number of + // objects to allocate. + // value[32:47] - Alignment. + // value[48] - Should we use aligned allocate? + // value[49] - Is the span sparsely- or densely-accessed? + // value[63:50] - Reserved. + Length length(std::clamp(value & 0xFFFF, 1, + kPagesPerHugePage.raw_num() - 1)); + size_t num_objects = std::max((value >> 16) & 0xFFFF, 1); + size_t object_size = length.in_bytes() / num_objects; + const bool use_aligned = ((value >> 48) & 0x1) == 0; + const Length align( + use_aligned ? std::clamp((value >> 32) & 0xFFFF, 1, + kPagesPerHugePage.raw_num() - 1) + : 1); + + AccessDensityPrediction density = + ((value >> 49) & 0x1) == 0 ? AccessDensityPrediction::kSparse + : AccessDensityPrediction::kDense; + if (object_size > kMaxSize || align > Length(1)) { + // Truncate to a single object. + num_objects = 1; + // TODO(b/283843066): Revisit this once we have fluid + // partitioning. + density = AccessDensityPrediction::kSparse; + } else if (!SizeMap::IsValidSizeClass(object_size, length.raw_num(), + kMinObjectsToMove)) { + // This is an invalid size class, so skip it. + break; + } + if (dense_tracker_type == + HugePageFillerDenseTrackerType::kSpansAllocated && + density == AccessDensityPrediction::kDense) { + length = Length(1); + } + + // Allocation is too big for filler if we try to allocate > + // kPagesPerHugePage / 2 run of pages. The allocations may go to + // HugeRegion and that might lead to donations with kSparse + // density. + if (length > kPagesPerHugePage / 2) { + density = AccessDensityPrediction::kSparse; + } + + Span* s; + SpanAllocInfo alloc_info = {.objects_per_span = num_objects, + .density = density}; + TC_CHECK( + dense_tracker_type == + HugePageFillerDenseTrackerType::kLongestFreeRangeAndChunks || + density == AccessDensityPrediction::kSparse || + length == Length(1)); + if (use_aligned) { + s = allocator->NewAligned(length, align, alloc_info); + } else { + s = allocator->New(length, alloc_info); + } + TC_CHECK_NE(s, nullptr); + TC_CHECK_GE(s->num_pages().raw_num(), length.raw_num()); + + allocs.push_back(SpanInfo{s, num_objects}); + + allocated += s->num_pages(); + break; + } + case 1: { + // Deallocate. We divide up our random value by: + // + // value - We choose index in allocs to deallocate a span. + + if (allocs.empty()) break; + + const size_t pos = value % allocs.size(); + std::swap(allocs[pos], allocs[allocs.size() - 1]); + + SpanInfo span_info = allocs[allocs.size() - 1]; + allocs.resize(allocs.size() - 1); + allocated -= span_info.span->num_pages(); + + { +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + PageHeapSpinLockHolder l; + allocator->Delete(span_info.span); +#else + PageAllocatorInterface::AllocationState a{ + Range(span_info.span->first_page(), + span_info.span->num_pages()), + span_info.span->donated(), + }; + allocator->forwarder().DeleteSpan(span_info.span); + PageHeapSpinLockHolder l; + allocator->Delete(a); +#endif // TCMALLOC_INTERNAL_LEGACY_LOCKING + } + break; + } + case 2: { + // Release pages. We divide up our random value by: + // + // value[7:0] - Choose number of pages to release. + // value[8:9] - Choose page release reason. + // value[63:9] - Reserved. + Length desired(value & 0x00FF); + PageReleaseReason reason; + switch ((value >> 8) & 0x3) { + case 0: + reason = PageReleaseReason::kReleaseMemoryToSystem; + break; + case 1: + reason = PageReleaseReason::kProcessBackgroundActions; + break; + case 2: + reason = PageReleaseReason::kSoftLimitExceeded; + break; + case 3: + reason = PageReleaseReason::kHardLimitExceeded; + break; + } + Length released; + PageReleaseStats actual_stats; + { + PageHeapSpinLockHolder l; + released = allocator->ReleaseAtLeastNPages(desired, reason); + actual_stats = allocator->GetReleaseStats(); + } + expected_stats.total += released; + switch (reason) { + case PageReleaseReason::kReleaseMemoryToSystem: + expected_stats.release_memory_to_system += released; + break; + case PageReleaseReason::kProcessBackgroundActions: + expected_stats.process_background_actions += released; + break; + case PageReleaseReason::kSoftLimitExceeded: + expected_stats.soft_limit_exceeded += released; + break; + case PageReleaseReason::kHardLimitExceeded: + expected_stats.hard_limit_exceeded += released; + break; + } + TC_CHECK_EQ(actual_stats, expected_stats); + + break; + } + case 3: { + // Release pages by breaking hugepages. We divide up our random + // value by: + // + // value[15:0] - Choose number of pages to release. + // value[16] - Choose page release reason. SoftLimitExceeded if + // zero, HardLimitExceeded otherwise. + // value[63:17] - Reserved. + Length desired(value & 0xFFFF); + const PageReleaseReason reason = + ((value & (uint64_t{1} << 16)) == 0) + ? PageReleaseReason::kSoftLimitExceeded + : PageReleaseReason::kHardLimitExceeded; + Length released; + size_t releasable_bytes; + PageReleaseStats actual_stats; + { + PageHeapSpinLockHolder l; + releasable_bytes = allocator->FillerStats().free_bytes + + allocator->RegionsFreeBacked().in_bytes() + + allocator->CacheStats().free_bytes; + released = allocator->ReleaseAtLeastNPagesBreakingHugepages(desired, + reason); + actual_stats = allocator->GetReleaseStats(); + } + + if (forwarder.release_succeeds()) { + const size_t min_released = + std::min(desired.in_bytes(), releasable_bytes); + TC_CHECK_GE(released.in_bytes(), min_released); + } else { + // TODO(b/271282540): This is not strict equality due to + // HugePageFiller's unmapping_unaccounted_ state. Narrow this + // bound. + TC_CHECK_GE(released.in_bytes(), 0); + } + + expected_stats.total += released; + if (reason == PageReleaseReason::kSoftLimitExceeded) { + expected_stats.soft_limit_exceeded += released; + } else { + expected_stats.hard_limit_exceeded += released; + } + + TC_CHECK_EQ(actual_stats, expected_stats); + + break; + } + case 4: { + // Gather stats in pbtxt format. + // + // value is unused. + Printer p(&output[0], output.size()); + { + PbtxtRegion region(p, kTop); + allocator->PrintInPbtxt(region); + } + CHECK_LE(p.SpaceRequired(), output.size()); + break; + } + case 5: { + // Print stats. + // + // value[0]: Choose if we print everything. + // value[63:1]: Reserved. + Printer p(&output[0], output.size()); + bool everything = (value % 2 == 0); + allocator->Print(p, everything); + break; + } + case 6: { + // Gather and check stats. + // + // value is unused. + BackingStats stats; + { + PageHeapSpinLockHolder l; + stats = allocator->stats(); + } + uint64_t used_bytes = + stats.system_bytes - stats.free_bytes - stats.unmapped_bytes; + TC_CHECK_EQ(used_bytes, allocated.in_bytes() + + forwarder.pending_release_.in_bytes()); + break; + } + case 7: { + // Change a runtime parameter. + // + // value[0:3] - Select parameter + // value[4:7] - Reserved + // value[8:63] - The value + const uint64_t actual_value = value >> 8; + switch (value & 0xF) { + case 0: + forwarder.set_filler_skip_subrelease_interval( + absl::Nanoseconds(actual_value)); + forwarder.set_filler_skip_subrelease_short_interval( + absl::ZeroDuration()); + forwarder.set_filler_skip_subrelease_long_interval( + absl::ZeroDuration()); + break; + case 1: + forwarder.set_filler_skip_subrelease_interval( + absl::ZeroDuration()); + forwarder.set_filler_skip_subrelease_short_interval( + absl::Nanoseconds(actual_value)); + break; + case 2: + forwarder.set_filler_skip_subrelease_interval( + absl::ZeroDuration()); + forwarder.set_filler_skip_subrelease_long_interval( + absl::Nanoseconds(actual_value)); + break; + case 3: + forwarder.set_release_partial_alloc_pages(actual_value & 0x1); + break; + case 4: + forwarder.set_hpaa_subrelease(actual_value & 0x1); + break; + case 5: + forwarder.set_release_succeeds(actual_value & 0x1); + break; + case 6: + forwarder.set_huge_region_demand_based_release(actual_value & + 0x1); + break; + case 7: { + // Not quite a runtime parameter: Interpret actual_value as a + // subprogram in our dsl. + size_t subprogram = std::min(size - i - 9, actual_value); + reentrant.emplace_back(data + i + 9, subprogram); + i += size; + break; + } + case 8: { + // Flips the settings used by demand-based release in HugeCache: + // actual_value[0] - release enabled + // actual_value[1:16] - interval_1 + // actual_value[17:32] - interval_2 + forwarder.set_huge_cache_demand_based_release(actual_value & 0x1); + if (forwarder.huge_cache_demand_based_release()) { + const uint64_t interval_1 = (actual_value >> 1) & 0xffff; + const uint64_t interval_2 = (actual_value >> 17) & 0xffff; + forwarder.set_cache_demand_release_long_interval( + interval_1 >= interval_2 ? absl::Nanoseconds(interval_1) + : absl::Nanoseconds(interval_2)); + forwarder.set_cache_demand_release_short_interval( + interval_1 >= interval_2 ? absl::Nanoseconds(interval_2) + : absl::Nanoseconds(interval_1)); + } + break; + } + } + break; + } + } + } + }; + + forwarder.release_callback_ = [&]() { + if (tcmalloc::tcmalloc_internal::pageheap_lock.IsHeld()) { + // This permits a slight degree of nondeterminism when linked against + // TCMalloc for the real memory allocator, as a background thread could + // also be holding the lock. Nevertheless, HPAA doesn't make it clear + // when we are releasing with/without the pageheap_lock. + // + // TODO(b/73749855): When all release paths unconditionally release the + // lock, remove this check and take the lock for an instant to ensure it + // can be taken. + return; + } + + if (reentrant.empty()) { + return; + } + + ABSL_CONST_INIT static int depth = 0; + if (depth >= 5) { + return; + } + + auto [data, size] = reentrant.back(); + reentrant.pop_back(); + + depth++; + run_dsl(data, size); + depth--; + }; + + run_dsl(data, size); + + // Stop recursing, since allocator->Delete below might cause us to "release" + // more pages to the system. + reentrant.clear(); + + // Clean up. + const PageReleaseStats final_stats = [&] { + for (auto span_info : allocs) { + Span* span = span_info.span; + allocated -= span->num_pages(); +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + PageHeapSpinLockHolder l; + allocator->Delete(span_info.span); +#else + PageAllocatorInterface::AllocationState a{ + Range(span_info.span->first_page(), span_info.span->num_pages()), + span_info.span->donated(), + }; + allocator->forwarder().DeleteSpan(span_info.span); + PageHeapSpinLockHolder l; + allocator->Delete(a); +#endif // TCMALLOC_INTERNAL_LEGACY_LOCKING + } + + PageHeapSpinLockHolder l; + return allocator->GetReleaseStats(); + }(); + + TC_CHECK_EQ(allocated.in_bytes(), 0); + TC_CHECK_EQ(final_stats, expected_stats); + + free(allocator); +} + +FUZZ_TEST(HugePageAwareAllocatorTest, FuzzHPAA) + ; + +TEST(HugePageAwareAllocatorTest, FuzzHPAARegression) { + FuzzHPAA( + "\370n,,,\3708\304\320\327\311[" + "PXG\"Y\037\216\366\366b\216\340\375\332\362"); +} + +TEST(HugePageAwareAllocatorTest, FuzzHPAARegression2) { + FuzzHPAA( + "\376\006\366>\354{{{{{\347\242\2048:\204\177{{" + "9\376d\027\224\312\257\276\252\026?\013\010\010"); +} + +} // namespace +} // namespace tcmalloc::tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator_test.cc b/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator_test.cc index 83ae930e44a6..247502d5b876 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/huge_page_aware_allocator_test.cc @@ -14,75 +14,130 @@ #include "tcmalloc/huge_page_aware_allocator.h" -#include +#include +#include #include #include #include -#include +#include #include +#include #include #include -#include +#include #include #include // NOLINT(build/c++11) #include #include +#include "benchmark/benchmark.h" #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/attributes.h" -#include "absl/base/const_init.h" #include "absl/base/internal/spinlock.h" -#include "absl/base/internal/sysinfo.h" +#include "absl/base/nullability.h" +#include "absl/base/optimization.h" +#include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_map.h" -#include "absl/flags/flag.h" +#include "absl/meta/type_traits.h" +#include "absl/random/bit_gen_ref.h" +#include "absl/random/distributions.h" #include "absl/random/random.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" -#include "absl/strings/str_split.h" +#include "absl/strings/string_view.h" #include "absl/synchronization/barrier.h" -#include "absl/synchronization/mutex.h" +#include "absl/time/clock.h" #include "absl/time/time.h" -#include "benchmark/benchmark.h" #include "tcmalloc/common.h" #include "tcmalloc/huge_pages.h" +#include "tcmalloc/huge_region.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/page_size.h" #include "tcmalloc/malloc_extension.h" +#include "tcmalloc/mock_huge_page_static_forwarder.h" #include "tcmalloc/page_allocator_test_util.h" -#include "tcmalloc/parameters.h" +#include "tcmalloc/pages.h" #include "tcmalloc/span.h" -#include "tcmalloc/static_vars.h" #include "tcmalloc/stats.h" #include "tcmalloc/system-alloc.h" #include "tcmalloc/testing/thread_manager.h" -ABSL_FLAG(std::string, tracefile, "", "file to pull trace from"); -ABSL_FLAG(uint64_t, limit, 0, ""); -ABSL_FLAG(bool, always_check_usage, false, "enable expensive memory checks"); - namespace tcmalloc { namespace tcmalloc_internal { namespace { +using huge_page_allocator_internal::HugePageAwareAllocatorOptions; using testing::HasSubstr; -class HugePageAwareAllocatorTest : public ::testing::Test { +class HugePageAwareAllocatorTest + : public ::testing::TestWithParam { + class FakeStaticForwarderWithReleaseCheck + : public huge_page_allocator_internal::FakeStaticForwarder { + public: + [[nodiscard]] bool ReleasePages(Range r) { + const uintptr_t start = reinterpret_cast(r.p.start_addr()); + bool ret = + huge_page_allocator_internal::FakeStaticForwarder::ReleasePages(r); + // Try to acquire the lock. It is possible that we are holding + // pageheap_lock while calling ReleasePages, so it might result in a + // deadlock as RecordAllocation/RecordDeallocation may allocate. + // This makes the release check a best effort. + if (!lock_.TryLock()) return ret; + + // Remove from the list of allocations, if the address was previously + // allocated. + auto it = std::find(allocations_.begin(), allocations_.end(), start); + if (it != allocations_.end()) { + *it = allocations_.back(); + allocations_.pop_back(); + } + lock_.Unlock(); + return ret; + } + + void RecordAllocation(uintptr_t start_addr) { + absl::base_internal::SpinLockHolder h(&lock_); + allocations_.push_back(start_addr); + } + void RecordDeallocation(uintptr_t start_addr) { + absl::base_internal::SpinLockHolder h(&lock_); + // Make sure the address was previously allocated and wasn't removed from + // the list when it was released. + auto it = std::find(allocations_.begin(), allocations_.end(), start_addr); + TC_CHECK(it != allocations_.end()); + *it = allocations_.back(); + allocations_.pop_back(); + } + + private: + std::vector allocations_; + absl::base_internal::SpinLock lock_; + }; + using MockedHugePageAwareAllocator = + huge_page_allocator_internal::HugePageAwareAllocator< + FakeStaticForwarderWithReleaseCheck>; + protected: - HugePageAwareAllocatorTest() : rng_() { + HugePageAwareAllocatorTest() { before_ = MallocExtension::GetRegionFactory(); extra_ = new ExtraRegionFactory(before_); MallocExtension::SetRegionFactory(extra_); - // HugePageAwareAllocator can't be destroyed cleanly, so we store a pointer - // to one and construct in place. - void* p = malloc(sizeof(HugePageAwareAllocator)); - allocator_ = new (p) HugePageAwareAllocator(MemoryTag::kNormal); + // HugePageAwareAllocator can't be destroyed cleanly, so we store a + // pointer to one and construct in place. + void* p = malloc(sizeof(MockedHugePageAwareAllocator)); + HugePageAwareAllocatorOptions options; + options.tag = MemoryTag::kNormal; + // TODO(b/242550501): Parameterize other parts of the options. + options.use_huge_region_more_often = GetParam(); + allocator_ = new (p) MockedHugePageAwareAllocator(options); } ~HugePageAwareAllocatorTest() override { - CHECK_CONDITION(ids_.empty()); - CHECK_CONDITION(total_ == Length(0)); + TC_CHECK(ids_.empty()); + TC_CHECK_EQ(total_, Length(0)); // We end up leaking both the backing allocations and the metadata. // The backing allocations are unmapped--it's silly, but not // costing us muchin a 64-bit address space. @@ -90,12 +145,9 @@ class HugePageAwareAllocatorTest : public ::testing::Test { // It'd be very complicated to rebuild the allocator to support // teardown, so we just put up with it. { - absl::base_internal::SpinLockHolder h(&pageheap_lock); + PageHeapSpinLockHolder l; auto stats = allocator_->stats(); - if (stats.free_bytes + stats.unmapped_bytes != stats.system_bytes) { - Crash(kCrash, __FILE__, __LINE__, stats.free_bytes, - stats.unmapped_bytes, "!=", stats.system_bytes); - } + TC_CHECK_EQ(stats.free_bytes + stats.unmapped_bytes, stats.system_bytes); } free(allocator_); @@ -108,7 +160,7 @@ class HugePageAwareAllocatorTest : public ::testing::Test { size_t actual_used_bytes = total_.in_bytes(); BackingStats stats; { - absl::base_internal::SpinLockHolder h2(&pageheap_lock); + PageHeapSpinLockHolder l; stats = allocator_->stats(); } uint64_t used_bytes = @@ -119,62 +171,101 @@ class HugePageAwareAllocatorTest : public ::testing::Test { uint64_t GetFreeBytes() { BackingStats stats; { - absl::base_internal::SpinLockHolder h2(&pageheap_lock); + PageHeapSpinLockHolder l; stats = allocator_->stats(); } return stats.free_bytes; } - Span* AllocatorNew(Length n) { return allocator_->New(n); } + Span* AllocatorNew(Length n, SpanAllocInfo span_alloc_info) { + Span* s = allocator_->New(n, span_alloc_info); + uintptr_t start = reinterpret_cast(s->start_address()); + allocator_->forwarder().RecordAllocation( + reinterpret_cast(start)); + return s; + } - void AllocatorDelete(Span* s) { - absl::base_internal::SpinLockHolder h(&pageheap_lock); + void AllocatorDelete(Span* s, size_t objects_per_span) { +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + PageHeapSpinLockHolder l; allocator_->Delete(s); +#else + uintptr_t start = reinterpret_cast(s->start_address()); + allocator_->forwarder().RecordDeallocation(start); + PageAllocatorInterface::AllocationState a{ + Range(s->first_page(), s->num_pages()), + s->donated(), + }; + allocator_->forwarder().DeleteSpan(s); + PageHeapSpinLockHolder l; + allocator_->Delete(a); +#endif // TCMALLOC_INTERNAL_LEGACY_LOCKING } - Span* New(Length n) { + Span* New(Length n, SpanAllocInfo span_alloc_info) { absl::base_internal::SpinLockHolder h(&lock_); - Span* span = AllocatorNew(n); - CHECK_CONDITION(span != nullptr); + Span* span = AllocatorNew(n, span_alloc_info); + TC_CHECK_NE(span, nullptr); EXPECT_GE(span->num_pages(), n); const size_t id = next_id_++; total_ += n; CheckStats(); // and distinct spans... - CHECK_CONDITION(ids_.insert({span, id}).second); + TC_CHECK(ids_.insert({span, id}).second); return span; } - void Delete(Span* span) { + void Delete(Span* span, size_t objects_per_span) { Length n = span->num_pages(); { absl::base_internal::SpinLockHolder h(&lock_); auto i = ids_.find(span); - CHECK_CONDITION(i != ids_.end()); + TC_CHECK(i != ids_.end()); const size_t id = i->second; ids_.erase(i); - AllocatorDelete(span); + AllocatorDelete(span, objects_per_span); total_ -= n; CheckStats(); } } // Mostly small things, some large ones. - Length RandomAllocSize() { - // TODO(b/128521238): scalable RNG - absl::base_internal::SpinLockHolder h(&lock_); - if (absl::Bernoulli(rng_, 1.0 / 1000)) { - Length n = - Length(1024) * (1 + absl::LogUniform(rng_, 0, (1 << 8) - 1)); - n += Length(absl::Uniform(rng_, 0, 1024)); - return n; + std::pair RandomAllocSize(absl::BitGenRef rng) { + Length n; + if (absl::Bernoulli(rng, 1.0 / 1000)) { + n = Length(1024) * (1 + absl::LogUniform(rng, 0, (1 << 8) - 1)); + n += Length(absl::Uniform(rng, 0, 1024)); + } else { + n = Length(1 + absl::LogUniform(rng, 0, (1 << 9) - 1)); } - return Length(1 + absl::LogUniform(rng_, 0, (1 << 9) - 1)); + // The condition used here ensures that if the allocated hugepage is donated + // to the HugePageFiller, then it is expected to be short lived. + size_t objects = (n <= kPagesPerHugePage / 2) + ? absl::Uniform(rng, 1, 256) + : absl::Uniform(rng, 1, 16); + + AccessDensityPrediction density = + (n <= kPagesPerHugePage / 2) + ? (absl::Bernoulli(rng, 1.0) ? AccessDensityPrediction::kSparse + : AccessDensityPrediction::kDense) + : AccessDensityPrediction::kSparse; + return {n, {objects, density}}; + } + + Length ReleasePages(Length k, PageReleaseReason reason) { + PageHeapSpinLockHolder l; + return allocator_->ReleaseAtLeastNPages(k, reason); + } + + Length ReleaseAtLeastNPagesBreakingHugepages(Length n, + PageReleaseReason reason) { + PageHeapSpinLockHolder l; + return allocator_->ReleaseAtLeastNPagesBreakingHugepages(n, reason); } - Length ReleasePages(Length k) { - absl::base_internal::SpinLockHolder h(&pageheap_lock); - return allocator_->ReleaseAtLeastNPages(k); + bool UseHugeRegionMoreOften() { + PageHeapSpinLockHolder l; + return allocator_->region().UseHugeRegionMoreOften(); } std::string Print() { @@ -182,63 +273,73 @@ class HugePageAwareAllocatorTest : public ::testing::Test { const size_t kSize = 1 << 20; ret.resize(kSize); Printer p(&ret[0], kSize); - allocator_->Print(&p); + allocator_->Print(p); ret.erase(p.SpaceRequired()); return ret; } - std::string PrintInPbTxt() { + std::string PrintInPbtxt() { std::string ret; const size_t kSize = 1 << 20; ret.resize(kSize); Printer p(&ret[0], kSize); { - PbtxtRegion region(&p, kNested, 0); - allocator_->PrintInPbtxt(®ion); + PbtxtRegion region(p, kNested); + allocator_->PrintInPbtxt(region); } ret.erase(p.SpaceRequired()); return ret; } - HugePageAwareAllocator* allocator_; + // TODO(b/242550501): Replace this with one templated with a different + // forwarder, as to facilitate mocks. + MockedHugePageAwareAllocator* allocator_; ExtraRegionFactory* extra_; AddressRegionFactory* before_; - absl::BitGen rng_; absl::base_internal::SpinLock lock_; absl::flat_hash_map ids_; size_t next_id_{0}; Length total_; }; -TEST_F(HugePageAwareAllocatorTest, Fuzz) { - std::vector allocs; +struct SpanInfo { + Span* span; + SpanAllocInfo span_alloc_info; +}; + +TEST_P(HugePageAwareAllocatorTest, Fuzz) { + absl::BitGen rng; + std::vector allocs; for (int i = 0; i < 5000; ++i) { - Length n = RandomAllocSize(); - allocs.push_back(New(n)); + auto [n, span_alloc_info] = RandomAllocSize(rng); + Span* s = New(n, span_alloc_info); + allocs.push_back(SpanInfo{s, span_alloc_info}); } static const size_t kReps = 50 * 1000; for (int i = 0; i < kReps; ++i) { SCOPED_TRACE(absl::StrFormat("%d reps, %d pages", i, total_.raw_num())); - size_t index = absl::Uniform(rng_, 0, allocs.size()); - Span* old = allocs[index]; - Delete(old); - Length n = RandomAllocSize(); - allocs[index] = New(n); + size_t index = absl::Uniform(rng, 0, allocs.size()); + Span* old_span = allocs[index].span; + size_t objects_per_span = allocs[index].span_alloc_info.objects_per_span; + Delete(old_span, objects_per_span); + auto [n, span_alloc_info] = RandomAllocSize(rng); + allocs[index] = SpanInfo{New(n, span_alloc_info), span_alloc_info}; } for (auto s : allocs) { - Delete(s); + Delete(s.span, s.span_alloc_info.objects_per_span); } } // Prevent regression of the fragmentation problem that was reported in // b/63301358, reproduced in CL/161345659 and (partially) fixed in CL/161305971. -TEST_F(HugePageAwareAllocatorTest, JustUnderMultipleOfHugepages) { +TEST_P(HugePageAwareAllocatorTest, JustUnderMultipleOfHugepages) { + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; std::vector big_allocs, small_allocs; // Trigger creation of a hugepage with more than one allocation and plenty of // free space. - small_allocs.push_back(New(Length(1))); - small_allocs.push_back(New(Length(10))); + small_allocs.push_back(New(Length(1), kSpanInfo)); + small_allocs.push_back(New(Length(10), kSpanInfo)); // Limit iterations so that the huge page with the small allocs doesn't fill // up. size_t n_iter = (kPagesPerHugePage - Length(2)).raw_num(); @@ -246,22 +347,22 @@ TEST_F(HugePageAwareAllocatorTest, JustUnderMultipleOfHugepages) { n_iter = std::min((1 << 30) / (2 * kHugePageSize), n_iter); for (int i = 0; i < n_iter; ++i) { Length n = 2 * kPagesPerHugePage - Length(1); - big_allocs.push_back(New(n)); - small_allocs.push_back(New(Length(1))); + big_allocs.push_back(New(n, kSpanInfo)); + small_allocs.push_back(New(Length(1), kSpanInfo)); } for (auto* span : big_allocs) { - Delete(span); + Delete(span, kSpanInfo.objects_per_span); } // We should have one hugepage that's full of small allocations and a bunch // of empty hugepages. The HugeCache will keep some of the empty hugepages // backed so free space should drop to a small multiple of the huge page size. EXPECT_LE(GetFreeBytes(), 20 * kHugePageSize); for (auto* span : small_allocs) { - Delete(span); + Delete(span, kSpanInfo.objects_per_span); } } -TEST_F(HugePageAwareAllocatorTest, Multithreaded) { +TEST_P(HugePageAwareAllocatorTest, Multithreaded) { static const size_t kThreads = 16; std::vector threads; threads.reserve(kThreads); @@ -270,22 +371,23 @@ TEST_F(HugePageAwareAllocatorTest, Multithreaded) { for (int i = 0; i < kThreads; ++i) { threads.push_back(std::thread([this, &b1, &b2]() { absl::BitGen rng; - std::vector allocs; + std::vector allocs; for (int i = 0; i < 150; ++i) { - Length n = RandomAllocSize(); - allocs.push_back(New(n)); + auto [n, span_alloc_info] = RandomAllocSize(rng); + allocs.push_back(SpanInfo{New(n, span_alloc_info), span_alloc_info}); } b1.Block(); static const size_t kReps = 4 * 1000; for (int i = 0; i < kReps; ++i) { size_t index = absl::Uniform(rng, 0, allocs.size()); - Delete(allocs[index]); - Length n = RandomAllocSize(); - allocs[index] = New(n); + Delete(allocs[index].span, + allocs[index].span_alloc_info.objects_per_span); + auto [n, span_alloc_info] = RandomAllocSize(rng); + allocs[index] = SpanInfo{New(n, span_alloc_info), span_alloc_info}; } b2.Block(); for (auto s : allocs) { - Delete(s); + Delete(s.span, s.span_alloc_info.objects_per_span); } })); } @@ -295,137 +397,725 @@ TEST_F(HugePageAwareAllocatorTest, Multithreaded) { } } -TEST_F(HugePageAwareAllocatorTest, ReleasingLarge) { - // Ensure the HugeCache has some free items: - Delete(New(kPagesPerHugePage)); - ASSERT_LE(kPagesPerHugePage, ReleasePages(kPagesPerHugePage)); +TEST_P(HugePageAwareAllocatorTest, ReleasingLargeForUserRequestedRelease) { + // Tests that we can release when requested by the user, irrespective of + // whether the demand-based release is enabled or not. We do this by + // alternating the state of the demand-based release flag. + bool enabled = allocator_->forwarder().huge_cache_demand_based_release(); + constexpr int kNumIterations = 100; + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; + for (int i = 0; i < kNumIterations; ++i) { + // Ensure the HugeCache has some free items: + Delete(New(kPagesPerHugePage, kSpanInfo), kSpanInfo.objects_per_span); + EXPECT_EQ( + ReleasePages(kPagesPerHugePage, + /*reason=*/PageReleaseReason::kReleaseMemoryToSystem), + kPagesPerHugePage); + enabled = !enabled; + allocator_->forwarder().set_huge_cache_demand_based_release(enabled); + } +} + +TEST_P(HugePageAwareAllocatorTest, ReleasingLargeForBackgroundActions) { + // Tests that the background release will be impacted by the demand-based + // release: when enabled, it will not release any pages due to the recent + // demand. + bool enabled = allocator_->forwarder().huge_cache_demand_based_release(); + constexpr int kNumIterations = 100; + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; + for (int i = 0; i < kNumIterations; ++i) { + Delete(New(kPagesPerHugePage, kSpanInfo), kSpanInfo.objects_per_span); + // Demand-based release would think releasing is not a good idea, hence we + // need to force a release later. + EXPECT_EQ( + ReleasePages(kPagesPerHugePage, + /*reason=*/PageReleaseReason::kProcessBackgroundActions), + enabled ? Length(0) : kPagesPerHugePage); + if (enabled) { + EXPECT_EQ(ReleasePages(Length(1), + /*reason=*/PageReleaseReason::kSoftLimitExceeded), + kPagesPerHugePage); + } + enabled = !enabled; + allocator_->forwarder().set_huge_cache_demand_based_release(enabled); + } +} + +TEST_P(HugePageAwareAllocatorTest, ReleasingMemoryLimitHit) { + // Tests that we can release when the memory limit is hit, irrespective of + // whether the demand-based release is enabled or not. We test this by + // alternating the state of the demand-based release flag. + bool enabled = allocator_->forwarder().huge_cache_demand_based_release(); + constexpr int kNumIterations = 100; + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; + for (int i = 0; i < kNumIterations; ++i) { + Delete(New(kPagesPerHugePage, kSpanInfo), kSpanInfo.objects_per_span); + EXPECT_EQ(ReleaseAtLeastNPagesBreakingHugepages( + kPagesPerHugePage, + /*reason=*/PageReleaseReason::kSoftLimitExceeded), + kPagesPerHugePage); + enabled = !enabled; + allocator_->forwarder().set_huge_cache_demand_based_release(enabled); + } +} + +TEST_P(HugePageAwareAllocatorTest, + ReleasingLargeForBackgroundActionsWithZeroIntervals) { + // Tests that the configured intervals can be passed to HugeCache: release is + // not being impacted by demand-based release when the intervals are zero. + const bool old_enabled = + allocator_->forwarder().huge_cache_demand_based_release(); + allocator_->forwarder().set_huge_cache_demand_based_release(/*value=*/true); + const absl::Duration old_cache_short_interval = + allocator_->forwarder().cache_demand_release_short_interval(); + const absl::Duration old_cache_long_interval = + allocator_->forwarder().cache_demand_release_long_interval(); + allocator_->forwarder().set_cache_demand_release_short_interval( + absl::ZeroDuration()); + allocator_->forwarder().set_cache_demand_release_long_interval( + absl::ZeroDuration()); + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; + Delete(New(kPagesPerHugePage, kSpanInfo), kSpanInfo.objects_per_span); + // There is no history to reference so release all. + EXPECT_EQ( + ReleasePages(kPagesPerHugePage, + /*reason=*/PageReleaseReason::kProcessBackgroundActions), + kPagesPerHugePage); + allocator_->forwarder().set_huge_cache_demand_based_release(old_enabled); + allocator_->forwarder().set_cache_demand_release_short_interval( + old_cache_short_interval); + allocator_->forwarder().set_cache_demand_release_long_interval( + old_cache_long_interval); } -TEST_F(HugePageAwareAllocatorTest, ReleasingSmall) { - const bool old_subrelease = Parameters::hpaa_subrelease(); - Parameters::set_hpaa_subrelease(true); +TEST_P(HugePageAwareAllocatorTest, ReleasingSmall) { + const bool old_subrelease = allocator_->forwarder().hpaa_subrelease(); + allocator_->forwarder().set_hpaa_subrelease(/*value=*/true); - const absl::Duration old_skip_subrelease = - Parameters::filler_skip_subrelease_interval(); - Parameters::set_filler_skip_subrelease_interval(absl::ZeroDuration()); + absl::Duration old_skip_subrelease_short_interval = + allocator_->forwarder().filler_skip_subrelease_short_interval(); + allocator_->forwarder().set_filler_skip_subrelease_short_interval( + absl::ZeroDuration()); + + absl::Duration old_skip_subrelease_long_interval = + allocator_->forwarder().filler_skip_subrelease_long_interval(); + allocator_->forwarder().set_filler_skip_subrelease_long_interval( + absl::ZeroDuration()); std::vector live, dead; static const size_t N = kPagesPerHugePage.raw_num() * 128; + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; for (int i = 0; i < N; ++i) { - Span* span = New(Length(1)); + Span* span = New(Length(1), kSpanInfo); ((i % 2 == 0) ? live : dead).push_back(span); } for (auto d : dead) { - Delete(d); + Delete(d, kSpanInfo.objects_per_span); } - EXPECT_EQ(kPagesPerHugePage / 2, ReleasePages(Length(1))); + EXPECT_EQ(kPagesPerHugePage / 2, + ReleasePages(Length(1), + /*reason=*/PageReleaseReason::kReleaseMemoryToSystem)); for (auto l : live) { - Delete(l); + Delete(l, kSpanInfo.objects_per_span); + } + + allocator_->forwarder().set_hpaa_subrelease(old_subrelease); + allocator_->forwarder().set_filler_skip_subrelease_short_interval( + old_skip_subrelease_short_interval); + allocator_->forwarder().set_filler_skip_subrelease_long_interval( + old_skip_subrelease_long_interval); +} + +TEST_P(HugePageAwareAllocatorTest, HardReleaseSmall) { + std::vector live, dead; + static const size_t N = kPagesPerHugePage.raw_num() * 128; + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; + for (int i = 0; i < N; ++i) { + Span* span = New(Length(1), kSpanInfo); + ((i % 2 == 0) ? live : dead).push_back(span); + } + + for (auto d : dead) { + Delete(d, kSpanInfo.objects_per_span); + } + + // Subrelease shouldn't release any pages by itself, but hard release using + // ReleaseAtLeastNPagesBreakingHugepages should release all the free pages. + EXPECT_EQ(ReleasePages(Length(1), + /*reason=*/PageReleaseReason::kReleaseMemoryToSystem), + Length(0)); + EXPECT_EQ(ReleaseAtLeastNPagesBreakingHugepages( + Length(1), /*reason=*/PageReleaseReason::kSoftLimitExceeded), + kPagesPerHugePage / 2); + + for (auto l : live) { + Delete(l, kSpanInfo.objects_per_span); + } +} + +TEST_P(HugePageAwareAllocatorTest, UseHugeRegion) { + // This test verifies that we use HugeRegion for large allocations as soon as + // the abandoned pages exceed 64MB, when we use abandoned count in addition to + // slack for determining when to use region. If we use slack for computation, + // this test should not trigger use of HugeRegion. + static constexpr Length kSlack = kPagesPerHugePage / 2 - Length(2); + static constexpr Length kSmallSize = kSlack; + static constexpr Length kLargeSize = kPagesPerHugePage - kSlack; + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; + + Length slack; + Length small_pages; + HugeLength donated_huge_pages; + Length abandoned_pages; + size_t active_regions; + BackingStats region_stats; + + auto RefreshStats = [&]() { + PageHeapSpinLockHolder l; + slack = allocator_->info().slack(); + small_pages = allocator_->info().small(); + donated_huge_pages = allocator_->DonatedHugePages(); + abandoned_pages = allocator_->AbandonedPages(); + active_regions = allocator_->region().ActiveRegions(); + region_stats = allocator_->region().stats(); + }; + + std::vector small_spans; + std::vector large_spans; + const Length small_binary_size = HLFromBytes(64 * 1024 * 1024).in_pages(); + Length expected_abandoned; + Length expected_slack; + int huge_pages = 0; + + // We first allocate large objects such that expected abandoned pages (once we + // deallocate those large objects) exceed the 64MB threshold. We place small + // allocations on the donated pages so that the hugepages aren't released. + while (true) { + Span* large = New(kLargeSize, kSpanInfo); + Span* small = New(kSmallSize, kSpanInfo); + large_spans.emplace_back(large); + small_spans.emplace_back(small); + ++huge_pages; + expected_abandoned += kLargeSize; + expected_slack += kSlack; + + RefreshStats(); + EXPECT_EQ(abandoned_pages, Length(0)); + EXPECT_EQ(donated_huge_pages, NHugePages(huge_pages)); + EXPECT_EQ(slack, expected_slack); + EXPECT_EQ(active_regions, 0); + if (expected_abandoned >= small_binary_size) break; + } + + // Reset the abandoned count and start releasing huge allocations. We should + // start accumulating abandoned pages in filler. As we don't expect to trigger + // HugeRegion yet, the number of active regions should be zero throughout. + expected_abandoned = Length(0); + for (auto l : large_spans) { + Delete(l, kSpanInfo.objects_per_span); + expected_abandoned += kLargeSize; + expected_slack -= kSlack; + RefreshStats(); + EXPECT_EQ(abandoned_pages, expected_abandoned); + EXPECT_EQ(donated_huge_pages, NHugePages(huge_pages)); + EXPECT_EQ(slack, expected_slack); + EXPECT_EQ(active_regions, 0); + } + large_spans.clear(); + + RefreshStats(); + EXPECT_EQ(slack, Length(0)); + EXPECT_GE(abandoned_pages, small_binary_size); + + // At this point, we have exhausted the 64MB slack for the donated pages to + // the filler. A large allocation should trigger allocation from a huge + // region if we are using huge regions more often. If we are using slack for + // determining when to use region, we should allocate from filler and the + // number of donated pages should continue to grow. + // + // We allocate a slightly larger object than before (kLargeSize + Length(1)) + // to make sure that filler doesn't try to pack it on the pages we released + // due to deallocations in the previous step. + static constexpr Length kSmallSize2 = kSmallSize - Length(1); + static constexpr Length kLargeSize2 = kLargeSize + Length(1); + + for (int i = 0; i < 100; ++i) { + Span* large = New(kLargeSize2, kSpanInfo); + Span* small = New(kSmallSize2, kSpanInfo); + large_spans.emplace_back(large); + small_spans.emplace_back(small); + RefreshStats(); + if (UseHugeRegionMoreOften()) { + EXPECT_EQ(abandoned_pages, expected_abandoned); + EXPECT_EQ(donated_huge_pages, NHugePages(huge_pages)); + EXPECT_EQ(active_regions, 1); + } else { + ASSERT_LT(slack, small_pages); + ++huge_pages; + EXPECT_EQ(abandoned_pages, expected_abandoned); + EXPECT_EQ(donated_huge_pages, NHugePages(huge_pages)); + EXPECT_EQ(active_regions, 0); + } + } + // Check stats to confirm that pages have been allocated from huge regions. + RefreshStats(); + size_t unmapped_bytes = region_stats.unmapped_bytes; + if (UseHugeRegionMoreOften()) { + EXPECT_GT(unmapped_bytes, 0); } - Parameters::set_hpaa_subrelease(old_subrelease); - Parameters::set_filler_skip_subrelease_interval(old_skip_subrelease); + // Deallocate large spans and make sure that HugeRegion does not unback that + // memory. This is because we do not unback objects during deallocation when a + // configuration to use huge region often is enabled. + for (auto l : large_spans) { + Delete(l, kSpanInfo.objects_per_span); + RefreshStats(); + EXPECT_EQ(region_stats.unmapped_bytes, unmapped_bytes); + } + + size_t backed_bytes = region_stats.system_bytes - region_stats.unmapped_bytes; + + // Release pages and make sure we release a few free-but-backed pages from + // huge region. As we release pages from HugeRegion gradually, first make sure + // that we do not release all the free pages. + if (UseHugeRegionMoreOften()) { + Length released; + { + PageHeapSpinLockHolder l; + released = allocator_->ReleaseAtLeastNPages( + Length(1), /*reason=*/PageReleaseReason::kReleaseMemoryToSystem); + } + EXPECT_GT(released.in_bytes(), 0); + EXPECT_LT(released.in_bytes(), backed_bytes); + RefreshStats(); + backed_bytes = region_stats.system_bytes - region_stats.unmapped_bytes; + + { + PageHeapSpinLockHolder l; + released = allocator_->ReleaseAtLeastNPages( + Length(1), /*reason=*/PageReleaseReason::kReleaseMemoryToSystem); + } + EXPECT_GT(released.in_bytes(), 0); + RefreshStats(); + backed_bytes = region_stats.system_bytes - region_stats.unmapped_bytes; + + Length backed_in_pages = LengthFromBytes(backed_bytes); + { + PageHeapSpinLockHolder l; + released = allocator_->ReleaseAtLeastNPagesBreakingHugepages( + backed_in_pages, /*reason=*/PageReleaseReason::kSoftLimitExceeded); + } + EXPECT_EQ(released, backed_in_pages); + RefreshStats(); + backed_bytes = region_stats.system_bytes - region_stats.unmapped_bytes; + EXPECT_EQ(backed_bytes, 0); + } + + for (auto s : small_spans) { + Delete(s, kSpanInfo.objects_per_span); + } } -TEST_F(HugePageAwareAllocatorTest, DonatedHugePages) { +TEST_P(HugePageAwareAllocatorTest, DonatedHugePages) { // This test verifies that we accurately measure the amount of RAM that we // donate to the huge page filler when making large allocations, including // those kept alive after we deallocate. static constexpr Length kSlack = Length(2); static constexpr Length kLargeSize = 2 * kPagesPerHugePage - kSlack; static constexpr Length kSmallSize = Length(1); + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; - Span* large1 = New(kLargeSize); + Span* large1 = New(kLargeSize, kSpanInfo); Length slack; HugeLength donated_huge_pages; - { - absl::base_internal::SpinLockHolder l(&pageheap_lock); + Length abandoned_pages; + + auto RefreshStats = [&]() { + PageHeapSpinLockHolder l; slack = allocator_->info().slack(); donated_huge_pages = allocator_->DonatedHugePages(); - } + abandoned_pages = allocator_->AbandonedPages(); + }; + RefreshStats(); + EXPECT_EQ(slack, kSlack); EXPECT_EQ(donated_huge_pages, NHugePages(1)); - + EXPECT_EQ(abandoned_pages, Length(0)); EXPECT_THAT(Print(), HasSubstr("filler donations 1")); - EXPECT_THAT(PrintInPbTxt(), HasSubstr("filler_donated_huge_pages: 1")); + EXPECT_THAT(PrintInPbtxt(), HasSubstr("filler_donated_huge_pages: 1")); + EXPECT_THAT(PrintInPbtxt(), HasSubstr("filler_abandoned_pages: 0")); // Make a small allocation and then free the large allocation. Slack should // fall, but we've kept alive our donation to the filler. - Span* small = New(kSmallSize); - Delete(large1); - { - absl::base_internal::SpinLockHolder l(&pageheap_lock); - slack = allocator_->info().slack(); - donated_huge_pages = allocator_->DonatedHugePages(); - } + Span* small = New(kSmallSize, kSpanInfo); + Delete(large1, kSpanInfo.objects_per_span); + + RefreshStats(); + EXPECT_EQ(slack, Length(0)); EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, kPagesPerHugePage - kSlack); - EXPECT_THAT(Print(), HasSubstr("filler donations 1")); - EXPECT_THAT(PrintInPbTxt(), HasSubstr("filler_donated_huge_pages: 1")); + EXPECT_THAT(Print(), HasSubstr(absl::StrCat("filler donations 1"))); + EXPECT_THAT(PrintInPbtxt(), HasSubstr("filler_donated_huge_pages: 1")); + EXPECT_THAT(PrintInPbtxt(), + HasSubstr(absl::StrCat("filler_abandoned_pages: ", + (kPagesPerHugePage - kSlack).raw_num()))); // Make another large allocation. The number of donated huge pages should // continue to increase. - Span* large2 = New(kLargeSize); - { - absl::base_internal::SpinLockHolder l(&pageheap_lock); - slack = allocator_->info().slack(); - donated_huge_pages = allocator_->DonatedHugePages(); - } + Span* large2 = New(kLargeSize, kSpanInfo); + + RefreshStats(); + EXPECT_EQ(slack, kSlack); EXPECT_EQ(donated_huge_pages, NHugePages(2)); + EXPECT_EQ(abandoned_pages, kPagesPerHugePage - kSlack); - EXPECT_THAT(Print(), HasSubstr("filler donations 2")); - EXPECT_THAT(PrintInPbTxt(), HasSubstr("filler_donated_huge_pages: 2")); + EXPECT_THAT(Print(), HasSubstr(absl::StrCat("filler donations 2"))); + EXPECT_THAT(PrintInPbtxt(), HasSubstr("filler_donated_huge_pages: 2")); + EXPECT_THAT(PrintInPbtxt(), + HasSubstr(absl::StrCat("filler_abandoned_pages: ", + (kPagesPerHugePage - kSlack).raw_num()))); + + // Deallocating the small allocation finally reduces the reduce the number of + // donations, as we were able reassemble the huge page for large1. + Delete(small, kSpanInfo.objects_per_span); + + RefreshStats(); - // Deallocating the small allocation does not reduce the number of donations, - // as we were unable to reassemble the VSS for large1. - Delete(small); - { - absl::base_internal::SpinLockHolder l(&pageheap_lock); - slack = allocator_->info().slack(); - donated_huge_pages = allocator_->DonatedHugePages(); - } EXPECT_EQ(slack, kSlack); - EXPECT_EQ(donated_huge_pages, NHugePages(2)); + EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, Length(0)); - EXPECT_THAT(Print(), HasSubstr("filler donations 2")); - EXPECT_THAT(PrintInPbTxt(), HasSubstr("filler_donated_huge_pages: 2")); + EXPECT_THAT(Print(), HasSubstr(absl::StrCat("filler donations 1"))); + EXPECT_THAT(PrintInPbtxt(), HasSubstr("filler_donated_huge_pages: 1")); + EXPECT_THAT(PrintInPbtxt(), HasSubstr("filler_abandoned_pages: 0")); // Deallocating everything should return slack to 0 and allow large2's // contiguous VSS to be reassembled. - Delete(large2); - { - absl::base_internal::SpinLockHolder l(&pageheap_lock); + Delete(large2, kSpanInfo.objects_per_span); + + RefreshStats(); + + EXPECT_EQ(slack, Length(0)); + EXPECT_EQ(donated_huge_pages, NHugePages(0)); + EXPECT_EQ(abandoned_pages, Length(0)); + + EXPECT_THAT(Print(), HasSubstr(absl::StrCat("filler donations 0"))); + EXPECT_THAT(PrintInPbtxt(), HasSubstr("filler_donated_huge_pages: 0")); + EXPECT_THAT(PrintInPbtxt(), HasSubstr("filler_abandoned_pages: 0")); +} + +TEST_P(HugePageAwareAllocatorTest, SmallDonations) { + // This test works with small donations (kHugePageSize/2,kHugePageSize]-bytes + // in size to check statistics. + static constexpr Length kSlack = Length(2); + static constexpr Length kLargeSize = kPagesPerHugePage - kSlack; + static constexpr Length kSmallSize = Length(1); + static constexpr Length kSmallSize2 = kSlack; + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; + + Span* large1 = New(kLargeSize, kSpanInfo); + Span* large2 = New(kLargeSize, kSpanInfo); + + Length slack; + HugeLength donated_huge_pages; + Length abandoned_pages; + + auto RefreshStats = [&]() { + PageHeapSpinLockHolder l; slack = allocator_->info().slack(); donated_huge_pages = allocator_->DonatedHugePages(); + abandoned_pages = allocator_->AbandonedPages(); + }; + RefreshStats(); + + EXPECT_EQ(slack, 2 * kSlack); + EXPECT_EQ(donated_huge_pages, NHugePages(2)); + EXPECT_EQ(abandoned_pages, Length(0)); + EXPECT_TRUE(large1->donated()); + EXPECT_TRUE(large2->donated()); + // HugePageAwareAllocatorTest.DonatedHugePages verifies Print works correctly + // for these stats. + + // Create two small allocations. They will be placed on different huge pages + // since kSmallSize+kSmallSize2 > kSlack for any single huge page. + Span* small1 = New(kSmallSize, kSpanInfo); + Span* small2 = New(kSmallSize2, kSpanInfo); + + RefreshStats(); + EXPECT_EQ(slack, 2 * kSlack); + EXPECT_EQ(donated_huge_pages, NHugePages(2)); + EXPECT_EQ(abandoned_pages, Length(0)); + EXPECT_FALSE(small1->donated()); + EXPECT_FALSE(small2->donated()); + + // To simplify the rest of the test, swap small1/small2 as required such that + // small1 is on the same huge page as large1, etc. This allows us to release + // 2 allocations from the same huge page. + if (HugePageContaining(large1->first_page()) != + HugePageContaining(small1->first_page())) { + std::swap(small1, small2); } + EXPECT_EQ(HugePageContaining(large1->first_page()), + HugePageContaining(small1->first_page())); + EXPECT_EQ(HugePageContaining(large2->first_page()), + HugePageContaining(small2->first_page())); + + // Release both allocations from one huge page. Donations should tick down + // and no pages should be considered abandoned. + Delete(large1, kSpanInfo.objects_per_span); + Delete(small1, kSpanInfo.objects_per_span); + + RefreshStats(); + EXPECT_EQ(slack, kSlack); + EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, Length(0)); + + // Delete the large allocation on the second huge page. Abandoned should tick + // up. + Delete(large2, kSpanInfo.objects_per_span); + + RefreshStats(); EXPECT_EQ(slack, Length(0)); EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, kLargeSize); - EXPECT_THAT(Print(), HasSubstr("filler donations 1")); - EXPECT_THAT(PrintInPbTxt(), HasSubstr("filler_donated_huge_pages: 1")); + // Reuse large2 and then deallocate it. Our abandoned count stats should not + // be double counted. + large2 = New(kLargeSize, kSpanInfo); + + RefreshStats(); + EXPECT_EQ(slack, kSlack); + EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, kLargeSize); + + Delete(large2, kSpanInfo.objects_per_span); + RefreshStats(); + EXPECT_EQ(slack, Length(0)); + EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, kLargeSize); + + // Cleanup + Delete(small2, kSpanInfo.objects_per_span); + + RefreshStats(); + EXPECT_EQ(slack, Length(0)); + EXPECT_EQ(donated_huge_pages, NHugePages(0)); + EXPECT_EQ(abandoned_pages, Length(0)); } -TEST_F(HugePageAwareAllocatorTest, PageMapInterference) { +TEST_P(HugePageAwareAllocatorTest, LargeDonations) { + // A small allocation of size (kHugePageSize/2,kHugePageSize]-bytes can be + // considered not donated if it filled in a gap on an otherwise mostly free + // huge page that came from a donation. + static constexpr Length kSmallSize = kPagesPerHugePage - Length(1); + static constexpr Length kLargeSize = kPagesPerHugePage + Length(1); + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; + + // large1 donates kSmallSize bytes to the filler. + Span* large = New(kLargeSize, kSpanInfo); + Length slack; + HugeLength donated_huge_pages; + Length abandoned_pages; + + auto RefreshStats = [&]() { + PageHeapSpinLockHolder l; + slack = allocator_->info().slack(); + donated_huge_pages = allocator_->DonatedHugePages(); + abandoned_pages = allocator_->AbandonedPages(); + }; + RefreshStats(); + + EXPECT_EQ(slack, kSmallSize); + EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, Length(0)); + EXPECT_TRUE(large->donated()); + // HugePageAwareAllocatorTest.DonatedHugePages verifies Print works correctly + // for these stats. + + Span* small = New(kSmallSize, kSpanInfo); + RefreshStats(); + + // TODO(b/199203282): Current slack computation is unaware that this + // allocation is on a donated page. It assumes that kSmallSize allocation + // would also result in a slack. We would eliminate this once abandoned count + // subsumes slack computation. + EXPECT_EQ(slack, kSmallSize + Length(1)); + EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, Length(0)); + EXPECT_FALSE(small->donated()); + + // small is on a donated hugepage. None of the stats should change when it is + // deallocated. + Delete(small, kSpanInfo.objects_per_span); + RefreshStats(); + EXPECT_EQ(slack, kSmallSize); + EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, Length(0)); + + // Cleanup. Deallocate large. + Delete(large, kSpanInfo.objects_per_span); + RefreshStats(); + EXPECT_EQ(slack, Length(0)); + EXPECT_EQ(donated_huge_pages, NHugePages(0)); + EXPECT_EQ(abandoned_pages, Length(0)); +} + +TEST_P(HugePageAwareAllocatorTest, TailDonation) { + // This test makes sure that we account for tail donations alone in the + // abandoned pages. + static constexpr Length kSmallSize = Length(1); + static constexpr Length kSlack = kPagesPerHugePage - Length(1); + static constexpr Length kLargeSize = 2 * kPagesPerHugePage - kSlack; + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; + + // large donates kSlack to the filler. + Span* large = New(kLargeSize, kSpanInfo); + Length slack; + HugeLength donated_huge_pages; + Length abandoned_pages; + + auto RefreshStats = [&]() { + PageHeapSpinLockHolder l; + slack = allocator_->info().slack(); + donated_huge_pages = allocator_->DonatedHugePages(); + abandoned_pages = allocator_->AbandonedPages(); + }; + RefreshStats(); + + EXPECT_EQ(slack, kSlack); + EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, Length(0)); + EXPECT_TRUE(large->donated()); + + // We should allocate small on the donated page. + Span* small = New(kSmallSize, kSpanInfo); + RefreshStats(); + EXPECT_EQ(slack, kSlack); + EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, Length(0)); + EXPECT_FALSE(small->donated()); + + // When we deallocate large, abandoned count should only account for the + // abandoned pages from the tail huge page. + Delete(large, kSpanInfo.objects_per_span); + RefreshStats(); + EXPECT_EQ(slack, Length(0)); + EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, Length(1)); + + // small is on a donated hugepage. Cleanup. + Delete(small, kSpanInfo.objects_per_span); + RefreshStats(); + EXPECT_EQ(slack, Length(0)); + EXPECT_EQ(donated_huge_pages, NHugePages(0)); + EXPECT_EQ(abandoned_pages, Length(0)); + + // large donates kSlack to the filler. + large = New(kLargeSize, kSpanInfo); + RefreshStats(); + EXPECT_EQ(slack, kSlack); + EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, Length(0)); + EXPECT_TRUE(large->donated()); + + // We should allocate small on the donated page. + small = New(kSmallSize, kSpanInfo); + RefreshStats(); + EXPECT_EQ(slack, kSlack); + EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, Length(0)); + + // If we delete small first, abandoned_pages should not tick up. + Delete(small, kSpanInfo.objects_per_span); + RefreshStats(); + EXPECT_EQ(slack, kSlack); + EXPECT_EQ(donated_huge_pages, NHugePages(1)); + EXPECT_EQ(abandoned_pages, Length(0)); + + // Deallocating large. Cleanup. All stats should reset to zero. + Delete(large, kSpanInfo.objects_per_span); + RefreshStats(); + EXPECT_EQ(slack, Length(0)); + EXPECT_EQ(donated_huge_pages, NHugePages(0)); + EXPECT_EQ(abandoned_pages, Length(0)); +} + +TEST_P(HugePageAwareAllocatorTest, NotDonated) { + // A small allocation of size (kHugePageSize/2,kHugePageSize]-bytes can be + // considered not donated if it filled in a gap on an otherwise mostly free + // huge page. + static constexpr Length kSmallSize = Length(1); + static constexpr Length kLargeSize = kPagesPerHugePage - kSmallSize; + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; + + Span* small = New(kSmallSize, kSpanInfo); + + Length slack; + HugeLength donated_huge_pages; + Length abandoned_pages; + + auto RefreshStats = [&]() { + PageHeapSpinLockHolder l; + slack = allocator_->info().slack(); + donated_huge_pages = allocator_->DonatedHugePages(); + abandoned_pages = allocator_->AbandonedPages(); + }; + RefreshStats(); + + EXPECT_EQ(slack, Length(0)); + EXPECT_EQ(donated_huge_pages, NHugePages(0)); + EXPECT_EQ(abandoned_pages, Length(0)); + EXPECT_FALSE(small->donated()); + + // We should allocate large on the free huge page. That is, this allocation + // should not cause any donations to filler. + Span* large = New(kLargeSize, kSpanInfo); + + RefreshStats(); + // large contributes slack, but isn't donated. + EXPECT_EQ(slack, kSmallSize); + EXPECT_EQ(donated_huge_pages, NHugePages(0)); + EXPECT_EQ(abandoned_pages, Length(0)); + EXPECT_FALSE(large->donated()); + + Delete(large, kSpanInfo.objects_per_span); + RefreshStats(); + // large contributes slack, but isn't donated. + EXPECT_EQ(slack, Length(0)); + EXPECT_EQ(donated_huge_pages, NHugePages(0)); + EXPECT_EQ(abandoned_pages, Length(0)); + + // Cleanup. + Delete(small, kSpanInfo.objects_per_span); + RefreshStats(); + EXPECT_EQ(slack, Length(0)); + EXPECT_EQ(donated_huge_pages, NHugePages(0)); + EXPECT_EQ(abandoned_pages, Length(0)); +} + +TEST_P(HugePageAwareAllocatorTest, PageMapInterference) { // This test manipulates the test HugePageAwareAllocator while making // allocations/deallocations that interact with the real PageAllocator. The // two share a global PageMap. // // If this test begins failing, the two are likely conflicting by violating // invariants in the PageMap. + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; std::vector allocs; for (int i : {10, 20, 30}) { auto n = Length(i << 7); - allocs.push_back(New(n)); + allocs.push_back(New(n, kSpanInfo)); } for (auto* a : allocs) { - Delete(a); + Delete(a, kSpanInfo.objects_per_span); } allocs.clear(); @@ -433,21 +1123,22 @@ TEST_F(HugePageAwareAllocatorTest, PageMapInterference) { // Do the same, but allocate something on the real page heap. for (int i : {10, 20, 30}) { auto n = Length(i << 7); - allocs.push_back(New(n)); + allocs.push_back(New(n, kSpanInfo)); ::operator delete(::operator new(1 << 20)); } for (auto* a : allocs) { - Delete(a); + Delete(a, kSpanInfo.objects_per_span); } } -TEST_F(HugePageAwareAllocatorTest, LargeSmall) { +TEST_P(HugePageAwareAllocatorTest, LargeSmall) { const int kIters = 2000; const Length kSmallPages = Length(1); // Large block must be larger than 1 huge page. const Length kLargePages = 2 * kPagesPerHugePage - kSmallPages; + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; std::vector small_allocs; // Repeatedly allocate large and small allocations that fit into a multiple of @@ -456,25 +1147,25 @@ TEST_F(HugePageAwareAllocatorTest, LargeSmall) { // without bound, keeping many huge pages alive because of the small // allocations. for (int i = 0; i < kIters; i++) { - Span* large = New(kLargePages); + Span* large = New(kLargePages, kSpanInfo); ASSERT_NE(large, nullptr); - Span* small = New(kSmallPages); + Span* small = New(kSmallPages, kSpanInfo); ASSERT_NE(small, nullptr); small_allocs.push_back(small); - Delete(large); + Delete(large, kSpanInfo.objects_per_span); } BackingStats stats; { - absl::base_internal::SpinLockHolder h(&pageheap_lock); + PageHeapSpinLockHolder l; stats = allocator_->stats(); } constexpr size_t kBufferSize = 1024 * 1024; char buffer[kBufferSize]; Printer printer(buffer, kBufferSize); - allocator_->Print(&printer); + allocator_->Print(printer); // Verify that we have less free memory than we allocated in total. We have // to account for bytes tied up in the cache. EXPECT_LE(stats.free_bytes - allocator_->cache()->size().in_bytes(), @@ -482,89 +1173,103 @@ TEST_F(HugePageAwareAllocatorTest, LargeSmall) { << buffer; for (Span* small : small_allocs) { - Delete(small); + Delete(small, kSpanInfo.objects_per_span); } } // Tests an edge case in hugepage donation behavior. -TEST_F(HugePageAwareAllocatorTest, DonatedPageLists) { +TEST_P(HugePageAwareAllocatorTest, DonatedPageLists) { const Length kSmallPages = Length(1); // Large block must be larger than 1 huge page. const Length kLargePages = 2 * kPagesPerHugePage - 2 * kSmallPages; + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; - Span* large = New(kLargePages); + Span* large = New(kLargePages, kSpanInfo); ASSERT_NE(large, nullptr); // Allocating small1 moves the backing huge page off of the donated pages // list. - Span* small1 = New(kSmallPages); + Span* small1 = New(kSmallPages, kSpanInfo); ASSERT_NE(small1, nullptr); // This delete needs to have put the origin PageTracker back onto the right // free list. - Delete(small1); + Delete(small1, kSpanInfo.objects_per_span); // This otherwise fails. - Span* small2 = New(kSmallPages); + Span* small2 = New(kSmallPages, kSpanInfo); ASSERT_NE(small2, nullptr); - Delete(small2); + Delete(small2, kSpanInfo.objects_per_span); // Clean up. - Delete(large); + Delete(large, kSpanInfo.objects_per_span); } -TEST_F(HugePageAwareAllocatorTest, DonationAccounting) { +TEST_P(HugePageAwareAllocatorTest, DonationAccounting) { const Length kSmallPages = Length(2); const Length kOneHugePageDonation = kPagesPerHugePage - kSmallPages; const Length kMultipleHugePagesDonation = 3 * kPagesPerHugePage - kSmallPages; + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; // Each of these allocations should count as one donation, but only if they // are actually being reused. - Span* large = New(kOneHugePageDonation); + Span* large = New(kOneHugePageDonation, kSpanInfo); ASSERT_NE(large, nullptr); // This allocation ensures that the donation is not counted. - Span* small = New(kSmallPages); + Span* small = New(kSmallPages, kSpanInfo); ASSERT_NE(small, nullptr); - Span* large2 = New(kMultipleHugePagesDonation); + Span* large2 = New(kMultipleHugePagesDonation, kSpanInfo); ASSERT_NE(large2, nullptr); // This allocation ensures that the donation is not counted. - Span* small2 = New(kSmallPages); + Span* small2 = New(kSmallPages, kSpanInfo); ASSERT_NE(small2, nullptr); - Span* large3 = New(kOneHugePageDonation); + Span* large3 = New(kOneHugePageDonation, kSpanInfo); ASSERT_NE(large3, nullptr); - Span* large4 = New(kMultipleHugePagesDonation); + Span* large4 = New(kMultipleHugePagesDonation, kSpanInfo); ASSERT_NE(large4, nullptr); + HugeLength donated; + // Check donation count. + { + PageHeapSpinLockHolder l; + donated = allocator_->DonatedHugePages(); + } + EXPECT_EQ(donated, NHugePages(4)); + // Clean up. - Delete(large); - Delete(large2); - Delete(large3); - Delete(large4); - Delete(small); - Delete(small2); + Delete(large, kSpanInfo.objects_per_span); + Delete(large2, kSpanInfo.objects_per_span); + Delete(large3, kSpanInfo.objects_per_span); + Delete(large4, kSpanInfo.objects_per_span); + Delete(small, kSpanInfo.objects_per_span); + Delete(small2, kSpanInfo.objects_per_span); // Check donation count. - absl::base_internal::SpinLockHolder h(&pageheap_lock); - CHECK_CONDITION(NHugePages(2) == allocator_->DonatedHugePages()); + { + PageHeapSpinLockHolder l; + donated = allocator_->DonatedHugePages(); + } + EXPECT_EQ(donated, NHugePages(0)); } // We'd like to test OOM behavior but this, err, OOMs. :) // (Usable manually in controlled environments. -TEST_F(HugePageAwareAllocatorTest, DISABLED_OOM) { +TEST_P(HugePageAwareAllocatorTest, DISABLED_OOM) { std::vector objs; auto n = Length(1); + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; while (true) { - Span* s = New(n); + Span* s = New(n, kSpanInfo); if (!s) break; objs.push_back(s); n *= 2; } for (auto s : objs) { - Delete(s); + Delete(s, kSpanInfo.objects_per_span); } } @@ -573,7 +1278,7 @@ struct MemoryBytes { uint64_t phys; }; -int64_t pagesize = getpagesize(); +int64_t pagesize = GetPageSize(); static size_t BytesInCore(void* p, size_t len) { static const size_t kBufSize = 1024; @@ -584,9 +1289,7 @@ static size_t BytesInCore(void* p, size_t len) { // We call mincore in bounded size chunks (though typically one // chunk will cover an entire request.) const size_t chunk_len = std::min(kChunk, len); - if (mincore(p, chunk_len, buf) != 0) { - Crash(kCrash, __FILE__, __LINE__, "mincore failed, errno", errno); - } + TC_CHECK_EQ(0, mincore(p, chunk_len, buf), "errno=%d", errno); const size_t lim = chunk_len / pagesize; for (size_t i = 0; i < lim; ++i) { if (buf[i] & 1) resident += pagesize; @@ -653,54 +1356,10 @@ void TouchTHP(Span* s) { // and without the validation class StatTest : public testing::Test { protected: - StatTest() : rng_() {} - - class RegionFactory; + StatTest() = default; - class Region : public AddressRegion { + class Forwarder : public huge_page_allocator_internal::StaticForwarder { public: - Region(AddressRegion* underlying, RegionFactory* factory) - : underlying_(underlying), factory_(factory) {} - - std::pair Alloc(size_t size, size_t alignment) override { - std::pair ret = underlying_->Alloc(size, alignment); - if (!ret.first) return {nullptr, 0}; - - // we only support so many allocations here for simplicity - CHECK_CONDITION(factory_->n_ < factory_->kNumAllocs); - // Anything coming from the test allocator will request full - // alignment. Metadata allocations will not. Since we can't - // control the backing of metadata allocations, elide them. - // TODO(b/128521238): this is not a good way to do this. - if (alignment >= kHugePageSize) { - factory_->allocs_[factory_->n_] = ret; - factory_->n_++; - } - return ret; - } - - private: - AddressRegion* underlying_; - RegionFactory* factory_; - }; - - class RegionFactory : public AddressRegionFactory { - public: - explicit RegionFactory(AddressRegionFactory* underlying) - : underlying_(underlying), n_(0) {} - - AddressRegion* Create(void* start, size_t size, UsageHint hint) override { - AddressRegion* underlying_region = underlying_->Create(start, size, hint); - CHECK_CONDITION(underlying_region); - void* region_space = MallocInternal(sizeof(Region)); - CHECK_CONDITION(region_space); - return new (region_space) Region(underlying_region, this); - } - - size_t GetStats(absl::Span buffer) override { - return underlying_->GetStats(buffer); - } - MemoryBytes Memory() { MemoryBytes b = {0, 0}; for (int i = 0; i < n_; ++i) { @@ -713,62 +1372,69 @@ class StatTest : public testing::Test { return b; } - AddressRegionFactory* underlying() const { return underlying_; } + // Provide hooked versions of AllocatePages + AddressRange AllocatePages(size_t bytes, size_t align, MemoryTag tag) { + auto& underlying = *static_cast(this); + auto range = underlying.AllocatePages(bytes, align, tag); - private: - friend class Region; - AddressRegionFactory* underlying_; + // we only support so many allocations here for simplicity + TC_CHECK_LT(n_, kNumAllocs); + if (tag != MemoryTag::kMetadata) { + allocs_[n_] = {range.ptr, range.bytes}; + n_++; + } + return range; + } + + private: static constexpr size_t kNumAllocs = 1000; - size_t n_; - std::pair allocs_[kNumAllocs]; + size_t n_ = 0; + std::pair allocs_[kNumAllocs] = {}; }; + using HookedAllocator = + huge_page_allocator_internal::HugePageAwareAllocator; + // Carefully get memory usage without touching anything. - MemoryBytes GetSystemBytes() { return replacement_region_factory_.Memory(); } + MemoryBytes GetSystemBytes() { return alloc_->forwarder().Memory(); } // This is essentially a test case set up, but run manually - // we can't guarantee gunit won't malloc between. void PrepTest() { - memset(buf, 0, sizeof(buf)); - MallocExtension::ReleaseMemoryToSystem(std::numeric_limits::max()); - SetRegionFactory(&replacement_region_factory_); - alloc = new (buf) HugePageAwareAllocator(MemoryTag::kNormal); + memset(buf_, 0, sizeof(buf_)); + alloc_ = new (buf_) + HookedAllocator(HugePageAwareAllocatorOptions{MemoryTag::kNormal}); } - ~StatTest() override { - SetRegionFactory(replacement_region_factory_.underlying()); - } + ~StatTest() override = default; BackingStats Stats() { - absl::base_internal::SpinLockHolder h(&pageheap_lock); - BackingStats stats = alloc->stats(); + PageHeapSpinLockHolder l; + BackingStats stats = alloc_->stats(); return stats; } // Use bigger allocs here to ensure growth: - Length RandomAllocSize() { + Length RandomAllocSize(absl::BitGenRef rng) { // Since we touch all of the pages, try to avoid OOM'ing by limiting the // number of big allocations. const Length kMaxBigAllocs = Length(4096); - if (big_allocs_ < kMaxBigAllocs && absl::Bernoulli(rng_, 1.0 / 50)) { + if (big_allocs_ < kMaxBigAllocs && absl::Bernoulli(rng, 1.0 / 50)) { auto n = - Length(1024 * (1 + absl::LogUniform(rng_, 0, (1 << 9) - 1))); - n += Length(absl::Uniform(rng_, 0, 1024)); + Length(1024 * (1 + absl::LogUniform(rng, 0, (1 << 9) - 1))); + n += Length(absl::Uniform(rng, 0, 1024)); big_allocs_ += n; return n; } - return Length(1 + absl::LogUniform(rng_, 0, (1 << 10) - 1)); + return Length(1 + absl::LogUniform(rng, 0, (1 << 10) - 1)); } - Span* Alloc(Length n) { - Span* span = alloc->New(n); + Span* Alloc(Length n, SpanAllocInfo span_info) { + Span* span = alloc_->New(n, span_info); TouchTHP(span); - if (n > span->num_pages()) { - Crash(kCrash, __FILE__, __LINE__, n.raw_num(), - "not <=", span->num_pages().raw_num()); - } + TC_CHECK_LE(n, span->num_pages()); n = span->num_pages(); if (n > longest_) longest_ = n; total_ += n; @@ -776,13 +1442,21 @@ class StatTest : public testing::Test { return span; } - void Free(Span* s) { + void Free(Span* s, SpanAllocInfo span_info) { Length n = s->num_pages(); total_ -= n; - { - absl::base_internal::SpinLockHolder h(&pageheap_lock); - alloc->Delete(s); - } +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + PageHeapSpinLockHolder l; + alloc_->Delete(s); +#else + PageAllocatorInterface::AllocationState a{ + Range(s->first_page(), s->num_pages()), + s->donated(), + }; + alloc_->forwarder().DeleteSpan(s); + PageHeapSpinLockHolder l; + alloc_->Delete(a); +#endif // TCMALLOC_INTERNAL_LEGACY_LOCKING } void CheckStats() { @@ -791,9 +1465,9 @@ class StatTest : public testing::Test { SmallSpanStats small; LargeSpanStats large; { - absl::base_internal::SpinLockHolder h(&pageheap_lock); - alloc->GetSmallSpanStats(&small); - alloc->GetLargeSpanStats(&large); + PageHeapSpinLockHolder l; + alloc_->GetSmallSpanStats(&small); + alloc_->GetLargeSpanStats(&large); } size_t span_stats_free_bytes = 0, span_stats_released_bytes = 0; @@ -805,30 +1479,19 @@ class StatTest : public testing::Test { span_stats_free_bytes += large.normal_pages.in_bytes(); span_stats_released_bytes += large.returned_pages.in_bytes(); -#ifndef __ppc__ const size_t alloced_bytes = total_.in_bytes(); -#endif ASSERT_EQ(here.virt, stats.system_bytes); -#ifndef __ppc__ const size_t actual_unmapped = here.virt - here.phys; -#endif - // TODO(b/122551676): On PPC, our release granularity may be smaller than - // the system page size, so we may not actually unmap memory that we expect. - // Pending using the return value of madvise, relax this constraint. -#ifndef __ppc__ ASSERT_EQ(actual_unmapped, stats.unmapped_bytes); ASSERT_EQ(here.phys, stats.free_bytes + alloced_bytes); ASSERT_EQ(alloced_bytes, stats.system_bytes - stats.free_bytes - stats.unmapped_bytes); -#endif ASSERT_EQ(stats.free_bytes, span_stats_free_bytes); ASSERT_EQ(stats.unmapped_bytes, span_stats_released_bytes); } - char buf[sizeof(HugePageAwareAllocator)]; - HugePageAwareAllocator* alloc; - RegionFactory replacement_region_factory_{GetRegionFactory()}; - absl::BitGen rng_; + char buf_[sizeof(HookedAllocator)]; + HookedAllocator* alloc_; Length total_; Length longest_; @@ -838,52 +1501,53 @@ class StatTest : public testing::Test { TEST_F(StatTest, Basic) { static const size_t kNumAllocs = 500; + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; + absl::BitGen rng; Span* allocs[kNumAllocs]; - const bool always_check_usage = absl::GetFlag(FLAGS_always_check_usage); - PrepTest(); // DO NOT MALLOC ANYTHING BELOW THIS LINE! WE'RE TRYING TO CAREFULLY COUNT // ALLOCATIONS. // (note we can't stop background threads, but hopefully they're idle enough.) for (int i = 0; i < kNumAllocs; ++i) { - Length k = RandomAllocSize(); - allocs[i] = Alloc(k); + Length k = RandomAllocSize(rng); + allocs[i] = Alloc(k, kSpanInfo); // stats are expensive, don't always check - if (i % 10 != 0 && !always_check_usage) continue; + if (i % 10 != 0) continue; CheckStats(); } static const size_t kReps = 1000; for (int i = 0; i < kReps; ++i) { - size_t index = absl::Uniform(rng_, 0, kNumAllocs); + size_t index = absl::Uniform(rng, 0, kNumAllocs); - Free(allocs[index]); - Length k = RandomAllocSize(); - allocs[index] = Alloc(k); + Free(allocs[index], kSpanInfo); + Length k = RandomAllocSize(rng); + allocs[index] = Alloc(k, kSpanInfo); - if (absl::Bernoulli(rng_, 1.0 / 3)) { - Length pages(absl::LogUniform(rng_, 0, (1 << 10) - 1) + 1); - absl::base_internal::SpinLockHolder h(&pageheap_lock); - alloc->ReleaseAtLeastNPages(pages); + if (absl::Bernoulli(rng, 1.0 / 3)) { + Length pages(absl::LogUniform(rng, 0, (1 << 10) - 1) + 1); + PageHeapSpinLockHolder l; + alloc_->ReleaseAtLeastNPages( + pages, /*reason=*/PageReleaseReason::kReleaseMemoryToSystem); } // stats are expensive, don't always check - if (i % 10 != 0 && !always_check_usage) continue; + if (i % 10 != 0) continue; CheckStats(); } for (int i = 0; i < kNumAllocs; ++i) { - Free(allocs[i]); - if (i % 10 != 0 && !always_check_usage) continue; + Free(allocs[i], kSpanInfo); + if (i % 10 != 0) continue; CheckStats(); } { CheckStats(); pageheap_lock.Lock(); - auto final_stats = alloc->stats(); + auto final_stats = alloc_->stats(); pageheap_lock.Unlock(); ASSERT_EQ(final_stats.free_bytes + final_stats.unmapped_bytes, final_stats.system_bytes); @@ -892,9 +1556,10 @@ TEST_F(StatTest, Basic) { // test over, malloc all you like } -TEST_F(HugePageAwareAllocatorTest, ParallelRelease) { +TEST_P(HugePageAwareAllocatorTest, ParallelRelease) { ThreadManager threads; constexpr int kThreads = 10; + const SpanAllocInfo kSpanInfo = {1, AccessDensityPrediction::kSparse}; struct ABSL_CACHELINE_ALIGNED Metadata { absl::BitGen rng; @@ -908,7 +1573,8 @@ TEST_F(HugePageAwareAllocatorTest, ParallelRelease) { Metadata& m = metadata[thread_id]; if (thread_id == 0) { - ReleasePages(Length(absl::Uniform(m.rng, 1, 1 << 10))); + ReleasePages(Length(absl::Uniform(m.rng, 1, 1 << 10)), + /*reason=*/PageReleaseReason::kReleaseMemoryToSystem); return; } else if (thread_id == 1) { benchmark::DoNotOptimize(Print()); @@ -916,15 +1582,9 @@ TEST_F(HugePageAwareAllocatorTest, ParallelRelease) { } if (absl::Bernoulli(m.rng, 0.6) || m.spans.empty()) { - Span* s = AllocatorNew(Length(absl::LogUniform(m.rng, 1, 1 << 10))); - CHECK_CONDITION(s != nullptr); - - // Touch the contents of the buffer. We later use it to verify we are the - // only thread manipulating the Span, for example, if another thread - // madvise DONTNEED'd the contents and zero'd them. - const uintptr_t key = reinterpret_cast(s) ^ thread_id; - *reinterpret_cast(s->start_address()) = key; - + Span* s = + AllocatorNew(Length(absl::LogUniform(m.rng, 1, 1 << 10)), kSpanInfo); + TC_CHECK_NE(s, nullptr); m.spans.push_back(s); } else { size_t index = absl::Uniform(m.rng, 0, m.spans.size()); @@ -934,10 +1594,7 @@ TEST_F(HugePageAwareAllocatorTest, ParallelRelease) { m.spans[index] = back; m.spans.pop_back(); - const uintptr_t key = reinterpret_cast(s) ^ thread_id; - EXPECT_EQ(*reinterpret_cast(s->start_address()), key); - - AllocatorDelete(s); + AllocatorDelete(s, kSpanInfo.objects_per_span); } }); @@ -947,11 +1604,345 @@ TEST_F(HugePageAwareAllocatorTest, ParallelRelease) { for (auto& m : metadata) { for (Span* s : m.spans) { - AllocatorDelete(s); + AllocatorDelete(s, kSpanInfo.objects_per_span); } } } +INSTANTIATE_TEST_SUITE_P( + All, HugePageAwareAllocatorTest, + testing::Values(HugeRegionUsageOption::kDefault, + HugeRegionUsageOption::kUseForAllLargeAllocs)); + +// This is set to ensure that .in_bytes() doesn't overflow 64-bit size_t. +inline constexpr Length kMaxLength = + Length(std::numeric_limits::max()); + +using FakeHugePageAwareAllocator = + huge_page_allocator_internal::HugePageAwareAllocator< + huge_page_allocator_internal::FakeStaticForwarder>; +struct SpanDeleter { + explicit SpanDeleter(absl::Nonnull allocator) + : allocator(*allocator) {} + + void operator()(Span* s) ABSL_LOCKS_EXCLUDED(pageheap_lock) { +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + PageHeapSpinLockHolder l; + allocator.Delete(s); +#else + PageAllocatorInterface::AllocationState a{ + Range(s->first_page(), s->num_pages()), + s->donated(), + }; + allocator.forwarder().DeleteSpan(s); + PageHeapSpinLockHolder l; + allocator.Delete(a); +#endif // TCMALLOC_INTERNAL_LEGACY_LOCKING + } + + FakeHugePageAwareAllocator& allocator; +}; + +using SpanUniquePtr = std::unique_ptr; + +class GetReleaseStatsTest : public testing::Test { + public: + void SetUp() override { + // Use SetUp instead of a constructor so that we can make assertions. + MallocExtension::SetRegionFactory(&factory_); + + allocator_ = new (allocator_storage_.data()) + FakeHugePageAwareAllocator({.tag = MemoryTag::kNormal}); + + allocator_->forwarder().set_hpaa_subrelease(/*value=*/false); + allocator_->forwarder().set_huge_cache_demand_based_release( + /*value=*/false); + allocator_->forwarder().set_huge_region_demand_based_release( + /*value=*/false); + allocator_->forwarder().set_filler_skip_subrelease_interval( + absl::ZeroDuration()); + allocator_->forwarder().set_filler_skip_subrelease_short_interval( + absl::ZeroDuration()); + allocator_->forwarder().set_filler_skip_subrelease_long_interval( + absl::ZeroDuration()); + + ASSERT_EQ(ReleaseAtLeastNPagesBreakingHugepages( + kMaxLength, + /*reason=*/PageReleaseReason::kReleaseMemoryToSystem), + Length(0)); + + ASSERT_EQ(GetReleaseStats(), PageReleaseStats{}); + } + + ~GetReleaseStatsTest() override { + ReleaseAtLeastNPagesBreakingHugepages( + Length(std::numeric_limits::max()), + /*reason=*/PageReleaseReason::kReleaseMemoryToSystem); + + MallocExtension::SetRegionFactory(previous_factory_); + }; + + FakeHugePageAwareAllocator& allocator() { return *allocator_; } + + PageReleaseStats GetReleaseStats() ABSL_LOCKS_EXCLUDED(pageheap_lock) { + const PageHeapSpinLockHolder l; + return allocator().GetReleaseStats(); + } + + SpanUniquePtr New(Length n, AccessDensityPrediction density = + AccessDensityPrediction::kDense) + ABSL_LOCKS_EXCLUDED(pageheap_lock) { + return {allocator().New(n, {.objects_per_span = 1, .density = density}), + SpanDeleter(&allocator())}; + } + + Length ReleaseAtLeastNPages(Length n, PageReleaseReason reason) + ABSL_LOCKS_EXCLUDED(pageheap_lock) { + const PageHeapSpinLockHolder l; + return allocator().ReleaseAtLeastNPages(n, reason); + } + + Length ReleaseAtLeastNPagesBreakingHugepages(Length n, + PageReleaseReason reason) + ABSL_LOCKS_EXCLUDED(pageheap_lock) { + const PageHeapSpinLockHolder l; + return allocator().ReleaseAtLeastNPagesBreakingHugepages(n, reason); + } + + protected: + AddressRegionFactory* const previous_factory_ = + MallocExtension::GetRegionFactory(); + + ExtraRegionFactory factory_{previous_factory_}; + + alignas(FakeHugePageAwareAllocator) std::array< + unsigned char, sizeof(FakeHugePageAwareAllocator)> allocator_storage_; + FakeHugePageAwareAllocator* allocator_; +}; + +TEST_F(GetReleaseStatsTest, GetReleaseStats) { + SpanUniquePtr huge_page = New(kPagesPerHugePage); + ASSERT_TRUE(huge_page != nullptr); + EXPECT_EQ(GetReleaseStats(), PageReleaseStats{}); + + EXPECT_EQ(ReleaseAtLeastNPages( + kMaxLength, + /*reason=*/PageReleaseReason::kReleaseMemoryToSystem), + Length(0)); + EXPECT_EQ(GetReleaseStats(), PageReleaseStats{}); + + huge_page.reset(); + EXPECT_EQ(GetReleaseStats(), PageReleaseStats{}); + + EXPECT_EQ(ReleaseAtLeastNPages( + kMaxLength, + /*reason=*/PageReleaseReason::kReleaseMemoryToSystem), + kPagesPerHugePage); + EXPECT_EQ(GetReleaseStats(), + (PageReleaseStats{ + .total = kPagesPerHugePage, + .release_memory_to_system = kPagesPerHugePage, + })); +} + +TEST_F(GetReleaseStatsTest, ReasonsTrackedSeparately) { + SpanUniquePtr release_memory_to_system = New(kPagesPerHugePage); + ASSERT_TRUE(release_memory_to_system != nullptr); + + SpanUniquePtr process_background_actions = New(kPagesPerHugePage); + ASSERT_TRUE(process_background_actions != nullptr); + + SpanUniquePtr soft_limit_exceeded = New(kPagesPerHugePage); + ASSERT_TRUE(soft_limit_exceeded != nullptr); + + SpanUniquePtr hard_limit_exceeded = New(kPagesPerHugePage); + ASSERT_TRUE(hard_limit_exceeded != nullptr); + + EXPECT_EQ( + ReleaseAtLeastNPages( + kMaxLength, /*reason=*/PageReleaseReason::kReleaseMemoryToSystem), + Length(0)); + + release_memory_to_system.reset(); + EXPECT_EQ( + ReleaseAtLeastNPages( + kMaxLength, /*reason=*/PageReleaseReason::kReleaseMemoryToSystem), + kPagesPerHugePage); + EXPECT_EQ(GetReleaseStats(), + (PageReleaseStats{ + .total = kPagesPerHugePage, + .release_memory_to_system = kPagesPerHugePage, + })); + + process_background_actions.reset(); + EXPECT_EQ( + ReleaseAtLeastNPages( + kMaxLength, /*reason=*/PageReleaseReason::kProcessBackgroundActions), + kPagesPerHugePage); + EXPECT_EQ(GetReleaseStats(), + (PageReleaseStats{ + .total = kPagesPerHugePage * 2, + .release_memory_to_system = kPagesPerHugePage, + .process_background_actions = kPagesPerHugePage, + })); + + soft_limit_exceeded.reset(); + EXPECT_EQ(ReleaseAtLeastNPages( + kMaxLength, /*reason=*/PageReleaseReason::kSoftLimitExceeded), + kPagesPerHugePage); + EXPECT_EQ(GetReleaseStats(), + (PageReleaseStats{ + .total = kPagesPerHugePage * 3, + .release_memory_to_system = kPagesPerHugePage, + .process_background_actions = kPagesPerHugePage, + .soft_limit_exceeded = kPagesPerHugePage, + })); + + hard_limit_exceeded.reset(); + EXPECT_EQ(ReleaseAtLeastNPages( + kMaxLength, /*reason=*/PageReleaseReason::kHardLimitExceeded), + kPagesPerHugePage); + EXPECT_EQ(GetReleaseStats(), + (PageReleaseStats{ + .total = kPagesPerHugePage * 4, + .release_memory_to_system = kPagesPerHugePage, + .process_background_actions = kPagesPerHugePage, + .soft_limit_exceeded = kPagesPerHugePage, + .hard_limit_exceeded = kPagesPerHugePage, + })); +} + +TEST_F(GetReleaseStatsTest, + ReleaseSinglePageAfterBreakingHugepagesRequiresBreakingAgain) { + SpanUniquePtr page = New(Length(1)); + ASSERT_TRUE(page != nullptr); + EXPECT_EQ(GetReleaseStats(), PageReleaseStats{}); + + // We should have to break a hugepage apart to release the other pages. + EXPECT_EQ(ReleaseAtLeastNPages( + kMaxLength, + /*reason=*/PageReleaseReason::kReleaseMemoryToSystem), + Length(0)); + EXPECT_EQ(GetReleaseStats(), (PageReleaseStats{})); + + EXPECT_EQ(ReleaseAtLeastNPagesBreakingHugepages( + kMaxLength, + /*reason=*/PageReleaseReason::kSoftLimitExceeded), + kPagesPerHugePage - Length(1)); + EXPECT_EQ(GetReleaseStats(), + (PageReleaseStats{ + .total = kPagesPerHugePage - Length(1), + .soft_limit_exceeded = kPagesPerHugePage - Length(1), + })); + + page.reset(); + EXPECT_EQ(ReleaseAtLeastNPages( + kMaxLength, + /*reason=*/PageReleaseReason::kReleaseMemoryToSystem), + Length(0)); + EXPECT_EQ(GetReleaseStats(), + (PageReleaseStats{ + .total = kPagesPerHugePage - Length(1), + .soft_limit_exceeded = kPagesPerHugePage - Length(1), + })); + + EXPECT_EQ(ReleaseAtLeastNPagesBreakingHugepages( + kMaxLength, + /*reason=*/PageReleaseReason::kHardLimitExceeded), + Length(1)); + EXPECT_EQ(GetReleaseStats(), + (PageReleaseStats{ + .total = kPagesPerHugePage, + .soft_limit_exceeded = kPagesPerHugePage - Length(1), + .hard_limit_exceeded = Length(1), + })); +} + +TEST_F(GetReleaseStatsTest, + ReleaseAfterNewDeleteSinglePageDoesNotRequireBreakingHugepages) { + SpanUniquePtr page = New(Length(1)); + ASSERT_TRUE(page != nullptr); + page.reset(); + + EXPECT_EQ(ReleaseAtLeastNPages( + kMaxLength, + /*reason=*/PageReleaseReason::kProcessBackgroundActions), + kPagesPerHugePage); + EXPECT_EQ(GetReleaseStats(), + (PageReleaseStats{ + .total = kPagesPerHugePage, + .process_background_actions = kPagesPerHugePage, + })); +} + +TEST_F(GetReleaseStatsTest, ReleaseAfterPartialReleaseContinuesTrackingStats) { + SpanUniquePtr two_hugepages = New(kPagesPerHugePage * 2); + ASSERT_TRUE(two_hugepages != nullptr); + two_hugepages.reset(); + + EXPECT_EQ(ReleaseAtLeastNPages( + kPagesPerHugePage, + /*reason=*/PageReleaseReason::kReleaseMemoryToSystem), + kPagesPerHugePage); + EXPECT_EQ(GetReleaseStats(), + (PageReleaseStats{ + .total = kPagesPerHugePage, + .release_memory_to_system = kPagesPerHugePage, + })); + + EXPECT_EQ(ReleaseAtLeastNPages( + kMaxLength, + /*reason=*/PageReleaseReason::kProcessBackgroundActions), + kPagesPerHugePage); + EXPECT_EQ(GetReleaseStats(), + (PageReleaseStats{ + .total = kPagesPerHugePage * 2, + .release_memory_to_system = kPagesPerHugePage, + .process_background_actions = kPagesPerHugePage, + })); +} + +TEST_F(GetReleaseStatsTest, b339535705) { + std::vector v; + size_t system_bytes; + do { + // Allocate until we trigger the huge regions. + v.push_back(New(kPagesPerHugePage * 2 + Length(1), + AccessDensityPrediction::kSparse)); + + PageHeapSpinLockHolder l; + system_bytes = allocator_->RegionsStats().system_bytes; + } while (system_bytes < kHugePageSize); + + EXPECT_FALSE(v.empty()); + + v.push_back( + New(kPagesPerHugePage * 2 + Length(1), AccessDensityPrediction::kSparse)); + v.push_back( + New(kPagesPerHugePage * 2 + Length(1), AccessDensityPrediction::kSparse)); + + v.pop_back(); + v.pop_back(); + + BackingStats stats; + { + PageHeapSpinLockHolder l; + stats = allocator_->RegionsStats(); + } + + EXPECT_GE(stats.system_bytes, kHugePageSize); + EXPECT_GE(stats.free_bytes, kHugePageSize); + + Length released = ReleaseAtLeastNPagesBreakingHugepages( + kPagesPerHugePage, /*reason=*/PageReleaseReason::kSoftLimitExceeded); + EXPECT_GE(released, kPagesPerHugePage); + EXPECT_EQ(GetReleaseStats(), (PageReleaseStats{ + .total = released, + .soft_limit_exceeded = released, + .hard_limit_exceeded = Length(0), + })); +} + } // namespace } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_page_filler.h b/contrib/libs/tcmalloc/tcmalloc/huge_page_filler.h index 2f72b438818c..288baa0a986d 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_page_filler.h +++ b/contrib/libs/tcmalloc/tcmalloc/huge_page_filler.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,19 +20,31 @@ #include #include +#include #include #include "absl/algorithm/container.h" +#include "absl/base/attributes.h" #include "absl/base/internal/cycleclock.h" +#include "absl/base/optimization.h" +#include "absl/base/thread_annotations.h" +#include "absl/strings/string_view.h" #include "absl/time/time.h" +#include "absl/types/span.h" #include "tcmalloc/common.h" -#include "tcmalloc/huge_allocator.h" +#include "tcmalloc/hinted_tracker_lists.h" #include "tcmalloc/huge_cache.h" +#include "tcmalloc/huge_page_subrelease.h" #include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/clock.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/linked_list.h" +#include "tcmalloc/internal/logging.h" #include "tcmalloc/internal/optimization.h" +#include "tcmalloc/internal/pageflags.h" #include "tcmalloc/internal/range_tracker.h" #include "tcmalloc/internal/timeseries_tracker.h" +#include "tcmalloc/pages.h" #include "tcmalloc/span.h" #include "tcmalloc/stats.h" @@ -39,607 +52,24 @@ GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { -// This and the following classes implement the adaptive hugepage subrelease -// mechanism and realized fragmentation metric described in "Adaptive Hugepage -// Subrelease for Non-moving Memory Allocators in Warehouse-Scale Computers" -// (ISMM 2021). - -// Tracks correctness of skipped subrelease decisions over time. -template -class SkippedSubreleaseCorrectnessTracker { - public: - struct SkippedSubreleaseDecision { - Length pages; // Number of pages we skipped subreleasing. - size_t count; // Number of times we skipped a subrelease. - - SkippedSubreleaseDecision() : pages(0), count(0) {} - explicit SkippedSubreleaseDecision(Length pages) : pages(pages), count(1) {} - explicit SkippedSubreleaseDecision(Length pages, size_t count) - : pages(pages), count(count) {} - - SkippedSubreleaseDecision& operator+=(SkippedSubreleaseDecision rhs) { - pages += rhs.pages; - count += rhs.count; - return *this; - } - - static SkippedSubreleaseDecision Zero() { - return SkippedSubreleaseDecision(); - } - }; - - explicit constexpr SkippedSubreleaseCorrectnessTracker(Clock clock, - absl::Duration w) - : window_(w), - epoch_length_(window_ / kEpochs), - last_confirmed_peak_(0), - tracker_(clock, w) {} - - // Not copyable or movable - SkippedSubreleaseCorrectnessTracker( - const SkippedSubreleaseCorrectnessTracker&) = delete; - SkippedSubreleaseCorrectnessTracker& operator=( - const SkippedSubreleaseCorrectnessTracker&) = delete; - - void ReportSkippedSubreleasePages( - Length skipped_pages, Length peak_pages, - absl::Duration expected_time_until_next_peak) { - total_skipped_ += SkippedSubreleaseDecision(skipped_pages); - pending_skipped_ += SkippedSubreleaseDecision(skipped_pages); - - SkippedSubreleaseUpdate update; - update.decision = SkippedSubreleaseDecision(skipped_pages); - update.num_pages_at_decision = peak_pages; - update.correctness_interval_epochs = - expected_time_until_next_peak / epoch_length_; - tracker_.Report(update); - } - - void ReportUpdatedPeak(Length current_peak) { - // Record this peak for the current epoch (so we don't double-count correct - // predictions later) and advance the tracker. - SkippedSubreleaseUpdate update; - update.confirmed_peak = current_peak; - if (tracker_.Report(update)) { - // Also keep track of the largest peak we have confirmed this epoch. - last_confirmed_peak_ = Length(0); - } - - // Recompute currently pending decisions. - pending_skipped_ = SkippedSubreleaseDecision::Zero(); - - Length largest_peak_already_confirmed = last_confirmed_peak_; - - tracker_.IterBackwards( - [&](size_t offset, int64_t ts, const SkippedSubreleaseEntry& e) { - // Do not clear any decisions in the current epoch. - if (offset == 0) { - return; - } - - if (e.decisions.count > 0 && - e.max_num_pages_at_decision > largest_peak_already_confirmed && - offset <= e.correctness_interval_epochs) { - if (e.max_num_pages_at_decision <= current_peak) { - // We can confirm a subrelease decision as correct and it had not - // been confirmed correct by an earlier peak yet. - correctly_skipped_ += e.decisions; - } else { - pending_skipped_ += e.decisions; - } - } - - // Did we clear any earlier decisions based on a peak in this epoch? - // Keep track of the peak, so we do not clear them again. - largest_peak_already_confirmed = - std::max(largest_peak_already_confirmed, e.max_confirmed_peak); - }, - -1); - - last_confirmed_peak_ = std::max(last_confirmed_peak_, current_peak); - } - - inline SkippedSubreleaseDecision total_skipped() const { - return total_skipped_; - } - - inline SkippedSubreleaseDecision correctly_skipped() const { - return correctly_skipped_; - } - - inline SkippedSubreleaseDecision pending_skipped() const { - return pending_skipped_; - } - - private: - struct SkippedSubreleaseUpdate { - // A subrelease decision that was made at this time step: How much did we - // decide not to release? - SkippedSubreleaseDecision decision; - - // What does our future demand have to be for this to be correct? If there - // were multiple subrelease decisions in the same epoch, use the max. - Length num_pages_at_decision; - - // How long from the time of the decision do we have before the decision - // will be determined incorrect? - int64_t correctness_interval_epochs = 0; - - // At this time step, we confirmed a demand peak at this level, which means - // all subrelease decisions in earlier time steps that had peak_demand_pages - // <= this confirmed_peak were confirmed correct and don't need to be - // considered again in the future. - Length confirmed_peak; - }; - - struct SkippedSubreleaseEntry { - SkippedSubreleaseDecision decisions = SkippedSubreleaseDecision::Zero(); - Length max_num_pages_at_decision; - int64_t correctness_interval_epochs = 0; - Length max_confirmed_peak; - - static SkippedSubreleaseEntry Nil() { return SkippedSubreleaseEntry(); } - - void Report(SkippedSubreleaseUpdate e) { - decisions += e.decision; - correctness_interval_epochs = - std::max(correctness_interval_epochs, e.correctness_interval_epochs); - max_num_pages_at_decision = - std::max(max_num_pages_at_decision, e.num_pages_at_decision); - max_confirmed_peak = std::max(max_confirmed_peak, e.confirmed_peak); - } - }; - - const absl::Duration window_; - const absl::Duration epoch_length_; - - // The largest peak we processed this epoch. This is required to avoid us - // double-counting correctly predicted decisions. - Length last_confirmed_peak_; - - SkippedSubreleaseDecision total_skipped_; - SkippedSubreleaseDecision correctly_skipped_; - SkippedSubreleaseDecision pending_skipped_; - - TimeSeriesTracker - tracker_; -}; - -struct SubreleaseStats { - Length total_pages_subreleased; // cumulative since startup - Length num_pages_subreleased; - HugeLength total_hugepages_broken{NHugePages(0)}; // cumulative since startup - HugeLength num_hugepages_broken{NHugePages(0)}; - - bool is_limit_hit = false; - // Keep these limit-related stats cumulative since startup only - Length total_pages_subreleased_due_to_limit; - HugeLength total_hugepages_broken_due_to_limit{NHugePages(0)}; - - void reset() { - total_pages_subreleased += num_pages_subreleased; - total_hugepages_broken += num_hugepages_broken; - num_pages_subreleased = Length(0); - num_hugepages_broken = NHugePages(0); - } - - // Must be called at the beginning of each subrelease request - void set_limit_hit(bool value) { is_limit_hit = value; } - - // This only has a well-defined meaning within ReleaseCandidates where - // set_limit_hit() has been called earlier. Do not use anywhere else. - bool limit_hit() { return is_limit_hit; } -}; - -// Track filler statistics over a time window. -template -class FillerStatsTracker { - public: - enum Type { kRegular, kDonated, kPartialReleased, kReleased, kNumTypes }; - - struct FillerStats { - Length num_pages; - Length free_pages; - Length unmapped_pages; - Length used_pages_in_subreleased_huge_pages; - HugeLength huge_pages[kNumTypes]; - Length num_pages_subreleased; - HugeLength num_hugepages_broken = NHugePages(0); - - HugeLength total_huge_pages() const { - HugeLength total_huge_pages; - for (int i = 0; i < kNumTypes; i++) { - total_huge_pages += huge_pages[i]; - } - return total_huge_pages; - } - }; - - struct NumberOfFreePages { - Length free; - Length free_backed; - }; - - explicit constexpr FillerStatsTracker(Clock clock, absl::Duration w, - absl::Duration summary_interval) - : summary_interval_(summary_interval), - window_(w), - epoch_length_(window_ / kEpochs), - tracker_(clock, w), - skipped_subrelease_correctness_(clock, w) {} - - // Not copyable or movable - FillerStatsTracker(const FillerStatsTracker&) = delete; - FillerStatsTracker& operator=(const FillerStatsTracker&) = delete; - - void Report(const FillerStats stats) { - if (ABSL_PREDICT_FALSE(tracker_.Report(stats))) { - if (ABSL_PREDICT_FALSE(pending_skipped().count > 0)) { - // Consider the peak within the just completed epoch to confirm the - // correctness of any recent subrelease decisions. - skipped_subrelease_correctness_.ReportUpdatedPeak(std::max( - stats.num_pages, - tracker_.GetEpochAtOffset(1).stats[kStatsAtMaxDemand].num_pages)); - } - } - } - - void Print(Printer* out) const; - void PrintInPbtxt(PbtxtRegion* hpaa) const; - - // Calculates recent peaks for skipping subrelease decisions. If our allocated - // memory is below the demand peak within the last peak_interval, we stop - // subreleasing. If our demand is going above that peak again within another - // peak_interval, we report that we made the correct decision. - FillerStats GetRecentPeak(absl::Duration peak_interval) { - last_peak_interval_ = peak_interval; - FillerStats recent_peak; - Length max_demand_pages; - - int64_t num_epochs = peak_interval / epoch_length_; - tracker_.IterBackwards( - [&](size_t offset, int64_t ts, const FillerStatsEntry& e) { - if (!e.empty()) { - // Identify the maximum number of demand pages we have seen within - // the time interval. - if (e.stats[kStatsAtMaxDemand].num_pages > max_demand_pages) { - recent_peak = e.stats[kStatsAtMaxDemand]; - max_demand_pages = recent_peak.num_pages; - } - } - }, - num_epochs); - - return recent_peak; - } - - void ReportSkippedSubreleasePages( - Length pages, Length peak_pages, - absl::Duration expected_time_until_next_peak) { - if (pages == Length(0)) { - return; - } - - skipped_subrelease_correctness_.ReportSkippedSubreleasePages( - pages, peak_pages, expected_time_until_next_peak); - } - - inline typename SkippedSubreleaseCorrectnessTracker< - kEpochs>::SkippedSubreleaseDecision - total_skipped() const { - return skipped_subrelease_correctness_.total_skipped(); - } - - inline typename SkippedSubreleaseCorrectnessTracker< - kEpochs>::SkippedSubreleaseDecision - correctly_skipped() const { - return skipped_subrelease_correctness_.correctly_skipped(); - } - - inline typename SkippedSubreleaseCorrectnessTracker< - kEpochs>::SkippedSubreleaseDecision - pending_skipped() const { - return skipped_subrelease_correctness_.pending_skipped(); - } - - // Returns the minimum number of free pages throughout the tracker period. - // The first value of the pair is the number of all free pages, the second - // value contains only the backed ones. - NumberOfFreePages min_free_pages(absl::Duration w) const { - NumberOfFreePages mins; - mins.free = Length::max(); - mins.free_backed = Length::max(); - - int64_t num_epochs = std::clamp(w / epoch_length_, int64_t{0}, - static_cast(kEpochs)); - - tracker_.IterBackwards( - [&](size_t offset, int64_t ts, const FillerStatsEntry& e) { - if (!e.empty()) { - mins.free = std::min(mins.free, e.min_free_pages); - mins.free_backed = - std::min(mins.free_backed, e.min_free_backed_pages); - } - }, - num_epochs); - mins.free = (mins.free == Length::max()) ? Length(0) : mins.free; - mins.free_backed = - (mins.free_backed == Length::max()) ? Length(0) : mins.free_backed; - return mins; - } - - private: - // We collect filler statistics at four "interesting points" within each time - // step: at min/max demand of pages and at min/max use of hugepages. This - // allows us to approximate the envelope of the different metrics. - enum StatsType { - kStatsAtMinDemand, - kStatsAtMaxDemand, - kStatsAtMinHugePages, - kStatsAtMaxHugePages, - kNumStatsTypes - }; - - struct FillerStatsEntry { - // Collect filler stats at "interesting points" (minimum/maximum page demand - // and at minimum/maximum usage of huge pages). - FillerStats stats[kNumStatsTypes] = {}; - static constexpr Length kDefaultValue = Length::max(); - Length min_free_pages = kDefaultValue; - Length min_free_backed_pages = kDefaultValue; - Length num_pages_subreleased; - HugeLength num_hugepages_broken = NHugePages(0); - - static FillerStatsEntry Nil() { return FillerStatsEntry(); } - - void Report(FillerStats e) { - if (empty()) { - for (int i = 0; i < kNumStatsTypes; i++) { - stats[i] = e; - } - } - - if (e.num_pages < stats[kStatsAtMinDemand].num_pages) { - stats[kStatsAtMinDemand] = e; - } - - if (e.num_pages > stats[kStatsAtMaxDemand].num_pages) { - stats[kStatsAtMaxDemand] = e; - } - - if (e.total_huge_pages() < - stats[kStatsAtMinHugePages].total_huge_pages()) { - stats[kStatsAtMinHugePages] = e; - } - - if (e.total_huge_pages() > - stats[kStatsAtMaxHugePages].total_huge_pages()) { - stats[kStatsAtMaxHugePages] = e; - } - - min_free_pages = - std::min(min_free_pages, e.free_pages + e.unmapped_pages); - min_free_backed_pages = std::min(min_free_backed_pages, e.free_pages); - - // Subrelease stats - num_pages_subreleased += e.num_pages_subreleased; - num_hugepages_broken += e.num_hugepages_broken; - } - - bool empty() const { return min_free_pages == kDefaultValue; } - }; - - // The tracker reports pages that have been free for at least this interval, - // as well as peaks within this interval. - const absl::Duration summary_interval_; - - const absl::Duration window_; - const absl::Duration epoch_length_; - - TimeSeriesTracker tracker_; - SkippedSubreleaseCorrectnessTracker skipped_subrelease_correctness_; - - // Records the last peak_interval value, for reporting and debugging only. - absl::Duration last_peak_interval_; -}; - -// Evaluate a/b, avoiding division by zero -inline double safe_div(double a, double b) { - if (b == 0) { - return 0.; - } else { - return a / b; - } -} - -inline double safe_div(Length a, Length b) { - return safe_div(a.raw_num(), b.raw_num()); -} - -template -void FillerStatsTracker::Print(Printer* out) const { - NumberOfFreePages free_pages = min_free_pages(summary_interval_); - out->printf("HugePageFiller: time series over %d min interval\n\n", - absl::ToInt64Minutes(summary_interval_)); - - // Realized fragmentation is equivalent to backed minimum free pages over a - // 5-min interval. It is printed for convenience but not included in pbtxt. - out->printf("HugePageFiller: realized fragmentation: %.1f MiB\n", - free_pages.free_backed.in_mib()); - out->printf("HugePageFiller: minimum free pages: %zu (%zu backed)\n", - free_pages.free.raw_num(), free_pages.free_backed.raw_num()); - - FillerStatsEntry at_peak_demand; - FillerStatsEntry at_peak_hps; - - tracker_.IterBackwards( - [&](size_t offset, int64_t ts, const FillerStatsEntry& e) { - if (!e.empty()) { - if (at_peak_demand.empty() || - at_peak_demand.stats[kStatsAtMaxDemand].num_pages < - e.stats[kStatsAtMaxDemand].num_pages) { - at_peak_demand = e; - } - - if (at_peak_hps.empty() || - at_peak_hps.stats[kStatsAtMaxHugePages].total_huge_pages() < - e.stats[kStatsAtMaxHugePages].total_huge_pages()) { - at_peak_hps = e; - } - } - }, - summary_interval_ / epoch_length_); - - out->printf( - "HugePageFiller: at peak demand: %zu pages (and %zu free, %zu unmapped)\n" - "HugePageFiller: at peak demand: %zu hps (%zu regular, %zu donated, " - "%zu partial, %zu released)\n", - at_peak_demand.stats[kStatsAtMaxDemand].num_pages.raw_num(), - at_peak_demand.stats[kStatsAtMaxDemand].free_pages.raw_num(), - at_peak_demand.stats[kStatsAtMaxDemand].unmapped_pages.raw_num(), - at_peak_demand.stats[kStatsAtMaxDemand].total_huge_pages().raw_num(), - at_peak_demand.stats[kStatsAtMaxDemand].huge_pages[kRegular].raw_num(), - at_peak_demand.stats[kStatsAtMaxDemand].huge_pages[kDonated].raw_num(), - at_peak_demand.stats[kStatsAtMaxDemand] - .huge_pages[kPartialReleased] - .raw_num(), - at_peak_demand.stats[kStatsAtMaxDemand].huge_pages[kReleased].raw_num()); - - out->printf( - "HugePageFiller: at peak hps: %zu pages (and %zu free, %zu unmapped)\n" - "HugePageFiller: at peak hps: %zu hps (%zu regular, %zu donated, " - "%zu partial, %zu released)\n", - at_peak_hps.stats[kStatsAtMaxDemand].num_pages.raw_num(), - at_peak_hps.stats[kStatsAtMaxDemand].free_pages.raw_num(), - at_peak_hps.stats[kStatsAtMaxDemand].unmapped_pages.raw_num(), - at_peak_hps.stats[kStatsAtMaxDemand].total_huge_pages().raw_num(), - at_peak_hps.stats[kStatsAtMaxDemand].huge_pages[kRegular].raw_num(), - at_peak_hps.stats[kStatsAtMaxDemand].huge_pages[kDonated].raw_num(), - at_peak_hps.stats[kStatsAtMaxDemand] - .huge_pages[kPartialReleased] - .raw_num(), - at_peak_hps.stats[kStatsAtMaxDemand].huge_pages[kReleased].raw_num()); - - out->printf( - "\nHugePageFiller: Since the start of the execution, %zu subreleases (%zu" - " pages) were skipped due to recent (%llds) peaks.\n", - total_skipped().count, total_skipped().pages.raw_num(), - static_cast(absl::ToInt64Seconds(last_peak_interval_))); - - Length skipped_pages = total_skipped().pages - pending_skipped().pages; - double correctly_skipped_pages_percentage = - safe_div(100.0 * correctly_skipped().pages, skipped_pages); - - size_t skipped_count = total_skipped().count - pending_skipped().count; - double correctly_skipped_count_percentage = - safe_div(100.0 * correctly_skipped().count, skipped_count); - - out->printf( - "HugePageFiller: %.4f%% of decisions confirmed correct, %zu " - "pending (%.4f%% of pages, %zu pending).\n", - correctly_skipped_count_percentage, pending_skipped().count, - correctly_skipped_pages_percentage, pending_skipped().pages.raw_num()); - - // Print subrelease stats - Length total_subreleased; - HugeLength total_broken = NHugePages(0); - tracker_.Iter( - [&](size_t offset, int64_t ts, const FillerStatsEntry& e) { - total_subreleased += e.num_pages_subreleased; - total_broken += e.num_hugepages_broken; - }, - tracker_.kSkipEmptyEntries); - out->printf( - "HugePageFiller: Subrelease stats last %d min: total " - "%zu pages subreleased, %zu hugepages broken\n", - static_cast(absl::ToInt64Minutes(window_)), - total_subreleased.raw_num(), total_broken.raw_num()); -} - -template -void FillerStatsTracker::PrintInPbtxt(PbtxtRegion* hpaa) const { - { - auto skip_subrelease = hpaa->CreateSubRegion("filler_skipped_subrelease"); - skip_subrelease.PrintI64("skipped_subrelease_interval_ms", - absl::ToInt64Milliseconds(last_peak_interval_)); - skip_subrelease.PrintI64("skipped_subrelease_pages", - total_skipped().pages.raw_num()); - skip_subrelease.PrintI64("correctly_skipped_subrelease_pages", - correctly_skipped().pages.raw_num()); - skip_subrelease.PrintI64("pending_skipped_subrelease_pages", - pending_skipped().pages.raw_num()); - skip_subrelease.PrintI64("skipped_subrelease_count", total_skipped().count); - skip_subrelease.PrintI64("correctly_skipped_subrelease_count", - correctly_skipped().count); - skip_subrelease.PrintI64("pending_skipped_subrelease_count", - pending_skipped().count); - } - - auto filler_stats = hpaa->CreateSubRegion("filler_stats_timeseries"); - filler_stats.PrintI64("window_ms", absl::ToInt64Milliseconds(epoch_length_)); - filler_stats.PrintI64("epochs", kEpochs); - - NumberOfFreePages free_pages = min_free_pages(summary_interval_); - filler_stats.PrintI64("min_free_pages_interval_ms", - absl::ToInt64Milliseconds(summary_interval_)); - filler_stats.PrintI64("min_free_pages", free_pages.free.raw_num()); - filler_stats.PrintI64("min_free_backed_pages", - free_pages.free_backed.raw_num()); - - static const char* labels[kNumStatsTypes] = { - "at_minimum_demand", "at_maximum_demand", "at_minimum_huge_pages", - "at_maximum_huge_pages"}; - - tracker_.Iter( - [&](size_t offset, int64_t ts, const FillerStatsEntry& e) { - auto region = filler_stats.CreateSubRegion("measurements"); - region.PrintI64("epoch", offset); - region.PrintI64("timestamp_ms", - absl::ToInt64Milliseconds(absl::Nanoseconds(ts))); - region.PrintI64("min_free_pages", e.min_free_pages.raw_num()); - region.PrintI64("min_free_backed_pages", - e.min_free_backed_pages.raw_num()); - region.PrintI64("num_pages_subreleased", - e.num_pages_subreleased.raw_num()); - region.PrintI64("num_hugepages_broken", - e.num_hugepages_broken.raw_num()); - for (int i = 0; i < kNumStatsTypes; i++) { - auto m = region.CreateSubRegion(labels[i]); - FillerStats stats = e.stats[i]; - m.PrintI64("num_pages", stats.num_pages.raw_num()); - m.PrintI64("regular_huge_pages", - stats.huge_pages[kRegular].raw_num()); - m.PrintI64("donated_huge_pages", - stats.huge_pages[kDonated].raw_num()); - m.PrintI64("partial_released_huge_pages", - stats.huge_pages[kPartialReleased].raw_num()); - m.PrintI64("released_huge_pages", - stats.huge_pages[kReleased].raw_num()); - m.PrintI64("used_pages_in_subreleased_huge_pages", - stats.used_pages_in_subreleased_huge_pages.raw_num()); - } - }, - tracker_.kSkipEmptyEntries); -} - // PageTracker keeps track of the allocation status of every page in a HugePage. // It allows allocation and deallocation of a contiguous run of pages. // // Its mutating methods are annotated as requiring the pageheap_lock, in order // to support unlocking the page heap lock in a dynamic annotation-friendly way. -template -class PageTracker : public TList>::Elem { +class PageTracker : public TList::Elem { public: - static void UnbackImpl(void* p, size_t size) { Unback(p, size); } - - constexpr PageTracker(HugePage p, uint64_t when) + PageTracker(HugePage p, bool was_donated, uint64_t now) : location_(p), released_count_(0), + abandoned_count_(0), donated_(false), + was_donated_(was_donated), + was_released_(false), + abandoned_(false), unbroken_(true), + alloctime_(now), free_{} { - init_when(when); - #ifndef __ppc64__ #if defined(__GNUC__) #pragma GCC diagnostic push @@ -653,29 +83,21 @@ class PageTracker : public TList>::Elem { // On PPC64, kHugePageSize / kPageSize is typically ~2K (16MB / 8KB), // requiring 512 bytes for representing free_. While its cache line size is // larger, the entirety of free_ will not fit on two cache lines. - static_assert( - offsetof(PageTracker, location_) + sizeof(location_) <= - 2 * ABSL_CACHELINE_SIZE, - "location_ should fall within the first two cachelines of " - "PageTracker."); - static_assert(offsetof(PageTracker, when_numerator_) + - sizeof(when_numerator_) <= - 2 * ABSL_CACHELINE_SIZE, - "when_numerator_ should fall within the first two cachelines " - "of PageTracker."); - static_assert(offsetof(PageTracker, when_denominator_) + - sizeof(when_denominator_) <= + static_assert(offsetof(PageTracker, location_) + sizeof(location_) <= 2 * ABSL_CACHELINE_SIZE, - "when_denominator_ should fall within the first two " - "cachelines of PageTracker."); + "location_ should fall within the first two cachelines of " + "PageTracker."); static_assert( - offsetof(PageTracker, donated_) + sizeof(donated_) <= + offsetof(PageTracker, donated_) + sizeof(donated_) <= 2 * ABSL_CACHELINE_SIZE, "donated_ should fall within the first two cachelines of PageTracker."); static_assert( - offsetof(PageTracker, free_) + sizeof(free_) <= - 2 * ABSL_CACHELINE_SIZE, + offsetof(PageTracker, free_) + sizeof(free_) <= 2 * ABSL_CACHELINE_SIZE, "free_ should fall within the first two cachelines of PageTracker."); + static_assert(offsetof(PageTracker, alloctime_) + sizeof(alloctime_) <= + 2 * ABSL_CACHELINE_SIZE, + "alloctime_ should fall within the first two cachelines of " + "PageTracker."); #if defined(__GNUC__) #pragma GCC diagnostic pop #endif @@ -693,8 +115,8 @@ class PageTracker : public TList>::Elem { // [i, i+n) in previously_unbacked. PageAllocation Get(Length n) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); - // REQUIRES: p was the result of a previous call to Get(n) - void Put(PageId p, Length n) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); + // REQUIRES: r was the result of a previous call to Get(n) + void Put(Range r) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); // Returns true if any unused pages have been returned-to-system. bool released() const { return released_count_ > 0; } @@ -703,16 +125,41 @@ class PageTracker : public TList>::Elem { // Only up-to-date when the tracker is on a TrackerList in the Filler; // otherwise the value is meaningless. bool donated() const { return donated_; } + // Set/reset the donated flag. The donated status is lost, for instance, // when further allocations are made on the tracker. void set_donated(bool status) { donated_ = status; } + // Tracks whether the page was given to the filler in the donated state. It + // is not cleared by the filler, allowing the HugePageAwareAllocator to track + // memory persistently donated to the filler. + bool was_donated() const { return was_donated_; } + + bool was_released() const { return was_released_; } + void set_was_released(bool status) { was_released_ = status; } + + // Tracks whether the page, previously donated to the filler, was abondoned. + // When a large allocation is deallocated but the huge page is not + // reassembled, the pages are abondoned to the filler for future allocations. + bool abandoned() const { return abandoned_; } + void set_abandoned(bool status) { abandoned_ = status; } + // Tracks how many pages were provided when the originating allocation of a + // donated page was deallocated but other allocations were in use. + // + // Requires was_donated(). + Length abandoned_count() const { return Length(abandoned_count_); } + void set_abandoned_count(Length count) { + TC_ASSERT(was_donated_); + abandoned_count_ = count.raw_num(); + } + // These statistics help us measure the fragmentation of a hugepage and // the desirability of allocating from this hugepage. Length longest_free_range() const { return Length(free_.longest_free()); } size_t nallocs() const { return free_.allocs(); } Length used_pages() const { return Length(free_.used()); } Length released_pages() const { return Length(released_count_); } + double alloctime() const { return alloctime_; } Length free_pages() const; bool empty() const; @@ -723,56 +170,32 @@ class PageTracker : public TList>::Elem { // Return all unused pages to the system, mark future frees to do same. // Returns the count of pages unbacked. - Length ReleaseFree() ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); - - // Return this allocation to the system, if policy warrants it. - // - // As of 3/2020 our policy is to rerelease: Once we break a hugepage by - // returning a fraction of it, we return *anything* unused. This simplifies - // tracking. - // - // TODO(b/141550014): Make retaining the default/sole policy. - void MaybeRelease(PageId p, Length n) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { - if (released_count_ == 0) { - return; - } - - // Mark pages as released. - Length index = p - location_.first_page(); - ASSERT(released_by_page_.CountBits(index.raw_num(), n.raw_num()) == 0); - released_by_page_.SetRange(index.raw_num(), n.raw_num()); - released_count_ += n.raw_num(); - ASSERT(released_by_page_.CountBits(0, kPagesPerHugePage.raw_num()) == - released_count_); - - // TODO(b/122551676): If release fails, we should not SetRange above. - ReleasePagesWithoutLock(p, n); - } + Length ReleaseFree(MemoryModifyFunction& unback) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); - void AddSpanStats(SmallSpanStats* small, LargeSpanStats* large, - PageAgeHistograms* ages) const; + void AddSpanStats(SmallSpanStats* small, LargeSpanStats* large) const; + bool HasDenseSpans() const { return has_dense_spans_; } + void SetHasDenseSpans() { has_dense_spans_ = true; } private: - void init_when(uint64_t w) { - const Length before = Length(free_.total_free()); - when_numerator_ = w * before.raw_num(); - when_denominator_ = before.raw_num(); - } - HugePage location_; - // We keep track of an average time weighted by Length::raw_num. In order to - // avoid doing division on fast path, store the numerator and denominator and - // only do the division when we need the average. - uint64_t when_numerator_; - uint64_t when_denominator_; // Cached value of released_by_page_.CountBits(0, kPagesPerHugePages) // // TODO(b/151663108): Logically, this is guarded by pageheap_lock. uint16_t released_count_; + uint16_t abandoned_count_; bool donated_; + bool was_donated_; + bool was_released_; + // Tracks whether we accounted for the abandoned state of the page. When a + // large allocation is deallocated but the huge page can not be reassembled, + // we measure the number of pages abandoned to the filler. To make sure that + // we do not double-count any future deallocations, we maintain a state and + // reset it once we measure those pages in abandoned_count_. + bool abandoned_; bool unbroken_; + double alloctime_; RangeTracker free_; // Bitmap of pages based on them being released to the OS. @@ -792,38 +215,44 @@ class PageTracker : public TList>::Elem { std::numeric_limits::max(), "nallocs must be able to support kPagesPerHugePage!"); - void ReleasePages(PageId p, Length n) { - void* ptr = p.start_addr(); - size_t byte_len = n.in_bytes(); - Unback(ptr, byte_len); - unbroken_ = false; - } - - void ReleasePagesWithoutLock(PageId p, Length n) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { - pageheap_lock.Unlock(); + bool has_dense_spans_ = false; - void* ptr = p.start_addr(); - size_t byte_len = n.in_bytes(); - Unback(ptr, byte_len); - - pageheap_lock.Lock(); - unbroken_ = false; + [[nodiscard]] bool ReleasePages(Range r, MemoryModifyFunction& unback) { + bool success = unback(r); + if (ABSL_PREDICT_TRUE(success)) { + unbroken_ = false; + } + return success; } }; -enum class FillerPartialRerelease : bool { - // Once we break a hugepage by returning a fraction of it, we return - // *anything* unused. This simplifies tracking. - // - // As of 2/2020, this is the default behavior. - Return, - // When releasing a page onto an already-released huge page, retain the page - // rather than releasing it back to the OS. This can reduce minor page - // faults for hot pages. - // - // TODO(b/141550014, b/122551676): Make this the default behavior. - Retain, +// Records number of hugepages in different types of allocs. +// +// We use an additional element in the array to record the total sum of pages +// in kSparse and kDense allocs. +struct HugePageFillerStats { + // Number of hugepages in fully-released alloc. + HugeLength n_fully_released[AccessDensityPrediction::kPredictionCounts + 1]; + // Number of hugepages in partially-released alloc. + HugeLength n_partial_released[AccessDensityPrediction::kPredictionCounts + 1]; + // Total hugepages that are either in fully- or partially-released allocs. + HugeLength n_released[AccessDensityPrediction::kPredictionCounts + 1]; + // Total hugepages in the filler of a particular object count. + HugeLength n_total[AccessDensityPrediction::kPredictionCounts + 1]; + // Total hugepages that have been fully allocated. + HugeLength n_full[AccessDensityPrediction::kPredictionCounts + 1]; + // Number of hugepages in partially allocated (but not released) allocs. + HugeLength n_partial[AccessDensityPrediction::kPredictionCounts + 1]; +}; + +enum class HugePageFillerDenseTrackerType : bool { + // Hugepages sorted on longest free range and chunk index. This is currently + // the default. + kLongestFreeRangeAndChunks, + // Hugepages sorted only on number of spans allocated. As we allocate + // single-page many-object spans, we do not sort hugepages on longest free + // range when this configuration is used. + kSpansAllocated, }; // This tracks a set of unfilled hugepages, and fulfills allocations @@ -832,14 +261,21 @@ enum class FillerPartialRerelease : bool { template class HugePageFiller { public: - explicit HugePageFiller(FillerPartialRerelease partial_rerelease); - HugePageFiller(FillerPartialRerelease partial_rerelease, Clock clock); + explicit HugePageFiller( + HugePageFillerDenseTrackerType dense_tracker_type, + MemoryModifyFunction& unback ABSL_ATTRIBUTE_LIFETIME_BOUND, + MemoryModifyFunction& unback_without_lock ABSL_ATTRIBUTE_LIFETIME_BOUND); + HugePageFiller(Clock clock, HugePageFillerDenseTrackerType dense_tracker_type, + MemoryModifyFunction& unback ABSL_ATTRIBUTE_LIFETIME_BOUND, + MemoryModifyFunction& unback_without_lock + ABSL_ATTRIBUTE_LIFETIME_BOUND); typedef TrackerType Tracker; struct TryGetResult { TrackerType* pt; PageId page; + bool from_released; }; // Our API is simple, but note that it does not include an unconditional @@ -847,36 +283,77 @@ class HugePageFiller { // needed. This simplifies using it in a few different contexts (and improves // the testing story - no dependencies.) // + // n is the number of TCMalloc pages to be allocated. num_objects is the + // number of individual objects that would be allocated on these n pages. + // // On failure, returns nullptr/PageId{0}. - TryGetResult TryGet(Length n) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); + TryGetResult TryGet(Length n, SpanAllocInfo span_alloc_info) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); - // Marks [p, p + n) as usable by new allocations into *pt; returns pt - // if that hugepage is now empty (nullptr otherwise.) + // Marks r as usable by new allocations into *pt; returns pt if that hugepage + // is now empty (nullptr otherwise.) + // // REQUIRES: pt is owned by this object (has been Contribute()), and - // {pt, p, n} was the result of a previous TryGet. - TrackerType* Put(TrackerType* pt, PageId p, Length n) + // {pt, Range{p, n}} was the result of a previous TryGet. + TrackerType* Put(TrackerType* pt, Range r) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); // Contributes a tracker to the filler. If "donated," then the tracker is // marked as having come from the tail of a multi-hugepage allocation, which // causes it to be treated slightly differently. - void Contribute(TrackerType* pt, bool donated); + void Contribute(TrackerType* pt, bool donated, SpanAllocInfo span_alloc_info); HugeLength size() const { return size_; } // Useful statistics - Length pages_allocated() const { return allocated_; } - Length used_pages() const { return allocated_; } + Length pages_allocated(AccessDensityPrediction type) const { + TC_ASSERT_LT(type, AccessDensityPrediction::kPredictionCounts); + return pages_allocated_[type]; + } + Length pages_allocated() const { + return pages_allocated_[AccessDensityPrediction::kSparse] + + pages_allocated_[AccessDensityPrediction::kDense]; + } + Length used_pages() const { return pages_allocated(); } Length unmapped_pages() const { return unmapped_; } Length free_pages() const; - Length used_pages_in_released() const { return n_used_released_; } + Length used_pages_in_released() const { + TC_ASSERT_LE(n_used_released_[AccessDensityPrediction::kSparse], + regular_alloc_released_[AccessDensityPrediction::kSparse] + .size() + .in_pages()); + TC_ASSERT_LE(n_used_released_[AccessDensityPrediction::kDense], + regular_alloc_released_[AccessDensityPrediction::kDense] + .size() + .in_pages()); + return n_used_released_[AccessDensityPrediction::kDense] + + n_used_released_[AccessDensityPrediction::kSparse]; + } Length used_pages_in_partial_released() const { - return n_used_partial_released_; + TC_ASSERT_LE( + n_used_partial_released_[AccessDensityPrediction::kSparse], + regular_alloc_partial_released_[AccessDensityPrediction::kSparse] + .size() + .in_pages()); + TC_ASSERT_LE( + n_used_partial_released_[AccessDensityPrediction::kDense], + regular_alloc_partial_released_[AccessDensityPrediction::kDense] + .size() + .in_pages()); + return n_used_partial_released_[AccessDensityPrediction::kDense] + + n_used_partial_released_[AccessDensityPrediction::kSparse]; } Length used_pages_in_any_subreleased() const { - return n_used_released_ + n_used_partial_released_; + return used_pages_in_released() + used_pages_in_partial_released(); } + HugeLength previously_released_huge_pages() const { + return n_was_released_[AccessDensityPrediction::kDense] + + n_was_released_[AccessDensityPrediction::kSparse]; + } + + Length FreePagesInPartialAllocs() const; + // Fraction of used pages that are on non-released hugepages and // thus could be backed by kernel hugepages. (Of course, we can't // guarantee that the kernel had available 2-mib regions of physical @@ -885,148 +362,119 @@ class HugePageFiller { double hugepage_frac() const; // Returns the amount of memory to release if all remaining options of - // releasing memory involve subreleasing pages. + // releasing memory involve subreleasing pages. Provided intervals are used + // for making skip subrelease decisions. Length GetDesiredSubreleasePages(Length desired, Length total_released, - absl::Duration peak_interval) + SkipSubreleaseIntervals intervals) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); // Tries to release desired pages by iteratively releasing from the emptiest - // possible hugepage and releasing its free memory to the system. Return the - // number of pages actually released. - Length ReleasePages(Length desired, - absl::Duration skip_subrelease_after_peaks_interval, - bool hit_limit) + // possible hugepage and releasing its free memory to the system. If + // release_partial_alloc_pages is enabled, it also releases all the free + // pages from the partial allocs. Note that the number of pages released may + // be greater than the desired number of pages. + // Returns the number of pages actually released. The releasing target can be + // reduced by skip subrelease which is disabled if all intervals are zero. + static constexpr double kPartialAllocPagesRelease = 0.1; + Length ReleasePages(Length desired, SkipSubreleaseIntervals intervals, + bool release_partial_alloc_pages, bool hit_limit) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); + // Number of candidate hugepages selected in each iteration for releasing + // their free memory. + static constexpr size_t kCandidatesForReleasingMemory = + kPagesPerHugePage.raw_num(); - void AddSpanStats(SmallSpanStats* small, LargeSpanStats* large, - PageAgeHistograms* ages) const; + void AddSpanStats(SmallSpanStats* small, LargeSpanStats* large) const; BackingStats stats() const; SubreleaseStats subrelease_stats() const { return subrelease_stats_; } - void Print(Printer* out, bool everything) const; - void PrintInPbtxt(PbtxtRegion* hpaa) const; - private: - typedef TList TrackerList; + HugePageFillerStats GetStats() const; + void Print(Printer& out, bool everything); + void PrintInPbtxt(PbtxtRegion& hpaa) const; + + template + void ForEachHugePage(const F& func) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); + private: // This class wraps an array of N TrackerLists and a Bitmap storing which // elements are non-empty. template - class HintedTrackerLists { + class PageTrackerLists : public HintedTrackerLists { public: - HintedTrackerLists() : nonempty_{}, size_(NHugePages(0)) {} - - // Removes a TrackerType from the first non-empty freelist with index at - // least n and returns it. Returns nullptr if there is none. - TrackerType* GetLeast(const size_t n) { - ASSERT(n < N); - size_t i = nonempty_.FindSet(n); - if (i == N) { - return nullptr; - } - ASSERT(!lists_[i].empty()); - TrackerType* pt = lists_[i].first(); - if (lists_[i].remove(pt)) { - nonempty_.ClearBit(i); - } - --size_; - return pt; + HugeLength size() const { + return NHugePages(HintedTrackerLists::size()); } - void Add(TrackerType* pt, const size_t i) { - ASSERT(i < N); - ASSERT(pt != nullptr); - lists_[i].prepend(pt); - nonempty_.SetBit(i); - ++size_; - } - void Remove(TrackerType* pt, const size_t i) { - ASSERT(i < N); - ASSERT(pt != nullptr); - if (lists_[i].remove(pt)) { - nonempty_.ClearBit(i); - } - --size_; - } - const TrackerList& operator[](const size_t n) const { - ASSERT(n < N); - return lists_[n]; - } - HugeLength size() const { return size_; } - bool empty() const { return size().raw_num() == 0; } - // Runs a functor on all HugePages in the TrackerLists. - // This method is const but the Functor gets passed a non-const pointer. - // This quirk is inherited from TrackerList. - template - void Iter(const Functor& func, size_t start) const { - size_t i = nonempty_.FindSet(start); - while (i < N) { - auto& list = lists_[i]; - ASSERT(!list.empty()); - for (TrackerType* pt : list) { - func(pt); - } - i++; - if (i < N) i = nonempty_.FindSet(i); - } - } - - private: - TrackerList lists_[N]; - Bitmap nonempty_; - HugeLength size_; }; SubreleaseStats subrelease_stats_; // We group hugepages first by longest-free (as a measure of fragmentation), - // then into 8 chunks inside there by desirability of allocation. + // then into kChunks chunks inside there by desirability of + // allocation. static constexpr size_t kChunks = 8; // Which chunk should this hugepage be in? - // This returns the largest possible value kChunks-1 iff pt has a single - // allocation. - size_t IndexFor(TrackerType* pt); + // This returns the largest possible value kChunks - 1 iff + // pt has a single allocation. + size_t IndexFor(TrackerType* pt) const; // Returns index for regular_alloc_. - static size_t ListFor(Length longest, size_t chunk); + size_t ListFor(Length longest, size_t chunk, AccessDensityPrediction density, + size_t nallocs) const; static constexpr size_t kNumLists = kPagesPerHugePage.raw_num() * kChunks; - HintedTrackerLists regular_alloc_; - HintedTrackerLists donated_alloc_; + // List of hugepages from which no pages have been released to the OS. + PageTrackerLists + regular_alloc_[AccessDensityPrediction::kPredictionCounts]; + PageTrackerLists donated_alloc_; // Partially released ones that we are trying to release. // - // When FillerPartialRerelease == Return: - // regular_alloc_partial_released_ is empty and n_used_partial_released_ is - // 0. - // - // When FillerPartialRerelease == Retain: - // regular_alloc_partial_released_ contains huge pages that are partially - // allocated, partially free, and partially returned to the OS. - // n_used_partial_released_ is the number of pages which have been allocated - // of the set. + // regular_alloc_partial_released_ contains huge pages that are partially + // allocated, partially free, and partially returned to the OS. // // regular_alloc_released_: This list contains huge pages whose pages are // either allocated or returned to the OS. There are no pages that are free, - // but not returned to the OS. n_used_released_ contains the number of - // pages in those huge pages that are not free (i.e., allocated). - Length n_used_partial_released_; - Length n_used_released_; - HintedTrackerLists regular_alloc_partial_released_; - HintedTrackerLists regular_alloc_released_; - - // RemoveFromFillerList pt from the appropriate HintedTrackerList. + // but not returned to the OS. + PageTrackerLists regular_alloc_partial_released_ + [AccessDensityPrediction::kPredictionCounts]; + PageTrackerLists + regular_alloc_released_[AccessDensityPrediction::kPredictionCounts]; + // n_used_released_ contains the number of pages in huge pages that are not + // free (i.e., allocated). Only the hugepages in regular_alloc_released_ are + // considered. + Length n_used_released_[AccessDensityPrediction::kPredictionCounts]; + + HugeLength n_was_released_[AccessDensityPrediction::kPredictionCounts]; + // n_used_partial_released_ is the number of pages which have been allocated + // from the hugepages in the set regular_alloc_partial_released. + Length n_used_partial_released_[AccessDensityPrediction::kPredictionCounts]; + const HugePageFillerDenseTrackerType dense_tracker_type_; + + // RemoveFromFillerList pt from the appropriate PageTrackerList. void RemoveFromFillerList(TrackerType* pt); - // Put pt in the appropriate HintedTrackerList. + // Put pt in the appropriate PageTrackerList. void AddToFillerList(TrackerType* pt); // Like AddToFillerList(), but for use when donating from the tail of a // multi-hugepage allocation. void DonateToFillerList(TrackerType* pt); + void PrintAllocStatsInPbtxt(absl::string_view field, PbtxtRegion& hpaa, + const HugePageFillerStats& stats, + AccessDensityPrediction count) const; // CompareForSubrelease identifies the worse candidate for subrelease, between // the choice of huge pages a and b. - static bool CompareForSubrelease(TrackerType* a, TrackerType* b) { - ASSERT(a != nullptr); - ASSERT(b != nullptr); - - return a->used_pages() < b->used_pages(); + static bool CompareForSubrelease(const TrackerType* a, const TrackerType* b) { + TC_ASSERT_NE(a, nullptr); + TC_ASSERT_NE(b, nullptr); + + if (a->used_pages() < b->used_pages()) return true; + if (a->used_pages() > b->used_pages()) return false; + // If 'a' has dense spans, then we do not prefer to release from 'a' + // compared to 'b'. + if (a->HasDenseSpans()) return false; + // We know 'a' does not have dense spans. If 'b' has dense spans, then we + // prefer to release from 'a'. Otherwise, we do not prefer either. + return b->HasDenseSpans(); } // SelectCandidates identifies the candidates.size() best candidates in the @@ -1037,38 +485,37 @@ class HugePageFiller { template static int SelectCandidates(absl::Span candidates, int current_candidates, - const HintedTrackerLists& tracker_list, + const PageTrackerLists& tracker_list, size_t tracker_start); // Release desired pages from the page trackers in candidates. Returns the // number of pages released. - Length ReleaseCandidates(absl::Span candidates, Length desired) + Length ReleaseCandidates(absl::Span candidates, Length target) ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock); HugeLength size_; - Length allocated_; + Length pages_allocated_[AccessDensityPrediction::kPredictionCounts]; Length unmapped_; // How much have we eagerly unmapped (in already released hugepages), but // not reported to ReleasePages calls? Length unmapping_unaccounted_; - FillerPartialRerelease partial_rerelease_; - // Functionality related to time series tracking. void UpdateFillerStatsTracker(); - using StatsTrackerType = FillerStatsTracker<600>; + using StatsTrackerType = SubreleaseStatsTracker<600>; StatsTrackerType fillerstats_tracker_; + Clock clock_; + // TODO(b/73749855): Remove remaining uses of unback_. + MemoryModifyFunction& unback_; + MemoryModifyFunction& unback_without_lock_; }; -template -inline typename PageTracker::PageAllocation PageTracker::Get( - Length n) { +inline typename PageTracker::PageAllocation PageTracker::Get(Length n) { size_t index = free_.FindAndMark(n.raw_num()); - ASSERT(released_by_page_.CountBits(0, kPagesPerHugePage.raw_num()) == - released_count_); + TC_ASSERT_EQ(released_by_page_.CountBits(), released_count_); size_t unbacked = 0; // If release_count_ == 0, CountBits will return 0 and ClearRange will be a @@ -1079,27 +526,21 @@ inline typename PageTracker::PageAllocation PageTracker::Get( if (ABSL_PREDICT_FALSE(released_count_ > 0)) { unbacked = released_by_page_.CountBits(index, n.raw_num()); released_by_page_.ClearRange(index, n.raw_num()); - ASSERT(released_count_ >= unbacked); + TC_ASSERT_GE(released_count_, unbacked); released_count_ -= unbacked; } - ASSERT(released_by_page_.CountBits(0, kPagesPerHugePage.raw_num()) == - released_count_); + TC_ASSERT_EQ(released_by_page_.CountBits(), released_count_); return PageAllocation{location_.first_page() + Length(index), Length(unbacked)}; } -template -inline void PageTracker::Put(PageId p, Length n) { - Length index = p - location_.first_page(); - free_.Unmark(index.raw_num(), n.raw_num()); - - when_numerator_ += n.raw_num() * absl::base_internal::CycleClock::Now(); - when_denominator_ += n.raw_num(); +inline void PageTracker::Put(Range r) { + Length index = r.p - location_.first_page(); + free_.Unmark(index.raw_num(), r.n.raw_num()); } -template -inline Length PageTracker::ReleaseFree() { +inline Length PageTracker::ReleaseFree(MemoryModifyFunction& unback) { size_t count = 0; size_t index = 0; size_t n; @@ -1124,16 +565,16 @@ inline Length PageTracker::ReleaseFree() { // In debug builds, verify [free_index, end) is backed. size_t length = end - free_index; - ASSERT(released_by_page_.CountBits(free_index, length) == 0); - // Mark pages as released. Amortize the update to release_count_. - released_by_page_.SetRange(free_index, length); - + TC_ASSERT_EQ(released_by_page_.CountBits(free_index, length), 0); PageId p = location_.first_page() + Length(free_index); - // TODO(b/122551676): If release fails, we should not SetRange above. - ReleasePages(p, Length(length)); + + if (ABSL_PREDICT_TRUE(ReleasePages(Range(p, Length(length)), unback))) { + // Mark pages as released. Amortize the update to release_count_. + released_by_page_.SetRange(free_index, length); + count += length; + } index = end; - count += length; } else { // [index, index+n) did not have an overlapping range in free_, move to // the next backed range of pages. @@ -1142,21 +583,15 @@ inline Length PageTracker::ReleaseFree() { } released_count_ += count; - ASSERT(Length(released_count_) <= kPagesPerHugePage); - ASSERT(released_by_page_.CountBits(0, kPagesPerHugePage.raw_num()) == - released_count_); - init_when(absl::base_internal::CycleClock::Now()); + TC_ASSERT_LE(Length(released_count_), kPagesPerHugePage); + TC_ASSERT_EQ(released_by_page_.CountBits(), released_count_); return Length(count); } -template -inline void PageTracker::AddSpanStats(SmallSpanStats* small, - LargeSpanStats* large, - PageAgeHistograms* ages) const { +inline void PageTracker::AddSpanStats(SmallSpanStats* small, + LargeSpanStats* large) const { size_t index = 0, n; - uint64_t w = when_denominator_ == 0 ? when_numerator_ - : when_numerator_ / when_denominator_; while (free_.NextFreeRange(index, &index, &n)) { bool is_released = released_by_page_.GetBit(index); // Find the last bit in the run with the same state (set or cleared) as @@ -1169,7 +604,7 @@ inline void PageTracker::AddSpanStats(SmallSpanStats* small, : released_by_page_.FindSet(index + 1); } n = std::min(end - index, n); - ASSERT(n > 0); + TC_ASSERT_GT(n, 0); if (n < kMaxPages.raw_num()) { if (small != nullptr) { @@ -1190,43 +625,44 @@ inline void PageTracker::AddSpanStats(SmallSpanStats* small, } } - if (ages) { - ages->RecordRange(Length(n), is_released, w); - } index += n; } } -template -inline bool PageTracker::empty() const { - return free_.used() == 0; -} +inline bool PageTracker::empty() const { return free_.used() == 0; } -template -inline Length PageTracker::free_pages() const { +inline Length PageTracker::free_pages() const { return kPagesPerHugePage - used_pages(); } template inline HugePageFiller::HugePageFiller( - FillerPartialRerelease partial_rerelease) - : HugePageFiller( - partial_rerelease, - Clock{.now = absl::base_internal::CycleClock::Now, - .freq = absl::base_internal::CycleClock::Frequency}) {} + HugePageFillerDenseTrackerType dense_tracker_type, + MemoryModifyFunction& unback, MemoryModifyFunction& unback_without_lock) + : HugePageFiller(Clock{.now = absl::base_internal::CycleClock::Now, + .freq = absl::base_internal::CycleClock::Frequency}, + dense_tracker_type, unback, unback_without_lock) {} // For testing with mock clock template inline HugePageFiller::HugePageFiller( - FillerPartialRerelease partial_rerelease, Clock clock) - : size_(NHugePages(0)), - partial_rerelease_(partial_rerelease), - fillerstats_tracker_(clock, absl::Minutes(10), absl::Minutes(5)) {} + Clock clock, HugePageFillerDenseTrackerType dense_tracker_type, + MemoryModifyFunction& unback, MemoryModifyFunction& unback_without_lock) + : dense_tracker_type_(dense_tracker_type), + size_(NHugePages(0)), + fillerstats_tracker_(clock, absl::Minutes(10), absl::Minutes(5)), + clock_(clock), + unback_(unback), + unback_without_lock_(unback_without_lock) {} template inline typename HugePageFiller::TryGetResult -HugePageFiller::TryGet(Length n) { - ASSERT(n > Length(0)); +HugePageFiller::TryGet(Length n, SpanAllocInfo span_alloc_info) { + TC_ASSERT_GT(n, Length(0)); + TC_ASSERT(dense_tracker_type_ == + HugePageFillerDenseTrackerType::kLongestFreeRangeAndChunks || + span_alloc_info.density == AccessDensityPrediction::kSparse || + n == Length(1)); // How do we choose which hugepage to allocate from (among those with // a free range of at least n?) Our goal is to be as space-efficient @@ -1240,7 +676,7 @@ HugePageFiller::TryGet(Length n) { // return them to the OS.) // // In practice, avoiding fragmentation is by far more important: - // space usage can explode if we don't jealously guard large free ranges. + // space usage can explode if we don't zealously guard large free ranges. // // Our primary measure of fragmentation of a hugepage by a proxy measure: the // longest free range it contains. If this is short, any free space is @@ -1280,7 +716,7 @@ HugePageFiller::TryGet(Length n) { // store each group in a TrackerList. All freshly-donated groups are stored // in a "donated" array and the groups with (possibly prior) small allocs are // stored in a "regular" array. Each of these arrays is encapsulated in a - // HintedTrackerLists object, which stores the array together with a bitmap to + // PageTrackerLists object, which stores the array together with a bitmap to // quickly find non-empty lists. The lists are ordered to satisfy the // following two useful properties: // @@ -1290,116 +726,120 @@ HugePageFiller::TryGet(Length n) { // for allocation. // // So all we have to do is find the first nonempty freelist in the regular - // HintedTrackerList that *could* support our allocation, and it will be our - // best choice. If there is none we repeat with the donated HintedTrackerList. + // PageTrackerList that *could* support our allocation, and it will be our + // best choice. If there is none we repeat with the donated PageTrackerList. ASSUME(n < kPagesPerHugePage); TrackerType* pt; bool was_released = false; + const AccessDensityPrediction type = span_alloc_info.density; do { - pt = regular_alloc_.GetLeast(ListFor(n, 0)); - if (pt) { - ASSERT(!pt->donated()); - break; - } - pt = donated_alloc_.GetLeast(n.raw_num()); + pt = regular_alloc_[type].GetLeast( + ListFor(n, 0, type, kPagesPerHugePage.raw_num() - 1)); if (pt) { + TC_ASSERT(!pt->donated()); break; } - if (partial_rerelease_ == FillerPartialRerelease::Retain) { - pt = regular_alloc_partial_released_.GetLeast(ListFor(n, 0)); + if (ABSL_PREDICT_TRUE(type == AccessDensityPrediction::kSparse)) { + pt = donated_alloc_.GetLeast(n.raw_num()); if (pt) { - ASSERT(!pt->donated()); - was_released = true; - ASSERT(n_used_partial_released_ >= pt->used_pages()); - n_used_partial_released_ -= pt->used_pages(); break; } } - pt = regular_alloc_released_.GetLeast(ListFor(n, 0)); + pt = regular_alloc_partial_released_[type].GetLeast( + ListFor(n, 0, type, kPagesPerHugePage.raw_num() - 1)); + if (pt) { + TC_ASSERT(!pt->donated()); + was_released = true; + TC_ASSERT_GE(n_used_partial_released_[type], pt->used_pages()); + n_used_partial_released_[type] -= pt->used_pages(); + break; + } + pt = regular_alloc_released_[type].GetLeast( + ListFor(n, 0, type, kPagesPerHugePage.raw_num() - 1)); if (pt) { - ASSERT(!pt->donated()); + TC_ASSERT(!pt->donated()); was_released = true; - ASSERT(n_used_released_ >= pt->used_pages()); - n_used_released_ -= pt->used_pages(); + TC_ASSERT_GE(n_used_released_[type], pt->used_pages()); + n_used_released_[type] -= pt->used_pages(); break; } - return {nullptr, PageId{0}}; + return {nullptr, PageId{0}, false}; } while (false); ASSUME(pt != nullptr); - ASSERT(pt->longest_free_range() >= n); + TC_ASSERT_GE(pt->longest_free_range(), n); + // type == AccessDensityPrediction::kDense => pt->HasDenseSpans(). This + // also verifies we do not end up with a donated pt on the kDense path. + TC_ASSERT(type == AccessDensityPrediction::kSparse || pt->HasDenseSpans()); const auto page_allocation = pt->Get(n); AddToFillerList(pt); - allocated_ += n; + pages_allocated_[type] += n; - ASSERT(was_released || page_allocation.previously_unbacked == Length(0)); - (void)was_released; - ASSERT(unmapped_ >= page_allocation.previously_unbacked); + // If it was in a released state earlier, and is about to be full again, + // record that the state has been toggled back and update the stat counter. + if (was_released && !pt->released() && !pt->was_released()) { + pt->set_was_released(/*status=*/true); + ++n_was_released_[type]; + } + TC_ASSERT(was_released || page_allocation.previously_unbacked == Length(0)); + TC_ASSERT_GE(unmapped_, page_allocation.previously_unbacked); unmapped_ -= page_allocation.previously_unbacked; // We're being used for an allocation, so we are no longer considered // donated by this point. - ASSERT(!pt->donated()); + TC_ASSERT(!pt->donated()); UpdateFillerStatsTracker(); - return {pt, page_allocation.page}; + return {pt, page_allocation.page, was_released}; } -// Marks [p, p + n) as usable by new allocations into *pt; returns pt -// if that hugepage is now empty (nullptr otherwise.) -// REQUIRES: pt is owned by this object (has been Contribute()), and -// {pt, p, n} was the result of a previous TryGet. +// Marks r as usable by new allocations into *pt; returns pt if that hugepage is +// now empty (nullptr otherwise.) +// +// REQUIRES: pt is owned by this object (has been Contribute()), and {pt, +// Range(p, n)} was the result of a previous TryGet. template -inline TrackerType* HugePageFiller::Put(TrackerType* pt, PageId p, - Length n) { - // Consider releasing [p, p+n). We do this here: - // * To unback the memory before we mark it as free. When partially - // unbacking, we release the pageheap_lock. Another thread could see the - // "free" memory and begin using it before we retake the lock. - // * To maintain maintain the invariant that - // pt->released() => regular_alloc_released_.size() > 0 || - // regular_alloc_partial_released_.size() > 0 - // We do this before removing pt from our lists, since another thread may - // encounter our post-RemoveFromFillerList() update to - // regular_alloc_released_.size() and regular_alloc_partial_released_.size() - // while encountering pt. - if (partial_rerelease_ == FillerPartialRerelease::Return) { - pt->MaybeRelease(p, n); - } - +inline TrackerType* HugePageFiller::Put(TrackerType* pt, Range r) { RemoveFromFillerList(pt); - - pt->Put(p, n); - - allocated_ -= n; - if (partial_rerelease_ == FillerPartialRerelease::Return && pt->released()) { - unmapped_ += n; - unmapping_unaccounted_ += n; + pt->Put(r); + if (pt->HasDenseSpans()) { + TC_ASSERT_GE(pages_allocated_[AccessDensityPrediction::kDense], r.n); + pages_allocated_[AccessDensityPrediction::kDense] -= r.n; + } else { + TC_ASSERT_GE(pages_allocated_[AccessDensityPrediction::kSparse], r.n); + pages_allocated_[AccessDensityPrediction::kSparse] -= r.n; } if (pt->longest_free_range() == kPagesPerHugePage) { + TC_ASSERT_EQ(pt->nallocs(), 0); --size_; if (pt->released()) { const Length free_pages = pt->free_pages(); const Length released_pages = pt->released_pages(); - ASSERT(free_pages >= released_pages); - ASSERT(unmapped_ >= released_pages); + TC_ASSERT_GE(free_pages, released_pages); + TC_ASSERT_GE(unmapped_, released_pages); unmapped_ -= released_pages; if (free_pages > released_pages) { - // We should only see a difference between free pages and released pages - // when we retain returned pages. - ASSERT(partial_rerelease_ == FillerPartialRerelease::Retain); - // pt is partially released. As the rest of the hugepage-aware // allocator works in terms of whole hugepages, we need to release the // rest of the hugepage. This simplifies subsequent accounting by // allowing us to work with hugepage-granularity, rather than needing to // retain pt's state indefinitely. - pageheap_lock.Unlock(); - TrackerType::UnbackImpl(pt->location().start_addr(), kHugePageSize); - pageheap_lock.Lock(); + bool success = + unback_without_lock_(HugeRange(pt->location(), NHugePages(1))); + + if (ABSL_PREDICT_TRUE(success)) { + unmapping_unaccounted_ += free_pages - released_pages; + } + } + } - unmapping_unaccounted_ += free_pages - released_pages; + if (pt->was_released()) { + pt->set_was_released(/*status=*/false); + if (pt->HasDenseSpans()) { + --n_was_released_[AccessDensityPrediction::kDense]; + } else { + --n_was_released_[AccessDensityPrediction::kSparse]; } } @@ -1412,17 +852,25 @@ inline TrackerType* HugePageFiller::Put(TrackerType* pt, PageId p, } template -inline void HugePageFiller::Contribute(TrackerType* pt, - bool donated) { +inline void HugePageFiller::Contribute( + TrackerType* pt, bool donated, SpanAllocInfo span_alloc_info) { // A contributed huge page should not yet be subreleased. - ASSERT(pt->released_pages() == Length(0)); + TC_ASSERT_EQ(pt->released_pages(), Length(0)); + + const AccessDensityPrediction type = span_alloc_info.density; - allocated_ += pt->used_pages(); + pages_allocated_[type] += pt->used_pages(); + TC_ASSERT(!(type == AccessDensityPrediction::kDense && donated)); if (donated) { + TC_ASSERT(pt->was_donated()); DonateToFillerList(pt); } else { + if (type == AccessDensityPrediction::kDense) { + pt->SetHasDenseSpans(); + } AddToFillerList(pt); } + ++size_; UpdateFillerStatsTracker(); } @@ -1431,15 +879,18 @@ template template inline int HugePageFiller::SelectCandidates( absl::Span candidates, int current_candidates, - const HintedTrackerLists& tracker_list, size_t tracker_start) { - auto PushCandidate = [&](TrackerType* pt) { + const PageTrackerLists& tracker_list, size_t tracker_start) { + auto PushCandidate = [&](TrackerType& pt) GOOGLE_MALLOC_SECTION { + TC_ASSERT_GT(pt.free_pages(), Length(0)); + TC_ASSERT_GT(pt.free_pages(), pt.released_pages()); + // If we have few candidates, we can avoid creating a heap. // // In ReleaseCandidates(), we unconditionally sort the list and linearly // iterate through it--rather than pop_heap repeatedly--so we only need the // heap for creating a bounded-size priority queue. if (current_candidates < candidates.size()) { - candidates[current_candidates] = pt; + candidates[current_candidates] = &pt; current_candidates++; if (current_candidates == candidates.size()) { @@ -1450,14 +901,14 @@ inline int HugePageFiller::SelectCandidates( } // Consider popping the worst candidate from our list. - if (CompareForSubrelease(candidates[0], pt)) { + if (CompareForSubrelease(candidates[0], &pt)) { // pt is worse than the current worst. return; } std::pop_heap(candidates.begin(), candidates.begin() + current_candidates, CompareForSubrelease); - candidates[current_candidates - 1] = pt; + candidates[current_candidates - 1] = &pt; std::push_heap(candidates.begin(), candidates.begin() + current_candidates, CompareForSubrelease); }; @@ -1479,11 +930,18 @@ inline Length HugePageFiller::ReleaseCandidates( #endif for (int i = 0; i < candidates.size() && total_released < target; i++) { TrackerType* best = candidates[i]; - ASSERT(best != nullptr); + TC_ASSERT_NE(best, nullptr); + + // Verify that we have pages that we can release. + TC_ASSERT_NE(best->free_pages(), Length(0)); + // TODO(b/73749855): This assertion may need to be relaxed if we release + // the pageheap_lock here. A candidate could change state with another + // thread while we have the lock released for another candidate. + TC_ASSERT_GT(best->free_pages(), best->released_pages()); #ifndef NDEBUG // Double check that our sorting criteria were applied correctly. - ASSERT(last <= best->used_pages()); + TC_ASSERT_LE(last, best->used_pages()); last = best->used_pages(); #endif @@ -1491,11 +949,22 @@ inline Length HugePageFiller::ReleaseCandidates( ++total_broken; } RemoveFromFillerList(best); - Length ret = best->ReleaseFree(); + Length ret = best->ReleaseFree(unback_); unmapped_ += ret; - ASSERT(unmapped_ >= best->released_pages()); + TC_ASSERT_GE(unmapped_, best->released_pages()); total_released += ret; AddToFillerList(best); + // If the candidate we just released from previously had was_released set, + // clear it. was_released is tracked only for pages that aren't in + // released state. + if (best->was_released() && best->released()) { + best->set_was_released(/*status=*/false); + if (best->HasDenseSpans()) { + --n_was_released_[AccessDensityPrediction::kDense]; + } else { + --n_was_released_[AccessDensityPrediction::kSparse]; + } + } } subrelease_stats_.num_pages_subreleased += total_released; @@ -1510,43 +979,70 @@ inline Length HugePageFiller::ReleaseCandidates( return total_released; } +template +inline Length HugePageFiller::FreePagesInPartialAllocs() const { + return regular_alloc_partial_released_[AccessDensityPrediction::kSparse] + .size() + .in_pages() + + regular_alloc_partial_released_[AccessDensityPrediction::kDense] + .size() + .in_pages() + + regular_alloc_released_[AccessDensityPrediction::kSparse] + .size() + .in_pages() + + regular_alloc_released_[AccessDensityPrediction::kDense] + .size() + .in_pages() - + used_pages_in_any_subreleased() - unmapped_pages(); +} + template inline Length HugePageFiller::GetDesiredSubreleasePages( - Length desired, Length total_released, absl::Duration peak_interval) { - // Don't subrelease pages if it wouldn't push you under the latest peak. - // This is a bit subtle: We want the current *mapped* pages not to be below - // the recent *demand* peak, i.e., if we have a large amount of free memory - // right now but demand is below a recent peak, we still want to subrelease. - ASSERT(total_released < desired); - - if (peak_interval == absl::ZeroDuration()) { + Length desired, Length total_released, SkipSubreleaseIntervals intervals) { + // Don't subrelease pages if it would push you under the sum of short-term + // demand fluctuation peak and long-term demand trend. This is a bit subtle: + // We want the current *mapped* pages not to be below the recent *demand* + // requirement, i.e., if we have a large amount of free memory right now but + // demand is below the requirement, we still want to subrelease. + TC_ASSERT_LT(total_released, desired); + if (!intervals.SkipSubreleaseEnabled()) { return desired; } - UpdateFillerStatsTracker(); - Length demand_at_peak = - fillerstats_tracker_.GetRecentPeak(peak_interval).num_pages; + Length required_pages; + required_pages = fillerstats_tracker_.GetRecentDemand( + intervals.short_interval, intervals.long_interval); + Length current_pages = used_pages() + free_pages(); - if (demand_at_peak != Length(0)) { + if (required_pages != Length(0)) { Length new_desired; - if (demand_at_peak >= current_pages) { + if (required_pages >= current_pages) { new_desired = total_released; } else { - new_desired = total_released + (current_pages - demand_at_peak); + new_desired = total_released + (current_pages - required_pages); } if (new_desired >= desired) { return desired; } - - // Report the amount of memory that we didn't release due to this - // mechanism, but never more than free_pages, since we would not have - // been able to release that much memory with or without this mechanism - // (i.e., reporting more would be confusing). - Length skipped_pages = std::min(free_pages(), (desired - new_desired)); + // Remaining target amount to release after applying skip subrelease. Note: + // the remaining target should always be smaller or equal to the number of + // free pages according to the mechanism (recent peak is always larger or + // equal to current used_pages), however, we still calculate allowed release + // using the minimum of the two to avoid relying on that assumption. + Length releasable_pages = + std::min(free_pages(), (new_desired - total_released)); + // Reports the amount of memory that we didn't release due to this + // mechanism, but never more than skipped free pages. In other words, + // skipped_pages is zero if all free pages are allowed to be released by + // this mechanism. Note, only free pages in the smaller of the two + // (current_pages and required_pages) are skipped, the rest are allowed to + // be subreleased. + Length skipped_pages = + std::min((free_pages() - releasable_pages), (desired - new_desired)); fillerstats_tracker_.ReportSkippedSubreleasePages( - skipped_pages, current_pages, peak_interval); + skipped_pages, std::min(current_pages, required_pages)); return new_desired; } @@ -1554,14 +1050,31 @@ inline Length HugePageFiller::GetDesiredSubreleasePages( } // Tries to release desired pages by iteratively releasing from the emptiest -// possible hugepage and releasing its free memory to the system. Return the +// possible hugepage and releasing its free memory to the system. Return the // number of pages actually released. template inline Length HugePageFiller::ReleasePages( - Length desired, absl::Duration skip_subrelease_after_peaks_interval, - bool hit_limit) { + Length desired, SkipSubreleaseIntervals intervals, + bool release_partial_alloc_pages, bool hit_limit) { Length total_released; + // If the feature to release all free pages in partially-released allocs is + // enabled, we increase the desired number of pages below to the total number + // of releasable pages in partially-released allocs. We disable this feature + // for cases when hit_limit is set to true (i.e. when memory limit is hit). + const bool release_all_from_partial_allocs = + release_partial_alloc_pages && !hit_limit; + if (ABSL_PREDICT_FALSE(release_all_from_partial_allocs)) { + // If we have fewer than desired number of free pages in partial allocs, we + // would try to release pages from full allocs as well (after we include + // unaccounted unmapped pages and release from partial allocs). Else, we aim + // to release up to the total number of free pages in partially-released + // allocs. + size_t from_partial_allocs = + kPartialAllocPagesRelease * FreePagesInPartialAllocs().raw_num(); + desired = std::max(desired, Length(from_partial_allocs)); + } + // We also do eager release, once we've called this at least once: // claim credit for anything that gets done. if (unmapping_unaccounted_.raw_num() > 0) { @@ -1570,17 +1083,19 @@ inline Length HugePageFiller::ReleasePages( Length n = unmapping_unaccounted_; unmapping_unaccounted_ = Length(0); subrelease_stats_.num_pages_subreleased += n; - - if (n >= desired) { - return n; - } - total_released += n; } - if (skip_subrelease_after_peaks_interval != absl::ZeroDuration()) { - desired = GetDesiredSubreleasePages(desired, total_released, - skip_subrelease_after_peaks_interval); + if (total_released >= desired) { + return total_released; + } + + // Only reduce desired if skip subrelease is on. + // + // Additionally, if we hit the limit, we should not be applying skip + // subrelease. OOM may be imminent. + if (intervals.SkipSubreleaseEnabled() && !hit_limit) { + desired = GetDesiredSubreleasePages(desired, total_released, intervals); if (desired <= total_released) { return total_released; } @@ -1591,37 +1106,51 @@ inline Length HugePageFiller::ReleasePages( // Optimize for releasing up to a huge page worth of small pages (scattered // over many parts of the filler). Since we hold pageheap_lock, we cannot // allocate here. - constexpr size_t kCandidates = kPagesPerHugePage.raw_num(); - using CandidateArray = std::array; - - if (partial_rerelease_ == FillerPartialRerelease::Retain) { - while (total_released < desired) { - CandidateArray candidates; - // We can skip the first kChunks lists as they are known to be 100% full. - // (Those lists are likely to be long.) - // - // We do not examine the regular_alloc_released_ lists, as only contain - // completely released pages. - int n_candidates = - SelectCandidates(absl::MakeSpan(candidates), 0, - regular_alloc_partial_released_, kChunks); - - Length released = - ReleaseCandidates(absl::MakeSpan(candidates.data(), n_candidates), - desired - total_released); - if (released == Length(0)) { - break; - } - total_released += released; + using CandidateArray = + std::array; + + while (total_released < desired) { + CandidateArray candidates; + // We can skip the first kChunks lists as they are known + // to be 100% full. (Those lists are likely to be long.) + // + // We do not examine the regular_alloc_released_ lists, as only contain + // completely released pages. + int n_candidates = SelectCandidates( + absl::MakeSpan(candidates), 0, + regular_alloc_partial_released_[AccessDensityPrediction::kSparse], + kChunks); + n_candidates = SelectCandidates( + absl::MakeSpan(candidates), n_candidates, + regular_alloc_partial_released_[AccessDensityPrediction::kDense], + kChunks); + + Length released = + ReleaseCandidates(absl::MakeSpan(candidates.data(), n_candidates), + desired - total_released); + subrelease_stats_.num_partial_alloc_pages_subreleased += released; + if (released == Length(0)) { + break; } + total_released += released; } // Only consider breaking up a hugepage if there are no partially released // pages. while (total_released < desired) { CandidateArray candidates; - int n_candidates = SelectCandidates(absl::MakeSpan(candidates), 0, - regular_alloc_, kChunks); + // TODO(b/199203282): revisit the order in which allocs are searched for + // release candidates. + // + // We select candidate hugepages from few_objects_alloc_ first as we expect + // hugepages in this alloc to become free earlier than those in other + // allocs. + int n_candidates = SelectCandidates( + absl::MakeSpan(candidates), /*current_candidates=*/0, + regular_alloc_[AccessDensityPrediction::kSparse], kChunks); + n_candidates = SelectCandidates( + absl::MakeSpan(candidates), n_candidates, + regular_alloc_[AccessDensityPrediction::kDense], kChunks); // TODO(b/138864853): Perhaps remove donated_alloc_ from here, it's not a // great candidate for partial release. n_candidates = SelectCandidates(absl::MakeSpan(candidates), n_candidates, @@ -1641,22 +1170,17 @@ inline Length HugePageFiller::ReleasePages( template inline void HugePageFiller::AddSpanStats( - SmallSpanStats* small, LargeSpanStats* large, - PageAgeHistograms* ages) const { - auto loop = [&](const TrackerType* pt) { - pt->AddSpanStats(small, large, ages); - }; - // We can skip the first kChunks lists as they are known to be 100% full. - regular_alloc_.Iter(loop, kChunks); + SmallSpanStats* small, LargeSpanStats* large) const { + auto loop = [&](const TrackerType& pt) { pt.AddSpanStats(small, large); }; + // We can skip the first kChunks lists as they are known to be + // 100% full. donated_alloc_.Iter(loop, 0); - - if (partial_rerelease_ == FillerPartialRerelease::Retain) { - regular_alloc_partial_released_.Iter(loop, 0); - } else { - ASSERT(regular_alloc_partial_released_.empty()); - ASSERT(n_used_partial_released_ == Length(0)); + for (const AccessDensityPrediction type : + {AccessDensityPrediction::kDense, AccessDensityPrediction::kSparse}) { + regular_alloc_[type].Iter(loop, kChunks); + regular_alloc_partial_released_[type].Iter(loop, 0); + regular_alloc_released_[type].Iter(loop, 0); } - regular_alloc_released_.Iter(loop, 0); } template @@ -1675,114 +1199,280 @@ namespace huge_page_filler_internal { // (mostly) even buckets in the middle. class UsageInfo { public: - enum Type { kRegular, kDonated, kPartialReleased, kReleased, kNumTypes }; + enum Type { + kSparseRegular, + kDenseRegular, + kDonated, + kSparsePartialReleased, + kDensePartialReleased, + kSparseReleased, + kDenseReleased, + kNumTypes + }; UsageInfo() { size_t i; - for (i = 0; i <= 4 && i < kPagesPerHugePage.raw_num(); ++i) { + for (i = 0; i <= kBucketsAtBounds && i < kPagesPerHugePage.raw_num(); ++i) { bucket_bounds_[buckets_size_] = i; buckets_size_++; } - if (i < kPagesPerHugePage.raw_num() - 4) { + // Histograms should have kBucketsAtBounds buckets at the start and at the + // end. Additionally kPagesPerHugePage - kBucketsAtBounds must not + // underflow. Hence the assert below. + static_assert(kPagesPerHugePage.raw_num() >= kBucketsAtBounds); + if (i < kPagesPerHugePage.raw_num() - kBucketsAtBounds) { // Because kPagesPerHugePage is a power of two, it must be at least 16 - // to get inside this "if" - either i=5 and kPagesPerHugePage=8 and - // the test fails, or kPagesPerHugePage <= 4 and the test fails. - ASSERT(kPagesPerHugePage >= Length(16)); + // to get inside this "if". The test fails if either (i=5 and + // kPagesPerHugePage=8), or kPagesPerHugePage <= kBucketsAtBounds. + TC_ASSERT_GE(kPagesPerHugePage, Length(16)); constexpr int step = kPagesPerHugePage.raw_num() / 16; // We want to move in "step"-sized increments, aligned every "step". // So first we have to round i up to the nearest step boundary. This // logic takes advantage of step being a power of two, so step-1 is // all ones in the low-order bits. i = ((i - 1) | (step - 1)) + 1; - for (; i < kPagesPerHugePage.raw_num() - 4; i += step) { + for (; i < kPagesPerHugePage.raw_num() - kBucketsAtBounds; i += step) { bucket_bounds_[buckets_size_] = i; buckets_size_++; } - i = kPagesPerHugePage.raw_num() - 4; + i = kPagesPerHugePage.raw_num() - kBucketsAtBounds; } for (; i < kPagesPerHugePage.raw_num(); ++i) { bucket_bounds_[buckets_size_] = i; buckets_size_++; } - CHECK_CONDITION(buckets_size_ <= kBucketCapacity); + + lifetime_bucket_bounds_[0] = 0; + lifetime_bucket_bounds_[1] = 1; + for (int i = 2; i <= kLifetimeBuckets; ++i) { + lifetime_bucket_bounds_[i] = lifetime_bucket_bounds_[i - 1] * 10; + } + TC_CHECK_LE(buckets_size_, kBucketCapacity); + } + + template + bool IsHugepageBacked(const TrackerType& tracker, PageFlags& pageflags) { + void* addr = tracker.location().start_addr(); + // TODO(b/28093874): Investigate if pageflags may be queried without + // pageheap_lock. + const bool is_hugepage_backed = pageflags.IsHugepageBacked(addr); + return is_hugepage_backed; + } + + // Reports the number of pages that were previously released, but later became + // full and are hugepage backed. + size_t HugepageBackedPreviouslyReleased() { + return hugepage_backed_previously_released_; } template - void Record(const TrackerType* pt, Type which) { - const Length free = kPagesPerHugePage - pt->used_pages(); - const Length lf = pt->longest_free_range(); - const size_t nalloc = pt->nallocs(); + void Record(const TrackerType& pt, PageFlags& pageflags, Type which, + double clock_now, double clock_frequency) { + TC_ASSERT_LT(which, kNumTypes); + const Length free = kPagesPerHugePage - pt.used_pages(); + const Length lf = pt.longest_free_range(); + const size_t nalloc = pt.nallocs(); // This is a little annoying as our buckets *have* to differ; // nalloc is in [1,256], free_pages and longest_free are in [0, 255]. free_page_histo_[which][BucketNum(free.raw_num())]++; longest_free_histo_[which][BucketNum(lf.raw_num())]++; nalloc_histo_[which][BucketNum(nalloc - 1)]++; + + const double elapsed = std::max(clock_now - pt.alloctime(), 0); + const absl::Duration lifetime = + absl::Milliseconds(elapsed * 1000 / clock_frequency); + ++lifetime_histo_[which][LifetimeBucketNum(lifetime)]; + + if (lifetime >= kLongLivedLifetime) { + ++long_lived_hps_histo_[which][BucketNum(nalloc - 1)]; + } + + if (free >= kLowOccupancyNumFreePages) { + ++low_occupancy_lifetime_histo_[which][LifetimeBucketNum(lifetime)]; + } + + if (which == kSparseRegular) { + nalloc_free_page_histo_[BucketNum(nalloc - 1)] + [BucketNum(free.raw_num())]++; + } + + if (IsHugepageBacked(pt, pageflags)) { + ++hugepage_backed_[which]; + if (pt.was_released()) { + ++hugepage_backed_previously_released_; + } + } + ++total_pages_[which]; } - void Print(Printer* out) { - PrintHisto(out, free_page_histo_[kRegular], - "# of regular hps with a<= # of free pages (i); + PrintHisto(out, free_page_histo_[type], type, + "hps with a<= # of free pages (i); + if (type == kDonated) continue; + PrintHisto(out, longest_free_histo_[type], type, + "hps with a<= longest free range (i); + if (type == kDonated) continue; + PrintHisto(out, nalloc_histo_[type], type, + "hps with a<= # of allocations (i); + PrintLifetimeHisto(out, lifetime_histo_[type], type, + "hps with lifetime a <= # hps < b"); + } + + out.printf( + "\nHugePageFiller: # of hps with >= %3zu free pages, with different " + "lifetimes.", + kLowOccupancyNumFreePages.raw_num()); + for (int i = 0; i < kNumTypes; ++i) { + const Type type = static_cast(i); + PrintLifetimeHisto(out, low_occupancy_lifetime_histo_[type], type, + "hps with lifetime a <= # hps < b"); + } + + out.printf("\nHugePageFiller: # of hps with lifetime >= %3zu ms.", + absl::ToInt64Milliseconds(kLongLivedLifetime)); + for (int i = 0; i < kNumTypes; ++i) { + const Type type = static_cast(i); + PrintHisto(out, long_lived_hps_histo_[type], type, + "hps with a <= # of allocations < b", 0); + } + + for (int i = 0; i < kNumTypes; ++i) { + const Type type = static_cast(i); + out.printf( + "\nHugePageFiller: %zu of %s pages hugepage backed out of %zu.", + hugepage_backed_[type], TypeToStr(type), total_pages_[type]); + } + out.printf("\n"); } - void Print(PbtxtRegion* hpaa) { - static constexpr absl::string_view kTrackerTypes[kNumTypes] = { - "REGULAR", "DONATED", "PARTIAL", "RELEASED"}; + void Print(PbtxtRegion& hpaa) { for (int i = 0; i < kNumTypes; ++i) { - PbtxtRegion scoped = hpaa->CreateSubRegion("filler_tracker"); - scoped.PrintRaw("type", kTrackerTypes[i]); - PrintHisto(&scoped, free_page_histo_[i], "free_pages_histogram", 0); - PrintHisto(&scoped, longest_free_histo_[i], - "longest_free_range_histogram", 0); - PrintHisto(&scoped, nalloc_histo_[i], "allocations_histogram", 1); + const Type type = static_cast(i); + PbtxtRegion scoped = hpaa.CreateSubRegion("filler_tracker"); + scoped.PrintRaw("type", AllocType(type)); + scoped.PrintRaw("objects", ObjectType(type)); + PrintHisto(scoped, free_page_histo_[i], "free_pages_histogram", 0); + PrintHisto(scoped, longest_free_histo_[i], "longest_free_range_histogram", + 0); + PrintHisto(scoped, nalloc_histo_[i], "allocations_histogram", 1); + PrintLifetimeHisto(scoped, lifetime_histo_[i], "lifetime_histogram"); + PrintLifetimeHisto(scoped, low_occupancy_lifetime_histo_[i], + "low_occupancy_lifetime_histogram"); + PrintHisto(scoped, long_lived_hps_histo_[i], + "long_lived_hugepages_histogram", 0); + if (type == kSparseRegular) { + for (int j = 0; j < buckets_size_; ++j) { + if (nalloc_histo_[i][j] == 0) continue; + PbtxtRegion twodhist = + hpaa.CreateSubRegion("allocations_free_pages_histogram"); + twodhist.PrintI64("lower_bound", bucket_bounds_[j] + 1); + twodhist.PrintI64("upper_bound", (j == buckets_size_ - 1 + ? bucket_bounds_[j] + : bucket_bounds_[j + 1] - 1) + + 1); + PrintHisto(twodhist, nalloc_free_page_histo_[j], "entry", 0); + } + } + scoped.PrintI64("total_pages", total_pages_[type]); + scoped.PrintI64("num_pages_hugepage_backed", hugepage_backed_[type]); } } private: - // Maximum of 4 buckets at the start and end, and 16 in the middle. - static constexpr size_t kBucketCapacity = 4 + 16 + 4; + // Maximum number of buckets at the start and end. + static constexpr size_t kBucketsAtBounds = 8; + static constexpr size_t kLifetimeBuckets = 8; + // Threshold for a page to be long-lived, as a lifetime in milliseconds, for + // telemetry purposes only. + static constexpr absl::Duration kLongLivedLifetime = + absl::Milliseconds(100000); + // Threshold for a hugepage considered to have a low occupancy, for logging + // lifetime telemetry only. + static constexpr Length kLowOccupancyNumFreePages = + Length(kPagesPerHugePage.raw_num() - (kPagesPerHugePage.raw_num() >> 3)); + // 16 buckets in the middle. + static constexpr size_t kBucketCapacity = + kBucketsAtBounds + 16 + kBucketsAtBounds; using Histo = size_t[kBucketCapacity]; + using LifetimeHisto = size_t[kLifetimeBuckets]; int BucketNum(size_t page) { auto it = std::upper_bound(bucket_bounds_, bucket_bounds_ + buckets_size_, page); - CHECK_CONDITION(it != bucket_bounds_); + TC_CHECK_NE(it, bucket_bounds_); return it - bucket_bounds_ - 1; } - void PrintHisto(Printer* out, Histo h, const char blurb[], size_t offset) { - out->printf("\nHugePageFiller: %s", blurb); + int LifetimeBucketNum(absl::Duration duration) { + int64_t duration_ms = absl::ToInt64Milliseconds(duration); + auto it = std::upper_bound(lifetime_bucket_bounds_, + lifetime_bucket_bounds_ + kLifetimeBuckets, + duration_ms); + TC_CHECK_NE(it, lifetime_bucket_bounds_); + return it - lifetime_bucket_bounds_ - 1; + } + + void PrintHisto(Printer& out, Histo h, Type type, absl::string_view blurb, + size_t offset) { + out.printf("\nHugePageFiller: # of %s %s", TypeToStr(type), blurb); for (size_t i = 0; i < buckets_size_; ++i) { if (i % 6 == 0) { - out->printf("\nHugePageFiller:"); + out.printf("\nHugePageFiller:"); + } + out.printf(" <%3zu<=%6zu", bucket_bounds_[i] + offset, h[i]); + } + out.printf("\n"); + } + + void PrintLifetimeHisto(Printer& out, Histo h, Type type, + absl::string_view blurb) { + out.printf("\nHugePageFiller: # of %s %s", TypeToStr(type), blurb); + for (size_t i = 0; i < kLifetimeBuckets; ++i) { + if (i % 6 == 0) { + out.printf("\nHugePageFiller:"); } - out->printf(" <%3zu<=%6zu", bucket_bounds_[i] + offset, h[i]); + out.printf(" < %3zu ms <= %6zu", lifetime_bucket_bounds_[i], h[i]); } - out->printf("\n"); + out.printf("\n"); } - void PrintHisto(PbtxtRegion* hpaa, Histo h, const char key[], size_t offset) { + void PrintHisto(PbtxtRegion& hpaa, Histo h, absl::string_view key, + size_t offset) { for (size_t i = 0; i < buckets_size_; ++i) { - auto hist = hpaa->CreateSubRegion(key); + if (h[i] == 0) continue; + auto hist = hpaa.CreateSubRegion(key); hist.PrintI64("lower_bound", bucket_bounds_[i] + offset); hist.PrintI64("upper_bound", (i == buckets_size_ - 1 ? bucket_bounds_[i] @@ -1792,68 +1482,225 @@ class UsageInfo { } } + void PrintLifetimeHisto(PbtxtRegion& hpaa, Histo h, absl::string_view key) { + for (size_t i = 0; i < kLifetimeBuckets; ++i) { + if (h[i] == 0) continue; + auto hist = hpaa.CreateSubRegion(key); + hist.PrintI64("lower_bound", lifetime_bucket_bounds_[i]); + hist.PrintI64("upper_bound", (i == kLifetimeBuckets - 1 + ? lifetime_bucket_bounds_[i] + : lifetime_bucket_bounds_[i + 1])); + hist.PrintI64("value", h[i]); + } + } + + absl::string_view TypeToStr(Type type) const { + TC_ASSERT_LT(type, kNumTypes); + switch (type) { + case kSparseRegular: + return "sparsely-accessed regular"; + case kDenseRegular: + return "densely-accessed regular"; + case kDonated: + return "donated"; + case kSparsePartialReleased: + return "sparsely-accessed partial released"; + case kDensePartialReleased: + return "densely-accessed partial released"; + case kSparseReleased: + return "sparsely-accessed released"; + case kDenseReleased: + return "densely-accessed released"; + default: + TC_BUG("bad type %v", type); + } + } + + absl::string_view AllocType(Type type) const { + TC_ASSERT_LT(type, kNumTypes); + switch (type) { + case kSparseRegular: + case kDenseRegular: + return "REGULAR"; + case kDonated: + return "DONATED"; + case kSparsePartialReleased: + case kDensePartialReleased: + return "PARTIAL"; + case kSparseReleased: + case kDenseReleased: + return "RELEASED"; + default: + TC_BUG("bad type %v", type); + } + } + + absl::string_view ObjectType(Type type) const { + TC_ASSERT_LT(type, kNumTypes); + switch (type) { + case kSparseRegular: + case kDonated: + case kSparsePartialReleased: + case kSparseReleased: + return "SPARSELY_ACCESSED"; + case kDenseRegular: + case kDensePartialReleased: + case kDenseReleased: + return "DENSELY_ACCESSED"; + default: + TC_BUG("bad type %v", type); + } + } + // Arrays, because they are split per alloc type. Histo free_page_histo_[kNumTypes]{}; Histo longest_free_histo_[kNumTypes]{}; Histo nalloc_histo_[kNumTypes]{}; + LifetimeHisto lifetime_histo_[kNumTypes]{}; + Histo long_lived_hps_histo_[kNumTypes]{}; + LifetimeHisto low_occupancy_lifetime_histo_[kNumTypes]{}; + // TODO(b/282993806): drop nalloc_free_page_histo_ after experiment is done. + // Two dimensional histogram. The outer histogram is indexed using the number + // of allocations. The nested histogram is indexed using the number of free + // pages. + // + // Unlike the histograms above, which have separate histograms for each type, + // the histogram below has data only for kSparseRegular hugepages. This is + // being done to reduce the amount of space required. + Histo nalloc_free_page_histo_[kBucketCapacity]{}; size_t bucket_bounds_[kBucketCapacity]; + size_t lifetime_bucket_bounds_[kBucketCapacity]; + size_t hugepage_backed_[kNumTypes] = {0}; + size_t total_pages_[kNumTypes] = {0}; + size_t hugepage_backed_previously_released_ = 0; int buckets_size_ = 0; }; } // namespace huge_page_filler_internal template -inline void HugePageFiller::Print(Printer* out, - bool everything) const { - out->printf("HugePageFiller: densely pack small requests into hugepages\n"); - - HugeLength nrel = - regular_alloc_released_.size() + regular_alloc_partial_released_.size(); - HugeLength nfull = NHugePages(0); - - // note kChunks, not kNumLists here--we're iterating *full* lists. +inline HugePageFillerStats HugePageFiller::GetStats() const { + HugePageFillerStats stats; + // Note kChunks, not kNumLists here--we're iterating *full* lists. for (size_t chunk = 0; chunk < kChunks; ++chunk) { - nfull += NHugePages( - regular_alloc_[ListFor(/*longest=*/Length(0), chunk)].length()); + stats.n_full[AccessDensityPrediction::kSparse] += NHugePages( + regular_alloc_[AccessDensityPrediction::kSparse] + [ListFor(/*longest=*/Length(0), chunk, + AccessDensityPrediction::kSparse, /*nallocs=*/0)] + .length()); + stats.n_full[AccessDensityPrediction::kDense] += + NHugePages(regular_alloc_[AccessDensityPrediction::kDense] + [ListFor(/*longest=*/Length(0), chunk, + AccessDensityPrediction::kDense, + kPagesPerHugePage.raw_num())] + .length()); } + stats.n_full[AccessDensityPrediction::kPredictionCounts] = + stats.n_full[AccessDensityPrediction::kSparse] + + stats.n_full[AccessDensityPrediction::kDense]; + + // We only use donated allocs for allocating sparse pages. + stats.n_total[AccessDensityPrediction::kSparse] = donated_alloc_.size(); + for (const AccessDensityPrediction count : + {AccessDensityPrediction::kSparse, AccessDensityPrediction::kDense}) { + stats.n_fully_released[count] = regular_alloc_released_[count].size(); + stats.n_partial_released[count] = + regular_alloc_partial_released_[count].size(); + stats.n_released[count] = + stats.n_fully_released[count] + stats.n_partial_released[count]; + stats.n_total[count] += + stats.n_released[count] + regular_alloc_[count].size(); + stats.n_partial[count] = + stats.n_total[count] - stats.n_released[count] - stats.n_full[count]; + } + + // Collect total stats that is the sum of both kSparse and kDense allocs. + stats.n_fully_released[AccessDensityPrediction::kPredictionCounts] = + stats.n_fully_released[AccessDensityPrediction::kSparse] + + stats.n_fully_released[AccessDensityPrediction::kDense]; + stats.n_partial_released[AccessDensityPrediction::kPredictionCounts] = + stats.n_partial_released[AccessDensityPrediction::kSparse] + + stats.n_partial_released[AccessDensityPrediction::kDense]; + stats.n_released[AccessDensityPrediction::kPredictionCounts] = + stats.n_released[AccessDensityPrediction::kSparse] + + stats.n_released[AccessDensityPrediction::kDense]; + + stats.n_total[AccessDensityPrediction::kPredictionCounts] = size(); + stats.n_partial[AccessDensityPrediction::kPredictionCounts] = + size() - stats.n_released[AccessDensityPrediction::kPredictionCounts] - + stats.n_full[AccessDensityPrediction::kPredictionCounts]; + return stats; +} + +template +inline void HugePageFiller::Print(Printer& out, bool everything) { + out.printf("HugePageFiller: densely pack small requests into hugepages\n"); + const HugePageFillerStats stats = GetStats(); + // A donated alloc full list is impossible because it would have never been // donated in the first place. (It's an even hugepage.) - ASSERT(donated_alloc_[0].empty()); + TC_ASSERT(donated_alloc_[0].empty()); // Evaluate a/b, avoiding division by zero const auto safe_div = [](Length a, Length b) { return b == Length(0) ? 0. : static_cast(a.raw_num()) / static_cast(b.raw_num()); }; - const HugeLength n_partial = size() - nrel - nfull; - const HugeLength n_nonfull = - n_partial + regular_alloc_partial_released_.size(); - out->printf( - "HugePageFiller: %zu total, %zu full, %zu partial, %zu released " + out.printf( + "HugePageFiller: Overall, %zu total, %zu full, %zu partial, %zu released " "(%zu partially), 0 quarantined\n", - size().raw_num(), nfull.raw_num(), n_partial.raw_num(), nrel.raw_num(), - regular_alloc_partial_released_.size().raw_num()); - out->printf("HugePageFiller: %zu pages free in %zu hugepages, %.4f free\n", - free_pages().raw_num(), size().raw_num(), - safe_div(free_pages(), size().in_pages())); + size().raw_num(), + stats.n_full[AccessDensityPrediction::kPredictionCounts].raw_num(), + stats.n_partial[AccessDensityPrediction::kPredictionCounts].raw_num(), + stats.n_released[AccessDensityPrediction::kPredictionCounts].raw_num(), + stats.n_partial_released[AccessDensityPrediction::kPredictionCounts] + .raw_num()); + + out.printf( + "HugePageFiller: those with sparsely-accessed spans, %zu total, " + "%zu full, %zu partial, %zu released (%zu partially), 0 quarantined\n", + stats.n_total[AccessDensityPrediction::kSparse].raw_num(), + stats.n_full[AccessDensityPrediction::kSparse].raw_num(), + stats.n_partial[AccessDensityPrediction::kSparse].raw_num(), + stats.n_released[AccessDensityPrediction::kSparse].raw_num(), + stats.n_partial_released[AccessDensityPrediction::kSparse].raw_num()); + + out.printf( + "HugePageFiller: those with densely-accessed spans, %zu total, " + "%zu full, %zu partial, %zu released (%zu partially), 0 quarantined\n", + stats.n_total[AccessDensityPrediction::kDense].raw_num(), + stats.n_full[AccessDensityPrediction::kDense].raw_num(), + stats.n_partial[AccessDensityPrediction::kDense].raw_num(), + stats.n_released[AccessDensityPrediction::kDense].raw_num(), + stats.n_partial_released[AccessDensityPrediction::kDense].raw_num()); + + out.printf("HugePageFiller: %zu pages free in %zu hugepages, %.4f free\n", + free_pages().raw_num(), size().raw_num(), + safe_div(free_pages(), size().in_pages())); - ASSERT(free_pages() <= n_nonfull.in_pages()); - out->printf("HugePageFiller: among non-fulls, %.4f free\n", - safe_div(free_pages(), n_nonfull.in_pages())); + const HugeLength n_nonfull = + stats.n_partial[AccessDensityPrediction::kPredictionCounts] + + stats.n_partial_released[AccessDensityPrediction::kPredictionCounts]; + TC_ASSERT_LE(free_pages(), n_nonfull.in_pages()); + out.printf("HugePageFiller: among non-fulls, %.4f free\n", + safe_div(free_pages(), n_nonfull.in_pages())); - out->printf( + out.printf( "HugePageFiller: %zu used pages in subreleased hugepages (%zu of them in " "partially released)\n", used_pages_in_any_subreleased().raw_num(), used_pages_in_partial_released().raw_num()); - out->printf( + out.printf( "HugePageFiller: %zu hugepages partially released, %.4f released\n", - nrel.raw_num(), safe_div(unmapped_pages(), nrel.in_pages())); - out->printf("HugePageFiller: %.4f of used pages hugepageable\n", - hugepage_frac()); + stats.n_released[AccessDensityPrediction::kPredictionCounts].raw_num(), + safe_div(unmapped_pages(), + stats.n_released[AccessDensityPrediction::kPredictionCounts] + .in_pages())); + out.printf("HugePageFiller: %.4f of used pages hugepageable\n", + hugepage_frac()); // Subrelease - out->printf( + out.printf( "HugePageFiller: Since startup, %zu pages subreleased, %zu hugepages " "broken, (%zu pages, %zu hugepages due to reaching tcmalloc limit)\n", subrelease_stats_.total_pages_subreleased.raw_num(), @@ -1866,130 +1713,225 @@ inline void HugePageFiller::Print(Printer* out, // Compute some histograms of fullness. using huge_page_filler_internal::UsageInfo; UsageInfo usage; - regular_alloc_.Iter( - [&](const TrackerType* pt) { usage.Record(pt, UsageInfo::kRegular); }, 0); + const double now = clock_.now(); + const double frequency = clock_.freq(); + PageFlags pageflags; donated_alloc_.Iter( - [&](const TrackerType* pt) { usage.Record(pt, UsageInfo::kDonated); }, 0); - if (partial_rerelease_ == FillerPartialRerelease::Retain) { - regular_alloc_partial_released_.Iter( - [&](const TrackerType* pt) { - usage.Record(pt, UsageInfo::kPartialReleased); - }, - 0); - } else { - ASSERT(regular_alloc_partial_released_.empty()); - ASSERT(n_used_partial_released_.raw_num() == 0); - } - regular_alloc_released_.Iter( - [&](const TrackerType* pt) { usage.Record(pt, UsageInfo::kReleased); }, + [&](const TrackerType& pt) { + usage.Record(pt, pageflags, UsageInfo::kDonated, now, frequency); + }, 0); + regular_alloc_[AccessDensityPrediction::kSparse].Iter( + [&](const TrackerType& pt) { + usage.Record(pt, pageflags, UsageInfo::kSparseRegular, now, frequency); + }, + 0); + regular_alloc_[AccessDensityPrediction::kDense].Iter( + [&](const TrackerType& pt) { + usage.Record(pt, pageflags, UsageInfo::kDenseRegular, now, frequency); + }, + 0); + regular_alloc_partial_released_[AccessDensityPrediction::kSparse].Iter( + [&](const TrackerType& pt) { + usage.Record(pt, pageflags, UsageInfo::kSparsePartialReleased, now, + frequency); + }, + 0); + regular_alloc_partial_released_[AccessDensityPrediction::kDense].Iter( + [&](const TrackerType& pt) { + usage.Record(pt, pageflags, UsageInfo::kDensePartialReleased, now, + frequency); + }, + 0); + regular_alloc_released_[AccessDensityPrediction::kSparse].Iter( + [&](const TrackerType& pt) { + usage.Record(pt, pageflags, UsageInfo::kSparseReleased, now, frequency); + }, + 0); + regular_alloc_released_[AccessDensityPrediction::kDense].Iter( + [&](const TrackerType& pt) { + usage.Record(pt, pageflags, UsageInfo::kDenseReleased, now, frequency); + }, + 0); + + out.printf( + "HugePageFiller: %zu hugepages became full after being previously " + "released, " + "out of which %zu pages are hugepage backed.\n", + previously_released_huge_pages().raw_num(), + usage.HugepageBackedPreviouslyReleased()); - out->printf("\n"); - out->printf("HugePageFiller: fullness histograms\n"); + out.printf("\n"); + out.printf("HugePageFiller: fullness histograms\n"); usage.Print(out); - out->printf("\n"); - fillerstats_tracker_.Print(out); + out.printf("\n"); + fillerstats_tracker_.Print(out, "HugePageFiller"); } template -inline void HugePageFiller::PrintInPbtxt(PbtxtRegion* hpaa) const { - HugeLength nrel = - regular_alloc_released_.size() + regular_alloc_partial_released_.size(); - HugeLength nfull = NHugePages(0); +inline void HugePageFiller::PrintAllocStatsInPbtxt( + absl::string_view field, PbtxtRegion& hpaa, + const HugePageFillerStats& stats, AccessDensityPrediction count) const { + TC_ASSERT_LT(count, AccessDensityPrediction::kPredictionCounts); + PbtxtRegion alloc_region = hpaa.CreateSubRegion(field); + alloc_region.PrintI64("full_huge_pages", stats.n_full[count].raw_num()); + alloc_region.PrintI64("partial_huge_pages", stats.n_partial[count].raw_num()); + alloc_region.PrintI64("released_huge_pages", + stats.n_released[count].raw_num()); + alloc_region.PrintI64("partially_released_huge_pages", + stats.n_partial_released[count].raw_num()); +} + +template +inline void HugePageFiller::PrintInPbtxt(PbtxtRegion& hpaa) const { + const HugePageFillerStats stats = GetStats(); - // note kChunks, not kNumLists here--we're iterating *full* lists. - for (size_t chunk = 0; chunk < kChunks; ++chunk) { - nfull += NHugePages( - regular_alloc_[ListFor(/*longest=*/Length(0), chunk)].length()); - } // A donated alloc full list is impossible because it would have never been // donated in the first place. (It's an even hugepage.) - ASSERT(donated_alloc_[0].empty()); + TC_ASSERT(donated_alloc_[0].empty()); // Evaluate a/b, avoiding division by zero const auto safe_div = [](Length a, Length b) { - return b == Length(0) ? 0 + return b == Length(0) ? 0. : static_cast(a.raw_num()) / static_cast(b.raw_num()); }; - const HugeLength n_partial = size() - nrel - nfull; - hpaa->PrintI64("filler_full_huge_pages", nfull.raw_num()); - hpaa->PrintI64("filler_partial_huge_pages", n_partial.raw_num()); - hpaa->PrintI64("filler_released_huge_pages", nrel.raw_num()); - hpaa->PrintI64("filler_partially_released_huge_pages", - regular_alloc_partial_released_.size().raw_num()); - hpaa->PrintI64("filler_free_pages", free_pages().raw_num()); - hpaa->PrintI64("filler_used_pages_in_subreleased", - used_pages_in_any_subreleased().raw_num()); - hpaa->PrintI64("filler_used_pages_in_partial_released", - used_pages_in_partial_released().raw_num()); - hpaa->PrintI64( + + hpaa.PrintI64( + "filler_full_huge_pages", + stats.n_full[AccessDensityPrediction::kPredictionCounts].raw_num()); + hpaa.PrintI64( + "filler_partial_huge_pages", + stats.n_partial[AccessDensityPrediction::kPredictionCounts].raw_num()); + hpaa.PrintI64( + "filler_released_huge_pages", + stats.n_released[AccessDensityPrediction::kPredictionCounts].raw_num()); + hpaa.PrintI64( + "filler_partially_released_huge_pages", + stats.n_partial_released[AccessDensityPrediction::kPredictionCounts] + .raw_num()); + + PrintAllocStatsInPbtxt("filler_sparsely_accessed_alloc_stats", hpaa, stats, + AccessDensityPrediction::kSparse); + PrintAllocStatsInPbtxt("filler_densely_accessed_alloc_stats", hpaa, stats, + AccessDensityPrediction::kDense); + + hpaa.PrintI64("filler_free_pages", free_pages().raw_num()); + hpaa.PrintI64("filler_used_pages_in_subreleased", + used_pages_in_any_subreleased().raw_num()); + hpaa.PrintI64("filler_used_pages_in_partial_released", + used_pages_in_partial_released().raw_num()); + hpaa.PrintI64( "filler_unmapped_bytes", - static_cast(nrel.raw_num() * - safe_div(unmapped_pages(), nrel.in_pages()))); - hpaa->PrintI64( + static_cast( + stats.n_released[AccessDensityPrediction::kPredictionCounts] + .raw_num() * + safe_div(unmapped_pages(), + stats.n_released[AccessDensityPrediction::kPredictionCounts] + .in_pages()))); + hpaa.PrintI64( "filler_hugepageable_used_bytes", - static_cast(hugepage_frac() * - static_cast(allocated_.in_bytes()))); - hpaa->PrintI64("filler_num_pages_subreleased", - subrelease_stats_.total_pages_subreleased.raw_num()); - hpaa->PrintI64("filler_num_hugepages_broken", - subrelease_stats_.total_hugepages_broken.raw_num()); - hpaa->PrintI64( + static_cast( + hugepage_frac() * + static_cast( + pages_allocated_[AccessDensityPrediction::kSparse].in_bytes() + + pages_allocated_[AccessDensityPrediction::kDense].in_bytes()))); + hpaa.PrintI64("filler_previously_released_huge_pages", + previously_released_huge_pages().raw_num()); + hpaa.PrintI64("filler_num_pages_subreleased", + subrelease_stats_.total_pages_subreleased.raw_num()); + hpaa.PrintI64("filler_num_hugepages_broken", + subrelease_stats_.total_hugepages_broken.raw_num()); + hpaa.PrintI64( "filler_num_pages_subreleased_due_to_limit", subrelease_stats_.total_pages_subreleased_due_to_limit.raw_num()); - hpaa->PrintI64( + hpaa.PrintI64( "filler_num_hugepages_broken_due_to_limit", subrelease_stats_.total_hugepages_broken_due_to_limit.raw_num()); // Compute some histograms of fullness. using huge_page_filler_internal::UsageInfo; UsageInfo usage; - regular_alloc_.Iter( - [&](const TrackerType* pt) { usage.Record(pt, UsageInfo::kRegular); }, 0); + const double now = clock_.now(); + const double frequency = clock_.freq(); + PageFlags pageflags; donated_alloc_.Iter( - [&](const TrackerType* pt) { usage.Record(pt, UsageInfo::kDonated); }, 0); - if (partial_rerelease_ == FillerPartialRerelease::Retain) { - regular_alloc_partial_released_.Iter( - [&](const TrackerType* pt) { - usage.Record(pt, UsageInfo::kPartialReleased); - }, - 0); - } else { - ASSERT(regular_alloc_partial_released_.empty()); - ASSERT(n_used_partial_released_ == Length(0)); - } - regular_alloc_released_.Iter( - [&](const TrackerType* pt) { usage.Record(pt, UsageInfo::kReleased); }, + [&](const TrackerType& pt) { + usage.Record(pt, pageflags, UsageInfo::kDonated, now, frequency); + }, + 0); + regular_alloc_[AccessDensityPrediction::kSparse].Iter( + [&](const TrackerType& pt) { + usage.Record(pt, pageflags, UsageInfo::kSparseRegular, now, frequency); + }, + 0); + regular_alloc_[AccessDensityPrediction::kDense].Iter( + [&](const TrackerType& pt) { + usage.Record(pt, pageflags, UsageInfo::kDenseRegular, now, frequency); + }, + 0); + regular_alloc_partial_released_[AccessDensityPrediction::kSparse].Iter( + [&](const TrackerType& pt) { + usage.Record(pt, pageflags, UsageInfo::kSparsePartialReleased, now, + frequency); + }, + 0); + regular_alloc_partial_released_[AccessDensityPrediction::kDense].Iter( + [&](const TrackerType& pt) { + usage.Record(pt, pageflags, UsageInfo::kDensePartialReleased, now, + frequency); + }, + 0); + regular_alloc_released_[AccessDensityPrediction::kSparse].Iter( + [&](const TrackerType& pt) { + usage.Record(pt, pageflags, UsageInfo::kSparseReleased, now, frequency); + }, + 0); + regular_alloc_released_[AccessDensityPrediction::kDense].Iter( + [&](const TrackerType& pt) { + usage.Record(pt, pageflags, UsageInfo::kDenseReleased, now, frequency); + }, 0); + hpaa.PrintI64("filler_previously_released_backed_huge_pages", + usage.HugepageBackedPreviouslyReleased()); usage.Print(hpaa); - - fillerstats_tracker_.PrintInPbtxt(hpaa); + fillerstats_tracker_.PrintSubreleaseStatsInPbtxt(hpaa, + "filler_skipped_subrelease"); + fillerstats_tracker_.PrintTimeseriesStatsInPbtxt(hpaa, + "filler_stats_timeseries"); } template inline void HugePageFiller::UpdateFillerStatsTracker() { - StatsTrackerType::FillerStats stats; - stats.num_pages = allocated_; + StatsTrackerType::SubreleaseStats stats; + stats.num_pages = pages_allocated(); stats.free_pages = free_pages(); stats.unmapped_pages = unmapped_pages(); stats.used_pages_in_subreleased_huge_pages = - n_used_partial_released_ + n_used_released_; - stats.huge_pages[StatsTrackerType::kRegular] = regular_alloc_.size(); + n_used_released_[AccessDensityPrediction::kDense] + + n_used_released_[AccessDensityPrediction::kSparse] + + n_used_partial_released_[AccessDensityPrediction::kDense] + + n_used_partial_released_[AccessDensityPrediction::kSparse]; stats.huge_pages[StatsTrackerType::kDonated] = donated_alloc_.size(); - stats.huge_pages[StatsTrackerType::kPartialReleased] = - regular_alloc_partial_released_.size(); - stats.huge_pages[StatsTrackerType::kReleased] = - regular_alloc_released_.size(); + for (const AccessDensityPrediction type : + {AccessDensityPrediction::kDense, AccessDensityPrediction::kSparse}) { + stats.huge_pages[StatsTrackerType::kRegular] += regular_alloc_[type].size(); + stats.huge_pages[StatsTrackerType::kPartialReleased] += + regular_alloc_partial_released_[type].size(); + stats.huge_pages[StatsTrackerType::kReleased] += + regular_alloc_released_[type].size(); + } stats.num_pages_subreleased = subrelease_stats_.num_pages_subreleased; + stats.num_partial_alloc_pages_subreleased = + subrelease_stats_.num_partial_alloc_pages_subreleased; stats.num_hugepages_broken = subrelease_stats_.num_hugepages_broken; fillerstats_tracker_.Report(stats); subrelease_stats_.reset(); } template -inline size_t HugePageFiller::IndexFor(TrackerType* pt) { - ASSERT(!pt->empty()); +inline size_t HugePageFiller::IndexFor(TrackerType* pt) const { + TC_ASSERT(!pt->empty()); // Prefer to allocate from hugepages with many allocations already present; // spaced logarithmically. const size_t na = pt->nallocs(); @@ -1998,52 +1940,69 @@ inline size_t HugePageFiller::IndexFor(TrackerType* pt) { const size_t neg_ceil_log = __builtin_clzl(2 * na - 1); // We want the same spread as neg_ceil_log, but spread over [0, - // kChunks) (clamped at the left edge) instead of [0, 64). So subtract off - // the difference (computed by forcing na=1 to kChunks - 1.) + // kChunks) (clamped at the left edge) instead of [0, 64). So + // subtract off the difference (computed by forcing na=1 to + // kChunks - 1.) const size_t kOffset = __builtin_clzl(1) - (kChunks - 1); const size_t i = std::max(neg_ceil_log, kOffset) - kOffset; - ASSERT(i < kChunks); + TC_ASSERT_LT(i, kChunks); return i; } template -inline size_t HugePageFiller::ListFor(const Length longest, - const size_t chunk) { - ASSERT(chunk < kChunks); - ASSERT(longest < kPagesPerHugePage); - return longest.raw_num() * kChunks + chunk; +inline size_t HugePageFiller::ListFor( + const Length longest, const size_t chunk, + const AccessDensityPrediction density, size_t nallocs) const { + TC_ASSERT_LT(chunk, kChunks); + if (ABSL_PREDICT_TRUE( + density == AccessDensityPrediction::kSparse || + dense_tracker_type_ == + HugePageFillerDenseTrackerType::kLongestFreeRangeAndChunks)) { + TC_ASSERT_LT(longest, kPagesPerHugePage); + return longest.raw_num() * kChunks + chunk; + } + TC_ASSERT(density == AccessDensityPrediction::kDense); + TC_ASSERT(dense_tracker_type_ == + HugePageFillerDenseTrackerType::kSpansAllocated); + TC_ASSERT_LE(nallocs, kPagesPerHugePage.raw_num()); + // For the dense tracker with hugepages sorted on allocs, the hugepages are + // placed only in lists that are multiples of kChunks. The in-between lists + // are empty. + return (kPagesPerHugePage.raw_num() - nallocs) * kChunks + chunk; } template inline void HugePageFiller::RemoveFromFillerList(TrackerType* pt) { Length longest = pt->longest_free_range(); - ASSERT(longest < kPagesPerHugePage); + TC_ASSERT_LT(longest, kPagesPerHugePage); if (pt->donated()) { donated_alloc_.Remove(pt, longest.raw_num()); + return; + } + + const AccessDensityPrediction type = pt->HasDenseSpans() + ? AccessDensityPrediction::kDense + : AccessDensityPrediction::kSparse; + size_t i = ListFor(longest, IndexFor(pt), type, pt->nallocs()); + + if (!pt->released()) { + regular_alloc_[type].Remove(pt, i); + } else if (pt->free_pages() <= pt->released_pages()) { + regular_alloc_released_[type].Remove(pt, i); + TC_ASSERT_GE(n_used_released_[type], pt->used_pages()); + n_used_released_[type] -= pt->used_pages(); } else { - size_t chunk = IndexFor(pt); - size_t i = ListFor(longest, chunk); - if (!pt->released()) { - regular_alloc_.Remove(pt, i); - } else if (partial_rerelease_ == FillerPartialRerelease::Return || - pt->free_pages() <= pt->released_pages()) { - regular_alloc_released_.Remove(pt, i); - ASSERT(n_used_released_ >= pt->used_pages()); - n_used_released_ -= pt->used_pages(); - } else { - regular_alloc_partial_released_.Remove(pt, i); - ASSERT(n_used_partial_released_ >= pt->used_pages()); - n_used_partial_released_ -= pt->used_pages(); - } + regular_alloc_partial_released_[type].Remove(pt, i); + TC_ASSERT_GE(n_used_partial_released_[type], pt->used_pages()); + n_used_partial_released_[type] -= pt->used_pages(); } } template inline void HugePageFiller::AddToFillerList(TrackerType* pt) { - size_t chunk = IndexFor(pt); Length longest = pt->longest_free_range(); - ASSERT(longest < kPagesPerHugePage); + TC_ASSERT_LT(longest, kPagesPerHugePage); // Once a donated alloc is used in any way, it degenerates into being a // regular alloc. This allows the algorithm to keep using it (we had to be @@ -2051,27 +2010,29 @@ inline void HugePageFiller::AddToFillerList(TrackerType* pt) { // donated allocs. pt->set_donated(false); - size_t i = ListFor(longest, chunk); + const AccessDensityPrediction type = pt->HasDenseSpans() + ? AccessDensityPrediction::kDense + : AccessDensityPrediction::kSparse; + size_t i = ListFor(longest, IndexFor(pt), type, pt->nallocs()); + if (!pt->released()) { - regular_alloc_.Add(pt, i); - } else if (partial_rerelease_ == FillerPartialRerelease::Return || - pt->free_pages() == pt->released_pages()) { - regular_alloc_released_.Add(pt, i); - n_used_released_ += pt->used_pages(); + regular_alloc_[type].Add(pt, i); + } else if (pt->free_pages() <= pt->released_pages()) { + regular_alloc_released_[type].Add(pt, i); + n_used_released_[type] += pt->used_pages(); } else { - ASSERT(partial_rerelease_ == FillerPartialRerelease::Retain); - regular_alloc_partial_released_.Add(pt, i); - n_used_partial_released_ += pt->used_pages(); + regular_alloc_partial_released_[type].Add(pt, i); + n_used_partial_released_[type] += pt->used_pages(); } } template inline void HugePageFiller::DonateToFillerList(TrackerType* pt) { Length longest = pt->longest_free_range(); - ASSERT(longest < kPagesPerHugePage); + TC_ASSERT_LT(longest, kPagesPerHugePage); // We should never be donating already-released trackers! - ASSERT(!pt->released()); + TC_ASSERT(!pt->released()); pt->set_donated(true); donated_alloc_.Add(pt, longest.raw_num()); @@ -2082,24 +2043,33 @@ inline double HugePageFiller::hugepage_frac() const { // How many of our used pages are on non-huge pages? Since // everything on a released hugepage is either used or released, // just the difference: - const Length nrel = regular_alloc_released_.size().in_pages(); const Length used = used_pages(); - const Length unmapped = unmapped_pages(); - ASSERT(n_used_partial_released_ <= - regular_alloc_partial_released_.size().in_pages()); - const Length used_on_rel = (nrel >= unmapped ? nrel - unmapped : Length(0)) + - n_used_partial_released_; - ASSERT(used >= used_on_rel); + const Length used_on_rel = used_pages_in_any_subreleased(); + TC_ASSERT_GE(used, used_on_rel); const Length used_on_huge = used - used_on_rel; const Length denom = used > Length(0) ? used : Length(1); const double ret = static_cast(used_on_huge.raw_num()) / denom.raw_num(); - ASSERT(ret >= 0); - ASSERT(ret <= 1); + TC_ASSERT_GE(ret, 0); + TC_ASSERT_LE(ret, 1); return std::clamp(ret, 0, 1); } +template +template +void HugePageFiller::ForEachHugePage(const F& func) { + donated_alloc_.Iter(func, 0); + regular_alloc_[AccessDensityPrediction::kSparse].Iter(func, 0); + regular_alloc_[AccessDensityPrediction::kDense].Iter(func, 0); + regular_alloc_partial_released_[AccessDensityPrediction::kSparse].Iter(func, + 0); + regular_alloc_partial_released_[AccessDensityPrediction::kDense].Iter(func, + 0); + regular_alloc_released_[AccessDensityPrediction::kSparse].Iter(func, 0); + regular_alloc_released_[AccessDensityPrediction::kDense].Iter(func, 0); +} + // Helper for stat functions. template inline Length HugePageFiller::free_pages() const { diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_page_filler_fuzz.cc b/contrib/libs/tcmalloc/tcmalloc/huge_page_filler_fuzz.cc new file mode 100644 index 000000000000..9c72b140acba --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/huge_page_filler_fuzz.cc @@ -0,0 +1,450 @@ +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include + +#include "fuzztest/fuzztest.h" +#include "absl/base/attributes.h" +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/log/check.h" +#include "absl/time/time.h" +#include "tcmalloc/common.h" +#include "tcmalloc/huge_cache.h" +#include "tcmalloc/huge_page_filler.h" +#include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/allocation_guard.h" +#include "tcmalloc/internal/clock.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/span.h" +#include "tcmalloc/stats.h" + +namespace tcmalloc::tcmalloc_internal { +namespace { + +// As we read the fuzzer input, we update these variables to control global +// state. +int64_t fake_clock = 0; +bool unback_success = true; + +int64_t mock_clock() { return fake_clock; } + +double freq() { return 1 << 10; } + +absl::flat_hash_set& ReleasedPages() { + static auto* set = new absl::flat_hash_set(); + return *set; +} + +class MockUnback final : public MemoryModifyFunction { + public: + [[nodiscard]] bool operator()(Range r) override { + if (!unback_success) { + return false; + } + + absl::flat_hash_set& released_set = ReleasedPages(); + + PageId end = r.p + r.n; + for (; r.p != end; ++r.p) { + released_set.insert(r.p); + } + + return true; + } +}; + +void FuzzFiller(const std::string& s) { + const char* data = s.data(); + size_t size = s.size(); + + // TODO(b/271282540): Strongly type these parameters from fuzztest. + constexpr int kInitBytes = 3; + if (size <= kInitBytes || size > 100000) { + // size <= kInitBytes for needing some entropy to initialize the filler + // with. + // + // size > 100000 for avoiding overly large inputs given we do extra + // checking. + return; + } + + // Reset global state. + MockUnback unback; + fake_clock = 0; + unback_success = true; + absl::flat_hash_set& released_set = ReleasedPages(); + released_set.clear(); + // To avoid reentrancy during unback, reserve space in released_set. + // We have at most size/5 allocations, for at most kPagesPerHugePage pages + // each, that we can track the released status of. + // + // TODO(b/73749855): Releasing the pageheap_lock during ReleaseFree will + // eliminate the need for this. + released_set.reserve(kPagesPerHugePage.raw_num() * size / 5); + + // We interpret data as a small DSL for exploring the state space of + // HugePageFiller. + // + // [0] - used for choosing dense tracker type. + // [1] - (available) + // [2] - (available) + // + // Afterwards, we read 5 bytes at a time until the buffer is exhausted. + // [i + 0] - Specifies an operation to perform on the filler (allocate, + // deallocate, release memory, gather stats, etc.) + // [i + 1, i + 4] - Specifies an integer. We use this as a source of + // deterministic entropy to allow inputs to be replayed. + // For example, this input can provide a Length to + // allocate, or the index of the previous allocation to + // deallocate. + const HugePageFillerDenseTrackerType dense_tracker_type = + static_cast(data[0]) >= 128 + ? HugePageFillerDenseTrackerType::kLongestFreeRangeAndChunks + : HugePageFillerDenseTrackerType::kSpansAllocated; + data += kInitBytes; + size -= kInitBytes; + + HugePageFiller filler(Clock{.now = mock_clock, .freq = freq}, + dense_tracker_type, unback, unback); + + std::vector trackers; + absl::flat_hash_map> allocs; + + // Running counter to allocate pseudo-random addresses + size_t next_hugepage = 1; + + for (size_t i = 0; i + 5 <= size; i += 5) { + const uint8_t op = data[i]; + uint32_t value; + memcpy(&value, &data[i + 1], sizeof(value)); + + switch (op & 0xF) { + case 0: { + // Allocate. We divide up our random value by: + // + // value[0:15] - We choose a Length to allocate. + // value[16:31] - We select num_to_objects. + Length n(std::clamp(value & 0xFFFF, 1, + kPagesPerHugePage.raw_num() - 1)); + AccessDensityPrediction density; + const uint32_t lval = (value >> 16); + // Choose many objects if the last bit is 1. + if (lval & 1) { + density = AccessDensityPrediction::kDense; + } else { + // We need to choose few objects, so only top four bits are used. + density = AccessDensityPrediction::kSparse; + } + size_t num_objects = std::max(lval >> 1, 1); + + // Truncate to single object for larger allocations. This ensures that + // we always allocate few-object spans from donations. + if (n > kPagesPerHugePage / 2) { + num_objects = 1; + density = AccessDensityPrediction::kSparse; + } + if (dense_tracker_type == + HugePageFillerDenseTrackerType::kSpansAllocated && + density == AccessDensityPrediction::kDense) { + n = Length(1); + } + + SpanAllocInfo alloc_info = {.objects_per_span = num_objects, + .density = density}; + absl::flat_hash_set& released_set = ReleasedPages(); + + CHECK_EQ(filler.size().raw_num(), trackers.size()); + CHECK_EQ(filler.unmapped_pages().raw_num(), released_set.size()); + + HugePageFiller::TryGetResult result; + { + PageHeapSpinLockHolder l; + result = filler.TryGet(n, alloc_info); + } + + if (result.pt == nullptr) { + // Failed to allocate. Create a new huge page. + // + // Donated pages do not necessarily have to have a particular size, + // since this may be (kPagesPerHugePage/2,kPagesPerHugePage) in size + // *or* the tail of an allocation >PagesPerHugePage. + // + // Since small objects are likely to be found, we model those tail + // donations separately. + const bool donated = n > kPagesPerHugePage / 2; + result.pt = new PageTracker(HugePage{.pn = next_hugepage}, donated, + fake_clock); + next_hugepage++; + { + PageHeapSpinLockHolder l; + + result.page = result.pt->Get(n).page; + filler.Contribute(result.pt, donated, alloc_info); + } + + trackers.push_back(result.pt); + } + + // We have now successfully allocated. Record the alloc and clear any + // released bits. + for (PageId p = result.page, end = p + n; p != end; ++p) { + released_set.erase(p); + } + + allocs[result.pt].push_back({result.page, n}); + + CHECK_EQ(filler.size().raw_num(), trackers.size()); + CHECK_EQ(filler.unmapped_pages().raw_num(), released_set.size()); + + break; + } + case 1: { + // Deallocate. + // + // value[0:15] - Index of the huge page (from trackers) to select + // value[16:31] - Index of the allocation (on pt) to select + if (trackers.empty()) { + break; + } + + const size_t lo = std::min(value & 0xFFFF, trackers.size() - 1); + PageTracker* pt = trackers[lo]; + + CHECK(!allocs[pt].empty()); + const size_t hi = std::min(value >> 16, allocs[pt].size() - 1); + Range alloc = allocs[pt][hi]; + + // Remove the allocation. + std::swap(allocs[pt][hi], allocs[pt].back()); + allocs[pt].resize(allocs[pt].size() - 1); + bool last_alloc = allocs[pt].empty(); + if (last_alloc) { + allocs.erase(pt); + std::swap(trackers[lo], trackers.back()); + trackers.resize(trackers.size() - 1); + } + + PageTracker* ret; + { + PageHeapSpinLockHolder l; + ret = filler.Put(pt, alloc); + } + CHECK_EQ(ret != nullptr, last_alloc); + absl::flat_hash_set& released_set = ReleasedPages(); + if (ret) { + // Clear released_set, since the page has become free. + HugePage hp = ret->location(); + for (PageId p = hp.first_page(), + end = hp.first_page() + kPagesPerHugePage; + p != end; ++p) { + released_set.erase(p); + } + delete ret; + } + + CHECK_EQ(filler.size().raw_num(), trackers.size()); + CHECK_EQ(filler.unmapped_pages().raw_num(), released_set.size()); + + break; + } + case 2: { + // Release + // + // value[0] - Whether are trying to apply TCMalloc's memory limits + // value[1] - reserved + // If using peak interval: + // value[2:9] - Peak interval for skip subrelease + // value[10:31]- Number of pages to try to release + // If not using peak interval: + // value[2:9] - Short interval for skip subrelease + // value[10:17]- Long interval for skip subrelease + // value[18:29]- Number of pages to try to release + // value[30] - Whether we release all free pages from partial allocs. + // value[31] - Reserved. + bool hit_limit = value & 0x1; + SkipSubreleaseIntervals skip_subrelease_intervals; + uint32_t short_interval_s = (value >> 2) & 0xFF; + uint32_t long_interval_s = (value >> 10) & 0xFF; + if (short_interval_s > long_interval_s) { + std::swap(short_interval_s, long_interval_s); + } + skip_subrelease_intervals.short_interval = + absl::Seconds(short_interval_s); + skip_subrelease_intervals.long_interval = + absl::Seconds(long_interval_s); + value >>= 18; + Length desired(value & 0xFFF); + const bool release_partial_allocs = (value >> 12) & 0x1; + size_t to_release_from_partial_allocs; + + Length released; + { + PageHeapSpinLockHolder l; + to_release_from_partial_allocs = + HugePageFiller::kPartialAllocPagesRelease * + filler.FreePagesInPartialAllocs().raw_num(); + released = filler.ReleasePages(desired, skip_subrelease_intervals, + release_partial_allocs, hit_limit); + } + + // We should be able to release all the free pages in partial allocs if + // skip-subrelease is disabled. + if (release_partial_allocs && !hit_limit && + !skip_subrelease_intervals.SkipSubreleaseEnabled() && + unback_success) { + CHECK_GE(released.raw_num(), to_release_from_partial_allocs); + } + break; + } + case 3: { + // Advance clock + // + // value[0:31] - Advances clock by this amount in arbitrary units. + fake_clock += value; + break; + } + case 4: { + // Toggle unback, simulating madvise potentially failing or succeeding. + // + // value is unused. + unback_success = !unback_success; + break; + } + case 5: { + // Gather stats + // + // value is unused. + std::string s; + s.resize(1 << 20); + Printer p(&s[0], s.size()); + PageHeapSpinLockHolder l; + filler.Print(p, true); + break; + } + case 6: { + // Model a tail from a larger allocation. The tail can have any size + // [1,kPagesPerHugePage). + // + // value[0:15] - We choose a Length to allocate. + // value[16:31] - Unused. + const Length n(std::clamp(value & 0xFFFF, 1, + kPagesPerHugePage.raw_num() - 1)); + absl::flat_hash_set& released_set = ReleasedPages(); + + auto* pt = new PageTracker(HugePage{.pn = next_hugepage}, + /*was_donated=*/true, fake_clock); + next_hugepage++; + PageId start; + { + PageHeapSpinLockHolder l; + + start = pt->Get(n).page; + filler.Contribute(pt, /*donated=*/true, + {1, AccessDensityPrediction::kSparse}); + } + + trackers.push_back(pt); + + // We have now successfully allocated. Record the alloc and clear any + // released bits. + for (PageId p = start, end = p + n; p != end; ++p) { + released_set.erase(p); + } + + allocs[pt].push_back({start, n}); + + CHECK_EQ(filler.size().raw_num(), trackers.size()); + CHECK_EQ(filler.unmapped_pages().raw_num(), released_set.size()); + break; + } + case 7: { + // Memory limit hit. Release. + // + // value[0:15]- Number of pages to try to release + Length desired(value & 0xFF); + + Length released; + const Length free = filler.free_pages(); + { + PageHeapSpinLockHolder l; + released = filler.ReleasePages(desired, SkipSubreleaseIntervals{}, + /*release_partial_alloc_pages=*/false, + /*hit_limit=*/true); + } + const Length expected = + unback_success ? std::min(free, desired) : Length(0); + CHECK_GE(released.raw_num(), expected.raw_num()); + break; + } + case 8: { + // Gather stats in pbtxt format. + // + // value is unused. + std::string s; + s.resize(1 << 20); + Printer p(&s[0], s.size()); + { + PbtxtRegion region(p, kTop); + PageHeapSpinLockHolder l; + filler.PrintInPbtxt(region); + } + + CHECK_LE(p.SpaceRequired(), s.size()); + s.resize(p.SpaceRequired()); + break; + } + case 9: { + // Gather span stats. + // + // value populates ages' now argument. + SmallSpanStats small; + LargeSpanStats large; + filler.AddSpanStats(&small, &large); + break; + } + } + } + + // Shut down, confirm filler is empty. + CHECK_EQ(ReleasedPages().size(), filler.unmapped_pages().raw_num()); + for (auto& [pt, v] : allocs) { + for (size_t i = 0, n = v.size(); i < n; ++i) { + auto alloc = v[i]; + PageTracker* ret; + { + PageHeapSpinLockHolder l; + ret = filler.Put(pt, alloc); + } + CHECK_EQ(ret != nullptr, i + 1 == n); + } + + delete pt; + } + + CHECK(filler.size() == NHugePages(0)); +} + +FUZZ_TEST(HugePageFillerTest, FuzzFiller) + ; + +} // namespace +} // namespace tcmalloc::tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_page_filler_test.cc b/contrib/libs/tcmalloc/tcmalloc/huge_page_filler_test.cc index 9879d41d7991..c98fadfd1c7a 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_page_filler_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/huge_page_filler_test.cc @@ -14,42 +14,47 @@ #include "tcmalloc/huge_page_filler.h" +#include #include #include -#include +#include #include -#include #include -#include #include #include #include // NOLINT(build/c++11) +#include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/algorithm/container.h" +#include "absl/base/attributes.h" +#include "absl/base/internal/cycleclock.h" #include "absl/base/internal/sysinfo.h" -#include "absl/base/thread_annotations.h" -#include "absl/container/flat_hash_map.h" +#include "absl/base/macros.h" #include "absl/container/flat_hash_set.h" #include "absl/flags/flag.h" #include "absl/memory/memory.h" -#include "absl/random/bernoulli_distribution.h" #include "absl/random/random.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" #include "absl/synchronization/blocking_counter.h" #include "absl/synchronization/mutex.h" #include "absl/time/clock.h" #include "absl/time/time.h" -#include "benchmark/benchmark.h" #include "tcmalloc/common.h" +#include "tcmalloc/huge_cache.h" +#include "tcmalloc/huge_page_subrelease.h" #include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/clock.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" #include "tcmalloc/pages.h" +#include "tcmalloc/span.h" #include "tcmalloc/stats.h" using tcmalloc::tcmalloc_internal::Length; @@ -57,12 +62,6 @@ using tcmalloc::tcmalloc_internal::Length; ABSL_FLAG(Length, page_tracker_defrag_lim, Length(32), "Max allocation size for defrag test"); -ABSL_FLAG(Length, frag_req_limit, Length(32), - "request size limit for frag test"); -ABSL_FLAG(Length, frag_size, Length(512 * 1024), - "target number of pages for frag test"); -ABSL_FLAG(uint64_t, frag_iters, 10 * 1000 * 1000, "iterations for frag test"); - ABSL_FLAG(double, release_until, 0.01, "fraction of used we target in pageheap"); ABSL_FLAG(uint64_t, bytes, 1024 * 1024 * 1024, "baseline usage"); @@ -160,13 +159,19 @@ class PageTrackerTest : public testing::Test { PageTrackerTest() : // an unlikely magic page huge_(HugePageContaining(reinterpret_cast(0x1abcde200000))), - tracker_(huge_, absl::base_internal::CycleClock::Now()) {} + tracker_(huge_, + /*was_donated=*/false, + absl::base_internal::CycleClock::Now()) {} ~PageTrackerTest() override { mock_.VerifyAndClear(); } struct PAlloc { PageId p; Length n; + SpanAllocInfo span_alloc_info; + + PAlloc(PageId pp, Length nn, SpanAllocInfo s) + : p(pp), n(nn), span_alloc_info(s) {} }; void Mark(PAlloc a, size_t mark) { @@ -179,17 +184,21 @@ class PageTrackerTest : public testing::Test { } } - class MockUnbackInterface { + class MockUnbackInterface final : public MemoryModifyFunction { public: - void Unback(void* p, size_t len) { - CHECK_CONDITION(actual_index_ < kMaxCalls); - actual_[actual_index_] = {p, len}; + [[nodiscard]] bool operator()(Range r) override { + TC_CHECK_LT(actual_index_, ABSL_ARRAYSIZE(actual_)); + actual_[actual_index_].r = r; + TC_CHECK_LT(actual_index_, ABSL_ARRAYSIZE(expected_)); + // Assume expected calls occur and use those return values. + const bool success = expected_[actual_index_].success; ++actual_index_; + return success; } - void Expect(void* p, size_t len) { - CHECK_CONDITION(expected_index_ < kMaxCalls); - expected_[expected_index_] = {p, len}; + void Expect(PageId p, Length len, bool success) { + TC_CHECK_LT(expected_index_, kMaxCalls); + expected_[expected_index_] = {Range(p, len), success}; ++expected_index_; } @@ -197,8 +206,8 @@ class PageTrackerTest : public testing::Test { EXPECT_EQ(expected_index_, actual_index_); for (size_t i = 0, n = std::min(expected_index_, actual_index_); i < n; ++i) { - EXPECT_EQ(expected_[i].ptr, actual_[i].ptr); - EXPECT_EQ(expected_[i].len, actual_[i].len); + EXPECT_EQ(expected_[i].r.p, actual_[i].r.p); + EXPECT_EQ(expected_[i].r.n, actual_[i].r.n); } expected_index_ = 0; actual_index_ = 0; @@ -206,8 +215,8 @@ class PageTrackerTest : public testing::Test { private: struct CallArgs { - void* ptr{nullptr}; - size_t len{0}; + Range r; + bool success = true; }; static constexpr size_t kMaxCalls = 10; @@ -217,12 +226,8 @@ class PageTrackerTest : public testing::Test { size_t actual_index_{0}; }; - static void MockUnback(void* p, size_t len); - - typedef PageTracker TestPageTracker; - // strict because release calls should only happen when we ask - static MockUnbackInterface mock_; + MockUnbackInterface mock_; void Check(PAlloc a, size_t mark) { EXPECT_LE(huge_.first_page(), a.p); @@ -230,55 +235,44 @@ class PageTrackerTest : public testing::Test { size_t end = index + a.n.raw_num(); EXPECT_LE(end, kPagesPerHugePage.raw_num()); for (; index < end; ++index) { - EXPECT_EQ(mark, marks_[index]); + EXPECT_EQ(marks_[index], mark); } } size_t marks_[kPagesPerHugePage.raw_num()]; HugePage huge_; - TestPageTracker tracker_; + PageTracker tracker_; - void ExpectPages(PAlloc a) { - void* ptr = a.p.start_addr(); - size_t bytes = a.n.in_bytes(); - mock_.Expect(ptr, bytes); + void ExpectPages(PAlloc a, bool success = true) { + mock_.Expect(a.p, a.n, success); } - PAlloc Get(Length n) { - absl::base_internal::SpinLockHolder l(&pageheap_lock); + PAlloc Get(Length n, SpanAllocInfo span_alloc_info) { + PageHeapSpinLockHolder l; PageId p = tracker_.Get(n).page; - return {p, n}; + return {p, n, span_alloc_info}; } void Put(PAlloc a) { - absl::base_internal::SpinLockHolder l(&pageheap_lock); - tracker_.Put(a.p, a.n); + PageHeapSpinLockHolder l; + tracker_.Put(Range(a.p, a.n)); } Length ReleaseFree() { - absl::base_internal::SpinLockHolder l(&pageheap_lock); - return tracker_.ReleaseFree(); - } - - void MaybeRelease(PAlloc a) { - absl::base_internal::SpinLockHolder l(&pageheap_lock); - tracker_.MaybeRelease(a.p, a.n); + PageHeapSpinLockHolder l; + return tracker_.ReleaseFree(mock_); } }; -void PageTrackerTest::MockUnback(void* p, size_t len) { mock_.Unback(p, len); } - -PageTrackerTest::MockUnbackInterface PageTrackerTest::mock_; - TEST_F(PageTrackerTest, AllocSane) { Length free = kPagesPerHugePage; auto n = Length(1); std::vector allocs; // This should work without fragmentation. while (n <= free) { - ASSERT_LE(n, tracker_.longest_free_range()); - EXPECT_EQ(kPagesPerHugePage - free, tracker_.used_pages()); - EXPECT_EQ(free, tracker_.free_pages()); - PAlloc a = Get(n); + ASSERT_GE(tracker_.longest_free_range(), n); + EXPECT_EQ(tracker_.used_pages(), kPagesPerHugePage - free); + EXPECT_EQ(tracker_.free_pages(), free); + PAlloc a = Get(n, {1, AccessDensityPrediction::kSparse}); Mark(a, n.raw_num()); allocs.push_back(a); free -= n; @@ -293,38 +287,36 @@ TEST_F(PageTrackerTest, AllocSane) { TEST_F(PageTrackerTest, ReleasingReturn) { static const Length kAllocSize = kPagesPerHugePage / 4; - PAlloc a1 = Get(kAllocSize - Length(3)); - PAlloc a2 = Get(kAllocSize); - PAlloc a3 = Get(kAllocSize + Length(1)); - PAlloc a4 = Get(kAllocSize + Length(2)); + SpanAllocInfo info = {1, AccessDensityPrediction::kSparse}; + PAlloc a1 = Get(kAllocSize - Length(3), info); + PAlloc a2 = Get(kAllocSize, info); + PAlloc a3 = Get(kAllocSize + Length(1), info); + PAlloc a4 = Get(kAllocSize + Length(2), info); Put(a2); Put(a4); // We now have a hugepage that looks like [alloced] [free] [alloced] [free]. // The free parts should be released when we mark the hugepage as such, // but not the allocated parts. - ExpectPages(a2); - ExpectPages(a4); + ExpectPages(a2, /*success=*/true); + ExpectPages(a4, /*success=*/true); ReleaseFree(); mock_.VerifyAndClear(); - // Now we return the other parts, and they *should* get released. - ExpectPages(a1); - ExpectPages(a3); + EXPECT_EQ(tracker_.released_pages(), a2.n + a4.n); + EXPECT_EQ(tracker_.free_pages(), a2.n + a4.n); - MaybeRelease(a1); Put(a1); - - MaybeRelease(a3); Put(a3); } TEST_F(PageTrackerTest, ReleasingRetain) { static const Length kAllocSize = kPagesPerHugePage / 4; - PAlloc a1 = Get(kAllocSize - Length(3)); - PAlloc a2 = Get(kAllocSize); - PAlloc a3 = Get(kAllocSize + Length(1)); - PAlloc a4 = Get(kAllocSize + Length(2)); + SpanAllocInfo info = {1, AccessDensityPrediction::kSparse}; + PAlloc a1 = Get(kAllocSize - Length(3), info); + PAlloc a2 = Get(kAllocSize, info); + PAlloc a3 = Get(kAllocSize + Length(1), info); + PAlloc a4 = Get(kAllocSize + Length(2), info); Put(a2); Put(a4); @@ -349,9 +341,49 @@ TEST_F(PageTrackerTest, ReleasingRetain) { mock_.VerifyAndClear(); } +TEST_F(PageTrackerTest, ReleasingRetainFailure) { + static const Length kAllocSize = kPagesPerHugePage / 4; + SpanAllocInfo info = {1, AccessDensityPrediction::kSparse}; + PAlloc a1 = Get(kAllocSize - Length(3), info); + PAlloc a2 = Get(kAllocSize, info); + PAlloc a3 = Get(kAllocSize + Length(1), info); + PAlloc a4 = Get(kAllocSize + Length(2), info); + + Put(a2); + Put(a4); + // We now have a hugepage that looks like [alloced] [free] [alloced] [free]. + // The free parts should be released when we mark the hugepage as such if + // successful, but not the allocated parts. + ExpectPages(a2, /*success=*/true); + ExpectPages(a4, /*success=*/false); + ReleaseFree(); + mock_.VerifyAndClear(); + + EXPECT_EQ(tracker_.released_pages(), a2.n); + EXPECT_EQ(tracker_.free_pages(), a2.n + a4.n); + + // Now we return the other parts, and they shouldn't get released. + Put(a1); + Put(a3); + + mock_.VerifyAndClear(); + + // But they will if we ReleaseFree. We attempt to coalesce the deallocation + // of a3/a4. + ExpectPages(a1, /*success=*/true); + ExpectPages(PAlloc{std::min(a3.p, a4.p), a3.n + a4.n, info}, + /*success=*/false); + ReleaseFree(); + mock_.VerifyAndClear(); + + EXPECT_EQ(tracker_.released_pages(), a1.n + a2.n); + EXPECT_EQ(tracker_.free_pages(), a1.n + a2.n + a3.n + a4.n); +} + TEST_F(PageTrackerTest, Defrag) { absl::BitGen rng; const Length N = absl::GetFlag(FLAGS_page_tracker_defrag_lim); + SpanAllocInfo info = {1, AccessDensityPrediction::kSparse}; auto dist = EmpiricalDistribution(N); std::vector allocs; @@ -362,7 +394,7 @@ TEST_F(PageTrackerTest, Defrag) { do { n = Length(dist(rng)); } while (n > tracker_.longest_free_range()); - PAlloc a = Get(n); + PAlloc a = Get(n, info); (absl::Bernoulli(rng, 1.0 / 2) ? allocs : doomed).push_back(a); } @@ -405,7 +437,7 @@ TEST_F(PageTrackerTest, Defrag) { do { n = Length(dist(rng)); } while (n > tracker_.longest_free_range()); - allocs.push_back(Get(n)); + allocs.push_back(Get(n, info)); } } @@ -424,9 +456,6 @@ TEST_F(PageTrackerTest, Defrag) { // We'd like to prety consistently rely on (75% of the time) reasonable // defragmentation (50% of space is fully usable...) // ...but we currently can't hit that mark consistently. - // The situation is worse on ppc with larger huge pages: - // pass rate for test is ~50% at 0.20. Reducing from 0.2 to 0.07. - // TODO(b/127466107) figure out a better solution. EXPECT_GE(p25, 0.07); } @@ -439,12 +468,12 @@ TEST_F(PageTrackerTest, Defrag) { printf("Longest free quantiles:\n"); printf("p10: %zu p25: %zu p50: %zu p75: %zu p90: %zu\n", p10.raw_num(), p25.raw_num(), p50.raw_num(), p75.raw_num(), p90.raw_num()); - // Similarly, we'd really like for there usually (p25) to be a space + // Similarly, we'd really like for there usually (p50) to be a space // for a large allocation (N - note that we've cooked the books so that // the page tracker is going to be something like half empty (ish) and N // is small, so that should be doable.) // ...but, of course, it isn't. - EXPECT_GE(p25, Length(4)); + EXPECT_GE(p50, Length(4)); } for (auto a : allocs) { @@ -454,14 +483,13 @@ TEST_F(PageTrackerTest, Defrag) { TEST_F(PageTrackerTest, Stats) { struct Helper { - static void Stat(const TestPageTracker& tracker, + static void Stat(const PageTracker& tracker, std::vector* small_backed, - std::vector* small_unbacked, LargeSpanStats* large, - double* avg_age_backed, double* avg_age_unbacked) { + std::vector* small_unbacked, + LargeSpanStats* large) { SmallSpanStats small; *large = LargeSpanStats(); - PageAgeHistograms ages(absl::base_internal::CycleClock::Now()); - tracker.AddSpanStats(&small, large, &ages); + tracker.AddSpanStats(&small, large); small_backed->clear(); small_unbacked->clear(); for (auto i = Length(0); i < kMaxPages; ++i) { @@ -473,99 +501,77 @@ TEST_F(PageTrackerTest, Stats) { small_unbacked->push_back(i); } } - - *avg_age_backed = ages.GetTotalHistogram(false)->avg_age(); - *avg_age_unbacked = ages.GetTotalHistogram(true)->avg_age(); } }; LargeSpanStats large; std::vector small_backed, small_unbacked; - double avg_age_backed, avg_age_unbacked; - const PageId p = Get(kPagesPerHugePage).p; + SpanAllocInfo info1 = {kPagesPerHugePage.raw_num(), + AccessDensityPrediction::kDense}; + const PageId p = Get(kPagesPerHugePage, info1).p; const PageId end = p + kPagesPerHugePage; PageId next = p; - Put({next, kMaxPages + Length(1)}); + Length n = kMaxPages + Length(1); + SpanAllocInfo info2 = {n.raw_num(), AccessDensityPrediction::kDense}; + Put({next, n, info2}); next += kMaxPages + Length(1); - absl::SleepFor(absl::Milliseconds(10)); - Helper::Stat(tracker_, &small_backed, &small_unbacked, &large, - &avg_age_backed, &avg_age_unbacked); + Helper::Stat(tracker_, &small_backed, &small_unbacked, &large); EXPECT_THAT(small_backed, testing::ElementsAre()); EXPECT_THAT(small_unbacked, testing::ElementsAre()); - EXPECT_EQ(1, large.spans); - EXPECT_EQ(kMaxPages + Length(1), large.normal_pages); - EXPECT_EQ(Length(0), large.returned_pages); - EXPECT_LE(0.01, avg_age_backed); + EXPECT_EQ(large.spans, 1); + EXPECT_EQ(large.normal_pages, kMaxPages + Length(1)); + EXPECT_EQ(large.returned_pages, Length(0)); ++next; - Put({next, Length(1)}); + SpanAllocInfo info3 = {1, AccessDensityPrediction::kSparse}; + Put({next, Length(1), info3}); next += Length(1); - absl::SleepFor(absl::Milliseconds(20)); - Helper::Stat(tracker_, &small_backed, &small_unbacked, &large, - &avg_age_backed, &avg_age_unbacked); + Helper::Stat(tracker_, &small_backed, &small_unbacked, &large); EXPECT_THAT(small_backed, testing::ElementsAre(Length(1))); EXPECT_THAT(small_unbacked, testing::ElementsAre()); - EXPECT_EQ(1, large.spans); - EXPECT_EQ(kMaxPages + Length(1), large.normal_pages); - EXPECT_EQ(Length(0), large.returned_pages); - EXPECT_LE(((kMaxPages + Length(1)).raw_num() * 0.03 + 1 * 0.02) / - (kMaxPages + Length(2)).raw_num(), - avg_age_backed); - EXPECT_EQ(0, avg_age_unbacked); + EXPECT_EQ(large.spans, 1); + EXPECT_EQ(large.normal_pages, kMaxPages + Length(1)); + EXPECT_EQ(large.returned_pages, Length(0)); ++next; - Put({next, Length(2)}); + SpanAllocInfo info4 = {2, AccessDensityPrediction::kSparse}; + Put({next, Length(2), info4}); next += Length(2); - absl::SleepFor(absl::Milliseconds(30)); - Helper::Stat(tracker_, &small_backed, &small_unbacked, &large, - &avg_age_backed, &avg_age_unbacked); + Helper::Stat(tracker_, &small_backed, &small_unbacked, &large); EXPECT_THAT(small_backed, testing::ElementsAre(Length(1), Length(2))); EXPECT_THAT(small_unbacked, testing::ElementsAre()); - EXPECT_EQ(1, large.spans); - EXPECT_EQ(kMaxPages + Length(1), large.normal_pages); - EXPECT_EQ(Length(0), large.returned_pages); - EXPECT_LE(((kMaxPages + Length(1)).raw_num() * 0.06 + 1 * 0.05 + 2 * 0.03) / - (kMaxPages + Length(4)).raw_num(), - avg_age_backed); - EXPECT_EQ(0, avg_age_unbacked); + EXPECT_EQ(large.spans, 1); + EXPECT_EQ(large.normal_pages, kMaxPages + Length(1)); + EXPECT_EQ(large.returned_pages, Length(0)); ++next; - Put({next, Length(3)}); + SpanAllocInfo info5 = {3, AccessDensityPrediction::kSparse}; + Put({next, Length(3), info5}); next += Length(3); ASSERT_LE(next, end); - absl::SleepFor(absl::Milliseconds(40)); - Helper::Stat(tracker_, &small_backed, &small_unbacked, &large, - &avg_age_backed, &avg_age_unbacked); + Helper::Stat(tracker_, &small_backed, &small_unbacked, &large); EXPECT_THAT(small_backed, testing::ElementsAre(Length(1), Length(2), Length(3))); EXPECT_THAT(small_unbacked, testing::ElementsAre()); - EXPECT_EQ(1, large.spans); - EXPECT_EQ(kMaxPages + Length(1), large.normal_pages); - EXPECT_EQ(Length(0), large.returned_pages); - EXPECT_LE(((kMaxPages + Length(1)).raw_num() * 0.10 + 1 * 0.09 + 2 * 0.07 + - 3 * 0.04) / - (kMaxPages + Length(7)).raw_num(), - avg_age_backed); - EXPECT_EQ(0, avg_age_unbacked); - - ExpectPages({p, kMaxPages + Length(1)}); - ExpectPages({p + kMaxPages + Length(2), Length(1)}); - ExpectPages({p + kMaxPages + Length(4), Length(2)}); - ExpectPages({p + kMaxPages + Length(7), Length(3)}); + EXPECT_EQ(large.spans, 1); + EXPECT_EQ(large.normal_pages, kMaxPages + Length(1)); + EXPECT_EQ(large.returned_pages, Length(0)); + + n = kMaxPages + Length(1); + ExpectPages({p, n, info2}); + ExpectPages({p + kMaxPages + Length(2), Length(1), info3}); + ExpectPages({p + kMaxPages + Length(4), Length(2), info4}); + ExpectPages({p + kMaxPages + Length(7), Length(3), info5}); EXPECT_EQ(kMaxPages + Length(7), ReleaseFree()); - absl::SleepFor(absl::Milliseconds(100)); - Helper::Stat(tracker_, &small_backed, &small_unbacked, &large, - &avg_age_backed, &avg_age_unbacked); + Helper::Stat(tracker_, &small_backed, &small_unbacked, &large); EXPECT_THAT(small_backed, testing::ElementsAre()); EXPECT_THAT(small_unbacked, testing::ElementsAre(Length(1), Length(2), Length(3))); - EXPECT_EQ(1, large.spans); - EXPECT_EQ(Length(0), large.normal_pages); - EXPECT_EQ(kMaxPages + Length(1), large.returned_pages); - EXPECT_EQ(0, avg_age_backed); - EXPECT_LE(0.1, avg_age_unbacked); + EXPECT_EQ(large.spans, 1); + EXPECT_EQ(large.normal_pages, Length(0)); + EXPECT_EQ(large.returned_pages, kMaxPages + Length(1)); } TEST_F(PageTrackerTest, b151915873) { @@ -585,8 +591,9 @@ TEST_F(PageTrackerTest, b151915873) { std::vector allocs; allocs.reserve(kPagesPerHugePage.raw_num()); + SpanAllocInfo info = {1, AccessDensityPrediction::kSparse}; for (int i = 0; i < kPagesPerHugePage.raw_num(); i++) { - allocs.push_back(Get(Length(1))); + allocs.push_back(Get(Length(1), info)); } std::sort(allocs.begin(), allocs.end(), @@ -599,9 +606,8 @@ TEST_F(PageTrackerTest, b151915873) { SmallSpanStats small; LargeSpanStats large; - PageAgeHistograms ages(absl::base_internal::CycleClock::Now()); - tracker_.AddSpanStats(&small, &large, &ages); + tracker_.AddSpanStats(&small, &large); EXPECT_EQ(small.normal_length[1], 1); EXPECT_THAT(0, @@ -609,33 +615,35 @@ TEST_F(PageTrackerTest, b151915873) { &small.normal_length[kMaxPages.raw_num()])); } -class BlockingUnback { +class BlockingUnback final : public MemoryModifyFunction { public: - static void Unback(void* p, size_t len) { + constexpr BlockingUnback() = default; + + [[nodiscard]] bool operator()(Range r) override { if (!mu_) { - return; + return success_; } - if (counter) { - counter->DecrementCount(); + if (counter_) { + counter_->DecrementCount(); } mu_->Lock(); mu_->Unlock(); + return success_; } - static void set_lock(absl::Mutex* mu) { mu_ = mu; } - - static absl::BlockingCounter* counter; + absl::BlockingCounter* counter_ = nullptr; + bool success_ = true; private: static thread_local absl::Mutex* mu_; }; thread_local absl::Mutex* BlockingUnback::mu_ = nullptr; -absl::BlockingCounter* BlockingUnback::counter = nullptr; -class FillerTest : public testing::TestWithParam { +class FillerTest : public testing::TestWithParam< + std::tuple> { protected: // Allow tests to modify the clock used by the cache. static int64_t FakeClock() { return clock_; } @@ -647,12 +655,6 @@ class FillerTest : public testing::TestWithParam { } static void ResetClock() { clock_ = 1234; } - static void Unback(void* p, size_t len) {} - - // Our templating approach lets us directly override certain functions - // and have mocks without virtualization. It's a bit funky but works. - typedef PageTracker FakeTracker; - // We have backing of one word per (normal-sized) page for our "hugepages". std::vector backing_; // This is space efficient enough that we won't bother recycling pages. @@ -660,7 +662,7 @@ class FillerTest : public testing::TestWithParam { intptr_t i = backing_.size(); backing_.resize(i + kPagesPerHugePage.raw_num()); intptr_t addr = i << kPageShift; - CHECK_CONDITION(addr % kHugePageSize == 0); + TC_CHECK_EQ(addr % kHugePageSize, 0); return HugePageContaining(reinterpret_cast(addr)); } @@ -678,21 +680,30 @@ class FillerTest : public testing::TestWithParam { } } - HugePageFiller filler_; + HugePageFiller filler_; + BlockingUnback blocking_unback_; FillerTest() - : filler_(GetParam(), - Clock{.now = FakeClock, .freq = GetFakeClockFrequency}) { + : filler_(Clock{.now = FakeClock, .freq = GetFakeClockFrequency}, + /*dense_tracker_type=*/std::get<0>(GetParam()), + blocking_unback_, blocking_unback_), + dense_tracker_sorted_on_allocs_( + std::get<0>(GetParam()) == + HugePageFillerDenseTrackerType::kSpansAllocated) { ResetClock(); + // Reset success state + blocking_unback_.success_ = true; } - ~FillerTest() override { EXPECT_EQ(NHugePages(0), filler_.size()); } + ~FillerTest() override { EXPECT_EQ(filler_.size(), NHugePages(0)); } struct PAlloc { - FakeTracker* pt; + PageTracker* pt; PageId p; Length n; size_t mark; + SpanAllocInfo span_alloc_info; + bool from_released; }; void Mark(const PAlloc& alloc) { MarkRange(alloc.p, alloc.n, alloc.mark); } @@ -705,36 +716,176 @@ class FillerTest : public testing::TestWithParam { Length total_allocated_{0}; absl::InsecureBitGen gen_; + // We usually choose the number of objects per span at random, but in tests + // where the output is hardcoded, we disable randomization through the + // variable below. + bool randomize_density_ = true; + bool dense_tracker_sorted_on_allocs_ = false; void CheckStats() { - EXPECT_EQ(hp_contained_, filler_.size()); + EXPECT_EQ(filler_.size(), hp_contained_); auto stats = filler_.stats(); const uint64_t freelist_bytes = stats.free_bytes + stats.unmapped_bytes; const uint64_t used_bytes = stats.system_bytes - freelist_bytes; - EXPECT_EQ(total_allocated_.in_bytes(), used_bytes); - EXPECT_EQ((hp_contained_.in_pages() - total_allocated_).in_bytes(), - freelist_bytes); + EXPECT_EQ(used_bytes, total_allocated_.in_bytes()); + EXPECT_EQ(freelist_bytes, + (hp_contained_.in_pages() - total_allocated_).in_bytes()); + } + + PAlloc AllocateWithSpanAllocInfo(Length n, SpanAllocInfo span_alloc_info, + bool donated = false) { + TC_CHECK_LE(n, kPagesPerHugePage); + PAlloc ret = AllocateRaw(n, span_alloc_info, donated); + ret.n = n; + Mark(ret); + CheckStats(); + return ret; + } + + std::vector AllocateVectorWithSpanAllocInfo( + Length n, SpanAllocInfo span_alloc_info, bool donated = false) { + TC_CHECK_LE(n, kPagesPerHugePage); + Length t(0); + std::vector ret; + Length alloc_len = + (dense_tracker_sorted_on_allocs_ && + span_alloc_info.density == AccessDensityPrediction::kDense) + ? Length(1) + : n; + while (t < n) { + ret.push_back(AllocateRaw(alloc_len, span_alloc_info, donated)); + ret.back().n = alloc_len; + Mark(ret.back()); + CheckStats(); + t += alloc_len; + } + return ret; + } + + std::vector AllocateVector(Length n, bool donated = false) { + std::vector ret; + size_t objects = + randomize_density_ ? (1 << absl::Uniform(gen_, 0, 8)) : 1; + AccessDensityPrediction density = + randomize_density_ + ? (absl::Bernoulli(gen_, 0.5) ? AccessDensityPrediction::kSparse + : AccessDensityPrediction::kDense) + : AccessDensityPrediction::kSparse; + + SpanAllocInfo info = {.objects_per_span = objects, .density = density}; + Length alloc_len = (dense_tracker_sorted_on_allocs_ && + density == AccessDensityPrediction::kDense) + ? Length(1) + : n; + Length total_len(0); + while (total_len < n) { + ret.push_back(AllocateRaw(alloc_len, info, donated)); + ret.back().n = alloc_len; + Mark(ret.back()); + CheckStats(); + total_len += alloc_len; + } + return ret; + } + + PAlloc Allocate(Length n, bool donated = false) { + TC_CHECK_LE(n, kPagesPerHugePage); + PAlloc ret; + size_t objects = + randomize_density_ ? (1 << absl::Uniform(gen_, 0, 8)) : 1; + + AccessDensityPrediction density = + randomize_density_ + ? (absl::Bernoulli(gen_, 0.5) ? AccessDensityPrediction::kSparse + : AccessDensityPrediction::kDense) + : AccessDensityPrediction::kSparse; + SpanAllocInfo info = {.objects_per_span = objects, .density = density}; + ret = AllocateRaw(n, info, donated); + ret.n = n; + Mark(ret); + CheckStats(); + return ret; + } + + bool AllReleased(const std::vector& pv) const { + for (const auto& p : pv) { + if (!p.pt->released()) return false; + } + return true; + } + + // Returns true iff the filler returned an empty hugepage + bool Delete(const PAlloc& p) { + Check(p); + bool r = DeleteRaw(p); + CheckStats(); + return r; + } + + // Return true iff the final Delete() call returns true. + bool DeleteVector(const std::vector& pv) { + bool ret = false; + for (const auto& p : pv) { + ret = Delete(p); + } + return ret; + } + + Length ReleasePages(Length desired, SkipSubreleaseIntervals intervals = {}) { + PageHeapSpinLockHolder l; + return filler_.ReleasePages(desired, intervals, + /*release_partial_alloc_pages=*/false, + /*hit_limit=*/false); + } + + Length ReleasePartialPages(Length desired, + SkipSubreleaseIntervals intervals = {}) { + PageHeapSpinLockHolder l; + return filler_.ReleasePages(desired, intervals, + /*release_partial_alloc_pages=*/true, + /*hit_limit=*/false); + } + + Length HardReleasePages(Length desired) { + PageHeapSpinLockHolder l; + return filler_.ReleasePages(desired, SkipSubreleaseIntervals{}, + /*release_partial_alloc_pages=*/false, + /*hit_limit=*/true); } - PAlloc AllocateRaw(Length n, bool donated = false) { + + // Generates an "interesting" pattern of allocations that highlights all the + // various features of our stats. + std::vector GenerateInterestingAllocs(); + + // Tests fragmentation + void FragmentationTest(); + + private: + PAlloc AllocateRaw(Length n, SpanAllocInfo span_alloc_info, bool donated) { EXPECT_LT(n, kPagesPerHugePage); + // Densely-accessed spans are not allocated from donated hugepages. So + // assert that we do not test such a situation. + EXPECT_TRUE(!donated || + span_alloc_info.density == AccessDensityPrediction::kSparse); PAlloc ret; ret.n = n; ret.pt = nullptr; ret.mark = ++next_mark_; + ret.span_alloc_info = span_alloc_info; if (!donated) { // Donated means always create a new hugepage - absl::base_internal::SpinLockHolder l(&pageheap_lock); - auto [pt, page] = filler_.TryGet(n); + PageHeapSpinLockHolder l; + auto [pt, page, from_released] = filler_.TryGet(n, span_alloc_info); ret.pt = pt; ret.p = page; + ret.from_released = from_released; } if (ret.pt == nullptr) { - ret.pt = - new FakeTracker(GetBacking(), absl::base_internal::CycleClock::Now()); + ret.pt = new PageTracker(GetBacking(), donated, clock_); { - absl::base_internal::SpinLockHolder l(&pageheap_lock); + PageHeapSpinLockHolder l; ret.p = ret.pt->Get(n).page; } - filler_.Contribute(ret.pt, donated); + filler_.Contribute(ret.pt, donated, span_alloc_info); ++hp_contained_; } @@ -742,25 +893,16 @@ class FillerTest : public testing::TestWithParam { return ret; } - PAlloc Allocate(Length n, bool donated = false) { - CHECK_CONDITION(n <= kPagesPerHugePage); - PAlloc ret = AllocateRaw(n, donated); - ret.n = n; - Mark(ret); - CheckStats(); - return ret; - } - // Returns true iff the filler returned an empty hugepage. bool DeleteRaw(const PAlloc& p) { - FakeTracker* pt; + PageTracker* pt; { - absl::base_internal::SpinLockHolder l(&pageheap_lock); - pt = filler_.Put(p.pt, p.p, p.n); + PageHeapSpinLockHolder l; + pt = filler_.Put(p.pt, Range(p.p, p.n)); } total_allocated_ -= p.n; if (pt != nullptr) { - EXPECT_EQ(kPagesPerHugePage, pt->longest_free_range()); + EXPECT_EQ(pt->longest_free_range(), kPagesPerHugePage); EXPECT_TRUE(pt->empty()); --hp_contained_; delete pt; @@ -770,29 +912,6 @@ class FillerTest : public testing::TestWithParam { return false; } - // Returns true iff the filler returned an empty hugepage - bool Delete(const PAlloc& p) { - Check(p); - bool r = DeleteRaw(p); - CheckStats(); - return r; - } - - Length ReleasePages(Length desired, absl::Duration d = absl::ZeroDuration()) { - absl::base_internal::SpinLockHolder l(&pageheap_lock); - return filler_.ReleasePages(desired, d, false); - } - - Length HardReleasePages(Length desired) { - absl::base_internal::SpinLockHolder l(&pageheap_lock); - return filler_.ReleasePages(desired, absl::ZeroDuration(), true); - } - - // Generates an "interesting" pattern of allocations that highlights all the - // various features of our stats. - std::vector GenerateInterestingAllocs(); - - private: static int64_t clock_; }; @@ -800,23 +919,24 @@ int64_t FillerTest::clock_{1234}; TEST_P(FillerTest, Density) { absl::BitGen rng; - // Start with a really annoying setup: some hugepages half - // empty (randomly) + // Start with a really annoying setup: some hugepages half empty (randomly) std::vector allocs; std::vector doomed_allocs; static const HugeLength kNumHugePages = NHugePages(64); for (auto i = Length(0); i < kNumHugePages.in_pages(); ++i) { - ASSERT_EQ(i, filler_.pages_allocated()); + ASSERT_EQ(filler_.pages_allocated(), i); + PAlloc p = Allocate(Length(1)); if (absl::Bernoulli(rng, 1.0 / 2)) { - allocs.push_back(Allocate(Length(1))); + allocs.push_back(p); } else { - doomed_allocs.push_back(Allocate(Length(1))); + doomed_allocs.push_back(p); } } for (auto d : doomed_allocs) { Delete(d); } - EXPECT_EQ(kNumHugePages, filler_.size()); + EXPECT_LE(filler_.size(), kNumHugePages + NHugePages(1)); + EXPECT_GE(filler_.size(), kNumHugePages); // We want a good chance of touching ~every allocation. size_t n = allocs.size(); // Now, randomly add and delete to the allocations. @@ -827,60 +947,335 @@ TEST_P(FillerTest, Density) { for (int i = 0; i < n; ++i) { Delete(allocs[i]); allocs[i] = Allocate(Length(1)); - ASSERT_EQ(Length(n), filler_.pages_allocated()); + ASSERT_EQ(filler_.pages_allocated(), Length(n)); } } - EXPECT_GE(allocs.size() / kPagesPerHugePage.raw_num() + 1, + EXPECT_GE(allocs.size() / kPagesPerHugePage.raw_num() + 3, filler_.size().raw_num()); // clean up, check for failures for (auto a : allocs) { Delete(a); - ASSERT_EQ(Length(--n), filler_.pages_allocated()); + ASSERT_EQ(filler_.pages_allocated(), Length(--n)); } } -TEST_P(FillerTest, Release) { +// This test makes sure that we continue releasing from regular (non-partial) +// allocs when we enable a feature to release all free pages from partial +// allocs. +TEST_P(FillerTest, ReleaseFromFullAllocs) { + const Length kAlloc = kPagesPerHugePage / 2; + // Maintain the object count for the second allocation so that the alloc list + // remains the same for the two allocations. + std::vector p1 = AllocateVector(kAlloc - Length(1)); + ASSERT_TRUE(!p1.empty()); + std::vector p2 = AllocateVectorWithSpanAllocInfo( + kAlloc + Length(1), p1.front().span_alloc_info); + + std::vector p3 = AllocateVector(kAlloc - Length(2)); + ASSERT_TRUE(!p3.empty()); + std::vector p4 = AllocateVectorWithSpanAllocInfo( + kAlloc + Length(2), p3.front().span_alloc_info); + // We have two hugepages, both full: nothing to release. + ASSERT_EQ(ReleasePartialPages(kMaxValidPages), Length(0)); + DeleteVector(p1); + DeleteVector(p3); + // Now we should see the p1 hugepage - emptier - released. + ASSERT_EQ(ReleasePartialPages(kAlloc - Length(1)), kAlloc - Length(1)); + EXPECT_EQ(filler_.unmapped_pages(), kAlloc - Length(1)); + ASSERT_TRUE(AllReleased(p1)); + ASSERT_FALSE(AllReleased(p3)); + for (const auto& pa : p3) { + ASSERT_FALSE(pa.from_released); + } + + // Check subrelease stats. + SubreleaseStats subrelease = filler_.subrelease_stats(); + EXPECT_EQ(subrelease.num_pages_subreleased, kAlloc - Length(1)); + EXPECT_EQ(subrelease.num_partial_alloc_pages_subreleased, Length(0)); + + // We expect to reuse both p1.pt and p3.pt. + std::vector p5 = AllocateVectorWithSpanAllocInfo( + kAlloc - Length(1), p1.front().span_alloc_info); + for (const auto& pa : p5) { + if (dense_tracker_sorted_on_allocs_) { + ASSERT_TRUE(pa.pt == p1.front().pt || pa.pt == p3.front().pt); + } else { + ASSERT_EQ(pa.pt, p1.front().pt); + ASSERT_TRUE(pa.from_released); + } + } + + DeleteVector(p2); + DeleteVector(p4); + ASSERT_TRUE(DeleteVector(p5)); +} + +// This test makes sure that we release all the free pages from partial allocs +// even when we request fewer pages to release. It also confirms that we +// continue to release desired number of pages from the full allocs even when +// release_partial_alloc_pages option is enabled. +TEST_P(FillerTest, ReleaseFreePagesInPartialAllocs) { + if (std::get<0>(GetParam()) == + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test for kSpansAllocated"; + } static const Length kAlloc = kPagesPerHugePage / 2; - PAlloc p1 = Allocate(kAlloc - Length(1)); - PAlloc p2 = Allocate(kAlloc + Length(1)); + static const Length kL1 = kAlloc - Length(1); + static const Length kL2 = kAlloc + Length(1); + + static const Length kL3 = kAlloc - Length(1); + static const Length kL4 = kAlloc + Length(1); + PAlloc p1 = Allocate(kL1); + PAlloc p2 = AllocateWithSpanAllocInfo(kL2, p1.span_alloc_info); + PAlloc p3 = Allocate(kL3); + PAlloc p4 = AllocateWithSpanAllocInfo(kL4, p3.span_alloc_info); + + // As there are no free pages, we shouldn't be able to release anything. + EXPECT_EQ(ReleasePartialPages(kMaxValidPages), Length(0)); + + Delete(p2); + Delete(p4); + + // Check subrelease stats. + SubreleaseStats subrelease = filler_.subrelease_stats(); + EXPECT_EQ(subrelease.num_pages_subreleased, Length(0)); + EXPECT_EQ(subrelease.num_partial_alloc_pages_subreleased, Length(0)); + + // As we do not have any pages in partially-released lists, we should continue + // to release the requested number of pages. + EXPECT_EQ(filler_.used_pages_in_partial_released(), Length(0)); + EXPECT_EQ(ReleasePartialPages(kL2), kL2); + EXPECT_EQ(ReleasePartialPages(kL4), kL4); + + // Check subrelease stats. + subrelease = filler_.subrelease_stats(); + EXPECT_EQ(subrelease.num_pages_subreleased, kL2 + kL4); + EXPECT_EQ(subrelease.num_partial_alloc_pages_subreleased, Length(0)); + // Now we allocate more. + static const Length kL5 = kL2 - Length(2); + static const Length kL6 = kL4 - Length(2); + PAlloc p5 = AllocateWithSpanAllocInfo(kL5, p1.span_alloc_info); + PAlloc p6 = AllocateWithSpanAllocInfo(kL6, p3.span_alloc_info); + EXPECT_EQ(filler_.used_pages_in_released(), kL1 + kL3 + kL5 + kL6); + EXPECT_EQ(filler_.used_pages_in_partial_released(), Length(0)); + + Delete(p5); + Delete(p6); + + // We have some free pages in partially-released allocs now. + EXPECT_EQ(filler_.used_pages_in_partial_released(), kL1 + kL3); + // Because we gradually release free pages from partially-released allocs, we + // shouldn't be able to release all the k5+k6 free pages at once. + EXPECT_EQ(ReleasePartialPages(kL5), kL5); + EXPECT_EQ(ReleasePartialPages(kL6), kL6); + + // Check subrelease stats. + subrelease = filler_.subrelease_stats(); + EXPECT_EQ(subrelease.num_pages_subreleased, kL5 + kL6); + EXPECT_EQ(subrelease.num_partial_alloc_pages_subreleased, kL5 + kL6); - PAlloc p3 = Allocate(kAlloc - Length(2)); - PAlloc p4 = Allocate(kAlloc + Length(2)); - // We have two hugepages, both full: nothing to release. - ASSERT_EQ(Length(0), ReleasePages(kMaxValidPages)); Delete(p1); Delete(p3); +} + +TEST_P(FillerTest, ReleaseFreePagesInPartialAllocs_SpansAllocated) { + if (std::get<0>(GetParam()) != + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test since !kSpansAllocated"; + } + randomize_density_ = false; + SpanAllocInfo info = {kPagesPerHugePage.raw_num(), + AccessDensityPrediction::kDense}; + static const Length kAlloc = kPagesPerHugePage / 2; + static const Length kL1 = kAlloc - Length(1); + static const Length kL2 = kAlloc + Length(1); + + static const Length kL3 = kAlloc - Length(1); + static const Length kL4 = kAlloc + Length(1); + std::vector p1 = AllocateVectorWithSpanAllocInfo(kL1, info); + ASSERT_TRUE(!p1.empty()); + std::vector p2 = + AllocateVectorWithSpanAllocInfo(kL2, p1.front().span_alloc_info); + std::vector p3 = AllocateVectorWithSpanAllocInfo(kL3, info); + ASSERT_TRUE(!p3.empty()); + std::vector p4 = + AllocateVectorWithSpanAllocInfo(kL4, p3.front().span_alloc_info); + + // As there are no free pages, we shouldn't be able to release anything. + EXPECT_EQ(ReleasePartialPages(kMaxValidPages), Length(0)); + + DeleteVector(p2); + DeleteVector(p4); + + // Check subrelease stats. + SubreleaseStats subrelease = filler_.subrelease_stats(); + EXPECT_EQ(subrelease.num_pages_subreleased, Length(0)); + EXPECT_EQ(subrelease.num_partial_alloc_pages_subreleased, Length(0)); + + // As we do not have any pages in partially-released lists, we should continue + // to release the requested number of pages. + EXPECT_EQ(filler_.used_pages_in_partial_released(), Length(0)); + EXPECT_EQ(ReleasePartialPages(kL2), kL2); + EXPECT_EQ(ReleasePartialPages(kL4), kL4); + + // Check subrelease stats. + subrelease = filler_.subrelease_stats(); + EXPECT_EQ(subrelease.num_pages_subreleased, kL2 + kL4); + EXPECT_EQ(subrelease.num_partial_alloc_pages_subreleased, Length(0)); + // Now we allocate more. + static const Length kL5 = kL2 - Length(2); + static const Length kL6 = kL4 - Length(2); + std::vector p5 = + AllocateVectorWithSpanAllocInfo(kL5, p1.front().span_alloc_info); + std::vector p6 = + AllocateVectorWithSpanAllocInfo(kL6, p3.front().span_alloc_info); + EXPECT_EQ(filler_.used_pages_in_released(), kL3 + kL6 - Length(2)); + EXPECT_EQ(filler_.used_pages_in_partial_released(), Length(0)); + + DeleteVector(p5); + DeleteVector(p6); + + // We have some free pages in partially-released allocs now. + EXPECT_EQ(filler_.used_pages_in_partial_released(), kL3); + // Because we gradually release free pages from partially-released allocs, we + // should be able to release all the k5+k6 free pages when the dense tracker + // is sorted on spans allocated. + static const Length kLReleased5 = ReleasePartialPages(kL5); + static const Length kLReleased6 = ReleasePartialPages(kL6); + EXPECT_TRUE(kLReleased5 == kL5 + kL6 && kLReleased6 == Length(0)); + + // Check subrelease stats. + subrelease = filler_.subrelease_stats(); + EXPECT_EQ(subrelease.num_pages_subreleased, kL5 + kL6); + EXPECT_EQ(subrelease.num_partial_alloc_pages_subreleased, kL6 - Length(2)); + + DeleteVector(p1); + DeleteVector(p3); +} + +TEST_P(FillerTest, AccountingForUsedPartialReleased) { + static const Length kAlloc = kPagesPerHugePage / 2; + static const Length kL1 = kAlloc + Length(3); + static const Length kL2 = kAlloc + Length(5); + std::vector p1 = AllocateVector(kL1); + ASSERT_TRUE(!p1.empty()); + std::vector p2 = AllocateVector(kL2); + ASSERT_TRUE(!p2.empty()); + // We have two hugepages. They maybe both partially allocated, or one of them + // is fully allocated and the other partially when the hugepages in the dense + // tracker are sorted on spans allocated. + ASSERT_EQ(ReleasePages(kMaxValidPages), + kPagesPerHugePage - kL1 + kPagesPerHugePage - kL2); + ASSERT_TRUE(filler_.used_pages_in_released() == kL1 + kL2 || + // When the hugepages in the dense tracker are sorted on spans and + // the two allocations above are both for dense spans. + filler_.used_pages_in_released() == + kL1 + kL2 - kPagesPerHugePage); + // Now we allocate more. + static const Length kL3 = kAlloc - Length(4); + static const Length kL4 = kAlloc - Length(7); + // Maintain the object count as above so that same alloc lists are used for + // the following two allocations. + std::vector p3 = + AllocateVectorWithSpanAllocInfo(kL3, p1.front().span_alloc_info); + std::vector p4 = + AllocateVectorWithSpanAllocInfo(kL4, p2.front().span_alloc_info); + EXPECT_TRUE(filler_.used_pages_in_released() == kL1 + kL2 + kL3 + kL4 || + filler_.used_pages_in_released() == + kL1 + kL2 + kL3 + kL4 - kPagesPerHugePage); + DeleteVector(p3); + DeleteVector(p4); + EXPECT_TRUE(filler_.used_pages_in_partial_released() == kL1 + kL2 || + // When the hugepages in the dense tracker are sorted on spans and + // the two allocations above are both for dense spans. + filler_.used_pages_in_partial_released() == + kL1 + kL2 - kPagesPerHugePage); + EXPECT_EQ(filler_.used_pages_in_released(), Length(0)); + DeleteVector(p1); + DeleteVector(p2); +} + +TEST_P(FillerTest, Release) { + static const Length kAlloc = kPagesPerHugePage / 2; + // Maintain the object count for the second allocation so that the alloc + // list + // remains the same for the two allocations. + std::vector p1 = AllocateVector(kAlloc - Length(1)); + ASSERT_TRUE(!p1.empty()); + std::vector p2 = AllocateVectorWithSpanAllocInfo( + kAlloc + Length(1), p1.front().span_alloc_info); + + std::vector p3 = AllocateVector(kAlloc - Length(2)); + ASSERT_TRUE(!p3.empty()); + std::vector p4 = AllocateVectorWithSpanAllocInfo( + kAlloc + Length(2), p3.front().span_alloc_info); + // We have two hugepages, both full: nothing to release. + ASSERT_EQ(ReleasePages(kMaxValidPages), Length(0)); + DeleteVector(p1); + DeleteVector(p3); // Now we should see the p1 hugepage - emptier - released. - ASSERT_EQ(kAlloc - Length(1), ReleasePages(kAlloc - Length(1))); - EXPECT_EQ(kAlloc - Length(1), filler_.unmapped_pages()); - ASSERT_TRUE(p1.pt->released()); - ASSERT_FALSE(p3.pt->released()); + ASSERT_EQ(ReleasePages(kAlloc - Length(1)), kAlloc - Length(1)); + EXPECT_EQ(filler_.unmapped_pages(), kAlloc - Length(1)); + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(0)); + ASSERT_TRUE(AllReleased(p1)); + for (const auto& pa : p1) { + ASSERT_FALSE(pa.from_released); + } + ASSERT_FALSE(AllReleased(p3)); + for (const auto& pa : p3) { + ASSERT_FALSE(pa.from_released); + } // We expect to reuse p1.pt. - PAlloc p5 = Allocate(kAlloc - Length(1)); - ASSERT_TRUE(p1.pt == p5.pt || p3.pt == p5.pt); + std::vector p5 = AllocateVectorWithSpanAllocInfo( + kAlloc - Length(1), p1.front().span_alloc_info); + const bool dense_tracker_and_sorted_on_allocs = + (std::get<0>(GetParam()) == + HugePageFillerDenseTrackerType::kSpansAllocated); + if (dense_tracker_and_sorted_on_allocs) { + ASSERT_TRUE(p1.front().pt == p5.front().pt || + p3.front().pt == p5.front().pt); + } else { + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(1)); + ASSERT_TRUE(p1.front().pt == p5.front().pt); + } - Delete(p2); - Delete(p4); - Delete(p5); + DeleteVector(p2); + DeleteVector(p4); + DeleteVector(p5); + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(0)); +} + +TEST_P(FillerTest, ReleaseZero) { + // Trying to release no pages should not crash. + EXPECT_EQ( + ReleasePages(Length(0), + SkipSubreleaseIntervals{.short_interval = absl::Seconds(1), + .long_interval = absl::Seconds(1)}), + Length(0)); } -TEST_P(FillerTest, Fragmentation) { +void FillerTest::FragmentationTest() { + constexpr Length kRequestLimit = Length(32); + constexpr Length kSizeLimit = Length(512 * 1024); + constexpr size_t kReps = 1000; + absl::BitGen rng; - auto dist = EmpiricalDistribution(absl::GetFlag(FLAGS_frag_req_limit)); + auto dist = EmpiricalDistribution(kRequestLimit); - std::vector allocs; + std::vector> allocs; + std::vector lengths; Length total; - while (total < absl::GetFlag(FLAGS_frag_size)) { + while (total < kSizeLimit) { auto n = Length(dist(rng)); total += n; - allocs.push_back(AllocateRaw(n)); + allocs.push_back(AllocateVector(n)); + lengths.push_back(n); } double max_slack = 0.0; - const size_t kReps = absl::GetFlag(FLAGS_frag_iters); for (size_t i = 0; i < kReps; ++i) { auto stats = filler_.stats(); double slack = static_cast(stats.free_bytes) / stats.system_bytes; @@ -893,23 +1288,28 @@ TEST_P(FillerTest, Fragmentation) { if (absl::Bernoulli(rng, 1.0 / 2)) { size_t index = absl::Uniform(rng, 0, allocs.size()); std::swap(allocs[index], allocs.back()); - DeleteRaw(allocs.back()); - total -= allocs.back().n; + std::swap(lengths[index], lengths.back()); + DeleteVector(allocs.back()); + total -= lengths.back(); allocs.pop_back(); + lengths.pop_back(); } else { auto n = Length(dist(rng)); - allocs.push_back(AllocateRaw(n)); + allocs.push_back(AllocateVector(n)); + lengths.push_back(n); total += n; } } - EXPECT_LE(max_slack, 0.05); + EXPECT_LE(max_slack, 0.06); for (auto a : allocs) { - DeleteRaw(a); + DeleteVector(a); } } +TEST_P(FillerTest, Fragmentation) { FragmentationTest(); } + TEST_P(FillerTest, PrintFreeRatio) { // This test is sensitive to the number of pages per hugepage, as we are // printing raw stats. @@ -917,63 +1317,60 @@ TEST_P(FillerTest, PrintFreeRatio) { GTEST_SKIP(); } + // We prevent randomly choosing the number of objects per span since this + // test has hardcoded output which will change if the objects per span are + // chosen at random. + randomize_density_ = false; + // Allocate two huge pages, release one, verify that we do not get an invalid // (>1.) ratio of free : non-fulls. // First huge page - PAlloc a1 = Allocate(kPagesPerHugePage / 2); - PAlloc a2 = Allocate(kPagesPerHugePage / 2); + std::vector a1 = AllocateVector(kPagesPerHugePage / 2); + ASSERT_TRUE(!a1.empty()); + std::vector a2 = AllocateVectorWithSpanAllocInfo( + kPagesPerHugePage / 2, a1.front().span_alloc_info); // Second huge page constexpr Length kQ = kPagesPerHugePage / 4; - PAlloc a3 = Allocate(kQ); - PAlloc a4 = Allocate(kQ); - PAlloc a5 = Allocate(kQ); - PAlloc a6 = Allocate(kQ); - - Delete(a6); + std::vector a3 = AllocateVector(kQ); + ASSERT_TRUE(!a3.empty()); + std::vector a4 = + AllocateVectorWithSpanAllocInfo(kQ, a3.front().span_alloc_info); + std::vector a5 = + AllocateVectorWithSpanAllocInfo(kQ, a3.front().span_alloc_info); + std::vector a6 = + AllocateVectorWithSpanAllocInfo(kQ, a3.front().span_alloc_info); + DeleteVector(a6); ReleasePages(kQ); - - Delete(a5); - + DeleteVector(a5); std::string buffer(1024 * 1024, '\0'); { + PageHeapSpinLockHolder l; Printer printer(&*buffer.begin(), buffer.size()); - filler_.Print(&printer, /*everything=*/true); + filler_.Print(printer, /*everything=*/true); buffer.erase(printer.SpaceRequired()); } - if (GetParam() == FillerPartialRerelease::Retain) { - EXPECT_THAT( - buffer, - testing::StartsWith( - R"(HugePageFiller: densely pack small requests into hugepages -HugePageFiller: 2 total, 1 full, 0 partial, 1 released (1 partially), 0 quarantined + EXPECT_THAT(buffer, + testing::StartsWith( + R"(HugePageFiller: densely pack small requests into hugepages +HugePageFiller: Overall, 2 total, 1 full, 0 partial, 1 released (1 partially), 0 quarantined +HugePageFiller: those with sparsely-accessed spans, 2 total, 1 full, 0 partial, 1 released (1 partially), 0 quarantined +HugePageFiller: those with densely-accessed spans, 0 total, 0 full, 0 partial, 0 released (0 partially), 0 quarantined HugePageFiller: 64 pages free in 2 hugepages, 0.1250 free HugePageFiller: among non-fulls, 0.2500 free HugePageFiller: 128 used pages in subreleased hugepages (128 of them in partially released) HugePageFiller: 1 hugepages partially released, 0.2500 released HugePageFiller: 0.6667 of used pages hugepageable)")); - } else { - EXPECT_THAT( - buffer, - testing::StartsWith( - R"(HugePageFiller: densely pack small requests into hugepages -HugePageFiller: 2 total, 1 full, 0 partial, 1 released (0 partially), 0 quarantined -HugePageFiller: 0 pages free in 2 hugepages, 0.0000 free -HugePageFiller: among non-fulls, 0.0000 free -HugePageFiller: 128 used pages in subreleased hugepages (0 of them in partially released) -HugePageFiller: 1 hugepages partially released, 0.5000 released -HugePageFiller: 0.6667 of used pages hugepageable)")); - } // Cleanup remaining allocs. - Delete(a1); - Delete(a2); - Delete(a3); - Delete(a4); + DeleteVector(a1); + DeleteVector(a2); + DeleteVector(a3); + DeleteVector(a4); } static double BytesToMiB(size_t bytes) { return bytes / (1024.0 * 1024.0); } @@ -989,50 +1386,54 @@ TEST_P(FillerTest, HugePageFrac) { EXPECT_THAT(filler_.hugepage_frac(), AnyOf(Eq(0), Eq(1))); static const Length kQ = kPagesPerHugePage / 4; // These are all on one page: - auto a1 = Allocate(kQ); - auto a2 = Allocate(kQ); - auto a3 = Allocate(kQ - Length(1)); - auto a4 = Allocate(kQ + Length(1)); + auto a1 = AllocateVector(kQ); + ASSERT_TRUE(!a1.empty()); + auto a2 = AllocateVectorWithSpanAllocInfo(kQ, a1.front().span_alloc_info); + auto a3 = AllocateVectorWithSpanAllocInfo(kQ - Length(1), + a1.front().span_alloc_info); + auto a4 = AllocateVectorWithSpanAllocInfo(kQ + Length(1), + a1.front().span_alloc_info); // As are these: - auto a5 = Allocate(kPagesPerHugePage - kQ); - auto a6 = Allocate(kQ); + auto a5 = AllocateVector(kPagesPerHugePage - kQ); + ASSERT_TRUE(!a5.empty()); + auto a6 = AllocateVectorWithSpanAllocInfo(kQ, a5.front().span_alloc_info); - EXPECT_EQ(1, filler_.hugepage_frac()); + EXPECT_EQ(filler_.hugepage_frac(), 1); // Free space doesn't affect it... - Delete(a4); - Delete(a6); + DeleteVector(a4); + DeleteVector(a6); - EXPECT_EQ(1, filler_.hugepage_frac()); + EXPECT_EQ(filler_.hugepage_frac(), 1); // Releasing the hugepage does. - ASSERT_EQ(kQ + Length(1), ReleasePages(kQ + Length(1))); - EXPECT_EQ((3.0 * kQ.raw_num()) / (6.0 * kQ.raw_num() - 1.0), - filler_.hugepage_frac()); + ASSERT_EQ(ReleasePages(kQ + Length(1)), kQ + Length(1)); + EXPECT_EQ(filler_.hugepage_frac(), + (3.0 * kQ.raw_num()) / (6.0 * kQ.raw_num() - 1.0)); // Check our arithmetic in a couple scenarios. // 2 kQs on the release and 3 on the hugepage - Delete(a2); - EXPECT_EQ((3.0 * kQ.raw_num()) / (5.0 * kQ.raw_num() - 1), - filler_.hugepage_frac()); + DeleteVector(a2); + EXPECT_EQ(filler_.hugepage_frac(), + (3.0 * kQ.raw_num()) / (5.0 * kQ.raw_num() - 1)); // This releases the free page on the partially released hugepage. - ASSERT_EQ(kQ, ReleasePages(kQ)); - EXPECT_EQ((3.0 * kQ.raw_num()) / (5.0 * kQ.raw_num() - 1), - filler_.hugepage_frac()); + ASSERT_EQ(ReleasePages(kQ), kQ); + EXPECT_EQ(filler_.hugepage_frac(), + (3.0 * kQ.raw_num()) / (5.0 * kQ.raw_num() - 1)); // just-over-1 kQ on the release and 3 on the hugepage - Delete(a3); - EXPECT_EQ((3 * kQ.raw_num()) / (4.0 * kQ.raw_num()), filler_.hugepage_frac()); + DeleteVector(a3); + EXPECT_EQ(filler_.hugepage_frac(), (3 * kQ.raw_num()) / (4.0 * kQ.raw_num())); // This releases the free page on the partially released hugepage. - ASSERT_EQ(kQ - Length(1), ReleasePages(kQ - Length(1))); - EXPECT_EQ((3 * kQ.raw_num()) / (4.0 * kQ.raw_num()), filler_.hugepage_frac()); + ASSERT_EQ(ReleasePages(kQ - Length(1)), kQ - Length(1)); + EXPECT_EQ(filler_.hugepage_frac(), (3 * kQ.raw_num()) / (4.0 * kQ.raw_num())); // All huge! - Delete(a1); - EXPECT_EQ(1, filler_.hugepage_frac()); + DeleteVector(a1); + EXPECT_EQ(filler_.hugepage_frac(), 1); - Delete(a5); + DeleteVector(a5); } // Repeatedly grow from FLAG_bytes to FLAG_bytes * growth factor, then shrink @@ -1051,12 +1452,12 @@ TEST_P(FillerTest, DISABLED_ReleaseFrac) { std::vector allocs; while (filler_.used_pages() < baseline) { - allocs.push_back(AllocateRaw(Length(1))); + allocs.push_back(Allocate(Length(1))); } while (true) { while (filler_.used_pages() < peak) { - allocs.push_back(AllocateRaw(Length(1))); + allocs.push_back(Allocate(Length(1))); } const double peak_frac = filler_.hugepage_frac(); // VSS @@ -1067,7 +1468,7 @@ TEST_P(FillerTest, DISABLED_ReleaseFrac) { size_t limit = allocs.size(); while (filler_.used_pages() > baseline) { --limit; - DeleteRaw(allocs[limit]); + Delete(allocs[limit]); } allocs.resize(limit); while (filler_.free_pages() > free_target) { @@ -1080,345 +1481,518 @@ TEST_P(FillerTest, DISABLED_ReleaseFrac) { } } -TEST_P(FillerTest, ReleaseAccounting) { +// Make sure we release appropriate number of pages when using +// ReleasePartialPages. +TEST_P(FillerTest, ReleasePagesFromPartialAllocs) { const Length N = kPagesPerHugePage; - auto big = Allocate(N - Length(2)); - auto tiny1 = Allocate(Length(1)); - auto tiny2 = Allocate(Length(1)); - auto half1 = Allocate(N / 2); - auto half2 = Allocate(N / 2); + auto big = AllocateVector(N - Length(2)); + ASSERT_TRUE(!big.empty()); + auto tiny1 = + AllocateWithSpanAllocInfo(Length(1), big.front().span_alloc_info); + auto tiny2 = + AllocateWithSpanAllocInfo(Length(1), big.front().span_alloc_info); + auto half1 = AllocateVector(N / 2); + ASSERT_TRUE(!half1.empty()); + auto half2 = + AllocateVectorWithSpanAllocInfo(N / 2, half1.front().span_alloc_info); + + DeleteVector(half1); + DeleteVector(big); + + ASSERT_EQ(filler_.size(), NHugePages(2)); - Delete(half1); - Delete(big); + // We should pick the [empty big][full tiny] hugepage here. + EXPECT_EQ(ReleasePartialPages(N - Length(2)), N - Length(2)); + EXPECT_EQ(filler_.unmapped_pages(), N - Length(2)); + // This shouldn't trigger a release. + Delete(tiny1); + EXPECT_EQ(filler_.unmapped_pages(), N - Length(2)); + // Until we call ReleasePartialPages() again. + EXPECT_EQ(ReleasePartialPages(Length(1)), Length(1)); + + // As should this, but this will drop the whole hugepage. + Delete(tiny2); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); + EXPECT_EQ(filler_.size(), NHugePages(1)); + + // We should release tiny2 here. + EXPECT_EQ(ReleasePartialPages(Length(1)), Length(1)); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); + EXPECT_EQ(filler_.size(), NHugePages(1)); + + // Check subrelease stats. + EXPECT_EQ(filler_.used_pages(), N / 2); + EXPECT_EQ(filler_.used_pages_in_any_subreleased(), Length(0)); + EXPECT_EQ(filler_.used_pages_in_partial_released(), Length(0)); + EXPECT_EQ(filler_.used_pages_in_released(), Length(0)); + + // Now we pick the half/half hugepage. We should be able to release pages from + // full allocs with ReleasePartialPages even though partially-released allocs + // are empty. + EXPECT_EQ(ReleasePartialPages(kMaxValidPages), N / 2); + EXPECT_EQ(filler_.unmapped_pages(), N / 2); + + // Check subrelease stats. + EXPECT_EQ(filler_.used_pages(), N / 2); + EXPECT_EQ(filler_.used_pages_in_any_subreleased(), N / 2); + EXPECT_EQ(filler_.used_pages_in_partial_released(), Length(0)); + EXPECT_EQ(filler_.used_pages_in_released(), N / 2); + + DeleteVector(half2); + EXPECT_EQ(filler_.size(), NHugePages(0)); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); +} - ASSERT_EQ(NHugePages(2), filler_.size()); +TEST_P(FillerTest, ReleaseAccounting) { + const Length N = kPagesPerHugePage; + auto big = AllocateVector(N - Length(2)); + ASSERT_TRUE(!big.empty()); + auto tiny1 = + AllocateWithSpanAllocInfo(Length(1), big.front().span_alloc_info); + auto tiny2 = + AllocateWithSpanAllocInfo(Length(1), big.front().span_alloc_info); + auto half1 = AllocateVector(N / 2); + ASSERT_TRUE(!half1.empty()); + auto half2 = + AllocateVectorWithSpanAllocInfo(N / 2, half1.front().span_alloc_info); + ASSERT_TRUE(!half2.empty()); + + DeleteVector(half1); + DeleteVector(big); + + ASSERT_EQ(filler_.size(), NHugePages(2)); // We should pick the [empty big][full tiny] hugepage here. - EXPECT_EQ(N - Length(2), ReleasePages(N - Length(2))); - EXPECT_EQ(N - Length(2), filler_.unmapped_pages()); + EXPECT_EQ(ReleasePages(N - Length(2)), N - Length(2)); + EXPECT_EQ(filler_.unmapped_pages(), N - Length(2)); // This shouldn't trigger a release Delete(tiny1); - if (GetParam() == FillerPartialRerelease::Retain) { - EXPECT_EQ(N - Length(2), filler_.unmapped_pages()); - // Until we call ReleasePages() - EXPECT_EQ(Length(1), ReleasePages(Length(1))); - } - EXPECT_EQ(N - Length(1), filler_.unmapped_pages()); + EXPECT_EQ(filler_.unmapped_pages(), N - Length(2)); + // Until we call ReleasePages() + EXPECT_EQ(ReleasePages(Length(1)), Length(1)); + EXPECT_EQ(filler_.unmapped_pages(), N - Length(1)); // As should this, but this will drop the whole hugepage Delete(tiny2); - EXPECT_EQ(Length(0), filler_.unmapped_pages()); - EXPECT_EQ(NHugePages(1), filler_.size()); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); + EXPECT_EQ(filler_.size(), NHugePages(1)); // This shouldn't trigger any release: we just claim credit for the // releases we did automatically on tiny2. - if (GetParam() == FillerPartialRerelease::Retain) { - EXPECT_EQ(Length(1), ReleasePages(Length(1))); - } else { - EXPECT_EQ(Length(2), ReleasePages(Length(2))); - } - EXPECT_EQ(Length(0), filler_.unmapped_pages()); - EXPECT_EQ(NHugePages(1), filler_.size()); + EXPECT_EQ(ReleasePages(Length(1)), Length(1)); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); + EXPECT_EQ(filler_.size(), NHugePages(1)); // Check subrelease stats - EXPECT_EQ(N / 2, filler_.used_pages()); - EXPECT_EQ(Length(0), filler_.used_pages_in_any_subreleased()); - EXPECT_EQ(Length(0), filler_.used_pages_in_partial_released()); - EXPECT_EQ(Length(0), filler_.used_pages_in_released()); + EXPECT_EQ(filler_.used_pages(), N / 2); + EXPECT_EQ(filler_.used_pages_in_any_subreleased(), Length(0)); + EXPECT_EQ(filler_.used_pages_in_partial_released(), Length(0)); + EXPECT_EQ(filler_.used_pages_in_released(), Length(0)); // Now we pick the half/half hugepage - EXPECT_EQ(N / 2, ReleasePages(kMaxValidPages)); - EXPECT_EQ(N / 2, filler_.unmapped_pages()); + EXPECT_EQ(ReleasePages(kMaxValidPages), N / 2); + EXPECT_EQ(filler_.unmapped_pages(), N / 2); // Check subrelease stats - EXPECT_EQ(N / 2, filler_.used_pages()); - EXPECT_EQ(N / 2, filler_.used_pages_in_any_subreleased()); - EXPECT_EQ(Length(0), filler_.used_pages_in_partial_released()); - EXPECT_EQ(N / 2, filler_.used_pages_in_released()); - - // Check accounting for partially released hugepages with partial rerelease - if (GetParam() == FillerPartialRerelease::Retain) { - // Allocating and deallocating a small object causes the page to turn from - // a released hugepage into a partially released hugepage. - auto tiny3 = Allocate(Length(1)); - auto tiny4 = Allocate(Length(1)); - Delete(tiny4); - EXPECT_EQ(N / 2 + Length(1), filler_.used_pages()); - EXPECT_EQ(N / 2 + Length(1), filler_.used_pages_in_any_subreleased()); - EXPECT_EQ(N / 2 + Length(1), filler_.used_pages_in_partial_released()); - EXPECT_EQ(Length(0), filler_.used_pages_in_released()); - Delete(tiny3); - } - - Delete(half2); - EXPECT_EQ(NHugePages(0), filler_.size()); - EXPECT_EQ(Length(0), filler_.unmapped_pages()); + EXPECT_EQ(filler_.used_pages(), N / 2); + EXPECT_EQ(filler_.used_pages_in_any_subreleased(), N / 2); + EXPECT_EQ(filler_.used_pages_in_partial_released(), Length(0)); + EXPECT_EQ(filler_.used_pages_in_released(), N / 2); + + // Check accounting for partially released hugepages with partial rerelease. + // Allocating and deallocating a small object causes the page to turn from a + // released hugepage into a partially released hugepage. + // + // The number of objects for each allocation is same as that for half2 so to + // ensure that same alloc list is used. + auto tiny3 = + AllocateWithSpanAllocInfo(Length(1), half2.front().span_alloc_info); + auto tiny4 = + AllocateWithSpanAllocInfo(Length(1), half2.front().span_alloc_info); + Delete(tiny4); + EXPECT_EQ(filler_.used_pages(), N / 2 + Length(1)); + EXPECT_EQ(filler_.used_pages_in_any_subreleased(), N / 2 + Length(1)); + EXPECT_EQ(filler_.used_pages_in_partial_released(), N / 2 + Length(1)); + EXPECT_EQ(filler_.used_pages_in_released(), Length(0)); + Delete(tiny3); + + DeleteVector(half2); + EXPECT_EQ(filler_.size(), NHugePages(0)); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); } TEST_P(FillerTest, ReleaseWithReuse) { const Length N = kPagesPerHugePage; - auto half = Allocate(N / 2); - auto tiny1 = Allocate(N / 4); - auto tiny2 = Allocate(N / 4); + auto half = AllocateVector(N / 2); + ASSERT_TRUE(!half.empty()); + auto tiny1 = + AllocateVectorWithSpanAllocInfo(N / 4, half.front().span_alloc_info); + auto tiny2 = + AllocateVectorWithSpanAllocInfo(N / 4, half.front().span_alloc_info); - Delete(half); - - ASSERT_EQ(NHugePages(1), filler_.size()); + DeleteVector(half); + ASSERT_EQ(filler_.size(), NHugePages(1)); // We should be able to release the pages from half1. - EXPECT_EQ(N / 2, ReleasePages(kMaxValidPages)); - EXPECT_EQ(N / 2, filler_.unmapped_pages()); + EXPECT_EQ(ReleasePages(kMaxValidPages), N / 2); + EXPECT_EQ(filler_.unmapped_pages(), N / 2); + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(0)); // Release tiny1, release more. - Delete(tiny1); + DeleteVector(tiny1); - EXPECT_EQ(N / 4, ReleasePages(kMaxValidPages)); - EXPECT_EQ(3 * N / 4, filler_.unmapped_pages()); + EXPECT_EQ(ReleasePages(kMaxValidPages), N / 4); + EXPECT_EQ(filler_.unmapped_pages(), 3 * N / 4); + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(0)); // Repopulate, confirm we can't release anything and unmapped pages goes to 0. - tiny1 = Allocate(N / 4); + tiny1 = AllocateVectorWithSpanAllocInfo(N / 4, half.front().span_alloc_info); EXPECT_EQ(Length(0), ReleasePages(kMaxValidPages)); EXPECT_EQ(N / 2, filler_.unmapped_pages()); + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(0)); // Continue repopulating. - half = Allocate(N / 2); - EXPECT_EQ(Length(0), ReleasePages(kMaxValidPages)); - EXPECT_EQ(Length(0), filler_.unmapped_pages()); - EXPECT_EQ(NHugePages(1), filler_.size()); + half = AllocateVectorWithSpanAllocInfo(N / 2, half.front().span_alloc_info); + EXPECT_EQ(ReleasePages(kMaxValidPages), Length(0)); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); + EXPECT_EQ(filler_.size(), NHugePages(1)); + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(1)); // Release everything and cleanup. - Delete(half); - Delete(tiny1); - Delete(tiny2); - EXPECT_EQ(NHugePages(0), filler_.size()); - EXPECT_EQ(Length(0), filler_.unmapped_pages()); + DeleteVector(half); + DeleteVector(tiny1); + DeleteVector(tiny2); + EXPECT_EQ(filler_.size(), NHugePages(0)); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(0)); } -TEST_P(FillerTest, AvoidArbitraryQuarantineVMGrowth) { +TEST_P(FillerTest, CheckPreviouslyReleasedStats) { const Length N = kPagesPerHugePage; - // Guarantee we have a ton of released pages go empty. - for (int i = 0; i < 10 * 1000; ++i) { - auto half1 = Allocate(N / 2); - auto half2 = Allocate(N / 2); - Delete(half1); - ASSERT_EQ(N / 2, ReleasePages(N / 2)); - Delete(half2); - } + auto half = AllocateVector(N / 2); + ASSERT_TRUE(!half.empty()); + auto tiny1 = + AllocateVectorWithSpanAllocInfo(N / 4, half.front().span_alloc_info); + auto tiny2 = + AllocateVectorWithSpanAllocInfo(N / 4, half.front().span_alloc_info); - auto s = filler_.stats(); - EXPECT_GE(1024 * 1024 * 1024, s.system_bytes); -} + DeleteVector(half); + ASSERT_EQ(filler_.size(), NHugePages(1)); -TEST_P(FillerTest, StronglyPreferNonDonated) { - // We donate several huge pages of varying fullnesses. Then we make several - // allocations that would be perfect fits for the donated hugepages, *after* - // making one allocation that won't fit, to ensure that a huge page is - // contributed normally. Finally, we verify that we can still get the - // donated huge pages back. (I.e. they weren't used.) - std::vector donated; - ASSERT_GE(kPagesPerHugePage, Length(10)); - for (auto i = Length(1); i <= Length(3); ++i) { - donated.push_back(Allocate(kPagesPerHugePage - i, /*donated=*/true)); - } + // We should be able to release the pages from half1. + EXPECT_EQ(ReleasePages(kMaxValidPages), N / 2); + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(0)); - std::vector regular; - for (auto i = Length(4); i >= Length(1); --i) { - regular.push_back(Allocate(i)); + std::string buffer(1024 * 1024, '\0'); + { + PageHeapSpinLockHolder l; + Printer printer(&*buffer.begin(), buffer.size()); + filler_.Print(printer, true); } - - for (const PAlloc& alloc : donated) { - // All the donated huge pages should be freeable. - EXPECT_TRUE(Delete(alloc)); + buffer.resize(strlen(buffer.c_str())); + EXPECT_THAT(buffer, testing::HasSubstr( + "HugePageFiller: 0 hugepages became full after " + "being previously released, " + "out of which 0 pages are hugepage backed.")); + + // Repopulate. + ASSERT_TRUE(!tiny1.empty()); + half = AllocateVectorWithSpanAllocInfo(N / 2, tiny1.front().span_alloc_info); + EXPECT_EQ(ReleasePages(kMaxValidPages), Length(0)); + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(1)); + buffer.resize(1024 * 1024); + { + PageHeapSpinLockHolder l; + Printer printer(&*buffer.begin(), buffer.size()); + filler_.Print(printer, true); } - for (const PAlloc& alloc : regular) { - Delete(alloc); + buffer.resize(strlen(buffer.c_str())); + EXPECT_THAT(buffer, + testing::HasSubstr("HugePageFiller: 1 hugepages became full " + "after being previously released, " + "out of which 0 pages are hugepage backed.")); + + // Release everything and cleanup. + DeleteVector(half); + DeleteVector(tiny1); + DeleteVector(tiny2); + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(0)); + buffer.resize(1024 * 1024); + { + PageHeapSpinLockHolder l; + Printer printer(&*buffer.begin(), buffer.size()); + filler_.Print(printer, true); } + buffer.resize(strlen(buffer.c_str())); + EXPECT_THAT(buffer, + testing::HasSubstr("HugePageFiller: 0 hugepages became full " + "after being previously released, " + "out of which 0 pages are hugepage backed.")); } -TEST_P(FillerTest, ParallelUnlockingSubrelease) { - if (GetParam() == FillerPartialRerelease::Retain) { - // When rerelease happens without going to Unback(), this test - // (intentionally) deadlocks, as we never receive the call. - return; - } +// Make sure that previously_released_huge_pages stat is correct when a huge +// page toggles from full -> released -> full -> released. +TEST_P(FillerTest, CheckFullReleasedFullReleasedState) { + const Length N = kPagesPerHugePage; + auto half = AllocateVector(N / 2); + ASSERT_TRUE(!half.empty()); + ASSERT_EQ(filler_.size(), NHugePages(1)); - // Verify that we can deallocate a partial huge page and successfully unlock - // the pageheap_lock without introducing race conditions around the metadata - // for PageTracker::released_. - // - // Currently, HPAA unbacks *all* subsequent deallocations to a huge page once - // we have broken up *any* part of it. - // - // If multiple deallocations are in-flight, we need to leave sufficient - // breadcrumbs to ourselves (PageTracker::releasing_ is a Length, not a bool) - // so that one deallocation completing does not have us "forget" that another - // deallocation is about to unback other parts of the hugepage. - // - // If PageTracker::releasing_ were a bool, the completion of "t1" and - // subsequent reallocation of "a2" in this test would mark the entirety of the - // page as full, so we would choose to *not* unback a2 (when deallocated) or - // a3 (when deallocated by t3). - constexpr Length N = kPagesPerHugePage; + // We should be able to release the N/2 pages that are free. + EXPECT_EQ(ReleasePages(kMaxValidPages), N / 2); + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(0)); - auto a1 = AllocateRaw(N / 2); - auto a2 = AllocateRaw(Length(1)); - auto a3 = AllocateRaw(Length(1)); + std::string buffer(1024 * 1024, '\0'); + { + PageHeapSpinLockHolder l; + Printer printer(&*buffer.begin(), buffer.size()); + filler_.Print(printer, true); + } + buffer.resize(strlen(buffer.c_str())); + EXPECT_THAT(buffer, + testing::HasSubstr("HugePageFiller: 0 hugepages became full " + "after being previously released, " + "out of which 0 pages are hugepage backed.")); + + // Repopulate. + auto half1 = + AllocateVectorWithSpanAllocInfo(N / 2, half.front().span_alloc_info); + EXPECT_EQ(ReleasePages(kMaxValidPages), Length(0)); + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(1)); + buffer.resize(1024 * 1024); + { + PageHeapSpinLockHolder l; + Printer printer(&*buffer.begin(), buffer.size()); + filler_.Print(printer, true); + } - // Trigger subrelease. The filler now has a partial hugepage, so subsequent - // calls to Delete() will cause us to unback the remainder of it. - EXPECT_GT(ReleasePages(kMaxValidPages), Length(0)); + buffer.resize(strlen(buffer.c_str())); + EXPECT_THAT(buffer, + testing::HasSubstr("HugePageFiller: 1 hugepages became full " + "after being previously released, " + "out of which 0 pages are hugepage backed.")); - auto m1 = absl::make_unique(); - auto m2 = absl::make_unique(); + // Release again. + DeleteVector(half1); + EXPECT_EQ(ReleasePages(kMaxValidPages), N / 2); + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(0)); - m1->Lock(); - m2->Lock(); + buffer.resize(1024 * 1024); + { + PageHeapSpinLockHolder l; + Printer printer(&*buffer.begin(), buffer.size()); + filler_.Print(printer, true); + } + buffer.resize(strlen(buffer.c_str())); + EXPECT_THAT(buffer, - absl::BlockingCounter counter(2); - BlockingUnback::counter = &counter; + testing::HasSubstr("HugePageFiller: 0 hugepages became full " + "after being previously released, " + "out of which 0 pages are hugepage backed.")); - std::thread t1([&]() { - BlockingUnback::set_lock(m1.get()); + // Release everything and cleanup. + DeleteVector(half); + EXPECT_EQ(filler_.previously_released_huge_pages(), NHugePages(0)); + buffer.resize(1024 * 1024); + { + PageHeapSpinLockHolder l; + Printer printer(&*buffer.begin(), buffer.size()); + filler_.Print(printer, true); + } + buffer.resize(strlen(buffer.c_str())); + EXPECT_THAT(buffer, + testing::HasSubstr("HugePageFiller: 0 hugepages became full " + "after being previously released, " + "out of which 0 pages are hugepage backed.")); +} - DeleteRaw(a2); - }); +TEST_P(FillerTest, AvoidArbitraryQuarantineVMGrowth) { + const Length N = kPagesPerHugePage; + // Guarantee we have a ton of released pages go empty. + for (int i = 0; i < 10 * 1000; ++i) { + auto half1 = AllocateVector(N / 2); + auto half2 = AllocateVector(N / 2); + DeleteVector(half1); + ASSERT_EQ(ReleasePages(N / 2), N / 2); + DeleteVector(half2); + } - std::thread t2([&]() { - BlockingUnback::set_lock(m2.get()); + auto s = filler_.stats(); + EXPECT_LE(s.system_bytes, 1024 * 1024 * 1024); +} - DeleteRaw(a3); - }); +TEST_P(FillerTest, StronglyPreferNonDonated) { + // We donate several huge pages of varying fullnesses. Then we make several + // allocations that would be perfect fits for the donated hugepages, *after* + // making one allocation that won't fit, to ensure that a huge page is + // contributed normally. Finally, we verify that we can still get the + // donated huge pages back. (I.e. they weren't used.) + std::vector> donated; + SpanAllocInfo info = {1, AccessDensityPrediction::kSparse}; + ASSERT_GE(kPagesPerHugePage, Length(10)); + for (auto i = Length(1); i <= Length(3); ++i) { + donated.push_back(AllocateVectorWithSpanAllocInfo(kPagesPerHugePage - i, + info, + /*donated=*/true)); + } - // Wait for t1 and t2 to block. - counter.Wait(); + std::vector> regular; + // Only sparsely-accessed spans are allocated from donated hugepages. So + // create a hugepage with a sparsely-accessed span. The test should prefer + // this hugepage for sparsely-accessed spans and should allocate a new + // hugepage for densely-accessed spans. + regular.push_back(AllocateVectorWithSpanAllocInfo(Length(4), info)); - // At this point, t1 and t2 are blocked (as if they were on a long-running - // syscall) on "unback" (m1 and m2, respectively). pageheap_lock is not held. - // - // Allocating a4 will complete the hugepage, but we have on-going releaser - // threads. - auto a4 = AllocateRaw((N / 2) - Length(2)); - EXPECT_EQ(NHugePages(1), filler_.size()); - - // Let one of the threads proceed. The huge page consists of: - // * a1 (N/2 ): Allocated - // * a2 ( 1): Unbacked - // * a3 ( 1): Unbacking (blocked on m2) - // * a4 (N/2-2): Allocated - m1->Unlock(); - t1.join(); - - // Reallocate a2. We should still consider the huge page partially backed for - // purposes of subreleasing. - a2 = AllocateRaw(Length(1)); - EXPECT_EQ(NHugePages(1), filler_.size()); - DeleteRaw(a2); - - // Let the other thread proceed. The huge page consists of: - // * a1 (N/2 ): Allocated - // * a2 ( 1): Unbacked - // * a3 ( 1): Unbacked - // * a4 (N/2-2): Allocated - m2->Unlock(); - t2.join(); - - EXPECT_EQ(filler_.used_pages(), N - Length(2)); - EXPECT_EQ(filler_.unmapped_pages(), Length(2)); - EXPECT_EQ(filler_.free_pages(), Length(0)); + for (auto i = Length(3); i >= Length(1); --i) { + regular.push_back(AllocateVector(i)); + } - // Clean up. - DeleteRaw(a1); - DeleteRaw(a4); + for (const std::vector& alloc : donated) { + // All the donated huge pages should be freeable. + EXPECT_TRUE(DeleteVector(alloc)); + } - BlockingUnback::counter = nullptr; + for (const std::vector& alloc : regular) { + DeleteVector(alloc); + } } -TEST_P(FillerTest, SkipSubrelease) { +TEST_P(FillerTest, SkipPartialAllocSubrelease) { // This test is sensitive to the number of pages per hugepage, as we are // printing raw stats. if (kPagesPerHugePage != Length(256)) { GTEST_SKIP(); } + if (std::get<0>(GetParam()) == + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test for kSpansAllocated"; + } - // Generate a peak, wait for time interval a, generate a trough, subrelease, - // wait for time interval b, generate another peak. - const auto peak_trough_peak = [&](absl::Duration a, absl::Duration b, - absl::Duration peak_interval, - bool expected_subrelease) { + // Firstly, this test generates a peak (long-term demand peak) and waits for + // time interval a. Then, it generates a higher peak plus a short-term + // fluctuation peak, and waits for time interval b. It then generates a trough + // in demand and tries to subrelease. Finally, it waits for time interval c to + // generate the highest peak for evaluating subrelease correctness. Skip + // subrelease selects those demand points using provided time intervals. + const auto demand_pattern = [&](absl::Duration a, absl::Duration b, + absl::Duration c, + SkipSubreleaseIntervals intervals, + bool expected_subrelease) { const Length N = kPagesPerHugePage; - PAlloc half = Allocate(N / 2); - PAlloc tiny1 = Allocate(N / 4); - PAlloc tiny2 = Allocate(N / 4); - - // To force a peak, we allocate 3/4 and 1/4 of a huge page. This is - // necessary after we delete `half` below, as a half huge page for the peak - // would fill into the gap previously occupied by it. + // First peak: min_demand 3/4N, max_demand 1N. PAlloc peak1a = Allocate(3 * N / 4); - PAlloc peak1b = Allocate(N / 4); - EXPECT_EQ(filler_.used_pages(), 2 * N); + PAlloc peak1b = AllocateWithSpanAllocInfo(N / 4, peak1a.span_alloc_info); + Advance(a); + // Second peak: min_demand 0, max_demand 2N. Delete(peak1a); Delete(peak1b); - Advance(a); - - Delete(half); - - EXPECT_EQ(expected_subrelease ? N / 2 : Length(0), - ReleasePages(10 * N, peak_interval)); - Advance(b); + PAlloc half = Allocate(N / 2); + PAlloc tiny1 = AllocateWithSpanAllocInfo(N / 4, half.span_alloc_info); + PAlloc tiny2 = AllocateWithSpanAllocInfo(N / 4, half.span_alloc_info); + // To force a peak, we allocate 3/4 and 1/4 of a huge page. This is + // necessary after we delete `half` below, as a half huge page for the + // peak would fill into the gap previously occupied by it. PAlloc peak2a = Allocate(3 * N / 4); - PAlloc peak2b = Allocate(N / 4); + PAlloc peak2b = AllocateWithSpanAllocInfo(N / 4, peak2a.span_alloc_info); + EXPECT_EQ(filler_.used_pages(), 2 * N); + Delete(peak2a); + Delete(peak2b); + Advance(b); + Delete(half); + EXPECT_EQ(filler_.free_pages(), Length(N / 2)); + // The number of released pages is limited to the number of free pages. + EXPECT_EQ(expected_subrelease ? N / 2 : Length(0), + ReleasePartialPages(10 * N, intervals)); + Advance(c); + // Third peak: min_demand 1/2N, max_demand (2+1/2)N. PAlloc peak3a = Allocate(3 * N / 4); - PAlloc peak3b = Allocate(N / 4); + PAlloc peak3b = AllocateWithSpanAllocInfo(N / 4, peak3a.span_alloc_info); + + PAlloc peak4a = Allocate(3 * N / 4); + PAlloc peak4b = AllocateWithSpanAllocInfo(N / 4, peak4a.span_alloc_info); Delete(tiny1); Delete(tiny2); - Delete(peak2a); - Delete(peak2b); Delete(peak3a); Delete(peak3b); + Delete(peak4a); + Delete(peak4b); EXPECT_EQ(filler_.used_pages(), Length(0)); EXPECT_EQ(filler_.unmapped_pages(), Length(0)); EXPECT_EQ(filler_.free_pages(), Length(0)); - EXPECT_EQ(expected_subrelease ? N / 2 : Length(0), ReleasePages(10 * N)); + EXPECT_EQ(expected_subrelease ? N / 2 : Length(0), + ReleasePartialPages(10 * N)); }; { - SCOPED_TRACE("peak-trough-peak 1"); - peak_trough_peak(absl::Minutes(2), absl::Minutes(2), absl::Minutes(3), - false); + // Skip subrelease feature is disabled if all intervals are zero. + SCOPED_TRACE("demand_pattern 1"); + demand_pattern(absl::Minutes(1), absl::Minutes(1), absl::Minutes(4), + SkipSubreleaseIntervals{}, true); } Advance(absl::Minutes(30)); { - SCOPED_TRACE("peak-trough-peak 2"); - peak_trough_peak(absl::Minutes(2), absl::Minutes(7), absl::Minutes(3), - false); + // Uses short-term and long-term intervals for skipping subrelease. It + // incorrectly skips 128 pages. + SCOPED_TRACE("demand_pattern 2"); + demand_pattern(absl::Minutes(3), absl::Minutes(2), absl::Minutes(7), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(3), + .long_interval = absl::Minutes(6)}, + false); } Advance(absl::Minutes(30)); { - SCOPED_TRACE("peak-trough-peak 3"); - peak_trough_peak(absl::Minutes(5), absl::Minutes(3), absl::Minutes(2), - true); + // Uses short-term and long-term intervals for skipping subrelease, + // subreleasing all free pages. + SCOPED_TRACE("demand_pattern 3"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(1), + .long_interval = absl::Minutes(2)}, + true); + } + Advance(absl::Minutes(30)); + + { + // Uses only short-term interval for skipping subrelease. It correctly + // skips 128 pages. + SCOPED_TRACE("demand_pattern 4"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(3)}, + false); } Advance(absl::Minutes(30)); - // This captures a corner case: If we hit another peak immediately after a - // subrelease decision (in the same time series epoch), do not count this as - // a correct subrelease decision. { - SCOPED_TRACE("peak-trough-peak 4"); - peak_trough_peak(absl::Milliseconds(10), absl::Milliseconds(10), - absl::Minutes(2), false); + // Uses only long-term interval for skipping subrelease, subreleased all + // free pages. + SCOPED_TRACE("demand_pattern 5"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.long_interval = absl::Minutes(2)}, + true); + } + + Advance(absl::Minutes(30)); + + // Repeats the "demand_pattern 9" test using short-term and long-term + // intervals, to show that subrelease decisions are evaluated independently. + { + SCOPED_TRACE("demand_pattern 6"); + demand_pattern(absl::Milliseconds(10), absl::Milliseconds(10), + absl::Milliseconds(10), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(1), + .long_interval = absl::Minutes(2)}, + false); } Advance(absl::Minutes(30)); @@ -1429,2099 +2003,1032 @@ TEST_P(FillerTest, SkipSubrelease) { std::string buffer(1024 * 1024, '\0'); { + PageHeapSpinLockHolder l; Printer printer(&*buffer.begin(), buffer.size()); - filler_.Print(&printer, true); + filler_.Print(printer, true); } buffer.resize(strlen(buffer.c_str())); - EXPECT_THAT(buffer, testing::HasSubstr(R"( -HugePageFiller: Since the start of the execution, 4 subreleases (512 pages) were skipped due to recent (120s) peaks. -HugePageFiller: 25.0000% of decisions confirmed correct, 0 pending (25.0000% of pages, 0 pending). + if (!dense_tracker_sorted_on_allocs_) { + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugePageFiller: Since the start of the execution, 3 subreleases (384 pages) were skipped due to the sum of short-term (60s) fluctuations and long-term (120s) trends. +HugePageFiller: 33.3333% of decisions confirmed correct, 0 pending (33.3333% of pages, 0 pending). )")); + } } -class FillerStatsTrackerTest : public testing::Test { - private: - static int64_t clock_; - static int64_t FakeClock() { return clock_; } - static double GetFakeClockFrequency() { - return absl::ToDoubleNanoseconds(absl::Seconds(2)); +TEST_P(FillerTest, SkipPartialAllocSubrelease_SpansAllocated) { + // This test is sensitive to the number of pages per hugepage, as we are + // printing raw stats. + if (kPagesPerHugePage != Length(256)) { + GTEST_SKIP(); } + if (std::get<0>(GetParam()) != + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test for !kSpansAllocated"; + } + randomize_density_ = false; + SpanAllocInfo info = {kPagesPerHugePage.raw_num(), + AccessDensityPrediction::kDense}; + + // Firstly, this test generates a peak (long-term demand peak) and waits for + // time interval a. Then, it generates a higher peak plus a short-term + // fluctuation peak, and waits for time interval b. It then generates a trough + // in demand and tries to subrelease. Finally, it waits for time interval c to + // generate the highest peak for evaluating subrelease correctness. Skip + // subrelease selects those demand points using provided time intervals. + const auto demand_pattern = [&](absl::Duration a, absl::Duration b, + absl::Duration c, + SkipSubreleaseIntervals intervals, + bool expected_subrelease) { + const Length N = kPagesPerHugePage; + // First peak: min_demand 3/4N, max_demand 1N. + std::vector peak1a = + AllocateVectorWithSpanAllocInfo(3 * N / 4, info); + ASSERT_TRUE(!peak1a.empty()); + std::vector peak1b = + AllocateVectorWithSpanAllocInfo(N / 4, peak1a.front().span_alloc_info); + Advance(a); + // Second peak: min_demand 0, max_demand 2N. + DeleteVector(peak1a); + DeleteVector(peak1b); - protected: - static constexpr absl::Duration kWindow = absl::Minutes(10); - - using StatsTrackerType = FillerStatsTracker<16>; - StatsTrackerType tracker_{ - Clock{.now = FakeClock, .freq = GetFakeClockFrequency}, kWindow, - absl::Minutes(5)}; + std::vector half = AllocateVectorWithSpanAllocInfo(N / 2, info); + ASSERT_TRUE(!half.empty()); + std::vector tiny1 = + AllocateVectorWithSpanAllocInfo(N / 4, half.front().span_alloc_info); + std::vector tiny2 = + AllocateVectorWithSpanAllocInfo(N / 4, half.front().span_alloc_info); - void Advance(absl::Duration d) { - clock_ += static_cast(absl::ToDoubleSeconds(d) * - GetFakeClockFrequency()); - } + // To force a peak, we allocate 3/4 and 1/4 of a huge page. This is + // necessary after we delete `half` below, as a half huge page for the + // peak would fill into the gap previously occupied by it. + std::vector peak2a = + AllocateVectorWithSpanAllocInfo(3 * N / 4, info); + ASSERT_TRUE(!peak2a.empty()); + std::vector peak2b = + AllocateVectorWithSpanAllocInfo(N / 4, peak2a.front().span_alloc_info); + EXPECT_EQ(filler_.used_pages(), 2 * N); + DeleteVector(peak2a); + DeleteVector(peak2b); + Advance(b); + DeleteVector(half); + EXPECT_EQ(filler_.free_pages(), Length(N / 2)); + // The number of released pages is limited to the number of free pages. + EXPECT_EQ(expected_subrelease ? N / 2 : Length(0), + ReleasePartialPages(10 * N, intervals)); + + Advance(c); + half = AllocateVectorWithSpanAllocInfo(N / 2, half.front().span_alloc_info); + // Third peak: min_demand 1/2N, max_demand (2+1/2)N. + std::vector peak3a = + AllocateVectorWithSpanAllocInfo(3 * N / 4, info); + ASSERT_TRUE(!peak3a.empty()); + std::vector peak3b = + AllocateVectorWithSpanAllocInfo(N / 4, peak3a.front().span_alloc_info); + + std::vector peak4a = + AllocateVectorWithSpanAllocInfo(3 * N / 4, info); + ASSERT_TRUE(!peak4a.empty()); + std::vector peak4b = + AllocateVectorWithSpanAllocInfo(N / 4, peak4a.front().span_alloc_info); + + DeleteVector(half); + DeleteVector(tiny1); + DeleteVector(tiny2); + DeleteVector(peak3a); + DeleteVector(peak3b); + DeleteVector(peak4a); + DeleteVector(peak4b); - // Generates four data points for the tracker that represent "interesting" - // points (i.e., min/max pages demand, min/max hugepages). - void GenerateInterestingPoints(Length num_pages, HugeLength num_hugepages, - Length num_free_pages); + EXPECT_EQ(filler_.used_pages(), Length(0)); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); + EXPECT_EQ(filler_.free_pages(), Length(0)); - // Generates a data point with a particular amount of demand pages, while - // ignoring the specific number of hugepages. - void GenerateDemandPoint(Length num_pages, Length num_free_pages); -}; + EXPECT_EQ(Length(0), ReleasePartialPages(10 * N)); + }; -int64_t FillerStatsTrackerTest::clock_{0}; - -void FillerStatsTrackerTest::GenerateInterestingPoints(Length num_pages, - HugeLength num_hugepages, - Length num_free_pages) { - for (int i = 0; i <= 1; ++i) { - for (int j = 0; j <= 1; ++j) { - StatsTrackerType::FillerStats stats; - stats.num_pages = num_pages + Length((i == 0) ? 4 : 8 * j); - stats.free_pages = num_free_pages + Length(10 * i + j); - stats.unmapped_pages = Length(10); - stats.used_pages_in_subreleased_huge_pages = num_pages; - stats.huge_pages[StatsTrackerType::kRegular] = - num_hugepages + ((i == 1) ? NHugePages(4) : NHugePages(8) * j); - stats.huge_pages[StatsTrackerType::kDonated] = num_hugepages; - stats.huge_pages[StatsTrackerType::kPartialReleased] = NHugePages(i); - stats.huge_pages[StatsTrackerType::kReleased] = NHugePages(j); - tracker_.Report(stats); - } + { + // Skip subrelease feature is disabled if all intervals are zero. + SCOPED_TRACE("demand_pattern 1"); + demand_pattern(absl::Minutes(1), absl::Minutes(1), absl::Minutes(4), + SkipSubreleaseIntervals{}, true); } -} -void FillerStatsTrackerTest::GenerateDemandPoint(Length num_pages, - Length num_free_pages) { - HugeLength hp = NHugePages(1); - StatsTrackerType::FillerStats stats; - stats.num_pages = num_pages; - stats.free_pages = num_free_pages; - stats.unmapped_pages = Length(0); - stats.used_pages_in_subreleased_huge_pages = Length(0); - stats.huge_pages[StatsTrackerType::kRegular] = hp; - stats.huge_pages[StatsTrackerType::kDonated] = hp; - stats.huge_pages[StatsTrackerType::kPartialReleased] = hp; - stats.huge_pages[StatsTrackerType::kReleased] = hp; - tracker_.Report(stats); -} + Advance(absl::Minutes(30)); -// Tests that the tracker aggregates all data correctly. The output is tested by -// comparing the text output of the tracker. While this is a bit verbose, it is -// much cleaner than extracting and comparing all data manually. -TEST_F(FillerStatsTrackerTest, Works) { - // Ensure that the beginning (when free pages are 0) is outside the 5-min - // window the instrumentation is recording. - GenerateInterestingPoints(Length(1), NHugePages(1), Length(1)); - Advance(absl::Minutes(5)); + { + // Uses short-term and long-term intervals for skipping subrelease. It + // incorrectly skips 128 pages. + SCOPED_TRACE("demand_pattern 2"); + demand_pattern(absl::Minutes(3), absl::Minutes(2), absl::Minutes(7), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(3), + .long_interval = absl::Minutes(6)}, + false); + } - GenerateInterestingPoints(Length(100), NHugePages(5), Length(200)); + Advance(absl::Minutes(30)); - Advance(absl::Minutes(1)); + { + // Uses short-term and long-term intervals for skipping subrelease, + // subreleasing all free pages. + SCOPED_TRACE("demand_pattern 3"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(1), + .long_interval = absl::Minutes(2)}, + true); + } + Advance(absl::Minutes(30)); - GenerateInterestingPoints(Length(200), NHugePages(10), Length(100)); + { + // Uses only short-term interval for skipping subrelease. It correctly + // skips 128 pages. + SCOPED_TRACE("demand_pattern 4"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(3)}, + false); + } - Advance(absl::Minutes(1)); + Advance(absl::Minutes(30)); - // Test text output (time series summary). { - std::string buffer(1024 * 1024, '\0'); - Printer printer(&*buffer.begin(), buffer.size()); - { - tracker_.Print(&printer); - buffer.erase(printer.SpaceRequired()); - } - - EXPECT_THAT(buffer, StrEq(R"(HugePageFiller: time series over 5 min interval + // Uses only long-term interval for skipping subrelease, subreleased all + // free pages. + SCOPED_TRACE("demand_pattern 5"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.long_interval = absl::Minutes(2)}, + true); + } -HugePageFiller: realized fragmentation: 0.8 MiB -HugePageFiller: minimum free pages: 110 (100 backed) -HugePageFiller: at peak demand: 208 pages (and 111 free, 10 unmapped) -HugePageFiller: at peak demand: 26 hps (14 regular, 10 donated, 1 partial, 1 released) -HugePageFiller: at peak hps: 208 pages (and 111 free, 10 unmapped) -HugePageFiller: at peak hps: 26 hps (14 regular, 10 donated, 1 partial, 1 released) + Advance(absl::Minutes(30)); -HugePageFiller: Since the start of the execution, 0 subreleases (0 pages) were skipped due to recent (0s) peaks. -HugePageFiller: 0.0000% of decisions confirmed correct, 0 pending (0.0000% of pages, 0 pending). -HugePageFiller: Subrelease stats last 10 min: total 0 pages subreleased, 0 hugepages broken -)")); + // This captures a corner case: If we hit another peak immediately after a + // subrelease decision (in the same time series epoch), do not count this as + // a correct subrelease decision. + { + SCOPED_TRACE("demand_pattern 6"); + demand_pattern(absl::Milliseconds(10), absl::Milliseconds(10), + absl::Milliseconds(10), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(1), + .long_interval = absl::Minutes(2)}, + false); } - // Test pbtxt output (full time series). + Advance(absl::Minutes(30)); + + // Ensure that the tracker is updated. + auto tiny = Allocate(Length(1)); + Delete(tiny); + + std::string buffer(1024 * 1024, '\0'); { - std::string buffer(1024 * 1024, '\0'); + PageHeapSpinLockHolder l; Printer printer(&*buffer.begin(), buffer.size()); - { - PbtxtRegion region(&printer, kTop, /*indent=*/0); - tracker_.PrintInPbtxt(®ion); - } - buffer.erase(printer.SpaceRequired()); - - EXPECT_THAT(buffer, StrEq(R"( - filler_skipped_subrelease { - skipped_subrelease_interval_ms: 0 - skipped_subrelease_pages: 0 - correctly_skipped_subrelease_pages: 0 - pending_skipped_subrelease_pages: 0 - skipped_subrelease_count: 0 - correctly_skipped_subrelease_count: 0 - pending_skipped_subrelease_count: 0 - } - filler_stats_timeseries { - window_ms: 37500 - epochs: 16 - min_free_pages_interval_ms: 300000 - min_free_pages: 110 - min_free_backed_pages: 100 - measurements { - epoch: 6 - timestamp_ms: 0 - min_free_pages: 11 - min_free_backed_pages: 1 - num_pages_subreleased: 0 - num_hugepages_broken: 0 - at_minimum_demand { - num_pages: 1 - regular_huge_pages: 5 - donated_huge_pages: 1 - partial_released_huge_pages: 1 - released_huge_pages: 0 - used_pages_in_subreleased_huge_pages: 1 - } - at_maximum_demand { - num_pages: 9 - regular_huge_pages: 5 - donated_huge_pages: 1 - partial_released_huge_pages: 1 - released_huge_pages: 1 - used_pages_in_subreleased_huge_pages: 1 - } - at_minimum_huge_pages { - num_pages: 5 - regular_huge_pages: 1 - donated_huge_pages: 1 - partial_released_huge_pages: 0 - released_huge_pages: 0 - used_pages_in_subreleased_huge_pages: 1 - } - at_maximum_huge_pages { - num_pages: 5 - regular_huge_pages: 9 - donated_huge_pages: 1 - partial_released_huge_pages: 0 - released_huge_pages: 1 - used_pages_in_subreleased_huge_pages: 1 - } - } - measurements { - epoch: 14 - timestamp_ms: 300000 - min_free_pages: 210 - min_free_backed_pages: 200 - num_pages_subreleased: 0 - num_hugepages_broken: 0 - at_minimum_demand { - num_pages: 100 - regular_huge_pages: 9 - donated_huge_pages: 5 - partial_released_huge_pages: 1 - released_huge_pages: 0 - used_pages_in_subreleased_huge_pages: 100 - } - at_maximum_demand { - num_pages: 108 - regular_huge_pages: 9 - donated_huge_pages: 5 - partial_released_huge_pages: 1 - released_huge_pages: 1 - used_pages_in_subreleased_huge_pages: 100 - } - at_minimum_huge_pages { - num_pages: 104 - regular_huge_pages: 5 - donated_huge_pages: 5 - partial_released_huge_pages: 0 - released_huge_pages: 0 - used_pages_in_subreleased_huge_pages: 100 - } - at_maximum_huge_pages { - num_pages: 104 - regular_huge_pages: 13 - donated_huge_pages: 5 - partial_released_huge_pages: 0 - released_huge_pages: 1 - used_pages_in_subreleased_huge_pages: 100 - } - } - measurements { - epoch: 15 - timestamp_ms: 337500 - min_free_pages: 110 - min_free_backed_pages: 100 - num_pages_subreleased: 0 - num_hugepages_broken: 0 - at_minimum_demand { - num_pages: 200 - regular_huge_pages: 14 - donated_huge_pages: 10 - partial_released_huge_pages: 1 - released_huge_pages: 0 - used_pages_in_subreleased_huge_pages: 200 - } - at_maximum_demand { - num_pages: 208 - regular_huge_pages: 14 - donated_huge_pages: 10 - partial_released_huge_pages: 1 - released_huge_pages: 1 - used_pages_in_subreleased_huge_pages: 200 - } - at_minimum_huge_pages { - num_pages: 204 - regular_huge_pages: 10 - donated_huge_pages: 10 - partial_released_huge_pages: 0 - released_huge_pages: 0 - used_pages_in_subreleased_huge_pages: 200 - } - at_maximum_huge_pages { - num_pages: 204 - regular_huge_pages: 18 - donated_huge_pages: 10 - partial_released_huge_pages: 0 - released_huge_pages: 1 - used_pages_in_subreleased_huge_pages: 200 - } - } + filler_.Print(printer, true); } + buffer.resize(strlen(buffer.c_str())); + + if (!dense_tracker_sorted_on_allocs_) { + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugePageFiller: Since the start of the execution, 3 subreleases (384 pages) were skipped due to the sum of short-term (60s) fluctuations and long-term (120s) trends. +HugePageFiller: 33.3333% of decisions confirmed correct, 0 pending (33.3333% of pages, 0 pending). )")); } } -TEST_F(FillerStatsTrackerTest, InvalidDurations) { - // These should not crash. - tracker_.min_free_pages(absl::InfiniteDuration()); - tracker_.min_free_pages(kWindow + absl::Seconds(1)); - tracker_.min_free_pages(-(kWindow + absl::Seconds(1))); - tracker_.min_free_pages(-absl::InfiniteDuration()); -} - -TEST_F(FillerStatsTrackerTest, ComputeRecentPeaks) { - GenerateDemandPoint(Length(3000), Length(1000)); - Advance(absl::Minutes(1.25)); - GenerateDemandPoint(Length(1500), Length(0)); - Advance(absl::Minutes(1)); - GenerateDemandPoint(Length(100), Length(2000)); - Advance(absl::Minutes(1)); - GenerateDemandPoint(Length(200), Length(3000)); - - GenerateDemandPoint(Length(200), Length(3000)); - FillerStatsTracker<>::FillerStats stats = - tracker_.GetRecentPeak(absl::Minutes(3)); - EXPECT_EQ(stats.num_pages, Length(1500)); - EXPECT_EQ(stats.free_pages, Length(0)); - - FillerStatsTracker<>::FillerStats stats2 = - tracker_.GetRecentPeak(absl::Minutes(5)); - EXPECT_EQ(stats2.num_pages, Length(3000)); - EXPECT_EQ(stats2.free_pages, Length(1000)); - - Advance(absl::Minutes(4)); - GenerateDemandPoint(Length(200), Length(3000)); - - FillerStatsTracker<>::FillerStats stats3 = - tracker_.GetRecentPeak(absl::Minutes(4)); - EXPECT_EQ(stats3.num_pages, Length(200)); - EXPECT_EQ(stats3.free_pages, Length(3000)); - - Advance(absl::Minutes(5)); - GenerateDemandPoint(Length(200), Length(3000)); - - FillerStatsTracker<>::FillerStats stats4 = - tracker_.GetRecentPeak(absl::Minutes(5)); - EXPECT_EQ(stats4.num_pages, Length(200)); - EXPECT_EQ(stats4.free_pages, Length(3000)); -} +TEST_P(FillerTest, SkipSubrelease) { + // This test is sensitive to the number of pages per hugepage, as we are + // printing raw stats. + if (kPagesPerHugePage != Length(256)) { + GTEST_SKIP(); + } + if (std::get<0>(GetParam()) == + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test for kSpansAllocated"; + } -TEST_F(FillerStatsTrackerTest, TrackCorrectSubreleaseDecisions) { - // First peak (large) - GenerateDemandPoint(Length(1000), Length(1000)); + // Firstly, this test generates a peak (long-term demand peak) and waits for + // time interval a. Then, it generates a higher peak plus a short-term + // fluctuation peak, and waits for time interval b. It then generates a trough + // in demand and tries to subrelease. Finally, it waits for time interval c to + // generate the highest peak for evaluating subrelease correctness. Skip + // subrelease selects those demand points using provided time intervals. + const auto demand_pattern = [&](absl::Duration a, absl::Duration b, + absl::Duration c, + SkipSubreleaseIntervals intervals, + bool expected_subrelease) { + const Length N = kPagesPerHugePage; + // First peak: min_demand 3/4N, max_demand 1N. + PAlloc peak1a = Allocate(3 * N / 4); + PAlloc peak1b = AllocateWithSpanAllocInfo(N / 4, peak1a.span_alloc_info); + Advance(a); + // Second peak: min_demand 0, max_demand 2N. + Delete(peak1a); + Delete(peak1b); - // Incorrect subrelease: Subrelease to 1000 - Advance(absl::Minutes(1)); - GenerateDemandPoint(Length(100), Length(1000)); - tracker_.ReportSkippedSubreleasePages(Length(900), Length(1000), - absl::Minutes(3)); + PAlloc half = Allocate(N / 2); + PAlloc tiny1 = AllocateWithSpanAllocInfo(N / 4, half.span_alloc_info); + PAlloc tiny2 = AllocateWithSpanAllocInfo(N / 4, half.span_alloc_info); - // Second peak (small) - Advance(absl::Minutes(1)); - GenerateDemandPoint(Length(500), Length(1000)); + // To force a peak, we allocate 3/4 and 1/4 of a huge page. This is + // necessary after we delete `half` below, as a half huge page for the + // peak would fill into the gap previously occupied by it. + PAlloc peak2a = Allocate(3 * N / 4); + PAlloc peak2b = AllocateWithSpanAllocInfo(N / 4, peak2a.span_alloc_info); + EXPECT_EQ(filler_.used_pages(), 2 * N); + Delete(peak2a); + Delete(peak2b); + Advance(b); + Delete(half); + EXPECT_EQ(filler_.free_pages(), Length(N / 2)); + // The number of released pages is limited to the number of free pages. + EXPECT_EQ(expected_subrelease ? N / 2 : Length(0), + ReleasePages(10 * N, intervals)); - EXPECT_EQ(tracker_.total_skipped().pages, Length(900)); - EXPECT_EQ(tracker_.total_skipped().count, 1); - EXPECT_EQ(tracker_.correctly_skipped().pages, Length(0)); - EXPECT_EQ(tracker_.correctly_skipped().count, 0); - EXPECT_EQ(tracker_.pending_skipped().pages, Length(900)); - EXPECT_EQ(tracker_.pending_skipped().count, 1); + Advance(c); + // Third peak: min_demand 1/2N, max_demand (2+1/2)N. + PAlloc peak3a = Allocate(3 * N / 4); + PAlloc peak3b = AllocateWithSpanAllocInfo(N / 4, peak3a.span_alloc_info); - // Correct subrelease: Subrelease to 500 - Advance(absl::Minutes(1)); - GenerateDemandPoint(Length(500), Length(100)); - tracker_.ReportSkippedSubreleasePages(Length(50), Length(550), - absl::Minutes(3)); - GenerateDemandPoint(Length(500), Length(50)); - tracker_.ReportSkippedSubreleasePages(Length(50), Length(500), - absl::Minutes(3)); - GenerateDemandPoint(Length(500), Length(0)); - - EXPECT_EQ(tracker_.total_skipped().pages, Length(1000)); - EXPECT_EQ(tracker_.total_skipped().count, 3); - EXPECT_EQ(tracker_.correctly_skipped().pages, Length(0)); - EXPECT_EQ(tracker_.correctly_skipped().count, 0); - EXPECT_EQ(tracker_.pending_skipped().pages, Length(1000)); - EXPECT_EQ(tracker_.pending_skipped().count, 3); - - // Third peak (large, too late for first peak) - Advance(absl::Minutes(1)); - GenerateDemandPoint(Length(1100), Length(1000)); + PAlloc peak4a = Allocate(3 * N / 4); + PAlloc peak4b = AllocateWithSpanAllocInfo(N / 4, peak4a.span_alloc_info); - Advance(absl::Minutes(5)); - GenerateDemandPoint(Length(1100), Length(1000)); + Delete(tiny1); + Delete(tiny2); + Delete(peak3a); + Delete(peak3b); + Delete(peak4a); + Delete(peak4b); - EXPECT_EQ(tracker_.total_skipped().pages, Length(1000)); - EXPECT_EQ(tracker_.total_skipped().count, 3); - EXPECT_EQ(tracker_.correctly_skipped().pages, Length(100)); - EXPECT_EQ(tracker_.correctly_skipped().count, 2); - EXPECT_EQ(tracker_.pending_skipped().pages, Length(0)); - EXPECT_EQ(tracker_.pending_skipped().count, 0); -} + EXPECT_EQ(filler_.used_pages(), Length(0)); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); + EXPECT_EQ(filler_.free_pages(), Length(0)); + EXPECT_EQ(expected_subrelease ? N / 2 : Length(0), ReleasePages(10 * N)); + }; -TEST_F(FillerStatsTrackerTest, SubreleaseCorrectnessWithChangingIntervals) { - // First peak (large) - GenerateDemandPoint(Length(1000), Length(1000)); + { + // Skip subrelease feature is disabled if all intervals are zero. + SCOPED_TRACE("demand_pattern 1"); + demand_pattern(absl::Minutes(1), absl::Minutes(1), absl::Minutes(4), + SkipSubreleaseIntervals{}, true); + } - Advance(absl::Minutes(1)); - GenerateDemandPoint(Length(100), Length(1000)); + Advance(absl::Minutes(30)); - tracker_.ReportSkippedSubreleasePages(Length(50), Length(1000), - absl::Minutes(4)); - Advance(absl::Minutes(1)); + { + // Uses short-term and long-term intervals for skipping subrelease. It + // incorrectly skips 128 pages. + SCOPED_TRACE("demand_pattern 2"); + demand_pattern(absl::Minutes(3), absl::Minutes(2), absl::Minutes(7), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(3), + .long_interval = absl::Minutes(6)}, + false); + } - // With two correctness intervals in the same epoch, take the maximum - tracker_.ReportSkippedSubreleasePages(Length(100), Length(1000), - absl::Minutes(1)); - tracker_.ReportSkippedSubreleasePages(Length(200), Length(1000), - absl::Minutes(7)); - - Advance(absl::Minutes(5)); - GenerateDemandPoint(Length(1100), Length(1000)); - Advance(absl::Minutes(10)); - GenerateDemandPoint(Length(1100), Length(1000)); - - EXPECT_EQ(tracker_.total_skipped().pages, Length(350)); - EXPECT_EQ(tracker_.total_skipped().count, 3); - EXPECT_EQ(tracker_.correctly_skipped().pages, Length(300)); - EXPECT_EQ(tracker_.correctly_skipped().count, 2); - EXPECT_EQ(tracker_.pending_skipped().pages, Length(0)); - EXPECT_EQ(tracker_.pending_skipped().count, 0); -} + Advance(absl::Minutes(30)); -std::vector FillerTest::GenerateInterestingAllocs() { - PAlloc a = Allocate(Length(1)); - EXPECT_EQ(ReleasePages(kMaxValidPages), kPagesPerHugePage - Length(1)); - Delete(a); - // Get the report on the released page - EXPECT_EQ(ReleasePages(kMaxValidPages), Length(1)); + { + // Uses short-term and long-term intervals for skipping subrelease, + // subreleasing all free pages. + SCOPED_TRACE("demand_pattern 3"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(1), + .long_interval = absl::Minutes(2)}, + true); + } + Advance(absl::Minutes(30)); - // Use a maximally-suboptimal pattern to get lots of hugepages into the - // filler. - std::vector result; - static_assert(kPagesPerHugePage > Length(7), - "Not enough pages per hugepage!"); - for (auto i = Length(0); i < Length(7); ++i) { - result.push_back(Allocate(kPagesPerHugePage - i - Length(1))); + { + // Uses only short-term interval for skipping subrelease. It correctly + // skips 128 pages. + SCOPED_TRACE("demand_pattern 4"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(3)}, + false); } - // Get two released hugepages. - EXPECT_EQ(ReleasePages(Length(7)), Length(7)); - EXPECT_EQ(ReleasePages(Length(6)), Length(6)); + Advance(absl::Minutes(30)); - // Fill some of the remaining pages with small allocations. - for (int i = 0; i < 9; ++i) { - result.push_back(Allocate(Length(1))); + { + // Uses only long-term interval for skipping subrelease, subreleased all + // free pages. + SCOPED_TRACE("demand_pattern 5"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.long_interval = absl::Minutes(2)}, + true); } - // Finally, donate one hugepage. - result.push_back(Allocate(Length(1), /*donated=*/true)); - return result; -} + Advance(absl::Minutes(30)); -// Test the output of Print(). This is something of a change-detector test, -// but that's not all bad in this case. -TEST_P(FillerTest, Print) { - if (kPagesPerHugePage != Length(256)) { - // The output is hardcoded on this assumption, and dynamically calculating - // it would be way too much of a pain. - return; + // This captures a corner case: If we hit another peak immediately after a + // subrelease decision (in the same time series epoch), do not count this as + // a correct subrelease decision. + { + SCOPED_TRACE("demand_pattern 6"); + demand_pattern(absl::Milliseconds(10), absl::Milliseconds(10), + absl::Milliseconds(10), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(1), + .long_interval = absl::Minutes(2)}, + false); } - auto allocs = GenerateInterestingAllocs(); + + Advance(absl::Minutes(30)); + + // Ensure that the tracker is updated. + auto tiny = Allocate(Length(1)); + Delete(tiny); std::string buffer(1024 * 1024, '\0'); { + PageHeapSpinLockHolder l; Printer printer(&*buffer.begin(), buffer.size()); - filler_.Print(&printer, /*everything=*/true); - buffer.erase(printer.SpaceRequired()); + filler_.Print(printer, true); } + buffer.resize(strlen(buffer.c_str())); - EXPECT_THAT( - buffer, - StrEq(R"(HugePageFiller: densely pack small requests into hugepages -HugePageFiller: 8 total, 3 full, 3 partial, 2 released (0 partially), 0 quarantined -HugePageFiller: 261 pages free in 8 hugepages, 0.1274 free -HugePageFiller: among non-fulls, 0.3398 free -HugePageFiller: 499 used pages in subreleased hugepages (0 of them in partially released) -HugePageFiller: 2 hugepages partially released, 0.0254 released -HugePageFiller: 0.7187 of used pages hugepageable -HugePageFiller: Since startup, 269 pages subreleased, 3 hugepages broken, (0 pages, 0 hugepages due to reaching tcmalloc limit) - -HugePageFiller: fullness histograms - -HugePageFiller: # of regular hps with a<= # of free pages (GetParam()) != + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test for kSpansAllocated"; + } + randomize_density_ = false; + SpanAllocInfo info = {kPagesPerHugePage.raw_num(), + AccessDensityPrediction::kDense}; + + // Firstly, this test generates a peak (long-term demand peak) and waits for + // time interval a. Then, it generates a higher peak plus a short-term + // fluctuation peak, and waits for time interval b. It then generates a trough + // in demand and tries to subrelease. Finally, it waits for time interval c to + // generate the highest peak for evaluating subrelease correctness. Skip + // subrelease selects those demand points using provided time intervals. + const auto demand_pattern = [&](absl::Duration a, absl::Duration b, + absl::Duration c, + SkipSubreleaseIntervals intervals, + bool expected_subrelease) { + const Length N = kPagesPerHugePage; + // First peak: min_demand 3/4N, max_demand 1N. + std::vector peak1a = + AllocateVectorWithSpanAllocInfo(3 * N / 4, info); + ASSERT_TRUE(!peak1a.empty()); + std::vector peak1b = + AllocateVectorWithSpanAllocInfo(N / 4, peak1a.front().span_alloc_info); + Advance(a); + // Second peak: min_demand 0, max_demand 2N. + DeleteVector(peak1a); + DeleteVector(peak1b); -HugePageFiller: time series over 5 min interval + std::vector half = AllocateVectorWithSpanAllocInfo(N / 2, info); + ASSERT_TRUE(!half.empty()); + std::vector tiny1 = + AllocateVectorWithSpanAllocInfo(N / 4, half.front().span_alloc_info); + std::vector tiny2 = + AllocateVectorWithSpanAllocInfo(N / 4, half.front().span_alloc_info); -HugePageFiller: realized fragmentation: 0.0 MiB -HugePageFiller: minimum free pages: 0 (0 backed) -HugePageFiller: at peak demand: 1774 pages (and 261 free, 13 unmapped) -HugePageFiller: at peak demand: 8 hps (5 regular, 1 donated, 0 partial, 2 released) -HugePageFiller: at peak hps: 1774 pages (and 261 free, 13 unmapped) -HugePageFiller: at peak hps: 8 hps (5 regular, 1 donated, 0 partial, 2 released) + // To force a peak, we allocate 3/4 and 1/4 of a huge page. This is + // necessary after we delete `half` below, as a half huge page for the + // peak would fill into the gap previously occupied by it. + std::vector peak2a = + AllocateVectorWithSpanAllocInfo(3 * N / 4, info); + ASSERT_TRUE(!peak2a.empty()); + std::vector peak2b = + AllocateVectorWithSpanAllocInfo(N / 4, peak2a.front().span_alloc_info); + EXPECT_EQ(filler_.used_pages(), 2 * N); + DeleteVector(peak2a); + DeleteVector(peak2b); + Advance(b); + DeleteVector(half); + EXPECT_EQ(filler_.free_pages(), Length(N / 2)); + // The number of released pages is limited to the number of free pages. + EXPECT_EQ(expected_subrelease ? N / 2 : Length(0), + ReleasePages(10 * N, intervals)); + + Advance(c); + // Third peak: min_demand 1/2N, max_demand (2+1/2)N. + std::vector peak3a = + AllocateVectorWithSpanAllocInfo(3 * N / 4, info); + ASSERT_TRUE(!peak3a.empty()); + std::vector peak3b = + AllocateVectorWithSpanAllocInfo(N / 4, peak3a.front().span_alloc_info); + + std::vector peak4a = + AllocateVectorWithSpanAllocInfo(3 * N / 4, info); + ASSERT_TRUE(!peak4a.empty()); + std::vector peak4b = + AllocateVectorWithSpanAllocInfo(N / 4, peak4a.front().span_alloc_info); + + DeleteVector(tiny1); + DeleteVector(tiny2); + DeleteVector(peak3a); + DeleteVector(peak3b); + DeleteVector(peak4a); + DeleteVector(peak4b); + + EXPECT_EQ(filler_.used_pages(), Length(0)); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); + EXPECT_EQ(filler_.free_pages(), Length(0)); + EXPECT_EQ(Length(0), ReleasePages(10 * N)); + }; + + { + // Skip subrelease feature is disabled if all intervals are zero. + SCOPED_TRACE("demand_pattern 1"); + demand_pattern(absl::Minutes(1), absl::Minutes(1), absl::Minutes(4), + SkipSubreleaseIntervals{}, true); + } + + Advance(absl::Minutes(30)); + + { + // Uses short-term and long-term intervals for skipping subrelease. It + // incorrectly skips 128 pages. + SCOPED_TRACE("demand_pattern 2"); + demand_pattern(absl::Minutes(3), absl::Minutes(2), absl::Minutes(7), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(3), + .long_interval = absl::Minutes(6)}, + false); + } + + Advance(absl::Minutes(30)); + + { + // Uses short-term and long-term intervals for skipping subrelease, + // subreleasing all free pages. + SCOPED_TRACE("demand_pattern 3"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(1), + .long_interval = absl::Minutes(2)}, + true); + } + Advance(absl::Minutes(30)); + + { + // Uses only short-term interval for skipping subrelease. It correctly + // skips 128 pages. + SCOPED_TRACE("demand_pattern 4"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(3)}, + false); + } + + Advance(absl::Minutes(30)); + + { + // Uses only long-term interval for skipping subrelease, subreleased all + // free pages. + SCOPED_TRACE("demand_pattern 5"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.long_interval = absl::Minutes(2)}, + true); + } + + Advance(absl::Minutes(30)); + + // Repeats the "demand_pattern 9" test using short-term and long-term + // intervals, to show that subrelease decisions are evaluated independently. + { + SCOPED_TRACE("demand_pattern 6"); + demand_pattern(absl::Milliseconds(10), absl::Milliseconds(10), + absl::Milliseconds(10), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(1), + .long_interval = absl::Minutes(2)}, + false); + } + + Advance(absl::Minutes(30)); + + // Ensure that the tracker is updated. + auto tiny = Allocate(Length(1)); + Delete(tiny); + + std::string buffer(1024 * 1024, '\0'); + { + PageHeapSpinLockHolder l; + Printer printer(&*buffer.begin(), buffer.size()); + filler_.Print(printer, true); + } + buffer.resize(strlen(buffer.c_str())); -HugePageFiller: Since the start of the execution, 0 subreleases (0 pages) were skipped due to recent (0s) peaks. + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugePageFiller: Since the start of the execution, 4 subreleases (511 pages) were skipped due to the sum of short-term (60s) fluctuations and long-term (120s) trends. HugePageFiller: 0.0000% of decisions confirmed correct, 0 pending (0.0000% of pages, 0 pending). -HugePageFiller: Subrelease stats last 10 min: total 269 pages subreleased, 3 hugepages broken )")); - for (const auto& alloc : allocs) { - Delete(alloc); - } } -// Test the output of PrintInPbtxt(). This is something of a change-detector -// test, but that's not all bad in this case. -TEST_P(FillerTest, PrintInPbtxt) { +TEST_P(FillerTest, LifetimeTelemetryTest) { + // This test is sensitive to the number of pages per hugepage, as we are + // printing raw stats. if (kPagesPerHugePage != Length(256)) { - // The output is hardcoded on this assumption, and dynamically calculating - // it would be way too much of a pain. - return; + GTEST_SKIP(); } - auto allocs = GenerateInterestingAllocs(); + + const Length N = kPagesPerHugePage; + SpanAllocInfo info_sparsely_accessed = {1, AccessDensityPrediction::kSparse}; + PAlloc small_alloc = AllocateWithSpanAllocInfo(N / 4, info_sparsely_accessed); + PAlloc large_alloc = + AllocateWithSpanAllocInfo(3 * N / 4, info_sparsely_accessed); std::string buffer(1024 * 1024, '\0'); - Printer printer(&*buffer.begin(), buffer.size()); { - PbtxtRegion region(&printer, kTop, /*indent=*/0); - filler_.PrintInPbtxt(®ion); - } - buffer.erase(printer.SpaceRequired()); - - EXPECT_THAT(buffer, StrEq(R"( - filler_full_huge_pages: 3 - filler_partial_huge_pages: 3 - filler_released_huge_pages: 2 - filler_partially_released_huge_pages: 0 - filler_free_pages: 261 - filler_used_pages_in_subreleased: 499 - filler_used_pages_in_partial_released: 0 - filler_unmapped_bytes: 0 - filler_hugepageable_used_bytes: 10444800 - filler_num_pages_subreleased: 269 - filler_num_hugepages_broken: 3 - filler_num_pages_subreleased_due_to_limit: 0 - filler_num_hugepages_broken_due_to_limit: 0 - filler_tracker { - type: REGULAR - free_pages_histogram { - lower_bound: 0 - upper_bound: 0 - value: 3 - } - free_pages_histogram { - lower_bound: 1 - upper_bound: 1 - value: 1 - } - free_pages_histogram { - lower_bound: 2 - upper_bound: 2 - value: 0 - } - free_pages_histogram { - lower_bound: 3 - upper_bound: 3 - value: 0 - } - free_pages_histogram { - lower_bound: 4 - upper_bound: 15 - value: 1 - } - free_pages_histogram { - lower_bound: 16 - upper_bound: 31 - value: 0 - } - free_pages_histogram { - lower_bound: 32 - upper_bound: 47 - value: 0 - } - free_pages_histogram { - lower_bound: 48 - upper_bound: 63 - value: 0 - } - free_pages_histogram { - lower_bound: 64 - upper_bound: 79 - value: 0 - } - free_pages_histogram { - lower_bound: 80 - upper_bound: 95 - value: 0 - } - free_pages_histogram { - lower_bound: 96 - upper_bound: 111 - value: 0 - } - free_pages_histogram { - lower_bound: 112 - upper_bound: 127 - value: 0 - } - free_pages_histogram { - lower_bound: 128 - upper_bound: 143 - value: 0 - } - free_pages_histogram { - lower_bound: 144 - upper_bound: 159 - value: 0 - } - free_pages_histogram { - lower_bound: 160 - upper_bound: 175 - value: 0 - } - free_pages_histogram { - lower_bound: 176 - upper_bound: 191 - value: 0 - } - free_pages_histogram { - lower_bound: 192 - upper_bound: 207 - value: 0 - } - free_pages_histogram { - lower_bound: 208 - upper_bound: 223 - value: 0 - } - free_pages_histogram { - lower_bound: 224 - upper_bound: 239 - value: 0 - } - free_pages_histogram { - lower_bound: 240 - upper_bound: 251 - value: 0 - } - free_pages_histogram { - lower_bound: 252 - upper_bound: 252 - value: 0 - } - free_pages_histogram { - lower_bound: 253 - upper_bound: 253 - value: 0 - } - free_pages_histogram { - lower_bound: 254 - upper_bound: 254 - value: 0 - } - free_pages_histogram { - lower_bound: 255 - upper_bound: 255 - value: 0 - } - longest_free_range_histogram { - lower_bound: 0 - upper_bound: 0 - value: 3 - } - longest_free_range_histogram { - lower_bound: 1 - upper_bound: 1 - value: 1 - } - longest_free_range_histogram { - lower_bound: 2 - upper_bound: 2 - value: 0 - } - longest_free_range_histogram { - lower_bound: 3 - upper_bound: 3 - value: 0 - } - longest_free_range_histogram { - lower_bound: 4 - upper_bound: 15 - value: 1 - } - longest_free_range_histogram { - lower_bound: 16 - upper_bound: 31 - value: 0 - } - longest_free_range_histogram { - lower_bound: 32 - upper_bound: 47 - value: 0 - } - longest_free_range_histogram { - lower_bound: 48 - upper_bound: 63 - value: 0 - } - longest_free_range_histogram { - lower_bound: 64 - upper_bound: 79 - value: 0 - } - longest_free_range_histogram { - lower_bound: 80 - upper_bound: 95 - value: 0 - } - longest_free_range_histogram { - lower_bound: 96 - upper_bound: 111 - value: 0 - } - longest_free_range_histogram { - lower_bound: 112 - upper_bound: 127 - value: 0 - } - longest_free_range_histogram { - lower_bound: 128 - upper_bound: 143 - value: 0 - } - longest_free_range_histogram { - lower_bound: 144 - upper_bound: 159 - value: 0 - } - longest_free_range_histogram { - lower_bound: 160 - upper_bound: 175 - value: 0 - } - longest_free_range_histogram { - lower_bound: 176 - upper_bound: 191 - value: 0 - } - longest_free_range_histogram { - lower_bound: 192 - upper_bound: 207 - value: 0 - } - longest_free_range_histogram { - lower_bound: 208 - upper_bound: 223 - value: 0 - } - longest_free_range_histogram { - lower_bound: 224 - upper_bound: 239 - value: 0 - } - longest_free_range_histogram { - lower_bound: 240 - upper_bound: 251 - value: 0 - } - longest_free_range_histogram { - lower_bound: 252 - upper_bound: 252 - value: 0 - } - longest_free_range_histogram { - lower_bound: 253 - upper_bound: 253 - value: 0 - } - longest_free_range_histogram { - lower_bound: 254 - upper_bound: 254 - value: 0 - } - longest_free_range_histogram { - lower_bound: 255 - upper_bound: 255 - value: 0 - } - allocations_histogram { - lower_bound: 1 - upper_bound: 1 - value: 1 - } - allocations_histogram { - lower_bound: 2 - upper_bound: 2 - value: 1 - } - allocations_histogram { - lower_bound: 3 - upper_bound: 3 - value: 1 - } - allocations_histogram { - lower_bound: 4 - upper_bound: 4 - value: 2 - } - allocations_histogram { - lower_bound: 5 - upper_bound: 16 - value: 0 - } - allocations_histogram { - lower_bound: 17 - upper_bound: 32 - value: 0 - } - allocations_histogram { - lower_bound: 33 - upper_bound: 48 - value: 0 - } - allocations_histogram { - lower_bound: 49 - upper_bound: 64 - value: 0 - } - allocations_histogram { - lower_bound: 65 - upper_bound: 80 - value: 0 - } - allocations_histogram { - lower_bound: 81 - upper_bound: 96 - value: 0 - } - allocations_histogram { - lower_bound: 97 - upper_bound: 112 - value: 0 - } - allocations_histogram { - lower_bound: 113 - upper_bound: 128 - value: 0 - } - allocations_histogram { - lower_bound: 129 - upper_bound: 144 - value: 0 - } - allocations_histogram { - lower_bound: 145 - upper_bound: 160 - value: 0 - } - allocations_histogram { - lower_bound: 161 - upper_bound: 176 - value: 0 - } - allocations_histogram { - lower_bound: 177 - upper_bound: 192 - value: 0 - } - allocations_histogram { - lower_bound: 193 - upper_bound: 208 - value: 0 - } - allocations_histogram { - lower_bound: 209 - upper_bound: 224 - value: 0 - } - allocations_histogram { - lower_bound: 225 - upper_bound: 240 - value: 0 - } - allocations_histogram { - lower_bound: 241 - upper_bound: 252 - value: 0 - } - allocations_histogram { - lower_bound: 253 - upper_bound: 253 - value: 0 - } - allocations_histogram { - lower_bound: 254 - upper_bound: 254 - value: 0 - } - allocations_histogram { - lower_bound: 255 - upper_bound: 255 - value: 0 - } - allocations_histogram { - lower_bound: 256 - upper_bound: 256 - value: 0 - } + PageHeapSpinLockHolder l; + Printer printer(&*buffer.begin(), buffer.size()); + filler_.Print(printer, true); } - filler_tracker { - type: DONATED - free_pages_histogram { - lower_bound: 0 - upper_bound: 0 - value: 0 - } - free_pages_histogram { - lower_bound: 1 - upper_bound: 1 - value: 0 - } - free_pages_histogram { - lower_bound: 2 - upper_bound: 2 - value: 0 - } - free_pages_histogram { - lower_bound: 3 - upper_bound: 3 - value: 0 - } - free_pages_histogram { - lower_bound: 4 - upper_bound: 15 - value: 0 - } - free_pages_histogram { - lower_bound: 16 - upper_bound: 31 - value: 0 - } - free_pages_histogram { - lower_bound: 32 - upper_bound: 47 - value: 0 - } - free_pages_histogram { - lower_bound: 48 - upper_bound: 63 - value: 0 - } - free_pages_histogram { - lower_bound: 64 - upper_bound: 79 - value: 0 - } - free_pages_histogram { - lower_bound: 80 - upper_bound: 95 - value: 0 - } - free_pages_histogram { - lower_bound: 96 - upper_bound: 111 - value: 0 - } - free_pages_histogram { - lower_bound: 112 - upper_bound: 127 - value: 0 - } - free_pages_histogram { - lower_bound: 128 - upper_bound: 143 - value: 0 - } - free_pages_histogram { - lower_bound: 144 - upper_bound: 159 - value: 0 - } - free_pages_histogram { - lower_bound: 160 - upper_bound: 175 - value: 0 - } - free_pages_histogram { - lower_bound: 176 - upper_bound: 191 - value: 0 - } - free_pages_histogram { - lower_bound: 192 - upper_bound: 207 - value: 0 - } - free_pages_histogram { - lower_bound: 208 - upper_bound: 223 - value: 0 - } - free_pages_histogram { - lower_bound: 224 - upper_bound: 239 - value: 0 - } - free_pages_histogram { - lower_bound: 240 - upper_bound: 251 - value: 0 - } - free_pages_histogram { - lower_bound: 252 - upper_bound: 252 - value: 0 - } - free_pages_histogram { - lower_bound: 253 - upper_bound: 253 - value: 0 - } - free_pages_histogram { - lower_bound: 254 - upper_bound: 254 - value: 0 - } - free_pages_histogram { - lower_bound: 255 - upper_bound: 255 - value: 1 - } - longest_free_range_histogram { - lower_bound: 0 - upper_bound: 0 - value: 0 - } - longest_free_range_histogram { - lower_bound: 1 - upper_bound: 1 - value: 0 - } - longest_free_range_histogram { - lower_bound: 2 - upper_bound: 2 - value: 0 - } - longest_free_range_histogram { - lower_bound: 3 - upper_bound: 3 - value: 0 - } - longest_free_range_histogram { - lower_bound: 4 - upper_bound: 15 - value: 0 - } - longest_free_range_histogram { - lower_bound: 16 - upper_bound: 31 - value: 0 - } - longest_free_range_histogram { - lower_bound: 32 - upper_bound: 47 - value: 0 - } - longest_free_range_histogram { - lower_bound: 48 - upper_bound: 63 - value: 0 - } - longest_free_range_histogram { - lower_bound: 64 - upper_bound: 79 - value: 0 - } - longest_free_range_histogram { - lower_bound: 80 - upper_bound: 95 - value: 0 - } - longest_free_range_histogram { - lower_bound: 96 - upper_bound: 111 - value: 0 - } - longest_free_range_histogram { - lower_bound: 112 - upper_bound: 127 - value: 0 - } - longest_free_range_histogram { - lower_bound: 128 - upper_bound: 143 - value: 0 - } - longest_free_range_histogram { - lower_bound: 144 - upper_bound: 159 - value: 0 - } - longest_free_range_histogram { - lower_bound: 160 - upper_bound: 175 - value: 0 - } - longest_free_range_histogram { - lower_bound: 176 - upper_bound: 191 - value: 0 - } - longest_free_range_histogram { - lower_bound: 192 - upper_bound: 207 - value: 0 - } - longest_free_range_histogram { - lower_bound: 208 - upper_bound: 223 - value: 0 - } - longest_free_range_histogram { - lower_bound: 224 - upper_bound: 239 - value: 0 - } - longest_free_range_histogram { - lower_bound: 240 - upper_bound: 251 - value: 0 - } - longest_free_range_histogram { - lower_bound: 252 - upper_bound: 252 - value: 0 - } - longest_free_range_histogram { - lower_bound: 253 - upper_bound: 253 - value: 0 - } - longest_free_range_histogram { - lower_bound: 254 - upper_bound: 254 - value: 0 - } - longest_free_range_histogram { - lower_bound: 255 - upper_bound: 255 - value: 1 - } - allocations_histogram { - lower_bound: 1 - upper_bound: 1 - value: 1 - } - allocations_histogram { - lower_bound: 2 - upper_bound: 2 - value: 0 - } - allocations_histogram { - lower_bound: 3 - upper_bound: 3 - value: 0 - } - allocations_histogram { - lower_bound: 4 - upper_bound: 4 - value: 0 - } - allocations_histogram { - lower_bound: 5 - upper_bound: 16 - value: 0 - } - allocations_histogram { - lower_bound: 17 - upper_bound: 32 - value: 0 - } - allocations_histogram { - lower_bound: 33 - upper_bound: 48 - value: 0 - } - allocations_histogram { - lower_bound: 49 - upper_bound: 64 - value: 0 - } - allocations_histogram { - lower_bound: 65 - upper_bound: 80 - value: 0 - } - allocations_histogram { - lower_bound: 81 - upper_bound: 96 - value: 0 - } - allocations_histogram { - lower_bound: 97 - upper_bound: 112 - value: 0 - } - allocations_histogram { - lower_bound: 113 - upper_bound: 128 - value: 0 - } - allocations_histogram { - lower_bound: 129 - upper_bound: 144 - value: 0 - } - allocations_histogram { - lower_bound: 145 - upper_bound: 160 - value: 0 - } - allocations_histogram { - lower_bound: 161 - upper_bound: 176 - value: 0 - } - allocations_histogram { - lower_bound: 177 - upper_bound: 192 - value: 0 - } - allocations_histogram { - lower_bound: 193 - upper_bound: 208 - value: 0 - } - allocations_histogram { - lower_bound: 209 - upper_bound: 224 - value: 0 - } - allocations_histogram { - lower_bound: 225 - upper_bound: 240 - value: 0 - } - allocations_histogram { - lower_bound: 241 - upper_bound: 252 - value: 0 - } - allocations_histogram { - lower_bound: 253 - upper_bound: 253 - value: 0 - } - allocations_histogram { - lower_bound: 254 - upper_bound: 254 - value: 0 - } - allocations_histogram { - lower_bound: 255 - upper_bound: 255 - value: 0 - } - allocations_histogram { - lower_bound: 256 - upper_bound: 256 - value: 0 - } + buffer.resize(strlen(buffer.c_str())); + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugePageFiller: # of sparsely-accessed regular hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 1 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of densely-accessed regular hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of donated hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of sparsely-accessed partial released hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of densely-accessed partial released hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of sparsely-accessed released hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of densely-accessed released hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of hps with >= 224 free pages, with different lifetimes. +HugePageFiller: # of sparsely-accessed regular hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of densely-accessed regular hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of donated hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of sparsely-accessed partial released hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of densely-accessed partial released hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of sparsely-accessed released hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of densely-accessed released hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of hps with lifetime >= 100000 ms. +HugePageFiller: # of sparsely-accessed regular hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 0 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 + +HugePageFiller: # of densely-accessed regular hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 0 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 + +HugePageFiller: # of donated hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 0 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 + +HugePageFiller: # of sparsely-accessed partial released hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 0 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 + +HugePageFiller: # of densely-accessed partial released hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 0 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 + +HugePageFiller: # of sparsely-accessed released hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 0 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 + +HugePageFiller: # of densely-accessed released hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 0 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 +)")); + + Advance(absl::Seconds(101)); + { + PageHeapSpinLockHolder l; + Printer printer(&*buffer.begin(), buffer.size()); + filler_.Print(printer, true); } - filler_tracker { - type: PARTIAL - free_pages_histogram { - lower_bound: 0 - upper_bound: 0 - value: 0 - } - free_pages_histogram { - lower_bound: 1 - upper_bound: 1 - value: 0 - } - free_pages_histogram { - lower_bound: 2 - upper_bound: 2 - value: 0 - } - free_pages_histogram { - lower_bound: 3 - upper_bound: 3 - value: 0 - } - free_pages_histogram { - lower_bound: 4 - upper_bound: 15 - value: 0 - } - free_pages_histogram { - lower_bound: 16 - upper_bound: 31 - value: 0 - } - free_pages_histogram { - lower_bound: 32 - upper_bound: 47 - value: 0 - } - free_pages_histogram { - lower_bound: 48 - upper_bound: 63 - value: 0 - } - free_pages_histogram { - lower_bound: 64 - upper_bound: 79 - value: 0 - } - free_pages_histogram { - lower_bound: 80 - upper_bound: 95 - value: 0 - } - free_pages_histogram { - lower_bound: 96 - upper_bound: 111 - value: 0 - } - free_pages_histogram { - lower_bound: 112 - upper_bound: 127 - value: 0 - } - free_pages_histogram { - lower_bound: 128 - upper_bound: 143 - value: 0 - } - free_pages_histogram { - lower_bound: 144 - upper_bound: 159 - value: 0 - } - free_pages_histogram { - lower_bound: 160 - upper_bound: 175 - value: 0 - } - free_pages_histogram { - lower_bound: 176 - upper_bound: 191 - value: 0 - } - free_pages_histogram { - lower_bound: 192 - upper_bound: 207 - value: 0 - } - free_pages_histogram { - lower_bound: 208 - upper_bound: 223 - value: 0 - } - free_pages_histogram { - lower_bound: 224 - upper_bound: 239 - value: 0 - } - free_pages_histogram { - lower_bound: 240 - upper_bound: 251 - value: 0 - } - free_pages_histogram { - lower_bound: 252 - upper_bound: 252 - value: 0 - } - free_pages_histogram { - lower_bound: 253 - upper_bound: 253 - value: 0 - } - free_pages_histogram { - lower_bound: 254 - upper_bound: 254 - value: 0 - } - free_pages_histogram { - lower_bound: 255 - upper_bound: 255 - value: 0 - } - longest_free_range_histogram { - lower_bound: 0 - upper_bound: 0 - value: 0 - } - longest_free_range_histogram { - lower_bound: 1 - upper_bound: 1 - value: 0 - } - longest_free_range_histogram { - lower_bound: 2 - upper_bound: 2 - value: 0 - } - longest_free_range_histogram { - lower_bound: 3 - upper_bound: 3 - value: 0 - } - longest_free_range_histogram { - lower_bound: 4 - upper_bound: 15 - value: 0 - } - longest_free_range_histogram { - lower_bound: 16 - upper_bound: 31 - value: 0 - } - longest_free_range_histogram { - lower_bound: 32 - upper_bound: 47 - value: 0 - } - longest_free_range_histogram { - lower_bound: 48 - upper_bound: 63 - value: 0 - } - longest_free_range_histogram { - lower_bound: 64 - upper_bound: 79 - value: 0 - } - longest_free_range_histogram { - lower_bound: 80 - upper_bound: 95 - value: 0 - } - longest_free_range_histogram { - lower_bound: 96 - upper_bound: 111 - value: 0 - } - longest_free_range_histogram { - lower_bound: 112 - upper_bound: 127 - value: 0 - } - longest_free_range_histogram { - lower_bound: 128 - upper_bound: 143 - value: 0 - } - longest_free_range_histogram { - lower_bound: 144 - upper_bound: 159 - value: 0 - } - longest_free_range_histogram { - lower_bound: 160 - upper_bound: 175 - value: 0 - } - longest_free_range_histogram { - lower_bound: 176 - upper_bound: 191 - value: 0 - } - longest_free_range_histogram { - lower_bound: 192 - upper_bound: 207 - value: 0 - } - longest_free_range_histogram { - lower_bound: 208 - upper_bound: 223 - value: 0 - } - longest_free_range_histogram { - lower_bound: 224 - upper_bound: 239 - value: 0 - } - longest_free_range_histogram { - lower_bound: 240 - upper_bound: 251 - value: 0 - } - longest_free_range_histogram { - lower_bound: 252 - upper_bound: 252 - value: 0 - } - longest_free_range_histogram { - lower_bound: 253 - upper_bound: 253 - value: 0 - } - longest_free_range_histogram { - lower_bound: 254 - upper_bound: 254 - value: 0 - } - longest_free_range_histogram { - lower_bound: 255 - upper_bound: 255 - value: 0 - } - allocations_histogram { - lower_bound: 1 - upper_bound: 1 - value: 0 - } - allocations_histogram { - lower_bound: 2 - upper_bound: 2 - value: 0 - } - allocations_histogram { - lower_bound: 3 - upper_bound: 3 - value: 0 - } - allocations_histogram { - lower_bound: 4 - upper_bound: 4 - value: 0 - } - allocations_histogram { - lower_bound: 5 - upper_bound: 16 - value: 0 - } - allocations_histogram { - lower_bound: 17 - upper_bound: 32 - value: 0 - } - allocations_histogram { - lower_bound: 33 - upper_bound: 48 - value: 0 - } - allocations_histogram { - lower_bound: 49 - upper_bound: 64 - value: 0 - } - allocations_histogram { - lower_bound: 65 - upper_bound: 80 - value: 0 - } - allocations_histogram { - lower_bound: 81 - upper_bound: 96 - value: 0 - } - allocations_histogram { - lower_bound: 97 - upper_bound: 112 - value: 0 - } - allocations_histogram { - lower_bound: 113 - upper_bound: 128 - value: 0 - } - allocations_histogram { - lower_bound: 129 - upper_bound: 144 - value: 0 - } - allocations_histogram { - lower_bound: 145 - upper_bound: 160 - value: 0 - } - allocations_histogram { - lower_bound: 161 - upper_bound: 176 - value: 0 - } - allocations_histogram { - lower_bound: 177 - upper_bound: 192 - value: 0 - } - allocations_histogram { - lower_bound: 193 - upper_bound: 208 - value: 0 - } - allocations_histogram { - lower_bound: 209 - upper_bound: 224 - value: 0 - } - allocations_histogram { - lower_bound: 225 - upper_bound: 240 - value: 0 - } - allocations_histogram { - lower_bound: 241 - upper_bound: 252 - value: 0 - } - allocations_histogram { - lower_bound: 253 - upper_bound: 253 - value: 0 - } - allocations_histogram { - lower_bound: 254 - upper_bound: 254 - value: 0 - } - allocations_histogram { - lower_bound: 255 - upper_bound: 255 - value: 0 - } - allocations_histogram { - lower_bound: 256 - upper_bound: 256 - value: 0 - } + + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugePageFiller: # of sparsely-accessed regular hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 1 < 1000000 ms <= 0 +)")); + + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugePageFiller: # of hps with >= 224 free pages, with different lifetimes. +HugePageFiller: # of sparsely-accessed regular hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 +)")); + + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugePageFiller: # of hps with lifetime >= 100000 ms. +HugePageFiller: # of sparsely-accessed regular hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 1 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 +)")); + + Delete(small_alloc); + Delete(large_alloc); +} + +TEST_P(FillerTest, SkipSubReleaseDemandPeak) { + // Tests that HugePageFiller can cap filler's short-term long-term + // skip-subrelease mechanism using the demand measured by subrelease + // intervals. + + const Length N = kPagesPerHugePage; + + // We trigger the demand such that short-term + long-term demand exceeds the + // peak demand. We should be able to sub-release memory from the HugeFiller + // up to the peak demand measured in the previous intervals. + + // min_demand = 0.75N, max_demand = 2.5N + std::vector peak1a = AllocateVector(3 * N / 4); + ASSERT_TRUE(!peak1a.empty()); + std::vector peak1b = AllocateVectorWithSpanAllocInfo( + 3 * N / 4, peak1a.front().span_alloc_info); + std::vector half1a = + AllocateVectorWithSpanAllocInfo(N / 2, peak1a.front().span_alloc_info); + std::vector half1b = + AllocateVectorWithSpanAllocInfo(N / 2, peak1a.front().span_alloc_info); + EXPECT_EQ(filler_.used_pages(), 2 * N + N / 2); + Advance(absl::Minutes(1)); + + // min_demand = 2N, max_demand = 2.5N + DeleteVector(half1b); + std::vector half1c = + AllocateVectorWithSpanAllocInfo(N / 2, peak1a.front().span_alloc_info); + EXPECT_EQ(filler_.used_pages(), 2 * N + N / 2); + EXPECT_EQ(filler_.free_pages(), N / 2); + Advance(absl::Minutes(1)); + + // At this point, short-term fluctuation, which is the maximum of the + // difference between max_demand and min_demand in the previous two + // intervals, is equal to 1.75N. Long-term demand, which is the maximum of + // min_demand in the previous two intervals, is 2N. As peak demand of 2.5N is + // lower than 3.75N, we should be able to subrelease 0.5N pages. + EXPECT_EQ(Length(N / 2), + ReleasePages(10 * N, SkipSubreleaseIntervals{ + .short_interval = absl::Minutes(2), + .long_interval = absl::Minutes(2)})); + DeleteVector(peak1a); + DeleteVector(peak1b); + DeleteVector(half1a); + DeleteVector(half1c); +} + +TEST_P(FillerTest, ReportSkipSubreleases) { + // Tests that HugePageFiller reports skipped subreleases using demand + // requirement that is the smaller of two (recent peak and its + // current capacity). This fix makes evaluating skip subrelease more accurate, + // which is useful for cross-comparing performance of different + // skip-subrelease intervals. + + // This test is sensitive to the number of pages per hugepage, as we are + // printing raw stats. + if (kPagesPerHugePage != Length(256)) { + GTEST_SKIP(); } - filler_tracker { - type: RELEASED - free_pages_histogram { - lower_bound: 0 - upper_bound: 0 - value: 0 - } - free_pages_histogram { - lower_bound: 1 - upper_bound: 1 - value: 0 - } - free_pages_histogram { - lower_bound: 2 - upper_bound: 2 - value: 0 - } - free_pages_histogram { - lower_bound: 3 - upper_bound: 3 - value: 0 - } - free_pages_histogram { - lower_bound: 4 - upper_bound: 15 - value: 2 - } - free_pages_histogram { - lower_bound: 16 - upper_bound: 31 - value: 0 - } - free_pages_histogram { - lower_bound: 32 - upper_bound: 47 - value: 0 - } - free_pages_histogram { - lower_bound: 48 - upper_bound: 63 - value: 0 - } - free_pages_histogram { - lower_bound: 64 - upper_bound: 79 - value: 0 - } - free_pages_histogram { - lower_bound: 80 - upper_bound: 95 - value: 0 - } - free_pages_histogram { - lower_bound: 96 - upper_bound: 111 - value: 0 - } - free_pages_histogram { - lower_bound: 112 - upper_bound: 127 - value: 0 - } - free_pages_histogram { - lower_bound: 128 - upper_bound: 143 - value: 0 - } - free_pages_histogram { - lower_bound: 144 - upper_bound: 159 - value: 0 - } - free_pages_histogram { - lower_bound: 160 - upper_bound: 175 - value: 0 - } - free_pages_histogram { - lower_bound: 176 - upper_bound: 191 - value: 0 - } - free_pages_histogram { - lower_bound: 192 - upper_bound: 207 - value: 0 - } - free_pages_histogram { - lower_bound: 208 - upper_bound: 223 - value: 0 - } - free_pages_histogram { - lower_bound: 224 - upper_bound: 239 - value: 0 - } - free_pages_histogram { - lower_bound: 240 - upper_bound: 251 - value: 0 - } - free_pages_histogram { - lower_bound: 252 - upper_bound: 252 - value: 0 - } - free_pages_histogram { - lower_bound: 253 - upper_bound: 253 - value: 0 - } - free_pages_histogram { - lower_bound: 254 - upper_bound: 254 - value: 0 - } - free_pages_histogram { - lower_bound: 255 - upper_bound: 255 - value: 0 - } - longest_free_range_histogram { - lower_bound: 0 - upper_bound: 0 - value: 0 - } - longest_free_range_histogram { - lower_bound: 1 - upper_bound: 1 - value: 0 - } - longest_free_range_histogram { - lower_bound: 2 - upper_bound: 2 - value: 0 - } - longest_free_range_histogram { - lower_bound: 3 - upper_bound: 3 - value: 0 - } - longest_free_range_histogram { - lower_bound: 4 - upper_bound: 15 - value: 2 - } - longest_free_range_histogram { - lower_bound: 16 - upper_bound: 31 - value: 0 - } - longest_free_range_histogram { - lower_bound: 32 - upper_bound: 47 - value: 0 - } - longest_free_range_histogram { - lower_bound: 48 - upper_bound: 63 - value: 0 - } - longest_free_range_histogram { - lower_bound: 64 - upper_bound: 79 - value: 0 - } - longest_free_range_histogram { - lower_bound: 80 - upper_bound: 95 - value: 0 - } - longest_free_range_histogram { - lower_bound: 96 - upper_bound: 111 - value: 0 - } - longest_free_range_histogram { - lower_bound: 112 - upper_bound: 127 - value: 0 - } - longest_free_range_histogram { - lower_bound: 128 - upper_bound: 143 - value: 0 - } - longest_free_range_histogram { - lower_bound: 144 - upper_bound: 159 - value: 0 - } - longest_free_range_histogram { - lower_bound: 160 - upper_bound: 175 - value: 0 - } - longest_free_range_histogram { - lower_bound: 176 - upper_bound: 191 - value: 0 - } - longest_free_range_histogram { - lower_bound: 192 - upper_bound: 207 - value: 0 - } - longest_free_range_histogram { - lower_bound: 208 - upper_bound: 223 - value: 0 - } - longest_free_range_histogram { - lower_bound: 224 - upper_bound: 239 - value: 0 - } - longest_free_range_histogram { - lower_bound: 240 - upper_bound: 251 - value: 0 - } - longest_free_range_histogram { - lower_bound: 252 - upper_bound: 252 - value: 0 - } - longest_free_range_histogram { - lower_bound: 253 - upper_bound: 253 - value: 0 - } - longest_free_range_histogram { - lower_bound: 254 - upper_bound: 254 - value: 0 - } - longest_free_range_histogram { - lower_bound: 255 - upper_bound: 255 - value: 0 - } - allocations_histogram { - lower_bound: 1 - upper_bound: 1 - value: 2 - } - allocations_histogram { - lower_bound: 2 - upper_bound: 2 - value: 0 - } - allocations_histogram { - lower_bound: 3 - upper_bound: 3 - value: 0 - } - allocations_histogram { - lower_bound: 4 - upper_bound: 4 - value: 0 - } - allocations_histogram { - lower_bound: 5 - upper_bound: 16 - value: 0 - } - allocations_histogram { - lower_bound: 17 - upper_bound: 32 - value: 0 - } - allocations_histogram { - lower_bound: 33 - upper_bound: 48 - value: 0 - } - allocations_histogram { - lower_bound: 49 - upper_bound: 64 - value: 0 - } - allocations_histogram { - lower_bound: 65 - upper_bound: 80 - value: 0 - } - allocations_histogram { - lower_bound: 81 - upper_bound: 96 - value: 0 - } - allocations_histogram { - lower_bound: 97 - upper_bound: 112 - value: 0 - } - allocations_histogram { - lower_bound: 113 - upper_bound: 128 - value: 0 - } - allocations_histogram { - lower_bound: 129 - upper_bound: 144 - value: 0 - } - allocations_histogram { - lower_bound: 145 - upper_bound: 160 - value: 0 - } - allocations_histogram { - lower_bound: 161 - upper_bound: 176 - value: 0 - } - allocations_histogram { - lower_bound: 177 - upper_bound: 192 - value: 0 - } - allocations_histogram { - lower_bound: 193 - upper_bound: 208 - value: 0 - } - allocations_histogram { - lower_bound: 209 - upper_bound: 224 - value: 0 - } - allocations_histogram { - lower_bound: 225 - upper_bound: 240 - value: 0 - } - allocations_histogram { - lower_bound: 241 - upper_bound: 252 - value: 0 - } - allocations_histogram { - lower_bound: 253 - upper_bound: 253 - value: 0 - } - allocations_histogram { - lower_bound: 254 - upper_bound: 254 - value: 0 - } - allocations_histogram { - lower_bound: 255 - upper_bound: 255 - value: 0 - } - allocations_histogram { - lower_bound: 256 - upper_bound: 256 - value: 0 - } + if (std::get<0>(GetParam()) == + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test for kSpansAllocated"; } - filler_skipped_subrelease { - skipped_subrelease_interval_ms: 0 - skipped_subrelease_pages: 0 - correctly_skipped_subrelease_pages: 0 - pending_skipped_subrelease_pages: 0 - skipped_subrelease_count: 0 - correctly_skipped_subrelease_count: 0 - pending_skipped_subrelease_count: 0 - } - filler_stats_timeseries { - window_ms: 1000 - epochs: 600 - min_free_pages_interval_ms: 300000 - min_free_pages: 0 - min_free_backed_pages: 0 - measurements { - epoch: 599 - timestamp_ms: 0 - min_free_pages: 0 - min_free_backed_pages: 0 - num_pages_subreleased: 269 - num_hugepages_broken: 3 - at_minimum_demand { - num_pages: 0 - regular_huge_pages: 0 - donated_huge_pages: 0 - partial_released_huge_pages: 0 - released_huge_pages: 0 - used_pages_in_subreleased_huge_pages: 0 - } - at_maximum_demand { - num_pages: 1774 - regular_huge_pages: 5 - donated_huge_pages: 1 - partial_released_huge_pages: 0 - released_huge_pages: 2 - used_pages_in_subreleased_huge_pages: 499 - } - at_minimum_huge_pages { - num_pages: 0 - regular_huge_pages: 0 - donated_huge_pages: 0 - partial_released_huge_pages: 0 - released_huge_pages: 0 - used_pages_in_subreleased_huge_pages: 0 - } - at_maximum_huge_pages { - num_pages: 1774 - regular_huge_pages: 5 - donated_huge_pages: 1 - partial_released_huge_pages: 0 - released_huge_pages: 2 - used_pages_in_subreleased_huge_pages: 499 - } - } + const Length N = kPagesPerHugePage; + // Reports skip subrelease using the recent demand peak (2.5N): it is smaller + // than the total number of pages (3N) when 0.25N free pages are skipped. The + // skipping is correct as the future demand is 2.5N. + std::vector peak1a = AllocateVector(3 * N / 4); + ASSERT_TRUE(!peak1a.empty()); + std::vector peak1b = + AllocateVectorWithSpanAllocInfo(N / 4, peak1a.front().span_alloc_info); + std::vector peak2a = AllocateVectorWithSpanAllocInfo( + 3 * N / 4, peak1a.front().span_alloc_info); + std::vector peak2b = + AllocateVectorWithSpanAllocInfo(N / 4, peak1a.front().span_alloc_info); + std::vector half1 = + AllocateVectorWithSpanAllocInfo(N / 2, peak1a.front().span_alloc_info); + Advance(absl::Minutes(2)); + DeleteVector(half1); + DeleteVector(peak1b); + DeleteVector(peak2b); + std::vector peak3a = AllocateVectorWithSpanAllocInfo( + 3 * N / 4, peak1a.front().span_alloc_info); + EXPECT_EQ(filler_.free_pages(), 3 * N / 4); + // Subreleases 0.5N free pages and skips 0.25N free pages. + EXPECT_EQ(N / 2, + ReleasePages(10 * N, SkipSubreleaseIntervals{ + .short_interval = absl::Minutes(3), + .long_interval = absl::Minutes(3)})); + Advance(absl::Minutes(3)); + std::vector tiny1 = + AllocateVectorWithSpanAllocInfo(N / 4, peak1a.front().span_alloc_info); + EXPECT_EQ(filler_.used_pages(), 2 * N + N / 2); + EXPECT_EQ(filler_.unmapped_pages(), N / 2); + EXPECT_EQ(filler_.free_pages(), Length(0)); + DeleteVector(peak1a); + DeleteVector(peak2a); + DeleteVector(peak3a); + DeleteVector(tiny1); + EXPECT_EQ(filler_.used_pages(), Length(0)); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); + EXPECT_EQ(filler_.free_pages(), Length(0)); + // Accounts for pages that are eagerly unmapped (unmapping_unaccounted_). + EXPECT_EQ(N + N / 2, ReleasePages(10 * N)); + + Advance(absl::Minutes(30)); + + // Reports skip subrelease using HugePageFiller's capacity (N pages): it is + // smaller than the recent peak (2N) when 0.5N pages are skipped. They are + // correctly skipped as the future demand is N. + std::vector peak4a = AllocateVector(3 * N / 4); + ASSERT_TRUE(!peak4a.empty()); + std::vector peak4b = + AllocateVectorWithSpanAllocInfo(N / 4, peak4a.front().span_alloc_info); + std::vector peak5a = AllocateVector(3 * N / 4); + ASSERT_TRUE(!peak5a.empty()); + std::vector peak5b = + AllocateVectorWithSpanAllocInfo(N / 4, peak5a.front().span_alloc_info); + Advance(absl::Minutes(2)); + DeleteVector(peak4a); + DeleteVector(peak4b); + DeleteVector(peak5a); + DeleteVector(peak5b); + std::vector half2 = AllocateVector(N / 2); + EXPECT_EQ(Length(0), + ReleasePages(10 * N, SkipSubreleaseIntervals{ + .short_interval = absl::Minutes(3), + .long_interval = absl::Minutes(3)})); + Advance(absl::Minutes(3)); + std::vector half3 = AllocateVector(N / 2); + DeleteVector(half2); + DeleteVector(half3); + EXPECT_EQ(filler_.used_pages(), Length(0)); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); + EXPECT_EQ(filler_.free_pages(), Length(0)); + EXPECT_EQ(Length(0), ReleasePages(10 * N)); + Advance(absl::Minutes(30)); + // Ensures that the tracker is updated. + auto tiny2 = Allocate(Length(1)); + Delete(tiny2); + + std::string buffer(1024 * 1024, '\0'); + { + Printer printer(&*buffer.begin(), buffer.size()); + filler_.Print(printer, true); } + buffer.resize(strlen(buffer.c_str())); + + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugePageFiller: Since the start of the execution, 2 subreleases (192 pages) were skipped due to the sum of short-term (180s) fluctuations and long-term (180s) trends. +HugePageFiller: 100.0000% of decisions confirmed correct, 0 pending (100.0000% of pages, 0 pending). )")); - for (const auto& alloc : allocs) { - Delete(alloc); +} + +TEST_P(FillerTest, ReportSkipSubreleases_SpansAllocated) { + // Tests that HugePageFiller reports skipped subreleases using demand + // requirement that is the smaller of two (recent peak and its + // current capacity). This fix makes evaluating skip subrelease more accurate, + // which is useful for cross-comparing performance of different + // skip-subrelease intervals. + + // This test is sensitive to the number of pages per hugepage, as we are + // printing raw stats. + if (kPagesPerHugePage != Length(256)) { + GTEST_SKIP(); + } + if (std::get<0>(GetParam()) != + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test for !kSpansAllocated"; + } + randomize_density_ = false; + const Length N = kPagesPerHugePage; + SpanAllocInfo info = {kPagesPerHugePage.raw_num(), + AccessDensityPrediction::kDense}; + // Reports skip subrelease using the recent demand peak (2.5N): it is smaller + // than the total number of pages (3N) when 0.25N free pages are skipped. The + // skipping is correct as the future demand is 2.5N. + std::vector peak1a = AllocateVectorWithSpanAllocInfo(3 * N / 4, info); + ASSERT_TRUE(!peak1a.empty()); + std::vector peak1b = + AllocateVectorWithSpanAllocInfo(N / 4, peak1a.front().span_alloc_info); + std::vector peak2a = AllocateVectorWithSpanAllocInfo( + 3 * N / 4, peak1a.front().span_alloc_info); + std::vector peak2b = + AllocateVectorWithSpanAllocInfo(N / 4, peak1a.front().span_alloc_info); + std::vector half1 = + AllocateVectorWithSpanAllocInfo(N / 2, peak1a.front().span_alloc_info); + Advance(absl::Minutes(2)); + DeleteVector(half1); + DeleteVector(peak1b); + DeleteVector(peak2b); + std::vector peak3a = AllocateVectorWithSpanAllocInfo( + 3 * N / 4, peak1a.front().span_alloc_info); + EXPECT_EQ(filler_.free_pages(), 3 * N / 4); + // Subreleases 0.75N free pages. + EXPECT_EQ(3 * N / 4, + ReleasePages(10 * N, SkipSubreleaseIntervals{ + .short_interval = absl::Seconds(1), + .long_interval = absl::Seconds(1)})); + Advance(absl::Minutes(3)); + std::vector tiny1 = + AllocateVectorWithSpanAllocInfo(N / 4, peak1a.front().span_alloc_info); + EXPECT_EQ(filler_.used_pages(), 2 * N + N / 2); + EXPECT_EQ(filler_.unmapped_pages(), N / 2); + EXPECT_EQ(filler_.free_pages(), Length(0)); + DeleteVector(peak1a); + DeleteVector(peak2a); + DeleteVector(peak3a); + DeleteVector(tiny1); + EXPECT_EQ(filler_.used_pages(), Length(0)); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); + EXPECT_EQ(filler_.free_pages(), Length(0)); + // Accounts for pages that are eagerly unmapped (unmapping_unaccounted_). + EXPECT_EQ(N / 2, ReleasePages(10 * N)); + + Advance(absl::Minutes(30)); + + // Reports skip subrelease using HugePageFiller's capacity (N pages): it is + // smaller than the recent peak (2N) when 0.5N pages are skipped. They are + // correctly skipped as the future demand is N. + std::vector peak4a = AllocateVectorWithSpanAllocInfo(3 * N / 4, info); + ASSERT_TRUE(!peak4a.empty()); + std::vector peak4b = + AllocateVectorWithSpanAllocInfo(N / 4, peak4a.front().span_alloc_info); + std::vector peak5a = AllocateVectorWithSpanAllocInfo(3 * N / 4, info); + ASSERT_TRUE(!peak5a.empty()); + std::vector peak5b = + AllocateVectorWithSpanAllocInfo(N / 4, peak5a.front().span_alloc_info); + Advance(absl::Minutes(2)); + DeleteVector(peak4a); + DeleteVector(peak4b); + DeleteVector(peak5a); + DeleteVector(peak5b); + std::vector half2 = AllocateVectorWithSpanAllocInfo(N / 2, info); + EXPECT_EQ(Length(0), + ReleasePages(10 * N, SkipSubreleaseIntervals{ + .short_interval = absl::Seconds(1), + .long_interval = absl::Seconds(1)})); + Advance(absl::Minutes(3)); + std::vector half3 = AllocateVectorWithSpanAllocInfo(N / 2, info); + DeleteVector(half2); + DeleteVector(half3); + EXPECT_EQ(filler_.used_pages(), Length(0)); + EXPECT_EQ(filler_.unmapped_pages(), Length(0)); + EXPECT_EQ(filler_.free_pages(), Length(0)); + EXPECT_EQ(Length(0), ReleasePages(10 * N)); + Advance(absl::Minutes(30)); + // Ensures that the tracker is updated. + auto tiny2 = Allocate(Length(1)); + Delete(tiny2); + + std::string buffer(1024 * 1024, '\0'); + { + Printer printer(&*buffer.begin(), buffer.size()); + filler_.Print(printer, true); + } + buffer.resize(strlen(buffer.c_str())); + + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugePageFiller: Since the start of the execution, 2 subreleases (191 pages) were skipped due to the sum of short-term (1s) fluctuations and long-term (1s) trends. +HugePageFiller: 0.0000% of decisions confirmed correct, 0 pending (0.0000% of pages, 0 pending). +)")); +} + +std::vector FillerTest::GenerateInterestingAllocs() { + SpanAllocInfo info_sparsely_accessed = {1, AccessDensityPrediction::kSparse}; + SpanAllocInfo info_densely_accessed = {kMaxValidPages.raw_num(), + AccessDensityPrediction::kDense}; + PAlloc a = AllocateWithSpanAllocInfo(Length(1), info_sparsely_accessed); + EXPECT_EQ(ReleasePages(kMaxValidPages), kPagesPerHugePage - Length(1)); + Delete(a); + // Get the report on the released page + EXPECT_EQ(ReleasePages(kMaxValidPages), Length(1)); + + // Use a maximally-suboptimal pattern to get lots of hugepages into the + // filler. + std::vector result; + static_assert(kPagesPerHugePage > Length(7), + "Not enough pages per hugepage!"); + for (auto i = Length(0); i < Length(7); ++i) { + std::vector temp = AllocateVectorWithSpanAllocInfo( + kPagesPerHugePage - i - Length(1), info_sparsely_accessed); + result.insert(result.end(), temp.begin(), temp.end()); + temp = AllocateVectorWithSpanAllocInfo(kPagesPerHugePage - i - Length(1), + info_densely_accessed); + result.insert(result.end(), temp.begin(), temp.end()); + } + + // Get released hugepages. + Length l = ReleasePages(Length(7)); + EXPECT_TRUE(l == Length(7) || l == Length(28)); + l = ReleasePages(Length(7)); + EXPECT_EQ(l, Length(7)); + l = ReleasePages(Length(6)); + EXPECT_EQ(l, Length(6)); + l = ReleasePages(Length(6)); + EXPECT_TRUE(l == Length(6) || l == Length(9)); + + // Fill some of the remaining pages with small allocations. + for (int i = 0; i < 9; ++i) { + result.push_back( + AllocateWithSpanAllocInfo(Length(1), info_sparsely_accessed)); + result.push_back( + AllocateWithSpanAllocInfo(Length(1), info_densely_accessed)); } + + // Finally, donate one hugepage. + result.push_back(AllocateWithSpanAllocInfo(Length(1), info_sparsely_accessed, + /*donated=*/true)); + return result; } // Testing subrelase stats: ensure that the cumulative number of released // pages and broken hugepages is no less than those of the last 10 mins TEST_P(FillerTest, CheckSubreleaseStats) { + if (std::get<0>(GetParam()) == + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test for kSpansAllocated"; + } // Get lots of hugepages into the filler. Advance(absl::Minutes(1)); - std::vector result; + std::vector> result; static_assert(kPagesPerHugePage > Length(10), "Not enough pages per hugepage!"); + // Fix the object count since very specific statistics are being tested. + const AccessDensityPrediction kDensity = + absl::Bernoulli(gen_, 0.5) ? AccessDensityPrediction::kSparse + : AccessDensityPrediction::kDense; + const size_t kObjects = (1 << absl::Uniform(gen_, 0, 8)); + const SpanAllocInfo kAllocInfo = {kObjects, kDensity}; + for (int i = 0; i < 10; ++i) { - result.push_back(Allocate(kPagesPerHugePage - Length(i + 1))); + result.push_back(AllocateVectorWithSpanAllocInfo( + kPagesPerHugePage - Length(i + 1), kAllocInfo)); } // Breaking up 2 hugepages, releasing 19 pages due to reaching limit, @@ -3531,6 +3038,7 @@ TEST_P(FillerTest, CheckSubreleaseStats) { Advance(absl::Minutes(1)); SubreleaseStats subrelease = filler_.subrelease_stats(); EXPECT_EQ(subrelease.total_pages_subreleased, Length(0)); + EXPECT_EQ(subrelease.total_partial_alloc_pages_subreleased, Length(0)); EXPECT_EQ(subrelease.total_hugepages_broken.raw_num(), 0); EXPECT_EQ(subrelease.num_pages_subreleased, Length(19)); EXPECT_EQ(subrelease.num_hugepages_broken.raw_num(), 2); @@ -3539,10 +3047,11 @@ TEST_P(FillerTest, CheckSubreleaseStats) { // Do some work so that the timeseries updates its stats for (int i = 0; i < 5; ++i) { - result.push_back(Allocate(Length(1))); + result.push_back(AllocateVectorWithSpanAllocInfo(Length(1), kAllocInfo)); } subrelease = filler_.subrelease_stats(); EXPECT_EQ(subrelease.total_pages_subreleased, Length(19)); + EXPECT_EQ(subrelease.total_partial_alloc_pages_subreleased, Length(0)); EXPECT_EQ(subrelease.total_hugepages_broken.raw_num(), 2); EXPECT_EQ(subrelease.num_pages_subreleased, Length(0)); EXPECT_EQ(subrelease.num_hugepages_broken.raw_num(), 0); @@ -3556,6 +3065,7 @@ TEST_P(FillerTest, CheckSubreleaseStats) { subrelease = filler_.subrelease_stats(); EXPECT_EQ(subrelease.total_pages_subreleased, Length(19)); + EXPECT_EQ(subrelease.total_partial_alloc_pages_subreleased, Length(0)); EXPECT_EQ(subrelease.total_hugepages_broken.raw_num(), 2); EXPECT_EQ(subrelease.num_pages_subreleased, Length(21)); EXPECT_EQ(subrelease.num_hugepages_broken.raw_num(), 3); @@ -3565,10 +3075,11 @@ TEST_P(FillerTest, CheckSubreleaseStats) { Advance(absl::Minutes(10)); // This forces timeseries to wrap // Do some work for (int i = 0; i < 5; ++i) { - result.push_back(Allocate(Length(1))); + result.push_back(AllocateVectorWithSpanAllocInfo(Length(1), kAllocInfo)); } subrelease = filler_.subrelease_stats(); EXPECT_EQ(subrelease.total_pages_subreleased, Length(40)); + EXPECT_EQ(subrelease.total_partial_alloc_pages_subreleased, Length(0)); EXPECT_EQ(subrelease.total_hugepages_broken.raw_num(), 5); EXPECT_EQ(subrelease.num_pages_subreleased, Length(0)); EXPECT_EQ(subrelease.num_hugepages_broken.raw_num(), 0); @@ -3577,8 +3088,9 @@ TEST_P(FillerTest, CheckSubreleaseStats) { std::string buffer(1024 * 1024, '\0'); { + PageHeapSpinLockHolder l; Printer printer(&*buffer.begin(), buffer.size()); - filler_.Print(&printer, /*everything=*/true); + filler_.Print(printer, /*everything=*/true); buffer.erase(printer.SpaceRequired()); } @@ -3590,10 +3102,119 @@ TEST_P(FillerTest, CheckSubreleaseStats) { "limit)")); ASSERT_THAT(buffer, testing::EndsWith( "HugePageFiller: Subrelease stats last 10 min: total " - "21 pages subreleased, 3 hugepages broken\n")); + "21 pages subreleased (0 pages from partial allocs), " + "3 hugepages broken\n")); for (const auto& alloc : result) { - Delete(alloc); + DeleteVector(alloc); + } +} + +TEST_P(FillerTest, CheckSubreleaseStats_SpansAllocated) { + if (std::get<0>(GetParam()) != + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test for !kSpansAllocated"; + } + randomize_density_ = false; + // Get lots of hugepages into the filler. + Advance(absl::Minutes(1)); + std::vector> result; + std::vector> temporary; + static_assert(kPagesPerHugePage > Length(10), + "Not enough pages per hugepage!"); + // Fix the object count since very specific statistics are being tested. + const AccessDensityPrediction kDensity = + absl::Bernoulli(gen_, 0.5) ? AccessDensityPrediction::kSparse + : AccessDensityPrediction::kDense; + const size_t kObjects = (1 << absl::Uniform(gen_, 0, 8)); + const SpanAllocInfo kAllocInfo = {kObjects, kDensity}; + + for (int i = 0; i < 10; ++i) { + result.push_back(AllocateVectorWithSpanAllocInfo( + kPagesPerHugePage - Length(i + 1), kAllocInfo)); + temporary.push_back( + AllocateVectorWithSpanAllocInfo(Length(i + 1), kAllocInfo)); + } + for (const auto& alloc : temporary) { + DeleteVector(alloc); + } + + // Breaking up 2 hugepages, releasing 19 pages due to reaching limit, + EXPECT_EQ(HardReleasePages(Length(10)), Length(10)); + EXPECT_EQ(HardReleasePages(Length(9)), Length(9)); + + Advance(absl::Minutes(1)); + SubreleaseStats subrelease = filler_.subrelease_stats(); + EXPECT_EQ(subrelease.total_pages_subreleased, Length(0)); + EXPECT_EQ(subrelease.total_partial_alloc_pages_subreleased, Length(0)); + EXPECT_EQ(subrelease.total_hugepages_broken.raw_num(), 0); + EXPECT_EQ(subrelease.num_pages_subreleased, Length(19)); + EXPECT_EQ(subrelease.num_hugepages_broken.raw_num(), 2); + EXPECT_EQ(subrelease.total_pages_subreleased_due_to_limit, Length(19)); + EXPECT_EQ(subrelease.total_hugepages_broken_due_to_limit.raw_num(), 2); + + // Do some work so that the timeseries updates its stats + for (int i = 0; i < 5; ++i) { + result.push_back(AllocateVectorWithSpanAllocInfo(Length(1), kAllocInfo)); + } + subrelease = filler_.subrelease_stats(); + EXPECT_EQ(subrelease.total_pages_subreleased, Length(19)); + EXPECT_EQ(subrelease.total_partial_alloc_pages_subreleased, Length(0)); + EXPECT_EQ(subrelease.total_hugepages_broken.raw_num(), 2); + EXPECT_EQ(subrelease.num_pages_subreleased, Length(0)); + EXPECT_EQ(subrelease.num_hugepages_broken.raw_num(), 0); + EXPECT_EQ(subrelease.total_pages_subreleased_due_to_limit, Length(19)); + EXPECT_EQ(subrelease.total_hugepages_broken_due_to_limit.raw_num(), 2); + + // Breaking up 3 hugepages, releasing 21 pages (background thread) + EXPECT_EQ(ReleasePages(Length(8)), Length(8)); + EXPECT_EQ(ReleasePages(Length(7)), Length(7)); + EXPECT_EQ(ReleasePages(Length(6)), Length(6)); + + subrelease = filler_.subrelease_stats(); + EXPECT_EQ(subrelease.total_pages_subreleased, Length(19)); + EXPECT_EQ(subrelease.total_partial_alloc_pages_subreleased, Length(0)); + EXPECT_EQ(subrelease.total_hugepages_broken.raw_num(), 2); + EXPECT_EQ(subrelease.num_pages_subreleased, Length(21)); + EXPECT_EQ(subrelease.num_hugepages_broken.raw_num(), 3); + EXPECT_EQ(subrelease.total_pages_subreleased_due_to_limit, Length(19)); + EXPECT_EQ(subrelease.total_hugepages_broken_due_to_limit.raw_num(), 2); + + Advance(absl::Minutes(10)); // This forces timeseries to wrap + // Do some work + for (int i = 0; i < 5; ++i) { + result.push_back(AllocateVectorWithSpanAllocInfo(Length(1), kAllocInfo)); + } + subrelease = filler_.subrelease_stats(); + EXPECT_EQ(subrelease.total_pages_subreleased, Length(40)); + EXPECT_EQ(subrelease.total_partial_alloc_pages_subreleased, Length(0)); + EXPECT_EQ(subrelease.total_hugepages_broken.raw_num(), 5); + EXPECT_EQ(subrelease.num_pages_subreleased, Length(0)); + EXPECT_EQ(subrelease.num_hugepages_broken.raw_num(), 0); + EXPECT_EQ(subrelease.total_pages_subreleased_due_to_limit, Length(19)); + EXPECT_EQ(subrelease.total_hugepages_broken_due_to_limit.raw_num(), 2); + + std::string buffer(1024 * 1024, '\0'); + { + PageHeapSpinLockHolder l; + Printer printer(&*buffer.begin(), buffer.size()); + filler_.Print(printer, /*everything=*/true); + buffer.erase(printer.SpaceRequired()); + } + + ASSERT_THAT( + buffer, + testing::HasSubstr( + "HugePageFiller: Since startup, 40 pages subreleased, 5 hugepages " + "broken, (19 pages, 2 hugepages due to reaching tcmalloc " + "limit)")); + ASSERT_THAT(buffer, testing::EndsWith( + "HugePageFiller: Subrelease stats last 10 min: total " + "21 pages subreleased (0 pages from partial allocs), " + "3 hugepages broken\n")); + + for (const auto& alloc : result) { + DeleteVector(alloc); } } @@ -3613,8 +3234,12 @@ TEST_P(FillerTest, ConstantBrokenHugePages) { auto size = Length(absl::Uniform(rng, 2, kPagesPerHugePage.raw_num() - 1)); alloc_small.push_back(Allocate(Length(1))); - alloc.push_back(Allocate(size - Length(1))); - dead.push_back(Allocate(kPagesPerHugePage - size)); + SpanAllocInfo info = alloc_small.back().span_alloc_info; + std::vector temp = + AllocateVectorWithSpanAllocInfo(size - Length(1), info); + alloc.insert(alloc.end(), temp.begin(), temp.end()); + temp = AllocateVectorWithSpanAllocInfo(kPagesPerHugePage - size, info); + dead.insert(dead.end(), temp.begin(), temp.end()); } ASSERT_EQ(filler_.size(), kHugePages); @@ -3629,8 +3254,9 @@ TEST_P(FillerTest, ConstantBrokenHugePages) { std::string buffer(1024 * 1024, '\0'); { + PageHeapSpinLockHolder l; Printer printer(&*buffer.begin(), buffer.size()); - filler_.Print(&printer, /*everything=*/false); + filler_.Print(printer, /*everything=*/false); buffer.erase(printer.SpaceRequired()); } @@ -3664,29 +3290,28 @@ TEST_P(FillerTest, ConstantBrokenHugePages) { TEST_P(FillerTest, CheckBufferSize) { const int kEpochs = 600; const absl::Duration kEpochLength = absl::Seconds(1); - - PAlloc big = Allocate(kPagesPerHugePage - Length(4)); + std::vector big = AllocateVector(kPagesPerHugePage - Length(4)); for (int i = 0; i < kEpochs; i += 2) { - auto tiny = Allocate(Length(2)); + auto tiny = AllocateVector(Length(2)); Advance(kEpochLength); - Delete(tiny); + DeleteVector(tiny); Advance(kEpochLength); } - Delete(big); + DeleteVector(big); std::string buffer(1024 * 1024, '\0'); Printer printer(&*buffer.begin(), buffer.size()); { - PbtxtRegion region(&printer, kTop, /*indent=*/0); - filler_.PrintInPbtxt(®ion); + PageHeapSpinLockHolder l; + PbtxtRegion region(printer, kTop); + filler_.PrintInPbtxt(region); } // We assume a maximum buffer size of 1 MiB. When increasing this size, ensure // that all places processing mallocz protos get updated as well. size_t buffer_size = printer.SpaceRequired(); - printf("HugePageFiller buffer size: %zu\n", buffer_size); EXPECT_LE(buffer_size, 1024 * 1024); } @@ -3699,32 +3324,34 @@ TEST_P(FillerTest, ReleasePriority) { // We will ensure that we fill full huge pages, then deallocate some parts of // those to provide space for subrelease. absl::BitGen rng; - std::vector alloc; + std::vector> alloc; alloc.reserve(kHugePages.raw_num()); - std::vector dead; + std::vector> dead; dead.reserve(kHugePages.raw_num()); - absl::flat_hash_set unique_pages; + absl::flat_hash_set unique_pages; unique_pages.reserve(kHugePages.raw_num()); for (HugeLength i; i < kHugePages; ++i) { Length size(absl::Uniform(rng, 1, kPagesPerHugePage.raw_num() - 1)); - PAlloc a = Allocate(size); - unique_pages.insert(a.pt); + std::vector a = AllocateVector(size); + ASSERT_TRUE(!a.empty()); + for (const auto& pa : a) unique_pages.insert(pa.pt); alloc.push_back(a); - dead.push_back(Allocate(kPagesPerHugePage - size)); + dead.push_back(AllocateVectorWithSpanAllocInfo(kPagesPerHugePage - size, + a.front().span_alloc_info)); } ASSERT_EQ(filler_.size(), kHugePages); for (auto& a : dead) { - Delete(a); + DeleteVector(a); } // As of 5/2020, our release priority is to subrelease huge pages with the // fewest used pages. Bucket unique_pages by that used_pages(). - std::vector> ordered(kPagesPerHugePage.raw_num()); + std::vector> ordered(kPagesPerHugePage.raw_num()); for (auto* pt : unique_pages) { // None of these should be released yet. EXPECT_FALSE(pt->released()); @@ -3786,13 +3413,883 @@ TEST_P(FillerTest, ReleasePriority) { } for (auto& a : alloc) { + DeleteVector(a); + } +} + +TEST_P(FillerTest, b258965495) { + // 1 huge page: 2 pages allocated, kPagesPerHugePage-2 free, 0 released + auto a1 = AllocateVector(Length(2)); + ASSERT_TRUE(!a1.empty()); + EXPECT_EQ(filler_.size(), NHugePages(1)); + + ASSERT_TRUE(blocking_unback_.success_); + // 1 huge page: 2 pages allocated, 0 free, kPagesPerHugePage-2 released + EXPECT_EQ(HardReleasePages(kPagesPerHugePage), kPagesPerHugePage - Length(2)); + + blocking_unback_.success_ = false; + // 1 huge page: 3 pages allocated, 0 free, kPagesPerHugePage-3 released + auto a2 = AllocateWithSpanAllocInfo(Length(1), a1.front().span_alloc_info); + EXPECT_EQ(filler_.size(), NHugePages(1)); + // Even if PartialRerelease::Return, returning a2 fails, so a2's pages stay + // freed rather than released. + // + // 1 huge page: 2 pages allocated, 1 free, kPagesPerHugePage-3 released + Delete(a2); + + blocking_unback_.success_ = true; + // During the deallocation of a1 under PartialRerelease::Return, but before we + // mark the pages as free (PageTracker::MaybeRelease), we have: + // + // 1 huge page: 2 pages allocated, 1 free, kPagesPerHugePage-1 released + // + // The page appears fully (free_pages() <= released_pages()), rather than + // partially released, so we look for it on the wrong list. + DeleteVector(a1); +} + +TEST_P(FillerTest, CheckFillerStats) { + if (std::get<0>(GetParam()) == + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test for kSpansAllocated"; + } + if (kPagesPerHugePage != Length(256)) { + // The output is hardcoded on this assumption, and dynamically calculating + // it would be way too much of a pain. + return; + } + // We prevent randomly choosing the number of objects per span since this + // test has hardcoded output which will change if the objects per span are + // chosen at random. + randomize_density_ = false; + auto allocs = GenerateInterestingAllocs(); + + const HugePageFillerStats stats = filler_.GetStats(); + for (int i = 0; i < AccessDensityPrediction::kPredictionCounts; ++i) { + EXPECT_GE(stats.n_fully_released[i].raw_num(), 0); + } + // Check sparsely-accessed filler stats. + EXPECT_EQ(stats.n_fully_released[AccessDensityPrediction::kSparse].raw_num(), + 2); + EXPECT_EQ(stats.n_released[AccessDensityPrediction::kSparse].raw_num(), 2); + EXPECT_EQ( + stats.n_partial_released[AccessDensityPrediction::kSparse].raw_num(), 0); + EXPECT_EQ(stats.n_total[AccessDensityPrediction::kSparse].raw_num(), 8); + EXPECT_EQ(stats.n_full[AccessDensityPrediction::kSparse].raw_num(), 3); + EXPECT_EQ(stats.n_partial[AccessDensityPrediction::kSparse].raw_num(), 3); + + // Check densely-accessed filler stats. + EXPECT_EQ(stats.n_fully_released[AccessDensityPrediction::kDense].raw_num(), + 2); + EXPECT_EQ(stats.n_released[AccessDensityPrediction::kDense].raw_num(), 2); + EXPECT_EQ(stats.n_partial_released[AccessDensityPrediction::kDense].raw_num(), + 0); + EXPECT_EQ(stats.n_total[AccessDensityPrediction::kDense].raw_num(), 7); + EXPECT_EQ(stats.n_full[AccessDensityPrediction::kDense].raw_num(), 3); + EXPECT_EQ(stats.n_partial[AccessDensityPrediction::kDense].raw_num(), 2); + + // Check total filler stats. + EXPECT_EQ(stats.n_fully_released[AccessDensityPrediction::kPredictionCounts] + .raw_num(), + 4); + EXPECT_EQ( + stats.n_released[AccessDensityPrediction::kPredictionCounts].raw_num(), + 4); + EXPECT_EQ(stats.n_partial_released[AccessDensityPrediction::kPredictionCounts] + .raw_num(), + 0); + EXPECT_EQ(stats.n_total[AccessDensityPrediction::kPredictionCounts].raw_num(), + 15); + EXPECT_EQ(stats.n_full[AccessDensityPrediction::kPredictionCounts].raw_num(), + 6); + EXPECT_EQ( + stats.n_partial[AccessDensityPrediction::kPredictionCounts].raw_num(), 5); + + for (const auto& alloc : allocs) { + Delete(alloc); + } +} + +TEST_P(FillerTest, CheckFillerStats_SpansAllocated) { + if (std::get<0>(GetParam()) != + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test for !kSpansAllocated"; + } + if (kPagesPerHugePage != Length(256)) { + // The output is hardcoded on this assumption, and dynamically calculating + // it would be way too much of a pain. + return; + } + // We prevent randomly choosing the number of objects per span since this + // test has hardcoded output which will change if the objects per span are + // chosen at random. + randomize_density_ = false; + auto allocs = GenerateInterestingAllocs(); + + const HugePageFillerStats stats = filler_.GetStats(); + for (int i = 0; i < AccessDensityPrediction::kPredictionCounts; ++i) { + EXPECT_GE(stats.n_fully_released[i].raw_num(), 0); + } + // Check sparsely-accessed filler stats. + EXPECT_EQ(stats.n_fully_released[AccessDensityPrediction::kSparse].raw_num(), + 4); + EXPECT_EQ(stats.n_released[AccessDensityPrediction::kSparse].raw_num(), 4); + EXPECT_EQ( + stats.n_partial_released[AccessDensityPrediction::kSparse].raw_num(), 0); + EXPECT_EQ(stats.n_total[AccessDensityPrediction::kSparse].raw_num(), 8); + EXPECT_EQ(stats.n_full[AccessDensityPrediction::kSparse].raw_num(), 3); + EXPECT_EQ(stats.n_partial[AccessDensityPrediction::kSparse].raw_num(), 1); + + // Check densely-accessed filler stats. + EXPECT_EQ(stats.n_fully_released[AccessDensityPrediction::kDense].raw_num(), + 1); + EXPECT_EQ(stats.n_released[AccessDensityPrediction::kDense].raw_num(), 1); + EXPECT_EQ(stats.n_partial_released[AccessDensityPrediction::kDense].raw_num(), + 0); + EXPECT_EQ(stats.n_total[AccessDensityPrediction::kDense].raw_num(), 7); + EXPECT_EQ(stats.n_full[AccessDensityPrediction::kDense].raw_num(), 6); + EXPECT_EQ(stats.n_partial[AccessDensityPrediction::kDense].raw_num(), 0); + + // Check total filler stats. + EXPECT_EQ(stats.n_fully_released[AccessDensityPrediction::kPredictionCounts] + .raw_num(), + 5); + EXPECT_EQ( + stats.n_released[AccessDensityPrediction::kPredictionCounts].raw_num(), + 5); + EXPECT_EQ(stats.n_partial_released[AccessDensityPrediction::kPredictionCounts] + .raw_num(), + 0); + EXPECT_EQ(stats.n_total[AccessDensityPrediction::kPredictionCounts].raw_num(), + 15); + EXPECT_EQ(stats.n_full[AccessDensityPrediction::kPredictionCounts].raw_num(), + 9); + EXPECT_EQ( + stats.n_partial[AccessDensityPrediction::kPredictionCounts].raw_num(), 1); + + for (const auto& alloc : allocs) { + Delete(alloc); + } +} + +// Test the output of Print(). This is something of a change-detector test, +// but that's not all bad in this case. +TEST_P(FillerTest, Print) { + // Skip test for kSpansAllocated since the output is hard coded. + if (std::get<0>(GetParam()) == + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test for kSpansAllocated"; + } + if (kPagesPerHugePage != Length(256)) { + // The output is hardcoded on this assumption, and dynamically calculating + // it would be way too much of a pain. + return; + } + // We prevent randomly choosing the number of objects per span since this + // test has hardcoded output which will change if the objects per span are + // chosen at random. + randomize_density_ = false; + auto allocs = GenerateInterestingAllocs(); + + std::string buffer(1024 * 1024, '\0'); + { + PageHeapSpinLockHolder l; + Printer printer(&*buffer.begin(), buffer.size()); + filler_.Print(printer, /*everything=*/true); + buffer.erase(printer.SpaceRequired()); + } + + EXPECT_THAT( + buffer, + StrEq(R"(HugePageFiller: densely pack small requests into hugepages +HugePageFiller: Overall, 15 total, 6 full, 5 partial, 4 released (0 partially), 0 quarantined +HugePageFiller: those with sparsely-accessed spans, 8 total, 3 full, 3 partial, 2 released (0 partially), 0 quarantined +HugePageFiller: those with densely-accessed spans, 7 total, 3 full, 2 partial, 2 released (0 partially), 0 quarantined +HugePageFiller: 267 pages free in 15 hugepages, 0.0695 free +HugePageFiller: among non-fulls, 0.2086 free +HugePageFiller: 998 used pages in subreleased hugepages (0 of them in partially released) +HugePageFiller: 4 hugepages partially released, 0.0254 released +HugePageFiller: 0.7186 of used pages hugepageable +HugePageFiller: Since startup, 282 pages subreleased, 5 hugepages broken, (0 pages, 0 hugepages due to reaching tcmalloc limit) +HugePageFiller: 0 hugepages became full after being previously released, out of which 0 pages are hugepage backed. + +HugePageFiller: fullness histograms + +HugePageFiller: # of sparsely-accessed regular hps with a<= # of free pages = 224 free pages, with different lifetimes. +HugePageFiller: # of sparsely-accessed regular hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of densely-accessed regular hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of donated hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 1 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of sparsely-accessed partial released hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of densely-accessed partial released hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of sparsely-accessed released hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of densely-accessed released hps with lifetime a <= # hps < b +HugePageFiller: < 0 ms <= 0 < 1 ms <= 0 < 10 ms <= 0 < 100 ms <= 0 < 1000 ms <= 0 < 10000 ms <= 0 +HugePageFiller: < 100000 ms <= 0 < 1000000 ms <= 0 + +HugePageFiller: # of hps with lifetime >= 100000 ms. +HugePageFiller: # of sparsely-accessed regular hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 0 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 + +HugePageFiller: # of densely-accessed regular hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 0 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 + +HugePageFiller: # of donated hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 0 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 + +HugePageFiller: # of sparsely-accessed partial released hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 0 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 + +HugePageFiller: # of densely-accessed partial released hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 0 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 + +HugePageFiller: # of sparsely-accessed released hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 0 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 + +HugePageFiller: # of densely-accessed released hps with a <= # of allocations < b +HugePageFiller: < 0<= 0 < 1<= 0 < 2<= 0 < 3<= 0 < 4<= 0 < 5<= 0 +HugePageFiller: < 6<= 0 < 7<= 0 < 8<= 0 < 16<= 0 < 32<= 0 < 48<= 0 +HugePageFiller: < 64<= 0 < 80<= 0 < 96<= 0 <112<= 0 <128<= 0 <144<= 0 +HugePageFiller: <160<= 0 <176<= 0 <192<= 0 <208<= 0 <224<= 0 <240<= 0 +HugePageFiller: <248<= 0 <249<= 0 <250<= 0 <251<= 0 <252<= 0 <253<= 0 +HugePageFiller: <254<= 0 <255<= 0 + +HugePageFiller: 0 of sparsely-accessed regular pages hugepage backed out of 5. +HugePageFiller: 0 of densely-accessed regular pages hugepage backed out of 5. +HugePageFiller: 0 of donated pages hugepage backed out of 1. +HugePageFiller: 0 of sparsely-accessed partial released pages hugepage backed out of 0. +HugePageFiller: 0 of densely-accessed partial released pages hugepage backed out of 0. +HugePageFiller: 0 of sparsely-accessed released pages hugepage backed out of 2. +HugePageFiller: 0 of densely-accessed released pages hugepage backed out of 2. + +HugePageFiller: time series over 5 min interval + +HugePageFiller: realized fragmentation: 0.0 MiB +HugePageFiller: minimum free pages: 0 (0 backed) +HugePageFiller: at peak demand: 3547 pages (and 267 free, 26 unmapped) +HugePageFiller: at peak demand: 15 hps (10 regular, 1 donated, 0 partial, 4 released) + +HugePageFiller: Since the start of the execution, 0 subreleases (0 pages) were skipped due to the sum of short-term (0s) fluctuations and long-term (0s) trends. +HugePageFiller: 0.0000% of decisions confirmed correct, 0 pending (0.0000% of pages, 0 pending). +HugePageFiller: Subrelease stats last 10 min: total 282 pages subreleased (0 pages from partial allocs), 5 hugepages broken +)")); + + absl::flat_hash_set expected_pts, actual_pts; + for (const auto& alloc : allocs) { + expected_pts.insert(alloc.pt); + } + actual_pts.reserve(expected_pts.size()); + + bool dupe_seen = false; + { + PageHeapSpinLockHolder l; + filler_.ForEachHugePage([&](const PageTracker& pt) { + // We are holding the page heap lock, so refrain from allocating + // (including using Google Test helpers). + dupe_seen = dupe_seen || actual_pts.contains(&pt); + + if (actual_pts.size() == actual_pts.capacity()) { + return; + } + + TC_CHECK(actual_pts.insert(&pt).second); + }); + } + EXPECT_FALSE(dupe_seen); + EXPECT_THAT(actual_pts, Eq(expected_pts)); + + for (const auto& alloc : allocs) { + Delete(alloc); + } +} + +// Test Get and Put operations on the filler work correctly when number of +// objects are provided. We expect that Get requests with sparsely-accessed +// and densely-accessed spans are satisfied by their respective allocs. +TEST_P(FillerTest, GetsAndPuts) { + randomize_density_ = false; + absl::BitGen rng; + std::vector sparsely_accessed_allocs; + std::vector densely_accessed_allocs; + SpanAllocInfo sparsely_accessed_info = {1, AccessDensityPrediction::kSparse}; + SpanAllocInfo densely_accessed_info = {kMaxValidPages.raw_num(), + AccessDensityPrediction::kDense}; + static const HugeLength kNumHugePages = NHugePages(64); + for (auto i = Length(0); i < kNumHugePages.in_pages(); ++i) { + ASSERT_EQ(filler_.pages_allocated(), i); + // Randomly select whether the next span should be sparsely-accessed or + // densely-accessed. + if (absl::Bernoulli(rng, 0.5)) { + sparsely_accessed_allocs.push_back( + AllocateWithSpanAllocInfo(Length(1), sparsely_accessed_info)); + EXPECT_EQ( + filler_.pages_allocated(AccessDensityPrediction::kSparse).raw_num(), + sparsely_accessed_allocs.size()); + } else { + densely_accessed_allocs.push_back( + AllocateWithSpanAllocInfo(Length(1), densely_accessed_info)); + EXPECT_EQ( + filler_.pages_allocated(AccessDensityPrediction::kDense).raw_num(), + densely_accessed_allocs.size()); + } + } + EXPECT_GE(filler_.size(), kNumHugePages); + EXPECT_LE(filler_.size(), kNumHugePages + NHugePages(1)); + // clean up, check for failures + for (auto a : densely_accessed_allocs) { + Delete(a); + } + ASSERT_EQ(filler_.pages_allocated(AccessDensityPrediction::kDense), + Length(0)); + for (auto a : sparsely_accessed_allocs) { Delete(a); } + ASSERT_EQ(filler_.pages_allocated(AccessDensityPrediction::kSparse), + Length(0)); + ASSERT_EQ(filler_.pages_allocated(), Length(0)); +} + +// Test that filler tries to release pages from the sparsely-accessed allocs +// before attempting to release pages from the densely-accessed allocs. +TEST_P(FillerTest, ReleasePrioritySparseAndDenseAllocs) { + randomize_density_ = false; + const Length N = kPagesPerHugePage; + const Length kToBeReleased(4); + SpanAllocInfo sparsely_accessed_info = {1, AccessDensityPrediction::kSparse}; + auto sparsely_accessed_alloc = AllocateVectorWithSpanAllocInfo( + N - kToBeReleased, sparsely_accessed_info); + ASSERT_EQ(sparsely_accessed_alloc.size(), 1); + SpanAllocInfo densely_accessed_info = {kMaxValidPages.raw_num(), + AccessDensityPrediction::kDense}; + auto densely_accessed_alloc = + AllocateVectorWithSpanAllocInfo(N - kToBeReleased, densely_accessed_info); + for (auto a : densely_accessed_alloc) { + ASSERT_EQ(a.pt, densely_accessed_alloc.front().pt); + } + EXPECT_EQ(ReleasePages(Length(1)), kToBeReleased); + auto get_released_pages = [&](const std::vector& alloc) { + return alloc.front().pt->released_pages(); + }; + EXPECT_EQ(get_released_pages(sparsely_accessed_alloc), kToBeReleased); + EXPECT_EQ(get_released_pages(densely_accessed_alloc), Length(0)); + EXPECT_EQ(ReleasePages(Length(1)), kToBeReleased); + EXPECT_EQ(get_released_pages(densely_accessed_alloc), kToBeReleased); + EXPECT_EQ(get_released_pages(sparsely_accessed_alloc), kToBeReleased); + DeleteVector(sparsely_accessed_alloc); + DeleteVector(densely_accessed_alloc); +} + +// Repeatedly grow from FLAG_bytes to FLAG_bytes * growth factor, then shrink +// back down by random deletion. Then release partial hugepages until +// pageheap is bounded by some fraction of usage. Measure the blowup in VSS +// footprint. +TEST_P(FillerTest, BoundedVSS) { + randomize_density_ = false; + absl::BitGen rng; + const Length baseline = LengthFromBytes(absl::GetFlag(FLAGS_bytes)); + const Length peak = baseline * absl::GetFlag(FLAGS_growth_factor); + + std::vector allocs; + while (filler_.used_pages() < baseline) { + allocs.push_back(Allocate(Length(1))); + } + EXPECT_EQ(filler_.pages_allocated().raw_num(), allocs.size()); + + for (int i = 0; i < 10; ++i) { + while (filler_.used_pages() < peak) { + allocs.push_back(Allocate(Length(1))); + } + std::shuffle(allocs.begin(), allocs.end(), rng); + size_t limit = allocs.size(); + while (filler_.used_pages() > baseline) { + --limit; + Delete(allocs[limit]); + } + allocs.resize(limit); + ReleasePages(kMaxValidPages); + // Compare the total size of the hugepages in the filler and the allocated + // pages. + EXPECT_LE(filler_.size().in_bytes(), + 2 * filler_.pages_allocated().in_bytes()); + } + while (!allocs.empty()) { + Delete(allocs.back()); + allocs.pop_back(); + } +} + +// In b/265337869, we observed failures in the huge_page_filler due to mixing +// of hugepages between sparsely-accessed and densely-accessed allocs. The test +// below reproduces the buggy situation. +TEST_P(FillerTest, CounterUnderflow) { + randomize_density_ = false; + const Length N = kPagesPerHugePage; + const Length kToBeReleased(kPagesPerHugePage / 2 + Length(1)); + // First allocate a densely-accessed span, then release the remaining pages on + // the hugepage. This would move the hugepage to + // regular_alloc_partial_released_. + SpanAllocInfo densely_accessed_info = {kMaxValidPages.raw_num(), + AccessDensityPrediction::kDense}; + auto densely_accessed_alloc = + AllocateVectorWithSpanAllocInfo(N - kToBeReleased, densely_accessed_info); + EXPECT_EQ(ReleasePages(Length(kToBeReleased)), kToBeReleased); + // Then allocate a sparsely-accessed objects span. The previous hugepage + // should not be used since while allocating a sparsely-accessed objects span, + // we do not check densely-accessed alloc. + SpanAllocInfo sparsely_accessed_info = {1, AccessDensityPrediction::kSparse}; + auto sparsely_accessed_alloc = AllocateVectorWithSpanAllocInfo( + Length(kToBeReleased), sparsely_accessed_info); + for (const auto& a1 : sparsely_accessed_alloc) { + for (const auto& a2 : densely_accessed_alloc) { + EXPECT_NE(a1.pt, a2.pt); + } + } + DeleteVector(sparsely_accessed_alloc); + DeleteVector(densely_accessed_alloc); +} + +// In b/270916852, we observed that the huge_page_filler may fail to release +// memory when densely-accessed alloc is being used. This is due to the +// presence of partially released and fully released pages in densely-accessed +// alloc. The comparator in use does not make correct choices in presence of +// such hugepages. The test below reproduces the buggy situation. +TEST_P(FillerTest, ReleasePagesFromDenseAlloc) { + // Skip test for kSpansAllocated since the test assumes hugepages can be + // partially allocated. + if (std::get<0>(GetParam()) == + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test for kSpansAllocated"; + } + randomize_density_ = false; + constexpr size_t kCandidatesForReleasingMemory = + HugePageFiller::kCandidatesForReleasingMemory; + // Make kCandidate memory allocations of length kPagesPerHugepage/2 + 1. Note + // that a fresh hugepage will be used for each alloction. + const Length kToBeUsed1(kPagesPerHugePage / 2 + Length(1)); + std::vector allocs; + SpanAllocInfo densely_accessed_info = {kMaxValidPages.raw_num(), + AccessDensityPrediction::kDense}; + for (int i = 0; i < kCandidatesForReleasingMemory; ++i) { + std::vector temp = + AllocateVectorWithSpanAllocInfo(kToBeUsed1, densely_accessed_info); + allocs.insert(allocs.end(), temp.begin(), temp.end()); + } + // Release the free portion from these hugepages. + const Length kExpectedReleased1 = + kCandidatesForReleasingMemory * (kPagesPerHugePage - kToBeUsed1); + EXPECT_EQ(ReleasePages(kExpectedReleased1), kExpectedReleased1); + // Allocate kCandidate (does not really matter) more hugepages with + // allocations of length kPagesPerHugepage/2 + 2. These allocations also need + // one fresh hugepage each and they use more pages than the previously + // allocated hugepages. + const Length kToBeUsed2(kPagesPerHugePage / 2 + Length(2)); + for (int i = 0; i < kCandidatesForReleasingMemory; ++i) { + std::vector temp = + AllocateVectorWithSpanAllocInfo(kToBeUsed2, densely_accessed_info); + allocs.insert(allocs.end(), temp.begin(), temp.end()); + } + // Try to release more memory. We should continue to make progress and return + // all of the pages we tried to. + const Length kExpectedReleased2 = + kCandidatesForReleasingMemory * (kPagesPerHugePage - kToBeUsed2); + EXPECT_EQ(ReleasePages(kExpectedReleased2), kExpectedReleased2); + EXPECT_EQ(filler_.free_pages(), Length(0)); + + for (auto alloc : allocs) { + Delete(alloc); + } +} + +TEST_P(FillerTest, ReleasePagesFromDenseAlloc_SpansAllocated) { + // Skip test for kSpansAllocated since the test assumes hugepages can be + // partially allocated. + if (std::get<0>(GetParam()) != + HugePageFillerDenseTrackerType::kSpansAllocated) { + GTEST_SKIP() << "Skipping test for !kSpansAllocated"; + } + randomize_density_ = false; + constexpr size_t kCandidatesForReleasingMemory = + HugePageFiller::kCandidatesForReleasingMemory; + // Make kCandidate memory allocations of length kPagesPerHugepage/2 + 1. Note + // that a fresh hugepage will be used for each alloction. + const Length kToBeUsed1(kPagesPerHugePage / 2 + Length(1)); + std::vector allocs; + std::vector allocs_to_be_released; + SpanAllocInfo densely_accessed_info = {kMaxValidPages.raw_num(), + AccessDensityPrediction::kDense}; + for (int i = 0; i < kCandidatesForReleasingMemory; ++i) { + std::vector temp = + AllocateVectorWithSpanAllocInfo(kToBeUsed1, densely_accessed_info); + allocs.insert(allocs.end(), temp.begin(), temp.end()); + temp = AllocateVectorWithSpanAllocInfo(kPagesPerHugePage - kToBeUsed1, + densely_accessed_info); + allocs_to_be_released.insert(allocs_to_be_released.end(), temp.begin(), + temp.end()); + } + // Release the allocs that were made so that the actual we care about are on + // fresh hugepages. + DeleteVector(allocs_to_be_released); + allocs_to_be_released.clear(); + // Release the free portion from these hugepages. + const Length kExpectedReleased1 = + kCandidatesForReleasingMemory * (kPagesPerHugePage - kToBeUsed1); + EXPECT_EQ(ReleasePages(kExpectedReleased1), kExpectedReleased1); + // Fill up the hugepages again so that subsequent allocations are made on + // fresh hugepages. + for (int i = 0; i < kCandidatesForReleasingMemory; ++i) { + std::vector temp = AllocateVectorWithSpanAllocInfo( + kPagesPerHugePage - kToBeUsed1, densely_accessed_info); + allocs_to_be_released.insert(allocs_to_be_released.end(), temp.begin(), + temp.end()); + } + // Allocate kCandidate (does not really matter) more hugepages with + // allocations of length kPagesPerHugepage/2 + 2. These allocations also need + // one fresh hugepage each and they use more pages than the previously + // allocated hugepages. + std::vector allocs_to_be_released_2; + const Length kToBeUsed2(kPagesPerHugePage / 2 + Length(2)); + for (int i = 0; i < kCandidatesForReleasingMemory; ++i) { + std::vector temp = + AllocateVectorWithSpanAllocInfo(kToBeUsed2, densely_accessed_info); + allocs.insert(allocs.end(), temp.begin(), temp.end()); + temp = AllocateVectorWithSpanAllocInfo(kPagesPerHugePage - kToBeUsed2, + densely_accessed_info); + allocs_to_be_released_2.insert(allocs_to_be_released_2.end(), temp.begin(), + temp.end()); + } + // Release the allocs that were made so that the actual we care about are on + // fresh hugepages. + DeleteVector(allocs_to_be_released_2); + allocs_to_be_released_2.clear(); + // Try to release more memory. We should continue to make progress and return + // all of the pages we tried to. + const Length kExpectedReleased2 = + kCandidatesForReleasingMemory * (kPagesPerHugePage - kToBeUsed2); + EXPECT_EQ(ReleasePages(kExpectedReleased2), kExpectedReleased2); + EXPECT_EQ(filler_.free_pages(), Length(0)); + + for (auto alloc : allocs) { + Delete(alloc); + } + DeleteVector(allocs_to_be_released); +} + +TEST_P(FillerTest, ReleasedPagesStatistics) { + constexpr Length N = kPagesPerHugePage / 4; + + std::vector a1 = AllocateVector(N); + ASSERT_TRUE(!a1.empty()); + + const Length released = ReleasePages(kPagesPerHugePage); + // We should have released some memory. + EXPECT_NE(released, Length(0)); + // Since we have only a single allocation, its pages should all be used on + // released pages. + EXPECT_EQ(filler_.size(), NHugePages(1)); + EXPECT_EQ(filler_.used_pages(), N); + EXPECT_EQ(filler_.free_pages(), Length(0)); + EXPECT_EQ(filler_.used_pages_in_released(), N); + EXPECT_EQ(filler_.used_pages_in_any_subreleased(), N); + + // Now differentiate fully released from partially released. Make an + // allocation and return it. + std::vector a2 = + AllocateVectorWithSpanAllocInfo(N, a1.front().span_alloc_info); + + // We now have N pages for a1, N pages for a2, and 2N pages + // released. + EXPECT_EQ(filler_.size(), NHugePages(1)); + EXPECT_EQ(filler_.used_pages(), 2 * N); + EXPECT_EQ(filler_.free_pages(), Length(0)); + EXPECT_EQ(filler_.used_pages_in_released(), 2 * N); + EXPECT_EQ(filler_.used_pages_in_any_subreleased(), 2 * N); + + DeleteVector(a2); + + // We now have N pages for a1, N pages free (but mapped), and 2N pages + // released. + EXPECT_EQ(filler_.used_pages(), N); + EXPECT_EQ(filler_.free_pages(), N); + EXPECT_EQ(filler_.used_pages_in_released(), Length(0)); + EXPECT_EQ(filler_.used_pages_in_any_subreleased(), N); + + DeleteVector(a1); } -INSTANTIATE_TEST_SUITE_P(All, FillerTest, - testing::Values(FillerPartialRerelease::Return, - FillerPartialRerelease::Retain)); +INSTANTIATE_TEST_SUITE_P( + All, FillerTest, + testing::Combine(testing::Values( + HugePageFillerDenseTrackerType::kLongestFreeRangeAndChunks, + HugePageFillerDenseTrackerType::kSpansAllocated))); + +TEST(SkipSubreleaseIntervalsTest, EmptyIsNotEnabled) { + // When we have a limit hit, we pass SkipSubreleaseIntervals{} to the + // filler. Make sure it doesn't signal that we should skip the limit. + EXPECT_FALSE(SkipSubreleaseIntervals{}.SkipSubreleaseEnabled()); +} } // namespace } // namespace tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_page_subrelease.h b/contrib/libs/tcmalloc/tcmalloc/huge_page_subrelease.h new file mode 100644 index 000000000000..fcdf018ec2c1 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/huge_page_subrelease.h @@ -0,0 +1,731 @@ +#pragma clang system_header +// Copyright 2019 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_HUGE_PAGE_SUBRELEASE_H_ +#define TCMALLOC_HUGE_PAGE_SUBRELEASE_H_ + +#include +#include + +#include + +#include "absl/base/optimization.h" +#include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "tcmalloc/common.h" +#include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/clock.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/timeseries_tracker.h" +#include "tcmalloc/pages.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +// This and the following classes implement the adaptive hugepage subrelease +// mechanism and realized fragmentation metric described in "Adaptive Hugepage +// Subrelease for Non-moving Memory Allocators in Warehouse-Scale Computers" +// (ISMM 2021). + +// Tracks correctness of skipped subrelease decisions over time. +template +class SkippedSubreleaseCorrectnessTracker { + public: + struct SkippedSubreleaseDecision { + Length pages; // Number of pages we skipped subreleasing. + size_t count; // Number of times we skipped a subrelease. + + SkippedSubreleaseDecision() : pages(0), count(0) {} + explicit SkippedSubreleaseDecision(Length pages) : pages(pages), count(1) {} + explicit SkippedSubreleaseDecision(Length pages, size_t count) + : pages(pages), count(count) {} + + SkippedSubreleaseDecision& operator+=(SkippedSubreleaseDecision rhs) { + pages += rhs.pages; + count += rhs.count; + return *this; + } + + static SkippedSubreleaseDecision Zero() { + return SkippedSubreleaseDecision(); + } + }; + + explicit constexpr SkippedSubreleaseCorrectnessTracker(Clock clock, + absl::Duration w) + : window_(w), + epoch_length_(window_ / kEpochs), + last_confirmed_peak_(0), + tracker_(clock, w) {} + + // Not copyable or movable + SkippedSubreleaseCorrectnessTracker( + const SkippedSubreleaseCorrectnessTracker&) = delete; + SkippedSubreleaseCorrectnessTracker& operator=( + const SkippedSubreleaseCorrectnessTracker&) = delete; + + void ReportSkippedSubreleasePages(Length skipped_pages, Length peak_pages, + absl::Duration summary_interval) { + total_skipped_ += SkippedSubreleaseDecision(skipped_pages); + pending_skipped_ += SkippedSubreleaseDecision(skipped_pages); + + SkippedSubreleaseUpdate update; + update.decision = SkippedSubreleaseDecision(skipped_pages); + update.num_pages_at_decision = peak_pages; + update.correctness_interval_epochs = summary_interval / epoch_length_; + tracker_.Report(update); + } + + void ReportUpdatedPeak(Length current_peak) { + // Record this peak for the current epoch (so we don't double-count correct + // predictions later) and advance the tracker. + SkippedSubreleaseUpdate update; + update.confirmed_peak = current_peak; + if (tracker_.Report(update)) { + // Also keep track of the largest peak we have confirmed this epoch. + last_confirmed_peak_ = Length(0); + } + + // Recompute currently pending decisions. + pending_skipped_ = SkippedSubreleaseDecision::Zero(); + + Length largest_peak_already_confirmed = last_confirmed_peak_; + + tracker_.IterBackwards( + [&](size_t offset, const SkippedSubreleaseEntry& e) { + // Do not clear any decisions in the current epoch. + if (offset == 0) { + return; + } + + if (e.decisions.count > 0 && + e.max_num_pages_at_decision > largest_peak_already_confirmed && + offset <= e.correctness_interval_epochs) { + if (e.max_num_pages_at_decision <= current_peak) { + // We can confirm a subrelease decision as correct and it had not + // been confirmed correct by an earlier peak yet. + correctly_skipped_ += e.decisions; + } else { + pending_skipped_ += e.decisions; + } + } + + // Did we clear any earlier decisions based on a peak in this epoch? + // Keep track of the peak, so we do not clear them again. + largest_peak_already_confirmed = + std::max(largest_peak_already_confirmed, e.max_confirmed_peak); + }, + -1); + + last_confirmed_peak_ = std::max(last_confirmed_peak_, current_peak); + } + + inline SkippedSubreleaseDecision total_skipped() const { + return total_skipped_; + } + + inline SkippedSubreleaseDecision correctly_skipped() const { + return correctly_skipped_; + } + + inline SkippedSubreleaseDecision pending_skipped() const { + return pending_skipped_; + } + + private: + struct SkippedSubreleaseUpdate { + // A subrelease decision that was made at this time step: How much did we + // decide not to release? + SkippedSubreleaseDecision decision; + + // What does our future demand have to be for this to be correct? If there + // were multiple subrelease decisions in the same epoch, use the max. + Length num_pages_at_decision; + + // How long from the time of the decision do we have before the decision + // will be determined incorrect? + int64_t correctness_interval_epochs = 0; + + // At this time step, we confirmed a demand peak at this level, which means + // all subrelease decisions in earlier time steps that had peak_demand_pages + // <= this confirmed_peak were confirmed correct and don't need to be + // considered again in the future. + Length confirmed_peak; + }; + + struct SkippedSubreleaseEntry { + SkippedSubreleaseDecision decisions = SkippedSubreleaseDecision::Zero(); + Length max_num_pages_at_decision; + int64_t correctness_interval_epochs = 0; + Length max_confirmed_peak; + + static SkippedSubreleaseEntry Nil() { return SkippedSubreleaseEntry(); } + + void Report(SkippedSubreleaseUpdate e) { + decisions += e.decision; + correctness_interval_epochs = + std::max(correctness_interval_epochs, e.correctness_interval_epochs); + max_num_pages_at_decision = + std::max(max_num_pages_at_decision, e.num_pages_at_decision); + max_confirmed_peak = std::max(max_confirmed_peak, e.confirmed_peak); + } + }; + + const absl::Duration window_; + const absl::Duration epoch_length_; + + // The largest peak we processed this epoch. This is required to avoid us + // double-counting correctly predicted decisions. + Length last_confirmed_peak_; + + SkippedSubreleaseDecision total_skipped_; + SkippedSubreleaseDecision correctly_skipped_; + SkippedSubreleaseDecision pending_skipped_; + + TimeSeriesTracker + tracker_; +}; + +struct SkipSubreleaseIntervals { + // Interval that locates recent short-term demand fluctuation. + absl::Duration short_interval; + // Interval that locates recent long-term demand trend. + absl::Duration long_interval; + // Checks if the skip subrelease feature is enabled. + bool SkipSubreleaseEnabled() const { + if (short_interval != absl::ZeroDuration() || + long_interval != absl::ZeroDuration()) { + return true; + } + return false; + } +}; + +struct SubreleaseStats { + Length total_pages_subreleased; // cumulative since startup + Length total_partial_alloc_pages_subreleased; // cumulative since startup + Length num_pages_subreleased; + Length num_partial_alloc_pages_subreleased; + HugeLength total_hugepages_broken{NHugePages(0)}; // cumulative since startup + HugeLength num_hugepages_broken{NHugePages(0)}; + + bool is_limit_hit = false; + // Keep these limit-related stats cumulative since startup only + Length total_pages_subreleased_due_to_limit; + HugeLength total_hugepages_broken_due_to_limit{NHugePages(0)}; + + void reset() { + total_pages_subreleased += num_pages_subreleased; + total_partial_alloc_pages_subreleased += + num_partial_alloc_pages_subreleased; + total_hugepages_broken += num_hugepages_broken; + num_pages_subreleased = Length(0); + num_partial_alloc_pages_subreleased = Length(0); + num_hugepages_broken = NHugePages(0); + } + + // Must be called at the beginning of each subrelease request + void set_limit_hit(bool value) { is_limit_hit = value; } + + // This only has a well-defined meaning within ReleaseCandidates where + // set_limit_hit() has been called earlier. Do not use anywhere else. + bool limit_hit() { return is_limit_hit; } +}; + +// Track subrelease statistics over a time window. +template +class SubreleaseStatsTracker { + public: + enum Type { + kRegular, + kSparse = kRegular, + kDense, + kDonated, + kPartialReleased, + kReleased, + kNumTypes + }; + + struct SubreleaseStats { + Length num_pages; + Length free_pages; + Length unmapped_pages; + Length used_pages_in_subreleased_huge_pages; + HugeLength huge_pages[kNumTypes]; + Length num_pages_subreleased; + Length num_partial_alloc_pages_subreleased; + HugeLength num_hugepages_broken = NHugePages(0); + + HugeLength total_huge_pages() const { + HugeLength total_huge_pages; + for (int i = 0; i < kNumTypes; i++) { + total_huge_pages += huge_pages[i]; + } + return total_huge_pages; + } + }; + + struct NumberOfFreePages { + Length free; + Length free_backed; + }; + + explicit constexpr SubreleaseStatsTracker(Clock clock, absl::Duration w, + absl::Duration summary_interval) + : summary_interval_(summary_interval), + window_(w), + epoch_length_(window_ / kEpochs), + tracker_(clock, w), + skipped_subrelease_correctness_(clock, w) { + // The summary_interval is used in two trackers: SubreleaseStatsTracker for + // evaluating realized fragmentation, and + // SkippedSubreleaseCorrectnessTracker for evaluating the correctness of + // skipped subrelease. Here we check the length of the two trackers are + // sufficient for the evaluation. + TC_ASSERT_LE(summary_interval, w); + } + + // Not copyable or movable + SubreleaseStatsTracker(const SubreleaseStatsTracker&) = delete; + SubreleaseStatsTracker& operator=(const SubreleaseStatsTracker&) = delete; + + void Report(const SubreleaseStats& stats) { + if (ABSL_PREDICT_FALSE(tracker_.Report(stats))) { + if (ABSL_PREDICT_FALSE(pending_skipped().count > 0)) { + // Consider the peak within the just completed epoch to confirm the + // correctness of any recent subrelease decisions. + skipped_subrelease_correctness_.ReportUpdatedPeak(std::max( + stats.num_pages, + tracker_.GetEpochAtOffset(1).stats[kStatsAtMaxDemand].num_pages)); + } + } + } + + void Print(Printer& out, absl::string_view field) const; + void PrintSubreleaseStatsInPbtxt(PbtxtRegion& hpaa, + absl::string_view field) const; + void PrintTimeseriesStatsInPbtxt(PbtxtRegion& hpaa, + absl::string_view field) const; + + // Calculates demand requirements for the skip subrelease: we do not + // subrelease if the number of free pages are than (or equal to) the demand + // computed by GetRecentDemand. The demand requirement is the sum of + // short-term demand fluctuation peak with in the last and + // long-term demand trend in the previous . When both are set, + // short_interval should be (significantly) shorter or equal to long_interval + // to avoid realized fragmentation caused by non-recent (short-term) demand + // spikes. The demand is capped to the peak observed in the time series. + Length GetRecentDemand(absl::Duration short_interval, + absl::Duration long_interval) { + return GetRecentDemand(short_interval, long_interval, window_); + } + + // Calculates demand requirements for the skip subrelease: we do not + // subrelease if the number of free pages are than (or equal to) the demand + // computed by GetRecentDemand. The demand requirement is the sum of + // short-term demand fluctuation peak with in the last and + // long-term demand trend in the previous . When both are set, + // short_interval should be (significantly) shorter or equal to long_interval + // to avoid realized fragmentation caused by non-recent (short-term) demand + // spikes. The demand is capped to the peak observed in the time series over + // the last . + Length GetRecentDemand(absl::Duration short_interval, + absl::Duration long_interval, + absl::Duration peak_interval) { + Length demand_trend = + CalculateCombinedDemandTrend(short_interval, long_interval); + Length demand_peak = CalculateDemandPeak(peak_interval); + return std::min(demand_peak, demand_trend); + } + + // Reports a skipped subrelease, which is evaluated by coming peaks within the + // realized fragmentation interval. The purpose is these skipped pages would + // only create realized fragmentation if peaks in that interval are + // smaller than peak_pages. + void ReportSkippedSubreleasePages(Length pages, Length peak_pages) { + ReportSkippedSubreleasePages(pages, peak_pages, summary_interval_); + } + + // Reports a skipped subrelease, which is evaluated by coming peaks within the + // given time interval. + void ReportSkippedSubreleasePages(Length pages, Length peak_pages, + absl::Duration summary_interval) { + if (pages == Length(0)) { + return; + } + skipped_subrelease_correctness_.ReportSkippedSubreleasePages( + pages, peak_pages, summary_interval); + } + + inline typename SkippedSubreleaseCorrectnessTracker< + kEpochs>::SkippedSubreleaseDecision + total_skipped() const { + return skipped_subrelease_correctness_.total_skipped(); + } + + inline typename SkippedSubreleaseCorrectnessTracker< + kEpochs>::SkippedSubreleaseDecision + correctly_skipped() const { + return skipped_subrelease_correctness_.correctly_skipped(); + } + + inline typename SkippedSubreleaseCorrectnessTracker< + kEpochs>::SkippedSubreleaseDecision + pending_skipped() const { + return skipped_subrelease_correctness_.pending_skipped(); + } + + // Returns the minimum number of free pages throughout the tracker period. + // The first value of the pair is the number of all free pages, the second + // value contains only the backed ones. + NumberOfFreePages min_free_pages(absl::Duration w) const { + NumberOfFreePages mins; + mins.free = Length::max(); + mins.free_backed = Length::max(); + + int64_t num_epochs = std::clamp(w / epoch_length_, int64_t{0}, + static_cast(kEpochs)); + + tracker_.IterBackwards( + [&](size_t offset, const SubreleaseStatsEntry& e) { + if (!e.empty()) { + mins.free = std::min(mins.free, e.min_free_pages); + mins.free_backed = + std::min(mins.free_backed, e.min_free_backed_pages); + } + }, + num_epochs); + mins.free = (mins.free == Length::max()) ? Length(0) : mins.free; + mins.free_backed = + (mins.free_backed == Length::max()) ? Length(0) : mins.free_backed; + return mins; + } + + // Returns the realized fragmentation, which is the minimum number of free + // backed pages over the last summary_interval_ (default 5 min). + Length RealizedFragmentation() const { + Length min_free_backed = Length::max(); + int64_t num_epochs = + std::min(summary_interval_ / epoch_length_, kEpochs); + tracker_.IterBackwards( + [&](size_t offset, const SubreleaseStatsEntry& e) { + if (!e.empty()) { + min_free_backed = + std::min(min_free_backed, e.min_free_backed_pages); + } + }, + num_epochs); + min_free_backed = + (min_free_backed == Length::max()) ? Length(0) : min_free_backed; + return min_free_backed; + } + + private: + // We collect subrelease statistics at four "interesting points" within each + // time step: at min/max demand of pages and at min/max use of hugepages. This + // allows us to approximate the envelope of the different metrics. + enum StatsType { kStatsAtMinDemand, kStatsAtMaxDemand, kNumStatsTypes }; + + struct SubreleaseStatsEntry { + // Collect stats at "interesting points" (minimum/maximum page demand + // and at minimum/maximum usage of huge pages). + SubreleaseStats stats[kNumStatsTypes] = {}; + static constexpr Length kDefaultValue = Length::max(); + Length min_free_pages = kDefaultValue; + Length min_free_backed_pages = kDefaultValue; + Length num_pages_subreleased; + Length num_partial_alloc_pages_subreleased; + HugeLength num_hugepages_broken = NHugePages(0); + + static SubreleaseStatsEntry Nil() { return SubreleaseStatsEntry(); } + + void Report(const SubreleaseStats& e) { + if (empty()) { + for (int i = 0; i < kNumStatsTypes; i++) { + stats[i] = e; + } + } + + if (e.num_pages < stats[kStatsAtMinDemand].num_pages) { + stats[kStatsAtMinDemand] = e; + } + + if (e.num_pages > stats[kStatsAtMaxDemand].num_pages) { + stats[kStatsAtMaxDemand] = e; + } + + min_free_pages = + std::min(min_free_pages, e.free_pages + e.unmapped_pages); + min_free_backed_pages = std::min(min_free_backed_pages, e.free_pages); + + // Subrelease stats + num_pages_subreleased += e.num_pages_subreleased; + num_partial_alloc_pages_subreleased += + e.num_partial_alloc_pages_subreleased; + num_hugepages_broken += e.num_hugepages_broken; + } + + bool empty() const { return min_free_pages == kDefaultValue; } + }; + + // Gets the peak demand recorded in the time series over the last + // . + Length CalculateDemandPeak(absl::Duration peak_interval) { + Length max_demand_pages; + int64_t num_epochs = + std::min(peak_interval / epoch_length_, kEpochs); + tracker_.IterBackwards( + [&](size_t offset, const SubreleaseStatsEntry& e) { + if (!e.empty()) { + // Identify the maximum number of demand pages we have seen within + // the time interval. + if (e.stats[kStatsAtMaxDemand].num_pages > max_demand_pages) { + max_demand_pages = e.stats[kStatsAtMaxDemand].num_pages; + } + } + }, + num_epochs); + return max_demand_pages; + } + + // Gets the combined demand trend, which is the sum of the maximum demand + // difference in and the maxmin demand in . + Length CalculateCombinedDemandTrend(absl::Duration short_interval, + absl::Duration long_interval) { + if (short_interval != absl::ZeroDuration() && + long_interval != absl::ZeroDuration()) { + short_interval = std::min(short_interval, long_interval); + } + last_skip_subrelease_intervals_.short_interval = + std::min(short_interval, window_); + last_skip_subrelease_intervals_.long_interval = + std::min(long_interval, window_); + Length short_term_fluctuation_pages, long_term_trend_pages; + int short_epochs = std::min(short_interval / epoch_length_, kEpochs); + int long_epochs = std::min(long_interval / epoch_length_, kEpochs); + + tracker_.IterBackwards( + [&](size_t offset, const SubreleaseStatsEntry& e) { + if (!e.empty()) { + Length demand_difference = e.stats[kStatsAtMaxDemand].num_pages - + e.stats[kStatsAtMinDemand].num_pages; + // Identifies the highest demand fluctuation (i.e., difference + // between max_demand and min_demand) that we have seen within the + // time interval. + if (demand_difference > short_term_fluctuation_pages) { + short_term_fluctuation_pages = demand_difference; + } + } + }, + short_epochs); + tracker_.IterBackwards( + [&](size_t offset, const SubreleaseStatsEntry& e) { + if (!e.empty()) { + // Identifies the long-term demand peak (i.e., largest minimum + // demand) that we have seen within the time interval. + if (e.stats[kStatsAtMinDemand].num_pages > long_term_trend_pages) { + long_term_trend_pages = e.stats[kStatsAtMinDemand].num_pages; + } + } + }, + long_epochs); + return short_term_fluctuation_pages + long_term_trend_pages; + } + + // The tracker reports pages that have been free for at least this interval, + // as well as peaks within this interval. The interval is also used for + // deciding correctness of skipped subreleases by associating past skipping + // decisions to peaks within this interval. + const absl::Duration summary_interval_; + + const absl::Duration window_; + const absl::Duration epoch_length_; + + TimeSeriesTracker tracker_; + SkippedSubreleaseCorrectnessTracker skipped_subrelease_correctness_; + + // Records most recent intervals for skipping subreleases, plus expected next + // intervals for evaluating skipped subreleases. All for reporting and + // debugging only. + SkipSubreleaseIntervals last_skip_subrelease_intervals_; +}; + +// Evaluates a/b, avoiding division by zero. +inline double safe_div(Length a, Length b) { + return safe_div(a.raw_num(), b.raw_num()); +} + +template +void SubreleaseStatsTracker::Print(Printer& out, + absl::string_view field) const { + NumberOfFreePages free_pages = min_free_pages(summary_interval_); + out.printf("%s: time series over %d min interval\n\n", field, + absl::ToInt64Minutes(summary_interval_)); + + // Realized fragmentation is equivalent to backed minimum free pages over a + // 5-min interval. It is printed for convenience but not included in pbtxt. + out.printf("%s: realized fragmentation: %.1f MiB\n", field, + free_pages.free_backed.in_mib()); + out.printf("%s: minimum free pages: %zu (%zu backed)\n", field, + free_pages.free.raw_num(), free_pages.free_backed.raw_num()); + + SubreleaseStatsEntry at_peak_demand; + + tracker_.IterBackwards( + [&](size_t offset, const SubreleaseStatsEntry& e) { + if (!e.empty()) { + if (at_peak_demand.empty() || + at_peak_demand.stats[kStatsAtMaxDemand].num_pages < + e.stats[kStatsAtMaxDemand].num_pages) { + at_peak_demand = e; + } + } + }, + summary_interval_ / epoch_length_); + + out.printf( + "%s: at peak demand: %zu pages (and %zu free, %zu unmapped)\n" + "%s: at peak demand: %zu hps (%zu regular, %zu donated, " + "%zu partial, %zu released)\n", + field, at_peak_demand.stats[kStatsAtMaxDemand].num_pages.raw_num(), + at_peak_demand.stats[kStatsAtMaxDemand].free_pages.raw_num(), + at_peak_demand.stats[kStatsAtMaxDemand].unmapped_pages.raw_num(), field, + at_peak_demand.stats[kStatsAtMaxDemand].total_huge_pages().raw_num(), + at_peak_demand.stats[kStatsAtMaxDemand].huge_pages[kRegular].raw_num(), + at_peak_demand.stats[kStatsAtMaxDemand].huge_pages[kDonated].raw_num(), + at_peak_demand.stats[kStatsAtMaxDemand] + .huge_pages[kPartialReleased] + .raw_num(), + at_peak_demand.stats[kStatsAtMaxDemand].huge_pages[kReleased].raw_num()); + + out.printf( + "\n%s: Since the start of the execution, %zu subreleases (%zu" + " pages) were skipped due to the sum of short-term (%ds)" + " fluctuations and long-term (%ds) trends.\n", + field, total_skipped().count, total_skipped().pages.raw_num(), + absl::ToInt64Seconds(last_skip_subrelease_intervals_.short_interval), + absl::ToInt64Seconds(last_skip_subrelease_intervals_.long_interval)); + + Length skipped_pages = total_skipped().pages - pending_skipped().pages; + double correctly_skipped_pages_percentage = + safe_div(100.0 * correctly_skipped().pages, skipped_pages); + + size_t skipped_count = total_skipped().count - pending_skipped().count; + double correctly_skipped_count_percentage = + safe_div(100.0 * correctly_skipped().count, skipped_count); + + out.printf( + "%s: %.4f%% of decisions confirmed correct, %zu " + "pending (%.4f%% of pages, %zu pending).\n", + field, correctly_skipped_count_percentage, pending_skipped().count, + correctly_skipped_pages_percentage, pending_skipped().pages.raw_num()); + + // Print subrelease stats + Length total_subreleased; + Length total_partial_alloc_pages_subreleased; + HugeLength total_broken = NHugePages(0); + tracker_.Iter( + [&](size_t offset, const SubreleaseStatsEntry& e) { + total_subreleased += e.num_pages_subreleased; + total_partial_alloc_pages_subreleased += + e.num_partial_alloc_pages_subreleased; + total_broken += e.num_hugepages_broken; + }, + tracker_.kSkipEmptyEntries); + out.printf( + "%s: Subrelease stats last %d min: total " + "%zu pages subreleased (%zu pages from partial allocs), " + "%zu hugepages broken\n", + field, static_cast(absl::ToInt64Minutes(window_)), + total_subreleased.raw_num(), + total_partial_alloc_pages_subreleased.raw_num(), total_broken.raw_num()); +} + +template +void SubreleaseStatsTracker::PrintSubreleaseStatsInPbtxt( + PbtxtRegion& hpaa, absl::string_view field) const { + PbtxtRegion region = hpaa.CreateSubRegion(field); + region.PrintI64("skipped_subrelease_short_interval_ms", + absl::ToInt64Milliseconds( + last_skip_subrelease_intervals_.short_interval)); + region.PrintI64( + "skipped_subrelease_long_interval_ms", + absl::ToInt64Milliseconds(last_skip_subrelease_intervals_.long_interval)); + region.PrintI64("skipped_subrelease_pages", total_skipped().pages.raw_num()); + region.PrintI64("correctly_skipped_subrelease_pages", + correctly_skipped().pages.raw_num()); + region.PrintI64("pending_skipped_subrelease_pages", + pending_skipped().pages.raw_num()); + region.PrintI64("skipped_subrelease_count", total_skipped().count); + region.PrintI64("correctly_skipped_subrelease_count", + correctly_skipped().count); + region.PrintI64("pending_skipped_subrelease_count", pending_skipped().count); +} + +template +void SubreleaseStatsTracker::PrintTimeseriesStatsInPbtxt( + PbtxtRegion& hpaa, absl::string_view field) const { + PbtxtRegion region = hpaa.CreateSubRegion(field); + region.PrintI64("window_ms", absl::ToInt64Milliseconds(epoch_length_)); + region.PrintI64("epochs", kEpochs); + + NumberOfFreePages free_pages = min_free_pages(summary_interval_); + region.PrintI64("min_free_pages_interval_ms", + absl::ToInt64Milliseconds(summary_interval_)); + region.PrintI64("min_free_pages", free_pages.free.raw_num()); + region.PrintI64("min_free_backed_pages", free_pages.free_backed.raw_num()); + + static const char* labels[kNumStatsTypes] = {"at_minimum_demand", + "at_maximum_demand"}; + + tracker_.Iter( + [&](size_t offset, const SubreleaseStatsEntry& e) GOOGLE_MALLOC_SECTION { + auto subregion = region.CreateSubRegion("measurements"); + subregion.PrintI64("epoch", offset); + subregion.PrintI64("min_free_pages", e.min_free_pages.raw_num()); + subregion.PrintI64("min_free_backed_pages", + e.min_free_backed_pages.raw_num()); + subregion.PrintI64("num_pages_subreleased", + e.num_pages_subreleased.raw_num()); + subregion.PrintI64("num_hugepages_broken", + e.num_hugepages_broken.raw_num()); + subregion.PrintI64("partial_alloc_pages_subreleased", + e.num_partial_alloc_pages_subreleased.raw_num()); + for (int i = 0; i < kNumStatsTypes; i++) { + auto m = subregion.CreateSubRegion(labels[i]); + SubreleaseStats stats = e.stats[i]; + m.PrintI64("num_pages", stats.num_pages.raw_num()); + m.PrintI64("regular_huge_pages", + stats.huge_pages[kRegular].raw_num()); + m.PrintI64("donated_huge_pages", + stats.huge_pages[kDonated].raw_num()); + m.PrintI64("partial_released_huge_pages", + stats.huge_pages[kPartialReleased].raw_num()); + m.PrintI64("released_huge_pages", + stats.huge_pages[kReleased].raw_num()); + m.PrintI64("used_pages_in_subreleased_huge_pages", + stats.used_pages_in_subreleased_huge_pages.raw_num()); + } + }, + tracker_.kSkipEmptyEntries); +} + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_HUGE_PAGE_SUBRELEASE_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_page_subrelease_test.cc b/contrib/libs/tcmalloc/tcmalloc/huge_page_subrelease_test.cc new file mode 100644 index 000000000000..ad4a263c6645 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/huge_page_subrelease_test.cc @@ -0,0 +1,351 @@ +// Copyright 2019 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/huge_page_subrelease.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include // NOLINT(build/c++11) +#include +#include +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/algorithm/container.h" +#include "absl/base/attributes.h" +#include "absl/base/internal/sysinfo.h" +#include "absl/base/macros.h" +#include "absl/container/flat_hash_set.h" +#include "absl/flags/flag.h" +#include "absl/memory/memory.h" +#include "absl/random/random.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" +#include "absl/synchronization/blocking_counter.h" +#include "absl/synchronization/mutex.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "tcmalloc/common.h" +#include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/clock.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/span.h" +#include "tcmalloc/stats.h" + +using tcmalloc::tcmalloc_internal::Length; +using testing::StrEq; + +namespace tcmalloc { +namespace tcmalloc_internal { +namespace { + +class StatsTrackerTest : public testing::Test { + private: + static int64_t clock_; + static int64_t FakeClock() { return clock_; } + static double GetFakeClockFrequency() { + return absl::ToDoubleNanoseconds(absl::Seconds(2)); + } + + protected: + static constexpr absl::Duration kWindow = absl::Minutes(10); + + using StatsTrackerType = SubreleaseStatsTracker<16>; + StatsTrackerType tracker_{ + Clock{.now = FakeClock, .freq = GetFakeClockFrequency}, kWindow, + absl::Minutes(5)}; + + void Advance(absl::Duration d) { + clock_ += static_cast(absl::ToDoubleSeconds(d) * + GetFakeClockFrequency()); + } + + // Generates four data points for the tracker that represent "interesting" + // points (i.e., min/max pages demand, min/max hugepages). + void GenerateInterestingPoints(Length num_pages, HugeLength num_hugepages, + Length num_free_pages); + + // Generates a data point with a particular amount of demand pages, while + // ignoring the specific number of hugepages. + void GenerateDemandPoint(Length num_pages, Length num_free_pages); + + void SetUp() override { + // Resets the clock used by SubreleaseStatsTracker, allowing each test + // starts in epoch 0. + clock_ = 0; + } +}; + +int64_t StatsTrackerTest::clock_{0}; + +void StatsTrackerTest::GenerateInterestingPoints(Length num_pages, + HugeLength num_hugepages, + Length num_free_pages) { + for (int i = 0; i <= 1; ++i) { + for (int j = 0; j <= 1; ++j) { + StatsTrackerType::SubreleaseStats stats; + stats.num_pages = num_pages + Length((i == 0) ? 4 : 8 * j); + stats.free_pages = num_free_pages + Length(10 * i + j); + stats.unmapped_pages = Length(10); + stats.used_pages_in_subreleased_huge_pages = num_pages; + stats.huge_pages[StatsTrackerType::kRegular] = + num_hugepages + ((i == 1) ? NHugePages(4) : NHugePages(8) * j); + stats.huge_pages[StatsTrackerType::kDonated] = num_hugepages; + stats.huge_pages[StatsTrackerType::kPartialReleased] = NHugePages(i); + stats.huge_pages[StatsTrackerType::kReleased] = NHugePages(j); + tracker_.Report(stats); + } + } +} + +void StatsTrackerTest::GenerateDemandPoint(Length num_pages, + Length num_free_pages) { + HugeLength hp = NHugePages(1); + StatsTrackerType::SubreleaseStats stats; + stats.num_pages = num_pages; + stats.free_pages = num_free_pages; + stats.unmapped_pages = Length(0); + stats.used_pages_in_subreleased_huge_pages = Length(0); + stats.huge_pages[StatsTrackerType::kRegular] = hp; + stats.huge_pages[StatsTrackerType::kDonated] = hp; + stats.huge_pages[StatsTrackerType::kPartialReleased] = hp; + stats.huge_pages[StatsTrackerType::kReleased] = hp; + tracker_.Report(stats); +} + +// Tests that the tracker aggregates all data correctly. The output is tested by +// comparing the text output of the tracker. While this is a bit verbose, it is +// much cleaner than extracting and comparing all data manually. +TEST_F(StatsTrackerTest, Works) { + // Ensure that the beginning (when free pages are 0) is outside the 5-min + // window the instrumentation is recording. + GenerateInterestingPoints(Length(1), NHugePages(1), Length(1)); + Advance(absl::Minutes(5)); + + GenerateInterestingPoints(Length(100), NHugePages(5), Length(200)); + + Advance(absl::Minutes(1)); + + GenerateInterestingPoints(Length(200), NHugePages(10), Length(100)); + + Advance(absl::Minutes(1)); + + // Test text output (time series summary). + { + std::string buffer(1024 * 1024, '\0'); + Printer printer(&*buffer.begin(), buffer.size()); + { + tracker_.Print(printer, "StatsTracker"); + buffer.erase(printer.SpaceRequired()); + } + + EXPECT_THAT(buffer, StrEq(R"(StatsTracker: time series over 5 min interval + +StatsTracker: realized fragmentation: 0.8 MiB +StatsTracker: minimum free pages: 110 (100 backed) +StatsTracker: at peak demand: 208 pages (and 111 free, 10 unmapped) +StatsTracker: at peak demand: 26 hps (14 regular, 10 donated, 1 partial, 1 released) + +StatsTracker: Since the start of the execution, 0 subreleases (0 pages) were skipped due to the sum of short-term (0s) fluctuations and long-term (0s) trends. +StatsTracker: 0.0000% of decisions confirmed correct, 0 pending (0.0000% of pages, 0 pending). +StatsTracker: Subrelease stats last 10 min: total 0 pages subreleased (0 pages from partial allocs), 0 hugepages broken +)")); + } +} + +TEST_F(StatsTrackerTest, InvalidDurations) { + // These should not crash. + tracker_.min_free_pages(absl::InfiniteDuration()); + tracker_.min_free_pages(kWindow + absl::Seconds(1)); + tracker_.min_free_pages(-(kWindow + absl::Seconds(1))); + tracker_.min_free_pages(-absl::InfiniteDuration()); +} + +TEST_F(StatsTrackerTest, ComputeRecentDemand) { + // Generates max and min demand in each epoch to create short-term demand + // fluctuations. + GenerateDemandPoint(Length(1500), Length(2000)); + GenerateDemandPoint(Length(3000), Length(1000)); + Advance(absl::Minutes(1.25)); + GenerateDemandPoint(Length(500), Length(1000)); + GenerateDemandPoint(Length(1500), Length(0)); + Advance(absl::Minutes(1)); + GenerateDemandPoint(Length(50), Length(1000)); + GenerateDemandPoint(Length(100), Length(2000)); + Advance(absl::Minutes(1)); + GenerateDemandPoint(Length(100), Length(2000)); + GenerateDemandPoint(Length(300), Length(3000)); + + Length short_long_peak_pages = + tracker_.GetRecentDemand(absl::Minutes(2), absl::Minutes(3)); + EXPECT_EQ(short_long_peak_pages, Length(700)); + Length short_long_peak_pages2 = + tracker_.GetRecentDemand(absl::Minutes(5), absl::Minutes(5)); + EXPECT_EQ(short_long_peak_pages2, Length(3000)); + + Advance(absl::Minutes(4)); + GenerateDemandPoint(Length(150), Length(500)); + GenerateDemandPoint(Length(200), Length(3000)); + + Length short_long_peak_pages3 = + tracker_.GetRecentDemand(absl::Minutes(1), absl::ZeroDuration()); + EXPECT_EQ(short_long_peak_pages3, Length(50)); + + Advance(absl::Minutes(5)); + GenerateDemandPoint(Length(100), Length(700)); + GenerateDemandPoint(Length(150), Length(800)); + + Length short_long_peak_pages4 = + tracker_.GetRecentDemand(absl::ZeroDuration(), absl::Minutes(5)); + EXPECT_EQ(short_long_peak_pages4, Length(100)); + // The short_interval needs to be shorter or equal to the long_interval when + // they are both set. We cap short_interval to long_interval when this is not + // the case. + EXPECT_EQ(tracker_.GetRecentDemand(absl::Minutes(2), absl::Minutes(1)), + tracker_.GetRecentDemand(absl::Minutes(1), absl::Minutes(1))); +} + +TEST_F(StatsTrackerTest, ComputeRecentDemandAndCappedToPeak) { + // Generates max and min demand in each epoch to create short-term demand + // fluctuations. + GenerateDemandPoint(Length(50), Length(2000)); + GenerateDemandPoint(Length(3000), Length(1000)); + Advance(absl::Minutes(2)); + GenerateDemandPoint(Length(1500), Length(0)); + Advance(absl::Minutes(1)); + GenerateDemandPoint(Length(50), Length(1000)); + GenerateDemandPoint(Length(100), Length(2000)); + // The calculated demand is 2500 (maximum demand diff) + 1500 (max + // min_demand), but capped by the peak observed in the time series. + Length demand_1 = + tracker_.GetRecentDemand(absl::Minutes(5), absl::Minutes(5)); + EXPECT_EQ(demand_1, Length(3000)); + // Capped by the peak observed in 2 mins. + Length demand_2 = tracker_.GetRecentDemand(absl::Minutes(5), absl::Minutes(5), + absl::Minutes(2)); + EXPECT_EQ(demand_2, Length(1500)); +} + +// Tests that we can compute the realized fragmentation correctly. +TEST_F(StatsTrackerTest, ComputeRealizedFragmentation) { + GenerateDemandPoint(Length(50), Length(500)); + Advance(absl::Minutes(2)); + GenerateDemandPoint(Length(3000), Length(1000)); + Advance(absl::Minutes(1)); + GenerateDemandPoint(Length(1500), Length(2000)); + Advance(absl::Minutes(2)); + Length fragmentation_1 = tracker_.RealizedFragmentation(); + EXPECT_EQ(fragmentation_1, Length(500)); + + Advance(absl::Minutes(30)); + GenerateDemandPoint(Length(1500), Length(2000)); + Advance(absl::Minutes(2)); + Length fragmentation_2 = tracker_.RealizedFragmentation(); + EXPECT_EQ(fragmentation_2, Length(2000)); +} + +TEST_F(StatsTrackerTest, TrackCorrectSubreleaseDecisions) { + // First peak (large) + GenerateDemandPoint(Length(1000), Length(1000)); + + // Incorrect subrelease: Subrelease to 1000 + Advance(absl::Minutes(1)); + GenerateDemandPoint(Length(100), Length(1000)); + tracker_.ReportSkippedSubreleasePages(Length(900), Length(1000)); + + // Second peak (small) + Advance(absl::Minutes(1)); + GenerateDemandPoint(Length(500), Length(1000)); + + EXPECT_EQ(tracker_.total_skipped().pages, Length(900)); + EXPECT_EQ(tracker_.total_skipped().count, 1); + EXPECT_EQ(tracker_.correctly_skipped().pages, Length(0)); + EXPECT_EQ(tracker_.correctly_skipped().count, 0); + EXPECT_EQ(tracker_.pending_skipped().pages, Length(900)); + EXPECT_EQ(tracker_.pending_skipped().count, 1); + + // Correct subrelease: Subrelease to 500 + Advance(absl::Minutes(1)); + GenerateDemandPoint(Length(500), Length(100)); + tracker_.ReportSkippedSubreleasePages(Length(50), Length(550)); + GenerateDemandPoint(Length(500), Length(50)); + tracker_.ReportSkippedSubreleasePages(Length(50), Length(500)); + GenerateDemandPoint(Length(500), Length(0)); + + EXPECT_EQ(tracker_.total_skipped().pages, Length(1000)); + EXPECT_EQ(tracker_.total_skipped().count, 3); + EXPECT_EQ(tracker_.correctly_skipped().pages, Length(0)); + EXPECT_EQ(tracker_.correctly_skipped().count, 0); + EXPECT_EQ(tracker_.pending_skipped().pages, Length(1000)); + EXPECT_EQ(tracker_.pending_skipped().count, 3); + + // Third peak (large, too late for first peak) + Advance(absl::Minutes(4)); + GenerateDemandPoint(Length(1100), Length(1000)); + + Advance(absl::Minutes(5)); + GenerateDemandPoint(Length(1100), Length(1000)); + + EXPECT_EQ(tracker_.total_skipped().pages, Length(1000)); + EXPECT_EQ(tracker_.total_skipped().count, 3); + EXPECT_EQ(tracker_.correctly_skipped().pages, Length(100)); + EXPECT_EQ(tracker_.correctly_skipped().count, 2); + EXPECT_EQ(tracker_.pending_skipped().pages, Length(0)); + EXPECT_EQ(tracker_.pending_skipped().count, 0); +} + +TEST_F(StatsTrackerTest, SubreleaseCorrectnessWithChangingIntervals) { + // First peak (large) + GenerateDemandPoint(Length(1000), Length(1000)); + + Advance(absl::Minutes(1)); + GenerateDemandPoint(Length(100), Length(1000)); + + tracker_.ReportSkippedSubreleasePages(Length(50), Length(1000), + absl::Minutes(4)); + Advance(absl::Minutes(1)); + + // With two correctness intervals in the same epoch, take the maximum + tracker_.ReportSkippedSubreleasePages(Length(100), Length(1000), + absl::Minutes(1)); + tracker_.ReportSkippedSubreleasePages(Length(200), Length(1000), + absl::Minutes(7)); + + Advance(absl::Minutes(5)); + GenerateDemandPoint(Length(1100), Length(1000)); + Advance(absl::Minutes(10)); + GenerateDemandPoint(Length(1100), Length(1000)); + + EXPECT_EQ(tracker_.total_skipped().pages, Length(350)); + EXPECT_EQ(tracker_.total_skipped().count, 3); + EXPECT_EQ(tracker_.correctly_skipped().pages, Length(300)); + EXPECT_EQ(tracker_.correctly_skipped().count, 2); + EXPECT_EQ(tracker_.pending_skipped().pages, Length(0)); + EXPECT_EQ(tracker_.pending_skipped().count, 0); +} + +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_pages.h b/contrib/libs/tcmalloc/tcmalloc/huge_pages.h index 4498994f7568..6c0b60aaf452 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_pages.h +++ b/contrib/libs/tcmalloc/tcmalloc/huge_pages.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,6 +28,7 @@ #include #include "tcmalloc/common.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" #include "tcmalloc/internal/optimization.h" #include "tcmalloc/pages.h" @@ -40,32 +42,40 @@ inline constexpr Length kPagesPerHugePage = // A single aligned huge page. struct HugePage { - void *start_addr() const { - ASSERT(pn <= kMaxPageNumber); - return reinterpret_cast(pn << kHugePageShift); + void* start_addr() const { + TC_ASSERT_LE(pn, kMaxPageNumber); + return reinterpret_cast(pn << kHugePageShift); } PageId first_page() const { - ASSERT(pn <= kMaxPageNumber); + TC_ASSERT_LE(pn, kMaxPageNumber); return PageId(pn << (kHugePageShift - kPageShift)); } size_t index() const { - ASSERT(pn <= kMaxPageNumber); + TC_ASSERT_LE(pn, kMaxPageNumber); return pn; } + template + friend H AbslHashValue(H h, const HugePage& p) { + return H::combine(std::move(h), p.pn); + } + static constexpr uintptr_t kMaxPageNumber = std::numeric_limits::max() >> kHugePageShift; + template + friend void AbslStringify(Sink& sink, const HugePage& v) { + absl::Format(&sink, "%p", v.start_addr()); + } + uintptr_t pn; }; struct HugeLength { - size_t n; - constexpr HugeLength() : n(0) {} - explicit HugeLength(double x) : n(ceil(x)) { ASSERT(x >= 0); } + explicit HugeLength(double x) : n(ceil(x)) { TC_ASSERT_GE(x, 0); } constexpr size_t raw_num() const { return n; } constexpr size_t in_bytes() const { return n * kHugePageSize; } constexpr size_t in_mib() const { @@ -77,10 +87,43 @@ struct HugeLength { // It is possible to have a HugeLength that corresponds to more // bytes than can be addressed (i.e. > size_t.) Check for that. bool overflows() const; + static constexpr HugeLength min() { + return HugeLength(static_cast(0)); + } + static constexpr HugeLength max() { + return HugeLength(static_cast(HugePage::kMaxPageNumber)); + } + + template + friend void AbslStringify(Sink& sink, const HugeLength& v) { + absl::Format(&sink, "%zu", v.in_bytes()); + } private: + size_t n; + explicit constexpr HugeLength(size_t x) : n(x) {} friend constexpr HugeLength NHugePages(size_t n); + friend HugeLength& operator++(HugeLength&); + friend HugeLength& operator--(HugeLength&); + friend constexpr bool operator<(HugeLength, HugeLength); + friend constexpr bool operator>(HugeLength, HugeLength); + friend constexpr bool operator<=(HugeLength, HugeLength); + friend constexpr bool operator>=(HugeLength, HugeLength); + friend constexpr bool operator==(HugeLength, HugeLength); + friend constexpr bool operator!=(HugeLength, HugeLength); + friend constexpr size_t operator/(HugeLength, HugeLength); + friend constexpr HugeLength operator%(HugeLength, HugeLength); + friend constexpr HugeLength operator*(HugeLength, size_t); + friend HugeLength& operator*=(HugeLength&, size_t); + friend constexpr HugeLength operator/(HugeLength, size_t); + friend constexpr HugePage operator+(HugePage lhs, HugeLength rhs); + friend constexpr HugePage operator-(HugePage lhs, HugeLength rhs); + friend HugePage& operator+=(HugePage& lhs, HugeLength rhs); + friend constexpr HugeLength operator+(HugeLength lhs, HugeLength rhs); + friend HugeLength& operator+=(HugeLength& lhs, HugeLength rhs); + friend constexpr HugeLength operator-(HugeLength lhs, HugeLength rhs); + friend HugeLength& operator-=(HugeLength& lhs, HugeLength rhs); }; // Literal constructors (made explicit to avoid accidental uses when @@ -100,19 +143,19 @@ inline constexpr HugeLength HLFromPages(Length pages) { kPagesPerHugePage); } -inline HugeLength &operator++(HugeLength &len) { // NOLINT(runtime/references) +inline HugeLength& operator++(HugeLength& len) { // NOLINT(runtime/references) len.n++; return len; } -inline HugePage &operator++(HugePage &p) { // NOLINT(runtime/references) - ASSERT(p.pn + 1 <= HugePage::kMaxPageNumber); +inline HugePage& operator++(HugePage& p) { // NOLINT(runtime/references) + TC_ASSERT_LE(p.pn + 1, HugePage::kMaxPageNumber); p.pn++; return p; } -inline HugeLength &operator--(HugeLength &len) { // NOLINT(runtime/references) - ASSERT(len.n >= 1); +inline HugeLength& operator--(HugeLength& len) { // NOLINT(runtime/references) + TC_ASSERT_GE(len.n, 1); len.n--; return len; } @@ -191,7 +234,7 @@ inline constexpr HugeLength operator/(HugeLength lhs, size_t rhs) { return NHugePages(lhs.n / rhs); } -inline HugeLength &operator*=(HugeLength &lhs, size_t rhs) { +inline HugeLength& operator*=(HugeLength& lhs, size_t rhs) { lhs.n *= rhs; return lhs; } @@ -203,7 +246,7 @@ inline constexpr HugeLength operator%(HugeLength lhs, HugeLength rhs) { TCMALLOC_ATTRIBUTE_CONST inline constexpr HugePage operator+(HugePage lhs, HugeLength rhs) { - ASSERT(lhs.pn + rhs.n <= HugePage::kMaxPageNumber); + TC_ASSERT_LE(lhs.pn + rhs.n, HugePage::kMaxPageNumber); return HugePage{lhs.pn + rhs.n}; } @@ -214,16 +257,16 @@ inline constexpr HugePage operator+(HugeLength lhs, HugePage rhs) { TCMALLOC_ATTRIBUTE_CONST inline constexpr HugePage operator-(HugePage lhs, HugeLength rhs) { - return ASSERT(lhs.pn >= rhs.n), HugePage{lhs.pn - rhs.n}; + return TC_ASSERT_GE(lhs.pn, rhs.n), HugePage{lhs.pn - rhs.n}; } TCMALLOC_ATTRIBUTE_CONST inline constexpr HugeLength operator-(HugePage lhs, HugePage rhs) { - return ASSERT(lhs.pn >= rhs.pn), NHugePages(lhs.pn - rhs.pn); + return TC_ASSERT_GE(lhs.pn, rhs.pn), NHugePages(lhs.pn - rhs.pn); } -inline HugePage &operator+=(HugePage &lhs, HugeLength rhs) { - ASSERT(lhs.pn + rhs.n <= HugePage::kMaxPageNumber); +inline HugePage& operator+=(HugePage& lhs, HugeLength rhs) { + TC_ASSERT_LE(lhs.pn + rhs.n, HugePage::kMaxPageNumber); lhs.pn += rhs.n; return lhs; } @@ -233,18 +276,18 @@ inline constexpr HugeLength operator+(HugeLength lhs, HugeLength rhs) { return NHugePages(lhs.n + rhs.n); } -inline HugeLength &operator+=(HugeLength &lhs, HugeLength rhs) { +inline HugeLength& operator+=(HugeLength& lhs, HugeLength rhs) { lhs.n += rhs.n; return lhs; } TCMALLOC_ATTRIBUTE_CONST inline constexpr HugeLength operator-(HugeLength lhs, HugeLength rhs) { - return ASSERT(lhs.n >= rhs.n), NHugePages(lhs.n - rhs.n); + return TC_ASSERT_GE(lhs.n, rhs.n), NHugePages(lhs.n - rhs.n); } -inline HugeLength &operator-=(HugeLength &lhs, HugeLength rhs) { - ASSERT(lhs.n >= rhs.n); +inline HugeLength& operator-=(HugeLength& lhs, HugeLength rhs) { + TC_ASSERT_GE(lhs.n, rhs.n); lhs.n -= rhs.n; return lhs; } @@ -253,7 +296,7 @@ inline bool HugeLength::overflows() const { return *this > HLFromBytes(std::numeric_limits::max()); } -inline void PrintTo(const HugeLength &n, ::std::ostream *os) { +inline void PrintTo(const HugeLength& n, ::std::ostream* os) { *os << n.raw_num() << "hps"; } @@ -263,16 +306,25 @@ inline HugePage HugePageContaining(PageId p) { } TCMALLOC_ATTRIBUTE_CONST -inline HugePage HugePageContaining(void *p) { +inline HugePage HugePageContaining(void* p) { return HugePageContaining(PageIdContaining(p)); } // A set of contiguous huge pages. struct HugeRange { - void *start_addr() const { return first.start_addr(); } - void *end_addr() const { return (first + n).start_addr(); } + HugeRange() = default; + constexpr HugeRange(HugePage p, HugeLength len) : first(p), n(len) {} + + constexpr HugeRange(const HugeRange&) = default; + constexpr HugeRange& operator=(const HugeRange&) = default; + + constexpr HugeRange(HugeRange&&) = default; + constexpr HugeRange& operator=(HugeRange&&) = default; + + void* start_addr() const { return first.start_addr(); } + void* end_addr() const { return (first + n).start_addr(); } size_t byte_len() const { - return static_cast(end_addr()) - static_cast(start_addr()); + return static_cast(end_addr()) - static_cast(start_addr()); } // Assume any range starting at 0 is bogus. @@ -285,7 +337,7 @@ struct HugeRange { HugePage operator[](HugeLength i) const { return first + i; } template - friend H AbslHashValue(H h, const HugeRange &r) { + friend H AbslHashValue(H h, const HugeRange& r) { return H::combine(std::move(h), r.start().start_addr(), r.len().raw_num()); } @@ -320,7 +372,7 @@ inline constexpr bool operator==(HugeRange lhs, HugeRange rhs) { // REQUIRES: a and b are disjoint but adjacent (in that order) inline HugeRange Join(HugeRange a, HugeRange b) { - CHECK_CONDITION(a.precedes(b)); + TC_CHECK(a.precedes(b)); return {a.start(), a.len() + b.len()}; } @@ -328,7 +380,7 @@ inline HugeRange Join(HugeRange a, HugeRange b) { // Splits r into two ranges, one of length n. The other is either the rest // of the space (if any) or Nil. inline std::pair Split(HugeRange r, HugeLength n) { - ASSERT(r.len() >= n); + TC_ASSERT_GE(r.len(), n); if (r.len() > n) { return {HugeRange::Make(r.start(), n), HugeRange::Make(r.start() + n, r.len() - n)}; diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_region.h b/contrib/libs/tcmalloc/tcmalloc/huge_region.h index 0262c007b219..64ea99c65062 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_region.h +++ b/contrib/libs/tcmalloc/tcmalloc/huge_region.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,11 +20,18 @@ #include +#include "absl/base/attributes.h" #include "absl/base/internal/cycleclock.h" -#include "tcmalloc/huge_allocator.h" -#include "tcmalloc/huge_page_filler.h" +#include "absl/base/optimization.h" +#include "absl/time/time.h" +#include "tcmalloc/huge_cache.h" +#include "tcmalloc/huge_page_subrelease.h" +#include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/clock.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/linked_list.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/range_tracker.h" #include "tcmalloc/pages.h" #include "tcmalloc/stats.h" @@ -31,6 +39,20 @@ GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { +constexpr double kFractionToReleaseFromRegion = 0.1; +enum class HugeRegionUsageOption : bool { + // This is a default behavior. We use slack to determine when to use + // HugeRegion. When slack is greater than 64MB (to ignore small binaries), and + // greater than the number of small allocations, we allocate large allocations + // from HugeRegion. + kDefault, + // When the experiment TEST_ONLY_TCMALLOC_USE_HUGE_REGIONS_MORE_OFTEN is + // enabled, we use number of abandoned pages in addition to slack to make a + // decision. If the size of abandoned pages plus slack exceeds 64MB (to ignore + // small binaries), we use HugeRegion for large allocations. + kUseForAllLargeAllocs +}; + // Track allocations from a fixed-size multiple huge page region. // Similar to PageTracker but a few important differences: // - crosses multiple hugepages @@ -51,21 +73,23 @@ class HugeRegion : public TList::Elem { static constexpr HugeLength size() { return kRegionSize; } // REQUIRES: r.len() == size(); r unbacked. - HugeRegion(HugeRange r, MemoryModifyFunction unback); + HugeRegion(HugeRange r, + MemoryModifyFunction& unback ABSL_ATTRIBUTE_LIFETIME_BOUND); HugeRegion() = delete; // If available, return a range of n free pages, setting *from_released = // true iff the returned range is currently unbacked. // Returns false if no range available. - bool MaybeGet(Length n, PageId *p, bool *from_released); + bool MaybeGet(Length n, PageId* p, bool* from_released); - // Return [p, p + n) for new allocations. + // Return r for new allocations. // If release=true, release any hugepages made empty as a result. - // REQUIRES: [p, p + n) was the result of a previous MaybeGet. - void Put(PageId p, Length n, bool release); + // REQUIRES: Range{p, n} was the result of a previous MaybeGet. + void Put(Range r, bool release); - // Release any hugepages that are unused but backed. - HugeLength Release(); + // Release numbae of pages from free-and-backed hugepages from + // region. + HugeLength Release(Length desired); // Is p located in this region? bool contains(PageId p) { return location_.contains(p); } @@ -77,57 +101,53 @@ class HugeRegion : public TList::Elem { } Length unmapped_pages() const { return (size() - nbacked_).in_pages(); } - void AddSpanStats(SmallSpanStats *small, LargeSpanStats *large, - PageAgeHistograms *ages) const; + void AddSpanStats(SmallSpanStats* small, LargeSpanStats* large) const; HugeLength backed() const; - void Print(Printer *out) const; - void PrintInPbtxt(PbtxtRegion *detail) const; + // Returns the number of hugepages that have been fully free (i.e. no + // allocated pages on them), but are backed. We release hugepages lazily when + // huge-regions-more-often feature is enabled. + HugeLength free_backed() const; + + void Print(Printer& out) const; + void PrintInPbtxt(PbtxtRegion& detail) const; BackingStats stats() const; // We don't define this as operator< because it's a rather specialized order. - bool BetterToAllocThan(const HugeRegion *rhs) const { + bool BetterToAllocThan(const HugeRegion* rhs) const { return longest_free() < rhs->longest_free(); } - void prepend_it(HugeRegion *other) { this->prepend(other); } + void prepend_it(HugeRegion* other) { this->prepend(other); } - void append_it(HugeRegion *other) { this->append(other); } + void append_it(HugeRegion* other) { this->append(other); } private: RangeTracker tracker_; HugeRange location_; - static int64_t AverageWhens(Length a, int64_t a_when, Length b, - int64_t b_when) { - const double aw = static_cast(a.raw_num()) * a_when; - const double bw = static_cast(b.raw_num()) * b_when; - return static_cast((aw + bw) / (a.raw_num() + b.raw_num())); - } - Length longest_free() const { return Length(tracker_.longest_free()); } - // Adjust counts of allocs-per-hugepage for [p, p + n) being added/removed. + // Adjust counts of allocs-per-hugepage for r being added/removed. - // *from_released is set to true iff [p, p + n) is currently unbacked - void Inc(PageId p, Length n, bool *from_released); + // *from_released is set to true iff r is currently unbacked + void Inc(Range r, bool* from_released); // If release is true, unback any hugepage that becomes empty. - void Dec(PageId p, Length n, bool release); + void Dec(Range r, bool release); - void UnbackHugepages(bool should[kNumHugePages]); + HugeLength UnbackHugepages(bool should_unback[kNumHugePages]); // How many pages are used in each hugepage? Length pages_used_[kNumHugePages]; // Is this hugepage backed? bool backed_[kNumHugePages]; HugeLength nbacked_; - int64_t whens_[kNumHugePages]; HugeLength total_unbacked_{NHugePages(0)}; - MemoryModifyFunction unback_; + MemoryModifyFunction& unback_; }; // Manage a set of regions from which we allocate. @@ -135,31 +155,61 @@ class HugeRegion : public TList::Elem { template class HugeRegionSet { public: - HugeRegionSet() : n_(0) {} + // For testing with mock clock. + HugeRegionSet(HugeRegionUsageOption use_huge_region_more_often, Clock clock) + : n_(0), + use_huge_region_more_often_(use_huge_region_more_often), + regionstats_tracker_(clock, absl::Minutes(10), absl::Minutes(5)) {} + + explicit HugeRegionSet(HugeRegionUsageOption use_huge_region_more_often) + : HugeRegionSet( + use_huge_region_more_often, + Clock{.now = absl::base_internal::CycleClock::Now, + .freq = absl::base_internal::CycleClock::Frequency}) {} // If available, return a range of n free pages, setting *from_released = // true iff the returned range is currently unbacked. // Returns false if no range available. - bool MaybeGet(Length n, PageId *page, bool *from_released); + bool MaybeGet(Length n, PageId* page, bool* from_released); // Return an allocation to a region (if one matches!) - bool MaybePut(PageId p, Length n); + bool MaybePut(Range r); // Add region to the set. - void Contribute(Region *region); - - // Unback any totally unused hugepages; return the number of pages - // we managed to release. - HugeLength Release(); - - void Print(Printer *out) const; - void PrintInPbtxt(PbtxtRegion *hpaa) const; - void AddSpanStats(SmallSpanStats *small, LargeSpanStats *large, - PageAgeHistograms *ages) const; + void Contribute(Region* region); + + // Tries to release up to number of pages from fully-free but backed + // hugepages in HugeRegions. defines the skip-subrelease + // intervals, but unlike HugePageFiller skip-subrelease, it only releases free + // hugepages. + // Releases all free and backed hugepages to system when is set to + // true. Else, it uses intervals to determine recent demand as seen by + // HugeRegions to compute realized fragmentation. It may only release as much + // memory in free pages as determined by the realized fragmentation. + // Returns the number of pages actually released. + Length ReleasePagesByPeakDemand(Length desired, + SkipSubreleaseIntervals intervals, + bool hit_limit); + + // Release hugepages that are unused but backed. + // Releases up to times number of free-but-backed hugepages + // from each huge region. Note that this clamps release_fraction between 0 and + // 1 if a fraction outside those bounds is specified. + Length ReleasePages(double release_fraction); + + void Print(Printer& out) const; + void PrintInPbtxt(PbtxtRegion& hpaa) const; + void AddSpanStats(SmallSpanStats* small, LargeSpanStats* large) const; BackingStats stats() const; + HugeLength free_backed() const; + size_t ActiveRegions() const; + bool UseHugeRegionMoreOften() const { + return use_huge_region_more_often_ == + HugeRegionUsageOption::kUseForAllLargeAllocs; + } private: - void Fix(Region *r) { + void Fix(Region* r) { // We've changed r's fragmentation--move it through the list to the // correct home (if needed). Rise(r); @@ -167,7 +217,7 @@ class HugeRegionSet { } // Check if r has to move forward in the list. - void Rise(Region *r) { + void Rise(Region* r) { auto prev = list_.at(r); --prev; if (prev == list_.end()) return; // we're at the front @@ -183,7 +233,7 @@ class HugeRegionSet { } // Check if r has to move backward in the list. - void Fall(Region *r) { + void Fall(Region* r) { auto next = list_.at(r); ++next; if (next == list_.end()) return; // we're at the back @@ -199,8 +249,8 @@ class HugeRegionSet { } // Add r in its sorted place. - void AddToList(Region *r) { - for (Region *curr : list_) { + void AddToList(Region* r) { + for (Region* curr : list_) { if (r->BetterToAllocThan(curr)) { curr->prepend_it(r); return; @@ -211,65 +261,123 @@ class HugeRegionSet { list_.append(r); } + using StatsTrackerType = SubreleaseStatsTracker<600>; + StatsTrackerType::SubreleaseStats GetSubreleaseStats() const { + StatsTrackerType::SubreleaseStats stats; + for (Region* region : list_) { + stats.num_pages += region->used_pages(); + stats.free_pages += region->free_pages(); + stats.unmapped_pages += region->unmapped_pages(); + stats.huge_pages[StatsTrackerType::kRegular] += region->size(); + } + stats.num_pages_subreleased = subrelease_stats_.num_pages_subreleased; + return stats; + } + + Length used_pages() const { + Length used; + for (Region* region : list_) { + used += region->used_pages(); + } + return used; + } + + Length free_pages() const { + Length free; + for (Region* region : list_) { + free += region->free_pages(); + } + return free; + } + + HugeLength size() const { + HugeLength size; + for (Region* region : list_) { + size += region->size(); + } + return size; + } + size_t n_; + HugeRegionUsageOption use_huge_region_more_often_; // Sorted by longest_free increasing. TList list_; + + // Computes the recent demand to compute the number of pages that may be + // released. determines an upper-bound on the number of pages to + // release. + // Returns number of pages that may be released based on recent demand. + Length GetDesiredReleasablePages(Length desired, + SkipSubreleaseIntervals intervals); + + // Functionality related to tracking demand. + void UpdateStatsTracker(); + StatsTrackerType regionstats_tracker_; + SubreleaseStats subrelease_stats_; }; // REQUIRES: r.len() == size(); r unbacked. -inline HugeRegion::HugeRegion(HugeRange r, MemoryModifyFunction unback) +inline HugeRegion::HugeRegion(HugeRange r, MemoryModifyFunction& unback) : tracker_{}, location_(r), pages_used_{}, backed_{}, nbacked_(NHugePages(0)), unback_(unback) { - int64_t now = absl::base_internal::CycleClock::Now(); for (int i = 0; i < kNumHugePages; ++i) { - whens_[i] = now; // These are already 0 but for clarity... pages_used_[i] = Length(0); backed_[i] = false; } } -inline bool HugeRegion::MaybeGet(Length n, PageId *p, bool *from_released) { +inline bool HugeRegion::MaybeGet(Length n, PageId* p, bool* from_released) { if (n > longest_free()) return false; + TC_ASSERT_GT(n, Length(0)); auto index = Length(tracker_.FindAndMark(n.raw_num())); PageId page = location_.start().first_page() + index; *p = page; // the last hugepage we touch - Inc(page, n, from_released); + Inc(Range{page, n}, from_released); return true; } // If release=true, release any hugepages made empty as a result. -inline void HugeRegion::Put(PageId p, Length n, bool release) { - Length index = p - location_.start().first_page(); - tracker_.Unmark(index.raw_num(), n.raw_num()); +inline void HugeRegion::Put(Range r, bool release) { + Length index = r.p - location_.start().first_page(); + tracker_.Unmark(index.raw_num(), r.n.raw_num()); - Dec(p, n, release); + Dec(r, release); } -// Release any hugepages that are unused but backed. -inline HugeLength HugeRegion::Release() { - HugeLength r = NHugePages(0); - bool should_unback_[kNumHugePages] = {}; +// Release hugepages that are unused but backed. +// TODO(b/199203282): We release pages, rounded up to a hugepage, from +// free but backed hugepages from the region. We can explore a more +// sophisticated mechanism similar to Filler/Cache, that accounts for a recent +// peak while releasing pages. +inline HugeLength HugeRegion::Release(Length desired) { + if (desired == Length(0)) return NHugePages(0); + + const Length free_yet_backed = free_backed().in_pages(); + const Length to_release = std::min(desired, free_yet_backed); + + HugeLength release_target = NHugePages(0); + bool should_unback[kNumHugePages] = {}; for (size_t i = 0; i < kNumHugePages; ++i) { if (backed_[i] && pages_used_[i] == Length(0)) { - should_unback_[i] = true; - ++r; + should_unback[i] = true; + ++release_target; } + + if (release_target.in_pages() >= to_release) break; } - UnbackHugepages(should_unback_); - return r; + return UnbackHugepages(should_unback); } -inline void HugeRegion::AddSpanStats(SmallSpanStats *small, - LargeSpanStats *large, - PageAgeHistograms *ages) const { +inline void HugeRegion::AddSpanStats(SmallSpanStats* small, + LargeSpanStats* large) const { size_t index = 0, n; Length f, u; // This is complicated a bit by the backed/unbacked status of pages. @@ -283,16 +391,14 @@ inline void HugeRegion::AddSpanStats(SmallSpanStats *small, size_t i = (hp - location_.start()) / NHugePages(1); const bool backed = backed_[i]; Length truncated; - int64_t when = 0; while (n > 0 && backed_[i] == backed) { const PageId lim = (location_.start() + NHugePages(i + 1)).first_page(); Length here = std::min(Length(n), lim - p); - when = AverageWhens(truncated, when, here, whens_[i]); truncated += here; n -= here.raw_num(); p += here; i++; - ASSERT(i < kNumHugePages || n == 0); + TC_ASSERT(i < kNumHugePages || n == 0); } n = truncated.raw_num(); const bool released = !backed; @@ -320,13 +426,20 @@ inline void HugeRegion::AddSpanStats(SmallSpanStats *small, } } - if (ages != nullptr) { - ages->RecordRange(Length(n), released, when); - } index += n; } - CHECK_CONDITION(f == free_pages()); - CHECK_CONDITION(u == unmapped_pages()); + TC_CHECK_EQ(f, free_pages()); + TC_CHECK_EQ(u, unmapped_pages()); +} + +inline HugeLength HugeRegion::free_backed() const { + HugeLength r = NHugePages(0); + for (size_t i = 0; i < kNumHugePages; ++i) { + if (backed_[i] && pages_used_[i] == Length(0)) { + ++r; + } + } + return r; } inline HugeLength HugeRegion::backed() const { @@ -340,13 +453,13 @@ inline HugeLength HugeRegion::backed() const { return b; } -inline void HugeRegion::Print(Printer *out) const { +inline void HugeRegion::Print(Printer& out) const { const size_t kib_used = used_pages().in_bytes() / 1024; const size_t kib_free = free_pages().in_bytes() / 1024; const size_t kib_longest_free = longest_free().in_bytes() / 1024; const HugeLength unbacked = size() - backed(); const size_t mib_unbacked = unbacked.in_mib(); - out->printf( + out.printf( "HugeRegion: %zu KiB used, %zu KiB free, " "%zu KiB contiguous space, %zu MiB unbacked, " "%zu MiB unbacked lifetime\n", @@ -354,13 +467,14 @@ inline void HugeRegion::Print(Printer *out) const { total_unbacked_.in_bytes() / 1024 / 1024); } -inline void HugeRegion::PrintInPbtxt(PbtxtRegion *detail) const { - detail->PrintI64("used_bytes", used_pages().in_bytes()); - detail->PrintI64("free_bytes", free_pages().in_bytes()); - detail->PrintI64("longest_free_range_bytes", longest_free().in_bytes()); +inline void HugeRegion::PrintInPbtxt(PbtxtRegion& detail) const { + detail.PrintI64("used_bytes", used_pages().in_bytes()); + detail.PrintI64("free_bytes", free_pages().in_bytes()); + detail.PrintI64("longest_free_range_bytes", longest_free().in_bytes()); const HugeLength unbacked = size() - backed(); - detail->PrintI64("unbacked_bytes", unbacked.in_bytes()); - detail->PrintI64("total_unbacked_bytes", total_unbacked_.in_bytes()); + detail.PrintI64("unbacked_bytes", unbacked.in_bytes()); + detail.PrintI64("total_unbacked_bytes", total_unbacked_.in_bytes()); + detail.PrintI64("backed_fully_free_bytes", free_backed().in_bytes()); } inline BackingStats HugeRegion::stats() const { @@ -371,86 +485,156 @@ inline BackingStats HugeRegion::stats() const { return s; } -inline void HugeRegion::Inc(PageId p, Length n, bool *from_released) { +inline void HugeRegion::Inc(Range r, bool* from_released) { bool should_back = false; - const int64_t now = absl::base_internal::CycleClock::Now(); - while (n > Length(0)) { - const HugePage hp = HugePageContaining(p); + while (r.n > Length(0)) { + const HugePage hp = HugePageContaining(r.p); const size_t i = (hp - location_.start()) / NHugePages(1); const PageId lim = (hp + NHugePages(1)).first_page(); - Length here = std::min(n, lim - p); + Length here = std::min(r.n, lim - r.p); if (pages_used_[i] == Length(0) && !backed_[i]) { backed_[i] = true; should_back = true; ++nbacked_; - whens_[i] = now; } pages_used_[i] += here; - ASSERT(pages_used_[i] <= kPagesPerHugePage); - p += here; - n -= here; + TC_ASSERT_LE(pages_used_[i], kPagesPerHugePage); + r.p += here; + r.n -= here; } *from_released = should_back; } -inline void HugeRegion::Dec(PageId p, Length n, bool release) { - const int64_t now = absl::base_internal::CycleClock::Now(); - bool should_unback_[kNumHugePages] = {}; - while (n > Length(0)) { - const HugePage hp = HugePageContaining(p); +inline void HugeRegion::Dec(Range r, bool release) { + bool should_unback[kNumHugePages] = {}; + while (r.n > Length(0)) { + const HugePage hp = HugePageContaining(r.p); const size_t i = (hp - location_.start()) / NHugePages(1); const PageId lim = (hp + NHugePages(1)).first_page(); - Length here = std::min(n, lim - p); - ASSERT(here > Length(0)); - ASSERT(pages_used_[i] >= here); - ASSERT(backed_[i]); - whens_[i] = - AverageWhens(here, now, kPagesPerHugePage - pages_used_[i], whens_[i]); + Length here = std::min(r.n, lim - r.p); + TC_ASSERT_GT(here, Length(0)); + TC_ASSERT_GE(pages_used_[i], here); + TC_ASSERT(backed_[i]); pages_used_[i] -= here; if (pages_used_[i] == Length(0)) { - should_unback_[i] = true; + should_unback[i] = true; } - p += here; - n -= here; + r.p += here; + r.n -= here; } if (release) { - UnbackHugepages(should_unback_); + UnbackHugepages(should_unback); } } -inline void HugeRegion::UnbackHugepages(bool should[kNumHugePages]) { - const int64_t now = absl::base_internal::CycleClock::Now(); +inline HugeLength HugeRegion::UnbackHugepages( + bool should_unback[kNumHugePages]) { + HugeLength released = NHugePages(0); size_t i = 0; while (i < kNumHugePages) { - if (!should[i]) { + if (!should_unback[i]) { i++; continue; } size_t j = i; - while (j < kNumHugePages && should[j]) { - backed_[j] = false; - whens_[j] = now; + while (j < kNumHugePages && should_unback[j]) { j++; } HugeLength hl = NHugePages(j - i); - nbacked_ -= hl; HugePage p = location_.start() + NHugePages(i); - unback_(p.start_addr(), hl.in_bytes()); - total_unbacked_ += hl; + if (ABSL_PREDICT_TRUE(unback_(HugeRange(p, hl)))) { + nbacked_ -= hl; + total_unbacked_ += hl; + + for (size_t k = i; k < j; k++) { + TC_ASSERT(should_unback[k]); + backed_[k] = false; + } + + released += hl; + } i = j; } + + return released; +} + +template +inline Length HugeRegionSet::GetDesiredReleasablePages( + Length desired, SkipSubreleaseIntervals intervals) { + if (!intervals.SkipSubreleaseEnabled()) { + return desired; + } + UpdateStatsTracker(); + + Length required_pages; + required_pages = regionstats_tracker_.GetRecentDemand( + intervals.short_interval, intervals.long_interval); + + Length current_pages = used_pages() + free_pages(); + + if (required_pages != Length(0)) { + Length new_desired; + if (required_pages < current_pages) { + new_desired = current_pages - required_pages; + } + + // Because we currently release pages from fully backed and free hugepages, + // make sure that the realized fragmentation in HugeRegion is at least equal + // to kPagesPerHugePage. Otherwise, return zero to make sure we do not + // release any pages. + if (new_desired < kPagesPerHugePage) { + new_desired = Length(0); + } + + if (new_desired >= desired) { + return desired; + } + + // Compute the number of releasable pages from HugeRegion. We do not + // subrelease pages yet. Instead, we only release hugepages that are fully + // free but backed. Note: the remaining target should always be smaller or + // equal to the number of free pages according to the mechanism (recent peak + // is always larger or equal to current used_pages), however, we still + // calculate allowed release using the minimum of the two to avoid relying + // on that assumption. + Length free_backed_pages = free_backed().in_pages(); + Length releasable_pages = std::min(free_backed_pages, new_desired); + + // Reports the amount of memory that we didn't release due to this + // mechanism, but never more than skipped free pages. In other words, + // skipped_pages is zero if all free pages are allowed to be released by + // this mechanism. Note, only free pages in the smaller of the two + // (current_pages and required_pages) are skipped, the rest are allowed to + // be subreleased. + Length skipped_pages = std::min((free_backed_pages - releasable_pages), + (desired - new_desired)); + + regionstats_tracker_.ReportSkippedSubreleasePages( + skipped_pages, std::min(current_pages, required_pages)); + return new_desired; + } + + return desired; +} + +template +inline void HugeRegionSet::UpdateStatsTracker() { + regionstats_tracker_.Report(GetSubreleaseStats()); + subrelease_stats_.reset(); } // If available, return a range of n free pages, setting *from_released = // true iff the returned range is currently unbacked. // Returns false if no range available. template -inline bool HugeRegionSet::MaybeGet(Length n, PageId *page, - bool *from_released) { - for (Region *region : list_) { +inline bool HugeRegionSet::MaybeGet(Length n, PageId* page, + bool* from_released) { + for (Region* region : list_) { if (region->MaybeGet(n, page, from_released)) { Fix(region); + UpdateStatsTracker(); return true; } } @@ -459,11 +643,16 @@ inline bool HugeRegionSet::MaybeGet(Length n, PageId *page, // Return an allocation to a region (if one matches!) template -inline bool HugeRegionSet::MaybePut(PageId p, Length n) { - for (Region *region : list_) { - if (region->contains(p)) { - region->Put(p, n, true); +inline bool HugeRegionSet::MaybePut(Range r) { + // When HugeRegionMoreOften experiment is enabled, we do not release + // free-but-backed hugepages when we deallocate pages, but we do that + // periodically on the background thread. + const bool release = !UseHugeRegionMoreOften(); + for (Region* region : list_) { + if (region->contains(r.p)) { + region->Put(r, release); Fix(region); + UpdateStatsTracker(); return true; } } @@ -473,77 +662,164 @@ inline bool HugeRegionSet::MaybePut(PageId p, Length n) { // Add region to the set. template -inline void HugeRegionSet::Contribute(Region *region) { +inline void HugeRegionSet::Contribute(Region* region) { n_++; AddToList(region); + UpdateStatsTracker(); } -// Unback any totally unused hugepages; return the number of pages -// we managed to release. template -inline HugeLength HugeRegionSet::Release() { - HugeLength hl = NHugePages(0); - for (Region *region : list_) { - hl += region->Release(); +inline Length HugeRegionSet::ReleasePagesByPeakDemand( + Length desired, SkipSubreleaseIntervals intervals, bool hit_limit) { + // Because we are releasing fully-freed hugepages, in cases when malloc + // release rate is set to zero, we would still want to release some pages, + // provided it is allowed by the demand-based release strategy. We try to + // release up to 10% of the free and backed hugepages. + if (!hit_limit && desired == Length(0)) { + size_t new_desired = + kFractionToReleaseFromRegion * free_backed().in_pages().raw_num(); + desired = Length(new_desired); + } + + // Only reduce desired if skip subrelease is on. + // + // Additionally, if we hit the limit, we should not be applying skip + // subrelease. OOM may be imminent. + if (intervals.SkipSubreleaseEnabled() && !hit_limit) { + desired = GetDesiredReleasablePages(desired, intervals); } - return hl; + subrelease_stats_.set_limit_hit(hit_limit); + + Length released; + if (desired != Length(0)) { + for (Region* region : list_) { + released += region->Release(desired - released).in_pages(); + if (released >= desired) break; + } + } + + subrelease_stats_.num_pages_subreleased += released; + + // Keep separate stats if the on going release is triggered by reaching + // tcmalloc limit. + if (subrelease_stats_.limit_hit()) { + subrelease_stats_.total_pages_subreleased_due_to_limit += released; + } + + return released; +} + +template +inline Length HugeRegionSet::ReleasePages(double release_fraction) { + const Length free_yet_backed = free_backed().in_pages(); + const size_t to_release = + free_yet_backed.raw_num() * std::clamp(release_fraction, 0, 1); + const Length to_release_pages = Length(to_release); + + Length released; + for (Region* region : list_) { + released += region->Release(to_release_pages - released).in_pages(); + if (released >= to_release_pages) return released; + } + return released; } template -inline void HugeRegionSet::Print(Printer *out) const { - out->printf("HugeRegionSet: 1 MiB+ allocations best-fit into %zu MiB slabs\n", - Region::size().in_bytes() / 1024 / 1024); - out->printf("HugeRegionSet: %zu total regions\n", n_); +inline void HugeRegionSet::Print(Printer& out) const { + out.printf("HugeRegionSet: 1 MiB+ allocations best-fit into %zu MiB slabs\n", + Region::size().in_bytes() / 1024 / 1024); + out.printf("HugeRegionSet: %zu total regions\n", n_); Length total_free; HugeLength total_backed = NHugePages(0); + HugeLength total_free_backed = NHugePages(0); - for (Region *region : list_) { + for (Region* region : list_) { region->Print(out); total_free += region->free_pages(); total_backed += region->backed(); + total_free_backed += region->free_backed(); } - out->printf("HugeRegionSet: %zu hugepages backed out of %zu total\n", - total_backed.raw_num(), Region::size().raw_num() * n_); + out.printf( + "HugeRegionSet: %zu hugepages backed, %zu backed and free, " + "out of %zu total\n", + total_backed.raw_num(), total_free_backed.raw_num(), + Region::size().raw_num() * n_); const Length in_pages = total_backed.in_pages(); - out->printf("HugeRegionSet: %zu pages free in backed region, %.4f free\n", - total_free.raw_num(), - in_pages > Length(0) ? static_cast(total_free.raw_num()) / - static_cast(in_pages.raw_num()) - : 0.0); + out.printf("HugeRegionSet: %zu pages free in backed region, %.4f free\n", + total_free.raw_num(), + in_pages > Length(0) ? static_cast(total_free.raw_num()) / + static_cast(in_pages.raw_num()) + : 0.0); + + // Subrelease telemetry. + out.printf( + "HugeRegion: Since startup, %zu pages subreleased, %zu hugepages " + "broken, (%zu pages, %zu hugepages due to reaching tcmalloc limit)\n", + subrelease_stats_.total_pages_subreleased.raw_num(), + subrelease_stats_.total_hugepages_broken.raw_num(), + subrelease_stats_.total_pages_subreleased_due_to_limit.raw_num(), + subrelease_stats_.total_hugepages_broken_due_to_limit.raw_num()); + + regionstats_tracker_.Print(out, "HugeRegion"); } template -inline void HugeRegionSet::PrintInPbtxt(PbtxtRegion *hpaa) const { - hpaa->PrintI64("min_huge_region_alloc_size", 1024 * 1024); - hpaa->PrintI64("huge_region_size", Region::size().in_bytes()); - for (Region *region : list_) { - auto detail = hpaa->CreateSubRegion("huge_region_details"); - region->PrintInPbtxt(&detail); +inline void HugeRegionSet::PrintInPbtxt(PbtxtRegion& hpaa) const { + hpaa.PrintI64("min_huge_region_alloc_size", 1024 * 1024); + hpaa.PrintI64("huge_region_size", Region::size().in_bytes()); + for (Region* region : list_) { + auto detail = hpaa.CreateSubRegion("huge_region_details"); + region->PrintInPbtxt(detail); } + + hpaa.PrintI64("region_num_pages_subreleased", + subrelease_stats_.total_pages_subreleased.raw_num()); + hpaa.PrintI64( + "region_num_pages_subreleased_due_to_limit", + subrelease_stats_.total_pages_subreleased_due_to_limit.raw_num()); + + regionstats_tracker_.PrintSubreleaseStatsInPbtxt(hpaa, + "region_skipped_subrelease"); + regionstats_tracker_.PrintTimeseriesStatsInPbtxt(hpaa, + "region_stats_timeseries"); } template -inline void HugeRegionSet::AddSpanStats(SmallSpanStats *small, - LargeSpanStats *large, - PageAgeHistograms *ages) const { - for (Region *region : list_) { - region->AddSpanStats(small, large, ages); +inline void HugeRegionSet::AddSpanStats(SmallSpanStats* small, + LargeSpanStats* large) const { + for (Region* region : list_) { + region->AddSpanStats(small, large); } } +template +inline size_t HugeRegionSet::ActiveRegions() const { + return n_; +} + template inline BackingStats HugeRegionSet::stats() const { BackingStats stats; - for (Region *region : list_) { + for (Region* region : list_) { stats += region->stats(); } return stats; } +template +inline HugeLength HugeRegionSet::free_backed() const { + HugeLength pages; + for (Region* region : list_) { + pages += region->free_backed(); + } + + return pages; +} + } // namespace tcmalloc_internal } // namespace tcmalloc GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_region_fuzz.cc b/contrib/libs/tcmalloc/tcmalloc/huge_region_fuzz.cc new file mode 100644 index 000000000000..5a299e20cc81 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/huge_region_fuzz.cc @@ -0,0 +1,262 @@ +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include "fuzztest/fuzztest.h" +#include "absl/base/attributes.h" +#include "absl/container/flat_hash_set.h" +#include "absl/log/check.h" +#include "tcmalloc/huge_cache.h" +#include "tcmalloc/huge_pages.h" +#include "tcmalloc/huge_region.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/stats.h" + +namespace tcmalloc::tcmalloc_internal { +namespace { + +class MockUnback final : public MemoryModifyFunction { + public: + [[nodiscard]] bool operator()(Range r) override { + release_callback_(); + + if (!unback_success_) { + return false; + } + + PageId end = r.p + r.n; + for (; r.p != end; ++r.p) { + released_.insert(r.p); + } + + return true; + } + + absl::flat_hash_set released_; + bool unback_success_ = true; + std::function release_callback_; +}; + +void FuzzRegion(const std::string& s) { + const char* data = s.data(); + size_t size = s.size(); + if (size < 4) { + return; + } + // data[0][0] - Simulate reentrancy from release. + // data[1...3] - Reserved + // + // TODO(b/271282540): Convert these to strongly typed fuzztest parameters. + const bool reentrant_release = data[0] & 0x1; + + data += 4; + size -= 4; + + const HugePage start = + HugePageContaining(reinterpret_cast(0x1faced200000)); + MockUnback unback; + HugeRegion region({start, region.size()}, unback); + + unback.released_.reserve(region.size().in_pages().raw_num()); + for (PageId p = start.first_page(), end = p + region.size().in_pages(); + p != end; ++p) { + unback.released_.insert(p); + } + + std::vector allocs; + std::vector> reentrant; + + std::string output; + output.resize(1 << 20); + + auto run_dsl = [&](const char* data, size_t size) { + for (size_t i = 0; i + 9 <= size; i += 9) { + const uint8_t op = data[i]; + uint64_t value; + memcpy(&value, &data[i + 1], sizeof(value)); + + switch (op & 0x7) { + case 0: { + // Allocate. + // + // value[0:17] - Length to allocate + const Length n = Length(std::max(value & ((1 << 18) - 1), 1)); + PageId p; + bool from_released; + if (!region.MaybeGet(n, &p, &from_released)) { + continue; + } + + allocs.emplace_back(p, n); + + if (from_released) { + bool did_release = false; + + for (PageId q = p, end = p + n; q != end; ++q) { + auto it = unback.released_.find(q); + if (it != unback.released_.end()) { + unback.released_.erase(it); + did_release = true; + } + } + + CHECK(did_release); + } + + break; + } + case 1: { + // Deallocate. + // + // value[0:17] - Index of allocs to remove. + // value[18] - Release + if (allocs.empty()) { + continue; + } + + int index = value & ((1 << 18) - 1); + const bool release = (value >> 18) & 0x1; + index %= allocs.size(); + + auto alloc = allocs[index]; + using std::swap; + swap(allocs[index], allocs.back()); + allocs.resize(allocs.size() - 1); + + region.Put(alloc, release); + break; + } + case 2: { + // Release + // value[0:17] - Length to release. + const Length len = Length(value & ((1 << 18) - 1)); + const HugeLength max_expected = + std::min(region.free_backed(), HLFromPages(len)); + + const HugeLength actual = region.Release(len); + if (unback.unback_success_) { + if (max_expected > NHugePages(0) && len > Length(0)) { + TC_CHECK_GT(actual, NHugePages(0)); + } + TC_CHECK_LE(actual, max_expected); + } else { + TC_CHECK_EQ(actual, NHugePages(0)); + } + break; + } + case 3: { + // Stats + region.stats(); + SmallSpanStats small; + LargeSpanStats large; + region.AddSpanStats(&small, &large); + break; + } + case 4: { + // Toggle + unback.unback_success_ = !unback.unback_success_; + break; + } + case 5: { + // Not quite a runtime parameter: Interpret value as a subprogram + // in our dsl. + size_t subprogram = std::min(size - i - 9, value); + if (subprogram < 9) { + break; + } + reentrant.emplace_back(data + i + 9, subprogram); + i += size; + break; + } + case 6: { + // Gather stats in pbtxt format. + // + // value is unused. + Printer p(&output[0], output.size()); + { + PbtxtRegion r(p, kTop); + region.PrintInPbtxt(r); + } + CHECK_LE(p.SpaceRequired(), output.size()); + break; + } + case 7: { + // Print stats. + // + // value is unused. + Printer p(&output[0], output.size()); + region.Print(p); + break; + } + } + } + }; + + unback.release_callback_ = [&]() { + if (!reentrant_release) { + return; + } + + if (reentrant.empty()) { + return; + } + + ABSL_CONST_INIT static int depth = 0; + if (depth >= 5) { + return; + } + + auto [data, size] = reentrant.back(); + reentrant.pop_back(); + + depth++; + run_dsl(data, size); + depth--; + }; + + run_dsl(data, size); + + // Stop recursing, since region.Put below might cause us to "release" + // more pages to the system. + reentrant.clear(); + + for (const auto& alloc : allocs) { + region.Put(alloc, false); + } +} + +FUZZ_TEST(HugeRegionTest, FuzzRegion) + ; + +TEST(HugeRegionTest, b339521569) { + FuzzRegion(std::string( + "L\220\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" + "\000\000\000\000\000\301\233", + 115)); +} + +} // namespace +} // namespace tcmalloc::tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/huge_region_test.cc b/contrib/libs/tcmalloc/tcmalloc/huge_region_test.cc index 4370b9276249..9565e10666cc 100644 --- a/contrib/libs/tcmalloc/tcmalloc/huge_region_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/huge_region_test.cc @@ -14,65 +14,72 @@ #include "tcmalloc/huge_region.h" +#include +#include #include -#include #include +#include +#include #include +#include +#include #include #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/base/thread_annotations.h" +#include "absl/container/fixed_array.h" +#include "absl/memory/memory.h" #include "absl/random/random.h" +#include "absl/synchronization/mutex.h" #include "absl/time/clock.h" #include "absl/time/time.h" +#include "absl/types/span.h" #include "tcmalloc/common.h" +#include "tcmalloc/huge_cache.h" +#include "tcmalloc/huge_page_subrelease.h" #include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/clock.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/pages.h" #include "tcmalloc/stats.h" +#include "tcmalloc/testing/thread_manager.h" namespace tcmalloc { namespace tcmalloc_internal { namespace { using testing::NiceMock; -using testing::StrictMock; +using testing::Return; class HugeRegionTest : public ::testing::Test { protected: HugeRegionTest() - : // an unlikely magic page - p_(HugePageContaining(reinterpret_cast(0x1faced200000))), - region_({p_, region_.size()}, MockUnback) { + : mock_(std::make_unique>()), + // an unlikely magic page + p_(HugePageContaining(reinterpret_cast(0x1faced200000))), + region_({p_, region_.size()}, *mock_) { // we usually don't care about backing calls, unless testing that // specifically. - mock_ = absl::make_unique>(); } ~HugeRegionTest() override { mock_.reset(nullptr); } - // This is wordy, but necessary for mocking: - class BackingInterface { + class MockBackingInterface : public MemoryModifyFunction { public: - virtual void Unback(void *p, size_t len) = 0; - virtual ~BackingInterface() {} - }; + MOCK_METHOD(bool, Unback, (PageId p, Length len), ()); - class MockBackingInterface : public BackingInterface { - public: - MOCK_METHOD2(Unback, void(void *p, size_t len)); + bool operator()(Range r) override { return Unback(r.p, r.n); } }; - static std::unique_ptr mock_; - - static void MockUnback(void *p, size_t len) { mock_->Unback(p, len); } + std::unique_ptr mock_; void CheckMock() { testing::Mock::VerifyAndClearExpectations(mock_.get()); } - void ExpectUnback(HugeRange r) { - void *ptr = r.start_addr(); - size_t bytes = r.byte_len(); - EXPECT_CALL(*mock_, Unback(ptr, bytes)).Times(1); + void ExpectUnback(HugeRange r, bool success = true) { + EXPECT_CALL(*mock_, Unback(r.start().first_page(), r.len().in_pages())) + .WillOnce(Return(success)); } struct Alloc { @@ -112,9 +119,9 @@ class HugeRegionTest : public ::testing::Test { return Allocate(n, &from_released); } - Alloc Allocate(Length n, bool *from_released) { + Alloc Allocate(Length n, bool* from_released) { Alloc ret; - CHECK_CONDITION(region_.MaybeGet(n, &ret.p, from_released)); + TC_CHECK(region_.MaybeGet(n, &ret.p, from_released)); ret.n = n; ret.mark = ++next_mark_; Mark(ret); @@ -123,17 +130,15 @@ class HugeRegionTest : public ::testing::Test { void Delete(Alloc a) { Check(a); - region_.Put(a.p, a.n, false); + region_.Put(Range(a.p, a.n), false); } void DeleteUnback(Alloc a) { Check(a); - region_.Put(a.p, a.n, true); + region_.Put(Range(a.p, a.n), true); } }; -std::unique_ptr HugeRegionTest::mock_; - TEST_F(HugeRegionTest, Basic) { Length total; std::vector allocs; @@ -195,8 +200,31 @@ TEST_F(HugeRegionTest, ReqsBacking) { } } +TEST_F(HugeRegionTest, ReleaseFrac) { + const Length n = kPagesPerHugePage; + bool from_released; + auto a = Allocate(n * 20, &from_released); + EXPECT_TRUE(from_released); + + Delete(a); + ExpectUnback({p_ + NHugePages(0), NHugePages(2)}); + EXPECT_EQ(NHugePages(2), region_.Release(NHugePages(2).in_pages())); + CheckMock(); + + ExpectUnback({p_ + NHugePages(2), NHugePages(1)}); + EXPECT_EQ(NHugePages(1), region_.Release(NHugePages(1).in_pages())); + CheckMock(); + + ExpectUnback({p_ + NHugePages(3), NHugePages(8)}); + EXPECT_EQ(NHugePages(8), region_.Release(NHugePages(8).in_pages())); + CheckMock(); + + ExpectUnback({p_ + NHugePages(11), NHugePages(9)}); + EXPECT_EQ(NHugePages(9), region_.Release(NHugePages(9).in_pages())); + CheckMock(); +} + TEST_F(HugeRegionTest, Release) { - mock_ = absl::make_unique>(); const Length n = kPagesPerHugePage; bool from_released; auto a = Allocate(n * 4 - Length(1), &from_released); @@ -220,18 +248,18 @@ TEST_F(HugeRegionTest, Release) { // overlap with others. Delete(b); ExpectUnback({p_ + NHugePages(4), NHugePages(2)}); - EXPECT_EQ(NHugePages(2), region_.Release()); + EXPECT_EQ(NHugePages(2), region_.Release(NHugePages(2).in_pages())); CheckMock(); // Now we're on exact boundaries so we should unback the whole range. Delete(d); ExpectUnback({p_ + NHugePages(12), NHugePages(2)}); - EXPECT_EQ(NHugePages(2), region_.Release()); + EXPECT_EQ(NHugePages(2), region_.Release(NHugePages(2).in_pages())); CheckMock(); Delete(a); ExpectUnback({p_ + NHugePages(0), NHugePages(4)}); - EXPECT_EQ(NHugePages(4), region_.Release()); + EXPECT_EQ(NHugePages(4), region_.Release(NHugePages(4).in_pages())); CheckMock(); // Should work just as well with aggressive Put(): @@ -247,8 +275,30 @@ TEST_F(HugeRegionTest, Release) { CheckMock(); } +TEST_F(HugeRegionTest, ReleaseFailure) { + const Length n = kPagesPerHugePage; + bool from_released; + auto a = Allocate(n * 4 - Length(1), &from_released); + EXPECT_TRUE(from_released); + EXPECT_EQ(NHugePages(4), region_.backed()); + + // Don't unback the first or last hugepage this touches -- since they + // overlap with others. + Delete(a); + ExpectUnback({p_, NHugePages(4)}, false); + EXPECT_EQ(NHugePages(0), region_.Release(NHugePages(4).in_pages())); + EXPECT_EQ(NHugePages(4), region_.backed()); + CheckMock(); + + // Reallocate. + a = Allocate(n * 4 - Length(1), &from_released); + EXPECT_FALSE(from_released); + Delete(a); + + EXPECT_EQ(NHugePages(4), region_.backed()); +} + TEST_F(HugeRegionTest, Reback) { - mock_ = absl::make_unique>(); const Length n = kPagesPerHugePage / 4; bool from_released; // Even in back/unback cycles we should still call the functions @@ -275,18 +325,151 @@ TEST_F(HugeRegionTest, Reback) { } } +class MemorySimulation final : public MemoryModifyFunction { + public: + MemorySimulation(absl::Mutex& mu, PageId base, + absl::Span> bytes) + : mu_(mu), base_(base), bytes_(bytes) {} + + bool operator()(Range r) override ABSL_NO_THREAD_SAFETY_ANALYSIS { + // TODO(b/73749855): Simulate with unlocking. + mu_.AssertHeld(); + + size_t index = (r.p - base_).raw_num(); + for (size_t i = 0, n = r.n.raw_num(); i < n; ++i) { + bytes_[index + i].store(0, std::memory_order_release); + } + + return true; + } + + private: + absl::Mutex& mu_; + PageId base_; + absl::Span> bytes_; +}; + +TEST_F(HugeRegionTest, ReleaseFuzz) { + absl::Mutex mu; + absl::FixedArray> bytes( + region_.size().in_pages().raw_num()); + + MemorySimulation simulation(mu, p_.first_page(), absl::MakeSpan(bytes)); + + region_.~HugeRegion(); + new (®ion_) HugeRegion({p_, region_.size()}, simulation); + + const int kThreads = 10; + std::vector rngs(kThreads); + + absl::Mutex state_mu; + struct FuzzAlloc { + int tid; + Range r; + }; + std::vector allocs; + + ThreadManager threads; + threads.Start(kThreads, [&](int tid) { + switch (absl::Uniform(rngs[tid], 0, 4)) { + case 0: { + const size_t n = + absl::Uniform(rngs[tid], 1u, region_.size().in_pages().raw_num()); + + FuzzAlloc f; + f.tid = tid; + f.r.n = Length(n); + bool from_released; + { + absl::MutexLock l(&mu); + if (!region_.MaybeGet(f.r.n, &f.r.p, &from_released)) { + break; + } + } + + const size_t base = (f.r.p - p_.first_page()).raw_num(); + for (size_t i = 0; i < n; ++i) { + const int old_val = + bytes[base + i].exchange(tid, std::memory_order_acq_rel); + TC_CHECK_EQ(old_val, 0); + } + + { + absl::MutexLock l(&state_mu); + allocs.push_back(f); + } + break; + } + case 1: { + FuzzAlloc f; + + { + absl::MutexLock l(&state_mu); + if (allocs.empty()) { + break; + } + + const size_t index = absl::Uniform(rngs[tid], 0u, allocs.size()); + f = allocs[index]; + std::swap(allocs[index], allocs.back()); + allocs.resize(allocs.size() - 1); + } + + const size_t base = (f.r.p - p_.first_page()).raw_num(); + for (size_t i = 0; i < f.r.n.raw_num(); ++i) { + const int old_val = + bytes[base + i].exchange(0, std::memory_order_acq_rel); + TC_CHECK_EQ(old_val, f.tid); + } + + absl::MutexLock l(&mu); + region_.Put(f.r, false); + break; + } + case 2: { + absl::MutexLock l(&state_mu); + if (allocs.empty()) { + break; + } + + const size_t index = absl::Uniform(rngs[tid], 0u, allocs.size()); + FuzzAlloc f = allocs[index]; + + const size_t base = (f.r.p - p_.first_page()).raw_num(); + for (size_t i = 0; i < f.r.n.raw_num(); ++i) { + const int val = bytes[base + i].load(std::memory_order_acquire); + TC_CHECK_EQ(val, f.tid); + } + + break; + } + case 3: { + const Length to_release = Length( + absl::Uniform(rngs[tid], 0u, region_.size().in_pages().raw_num())); + + absl::MutexLock l(&mu); + region_.Release(to_release); + + break; + } + } + }); + + absl::SleepFor(absl::Seconds(1)); + + threads.Stop(); +} + TEST_F(HugeRegionTest, Stats) { const Length kLen = region_.size().in_pages(); const size_t kBytes = kLen.in_bytes(); struct Helper { - static void Stat(const Region ®ion, std::vector *small_backed, - std::vector *small_unbacked, LargeSpanStats *large, - BackingStats *stats, double *avg_age_backed, - double *avg_age_unbacked) { + static void Stat(const Region& region, std::vector* small_backed, + std::vector* small_unbacked, LargeSpanStats* large, + BackingStats* stats) { SmallSpanStats small; *large = LargeSpanStats(); - PageAgeHistograms ages(absl::base_internal::CycleClock::Now()); - region.AddSpanStats(&small, large, &ages); + region.AddSpanStats(&small, large); small_backed->clear(); small_unbacked->clear(); for (auto i = Length(0); i < kMaxPages; ++i) { @@ -300,20 +483,14 @@ TEST_F(HugeRegionTest, Stats) { } *stats = region.stats(); - - *avg_age_backed = ages.GetTotalHistogram(false)->avg_age(); - *avg_age_unbacked = ages.GetTotalHistogram(true)->avg_age(); } }; LargeSpanStats large; std::vector small_backed, small_unbacked; BackingStats stats; - double avg_age_backed, avg_age_unbacked; - absl::SleepFor(absl::Milliseconds(10)); - Helper::Stat(region_, &small_backed, &small_unbacked, &large, &stats, - &avg_age_backed, &avg_age_unbacked); + Helper::Stat(region_, &small_backed, &small_unbacked, &large, &stats); EXPECT_THAT(small_backed, testing::ElementsAre()); EXPECT_THAT(small_unbacked, testing::ElementsAre()); EXPECT_EQ(1, large.spans); @@ -322,8 +499,6 @@ TEST_F(HugeRegionTest, Stats) { EXPECT_EQ(kBytes, stats.system_bytes); EXPECT_EQ(0, stats.free_bytes); EXPECT_EQ(kBytes, stats.unmapped_bytes); - EXPECT_LE(0.01, avg_age_unbacked); - EXPECT_EQ(0, avg_age_backed); // We don't, in production, use small allocations from the region, but // the API supports it, so test it here. @@ -335,9 +510,7 @@ TEST_F(HugeRegionTest, Stats) { Allocate(Length(1)); const Length slack = kPagesPerHugePage - Length(9); - absl::SleepFor(absl::Milliseconds(20)); - Helper::Stat(region_, &small_backed, &small_unbacked, &large, &stats, - &avg_age_backed, &avg_age_unbacked); + Helper::Stat(region_, &small_backed, &small_unbacked, &large, &stats); EXPECT_THAT(small_backed, testing::ElementsAre()); EXPECT_THAT(small_unbacked, testing::ElementsAre()); EXPECT_EQ(2, large.spans); @@ -346,13 +519,9 @@ TEST_F(HugeRegionTest, Stats) { EXPECT_EQ(kBytes, stats.system_bytes); EXPECT_EQ(slack.in_bytes(), stats.free_bytes); EXPECT_EQ((region_.size() - NHugePages(1)).in_bytes(), stats.unmapped_bytes); - EXPECT_LE(0.02, avg_age_backed); - EXPECT_LE(0.03, avg_age_unbacked); Delete(a); - absl::SleepFor(absl::Milliseconds(30)); - Helper::Stat(region_, &small_backed, &small_unbacked, &large, &stats, - &avg_age_backed, &avg_age_unbacked); + Helper::Stat(region_, &small_backed, &small_unbacked, &large, &stats); EXPECT_THAT(small_backed, testing::ElementsAre(Length(1))); EXPECT_THAT(small_unbacked, testing::ElementsAre()); EXPECT_EQ(2, large.spans); @@ -361,14 +530,9 @@ TEST_F(HugeRegionTest, Stats) { EXPECT_EQ(kBytes, stats.system_bytes); EXPECT_EQ((slack + Length(1)).in_bytes(), stats.free_bytes); EXPECT_EQ((region_.size() - NHugePages(1)).in_bytes(), stats.unmapped_bytes); - EXPECT_LE((slack.raw_num() * 0.05 + 1 * 0.03) / (slack.raw_num() + 1), - avg_age_backed); - EXPECT_LE(0.06, avg_age_unbacked); Delete(b); - absl::SleepFor(absl::Milliseconds(40)); - Helper::Stat(region_, &small_backed, &small_unbacked, &large, &stats, - &avg_age_backed, &avg_age_unbacked); + Helper::Stat(region_, &small_backed, &small_unbacked, &large, &stats); EXPECT_THAT(small_backed, testing::ElementsAre(Length(1), Length(2))); EXPECT_THAT(small_unbacked, testing::ElementsAre()); EXPECT_EQ(2, large.spans); @@ -377,15 +541,9 @@ TEST_F(HugeRegionTest, Stats) { EXPECT_EQ(kBytes, stats.system_bytes); EXPECT_EQ((slack + Length(3)).in_bytes(), stats.free_bytes); EXPECT_EQ((region_.size() - NHugePages(1)).in_bytes(), stats.unmapped_bytes); - EXPECT_LE( - (slack.raw_num() * 0.09 + 1 * 0.07 + 2 * 0.04) / (slack.raw_num() + 3), - avg_age_backed); - EXPECT_LE(0.10, avg_age_unbacked); Delete(c); - absl::SleepFor(absl::Milliseconds(50)); - Helper::Stat(region_, &small_backed, &small_unbacked, &large, &stats, - &avg_age_backed, &avg_age_unbacked); + Helper::Stat(region_, &small_backed, &small_unbacked, &large, &stats); EXPECT_THAT(small_backed, testing::ElementsAre(Length(1), Length(2), Length(3))); EXPECT_THAT(small_unbacked, testing::ElementsAre()); @@ -395,15 +553,9 @@ TEST_F(HugeRegionTest, Stats) { EXPECT_EQ(kBytes, stats.system_bytes); EXPECT_EQ((slack + Length(6)).in_bytes(), stats.free_bytes); EXPECT_EQ((region_.size() - NHugePages(1)).in_bytes(), stats.unmapped_bytes); - EXPECT_LE((slack.raw_num() * 0.14 + 1 * 0.12 + 2 * 0.09 + 3 * 0.05) / - (slack.raw_num() + 6), - avg_age_backed); - EXPECT_LE(0.15, avg_age_unbacked); Delete(barrier); - absl::SleepFor(absl::Milliseconds(60)); - Helper::Stat(region_, &small_backed, &small_unbacked, &large, &stats, - &avg_age_backed, &avg_age_unbacked); + Helper::Stat(region_, &small_backed, &small_unbacked, &large, &stats); EXPECT_THAT(small_backed, testing::ElementsAre(Length(1), Length(6))); EXPECT_THAT(small_unbacked, testing::ElementsAre()); EXPECT_EQ(2, large.spans); @@ -412,11 +564,6 @@ TEST_F(HugeRegionTest, Stats) { EXPECT_EQ(kBytes, stats.system_bytes); EXPECT_EQ((slack + Length(7)).in_bytes(), stats.free_bytes); EXPECT_EQ((region_.size() - NHugePages(1)).in_bytes(), stats.unmapped_bytes); - EXPECT_LE( - (slack.raw_num() * 0.20 + 1 * 0.18 + 2 * 0.15 + 3 * 0.11 + 1 * 0.06) / - (slack.raw_num() + 7), - avg_age_backed); - EXPECT_LE(0.21, avg_age_unbacked); } // Test that free regions are broken down properly when they cross @@ -429,11 +576,13 @@ TEST_F(HugeRegionTest, StatBreakdown) { Alloc d = Allocate(n - (n / 5) - Length(1)); // This unbacks the middle 2 hugepages, but not the beginning or // trailing region + ExpectUnback( + HugeRange::Make(HugePageContaining(b.p) + NHugePages(1), NHugePages(2))); DeleteUnback(b); Delete(c); SmallSpanStats small; LargeSpanStats large; - region_.AddSpanStats(&small, &large, nullptr); + region_.AddSpanStats(&small, &large); // Backed beginning of hugepage 0, unbacked range in middle of b, // long backed range from c, unbacked tail of allocation. EXPECT_EQ(4, large.spans); @@ -450,31 +599,439 @@ TEST_F(HugeRegionTest, StatBreakdown) { Delete(d); } -static void NilUnback(void *p, size_t bytes) {} +TEST_F(HugeRegionTest, StatBreakdownReleaseFailure) { + const Length n = kPagesPerHugePage; + Alloc a = Allocate(n / 4); + Alloc b = Allocate(n * 3 + n / 3); + Alloc c = Allocate((n - n / 3 - n / 4) + n * 5 + n / 5); + Alloc d = Allocate(n - (n / 5) - Length(1)); + // This tries to unback the middle 2 hugepages, but not the beginning or + // trailing region, but fails. + ExpectUnback( + HugeRange::Make(HugePageContaining(b.p) + NHugePages(1), NHugePages(2)), + /*success=*/false); + DeleteUnback(b); + Delete(c); + SmallSpanStats small; + LargeSpanStats large; + region_.AddSpanStats(&small, &large); + // Backed beginning of hugepage A/B/C/D and the unbacked tail of allocation. + EXPECT_EQ(2, large.spans); + // Tail end of A's page, all of B, all of C. + EXPECT_EQ((n - n / 4) + n * 8 + (n / 5), large.normal_pages); + // The above fill up 10 total pages. + EXPECT_EQ((Region::size().raw_num() - 10) * n, large.returned_pages); + EXPECT_EQ(1, small.normal_length[1]); -class HugeRegionSetTest : public testing::Test { + EXPECT_EQ(Length(1) + large.normal_pages + large.returned_pages + + region_.used_pages(), + Region::size().in_pages()); + Delete(a); + Delete(d); +} + +class NilUnback final : public MemoryModifyFunction { + public: + bool operator()(Range r) override { return true; } +}; + +class HugeRegionSetTest + : public ::testing::TestWithParam { protected: typedef HugeRegion Region; - HugeRegionSetTest() { next_ = HugePageContaining(nullptr); } + static int64_t FakeClock() { return clock_; } + static double GetFakeClockFrequency() { + return absl::ToDoubleNanoseconds(absl::Seconds(2)); + } + static void Advance(absl::Duration d) { + clock_ += absl::ToDoubleSeconds(d) * GetFakeClockFrequency(); + } + + HugeRegionSetTest() + : set_(/*use_huge_region_more_often=*/GetParam(), + Clock{.now = FakeClock, .freq = GetFakeClockFrequency}) { + next_ = HugePageContaining(nullptr); + } std::unique_ptr GetRegion() { // These regions are backed by "real" memory, but we don't touch it. - std::unique_ptr r(new Region({next_, Region::size()}, NilUnback)); + std::unique_ptr r(new Region({next_, Region::size()}, nil_unback_)); next_ += Region::size(); return r; } - HugeRegionSet set_; - HugePage next_; - struct Alloc { PageId p; Length n; }; + + Alloc Allocate(Length n) { + bool from_released; + return Allocate(n, &from_released); + } + + Alloc Allocate(Length n, bool* from_released) { + Alloc ret; + TC_CHECK(set_.MaybeGet(n, &ret.p, from_released)); + ret.n = n; + return ret; + } + + void Delete(Alloc a) { TC_CHECK(set_.MaybePut(Range(a.p, a.n))); } + + Length ReleasePagesByPeakDemand(Length desired, + SkipSubreleaseIntervals intervals = {}, + bool hit_limit = false) { + return set_.ReleasePagesByPeakDemand(desired, intervals, hit_limit); + } + + Length HardReleasePages(Length desired) { + return set_.ReleasePagesByPeakDemand(desired, SkipSubreleaseIntervals{}, + /*hit_limit=*/true); + } + + bool UseHugeRegionMoreOften() const { return set_.UseHugeRegionMoreOften(); } + + NilUnback nil_unback_; + HugeRegionSet set_; + HugePage next_; + + static int64_t clock_; }; -TEST_F(HugeRegionSetTest, Set) { +int64_t HugeRegionSetTest::clock_{1234}; + +TEST_P(HugeRegionSetTest, Release) { + absl::BitGen rng; + PageId p; + constexpr Length kSize = kPagesPerHugePage + Length(1); + bool from_released; + ASSERT_FALSE(set_.MaybeGet(Length(1), &p, &from_released)); + auto r1 = GetRegion(); + set_.Contribute(r1.get()); + + std::vector allocs; + + while (set_.MaybeGet(kSize, &p, &from_released)) { + allocs.push_back({p, kSize}); + } + BackingStats stats = set_.stats(); + EXPECT_EQ(stats.unmapped_bytes, 0); + + for (auto a : allocs) { + ASSERT_TRUE(set_.MaybePut(Range(a.p, a.n))); + } + + stats = set_.stats(); + EXPECT_EQ(stats.unmapped_bytes, + UseHugeRegionMoreOften() ? 0 : stats.system_bytes); + // All the huge pages in the region would be free, but backed, when + // huge-region-more-often feature is enabled. + EXPECT_EQ(r1->free_backed().raw_num(), + UseHugeRegionMoreOften() ? Region::size().raw_num() : 0); + Length released = set_.ReleasePages(/*release_fraction=*/1.0); + stats = set_.stats(); + EXPECT_EQ(released.in_bytes(), + UseHugeRegionMoreOften() ? stats.system_bytes : 0); + EXPECT_EQ(r1->free_backed().in_bytes(), 0); + EXPECT_EQ(stats.unmapped_bytes, stats.system_bytes); +} + +// Tests that HugeRegions releases all pages in free hugepages when +// skip-subrelease intervals are not set. +TEST_P(HugeRegionSetTest, ReleasePagesWithoutIntervals) { + absl::BitGen rng; + PageId p; + constexpr Length kSize = kPagesPerHugePage + Length(1); + bool from_released; + ASSERT_FALSE(set_.MaybeGet(Length(1), &p, &from_released)); + auto r1 = GetRegion(); + set_.Contribute(r1.get()); + + std::vector allocs; + + while (set_.MaybeGet(kSize, &p, &from_released)) { + allocs.push_back({p, kSize}); + } + BackingStats stats = set_.stats(); + EXPECT_EQ(stats.unmapped_bytes, 0); + + for (auto a : allocs) { + ASSERT_TRUE(set_.MaybePut(Range(a.p, a.n))); + } + + stats = set_.stats(); + EXPECT_EQ(stats.unmapped_bytes, + UseHugeRegionMoreOften() ? 0 : stats.system_bytes); + // All the huge pages in the region would be free, but backed, when + // huge-region-more-often feature is enabled. + EXPECT_EQ(r1->free_backed().raw_num(), + UseHugeRegionMoreOften() ? Region::size().raw_num() : 0); + Length released = ReleasePagesByPeakDemand(r1->free_backed().in_pages()); + stats = set_.stats(); + EXPECT_EQ(released.in_bytes(), + UseHugeRegionMoreOften() ? stats.system_bytes : 0); + EXPECT_EQ(r1->free_backed().in_bytes(), 0); + EXPECT_EQ(stats.unmapped_bytes, stats.system_bytes); +} + +// Tests that releasing zero pages is allowed and does not crash. +TEST_P(HugeRegionSetTest, ReleaseZero) { + // Trying to release no pages should not crash. + EXPECT_EQ(ReleasePagesByPeakDemand( + Length(0), + SkipSubreleaseIntervals{.short_interval = absl::Seconds(10), + .long_interval = absl::Seconds(600)}), + Length(0)); +} + +// Tests that HugeRegions releases fraction of hugepages when desired pages is +// set to zero. Because HugeRegion releases complete hugepages, for cases when +// malloc release rate is set to zero, this ensures that we still release a +// fraction of free hugepages. +TEST_P(HugeRegionSetTest, ReleaseZeroPages) { + absl::BitGen rng; + PageId p; + constexpr Length kSize = kPagesPerHugePage + Length(1); + bool from_released; + ASSERT_FALSE(set_.MaybeGet(Length(1), &p, &from_released)); + auto r1 = GetRegion(); + set_.Contribute(r1.get()); + + std::vector allocs; + + while (set_.MaybeGet(kSize, &p, &from_released)) { + allocs.push_back({p, kSize}); + } + BackingStats stats = set_.stats(); + EXPECT_EQ(stats.unmapped_bytes, 0); + + for (auto a : allocs) { + ASSERT_TRUE(set_.MaybePut(Range(a.p, a.n))); + } + + stats = set_.stats(); + EXPECT_EQ(stats.unmapped_bytes, + UseHugeRegionMoreOften() ? 0 : stats.system_bytes); + // All the huge pages in the region would be free, but backed, when + // huge-region-more-often feature is enabled. + EXPECT_EQ(r1->free_backed().raw_num(), + UseHugeRegionMoreOften() ? Region::size().raw_num() : 0); + HugeLength expected = + UseHugeRegionMoreOften() + ? HugeLength(kFractionToReleaseFromRegion * Region::size().raw_num()) + : NHugePages(0); + Length released = ReleasePagesByPeakDemand(Length(0)); + stats = set_.stats(); + EXPECT_EQ(released.in_bytes(), + UseHugeRegionMoreOften() ? expected.in_bytes() : 0); +} + +// Tests the number of pages that are released for different skip subrelease +// intervals. +TEST_P(HugeRegionSetTest, SkipSubrelease) { + // This test is sensitive to the number of pages per hugepage, as we are + // printing raw stats. + if (kPagesPerHugePage != Length(256)) { + GTEST_SKIP(); + } + + if (!UseHugeRegionMoreOften()) { + GTEST_SKIP() << "Skipping this test as background release is available " + "only when we use huge regions more often."; + } + + auto r1 = GetRegion(); + set_.Contribute(r1.get()); + // Firstly, this test generates a peak (long-term demand peak) and waits for + // time interval a. Then, it generates a higher peak plus a short-term + // fluctuation peak, and waits for time interval b. It then generates a trough + // in demand and tries to subrelease. Finally, it waits for time interval c to + // generate the highest peak for evaluating subrelease correctness. Skip + // subrelease selects those demand points using provided time intervals. + const auto demand_pattern = [&](absl::Duration a, absl::Duration b, + absl::Duration c, + SkipSubreleaseIntervals intervals, + bool release_phase_1, bool release_phase_2) { + const Length N = kPagesPerHugePage; + // First peak: min_demand 3/4N, max_demand 1N. + Alloc peak1a = Allocate(3 * N / 4); + Alloc peak1b = Allocate(N / 4); + Advance(a); + // Second peak: min_demand 0, max_demand 2N. + Delete(peak1a); + Delete(peak1b); + + Alloc half = Allocate(N / 2); + Alloc tiny1 = Allocate(N / 4); + Alloc tiny2 = Allocate(N / 4); + + // To force a peak, we allocate 3/4 and 1/4 of a huge page. This is + // necessary after we delete `half` below, as a half huge page for the + // peak would fill into the gap previously occupied by it. + Alloc peak2a = Allocate(3 * N / 4); + Alloc peak2b = Allocate(N / 4); + // EXPECT_EQ(set_.used_pages(), 2 * N); + Delete(peak2a); + Delete(peak2b); + Advance(b); + Delete(half); + EXPECT_EQ(set_.free_backed(), NHugePages(1)); + // The number of released pages is limited to the number of free pages. + EXPECT_EQ(ReleasePagesByPeakDemand(10 * N, intervals), + release_phase_1 ? kPagesPerHugePage : Length(0)); + // + Advance(c); + // Third peak: min_demand 1/2N, max_demand (2+1/2)N. + Alloc peak3a = Allocate(3 * N / 4); + Alloc peak3b = Allocate(N / 4); + + Alloc peak4a = Allocate(3 * N / 4); + Alloc peak4b = Allocate(N / 4); + + Delete(tiny1); + Delete(tiny2); + Delete(peak3a); + Delete(peak3b); + Delete(peak4a); + Delete(peak4b); + + EXPECT_EQ(set_.free_backed(), NHugePages(3)); + EXPECT_EQ(ReleasePagesByPeakDemand(10 * N, intervals), + release_phase_2 ? NHugePages(3).in_pages() : Length(0)); + HardReleasePages(10 * N); + }; + + { + // Skip subrelease feature is disabled if all intervals are zero. + SCOPED_TRACE("demand_pattern 1"); + demand_pattern(absl::Minutes(1), absl::Minutes(1), absl::Minutes(4), + SkipSubreleaseIntervals{}, + /*release_phase_1=*/true, + /*release_phase_2=*/true); + } + + Advance(absl::Minutes(30)); + + { + // Uses short-term and long-term intervals for skipping subrelease. + SCOPED_TRACE("demand_pattern 2"); + demand_pattern(absl::Minutes(3), absl::Minutes(2), absl::Minutes(7), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(3), + .long_interval = absl::Minutes(6)}, + /*release_phase_1=*/false, + /*release_phase_2=*/false); + } + + Advance(absl::Minutes(30)); + + { + // Uses short-term and long-term intervals for skipping subrelease, + // subreleasing all free pages. + SCOPED_TRACE("demand_pattern 3"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(1), + .long_interval = absl::Minutes(2)}, + /*release_phase_1=*/true, + /*release_phase_2=*/false); + } + Advance(absl::Minutes(30)); + + { + // Uses only short-term interval for skipping subrelease. + SCOPED_TRACE("demand_pattern 4"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(3)}, + /*release_phase_1=*/false, + /*release_phase_2=*/false); + } + + Advance(absl::Minutes(30)); + + { + // Uses only long-term interval for skipping subrelease, subreleased all + // free pages. + SCOPED_TRACE("demand_pattern 5"); + demand_pattern(absl::Minutes(4), absl::Minutes(2), absl::Minutes(3), + SkipSubreleaseIntervals{.long_interval = absl::Minutes(2)}, + /*release_phase_1=*/true, + /*release_phase_2=*/true); + } + + Advance(absl::Minutes(30)); + + // This captures a corner case: If we hit another peak immediately after a + // subrelease decision (in the same time series epoch), do not count this as + // a correct subrelease decision. + { + SCOPED_TRACE("demand_pattern 6"); + demand_pattern(absl::Milliseconds(10), absl::Milliseconds(10), + absl::Milliseconds(10), + SkipSubreleaseIntervals{.short_interval = absl::Minutes(1), + .long_interval = absl::Minutes(2)}, + /*release_phase_1=*/false, + /*release_phase_2=*/false); + } + + Advance(absl::Minutes(30)); + + // Ensure that the tracker is updated. + auto tiny = Allocate(Length(1)); + Delete(tiny); + + std::string buffer(1024 * 1024, '\0'); + { + Printer printer(&*buffer.begin(), buffer.size()); + set_.Print(printer); + } + buffer.resize(strlen(buffer.c_str())); + + EXPECT_THAT(buffer, testing::HasSubstr(R"( +HugeRegion: Since the start of the execution, 7 subreleases (3840 pages) were skipped due to the sum of short-term (60s) fluctuations and long-term (120s) trends. +HugeRegion: 0.0000% of decisions confirmed correct, 0 pending (0.0000% of pages, 0 pending). +)")); +} + +// Tests that HugeRegion releases all free hugepages when hit_limit is set to +// true. +TEST_P(HugeRegionSetTest, HardRelease) { + absl::BitGen rng; + PageId p; + constexpr Length kSize = kPagesPerHugePage + Length(1); + bool from_released; + ASSERT_FALSE(set_.MaybeGet(Length(1), &p, &from_released)); + auto r1 = GetRegion(); + set_.Contribute(r1.get()); + + std::vector allocs; + + while (set_.MaybeGet(kSize, &p, &from_released)) { + allocs.push_back({p, kSize}); + } + BackingStats stats = set_.stats(); + EXPECT_EQ(stats.unmapped_bytes, 0); + + for (auto a : allocs) { + ASSERT_TRUE(set_.MaybePut(Range(a.p, a.n))); + } + + stats = set_.stats(); + EXPECT_EQ(stats.unmapped_bytes, + UseHugeRegionMoreOften() ? 0 : stats.system_bytes); + // All the huge pages in the region would be free, but backed, when + // huge-region-more-often feature is enabled. + EXPECT_EQ(r1->free_backed().raw_num(), + UseHugeRegionMoreOften() ? Region::size().raw_num() : 0); + Length released = HardReleasePages(r1->free_backed().in_pages()); + stats = set_.stats(); + EXPECT_EQ(released.in_bytes(), + UseHugeRegionMoreOften() ? stats.system_bytes : 0); + EXPECT_EQ(r1->free_backed().in_bytes(), 0); + EXPECT_EQ(stats.unmapped_bytes, stats.system_bytes); +} + +TEST_P(HugeRegionSetTest, Set) { absl::BitGen rng; PageId p; constexpr Length kSize = kPagesPerHugePage + Length(1); @@ -504,7 +1061,7 @@ TEST_F(HugeRegionSetTest, Set) { allocs.erase(allocs.begin() + allocs.size() / 2, allocs.end()); for (auto d : doomed) { - ASSERT_TRUE(set_.MaybePut(d.p, d.n)); + ASSERT_TRUE(set_.MaybePut(Range(d.p, d.n))); } for (size_t i = 0; i < 100 * 1000; ++i) { @@ -512,7 +1069,7 @@ TEST_F(HugeRegionSetTest, Set) { size_t index = absl::Uniform(rng, 0, N); std::swap(allocs[index], allocs[N - 1]); auto a = allocs.back(); - ASSERT_TRUE(set_.MaybePut(a.p, a.n)); + ASSERT_TRUE(set_.MaybePut(Range(a.p, a.n))); allocs.pop_back(); ASSERT_TRUE(set_.MaybeGet(kSize, &p, &from_released)); allocs.push_back({p, kSize}); @@ -521,16 +1078,15 @@ TEST_F(HugeRegionSetTest, Set) { // Random traffic should have defragmented our allocations into full // and empty regions, and released the empty ones. Annoyingly, we don't // know which region is which, so we have to do a bit of silliness: - std::vector regions = {r1.get(), r2.get(), r3.get(), r4.get()}; + std::vector regions = {r1.get(), r2.get(), r3.get(), r4.get()}; std::sort(regions.begin(), regions.end(), - [](const Region *a, const Region *b) -> bool { + [](const Region* a, const Region* b) -> bool { return a->used_pages() > b->used_pages(); }); for (int i = 0; i < regions.size(); i++) { - Log(kLog, __FILE__, __LINE__, i, regions[i]->used_pages().raw_num(), - regions[i]->free_pages().raw_num(), - regions[i]->unmapped_pages().raw_num()); + TC_LOG("i=%v used=%v free=%v unmapped=%v", i, regions[i]->used_pages(), + regions[i]->free_pages(), regions[i]->unmapped_pages()); } // Now first two should be "full" (ish) EXPECT_LE(Region::size().in_pages().raw_num() * 0.9, @@ -538,10 +1094,21 @@ TEST_F(HugeRegionSetTest, Set) { EXPECT_LE(Region::size().in_pages().raw_num() * 0.9, regions[1]->used_pages().raw_num()); // and last two "empty" (ish.) - EXPECT_LE(Region::size().in_pages().raw_num() * 0.9, - regions[2]->unmapped_pages().raw_num()); - EXPECT_LE(Region::size().in_pages().raw_num() * 0.9, - regions[3]->unmapped_pages().raw_num()); + if (UseHugeRegionMoreOften()) { + EXPECT_EQ(regions[2]->unmapped_pages().raw_num(), 0); + EXPECT_EQ(regions[3]->unmapped_pages().raw_num(), 0); + EXPECT_GT(regions[2]->free_backed().raw_num(), + Region::size().raw_num() * 0.9); + EXPECT_GT(regions[3]->free_backed().raw_num(), + Region::size().raw_num() * 0.9); + } else { + EXPECT_LE(Region::size().in_pages().raw_num() * 0.9, + regions[2]->unmapped_pages().raw_num()); + EXPECT_LE(Region::size().in_pages().raw_num() * 0.9, + regions[3]->unmapped_pages().raw_num()); + EXPECT_EQ(regions[2]->free_backed().raw_num(), 0); + EXPECT_EQ(regions[3]->free_backed().raw_num(), 0); + } // Check the stats line up. auto stats = set_.stats(); @@ -556,10 +1123,15 @@ TEST_F(HugeRegionSetTest, Set) { // Print out the stats for inspection of formats. std::vector buf(64 * 1024); Printer out(&buf[0], buf.size()); - set_.Print(&out); + set_.Print(out); printf("%s\n", &buf[0]); } +INSTANTIATE_TEST_SUITE_P( + All, HugeRegionSetTest, + testing::Values(HugeRegionUsageOption::kDefault, + HugeRegionUsageOption::kUseForAllLargeAllocs)); + } // namespace } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/BUILD b/contrib/libs/tcmalloc/tcmalloc/internal/BUILD new file mode 100644 index 000000000000..38a2b6f54952 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/BUILD @@ -0,0 +1,1122 @@ +# Copyright 2019 The TCMalloc Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Internal libraries used for the implementation and testing of TCMalloc. + +load("@com_google_protobuf//bazel:cc_proto_library.bzl", "cc_proto_library") +load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library") +load("//tcmalloc:copts.bzl", "TCMALLOC_DEFAULT_COPTS") +load("//tcmalloc:variants.bzl", "create_tcmalloc_benchmark") + +package(default_visibility = ["//visibility:private"]) + +licenses(["notice"]) + +cc_library( + name = "affinity", + testonly = 1, + srcs = ["affinity.cc"], + hdrs = ["affinity.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":cpu_utils", + ":logging", + "@com_google_absl//absl/types:span", + ], +) + +cc_test( + name = "affinity_test", + srcs = ["affinity_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":affinity", + ":cpu_utils", + ":percpu", + "@com_google_absl//absl/types:span", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "allocation_guard", + srcs = ["allocation_guard.cc"], + hdrs = ["allocation_guard.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + "@com_google_absl//absl/base", + "@com_google_absl//absl/base:core_headers", + ], +) + +cc_test( + name = "allocation_guard_test", + srcs = ["allocation_guard_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":allocation_guard", + "@com_google_absl//absl/base", + "@com_google_absl//absl/base:core_headers", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "atomic_danger", + hdrs = ["atomic_danger.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = ["//visibility:private"], + deps = [":config"], +) + +cc_library( + name = "atomic_stats_counter", + hdrs = ["atomic_stats_counter.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [":config"], +) + +cc_library( + name = "clock", + hdrs = ["clock.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [":config"], +) + +cc_library( + name = "config", + hdrs = ["config.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + "@com_google_absl//absl/base:config", + "@com_google_absl//absl/base:core_headers", + ], +) + +cc_test( + name = "config_test", + srcs = ["config_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":config", + ":util", + "@com_google_absl//absl/strings", + "@com_google_googletest//:gtest_main", + "@com_google_protobuf//:protobuf", + ], +) + +cc_library( + name = "declarations", + hdrs = ["declarations.h"], + visibility = [ + "//tcmalloc:__subpackages__", + ], +) + +cc_library( + name = "environment", + srcs = ["environment.cc"], + hdrs = ["environment.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [":config"], +) + +cc_test( + name = "environment_test", + srcs = ["environment_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":environment", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "explicitly_constructed", + hdrs = ["explicitly_constructed.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = ["//tcmalloc:__subpackages__"], + deps = [ + ":config", + ], +) + +cc_library( + name = "exponential_biased", + hdrs = ["exponential_biased.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], +) + +cc_test( + name = "exponential_biased_test", + srcs = ["exponential_biased_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":exponential_biased", + "//tcmalloc/testing:testutil", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "fake_profile", + hdrs = ["fake_profile.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + "//tcmalloc:malloc_extension", + "@com_google_absl//absl/functional:function_ref", + "@com_google_absl//absl/time", + ], +) + +cc_library( + name = "linked_list", + hdrs = ["linked_list.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":logging", + "@com_google_absl//absl/base:core_headers", + ], +) + +create_tcmalloc_benchmark( + name = "linked_list_benchmark", + srcs = ["linked_list_benchmark.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + malloc = "//tcmalloc", + deps = [ + ":config", + ":linked_list", + ":logging", + ":mock_span", + "@com_github_google_benchmark//:benchmark", + "@com_google_absl//absl/random", + ], +) + +cc_test( + name = "linked_list_test", + size = "small", + srcs = ["linked_list_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + linkstatic = 1, + deps = [ + ":linked_list", + ":mock_span", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/random", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "linux_syscall_support", + hdrs = ["linux_syscall_support.h"], + copts = TCMALLOC_DEFAULT_COPTS, +) + +cc_library( + name = "logging", + srcs = ["logging.cc"], + hdrs = ["logging.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__pkg__", + "//tcmalloc:__subpackages__", + ], + deps = [ + ":allocation_guard", + ":config", + ":environment", + ":parameter_accessors", + "//tcmalloc:malloc_extension", + "@com_google_absl//absl/base", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/debugging:stacktrace", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/time", + ], +) + +cc_test( + name = "logging_test", + srcs = ["logging_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + data = [ + ], + deps = [ + ":logging", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:string_view", + "@com_google_googletest//:gtest_main", + ], +) + +cc_binary( + name = "logging_test_helper", + testonly = 1, + srcs = ["logging_test_helper.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + malloc = "//tcmalloc", +) + +cc_library( + name = "memory_stats", + srcs = ["memory_stats.cc"], + hdrs = ["memory_stats.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":logging", + ":page_size", + ":util", + "@com_google_absl//absl/strings", + ], +) + +cc_test( + name = "memory_stats_test", + srcs = ["memory_stats_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":memory_stats", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "memory_tag", + srcs = ["memory_tag.cc"], + hdrs = ["memory_tag.h"], + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":logging", + ":optimization", + "@com_google_absl//absl/strings:string_view", + ], +) + +cc_library( + name = "mincore", + srcs = ["mincore.cc"], + hdrs = ["mincore.h"], + copts = TCMALLOC_DEFAULT_COPTS, + linkstatic = 1, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":page_size", + ], +) + +cc_library( + name = "mismatched_delete_state", + hdrs = ["mismatched_delete_state.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":logging", + "@com_google_absl//absl/types:span", + ], +) + +cc_library( + name = "residency", + srcs = ["residency.cc"], + hdrs = ["residency.h"], + copts = TCMALLOC_DEFAULT_COPTS, + linkstatic = 1, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":logging", + ":page_size", + ":range_tracker", + ":util", + "@com_google_absl//absl/status", + ], +) + +cc_library( + name = "pageflags", + srcs = ["pageflags.cc"], + hdrs = ["pageflags.h"], + copts = TCMALLOC_DEFAULT_COPTS, + linkstatic = 1, + visibility = [ + "//tcmalloc:__pkg__", + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":logging", + ":page_size", + ":util", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/cleanup", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + ], +) + +cc_test( + name = "pageflags_test", + srcs = ["pageflags_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + linkstatic = 1, + tags = [ + ], + deps = [ + ":allocation_guard", + ":pageflags", + ":util", + "@com_github_google_benchmark//:benchmark", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/log", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/random", + "@com_google_absl//absl/random:distributions", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", + "@com_google_absl//absl/time", + "@com_google_googletest//:gtest_main", + ], +) + +create_tcmalloc_benchmark( + name = "mincore_benchmark", + srcs = ["mincore_benchmark.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":config", + ":logging", + ":page_size", + "@com_github_google_benchmark//:benchmark", + ], +) + +cc_test( + name = "mincore_test", + srcs = ["mincore_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + linkstatic = 1, + deps = [ + ":mincore", + ":page_size", + "@com_github_google_benchmark//:benchmark", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "residency_test", + srcs = ["residency_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + linkstatic = 1, + deps = [ + ":allocation_guard", + ":config", + ":page_size", + ":range_tracker", + ":residency", + ":util", + "@com_github_google_benchmark//:benchmark", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:string_view", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "mock_span", + testonly = 1, + hdrs = ["mock_span.h"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":linked_list", + ], +) + +cc_library( + name = "cache_topology", + srcs = ["cache_topology.cc"], + hdrs = ["cache_topology.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":cpu_utils", + ":logging", + ":sysinfo", + ":util", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/strings", + ], +) + +cc_test( + name = "cache_topology_test", + srcs = ["cache_topology_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + linkstatic = 1, + deps = [ + ":cache_topology", + ":sysinfo", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "numa", + srcs = ["numa.cc"], + hdrs = ["numa.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":cpu_utils", + ":environment", + ":logging", + ":percpu", + ":sysinfo", + ":util", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/functional:function_ref", + ], +) + +cc_test( + name = "numa_test", + srcs = ["numa_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + linkstatic = 1, + deps = [ + ":logging", + ":numa", + ":percpu", + ":sysinfo", + "//tcmalloc:want_numa_aware", + "@com_google_absl//absl/random", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:optional", + "@com_google_absl//absl/types:span", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "optimization", + hdrs = ["optimization.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":logging", + "@com_google_absl//absl/base:core_headers", + ], +) + +cc_library( + name = "overflow", + hdrs = ["overflow.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + "@com_google_absl//absl/base:config", + ], +) + +cc_library( + name = "page_size", + srcs = ["page_size.cc"], + hdrs = ["page_size.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + "@com_google_absl//absl/base", + "@com_google_absl//absl/base:core_headers", + ], +) + +cc_library( + name = "parameter_accessors", + hdrs = ["parameter_accessors.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + "//tcmalloc:malloc_extension", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/time", + ], +) + +cc_library( + name = "percpu", + srcs = [ + "percpu.cc", + "percpu_rseq_asm.S", + "percpu_rseq_unsupported.cc", + ], + hdrs = ["percpu.h"], + copts = TCMALLOC_DEFAULT_COPTS, + # See b/299621672 for details. + linkstatic = 1, + textual_hdrs = [ + "percpu_rseq_aarch64.S", + "percpu_rseq_x86_64.S", + ], + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":cpu_utils", + ":linux_syscall_support", + ":logging", + ":optimization", + ":sysinfo", + ":util", + "@com_google_absl//absl/base", + "@com_google_absl//absl/base:core_headers", + ], +) + +cc_test( + name = "percpu_test", + srcs = ["percpu_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":logging", + ":percpu", + "//tcmalloc/testing:testutil", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/log:absl_check", + "@com_google_absl//absl/time", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "percpu_early_test", + srcs = ["percpu_early_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + linkstatic = 1, + tags = [ + ], + deps = [ + ":percpu", + "@com_google_absl//absl/base:core_headers", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "percpu_tcmalloc", + hdrs = ["percpu_tcmalloc.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":linux_syscall_support", + ":logging", + ":mincore", + ":optimization", + ":percpu", + ":prefetch", + ":sysinfo", + "@com_google_absl//absl/base", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/base:dynamic_annotations", + "@com_google_absl//absl/functional:function_ref", + "@com_google_absl//absl/numeric:bits", + ], +) + +cc_test( + name = "percpu_tcmalloc_test", + timeout = "long", + srcs = ["percpu_tcmalloc_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + linkstatic = 1, + malloc = ":system_malloc", + tags = ["noubsan"], + deps = [ + ":affinity", + ":config", + ":cpu_utils", + ":logging", + ":page_size", + ":percpu", + ":percpu_tcmalloc", + ":sysinfo", + ":util", + "//tcmalloc:malloc_extension", + "//tcmalloc/testing:testutil", + "@com_github_google_benchmark//:benchmark", + "@com_google_absl//absl/base", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/container:fixed_array", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/functional:function_ref", + "@com_google_absl//absl/random", + "@com_google_absl//absl/random:seed_sequences", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "prefetch", + hdrs = ["prefetch.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [":config"], +) + +cc_test( + name = "prefetch_test", + srcs = ["prefetch_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":prefetch", + "@com_google_googletest//:gtest_main", + ], +) + +proto_library( + name = "profile_proto", + srcs = ["profile.proto"], +) + +cc_proto_library( + name = "profile_cc_proto", + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [":profile_proto"], +) + +cc_library( + name = "profile_builder", + srcs = ["profile_builder.cc"], + hdrs = ["profile_builder.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":logging", + ":pageflags", + ":residency", + "//tcmalloc:malloc_extension", + "//tcmalloc/internal:profile_cc_proto", + "@com_google_absl//absl/base", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/container:btree", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/hash", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/time", + "@com_google_absl//absl/types:span", + ], +) + +cc_test( + name = "profile_builder_fuzz", + srcs = ["profile_builder_fuzz.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + data = glob(["testdata/profile_builder_fuzz/*"]), + deps = [ + ":profile_builder", + "@com_google_fuzztest//fuzztest", + "@com_google_fuzztest//fuzztest:fuzztest_gtest_main", + "@com_google_googletest//:gtest", + ], +) + +cc_test( + name = "profile_builder_test", + srcs = ["profile_builder_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + data = [ + "testdata/b180635896.so", + "testdata/gnu-property.so", + ], + deps = [ + ":environment", + ":fake_profile", + ":page_size", + ":pageflags", + ":profile_builder", + ":residency", + "//tcmalloc:malloc_extension", + "//tcmalloc/internal:profile_cc_proto", + "@com_google_absl//absl/base", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/log:check", + "@com_google_absl//absl/meta:type_traits", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/time", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( + name = "profile_builder_no_tcmalloc_test", + srcs = ["profile_builder_no_tcmalloc_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + malloc = ":system_malloc", + tags = [ + "noubsan", + ], + deps = [ + ":profile_builder", + "//tcmalloc:malloc_extension", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:status_matchers", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "proc_maps", + srcs = ["proc_maps.cc"], + hdrs = ["proc_maps.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":logging", + ":util", + "@com_google_absl//absl/strings:str_format", + ], +) + +cc_library( + name = "range_tracker", + hdrs = ["range_tracker.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":logging", + ":optimization", + "@com_google_absl//absl/numeric:bits", + ], +) + +create_tcmalloc_benchmark( + name = "range_tracker_benchmark", + srcs = ["range_tracker_benchmark.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + malloc = "//tcmalloc", + deps = [ + ":config", + ":range_tracker", + "@com_github_google_benchmark//:benchmark", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/random", + "@com_google_absl//absl/random:distributions", + ], +) + +cc_test( + name = "range_tracker_test", + srcs = ["range_tracker_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + linkstatic = 1, + deps = [ + ":range_tracker", + "@com_google_absl//absl/container:fixed_array", + "@com_google_absl//absl/random", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "sampled_allocation", + hdrs = ["sampled_allocation.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = ["//tcmalloc:__subpackages__"], + deps = [ + ":logging", + ":sampled_allocation_recorder", + ], +) + +cc_test( + name = "sampled_allocation_test", + srcs = ["sampled_allocation_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":logging", + ":sampled_allocation", + "@com_google_absl//absl/base", + "@com_google_absl//absl/debugging:stacktrace", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "sampled_allocation_recorder", + hdrs = ["sampled_allocation_recorder.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = ["//tcmalloc:__subpackages__"], + deps = [ + ":allocation_guard", + ":config", + "@com_google_absl//absl/base", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/functional:function_ref", + ], +) + +cc_test( + name = "sampled_allocation_recorder_test", + srcs = ["sampled_allocation_recorder_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":explicitly_constructed", + ":sampled_allocation_recorder", + "//tcmalloc/testing:thread_manager", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/synchronization", + "@com_google_absl//absl/time", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "stacktrace_filter", + hdrs = ["stacktrace_filter.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + "@com_google_absl//absl/hash", + "@com_google_absl//absl/types:span", + ], +) + +cc_test( + name = "stacktrace_filter_test", + timeout = "long", + srcs = ["stacktrace_filter_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":stacktrace_filter", + "@com_google_absl//absl/container:flat_hash_set", + "@com_google_absl//absl/types:span", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "sysinfo", + srcs = ["sysinfo.cc"], + hdrs = ["sysinfo.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__pkg__", + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":cpu_utils", + ":logging", + ":util", + "@com_google_absl//absl/base", + "@com_google_absl//absl/base:core_headers", + "@com_google_absl//absl/functional:function_ref", + "@com_google_absl//absl/strings", + ], +) + +cc_test( + name = "sysinfo_fuzz", + srcs = ["sysinfo_fuzz.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":cpu_utils", + ":sysinfo", + "@com_google_fuzztest//fuzztest", + "@com_google_fuzztest//fuzztest:fuzztest_gtest_main", + "@com_google_googletest//:gtest", + ], +) + +cc_test( + name = "sysinfo_test", + srcs = ["sysinfo_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":allocation_guard", + ":cpu_utils", + ":sysinfo", + "@com_google_absl//absl/base", + "@com_google_absl//absl/random", + "@com_google_absl//absl/strings", + "@com_google_absl//absl/types:optional", + "@com_google_googletest//:gtest_main", + ], +) + +# An empty rule to force libc malloc instead of TCMalloc. +cc_library( + name = "system_malloc", + copts = TCMALLOC_DEFAULT_COPTS, + linkstatic = 1, + visibility = [ + "//tcmalloc:__subpackages__", + ], +) + +cc_library( + name = "timeseries_tracker", + hdrs = ["timeseries_tracker.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":clock", + ":logging", + "@com_google_absl//absl/base", + "@com_google_absl//absl/functional:function_ref", + "@com_google_absl//absl/numeric:bits", + "@com_google_absl//absl/numeric:int128", + "@com_google_absl//absl/time", + ], +) + +cc_test( + name = "timeseries_tracker_test", + srcs = ["timeseries_tracker_test.cc"], + copts = TCMALLOC_DEFAULT_COPTS, + deps = [ + ":clock", + ":timeseries_tracker", + "@com_google_absl//absl/base", + "@com_google_absl//absl/time", + "@com_google_googletest//:gtest_main", + ], +) + +cc_library( + name = "util", + srcs = ["util.cc"], + hdrs = ["util.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__pkg__", + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + ":logging", + "@com_google_absl//absl/time", + ], +) + +cc_library( + name = "cpu_utils", + hdrs = ["cpu_utils.h"], + copts = TCMALLOC_DEFAULT_COPTS, + visibility = [ + "//tcmalloc:__subpackages__", + ], + deps = [ + ":config", + "@com_google_absl//absl/base:core_headers", + ], +) diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/affinity.cc b/contrib/libs/tcmalloc/tcmalloc/internal/affinity.cc new file mode 100644 index 000000000000..78f60423e9df --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/affinity.cc @@ -0,0 +1,99 @@ +// Copyright 2019 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include "tcmalloc/internal/affinity.h" + +#include +#include +#include + +#include + +#include "absl/types/span.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/cpu_utils.h" +#include "tcmalloc/internal/logging.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +std::vector AllowedCpus() { + // We have no need for dynamically sized sets (currently >1024 CPUs for glibc) + // at the present time. We could change this in the future. + CpuSet allowed_cpus; + TC_CHECK(allowed_cpus.GetAffinity(0)); + int n = allowed_cpus.Count(), c = 0; + + std::vector result(n); + for (int i = 0; i < kMaxCpus && n; i++) { + if (allowed_cpus.IsSet(i)) { + result[c++] = i; + n--; + } + } + TC_CHECK_EQ(0, n); + + return result; +} + +static CpuSet SpanToCpuSetT(absl::Span mask) { + CpuSet result; + result.Zero(); + for (int cpu : mask) { + result.Set(cpu); + } + return result; +} + +ScopedAffinityMask::ScopedAffinityMask(absl::Span allowed_cpus) { + specified_cpus_ = SpanToCpuSetT(allowed_cpus); + // getaffinity should never fail. + TC_CHECK(original_cpus_.GetAffinity(0)); + // See destructor comments on setaffinity interactions. Tampered() will + // necessarily be true in this case. + TC_CHECK(specified_cpus_.SetAffinity(0)); +} + +ScopedAffinityMask::ScopedAffinityMask(int allowed_cpu) { + specified_cpus_.Zero(); + specified_cpus_.Set(allowed_cpu); + + // getaffinity should never fail. + TC_CHECK(original_cpus_.GetAffinity(0)); + // See destructor comments on setaffinity interactions. Tampered() will + // necessarily be true in this case. + TC_CHECK(specified_cpus_.SetAffinity(0)); +} + +ScopedAffinityMask::~ScopedAffinityMask() { + // If something else has already reset our affinity, do not attempt to + // restrict towards our original mask. This is best-effort as the tampering + // may obviously occur during the destruction of *this. + if (!Tampered()) { + // Note: We do not assert success here, conflicts may restrict us from all + // 'original_cpus_'. + (void)original_cpus_.SetAffinity(0); + } +} + +bool ScopedAffinityMask::Tampered() { + CpuSet current_cpus; + TC_CHECK(current_cpus.GetAffinity(0)); + return !CPU_EQUAL_S(kCpuSetBytes, ¤t_cpus, + &specified_cpus_); // Mismatch => modified. +} + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/affinity.h b/contrib/libs/tcmalloc/tcmalloc/internal/affinity.h new file mode 100644 index 000000000000..aa9cf38431d1 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/affinity.h @@ -0,0 +1,71 @@ +#pragma clang system_header +// Copyright 2019 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_INTERNAL_AFFINITY_H_ +#define TCMALLOC_INTERNAL_AFFINITY_H_ + +#include + +#include + +#include "absl/types/span.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/cpu_utils.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +// Affinity helpers. + +// Returns a vector of the which cpus the currently allowed thread is allowed to +// run on. There are no guarantees that this will not change before, after, or +// even during, the call to AllowedCpus(). +std::vector AllowedCpus(); + +// Enacts a scoped affinity mask on the constructing thread. Attempts to +// restore the original affinity mask on destruction. +// +// REQUIRES: For test-use only. Do not use this in production code. +class ScopedAffinityMask { + public: + // When racing with an external restriction that has a zero-intersection with + // "allowed_cpus" we will construct, but immediately register as "Tampered()", + // without actual changes to affinity. + explicit ScopedAffinityMask(absl::Span allowed_cpus); + explicit ScopedAffinityMask(int allowed_cpu); + + // Restores original affinity iff our scoped affinity has not been externally + // modified (i.e. Tampered()). Otherwise, the updated affinity is preserved. + ~ScopedAffinityMask(); + + // Returns true if the affinity mask no longer matches what was set at point + // of construction. + // + // Note: This is instantaneous and not fool-proof. It's possible for an + // external affinity modification to subsequently align with our originally + // specified "allowed_cpus". In this case Tampered() will return false when + // time may have been spent executing previously on non-specified cpus. + bool Tampered(); + + private: + CpuSet original_cpus_, specified_cpus_; +}; + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_AFFINITY_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/affinity_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/affinity_test.cc new file mode 100644 index 000000000000..6fd2918f8ce3 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/affinity_test.cc @@ -0,0 +1,102 @@ +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/affinity.h" + +#include +#include + +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/types/span.h" +#include "tcmalloc/internal/cpu_utils.h" +#include "tcmalloc/internal/percpu.h" + +namespace tcmalloc { +namespace tcmalloc_internal { +namespace { + +static bool AffinityMatches(std::vector expected_affinity) { + CpuSet allowed_cpus; + EXPECT_TRUE(allowed_cpus.GetAffinity(0)) << errno; + for (int cpu : expected_affinity) { + if (!allowed_cpus.IsSet(cpu)) return false; + + allowed_cpus.CLR(cpu); + } + + // All cpus should now be accounted for. + return allowed_cpus.Count() == 0; +} + +TEST(AffinityInternalTest, AllowedCpus) { + ASSERT_THAT(AllowedCpus(), testing::Contains(subtle::percpu::GetRealCpu())); + ASSERT_TRUE(AffinityMatches(AllowedCpus())); +} + +TEST(AffinityInternalTest, ScopedAffinityTamper) { + // It would be convenient to use a ScopedAffinityMask here also, however, the + // tamper logic disables the destructor (this is intentional so as to leave us + // with the most consistent masks). + CpuSet original_cpus; +restart: + EXPECT_TRUE(original_cpus.GetAffinity(0)) << errno; + + // We require at least 2 cpus to run this test. + if (original_cpus.Count() == 1) return; + + for (int i = 0; i < kMaxCpus; i++) { + if (original_cpus.IsSet(i)) { + ScopedAffinityMask mask(i); + + // Progressing past this point _requires_ a successful false return. + if (mask.Tampered()) goto restart; + + EXPECT_FALSE(mask.Tampered()); + // Manually tamper. Note that the only way this can fail (external + // restriction away from "i", must in itself trigger tampering. + ASSERT_TRUE(original_cpus.SetAffinity(0)); + ASSERT_TRUE(mask.Tampered()); + break; + } + } + // We already restored original_cpus above. +} + +TEST(AffinityInternalTest, ScopedAffinityMask) { + auto original_cpus = AllowedCpus(); + +restart: + std::vector original_affinity = AllowedCpus(), temporary_affinity; + + for (int i = 0; i < original_affinity.size(); i++) { + if (AllowedCpus() != original_affinity) goto restart; + + temporary_affinity.push_back(original_affinity[i]); + ScopedAffinityMask mask(absl::MakeSpan(temporary_affinity)); + ASSERT_TRUE(AllowedCpus() == temporary_affinity || mask.Tampered()); + + if (mask.Tampered()) { + goto restart; + } + } + + EXPECT_EQ(original_affinity, AllowedCpus()); +} + +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/allocation_guard.cc b/contrib/libs/tcmalloc/tcmalloc/internal/allocation_guard.cc new file mode 100644 index 000000000000..c61bd6c06378 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/allocation_guard.cc @@ -0,0 +1,24 @@ +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/allocation_guard.h" + +#include "absl/base/attributes.h" +#include "tcmalloc/internal/config.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc::tcmalloc_internal { + +} // namespace tcmalloc::tcmalloc_internal +GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/allocation_guard.h b/contrib/libs/tcmalloc/tcmalloc/internal/allocation_guard.h new file mode 100644 index 000000000000..ac8675602cbf --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/allocation_guard.h @@ -0,0 +1,57 @@ +#pragma clang system_header +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_INTERNAL_ALLOCATION_GUARD_H_ +#define TCMALLOC_INTERNAL_ALLOCATION_GUARD_H_ + +#include "absl/base/attributes.h" +#include "absl/base/internal/spinlock.h" +#include "absl/base/thread_annotations.h" +#include "tcmalloc/internal/config.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc::tcmalloc_internal { + +// TODO(b/143069684): actually ensure no allocations in debug mode here. +struct AllocationGuard { + AllocationGuard() {} +}; + +// A SpinLockHolder that also enforces no allocations while the lock is held in +// debug mode. +class ABSL_SCOPED_LOCKABLE AllocationGuardSpinLockHolder { + public: + explicit AllocationGuardSpinLockHolder(absl::base_internal::SpinLock* l) + ABSL_EXCLUSIVE_LOCK_FUNCTION(l) + : lock_holder_(l) { +#ifndef NDEBUG + if (l->IsCooperative()) { + abort(); + } +#endif // NDEBUG + } + + inline ~AllocationGuardSpinLockHolder() ABSL_UNLOCK_FUNCTION() = default; + + private: + absl::base_internal::SpinLockHolder lock_holder_; + // In debug mode, enforces no allocations. + AllocationGuard enforce_no_alloc_; +}; + +} // namespace tcmalloc::tcmalloc_internal +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_ALLOCATION_GUARD_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/allocation_guard_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/allocation_guard_test.cc new file mode 100644 index 000000000000..c1faa12e4063 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/allocation_guard_test.cc @@ -0,0 +1,40 @@ +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/allocation_guard.h" + +#include + +#include "gtest/gtest.h" +#include "absl/base/const_init.h" +#include "absl/base/internal/spinlock.h" + +namespace tcmalloc::tcmalloc_internal { +namespace { + +TEST(AllocationGuard, Noncooperative) { + absl::base_internal::SpinLock lock(absl::kConstInit, + absl::base_internal::SCHEDULE_KERNEL_ONLY); + AllocationGuardSpinLockHolder h(&lock); +} + +TEST(AllocationGuard, CooperativeDeathTest) { + absl::base_internal::SpinLock lock; + + EXPECT_DEBUG_DEATH( + { AllocationGuardSpinLockHolder h(&lock); }, "SIGABRT received"); +} + +} // namespace +} // namespace tcmalloc::tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/atomic_danger.h b/contrib/libs/tcmalloc/tcmalloc/internal/atomic_danger.h index 49c95d66cb5b..bfbfc9f3d6c1 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/atomic_danger.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/atomic_danger.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,6 +20,7 @@ #include #include +#include #include "tcmalloc/internal/config.h" diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/atomic_stats_counter.h b/contrib/libs/tcmalloc/tcmalloc/internal/atomic_stats_counter.h index da7f30646d5e..d155cc753d51 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/atomic_stats_counter.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/atomic_stats_counter.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,8 +17,8 @@ #define TCMALLOC_INTERNAL_ATOMIC_STATS_COUNTER_H_ #include +#include -#include "absl/base/macros.h" #include "tcmalloc/internal/config.h" GOOGLE_MALLOC_SECTION_BEGIN diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/bits.h b/contrib/libs/tcmalloc/tcmalloc/internal/bits.h deleted file mode 100644 index 80ca17085c0c..000000000000 --- a/contrib/libs/tcmalloc/tcmalloc/internal/bits.h +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2019 The TCMalloc Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef TCMALLOC_INTERNAL_BITS_H_ -#define TCMALLOC_INTERNAL_BITS_H_ - -#include -#include - -#include "tcmalloc/internal/logging.h" - -namespace tcmalloc { -namespace tcmalloc_internal { - -class Bits { - public: - // Returns true if a value is zero or a power of two. - template - static constexpr - typename std::enable_if::value, bool>::type - IsZeroOrPow2(T n) { - return (n & (n - 1)) == 0; - } - - // Returns true if a value is a power of two. - template - static constexpr - typename std::enable_if::value, bool>::type - IsPow2(T n) { - return n != 0 && (n & (n - 1)) == 0; - } - - template - static constexpr typename std::enable_if::value, T>::type - Log2Floor(T n) { - if (n == 0) { - return -1; - } - - if (sizeof(T) <= sizeof(unsigned int)) { - return std::numeric_limits::digits - 1 - __builtin_clz(n); - } else if (sizeof(T) <= sizeof(unsigned long)) { - return std::numeric_limits::digits - 1 - __builtin_clzl(n); - } else { - static_assert(sizeof(T) <= sizeof(unsigned long long)); - return std::numeric_limits::digits - 1 - __builtin_clzll(n); - } - } - - template - static constexpr typename std::enable_if::value, T>::type - Log2Ceiling(T n) { - T floor = Log2Floor(n); - if (IsZeroOrPow2(n)) - return floor; - else - return floor + 1; - } - - template - static constexpr typename std::enable_if::value, T>::type - RoundUpToPow2(T n) { - if (n == 0) return 1; - return T{1} << Log2Ceiling(n); - } -}; - -} // namespace tcmalloc_internal -} // namespace tcmalloc - -#endif // TCMALLOC_INTERNAL_BITS_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/bits_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/bits_test.cc deleted file mode 100644 index 0589b314d2c8..000000000000 --- a/contrib/libs/tcmalloc/tcmalloc/internal/bits_test.cc +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2019 The TCMalloc Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "tcmalloc/internal/bits.h" - -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/random/random.h" - -namespace tcmalloc { -namespace tcmalloc_internal { -namespace { - -TEST(BitsTest, Log2EdgeCases) { - EXPECT_EQ(-1, Bits::Log2Floor(0u)); - EXPECT_EQ(-1, Bits::Log2Ceiling(0u)); - - for (int i = 0; i < 32; i++) { - uint32_t n = 1U << i; - EXPECT_EQ(i, Bits::Log2Floor(n)); - EXPECT_EQ(i, Bits::Log2Ceiling(n)); - if (n > 2) { - EXPECT_EQ(i - 1, Bits::Log2Floor(n - 1)); - EXPECT_EQ(i, Bits::Log2Floor(n + 1)); - EXPECT_EQ(i, Bits::Log2Ceiling(n - 1)); - EXPECT_EQ(i + 1, Bits::Log2Ceiling(n + 1)); - } - } - - EXPECT_EQ(Bits::Log2Ceiling(uint64_t{0x40000000000}), 42); - EXPECT_EQ(Bits::Log2Floor(uint64_t{0x40000000000}), 42); -} - -TEST(BitsTest, Log2Random) { - absl::BitGen random; - - const int kNumIterations = 10000; - for (int i = 0; i < kNumIterations; i++) { - int maxbit = -1; - uint32_t n = 0; - while (!absl::Bernoulli(random, 1.0 / 32)) { - int bit = absl::Uniform(random, 0, 32); - n |= (1U << bit); - maxbit = std::max(bit, maxbit); - } - EXPECT_EQ(maxbit, Bits::Log2Floor(n)); - } -} - -TEST(BitsTest, IsZeroOrPow2) { - EXPECT_TRUE(Bits::IsZeroOrPow2(0u)); - EXPECT_TRUE(Bits::IsZeroOrPow2(1u)); - EXPECT_TRUE(Bits::IsZeroOrPow2(2u)); - EXPECT_FALSE(Bits::IsZeroOrPow2(3u)); - EXPECT_TRUE(Bits::IsZeroOrPow2(4u)); - EXPECT_FALSE(Bits::IsZeroOrPow2(1337u)); - EXPECT_TRUE(Bits::IsZeroOrPow2(65536u)); - EXPECT_FALSE(Bits::IsZeroOrPow2(std::numeric_limits::max())); - EXPECT_TRUE(Bits::IsZeroOrPow2(uint32_t{1} << 31)); -} - -TEST(BitsTest, IsPow2) { - EXPECT_FALSE(Bits::IsPow2(0u)); - EXPECT_TRUE(Bits::IsPow2(1u)); - EXPECT_TRUE(Bits::IsPow2(2u)); - EXPECT_FALSE(Bits::IsPow2(3u)); - EXPECT_TRUE(Bits::IsPow2(4u)); - EXPECT_FALSE(Bits::IsPow2(1337u)); - EXPECT_TRUE(Bits::IsPow2(65536u)); - EXPECT_FALSE(Bits::IsPow2(std::numeric_limits::max())); - EXPECT_TRUE(Bits::IsPow2(uint32_t{1} << 31)); -} - -TEST(BitsTest, RoundUpToPow2) { - EXPECT_EQ(Bits::RoundUpToPow2(0u), 1); - EXPECT_EQ(Bits::RoundUpToPow2(1u), 1); - EXPECT_EQ(Bits::RoundUpToPow2(2u), 2); - EXPECT_EQ(Bits::RoundUpToPow2(3u), 4); - EXPECT_EQ(Bits::RoundUpToPow2(4u), 4); - EXPECT_EQ(Bits::RoundUpToPow2(1337u), 2048); - EXPECT_EQ(Bits::RoundUpToPow2(65536u), 65536); - EXPECT_EQ(Bits::RoundUpToPow2(65536u - 1337u), 65536); - EXPECT_EQ(Bits::RoundUpToPow2(uint64_t{0x40000000000}), - uint64_t{0x40000000000}); -} - -} // namespace -} // namespace tcmalloc_internal -} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/cache_topology.cc b/contrib/libs/tcmalloc/tcmalloc/internal/cache_topology.cc index 12a1709b34fb..d86ef754b34f 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/cache_topology.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/cache_topology.cc @@ -17,10 +17,14 @@ #include #include -#include "absl/strings/numbers.h" -#include "absl/strings/string_view.h" +#include +#include +#include + #include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/cpu_utils.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/sysinfo.h" #include "tcmalloc/internal/util.h" GOOGLE_MALLOC_SECTION_BEGIN @@ -36,51 +40,71 @@ int OpenSysfsCacheList(size_t cpu) { } } // namespace -int BuildCpuToL3CacheMap_FindFirstNumberInBuf(absl::string_view current) { - // Remove all parts coming after a dash or comma. - const size_t dash = current.find('-'); - if (dash != absl::string_view::npos) current = current.substr(0, dash); - const size_t comma = current.find(','); - if (comma != absl::string_view::npos) current = current.substr(0, comma); +void CacheTopology::Init() { + const auto maybe_numcpus = NumCPUsMaybe(); + if (!maybe_numcpus.has_value()) { + l3_count_ = 1; + return; + } - int first_cpu; - CHECK_CONDITION(absl::SimpleAtoi(current, &first_cpu)); - CHECK_CONDITION(first_cpu < CPU_SETSIZE); - return first_cpu; -} + cpu_count_ = *maybe_numcpus; + CpuSet cpus_to_check; + cpus_to_check.Zero(); + for (int cpu = 0; cpu < cpu_count_; ++cpu) { + cpus_to_check.Set(cpu); + } -int BuildCpuToL3CacheMap(uint8_t l3_cache_index[CPU_SETSIZE]) { - int index = 0; - // Set to a sane value. - memset(l3_cache_index, 0, CPU_SETSIZE); - for (int cpu = 0; cpu < CPU_SETSIZE; ++cpu) { + while (true) { + const int cpu = cpus_to_check.FindFirstSet(); + if (cpu == -1) { + break; + } const int fd = OpenSysfsCacheList(cpu); if (fd == -1) { // At some point we reach the number of CPU on the system, and // we should exit. We verify that there was no other problem. - CHECK_CONDITION(errno == ENOENT); - return index; + TC_CHECK_EQ(errno, ENOENT); + // For aarch64 if + // /sys/devices/system/cpu/cpu*/cache/index3/shared_cpu_list is missing + // then L3 is assumed to be shared by all CPUs. + // TODO(b/210049384): find a better replacement for shared_cpu_list in + // this case, e.g. based on numa nodes. +#ifdef __aarch64__ + if (l3_count_ == 0) { + l3_count_ = 1; + } +#endif + return; } // The file contains something like: // 0-11,22-33 - // we are looking for the first number in that file. - char buf[10]; - const size_t bytes_read = - signal_safe_read(fd, buf, 10, /*bytes_read=*/nullptr); + // Extract all CPUs from that. + + std::optional maybe_shared_cpu_list = + ParseCpulist([&](char* const buf, const size_t count) { + return signal_safe_read(fd, buf, count, /*bytes_read=*/nullptr); + }); signal_safe_close(fd); - CHECK_CONDITION(bytes_read >= 0); - const int first_cpu = - BuildCpuToL3CacheMap_FindFirstNumberInBuf({buf, bytes_read}); - CHECK_CONDITION(first_cpu < CPU_SETSIZE); - CHECK_CONDITION(first_cpu <= cpu); - if (cpu == first_cpu) { - l3_cache_index[cpu] = index++; - } else { - l3_cache_index[cpu] = l3_cache_index[first_cpu]; + TC_CHECK(maybe_shared_cpu_list.has_value()); + CpuSet& shared_cpu_list = *maybe_shared_cpu_list; + shared_cpu_list.CLR(cpu); + cpus_to_check.CLR(cpu); + + const int first_cpu = cpu; + l3_cache_index_[first_cpu] = l3_count_++; + // Set the remaining in the parsed cpu set to the l3_cache_index of + // the first one. + while (true) { + int next_cpu = shared_cpu_list.FindFirstSet(); + if (next_cpu == -1) { + break; + } + shared_cpu_list.CLR(next_cpu); + cpus_to_check.CLR(next_cpu); + l3_cache_index_[next_cpu] = l3_cache_index_[first_cpu]; } } - return index; } } // namespace tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/cache_topology.h b/contrib/libs/tcmalloc/tcmalloc/internal/cache_topology.h index 292f17547030..83c0f5f7046f 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/cache_topology.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/cache_topology.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2021 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,19 +16,44 @@ #ifndef TCMALLOC_INTERNAL_CACHE_TOPOLOGY_H_ #define TCMALLOC_INTERNAL_CACHE_TOPOLOGY_H_ +#include + +#include "absl/base/attributes.h" +#include "absl/strings/string_view.h" #include "tcmalloc/internal/config.h" -#include "tcmalloc/internal/util.h" +#include "tcmalloc/internal/cpu_utils.h" +#include "tcmalloc/internal/logging.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { -// Build a mapping from cpuid to the index of the L3 cache used by that cpu. -// Returns the number of caches detected. -int BuildCpuToL3CacheMap(uint8_t l3_cache_index[CPU_SETSIZE]); +class CacheTopology { + public: + static CacheTopology& Instance() { + ABSL_CONST_INIT static CacheTopology instance; + return instance; + } + + constexpr CacheTopology() = default; + + void Init(); + + unsigned l3_count() const { return l3_count_; } + + unsigned GetL3FromCpuId(int cpu) const { + TC_ASSERT_GE(cpu, 0); + TC_ASSERT_LT(cpu, cpu_count_); + unsigned l3 = l3_cache_index_[cpu]; + TC_ASSERT_LT(l3, l3_count_); + return l3; + } -// Helper function exposed to permit testing it. -int BuildCpuToL3CacheMap_FindFirstNumberInBuf(absl::string_view current); + private: + unsigned cpu_count_ = 0; + unsigned l3_count_ = 0; + uint8_t l3_cache_index_[kMaxCpus] = {}; +}; } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/cache_topology_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/cache_topology_test.cc index 927ecace94e4..df795abb86b2 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/cache_topology_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/cache_topology_test.cc @@ -14,38 +14,29 @@ #include "tcmalloc/internal/cache_topology.h" -#include - -#include "gmock/gmock.h" #include "gtest/gtest.h" +#include "tcmalloc/internal/sysinfo.h" +namespace tcmalloc::tcmalloc_internal { namespace { -TEST(CacheToplogy, ComputesSomethingReasonable) { +TEST(CacheTopology, ComputesSomethingReasonable) { // This test verifies that each L3 cache serves the same number of CPU. This // is not a strict requirement for the correct operation of this code, but a // sign of sanity. - uint8_t l3_cache_index[CPU_SETSIZE]; - const int num_nodes = - tcmalloc::tcmalloc_internal::BuildCpuToL3CacheMap(l3_cache_index); - EXPECT_EQ(absl::base_internal::NumCPUs() % num_nodes, 0); - ASSERT_GT(num_nodes, 0); + CacheTopology topology; + topology.Init(); + EXPECT_EQ(NumCPUs() % topology.l3_count(), 0); + ASSERT_GT(topology.l3_count(), 0); static const int kMaxNodes = 256 / 8; int count_per_node[kMaxNodes] = {0}; - for (int i = 0; i < absl::base_internal::NumCPUs(); ++i) { - count_per_node[l3_cache_index[i]]++; + for (int i = 0, n = NumCPUs(); i < n; ++i) { + count_per_node[topology.GetL3FromCpuId(i)]++; } - for (int i = 0; i < num_nodes; ++i) { - EXPECT_EQ(count_per_node[i], absl::base_internal::NumCPUs() / num_nodes); + for (int i = 0; i < topology.l3_count(); ++i) { + EXPECT_EQ(count_per_node[i], NumCPUs() / topology.l3_count()); } } -TEST(CacheTopology, FindFirstNumberInBuf) { - using tcmalloc::tcmalloc_internal::BuildCpuToL3CacheMap_FindFirstNumberInBuf; - EXPECT_EQ(7, BuildCpuToL3CacheMap_FindFirstNumberInBuf("7,-787")); - EXPECT_EQ(5, BuildCpuToL3CacheMap_FindFirstNumberInBuf("5")); - EXPECT_EQ(5, BuildCpuToL3CacheMap_FindFirstNumberInBuf("5-9")); - EXPECT_EQ(5, BuildCpuToL3CacheMap_FindFirstNumberInBuf("5,9")); -} - } // namespace +} // namespace tcmalloc::tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/clock.h b/contrib/libs/tcmalloc/tcmalloc/internal/clock.h index 65c765203c90..d145040f6f3f 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/clock.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/clock.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2021 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/config.h b/contrib/libs/tcmalloc/tcmalloc/internal/config.h index 73dbab06aa83..55e4cd81eea8 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/config.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/config.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +18,8 @@ #include -#include "absl/base/policy_checks.h" +#include "absl/base/attributes.h" +#include "absl/base/config.h" // TCMALLOC_HAVE_SCHED_GETCPU is defined when the system implements // sched_getcpu(3) as by glibc and it's imitators. @@ -27,23 +29,34 @@ #undef TCMALLOC_HAVE_SCHED_GETCPU #endif +#if defined(__GLIBC__) && defined(__GLIBC_MINOR__) +#define TCMALLOC_GLIBC_PREREQ(major, minor) \ + ((__GLIBC__ * 100 + __GLIBC_MINOR__) >= ((major) * 100 + (minor))) +#else +#define TCMALLOC_GLIBC_PREREQ(major, minor) 0 +#endif + // TCMALLOC_HAVE_STRUCT_MALLINFO is defined when we know that the system has // `struct mallinfo` available. // -// The FreeBSD libc, and subsequently macOS, does not provide the `mallopt` -// interfaces. We know that bionic, glibc (and variants), newlib, and uclibc do +// We know that bionic, glibc (and variants), newlib, and uclibc do // provide the `mallopt` interface. The musl libc is known to not provide the // interface, nor does it provide a macro for checking. As a result, we // conservatively state that `struct mallinfo` is only available on these // environments. -#if !defined(OS_FREEBSD) && !defined(OS_MACOSX) && \ - (defined(__BIONIC__) || defined(__GLIBC__) || defined(__NEWLIB__) || \ - defined(__UCLIBC__)) +#if defined(__BIONIC__) || defined(__GLIBC__) || defined(__NEWLIB__) || \ + defined(__UCLIBC__) #define TCMALLOC_HAVE_STRUCT_MALLINFO 1 #else #undef TCMALLOC_HAVE_STRUCT_MALLINFO #endif +#if TCMALLOC_GLIBC_PREREQ(2, 33) +#define TCMALLOC_HAVE_STRUCT_MALLINFO2 1 +#else +#undef TCMALLOC_HAVE_STRUCT_MALLINFO2 +#endif + // When possible, name the text section as google_malloc. This macro should not // be added to header files as that may move unrelated code to google_malloc // section. @@ -51,9 +64,20 @@ #define GOOGLE_MALLOC_SECTION_BEGIN \ _Pragma("clang section text = \"google_malloc\"") #define GOOGLE_MALLOC_SECTION_END _Pragma("clang section text = \"\"") +// For inline lambdas, which aren't covered +#define GOOGLE_MALLOC_SECTION __attribute__((section("google_malloc"))) #else #define GOOGLE_MALLOC_SECTION_BEGIN #define GOOGLE_MALLOC_SECTION_END +#define GOOGLE_MALLOC_SECTION +#endif + +// TCMALLOC_ATTRIBUTE_NO_DESTROY is defined when clang::no_destroy attribute is +// present. +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::no_destroy) +#define TCMALLOC_ATTRIBUTE_NO_DESTROY [[clang::no_destroy]] +#else +#define TCMALLOC_ATTRIBUTE_NO_DESTROY #endif #if defined(__GNUC__) && !defined(__clang__) @@ -68,11 +92,19 @@ #endif #endif -#if !defined(__x86_64__) && !defined(__ppc64__) && !defined(__arm__) && \ - !defined(__aarch64__) && !defined(__riscv) +#if !defined(__i386__) && !defined(__x86_64__) && !defined(__ppc64__) && \ + !defined(__arm__) && !defined(__aarch64__) && !defined(__riscv) #error "Unsupported architecture." #endif +#ifndef ABSL_IS_LITTLE_ENDIAN +#error "TCMalloc only supports little endian architectures" +#endif + +#ifndef __linux__ +#error "TCMalloc is only supported on Linux." +#endif + #if !defined(__cplusplus) || __cplusplus < 201703L #error "TCMalloc requires C++17 or later." #else @@ -86,32 +118,44 @@ namespace tcmalloc { namespace tcmalloc_internal { #if defined __x86_64__ -// All current and planned x86_64 processors only look at the lower 48 bits -// in virtual to physical address translation. The top 16 are thus unused. +// x86_64 processors use lower 48 bits in virtual to physical address +// translation with 4-level page tables. The top 16 are thus unused. +// We don't support 5-level page tables yet. // TODO(b/134686025): Under what operating systems can we increase it safely to // 17? This lets us use smaller page maps. On first allocation, a 36-bit page // map uses only 96 KB instead of the 4.5 MB used by a 52-bit page map. -inline constexpr int kAddressBits = - (sizeof(void*) < 8 ? (8 * sizeof(void*)) : 48); +inline constexpr int kAddressBits = 48; #elif defined __powerpc64__ && defined __linux__ // Linux(4.12 and above) on powerpc64 supports 128TB user virtual address space -// by default, and up to 512TB if user space opts in by specifing hint in mmap. +// by default, and up to 512TB if user space opts in by specifying hint in mmap. // See comments in arch/powerpc/include/asm/processor.h // and arch/powerpc/mm/mmap.c. -inline constexpr int kAddressBits = - (sizeof(void*) < 8 ? (8 * sizeof(void*)) : 49); +inline constexpr int kAddressBits = 49; #elif defined __aarch64__ && defined __linux__ // According to Documentation/arm64/memory.txt of kernel 3.16, // AARCH64 kernel supports 48-bit virtual addresses for both user and kernel. -inline constexpr int kAddressBits = - (sizeof(void*) < 8 ? (8 * sizeof(void*)) : 48); +inline constexpr int kAddressBits = 48; #elif defined __riscv && defined __linux__ -inline constexpr int kAddressBits = - (sizeof(void *) < 8 ? (8 * sizeof(void *)) : 48); +inline constexpr int kAddressBits = 48; #else inline constexpr int kAddressBits = 8 * sizeof(void*); #endif +#ifdef TCMALLOC_INTERNAL_SELSAN +inline constexpr bool kSelSanPresent = true; +#else +inline constexpr bool kSelSanPresent = false; +#endif + +// Sanitizers constrain the memory layout which causes problems with the +// enlarged tags required to represent NUMA partitions and for SelSan. +#if defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER) +static_assert(!kSelSanPresent, "MSan/TSan are incompatible with SelSan."); +inline constexpr bool kSanitizerAddressSpace = true; +#else +inline constexpr bool kSanitizerAddressSpace = false; +#endif + #if defined(__x86_64__) // x86 has 2 MiB huge pages static constexpr size_t kHugePageShift = 21; diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/config_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/config_test.cc new file mode 100644 index 000000000000..a9c042817c7d --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/config_test.cc @@ -0,0 +1,101 @@ +// Copyright 2020 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/config.h" + +#include + +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/strings/match.h" +#include "absl/strings/str_cat.h" +#include "google/protobuf/io/gzip_stream.h" +#include "google/protobuf/io/zero_copy_stream_impl.h" +#include "tcmalloc/internal/util.h" + +namespace tcmalloc { +namespace tcmalloc_internal { +namespace { + +TEST(AddressBits, CpuVirtualBits) { + // Check that kAddressBits is as least as large as either the number of bits + // in a pointer or as the number of virtual bits handled by the processor. + // To be effective this test must be run on each processor model. +#ifdef __x86_64__ + const int kPointerBits = 8 * sizeof(void*); + + // LLVM has a miscompile bug around %rbx, see + // https://bugs.llvm.org/show_bug.cgi?id=17907 + int ret; + asm("mov %%rbx, %%rdi\n" + "cpuid\n" + "xchg %%rdi, %%rbx\n" + /* inputs */ + : "=a"(ret) + /* outputs */ + : "a"(0x80000008) + /* clobbers */ + : "rdi", "ecx", "edx"); + const int kImplementedVirtualBits = (ret >> 8) & ((1 << 8) - 1); + ASSERT_GE(kAddressBits, std::min(kImplementedVirtualBits, kPointerBits)); +#elif __aarch64__ + const int kPointerBits = 8 * sizeof(void*); + + int fd = signal_safe_open("/proc/config.gz", O_RDONLY); + if (fd < 0) { + GTEST_SKIP() << "Unable to open kernel config."; + } + + google::protobuf::io::FileInputStream fs(fd); + google::protobuf::io::GzipInputStream gs(&fs, google::protobuf::io::GzipInputStream::GZIP); + + std::string config; + do { + const void* buf; + int size; + if (!gs.Next(&buf, &size)) { + break; + } + if (size < 0) { + break; + } + + absl::StrAppend( + &config, absl::string_view(reinterpret_cast(buf), size)); + } while (true); + + constexpr absl::string_view token = "CONFIG_PGTABLE_LEVELS="; + ASSERT_THAT(config, testing::HasSubstr(token)); + auto position = config.find(token); + ASSERT_NE(position, std::string::npos); + position += token.size(); + auto eol = config.find('\n', position); + ASSERT_NE(eol, std::string::npos); + ASSERT_NE(eol, position); + absl::string_view string_levels(&config[position], eol - position); + int levels; + ASSERT_TRUE(absl::SimpleAtoi(string_levels, &levels)) << string_levels; + + ASSERT_GE(levels, 3); + const int kImplementedVirtualBits = 39 + (levels - 3) * 9; + ASSERT_EQ(kAddressBits, kImplementedVirtualBits); + ASSERT_GE(kAddressBits, std::min(kImplementedVirtualBits, kPointerBits)); +#endif +} + +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/cpu_utils.h b/contrib/libs/tcmalloc/tcmalloc/internal/cpu_utils.h new file mode 100644 index 000000000000..9d2981cf5e79 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/cpu_utils.h @@ -0,0 +1,85 @@ +#pragma clang system_header +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_INTERNAL_CPU_UTILS_H_ +#define TCMALLOC_INTERNAL_CPU_UTILS_H_ + +#include + +#include + +#include "absl/base/attributes.h" +#include "tcmalloc/internal/config.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +// The maximum number of CPUs supported by TCMalloc. +static constexpr int kMaxCpus = 2048; +// The size of the CPU set in bytes. +static constexpr int kCpuSetBytes = CPU_ALLOC_SIZE(kMaxCpus); + +class CpuSet { + public: + void Zero() { CPU_ZERO_S(kCpuSetBytes, cpu_set_.data()); } + void Set(int cpu) { CPU_SET_S(cpu, kCpuSetBytes, cpu_set_.data()); } + bool IsSet(int cpu) const { + return CPU_ISSET_S(cpu, kCpuSetBytes, cpu_set_.data()); + } + void CLR(int cpu) { CPU_CLR_S(cpu, kCpuSetBytes, cpu_set_.data()); } + int Count() const { return CPU_COUNT_S(kCpuSetBytes, cpu_set_.data()); } + + // Find the index of the first set CPU. Returns -1 if none are set. + int FindFirstSet() const { + if (Count() == 0) { + return -1; + } + int cpu = 0; + while (!IsSet(cpu)) { + ++cpu; + } + return cpu; + } + + // Sets the CPU affinity of the process with the given pid. Returns true if + // successful. If returns false, please check the global 'errno' variable to + // determine the specific error that occurred. + [[nodiscard]] bool SetAffinity(pid_t pid) { + return sched_setaffinity(pid, kCpuSetBytes, cpu_set_.data()) == 0; + } + + // Gets the CPU affinity of the process with the given pid. Return trues if + // successful. If returns false, please check the global 'errno' variable to + // determine the specific error that occurred. + [[nodiscard]] bool GetAffinity(pid_t pid) { + return sched_getaffinity(pid, kCpuSetBytes, cpu_set_.data()) == 0; + } + + const cpu_set_t* data() const { return cpu_set_.data(); } + + private: + // In the sched.h, each CPU occupies one bit. + // Declare a bit array with a size that is an integer multiple of cpu_set_t: + std::array + cpu_set_; +}; + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_CPU_UTILS_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/declarations.h b/contrib/libs/tcmalloc/tcmalloc/internal/declarations.h index b82a3ce9e5e6..d234f7ea8d6c 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/declarations.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/declarations.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,8 +19,14 @@ #ifndef TCMALLOC_INTERNAL_DECLARATIONS_H_ #define TCMALLOC_INTERNAL_DECLARATIONS_H_ -#include -#include +#if !defined(__cpp_sized_deallocation) + +void operator delete(void*, std::size_t) noexcept; +void operator delete[](void*, std::size_t) noexcept; + +#endif // !defined(__cpp_sized_deallocation) + +#if !defined(__cpp_aligned_new) namespace std { enum class align_val_t : size_t; @@ -33,10 +40,15 @@ void* operator new[](std::size_t, std::align_val_t, const std::nothrow_t&) noexcept; void operator delete(void*, std::align_val_t) noexcept; -void operator delete(void*, std::size_t) noexcept; -void operator delete(void*, std::size_t, std::align_val_t) noexcept; void operator delete[](void*, std::align_val_t) noexcept; -void operator delete[](void*, std::size_t) noexcept; + +#endif // !defined(__cpp_aligned_new) + +#if !defined(__cpp_sized_deallocation) || !defined(__cpp_aligned_new) + +void operator delete(void*, std::size_t, std::align_val_t) noexcept; void operator delete[](void*, std::size_t, std::align_val_t) noexcept; +#endif // !defined(__cpp_sized_deallocation) || !defined(__cpp_aligned_new) + #endif // TCMALLOC_INTERNAL_DECLARATIONS_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/environment.cc b/contrib/libs/tcmalloc/tcmalloc/internal/environment.cc index e786dd7a96dc..dd5e25120f4a 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/environment.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/environment.cc @@ -15,6 +15,8 @@ #include +#include "tcmalloc/internal/config.h" + GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/environment.h b/contrib/libs/tcmalloc/tcmalloc/internal/environment.h index f54840e8d781..86023160bdd0 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/environment.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/environment.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/explicitly_constructed.h b/contrib/libs/tcmalloc/tcmalloc/internal/explicitly_constructed.h new file mode 100644 index 000000000000..0ae0e8a0a250 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/explicitly_constructed.h @@ -0,0 +1,63 @@ +#pragma clang system_header +// Copyright 2019 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_INTERNAL_EXPLICITLY_CONSTRUCTED_H_ +#define TCMALLOC_INTERNAL_EXPLICITLY_CONSTRUCTED_H_ + +#include + +#include + +#include "tcmalloc/internal/config.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +// Wraps a variable whose constructor is explicitly called. It is particularly +// useful for a global variable, without its constructor and destructor run on +// start and end of the program lifetime. This circumvents the initial +// construction order fiasco, while keeping the address of the empty string a +// compile time constant. +// +// Pay special attention to the initialization state of the object. +// 1. The object is "uninitialized" to begin with. +// 2. Call Construct() only if the object is uninitialized. After the call, the +// object becomes "initialized". +// 3. Call get_mutable() only if the object is initialized. +template +class ExplicitlyConstructed { + public: + template + void Construct(Args&&... args) { + new (&union_) T(std::forward(args)...); + } + + T& get_mutable() { return reinterpret_cast(union_); } + + private: + union AlignedUnion { + constexpr AlignedUnion() = default; + alignas(T) char space[sizeof(T)]; + int64_t align_to_int64; + void* align_to_ptr; + } union_; +}; + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_EXPLICITLY_CONSTRUCTED_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/exponential_biased.h b/contrib/libs/tcmalloc/tcmalloc/internal/exponential_biased.h new file mode 100644 index 000000000000..cfe85e0b3e16 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/exponential_biased.h @@ -0,0 +1,78 @@ +#pragma clang system_header +// Copyright 2019 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_INTERNAL_EXPONENTIAL_BIASED_H_ +#define TCMALLOC_INTERNAL_EXPONENTIAL_BIASED_H_ + +#include +#include + +namespace tcmalloc { +namespace tcmalloc_internal { + +class ExponentialBiased { + public: + static uint64_t NextRandom(uint64_t rnd); + static uint32_t GetRandom(uint64_t rnd); +}; + +// Returns the next prng value. +// pRNG is: aX+b mod c with a = 0x5DEECE66D, b = 0xB, c = 1<<48 +// This is the lrand64 generator. +inline uint64_t ExponentialBiased::NextRandom(uint64_t rnd) { + const uint64_t prng_mult = UINT64_C(0x5DEECE66D); + const uint64_t prng_add = 0xB; + const uint64_t prng_mod_power = 48; + const uint64_t prng_mod_mask = + ~((~static_cast(0)) << prng_mod_power); + return (prng_mult * rnd + prng_add) & prng_mod_mask; +} + +// Extracts higher-quality random bits. +// The raw value returned from NextRandom has poor randomness low bits +// and is not directly suitable for things like 'if (rnd % 2)'. +inline uint32_t ExponentialBiased::GetRandom(uint64_t rnd) { return rnd >> 16; } + +// Convenience wrapper to initialize a seed and return a sequence of +// pseudo-random values. Thread-safety: thread safe. +class Random { + public: + constexpr explicit Random(uint64_t seed) : state_(seed) {} + + // Return the next pseudo-random value. + uint32_t Next(); + + // Reset internal state with provided seed. + void Reset(uint64_t seed); + + private: + std::atomic state_; +}; + +inline uint32_t Random::Next() { + uint64_t r = state_.load(std::memory_order_relaxed); + r = ExponentialBiased::NextRandom(r); + state_.store(r, std::memory_order_relaxed); + return ExponentialBiased::GetRandom(r); +} + +inline void Random::Reset(uint64_t seed) { + state_.store(seed, std::memory_order_relaxed); +} + +} // namespace tcmalloc_internal +} // namespace tcmalloc + +#endif // TCMALLOC_INTERNAL_EXPONENTIAL_BIASED_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/exponential_biased_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/exponential_biased_test.cc new file mode 100755 index 000000000000..e850e20fdf6c --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/exponential_biased_test.cc @@ -0,0 +1,125 @@ +// Copyright 2019 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/exponential_biased.h" + +#include +#include +#include + +#include "gtest/gtest.h" +#include "tcmalloc/testing/testutil.h" + +namespace tcmalloc { +namespace tcmalloc_internal { +namespace { + +// Testing that NextRandom generates uniform +// random numbers. +// Applies the Anderson-Darling test for uniformity +void TestNextRandom(int n) { + uint64_t x = 1; + // This assumes that the prng returns 48 bit numbers + uint64_t max_prng_value = static_cast(1) << 48; + // Initialize + for (int i = 1; i <= 20; i++) { // 20 mimics sampler.Init() + x = ExponentialBiased::NextRandom(x); + } + std::vector int_random_sample(n); + // Collect samples + for (int i = 0; i < n; i++) { + int_random_sample[i] = x; + x = ExponentialBiased::NextRandom(x); + } + // First sort them... + std::sort(int_random_sample.begin(), int_random_sample.end()); + std::vector random_sample(n); + // Convert them to uniform randoms (in the range [0,1]) + for (int i = 0; i < n; i++) { + random_sample[i] = + static_cast(int_random_sample[i]) / max_prng_value; + } + // Now compute the Anderson-Darling statistic + double ad_pvalue = AndersonDarlingTest(random_sample); + EXPECT_GT(std::min(ad_pvalue, 1 - ad_pvalue), 0.0001) + << "prng is not uniform: n = " << n << " p = " << ad_pvalue; +} + +TEST(ExponentialBiased, TestNextRandom_MultipleValues) { + TestNextRandom(10); // Check short-range correlation + TestNextRandom(100); + TestNextRandom(1000); + TestNextRandom(10000); // Make sure there's no systematic error +} + +// Test that NextRand is in the right range. Unfortunately, this is a +// stochastic test which could miss problems. +TEST(ExponentialBiased, NextRand_range) { + uint64_t one = 1; + // The next number should be (one << 48) - 1 + uint64_t max_value = (one << 48) - 1; + uint64_t x = (one << 55); + int n = 22; // 27; + for (int i = 1; i <= (1 << n); i++) { // 20 mimics sampler.Init() + x = ExponentialBiased::NextRandom(x); + ASSERT_LE(x, max_value); + } +} + +// Tests certain arithmetic operations to make sure they compute what we +// expect them too (for testing across different platforms) +TEST(ExponentialBiased, arithmetic_1) { + uint64_t rnd; // our 48 bit random number, which we don't trust + const uint64_t prng_mod_power = 48; + uint64_t one = 1; + rnd = one; + uint64_t max_value = (one << 48) - 1; + for (int i = 1; i <= (1 << 27); i++) { // 20 mimics sampler.Init() + rnd = ExponentialBiased::NextRandom(rnd); + ASSERT_LE(rnd, max_value); + double q = (rnd >> (prng_mod_power - 26)) + 1.0; + ASSERT_GE(q, 0) << rnd << " " << prng_mod_power; + } + // Test some potentially out of bounds value for rnd + for (int i = 1; i < 64; i++) { + rnd = one << i; + double q = (rnd >> (prng_mod_power - 26)) + 1.0; + ASSERT_GE(q, 0) << " rnd=" << rnd << " i=" << i << " prng_mod_power" + << prng_mod_power; + } +} + +TEST(ExponentialBiased, CoinFlip) { + // Ensure that the low bits contain good randomness and can be as a coin flip. + for (uint64_t seed = 0; seed < 100; seed++) { + uint64_t rnd = seed; + int even = 0; + constexpr int kIters = 100; + for (int i = 0; i < 2 * kIters; i++) { + rnd = ExponentialBiased::NextRandom(rnd); + // Check that it works even if we look at every second value + // (i.e. if the rand is used twice per some operation). + // This fails without GetRandom, which caused issues for guarded page + // allocator sampling (left-right-alignment decision). + if (i % 2) { + even += ExponentialBiased::GetRandom(rnd) % 2; + } + } + EXPECT_GT(even, kIters / 10) << seed; + EXPECT_LT(even, kIters / 10 * 9) << seed; + } +} +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/fake_profile.h b/contrib/libs/tcmalloc/tcmalloc/internal/fake_profile.h new file mode 100644 index 000000000000..e8b7885c2294 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/fake_profile.h @@ -0,0 +1,66 @@ +#pragma clang system_header +// Copyright 2021 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_INTERNAL_FAKE_PROFILE_H_ +#define TCMALLOC_INTERNAL_FAKE_PROFILE_H_ + +#include +#include +#include + +#include "absl/functional/function_ref.h" +#include "absl/time/time.h" +#include "tcmalloc/malloc_extension.h" + +namespace tcmalloc { +namespace tcmalloc_internal { + +class FakeProfile final : public ProfileBase { + public: + void SetSamples(std::vector samples) { + samples_ = std::move(samples); + } + + // For each sample in the profile, Iterate invokes the callback f on the + // sample. + void Iterate( + absl::FunctionRef f) const override { + for (const auto& sample : samples_) { + f(sample); + } + } + + // The type of profile (live objects, allocated, etc.). + ProfileType Type() const override { return type_; } + void SetType(ProfileType type) { type_ = type; } + + // The duration of the profile + absl::Duration Duration() const override { return duration_; } + void SetDuration(absl::Duration duration) { duration_ = duration; } + + std::optional StartTime() const override { return start_time_; } + void SetStartTime(std::optional t) { start_time_ = t; } + + private: + std::vector samples_; + ProfileType type_; + absl::Duration duration_; + std::optional start_time_; +}; + +} // namespace tcmalloc_internal +} // namespace tcmalloc + +#endif // TCMALLOC_INTERNAL_FAKE_PROFILE_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/lifetime_predictions.h b/contrib/libs/tcmalloc/tcmalloc/internal/lifetime_predictions.h deleted file mode 100644 index 514dd4a73e72..000000000000 --- a/contrib/libs/tcmalloc/tcmalloc/internal/lifetime_predictions.h +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2020 The TCMalloc Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef TCMALLOC_INTERNAL_LIFETIME_PREDICTIONS_H_ -#define TCMALLOC_INTERNAL_LIFETIME_PREDICTIONS_H_ - -#include -#include -#include - -#include "absl/algorithm/container.h" -#include "absl/base/const_init.h" -#include "absl/base/internal/low_level_alloc.h" -#include "absl/base/internal/spinlock.h" -#include "absl/debugging/stacktrace.h" -#include "absl/hash/hash.h" -#include "absl/time/clock.h" -#include "absl/time/time.h" -#include "tcmalloc/internal/linked_list.h" - -GOOGLE_MALLOC_SECTION_BEGIN -namespace tcmalloc { -namespace tcmalloc_internal { - -// Counts how many times we observed objects with a particular stack trace -// that were short lived/long lived. Each LifetimeStats object is associated -// with a particular allocation site (i.e., allocation stack trace) and each -// allocation site has at most one LifetimeStats object. All accesses to -// LifetimeStats objects need to be synchronized via the page heap lock. -class LifetimeStats : public TList::Elem { - public: - enum class Certainty { kLowCertainty, kHighCertainty }; - enum class Prediction { kShortLived, kLongLived }; - - void Update(Prediction prediction) { - if (prediction == Prediction::kShortLived) { - short_lived_++; - } else { - long_lived_++; - } - } - - Prediction Predict(Certainty certainty) { - if (certainty == Certainty::kLowCertainty) { - return (short_lived_ > long_lived_) ? Prediction::kShortLived - : Prediction::kLongLived; - } else { - // If little data was collected, predict as long-lived (current behavior). - return (short_lived_ > (long_lived_ + 10)) ? Prediction::kShortLived - : Prediction::kLongLived; - } - } - - // Reference counts are protected by LifetimeDatabase::table_lock_. - - // Increments the reference count of this entry. - void IncRef() { ++refcount_; } - - // Returns true if and only if the reference count reaches 0. - bool DecRef() { return --refcount_ == 0; } - - private: - uint64_t refcount_ = 1; - uint64_t short_lived_ = 0; - uint64_t long_lived_ = 0; -}; - -// Manages stack traces and statistics about their associated lifetimes. Since -// the database can fill up, old entries are evicted. Evicted entries need to -// survive as long as the last lifetime tracker referencing them and are thus -// reference-counted. -class LifetimeDatabase { - public: - struct Key { - int depth; // Number of PC values stored in array below - void* stack[kMaxStackDepth]; - - // Statically instantiate at the start of the allocation to acquire - // the allocation stack trace. - Key() { depth = absl::GetStackTrace(stack, kMaxStackDepth, 1); } - - template - friend H AbslHashValue(H h, const Key& c) { - return H::combine(H::combine_contiguous(std::move(h), c.stack, c.depth), - c.depth); - } - - bool operator==(const Key& other) const { - if (depth != other.depth) { - return false; - } - return std::equal(stack, stack + depth, other.stack); - } - }; - - // Captures statistics associated with the low-level allocator backing the - // memory used by the database. - struct ArenaStats { - uint64_t bytes_allocated; - }; - - static constexpr int kMaxDatabaseSize = 1024; - - LifetimeDatabase() {} - ~LifetimeDatabase() {} - - // Not copyable or movable - LifetimeDatabase(const LifetimeDatabase&) = delete; - LifetimeDatabase& operator=(const LifetimeDatabase&) = delete; - - // Identifies the current stack trace and returns a handle to the lifetime - // statistics associated with this stack trace. May run outside the page heap - // lock -- we therefore need to do our own locking. This increments the - // reference count of the lifetime stats object and the caller is responsible - // for calling RemoveLifetimeStatsReference when finished with the object. - LifetimeStats* LookupOrAddLifetimeStats(Key* k) { - absl::base_internal::SpinLockHolder h(&table_lock_); - auto it = table_.find(*k); - LifetimeStats* s; - if (it == table_.end()) { - MaybeEvictLRU(); - // Allocate a new entry using the low-level allocator, which is safe - // to call from within TCMalloc. - s = stats_allocator_.allocate(1); - new (s) LifetimeStats(); - table_.insert(std::make_pair(*k, s)); - stats_fifo_.append(s); - } else { - s = it->second; - UpdateLRU(s); - } - s->IncRef(); - return s; - } - - void RemoveLifetimeStatsReference(LifetimeStats* s) { - absl::base_internal::SpinLockHolder h(&table_lock_); - if (s->DecRef()) { - stats_allocator_.deallocate(s, 1); - } - } - - size_t size() const { - absl::base_internal::SpinLockHolder h(&table_lock_); - return table_.size(); - } - - size_t evictions() const { - absl::base_internal::SpinLockHolder h(&table_lock_); - return n_evictions_; - } - - static ArenaStats* arena_stats() { - static ArenaStats stats = {0}; - return &stats; - } - - protected: - static const int kMaxStackDepth = 64; - - static absl::base_internal::LowLevelAlloc::Arena* GetArena() { - static absl::base_internal::LowLevelAlloc::Arena* arena = - absl::base_internal::LowLevelAlloc::NewArena(0); - return arena; - } - - static uint64_t bytes_allocated_ ABSL_GUARDED_BY(table_lock_); - - void UpdateLRU(LifetimeStats* stats) - ABSL_EXCLUSIVE_LOCKS_REQUIRED(table_lock_) { - stats_fifo_.remove(stats); - stats_fifo_.append(stats); - } - - // If an entry is evicted, it is returned (nullptr otherwise). - void MaybeEvictLRU() ABSL_EXCLUSIVE_LOCKS_REQUIRED(table_lock_) { - if (table_.size() < kMaxDatabaseSize) { - return; - } - n_evictions_++; - LifetimeStats* evict = stats_fifo_.first(); - stats_fifo_.remove(evict); - for (auto it = table_.begin(); it != table_.end(); ++it) { - if (it->second == evict) { - table_.erase(it); - if (evict->DecRef()) { - stats_allocator_.deallocate(evict, 1); - } - return; - } - } - CHECK_CONDITION(false); // Should not happen - } - - private: - template - class MyAllocator : public std::allocator { - public: - template - struct rebind { - using other = MyAllocator; - }; - - MyAllocator() noexcept {} - - template - explicit MyAllocator(const MyAllocator&) noexcept {} - - T* allocate(size_t num_objects, const void* = nullptr) { - size_t bytes = num_objects * sizeof(T); - arena_stats()->bytes_allocated += bytes; - return static_cast(absl::base_internal::LowLevelAlloc::AllocWithArena( - bytes, GetArena())); - } - - void deallocate(T* p, size_t num_objects) { - size_t bytes = num_objects * sizeof(T); - arena_stats()->bytes_allocated -= bytes; - absl::base_internal::LowLevelAlloc::Free(p); - } - }; - - MyAllocator stats_allocator_ ABSL_GUARDED_BY(table_lock_); - mutable absl::base_internal::SpinLock table_lock_{ - absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY}; - - // Stores the current mapping from allocation site to LifetimeStats. - std::unordered_map, std::equal_to, - MyAllocator>> - table_ ABSL_GUARDED_BY(table_lock_); - - // Stores the entries ordered by how many times they have been accessed. - TList stats_fifo_ ABSL_GUARDED_BY(table_lock_); - size_t n_evictions_ ABSL_GUARDED_BY(table_lock_) = 0; -}; - -} // namespace tcmalloc_internal -} // namespace tcmalloc -GOOGLE_MALLOC_SECTION_END - -#endif // TCMALLOC_INTERNAL_LIFETIME_PREDICTIONS_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/lifetime_predictions_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/lifetime_predictions_test.cc deleted file mode 100644 index 4280890afe6c..000000000000 --- a/contrib/libs/tcmalloc/tcmalloc/internal/lifetime_predictions_test.cc +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2019 The TCMalloc Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "tcmalloc/internal/lifetime_predictions.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "tcmalloc/testing/testutil.h" - -namespace tcmalloc { -namespace tcmalloc_internal { -namespace { - -class LifetimeDatabaseTest : public testing::Test { - protected: - LifetimeDatabase lifetime_database_; - - ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL LifetimeStats* - AllocateA() { - LifetimeDatabase::Key key; - return lifetime_database_.LookupOrAddLifetimeStats(&key); - } - - ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL LifetimeStats* - AllocateB() { - LifetimeDatabase::Key key; - return lifetime_database_.LookupOrAddLifetimeStats(&key); - } - - ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL LifetimeStats* - AllocateWithStacktraceId(int id) { - if (id == 0) { - LifetimeDatabase::Key key; - return lifetime_database_.LookupOrAddLifetimeStats(&key); - } else if (id % 2 == 0) { - return AllocateWithStacktraceId(id / 2); - } else { - return AllocateWithStacktraceId_2(id / 2); - } - } - - // Record a sufficiently large number of short-lived allocations to make - // a prediction short-lived, absent any long-lived allocations. - void MakeShortLived(LifetimeStats* stats, bool high_certainty) { - for (int i = 0; i < (high_certainty ? 100 : 2); i++) { - stats->Update(LifetimeStats::Prediction::kShortLived); - } - } - - private: - ABSL_ATTRIBUTE_NOINLINE ABSL_ATTRIBUTE_NO_TAIL_CALL LifetimeStats* - AllocateWithStacktraceId_2(int id) { - if (id == 0) { - LifetimeDatabase::Key key; - return lifetime_database_.LookupOrAddLifetimeStats(&key); - } else if (id % 2 == 0) { - return AllocateWithStacktraceId(id / 2); - } else { - return AllocateWithStacktraceId_2(id / 2); - } - } -}; - -TEST_F(LifetimeDatabaseTest, Basic) { - PRAGMA_NO_UNROLL - for (int i = 0; i < 2; i++) { - LifetimeStats* r1 = AllocateA(); - LifetimeStats* r2 = AllocateB(); - LifetimeStats* r3 = AllocateB(); - ASSERT_NE(nullptr, r1); - ASSERT_NE(nullptr, r2); - ASSERT_NE(nullptr, r3); - - // First iteration: set short-lived count. - if (i == 0) { - MakeShortLived(r1, false); - MakeShortLived(r2, true); - } else { - EXPECT_EQ(LifetimeStats::Prediction::kShortLived, - r1->Predict(LifetimeStats::Certainty::kLowCertainty)); - EXPECT_EQ(LifetimeStats::Prediction::kLongLived, - r1->Predict(LifetimeStats::Certainty::kHighCertainty)); - EXPECT_EQ(LifetimeStats::Prediction::kShortLived, - r2->Predict(LifetimeStats::Certainty::kLowCertainty)); - EXPECT_EQ(LifetimeStats::Prediction::kShortLived, - r2->Predict(LifetimeStats::Certainty::kHighCertainty)); - EXPECT_EQ(LifetimeStats::Prediction::kLongLived, - r3->Predict(LifetimeStats::Certainty::kLowCertainty)); - EXPECT_EQ(LifetimeStats::Prediction::kLongLived, - r3->Predict(LifetimeStats::Certainty::kHighCertainty)); - } - - lifetime_database_.RemoveLifetimeStatsReference(r1); - lifetime_database_.RemoveLifetimeStatsReference(r2); - lifetime_database_.RemoveLifetimeStatsReference(r3); - } -} - -TEST_F(LifetimeDatabaseTest, Eviction) { - const int kEntries = 5 * LifetimeDatabase::kMaxDatabaseSize; - - std::vector refs; - - PRAGMA_NO_UNROLL - for (int i = 0; i < kEntries; i++) { - LifetimeStats* r = AllocateWithStacktraceId(i); - refs.push_back(r); - - ASSERT_NE(nullptr, r); - if (i < LifetimeDatabase::kMaxDatabaseSize) { - MakeShortLived(r, true); - } - } - - // Check that even evicted entries are still accessible due to refcounts. - for (int i = 0; i < kEntries; i++) { - if (i < LifetimeDatabase::kMaxDatabaseSize) { - EXPECT_EQ(LifetimeStats::Prediction::kShortLived, - refs[i]->Predict(LifetimeStats::Certainty::kLowCertainty)); - } else { - EXPECT_EQ(LifetimeStats::Prediction::kLongLived, - refs[i]->Predict(LifetimeStats::Certainty::kLowCertainty)); - } - } - - EXPECT_EQ(LifetimeDatabase::kMaxDatabaseSize, lifetime_database_.size()); - EXPECT_EQ(kEntries - LifetimeDatabase::kMaxDatabaseSize, - lifetime_database_.evictions()); - - uint64_t before_bytes = lifetime_database_.arena_stats()->bytes_allocated; - - // Return all of the references, which should drop the remaining refcounts. - for (int i = 0; i < kEntries; i++) { - lifetime_database_.RemoveLifetimeStatsReference(refs[i]); - } - - uint64_t after_bytes = lifetime_database_.arena_stats()->bytes_allocated; - - // Check that this freed up memory - EXPECT_LT(after_bytes, before_bytes); -} - -} // namespace -} // namespace tcmalloc_internal -} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/lifetime_tracker.h b/contrib/libs/tcmalloc/tcmalloc/internal/lifetime_tracker.h deleted file mode 100644 index d348dbe60931..000000000000 --- a/contrib/libs/tcmalloc/tcmalloc/internal/lifetime_tracker.h +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 2020 The TCMalloc Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef TCMALLOC_INTERNAL_LIFETIME_TRACKER_H_ -#define TCMALLOC_INTERNAL_LIFETIME_TRACKER_H_ - -#include "absl/base/internal/cycleclock.h" -#include "absl/time/time.h" -#include "tcmalloc/internal/clock.h" -#include "tcmalloc/internal/lifetime_predictions.h" -#include "tcmalloc/internal/linked_list.h" - -GOOGLE_MALLOC_SECTION_BEGIN -namespace tcmalloc { -namespace tcmalloc_internal { - -template -class LifetimeTrackerImpl { - public: - // A tracker is attached to an individual allocation and tracks its lifetime. - // This allocation can either be in a region or in the filler. It contains - // a pointer back to the LifetimeStats of the allocation site that generated - // this allocation, so that statistics can be updated. - struct Tracker : public TList::Elem { - // The deadline after which the object is considered long-lived. - uint64_t deadline = 0; - - // If the allocation is associated with a counterfactual, this contains - // the hypothetical location in the short-lived region (null otherwise). - void* counterfactual_ptr = nullptr; - - // Lifetime statistics associated with this allocation (will be updated when - // the lifetime is known). - LifetimeStatsT* lifetime; - - // The allocation this stat belongs to was predicted short-lived. - bool predicted_short_lived = false; - - // Is this element currently tracked by the lifetime tracker? - bool is_tracked() { return deadline != 0; } - - // Reset the element (implies not tracked). - void reset() { - deadline = 0; - counterfactual_ptr = nullptr; - } - }; - - struct Stats { - uint64_t expired_lifetimes = 0; - uint64_t overestimated_lifetimes = 0; - uint64_t short_lived_predictions = 0; - uint64_t long_lived_predictions = 0; - }; - - explicit LifetimeTrackerImpl( - LifetimeDatabaseT* lifetime_database, absl::Duration timeout, - Clock clock = Clock{.now = absl::base_internal::CycleClock::Now, - .freq = absl::base_internal::CycleClock::Frequency}) - : timeout_(absl::ToDoubleSeconds(timeout) * clock.freq()), - lifetime_database_(*lifetime_database), - clock_(clock) {} - - // Registers a donated allocation with the tracker. - void AddAllocation(Tracker* tracker, LifetimeStatsT* lifetime, - bool predicted_short_lived) { - CheckForLifetimeExpirations(); - - if (predicted_short_lived) { - stats_.short_lived_predictions++; - } else { - stats_.long_lived_predictions++; - } - - ASSERT(tracker != nullptr); - ASSERT(lifetime != nullptr); - tracker->deadline = clock_.now() + timeout_; - tracker->lifetime = lifetime; - tracker->predicted_short_lived = predicted_short_lived; - list_.append(tracker); - } - - // Remove an allocation from the tracker. This will stop tracking the - // allocation and record whether it was correctly predicted. - void RemoveAllocation(Tracker* tracker) { - CheckForLifetimeExpirations(); - - // This is not tracked anymore. - if (!tracker->is_tracked()) { - return; - } - - if (!tracker->predicted_short_lived) { - stats_.overestimated_lifetimes++; - } - - if (tracker->lifetime != nullptr) { - tracker->lifetime->Update(LifetimeStatsT::Prediction::kShortLived); - lifetime_database_.RemoveLifetimeStatsReference(tracker->lifetime); - } - - tracker->reset(); - - list_.remove(tracker); - } - - // Check whether any lifetimes in the tracker have passed the threshold after - // which they are not short-lived anymore. - void CheckForLifetimeExpirations() { - // TODO(mmaas): Expirations are fairly cheap, but there is a theoretical - // possibility of having an arbitrary number of expirations at once, which - // could affect tail latency. We may want to limit the number of pages we - // let expire per unit time. - uint64_t now = clock_.now(); - Tracker* tracker = TryGetExpired(now); - while (tracker != nullptr) { - ASSERT(tracker->is_tracked()); - - // A page that was predicted short-lived was actually long-lived. - if (tracker->predicted_short_lived) { - stats_.expired_lifetimes++; - } - - if (tracker->lifetime != nullptr) { - tracker->lifetime->Update(LifetimeStatsT::Prediction::kLongLived); - lifetime_database_.RemoveLifetimeStatsReference(tracker->lifetime); - } - - tracker->reset(); - tracker = TryGetExpired(now); - } - } - - Stats stats() const { return stats_; } - - private: - // Returns the earliest expiring entry, or nullptr if none expired. - Tracker* TryGetExpired(uint64_t now) { - if (!list_.empty() && list_.first()->deadline < now) { - Tracker* s = list_.first(); - list_.remove(s); - return s; - } - return nullptr; - } - - const uint64_t timeout_; - - TList list_; - Stats stats_; - LifetimeDatabaseT& lifetime_database_; - Clock clock_; -}; - -using LifetimeTracker = LifetimeTrackerImpl; - -} // namespace tcmalloc_internal -} // namespace tcmalloc -GOOGLE_MALLOC_SECTION_END - -#endif // TCMALLOC_INTERNAL_LIFETIME_TRACKER_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/lifetime_tracker_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/lifetime_tracker_test.cc deleted file mode 100644 index 78ed38ecae45..000000000000 --- a/contrib/libs/tcmalloc/tcmalloc/internal/lifetime_tracker_test.cc +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright 2019 The TCMalloc Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "tcmalloc/internal/lifetime_tracker.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/time/time.h" -#include "tcmalloc/internal/lifetime_predictions.h" - -namespace tcmalloc { -namespace tcmalloc_internal { -namespace { - -class MockLifetimeStats { - public: - enum class Prediction { kShortLived, kLongLived }; - MOCK_METHOD(void, Update, (Prediction prediction), ()); -}; - -class MockLifetimeDatabase { - public: - MOCK_METHOD(void, RemoveLifetimeStatsReference, (MockLifetimeStats*), ()); -}; - -using LifetimeTrackerUnderTest = - LifetimeTrackerImpl; - -class LifetimeTrackerTest : public testing::Test { - protected: - const Clock kFakeClock = - Clock{.now = FakeClock, .freq = GetFakeClockFrequency}; - - void Advance(absl::Duration d) { - clock_ += absl::ToDoubleSeconds(d) * GetFakeClockFrequency(); - } - - private: - static int64_t FakeClock() { return clock_; } - - static double GetFakeClockFrequency() { - return absl::ToDoubleNanoseconds(absl::Seconds(2)); - } - - static int64_t clock_; -}; - -int64_t LifetimeTrackerTest::clock_{0}; - -TEST_F(LifetimeTrackerTest, Basic) { - MockLifetimeDatabase database; - LifetimeTrackerUnderTest tracker(&database, absl::Seconds(0.5), kFakeClock); - MockLifetimeStats stats; - - LifetimeTrackerUnderTest::Tracker tracker1; - tracker.AddAllocation(&tracker1, &stats, false); - Advance(absl::Seconds(1)); - - EXPECT_CALL(stats, Update(MockLifetimeStats::Prediction::kLongLived)); - EXPECT_CALL(database, RemoveLifetimeStatsReference(&stats)); - - LifetimeTrackerUnderTest::Tracker tracker2; - tracker.AddAllocation(&tracker2, &stats, false); - - EXPECT_CALL(stats, Update(MockLifetimeStats::Prediction::kShortLived)); - EXPECT_CALL(database, RemoveLifetimeStatsReference(&stats)); - - Advance(absl::Seconds(0.1)); - tracker.RemoveAllocation(&tracker2); - - EXPECT_EQ(tracker.stats().expired_lifetimes, 0); - EXPECT_EQ(tracker.stats().overestimated_lifetimes, 1); - EXPECT_EQ(tracker.stats().short_lived_predictions, 0); - EXPECT_EQ(tracker.stats().long_lived_predictions, 2); -} - -TEST_F(LifetimeTrackerTest, ExpirationLogic) { - MockLifetimeDatabase database; - LifetimeTrackerUnderTest tracker(&database, absl::Seconds(0.5), kFakeClock); - - // Create 100 trackers, all predicted short-lived. Every second tracker will - // be long-lived and therefore expire. - const int kNumTrackers = 100; - std::vector trackers(kNumTrackers); - MockLifetimeStats stats[] = {MockLifetimeStats(), MockLifetimeStats()}; - - for (int i = 0; i < kNumTrackers; ++i) { - tracker.AddAllocation(&trackers[i], &stats[i % 2], true); - Advance(absl::Milliseconds(1)); - } - - EXPECT_CALL(stats[0], Update(MockLifetimeStats::Prediction::kShortLived)) - .Times(kNumTrackers / 2); - EXPECT_CALL(database, RemoveLifetimeStatsReference(&stats[0])) - .Times(kNumTrackers / 2); - - for (int i = 0; i < kNumTrackers; i += 2) { - tracker.RemoveAllocation(&trackers[i]); - } - - // After an additional 450ms, 1/4 of the allocations should have expired. - EXPECT_CALL(stats[1], Update(MockLifetimeStats::Prediction::kLongLived)) - .Times(kNumTrackers / 4); - EXPECT_CALL(database, RemoveLifetimeStatsReference(&stats[1])) - .Times(kNumTrackers / 4); - - Advance(absl::Milliseconds(450)); - tracker.CheckForLifetimeExpirations(); - - EXPECT_EQ(tracker.stats().expired_lifetimes, kNumTrackers / 4); - EXPECT_EQ(tracker.stats().overestimated_lifetimes, 0); - EXPECT_EQ(tracker.stats().short_lived_predictions, kNumTrackers); - EXPECT_EQ(tracker.stats().long_lived_predictions, 0); -} - -} // namespace -} // namespace tcmalloc_internal -} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/linked_list.h b/contrib/libs/tcmalloc/tcmalloc/internal/linked_list.h index 181a48027580..5651ed0f3012 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/linked_list.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/linked_list.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,6 +24,7 @@ #include "absl/base/attributes.h" #include "absl/base/optimization.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" GOOGLE_MALLOC_SECTION_BEGIN @@ -59,14 +61,17 @@ inline void* SLL_Pop(void** list) { // LinkedList forms an in-place linked list with its void* elements. class LinkedList { private: - void* list_; // Linked list. - uint32_t length_; // Current length. + void* list_ = nullptr; // Linked list. + uint32_t length_ = 0; // Current length. public: - void Init() { - list_ = nullptr; - length_ = 0; - } + constexpr LinkedList() = default; + + // Not copy constructible or movable. + LinkedList(const LinkedList&) = delete; + LinkedList(LinkedList&&) = delete; + LinkedList& operator=(const LinkedList&) = delete; + LinkedList& operator=(LinkedList&&) = delete; // Return current length of list size_t length() const { return length_; } @@ -101,7 +106,7 @@ class LinkedList { // PushBatch and PopBatch do not guarantee an ordering. void PushBatch(int N, void** batch) { - ASSERT(N > 0); + TC_ASSERT_GT(N, 0); for (int i = 0; i < N - 1; ++i) { SLL_SetNext(batch[i], batch[i + 1]); } @@ -117,7 +122,7 @@ class LinkedList { p = SLL_Next(p); } list_ = p; - ASSERT(length_ >= N); + TC_ASSERT_GE(length_, N); length_ -= N; } }; @@ -146,9 +151,9 @@ class TList { // potential aliasing and does unnecessary reloads after stores. Elem* next = next_; Elem* prev = prev_; - ASSERT(prev->next_ == this); + TC_ASSERT_EQ(prev->next_, this); prev->next_ = next; - ASSERT(next->prev_ == this); + TC_ASSERT_EQ(next->prev_, this); next->prev_ = prev; #ifndef NDEBUG prev_ = nullptr; @@ -177,6 +182,12 @@ class TList { // Initialize to empty list. constexpr TList() { head_.next_ = head_.prev_ = &head_; } + // Not copy constructible/movable. + TList(const TList&) = delete; + TList(TList&&) = delete; + TList& operator=(const TList&) = delete; + TList& operator=(TList&&) = delete; + bool empty() const { return head_.next_ == &head_; } // Return the length of the linked list. O(n). @@ -190,15 +201,15 @@ class TList { // Returns first element in the list. The list must not be empty. ABSL_ATTRIBUTE_RETURNS_NONNULL T* first() const { - ASSERT(!empty()); - ASSERT(head_.next_ != nullptr); + TC_ASSERT(!empty()); + TC_ASSERT_NE(head_.next_, nullptr); return static_cast(head_.next_); } // Returns last element in the list. The list must not be empty. ABSL_ATTRIBUTE_RETURNS_NONNULL T* last() const { - ASSERT(!empty()); - ASSERT(head_.prev_ != nullptr); + TC_ASSERT(!empty()); + TC_ASSERT_NE(head_.prev_, nullptr); return static_cast(head_.prev_); } diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/linked_list_benchmark.cc b/contrib/libs/tcmalloc/tcmalloc/internal/linked_list_benchmark.cc index 505b1b62c222..2db3a7bcf7b6 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/linked_list_benchmark.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/linked_list_benchmark.cc @@ -19,6 +19,7 @@ #include "absl/random/random.h" #include "benchmark/benchmark.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/linked_list.h" #include "tcmalloc/internal/logging.h" #include "tcmalloc/internal/mock_span.h" @@ -33,7 +34,6 @@ void BM_PushPop(benchmark::State& state) { const int sequential_calls = state.range(1); LinkedList list; - list.Init(); const size_t size = pointers * sizeof(void*); std::vector v(sequential_calls); @@ -68,7 +68,6 @@ void BM_PushPopBatch(benchmark::State& state) { const int batch_size = state.range(1); LinkedList list; - list.Init(); const size_t size = pointers * sizeof(void*); const int kNumberOfObjects = 64 << 10; @@ -112,7 +111,7 @@ static void BM_AppendRemove(benchmark::State& state) { // Create MockSpans in append order for (int i = 0; i < sequential_calls; i++) { MockSpan* s = MockSpan::New(i); - CHECK_CONDITION(s != nullptr); + TC_CHECK_NE(s, nullptr); vappend[i] = s; } diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/linked_list_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/linked_list_test.cc index 3299bca8d873..66f9bcf4454a 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/linked_list_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/linked_list_test.cc @@ -14,16 +14,16 @@ #include "tcmalloc/internal/linked_list.h" +#include #include #include +#include #include #include "gtest/gtest.h" #include "absl/container/flat_hash_set.h" -#include "absl/container/node_hash_set.h" #include "absl/random/random.h" -#include "benchmark/benchmark.h" #include "tcmalloc/internal/mock_span.h" namespace tcmalloc { @@ -32,9 +32,12 @@ namespace { class LinkedListTest : public ::testing::Test { protected: - void SetUp() override { list_.Init(); } - LinkedList list_; + + static_assert(!std::is_copy_constructible::value, + "LinkedList should not be copyable"); + static_assert(!std::is_move_constructible::value, + "LinkedList should not be movable"); }; TEST_F(LinkedListTest, PushPop) { @@ -117,6 +120,11 @@ TEST_F(LinkedListTest, PushPopBatch) { class TListTest : public ::testing::Test { protected: MockSpanList list_; + + static_assert(!std::is_copy_constructible::value, + "TList should not be copyable"); + static_assert(!std::is_move_constructible::value, + "TList should not be movable"); }; TEST_F(TListTest, AppendPushPop) { diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/linux_syscall_support.h b/contrib/libs/tcmalloc/tcmalloc/internal/linux_syscall_support.h index 367c8a9e4dd6..9346b8d43584 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/linux_syscall_support.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/linux_syscall_support.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,6 +16,14 @@ #ifndef TCMALLOC_INTERNAL_LINUX_SYSCALL_SUPPORT_H_ #define TCMALLOC_INTERNAL_LINUX_SYSCALL_SUPPORT_H_ +#ifdef __linux__ +#ifdef __has_include +#if __has_include() +#include +#endif // __has_include() +#endif // __has_include +#endif // __linux__ + /* include/uapi/linux/rseq.h */ struct kernel_rseq { @@ -41,11 +50,6 @@ static_assert(sizeof(kernel_rseq) == (4 * sizeof(unsigned long long)), "Unexpected size for rseq structure"); struct kernel_rseq_cs { - unsigned version; - unsigned flags; - unsigned long long start_ip; - unsigned long long post_commit_offset; - unsigned long long abort_ip; // This is aligned, per upstream RSEQ specification. } __attribute__((aligned(4 * sizeof(unsigned long long)))); @@ -55,7 +59,6 @@ static_assert(sizeof(kernel_rseq_cs) == (4 * sizeof(unsigned long long)), #if !defined(__NR_rseq) #if defined(__x86_64__) #define __NR_rseq 334 -#define __NR_membarrier 324 #elif defined(__aarch64__) #define __NR_rseq 293 #elif defined(__PPC__) @@ -63,4 +66,8 @@ static_assert(sizeof(kernel_rseq_cs) == (4 * sizeof(unsigned long long)), #endif #endif +#ifndef KPF_ZERO_PAGE +#define KPF_ZERO_PAGE 24 +#endif + #endif // TCMALLOC_INTERNAL_LINUX_SYSCALL_SUPPORT_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/logging.cc b/contrib/libs/tcmalloc/tcmalloc/internal/logging.cc index 2b70bc1502a7..a53c26aa15bb 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/logging.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/logging.cc @@ -14,7 +14,7 @@ #include "tcmalloc/internal/logging.h" -#include +#include #include #include #include @@ -22,19 +22,31 @@ #include #include +#include +#include +#include #include "absl/base/attributes.h" #include "absl/base/const_init.h" #include "absl/base/internal/spinlock.h" #include "absl/base/macros.h" #include "absl/debugging/stacktrace.h" +#include "absl/strings/ascii.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "tcmalloc/internal/allocation_guard.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/environment.h" #include "tcmalloc/internal/parameter_accessors.h" -#include "tcmalloc/malloc_extension.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { +ABSL_CONST_INIT SampleUserDataSupport::CreateSampleUserDataCallback* SampleUserDataSupport::create_sample_user_data_callback_ = nullptr; +ABSL_CONST_INIT SampleUserDataSupport::CopySampleUserDataCallback* SampleUserDataSupport::copy_sample_user_data_callback_ = nullptr; +ABSL_CONST_INIT SampleUserDataSupport::DestroySampleUserDataCallback* SampleUserDataSupport::destroy_sample_user_data_callback_ = nullptr; + // Variables for storing crash output. Allocated statically since we // may not be able to heap-allocate while crashing. ABSL_CONST_INIT static absl::base_internal::SpinLock crash_lock( @@ -42,7 +54,9 @@ ABSL_CONST_INIT static absl::base_internal::SpinLock crash_lock( static bool crashed = false; static const size_t kStatsBufferSize = 16 << 10; +#ifndef __APPLE__ static char stats_buffer[kStatsBufferSize] = {0}; +#endif // __APPLE__ static void WriteMessage(const char* msg, int length) { (void)::write(STDERR_FILENO, msg, length); @@ -50,91 +64,106 @@ static void WriteMessage(const char* msg, int length) { void (*log_message_writer)(const char* msg, int length) = WriteMessage; -class Logger { - public: - bool Add(const LogItem& item); - bool AddStr(const char* str, int n); - bool AddNum(uint64_t num, int base); // base must be 10 or 16. - - static constexpr int kBufSize = 512; - char* p_; - char* end_; - char buf_[kBufSize]; - - StackTrace trace; -}; - -static Logger FormatLog(bool with_stack, const char* filename, int line, - LogItem a, LogItem b, LogItem c, LogItem d) { - Logger state; - state.p_ = state.buf_; - state.end_ = state.buf_ + sizeof(state.buf_); - // clang-format off - state.AddStr(filename, strlen(filename)) && - state.AddStr(":", 1) && - state.AddNum(line, 10) && - state.AddStr("]", 1) && - state.Add(a) && - state.Add(b) && - state.Add(c) && - state.Add(d); - // clang-format on - - if (with_stack) { - state.trace.depth = - absl::GetStackTrace(state.trace.stack, kMaxStackDepth, 1); - state.Add(LogItem("@")); - for (int i = 0; i < state.trace.depth; i++) { - state.Add(LogItem(state.trace.stack[i])); - } - } +// If this failure occurs during "bazel test", writes a warning for Bazel to +// display. +static void RecordBazelWarning(absl::string_view type, + absl::string_view error) { + constexpr absl::string_view kHeaderSuffix = " error detected: "; + + const char* warning_file = thread_safe_getenv("TEST_WARNINGS_OUTPUT_FILE"); + if (!warning_file) return; // Not a bazel test. + + int fd = open(warning_file, O_CREAT | O_WRONLY | O_APPEND, 0644); + if (fd == -1) return; + (void)write(fd, type.data(), type.size()); + (void)write(fd, kHeaderSuffix.data(), kHeaderSuffix.size()); + (void)write(fd, error.data(), error.size()); + (void)write(fd, "\n", 1); + close(fd); +} - // Teminate with newline - if (state.p_ >= state.end_) { - state.p_ = state.end_ - 1; +// If this failure occurs during a gUnit test, writes an XML file describing the +// error type. Note that we cannot use ::testing::Test::RecordProperty() +// because it doesn't write the XML file if a test crashes (which we're about to +// do here). So we write directly to the XML file instead. +// +static void RecordTestFailure(absl::string_view detector, + absl::string_view error) { + const char* xml_file = thread_safe_getenv("XML_OUTPUT_FILE"); + if (!xml_file) return; // Not a gUnit test. + + // Record test failure for Sponge. + constexpr absl::string_view kXmlHeaderPart1 = + "" + "" + " " + " " + " " + " " + " "; + constexpr absl::string_view kXmlFooterPart2 = + " detected a memory error. See the test log for full report." + " " + ""; + + int fd = open(xml_file, O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (fd == -1) return; + (void)write(fd, kXmlHeaderPart1.data(), kXmlHeaderPart1.size()); + for (char c : detector) { + c = absl::ascii_tolower(c); + (void)write(fd, &c, 1); } - *state.p_ = '\n'; - state.p_++; - - return state; + (void)write(fd, kXmlHeaderPart2.data(), kXmlHeaderPart2.size()); + (void)write(fd, error.data(), error.size()); + (void)write(fd, kXmlFooterPart1.data(), kXmlFooterPart1.size()); + (void)write(fd, detector.data(), detector.size()); + (void)write(fd, kXmlFooterPart2.data(), kXmlFooterPart2.size()); + close(fd); } - -ABSL_ATTRIBUTE_NOINLINE -void Log(LogMode mode, const char* filename, int line, LogItem a, LogItem b, - LogItem c, LogItem d) { - Logger state = FormatLog(mode == kLogWithStack, filename, line, a, b, c, d); - int msglen = state.p_ - state.buf_; - (*log_message_writer)(state.buf_, msglen); +// +// If this crash occurs in a test, records test failure summaries. +// +// detector is the bug detector or tools that found the error +// error contains the type of error to record. +void RecordCrash(absl::string_view detector, absl::string_view error) { + TC_ASSERT(!detector.empty()); + TC_ASSERT(!error.empty()); + + RecordBazelWarning(detector, error); + RecordTestFailure(detector, error); } ABSL_ATTRIBUTE_NOINLINE -void Crash(CrashMode mode, const char* filename, int line, LogItem a, LogItem b, - LogItem c, LogItem d) { - Logger state = FormatLog(true, filename, line, a, b, c, d); - - int msglen = state.p_ - state.buf_; +ABSL_ATTRIBUTE_NORETURN +static void Crash(const char* filename, int line, const char* msg, + size_t msglen, bool oom) { + StackTrace trace; + trace.depth = absl::GetStackTrace(trace.stack, kMaxStackDepth, 1); // FailureSignalHandler mallocs for various logging attempts. // We might be crashing holding tcmalloc locks. // We're substantially less likely to try to take those locks // (and thus deadlock until the alarm timer fires) if we disable sampling. #ifndef __APPLE__ - if (&TCMalloc_Internal_SetProfileSamplingRate != nullptr) { - TCMalloc_Internal_SetProfileSamplingRate(0); + if (&TCMalloc_Internal_SetProfileSamplingInterval != nullptr) { + TCMalloc_Internal_SetProfileSamplingInterval(0); } #endif // __APPLE__ bool first_crash = false; { - absl::base_internal::SpinLockHolder l(&crash_lock); + AllocationGuardSpinLockHolder l(&crash_lock); if (!crashed) { crashed = true; first_crash = true; } } - (*log_message_writer)(state.buf_, msglen); - if (first_crash && mode == kCrashWithStats) { + (*log_message_writer)(msg, msglen); + if (first_crash && oom) { #ifndef __APPLE__ if (&TCMalloc_Internal_GetStats != nullptr) { size_t n = TCMalloc_Internal_GetStats(stats_buffer, kStatsBufferSize); @@ -146,128 +175,107 @@ void Crash(CrashMode mode, const char* filename, int line, LogItem a, LogItem b, abort(); } -bool Logger::Add(const LogItem& item) { - // Separate real items with spaces - if (item.tag_ != LogItem::kEnd && p_ < end_) { - *p_ = ' '; - p_++; - } +ABSL_ATTRIBUTE_NORETURN void CheckFailed(const char* file, int line, + const char* msg, int msglen) { + Crash(file, line, msg, msglen, false); +} - switch (item.tag_) { - case LogItem::kStr: - return AddStr(item.u_.str, strlen(item.u_.str)); - case LogItem::kUnsigned: - return AddNum(item.u_.unum, 10); - case LogItem::kSigned: - if (item.u_.snum < 0) { - // The cast to uint64_t is intentionally before the negation - // so that we do not attempt to negate -2^63. - return AddStr("-", 1) && - AddNum(-static_cast(item.u_.snum), 10); - } else { - return AddNum(static_cast(item.u_.snum), 10); - } - case LogItem::kPtr: - return AddStr("0x", 2) && - AddNum(reinterpret_cast(item.u_.ptr), 16); - default: - return false; - } +void CrashWithOOM(size_t alloc_size) { + char buf[512]; + int n = absl::SNPrintF(buf, sizeof(buf), + "Unable to allocate %zu (new failed)", alloc_size); + Crash("tcmalloc", 0, buf, n, true); } -bool Logger::AddStr(const char* str, int n) { - ptrdiff_t remaining = end_ - p_; - if (remaining < n) { - // Try to log a truncated message if there is some space. - static constexpr absl::string_view kDots = "..."; - if (remaining > kDots.size() + 1) { - int truncated = remaining - kDots.size(); - memcpy(p_, str, truncated); - p_ += truncated; - memcpy(p_, kDots.data(), kDots.size()); - p_ += kDots.size(); - - return true; - } - return false; - } else { - memcpy(p_, str, n); - p_ += n; - return true; +void PrintStackTrace(void* const* stack_frames, size_t depth) { + for (size_t i = 0; i < depth; ++i) { + TC_LOG(" @ %p", stack_frames[i]); } } -bool Logger::AddNum(uint64_t num, int base) { - static const char kDigits[] = "0123456789abcdef"; - char space[22]; // more than enough for 2^64 in smallest supported base (10) - char* end = space + sizeof(space); - char* pos = end; - do { - pos--; - *pos = kDigits[num % base]; - num /= base; - } while (num > 0 && pos > space); - return AddStr(pos, end - pos); +void PrintStackTraceFromSignalHandler(void* context) { + void* stack_frames[kMaxStackDepth]; + size_t depth = absl::GetStackTraceWithContext(stack_frames, kMaxStackDepth, + 1, + context, nullptr); + PrintStackTrace(stack_frames, depth); } -PbtxtRegion::PbtxtRegion(Printer* out, PbtxtRegionType type, int indent) - : out_(out), type_(type), indent_(indent) { +PbtxtRegion::PbtxtRegion(Printer& out, PbtxtRegionType type) + : out_(&out), type_(type) { switch (type_) { case kTop: break; case kNested: - out_->printf("{"); + out_->Append("{"); break; } - ++indent_; } PbtxtRegion::~PbtxtRegion() { - --indent_; - out_->printf("\n"); - for (int i = 0; i < indent_; i++) { - out_->printf(" "); - } switch (type_) { case kTop: break; case kNested: - out_->printf("}"); + out_->Append("}"); break; } } -void PbtxtRegion::NewLineAndIndent() { - out_->printf("\n"); - for (int i = 0; i < indent_; i++) { - out_->printf(" "); - } -} +#ifndef NDEBUG +static std::atomic injected_i64; +static std::atomic injected_d; +static std::atomic injected_b; +#endif // NDEBUG void PbtxtRegion::PrintI64(absl::string_view key, int64_t value) { - NewLineAndIndent(); - out_->printf("%s: %" PRIi64, key, value); +#ifndef NDEBUG + int64_t* ptr = injected_i64.load(std::memory_order_acquire); + if (ptr) { + value = *ptr; + } +#endif + + out_->Append(" ", key, ": ", value); } void PbtxtRegion::PrintDouble(absl::string_view key, double value) { - NewLineAndIndent(); - out_->printf("%s: %f", key, value); +#ifndef NDEBUG + double* ptr = injected_d.load(std::memory_order_acquire); + if (ptr) { + value = *ptr; + } +#endif + + out_->Append(" ", key, ": ", value); } void PbtxtRegion::PrintBool(absl::string_view key, bool value) { - NewLineAndIndent(); - out_->printf("%s: %s", key, value ? "true" : "false"); +#ifndef NDEBUG + bool* ptr = injected_b.load(std::memory_order_acquire); + if (ptr) { + value = *ptr; + } +#endif + + out_->Append(" ", key, value ? ": true" : ": false"); } void PbtxtRegion::PrintRaw(absl::string_view key, absl::string_view value) { - NewLineAndIndent(); - out_->printf("%s: %s", key, value); + out_->Append(" ", key, ": ", value); +} + +#ifndef NDEBUG +void PbtxtRegion::InjectValues(int64_t* i64, double* d, bool* b) { + injected_i64.store(i64, std::memory_order_release); + injected_d.store(d, std::memory_order_release); + injected_b.store(b, std::memory_order_release); } +#endif // NDEBUG PbtxtRegion PbtxtRegion::CreateSubRegion(absl::string_view key) { - NewLineAndIndent(); - out_->printf("%s ", key); - PbtxtRegion sub(out_, kNested, indent_); + out_->Append(" ", key, " "); + PbtxtRegion sub(*out_, kNested); return sub; } diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/logging.h b/contrib/libs/tcmalloc/tcmalloc/internal/logging.h index 4d42aa40a9fe..e41732dc4254 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/logging.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/logging.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,11 +21,24 @@ #include #include -#include "absl/base/internal/per_thread_tls.h" +#include +#include +#include +#include +#include +#include +#include + +#include "absl/base/attributes.h" +#include "absl/base/internal/sysinfo.h" #include "absl/base/optimization.h" +#include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" +#include "absl/time/time.h" +#include "tcmalloc/internal/allocation_guard.h" #include "tcmalloc/internal/config.h" +#include "tcmalloc/malloc_extension.h" //------------------------------------------------------------------- // Utility routines @@ -33,19 +47,103 @@ // Safe logging helper: we write directly to the stderr file // descriptor and avoid FILE buffering because that may invoke // malloc(). -// -// Example: -// Log(kLog, __FILE__, __LINE__, "error", bytes); GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { +class SampleUserDataSupport { +public: + using CreateSampleUserDataCallback = void*(); + using CopySampleUserDataCallback = void*(void*); + using DestroySampleUserDataCallback = void(void*); + + class UserData { + public: + static UserData Make() { + return UserData{CreateSampleUserData()}; + } + + constexpr UserData() noexcept : ptr_(nullptr) {} + + UserData(const UserData& that) noexcept : ptr_(CopySampleUserData(that.ptr_)) {} + UserData& operator=(const UserData& that) noexcept { + DestroySampleUserData(ptr_); + ptr_ = CopySampleUserData(that.ptr_); + return *this; + } + + UserData(UserData&& that) noexcept : ptr_(that.ptr_) { + that.ptr_ = nullptr; + } + UserData& operator=(UserData&& that) noexcept { + if (this == &that) { + return *this; + } + DestroySampleUserData(ptr_); + ptr_ = that.ptr_; + that.ptr_ = nullptr; + return *this; + } + void Reset() { + DestroySampleUserData(ptr_); + ptr_ = nullptr; + } + + ~UserData() { + DestroySampleUserData(ptr_); + } + + void* Get() const { return ptr_; } + private: + UserData(void* ptr) noexcept : ptr_(ptr) {} + private: + void* ptr_; + }; + + static void Enable(CreateSampleUserDataCallback create, + CopySampleUserDataCallback copy, + DestroySampleUserDataCallback destroy) { + create_sample_user_data_callback_ = create; + copy_sample_user_data_callback_ = copy; + destroy_sample_user_data_callback_ = destroy; + } +private: + static void* CreateSampleUserData() { + if (create_sample_user_data_callback_ != nullptr) { + return create_sample_user_data_callback_(); + } + return nullptr; + } + + static void* CopySampleUserData(void* ptr) noexcept { + if (copy_sample_user_data_callback_ != nullptr) { + return copy_sample_user_data_callback_(ptr); + } + return nullptr; + } + + static void DestroySampleUserData(void* ptr) noexcept { + if (destroy_sample_user_data_callback_ != nullptr) { + destroy_sample_user_data_callback_(ptr); + } + } + ABSL_CONST_INIT static CreateSampleUserDataCallback* create_sample_user_data_callback_; + ABSL_CONST_INIT static CopySampleUserDataCallback* copy_sample_user_data_callback_; + ABSL_CONST_INIT static DestroySampleUserDataCallback* destroy_sample_user_data_callback_; +}; + static constexpr int kMaxStackDepth = 64; +// An opaque handle type used to identify allocations. +using AllocHandle = int64_t; + // size/depth are made the same size as a pointer so that some generic // code below can conveniently cast them back and forth to void*. struct StackTrace { + // An opaque handle used by allocator to uniquely identify the sampled + // memory block. + AllocHandle sampled_alloc_handle; // For small sampled objects, we allocate a full span to hold the // sampled object. However to avoid disturbing fragmentation @@ -59,113 +157,201 @@ struct StackTrace { uintptr_t requested_size; uintptr_t requested_alignment; uintptr_t allocated_size; // size after sizeclass/page rounding + bool requested_size_returning; - uintptr_t depth; // Number of PC values stored in array below - void* stack[kMaxStackDepth]; + uint8_t access_hint; + bool cold_allocated; // weight is the expected number of *bytes* that were requested // between the previous sample and this one size_t weight; - void* user_data; + SampleUserDataSupport::UserData user_data; - template - friend H AbslHashValue(H h, const StackTrace& t) { - // As we use StackTrace as a key-value node in StackTraceTable, we only - // produce a hasher for the fields used as keys. - return H::combine(H::combine_contiguous(std::move(h), t.stack, t.depth), - t.depth, t.requested_size, t.requested_alignment, - t.allocated_size - ); - } -}; + // Timestamp of allocation. + absl::Time allocation_time; -enum LogMode { - kLog, // Just print the message - kLogWithStack, // Print the message and a stack trace -}; + Profile::Sample::GuardedStatus guarded_status; -class Logger; + // How the memory was allocated (new/malloc/etc.) + Profile::Sample::AllocationType allocation_type; -// A LogItem holds any of the argument types that can be passed to Log() -class LogItem { - public: - LogItem() : tag_(kEnd) {} - LogItem(const char* v) : tag_(kStr) { u_.str = v; } - LogItem(int v) : tag_(kSigned) { u_.snum = v; } - LogItem(long v) : tag_(kSigned) { u_.snum = v; } - LogItem(long long v) : tag_(kSigned) { u_.snum = v; } - LogItem(unsigned int v) : tag_(kUnsigned) { u_.unum = v; } - LogItem(unsigned long v) : tag_(kUnsigned) { u_.unum = v; } - LogItem(unsigned long long v) : tag_(kUnsigned) { u_.unum = v; } - LogItem(const void* v) : tag_(kPtr) { u_.ptr = v; } + // If not nullptr, this is the start address of the span corresponding to this + // sampled allocation. This may be nullptr for cases where it is not useful + // for residency analysis such as for peakheapz. + void* span_start_address = nullptr; - private: - friend class Logger; - enum Tag { kStr, kSigned, kUnsigned, kPtr, kEnd }; - Tag tag_; - union { - const char* str; - const void* ptr; - int64_t snum; - uint64_t unum; - } u_; + uintptr_t depth; // Number of PC values stored in array below + // Place stack as last member because it might not all be accessed. + void* stack[kMaxStackDepth]; }; -extern void Log(LogMode mode, const char* filename, int line, LogItem a, - LogItem b = LogItem(), LogItem c = LogItem(), - LogItem d = LogItem()); +#define TC_LOG(msg, ...) \ + tcmalloc::tcmalloc_internal::LogImpl("%d %s:%d] " msg "\n", __FILE__, \ + __LINE__, ##__VA_ARGS__) + +void RecordCrash(absl::string_view detector, absl::string_view error); +ABSL_ATTRIBUTE_NORETURN void CrashWithOOM(size_t alloc_size); +ABSL_ATTRIBUTE_NORETURN void CheckFailed(const char* file, int line, + const char* msg, int msglen); + +template +ABSL_ATTRIBUTE_NORETURN ABSL_ATTRIBUTE_NOINLINE void CheckFailed( + const char* func, const char* file, int line, + const absl::FormatSpec& format, + const Args&... args) { + AllocationGuard no_allocations; + char buf[512]; + int n = + absl::SNPrintF(buf, sizeof(buf), format, absl::base_internal::GetTID(), + file, line, func, args...); + buf[sizeof(buf) - 1] = 0; + CheckFailed(file, line, buf, std::min(n, sizeof(buf) - 1)); +} + +void PrintStackTrace(void* const* stack_frames, size_t depth); +void PrintStackTraceFromSignalHandler(void* context); + +// Tests can override this function to collect logging messages. +extern void (*log_message_writer)(const char* msg, int length); -enum CrashMode { - kCrash, // Print the message and crash - kCrashWithStats // Print the message, some stats, and crash +template +ABSL_ATTRIBUTE_NOINLINE void LogImpl( + const absl::FormatSpec& format, const Args&... args) { + char buf[512]; + int n; + { + AllocationGuard no_allocations; + n = absl::SNPrintF(buf, sizeof(buf), format, absl::base_internal::GetTID(), + args...); + } + buf[sizeof(buf) - 1] = 0; + (*log_message_writer)(buf, std::min(n, sizeof(buf) - 1)); +} + +// TC_BUG unconditionally aborts the program with the message. +#define TC_BUG(msg, ...) \ + tcmalloc::tcmalloc_internal::CheckFailed(__FUNCTION__, __FILE__, __LINE__, \ + "%d %s:%d] CHECK in %s: " msg "\n", \ + ##__VA_ARGS__) + +// TC_CHECK* check the given condition in both debug and release builds, +// and abort the program if the condition is false. +// Macros accept an additional optional formatted message, for example: +// TC_CHECK_EQ(a, b); +// TC_CHECK_EQ(a, b, "ptr=%p flags=%d", ptr, flags); +#define TC_CHECK(a, ...) TCMALLOC_CHECK_IMPL(a, #a, "" __VA_ARGS__) +#define TC_CHECK_EQ(a, b, ...) \ + TCMALLOC_CHECK_OP((a), ==, (b), #a, #b, "" __VA_ARGS__) +#define TC_CHECK_NE(a, b, ...) \ + TCMALLOC_CHECK_OP((a), !=, (b), #a, #b, "" __VA_ARGS__) +#define TC_CHECK_LT(a, b, ...) \ + TCMALLOC_CHECK_OP((a), <, (b), #a, #b, "" __VA_ARGS__) +#define TC_CHECK_LE(a, b, ...) \ + TCMALLOC_CHECK_OP((a), <=, (b), #a, #b, "" __VA_ARGS__) +#define TC_CHECK_GT(a, b, ...) \ + TCMALLOC_CHECK_OP((a), >, (b), #a, #b, "" __VA_ARGS__) +#define TC_CHECK_GE(a, b, ...) \ + TCMALLOC_CHECK_OP((a), >=, (b), #a, #b, "" __VA_ARGS__) + +// TC_ASSERT* are debug-only versions of TC_CHECK*. +#ifndef NDEBUG +#define TC_ASSERT TC_CHECK +#define TC_ASSERT_EQ TC_CHECK_EQ +#define TC_ASSERT_NE TC_CHECK_NE +#define TC_ASSERT_LT TC_CHECK_LT +#define TC_ASSERT_LE TC_CHECK_LE +#define TC_ASSERT_GT TC_CHECK_GT +#define TC_ASSERT_GE TC_CHECK_GE +#else // #ifndef NDEBUG +#define TC_ASSERT(a, ...) TC_CHECK(true || (a), ##__VA_ARGS__) +#define TC_ASSERT_EQ(a, b, ...) TC_ASSERT((a) == (b), ##__VA_ARGS__) +#define TC_ASSERT_NE(a, b, ...) TC_ASSERT((a) == (b), ##__VA_ARGS__) +#define TC_ASSERT_LT(a, b, ...) TC_ASSERT((a) == (b), ##__VA_ARGS__) +#define TC_ASSERT_LE(a, b, ...) TC_ASSERT((a) == (b), ##__VA_ARGS__) +#define TC_ASSERT_GT(a, b, ...) TC_ASSERT((a) == (b), ##__VA_ARGS__) +#define TC_ASSERT_GE(a, b, ...) TC_ASSERT((a) == (b), ##__VA_ARGS__) +#endif // #ifndef NDEBUG + +#define TCMALLOC_CHECK_IMPL(condition, str, msg, ...) \ + ({ \ + ABSL_PREDICT_TRUE((condition)) \ + ? (void)0 : TC_BUG("%s (false) " msg, str, ##__VA_ARGS__); \ + }) + +#define TCMALLOC_CHECK_OP(c1, op, c2, cs1, cs2, msg, ...) \ + ({ \ + const auto& cc1 = (c1); \ + const auto& cc2 = (c2); \ + if (ABSL_PREDICT_FALSE(!(cc1 op cc2))) { \ + TC_BUG("%s " #op " %s (%v " #op " %v) " msg, cs1, cs2, \ + tcmalloc::tcmalloc_internal::FormatConvert(cc1), \ + tcmalloc::tcmalloc_internal::FormatConvert(cc2), ##__VA_ARGS__); \ + } \ + (void)0; \ + }) + +// absl::SNPrintF rejects to print pointers with %v, +// so we need this little dance to convenience it. +struct PtrFormatter { + const volatile void* val; + template + friend void AbslStringify(Sink& sink, const PtrFormatter& p) { + absl::Format(&sink, "%p", p.val); + } }; -ABSL_ATTRIBUTE_NORETURN -void Crash(CrashMode mode, const char* filename, int line, LogItem a, - LogItem b = LogItem(), LogItem c = LogItem(), LogItem d = LogItem()); +template +PtrFormatter FormatConvert(T* v) { + return PtrFormatter{v}; +} -// Tests can override this function to collect logging messages. -extern void (*log_message_writer)(const char* msg, int length); +inline PtrFormatter FormatConvert(std::nullptr_t v) { return PtrFormatter{v}; } + +template +struct OptionalFormatter { + const T* val; + template + friend void AbslStringify(Sink& sink, const OptionalFormatter& p) { + if (p.val != nullptr) { + absl::Format(&sink, "%v", *p.val); + } else { + absl::Format(&sink, "???"); + } + } +}; -// Like assert(), but executed even in NDEBUG mode -#undef CHECK_CONDITION -#define CHECK_CONDITION(cond) \ - (ABSL_PREDICT_TRUE(cond) ? (void)0 \ - : (::tcmalloc::tcmalloc_internal::Crash( \ - ::tcmalloc::tcmalloc_internal::kCrash, \ - __FILE__, __LINE__, #cond))) +template +OptionalFormatter FormatConvert(const std::optional& v) { + return {v.has_value() ? &*v : nullptr}; +} -// Our own version of assert() so we can avoid hanging by trying to do -// all kinds of goofy printing while holding the malloc lock. -#ifndef NDEBUG -#define ASSERT(cond) CHECK_CONDITION(cond) -#else -#define ASSERT(cond) ((void)0) -#endif +template +const T& FormatConvert(const T& v) { + return v; +} // Print into buffer class Printer { private: - char* buf_; // Where should we write next - int left_; // Space left in buffer (including space for \0) - int required_; // Space we needed to complete all printf calls up to this - // point + char* buf_; // Where should we write next + size_t left_; // Space left in buffer (including space for \0) + size_t required_; // Space we needed to complete all printf calls up to this + // point public: // REQUIRES: "length > 0" - Printer(char* buf, int length) : buf_(buf), left_(length), required_(0) { - ASSERT(length > 0); + Printer(char* buf, size_t length) : buf_(buf), left_(length), required_(0) { + TC_ASSERT_GT(length, 0); buf[0] = '\0'; } + Printer(const Printer&) = delete; + Printer(Printer&&) = default; + template void printf(const absl::FormatSpec& format, const Args&... args) { - ASSERT(left_ >= 0); - if (left_ <= 0) { - return; - } - + AllocationGuard enforce_no_alloc; const int r = absl::SNPrintF(buf_, left_, format, args...); if (r < 0) { left_ = 0; @@ -181,7 +367,37 @@ class Printer { } } - int SpaceRequired() const { return required_; } + template + void Append(const Args&... args) { + AllocationGuard enforce_no_alloc; + AppendPieces({static_cast(args).Piece()...}); + } + + size_t SpaceRequired() const { return required_; } + + private: + void AppendPieces(std::initializer_list pieces) { + size_t total_size = 0; + for (const absl::string_view piece : pieces) total_size += piece.size(); + + required_ += total_size; + if (left_ < total_size) { + left_ = 0; + return; + } + + for (const absl::string_view& piece : pieces) { + const size_t this_size = piece.size(); + if (this_size == 0) { + continue; + } + + memcpy(buf_, piece.data(), this_size); + buf_ += this_size; + } + + left_ -= total_size; + } }; enum PbtxtRegionType { kTop, kNested }; @@ -191,7 +407,7 @@ enum PbtxtRegionType { kTop, kNested }; // brackets). class PbtxtRegion { public: - PbtxtRegion(Printer* out, PbtxtRegionType type, int indent); + PbtxtRegion(Printer& out ABSL_ATTRIBUTE_LIFETIME_BOUND, PbtxtRegionType type); ~PbtxtRegion(); PbtxtRegion(const PbtxtRegion&) = delete; @@ -205,14 +421,16 @@ class PbtxtRegion { void PrintRaw(absl::string_view key, absl::string_view value); // Prints 'key subregion'. Return the created subregion. - PbtxtRegion CreateSubRegion(absl::string_view key); + PbtxtRegion CreateSubRegion(absl::string_view key) + ABSL_ATTRIBUTE_LIFETIME_BOUND; - private: - void NewLineAndIndent(); +#ifndef NDEBUG + static void InjectValues(int64_t* i64, double* d, bool* b); +#endif + private: Printer* out_; PbtxtRegionType type_; - int indent_; }; } // namespace tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/logging_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/logging_test.cc index c7b58de40fc8..0928d856e251 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/logging_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/logging_test.cc @@ -14,28 +14,26 @@ #include "tcmalloc/internal/logging.h" +#include #include +#include +#include +#include +#include #include +#include #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/flags/flag.h" +#include "absl/base/attributes.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" namespace tcmalloc { namespace tcmalloc_internal { namespace { -static std::string* log_buffer; - -static void RecordLogMessage(const char* msg, int length) { - // Make tests less brittle by trimming trailing whitespace - while (length > 0 && (msg[length - 1] == ' ' || msg[length - 1] == '\n')) { - length--; - } - log_buffer->assign(msg, length); -} - TEST(InternalLogging, MessageFormatting) { std::string long_string; for (int i = 0; i < 100; i++) { @@ -43,75 +41,218 @@ TEST(InternalLogging, MessageFormatting) { } // Arrange to intercept Log() output - log_buffer = new std::string(); - void (*old_writer)(const char*, int) = log_message_writer; - log_message_writer = RecordLogMessage; + auto old_writer = log_message_writer; + static std::string* log_buffer = new std::string(); + log_message_writer = [](const char* msg, int length) { + log_buffer->assign(msg, length); + }; - Log(kLog, "foo.cc", 100, "Hello"); - EXPECT_EQ("foo.cc:100] Hello", *log_buffer); + TC_LOG("Hello int=%d str=%s", 42, "bar"); + EXPECT_THAT(*log_buffer, + testing::MatchesRegex( + "[0-9]+ .*tcmalloc\\/internal/logging_test\\.cc:[0-9]+\\] " + "Hello int=42 str=bar\\n")); - Log(kLog, "foo.cc", 100, 123u, -456, 0); - EXPECT_EQ("foo.cc:100] 123 -456 0", *log_buffer); + TC_LOG("Long string: %s", long_string.c_str()); + EXPECT_THAT(*log_buffer, + testing::MatchesRegex( + "[0-9]+ .*tcmalloc\\/internal/logging_test\\.cc:[0-9]+\\] " + "Long string: the quick brown fox jumped over the lazy " + "dogthe quick brown fox jumped over the lazy dog.*")); - Log(kLog, "foo.cc", 100, 123u, std::numeric_limits::min()); - EXPECT_EQ("foo.cc:100] 123 -9223372036854775808", *log_buffer); + log_message_writer = old_writer; +} - Log(kLog, "foo.cc", 2, - reinterpret_cast(static_cast(1025))); - EXPECT_EQ("foo.cc:2] 0x401", *log_buffer); +TEST(Printer, RequiredSpace) { + constexpr absl::string_view kChunk = "0123456789"; + std::string expected; - Log(kLog, "foo.cc", 10, "hello", long_string.c_str()); - EXPECT_THAT(*log_buffer, - testing::StartsWith( - "foo.cc:10] hello the quick brown fox jumped over the lazy " - "dogthe quick brown fox jumped over the lazy dog")); + for (int i = 0; i < 10; i++) { + int length = kChunk.size() * i + 1; + std::unique_ptr buf(new char[length]); + Printer printer(buf.get(), length); - Log(kLogWithStack, "foo.cc", 10, "stk"); - EXPECT_TRUE(strstr(log_buffer->c_str(), "stk @ 0x") != nullptr) - << *log_buffer; + auto get_buf = [&]() { + return absl::string_view( + buf.get(), std::min(length - 1, printer.SpaceRequired())); + }; - log_message_writer = old_writer; - delete log_buffer; -} + for (int j = 0; j < i; j++) { + printer.printf("%s", kChunk); + } + EXPECT_EQ(get_buf(), expected); + EXPECT_EQ(length - 1, printer.SpaceRequired()); -TEST(InternalLogging, Assert) { - CHECK_CONDITION((2 + 2) == 4); + // Go past the end of the buffer. This should not overrun or affect the + // existing contents of buf, but we should see SpaceRequired tick up. + printer.printf("%s", kChunk); + EXPECT_EQ(get_buf(), expected); + EXPECT_EQ(length - 1 + kChunk.size(), printer.SpaceRequired()); - if (false) - CHECK_CONDITION(false); - else - CHECK_CONDITION(true); + printer.printf("%s", kChunk); + EXPECT_EQ(get_buf(), expected); + EXPECT_EQ(length - 1 + 2 * kChunk.size(), printer.SpaceRequired()); - ASSERT_DEATH(CHECK_CONDITION((2 + 2) == 5), - ".*tcmalloc\\/internal/logging_test\\.cc:[0-9]+\\] " - "\\(2 \\+ 2\\) == 5 @( 0x[0-9a-f]+)+"); + expected.append(kChunk); + } } -TEST(Printer, RequiredSpace) { - const char kChunk[] = "0123456789"; +TEST(Printer, RequiredSpacePieces) { + constexpr absl::string_view kChunk = "0123456789"; std::string expected; for (int i = 0; i < 10; i++) { - int length = strlen(kChunk) * i + 1; + int length = 2 * kChunk.size() * i + 1; std::unique_ptr buf(new char[length]); Printer printer(buf.get(), length); + auto get_buf = [&]() { + return absl::string_view( + buf.get(), std::min(length - 1, printer.SpaceRequired())); + }; + for (int j = 0; j < i; j++) { - printer.printf("%s", kChunk); + printer.Append(kChunk, kChunk); } - EXPECT_EQ(buf.get(), expected); + EXPECT_EQ(get_buf(), expected); EXPECT_EQ(length - 1, printer.SpaceRequired()); // Go past the end of the buffer. This should not overrun or affect the // existing contents of buf, but we should see SpaceRequired tick up. - printer.printf("%s", kChunk); - EXPECT_EQ(buf.get(), expected); - EXPECT_EQ(length - 1 + strlen(kChunk), printer.SpaceRequired()); + printer.Append(kChunk, kChunk); + EXPECT_EQ(get_buf(), expected); + EXPECT_EQ(length - 1 + 2 * kChunk.size(), printer.SpaceRequired()); + printer.Append(kChunk, kChunk); + EXPECT_EQ(get_buf(), expected); + EXPECT_EQ(length - 1 + 4 * kChunk.size(), printer.SpaceRequired()); + + expected.append(kChunk); expected.append(kChunk); } } +TEST(Check, OK) { + TC_CHECK(true); + TC_CHECK_EQ(1, 1); + TC_CHECK_NE(1, 2); + TC_CHECK_GT(2, 1); + TC_CHECK_GE(2, 1); + TC_CHECK_GE(2, 2); + TC_CHECK_LT(1, 2); + TC_CHECK_LE(-1, 1); + TC_CHECK_LE(2, 2); + + void* ptr1 = &ptr1; + void** ptr2 = &ptr1; + TC_CHECK_EQ(ptr1, ptr2); + TC_CHECK_NE(ptr1, nullptr); + + TC_ASSERT(true); + TC_ASSERT_EQ(1, 1); + TC_ASSERT_NE(1, 2); + TC_ASSERT_GT(2, 1); + TC_ASSERT_GE(2, 1); + TC_ASSERT_GE(2, 2); + TC_ASSERT_LT(1, 2); + TC_ASSERT_LE(-1, 1); + TC_ASSERT_LE(2, 2); + + ABSL_ATTRIBUTE_UNUSED int unused[] = { + (TC_CHECK(true), 1), + (TC_CHECK_EQ(1, 1), 2), + (TC_ASSERT(true), 3), + (TC_ASSERT_EQ(1, 1), 4), + }; +} + +TEST(Check, UnusedVars) { + int a = 1, b = 1; + TC_ASSERT_EQ(a, b); +} + +TEST(Check, DebugCheck) { + int eval1 = 0, eval2 = 0; + TC_CHECK_EQ([&]() { return ++eval1; }(), [&]() { return ++eval2; }()); + ASSERT_EQ(eval1, 1); + ASSERT_EQ(eval2, 1); +} + +TEST(Check, DebugAssert) { + int eval1 = 0, eval2 = 0; + TC_ASSERT_EQ([&]() { return ++eval1; }(), [&]() { return ++eval2; }(), + "val=%d", 1); +#ifdef NDEBUG + ASSERT_EQ(eval1, 0); + ASSERT_EQ(eval2, 0); +#else + ASSERT_EQ(eval1, 1); + ASSERT_EQ(eval2, 1); +#endif +} + +TEST(Check, Message) { + bool my_false = false; + EXPECT_DEATH(TC_CHECK(my_false, "ptr=%p foo=%d str=%s", &my_false, 42, "bar"), + "[0-9]+ .*tcmalloc\\/internal/logging_test\\.cc:[0-9]+\\] CHECK " + "in TestBody: my_false " + "\\(false\\) ptr=0x[0-9a-f]+ foo=42 str=bar"); + + int x = -1, y = 1; + EXPECT_DEATH(TC_CHECK_GE(x, y), + "[0-9]+ .*tcmalloc\\/internal/logging_test\\.cc:[0-9]+\\] CHECK " + "in TestBody: x >= y \\(-1 >= 1\\)"); + + int64_t a = -1, b = 1; + EXPECT_DEATH(TC_CHECK_EQ(a, b, "ptr=%p foo=%d str=%s", &my_false, 42, "bar"), + "[0-9]+ .*tcmalloc\\/internal/logging_test\\.cc:[0-9]+\\] CHECK " + "in TestBody: a == b \\(-1 " + "== 1\\) ptr=0x[0-9a-f]+ foo=42 str=bar"); + + enum class Something : unsigned { + kFoo = 1, + kBar = 2, + }; + auto bar = []() { return Something::kBar; }; + EXPECT_DEATH(TC_CHECK_EQ(bar(), Something::kFoo), + "bar\\(\\) == Something::kFoo \\(2 == 1\\)"); + + EXPECT_DEATH(TC_BUG("bad: foo=%d bar=%s", 42, "str"), + "[0-9]+ .*tcmalloc\\/internal/logging_test\\.cc:[0-9]+\\] CHECK " + "in TestBody: bad: foo=42 bar=str"); + + int s = 1; + // Ensure %s in the expression won't confuse the macro. + // clang-format off + EXPECT_DEATH(TC_CHECK_EQ(0%s, 1), "0%s == 1 \\(0 == 1\\)"); + TC_ASSERT_NE(0%s, 1); + // clang-format on + +#ifndef NDEBUG + EXPECT_DEATH(TC_ASSERT(false, "foo=%d", 42), "false \\(false\\) foo=42"); +#endif +} + +TEST(Check, DoubleEvaluation) { + int eval1 = 0, eval2 = 0; + auto f1 = [&]() { return ++eval1; }; + auto f2 = [&]() { return ++eval2; }; + EXPECT_DEATH(TC_CHECK_NE(f1(), f2()), + "CHECK in TestBody: f1\\(\\) != f2\\(\\) \\(1 != 1\\)"); +} + +TEST(Check, Optional) { + std::optional opt1(1); + std::optional opt2(2); + std::optional noopt; + TC_CHECK_EQ(opt1, opt1); + TC_CHECK_NE(opt1, opt2); + TC_CHECK_NE(opt1, noopt); + TC_CHECK_NE(noopt, 1); + EXPECT_DEATH(TC_CHECK_EQ(opt1, opt2), "opt1 == opt2 \\(1 == 2\\)"); + EXPECT_DEATH(TC_CHECK_EQ(opt1, noopt), "opt1 == noopt \\(1 == \\?\\?\\?\\)"); +} + } // namespace } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/memory_stats.cc b/contrib/libs/tcmalloc/tcmalloc/internal/memory_stats.cc index 71591834d411..c3b38f369341 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/memory_stats.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/memory_stats.cc @@ -19,9 +19,14 @@ #include #include +#include +#include + #include "absl/strings/numbers.h" +#include "absl/strings/string_view.h" #include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/page_size.h" #include "tcmalloc/internal/util.h" GOOGLE_MALLOC_SECTION_BEGIN @@ -49,21 +54,21 @@ bool GetMemoryStats(MemoryStats* stats) { FDCloser fd; fd.fd = signal_safe_open("/proc/self/statm", O_RDONLY | O_CLOEXEC); - ASSERT(fd.fd >= 0); + TC_ASSERT_GE(fd.fd, 0); if (fd.fd < 0) { return false; } char buf[1024]; ssize_t rc = signal_safe_read(fd.fd, buf, sizeof(buf), nullptr); - ASSERT(rc >= 0); - ASSERT(rc < sizeof(buf)); - if (rc < 0 || rc >= sizeof(buf)) { + TC_ASSERT_GE(rc, 0); + TC_ASSERT_LT(rc, static_cast(sizeof(buf))); + if (rc < 0 || rc >= static_cast(sizeof(buf))) { return false; } buf[rc] = '\0'; - const size_t pagesize = getpagesize(); + const size_t pagesize = GetPageSize(); absl::string_view contents(buf, rc); absl::string_view::size_type start = 0; int index = 0; diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/memory_stats.h b/contrib/libs/tcmalloc/tcmalloc/internal/memory_stats.h index a65f5b03d36d..133f73e9f02a 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/memory_stats.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/memory_stats.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/memory_stats_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/memory_stats_test.cc index 176c712734cb..51929879acd5 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/memory_stats_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/memory_stats_test.cc @@ -14,7 +14,8 @@ #include "tcmalloc/internal/memory_stats.h" -#include +#include +#include #include "gtest/gtest.h" diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/memory_tag.cc b/contrib/libs/tcmalloc/tcmalloc/internal/memory_tag.cc new file mode 100644 index 000000000000..30d873ba5db3 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/memory_tag.cc @@ -0,0 +1,44 @@ +// Copyright 2024 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/memory_tag.h" + +#include "absl/strings/string_view.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/optimization.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc::tcmalloc_internal { + +absl::string_view MemoryTagToLabel(MemoryTag tag) { + switch (tag) { + case MemoryTag::kNormal: + return "NORMAL"; + case MemoryTag::kNormalP1: + return "NORMAL_P1"; + case MemoryTag::kSampled: + return "SAMPLED"; + case MemoryTag::kSelSan: + return "SELSAN"; + case MemoryTag::kCold: + return "COLD"; + case MemoryTag::kMetadata: + return "METADATA"; + } + + ASSUME(false); +} + +} // namespace tcmalloc::tcmalloc_internal +GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/memory_tag.h b/contrib/libs/tcmalloc/tcmalloc/internal/memory_tag.h new file mode 100644 index 000000000000..d8d04f200313 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/memory_tag.h @@ -0,0 +1,90 @@ +#pragma clang system_header +// Copyright 2024 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_INTERNAL_MEMORY_TAG_H_ +#define TCMALLOC_INTERNAL_MEMORY_TAG_H_ + +#include +#include + +#include "absl/strings/string_view.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc::tcmalloc_internal { + +enum class MemoryTag : uint8_t { + // Sampled, infrequently allocated + kSampled = 0x0, + // Normal memory, NUMA partition 0 + kNormalP0 = kSanitizerAddressSpace ? 0x1 : 0x4, + // Normal memory, NUMA partition 1 + kNormalP1 = kSanitizerAddressSpace ? 0xff : 0x6, + // Normal memory + kNormal = kNormalP0, + // Cold + kCold = 0x2, + // Metadata + kMetadata = 0x3, + // SelSan sampled spans, kept separately because we need to quickly + // distinguish them from the rest during delete and they also consume + // shadow memory. 0xfe is an arbitrary value that shouldn't be used. + kSelSan = kSelSanPresent ? 0x1 : 0xfe, +}; + +inline constexpr uintptr_t kTagShift = std::min(kAddressBits - 4, 42); +inline constexpr uintptr_t kTagMask = + uintptr_t{kSanitizerAddressSpace ? 0x3 : 0x7} << kTagShift; + +inline MemoryTag GetMemoryTag(const void* ptr) { + return static_cast((reinterpret_cast(ptr) & kTagMask) >> + kTagShift); +} + +inline bool IsNormalMemory(const void* ptr) { + // This is slightly faster than checking kNormalP0/P1 separetly. + static_assert((static_cast(MemoryTag::kNormalP0) & + (static_cast(MemoryTag::kSampled) | + static_cast(MemoryTag::kCold))) == 0); + bool res = (static_cast(GetMemoryTag(ptr)) & + static_cast(MemoryTag::kNormal)) != 0; + TC_ASSERT(res == (GetMemoryTag(ptr) == MemoryTag::kNormalP0 || + GetMemoryTag(ptr) == MemoryTag::kNormalP1), + "ptr=%p res=%d tag=%d", ptr, res, + static_cast(GetMemoryTag(ptr))); + return res; +} + +inline bool IsSelSanMemory(const void* ptr) { + // This is a faster way to check for SelSan memory provided we already know + // it's not a normal memory, and assuming it's not kMetadata (both assumptions + // are checked by the assert below). A straightforward comparison with kSelSan + // leads to extraction/check of 2 bits (these use 2 8-byte immediates); + // this check can be done with a single BT instruction. + // kSelSanPresent part allows to optimize away branches in non SelSan build. + bool res = + kSelSanPresent && (static_cast(GetMemoryTag(ptr)) & + static_cast(MemoryTag::kSelSan)) != 0; + TC_ASSERT_EQ(res, GetMemoryTag(ptr) == MemoryTag::kSelSan); + return res; +} + +absl::string_view MemoryTagToLabel(MemoryTag tag); + +} // namespace tcmalloc::tcmalloc_internal +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_MEMORY_TAG_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/mincore.cc b/contrib/libs/tcmalloc/tcmalloc/internal/mincore.cc index e4120bcf5ae5..b4443312d6e4 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/mincore.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/mincore.cc @@ -18,9 +18,11 @@ #include #include +#include #include #include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/page_size.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { @@ -44,7 +46,7 @@ size_t MInCore::residence_impl(void* addr, size_t size, return 0; } unsigned char res[kArrayLength]; - const size_t kPageSize = getpagesize(); + const size_t kPageSize = GetPageSize(); uintptr_t uaddr = reinterpret_cast(addr); // Round address down to get the start of the page containing the data. @@ -61,7 +63,10 @@ size_t MInCore::residence_impl(void* addr, size_t size, // then handle the case where the object spans more than one page. if (remainingPages == kPageSize) { // Find out whether the first page is resident. - mincore->mincore(reinterpret_cast(basePage), remainingPages, res); + if (mincore->mincore(reinterpret_cast(basePage), remainingPages, + res) != 0) { + return 0; + } // Residence info is returned in LSB, other bits are undefined. if ((res[0] & 1) == 1) { return size; diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/mincore.h b/contrib/libs/tcmalloc/tcmalloc/internal/mincore.h index c353bdac8708..45a74fd8263f 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/mincore.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/mincore.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/mincore_benchmark.cc b/contrib/libs/tcmalloc/tcmalloc/internal/mincore_benchmark.cc index 02c8ead48d0c..13b8c8029685 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/mincore_benchmark.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/mincore_benchmark.cc @@ -16,14 +16,14 @@ #include #include +#include #include #include -#include -#include "absl/memory/memory.h" #include "benchmark/benchmark.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" -#include "tcmalloc/internal/mincore.h" +#include "tcmalloc/internal/page_size.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { @@ -38,10 +38,10 @@ void BM_mincore(benchmark::State& state) { // If we want to place the array on the stack then the maximum frame size is // 16KiB. So there is no point in benchmarking sizes larger than this. const int kMaxArraySize = 16 * 1024; - CHECK_CONDITION(size <= kMaxArraySize); - auto resident = absl::make_unique(kMaxArraySize); + TC_CHECK_LE(size, kMaxArraySize); + auto resident = std::make_unique(kMaxArraySize); - const size_t kPageSize = getpagesize(); + const size_t kPageSize = tcmalloc_internal::GetPageSize(); // We want to scan the same amount of memory in all cases const size_t regionSize = 1 * 1024 * 1024 * 1024; for (auto s : state) { diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/mincore_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/mincore_test.cc index daa1178b2563..1f1f9b769e34 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/mincore_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/mincore_test.cc @@ -14,18 +14,18 @@ #include "tcmalloc/internal/mincore.h" +#include +#include +#include #include -#include -#include #include -#include #include +#include "benchmark/benchmark.h" #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "benchmark/benchmark.h" -#include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/page_size.h" namespace tcmalloc { namespace tcmalloc_internal { @@ -41,7 +41,7 @@ class MInCoreMock : public MInCoreInterface { // Implementation of minCore that reports presence based on provided array. int mincore(void* addr, size_t length, unsigned char* result) override { - const size_t kPageSize = getpagesize(); + const size_t kPageSize = GetPageSize(); uintptr_t uAddress = reinterpret_cast(addr); // Check that we only pass page aligned addresses into mincore(). EXPECT_THAT(uAddress & (kPageSize - 1), Eq(0)); @@ -87,9 +87,9 @@ namespace { using ::testing::Eq; -TEST(StaticVarsTest, TestResidence) { +TEST(MInCoreTest, TestResidence) { MInCoreTest mct; - const size_t kPageSize = getpagesize(); + const size_t kPageSize = GetPageSize(); // Set up a pattern with a few resident pages. // page 0 not mapped @@ -141,10 +141,10 @@ TEST(StaticVarsTest, TestResidence) { } // Test whether we are correctly handling multiple calls to mincore. -TEST(StaticVarsTest, TestLargeResidence) { +TEST(MInCoreTest, TestLargeResidence) { MInCoreTest mct; uintptr_t uAddress = 0; - const size_t kPageSize = getpagesize(); + const size_t kPageSize = GetPageSize(); // Set up a pattern covering 6 * page size * MInCore::kArrayLength to // allow us to test for situations where the region we're checking // requires multiple calls to mincore(). @@ -164,8 +164,8 @@ TEST(StaticVarsTest, TestLargeResidence) { } } -TEST(StaticVarsTest, UnmappedMemory) { - const size_t kPageSize = getpagesize(); +TEST(MInCoreTest, UnmappedMemory) { + const size_t kPageSize = GetPageSize(); const int kNumPages = 16; // Overallocate kNumPages of memory, so we can munmap the page before and @@ -181,10 +181,18 @@ TEST(StaticVarsTest, UnmappedMemory) { memset(q, 0, kNumPages * kPageSize); ::benchmark::DoNotOptimize(q); + EXPECT_EQ(0, MInCore::residence(nullptr, kPageSize)); + EXPECT_EQ(0, MInCore::residence(p, kPageSize)); for (int i = 0; i <= kNumPages; i++) { EXPECT_EQ(i * kPageSize, MInCore::residence(q, i * kPageSize)); } + // Note we can only query regions that are entirely mapped, but we should also + // test the edge case of incomplete pages. + EXPECT_EQ((kNumPages - 1) * kPageSize, + MInCore::residence(reinterpret_cast(q) + 7, + (kNumPages - 1) * kPageSize)); + ASSERT_EQ(munmap(q, kNumPages * kPageSize), 0); } diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/mismatched_delete_state.h b/contrib/libs/tcmalloc/tcmalloc/internal/mismatched_delete_state.h new file mode 100644 index 000000000000..3b7403e39b46 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/mismatched_delete_state.h @@ -0,0 +1,122 @@ +#pragma clang system_header +// Copyright 2024 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_INTERNAL_MISMATCHED_DELETE_STATE_H_ +#define TCMALLOC_INTERNAL_MISMATCHED_DELETE_STATE_H_ + +#include +#include +#include +#include + +#include "absl/types/span.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +class MismatchedDeleteState { + public: + constexpr MismatchedDeleteState() = default; + + bool triggered() const { return triggered_; } + + std::optional> AllocationStack() const { + TC_ASSERT(triggered_); + + if (!allocation_stack_depth_.has_value()) { + return std::nullopt; + } + + return absl::MakeSpan(allocation_stack_, *allocation_stack_depth_); + } + + std::optional> DeallocationStack() const { + TC_ASSERT(triggered_); + if (!deallocation_stack_depth_.has_value()) { + return std::nullopt; + } + + return absl::MakeSpan(deallocation_stack_, *deallocation_stack_depth_); + } + + size_t provided_min() const { + TC_ASSERT(triggered_); + return provided_min_; + } + size_t provided_max() const { + TC_ASSERT(triggered_); + return provided_max_; + } + + size_t minimum_size() const { + TC_ASSERT(triggered_); + return minimum_; + } + + size_t maximum_size() const { + TC_ASSERT(triggered_); + return maximum_; + } + + void Record(size_t provided_min, size_t provided_max, size_t minimum, + size_t maximum, + std::optional> allocation_stack, + std::optional> deallocation_stack) { + triggered_ = true; + + provided_min_ = provided_min; + provided_max_ = provided_max; + minimum_ = minimum; + maximum_ = maximum; + + if (allocation_stack.has_value()) { + size_t allocation_stack_depth = + std::min(kMaxStackDepth, allocation_stack->size()); + memcpy(allocation_stack_, allocation_stack->data(), + sizeof(void*) * allocation_stack_depth); + allocation_stack_depth_ = allocation_stack_depth; + } else { + allocation_stack_depth_ = std::nullopt; + } + + if (deallocation_stack.has_value()) { + size_t deallocation_stack_depth = + std::min(kMaxStackDepth, deallocation_stack->size()); + memcpy(deallocation_stack_, deallocation_stack->data(), + sizeof(void*) * deallocation_stack_depth); + deallocation_stack_depth_ = deallocation_stack_depth; + } else { + deallocation_stack_depth_ = std::nullopt; + } + } + + private: + bool triggered_ = false; + size_t provided_min_ = 0, provided_max_ = 0, minimum_ = 0, maximum_ = 0; + + void* allocation_stack_[kMaxStackDepth] = {}; + std::optional allocation_stack_depth_ = std::nullopt; + void* deallocation_stack_[kMaxStackDepth] = {}; + std::optional deallocation_stack_depth_ = std::nullopt; +}; + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_MISMATCHED_DELETE_STATE_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/mock_span.h b/contrib/libs/tcmalloc/tcmalloc/internal/mock_span.h index 10922c48bdba..a43ecef55175 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/mock_span.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/mock_span.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/numa.cc b/contrib/libs/tcmalloc/tcmalloc/internal/numa.cc index 1639bd1b6d89..6e65e125155d 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/numa.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/numa.cc @@ -16,24 +16,23 @@ #include #include -#include #include #include #include #include #include -#include #include +#include #include "absl/base/attributes.h" -#include "absl/base/internal/sysinfo.h" #include "absl/functional/function_ref.h" -#include "absl/strings/numbers.h" -#include "absl/strings/string_view.h" #include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/cpu_utils.h" #include "tcmalloc/internal/environment.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/percpu.h" +#include "tcmalloc/internal/sysinfo.h" #include "tcmalloc/internal/util.h" GOOGLE_MALLOC_SECTION_BEGIN @@ -52,62 +51,9 @@ int OpenSysfsCpulist(size_t node) { return signal_safe_open(path, O_RDONLY | O_CLOEXEC); } -cpu_set_t ParseCpulist(absl::FunctionRef read) { - cpu_set_t set; - CPU_ZERO(&set); - - std::array buf; - size_t carry_over = 0; - int cpu_from = -1; - - while (true) { - const ssize_t rc = read(buf.data() + carry_over, buf.size() - carry_over); - CHECK_CONDITION(rc >= 0); - - const absl::string_view current(buf.data(), carry_over + rc); - - // If we have no more data to parse & couldn't read any then we've reached - // the end of the input & are done. - if (current.empty() && rc == 0) { - break; - } - - size_t consumed; - const size_t dash = current.find('-'); - const size_t comma = current.find(','); - if (dash != absl::string_view::npos && dash < comma) { - CHECK_CONDITION(absl::SimpleAtoi(current.substr(0, dash), &cpu_from)); - consumed = dash + 1; - } else if (comma != absl::string_view::npos || rc == 0) { - int cpu; - CHECK_CONDITION(absl::SimpleAtoi(current.substr(0, comma), &cpu)); - if (comma == absl::string_view::npos) { - consumed = current.size(); - } else { - consumed = comma + 1; - } - if (cpu_from != -1) { - for (int c = cpu_from; c <= cpu; c++) { - CPU_SET(c, &set); - } - cpu_from = -1; - } else { - CPU_SET(cpu, &set); - } - } else { - consumed = 0; - } - - carry_over = current.size() - consumed; - memmove(buf.data(), buf.data() + consumed, carry_over); - } - - return set; -} - -bool InitNumaTopology(size_t cpu_to_scaled_partition[CPU_SETSIZE], - uint64_t *const partition_to_nodes, - NumaBindMode *const bind_mode, +bool InitNumaTopology(size_t cpu_to_scaled_partition[kMaxCpus], + uint64_t* const partition_to_nodes, + NumaBindMode* const bind_mode, const size_t num_partitions, const size_t scale_by, absl::FunctionRef open_node_cpulist) { // Node 0 will always map to partition 0; record it here in case the system @@ -115,10 +61,6 @@ bool InitNumaTopology(size_t cpu_to_scaled_partition[CPU_SETSIZE], // either case we'll record nothing in the loop below. partition_to_nodes[NodeToPartition(0, num_partitions)] |= 1 << 0; - // If we only compiled in support for one partition then we're trivially - // done; NUMA awareness is unavailable. - if (num_partitions == 1) return false; - // We rely on rseq to quickly obtain a CPU ID & lookup the appropriate // partition in NumaTopology::GetCurrentPartition(). If rseq is unavailable, // disable NUMA awareness. @@ -133,11 +75,14 @@ bool InitNumaTopology(size_t cpu_to_scaled_partition[CPU_SETSIZE], // cpu_to_scaled_partition & partition_to_nodes arrays are zero initialized // we're trivially done - CPUs all map to partition 0, which contains only // CPU 0 added above. - const char *e = + const char* e = tcmalloc::tcmalloc_internal::thread_safe_getenv("TCMALLOC_NUMA_AWARE"); + bool enabled = true; if (e == nullptr) { // Enable NUMA awareness iff default_want_numa_aware(). - if (!default_want_numa_aware()) return false; + if (!default_want_numa_aware()) { + enabled = false; + } } else if (!strcmp(e, "no-binding")) { // Enable NUMA awareness with no memory binding behavior. *bind_mode = NumaBindMode::kNone; @@ -149,18 +94,18 @@ bool InitNumaTopology(size_t cpu_to_scaled_partition[CPU_SETSIZE], *bind_mode = NumaBindMode::kStrict; } else if (!strcmp(e, "0")) { // Disable NUMA awareness. - return false; + enabled = false; } else { - Crash(kCrash, __FILE__, __LINE__, "bad TCMALLOC_NUMA_AWARE env var", e); + TC_BUG("bad TCMALLOC_NUMA_AWARE env var '%s'", e); } // The cpu_to_scaled_partition array has a fixed size so that we can // statically allocate it & avoid the need to check whether it has been - // allocated prior to lookups. It has CPU_SETSIZE entries which ought to be + // allocated prior to lookups. It has kMaxCpus entries which ought to be // sufficient, but sanity check that indexing it by CPU number shouldn't // exceed its bounds. - int num_cpus = absl::base_internal::NumCPUs(); - CHECK_CONDITION(num_cpus <= CPU_SETSIZE); + int num_cpus = NumCPUs(); + TC_CHECK_LE(num_cpus, kMaxCpus); // We could just always report that we're NUMA aware, but if a NUMA-aware // binary runs on a system that doesn't include multiple NUMA nodes then our @@ -175,7 +120,7 @@ bool InitNumaTopology(size_t cpu_to_scaled_partition[CPU_SETSIZE], if (fd == -1) { // We expect to encounter ENOENT once node surpasses the actual number of // nodes present in the system. Any other error is a problem. - CHECK_CONDITION(errno == ENOENT); + TC_CHECK_EQ(errno, ENOENT); break; } @@ -191,28 +136,32 @@ bool InitNumaTopology(size_t cpu_to_scaled_partition[CPU_SETSIZE], } // Parse the cpulist file to determine which CPUs are local to this node. - const cpu_set_t node_cpus = - ParseCpulist([&](char *const buf, const size_t count) { + const std::optional node_cpus = + ParseCpulist([&](char* const buf, const size_t count) { return signal_safe_read(fd, buf, count, /*bytes_read=*/nullptr); }); + // We are on the same side of an airtight hatchway as the kernel, but we + // want to know if we can no longer parse the values the kernel is + // providing. + TC_CHECK(node_cpus.has_value()); // Assign local CPUs to the appropriate partition. - for (size_t cpu = 0; cpu < CPU_SETSIZE; cpu++) { - if (CPU_ISSET(cpu, &node_cpus)) { + for (size_t cpu = 0; cpu < kMaxCpus; cpu++) { + if (node_cpus->IsSet(cpu)) { cpu_to_scaled_partition[cpu + kNumaCpuFudge] = partition * scale_by; } } // If we observed any CPUs for this node then we've now got CPUs assigned // to a non-zero partition; report that we're NUMA aware. - if (CPU_COUNT(&node_cpus) != 0) { + if (node_cpus->Count() != 0) { numa_aware = true; } signal_safe_close(fd); } - return numa_aware; + return enabled && numa_aware; } } // namespace tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/numa.h b/contrib/libs/tcmalloc/tcmalloc/internal/numa.h index bf04c65c21b7..3a4151624982 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/numa.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/numa.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2021 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,8 +20,13 @@ #include #include +#include +#include +#include + #include "absl/functional/function_ref.h" #include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/cpu_utils.h" #include "tcmalloc/internal/percpu.h" GOOGLE_MALLOC_SECTION_BEGIN @@ -45,8 +51,8 @@ enum class NumaBindMode { kStrict, }; -// We use the result of RseqCpuId() in GetCurrentPartition() to avoid branching -// in the fast path, but this means that the CPU number we look up in +// We use the result of GetRealCpuUnsafe() in GetCurrentPartition() to avoid +// branching in the fast path, but this means that the CPU number we look up in // cpu_to_scaled_partition_ might equal kCpuIdUninitialized or // kCpuIdUnsupported. We add this fudge factor to the value to compensate, // ensuring that our accesses to the cpu_to_scaled_partition_ array are always @@ -69,7 +75,14 @@ static constexpr size_t kNumaCpuFudge = -subtle::percpu::kCpuIdUnsupported; // may incur a performance hit, but allows us to at least run on any system. template class NumaTopology { + // To give ourselves non-trivial data even when NUMA support is compiled out + // of the allocation path, we enable >1 partition. + static constexpr size_t kNumInternalPartitions = + std::max(2, NumPartitions); + public: + static constexpr size_t kNumPartitions = NumPartitions; + // Trivially zero initialize data members. constexpr NumaTopology() = default; @@ -94,7 +107,9 @@ class NumaTopology { // partitions that other parts of TCMalloc need to concern themselves with. // Checking this rather than using kNumaPartitions allows users to avoid work // on non-zero partitions when NUMA awareness is disabled. - size_t active_partitions() const { return numa_aware() ? NumPartitions : 1; } + size_t active_partitions() const { + return numa_aware() ? kNumInternalPartitions : 1; + } // Return a value indicating how we should behave with regards to binding // memory regions to NUMA nodes. @@ -110,7 +125,9 @@ class NumaTopology { // ScaleBy. size_t GetCurrentScaledPartition() const; - // Return the NUMA partition number to which `cpu` belongs. + // Return the NUMA partition number to which `cpu` belongs. This partition + // number may exceed NumPartitions as part of providing an unconditional NUMA + // partition. // // It is valid for cpu to equal subtle::percpu::kCpuIdUninitialized or // subtle::percpu::kCpuIdUnsupported. In either case partition 0 will be @@ -126,32 +143,39 @@ class NumaTopology { uint64_t GetPartitionNodes(int partition) const; private: - // Maps from CPU number (plus kNumaCpuFudge) to NUMA partition. - size_t cpu_to_scaled_partition_[CPU_SETSIZE + kNumaCpuFudge] = {0}; // Maps from NUMA partition to a bitmap of NUMA nodes within the partition. - uint64_t partition_to_nodes_[NumPartitions] = {0}; + uint64_t partition_to_nodes_[kNumInternalPartitions] = {0}; // Indicates whether NUMA awareness is available & enabled. bool numa_aware_ = false; // Desired memory binding behavior. NumaBindMode bind_mode_ = NumaBindMode::kAdvisory; + + // We maintain two sets of CPU-to-partition information. One is + // unconditionally available in cpu_to_scaled_partition_. + // + // The other is used by GetCurrent...Partition methods, which are used on the + // allocation fastpath. + // * If NUMA support is not compiled in, these methods short-circuit and + // return '0'. + // * If NUMA support is not enabled at runtime, gated_cpu_to_scaled_partition_ + // is left zero initialized. + + static constexpr size_t kCpuMapSize = kMaxCpus + kNumaCpuFudge; + std::array cpu_to_scaled_partition_ = {}; + // Maps from CPU number (plus kNumaCpuFudge) to NUMA partition. + // If NUMA awareness is not enabled, allocate array of 0 size to not waste + // space, we shouldn't access it. Place it as the last member, so that ASan + // warns about any unintentional accesses. This is checked by the + // static_assert in Init. + static constexpr size_t kGatedCpuMapSize = + NumPartitions > 1 ? kMaxCpus + kNumaCpuFudge : 0; + std::array gated_cpu_to_scaled_partition_ = {}; }; // Opens a /sys/devices/system/node/nodeX/cpulist file for read only access & // returns the file descriptor. int OpenSysfsCpulist(size_t node); -// Parse a CPU list in the format used by -// /sys/devices/system/node/nodeX/cpulist files - that is, individual CPU -// numbers or ranges in the format - inclusive all joined by comma -// characters. -// -// The read function is expected to operate much like the read syscall. It -// should read up to `count` bytes into `buf` and return the number of bytes -// actually read. If an error occurs during reading it should return -1 with -// errno set to an appropriate error code. -cpu_set_t ParseCpulist( - absl::FunctionRef read); - // Initialize the data members of a NumaTopology<> instance. // // This function must only be called once per NumaTopology<> instance, and @@ -162,8 +186,8 @@ cpu_set_t ParseCpulist( // // Returns true if we're actually NUMA aware; i.e. if we have CPUs mapped to // multiple partitions. -bool InitNumaTopology(size_t cpu_to_scaled_partition[CPU_SETSIZE], - uint64_t *partition_to_nodes, NumaBindMode *bind_mode, +bool InitNumaTopology(size_t cpu_to_scaled_partition[kMaxCpus], + uint64_t* partition_to_nodes, NumaBindMode* bind_mode, size_t num_partitions, size_t scale_by, absl::FunctionRef open_node_cpulist); @@ -174,31 +198,48 @@ inline size_t NodeToPartition(const size_t node, const size_t num_partitions) { template inline void NumaTopology::Init() { - numa_aware_ = - InitNumaTopology(cpu_to_scaled_partition_, partition_to_nodes_, - &bind_mode_, NumPartitions, ScaleBy, OpenSysfsCpulist); + static_assert(offsetof(NumaTopology, gated_cpu_to_scaled_partition_) + + sizeof(gated_cpu_to_scaled_partition_) + + sizeof(*gated_cpu_to_scaled_partition_.data()) >= + sizeof(NumaTopology), + "cpu_to_scaled_partition_ is not the last field"); + numa_aware_ = InitNumaTopology( + cpu_to_scaled_partition_.data(), partition_to_nodes_, &bind_mode_, + kNumInternalPartitions, ScaleBy, OpenSysfsCpulist); + if constexpr (NumPartitions > 1) { + if (numa_aware_) { + gated_cpu_to_scaled_partition_ = cpu_to_scaled_partition_; + } + } } template inline void NumaTopology::InitForTest( absl::FunctionRef open_node_cpulist) { - numa_aware_ = - InitNumaTopology(cpu_to_scaled_partition_, partition_to_nodes_, - &bind_mode_, NumPartitions, ScaleBy, open_node_cpulist); + numa_aware_ = InitNumaTopology( + cpu_to_scaled_partition_.data(), partition_to_nodes_, &bind_mode_, + kNumInternalPartitions, ScaleBy, open_node_cpulist); + if constexpr (NumPartitions > 1) { + if (numa_aware_) { + gated_cpu_to_scaled_partition_ = cpu_to_scaled_partition_; + } + } } template inline size_t NumaTopology::GetCurrentPartition() const { if constexpr (NumPartitions == 1) return 0; - return GetCpuPartition(subtle::percpu::RseqCpuId()); + const int cpu = subtle::percpu::GetRealCpuUnsafe(); + return gated_cpu_to_scaled_partition_[cpu + kNumaCpuFudge] / ScaleBy; } template inline size_t NumaTopology::GetCurrentScaledPartition() const { if constexpr (NumPartitions == 1) return 0; - return GetCpuScaledPartition(subtle::percpu::RseqCpuId()); + const int cpu = subtle::percpu::GetRealCpuUnsafe(); + return gated_cpu_to_scaled_partition_[cpu + kNumaCpuFudge]; } template @@ -210,7 +251,6 @@ inline size_t NumaTopology::GetCpuPartition( template inline size_t NumaTopology::GetCpuScaledPartition( const int cpu) const { - if constexpr (NumPartitions == 1) return 0; return cpu_to_scaled_partition_[cpu + kNumaCpuFudge]; } diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/numa_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/numa_test.cc index bbd86a3f7dee..5a0ee339211e 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/numa_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/numa_test.cc @@ -29,19 +29,23 @@ #include #include +#include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/random/random.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_join.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" #include "absl/types/span.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/percpu.h" +#include "tcmalloc/internal/sysinfo.h" namespace tcmalloc { namespace tcmalloc_internal { namespace { -int memfd_create(const char *name, unsigned int flags) { +int memfd_create(const char* name, unsigned int flags) { #ifdef __NR_memfd_create return syscall(__NR_memfd_create, name, flags); #else @@ -55,25 +59,24 @@ class SyntheticCpuList { public: explicit SyntheticCpuList(const absl::string_view content) { fd_ = memfd_create("cpulist", MFD_CLOEXEC); - CHECK_CONDITION(fd_ != -1); + TC_CHECK_NE(fd_, -1); - CHECK_CONDITION(write(fd_, content.data(), content.size()) == - content.size()); - CHECK_CONDITION(write(fd_, "\n", 1) == 1); - CHECK_CONDITION(lseek(fd_, 0, SEEK_SET) == 0); + TC_CHECK_EQ(write(fd_, content.data(), content.size()), content.size()); + TC_CHECK_EQ(write(fd_, "\n", 1), 1); + TC_CHECK_EQ(lseek(fd_, 0, SEEK_SET), 0); } ~SyntheticCpuList() { close(fd_); } // Disallow copies, which would make require reference counting to know when // we should close fd_. - SyntheticCpuList(const SyntheticCpuList &) = delete; - SyntheticCpuList &operator=(const SyntheticCpuList &) = delete; + SyntheticCpuList(const SyntheticCpuList&) = delete; + SyntheticCpuList& operator=(const SyntheticCpuList&) = delete; // Moves are fine - only one instance at a time holds the fd. - SyntheticCpuList(SyntheticCpuList &&other) + SyntheticCpuList(SyntheticCpuList&& other) : fd_(std::exchange(other.fd_, -1)) {} - SyntheticCpuList &operator=(SyntheticCpuList &&other) { + SyntheticCpuList& operator=(SyntheticCpuList&& other) { new (this) SyntheticCpuList(std::move(other)); return *this; } @@ -104,10 +107,10 @@ class NumaTopologyTest : public ::testing::Test { } }; -template -NumaTopology CreateNumaTopology( +template +NumaTopology CreateNumaTopology( const absl::Span cpu_lists) { - NumaTopology nt; + NumaTopology nt; nt.InitForTest([&](const size_t node) { if (node >= cpu_lists.size()) { errno = ENOENT; @@ -129,6 +132,7 @@ TEST_F(NumaTopologyTest, NoCompileTimeNuma) { EXPECT_EQ(nt.numa_aware(), false); EXPECT_EQ(nt.active_partitions(), 1); + EXPECT_EQ(nt.GetCurrentPartition(), 0); } // Ensure that if we run on a system with no NUMA support at all (i.e. no @@ -139,6 +143,7 @@ TEST_F(NumaTopologyTest, NoRunTimeNuma) { EXPECT_EQ(nt.numa_aware(), false); EXPECT_EQ(nt.active_partitions(), 1); + EXPECT_EQ(nt.GetCurrentPartition(), 0); } // Ensure that if we run on a system with only 1 node then we disable NUMA @@ -172,6 +177,26 @@ TEST_F(NumaTopologyTest, TwoNode) { } } +// Confirm that an empty node parses correctly (b/212827142). +TEST_F(NumaTopologyTest, EmptyNode) { + std::vector nodes; + nodes.emplace_back("0-5"); + nodes.emplace_back(""); + nodes.emplace_back("6-11"); + + const auto nt = CreateNumaTopology<3>(nodes); + + EXPECT_EQ(nt.numa_aware(), true); + EXPECT_EQ(nt.active_partitions(), 3); + + for (int cpu = 0; cpu <= 5; cpu++) { + EXPECT_EQ(nt.GetCpuPartition(cpu), 0); + } + for (int cpu = 6; cpu <= 11; cpu++) { + EXPECT_EQ(nt.GetCpuPartition(cpu), 2); + } +} + // Test that cpulists too long to fit into the 16 byte buffer used by // InitNumaTopology() parse successfully. TEST_F(NumaTopologyTest, LongCpuLists) { @@ -214,68 +239,13 @@ TEST_F(NumaTopologyTest, Host) { NumaTopology<4> nt; nt.Init(); + const size_t active_partitions = nt.active_partitions(); + // We don't actually know anything about the host, so there's not much more // we can do beyond checking that we didn't crash. -} - -// Ensure that we can parse randomized cpulists correctly. -TEST(ParseCpulistTest, Random) { - absl::BitGen gen; - - static constexpr int kIterations = 100; - for (int i = 0; i < kIterations; i++) { - cpu_set_t reference; - CPU_ZERO(&reference); - - // Set a random number of CPUs within the reference set. - const double density = absl::Uniform(gen, 0.0, 1.0); - for (int cpu = 0; cpu < CPU_SETSIZE; cpu++) { - if (absl::Bernoulli(gen, density)) { - CPU_SET(cpu, &reference); - } - } - - // Serialize the reference set into a cpulist-style string. - std::vector components; - for (int cpu = 0; cpu < CPU_SETSIZE; cpu++) { - if (!CPU_ISSET(cpu, &reference)) continue; - - const int start = cpu; - int next = cpu + 1; - while (next < CPU_SETSIZE && CPU_ISSET(next, &reference)) { - cpu = next; - next = cpu + 1; - } - - if (cpu == start) { - components.push_back(absl::StrCat(cpu)); - } else { - components.push_back(absl::StrCat(start, "-", cpu)); - } - } - const std::string serialized = absl::StrJoin(components, ","); - - // Now parse that string using our ParseCpulist function, randomizing the - // amount of data we provide to it from each read. - absl::string_view remaining(serialized); - const cpu_set_t parsed = - ParseCpulist([&](char *const buf, const size_t count) -> ssize_t { - // Calculate how much data we have left to provide. - const size_t max = std::min(count, remaining.size()); - - // If none, we have no choice but to provide nothing. - if (max == 0) return 0; - - // If we do have data, return a randomly sized subset of it to stress - // the logic around reading partial values. - const size_t copy = absl::Uniform(gen, static_cast(1), max); - memcpy(buf, remaining.data(), copy); - remaining.remove_prefix(copy); - return copy; - }); - - // We ought to have parsed the same set of CPUs that we serialized. - EXPECT_TRUE(CPU_EQUAL(&parsed, &reference)); + for (int cpu = 0, n = NumCPUs(); cpu < n; ++cpu) { + size_t partition = nt.GetCpuPartition(cpu); + EXPECT_LT(partition, active_partitions) << cpu; } } diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/optimization.h b/contrib/libs/tcmalloc/tcmalloc/internal/optimization.h index 6380183a5004..edede9a81468 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/optimization.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/optimization.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2020 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,16 +16,22 @@ #ifndef TCMALLOC_INTERNAL_OPTIMIZATION_H_ #define TCMALLOC_INTERNAL_OPTIMIZATION_H_ +#include "absl/base/attributes.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + // Our wrapper for __builtin_assume, allowing us to check the assumption on // debug builds. #ifndef NDEBUG #ifdef __clang__ -#define ASSUME(cond) CHECK_CONDITION(cond), __builtin_assume(cond) +#define ASSUME(cond) TC_CHECK(cond), __builtin_assume(cond) #else #define ASSUME(cond) \ - CHECK_CONDITION(cond), (!(cond) ? __builtin_unreachable() : (void)0) + TC_CHECK(cond), (!(cond) ? __builtin_unreachable() : (void)0) #endif #else #ifdef __clang__ @@ -42,4 +49,21 @@ #define TCMALLOC_ATTRIBUTE_CONST #endif +// Can be applied to a return statement to tell the compiler to generate +// a tail call. +#if ABSL_HAVE_CPP_ATTRIBUTE(clang::musttail) +#define TCMALLOC_MUSTTAIL [[clang::musttail]] +#else +#define TCMALLOC_MUSTTAIL +#endif + +inline void* AssumeNotNull(void* p) { + ASSUME(p != nullptr); + return p; +} + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + #endif // TCMALLOC_INTERNAL_OPTIMIZATION_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/noruntime_size_classes.cc b/contrib/libs/tcmalloc/tcmalloc/internal/overflow.h similarity index 58% rename from contrib/libs/tcmalloc/tcmalloc/noruntime_size_classes.cc rename to contrib/libs/tcmalloc/tcmalloc/internal/overflow.h index c6dc90adcc94..970a88a501bc 100644 --- a/contrib/libs/tcmalloc/tcmalloc/noruntime_size_classes.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/overflow.h @@ -1,4 +1,5 @@ -// Copyright 2019 The TCMalloc Authors +#pragma clang system_header +// Copyright 2022 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,22 +13,29 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "absl/base/attributes.h" -#include "tcmalloc/runtime_size_classes.h" -#include "tcmalloc/size_class_info.h" +#ifndef TCMALLOC_INTERNAL_OVERFLOW_H_ +#define TCMALLOC_INTERNAL_OVERFLOW_H_ + +#include + +#include "absl/base/config.h" +#include "tcmalloc/internal/config.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { -// Default implementation doesn't load runtime size classes. -// To enable runtime size classes, link with :runtime_size_classes. -// This is in a separate library so that it doesn't get inlined inside common.cc -ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE int MaybeSizeClassesFromEnv( - int max_size, int max_classes, SizeClassInfo* parsed) { - return -1; +inline bool MultiplyOverflow(size_t a, size_t b, size_t* out) { +#if ABSL_HAVE_BUILTIN(__builtin_mul_overflow) + return __builtin_mul_overflow(a, b, out); +#else + *out = a * b; + return b != 0 && *out / b != a; +#endif } } // namespace tcmalloc_internal } // namespace tcmalloc GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_OVERFLOW_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/page_size.cc b/contrib/libs/tcmalloc/tcmalloc/internal/page_size.cc new file mode 100644 index 000000000000..0a3468601474 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/page_size.cc @@ -0,0 +1,45 @@ +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/page_size.h" + +#include + +#include + +#include "absl/base/attributes.h" +#include "absl/base/call_once.h" +#include "tcmalloc/internal/config.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +size_t GetPageSize() { + ABSL_CONST_INIT static size_t page_size; + ABSL_CONST_INIT static absl::once_flag flag; + + absl::base_internal::LowLevelCallOnce(&flag, [&]() { +#if defined(__wasm__) || defined(__asmjs__) + page_size = static_cast(getpagesize()); +#else + page_size = static_cast(sysconf(_SC_PAGESIZE)); +#endif + }); + return page_size; +} + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/want_hpaa_subrelease.cc b/contrib/libs/tcmalloc/tcmalloc/internal/page_size.h similarity index 75% rename from contrib/libs/tcmalloc/tcmalloc/want_hpaa_subrelease.cc rename to contrib/libs/tcmalloc/tcmalloc/internal/page_size.h index 323cce40edc7..7ea86da220ae 100644 --- a/contrib/libs/tcmalloc/tcmalloc/want_hpaa_subrelease.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/page_size.h @@ -1,4 +1,5 @@ -// Copyright 2019 The TCMalloc Authors +#pragma clang system_header +// Copyright 2022 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,6 +13,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +#ifndef TCMALLOC_INTERNAL_PAGE_SIZE_H_ +#define TCMALLOC_INTERNAL_PAGE_SIZE_H_ + +#include + #include "absl/base/attributes.h" #include "tcmalloc/internal/config.h" @@ -19,12 +25,10 @@ GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { -// This -if linked into a binary - overrides page_allocator.cc and forces HPAA -// on/subrelease on. -ABSL_ATTRIBUTE_UNUSED int default_want_hpaa() { return 1; } - -ABSL_ATTRIBUTE_UNUSED int default_subrelease() { return 1; } +ABSL_ATTRIBUTE_PURE_FUNCTION size_t GetPageSize(); } // namespace tcmalloc_internal } // namespace tcmalloc GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_PAGE_SIZE_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/pageflags.cc b/contrib/libs/tcmalloc/tcmalloc/internal/pageflags.cc new file mode 100644 index 000000000000..653f78378ff9 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/pageflags.cc @@ -0,0 +1,368 @@ +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/pageflags.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "absl/base/optimization.h" +#include "absl/cleanup/cleanup.h" +#include "absl/status/status.h" +#include "absl/strings/numbers.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/util.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { +namespace { +// From include/uapi/linux/kernel-page-flags.h +#define KPF_COMPOUND_HEAD 15 +#define KPF_COMPOUND_TAIL 16 +#define KPF_THP 22 + +#ifndef KPF_HUGE +#define KPF_HUGE 17 +#endif + +#ifndef KPF_MLOCKED +#define KPF_MLOCKED 33 +#endif +#define KPF_STALE 44 + +// If a page is Head or Tail it is a compound page. It cannot be both, but it +// can be neither, in which case it's just a native page and no special handling +// needs to be done. +constexpr bool PageHead(uint64_t flags) { + constexpr uint64_t kPageHead = (1UL << KPF_COMPOUND_HEAD); + return (flags & kPageHead) == kPageHead; +} +constexpr bool PageTail(uint64_t flags) { + constexpr uint64_t kPageTail = (1UL << KPF_COMPOUND_TAIL); + return (flags & kPageTail) == kPageTail; +} +constexpr bool PageThp(uint64_t flags) { + constexpr uint64_t kPageThp = (1UL << KPF_THP); + return (flags & kPageThp) == kPageThp; +} +constexpr bool PageHugetlbfs(uint64_t flags) { + constexpr uint64_t kPageHuge = (1UL << KPF_HUGE); + return (flags & kPageHuge) == kPageHuge; +} +constexpr bool IsHugepage(uint64_t flags) { + return PageThp(flags) || PageHugetlbfs(flags); +} +constexpr bool PageStale(uint64_t flags) { + constexpr uint64_t kPageStale = (1UL << KPF_STALE); + return (flags & kPageStale) == kPageStale; +} +constexpr bool PageLocked(uint64_t flags) { + constexpr uint64_t kPageMlocked = (1UL << KPF_MLOCKED); + // Locked pages are often "unevictable." KPF_LOCKED has a different meaning. + constexpr uint64_t kPageUnevictable = (1UL << KPF_UNEVICTABLE); + return (flags & (kPageMlocked | kPageUnevictable)) != 0; +} + +void MaybeAddToStats(PageStats& stats, const uint64_t flags, + const size_t delta) { + if (PageStale(flags)) stats.bytes_stale += delta; + if (PageLocked(flags)) stats.bytes_locked += delta; +} + +} // namespace + +PageFlags::PageFlags() + : fd_(signal_safe_open("/proc/self/pageflags", O_RDONLY)) {} + +PageFlags::PageFlags(const char* const alternate_filename) + : fd_(signal_safe_open(alternate_filename, O_RDONLY)) { + if (fd_ == -1) { + TC_LOG("Could not open %s (errno %d)", alternate_filename, errno); + } +} + +PageFlags::~PageFlags() { + if (fd_ >= 0) { + signal_safe_close(fd_); + } +} + +size_t PageFlags::GetOffset(const uintptr_t vaddr) { + TC_ASSERT_EQ(vaddr % kPageSize, 0); + return vaddr / kPageSize * kPagemapEntrySize; +} + +absl::StatusCode PageFlags::Seek(const uintptr_t vaddr) { + size_t offset = GetOffset(vaddr); + // Note: lseek can't be interrupted. + off_t status = ::lseek(fd_, offset, SEEK_SET); + if (status != offset) { + return absl::StatusCode::kUnavailable; + } + return absl::StatusCode::kOk; +} + +absl::StatusCode PageFlags::MaybeReadOne(uintptr_t vaddr, uint64_t& flags, + bool& is_huge) { + if (auto res = Seek(vaddr); res != absl::StatusCode::kOk) return res; + static_assert(sizeof(flags) == kPagemapEntrySize); + auto status = signal_safe_read(fd_, reinterpret_cast(&flags), + kPagemapEntrySize, nullptr); + if (status != kPagemapEntrySize) { + return absl::StatusCode::kUnavailable; + } + + if (ABSL_PREDICT_FALSE((PageHead(flags) || PageTail(flags)) && + !PageThp(flags))) { + TC_LOG("PageFlags asked for information on non-THP hugepage??"); + return absl::StatusCode::kFailedPrecondition; + } + + if (PageTail(flags)) { + if (auto res = Seek(vaddr & kHugePageMask); res != absl::StatusCode::kOk) { + return res; + } + auto status = signal_safe_read(fd_, reinterpret_cast(&flags), + kPagemapEntrySize, nullptr); + if (status != kPagemapEntrySize) { + return absl::StatusCode::kUnavailable; + } + if (ABSL_PREDICT_FALSE(PageTail(flags))) { + TC_LOG("Somehow still at tail page even after seeking?"); + return absl::StatusCode::kFailedPrecondition; + } + // NOMUTANTS--Efficiency improvement that's not visible + is_huge = true; + } else { + // The current page is not a tail page, but it could still be the very first + // page of a hugepage. If this is the case, also plumb the information + // upward so we don't waste time re-reading the next 511 tail pages. + // NOMUTANTS--Efficiency improvement that's not visible + is_huge = PageHead(flags); + } + + return absl::StatusCode::kOk; +} + +absl::StatusCode PageFlags::ReadMany(int64_t num_pages, PageStats& output) { + while (num_pages > 0) { + const size_t batch_size = std::min(kEntriesInBuf, num_pages); + const size_t to_read = kPagemapEntrySize * batch_size; + + // We read continuously. For the first read, this starts at wherever the + // first ReadOne ended. See above note for the reinterpret_cast. + auto status = + signal_safe_read(fd_, reinterpret_cast(buf_), to_read, nullptr); + if (status != to_read) { + return absl::StatusCode::kUnavailable; + } + for (int i = 0; i < batch_size; ++i) { + if (PageHead(buf_[i])) { + last_head_read_ = buf_[i]; + } + + if (PageTail(buf_[i])) { + if (ABSL_PREDICT_FALSE(last_head_read_ == -1)) { + TC_LOG("Did not see head page before tail page (i=%v, buf=%v)", i, + buf_[i]); + return absl::StatusCode::kFailedPrecondition; + } + auto last_read = last_head_read_; + MaybeAddToStats(output, last_read, kPageSize); + } else { + MaybeAddToStats(output, buf_[i], kPageSize); + } + } + num_pages -= batch_size; + } + return absl::StatusCode::kOk; +} + +bool PageFlags::IsHugepageBacked(const void* const addr) { + if (fd_ < 0) { + return false; + } + + uint64_t flags = 0; + uintptr_t uaddr = reinterpret_cast(addr); + // Round address down to get the start of the first page that has any bytes + // corresponding to the span [addr, addr+size). + uintptr_t basePage = uaddr & ~(kPageSize - 1); + // Seek into fd. + if (auto res = Seek(basePage); res != absl::StatusCode::kOk) return false; + // Read entry + static_assert(sizeof(flags) == kPagemapEntrySize); + auto status = signal_safe_read(fd_, reinterpret_cast(&flags), + kPagemapEntrySize, nullptr); + if (status != kPagemapEntrySize) { + return false; + } + // pass entry to check if its hugepage backed. + return IsHugepage(flags); +} + +std::optional PageFlags::Get(const void* const addr, + const size_t size) { + if (fd_ < 0) { + return std::nullopt; + } + last_head_read_ = -1; + + PageStats ret; + if (size == 0) return ret; + uint64_t result_flags = 0; + bool is_huge = false; + + uintptr_t uaddr = reinterpret_cast(addr); + // Round address down to get the start of the first page that has any bytes + // corresponding to the span [addr, addr+size). + uintptr_t basePage = uaddr & ~(kPageSize - 1); + // Round end address up to get the start of the first page that does not + // have any bytes corresponding to the span [addr, addr+size). + // The span is a subset of [basePage, endPage). + uintptr_t endPage = (uaddr + size + kPageSize - 1) & ~(kPageSize - 1); + + int64_t remainingPages = (endPage - basePage) / kPageSize; + + if (remainingPages == 1) { + if (auto res = MaybeReadOne(basePage, result_flags, is_huge); + res != absl::StatusCode::kOk) { + return std::nullopt; + } + MaybeAddToStats(ret, result_flags, size); + if (ret.bytes_stale > 0) { + ret.stale_scan_seconds = MaybeReadStaleScanSeconds(); + } + return ret; + } + + // Since the input address might not be page-aligned (it can possibly point + // to an arbitrary object), we read staleness about the first page separately + // with ReadOne, then read the complete pages with ReadMany, and then read the + // last page with ReadOne again if needed. + + // Handle the first page. + if (auto res = MaybeReadOne(basePage, result_flags, is_huge); + res != absl::StatusCode::kOk) { + return std::nullopt; + } + size_t firstPageSize = kPageSize - (uaddr - basePage); + if (is_huge) { + // The object starts in the middle of a native page, but the entire page + // might be stale. So the situation looks like, simplifying to four native + // pages per hugepage to make the diagram fit, an entire hugepage that looks + // like (where X is the span of interest): + // . basePage + // [....|..XX|XXXX|XXXX] + // ^^^^^^^ some other stale object(s) + // ^^ firstPageSize + // ^^^^^^^^^^^^^^ `pages_represented` pages, each of kPageSize + // The remainingPages <= 0 case covers the situation where the span ends + // before the hugepage. + const uint64_t base_page_offset = basePage & (kHugePageSize - 1); + const uint64_t base_page_index = base_page_offset / kPageSize; + const int64_t pages_represented = kPagesInHugePage - base_page_index; + remainingPages -= pages_represented; + if (remainingPages <= 0) { + // This hugepage represents every single page that this object is on; + // we're done. + MaybeAddToStats(ret, result_flags, size); + + if (ret.bytes_stale > 0) { + ret.stale_scan_seconds = MaybeReadStaleScanSeconds(); + } + return ret; + } + + // pages_represented - 1 is the number of full pages represented (see + // diagram) + MaybeAddToStats(ret, result_flags, + firstPageSize + (pages_represented - 1) * kPageSize); + + // We've read one uint64_t about a single page, but it represents 512 small + // pages. So the next page that is of interest is one hugepage away -- seek + // to make sure the next read doesn't double-count the native pages in + // between the two head pages. + if (auto res = Seek((basePage & kHugePageMask) + kHugePageSize); + res != absl::StatusCode::kOk) { + return std::nullopt; + } + } else { + remainingPages--; + MaybeAddToStats(ret, result_flags, firstPageSize); + } + + // Handle all pages but the last page. + if (auto res = ReadMany(remainingPages - 1, ret); + res != absl::StatusCode::kOk) { + return std::nullopt; + } + + // Check final page. It doesn't really matter if is_huge; we just want the + // statistics about the page that has the last byte of the object. + size_t lastPageSize = kPageSize - (endPage - uaddr - size); + if (auto res = MaybeReadOne(endPage - kPageSize, result_flags, is_huge); + res != absl::StatusCode::kOk) { + return std::nullopt; + } + MaybeAddToStats(ret, result_flags, lastPageSize); + + if (ret.bytes_stale > 0) { + ret.stale_scan_seconds = MaybeReadStaleScanSeconds(); + } + return ret; +} + +uint64_t PageFlags::MaybeReadStaleScanSeconds(const char* filename) { + if (cached_scan_seconds_ != 0) return cached_scan_seconds_; + + int fd = signal_safe_open(filename, O_RDONLY); + if (fd == -1) { + TC_LOG("could not open %s (errno %d)", filename, errno); + return 0; + } + absl::Cleanup closer([fd] { signal_safe_close(fd); }); + char buf[32]; + int read = signal_safe_read(fd, buf, 32, /*bytes_read=*/nullptr); + if (read == -1) { + TC_LOG("could not read %s (errno %d)", filename, errno); + return 0; + } + if (read >= 32) { + buf[31] = '\0'; + TC_LOG("read nonsense from %s (%s)", filename, buf); + return 0; + } + buf[read] = '\0'; + if (!absl::SimpleAtoi(buf, &cached_scan_seconds_)) { + TC_LOG("read nonsense from %s (%s)", filename, buf); + cached_scan_seconds_ = 0; + } + + return cached_scan_seconds_; +} + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/pageflags.h b/contrib/libs/tcmalloc/tcmalloc/internal/pageflags.h new file mode 100644 index 000000000000..2034c4dcfca5 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/pageflags.h @@ -0,0 +1,154 @@ +#pragma clang system_header +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// /proc/self/pageflags is not available without kernel patches such as +// https://patchwork.kernel.org/project/linux-mm/patch/20211028205854.830200-1-almasrymina@google.com/ +// The pageflags that we look at are subject to change. + +#ifndef TCMALLOC_INTERNAL_PAGEFLAGS_H_ +#define TCMALLOC_INTERNAL_PAGEFLAGS_H_ + +#include +#include +#include + +#include + +#include "absl/status/status.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/page_size.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +struct PageStats { + size_t bytes_stale = 0; + size_t bytes_locked = 0; + // The number of seconds that must elapse (at minimum) for a page to be + // considered "stale". 0 indicates that kstaled is disabled or we weren't + // able to read from the scan_seconds sysfs control. (See b/111239799 + // regarding machines that disable kstaled). + // + // This isn't set if bytes_stale is zero because there are no bytes + // that it would refer to, and Get(nullptr, 0) will return an all-zero + // object as expected. + uint64_t stale_scan_seconds = 0; + + // This is currently used only by tests. It'll be good to convert this to + // C++20 "= default" when we increase the baseline compiler requirement. + bool operator==(const PageStats& rhs) const { + return bytes_stale == rhs.bytes_stale && bytes_locked == rhs.bytes_locked && + stale_scan_seconds == rhs.stale_scan_seconds; + } + + bool operator!=(const PageStats& rhs) const { return !(*this == rhs); } +}; + +// Base pageflags class that may be mocked for testing. +class PageFlagsBase { + public: + PageFlagsBase() = default; + virtual ~PageFlagsBase() = default; + PageFlagsBase(const PageFlagsBase&) = delete; + PageFlagsBase(PageFlagsBase&&) = delete; + PageFlagsBase& operator=(const PageFlagsBase&) = delete; + PageFlagsBase& operator=(PageFlagsBase&&) = delete; + virtual std::optional Get(const void* addr, size_t size) = 0; +}; + +// PageFlags offers a look at kernel page flags to identify pieces of memory as +// stale. This class is very similar to Residency but has some substantial +// differences to be hugepage aware. +// +// Specifically, if a page is huge, KPF_STALE is set only on the head native +// page of a hugepage and means that the entire hugepage is stale. Thus, when +// encountering tail pages, we must rewind to find the head page to get the +// information related to them. Native pages have KPF_STALE set as normal; no +// special handling needs to be done for them. +class PageFlags final : public PageFlagsBase { + public: + // This class keeps an open file handle to procfs. Destroy the object to + // reclaim it. + PageFlags(); + ~PageFlags() override; + + // Query a span of memory starting from `addr` for `size` bytes. The memory + // span must consist of only native-size pages and THP hugepages; the behavior + // is undefined if we encounter other hugepages (such as hugetlbfs). We try to + // bail out if we find hugetlbfs immediately, but in esoteric cases like a + // hugetlbfs in the middle of another mapping, this won't work. + // + // We use std::optional for return value as std::optional guarantees that no + // dynamic memory allocation would happen. In contrast, absl::StatusOr may + // dynamically allocate memory when needed. Using std::optional allows us to + // use the function in places where memory allocation is prohibited. + std::optional Get(const void* addr, size_t size) override; + bool IsHugepageBacked(const void* addr); + + private: + // Returns the offset in the pageflags file for the given virtual address. + size_t GetOffset(uintptr_t vaddr); + + // This helper seeks the internal file to the correct location for the given + // virtual address. + [[nodiscard]] absl::StatusCode Seek(uintptr_t vaddr); + + // Tries to read staleness information about the page that contains vaddr. + // Possibly seeks backwards in an effort to find head hugepages. + absl::StatusCode MaybeReadOne(uintptr_t vaddr, uint64_t& flags, + bool& is_huge); + // This helper reads staleness information for `num_pages` worth of _full_ + // pages and puts the results into `output`. It continues the read from the + // last Seek() or last Read operation. + absl::StatusCode ReadMany(int64_t num_pages, PageStats& output); + + static constexpr const char* kKstaledScanSeconds = + "/sys/kernel/mm/kstaled/scan_seconds"; + uint64_t MaybeReadStaleScanSeconds( + const char* filename = kKstaledScanSeconds); + + // For testing. + friend class PageFlagsFriend; + explicit PageFlags(const char* alternate_filename); + + // Size of the buffer used to gather results. + static constexpr int kBufferLength = 4096; + static constexpr int kPagemapEntrySize = 8; + static constexpr int kEntriesInBuf = kBufferLength / kPagemapEntrySize; + + const size_t kPageSize = GetPageSize(); + // You can technically not hard-code this but it would involve many more + // queries to figure out the size of every page. It's a lot easier to just + // assume any compound pages are 2 MB. + static constexpr int kHugePageSize = (2 << 20); + static constexpr uintptr_t kHugePageMask = ~(kHugePageSize - 1); + const size_t kPagesInHugePage = kHugePageSize / kPageSize; + + uint64_t buf_[kEntriesInBuf]; + // Information about the previous head page. For any future-encountered tail + // pages, we use the information from this page to determine staleness of the + // tail page. + uint64_t last_head_read_ = -1; + // Scan seconds. If zero, unknown / disabled. + uint64_t cached_scan_seconds_ = 0; + const int fd_; +}; + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_PAGEFLAGS_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/pageflags_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/pageflags_test.cc new file mode 100644 index 000000000000..cb9b21c8b2ba --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/pageflags_test.cc @@ -0,0 +1,571 @@ +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/pageflags.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "benchmark/benchmark.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/flags/flag.h" +#include "absl/log/check.h" +#include "absl/log/log.h" +#include "absl/random/distributions.h" +#include "absl/random/random.h" +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "tcmalloc/internal/allocation_guard.h" +#include "tcmalloc/internal/util.h" + +ABSL_FLAG(bool, check_staleness, false, + "If true, actually wait around for memory to go stale."); + +namespace tcmalloc { +namespace tcmalloc_internal { + +class PageFlagsFriend { + public: + explicit PageFlagsFriend() = default; + explicit PageFlagsFriend(absl::string_view filename) : r_(filename.data()) {} + + template + decltype(auto) Get(Args&&... args) { + return r_.Get(std::forward(args)...); + } + + decltype(auto) MaybeReadStaleScanSeconds(absl::string_view filename) { + return r_.MaybeReadStaleScanSeconds(filename.data()); + } + + decltype(auto) CachedScanSeconds() { return r_.cached_scan_seconds_; } + + decltype(auto) IsHugepageBacked(const void* const addr) { + return r_.IsHugepageBacked(addr); + } + + void SetCachedScanSeconds( + decltype(PageFlags::cached_scan_seconds_) scan_seconds) { + r_.cached_scan_seconds_ = scan_seconds; + } + + private: + PageFlags r_; +}; + +std::ostream& operator<<(std::ostream& os, const PageStats& s) { + return os << "{ stale = " << s.bytes_stale << ", locked = " << s.bytes_locked + << ", stale_scan_seconds = " << s.stale_scan_seconds << "}"; +} + +namespace { + +using ::testing::FieldsAre; +using ::testing::Optional; + +constexpr uint64_t kPageHead = (1UL << 15); +constexpr uint64_t kPageTail = (1UL << 16); +constexpr uint64_t kPageThp = (1UL << 22); +constexpr uint64_t kPageHuge = (1UL << 17); +constexpr uint64_t kPageStale = (1UL << 44); + +constexpr size_t kPagemapEntrySize = 8; +constexpr size_t kHugePageSize = 2 << 20; +constexpr size_t kHugePageMask = ~(kHugePageSize - 1); + +// Write the given content into the given filename. Suitable only for tests. +void SetContents(absl::string_view filename, absl::string_view content) { + int fd = + signal_safe_open(filename.data(), O_CREAT | O_WRONLY | O_TRUNC, 0644); + CHECK_NE(fd, -1) << errno << " while writing to " << filename; + int written = + signal_safe_write(fd, content.data(), content.length(), nullptr); + CHECK_EQ(written, content.length()) << errno; + CHECK_EQ(signal_safe_close(fd), 0) << errno; +} + +TEST(PageFlagsTest, Smoke) { + GTEST_SKIP() << "pageflags not commonly available"; + auto res = PageFlags{}.Get(nullptr, 0); + EXPECT_THAT(res, Optional(PageStats{})); +} + +TEST(PageFlagsTest, Stack) { + GTEST_SKIP() << "pageflags not commonly available"; + + char buf[256]; + std::fill(std::begin(buf), std::end(buf), 12); + ::benchmark::DoNotOptimize(buf); + + PageFlags s; + EXPECT_THAT(s.Get(reinterpret_cast(buf), sizeof(buf)), + Optional(PageStats{})); +} + +TEST(PageFlagsTest, Alignment) { + GTEST_SKIP() << "pageflags not commonly available"; + + const size_t kPageSize = getpagesize(); + const int kNumPages = 6 * kHugePageSize / kPageSize; + for (auto mmap_hint : std::initializer_list{ + nullptr, reinterpret_cast(0x00007BADDE000000), + reinterpret_cast(0x00007BADDF001000)}) { + void* p = mmap( + mmap_hint, kNumPages * kPageSize, PROT_READ | PROT_WRITE, + (mmap_hint == nullptr ? 0 : MAP_FIXED) | MAP_ANONYMOUS | MAP_PRIVATE, + -1, 0); + ASSERT_NE(p, MAP_FAILED) << errno; + ASSERT_EQ(madvise(p, kPageSize * kNumPages, MADV_HUGEPAGE), 0) << errno; + + PageFlags s; + EXPECT_THAT(s.Get(p, kPageSize * kNumPages), Optional(PageStats{})) << p; + munmap(p, kNumPages * kPageSize); + } +} + +// Write an alternate "pageflags" file comprising all stale pages at the path +// indicated by `filename`. The actual pageflags are copied from the pages that +// obj spans, but we add KPF_STALE. The alternate pageflags file starts at 0, so +// we return a pointer to `obj` in the alternate virtual memory space. If `obj` +// is page-aligned, this is a zero pointer (not to be confused with a null +// pointer). +void* GenerateAllStaleTest(absl::string_view filename, void* obj, size_t size) { + const size_t kPageSize = getpagesize(); + + uintptr_t ptr = reinterpret_cast(obj); + uintptr_t pages_start = ptr & kHugePageMask; + uintptr_t new_offset = ptr - pages_start; + + off_t file_read_offset = pages_start / kPageSize * kPagemapEntrySize; + int read_fd = signal_safe_open("/proc/self/pageflags", O_RDONLY); + CHECK_NE(read_fd, -1) + << strerror(errno) + << " while reading pageflags; does your kernel support it?"; + int write_fd = signal_safe_open(filename.data(), O_CREAT | O_WRONLY, S_IRUSR); + CHECK_NE(write_fd, -1) << errno; + + CHECK_EQ(::lseek(read_fd, file_read_offset, SEEK_SET), file_read_offset); + std::array buf; + for (int i = 0; i < size / kHugePageSize + 3; ++i) { + CHECK_EQ(signal_safe_read(read_fd, reinterpret_cast(buf.data()), + kHugePageSize, nullptr), + kHugePageSize); + for (uint64_t& page : buf) { + if ((page & kPageHead) == kPageHead || (page & kPageTail) != kPageTail) { + page |= kPageStale; + } + } + CHECK_EQ(write(write_fd, buf.data(), kHugePageSize), kHugePageSize); + } + CHECK_EQ(close(read_fd), 0) << errno; + CHECK_EQ(close(write_fd), 0) << errno; + return reinterpret_cast(new_offset); +} + +TEST(PageFlagsTest, Stale) { + GTEST_SKIP() << "pageflags not commonly available"; + + constexpr size_t kPageSize = 4096; + constexpr int kNumPages = 6 * kHugePageSize / kPageSize; + // This is hardcoded because we need to know number of pages in a hugepage. + ASSERT_EQ(getpagesize(), kPageSize); + char* p = reinterpret_cast( + mmap(reinterpret_cast(0x00007BADDE001000), kNumPages * kPageSize, + PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); + ASSERT_NE(p, MAP_FAILED) << errno; + absl::BitGen rng; + for (int i = 0; i < kNumPages * kPageSize; ++i) { + p[i] = absl::Uniform(rng, 0, 256); + } + + // TODO(patrickx): Use MADV_COLLAPSE when broadly available. + // four hugepages + // nohugepage hugepage hugepage hugepage nohugepage hugepage + ASSERT_EQ(madvise(p, kHugePageSize, MADV_NOHUGEPAGE), 0) << errno; + ASSERT_EQ(madvise(p + kHugePageSize, 3 * kHugePageSize, MADV_HUGEPAGE), 0) + << errno; + ASSERT_EQ(madvise(p + 4 * kHugePageSize, kHugePageSize, MADV_NOHUGEPAGE), 0) + << errno; + ASSERT_EQ(madvise(p + 5 * kHugePageSize, kHugePageSize, MADV_HUGEPAGE), 0) + << errno; + PageFlags s; + ASSERT_THAT(s.Get(p, kPageSize * kNumPages), Optional(PageStats{})); + + // This doesn't work within a short test timeout. But if you have your own + // machine with appropriate patches, you can try it out! + if (absl::GetFlag(FLAGS_check_staleness)) { + absl::Time start = absl::Now(); + bool ok = false; + do { + auto res = s.Get(p, kPageSize * kNumPages); + ASSERT_TRUE(res.has_value()); + if (res->bytes_stale > kNumPages * kPageSize / 2) { + LOG(INFO) << absl::StrFormat("Got %ld bytes stale, pointer is at %p", + res->bytes_stale, p); + ok = true; + break; + } + LOG(INFO) << "still waiting; stale = " << res->bytes_stale; + absl::SleepFor(absl::Seconds(5)); + } while (absl::Now() - start < absl::Seconds(600)); + EXPECT_TRUE(ok) << "Failed to get enough stale memory."; + } else { + std::string fake_pageflags = + absl::StrCat(testing::TempDir(), "/fake_pageflags"); + void* fake_p = + GenerateAllStaleTest(fake_pageflags, p, kNumPages * kPageSize); + // fake_p is likely already aligned, but might as well make sure. This is + // likely a zero pointer (not to be confused with nullptr). + void* base_p = reinterpret_cast(reinterpret_cast(fake_p) & + ~(kPageSize - 1)); + PageFlagsFriend mocks(fake_pageflags); + constexpr uint64_t kSetScanSeconds = 63; + mocks.SetCachedScanSeconds(kSetScanSeconds); + for (int num_pages = 0; num_pages < kNumPages; ++num_pages) { + for (int offset = -1; offset <= 1; ++offset) { + if (num_pages == 0 && offset == -1) continue; + // Messing around with scan_seconds is kind of confusing here but not as + // much overhead as adding a custom matcher. But if you add yet another + // field here it's time to write one. + uint64_t scan_seconds = kSetScanSeconds; + if (num_pages * kPageSize + offset == 0) scan_seconds = 0; + // CAUTION: If you think this test is very flaky, it's possible it's + // only passing when the machine you get scheduled on is out of + // hugepages. + EXPECT_THAT(mocks.Get(base_p, num_pages * kPageSize + offset), + Optional(FieldsAre(num_pages * kPageSize + offset, 0, + scan_seconds))) + << num_pages << "," << offset; + + EXPECT_THAT( + mocks.Get((char*)fake_p - offset, num_pages * kPageSize + offset), + Optional( + FieldsAre(num_pages * kPageSize + offset, 0, scan_seconds))) + << num_pages << "," << offset; + + EXPECT_THAT(mocks.Get(fake_p, num_pages * kPageSize + offset), + Optional(FieldsAre(num_pages * kPageSize + offset, 0, + scan_seconds))) + << num_pages << "," << offset; + + EXPECT_THAT( + mocks.Get((char*)fake_p + offset, num_pages * kPageSize + offset), + Optional( + FieldsAre(num_pages * kPageSize + offset, 0, scan_seconds))) + << num_pages << "," << offset; + + scan_seconds = kSetScanSeconds; + if (num_pages == 0) scan_seconds = 0; + EXPECT_THAT( + mocks.Get((char*)kHugePageSize + offset, num_pages * kPageSize), + Optional(FieldsAre(num_pages * kPageSize, 0, scan_seconds))) + << num_pages << "," << offset; + } + } + + EXPECT_THAT(mocks.Get(reinterpret_cast(2 * kHugePageSize + + 16 * kPageSize + 2), + kHugePageSize * 3), + Optional(FieldsAre(kHugePageSize * 3, 0, kSetScanSeconds))); + } + + ASSERT_EQ(munmap(p, kNumPages * kPageSize), 0) << errno; +} + +TEST(PageFlagsTest, Locked) { + GTEST_SKIP() << "pageflags not commonly available"; + +#if ABSL_HAVE_ADDRESS_SANITIZER || ABSL_HAVE_MEMORY_SANITIZER || \ + ABSL_HAVE_THREAD_SANITIZER + GTEST_SKIP() << "Skipped under sanitizers."; +#endif + + constexpr size_t kPageSize = 4096; + constexpr int kNumPages = 6 * kHugePageSize / kPageSize; + // This is hardcoded because we need to know number of pages in a hugepage. + ASSERT_EQ(getpagesize(), kPageSize); + char* p = reinterpret_cast( + mmap(reinterpret_cast(0x00007BADDE000000), kNumPages * kPageSize, + PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); + ASSERT_NE(p, MAP_FAILED) << errno; + absl::BitGen rng; + for (int i = 0; i < kNumPages * kPageSize; ++i) { + p[i] = absl::Uniform(rng, 0, 256); + } + + PageFlags s; + ASSERT_THAT(s.Get(p, kPageSize * kNumPages), Optional(PageStats{})); + + ASSERT_EQ(madvise(p, kHugePageSize, MADV_NOHUGEPAGE), 0) << errno; + ASSERT_EQ(madvise(p + kHugePageSize, 3 * kHugePageSize, MADV_HUGEPAGE), 0) + << errno; + ASSERT_EQ(madvise(p + 4 * kHugePageSize, kHugePageSize, MADV_NOHUGEPAGE), 0) + << errno; + ASSERT_EQ(madvise(p + 5 * kHugePageSize, kHugePageSize, MADV_HUGEPAGE), 0) + << errno; + + ASSERT_THAT(s.Get(p, kPageSize * kNumPages), Optional(PageStats{})); + + ASSERT_EQ(mlock(p, kPageSize * kNumPages), 0) << errno; + + // Wait until the kernel has had time to propagate flags. + absl::Time start = absl::Now(); + do { + auto res = s.Get(p, kPageSize * kNumPages); + ASSERT_TRUE(res.has_value()); + if (res->bytes_locked > kNumPages * kPageSize / 2) { + LOG(INFO) << "Got " << res->bytes_locked + << " bytes locked, pointer is at " << (uintptr_t)p; + + if (res->bytes_locked == kNumPages * kPageSize) { + break; + } + } + LOG(INFO) << "still waiting; locked = " << res->bytes_locked; + absl::SleepFor(absl::Seconds(5)); + } while (absl::Now() - start < absl::Seconds(60)); + + auto res = s.Get(p, kPageSize * kNumPages); + ASSERT_TRUE(res.has_value()); + ASSERT_EQ(res->bytes_locked, kPageSize * kNumPages); + + ASSERT_EQ(munmap(p, kNumPages * kPageSize), 0) << errno; +} + +TEST(PageFlagsTest, OnlyTails) { + const size_t kPageSize = getpagesize(); + std::vector data(5 * kHugePageSize / kPageSize); + for (auto& page : data) { + page |= kPageTail; + page |= kPageThp; + } + std::string file_path = absl::StrCat(testing::TempDir(), "/only-tails"); + int write_fd = + signal_safe_open(file_path.c_str(), O_CREAT | O_WRONLY, S_IRUSR); + ASSERT_NE(write_fd, -1) << errno; + + size_t bytes_to_write = data.size() * sizeof(data[0]); + ASSERT_EQ(write(write_fd, data.data(), bytes_to_write), bytes_to_write) + << errno; + ASSERT_EQ(close(write_fd), 0) << errno; + + PageFlagsFriend s(file_path); + ASSERT_EQ(s.Get(reinterpret_cast(kHugePageSize), kHugePageSize), + std::nullopt); +} + +// Queries and checks the pageflags if the pages are hugepage-backed or not. +// TODO(b/28093874): Check to see if we can add a real pageflags test (e.g. +// using MADV_COLLAPSE) to confirm the hugepage status using pageflags. +TEST(PageFlagsTest, IsHugepageBacked) { + const auto test_hugepage_status = [&](uint64_t flags, bool expected) { + const size_t kPageSize = getpagesize(); + const size_t kPagesPerHugepage = kHugePageSize / kPageSize; + + std::vector data(kPagesPerHugepage); + for (auto& page : data) { + page |= flags; + } + std::string file_path = + absl::StrCat(testing::TempDir(), "/hugepage_backed_", flags); + int write_fd = + signal_safe_open(file_path.c_str(), O_CREAT | O_WRONLY, S_IRUSR); + ASSERT_NE(write_fd, -1) << errno; + + size_t bytes_to_write = data.size() * sizeof(data[0]); + ASSERT_EQ(write(write_fd, data.data(), bytes_to_write), bytes_to_write) + << errno; + ASSERT_EQ(close(write_fd), 0) << errno; + + PageFlagsFriend s(file_path); + for (int page = 0; page < kPagesPerHugepage; ++page) { + ASSERT_EQ(s.IsHugepageBacked(reinterpret_cast(page)), expected); + } + CHECK_EQ(signal_safe_close(write_fd), 0) << errno; + }; + + test_hugepage_status(kPageHuge, /*expected=*/true); + test_hugepage_status(kPageHuge | kPageThp, /*expected=*/true); + test_hugepage_status(kPageThp, /*expected=*/true); + test_hugepage_status(/*flags=*/0, /*expected=*/false); +} + +TEST(PageFlagsTest, TooManyTails) { + const size_t kPageSize = getpagesize(); + std::vector data(7 * kHugePageSize / kPageSize); + for (auto& page : data) { + page |= kPageTail; + page |= kPageThp; + } + data[kHugePageSize / kPageSize] = kPageHead | kPageThp; + data[2 * kHugePageSize / kPageSize] = kPageHead | kPageThp; + data[3 * kHugePageSize / kPageSize] = kPageHead | kPageThp; + data[5 * kHugePageSize / kPageSize] = kPageHead | kPageThp; + + std::string file_path = absl::StrCat(testing::TempDir(), "/too-many-tails"); + int write_fd = + signal_safe_open(file_path.c_str(), O_CREAT | O_WRONLY, S_IRUSR); + ASSERT_NE(write_fd, -1) << errno; + + size_t bytes_to_write = data.size() * sizeof(data[0]); + ASSERT_EQ(write(write_fd, data.data(), bytes_to_write), bytes_to_write) + << errno; + ASSERT_EQ(close(write_fd), 0) << errno; + + PageFlagsFriend s(file_path); + EXPECT_THAT(s.Get(reinterpret_cast(kHugePageSize), kHugePageSize), + Optional(PageStats{})); + EXPECT_THAT(s.Get(reinterpret_cast(kHugePageSize), 3 * kHugePageSize), + Optional(PageStats{})); + + EXPECT_THAT(s.Get(reinterpret_cast(3 * kHugePageSize), kHugePageSize), + Optional(PageStats{})); + EXPECT_THAT( + s.Get(reinterpret_cast(3 * kHugePageSize), 2 * kHugePageSize), + std::nullopt); + EXPECT_THAT( + s.Get(reinterpret_cast(3 * kHugePageSize), 3 * kHugePageSize), + std::nullopt); +} + +TEST(PageFlagsTest, NotThp) { + const size_t kPageSize = getpagesize(); + std::vector data(3 * kHugePageSize / kPageSize); + for (auto& page : data) { + page |= kPageHead; + } + + std::string file_path = absl::StrCat(testing::TempDir(), "/not-thp"); + int write_fd = + signal_safe_open(file_path.c_str(), O_CREAT | O_WRONLY, S_IRUSR); + ASSERT_NE(write_fd, -1) << errno; + + size_t bytes_to_write = data.size() * sizeof(data[0]); + ASSERT_EQ(write(write_fd, data.data(), bytes_to_write), bytes_to_write) + << errno; + ASSERT_EQ(close(write_fd), 0) << errno; + + PageFlagsFriend s(file_path); + EXPECT_THAT(s.Get(nullptr, kHugePageSize), std::nullopt); +} + +TEST(PageFlagsTest, CannotOpen) { + PageFlagsFriend s("/tmp/a667ba48-18ba-4523-a8a7-b49ece3a6c2b"); + EXPECT_FALSE(s.Get(nullptr, 1).has_value()); +} + +TEST(PageFlagsTest, CannotRead) { + PageFlagsFriend s("/dev/null"); + EXPECT_FALSE(s.Get(nullptr, 1).has_value()); +} + +TEST(PageFlagsTest, CannotSeek) { + PageFlagsFriend s("/dev/null"); + EXPECT_FALSE(s.Get(&s, 1).has_value()); +} + +// For this and the following tests, the EXPECT_* macros allocate memory so +// that's why we have a strange dance with resetting the AllocationGuard. +TEST(StaleSeconds, Read) { + GTEST_SKIP() << "pageflags not commonly available"; + // Allocate at least a couple hugepages or pageflags might have a short read. + auto alloc = std::make_unique>(); + + std::string fake_pageflags = + absl::StrCat(testing::TempDir(), "/fake_pageflags2"); + void* fake_p = GenerateAllStaleTest(fake_pageflags, &*alloc, 1); + std::string fake_stale_seconds = + absl::StrCat(testing::TempDir(), "/fake_stale_seconds"); + SetContents(fake_stale_seconds, "123"); + + std::optional g; + g.emplace(); + PageFlagsFriend s(fake_pageflags); + auto read_seconds = s.MaybeReadStaleScanSeconds(fake_stale_seconds); + auto result = s.Get(fake_p, 1); + g.reset(); + + EXPECT_THAT(read_seconds, 123); + EXPECT_THAT(result, Optional(FieldsAre(1, 0, 123))); +} + +void ExpectStaleSecondsFailedReadFrom(absl::string_view filename) { + std::optional g; + g.emplace(); + PageFlagsFriend s; + auto read_seconds = s.MaybeReadStaleScanSeconds(filename); + auto cached_seconds = s.CachedScanSeconds(); + g.reset(); + + EXPECT_EQ(read_seconds, cached_seconds); + EXPECT_EQ(cached_seconds, 0); +} + +TEST(StaleSeconds, NotFound) { + ExpectStaleSecondsFailedReadFrom(absl::StrCat( + testing::TempDir(), "/nonexistent-f52a3d06-ee84-42c1-a298-a93a4b164ff0")); +} + +TEST(StaleSeconds, Bad) { + std::string fake_stale_seconds = + absl::StrCat(testing::TempDir(), "/fake_stale_seconds2"); + SetContents(fake_stale_seconds, "[always]"); + + ExpectStaleSecondsFailedReadFrom(fake_stale_seconds); +} + +TEST(StaleSeconds, IntOutOfBounds) { + std::string fake_stale_seconds = + absl::StrCat(testing::TempDir(), "/fake_stale_seconds3"); + SetContents(fake_stale_seconds, "-1"); + + ExpectStaleSecondsFailedReadFrom(fake_stale_seconds); +} + +TEST(StaleSeconds, TextOverflow) { + std::string fake_stale_seconds = + absl::StrCat(testing::TempDir(), "/fake_stale_seconds4"); + std::string contents(1 << 22, '9'); + SetContents(fake_stale_seconds, contents); + + ExpectStaleSecondsFailedReadFrom(fake_stale_seconds); +} + +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/parameter_accessors.h b/contrib/libs/tcmalloc/tcmalloc/internal/parameter_accessors.h index f14798fe7468..6616ec6b9a89 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/parameter_accessors.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/parameter_accessors.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,8 +16,12 @@ #ifndef TCMALLOC_INTERNAL_PARAMETER_ACCESSORS_H_ #define TCMALLOC_INTERNAL_PARAMETER_ACCESSORS_H_ +#include +#include + #include "absl/base/attributes.h" #include "absl/time/time.h" +#include "tcmalloc/malloc_extension.h" extern "C" { @@ -25,32 +30,92 @@ ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetBackgroundReleaseRate( ABSL_ATTRIBUTE_WEAK uint64_t TCMalloc_Internal_GetHeapSizeHardLimit(); ABSL_ATTRIBUTE_WEAK bool TCMalloc_Internal_GetHPAASubrelease(); ABSL_ATTRIBUTE_WEAK void -TCMalloc_Internal_GetHugePageFillerSkipSubreleaseInterval(absl::Duration* v); -ABSL_ATTRIBUTE_WEAK bool TCMalloc_Internal_GetShufflePerCpuCachesEnabled(); -ABSL_ATTRIBUTE_WEAK bool TCMalloc_Internal_GetReclaimIdlePerCpuCachesEnabled(); -ABSL_ATTRIBUTE_WEAK bool TCMalloc_Internal_GetLazyPerCpuCachesEnabled(); +TCMalloc_Internal_GetHugePageFillerSkipSubreleaseShortInterval( + absl::Duration* v); +ABSL_ATTRIBUTE_WEAK void +TCMalloc_Internal_GetHugePageFillerSkipSubreleaseLongInterval( + absl::Duration* v); +ABSL_ATTRIBUTE_WEAK void +TCMalloc_Internal_GetHugeCacheDemandReleaseShortInterval(absl::Duration* v); +ABSL_ATTRIBUTE_WEAK void +TCMalloc_Internal_GetHugeCacheDemandReleaseLongInterval(absl::Duration* v); +ABSL_ATTRIBUTE_WEAK bool TCMalloc_Internal_GetReleasePartialAllocPagesEnabled(); +ABSL_ATTRIBUTE_WEAK bool TCMalloc_Internal_GetHugeCacheDemandBasedRelease(); +ABSL_ATTRIBUTE_WEAK bool TCMalloc_Internal_GetHugeRegionDemandBasedRelease(); +ABSL_ATTRIBUTE_WEAK bool +TCMalloc_Internal_GetReleasePagesFromHugeRegionEnabled(); +ABSL_ATTRIBUTE_WEAK bool +TCMalloc_Internal_GetResizeSizeClassMaxCapacityEnabled(); +ABSL_ATTRIBUTE_WEAK bool TCMalloc_Internal_GetPrioritizeSpansEnabled(); ABSL_ATTRIBUTE_WEAK double TCMalloc_Internal_GetPeakSamplingHeapGrowthFraction(); ABSL_ATTRIBUTE_WEAK bool TCMalloc_Internal_GetPerCpuCachesEnabled(); ABSL_ATTRIBUTE_WEAK size_t TCMalloc_Internal_GetStats(char* buffer, size_t buffer_length); -ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetGuardedSamplingRate(int64_t v); +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetGuardedSamplingInterval( + int64_t v); +ABSL_ATTRIBUTE_WEAK int TCMalloc_Internal_GetSelSanPercent(); +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetSelSanPercent(int v); ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetHeapSizeHardLimit(uint64_t v); ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetHPAASubrelease(bool v); -ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetShufflePerCpuCachesEnabled( +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetReleasePartialAllocPagesEnabled( bool v); -ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetReclaimIdlePerCpuCachesEnabled( +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetHugeCacheDemandBasedRelease( bool v); -ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetLazyPerCpuCachesEnabled(bool v); +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetHugeRegionDemandBasedRelease( + bool v); +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetReleasePagesFromHugeRegionEnabled( + bool v); +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetResizeSizeClassMaxCapacityEnabled( + bool v); +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetPrioritizeSpansEnabled(bool v); ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetMaxPerCpuCacheSize(int32_t v); ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetMaxTotalThreadCacheBytes( int64_t v); ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetPeakSamplingHeapGrowthFraction( double v); ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetPerCpuCachesEnabled(bool v); -ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetProfileSamplingRate(int64_t v); ABSL_ATTRIBUTE_WEAK void -TCMalloc_Internal_SetHugePageFillerSkipSubreleaseInterval(absl::Duration v); +TCMalloc_Internal_SetPerCpuCachesEnabledNoBuildRequirement(bool v); +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetProfileSamplingInterval( + int64_t v); +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetBackgroundProcessActionsEnabled( + bool v); +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetBackgroundProcessSleepInterval( + absl::Duration v); +ABSL_ATTRIBUTE_WEAK void +TCMalloc_Internal_SetHugePageFillerSkipSubreleaseShortInterval( + absl::Duration v); +ABSL_ATTRIBUTE_WEAK void +TCMalloc_Internal_SetHugePageFillerSkipSubreleaseLongInterval(absl::Duration v); +ABSL_ATTRIBUTE_WEAK void +TCMalloc_Internal_SetHugeCacheDemandReleaseShortInterval(absl::Duration v); +ABSL_ATTRIBUTE_WEAK void +TCMalloc_Internal_SetHugeCacheDemandReleaseLongInterval(absl::Duration v); +ABSL_ATTRIBUTE_WEAK bool TCMalloc_Internal_GetMadviseColdRegionsNoHugepage(); +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetMadviseColdRegionsNoHugepage( + bool v); +ABSL_ATTRIBUTE_WEAK uint8_t TCMalloc_Internal_GetMinHotAccessHint(); +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetMinHotAccessHint(uint8_t v); +[[maybe_unused]] ABSL_ATTRIBUTE_WEAK bool TCMalloc_Internal_PossiblyCold( + const void* ptr); +ABSL_ATTRIBUTE_WEAK bool TCMalloc_Internal_GetPerCpuCachesDynamicSlabEnabled(); +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetPerCpuCachesDynamicSlabEnabled( + bool v); +ABSL_ATTRIBUTE_WEAK double +TCMalloc_Internal_GetPerCpuCachesDynamicSlabGrowThreshold(); +ABSL_ATTRIBUTE_WEAK void +TCMalloc_Internal_SetPerCpuCachesDynamicSlabGrowThreshold(double v); +ABSL_ATTRIBUTE_WEAK double +TCMalloc_Internal_GetPerCpuCachesDynamicSlabShrinkThreshold(); +ABSL_ATTRIBUTE_WEAK void +TCMalloc_Internal_SetPerCpuCachesDynamicSlabShrinkThreshold(double v); +ABSL_ATTRIBUTE_WEAK bool TCMalloc_Internal_GetMadviseFree(); +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetMadviseFree(bool v); +ABSL_ATTRIBUTE_WEAK tcmalloc::tcmalloc_internal::MadvisePreference +TCMalloc_Internal_GetMadvise(); +ABSL_ATTRIBUTE_WEAK void TCMalloc_Internal_SetMadvise( + tcmalloc::tcmalloc_internal::MadvisePreference v); } #endif // TCMALLOC_INTERNAL_PARAMETER_ACCESSORS_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/percpu.cc b/contrib/libs/tcmalloc/tcmalloc/internal/percpu.cc index f8706f0f2120..ef5699f920a4 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/percpu.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/percpu.cc @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -22,13 +23,20 @@ #include #include +#include +#include +#include +#include #include "absl/base/attributes.h" #include "absl/base/call_once.h" // IWYU pragma: keep -#include "absl/base/internal/sysinfo.h" +#include "absl/base/optimization.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/cpu_utils.h" #include "tcmalloc/internal/linux_syscall_support.h" #include "tcmalloc/internal/logging.h" #include "tcmalloc/internal/optimization.h" +#include "tcmalloc/internal/sysinfo.h" #include "tcmalloc/internal/util.h" GOOGLE_MALLOC_SECTION_BEGIN @@ -43,37 +51,6 @@ namespace percpu { // Restartable Sequence (RSEQ) -extern "C" { -// We provide a per-thread value (defined in percpu_.c) which both tracks -// thread-local initialization state and (with RSEQ) provides an atomic -// in-memory reference for this thread's execution CPU. This value is only -// valid when the thread is currently executing -// Possible values: -// Unavailable/uninitialized: -// { kCpuIdUnsupported, kCpuIdUninitialized } -// Initialized, available: -// [0, NumCpus()) (Always updated at context-switch) -ABSL_PER_THREAD_TLS_KEYWORD ABSL_ATTRIBUTE_WEAK volatile kernel_rseq - __rseq_abi = { - 0, static_cast(kCpuIdUninitialized), 0, 0, - {0, 0}, {{kCpuIdUninitialized, kCpuIdUninitialized}}, -}; - -#ifdef __ppc__ -// On PPC, we have two cases for accessing the __rseq_abi TLS variable: -// * For initial-exec TLS, we write the raw assembly for accessing the memory -// with the appropriate relocations and offsets. On optimized builds, this is -// the use case that matters. -// * For non-initial-exec TLS, access is far more involved. We call this helper -// function from percpu_rseq_ppc.S to leave the initialization and access to -// the compiler. -ABSL_ATTRIBUTE_UNUSED ABSL_ATTRIBUTE_NOINLINE void* tcmalloc_tls_fetch_pic() { - return const_cast(&__rseq_abi); -} -#endif - -} // extern "C" - enum PerCpuInitStatus { kFastMode, kSlowMode, @@ -81,47 +58,112 @@ enum PerCpuInitStatus { ABSL_CONST_INIT static PerCpuInitStatus init_status = kSlowMode; ABSL_CONST_INIT static absl::once_flag init_per_cpu_once; -#if TCMALLOC_PERCPU_USE_RSEQ +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ ABSL_CONST_INIT static std::atomic using_upstream_fence{false}; -#endif // TCMALLOC_PERCPU_USE_RSEQ +#endif // TCMALLOC_INTERNAL_PERCPU_USE_RSEQ -// Is this thread's __rseq_abi struct currently registered with the kernel? -static bool ThreadRegistered() { return RseqCpuId() >= kCpuIdInitialized; } +extern "C" thread_local char tcmalloc_sampler ABSL_ATTRIBUTE_INITIAL_EXEC; static bool InitThreadPerCpu() { // If we're already registered, there's nothing further for us to do. - if (ThreadRegistered()) { + if (IsFastNoInit()) { return true; } -#ifdef __NR_rseq + // Mask signals and double check thread registration afterwards. If we + // encounter a signal between ThreadRegistered() above and rseq() and that + // signal initializes per-CPU, rseq() here will fail with EBUSY. + ScopedSigmask mask; + + if (IsFastNoInit()) { + return true; + } + +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ && defined(__NR_rseq) return 0 == syscall(__NR_rseq, &__rseq_abi, sizeof(__rseq_abi), 0, TCMALLOC_PERCPU_RSEQ_SIGNATURE); #endif // __NR_rseq return false; } -bool UsingFlatVirtualCpus() { +bool UsingRseqVirtualCpus() { return false; } +static int UserVirtualCpuId() { + TC_BUG("initialized unsupported vCPU mode"); +} + +int VirtualCpu::Synchronize() { +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + int vcpu = kCpuIdUninitialized; + + if (TestSynchronize) { + vcpu = TestSynchronize(); + if (vcpu >= kCpuIdInitialized) { + tcmalloc_cached_vcpu = vcpu; + return vcpu; + } + } + + if (UsingVirtualCpus()) { + if (UsingRseqVirtualCpus()) + vcpu = __rseq_abi.vcpu_id; + else + vcpu = UserVirtualCpuId(); + } else { + vcpu = GetRealCpuUnsafe(); + } + + TC_CHECK_GE(vcpu, kCpuIdInitialized); + tcmalloc_cached_vcpu = vcpu; + return vcpu; +#else // TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + TC_BUG("unsupported without rseq"); +#endif // TCMALLOC_INTERNAL_PERCPU_USE_RSEQ +} + static void InitPerCpu() { - CHECK_CONDITION(absl::base_internal::NumCPUs() <= - std::numeric_limits::max()); + const auto maybe_numcpus = NumCPUsMaybe(); + if (!maybe_numcpus.has_value()) { + init_status = kSlowMode; + return; + } + TC_CHECK(*maybe_numcpus <= std::numeric_limits::max()); // Based on the results of successfully initializing the first thread, mark // init_status to initialize all subsequent threads. if (InitThreadPerCpu()) { init_status = kFastMode; -#if TCMALLOC_PERCPU_USE_RSEQ +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + // See the comment about data layout in percpu.h for details. + auto sampler_addr = reinterpret_cast(&tcmalloc_sampler); + // Have to use volatile because C++ compiler rejects to believe that + // objects can overlap. + volatile auto slabs_addr = reinterpret_cast(&tcmalloc_slabs); + auto rseq_abi_addr = reinterpret_cast(&__rseq_abi); + // Ensure __rseq_abi alignment required by ABI. + TC_CHECK_EQ(rseq_abi_addr % 32, 0); + // Ensure that all our TLS data is in a single cache line. + TC_CHECK_EQ(rseq_abi_addr / 64, slabs_addr / 64); + TC_CHECK_EQ(rseq_abi_addr / 64, + (sampler_addr + TCMALLOC_SAMPLER_HOT_OFFSET) / 64); + // Ensure that tcmalloc_slabs partially overlap with + // __rseq_abi.cpu_id_start as we expect. + TC_CHECK_EQ(slabs_addr, rseq_abi_addr + TCMALLOC_RSEQ_SLABS_OFFSET); + // Ensure Sampler is properly aligned. + TC_CHECK_EQ(sampler_addr % TCMALLOC_SAMPLER_ALIGN, 0); + // Ensure that tcmalloc_sampler is located before tcmalloc_slabs. + TC_CHECK_LE(sampler_addr + TCMALLOC_SAMPLER_SIZE, slabs_addr); + constexpr int kMEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ = (1 << 8); // It is safe to make the syscall below multiple times. using_upstream_fence.store( - 0 == syscall(__NR_membarrier, - kMEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ, 0, 0), + 0 == syscall(__NR_membarrier, + kMEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ, 0, 0), std::memory_order_relaxed); -#endif // TCMALLOC_PERCPU_USE_RSEQ +#endif // TCMALLOC_INTERNAL_PERCPU_USE_RSEQ } } @@ -130,20 +172,45 @@ static void InitPerCpu() { // completed then only the thread-level will be completed. A return of false // indicates that initialization failed and RSEQ is unavailable. bool InitFastPerCpu() { - absl::base_internal::LowLevelCallOnce(&init_per_cpu_once, InitPerCpu); + // On the first trip through this function do the necessary process-wide + // initialization work. + // + // We do this with all signals disabled so that we don't deadlock due to + // re-entering from a signal handler. + // + // We use a global atomic to record an 'initialized' state as a fast path + // check, which allows us to avoid the signal mask syscall that we must + // use to prevent nested initialization during a signal deadlocking on + // LowLevelOnceInit, before we can enter the 'init once' logic. + ABSL_CONST_INIT static std::atomic initialized(false); + if (!initialized.load(std::memory_order_acquire)) { + ScopedSigmask mask; + + absl::base_internal::LowLevelCallOnce(&init_per_cpu_once, [&] { + InitPerCpu(); + + // Set `initialized` to true after all initialization has completed. + // The below store orders with the load acquire further up, i.e., all + // initialization and side effects thereof are visible to any thread + // observing a true value in the fast path check. + initialized.store(true, std::memory_order_release); + }); + } // Once we've decided fast-cpu support is available, initialization for all // subsequent threads must succeed for consistency. - if (init_status == kFastMode && RseqCpuId() == kCpuIdUninitialized) { - CHECK_CONDITION(InitThreadPerCpu()); + if (init_status == kFastMode && GetRealCpuUnsafe() == kCpuIdUninitialized) { + TC_CHECK(InitThreadPerCpu()); } +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ // If we've decided to use slow mode, set the thread-local CPU ID to // __rseq_abi.cpu_id so that IsFast doesn't call this function again for // this thread. if (init_status == kSlowMode) { __rseq_abi.cpu_id = kCpuIdUnsupported; } +#endif return init_status == kFastMode; } @@ -153,32 +220,31 @@ bool InitFastPerCpu() { // ---------------------------------------------------------------------------- static bool SetAffinityOneCpu(int cpu) { - cpu_set_t set; - CPU_ZERO(&set); - CPU_SET(cpu, &set); - if (0 == sched_setaffinity(0, sizeof(cpu_set_t), &set)) { + CpuSet set; + set.Zero(); + set.Set(cpu); + if (set.SetAffinity(0)) { return true; } - CHECK_CONDITION(errno == EINVAL); + TC_CHECK_EQ(errno, EINVAL); return false; } -// We're being asked to fence against the mask , but a NULL mask +// We're being asked to fence against the mask , but a -1 mask // means every CPU. Do we need ? -static bool NeedCpu(int cpu, const cpu_set_t* cpus) { - if (cpus == nullptr) return true; - return CPU_ISSET(cpu, cpus); +static bool NeedCpu(const int cpu, const int target) { + return target == -1 || target == cpu; } -static void SlowFence(const cpu_set_t* cpus) { +static void SlowFence(int target) { // Necessary, so the point in time mentioned below has visibility // of our writes. std::atomic_thread_fence(std::memory_order_seq_cst); // First, save our cpumask (the user may want it back.) - cpu_set_t old; - CPU_ZERO(&old); - CHECK_CONDITION(0 == sched_getaffinity(0, sizeof(cpu_set_t), &old)); + CpuSet old; + old.Zero(); + TC_CHECK(old.GetAffinity(0)); // Here's the basic idea: if we run on every CPU, then every thread // that runs after us has certainly seen every store we've made up @@ -189,8 +255,8 @@ static void SlowFence(const cpu_set_t* cpus) { // side, if we are unable to run on a particular CPU, the same is true for our // siblings (up to some races, dealt with below), so we don't need to. - for (int cpu = 0; cpu < absl::base_internal::NumCPUs(); ++cpu) { - if (!NeedCpu(cpu, cpus)) { + for (int cpu = 0, n = NumCPUs(); cpu < n; ++cpu) { + if (!NeedCpu(cpu, target)) { // unnecessary -- user doesn't care about synchronization on this cpu continue; } @@ -239,33 +305,32 @@ static void SlowFence(const cpu_set_t* cpus) { using tcmalloc::tcmalloc_internal::signal_safe_open; using tcmalloc::tcmalloc_internal::signal_safe_read; int fd = signal_safe_open("/proc/self/cpuset", O_RDONLY); - CHECK_CONDITION(fd >= 0); + TC_CHECK_GE(fd, 0); char c; - CHECK_CONDITION(1 == signal_safe_read(fd, &c, 1, nullptr)); - - CHECK_CONDITION(0 == signal_safe_close(fd)); + TC_CHECK_EQ(1, signal_safe_read(fd, &c, 1, nullptr)); + TC_CHECK_EQ(0, signal_safe_close(fd)); // Try to go back to what we originally had before Fence. - if (0 != sched_setaffinity(0, sizeof(cpu_set_t), &old)) { - CHECK_CONDITION(EINVAL == errno); + if (!old.SetAffinity(0)) { + TC_CHECK_EQ(EINVAL, errno); // The original set is no longer valid, which should only happen if // cpuset.cpus was changed at some point in Fence. If that happened and we // didn't fence, our control plane would have rewritten our affinity mask to // everything in cpuset.cpus, so do that. - cpu_set_t set; - CPU_ZERO(&set); - for (int i = 0; i < absl::base_internal::NumCPUs(); ++i) { - CPU_SET(i, &set); + CpuSet set; + set.Zero(); + for (int i = 0, n = NumCPUs(); i < n; ++i) { + set.Set(i); } - CHECK_CONDITION(0 == sched_setaffinity(0, sizeof(cpu_set_t), &set)); + TC_CHECK(set.SetAffinity(0)); } } -#if TCMALLOC_PERCPU_USE_RSEQ +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ static void UpstreamRseqFenceCpu(int cpu) { - ABSL_RAW_CHECK(using_upstream_fence.load(std::memory_order_relaxed), - "upstream fence unavailable."); + TC_CHECK(using_upstream_fence.load(std::memory_order_relaxed) && + "upstream fence unavailable."); constexpr int kMEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ = (1 << 7); constexpr int kMEMBARRIER_CMD_FLAG_CPU = (1 << 0); @@ -273,76 +338,63 @@ static void UpstreamRseqFenceCpu(int cpu) { int64_t res = syscall(__NR_membarrier, kMEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ, kMEMBARRIER_CMD_FLAG_CPU, cpu); - ABSL_RAW_CHECK(res == 0 || res == -ENXIO /* missing CPU */, - "Upstream fence failed."); + TC_CHECK(res == 0 || res == -ENXIO /* missing CPU */, + "Upstream fence failed."); } -#endif // TCMALLOC_PERCPU_USE_RSEQ +#endif // TCMALLOC_INTERNAL_PERCPU_USE_RSEQ -// Interrupt every concurrently running sibling thread on any cpu in -// "cpus", and guarantee our writes up til now are visible to every -// other CPU. (cpus == NULL is equivalent to all CPUs.) -static void FenceInterruptCPUs(const cpu_set_t* cpus) { - CHECK_CONDITION(IsFast()); +// Interrupt every concurrently running sibling thread on "cpu", and guarantee +// our writes up til now are visible to every other CPU. (cpu == -1 is +// equivalent to all CPUs.) +static void FenceInterruptCPU(int cpu) { + TC_CHECK(IsFast()); // TODO(b/149390298): Provide an upstream extension for sys_membarrier to // interrupt ongoing restartable sequences. - SlowFence(cpus); -} - -void Fence() { - CompilerBarrier(); - - // Other operations (or all in RSEQ mode) might just be running on another - // CPU. Do something about that: use RSEQ::Fence() to just send interrupts - // and restart any such operation. -#if TCMALLOC_PERCPU_USE_RSEQ - if (using_upstream_fence.load(std::memory_order_relaxed)) { - UpstreamRseqFenceCpu(-1); - return; - } -#endif // TCMALLOC_PERCPU_USE_RSEQ - - FenceInterruptCPUs(nullptr); + SlowFence(cpu); } -void FenceCpu(int cpu, const size_t virtual_cpu_id_offset) { +void FenceCpu(int vcpu) { // Prevent compiler re-ordering of code below. In particular, the call to - // GetCurrentCpu must not appear in assembly program order until after any + // GetRealCpu must not appear in assembly program order until after any // code that comes before FenceCpu in C++ program order. CompilerBarrier(); // A useful fast path: nothing needs doing at all to order us with respect // to our own CPU. - if (GetCurrentVirtualCpu(virtual_cpu_id_offset) == cpu) { + if (ABSL_PREDICT_TRUE(IsFastNoInit()) && VirtualCpu::Synchronize() == vcpu) { return; } - if (virtual_cpu_id_offset == offsetof(kernel_rseq, vcpu_id)) { + if (UsingRseqVirtualCpus()) { ASSUME(false); // With virtual CPUs, we cannot identify the true physical core we need to // interrupt. -#if TCMALLOC_PERCPU_USE_RSEQ - if (using_upstream_fence.load(std::memory_order_relaxed)) { - UpstreamRseqFenceCpu(-1); - return; - } -#endif // TCMALLOC_PERCPU_USE_RSEQ - FenceInterruptCPUs(nullptr); + FenceAllCpus(); return; } -#if TCMALLOC_PERCPU_USE_RSEQ + int real_cpu = vcpu; + +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ if (using_upstream_fence.load(std::memory_order_relaxed)) { - UpstreamRseqFenceCpu(cpu); + UpstreamRseqFenceCpu(real_cpu); return; } -#endif // TCMALLOC_PERCPU_USE_RSEQ +#endif // TCMALLOC_INTERNAL_PERCPU_USE_RSEQ - cpu_set_t set; - CPU_ZERO(&set); - CPU_SET(cpu, &set); - FenceInterruptCPUs(&set); + FenceInterruptCPU(real_cpu); +} + +void FenceAllCpus() { +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + if (using_upstream_fence.load(std::memory_order_relaxed)) { + UpstreamRseqFenceCpu(-1); + return; + } +#endif // TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + FenceInterruptCPU(-1); } } // namespace percpu diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/percpu.h b/contrib/libs/tcmalloc/tcmalloc/internal/percpu.h index ad2124e0d186..b289eb643994 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/percpu.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/percpu.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,12 +16,23 @@ #ifndef TCMALLOC_INTERNAL_PERCPU_H_ #define TCMALLOC_INTERNAL_PERCPU_H_ -#define TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT 18 +// sizeof(Sampler) +#define TCMALLOC_SAMPLER_SIZE 32 +// alignof(Sampler) +#define TCMALLOC_SAMPLER_ALIGN 8 +// Sampler::HotDataOffset() +#define TCMALLOC_SAMPLER_HOT_OFFSET 24 + +// Offset from __rseq_abi to the cached slabs address. +#define TCMALLOC_RSEQ_SLABS_OFFSET -4 + +// The bit denotes that tcmalloc_rseq.slabs contains valid slabs offset. +#define TCMALLOC_CACHED_SLABS_BIT 63 +#define TCMALLOC_CACHED_SLABS_MASK (1ul << TCMALLOC_CACHED_SLABS_BIT) // TCMALLOC_PERCPU_RSEQ_SUPPORTED_PLATFORM defines whether or not we have an // implementation for the target OS and architecture. -#if defined(__linux__) && \ - (defined(__x86_64__) || defined(__PPC64__) || defined(__aarch64__)) +#if defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__)) #define TCMALLOC_PERCPU_RSEQ_SUPPORTED_PLATFORM 1 #else #define TCMALLOC_PERCPU_RSEQ_SUPPORTED_PLATFORM 0 @@ -30,8 +42,6 @@ #define TCMALLOC_PERCPU_RSEQ_FLAGS 0x0 #if defined(__x86_64__) #define TCMALLOC_PERCPU_RSEQ_SIGNATURE 0x53053053 -#elif defined(__ppc__) -#define TCMALLOC_PERCPU_RSEQ_SIGNATURE 0x0FE5000B #elif defined(__aarch64__) #define TCMALLOC_PERCPU_RSEQ_SIGNATURE 0xd428bc00 #else @@ -51,25 +61,22 @@ #include #include -#include "absl/base/dynamic_annotations.h" -#include "absl/base/internal/per_thread_tls.h" -#include "absl/base/macros.h" +#include "absl/base/attributes.h" #include "absl/base/optimization.h" -#include "tcmalloc/internal/atomic_danger.h" #include "tcmalloc/internal/config.h" #include "tcmalloc/internal/linux_syscall_support.h" #include "tcmalloc/internal/logging.h" -// TCMALLOC_PERCPU_USE_RSEQ defines whether TCMalloc support for RSEQ on the -// target architecture exists. We currently only provide RSEQ for 64-bit x86 and -// PPC binaries. -#if !defined(TCMALLOC_PERCPU_USE_RSEQ) -#if (ABSL_PER_THREAD_TLS == 1) && (TCMALLOC_PERCPU_RSEQ_SUPPORTED_PLATFORM == 1) -#define TCMALLOC_PERCPU_USE_RSEQ 1 +// TCMALLOC_INTERNAL_PERCPU_USE_RSEQ defines whether TCMalloc support for RSEQ +// on the target architecture exists. We currently only provide RSEQ for 64-bit +// x86, Arm binaries. +#if !defined(TCMALLOC_INTERNAL_PERCPU_USE_RSEQ) +#if TCMALLOC_PERCPU_RSEQ_SUPPORTED_PLATFORM == 1 +#define TCMALLOC_INTERNAL_PERCPU_USE_RSEQ 1 #else -#define TCMALLOC_PERCPU_USE_RSEQ 0 +#define TCMALLOC_INTERNAL_PERCPU_USE_RSEQ 0 #endif -#endif // !defined(TCMALLOC_PERCPU_USE_RSEQ) +#endif // !defined(TCMALLOC_INTERNAL_PERCPU_USE_RSEQ) GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { @@ -79,170 +86,200 @@ namespace percpu { inline constexpr int kRseqUnregister = 1; -// Internal state used for tracking initialization of RseqCpuId() +// Internal state used for tracking initialization of GetRealCpuUnsafe() inline constexpr int kCpuIdUnsupported = -2; inline constexpr int kCpuIdUninitialized = -1; inline constexpr int kCpuIdInitialized = 0; -#if TCMALLOC_PERCPU_USE_RSEQ -extern "C" ABSL_PER_THREAD_TLS_KEYWORD volatile kernel_rseq __rseq_abi; - -static inline int RseqCpuId() { return __rseq_abi.cpu_id; } - -static inline int VirtualRseqCpuId(const size_t virtual_cpu_id_offset) { -#ifdef __x86_64__ - ASSERT(virtual_cpu_id_offset == offsetof(kernel_rseq, cpu_id) || - virtual_cpu_id_offset == offsetof(kernel_rseq, vcpu_id)); - return *reinterpret_cast(reinterpret_cast(&__rseq_abi) + - virtual_cpu_id_offset); -#else - ASSERT(virtual_cpu_id_offset == offsetof(kernel_rseq, cpu_id)); - return RseqCpuId(); -#endif -} -#else // !TCMALLOC_PERCPU_USE_RSEQ -static inline int RseqCpuId() { return kCpuIdUnsupported; } - -static inline int VirtualRseqCpuId(const size_t virtual_cpu_id_offset) { - return kCpuIdUnsupported; -} +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ +// We provide a per-thread value (defined in percpu_rseq_asm.S) which both +// tracks thread-local initialization state and (with RSEQ) provides an atomic +// in-memory reference for this thread's execution CPU. This value is only +// valid when the thread is currently executing. +// Possible values: +// Unavailable/uninitialized: +// { kCpuIdUnsupported, kCpuIdUninitialized } +// Initialized, available: +// [0, NumCpus()) (Always updated at context-switch) +// +// CPU slabs region address caching. +// Calculation of the address of the current CPU slabs region is needed for +// allocation/deallocation fast paths, but is quite expensive. Due to variable +// shift and experimental support for "virtual CPUs", the calculation involves +// several additional loads and dependent calculations. Pseudo-code for the +// address calculation is as follows: +// +// cpu_offset = TcmallocSlab.virtual_cpu_id_offset_; +// cpu = *(&__rseq_abi + virtual_cpu_id_offset_); +// slabs_and_shift = TcmallocSlab.slabs_and_shift_; +// shift = slabs_and_shift & kShiftMask; +// shifted_cpu = cpu << shift; +// slabs = slabs_and_shift & kSlabsMask; +// slabs += shifted_cpu; +// +// To remove this calculation from fast paths, we cache the slabs address +// for the current CPU in thread local storage. However, when a thread is +// rescheduled to another CPU, we somehow need to understand that the cached +// address is not valid anymore. To achieve this, we overlap the top 4 bytes +// of the cached address with __rseq_abi.cpu_id_start. When a thread is +// rescheduled the kernel overwrites cpu_id_start with the current CPU number, +// which gives us the signal that the cached address is not valid anymore. +// To distinguish the high part of the cached address from the CPU number, +// we set the top bit in the cached address, real CPU numbers (<2^31) do not +// have this bit set. +// +// With these arrangements, slabs address calculation on allocation/deallocation +// fast paths reduces to load and check of the cached address: +// +// slabs = __rseq_abi[-4]; +// if ((slabs & (1 << 63)) == 0) goto slowpath; +// slabs &= ~(1 << 63); +// +// Note: here we assume little-endian byte order (which is the case for our +// supported architectures). On a little-endian arch, reading 8 bytes starting +// at __rseq_abi-4 gives __rseq_abi[-4...3]. So the tag bit (1<<63) is +// therefore from __rseq_abi[3]. That's also the most significant byte of +// __rseq_abi.cpu_id_start, hence real CPU numbers can't have this bit set +// (assuming <2^31 CPUs). +// +// The slow path does full slabs address calculation and caches it. +// +// Note: this makes __rseq_abi.cpu_id_start unusable for its original purpose. +// +// Since we need to export the __rseq_abi variable (as part of rseq ABI), +// we arrange overlapping of __rseq_abi and the preceding cached slabs +// address in percpu_rseq_asm.S (C++ is not capable of expressing that). +// __rseq_abi must be aligned to 32 bytes as per ABI. We want the cached slabs +// address to be contained within a single cache line (64 bytes), rather than +// split 2 cache lines. To achieve that we locate __rseq_abi in the second +// part of a cache line. +// For performance reasons we also collocate tcmalloc_sampler with __rseq_abi +// in the same cache line. +// InitPerCpu contains checks that the resulting data layout is as expected. + +// Top 4 bytes of this variable overlap with __rseq_abi.cpu_id_start. +extern "C" ABSL_CONST_INIT thread_local volatile uintptr_t tcmalloc_slabs + ABSL_ATTRIBUTE_INITIAL_EXEC; +extern "C" ABSL_CONST_INIT thread_local volatile kernel_rseq __rseq_abi + ABSL_ATTRIBUTE_INITIAL_EXEC; +extern "C" ABSL_CONST_INIT thread_local volatile int tcmalloc_cached_vcpu + ABSL_ATTRIBUTE_INITIAL_EXEC; + +// Provide weak definitions here to enable more efficient codegen. +// If compiler sees only extern declaration when generating accesses, +// then even with initial-exec model and -fno-PIE compiler has to assume +// that the definition may come from a dynamic library and has to use +// GOT access. When compiler sees even a weak definition, it knows the +// declaration will be in the current module and can generate direct accesses. +ABSL_CONST_INIT thread_local volatile uintptr_t tcmalloc_slabs + ABSL_ATTRIBUTE_WEAK = {}; +ABSL_CONST_INIT thread_local volatile kernel_rseq __rseq_abi + ABSL_ATTRIBUTE_WEAK = { + 0, static_cast(kCpuIdUninitialized), 0, 0, + {0, 0}, {{kCpuIdUninitialized, kCpuIdUninitialized}}, +}; +ABSL_CONST_INIT thread_local volatile int tcmalloc_cached_vcpu + ABSL_ATTRIBUTE_WEAK = kCpuIdUninitialized; + +inline int GetRealCpuUnsafe() { return __rseq_abi.cpu_id; } +#else // !TCMALLOC_INTERNAL_PERCPU_USE_RSEQ +inline int GetRealCpuUnsafe() { return kCpuIdUnsupported; } #endif -typedef int (*OverflowHandler)(int cpu, size_t cl, void *item); -typedef void *(*UnderflowHandler)(int cpu, size_t cl); - // Functions below are implemented in the architecture-specific percpu_rseq_*.S // files. extern "C" { -int TcmallocSlab_Internal_PerCpuCmpxchg64(int target_cpu, intptr_t *p, - intptr_t old_val, intptr_t new_val); - -#ifndef __x86_64__ -int TcmallocSlab_Internal_Push(void *ptr, size_t cl, void *item, size_t shift, - OverflowHandler f); -int TcmallocSlab_Internal_Push_FixedShift(void *ptr, size_t cl, void *item, - OverflowHandler f); -void *TcmallocSlab_Internal_Pop(void *ptr, size_t cl, UnderflowHandler f, - size_t shift); -void *TcmallocSlab_Internal_Pop_FixedShift(void *ptr, size_t cl, - UnderflowHandler f); -#endif // __x86_64__ - -// Push a batch for a slab which the Shift equal to -// TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT -size_t TcmallocSlab_Internal_PushBatch_FixedShift(void *ptr, size_t cl, - void **batch, size_t len); - -// Pop a batch for a slab which the Shift equal to -// TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT -size_t TcmallocSlab_Internal_PopBatch_FixedShift(void *ptr, size_t cl, - void **batch, size_t len); - -#ifdef __x86_64__ -int TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU(int target_cpu, intptr_t *p, - intptr_t old_val, - intptr_t new_val); -size_t TcmallocSlab_Internal_PushBatch_FixedShift_VCPU(void *ptr, size_t cl, - void **batch, - size_t len); -size_t TcmallocSlab_Internal_PopBatch_FixedShift_VCPU(void *ptr, size_t cl, - void **batch, size_t len); -#endif -} +size_t TcmallocSlab_Internal_PushBatch(size_t size_class, void** batch, + size_t len); +size_t TcmallocSlab_Internal_PopBatch(size_t size_class, void** batch, + size_t len, + std::atomic* begin_ptr); +} // extern "C" // NOTE: We skirt the usual naming convention slightly above using "_" to // increase the visibility of functions embedded into the root-namespace (by // virtue of C linkage) in the supported case. -// Return whether we are using flat virtual CPUs. -bool UsingFlatVirtualCpus(); - -inline int GetCurrentCpuUnsafe() { -// On PowerPC, Linux maintains the current CPU in the bottom 12 bits of special -// purpose register SPRG3, which is readable from user mode. References: -// -// https://github.com/torvalds/linux/blob/164c09978cebebd8b5fc198e9243777dbaecdfa0/arch/powerpc/kernel/vdso.c#L727 -// https://github.com/torvalds/linux/blob/dfb945473ae8528fd885607b6fa843c676745e0c/arch/powerpc/include/asm/reg.h#L966 -// https://github.com/torvalds/linux/blob/dfb945473ae8528fd885607b6fa843c676745e0c/arch/powerpc/include/asm/reg.h#L593 -// https://lists.ozlabs.org/pipermail/linuxppc-dev/2012-July/099011.html -// -// This is intended for VDSO syscalls, but is much faster if we simply inline it -// here, presumably due to the function call and null-check overheads of the -// VDSO version. As of 2014-07 the CPU time costs are something like 1.2 ns for -// the inline version vs 12 ns for VDSO. -#if defined(__PPC64__) && defined(__linux__) - uint64_t spr; - - // Mark the asm as volatile, so that it is not hoisted out of loops. - asm volatile("mfspr %0, 0x103;" : "=r"(spr)); +enum class RseqVcpuMode { kNone }; +inline RseqVcpuMode GetRseqVcpuMode() { return RseqVcpuMode::kNone; } - return spr & 0xfff; -#else - // Elsewhere, use the rseq mechanism. - return RseqCpuId(); -#endif +// Return whether we are using any kind of virtual CPUs. +inline bool UsingVirtualCpus() { + return GetRseqVcpuMode() != RseqVcpuMode::kNone; } -inline int GetCurrentCpu() { - // We can't use the unsafe version unless we have the appropriate version of - // the rseq extension. This also allows us a convenient escape hatch if the - // kernel changes the way it uses special-purpose registers for CPU IDs. - int cpu = GetCurrentCpuUnsafe(); +// Return whether we are using flat virtual CPUs (provided by kernel RSEQ). +bool UsingRseqVirtualCpus(); + +inline int GetRealCpu() { + // The "unsafe" variant strongly depends on RSEQ. + int cpu = GetRealCpuUnsafe(); // We open-code the check for fast-cpu availability since we do not want to - // force initialization in the first-call case. This so done so that we can - // use this in places where it may not always be safe to initialize and so - // that it may serve in the future as a proxy for callers such as - // CPULogicalId() without introducing an implicit dependence on the fast-path - // extensions. Initialization is also simply unneeded on some platforms. + // force initialization in the first-call case. This is done so that we can + // use this in places where it may not always be safe to initialize. + // Initialization is also simply unneeded on some platforms. if (ABSL_PREDICT_TRUE(cpu >= kCpuIdInitialized)) { return cpu; } #ifdef TCMALLOC_HAVE_SCHED_GETCPU cpu = sched_getcpu(); - ASSERT(cpu >= 0); + TC_ASSERT_GE(cpu, 0); #endif // TCMALLOC_HAVE_SCHED_GETCPU return cpu; } -inline int GetCurrentVirtualCpuUnsafe(const size_t virtual_cpu_id_offset) { - return VirtualRseqCpuId(virtual_cpu_id_offset); -} - -inline int GetCurrentVirtualCpu(const size_t virtual_cpu_id_offset) { - // We can't use the unsafe version unless we have the appropriate version of - // the rseq extension. This also allows us a convenient escape hatch if the - // kernel changes the way it uses special-purpose registers for CPU IDs. - int cpu = VirtualRseqCpuId(virtual_cpu_id_offset); +// Static accessors functions for any kind of vCPU IDs, which transparently +// choose the right vCPU source based on the initialized mode. Wrapping it into +// a class helps to restrict access and avoid accidental misuse. +class VirtualCpu { + public: + // Returns the last vCPU ID since the last synchronization point. This may be + // used where the vCPU ID is not used to derive RSEQ-validated state. Returns + // kCpuIdUninitialized if this thread has never synchronized with a vCPU ID, + // or kCpuIdUnsupported if RSEQ is not used. + // + // This is safe, because without a RSEQ critical section to detect thread + // preemption, a thread may be preempted at any point and the virtual (or + // real) CPU may change. + static int get() { +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + return tcmalloc_cached_vcpu; +#else // TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + return kCpuIdUnsupported; +#endif // TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + } - // We open-code the check for fast-cpu availability since we do not want to - // force initialization in the first-call case. This so done so that we can - // use this in places where it may not always be safe to initialize and so - // that it may serve in the future as a proxy for callers such as - // CPULogicalId() without introducing an implicit dependence on the fast-path - // extensions. Initialization is also simply unneeded on some platforms. - if (ABSL_PREDICT_TRUE(cpu >= kCpuIdInitialized)) { - return cpu; + // Returns the last vCPU ID since the last synchronization point. + // REQUIRES: Synchronize() has been called by this thread + static int GetAfterSynchronize() { + const int ret = get(); + TC_ASSERT_GE(ret, kCpuIdInitialized); + return ret; } -#ifdef TCMALLOC_HAVE_SCHED_GETCPU - cpu = sched_getcpu(); - ASSERT(cpu >= 0); -#endif // TCMALLOC_HAVE_SCHED_GETCPU + // Returns the current vCPU ID. Use to synchronize RSEQ-validated state that + // depends on the (per-CPU mutually exclusive) vCPU ID with the current vCPU + // ID after a thread preemption was detected. This function may be expensive, + // so it should only be called on slow paths. + static int Synchronize(); - return cpu; -} + private: + // The return value of Synchronize() may be overridden by tests if they define + // VirtualCpu::TestSynchronize(). + ABSL_ATTRIBUTE_WEAK static int TestSynchronize(); +}; bool InitFastPerCpu(); inline bool IsFast() { - if (!TCMALLOC_PERCPU_USE_RSEQ) { + if (!TCMALLOC_INTERNAL_PERCPU_USE_RSEQ) { return false; } - int cpu = RseqCpuId(); + int cpu = GetRealCpuUnsafe(); if (ABSL_PREDICT_TRUE(cpu >= kCpuIdInitialized)) { return true; @@ -258,10 +295,10 @@ inline bool IsFast() { // As IsFast(), but if this thread isn't already initialized, will not // attempt to do so. inline bool IsFastNoInit() { - if (!TCMALLOC_PERCPU_USE_RSEQ) { + if (!TCMALLOC_INTERNAL_PERCPU_USE_RSEQ) { return false; } - int cpu = RseqCpuId(); + int cpu = GetRealCpuUnsafe(); return ABSL_PREDICT_TRUE(cpu >= kCpuIdInitialized); } @@ -276,61 +313,47 @@ inline void CompilerBarrier() { // Internal tsan annotations, do not use externally. // Required as tsan does not natively understand RSEQ. -#ifdef THREAD_SANITIZER +#ifdef ABSL_HAVE_THREAD_SANITIZER extern "C" { -void __tsan_acquire(void *addr); -void __tsan_release(void *addr); +void __tsan_acquire(void* addr); +void __tsan_release(void* addr); } #endif // TSAN relies on seeing (and rewriting) memory accesses. It can't -// get at the memory acccesses we make from RSEQ assembler sequences, +// get at the memory accesses we make from RSEQ assembler sequences, // which means it doesn't know about the semantics our sequences // enforce. So if we're under TSAN, add barrier annotations. -inline void TSANAcquire(void *p) { -#ifdef THREAD_SANITIZER +inline void TSANAcquire(void* p) { +#ifdef ABSL_HAVE_THREAD_SANITIZER __tsan_acquire(p); #endif } -inline void TSANRelease(void *p) { -#ifdef THREAD_SANITIZER - __tsan_release(p); +inline void TSANAcquireBatch(void** batch, int n) { +#ifdef ABSL_HAVE_THREAD_SANITIZER + for (int i = 0; i < n; i++) { + __tsan_acquire(batch[i]); + } #endif } -inline void TSANMemoryBarrierOn(void *p) { - TSANAcquire(p); - TSANRelease(p); +inline void TSANRelease(void* p) { +#ifdef ABSL_HAVE_THREAD_SANITIZER + __tsan_release(p); +#endif } -// These methods may *only* be called if IsFast() has been called by the current -// thread (and it returned true). -inline int CompareAndSwapUnsafe(int target_cpu, std::atomic *p, - intptr_t old_val, intptr_t new_val, - const size_t virtual_cpu_id_offset) { - TSANMemoryBarrierOn(p); -#if TCMALLOC_PERCPU_USE_RSEQ - switch (virtual_cpu_id_offset) { - case offsetof(kernel_rseq, cpu_id): - return TcmallocSlab_Internal_PerCpuCmpxchg64( - target_cpu, tcmalloc_internal::atomic_danger::CastToIntegral(p), - old_val, new_val); -#ifdef __x86_64__ - case offsetof(kernel_rseq, vcpu_id): - return TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU( - target_cpu, tcmalloc_internal::atomic_danger::CastToIntegral(p), - old_val, new_val); -#endif // __x86_64__ - default: - __builtin_unreachable(); +inline void TSANReleaseBatch(void** batch, int n) { +#ifdef ABSL_HAVE_THREAD_SANITIZER + for (int i = 0; i < n; i++) { + __tsan_release(batch[i]); } -#else // !TCMALLOC_PERCPU_USE_RSEQ - __builtin_unreachable(); -#endif // !TCMALLOC_PERCPU_USE_RSEQ +#endif } -void FenceCpu(int cpu, const size_t virtual_cpu_id_offset); +void FenceCpu(int vcpu); +void FenceAllCpus(); } // namespace percpu } // namespace subtle diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_early_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_early_test.cc new file mode 100644 index 000000000000..6d6603ac2154 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_early_test.cc @@ -0,0 +1,39 @@ +// Copyright 2024 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "gtest/gtest.h" +#include "absl/base/attributes.h" +#include "tcmalloc/internal/percpu.h" + +namespace tcmalloc::tcmalloc_internal::subtle::percpu { +namespace { + +ABSL_CONST_INIT std::optional success; + +TEST(PerCpu, IsRegistered) { + // Verify preinit ran. Its success should be identical to running it after + // main has started. + EXPECT_TRUE(success.has_value()); + EXPECT_EQ(success, IsFast()); +} + +void register_rseq() { success = IsFast(); } + +__attribute__((section(".preinit_array"), + used)) void (*__local_install_factory_preinit)() = register_rseq; + +} // namespace +} // namespace tcmalloc::tcmalloc_internal::subtle::percpu diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_aarch64.S b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_aarch64.S index 3cdaf17835d0..d6a684c130f0 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_aarch64.S +++ b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_aarch64.S @@ -90,8 +90,7 @@ // distinct from label_start, as the return IP must be "signed" (see // SIGN_ABORT()). // -// TODO(b/141629158): __rseq_cs only needs to be writeable to allow for -// relocations, but could be read-only for non-PIE builds. +// __rseq_cs only needs to be writeable to allow for relocations. #define DEFINE_UPSTREAM_CS(label) \ .pushsection __rseq_cs, "aw"; \ .balign 32; \ @@ -114,10 +113,10 @@ .globl label##_trampoline; \ .type label##_trampoline, @function; \ label##_trampoline: \ - .cfi_startproc; \ + CFI(.cfi_startproc); \ BTI_C; \ b .L##label##_abort; \ - .cfi_endproc; \ + CFI(.cfi_endproc); \ .size label##_trampoline, . - label##_trampoline; \ .popsection; @@ -141,8 +140,8 @@ label##_trampoline: \ #endif /* FETCH_CPU assumes &__rseq_abi is in x5. */ -#define FETCH_CPU(dest) \ - ldr dest, [x5, #4] /* cpuid is 32-bits */ +#define FETCH_CPU(dest, offset) ldrh dest, [x5, offset] +#define FETCH_SLABS(dest) ldr dest, [x5, TCMALLOC_RSEQ_SLABS_OFFSET] /* With PIE have initial-exec TLS, even in the presence of position independent code. */ @@ -198,309 +197,148 @@ label##_trampoline: \ /* start of atomic restartable sequences */ -/* - * int TcmallocSlab_Internal_PerCpuCmpxchg64(int target_cpu, long *p, - * long old_val, long new_val) - * w0: target_cpu - * x1: p - * x2: old_val - * x3: new_val - */ - .p2align 6 /* aligns to 2^6 with NOP filling */ - .globl TcmallocSlab_Internal_PerCpuCmpxchg64 - .type TcmallocSlab_Internal_PerCpuCmpxchg64, @function -TcmallocSlab_Internal_PerCpuCmpxchg64: - .cfi_startproc - BTI_C - START_RSEQ(TcmallocSlab_Internal_PerCpuCmpxchg64) - FETCH_CPU(w4) - cmp w0, w4 /* check cpu vs current_cpu */ - bne .LTcmallocSlab_Internal_PerCpuCmpxchg64_commit - ldr x6, [x1] - cmp x6, x2 /* verify *p == old */ - bne .LTcmallocSlab_Internal_PerCpuCmpxchg64_mismatch - str x3, [x1] -.LTcmallocSlab_Internal_PerCpuCmpxchg64_commit: - mov x0, x4 - ret /* return current cpu, indicating mismatch OR success */ -.LTcmallocSlab_Internal_PerCpuCmpxchg64_mismatch: - mov x0, #-1 /* mismatch versus "old" or "check", return -1 */ - ret - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_PerCpuCmpxchg64) -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PerCpuCmpxchg64) - -/* size_t TcmallocSlab_Internal_PushBatch_FixedShift( - * void *ptr (x0), - * size_t cl (w1), - * void** batch (x2), - * size_t len (w3) { - * uint64_t r8 = __rseq_abi.cpu_id - * uint64_t* r8 = CpuMemoryStart(x0, r8) - * Header* hdr = r8 + w1 * 8 +/* size_t TcmallocSlab_Internal_PushBatch( + * size_t size_class (x0), + * void** batch (x1), + * size_t len (x2)) { + * uint64_t* r8 = tcmalloc_rseq.slabs; + * if ((r8 & TCMALLOC_CACHED_SLABS_BIT) == 0) return 0; + * r8 &= ~TCMALLOC_CACHED_SLABS_BIT; + * Header* hdr = r8 + r0 * 8 * uint64_t r9 = hdr->current (zero-extend 16bit) * uint64_t r10 = hdr->end (zero-extend 16bit) * if (r9 >= r10) return 0 - * r11 = r3 + * r11 = r2 * r10 = r9 + min(len, r10 - r9) * r13 = r9 + r10 * r9 = r8 + r9 * 8 * r14 = r8 + r13 * 8 * loop: - * r12 = *(r11-=8) (pre-index) Pop from Batch - * *(r9+=8) = r12 (post-index) Push to Slab + * r12 = *(r11 -= 8) (pre-index) Pop from Batch + * *(r9 += 8) = r12 (post-index) Push to Slab * if (r9 != r14) goto loop * hdr->current = r13 (16bit store) * return r10 * } */ .p2align 6 /* aligns to 2^6 with NOP filling */ - .globl TcmallocSlab_Internal_PushBatch_FixedShift - .type TcmallocSlab_Internal_PushBatch_FixedShift, @function -TcmallocSlab_Internal_PushBatch_FixedShift: - .cfi_startproc + .globl TcmallocSlab_Internal_PushBatch + .type TcmallocSlab_Internal_PushBatch, @function +TcmallocSlab_Internal_PushBatch: + CFI(.cfi_startproc) BTI_C - START_RSEQ(TcmallocSlab_Internal_PushBatch_FixedShift) - FETCH_CPU(w8) - lsl x8, x8, #TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT /* multiply cpu by 256k */ - add x8, x0, x8 - add x4, x8, x1, LSL #3 /* r4 = hdr */ - ldrh w9, [x4] /* r9 = current */ - ldrh w10, [x4, #6] /* r10 = end */ + START_RSEQ(TcmallocSlab_Internal_PushBatch) + FETCH_SLABS(x8) + tbz x8, #TCMALLOC_CACHED_SLABS_BIT, .LTcmallocSlab_Internal_PushBatch_no_capacity + and x8, x8, #~TCMALLOC_CACHED_SLABS_MASK + add x15, x8, x0, LSL #2 /* r15 = hdr */ + ldrh w9, [x15] /* r9 = current */ + ldrh w10, [x15, #2] /* r10 = end */ cmp w9, w10 - bge .LTcmallocSlab_Internal_PushBatch_FixedShift_no_capacity - add x11, x2, x3, LSL #3 /* r11 = batch + len * 8 */ + bge .LTcmallocSlab_Internal_PushBatch_no_capacity + add x11, x1, x2, LSL #3 /* r11 = batch + len * 8 */ sub w10, w10, w9 /* r10 = free capacity */ - cmp w3, w10 - csel w10, w3, w10, ls /* r10 = min(len, free capacity), amount we are + cmp w2, w10 + csel w10, w2, w10, ls /* r10 = min(len, free capacity), amount we are pushing */ add x13, x9, x10 /* r13 = current + amount we are pushing. */ add x9, x8, x9, LSL #3 /* r9 = current cpu slab stack */ add x14, x8, x13, LSL #3 /* r14 = new current address */ -.LTcmallocSlab_Internal_PushBatch_FixedShift_loop: + tst w10, #1 + beq .LTcmallocSlab_Internal_PushBatch_loop ldr x12, [x11, #-8]! /* r12 = [--r11] */ str x12, [x9], #8 /* [r9++] = r12 */ + cmp w10, #1 + beq .LTcmallocSlab_Internal_PushBatch_store +.LTcmallocSlab_Internal_PushBatch_loop: + ldr q4, [x11, #-16]! /* q4 = [r11 - 2], r11 -= 2 */ + str q4, [x9], #16 /* [r9 += 2] = q4 */ cmp x9, x14 /* if current cpu slab address == new current address */ - bne .LTcmallocSlab_Internal_PushBatch_FixedShift_loop - strh w13, [x4] /* store new current index */ -.LTcmallocSlab_Internal_PushBatch_FixedShift_commit: + bne .LTcmallocSlab_Internal_PushBatch_loop +.LTcmallocSlab_Internal_PushBatch_store: + strh w13, [x15] /* store new current index */ +.LTcmallocSlab_Internal_PushBatch_commit: mov x0, x10 ret -.LTcmallocSlab_Internal_PushBatch_FixedShift_no_capacity: +.LTcmallocSlab_Internal_PushBatch_no_capacity: mov x0, #0 ret - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_PushBatch_FixedShift) -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PushBatch_FixedShift) - -/* size_t TcmallocSlab_Internal_PopBatch_FixedShift( - * void *ptr (x0), - * size_t cl (w1), - * void** batch (x2), - * size_t len (w3) { - * uint64_t r8 = __rseq_abi.cpu_id - * uint64_t* r8 = CpuMemoryStart(ptr, r8) - * Header* hdr = GetHeader(r8, cl) + CFI(.cfi_endproc) +ENCODE_SIZE(TcmallocSlab_Internal_PushBatch) +DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PushBatch) + +/* size_t TcmallocSlab_Internal_PopBatch( + * size_t size_class (x0), + * void** batch (x1), + * size_t len (x2), + * std::atomic* begin_ptr (x3)) { + * uint64_t* r8 = tcmalloc_rseq.slabs; + * if ((r8 & TCMALLOC_CACHED_SLABS_BIT) == 0) return 0; + * r8 &= ~TCMALLOC_CACHED_SLABS_BIT; + * Header* hdr = GetHeader(r8, size_class) * uint64_t r9 = hdr->current - * uint64_t r10 = hdr->begin + * uint64_t r10 = *begin_ptr * if (r9 <= r10) return 0 * r11 = min(len, r9 - r10) * r13 = r8 + r9 * 8 * r9 = r9 - r11 - * r12 = r2 - * r14 = r2 + r11 * 8 + * r12 = r1 + * r14 = r1 + r11 * 8 * loop: * r10 = *(r13 -= 8) (pre-index) Pop from slab - * *(r12+=8) = r10 (post-index) Push to Batch + * *(r12 += 8) = r10 (post-index) Push to Batch * if (r12 != r14) goto loop * hdr->current = r9 * return r11 * } */ .p2align 6 /* aligns to 2^6 with NOP filling */ - .globl TcmallocSlab_Internal_PopBatch_FixedShift - .type TcmallocSlab_Internal_PopBatch_FixedShift, @function -TcmallocSlab_Internal_PopBatch_FixedShift: - .cfi_startproc + .globl TcmallocSlab_Internal_PopBatch + .type TcmallocSlab_Internal_PopBatch, @function +TcmallocSlab_Internal_PopBatch: + CFI(.cfi_startproc) BTI_C - START_RSEQ(TcmallocSlab_Internal_PopBatch_FixedShift) - FETCH_CPU(w8) - lsl x8, x8, #TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT /* multiply cpu by 256k */ - add x8, x0, x8 - add x4, x8, x1, LSL #3 - ldrh w9, [x4] /* current */ - ldrh w10, [x4, #4] /* begin */ + START_RSEQ(TcmallocSlab_Internal_PopBatch) + FETCH_SLABS(x8) + tbz x8, #TCMALLOC_CACHED_SLABS_BIT, .LTcmallocSlab_Internal_PopBatch_no_items + and x8, x8, #~TCMALLOC_CACHED_SLABS_MASK + add x15, x8, x0, LSL #2 + ldrh w9, [x15] /* current */ + ldrh w10, [x3] /* begin */ cmp w10, w9 - bhs .LTcmallocSlab_Internal_PopBatch_FixedShift_no_items + bhs .LTcmallocSlab_Internal_PopBatch_no_items sub w11, w9, w10 /* r11 = available items */ - cmp w3, w11 - csel w11, w3, w11, ls /* r11 = min(len, available items), amount we are + cmp w2, w11 + csel w11, w2, w11, ls /* r11 = min(len, available items), amount we are popping */ add x13, x8, x9, LSL #3 /* r13 = current cpu slab stack */ sub x9, x9, x11 /* update new current */ - mov x12, x2 /* r12 = batch */ - add x14, x2, x11, LSL #3 /* r14 = batch + amount we are popping*8 */ -.LTcmallocSlab_Internal_PopBatch_FixedShift_loop: + mov x12, x1 /* r12 = batch */ + add x14, x1, x11, LSL #3 /* r14 = batch + amount we are popping*8 */ + tst w11, #1 + beq .LTcmallocSlab_Internal_PopBatch_loop ldr x10, [x13, #-8]! /* r10 = [--r13] */ str x10, [x12], #8 /* [r12++] = r10 */ + cmp w11, #1 + beq .LTcmallocSlab_Internal_PopBatch_store +.LTcmallocSlab_Internal_PopBatch_loop: + ldr q4, [x13, #-16]! /* q4 = [r13 - 2], r13 -= 2 */ + str q4, [x12], #16 /* [r12 += 2] = q4 */ cmp x12, x14 /* if current batch == batch + amount we are popping */ - bne .LTcmallocSlab_Internal_PopBatch_FixedShift_loop - strh w9, [x4] /* store new current */ -.LTcmallocSlab_Internal_PopBatch_FixedShift_commit: + bne .LTcmallocSlab_Internal_PopBatch_loop +.LTcmallocSlab_Internal_PopBatch_store: + strh w9, [x15] /* store new current */ +.LTcmallocSlab_Internal_PopBatch_commit: mov x0, x11 ret -.LTcmallocSlab_Internal_PopBatch_FixedShift_no_items: +.LTcmallocSlab_Internal_PopBatch_no_items: mov x0, #0 ret - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_PopBatch_FixedShift) -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PopBatch_FixedShift) - - .globl TcmallocSlab_Internal_Push - .type TcmallocSlab_Internal_Push, @function -TcmallocSlab_Internal_Push: -.LTcmallocSlab_Internal_Push_entry: - .cfi_startproc - // Arguments use: - // * x0: (Argument: Slabs*) cpu_0_slab_ptr - // * x1: (Argument: uintptr_t) cl - // * x2: (Argument: uintptr_t) p - // * w3: (Argument: size_t) shift - // * x4: (Argument: uintptr_t) f - // Return value: current CPU - // Available x5-x15 - - BTI_C - START_RSEQ(TcmallocSlab_Internal_Push) - FETCH_CPU(w8) - lsl x9, x8, x3 - add x9, x0, x9 - add x10, x9, x1, LSL #3 - ldrh w12, [x10] /* current */ - ldrh w11, [x10, #6] /* end */ - cmp w11, w12 - ble .LTcmallocSlab_Internal_Push_no_capacity - str x2, [x9, x12, LSL #3] - add w12, w12, #1 - strh w12, [x10] -.LTcmallocSlab_Internal_Push_commit: - mov x0, x8 - ret -.LTcmallocSlab_Internal_Push_no_capacity: - mov x0, x8 - TAILCALL(x4) -.LTcmallocSlab_Internal_Push_region3: - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_Push) -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_Push) - - - .globl TcmallocSlab_Internal_Push_FixedShift - .type TcmallocSlab_Internal_Push_FixedShift, @function -TcmallocSlab_Internal_Push_FixedShift: - .cfi_startproc - // Arguments use: - // * x0: (Argument: Slabs*) cpu_0_slab_ptr - // * x1: (Argument: uintptr_t) cl - // * x2: (Argument: uintptr_t) p - // * x3: (Argument: uintptr_t) f - // Return value: current CPU - // Available x4-x15 - - BTI_C - START_RSEQ(TcmallocSlab_Internal_Push_FixedShift) - FETCH_CPU(w8) - lsl x9, x8, #TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT - add x9, x0, x9 - add x10, x9, x1, LSL #3 - ldrh w12, [x10] /* current */ - ldrh w11, [x10, #6] /* end */ - cmp w11, w12 - ble .LTcmallocSlab_Internal_Push_FixedShift_no_capacity - str x2, [x9, x12, LSL #3] - add w12, w12, #1 - strh w12, [x10] -.LTcmallocSlab_Internal_Push_FixedShift_commit: - mov x0, x8 - ret -.LTcmallocSlab_Internal_Push_FixedShift_no_capacity: - mov x0, x8 - TAILCALL(x3) - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_Push_FixedShift) -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_Push_FixedShift) - - .globl TcmallocSlab_Internal_Pop_FixedShift - .type TcmallocSlab_Internal_Pop_FixedShift, @function -TcmallocSlab_Internal_Pop_FixedShift: - .cfi_startproc - // Arguments use: - // * x0: (Argument: Slabs*) cpu_0_slab_ptr - // * x1: (Argument: uintptr_t) cl - // * x2: (Argument: uintptr_t) f - // Return value: current CPU - // Available x3-x15 - - BTI_C - START_RSEQ(TcmallocSlab_Internal_Pop_FixedShift) - FETCH_CPU(w8) /* r8 = CPU */ - lsl x9, x8, #TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT - /* r9 = CPU shifted */ - add x9, x0, x9 /* r9 = start of CPU region */ - add x10, x9, x1, LSL #3 /* r10 = start of slab header */ - ldrh w12, [x10] /* r12 = current index */ - ldrh w11, [x10, #4] /* r11 = begin index */ - cmp w11, w12 /* if begin >= current */ - bge .LTcmallocSlab_Internal_Pop_FixedShift_no_items - sub w12, w12, #1 /* r12 = current-- */ - ldr x3, [x9, x12, LSL #3] /* r3 = [start + current * 8] */ - strh w12, [x10] /* store new current index */ -.LTcmallocSlab_Internal_Pop_FixedShift_commit: - mov x0, x3 /* return popped item */ - ret -.LTcmallocSlab_Internal_Pop_FixedShift_no_items: - mov x0, x8 /* call overflow handler with CPU ID */ - TAILCALL(x2) - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_Pop_FixedShift) -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_Pop_FixedShift) - - .globl TcmallocSlab_Internal_Pop - .type TcmallocSlab_Internal_Pop, @function -TcmallocSlab_Internal_Pop: - .cfi_startproc - // Arguments use: - // * x0: (Argument: Slabs*) cpu_0_slab_ptr - // * x1: (Argument: uintptr_t) cl - // * x2: (Argument: uintptr_t) f - // * w3: (Argument: size_t) shift - // Return value: Value - // Available x4-x15 - - BTI_C - START_RSEQ(TcmallocSlab_Internal_Pop) - FETCH_CPU(w8) /* r8 = CPU ID */ - lsl x9, x8, x3 /* x9 = CPU shifted by (r3) */ - add x9, x0, x9 /* x9 = start of this CPU region */ - add x10, x9, x1, LSL #3 /* r10 = slab header addr */ - ldrh w12, [x10] /* r12 = current index */ - ldrh w11, [x10, #4] /* x11 = begin index */ - cmp w11, w12 /* if begin >= current */ - bge .LTcmallocSlab_Internal_Pop_no_items - sub w12, w12, #1 /* r12 = current-- */ - ldr x4, [x9, x12, LSL #3] /* r4 = [start + current * 8] */ - strh w12, [x10] /* update current index */ -.LTcmallocSlab_Internal_Pop_commit: - mov x0, x4 /* return popped item */ - ret -.LTcmallocSlab_Internal_Pop_no_items: - mov x0, x8 /* call overflow handler with CPU ID */ - TAILCALL(x2) - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_Pop) -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_Pop) + CFI(.cfi_endproc) +ENCODE_SIZE(TcmallocSlab_Internal_PopBatch) +DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PopBatch) .section .note.GNU-stack,"",@progbits diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_asm.S b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_asm.S index 0219a2760a06..1219f8a89238 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_asm.S +++ b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_asm.S @@ -16,16 +16,51 @@ #include "tcmalloc/internal/percpu.h" +#ifdef __GCC_HAVE_DWARF2_CFI_ASM +#define CFI(...) __VA_ARGS__ +#else +#define CFI(...) +#endif + #if TCMALLOC_PERCPU_RSEQ_SUPPORTED_PLATFORM #if defined(__x86_64__) #include "tcmalloc/internal/percpu_rseq_x86_64.S" -#elif defined(__ppc__) -#include "tcmalloc/internal/percpu_rseq_ppc.S" #elif defined(__aarch64__) #include "tcmalloc/internal/percpu_rseq_aarch64.S" #else #error "RSEQ support expected, but not found." #endif + +// See the comment about data layout in percpu.h for details. +.type tcmalloc_sampler, @object +.type tcmalloc_cached_vcpu, @object +.type tcmalloc_slabs, @object +.type __rseq_abi, @object +.section .tdata, "awT", @progbits +.globl tcmalloc_sampler +.globl tcmalloc_cached_vcpu +.globl tcmalloc_slabs +.globl __rseq_abi +.p2align 6 +.zero 64 + 32 - TCMALLOC_SAMPLER_SIZE - 8 +tcmalloc_sampler: +.zero TCMALLOC_SAMPLER_SIZE +tcmalloc_cached_vcpu: +.long 0xffffffff // cpu_id (kCpuIdUninitialized) +tcmalloc_slabs: +.long 0 +__rseq_abi: +.long 0 // cpu_id_start +.long 0xffffffff // cpu_id (kCpuIdUninitialized) +.quad 0 // rseq_cs +.long 0 // flags +.quad 0 // padding +.short 0xffff // numa_node_id (kCpuIdUninitialized) +.short 0xffff // vcpu_id (kCpuIdUninitialized) +.size __rseq_abi, 32 +.size tcmalloc_sampler, TCMALLOC_SAMPLER_SIZE +.size tcmalloc_slabs, 8 + #endif // TCMALLOC_PERCPU_RSEQ_SUPPORTED_PLATFORM // We do not need an executable stack. Put this outside the @@ -33,9 +68,9 @@ // .note.GNU-stack section implies executable stack" errors. // // Cf. http://en.chys.info/2010/12/note-gnu-stack/ -#if defined(__arm__) || defined(__PPC64__) +#if defined(__arm__) .section .note.GNU-stack, "", %progbits #else .section .note.GNU-stack, "", @progbits -#endif // __arm__ || __PPC64__ +#endif // __arm__ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_ppc.S b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_ppc.S deleted file mode 100644 index 234f28c2e7ea..000000000000 --- a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_ppc.S +++ /dev/null @@ -1,606 +0,0 @@ -/* - * Copyright 2019 The TCMalloc Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// Rseq critical section functions and restart handlers. -// -// They must also avoid writing the nonvolatile and reserved general purpose -// registers defined by the Power Architecture 64-Bit ELF V2 ABI -// -// * r1-r2 -// * r13 -// * r14-r31 -// -// Finally, note that the restart handler reserves the right to clobber -// condition registers. This means that critical section functions must not -// explicitly or implicitly read condition registers outside of their -// [start, limit) critical regions. - -#ifndef __ppc__ -#error "percpu_rseq_ppc.S should only be included for PPC builds" -#endif - -#include "tcmalloc/internal/percpu.h" - -// Use the ELFv2 ABI. -.abiversion 2 -.section google_malloc, "ax" - -//////////////////////////////////////////////////////////////////////// -// Macros -//////////////////////////////////////////////////////////////////////// - -/* - * Provide a directive to specify the size of symbol "label", relative to the - * current location and its start. - */ -#define ENCODE_SIZE(label) .size label, . - label; - -// Place the CPU number into the bottom 12 bits of dst. The upper 52 bits are -// unspecified. -// -// See GetCurrentCpu() for notes on the implementation. -#define GET_CPU_UNMASKED(dst) \ - mfspr dst, 259 - -// Given an unmasked CPU number, put the interesting parts into dst. -#define MASK_CPU(dst, src) \ - clrldi dst, src, 52 - -// Like GET_CPU_UNMASKED, but guarantees that the upper bits are cleared. May -// be slower than the unmasked version. -#define GET_CPU(dst) \ - GET_CPU_UNMASKED(dst); \ - MASK_CPU(dst, dst) - -// This is part of the upstream rseq ABI. The 4 bytes prior to the abort IP -// must match TCMALLOC_PERCPU_RSEQ_SIGNATURE (as configured by our rseq -// syscall's signature parameter). This signature is used to annotate valid -// abort IPs (since rseq_cs could live in a user-writable segment). -#define SIGN_ABORT() \ - .long TCMALLOC_PERCPU_RSEQ_SIGNATURE; - -// DEFINE_UPSTREAM_CS triggers the generation of rseq_cs table (the triple of -// start, commit, abort IPs) and a trampoline function. -// -// Upstream API Exposition: -// -// START_RSEQ() // vvvvv emits a bunch of things -// global entry point: -// TOC setup -// METHOD_critical_abort: -// local entry point: -// store rseq_cs to __rseq_abi.rseq_cs, starting restartable sequence -// METHOD_start: // Emitted as part of START_RSEQ() -// // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -// -// GET_CPU...() // Reads current CPU -// ... -// single store // Commits sequence -// METHOD_critical_limit: -// ...return... -// -// START_RSEQ does several things: -// * We need to set up the TOC pointer for global entry points. -// * When restarting, we return to the local entry point, since the TOC pointer -// is left intact from the restart. METHOD_critical_abort and local entry -// point are therefore the same address. -// * It stores to the TLS to register that we're in a restartable sequence with -// the kernel. -// -// This process is assisted by the DEFINE_UPSTREAM_CS macro, which encodes a -// (rodata) constant table, whose address is used to start the critical -// section, and the abort trampoline. -// -// The trampoline is used because: -// 1. Restarts are expected to be rare, so the extra jump when restarting is -// expected to be infrequent. -// 2. The upstream restartable sequence implementation expects the trailing 4 -// bytes of the abort PC to be "signed" (to prevent manipulation of the PC -// to an arbitrary choice). For us, this is -// TCMALLOC_PERCPU_RSEQ_SIGNATURE. This value is passed to the kernel -// during configuration of the rseq syscall. This would either need to be -// encoded as a nop* at the start of every restartable sequence, increasing -// instruction cache pressure, or placed directly before the entry point. -// -// * The upstream rseq protocol appears to be converging on using a trap -// instruction (twui), so we cannot allow it to appear anywhere in our -// actual executed path. -// -// Upon restart, the (upstream) kernel API clears the per-thread restartable -// sequence state. We return to METHOD_abort (rather than METHOD_start), as we -// need to reinitialize this value. - -// This macro defines a relocation associated with the provided label to keep -// section GC from discarding it independently of label. -#if !defined(__clang_major__) || __clang_major__ >= 9 -#define PINSECTION(label) .reloc 0, R_PPC64_NONE, label -#else -#define PINSECTION(label) -#endif - -// TODO(b/141629158): __rseq_cs only needs to be writeable to allow for -// relocations, but could be read-only for non-PIE builds. -#define DEFINE_UPSTREAM_CS(label) \ - .pushsection __rseq_cs, "aw"; \ - .balign 32; \ - .protected __rseq_cs_##label; \ - .type __rseq_cs_##label,@object; \ - .size __rseq_cs_##label,32; \ - __rseq_cs_##label: \ - .long TCMALLOC_PERCPU_RSEQ_VERSION, TCMALLOC_PERCPU_RSEQ_FLAGS; \ - .quad .L##label##_critical_start; \ - .quad .L##label##_critical_limit - .L##label##_critical_start; \ - .quad label##_trampoline; \ - PINSECTION(.L##label##array); \ - .popsection; \ - .pushsection __rseq_cs_ptr_array, "aw"; \ - .L##label##array: \ - .quad __rseq_cs_##label; \ - .popsection; \ - .pushsection rseq_trampoline, "ax"; \ - SIGN_ABORT(); \ - .globl label##_trampoline; \ - .type label##_trampoline, @function; \ -label##_trampoline: \ - .cfi_startproc; \ - b .L##label##_critical_abort; \ - .cfi_endproc; \ - .size label##_trampoline, . - label##_trampoline; \ - .popsection - -// With PIE: We have initial-exec TLS, even in the presence of position -// independent code. -#if !defined(__PIC__) || defined(__PIE__) - -#define START_RSEQ(label) \ - .L##label##_gep0: \ - addis %r2, %r12, .TOC.-.L##label##_gep0@ha; \ - addi %r2, %r2, .TOC.-.L##label##_gep0@l; \ - .L##label##_critical_abort: \ - .L##label##_lep0: \ - .localentry label,.-label; \ - addis %r9, %r2, __rseq_cs_##label@toc@ha; \ - addi %r9, %r9, __rseq_cs_##label@toc@l; \ - addis %r10, %r13, __rseq_abi@tprel@ha; \ - addi %r10, %r10, __rseq_abi@tprel@l; \ - std %r9, 8(%r10); \ - .L##label##_critical_start: - -#else /* !defined(__PIC__) || defined(__PIE__) */ - -// Handle non-initial exec TLS. When performance matters, we should be using -// initial-exec TLS. -// -// We need to caller-save r3-r8, as they are our arguments to the actual -// restartable sequence code. - -#define START_RSEQ(label) \ - .L##label##_gep0: \ - addis %r2, %r12, .TOC.-.L##label##_gep0@ha; \ - addi %r2, %r2, .TOC.-.L##label##_gep0@l; \ - .L##label##_critical_abort: \ - .L##label##_lep0: \ - .localentry label,.-label; \ - mflr 0; \ - std %r0, 0x10(1); \ - std %r3, -0x10(1); \ - std %r4, -0x18(1); \ - std %r5, -0x20(1); \ - std %r6, -0x28(1); \ - std %r7, -0x30(1); \ - std %r8, -0x38(1); \ - stdu %r1, -0x200(1); \ - bl tcmalloc_tls_fetch_pic; \ - nop; \ - mr %r10, %r3; \ - addi %r1, %r1, 0x200; \ - ld %r8, -0x38(1); \ - ld %r7, -0x30(1); \ - ld %r6, -0x28(1); \ - ld %r5, -0x20(1); \ - ld %r4, -0x18(1); \ - ld %r3, -0x10(1); \ - ld %r0, 0x10(1); \ - mtlr 0; \ - addis %r9, %r2, __rseq_cs_##label@toc@ha; \ - addi %r9, %r9, __rseq_cs_##label@toc@l; \ - std %r9, 8(%r10); \ - .L##label##_critical_start: - -#endif - -//////////////////////////////////////////////////////////////////////// -// TcmallocSlab_Internal_PerCpuCmpxchg64 -//////////////////////////////////////////////////////////////////////// - -.globl TcmallocSlab_Internal_PerCpuCmpxchg64 -.type TcmallocSlab_Internal_PerCpuCmpxchg64, @function -TcmallocSlab_Internal_PerCpuCmpxchg64: -.LTcmallocSlab_Internal_PerCpuCmpxchg64_entry: - .cfi_startproc - // Register use: - // - // * r3: (Argument: int64) target_cpu - // * r4: (Argument: intptr_t*) p - // * r5: (Argument: intptr_t) old_val - // * r6: (Argument: intptr_t) new_val - // * r7: The current CPU number. - // * r8: The current value of *p. - // - - START_RSEQ(TcmallocSlab_Internal_PerCpuCmpxchg64) - - // Are we running on the target CPU? - GET_CPU(%r7) - cmpd %r7, %r3 - bne .LCAS_wrong_cpu - - // Load the current value of *p. - ld %r8, 0(%r4) - - // Is the value up to date? - cmpd %r8, %r5 - bne .LCAS_wrong_value - - // Store the new value, committing the operation. - std %r6, 0(%r4) -.LTcmallocSlab_Internal_PerCpuCmpxchg64_critical_limit: - - // Return the target CPU, which is already in r3. - blr - -.LCAS_wrong_cpu: - // Return the current CPU. - mr %r3, %r7 - blr - -.LCAS_wrong_value: - // Return -1. - li %r3, -1 - blr - -.LTcmallocSlab_Internal_PerCpuCmpxchg64_function_limit: - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_PerCpuCmpxchg64); -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PerCpuCmpxchg64); - - -//////////////////////////////////////////////////////////////////////// -// TcmallocSlab_Internal_Push -//////////////////////////////////////////////////////////////////////// - -.globl TcmallocSlab_Internal_Push -.type TcmallocSlab_Internal_Push, @function -TcmallocSlab_Internal_Push: -.LTcmallocSlab_Internal_Push_entry: - .cfi_startproc - // Arguments use: - // * r3: (Argument: Slabs*) cpu_0_slab_ptr - // * r4: (Argument: uintptr_t) cl - // * r5: (Argument: uintptr_t) p - // * r6: (Argument: size_t) shift - // * r7: (Argument: uintptr_t) f - // Return value: current CPU - // Available r8 r9 r10 r11 r12 - // Note that r12 may be overwritten in rseq_restart_address_internal so - // cannot be relied upon across restartable sequence boundaries. - - START_RSEQ(TcmallocSlab_Internal_Push) - - GET_CPU(%r8) // r8 = current CPU, includes MASK operation - sld %r9, %r8, %r6 // r9 = r8 << shift (r6) - add %r9, %r3, %r9 // r9 = start of this CPU region - rldicr %r10, %r4, 3, 60 // r10 = header offset for class size cl (r4) - add %r10, %r9, %r10 // r10 = slab header addr (class offset + CPU base) - lhz %r12, 0(%r10) // r12 = current index - lhz %r11, 6(%r10) // r11 = length - cmpld %cr7, %r11, %r12 // compare current index with length - ble %cr7, .LTcmallocSlab_Internal_Push_no_capacity - rldicr %r11, %r12, 3, 60 // r11 = offset of current index - addi %r12, %r12, 1 // current index += 1 - stdx %r5, %r9, %r11 // store pointer p (r5) into current offset - sth %r12, 0(%r10) // update current index - -.LTcmallocSlab_Internal_Push_critical_limit: - mr %r3, %r8 // Return current CPU in r3 - blr - -.LTcmallocSlab_Internal_Push_no_capacity: - mr %r3, %r8 // Place current CPU in r3 - // r7 already contains target function - b .LPushOverflowTrampoline - -.LTcmallocSlab_Internal_Push_function_limit: - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_Push); -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_Push); - -//////////////////////////////////////////////////////////////////////// -// TcmallocSlab_Internal_Push_FixedShift -//////////////////////////////////////////////////////////////////////// - -.globl TcmallocSlab_Internal_Push_FixedShift -.type TcmallocSlab_Internal_Push_FixedShift, @function -TcmallocSlab_Internal_Push_FixedShift: -.LTcmallocSlab_Internal_Push_FixedShift_entry: - .cfi_startproc - // Arguments use: - // * r3: (Argument: Slabs*) cpu_0_slab_ptr - // * r4: (Argument: uintptr_t) cl - // * r5: (Argument: uintptr_t) p - // * r6: (Argument: uintptr_t) f - - START_RSEQ(TcmallocSlab_Internal_Push_FixedShift) - - GET_CPU_UNMASKED(%r7) // r7 = unmasked CPU - // Mask upper 52 bits of %r7 and shift left in single - // operation. Removes the need to have a separate - // MASK operation on the critical path. - clrlsldi %r8, %r7, 52, TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT - add %r8, %r3, %r8 // r8 = start of this CPU region - rldicr %r9, %r4, 3, 60 // r9 = start of header - add %r9, %r8, %r9 // r9 = slab header addr - lhz %r10, 0(%r9) // r10 = current index - lhz %r11, 6(%r9) // r11 = end index - cmpld %cr7, %r11, %r10 // Check for space - ble %cr7, .LTcmallocSlab_Internal_Push_FixedShift_no_capacity - rldicr %r11, %r10, 3, 60 // r11 = offset of current index - addi %r10, %r10, 1 // current index ++ - stdx %r5, %r8, %r11 // store the item (from r5) - sth %r10, 0(%r9) // store current index - -.LTcmallocSlab_Internal_Push_FixedShift_critical_limit: - MASK_CPU(%r3, %r7) // Return and mask CPU into %r3 - blr - -.LTcmallocSlab_Internal_Push_FixedShift_no_capacity: - MASK_CPU(%r3, %r7) // Move and mask CPU into %r3 - mr %r7, %r6 // Move target function into r7 - b .LPushOverflowTrampoline - -.LTcmallocSlab_Internal_Push_FixedShift_function_limit: - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_Push_FixedShift); -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_Push_FixedShift); - - -//////////////////////////////////////////////////////////////////////// -// TcmallocSlab_Internal_Pop -//////////////////////////////////////////////////////////////////////// - -.globl TcmallocSlab_Internal_Pop -.type TcmallocSlab_Internal_Pop, @function -TcmallocSlab_Internal_Pop: -.LTcmallocSlab_Internal_Pop_entry: - .cfi_startproc - // Arguments use: - // * r3: (Argument: Slabs*) cpu_0_slab_ptr - // * r4: (Argument: uintptr_t) cl - // * r5: (Argument: uintptr_t) f - // * r6: (Argument: size_t) shift - // Available r7 r8 r9 r10 r11 - // r12 can be used as a temporary within rseq - - START_RSEQ(TcmallocSlab_Internal_Pop) - - GET_CPU(%r7) // r7 = CPU, includes mask operation - sld %r12, %r7, %r6 // r12 = CPU shifted by shift (r6) - add %r12, %r3, %r12 // r12 = start of this CPU region - rldicr %r8, %r4, 3, 60 // r8 = offset to class size - add %r8, %r12, %r8 // r8 = slab header addr for class size - lhz %r9, 0(%r8) // r9 = current index - lhz %r10, 4(%r8) // r10 = begin - cmpld %cr7, %r10, %r9 // Check that we have items to pop - bge %cr7, .LTcmallocSlab_Internal_Pop_no_item - subi %r9, %r9, 1 // r9 = current index -- - rldicr %r10, %r9, 3, 60 // r10 = offset to current item - ldx %r11, %r12, %r10 // load the item from base + index - sth %r9, 0(%r8) // store current index - -.LTcmallocSlab_Internal_Pop_critical_limit: - // Move the item into r3, now that it's safe to do so. - mr %r3, %r11 - blr - -.LTcmallocSlab_Internal_Pop_no_item: - mr %r3, %r7 // Place CPU into r3 - b .LPopUnderflowTrampoline - -.LTcmallocSlab_Internal_Pop_function_limit: - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_Pop); -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_Pop); - -//////////////////////////////////////////////////////////////////////// -// TcmallocSlab_Internal_Pop_FixedShift -//////////////////////////////////////////////////////////////////////// - -.globl TcmallocSlab_Internal_Pop_FixedShift -.type TcmallocSlab_Internal_Pop_FixedShift, @function -TcmallocSlab_Internal_Pop_FixedShift: -.LTcmallocSlab_Internal_Pop_FixedShift_entry: - .cfi_startproc - // Arguments use: - // * r3: (Argument: Slabs*) cpu_0_slab_ptr - // * r4: (Argument: uintptr_t) cl - // * r5: (Argument: uintptr_t) f - - START_RSEQ(TcmallocSlab_Internal_Pop_FixedShift) - - GET_CPU_UNMASKED(%r6) // r6 = current CPU - // Following instruction combines mask and shift - clrlsldi %r7, %r6, 52, TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT - // r7 = header offset - add %r7, %r3, %r7 // r7 = start of this CPU region - rldicr %r8, %r4, 3, 60 // r8 = offset of size class - add %r8, %r7, %r8 // r8 = slab header addr - lhz %r9, 0(%r8) // r9 = current index - lhz %r10, 4(%r8) // r10 = begin index - cmpld %cr7, %r10, %r9 // Check that there are elements available - bge %cr7, .LTcmallocSlab_Internal_Pop_FixedShift_no_item - subi %r9, %r9, 1 // current index -- - rldicr %r10, %r9, 3, 60 // r10 = offset of current index - ldx %r11, %r7, %r10 // r11 = load the item - sth %r9, 0(%r8) // update current index - -.LTcmallocSlab_Internal_Pop_FixedShift_critical_limit: - // Move the item into r3, now that it's safe to do so. - mr %r3, %r11 - blr - -.LTcmallocSlab_Internal_Pop_FixedShift_no_item: - MASK_CPU(%r3, %r6) // Extract CPU from unmasked value in %r6 - b .LPopUnderflowTrampoline - -.LTcmallocSlab_Internal_Pop_FixedShift_function_limit: - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_Pop_FixedShift); -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_Pop_FixedShift); - -//////////////////////////////////////////////////////////////////////// -// TcmallocSlab_Internal_PushBatch_FixedShift -//////////////////////////////////////////////////////////////////////// - -.globl TcmallocSlab_Internal_PushBatch_FixedShift -.type TcmallocSlab_Internal_PushBatch_FixedShift, @function -TcmallocSlab_Internal_PushBatch_FixedShift: -.LTcmallocSlab_Internal_PushBatch_FixedShift_entry: - .cfi_startproc - // Arguments use: - // * r3: (Argument: Slabs*) cpu_0_slab_ptr - // * r4: (Argument: uintptr_t) cl - // * r5: (Argument: uintptr_t) batch - // * r6: (Argument: uintptr_t) len - - START_RSEQ(TcmallocSlab_Internal_PushBatch_FixedShift) - - GET_CPU_UNMASKED(%r7) - clrlsldi %r8, %r7, 52, TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT - add %r8, %r3, %r8 // r8 - start of this CPU region - sldi %r9, %r4, 3 - add %r9, %r8, %r9 // r9 - slab header addr - lhz %r10, 0(%r9) // r10 - current - lhz %r11, 6(%r9) // r11 - end - sldi %r7, %r6, 3 // r7 - len * 8 - cmpld %cr7, %r11, %r10 // current < end? - ble %cr7, .LTcmallocSlab_Internal_PushBatch_FixedShift_critical_limit - sub %r11, %r11, %r10 // r11 - available capacity - // r11 = min(r11, r6) - cmpld %cr7, %r6, %r11 - bge %cr7, .LTcmallocSlab_Internal_PushBatch_FixedShift_min - mr %r11, %r6 -.LTcmallocSlab_Internal_PushBatch_FixedShift_min: - add %r11, %r10, %r11 - sldi %r11, %r11, 3 - sldi %r10, %r10, 3 - - // At this point: - // r5 - batch, r7 - offset in the batch - // r8 - cpu region, r10 - offset into the cpu region, r11 - limit of offset -.LTcmallocSlab_Internal_PushBatch_FixedShift_loop: - subi %r7, %r7, 8 - ldx %r12, %r5, %r7 // load the item - stdx %r12, %r8, %r10 // store the item - addi %r10, %r10, 8 - cmpld %cr7, %r10, %r11 - bne %cr7, .LTcmallocSlab_Internal_PushBatch_FixedShift_loop - rotrdi %r10, %r10, 3 - sth %r10, 0(%r9) // update current - -.LTcmallocSlab_Internal_PushBatch_FixedShift_critical_limit: - // return r6 - r7 / 8 - rotrdi %r7, %r7, 3 - sub %r3, %r6, %r7 - blr - -.LTcmallocSlab_Internal_PushBatch_FixedShift_function_limit: - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_PushBatch_FixedShift); -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PushBatch_FixedShift); - -//////////////////////////////////////////////////////////////////////// -// TcmallocSlab_Internal_PopBatch_FixedShift -//////////////////////////////////////////////////////////////////////// - -.globl TcmallocSlab_Internal_PopBatch_FixedShift -.type TcmallocSlab_Internal_PopBatch_FixedShift, @function -TcmallocSlab_Internal_PopBatch_FixedShift: -.LTcmallocSlab_Internal_PopBatch_FixedShift_entry: - .cfi_startproc - // Arguments use: - // * r3: (Argument: Slabs*) cpu_0_slab_ptr - // * r4: (Argument: uintptr_t) cl - // * r5: (Argument: uintptr_t) batch - // * r6: (Argument: uintptr_t) len - - START_RSEQ(TcmallocSlab_Internal_PopBatch_FixedShift) - - GET_CPU_UNMASKED(%r7) - clrlsldi %r7, %r7, 52, TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT - add %r7, %r3, %r7 // r7 - start of this CPU region - sldi %r8, %r4, 3 - add %r8, %r7, %r8 // r8 - slab header addr - lhz %r9, 0(%r8) // r9 - current - lhz %r10, 4(%r8) // r10 - begin - li %r11, 0 // current position in batch - cmpld %cr7, %r10, %r9 - bge %cr7, .LTcmallocSlab_Internal_PopBatch_FixedShift_critical_limit - sub %r10, %r9, %r10 // r10 - available items - // r10 = min(r10, r6) - cmpld %cr7, %r6, %r10 - bge %cr7, .LTcmallocSlab_Internal_PopBatch_FixedShift_min - mr %r10, %r6 -.LTcmallocSlab_Internal_PopBatch_FixedShift_min: - sub %r10, %r9, %r10 - sldi %r10, %r10, 3 - sldi %r9, %r9, 3 - - // At this point: - // r5 - batch, r11 - offset in the batch - // r7 - cpu region, r9 - offset into the cpu region, r10 - limit of offset -.LTcmallocSlab_Internal_PopBatch_FixedShift_loop: - subi %r9, %r9, 8 - ldx %r12, %r7, %r9 // load the item - stdx %r12, %r5, %r11 // store the item - addi %r11, %r11, 8 - cmpld %cr7, %r9, %r10 - bne %cr7, .LTcmallocSlab_Internal_PopBatch_FixedShift_loop - rotrdi %r9, %r9, 3 - sth %r9, 0(%r8) // update current - -.LTcmallocSlab_Internal_PopBatch_FixedShift_critical_limit: - rotrdi %r3, %r11, 3 - blr - -.LTcmallocSlab_Internal_PopBatch_FixedShift_function_limit: - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_PopBatch_FixedShift); -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PopBatch_FixedShift); - - // Input: r7 points to the function to tail call. r3...r6 are args for it. -.LPushOverflowTrampoline: - mtctr %r7 - mr %r12, %r7 // Callee expects r12 to point to its first instruction. - bctr - - // Input: r5 points to the function to tail call. r3...r4 are args for it. -.LPopUnderflowTrampoline: - mtctr %r5 - mr %r12, %r5 // Callee expects r12 to point to its first instruction. - bctr - -.section .note.GNU-stack,"",%progbits - diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_unsupported.cc b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_unsupported.cc index 1438d8c3d826..249157d06749 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_unsupported.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_unsupported.cc @@ -15,7 +15,6 @@ // Provides skeleton RSEQ functions which raise a hard error in the case of // being erroneously called on an unsupported platform. -#include "tcmalloc/internal/logging.h" #include "tcmalloc/internal/percpu.h" #if !TCMALLOC_PERCPU_RSEQ_SUPPORTED_PLATFORM @@ -27,53 +26,31 @@ namespace subtle { namespace percpu { static void Unsupported() { - Crash(kCrash, __FILE__, __LINE__, - "RSEQ function called on unsupported platform."); + TC_BUG("RSEQ function called on unsupported platform."); } -int TcmallocSlab_Internal_PerCpuCmpxchg64(int target_cpu, intptr_t *p, - intptr_t old_val, intptr_t new_val) { +int TcmallocSlab_Internal_PerCpuCmpxchg64(int target_cpu, intptr_t* p, + intptr_t old_val, intptr_t new_val, + size_t virtual_cpu_id_offset) { Unsupported(); return -1; } -int TcmallocSlab_Internal_Push(void *ptr, size_t cl, void *item, size_t shift, - OverflowHandler f) { - Unsupported(); - return -1; -} - -int TcmallocSlab_Internal_Push_FixedShift(void *ptr, size_t cl, void *item, - OverflowHandler f) { - Unsupported(); - return -1; -} - -void *TcmallocSlab_Internal_Pop(void *ptr, size_t cl, UnderflowHandler f, - size_t shift) { - Unsupported(); - return nullptr; -} - -void *TcmallocSlab_Internal_Pop_FixedShift(void *ptr, size_t cl, - UnderflowHandler f) { - Unsupported(); - return nullptr; -} - -size_t TcmallocSlab_Internal_PushBatch_FixedShift(void *ptr, size_t cl, - void **batch, size_t len) { +size_t TcmallocSlab_Internal_PushBatch(size_t size_class, void** batch, + size_t len, uintptr_t slabs_and_shift, + size_t virtual_cpu_id_offset) { Unsupported(); return 0; } -size_t TcmallocSlab_Internal_PopBatch_FixedShift(void *ptr, size_t cl, - void **batch, size_t len) { +size_t TcmallocSlab_Internal_PopBatch(size_t size_class, void** batch, + size_t len, uintptr_t slabs_and_shift, + size_t virtual_cpu_id_offset) { Unsupported(); return 0; } -int PerCpuReadCycleCounter(int64_t *cycles) { +int PerCpuReadCycleCounter(int64_t* cycles) { Unsupported(); return -1; } diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_x86_64.S b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_x86_64.S index 866f4f90ca10..797fec5572fd 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_x86_64.S +++ b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_rseq_x86_64.S @@ -75,8 +75,7 @@ // distinct from label_start, as the return IP must be "signed" (see // SIGN_ABORT()). // -// TODO(b/141629158): __rseq_cs only needs to be writeable to allow for -// relocations, but could be read-only for non-PIE builds. +// __rseq_cs only needs to be writeable to allow for relocations. #define DEFINE_UPSTREAM_CS(label) \ .pushsection __rseq_cs, "aw"; \ .balign 32; \ @@ -98,9 +97,9 @@ .globl label##_trampoline; \ .type label##_trampoline, @function; \ label##_trampoline: \ - .cfi_startproc; \ + CFI(.cfi_startproc); \ jmp .L##label##_abort; \ - .cfi_endproc; \ + CFI(.cfi_endproc); \ .size label##_trampoline, . - label##_trampoline; // This is part of the upstream rseq ABI. The 4 bytes prior to the abort IP @@ -134,13 +133,15 @@ label##_trampoline: \ /* With PIE; have initial-exec TLS, even in the presence of position independent code. */ #if !defined(__PIC__) || defined(__PIE__) -#define FETCH_CPU(dest) movl %fs:__rseq_abi@TPOFF+4, dest; -#define FETCH_VCPU(dest) movzwl %fs:__rseq_abi@TPOFF+30, dest; -#define START_RSEQ(src) \ - .L##src##_abort: \ - leaq __rseq_cs_##src(%rip), %rax; \ - movq %rax, %fs:__rseq_abi@TPOFF+8; \ - .L##src##_start: +#define FETCH_CPU(dest, offset) \ + movzwl %fs:__rseq_abi@TPOFF(offset), dest; +#define FETCH_SLABS(dest) \ + movq %fs:__rseq_abi@TPOFF + TCMALLOC_RSEQ_SLABS_OFFSET, dest +#define START_RSEQ(src) \ + .L##src##_abort: \ + leaq __rseq_cs_##src(%rip), %rax; \ + movq %rax, %fs:__rseq_abi@TPOFF+8; \ + .L##src##_start: #else /* !defined(__PIC__) || defined(__PIE__) */ @@ -151,16 +152,14 @@ label##_trampoline: \ * tcmalloc_tls_fetch_pic does not appear in the restartable sequence's address * range. */ -#define FETCH_CPU(dest) \ - movl 4(%rax), dest; /* cpuid is 32-bits */ -#define FETCH_VCPU(dest) \ - movzwl 30(%rax), dest; /* vcpu_id is 16-bits */ +#define FETCH_CPU(dest, offset) movzwl (%rax, offset), dest; +#define FETCH_SLABS(dest) movq TCMALLOC_RSEQ_SLABS_OFFSET(%rax), dest #define START_RSEQ(src) \ .L##src##_abort: \ call tcmalloc_internal_tls_fetch_pic@PLT; \ leaq __rseq_cs_##src(%rip), %r11; \ movq %r11, 8(%rax); \ - .L##src##_start: + .L##src##_start: /* * We can safely call this function from within an RSEQ section as it only @@ -170,12 +169,12 @@ label##_trampoline: \ .local tcmalloc_internal_tls_fetch_pic .type tcmalloc_internal_tls_fetch_pic, @function tcmalloc_internal_tls_fetch_pic: - .cfi_startproc + CFI(.cfi_startproc) push %rbp - .cfi_def_cfa_offset 16 - .cfi_offset 6, -16 + CFI(.cfi_def_cfa_offset 16) + CFI(.cfi_offset 6, -16) mov %rsp, %rbp - .cfi_def_cfa_register 6 + CFI(.cfi_def_cfa_register 6) sub $0x30, %rsp mov %rsi, -0x08(%rbp) /* atypical abi: tcmalloc_tls_fetch_pic preserves regs */ mov %rdi, -0x10(%rbp) @@ -201,10 +200,10 @@ tcmalloc_internal_tls_fetch_pic: mov -0x30(%rbp), %r9 add $0x30, %rsp leave - .cfi_def_cfa_register 7 - .cfi_def_cfa_offset 8 + CFI(.cfi_def_cfa_register 7) + CFI(.cfi_def_cfa_offset 8) ret; /* &__rseq_abi in %rax */ - .cfi_endproc + CFI(.cfi_endproc) ENCODE_SIZE(tcmalloc_internal_tls_fetch_pic) #endif /* !defined(__PIC__) || defined(__PIE__) */ @@ -212,73 +211,19 @@ ENCODE_SIZE(tcmalloc_internal_tls_fetch_pic) /* start of atomic restartable sequences */ -/* - * NOTE: We don't use cmpxchgq in the following functions since this would - make checking the success of our commit operation dependent on flags (which - * are in turn clobbered by the restart region) -- furthermore we can't just - * retry to fill in the flags since the restarted cmpxchg may have actually - * succeeded; spuriously failing subsequent attempts. - */ - -/* - * int TcmallocSlab_Internal_PerCpuCmpxchg64(int target_cpu, long *p, - * long old_val, long new_val) - */ - .p2align 6; /* aligns to 2^6 with NOP filling */ - .globl TcmallocSlab_Internal_PerCpuCmpxchg64 - .type TcmallocSlab_Internal_PerCpuCmpxchg64, @function -TcmallocSlab_Internal_PerCpuCmpxchg64: - .cfi_startproc - START_RSEQ(TcmallocSlab_Internal_PerCpuCmpxchg64); - FETCH_CPU(%eax); - cmp %eax, %edi; /* check cpu vs current_cpu */ - jne .LTcmallocSlab_Internal_PerCpuCmpxchg64_commit; - cmp %rdx, (%rsi); /* verify *p == old */ - jne .LTcmallocSlab_Internal_PerCpuCmpxchg64_value_mismatch; - mov %rcx, (%rsi); -.LTcmallocSlab_Internal_PerCpuCmpxchg64_commit: - ret; /* return current cpu, indicating mismatch OR success */ -.LTcmallocSlab_Internal_PerCpuCmpxchg64_value_mismatch: - mov $-1, %eax; /* mismatch versus "old" or "check", return -1 */ - ret; - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_PerCpuCmpxchg64) -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PerCpuCmpxchg64) - - .p2align 6; /* aligns to 2^6 with NOP filling */ - .globl TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU - .type TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU, @function -TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU: - .cfi_startproc - START_RSEQ(TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU); - FETCH_VCPU(%eax); - cmp %eax, %edi; /* check cpu vs current_cpu */ - jne .LTcmallocSlab_Internal_PerCpuCmpxchg64_VCPU_commit; - cmp %rdx, (%rsi); /* verify *p == old */ - jne .LTcmallocSlab_Internal_PerCpuCmpxchg64_VCPU_value_mismatch; - mov %rcx, (%rsi); -.LTcmallocSlab_Internal_PerCpuCmpxchg64_VCPU_commit: - ret; /* return current cpu, indicating mismatch OR success */ -.LTcmallocSlab_Internal_PerCpuCmpxchg64_VCPU_value_mismatch: - mov $-1, %eax; /* mismatch versus "old" or "check", return -1 */ - ret; - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU) -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU) - -/* size_t TcmallocSlab_Internal_PushBatch_FixedShift( - * void *ptr (%rdi), - * size_t cl (%rsi), - * void** batch (%rdx), - * size_t len (%rcx) { - * uint64_t r8 = __rseq_abi.cpu_id; - * uint64_t* r8 = CpuMemoryStart(rdi, r8); - * Header* hdr = r8 + rsi * 8; +/* size_t TcmallocSlab_Internal_PushBatch( + * size_t size_class (%rdi), + * void** batch (%rsi), + * size_t len (%rdx)) { + * uint64_t* r8 = tcmalloc_rseq.slabs; + * if ((r8 & TCMALLOC_CACHED_SLABS_BIT) == 0) return 0; + * r8 &= ~TCMALLOC_CACHED_SLABS_BIT; + * Header* hdr = r8 + rdi * 8; * uint64_t r9 = hdr->current; * uint64_t r10 = hdr->end; * if (r9 >= r10) return 0; - * r11 = rcx; - * r10 = r9 + min(rcx, r10 - r9); + * r11 = rdx; + * r10 = r9 + min(rdx, r10 - r9); * loop: * r11--; * rax = batch[r11]; @@ -286,97 +231,59 @@ DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PerCpuCmpxchg64_VCPU) * r9++; * if (r9 != r10) goto loop; * hdr->current = r9; - * return rcx - r11; + * return rdx - r11; * } */ .p2align 6; /* aligns to 2^6 with NOP filling */ - .globl TcmallocSlab_Internal_PushBatch_FixedShift - .type TcmallocSlab_Internal_PushBatch_FixedShift, @function -TcmallocSlab_Internal_PushBatch_FixedShift: - .cfi_startproc - START_RSEQ(TcmallocSlab_Internal_PushBatch_FixedShift); - FETCH_CPU(%r8d); - shl $TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT, %r8; - /* multiply cpu by 256k */ - lea (%rdi, %r8), %r8; - movzwq (%r8, %rsi, 8), %r9; /* current */ - movzwq 6(%r8, %rsi, 8), %r10; /* end */ + .globl TcmallocSlab_Internal_PushBatch + .type TcmallocSlab_Internal_PushBatch, @function +TcmallocSlab_Internal_PushBatch: + CFI(.cfi_startproc) + START_RSEQ(TcmallocSlab_Internal_PushBatch); + FETCH_SLABS(%r8); + btrq $TCMALLOC_CACHED_SLABS_BIT, %r8; + jnc .LTcmallocSlab_Internal_PushBatch_full; + movzwq (%r8, %rdi, 4), %r9; /* current */ + movzwq 2(%r8, %rdi, 4), %r10; /* end */ cmpq %r10, %r9; - jae .LTcmallocSlab_Internal_PushBatch_FixedShift_full; - movq %rcx, %r11; /* r11 = copy of len */ + jae .LTcmallocSlab_Internal_PushBatch_full; + movq %rdx, %r11; /* r11 = copy of len */ subq %r9, %r10; /* r10 = free capacity */ - cmpq %rcx, %r10; - cmovaq %rcx, %r10; /* r10 = min(len, free capacity) */ + cmpq %rdx, %r10; + cmovaq %rdx, %r10; /* r10 = min(len, free capacity) */ addq %r9, %r10; -.LTcmallocSlab_Internal_PushBatch_FixedShift_loop: +.LTcmallocSlab_Internal_PushBatch_loop: decq %r11; - movq (%rdx, %r11, 8), %rax; + movq (%rsi, %r11, 8), %rax; movq %rax, (%r8, %r9, 8); incq %r9; cmpq %r9, %r10; - jne .LTcmallocSlab_Internal_PushBatch_FixedShift_loop - movw %r9w, (%r8, %rsi, 8); -.LTcmallocSlab_Internal_PushBatch_FixedShift_commit: - movq %rcx, %rax; + jne .LTcmallocSlab_Internal_PushBatch_loop + movw %r9w, (%r8, %rdi, 4); +.LTcmallocSlab_Internal_PushBatch_commit: + movq %rdx, %rax; subq %r11, %rax; ret; -.LTcmallocSlab_Internal_PushBatch_FixedShift_full: +.LTcmallocSlab_Internal_PushBatch_full: xor %rax, %rax; ret; - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_PushBatch_FixedShift) -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PushBatch_FixedShift) + CFI(.cfi_endproc) +ENCODE_SIZE(TcmallocSlab_Internal_PushBatch) +DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PushBatch) - .p2align 6; /* aligns to 2^6 with NOP filling */ - .globl TcmallocSlab_Internal_PushBatch_FixedShift_VCPU - .type TcmallocSlab_Internal_PushBatch_FixedShift_VCPU, @function -TcmallocSlab_Internal_PushBatch_FixedShift_VCPU: - .cfi_startproc - START_RSEQ(TcmallocSlab_Internal_PushBatch_FixedShift_VCPU); - FETCH_VCPU(%r8d); - shl $TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT, %r8; - /* multiply cpu by 256k */ - lea (%rdi, %r8), %r8; - movzwq (%r8, %rsi, 8), %r9; /* current */ - movzwq 6(%r8, %rsi, 8), %r10; /* end */ - cmpq %r10, %r9; - jae .LTcmallocSlab_Internal_PushBatch_FixedShift_VCPU_full; - movq %rcx, %r11; /* r11 = copy of len */ - subq %r9, %r10; /* r10 = free capacity */ - cmpq %rcx, %r10; - cmovaq %rcx, %r10; /* r10 = min(len, free capacity) */ - addq %r9, %r10; -.LTcmallocSlab_Internal_PushBatch_FixedShift_VCPU_loop: - decq %r11; - movq (%rdx, %r11, 8), %rax; - movq %rax, (%r8, %r9, 8); - incq %r9; - cmpq %r9, %r10; - jne .LTcmallocSlab_Internal_PushBatch_FixedShift_VCPU_loop - movw %r9w, (%r8, %rsi, 8); -.LTcmallocSlab_Internal_PushBatch_FixedShift_VCPU_commit: - movq %rcx, %rax; - subq %r11, %rax; - ret; -.LTcmallocSlab_Internal_PushBatch_FixedShift_VCPU_full: - xor %rax, %rax; - ret; - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_PushBatch_FixedShift_VCPU) -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PushBatch_FixedShift_VCPU) - -/* size_t TcmallocSlab_Internal_PopBatch_FixedShift( - * void *ptr (%rdi), - * size_t cl (%rsi), - * void** batch (%rdx), - * size_t len (%rcx) { - * uint64_t r8 = __rseq_abi.cpu_id; - * uint64_t* r8 = CpuMemoryStart(rdi, r8); - * Header* hdr = GetHeader(rdi, rax, cl); +/* size_t TcmallocSlab_Internal_PopBatch( + * size_t size_class (%rdi), + * void** batch (%rsi), + * size_t len (%rdx), + * std::atomic* begin_ptr (%rcx)) { + * uint64_t* r8 = tcmalloc_rseq.slabs; + * if ((r8 & TCMALLOC_CACHED_SLABS_BIT) == 0) return 0; + * r8 &= ~TCMALLOC_CACHED_SLABS_BIT; + * Header* hdr = GetHeader(rdi, rax, size_class); * uint64_t r9 = hdr->current; - * uint64_t r10 = hdr->begin; + * uint64_t r10 = *begin_ptr; * if (r9 <= r10) return 0; - * r11 = min(rcx, r9 - r10); + * r11 = min(rdx, r9 - r10); * rax = 0; * loop: * r9--; @@ -389,75 +296,35 @@ DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PushBatch_FixedShift_VCPU) * } */ .p2align 6; /* aligns to 2^6 with NOP filling */ - .globl TcmallocSlab_Internal_PopBatch_FixedShift - .type TcmallocSlab_Internal_PopBatch_FixedShift, @function -TcmallocSlab_Internal_PopBatch_FixedShift: - .cfi_startproc - START_RSEQ(TcmallocSlab_Internal_PopBatch_FixedShift); - FETCH_CPU(%r8d); - shl $TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT, %r8; - /* multiply cpu by 256k */ - lea (%rdi, %r8), %r8; - movzwq (%r8, %rsi, 8), %r9; /* current */ - movzwq 4(%r8, %rsi, 8), %r10; /* begin */ - cmp %r10, %r9; - jbe .LTcmallocSlab_Internal_PopBatch_FixedShift_empty; - movq %r9, %r11; - subq %r10, %r11; /* r11 = available items */ - cmpq %rcx, %r11; - cmovaq %rcx, %r11; /* r11 = min(len, available items) */ + .globl TcmallocSlab_Internal_PopBatch + .type TcmallocSlab_Internal_PopBatch, @function +TcmallocSlab_Internal_PopBatch: + CFI(.cfi_startproc) + START_RSEQ(TcmallocSlab_Internal_PopBatch); + FETCH_SLABS(%r8); xorq %rax, %rax; -.LTcmallocSlab_Internal_PopBatch_FixedShift_loop: - decq %r9; - movq (%r8, %r9, 8), %r10; - movq %r10, (%rdx, %rax, 8); - incq %rax; - cmpq %rax, %r11; - jne .LTcmallocSlab_Internal_PopBatch_FixedShift_loop - movw %r9w, (%r8, %rsi, 8); -.LTcmallocSlab_Internal_PopBatch_FixedShift_commit: - ret; -.LTcmallocSlab_Internal_PopBatch_FixedShift_empty: - xor %rax, %rax; - ret; - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_PopBatch_FixedShift) -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PopBatch_FixedShift) - - .p2align 6; /* aligns to 2^6 with NOP filling */ - .globl TcmallocSlab_Internal_PopBatch_FixedShift_VCPU - .type TcmallocSlab_Internal_PopBatch_FixedShift_VCPU, @function -TcmallocSlab_Internal_PopBatch_FixedShift_VCPU: - .cfi_startproc - START_RSEQ(TcmallocSlab_Internal_PopBatch_FixedShift_VCPU); - FETCH_VCPU(%r8d); - shl $TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT, %r8; - /* multiply cpu by 256k */ - lea (%rdi, %r8), %r8; - movzwq (%r8, %rsi, 8), %r9; /* current */ - movzwq 4(%r8, %rsi, 8), %r10; /* begin */ + btrq $TCMALLOC_CACHED_SLABS_BIT, %r8; + jnc .LTcmallocSlab_Internal_PopBatch_commit; + movzwq (%r8, %rdi, 4), %r9; /* current */ + movzwq (%rcx), %r10; /* begin */ cmp %r10, %r9; - jbe .LTcmallocSlab_Internal_PopBatch_FixedShift_VCPU_empty; + jbe .LTcmallocSlab_Internal_PopBatch_commit; movq %r9, %r11; subq %r10, %r11; /* r11 = available items */ - cmpq %rcx, %r11; - cmovaq %rcx, %r11; /* r11 = min(len, available items) */ - xorq %rax, %rax; -.LTcmallocSlab_Internal_PopBatch_FixedShift_VCPU_loop: + cmpq %rdx, %r11; + cmovaq %rdx, %r11; /* r11 = min(len, available items) */ +.LTcmallocSlab_Internal_PopBatch_loop: decq %r9; movq (%r8, %r9, 8), %r10; - movq %r10, (%rdx, %rax, 8); + movq %r10, (%rsi, %rax, 8); incq %rax; cmpq %rax, %r11; - jne .LTcmallocSlab_Internal_PopBatch_FixedShift_VCPU_loop - movw %r9w, (%r8, %rsi, 8); -.LTcmallocSlab_Internal_PopBatch_FixedShift_VCPU_commit: - ret; -.LTcmallocSlab_Internal_PopBatch_FixedShift_VCPU_empty: - xor %rax, %rax; + jne .LTcmallocSlab_Internal_PopBatch_loop + movw %r9w, (%r8, %rdi, 4); +.LTcmallocSlab_Internal_PopBatch_commit: ret; - .cfi_endproc -ENCODE_SIZE(TcmallocSlab_Internal_PopBatch_FixedShift_VCPU) -DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PopBatch_FixedShift_VCPU) + CFI(.cfi_endproc) +ENCODE_SIZE(TcmallocSlab_Internal_PopBatch) +DEFINE_UPSTREAM_CS(TcmallocSlab_Internal_PopBatch) .section .note.GNU-stack,"",@progbits diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_tcmalloc.h b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_tcmalloc.h index 91d15ba9088d..ea396b775d54 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_tcmalloc.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_tcmalloc.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,49 +16,82 @@ #ifndef TCMALLOC_INTERNAL_PERCPU_TCMALLOC_H_ #define TCMALLOC_INTERNAL_PERCPU_TCMALLOC_H_ +#if defined(__linux__) +#include +#else +#include +#endif +#include + +#include +#include #include +#include #include +#include +#include +#include "absl/base/attributes.h" #include "absl/base/casts.h" #include "absl/base/dynamic_annotations.h" -#include "absl/base/internal/sysinfo.h" +#include "absl/base/optimization.h" +#include "absl/functional/function_ref.h" +#include "absl/numeric/bits.h" +#include "tcmalloc/internal/logging.h" #include "tcmalloc/internal/mincore.h" +#include "tcmalloc/internal/optimization.h" #include "tcmalloc/internal/percpu.h" +#include "tcmalloc/internal/prefetch.h" +#include "tcmalloc/internal/sysinfo.h" -#if defined(TCMALLOC_PERCPU_USE_RSEQ) -#if !defined(__clang__) -#define TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO 1 -#elif __clang_major__ >= 9 && !__has_feature(speculative_load_hardening) -// asm goto requires the use of Clang 9 or newer: -// https://releases.llvm.org/9.0.0/tools/clang/docs/ReleaseNotes.html#c-language-changes-in-clang -// -// SLH (Speculative Load Hardening) builds do not support asm goto. We can -// detect these compilation modes since -// https://github.com/llvm/llvm-project/commit/379e68a763097bed55556c6dc7453e4b732e3d68. -#define TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO 1 #if __clang_major__ >= 11 -#define TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT 1 -#endif - -#else -#define TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO 0 -#endif -#else -#define TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO 0 +#define TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT 1 #endif GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { +struct PerSizeClassMaxCapacity { + size_t size_class; + size_t max_capacity; +}; + struct PerCPUMetadataState { size_t virtual_size; size_t resident_size; }; +struct ResizeSlabsInfo { + void* old_slabs; + size_t old_slabs_size; +}; + namespace subtle { namespace percpu { +enum class Shift : uint8_t; +constexpr uint8_t ToUint8(Shift shift) { return static_cast(shift); } +constexpr Shift ToShiftType(size_t shift) { + TC_ASSERT_EQ(ToUint8(static_cast(shift)), shift); + return static_cast(shift); +} + +// The allocation size for the slabs array. +inline size_t GetSlabsAllocSize(Shift shift, int num_cpus) { + return static_cast(num_cpus) << ToUint8(shift); +} + +// Since we lazily initialize our slab, we expect it to be mmap'd and not +// resident. We align it to a page size so neighboring allocations (from +// TCMalloc's internal arena) do not necessarily cause the metadata to be +// faulted in. +// +// We prefer a small page size (EXEC_PAGESIZE) over the anticipated huge page +// size to allow small-but-slow to allocate the slab in the tail of its +// existing Arena block. +static constexpr std::align_val_t kPhysicalPageAlign{EXEC_PAGESIZE}; + // Tcmalloc slab for per-cpu caching mode. // Conceptually it is equivalent to an array of NumClasses PerCpuSlab's, // and in fallback implementation it is implemented that way. But optimized @@ -69,1204 +103,1322 @@ namespace percpu { template class TcmallocSlab { public: + using DrainHandler = absl::FunctionRef; + using ShrinkHandler = + absl::FunctionRef; + + // We use a single continuous region of memory for all slabs on all CPUs. + // This region is split into NumCPUs regions of a power-of-2 size + // (32/64/128/256/512k). + // First NumClasses words of each CPU region are occupied by slab + // headers (Header struct). The remaining memory contain slab arrays. + // struct Slabs { + // std::atomic header[NumClasses]; + // void* mem[]; + // }; + constexpr TcmallocSlab() = default; // Init must be called before any other methods. - // is memory allocation callback (e.g. malloc). - // callback returns max capacity for size class . - // indicates that per-CPU slabs should be populated on demand + // is memory for the slabs with size corresponding to . + // callback returns max capacity for size class . // indicates the number of bits to shift the CPU ID in order to - // obtain the location of the per-CPU slab. If this parameter matches - // TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT as set in - // percpu_intenal.h then the assembly language versions of push/pop - // batch can be used; otherwise batch operations are emulated. + // obtain the location of the per-CPU slab. // // Initial capacity is 0 for all slabs. - void Init(void*(alloc)(size_t size), size_t (*capacity)(size_t cl), bool lazy, - size_t shift); - - // Only may be called if Init(..., lazy = true) was used. - void InitCPU(int cpu, size_t (*capacity)(size_t cl)); - - // For tests. - void Destroy(void(free)(void*)); + void Init(absl::FunctionRef alloc, + void* slabs, absl::FunctionRef capacity, + Shift shift); - // Number of elements in cpu/cl slab. - size_t Length(int cpu, size_t cl) const; + void InitSlabs(void* slabs, Shift shift, + absl::FunctionRef capacity); - // Number of elements (currently) allowed in cpu/cl slab. - size_t Capacity(int cpu, size_t cl) const; - - // If running on cpu, increment the cpu/cl slab's capacity to no greater than - // min(capacity+len, max_cap) and return the increment applied. Otherwise - // return 0. Note: max_cap must be the same as returned by capacity callback - // passed to Init. - size_t Grow(int cpu, size_t cl, size_t len, size_t max_cap); - - // If running on cpu, decrement the cpu/cl slab's capacity to no less than - // max(capacity-len, 0) and return the actual decrement applied. Otherwise - // return 0. - size_t Shrink(int cpu, size_t cl, size_t len); + // Lazily initializes the slab for a specific cpu. + // callback returns max capacity for size class . + // + // Prior to InitCpu being called on a particular `cpu`, non-const operations + // other than Push/Pop/PushBatch/PopBatch are invalid. + void InitCpu(int cpu, absl::FunctionRef capacity); + + // Update maximum capacities allocated to each size class. + // Build and initialize so as to use new maximum capacities + // provided by callback for the . + // updates capacities for the with the new + // once the slabs are initialized. + // provides an array of new maximum capacities to be + // updated for size classes. + // provides the number of size classes for which the + // capacity needs to be updated. + // callback drains the old slab. + [[nodiscard]] ResizeSlabsInfo UpdateMaxCapacities( + void* new_slabs, absl::FunctionRef capacity, + absl::FunctionRef update_capacity, + absl::FunctionRef populated, DrainHandler drain_handler, + PerSizeClassMaxCapacity* new_max_capacity, int classes_to_resize); + + // Grows or shrinks the size of the slabs to use the value. First + // we initialize , then lock all headers on the old slabs, + // atomically update to use the new slabs, and teardown the old slabs. Returns + // a pointer to old slabs to be madvised away along with the size of the old + // slabs and the number of bytes that were reused. + // + // is memory allocation callback (e.g. malloc). + // callback returns max capacity for size class . + // returns whether the corresponding cpu has been populated. + // + // Caller must ensure that there are no concurrent calls to InitCpu, + // ShrinkOtherCache, or Drain. + [[nodiscard]] ResizeSlabsInfo ResizeSlabs( + Shift new_shift, void* new_slabs, + absl::FunctionRef capacity, + absl::FunctionRef populated, DrainHandler drain_handler); + + // For tests. Returns the freed slabs pointer. + void* Destroy(absl::FunctionRef free); + + // Number of elements in cpu/size_class slab. + size_t Length(int cpu, size_t size_class) const; + + // Number of elements (currently) allowed in cpu/size_class slab. + size_t Capacity(int cpu, size_t size_class) const; + + // If running on cpu, increment the cpu/size_class slab's capacity to no + // greater than min(capacity+len, max_capacity()) and return the + // increment applied. Otherwise return 0. + // is a callback that takes the current slab shift as input and + // returns the max capacity of for that shift value - this is in + // order to ensure that the shift value used is consistent with the one used + // in the rest of this function call. Note: max_capacity must be the same as + // returned by capacity callback passed to Init. + size_t Grow(int cpu, size_t size_class, size_t len, + absl::FunctionRef max_capacity); // Add an item (which must be non-zero) to the current CPU's slab. Returns - // true if add succeeds. Otherwise invokes and returns false (assuming - // that returns negative value). - bool Push(size_t cl, void* item, OverflowHandler f); + // true if add succeeds. Otherwise invokes and returns + // false (assuming that returns negative value). + bool Push(size_t size_class, void* item); // Remove an item (LIFO) from the current CPU's slab. If the slab is empty, - // invokes and returns its result. - void* Pop(size_t cl, UnderflowHandler f); + // invokes and returns its result. + [[nodiscard]] void* Pop(size_t size_class); // Add up to items to the current cpu slab from the array located at // . Returns the number of items that were added (possibly 0). All - // items not added will be returned at the start of . Items are only - // not added if there is no space on the current cpu. + // items not added will be returned at the start of . Items are not + // added if there is no space on the current cpu, or if the thread was + // re-scheduled since last Push/Pop. // REQUIRES: len > 0. - size_t PushBatch(size_t cl, void** batch, size_t len); + size_t PushBatch(size_t size_class, void** batch, size_t len); // Pop up to items from the current cpu slab and return them in . - // Returns the number of items actually removed. + // Returns the number of items actually removed. If the thread was + // re-scheduled since last Push/Pop, the function returns 0. // REQUIRES: len > 0. - size_t PopBatch(size_t cl, void** batch, size_t len); - - // Decrements the cpu/cl slab's capacity to no less than max(capacity-len, 0) - // and returns the actual decrement applied. It attempts to shrink any - // unused capacity (i.e end-current) in cpu/cl's slab; if it does not have - // enough unused items, it pops up to items from cpu/cl slab and then - // shrinks the freed capacity. + size_t PopBatch(size_t size_class, void** batch, size_t len); + + // Caches the current cpu slab offset in tcmalloc_slabs if it wasn't + // cached and the cpu is not stopped. Returns the current cpu and the flag + // if the offset was previously uncached and is now cached. If the cpu + // is stopped, returns {-1, true}. + std::pair CacheCpuSlab(); + + // Uncaches the slab offset for the current thread, so that the next Push/Pop + // operation will return false. + void UncacheCpuSlab(); + + // Synchronization protocol between local and remote operations. + // This class supports a set of cpu local operations (Push/Pop/ + // PushBatch/PopBatch/Grow), and a set of remote operations that + // operate on non-current cpu's slab (GrowOtherCache/ShrinkOtherCache/ + // Drain/Resize). Local operations always use a restartable sequence + // that aborts if the slab pointer (tcamlloc_slab) is uncached. + // Caching of the slab pointer after rescheduling checks if + // stopped_[cpu] is unset. Remote operations set stopped_[cpu] + // and then execute Fence, this ensures that any local operation + // on the cpu will abort without changing any state and that the + // slab pointer won't be cached on the cpu. This part uses relaxed atomic + // operations on stopped_[cpu] because the Fence provides all necessary + // synchronization between remote and local threads. When a remote operation + // finishes, it unsets stopped_[cpu] using release memory ordering. + // This ensures that any new local operation on the cpu that observes + // unset stopped_[cpu] with acquire memory ordering, will also see all + // side-effects of the remote operation, and won't interfere with it. + // StopCpu/StartCpu implement the corresponding parts of the remote + // synchronization protocol. + void StopCpu(int cpu); + void StartCpu(int cpu); + + // Grows the cpu/size_class slab's capacity to no greater than + // min(capacity+len, max_capacity()) and returns the increment + // applied. + // is a callback that takes the current slab shift as input and + // returns the max capacity of for that shift value - this is in + // order to ensure that the shift value used is consistent with the one used + // in the rest of this function call. Note: max_capacity must be the same as + // returned by capacity callback passed to Init. + // This may be called from another processor, not just the . + size_t GrowOtherCache(int cpu, size_t size_class, size_t len, + absl::FunctionRef max_capacity); + + // Decrements the cpu/size_class slab's capacity to no less than + // max(capacity-len, 0) and returns the actual decrement applied. It attempts + // to shrink any unused capacity (i.e end-current) in cpu/size_class's slab; + // if it does not have enough unused items, it pops up to items from + // cpu/size_class slab and then shrinks the freed capacity. // // May be called from another processor, not just the . // REQUIRES: len > 0. - typedef void (*ShrinkHandler)(void* arg, size_t cl, void** batch, size_t n); - size_t ShrinkOtherCache(int cpu, size_t cl, size_t len, void* shrink_ctx, - ShrinkHandler f); + size_t ShrinkOtherCache(int cpu, size_t size_class, size_t len, + ShrinkHandler shrink_handler); // Remove all items (of all classes) from 's slab; reset capacity for all // classes to zero. Then, for each sizeclass, invoke - // DrainHandler(drain_ctx, cl, , ); + // DrainHandler(size_class, , ); // // It is invalid to concurrently execute Drain() for the same CPU; calling // Push/Pop/Grow/Shrink concurrently (even on the same CPU) is safe. - typedef void (*DrainHandler)(void* drain_ctx, size_t cl, void** batch, - size_t n, size_t cap); - void Drain(int cpu, void* drain_ctx, DrainHandler f); + void Drain(int cpu, DrainHandler drain_handler); PerCPUMetadataState MetadataMemoryUsage() const; - // We use a single continuous region of memory for all slabs on all CPUs. - // This region is split into NumCPUs regions of size kPerCpuMem (256k). - // First NumClasses words of each CPU region are occupied by slab - // headers (Header struct). The remaining memory contain slab arrays. - struct Slabs { - std::atomic header[NumClasses]; - void* mem[]; - }; - - inline int GetCurrentVirtualCpuUnsafe() { - return VirtualRseqCpuId(virtual_cpu_id_offset_); + // Gets the current shift of the slabs. Intended for use by the thread that + // calls ResizeSlabs(). + uint8_t GetShift() const { + return ToUint8(GetSlabsAndShift(std::memory_order_relaxed).second); } private: - // Slab header (packed, atomically updated 64-bit). + // In order to support dynamic slab metadata sizes, we need to be able to + // atomically update both the slabs pointer and the shift value so we store + // both together in an atomic SlabsAndShift, which manages the bit operations. + class SlabsAndShift { + public: + // These masks allow for distinguishing the shift bits from the slabs + // pointer bits. The maximum shift value is less than kShiftMask and + // kShiftMask is less than kPhysicalPageAlign. + static constexpr size_t kShiftMask = 0xFF; + static constexpr size_t kSlabsMask = ~kShiftMask; + + constexpr explicit SlabsAndShift() noexcept : raw_(0) {} + SlabsAndShift(const void* slabs, Shift shift) + : raw_(reinterpret_cast(slabs) | ToUint8(shift)) { + TC_ASSERT_EQ(raw_ & kShiftMask, ToUint8(shift)); + TC_ASSERT_EQ(reinterpret_cast(raw_ & kSlabsMask), slabs); + } + + std::pair Get() const { + static_assert(kShiftMask >= 0 && kShiftMask <= UCHAR_MAX, + "kShiftMask must fit in a uint8_t"); + // Avoid expanding the width of Shift else the compiler will insert an + // additional instruction to zero out the upper bits on the critical path + // of alloc / free. Not zeroing out the bits is safe because both ARM and + // x86 only use the lowest byte for shift count in variable shifts. + return {reinterpret_cast(raw_ & kSlabsMask), + static_cast(raw_ & kShiftMask)}; + } + + bool operator!=(const SlabsAndShift& other) const { + return raw_ != other.raw_; + } + + private: + uintptr_t raw_; + }; + + // Slab header (packed, atomically updated 32-bit). + // Current and end are pointer offsets from per-CPU region start. + // The slot array is prefixed with an item that has low bit set and ends + // at end, and the occupied slots are up to current. struct Header { - // All values are word offsets from per-CPU region start. - // The array is [begin, end). + // The end offset of the currently occupied slots. uint16_t current; - // Copy of end. Updated by Shrink/Grow, but is not overwritten by Drain. - uint16_t end_copy; - // Lock updates only begin and end with a 32-bit write. - union { - struct { - uint16_t begin; - uint16_t end; - }; - uint32_t lock_update; - }; - - // Lock is used by Drain to stop concurrent mutations of the Header. - // Lock sets begin to 0xffff and end to 0, which makes Push and Pop fail - // regardless of current value. - bool IsLocked() const; - void Lock(); + // The end offset of the slot array for this size class. + uint16_t end; }; - // We cast Header to std::atomic. - static_assert(sizeof(Header) == sizeof(std::atomic), - "bad Header size"); - - Slabs* slabs_ = nullptr; - size_t shift_ = 0; - // This is in units of bytes. - size_t virtual_cpu_id_offset_ = offsetof(kernel_rseq, cpu_id); - - Slabs* CpuMemoryStart(int cpu) const; - std::atomic* GetHeader(int cpu, size_t cl) const; - static Header LoadHeader(std::atomic* hdrp); - static void StoreHeader(std::atomic* hdrp, Header hdr); - static int CompareAndSwapHeader(int cpu, std::atomic* hdrp, - Header old, Header hdr, - size_t virtual_cpu_id_offset); + using AtomicHeader = std::atomic; + + // We cast Header to AtomicHeader. + static_assert(sizeof(Header) == sizeof(AtomicHeader)); + + // We mark the pointer that's stored right before size class object range + // in the slabs array with this mask. When we reach pointer marked with this + // mask when popping, we understand that we reached the beginning of the + // range (the slab is empty). The pointer is also a valid pointer for + // prefetching, so it allows us to always prefetch the previous element + // when popping. + static constexpr uintptr_t kBeginMark = 1; + + // It's important that we use consistent values for slabs/shift rather than + // loading from the atomic repeatedly whenever we use one of the values. + [[nodiscard]] std::pair GetSlabsAndShift( + std::memory_order order) const { + return slabs_and_shift_.load(order).Get(); + } + + static void* CpuMemoryStart(void* slabs, Shift shift, int cpu); + static AtomicHeader* GetHeader(void* slabs, Shift shift, int cpu, + size_t size_class); + static Header LoadHeader(AtomicHeader* hdrp); + static void StoreHeader(AtomicHeader* hdrp, Header hdr); + void DrainCpu(void* slabs, Shift shift, int cpu, DrainHandler drain_handler); + void DrainOldSlabs(void* slabs, Shift shift, int cpu, + const std::array& old_begins, + DrainHandler drain_handler); + + // Implementation of InitCpu() allowing for reuse in ResizeSlabs(). + void InitCpuImpl(void* slabs, Shift shift, int cpu, + absl::FunctionRef capacity); + + std::pair CacheCpuSlabSlow(); + + // We store both a pointer to the array of slabs and the shift value together + // so that we can atomically update both with a single store. + std::atomic slabs_and_shift_{}; + // Remote Cpu operation (Resize/Drain/Grow/Shrink) is running so any local + // operations (Push/Pop) should fail. + std::atomic* stopped_ = nullptr; + // begins_[size_class] is offset of the size_class region in the slabs area. + std::atomic* begins_ = nullptr; }; +// RAII for StopCpu/StartCpu. template -inline size_t TcmallocSlab::Length(int cpu, size_t cl) const { - Header hdr = LoadHeader(GetHeader(cpu, cl)); - return hdr.IsLocked() ? 0 : hdr.current - hdr.begin; -} +class ScopedSlabCpuStop { + public: + ScopedSlabCpuStop(TcmallocSlab& slab, int cpu) + : slab_(slab), cpu_(cpu) { + slab_.StopCpu(cpu_); + } + + ~ScopedSlabCpuStop() { slab_.StartCpu(cpu_); } + + private: + TcmallocSlab& slab_; + const int cpu_; + + ScopedSlabCpuStop(const ScopedSlabCpuStop&) = delete; + ScopedSlabCpuStop& operator=(const ScopedSlabCpuStop&) = delete; +}; template -inline size_t TcmallocSlab::Capacity(int cpu, size_t cl) const { - Header hdr = LoadHeader(GetHeader(cpu, cl)); - return hdr.IsLocked() ? 0 : hdr.end - hdr.begin; +inline size_t TcmallocSlab::Length(int cpu, + size_t size_class) const { + const auto [slabs, shift] = GetSlabsAndShift(std::memory_order_relaxed); + Header hdr = LoadHeader(GetHeader(slabs, shift, cpu, size_class)); + uint16_t begin = begins_[size_class].load(std::memory_order_relaxed); + // We can read inconsistent hdr/begin during Resize, to avoid surprising + // callers return 0 instead of overflows values. + return std::max(0, hdr.current - begin); } template -inline size_t TcmallocSlab::Grow(int cpu, size_t cl, size_t len, - size_t max_cap) { - const size_t virtual_cpu_id_offset = virtual_cpu_id_offset_; - std::atomic* hdrp = GetHeader(cpu, cl); - for (;;) { - Header old = LoadHeader(hdrp); - if (old.IsLocked() || old.end - old.begin == max_cap) { - return 0; - } - uint16_t n = std::min(len, max_cap - (old.end - old.begin)); - Header hdr = old; - hdr.end += n; - hdr.end_copy += n; - const int ret = - CompareAndSwapHeader(cpu, hdrp, old, hdr, virtual_cpu_id_offset); - if (ret == cpu) { - return n; - } else if (ret >= 0) { - return 0; - } - } +inline size_t TcmallocSlab::Capacity(int cpu, + size_t size_class) const { + const auto [slabs, shift] = GetSlabsAndShift(std::memory_order_relaxed); + Header hdr = LoadHeader(GetHeader(slabs, shift, cpu, size_class)); + uint16_t begin = begins_[size_class].load(std::memory_order_relaxed); + return std::max(0, hdr.end - begin); } -template -inline size_t TcmallocSlab::Shrink(int cpu, size_t cl, size_t len) { - const size_t virtual_cpu_id_offset = virtual_cpu_id_offset_; - std::atomic* hdrp = GetHeader(cpu, cl); - for (;;) { - Header old = LoadHeader(hdrp); - if (old.IsLocked() || old.current == old.end) { - return 0; - } - uint16_t n = std::min(len, old.end - old.current); - Header hdr = old; - hdr.end -= n; - hdr.end_copy -= n; - const int ret = - CompareAndSwapHeader(cpu, hdrp, old, hdr, virtual_cpu_id_offset); - if (ret == cpu) { - return n; - } else if (ret >= 0) { - return 0; - } +#if defined(__x86_64__) +#define TCMALLOC_RSEQ_RELOC_TYPE "R_X86_64_NONE" +#define TCMALLOC_RSEQ_JUMP "jmp" +#if !defined(__PIC__) && !defined(__PIE__) +#define TCMALLOC_RSEQ_SET_CS(name) \ + "movq $__rseq_cs_" #name "_%=, %[rseq_cs_addr]\n" +#else +#define TCMALLOC_RSEQ_SET_CS(name) \ + "lea __rseq_cs_" #name \ + "_%=(%%rip), %[scratch]\n" \ + "movq %[scratch], %[rseq_cs_addr]\n" +#endif + +#elif defined(__aarch64__) +// The trampoline uses a non-local branch to restart critical sections. +// The trampoline is located in the .text.unlikely section, and the maximum +// distance of B and BL branches in ARM64 is limited to 128MB. If the linker +// detects the distance being too large, it injects a thunk which may clobber +// the x16 or x17 register according to the ARMv8 ABI standard. +// The actual clobbering is hard to trigger in a test, so instead of waiting +// for clobbering to happen in production binaries, we proactively always +// clobber x16 and x17 to shake out bugs earlier. +// RSEQ critical section asm blocks should use TCMALLOC_RSEQ_CLOBBER +// in the clobber list to account for this. +#ifndef NDEBUG +#define TCMALLOC_RSEQ_TRAMPLINE_SMASH \ + "mov x16, #-2097\n" \ + "mov x17, #-2099\n" +#else +#define TCMALLOC_RSEQ_TRAMPLINE_SMASH +#endif +#define TCMALLOC_RSEQ_CLOBBER "x16", "x17" +#define TCMALLOC_RSEQ_RELOC_TYPE "R_AARCH64_NONE" +#define TCMALLOC_RSEQ_JUMP "b" +#define TCMALLOC_RSEQ_SET_CS(name) \ + TCMALLOC_RSEQ_TRAMPLINE_SMASH \ + "adrp %[scratch], __rseq_cs_" #name \ + "_%=\n" \ + "add %[scratch], %[scratch], :lo12:__rseq_cs_" #name \ + "_%=\n" \ + "str %[scratch], %[rseq_cs_addr]\n" +#endif + +#if !defined(__clang_major__) || __clang_major__ >= 9 +#define TCMALLOC_RSEQ_RELOC ".reloc 0, " TCMALLOC_RSEQ_RELOC_TYPE ", 1f\n" +#else +#define TCMALLOC_RSEQ_RELOC +#endif + +// Common rseq asm prologue. +// It uses labels 1-4 and assumes the critical section ends with label 5. +// The prologue assumes there is [scratch] input with a scratch register. +#define TCMALLOC_RSEQ_PROLOGUE(name) \ + /* __rseq_cs only needs to be writeable to allow for relocations.*/ \ + ".pushsection __rseq_cs, \"aw?\"\n" \ + ".balign 32\n" \ + ".local __rseq_cs_" #name \ + "_%=\n" \ + ".type __rseq_cs_" #name \ + "_%=,@object\n" \ + ".size __rseq_cs_" #name \ + "_%=,32\n" \ + "__rseq_cs_" #name \ + "_%=:\n" \ + ".long 0x0\n" \ + ".long 0x0\n" \ + ".quad 4f\n" \ + ".quad 5f - 4f\n" \ + ".quad 2f\n" \ + ".popsection\n" TCMALLOC_RSEQ_RELOC \ + ".pushsection __rseq_cs_ptr_array, \"aw?\"\n" \ + "1:\n" \ + ".balign 8\n" \ + ".quad __rseq_cs_" #name \ + "_%=\n" /* Force this section to be retained. \ + It is for debugging, but is otherwise not referenced. */ \ + ".popsection\n" \ + ".pushsection .text.unlikely, \"ax?\"\n" /* This is part of the upstream \ + rseq ABI. The 4 bytes prior to \ + the abort IP must match \ + TCMALLOC_PERCPU_RSEQ_SIGNATURE \ + (as configured by our rseq \ + syscall's signature parameter). \ + This signature is used to \ + annotate valid abort IPs (since \ + rseq_cs could live in a \ + user-writable segment). */ \ + ".long %c[rseq_sig]\n" \ + ".local " #name \ + "_trampoline_%=\n" \ + ".type " #name \ + "_trampoline_%=,@function\n" \ + "" #name \ + "_trampoline_%=:\n" \ + "2:\n" TCMALLOC_RSEQ_JUMP \ + " 3f\n" \ + ".size " #name "_trampoline_%=, . - " #name \ + "_trampoline_%=\n" \ + ".popsection\n" /* Prepare */ \ + "3:\n" TCMALLOC_RSEQ_SET_CS(name) /* Start */ \ + "4:\n" + +#define TCMALLOC_RSEQ_INPUTS \ + [rseq_cs_addr] "m"(__rseq_abi.rseq_cs), \ + [rseq_slabs_addr] "m"(*reinterpret_cast( \ + reinterpret_cast(&__rseq_abi) + \ + TCMALLOC_RSEQ_SLABS_OFFSET)), \ + [rseq_sig] "n"( \ + TCMALLOC_PERCPU_RSEQ_SIGNATURE), /* Also pass common consts, there \ + is no cost to passing unused \ + consts. */ \ + [cached_slabs_bit] "n"(TCMALLOC_CACHED_SLABS_BIT), \ + [cached_slabs_mask_neg] "n"(~TCMALLOC_CACHED_SLABS_MASK) + +// Store v to p (*p = v) if the current thread wasn't rescheduled +// (still has the slab pointer cached). Otherwise returns false. +template +inline ABSL_ATTRIBUTE_ALWAYS_INLINE bool StoreCurrentCpu(volatile void* p, + T v) { + uintptr_t scratch = 0; +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ && defined(__x86_64__) + asm(TCMALLOC_RSEQ_PROLOGUE(TcmallocSlab_Internal_StoreCurrentCpu) + R"( + xorq %[scratch], %[scratch] + btq $%c[cached_slabs_bit], %[rseq_slabs_addr] + jnc 5f + movl $1, %k[scratch] + mov %[v], %[p] + 5 :)" + : [scratch] "=&r"(scratch) + : TCMALLOC_RSEQ_INPUTS, [p] "m"(*static_cast(p)), + [v] "r"(v) + : "cc", "memory"); +#elif TCMALLOC_INTERNAL_PERCPU_USE_RSEQ && defined(__aarch64__) + uintptr_t tmp; + // Aarch64 requires different argument references for different sizes + // for the STR instruction (%[v] vs %w[v]), so we have to duplicate + // the asm block. + if constexpr (sizeof(T) == sizeof(uint64_t)) { + asm(TCMALLOC_RSEQ_PROLOGUE(TcmallocSlab_Internal_StoreCurrentCpu) + R"( + mov %[scratch], #0 + ldr %[tmp], %[rseq_slabs_addr] + tbz %[tmp], #%c[cached_slabs_bit], 5f + mov %[scratch], #1 + str %[v], %[p] + 5 :)" + : [scratch] "=&r"(scratch), [tmp] "=&r"(tmp) + : TCMALLOC_RSEQ_INPUTS, [p] "m"(*static_cast(p)), + [v] "r"(v) + : TCMALLOC_RSEQ_CLOBBER, "cc", "memory"); + } else { + static_assert(sizeof(T) == sizeof(uint32_t)); + asm(TCMALLOC_RSEQ_PROLOGUE(TcmallocSlab_Internal_StoreCurrentCpu) + R"( + mov %[scratch], #0 + ldr %[tmp], %[rseq_slabs_addr] + tbz %[tmp], #%c[cached_slabs_bit], 5f + mov %[scratch], #1 + str %w[v], %[p] + 5 :)" + : [scratch] "=&r"(scratch), [tmp] "=&r"(tmp) + : TCMALLOC_RSEQ_INPUTS, [p] "m"(*static_cast(p)), + [v] "r"(v) + : TCMALLOC_RSEQ_CLOBBER, "cc", "memory"); } +#endif + return scratch; } -#if defined(__x86_64__) -template -static inline ABSL_ATTRIBUTE_ALWAYS_INLINE int TcmallocSlab_Internal_Push( - typename TcmallocSlab::Slabs* slabs, size_t cl, void* item, - const size_t shift, OverflowHandler f, const size_t virtual_cpu_id_offset) { -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO +// Prefetch slabs memory for the case of repeated pushes/pops. +// Note: this prefetch slows down micro-benchmarks, but provides ~0.1-0.5% +// speedup for larger real applications. +inline ABSL_ATTRIBUTE_ALWAYS_INLINE void PrefetchSlabMemory(uintptr_t ptr) { + PrefetchWT0(reinterpret_cast(ptr)); +} + +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ && defined(__x86_64__) +// Note: These helpers must be "static inline" to avoid ODR violations due to +// different labels emitted in TCMALLOC_RSEQ_PROLOGUE. +static inline ABSL_ATTRIBUTE_ALWAYS_INLINE bool TcmallocSlab_Internal_Push( + size_t size_class, void* item) { + uintptr_t scratch, current; +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT asm goto( #else bool overflow; asm volatile( #endif - // TODO(b/141629158): __rseq_cs only needs to be writeable to allow for - // relocations, but could be read-only for non-PIE builds. - ".pushsection __rseq_cs, \"aw?\"\n" - ".balign 32\n" - ".local __rseq_cs_TcmallocSlab_Internal_Push_%=\n" - ".type __rseq_cs_TcmallocSlab_Internal_Push_%=,@object\n" - ".size __rseq_cs_TcmallocSlab_Internal_Push_%=,32\n" - "__rseq_cs_TcmallocSlab_Internal_Push_%=:\n" - ".long 0x0\n" - ".long 0x0\n" - ".quad 4f\n" - ".quad 5f - 4f\n" - ".quad 2f\n" - ".popsection\n" -#if !defined(__clang_major__) || __clang_major__ >= 9 - ".reloc 0, R_X86_64_NONE, 1f\n" + TCMALLOC_RSEQ_PROLOGUE(TcmallocSlab_Internal_Push) + // scratch = tcmalloc_slabs; + "movq %[rseq_slabs_addr], %[scratch]\n" + // if (scratch & TCMALLOC_CACHED_SLABS_MASK>) goto overflow_label; + // scratch &= ~TCMALLOC_CACHED_SLABS_MASK; + "btrq $%c[cached_slabs_bit], %[scratch]\n" +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + "jnc %l[overflow_label]\n" +#else + "jae 5f\n" // ae==c #endif - ".pushsection __rseq_cs_ptr_array, \"aw?\"\n" - "1:\n" - ".balign 8;" - ".quad __rseq_cs_TcmallocSlab_Internal_Push_%=\n" - // Force this section to be retained. It is for debugging, but is - // otherwise not referenced. - ".popsection\n" - ".pushsection .text.unlikely, \"ax?\"\n" - ".byte 0x0f, 0x1f, 0x05\n" - ".long %c[rseq_sig]\n" - ".local TcmallocSlab_Internal_Push_trampoline_%=\n" - ".type TcmallocSlab_Internal_Push_trampoline_%=,@function\n" - "TcmallocSlab_Internal_Push_trampoline_%=:\n" - "2:\n" - "jmp 3f\n" - ".size TcmallocSlab_Internal_Push_trampoline_%=, . - " - "TcmallocSlab_Internal_Push_trampoline_%=;\n" - ".popsection\n" - // Prepare - // - // TODO(b/151503411): Pending widespread availability of LLVM's asm - // goto with output contraints - // (https://github.com/llvm/llvm-project/commit/23c2a5ce33f0), we can - // return the register allocations to the compiler rather than using - // explicit clobbers. Prior to this, blocks which use asm goto cannot - // also specify outputs. - // - // r10: Scratch - // r11: Current - "3:\n" - "lea __rseq_cs_TcmallocSlab_Internal_Push_%=(%%rip), %%r10\n" - "mov %%r10, %c[rseq_cs_offset](%[rseq_abi])\n" - // Start - "4:\n" - // scratch = __rseq_abi.cpu_id; - "movzwl (%[rseq_abi], %[rseq_cpu_offset]), %%r10d\n" - // scratch = slabs + scratch - "shlq %b[shift], %%r10\n" - "add %[slabs], %%r10\n" - // r11 = slabs->current; - "movzwq (%%r10, %[cl], 8), %%r11\n" - // if (ABSL_PREDICT_FALSE(r11 >= slabs->end)) { goto overflow; } - "cmp 6(%%r10, %[cl], 8), %%r11w\n" -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO + // current = slabs->current; + "movzwq (%[scratch], %[size_class], 4), %[current]\n" + // if (ABSL_PREDICT_FALSE(current >= slabs->end)) { goto overflow_label; } + "cmp 2(%[scratch], %[size_class], 4), %w[current]\n" +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT "jae %l[overflow_label]\n" #else "jae 5f\n" // Important! code below this must not affect any flags (i.e.: ccae) // If so, the above code needs to explicitly set a ccae return value. #endif - "mov %[item], (%%r10, %%r11, 8)\n" - "lea 1(%%r11), %%r11\n" - "mov %%r11w, (%%r10, %[cl], 8)\n" + "mov %[item], (%[scratch], %[current], 8)\n" + "lea 1(%[current]), %[current]\n" + "mov %w[current], (%[scratch], %[size_class], 4)\n" // Commit "5:\n" : -#if !TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO - [overflow] "=@ccae"(overflow) +#if !TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + [overflow] "=@ccae"(overflow), #endif - : [rseq_abi] "r"(&__rseq_abi), - [rseq_cs_offset] "n"(offsetof(kernel_rseq, rseq_cs)), - [rseq_cpu_offset] "r"(virtual_cpu_id_offset), - [rseq_sig] "in"(TCMALLOC_PERCPU_RSEQ_SIGNATURE), [shift] "c"(shift), - [slabs] "r"(slabs), [cl] "r"(cl), [item] "r"(item) - : "cc", "memory", "r10", "r11" -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO + [scratch] "=&r"(scratch), [current] "=&r"(current) + : TCMALLOC_RSEQ_INPUTS, [size_class] "r"(size_class), [item] "r"(item) + : "cc", "memory" +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT : overflow_label #endif ); -#if !TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO +#if !TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT if (ABSL_PREDICT_FALSE(overflow)) { goto overflow_label; } #endif - return 0; + // Current now points to the slot we are going to push to next. + PrefetchSlabMemory(scratch + current * sizeof(void*)); + return true; overflow_label: - // As of 3/2020, LLVM's asm goto (even with output constraints) only provides - // values for the fallthrough path. The values on the taken branches are - // undefined. - int cpu = VirtualRseqCpuId(virtual_cpu_id_offset); - return f(cpu, cl, item); + return false; } #endif // defined(__x86_64__) -#if defined(__aarch64__) - -template -static inline ABSL_ATTRIBUTE_ALWAYS_INLINE int TcmallocSlab_Internal_Push( - typename TcmallocSlab::Slabs* slabs, size_t cl, void* item, - const size_t shift, OverflowHandler f, const size_t virtual_cpu_id_offset) { - void* region_start; - uint64_t cpu_id; - void* end_ptr; - uintptr_t current; - uintptr_t end; - // Multiply cl by the bytesize of each header - size_t cl_lsl3 = cl * 8; -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ && defined(__aarch64__) +static inline ABSL_ATTRIBUTE_ALWAYS_INLINE bool TcmallocSlab_Internal_Push( + size_t size_class, void* item) { + uintptr_t region_start, scratch, end_ptr, end; +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT asm goto( #else bool overflow; asm volatile( #endif - // TODO(b/141629158): __rseq_cs only needs to be writeable to allow for - // relocations, but could be read-only for non-PIE builds. - ".pushsection __rseq_cs, \"aw?\"\n" - ".balign 32\n" - ".local __rseq_cs_TcmallocSlab_Internal_Push_%=\n" - ".type __rseq_cs_TcmallocSlab_Internal_Push_%=,@object\n" - ".size __rseq_cs_TcmallocSlab_Internal_Push_%=,32\n" - "__rseq_cs_TcmallocSlab_Internal_Push_%=:\n" - ".long 0x0\n" - ".long 0x0\n" - ".quad 4f\n" - ".quad 5f - 4f\n" - ".quad 2f\n" - ".popsection\n" -#if !defined(__clang_major__) || __clang_major__ >= 9 - ".reloc 0, R_AARCH64_NONE, 1f\n" + TCMALLOC_RSEQ_PROLOGUE(TcmallocSlab_Internal_Push) + // region_start = tcmalloc_slabs; + "ldr %[region_start], %[rseq_slabs_addr]\n" + // if (region_start & TCMALLOC_CACHED_SLABS_MASK) goto overflow_label; + // region_start &= ~TCMALLOC_CACHED_SLABS_MASK; +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + "tbz %[region_start], #%c[cached_slabs_bit], %l[overflow_label]\n" + "and %[region_start], %[region_start], #%c[cached_slabs_mask_neg]\n" +#else + "subs %[region_start], %[region_start], %[cached_slabs_mask]\n" + "b.ls 5f\n" #endif - ".pushsection __rseq_cs_ptr_array, \"aw?\"\n" - "1:\n" - ".balign 8;" - ".quad __rseq_cs_TcmallocSlab_Internal_Push_%=\n" - // Force this section to be retained. It is for debugging, but is - // otherwise not referenced. - ".popsection\n" - ".pushsection .text.unlikely, \"ax?\"\n" - ".long %c[rseq_sig]\n" - ".local TcmallocSlab_Internal_Push_trampoline_%=\n" - ".type TcmallocSlab_Internal_Push_trampoline_%=,@function\n" - "TcmallocSlab_Internal_Push_trampoline_%=:\n" - "2:\n" - "b 3f\n" - ".popsection\n" - // Prepare - // - // TODO(b/151503411): Pending widespread availability of LLVM's asm - // goto with output contraints - // (https://github.com/llvm/llvm-project/commit/23c2a5ce33f0), we can - // return the register allocations to the compiler rather than using - // explicit clobbers. Prior to this, blocks which use asm goto cannot - // also specify outputs. - "3:\n" - // Use current as scratch here to hold address of this function's - // critical section - "adrp %[current], __rseq_cs_TcmallocSlab_Internal_Push_%=\n" - "add %[current], %[current], " - ":lo12:__rseq_cs_TcmallocSlab_Internal_Push_%=\n" - "str %[current], [%[rseq_abi], %c[rseq_cs_offset]]\n" - // Start - "4:\n" - // cpu_id = __rseq_abi.cpu_id; - "ldr %w[cpu_id], [%[rseq_abi], %[rseq_cpu_offset]]\n" - // region_start = Start of cpu region - "lsl %[region_start], %[cpu_id], %[shift]\n" - "add %[region_start], %[region_start], %[slabs]\n" // end_ptr = &(slab_headers[0]->end) - "add %[end_ptr], %[region_start], #6\n" - // current = slab_headers[cl]->current (current index) - "ldrh %w[current], [%[region_start], %[cl_lsl3]]\n" - // end = slab_headers[cl]->end (end index) - "ldrh %w[end], [%[end_ptr], %[cl_lsl3]]\n" - // if (ABSL_PREDICT_FALSE(current >= end)) { goto overflow; } - "cmp %[end], %[current]\n" -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO - "b.le %l[overflow_label]\n" + "add %[end_ptr], %[region_start], #2\n" + // scratch = slab_headers[size_class]->current (current index) + "ldrh %w[scratch], [%[region_start], %[size_class_lsl2]]\n" + // end = slab_headers[size_class]->end (end index) + "ldrh %w[end], [%[end_ptr], %[size_class_lsl2]]\n" + // if (ABSL_PREDICT_FALSE(end <= scratch)) { goto overflow_label; } + "cmp %[end], %[scratch]\n" +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + "b.ls %l[overflow_label]\n" #else - "b.le 5f\n" - // Important! code below this must not affect any flags (i.e.: ccae) - // If so, the above code needs to explicitly set a ccae return value. + "b.ls 5f\n" + // Important! code below this must not affect any flags (i.e.: ccls) + // If so, the above code needs to explicitly set a ccls return value. #endif - "str %[item], [%[region_start], %[current], LSL #3]\n" - "add %w[current], %w[current], #1\n" - "strh %w[current], [%[region_start], %[cl_lsl3]]\n" + "str %[item], [%[region_start], %[scratch], LSL #3]\n" + "add %w[scratch], %w[scratch], #1\n" + "strh %w[scratch], [%[region_start], %[size_class_lsl2]]\n" // Commit "5:\n" - : [end_ptr] "=&r"(end_ptr), [cpu_id] "=&r"(cpu_id), - [current] "=&r"(current), [end] "=&r"(end), + : [end_ptr] "=&r"(end_ptr), [scratch] "=&r"(scratch), [end] "=&r"(end), +#if !TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + [overflow] "=@ccls"(overflow), +#endif [region_start] "=&r"(region_start) - -#if !TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO - , - [overflow] "=@ccae"(overflow) + : TCMALLOC_RSEQ_INPUTS, +#if !TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + [cached_slabs_mask] "r"(TCMALLOC_CACHED_SLABS_MASK), #endif - : [rseq_cpu_offset] "r"(virtual_cpu_id_offset), [slabs] "r"(slabs), - [cl_lsl3] "r"(cl_lsl3), [item] "r"(item), [rseq_abi] "r"(&__rseq_abi), - [shift] "r"(shift), - // Constants - [rseq_cs_offset] "n"(offsetof(kernel_rseq, rseq_cs)), - [rseq_sig] "in"(TCMALLOC_PERCPU_RSEQ_SIGNATURE) - : "cc", "memory" -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO + [size_class_lsl2] "r"(size_class << 2), [item] "r"(item) + : TCMALLOC_RSEQ_CLOBBER, "memory" +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + , + "cc" : overflow_label #endif ); -#if !TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO +#if !TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT if (ABSL_PREDICT_FALSE(overflow)) { goto overflow_label; } #endif - return 0; + return true; overflow_label: -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT - // As of 3/2020, LLVM's asm goto (even with output constraints) only provides - // values for the fallthrough path. The values on the taken branches are - // undefined. - int cpu = VirtualRseqCpuId(virtual_cpu_id_offset); -#else - // With asm goto--without output constraints--the value of scratch is - // well-defined by the compiler and our implementation. As an optimization on - // this case, we can avoid looking up cpu_id again, by undoing the - // transformation of cpu_id to the value of scratch. - int cpu = cpu_id; -#endif - return f(cpu, cl, item); + return false; } #endif // defined (__aarch64__) template inline ABSL_ATTRIBUTE_ALWAYS_INLINE bool TcmallocSlab::Push( - size_t cl, void* item, OverflowHandler f) { - ASSERT(item != nullptr); -#if defined(__x86_64__) || defined(__aarch64__) - return TcmallocSlab_Internal_Push(slabs_, cl, item, shift_, f, - virtual_cpu_id_offset_) >= 0; + size_t size_class, void* item) { + TC_ASSERT_NE(size_class, 0); + TC_ASSERT_NE(item, nullptr); + TC_ASSERT_EQ(reinterpret_cast(item) & kBeginMark, 0); + // Speculatively annotate item as released to TSan. We may not succeed in + // pushing the item, but if we wait for the restartable sequence to succeed, + // it may become visible to another thread before we can trigger the + // annotation. + TSANRelease(item); +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + return TcmallocSlab_Internal_Push(size_class, item); #else - if (shift_ == TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT) { - return TcmallocSlab_Internal_Push_FixedShift(slabs_, cl, item, f) >= 0; - } else { - return TcmallocSlab_Internal_Push(slabs_, cl, item, shift_, f) >= 0; - } + return false; #endif } -#if defined(__x86_64__) +// PrefetchNextObject provides a common code path across architectures for +// generating a prefetch of the next object. +// +// It is in a distinct, always-lined method to make its cost more transparent +// when profiling with debug information. +inline ABSL_ATTRIBUTE_ALWAYS_INLINE void PrefetchNextObject( + void* prefetch_target) { + // A note about prefetcht0 in Pop: While this prefetch may appear costly, + // trace analysis shows the target is frequently used (b/70294962). Stalling + // on a TLB miss at the prefetch site (which has no deps) and prefetching the + // line async is better than stalling at the use (which may have deps) to fill + // the TLB and the cache miss. + // + // See "Beyond malloc efficiency to fleet efficiency" + // (https://research.google/pubs/pub50370/), section 6.4 for additional + // details. + // + // TODO(b/214608320): Evaluate prefetch for write. + __builtin_prefetch(prefetch_target, 0, 3); +} + +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ && defined(__x86_64__) template -static inline ABSL_ATTRIBUTE_ALWAYS_INLINE void* TcmallocSlab_Internal_Pop( - typename TcmallocSlab::Slabs* slabs, size_t cl, - UnderflowHandler f, const size_t shift, - const size_t virtual_cpu_id_offset) { +inline ABSL_ATTRIBUTE_ALWAYS_INLINE void* TcmallocSlab::Pop( + size_t size_class) { + TC_ASSERT_NE(size_class, 0); + void* next; void* result; - void* scratch; - uintptr_t current; -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT - asm goto + uintptr_t scratch, current; + +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + asm goto( #else bool underflow; - asm + asm( #endif - ( - // TODO(b/141629158): __rseq_cs only needs to be writeable to allow - // for relocations, but could be read-only for non-PIE builds. - ".pushsection __rseq_cs, \"aw?\"\n" - ".balign 32\n" - ".local __rseq_cs_TcmallocSlab_Internal_Pop_%=\n" - ".type __rseq_cs_TcmallocSlab_Internal_Pop_%=,@object\n" - ".size __rseq_cs_TcmallocSlab_Internal_Pop_%=,32\n" - "__rseq_cs_TcmallocSlab_Internal_Pop_%=:\n" - ".long 0x0\n" - ".long 0x0\n" - ".quad 4f\n" - ".quad 5f - 4f\n" - ".quad 2f\n" - ".popsection\n" -#if !defined(__clang_major__) || __clang_major__ >= 9 - ".reloc 0, R_X86_64_NONE, 1f\n" + TCMALLOC_RSEQ_PROLOGUE(TcmallocSlab_Internal_Pop) + // scratch = tcmalloc_slabs; + "movq %[rseq_slabs_addr], %[scratch]\n" + // if (scratch & TCMALLOC_CACHED_SLABS_MASK) goto overflow_label; + // scratch &= ~TCMALLOC_CACHED_SLABS_MASK; + "btrq $%c[cached_slabs_bit], %[scratch]\n" +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + "jnc %l[underflow_path]\n" +#else + "cmc\n" + "jc 5f\n" #endif - ".pushsection __rseq_cs_ptr_array, \"aw?\"\n" - "1:\n" - ".balign 8;" - ".quad __rseq_cs_TcmallocSlab_Internal_Pop_%=\n" - // Force this section to be retained. It is for debugging, but is - // otherwise not referenced. - ".popsection\n" - ".pushsection .text.unlikely, \"ax?\"\n" - ".byte 0x0f, 0x1f, 0x05\n" - ".long %c[rseq_sig]\n" - ".local TcmallocSlab_Internal_Pop_trampoline_%=\n" - ".type TcmallocSlab_Internal_Pop_trampoline_%=,@function\n" - "TcmallocSlab_Internal_Pop_trampoline_%=:\n" - "2:\n" - "jmp 3f\n" - ".size TcmallocSlab_Internal_Pop_trampoline_%=, . - " - "TcmallocSlab_Internal_Pop_trampoline_%=;\n" - ".popsection\n" - // Prepare - "3:\n" - "lea __rseq_cs_TcmallocSlab_Internal_Pop_%=(%%rip), %[scratch];\n" - "mov %[scratch], %c[rseq_cs_offset](%[rseq_abi])\n" - // Start - "4:\n" - // scratch = __rseq_abi.cpu_id; - "movzwl (%[rseq_abi], %[rseq_cpu_offset]), %k[scratch]\n" - // scratch = slabs + scratch - "shlq %b[shift], %[scratch]\n" - "add %[slabs], %[scratch]\n" - // current = scratch->header[cl].current; - "movzwq (%[scratch], %[cl], 8), %[current]\n" - // if (ABSL_PREDICT_FALSE(scratch->header[cl].begin > current)) - "cmp 4(%[scratch], %[cl], 8), %w[current]\n" -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT - "jbe %l[underflow_path]\n" + // current = scratch->header[size_class].current; + "movzwq (%[scratch], %[size_class], 4), %[current]\n" + "movq -8(%[scratch], %[current], 8), %[result]\n" +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + "testb $%c[begin_mark_mask], %b[result]\n" + "jnz %l[underflow_path]\n" #else - "jbe 5f\n" - // Important! code below this must not affect any flags (i.e.: ccbe) - // If so, the above code needs to explicitly set a ccbe return value. + "btq $%c[begin_mark_bit], %[result]\n" + "jc 5f\n" + // Important! code below this must not affect any flags (i.e.: ccc) + // If so, the above code needs to explicitly set a ccc return value. #endif - "mov -16(%[scratch], %[current], 8), %[result]\n" - // A note about prefetcht0 in Pop: While this prefetch may appear - // costly, trace analysis shows the target is frequently used - // (b/70294962). Stalling on a TLB miss at the prefetch site (which - // has no deps) and prefetching the line async is better than stalling - // at the use (which may have deps) to fill the TLB and the cache - // miss. - "prefetcht0 (%[result])\n" - "movq -8(%[scratch], %[current], 8), %[result]\n" - "lea -1(%[current]), %[current]\n" - "mov %w[current], (%[scratch], %[cl], 8)\n" - // Commit - "5:\n" - : [result] "=&r"(result), -#if !TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT - [underflow] "=@ccbe"(underflow), + "movq -16(%[scratch], %[current], 8), %[next]\n" + "lea -1(%[current]), %[current]\n" + "movw %w[current], (%[scratch], %[size_class], 4)\n" + // Commit + "5:\n" + : [result] "=&r"(result), +#if !TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + [underflow] "=@ccc"(underflow), #endif - [scratch] "=&r"(scratch), [current] "=&r"(current) - : [rseq_abi] "r"(&__rseq_abi), - [rseq_cs_offset] "n"(offsetof(kernel_rseq, rseq_cs)), - [rseq_cpu_offset] "r"(virtual_cpu_id_offset), - [rseq_sig] "n"(TCMALLOC_PERCPU_RSEQ_SIGNATURE), [shift] "c"(shift), - [slabs] "r"(slabs), [cl] "r"(cl) - : "cc", "memory" -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT - : underflow_path + [scratch] "=&r"(scratch), [current] "=&r"(current), [next] "=&r"(next) + : TCMALLOC_RSEQ_INPUTS, +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + [begin_mark_mask] "n"(kBeginMark), +#else + [begin_mark_bit] "n"(absl::countr_zero(kBeginMark)), +#endif + [size_class] "r"(size_class) + : "cc", "memory" +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + : underflow_path #endif - ); -#if !TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + ); +#if !TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT if (ABSL_PREDICT_FALSE(underflow)) { goto underflow_path; } #endif - - return result; + TC_ASSERT(next); + TC_ASSERT(result); + TSANAcquire(result); + + // The next pop will be from current-1, but because we prefetch the previous + // element we've already just read that, so prefetch current-2. + PrefetchSlabMemory(scratch + (current - 2) * sizeof(void*)); + PrefetchNextObject(next); + return AssumeNotNull(result); underflow_path: -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT - // As of 3/2020, LLVM's asm goto (even with output constraints) only provides - // values for the fallthrough path. The values on the taken branches are - // undefined. - int cpu = VirtualRseqCpuId(virtual_cpu_id_offset); -#else - // With asm goto--without output constraints--the value of scratch is - // well-defined by the compiler and our implementation. As an optimization on - // this case, we can avoid looking up cpu_id again, by undoing the - // transformation of cpu_id to the value of scratch. - int cpu = - (reinterpret_cast(scratch) - reinterpret_cast(slabs)) >> - shift; -#endif - return f(cpu, cl); + return nullptr; } #endif // defined(__x86_64__) -#if defined(__aarch64__) +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ && defined(__aarch64__) template -static inline ABSL_ATTRIBUTE_ALWAYS_INLINE void* TcmallocSlab_Internal_Pop( - typename TcmallocSlab::Slabs* slabs, size_t cl, - UnderflowHandler f, const size_t shift, - const size_t virtual_cpu_id_offset) { +inline ABSL_ATTRIBUTE_ALWAYS_INLINE void* TcmallocSlab::Pop( + size_t size_class) { + TC_ASSERT_NE(size_class, 0); void* result; void* region_start; - uint64_t cpu_id; - void* begin_ptr; - uintptr_t current; - uintptr_t new_current; - uintptr_t begin; - // Multiply cl by the bytesize of each header - size_t cl_lsl3 = cl * 8; -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT - asm goto + void* prefetch; + uintptr_t scratch; + uintptr_t previous; +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + asm goto( #else bool underflow; - asm + asm( #endif - ( - // TODO(b/141629158): __rseq_cs only needs to be writeable to allow - // for relocations, but could be read-only for non-PIE builds. - ".pushsection __rseq_cs, \"aw?\"\n" - ".balign 32\n" - ".local __rseq_cs_TcmallocSlab_Internal_Pop_%=\n" - ".type __rseq_cs_TcmallocSlab_Internal_Pop_%=,@object\n" - ".size __rseq_cs_TcmallocSlab_Internal_Pop_%=,32\n" - "__rseq_cs_TcmallocSlab_Internal_Pop_%=:\n" - ".long 0x0\n" - ".long 0x0\n" - ".quad 4f\n" - ".quad 5f - 4f\n" - ".quad 2f\n" - ".popsection\n" -#if !defined(__clang_major__) || __clang_major__ >= 9 - ".reloc 0, R_AARCH64_NONE, 1f\n" + TCMALLOC_RSEQ_PROLOGUE(TcmallocSlab_Internal_Pop) + // region_start = tcmalloc_slabs; + "ldr %[region_start], %[rseq_slabs_addr]\n" + // if (region_start & TCMALLOC_CACHED_SLABS_MASK) goto overflow_label; + // region_start &= ~TCMALLOC_CACHED_SLABS_MASK; +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + "tbz %[region_start], #%c[cached_slabs_bit], %l[underflow_path]\n" +#else + "tst %[region_start], %[cached_slabs_mask]\n" + "b.eq 5f\n" #endif - ".pushsection __rseq_cs_ptr_array, \"aw?\"\n" - "1:\n" - ".balign 8;" - ".quad __rseq_cs_TcmallocSlab_Internal_Pop_%=\n" - // Force this section to be retained. It is for debugging, but is - // otherwise not referenced. - ".popsection\n" - ".pushsection .text.unlikely, \"ax?\"\n" - ".long %c[rseq_sig]\n" - ".local TcmallocSlab_Internal_Pop_trampoline_%=\n" - ".type TcmallocSlab_Internal_Pop_trampoline_%=,@function\n" - "TcmallocSlab_Internal_Pop_trampoline_%=:\n" - "2:\n" - "b 3f\n" - ".popsection\n" - // Prepare - "3:\n" - // Use current as scratch here to hold address of this function's - // critical section - "adrp %[current], __rseq_cs_TcmallocSlab_Internal_Pop_%=\n" - "add %[current], %[current], " - ":lo12:__rseq_cs_TcmallocSlab_Internal_Pop_%=\n" - "str %[current], [%[rseq_abi], %c[rseq_cs_offset]]\n" - // Start - "4:\n" - // cpu_id = __rseq_abi.cpu_id; - "ldr %w[cpu_id], [%[rseq_abi], %[rseq_cpu_offset]]\n" - // region_start = Start of cpu region - "lsl %[region_start], %[cpu_id], %[shift]\n" - "add %[region_start], %[region_start], %[slabs]\n" - // begin_ptr = &(slab_headers[0]->begin) - "add %[begin_ptr], %[region_start], #4\n" - // current = slab_headers[cl]->current (current index) - "ldrh %w[current], [%[region_start], %[cl_lsl3]]\n" - // begin = slab_headers[cl]->begin (begin index) - "ldrh %w[begin], [%[begin_ptr], %[cl_lsl3]]\n" - // if (ABSL_PREDICT_FALSE(begin >= current)) { goto overflow; } - "cmp %w[begin], %w[current]\n" - "sub %w[new_current], %w[current], #1\n" -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT - "b.ge %l[underflow_path]\n" + "and %[region_start], %[region_start], #%c[cached_slabs_mask_neg]\n" + // scratch = slab_headers[size_class]->current (current index) + "ldrh %w[scratch], [%[region_start], %[size_class_lsl2]]\n" + // scratch-- + "sub %w[scratch], %w[scratch], #1\n" + "ldr %[result], [%[region_start], %[scratch], LSL #3]\n" +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + "tbnz %[result], #%c[begin_mark_bit], %l[underflow_path]\n" #else - "b.ge 5f\n" - // Important! code below this must not affect any flags (i.e.: ccbe) - // If so, the above code needs to explicitly set a ccbe return value. + // Temporary use %[previous] to store %[result] with inverted mark bit. + "eor %[previous], %[result], #%c[begin_mark_mask]\n" + "tst %[previous], #%c[begin_mark_mask]\n" + "b.eq 5f\n" + // Important! code below this must not affect any flags (i.e.: cceq) + // If so, the above code needs to explicitly set a cceq return value. +#endif + "sub %w[previous], %w[scratch], #1\n" + "ldr %[prefetch], [%[region_start], %[previous], LSL #3]\n" + "strh %w[scratch], [%[region_start], %[size_class_lsl2]]\n" + // Commit + "5:\n" + : +#if !TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + [underflow] "=@cceq"(underflow), #endif - // current-- - "ldr %[result], [%[region_start], %[new_current], LSL #3]\n" - "strh %w[new_current], [%[region_start], %[cl_lsl3]]\n" - // Commit - "5:\n" - : -#if !TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT - [underflow] "=@ccbe"(underflow), + [result] "=&r"(result), [prefetch] "=&r"(prefetch), + // Temps + [region_start] "=&r"(region_start), [previous] "=&r"(previous), + [scratch] "=&r"(scratch) + // Real inputs + : TCMALLOC_RSEQ_INPUTS, +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + [begin_mark_bit] "n"(absl::countr_zero(kBeginMark)), +#else + [cached_slabs_mask] "r"(TCMALLOC_CACHED_SLABS_MASK), #endif - [result] "=&r"(result), - // Temps - [cpu_id] "=&r"(cpu_id), [region_start] "=&r"(region_start), - [begin] "=&r"(begin), [current] "=&r"(current), - [new_current] "=&r"(new_current), [begin_ptr] "=&r"(begin_ptr) - // Real inputs - : [rseq_cpu_offset] "r"(virtual_cpu_id_offset), [slabs] "r"(slabs), - [cl_lsl3] "r"(cl_lsl3), [rseq_abi] "r"(&__rseq_abi), - [shift] "r"(shift), - // constants - [rseq_cs_offset] "in"(offsetof(kernel_rseq, rseq_cs)), - [rseq_sig] "in"(TCMALLOC_PERCPU_RSEQ_SIGNATURE) - : "cc", "memory" -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT - : underflow_path + [begin_mark_mask] "n"(kBeginMark), [size_class] "r"(size_class), + [size_class_lsl2] "r"(size_class << 2) + : TCMALLOC_RSEQ_CLOBBER, "memory" +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + , + "cc" + : underflow_path #endif - ); -#if !TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT + ); +#if !TCMALLOC_INTERNAL_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT if (ABSL_PREDICT_FALSE(underflow)) { goto underflow_path; } #endif - - return result; + TSANAcquire(result); + PrefetchNextObject(prefetch); + return AssumeNotNull(result); underflow_path: -#if TCMALLOC_PERCPU_USE_RSEQ_ASM_GOTO_OUTPUT - // As of 3/2020, LLVM's asm goto (even with output constraints) only provides - // values for the fallthrough path. The values on the taken branches are - // undefined. - int cpu = VirtualRseqCpuId(virtual_cpu_id_offset); -#else - // With asm goto--without output constraints--the value of scratch is - // well-defined by the compiler and our implementation. As an optimization on - // this case, we can avoid looking up cpu_id again, by undoing the - // transformation of cpu_id to the value of scratch. - int cpu = cpu_id; -#endif - return f(cpu, cl); + return nullptr; } #endif // defined(__aarch64__) +#if !TCMALLOC_INTERNAL_PERCPU_USE_RSEQ template inline ABSL_ATTRIBUTE_ALWAYS_INLINE void* TcmallocSlab::Pop( - size_t cl, UnderflowHandler f) { -#if defined(__x86_64__) || defined(__aarch64__) - return TcmallocSlab_Internal_Pop(slabs_, cl, f, shift_, - virtual_cpu_id_offset_); -#else - if (shift_ == TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT) { - return TcmallocSlab_Internal_Pop_FixedShift(slabs_, cl, f); - } else { - return TcmallocSlab_Internal_Pop(slabs_, cl, f, shift_); - } -#endif + size_t size_class) { + return nullptr; } +#endif -static inline void* NoopUnderflow(int cpu, size_t cl) { return nullptr; } - -static inline int NoopOverflow(int cpu, size_t cl, void* item) { return -1; } +template +inline size_t TcmallocSlab::Grow( + int cpu, size_t size_class, size_t len, + absl::FunctionRef max_capacity) { + const auto [slabs, shift] = GetSlabsAndShift(std::memory_order_relaxed); + const size_t max_cap = max_capacity(ToUint8(shift)); + auto* hdrp = GetHeader(slabs, shift, cpu, size_class); + Header hdr = LoadHeader(hdrp); + uint16_t begin = begins_[size_class].load(std::memory_order_relaxed); + ssize_t have = static_cast(max_cap - (hdr.end - begin)); + if (have <= 0) { + return 0; + } + uint16_t n = std::min(len, have); + hdr.end += n; + return StoreCurrentCpu(hdrp, hdr) ? n : 0; +} template -inline size_t TcmallocSlab::PushBatch(size_t cl, void** batch, - size_t len) { - ASSERT(len != 0); - if (shift_ == TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT) { -#if TCMALLOC_PERCPU_USE_RSEQ - // TODO(b/159923407): TcmallocSlab_Internal_PushBatch_FixedShift needs to be - // refactored to take a 5th parameter (virtual_cpu_id_offset) to avoid - // needing to dispatch on two separate versions of the same function with - // only minor differences between them. - switch (virtual_cpu_id_offset_) { - case offsetof(kernel_rseq, cpu_id): - return TcmallocSlab_Internal_PushBatch_FixedShift(slabs_, cl, batch, - len); -#ifdef __x86_64__ - case offsetof(kernel_rseq, vcpu_id): - return TcmallocSlab_Internal_PushBatch_FixedShift_VCPU(slabs_, cl, - batch, len); -#endif // __x86_64__ - default: - __builtin_unreachable(); - } -#else // !TCMALLOC_PERCPU_USE_RSEQ - __builtin_unreachable(); -#endif // !TCMALLOC_PERCPU_USE_RSEQ - } else { - size_t n = 0; - // Push items until either all done or a push fails - while (n < len && Push(cl, batch[len - 1 - n], NoopOverflow)) { - n++; - } - return n; +inline std::pair TcmallocSlab::CacheCpuSlab() { +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + if (ABSL_PREDICT_FALSE((tcmalloc_slabs & TCMALLOC_CACHED_SLABS_MASK) == 0)) { + return CacheCpuSlabSlow(); } + // We already have slab offset cached, so the slab is indeed full/empty. +#endif + return {VirtualCpu::GetAfterSynchronize(), false}; } template -inline size_t TcmallocSlab::PopBatch(size_t cl, void** batch, - size_t len) { - ASSERT(len != 0); - size_t n = 0; - if (shift_ == TCMALLOC_PERCPU_TCMALLOC_FIXED_SLAB_SHIFT) { -#if TCMALLOC_PERCPU_USE_RSEQ - // TODO(b/159923407): TcmallocSlab_Internal_PopBatch_FixedShift needs to be - // refactored to take a 5th parameter (virtual_cpu_id_offset) to avoid - // needing to dispatch on two separate versions of the same function with - // only minor differences between them. - switch (virtual_cpu_id_offset_) { - case offsetof(kernel_rseq, cpu_id): - n = TcmallocSlab_Internal_PopBatch_FixedShift(slabs_, cl, batch, len); - break; -#ifdef __x86_64__ - case offsetof(kernel_rseq, vcpu_id): - n = TcmallocSlab_Internal_PopBatch_FixedShift_VCPU(slabs_, cl, batch, - len); - break; -#endif // __x86_64__ - default: - __builtin_unreachable(); - } +inline void TcmallocSlab::UncacheCpuSlab() { +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + tcmalloc_slabs = 0; +#endif +} - // PopBatch is implemented in assembly, msan does not know that the returned - // batch is initialized. - ANNOTATE_MEMORY_IS_INITIALIZED(batch, n * sizeof(batch[0])); -#else // !TCMALLOC_PERCPU_USE_RSEQ - __builtin_unreachable(); -#endif // !TCMALLOC_PERCPU_USE_RSEQ - } else { - // Pop items until either all done or a pop fails - while (n < len && (batch[n] = Pop(cl, NoopUnderflow))) { - n++; - } - } +template +inline size_t TcmallocSlab::PushBatch(size_t size_class, + void** batch, size_t len) { + TC_ASSERT_NE(size_class, 0); + TC_ASSERT_NE(len, 0); + // We need to annotate batch[...] as released before running the restartable + // sequence, since those objects become visible to other threads the moment + // the restartable sequence is complete and before the annotation potentially + // runs. + // + // This oversynchronizes slightly, since PushBatch may succeed only partially. + TSANReleaseBatch(batch, len); + return TcmallocSlab_Internal_PushBatch(size_class, batch, len); +} + +template +inline size_t TcmallocSlab::PopBatch(size_t size_class, + void** batch, size_t len) { + TC_ASSERT_NE(size_class, 0); + TC_ASSERT_NE(len, 0); + const size_t n = TcmallocSlab_Internal_PopBatch(size_class, batch, len, + &begins_[size_class]); + TC_ASSERT_LE(n, len); + + // PopBatch is implemented in assembly, msan does not know that the returned + // batch is initialized. + ANNOTATE_MEMORY_IS_INITIALIZED(batch, n * sizeof(batch[0])); + TSANAcquireBatch(batch, n); return n; } template -inline typename TcmallocSlab::Slabs* -TcmallocSlab::CpuMemoryStart(int cpu) const { - char* const bytes = reinterpret_cast(slabs_); - return reinterpret_cast(&bytes[cpu << shift_]); +inline void* TcmallocSlab::CpuMemoryStart(void* slabs, Shift shift, + int cpu) { + return &static_cast(slabs)[cpu << ToUint8(shift)]; } template -inline std::atomic* TcmallocSlab::GetHeader( - int cpu, size_t cl) const { - return &CpuMemoryStart(cpu)->header[cl]; +inline auto TcmallocSlab::GetHeader(void* slabs, Shift shift, + int cpu, size_t size_class) + -> AtomicHeader* { + TC_ASSERT_NE(size_class, 0); + return &static_cast( + CpuMemoryStart(slabs, shift, cpu))[size_class]; } template -inline typename TcmallocSlab::Header -TcmallocSlab::LoadHeader(std::atomic* hdrp) { +inline auto TcmallocSlab::LoadHeader(AtomicHeader* hdrp) -> Header { return absl::bit_cast
(hdrp->load(std::memory_order_relaxed)); } template -inline void TcmallocSlab::StoreHeader(std::atomic* hdrp, +inline void TcmallocSlab::StoreHeader(AtomicHeader* hdrp, Header hdr) { - hdrp->store(absl::bit_cast(hdr), std::memory_order_relaxed); + hdrp->store(absl::bit_cast(hdr), std::memory_order_relaxed); } template -inline int TcmallocSlab::CompareAndSwapHeader( - int cpu, std::atomic* hdrp, Header old, Header hdr, - const size_t virtual_cpu_id_offset) { -#if __SIZEOF_POINTER__ == 8 - const int64_t old_raw = absl::bit_cast(old); - const int64_t new_raw = absl::bit_cast(hdr); - return CompareAndSwapUnsafe(cpu, hdrp, static_cast(old_raw), - static_cast(new_raw), - virtual_cpu_id_offset); -#else - Crash(kCrash, __FILE__, __LINE__, "This architecture is not supported."); +void TcmallocSlab::Init( + absl::FunctionRef alloc, void* slabs, + absl::FunctionRef capacity, Shift shift) { + stopped_ = new (alloc(sizeof(stopped_[0]) * NumCPUs(), + std::align_val_t{ABSL_CACHELINE_SIZE})) + std::atomic[NumCPUs()]; + for (int cpu = NumCPUs() - 1; cpu >= 0; cpu--) { + stopped_[cpu].store(false, std::memory_order_relaxed); + } + begins_ = static_cast*>(alloc( + sizeof(begins_[0]) * NumClasses, std::align_val_t{ABSL_CACHELINE_SIZE})); + InitSlabs(slabs, shift, capacity); + +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + // This is needed only for tests that create/destroy slabs, + // w/o this cpu_id_start may contain wrong offset for a new slab. + __rseq_abi.cpu_id_start = 0; #endif } template -inline bool TcmallocSlab::Header::IsLocked() const { - return begin == 0xffffu; +void TcmallocSlab::InitSlabs( + void* slabs, Shift shift, absl::FunctionRef capacity) { + slabs_and_shift_.store({slabs, shift}, std::memory_order_relaxed); + size_t consumed_bytes = + (NumClasses * sizeof(Header) + sizeof(void*) - 1) & ~(sizeof(void*) - 1); + bool prev_empty = false; + for (size_t size_class = 1; size_class < NumClasses; ++size_class) { + size_t cap = capacity(size_class); + TC_CHECK_EQ(static_cast(cap), cap); + // One extra element for prefetch/begin marker. + if (!prev_empty) { + consumed_bytes += sizeof(void*); + } + prev_empty = cap == 0; + begins_[size_class].store(consumed_bytes / sizeof(void*), + std::memory_order_relaxed); + consumed_bytes += cap * sizeof(void*); + if (consumed_bytes > (1 << ToUint8(shift))) { + TC_BUG("per-CPU memory exceeded, have %v, need %v, size_class %v", + 1 << ToUint8(shift), consumed_bytes, size_class); + } + } } template -inline void TcmallocSlab::Header::Lock() { - // Write 0xffff to begin and 0 to end. This blocks new Push'es and Pop's. - // Note: we write only 4 bytes. The first 4 bytes are left intact. - // See Drain method for details. tl;dr: C++ does not allow us to legally - // express this without undefined behavior. - std::atomic* p = - reinterpret_cast*>(&lock_update); - Header hdr; - hdr.begin = 0xffffu; - hdr.end = 0; - p->store(absl::bit_cast(hdr.lock_update), std::memory_order_relaxed); +void TcmallocSlab::InitCpu( + int cpu, absl::FunctionRef capacity) { + ScopedSlabCpuStop cpu_stop(*this, cpu); + const auto [slabs, shift] = GetSlabsAndShift(std::memory_order_relaxed); + InitCpuImpl(slabs, shift, cpu, capacity); } template -void TcmallocSlab::Init(void*(alloc)(size_t size), - size_t (*capacity)(size_t cl), bool lazy, - size_t shift) { -#ifdef __x86_64__ - if (UsingFlatVirtualCpus()) { - virtual_cpu_id_offset_ = offsetof(kernel_rseq, vcpu_id); - } -#endif // __x86_64__ - - shift_ = shift; - size_t mem_size = absl::base_internal::NumCPUs() * (1ul << shift); - void* backing = alloc(mem_size); - // MSan does not see writes in assembly. - ANNOTATE_MEMORY_IS_INITIALIZED(backing, mem_size); - if (!lazy) { - memset(backing, 0, mem_size); - } - slabs_ = static_cast(backing); - size_t bytes_used = 0; - for (int cpu = 0; cpu < absl::base_internal::NumCPUs(); ++cpu) { - bytes_used += sizeof(std::atomic) * NumClasses; - void** elems = CpuMemoryStart(cpu)->mem; - - for (size_t cl = 0; cl < NumClasses; ++cl) { - size_t cap = capacity(cl); - CHECK_CONDITION(static_cast(cap) == cap); - - if (cap == 0) { - continue; - } - - if (cap) { - if (!lazy) { - // In Pop() we prefetch the item a subsequent Pop() would return; this - // is slow if it's not a valid pointer. To avoid this problem when - // popping the last item, keep one fake item before the actual ones - // (that points, safely, to itself.) - *elems = elems; - elems++; - } - - // One extra element for prefetch - bytes_used += (cap + 1) * sizeof(void*); - } - - if (!lazy) { - // TODO(ckennelly): Consolidate this initialization logic with that in - // InitCPU. - size_t offset = elems - reinterpret_cast(CpuMemoryStart(cpu)); - CHECK_CONDITION(static_cast(offset) == offset); - - Header hdr; - hdr.current = offset; - hdr.begin = offset; - hdr.end = offset; - hdr.end_copy = offset; - - StoreHeader(GetHeader(cpu, cl), hdr); - } - - elems += cap; - CHECK_CONDITION(reinterpret_cast(elems) - - reinterpret_cast(CpuMemoryStart(cpu)) <= - (1 << shift_)); +void TcmallocSlab::InitCpuImpl( + void* slabs, Shift shift, int cpu, + absl::FunctionRef capacity) { + TC_CHECK(stopped_[cpu].load(std::memory_order_relaxed)); + TC_CHECK_LE((1 << ToUint8(shift)), (1 << 16) * sizeof(void*)); + + // Initialize prefetch target and compute the offsets for the + // boundaries of each size class' cache. + void* curr_slab = CpuMemoryStart(slabs, shift, cpu); + void** elems = reinterpret_cast( + (reinterpret_cast(GetHeader(slabs, shift, cpu, NumClasses)) + + sizeof(void*) - 1) & + ~(sizeof(void*) - 1)); + bool prev_empty = false; + for (size_t size_class = 1; size_class < NumClasses; ++size_class) { + size_t cap = capacity(size_class); + TC_CHECK_EQ(static_cast(cap), cap); + + // This item serves both as the marker of slab begin (Pop checks for low bit + // set to understand that it reached begin), and as prefetching stub + // (Pop prefetches the previous element and prefetching an invalid pointer + // is slow, this is a valid pointer for prefetching). + if (!prev_empty) { + *elems = reinterpret_cast(reinterpret_cast(elems) | + kBeginMark); + ++elems; + } + prev_empty = cap == 0; + + Header hdr = {}; + hdr.current = elems - reinterpret_cast(curr_slab); + hdr.end = hdr.current; + StoreHeader(GetHeader(slabs, shift, cpu, size_class), hdr); + + elems += cap; + const size_t bytes_used_on_curr_slab = + reinterpret_cast(elems) - reinterpret_cast(curr_slab); + if (bytes_used_on_curr_slab > (1 << ToUint8(shift))) { + TC_BUG("per-CPU memory exceeded, have %v, need %v", 1 << ToUint8(shift), + bytes_used_on_curr_slab); } - } - // Check for less than 90% usage of the reserved memory - if (bytes_used * 10 < 9 * mem_size) { - Log(kLog, __FILE__, __LINE__, "Bytes used per cpu of available", bytes_used, - mem_size); } } +#if TCMALLOC_INTERNAL_PERCPU_USE_RSEQ template -void TcmallocSlab::InitCPU(int cpu, size_t (*capacity)(size_t cl)) { - const size_t virtual_cpu_id_offset = virtual_cpu_id_offset_; - - // TODO(ckennelly): Consolidate this logic with Drain. - // Phase 1: verify no header is locked - for (size_t cl = 0; cl < NumClasses; ++cl) { - Header hdr = LoadHeader(GetHeader(cpu, cl)); - CHECK_CONDITION(!hdr.IsLocked()); - } - - // Phase 2: Stop concurrent mutations. Locking ensures that there exists no - // value of current such that begin < current. - for (bool done = false; !done;) { - for (size_t cl = 0; cl < NumClasses; ++cl) { - // Note: this reinterpret_cast and write in Lock lead to undefined - // behavior, because the actual object type is std::atomic. But - // C++ does not allow to legally express what we need here: atomic writes - // of different sizes. - reinterpret_cast(GetHeader(cpu, cl))->Lock(); +std::pair TcmallocSlab::CacheCpuSlabSlow() { + TC_ASSERT(!(tcmalloc_slabs & TCMALLOC_CACHED_SLABS_MASK)); + int vcpu = -1; + for (;;) { + tcmalloc_slabs = TCMALLOC_CACHED_SLABS_MASK; + CompilerBarrier(); + vcpu = VirtualCpu::Synchronize(); + auto slabs_and_shift = slabs_and_shift_.load(std::memory_order_relaxed); + const auto [slabs, shift] = slabs_and_shift.Get(); + void* start = CpuMemoryStart(slabs, shift, vcpu); + uintptr_t new_val = + reinterpret_cast(start) | TCMALLOC_CACHED_SLABS_MASK; + if (!StoreCurrentCpu(&tcmalloc_slabs, new_val)) { + continue; + } + // If ResizeSlabs is concurrently modifying slabs_and_shift_, we may + // cache the offset with the shift that won't match slabs pointer used + // by Push/Pop operations later. To avoid this, we check stopped_ after + // the calculation. Coupled with setting of stopped_ and a Fence + // in ResizeSlabs, this prevents possibility of mismatching shift/slabs. + CompilerBarrier(); + if (stopped_[vcpu].load(std::memory_order_acquire)) { + tcmalloc_slabs = 0; + return {-1, true}; } - FenceCpu(cpu, virtual_cpu_id_offset); - done = true; - for (size_t cl = 0; cl < NumClasses; ++cl) { - Header hdr = LoadHeader(GetHeader(cpu, cl)); - if (!hdr.IsLocked()) { - // Header was overwritten by Grow/Shrink. Retry. - done = false; - break; - } + // Ensure that we've cached the current slabs pointer. + // Without this check the following bad interleaving is possible. + // Thread 1 executes ResizeSlabs, stops all CPUs and executes Fence. + // Now thread 2 executes CacheCpuSlabSlow, reads old slabs and caches + // the pointer. Now thread 1 stores the new slabs pointer and resets + // stopped_[cpu]. Now thread 2 resumes, checks that stopped_[cpu] is not + // set and proceeds with using the old slabs pointer. Since we use + // acquire/release on stopped_[cpu], if this thread observes reset + // stopped_[cpu], it's also guaranteed to observe the new value of slabs + // and retry. In the very unlikely case that slabs are resized twice in + // between (to new slabs and then back to old slabs), the check below will + // not lead to a retry, but changing slabs back also implies another Fence, + // so this thread won't have old slabs cached already (Fence invalidates + // the cached pointer). + if (slabs_and_shift != slabs_and_shift_.load(std::memory_order_relaxed)) { + continue; } + return {vcpu, true}; } +} +#endif - // Phase 3: Initialize prefetch target and compute the offsets for the - // boundaries of each size class' cache. - void** elems = CpuMemoryStart(cpu)->mem; - uint16_t begin[NumClasses]; - for (size_t cl = 0; cl < NumClasses; ++cl) { - size_t cap = capacity(cl); - CHECK_CONDITION(static_cast(cap) == cap); - - if (cap) { - // In Pop() we prefetch the item a subsequent Pop() would return; this is - // slow if it's not a valid pointer. To avoid this problem when popping - // the last item, keep one fake item before the actual ones (that points, - // safely, to itself.) - *elems = elems; - elems++; +template +void TcmallocSlab::DrainCpu(void* slabs, Shift shift, int cpu, + DrainHandler drain_handler) { + TC_ASSERT(stopped_[cpu].load(std::memory_order_relaxed)); + for (size_t size_class = 1; size_class < NumClasses; ++size_class) { + uint16_t begin = begins_[size_class].load(std::memory_order_relaxed); + auto* hdrp = GetHeader(slabs, shift, cpu, size_class); + Header hdr = LoadHeader(hdrp); + if (hdr.current == 0) { + continue; } + const size_t size = hdr.current - begin; + const size_t cap = hdr.end - begin; - size_t offset = elems - reinterpret_cast(CpuMemoryStart(cpu)); - CHECK_CONDITION(static_cast(offset) == offset); - begin[cl] = offset; - - elems += cap; - CHECK_CONDITION(reinterpret_cast(elems) - - reinterpret_cast(CpuMemoryStart(cpu)) <= - (1 << shift_)); + void** batch = + reinterpret_cast(CpuMemoryStart(slabs, shift, cpu)) + begin; + TSANAcquireBatch(batch, size); + drain_handler(cpu, size_class, batch, size, cap); + hdr.current = begin; + hdr.end = begin; + StoreHeader(hdrp, hdr); } +} - // Phase 4: Store current. No restartable sequence will proceed - // (successfully) as !(begin < current) for all size classes. - for (size_t cl = 0; cl < NumClasses; ++cl) { - std::atomic* hdrp = GetHeader(cpu, cl); +template +void TcmallocSlab::DrainOldSlabs( + void* slabs, Shift shift, int cpu, + const std::array& old_begins, + DrainHandler drain_handler) { + for (size_t size_class = 1; size_class < NumClasses; ++size_class) { + uint16_t begin = old_begins[size_class]; + auto* hdrp = GetHeader(slabs, shift, cpu, size_class); Header hdr = LoadHeader(hdrp); - hdr.current = begin[cl]; + if (hdr.current == 0) { + continue; + } + const size_t size = hdr.current - begin; + const size_t cap = hdr.end - begin; + + void** batch = + reinterpret_cast(CpuMemoryStart(slabs, shift, cpu)) + begin; + TSANAcquireBatch(batch, size); + drain_handler(cpu, size_class, batch, size, cap); + hdr.current = begin; + hdr.end = begin; StoreHeader(hdrp, hdr); } - FenceCpu(cpu, virtual_cpu_id_offset); - - // Phase 5: Allow access to this cache. - for (size_t cl = 0; cl < NumClasses; ++cl) { - Header hdr; - hdr.current = begin[cl]; - hdr.begin = begin[cl]; - hdr.end = begin[cl]; - hdr.end_copy = begin[cl]; - StoreHeader(GetHeader(cpu, cl), hdr); - } } template -void TcmallocSlab::Destroy(void(free)(void*)) { - free(slabs_); - slabs_ = nullptr; -} +ResizeSlabsInfo TcmallocSlab::UpdateMaxCapacities( + void* new_slabs, absl::FunctionRef capacity, + absl::FunctionRef update_capacity, + absl::FunctionRef populated, DrainHandler drain_handler, + PerSizeClassMaxCapacity* new_max_capacity, int classes_to_resize) { + // Phase 1: Stop all CPUs and initialize any CPUs in the new slab that have + // already been populated in the old slab. + const auto [old_slabs, shift] = GetSlabsAndShift(std::memory_order_relaxed); + std::array old_begins; + for (int size_class = 1; size_class < NumClasses; ++size_class) { + old_begins[size_class] = + begins_[size_class].load(std::memory_order_relaxed); + } -template -size_t TcmallocSlab::ShrinkOtherCache(int cpu, size_t cl, - size_t len, void* ctx, - ShrinkHandler f) { - ASSERT(cpu >= 0); - ASSERT(cpu < absl::base_internal::NumCPUs()); - const size_t virtual_cpu_id_offset = virtual_cpu_id_offset_; - - // Phase 1: Collect begin as it will be overwritten by the lock. - std::atomic* hdrp = GetHeader(cpu, cl); - Header hdr = LoadHeader(hdrp); - CHECK_CONDITION(!hdr.IsLocked()); - const uint16_t begin = hdr.begin; - - // Phase 2: stop concurrent mutations. - for (bool done = false; !done;) { - reinterpret_cast(GetHeader(cpu, cl))->Lock(); - FenceCpu(cpu, virtual_cpu_id_offset); - done = true; - - hdr = LoadHeader(GetHeader(cpu, cl)); - if (!hdr.IsLocked()) { - // Header was overwritten by Grow/Shrink. Retry. - done = false; - } + const int num_cpus = NumCPUs(); + for (size_t cpu = 0; cpu < num_cpus; ++cpu) { + TC_CHECK(!stopped_[cpu].load(std::memory_order_relaxed)); + stopped_[cpu].store(true, std::memory_order_relaxed); } + FenceAllCpus(); - // Phase 3: If we do not have len number of items to shrink, we try - // to pop items from the list first to create enough capacity that can be - // shrunk. If we pop items, we also execute callbacks. - // - // We can't write all 4 fields at once with a single write, because Pop does - // several non-atomic loads of the fields. Consider that a concurrent Pop - // loads old current (still pointing somewhere in the middle of the region); - // then we update all fields with a single write; then Pop loads the updated - // begin which allows it to proceed; then it decrements current below begin. - // - // So we instead first just update current--our locked begin/end guarantee - // no Push/Pop will make progress. Once we Fence below, we know no Push/Pop - // is using the old current, and can safely update begin/end to be an empty - // slab. - - const uint16_t unused = hdr.end_copy - hdr.current; - if (unused < len) { - const uint16_t expected_pop = len - unused; - const uint16_t actual_pop = - std::min(expected_pop, hdr.current - begin); - void** batch = - reinterpret_cast(GetHeader(cpu, 0) + hdr.current - actual_pop); - f(ctx, cl, batch, actual_pop); - hdr.current -= actual_pop; - StoreHeader(hdrp, hdr); - FenceCpu(cpu, virtual_cpu_id_offset); + // Phase 2: Update max capacity of the size classes. + for (int i = 0; i < classes_to_resize; ++i) { + size_t size_class = new_max_capacity[i].size_class; + size_t cap = new_max_capacity[i].max_capacity; + update_capacity(size_class, cap); } - // Phase 4: Shrink the capacity. Use a copy of begin and end_copy to - // restore the header, shrink it, and return the length by which the - // region was shrunk. - hdr.begin = begin; - const uint16_t to_shrink = - std::min(len, hdr.end_copy - hdr.current); - hdr.end_copy -= to_shrink; - hdr.end = hdr.end_copy; - StoreHeader(hdrp, hdr); - return to_shrink; + // Phase 3: Initialize slabs. + for (size_t cpu = 0; cpu < num_cpus; ++cpu) { + if (!populated(cpu)) continue; + InitCpuImpl(new_slabs, shift, cpu, capacity); + } + InitSlabs(new_slabs, shift, capacity); + + // Phase 4: Re-start all CPUs. + for (size_t cpu = 0; cpu < num_cpus; ++cpu) { + stopped_[cpu].store(false, std::memory_order_release); + } + + // Phase 5: Return pointers from the old slab to the TransferCache. + for (size_t cpu = 0; cpu < num_cpus; ++cpu) { + if (!populated(cpu)) continue; + DrainOldSlabs(old_slabs, shift, cpu, old_begins, drain_handler); + } + return {old_slabs, GetSlabsAllocSize(shift, num_cpus)}; } template -void TcmallocSlab::Drain(int cpu, void* ctx, DrainHandler f) { - CHECK_CONDITION(cpu >= 0); - CHECK_CONDITION(cpu < absl::base_internal::NumCPUs()); - const size_t virtual_cpu_id_offset = virtual_cpu_id_offset_; - - // Push/Pop/Grow/Shrink can be executed concurrently with Drain. - // That's not an expected case, but it must be handled for correctness. - // Push/Pop/Grow/Shrink can only be executed on and use rseq primitives. - // Push only updates current. Pop only updates current and end_copy - // (it mutates only current but uses 4 byte write for performance). - // Grow/Shrink mutate end and end_copy using 64-bit stores. - - // We attempt to stop all concurrent operations by writing 0xffff to begin - // and 0 to end. However, Grow/Shrink can overwrite our write, so we do this - // in a loop until we know that the header is in quiescent state. - - // Phase 1: collect all begin's (these are not mutated by anybody else). - uint16_t begin[NumClasses]; - for (size_t cl = 0; cl < NumClasses; ++cl) { - Header hdr = LoadHeader(GetHeader(cpu, cl)); - CHECK_CONDITION(!hdr.IsLocked()); - begin[cl] = hdr.begin; +auto TcmallocSlab::ResizeSlabs( + Shift new_shift, void* new_slabs, + absl::FunctionRef capacity, + absl::FunctionRef populated, DrainHandler drain_handler) + -> ResizeSlabsInfo { + // Phase 1: Collect begins, stop all CPUs and initialize any CPUs in the new + // slab that have already been populated in the old slab. + const auto [old_slabs, old_shift] = + GetSlabsAndShift(std::memory_order_relaxed); + std::array old_begins; + for (int size_class = 1; size_class < NumClasses; ++size_class) { + old_begins[size_class] = + begins_[size_class].load(std::memory_order_relaxed); } - // Phase 2: stop concurrent mutations. - for (bool done = false; !done;) { - for (size_t cl = 0; cl < NumClasses; ++cl) { - // Note: this reinterpret_cast and write in Lock lead to undefined - // behavior, because the actual object type is std::atomic. But - // C++ does not allow to legally express what we need here: atomic writes - // of different sizes. - reinterpret_cast(GetHeader(cpu, cl))->Lock(); - } - FenceCpu(cpu, virtual_cpu_id_offset); - done = true; - for (size_t cl = 0; cl < NumClasses; ++cl) { - Header hdr = LoadHeader(GetHeader(cpu, cl)); - if (!hdr.IsLocked()) { - // Header was overwritten by Grow/Shrink. Retry. - done = false; - break; - } + TC_ASSERT_NE(new_shift, old_shift); + const int num_cpus = NumCPUs(); + for (size_t cpu = 0; cpu < num_cpus; ++cpu) { + TC_CHECK(!stopped_[cpu].load(std::memory_order_relaxed)); + stopped_[cpu].store(true, std::memory_order_relaxed); + if (populated(cpu)) { + InitCpuImpl(new_slabs, new_shift, cpu, capacity); } } + FenceAllCpus(); - // Phase 3: execute callbacks. - for (size_t cl = 0; cl < NumClasses; ++cl) { - Header hdr = LoadHeader(GetHeader(cpu, cl)); - // We overwrote begin and end, instead we use our local copy of begin - // and end_copy. - size_t n = hdr.current - begin[cl]; - size_t cap = hdr.end_copy - begin[cl]; - void** batch = reinterpret_cast(GetHeader(cpu, 0) + begin[cl]); - f(ctx, cl, batch, n, cap); + // Phase 2: Atomically update slabs and shift. + InitSlabs(new_slabs, new_shift, capacity); + + // Phase 3: Re-start all CPUs. + for (size_t cpu = 0; cpu < num_cpus; ++cpu) { + stopped_[cpu].store(false, std::memory_order_release); } - // Phase 4: reset current to beginning of the region. - // We can't write all 4 fields at once with a single write, because Pop does - // several non-atomic loads of the fields. Consider that a concurrent Pop - // loads old current (still pointing somewhere in the middle of the region); - // then we update all fields with a single write; then Pop loads the updated - // begin which allows it to proceed; then it decrements current below begin. - // - // So we instead first just update current--our locked begin/end guarantee - // no Push/Pop will make progress. Once we Fence below, we know no Push/Pop - // is using the old current, and can safely update begin/end to be an empty - // slab. - for (size_t cl = 0; cl < NumClasses; ++cl) { - std::atomic* hdrp = GetHeader(cpu, cl); - Header hdr = LoadHeader(hdrp); - hdr.current = begin[cl]; - StoreHeader(hdrp, hdr); + // Phase 4: Return pointers from the old slab to the TransferCache. + for (size_t cpu = 0; cpu < num_cpus; ++cpu) { + if (!populated(cpu)) continue; + DrainOldSlabs(old_slabs, old_shift, cpu, old_begins, drain_handler); } - // Phase 5: fence and reset the remaining fields to beginning of the region. - // This allows concurrent mutations again. - FenceCpu(cpu, virtual_cpu_id_offset); - for (size_t cl = 0; cl < NumClasses; ++cl) { - std::atomic* hdrp = GetHeader(cpu, cl); - Header hdr; - hdr.current = begin[cl]; - hdr.begin = begin[cl]; - hdr.end = begin[cl]; - hdr.end_copy = begin[cl]; - StoreHeader(hdrp, hdr); + return {old_slabs, GetSlabsAllocSize(old_shift, num_cpus)}; +} + +template +void* TcmallocSlab::Destroy( + absl::FunctionRef free) { + free(stopped_, sizeof(stopped_[0]) * NumCPUs(), + std::align_val_t{ABSL_CACHELINE_SIZE}); + stopped_ = nullptr; + free(begins_, sizeof(begins_[0]) * NumClasses, + std::align_val_t{ABSL_CACHELINE_SIZE}); + begins_ = nullptr; + const auto [slabs, shift] = GetSlabsAndShift(std::memory_order_relaxed); + free(slabs, GetSlabsAllocSize(shift, NumCPUs()), kPhysicalPageAlign); + slabs_and_shift_.store({nullptr, shift}, std::memory_order_relaxed); + return slabs; +} + +template +size_t TcmallocSlab::GrowOtherCache( + int cpu, size_t size_class, size_t len, + absl::FunctionRef max_capacity) { + TC_ASSERT(stopped_[cpu].load(std::memory_order_relaxed)); + const auto [slabs, shift] = GetSlabsAndShift(std::memory_order_relaxed); + const size_t max_cap = max_capacity(ToUint8(shift)); + auto* hdrp = GetHeader(slabs, shift, cpu, size_class); + Header hdr = LoadHeader(hdrp); + uint16_t begin = begins_[size_class].load(std::memory_order_relaxed); + uint16_t to_grow = std::min(len, max_cap - (hdr.end - begin)); + hdr.end += to_grow; + StoreHeader(hdrp, hdr); + return to_grow; +} + +template +size_t TcmallocSlab::ShrinkOtherCache( + int cpu, size_t size_class, size_t len, ShrinkHandler shrink_handler) { + TC_ASSERT(stopped_[cpu].load(std::memory_order_relaxed)); + const auto [slabs, shift] = GetSlabsAndShift(std::memory_order_relaxed); + + auto* hdrp = GetHeader(slabs, shift, cpu, size_class); + Header hdr = LoadHeader(hdrp); + + // If we do not have len number of items to shrink, we try to pop items from + // the list first to create enough capacity that can be shrunk. + // If we pop items, we also execute callbacks. + const uint16_t unused = hdr.end - hdr.current; + uint16_t begin = begins_[size_class].load(std::memory_order_relaxed); + if (unused < len && hdr.current != begin) { + uint16_t pop = std::min(len - unused, hdr.current - begin); + void** batch = reinterpret_cast(CpuMemoryStart(slabs, shift, cpu)) + + hdr.current - pop; + TSANAcquireBatch(batch, pop); + shrink_handler(size_class, batch, pop); + hdr.current -= pop; } + + // Shrink the capacity. + const uint16_t to_shrink = std::min(len, hdr.end - hdr.current); + hdr.end -= to_shrink; + StoreHeader(hdrp, hdr); + return to_shrink; +} + +template +void TcmallocSlab::Drain(int cpu, DrainHandler drain_handler) { + ScopedSlabCpuStop cpu_stop(*this, cpu); + const auto [slabs, shift] = GetSlabsAndShift(std::memory_order_relaxed); + DrainCpu(slabs, shift, cpu, drain_handler); +} + +template +void TcmallocSlab::StopCpu(int cpu) { + TC_ASSERT(cpu >= 0 && cpu < NumCPUs(), "cpu=%d", cpu); + TC_CHECK(!stopped_[cpu].load(std::memory_order_relaxed)); + stopped_[cpu].store(true, std::memory_order_relaxed); + FenceCpu(cpu); +} + +template +void TcmallocSlab::StartCpu(int cpu) { + TC_ASSERT(cpu >= 0 && cpu < NumCPUs(), "cpu=%d", cpu); + TC_ASSERT(stopped_[cpu].load(std::memory_order_relaxed)); + stopped_[cpu].store(false, std::memory_order_release); } template PerCPUMetadataState TcmallocSlab::MetadataMemoryUsage() const { PerCPUMetadataState result; - result.virtual_size = absl::base_internal::NumCPUs() * (1ul << shift_); - result.resident_size = MInCore::residence(slabs_, result.virtual_size); + const auto [slabs, shift] = GetSlabsAndShift(std::memory_order_relaxed); + size_t slabs_size = GetSlabsAllocSize(shift, NumCPUs()); + size_t stopped_size = NumCPUs() * sizeof(stopped_[0]); + size_t begins_size = NumClasses * sizeof(begins_[0]); + result.virtual_size = stopped_size + slabs_size + begins_size; + result.resident_size = MInCore::residence(slabs, slabs_size); return result; } diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_tcmalloc_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_tcmalloc_test.cc index 39f07fbe670b..1d3e42949e50 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_tcmalloc_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_tcmalloc_test.cc @@ -14,31 +14,57 @@ #include "tcmalloc/internal/percpu_tcmalloc.h" +#include #include +#include #include #include #include +#include +#include + +#include "absl/functional/function_ref.h" +#include "tcmalloc/internal/cpu_utils.h" +#include "tcmalloc/internal/percpu.h" + +#if defined(__linux__) +#include +#else +#include +#endif + +#include +#include #include +#include +#include +#include +#include +#include #include // NOLINT(build/c++11) +#include +#include #include +#include "benchmark/benchmark.h" #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/internal/sysinfo.h" +#include "absl/base/call_once.h" +#include "absl/base/thread_annotations.h" #include "absl/container/fixed_array.h" #include "absl/container/flat_hash_set.h" -#include "absl/debugging/symbolize.h" #include "absl/random/random.h" #include "absl/random/seed_sequences.h" -#include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "absl/time/clock.h" #include "absl/time/time.h" #include "absl/types/span.h" -#include "benchmark/benchmark.h" +#include "tcmalloc/internal/affinity.h" #include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/page_size.h" +#include "tcmalloc/internal/sysinfo.h" #include "tcmalloc/internal/util.h" #include "tcmalloc/malloc_extension.h" #include "tcmalloc/testing/testutil.h" @@ -52,203 +78,112 @@ namespace { using testing::Each; using testing::UnorderedElementsAreArray; -// Choose an available CPU and executes the passed functor on it. The -// cpu that is chosen, as long as a valid disjoint remote CPU will be passed -// as arguments to it. -// -// If the functor believes that it has failed in a manner attributable to -// external modification, then it should return false and we will attempt to -// retry the operation (up to a constant limit). -void RunOnSingleCpuWithRemoteCpu(std::function test) { - constexpr int kMaxTries = 1000; - - for (int i = 0; i < kMaxTries; i++) { - auto allowed = AllowedCpus(); - - int target_cpu = allowed[0], remote_cpu; - - // We try to pass something actually within the mask, but, for most tests it - // only needs to exist. - if (allowed.size() > 1) - remote_cpu = allowed[1]; - else - remote_cpu = target_cpu ? 0 : 1; - - ScopedAffinityMask mask(target_cpu); - - // If the test function failed, assert that the mask was tampered with. - if (!test(target_cpu, remote_cpu)) - ASSERT_TRUE(mask.Tampered()); - else - return; - } +constexpr size_t kStressSlabs = 5; +constexpr size_t kStressCapacity = 4; +constexpr size_t kMaxStressCapacity = kStressCapacity * 2; - ASSERT_TRUE(false); -} +constexpr size_t kShift = 18; +typedef class TcmallocSlab TcmallocSlab; -// Equivalent to RunOnSingleCpuWithRemoteCpu, except that only the CPU the -// functor is executing on is passed. -void RunOnSingleCpu(std::function test) { - auto wrapper = [&test](int this_cpu, int unused) { return test(this_cpu); }; - RunOnSingleCpuWithRemoteCpu(wrapper); +void* AllocSlabs(absl::FunctionRef alloc, + size_t raw_shift) { + Shift shift = ToShiftType(raw_shift); + const size_t slabs_size = GetSlabsAllocSize(shift, NumCPUs()); + return alloc(slabs_size, kPhysicalPageAlign); } -constexpr size_t kStressSlabs = 4; -constexpr size_t kStressCapacity = 4; +void InitSlab(TcmallocSlab& slab, + absl::FunctionRef alloc, + absl::FunctionRef capacity, size_t raw_shift) { + void* slabs = AllocSlabs(alloc, raw_shift); + slab.Init(alloc, slabs, capacity, ToShiftType(raw_shift)); +} -constexpr size_t kShift = 18; -typedef class TcmallocSlab TcmallocSlab; +struct GetMaxCapacity { + size_t operator()(size_t size_class) const { + if (size_class >= kStressSlabs) return 0; + return max_capacities[size_class].load(std::memory_order_relaxed); + } -enum class SlabInit { - kEager, - kLazy, + const std::atomic* max_capacities; }; -class TcmallocSlabTest : public testing::TestWithParam { - protected: +class TcmallocSlabTest : public testing::Test { + public: TcmallocSlabTest() { - slab_test_ = &slab_; - metadata_bytes_ = 0; - // Ignore false-positive warning in GCC. For more information, see: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96003 #pragma GCC diagnostic ignored "-Wnonnull" - slab_.Init( - &ByteCountingMalloc, [](size_t cl) { return kCapacity; }, - GetParam() == SlabInit::kLazy, kShift); - - for (int i = 0; i < kCapacity; ++i) { - object_ptrs_[i] = &objects_[i]; - } - } - - ~TcmallocSlabTest() override { slab_.Destroy(free); } - - template - static int ExpectOverflow(int cpu, size_t cl, void* item) { - EXPECT_EQ(cpu, current_cpu_); - EXPECT_EQ(cl, current_cl_); - EXPECT_FALSE(overflow_called_); - overflow_called_ = true; - return result; - } - - template - static void* ExpectUnderflow(int cpu, size_t cl) { - EXPECT_EQ(cpu, current_cpu_); - EXPECT_EQ(cl, current_cl_); - EXPECT_LT(result_object, kCapacity); - EXPECT_FALSE(underflow_called_); - underflow_called_ = true; - return &objects_[result_object]; - } - - template - bool PushExpectOverflow(TcmallocSlab* slab, size_t cl, void* item) { - bool res = slab->Push(cl, item, ExpectOverflow); - EXPECT_TRUE(overflow_called_); - overflow_called_ = false; - return res; + InitSlab( + slab_, + [&](size_t size, std::align_val_t align) { + return ByteCountingMalloc(size, align); + }, + [](size_t) { return kCapacity; }, kShift); } - template - void* PopExpectUnderflow(TcmallocSlab* slab, size_t cl) { - void* res = slab->Pop(cl, ExpectUnderflow); - EXPECT_TRUE(underflow_called_); - underflow_called_ = false; - return res; - } + ~TcmallocSlabTest() override { slab_.Destroy(sized_aligned_delete); } - static void* ByteCountingMalloc(size_t size) { - const size_t kPageSize = getpagesize(); - void* ptr; - CHECK_CONDITION(posix_memalign(&ptr, kPageSize, size) == 0); - if (ptr) { - // Emulate obtaining memory as if we got it from mmap (zero'd). - memset(ptr, 0, size); + void* ByteCountingMalloc(size_t size, std::align_val_t alignment) { + void* ptr = ::operator new(size, alignment); + // Emulate obtaining memory as if we got it from mmap (zero'd). + memset(ptr, 0, size); + if (static_cast(alignment) >= GetPageSize()) { madvise(ptr, size, MADV_DONTNEED); - metadata_bytes_ += size; } + metadata_bytes_ += size; return ptr; } TcmallocSlab slab_; - static constexpr size_t kCapacity = 10; - static char objects_[kCapacity]; - static void* object_ptrs_[kCapacity]; - static int current_cpu_; - static size_t current_cl_; - static bool overflow_called_; - static bool underflow_called_; - static TcmallocSlab* slab_test_; - static size_t metadata_bytes_; + size_t metadata_bytes_ = 0; }; -static int ExpectNoOverflow(int cpu, size_t cl, void* item) { - CHECK_CONDITION(false && "overflow is not expected"); - return 0; -} - -static void* ExpectNoUnderflow(int cpu, size_t cl) { - CHECK_CONDITION(false && "underflow is not expected"); - return nullptr; -} - -char TcmallocSlabTest::objects_[TcmallocSlabTest::kCapacity]; -void* TcmallocSlabTest::object_ptrs_[TcmallocSlabTest::kCapacity]; -int TcmallocSlabTest::current_cpu_; -size_t TcmallocSlabTest::current_cl_; -bool TcmallocSlabTest::overflow_called_; -bool TcmallocSlabTest::underflow_called_; -TcmallocSlab* TcmallocSlabTest::slab_test_; -size_t TcmallocSlabTest::metadata_bytes_; - -TEST_P(TcmallocSlabTest, Metadata) { +TEST_F(TcmallocSlabTest, Metadata) { PerCPUMetadataState r = slab_.MetadataMemoryUsage(); ASSERT_GT(metadata_bytes_, 0); EXPECT_EQ(r.virtual_size, metadata_bytes_); - if (GetParam() == SlabInit::kLazy) { - EXPECT_EQ(r.resident_size, 0); + EXPECT_EQ(r.resident_size, 0); - if (!IsFast()) { - GTEST_SKIP() << "Need fast percpu. Skipping."; - return; - } + if (!IsFast()) { + GTEST_SKIP() << "Need fast percpu. Skipping."; + return; + } - // Initialize a core. Verify that the increased RSS is proportional to a - // core. - slab_.InitCPU(0, [](size_t cl) { return kCapacity; }); - - r = slab_.MetadataMemoryUsage(); - // We may fault a whole hugepage, so round up the expected per-core share to - // a full hugepage. - size_t expected = r.virtual_size / absl::base_internal::NumCPUs(); - expected = (expected + kHugePageSize - 1) & ~(kHugePageSize - 1); - - // A single core may be less than the full slab for that core, since we do - // not touch every page within the slab. - EXPECT_GE(expected, r.resident_size); - - // Read stats from the slab. This will fault additional memory. - for (int cpu = 0, n = absl::base_internal::NumCPUs(); cpu < n; ++cpu) { - // To inhibit optimization, verify the values are sensible. - for (int cl = 0; cl < kStressSlabs; ++cl) { - EXPECT_EQ(0, slab_.Length(cpu, cl)); - EXPECT_EQ(0, slab_.Capacity(cpu, cl)); - } + // Initialize a core. Verify that the increased RSS is proportional to a + // core. + slab_.InitCpu(0, [](size_t size_class) { return kCapacity; }); + + r = slab_.MetadataMemoryUsage(); + // We may fault a whole hugepage, so round up the expected per-core share to + // a full hugepage. + size_t expected = r.virtual_size / NumCPUs(); + expected = (expected + kHugePageSize - 1) & ~(kHugePageSize - 1); + + // A single core may be less than the full slab for that core, since we do + // not touch every page within the slab. + EXPECT_GE(expected, r.resident_size); + // We expect to have touched at least one page, so resident size should be a + // non-zero number of bytes. + EXPECT_GT(r.resident_size, 0); + + // Read stats from the slab. This will fault additional memory. + for (int cpu = 0, n = NumCPUs(); cpu < n; ++cpu) { + // To inhibit optimization, verify the values are sensible. + for (int size_class = 1; size_class < kStressSlabs; ++size_class) { + EXPECT_EQ(0, slab_.Length(cpu, size_class)); + EXPECT_EQ(0, slab_.Capacity(cpu, size_class)); } - - PerCPUMetadataState post_stats = slab_.MetadataMemoryUsage(); - EXPECT_LE(post_stats.resident_size, metadata_bytes_); - EXPECT_GT(post_stats.resident_size, r.resident_size); - } else { - EXPECT_EQ(r.resident_size, metadata_bytes_); } + + PerCPUMetadataState post_stats = slab_.MetadataMemoryUsage(); + EXPECT_LE(post_stats.resident_size, metadata_bytes_); + EXPECT_GT(post_stats.resident_size, r.resident_size); } -TEST_P(TcmallocSlabTest, Unit) { +TEST_F(TcmallocSlabTest, Unit) { if (MallocExtension::PerCpuCachesActive()) { // This test unregisters rseq temporarily, as to decrease flakiness. GTEST_SKIP() << "per-CPU TCMalloc is incompatible with unregistering rseq"; @@ -261,8 +196,13 @@ TEST_P(TcmallocSlabTest, Unit) { // Decide if we should expect a push or pop to be the first action on the CPU // slab to trigger initialization. - absl::FixedArray initialized(absl::base_internal::NumCPUs(), - GetParam() != SlabInit::kLazy); + absl::FixedArray initialized(NumCPUs(), false); + + void* objects[kCapacity]; + void* object_ptrs[kCapacity]; + for (int i = 0; i < kCapacity; ++i) { + object_ptrs[i] = &objects[i]; + } for (auto cpu : AllowedCpus()) { SCOPED_TRACE(cpu); @@ -270,146 +210,135 @@ TEST_P(TcmallocSlabTest, Unit) { // Temporarily fake being on the given CPU. ScopedFakeCpuId fake_cpu_id(cpu); -#if !defined(__ppc__) - if (UsingFlatVirtualCpus()) { -#if TCMALLOC_PERCPU_USE_RSEQ - __rseq_abi.vcpu_id = cpu ^ 1; -#endif - cpu = cpu ^ 1; - } -#endif - current_cpu_ = cpu; - - for (size_t cl = 0; cl < kStressSlabs; ++cl) { - SCOPED_TRACE(cl); - current_cl_ = cl; - -#ifdef __ppc__ - // This is imperfect but the window between operations below is small. We - // can make this more precise around individual operations if we see - // measurable flakiness as a result. - if (fake_cpu_id.Tampered()) break; -#endif + for (size_t size_class = 1; size_class < kStressSlabs; ++size_class) { + SCOPED_TRACE(size_class); // Check new slab state. - ASSERT_EQ(slab_.Length(cpu, cl), 0); - ASSERT_EQ(slab_.Capacity(cpu, cl), 0); + ASSERT_EQ(slab_.Length(cpu, size_class), 0); + ASSERT_EQ(slab_.Capacity(cpu, size_class), 0); if (!initialized[cpu]) { -#pragma GCC diagnostic ignored "-Wnonnull" - void* ptr = slab_.Pop(cl, [](int cpu, size_t cl) { - slab_test_->InitCPU(cpu, [](size_t cl) { return kCapacity; }); - - return static_cast(slab_test_); - }); - - ASSERT_TRUE(ptr == slab_test_); + ASSERT_EQ(slab_.Pop(size_class), nullptr); + slab_.InitCpu(cpu, [](size_t size_class) { return kCapacity; }); initialized[cpu] = true; } - // Test overflow/underflow handlers. - ASSERT_EQ(PopExpectUnderflow<5>(&slab_, cl), &objects_[5]); - ASSERT_FALSE(PushExpectOverflow<-1>(&slab_, cl, &objects_[0])); - ASSERT_FALSE(PushExpectOverflow<-2>(&slab_, cl, &objects_[0])); - ASSERT_TRUE(PushExpectOverflow<0>(&slab_, cl, &objects_[0])); + // Test that operations on uncached slab fail. + ASSERT_EQ(slab_.Pop(size_class), nullptr); + EXPECT_FALSE(slab_.Push(size_class, &objects[0])); + EXPECT_FALSE(slab_.Push(size_class, &objects[0])); + EXPECT_FALSE(slab_.Push(size_class, &objects[0])); + const auto max_capacity = [](uint8_t shift) { return kCapacity; }; + ASSERT_EQ(slab_.Grow(cpu, size_class, 1, max_capacity), 0); + { + auto [got_cpu, cached] = slab_.CacheCpuSlab(); + ASSERT_TRUE(cached); + ASSERT_EQ(got_cpu, cpu); + } + { + auto [got_cpu, cached] = slab_.CacheCpuSlab(); + ASSERT_FALSE(cached); + ASSERT_EQ(got_cpu, cpu); + } // Grow capacity to kCapacity / 2. - ASSERT_EQ(slab_.Grow(cpu, cl, kCapacity / 2, kCapacity), kCapacity / 2); - ASSERT_EQ(slab_.Length(cpu, cl), 0); - ASSERT_EQ(slab_.Capacity(cpu, cl), kCapacity / 2); - ASSERT_EQ(PopExpectUnderflow<5>(&slab_, cl), &objects_[5]); - ASSERT_TRUE(slab_.Push(cl, &objects_[0], ExpectNoOverflow)); - ASSERT_EQ(slab_.Length(cpu, cl), 1); - ASSERT_EQ(slab_.Capacity(cpu, cl), kCapacity / 2); - ASSERT_EQ(slab_.Pop(cl, ExpectNoUnderflow), &objects_[0]); - ASSERT_EQ(slab_.Length(cpu, cl), 0); + ASSERT_EQ(slab_.Grow(cpu, size_class, kCapacity / 2, max_capacity), + kCapacity / 2); + ASSERT_EQ(slab_.Length(cpu, size_class), 0); + ASSERT_EQ(slab_.Capacity(cpu, size_class), kCapacity / 2); + ASSERT_EQ(slab_.Pop(size_class), nullptr); + ASSERT_TRUE(slab_.Push(size_class, &objects[0])); + + ASSERT_EQ(slab_.Length(cpu, size_class), 1); + ASSERT_EQ(slab_.Capacity(cpu, size_class), kCapacity / 2); + ASSERT_EQ(slab_.Pop(size_class), &objects[0]); + ASSERT_EQ(slab_.Length(cpu, size_class), 0); for (size_t i = 0; i < kCapacity / 2; ++i) { - ASSERT_TRUE(slab_.Push(cl, &objects_[i], ExpectNoOverflow)); - ASSERT_EQ(slab_.Length(cpu, cl), i + 1); + ASSERT_TRUE(slab_.Push(size_class, &objects[i])); + ASSERT_EQ(slab_.Length(cpu, size_class), i + 1); } - ASSERT_FALSE(PushExpectOverflow<-1>(&slab_, cl, &objects_[0])); + EXPECT_FALSE(slab_.Push(size_class, &objects[0])); for (size_t i = kCapacity / 2; i > 0; --i) { - ASSERT_EQ(slab_.Pop(cl, ExpectNoUnderflow), &objects_[i - 1]); - ASSERT_EQ(slab_.Length(cpu, cl), i - 1); + ASSERT_EQ(slab_.Pop(size_class), &objects[i - 1]); + ASSERT_EQ(slab_.Length(cpu, size_class), i - 1); } - // Ensure that Shink don't underflow capacity. - ASSERT_EQ(slab_.Shrink(cpu, cl, kCapacity), kCapacity / 2); - ASSERT_EQ(slab_.Capacity(cpu, cl), 0); - - // Grow capacity to kCapacity. - ASSERT_EQ(slab_.Grow(cpu, cl, kCapacity / 2, kCapacity), kCapacity / 2); - // Ensure that grow don't overflow max capacity. - ASSERT_EQ(slab_.Grow(cpu, cl, kCapacity, kCapacity), kCapacity / 2); - ASSERT_EQ(slab_.Capacity(cpu, cl), kCapacity); + + // Grow capacity to kCapacity and ensure that grow don't overflow max + // capacity. + ASSERT_EQ(slab_.Grow(cpu, size_class, kCapacity, max_capacity), + kCapacity / 2); + ASSERT_EQ(slab_.Capacity(cpu, size_class), kCapacity); for (size_t i = 0; i < kCapacity; ++i) { - ASSERT_TRUE(slab_.Push(cl, &objects_[i], ExpectNoOverflow)); - ASSERT_EQ(slab_.Length(cpu, cl), i + 1); + ASSERT_TRUE(slab_.Push(size_class, &objects[i])); + ASSERT_EQ(slab_.Length(cpu, size_class), i + 1); } - ASSERT_FALSE(PushExpectOverflow<-1>(&slab_, cl, &objects_[0])); + EXPECT_FALSE(slab_.Push(size_class, &objects[0])); for (size_t i = kCapacity; i > 0; --i) { - ASSERT_EQ(slab_.Pop(cl, ExpectNoUnderflow), &objects_[i - 1]); - ASSERT_EQ(slab_.Length(cpu, cl), i - 1); + ASSERT_EQ(slab_.Pop(size_class), &objects[i - 1]); + ASSERT_EQ(slab_.Length(cpu, size_class), i - 1); } - // Ensure that we can't shrink below length. - ASSERT_TRUE(slab_.Push(cl, &objects_[0], ExpectNoOverflow)); - ASSERT_TRUE(slab_.Push(cl, &objects_[1], ExpectNoOverflow)); - ASSERT_EQ(slab_.Shrink(cpu, cl, kCapacity), kCapacity - 2); - ASSERT_EQ(slab_.Capacity(cpu, cl), 2); - // Test Drain. - ASSERT_EQ(slab_.Grow(cpu, cl, 2, kCapacity), 2); - slab_.Drain(cpu, &cl, - [](void* ctx, size_t cl, void** batch, size_t n, size_t cap) { - size_t mycl = *static_cast(ctx); - if (cl == mycl) { - ASSERT_EQ(n, 2); - ASSERT_EQ(cap, 4); - ASSERT_EQ(batch[0], &objects_[0]); - ASSERT_EQ(batch[1], &objects_[1]); - } else { - ASSERT_EQ(n, 0); - ASSERT_EQ(cap, 0); - } - }); - ASSERT_EQ(slab_.Length(cpu, cl), 0); - ASSERT_EQ(slab_.Capacity(cpu, cl), 0); + ASSERT_TRUE(slab_.Push(size_class, &objects[0])); + ASSERT_TRUE(slab_.Push(size_class, &objects[1])); + + slab_.Drain(cpu, [size_class, cpu, &objects]( + int cpu_arg, size_t size_class_arg, void** batch, + size_t size, size_t cap) { + ASSERT_EQ(cpu, cpu_arg); + if (size_class == size_class_arg) { + ASSERT_EQ(size, 2); + ASSERT_EQ(cap, 10); + ASSERT_EQ(batch[0], &objects[0]); + ASSERT_EQ(batch[1], &objects[1]); + } else { + ASSERT_EQ(size, 0); + ASSERT_EQ(cap, 0); + } + }); + ASSERT_EQ(slab_.Length(cpu, size_class), 0); + ASSERT_EQ(slab_.Capacity(cpu, size_class), 0); // Test PushBatch/PopBatch. void* batch[kCapacity + 1]; for (size_t i = 0; i < kCapacity; ++i) { - batch[i] = &objects_[i]; + batch[i] = &objects[i]; } - ASSERT_EQ(slab_.PopBatch(cl, batch, kCapacity), 0); - ASSERT_EQ(slab_.PushBatch(cl, batch, kCapacity), 0); - ASSERT_EQ(slab_.Grow(cpu, cl, kCapacity / 2, kCapacity), kCapacity / 2); - ASSERT_EQ(slab_.PopBatch(cl, batch, kCapacity), 0); + void* slabs_result[kCapacity + 1]; + ASSERT_EQ(slab_.PopBatch(size_class, batch, kCapacity), 0); + ASSERT_EQ(slab_.PushBatch(size_class, batch, kCapacity), 0); + ASSERT_EQ(slab_.Grow(cpu, size_class, kCapacity / 2, max_capacity), + kCapacity / 2); + ASSERT_EQ(slab_.PopBatch(size_class, batch, kCapacity), 0); // Push a batch of size i into empty slab. for (size_t i = 1; i < kCapacity; ++i) { const size_t expect = std::min(i, kCapacity / 2); - ASSERT_EQ(slab_.PushBatch(cl, batch, i), expect); - ASSERT_EQ(slab_.Length(cpu, cl), expect); + ASSERT_EQ(slab_.PushBatch(size_class, batch, i), expect); + ASSERT_EQ(slab_.Length(cpu, size_class), expect); for (size_t j = 0; j < expect; ++j) { - ASSERT_EQ(slab_.Pop(cl, ExpectNoUnderflow), - &objects_[j + (i - expect)]); + slabs_result[j] = slab_.Pop(size_class); } - ASSERT_EQ(PopExpectUnderflow<5>(&slab_, cl), &objects_[5]); + ASSERT_THAT( + std::vector(&slabs_result[0], &slabs_result[expect]), + UnorderedElementsAreArray(&object_ptrs[i - expect], expect)); + ASSERT_EQ(slab_.Pop(size_class), nullptr); } // Push a batch of size i into non-empty slab. for (size_t i = 1; i < kCapacity / 2; ++i) { const size_t expect = std::min(i, kCapacity / 2 - i); - ASSERT_EQ(slab_.PushBatch(cl, batch, i), i); - ASSERT_EQ(slab_.PushBatch(cl, batch, i), expect); - ASSERT_EQ(slab_.Length(cpu, cl), i + expect); - for (size_t j = 0; j < expect; ++j) { - ASSERT_EQ(slab_.Pop(cl, ExpectNoUnderflow), - static_cast(&objects_[j + (i - expect)])); - } - for (size_t j = 0; j < i; ++j) { - ASSERT_EQ(slab_.Pop(cl, ExpectNoUnderflow), - static_cast(&objects_[j])); + ASSERT_EQ(slab_.PushBatch(size_class, batch, i), i); + ASSERT_EQ(slab_.PushBatch(size_class, batch, i), expect); + ASSERT_EQ(slab_.Length(cpu, size_class), i + expect); + // Because slabs are LIFO fill in this array from the end. + for (int j = i + expect - 1; j >= 0; --j) { + slabs_result[j] = slab_.Pop(size_class); } - ASSERT_EQ(PopExpectUnderflow<5>(&slab_, cl), &objects_[5]); + ASSERT_THAT(std::vector(&slabs_result[0], &slabs_result[i]), + UnorderedElementsAreArray(&object_ptrs[0], i)); + ASSERT_THAT( + std::vector(&slabs_result[i], &slabs_result[i + expect]), + UnorderedElementsAreArray(&object_ptrs[i - expect], expect)); + ASSERT_EQ(slab_.Pop(size_class), nullptr); } for (size_t i = 0; i < kCapacity + 1; ++i) { batch[i] = nullptr; @@ -417,14 +346,14 @@ TEST_P(TcmallocSlabTest, Unit) { // Pop all elements in a single batch. for (size_t i = 1; i < kCapacity / 2; ++i) { for (size_t j = 0; j < i; ++j) { - ASSERT_TRUE(slab_.Push(cl, &objects_[j], ExpectNoOverflow)); + ASSERT_TRUE(slab_.Push(size_class, &objects[j])); } - ASSERT_EQ(slab_.PopBatch(cl, batch, i), i); - ASSERT_EQ(slab_.Length(cpu, cl), 0); - ASSERT_EQ(PopExpectUnderflow<5>(&slab_, cl), &objects_[5]); + ASSERT_EQ(slab_.PopBatch(size_class, batch, i), i); + ASSERT_EQ(slab_.Length(cpu, size_class), 0); + ASSERT_EQ(slab_.Pop(size_class), nullptr); ASSERT_THAT(absl::MakeSpan(&batch[0], i), - UnorderedElementsAreArray(&object_ptrs_[0], i)); + UnorderedElementsAreArray(&object_ptrs[0], i)); ASSERT_THAT(absl::MakeSpan(&batch[i], kCapacity - i), Each(nullptr)); for (size_t j = 0; j < kCapacity + 1; ++j) { batch[j] = nullptr; @@ -433,22 +362,21 @@ TEST_P(TcmallocSlabTest, Unit) { // Pop half of elements in a single batch. for (size_t i = 1; i < kCapacity / 2; ++i) { for (size_t j = 0; j < i; ++j) { - ASSERT_TRUE(slab_.Push(cl, &objects_[j], ExpectNoOverflow)); + ASSERT_TRUE(slab_.Push(size_class, &objects[j])); } size_t want = std::max(1, i / 2); - ASSERT_EQ(slab_.PopBatch(cl, batch, want), want); - ASSERT_EQ(slab_.Length(cpu, cl), i - want); + ASSERT_EQ(slab_.PopBatch(size_class, batch, want), want); + ASSERT_EQ(slab_.Length(cpu, size_class), i - want); for (size_t j = 0; j < i - want; ++j) { - ASSERT_EQ(slab_.Pop(cl, ExpectNoUnderflow), - static_cast(&objects_[i - want - j - 1])); + ASSERT_EQ(slab_.Pop(size_class), &objects[i - want - j - 1]); } - ASSERT_EQ(PopExpectUnderflow<5>(&slab_, cl), &objects_[5]); + ASSERT_EQ(slab_.Pop(size_class), nullptr); ASSERT_GE(i, want); ASSERT_THAT(absl::MakeSpan(&batch[0], want), - UnorderedElementsAreArray(&object_ptrs_[i - want], want)); + UnorderedElementsAreArray(&object_ptrs[i - want], want)); ASSERT_THAT(absl::MakeSpan(&batch[want], kCapacity - want), Each(nullptr)); for (size_t j = 0; j < kCapacity + 1; ++j) { @@ -458,242 +386,697 @@ TEST_P(TcmallocSlabTest, Unit) { // Pop 2x elements in a single batch. for (size_t i = 1; i < kCapacity / 2; ++i) { for (size_t j = 0; j < i; ++j) { - ASSERT_TRUE(slab_.Push(cl, &objects_[j], ExpectNoOverflow)); + ASSERT_TRUE(slab_.Push(size_class, &objects[j])); } - ASSERT_EQ(slab_.PopBatch(cl, batch, i * 2), i); - ASSERT_EQ(slab_.Length(cpu, cl), 0); - ASSERT_EQ(PopExpectUnderflow<5>(&slab_, cl), &objects_[5]); + ASSERT_EQ(slab_.PopBatch(size_class, batch, i * 2), i); + ASSERT_EQ(slab_.Length(cpu, size_class), 0); + ASSERT_EQ(slab_.Pop(size_class), nullptr); ASSERT_THAT(absl::MakeSpan(&batch[0], i), - UnorderedElementsAreArray(&object_ptrs_[0], i)); + UnorderedElementsAreArray(&object_ptrs[0], i)); ASSERT_THAT(absl::MakeSpan(&batch[i], kCapacity - i), Each(nullptr)); for (size_t j = 0; j < kCapacity + 1; ++j) { batch[j] = nullptr; } } - ASSERT_EQ(slab_.Shrink(cpu, cl, kCapacity / 2), kCapacity / 2); + + slab_.Drain(cpu, + [size_class, cpu](int cpu_arg, size_t size_class_arg, + void** batch, size_t size, size_t cap) { + ASSERT_EQ(cpu, cpu_arg); + if (size_class == size_class_arg) { + ASSERT_EQ(size, 0); + ASSERT_EQ(cap, 5); + } else { + ASSERT_EQ(size, 0); + ASSERT_EQ(cap, 0); + } + }); + ASSERT_EQ(slab_.Length(cpu, size_class), 0); + ASSERT_EQ(slab_.Capacity(cpu, size_class), 0); + slab_.UncacheCpuSlab(); } } } -INSTANTIATE_TEST_SUITE_P(Instant, TcmallocSlabTest, - testing::Values(SlabInit::kEager, SlabInit::kLazy)); +void* allocator(size_t bytes, std::align_val_t alignment) { + void* ptr = ::operator new(bytes, alignment); + memset(ptr, 0, bytes); + return ptr; +} -static void StressThread(size_t thread_id, TcmallocSlab* slab, - std::vector* block, - std::vector* mutexes, - std::atomic* capacity, - std::atomic* stop) { - EXPECT_TRUE(IsFast()); +TEST_F(TcmallocSlabTest, ResizeMaxCapacities) { + if (MallocExtension::PerCpuCachesActive()) { + // This test unregisters rseq temporarily, as to decrease flakiness. + GTEST_SKIP() << "per-CPU TCMalloc is incompatible with unregistering rseq"; + } - struct Handler { - static int Overflow(int cpu, size_t cl, void* item) { - EXPECT_GE(cpu, 0); - EXPECT_LT(cpu, absl::base_internal::NumCPUs()); - EXPECT_LT(cl, kStressSlabs); - EXPECT_NE(item, nullptr); - return -1; - } + if (!IsFast()) { + GTEST_SKIP() << "Need fast percpu. Skipping."; + return; + } + constexpr int kCpu = 1; + constexpr int kSizeClassToGrow = 1; + constexpr int kSizeClassToShrink = 2; + ASSERT_LT(kSizeClassToShrink, kStressSlabs); + ASSERT_LT(kSizeClassToGrow, kStressSlabs); + + ScopedFakeCpuId fake_cpu_id(kCpu); + slab_.InitCpu(kCpu, [](size_t size_class) { return kCapacity; }); + { + auto [got_cpu, cached] = slab_.CacheCpuSlab(); + ASSERT_TRUE(cached); + ASSERT_EQ(got_cpu, kCpu); + } - static void* Underflow(int cpu, size_t cl) { - EXPECT_GE(cpu, 0); - EXPECT_LT(cpu, absl::base_internal::NumCPUs()); - EXPECT_LT(cl, kStressSlabs); - return nullptr; - } + size_t max_capacity[kStressSlabs] = {0}; + max_capacity[kSizeClassToShrink] = kCapacity; + max_capacity[kSizeClassToGrow] = kCapacity; + + // Make sure that the slab may grow the available maximum capacity. + EXPECT_EQ(slab_.Grow(kCpu, kSizeClassToGrow, max_capacity[kSizeClassToGrow], + [&](uint8_t) { return max_capacity[kSizeClassToGrow]; }), + max_capacity[kSizeClassToGrow]); + EXPECT_EQ( + slab_.Grow(kCpu, kSizeClassToShrink, max_capacity[kSizeClassToShrink], + [&](uint8_t) { return max_capacity[kSizeClassToShrink]; }), + max_capacity[kSizeClassToShrink]); + + for (int i = 0; i < kCapacity; ++i) { + PerSizeClassMaxCapacity new_max_capacity[2]; + new_max_capacity[0] = PerSizeClassMaxCapacity{ + .size_class = kSizeClassToGrow, + .max_capacity = max_capacity[kSizeClassToGrow] + 1}; + new_max_capacity[1] = PerSizeClassMaxCapacity{ + .size_class = kSizeClassToShrink, + .max_capacity = max_capacity[kSizeClassToShrink] - 1}; + void* slabs = AllocSlabs(allocator, kShift); + const auto [old_slabs, old_slabs_size] = slab_.UpdateMaxCapacities( + slabs, [&](size_t size_class) { return max_capacity[size_class]; }, + [&](int size, uint16_t cap) { max_capacity[size] = cap; }, + [](int cpu) { return cpu == kCpu; }, + [&](int cpu, size_t size_class, void** batch, size_t size, size_t cap) { + EXPECT_EQ(size, 0); + }, + new_max_capacity, + /*classes_to_resize=*/2); + ASSERT_NE(old_slabs, nullptr); + mprotect(old_slabs, old_slabs_size, PROT_READ | PROT_WRITE); + sized_aligned_delete(old_slabs, old_slabs_size, + std::align_val_t{EXEC_PAGESIZE}); + + // Make sure that the capacity is zero as UpdateMaxCapacity should + // initialize slabs. + EXPECT_EQ(slab_.Capacity(kCpu, kSizeClassToGrow), 0); + EXPECT_EQ(slab_.Capacity(kCpu, kSizeClassToShrink), 0); + + // Make sure that the slab may grow the available maximum capacity. + EXPECT_EQ( + slab_.Grow(kCpu, kSizeClassToGrow, max_capacity[kSizeClassToGrow], + [&](uint8_t) { return max_capacity[kSizeClassToGrow]; }), + max_capacity[kSizeClassToGrow]); + EXPECT_EQ( + slab_.Grow(kCpu, kSizeClassToShrink, max_capacity[kSizeClassToShrink], + [&](uint8_t) { return max_capacity[kSizeClassToShrink]; }), + max_capacity[kSizeClassToShrink]); + } + + EXPECT_EQ(max_capacity[kSizeClassToShrink], 0); + EXPECT_EQ(max_capacity[kSizeClassToGrow], 2 * kCapacity); +} + +TEST_F(TcmallocSlabTest, ShrinkEmptyCache) { + if (MallocExtension::PerCpuCachesActive()) { + // This test unregisters rseq temporarily, as to decrease flakiness. + GTEST_SKIP() << "per-CPU TCMalloc is incompatible with unregistering rseq"; + } + + if (!IsFast()) { + GTEST_SKIP() << "Need fast percpu. Skipping."; + return; + } + constexpr int kCpu = 1; + constexpr int kSizeClass = 1; + slab_.InitCpu(kCpu, [](size_t size_class) { return kCapacity; }); + slab_.StopCpu(kCpu); + EXPECT_EQ( + slab_.ShrinkOtherCache(kCpu, kSizeClass, /*len=*/1, + [](size_t size_class, void** batch, size_t n) { + EXPECT_LT(size_class, kStressSlabs); + EXPECT_LE(n, kStressCapacity); + EXPECT_GT(n, 0); + for (size_t i = 0; i < n; ++i) { + EXPECT_NE(batch[i], nullptr); + } + }), + 0); + slab_.StartCpu(kCpu); +} + +TEST_F(TcmallocSlabTest, SimulatedMadviseFailure) { + if (!IsFast()) { + GTEST_SKIP() << "Need fast percpu. Skipping."; + return; + } + + // Initialize a core. + slab_.InitCpu(0, [](size_t size_class) { return kCapacity; }); + + auto trigger_resize = [&](size_t shift) { + // We are deliberately simulating madvise failing, so ignore the return + // value. + auto alloc = [&](size_t size, std::align_val_t alignment) { + return ByteCountingMalloc(size, alignment); + }; + void* slabs = AllocSlabs(alloc, shift); + (void)slab_.ResizeSlabs( + subtle::percpu::ToShiftType(shift), slabs, + [](size_t) { return kCapacity / 2; }, [](int cpu) { return cpu == 0; }, + [&](int cpu, size_t size_class, void** batch, size_t size, size_t cap) { + EXPECT_EQ(size, 0); + EXPECT_EQ(cap, 0); + }); }; + // We need to switch from one size (kShift) to another (kShift - 1) and back. + trigger_resize(kShift - 1); + trigger_resize(kShift); +} + +struct Context { + TcmallocSlab* slab; + std::vector>* blocks; + absl::Span mutexes; + std::atomic* capacity; + std::atomic* stop; + absl::Span init; + absl::Span> has_init; + std::atomic* max_capacity; + + GetMaxCapacity GetMaxCapacityFunctor() const { return {max_capacity}; } +}; + +void InitCpuOnce(Context& ctx, int cpu) { + if (cpu < 0) { + cpu = ctx.slab->CacheCpuSlab().first; + if (cpu < 0) { + return; + } + } + absl::base_internal::LowLevelCallOnce(&ctx.init[cpu], [&]() { + absl::MutexLock lock(&ctx.mutexes[cpu]); + ctx.slab->InitCpu(cpu, ctx.GetMaxCapacityFunctor()); + ctx.has_init[cpu].store(true, std::memory_order_relaxed); + }); +} + +int GetResizedMaxCapacities(Context& ctx, + PerSizeClassMaxCapacity* new_max_capacity) { + std::atomic* max_capacity = ctx.max_capacity; + absl::BitGen rnd; + size_t to_shrink = absl::Uniform(rnd, 0, kStressSlabs); + size_t to_grow = absl::Uniform(rnd, 0, kStressSlabs); + if (to_shrink == to_grow || max_capacity[to_shrink] == 0 || + max_capacity[to_grow].load(std::memory_order_relaxed) == + kMaxStressCapacity - 1) + return 0; + new_max_capacity[0] = PerSizeClassMaxCapacity{ + .size_class = to_shrink, + .max_capacity = + max_capacity[to_shrink].load(std::memory_order_relaxed) - 1}; + new_max_capacity[1] = PerSizeClassMaxCapacity{ + .size_class = to_grow, + .max_capacity = + max_capacity[to_grow].load(std::memory_order_relaxed) + 1}; + return 2; +} + +// TODO(b/213923453): move to an environment style of test, as in +// FakeTransferCacheEnvironment. +void StressThread(size_t thread_id, + Context& ctx) ABSL_NO_THREAD_SAFETY_ANALYSIS { + EXPECT_TRUE(IsFast()); + + std::vector& block = (*ctx.blocks)[thread_id]; + + const int num_cpus = NumCPUs(); absl::BitGen rnd(absl::SeedSeq({thread_id})); - while (!*stop) { - size_t cl = absl::Uniform(rnd, 0, kStressSlabs); + while (!*ctx.stop) { + size_t size_class = absl::Uniform(rnd, 1, kStressSlabs); const int what = absl::Uniform(rnd, 0, 91); if (what < 10) { - if (!block->empty()) { - if (slab->Push(cl, block->back(), &Handler::Overflow)) { - block->pop_back(); + if (!block.empty()) { + if (ctx.slab->Push(size_class, block.back())) { + block.pop_back(); + } else { + InitCpuOnce(ctx, -1); } } } else if (what < 20) { - if (void* item = slab->Pop(cl, &Handler::Underflow)) { - block->push_back(item); + if (void* item = ctx.slab->Pop(size_class)) { + // Ensure that we never return a null item which could be indicative + // of a bug in lazy InitCpu initialization (b/148973091, b/147974701). + EXPECT_NE(item, nullptr); + block.push_back(item); + } else { + InitCpuOnce(ctx, -1); } } else if (what < 30) { - if (!block->empty()) { + if (!block.empty()) { void* batch[kStressCapacity]; size_t n = absl::Uniform( - rnd, 0, std::min(block->size(), kStressCapacity)) + + rnd, 0, std::min(block.size(), kStressCapacity)) + 1; for (size_t i = 0; i < n; ++i) { - batch[i] = block->back(); - block->pop_back(); + batch[i] = block.back(); + block.pop_back(); } - size_t pushed = slab->PushBatch(cl, batch, n); + size_t pushed = ctx.slab->PushBatch(size_class, batch, n); EXPECT_LE(pushed, n); for (size_t i = 0; i < n - pushed; ++i) { - block->push_back(batch[i]); + block.push_back(batch[i]); } } } else if (what < 40) { void* batch[kStressCapacity]; size_t n = absl::Uniform(rnd, 0, kStressCapacity) + 1; - size_t popped = slab->PopBatch(cl, batch, n); + size_t popped = ctx.slab->PopBatch(size_class, batch, n); EXPECT_LE(popped, n); for (size_t i = 0; i < popped; ++i) { - block->push_back(batch[i]); + block.push_back(batch[i]); } } else if (what < 50) { size_t n = absl::Uniform(rnd, 0, kStressCapacity) + 1; for (;;) { - size_t c = capacity->load(); + size_t c = ctx.capacity->load(); n = std::min(n, c); if (n == 0) { break; } - if (capacity->compare_exchange_weak(c, c - n)) { + if (ctx.capacity->compare_exchange_weak(c, c - n)) { break; } } + size_t res = 0; if (n != 0) { - size_t res = slab->Grow(slab->GetCurrentVirtualCpuUnsafe(), cl, n, - kStressCapacity); - EXPECT_LE(res, n); - capacity->fetch_add(n - res); + const int cpu = ctx.slab->CacheCpuSlab().first; + if (cpu >= 0) { + // Grow mutates the header array and must be operating on + // an initialized core. + InitCpuOnce(ctx, cpu); + + res = ctx.slab->Grow(cpu, size_class, n, [&](uint8_t shift) { + return ctx.GetMaxCapacityFunctor()(size_class); + }); + EXPECT_LE(res, n); + } + ctx.capacity->fetch_add(n - res); } } else if (what < 60) { - size_t n = - slab->Shrink(slab->GetCurrentVirtualCpuUnsafe(), cl, - absl::Uniform(rnd, 0, kStressCapacity) + 1); - capacity->fetch_add(n); + int cpu = absl::Uniform(rnd, 0, num_cpus); + absl::MutexLock lock(&ctx.mutexes[cpu]); + size_t len = ctx.slab->Length(cpu, size_class); + EXPECT_LE(len, kMaxStressCapacity); + size_t cap = ctx.slab->Capacity(cpu, size_class); + EXPECT_LE(cap, kMaxStressCapacity); + EXPECT_LE(len, cap); } else if (what < 70) { - size_t len = slab->Length( - absl::Uniform(rnd, 0, absl::base_internal::NumCPUs()), cl); - EXPECT_LE(len, kStressCapacity); + int cpu = absl::Uniform(rnd, 0, num_cpus); + + // ShrinkOtherCache mutates the header array and must be operating on an + // initialized core. + InitCpuOnce(ctx, cpu); + + absl::MutexLock lock(&ctx.mutexes[cpu]); + size_t to_shrink = absl::Uniform(rnd, 0, kStressCapacity) + 1; + ctx.slab->StopCpu(cpu); + size_t total_shrunk = ctx.slab->ShrinkOtherCache( + cpu, size_class, to_shrink, + [&block](size_t size_class, void** batch, size_t n) { + EXPECT_LT(size_class, kStressSlabs); + EXPECT_LE(n, kStressCapacity); + EXPECT_GT(n, 0); + for (size_t i = 0; i < n; ++i) { + EXPECT_NE(batch[i], nullptr); + block.push_back(batch[i]); + } + }); + ctx.slab->StartCpu(cpu); + EXPECT_LE(total_shrunk, to_shrink); + EXPECT_LE(0, total_shrunk); + ctx.capacity->fetch_add(total_shrunk); } else if (what < 80) { - size_t cap = slab->Capacity( - absl::Uniform(rnd, 0, absl::base_internal::NumCPUs()), cl); - EXPECT_LE(cap, kStressCapacity); - } else if (what < 90) { - struct Context { - std::vector* block; - std::atomic* capacity; - }; - Context ctx = {block, capacity}; - int cpu = absl::Uniform(rnd, 0, absl::base_internal::NumCPUs()); - if (mutexes->at(cpu).TryLock()) { - size_t to_shrink = absl::Uniform(rnd, 0, kStressCapacity) + 1; - size_t total_shrunk = slab->ShrinkOtherCache( - cpu, cl, to_shrink, &ctx, - [](void* arg, size_t cl, void** batch, size_t n) { - Context* ctx = static_cast(arg); - EXPECT_LT(cl, kStressSlabs); - EXPECT_LE(n, kStressCapacity); - for (size_t i = 0; i < n; ++i) { - EXPECT_NE(batch[i], nullptr); - ctx->block->push_back(batch[i]); - } - }); - EXPECT_LE(total_shrunk, to_shrink); - EXPECT_LE(0, total_shrunk); - capacity->fetch_add(total_shrunk); - mutexes->at(cpu).Unlock(); + size_t to_grow = absl::Uniform(rnd, 0, kStressCapacity) + 1; + for (;;) { + size_t c = ctx.capacity->load(); + to_grow = std::min(to_grow, c); + if (to_grow == 0) { + break; + } + if (ctx.capacity->compare_exchange_weak(c, c - to_grow)) { + break; + } + } + if (to_grow != 0) { + int cpu = absl::Uniform(rnd, 0, num_cpus); + + // GrowOtherCache mutates the header array and must be operating on an + // initialized core. + InitCpuOnce(ctx, cpu); + + absl::MutexLock lock(&ctx.mutexes[cpu]); + ctx.slab->StopCpu(cpu); + size_t grown = ctx.slab->GrowOtherCache( + cpu, size_class, to_grow, + [&](uint8_t) { return ctx.GetMaxCapacityFunctor()(size_class); }); + ctx.slab->StartCpu(cpu); + EXPECT_LE(grown, to_grow); + EXPECT_GE(grown, 0); + ctx.capacity->fetch_add(to_grow - grown); } } else { - struct Context { - std::vector* block; - std::atomic* capacity; - }; - Context ctx = {block, capacity}; - int cpu = absl::Uniform(rnd, 0, absl::base_internal::NumCPUs()); - if (mutexes->at(cpu).TryLock()) { - slab->Drain( - cpu, &ctx, - [](void* arg, size_t cl, void** batch, size_t n, size_t cap) { - Context* ctx = static_cast(arg); - EXPECT_LT(cl, kStressSlabs); - EXPECT_LE(n, kStressCapacity); - EXPECT_LE(cap, kStressCapacity); - for (size_t i = 0; i < n; ++i) { + int cpu = absl::Uniform(rnd, 0, num_cpus); + // Flip coin on whether to unregister rseq on this thread. + const bool unregister = absl::Bernoulli(rnd, 0.5); + + // Drain mutates the header array and must be operating on an initialized + // core. + InitCpuOnce(ctx, cpu); + + { + absl::MutexLock lock(&ctx.mutexes[cpu]); + std::optional scoped_rseq; + if (unregister) { + scoped_rseq.emplace(); + TC_ASSERT(!IsFastNoInit()); + } + + ctx.slab->Drain( + cpu, [&block, &ctx, cpu](int cpu_arg, size_t size_class, + void** batch, size_t size, size_t cap) { + EXPECT_EQ(cpu, cpu_arg); + EXPECT_LT(size_class, kStressSlabs); + EXPECT_LE(size, kMaxStressCapacity); + EXPECT_LE(cap, kMaxStressCapacity); + for (size_t i = 0; i < size; ++i) { EXPECT_NE(batch[i], nullptr); - ctx->block->push_back(batch[i]); + block.push_back(batch[i]); } - ctx->capacity->fetch_add(cap); + ctx.capacity->fetch_add(cap); }); - mutexes->at(cpu).Unlock(); } + + // Verify we re-registered with rseq as required. + TC_ASSERT(IsFastNoInit()); } } } -static void* allocator(size_t bytes) { - void* ptr = malloc(bytes); - if (ptr) { - memset(ptr, 0, bytes); +void ResizeMaxCapacitiesThread( + Context& ctx, TcmallocSlab::DrainHandler drain_handler, + absl::Span> old_slabs_span) + ABSL_NO_THREAD_SAFETY_ANALYSIS { + absl::BitGen rnd; + const size_t num_cpus = NumCPUs(); + + while (!*ctx.stop) { + for (size_t cpu = 0; cpu < num_cpus; ++cpu) ctx.mutexes[cpu].Lock(); + PerSizeClassMaxCapacity new_max_capacity[2]; + int to_resize = GetResizedMaxCapacities(ctx, new_max_capacity); + size_t old_slabs_idx = 0; + + uint8_t shift = ctx.slab->GetShift(); + void* slabs = AllocSlabs(allocator, shift); + const auto [old_slabs, old_slabs_size] = ctx.slab->UpdateMaxCapacities( + slabs, ctx.GetMaxCapacityFunctor(), + [&](int size, uint16_t cap) { + ctx.max_capacity[size].store(cap, std::memory_order_relaxed); + }, + [&](size_t cpu) { + return ctx.has_init[cpu].load(std::memory_order_relaxed); + }, + drain_handler, new_max_capacity, to_resize); + for (size_t cpu = 0; cpu < num_cpus; ++cpu) ctx.mutexes[cpu].Unlock(); + ASSERT_NE(old_slabs, nullptr); + // We sometimes don't madvise away the old slabs in order to simulate + // madvise failing. + const bool simulate_madvise_failure = absl::Bernoulli(rnd, 0.1); + if (!simulate_madvise_failure) { + // Verify that we do not write to an old slab, as this may indicate a bug. + mprotect(old_slabs, old_slabs_size, PROT_READ); + // It's important that we do this here in order to uncover any potential + // correctness issues due to madvising away the old slabs. + // TODO(b/214241843): we should be able to just do one MADV_DONTNEED once + // the kernel enables huge zero pages. + madvise(old_slabs, old_slabs_size, MADV_NOHUGEPAGE); + madvise(old_slabs, old_slabs_size, MADV_DONTNEED); + + // Verify that old_slabs is now non-resident. + const int fd = signal_safe_open("/proc/self/pageflags", O_RDONLY); + if (fd < 0) continue; + + // /proc/self/pageflags is an array. Each entry is a bitvector of size 64. + // To index the array, divide the virtual address by the pagesize. The + // 64b word has bit fields set. + const uintptr_t start_addr = reinterpret_cast(old_slabs); + constexpr size_t kPhysicalPageSize = EXEC_PAGESIZE; + for (uintptr_t addr = start_addr; addr < start_addr + old_slabs_size; + addr += kPhysicalPageSize) { + ASSERT_EQ(addr % kPhysicalPageSize, 0); + // Offset in /proc/self/pageflags. + const off64_t offset = addr / kPhysicalPageSize * 8; + uint64_t entry = 0; + // Ignore false-positive warning in GCC. +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattribute-warning" +#endif + const int64_t bytes_read = pread(fd, &entry, sizeof(entry), offset); +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + ASSERT_EQ(bytes_read, sizeof(entry)); + constexpr uint64_t kExpectedBits = + (uint64_t{1} << KPF_ZERO_PAGE) | (uint64_t{1} << KPF_NOPAGE); + ASSERT_NE(entry & kExpectedBits, 0) + << entry << " " << addr << " " << start_addr; + } + signal_safe_close(fd); + } + + // Delete the old slab from 100 iterations ago. + if (old_slabs_span[old_slabs_idx].first != nullptr) { + auto [old_slabs, old_slabs_size] = old_slabs_span[old_slabs_idx]; + + mprotect(old_slabs, old_slabs_size, PROT_READ | PROT_WRITE); + sized_aligned_delete(old_slabs, old_slabs_size, + std::align_val_t{EXEC_PAGESIZE}); + } + old_slabs_span[old_slabs_idx] = {old_slabs, old_slabs_size}; + if (++old_slabs_idx == old_slabs_span.size()) old_slabs_idx = 0; + } +} + +constexpr size_t kResizeInitialShift = 14; +constexpr size_t kResizeMaxShift = 18; + +void ResizeSlabsThread(Context& ctx, TcmallocSlab::DrainHandler drain_handler, + absl::Span> old_slabs_span) + ABSL_NO_THREAD_SAFETY_ANALYSIS { + absl::BitGen rnd; + const size_t num_cpus = NumCPUs(); + size_t shift = kResizeInitialShift; + size_t old_slabs_idx = 0; + for (int i = 0; i < 10; ++i) { + if (shift == kResizeInitialShift) { + ++shift; + } else if (shift == kResizeMaxShift) { + --shift; + } else { + const bool grow = absl::Bernoulli(rnd, 0.5); + if (grow) { + ++shift; + } else { + --shift; + } + } + for (size_t cpu = 0; cpu < num_cpus; ++cpu) ctx.mutexes[cpu].Lock(); + void* slabs = AllocSlabs(allocator, shift); + const auto [old_slabs, old_slabs_size] = ctx.slab->ResizeSlabs( + ToShiftType(shift), slabs, ctx.GetMaxCapacityFunctor(), + [&](size_t cpu) { + return ctx.has_init[cpu].load(std::memory_order_relaxed); + }, + drain_handler); + for (size_t cpu = 0; cpu < num_cpus; ++cpu) ctx.mutexes[cpu].Unlock(); + ASSERT_NE(old_slabs, nullptr); + // We sometimes don't madvise away the old slabs in order to simulate + // madvise failing. + const bool simulate_madvise_failure = absl::Bernoulli(rnd, 0.1); + if (!simulate_madvise_failure) { + // Verify that we do not write to an old slab, as this may indicate a bug. + mprotect(old_slabs, old_slabs_size, PROT_READ); + // It's important that we do this here in order to uncover any potential + // correctness issues due to madvising away the old slabs. + // TODO(b/214241843): we should be able to just do one MADV_DONTNEED once + // the kernel enables huge zero pages. + madvise(old_slabs, old_slabs_size, MADV_NOHUGEPAGE); + madvise(old_slabs, old_slabs_size, MADV_DONTNEED); + + // Verify that old_slabs is now non-resident. + const int fd = signal_safe_open("/proc/self/pageflags", O_RDONLY); + if (fd < 0) continue; + + // /proc/self/pageflags is an array. Each entry is a bitvector of size 64. + // To index the array, divide the virtual address by the pagesize. The + // 64b word has bit fields set. + const uintptr_t start_addr = reinterpret_cast(old_slabs); + constexpr size_t kPhysicalPageSize = EXEC_PAGESIZE; + for (uintptr_t addr = start_addr; addr < start_addr + old_slabs_size; + addr += kPhysicalPageSize) { + ASSERT_EQ(addr % kPhysicalPageSize, 0); + // Offset in /proc/self/pageflags. + const off64_t offset = addr / kPhysicalPageSize * 8; + uint64_t entry = 0; +// Ignore false-positive warning in GCC. +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattribute-warning" +#endif + const int64_t bytes_read = pread(fd, &entry, sizeof(entry), offset); +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + ASSERT_EQ(bytes_read, sizeof(entry)); + constexpr uint64_t kExpectedBits = + (uint64_t{1} << KPF_ZERO_PAGE) | (uint64_t{1} << KPF_NOPAGE); + ASSERT_NE(entry & kExpectedBits, 0) + << entry << " " << addr << " " << start_addr; + } + signal_safe_close(fd); + } + + // Delete the old slab from 100 iterations ago. + if (old_slabs_span[old_slabs_idx].first != nullptr) { + auto [old_slabs, old_slabs_size] = old_slabs_span[old_slabs_idx]; + + mprotect(old_slabs, old_slabs_size, PROT_READ | PROT_WRITE); + sized_aligned_delete(old_slabs, old_slabs_size, + std::align_val_t{EXEC_PAGESIZE}); + } + old_slabs_span[old_slabs_idx] = {old_slabs, old_slabs_size}; + if (++old_slabs_idx == old_slabs_span.size()) old_slabs_idx = 0; } - return ptr; } -TEST(TcmallocSlab, Stress) { +class StressThreadTest : public testing::TestWithParam> { +}; + +TEST_P(StressThreadTest, Stress) { // The test creates 2 * NumCPUs() threads each executing all possible - // operations on TcmallocSlab. After that we verify that no objects - // lost/duplicated and that total capacity is preserved. + // operations on TcmallocSlab. Depending on the test param, we may grow the + // slabs a few times while stress threads are running. After that we verify + // that no objects lost/duplicated and that total capacity is preserved. if (!IsFast()) { GTEST_SKIP() << "Need fast percpu. Skipping."; return; } - EXPECT_LE(kStressSlabs, kStressSlabs); + const bool resize = std::get<0>(GetParam()); + const bool pin_cpu = std::get<1>(GetParam()); + TcmallocSlab slab; - slab.Init( - allocator, - [](size_t cl) { return cl < kStressSlabs ? kStressCapacity : 0; }, false, - kShift); + size_t shift = resize ? kResizeInitialShift : kShift; std::vector threads; - const int n_threads = 2 * absl::base_internal::NumCPUs(); + const size_t num_cpus = NumCPUs(); + const size_t n_stress_threads = 2 * num_cpus; + const size_t n_threads = n_stress_threads + resize; + std::atomic max_capacity[kStressSlabs]; + + for (size_t size_class = 0; size_class < kStressSlabs; ++size_class) { + max_capacity[size_class].store(kStressCapacity, std::memory_order_relaxed); + } + + // once_flag's protect InitCpu on a CPU. + std::vector init(num_cpus); + // Tracks whether init has occurred on a CPU for use in ResizeSlabs. + std::vector> has_init(num_cpus); // Mutexes protect Drain operation on a CPU. - std::vector mutexes(absl::base_internal::NumCPUs()); + std::vector mutexes(num_cpus); // Give each thread an initial set of local objects. - std::vector> blocks(n_threads); + std::vector> blocks(n_stress_threads); for (size_t i = 0; i < blocks.size(); ++i) { for (size_t j = 0; j < kStressCapacity; ++j) { - blocks[i].push_back(reinterpret_cast(i * kStressCapacity + j + 1)); + blocks[i].push_back(reinterpret_cast( + (i * kStressCapacity + j + 1) * sizeof(void*))); } } std::atomic stop(false); // Total capacity shared between all size classes and all CPUs. - const int kTotalCapacity = blocks.size() * kStressCapacity * 3 / 4; + const size_t kTotalCapacity = blocks.size() * kStressCapacity * 3 / 4; std::atomic capacity(kTotalCapacity); - // Create threads and let them work for 5 seconds. + Context ctx = {&slab, + &blocks, + absl::MakeSpan(mutexes), + &capacity, + &stop, + absl::MakeSpan(init), + absl::MakeSpan(has_init), + &max_capacity[0]}; + InitSlab(slab, allocator, ctx.GetMaxCapacityFunctor(), shift); + // Create threads and let them work for 5 seconds while we may or not also be + // resizing the slab. threads.reserve(n_threads); - for (size_t t = 0; t < n_threads; ++t) { - threads.push_back(std::thread(StressThread, t, &slab, &blocks[t], &mutexes, - &capacity, &stop)); + for (size_t t = 0; t < n_stress_threads; ++t) { + threads.push_back(std::thread(StressThread, t, std::ref(ctx))); + } + // Collect objects and capacity from all slabs in Drain in ResizeSlabs. + absl::flat_hash_set objects; + const auto drain_handler = [&objects, &ctx](int cpu, size_t size_class, + void** batch, size_t size, + size_t cap) { + for (size_t i = 0; i < size; ++i) { + objects.insert(batch[i]); + } + ctx.capacity->fetch_add(cap); + }; + + std::array, 100> max_cap_slabs_array{}; + threads.push_back(std::thread(ResizeMaxCapacitiesThread, std::ref(ctx), + std::ref(drain_handler), + absl::MakeSpan(max_cap_slabs_array))); + + // Keep track of old slabs so we can free the memory. We technically could + // have a sleeping StressThread access any of the old slabs, but it's very + // inefficient to keep all the old slabs around so we just keep 100. + std::array, 100> old_slabs_arr{}; + if (resize) { + threads.push_back(std::thread(ResizeSlabsThread, std::ref(ctx), + std::ref(drain_handler), + absl::MakeSpan(old_slabs_arr))); + } + if (pin_cpu) { + // Regression test for a livelock when a thread keeps running on cpu 0. + absl::SleepFor(absl::Seconds(1)); + CpuSet cpus; + cpus.Zero(); + cpus.Set(0); + (void)cpus.SetAffinity(0); + absl::SleepFor(absl::Seconds(1)); + } else { + absl::SleepFor(absl::Seconds(5)); } - absl::SleepFor(absl::Seconds(5)); stop = true; for (auto& t : threads) { t.join(); } - // Collect objects and capacity from all slabs. - std::set objects; - struct Context { - std::set* objects; - std::atomic* capacity; - }; - Context ctx = {&objects, &capacity}; - for (int cpu = 0; cpu < absl::base_internal::NumCPUs(); ++cpu) { - slab.Drain(cpu, &ctx, - [](void* arg, size_t cl, void** batch, size_t n, size_t cap) { - Context* ctx = static_cast(arg); - for (size_t i = 0; i < n; ++i) { - ctx->objects->insert(batch[i]); - } - ctx->capacity->fetch_add(cap); - }); - for (size_t cl = 0; cl < kStressSlabs; ++cl) { - EXPECT_EQ(slab.Length(cpu, cl), 0); - EXPECT_EQ(slab.Capacity(cpu, cl), 0); + for (int cpu = 0; cpu < num_cpus; ++cpu) { + slab.Drain(cpu, drain_handler); + for (size_t size_class = 1; size_class < kStressSlabs; ++size_class) { + EXPECT_EQ(slab.Length(cpu, size_class), 0); + EXPECT_EQ(slab.Capacity(cpu, size_class), 0); } } for (const auto& b : blocks) { @@ -703,16 +1086,39 @@ TEST(TcmallocSlab, Stress) { } EXPECT_EQ(objects.size(), blocks.size() * kStressCapacity); EXPECT_EQ(capacity.load(), kTotalCapacity); - slab.Destroy(free); + void* deleted_slabs = slab.Destroy(sized_aligned_delete); + + for (const auto& [old_slabs, old_slabs_size] : max_cap_slabs_array) { + if (old_slabs == nullptr || old_slabs == deleted_slabs) continue; + + mprotect(old_slabs, old_slabs_size, PROT_READ | PROT_WRITE); + sized_aligned_delete(old_slabs, old_slabs_size, + std::align_val_t{EXEC_PAGESIZE}); + } + + for (const auto& [old_slabs, old_slabs_size] : old_slabs_arr) { + if (old_slabs == nullptr || old_slabs == deleted_slabs) continue; + + mprotect(old_slabs, old_slabs_size, PROT_READ | PROT_WRITE); + sized_aligned_delete(old_slabs, old_slabs_size, + std::align_val_t{EXEC_PAGESIZE}); + } } +INSTANTIATE_TEST_SUITE_P( + Group, StressThreadTest, testing::Combine(testing::Bool(), testing::Bool()), + [](const testing::TestParamInfo info) { + return std::string(std::get<0>(info.param) ? "" : "No") + "Resize_" + + (std::get<1>(info.param) ? "" : "No") + "Pin"; + }); + TEST(TcmallocSlab, SMP) { // For the other tests here to be meaningful, we need multiple cores. - ASSERT_GT(absl::base_internal::NumCPUs(), 1); + ASSERT_GT(NumCPUs(), 1); } #if ABSL_INTERNAL_HAVE_ELF_SYMBOLIZE -static int FilterElfHeader(struct dl_phdr_info* info, size_t size, void* data) { +int FilterElfHeader(struct dl_phdr_info* info, size_t size, void* data) { *reinterpret_cast(data) = reinterpret_cast(info->dlpi_addr); // No further iteration wanted. @@ -726,6 +1132,10 @@ TEST(TcmallocSlab, CriticalSectionMetadata) { GTEST_SKIP() << "--gc-sections cannot be inhibited on this compiler."; #endif +#if !TCMALLOC_INTERNAL_PERCPU_USE_RSEQ + GTEST_SKIP() << "rseq is not enabled in this build."; +#endif + // We expect that restartable sequence critical sections (rseq_cs) are in the // __rseq_cs section (by convention, not hard requirement). Additionally, for // each entry in that section, there should be a pointer to it in @@ -794,57 +1204,78 @@ TEST(TcmallocSlab, CriticalSectionMetadata) { #endif } -static void BM_PushPop(benchmark::State& state) { - CHECK_CONDITION(IsFast()); - RunOnSingleCpu([&](int this_cpu) { - const int kBatchSize = 32; - TcmallocSlab slab; +void BM_PushPop(benchmark::State& state) { + TC_CHECK(IsFast()); + constexpr int kCpu = 0; + constexpr size_t kSizeClass = 0; + // Fake being on the given CPU. This allows Grow to succeed for + // kCpu/kSizeClass, and then we Push/Pop repeatedly on kCpu/kSizeClass. + // Note that no other thread has access to `slab` so we don't need to worry + // about races. + ScopedFakeCpuId fake_cpu_id(kCpu); + constexpr int kBatchSize = 32; + TcmallocSlab slab; #pragma GCC diagnostic ignored "-Wnonnull" - slab.Init( - allocator, [](size_t cl) -> size_t { return kBatchSize; }, false, - kShift); - - CHECK_CONDITION(slab.Grow(this_cpu, 0, kBatchSize, kBatchSize) == - kBatchSize); - void* batch[kBatchSize]; - for (int i = 0; i < kBatchSize; i++) { - batch[i] = &batch[i]; + const auto get_capacity = [](size_t size_class) -> size_t { + return kBatchSize; + }; + InitSlab(slab, allocator, get_capacity, kShift); + for (int cpu = 0, n = NumCPUs(); cpu < n; ++cpu) { + slab.InitCpu(cpu, get_capacity); + } + auto [cpu, _] = slab.CacheCpuSlab(); + TC_CHECK_EQ(cpu, kCpu); + + TC_CHECK_EQ(slab.Grow(kCpu, kSizeClass, kBatchSize, + [](uint8_t shift) { return kBatchSize; }), + kBatchSize); + void* batch[kBatchSize]; + for (int i = 0; i < kBatchSize; i++) { + batch[i] = &batch[i]; + } + for (auto _ : state) { + for (size_t x = 0; x < kBatchSize; x++) { + TC_CHECK(slab.Push(kSizeClass, batch[x])); } - for (auto _ : state) { - for (size_t x = 0; x < kBatchSize; x++) { - CHECK_CONDITION(slab.Push(0, batch[x], ExpectNoOverflow)); - } - for (size_t x = 0; x < kBatchSize; x++) { - CHECK_CONDITION(slab.Pop(0, ExpectNoUnderflow) == - batch[kBatchSize - x - 1]); - } + for (size_t x = 0; x < kBatchSize; x++) { + TC_CHECK(slab.Pop(kSizeClass) == batch[kBatchSize - x - 1]); } - return true; - }); + } } BENCHMARK(BM_PushPop); -static void BM_PushPopBatch(benchmark::State& state) { - CHECK_CONDITION(IsFast()); - RunOnSingleCpu([&](int this_cpu) { - const int kBatchSize = 32; - TcmallocSlab slab; - slab.Init( - allocator, [](size_t cl) -> size_t { return kBatchSize; }, false, - kShift); - CHECK_CONDITION(slab.Grow(this_cpu, 0, kBatchSize, kBatchSize) == - kBatchSize); - void* batch[kBatchSize]; - for (int i = 0; i < kBatchSize; i++) { - batch[i] = &batch[i]; - } - for (auto _ : state) { - CHECK_CONDITION(slab.PushBatch(0, batch, kBatchSize) == kBatchSize); - CHECK_CONDITION(slab.PopBatch(0, batch, kBatchSize) == kBatchSize); - } - return true; - }); +void BM_PushPopBatch(benchmark::State& state) { + TC_CHECK(IsFast()); + constexpr int kCpu = 0; + constexpr size_t kSizeClass = 0; + // Fake being on the given CPU. This allows Grow to succeed for + // kCpu/kSizeClass, and then we Push/PopBatch repeatedly on kCpu/kSizeClass. + // Note that no other thread has access to `slab` so we don't need to worry + // about races. + ScopedFakeCpuId fake_cpu_id(kCpu); + constexpr int kBatchSize = 32; + TcmallocSlab slab; + const auto get_capacity = [](size_t size_class) -> size_t { + return kBatchSize; + }; + InitSlab(slab, allocator, get_capacity, kShift); + for (int cpu = 0, n = NumCPUs(); cpu < n; ++cpu) { + slab.InitCpu(cpu, get_capacity); + } + auto [cpu, _] = slab.CacheCpuSlab(); + TC_CHECK_EQ(cpu, kCpu); + TC_CHECK_EQ(slab.Grow(kCpu, kSizeClass, kBatchSize, + [](uint8_t shift) { return kBatchSize; }), + kBatchSize); + void* batch[kBatchSize]; + for (int i = 0; i < kBatchSize; i++) { + batch[i] = &batch[i]; + } + for (auto _ : state) { + TC_CHECK_EQ(slab.PushBatch(kSizeClass, batch, kBatchSize), kBatchSize); + TC_CHECK_EQ(slab.PopBatch(kSizeClass, batch, kBatchSize), kBatchSize); + } } BENCHMARK(BM_PushPopBatch); diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/percpu_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_test.cc new file mode 100644 index 000000000000..64488e7b43be --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/percpu_test.cc @@ -0,0 +1,74 @@ +// Copyright 2024 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/percpu.h" + +#include + +#include +#include + +#include "gtest/gtest.h" +#include "absl/base/attributes.h" +#include "absl/log/absl_check.h" +#include "absl/time/time.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/testing/testutil.h" + +namespace tcmalloc::tcmalloc_internal::subtle::percpu { +namespace { + +ABSL_CONST_INIT std::atomic alarms{0}; + +void sa_alrm(int sig) { + alarms.fetch_add(1, std::memory_order_relaxed); + TC_CHECK(IsFast()); +} + +TEST(PerCpu, SignalHandling) { + if (!IsFast()) { + GTEST_SKIP() << "per-CPU unavailable"; + } + + struct sigaction sig; + memset(&sig, 0, sizeof(sig)); // sa_flags == 0 => SA_RESTART not set + sig.sa_handler = sa_alrm; + ABSL_CHECK_EQ(sigaction(SIGALRM, &sig, nullptr), + 0); // install signal handler + + constexpr absl::Duration interval = absl::Microseconds(1); + struct timeval timeval = absl::ToTimeval(interval); + + struct itimerval signal_interval; + signal_interval.it_value = timeval; + signal_interval.it_interval = timeval; + + setitimer(ITIMER_REAL, &signal_interval, nullptr); + + for (int i = 0; i < 100000; ++i) { + UnregisterRseq(); + TC_CHECK(IsFast()); + } + + timeval = absl::ToTimeval(absl::ZeroDuration()); + signal_interval.it_value = timeval; + signal_interval.it_interval = timeval; + + setitimer(ITIMER_REAL, &signal_interval, nullptr); + + EXPECT_GT(alarms.load(std::memory_order_relaxed), 0); +} + +} // namespace +} // namespace tcmalloc::tcmalloc_internal::subtle::percpu diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/prefetch.h b/contrib/libs/tcmalloc/tcmalloc/internal/prefetch.h new file mode 100644 index 000000000000..47aaa6dd0799 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/prefetch.h @@ -0,0 +1,116 @@ +#pragma clang system_header +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_INTERNAL_PREFETCH_H_ +#define TCMALLOC_INTERNAL_PREFETCH_H_ + +#include + +#include "tcmalloc/internal/config.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +// Move data into the cache before it is read, or "prefetch" it. +// +// The value of `addr` is the address of the memory to prefetch. If +// the target and compiler support it, data prefetch instructions are +// generated. If the prefetch is done some time before the memory is +// read, it may be in the cache by the time the read occurs. +// +// The function names specify the temporal locality heuristic applied, +// using the names of Intel prefetch instructions: +// +// T0 - high degree of temporal locality; data should be left in as +// many levels of the cache possible +// T1 - moderate degree of temporal locality +// T2 - low degree of temporal locality +// Nta - no temporal locality, data need not be left in the cache +// after the read +// W - prefetch data in preparation for a write; may prefetch data +// to the local CPU and invalidate other cached copies +// +// Incorrect or gratuitous use of these functions can degrade +// performance, so use them only when representative benchmarks show +// an improvement. +// +// Example usage: +// +// tcmalloc_internal::PrefetchT0(addr); +// +#if defined(__GNUC__) +// See __builtin_prefetch: +// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html. +inline void PrefetchT0(const void* addr) { __builtin_prefetch(addr, 0, 3); } +inline void PrefetchT1(const void* addr) { __builtin_prefetch(addr, 0, 2); } +inline void PrefetchT2(const void* addr) { __builtin_prefetch(addr, 0, 1); } +inline void PrefetchNta(const void* addr) { __builtin_prefetch(addr, 0, 0); } +// Wrappers for prefetch with intent to modify. +// [x86] gcc/clang don't generate PREFETCHW for __builtin_prefetch(.., /*rw=*/1) +// unless -march=broadwell or newer; this is not generally the default, so +// manually emit prefetchw. PREFETCHW is recognized as a no-op on older Intel +// processors and has been present on AMD processors since the K6-2. +inline void PrefetchW(const void* addr) { +#if defined(__x86_64__) && !defined(__PRFCHW__) + asm("prefetchw %0" : : "m"(*static_cast(addr))); +#else + __builtin_prefetch(addr, /*rw=*/1, 0); +#endif +} +inline void PrefetchWT0(const void* addr) { +#if defined(__x86_64__) && !defined(__PRFCHW__) + asm("prefetchw %0" : : "m"(*static_cast(addr))); +#else + __builtin_prefetch(addr, 1, 3); +#endif +} +inline void PrefetchWT1(const void* addr) { +#if defined(__x86_64__) && !defined(__PRFCHW__) + asm("prefetchw %0" : : "m"(*static_cast(addr))); +#else + __builtin_prefetch(addr, 1, 2); +#endif +} +inline void PrefetchWT2(const void* addr) { +#if defined(__x86_64__) && !defined(__PRFCHW__) + asm("prefetchw %0" : : "m"(*static_cast(addr))); +#else + __builtin_prefetch(addr, 1, 1); +#endif +} +inline void PrefetchWNta(const void* addr) { +#if defined(__x86_64__) && !defined(__PRFCHW__) + asm("prefetchw %0" : : "m"(*static_cast(addr))); +#else + __builtin_prefetch(addr, 1, 0); +#endif +} +#else +inline void PrefetchT0(const void*) {} +inline void PrefetchT1(const void*) {} +inline void PrefetchT2(const void*) {} +inline void PrefetchNta(const void*) {} +inline void PrefetchWT0(const void*) {} +inline void PrefetchWT1(const void*) {} +inline void PrefetchWT2(const void*) {} +inline void PrefetchWT3(const void*) {} +#endif + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_PREFETCH_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/prefetch_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/prefetch_test.cc new file mode 100644 index 000000000000..2ab36a460d9f --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/prefetch_test.cc @@ -0,0 +1,72 @@ +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/prefetch.h" + +#include "gtest/gtest.h" + +namespace tcmalloc { +namespace tcmalloc_internal { +namespace { + +int number = 42; + +TEST(Prefetch, TemporalLocalityNone) { + PrefetchNta(&number); + EXPECT_EQ(number, 42); +} + +TEST(Prefetch, TemporalLocalityLow) { + PrefetchT2(&number); + EXPECT_EQ(number, 42); +} + +TEST(Prefetch, TemporalLocalityMedium) { + PrefetchT1(&number); + EXPECT_EQ(number, 42); +} + +TEST(Prefetch, TemporalLocalityHigh) { + PrefetchT0(&number); + EXPECT_EQ(number, 42); +} + +TEST(Prefetch, PrefetchForWrite) { + PrefetchW(&number); + EXPECT_EQ(number, 42); +} + +TEST(Prefetch, WriteTemporalLocalityNone) { + PrefetchWNta(&number); + EXPECT_EQ(number, 42); +} + +TEST(Prefetch, WriteTemporalLocalityLow) { + PrefetchWT2(&number); + EXPECT_EQ(number, 42); +} + +TEST(Prefetch, WriteTemporalLocalityMedium) { + PrefetchWT1(&number); + EXPECT_EQ(number, 42); +} + +TEST(Prefetch, WriteTemporalLocalityHigh) { + PrefetchWT0(&number); + EXPECT_EQ(number, 42); +} + +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/proc_maps.cc b/contrib/libs/tcmalloc/tcmalloc/internal/proc_maps.cc index 5a5586cfff83..b2af93cec788 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/proc_maps.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/proc_maps.cc @@ -18,10 +18,12 @@ #include #include +#include #include #include #include "absl/strings/str_format.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" #include "tcmalloc/internal/util.h" @@ -29,26 +31,12 @@ GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { namespace tcmalloc_internal { -ProcMapsIterator::ProcMapsIterator(pid_t pid) { Init(pid, nullptr); } - ProcMapsIterator::ProcMapsIterator(pid_t pid, Buffer* buffer) { - Init(pid, buffer); -} - -void ProcMapsIterator::Init(pid_t pid, Buffer* buffer) { if (pid == 0) { pid = getpid(); } pid_ = pid; - if (!buffer) { - // If the user didn't pass in any buffer storage, allocate it - // now. This is the normal case; the signal handler passes in a - // static buffer. - buffer = dynamic_buffer_ = new Buffer; - } else { - dynamic_buffer_ = nullptr; - } ibuf_ = buffer->buf; @@ -64,7 +52,7 @@ void ProcMapsIterator::Init(pid_t pid, Buffer* buffer) { // Use the main thread's "local" view to ensure adequate performance. int path_length = absl::SNPrintF(ibuf_, Buffer::kBufSize, "/proc/%d/task/%d/maps", pid, pid); - CHECK_CONDITION(path_length < Buffer::kBufSize); + TC_CHECK_LT(path_length, Buffer::kBufSize); // No error logging since this can be called from the crash dump // handler at awkward moments. Users should call Valid() before @@ -81,7 +69,6 @@ ProcMapsIterator::~ProcMapsIterator() { // the manpage for close(2), this is widespread yet not fully portable, which // is unfortunate. POSIX explicitly leaves this behavior as unspecified. if (fd_ >= 0) close(fd_); - delete dynamic_buffer_; } bool ProcMapsIterator::Valid() const { return fd_ != -1; } diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/proc_maps.h b/contrib/libs/tcmalloc/tcmalloc/internal/proc_maps.h index c5c763a1e864..ce68f217fe7b 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/proc_maps.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/proc_maps.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,10 +16,11 @@ #ifndef TCMALLOC_INTERNAL_PROC_MAPS_H_ #define TCMALLOC_INTERNAL_PROC_MAPS_H_ -#include #include #include +#include + #include "tcmalloc/internal/config.h" GOOGLE_MALLOC_SECTION_BEGIN @@ -33,12 +35,9 @@ class ProcMapsIterator { char buf[kBufSize]; }; - // Create a new iterator for the specified pid. pid can be 0 for "self". - explicit ProcMapsIterator(pid_t pid); - // Create an iterator with specified storage (for use in signal handler). - // "buffer" should point to a ProcMapsIterator::Buffer buffer can be null in - // which case a buffer will be allocated. + // + // pid can be 0 for "self". ProcMapsIterator(pid_t pid, Buffer* buffer); // Returns true if the iterator successfully initialized; @@ -50,8 +49,6 @@ class ProcMapsIterator { ~ProcMapsIterator(); private: - void Init(pid_t pid, Buffer* buffer); - char* ibuf_; // input buffer char* stext_; // start of text char* etext_; // end of text @@ -60,7 +57,6 @@ class ProcMapsIterator { int fd_; // filehandle on /proc/*/maps pid_t pid_; char flags_[10]; - Buffer* dynamic_buffer_; // dynamically-allocated Buffer }; } // namespace tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/profile.proto b/contrib/libs/tcmalloc/tcmalloc/internal/profile.proto new file mode 100644 index 000000000000..d557a741f327 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/profile.proto @@ -0,0 +1,233 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Profile is a common stacktrace profile format. +// +// Measurements represented with this format should follow the +// following conventions: +// +// - Consumers should treat unset optional fields as if they had been +// set with their default value. +// +// - When possible, measurements should be stored in "unsampled" form +// that is most useful to humans. There should be enough +// information present to determine the original sampled values. +// +// - On-disk, the serialized proto must be gzip-compressed. +// +// - The profile is represented as a set of samples, where each sample +// references a sequence of locations, and where each location belongs +// to a mapping. +// - There is a N->1 relationship from sample.location_id entries to +// locations. For every sample.location_id entry there must be a +// unique Location with that id. +// - There is an optional N->1 relationship from locations to +// mappings. For every nonzero Location.mapping_id there must be a +// unique Mapping with that id. + +syntax = "proto3"; + +package tcmalloc.tcmalloc_internal.perftools.profiles; + +option java_package = "com.google.perftools.profiles"; +option java_outer_classname = "ProfileProto"; + +message Profile { + // A description of the samples associated with each Sample.value. + // For a cpu profile this might be: + // [["cpu","nanoseconds"]] or [["wall","seconds"]] or [["syscall","count"]] + // For a heap profile, this might be: + // [["allocations","count"], ["space","bytes"]], + // If one of the values represents the number of events represented + // by the sample, by convention it should be at index 0 and use + // sample_type.unit == "count". + repeated ValueType sample_type = 1; + // The set of samples recorded in this profile. + repeated Sample sample = 2; + // Mapping from address ranges to the image/binary/library mapped + // into that address range. mapping[0] will be the main binary. + repeated Mapping mapping = 3; + // Locations referenced by samples. + repeated Location location = 4; + // Functions referenced by locations. + repeated Function function = 5; + // A common table for strings referenced by various messages. + // string_table[0] must always be "". + repeated string string_table = 6; + // frames with Function.function_name fully matching the following + // regexp will be dropped from the samples, along with their successors. + int64 drop_frames = 7; // Index into string table. + // frames with Function.function_name fully matching the following + // regexp will be kept, even if it matches drop_frames. + int64 keep_frames = 8; // Index into string table. + + // The following fields are informational, do not affect + // interpretation of results. + + // Time of collection (UTC) represented as nanoseconds past the epoch. + int64 time_nanos = 9; + // Duration of the profile, if a duration makes sense. + int64 duration_nanos = 10; + // The kind of events between sampled occurrences. + // e.g [ "cpu","cycles" ] or [ "heap","bytes" ] + ValueType period_type = 11; + // The number of events between sampled occurrences. + int64 period = 12; + // Free-form text associated with the profile. The text is displayed as is + // to the user by the tools that read profiles (e.g. by pprof). This field + // should not be used to store any machine-readable information, it is only + // for human-friendly content. The profile must stay functional if this field + // is cleaned. + repeated int64 comment = 13; // Indices into string table. + // Index into the string table of the type of the preferred sample + // value. If unset, clients should default to the last sample value. + int64 default_sample_type = 14; + // Documentation link for this profile. The URL must be absolute, + // e.g., http://pprof.example.com/cpu-profile.html + // + // The URL may be missing if the profile was generated by older code or code + // that did not bother to supply a link. + int64 doc_url = 15; // Index into string table. +} + +// ValueType describes the semantics and measurement units of a value. +message ValueType { + int64 type = 1; // Index into string table. + int64 unit = 2; // Index into string table. +} + +// Each Sample records values encountered in some program +// context. The program context is typically a stack trace, perhaps +// augmented with auxiliary information like the thread-id, some +// indicator of a higher level request being handled etc. +message Sample { + // The ids recorded here correspond to a Profile.location.id. + // The leaf is at location_id[0]. + repeated uint64 location_id = 1; + // The type and unit of each value is defined by the corresponding + // entry in Profile.sample_type. All samples must have the same + // number of values, the same as the length of Profile.sample_type. + // When aggregating multiple samples into a single sample, the + // result has a list of values that is the element-wise sum of the + // lists of the originals. + repeated int64 value = 2; + // label includes additional context for this sample. It can include + // things like a thread id, allocation size, etc. + // + // NOTE: While possible, having multiple values for the same label key is + // strongly discouraged and should never be used. Most tools (e.g. pprof) do + // not have good (or any) support for multi-value labels. And an even more + // discouraged case is having a string label and a numeric label of the same + // name on a sample. Again, possible to express, but should not be used. + repeated Label label = 3; +} + +message Label { + // Index into string table. An annotation for a sample (e.g. + // "allocation_size") with an associated value. + // Keys with "pprof::" prefix are reserved for internal use by pprof. + int64 key = 1; + + // At most one of the following must be present + int64 str = 2; // Index into string table + int64 num = 3; + + // Should only be present when num is present. + // Specifies the units of num. + // Use arbitrary string (for example, "requests") as a custom count unit. + // If no unit is specified, consumer may apply heuristic to deduce the unit. + // Consumers may also interpret units like "bytes" and "kilobytes" as memory + // units and units like "seconds" and "nanoseconds" as time units, + // and apply appropriate unit conversions to these. + int64 num_unit = 4; // Index into string table +} + +message Mapping { + // Unique nonzero id for the mapping. + uint64 id = 1; + // Address at which the binary (or DLL) is loaded into memory. + uint64 memory_start = 2; + // The limit of the address range occupied by this mapping. + uint64 memory_limit = 3; + // Offset in the binary that corresponds to the first mapped address. + uint64 file_offset = 4; + // The object this entry is loaded from. This can be a filename on + // disk for the main binary and shared libraries, or virtual + // abstractions like "[vdso]". + int64 filename = 5; // Index into string table + // A string that uniquely identifies a particular program version + // with high probability. E.g., for binaries generated by GNU tools, + // it could be the contents of the .note.gnu.build-id field. + int64 build_id = 6; // Index into string table + + // The following fields indicate the resolution of symbolic info. + bool has_functions = 7; + bool has_filenames = 8; + bool has_line_numbers = 9; + bool has_inline_frames = 10; +} + +// Describes function and line table debug information. +message Location { + // Unique nonzero id for the location. A profile could use + // instruction addresses or any integer sequence as ids. + uint64 id = 1; + // The id of the corresponding profile.Mapping for this location. + // It can be unset if the mapping is unknown or not applicable for + // this profile type. + uint64 mapping_id = 2; + // The instruction address for this location, if available. It + // should be within [Mapping.memory_start...Mapping.memory_limit] + // for the corresponding mapping. A non-leaf address may be in the + // middle of a call instruction. It is up to display tools to find + // the beginning of the instruction if necessary. + uint64 address = 3; + // Multiple line indicates this location has inlined functions, + // where the last entry represents the caller into which the + // preceding entries were inlined. + // + // E.g., if memcpy() is inlined into printf: + // line[0].function_name == "memcpy" + // line[1].function_name == "printf" + repeated Line line = 4; + // Provides an indication that multiple symbols map to this location's + // address, for example due to identical code folding by the linker. In that + // case the line information above represents one of the multiple + // symbols. This field must be recomputed when the symbolization state of the + // profile changes. + bool is_folded = 5; +} + +message Line { + // The id of the corresponding profile.Function for this line. + uint64 function_id = 1; + // Line number in source code. + int64 line = 2; + // Column number in source code. + int64 column = 3; +} + +message Function { + // Unique nonzero id for the function. + uint64 id = 1; + // Name of the function, in human-readable form if available. + int64 name = 2; // Index into string table + // Name of the function, as identified by the system. + // For instance, it can be a C++ mangled name. + int64 system_name = 3; // Index into string table + // Source file containing the function. + int64 filename = 4; // Index into string table + // Line number in source file. + int64 start_line = 5; +} diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder.cc b/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder.cc new file mode 100644 index 000000000000..a74e3c7ff711 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder.cc @@ -0,0 +1,927 @@ +// Copyright 2021 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/profile_builder.h" + +#include +#include +#include + +#include "absl/base/casts.h" +#include "absl/container/flat_hash_map.h" +#include "absl/hash/hash.h" +#include "absl/status/statusor.h" +#include "absl/strings/match.h" +#include "absl/strings/str_cat.h" +#include "absl/time/time.h" +#include "absl/types/span.h" +#include "tcmalloc/internal/pageflags.h" +#include "tcmalloc/malloc_extension.h" + +#if defined(__linux__) +#include +#include +#endif // defined(__linux__) +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "tcmalloc/internal/profile.pb.h" +#include "absl/base/attributes.h" +#include "absl/base/macros.h" +#include "absl/status/status.h" +#include "absl/strings/escaping.h" +#include "absl/strings/string_view.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/residency.h" + +namespace tcmalloc { +namespace tcmalloc_internal { +namespace { + +#if defined(__linux__) +// Returns the Phdr of the first segment of the given type. +const ElfW(Phdr) * + GetFirstSegment(const dl_phdr_info* const info, const int segment_type) { + for (int i = 0; i < info->dlpi_phnum; ++i) { + if (info->dlpi_phdr[i].p_type == segment_type) { + return &info->dlpi_phdr[i]; + } + } + return nullptr; +} + +// Return DT_SONAME for the given image. If there is no PT_DYNAMIC or if +// PT_DYNAMIC does not contain DT_SONAME, return nullptr. +static const char* GetSoName(const dl_phdr_info* const info) { + const ElfW(Phdr)* const pt_dynamic = GetFirstSegment(info, PT_DYNAMIC); + if (pt_dynamic == nullptr) { + return nullptr; + } + const ElfW(Dyn)* dyn = + reinterpret_cast(info->dlpi_addr + pt_dynamic->p_vaddr); + const ElfW(Dyn)* dt_strtab = nullptr; + const ElfW(Dyn)* dt_strsz = nullptr; + const ElfW(Dyn)* dt_soname = nullptr; + for (; dyn->d_tag != DT_NULL; ++dyn) { + if (dyn->d_tag == DT_SONAME) { + dt_soname = dyn; + } else if (dyn->d_tag == DT_STRTAB) { + dt_strtab = dyn; + } else if (dyn->d_tag == DT_STRSZ) { + dt_strsz = dyn; + } + } + if (dt_soname == nullptr) { + return nullptr; + } + TC_CHECK_NE(dt_strtab, nullptr); + TC_CHECK_NE(dt_strsz, nullptr); + const char* const strtab = + reinterpret_cast(info->dlpi_addr + dt_strtab->d_un.d_val); + TC_CHECK_LT(dt_soname->d_un.d_val, dt_strsz->d_un.d_val); + return strtab + dt_soname->d_un.d_val; +} +#endif // defined(__linux__) + +struct SampleMergedData { + int64_t count = 0; + int64_t sum = 0; + std::optional resident_size; + std::optional swapped_size; + std::optional stale_size; + std::optional locked_size; + std::optional stale_scan_period; +}; + +// The equality and hash methods of Profile::Sample only use a subset of its +// member fields. +struct SampleEqWithSubFields { + bool operator()(const Profile::Sample& a, const Profile::Sample& b) const { + auto fields = [](const Profile::Sample& s) { + return std::tie(s.depth, s.requested_size, s.requested_alignment, + s.requested_size_returning, s.allocated_size, + s.access_hint, s.access_allocated, s.guarded_status, + s.type); + }; + return fields(a) == fields(b) && + std::equal(a.stack, a.stack + a.depth, b.stack, b.stack + b.depth); + } +}; + +struct SampleHashWithSubFields { + size_t operator()(const Profile::Sample& s) const { + return absl::HashOf( + absl::MakeConstSpan(s.stack, s.depth), s.depth, s.requested_size, + s.requested_alignment, s.requested_size_returning, s.allocated_size, + s.access_hint, s.access_allocated, s.guarded_status, s.type); + } +}; + +using SampleMergedMap = + absl::flat_hash_map; + +SampleMergedMap MergeProfileSamplesAndMaybeGetResidencyInfo( + const tcmalloc::Profile& profile, PageFlagsBase* pageflags, + Residency* residency) { + SampleMergedMap map; + + profile.Iterate([&](const tcmalloc::Profile::Sample& entry) { + SampleMergedData& data = map[entry]; + data.count += entry.count; + data.sum += entry.sum; + if (residency) { + auto residency_info = + residency->Get(entry.span_start_address, entry.allocated_size); + // As long as `residency_info` provides data in some samples, the merged + // data will have their sums. + // NOTE: The data here is comparable to `tcmalloc::Profile::Sample::sum`, + // not to `tcmalloc::Profile::Sample::requested_size` (it's pre-multiplied + // by count and represents all of the resident memory). + if (residency_info.has_value()) { + size_t resident_size = entry.count * residency_info->bytes_resident; + size_t swapped_size = entry.count * residency_info->bytes_swapped; + if (!data.resident_size.has_value()) { + data.resident_size = resident_size; + data.swapped_size = swapped_size; + } else { + data.resident_size.value() += resident_size; + data.swapped_size.value() += swapped_size; + } + } + } + + if (pageflags) { + auto page_stats = + pageflags->Get(entry.span_start_address, entry.allocated_size); + if (page_stats.has_value()) { + if (!data.stale_size.has_value()) { + data.stale_size.emplace(); + } + data.stale_size.value() += entry.count * page_stats->bytes_stale; + + if (!data.locked_size.has_value()) { + data.locked_size.emplace(); + } + data.locked_size.value() += entry.count * page_stats->bytes_locked; + + if (!data.stale_scan_period.has_value()) { + data.stale_scan_period = page_stats->stale_scan_seconds; + } else if (*data.stale_scan_period != page_stats->stale_scan_seconds) { + // multiple values for stale_scan_seconds, so we don't know what it + // is; explicitly set to the default of zero. + data.stale_scan_period = 0; + } + } + } + }); + return map; +} + +} // namespace + +#if defined(__linux__) +// Extracts the linker provided build ID from the PT_NOTE segment found in info. +// +// On failure, returns an empty string. +std::string GetBuildId(const dl_phdr_info* const info) { + std::string result; + + // pt_note contains entries (of type ElfW(Nhdr)) starting at + // info->dlpi_addr + pt_note->p_vaddr + // with length + // pt_note->p_memsz + // + // The length of each entry is given by + // Align(sizeof(ElfW(Nhdr)) + nhdr->n_namesz) + Align(nhdr->n_descsz) + for (int i = 0; i < info->dlpi_phnum; ++i) { + const ElfW(Phdr)* pt_note = &info->dlpi_phdr[i]; + if (pt_note->p_type != PT_NOTE) continue; + + const char* note = + reinterpret_cast(info->dlpi_addr + pt_note->p_vaddr); + const char* const last = note + pt_note->p_filesz; + const ElfW(Word) align = pt_note->p_align; + while (note < last) { + const ElfW(Nhdr)* const nhdr = reinterpret_cast(note); + if (note + sizeof(*nhdr) > last) { + // Corrupt PT_NOTE + break; + } + + // Both the start and end of the descriptor are aligned by sh_addralign + // (= p_align). + const ElfW(Word) desc_start = + (sizeof(*nhdr) + nhdr->n_namesz + align - 1) & -align; + const ElfW(Word) size = + desc_start + ((nhdr->n_descsz + align - 1) & -align); + + // Beware of wrap-around. + if (nhdr->n_namesz >= static_cast(-align) || + nhdr->n_descsz >= static_cast(-align) || + desc_start < sizeof(*nhdr) || size < desc_start || + size > last - note) { + // Corrupt PT_NOTE + break; + } + + if (nhdr->n_type == NT_GNU_BUILD_ID) { + const char* const note_name = note + sizeof(*nhdr); + // n_namesz is the length of note_name. + if (nhdr->n_namesz == 4 && memcmp(note_name, "GNU\0", 4) == 0) { + if (!result.empty()) { + // Repeated build-ids. Ignore them. + return ""; + } + result = absl::BytesToHexString( + absl::string_view(note + desc_start, nhdr->n_descsz)); + } + } + note += size; + } + } + + return result; +} +#endif // defined(__linux__) + +ABSL_CONST_INIT const absl::string_view kProfileDropFrames = + // POSIX entry points. + "calloc|" + "cfree|" + "malloc|" + "free|" + "memalign|" + "do_memalign|" + "(__)?posix_memalign|" + "pvalloc|" + "valloc|" + "realloc|" + "aligned_alloc|" + "sdallocx|" + + // TCMalloc. + "tcmalloc::.*|" + "TCMallocInternalCalloc|" + "TCMallocInternalCfree|" + "TCMallocInternalMalloc|" + "TCMallocInternalFree|" + "TCMallocInternalMemalign|" + "TCMallocInternalAlignedAlloc|" + "TCMallocInternalPosixMemalign|" + "TCMallocInternalPvalloc|" + "TCMallocInternalValloc|" + "TCMallocInternalRealloc|" + "TCMallocInternalNew(Array)?(Aligned)?(Nothrow)?|" + "TCMallocInternalDelete(Array)?(Sized)?(Aligned)?(Nothrow)?|" + "TCMallocInternalSdallocx|" + "(tcmalloc_)?size_returning_operator_new(_hot_cold)?(_nothrow)?|" + + // Lifetime (deallocation) profiler routines. + ".*deallocationz::DeallocationProfiler.*|" + + // libstdc++ memory allocation routines + "__gnu_cxx::new_allocator::allocate|" + "__gnu_cxx::new_allocator::deallocate|" + "__malloc_alloc_template::allocate|" + "std::__new_allocator::allocate|" + "std::__new_allocator::deallocate|" + "_M_allocate|" + + // libc++ memory allocation routines + "std::__(u|1)::__libcpp_allocate|" + "std::__(u|1)::__libcpp_deallocate|" + "std::__(u|1)::__libcpp_operator_new|" + "std::__(u|1)::__libcpp_operator_delete|" + "std::__(u|1)::allocator::allocate|" + "std::__(u|1)::allocator::deallocate|" + "std::__(u|1)::allocator_traits::allocate|" + "std::__(u|1)::allocator_traits::deallocate|" + "std::__(u|1)::__builtin_new_allocator::__allocate_bytes|" + "std::__(u|1)::__do_deallocate_handle_size|" + "std::__(u|1)::__allocate_at_least|" + "std::__(u|1)::__allocation_guard::(~)?__allocation_guard|" + "std::__(u|1)::__split_buffer::(~)?__split_buffer|" + + // Other misc. memory allocation routines + "(::)?do_malloc_pages|" + "(::)?do_realloc|" + "__builtin_(vec_)?delete|" + "__builtin_(vec_)?new|" + "__libc_calloc|" + "__libc_malloc|" + "__libc_memalign|" + "__libc_realloc|" + "__size_returning_new|" + "__size_returning_new_hot_cold|" + "__size_returning_new_aligned|" + "__size_returning_new_aligned_hot_cold|" + "slow_alloc|" + "fast_alloc|" + "AllocSmall|" + "operator new|" + "operator delete"; + +ProfileBuilder::ProfileBuilder() + : profile_(std::make_unique()) { + // string_table[0] must be "" + profile_->add_string_table(""); +} + +int ProfileBuilder::InternString(absl::string_view sv) { + if (sv.empty()) { + return 0; + } + + const int index = profile_->string_table_size(); + const auto inserted = strings_.emplace(sv, index); + if (!inserted.second) { + // Failed to insert -- use existing id. + return inserted.first->second; + } + profile_->add_string_table(inserted.first->first); + return index; +} + +int ProfileBuilder::InternLocation(const void* ptr) { + uintptr_t address = absl::bit_cast(ptr); + + // Avoid assigning location ID 0 by incrementing by 1. + const int index = profile_->location_size() + 1; + const auto inserted = locations_.emplace(address, index); + if (!inserted.second) { + // Failed to insert -- use existing id. + return inserted.first->second; + } + perftools::profiles::Location& location = *profile_->add_location(); + TC_ASSERT_EQ(inserted.first->second, index); + location.set_id(index); + location.set_address(address); + + if (mappings_.empty()) { + return index; + } + + // Find the mapping ID. + auto it = mappings_.upper_bound(address); + if (it != mappings_.begin()) { + --it; + } + + // If *it contains address, add mapping to location. + const int mapping_index = it->second; + const perftools::profiles::Mapping& mapping = + profile_->mapping(mapping_index); + const int mapping_id = mapping.id(); + TC_ASSERT(it->first == mapping.memory_start()); + + if (it->first <= address && address < mapping.memory_limit()) { + location.set_mapping_id(mapping_id); + } + + return index; +} + +void ProfileBuilder::InternCallstack(absl::Span stack, + perftools::profiles::Sample& sample) { + // Profile addresses are raw stack unwind addresses, so they should be + // adjusted by -1 to land inside the call instruction (although potentially + // misaligned). + for (const void* frame : stack) { + int id = InternLocation( + absl::bit_cast(absl::bit_cast(frame) - 1)); + sample.add_location_id(id); + } + TC_ASSERT_EQ(sample.location_id().size(), stack.size()); +} + +void ProfileBuilder::AddCurrentMappings() { +#if defined(__linux__) + auto dl_iterate_callback = +[](dl_phdr_info* info, size_t size, void* data) { + // Skip dummy entry introduced since glibc 2.18. + if (info->dlpi_phdr == nullptr && info->dlpi_phnum == 0) { + return 0; + } + + ProfileBuilder& builder = *static_cast(data); + const bool is_main_executable = builder.profile_->mapping_size() == 0; + + // Evaluate all the loadable segments. + for (int i = 0; i < info->dlpi_phnum; ++i) { + if (info->dlpi_phdr[i].p_type != PT_LOAD) { + continue; + } + const ElfW(Phdr)* pt_load = &info->dlpi_phdr[i]; + + TC_CHECK_NE(pt_load, nullptr); + + // Extract data. + const size_t memory_start = info->dlpi_addr + pt_load->p_vaddr; + const size_t memory_limit = memory_start + pt_load->p_memsz; + const size_t file_offset = pt_load->p_offset; + + // Storage for path to executable as dlpi_name isn't populated for the + // main executable. +1 to allow for the null terminator that readlink + // does not add. + char self_filename[PATH_MAX + 1]; + const char* filename = info->dlpi_name; + if (filename == nullptr || filename[0] == '\0') { + // This is either the main executable or the VDSO. The main executable + // is always the first entry processed by callbacks. + if (is_main_executable) { + // This is the main executable. + ssize_t ret = readlink("/proc/self/exe", self_filename, + sizeof(self_filename) - 1); + if (ret >= 0 && ret < sizeof(self_filename)) { + self_filename[ret] = '\0'; + filename = self_filename; + } + } else { + // This is the VDSO. + filename = GetSoName(info); + } + } + + char resolved_path[PATH_MAX]; + absl::string_view resolved_filename; + if (realpath(filename, resolved_path)) { + resolved_filename = resolved_path; + } else { + resolved_filename = filename; + } + + const std::string build_id = GetBuildId(info); + + // Add to profile. + builder.AddMapping(memory_start, memory_limit, file_offset, + resolved_filename, build_id); + } + // Keep going. + return 0; + }; + + dl_iterate_phdr(dl_iterate_callback, this); +#endif // defined(__linux__) +} + +int ProfileBuilder::AddMapping(uintptr_t memory_start, uintptr_t memory_limit, + uintptr_t file_offset, + absl::string_view filename, + absl::string_view build_id) { + perftools::profiles::Mapping& mapping = *profile_->add_mapping(); + const int mapping_id = profile_->mapping_size(); + mapping.set_id(mapping_id); + mapping.set_memory_start(memory_start); + mapping.set_memory_limit(memory_limit); + mapping.set_file_offset(file_offset); + mapping.set_filename(InternString(filename)); + mapping.set_build_id(InternString(build_id)); + + mappings_.emplace(memory_start, mapping_id - 1); + return mapping_id; +} + +static absl::Status MakeLifetimeProfileProto(const tcmalloc::Profile& profile, + ProfileBuilder* builder) { + TC_CHECK_NE(builder, nullptr); + perftools::profiles::Profile& converted = builder->profile(); + perftools::profiles::ValueType* period_type = converted.mutable_period_type(); + + period_type->set_type(builder->InternString("space")); + period_type->set_unit(builder->InternString("bytes")); + + for (const auto& [type, unit] : {std::pair{"allocated_objects", "count"}, + {"allocated_space", "bytes"}, + {"deallocated_objects", "count"}, + {"deallocated_space", "bytes"}, + {"censored_allocated_objects", "count"}, + {"censored_allocated_space", "bytes"}}) { + perftools::profiles::ValueType* sample_type = converted.add_sample_type(); + sample_type->set_type(builder->InternString(type)); + sample_type->set_unit(builder->InternString(unit)); + } + + converted.set_default_sample_type(builder->InternString("deallocated_space")); + converted.set_duration_nanos(absl::ToInt64Nanoseconds(profile.Duration())); + + if (auto start = profile.StartTime(); start.has_value()) { + converted.set_time_nanos(absl::ToUnixNanos(*start)); + } + + converted.set_drop_frames(builder->InternString(kProfileDropFrames)); + + // Common intern string ids which are going to be used for each sample. + const int count_id = builder->InternString("count"); + const int bytes_id = builder->InternString("bytes"); + const int request_id = builder->InternString("request"); + const int alignment_id = builder->InternString("alignment"); + const int nanoseconds_id = builder->InternString("nanoseconds"); + const int avg_lifetime_id = builder->InternString("avg_lifetime"); + const int stddev_lifetime_id = builder->InternString("stddev_lifetime"); + const int min_lifetime_id = builder->InternString("min_lifetime"); + const int max_lifetime_id = builder->InternString("max_lifetime"); + const int active_cpu_id = builder->InternString("active CPU"); + const int active_vcpu_id = builder->InternString("active vCPU"); + const int active_l3_id = builder->InternString("active L3"); + const int active_numa_id = builder->InternString("active NUMA"); + const int same_id = builder->InternString("same"); + const int different_id = builder->InternString("different"); + const int active_thread_id = builder->InternString("active thread"); + const int callstack_pair_id = builder->InternString("callstack-pair-id"); + const int none_id = builder->InternString("none"); + + profile.Iterate([&](const tcmalloc::Profile::Sample& entry) { + perftools::profiles::Sample& sample = *converted.add_sample(); + + TC_CHECK_LE(entry.depth, ABSL_ARRAYSIZE(entry.stack)); + builder->InternCallstack(absl::MakeSpan(entry.stack, entry.depth), sample); + + auto add_label = [&](int key, int unit, size_t value) { + perftools::profiles::Label& label = *sample.add_label(); + label.set_key(key); + label.set_num(value); + label.set_num_unit(unit); + }; + + auto add_positive_label = [&](int key, int unit, size_t value) { + if (value <= 0) return; + add_label(key, unit, value); + }; + + auto add_optional_string_label = + [&](int key, const std::optional& optional_result, int result1, + int result2) { + perftools::profiles::Label& label = *sample.add_label(); + label.set_key(key); + + if (!optional_result.has_value()) { + label.set_str(none_id); + } else if (optional_result.value()) { + label.set_str(result1); + } else { + label.set_str(result2); + } + }; + + // The following three fields are common across profiles. + add_positive_label(bytes_id, bytes_id, entry.allocated_size); + add_positive_label(request_id, bytes_id, entry.requested_size); + add_positive_label(alignment_id, bytes_id, entry.requested_alignment); + + // The following fields are specific to lifetime (deallocation) profiler. + add_positive_label(callstack_pair_id, count_id, entry.profile_id); + add_positive_label(avg_lifetime_id, nanoseconds_id, + absl::ToInt64Nanoseconds(entry.avg_lifetime)); + add_positive_label(stddev_lifetime_id, nanoseconds_id, + absl::ToInt64Nanoseconds(entry.stddev_lifetime)); + add_positive_label(min_lifetime_id, nanoseconds_id, + absl::ToInt64Nanoseconds(entry.min_lifetime)); + add_positive_label(max_lifetime_id, nanoseconds_id, + absl::ToInt64Nanoseconds(entry.max_lifetime)); + + add_optional_string_label(active_cpu_id, + entry.allocator_deallocator_physical_cpu_matched, + same_id, different_id); + add_optional_string_label(active_vcpu_id, + entry.allocator_deallocator_virtual_cpu_matched, + same_id, different_id); + add_optional_string_label(active_l3_id, + entry.allocator_deallocator_l3_matched, same_id, + different_id); + add_optional_string_label(active_numa_id, + entry.allocator_deallocator_numa_matched, same_id, + different_id); + add_optional_string_label(active_thread_id, + entry.allocator_deallocator_thread_matched, + same_id, different_id); + + int64_t count = abs(entry.count); + int64_t weight = entry.sum; + + // Handle censored allocations first since we distinguish + // the samples based on the is_censored flag. + if (entry.is_censored) { + sample.add_value(0); + sample.add_value(0); + sample.add_value(0); + sample.add_value(0); + sample.add_value(count); + sample.add_value(weight); + } else if (entry.count > 0) { // for allocation, e.count is positive + sample.add_value(count); + sample.add_value(weight); + sample.add_value(0); + sample.add_value(0); + sample.add_value(0); + sample.add_value(0); + } else { // for deallocation, e.count is negative + sample.add_value(0); + sample.add_value(0); + sample.add_value(count); + sample.add_value(weight); + sample.add_value(0); + sample.add_value(0); + } + }); + return absl::OkStatus(); +} + +std::unique_ptr ProfileBuilder::Finalize() && { + return std::move(profile_); +} + +absl::StatusOr> MakeProfileProto( + const ::tcmalloc::Profile& profile, PageFlagsBase* pageflags, + Residency* residency) { + if (profile.Type() == ProfileType::kDoNotUse) { +#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ + defined(ABSL_HAVE_LEAK_SANITIZER) || \ + defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER) + return absl::UnimplementedError( + "Program was built with sanitizers enabled, which do not support heap " + "profiling"); +#else + return absl::InvalidArgumentError( + "Empty heap profile: TCMalloc appears disabled or unavailable (e.g. a " + "custom allocator may be linked)"); +#endif + } + + ProfileBuilder builder; + builder.AddCurrentMappings(); + + if (profile.Type() == ProfileType::kLifetimes) { + absl::Status error = MakeLifetimeProfileProto(profile, &builder); + if (!error.ok()) { + return error; + } + return std::move(builder).Finalize(); + } + + const int alignment_id = builder.InternString("alignment"); + const int bytes_id = builder.InternString("bytes"); + const int count_id = builder.InternString("count"); + const int objects_id = builder.InternString("objects"); + const int request_id = builder.InternString("request"); + const int size_returning_id = builder.InternString("size_returning"); + const int stale_scan_period_id = builder.InternString("stale_scan_period"); + const int seconds_id = builder.InternString("seconds"); + const int space_id = builder.InternString("space"); + const int resident_space_id = builder.InternString("resident_space"); + const int swapped_space_id = builder.InternString("swapped_space"); + const int stale_space_id = builder.InternString("stale_space"); + const int locked_space_id = builder.InternString("locked_space"); + const int access_hint_id = builder.InternString("access_hint"); + const int access_allocated_id = builder.InternString("access_allocated"); + const int cold_id = builder.InternString("cold"); + const int hot_id = builder.InternString("hot"); + const int allocation_type_id = builder.InternString("allocation type"); + const int new_id = builder.InternString("new"); + const int malloc_id = builder.InternString("malloc"); + const int aligned_malloc_id = builder.InternString("aligned malloc"); + + perftools::profiles::Profile& converted = builder.profile(); + + perftools::profiles::ValueType& period_type = + *converted.mutable_period_type(); + period_type.set_type(space_id); + period_type.set_unit(bytes_id); + converted.set_drop_frames(builder.InternString(kProfileDropFrames)); + converted.set_duration_nanos(absl::ToInt64Nanoseconds(profile.Duration())); + + if (auto start = profile.StartTime(); start.has_value()) { + converted.set_time_nanos(absl::ToUnixNanos(*start)); + } + + { + perftools::profiles::ValueType& sample_type = *converted.add_sample_type(); + sample_type.set_type(objects_id); + sample_type.set_unit(count_id); + } + + { + perftools::profiles::ValueType& sample_type = *converted.add_sample_type(); + sample_type.set_type(space_id); + sample_type.set_unit(bytes_id); + } + + const bool exporting_residency = + (profile.Type() == tcmalloc::ProfileType::kHeap); + if (exporting_residency) { + perftools::profiles::ValueType* sample_type = converted.add_sample_type(); + sample_type->set_type(resident_space_id); + sample_type->set_unit(bytes_id); + + sample_type = converted.add_sample_type(); + sample_type->set_type(swapped_space_id); + sample_type->set_unit(bytes_id); + + sample_type = converted.add_sample_type(); + sample_type->set_type(stale_space_id); + sample_type->set_unit(bytes_id); + + sample_type = converted.add_sample_type(); + sample_type->set_type(locked_space_id); + sample_type->set_unit(bytes_id); + } + + int default_sample_type_id; + switch (profile.Type()) { + case tcmalloc::ProfileType::kFragmentation: + case tcmalloc::ProfileType::kHeap: + case tcmalloc::ProfileType::kPeakHeap: + default_sample_type_id = space_id; + break; + case tcmalloc::ProfileType::kAllocations: + default_sample_type_id = objects_id; + break; + default: + return absl::InvalidArgumentError("Unexpected profile format"); + } + + converted.set_default_sample_type(default_sample_type_id); + + SampleMergedMap samples = MergeProfileSamplesAndMaybeGetResidencyInfo( + profile, pageflags, residency); + for (const auto& [entry, data] : samples) { + perftools::profiles::Profile& profile = builder.profile(); + perftools::profiles::Sample& sample = *profile.add_sample(); + + TC_CHECK_LE(entry.depth, ABSL_ARRAYSIZE(entry.stack)); + builder.InternCallstack(absl::MakeSpan(entry.stack, entry.depth), sample); + + sample.add_value(data.count); + sample.add_value(data.sum); + if (exporting_residency) { + sample.add_value(data.resident_size.value_or(0)); + sample.add_value(data.swapped_size.value_or(0)); + sample.add_value(data.stale_size.value_or(0)); + sample.add_value(data.locked_size.value_or(0)); + } + + // add fields that are common to all memory profiles + auto add_label = [&](int key, int unit, size_t value) { + perftools::profiles::Label& label = *sample.add_label(); + label.set_key(key); + label.set_num(value); + label.set_num_unit(unit); + }; + + auto add_positive_label = [&](int key, int unit, size_t value) { + if (value <= 0) return; + add_label(key, unit, value); + }; + + add_positive_label(bytes_id, bytes_id, entry.allocated_size); + add_positive_label(request_id, bytes_id, entry.requested_size); + add_positive_label(alignment_id, bytes_id, entry.requested_alignment); + add_positive_label(size_returning_id, 0, entry.requested_size_returning); + add_positive_label(stale_scan_period_id, seconds_id, + data.stale_scan_period.value_or(0)); + + auto add_access_label = [&](int key, + tcmalloc::Profile::Sample::Access access) { + switch (access) { + case tcmalloc::Profile::Sample::Access::Hot: { + perftools::profiles::Label& access_label = *sample.add_label(); + access_label.set_key(key); + access_label.set_str(hot_id); + break; + } + case tcmalloc::Profile::Sample::Access::Cold: { + perftools::profiles::Label& access_label = *sample.add_label(); + access_label.set_key(key); + access_label.set_str(cold_id); + break; + } + default: + break; + } + }; + + add_label(access_hint_id, access_hint_id, + static_cast(entry.access_hint)); + add_access_label(access_allocated_id, entry.access_allocated); + + perftools::profiles::Label& type_label = *sample.add_label(); + type_label.set_key(allocation_type_id); + + switch (entry.type) { + case Profile::Sample::AllocationType::New: + type_label.set_str(new_id); + break; + case Profile::Sample::AllocationType::Malloc: + type_label.set_str(malloc_id); + break; + case Profile::Sample::AllocationType::AlignedMalloc: + type_label.set_str(aligned_malloc_id); + break; + } + + const int guarded_status_id = builder.InternString("guarded_status"); + const int larger_than_one_page_id = + builder.InternString("LargerThanOnePage"); + const int disabled_id = builder.InternString("Disabled"); + const int rate_limited_id = builder.InternString("RateLimited"); + const int too_small_id = builder.InternString("TooSmall"); + const int no_available_slots_id = builder.InternString("NoAvailableSlots"); + const int m_protect_failed_id = builder.InternString("MProtectFailed"); + const int filtered_id = builder.InternString("Filtered"); + const int unknown_id = builder.InternString("Unknown"); + const int not_attempted_id = builder.InternString("NotAttempted"); + const int requested_id = builder.InternString("Requested"); + const int required_id = builder.InternString("Required"); + const int guarded_id = builder.InternString("Guarded"); + + perftools::profiles::Label& guarded_status_label = *sample.add_label(); + guarded_status_label.set_key(guarded_status_id); + switch (entry.guarded_status) { + case Profile::Sample::GuardedStatus::LargerThanOnePage: + guarded_status_label.set_str(larger_than_one_page_id); + break; + case Profile::Sample::GuardedStatus::Disabled: + guarded_status_label.set_str(disabled_id); + break; + case Profile::Sample::GuardedStatus::RateLimited: + guarded_status_label.set_str(rate_limited_id); + break; + case Profile::Sample::GuardedStatus::TooSmall: + guarded_status_label.set_str(too_small_id); + break; + case Profile::Sample::GuardedStatus::NoAvailableSlots: + guarded_status_label.set_str(no_available_slots_id); + break; + case Profile::Sample::GuardedStatus::MProtectFailed: + guarded_status_label.set_str(m_protect_failed_id); + break; + case Profile::Sample::GuardedStatus::Filtered: + guarded_status_label.set_str(filtered_id); + break; + case Profile::Sample::GuardedStatus::Unknown: + guarded_status_label.set_str(unknown_id); + break; + case Profile::Sample::GuardedStatus::NotAttempted: + guarded_status_label.set_str(not_attempted_id); + break; + case Profile::Sample::GuardedStatus::Requested: + guarded_status_label.set_str(requested_id); + break; + case Profile::Sample::GuardedStatus::Required: + guarded_status_label.set_str(required_id); + break; + case Profile::Sample::GuardedStatus::Guarded: + guarded_status_label.set_str(guarded_id); + break; + } + } + + return std::move(builder).Finalize(); +} + +absl::Status ProfileBuilder::SetDocURL(absl::string_view url) { + if (!url.empty() && !absl::StartsWith(url, "http://") && + !absl::StartsWith(url, "https://")) { + return absl::InternalError( + absl::StrCat("setting invalid profile doc URL '", url, "'")); + } + profile_->set_doc_url(InternString(url)); + return absl::OkStatus(); +} + +absl::StatusOr> MakeProfileProto( + const ::tcmalloc::Profile& profile) { + // Used to populate residency info in heap profile. + std::optional pageflags; + std::optional residency; + + PageFlags* p = nullptr; + Residency* r = nullptr; + + if (profile.Type() == ProfileType::kHeap) { + p = &pageflags.emplace(); + r = &residency.emplace(); + } + + return MakeProfileProto(profile, p, r); +} + +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder.h b/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder.h new file mode 100644 index 000000000000..c52843361d1c --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder.h @@ -0,0 +1,102 @@ +#pragma clang system_header +// Copyright 2021 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_INTERNAL_PROFILE_BUILDER_H_ +#define TCMALLOC_INTERNAL_PROFILE_BUILDER_H_ + +#if defined(__linux__) +#include +#include +#endif // defined(__linux__) + +#include +#include +#include + +// #include "tcmalloc/internal/profile.pb.h" +#include "absl/container/btree_map.h" +#include "absl/container/flat_hash_map.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "absl/types/span.h" +#include "tcmalloc/malloc_extension.h" + +namespace tcmalloc { +namespace tcmalloc_internal { + +#if defined(__linux__) +std::string GetBuildId(const dl_phdr_info* info); +#endif // defined(__linux__) + +// ProfileBuilder manages building up a profile.proto instance and populating +// common parts using the string/pointer table conventions expected by pprof. +class ProfileBuilder { + public: + ProfileBuilder(); + + perftools::profiles::Profile& profile() { return *profile_; } + + // Adds the current process mappings to the profile. + void AddCurrentMappings(); + + // Adds a single mapping to the profile and to lookup cache and returns the + // resulting ID. + int AddMapping(uintptr_t memory_start, uintptr_t memory_limit, + uintptr_t file_offset, absl::string_view filename, + absl::string_view build_id); + + // Add documentation URL. + absl::Status SetDocURL(absl::string_view url); + + // Interns sv in the profile's string table and returns the resulting ID. + int InternString(absl::string_view sv); + // Interns a location in the profile's location table and returns the + // resulting ID. + int InternLocation(const void* ptr); + + // Interns a callstack and adds the IDs to the provided sample. + void InternCallstack(absl::Span stack, + perftools::profiles::Sample& sample); + + std::unique_ptr Finalize() &&; + + private: + std::unique_ptr profile_; + // mappings_ stores the start address of each mapping in profile_->mapping() + // to its index. + absl::btree_map mappings_; + absl::flat_hash_map strings_; + absl::flat_hash_map locations_; +}; + +extern const absl::string_view kProfileDropFrames; + +absl::StatusOr> MakeProfileProto( + const ::tcmalloc::Profile& profile); + +class PageFlagsBase; +class PageFlags; +class Residency; + +// Exposed to facilitate testing. +absl::StatusOr> MakeProfileProto( + const ::tcmalloc::Profile& profile, PageFlagsBase* pageflags, + Residency* residency); + +} // namespace tcmalloc_internal +} // namespace tcmalloc + +#endif // TCMALLOC_INTERNAL_PROFILE_BUILDER_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder_fuzz.cc b/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder_fuzz.cc new file mode 100644 index 000000000000..a33200cbc158 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder_fuzz.cc @@ -0,0 +1,54 @@ +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/profile_builder.h" + +#if defined(__linux__) +#include +#include +#endif // defined(__linux__) + +#include + +#include "fuzztest/fuzztest.h" + +namespace tcmalloc::tcmalloc_internal { +namespace { + +void ParseBuildID(const std::string& s) { + const char* data = s.data(); + size_t size = s.size(); +#if defined(__linux__) + ElfW(Phdr) note; + note.p_type = PT_NOTE; + note.p_vaddr = reinterpret_cast(nullptr); + note.p_filesz = size; + note.p_memsz = size; + note.p_align = 4; + + dl_phdr_info info = {}; + info.dlpi_name = "test"; + info.dlpi_addr = reinterpret_cast(data); + info.dlpi_phdr = ¬e; + info.dlpi_phnum = 1; + + GetBuildId(&info); +#endif // defined(__linux__) +} + +FUZZ_TEST(ProfileBuilderTest, ParseBuildID) + ; + +} // namespace +} // namespace tcmalloc::tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder_no_tcmalloc_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder_no_tcmalloc_test.cc new file mode 100644 index 000000000000..a8ef13b04ae2 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder_no_tcmalloc_test.cc @@ -0,0 +1,46 @@ +// Copyright 2024 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/status/status.h" +#include "absl/status/status_matchers.h" +#include "tcmalloc/internal/profile_builder.h" +#include "tcmalloc/malloc_extension.h" + +namespace tcmalloc { +namespace tcmalloc_internal { +namespace { + +using ::absl_testing::StatusIs; +using ::testing::HasSubstr; + +TEST(ProfileBuilderNoTCMallocTest, StatusErrorTest) { + auto profile_st = + MakeProfileProto(MallocExtension::SnapshotCurrent(ProfileType::kHeap)); +#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ + defined(ABSL_HAVE_LEAK_SANITIZER) || \ + defined(ABSL_HAVE_MEMORY_SANITIZER) || defined(ABSL_HAVE_THREAD_SANITIZER) + EXPECT_THAT(profile_st, + StatusIs(absl::StatusCode::kUnimplemented, + HasSubstr("Program was built with sanitizers enabled"))); +#else + EXPECT_THAT(profile_st, StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Empty heap profile"))); +#endif +} + +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder_test.cc new file mode 100644 index 000000000000..a69b2151aa62 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/profile_builder_test.cc @@ -0,0 +1,1031 @@ +// Copyright 2021 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/profile_builder.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tcmalloc/internal/profile.pb.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/base/casts.h" +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" +#include "absl/log/check.h" +#include "absl/meta/type_traits.h" +#include "absl/status/statusor.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "tcmalloc/internal/environment.h" +#include "tcmalloc/internal/fake_profile.h" +#include "tcmalloc/internal/page_size.h" +#include "tcmalloc/internal/pageflags.h" +#include "tcmalloc/internal/residency.h" +#include "tcmalloc/internal_malloc_extension.h" +#include "tcmalloc/malloc_extension.h" + +namespace tcmalloc { +namespace tcmalloc_internal { +namespace { + +using ::testing::AnyOf; +using ::testing::Each; +using ::testing::IsSupersetOf; +using ::testing::Key; +using ::testing::Not; +using ::testing::Pair; +using ::testing::SizeIs; +using ::testing::UnorderedElementsAre; + +class StubPageFlags final : public PageFlagsBase { + public: + StubPageFlags() = default; + ~StubPageFlags() override = default; + std::optional Get(const void* addr, size_t size) override { + PageStats ret; + uintptr_t uaddr = reinterpret_cast(addr); + if (stale_bytes_.find(uaddr) != stale_bytes_.end()) { + ret.bytes_stale = stale_bytes_[uaddr]; + } + if (locked_bytes_.find(uaddr) != locked_bytes_.end()) { + ret.bytes_locked = locked_bytes_[uaddr]; + } + ret.stale_scan_seconds = stale_scan_period_; + return ret; + } + + void set_bytes_stale(const void* addr, int stale) { + uintptr_t uaddr = reinterpret_cast(addr); + stale_bytes_[uaddr] = stale; + } + + void set_bytes_locked(const void* addr, int locked) { + uintptr_t uaddr = reinterpret_cast(addr); + locked_bytes_[uaddr] = locked; + } + + void set_stale_scan_period(const void* addr, uint64_t seconds_stale) { + stale_scan_period_ = seconds_stale; + } + + private: + absl::flat_hash_map stale_bytes_; + absl::flat_hash_map locked_bytes_; + uint64_t stale_scan_period_; +}; + +// Returns the fully resolved path of this program. +std::string RealPath() { + char path[PATH_MAX]; + if (realpath("/proc/self/exe", path)) { + return path; + } + return ""; +} + +TEST(ProfileBuilderTest, Mappings) { + ProfileBuilder builder; + builder.AddCurrentMappings(); + auto profile = std::move(builder).Finalize(); + + absl::flat_hash_set filenames; + absl::flat_hash_set mapping_ids; + for (const auto& mapping : profile->mapping()) { + const int filename_id = mapping.filename(); + ASSERT_GE(filename_id, 0); + ASSERT_LT(filename_id, profile->string_table_size()); + + const absl::string_view filename = profile->string_table(filename_id); + filenames.emplace(filename); + mapping_ids.insert(mapping.id()); + } + + // Check for duplicates in mapping IDs. + EXPECT_EQ(mapping_ids.size(), profile->mapping_size()); + EXPECT_THAT(filenames, testing::Contains(RealPath())); + + // Ensure that no mapping ID is ID "0". + EXPECT_THAT(mapping_ids, Not(testing::Contains(0))); +} + +TEST(ProfileBuilderTest, LocationTableNoMappings) { + const uintptr_t kAddress = uintptr_t{0x150}; + + ProfileBuilder builder; + const int loc1 = + builder.InternLocation(absl::bit_cast(kAddress)); + auto profile = std::move(builder).Finalize(); + + // There should be no mappings. + EXPECT_TRUE(profile->mapping().empty()); + + // There should be 1 location. + ASSERT_EQ(profile->location().size(), 1); + const auto& location = profile->location(0); + EXPECT_EQ(location.id(), loc1); + EXPECT_EQ(location.mapping_id(), 0); + EXPECT_EQ(location.address(), kAddress); +} + +TEST(ProfileBuilderTest, DocURL) { + // Try good and bad URLs. + constexpr absl::string_view good1 = "http://example.com/foo"; + constexpr absl::string_view good2 = "https://example.com/foo"; + constexpr absl::string_view good3 = ""; + constexpr absl::string_view bad = "example.com/foo"; + for (absl::string_view url : {good1, good2, good3, bad}) { + ProfileBuilder b; + absl::Status error = b.SetDocURL(url); + if (url == bad) { + EXPECT_FALSE(error.ok()) << url; + } else { + EXPECT_TRUE(error.ok()) << url; + } + } +} + +TEST(ProfileBuilderTest, LocationTable) { + ProfileBuilder builder; + + // Verify we add mapping information to locations correctly. + builder.AddMapping(uintptr_t{0x200}, uintptr_t{0x300}, uintptr_t{0x123}, + "foo.so", "abababab"); + + // loc1/loc3 should lack mappings, loc2 should have a mapping. + const int loc1 = + builder.InternLocation(absl::bit_cast(uintptr_t{0x150})); + const int loc2 = + builder.InternLocation(absl::bit_cast(uintptr_t{0x250})); + const int loc3 = + builder.InternLocation(absl::bit_cast(uintptr_t{0x350})); + + auto profile = std::move(builder).Finalize(); + + // There should be one mapping. + ASSERT_EQ(profile->mapping().size(), 1); + const auto mapping = profile->mapping(0); + EXPECT_EQ(mapping.memory_start(), 0x200); + EXPECT_EQ(mapping.memory_limit(), 0x300); + EXPECT_EQ(mapping.file_offset(), 0x123); + EXPECT_EQ(profile->string_table(mapping.filename()), "foo.so"); + EXPECT_EQ(profile->string_table(mapping.build_id()), "abababab"); + + struct SimpleLocation { + uint64_t id; + uint64_t mapping_id; + uint64_t address; + + bool operator==(const SimpleLocation& rhs) const { + return std::tie(id, mapping_id, address) == + std::tie(rhs.id, rhs.mapping_id, rhs.address); + } + }; + std::vector actual; + for (auto location : profile->location()) { + SimpleLocation& l = actual.emplace_back(); + l.id = location.id(); + l.mapping_id = location.mapping_id(); + l.address = location.address(); + } + std::vector expected = { + {static_cast(loc1), 0, 0x150}, + {static_cast(loc2), mapping.id(), 0x250}, + {static_cast(loc3), 0, 0x350}, + }; + + EXPECT_THAT(actual, testing::UnorderedElementsAreArray(expected)); +} + +TEST(ProfileBuilderTest, StringTable) { + auto profile = ProfileBuilder().Finalize(); + + ASSERT_FALSE(profile->string_table().empty()); + // The first entry should be the empty string. + EXPECT_EQ(profile->string_table(0), ""); + + // There should be no duplicates. + absl::flat_hash_set strings; + strings.reserve(profile->string_table_size()); + strings.insert(profile->string_table().begin(), + profile->string_table().end()); + EXPECT_EQ(strings.size(), profile->string_table_size()); +} + +// A helper type alias for a list of samples and their labels. +using SampleLabels = std::vector< + std::vector>>>; + +void CheckAndExtractSampleLabels(const perftools::profiles::Profile& converted, + SampleLabels& extracted) { + // Strings + ASSERT_FALSE(converted.string_table().empty()); + + // Mappings: Build a lookup table from mapping ID to index in mapping array. + ASSERT_FALSE(converted.mapping().empty()); + absl::flat_hash_map mappings; + for (int i = 0, n = converted.mapping().size(); i < n; i++) { + mappings.emplace(converted.mapping(i).id(), i); + } + + // Locations + ASSERT_FALSE(converted.location().empty()); + absl::flat_hash_map addresses; + absl::flat_hash_set interned_addresses; + int location_with_mapping_found = 0; + for (const auto& location : converted.location()) { + uintptr_t address = location.address(); + if (location.mapping_id() > 0) { + ASSERT_THAT( + mappings, + testing::Contains(testing::Key(testing::Eq(location.mapping_id())))); + const int mapping_index = mappings.at(location.mapping_id()); + ASSERT_LT(mapping_index, converted.mapping_size()); + const auto& mapping = converted.mapping(mapping_index); + + location_with_mapping_found++; + + // Confirm address actually falls within [mapping.memory_start(), + // mapping.memory_limit()). + EXPECT_LE(mapping.memory_start(), address); + EXPECT_LT(address, mapping.memory_limit()); + } + + EXPECT_TRUE(interned_addresses.insert(location.id()).second) + << "Duplicate interned location ID found"; + } + // Expect that we find at least 2 locations with a mapping. + EXPECT_GE(location_with_mapping_found, 2); + // Expect that no location has ID "0." + EXPECT_THAT(interned_addresses, Not(testing::Contains(0))); + + // Samples + for (const auto& s : converted.sample()) { + EXPECT_FALSE(s.location_id().empty()); + // No duplicates + EXPECT_THAT( + absl::flat_hash_set(s.location_id().begin(), s.location_id().end()) + .size(), + s.location_id().size()); + // Interned locations should appear in the location list. + EXPECT_THAT(s.location_id(), testing::IsSubsetOf(interned_addresses)); + + EXPECT_EQ(converted.sample_type().size(), s.value().size()); + extracted.emplace_back(); + auto& labels = extracted.back(); + for (const auto& l : s.label()) { + if (l.str() != 0) { + labels.emplace_back(converted.string_table(l.key()), + converted.string_table(l.str())); + } else { + labels.emplace_back(converted.string_table(l.key()), + static_cast(l.num())); + } + } + } +} + +perftools::profiles::Profile MakeTestProfile( + std::optional start_time, const absl::Duration duration, + const ProfileType profile_type) { + std::vector samples; + StubPageFlags* p = nullptr; + Residency* r = nullptr; + std::optional pageflags; + std::optional residency; + if (profile_type == ProfileType::kHeap) { + p = &pageflags.emplace(); + r = &residency.emplace(); + } + + { // We have three samples here that will be merged. The second sample has + // `span_start_address` as nullptr, so `resident_space` in the + // profile is contributed by the other two samples. + Profile::Sample sample; + + sample.sum = 1234; + sample.count = 2; + sample.requested_size = 2; + sample.requested_alignment = 4; + sample.requested_size_returning = true; + sample.allocated_size = 16; + + std::vector bytes(sample.allocated_size); + sample.span_start_address = bytes.data(); + + // This stack is mostly artificial, but we include a real symbol from the + // binary to confirm that at least one location was indexed into its + // mapping. + sample.depth = 5; + sample.stack[0] = absl::bit_cast(uintptr_t{0x12345}); + sample.stack[1] = absl::bit_cast(uintptr_t{0x23451}); + sample.stack[2] = absl::bit_cast(uintptr_t{0x34512}); + sample.stack[3] = absl::bit_cast(uintptr_t{0x45123}); + sample.stack[4] = reinterpret_cast(&ProfileAccessor::MakeProfile); + sample.access_hint = hot_cold_t{254}; + sample.access_allocated = Profile::Sample::Access::Cold; + sample.type = Profile::Sample::AllocationType::New; + samples.push_back(sample); + + Profile::Sample sample2 = sample; + sample2.span_start_address = nullptr; + samples.push_back(sample2); + + Profile::Sample sample3 = sample; + sample3.span_start_address = bytes.data(); + samples.push_back(sample3); + } + + { + // We have two samples here. For the second sample, we remove the mappings + // for the page starting at the pointer, so no resident info is available + // for the sample. + Profile::Sample sample; + + size_t kSize = GetPageSize(); + void* ptr1 = mmap(nullptr, kSize, PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_LOCKED, -1, 0); + CHECK_NE(ptr1, MAP_FAILED) << errno; + void* ptr2 = mmap(nullptr, kSize, PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_PRIVATE | MAP_LOCKED, -1, 0); + CHECK_NE(ptr2, MAP_FAILED) << errno; + CHECK_EQ(munmap(ptr2, kSize), 0) << errno; + + sample.sum = 2345; + sample.count = 5; + sample.requested_size = 4; + sample.requested_alignment = 0; + sample.requested_size_returning = false; + sample.allocated_size = 8; + sample.span_start_address = ptr1; + + // This stack is mostly artificial, but we include a real symbol from the + // binary to confirm that at least one location was indexed into its + // mapping. + sample.depth = 4; + sample.stack[0] = absl::bit_cast(uintptr_t{0x12345}); + sample.stack[1] = absl::bit_cast(uintptr_t{0x23451}); + sample.stack[2] = absl::bit_cast(uintptr_t{0x45123}); + sample.stack[3] = reinterpret_cast(&RealPath); + sample.access_hint = hot_cold_t{1}; + sample.access_allocated = Profile::Sample::Access::Hot; + sample.type = Profile::Sample::AllocationType::Malloc; + + if (profile_type == ProfileType::kHeap) { + // Total stale bytes for this sample = 5 * 17 = 85. + // Total locked bytes for this sample = 5 * 11 = 55. + p->set_bytes_stale(sample.span_start_address, /*stale=*/17); + p->set_bytes_locked(sample.span_start_address, /*locked=*/11); + p->set_stale_scan_period(sample.span_start_address, + /*seconds_stale=*/10); + } + + samples.push_back(sample); + + Profile::Sample sample2 = sample; + sample2.span_start_address = ptr2; + samples.push_back(sample2); + } + + { + // This sample does not set `span_start_address`, so `resident_space` + // is 0. + auto& sample = samples.emplace_back(); + + sample.sum = 2345; + sample.count = 8; + sample.requested_size = 16; + sample.requested_alignment = 0; + sample.requested_size_returning = true; + sample.allocated_size = 16; + // This stack is mostly artificial, but we include a real symbol from the + // binary to confirm that at least one location was indexed into its + // mapping. + sample.depth = 3; + sample.stack[0] = absl::bit_cast(uintptr_t{0x12345}); + sample.stack[1] = absl::bit_cast(uintptr_t{0x23451}); + sample.stack[2] = reinterpret_cast(&RealPath); + sample.access_hint = hot_cold_t{0}; + sample.access_allocated = Profile::Sample::Access::Hot; + sample.type = Profile::Sample::AllocationType::AlignedMalloc; + } + + { // We have three samples here that will be merged (if guarded_status is not + // considered). The second and third samples have different + // guarded_status-es. + Profile::Sample sample; + + sample.sum = 1235; + sample.count = 2; + sample.requested_size = 2; + sample.requested_alignment = 4; + sample.requested_size_returning = true; + sample.allocated_size = 16; + + std::vector bytes(sample.allocated_size); + sample.span_start_address = bytes.data(); + + // This stack is mostly artificial, but we include a real symbol from the + // binary to confirm that at least one location was indexed into its + // mapping. + sample.depth = 5; + sample.stack[0] = absl::bit_cast(uintptr_t{0x12345}); + sample.stack[1] = absl::bit_cast(uintptr_t{0x23451}); + sample.stack[2] = absl::bit_cast(uintptr_t{0x34512}); + sample.stack[3] = absl::bit_cast(uintptr_t{0x45123}); + sample.stack[4] = reinterpret_cast(&ProfileAccessor::MakeProfile); + sample.access_hint = hot_cold_t{253}; + sample.access_allocated = Profile::Sample::Access::Cold; + sample.guarded_status = Profile::Sample::GuardedStatus::RateLimited; + sample.type = Profile::Sample::AllocationType::New; + samples.push_back(sample); + + Profile::Sample sample2 = sample; + sample2.guarded_status = Profile::Sample::GuardedStatus::Filtered; + samples.push_back(sample2); + + Profile::Sample sample3 = sample; + sample3.guarded_status = Profile::Sample::GuardedStatus::Guarded; + samples.push_back(sample3); + } + auto fake_profile = std::make_unique(); + fake_profile->SetType(profile_type); + fake_profile->SetDuration(duration); + fake_profile->SetStartTime(start_time); + fake_profile->SetSamples(std::move(samples)); + Profile profile = ProfileAccessor::MakeProfile(std::move(fake_profile)); + auto converted_or = MakeProfileProto(profile, p, r); + CHECK_OK(converted_or.status()); + return **converted_or; +} + +TEST(ProfileConverterTest, NonHeapProfileDoesntHaveResidency) { + const absl::Time start_time = absl::Now(); + constexpr absl::Duration kDuration = absl::Milliseconds(1500); + const auto& converted = + MakeTestProfile(start_time, kDuration, ProfileType::kPeakHeap); + + // Two sample types: [objects, count] and [space, bytes] + std::vector> extracted_sample_type; + absl::flat_hash_set sample_types; + for (const auto& s : converted.sample_type()) { + auto& labels = extracted_sample_type.emplace_back(); + labels.first = converted.string_table(s.type()); + labels.second = converted.string_table(s.unit()); + + ASSERT_TRUE(sample_types.insert(s.type()).second) + << "Duplicate sample type #" << s.type() << ": " + << converted.string_table(s.type()); + } + // Require that the default_sample_type appeared in sample_type. + EXPECT_THAT(sample_types, testing::Contains(converted.default_sample_type())); + EXPECT_THAT( + extracted_sample_type, + UnorderedElementsAre(Pair("objects", "count"), Pair("space", "bytes"))); + EXPECT_EQ(converted.time_nanos(), absl::ToUnixNanos(start_time)); + + absl::flat_hash_map label_to_units; + for (const auto& s : converted.sample()) { + for (const auto& l : s.label()) { + if (l.num_unit() != 0) { + const std::string unit = converted.string_table(l.num_unit()); + auto it = label_to_units.insert({converted.string_table(l.key()), unit}) + .first; + // We expect units to be consistent for the same key, across samples. + EXPECT_EQ(it->second, unit); + } + } + } + + EXPECT_THAT( + label_to_units, + Each(Key(Not(AnyOf("sampled_resident_bytes", + "swapped_bytes"))))); +} + +TEST(ProfileConverterTest, HeapProfile) { + constexpr absl::Duration kDuration = absl::Milliseconds(1500); + const auto& converted = + MakeTestProfile(std::nullopt, kDuration, ProfileType::kHeap); + + // Two sample types: [objects, count] and [space, bytes] + std::vector> extracted_sample_type; + absl::flat_hash_set sample_types; + for (const auto& s : converted.sample_type()) { + auto& labels = extracted_sample_type.emplace_back(); + labels.first = converted.string_table(s.type()); + labels.second = converted.string_table(s.unit()); + + ASSERT_TRUE(sample_types.insert(s.type()).second) + << "Duplicate sample type #" << s.type() << ": " + << converted.string_table(s.type()); + } + // Require that the default_sample_type appeared in sample_type. + EXPECT_THAT(sample_types, testing::Contains(converted.default_sample_type())); + + constexpr int kNumSamples = 6; + // This is slightly redundant with the next line, but we need to loop over + // each of the samples later. + EXPECT_THAT(extracted_sample_type, SizeIs(kNumSamples)); + EXPECT_THAT( + extracted_sample_type, + UnorderedElementsAre( + Pair("objects", "count"), Pair("space", "bytes"), + Pair("resident_space", "bytes"), Pair("stale_space", "bytes"), + Pair("locked_space", "bytes"), Pair("swapped_space", "bytes"))); + + SampleLabels extracted_labels; + { + SCOPED_TRACE("Profile"); + ASSERT_NO_FATAL_FAILURE( + CheckAndExtractSampleLabels(converted, extracted_labels)); + } + + absl::flat_hash_map label_to_units; + std::vector> extracted_samples; + for (const auto& s : converted.sample()) { + extracted_samples.emplace_back(); + for (const auto& l : s.label()) { + if (l.num_unit() != 0) { + const std::string unit = converted.string_table(l.num_unit()); + auto it = label_to_units.insert({converted.string_table(l.key()), unit}) + .first; + // We expect units to be consistent for the same key, across samples. + EXPECT_EQ(it->second, unit); + } + } + ASSERT_EQ(s.value_size(), converted.sample_type_size()); + for (int i = 0; i < s.value_size(); ++i) { + extracted_samples.back().emplace( + converted.string_table(converted.sample_type(i).type()), s.value(i)); + } + } + + EXPECT_THAT(label_to_units, + IsSupersetOf({Pair("bytes", "bytes"), Pair("request", "bytes"), + Pair("alignment", "bytes"), + Pair("access_hint", "access_hint")})); + + EXPECT_THAT( + label_to_units, + Each(Key(Not(AnyOf("sampled_resident_bytes", + "swapped_bytes"))))); + + EXPECT_THAT( + extracted_labels, + UnorderedElementsAre( + UnorderedElementsAre( + Pair("bytes", 16), Pair("request", 2), Pair("alignment", 4), + Pair("stale_scan_period", 10), + Pair("access_hint", 254), Pair("access_allocated", "cold"), + Pair("size_returning", 1), Pair("guarded_status", "Unknown"), + Pair("allocation type", "new")), + UnorderedElementsAre(Pair("bytes", 8), Pair("request", 4), + Pair("stale_scan_period", 10), + Pair("access_hint", 1), + Pair("access_allocated", "hot"), + Pair("guarded_status", "Unknown"), + Pair("allocation type", "malloc")), + UnorderedElementsAre( + Pair("bytes", 16), Pair("request", 16), + Pair("stale_scan_period", 10), + Pair("access_hint", 0), Pair("access_allocated", "hot"), + Pair("size_returning", 1), Pair("guarded_status", "Unknown"), + Pair("allocation type", "aligned malloc")), + UnorderedElementsAre( + Pair("bytes", 16), Pair("request", 2), Pair("alignment", 4), + Pair("stale_scan_period", 10), + Pair("access_hint", 253), Pair("access_allocated", "cold"), + Pair("size_returning", 1), Pair("guarded_status", "RateLimited"), + Pair("allocation type", "new")), + UnorderedElementsAre( + Pair("bytes", 16), Pair("request", 2), Pair("alignment", 4), + Pair("stale_scan_period", 10), + Pair("access_hint", 253), Pair("access_allocated", "cold"), + Pair("size_returning", 1), Pair("guarded_status", "Filtered"), + Pair("allocation type", "new")), + UnorderedElementsAre( + Pair("bytes", 16), Pair("request", 2), Pair("alignment", 4), + Pair("stale_scan_period", 10), + Pair("access_hint", 253), Pair("access_allocated", "cold"), + Pair("size_returning", 1), Pair("guarded_status", "Guarded"), + Pair("allocation type", "new")))); + + EXPECT_THAT(extracted_samples, + UnorderedElementsAre(IsSupersetOf({ + Pair("resident_space", 64), + Pair("swapped_space", 0), + Pair("space", 3702), + Pair("objects", 6), + }), + IsSupersetOf({ + Pair("resident_space", 40), + Pair("swapped_space", 0), + Pair("space", 4690), + Pair("objects", 10), + }), + IsSupersetOf({ + Pair("resident_space", 0), + Pair("swapped_space", 0), + Pair("space", 2345), + Pair("objects", 8), + }), + IsSupersetOf({ + Pair("resident_space", 32), + Pair("swapped_space", 0), + Pair("space", 1235), + Pair("objects", 2), + }), + IsSupersetOf({ + Pair("resident_space", 32), + Pair("swapped_space", 0), + Pair("space", 1235), + Pair("objects", 2), + }), + IsSupersetOf({ + Pair("resident_space", 32), + Pair("swapped_space", 0), + Pair("space", 1235), + Pair("objects", 2), + }))); + + ASSERT_EQ(converted.sample().size(), kNumSamples); + // The addresses for the samples at stack[0], stack[1] should match. + for (int i = 0; i < kNumSamples; ++i) { + ASSERT_GE(converted.sample(i).location_id().size(), 2) << i; + if (i > 0) { + EXPECT_EQ(converted.sample(i - 1).location_id(0), + converted.sample(i).location_id(0)) + << i; + EXPECT_EQ(converted.sample(i - 1).location_id(1), + converted.sample(i).location_id(1)) + << i; + } + } + + EXPECT_THAT(converted.string_table(converted.drop_frames()), + testing::HasSubstr("TCMallocInternalNew")); + // No keep frames. + EXPECT_EQ(converted.string_table(converted.keep_frames()), ""); + + EXPECT_EQ(converted.duration_nanos(), absl::ToInt64Nanoseconds(kDuration)); + EXPECT_EQ(converted.time_nanos(), 0); + + // Period type [space, bytes] + EXPECT_EQ(converted.string_table(converted.period_type().type()), "space"); + EXPECT_EQ(converted.string_table(converted.period_type().unit()), "bytes"); + + // Period not set + EXPECT_EQ(converted.period(), 0); +} + +// This test is to check that profile of type other than `kHeap` should not have +// residency info available, even if samples' `span_start_address` is not null. +TEST(ProfileBuilderTest, PeakHeapProfile) { + const absl::Time start_time = absl::Now(); + constexpr absl::Duration kDuration = absl::Milliseconds(1500); + auto fake_profile = std::make_unique(); + fake_profile->SetType(ProfileType::kPeakHeap); + fake_profile->SetDuration(kDuration); + fake_profile->SetStartTime(start_time); + + std::vector samples; + + { + auto& sample = samples.emplace_back(); + sample.sum = 1234; + sample.count = 2; + sample.requested_size = 2; + sample.requested_alignment = 4; + sample.requested_size_returning = true; + sample.allocated_size = 16; + + std::vector bytes(sample.allocated_size); + sample.span_start_address = bytes.data(); + + sample.depth = 3; + sample.stack[0] = absl::bit_cast(uintptr_t{0x12345}); + sample.stack[1] = absl::bit_cast(uintptr_t{0x45123}); + sample.stack[2] = reinterpret_cast(&ProfileAccessor::MakeProfile); + sample.access_hint = hot_cold_t{254}; + sample.access_allocated = Profile::Sample::Access::Cold; + } + + { + auto& sample = samples.emplace_back(); + sample.sum = 2345; + sample.count = 5; + sample.requested_size = 4; + sample.requested_alignment = 0; + sample.requested_size_returning = false; + sample.allocated_size = 8; + + std::vector bytes(sample.allocated_size); + sample.span_start_address = bytes.data(); + + sample.depth = 2; + sample.stack[0] = absl::bit_cast(uintptr_t{0x12345}); + sample.stack[1] = reinterpret_cast(&RealPath); + sample.access_hint = hot_cold_t{1}; + sample.access_allocated = Profile::Sample::Access::Hot; + } + + fake_profile->SetSamples(std::move(samples)); + Profile profile = ProfileAccessor::MakeProfile(std::move(fake_profile)); + auto converted_or = MakeProfileProto(profile); + ASSERT_TRUE(converted_or.ok()); + const auto& converted = **converted_or; + + SampleLabels extracted; + { + SCOPED_TRACE("Profile"); + ASSERT_NO_FATAL_FAILURE(CheckAndExtractSampleLabels(converted, extracted)); + } + + EXPECT_THAT( + extracted, + UnorderedElementsAre( + UnorderedElementsAre( + Pair("bytes", 16), Pair("request", 2), Pair("alignment", 4), + Pair("access_hint", 254), Pair("access_allocated", "cold"), + Pair("size_returning", 1), Pair("guarded_status", "Unknown"), + Pair("allocation type", "new")), + UnorderedElementsAre(Pair("bytes", 8), Pair("request", 4), + Pair("access_hint", 1), + Pair("access_allocated", "hot"), + Pair("guarded_status", "Unknown"), + Pair("allocation type", "new")))); + + ASSERT_GE(converted.sample().size(), 2); + ASSERT_GE(converted.sample(0).location_id().size(), 2); + ASSERT_GE(converted.sample(1).location_id().size(), 2); + EXPECT_EQ(converted.sample(0).location_id(0), + converted.sample(1).location_id(0)); + + EXPECT_EQ(converted.time_nanos(), absl::ToUnixNanos(start_time)); +} + +TEST(ProfileBuilderTest, LifetimeProfile) { + const absl::Time start_time = absl::Now(); + constexpr absl::Duration kDuration = absl::Milliseconds(1500); + auto fake_profile = std::make_unique(); + fake_profile->SetType(ProfileType::kLifetimes); + fake_profile->SetDuration(kDuration); + fake_profile->SetStartTime(start_time); + + std::vector samples; + { + // The allocation sample. + Profile::Sample alloc1{ + .sum = 123, + .count = 2, + // Common information we retain in the lifetime profile. + .requested_size = 2, + .requested_alignment = 4, + .allocated_size = 16, + // Lifetime specific information in each sample. + .profile_id = 33, + .avg_lifetime = absl::Nanoseconds(77), + .stddev_lifetime = absl::Nanoseconds(22), + .min_lifetime = absl::Nanoseconds(55), + .max_lifetime = absl::Nanoseconds(99), + .allocator_deallocator_physical_cpu_matched = true, + .allocator_deallocator_virtual_cpu_matched = true, + .allocator_deallocator_l3_matched = true, + .allocator_deallocator_numa_matched = true, + .allocator_deallocator_thread_matched = false, + }; + // This stack is mostly artificial, but we include a couple of real symbols + // from the binary to confirm that the locations are indexed into the + // mappings. + alloc1.depth = 6; + alloc1.stack[0] = absl::bit_cast(uintptr_t{0x12345}); + alloc1.stack[1] = absl::bit_cast(uintptr_t{0x23451}); + alloc1.stack[2] = absl::bit_cast(uintptr_t{0x34512}); + alloc1.stack[3] = absl::bit_cast(uintptr_t{0x45123}); + alloc1.stack[4] = reinterpret_cast(&ProfileAccessor::MakeProfile); + alloc1.stack[5] = reinterpret_cast(&RealPath); + + samples.push_back(alloc1); + + // The deallocation sample contains the same information with a negative + // count to denote deallocaiton. The stack can be different, or empty if the + // deallocation has not been observed (once b/236755869 is implemented). + Profile::Sample dealloc1 = alloc1; + dealloc1.count = -dealloc1.count; + samples.push_back(dealloc1); + + // Also add a censored sample with a different profile id. + Profile::Sample censored_alloc1 = alloc1; + censored_alloc1.is_censored = true; + // The *_matched fields are unset for censored allocations since we did not + // observe the deallocation. + censored_alloc1.allocator_deallocator_physical_cpu_matched = std::nullopt; + censored_alloc1.allocator_deallocator_virtual_cpu_matched = std::nullopt; + censored_alloc1.allocator_deallocator_l3_matched = std::nullopt; + censored_alloc1.allocator_deallocator_numa_matched = std::nullopt; + censored_alloc1.allocator_deallocator_thread_matched = std::nullopt; + censored_alloc1.profile_id++; + samples.push_back(censored_alloc1); + } + + fake_profile->SetSamples(std::move(samples)); + Profile profile = ProfileAccessor::MakeProfile(std::move(fake_profile)); + auto converted_or = MakeProfileProto(profile); + ASSERT_TRUE(converted_or.ok()); + const perftools::profiles::Profile& converted = **converted_or; + const auto& string_table = converted.string_table(); + + // Checks for lifetime (deallocation) profile specific fields. + ASSERT_EQ(converted.sample_type_size(), 6); + EXPECT_EQ(string_table.at(converted.sample_type(0).type()), + "allocated_objects"); + EXPECT_EQ(string_table.at(converted.sample_type(1).type()), + "allocated_space"); + EXPECT_EQ(string_table.at(converted.sample_type(2).type()), + "deallocated_objects"); + EXPECT_EQ(string_table.at(converted.sample_type(3).type()), + "deallocated_space"); + EXPECT_EQ(string_table.at(converted.sample_type(4).type()), + "censored_allocated_objects"); + EXPECT_EQ(string_table.at(converted.sample_type(5).type()), + "censored_allocated_space"); + + ASSERT_EQ(converted.sample_size(), 3); + // For the alloc sample, the values are in indices 0, 1. + EXPECT_EQ(converted.sample(0).value(0), 2); + EXPECT_EQ(converted.sample(0).value(1), 123); + EXPECT_EQ(converted.sample(0).value(2), 0); + EXPECT_EQ(converted.sample(0).value(3), 0); + EXPECT_EQ(converted.sample(0).value(4), 0); + EXPECT_EQ(converted.sample(0).value(5), 0); + // For the dealloc sample, the values are in indices 2, 3. + EXPECT_EQ(converted.sample(1).value(0), 0); + EXPECT_EQ(converted.sample(1).value(1), 0); + EXPECT_EQ(converted.sample(1).value(2), 2); + EXPECT_EQ(converted.sample(1).value(3), 123); + EXPECT_EQ(converted.sample(1).value(4), 0); + EXPECT_EQ(converted.sample(1).value(5), 0); + // For the censored alloc sample, the values are in indices 4, 5. + EXPECT_EQ(converted.sample(2).value(0), 0); + EXPECT_EQ(converted.sample(2).value(1), 0); + EXPECT_EQ(converted.sample(2).value(2), 0); + EXPECT_EQ(converted.sample(2).value(3), 0); + EXPECT_EQ(converted.sample(2).value(4), 2); + EXPECT_EQ(converted.sample(2).value(5), 123); + + // Check the location and mapping fields and extract sample, label pairs. + SampleLabels extracted; + { + SCOPED_TRACE("LifetimeProfile"); + ASSERT_NO_FATAL_FAILURE(CheckAndExtractSampleLabels(converted, extracted)); + } + + // TODO(b/248332543): Reduce implementation duplication so that properties + // (allocation type) of the original allocation are captured without this + // duplication. + EXPECT_THAT( + extracted, + UnorderedElementsAre( + UnorderedElementsAre( + Pair("bytes", 16), Pair("request", 2), Pair("alignment", 4), + Pair("callstack-pair-id", 33), Pair("avg_lifetime", 77), + Pair("stddev_lifetime", 22), Pair("min_lifetime", 55), + Pair("max_lifetime", 99), + Pair("active CPU", "same"), Pair("active vCPU", "same"), + Pair("active L3", "same"), Pair("active NUMA", "same"), + Pair("active thread", "different")), + UnorderedElementsAre( + Pair("bytes", 16), Pair("request", 2), Pair("alignment", 4), + Pair("callstack-pair-id", 33), Pair("avg_lifetime", 77), + Pair("stddev_lifetime", 22), Pair("min_lifetime", 55), + Pair("max_lifetime", 99), + Pair("active CPU", "same"), Pair("active vCPU", "same"), + Pair("active L3", "same"), Pair("active NUMA", "same"), + Pair("active thread", "different")), + // Check the contents of the censored sample. + UnorderedElementsAre( + Pair("bytes", 16), Pair("request", 2), Pair("alignment", 4), + Pair("callstack-pair-id", 34), Pair("avg_lifetime", 77), + Pair("stddev_lifetime", 22), Pair("min_lifetime", 55), + Pair("max_lifetime", 99), + Pair("active CPU", "none"), Pair("active vCPU", "none"), + Pair("active L3", "none"), Pair("active NUMA", "none"), + Pair("active thread", "none")))); + + // Checks for common fields. + EXPECT_THAT(converted.string_table(converted.drop_frames()), + testing::HasSubstr("TCMallocInternalNew")); + // No keep frames. + EXPECT_EQ(converted.string_table(converted.keep_frames()), ""); + + EXPECT_EQ(converted.duration_nanos(), absl::ToInt64Nanoseconds(kDuration)); + EXPECT_EQ(converted.time_nanos(), absl::ToUnixNanos(start_time)); + + // Period type [space, bytes] + EXPECT_EQ(converted.string_table(converted.period_type().type()), "space"); + EXPECT_EQ(converted.string_table(converted.period_type().unit()), "bytes"); + + // Period not set + EXPECT_EQ(converted.period(), 0); +} + +TEST(BuildId, CorruptImage_b180635896) { + std::string image_path; + const char* srcdir = thread_safe_getenv("TEST_SRCDIR"); + if (srcdir) { + absl::StrAppend(&image_path, srcdir, "/"); + } + const char* workspace = thread_safe_getenv("TEST_WORKSPACE"); + if (workspace) { + absl::StrAppend(&image_path, workspace, "/"); + } + absl::StrAppend(&image_path, + "tcmalloc/internal/testdata/b180635896.so"); + + int fd = open(image_path.c_str(), O_RDONLY); + ASSERT_TRUE(fd != -1) << "open: " << errno << " " << image_path; + void* p = mmap(nullptr, /*size*/ 4096, PROT_READ, MAP_PRIVATE, fd, /*off*/ 0); + ASSERT_TRUE(p != MAP_FAILED) << "mmap: " << errno; + close(fd); + + const ElfW(Ehdr)* const ehdr = reinterpret_cast(p); + dl_phdr_info info = {}; + info.dlpi_name = image_path.c_str(); + info.dlpi_addr = reinterpret_cast(p); + info.dlpi_phdr = + reinterpret_cast(info.dlpi_addr + ehdr->e_phoff); + info.dlpi_phnum = ehdr->e_phnum; + + EXPECT_EQ(GetBuildId(&info), ""); + munmap(p, 4096); +} + +// There are two PT_NOTE segments, one with .note.gnu.property and the other +// with .note.gnu.build-id. Test that we correctly skip .note.gnu.property. +// +// .note.gnu.property intentionally contains two NT_GNU_PROPERTY_TYPE_0 notes +// to simulate outputs from old linkers (no NT_GNU_PROPERTY_TYPE_0 merging). +// Test that we correctly parse and skip the notes. +TEST(BuildId, GnuProperty) { + std::string image_path; + const char* srcdir = thread_safe_getenv("TEST_SRCDIR"); + if (srcdir) { + absl::StrAppend(&image_path, srcdir, "/"); + } + const char* workspace = thread_safe_getenv("TEST_WORKSPACE"); + if (workspace) { + absl::StrAppend(&image_path, workspace, "/"); + } + absl::StrAppend(&image_path, + "tcmalloc/internal/testdata/gnu-property.so"); + + int fd = open(image_path.c_str(), O_RDONLY); + ASSERT_TRUE(fd != -1) << "open: " << errno << " " << image_path; + void* p = mmap(nullptr, /*size*/ 4096, PROT_READ, MAP_PRIVATE, fd, /*off*/ 0); + ASSERT_TRUE(p != MAP_FAILED) << "mmap: " << errno; + close(fd); + + const ElfW(Ehdr)* const ehdr = reinterpret_cast(p); + dl_phdr_info info = {}; + info.dlpi_name = image_path.c_str(); + info.dlpi_addr = reinterpret_cast(p); + info.dlpi_phdr = + reinterpret_cast(info.dlpi_addr + ehdr->e_phoff); + info.dlpi_phnum = ehdr->e_phnum; + + EXPECT_EQ(GetBuildId(&info), "1f2a67344247b1cb91260e53c03817f9"); + munmap(p, 4096); +} + +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/range_tracker.h b/contrib/libs/tcmalloc/tcmalloc/internal/range_tracker.h index 25b863934f7d..f1bb01153050 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/range_tracker.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/range_tracker.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,11 +20,12 @@ #include #include -#include +#include #include #include #include "absl/numeric/bits.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/logging.h" #include "tcmalloc/internal/optimization.h" @@ -45,6 +47,8 @@ class Bitmap { // Returns the number of set bits [index, ..., index + n - 1]. size_t CountBits(size_t index, size_t n) const; + // Returns the total number of set bits. + size_t CountBits() const; // Returns whether the bitmap is entirely zero or not. bool IsZero() const; @@ -58,7 +62,7 @@ class Bitmap { // If there is at least one free range at or after , // put it in *index, *length and return true; else return false. - bool NextFreeRange(size_t start, size_t *index, size_t *length) const; + bool NextFreeRange(size_t start, size_t* index, size_t* length) const; // Returns index of the first {true, false} bit >= index, or N if none. size_t FindSet(size_t index) const; @@ -102,26 +106,28 @@ class RangeTracker { size_t size() const; // Number of bits marked size_t used() const; - // Number of bits clear - size_t total_free() const; // Longest contiguous range of clear bits. size_t longest_free() const; // Count of live allocations. size_t allocs() const; // REQUIRES: there is a free range of at least n bits - // (i.e. n <= longest_free()) - // finds and marks n free bits, returning index of the first bit. - // Chooses by best fit. + // (i.e. n <= longest_free()). + // + // Finds and marks n free bits, returning index of the first bit. Chooses by + // best fit. size_t FindAndMark(size_t n); + // REQUIRES: the range [index, index + n) is fully unmarked. + void Mark(size_t index, size_t n); + // REQUIRES: the range [index, index + n) is fully marked, and // was the returned value from a call to FindAndMark. // Unmarks it. void Unmark(size_t index, size_t n); // If there is at least one free range at or after , // put it in *index, *length and return true; else return false. - bool NextFreeRange(size_t start, size_t *index, size_t *length) const; + bool NextFreeRange(size_t start, size_t* index, size_t* length) const; void Clear(); @@ -174,11 +180,6 @@ inline size_t RangeTracker::used() const { return nused_; } -template -inline size_t RangeTracker::total_free() const { - return N - used(); -} - template inline size_t RangeTracker::longest_free() const { return longest_free_; @@ -191,7 +192,7 @@ inline size_t RangeTracker::allocs() const { template inline size_t RangeTracker::FindAndMark(size_t n) { - ASSERT(n > 0); + TC_ASSERT_GT(n, 0); // We keep the two longest ranges in the bitmap since we might allocate // from one. @@ -221,7 +222,7 @@ inline size_t RangeTracker::FindAndMark(size_t n) { index += len; } - CHECK_CONDITION(best_index < N); + TC_CHECK_LT(best_index, N); bits_.SetRange(best_index, n); if (best_len == longest_len) { @@ -235,11 +236,36 @@ inline size_t RangeTracker::FindAndMark(size_t n) { return best_index; } +// REQUIRES: the range [index, index + n) is fully unmarked. +// Marks it. +template +inline void RangeTracker::Mark(size_t index, size_t n) { + TC_ASSERT_GE(bits_.FindSet(index), index + n); + bits_.SetRange(index, n); + nused_ += n; + nallocs_++; + + size_t longest_len = 0; + size_t scan_index = 0, scan_len; + + // We just marked a range as used. This might change the longest free range + // recorded in longest_free_. Recompute. + while (bits_.NextFreeRange(scan_index, &scan_index, &scan_len)) { + if (scan_len > longest_len) { + longest_len = scan_len; + } + + scan_index += scan_len; + } + + longest_free_ = longest_len; +} + // REQUIRES: the range [index, index + n) is fully marked. // Unmarks it. template inline void RangeTracker::Unmark(size_t index, size_t n) { - ASSERT(bits_.FindClear(index) >= index + n); + TC_ASSERT(bits_.FindClear(index) >= index + n); bits_.ClearRange(index, n); nused_ -= n; nallocs_--; @@ -256,8 +282,8 @@ inline void RangeTracker::Unmark(size_t index, size_t n) { // If there is at least one free range at or after , // put it in *index, *length and return true; else return false. template -inline bool RangeTracker::NextFreeRange(size_t start, size_t *index, - size_t *length) const { +inline bool RangeTracker::NextFreeRange(size_t start, size_t* index, + size_t* length) const { return bits_.NextFreeRange(start, index, length); } @@ -272,12 +298,12 @@ inline void RangeTracker::Clear() { // Count the set bits [from, to) in the i-th word to Value. template inline size_t Bitmap::CountWordBits(size_t i, size_t from, size_t to) const { - ASSERT(from < kWordSize); - ASSERT(to <= kWordSize); + TC_ASSERT_LT(from, kWordSize); + TC_ASSERT_LE(to, kWordSize); const size_t all_ones = ~static_cast(0); // how many bits are we setting? const size_t n = to - from; - ASSERT(0 < n && n <= kWordSize); + TC_ASSERT(0 < n && n <= kWordSize); const size_t mask = (all_ones >> (kWordSize - n)) << from; ASSUME(i < kWords); @@ -288,12 +314,12 @@ inline size_t Bitmap::CountWordBits(size_t i, size_t from, size_t to) const { template template inline void Bitmap::SetWordBits(size_t i, size_t from, size_t to) { - ASSERT(from < kWordSize); - ASSERT(to <= kWordSize); + TC_ASSERT_LT(from, kWordSize); + TC_ASSERT_LE(to, kWordSize); const size_t all_ones = ~static_cast(0); // how many bits are we setting? const size_t n = to - from; - ASSERT(n > 0 && n <= kWordSize); + TC_ASSERT(n > 0 && n <= kWordSize); const size_t mask = (all_ones >> (kWordSize - n)) << from; ASSUME(i < kWords); if (Value) { @@ -305,7 +331,7 @@ inline void Bitmap::SetWordBits(size_t i, size_t from, size_t to) { template inline bool Bitmap::GetBit(size_t i) const { - ASSERT(i < N); + TC_ASSERT_LT(i, N); size_t word = i / kWordSize; size_t offset = i % kWordSize; ASSUME(word < kWords); @@ -314,7 +340,7 @@ inline bool Bitmap::GetBit(size_t i) const { template inline void Bitmap::SetBit(size_t i) { - ASSERT(i < N); + TC_ASSERT_LT(i, N); size_t word = i / kWordSize; size_t offset = i % kWordSize; ASSUME(word < kWords); @@ -323,13 +349,18 @@ inline void Bitmap::SetBit(size_t i) { template inline void Bitmap::ClearBit(size_t i) { - ASSERT(i < N); + TC_ASSERT_LT(i, N); size_t word = i / kWordSize; size_t offset = i % kWordSize; ASSUME(word < kWords); bits_[word] &= ~(size_t{1} << offset); } +template +inline size_t Bitmap::CountBits() const { + return CountBits(0, N); +} + template inline size_t Bitmap::CountBits(size_t index, size_t n) const { ASSUME(index + n <= N); @@ -386,7 +417,7 @@ inline void Bitmap::ClearLowestBit() { template template inline void Bitmap::SetRangeValue(size_t index, size_t n) { - ASSERT(index + n <= N); + TC_ASSERT_LE(index + n, N); size_t word = index / kWordSize; size_t offset = index % kWordSize; size_t k = offset + n; @@ -403,8 +434,8 @@ inline void Bitmap::SetRangeValue(size_t index, size_t n) { } template -inline bool Bitmap::NextFreeRange(size_t start, size_t *index, - size_t *length) const { +inline bool Bitmap::NextFreeRange(size_t start, size_t* index, + size_t* length) const { if (start >= N) return false; size_t i = FindClear(start); if (i == N) return false; @@ -444,7 +475,7 @@ inline void Bitmap::Clear() { template template inline size_t Bitmap::FindValue(size_t index) const { - ASSERT(index < N); + TC_ASSERT_LT(index, N); size_t offset = index % kWordSize; size_t word = index / kWordSize; ASSUME(word < kWords); @@ -473,7 +504,7 @@ inline size_t Bitmap::FindValue(size_t index) const { template template inline ssize_t Bitmap::FindValueBackwards(size_t index) const { - ASSERT(index < N); + TC_ASSERT_LT(index, N); size_t offset = index % kWordSize; ssize_t word = index / kWordSize; ASSUME(word < kWords); diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/range_tracker_benchmark.cc b/contrib/libs/tcmalloc/tcmalloc/internal/range_tracker_benchmark.cc index 278fc9ef1ec7..b83e0429c297 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/range_tracker_benchmark.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/range_tracker_benchmark.cc @@ -13,13 +13,15 @@ // limitations under the License. #include -#include +#include +#include #include #include "absl/base/attributes.h" #include "absl/random/distributions.h" #include "absl/random/random.h" #include "benchmark/benchmark.h" +#include "tcmalloc/internal/config.h" #include "tcmalloc/internal/range_tracker.h" GOOGLE_MALLOC_SECTION_BEGIN @@ -27,11 +29,16 @@ namespace tcmalloc { namespace tcmalloc_internal { namespace { +struct RangeInfo { + size_t index; + size_t len; +}; + template static void BM_MarkUnmark(benchmark::State& state) { RangeTracker range; absl::BitGen rng; - std::vector> things; + std::vector things; while (range.used() < N / 2) { size_t len = absl::LogUniform(rng, 0, range.longest_free() - 1) + 1; @@ -43,7 +50,7 @@ static void BM_MarkUnmark(benchmark::State& state) { for (auto s : state) { size_t index = absl::Uniform(rng, 0, things.size()); auto p = things[index]; - range.Unmark(p.first, p.second); + range.Unmark(p.index, p.len); size_t len = absl::LogUniform(rng, 0, range.longest_free() - 1) + 1; things[index] = {range.FindAndMark(len), len}; @@ -58,6 +65,7 @@ BENCHMARK_TEMPLATE(BM_MarkUnmark, 256 * 32); template static void BM_MarkUnmarkEmpty(benchmark::State& state) { RangeTracker range; + absl::BitGen rng; for (auto s : state) { size_t index = range.FindAndMark(K); benchmark::DoNotOptimize(index); diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/range_tracker_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/range_tracker_test.cc index 4f9202e22196..9cd9df1e9710 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/range_tracker_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/range_tracker_test.cc @@ -14,15 +14,15 @@ #include "tcmalloc/internal/range_tracker.h" -#include +#include +#include + #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "absl/base/attributes.h" #include "absl/container/fixed_array.h" -#include "absl/random/distributions.h" #include "absl/random/random.h" namespace tcmalloc { @@ -35,17 +35,17 @@ using testing::Pair; class BitmapTest : public testing::Test { protected: template - std::vector FindSetResults(const Bitmap &map) { + std::vector FindSetResults(const Bitmap& map) { return FindResults(map); } template - std::vector FindClearResults(const Bitmap &map) { + std::vector FindClearResults(const Bitmap& map) { return FindResults(map); } template - std::vector FindResults(const Bitmap &map) { + std::vector FindResults(const Bitmap& map) { std::vector results; ssize_t last = -1; for (size_t i = 0; i < N; ++i) { @@ -63,17 +63,17 @@ class BitmapTest : public testing::Test { } template - std::vector FindSetResultsBackwards(const Bitmap &map) { + std::vector FindSetResultsBackwards(const Bitmap& map) { return FindResultsBackwards(map); } template - std::vector FindClearResultsBackwards(const Bitmap &map) { + std::vector FindClearResultsBackwards(const Bitmap& map) { return FindResultsBackwards(map); } template - std::vector FindResultsBackwards(const Bitmap &map) { + std::vector FindResultsBackwards(const Bitmap& map) { std::vector results; ssize_t last = N; for (ssize_t i = N - 1; i >= 0; --i) { @@ -187,6 +187,7 @@ TEST_F(BitmapTest, FindClear) { TEST_F(BitmapTest, CountBits) { Bitmap<253> map; map.SetRange(0, 253); + EXPECT_EQ(map.CountBits(), 253); EXPECT_EQ(map.CountBits(0, 253), 253); EXPECT_EQ(map.CountBits(8, 245), 245); EXPECT_EQ(map.CountBits(0, 250), 250); @@ -197,6 +198,7 @@ TEST_F(BitmapTest, CountBits) { map.ClearBit(63); map.ClearBit(128); + EXPECT_EQ(map.CountBits(), 248); EXPECT_EQ(map.CountBits(0, 253), 248); EXPECT_EQ(map.CountBits(8, 245), 241); EXPECT_EQ(map.CountBits(0, 250), 245); @@ -206,12 +208,14 @@ TEST_F(BitmapTest, CountBits) { map.ClearBit(251); map.ClearBit(252); + EXPECT_EQ(map.CountBits(), 244); EXPECT_EQ(map.CountBits(0, 253), 244); EXPECT_EQ(map.CountBits(8, 245), 237); EXPECT_EQ(map.CountBits(0, 250), 243); map.ClearBit(0); + EXPECT_EQ(map.CountBits(), 243); EXPECT_EQ(map.CountBits(0, 253), 243); EXPECT_EQ(map.CountBits(8, 245), 237); EXPECT_EQ(map.CountBits(0, 250), 242); @@ -289,6 +293,17 @@ TEST_F(RangeTrackerTest, Trivial) { EXPECT_THAT(FreeRanges(), ElementsAre(Pair(0, 300))); } +TEST_F(RangeTrackerTest, Mark) { + EXPECT_EQ(range_.longest_free(), kBits); + range_.Mark(100, 100); + EXPECT_EQ(range_.used(), 100); + EXPECT_EQ(range_.longest_free(), kBits - 200); + EXPECT_THAT(FreeRanges(), ElementsAre(Pair(0, 100), Pair(200, kBits - 200))); + range_.Unmark(100, 100); + EXPECT_EQ(range_.used(), 0); + EXPECT_EQ(range_.longest_free(), kBits); +} + } // namespace } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/residency.cc b/contrib/libs/tcmalloc/tcmalloc/internal/residency.cc new file mode 100644 index 000000000000..13f804f5a28f --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/residency.cc @@ -0,0 +1,230 @@ +// Copyright 2019 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/residency.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include "absl/status/status.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/range_tracker.h" +#include "tcmalloc/internal/util.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { +namespace { + +// From fs/proc/task_mmu.c: +#define PM_SWAP 1ULL << 62 +#define PM_PRESENT 1ULL << 63 + +constexpr bool PageSwapped(uint64_t flags) { + constexpr uint64_t kSwap = PM_SWAP; + return (flags & kSwap) == kSwap; +} + +constexpr bool PagePresent(uint64_t flags) { + constexpr uint64_t kPresentPage = PM_PRESENT; + return (flags & kPresentPage) == kPresentPage; +} + +// Small helper to interpret /proc/pid/pagemap. Bit 62 represents if the page is +// swapped, and bit 63 represents if the page is present. +void Update(const uint64_t input, const size_t size, Residency::Info& info) { + // From fs/proc/task_mmu.c: + if (PagePresent(input)) { + info.bytes_resident += size; + } + if (PageSwapped(input)) { + info.bytes_swapped += size; + } +} + +} // namespace + +Residency::Residency() : fd_(signal_safe_open("/proc/self/pagemap", O_RDONLY)) { + TC_CHECK_GE(sizeof(buf_), kSizeOfHugepageInPagemap, + "Buffer size is not large enough to hold the pagemap entries"); + TC_CHECK_LE(kNativePagesInHugePage, kMaxResidencyBits, + "Actual number of native pages in a hugepage is larger than the " + "total capacity of residency bitmaps"); +} + +Residency::Residency(const char* const alternate_filename) + : fd_(signal_safe_open(alternate_filename, O_RDONLY)) { + TC_CHECK_GE(sizeof(buf_), kSizeOfHugepageInPagemap, + "Buffer size is not large enough to hold the pagemap entries"); + TC_CHECK_LE(kNativePagesInHugePage, kMaxResidencyBits, + "Actual number of native pages in a hugepage is larger than the " + "total capacity of residency bitmaps"); +} + +Residency::~Residency() { + if (fd_ >= 0) { + signal_safe_close(fd_); + } +} + +absl::StatusCode Residency::Seek(const uintptr_t vaddr) { + size_t offset = vaddr / kPageSize * kPagemapEntrySize; + // Note: lseek can't be interrupted. + off_t status = ::lseek(fd_, offset, SEEK_SET); + if (status != offset) { + return absl::StatusCode::kUnavailable; + } + return absl::StatusCode::kOk; +} + +std::optional Residency::ReadOne() { + static_assert(sizeof(buf_) >= kPagemapEntrySize); + // /proc/pid/pagemap is a sequence of 64-bit values in machine endianness, one + // per page. The style guide really does not want me to do this "unsafe + // conversion", but the conversion is done in reverse by the kernel and we + // never persist it anywhere, so we actually do want this. + auto status = signal_safe_read(fd_, reinterpret_cast(buf_), + kPagemapEntrySize, nullptr); + if (status != kPagemapEntrySize) { + return std::nullopt; + } + return buf_[0]; +} + +absl::StatusCode Residency::ReadMany(int64_t num_pages, Residency::Info& info) { + while (num_pages > 0) { + const size_t batch_size = std::min(kEntriesInBuf, num_pages); + const size_t to_read = kPagemapEntrySize * batch_size; + + // We read continuously. For the first read, this starts at wherever the + // first ReadOne ended. See above note for the reinterpret_cast. + auto status = + signal_safe_read(fd_, reinterpret_cast(buf_), to_read, nullptr); + if (status != to_read) { + return absl::StatusCode::kUnavailable; + } + for (int i = 0; i < batch_size; ++i) { + Update(buf_[i], kPageSize, info); + } + num_pages -= batch_size; + } + return absl::StatusCode::kOk; +} + +std::optional Residency::Get(const void* const addr, + const size_t size) { + if (fd_ < 0) { + return std::nullopt; + } + + Residency::Info info; + if (size == 0) return info; + + uintptr_t uaddr = reinterpret_cast(addr); + // Round address down to get the start of the page containing the data. + uintptr_t basePage = uaddr & ~(kPageSize - 1); + // Round end address up to get the end of the page containing the data. + // The data is in [basePage, endPage). + uintptr_t endPage = (uaddr + size + kPageSize - 1) & ~(kPageSize - 1); + + int64_t remainingPages = (endPage - basePage) / kPageSize; + + if (auto res = Seek(basePage); res != absl::StatusCode::kOk) { + return std::nullopt; + } + + if (remainingPages == 1) { + auto res = ReadOne(); + if (!res.has_value()) return std::nullopt; + Update(res.value(), size, info); + return info; + } + + // Since the input address might not be page-aligned (it can possibly point to + // an arbitrary object), we read the information about the first page + // separately with ReadOne, then read the complete pages with ReadMany, and + // then read the last page with ReadOne again if needed. + auto res = ReadOne(); + if (!res.has_value()) return std::nullopt; + + // Handle the first page. + size_t firstPageSize = kPageSize - (uaddr - basePage); + Update(res.value(), firstPageSize, info); + remainingPages--; + + // Handle all pages but the last page. + if (auto res = ReadMany(remainingPages - 1, info); + res != absl::StatusCode::kOk) { + return std::nullopt; + } + + // Check final page + size_t lastPageSize = kPageSize - (endPage - uaddr - size); + res = ReadOne(); + if (!res.has_value()) return std::nullopt; + Update(res.value(), lastPageSize, info); + return info; +} + +Residency::SinglePageBitmaps Residency::GetHolesAndSwappedBitmaps( + const void* const addr) { + Bitmap page_holes; + Bitmap page_swapped; + uintptr_t currPage = reinterpret_cast(addr); + if ((currPage & kHugePageMask) != currPage) { + TC_LOG("Address is not hugepage aligned"); + return SinglePageBitmaps{page_holes, page_swapped, + absl::StatusCode::kFailedPrecondition}; + } + auto res = Seek(currPage); + if (res != absl::StatusCode::kOk) { + return SinglePageBitmaps{page_holes, page_swapped, + absl::StatusCode::kUnavailable}; + } + auto status = signal_safe_read(fd_, reinterpret_cast(buf_), + kSizeOfHugepageInPagemap, nullptr); + if (status != kSizeOfHugepageInPagemap) { + TC_LOG( + "Could not read from pagemap file due to unexpected number of bytes " + "read. Expected %d bytes, got %d bytes", + kSizeOfHugepageInPagemap, status); + return SinglePageBitmaps{page_holes, page_swapped, + absl::StatusCode::kUnavailable}; + } + + for (int native_page_idx = 0; native_page_idx < kNativePagesInHugePage; + ++native_page_idx) { + uint64_t page_map = buf_[native_page_idx]; + // Case for page hole + if (!PagePresent(page_map)) { + page_holes.SetBit(native_page_idx); + // Case for zswap + if (PageSwapped(page_map)) { + page_swapped.SetBit(native_page_idx); + } + } + } + return SinglePageBitmaps{page_holes, page_swapped, absl::StatusCode::kOk}; +} + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/residency.h b/contrib/libs/tcmalloc/tcmalloc/internal/residency.h new file mode 100644 index 000000000000..309edb393c69 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/residency.h @@ -0,0 +1,120 @@ +#pragma clang system_header +// Copyright 2019 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_INTERNAL_RESIDENCY_H_ +#define TCMALLOC_INTERNAL_RESIDENCY_H_ + +#include +#include +#include + +#include +#include + +#include "absl/status/status.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/page_size.h" +#include "tcmalloc/internal/range_tracker.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +// Residency offers information about memory residency: whether or not specific +// spans of memory are resident in core ("m in core"), swapped, or not present. +// Originally, this was implemented via the mincore syscall, but has since been +// abstracted to provide more information. +class Residency { + public: + // This class keeps an open file handle to procfs. Destroy the object to + // reclaim it. + Residency(); + ~Residency(); + + // Query a span of memory starting from `addr` for `size` bytes. + // + // We use std::optional for return value as std::optional guarantees that no + // dynamic memory allocation would happen. In contrast, absl::StatusOr may + // dynamically allocate memory when needed. Using std::optional allows us to + // use the function in places where memory allocation is prohibited. + // + // This is NOT thread-safe. Do not use multiple copies of this class across + // threads. + struct Info { + size_t bytes_resident = 0; + size_t bytes_swapped = 0; + }; + std::optional Get(const void* addr, size_t size); + + static constexpr int kMaxResidencyBits = 512; + + // Struct is ordered with bitmaps first to optimize cacheline usage. + struct SinglePageBitmaps { + Bitmap holes; + Bitmap swapped; + absl::StatusCode status; + }; + + // Using a hugepage-aligned address, parse through /proc/self/pagemap + // to output two bitmaps - one for pages that are holes and one for pages that + // are swapped. Hugepage-sized regions are assumed to be 2MiB in size. A + // SinglePageBitmaps struct is returned with the status , the page_holes + // bitmap, and the page_swapped bitmap. + SinglePageBitmaps GetHolesAndSwappedBitmaps(const void* addr); + + private: + // This helper seeks the internal file to the correct location for the given + // virtual address. + absl::StatusCode Seek(uintptr_t vaddr); + // This helper reads information for a single page. This is useful for the + // boundaries. It continues the read from the last Seek() or last Read + // operation. + std::optional ReadOne(); + // This helper reads information for `num_pages` worth of _full_ pages and + // puts the results into `info`. It continues the read from the last Seek() or + // last Read operation. + absl::StatusCode ReadMany(int64_t num_pages, Info& info); + + // For testing. + friend class ResidencySpouse; + explicit Residency(const char* alternate_filename); + + // Size of the buffer used to gather results. + static constexpr int kBufferLength = 4096; + static constexpr int kPagemapEntrySize = 8; + static constexpr int kEntriesInBuf = kBufferLength / kPagemapEntrySize; + + const size_t kPageSize = GetPageSize(); + + static constexpr uintptr_t kHugePageMask = ~(kHugePageSize - 1); + const size_t kNativePagesInHugePage = kHugePageSize / kPageSize; + + uint64_t buf_[kEntriesInBuf]; + const int fd_; + const size_t kSizeOfHugepageInPagemap = + kPagemapEntrySize * kNativePagesInHugePage; +}; + +inline std::ostream& operator<<(std::ostream& stream, + const Residency::Info& rhs) { + return stream << "{.resident = " << rhs.bytes_resident + << ", .swapped = " << rhs.bytes_swapped << "}"; +} + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_RESIDENCY_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/residency_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/residency_test.cc new file mode 100644 index 000000000000..c0a8cb1fc0a5 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/residency_test.cc @@ -0,0 +1,373 @@ +// Copyright 2019 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/residency.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "benchmark/benchmark.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/log/check.h" +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" +#include "tcmalloc/internal/allocation_guard.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/page_size.h" +#include "tcmalloc/internal/range_tracker.h" +#include "tcmalloc/internal/util.h" + +namespace tcmalloc { +namespace tcmalloc_internal { + +class ResidencySpouse { + public: + explicit ResidencySpouse() = default; + explicit ResidencySpouse(const char* const filename) : r_(filename) {} + explicit ResidencySpouse(absl::string_view filename) : r_(filename.data()) {} + + template + decltype(auto) Get(Args&&... args) { + return r_.Get(std::forward(args)...); + } + + decltype(auto) GetHolesAndSwappedBitmaps(const void* const addr) { + return r_.GetHolesAndSwappedBitmaps(addr); + } + + private: + Residency r_; +}; + +namespace { + +using ::testing::FieldsAre; +using ::testing::Optional; + +constexpr uint64_t kPageSwapped = (1ULL << 62); +constexpr uint64_t kPagePresent = (1ULL << 63); + +TEST(ResidenceTest, ThisProcess) { + const size_t kPageSize = GetPageSize(); + const int kNumPages = 16; + + // Try both private and shared mappings to make sure we have the bit order of + // /proc/pid/pageflags correct. + for (const int flags : + {MAP_ANONYMOUS | MAP_SHARED, MAP_ANONYMOUS | MAP_PRIVATE}) { + const size_t kHead = kPageSize * 10; + const size_t kTail = kPageSize * 10; + + Residency r; + // Overallocate kNumPages of memory, so we can munmap the page before and + // after it. + void* p = mmap(nullptr, kNumPages * kPageSize + kHead + kTail, + PROT_READ | PROT_WRITE, flags, -1, 0); + ASSERT_NE(p, MAP_FAILED) << errno; + + EXPECT_THAT(r.Get(p, (kNumPages + 2) * kPageSize), + Optional(FieldsAre(0, 0))); + ASSERT_EQ(munmap(p, kPageSize), 0); + void* q = reinterpret_cast(p) + kHead; + void* last = reinterpret_cast(p) + kNumPages * kPageSize + kHead; + ASSERT_EQ(munmap(last, kPageSize), 0); + + EXPECT_THAT(r.Get(p, kHead), Optional(FieldsAre(0, 0))); + EXPECT_THAT(r.Get(last, kTail), Optional(FieldsAre(0, 0))); + + memset(q, 0, kNumPages * kPageSize); + (void)mlock(q, kNumPages * kPageSize); + ::benchmark::DoNotOptimize(q); + + EXPECT_THAT(r.Get(p, kHead), Optional(FieldsAre(0, 0))); + EXPECT_THAT(r.Get(last, kTail), Optional(FieldsAre(0, 0))); + + EXPECT_THAT(r.Get(q, kPageSize), Optional(FieldsAre(kPageSize, 0))); + + EXPECT_THAT(r.Get(q, (kNumPages + 2) * kPageSize), + Optional(FieldsAre(kPageSize * kNumPages, 0))); + + EXPECT_THAT(r.Get(reinterpret_cast(q) + 7, kPageSize - 7), + Optional(FieldsAre(kPageSize - 7, 0))); + + EXPECT_THAT(r.Get(reinterpret_cast(q) + 7, kPageSize), + Optional(FieldsAre(kPageSize, 0))); + + EXPECT_THAT(r.Get(reinterpret_cast(q) + 7, 3 * kPageSize), + Optional(FieldsAre(kPageSize * 3, 0))); + + EXPECT_THAT(r.Get(reinterpret_cast(q) + 7, kNumPages * kPageSize), + Optional(FieldsAre(kPageSize * kNumPages - 7, 0))); + + EXPECT_THAT( + r.Get(reinterpret_cast(q) + 7, kNumPages * kPageSize - 7), + Optional(FieldsAre(kPageSize * kNumPages - 7, 0))); + + EXPECT_THAT( + r.Get(reinterpret_cast(q) + 7, (kNumPages + 1) * kPageSize), + Optional(FieldsAre(kPageSize * kNumPages - 7, 0))); + + EXPECT_THAT( + r.Get(reinterpret_cast(q) + 7, (kNumPages + 1) * kPageSize - 7), + Optional(FieldsAre(kPageSize * kNumPages - 7, 0))); + + ASSERT_EQ(munmap(q, kNumPages * kPageSize), 0); + } +} + +TEST(ResidenceTest, CannotOpen) { + ResidencySpouse r("/tmp/a667ba48-18ba-4523-a8a7-b49ece3a6c2b"); + EXPECT_FALSE(r.Get(nullptr, 1).has_value()); +} + +TEST(ResidenceTest, CannotRead) { + ResidencySpouse r("/dev/null"); + EXPECT_FALSE(r.Get(nullptr, 1).has_value()); +} + +TEST(ResidenceTest, CannotSeek) { + ResidencySpouse r("/dev/null"); + EXPECT_FALSE(r.Get(&r, 1).has_value()); +} + +// Method that can write a region with a single hugepage +// a region with a single missing page, a region with every other page missing, +// a region with all missing pages, or a region with a hugepage in the middle. +void GenerateHolesInSinglePage(absl::string_view filename, int case_num, + int num_pages) { + int write_fd = signal_safe_open(filename.data(), O_CREAT | O_WRONLY, S_IRUSR); + CHECK_NE(write_fd, -1) << errno; + std::vector buf(num_pages, 0); + for (int i = 0; i < num_pages; i++) { + switch (case_num) { + case 0: + // All pages are present + buf[i] = kPagePresent; + break; + case 1: + // All Pages are swapped + buf[i] = kPageSwapped; + break; + case 2: + // All pages are holes + buf[i] = 0; + break; + case 3: + // Every other page is a hole, rest are present + if (i % 2 == 0) { + buf[i] = 0; + } else if (i % 2 == 1) { + buf[i] = kPagePresent; + } + break; + case 4: + // Every other page is swapped, rest are present + if (i % 2 == 0) { + buf[i] = kPageSwapped; + } else if (i % 2 == 1) { + buf[i] = kPagePresent; + } + break; + case 5: + // Every other page is swapped, rest are holes + if (i % 2 == 0) { + buf[i] = kPageSwapped; + } else if (i % 2 == 1) { + buf[i] = 0; + } + break; + } + } + int size_of_write = num_pages * sizeof(uint64_t); + CHECK_EQ(write(write_fd, buf.data(), size_of_write), size_of_write); + CHECK_EQ(close(write_fd), 0) << errno; +} + +Residency::SinglePageBitmaps GenerateExpectedSinglePageBitmaps(int case_num) { + Bitmap<512> expected_holes; + Bitmap<512> expected_swapped; + switch (case_num) { + case 0: + // All Pages are present. Both bitmaps are 0 + break; + case 1: + // All Pages are swapped. Both bitmaps are all 1 + expected_holes.SetRange(0, 512); + expected_swapped.SetRange(0, 512); + break; + case 2: + // All pages are holes. Holes bitmap is all 1 + expected_holes.SetRange(0, 512); + break; + case 3: + // Every other page is a hole, rest are present. + // Both bitmaps are 0 and 1 alternating + for (int idx = 0; idx < 512; idx += 2) { + if (idx % 2 == 0) { + expected_holes.SetBit(idx); + } + } + break; + case 4: + // Every other page is swapped, rest are present, + // Bitmaps are 0 and 1 alternating + for (int idx = 0; idx < 512; idx += 2) { + if (idx % 2 == 0) { + expected_holes.SetBit(idx); + expected_swapped.SetBit(idx); + } + } + break; + case 5: + // Every other page is swapped, rest are holes, + // swapped bitmaps are 0 and 1 alternating, holes bitmaps are all 1 + for (int idx = 0; idx < 512; idx++) { + expected_holes.SetRange(0, 512); + if (idx % 2 == 0) { + expected_swapped.SetBit(idx); + } + } + break; + } + return Residency::SinglePageBitmaps{expected_holes, expected_swapped, + absl::StatusCode::kOk}; +} + +// Method that compares two bitmaps to see if they are equivalent +bool BitmapsAreEqual(const Bitmap<512>& bitmap1, const Bitmap<512>& bitmap2) { + for (int i = 0; i < 512; ++i) { + if (bitmap1.GetBit(i) != bitmap2.GetBit(i)) { + return false; + } + } + return true; +} + +TEST(PageMapTest, GetHolesAndSwappedBitmaps) { + constexpr int kNumCases = 6; + std::array expected; + for (int i = 0; i < kNumCases; ++i) { + expected[i] = GenerateExpectedSinglePageBitmaps(i); + } + + std::optional g; + for (int i = 0; i < kNumCases; ++i) { + std::string file_path = + absl::StrCat(testing::TempDir(), "/holes_in_single_page_", i); + GenerateHolesInSinglePage(file_path, /*case_num=*/i, + /*num_pages=*/512); + + g.emplace(); + ResidencySpouse s(file_path); + Residency::SinglePageBitmaps res = + s.GetHolesAndSwappedBitmaps(reinterpret_cast(0)); + g.reset(); + EXPECT_THAT(res.status, expected[i].status); + EXPECT_TRUE(BitmapsAreEqual(res.holes, expected[i].holes)); + EXPECT_TRUE(BitmapsAreEqual(res.swapped, expected[i].swapped)); + } +} + +TEST(PageMapTest, CountHolesWithAddressBeyondFirstPage) { + std::optional g; + std::string file_path = + absl::StrCat(testing::TempDir(), "/holes_in_single_page"); + GenerateHolesInSinglePage(file_path, /*case_num=*/5, + /*num_pages=*/2048); + Residency::SinglePageBitmaps expected = GenerateExpectedSinglePageBitmaps(5); + g.emplace(); + ResidencySpouse s(file_path); + Residency::SinglePageBitmaps res = + s.GetHolesAndSwappedBitmaps(reinterpret_cast(2 << 21)); + g.reset(); + EXPECT_THAT(res.status, expected.status); + EXPECT_TRUE(BitmapsAreEqual(res.holes, expected.holes)); + EXPECT_TRUE(BitmapsAreEqual(res.swapped, expected.swapped)); +} + +TEST(PageMapTest, VerifyAddressAlignmentCheckPasses) { + std::optional g; + std::string file_path = absl::StrCat(testing::TempDir(), "/alignment_check"); + GenerateHolesInSinglePage(file_path, /*case_num=*/0, + /*num_pages=*/512); + g.emplace(); + ResidencySpouse s(file_path); + Residency::SinglePageBitmaps non_align_addr_res = + s.GetHolesAndSwappedBitmaps(reinterpret_cast(0x00001)); + g.reset(); + EXPECT_EQ(non_align_addr_res.status, absl::StatusCode::kFailedPrecondition); +} + +TEST(PageMapTest, VerifyAddressAlignmentBeyondFirstPageFails) { + std::optional g; + g.emplace(); + ResidencySpouse s; + Residency::SinglePageBitmaps res = + s.GetHolesAndSwappedBitmaps(reinterpret_cast((2 << 21) + 1)); + g.reset(); + EXPECT_EQ(res.status, absl::StatusCode::kFailedPrecondition); +} + +TEST(PageMapIntegrationTest, WorksOnActualData) { + std::optional g; + void* addr = mmap(nullptr, 4 << 20, PROT_WRITE, + MAP_ANONYMOUS | MAP_POPULATE | MAP_PRIVATE, -1, 0); + ASSERT_NE(addr, MAP_FAILED) << errno; + auto position = reinterpret_cast(addr); + if ((position & (kHugePageSize - 1)) != 0) { + position |= kHugePageSize - 1; + position++; + addr = reinterpret_cast(position); + } + g.emplace(); + Residency r; + auto res = r.GetHolesAndSwappedBitmaps(addr); + g.reset(); + ASSERT_EQ(res.status, absl::StatusCode::kOk); + EXPECT_TRUE(res.holes.IsZero()); + EXPECT_TRUE(res.swapped.IsZero()); + ASSERT_EQ(munmap(reinterpret_cast(addr) + 1 * 4096, 4096), 0) + << errno; + ASSERT_EQ(munmap(reinterpret_cast(addr) + 17 * 4096, 4096), 0) + << errno; + + g.emplace(); + res = r.GetHolesAndSwappedBitmaps(addr); + g.reset(); + ASSERT_EQ(res.status, absl::StatusCode::kOk); + EXPECT_FALSE(res.holes.IsZero()); + ASSERT_TRUE(res.holes.GetBit(1)); + ASSERT_TRUE(res.holes.GetBit(17)); + res.holes.ClearLowestBit(); + res.holes.ClearLowestBit(); + EXPECT_TRUE(res.holes.IsZero()); + EXPECT_TRUE(res.swapped.IsZero()); +} + +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation.h b/contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation.h new file mode 100644 index 000000000000..ef6f7d551bc1 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation.h @@ -0,0 +1,64 @@ +#pragma clang system_header +// Copyright 2021 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_INTERNAL_SAMPLED_ALLOCATION_H_ +#define TCMALLOC_INTERNAL_SAMPLED_ALLOCATION_H_ + +#include + +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/sampled_allocation_recorder.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +// Stores information about the sampled allocation. +struct SampledAllocation : public tcmalloc_internal::Sample { + // We use this constructor to initialize `graveyard_`, which is used to + // maintain the freelist of SampledAllocations. When we revive objects from + // the freelist, we use `PrepareForSampling()` to update the state of the + // object. + constexpr SampledAllocation() = default; + + // When no object is available on the freelist, we allocate for a new + // SampledAllocation object and invoke this constructor with + // `PrepareForSampling()`. + explicit SampledAllocation(StackTrace&& stack_trace) { + PrepareForSampling(std::move(stack_trace)); + } + + SampledAllocation(const SampledAllocation&) = delete; + SampledAllocation& operator=(const SampledAllocation&) = delete; + + SampledAllocation(SampledAllocation&&) = delete; + SampledAllocation& operator=(SampledAllocation&&) = delete; + + // Prepares the state of the object. It is invoked when either a new sampled + // allocation is constructed or when an object is revived from the freelist. + void PrepareForSampling(StackTrace&& stack_trace) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock) { + sampled_stack = std::move(stack_trace); + } + + // The stack trace of the sampled allocation. + StackTrace sampled_stack = {}; +}; + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_SAMPLED_ALLOCATION_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation_recorder.h b/contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation_recorder.h new file mode 100644 index 000000000000..cf4a1164d658 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation_recorder.h @@ -0,0 +1,262 @@ +#pragma clang system_header +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// ----------------------------------------------------------------------------- +// File: sampled_allocation_recorder.h +// ----------------------------------------------------------------------------- +// +// This header file defines a lock-free linked list for recording TCMalloc +// sampled allocations collected from a random/stochastic process. + +#ifndef TCMALLOC_INTERNAL_SAMPLED_ALLOCATION_RECORDER_H_ +#define TCMALLOC_INTERNAL_SAMPLED_ALLOCATION_RECORDER_H_ + +#include + +#include "absl/base/attributes.h" +#include "absl/base/const_init.h" +#include "absl/base/internal/spinlock.h" +#include "absl/base/thread_annotations.h" +#include "absl/functional/function_ref.h" +#include "tcmalloc/internal/allocation_guard.h" +#include "tcmalloc/internal/config.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +// Sample that has members required for linking samples in the linked list of +// samples maintained by the SampleRecorder. Type T defines the sampled data. +template +struct Sample { + // Guards the ability to restore the sample to a pristine state. This + // prevents races with sampling and resurrecting an object. + absl::base_internal::SpinLock lock{absl::kConstInit, + absl::base_internal::SCHEDULE_KERNEL_ONLY}; + T* next = nullptr; + T* dead ABSL_GUARDED_BY(lock) = nullptr; +}; + +// Holds samples and their associated stack traces. +// +// Thread safe. +template +class SampleRecorder { + public: + using Allocator = AllocatorT; + + constexpr explicit SampleRecorder( + Allocator& allocator ABSL_ATTRIBUTE_LIFETIME_BOUND); + ~SampleRecorder(); + + SampleRecorder(const SampleRecorder&) = delete; + SampleRecorder& operator=(const SampleRecorder&) = delete; + + SampleRecorder(SampleRecorder&&) = delete; + SampleRecorder& operator=(SampleRecorder&&) = delete; + + // Registers for sampling. Returns an opaque registration info. + template + T* Register(Targs&&... args); + + // Unregisters the sample. + void Unregister(T* sample); + + // The dispose callback will be called on all samples the moment they are + // being unregistered. Only affects samples that are unregistered after the + // callback has been set. + // Returns the previous callback. + using DisposeCallback = void (*)(const T&); + DisposeCallback SetDisposeCallback(DisposeCallback f); + + // Unregisters any live samples starting from `all_`. Note that if there are + // any samples added in front of `all_` in other threads after this function + // reads `all_`, they won't be cleaned up. External synchronization is + // required if the intended outcome is to have no live sample after this call. + // Extra care must be taken when `Unregister()` is invoked concurrently with + // this function to avoid a dead sample (updated by this function) being + // passed to `Unregister()` which assumes the sample is live. + void UnregisterAll(); + + // Iterates over all the registered samples. + void Iterate(const absl::FunctionRef& f); + + void AcquireInternalLocks(); + void ReleaseInternalLocks(); + + private: + void PushNew(T* sample); + void PushDead(T* sample); + template + T* PopDead(Targs&&... args); + + // Intrusive lock free linked lists for tracking samples. + // + // `all_` records all samples (they are never removed from this list) and is + // terminated with a `nullptr`. + // + // `graveyard_.dead` is a circular linked list. When it is empty, + // `graveyard_.dead == &graveyard`. The list is circular so that + // every item on it (even the last) has a non-null dead pointer. This allows + // `Iterate` to determine if a given sample is live or dead using only + // information on the sample itself. + // + // For example, nodes [A, B, C, D, E] with [A, C, E] alive and [B, D] dead + // looks like this (G is the Graveyard): + // + // +---+ +---+ +---+ +---+ +---+ + // all -->| A |--->| B |--->| C |--->| D |--->| E | + // | | | | | | | | | | + // +---+ | | +->| |-+ | | +->| |-+ | | + // | G | +---+ | +---+ | +---+ | +---+ | +---+ + // | | | | | | + // | | --------+ +--------+ | + // +---+ | + // ^ | + // +--------------------------------------+ + // + std::atomic all_; + T graveyard_; + + std::atomic dispose_; + Allocator* const allocator_; +}; + +template +typename SampleRecorder::DisposeCallback +SampleRecorder::SetDisposeCallback(DisposeCallback f) { + return dispose_.exchange(f, std::memory_order_relaxed); +} + +template +constexpr SampleRecorder::SampleRecorder(Allocator& allocator) + : all_(nullptr), dispose_(nullptr), allocator_(&allocator) { + graveyard_.dead = &graveyard_; +} + +template +SampleRecorder::~SampleRecorder() { + T* s = all_.load(std::memory_order_acquire); + while (s != nullptr) { + T* next = s->next; + allocator_->Delete(s); + s = next; + } +} + +template +void SampleRecorder::PushNew(T* sample) { + sample->next = all_.load(std::memory_order_relaxed); + while (!all_.compare_exchange_weak(sample->next, sample, + std::memory_order_release, + std::memory_order_relaxed)) { + } +} + +template +void SampleRecorder::PushDead(T* sample) { + if (auto* dispose = dispose_.load(std::memory_order_relaxed)) { + dispose(*sample); + } + sample->sampled_stack.user_data.Reset(); + + AllocationGuardSpinLockHolder graveyard_lock(&graveyard_.lock); + AllocationGuardSpinLockHolder sample_lock(&sample->lock); + sample->dead = graveyard_.dead; + graveyard_.dead = sample; +} + +template +template +T* SampleRecorder::PopDead(Targs&&... args) { + AllocationGuardSpinLockHolder graveyard_lock(&graveyard_.lock); + + // The list is circular, so eventually it collapses down to + // graveyard_.dead == &graveyard_ + // when it is empty. + T* sample = graveyard_.dead; + if (sample == &graveyard_) return nullptr; + + AllocationGuardSpinLockHolder sample_lock(&sample->lock); + graveyard_.dead = sample->dead; + sample->dead = nullptr; + sample->PrepareForSampling(std::forward(args)...); + return sample; +} + +template +template +T* SampleRecorder::Register(Targs&&... args) { + T* sample = PopDead(std::forward(args)...); + if (sample == nullptr) { + // Resurrection failed. Hire a new warlock. + sample = allocator_->New(std::forward(args)...); + PushNew(sample); + } + + return sample; +} + +template +void SampleRecorder::Unregister(T* sample) { + PushDead(sample); +} + +template +void SampleRecorder::UnregisterAll() { + AllocationGuardSpinLockHolder graveyard_lock(&graveyard_.lock); + T* sample = all_.load(std::memory_order_acquire); + auto* dispose = dispose_.load(std::memory_order_relaxed); + while (sample != nullptr) { + { + AllocationGuardSpinLockHolder sample_lock(&sample->lock); + if (sample->dead == nullptr) { + if (dispose) dispose(*sample); + sample->dead = graveyard_.dead; + graveyard_.dead = sample; + } + } + sample = sample->next; + } +} + +template +void SampleRecorder::Iterate( + const absl::FunctionRef& f) { + T* s = all_.load(std::memory_order_acquire); + while (s != nullptr) { + AllocationGuardSpinLockHolder l(&s->lock); + if (s->dead == nullptr) { + f(*s); + } + s = s->next; + } +} + +template +void SampleRecorder::AcquireInternalLocks() { + graveyard_.lock.Lock(); +} + +template +void SampleRecorder::ReleaseInternalLocks() { + graveyard_.lock.Unlock(); +} + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_SAMPLED_ALLOCATION_RECORDER_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation_recorder_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation_recorder_test.cc new file mode 100644 index 000000000000..6e42bc972415 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation_recorder_test.cc @@ -0,0 +1,278 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/sampled_allocation_recorder.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/base/thread_annotations.h" +#include "absl/synchronization/notification.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "tcmalloc/internal/explicitly_constructed.h" +#include "tcmalloc/testing/thread_manager.h" + +namespace tcmalloc { +namespace tcmalloc_internal { +namespace { +using ::testing::IsEmpty; +using ::testing::UnorderedElementsAre; + +struct Info : public Sample { + public: + Info() { PrepareForSampling(); } + void PrepareForSampling() ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock) { + initialized = true; + } + std::atomic size; + absl::Time create_time; + bool initialized; +}; + +class TestAllocator { + public: + static Info* New() { + alloc_count_.fetch_add(1, std::memory_order_relaxed); + return new Info; + } + static void Delete(Info* info) { + alloc_count_.fetch_sub(1, std::memory_order_relaxed); + delete info; + } + static uint64_t alloc_count() { + return alloc_count_.load(std::memory_order_relaxed); + } + inline static std::atomic alloc_count_{0}; +}; + +class SampleRecorderTest : public ::testing::Test { + public: + SampleRecorderTest() : sample_recorder_(allocator_) {} + + std::vector GetSizes() { + std::vector res; + // Reserve to avoid reentrant allocations while iterating. + res.reserve(5); + sample_recorder_.Iterate([&](const Info& info) { + res.push_back(info.size.load(std::memory_order_acquire)); + }); + return res; + } + + Info* Register(size_t size) { + auto* info = sample_recorder_.Register(); + assert(info != nullptr); + info->size.store(size); + return info; + } + + TestAllocator allocator_; + SampleRecorder sample_recorder_; +}; + +// Check that the state modified by PrepareForSampling() is properly set. +TEST_F(SampleRecorderTest, PrepareForSampling) { + Info* info1 = Register(1); + // PrepareForSampling() is invoked in the constructor. + EXPECT_TRUE(info1->initialized); + info1->initialized = false; + sample_recorder_.Unregister(info1); + + Info* info2 = Register(2); + // We are reusing the sample, PrepareForSampling() is invoked in PopDead(); + EXPECT_TRUE(info2->initialized); +} + +TEST_F(SampleRecorderTest, Registration) { + auto* info1 = Register(1); + EXPECT_THAT(GetSizes(), UnorderedElementsAre(1)); + + auto* info2 = Register(2); + EXPECT_THAT(GetSizes(), UnorderedElementsAre(1, 2)); + info1->size.store(3); + EXPECT_THAT(GetSizes(), UnorderedElementsAre(3, 2)); + + sample_recorder_.Unregister(info1); + sample_recorder_.Unregister(info2); +} + +TEST_F(SampleRecorderTest, Unregistration) { + std::vector infos; + for (size_t i = 0; i < 3; ++i) { + infos.push_back(Register(i)); + } + EXPECT_THAT(GetSizes(), UnorderedElementsAre(0, 1, 2)); + + sample_recorder_.Unregister(infos[1]); + EXPECT_THAT(GetSizes(), UnorderedElementsAre(0, 2)); + + infos.push_back(Register(3)); + infos.push_back(Register(4)); + EXPECT_THAT(GetSizes(), UnorderedElementsAre(0, 2, 3, 4)); + sample_recorder_.Unregister(infos[3]); + EXPECT_THAT(GetSizes(), UnorderedElementsAre(0, 2, 4)); + + sample_recorder_.Unregister(infos[0]); + sample_recorder_.Unregister(infos[2]); + sample_recorder_.Unregister(infos[4]); + EXPECT_THAT(GetSizes(), IsEmpty()); + + for (size_t i = 0; i < 10; ++i) { + Register(i); + } + sample_recorder_.UnregisterAll(); + // In a single thread, we expect all samples to be cleaned up. + EXPECT_THAT(GetSizes(), IsEmpty()); + // UnregisterAll() marks all the live samples as dead. If we register + // another set of samples, we expect the dead samples are reused and + // no actual allocation is needed for the new set of samples. + const uint64_t alloc_count1 = allocator_.alloc_count(); + for (size_t i = 0; i < 10; ++i) { + Register(i); + } + const uint64_t alloc_count2 = allocator_.alloc_count(); + EXPECT_EQ(alloc_count1, alloc_count2); +} + +TEST_F(SampleRecorderTest, MultiThreaded) { + absl::Notification stop; + ThreadManager threads; + const int kThreads = 10; + threads.Start(kThreads, [&](int) { + std::random_device rd; + std::mt19937 gen(rd()); + + std::vector infoz; + while (!stop.HasBeenNotified()) { + if (infoz.empty()) { + infoz.push_back(sample_recorder_.Register()); + } + switch (std::uniform_int_distribution<>(0, 2)(gen)) { + case 0: { + infoz.push_back(sample_recorder_.Register()); + break; + } + case 1: { + size_t p = std::uniform_int_distribution<>(0, infoz.size() - 1)(gen); + Info* info = infoz[p]; + infoz[p] = infoz.back(); + infoz.pop_back(); + sample_recorder_.Unregister(info); + break; + } + case 2: { + absl::Duration oldest = absl::ZeroDuration(); + sample_recorder_.Iterate([&](const Info& info) { + oldest = std::max(oldest, absl::Now() - info.create_time); + ASSERT_TRUE(info.initialized); + }); + ASSERT_GE(oldest, absl::ZeroDuration()); + break; + } + } + } + }); + + // Another `SampleRecorder` instance to test `UnregisterAll()`, which does not + // work well with the setup above since `infoz` might find itself storing dead + // objects as `UnregisterAll()` is running concurrently. And `Unregister()` + // assumes the object it is going to mark dead is still alive. + SampleRecorder sample_recorder{allocator_}; + threads.Start(kThreads, [&](int) { sample_recorder.Register(); }); + threads.Start(kThreads, [&](int) { sample_recorder.UnregisterAll(); }); + threads.Start(kThreads, [&](int) { + sample_recorder.Iterate( + [&](const Info& info) { ASSERT_TRUE(info.initialized); }); + }); + + // The threads will hammer away. Give it a little bit of time for tsan to + // spot errors. + absl::SleepFor(absl::Seconds(3)); + stop.Notify(); + threads.Stop(); +} + +TEST_F(SampleRecorderTest, Callback) { + auto* info1 = Register(1); + auto* info2 = Register(2); + + static const Info* expected; + + auto callback = [](const Info& info) { + // We can't use `info` outside of this callback because the object will be + // disposed as soon as we return from here. + EXPECT_EQ(&info, expected); + }; + + // Set the callback. + EXPECT_EQ(sample_recorder_.SetDisposeCallback(callback), nullptr); + expected = info1; + sample_recorder_.Unregister(info1); + + // Unset the callback. + EXPECT_EQ(callback, sample_recorder_.SetDisposeCallback(nullptr)); + expected = nullptr; // no more calls. + sample_recorder_.Unregister(info2); +} + +// Similar to Sample above but requires parameter(s) at initialization. +struct InfoWithParam : public Sample { + public: + // Default constructor to initialize |graveyard_|. + InfoWithParam() = default; + explicit InfoWithParam(size_t size) { PrepareForSampling(size); } + void PrepareForSampling(size_t size) ABSL_EXCLUSIVE_LOCKS_REQUIRED(lock) { + info_size = size; + initialized = true; + } + size_t info_size; + bool initialized; +}; + +class InfoAllocator { + public: + static InfoWithParam* New(size_t size) { return new InfoWithParam(size); } + static void Delete(InfoWithParam* infoWithParam) { delete infoWithParam; } +}; + +TEST(SampleRecorderWithParamTest, RegisterWithParam) { + InfoAllocator allocator; + SampleRecorder sample_recorder{allocator}; + // Register() goes though New(). + InfoWithParam* info = sample_recorder.Register(1); + EXPECT_THAT(info->info_size, 1); + EXPECT_TRUE(info->initialized); + // Set these values to something else. + info->info_size = 0; + info->initialized = false; + sample_recorder.Unregister(info); + // |info| is not deleted, just marked as dead. Here, Register() would invoke + // PopDead(), revive the same object, with its fields populated by PopDead(). + sample_recorder.Register(2); + EXPECT_THAT(info->info_size, 2); + EXPECT_TRUE(info->initialized); +} + +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation_test.cc new file mode 100644 index 000000000000..e398d6d2320b --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/sampled_allocation_test.cc @@ -0,0 +1,70 @@ +// Copyright 2021 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/sampled_allocation.h" + +#include "gtest/gtest.h" +#include "absl/base/internal/spinlock.h" +#include "absl/debugging/stacktrace.h" +#include "tcmalloc/internal/logging.h" + +namespace tcmalloc { +namespace tcmalloc_internal { +namespace { + +StackTrace PrepareStackTrace() { + StackTrace st; + st.depth = absl::GetStackTrace(st.stack, kMaxStackDepth, /* skip_count= */ 0); + st.requested_size = 8; + st.requested_alignment = 4; + st.allocated_size = 8; + st.access_hint = 1; + st.weight = 4; + return st; +} + +TEST(SampledAllocationTest, PrepareForSampling) { + // PrepareForSampling() invoked in the constructor. + SampledAllocation sampled_allocation(PrepareStackTrace()); + absl::base_internal::SpinLockHolder sample_lock(&sampled_allocation.lock); + + // Now verify some fields. + EXPECT_GT(sampled_allocation.sampled_stack.depth, 0); + EXPECT_EQ(sampled_allocation.sampled_stack.requested_size, 8); + EXPECT_EQ(sampled_allocation.sampled_stack.requested_alignment, 4); + EXPECT_EQ(sampled_allocation.sampled_stack.allocated_size, 8); + EXPECT_EQ(sampled_allocation.sampled_stack.access_hint, 1); + EXPECT_EQ(sampled_allocation.sampled_stack.weight, 4); + + // Set them to different values. + sampled_allocation.sampled_stack.depth = 0; + sampled_allocation.sampled_stack.requested_size = 0; + sampled_allocation.sampled_stack.requested_alignment = 0; + sampled_allocation.sampled_stack.allocated_size = 0; + sampled_allocation.sampled_stack.access_hint = 0; + sampled_allocation.sampled_stack.weight = 0; + + // Call PrepareForSampling() again and check the fields. + sampled_allocation.PrepareForSampling(PrepareStackTrace()); + EXPECT_GT(sampled_allocation.sampled_stack.depth, 0); + EXPECT_EQ(sampled_allocation.sampled_stack.requested_size, 8); + EXPECT_EQ(sampled_allocation.sampled_stack.requested_alignment, 4); + EXPECT_EQ(sampled_allocation.sampled_stack.allocated_size, 8); + EXPECT_EQ(sampled_allocation.sampled_stack.access_hint, 1); + EXPECT_EQ(sampled_allocation.sampled_stack.weight, 4); +} + +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/stacktrace_filter.h b/contrib/libs/tcmalloc/tcmalloc/internal/stacktrace_filter.h new file mode 100644 index 000000000000..b05b587d9bd2 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/stacktrace_filter.h @@ -0,0 +1,161 @@ +#pragma clang system_header +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_INTERNAL_STACKTRACE_FILTER_H_ +#define TCMALLOC_INTERNAL_STACKTRACE_FILTER_H_ + +#include +#include +#include +#include + +#include "absl/hash/hash.h" +#include "absl/types/span.h" +#include "tcmalloc/internal/config.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +// Counting Bloom Filter (CBF) implementation for stack traces. The template +// parameter kSize denotes the size of the Bloom Filter, and kHashNum the number +// of hash functions used. The probability of false positives is calculated as: +// +// P(num_stacks) = (1 - e^(-kHashNum * (num_stacks / kSize))) ^ kHashNum +// +// Where `num_stacks` are unique stack traces currently present in the filter. +// +// The main benefit of a CBF (vs. other data structure such as a regular Bloom +// Filter, or a Cache with an eviction policy) is that if the sum of all Add() +// operations becomes zero again, the CBF will no longer contain the item. False +// positives can be mitigated by configuring the CBF according to above formula. +// +// Thread-safety: thread-safe. +template +class StackTraceFilter { + public: + static constexpr size_t kSize = kSize_; + static constexpr size_t kHashNum = kHashNum_; + + static_assert(kSize > 0, "size must be non-zero"); + static_assert(kHashNum > 0, "number of hashes must be non-zero"); + + constexpr StackTraceFilter() = default; + + // Returns true if the filter contains the provided stack trace. See above + // formula to calculate the probability of false positives. + bool Contains(absl::Span stack_trace) const { + size_t stack_hash = GetFirstHash(stack_trace); + + for (size_t i = 0; i < kHashNum; ++i) { + if (!counts_[stack_hash % kSize].load(std::memory_order_relaxed)) + return false; + stack_hash = GetNextHash(stack_hash); + } + + return true; + } + + // Add (or remove if `val` < 0) a stack trace from the filter. The sum of + // values `val` added to the filter since construction or the last Clear() + // determines if a stack trace is contained or not: for any non-zero sum, + // Contains() returns true; false if the sum is zero. + void Add(absl::Span stack_trace, int val) { + Add(GetFirstHash(stack_trace), val); + } + + protected: + static size_t GetFirstHash(absl::Span s) { + return absl::HashOf(s); + } + + static size_t GetNextHash(size_t prev_hash) { + return absl::HashOf(prev_hash); + } + + void Add(size_t stack_hash, int val) { + for (size_t i = 0; i < kHashNum; ++i) { + counts_[stack_hash % kSize].fetch_add(val, std::memory_order_relaxed); + stack_hash = GetNextHash(stack_hash); + } + } + + private: + // Use uint to allow for integer wrap-around; false positives are possible if + // all kHashNum counts wrap to 0 (which is unlikely with kHashNum > 1). + std::array, kSize> counts_ = {}; + + friend class StackTraceFilterTest; +}; + +// Similar to StackTraceFilter, except that entries have to be decayed to be +// fully removed from the filter: the sum value of a stack trace is the added +// value + number of non-negative Add() calls. Each call to Add() or Decay() +// decays a stack trace: the stack trace to be decayed is the one added in the +// kDecaySteps'th previous call to Add(). +// +// Thread-safety: thread-safe. +template +class DecayingStackTraceFilter : public StackTraceFilter { + using Base = StackTraceFilter; + + public: + // Add (or remove if `val` < 0) a stack trace from the filter. On addition + // (non-negative value), a previously added stack trace is decayed. + void Add(absl::Span stack_trace, int val) { + const size_t stack_hash = this->GetFirstHash(stack_trace); + if (val >= 0) { + Decay(stack_hash); + // Because 0-valued entries denote unused entries, add 1 to be decayed if + // this is a non-zero hash (very likely). + Base::Add(stack_hash, val + !!stack_hash); + } else { + // Removal. + Base::Add(stack_hash, val); + } + } + + // Decays a previously added stack trace. + void Decay() { Decay(0); } + + // Force decay all previously added stack traces. + void DecayAll() { + for (int i = 0; i < kDecaySteps; ++i) { + Decay(); + } + } + + private: + // Replace the entry in the current ring buffer position with `replace_hash` + // and decay the previous stack trace. Advances to the next position. + void Decay(size_t replace_hash) { + const size_t pos = pos_.fetch_add(1, std::memory_order_relaxed); + const size_t decay_hash = + ring(pos).exchange(replace_hash, std::memory_order_relaxed); + // 0-valued entries denote unused entries. + if (decay_hash) Base::Add(decay_hash, -1); + } + + auto& ring(size_t pos) { return ring_[pos % ring_.size()]; } + + std::array, kDecaySteps> ring_ = {}; + std::atomic pos_ = 0; +}; + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_STACKTRACE_FILTER_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/stacktrace_filter_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/stacktrace_filter_test.cc new file mode 100644 index 000000000000..9347a62b1dce --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/stacktrace_filter_test.cc @@ -0,0 +1,262 @@ +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/stacktrace_filter.h" + +#include +#include + +#include "gtest/gtest.h" +#include "absl/container/flat_hash_set.h" +#include "absl/types/span.h" + +namespace tcmalloc { +namespace tcmalloc_internal { + +class StackTraceFilterTest : public testing::Test { + protected: + using DefaultFilter = StackTraceFilter<256, 1>; + + void SetUp() override { + absl::flat_hash_set hashes; + absl::flat_hash_set hash_bases; + + auto initialize_unique_stack_trace = [&](void*& val) { + uint64_t pc = 0; + while (true) { + ++pc; + // Checking for wrap around (unique stack trace never found) + ASSERT_NE(pc, 0); + val = reinterpret_cast(pc); + size_t hash = DefaultFilter::GetFirstHash({&val, 1}); + size_t hash_base = GetFirstIndex({&val, 1}); + if (!hash_bases.contains(hash_base) && !hashes.contains(hash)) { + hashes.insert(hash); + hash_bases.insert(hash_base); + break; + } + } + }; + + initialize_unique_stack_trace(stack_trace1_val_); + initialize_unique_stack_trace(stack_trace2_val_); + initialize_unique_stack_trace(stack_trace3_val_); + + // Ensure no collisions among test set (the initializer above should ensure + // this already). + ASSERT_NE(DefaultFilter::GetFirstHash(stack_trace1_), + DefaultFilter::GetFirstHash(stack_trace2_)); + ASSERT_NE(GetFirstIndex(stack_trace1_), GetFirstIndex(stack_trace2_)); + ASSERT_NE(DefaultFilter::GetFirstHash(stack_trace1_), + DefaultFilter::GetFirstHash(stack_trace3_)); + ASSERT_NE(GetFirstIndex(stack_trace1_), GetFirstIndex(stack_trace3_)); + ASSERT_NE(DefaultFilter::GetFirstHash(stack_trace2_), + DefaultFilter::GetFirstHash(stack_trace3_)); + ASSERT_NE(GetFirstIndex(stack_trace2_), GetFirstIndex(stack_trace3_)); + } + + void InitializeColliderStackTrace() { + absl::flat_hash_set hashes; + absl::flat_hash_set hash_bases; + + // Do not add base of stack_trace1_, because that is the match that is being + // created. + hashes.insert(DefaultFilter::GetFirstHash(stack_trace1_)); + hashes.insert(DefaultFilter::GetFirstHash(stack_trace2_)); + hash_bases.insert(GetFirstIndex(stack_trace2_)); + hashes.insert(DefaultFilter::GetFirstHash(stack_trace3_)); + hash_bases.insert(GetFirstIndex(stack_trace3_)); + + size_t hash1_base = GetFirstIndex(stack_trace1_); + uint64_t pc = reinterpret_cast(stack_trace1_[0]); + size_t collider_hash; + size_t collider_hash_base; + while (true) { + ++pc; + // Checking for wrap around + ASSERT_NE(pc, 0); + collider_stack_trace_val_ = reinterpret_cast(pc); + collider_hash = DefaultFilter::GetFirstHash(collider_stack_trace_); + collider_hash_base = GetFirstIndex(collider_stack_trace_); + // if a possible match, check to avoid collisions with others + if (hash1_base == collider_hash_base && !hashes.contains(collider_hash) && + !hash_bases.contains(collider_hash_base)) { + break; + } + } + + // Double check the work above + ASSERT_NE(DefaultFilter::GetFirstHash(stack_trace1_), + DefaultFilter::GetFirstHash(collider_stack_trace_)); + ASSERT_EQ(GetFirstIndex(stack_trace1_), + GetFirstIndex(collider_stack_trace_)); + ASSERT_NE(DefaultFilter::GetFirstHash(stack_trace2_), + DefaultFilter::GetFirstHash(collider_stack_trace_)); + ASSERT_NE(GetFirstIndex(stack_trace2_), + GetFirstIndex(collider_stack_trace_)); + ASSERT_NE(DefaultFilter::GetFirstHash(stack_trace3_), + DefaultFilter::GetFirstHash(collider_stack_trace_)); + ASSERT_NE(GetFirstIndex(stack_trace3_), + GetFirstIndex(collider_stack_trace_)); + } + + static size_t GetFirstIndex(absl::Span stack_trace) { + return DefaultFilter::GetFirstHash(stack_trace) % DefaultFilter::kSize; + } + + void* stack_trace1_val_ = nullptr; + absl::Span stack_trace1_{&stack_trace1_val_, 1}; + void* stack_trace2_val_ = nullptr; + absl::Span stack_trace2_{&stack_trace2_val_, 1}; + void* stack_trace3_val_ = nullptr; + absl::Span stack_trace3_{&stack_trace3_val_, 1}; + void* collider_stack_trace_val_ = nullptr; + absl::Span collider_stack_trace_{&collider_stack_trace_val_, 1}; +}; + +namespace { + +// This test proves that class can be owned by a constexpr constructor class. +// This is required as the class will be instantiated within +// tcmalloc::tcmalloc_internal::Static. +TEST_F(StackTraceFilterTest, ConstexprConstructor) { + class Wrapper { + public: + constexpr Wrapper() = default; + DefaultFilter filter_; + }; + + // Instantiate + [[maybe_unused]] Wrapper wrapper; +} + +TEST_F(StackTraceFilterTest, InitialState) { + DefaultFilter filter; + EXPECT_FALSE(filter.Contains(stack_trace1_)); +} + +TEST_F(StackTraceFilterTest, AddRemove) { + DefaultFilter filter; + for (int i = 0; i < 100; ++i) { + filter.Add(stack_trace1_, i); + EXPECT_EQ(i > 0, filter.Contains(stack_trace1_)); + } + for (int i = 0; i < 100; ++i) { + filter.Add(stack_trace1_, -i); + } + EXPECT_FALSE(filter.Contains(stack_trace1_)); +} + +TEST_F(StackTraceFilterTest, CollisionFalsePositive) { + InitializeColliderStackTrace(); + // False positive because of collision ... + DefaultFilter filter; + filter.Add(stack_trace1_, 1); + EXPECT_TRUE(filter.Contains(stack_trace1_)); + EXPECT_TRUE(filter.Contains(collider_stack_trace_)); + + filter.Add(stack_trace1_, -1); + EXPECT_FALSE(filter.Contains(stack_trace1_)); + EXPECT_FALSE(filter.Contains(collider_stack_trace_)); + + filter.Add(collider_stack_trace_, 1); + EXPECT_TRUE(filter.Contains(stack_trace1_)); + EXPECT_TRUE(filter.Contains(collider_stack_trace_)); +} + +TEST_F(StackTraceFilterTest, CollisionMultiHash) { + InitializeColliderStackTrace(); + // ... but with additional hash functions the probability of collision + // decreases. + StackTraceFilter<256, 10> filter; + filter.Add(stack_trace1_, 1); + EXPECT_TRUE(filter.Contains(stack_trace1_)); + EXPECT_FALSE(filter.Contains(collider_stack_trace_)); + + filter.Add(collider_stack_trace_, 1); + EXPECT_TRUE(filter.Contains(stack_trace1_)); + EXPECT_TRUE(filter.Contains(collider_stack_trace_)); + + filter.Add(stack_trace1_, -1); + EXPECT_FALSE(filter.Contains(stack_trace1_)); + EXPECT_TRUE(filter.Contains(collider_stack_trace_)); + + filter.Add(collider_stack_trace_, -1); + EXPECT_FALSE(filter.Contains(stack_trace1_)); + EXPECT_FALSE(filter.Contains(collider_stack_trace_)); +} + +// Just test that integer wrap around does not trigger any hardening checks, +// because for our CBF wrap around is benign. +TEST_F(StackTraceFilterTest, IntegerWrapAround) { + DefaultFilter filter; + filter.Add(stack_trace1_, 1); + EXPECT_TRUE(filter.Contains(stack_trace1_)); + filter.Add(stack_trace1_, ~0u); + EXPECT_FALSE(filter.Contains(stack_trace1_)); +} + +class DecayingStackTraceFilterTest : public StackTraceFilterTest { + protected: + static constexpr size_t kDecaySteps = 3; + using DefaultFilter = DecayingStackTraceFilter<256, 10, kDecaySteps>; +}; + +TEST_F(DecayingStackTraceFilterTest, AddAndDecay) { + DefaultFilter filter; + for (int i = 0; i < 10; ++i) { + filter.Add(stack_trace1_, i); + for (int j = 0; j < kDecaySteps; ++j) { + EXPECT_TRUE(filter.Contains(stack_trace1_)); + filter.Decay(); + } + if (i) { + // If non-zero addition, we need to negate it as well. + EXPECT_TRUE(filter.Contains(stack_trace1_)); + filter.Add(stack_trace1_, -i); + } + EXPECT_FALSE(filter.Contains(stack_trace1_)); + } +} + +TEST_F(DecayingStackTraceFilterTest, AddAndAdd) { + DefaultFilter filter; + for (int i = 0; i < 10; ++i) { + filter.Add(stack_trace1_, i); + for (int j = 0; j < kDecaySteps; ++j) { + EXPECT_TRUE(filter.Contains(stack_trace1_)); + filter.Add(stack_trace2_, 0); // implies decay + } + if (i) { + // If non-zero addition, we need to negate it as well. + EXPECT_TRUE(filter.Contains(stack_trace1_)); + filter.Add(stack_trace1_, -i); + } + EXPECT_FALSE(filter.Contains(stack_trace1_)); + EXPECT_TRUE(filter.Contains(stack_trace2_)); + } +} + +TEST_F(DecayingStackTraceFilterTest, DecayAll) { + DefaultFilter filter; + filter.Add(stack_trace1_, 1); + filter.Add(stack_trace1_, -1); + EXPECT_TRUE(filter.Contains(stack_trace1_)); + filter.DecayAll(); + EXPECT_FALSE(filter.Contains(stack_trace1_)); +} + +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/sysinfo.cc b/contrib/libs/tcmalloc/tcmalloc/internal/sysinfo.cc new file mode 100644 index 000000000000..50252e821dcd --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/sysinfo.cc @@ -0,0 +1,147 @@ +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/sysinfo.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include "absl/base/optimization.h" +#include "absl/functional/function_ref.h" +#include "absl/strings/numbers.h" +#include "absl/strings/string_view.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/cpu_utils.h" +#include "tcmalloc/internal/util.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +#if __linux__ +namespace { +bool IsInBounds(int cpu) { return 0 <= cpu && cpu < kMaxCpus; } +} // namespace + +std::optional ParseCpulist( + absl::FunctionRef read) { + CpuSet set; + set.Zero(); + + std::array buf; + size_t carry_over = 0; + int cpu_from = -1; + + while (true) { + const ssize_t rc = read(buf.data() + carry_over, buf.size() - carry_over); + if (ABSL_PREDICT_FALSE(rc < 0)) { + return std::nullopt; + } + + const absl::string_view current(buf.data(), carry_over + rc); + + // If we have no more data to parse & couldn't read any then we've reached + // the end of the input & are done. + if (current.empty() && rc == 0) { + break; + } + if (current == "\n" && rc == 0) { + break; + } + + size_t consumed; + const size_t dash = current.find('-'); + const size_t comma = current.find(','); + if (dash != absl::string_view::npos && dash < comma) { + if (!absl::SimpleAtoi(current.substr(0, dash), &cpu_from) || + !IsInBounds(cpu_from)) { + return std::nullopt; + } + consumed = dash + 1; + } else if (comma != absl::string_view::npos || rc == 0) { + int cpu; + if (!absl::SimpleAtoi(current.substr(0, comma), &cpu) || + !IsInBounds(cpu)) { + return std::nullopt; + } + if (comma == absl::string_view::npos) { + consumed = current.size(); + } else { + consumed = comma + 1; + } + if (cpu_from != -1) { + for (int c = cpu_from; c <= cpu; c++) { + set.Set(c); + } + cpu_from = -1; + } else { + set.Set(cpu); + } + } else { + consumed = 0; + } + + carry_over = current.size() - consumed; + memmove(buf.data(), buf.data() + consumed, carry_over); + } + + return set; +} + +namespace sysinfo_internal { + +std::optional NumPossibleCPUsNoCache() { + int fd = signal_safe_open("/sys/devices/system/cpu/possible", + O_RDONLY | O_CLOEXEC); + + // This is slightly more state than we actually need, but it lets us reuse + // an already fuzz tested implementation detail. + std::optional cpus = + ParseCpulist([&](char* const buf, const size_t count) { + return signal_safe_read(fd, buf, count, /*bytes_read=*/nullptr); + }); + + signal_safe_close(fd); + + if (!cpus.has_value()) { + return std::nullopt; + } + + std::optional max_so_far; + for (int i = 0; i < kMaxCpus; ++i) { + if (cpus->IsSet(i)) { + max_so_far = std::max(i, max_so_far.value_or(-1)); + } + } + + if (!max_so_far.has_value()) { + return std::nullopt; + } + + return *max_so_far + 1; +} + +} // namespace sysinfo_internal + +#endif // __linux__ + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/sysinfo.h b/contrib/libs/tcmalloc/tcmalloc/internal/sysinfo.h new file mode 100644 index 000000000000..3cc218fbe95b --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/sysinfo.h @@ -0,0 +1,80 @@ +#pragma clang system_header +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_INTERNAL_SYSINFO_H_ +#define TCMALLOC_INTERNAL_SYSINFO_H_ + +#include +#include + +#include +#include + +#include "absl/base/attributes.h" +#include "absl/base/call_once.h" +#include "absl/functional/function_ref.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/cpu_utils.h" +#include "tcmalloc/internal/logging.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +#if __linux__ +// Parse a CPU list in the format used by +// /sys/devices/system/node/nodeX/cpulist files - that is, individual CPU +// numbers or ranges in the format - inclusive all joined by comma +// characters. +// +// Returns std::nullopt on error. +// +// The read function is expected to operate much like the read syscall. It +// should read up to `count` bytes into `buf` and return the number of bytes +// actually read. If an error occurs during reading it should return -1 with +// errno set to an appropriate error code. read should handle EINTR and retry. +std::optional ParseCpulist( + absl::FunctionRef read); + +namespace sysinfo_internal { + +// Returns the number of possible CPUs on the machine, including currently +// offline CPUs. If this cannot be retrieved, std::nullopt is returned. +// +// The result of this function is not cached internally. +std::optional NumPossibleCPUsNoCache(); + +} // namespace sysinfo_internal +#endif // __linux__ + +inline std::optional NumCPUsMaybe() { + ABSL_CONST_INIT static absl::once_flag flag; + ABSL_CONST_INIT static std::optional result; + absl::base_internal::LowLevelCallOnce( + &flag, [&]() { result = sysinfo_internal::NumPossibleCPUsNoCache(); }); + return result; +} + +inline int NumCPUs() { + std::optional maybe_cpus = NumCPUsMaybe(); + TC_CHECK(maybe_cpus.has_value()); + return *maybe_cpus; +} + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_INTERNAL_SYSINFO_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/sysinfo_fuzz.cc b/contrib/libs/tcmalloc/tcmalloc/internal/sysinfo_fuzz.cc new file mode 100644 index 000000000000..d5ae38d250bf --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/sysinfo_fuzz.cc @@ -0,0 +1,48 @@ +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include "fuzztest/fuzztest.h" +#include "tcmalloc/internal/cpu_utils.h" +#include "tcmalloc/internal/sysinfo.h" + +namespace tcmalloc::tcmalloc_internal { +namespace { + +void ParseInput(const std::string& s) { + const char* data = s.data(); + size_t size = s.size(); + + std::optional r = + ParseCpulist([&](char* buf, size_t count) -> ssize_t { + size_t to_read = std::min(size, count); + if (to_read > 0) { + memcpy(buf, data, to_read); + data += to_read; + size -= to_read; + } + return to_read; + }); + (void)r; +} + +FUZZ_TEST(SysinfoTest, ParseInput) + ; + +} // namespace +} // namespace tcmalloc::tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/sysinfo_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/sysinfo_test.cc new file mode 100644 index 000000000000..950f6f344ea8 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/sysinfo_test.cc @@ -0,0 +1,181 @@ +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "tcmalloc/internal/sysinfo.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/base/internal/sysinfo.h" +#include "absl/random/random.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_join.h" +#include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "tcmalloc/internal/allocation_guard.h" +#include "tcmalloc/internal/cpu_utils.h" + +namespace tcmalloc { +namespace tcmalloc_internal { +namespace { + +TEST(ParseCpulistTest, Empty) { + absl::string_view empty("\n"); + + const absl::optional parsed = + ParseCpulist([&](char* const buf, const size_t count) -> ssize_t { + // Calculate how much data we have left to provide. + const size_t to_copy = std::min(count, empty.size()); + + // If none, we have no choice but to provide nothing. + if (to_copy == 0) return 0; + + memcpy(buf, empty.data(), to_copy); + empty.remove_prefix(to_copy); + return to_copy; + }); + + // No CPUs should be active on this NUMA node. + ASSERT_THAT(parsed, testing::Ne(std::nullopt)); + EXPECT_EQ(parsed->Count(), 0); +} + +TEST(ParseCpulistTest, AtBounds) { + std::string cpulist = absl::StrCat("0-", kMaxCpus - 1); + + const absl::optional parsed = + ParseCpulist([&](char* const buf, const size_t count) -> ssize_t { + // Calculate how much data we have left to provide. + const size_t to_copy = std::min(count, cpulist.size()); + + // If none, we have no choice but to provide nothing. + if (to_copy == 0) return 0; + + memcpy(buf, cpulist.data(), to_copy); + cpulist.erase(0, to_copy); + return to_copy; + }); + + // All CPUs should be active on this NUMA node. + ASSERT_THAT(parsed, testing::Ne(std::nullopt)); + EXPECT_EQ(parsed->Count(), kMaxCpus); +} + +TEST(ParseCpulistTest, NotInBounds) { + std::string cpulist = absl::StrCat("0-", kMaxCpus); + + const absl::optional parsed = + ParseCpulist([&](char* const buf, const size_t count) -> ssize_t { + // Calculate how much data we have left to provide. + const size_t to_copy = std::min(count, cpulist.size()); + + // If none, we have no choice but to provide nothing. + if (to_copy == 0) return 0; + + memcpy(buf, cpulist.data(), to_copy); + cpulist.erase(0, to_copy); + return to_copy; + }); + + ASSERT_THAT(parsed, testing::Eq(std::nullopt)); +} + +// Ensure that we can parse randomized cpulists correctly. +TEST(ParseCpulistTest, Random) { + absl::BitGen gen; + + static constexpr int kIterations = 100; + for (int i = 0; i < kIterations; i++) { + CpuSet reference; + reference.Zero(); + + // Set a random number of CPUs within the reference set. + const double density = absl::Uniform(gen, 0.0, 1.0); + for (int cpu = 0; cpu < kMaxCpus; cpu++) { + if (absl::Bernoulli(gen, density)) { + reference.Set(cpu); + } + } + + // Serialize the reference set into a cpulist-style string. + std::vector components; + for (int cpu = 0; cpu < kMaxCpus; cpu++) { + if (!reference.IsSet(cpu)) continue; + + const int start = cpu; + int next = cpu + 1; + while (next < kMaxCpus && reference.IsSet(next)) { + cpu = next; + next = cpu + 1; + } + + if (cpu == start) { + components.push_back(absl::StrCat(cpu)); + } else { + components.push_back(absl::StrCat(start, "-", cpu)); + } + } + const std::string serialized = absl::StrJoin(components, ","); + + // Now parse that string using our ParseCpulist function, randomizing the + // amount of data we provide to it from each read. + absl::string_view remaining(serialized); + const absl::optional parsed = + ParseCpulist([&](char* const buf, const size_t count) -> ssize_t { + // Calculate how much data we have left to provide. + const size_t max = std::min(count, remaining.size()); + + // If none, we have no choice but to provide nothing. + if (max == 0) return 0; + + // If we do have data, return a randomly sized subset of it to stress + // the logic around reading partial values. + const size_t copy = absl::Uniform(gen, static_cast(1), max); + memcpy(buf, remaining.data(), copy); + remaining.remove_prefix(copy); + return copy; + }); + + // We ought to have parsed the same set of CPUs that we serialized. + ASSERT_THAT(parsed, testing::Ne(std::nullopt)); + EXPECT_TRUE(CPU_EQUAL_S(kCpuSetBytes, parsed->data(), reference.data())); + } +} + +TEST(NumCPUs, NoCache) { + const int result = []() { + AllocationGuard guard; + return *sysinfo_internal::NumPossibleCPUsNoCache(); + }(); + + // TODO(b/67389555): This test may fail if there are offlined CPUs. + EXPECT_EQ(result, absl::base_internal::NumCPUs()); +} + +TEST(NumCPUs, Cached) { + // TODO(b/67389555): This test may fail if there are offlined CPUs. + EXPECT_EQ(NumCPUs(), absl::base_internal::NumCPUs()); +} + +} // namespace +} // namespace tcmalloc_internal +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/testdata/profile_builder_fuzz/clusterfuzz-testcase-minimized-profile_builder_fuzz-5534221534363648 b/contrib/libs/tcmalloc/tcmalloc/internal/testdata/profile_builder_fuzz/clusterfuzz-testcase-minimized-profile_builder_fuzz-5534221534363648 new file mode 100644 index 0000000000000000000000000000000000000000..4f148062426d06ccd0526192f85c9637de3b1a02 GIT binary patch literal 16 UcmZQ!U|{$U1k6C%-7k~@04(kV?f?J) literal 0 HcmV?d00001 diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/testdata/profile_builder_fuzz/clusterfuzz-testcase-minimized-profile_builder_fuzz-5647243657216000 b/contrib/libs/tcmalloc/tcmalloc/internal/testdata/profile_builder_fuzz/clusterfuzz-testcase-minimized-profile_builder_fuzz-5647243657216000 new file mode 100644 index 0000000000000000000000000000000000000000..4f148062426d06ccd0526192f85c9637de3b1a02 GIT binary patch literal 16 UcmZQ!U|{$U1k6C%-7k~@04(kV?f?J) literal 0 HcmV?d00001 diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/testdata/profile_builder_fuzz/clusterfuzz-testcase-minimized-profile_builder_fuzz-5915530833559552 b/contrib/libs/tcmalloc/tcmalloc/internal/testdata/profile_builder_fuzz/clusterfuzz-testcase-minimized-profile_builder_fuzz-5915530833559552 new file mode 100644 index 0000000000000000000000000000000000000000..8ef030e030e9893df4c0cbc223946b0499953085 GIT binary patch literal 12 ScmZQ!U|{(D|NnnxAPoQ-4g>%I literal 0 HcmV?d00001 diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/testdata/profile_builder_fuzz/clusterfuzz-testcase-minimized-profile_builder_fuzz-6685031907328000.fuzz b/contrib/libs/tcmalloc/tcmalloc/internal/testdata/profile_builder_fuzz/clusterfuzz-testcase-minimized-profile_builder_fuzz-6685031907328000.fuzz new file mode 100644 index 0000000000000000000000000000000000000000..9c88f4b010401328921f6a0ceeca9321eb7b2a72 GIT binary patch literal 84 zcmZQ!U|{$U1k6C%-7l2ke-Q`(IRXp}AQlUR$$%lx!0->G4+ua~U f, + // receives the offset of the entry and the entry itself. Offsets are relative + // to the beginning of the buffer. + void Iter(absl::FunctionRef f, SkipEntriesSetting skip_entries) const; // Iterates over the last num_epochs data points (if -1, iterate to the // oldest entry). Offsets are relative to the end of the buffer. - void IterBackwards(absl::FunctionRef f, + void IterBackwards(absl::FunctionRef f, int64_t num_epochs = -1) const; // This retrieves a particular data point (if offset is outside the valid @@ -139,16 +140,13 @@ bool TimeSeriesTracker::UpdateClock() { template void TimeSeriesTracker::Iter( - absl::FunctionRef f, + absl::FunctionRef f, SkipEntriesSetting skip_entries) const { size_t j = current_epoch_ + 1; if (j == kEpochs) j = 0; - int64_t timestamp = - (last_epoch_ - kEpochs) * absl::ToInt64Nanoseconds(epoch_length_); for (int offset = 0; offset < kEpochs; offset++) { - timestamp += absl::ToInt64Nanoseconds(epoch_length_); if (skip_entries == kDoNotSkipEmptyEntries || !entries_[j].empty()) { - f(offset, timestamp, entries_[j]); + f(offset, entries_[j]); } j++; if (j == kEpochs) j = 0; @@ -157,18 +155,13 @@ void TimeSeriesTracker::Iter( template void TimeSeriesTracker::IterBackwards( - absl::FunctionRef f, - int64_t num_epochs) const { + absl::FunctionRef f, int64_t num_epochs) const { // -1 means that we are outputting all epochs. num_epochs = (num_epochs == -1) ? kEpochs : num_epochs; size_t j = current_epoch_; - ASSERT(num_epochs <= kEpochs); - int64_t timestamp = last_epoch_ * absl::ToInt64Nanoseconds(epoch_length_); + TC_ASSERT_LE(num_epochs, kEpochs); for (size_t offset = 0; offset < num_epochs; ++offset) { - // This is deliberately int64_t and not a time unit, since clock_ is not - // guaranteed to be a real time base. - f(offset, timestamp, entries_[j]); - timestamp -= absl::ToInt64Nanoseconds(epoch_length_); + f(offset, entries_[j]); if (j == 0) j = kEpochs; --j; } @@ -182,7 +175,7 @@ const T TimeSeriesTracker::GetEpochAtOffset(size_t offset) { } template -bool TimeSeriesTracker::Report(S val) { +bool TimeSeriesTracker::Report(const S& val) { bool updated_clock = UpdateClock(); entries_[current_epoch_].Report(val); return updated_clock; diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/timeseries_tracker_test.cc b/contrib/libs/tcmalloc/tcmalloc/internal/timeseries_tracker_test.cc index 1f753061616c..aee5d440778f 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/timeseries_tracker_test.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/timeseries_tracker_test.cc @@ -14,8 +14,16 @@ #include "tcmalloc/internal/timeseries_tracker.h" +#include +#include +#include + #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "absl/base/internal/cycleclock.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" +#include "tcmalloc/internal/clock.h" using ::testing::ElementsAre; @@ -72,8 +80,7 @@ TEST(TimeSeriesTest, CycleClock) { int num_timestamps = 0; int offset_1, offset_2; tracker.Iter( - [&](size_t offset, int64_t ts, - const TimeSeriesTrackerTest::TestEntry& e) { + [&](size_t offset, const TimeSeriesTrackerTest::TestEntry& e) { ASSERT_LT(num_timestamps, 2); if (num_timestamps == 0) { offset_1 = offset; @@ -92,7 +99,6 @@ TEST(TimeSeriesTest, CycleClock) { } TEST_F(TimeSeriesTrackerTest, Works) { - const int64_t kEpochLength = absl::ToInt64Nanoseconds(kDuration) / 8; Advance(kDuration); tracker_.Report(1); @@ -105,17 +111,13 @@ TEST_F(TimeSeriesTrackerTest, Works) { int num_timestamps = 0; int offset_1, offset_2; tracker_.Iter( - [&](size_t offset, int64_t ts, const TestEntry& e) { + [&](size_t offset, const TestEntry& e) { ASSERT_LT(num_timestamps, 2); if (num_timestamps == 0) { offset_1 = offset; - EXPECT_EQ(absl::ToInt64Nanoseconds(kDuration), ts); EXPECT_THAT(e.values_, ElementsAre(1, 2)); } else { offset_2 = offset; - EXPECT_EQ(absl::ToInt64Nanoseconds(kDuration) + - absl::ToInt64Nanoseconds(kDuration) / 4, - ts); EXPECT_THAT(e.values_, ElementsAre(4)); } num_timestamps++; @@ -128,14 +130,11 @@ TEST_F(TimeSeriesTrackerTest, Works) { Advance(kDuration / 4); // Iterate through entries not skipping empty entries. - int64_t expected_timestamp = absl::ToInt64Nanoseconds(kDuration) / 4; num_timestamps = 0; tracker_.Iter( - [&](size_t offset, int64_t ts, const TestEntry& e) { - expected_timestamp += kEpochLength; + [&](size_t offset, const TestEntry& e) { ASSERT_LT(num_timestamps, 8); - EXPECT_EQ(expected_timestamp, ts); num_timestamps++; }, tracker_.kDoNotSkipEmptyEntries); @@ -148,13 +147,10 @@ TEST_F(TimeSeriesTrackerTest, Works) { // Iterate backwards. num_timestamps = 0; - expected_timestamp = - 7 * absl::ToInt64Nanoseconds(kDuration) / 4; // Current time tracker_.IterBackwards( - [&](size_t offset, int64_t ts, const TestEntry& e) { + [&](size_t offset, const TestEntry& e) { ASSERT_LT(num_timestamps, 3); EXPECT_EQ(num_timestamps, offset); - EXPECT_EQ(expected_timestamp, ts); if (num_timestamps == 0) { EXPECT_THAT(e.values_, ElementsAre(16)); } else if (num_timestamps == 1) { @@ -162,7 +158,6 @@ TEST_F(TimeSeriesTrackerTest, Works) { } else { EXPECT_THAT(e.values_, ElementsAre(8)); } - expected_timestamp -= kEpochLength; num_timestamps++; }, 3); @@ -174,12 +169,12 @@ TEST_F(TimeSeriesTrackerTest, Works) { EXPECT_TRUE(tracker_.GetEpochAtOffset(3).empty()); EXPECT_TRUE(tracker_.GetEpochAtOffset(1000).empty()); - // This should annilate everything. + // This should annihilate everything. Advance(kDuration * 2); tracker_.UpdateTimeBase(); tracker_.Iter( - [&](size_t offset, int64_t ts, const TestEntry& e) { - ASSERT_TRUE(false) << "Time series should be empty"; + [&](size_t offset, const TestEntry& e) { + FAIL() << "Time series should be empty"; }, tracker_.kSkipEmptyEntries); diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/util.cc b/contrib/libs/tcmalloc/tcmalloc/internal/util.cc index ef705b02e38e..5f26e286ea30 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/util.cc +++ b/contrib/libs/tcmalloc/tcmalloc/internal/util.cc @@ -21,11 +21,11 @@ #include #include -#include +#include #include "absl/time/clock.h" #include "absl/time/time.h" -#include "tcmalloc/internal/logging.h" +#include "tcmalloc/internal/config.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { @@ -34,9 +34,11 @@ namespace tcmalloc_internal { int signal_safe_open(const char* path, int flags, ...) { int fd; va_list ap; + using mode_t_va_arg_type = + std::conditional::type; va_start(ap, flags); - mode_t mode = va_arg(ap, mode_t); + mode_t mode = va_arg(ap, mode_t_va_arg_type); va_end(ap); do { @@ -121,75 +123,6 @@ ssize_t signal_safe_read(int fd, char* buf, size_t count, size_t* bytes_read) { return rc; } -std::vector AllowedCpus() { - // We have no need for dynamically sized sets (currently >1024 CPUs for glibc) - // at the present time. We could change this in the future. - cpu_set_t allowed_cpus; - CHECK_CONDITION(sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus) == - 0); - int n = CPU_COUNT(&allowed_cpus), c = 0; - - std::vector result(n); - for (int i = 0; i < CPU_SETSIZE && n; i++) { - if (CPU_ISSET(i, &allowed_cpus)) { - result[c++] = i; - n--; - } - } - CHECK_CONDITION(0 == n); - - return result; -} - -static cpu_set_t SpanToCpuSetT(absl::Span mask) { - cpu_set_t result; - CPU_ZERO(&result); - for (int cpu : mask) { - CPU_SET(cpu, &result); - } - return result; -} - -ScopedAffinityMask::ScopedAffinityMask(absl::Span allowed_cpus) { - specified_cpus_ = SpanToCpuSetT(allowed_cpus); - // getaffinity should never fail. - CHECK_CONDITION( - sched_getaffinity(0, sizeof(original_cpus_), &original_cpus_) == 0); - // See destructor comments on setaffinity interactions. Tampered() will - // necessarily be true in this case. - sched_setaffinity(0, sizeof(specified_cpus_), &specified_cpus_); -} - -ScopedAffinityMask::ScopedAffinityMask(int allowed_cpu) { - CPU_ZERO(&specified_cpus_); - CPU_SET(allowed_cpu, &specified_cpus_); - - // getaffinity should never fail. - CHECK_CONDITION( - sched_getaffinity(0, sizeof(original_cpus_), &original_cpus_) == 0); - // See destructor comments on setaffinity interactions. Tampered() will - // necessarily be true in this case. - sched_setaffinity(0, sizeof(specified_cpus_), &specified_cpus_); -} - -ScopedAffinityMask::~ScopedAffinityMask() { - // If something else has already reset our affinity, do not attempt to - // restrict towards our original mask. This is best-effort as the tampering - // may obviously occur during the destruction of *this. - if (!Tampered()) { - // Note: We do not assert success here, conflicts may restrict us from all - // 'original_cpus_'. - sched_setaffinity(0, sizeof(original_cpus_), &original_cpus_); - } -} - -bool ScopedAffinityMask::Tampered() { - cpu_set_t current_cpus; - CHECK_CONDITION(sched_getaffinity(0, sizeof(current_cpus), ¤t_cpus) == - 0); - return !CPU_EQUAL(¤t_cpus, &specified_cpus_); // Mismatch => modified. -} - } // namespace tcmalloc_internal } // namespace tcmalloc GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/util.h b/contrib/libs/tcmalloc/tcmalloc/internal/util.h index b43e32225727..4469685d6c15 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal/util.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal/util.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,21 +16,18 @@ #ifndef TCMALLOC_INTERNAL_UTIL_H_ #define TCMALLOC_INTERNAL_UTIL_H_ +#include #include // IWYU pragma: keep #include #include #include -#include #include #include #include -#include - -#include "absl/base/internal/sysinfo.h" #include "absl/time/time.h" -#include "absl/types/span.h" #include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" #define TCMALLOC_RETRY_ON_TEMP_FAILURE(expression) \ (__extension__({ \ @@ -49,7 +47,7 @@ namespace tcmalloc_internal { // signal_safe_open() - a wrapper for open(2) which ignores signals // Semantics equivalent to open(2): // returns a file-descriptor (>=0) on success, -1 on failure, error in errno -int signal_safe_open(const char *path, int flags, ...); +int signal_safe_open(const char* path, int flags, ...); // signal_safe_close() - a wrapper for close(2) which ignores signals // Semantics equivalent to close(2): @@ -68,8 +66,8 @@ int signal_safe_close(int fd); // flushed from the buffer in the first write. To handle this case the optional // bytes_written parameter is provided, when not-NULL, it will always return the // total bytes written before any error. -ssize_t signal_safe_write(int fd, const char *buf, size_t count, - size_t *bytes_written); +ssize_t signal_safe_write(int fd, const char* buf, size_t count, + size_t* bytes_written); // signal_safe_read() - a wrapper for read(2) which ignores signals // Semantics equivalent to read(2): @@ -83,7 +81,7 @@ ssize_t signal_safe_write(int fd, const char *buf, size_t count, // read by a previous read. To handle this case the optional bytes_written // parameter is provided, when not-NULL, it will always return the total bytes // read before any error. -ssize_t signal_safe_read(int fd, char *buf, size_t count, size_t *bytes_read); +ssize_t signal_safe_read(int fd, char* buf, size_t count, size_t* bytes_read); // signal_safe_poll() - a wrapper for poll(2) which ignores signals // Semantics equivalent to poll(2): @@ -93,42 +91,52 @@ ssize_t signal_safe_read(int fd, char *buf, size_t count, size_t *bytes_read); // poll for data. Unlike ppoll/pselect, signal_safe_poll is *ignoring* signals // not attempting to re-enable them. Protecting us from the traditional races // involved with the latter. -int signal_safe_poll(struct ::pollfd *fds, int nfds, absl::Duration timeout); +int signal_safe_poll(struct ::pollfd* fds, int nfds, absl::Duration timeout); -// Affinity helpers. +class ScopedSigmask { + public: + // Masks all signal handlers. (SIG_SETMASK, All) + ScopedSigmask() noexcept; -// Returns a vector of the which cpus the currently allowed thread is allowed to -// run on. There are no guarantees that this will not change before, after, or -// even during, the call to AllowedCpus(). -std::vector AllowedCpus(); + // No copy, move or assign + ScopedSigmask(const ScopedSigmask&) = delete; + ScopedSigmask& operator=(const ScopedSigmask&) = delete; -// Enacts a scoped affinity mask on the constructing thread. Attempts to -// restore the original affinity mask on destruction. -// -// REQUIRES: For test-use only. Do not use this in production code. -class ScopedAffinityMask { + // Restores the masked signal handlers to its former state. + ~ScopedSigmask() noexcept; + + private: + void Setmask(int how, sigset_t* set, sigset_t* old); + + sigset_t old_set_; +}; + +inline ScopedSigmask::ScopedSigmask() noexcept { + sigset_t set; + sigfillset(&set); + Setmask(SIG_SETMASK, &set, &old_set_); +} + +inline ScopedSigmask::~ScopedSigmask() noexcept { + Setmask(SIG_SETMASK, &old_set_, nullptr); +} + +inline void ScopedSigmask::Setmask(int how, sigset_t* set, sigset_t* old) { + const int result = pthread_sigmask(how, set, old); + TC_CHECK_EQ(result, 0); +} + +// RAII class that will restore errno to the value it has when created. +class ErrnoRestorer { public: - // When racing with an external restriction that has a zero-intersection with - // "allowed_cpus" we will construct, but immediately register as "Tampered()", - // without actual changes to affinity. - explicit ScopedAffinityMask(absl::Span allowed_cpus); - explicit ScopedAffinityMask(int allowed_cpu); - - // Restores original affinity iff our scoped affinity has not been externally - // modified (i.e. Tampered()). Otherwise, the updated affinity is preserved. - ~ScopedAffinityMask(); - - // Returns true if the affinity mask no longer matches what was set at point - // of construction. - // - // Note: This is instantaneous and not fool-proof. It's possible for an - // external affinity modification to subsequently align with our originally - // specified "allowed_cpus". In this case Tampered() will return false when - // time may have been spent executing previously on non-specified cpus. - bool Tampered(); + ErrnoRestorer() : saved_errno_(errno) {} + ~ErrnoRestorer() { errno = saved_errno_; } + + ErrnoRestorer(const ErrnoRestorer&) = delete; + ErrnoRestorer& operator=(const ErrnoRestorer&) = delete; private: - cpu_set_t original_cpus_, specified_cpus_; + int saved_errno_; }; } // namespace tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/internal/ya.make b/contrib/libs/tcmalloc/tcmalloc/internal/ya.make new file mode 100644 index 000000000000..36fd07fe3482 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal/ya.make @@ -0,0 +1,21 @@ +PROTO_LIBRARY() + +VERSION(dummy) + +LICENSE(Apache-2.0) + +WITHOUT_LICENSE_TEXTS() + +EXCLUDE_TAGS( + GO_PROTO + PY_PROTO + JAVA_PROTO +) + +SRC(profile.proto) + +ADDINCL( + GLOBAL contrib/libs/tcmalloc +) + +END() diff --git a/contrib/libs/tcmalloc/tcmalloc/internal_malloc_extension.h b/contrib/libs/tcmalloc/tcmalloc/internal_malloc_extension.h index 66027418ed20..fc29fad7730f 100644 --- a/contrib/libs/tcmalloc/tcmalloc/internal_malloc_extension.h +++ b/contrib/libs/tcmalloc/tcmalloc/internal_malloc_extension.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,10 +21,15 @@ #ifndef TCMALLOC_INTERNAL_MALLOC_EXTENSION_H_ #define TCMALLOC_INTERNAL_MALLOC_EXTENSION_H_ +#include +#include +#include +#include #include +#include #include "absl/base/attributes.h" -#include "absl/functional/function_ref.h" +#include "absl/time/time.h" #include "tcmalloc/malloc_extension.h" namespace tcmalloc { @@ -66,39 +72,71 @@ MallocExtension_Internal_SnapshotCurrent(tcmalloc::ProfileType type); ABSL_ATTRIBUTE_WEAK tcmalloc::tcmalloc_internal::AllocationProfilingTokenBase* MallocExtension_Internal_StartAllocationProfiling(); +ABSL_ATTRIBUTE_WEAK tcmalloc::tcmalloc_internal::AllocationProfilingTokenBase* +MallocExtension_Internal_StartLifetimeProfiling(); ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_ActivateGuardedSampling(); ABSL_ATTRIBUTE_WEAK tcmalloc::MallocExtension::Ownership MallocExtension_Internal_GetOwnership(const void* ptr); -ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_GetMemoryLimit( - tcmalloc::MallocExtension::MemoryLimit* limit); +ABSL_ATTRIBUTE_WEAK size_t MallocExtension_Internal_GetMemoryLimit( + tcmalloc::MallocExtension::LimitKind limit_kind); ABSL_ATTRIBUTE_WEAK bool MallocExtension_Internal_GetNumericProperty( const char* name_data, size_t name_size, size_t* value); ABSL_ATTRIBUTE_WEAK bool MallocExtension_Internal_GetPerCpuCachesActive(); -ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_DeactivatePerCpuCaches(); ABSL_ATTRIBUTE_WEAK int32_t MallocExtension_Internal_GetMaxPerCpuCacheSize(); +ABSL_ATTRIBUTE_WEAK bool +MallocExtension_Internal_GetBackgroundProcessActionsEnabled(); +ABSL_ATTRIBUTE_WEAK void +MallocExtension_Internal_GetBackgroundProcessSleepInterval(absl::Duration* ret); ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_GetSkipSubreleaseInterval( absl::Duration* ret); +ABSL_ATTRIBUTE_WEAK void +MallocExtension_Internal_GetSkipSubreleaseShortInterval(absl::Duration* ret); +ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_GetSkipSubreleaseLongInterval( + absl::Duration* ret); +ABSL_ATTRIBUTE_WEAK void +MallocExtension_Internal_GetCacheDemandReleaseShortInterval( + absl::Duration* ret); +ABSL_ATTRIBUTE_WEAK void +MallocExtension_Internal_GetCacheDemandReleaseLongInterval(absl::Duration* ret); ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_GetProperties( std::map* ret); +ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_GetExperiments( + std::map* ret); ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_GetStats(std::string* ret); ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_SetMaxPerCpuCacheSize( int32_t value); +ABSL_ATTRIBUTE_WEAK void +MallocExtension_Internal_SetBackgroundProcessActionsEnabled(bool value); +ABSL_ATTRIBUTE_WEAK void +MallocExtension_Internal_SetBackgroundProcessSleepInterval( + absl::Duration value); ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_SetSkipSubreleaseInterval( absl::Duration value); +ABSL_ATTRIBUTE_WEAK void +MallocExtension_Internal_SetSkipSubreleaseShortInterval(absl::Duration value); +ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_SetSkipSubreleaseLongInterval( + absl::Duration value); +ABSL_ATTRIBUTE_WEAK void +MallocExtension_Internal_SetCacheDemandReleaseShortInterval( + absl::Duration value); +ABSL_ATTRIBUTE_WEAK void +MallocExtension_Internal_SetCacheDemandReleaseLongInterval( + absl::Duration value); ABSL_ATTRIBUTE_WEAK size_t MallocExtension_Internal_ReleaseCpuMemory(int cpu); -ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_ReleaseMemoryToSystem( - size_t bytes); +ABSL_ATTRIBUTE_WEAK size_t +MallocExtension_Internal_ReleaseMemoryToSystem(size_t bytes); ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_SetMemoryLimit( - const tcmalloc::MallocExtension::MemoryLimit* limit); + size_t limit, tcmalloc::MallocExtension::LimitKind limit_kind); ABSL_ATTRIBUTE_WEAK size_t MallocExtension_Internal_GetAllocatedSize(const void* ptr); ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_MarkThreadBusy(); ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_MarkThreadIdle(); -ABSL_ATTRIBUTE_WEAK int64_t MallocExtension_Internal_GetProfileSamplingRate(); -ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_SetProfileSamplingRate( +ABSL_ATTRIBUTE_WEAK int64_t +MallocExtension_Internal_GetProfileSamplingInterval(); +ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_SetProfileSamplingInterval( int64_t); ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_ProcessBackgroundActions(); @@ -108,8 +146,9 @@ MallocExtension_Internal_GetBackgroundReleaseRate(); ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_SetBackgroundReleaseRate( tcmalloc::MallocExtension::BytesPerSecond); -ABSL_ATTRIBUTE_WEAK int64_t MallocExtension_Internal_GetGuardedSamplingRate(); -ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_SetGuardedSamplingRate( +ABSL_ATTRIBUTE_WEAK int64_t +MallocExtension_Internal_GetGuardedSamplingInterval(); +ABSL_ATTRIBUTE_WEAK void MallocExtension_Internal_SetGuardedSamplingInterval( int64_t); ABSL_ATTRIBUTE_WEAK int64_t @@ -125,7 +164,6 @@ MallocExtension_SetSampleUserDataCallbacks( tcmalloc::MallocExtension::CreateSampleUserDataCallback create, tcmalloc::MallocExtension::CopySampleUserDataCallback copy, tcmalloc::MallocExtension::DestroySampleUserDataCallback destroy); - } #endif diff --git a/contrib/libs/tcmalloc/tcmalloc/internal_malloc_tracing_extension.h b/contrib/libs/tcmalloc/tcmalloc/internal_malloc_tracing_extension.h new file mode 100644 index 000000000000..f747c9bb9362 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/internal_malloc_tracing_extension.h @@ -0,0 +1,36 @@ +#pragma clang system_header +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Extra extensions exported by some malloc implementations. These +// extensions are accessed through a virtual base class so an +// application can link against a malloc that does not implement these +// extensions, and it will get default versions that do nothing. + +#ifndef TCMALLOC_INTERNAL_MALLOC_TRACING_EXTENSION_H_ +#define TCMALLOC_INTERNAL_MALLOC_TRACING_EXTENSION_H_ + +#include "absl/base/attributes.h" +#include "absl/status/statusor.h" +#include "tcmalloc/malloc_tracing_extension.h" + +#if ABSL_HAVE_ATTRIBUTE_WEAK && !defined(__APPLE__) && !defined(__EMSCRIPTEN__) + +ABSL_ATTRIBUTE_WEAK +absl::StatusOr +MallocTracingExtension_Internal_GetAllocatedAddressRanges(); + +#endif + +#endif // TCMALLOC_INTERNAL_MALLOC_TRACING_EXTENSION_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/legacy_size_classes.cc b/contrib/libs/tcmalloc/tcmalloc/legacy_size_classes.cc index 539525271946..dc6593423031 100644 --- a/contrib/libs/tcmalloc/tcmalloc/legacy_size_classes.cc +++ b/contrib/libs/tcmalloc/tcmalloc/legacy_size_classes.cc @@ -12,358 +12,389 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "absl/types/span.h" #include "tcmalloc/common.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/size_class_info.h" GOOGLE_MALLOC_SECTION_BEGIN namespace tcmalloc { - namespace tcmalloc_internal { -// is fixed per-size-class overhead due to end-of-span fragmentation -// and other factors. For instance, if we have a 96 byte size class, and use a -// single 8KiB page, then we will hold 85 objects per span, and have 32 bytes -// left over. There is also a fixed component of 48 bytes of TCMalloc metadata -// per span. Together, the fixed overhead would be wasted/allocated = -// (32 + 48) / (8192 - 32) ~= 0.98%. -// There is also a dynamic component to overhead based on mismatches between the -// number of bytes requested and the number of bytes provided by the size class. -// Together they sum to the total overhead; for instance if you asked for a -// 50-byte allocation that rounds up to a 64-byte size class, the dynamic -// overhead would be 28%, and if were 22% it would mean (on average) -// 25 bytes of overhead for allocations of that size. +// Columns in the following tables: +// - bytes: size of the size class +// - pages: number of pages per span +// - batch: preferred number of objects for transfers between caches +// - class: size class number +// - objs: number of objects per span +// - waste/fixed: fixed per-size-class overhead due to end-of-span fragmentation +// and other factors. For instance, if we have a 96 byte size class, and use +// a single 8KiB page, then we will hold 85 objects per span, and have 32 +// bytes left over. There is also a fixed component of 48 bytes of TCMalloc +// metadata per span. Together, the fixed overhead would be wasted/allocated +// = (32 + 48) / (8192 - 32) ~= 0.98%. +// - waste/sampling: overhead due to heap sampling +// (rounding to page size, proxy object, metadata). +// - inc: increment from the previous size class. This caps the dynamic +// overhead component based on mismatches between the number of bytes +// requested and the number of bytes provided by the size class. Together +// they sum to the total overhead; for instance if you asked for a 50-byte +// allocation that rounds up to a 64-byte size class, the dynamic overhead +// would be 28%, and if waste were 22% it would mean (on average) 25 bytes +// of overhead for allocations of that size. // clang-format off #if defined(__cpp_aligned_new) && __STDCPP_DEFAULT_NEW_ALIGNMENT__ <= 8 #if TCMALLOC_PAGE_SHIFT == 13 static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 86; -static_assert(kCount <= kNumClasses); -const int SizeMap::kLegacySizeClassesCount = kCount; -const SizeClassInfo SizeMap::kLegacySizeClasses[SizeMap::kLegacySizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.59% - { 16, 1, 32}, // 0.59% - { 24, 1, 32}, // 0.68% - { 32, 1, 32}, // 0.59% - { 40, 1, 32}, // 0.98% - { 48, 1, 32}, // 0.98% - { 56, 1, 32}, // 0.78% - { 64, 1, 32}, // 0.59% - { 72, 1, 32}, // 1.28% - { 80, 1, 32}, // 0.98% - { 88, 1, 32}, // 0.68% - { 96, 1, 32}, // 0.98% - { 104, 1, 32}, // 1.58% - { 112, 1, 32}, // 0.78% - { 120, 1, 32}, // 0.98% - { 128, 1, 32}, // 0.59% - { 136, 1, 32}, // 0.98% - { 144, 1, 32}, // 2.18% - { 160, 1, 32}, // 0.98% - { 176, 1, 32}, // 1.78% - { 192, 1, 32}, // 2.18% - { 208, 1, 32}, // 1.58% - { 224, 1, 32}, // 2.18% - { 240, 1, 32}, // 0.98% - { 256, 1, 32}, // 0.59% - { 272, 1, 32}, // 0.98% - { 296, 1, 32}, // 3.10% - { 312, 1, 32}, // 1.58% - { 336, 1, 32}, // 2.18% - { 352, 1, 32}, // 1.78% - { 368, 1, 32}, // 1.78% - { 408, 1, 32}, // 0.98% - { 448, 1, 32}, // 2.18% - { 480, 1, 32}, // 0.98% - { 512, 1, 32}, // 0.59% - { 576, 1, 32}, // 2.18% - { 640, 1, 32}, // 7.29% - { 704, 1, 32}, // 6.40% - { 768, 1, 32}, // 7.29% - { 896, 1, 32}, // 2.18% - { 1024, 1, 32}, // 0.59% - { 1152, 2, 32}, // 1.88% - { 1280, 2, 32}, // 6.98% - { 1408, 2, 32}, // 6.10% - { 1536, 2, 32}, // 6.98% - { 1792, 2, 32}, // 1.88% - { 2048, 2, 32}, // 0.29% - { 2304, 2, 28}, // 1.88% - { 2688, 2, 24}, // 1.88% - { 2816, 3, 23}, // 9.30% - { 3200, 2, 20}, // 2.70% - { 3456, 3, 18}, // 1.79% - { 3584, 4, 18}, // 1.74% - { 4096, 2, 16}, // 0.29% - { 4736, 3, 13}, // 3.99% - { 5376, 2, 12}, // 1.88% - { 6144, 3, 10}, // 0.20% - { 6528, 4, 10}, // 0.54% - { 7168, 7, 9}, // 0.08% - { 8192, 2, 8}, // 0.29% - { 9472, 5, 6}, // 8.23% - { 10240, 4, 6}, // 6.82% - { 12288, 3, 5}, // 0.20% - { 13568, 5, 4}, // 0.75% - { 14336, 7, 4}, // 0.08% - { 16384, 2, 4}, // 0.29% - { 20480, 5, 3}, // 0.12% - { 24576, 3, 2}, // 0.20% - { 28672, 7, 2}, // 0.08% - { 32768, 4, 2}, // 0.15% - { 40960, 5, 2}, // 0.12% - { 49152, 6, 2}, // 0.10% - { 57344, 7, 2}, // 0.08% - { 65536, 8, 2}, // 0.07% - { 73728, 9, 2}, // 0.07% - { 81920, 10, 2}, // 0.06% - { 98304, 12, 2}, // 0.05% - { 114688, 14, 2}, // 0.04% - { 131072, 16, 2}, // 0.04% - { 147456, 18, 2}, // 0.03% - { 163840, 20, 2}, // 0.03% - { 180224, 22, 2}, // 0.03% - { 204800, 25, 2}, // 0.02% - { 237568, 29, 2}, // 0.02% - { 262144, 32, 2}, // 0.02% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = true, + .span_size = 48, + .sampling_interval = 2097152, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 1024 0.58% 0.42% 0.00% + { 16, 1, 32}, // 1 512 0.58% 0.42% 100.00% + { 24, 1, 32}, // 2 341 0.68% 0.42% 50.00% + { 32, 1, 32}, // 3 256 0.58% 0.42% 33.33% + { 40, 1, 32}, // 4 204 0.97% 0.42% 25.00% + { 48, 1, 32}, // 5 170 0.97% 0.42% 20.00% + { 56, 1, 32}, // 6 146 0.78% 0.42% 16.67% + { 64, 1, 32}, // 7 128 0.58% 0.42% 14.29% + { 72, 1, 32}, // 8 113 1.26% 0.42% 12.50% + { 80, 1, 32}, // 9 102 0.97% 0.42% 11.11% + { 88, 1, 32}, // 10 93 0.68% 0.42% 10.00% + { 96, 1, 32}, // 11 85 0.97% 0.42% 9.09% + { 104, 1, 32}, // 12 78 1.55% 0.42% 8.33% + { 112, 1, 32}, // 13 73 0.78% 0.42% 7.69% + { 120, 1, 32}, // 14 68 0.97% 0.42% 7.14% + { 128, 1, 32}, // 15 64 0.58% 0.42% 6.67% + { 136, 1, 32}, // 16 60 0.97% 0.42% 6.25% + { 144, 1, 32}, // 17 56 2.14% 0.42% 5.88% + { 152, 1, 32}, // 18 53 2.23% 0.42% 5.56% + { 160, 1, 32}, // 19 51 0.97% 0.42% 5.26% + { 168, 1, 32}, // 20 48 2.14% 0.42% 5.00% + { 184, 1, 32}, // 21 44 1.75% 0.42% 9.52% + { 192, 1, 32}, // 22 42 2.14% 0.42% 4.35% + { 208, 1, 32}, // 23 39 1.55% 0.42% 8.33% + { 224, 1, 32}, // 24 36 2.14% 0.42% 7.69% + { 240, 1, 32}, // 25 34 0.97% 0.42% 7.14% + { 256, 1, 32}, // 26 32 0.58% 0.42% 6.67% + { 264, 1, 32}, // 27 31 0.68% 0.42% 3.12% + { 280, 1, 32}, // 28 29 1.46% 0.42% 6.06% + { 312, 1, 32}, // 29 26 1.55% 0.42% 11.43% + { 336, 1, 32}, // 30 24 2.14% 0.42% 7.69% + { 352, 1, 32}, // 31 23 1.75% 0.42% 4.76% + { 384, 1, 32}, // 32 21 2.14% 0.42% 9.09% + { 408, 1, 32}, // 33 20 0.97% 0.42% 6.25% + { 448, 1, 32}, // 34 18 2.14% 0.42% 9.80% + { 480, 1, 32}, // 35 17 0.97% 0.42% 7.14% + { 512, 1, 32}, // 36 16 0.58% 0.42% 6.67% + { 576, 1, 32}, // 37 14 2.14% 0.42% 12.50% + { 640, 1, 32}, // 38 12 6.80% 0.43% 11.11% + { 704, 1, 32}, // 39 11 6.02% 0.43% 10.00% + { 768, 1, 32}, // 40 10 6.80% 0.43% 9.09% + { 896, 1, 32}, // 41 9 2.14% 0.43% 16.67% + { 1024, 1, 32}, // 42 8 0.58% 0.42% 14.29% + { 1152, 2, 32}, // 43 14 1.85% 0.43% 12.50% + { 1280, 2, 32}, // 44 12 6.52% 0.43% 11.11% + { 1408, 2, 32}, // 45 11 5.74% 0.43% 10.00% + { 1536, 2, 32}, // 46 10 6.52% 0.43% 9.09% + { 1792, 2, 32}, // 47 9 1.85% 0.43% 16.67% + { 2048, 2, 32}, // 48 8 0.29% 0.42% 14.29% + { 2304, 2, 28}, // 49 7 1.85% 0.43% 12.50% + { 2688, 2, 24}, // 50 6 1.85% 0.43% 16.67% + { 3200, 2, 20}, // 51 5 2.63% 0.43% 19.05% + { 3584, 4, 18}, // 52 9 1.71% 0.43% 12.00% + { 4096, 1, 16}, // 53 2 0.58% 0.43% 14.29% + { 4736, 3, 13}, // 54 5 3.83% 0.43% 15.62% + { 5376, 2, 12}, // 55 3 1.85% 0.43% 13.51% + { 6144, 3, 10}, // 56 4 0.19% 0.42% 14.29% + { 6528, 4, 10}, // 57 5 0.54% 0.43% 6.25% + { 7168, 7, 9}, // 58 8 0.08% 0.42% 9.80% + { 8192, 1, 8}, // 59 1 0.58% 0.03% 14.29% + { 9472, 5, 6}, // 60 4 7.61% 0.85% 15.62% + { 10240, 4, 6}, // 61 3 6.39% 0.85% 8.11% + { 12288, 3, 5}, // 62 2 0.19% 0.82% 20.00% + { 13568, 5, 4}, // 63 3 0.74% 0.82% 10.42% + { 14336, 7, 4}, // 64 4 0.08% 0.82% 5.66% + { 16384, 2, 4}, // 65 1 0.29% 0.03% 14.29% + { 20480, 5, 3}, // 66 2 0.12% 1.21% 25.00% + { 24576, 3, 2}, // 67 1 0.19% 0.03% 20.00% + { 28672, 7, 2}, // 68 2 0.08% 1.60% 16.67% + { 32768, 4, 2}, // 69 1 0.15% 0.03% 14.29% + { 40960, 5, 2}, // 70 1 0.12% 0.03% 25.00% + { 49152, 6, 2}, // 71 1 0.10% 0.03% 20.00% + { 57344, 7, 2}, // 72 1 0.08% 0.03% 16.67% + { 65536, 8, 2}, // 73 1 0.07% 0.03% 14.29% + { 73728, 9, 2}, // 74 1 0.07% 0.03% 12.50% + { 81920, 10, 2}, // 75 1 0.06% 0.03% 11.11% + { 98304, 12, 2}, // 76 1 0.05% 0.03% 20.00% + {114688, 14, 2}, // 77 1 0.04% 0.03% 16.67% + {131072, 16, 2}, // 78 1 0.04% 0.03% 14.29% + {139264, 17, 2}, // 79 1 0.03% 0.03% 6.25% + {155648, 19, 2}, // 80 1 0.03% 0.03% 11.76% + {180224, 22, 2}, // 81 1 0.03% 0.03% 15.79% + {204800, 25, 2}, // 82 1 0.02% 0.03% 13.64% + {229376, 28, 2}, // 83 1 0.02% 0.03% 12.00% + {262144, 32, 2}, // 84 1 0.02% 0.03% 14.29% }; #elif TCMALLOC_PAGE_SHIFT == 15 static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 78; -static_assert(kCount <= kNumClasses); -const int SizeMap::kLegacySizeClassesCount = kCount; -const SizeClassInfo SizeMap::kLegacySizeClasses[SizeMap::kLegacySizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.15% - { 16, 1, 32}, // 0.15% - { 24, 1, 32}, // 0.17% - { 32, 1, 32}, // 0.15% - { 40, 1, 32}, // 0.17% - { 48, 1, 32}, // 0.24% - { 56, 1, 32}, // 0.17% - { 64, 1, 32}, // 0.15% - { 72, 1, 32}, // 0.17% - { 80, 1, 32}, // 0.29% - { 88, 1, 32}, // 0.24% - { 96, 1, 32}, // 0.24% - { 104, 1, 32}, // 0.17% - { 112, 1, 32}, // 0.34% - { 128, 1, 32}, // 0.15% - { 144, 1, 32}, // 0.39% - { 160, 1, 32}, // 0.54% - { 176, 1, 32}, // 0.24% - { 192, 1, 32}, // 0.54% - { 208, 1, 32}, // 0.49% - { 224, 1, 32}, // 0.34% - { 240, 1, 32}, // 0.54% - { 256, 1, 32}, // 0.15% - { 280, 1, 32}, // 0.17% - { 304, 1, 32}, // 0.89% - { 328, 1, 32}, // 1.06% - { 352, 1, 32}, // 0.24% - { 384, 1, 32}, // 0.54% - { 416, 1, 32}, // 1.13% - { 448, 1, 32}, // 0.34% - { 488, 1, 32}, // 0.37% - { 512, 1, 32}, // 0.15% - { 576, 1, 32}, // 1.74% - { 640, 1, 32}, // 0.54% - { 704, 1, 32}, // 1.33% - { 832, 1, 32}, // 1.13% - { 896, 1, 32}, // 1.74% - { 1024, 1, 32}, // 0.15% - { 1152, 1, 32}, // 1.74% - { 1280, 1, 32}, // 2.55% - { 1536, 1, 32}, // 1.74% - { 1792, 1, 32}, // 1.74% - { 2048, 1, 32}, // 0.15% - { 2176, 1, 30}, // 0.54% - { 2304, 1, 28}, // 1.74% - { 2688, 1, 24}, // 1.74% - { 2944, 1, 22}, // 1.33% - { 3200, 1, 20}, // 2.55% - { 3584, 1, 18}, // 1.74% - { 4096, 1, 16}, // 0.15% - { 4608, 1, 14}, // 1.74% - { 5376, 1, 12}, // 1.74% - { 6528, 1, 10}, // 0.54% - { 7168, 2, 9}, // 1.66% - { 8192, 1, 8}, // 0.15% - { 9344, 2, 7}, // 0.27% - { 10880, 1, 6}, // 0.54% - { 13952, 3, 4}, // 0.70% - { 16384, 1, 4}, // 0.15% - { 19072, 3, 3}, // 3.14% - { 21760, 2, 3}, // 0.47% - { 24576, 3, 2}, // 0.05% - { 28032, 6, 2}, // 0.22% - { 32768, 1, 2}, // 0.15% - { 38144, 5, 2}, // 7.41% - { 40960, 4, 2}, // 6.71% - { 49152, 3, 2}, // 0.05% - { 57344, 7, 2}, // 0.02% - { 65536, 2, 2}, // 0.07% - { 81920, 5, 2}, // 0.03% - { 98304, 3, 2}, // 0.05% - { 114688, 7, 2}, // 0.02% - { 131072, 4, 2}, // 0.04% - { 163840, 5, 2}, // 0.03% - { 196608, 6, 2}, // 0.02% - { 229376, 7, 2}, // 0.02% - { 262144, 8, 2}, // 0.02% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = true, + .span_size = 48, + .sampling_interval = 2097152, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 4096 0.15% 1.60% 0.00% + { 16, 1, 32}, // 1 2048 0.15% 1.60% 100.00% + { 24, 1, 32}, // 2 1365 0.17% 1.60% 50.00% + { 32, 1, 32}, // 3 1024 0.15% 1.60% 33.33% + { 40, 1, 32}, // 4 819 0.17% 1.60% 25.00% + { 48, 1, 32}, // 5 682 0.24% 1.60% 20.00% + { 56, 1, 32}, // 6 585 0.17% 1.60% 16.67% + { 64, 1, 32}, // 7 512 0.15% 1.60% 14.29% + { 72, 1, 32}, // 8 455 0.17% 1.60% 12.50% + { 80, 1, 32}, // 9 409 0.29% 1.60% 11.11% + { 88, 1, 32}, // 10 372 0.24% 1.60% 10.00% + { 96, 1, 32}, // 11 341 0.24% 1.60% 9.09% + { 104, 1, 32}, // 12 315 0.17% 1.60% 8.33% + { 112, 1, 32}, // 13 292 0.34% 1.60% 7.69% + { 120, 1, 32}, // 14 273 0.17% 1.60% 7.14% + { 128, 1, 32}, // 15 256 0.15% 1.60% 6.67% + { 144, 1, 32}, // 16 227 0.39% 1.60% 12.50% + { 160, 1, 32}, // 17 204 0.54% 1.60% 11.11% + { 176, 1, 32}, // 18 186 0.24% 1.60% 10.00% + { 192, 1, 32}, // 19 170 0.54% 1.60% 9.09% + { 208, 1, 32}, // 20 157 0.49% 1.60% 8.33% + { 224, 1, 32}, // 21 146 0.34% 1.60% 7.69% + { 240, 1, 32}, // 22 136 0.54% 1.60% 7.14% + { 256, 1, 32}, // 23 128 0.15% 1.60% 6.67% + { 280, 1, 32}, // 24 117 0.17% 1.60% 9.38% + { 312, 1, 32}, // 25 105 0.17% 1.60% 11.43% + { 344, 1, 32}, // 26 95 0.41% 1.60% 10.26% + { 376, 1, 32}, // 27 87 0.32% 1.60% 9.30% + { 400, 1, 32}, // 28 81 1.27% 1.60% 6.38% + { 448, 1, 32}, // 29 73 0.34% 1.60% 12.00% + { 512, 1, 32}, // 30 64 0.15% 1.60% 14.29% + { 576, 1, 32}, // 31 56 1.71% 1.60% 12.50% + { 640, 1, 32}, // 32 51 0.54% 1.60% 11.11% + { 704, 1, 32}, // 33 46 1.32% 1.60% 10.00% + { 768, 1, 32}, // 34 42 1.71% 1.60% 9.09% + { 896, 1, 32}, // 35 36 1.71% 1.60% 16.67% + { 1024, 1, 32}, // 36 32 0.15% 1.60% 14.29% + { 1152, 1, 32}, // 37 28 1.71% 1.60% 12.50% + { 1280, 1, 32}, // 38 25 2.49% 1.60% 11.11% + { 1536, 1, 32}, // 39 21 1.71% 1.60% 20.00% + { 1664, 1, 32}, // 40 19 3.66% 1.60% 8.33% + { 1920, 1, 32}, // 41 17 0.54% 1.60% 15.38% + { 2048, 1, 32}, // 42 16 0.15% 1.60% 6.67% + { 2176, 1, 30}, // 43 15 0.54% 1.60% 6.25% + { 2432, 1, 26}, // 44 13 3.66% 1.60% 11.76% + { 2688, 1, 24}, // 45 12 1.71% 1.60% 10.53% + { 2944, 1, 22}, // 46 11 1.32% 1.60% 9.52% + { 3200, 1, 20}, // 47 10 2.49% 1.60% 8.70% + { 3584, 1, 18}, // 48 9 1.71% 1.60% 12.00% + { 4096, 1, 16}, // 49 8 0.15% 1.60% 14.29% + { 4608, 1, 14}, // 50 7 1.71% 1.60% 12.50% + { 5376, 1, 12}, // 51 6 1.71% 1.60% 16.67% + { 6528, 1, 10}, // 52 5 0.54% 1.60% 21.43% + { 8192, 1, 8}, // 53 4 0.15% 1.60% 25.49% + { 9344, 2, 7}, // 54 7 0.27% 1.60% 14.06% + { 10880, 1, 6}, // 55 3 0.54% 1.60% 16.44% + { 13056, 2, 5}, // 56 5 0.46% 1.60% 20.00% + { 13952, 3, 4}, // 57 7 0.70% 1.60% 6.86% + { 16384, 1, 4}, // 58 2 0.15% 1.60% 17.43% + { 19072, 3, 3}, // 59 5 3.04% 1.62% 16.41% + { 21760, 2, 3}, // 60 3 0.46% 1.60% 14.09% + { 24576, 3, 2}, // 61 4 0.05% 1.60% 12.94% + { 28672, 7, 2}, // 62 8 0.02% 1.60% 16.67% + { 32768, 1, 2}, // 63 1 0.15% 0.03% 14.29% + { 38144, 5, 2}, // 64 4 6.90% 3.28% 16.41% + { 40960, 4, 2}, // 65 3 6.28% 3.28% 7.38% + { 49152, 3, 2}, // 66 2 0.05% 3.16% 20.00% + { 57344, 7, 2}, // 67 4 0.02% 3.16% 16.67% + { 65536, 2, 2}, // 68 1 0.07% 0.03% 14.29% + { 81920, 5, 2}, // 69 2 0.03% 4.72% 25.00% + { 98304, 3, 2}, // 70 1 0.05% 0.03% 20.00% + {114688, 7, 2}, // 71 2 0.02% 6.28% 16.67% + {131072, 4, 2}, // 72 1 0.04% 0.03% 14.29% + {163840, 5, 2}, // 73 1 0.03% 0.03% 25.00% + {196608, 6, 2}, // 74 1 0.02% 0.03% 20.00% + {229376, 7, 2}, // 75 1 0.02% 0.03% 16.67% + {262144, 8, 2}, // 76 1 0.02% 0.03% 14.29% }; #elif TCMALLOC_PAGE_SHIFT == 18 static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 89; -static_assert(kCount <= kNumClasses); -const int SizeMap::kLegacySizeClassesCount = kCount; -const SizeClassInfo SizeMap::kLegacySizeClasses[SizeMap::kLegacySizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.02% - { 16, 1, 32}, // 0.02% - { 24, 1, 32}, // 0.02% - { 32, 1, 32}, // 0.02% - { 40, 1, 32}, // 0.03% - { 48, 1, 32}, // 0.02% - { 56, 1, 32}, // 0.02% - { 64, 1, 32}, // 0.02% - { 72, 1, 32}, // 0.04% - { 80, 1, 32}, // 0.04% - { 88, 1, 32}, // 0.05% - { 96, 1, 32}, // 0.04% - { 104, 1, 32}, // 0.04% - { 112, 1, 32}, // 0.04% - { 128, 1, 32}, // 0.02% - { 144, 1, 32}, // 0.04% - { 160, 1, 32}, // 0.04% - { 176, 1, 32}, // 0.05% - { 192, 1, 32}, // 0.04% - { 208, 1, 32}, // 0.04% - { 240, 1, 32}, // 0.04% - { 256, 1, 32}, // 0.02% - { 304, 1, 32}, // 0.05% - { 336, 1, 32}, // 0.04% - { 360, 1, 32}, // 0.04% - { 408, 1, 32}, // 0.10% - { 456, 1, 32}, // 0.17% - { 512, 1, 32}, // 0.02% - { 576, 1, 32}, // 0.04% - { 640, 1, 32}, // 0.17% - { 704, 1, 32}, // 0.12% - { 768, 1, 32}, // 0.12% - { 832, 1, 32}, // 0.04% - { 896, 1, 32}, // 0.21% - { 1024, 1, 32}, // 0.02% - { 1152, 1, 32}, // 0.26% - { 1280, 1, 32}, // 0.41% - { 1536, 1, 32}, // 0.41% - { 1664, 1, 32}, // 0.36% - { 1792, 1, 32}, // 0.21% - { 1920, 1, 32}, // 0.41% - { 2048, 1, 32}, // 0.02% - { 2176, 1, 30}, // 0.41% - { 2304, 1, 28}, // 0.71% - { 2432, 1, 26}, // 0.76% - { 2560, 1, 25}, // 0.41% - { 2688, 1, 24}, // 0.56% - { 2816, 1, 23}, // 0.12% - { 2944, 1, 22}, // 0.07% - { 3072, 1, 21}, // 0.41% - { 3328, 1, 19}, // 1.00% - { 3584, 1, 18}, // 0.21% - { 3840, 1, 17}, // 0.41% - { 4096, 1, 16}, // 0.02% - { 4736, 1, 13}, // 0.66% - { 5504, 1, 11}, // 1.35% - { 6144, 1, 10}, // 1.61% - { 6528, 1, 10}, // 0.41% - { 6784, 1, 9}, // 1.71% - { 7168, 1, 9}, // 1.61% - { 7680, 1, 8}, // 0.41% - { 8192, 1, 8}, // 0.02% - { 8704, 1, 7}, // 0.41% - { 9344, 1, 7}, // 0.21% - { 10880, 1, 6}, // 0.41% - { 11904, 1, 5}, // 0.12% - { 13056, 1, 5}, // 0.41% - { 14464, 1, 4}, // 0.71% - { 16384, 1, 4}, // 0.02% - { 18688, 1, 3}, // 0.21% - { 21760, 1, 3}, // 0.41% - { 26112, 1, 2}, // 0.41% - { 29056, 1, 2}, // 0.26% - { 32768, 1, 2}, // 0.02% - { 37376, 1, 2}, // 0.21% - { 43648, 1, 2}, // 0.12% - { 52352, 1, 2}, // 0.17% - { 56064, 2, 2}, // 3.92% - { 65536, 1, 2}, // 0.02% - { 74880, 2, 2}, // 0.03% - { 87296, 1, 2}, // 0.12% - { 104832, 2, 2}, // 0.03% - { 112256, 3, 2}, // 0.09% - { 131072, 1, 2}, // 0.02% - { 149760, 3, 2}, // 5.03% - { 174720, 2, 2}, // 0.03% - { 209664, 4, 2}, // 0.03% - { 262144, 1, 2}, // 0.02% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = true, + .span_size = 48, + .sampling_interval = 2097152, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 32768 0.02% 12.53% 0.00% + { 16, 1, 32}, // 1 16384 0.02% 12.53% 100.00% + { 24, 1, 32}, // 2 10922 0.02% 12.53% 50.00% + { 32, 1, 32}, // 3 8192 0.02% 12.53% 33.33% + { 40, 1, 32}, // 4 6553 0.03% 12.53% 25.00% + { 48, 1, 32}, // 5 5461 0.02% 12.53% 20.00% + { 56, 1, 32}, // 6 4681 0.02% 12.53% 16.67% + { 64, 1, 32}, // 7 4096 0.02% 12.53% 14.29% + { 72, 1, 32}, // 8 3640 0.04% 12.53% 12.50% + { 80, 1, 32}, // 9 3276 0.04% 12.53% 11.11% + { 88, 1, 32}, // 10 2978 0.05% 12.53% 10.00% + { 96, 1, 32}, // 11 2730 0.04% 12.53% 9.09% + { 104, 1, 32}, // 12 2520 0.04% 12.53% 8.33% + { 112, 1, 32}, // 13 2340 0.04% 12.53% 7.69% + { 128, 1, 32}, // 14 2048 0.02% 12.53% 14.29% + { 144, 1, 32}, // 15 1820 0.04% 12.53% 12.50% + { 160, 1, 32}, // 16 1638 0.04% 12.53% 11.11% + { 176, 1, 32}, // 17 1489 0.05% 12.53% 10.00% + { 192, 1, 32}, // 18 1365 0.04% 12.53% 9.09% + { 208, 1, 32}, // 19 1260 0.04% 12.53% 8.33% + { 232, 1, 32}, // 20 1129 0.10% 12.53% 11.54% + { 256, 1, 32}, // 21 1024 0.02% 12.53% 10.34% + { 280, 1, 32}, // 22 936 0.04% 12.53% 9.38% + { 304, 1, 32}, // 23 862 0.05% 12.53% 8.57% + { 336, 1, 32}, // 24 780 0.04% 12.53% 10.53% + { 384, 1, 32}, // 25 682 0.12% 12.53% 14.29% + { 448, 1, 32}, // 26 585 0.04% 12.53% 16.67% + { 480, 1, 32}, // 27 546 0.04% 12.53% 7.14% + { 512, 1, 32}, // 28 512 0.02% 12.53% 6.67% + { 576, 1, 32}, // 29 455 0.04% 12.53% 12.50% + { 640, 1, 32}, // 30 409 0.16% 12.53% 11.11% + { 704, 1, 32}, // 31 372 0.12% 12.53% 10.00% + { 768, 1, 32}, // 32 341 0.12% 12.53% 9.09% + { 896, 1, 32}, // 33 292 0.21% 12.53% 16.67% + { 1024, 1, 32}, // 34 256 0.02% 12.53% 14.29% + { 1152, 1, 32}, // 35 227 0.26% 12.53% 12.50% + { 1280, 1, 32}, // 36 204 0.41% 12.53% 11.11% + { 1408, 1, 32}, // 37 186 0.12% 12.53% 10.00% + { 1664, 1, 32}, // 38 157 0.36% 12.53% 18.18% + { 1920, 1, 32}, // 39 136 0.41% 12.53% 15.38% + { 2048, 1, 32}, // 40 128 0.02% 12.53% 6.67% + { 2304, 1, 28}, // 41 113 0.70% 12.53% 12.50% + { 2560, 1, 25}, // 42 102 0.41% 12.53% 11.11% + { 2688, 1, 24}, // 43 97 0.56% 12.53% 5.00% + { 3072, 1, 21}, // 44 85 0.41% 12.53% 14.29% + { 3328, 1, 19}, // 45 78 0.99% 12.54% 8.33% + { 3584, 1, 18}, // 46 73 0.21% 12.53% 7.69% + { 3840, 1, 17}, // 47 68 0.41% 12.53% 7.14% + { 4096, 1, 16}, // 48 64 0.02% 12.53% 6.67% + { 4224, 1, 15}, // 49 62 0.12% 12.53% 3.12% + { 4480, 1, 14}, // 50 58 0.90% 12.54% 6.06% + { 4736, 1, 13}, // 51 55 0.65% 12.54% 5.71% + { 5120, 1, 12}, // 52 51 0.41% 12.53% 8.11% + { 5504, 1, 11}, // 53 47 1.34% 12.54% 7.50% + { 6144, 1, 10}, // 54 42 1.58% 12.54% 11.63% + { 6528, 1, 10}, // 55 40 0.41% 12.53% 6.25% + { 7168, 1, 9}, // 56 36 1.58% 12.54% 9.80% + { 8192, 1, 8}, // 57 32 0.02% 12.53% 14.29% + { 9344, 1, 7}, // 58 28 0.21% 12.53% 14.06% + { 10368, 1, 6}, // 59 25 1.14% 12.54% 10.96% + { 11392, 1, 5}, // 60 23 0.07% 12.53% 9.88% + { 12416, 1, 5}, // 61 21 0.56% 12.54% 8.99% + { 13696, 1, 4}, // 62 19 0.75% 12.54% 10.31% + { 15360, 1, 4}, // 63 17 0.41% 12.54% 12.15% + { 16384, 1, 4}, // 64 16 0.02% 12.53% 6.67% + { 17408, 1, 3}, // 65 15 0.41% 12.54% 6.25% + { 18688, 1, 3}, // 66 14 0.21% 12.54% 7.35% + { 20096, 1, 3}, // 67 13 0.36% 12.54% 7.53% + { 21760, 1, 3}, // 68 12 0.41% 12.54% 8.28% + { 23808, 1, 2}, // 69 11 0.12% 12.53% 9.41% + { 26112, 1, 2}, // 70 10 0.41% 12.54% 9.68% + { 29056, 1, 2}, // 71 9 0.26% 12.54% 11.27% + { 32768, 1, 2}, // 72 8 0.02% 12.53% 12.78% + { 37376, 1, 2}, // 73 7 0.21% 12.54% 14.06% + { 43648, 1, 2}, // 74 6 0.12% 12.54% 16.78% + { 45568, 2, 2}, // 75 11 4.40% 12.63% 4.40% + { 52352, 1, 2}, // 76 5 0.16% 12.54% 14.89% + { 56064, 2, 2}, // 77 9 3.77% 12.63% 7.09% + { 65536, 1, 2}, // 78 4 0.02% 12.53% 16.89% + { 74880, 2, 2}, // 79 7 0.03% 12.53% 14.26% + { 87296, 1, 2}, // 80 3 0.12% 12.54% 16.58% + {104832, 2, 2}, // 81 5 0.03% 12.54% 20.09% + {112256, 3, 2}, // 82 7 0.09% 12.54% 7.08% + {131072, 1, 2}, // 83 2 0.02% 12.53% 16.76% + {149760, 3, 2}, // 84 5 4.79% 12.88% 14.26% + {174720, 2, 2}, // 85 3 0.03% 12.54% 16.67% + {209664, 4, 2}, // 86 5 0.03% 12.54% 20.00% + {262144, 1, 2}, // 87 1 0.02% 0.03% 25.03% }; #elif TCMALLOC_PAGE_SHIFT == 12 static_assert(kMaxSize == 8192, "kMaxSize mismatch"); -static const int kCount = 46; -static_assert(kCount <= kNumClasses); -const int SizeMap::kLegacySizeClassesCount = kCount; -const SizeClassInfo SizeMap::kLegacySizeClasses[SizeMap::kLegacySizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 1.17% - { 16, 1, 32}, // 1.17% - { 24, 1, 32}, // 1.57% - { 32, 1, 32}, // 1.17% - { 40, 1, 32}, // 1.57% - { 48, 1, 32}, // 1.57% - { 56, 1, 32}, // 1.37% - { 64, 1, 32}, // 1.17% - { 72, 1, 32}, // 2.78% - { 80, 1, 32}, // 1.57% - { 88, 1, 32}, // 2.37% - { 96, 1, 32}, // 2.78% - { 104, 1, 32}, // 2.17% - { 120, 1, 32}, // 1.57% - { 128, 1, 32}, // 1.17% - { 144, 1, 32}, // 2.78% - { 160, 1, 32}, // 3.60% - { 184, 1, 32}, // 2.37% - { 208, 1, 32}, // 4.86% - { 240, 1, 32}, // 1.57% - { 256, 1, 32}, // 1.17% - { 272, 1, 32}, // 1.57% - { 312, 1, 32}, // 2.17% - { 336, 1, 32}, // 2.78% - { 368, 1, 32}, // 2.37% - { 408, 1, 32}, // 1.57% - { 512, 1, 32}, // 1.17% - { 576, 2, 32}, // 2.18% - { 704, 2, 32}, // 6.40% - { 768, 2, 32}, // 7.29% - { 896, 2, 32}, // 2.18% - { 1024, 2, 32}, // 0.59% - { 1152, 3, 32}, // 7.08% - { 1280, 3, 32}, // 7.08% - { 1536, 3, 32}, // 0.39% - { 1792, 4, 32}, // 1.88% - { 2048, 4, 32}, // 0.29% - { 2304, 4, 28}, // 1.88% - { 2688, 4, 24}, // 1.88% - { 3456, 6, 18}, // 1.79% - { 4096, 4, 16}, // 0.29% - { 5376, 4, 12}, // 1.88% - { 6144, 3, 10}, // 0.39% - { 7168, 7, 9}, // 0.17% - { 8192, 4, 8}, // 0.29% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = false, + .span_size = 48, + .sampling_interval = 524288, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 512 1.16% 0.92% 0.00% + { 16, 1, 32}, // 1 256 1.16% 0.92% 100.00% + { 24, 1, 32}, // 2 170 1.54% 0.92% 50.00% + { 32, 1, 32}, // 3 128 1.16% 0.92% 33.33% + { 40, 1, 32}, // 4 102 1.54% 0.92% 25.00% + { 48, 1, 32}, // 5 85 1.54% 0.92% 20.00% + { 56, 1, 32}, // 6 73 1.35% 0.92% 16.67% + { 64, 1, 32}, // 7 64 1.16% 0.92% 14.29% + { 72, 1, 32}, // 8 56 2.70% 0.92% 12.50% + { 80, 1, 32}, // 9 51 1.54% 0.92% 11.11% + { 88, 1, 32}, // 10 46 2.32% 0.92% 10.00% + { 96, 1, 32}, // 11 42 2.70% 0.92% 9.09% + { 104, 1, 32}, // 12 39 2.12% 0.92% 8.33% + { 112, 1, 32}, // 13 36 2.70% 0.92% 7.69% + { 128, 1, 32}, // 14 32 1.16% 0.92% 14.29% + { 144, 1, 32}, // 15 28 2.70% 0.92% 12.50% + { 160, 1, 32}, // 16 25 3.47% 0.92% 11.11% + { 176, 1, 32}, // 17 23 2.32% 0.92% 10.00% + { 192, 1, 32}, // 18 21 2.70% 0.92% 9.09% + { 208, 1, 32}, // 19 19 4.63% 0.92% 8.33% + { 224, 1, 32}, // 20 18 2.70% 0.92% 7.69% + { 240, 1, 32}, // 21 17 1.54% 0.92% 7.14% + { 256, 1, 32}, // 22 16 1.16% 0.92% 6.67% + { 272, 1, 32}, // 23 15 1.54% 0.92% 6.25% + { 312, 1, 32}, // 24 13 2.12% 0.92% 14.71% + { 336, 1, 32}, // 25 12 2.70% 0.92% 7.69% + { 368, 1, 32}, // 26 11 2.32% 0.92% 9.52% + { 448, 1, 32}, // 27 9 2.70% 0.92% 21.74% + { 512, 1, 32}, // 28 8 1.16% 0.92% 14.29% + { 576, 2, 32}, // 29 14 2.14% 0.92% 12.50% + { 704, 2, 32}, // 30 11 6.02% 0.92% 22.22% + { 768, 2, 32}, // 31 10 6.80% 0.93% 9.09% + { 896, 2, 32}, // 32 9 2.14% 0.92% 16.67% + { 1024, 2, 32}, // 33 8 0.58% 0.92% 14.29% + { 1152, 3, 32}, // 34 10 6.61% 0.93% 12.50% + { 1536, 3, 32}, // 35 8 0.39% 0.92% 33.33% + { 1792, 4, 32}, // 36 9 1.85% 0.92% 16.67% + { 2048, 4, 32}, // 37 8 0.29% 0.92% 14.29% + { 2688, 4, 24}, // 38 6 1.85% 0.93% 31.25% + { 3200, 4, 20}, // 39 5 2.63% 0.93% 19.05% + { 4096, 4, 16}, // 40 4 0.29% 0.92% 28.00% + { 4736, 5, 13}, // 41 4 7.72% 1.77% 15.62% + { 6144, 3, 10}, // 42 2 0.39% 1.70% 29.73% + { 7168, 7, 9}, // 43 4 0.17% 1.70% 16.67% + { 8192, 4, 8}, // 44 2 0.29% 1.70% 14.29% }; #else #error "Unsupported TCMALLOC_PAGE_SHIFT value!" @@ -371,334 +402,354 @@ const SizeClassInfo SizeMap::kLegacySizeClasses[SizeMap::kLegacySizeClassesCount #else #if TCMALLOC_PAGE_SHIFT == 13 static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 86; -static_assert(kCount <= kNumClasses); -const int SizeMap::kLegacySizeClassesCount = kCount; -const SizeClassInfo SizeMap::kLegacySizeClasses[SizeMap::kLegacySizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.59% - { 16, 1, 32}, // 0.59% - { 32, 1, 32}, // 0.59% - { 48, 1, 32}, // 0.98% - { 64, 1, 32}, // 0.59% - { 80, 1, 32}, // 0.98% - { 96, 1, 32}, // 0.98% - { 112, 1, 32}, // 0.78% - { 128, 1, 32}, // 0.59% - { 144, 1, 32}, // 2.18% - { 160, 1, 32}, // 0.98% - { 176, 1, 32}, // 1.78% - { 192, 1, 32}, // 2.18% - { 208, 1, 32}, // 1.58% - { 224, 1, 32}, // 2.18% - { 240, 1, 32}, // 0.98% - { 256, 1, 32}, // 0.59% - { 272, 1, 32}, // 0.98% - { 288, 1, 32}, // 2.18% - { 304, 1, 32}, // 4.25% - { 320, 1, 32}, // 3.00% - { 336, 1, 32}, // 2.18% - { 352, 1, 32}, // 1.78% - { 368, 1, 32}, // 1.78% - { 384, 1, 32}, // 2.18% - { 400, 1, 32}, // 3.00% - { 416, 1, 32}, // 4.25% - { 448, 1, 32}, // 2.18% - { 480, 1, 32}, // 0.98% - { 512, 1, 32}, // 0.59% - { 576, 1, 32}, // 2.18% - { 640, 1, 32}, // 7.29% - { 704, 1, 32}, // 6.40% - { 768, 1, 32}, // 7.29% - { 896, 1, 32}, // 2.18% - { 1024, 1, 32}, // 0.59% - { 1152, 2, 32}, // 1.88% - { 1280, 2, 32}, // 6.98% - { 1408, 2, 32}, // 6.10% - { 1536, 2, 32}, // 6.98% - { 1792, 2, 32}, // 1.88% - { 2048, 2, 32}, // 0.29% - { 2304, 2, 28}, // 1.88% - { 2688, 2, 24}, // 1.88% - { 2816, 3, 23}, // 9.30% - { 3200, 2, 20}, // 2.70% - { 3456, 3, 18}, // 1.79% - { 3584, 4, 18}, // 1.74% - { 4096, 2, 16}, // 0.29% - { 4736, 3, 13}, // 3.99% - { 5376, 2, 12}, // 1.88% - { 6144, 3, 10}, // 0.20% - { 6528, 4, 10}, // 0.54% - { 6784, 5, 9}, // 0.75% - { 7168, 7, 9}, // 0.08% - { 8192, 2, 8}, // 0.29% - { 9472, 5, 6}, // 8.23% - { 10240, 4, 6}, // 6.82% - { 12288, 3, 5}, // 0.20% - { 13568, 5, 4}, // 0.75% - { 14336, 7, 4}, // 0.08% - { 16384, 2, 4}, // 0.29% - { 20480, 5, 3}, // 0.12% - { 24576, 3, 2}, // 0.20% - { 28672, 7, 2}, // 0.08% - { 32768, 4, 2}, // 0.15% - { 40960, 5, 2}, // 0.12% - { 49152, 6, 2}, // 0.10% - { 57344, 7, 2}, // 0.08% - { 65536, 8, 2}, // 0.07% - { 73728, 9, 2}, // 0.07% - { 81920, 10, 2}, // 0.06% - { 90112, 11, 2}, // 0.05% - { 98304, 12, 2}, // 0.05% - { 106496, 13, 2}, // 0.05% - { 114688, 14, 2}, // 0.04% - { 131072, 16, 2}, // 0.04% - { 139264, 17, 2}, // 0.03% - { 155648, 19, 2}, // 0.03% - { 172032, 21, 2}, // 0.03% - { 188416, 23, 2}, // 0.03% - { 204800, 25, 2}, // 0.02% - { 221184, 27, 2}, // 0.02% - { 237568, 29, 2}, // 0.02% - { 262144, 32, 2}, // 0.02% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = true, + .span_size = 48, + .sampling_interval = 2097152, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 1024 0.58% 0.42% 0.00% + { 16, 1, 32}, // 1 512 0.58% 0.42% 100.00% + { 32, 1, 32}, // 2 256 0.58% 0.42% 100.00% + { 48, 1, 32}, // 3 170 0.97% 0.42% 50.00% + { 64, 1, 32}, // 4 128 0.58% 0.42% 33.33% + { 80, 1, 32}, // 5 102 0.97% 0.42% 25.00% + { 96, 1, 32}, // 6 85 0.97% 0.42% 20.00% + { 112, 1, 32}, // 7 73 0.78% 0.42% 16.67% + { 128, 1, 32}, // 8 64 0.58% 0.42% 14.29% + { 144, 1, 32}, // 9 56 2.14% 0.42% 12.50% + { 160, 1, 32}, // 10 51 0.97% 0.42% 11.11% + { 176, 1, 32}, // 11 46 1.75% 0.42% 10.00% + { 192, 1, 32}, // 12 42 2.14% 0.42% 9.09% + { 208, 1, 32}, // 13 39 1.55% 0.42% 8.33% + { 224, 1, 32}, // 14 36 2.14% 0.42% 7.69% + { 240, 1, 32}, // 15 34 0.97% 0.42% 7.14% + { 256, 1, 32}, // 16 32 0.58% 0.42% 6.67% + { 272, 1, 32}, // 17 30 0.97% 0.42% 6.25% + { 288, 1, 32}, // 18 28 2.14% 0.42% 5.88% + { 304, 1, 32}, // 19 26 4.08% 0.42% 5.56% + { 320, 1, 32}, // 20 25 2.91% 0.42% 5.26% + { 336, 1, 32}, // 21 24 2.14% 0.42% 5.00% + { 352, 1, 32}, // 22 23 1.75% 0.42% 4.76% + { 368, 1, 32}, // 23 22 1.75% 0.42% 4.55% + { 384, 1, 32}, // 24 21 2.14% 0.42% 4.35% + { 400, 1, 32}, // 25 20 2.91% 0.42% 4.17% + { 416, 1, 32}, // 26 19 4.08% 0.43% 4.00% + { 448, 1, 32}, // 27 18 2.14% 0.42% 7.69% + { 480, 1, 32}, // 28 17 0.97% 0.42% 7.14% + { 512, 1, 32}, // 29 16 0.58% 0.42% 6.67% + { 576, 1, 32}, // 30 14 2.14% 0.42% 12.50% + { 640, 1, 32}, // 31 12 6.80% 0.43% 11.11% + { 704, 1, 32}, // 32 11 6.02% 0.43% 10.00% + { 768, 1, 32}, // 33 10 6.80% 0.43% 9.09% + { 896, 1, 32}, // 34 9 2.14% 0.43% 16.67% + { 1024, 1, 32}, // 35 8 0.58% 0.42% 14.29% + { 1152, 2, 32}, // 36 14 1.85% 0.43% 12.50% + { 1280, 2, 32}, // 37 12 6.52% 0.43% 11.11% + { 1408, 2, 32}, // 38 11 5.74% 0.43% 10.00% + { 1536, 2, 32}, // 39 10 6.52% 0.43% 9.09% + { 1792, 2, 32}, // 40 9 1.85% 0.43% 16.67% + { 2048, 2, 32}, // 41 8 0.29% 0.42% 14.29% + { 2304, 2, 28}, // 42 7 1.85% 0.43% 12.50% + { 2688, 2, 24}, // 43 6 1.85% 0.43% 16.67% + { 2816, 3, 23}, // 44 8 8.51% 0.44% 4.76% + { 3200, 2, 20}, // 45 5 2.63% 0.43% 13.64% + { 3456, 3, 18}, // 46 7 1.75% 0.43% 8.00% + { 3584, 4, 18}, // 47 9 1.71% 0.43% 3.70% + { 4096, 1, 16}, // 48 2 0.58% 0.43% 14.29% + { 4736, 3, 13}, // 49 5 3.83% 0.43% 15.62% + { 5376, 2, 12}, // 50 3 1.85% 0.43% 13.51% + { 6144, 3, 10}, // 51 4 0.19% 0.42% 14.29% + { 6528, 4, 10}, // 52 5 0.54% 0.43% 6.25% + { 7168, 7, 9}, // 53 8 0.08% 0.42% 9.80% + { 8192, 1, 8}, // 54 1 0.58% 0.03% 14.29% + { 9472, 5, 6}, // 55 4 7.61% 0.85% 15.62% + { 10240, 4, 6}, // 56 3 6.39% 0.85% 8.11% + { 12288, 3, 5}, // 57 2 0.19% 0.82% 20.00% + { 13568, 5, 4}, // 58 3 0.74% 0.82% 10.42% + { 14336, 7, 4}, // 59 4 0.08% 0.82% 5.66% + { 16384, 2, 4}, // 60 1 0.29% 0.03% 14.29% + { 20480, 5, 3}, // 61 2 0.12% 1.21% 25.00% + { 24576, 3, 2}, // 62 1 0.19% 0.03% 20.00% + { 28672, 7, 2}, // 63 2 0.08% 1.60% 16.67% + { 32768, 4, 2}, // 64 1 0.15% 0.03% 14.29% + { 40960, 5, 2}, // 65 1 0.12% 0.03% 25.00% + { 49152, 6, 2}, // 66 1 0.10% 0.03% 20.00% + { 57344, 7, 2}, // 67 1 0.08% 0.03% 16.67% + { 65536, 8, 2}, // 68 1 0.07% 0.03% 14.29% + { 73728, 9, 2}, // 69 1 0.07% 0.03% 12.50% + { 81920, 10, 2}, // 70 1 0.06% 0.03% 11.11% + { 90112, 11, 2}, // 71 1 0.05% 0.03% 10.00% + { 98304, 12, 2}, // 72 1 0.05% 0.03% 9.09% + {106496, 13, 2}, // 73 1 0.05% 0.03% 8.33% + {114688, 14, 2}, // 74 1 0.04% 0.03% 7.69% + {131072, 16, 2}, // 75 1 0.04% 0.03% 14.29% + {139264, 17, 2}, // 76 1 0.03% 0.03% 6.25% + {147456, 18, 2}, // 77 1 0.03% 0.03% 5.88% + {155648, 19, 2}, // 78 1 0.03% 0.03% 5.56% + {172032, 21, 2}, // 79 1 0.03% 0.03% 10.53% + {188416, 23, 2}, // 80 1 0.03% 0.03% 9.52% + {204800, 25, 2}, // 81 1 0.02% 0.03% 8.70% + {221184, 27, 2}, // 82 1 0.02% 0.03% 8.00% + {237568, 29, 2}, // 83 1 0.02% 0.03% 7.41% + {262144, 32, 2}, // 84 1 0.02% 0.03% 10.34% }; #elif TCMALLOC_PAGE_SHIFT == 15 static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 78; -static_assert(kCount <= kNumClasses); -const int SizeMap::kLegacySizeClassesCount = kCount; -const SizeClassInfo SizeMap::kLegacySizeClasses[SizeMap::kLegacySizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.15% - { 16, 1, 32}, // 0.15% - { 32, 1, 32}, // 0.15% - { 48, 1, 32}, // 0.24% - { 64, 1, 32}, // 0.15% - { 80, 1, 32}, // 0.29% - { 96, 1, 32}, // 0.24% - { 112, 1, 32}, // 0.34% - { 128, 1, 32}, // 0.15% - { 144, 1, 32}, // 0.39% - { 160, 1, 32}, // 0.54% - { 176, 1, 32}, // 0.24% - { 192, 1, 32}, // 0.54% - { 208, 1, 32}, // 0.49% - { 224, 1, 32}, // 0.34% - { 240, 1, 32}, // 0.54% - { 256, 1, 32}, // 0.15% - { 272, 1, 32}, // 0.54% - { 288, 1, 32}, // 0.84% - { 304, 1, 32}, // 0.89% - { 320, 1, 32}, // 0.54% - { 336, 1, 32}, // 0.69% - { 352, 1, 32}, // 0.24% - { 384, 1, 32}, // 0.54% - { 416, 1, 32}, // 1.13% - { 448, 1, 32}, // 0.34% - { 480, 1, 32}, // 0.54% - { 512, 1, 32}, // 0.15% - { 576, 1, 32}, // 1.74% - { 640, 1, 32}, // 0.54% - { 704, 1, 32}, // 1.33% - { 768, 1, 32}, // 1.74% - { 832, 1, 32}, // 1.13% - { 896, 1, 32}, // 1.74% - { 1024, 1, 32}, // 0.15% - { 1152, 1, 32}, // 1.74% - { 1280, 1, 32}, // 2.55% - { 1408, 1, 32}, // 1.33% - { 1536, 1, 32}, // 1.74% - { 1792, 1, 32}, // 1.74% - { 2048, 1, 32}, // 0.15% - { 2176, 1, 30}, // 0.54% - { 2304, 1, 28}, // 1.74% - { 2432, 1, 26}, // 3.80% - { 2688, 1, 24}, // 1.74% - { 2944, 1, 22}, // 1.33% - { 3200, 1, 20}, // 2.55% - { 3584, 1, 18}, // 1.74% - { 4096, 1, 16}, // 0.15% - { 4608, 1, 14}, // 1.74% - { 5376, 1, 12}, // 1.74% - { 6528, 1, 10}, // 0.54% - { 7168, 2, 9}, // 1.66% - { 8192, 1, 8}, // 0.15% - { 9344, 2, 7}, // 0.27% - { 10880, 1, 6}, // 0.54% - { 13056, 2, 5}, // 0.47% - { 13952, 3, 4}, // 0.70% - { 16384, 1, 4}, // 0.15% - { 19072, 3, 3}, // 3.14% - { 21760, 2, 3}, // 0.47% - { 24576, 3, 2}, // 0.05% - { 28032, 6, 2}, // 0.22% - { 32768, 1, 2}, // 0.15% - { 38144, 5, 2}, // 7.41% - { 40960, 4, 2}, // 6.71% - { 49152, 3, 2}, // 0.05% - { 57344, 7, 2}, // 0.02% - { 65536, 2, 2}, // 0.07% - { 81920, 5, 2}, // 0.03% - { 98304, 3, 2}, // 0.05% - { 114688, 7, 2}, // 0.02% - { 131072, 4, 2}, // 0.04% - { 163840, 5, 2}, // 0.03% - { 196608, 6, 2}, // 0.02% - { 229376, 7, 2}, // 0.02% - { 262144, 8, 2}, // 0.02% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = true, + .span_size = 48, + .sampling_interval = 2097152, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 4096 0.15% 1.60% 0.00% + { 16, 1, 32}, // 1 2048 0.15% 1.60% 100.00% + { 32, 1, 32}, // 2 1024 0.15% 1.60% 100.00% + { 48, 1, 32}, // 3 682 0.24% 1.60% 50.00% + { 64, 1, 32}, // 4 512 0.15% 1.60% 33.33% + { 80, 1, 32}, // 5 409 0.29% 1.60% 25.00% + { 96, 1, 32}, // 6 341 0.24% 1.60% 20.00% + { 112, 1, 32}, // 7 292 0.34% 1.60% 16.67% + { 128, 1, 32}, // 8 256 0.15% 1.60% 14.29% + { 144, 1, 32}, // 9 227 0.39% 1.60% 12.50% + { 160, 1, 32}, // 10 204 0.54% 1.60% 11.11% + { 176, 1, 32}, // 11 186 0.24% 1.60% 10.00% + { 192, 1, 32}, // 12 170 0.54% 1.60% 9.09% + { 208, 1, 32}, // 13 157 0.49% 1.60% 8.33% + { 224, 1, 32}, // 14 146 0.34% 1.60% 7.69% + { 240, 1, 32}, // 15 136 0.54% 1.60% 7.14% + { 256, 1, 32}, // 16 128 0.15% 1.60% 6.67% + { 288, 1, 32}, // 17 113 0.83% 1.60% 12.50% + { 320, 1, 32}, // 18 102 0.54% 1.60% 11.11% + { 352, 1, 32}, // 19 93 0.24% 1.60% 10.00% + { 384, 1, 32}, // 20 85 0.54% 1.60% 9.09% + { 400, 1, 32}, // 21 81 1.27% 1.60% 4.17% + { 448, 1, 32}, // 22 73 0.34% 1.60% 12.00% + { 480, 1, 32}, // 23 68 0.54% 1.60% 7.14% + { 512, 1, 32}, // 24 64 0.15% 1.60% 6.67% + { 576, 1, 32}, // 25 56 1.71% 1.60% 12.50% + { 640, 1, 32}, // 26 51 0.54% 1.60% 11.11% + { 704, 1, 32}, // 27 46 1.32% 1.60% 10.00% + { 768, 1, 32}, // 28 42 1.71% 1.60% 9.09% + { 832, 1, 32}, // 29 39 1.12% 1.60% 8.33% + { 896, 1, 32}, // 30 36 1.71% 1.60% 7.69% + { 1024, 1, 32}, // 31 32 0.15% 1.60% 14.29% + { 1152, 1, 32}, // 32 28 1.71% 1.60% 12.50% + { 1280, 1, 32}, // 33 25 2.49% 1.60% 11.11% + { 1408, 1, 32}, // 34 23 1.32% 1.60% 10.00% + { 1536, 1, 32}, // 35 21 1.71% 1.60% 9.09% + { 1664, 1, 32}, // 36 19 3.66% 1.60% 8.33% + { 1792, 1, 32}, // 37 18 1.71% 1.60% 7.69% + { 1920, 1, 32}, // 38 17 0.54% 1.60% 7.14% + { 2048, 1, 32}, // 39 16 0.15% 1.60% 6.67% + { 2176, 1, 30}, // 40 15 0.54% 1.60% 6.25% + { 2304, 1, 28}, // 41 14 1.71% 1.60% 5.88% + { 2432, 1, 26}, // 42 13 3.66% 1.60% 5.56% + { 2688, 1, 24}, // 43 12 1.71% 1.60% 10.53% + { 2944, 1, 22}, // 44 11 1.32% 1.60% 9.52% + { 3200, 1, 20}, // 45 10 2.49% 1.60% 8.70% + { 3584, 1, 18}, // 46 9 1.71% 1.60% 12.00% + { 4096, 1, 16}, // 47 8 0.15% 1.60% 14.29% + { 4608, 1, 14}, // 48 7 1.71% 1.60% 12.50% + { 5376, 1, 12}, // 49 6 1.71% 1.60% 16.67% + { 6528, 1, 10}, // 50 5 0.54% 1.60% 21.43% + { 7168, 2, 9}, // 51 9 1.63% 1.60% 9.80% + { 8192, 1, 8}, // 52 4 0.15% 1.60% 14.29% + { 9344, 2, 7}, // 53 7 0.27% 1.60% 14.06% + { 10880, 1, 6}, // 54 3 0.54% 1.60% 16.44% + { 13056, 2, 5}, // 55 5 0.46% 1.60% 20.00% + { 13952, 3, 4}, // 56 7 0.70% 1.60% 6.86% + { 16384, 1, 4}, // 57 2 0.15% 1.60% 17.43% + { 19072, 3, 3}, // 58 5 3.04% 1.62% 16.41% + { 21760, 2, 3}, // 59 3 0.46% 1.60% 14.09% + { 24576, 3, 2}, // 60 4 0.05% 1.60% 12.94% + { 26112, 4, 2}, // 61 5 0.43% 1.60% 6.25% + { 28672, 7, 2}, // 62 8 0.02% 1.60% 9.80% + { 32768, 1, 2}, // 63 1 0.15% 0.03% 14.29% + { 38144, 5, 2}, // 64 4 6.90% 3.28% 16.41% + { 40960, 4, 2}, // 65 3 6.28% 3.28% 7.38% + { 49152, 3, 2}, // 66 2 0.05% 3.16% 20.00% + { 57344, 7, 2}, // 67 4 0.02% 3.16% 16.67% + { 65536, 2, 2}, // 68 1 0.07% 0.03% 14.29% + { 81920, 5, 2}, // 69 2 0.03% 4.72% 25.00% + { 98304, 3, 2}, // 70 1 0.05% 0.03% 20.00% + {114688, 7, 2}, // 71 2 0.02% 6.28% 16.67% + {131072, 4, 2}, // 72 1 0.04% 0.03% 14.29% + {163840, 5, 2}, // 73 1 0.03% 0.03% 25.00% + {196608, 6, 2}, // 74 1 0.02% 0.03% 20.00% + {229376, 7, 2}, // 75 1 0.02% 0.03% 16.67% + {262144, 8, 2}, // 76 1 0.02% 0.03% 14.29% }; #elif TCMALLOC_PAGE_SHIFT == 18 static_assert(kMaxSize == 262144, "kMaxSize mismatch"); -static const int kCount = 89; -static_assert(kCount <= kNumClasses); -const int SizeMap::kLegacySizeClassesCount = kCount; -const SizeClassInfo SizeMap::kLegacySizeClasses[SizeMap::kLegacySizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 0.02% - { 16, 1, 32}, // 0.02% - { 32, 1, 32}, // 0.02% - { 48, 1, 32}, // 0.02% - { 64, 1, 32}, // 0.02% - { 80, 1, 32}, // 0.04% - { 96, 1, 32}, // 0.04% - { 112, 1, 32}, // 0.04% - { 128, 1, 32}, // 0.02% - { 144, 1, 32}, // 0.04% - { 160, 1, 32}, // 0.04% - { 176, 1, 32}, // 0.05% - { 192, 1, 32}, // 0.04% - { 208, 1, 32}, // 0.04% - { 240, 1, 32}, // 0.04% - { 256, 1, 32}, // 0.02% - { 304, 1, 32}, // 0.05% - { 336, 1, 32}, // 0.04% - { 368, 1, 32}, // 0.07% - { 416, 1, 32}, // 0.04% - { 464, 1, 32}, // 0.19% - { 512, 1, 32}, // 0.02% - { 576, 1, 32}, // 0.04% - { 640, 1, 32}, // 0.17% - { 704, 1, 32}, // 0.12% - { 768, 1, 32}, // 0.12% - { 832, 1, 32}, // 0.04% - { 896, 1, 32}, // 0.21% - { 1024, 1, 32}, // 0.02% - { 1152, 1, 32}, // 0.26% - { 1280, 1, 32}, // 0.41% - { 1408, 1, 32}, // 0.12% - { 1536, 1, 32}, // 0.41% - { 1664, 1, 32}, // 0.36% - { 1792, 1, 32}, // 0.21% - { 1920, 1, 32}, // 0.41% - { 2048, 1, 32}, // 0.02% - { 2176, 1, 30}, // 0.41% - { 2304, 1, 28}, // 0.71% - { 2432, 1, 26}, // 0.76% - { 2560, 1, 25}, // 0.41% - { 2688, 1, 24}, // 0.56% - { 2816, 1, 23}, // 0.12% - { 2944, 1, 22}, // 0.07% - { 3072, 1, 21}, // 0.41% - { 3200, 1, 20}, // 1.15% - { 3328, 1, 19}, // 1.00% - { 3584, 1, 18}, // 0.21% - { 3840, 1, 17}, // 0.41% - { 4096, 1, 16}, // 0.02% - { 4736, 1, 13}, // 0.66% - { 5504, 1, 11}, // 1.35% - { 6144, 1, 10}, // 1.61% - { 6528, 1, 10}, // 0.41% - { 6784, 1, 9}, // 1.71% - { 7168, 1, 9}, // 1.61% - { 7680, 1, 8}, // 0.41% - { 8192, 1, 8}, // 0.02% - { 8704, 1, 7}, // 0.41% - { 9344, 1, 7}, // 0.21% - { 10368, 1, 6}, // 1.15% - { 11392, 1, 5}, // 0.07% - { 12416, 1, 5}, // 0.56% - { 13696, 1, 4}, // 0.76% - { 14464, 1, 4}, // 0.71% - { 16384, 1, 4}, // 0.02% - { 17408, 1, 3}, // 0.41% - { 20096, 1, 3}, // 0.36% - { 21760, 1, 3}, // 0.41% - { 23808, 1, 2}, // 0.12% - { 26112, 1, 2}, // 0.41% - { 29056, 1, 2}, // 0.26% - { 32768, 1, 2}, // 0.02% - { 37376, 1, 2}, // 0.21% - { 43648, 1, 2}, // 0.12% - { 52352, 1, 2}, // 0.17% - { 56064, 2, 2}, // 3.92% - { 65536, 1, 2}, // 0.02% - { 74880, 2, 2}, // 0.03% - { 87296, 1, 2}, // 0.12% - { 104832, 2, 2}, // 0.03% - { 112256, 3, 2}, // 0.09% - { 131072, 1, 2}, // 0.02% - { 149760, 3, 2}, // 5.03% - { 174720, 2, 2}, // 0.03% - { 196608, 3, 2}, // 0.01% - { 209664, 4, 2}, // 0.03% - { 262144, 1, 2}, // 0.02% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = true, + .span_size = 48, + .sampling_interval = 2097152, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 32768 0.02% 12.53% 0.00% + { 16, 1, 32}, // 1 16384 0.02% 12.53% 100.00% + { 32, 1, 32}, // 2 8192 0.02% 12.53% 100.00% + { 48, 1, 32}, // 3 5461 0.02% 12.53% 50.00% + { 64, 1, 32}, // 4 4096 0.02% 12.53% 33.33% + { 80, 1, 32}, // 5 3276 0.04% 12.53% 25.00% + { 96, 1, 32}, // 6 2730 0.04% 12.53% 20.00% + { 112, 1, 32}, // 7 2340 0.04% 12.53% 16.67% + { 128, 1, 32}, // 8 2048 0.02% 12.53% 14.29% + { 144, 1, 32}, // 9 1820 0.04% 12.53% 12.50% + { 160, 1, 32}, // 10 1638 0.04% 12.53% 11.11% + { 176, 1, 32}, // 11 1489 0.05% 12.53% 10.00% + { 192, 1, 32}, // 12 1365 0.04% 12.53% 9.09% + { 208, 1, 32}, // 13 1260 0.04% 12.53% 8.33% + { 224, 1, 32}, // 14 1170 0.04% 12.53% 7.69% + { 240, 1, 32}, // 15 1092 0.04% 12.53% 7.14% + { 256, 1, 32}, // 16 1024 0.02% 12.53% 6.67% + { 272, 1, 32}, // 17 963 0.10% 12.53% 6.25% + { 304, 1, 32}, // 18 862 0.05% 12.53% 11.76% + { 336, 1, 32}, // 19 780 0.04% 12.53% 10.53% + { 384, 1, 32}, // 20 682 0.12% 12.53% 14.29% + { 416, 1, 32}, // 21 630 0.04% 12.53% 8.33% + { 448, 1, 32}, // 22 585 0.04% 12.53% 7.69% + { 480, 1, 32}, // 23 546 0.04% 12.53% 7.14% + { 512, 1, 32}, // 24 512 0.02% 12.53% 6.67% + { 576, 1, 32}, // 25 455 0.04% 12.53% 12.50% + { 640, 1, 32}, // 26 409 0.16% 12.53% 11.11% + { 704, 1, 32}, // 27 372 0.12% 12.53% 10.00% + { 768, 1, 32}, // 28 341 0.12% 12.53% 9.09% + { 896, 1, 32}, // 29 292 0.21% 12.53% 16.67% + { 1024, 1, 32}, // 30 256 0.02% 12.53% 14.29% + { 1152, 1, 32}, // 31 227 0.26% 12.53% 12.50% + { 1280, 1, 32}, // 32 204 0.41% 12.53% 11.11% + { 1408, 1, 32}, // 33 186 0.12% 12.53% 10.00% + { 1536, 1, 32}, // 34 170 0.41% 12.53% 9.09% + { 1664, 1, 32}, // 35 157 0.36% 12.53% 8.33% + { 1920, 1, 32}, // 36 136 0.41% 12.53% 15.38% + { 2048, 1, 32}, // 37 128 0.02% 12.53% 6.67% + { 2304, 1, 28}, // 38 113 0.70% 12.53% 12.50% + { 2560, 1, 25}, // 39 102 0.41% 12.53% 11.11% + { 2688, 1, 24}, // 40 97 0.56% 12.53% 5.00% + { 3072, 1, 21}, // 41 85 0.41% 12.53% 14.29% + { 3328, 1, 19}, // 42 78 0.99% 12.54% 8.33% + { 3584, 1, 18}, // 43 73 0.21% 12.53% 7.69% + { 3840, 1, 17}, // 44 68 0.41% 12.53% 7.14% + { 4096, 1, 16}, // 45 64 0.02% 12.53% 6.67% + { 4224, 1, 15}, // 46 62 0.12% 12.53% 3.12% + { 4480, 1, 14}, // 47 58 0.90% 12.54% 6.06% + { 4736, 1, 13}, // 48 55 0.65% 12.54% 5.71% + { 5120, 1, 12}, // 49 51 0.41% 12.53% 8.11% + { 5504, 1, 11}, // 50 47 1.34% 12.54% 7.50% + { 6144, 1, 10}, // 51 42 1.58% 12.54% 11.63% + { 6528, 1, 10}, // 52 40 0.41% 12.53% 6.25% + { 7168, 1, 9}, // 53 36 1.58% 12.54% 9.80% + { 8192, 1, 8}, // 54 32 0.02% 12.53% 14.29% + { 8704, 1, 7}, // 55 30 0.41% 12.54% 6.25% + { 9344, 1, 7}, // 56 28 0.21% 12.53% 7.35% + { 10368, 1, 6}, // 57 25 1.14% 12.54% 10.96% + { 11392, 1, 5}, // 58 23 0.07% 12.53% 9.88% + { 12416, 1, 5}, // 59 21 0.56% 12.54% 8.99% + { 13056, 1, 5}, // 60 20 0.41% 12.54% 5.15% + { 13696, 1, 4}, // 61 19 0.75% 12.54% 4.90% + { 15360, 1, 4}, // 62 17 0.41% 12.54% 12.15% + { 16384, 1, 4}, // 63 16 0.02% 12.53% 6.67% + { 17408, 1, 3}, // 64 15 0.41% 12.54% 6.25% + { 18688, 1, 3}, // 65 14 0.21% 12.54% 7.35% + { 20096, 1, 3}, // 66 13 0.36% 12.54% 7.53% + { 21760, 1, 3}, // 67 12 0.41% 12.54% 8.28% + { 23808, 1, 2}, // 68 11 0.12% 12.53% 9.41% + { 26112, 1, 2}, // 69 10 0.41% 12.54% 9.68% + { 29056, 1, 2}, // 70 9 0.26% 12.54% 11.27% + { 32768, 1, 2}, // 71 8 0.02% 12.53% 12.78% + { 37376, 1, 2}, // 72 7 0.21% 12.54% 14.06% + { 43648, 1, 2}, // 73 6 0.12% 12.54% 16.78% + { 45568, 2, 2}, // 74 11 4.40% 12.63% 4.40% + { 52352, 1, 2}, // 75 5 0.16% 12.54% 14.89% + { 56064, 2, 2}, // 76 9 3.77% 12.63% 7.09% + { 65536, 1, 2}, // 77 4 0.02% 12.53% 16.89% + { 74880, 2, 2}, // 78 7 0.03% 12.53% 14.26% + { 87296, 1, 2}, // 79 3 0.12% 12.54% 16.58% + {104832, 2, 2}, // 80 5 0.03% 12.54% 20.09% + {112256, 3, 2}, // 81 7 0.09% 12.54% 7.08% + {131072, 1, 2}, // 82 2 0.02% 12.53% 16.76% + {149760, 3, 2}, // 83 5 4.79% 12.88% 14.26% + {174720, 2, 2}, // 84 3 0.03% 12.54% 16.67% + {196608, 3, 2}, // 85 4 0.01% 12.53% 12.53% + {209664, 4, 2}, // 86 5 0.03% 12.54% 6.64% + {262144, 1, 2}, // 87 1 0.02% 0.03% 25.03% }; #elif TCMALLOC_PAGE_SHIFT == 12 static_assert(kMaxSize == 8192, "kMaxSize mismatch"); -static const int kCount = 46; -static_assert(kCount <= kNumClasses); -const int SizeMap::kLegacySizeClassesCount = kCount; -const SizeClassInfo SizeMap::kLegacySizeClasses[SizeMap::kLegacySizeClassesCount] = { - // , , - { 0, 0, 0}, // +Inf% - { 8, 1, 32}, // 1.17% - { 16, 1, 32}, // 1.17% - { 32, 1, 32}, // 1.17% - { 48, 1, 32}, // 1.57% - { 64, 1, 32}, // 1.17% - { 80, 1, 32}, // 1.57% - { 96, 1, 32}, // 2.78% - { 112, 1, 32}, // 2.78% - { 128, 1, 32}, // 1.17% - { 144, 1, 32}, // 2.78% - { 160, 1, 32}, // 3.60% - { 176, 1, 32}, // 2.37% - { 192, 1, 32}, // 2.78% - { 208, 1, 32}, // 4.86% - { 224, 1, 32}, // 2.78% - { 240, 1, 32}, // 1.57% - { 256, 1, 32}, // 1.17% - { 272, 1, 32}, // 1.57% - { 288, 1, 32}, // 2.78% - { 304, 1, 32}, // 4.86% - { 336, 1, 32}, // 2.78% - { 368, 1, 32}, // 2.37% - { 400, 1, 32}, // 3.60% - { 448, 1, 32}, // 2.78% - { 512, 1, 32}, // 1.17% - { 576, 2, 32}, // 2.18% - { 640, 2, 32}, // 7.29% - { 704, 2, 32}, // 6.40% - { 768, 2, 32}, // 7.29% - { 896, 2, 32}, // 2.18% - { 1024, 2, 32}, // 0.59% - { 1152, 3, 32}, // 7.08% - { 1280, 3, 32}, // 7.08% - { 1536, 3, 32}, // 0.39% - { 1792, 4, 32}, // 1.88% - { 2048, 4, 32}, // 0.29% - { 2304, 4, 28}, // 1.88% - { 2688, 4, 24}, // 1.88% - { 3200, 4, 20}, // 2.70% - { 3584, 7, 18}, // 0.17% - { 4096, 4, 16}, // 0.29% - { 5376, 4, 12}, // 1.88% - { 6144, 3, 10}, // 0.39% - { 7168, 7, 9}, // 0.17% - { 8192, 4, 8}, // 0.29% +static constexpr SizeClassAssumptions Assumptions{ + .has_expanded_classes = false, + .span_size = 48, + .sampling_interval = 524288, + .large_size = 1024, + .large_size_alignment = 128, +}; +static constexpr SizeClassInfo List[] = { +// | waste | +// bytes pages batch class objs |fixed sampling| inc + { 0, 0, 0}, // 0 0 0.00% 0.00% 0.00% + { 8, 1, 32}, // 0 512 1.16% 0.92% 0.00% + { 16, 1, 32}, // 1 256 1.16% 0.92% 100.00% + { 32, 1, 32}, // 2 128 1.16% 0.92% 100.00% + { 48, 1, 32}, // 3 85 1.54% 0.92% 50.00% + { 64, 1, 32}, // 4 64 1.16% 0.92% 33.33% + { 80, 1, 32}, // 5 51 1.54% 0.92% 25.00% + { 96, 1, 32}, // 6 42 2.70% 0.92% 20.00% + { 112, 1, 32}, // 7 36 2.70% 0.92% 16.67% + { 128, 1, 32}, // 8 32 1.16% 0.92% 14.29% + { 144, 1, 32}, // 9 28 2.70% 0.92% 12.50% + { 160, 1, 32}, // 10 25 3.47% 0.92% 11.11% + { 176, 1, 32}, // 11 23 2.32% 0.92% 10.00% + { 192, 1, 32}, // 12 21 2.70% 0.92% 9.09% + { 208, 1, 32}, // 13 19 4.63% 0.92% 8.33% + { 224, 1, 32}, // 14 18 2.70% 0.92% 7.69% + { 240, 1, 32}, // 15 17 1.54% 0.92% 7.14% + { 256, 1, 32}, // 16 16 1.16% 0.92% 6.67% + { 272, 1, 32}, // 17 15 1.54% 0.92% 6.25% + { 288, 1, 32}, // 18 14 2.70% 0.92% 5.88% + { 304, 1, 32}, // 19 13 4.63% 0.92% 5.56% + { 336, 1, 32}, // 20 12 2.70% 0.92% 10.53% + { 368, 1, 32}, // 21 11 2.32% 0.92% 9.52% + { 448, 1, 32}, // 22 9 2.70% 0.92% 21.74% + { 512, 1, 32}, // 23 8 1.16% 0.92% 14.29% + { 576, 2, 32}, // 24 14 2.14% 0.92% 12.50% + { 640, 2, 32}, // 25 12 6.80% 0.92% 11.11% + { 704, 2, 32}, // 26 11 6.02% 0.92% 10.00% + { 768, 2, 32}, // 27 10 6.80% 0.93% 9.09% + { 896, 2, 32}, // 28 9 2.14% 0.92% 16.67% + { 1024, 2, 32}, // 29 8 0.58% 0.92% 14.29% + { 1152, 3, 32}, // 30 10 6.61% 0.93% 12.50% + { 1280, 3, 32}, // 31 9 6.61% 0.93% 11.11% + { 1536, 3, 32}, // 32 8 0.39% 0.92% 20.00% + { 1792, 4, 32}, // 33 9 1.85% 0.92% 16.67% + { 2048, 4, 32}, // 34 8 0.29% 0.92% 14.29% + { 2304, 4, 28}, // 35 7 1.85% 0.92% 12.50% + { 2688, 4, 24}, // 36 6 1.85% 0.93% 16.67% + { 3200, 4, 20}, // 37 5 2.63% 0.93% 19.05% + { 3584, 7, 18}, // 38 8 0.17% 0.92% 12.00% + { 4096, 4, 16}, // 39 4 0.29% 0.92% 14.29% + { 4736, 5, 13}, // 40 4 7.72% 1.77% 15.62% + { 5376, 4, 12}, // 41 3 1.85% 1.72% 13.51% + { 6144, 3, 10}, // 42 2 0.39% 1.70% 14.29% + { 7168, 7, 9}, // 43 4 0.17% 1.70% 16.67% + { 8192, 4, 8}, // 44 2 0.29% 1.70% 14.29% }; #else #error "Unsupported TCMALLOC_PAGE_SHIFT value!" @@ -706,6 +757,9 @@ const SizeClassInfo SizeMap::kLegacySizeClasses[SizeMap::kLegacySizeClassesCount #endif // clang-format on +static_assert(sizeof(List) / sizeof(List[0]) <= kNumBaseClasses); +extern constexpr SizeClasses kLegacySizeClasses{List, Assumptions}; + } // namespace tcmalloc_internal } // namespace tcmalloc GOOGLE_MALLOC_SECTION_END diff --git a/contrib/libs/tcmalloc/tcmalloc/libc_override.h b/contrib/libs/tcmalloc/tcmalloc/libc_override.h index 89f8e4e5c817..ec99f52567ca 100644 --- a/contrib/libs/tcmalloc/tcmalloc/libc_override.h +++ b/contrib/libs/tcmalloc/tcmalloc/libc_override.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,15 +26,193 @@ #define TCMALLOC_LIBC_OVERRIDE_H_ #include +#include +#include -#include "tcmalloc/tcmalloc.h" +#include +#include +#include + +#include "tcmalloc/tcmalloc.h" // IWYU pragma: keep + +#define TCMALLOC_ALIAS(tc_fn) \ + __attribute__((alias(#tc_fn), visibility("default"))) + +// NOLINTBEGIN(misc-definitions-in-headers) #if defined(__GLIBC__) -#include "tcmalloc/libc_override_glibc.h" + +#define TCMALLOC_NOTHROW noexcept + +extern "C" { + +void* __libc_malloc(size_t size) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalMalloc); +void __libc_free(void* ptr) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalFree); +void* __libc_realloc(void* ptr, size_t size) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalRealloc); +void* __libc_calloc(size_t n, size_t size) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalCalloc); +void __libc_cfree(void* ptr) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalCfree); +void* __libc_memalign(size_t align, size_t s) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalMemalign); +void* __libc_valloc(size_t size) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalValloc); +void* __libc_pvalloc(size_t size) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalPvalloc); +int __posix_memalign(void** r, size_t a, size_t s) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalPosixMemalign); + +// We also have to hook libc malloc. While our work with weak symbols +// should make sure libc malloc is never called in most situations, it +// can be worked around by shared libraries with the DEEPBIND +// environment variable set. The below hooks libc to call our malloc +// routines even in that situation. In other situations, this hook +// should never be called. + +static void* glibc_override_malloc(size_t size, const void* caller) { + return TCMallocInternalMalloc(size); +} +static void* glibc_override_realloc(void* ptr, size_t size, + const void* caller) { + return TCMallocInternalRealloc(ptr, size); +} +static void glibc_override_free(void* ptr, const void* caller) { + TCMallocInternalFree(ptr); +} +static void* glibc_override_memalign(size_t align, size_t size, + const void* caller) { + return TCMallocInternalMemalign(align, size); +} + +// We should be using __malloc_initialize_hook here. (See +// http://swoolley.org/man.cgi/3/malloc_hook.) However, this causes weird +// linker errors with programs that link with -static, so instead we just assign +// the vars directly at static-constructor time. That should serve the same +// effect of making sure the hooks are set before the first malloc call the +// program makes. + +// Glibc-2.14 and above make __malloc_hook and friends volatile +#ifndef __MALLOC_HOOK_VOLATILE +#define __MALLOC_HOOK_VOLATILE /**/ +#endif + +void* (*__MALLOC_HOOK_VOLATILE __malloc_hook)(size_t, const void*) = + &glibc_override_malloc; +void* (*__MALLOC_HOOK_VOLATILE __realloc_hook)(void*, size_t, const void*) = + &glibc_override_realloc; +void (*__MALLOC_HOOK_VOLATILE __free_hook)(void*, + const void*) = &glibc_override_free; +void* (*__MALLOC_HOOK_VOLATILE __memalign_hook)(size_t, size_t, const void*) = + &glibc_override_memalign; + +} // extern "C" #else -#include "tcmalloc/libc_override_redefine.h" +#define TCMALLOC_NOTHROW + +#endif // defined(__GLIBC__) + +void* operator new(size_t size) noexcept(false) + TCMALLOC_ALIAS(TCMallocInternalNew); +void operator delete(void* p) noexcept TCMALLOC_ALIAS(TCMallocInternalDelete); +void operator delete(void* p, size_t size) noexcept + TCMALLOC_ALIAS(TCMallocInternalDeleteSized); +void* operator new[](size_t size) noexcept(false) + TCMALLOC_ALIAS(TCMallocInternalNewArray); +void operator delete[](void* p) noexcept + TCMALLOC_ALIAS(TCMallocInternalDeleteArray); +void operator delete[](void* p, size_t size) noexcept + TCMALLOC_ALIAS(TCMallocInternalDeleteArraySized); +void* operator new(size_t size, const std::nothrow_t& nt) noexcept + TCMALLOC_ALIAS(TCMallocInternalNewNothrow); +void* operator new[](size_t size, const std::nothrow_t& nt) noexcept + TCMALLOC_ALIAS(TCMallocInternalNewArrayNothrow); +void operator delete(void* p, const std::nothrow_t& nt) noexcept + TCMALLOC_ALIAS(TCMallocInternalDeleteNothrow); +void operator delete[](void* p, const std::nothrow_t& nt) noexcept + TCMALLOC_ALIAS(TCMallocInternalDeleteArrayNothrow); + +void* operator new(size_t size, std::align_val_t alignment) noexcept(false) + TCMALLOC_ALIAS(TCMallocInternalNewAligned); +void* operator new(size_t size, std::align_val_t alignment, + const std::nothrow_t&) noexcept + TCMALLOC_ALIAS(TCMallocInternalNewAlignedNothrow); +void operator delete(void* p, std::align_val_t alignment) noexcept + TCMALLOC_ALIAS(TCMallocInternalDeleteAligned); +void operator delete(void* p, std::align_val_t alignment, + const std::nothrow_t&) noexcept + TCMALLOC_ALIAS(TCMallocInternalDeleteAlignedNothrow); +void operator delete(void* p, size_t size, std::align_val_t alignment) noexcept + TCMALLOC_ALIAS(TCMallocInternalDeleteSizedAligned); +void* operator new[](size_t size, std::align_val_t alignment) noexcept(false) + TCMALLOC_ALIAS(TCMallocInternalNewArrayAligned); +void* operator new[](size_t size, std::align_val_t alignment, + const std::nothrow_t&) noexcept + TCMALLOC_ALIAS(TCMallocInternalNewArrayAlignedNothrow); +void operator delete[](void* p, std::align_val_t alignment) noexcept + TCMALLOC_ALIAS(TCMallocInternalDeleteArrayAligned); +void operator delete[](void* p, std::align_val_t alignment, + const std::nothrow_t&) noexcept + TCMALLOC_ALIAS(TCMallocInternalDeleteArrayAlignedNothrow); +void operator delete[](void* p, size_t size, + std::align_val_t alignment) noexcept + TCMALLOC_ALIAS(TCMallocInternalDeleteArraySizedAligned); + +extern "C" { + +void* malloc(size_t size) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalMalloc); +void free(void* ptr) TCMALLOC_NOTHROW TCMALLOC_ALIAS(TCMallocInternalFree); +void free_sized(void* ptr, size_t size) + TCMALLOC_ALIAS(TCMallocInternalFreeSized); +void free_aligned_sized(void* ptr, size_t align, size_t size) + TCMALLOC_ALIAS(TCMallocInternalFreeAlignedSized); +void sdallocx(void* ptr, size_t size, int flags) noexcept + TCMALLOC_ALIAS(TCMallocInternalSdallocx); +void* realloc(void* ptr, size_t size) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalRealloc); +void* reallocarray(void* ptr, size_t n, size_t size) + TCMALLOC_ALIAS(TCMallocInternalReallocArray); +void* calloc(size_t n, size_t size) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalCalloc); +void cfree(void* ptr) TCMALLOC_NOTHROW TCMALLOC_ALIAS(TCMallocInternalCfree); +void* memalign(size_t align, size_t s) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalMemalign); +void* aligned_alloc(size_t align, size_t s) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalAlignedAlloc); +void* valloc(size_t size) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalValloc); +void* pvalloc(size_t size) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalPvalloc); +int posix_memalign(void** r, size_t a, size_t s) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalPosixMemalign); +void malloc_stats(void) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalMallocStats); +int malloc_trim(size_t pad) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalMallocTrim); +int mallopt(int cmd, int value) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalMallOpt); +#ifdef TCMALLOC_HAVE_STRUCT_MALLINFO +struct mallinfo mallinfo(void) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalMallInfo); +#endif +#ifdef TCMALLOC_HAVE_STRUCT_MALLINFO2 +struct mallinfo2 mallinfo2(void) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalMallInfo2); #endif +int malloc_info(int opts, FILE* fp) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalMallocInfo); +size_t malloc_size(void* p) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalMallocSize); +size_t malloc_usable_size(void* p) TCMALLOC_NOTHROW + TCMALLOC_ALIAS(TCMallocInternalMallocSize); + +} // extern "C" + +// NOLINTEND(misc-definitions-in-headers) #endif // TCMALLOC_LIBC_OVERRIDE_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/libc_override_gcc_and_weak.h b/contrib/libs/tcmalloc/tcmalloc/libc_override_gcc_and_weak.h deleted file mode 100644 index 709bcb727fef..000000000000 --- a/contrib/libs/tcmalloc/tcmalloc/libc_override_gcc_and_weak.h +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2019 The TCMalloc Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Used to override malloc routines on systems that define the -// memory allocation routines to be weak symbols in their libc -// (almost all unix-based systems are like this), on gcc, which -// suppports the 'alias' attribute. - -#ifndef TCMALLOC_LIBC_OVERRIDE_GCC_AND_WEAK_INL_H_ -#define TCMALLOC_LIBC_OVERRIDE_GCC_AND_WEAK_INL_H_ - -#include - -#include - -#include "tcmalloc/tcmalloc.h" - -#ifndef __GNUC__ -#error libc_override_gcc_and_weak.h is for gcc distributions only. -#endif - -// visibility("default") ensures that these symbols are always exported, even -// with -fvisibility=hidden. -#define TCMALLOC_ALIAS(tc_fn) \ - __attribute__((alias(#tc_fn), visibility("default"))) - -void* operator new(size_t size) noexcept(false) - TCMALLOC_ALIAS(TCMallocInternalNew); -void operator delete(void* p) noexcept TCMALLOC_ALIAS(TCMallocInternalDelete); -void operator delete(void* p, size_t size) noexcept - TCMALLOC_ALIAS(TCMallocInternalDeleteSized); -void* operator new[](size_t size) noexcept(false) - TCMALLOC_ALIAS(TCMallocInternalNewArray); -void operator delete[](void* p) noexcept - TCMALLOC_ALIAS(TCMallocInternalDeleteArray); -void operator delete[](void* p, size_t size) noexcept - TCMALLOC_ALIAS(TCMallocInternalDeleteArraySized); -void* operator new(size_t size, const std::nothrow_t& nt) noexcept - TCMALLOC_ALIAS(TCMallocInternalNewNothrow); -void* operator new[](size_t size, const std::nothrow_t& nt) noexcept - TCMALLOC_ALIAS(TCMallocInternalNewArrayNothrow); -void operator delete(void* p, const std::nothrow_t& nt) noexcept - TCMALLOC_ALIAS(TCMallocInternalDeleteNothrow); -void operator delete[](void* p, const std::nothrow_t& nt) noexcept - TCMALLOC_ALIAS(TCMallocInternalDeleteArrayNothrow); - -void* operator new(size_t size, std::align_val_t alignment) noexcept(false) - TCMALLOC_ALIAS(TCMallocInternalNewAligned); -void* operator new(size_t size, std::align_val_t alignment, - const std::nothrow_t&) noexcept - TCMALLOC_ALIAS(TCMallocInternalNewAligned_nothrow); -void operator delete(void* p, std::align_val_t alignment) noexcept - TCMALLOC_ALIAS(TCMallocInternalDeleteAligned); -void operator delete(void* p, std::align_val_t alignment, - const std::nothrow_t&) noexcept - TCMALLOC_ALIAS(TCMallocInternalDeleteAligned_nothrow); -void operator delete(void* p, size_t size, std::align_val_t alignment) noexcept - TCMALLOC_ALIAS(TCMallocInternalDeleteSizedAligned); -void* operator new[](size_t size, std::align_val_t alignment) noexcept(false) - TCMALLOC_ALIAS(TCMallocInternalNewArrayAligned); -void* operator new[](size_t size, std::align_val_t alignment, - const std::nothrow_t&) noexcept - TCMALLOC_ALIAS(TCMallocInternalNewArrayAligned_nothrow); -void operator delete[](void* p, std::align_val_t alignment) noexcept - TCMALLOC_ALIAS(TCMallocInternalDeleteArrayAligned); -void operator delete[](void* p, std::align_val_t alignment, - const std::nothrow_t&) noexcept - TCMALLOC_ALIAS(TCMallocInternalDeleteArrayAligned_nothrow); -void operator delete[](void* p, size_t size, - std::align_val_t alignemnt) noexcept - TCMALLOC_ALIAS(TCMallocInternalDeleteArraySizedAligned); - -extern "C" { -void* malloc(size_t size) noexcept TCMALLOC_ALIAS(TCMallocInternalMalloc); -void free(void* ptr) noexcept TCMALLOC_ALIAS(TCMallocInternalFree); -void sdallocx(void* ptr, size_t size, int flags) noexcept - TCMALLOC_ALIAS(TCMallocInternalSdallocx); -void* realloc(void* ptr, size_t size) noexcept - TCMALLOC_ALIAS(TCMallocInternalRealloc); -void* calloc(size_t n, size_t size) noexcept - TCMALLOC_ALIAS(TCMallocInternalCalloc); -void cfree(void* ptr) noexcept TCMALLOC_ALIAS(TCMallocInternalCfree); -void* memalign(size_t align, size_t s) noexcept - TCMALLOC_ALIAS(TCMallocInternalMemalign); -void* aligned_alloc(size_t align, size_t s) noexcept - TCMALLOC_ALIAS(TCMallocInternalAlignedAlloc); -void* valloc(size_t size) noexcept TCMALLOC_ALIAS(TCMallocInternalValloc); -void* pvalloc(size_t size) noexcept TCMALLOC_ALIAS(TCMallocInternalPvalloc); -int posix_memalign(void** r, size_t a, size_t s) noexcept - TCMALLOC_ALIAS(TCMallocInternalPosixMemalign); -void malloc_stats(void) noexcept TCMALLOC_ALIAS(TCMallocInternalMallocStats); -int mallopt(int cmd, int value) noexcept - TCMALLOC_ALIAS(TCMallocInternalMallOpt); -#ifdef TCMALLOC_HAVE_STRUCT_MALLINFO -struct mallinfo mallinfo(void) noexcept - TCMALLOC_ALIAS(TCMallocInternalMallocInfo); -#endif -size_t malloc_size(void* p) noexcept TCMALLOC_ALIAS(TCMallocInternalMallocSize); -size_t malloc_usable_size(void* p) noexcept - TCMALLOC_ALIAS(TCMallocInternalMallocSize); -} // extern "C" - -#endif // TCMALLOC_LIBC_OVERRIDE_GCC_AND_WEAK_INL_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/libc_override_glibc.h b/contrib/libs/tcmalloc/tcmalloc/libc_override_glibc.h deleted file mode 100644 index 8e23b6eb78a7..000000000000 --- a/contrib/libs/tcmalloc/tcmalloc/libc_override_glibc.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2019 The TCMalloc Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Used to override malloc routines on systems that are using glibc. - -#ifndef TCMALLOC_LIBC_OVERRIDE_GLIBC_INL_H_ -#define TCMALLOC_LIBC_OVERRIDE_GLIBC_INL_H_ - -#include -#include - -#include "tcmalloc/tcmalloc.h" - -#ifndef __GLIBC__ -#error libc_override_glibc.h is for glibc distributions only. -#endif - -// In glibc, the memory-allocation methods are weak symbols, so we can -// just override them with our own. If we're using gcc, we can use -// __attribute__((alias)) to do the overriding easily (exception: -// Mach-O, which doesn't support aliases). Otherwise we have to use a -// function call. -#if !defined(__GNUC__) || defined(__MACH__) - -#include "libc_override_redefine.h" - -#else // #if !defined(__GNUC__) || defined(__MACH__) - -// If we get here, we're a gcc system, so do all the overriding we do -// with gcc. This does the overriding of all the 'normal' memory -// allocation. -#include "libc_override_gcc_and_weak.h" - -// We also have to do some glibc-specific overriding. Some library -// routines on RedHat 9 allocate memory using malloc() and free it -// using __libc_free() (or vice-versa). Since we provide our own -// implementations of malloc/free, we need to make sure that the -// __libc_XXX variants (defined as part of glibc) also point to the -// same implementations. Since it only matters for redhat, we -// do it inside the gcc #ifdef, since redhat uses gcc. -// TODO(b/134690953): only do this if we detect we're an old enough glibc? - -extern "C" { -void* __libc_malloc(size_t size) noexcept - TCMALLOC_ALIAS(TCMallocInternalMalloc); -void __libc_free(void* ptr) noexcept TCMALLOC_ALIAS(TCMallocInternalFree); -void* __libc_realloc(void* ptr, size_t size) noexcept - TCMALLOC_ALIAS(TCMallocInternalRealloc); -void* __libc_calloc(size_t n, size_t size) noexcept - TCMALLOC_ALIAS(TCMallocInternalCalloc); -void __libc_cfree(void* ptr) noexcept TCMALLOC_ALIAS(TCMallocInternalCfree); -void* __libc_memalign(size_t align, size_t s) noexcept - TCMALLOC_ALIAS(TCMallocInternalMemalign); -void* __libc_valloc(size_t size) noexcept - TCMALLOC_ALIAS(TCMallocInternalValloc); -void* __libc_pvalloc(size_t size) noexcept - TCMALLOC_ALIAS(TCMallocInternalPvalloc); -int __posix_memalign(void** r, size_t a, size_t s) noexcept - TCMALLOC_ALIAS(TCMallocInternalPosixMemalign); -} // extern "C" - -#endif // #if defined(__GNUC__) && !defined(__MACH__) - -// We also have to hook libc malloc. While our work with weak symbols -// should make sure libc malloc is never called in most situations, it -// can be worked around by shared libraries with the DEEPBIND -// environment variable set. The below hooks libc to call our malloc -// routines even in that situation. In other situations, this hook -// should never be called. -extern "C" { -static void* glibc_override_malloc(size_t size, const void* caller) { - return TCMallocInternalMalloc(size); -} -static void* glibc_override_realloc(void* ptr, size_t size, - const void* caller) { - return TCMallocInternalRealloc(ptr, size); -} -static void glibc_override_free(void* ptr, const void* caller) { - TCMallocInternalFree(ptr); -} -static void* glibc_override_memalign(size_t align, size_t size, - const void* caller) { - return TCMallocInternalMemalign(align, size); -} - -// We should be using __malloc_initialize_hook here. (See -// http://swoolley.org/man.cgi/3/malloc_hook.) However, this causes weird -// linker errors with programs that link with -static, so instead we just assign -// the vars directly at static-constructor time. That should serve the same -// effect of making sure the hooks are set before the first malloc call the -// program makes. - -// Glibc-2.14 and above make __malloc_hook and friends volatile -#ifndef __MALLOC_HOOK_VOLATILE -#define __MALLOC_HOOK_VOLATILE /**/ -#endif - -void* (*__MALLOC_HOOK_VOLATILE __malloc_hook)(size_t, const void*) = - &glibc_override_malloc; -void* (*__MALLOC_HOOK_VOLATILE __realloc_hook)(void*, size_t, const void*) = - &glibc_override_realloc; -void (*__MALLOC_HOOK_VOLATILE __free_hook)(void*, - const void*) = &glibc_override_free; -void* (*__MALLOC_HOOK_VOLATILE __memalign_hook)(size_t, size_t, const void*) = - &glibc_override_memalign; - -} // extern "C" - -#endif // TCMALLOC_LIBC_OVERRIDE_GLIBC_INL_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/libc_override_redefine.h b/contrib/libs/tcmalloc/tcmalloc/libc_override_redefine.h deleted file mode 100644 index b1655461c39d..000000000000 --- a/contrib/libs/tcmalloc/tcmalloc/libc_override_redefine.h +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2019 The TCMalloc Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Used on systems that don't have their own definition of -// malloc/new/etc. (Typically this will be a windows msvcrt.dll that -// has been edited to remove the definitions.) We can just define our -// own as normal functions. -// -// This should also work on systems were all the malloc routines are -// defined as weak symbols, and there's no support for aliasing. - -#ifndef TCMALLOC_LIBC_OVERRIDE_REDEFINE_H_ -#define TCMALLOC_LIBC_OVERRIDE_REDEFINE_H_ - -#include -#include - -#include "tcmalloc/tcmalloc.h" - -void* operator new(size_t size) { return TCMallocInternalNew(size); } -void operator delete(void* p) noexcept { TCMallocInternalDelete(p); } -void* operator new[](size_t size) { return TCMallocInternalNewArray(size); } -void operator delete[](void* p) noexcept { TCMallocInternalDeleteArray(p); } -void* operator new(size_t size, const std::nothrow_t& nt) noexcept { - return TCMallocInternalNewNothrow(size, nt); -} -void* operator new[](size_t size, const std::nothrow_t& nt) noexcept { - return TCMallocInternalNewArrayNothrow(size, nt); -} -void operator delete(void* ptr, const std::nothrow_t& nt) noexcept { - return TCMallocInternalDeleteNothrow(ptr, nt); -} -void operator delete[](void* ptr, const std::nothrow_t& nt) noexcept { - return TCMallocInternalDeleteArrayNothrow(ptr, nt); -} - -extern "C" { -void* malloc(size_t s) { return TCMallocInternalMalloc(s); } -void* calloc(size_t n, size_t s) { return TCMallocInternalCalloc(n, s); } -void* realloc(void* p, size_t s) { return TCMallocInternalRealloc(p, s); } -void free(void* p) { TCMallocInternalFree(p); } -void* memalign(size_t a, size_t s) { return TCMallocInternalMemalign(a, s); } -int posix_memalign(void** r, size_t a, size_t s) { - return TCMallocInternalPosixMemalign(r, a, s); -} -size_t malloc_usable_size(void* p) { return TCMallocInternalMallocSize(p); } - -// tcmalloc extension -void sdallocx(void* p, size_t s, int flags) noexcept { - TCMallocInternalSdallocx(p, s, flags); -} - -#if defined(__GLIBC__) || defined(__NEWLIB__) -// SunOS extension -void cfree(void* p) { TCMallocInternalCfree(p); } -#endif - -#if defined(OS_MACOSX) || defined(__BIONIC__) || defined(__GLIBC__) || \ - defined(__NEWLIB__) || defined(__UCLIBC__) -// Obsolete memalign -void* valloc(size_t s) { return TCMallocInternalValloc(s); } -#endif - -#if defined(__BIONIC__) || defined(__GLIBC__) || defined(__NEWLIB__) -// Obsolete memalign -void* pvalloc(size_t s) { return TCMallocInternalPvalloc(s); } -#endif - -#if defined(__GLIBC__) || defined(__NEWLIB__) || defined(__UCLIBC__) -void malloc_stats(void) { TCMallocInternalMallocStats(); } -#endif - -#if defined(__BIONIC__) || defined(__GLIBC__) || defined(__NEWLIB__) || \ - defined(__UCLIBC__) -int mallopt(int cmd, int v) { return TCMallocInternalMallOpt(cmd, v); } -#endif - -#ifdef TCMALLOC_HAVE_STRUCT_MALLINFO -struct mallinfo mallinfo(void) { - return TCMallocInternalMallocInfo(); -} -#endif - -#if defined(__GLIBC__) -size_t malloc_size(void* p) { return TCMallocInternalMallocSize(p); } -#endif -} // extern "C" - -#endif // TCMALLOC_LIBC_OVERRIDE_REDEFINE_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/malloc_extension.cc b/contrib/libs/tcmalloc/tcmalloc/malloc_extension.cc index 5a4ad7004385..dc4aeb5f3b5c 100644 --- a/contrib/libs/tcmalloc/tcmalloc/malloc_extension.cc +++ b/contrib/libs/tcmalloc/tcmalloc/malloc_extension.cc @@ -18,18 +18,108 @@ #include #include +#include #include +#include +#include #include #include +#include #include +#include #include "absl/base/attributes.h" +#include "absl/base/call_once.h" #include "absl/base/internal/low_level_alloc.h" -#include "absl/memory/memory.h" +#include "absl/functional/function_ref.h" +#include "absl/strings/string_view.h" #include "absl/time/time.h" -#include "tcmalloc/internal/parameter_accessors.h" +#include "absl/types/optional.h" +#include "absl/types/span.h" #include "tcmalloc/internal_malloc_extension.h" +#if (defined(ABSL_HAVE_ADDRESS_SANITIZER) || \ + defined(ABSL_HAVE_MEMORY_SANITIZER) || \ + defined(ABSL_HAVE_THREAD_SANITIZER) || \ + defined(ABSL_HAVE_HWADDRESS_SANITIZER) || \ + defined(ABSL_HAVE_DATAFLOW_SANITIZER) || \ + defined(ABSL_HAVE_LEAK_SANITIZER)) && \ + !defined(TCMALLOC_INTERNAL_SELSAN) +#define TCMALLOC_UNDER_SANITIZERS 1 +static constexpr size_t kTerabyte = (size_t)(1ULL << 40); + +#include + +#if defined(ABSL_HAVE_ADDRESS_SANITIZER) +static size_t SanitizerVirtualMemoryOverhead() { return 20 * kTerabyte; } + +static size_t SanitizerMemoryUsageMultiplier() { return 2; } + +static size_t SanitizerStackSizeMultiplier() { return 4; } +#endif + +#if defined(ABSL_HAVE_THREAD_SANITIZER) +static size_t SanitizerVirtualMemoryOverhead() { return 98 * kTerabyte; } + +static size_t SanitizerMemoryUsageMultiplier() { return 5; } + +static size_t SanitizerStackSizeMultiplier() { return 5; } +#endif + +#if defined(ABSL_HAVE_MEMORY_SANITIZER) +#include + +static size_t SanitizerVirtualMemoryOverhead() { + return (__msan_get_track_origins() ? 40 : 20) * kTerabyte; +} + +static size_t SanitizerMemoryUsageMultiplier() { + return __msan_get_track_origins() ? 3 : 2; +} + +static size_t SanitizerStackSizeMultiplier() { + // Very rough estimate based on analysing "sub $.*, %rsp" instructions. + return 2; +} +#endif + +#if defined(ABSL_HAVE_HWADDRESS_SANITIZER) +static size_t SanitizerVirtualMemoryOverhead() { return 20 * kTerabyte; } + +static size_t SanitizerMemoryUsageMultiplier() { return 1; } + +static size_t SanitizerStackSizeMultiplier() { return 1; } +#endif + +#if defined(ABSL_HAVE_DATAFLOW_SANITIZER) +#include + +static size_t SanitizerVirtualMemoryOverhead() { return 40 * kTerabyte; } + +static size_t SanitizerMemoryUsageMultiplier() { + return dfsan_get_track_origins() ? 3 : 2; +} + +static size_t SanitizerStackSizeMultiplier() { + // Very rough estimate based on analysing "sub $.*, %rsp" instructions. + return dfsan_get_track_origins() ? 3 : 2; +} +#endif + +#if defined(ABSL_HAVE_LEAK_SANITIZER) && \ + !defined(ABSL_HAVE_ADDRESS_SANITIZER) && \ + !defined(ABSL_HAVE_HWADDRESS_SANITIZER) +static size_t SanitizerVirtualMemoryOverhead() { return 0; } + +static size_t SanitizerMemoryUsageMultiplier() { return 1; } + +static size_t SanitizerStackSizeMultiplier() { return 1; } +#endif + +#else +#define TCMALLOC_UNDER_SANITIZERS 0 +#endif + namespace tcmalloc { MallocExtension::AllocationProfilingToken::AllocationProfilingToken( @@ -60,25 +150,31 @@ void Profile::Iterate(absl::FunctionRef f) const { impl_->Iterate(f); } -int64_t Profile::Period() const { +ProfileType Profile::Type() const { if (!impl_) { - return -1; + return ProfileType::kDoNotUse; } - return impl_->Period(); + return impl_->Type(); } -ProfileType Profile::Type() const { +std::optional Profile::StartTime() const { if (!impl_) { - return ProfileType::kDoNotUse; + return std::nullopt; } - return impl_->Type(); + return impl_->StartTime(); } -AddressRegion::~AddressRegion() {} +absl::Duration Profile::Duration() const { + if (!impl_) { + return absl::ZeroDuration(); + } + + return impl_->Duration(); +} -AddressRegionFactory::~AddressRegionFactory() {} +AddressRegion::~AddressRegion() {} size_t AddressRegionFactory::GetStats(absl::Span buffer) { static_cast(buffer); @@ -99,8 +195,12 @@ size_t AddressRegionFactory::InternalBytesAllocated() { void* AddressRegionFactory::MallocInternal(size_t size) { // Use arena without malloc hooks to avoid HeapChecker reporting a leak. - static auto* arena = - absl::base_internal::LowLevelAlloc::NewArena(/*flags=*/0); + ABSL_CONST_INIT static absl::base_internal::LowLevelAlloc::Arena* arena; + ABSL_CONST_INIT static absl::once_flag flag; + + absl::base_internal::LowLevelCallOnce(&flag, [&]() { + arena = absl::base_internal::LowLevelAlloc::NewArena(/*flags=*/0); + }); void* result = absl::base_internal::LowLevelAlloc::AllocWithArena(size, arena); if (result) { @@ -117,13 +217,17 @@ void* AddressRegionFactory::MallocInternal(size_t size) { #endif std::string MallocExtension::GetStats() { - std::string ret; #if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS if (&MallocExtension_Internal_GetStats != nullptr) { + std::string ret; MallocExtension_Internal_GetStats(&ret); + return ret; } #endif - return ret; +#if defined(ABSL_HAVE_THREAD_SANITIZER) + return "NOT IMPLEMENTED"; +#endif + return ""; } void MallocExtension::ReleaseMemoryToSystem(size_t num_bytes) { @@ -186,6 +290,21 @@ MallocExtension::StartAllocationProfiling() { #endif } +MallocExtension::AllocationProfilingToken +MallocExtension::StartLifetimeProfiling() { +#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS + if (&MallocExtension_Internal_StartLifetimeProfiling == nullptr) { + return {}; + } + + return tcmalloc_internal::AllocationProfilingTokenAccessor::MakeToken( + std::unique_ptr( + MallocExtension_Internal_StartLifetimeProfiling())); +#else + return {}; +#endif +} + void MallocExtension::MarkThreadIdle() { #if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS if (&MallocExtension_Internal_MarkThreadIdle == nullptr) { @@ -194,6 +313,9 @@ void MallocExtension::MarkThreadIdle() { MallocExtension_Internal_MarkThreadIdle(); #endif + // TODO(b/273799005) - move __tsan_on_thread_idle call here from + // testing/tsan/v2/allocator.cconce we have it available in shared tsan + // libraries. } void MallocExtension::MarkThreadBusy() { @@ -206,64 +328,65 @@ void MallocExtension::MarkThreadBusy() { #endif } -MallocExtension::MemoryLimit MallocExtension::GetMemoryLimit() { - MemoryLimit ret; +size_t MallocExtension::GetMemoryLimit(LimitKind limit_kind) { #if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS if (&MallocExtension_Internal_GetMemoryLimit != nullptr) { - MallocExtension_Internal_GetMemoryLimit(&ret); + return MallocExtension_Internal_GetMemoryLimit(limit_kind); } #endif - return ret; + return 0; } -void MallocExtension::SetMemoryLimit( - const MallocExtension::MemoryLimit& limit) { +void MallocExtension::SetMemoryLimit(const size_t limit, LimitKind limit_kind) { #if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS if (&MallocExtension_Internal_SetMemoryLimit != nullptr) { - MallocExtension_Internal_SetMemoryLimit(&limit); + // limit == 0 implies no limit. + const size_t new_limit = + (limit > 0) ? limit : std::numeric_limits::max(); + MallocExtension_Internal_SetMemoryLimit(new_limit, limit_kind); } #endif } -int64_t MallocExtension::GetProfileSamplingRate() { +int64_t MallocExtension::GetProfileSamplingInterval() { #if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS - if (&MallocExtension_Internal_GetProfileSamplingRate != nullptr) { - return MallocExtension_Internal_GetProfileSamplingRate(); + if (&MallocExtension_Internal_GetProfileSamplingInterval != nullptr) { + return MallocExtension_Internal_GetProfileSamplingInterval(); } #endif return -1; } -void MallocExtension::SetProfileSamplingRate(int64_t rate) { +void MallocExtension::SetProfileSamplingInterval(int64_t interval) { #if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS - if (&MallocExtension_Internal_SetProfileSamplingRate != nullptr) { - MallocExtension_Internal_SetProfileSamplingRate(rate); + if (&MallocExtension_Internal_SetProfileSamplingInterval != nullptr) { + MallocExtension_Internal_SetProfileSamplingInterval(interval); } #endif - (void)rate; + (void)interval; } -int64_t MallocExtension::GetGuardedSamplingRate() { +int64_t MallocExtension::GetGuardedSamplingInterval() { #if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS - if (MallocExtension_Internal_GetGuardedSamplingRate == nullptr) { + if (MallocExtension_Internal_GetGuardedSamplingInterval == nullptr) { return -1; } - return MallocExtension_Internal_GetGuardedSamplingRate(); + return MallocExtension_Internal_GetGuardedSamplingInterval(); #else return -1; #endif } -void MallocExtension::SetGuardedSamplingRate(int64_t rate) { +void MallocExtension::SetGuardedSamplingInterval(int64_t interval) { #if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS - if (MallocExtension_Internal_SetGuardedSamplingRate == nullptr) { + if (MallocExtension_Internal_SetGuardedSamplingInterval == nullptr) { return; } - MallocExtension_Internal_SetGuardedSamplingRate(rate); + MallocExtension_Internal_SetGuardedSamplingInterval(interval); #else - (void)rate; + (void)interval; #endif } @@ -287,16 +410,6 @@ bool MallocExtension::PerCpuCachesActive() { #endif } -void MallocExtension::DeactivatePerCpuCaches() { -#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS - if (MallocExtension_Internal_DeactivatePerCpuCaches == nullptr) { - return; - } - - MallocExtension_Internal_DeactivatePerCpuCaches(); -#endif -} - int32_t MallocExtension::GetMaxPerCpuCacheSize() { #if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS if (MallocExtension_Internal_GetMaxPerCpuCacheSize == nullptr) { @@ -371,7 +484,161 @@ void MallocExtension::SetSkipSubreleaseInterval(absl::Duration value) { #endif } -absl::optional MallocExtension::GetNumericProperty( +bool MallocExtension::GetBackgroundProcessActionsEnabled() { +#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS + if (MallocExtension_Internal_GetBackgroundProcessActionsEnabled == nullptr) { + return false; + } + + return MallocExtension_Internal_GetBackgroundProcessActionsEnabled(); +#else + return false; +#endif +} + +void MallocExtension::SetBackgroundProcessActionsEnabled(bool value) { +#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS + if (MallocExtension_Internal_SetBackgroundProcessActionsEnabled == nullptr) { + return; + } + + MallocExtension_Internal_SetBackgroundProcessActionsEnabled(value); +#else + (void)value; +#endif +} + +absl::Duration MallocExtension::GetBackgroundProcessSleepInterval() { +#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS + if (MallocExtension_Internal_GetBackgroundProcessSleepInterval == nullptr) { + return absl::ZeroDuration(); + } + + absl::Duration value; + MallocExtension_Internal_GetBackgroundProcessSleepInterval(&value); + return value; +#else + return absl::ZeroDuration(); +#endif +} + +void MallocExtension::SetBackgroundProcessSleepInterval(absl::Duration value) { +#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS + if (MallocExtension_Internal_SetBackgroundProcessSleepInterval == nullptr) { + return; + } + + MallocExtension_Internal_SetBackgroundProcessSleepInterval(value); +#else + (void)value; +#endif +} + +absl::Duration MallocExtension::GetSkipSubreleaseShortInterval() { +#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS + if (MallocExtension_Internal_GetSkipSubreleaseShortInterval == nullptr) { + return absl::ZeroDuration(); + } + + absl::Duration value; + MallocExtension_Internal_GetSkipSubreleaseShortInterval(&value); + return value; +#else + return absl::ZeroDuration(); +#endif +} + +void MallocExtension::SetSkipSubreleaseShortInterval(absl::Duration value) { +#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS + if (MallocExtension_Internal_SetSkipSubreleaseShortInterval == nullptr) { + return; + } + + MallocExtension_Internal_SetSkipSubreleaseShortInterval(value); +#else + (void)value; +#endif +} + +absl::Duration MallocExtension::GetSkipSubreleaseLongInterval() { +#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS + if (MallocExtension_Internal_GetSkipSubreleaseLongInterval == nullptr) { + return absl::ZeroDuration(); + } + + absl::Duration value; + MallocExtension_Internal_GetSkipSubreleaseLongInterval(&value); + return value; +#else + return absl::ZeroDuration(); +#endif +} + +void MallocExtension::SetSkipSubreleaseLongInterval(absl::Duration value) { +#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS + if (MallocExtension_Internal_SetSkipSubreleaseLongInterval == nullptr) { + return; + } + + MallocExtension_Internal_SetSkipSubreleaseLongInterval(value); +#else + (void)value; +#endif +} + +absl::Duration MallocExtension::GetCacheDemandReleaseShortInterval() { +#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS + if (MallocExtension_Internal_GetCacheDemandReleaseShortInterval == nullptr) { + return absl::ZeroDuration(); + } + + absl::Duration value; + MallocExtension_Internal_GetCacheDemandReleaseShortInterval(&value); + return value; +#else + return absl::ZeroDuration(); +#endif +} + +void MallocExtension::SetCacheDemandReleaseShortInterval(absl::Duration value) { +#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS + if (MallocExtension_Internal_SetCacheDemandReleaseShortInterval == nullptr) { + return; + } + + MallocExtension_Internal_SetCacheDemandReleaseShortInterval(value); +#else + (void)value; +#endif +} + +absl::Duration MallocExtension::GetCacheDemandReleaseLongInterval() { +#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS + if (MallocExtension_Internal_GetCacheDemandReleaseLongInterval == nullptr) { + return absl::ZeroDuration(); + } + + absl::Duration value; + MallocExtension_Internal_GetCacheDemandReleaseLongInterval(&value); + return value; +#else + return absl::ZeroDuration(); +#endif +} + +void MallocExtension::SetCacheDemandReleaseLongInterval(absl::Duration value) { +#if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS + if (MallocExtension_Internal_SetCacheDemandReleaseLongInterval == nullptr) { + return; + } + + MallocExtension_Internal_SetCacheDemandReleaseLongInterval(value); +#else + (void)value; +#endif +} + +std::optional MallocExtension::GetNumericProperty( absl::string_view property) { #if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS if (&MallocExtension_Internal_GetNumericProperty != nullptr) { @@ -382,20 +649,59 @@ absl::optional MallocExtension::GetNumericProperty( } } #endif - return absl::nullopt; +#if TCMALLOC_UNDER_SANITIZERS + // TODO(b/273946827): Add local tcmalloc tests for the various sanitizer + // configs as opposed to depending on + // //testing/sanitizer_common:malloc_extension_test + // LINT.IfChange(SanitizerGetProperty) + if (property == "dynamic_tool.virtual_memory_overhead") { + return SanitizerVirtualMemoryOverhead(); + } + if (property == "dynamic_tool.memory_usage_multiplier") { + return SanitizerMemoryUsageMultiplier(); + } + if (property == "dynamic_tool.stack_size_multiplier") { + return SanitizerStackSizeMultiplier(); + } + if (property == "generic.current_allocated_bytes") { + return __sanitizer_get_current_allocated_bytes(); + } + if (property == "generic.heap_size") { + return __sanitizer_get_heap_size(); + } + if (property == "tcmalloc.per_cpu_caches_active") { + // Queried by ReleasePerCpuMemoryToOS(). + return 0; + } + if (property == "tcmalloc.pageheap_free_bytes") { + return __sanitizer_get_free_bytes(); + } + if (property == "tcmalloc.pageheap_unmapped_bytes") { + return __sanitizer_get_unmapped_bytes(); + } + if (property == "tcmalloc.slack_bytes") { + // Kept for backwards compatibility. + return __sanitizer_get_free_bytes() + __sanitizer_get_unmapped_bytes(); + } + // LINT.ThenChange(:SanitizerGetProperties) +#endif // TCMALLOC_UNDER_SANITIZERS + return std::nullopt; } size_t MallocExtension::GetEstimatedAllocatedSize(size_t size) { return nallocx(size, 0); } -absl::optional MallocExtension::GetAllocatedSize(const void* p) { +std::optional MallocExtension::GetAllocatedSize(const void* p) { #if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS if (MallocExtension_Internal_GetAllocatedSize != nullptr) { return MallocExtension_Internal_GetAllocatedSize(p); } #endif - return absl::nullopt; +#if TCMALLOC_UNDER_SANITIZERS + return __sanitizer_get_allocated_size(p); +#endif + return std::nullopt; } MallocExtension::Ownership MallocExtension::GetOwnership(const void* p) { @@ -403,6 +709,11 @@ MallocExtension::Ownership MallocExtension::GetOwnership(const void* p) { if (MallocExtension_Internal_GetOwnership != nullptr) { return MallocExtension_Internal_GetOwnership(p); } +#endif +#if TCMALLOC_UNDER_SANITIZERS + return __sanitizer_get_ownership(p) + ? tcmalloc::MallocExtension::Ownership::kOwned + : tcmalloc::MallocExtension::Ownership::kNotOwned; #endif return MallocExtension::Ownership::kUnknown; } @@ -410,10 +721,35 @@ MallocExtension::Ownership MallocExtension::GetOwnership(const void* p) { std::map MallocExtension::GetProperties() { std::map ret; +#if TCMALLOC_UNDER_SANITIZERS + // Unlike other extension points this one fills in sanitizer data before the + // weak function is called so that the weak function can override as needed. + // LINT.IfChange(SanitizerGetProperties) + const std::array properties = {"dynamic_tool.virtual_memory_overhead", + "dynamic_tool.memory_usage_multiplier", + "dynamic_tool.stack_size_multiplier", + "generic.current_allocated_bytes", + "generic.heap_size", + "tcmalloc.per_cpu_caches_active", + "tcmalloc.pageheap_free_bytes", + "tcmalloc.pageheap_unmapped_bytes", + "tcmalloc.slack_bytes"}; + // LINT.ThenChange(:SanitizerGetProperty) + + for (const auto& p : properties) { + const auto& value = GetNumericProperty(p); + if (value) { + ret[p].value = *value; + } + } +#endif // TCMALLOC_UNDER_SANITIZERS #if ABSL_INTERNAL_HAVE_WEAK_MALLOCEXTENSION_STUBS if (&MallocExtension_Internal_GetProperties != nullptr) { MallocExtension_Internal_GetProperties(&ret); } + if (&MallocExtension_Internal_GetExperiments != nullptr) { + MallocExtension_Internal_GetExperiments(&ret); + } #endif return ret; } @@ -504,6 +840,9 @@ void MallocExtension::SetSampleUserDataCallbacks( // this weak function with a better implementation. ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE size_t nallocx(size_t size, int) noexcept { +#if TCMALLOC_UNDER_SANITIZERS + return __sanitizer_get_estimated_allocated_size(size); +#endif return size; } @@ -515,8 +854,29 @@ ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE void sdallocx(void* ptr, size_t, free(ptr); } +ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE void free_sized(void* ptr, size_t) { + free(ptr); +} + +ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE void free_aligned_sized(void* ptr, + size_t, + size_t) { + free(ptr); +} + +ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE tcmalloc::sized_ptr_t +__size_returning_new(size_t size) { + return {::operator new(size), size}; +} + +// TODO(b/283856455): Remove once experiment is done. +ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE tcmalloc::sized_ptr_t +__size_returning_new_experiment(size_t size) { + return {::operator new(size), size}; +} + ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE tcmalloc::sized_ptr_t -tcmalloc_size_returning_operator_new(size_t size) { +__size_returning_new_hot_cold(size_t size, __hot_cold_t) { return {::operator new(size), size}; } @@ -526,11 +886,24 @@ tcmalloc_size_returning_operator_new_nothrow(size_t size) noexcept { return {p, p ? size : 0}; } +ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE tcmalloc::sized_ptr_t +tcmalloc_size_returning_operator_new_hot_cold_nothrow(size_t size, + __hot_cold_t) noexcept { + void* p = ::operator new(size, std::nothrow); + return {p, p ? size : 0}; +} + #if defined(_LIBCPP_VERSION) && defined(__cpp_aligned_new) ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE tcmalloc::sized_ptr_t -tcmalloc_size_returning_operator_new_aligned(size_t size, - std::align_val_t alignment) { +__size_returning_new_aligned(size_t size, std::align_val_t alignment) { + return {::operator new(size, alignment), size}; +} + +// TODO(b/283856455): Remove once experiment is done. +ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE tcmalloc::sized_ptr_t +__size_returning_new_aligned_experiment(size_t size, + std::align_val_t alignment) { return {::operator new(size, alignment), size}; } @@ -541,4 +914,63 @@ tcmalloc_size_returning_operator_new_aligned_nothrow( return {p, p ? size : 0}; } +ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE tcmalloc::sized_ptr_t +__size_returning_new_aligned_hot_cold(size_t size, std::align_val_t alignment, + __hot_cold_t) { + return {::operator new(size, alignment), size}; +} + +ABSL_ATTRIBUTE_WEAK ABSL_ATTRIBUTE_NOINLINE tcmalloc::sized_ptr_t +tcmalloc_size_returning_operator_new_aligned_hot_cold_nothrow( + size_t size, std::align_val_t alignment, __hot_cold_t) noexcept { + void* p = ::operator new(size, alignment, std::nothrow); + return {p, p ? size : 0}; +} + #endif // _LIBCPP_VERSION && __cpp_aligned_new + +ABSL_ATTRIBUTE_WEAK void* operator new(size_t size, + tcmalloc::hot_cold_t) noexcept(false) { + return ::operator new(size); +} + +ABSL_ATTRIBUTE_WEAK void* operator new(size_t size, const std::nothrow_t&, + tcmalloc::hot_cold_t) noexcept { + return ::operator new(size, std::nothrow); +} + +ABSL_ATTRIBUTE_WEAK void* operator new[](size_t size, + tcmalloc::hot_cold_t) noexcept(false) { + return ::operator new[](size); +} + +ABSL_ATTRIBUTE_WEAK void* operator new[](size_t size, const std::nothrow_t&, + tcmalloc::hot_cold_t) noexcept { + return ::operator new[](size, std::nothrow); +} + +#ifdef __cpp_aligned_new +ABSL_ATTRIBUTE_WEAK void* operator new(size_t size, std::align_val_t alignment, + tcmalloc::hot_cold_t) noexcept(false) { + return ::operator new(size, alignment); +} + +ABSL_ATTRIBUTE_WEAK void* operator new(size_t size, std::align_val_t alignment, + const std::nothrow_t&, + tcmalloc::hot_cold_t) noexcept { + return ::operator new(size, alignment, std::nothrow); +} + +ABSL_ATTRIBUTE_WEAK void* operator new[](size_t size, + std::align_val_t alignment, + tcmalloc::hot_cold_t) noexcept(false) { + return ::operator new[](size, alignment); +} + +ABSL_ATTRIBUTE_WEAK void* operator new[](size_t size, + std::align_val_t alignment, + const std::nothrow_t&, + tcmalloc::hot_cold_t) noexcept { + return ::operator new[](size, alignment, std::nothrow); +} +#endif // __cpp_aligned_new diff --git a/contrib/libs/tcmalloc/tcmalloc/malloc_extension.h b/contrib/libs/tcmalloc/tcmalloc/malloc_extension.h index 19b68ba8acf2..ea57e3b0460d 100644 --- a/contrib/libs/tcmalloc/tcmalloc/malloc_extension.h +++ b/contrib/libs/tcmalloc/tcmalloc/malloc_extension.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2019 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,32 +18,76 @@ // tuning the internal implementation of TCMalloc. The internal implementation // functions use weak linkage, allowing an application to link against the // extensions without always linking against TCMalloc. +// +// Many of these APIs are also supported when built with sanitizers. #ifndef TCMALLOC_MALLOC_EXTENSION_H_ #define TCMALLOC_MALLOC_EXTENSION_H_ -#include #include #include -#include #include #include #include #include +#include #include #include -#include #include "absl/base/attributes.h" #include "absl/base/macros.h" -#include "absl/base/policy_checks.h" -#include "absl/base/port.h" #include "absl/functional/function_ref.h" +#include "absl/strings/numbers.h" +#include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" #include "absl/types/optional.h" #include "absl/types/span.h" +// Not all versions of Abseil provide this macro. +// TODO(b/323943471): Remove on upgrading to version that provides the macro. +#ifndef ABSL_DEPRECATE_AND_INLINE +#define ABSL_DEPRECATE_AND_INLINE() +#endif + +// Indicates how frequently accessed the allocation is expected to be. +// 0 - The allocation is rarely accessed. +// ... +// 255 - The allocation is accessed very frequently. +enum class __hot_cold_t : uint8_t; + +// TODO(ckennelly): Lifetimes + +namespace tcmalloc { + +// Alias to the newer type in the global namespace, so that existing code works +// as is. +using hot_cold_t = __hot_cold_t; + +constexpr hot_cold_t kDefaultMinHotAccessHint = + static_cast(2); + +} // namespace tcmalloc + +inline bool AbslParseFlag(absl::string_view text, tcmalloc::hot_cold_t* hotness, + std::string* /* error */) { + uint32_t value; + if (!absl::SimpleAtoi(text, &value)) { + return false; + } + // hot_cold_t is a uint8_t, so make sure the flag is within the allowable + // range before casting. + if (value > std::numeric_limits::max()) { + return false; + } + *hotness = static_cast(value); + return true; +} + +inline std::string AbslUnparseFlag(tcmalloc::hot_cold_t hotness) { + return absl::StrCat(hotness); +} + namespace tcmalloc { namespace tcmalloc_internal { class AllocationProfilingTokenAccessor; @@ -66,6 +111,9 @@ enum class ProfileType { // the profile was terminated with Stop(). kAllocations, + // Lifetimes of sampled objects that are live during the profiling session. + kLifetimes, + // Only present to prevent switch statements without a default clause so that // we can extend this enumeration without breaking code. kDoNotUse, @@ -86,23 +134,127 @@ class Profile final { static constexpr int kMaxStackDepth = 64; int64_t sum; - int64_t count; // Total added with this + // The reported count of samples, with possible rounding up for unsample. + // A given sample typically corresponds to some allocated objects, and the + // number of objects is the quotient of weight (number of bytes requested + // between previous and current samples) divided by the requested size. + int64_t count; size_t requested_size; size_t requested_alignment; size_t allocated_size; + // Return whether the allocation was returned with + // tcmalloc_size_returning_operator_new or its variants. + bool requested_size_returning; + + enum class Access : uint8_t { + Hot, + Cold, + + // Only present to prevent switch statements without a default clause so + // that we can extend this enumeration without breaking code. + kDoNotUse, + }; + hot_cold_t access_hint; + Access access_allocated; + + // Whether this sample captures allocations where the deallocation event + // was not observed. Thus the measurements are censored in the statistical + // sense, see https://en.wikipedia.org/wiki/Censoring_(statistics)#Types. + bool is_censored = false; + + // Provide the status of GWP-ASAN guarding for a given sample. + enum class GuardedStatus : int8_t { + // Conditions which represent why a sample was not guarded: + // + // The requested_size of the allocation sample is larger than the + // available pages which are guardable. + LargerThanOnePage = -1, + // By flag, the guarding of samples has been disabled. + Disabled = -2, + // Too many guards have been placed, any further guards will cause + // unexpected load on binary. + RateLimited = -3, + // The requested_size of the allocation sample is too small (= 0) to be + // guarded. + TooSmall = -4, + // Too many samples are already guarded. + NoAvailableSlots = -5, + // Perhaps the only true error, when the mprotect call fails. + MProtectFailed = -6, + // Used in an improved guarding selection algorithm. + Filtered = -7, + // An unexpected state, which represents that branch for selection was + // missed. + Unknown = -100, + // When guarding is not even considered on a sample. + NotAttempted = 0, + // The following values do not represent final states, but rather intent + // based on the applied algorithm for selecting guarded samples: + // + // Request guard: may still not be guarded for other reasons (see + // above) + Requested = 1, + // Unused. + Required = 2, + // The result when a sample is actually guarded by GWP-ASAN. + Guarded = 10, + }; + GuardedStatus guarded_status = GuardedStatus::Unknown; + + // How the memory was allocated (new/malloc/etc.). + enum class AllocationType : uint8_t { + New, + Malloc, + AlignedMalloc, + }; + + AllocationType type; + int depth; void* stack[kMaxStackDepth]; void* user_data; + + // The following vars are used by the lifetime (deallocation) profiler. + uint64_t profile_id; + + // Timestamp of allocation. + absl::Time allocation_time; + + // Aggregated lifetime statistics per callstack. + absl::Duration avg_lifetime; + absl::Duration stddev_lifetime; + absl::Duration min_lifetime; + absl::Duration max_lifetime; + + // For the *_matched vars below we use true = "same", false = "different". + // When the value is unavailable the profile contains "none". For + // right-censored observations, CPU and thread matched values are "none". + std::optional allocator_deallocator_physical_cpu_matched; + std::optional allocator_deallocator_virtual_cpu_matched; + std::optional allocator_deallocator_l3_matched; + std::optional allocator_deallocator_numa_matched; + std::optional allocator_deallocator_thread_matched; + + // The start address of the sampled allocation, used to calculate the + // residency info for the objects represented by this sampled allocation. + void* span_start_address; }; void Iterate(absl::FunctionRef f) const; - int64_t Period() const; ProfileType Type() const; + // Time stamp when the profile collection started. Returns std::nullopt if + // this is not available. + std::optional StartTime() const; + + // The duration the profile was collected for. For instantaneous profiles + // (heap, peakheap, etc.), this returns absl::ZeroDuration(). + absl::Duration Duration() const; + private: explicit Profile(std::unique_ptr); @@ -133,10 +285,17 @@ class AddressRegionFactory { // frequently than normal regions. kInfrequent ABSL_DEPRECATED("Use kInfrequentAllocation") = kInfrequentAllocation, + kMetadata, // Metadata for TCMalloc not returned via new/malloc. + kInfrequentAccess, // TCMalloc places cold allocations in these regions. + // Usage of the below implies numa_aware is enabled. tcmalloc will mbind the + // address region to the hinted socket, but also passes the hint in case + // mbind is not sufficient (e.g. when dealing with pre-faulted memory). + kNormalNumaAwareS0, // Normal usage intended for NUMA S0 under numa_aware. + kNormalNumaAwareS1, // Normal usage intended for NUMA S1 under numa_aware. }; - AddressRegionFactory() {} - virtual ~AddressRegionFactory(); + constexpr AddressRegionFactory() = default; + virtual ~AddressRegionFactory() = default; // Returns an AddressRegion with the specified start address and size. hint // indicates how the caller intends to use the returned region (helpful for @@ -229,7 +388,7 @@ class MallocExtension final { // ------------------------------------------------------------------- // Gets the named property's value or a nullopt if the property is not valid. - static absl::optional GetNumericProperty(absl::string_view property); + static std::optional GetNumericProperty(absl::string_view property); // Marks the current thread as "idle". This function may optionally be called // by threads as a hint to the malloc implementation that any thread-specific @@ -287,42 +446,50 @@ class MallocExtension final { // back in. static void ReleaseMemoryToSystem(size_t num_bytes); - struct MemoryLimit { - // Make a best effort attempt to prevent more than limit bytes of memory - // from being allocated by the system. In particular, if satisfying a given - // malloc call would require passing this limit, release as much memory to - // the OS as needed to stay under it if possible. - // - // If hard is set, crash if returning memory is unable to get below the - // limit. - // - // Note: limit=SIZE_T_MAX implies no limit. - size_t limit = std::numeric_limits::max(); - bool hard = false; - - // Explicitly declare the ctor to put it in the google_malloc section. - MemoryLimit() = default; - }; + enum class LimitKind { kSoft, kHard }; - static MemoryLimit GetMemoryLimit(); - static void SetMemoryLimit(const MemoryLimit& limit); + // Make a best effort attempt to prevent more than limit bytes of memory + // from being allocated by the system. In particular, if satisfying a given + // malloc call would require passing this limit, release as much memory to + // the OS as needed to stay under it if possible. + // + // If limit_kind == kHard, crash if returning memory is unable to get below + // the limit. + static size_t GetMemoryLimit(LimitKind limit_kind); + static void SetMemoryLimit(size_t limit, LimitKind limit_kind); - // Gets the sampling rate. Returns a value < 0 if unknown. - static int64_t GetProfileSamplingRate(); - // Sets the sampling rate for heap profiles. TCMalloc samples approximately - // every rate bytes allocated. - static void SetProfileSamplingRate(int64_t rate); + // Gets the sampling interval. Returns a value < 0 if unknown. + static int64_t GetProfileSamplingInterval(); + // Sets the sampling interval for heap profiles. TCMalloc samples + // approximately every interval bytes allocated. + static void SetProfileSamplingInterval(int64_t interval); // Gets the guarded sampling rate. Returns a value < 0 if unknown. - static int64_t GetGuardedSamplingRate(); - // Sets the guarded sampling rate for sampled allocations. TCMalloc samples - // approximately every rate bytes allocated, subject to implementation - // limitations in GWP-ASan. + static int64_t GetGuardedSamplingInterval(); + // Sets the guarded sampling interval for sampled allocations. TCMalloc + // samples approximately every interval bytes allocated, subject to + // implementation limitations in GWP-ASan. // - // Guarded samples provide probablistic protections against buffer underflow, + // Guarded samples provide probabilistic protections against buffer underflow, // overflow, and use-after-free when GWP-ASan is active (via calling // ActivateGuardedSampling). - static void SetGuardedSamplingRate(int64_t rate); + static void SetGuardedSamplingInterval(int64_t interval); + + // The old names to get and set profile sampling intervals used "rate" to + // refer to intervals. Use of the below is deprecated to avoid confusion. + static int64_t GetProfileSamplingRate() { + return GetProfileSamplingInterval(); + } + static void SetProfileSamplingRate(int64_t rate) { + SetProfileSamplingInterval(rate); + } + ABSL_DEPRECATE_AND_INLINE() + static int64_t GetGuardedSamplingRate() { + return GetGuardedSamplingInterval(); + } + static void SetGuardedSamplingRate(int64_t rate) { + SetGuardedSamplingInterval(rate); + } // Switches TCMalloc to guard sampled allocations for underflow, overflow, and // use-after-free according to the guarded sample parameter value. @@ -331,11 +498,6 @@ class MallocExtension final { // Gets whether TCMalloc is using per-CPU caches. static bool PerCpuCachesActive(); - // Extension for unified agent. - // - // Should be removed in the future https://st.yandex-team.ru/UNIFIEDAGENT-321 - static void DeactivatePerCpuCaches(); - // Gets the current maximum cache size per CPU cache. static int32_t GetMaxPerCpuCacheSize(); // Sets the maximum cache size per CPU cache. This is a per-core limit. @@ -346,10 +508,34 @@ class MallocExtension final { // Sets the maximum thread cache size. This is a whole-process limit. static void SetMaxTotalThreadCacheBytes(int64_t value); - // Gets the delayed subrelease interval (0 if delayed subrelease is disabled) + // Enables or disables background processes. + static bool GetBackgroundProcessActionsEnabled(); + static void SetBackgroundProcessActionsEnabled(bool value); + + // Gets and sets background process sleep time. This controls the interval + // granularity at which the actions are invoked. + static absl::Duration GetBackgroundProcessSleepInterval(); + static void SetBackgroundProcessSleepInterval(absl::Duration value); + + // Gets and sets intervals used for finding recent demand peak, short-term + // demand fluctuation, and long-term demand trend. Zero duration means not + // considering corresponding demand history for delayed subrelease. Delayed + // subrelease is disabled if all intervals are zero. static absl::Duration GetSkipSubreleaseInterval(); - // Sets the delayed subrelease interval (0 to disable delayed subrelease) static void SetSkipSubreleaseInterval(absl::Duration value); + static absl::Duration GetSkipSubreleaseShortInterval(); + static void SetSkipSubreleaseShortInterval(absl::Duration value); + static absl::Duration GetSkipSubreleaseLongInterval(); + static void SetSkipSubreleaseLongInterval(absl::Duration value); + + // Gets and sets intervals used for finding the recent short-term demand + // fluctuation and long-term demand trend in HugeCache. Zero duration means + // not considering corresponding demand history for delayed (demand-based) + // hugepage release. The feature is disabled if both intervals are zero. + static absl::Duration GetCacheDemandReleaseShortInterval(); + static void SetCacheDemandReleaseShortInterval(absl::Duration value); + static absl::Duration GetCacheDemandReleaseLongInterval(); + static void SetCacheDemandReleaseLongInterval(absl::Duration value); // Returns the estimated number of bytes that will be allocated for a request // of "size" bytes. This is an estimate: an allocation of "size" bytes may @@ -372,7 +558,7 @@ class MallocExtension final { // -- that is, must be exactly the pointer returned to by malloc() et al., not // some offset from that -- and should not have been freed yet. p may be // null. - static absl::optional GetAllocatedSize(const void* p); + static std::optional GetAllocatedSize(const void* p); // Returns // * kOwned if TCMalloc allocated the memory pointed to by p, or @@ -444,6 +630,10 @@ class MallocExtension final { // null if the implementation does not support profiling. static AllocationProfilingToken StartAllocationProfiling(); + // Start recording lifetimes of objects live during this profiling + // session. Returns null if the implementation does not support profiling. + static AllocationProfilingToken StartLifetimeProfiling(); + // Runs housekeeping actions for the allocator off of the main allocation path // of new/delete. As of 2020, this includes: // * Inspecting the current CPU mask and releasing memory from inaccessible @@ -498,6 +688,9 @@ class MallocExtension final { // Default weak implementation returns size unchanged, but tcmalloc overrides it // and returns rounded up size. See the following link for details: // http://www.unix.com/man-page/freebsd/3/nallocx/ +// NOTE: prefer using tcmalloc_size_returning_operator_new over nallocx. +// tcmalloc_size_returning_operator_new is more efficienct and provides tcmalloc +// with better telemetry. extern "C" size_t nallocx(size_t size, int flags) noexcept; // The sdallocx function deallocates memory allocated by malloc or memalign. It @@ -507,16 +700,27 @@ extern "C" size_t nallocx(size_t size, int flags) noexcept; // uses the size to improve deallocation performance. extern "C" void sdallocx(void* ptr, size_t size, int flags) noexcept; -namespace tcmalloc { +#if !defined(__STDC_VERSION_STDLIB_H__) || __STDC_VERSION_STDLIB_H__ < 202311L +// Frees ptr allocated with malloc(size) introduced in C23. +extern "C" void free_sized(void* ptr, size_t size); + +// Frees ptr allocated with aligned_alloc/posix_memalign with the specified size +// and alignment introduced in C23. +extern "C" void free_aligned_sized(void* ptr, size_t alignment, size_t size); +#endif -// Pointer / capacity information as returned by -// tcmalloc_size_returning_operator_new(). See -// tcmalloc_size_returning_operator_new() for more information. -struct sized_ptr_t { +// Define __sized_ptr_t in the global namespace so that it can be named by the +// __size_returning_new implementations defined in tcmalloc.cc. +struct __sized_ptr_t { void* p; size_t n; }; +namespace tcmalloc { +// sized_ptr_t constains pointer / capacity information as returned +// by `tcmalloc_size_returning_operator_new()`. +// See `tcmalloc_size_returning_operator_new()` for more information. +using sized_ptr_t = __sized_ptr_t; } // namespace tcmalloc // Allocates memory of at least the requested size. @@ -548,25 +752,73 @@ struct sized_ptr_t { // new" proposal: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0901r5.html extern "C" { -tcmalloc::sized_ptr_t tcmalloc_size_returning_operator_new(size_t size); -tcmalloc::sized_ptr_t tcmalloc_size_returning_operator_new_nothrow( +// The following declarations provide an alternative spelling which should be +// used so that the compiler can identify these as allocator functions. +__sized_ptr_t __size_returning_new(size_t size); +__sized_ptr_t __size_returning_new_hot_cold(size_t, __hot_cold_t); +__sized_ptr_t __size_returning_new_aligned(size_t, std::align_val_t); +__sized_ptr_t __size_returning_new_aligned_hot_cold(size_t, std::align_val_t, + __hot_cold_t); + +ABSL_DEPRECATE_AND_INLINE() +inline __sized_ptr_t tcmalloc_size_returning_operator_new(size_t size) { + return __size_returning_new(size); +} +__sized_ptr_t tcmalloc_size_returning_operator_new_nothrow( size_t size) noexcept; +ABSL_DEPRECATE_AND_INLINE() +inline __sized_ptr_t tcmalloc_size_returning_operator_new_hot_cold( + size_t size, tcmalloc::hot_cold_t hot_cold) { + return __size_returning_new_hot_cold(size, hot_cold); +} +__sized_ptr_t tcmalloc_size_returning_operator_new_hot_cold_nothrow( + size_t size, tcmalloc::hot_cold_t hot_cold) noexcept; -// Aligned size returning new is only supported for libc++ because of issues -// with libstdcxx.so linkage. See http://b/110969867 for background. #if defined(__cpp_aligned_new) // Identical to `tcmalloc_size_returning_operator_new` except that the returned // memory is aligned according to the `alignment` argument. -tcmalloc::sized_ptr_t tcmalloc_size_returning_operator_new_aligned( - size_t size, std::align_val_t alignment); -tcmalloc::sized_ptr_t tcmalloc_size_returning_operator_new_aligned_nothrow( +ABSL_DEPRECATE_AND_INLINE() +inline __sized_ptr_t tcmalloc_size_returning_operator_new_aligned( + size_t size, std::align_val_t alignment) { + return __size_returning_new_aligned(size, alignment); +} +__sized_ptr_t tcmalloc_size_returning_operator_new_aligned_nothrow( size_t size, std::align_val_t alignment) noexcept; +ABSL_DEPRECATE_AND_INLINE() +inline __sized_ptr_t tcmalloc_size_returning_operator_new_aligned_hot_cold( + size_t size, std::align_val_t alignment, tcmalloc::hot_cold_t hot_cold) { + return __size_returning_new_aligned_hot_cold(size, alignment, hot_cold); +} +__sized_ptr_t tcmalloc_size_returning_operator_new_aligned_hot_cold_nothrow( + size_t size, std::align_val_t alignment, + tcmalloc::hot_cold_t hot_cold) noexcept; #endif // __cpp_aligned_new } // extern "C" +void* operator new(size_t size, tcmalloc::hot_cold_t hot_cold) noexcept(false); +void* operator new(size_t size, const std::nothrow_t&, + tcmalloc::hot_cold_t hot_cold) noexcept; +void* operator new[](size_t size, + tcmalloc::hot_cold_t hot_cold) noexcept(false); +void* operator new[](size_t size, const std::nothrow_t&, + tcmalloc::hot_cold_t hot_cold) noexcept; + +#ifdef __cpp_aligned_new +void* operator new(size_t size, std::align_val_t alignment, + tcmalloc::hot_cold_t hot_cold) noexcept(false); +void* operator new(size_t size, std::align_val_t alignment, + const std::nothrow_t&, + tcmalloc::hot_cold_t hot_cold) noexcept; +void* operator new[](size_t size, std::align_val_t alignment, + tcmalloc::hot_cold_t hot_cold) noexcept(false); +void* operator new[](size_t size, std::align_val_t alignment, + const std::nothrow_t&, + tcmalloc::hot_cold_t hot_cold) noexcept; +#endif // __cpp_aligned_new + #ifndef MALLOCX_LG_ALIGN #define MALLOCX_LG_ALIGN(la) (la) #endif @@ -607,14 +859,58 @@ class ProfileBase { virtual void Iterate( absl::FunctionRef f) const = 0; - // The approximate interval between recorded samples of the event of interest. - // A period of 1 means every sample was recorded. - virtual int64_t Period() const = 0; - // The type of profile (live objects, allocated, etc.). virtual ProfileType Type() const = 0; + + virtual std::optional StartTime() const = 0; + + // The duration the profile was collected for. For instantaneous profiles + // (heap, peakheap, etc.), this returns absl::ZeroDuration(). + virtual absl::Duration Duration() const = 0; +}; + +enum class MadvisePreference { + kNever = 0x0, + kDontNeed = 0x1, + kFreeAndDontNeed = 0x3, + kFreeOnly = 0x2, }; +inline bool AbslParseFlag(absl::string_view text, MadvisePreference* preference, + std::string* /* error */) { + if (text == "NEVER") { + *preference = MadvisePreference::kNever; + return true; + } else if (text == "DONTNEED") { + *preference = MadvisePreference::kDontNeed; + return true; + } else if (text == "FREE_AND_DONTNEED") { + *preference = MadvisePreference::kFreeAndDontNeed; + return true; + } else if (text == "FREE_ONLY") { + *preference = MadvisePreference::kFreeOnly; + return true; + } else { + return false; + } +} + +inline std::string AbslUnparseFlag(MadvisePreference preference) { + switch (preference) { + case MadvisePreference::kNever: + return "NEVER"; + case MadvisePreference::kDontNeed: + return "DONTNEED"; + case MadvisePreference::kFreeAndDontNeed: + return "FREE_AND_DONTNEED"; + case MadvisePreference::kFreeOnly: + return "FREE_ONLY"; + } + + ABSL_UNREACHABLE(); + return ""; +} + } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/malloc_extension_fuzz.cc b/contrib/libs/tcmalloc/tcmalloc/malloc_extension_fuzz.cc index 26335bdef825..2a7d268cc852 100644 --- a/contrib/libs/tcmalloc/tcmalloc/malloc_extension_fuzz.cc +++ b/contrib/libs/tcmalloc/tcmalloc/malloc_extension_fuzz.cc @@ -14,23 +14,26 @@ #include +#include #include +#include #include +#include "fuzztest/fuzztest.h" #include "absl/types/optional.h" #include "tcmalloc/malloc_extension.h" -extern "C" int LLVMFuzzerTestOneInput(const uint8_t* d, size_t size) { - using tcmalloc::MallocExtension; +namespace tcmalloc { +namespace { - const std::string property(reinterpret_cast(d), size); - absl::optional val = MallocExtension::GetNumericProperty(property); +void FuzzGetProperty(const std::string& property) { + std::optional val = MallocExtension::GetNumericProperty(property); if (!val.has_value()) { // Rather than inspect the result of MallocExtension::GetProperties, we - // defer to the test in //tcmalloc/malloc_extension_test.cc to - // ensure that every key in GetProperties has a value returned by - // GetNumericProperty. - return 0; + // defer to the test in + // //tcmalloc/testing/malloc_extension_test.cc to ensure that + // every key in GetProperties has a value returned by GetNumericProperty. + return; } std::map properties = @@ -38,5 +41,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* d, size_t size) { if (properties.find(property) == properties.end()) { __builtin_trap(); } - return 0; } + +FUZZ_TEST(MallocExtensionTest, FuzzGetProperty) + ; + +} // namespace +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/malloc_extension_test.cc b/contrib/libs/tcmalloc/tcmalloc/malloc_extension_test.cc deleted file mode 100644 index 5088806ff8fe..000000000000 --- a/contrib/libs/tcmalloc/tcmalloc/malloc_extension_test.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2019 The TCMalloc Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// Test for TCMalloc implementation of MallocExtension - -#include "tcmalloc/malloc_extension.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "absl/time/time.h" - -namespace tcmalloc { -namespace { - -TEST(MallocExtension, BackgroundReleaseRate) { - - // Mutate via MallocExtension. - MallocExtension::SetBackgroundReleaseRate( - MallocExtension::BytesPerSecond{100 << 20}); - - EXPECT_EQ(static_cast(MallocExtension::GetBackgroundReleaseRate()), - 100 << 20); - - // Disable release - MallocExtension::SetBackgroundReleaseRate(MallocExtension::BytesPerSecond{0}); - - EXPECT_EQ(static_cast(MallocExtension::GetBackgroundReleaseRate()), - 0); -} - -TEST(MallocExtension, SkipSubreleaseInterval) { - - // Mutate via MallocExtension. - MallocExtension::SetSkipSubreleaseInterval(absl::Seconds(10)); - EXPECT_EQ(MallocExtension::GetSkipSubreleaseInterval(), absl::Seconds(10)); - - // Disable skip subrelease - MallocExtension::SetSkipSubreleaseInterval(absl::ZeroDuration()); - EXPECT_EQ(MallocExtension::GetSkipSubreleaseInterval(), absl::ZeroDuration()); -} - -TEST(MallocExtension, Properties) { - // Verify that every property under GetProperties also works with - // GetNumericProperty. - const auto properties = MallocExtension::GetProperties(); - for (const auto& property : properties) { - absl::optional scalar = - MallocExtension::GetNumericProperty(property.first); - // The value of the property itself may have changed, so just check that it - // is present. - EXPECT_THAT(scalar, testing::Ne(absl::nullopt)) << property.first; - } -} - -} // namespace -} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/malloc_tracing_extension.cc b/contrib/libs/tcmalloc/tcmalloc/malloc_tracing_extension.cc new file mode 100644 index 000000000000..a0756f5963e1 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/malloc_tracing_extension.cc @@ -0,0 +1,41 @@ +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Extra extensions exported by some malloc implementations. These +// extensions are accessed through a virtual base class so an +// application can link against a malloc that does not implement these +// extensions, and it will get default versions that do nothing. + +#include "tcmalloc/malloc_tracing_extension.h" + +#include "absl/base/attributes.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "tcmalloc/internal_malloc_tracing_extension.h" + +namespace tcmalloc { +namespace malloc_tracing_extension { + +absl::StatusOr GetAllocatedAddressRanges() { +#if ABSL_HAVE_ATTRIBUTE_WEAK && !defined(__APPLE__) && !defined(__EMSCRIPTEN__) + if (&MallocTracingExtension_Internal_GetAllocatedAddressRanges != nullptr) { + return MallocTracingExtension_Internal_GetAllocatedAddressRanges(); + } +#endif + return absl::UnimplementedError( + "malloc_tracing_extension routines not exported by the current malloc."); +} + +} // namespace malloc_tracing_extension +} // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/malloc_tracing_extension.h b/contrib/libs/tcmalloc/tcmalloc/malloc_tracing_extension.h new file mode 100644 index 000000000000..ed020512fd14 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/malloc_tracing_extension.h @@ -0,0 +1,55 @@ +#pragma clang system_header +// Copyright 2022 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Extra extensions exported by some malloc implementations. These +// extensions are accessed through a virtual base class so an +// application can link against a malloc that does not implement these +// extensions, and it will get default versions that do nothing. + +#ifndef TCMALLOC_MALLOC_TRACING_EXTENSION_H_ +#define TCMALLOC_MALLOC_TRACING_EXTENSION_H_ + +#include +#include +#include + +#include "absl/status/statusor.h" + +namespace tcmalloc { +namespace malloc_tracing_extension { + +// Type used by GetAllocatedAddressRanges. Contains details of address ranges +// that have a corresponding Span in TCMalloc. +struct AllocatedAddressRanges { + struct SpanDetails { + uintptr_t start_addr; + size_t size; + // For Spans with objects that fit into some size-class, object_size is + // actually the size-class bytes, not the exact object size bytes. + // This is zero for non-size-class objects that are objects larger than + // kMaxSize. + size_t object_size; + }; + // Note that any subset of size-class-sized objects may be currently + // allocated from each Span. + std::vector spans; +}; +// Returns the address ranges currently allocated by TCMalloc. +absl::StatusOr GetAllocatedAddressRanges(); + +} // namespace malloc_tracing_extension +} // namespace tcmalloc + +#endif // TCMALLOC_MALLOC_TRACING_EXTENSION_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/metadata_allocator.h b/contrib/libs/tcmalloc/tcmalloc/metadata_allocator.h new file mode 100644 index 000000000000..e0cbaa78711b --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/metadata_allocator.h @@ -0,0 +1,41 @@ +#pragma clang system_header +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_METADATA_ALLOCATOR_H_ +#define TCMALLOC_METADATA_ALLOCATOR_H_ + +#include + +#include "absl/base/attributes.h" + +namespace tcmalloc::tcmalloc_internal { + +class MetadataAllocator { + public: + MetadataAllocator() = default; + virtual ~MetadataAllocator() = default; + + MetadataAllocator(const MetadataAllocator&) = delete; + MetadataAllocator(MetadataAllocator&&) = delete; + MetadataAllocator& operator=(const MetadataAllocator&) = delete; + MetadataAllocator& operator=(MetadataAllocator&&) = delete; + + // Allocates bytes suitable for metadata. + [[nodiscard]] virtual void* operator()(size_t bytes) = 0; +}; + +} // namespace tcmalloc::tcmalloc_internal + +#endif // TCMALLOC_METADATA_ALLOCATOR_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/metadata_object_allocator.h b/contrib/libs/tcmalloc/tcmalloc/metadata_object_allocator.h new file mode 100644 index 000000000000..b6d34650f59b --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/metadata_object_allocator.h @@ -0,0 +1,142 @@ +#pragma clang system_header +// Copyright 2019 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_METADATA_OBJECT_ALLOCATOR_H_ +#define TCMALLOC_METADATA_OBJECT_ALLOCATOR_H_ + +#include + +#include + +#include "absl/base/attributes.h" +#include "absl/base/const_init.h" +#include "absl/base/dynamic_annotations.h" +#include "absl/base/internal/spinlock.h" +#include "absl/base/optimization.h" +#include "absl/base/thread_annotations.h" +#include "tcmalloc/arena.h" +#include "tcmalloc/common.h" +#include "tcmalloc/internal/allocation_guard.h" +#include "tcmalloc/internal/config.h" + +#ifdef ABSL_HAVE_ADDRESS_SANITIZER +#include +#endif + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { + +struct AllocatorStats { + // Number of allocated but unfreed objects + size_t in_use; + // Number of objects created (both free and allocated) + size_t total; +}; + +// Simple allocator for objects of a specified type. External locking +// is required before accessing one of these objects. +template +class MetadataObjectAllocator { + public: + constexpr explicit MetadataObjectAllocator( + Arena& arena ABSL_ATTRIBUTE_LIFETIME_BOUND) + : arena_(&arena), free_list_(nullptr), stats_{0, 0} {} + + // Allocates storage for a T. + // + // Once New() has been invoked to allocate storage, it is no longer safe to + // request an overaligned instance via NewWithSize as the underaligned result + // may be freelisted. + template + [[nodiscard]] ABSL_ATTRIBUTE_RETURNS_NONNULL T* New(Args&&... args) { + return NewWithSize(sizeof(T), static_cast(alignof(T)), + std::forward(args)...); + } + + template + [[nodiscard]] ABSL_ATTRIBUTE_RETURNS_NONNULL T* NewWithSize( + size_t size, std::align_val_t align, Args&&... args) { + T* ret = LockAndAllocMemory(size, align); + return new (ret) T(std::forward(args)...); + } + + void Delete(T* p) ABSL_ATTRIBUTE_NONNULL() { + p->~T(); + LockAndDeleteMemory(p); + } + + AllocatorStats stats() const { + AllocationGuardSpinLockHolder l(&metadata_lock_); + + return stats_; + } + + private: + ABSL_ATTRIBUTE_RETURNS_NONNULL T* LockAndAllocMemory(size_t size, + std::align_val_t align) { + TC_ASSERT_GE(static_cast(align), alignof(T)); + + AllocationGuardSpinLockHolder l(&metadata_lock_); + + // Consult free list + T* result = free_list_; + stats_.in_use++; + if (ABSL_PREDICT_FALSE(result == nullptr)) { + stats_.total++; + result = reinterpret_cast(arena_->Alloc(size, align)); + ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(result, size); + return result; + } else { +#ifdef ABSL_HAVE_ADDRESS_SANITIZER + // Unpoison the object on the freelist. + ASAN_UNPOISON_MEMORY_REGION(result, size); +#endif + } + free_list_ = *(reinterpret_cast(free_list_)); + ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(result, size); + return result; + } + + void LockAndDeleteMemory(T* p) ABSL_ATTRIBUTE_NONNULL() { + AllocationGuardSpinLockHolder l(&metadata_lock_); + + *(reinterpret_cast(p)) = free_list_; +#ifdef ABSL_HAVE_ADDRESS_SANITIZER + // Poison the object on the freelist. We do not dereference it after this + // point. + ASAN_POISON_MEMORY_REGION(p, sizeof(*p)); +#endif + free_list_ = p; + stats_.in_use--; + } + + // Arena from which to allocate memory + Arena* arena_; + + mutable absl::base_internal::SpinLock metadata_lock_{ + absl::kConstInit, absl::base_internal::SCHEDULE_KERNEL_ONLY}; + + // Free list of already carved objects + T* free_list_ ABSL_GUARDED_BY(metadata_lock_); + + AllocatorStats stats_ ABSL_GUARDED_BY(metadata_lock_); +}; + +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_METADATA_OBJECT_ALLOCATOR_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/mock_central_freelist.cc b/contrib/libs/tcmalloc/tcmalloc/mock_central_freelist.cc index 13308b947a9c..9fd3d91fb4fe 100644 --- a/contrib/libs/tcmalloc/tcmalloc/mock_central_freelist.cc +++ b/contrib/libs/tcmalloc/tcmalloc/mock_central_freelist.cc @@ -15,17 +15,34 @@ #include "tcmalloc/mock_central_freelist.h" #include "absl/base/internal/spinlock.h" +#include "absl/types/span.h" #include "tcmalloc/internal/logging.h" namespace tcmalloc { namespace tcmalloc_internal { -void MinimalFakeCentralFreeList::AllocateBatch(void** batch, int n) { - for (int i = 0; i < n; ++i) batch[i] = &batch[i]; +void RealCentralFreeListForTesting::AllocateBatch(absl::Span batch) { + int total = 0; + + while (total < batch.size()) { + const int to_remove = batch.size() - total; + const int removed = RemoveRange(batch.subspan(total)); + ASSERT_GT(removed, 0); + ASSERT_LE(removed, to_remove); + total += removed; + } +} + +void RealCentralFreeListForTesting::FreeBatch(absl::Span batch) { + InsertRange(batch); +} + +void MinimalFakeCentralFreeList::AllocateBatch(absl::Span batch) { + for (void*& v : batch) v = &v; } void MinimalFakeCentralFreeList::FreeBatch(absl::Span batch) { - for (void* x : batch) CHECK_CONDITION(x != nullptr); + for (void* x : batch) TC_CHECK_NE(x, nullptr); } void MinimalFakeCentralFreeList::InsertRange(absl::Span batch) { @@ -33,14 +50,14 @@ void MinimalFakeCentralFreeList::InsertRange(absl::Span batch) { FreeBatch(batch); } -int MinimalFakeCentralFreeList::RemoveRange(void** batch, int n) { +int MinimalFakeCentralFreeList::RemoveRange(absl::Span batch) { absl::base_internal::SpinLockHolder h(&lock_); - AllocateBatch(batch, n); - return n; + AllocateBatch(batch); + return batch.size(); } -void FakeCentralFreeList::AllocateBatch(void** batch, int n) { - for (int i = 0; i < n; ++i) { +void FakeCentralFreeList::AllocateBatch(absl::Span batch) { + for (int i = 0; i < batch.size(); ++i) { batch[i] = ::operator new(4); } } @@ -55,9 +72,9 @@ void FakeCentralFreeList::InsertRange(absl::Span batch) { FreeBatch(batch); } -int FakeCentralFreeList::RemoveRange(void** batch, int n) { - AllocateBatch(batch, n); - return n; +int FakeCentralFreeList::RemoveRange(absl::Span batch) { + AllocateBatch(batch); + return batch.size(); } } // namespace tcmalloc_internal diff --git a/contrib/libs/tcmalloc/tcmalloc/mock_central_freelist.h b/contrib/libs/tcmalloc/tcmalloc/mock_central_freelist.h index c2a56c0c6088..f70690727e9b 100644 --- a/contrib/libs/tcmalloc/tcmalloc/mock_central_freelist.h +++ b/contrib/libs/tcmalloc/tcmalloc/mock_central_freelist.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2020 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,10 +21,23 @@ #include "gmock/gmock.h" #include "absl/base/internal/spinlock.h" #include "absl/types/span.h" +#include "tcmalloc/central_freelist.h" namespace tcmalloc { namespace tcmalloc_internal { +// CentralFreeList implementation that uses a real central freelist to allocate +// objects. It implements additional methods used by benchmarks and tests. +// +// This is useful for benchmarking in cases where, for instance, we can test the +// efficiency of TCMalloc's frontend as it has to access real central freelist +// upon a miss. +class RealCentralFreeListForTesting : public CentralFreeList { + public: + void AllocateBatch(absl::Span batch); + void FreeBatch(absl::Span batch); +}; + class FakeCentralFreeListBase { public: FakeCentralFreeListBase() {} @@ -40,9 +54,9 @@ class FakeCentralFreeListBase { class FakeCentralFreeList : public FakeCentralFreeListBase { public: void InsertRange(absl::Span batch); - int RemoveRange(void** batch, int N); + [[nodiscard]] int RemoveRange(absl::Span batch); - void AllocateBatch(void** batch, int n); + void AllocateBatch(absl::Span batch); void FreeBatch(absl::Span batch); }; @@ -53,9 +67,9 @@ class FakeCentralFreeList : public FakeCentralFreeListBase { class MinimalFakeCentralFreeList : public FakeCentralFreeListBase { public: void InsertRange(absl::Span batch); - int RemoveRange(void** batch, int N); + [[nodiscard]] int RemoveRange(absl::Span batch); - void AllocateBatch(void** batch, int n); + void AllocateBatch(absl::Span batch); void FreeBatch(absl::Span batch); private: @@ -72,13 +86,13 @@ class RawMockCentralFreeList : public FakeCentralFreeList { ON_CALL(*this, InsertRange).WillByDefault([this](absl::Span batch) { return static_cast(this)->InsertRange(batch); }); - ON_CALL(*this, RemoveRange).WillByDefault([this](void** batch, int n) { - return static_cast(this)->RemoveRange(batch, n); + ON_CALL(*this, RemoveRange).WillByDefault([this](absl::Span batch) { + return static_cast(this)->RemoveRange(batch); }); } MOCK_METHOD(void, InsertRange, (absl::Span batch)); - MOCK_METHOD(int, RemoveRange, (void** batch, int N)); + MOCK_METHOD(int, RemoveRange, (absl::Span batch)); }; using MockCentralFreeList = testing::NiceMock; diff --git a/contrib/libs/tcmalloc/tcmalloc/mock_huge_page_static_forwarder.cc b/contrib/libs/tcmalloc/tcmalloc/mock_huge_page_static_forwarder.cc new file mode 100644 index 000000000000..3625d623510d --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/mock_huge_page_static_forwarder.cc @@ -0,0 +1,13 @@ +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. diff --git a/contrib/libs/tcmalloc/tcmalloc/mock_huge_page_static_forwarder.h b/contrib/libs/tcmalloc/tcmalloc/mock_huge_page_static_forwarder.h new file mode 100644 index 000000000000..e1da0f38eca8 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/mock_huge_page_static_forwarder.h @@ -0,0 +1,243 @@ +#pragma clang system_header +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_MOCK_HUGE_PAGE_STATIC_FORWARDER_H_ +#define TCMALLOC_MOCK_HUGE_PAGE_STATIC_FORWARDER_H_ + +#include +#include +#include +#include +#include + +#include "absl/base/attributes.h" +#include "absl/base/call_once.h" +#include "absl/base/internal/low_level_alloc.h" +#include "absl/base/thread_annotations.h" +#include "absl/container/flat_hash_map.h" +#include "absl/hash/hash.h" +#include "absl/numeric/bits.h" +#include "absl/time/time.h" +#include "tcmalloc/arena.h" +#include "tcmalloc/common.h" +#include "tcmalloc/huge_pages.h" +#include "tcmalloc/internal/config.h" +#include "tcmalloc/internal/logging.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/span.h" +#include "tcmalloc/system-alloc.h" + +GOOGLE_MALLOC_SECTION_BEGIN +namespace tcmalloc { +namespace tcmalloc_internal { +namespace huge_page_allocator_internal { + +class FakeStaticForwarder { + public: + // Runtime parameters. This can change between calls. + absl::Duration filler_skip_subrelease_interval() { + return subrelease_interval_; + } + absl::Duration filler_skip_subrelease_short_interval() { + return short_interval_; + } + absl::Duration filler_skip_subrelease_long_interval() { + return long_interval_; + } + absl::Duration cache_demand_release_short_interval() { + return cache_demand_release_short_interval_; + } + absl::Duration cache_demand_release_long_interval() { + return cache_demand_release_long_interval_; + } + bool release_partial_alloc_pages() { return release_partial_alloc_pages_; } + bool hpaa_subrelease() const { return hpaa_subrelease_; } + + void set_filler_skip_subrelease_interval(absl::Duration value) { + subrelease_interval_ = value; + } + void set_filler_skip_subrelease_short_interval(absl::Duration value) { + short_interval_ = value; + } + void set_filler_skip_subrelease_long_interval(absl::Duration value) { + long_interval_ = value; + } + void set_cache_demand_release_short_interval(absl::Duration value) { + cache_demand_release_short_interval_ = value; + } + void set_cache_demand_release_long_interval(absl::Duration value) { + cache_demand_release_long_interval_ = value; + } + void set_release_partial_alloc_pages(bool value) { + release_partial_alloc_pages_ = value; + } + void set_hpaa_subrelease(bool value) { hpaa_subrelease_ = value; } + bool release_succeeds() const { return release_succeeds_; } + void set_release_succeeds(bool value) { release_succeeds_ = value; } + + bool huge_region_demand_based_release() const { + return huge_region_demand_based_release_; + } + void set_huge_region_demand_based_release(bool value) { + huge_region_demand_based_release_ = value; + } + + bool huge_cache_demand_based_release() const { + return huge_cache_demand_based_release_; + } + void set_huge_cache_demand_based_release(bool value) { + huge_cache_demand_based_release_ = value; + } + + // Arena state. + Arena& arena() { return arena_; } + + // PageAllocator state. + + // Check page heap memory limit. `n` indicates the size of the allocation + // currently being made, which will not be included in the sampled memory heap + // for realized fragmentation estimation. + void ShrinkToUsageLimit(Length n) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) {} + + // PageMap state. + [[nodiscard]] void* GetHugepage(HugePage p) { + auto it = trackers_.find(p); + if (it == trackers_.end()) { + return nullptr; + } + return it->second; + } + [[nodiscard]] bool Ensure(Range r) + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) { + return true; + } + void Set(PageId page, Span* span) {} + void SetHugepage(HugePage p, void* pt) { trackers_[p] = pt; } + + // SpanAllocator state. + [[nodiscard]] Span* NewSpan(Range r) +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) +#endif // TCMALLOC_INTERNAL_LEGACY_LOCKING + ABSL_ATTRIBUTE_RETURNS_NONNULL { + Span* span; + void* result = absl::base_internal::LowLevelAlloc::AllocWithArena( + sizeof(*span) + alignof(Span) + sizeof(void*), ll_arena()); + span = new (reinterpret_cast( + (reinterpret_cast(result) + alignof(Span) - 1u) & + ~(alignof(Span) - 1u))) Span(r); + *(reinterpret_cast(span + 1)) = + reinterpret_cast(result); + return span; + } + void DeleteSpan(Span* span) +#ifdef TCMALLOC_INTERNAL_LEGACY_LOCKING + ABSL_EXCLUSIVE_LOCKS_REQUIRED(pageheap_lock) +#endif // TCMALLOC_INTERNAL_LEGACY_LOCKING + ABSL_ATTRIBUTE_NONNULL() { + absl::base_internal::LowLevelAlloc::Free( + reinterpret_cast(*(reinterpret_cast(span + 1)))); + } + + // SystemAlloc state. + [[nodiscard]] AddressRange AllocatePages(size_t bytes, size_t align, + MemoryTag tag) { + TC_CHECK(absl::has_single_bit(align), "align=%v", align); + uintptr_t allocation, aligned_allocation, new_allocation; + do { + allocation = fake_allocation_.load(std::memory_order_relaxed); + aligned_allocation = (allocation + align - 1u) & ~(align - 1u); + new_allocation = aligned_allocation + bytes; + } while (!fake_allocation_.compare_exchange_weak( + allocation, new_allocation, std::memory_order_relaxed)); + + AddressRange ret{ + reinterpret_cast(aligned_allocation | + (static_cast(tag) << kTagShift)), + bytes}; + return ret; + } + void Back(Range r) {} + [[nodiscard]] bool ReleasePages(Range r) { + const uintptr_t start = + reinterpret_cast(r.p.start_addr()) & ~kTagMask; + const uintptr_t end = start + r.n.in_bytes(); + TC_CHECK_LE(end, fake_allocation_); + + return release_succeeds_; + } + + private: + static absl::base_internal::LowLevelAlloc::Arena* ll_arena() { + ABSL_CONST_INIT static absl::base_internal::LowLevelAlloc::Arena* a; + ABSL_CONST_INIT static absl::once_flag flag; + absl::base_internal::LowLevelCallOnce(&flag, [&]() { + a = absl::base_internal::LowLevelAlloc::NewArena( + absl::base_internal::LowLevelAlloc::kAsyncSignalSafe); + }); + return a; + } + absl::Duration subrelease_interval_; + absl::Duration short_interval_ = absl::Seconds(60); + absl::Duration long_interval_ = absl::Seconds(300); + absl::Duration cache_demand_release_short_interval_ = absl::Seconds(10); + absl::Duration cache_demand_release_long_interval_ = absl::Seconds(30); + bool release_partial_alloc_pages_ = false; + bool hpaa_subrelease_ = true; + bool release_succeeds_ = true; + bool huge_region_demand_based_release_ = false; + bool huge_cache_demand_based_release_ = false; + Arena arena_; + + std::atomic fake_allocation_ = 0x1000; + + template + class AllocAdaptor final { + public: + using value_type = T; + + AllocAdaptor() = default; + AllocAdaptor(const AllocAdaptor&) = default; + + template + using rebind = AllocAdaptor; + + template + explicit AllocAdaptor(const AllocAdaptor&) {} + + T* allocate(size_t n) { + // Check if n is too big to allocate. + TC_ASSERT_EQ((n * sizeof(T)) / sizeof(T), n); + return static_cast(absl::base_internal::LowLevelAlloc::AllocWithArena( + n * sizeof(T), ll_arena())); + } + void deallocate(T* p, size_t n) { + absl::base_internal::LowLevelAlloc::Free(p); + } + }; + + absl::flat_hash_map, + std::equal_to, + AllocAdaptor>> + trackers_; +}; + +} // namespace huge_page_allocator_internal +} // namespace tcmalloc_internal +} // namespace tcmalloc +GOOGLE_MALLOC_SECTION_END + +#endif // TCMALLOC_MOCK_HUGE_PAGE_STATIC_FORWARDER_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/mock_metadata_allocator.h b/contrib/libs/tcmalloc/tcmalloc/mock_metadata_allocator.h new file mode 100644 index 000000000000..eee60193bf90 --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/mock_metadata_allocator.h @@ -0,0 +1,47 @@ +#pragma clang system_header +// Copyright 2023 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_MOCK_METADATA_ALLOCATOR_H_ +#define TCMALLOC_MOCK_METADATA_ALLOCATOR_H_ + +#include +#include + +#include "absl/base/attributes.h" +#include "tcmalloc/metadata_allocator.h" + +namespace tcmalloc::tcmalloc_internal { + +class FakeMetadataAllocator final : public MetadataAllocator { + public: + ~FakeMetadataAllocator() override { + for (void* p : metadata_allocs_) { + free(p); + } + } + + [[nodiscard]] void* operator()(size_t size) override { + void* ptr = malloc(size); + metadata_allocs_.push_back(ptr); + return ptr; + } + + private: + std::vector metadata_allocs_; +}; + +} // namespace tcmalloc::tcmalloc_internal + +#endif // TCMALLOC_MOCK_METADATA_ALLOCATOR_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/mock_static_forwarder.h b/contrib/libs/tcmalloc/tcmalloc/mock_static_forwarder.h new file mode 100644 index 000000000000..5854dbcc6fab --- /dev/null +++ b/contrib/libs/tcmalloc/tcmalloc/mock_static_forwarder.h @@ -0,0 +1,242 @@ +#pragma clang system_header +// Copyright 2021 The TCMalloc Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TCMALLOC_MOCK_STATIC_FORWARDER_H_ +#define TCMALLOC_MOCK_STATIC_FORWARDER_H_ + +#include +#include +#include +#include + +#include "gmock/gmock.h" +#include "absl/synchronization/mutex.h" +#include "absl/time/time.h" +#include "absl/types/span.h" +#include "tcmalloc/pages.h" +#include "tcmalloc/span.h" + +namespace tcmalloc { +namespace tcmalloc_internal { + +class FakeStaticForwarder { + public: + FakeStaticForwarder() : class_size_(0), pages_() {} + void Init(size_t class_size, size_t pages, size_t num_objects_to_move, + bool use_large_spans) { + class_size_ = class_size; + pages_ = Length(pages); + num_objects_to_move_ = num_objects_to_move; + use_large_spans_ = use_large_spans; + TC_ASSERT_LE(max_span_cache_size(), max_span_cache_array_size()); + clock_ = 1234; + } + uint64_t clock_now() const { return clock_; } + double clock_frequency() const { + return absl::ToDoubleNanoseconds(absl::Seconds(2)); + } + void AdvanceClock(absl::Duration d) { + clock_ += absl::ToDoubleSeconds(d) * clock_frequency(); + } + + size_t class_to_size(int size_class) const { return class_size_; } + Length class_to_pages(int size_class) const { return pages_; } + size_t num_objects_to_move() const { return num_objects_to_move_; } + uint32_t max_span_cache_size() const { + return use_large_spans_ ? Span::kLargeCacheSize : Span::kCacheSize; + } + uint32_t max_span_cache_array_size() const { + return use_large_spans_ ? Span::kLargeCacheArraySize : Span::kCacheSize; + } + + void MapObjectsToSpans(absl::Span batch, Span** spans, + int expected_size_class) { + for (size_t i = 0; i < batch.size(); ++i) { + spans[i] = MapObjectToSpan(batch[i]); + } + } + + [[nodiscard]] Span* MapObjectToSpan(const void* object) { + const PageId page = PageIdContaining(object); + + absl::MutexLock l(&mu_); + auto it = map_.lower_bound(page); + if (it->first != page && it != map_.begin()) { + --it; + } + + if (it->first <= page && page <= it->second.span->last_page()) { + return it->second.span; + } + + return nullptr; + } + + [[nodiscard]] Span* AllocateSpan(int, size_t objects_per_span, + Length pages_per_span) { + void* backing = + ::operator new(pages_per_span.in_bytes(), std::align_val_t(kPageSize)); + PageId page = PageIdContaining(backing); + + void* span_buf = + ::operator new(Span::CalcSizeOf(max_span_cache_array_size()), + Span::CalcAlignOf(max_span_cache_array_size())); + TC_ASSERT_LE(max_span_cache_size(), max_span_cache_array_size()); + + auto* span = new (span_buf) Span(Range(page, pages_per_span)); + + absl::MutexLock l(&mu_); + SpanInfo info; + info.span = span; + SpanAllocInfo span_alloc_info = { + .objects_per_span = objects_per_span, + .density = AccessDensityPrediction::kSparse}; + info.span_alloc_info = span_alloc_info; + map_.emplace(page, info); + return span; + } + + void DeallocateSpans(size_t, absl::Span free_spans) { + { + absl::MutexLock l(&mu_); + for (Span* span : free_spans) { + auto it = map_.find(span->first_page()); + EXPECT_NE(it, map_.end()); + map_.erase(it); + } + } + + const std::align_val_t span_alignment = + Span::CalcAlignOf(max_span_cache_array_size()); + + for (Span* span : free_spans) { + ::operator delete(span->start_address(), std::align_val_t(kPageSize)); + + span->~Span(); + ::operator delete(span, span_alignment); + } + } + + private: + struct SpanInfo { + Span* span; + SpanAllocInfo span_alloc_info; + }; + + absl::Mutex mu_; + std::map map_ ABSL_GUARDED_BY(mu_); + size_t class_size_; + Length pages_; + size_t num_objects_to_move_; + bool use_large_spans_; + uint64_t clock_; +}; + +class RawMockStaticForwarder : public FakeStaticForwarder { + public: + RawMockStaticForwarder() { + ON_CALL(*this, class_to_size).WillByDefault([this](int size_class) { + return FakeStaticForwarder::class_to_size(size_class); + }); + ON_CALL(*this, class_to_pages).WillByDefault([this](int size_class) { + return FakeStaticForwarder::class_to_pages(size_class); + }); + ON_CALL(*this, num_objects_to_move).WillByDefault([this]() { + return FakeStaticForwarder::num_objects_to_move(); + }); + ON_CALL(*this, Init) + .WillByDefault([this](size_t size_class, size_t pages, + size_t num_objects_to_move, + bool use_large_spans) { + FakeStaticForwarder::Init(size_class, pages, num_objects_to_move, + use_large_spans); + }); + + ON_CALL(*this, MapObjectsToSpans) + .WillByDefault([this](absl::Span batch, Span** spans, + int expected_size_class) { + return FakeStaticForwarder::MapObjectsToSpans(batch, spans, + expected_size_class); + }); + ON_CALL(*this, AllocateSpan) + .WillByDefault([this](int size_class, size_t objects_per_span, + Length pages_per_span) { + return FakeStaticForwarder::AllocateSpan(size_class, objects_per_span, + pages_per_span); + }); + ON_CALL(*this, DeallocateSpans) + .WillByDefault([this](size_t objects_per_span, + absl::Span free_spans) { + FakeStaticForwarder::DeallocateSpans(objects_per_span, free_spans); + }); + } + + MOCK_METHOD(size_t, class_to_size, (int size_class)); + MOCK_METHOD(Length, class_to_pages, (int size_class)); + MOCK_METHOD(size_t, num_objects_to_move, ()); + MOCK_METHOD(void, Init, + (size_t class_size, size_t pages, size_t num_objects_to_move, + bool use_large_spans)); + MOCK_METHOD(void, MapObjectsToSpans, + (absl::Span batch, Span** spans, int expected_size_class)); + MOCK_METHOD(Span*, AllocateSpan, + (int size_class, size_t objects_per_span, Length pages_per_span)); + MOCK_METHOD(void, DeallocateSpans, + (size_t object_per_span, absl::Span free_spans)); +}; + +using MockStaticForwarder = testing::NiceMock; + +// Wires up a largely functional CentralFreeList + MockStaticForwarder. +// +// By default, it fills allocations and responds sensibly. Because it backs +// onto malloc/free, it will detect leaks and memory misuse when run under +// sanitizers. +// +// Exposes the underlying mocks to allow for more whitebox tests. +template +class FakeCentralFreeListEnvironment { + public: + using CentralFreeList = CentralFreeListT; + using Forwarder = typename CentralFreeListT::Forwarder; + + static constexpr int kSizeClass = 1; + size_t objects_per_span() { + return forwarder().class_to_pages(kSizeClass).in_bytes() / + forwarder().class_to_size(kSizeClass); + } + size_t batch_size() { return forwarder().num_objects_to_move(); } + + explicit FakeCentralFreeListEnvironment(size_t class_size, size_t pages, + size_t num_objects_to_move, + bool use_large_spans) { + forwarder().Init(class_size, pages, num_objects_to_move, use_large_spans); + cache_.Init(kSizeClass); + } + + ~FakeCentralFreeListEnvironment() { EXPECT_EQ(cache_.length(), 0); } + + CentralFreeList& central_freelist() { return cache_; } + + Forwarder& forwarder() { return cache_.forwarder(); } + + private: + CentralFreeList cache_; +}; + +} // namespace tcmalloc_internal +} // namespace tcmalloc + +#endif // TCMALLOC_MOCK_STATIC_FORWARDER_H_ diff --git a/contrib/libs/tcmalloc/tcmalloc/mock_transfer_cache.cc b/contrib/libs/tcmalloc/tcmalloc/mock_transfer_cache.cc index b8b2bcf13102..075928919849 100644 --- a/contrib/libs/tcmalloc/tcmalloc/mock_transfer_cache.cc +++ b/contrib/libs/tcmalloc/tcmalloc/mock_transfer_cache.cc @@ -17,8 +17,12 @@ namespace tcmalloc { namespace tcmalloc_internal { -int FakeTransferCacheManager::DetermineSizeClassToEvict() { return 3; } -bool FakeTransferCacheManager::ShrinkCache(int) { return true; } - +ABSL_CONST_INIT bool + ArenaBasedFakeTransferCacheManager::partial_legacy_transfer_cache_(false); +ABSL_CONST_INIT bool FakeShardedTransferCacheManager::enable_generic_cache_( + false); +ABSL_CONST_INIT bool + FakeShardedTransferCacheManager::enable_cache_for_large_classes_only_( + false); } // namespace tcmalloc_internal } // namespace tcmalloc diff --git a/contrib/libs/tcmalloc/tcmalloc/mock_transfer_cache.h b/contrib/libs/tcmalloc/tcmalloc/mock_transfer_cache.h index 5b5192f6dc9b..511ec8d9b4a4 100644 --- a/contrib/libs/tcmalloc/tcmalloc/mock_transfer_cache.h +++ b/contrib/libs/tcmalloc/tcmalloc/mock_transfer_cache.h @@ -1,3 +1,4 @@ +#pragma clang system_header // Copyright 2020 The TCMalloc Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,13 +20,17 @@ #include #include +#include #include +#include #include "gmock/gmock.h" +#include "gtest/gtest.h" #include "absl/random/distributions.h" #include "absl/random/random.h" #include "tcmalloc/common.h" #include "tcmalloc/mock_central_freelist.h" +#include "tcmalloc/transfer_cache.h" #include "tcmalloc/transfer_cache_internals.h" namespace tcmalloc { @@ -33,66 +38,91 @@ namespace tcmalloc_internal { inline constexpr size_t kClassSize = 8; inline constexpr size_t kNumToMove = 32; -inline constexpr int kSizeClass = 0; +inline constexpr int kSizeClass = 1; -class FakeTransferCacheManagerBase { +// TransferCacheManager with basic stubs for everything. +// +// Useful for benchmarks where you want to unrelated expensive operations. +class FakeTransferCacheManager { public: constexpr static size_t class_to_size(int size_class) { return kClassSize; } constexpr static size_t num_objects_to_move(int size_class) { // TODO(b/170732338): test with multiple different num_objects_to_move return kNumToMove; } - void* Alloc(size_t size) { - memory_.emplace_back(::operator new(size)); - return memory_.back().get(); + void* Alloc(size_t size, std::align_val_t alignment = kAlignment) { + memory_.push_back(std::make_unique( + ::operator new(size, alignment), alignment)); + return memory_.back()->ptr; } - struct Free { - void operator()(void* b) { ::operator delete(b); } - }; private: - std::vector> memory_; + struct AlignedPtr { + AlignedPtr(void* ptr, std::align_val_t alignment) + : ptr(ptr), alignment(alignment) {} + ~AlignedPtr() { ::operator delete(ptr, alignment); } + void* ptr; + std::align_val_t alignment; + }; + std::vector> memory_; }; -// TransferCacheManager with basic stubs for everything. +// A transfer cache manager which wraps malloc. // -// Useful for benchmarks where you want to unrelated expensive operations. -class FakeTransferCacheManager : public FakeTransferCacheManagerBase { +// TODO(b/175334169): Remove this once the locks are no longer used. +class ArenaBasedFakeTransferCacheManager { public: - int DetermineSizeClassToEvict(); - bool ShrinkCache(int); + ArenaBasedFakeTransferCacheManager() = default; + constexpr static size_t class_to_size(int size_class) { + // Chosen >= min size for the sharded transfer cache to kick in. + if (size_class == kSizeClass) return 4096; + return 0; + } + constexpr static size_t num_objects_to_move(int size_class) { + if (size_class == kSizeClass) return kNumToMove; + return 0; + } + void* Alloc(size_t size, std::align_val_t alignment = kAlignment) { + { + // Bounce pageheap_lock to verify we can take it. + // + // TODO(b/175334169): Remove this. + PageHeapSpinLockHolder l; + } + used_ += size; + return ::operator new(size, alignment); + } + size_t used() const { return used_; } + + static void SetPartialLegacyTransferCache(bool value) { + partial_legacy_transfer_cache_ = value; + } + + private: + size_t used_ = 0; + static bool partial_legacy_transfer_cache_; }; -// TransferCacheManager which allows intercepting intersting methods. -// -// Useful for intrusive unit tests that want to verify internal behavior. -class RawMockTransferCacheManager : public FakeTransferCacheManagerBase { +// A manager that may provide different configurations of sharded transfer +// cache. +class FakeShardedTransferCacheManager + : public ArenaBasedFakeTransferCacheManager { public: - RawMockTransferCacheManager() : FakeTransferCacheManagerBase() { - // We want single threaded tests to be deterministic, so we use a - // deterministic generator. Because we don't know about the threading for - // our tests we cannot keep the generator in a local variable. - ON_CALL(*this, ShrinkCache).WillByDefault([]() { - thread_local std::mt19937 gen{0}; - return absl::Bernoulli(gen, 0.8); - }); - ON_CALL(*this, GrowCache).WillByDefault([]() { - thread_local std::mt19937 gen{0}; - return absl::Bernoulli(gen, 0.8); - }); - ON_CALL(*this, DetermineSizeClassToEvict).WillByDefault([]() { - thread_local std::mt19937 gen{0}; - return absl::Uniform(gen, 1, kNumClasses); - }); + static void Init() {} + static bool UseGenericCache() { return enable_generic_cache_; } + static void SetGenericCache(bool value) { enable_generic_cache_ = value; } + static bool EnableCacheForLargeClassesOnly() { + return enable_cache_for_large_classes_only_; + } + static void SetCacheForLargeClassesOnly(bool value) { + enable_cache_for_large_classes_only_ = value; } - MOCK_METHOD(int, DetermineSizeClassToEvict, ()); - MOCK_METHOD(bool, ShrinkCache, (int size_class)); - MOCK_METHOD(bool, GrowCache, (int size_class)); + private: + static bool enable_generic_cache_; + static bool enable_cache_for_large_classes_only_; }; -using MockTransferCacheManager = testing::NiceMock; - // Wires up a largely functional TransferCache + TransferCacheManager + // MockCentralFreeList. // @@ -114,30 +144,30 @@ class FakeTransferCacheEnvironment { ::tcmalloc::tcmalloc_internal::kMaxObjectsToMove; static constexpr int kBatchSize = Manager::num_objects_to_move(1); - FakeTransferCacheEnvironment() : manager_(), cache_(&manager_, 1) {} + FakeTransferCacheEnvironment() : manager_(), cache_(&manager_, 1) { Init(); } ~FakeTransferCacheEnvironment() { Drain(); } - void Shrink() { cache_.ShrinkCache(kSizeClass); } - void Grow() { cache_.GrowCache(kSizeClass); } + bool Shrink() { return cache_.ShrinkCache(kSizeClass); } + bool Grow() { return cache_.IncreaseCacheCapacity(kSizeClass); } - void Insert(int n) { + void Insert(int n, int batch = kBatchSize) { std::vector bufs; while (n > 0) { - int b = std::min(n, kBatchSize); + int b = std::min(n, batch); bufs.resize(b); - central_freelist().AllocateBatch(&bufs[0], b); + central_freelist().AllocateBatch(absl::MakeSpan(bufs)); cache_.InsertRange(kSizeClass, absl::MakeSpan(bufs)); n -= b; } } - void Remove(int n) { + void Remove(int n, int batch = kBatchSize) { std::vector bufs; while (n > 0) { - int b = std::min(n, kBatchSize); + int b = std::min(n, batch); bufs.resize(b); - int removed = cache_.RemoveRange(kSizeClass, &bufs[0], b); + int removed = cache_.RemoveRange(kSizeClass, absl::MakeSpan(bufs)); // Ensure we make progress. ASSERT_GT(removed, 0); ASSERT_LE(removed, b); @@ -146,6 +176,8 @@ class FakeTransferCacheEnvironment { } } + void TryPlunder() { cache_.TryPlunder(kSizeClass); } + void Drain() { Remove(cache_.tc_length()); } void RandomlyPoke() { @@ -160,20 +192,26 @@ class FakeTransferCacheEnvironment { Grow(); } else if (choice < 0.3) { cache_.HasSpareCapacity(kSizeClass); - } else if (choice < 0.65) { + } else if (choice < 0.4) { Insert(absl::Uniform(gen, 1, kBatchSize)); - } else { + } else if (choice < 0.5) { Remove(absl::Uniform(gen, 1, kBatchSize)); + } else if (choice < 0.7) { + Insert(kBatchSize); + } else if (choice < 0.9) { + Remove(kBatchSize); + } else { + TryPlunder(); } } TransferCache& transfer_cache() { return cache_; } - Manager& transfer_cache_manager() { return manager_; } - FreeList& central_freelist() { return cache_.freelist(); } private: + void Init() {}; + Manager manager_; TransferCache cache_; }; @@ -183,23 +221,22 @@ class FakeTransferCacheEnvironment { // inside the cache manager, like in production code. template class TransferCacheT> -class TwoSizeClassManager : public FakeTransferCacheManagerBase { +class TwoSizeClassManager : public FakeTransferCacheManager { public: using FreeList = FreeListT; using TransferCache = TransferCacheT; - // This is 3 instead of 2 because we hard code cl == 0 to be invalid in many - // places. We only use cl 1 and 2 here. - static constexpr int kSizeClasses = 3; + // This is 3 instead of 2 because we hard code size_class == 0 to be invalid + // in many places. We only use size_class 1 and 2 here. static constexpr size_t kClassSize1 = 8; - static constexpr size_t kClassSize2 = 16; + static constexpr size_t kClassSize2 = 16 << 10; static constexpr size_t kNumToMove1 = 32; - static constexpr size_t kNumToMove2 = 16; + static constexpr size_t kNumToMove2 = 2; TwoSizeClassManager() { - caches_.push_back(absl::make_unique(this, 0)); - caches_.push_back(absl::make_unique(this, 1)); - caches_.push_back(absl::make_unique(this, 2)); + caches_.push_back(std::make_unique(this, 0)); + caches_.push_back(std::make_unique(this, 1)); + caches_.push_back(std::make_unique(this, 2)); } constexpr static size_t class_to_size(int size_class) { @@ -223,87 +260,187 @@ class TwoSizeClassManager : public FakeTransferCacheManagerBase { } } - int DetermineSizeClassToEvict() { return evicting_from_; } - - bool ShrinkCache(int size_class) { - return caches_[size_class]->ShrinkCache(size_class); + void InsertRange(int size_class, absl::Span batch) { + caches_[size_class]->InsertRange(size_class, batch); } - FreeList& central_freelist(int cl) { return caches_[cl]->freelist(); } - - void InsertRange(int cl, absl::Span batch) { - caches_[cl]->InsertRange(cl, batch); + int RemoveRange(int size_class, absl::Span batch) { + return caches_[size_class]->RemoveRange(size_class, batch); } - int RemoveRange(int cl, void** batch, int N) { - return caches_[cl]->RemoveRange(cl, batch, N); + size_t tc_length(int size_class) { return caches_[size_class]->tc_length(); } + TransferCacheStats GetStats(int size_class) { + return caches_[size_class]->GetStats(); } - bool HasSpareCapacity(int cl) { return caches_[cl]->HasSpareCapacity(cl); } + std::vector> caches_; +}; + +class FakeCpuLayout { + public: + static constexpr int kNumCpus = 6; + static constexpr int kCpusPerShard = 2; - size_t tc_length(int cl) { return caches_[cl]->tc_length(); } + void Init(int shards) { + TC_ASSERT_GT(shards, 0); + TC_ASSERT_LE(shards * kCpusPerShard, kNumCpus); + num_shards_ = shards; + } - std::vector> caches_; + void SetCurrentCpu(int cpu) { + TC_ASSERT_GE(cpu, 0); + TC_ASSERT_LT(cpu, kNumCpus); + current_cpu_ = cpu; + } + + unsigned NumShards() { return num_shards_; } + int CurrentCpu() { return current_cpu_; } + unsigned CpuShard(int cpu) { + return std::min(cpu / kCpusPerShard, num_shards_ - 1); + } - // From which size class to evict. - int evicting_from_ = 1; + private: + int current_cpu_ = 0; + int num_shards_ = 0; }; -template